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