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