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