]> Pileus Git - ~andy/gtk/blob - gtk/gtkpaned.c
fabbc25d7f0bc2c70a69316151ef75c2095061ed
[~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, see <http://www.gnu.org/licenses/>.
16  */
17
18 /*
19  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
20  * file for a list of people on the GTK+ Team.  See the ChangeLog
21  * files for a list of changes.  These files are distributed with
22  * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
23  */
24
25 #include "config.h"
26
27 #include "gtkpaned.h"
28
29 #include "gtkbindings.h"
30 #include "gtkmain.h"
31 #include "gtkmarshalers.h"
32 #include "gtkorientable.h"
33 #include "gtkwindow.h"
34 #include "gtktypebuiltins.h"
35 #include "gtkprivate.h"
36 #include "gtkintl.h"
37 #include "a11y/gtkpanedaccessible.h"
38
39 /**
40  * SECTION:gtkpaned
41  * @Short_description: A widget with two adjustable panes
42  * @Title: GtkPaned
43  *
44  * #GtkPaned has two panes, arranged either
45  * horizontally or vertically. The division between
46  * the two panes is adjustable by the user by dragging
47  * a handle.
48  *
49  * Child widgets are
50  * added to the panes of the widget with gtk_paned_pack1() and
51  * gtk_paned_pack2(). The division between the two children is set by default
52  * from the size requests of the children, but it can be adjusted by the
53  * user.
54  *
55  * A paned widget draws a separator between the two child widgets and a
56  * small handle that the user can drag to adjust the division. It does not
57  * draw any relief around the children or around the separator. (The space
58  * in which the separator is called the gutter.) Often, it is useful to put
59  * each child inside a #GtkFrame with the shadow type set to %GTK_SHADOW_IN
60  * so that the gutter appears as a ridge. No separator is drawn if one of
61  * the children is missing.
62  *
63  * Each child has two options that can be set, @resize and @shrink. If
64  * @resize is true, then when the #GtkPaned is resized, that child will
65  * expand or shrink along with the paned widget. If @shrink is true, then
66  * that child can be made smaller than its requisition by the user.
67  * Setting @shrink to %FALSE allows the application to set a minimum size.
68  * If @resize is false for both children, then this is treated as if
69  * @resize is true for both children.
70  *
71  * The application can set the position of the slider as if it were set
72  * by the user, by calling gtk_paned_set_position().
73  *
74  * <example>
75  * <title>Creating a paned widget with minimum sizes.</title>
76  * <programlisting>
77  * GtkWidget *hpaned = gtk_paned_new (GTK_ORIENTATION_HORIZONTAL);
78  * GtkWidget *frame1 = gtk_frame_new (NULL);
79  * GtkWidget *frame2 = gtk_frame_new (NULL);
80  * gtk_frame_set_shadow_type (GTK_FRAME (frame1), GTK_SHADOW_IN);
81  * gtk_frame_set_shadow_type (GTK_FRAME (frame2), GTK_SHADOW_IN);
82  *
83  * gtk_widget_set_size_request (hpaned, 200, -1);
84  *
85  * gtk_paned_pack1 (GTK_PANED (hpaned), frame1, TRUE, FALSE);
86  * gtk_widget_set_size_request (frame1, 50, -1);
87  *
88  * gtk_paned_pack2 (GTK_PANED (hpaned), frame2, FALSE, FALSE);
89  * gtk_widget_set_size_request (frame2, 50, -1);
90  * </programlisting>
91  * </example>
92  */
93
94 enum {
95   CHILD1,
96   CHILD2
97 };
98
99 struct _GtkPanedPrivate
100 {
101   GtkPaned       *first_paned;
102   GtkWidget      *child1;
103   GtkWidget      *child2;
104   GdkWindow      *child1_window;
105   GdkWindow      *child2_window;
106   GtkWidget      *last_child1_focus;
107   GtkWidget      *last_child2_focus;
108   GtkWidget      *saved_focus;
109   GtkOrientation  orientation;
110
111   GdkCursorType  cursor_type;
112   GdkDevice     *grab_device;
113   GdkRectangle   handle_pos;
114   GdkWindow     *handle;
115
116   gint          child1_size;
117   gint          drag_pos;
118   gint          last_allocation;
119   gint          max_position;
120   gint          min_position;
121   gint          original_position;
122
123   guint32       grab_time;
124
125   guint         handle_prelit : 1;
126   guint         in_drag       : 1;
127   guint         in_recursion  : 1;
128   guint         child1_resize : 1;
129   guint         child1_shrink : 1;
130   guint         child2_resize : 1;
131   guint         child2_shrink : 1;
132   guint         position_set  : 1;
133 };
134
135 enum {
136   PROP_0,
137   PROP_ORIENTATION,
138   PROP_POSITION,
139   PROP_POSITION_SET,
140   PROP_MIN_POSITION,
141   PROP_MAX_POSITION
142 };
143
144 enum {
145   CHILD_PROP_0,
146   CHILD_PROP_RESIZE,
147   CHILD_PROP_SHRINK
148 };
149
150 enum {
151   CYCLE_CHILD_FOCUS,
152   TOGGLE_HANDLE_FOCUS,
153   MOVE_HANDLE,
154   CYCLE_HANDLE_FOCUS,
155   ACCEPT_POSITION,
156   CANCEL_POSITION,
157   LAST_SIGNAL
158 };
159
160 static void     gtk_paned_set_property          (GObject          *object,
161                                                  guint             prop_id,
162                                                  const GValue     *value,
163                                                  GParamSpec       *pspec);
164 static void     gtk_paned_get_property          (GObject          *object,
165                                                  guint             prop_id,
166                                                  GValue           *value,
167                                                  GParamSpec       *pspec);
168 static void     gtk_paned_set_child_property    (GtkContainer     *container,
169                                                  GtkWidget        *child,
170                                                  guint             property_id,
171                                                  const GValue     *value,
172                                                  GParamSpec       *pspec);
173 static void     gtk_paned_get_child_property    (GtkContainer     *container,
174                                                  GtkWidget        *child,
175                                                  guint             property_id,
176                                                  GValue           *value,
177                                                  GParamSpec       *pspec);
178 static void     gtk_paned_finalize              (GObject          *object);
179
180 static void     gtk_paned_get_preferred_width   (GtkWidget        *widget,
181                                                  gint             *minimum,
182                                                  gint             *natural);
183 static void     gtk_paned_get_preferred_height  (GtkWidget        *widget,
184                                                  gint             *minimum,
185                                                  gint             *natural);
186 static void     gtk_paned_get_preferred_width_for_height
187                                                 (GtkWidget        *widget,
188                                                  gint              height,
189                                                  gint             *minimum,
190                                                  gint             *natural);
191 static void     gtk_paned_get_preferred_height_for_width
192                                                 (GtkWidget        *widget,
193                                                  gint              width,
194                                                  gint             *minimum,
195                                                  gint              *natural);
196
197 static void     gtk_paned_size_allocate         (GtkWidget        *widget,
198                                                  GtkAllocation    *allocation);
199 static void     gtk_paned_realize               (GtkWidget        *widget);
200 static void     gtk_paned_unrealize             (GtkWidget        *widget);
201 static void     gtk_paned_map                   (GtkWidget        *widget);
202 static void     gtk_paned_unmap                 (GtkWidget        *widget);
203 static void     gtk_paned_state_flags_changed   (GtkWidget        *widget,
204                                                  GtkStateFlags     previous_state);
205 static gboolean gtk_paned_draw                  (GtkWidget        *widget,
206                                                  cairo_t          *cr);
207 static gboolean gtk_paned_enter                 (GtkWidget        *widget,
208                                                  GdkEventCrossing *event);
209 static gboolean gtk_paned_leave                 (GtkWidget        *widget,
210                                                  GdkEventCrossing *event);
211 static gboolean gtk_paned_button_press          (GtkWidget        *widget,
212                                                  GdkEventButton   *event);
213 static gboolean gtk_paned_button_release        (GtkWidget        *widget,
214                                                  GdkEventButton   *event);
215 static gboolean gtk_paned_motion                (GtkWidget        *widget,
216                                                  GdkEventMotion   *event);
217 static gboolean gtk_paned_focus                 (GtkWidget        *widget,
218                                                  GtkDirectionType  direction);
219 static gboolean gtk_paned_grab_broken           (GtkWidget          *widget,
220                                                  GdkEventGrabBroken *event);
221 static void     gtk_paned_add                   (GtkContainer     *container,
222                                                  GtkWidget        *widget);
223 static void     gtk_paned_remove                (GtkContainer     *container,
224                                                  GtkWidget        *widget);
225 static void     gtk_paned_forall                (GtkContainer     *container,
226                                                  gboolean          include_internals,
227                                                  GtkCallback       callback,
228                                                  gpointer          callback_data);
229 static void     gtk_paned_calc_position         (GtkPaned         *paned,
230                                                  gint              allocation,
231                                                  gint              child1_req,
232                                                  gint              child2_req);
233 static void     gtk_paned_set_focus_child       (GtkContainer     *container,
234                                                  GtkWidget        *child);
235 static void     gtk_paned_set_saved_focus       (GtkPaned         *paned,
236                                                  GtkWidget        *widget);
237 static void     gtk_paned_set_first_paned       (GtkPaned         *paned,
238                                                  GtkPaned         *first_paned);
239 static void     gtk_paned_set_last_child1_focus (GtkPaned         *paned,
240                                                  GtkWidget        *widget);
241 static void     gtk_paned_set_last_child2_focus (GtkPaned         *paned,
242                                                  GtkWidget        *widget);
243 static gboolean gtk_paned_cycle_child_focus     (GtkPaned         *paned,
244                                                  gboolean          reverse);
245 static gboolean gtk_paned_cycle_handle_focus    (GtkPaned         *paned,
246                                                  gboolean          reverse);
247 static gboolean gtk_paned_move_handle           (GtkPaned         *paned,
248                                                  GtkScrollType     scroll);
249 static gboolean gtk_paned_accept_position       (GtkPaned         *paned);
250 static gboolean gtk_paned_cancel_position       (GtkPaned         *paned);
251 static gboolean gtk_paned_toggle_handle_focus   (GtkPaned         *paned);
252
253 static GType    gtk_paned_child_type            (GtkContainer     *container);
254 static void     gtk_paned_grab_notify           (GtkWidget        *widget,
255                                                  gboolean          was_grabbed);
256
257
258 G_DEFINE_TYPE_WITH_CODE (GtkPaned, gtk_paned, GTK_TYPE_CONTAINER,
259                          G_IMPLEMENT_INTERFACE (GTK_TYPE_ORIENTABLE,
260                                                 NULL))
261
262 static guint signals[LAST_SIGNAL] = { 0 };
263
264
265 static void
266 add_tab_bindings (GtkBindingSet    *binding_set,
267                   GdkModifierType   modifiers)
268 {
269   gtk_binding_entry_add_signal (binding_set, GDK_KEY_Tab, modifiers,
270                                 "toggle-handle-focus", 0);
271   gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Tab, modifiers,
272                                 "toggle-handle-focus", 0);
273 }
274
275 static void
276 add_move_binding (GtkBindingSet   *binding_set,
277                   guint            keyval,
278                   GdkModifierType  mask,
279                   GtkScrollType    scroll)
280 {
281   gtk_binding_entry_add_signal (binding_set, keyval, mask,
282                                 "move-handle", 1,
283                                 GTK_TYPE_SCROLL_TYPE, scroll);
284 }
285
286 static void
287 gtk_paned_class_init (GtkPanedClass *class)
288 {
289   GObjectClass *object_class;
290   GtkWidgetClass *widget_class;
291   GtkContainerClass *container_class;
292   GtkPanedClass *paned_class;
293   GtkBindingSet *binding_set;
294
295   object_class = (GObjectClass *) class;
296   widget_class = (GtkWidgetClass *) class;
297   container_class = (GtkContainerClass *) class;
298   paned_class = (GtkPanedClass *) class;
299
300   object_class->set_property = gtk_paned_set_property;
301   object_class->get_property = gtk_paned_get_property;
302   object_class->finalize = gtk_paned_finalize;
303
304   widget_class->get_preferred_width = gtk_paned_get_preferred_width;
305   widget_class->get_preferred_height = gtk_paned_get_preferred_height;
306   widget_class->get_preferred_width_for_height = gtk_paned_get_preferred_width_for_height;
307   widget_class->get_preferred_height_for_width = gtk_paned_get_preferred_height_for_width;
308   widget_class->size_allocate = gtk_paned_size_allocate;
309   widget_class->realize = gtk_paned_realize;
310   widget_class->unrealize = gtk_paned_unrealize;
311   widget_class->map = gtk_paned_map;
312   widget_class->unmap = gtk_paned_unmap;
313   widget_class->draw = gtk_paned_draw;
314   widget_class->focus = gtk_paned_focus;
315   widget_class->enter_notify_event = gtk_paned_enter;
316   widget_class->leave_notify_event = gtk_paned_leave;
317   widget_class->button_press_event = gtk_paned_button_press;
318   widget_class->button_release_event = gtk_paned_button_release;
319   widget_class->motion_notify_event = gtk_paned_motion;
320   widget_class->grab_broken_event = gtk_paned_grab_broken;
321   widget_class->grab_notify = gtk_paned_grab_notify;
322   widget_class->state_flags_changed = gtk_paned_state_flags_changed;
323
324   container_class->add = gtk_paned_add;
325   container_class->remove = gtk_paned_remove;
326   container_class->forall = gtk_paned_forall;
327   container_class->child_type = gtk_paned_child_type;
328   container_class->set_focus_child = gtk_paned_set_focus_child;
329   container_class->set_child_property = gtk_paned_set_child_property;
330   container_class->get_child_property = gtk_paned_get_child_property;
331   gtk_container_class_handle_border_width (container_class);
332
333   paned_class->cycle_child_focus = gtk_paned_cycle_child_focus;
334   paned_class->toggle_handle_focus = gtk_paned_toggle_handle_focus;
335   paned_class->move_handle = gtk_paned_move_handle;
336   paned_class->cycle_handle_focus = gtk_paned_cycle_handle_focus;
337   paned_class->accept_position = gtk_paned_accept_position;
338   paned_class->cancel_position = gtk_paned_cancel_position;
339
340   g_object_class_override_property (object_class,
341                                     PROP_ORIENTATION,
342                                     "orientation");
343
344   g_object_class_install_property (object_class,
345                                    PROP_POSITION,
346                                    g_param_spec_int ("position",
347                                                      P_("Position"),
348                                                      P_("Position of paned separator in pixels (0 means all the way to the left/top)"),
349                                                      0,
350                                                      G_MAXINT,
351                                                      0,
352                                                      GTK_PARAM_READWRITE));
353
354   g_object_class_install_property (object_class,
355                                    PROP_POSITION_SET,
356                                    g_param_spec_boolean ("position-set",
357                                                          P_("Position Set"),
358                                                          P_("TRUE if the Position property should be used"),
359                                                          FALSE,
360                                                          GTK_PARAM_READWRITE));
361
362   gtk_widget_class_install_style_property (widget_class,
363                                            g_param_spec_int ("handle-size",
364                                                              P_("Handle Size"),
365                                                              P_("Width of handle"),
366                                                              0,
367                                                              G_MAXINT,
368                                                              5,
369                                                              GTK_PARAM_READABLE));
370   /**
371    * GtkPaned:min-position:
372    *
373    * The smallest possible value for the position property. This property is derived from the
374    * size and shrinkability of the widget's children.
375    *
376    * Since: 2.4
377    */
378   g_object_class_install_property (object_class,
379                                    PROP_MIN_POSITION,
380                                    g_param_spec_int ("min-position",
381                                                      P_("Minimal Position"),
382                                                      P_("Smallest possible value for the \"position\" property"),
383                                                      0,
384                                                      G_MAXINT,
385                                                      0,
386                                                      GTK_PARAM_READABLE));
387
388   /**
389    * GtkPaned:max-position:
390    *
391    * The largest possible value for the position property. This property is derived from the
392    * size and shrinkability of the widget's children.
393    *
394    * Since: 2.4
395    */
396   g_object_class_install_property (object_class,
397                                    PROP_MAX_POSITION,
398                                    g_param_spec_int ("max-position",
399                                                      P_("Maximal Position"),
400                                                      P_("Largest possible value for the \"position\" property"),
401                                                      0,
402                                                      G_MAXINT,
403                                                      G_MAXINT,
404                                                      GTK_PARAM_READABLE));
405
406   /**
407    * GtkPaned:resize:
408    *
409    * The "resize" child property determines whether the child expands and
410    * shrinks along with the paned widget.
411    *
412    * Since: 2.4
413    */
414   gtk_container_class_install_child_property (container_class,
415                                               CHILD_PROP_RESIZE,
416                                               g_param_spec_boolean ("resize", 
417                                                                     P_("Resize"),
418                                                                     P_("If TRUE, the child expands and shrinks along with the paned widget"),
419                                                                     TRUE,
420                                                                     GTK_PARAM_READWRITE));
421
422   /**
423    * GtkPaned:shrink:
424    *
425    * The "shrink" child property determines whether the child can be made
426    * smaller than its requisition.
427    *
428    * Since: 2.4
429    */
430   gtk_container_class_install_child_property (container_class,
431                                               CHILD_PROP_SHRINK,
432                                               g_param_spec_boolean ("shrink", 
433                                                                     P_("Shrink"),
434                                                                     P_("If TRUE, the child can be made smaller than its requisition"),
435                                                                     TRUE,
436                                                                     GTK_PARAM_READWRITE));
437
438   /**
439    * GtkPaned::cycle-child-focus:
440    * @widget: the object that received the signal
441    * @reversed: whether cycling backward or forward
442    *
443    * The ::cycle-child-focus signal is a 
444    * <link linkend="keybinding-signals">keybinding signal</link>
445    * which gets emitted to cycle the focus between the children of the paned.
446    *
447    * The default binding is f6.
448    *
449    * Since: 2.0
450    */
451   signals [CYCLE_CHILD_FOCUS] =
452     g_signal_new (I_("cycle-child-focus"),
453                   G_TYPE_FROM_CLASS (object_class),
454                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
455                   G_STRUCT_OFFSET (GtkPanedClass, cycle_child_focus),
456                   NULL, NULL,
457                   _gtk_marshal_BOOLEAN__BOOLEAN,
458                   G_TYPE_BOOLEAN, 1,
459                   G_TYPE_BOOLEAN);
460
461   /**
462    * GtkPaned::toggle-handle-focus:
463    * @widget: the object that received the signal
464    *
465    * The ::toggle-handle-focus is a 
466    * <link linkend="keybinding-signals">keybinding signal</link>
467    * which gets emitted to accept the current position of the handle and then 
468    * move focus to the next widget in the focus chain.
469    *
470    * The default binding is Tab.
471    *
472    * Since: 2.0
473    */
474   signals [TOGGLE_HANDLE_FOCUS] =
475     g_signal_new (I_("toggle-handle-focus"),
476                   G_TYPE_FROM_CLASS (object_class),
477                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
478                   G_STRUCT_OFFSET (GtkPanedClass, toggle_handle_focus),
479                   NULL, NULL,
480                   _gtk_marshal_BOOLEAN__VOID,
481                   G_TYPE_BOOLEAN, 0);
482
483   /**
484    * GtkPaned::move-handle:
485    * @widget: the object that received the signal
486    * @scroll_type: a #GtkScrollType
487    *
488    * The ::move-handle signal is a 
489    * <link linkend="keybinding-signals">keybinding signal</link>
490    * which gets emitted to move the handle when the user is using key bindings 
491    * to move it.
492    *
493    * Since: 2.0
494    */
495   signals[MOVE_HANDLE] =
496     g_signal_new (I_("move-handle"),
497                   G_TYPE_FROM_CLASS (object_class),
498                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
499                   G_STRUCT_OFFSET (GtkPanedClass, move_handle),
500                   NULL, NULL,
501                   _gtk_marshal_BOOLEAN__ENUM,
502                   G_TYPE_BOOLEAN, 1,
503                   GTK_TYPE_SCROLL_TYPE);
504
505   /**
506    * GtkPaned::cycle-handle-focus:
507    * @widget: the object that received the signal
508    * @reversed: whether cycling backward or forward
509    *
510    * The ::cycle-handle-focus signal is a 
511    * <link linkend="keybinding-signals">keybinding signal</link>
512    * which gets emitted to cycle whether the paned should grab focus to allow
513    * the user to change position of the handle by using key bindings.
514    *
515    * The default binding for this signal is f8.
516    *
517    * Since: 2.0
518    */
519   signals [CYCLE_HANDLE_FOCUS] =
520     g_signal_new (I_("cycle-handle-focus"),
521                   G_TYPE_FROM_CLASS (object_class),
522                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
523                   G_STRUCT_OFFSET (GtkPanedClass, cycle_handle_focus),
524                   NULL, NULL,
525                   _gtk_marshal_BOOLEAN__BOOLEAN,
526                   G_TYPE_BOOLEAN, 1,
527                   G_TYPE_BOOLEAN);
528
529   /**
530    * GtkPaned::accept-position:
531    * @widget: the object that received the signal
532    *
533    * The ::accept-position signal is a 
534    * <link linkend="keybinding-signals">keybinding signal</link>
535    * which gets emitted to accept the current position of the handle when 
536    * moving it using key bindings.
537    *
538    * The default binding for this signal is Return or Space.
539    *
540    * Since: 2.0
541    */
542   signals [ACCEPT_POSITION] =
543     g_signal_new (I_("accept-position"),
544                   G_TYPE_FROM_CLASS (object_class),
545                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
546                   G_STRUCT_OFFSET (GtkPanedClass, accept_position),
547                   NULL, NULL,
548                   _gtk_marshal_BOOLEAN__VOID,
549                   G_TYPE_BOOLEAN, 0);
550
551   /**
552    * GtkPaned::cancel-position:
553    * @widget: the object that received the signal
554    *
555    * The ::cancel-position signal is a 
556    * <link linkend="keybinding-signals">keybinding signal</link>
557    * which gets emitted to cancel moving the position of the handle using key 
558    * bindings. The position of the handle will be reset to the value prior to 
559    * moving it.
560    *
561    * The default binding for this signal is Escape.
562    *
563    * Since: 2.0
564    */
565   signals [CANCEL_POSITION] =
566     g_signal_new (I_("cancel-position"),
567                   G_TYPE_FROM_CLASS (object_class),
568                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
569                   G_STRUCT_OFFSET (GtkPanedClass, cancel_position),
570                   NULL, NULL,
571                   _gtk_marshal_BOOLEAN__VOID,
572                   G_TYPE_BOOLEAN, 0);
573
574   binding_set = gtk_binding_set_by_class (class);
575
576   /* F6 and friends */
577   gtk_binding_entry_add_signal (binding_set,
578                                 GDK_KEY_F6, 0,
579                                 "cycle-child-focus", 1, 
580                                 G_TYPE_BOOLEAN, FALSE);
581   gtk_binding_entry_add_signal (binding_set,
582                                 GDK_KEY_F6, GDK_SHIFT_MASK,
583                                 "cycle-child-focus", 1,
584                                 G_TYPE_BOOLEAN, TRUE);
585
586   /* F8 and friends */
587   gtk_binding_entry_add_signal (binding_set,
588                                 GDK_KEY_F8, 0,
589                                 "cycle-handle-focus", 1,
590                                 G_TYPE_BOOLEAN, FALSE);
591  
592   gtk_binding_entry_add_signal (binding_set,
593                                 GDK_KEY_F8, GDK_SHIFT_MASK,
594                                 "cycle-handle-focus", 1,
595                                 G_TYPE_BOOLEAN, TRUE);
596  
597   add_tab_bindings (binding_set, 0);
598   add_tab_bindings (binding_set, GDK_CONTROL_MASK);
599   add_tab_bindings (binding_set, GDK_SHIFT_MASK);
600   add_tab_bindings (binding_set, GDK_CONTROL_MASK | GDK_SHIFT_MASK);
601
602   /* accept and cancel positions */
603   gtk_binding_entry_add_signal (binding_set,
604                                 GDK_KEY_Escape, 0,
605                                 "cancel-position", 0);
606
607   gtk_binding_entry_add_signal (binding_set,
608                                 GDK_KEY_Return, 0,
609                                 "accept-position", 0);
610   gtk_binding_entry_add_signal (binding_set,
611                                 GDK_KEY_ISO_Enter, 0,
612                                 "accept-position", 0);
613   gtk_binding_entry_add_signal (binding_set,
614                                 GDK_KEY_KP_Enter, 0,
615                                 "accept-position", 0);
616   gtk_binding_entry_add_signal (binding_set,
617                                 GDK_KEY_space, 0,
618                                 "accept-position", 0);
619   gtk_binding_entry_add_signal (binding_set,
620                                 GDK_KEY_KP_Space, 0,
621                                 "accept-position", 0);
622
623   /* move handle */
624   add_move_binding (binding_set, GDK_KEY_Left, 0, GTK_SCROLL_STEP_LEFT);
625   add_move_binding (binding_set, GDK_KEY_KP_Left, 0, GTK_SCROLL_STEP_LEFT);
626   add_move_binding (binding_set, GDK_KEY_Left, GDK_CONTROL_MASK, GTK_SCROLL_PAGE_LEFT);
627   add_move_binding (binding_set, GDK_KEY_KP_Left, GDK_CONTROL_MASK, GTK_SCROLL_PAGE_LEFT);
628
629   add_move_binding (binding_set, GDK_KEY_Right, 0, GTK_SCROLL_STEP_RIGHT);
630   add_move_binding (binding_set, GDK_KEY_Right, GDK_CONTROL_MASK, GTK_SCROLL_PAGE_RIGHT);
631   add_move_binding (binding_set, GDK_KEY_KP_Right, 0, GTK_SCROLL_STEP_RIGHT);
632   add_move_binding (binding_set, GDK_KEY_KP_Right, GDK_CONTROL_MASK, GTK_SCROLL_PAGE_RIGHT);
633
634   add_move_binding (binding_set, GDK_KEY_Up, 0, GTK_SCROLL_STEP_UP);
635   add_move_binding (binding_set, GDK_KEY_Up, GDK_CONTROL_MASK, GTK_SCROLL_PAGE_UP);
636   add_move_binding (binding_set, GDK_KEY_KP_Up, 0, GTK_SCROLL_STEP_UP);
637   add_move_binding (binding_set, GDK_KEY_KP_Up, GDK_CONTROL_MASK, GTK_SCROLL_PAGE_UP);
638   add_move_binding (binding_set, GDK_KEY_Page_Up, 0, GTK_SCROLL_PAGE_UP);
639   add_move_binding (binding_set, GDK_KEY_KP_Page_Up, 0, GTK_SCROLL_PAGE_UP);
640
641   add_move_binding (binding_set, GDK_KEY_Down, 0, GTK_SCROLL_STEP_DOWN);
642   add_move_binding (binding_set, GDK_KEY_Down, GDK_CONTROL_MASK, GTK_SCROLL_PAGE_DOWN);
643   add_move_binding (binding_set, GDK_KEY_KP_Down, 0, GTK_SCROLL_STEP_DOWN);
644   add_move_binding (binding_set, GDK_KEY_KP_Down, GDK_CONTROL_MASK, GTK_SCROLL_PAGE_DOWN);
645   add_move_binding (binding_set, GDK_KEY_Page_Down, 0, GTK_SCROLL_PAGE_RIGHT);
646   add_move_binding (binding_set, GDK_KEY_KP_Page_Down, 0, GTK_SCROLL_PAGE_RIGHT);
647
648   add_move_binding (binding_set, GDK_KEY_Home, 0, GTK_SCROLL_START);
649   add_move_binding (binding_set, GDK_KEY_KP_Home, 0, GTK_SCROLL_START);
650   add_move_binding (binding_set, GDK_KEY_End, 0, GTK_SCROLL_END);
651   add_move_binding (binding_set, GDK_KEY_KP_End, 0, GTK_SCROLL_END);
652
653   g_type_class_add_private (object_class, sizeof (GtkPanedPrivate));
654   gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_PANED_ACCESSIBLE);
655 }
656
657 static GType
658 gtk_paned_child_type (GtkContainer *container)
659 {
660   GtkPaned *paned = GTK_PANED (container);
661   GtkPanedPrivate *priv = paned->priv;
662
663   if (!priv->child1 || !priv->child2)
664     return GTK_TYPE_WIDGET;
665   else
666     return G_TYPE_NONE;
667 }
668
669 static void
670 gtk_paned_init (GtkPaned *paned)
671 {
672   GtkPanedPrivate *priv;
673
674   gtk_widget_set_has_window (GTK_WIDGET (paned), FALSE);
675   gtk_widget_set_can_focus (GTK_WIDGET (paned), TRUE);
676
677   /* We only need to redraw when the handle position moves, which is
678    * independent of the overall allocation of the GtkPaned
679    */
680   gtk_widget_set_redraw_on_allocate (GTK_WIDGET (paned), FALSE);
681
682   paned->priv = G_TYPE_INSTANCE_GET_PRIVATE (paned, GTK_TYPE_PANED, GtkPanedPrivate);
683   priv = paned->priv;
684
685   priv->orientation = GTK_ORIENTATION_HORIZONTAL;
686   priv->cursor_type = GDK_SB_H_DOUBLE_ARROW;
687
688   priv->child1 = NULL;
689   priv->child2 = NULL;
690   priv->handle = NULL;
691   priv->cursor_type = GDK_CROSS;
692
693   priv->handle_pos.width = 5;
694   priv->handle_pos.height = 5;
695   priv->position_set = FALSE;
696   priv->last_allocation = -1;
697   priv->in_drag = FALSE;
698
699   priv->last_child1_focus = NULL;
700   priv->last_child2_focus = NULL;
701   priv->in_recursion = FALSE;
702   priv->handle_prelit = FALSE;
703   priv->original_position = -1;
704
705   priv->handle_pos.x = -1;
706   priv->handle_pos.y = -1;
707
708   priv->drag_pos = -1;
709 }
710
711 static void
712 gtk_paned_set_property (GObject        *object,
713                         guint           prop_id,
714                         const GValue   *value,
715                         GParamSpec     *pspec)
716 {
717   GtkPaned *paned = GTK_PANED (object);
718   GtkPanedPrivate *priv = paned->priv;
719
720   switch (prop_id)
721     {
722     case PROP_ORIENTATION:
723       priv->orientation = g_value_get_enum (value);
724
725       if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
726         priv->cursor_type = GDK_SB_H_DOUBLE_ARROW;
727       else
728         priv->cursor_type = GDK_SB_V_DOUBLE_ARROW;
729
730       /* state_flags_changed updates the cursor */
731       gtk_paned_state_flags_changed (GTK_WIDGET (paned), 0);
732       gtk_widget_queue_resize (GTK_WIDGET (paned));
733       break;
734     case PROP_POSITION:
735       gtk_paned_set_position (paned, g_value_get_int (value));
736       break;
737     case PROP_POSITION_SET:
738       priv->position_set = g_value_get_boolean (value);
739       gtk_widget_queue_resize_no_redraw (GTK_WIDGET (paned));
740       break;
741     default:
742       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
743       break;
744     }
745 }
746
747 static void
748 gtk_paned_get_property (GObject        *object,
749                         guint           prop_id,
750                         GValue         *value,
751                         GParamSpec     *pspec)
752 {
753   GtkPaned *paned = GTK_PANED (object);
754   GtkPanedPrivate *priv = paned->priv;
755
756   switch (prop_id)
757     {
758     case PROP_ORIENTATION:
759       g_value_set_enum (value, priv->orientation);
760       break;
761     case PROP_POSITION:
762       g_value_set_int (value, priv->child1_size);
763       break;
764     case PROP_POSITION_SET:
765       g_value_set_boolean (value, priv->position_set);
766       break;
767     case PROP_MIN_POSITION:
768       g_value_set_int (value, priv->min_position);
769       break;
770     case PROP_MAX_POSITION:
771       g_value_set_int (value, priv->max_position);
772       break;
773     default:
774       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
775       break;
776     }
777 }
778
779 static void
780 gtk_paned_set_child_property (GtkContainer    *container,
781                               GtkWidget       *child,
782                               guint            property_id,
783                               const GValue    *value,
784                               GParamSpec      *pspec)
785 {
786   GtkPaned *paned = GTK_PANED (container);
787   GtkPanedPrivate *priv = paned->priv;
788   gboolean old_value, new_value;
789
790   g_assert (child == priv->child1 || child == priv->child2);
791
792   new_value = g_value_get_boolean (value);
793   switch (property_id)
794     {
795     case CHILD_PROP_RESIZE:
796       if (child == priv->child1)
797         {
798           old_value = priv->child1_resize;
799           priv->child1_resize = new_value;
800         }
801       else
802         {
803           old_value = priv->child2_resize;
804           priv->child2_resize = new_value;
805         }
806       break;
807     case CHILD_PROP_SHRINK:
808       if (child == priv->child1)
809         {
810           old_value = priv->child1_shrink;
811           priv->child1_shrink = new_value;
812         }
813       else
814         {
815           old_value = priv->child2_shrink;
816           priv->child2_shrink = new_value;
817         }
818       break;
819     default:
820       GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
821       old_value = -1; /* quiet gcc */
822       break;
823     }
824   if (old_value != new_value)
825     gtk_widget_queue_resize_no_redraw (GTK_WIDGET (container));
826 }
827
828 static void
829 gtk_paned_get_child_property (GtkContainer *container,
830                               GtkWidget    *child,
831                               guint         property_id,
832                               GValue       *value,
833                               GParamSpec   *pspec)
834 {
835   GtkPaned *paned = GTK_PANED (container);
836   GtkPanedPrivate *priv = paned->priv;
837
838   g_assert (child == priv->child1 || child == priv->child2);
839   
840   switch (property_id)
841     {
842     case CHILD_PROP_RESIZE:
843       if (child == priv->child1)
844         g_value_set_boolean (value, priv->child1_resize);
845       else
846         g_value_set_boolean (value, priv->child2_resize);
847       break;
848     case CHILD_PROP_SHRINK:
849       if (child == priv->child1)
850         g_value_set_boolean (value, priv->child1_shrink);
851       else
852         g_value_set_boolean (value, priv->child2_shrink);
853       break;
854     default:
855       GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
856       break;
857     }
858 }
859
860 static void
861 gtk_paned_finalize (GObject *object)
862 {
863   GtkPaned *paned = GTK_PANED (object);
864   
865   gtk_paned_set_saved_focus (paned, NULL);
866   gtk_paned_set_first_paned (paned, NULL);
867
868   G_OBJECT_CLASS (gtk_paned_parent_class)->finalize (object);
869 }
870
871 static void
872 get_preferred_size_for_size (GtkWidget      *widget,
873                              GtkOrientation  orientation,
874                              gint            size,
875                              gint           *minimum,
876                              gint           *natural)
877 {
878   if (orientation == GTK_ORIENTATION_HORIZONTAL)
879     if (size < 0)
880       gtk_widget_get_preferred_width (widget, minimum, natural);
881     else
882       gtk_widget_get_preferred_width_for_height (widget, size, minimum, natural);
883   else
884     if (size < 0)
885       gtk_widget_get_preferred_height (widget, minimum, natural);
886     else
887       gtk_widget_get_preferred_height_for_width (widget, size, minimum, natural);
888 }
889
890 static void
891 gtk_paned_get_preferred_size (GtkWidget      *widget,
892                               GtkOrientation  orientation,
893                               gint            size,
894                               gint           *minimum,
895                               gint           *natural)
896 {
897   GtkPaned *paned = GTK_PANED (widget);
898   GtkPanedPrivate *priv = paned->priv;
899   gint child_min, child_nat;
900
901   *minimum = *natural = 0;
902
903   if (priv->child1 && gtk_widget_get_visible (priv->child1))
904     {
905       get_preferred_size_for_size (priv->child1, orientation, size, &child_min, &child_nat);
906       *minimum = child_min;
907       *natural = child_nat;
908     }
909
910   if (priv->child2 && gtk_widget_get_visible (priv->child2))
911     {
912       get_preferred_size_for_size (priv->child2, orientation, size, &child_min, &child_nat);
913
914       if (priv->orientation == orientation)
915         {
916           *minimum += child_min;
917           *natural += child_nat;
918         }
919       else
920         {
921           *minimum = MAX (*minimum, child_min);
922           *natural = MAX (*natural, child_nat);
923         }
924     }
925
926   if (priv->child1 && gtk_widget_get_visible (priv->child1) &&
927       priv->child2 && gtk_widget_get_visible (priv->child2))
928     {
929       gint handle_size;
930
931       gtk_widget_style_get (widget, "handle-size", &handle_size, NULL);
932
933       if (priv->orientation == orientation)
934         {
935           *minimum += handle_size;
936           *natural += handle_size;
937         }
938     }
939 }
940
941 static void
942 gtk_paned_get_preferred_width (GtkWidget *widget,
943                                gint      *minimum,
944                                gint      *natural)
945 {
946   gtk_paned_get_preferred_size (widget, GTK_ORIENTATION_HORIZONTAL, -1, minimum, natural);
947 }
948
949 static void
950 gtk_paned_get_preferred_height (GtkWidget *widget,
951                                 gint      *minimum,
952                                 gint      *natural)
953 {
954   gtk_paned_get_preferred_size (widget, GTK_ORIENTATION_VERTICAL, -1, minimum, natural);
955 }
956
957 static void
958 gtk_paned_get_preferred_width_for_height (GtkWidget *widget,
959                                           gint       height,
960                                           gint      *minimum,
961                                           gint      *natural)
962 {
963   gtk_paned_get_preferred_size (widget, GTK_ORIENTATION_HORIZONTAL, height, minimum, natural);
964 }
965
966 static void
967 gtk_paned_get_preferred_height_for_width (GtkWidget *widget,
968                                           gint       width,
969                                           gint      *minimum,
970                                           gint      *natural)
971 {
972   gtk_paned_get_preferred_size (widget, GTK_ORIENTATION_VERTICAL, width, minimum, natural);
973 }
974
975 static void
976 flip_child (GtkWidget     *widget,
977             GtkAllocation *child_pos)
978 {
979   GtkAllocation allocation;
980   gint x, width;
981
982   gtk_widget_get_allocation (widget, &allocation);
983   x = allocation.x;
984   width = allocation.width;
985
986   child_pos->x = 2 * x + width - child_pos->x - child_pos->width;
987 }
988
989 static void
990 gtk_paned_set_child_visible (GtkPaned  *paned,
991                              guint      id,
992                              gboolean   visible)
993 {
994   GtkPanedPrivate *priv = paned->priv;
995   GtkWidget *child;
996
997   child = id == CHILD1 ? priv->child1 : priv->child2;
998
999   if (child == NULL)
1000     return;
1001
1002   gtk_widget_set_child_visible (child, visible);
1003
1004   if (gtk_widget_get_mapped (GTK_WIDGET (paned)))
1005     {
1006       GdkWindow *window = id == CHILD1 ? priv->child1_window : priv->child2_window;
1007
1008       if (visible != gdk_window_is_visible (window))
1009         {
1010           if (visible)
1011             gdk_window_show (window);
1012           else
1013             gdk_window_hide (window);
1014         }
1015     }
1016 }
1017
1018 static void
1019 gtk_paned_child_allocate (GtkWidget           *child,
1020                           GdkWindow           *child_window, /* can be NULL */
1021                           const GtkAllocation *window_allocation,
1022                           GtkAllocation       *child_allocation)
1023 {
1024   if (child_window)
1025     gdk_window_move_resize (child_window,
1026                             window_allocation->x, window_allocation->y,
1027                             window_allocation->width, window_allocation->height);
1028
1029   gtk_widget_size_allocate (child, child_allocation);
1030 }
1031
1032 static void
1033 gtk_paned_size_allocate (GtkWidget     *widget,
1034                          GtkAllocation *allocation)
1035 {
1036   GtkPaned *paned = GTK_PANED (widget);
1037   GtkPanedPrivate *priv = paned->priv;
1038
1039   gtk_widget_set_allocation (widget, allocation);
1040
1041   if (priv->child1 && gtk_widget_get_visible (priv->child1) &&
1042       priv->child2 && gtk_widget_get_visible (priv->child2))
1043     {
1044       GtkAllocation child1_allocation, window1_allocation;
1045       GtkAllocation child2_allocation, window2_allocation;
1046       GtkAllocation priv_child1_allocation;
1047       GdkRectangle old_handle_pos;
1048       gint handle_size;
1049
1050       gtk_widget_style_get (widget, "handle-size", &handle_size, NULL);
1051
1052       old_handle_pos = priv->handle_pos;
1053
1054       if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
1055         {
1056           gint child1_width, child2_width;
1057
1058           gtk_widget_get_preferred_width_for_height (priv->child1,
1059                                                      allocation->height,
1060                                                      &child1_width, NULL);
1061           gtk_widget_get_preferred_width_for_height (priv->child2,
1062                                                      allocation->height,
1063                                                      &child2_width, NULL);
1064
1065           gtk_paned_calc_position (paned,
1066                                    MAX (1, allocation->width - handle_size),
1067                                    child1_width,
1068                                    child2_width);
1069
1070           priv->handle_pos.x = allocation->x + priv->child1_size;
1071           priv->handle_pos.y = allocation->y;
1072           priv->handle_pos.width = handle_size;
1073           priv->handle_pos.height = allocation->height;
1074
1075           window1_allocation.height = window2_allocation.height = allocation->height;
1076           window1_allocation.width = MAX (1, priv->child1_size);
1077           window1_allocation.x = allocation->x;
1078           window1_allocation.y = window2_allocation.y = allocation->y;
1079
1080           window2_allocation.x = window1_allocation.x + priv->child1_size + priv->handle_pos.width;
1081           window2_allocation.width = MAX (1, allocation->x + allocation->width - window2_allocation.x);
1082
1083           if (gtk_widget_get_direction (GTK_WIDGET (widget)) == GTK_TEXT_DIR_RTL)
1084             {
1085               flip_child (widget, &(window2_allocation));
1086               flip_child (widget, &(window1_allocation));
1087               flip_child (widget, &(priv->handle_pos));
1088             }
1089
1090           child1_allocation.x = child1_allocation.y = 0;
1091           child1_allocation.width = window1_allocation.width;
1092           child1_allocation.height = window1_allocation.height;
1093           if (child1_width > child1_allocation.width)
1094             {
1095               if (gtk_widget_get_direction (GTK_WIDGET (widget)) == GTK_TEXT_DIR_LTR)
1096                 child1_allocation.x -= child1_width - child1_allocation.width;
1097               child1_allocation.width = child1_width;
1098             }
1099
1100           child2_allocation.x = child2_allocation.y = 0;
1101           child2_allocation.width = window2_allocation.width;
1102           child2_allocation.height = window2_allocation.height;
1103           if (child2_width > child2_allocation.width)
1104             {
1105               if (gtk_widget_get_direction (GTK_WIDGET (widget)) == GTK_TEXT_DIR_RTL)
1106                 child2_allocation.x -= child2_width - child2_allocation.width;
1107               child2_allocation.width = child2_width;
1108             }
1109         }
1110       else
1111         {
1112           gint child1_height, child2_height;
1113
1114           gtk_widget_get_preferred_height_for_width (priv->child1,
1115                                                      allocation->width,
1116                                                      &child1_height, NULL);
1117           gtk_widget_get_preferred_height_for_width (priv->child2,
1118                                                      allocation->width,
1119                                                      &child2_height, NULL);
1120
1121           gtk_paned_calc_position (paned,
1122                                    MAX (1, allocation->height - handle_size),
1123                                    child1_height,
1124                                    child2_height);
1125
1126           priv->handle_pos.x = allocation->x;
1127           priv->handle_pos.y = allocation->y + priv->child1_size;
1128           priv->handle_pos.width = allocation->width;
1129           priv->handle_pos.height = handle_size;
1130
1131           window1_allocation.width = window2_allocation.width = allocation->width;
1132           window1_allocation.height = MAX (1, priv->child1_size);
1133           window1_allocation.x = window2_allocation.x = allocation->x;
1134           window1_allocation.y = allocation->y;
1135
1136           window2_allocation.y = window1_allocation.y + priv->child1_size + priv->handle_pos.height;
1137           window2_allocation.height = MAX (1, allocation->y + allocation->height - window2_allocation.y);
1138
1139           child1_allocation.x = child1_allocation.y = 0;
1140           child1_allocation.width = window1_allocation.width;
1141           child1_allocation.height = window1_allocation.height;
1142           if (child1_height > child1_allocation.height)
1143             {
1144               child1_allocation.y -= child1_height - child1_allocation.height;
1145               child1_allocation.height = child1_height;
1146             }
1147
1148           child2_allocation.x = child2_allocation.y = 0;
1149           child2_allocation.width = window2_allocation.width;
1150           child2_allocation.height = window2_allocation.height;
1151           if (child2_height > child2_allocation.height)
1152             child2_allocation.height = child2_height;
1153         }
1154
1155       if (gtk_widget_get_mapped (widget) &&
1156           (old_handle_pos.x != priv->handle_pos.x ||
1157            old_handle_pos.y != priv->handle_pos.y ||
1158            old_handle_pos.width != priv->handle_pos.width ||
1159            old_handle_pos.height != priv->handle_pos.height))
1160         {
1161           GdkWindow *window;
1162
1163           window = gtk_widget_get_window (widget);
1164           gdk_window_invalidate_rect (window, &old_handle_pos, FALSE);
1165           gdk_window_invalidate_rect (window, &priv->handle_pos, FALSE);
1166         }
1167
1168       if (gtk_widget_get_realized (widget))
1169         {
1170           if (gtk_widget_get_mapped (widget))
1171             gdk_window_show (priv->handle);
1172
1173           if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
1174             {
1175               gdk_window_move_resize (priv->handle,
1176                                       priv->handle_pos.x,
1177                                       priv->handle_pos.y,
1178                                       handle_size,
1179                                       priv->handle_pos.height);
1180             }
1181           else
1182             {
1183               gdk_window_move_resize (priv->handle,
1184                                       priv->handle_pos.x,
1185                                       priv->handle_pos.y,
1186                                       priv->handle_pos.width,
1187                                       handle_size);
1188             }
1189         }
1190
1191       /* Now allocate the childen, making sure, when resizing not to
1192        * overlap the windows
1193        */
1194       gtk_widget_get_allocation (priv->child1, &priv_child1_allocation);
1195       if (gtk_widget_get_mapped (widget) &&
1196           ((priv->orientation == GTK_ORIENTATION_HORIZONTAL &&
1197             priv_child1_allocation.width < child1_allocation.width) ||
1198
1199            (priv->orientation == GTK_ORIENTATION_VERTICAL &&
1200             priv_child1_allocation.height < child1_allocation.height)))
1201         {
1202           gtk_paned_child_allocate (priv->child2,
1203                                     priv->child2_window,
1204                                     &window2_allocation,
1205                                     &child2_allocation);
1206           gtk_paned_child_allocate (priv->child1,
1207                                     priv->child1_window,
1208                                     &window1_allocation,
1209                                     &child1_allocation);
1210         }
1211       else
1212         {
1213           gtk_paned_child_allocate (priv->child1,
1214                                     priv->child1_window,
1215                                     &window1_allocation,
1216                                     &child1_allocation);
1217           gtk_paned_child_allocate (priv->child2,
1218                                     priv->child2_window,
1219                                     &window2_allocation,
1220                                     &child2_allocation);
1221         }
1222     }
1223   else
1224     {
1225       GtkAllocation window_allocation, child_allocation;
1226
1227       if (gtk_widget_get_realized (widget))
1228         gdk_window_hide (priv->handle);
1229
1230       window_allocation.x = allocation->x;
1231       window_allocation.y = allocation->y;
1232       window_allocation.width = allocation->width;
1233       window_allocation.height = allocation->height;
1234       child_allocation.x = child_allocation.y = 0;
1235       child_allocation.width = allocation->width;
1236       child_allocation.height = allocation->height;
1237
1238       if (priv->child1 && gtk_widget_get_visible (priv->child1))
1239         {
1240           gtk_paned_set_child_visible (paned, 0, TRUE);
1241           if (priv->child2)
1242             gtk_paned_set_child_visible (paned, 1, FALSE);
1243
1244           gtk_paned_child_allocate (priv->child1,
1245                                     priv->child1_window,
1246                                     &window_allocation,
1247                                     &child_allocation);
1248         }
1249       else if (priv->child2 && gtk_widget_get_visible (priv->child2))
1250         {
1251           gtk_paned_set_child_visible (paned, 1, TRUE);
1252           if (priv->child1)
1253             gtk_paned_set_child_visible (paned, 0, FALSE);
1254
1255           gtk_paned_child_allocate (priv->child2,
1256                                     priv->child2_window,
1257                                     &window_allocation,
1258                                     &child_allocation);
1259         }
1260       else
1261         {
1262           if (priv->child1)
1263             gtk_paned_set_child_visible (paned, 0, FALSE);
1264           if (priv->child2)
1265             gtk_paned_set_child_visible (paned, 1, FALSE);
1266         }
1267     }
1268 }
1269
1270 static GdkWindow *
1271 gtk_paned_create_child_window (GtkPaned  *paned,
1272                                GtkWidget *child) /* may be NULL */
1273 {
1274   GtkWidget *widget = GTK_WIDGET (paned);
1275   GtkPanedPrivate *priv = paned->priv;
1276   GdkWindow *window;
1277   GdkWindowAttr attributes;
1278   gint attributes_mask;
1279
1280   attributes.window_type = GDK_WINDOW_CHILD;
1281   attributes.wclass = GDK_INPUT_OUTPUT;
1282   attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK;
1283   if (child)
1284     {
1285       GtkAllocation allocation;
1286       int handle_size;
1287
1288       gtk_widget_style_get (widget, "handle-size", &handle_size, NULL);
1289
1290       gtk_widget_get_allocation (widget, &allocation);
1291       if (priv->orientation == GTK_ORIENTATION_HORIZONTAL &&
1292           child == priv->child2 && priv->child1 &&
1293           gtk_widget_get_visible (priv->child1))
1294         attributes.x = priv->handle_pos.x + handle_size;
1295       else
1296         attributes.x = allocation.x;
1297       if (priv->orientation == GTK_ORIENTATION_VERTICAL &&
1298           child == priv->child2 && priv->child1 &&
1299           gtk_widget_get_visible (priv->child1))
1300         attributes.y = priv->handle_pos.y + handle_size;
1301       else
1302         attributes.y = allocation.y;
1303
1304       gtk_widget_get_allocation (child, &allocation);
1305       attributes.width = allocation.width;
1306       attributes.height = allocation.height;
1307       attributes_mask = GDK_WA_X | GDK_WA_Y;
1308     }
1309   else
1310     {
1311       attributes.width = 1;
1312       attributes.height = 1;
1313       attributes_mask = 0;
1314     }
1315
1316   window = gdk_window_new (gtk_widget_get_window (widget),
1317                            &attributes, attributes_mask);
1318   gdk_window_set_user_data (window, paned);
1319   gtk_style_context_set_background (gtk_widget_get_style_context (widget), window);
1320
1321   if (child)
1322     gtk_widget_set_parent_window (child, window);
1323
1324   return window;
1325 }
1326
1327 static void
1328 gtk_paned_realize (GtkWidget *widget)
1329 {
1330   GtkPaned *paned = GTK_PANED (widget);
1331   GtkPanedPrivate *priv = paned->priv;
1332   GdkWindow *window;
1333   GdkWindowAttr attributes;
1334   gint attributes_mask;
1335
1336   gtk_widget_set_realized (widget, TRUE);
1337
1338   window = gtk_widget_get_parent_window (widget);
1339   gtk_widget_set_window (widget, window);
1340   g_object_ref (window);
1341
1342   attributes.window_type = GDK_WINDOW_CHILD;
1343   attributes.wclass = GDK_INPUT_ONLY;
1344   attributes.x = priv->handle_pos.x;
1345   attributes.y = priv->handle_pos.y;
1346   attributes.width = priv->handle_pos.width;
1347   attributes.height = priv->handle_pos.height;
1348   attributes.event_mask = gtk_widget_get_events (widget);
1349   attributes.event_mask |= (GDK_BUTTON_PRESS_MASK |
1350                             GDK_BUTTON_RELEASE_MASK |
1351                             GDK_ENTER_NOTIFY_MASK |
1352                             GDK_LEAVE_NOTIFY_MASK |
1353                             GDK_POINTER_MOTION_MASK);
1354   attributes_mask = GDK_WA_X | GDK_WA_Y;
1355   if (gtk_widget_is_sensitive (widget))
1356     {
1357       attributes.cursor = gdk_cursor_new_for_display (gtk_widget_get_display (widget),
1358                                                       priv->cursor_type);
1359       attributes_mask |= GDK_WA_CURSOR;
1360     }
1361
1362   priv->handle = gdk_window_new (window,
1363                                  &attributes, attributes_mask);
1364   gdk_window_set_user_data (priv->handle, paned);
1365   if (attributes_mask & GDK_WA_CURSOR)
1366     g_object_unref (attributes.cursor);
1367
1368   priv->child1_window = gtk_paned_create_child_window (paned, priv->child1);
1369   priv->child2_window = gtk_paned_create_child_window (paned, priv->child2);
1370 }
1371
1372 static void
1373 gtk_paned_unrealize (GtkWidget *widget)
1374 {
1375   GtkPaned *paned = GTK_PANED (widget);
1376   GtkPanedPrivate *priv = paned->priv;
1377
1378   if (priv->child2)
1379     gtk_widget_set_parent_window (priv->child2, NULL);
1380   gdk_window_set_user_data (priv->child2_window, NULL);
1381   gdk_window_destroy (priv->child2_window);
1382   priv->child2_window = NULL;
1383
1384   if (priv->child1)
1385     gtk_widget_set_parent_window (priv->child1, NULL);
1386   gdk_window_set_user_data (priv->child1_window, NULL);
1387   gdk_window_destroy (priv->child1_window);
1388   priv->child1_window = NULL;
1389
1390   if (priv->handle)
1391     {
1392       gdk_window_set_user_data (priv->handle, NULL);
1393       gdk_window_destroy (priv->handle);
1394       priv->handle = NULL;
1395     }
1396
1397   gtk_paned_set_last_child1_focus (paned, NULL);
1398   gtk_paned_set_last_child2_focus (paned, NULL);
1399   gtk_paned_set_saved_focus (paned, NULL);
1400   gtk_paned_set_first_paned (paned, NULL);
1401
1402   GTK_WIDGET_CLASS (gtk_paned_parent_class)->unrealize (widget);
1403 }
1404
1405 static void
1406 gtk_paned_map (GtkWidget *widget)
1407 {
1408   GtkPaned *paned = GTK_PANED (widget);
1409   GtkPanedPrivate *priv = paned->priv;
1410
1411   if (priv->child1 && gtk_widget_get_visible (priv->child1) &&
1412       priv->child2 && gtk_widget_get_visible (priv->child2))
1413     gdk_window_show (priv->handle);
1414
1415   if (priv->child1 && gtk_widget_get_visible (priv->child1) && gtk_widget_get_child_visible (priv->child1))
1416     gdk_window_show (priv->child1_window);
1417   if (priv->child2 && gtk_widget_get_visible (priv->child2) && gtk_widget_get_child_visible (priv->child2))
1418     gdk_window_show (priv->child2_window);
1419
1420   GTK_WIDGET_CLASS (gtk_paned_parent_class)->map (widget);
1421 }
1422
1423 static void
1424 gtk_paned_unmap (GtkWidget *widget)
1425 {
1426   GtkPaned *paned = GTK_PANED (widget);
1427   GtkPanedPrivate *priv = paned->priv;
1428
1429   gdk_window_hide (priv->handle);
1430   
1431   if (gdk_window_is_visible (priv->child1_window))
1432     gdk_window_hide (priv->child1_window);
1433   if (gdk_window_is_visible (priv->child2_window))
1434     gdk_window_hide (priv->child2_window);
1435
1436   GTK_WIDGET_CLASS (gtk_paned_parent_class)->unmap (widget);
1437 }
1438
1439 static gboolean
1440 gtk_paned_draw (GtkWidget *widget,
1441                 cairo_t   *cr)
1442 {
1443   GtkPaned *paned = GTK_PANED (widget);
1444   GtkPanedPrivate *priv = paned->priv;
1445
1446   if (gtk_cairo_should_draw_window (cr, priv->child1_window))
1447     {
1448       cairo_save (cr);
1449       gtk_cairo_transform_to_window (cr, widget, priv->child1_window);
1450       gtk_render_background (gtk_widget_get_style_context (widget),
1451                              cr,
1452                              0, 0,
1453                              gdk_window_get_width (priv->child1_window),
1454                              gdk_window_get_height (priv->child1_window));
1455       cairo_restore (cr);
1456     }
1457
1458   if (gtk_cairo_should_draw_window (cr, priv->child2_window))
1459     {
1460       cairo_save (cr);
1461       gtk_cairo_transform_to_window (cr, widget, priv->child2_window);
1462       gtk_render_background (gtk_widget_get_style_context (widget),
1463                              cr,
1464                              0, 0,
1465                              gdk_window_get_width (priv->child2_window),
1466                              gdk_window_get_height (priv->child2_window));
1467       cairo_restore (cr);
1468     }
1469
1470   if (gtk_cairo_should_draw_window (cr, gtk_widget_get_window (widget)) &&
1471       priv->child1 && gtk_widget_get_visible (priv->child1) &&
1472       priv->child2 && gtk_widget_get_visible (priv->child2))
1473     {
1474       GtkStyleContext *context;
1475       GtkStateFlags state;
1476       GtkAllocation allocation;
1477
1478       gtk_widget_get_allocation (widget, &allocation);
1479       context = gtk_widget_get_style_context (widget);
1480       state = gtk_widget_get_state_flags (widget);
1481
1482       if (gtk_widget_is_focus (widget))
1483         state |= GTK_STATE_FLAG_SELECTED;
1484       if (priv->handle_prelit)
1485         state |= GTK_STATE_FLAG_PRELIGHT;
1486
1487       gtk_style_context_save (context);
1488       gtk_style_context_set_state (context, state);
1489       gtk_style_context_add_class (context, GTK_STYLE_CLASS_PANE_SEPARATOR);
1490       gtk_render_handle (context, cr,
1491                          priv->handle_pos.x - allocation.x,
1492                          priv->handle_pos.y - allocation.y,
1493                          priv->handle_pos.width,
1494                          priv->handle_pos.height);
1495
1496       gtk_style_context_restore (context);
1497     }
1498
1499   /* Chain up to draw children */
1500   GTK_WIDGET_CLASS (gtk_paned_parent_class)->draw (widget, cr);
1501   
1502   return FALSE;
1503 }
1504
1505 static gboolean
1506 is_rtl (GtkPaned *paned)
1507 {
1508   GtkPanedPrivate *priv = paned->priv;
1509
1510   if (priv->orientation == GTK_ORIENTATION_HORIZONTAL &&
1511       gtk_widget_get_direction (GTK_WIDGET (paned)) == GTK_TEXT_DIR_RTL)
1512     {
1513       return TRUE;
1514     }
1515
1516   return FALSE;
1517 }
1518
1519 static void
1520 update_drag (GtkPaned         *paned,
1521              /* relative to priv->handle */
1522              int               xpos,
1523              int               ypos)
1524 {
1525   GtkPanedPrivate *priv = paned->priv;
1526   GtkAllocation allocation;
1527   GtkWidget *widget = GTK_WIDGET (paned);
1528   gint pos;
1529   gint handle_size;
1530   gint size;
1531   gint x, y;
1532
1533   gdk_window_get_position (priv->handle, &x, &y);
1534   gtk_widget_get_allocation (widget, &allocation);
1535   if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
1536     {
1537       pos = xpos + x - allocation.x;
1538     }
1539   else
1540     {
1541       pos = ypos + y - allocation.y;
1542     }
1543
1544   pos -= priv->drag_pos;
1545
1546   if (is_rtl (paned))
1547     {
1548       gtk_widget_style_get (widget,
1549                             "handle-size", &handle_size,
1550                             NULL);
1551
1552       size = allocation.width - pos - handle_size;
1553     }
1554   else
1555     {
1556       size = pos;
1557     }
1558
1559   size = CLAMP (size, priv->min_position, priv->max_position);
1560
1561   if (size != priv->child1_size)
1562     gtk_paned_set_position (paned, size);
1563 }
1564
1565 static gboolean
1566 gtk_paned_enter (GtkWidget        *widget,
1567                  GdkEventCrossing *event)
1568 {
1569   GtkPaned *paned = GTK_PANED (widget);
1570   GtkPanedPrivate *priv = paned->priv;
1571
1572   if (priv->in_drag)
1573     update_drag (paned, event->x, event->y);
1574   else
1575     {
1576       priv->handle_prelit = TRUE;
1577       gtk_widget_queue_draw_area (widget,
1578                                   priv->handle_pos.x,
1579                                   priv->handle_pos.y,
1580                                   priv->handle_pos.width,
1581                                   priv->handle_pos.height);
1582     }
1583   
1584   return TRUE;
1585 }
1586
1587 static gboolean
1588 gtk_paned_leave (GtkWidget        *widget,
1589                  GdkEventCrossing *event)
1590 {
1591   GtkPaned *paned = GTK_PANED (widget);
1592   GtkPanedPrivate *priv = paned->priv;
1593
1594   if (priv->in_drag)
1595     update_drag (paned, event->x, event->y);
1596   else
1597     {
1598       priv->handle_prelit = FALSE;
1599       gtk_widget_queue_draw_area (widget,
1600                                   priv->handle_pos.x,
1601                                   priv->handle_pos.y,
1602                                   priv->handle_pos.width,
1603                                   priv->handle_pos.height);
1604     }
1605
1606   return TRUE;
1607 }
1608
1609 static gboolean
1610 gtk_paned_focus (GtkWidget        *widget,
1611                  GtkDirectionType  direction)
1612
1613 {
1614   gboolean retval;
1615   
1616   /* This is a hack, but how can this be done without
1617    * excessive cut-and-paste from gtkcontainer.c?
1618    */
1619
1620   gtk_widget_set_can_focus (widget, FALSE);
1621   retval = GTK_WIDGET_CLASS (gtk_paned_parent_class)->focus (widget, direction);
1622   gtk_widget_set_can_focus (widget, TRUE);
1623
1624   return retval;
1625 }
1626
1627 static gboolean
1628 gtk_paned_button_press (GtkWidget      *widget,
1629                         GdkEventButton *event)
1630 {
1631   GtkPaned *paned = GTK_PANED (widget);
1632   GtkPanedPrivate *priv = paned->priv;
1633
1634   if (!priv->in_drag &&
1635       (event->window == priv->handle) && (event->button == GDK_BUTTON_PRIMARY))
1636     {
1637       /* We need a server grab here, not gtk_grab_add(), since
1638        * we don't want to pass events on to the widget's children */
1639       if (gdk_device_grab (event->device,
1640                            priv->handle,
1641                            GDK_OWNERSHIP_WINDOW, FALSE,
1642                            GDK_BUTTON1_MOTION_MASK
1643                            | GDK_BUTTON_RELEASE_MASK
1644                            | GDK_ENTER_NOTIFY_MASK
1645                            | GDK_LEAVE_NOTIFY_MASK,
1646                            NULL, event->time) != GDK_GRAB_SUCCESS)
1647         return FALSE;
1648
1649       priv->in_drag = TRUE;
1650       priv->grab_time = event->time;
1651       priv->grab_device = event->device;
1652
1653       if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
1654         priv->drag_pos = event->x;
1655       else
1656         priv->drag_pos = event->y;
1657
1658       return TRUE;
1659     }
1660
1661   return FALSE;
1662 }
1663
1664 static gboolean
1665 gtk_paned_grab_broken (GtkWidget          *widget,
1666                        GdkEventGrabBroken *event)
1667 {
1668   GtkPaned *paned = GTK_PANED (widget);
1669   GtkPanedPrivate *priv = paned->priv;
1670
1671   priv->in_drag = FALSE;
1672   priv->drag_pos = -1;
1673   priv->position_set = TRUE;
1674
1675   return TRUE;
1676 }
1677
1678 static void
1679 stop_drag (GtkPaned *paned)
1680 {
1681   GtkPanedPrivate *priv = paned->priv;
1682
1683   priv->in_drag = FALSE;
1684   priv->drag_pos = -1;
1685   priv->position_set = TRUE;
1686
1687   gdk_device_ungrab (priv->grab_device,
1688                      priv->grab_time);
1689   priv->grab_device = NULL;
1690 }
1691
1692 static void
1693 gtk_paned_grab_notify (GtkWidget *widget,
1694                        gboolean   was_grabbed)
1695 {
1696   GtkPaned *paned = GTK_PANED (widget);
1697   GtkPanedPrivate *priv = paned->priv;
1698   GdkDevice *grab_device;
1699
1700   grab_device = priv->grab_device;
1701
1702   if (priv->in_drag && grab_device &&
1703       gtk_widget_device_is_shadowed (widget, grab_device))
1704     stop_drag (paned);
1705 }
1706
1707 static void
1708 gtk_paned_state_flags_changed (GtkWidget     *widget,
1709                                GtkStateFlags  previous_state)
1710 {
1711   GtkPaned *paned = GTK_PANED (widget);
1712   GtkPanedPrivate *priv = paned->priv;
1713   GdkCursor *cursor;
1714
1715   if (gtk_widget_get_realized (widget))
1716     {
1717       if (gtk_widget_is_sensitive (widget))
1718         cursor = gdk_cursor_new_for_display (gtk_widget_get_display (widget),
1719                                              priv->cursor_type);
1720       else
1721         cursor = NULL;
1722
1723       gdk_window_set_cursor (priv->handle, cursor);
1724
1725       if (cursor)
1726         g_object_unref (cursor);
1727     }
1728 }
1729
1730 static gboolean
1731 gtk_paned_button_release (GtkWidget      *widget,
1732                           GdkEventButton *event)
1733 {
1734   GtkPaned *paned = GTK_PANED (widget);
1735   GtkPanedPrivate *priv = paned->priv;
1736
1737   if (priv->in_drag && (event->button == GDK_BUTTON_PRIMARY))
1738     {
1739       stop_drag (paned);
1740
1741       return TRUE;
1742     }
1743
1744   return FALSE;
1745 }
1746
1747 static gboolean
1748 gtk_paned_motion (GtkWidget      *widget,
1749                   GdkEventMotion *event)
1750 {
1751   GtkPaned *paned = GTK_PANED (widget);
1752   GtkPanedPrivate *priv = paned->priv;
1753
1754   if (priv->in_drag)
1755     {
1756       update_drag (paned, event->x, event->y);
1757       return TRUE;
1758     }
1759   
1760   return FALSE;
1761 }
1762
1763 /**
1764  * gtk_paned_new:
1765  * @orientation: the paned's orientation.
1766  *
1767  * Creates a new #GtkPaned widget.
1768  *
1769  * Return value: a new #GtkPaned.
1770  *
1771  * Since: 3.0
1772  **/
1773 GtkWidget *
1774 gtk_paned_new (GtkOrientation orientation)
1775 {
1776   return g_object_new (GTK_TYPE_PANED,
1777                        "orientation", orientation,
1778                        NULL);
1779 }
1780
1781 /**
1782  * gtk_paned_add1:
1783  * @paned: a paned widget
1784  * @child: the child to add
1785  *
1786  * Adds a child to the top or left pane with default parameters. This is
1787  * equivalent to
1788  * <literal>gtk_paned_pack1 (paned, child, FALSE, TRUE)</literal>.
1789  */
1790 void
1791 gtk_paned_add1 (GtkPaned  *paned,
1792                 GtkWidget *widget)
1793 {
1794   gtk_paned_pack1 (paned, widget, FALSE, TRUE);
1795 }
1796
1797 /**
1798  * gtk_paned_add2:
1799  * @paned: a paned widget
1800  * @child: the child to add
1801  *
1802  * Adds a child to the bottom or right pane with default parameters. This
1803  * is equivalent to
1804  * <literal>gtk_paned_pack2 (paned, child, TRUE, TRUE)</literal>.
1805  */
1806 void
1807 gtk_paned_add2 (GtkPaned  *paned,
1808                 GtkWidget *widget)
1809 {
1810   gtk_paned_pack2 (paned, widget, TRUE, TRUE);
1811 }
1812
1813 /**
1814  * gtk_paned_pack1:
1815  * @paned: a paned widget
1816  * @child: the child to add
1817  * @resize: should this child expand when the paned widget is resized.
1818  * @shrink: can this child be made smaller than its requisition.
1819  *
1820  * Adds a child to the top or left pane.
1821  */
1822 void
1823 gtk_paned_pack1 (GtkPaned  *paned,
1824                  GtkWidget *child,
1825                  gboolean   resize,
1826                  gboolean   shrink)
1827 {
1828   GtkPanedPrivate *priv;
1829
1830   g_return_if_fail (GTK_IS_PANED (paned));
1831   g_return_if_fail (GTK_IS_WIDGET (child));
1832
1833   priv = paned->priv;
1834
1835   if (!priv->child1)
1836     {
1837       priv->child1 = child;
1838       priv->child1_resize = resize;
1839       priv->child1_shrink = shrink;
1840
1841       gtk_widget_set_parent_window (child, priv->child1_window);
1842       gtk_widget_set_parent (child, GTK_WIDGET (paned));
1843     }
1844 }
1845
1846 /**
1847  * gtk_paned_pack2:
1848  * @paned: a paned widget
1849  * @child: the child to add
1850  * @resize: should this child expand when the paned widget is resized.
1851  * @shrink: can this child be made smaller than its requisition.
1852  *
1853  * Adds a child to the bottom or right pane.
1854  */
1855 void
1856 gtk_paned_pack2 (GtkPaned  *paned,
1857                  GtkWidget *child,
1858                  gboolean   resize,
1859                  gboolean   shrink)
1860 {
1861   GtkPanedPrivate *priv;
1862
1863   g_return_if_fail (GTK_IS_PANED (paned));
1864   g_return_if_fail (GTK_IS_WIDGET (child));
1865
1866   priv = paned->priv;
1867
1868   if (!priv->child2)
1869     {
1870       priv->child2 = child;
1871       priv->child2_resize = resize;
1872       priv->child2_shrink = shrink;
1873
1874       gtk_widget_set_parent_window (child, priv->child2_window);
1875       gtk_widget_set_parent (child, GTK_WIDGET (paned));
1876     }
1877 }
1878
1879
1880 static void
1881 gtk_paned_add (GtkContainer *container,
1882                GtkWidget    *widget)
1883 {
1884   GtkPanedPrivate *priv;
1885   GtkPaned *paned;
1886
1887   g_return_if_fail (GTK_IS_PANED (container));
1888
1889   paned = GTK_PANED (container);
1890   priv = paned->priv;
1891
1892   if (!priv->child1)
1893     gtk_paned_add1 (paned, widget);
1894   else if (!priv->child2)
1895     gtk_paned_add2 (paned, widget);
1896   else
1897     g_warning ("GtkPaned cannot have more than 2 children\n");
1898 }
1899
1900 static void
1901 gtk_paned_remove (GtkContainer *container,
1902                   GtkWidget    *widget)
1903 {
1904   GtkPaned *paned = GTK_PANED (container);
1905   GtkPanedPrivate *priv = paned->priv;
1906   gboolean was_visible;
1907
1908   was_visible = gtk_widget_get_visible (widget);
1909
1910   if (priv->child1 == widget)
1911     {
1912       if (priv->child1_window && gdk_window_is_visible (priv->child1_window))
1913         gdk_window_hide (priv->child1_window);
1914
1915       gtk_widget_unparent (widget);
1916
1917       priv->child1 = NULL;
1918
1919       if (was_visible && gtk_widget_get_visible (GTK_WIDGET (container)))
1920         gtk_widget_queue_resize_no_redraw (GTK_WIDGET (container));
1921     }
1922   else if (priv->child2 == widget)
1923     {
1924       if (priv->child2_window && gdk_window_is_visible (priv->child2_window))
1925         gdk_window_hide (priv->child2_window);
1926
1927       gtk_widget_unparent (widget);
1928
1929       priv->child2 = NULL;
1930
1931       if (was_visible && gtk_widget_get_visible (GTK_WIDGET (container)))
1932         gtk_widget_queue_resize_no_redraw (GTK_WIDGET (container));
1933     }
1934 }
1935
1936 static void
1937 gtk_paned_forall (GtkContainer *container,
1938                   gboolean      include_internals,
1939                   GtkCallback   callback,
1940                   gpointer      callback_data)
1941 {
1942   GtkPanedPrivate *priv;
1943   GtkPaned *paned;
1944
1945   g_return_if_fail (callback != NULL);
1946
1947   paned = GTK_PANED (container);
1948   priv = paned->priv;
1949
1950   if (priv->child1)
1951     (*callback) (priv->child1, callback_data);
1952   if (priv->child2)
1953     (*callback) (priv->child2, callback_data);
1954 }
1955
1956 /**
1957  * gtk_paned_get_position:
1958  * @paned: a #GtkPaned widget
1959  * 
1960  * Obtains the position of the divider between the two panes.
1961  * 
1962  * Return value: position of the divider
1963  **/
1964 gint
1965 gtk_paned_get_position (GtkPaned  *paned)
1966 {
1967   g_return_val_if_fail (GTK_IS_PANED (paned), 0);
1968
1969   return paned->priv->child1_size;
1970 }
1971
1972 /**
1973  * gtk_paned_set_position:
1974  * @paned: a #GtkPaned widget
1975  * @position: pixel position of divider, a negative value means that the position
1976  *            is unset.
1977  * 
1978  * Sets the position of the divider between the two panes.
1979  **/
1980 void
1981 gtk_paned_set_position (GtkPaned *paned,
1982                         gint      position)
1983 {
1984   GtkPanedPrivate *priv;
1985   GObject *object;
1986
1987   g_return_if_fail (GTK_IS_PANED (paned));
1988
1989   priv = paned->priv;
1990
1991   if (priv->child1_size == position)
1992     return;
1993
1994   object = G_OBJECT (paned);
1995   
1996   if (position >= 0)
1997     {
1998       /* We don't clamp here - the assumption is that
1999        * if the total allocation changes at the same time
2000        * as the position, the position set is with reference
2001        * to the new total size. If only the position changes,
2002        * then clamping will occur in gtk_paned_calc_position()
2003        */
2004
2005       priv->child1_size = position;
2006       priv->position_set = TRUE;
2007     }
2008   else
2009     {
2010       priv->position_set = FALSE;
2011     }
2012
2013   g_object_freeze_notify (object);
2014   g_object_notify (object, "position");
2015   g_object_notify (object, "position-set");
2016   g_object_thaw_notify (object);
2017
2018   gtk_widget_queue_resize_no_redraw (GTK_WIDGET (paned));
2019
2020 #ifdef G_OS_WIN32
2021   /* Hacky work-around for bug #144269 */
2022   if (priv->child2 != NULL)
2023     {
2024       gtk_widget_queue_draw (priv->child2);
2025     }
2026 #endif
2027 }
2028
2029 /**
2030  * gtk_paned_get_child1:
2031  * @paned: a #GtkPaned widget
2032  * 
2033  * Obtains the first child of the paned widget.
2034  * 
2035  * Return value: (transfer none): first child, or %NULL if it is not set.
2036  *
2037  * Since: 2.4
2038  **/
2039 GtkWidget *
2040 gtk_paned_get_child1 (GtkPaned *paned)
2041 {
2042   g_return_val_if_fail (GTK_IS_PANED (paned), NULL);
2043
2044   return paned->priv->child1;
2045 }
2046
2047 /**
2048  * gtk_paned_get_child2:
2049  * @paned: a #GtkPaned widget
2050  * 
2051  * Obtains the second child of the paned widget.
2052  * 
2053  * Return value: (transfer none): second child, or %NULL if it is not set.
2054  *
2055  * Since: 2.4
2056  **/
2057 GtkWidget *
2058 gtk_paned_get_child2 (GtkPaned *paned)
2059 {
2060   g_return_val_if_fail (GTK_IS_PANED (paned), NULL);
2061
2062   return paned->priv->child2;
2063 }
2064
2065 static void
2066 gtk_paned_calc_position (GtkPaned *paned,
2067                          gint      allocation,
2068                          gint      child1_req,
2069                          gint      child2_req)
2070 {
2071   GtkPanedPrivate *priv = paned->priv;
2072   gint old_position;
2073   gint old_min_position;
2074   gint old_max_position;
2075
2076   old_position = priv->child1_size;
2077   old_min_position = priv->min_position;
2078   old_max_position = priv->max_position;
2079
2080   priv->min_position = priv->child1_shrink ? 0 : child1_req;
2081
2082   priv->max_position = allocation;
2083   if (!priv->child2_shrink)
2084     priv->max_position = MAX (1, priv->max_position - child2_req);
2085   priv->max_position = MAX (priv->min_position, priv->max_position);
2086
2087   if (!priv->position_set)
2088     {
2089       if (priv->child1_resize && !priv->child2_resize)
2090         priv->child1_size = MAX (0, allocation - child2_req);
2091       else if (!priv->child1_resize && priv->child2_resize)
2092         priv->child1_size = child1_req;
2093       else if (child1_req + child2_req != 0)
2094         priv->child1_size = allocation * ((gdouble)child1_req / (child1_req + child2_req)) + 0.5;
2095       else
2096         priv->child1_size = allocation * 0.5 + 0.5;
2097     }
2098   else
2099     {
2100       /* If the position was set before the initial allocation.
2101        * (priv->last_allocation <= 0) just clamp it and leave it.
2102        */
2103       if (priv->last_allocation > 0)
2104         {
2105           if (priv->child1_resize && !priv->child2_resize)
2106             priv->child1_size += allocation - priv->last_allocation;
2107           else if (!(!priv->child1_resize && priv->child2_resize))
2108             priv->child1_size = allocation * ((gdouble) priv->child1_size / (priv->last_allocation)) + 0.5;
2109         }
2110     }
2111
2112   priv->child1_size = CLAMP (priv->child1_size,
2113                               priv->min_position,
2114                               priv->max_position);
2115
2116   if (priv->child1)
2117     gtk_paned_set_child_visible (paned, 0, priv->child1_size != 0);
2118   
2119   if (priv->child2)
2120     gtk_paned_set_child_visible (paned, 1, priv->child1_size != allocation); 
2121
2122   g_object_freeze_notify (G_OBJECT (paned));
2123   if (priv->child1_size != old_position)
2124     g_object_notify (G_OBJECT (paned), "position");
2125   if (priv->min_position != old_min_position)
2126     g_object_notify (G_OBJECT (paned), "min-position");
2127   if (priv->max_position != old_max_position)
2128     g_object_notify (G_OBJECT (paned), "max-position");
2129   g_object_thaw_notify (G_OBJECT (paned));
2130
2131   priv->last_allocation = allocation;
2132 }
2133
2134 static void
2135 gtk_paned_set_saved_focus (GtkPaned *paned, GtkWidget *widget)
2136 {
2137   GtkPanedPrivate *priv = paned->priv;
2138
2139   if (priv->saved_focus)
2140     g_object_remove_weak_pointer (G_OBJECT (priv->saved_focus),
2141                                   (gpointer *)&(priv->saved_focus));
2142
2143   priv->saved_focus = widget;
2144
2145   if (priv->saved_focus)
2146     g_object_add_weak_pointer (G_OBJECT (priv->saved_focus),
2147                                (gpointer *)&(priv->saved_focus));
2148 }
2149
2150 static void
2151 gtk_paned_set_first_paned (GtkPaned *paned, GtkPaned *first_paned)
2152 {
2153   GtkPanedPrivate *priv = paned->priv;
2154
2155   if (priv->first_paned)
2156     g_object_remove_weak_pointer (G_OBJECT (priv->first_paned),
2157                                   (gpointer *)&(priv->first_paned));
2158
2159   priv->first_paned = first_paned;
2160
2161   if (priv->first_paned)
2162     g_object_add_weak_pointer (G_OBJECT (priv->first_paned),
2163                                (gpointer *)&(priv->first_paned));
2164 }
2165
2166 static void
2167 gtk_paned_set_last_child1_focus (GtkPaned *paned, GtkWidget *widget)
2168 {
2169   GtkPanedPrivate *priv = paned->priv;
2170
2171   if (priv->last_child1_focus)
2172     g_object_remove_weak_pointer (G_OBJECT (priv->last_child1_focus),
2173                                   (gpointer *)&(priv->last_child1_focus));
2174
2175   priv->last_child1_focus = widget;
2176
2177   if (priv->last_child1_focus)
2178     g_object_add_weak_pointer (G_OBJECT (priv->last_child1_focus),
2179                                (gpointer *)&(priv->last_child1_focus));
2180 }
2181
2182 static void
2183 gtk_paned_set_last_child2_focus (GtkPaned *paned, GtkWidget *widget)
2184 {
2185   GtkPanedPrivate *priv = paned->priv;
2186
2187   if (priv->last_child2_focus)
2188     g_object_remove_weak_pointer (G_OBJECT (priv->last_child2_focus),
2189                                   (gpointer *)&(priv->last_child2_focus));
2190
2191   priv->last_child2_focus = widget;
2192
2193   if (priv->last_child2_focus)
2194     g_object_add_weak_pointer (G_OBJECT (priv->last_child2_focus),
2195                                (gpointer *)&(priv->last_child2_focus));
2196 }
2197
2198 static GtkWidget *
2199 paned_get_focus_widget (GtkPaned *paned)
2200 {
2201   GtkWidget *toplevel;
2202
2203   toplevel = gtk_widget_get_toplevel (GTK_WIDGET (paned));
2204   if (gtk_widget_is_toplevel (toplevel))
2205     return gtk_window_get_focus (GTK_WINDOW (toplevel));
2206
2207   return NULL;
2208 }
2209
2210 static void
2211 gtk_paned_set_focus_child (GtkContainer *container,
2212                            GtkWidget    *focus_child)
2213 {
2214   GtkPaned *paned;
2215   GtkPanedPrivate *priv;
2216   GtkWidget *container_focus_child;
2217
2218   g_return_if_fail (GTK_IS_PANED (container));
2219
2220   paned = GTK_PANED (container);
2221   priv = paned->priv;
2222
2223   if (focus_child == NULL)
2224     {
2225       GtkWidget *last_focus;
2226       GtkWidget *w;
2227       
2228       last_focus = paned_get_focus_widget (paned);
2229
2230       if (last_focus)
2231         {
2232           /* If there is one or more paned widgets between us and the
2233            * focus widget, we want the topmost of those as last_focus
2234            */
2235           for (w = last_focus; w != GTK_WIDGET (paned); w = gtk_widget_get_parent (w))
2236             if (GTK_IS_PANED (w))
2237               last_focus = w;
2238
2239           container_focus_child = gtk_container_get_focus_child (container);
2240           if (container_focus_child == priv->child1)
2241             gtk_paned_set_last_child1_focus (paned, last_focus);
2242           else if (container_focus_child == priv->child2)
2243             gtk_paned_set_last_child2_focus (paned, last_focus);
2244         }
2245     }
2246
2247   if (GTK_CONTAINER_CLASS (gtk_paned_parent_class)->set_focus_child)
2248     GTK_CONTAINER_CLASS (gtk_paned_parent_class)->set_focus_child (container, focus_child);
2249 }
2250
2251 static void
2252 gtk_paned_get_cycle_chain (GtkPaned          *paned,
2253                            GtkDirectionType   direction,
2254                            GList            **widgets)
2255 {
2256   GtkPanedPrivate *priv = paned->priv;
2257   GtkContainer *container = GTK_CONTAINER (paned);
2258   GtkWidget *ancestor = NULL;
2259   GtkWidget *focus_child;
2260   GtkWidget *parent;
2261   GtkWidget *widget = GTK_WIDGET (paned);
2262   GList *temp_list = NULL;
2263   GList *list;
2264
2265   if (priv->in_recursion)
2266     return;
2267
2268   g_assert (widgets != NULL);
2269
2270   if (priv->last_child1_focus &&
2271       !gtk_widget_is_ancestor (priv->last_child1_focus, widget))
2272     {
2273       gtk_paned_set_last_child1_focus (paned, NULL);
2274     }
2275
2276   if (priv->last_child2_focus &&
2277       !gtk_widget_is_ancestor (priv->last_child2_focus, widget))
2278     {
2279       gtk_paned_set_last_child2_focus (paned, NULL);
2280     }
2281
2282   parent = gtk_widget_get_parent (widget);
2283   if (parent)
2284     ancestor = gtk_widget_get_ancestor (parent, GTK_TYPE_PANED);
2285
2286   /* The idea here is that temp_list is a list of widgets we want to cycle
2287    * to. The list is prioritized so that the first element is our first
2288    * choice, the next our second, and so on.
2289    *
2290    * We can't just use g_list_reverse(), because we want to try
2291    * priv->last_child?_focus before priv->child?, both when we
2292    * are going forward and backward.
2293    */
2294   focus_child = gtk_container_get_focus_child (container);
2295   if (direction == GTK_DIR_TAB_FORWARD)
2296     {
2297       if (focus_child == priv->child1)
2298         {
2299           temp_list = g_list_append (temp_list, priv->last_child2_focus);
2300           temp_list = g_list_append (temp_list, priv->child2);
2301           temp_list = g_list_append (temp_list, ancestor);
2302         }
2303       else if (focus_child == priv->child2)
2304         {
2305           temp_list = g_list_append (temp_list, ancestor);
2306           temp_list = g_list_append (temp_list, priv->last_child1_focus);
2307           temp_list = g_list_append (temp_list, priv->child1);
2308         }
2309       else
2310         {
2311           temp_list = g_list_append (temp_list, priv->last_child1_focus);
2312           temp_list = g_list_append (temp_list, priv->child1);
2313           temp_list = g_list_append (temp_list, priv->last_child2_focus);
2314           temp_list = g_list_append (temp_list, priv->child2);
2315           temp_list = g_list_append (temp_list, ancestor);
2316         }
2317     }
2318   else
2319     {
2320       if (focus_child == priv->child1)
2321         {
2322           temp_list = g_list_append (temp_list, ancestor);
2323           temp_list = g_list_append (temp_list, priv->last_child2_focus);
2324           temp_list = g_list_append (temp_list, priv->child2);
2325         }
2326       else if (focus_child == priv->child2)
2327         {
2328           temp_list = g_list_append (temp_list, priv->last_child1_focus);
2329           temp_list = g_list_append (temp_list, priv->child1);
2330           temp_list = g_list_append (temp_list, ancestor);
2331         }
2332       else
2333         {
2334           temp_list = g_list_append (temp_list, priv->last_child2_focus);
2335           temp_list = g_list_append (temp_list, priv->child2);
2336           temp_list = g_list_append (temp_list, priv->last_child1_focus);
2337           temp_list = g_list_append (temp_list, priv->child1);
2338           temp_list = g_list_append (temp_list, ancestor);
2339         }
2340     }
2341
2342   /* Walk the list and expand all the paned widgets. */
2343   for (list = temp_list; list != NULL; list = list->next)
2344     {
2345       GtkWidget *widget = list->data;
2346
2347       if (widget)
2348         {
2349           if (GTK_IS_PANED (widget))
2350             {
2351               priv->in_recursion = TRUE;
2352               gtk_paned_get_cycle_chain (GTK_PANED (widget), direction, widgets);
2353               priv->in_recursion = FALSE;
2354             }
2355           else
2356             {
2357               *widgets = g_list_append (*widgets, widget);
2358             }
2359         }
2360     }
2361
2362   g_list_free (temp_list);
2363 }
2364
2365 static gboolean
2366 gtk_paned_cycle_child_focus (GtkPaned *paned,
2367                              gboolean  reversed)
2368 {
2369   GList *cycle_chain = NULL;
2370   GList *list;
2371   
2372   GtkDirectionType direction = reversed? GTK_DIR_TAB_BACKWARD : GTK_DIR_TAB_FORWARD;
2373
2374   /* ignore f6 if the handle is focused */
2375   if (gtk_widget_is_focus (GTK_WIDGET (paned)))
2376     return TRUE;
2377   
2378   /* we can't just let the event propagate up the hierarchy,
2379    * because the paned will want to cycle focus _unless_ an
2380    * ancestor paned handles the event
2381    */
2382   gtk_paned_get_cycle_chain (paned, direction, &cycle_chain);
2383
2384   for (list = cycle_chain; list != NULL; list = list->next)
2385     if (gtk_widget_child_focus (GTK_WIDGET (list->data), direction))
2386       break;
2387
2388   g_list_free (cycle_chain);
2389   
2390   return TRUE;
2391 }
2392
2393 static void
2394 get_child_panes (GtkWidget  *widget,
2395                  GList     **panes)
2396 {
2397   if (!widget || !gtk_widget_get_realized (widget))
2398     return;
2399
2400   if (GTK_IS_PANED (widget))
2401     {
2402       GtkPaned *paned = GTK_PANED (widget);
2403       GtkPanedPrivate *priv = paned->priv;
2404
2405       get_child_panes (priv->child1, panes);
2406       *panes = g_list_prepend (*panes, widget);
2407       get_child_panes (priv->child2, panes);
2408     }
2409   else if (GTK_IS_CONTAINER (widget))
2410     {
2411       gtk_container_forall (GTK_CONTAINER (widget),
2412                             (GtkCallback)get_child_panes, panes);
2413     }
2414 }
2415
2416 static GList *
2417 get_all_panes (GtkPaned *paned)
2418 {
2419   GtkPaned *topmost = NULL;
2420   GList *result = NULL;
2421   GtkWidget *w;
2422
2423   for (w = GTK_WIDGET (paned); w != NULL; w = gtk_widget_get_parent (w))
2424     {
2425       if (GTK_IS_PANED (w))
2426         topmost = GTK_PANED (w);
2427     }
2428
2429   g_assert (topmost);
2430
2431   get_child_panes (GTK_WIDGET (topmost), &result);
2432
2433   return g_list_reverse (result);
2434 }
2435
2436 static void
2437 gtk_paned_find_neighbours (GtkPaned  *paned,
2438                            GtkPaned **next,
2439                            GtkPaned **prev)
2440 {
2441   GList *all_panes;
2442   GList *this_link;
2443
2444   all_panes = get_all_panes (paned);
2445   g_assert (all_panes);
2446
2447   this_link = g_list_find (all_panes, paned);
2448
2449   g_assert (this_link);
2450   
2451   if (this_link->next)
2452     *next = this_link->next->data;
2453   else
2454     *next = all_panes->data;
2455
2456   if (this_link->prev)
2457     *prev = this_link->prev->data;
2458   else
2459     *prev = g_list_last (all_panes)->data;
2460
2461   g_list_free (all_panes);
2462 }
2463
2464 static gboolean
2465 gtk_paned_move_handle (GtkPaned      *paned,
2466                        GtkScrollType  scroll)
2467 {
2468   GtkPanedPrivate *priv = paned->priv;
2469
2470   if (gtk_widget_is_focus (GTK_WIDGET (paned)))
2471     {
2472       gint old_position;
2473       gint new_position;
2474       gint increment;
2475       
2476       enum {
2477         SINGLE_STEP_SIZE = 1,
2478         PAGE_STEP_SIZE   = 75
2479       };
2480       
2481       new_position = old_position = gtk_paned_get_position (paned);
2482       increment = 0;
2483       
2484       switch (scroll)
2485         {
2486         case GTK_SCROLL_STEP_LEFT:
2487         case GTK_SCROLL_STEP_UP:
2488         case GTK_SCROLL_STEP_BACKWARD:
2489           increment = - SINGLE_STEP_SIZE;
2490           break;
2491           
2492         case GTK_SCROLL_STEP_RIGHT:
2493         case GTK_SCROLL_STEP_DOWN:
2494         case GTK_SCROLL_STEP_FORWARD:
2495           increment = SINGLE_STEP_SIZE;
2496           break;
2497           
2498         case GTK_SCROLL_PAGE_LEFT:
2499         case GTK_SCROLL_PAGE_UP:
2500         case GTK_SCROLL_PAGE_BACKWARD:
2501           increment = - PAGE_STEP_SIZE;
2502           break;
2503           
2504         case GTK_SCROLL_PAGE_RIGHT:
2505         case GTK_SCROLL_PAGE_DOWN:
2506         case GTK_SCROLL_PAGE_FORWARD:
2507           increment = PAGE_STEP_SIZE;
2508           break;
2509           
2510         case GTK_SCROLL_START:
2511           new_position = priv->min_position;
2512           break;
2513           
2514         case GTK_SCROLL_END:
2515           new_position = priv->max_position;
2516           break;
2517
2518         default:
2519           break;
2520         }
2521
2522       if (increment)
2523         {
2524           if (is_rtl (paned))
2525             increment = -increment;
2526           
2527           new_position = old_position + increment;
2528         }
2529       
2530       new_position = CLAMP (new_position, priv->min_position, priv->max_position);
2531       
2532       if (old_position != new_position)
2533         gtk_paned_set_position (paned, new_position);
2534
2535       return TRUE;
2536     }
2537
2538   return FALSE;
2539 }
2540
2541 static void
2542 gtk_paned_restore_focus (GtkPaned *paned)
2543 {
2544   GtkPanedPrivate *priv = paned->priv;
2545
2546   if (gtk_widget_is_focus (GTK_WIDGET (paned)))
2547     {
2548       if (priv->saved_focus &&
2549           gtk_widget_get_sensitive (priv->saved_focus))
2550         {
2551           gtk_widget_grab_focus (priv->saved_focus);
2552         }
2553       else
2554         {
2555           /* the saved focus is somehow not available for focusing,
2556            * try
2557            *   1) tabbing into the paned widget
2558            * if that didn't work,
2559            *   2) unset focus for the window if there is one
2560            */
2561           
2562           if (!gtk_widget_child_focus (GTK_WIDGET (paned), GTK_DIR_TAB_FORWARD))
2563             {
2564               GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (paned));
2565               
2566               if (GTK_IS_WINDOW (toplevel))
2567                 gtk_window_set_focus (GTK_WINDOW (toplevel), NULL);
2568             }
2569         }
2570       
2571       gtk_paned_set_saved_focus (paned, NULL);
2572       gtk_paned_set_first_paned (paned, NULL);
2573     }
2574 }
2575
2576 static gboolean
2577 gtk_paned_accept_position (GtkPaned *paned)
2578 {
2579   GtkPanedPrivate *priv = paned->priv;
2580
2581   if (gtk_widget_is_focus (GTK_WIDGET (paned)))
2582     {
2583       priv->original_position = -1;
2584       gtk_paned_restore_focus (paned);
2585
2586       return TRUE;
2587     }
2588
2589   return FALSE;
2590 }
2591
2592
2593 static gboolean
2594 gtk_paned_cancel_position (GtkPaned *paned)
2595 {
2596   GtkPanedPrivate *priv = paned->priv;
2597
2598   if (gtk_widget_is_focus (GTK_WIDGET (paned)))
2599     {
2600       if (priv->original_position != -1)
2601         {
2602           gtk_paned_set_position (paned, priv->original_position);
2603           priv->original_position = -1;
2604         }
2605
2606       gtk_paned_restore_focus (paned);
2607       return TRUE;
2608     }
2609
2610   return FALSE;
2611 }
2612
2613 static gboolean
2614 gtk_paned_cycle_handle_focus (GtkPaned *paned,
2615                               gboolean  reversed)
2616 {
2617   GtkPanedPrivate *priv = paned->priv;
2618   GtkPaned *next, *prev;
2619
2620   if (gtk_widget_is_focus (GTK_WIDGET (paned)))
2621     {
2622       GtkPaned *focus = NULL;
2623
2624       if (!priv->first_paned)
2625         {
2626           /* The first_pane has disappeared. As an ad-hoc solution,
2627            * we make the currently focused paned the first_paned. To the
2628            * user this will seem like the paned cycling has been reset.
2629            */
2630           
2631           gtk_paned_set_first_paned (paned, paned);
2632         }
2633       
2634       gtk_paned_find_neighbours (paned, &next, &prev);
2635
2636       if (reversed && prev &&
2637           prev != paned && paned != priv->first_paned)
2638         {
2639           focus = prev;
2640         }
2641       else if (!reversed && next &&
2642                next != paned && next != priv->first_paned)
2643         {
2644           focus = next;
2645         }
2646       else
2647         {
2648           gtk_paned_accept_position (paned);
2649           return TRUE;
2650         }
2651
2652       g_assert (focus);
2653       
2654       gtk_paned_set_saved_focus (focus, priv->saved_focus);
2655       gtk_paned_set_first_paned (focus, priv->first_paned);
2656       
2657       gtk_paned_set_saved_focus (paned, NULL);
2658       gtk_paned_set_first_paned (paned, NULL);
2659       
2660       gtk_widget_grab_focus (GTK_WIDGET (focus));
2661       
2662       if (!gtk_widget_is_focus (GTK_WIDGET (paned)))
2663         {
2664           priv->original_position = -1;
2665           focus->priv->original_position = gtk_paned_get_position (focus);
2666         }
2667     }
2668   else
2669     {
2670       GtkContainer *container = GTK_CONTAINER (paned);
2671       GtkPaned *focus;
2672       GtkPaned *first;
2673       GtkPaned *prev, *next;
2674       GtkWidget *toplevel;
2675       GtkWidget *focus_child;
2676
2677       gtk_paned_find_neighbours (paned, &next, &prev);
2678       focus_child = gtk_container_get_focus_child (container);
2679
2680       if (focus_child == priv->child1)
2681         {
2682           if (reversed)
2683             {
2684               focus = prev;
2685               first = paned;
2686             }
2687           else
2688             {
2689               focus = paned;
2690               first = paned;
2691             }
2692         }
2693       else if (focus_child == priv->child2)
2694         {
2695           if (reversed)
2696             {
2697               focus = paned;
2698               first = next;
2699             }
2700           else
2701             {
2702               focus = next;
2703               first = next;
2704             }
2705         }
2706       else
2707         {
2708           /* Focus is not inside this paned, and we don't have focus.
2709            * Presumably this happened because the application wants us
2710            * to start keyboard navigating.
2711            */
2712           focus = paned;
2713
2714           if (reversed)
2715             first = paned;
2716           else
2717             first = next;
2718         }
2719
2720       toplevel = gtk_widget_get_toplevel (GTK_WIDGET (paned));
2721
2722       if (GTK_IS_WINDOW (toplevel))
2723         gtk_paned_set_saved_focus (focus, gtk_window_get_focus (GTK_WINDOW (toplevel)));
2724       gtk_paned_set_first_paned (focus, first);
2725       focus->priv->original_position = gtk_paned_get_position (focus);
2726
2727       gtk_widget_grab_focus (GTK_WIDGET (focus));
2728    }
2729
2730   return TRUE;
2731 }
2732
2733 static gboolean
2734 gtk_paned_toggle_handle_focus (GtkPaned *paned)
2735 {
2736   /* This function/signal has the wrong name. It is called when you
2737    * press Tab or Shift-Tab and what we do is act as if
2738    * the user pressed Return and then Tab or Shift-Tab
2739    */
2740   if (gtk_widget_is_focus (GTK_WIDGET (paned)))
2741     gtk_paned_accept_position (paned);
2742
2743   return FALSE;
2744 }
2745
2746 /**
2747  * gtk_paned_get_handle_window:
2748  * @paned: a #GtkPaned
2749  *
2750  * Returns the #GdkWindow of the handle. This function is
2751  * useful when handling button or motion events because it
2752  * enables the callback to distinguish between the window
2753  * of the paned, a child and the handle.
2754  *
2755  * Return value: (transfer none): the paned's handle window.
2756  *
2757  * Since: 2.20
2758  **/
2759 GdkWindow *
2760 gtk_paned_get_handle_window (GtkPaned *paned)
2761 {
2762   g_return_val_if_fail (GTK_IS_PANED (paned), NULL);
2763
2764   return paned->priv->handle;
2765 }