Merge branch 'master' into rewrite-sheet
[pspp-builds.git] / lib / gtksheet / gtkxpaned.c
1 /*******************************************************************************
2 **3456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 
3 **      10        20        30        40        50        60        70        80
4 **
5 **  library for GtkXPaned-widget, a 2x2 grid-like variation of GtkPaned of gtk+
6 **  Copyright (C) 2005-2006 Mirco "MacSlow" Müller <macslow@bangang.de>
7 **
8 **  This library is free software; you can redistribute it and/or
9 **  modify it under the terms of the GNU Lesser General Public
10 **  License as published by the Free Software Foundation; either
11 **  version 2.1 of the License, or (at your option) any later version.
12 **
13 **  This library is distributed in the hope that it will be useful,
14 **  but WITHOUT ANY WARRANTY; without even the implied warranty of
15 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 **  Lesser General Public License for more details.
17 **
18 **  You should have received a copy of the GNU Lesser General Public
19 **  License along with this library; if not, write to the Free Software
20 **  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 **
22 **  GtkXPaned is based on GtkPaned which was done by...
23 **
24 **  "Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald"
25 **
26 **  and later modified by...
27 **
28 **  "the GTK+ Team and others 1997-2000"
29 **
30 *******************************************************************************/
31
32 #include "gtkxpaned.h"
33 #include "gtkmarshalers.h"
34 #include <gtk/gtkbindings.h>
35 #include <gtk/gtksignal.h>
36 #include <gdk/gdkkeysyms.h>
37 #include <gtk/gtkwindow.h>
38 #include <gtk/gtkmain.h>
39
40 enum WidgetProperties
41 {
42         PROP_0,
43         PROP_X_POSITION,
44         PROP_Y_POSITION,
45         PROP_POSITION_SET,
46         PROP_MIN_X_POSITION,
47         PROP_MIN_Y_POSITION,
48         PROP_MAX_X_POSITION,
49         PROP_MAX_Y_POSITION
50 };
51
52 enum ChildProperties
53 {
54         CHILD_PROP_0,
55         CHILD_PROP_RESIZE,
56         CHILD_PROP_SHRINK
57 };
58
59 enum WidgetSignals
60 {
61         CYCLE_CHILD_FOCUS,
62         TOGGLE_HANDLE_FOCUS,
63         MOVE_HANDLE,
64         CYCLE_HANDLE_FOCUS,
65         ACCEPT_POSITION,
66         CANCEL_POSITION,
67         LAST_SIGNAL
68 };
69
70 static void gtk_xpaned_class_init (GtkXPanedClass* klass);
71
72 static void gtk_xpaned_init (GtkXPaned* xpaned);
73
74 static void gtk_xpaned_size_request (GtkWidget* widget,
75                                                                          GtkRequisition* requisition);
76
77 static void gtk_xpaned_size_allocate (GtkWidget* widget,
78                                                                           GtkAllocation* allocation);
79
80 static void gtk_xpaned_set_property (GObject* object,
81                                                                          guint prop_id,
82                                                                          const GValue* value,
83                                                                          GParamSpec* pspec);
84
85 static void gtk_xpaned_get_property (GObject* object,
86                                                                          guint prop_id,
87                                                                          GValue* value,
88                                                                          GParamSpec* pspec);
89
90 static void gtk_xpaned_set_child_property (GtkContainer* container,
91                                                                                    GtkWidget* child,
92                                                                                    guint property_id,
93                                                                                    const GValue* value,
94                                                                                    GParamSpec* pspec);
95
96 static void gtk_xpaned_get_child_property (GtkContainer* container,
97                                                                                    GtkWidget* child,
98                                                                                    guint property_id,
99                                                                                    GValue* value,
100                                                                                    GParamSpec* pspec);
101
102 static void gtk_xpaned_finalize (GObject* object);
103
104 static void gtk_xpaned_realize (GtkWidget* widget);
105
106 static void gtk_xpaned_unrealize (GtkWidget* widget);
107
108 static void gtk_xpaned_map (GtkWidget* widget);
109
110 static void gtk_xpaned_unmap (GtkWidget* widget);
111
112 static gboolean gtk_xpaned_expose (GtkWidget* widget, GdkEventExpose* event);
113
114 static gboolean gtk_xpaned_enter (GtkWidget* widget, GdkEventCrossing* event);
115
116 static gboolean gtk_xpaned_leave (GtkWidget* widget, GdkEventCrossing* event);
117
118 static gboolean gtk_xpaned_button_press (GtkWidget* widget,
119                                                                                  GdkEventButton* event);
120
121 static gboolean gtk_xpaned_button_release (GtkWidget* widget,
122                                                                                    GdkEventButton* event);
123
124 static gboolean gtk_xpaned_motion (GtkWidget* widget, GdkEventMotion* event);
125
126 static gboolean gtk_xpaned_focus (GtkWidget* widget,
127                                                                   GtkDirectionType direction);
128
129 static void gtk_xpaned_add (GtkContainer* container, GtkWidget* widget);
130
131 static void gtk_xpaned_remove (GtkContainer* container, GtkWidget* widget);
132
133 static void gtk_xpaned_forall (GtkContainer* container,
134                                                            gboolean include_internals,
135                                                            GtkCallback callback,
136                                                            gpointer callback_data);
137
138 static void gtk_xpaned_set_focus_child (GtkContainer* container,
139                                                                             GtkWidget* child);
140
141 static void gtk_xpaned_set_saved_focus (GtkXPaned* xpaned, GtkWidget* widget);
142
143 static void gtk_xpaned_set_first_xpaned (GtkXPaned* xpaned,
144                                                                                  GtkXPaned* first_xpaned);
145
146 static void gtk_xpaned_set_last_top_left_child_focus (GtkXPaned* xpaned,
147                                                                                                           GtkWidget* widget);
148
149 static void gtk_xpaned_set_last_top_right_child_focus (GtkXPaned* xpaned,
150                                                                                                            GtkWidget* widget);
151
152 static void gtk_xpaned_set_last_bottom_left_child_focus (GtkXPaned* xpaned,
153                                                                                                                  GtkWidget* widget);
154
155 static void gtk_xpaned_set_last_bottom_right_child_focus (GtkXPaned* xpaned,
156                                                                                                                   GtkWidget* widget);
157
158 static gboolean gtk_xpaned_cycle_child_focus (GtkXPaned* xpaned,
159                                                                                           gboolean reverse);
160
161 static gboolean gtk_xpaned_cycle_handle_focus (GtkXPaned* xpaned,
162                                                                                            gboolean reverse);
163
164 static gboolean gtk_xpaned_move_handle (GtkXPaned* xpaned,
165                                                                             GtkScrollType scroll);
166
167 static gboolean gtk_xpaned_accept_position (GtkXPaned* xpaned);
168
169 static gboolean gtk_xpaned_cancel_position (GtkXPaned* xpaned);
170
171 static gboolean gtk_xpaned_toggle_handle_focus (GtkXPaned* xpaned);
172
173 static GType gtk_xpaned_child_type (GtkContainer* container);
174
175 static GtkContainerClass* parent_class = NULL;
176
177 struct _GtkXPanedPrivate
178 {
179         GtkWidget *saved_focus;
180         GtkXPaned *first_xpaned;
181 };
182
183 GType gtk_xpaned_get_type (void)
184 {
185         static GType xpaned_type = 0;
186   
187         if (!xpaned_type)
188         {
189                 static const GTypeInfo xpaned_info =
190                 {
191                         sizeof (GtkXPanedClass),
192                         NULL,           /* base_init */
193                         NULL,           /* base_finalize */
194                         (GClassInitFunc) gtk_xpaned_class_init,
195                         NULL,           /* class_finalize */
196                         NULL,           /* class_data */
197                         sizeof (GtkXPaned),
198                         0,              /* n_preallocs */
199                         (GInstanceInitFunc) gtk_xpaned_init
200                 };
201
202                 xpaned_type = g_type_register_static (GTK_TYPE_CONTAINER,
203                                                                                           "GtkXPaned",
204                                                                                           &xpaned_info,
205                                                                                           0);
206         }
207
208         return xpaned_type;
209 }
210
211 GtkWidget* gtk_xpaned_new (void)
212 {
213         GtkXPaned* xpaned;
214
215         xpaned = g_object_new (GTK_TYPE_XPANED, NULL);
216
217         return GTK_WIDGET (xpaned);
218 }
219
220 static guint signals[LAST_SIGNAL] = { 0 };
221
222 static void add_tab_bindings (GtkBindingSet* binding_set,
223                                                           GdkModifierType modifiers)
224 {
225         gtk_binding_entry_add_signal (binding_set,
226                                                                   GDK_Tab,
227                                                                   modifiers,
228                                                                   "toggle_handle_focus",
229                                                                   0);
230
231         gtk_binding_entry_add_signal (binding_set,
232                                                                   GDK_KP_Tab,
233                                                                   modifiers,
234                                                                   "toggle_handle_focus",
235                                                                   0);
236 }
237
238 static void add_move_binding (GtkBindingSet* binding_set,
239                                                           guint keyval,
240                                                           GdkModifierType mask,
241                                                           GtkScrollType scroll)
242 {
243         gtk_binding_entry_add_signal (binding_set,
244                                                                   keyval,
245                                                                   mask,
246                                                                   "move_handle",
247                                                                   1,
248                                                                   GTK_TYPE_SCROLL_TYPE,
249                                                                   scroll);
250 }
251
252 static void gtk_xpaned_class_init (GtkXPanedClass* class)
253 {
254         GObjectClass* object_class;
255         GtkWidgetClass* widget_class;
256         GtkContainerClass* container_class;
257         GtkXPanedClass* xpaned_class;
258         GtkBindingSet* binding_set;
259
260         object_class = (GObjectClass *) class;
261         widget_class = (GtkWidgetClass *) class;
262         container_class = (GtkContainerClass *) class;
263         xpaned_class = (GtkXPanedClass *) class;
264
265         parent_class = g_type_class_peek_parent (class);
266
267         object_class->set_property = gtk_xpaned_set_property;
268         object_class->get_property = gtk_xpaned_get_property;
269         object_class->finalize = gtk_xpaned_finalize;
270
271         widget_class->realize = gtk_xpaned_realize;
272         widget_class->unrealize = gtk_xpaned_unrealize;
273         widget_class->map = gtk_xpaned_map;
274         widget_class->unmap = gtk_xpaned_unmap;
275         widget_class->expose_event = gtk_xpaned_expose;
276         widget_class->focus = gtk_xpaned_focus;
277         widget_class->enter_notify_event = gtk_xpaned_enter;
278         widget_class->leave_notify_event = gtk_xpaned_leave;
279         widget_class->button_press_event = gtk_xpaned_button_press;
280         widget_class->button_release_event = gtk_xpaned_button_release;
281         widget_class->motion_notify_event = gtk_xpaned_motion;
282         widget_class->size_request = gtk_xpaned_size_request;
283         widget_class->size_allocate = gtk_xpaned_size_allocate;
284
285         container_class->add = gtk_xpaned_add;
286         container_class->remove = gtk_xpaned_remove;
287         container_class->forall = gtk_xpaned_forall;
288         container_class->child_type = gtk_xpaned_child_type;
289         container_class->set_focus_child = gtk_xpaned_set_focus_child;
290         container_class->set_child_property = gtk_xpaned_set_child_property;
291         container_class->get_child_property = gtk_xpaned_get_child_property;
292
293         xpaned_class->cycle_child_focus = gtk_xpaned_cycle_child_focus;
294         xpaned_class->toggle_handle_focus = gtk_xpaned_toggle_handle_focus;
295         xpaned_class->move_handle = gtk_xpaned_move_handle;
296         xpaned_class->cycle_handle_focus = gtk_xpaned_cycle_handle_focus;
297         xpaned_class->accept_position = gtk_xpaned_accept_position;
298         xpaned_class->cancel_position = gtk_xpaned_cancel_position;
299
300         g_object_class_install_property (object_class,
301                                                                          PROP_X_POSITION,
302                                                                          g_param_spec_int ("x-position",
303                                                                                                            ("x-Position"),
304                                                                                                            ("x-Position of paned separator in pixels (0 means all the way to the left)"),
305                                                                                                            0,
306                                                                                                            G_MAXINT,
307                                                                                                            0,
308                                                                                                            G_PARAM_READABLE | G_PARAM_WRITABLE));
309
310         g_object_class_install_property (object_class,
311                                                                          PROP_Y_POSITION,
312                                                                          g_param_spec_int ("y-position",
313                                                                                                            "y-Position",
314                                                                                                            "y-Position of paned separator in pixels (0 means all the way to the top)",
315                                                                                                            0,
316                                                                                                            G_MAXINT,
317                                                                                                            0,
318                                                                                                            G_PARAM_READABLE | G_PARAM_WRITABLE));
319
320         g_object_class_install_property (object_class,
321                                                                          PROP_POSITION_SET,
322                                                                          g_param_spec_boolean ("position-set",
323                                                                                                                    "Position Set",
324                                                                                                                    "TRUE if the Position property should be used",
325                                                                                                                    FALSE,
326                                                                                                                    G_PARAM_READABLE | G_PARAM_WRITABLE));
327                                    
328         gtk_widget_class_install_style_property (widget_class,
329                                                                                          g_param_spec_int ("handle-size",
330                                                                                                                            "Handle Size",
331                                                                                                                            "Width of handle",
332                                                                                                                            0,
333                                                                                                                            G_MAXINT,
334                                                                                                                            3,
335                                                                                                                            G_PARAM_READABLE));
336         /**
337         * GtkXPaned:min-x-position:
338         *
339         * The smallest possible value for the x-position property. This property is derived from the
340         * size and shrinkability of the widget's children.
341         *
342         * Since: 2.4
343         */
344         g_object_class_install_property (object_class,
345                                                                          PROP_MIN_X_POSITION,
346                                                                          g_param_spec_int ("min-x-position",
347                                                                                                            "Minimal x-Position",
348                                                                                                            "Smallest possible value for the \"x-position\" property",
349                                                                                                            0,
350                                                                                                            G_MAXINT,
351                                                                                                            0,
352                                                                                                            G_PARAM_READABLE));
353
354         /**
355         * GtkXPaned:min-y-position:
356         *
357         * The smallest possible value for the y-position property. This property is derived from the
358         * size and shrinkability of the widget's children.
359         *
360         * Since: 2.4
361         */
362         g_object_class_install_property (object_class,
363                                                                          PROP_MIN_Y_POSITION,
364                                                                          g_param_spec_int ("min-y-position",
365                                                                                                            "Minimal y-Position",
366                                                                                                            "Smallest possible value for the \"y-position\" property",
367                                                                                                            0,
368                                                                                                            G_MAXINT,
369                                                                                                            0,
370                                                                                                            G_PARAM_READABLE));
371
372         /**
373         * GtkPaned:max-x-position:
374         *
375         * The largest possible value for the x-position property. This property is derived from the
376         * size and shrinkability of the widget's children.
377         *
378         * Since: 2.4
379         */
380         g_object_class_install_property (object_class,
381                                                                          PROP_MAX_X_POSITION,
382                                                                          g_param_spec_int ("max-x-position",
383                                                                                                            "Maximal x-Position",
384                                                                                                            "Largest possible value for the \"x-position\" property",
385                                                                                                            0,
386                                                                                                            G_MAXINT,
387                                                                                                            G_MAXINT,
388                                                                                                            G_PARAM_READABLE));
389
390         /**
391         * GtkPaned:max-y-position:
392         *
393         * The largest possible value for the y-position property. This property is derived from the
394         * size and shrinkability of the widget's children.
395         *
396         * Since: 2.4
397         */
398         g_object_class_install_property (object_class,
399                                                                          PROP_MAX_Y_POSITION,
400                                                                          g_param_spec_int ("max-y-position",
401                                                                                                            "Maximal y-Position",
402                                                                                                            "Largest possible value for the \"y-position\" property",
403                                                                                                            0,
404                                                                                                            G_MAXINT,
405                                                                                                            G_MAXINT,
406                                                                                                            G_PARAM_READABLE));
407
408         /**
409         * GtkPaned:resize:
410         *
411         * The "resize" child property determines whether the child expands and 
412         * shrinks along with the paned widget.
413         * 
414         * Since: 2.4 
415         */
416         gtk_container_class_install_child_property (container_class,
417                                                                                                 CHILD_PROP_RESIZE,
418                                                                                                 g_param_spec_boolean ("resize",
419                                                                                                                                           "Resize",
420                                                                                                                                           "If TRUE, the child expands and shrinks along with the paned widget",
421                                                                                                                                           TRUE,
422                                                                                                                                           G_PARAM_READWRITE));
423
424         /**
425         * GtkPaned:shrink:
426         *
427         * The "shrink" child property determines whether the child can be made 
428         * smaller than its requisition.
429         * 
430         * Since: 2.4 
431         */
432         gtk_container_class_install_child_property (container_class,
433                                                                                                 CHILD_PROP_SHRINK,
434                                                                                                 g_param_spec_boolean ("shrink", 
435                                                                                                                                           "Shrink",
436                                                                                                                                           "If TRUE, the child can be made smaller than its requisition",
437                                                                                                                                           TRUE,
438                                                                                                                                           G_PARAM_READWRITE));
439
440         signals [CYCLE_CHILD_FOCUS] = g_signal_new ("cycle-child-focus",
441                                                                                                 G_TYPE_FROM_CLASS (object_class),
442                                                                                                 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
443                                                                                                 G_STRUCT_OFFSET (GtkXPanedClass, cycle_child_focus),
444                                                                                                 NULL, NULL,
445                                                                                                 gtk_marshal_BOOLEAN__BOOLEAN,
446                                                                                                 G_TYPE_BOOLEAN, 1,
447                                                                                                 G_TYPE_BOOLEAN);
448
449         signals [TOGGLE_HANDLE_FOCUS] = g_signal_new ("toggle-handle-focus",
450                                                                                                   G_TYPE_FROM_CLASS (object_class),
451                                                                                                   G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
452                                                                                                   G_STRUCT_OFFSET (GtkXPanedClass, toggle_handle_focus),
453                                                                                                   NULL, NULL,
454                                                                                                   gtk_marshal_BOOLEAN__VOID,
455                                                                                                   G_TYPE_BOOLEAN, 0);
456
457         signals[MOVE_HANDLE] = g_signal_new ("move-handle",
458                                                                                  G_TYPE_FROM_CLASS (object_class),
459                                                                                  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
460                                                                                  G_STRUCT_OFFSET (GtkXPanedClass, move_handle),
461                                                                                  NULL, NULL,
462                                                                                  gtk_marshal_BOOLEAN__ENUM,
463                                                                                  G_TYPE_BOOLEAN, 1,
464                                                                                  GTK_TYPE_SCROLL_TYPE);
465
466         signals [CYCLE_HANDLE_FOCUS] = g_signal_new ("cycle-handle-focus",
467                                                                                                  G_TYPE_FROM_CLASS (object_class),
468                                                                                                  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
469                                                                                                  G_STRUCT_OFFSET (GtkXPanedClass, cycle_handle_focus),
470                                                                                                  NULL, NULL,
471                                                                                                  gtk_marshal_BOOLEAN__BOOLEAN,
472                                                                                                  G_TYPE_BOOLEAN, 1,
473                                                                                                  G_TYPE_BOOLEAN);
474
475         signals [ACCEPT_POSITION] = g_signal_new ("accept-position",
476                                                                                           G_TYPE_FROM_CLASS (object_class),
477                                                                                           G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
478                                                                                           G_STRUCT_OFFSET (GtkXPanedClass, accept_position),
479                                                                                           NULL, NULL,
480                                                                                           gtk_marshal_BOOLEAN__VOID,
481                                                                                           G_TYPE_BOOLEAN, 0);
482
483         signals [CANCEL_POSITION] = g_signal_new ("cancel-position",
484                                                                                           G_TYPE_FROM_CLASS (object_class),
485                                                                                           G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
486                                                                                           G_STRUCT_OFFSET (GtkXPanedClass, cancel_position),
487                                                                                           NULL, NULL,
488                                                                                           gtk_marshal_BOOLEAN__VOID,
489                                                                                           G_TYPE_BOOLEAN, 0);
490
491         binding_set = gtk_binding_set_by_class (class);
492
493         /* F6 and friends */
494         gtk_binding_entry_add_signal (binding_set,
495                                                                   GDK_F6, 0,
496                                                                   "cycle-child-focus", 1, 
497                                                                   G_TYPE_BOOLEAN, FALSE);
498
499         gtk_binding_entry_add_signal (binding_set,
500                                                                   GDK_F6, GDK_SHIFT_MASK,
501                                                                   "cycle-child-focus", 1,
502                                                                   G_TYPE_BOOLEAN, TRUE);
503
504         /* F8 and friends */
505         gtk_binding_entry_add_signal (binding_set,
506                                                                   GDK_F8, 0,
507                                                                   "cycle-handle-focus", 1,
508                                                                   G_TYPE_BOOLEAN, FALSE);
509  
510         gtk_binding_entry_add_signal (binding_set,
511                                                                   GDK_F8, GDK_SHIFT_MASK,
512                                                                   "cycle-handle-focus", 1,
513                                                                   G_TYPE_BOOLEAN, TRUE);
514  
515         add_tab_bindings (binding_set, 0);
516         add_tab_bindings (binding_set, GDK_CONTROL_MASK);
517         add_tab_bindings (binding_set, GDK_SHIFT_MASK);
518         add_tab_bindings (binding_set, GDK_CONTROL_MASK | GDK_SHIFT_MASK);
519
520         /* accept and cancel positions */
521         gtk_binding_entry_add_signal (binding_set,
522                                                                   GDK_Escape, 0,
523                                                                   "cancel-position", 0);
524
525         gtk_binding_entry_add_signal (binding_set,
526                                                                   GDK_Return, 0,
527                                                                   "accept-position", 0);
528
529         gtk_binding_entry_add_signal (binding_set,
530                                                                   GDK_KP_Enter, 0,
531                                                                   "accept-position", 0);
532
533         gtk_binding_entry_add_signal (binding_set,
534                                                                   GDK_space, 0,
535                                                                   "accept-position", 0);
536                                                                   
537         gtk_binding_entry_add_signal (binding_set,
538                                                                   GDK_KP_Space, 0,
539                                                                   "accept-position", 0);
540
541         /* move handle */
542         add_move_binding (binding_set, GDK_Left, 0, GTK_SCROLL_STEP_LEFT);
543         add_move_binding (binding_set, GDK_KP_Left, 0, GTK_SCROLL_STEP_LEFT);
544         add_move_binding (binding_set, GDK_Left, GDK_CONTROL_MASK, GTK_SCROLL_PAGE_LEFT);
545         add_move_binding (binding_set, GDK_KP_Left, GDK_CONTROL_MASK, GTK_SCROLL_PAGE_LEFT);
546
547         add_move_binding (binding_set, GDK_Right, 0, GTK_SCROLL_STEP_RIGHT);
548         add_move_binding (binding_set, GDK_Right, GDK_CONTROL_MASK, GTK_SCROLL_PAGE_RIGHT);
549         add_move_binding (binding_set, GDK_KP_Right, 0, GTK_SCROLL_STEP_RIGHT);
550         add_move_binding (binding_set, GDK_KP_Right, GDK_CONTROL_MASK, GTK_SCROLL_PAGE_RIGHT);
551
552         add_move_binding (binding_set, GDK_Up, 0, GTK_SCROLL_STEP_UP);
553         add_move_binding (binding_set, GDK_Up, GDK_CONTROL_MASK, GTK_SCROLL_PAGE_UP);
554         add_move_binding (binding_set, GDK_KP_Up, 0, GTK_SCROLL_STEP_UP);
555         add_move_binding (binding_set, GDK_KP_Up, GDK_CONTROL_MASK, GTK_SCROLL_PAGE_UP);
556         add_move_binding (binding_set, GDK_Page_Up, 0, GTK_SCROLL_PAGE_UP);
557         add_move_binding (binding_set, GDK_KP_Page_Up, 0, GTK_SCROLL_PAGE_UP);
558
559         add_move_binding (binding_set, GDK_Down, 0, GTK_SCROLL_STEP_DOWN);
560         add_move_binding (binding_set, GDK_Down, GDK_CONTROL_MASK, GTK_SCROLL_PAGE_DOWN);
561         add_move_binding (binding_set, GDK_KP_Down, 0, GTK_SCROLL_STEP_DOWN);
562         add_move_binding (binding_set, GDK_KP_Down, GDK_CONTROL_MASK, GTK_SCROLL_PAGE_DOWN);
563         add_move_binding (binding_set, GDK_Page_Down, 0, GTK_SCROLL_PAGE_RIGHT);
564         add_move_binding (binding_set, GDK_KP_Page_Down, 0, GTK_SCROLL_PAGE_RIGHT);
565
566         add_move_binding (binding_set, GDK_Home, 0, GTK_SCROLL_START);
567         add_move_binding (binding_set, GDK_KP_Home, 0, GTK_SCROLL_START);
568         add_move_binding (binding_set, GDK_End, 0, GTK_SCROLL_END);
569         add_move_binding (binding_set, GDK_KP_End, 0, GTK_SCROLL_END);
570 }
571
572 static GType gtk_xpaned_child_type (GtkContainer* container)
573 {
574         if (!GTK_XPANED (container)->top_left_child || 
575                 !GTK_XPANED (container)->top_right_child ||
576                 !GTK_XPANED (container)->bottom_left_child || 
577                 !GTK_XPANED (container)->bottom_right_child)
578                 return GTK_TYPE_WIDGET;
579           else
580                 return G_TYPE_NONE;
581 }
582
583 static void gtk_xpaned_init (GtkXPaned* xpaned)
584 {
585         GTK_WIDGET_SET_FLAGS (xpaned, GTK_NO_WINDOW | GTK_CAN_FOCUS);
586   
587         xpaned->top_left_child = NULL;
588         xpaned->top_right_child = NULL;
589         xpaned->bottom_left_child = NULL;
590         xpaned->bottom_right_child = NULL;
591         xpaned->handle_east = NULL;
592         xpaned->handle_west = NULL;
593         xpaned->handle_north = NULL;
594         xpaned->handle_south = NULL;
595         xpaned->handle_middle = NULL;
596         xpaned->xor_gc = NULL;
597         xpaned->cursor_type_east = GDK_SB_V_DOUBLE_ARROW;
598         xpaned->cursor_type_west = GDK_SB_V_DOUBLE_ARROW;
599         xpaned->cursor_type_north = GDK_SB_H_DOUBLE_ARROW;
600         xpaned->cursor_type_south = GDK_SB_H_DOUBLE_ARROW;
601         xpaned->cursor_type_middle = GDK_FLEUR;
602
603         xpaned->handle_pos_east.width = 5;
604         xpaned->handle_pos_east.height = 5;
605         xpaned->handle_pos_west.width = 5;
606         xpaned->handle_pos_west.height = 5;
607         xpaned->handle_pos_north.width = 5;
608         xpaned->handle_pos_north.height = 5;
609         xpaned->handle_pos_south.width = 5;
610         xpaned->handle_pos_south.height = 5;
611         xpaned->handle_pos_middle.width = 5;
612         xpaned->handle_pos_middle.height = 5;
613
614         xpaned->position_set = FALSE;
615         xpaned->last_allocation.width = -1;
616         xpaned->last_allocation.height = -1;
617         xpaned->in_drag_vert = FALSE;
618         xpaned->in_drag_horiz = FALSE;
619         xpaned->in_drag_vert_and_horiz = FALSE;
620
621         xpaned->maximized[GTK_XPANED_TOP_LEFT] = FALSE;
622         xpaned->maximized[GTK_XPANED_TOP_RIGHT] = FALSE;
623         xpaned->maximized[GTK_XPANED_BOTTOM_LEFT] = FALSE;
624         xpaned->maximized[GTK_XPANED_BOTTOM_RIGHT] = FALSE;
625
626         xpaned->priv = g_new0 (GtkXPanedPrivate, 1);
627         xpaned->last_top_left_child_focus = NULL;
628         xpaned->last_top_right_child_focus = NULL;
629         xpaned->last_bottom_left_child_focus = NULL;
630         xpaned->last_bottom_right_child_focus = NULL;
631         xpaned->in_recursion = FALSE;
632         xpaned->handle_prelit = FALSE;
633         xpaned->original_position.x = -1;
634         xpaned->original_position.y = -1;
635         xpaned->unmaximized_position.x = -1;
636         xpaned->unmaximized_position.y = -1;
637
638         xpaned->handle_pos_east.x = -1;
639         xpaned->handle_pos_east.y = -1;
640         xpaned->handle_pos_west.x = -1;
641         xpaned->handle_pos_west.y = -1;
642         xpaned->handle_pos_north.x = -1;
643         xpaned->handle_pos_north.y = -1;
644         xpaned->handle_pos_south.x = -1;
645         xpaned->handle_pos_south.y = -1;
646         xpaned->handle_pos_middle.x = -1;
647         xpaned->handle_pos_middle.y = -1;
648
649         xpaned->drag_pos.x = -1;
650         xpaned->drag_pos.y = -1;
651 }
652
653 static void gtk_xpaned_size_request (GtkWidget* widget,
654                                                                          GtkRequisition* requisition)
655 {
656         GtkXPaned* xpaned = GTK_XPANED (widget);
657         GtkRequisition child_requisition;
658
659         requisition->width = 0;
660         requisition->height = 0;
661
662         if (xpaned->top_left_child && GTK_WIDGET_VISIBLE (xpaned->top_left_child))
663         {
664                 gtk_widget_size_request (xpaned->top_left_child, &child_requisition);
665
666                 requisition->width = child_requisition.width;
667                 requisition->height = child_requisition.height;
668         }
669
670         if (xpaned->top_right_child && GTK_WIDGET_VISIBLE (xpaned->top_right_child))
671         {
672                 gtk_widget_size_request (xpaned->top_right_child, &child_requisition);
673
674                 requisition->width += child_requisition.width;
675                 requisition->height = MAX (requisition->height, child_requisition.height);
676         }
677
678         if (xpaned->bottom_left_child && GTK_WIDGET_VISIBLE (xpaned->bottom_left_child))
679         {
680                 gtk_widget_size_request (xpaned->bottom_left_child, &child_requisition);
681
682                 requisition->width = MAX (requisition->width, child_requisition.width);
683                 requisition->height += child_requisition.height;
684         }
685
686         if (xpaned->bottom_right_child && GTK_WIDGET_VISIBLE (xpaned->bottom_right_child))
687         {
688                 gtk_widget_size_request (xpaned->bottom_right_child, &child_requisition);
689
690                 requisition->width = MAX (requisition->width, child_requisition.width);
691                 requisition->height = MAX (requisition->height, child_requisition.height);
692         }
693
694         /* add 2 times the set border-width to the GtkXPaneds requisition */
695         requisition->width += GTK_CONTAINER (xpaned)->border_width * 2;
696         requisition->height += GTK_CONTAINER (xpaned)->border_width * 2;
697
698         /* also add the handle "thickness" to GtkXPaneds width- and height-requisitions */
699         if (xpaned->top_left_child && GTK_WIDGET_VISIBLE (xpaned->top_left_child) &&
700                 xpaned->top_right_child && GTK_WIDGET_VISIBLE (xpaned->top_right_child) &&
701                 xpaned->bottom_left_child && GTK_WIDGET_VISIBLE (xpaned->bottom_left_child) &&
702                 xpaned->bottom_right_child && GTK_WIDGET_VISIBLE (xpaned->bottom_right_child))
703         {
704                 gint handle_size;
705
706                 gtk_widget_style_get (widget, "handle-size", &handle_size, NULL);
707                 requisition->width += handle_size;
708                 requisition->height += handle_size;
709         }
710 }
711
712 static void gtk_xpaned_size_allocate (GtkWidget* widget,
713                                                                           GtkAllocation* allocation)
714 {
715         GtkXPaned* xpaned = GTK_XPANED (widget);
716         gint border_width = GTK_CONTAINER (xpaned)->border_width;
717         GtkAllocation top_left_child_allocation;
718         GtkAllocation top_right_child_allocation;
719         GtkAllocation bottom_left_child_allocation;
720         GtkAllocation bottom_right_child_allocation;
721         GtkRequisition top_left_child_requisition;
722         GtkRequisition top_right_child_requisition;
723         GtkRequisition bottom_left_child_requisition;
724         GtkRequisition bottom_right_child_requisition;
725         gint handle_size;
726
727         /* determine size of handle(s) */
728         gtk_widget_style_get (widget, "handle-size", &handle_size, NULL);
729
730         widget->allocation = *allocation;
731
732         if (xpaned->top_left_child && GTK_WIDGET_VISIBLE (xpaned->top_left_child) &&
733                 xpaned->top_right_child && GTK_WIDGET_VISIBLE (xpaned->top_right_child) &&
734                 xpaned->bottom_left_child && GTK_WIDGET_VISIBLE (xpaned->bottom_left_child) &&
735                 xpaned->bottom_right_child && GTK_WIDGET_VISIBLE (xpaned->bottom_right_child))
736     {
737                 /* what sizes do the children want to be at least at */
738                 gtk_widget_get_child_requisition (xpaned->top_left_child,
739                                                                                   &top_left_child_requisition);
740                 gtk_widget_get_child_requisition (xpaned->top_right_child,
741                                                                                   &top_right_child_requisition);
742                 gtk_widget_get_child_requisition (xpaned->bottom_left_child,
743                                                                                   &bottom_left_child_requisition);
744                 gtk_widget_get_child_requisition (xpaned->bottom_right_child,
745                                                                                   &bottom_right_child_requisition);
746
747                 /* determine the total requisition-sum of all requisitions of borders,
748                  * handles, children etc. */
749                 gtk_xpaned_compute_position (xpaned,
750                                                                          allocation,
751                                                                          &top_left_child_requisition,
752                                                                          &top_right_child_requisition,
753                                                                          &bottom_left_child_requisition,
754                                                                          &bottom_right_child_requisition);
755
756                 /* calculate the current positions and sizes of the handles */
757                 xpaned->handle_pos_east.x = widget->allocation.x + border_width + xpaned->top_left_child_size.width + handle_size;
758                 xpaned->handle_pos_east.y = widget->allocation.y + border_width + xpaned->top_left_child_size.height;
759                 xpaned->handle_pos_east.width = widget->allocation.width - xpaned->top_left_child_size.width - 2 * border_width - handle_size;
760                 xpaned->handle_pos_east.height = handle_size;
761
762                 xpaned->handle_pos_west.x = widget->allocation.x + border_width;
763                 xpaned->handle_pos_west.y = xpaned->handle_pos_east.y;
764                 xpaned->handle_pos_west.width = widget->allocation.width - xpaned->handle_pos_east.width - 2 * border_width - handle_size;
765                 xpaned->handle_pos_west.height = handle_size;
766
767                 xpaned->handle_pos_north.x = xpaned->handle_pos_east.x - handle_size;
768                 xpaned->handle_pos_north.y = widget->allocation.y + border_width;
769                 xpaned->handle_pos_north.width = handle_size;
770                 xpaned->handle_pos_north.height = xpaned->handle_pos_east.y - widget->allocation.y - border_width;
771
772                 xpaned->handle_pos_south.x = xpaned->handle_pos_north.x;
773                 xpaned->handle_pos_south.y = xpaned->handle_pos_east.y + handle_size;
774                 xpaned->handle_pos_south.width = handle_size;
775                 xpaned->handle_pos_south.height = widget->allocation.height - xpaned->handle_pos_north.height - 2 * border_width - handle_size;
776
777
778 #define CENTRUM 20
779                 xpaned->handle_pos_middle.x = xpaned->handle_pos_north.x ;
780                 xpaned->handle_pos_middle.y = xpaned->handle_pos_east.y ;
781                 xpaned->handle_pos_middle.width = handle_size + CENTRUM ;
782                 xpaned->handle_pos_middle.height = handle_size + CENTRUM;
783
784                 /* set allocation for top-left child */
785                 top_left_child_allocation.x = widget->allocation.x + border_width;
786                 top_left_child_allocation.y = widget->allocation.y + border_width;
787                 top_left_child_allocation.width = xpaned->handle_pos_west.width;
788                 top_left_child_allocation.height = xpaned->handle_pos_north.height;
789
790                 /* set allocation for top-right child */
791                 top_right_child_allocation.x = widget->allocation.x + border_width + handle_size + top_left_child_allocation.width;
792                 top_right_child_allocation.y = widget->allocation.y + border_width;
793                 top_right_child_allocation.width = xpaned->handle_pos_east.width;
794                 top_right_child_allocation.height = xpaned->handle_pos_north.height;
795
796                 /* set allocation for bottom-left child */
797                 bottom_left_child_allocation.x = xpaned->handle_pos_west.x;
798                 bottom_left_child_allocation.y = xpaned->handle_pos_south.y;
799                 bottom_left_child_allocation.width = xpaned->handle_pos_west.width;
800                 bottom_left_child_allocation.height = xpaned->handle_pos_south.height;
801
802                 /* set allocation for bottom-right child */
803                 bottom_right_child_allocation.x = top_right_child_allocation.x;
804                 bottom_right_child_allocation.y = bottom_left_child_allocation.y;
805                 bottom_right_child_allocation.width = xpaned->handle_pos_east.width;
806                 bottom_right_child_allocation.height = xpaned->handle_pos_south.height;
807
808                 if (GTK_WIDGET_REALIZED (widget))
809                 {
810                         if (GTK_WIDGET_MAPPED (widget))
811                         {
812                                 gdk_window_show (xpaned->handle_east);
813                                 gdk_window_show (xpaned->handle_west);
814                                 gdk_window_show (xpaned->handle_north);
815                                 gdk_window_show (xpaned->handle_south);
816                                 gdk_window_show (xpaned->handle_middle);
817                         }
818
819                         gdk_window_move_resize (xpaned->handle_east,
820                                                                         xpaned->handle_pos_east.x,
821                                                                         xpaned->handle_pos_east.y,
822                                                                         xpaned->handle_pos_east.width,
823                                                                         xpaned->handle_pos_east.height);
824
825                         gdk_window_move_resize (xpaned->handle_west,
826                                                                         xpaned->handle_pos_west.x,
827                                                                         xpaned->handle_pos_west.y,
828                                                                         xpaned->handle_pos_west.width,
829                                                                         xpaned->handle_pos_west.height);
830
831                         gdk_window_move_resize (xpaned->handle_north,
832                                                                         xpaned->handle_pos_north.x,
833                                                                         xpaned->handle_pos_north.y,
834                                                                         xpaned->handle_pos_north.width,
835                                                                         xpaned->handle_pos_north.height);
836
837                         gdk_window_move_resize (xpaned->handle_south,
838                                                                         xpaned->handle_pos_south.x,
839                                                                         xpaned->handle_pos_south.y,
840                                                                         xpaned->handle_pos_south.width,
841                                                                         xpaned->handle_pos_south.height);
842
843                         gdk_window_move_resize (xpaned->handle_middle,
844                                                 xpaned->handle_pos_middle.x,
845                                                 xpaned->handle_pos_middle.y,
846                                                 xpaned->handle_pos_middle.width,
847                                                 xpaned->handle_pos_middle.height);
848                 }
849
850                 /* Now allocate the childen, making sure, when resizing not to
851                 * overlap the windows
852                 */
853                 if (GTK_WIDGET_MAPPED (widget))
854                 {
855                         gtk_widget_size_allocate (xpaned->top_right_child, &top_right_child_allocation);
856                         gtk_widget_size_allocate (xpaned->top_left_child, &top_left_child_allocation);
857                         gtk_widget_size_allocate (xpaned->bottom_left_child, &bottom_left_child_allocation);
858                         gtk_widget_size_allocate (xpaned->bottom_right_child, &bottom_right_child_allocation);
859                 }
860         }
861 }
862
863 static void gtk_xpaned_set_property (GObject* object,
864                                                                          guint prop_id,
865                                                                          const GValue* value,
866                                                                          GParamSpec* pspec)
867 {
868         GtkXPaned* xpaned = GTK_XPANED (object);
869   
870         switch (prop_id)
871         {
872                 case PROP_X_POSITION:
873                         gtk_xpaned_set_position_x (xpaned, g_value_get_int (value));
874                 break;
875
876                 case PROP_Y_POSITION:
877                         gtk_xpaned_set_position_y (xpaned, g_value_get_int (value));
878                 break;
879
880                 case PROP_POSITION_SET:
881                         xpaned->position_set = g_value_get_boolean (value);
882                         gtk_widget_queue_resize (GTK_WIDGET (xpaned));
883                 break;
884
885                 default:
886                         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
887                 break;
888         }
889 }
890
891 static void gtk_xpaned_get_property (GObject* object,
892                                                                          guint prop_id,
893                                                                          GValue* value,
894                                                                          GParamSpec* pspec)
895 {
896         GtkXPaned* xpaned = GTK_XPANED (object);
897   
898         switch (prop_id)
899         {
900                 case PROP_X_POSITION:
901                         g_value_set_int (value, xpaned->top_left_child_size.width);
902                 break;
903
904                 case PROP_Y_POSITION:
905                         g_value_set_int (value, xpaned->top_left_child_size.height);
906                 break;
907
908                 case PROP_POSITION_SET:
909                         g_value_set_boolean (value, xpaned->position_set);
910                 break;
911
912                 case PROP_MIN_X_POSITION:
913                         g_value_set_int (value, xpaned->min_position.x);
914                 break;
915
916                 case PROP_MIN_Y_POSITION:
917                         g_value_set_int (value, xpaned->min_position.y);
918                 break;
919
920                 case PROP_MAX_X_POSITION:
921                         g_value_set_int (value, xpaned->max_position.x);
922                 break;
923
924                 case PROP_MAX_Y_POSITION:
925                         g_value_set_int (value, xpaned->max_position.y);
926                 break;
927
928                 default:
929                         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
930                 break;
931         }
932 }
933
934 static void gtk_xpaned_set_child_property (GtkContainer* container,
935                                                                                    GtkWidget* child,
936                                                                                    guint property_id,
937                                                                                    const GValue* value,
938                                                                                    GParamSpec* pspec)
939 {
940         GtkXPaned* xpaned = GTK_XPANED (container);
941         gboolean old_value = FALSE;
942         gboolean new_value = FALSE;
943
944         g_assert (child == xpaned->top_left_child ||
945                           child == xpaned->top_right_child ||
946                           child == xpaned->bottom_left_child ||
947                           child == xpaned->bottom_right_child);
948
949         new_value = g_value_get_boolean (value);
950
951         switch (property_id)
952         {
953                 case CHILD_PROP_RESIZE:
954                         if (child == xpaned->top_left_child)
955                         {
956                                 old_value = xpaned->top_left_child_resize;
957                                 xpaned->top_left_child_resize = new_value;
958                         }
959                         else if (child == xpaned->top_right_child)
960                         {
961                                 old_value = xpaned->top_right_child_resize;
962                                 xpaned->top_right_child_resize = new_value;
963                         }
964                         else if (child == xpaned->bottom_left_child)
965                         {
966                                 old_value = xpaned->bottom_left_child_resize;
967                                 xpaned->bottom_left_child_resize = new_value;
968                         }
969                         else if (child == xpaned->bottom_right_child)
970                         {
971                                 old_value = xpaned->bottom_right_child_resize;
972                                 xpaned->bottom_right_child_resize = new_value;
973                         }
974                 break;
975
976                 case CHILD_PROP_SHRINK :
977                         if (child == xpaned->top_left_child)
978                         {
979                                 old_value = xpaned->top_left_child_shrink;
980                                 xpaned->top_left_child_shrink = new_value;
981                         }
982                         else if (child == xpaned->top_right_child)
983                         {
984                                 old_value = xpaned->top_right_child_shrink;
985                                 xpaned->top_right_child_shrink = new_value;
986                         }
987                         else if (child == xpaned->bottom_left_child)
988                         {
989                                 old_value = xpaned->bottom_left_child_shrink;
990                                 xpaned->bottom_left_child_shrink = new_value;
991                         }
992                         else if (child == xpaned->bottom_right_child)
993                         {
994                                 old_value = xpaned->bottom_right_child_shrink;
995                                 xpaned->bottom_right_child_shrink = new_value;
996                         }
997                 break;
998
999                 default:
1000                         GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container,
1001                                                                                                                   property_id,
1002                                                                                                                   pspec);
1003                         old_value = -1; /* quiet gcc */
1004                 break;
1005         }
1006
1007         if (old_value != new_value)
1008                 gtk_widget_queue_resize (GTK_WIDGET (container));
1009 }
1010
1011 static void gtk_xpaned_get_child_property (GtkContainer* container,
1012                                                                                    GtkWidget* child,
1013                                                                                    guint property_id,
1014                                                                                    GValue* value,
1015                                                                                    GParamSpec* pspec)
1016 {
1017         GtkXPaned* xpaned = GTK_XPANED (container);
1018
1019         g_assert (child == xpaned->top_left_child ||
1020                           child == xpaned->top_right_child ||
1021                           child == xpaned->bottom_left_child ||
1022                           child == xpaned->bottom_right_child);
1023
1024         switch (property_id)
1025         {
1026                 case CHILD_PROP_RESIZE :
1027                         if (child == xpaned->top_left_child)
1028                                 g_value_set_boolean (value, xpaned->top_left_child_resize);
1029                         else if (child == xpaned->top_right_child)
1030                                 g_value_set_boolean (value, xpaned->top_right_child_resize);
1031                         else if (child == xpaned->bottom_left_child)
1032                                 g_value_set_boolean (value, xpaned->bottom_left_child_resize);
1033                         else if (child == xpaned->bottom_right_child)
1034                                 g_value_set_boolean (value, xpaned->bottom_right_child_resize);                 
1035                 break;
1036
1037                 case CHILD_PROP_SHRINK :
1038                         if (child == xpaned->top_left_child)
1039                                 g_value_set_boolean (value, xpaned->top_left_child_shrink);
1040                         else if (child == xpaned->top_right_child)
1041                                 g_value_set_boolean (value, xpaned->top_right_child_shrink);
1042                         else if (child == xpaned->bottom_left_child)
1043                                 g_value_set_boolean (value, xpaned->bottom_left_child_shrink);
1044                         else if (child == xpaned->bottom_right_child)
1045                                 g_value_set_boolean (value, xpaned->bottom_right_child_shrink);
1046                 break;
1047
1048                 default:
1049                         GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container,
1050                                                                                                                   property_id,
1051                                                                                                                   pspec);
1052                 break;
1053         }
1054 }
1055
1056 static void gtk_xpaned_finalize (GObject* object)
1057 {
1058         GtkXPaned* xpaned = GTK_XPANED (object);
1059   
1060         gtk_xpaned_set_saved_focus (xpaned, NULL);
1061         gtk_xpaned_set_first_xpaned (xpaned, NULL);
1062
1063         g_free (xpaned->priv);
1064
1065         G_OBJECT_CLASS (parent_class)->finalize (object);
1066 }
1067
1068 static void gtk_xpaned_realize (GtkWidget* widget)
1069 {
1070         GtkXPaned* xpaned;
1071         GdkWindowAttr attributes_east;
1072         GdkWindowAttr attributes_west;
1073         GdkWindowAttr attributes_north;
1074         GdkWindowAttr attributes_south;
1075         GdkWindowAttr attributes_middle;
1076         gint attributes_mask_east;
1077         gint attributes_mask_west;
1078         gint attributes_mask_north;
1079         gint attributes_mask_south;
1080         gint attributes_mask_middle;
1081
1082         GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
1083         xpaned = GTK_XPANED (widget);
1084
1085         widget->window = gtk_widget_get_parent_window (widget);
1086         g_object_ref (widget->window);
1087   
1088         attributes_east.window_type = GDK_WINDOW_CHILD;
1089         attributes_west.window_type = GDK_WINDOW_CHILD;
1090         attributes_north.window_type = GDK_WINDOW_CHILD;
1091         attributes_south.window_type = GDK_WINDOW_CHILD;
1092         attributes_middle.window_type = GDK_WINDOW_CHILD;
1093
1094         attributes_east.wclass = GDK_INPUT_ONLY;
1095         attributes_west.wclass = GDK_INPUT_ONLY;
1096         attributes_north.wclass = GDK_INPUT_ONLY;
1097         attributes_south.wclass = GDK_INPUT_ONLY;
1098         attributes_middle.wclass = GDK_INPUT_ONLY;
1099
1100         attributes_east.x = xpaned->handle_pos_east.x;
1101         attributes_east.y = xpaned->handle_pos_east.y;
1102         attributes_east.width = xpaned->handle_pos_east.width;
1103         attributes_east.height = xpaned->handle_pos_east.height;
1104
1105         attributes_west.x = xpaned->handle_pos_west.x;
1106         attributes_west.y = xpaned->handle_pos_west.y;
1107         attributes_west.width = xpaned->handle_pos_west.width;
1108         attributes_west.height = xpaned->handle_pos_west.height;
1109
1110         attributes_north.x = xpaned->handle_pos_north.x;
1111         attributes_north.y = xpaned->handle_pos_north.y;
1112         attributes_north.width = xpaned->handle_pos_north.width;
1113         attributes_north.height = xpaned->handle_pos_north.height;
1114
1115         attributes_south.x = xpaned->handle_pos_south.x;
1116         attributes_south.y = xpaned->handle_pos_south.y;
1117         attributes_south.width = xpaned->handle_pos_south.width;
1118         attributes_south.height = xpaned->handle_pos_south.height;
1119
1120         attributes_middle.x = xpaned->handle_pos_middle.x;
1121         attributes_middle.y = xpaned->handle_pos_middle.y;
1122         attributes_middle.width = xpaned->handle_pos_middle.width;
1123         attributes_middle.height = xpaned->handle_pos_middle.height;
1124
1125         attributes_east.cursor = gdk_cursor_new_for_display (gtk_widget_get_display (widget),
1126                                                                                                         xpaned->cursor_type_east);
1127         attributes_west.cursor = gdk_cursor_new_for_display (gtk_widget_get_display (widget),
1128                                                                                                         xpaned->cursor_type_west);
1129         attributes_north.cursor = gdk_cursor_new_for_display (gtk_widget_get_display (widget),
1130                                                                                                         xpaned->cursor_type_north);
1131         attributes_south.cursor = gdk_cursor_new_for_display (gtk_widget_get_display (widget),
1132                                                                                                         xpaned->cursor_type_south);
1133         attributes_middle.cursor = gdk_cursor_new_for_display (gtk_widget_get_display (widget),
1134                                                                                                         xpaned->cursor_type_middle);
1135
1136         attributes_east.event_mask = gtk_widget_get_events (widget);
1137         attributes_west.event_mask = gtk_widget_get_events (widget);
1138         attributes_north.event_mask = gtk_widget_get_events (widget);
1139         attributes_south.event_mask = gtk_widget_get_events (widget);
1140         attributes_middle.event_mask = gtk_widget_get_events (widget);
1141
1142         attributes_east.event_mask |= (GDK_BUTTON_PRESS_MASK |
1143                                                           GDK_BUTTON_RELEASE_MASK |
1144                                                           GDK_ENTER_NOTIFY_MASK |
1145                                                           GDK_LEAVE_NOTIFY_MASK |
1146                                                           GDK_POINTER_MOTION_MASK |
1147                                                           GDK_POINTER_MOTION_HINT_MASK);
1148         attributes_west.event_mask |= (GDK_BUTTON_PRESS_MASK |
1149                                                           GDK_BUTTON_RELEASE_MASK |
1150                                                           GDK_ENTER_NOTIFY_MASK |
1151                                                           GDK_LEAVE_NOTIFY_MASK |
1152                                                           GDK_POINTER_MOTION_MASK |
1153                                                           GDK_POINTER_MOTION_HINT_MASK);
1154         attributes_north.event_mask |= (GDK_BUTTON_PRESS_MASK |
1155                                                           GDK_BUTTON_RELEASE_MASK |
1156                                                           GDK_ENTER_NOTIFY_MASK |
1157                                                           GDK_LEAVE_NOTIFY_MASK |
1158                                                           GDK_POINTER_MOTION_MASK |
1159                                                           GDK_POINTER_MOTION_HINT_MASK);
1160         attributes_south.event_mask |= (GDK_BUTTON_PRESS_MASK |
1161                                                           GDK_BUTTON_RELEASE_MASK |
1162                                                           GDK_ENTER_NOTIFY_MASK |
1163                                                           GDK_LEAVE_NOTIFY_MASK |
1164                                                           GDK_POINTER_MOTION_MASK |
1165                                                           GDK_POINTER_MOTION_HINT_MASK);
1166         attributes_middle.event_mask |= (GDK_BUTTON_PRESS_MASK |
1167                                                           GDK_BUTTON_RELEASE_MASK |
1168                                                           GDK_ENTER_NOTIFY_MASK |
1169                                                           GDK_LEAVE_NOTIFY_MASK |
1170                                                           GDK_POINTER_MOTION_MASK |
1171                                                           GDK_POINTER_MOTION_HINT_MASK);
1172
1173         attributes_mask_east = GDK_WA_X | GDK_WA_Y | GDK_WA_CURSOR;
1174         attributes_mask_west = GDK_WA_X | GDK_WA_Y | GDK_WA_CURSOR;
1175         attributes_mask_north = GDK_WA_X | GDK_WA_Y | GDK_WA_CURSOR;
1176         attributes_mask_south = GDK_WA_X | GDK_WA_Y | GDK_WA_CURSOR;
1177         attributes_mask_middle = GDK_WA_X | GDK_WA_Y | GDK_WA_CURSOR;
1178
1179         xpaned->handle_east = gdk_window_new (widget->window,
1180                                                                                   &attributes_east,
1181                                                                                   attributes_mask_east);
1182         xpaned->handle_west = gdk_window_new (widget->window,
1183                                                                                   &attributes_west,
1184                                                                                   attributes_mask_west);
1185         xpaned->handle_north = gdk_window_new (widget->window,
1186                                                                                   &attributes_north,
1187                                                                                   attributes_mask_north);
1188         xpaned->handle_south = gdk_window_new (widget->window,
1189                                                                                   &attributes_south,
1190                                                                                   attributes_mask_south);
1191         xpaned->handle_middle = gdk_window_new (widget->window,
1192                                                                                   &attributes_middle,
1193                                                                                   attributes_mask_middle);
1194
1195         gdk_window_set_user_data (xpaned->handle_east, xpaned);
1196         gdk_window_set_user_data (xpaned->handle_west, xpaned);
1197         gdk_window_set_user_data (xpaned->handle_north, xpaned);
1198         gdk_window_set_user_data (xpaned->handle_south, xpaned);
1199         gdk_window_set_user_data (xpaned->handle_middle, xpaned);
1200
1201         gdk_cursor_unref (attributes_east.cursor);
1202         gdk_cursor_unref (attributes_west.cursor);
1203         gdk_cursor_unref (attributes_north.cursor);
1204         gdk_cursor_unref (attributes_south.cursor);
1205         gdk_cursor_unref (attributes_middle.cursor);
1206
1207         widget->style = gtk_style_attach (widget->style, widget->window);
1208
1209         if (xpaned->top_left_child && GTK_WIDGET_VISIBLE (xpaned->top_left_child) &&
1210                 xpaned->top_right_child && GTK_WIDGET_VISIBLE (xpaned->top_right_child) &&
1211                 xpaned->bottom_left_child && GTK_WIDGET_VISIBLE (xpaned->bottom_left_child) &&
1212                 xpaned->bottom_right_child && GTK_WIDGET_VISIBLE (xpaned->bottom_right_child))
1213         {
1214                 gdk_window_show (xpaned->handle_east);
1215                 gdk_window_show (xpaned->handle_west);
1216                 gdk_window_show (xpaned->handle_north);
1217                 gdk_window_show (xpaned->handle_south);
1218                 gdk_window_show (xpaned->handle_middle);
1219         }
1220 }
1221
1222 static void gtk_xpaned_unrealize (GtkWidget *widget)
1223 {
1224         GtkXPaned* xpaned = GTK_XPANED (widget);
1225
1226         if (xpaned->xor_gc)
1227         {
1228                 g_object_unref (xpaned->xor_gc);
1229                 xpaned->xor_gc = NULL;
1230         }
1231
1232         if (xpaned->handle_east)
1233         {
1234                 gdk_window_set_user_data (xpaned->handle_east, NULL);
1235                 gdk_window_destroy (xpaned->handle_east);
1236                 xpaned->handle_east = NULL;
1237         }
1238
1239         if (xpaned->handle_west)
1240         {
1241                 gdk_window_set_user_data (xpaned->handle_west, NULL);
1242                 gdk_window_destroy (xpaned->handle_west);
1243                 xpaned->handle_west = NULL;
1244         }
1245
1246         if (xpaned->handle_north)
1247         {
1248                 gdk_window_set_user_data (xpaned->handle_north, NULL);
1249                 gdk_window_destroy (xpaned->handle_north);
1250                 xpaned->handle_north = NULL;
1251         }
1252
1253         if (xpaned->handle_south)
1254         {
1255                 gdk_window_set_user_data (xpaned->handle_south, NULL);
1256                 gdk_window_destroy (xpaned->handle_south);
1257                 xpaned->handle_south = NULL;
1258         }
1259
1260         if (xpaned->handle_middle)
1261         {
1262                 gdk_window_set_user_data (xpaned->handle_middle, NULL);
1263                 gdk_window_destroy (xpaned->handle_middle);
1264                 xpaned->handle_middle = NULL;
1265         }
1266
1267         gtk_xpaned_set_last_top_left_child_focus (xpaned, NULL);
1268         gtk_xpaned_set_last_top_right_child_focus (xpaned, NULL);
1269         gtk_xpaned_set_last_bottom_left_child_focus (xpaned, NULL);
1270         gtk_xpaned_set_last_bottom_right_child_focus (xpaned, NULL);
1271         gtk_xpaned_set_saved_focus (xpaned, NULL);
1272         gtk_xpaned_set_first_xpaned (xpaned, NULL);
1273   
1274         if (GTK_WIDGET_CLASS (parent_class)->unrealize)
1275                 (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
1276 }
1277
1278 static void gtk_xpaned_map (GtkWidget* widget)
1279 {
1280         GtkXPaned* xpaned = GTK_XPANED (widget);
1281
1282         gdk_window_show (xpaned->handle_east);
1283         gdk_window_show (xpaned->handle_west);
1284         gdk_window_show (xpaned->handle_north);
1285         gdk_window_show (xpaned->handle_south);
1286         gdk_window_show (xpaned->handle_middle);
1287
1288         GTK_WIDGET_CLASS (parent_class)->map (widget);
1289 }
1290
1291 static void gtk_xpaned_unmap (GtkWidget* widget)
1292 {
1293         GtkXPaned* xpaned = GTK_XPANED (widget);
1294
1295         gdk_window_hide (xpaned->handle_east);
1296         gdk_window_hide (xpaned->handle_west);
1297         gdk_window_hide (xpaned->handle_north);
1298         gdk_window_hide (xpaned->handle_south);
1299         gdk_window_hide (xpaned->handle_middle);
1300
1301         GTK_WIDGET_CLASS (parent_class)->unmap (widget);
1302 }
1303
1304 static gboolean gtk_xpaned_expose (GtkWidget* widget,
1305                                                                    GdkEventExpose* event)
1306 {
1307         GtkXPaned* xpaned = GTK_XPANED (widget);
1308         gint handle_size;
1309         GdkRectangle horizontalClipArea;
1310         GdkRectangle verticalClipArea;
1311
1312         /* determine size of handle(s) */
1313         gtk_widget_style_get (widget, "handle-size", &handle_size, NULL);
1314
1315         /* I want the handle-"thickness" to be at least 3 */
1316         g_assert (handle_size >= 3);
1317
1318         if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_MAPPED (widget) &&
1319                 xpaned->top_left_child && GTK_WIDGET_VISIBLE (xpaned->top_left_child) &&
1320                 xpaned->top_right_child && GTK_WIDGET_VISIBLE (xpaned->top_right_child) &&
1321                 xpaned->bottom_left_child && GTK_WIDGET_VISIBLE (xpaned->bottom_left_child) &&
1322                 xpaned->bottom_right_child && GTK_WIDGET_VISIBLE (xpaned->bottom_right_child))
1323     {
1324                 GtkStateType state;
1325
1326                 if (gtk_widget_is_focus (widget))
1327                         state = GTK_STATE_SELECTED;
1328                 else if (xpaned->handle_prelit)
1329                         state = GTK_STATE_PRELIGHT;
1330                 else
1331                         state = GTK_WIDGET_STATE (widget);
1332
1333                 horizontalClipArea.x = xpaned->handle_pos_west.x;
1334                 horizontalClipArea.y = xpaned->handle_pos_west.y;
1335                 horizontalClipArea.width = xpaned->handle_pos_west.width + handle_size + xpaned->handle_pos_east.width;
1336                 horizontalClipArea.height = handle_size;
1337
1338                 verticalClipArea.x = xpaned->handle_pos_north.x;
1339                 verticalClipArea.y = xpaned->handle_pos_north.y;
1340                 verticalClipArea.width = handle_size;
1341                 verticalClipArea.height = xpaned->handle_pos_north.height + handle_size + xpaned->handle_pos_south.height;
1342
1343                 gtk_paint_handle (widget->style,
1344                                                   widget->window,
1345                                                   state,
1346                                                   GTK_SHADOW_NONE,
1347                                                   &horizontalClipArea,
1348                                                   widget,
1349                                                   "paned",
1350                                                   xpaned->handle_pos_east.x - handle_size - 256 / 2,
1351                                                   xpaned->handle_pos_west.y + 1,
1352                                                   256 + handle_size,
1353                                                   handle_size - 2,
1354                                                   /*xpaned->handle_pos_west.x,
1355                                                   xpaned->handle_pos_west.y + 1,
1356                                                   xpaned->handle_pos_west.width + handle_size + xpaned->handle_pos_east.width,
1357                                                   handle_size - 2,*/
1358                                                   GTK_ORIENTATION_HORIZONTAL);
1359                 gtk_paint_handle (widget->style,
1360                                                   widget->window,
1361                                                   state,
1362                                                   GTK_SHADOW_NONE,
1363                                                   &verticalClipArea,
1364                                                   widget,
1365                                                   "paned",
1366                                                   xpaned->handle_pos_north.x + 1,
1367                                                   xpaned->handle_pos_south.y - handle_size - 256 / 2,
1368                                                   handle_size - 2,
1369                                                   256 + handle_size,
1370                                                   /*xpaned->handle_pos_north.x + 1,
1371                                                   xpaned->handle_pos_north.y,
1372                                                   handle_size - 2,
1373                                                   xpaned->handle_pos_north.height + handle_size + xpaned->handle_pos_south.height,*/
1374                                                   GTK_ORIENTATION_VERTICAL);
1375         }
1376
1377         /* Chain up to draw children */
1378         GTK_WIDGET_CLASS (parent_class)->expose_event (widget, event);
1379   
1380         return FALSE;
1381 }
1382
1383 static gboolean is_rtl (GtkXPaned* xpaned)
1384 {
1385         if (gtk_widget_get_direction (GTK_WIDGET (xpaned)) == GTK_TEXT_DIR_RTL)
1386                 return TRUE;
1387
1388         return FALSE;
1389 }
1390
1391 static void update_drag (GtkXPaned* xpaned)
1392 {
1393         GdkPoint pos;
1394         gint handle_size;
1395         GtkRequisition size;
1396   
1397         gtk_widget_get_pointer (GTK_WIDGET (xpaned), &pos.x, &pos.y);
1398
1399         if (xpaned->in_drag_vert)
1400         {
1401                 pos.y -= xpaned->drag_pos.y;
1402
1403                 if (is_rtl (xpaned))
1404             {
1405                         gtk_widget_style_get (GTK_WIDGET (xpaned),
1406                                                                   "handle-size", &handle_size,
1407                                                                   NULL);
1408       
1409                         size.height = GTK_WIDGET (xpaned)->allocation.height - pos.y - handle_size;
1410                 }
1411                 else
1412                 {
1413                         size.height = pos.y;
1414                 }
1415
1416                 size.height -= GTK_CONTAINER (xpaned)->border_width;
1417
1418                 size.height = CLAMP (size.height, xpaned->min_position.y, xpaned->max_position.y);
1419
1420                 if (size.height != xpaned->top_left_child_size.height)
1421                         gtk_xpaned_set_position_y (xpaned, size.height);
1422         }
1423
1424         if (xpaned->in_drag_horiz)
1425         {
1426                 pos.x -= xpaned->drag_pos.x;
1427         
1428                 if (is_rtl (xpaned))
1429             {
1430                         gtk_widget_style_get (GTK_WIDGET (xpaned),
1431                                                                   "handle-size", &handle_size,
1432                                                                   NULL);
1433
1434                         size.width = GTK_WIDGET (xpaned)->allocation.width - pos.x - handle_size;
1435                 }
1436                 else
1437                 {
1438                         size.width = pos.x;
1439                 }
1440
1441                 size.width -= GTK_CONTAINER (xpaned)->border_width;
1442
1443                 size.width = CLAMP (size.width, xpaned->min_position.x, xpaned->max_position.x);
1444
1445                 if (size.width != xpaned->top_left_child_size.width)
1446                         gtk_xpaned_set_position_x (xpaned, size.width);
1447         }
1448
1449         if (xpaned->in_drag_vert_and_horiz)
1450         {
1451                 pos.x -= xpaned->drag_pos.x;
1452                 pos.y -= xpaned->drag_pos.y;
1453
1454                 if (is_rtl (xpaned))
1455             {
1456                         gtk_widget_style_get (GTK_WIDGET (xpaned),
1457                                                                   "handle-size", &handle_size,
1458                                                                   NULL);
1459       
1460                         size.width = GTK_WIDGET (xpaned)->allocation.width - pos.x - handle_size;
1461                         size.height = GTK_WIDGET (xpaned)->allocation.height - pos.y - handle_size;
1462                 }
1463                 else
1464                 {
1465                         size.width = pos.x;
1466                         size.height = pos.y;
1467                 }
1468
1469                 size.width -= GTK_CONTAINER (xpaned)->border_width;
1470                 size.height -= GTK_CONTAINER (xpaned)->border_width;
1471
1472                 size.width = CLAMP (size.width, xpaned->min_position.x, xpaned->max_position.x);
1473                 size.height = CLAMP (size.height, xpaned->min_position.y, xpaned->max_position.y);
1474
1475                 if (size.width != xpaned->top_left_child_size.width)
1476                         gtk_xpaned_set_position_x (xpaned, size.width);
1477
1478                 if (size.height != xpaned->top_left_child_size.height)
1479                         gtk_xpaned_set_position_y (xpaned, size.height);
1480         }
1481 }
1482
1483 static gboolean gtk_xpaned_enter (GtkWidget* widget, GdkEventCrossing* event)
1484 {
1485         GtkXPaned* xpaned = GTK_XPANED (widget);
1486
1487         if (xpaned->in_drag_vert ||
1488                 xpaned->in_drag_horiz ||
1489                 xpaned->in_drag_vert_and_horiz)
1490                 update_drag (xpaned);
1491         else
1492         {
1493                 xpaned->handle_prelit = TRUE;
1494
1495                 gtk_widget_queue_draw_area (widget,
1496                                                                         xpaned->handle_pos_east.x,
1497                                                                         xpaned->handle_pos_east.y,
1498                                                                         xpaned->handle_pos_east.width,
1499                                                                         xpaned->handle_pos_east.height);
1500
1501                 gtk_widget_queue_draw_area (widget,
1502                                                                         xpaned->handle_pos_west.x,
1503                                                                         xpaned->handle_pos_west.y,
1504                                                                         xpaned->handle_pos_west.width,
1505                                                                         xpaned->handle_pos_west.height);
1506
1507                 gtk_widget_queue_draw_area (widget,
1508                                                                         xpaned->handle_pos_north.x,
1509                                                                         xpaned->handle_pos_north.y,
1510                                                                         xpaned->handle_pos_north.width,
1511                                                                         xpaned->handle_pos_north.height);
1512
1513                 gtk_widget_queue_draw_area (widget,
1514                                                                         xpaned->handle_pos_south.x,
1515                                                                         xpaned->handle_pos_south.y,
1516                                                                         xpaned->handle_pos_south.width,
1517                                                                         xpaned->handle_pos_south.height);
1518
1519                 gtk_widget_queue_draw_area (widget,
1520                                                                         xpaned->handle_pos_middle.x,
1521                                                                         xpaned->handle_pos_middle.y,
1522                                                                         xpaned->handle_pos_middle.width,
1523                                                                         xpaned->handle_pos_middle.height);
1524         }
1525
1526         return TRUE;
1527 }
1528
1529 static gboolean gtk_xpaned_leave (GtkWidget* widget, GdkEventCrossing* event)
1530 {
1531         GtkXPaned* xpaned = GTK_XPANED (widget);
1532
1533         if (xpaned->in_drag_vert ||
1534                 xpaned->in_drag_horiz ||
1535                 xpaned->in_drag_vert_and_horiz)
1536                 update_drag (xpaned);
1537         else
1538         {
1539                 xpaned->handle_prelit = FALSE;
1540
1541                 gtk_widget_queue_draw_area (widget,
1542                                                                         xpaned->handle_pos_east.x,
1543                                                                         xpaned->handle_pos_east.y,
1544                                                                         xpaned->handle_pos_east.width,
1545                                                                         xpaned->handle_pos_east.height);
1546
1547                 gtk_widget_queue_draw_area (widget,
1548                                                                         xpaned->handle_pos_west.x,
1549                                                                         xpaned->handle_pos_west.y,
1550                                                                         xpaned->handle_pos_west.width,
1551                                                                         xpaned->handle_pos_west.height);
1552
1553                 gtk_widget_queue_draw_area (widget,
1554                                                                         xpaned->handle_pos_north.x,
1555                                                                         xpaned->handle_pos_north.y,
1556                                                                         xpaned->handle_pos_north.width,
1557                                                                         xpaned->handle_pos_north.height);
1558
1559                 gtk_widget_queue_draw_area (widget,
1560                                                                         xpaned->handle_pos_south.x,
1561                                                                         xpaned->handle_pos_south.y,
1562                                                                         xpaned->handle_pos_south.width,
1563                                                                         xpaned->handle_pos_south.height);
1564
1565                 gtk_widget_queue_draw_area (widget,
1566                                                                         xpaned->handle_pos_middle.x,
1567                                                                         xpaned->handle_pos_middle.y,
1568                                                                         xpaned->handle_pos_middle.width,
1569                                                                         xpaned->handle_pos_middle.height);
1570         }
1571
1572         return TRUE;
1573 }
1574
1575 static gboolean gtk_xpaned_focus (GtkWidget* widget, GtkDirectionType direction)
1576 {
1577         gboolean retval;
1578
1579         /* This is a hack, but how can this be done without
1580         * excessive cut-and-paste from gtkcontainer.c?
1581         */
1582
1583         GTK_WIDGET_UNSET_FLAGS (widget, GTK_CAN_FOCUS);
1584         retval = (* GTK_WIDGET_CLASS (parent_class)->focus) (widget, direction);
1585         GTK_WIDGET_SET_FLAGS (widget, GTK_CAN_FOCUS);
1586
1587   return retval;
1588 }
1589
1590 static gboolean gtk_xpaned_button_press (GtkWidget* widget,
1591                                                                                  GdkEventButton* event)
1592 {
1593         GtkXPaned* xpaned = GTK_XPANED (widget);
1594
1595         /* if any child is currently maximized, jump right back */
1596         if (xpaned->maximized[GTK_XPANED_TOP_LEFT]    ||
1597                 xpaned->maximized[GTK_XPANED_TOP_RIGHT]   ||
1598                 xpaned->maximized[GTK_XPANED_BOTTOM_LEFT] ||
1599                 xpaned->maximized[GTK_XPANED_BOTTOM_RIGHT])
1600                 return FALSE;
1601
1602         /* if user is dragging the handles around */
1603         if (!xpaned->in_drag_vert_and_horiz &&
1604                          event->window != xpaned->handle_east &&
1605                          event->window != xpaned->handle_west &&
1606                          event->window != xpaned->handle_north &&
1607                          event->window != xpaned->handle_south &&
1608                          event->window == xpaned->handle_middle &&
1609                          event->button == 1)
1610         {
1611                 xpaned->in_drag_vert_and_horiz = TRUE;
1612
1613                 /* We need a server grab here, not gtk_grab_add(), since
1614                 * we don't want to pass events on to the widget's children */
1615                 if (gdk_pointer_grab (xpaned->handle_middle,
1616                                                           FALSE,
1617                                                           GDK_POINTER_MOTION_HINT_MASK
1618                                                           | GDK_BUTTON1_MOTION_MASK
1619                                                           | GDK_BUTTON_RELEASE_MASK
1620                                                           | GDK_ENTER_NOTIFY_MASK
1621                                                           | GDK_LEAVE_NOTIFY_MASK,
1622                                                           NULL,
1623                                                           NULL,
1624                                                           event->time) == GDK_GRAB_SUCCESS)
1625                 {
1626                 }
1627
1628                 xpaned->drag_pos.x = event->x;
1629                 xpaned->drag_pos.y = event->y;
1630
1631                 return TRUE;
1632         }
1633         else if (!xpaned->in_drag_vert &&
1634                 event->window == xpaned->handle_east &&
1635                 event->window != xpaned->handle_west &&
1636                 event->window != xpaned->handle_north &&
1637                 event->window != xpaned->handle_south &&
1638                 event->window != xpaned->handle_middle &&
1639                 event->button == 1)
1640         {
1641                 xpaned->in_drag_vert = TRUE;
1642
1643                 /* We need a server grab here, not gtk_grab_add(), since
1644                 * we don't want to pass events on to the widget's children */
1645                 if (gdk_pointer_grab (xpaned->handle_east,
1646                                                           FALSE,
1647                                                           GDK_POINTER_MOTION_HINT_MASK
1648                                                           | GDK_BUTTON1_MOTION_MASK
1649                                                           | GDK_BUTTON_RELEASE_MASK
1650                                                           | GDK_ENTER_NOTIFY_MASK
1651                                                           | GDK_LEAVE_NOTIFY_MASK,
1652                                                           NULL,
1653                                                           NULL,
1654                                                           event->time) == GDK_GRAB_SUCCESS)
1655                 {
1656                 }
1657
1658                 xpaned->drag_pos.y = event->y;
1659
1660                 return TRUE;
1661         }
1662         else if (!xpaned->in_drag_vert &&
1663                          event->window != xpaned->handle_east &&
1664                          event->window == xpaned->handle_west &&
1665                          event->window != xpaned->handle_north &&
1666                          event->window != xpaned->handle_south &&
1667                          event->window != xpaned->handle_middle &&
1668                          event->button == 1)
1669         {
1670                 xpaned->in_drag_vert = TRUE;
1671
1672                 /* We need a server grab here, not gtk_grab_add(), since
1673                 * we don't want to pass events on to the widget's children */
1674                 if (gdk_pointer_grab (xpaned->handle_west,
1675                                                           FALSE,
1676                                                           GDK_POINTER_MOTION_HINT_MASK
1677                                                           | GDK_BUTTON1_MOTION_MASK
1678                                                           | GDK_BUTTON_RELEASE_MASK
1679                                                           | GDK_ENTER_NOTIFY_MASK
1680                                                           | GDK_LEAVE_NOTIFY_MASK,
1681                                                           NULL,
1682                                                           NULL,
1683                                                           event->time) == GDK_GRAB_SUCCESS)
1684                 {
1685                 }
1686
1687                 xpaned->drag_pos.y = event->y;
1688
1689                 return TRUE;
1690         }
1691         else if (!xpaned->in_drag_horiz &&
1692                          event->window != xpaned->handle_east &&
1693                          event->window != xpaned->handle_west &&
1694                          event->window == xpaned->handle_north &&
1695                          event->window != xpaned->handle_south &&
1696                          event->window != xpaned->handle_middle &&
1697                          event->button == 1)
1698         {
1699                 xpaned->in_drag_horiz = TRUE;
1700
1701                 /* We need a server grab here, not gtk_grab_add(), since
1702                 * we don't want to pass events on to the widget's children */
1703                 if (gdk_pointer_grab (xpaned->handle_north,
1704                                                           FALSE,
1705                                                           GDK_POINTER_MOTION_HINT_MASK
1706                                                           | GDK_BUTTON1_MOTION_MASK
1707                                                           | GDK_BUTTON_RELEASE_MASK
1708                                                           | GDK_ENTER_NOTIFY_MASK
1709                                                           | GDK_LEAVE_NOTIFY_MASK,
1710                                                           NULL,
1711                                                           NULL,
1712                                                           event->time) == GDK_GRAB_SUCCESS)
1713                 {
1714                 }
1715
1716                 xpaned->drag_pos.x = event->x;
1717
1718                 return TRUE;
1719         }
1720         else if (!xpaned->in_drag_horiz &&
1721                          event->window != xpaned->handle_east &&
1722                          event->window != xpaned->handle_west &&
1723                          event->window != xpaned->handle_north &&
1724                          event->window == xpaned->handle_south &&
1725                          event->window != xpaned->handle_middle &&
1726                          event->button == 1)
1727         {
1728                 xpaned->in_drag_horiz = TRUE;
1729
1730                 /* We need a server grab here, not gtk_grab_add(), since
1731                 * we don't want to pass events on to the widget's children */
1732                 if (gdk_pointer_grab (xpaned->handle_south,
1733                                                           FALSE,
1734                                                           GDK_POINTER_MOTION_HINT_MASK
1735                                                           | GDK_BUTTON1_MOTION_MASK
1736                                                           | GDK_BUTTON_RELEASE_MASK
1737                                                           | GDK_ENTER_NOTIFY_MASK
1738                                                           | GDK_LEAVE_NOTIFY_MASK,
1739                                                           NULL,
1740                                                           NULL,
1741                                                           event->time) == GDK_GRAB_SUCCESS)
1742                 {
1743                 }
1744
1745                 xpaned->drag_pos.x = event->x;
1746
1747                 return TRUE;
1748         }
1749         return FALSE;
1750 }
1751
1752 static gboolean gtk_xpaned_button_release (GtkWidget* widget,
1753                                                                                    GdkEventButton* event)
1754 {
1755         GtkXPaned* xpaned = GTK_XPANED (widget);
1756
1757         if (xpaned->in_drag_vert && (event->button == 1))
1758         {
1759                 xpaned->in_drag_vert = FALSE;
1760                 xpaned->drag_pos.y = -1;
1761                 xpaned->position_set = TRUE;
1762                 gdk_display_pointer_ungrab (gtk_widget_get_display (widget),
1763                                                                         event->time);
1764                 return TRUE;
1765     }
1766         else if (xpaned->in_drag_horiz && (event->button == 1))
1767         {
1768                 xpaned->in_drag_horiz = FALSE;
1769                 xpaned->drag_pos.x = -1;
1770                 xpaned->position_set = TRUE;
1771                 gdk_display_pointer_ungrab (gtk_widget_get_display (widget),
1772                                                                         event->time);
1773                 return TRUE;
1774     }
1775         else if (xpaned->in_drag_vert_and_horiz && (event->button == 1))
1776         {
1777                 xpaned->in_drag_vert_and_horiz = FALSE;
1778                 xpaned->drag_pos.x = -1;
1779                 xpaned->drag_pos.y = -1;
1780                 xpaned->position_set = TRUE;
1781                 gdk_display_pointer_ungrab (gtk_widget_get_display (widget),
1782                                                                         event->time);
1783                 return TRUE;
1784     }
1785
1786         return FALSE;
1787 }
1788
1789 static gboolean gtk_xpaned_motion (GtkWidget* widget, GdkEventMotion* event)
1790 {
1791         GtkXPaned* xpaned = GTK_XPANED (widget);
1792
1793         if (xpaned->in_drag_vert ||
1794                 xpaned->in_drag_horiz ||
1795                 xpaned->in_drag_vert_and_horiz)
1796
1797         {
1798                 update_drag (xpaned);
1799                 return TRUE;
1800         }
1801
1802         return FALSE;
1803 }
1804
1805 void gtk_xpaned_add_top_left (GtkXPaned* xpaned, GtkWidget *widget)
1806 {
1807         gtk_xpaned_pack_top_left (xpaned, widget, FALSE, TRUE);
1808 }
1809
1810 void gtk_xpaned_add_top_right (GtkXPaned* xpaned, GtkWidget *widget)
1811 {
1812         gtk_xpaned_pack_top_right (xpaned, widget, FALSE, TRUE);
1813 }
1814
1815 void gtk_xpaned_add_bottom_left (GtkXPaned* xpaned, GtkWidget *widget)
1816 {
1817         gtk_xpaned_pack_bottom_left (xpaned, widget, FALSE, TRUE);
1818 }
1819
1820 void gtk_xpaned_add_bottom_right (GtkXPaned* xpaned, GtkWidget *widget)
1821 {
1822         gtk_xpaned_pack_bottom_right (xpaned, widget, FALSE, TRUE);
1823 }
1824
1825 void gtk_xpaned_pack_top_left (GtkXPaned* xpaned,
1826                                                            GtkWidget* child,
1827                                                            gboolean   resize,
1828                                                            gboolean   shrink)
1829 {
1830         g_return_if_fail (GTK_IS_XPANED (xpaned));
1831         g_return_if_fail (GTK_IS_WIDGET (child));
1832
1833         if (!xpaned->top_left_child)
1834         {
1835                 xpaned->top_left_child = child;
1836                 xpaned->top_left_child_resize = resize;
1837                 xpaned->top_left_child_shrink = shrink;
1838
1839                 gtk_widget_set_parent (child, GTK_WIDGET (xpaned));
1840         }
1841 }
1842
1843 void gtk_xpaned_pack_top_right (GtkXPaned* xpaned,
1844                                                                 GtkWidget* child,
1845                                                                 gboolean   resize,
1846                                                                 gboolean   shrink)
1847 {
1848         g_return_if_fail (GTK_IS_XPANED (xpaned));
1849         g_return_if_fail (GTK_IS_WIDGET (child));
1850
1851         if (!xpaned->top_right_child)
1852         {
1853                 xpaned->top_right_child = child;
1854                 xpaned->top_right_child_resize = resize;
1855                 xpaned->top_right_child_shrink = shrink;
1856
1857                 gtk_widget_set_parent (child, GTK_WIDGET (xpaned));
1858         }
1859 }
1860
1861 void gtk_xpaned_pack_bottom_left (GtkXPaned* xpaned,
1862                                                                   GtkWidget* child,
1863                                                                   gboolean   resize,
1864                                                                   gboolean   shrink)
1865 {
1866         g_return_if_fail (GTK_IS_XPANED (xpaned));
1867         g_return_if_fail (GTK_IS_WIDGET (child));
1868
1869         if (!xpaned->bottom_left_child)
1870         {
1871                 xpaned->bottom_left_child = child;
1872                 xpaned->bottom_left_child_resize = resize;
1873                 xpaned->bottom_left_child_shrink = shrink;
1874
1875                 gtk_widget_set_parent (child, GTK_WIDGET (xpaned));
1876         }
1877 }
1878
1879 void gtk_xpaned_pack_bottom_right (GtkXPaned* xpaned,
1880                                                                    GtkWidget* child,
1881                                                                    gboolean   resize,
1882                                                                    gboolean   shrink)
1883 {
1884         g_return_if_fail (GTK_IS_XPANED (xpaned));
1885         g_return_if_fail (GTK_IS_WIDGET (child));
1886
1887         if (!xpaned->bottom_right_child)
1888         {
1889                 xpaned->bottom_right_child = child;
1890                 xpaned->bottom_right_child_resize = resize;
1891                 xpaned->bottom_right_child_shrink = shrink;
1892
1893                 gtk_widget_set_parent (child, GTK_WIDGET (xpaned));
1894         }
1895 }
1896
1897 static void gtk_xpaned_add (GtkContainer* container, GtkWidget* widget)
1898 {
1899         GtkXPaned* xpaned;
1900
1901         g_return_if_fail (GTK_IS_XPANED (container));
1902
1903         xpaned = GTK_XPANED (container);
1904
1905         if (!xpaned->top_left_child)
1906                 gtk_xpaned_add_top_left (xpaned, widget);
1907         else if (!xpaned->top_right_child)
1908                 gtk_xpaned_add_top_right (xpaned, widget);
1909         else if (!xpaned->bottom_left_child)
1910                 gtk_xpaned_add_bottom_left (xpaned, widget);
1911         else if (!xpaned->bottom_right_child)
1912                 gtk_xpaned_add_bottom_right (xpaned, widget);
1913         else
1914                 g_warning ("GtkXPaned cannot have more than 4 children\n");
1915 }
1916
1917 static void gtk_xpaned_remove (GtkContainer* container, GtkWidget* widget)
1918 {
1919         GtkXPaned* xpaned;
1920         gboolean was_visible;
1921
1922         xpaned = GTK_XPANED (container);
1923         was_visible = GTK_WIDGET_VISIBLE (widget);
1924
1925         if (xpaned->top_left_child == widget)
1926         {
1927                 gtk_widget_unparent (widget);
1928
1929                 xpaned->top_left_child = NULL;
1930
1931                 if (was_visible && GTK_WIDGET_VISIBLE (container))
1932                         gtk_widget_queue_resize (GTK_WIDGET (container));
1933         }
1934         else if (xpaned->top_right_child == widget)
1935         {
1936                 gtk_widget_unparent (widget);
1937
1938                 xpaned->top_right_child = NULL;
1939
1940                 if (was_visible && GTK_WIDGET_VISIBLE (container))
1941                         gtk_widget_queue_resize (GTK_WIDGET (container));
1942         }
1943         else if (xpaned->bottom_left_child == widget)
1944         {
1945                 gtk_widget_unparent (widget);
1946
1947                 xpaned->bottom_left_child = NULL;
1948
1949                 if (was_visible && GTK_WIDGET_VISIBLE (container))
1950                         gtk_widget_queue_resize (GTK_WIDGET (container));
1951         }
1952         else if (xpaned->bottom_right_child == widget)
1953         {
1954                 gtk_widget_unparent (widget);
1955
1956                 xpaned->bottom_right_child = NULL;
1957
1958                 if (was_visible && GTK_WIDGET_VISIBLE (container))
1959                         gtk_widget_queue_resize (GTK_WIDGET (container));
1960         }
1961         else
1962                 g_warning ("GtkXPaned has no more children attached\n");
1963
1964 }
1965
1966 static void gtk_xpaned_forall (GtkContainer* container,
1967                                                            gboolean      include_internals,
1968                                                            GtkCallback   callback,
1969                                                            gpointer      callback_data)
1970 {
1971         GtkXPaned* xpaned;
1972
1973         g_return_if_fail (callback != NULL);
1974
1975         xpaned = GTK_XPANED (container);
1976
1977         if (xpaned->top_left_child)
1978         (*callback) (xpaned->top_left_child, callback_data);
1979         if (xpaned->top_right_child)
1980                 (*callback) (xpaned->top_right_child, callback_data);
1981         if (xpaned->bottom_left_child)
1982         (*callback) (xpaned->bottom_left_child, callback_data);
1983         if (xpaned->bottom_right_child)
1984                 (*callback) (xpaned->bottom_right_child, callback_data);
1985 }
1986
1987 /**
1988  * gtk_xpaned_get_position_x:
1989  * @paned: a #GtkXPaned widget
1990  * 
1991  * Obtains the x-position of the divider.
1992  * 
1993  * Return value: x-position of the divider
1994  **/
1995 gint gtk_xpaned_get_position_x (GtkXPaned* xpaned)
1996 {
1997         g_return_val_if_fail (GTK_IS_XPANED (xpaned), 0);
1998
1999         return xpaned->top_left_child_size.width;
2000 }
2001
2002 /**
2003  * gtk_xpaned_get_position_y:
2004  * @paned: a #GtkXPaned widget
2005  * 
2006  * Obtains the y-position of the divider.
2007  * 
2008  * Return value: y-position of the divider
2009  **/
2010 gint gtk_xpaned_get_position_y (GtkXPaned* xpaned)
2011 {
2012         g_return_val_if_fail (GTK_IS_XPANED (xpaned), 0);
2013
2014         return xpaned->top_left_child_size.height;
2015 }
2016
2017 /**
2018  * gtk_xpaned_set_position_x:
2019  * @paned: a #GtkXPaned widget
2020  * @xposition: pixel x-position of divider, a negative values
2021  *                         of a component mean that the position is unset.
2022  * 
2023  * Sets the x-position of the divider between the four panes.
2024  **/
2025 void gtk_xpaned_set_position_x (GtkXPaned* xpaned, gint xposition)
2026 {
2027         GObject* object;
2028   
2029         g_return_if_fail (GTK_IS_XPANED (xpaned));
2030
2031         /* if any child is currently maximized, jump right back */
2032         if (xpaned->maximized[GTK_XPANED_TOP_LEFT]    ||
2033                 xpaned->maximized[GTK_XPANED_TOP_RIGHT]   ||
2034                 xpaned->maximized[GTK_XPANED_BOTTOM_LEFT] ||
2035                 xpaned->maximized[GTK_XPANED_BOTTOM_RIGHT])
2036                 return;
2037
2038         object = G_OBJECT (xpaned);
2039
2040         if (xposition >= 0)
2041         {
2042                 /* We don't clamp here - the assumption is that
2043                 * if the total allocation changes at the same time
2044                 * as the position, the position set is with reference
2045                 * to the new total size. If only the position changes,
2046                 * then clamping will occur in gtk_paned_compute_position()
2047                 */
2048
2049                 xpaned->top_left_child_size.width = xposition;
2050                 xpaned->position_set = TRUE;
2051         }
2052         else
2053         {
2054                 xpaned->position_set = FALSE;
2055         }
2056
2057         g_object_freeze_notify (object);
2058         g_object_notify (object, "x-position");
2059         g_object_notify (object, "position-set");
2060         g_object_thaw_notify (object);
2061
2062         gtk_widget_queue_resize (GTK_WIDGET (xpaned));
2063 }
2064
2065 /**
2066  * gtk_xpaned_set_position_y:
2067  * @paned: a #GtkXPaned widget
2068  * @yposition: pixel y-position of divider, a negative values
2069  *                         of a component mean that the position is unset.
2070  * 
2071  * Sets the y-position of the divider between the four panes.
2072  **/
2073 void gtk_xpaned_set_position_y (GtkXPaned* xpaned, gint yposition)
2074 {
2075         GObject* object;
2076   
2077         g_return_if_fail (GTK_IS_XPANED (xpaned));
2078
2079         /* if any child is currently maximized, jump right back */
2080         if (xpaned->maximized[GTK_XPANED_TOP_LEFT]    ||
2081                 xpaned->maximized[GTK_XPANED_TOP_RIGHT]   ||
2082                 xpaned->maximized[GTK_XPANED_BOTTOM_LEFT] ||
2083                 xpaned->maximized[GTK_XPANED_BOTTOM_RIGHT])
2084                 return;
2085
2086         object = G_OBJECT (xpaned);
2087
2088         if (yposition >= 0)
2089         {
2090                 /* We don't clamp here - the assumption is that
2091                 * if the total allocation changes at the same time
2092                 * as the position, the position set is with reference
2093                 * to the new total size. If only the position changes,
2094                 * then clamping will occur in gtk_paned_compute_position()
2095                 */
2096
2097                 xpaned->top_left_child_size.height = yposition;
2098                 xpaned->position_set = TRUE;
2099         }
2100         else
2101         {
2102                 xpaned->position_set = FALSE;
2103         }
2104
2105         g_object_freeze_notify (object);
2106         g_object_notify (object, "y-position");
2107         g_object_notify (object, "position-set");
2108         g_object_thaw_notify (object);
2109
2110         gtk_widget_queue_resize (GTK_WIDGET (xpaned));
2111 }
2112
2113 /* this call is private and only intended for internal use! */
2114 void gtk_xpaned_save_unmaximized_x (GtkXPaned* xpaned)
2115 {
2116         xpaned->unmaximized_position.x = gtk_xpaned_get_position_x (xpaned);
2117 }
2118
2119 /* this call is private and only intended for internal use! */
2120 void gtk_xpaned_save_unmaximized_y (GtkXPaned* xpaned)
2121 {
2122         xpaned->unmaximized_position.y = gtk_xpaned_get_position_y (xpaned);
2123 }
2124
2125 /* this call is private and only intended for internal use! */
2126 gint gtk_xpaned_fetch_unmaximized_x (GtkXPaned* xpaned)
2127 {
2128         return xpaned->unmaximized_position.x;
2129 }
2130
2131 /* this call is private and only intended for internal use! */
2132 gint gtk_xpaned_fetch_unmaximized_y (GtkXPaned* xpaned)
2133 {
2134         return xpaned->unmaximized_position.y;
2135 }
2136
2137 /**
2138  * gtk_xpaned_get_top_left_child:
2139  * @xpaned: a #GtkXPaned widget
2140  * 
2141  * Obtains the top-left child of the xpaned widget.
2142  * 
2143  * Return value: top-left child, or %NULL if it is not set.
2144  *
2145  * Since: 2.4
2146  **/
2147 GtkWidget* gtk_xpaned_get_top_left_child (GtkXPaned* xpaned)
2148 {
2149         g_return_val_if_fail (GTK_IS_XPANED (xpaned), NULL);
2150
2151         return xpaned->top_left_child;
2152 }
2153
2154 /**
2155  * gtk_xpaned_get_top_right_child:
2156  * @xpaned: a #GtkXPaned widget
2157  * 
2158  * Obtains the top-right child of the xpaned widget.
2159  * 
2160  * Return value: top-right child, or %NULL if it is not set.
2161  *
2162  * Since: 2.4
2163  **/
2164 GtkWidget* gtk_xpaned_get_top_right_child (GtkXPaned* xpaned)
2165 {
2166         g_return_val_if_fail (GTK_IS_XPANED (xpaned), NULL);
2167
2168         return xpaned->top_right_child;
2169 }
2170
2171 /**
2172  * gtk_xpaned_get_bottom_left_child:
2173  * @xpaned: a #GtkXPaned widget
2174  * 
2175  * Obtains the bottom-left child of the xpaned widget.
2176  * 
2177  * Return value: bottom-left child, or %NULL if it is not set.
2178  *
2179  * Since: 2.4
2180  **/
2181 GtkWidget* gtk_xpaned_get_bottom_left_child (GtkXPaned* xpaned)
2182 {
2183         g_return_val_if_fail (GTK_IS_XPANED (xpaned), NULL);
2184
2185         return xpaned->bottom_left_child;
2186 }
2187
2188 /**
2189  * gtk_xpaned_get_bottom_right_child:
2190  * @xpaned: a #GtkXPaned widget
2191  * 
2192  * Obtains the bottom-right child of the xpaned widget.
2193  * 
2194  * Return value: bottom-right child, or %NULL if it is not set.
2195  *
2196  * Since: 2.4
2197  **/
2198 GtkWidget* gtk_xpaned_get_bottom_right_child (GtkXPaned* xpaned)
2199 {
2200         g_return_val_if_fail (GTK_IS_XPANED (xpaned), NULL);
2201
2202         return xpaned->bottom_right_child;
2203 }
2204
2205 gboolean gtk_xpaned_maximize_top_left (GtkXPaned* xpaned, gboolean maximize)
2206 {
2207         if (maximize)
2208         {
2209                 /* see if any child is already maximized */
2210                 if (!xpaned->maximized[GTK_XPANED_TOP_LEFT] &&
2211                         !xpaned->maximized[GTK_XPANED_TOP_RIGHT] &&
2212                         !xpaned->maximized[GTK_XPANED_BOTTOM_LEFT] &&
2213                         !xpaned->maximized[GTK_XPANED_BOTTOM_RIGHT])
2214                 {
2215                         /* save current position */
2216                         gtk_xpaned_save_unmaximized_x (xpaned);
2217                         gtk_xpaned_save_unmaximized_y (xpaned);
2218
2219                         /* set new maximized position */
2220                         gtk_xpaned_set_position_x (xpaned, xpaned->max_position.x);
2221                         gtk_xpaned_set_position_y (xpaned, xpaned->max_position.y);
2222
2223                         /* mark maximized flag for top-left child */
2224                         xpaned->maximized[GTK_XPANED_TOP_LEFT] = TRUE;
2225
2226                         return TRUE;
2227                 }
2228                 /* already one child maximized, report error */
2229                 else
2230                         return FALSE;
2231         }
2232         else
2233         {
2234                 /* verify that top-left child is really currently maximized */
2235                 if (xpaned->maximized[GTK_XPANED_TOP_LEFT])
2236                 {
2237                         /* clear maximized flat for top-left child */
2238                         xpaned->maximized[GTK_XPANED_TOP_LEFT] = FALSE;
2239
2240                         /* restore unmaximized position */
2241                         gtk_xpaned_set_position_x (xpaned, gtk_xpaned_fetch_unmaximized_x (xpaned));
2242                         gtk_xpaned_set_position_y (xpaned, gtk_xpaned_fetch_unmaximized_y (xpaned));
2243
2244                         return TRUE;
2245                 }
2246                 /* top-left child is currently not maximized, report error */
2247                 else
2248                         return FALSE;
2249         }
2250 }
2251
2252 gboolean gtk_xpaned_maximize_top_right (GtkXPaned* xpaned, gboolean maximize)
2253 {
2254         if (maximize)
2255         {
2256                 /* see if any child is already maximized */
2257                 if (!xpaned->maximized[GTK_XPANED_TOP_LEFT] &&
2258                         !xpaned->maximized[GTK_XPANED_TOP_RIGHT] &&
2259                         !xpaned->maximized[GTK_XPANED_BOTTOM_LEFT] &&
2260                         !xpaned->maximized[GTK_XPANED_BOTTOM_RIGHT])
2261                 {
2262                         /* save current position */
2263                         gtk_xpaned_save_unmaximized_x (xpaned);
2264                         gtk_xpaned_save_unmaximized_y (xpaned);
2265
2266                         /* set new maximized position */
2267                         gtk_xpaned_set_position_x (xpaned, xpaned->min_position.x);
2268                         gtk_xpaned_set_position_y (xpaned, xpaned->max_position.y);
2269                 
2270                         /* mark maximized flag for top-right child */
2271                         xpaned->maximized[GTK_XPANED_TOP_RIGHT] = TRUE;
2272
2273                         return TRUE;
2274                 }
2275                 /* already one child maximized, report error */
2276                 else
2277                         return FALSE;
2278         }
2279         else
2280         {
2281                 /* verify that top-right child is really currently maximized */
2282                 if (xpaned->maximized[GTK_XPANED_TOP_RIGHT])
2283                 {
2284                         /* clear maximized flat for top-right child */
2285                         xpaned->maximized[GTK_XPANED_TOP_RIGHT] = FALSE;
2286
2287                         /* restore unmaximized position */
2288                         gtk_xpaned_set_position_x (xpaned, gtk_xpaned_fetch_unmaximized_x (xpaned));
2289                         gtk_xpaned_set_position_y (xpaned, gtk_xpaned_fetch_unmaximized_y (xpaned));
2290
2291                         return TRUE;
2292                 }
2293                 /* top-right child is currently not maximized, report error */
2294                 else
2295                         return FALSE;
2296         }
2297 }
2298
2299 gboolean gtk_xpaned_maximize_bottom_left (GtkXPaned* xpaned, gboolean maximize)
2300 {
2301         if (maximize)
2302         {
2303                 /* see if any child is already maximized */
2304                 if (!xpaned->maximized[GTK_XPANED_TOP_LEFT] &&
2305                         !xpaned->maximized[GTK_XPANED_TOP_RIGHT] &&
2306                         !xpaned->maximized[GTK_XPANED_BOTTOM_LEFT] &&
2307                         !xpaned->maximized[GTK_XPANED_BOTTOM_RIGHT])
2308                 {
2309                         /* save current position */
2310                         gtk_xpaned_save_unmaximized_x (xpaned);
2311                         gtk_xpaned_save_unmaximized_y (xpaned);
2312
2313                         /* set new maximized position */
2314                         gtk_xpaned_set_position_x (xpaned, xpaned->max_position.x);
2315                         gtk_xpaned_set_position_y (xpaned, xpaned->min_position.y);
2316
2317                         /* mark maximized flag for bottom-left child */
2318                         xpaned->maximized[GTK_XPANED_BOTTOM_LEFT] = TRUE;
2319
2320                         return TRUE;
2321                 }
2322                 /* already one child maximized, report error */
2323                 else
2324                         return FALSE;
2325         }
2326         else
2327         {
2328                 /* verify that bottom-left child is really currently maximized */
2329                 if (xpaned->maximized[GTK_XPANED_BOTTOM_LEFT])
2330                 {
2331                         /* clear maximized flat for bottom-left child */
2332                         xpaned->maximized[GTK_XPANED_BOTTOM_LEFT] = FALSE;
2333
2334                         /* restore unmaximized position */
2335                         gtk_xpaned_set_position_x (xpaned, gtk_xpaned_fetch_unmaximized_x (xpaned));
2336                         gtk_xpaned_set_position_y (xpaned, gtk_xpaned_fetch_unmaximized_y (xpaned));
2337
2338                         return TRUE;
2339                 }
2340                 /* bottom-left child is currently not maximized, report error */
2341                 else
2342                         return FALSE;
2343         }
2344 }
2345
2346 gboolean gtk_xpaned_maximize_bottom_right (GtkXPaned* xpaned, gboolean maximize)
2347 {
2348         if (maximize)
2349         {
2350                 /* see if any child is already maximized */
2351                 if (!xpaned->maximized[GTK_XPANED_TOP_LEFT] &&
2352                         !xpaned->maximized[GTK_XPANED_TOP_RIGHT] &&
2353                         !xpaned->maximized[GTK_XPANED_BOTTOM_LEFT] &&
2354                         !xpaned->maximized[GTK_XPANED_BOTTOM_RIGHT])
2355                 {
2356                         /* save current position */
2357                         gtk_xpaned_save_unmaximized_x (xpaned);
2358                         gtk_xpaned_save_unmaximized_y (xpaned);
2359
2360                         /* set new maximized position */
2361                         gtk_xpaned_set_position_x (xpaned, xpaned->min_position.x);
2362                         gtk_xpaned_set_position_y (xpaned, xpaned->min_position.y);
2363
2364                         /* mark maximized flag for bottom-right child */
2365                         xpaned->maximized[GTK_XPANED_BOTTOM_RIGHT] = TRUE;
2366
2367                         return TRUE;
2368                 }
2369                 /* already one child maximized, report error */
2370                 else
2371                         return FALSE;
2372         }
2373         else
2374         {
2375                 /* verify that bottom-right child is really currently maximized */
2376                 if (xpaned->maximized[GTK_XPANED_BOTTOM_RIGHT])
2377                 {
2378                         /* clear maximized flat for bottom-right child */
2379                         xpaned->maximized[GTK_XPANED_BOTTOM_RIGHT] = FALSE;
2380
2381                         /* restore unmaximized position */
2382                         gtk_xpaned_set_position_x (xpaned, gtk_xpaned_fetch_unmaximized_x (xpaned));
2383                         gtk_xpaned_set_position_y (xpaned, gtk_xpaned_fetch_unmaximized_y (xpaned));
2384
2385                         return TRUE;
2386                 }
2387                 /* bottom-right child is currently not maximized, report error */
2388                 else
2389                         return FALSE;
2390         }
2391 }
2392
2393 void
2394 gtk_xpaned_compute_position (GtkXPaned* xpaned,
2395                              const GtkAllocation* allocation,
2396                              GtkRequisition* top_left_child_req,
2397                              GtkRequisition* top_right_child_req,
2398                              GtkRequisition* bottom_left_child_req,
2399                              GtkRequisition* bottom_right_child_req)
2400 {
2401   GdkPoint old_position;
2402   GdkPoint old_min_position;
2403         GdkPoint old_max_position;
2404         gint handle_size;
2405         gint border_width = GTK_CONTAINER (xpaned)->border_width;
2406         float fX;
2407         float fY;
2408
2409         g_return_if_fail (GTK_IS_XPANED (xpaned));
2410
2411         old_position.x = xpaned->top_left_child_size.width;
2412         old_position.y = xpaned->top_left_child_size.height;
2413         old_min_position.x = xpaned->min_position.x;
2414         old_min_position.y = xpaned->min_position.y;
2415         old_max_position.x = xpaned->max_position.x;
2416         old_max_position.y = xpaned->max_position.y;
2417
2418         fX = 100.0f * (float) old_position.x / (float) allocation->width;
2419         fY = 100.0f * (float) old_position.y / (float) allocation->height;
2420
2421         xpaned->min_position.x = xpaned->top_left_child_shrink ? 0 : top_left_child_req->width;
2422         xpaned->min_position.y = xpaned->top_left_child_shrink ? 0 : top_left_child_req->height;
2423
2424         gtk_widget_style_get (GTK_WIDGET (xpaned), "handle-size", &handle_size, NULL);
2425
2426         xpaned->max_position.x = allocation->width - 2 * border_width - handle_size;
2427         xpaned->max_position.y = allocation->height - 2 * border_width - handle_size;
2428         if (!xpaned->top_left_child_shrink)
2429                 xpaned->max_position.x = MAX (1, xpaned->max_position.x - top_left_child_req->width);
2430         xpaned->max_position.x = MAX (xpaned->min_position.x, xpaned->max_position.x);
2431
2432         if (!xpaned->position_set)
2433         {
2434                 if (xpaned->top_left_child_resize && !xpaned->top_right_child_resize)
2435                 {
2436                         xpaned->top_left_child_size.width = MAX (0, allocation->width - top_right_child_req->width);
2437                         xpaned->top_left_child_size.height = MAX (0, allocation->height - top_right_child_req->height);
2438                 }
2439                 else if (!xpaned->top_left_child_resize && xpaned->top_right_child_resize)
2440                 {
2441                         xpaned->top_left_child_size.width = top_left_child_req->width;
2442                         xpaned->top_left_child_size.height = top_left_child_req->height;
2443                 }
2444                 else if (top_left_child_req->width + top_right_child_req->width != 0)
2445                 {
2446                         xpaned->top_left_child_size.width = allocation->width * ((gdouble)top_left_child_req->width / (top_left_child_req->width + top_right_child_req->width)) + 0.5;
2447                 }
2448                 else if (top_left_child_req->height + top_right_child_req->height != 0)
2449                 {
2450                         xpaned->top_left_child_size.height = allocation->height * ((gdouble)top_left_child_req->height / (top_left_child_req->height + top_right_child_req->height)) + 0.5;
2451                 }
2452                 else
2453                 {
2454                         xpaned->top_left_child_size.width = allocation->width * 0.5 + 0.5;
2455                         xpaned->top_left_child_size.height = allocation->height * 0.5 + 0.5;
2456                 }
2457         }
2458         else
2459         {
2460                 /* If the position was set before the initial allocation.
2461                 ** (paned->last_allocation <= 0) just clamp it and leave it. */
2462                 if (xpaned->last_allocation.width > 0)
2463                 {
2464                         if (xpaned->top_left_child_resize && !xpaned->top_right_child_resize)
2465                         {
2466                                 xpaned->top_left_child_size.width += allocation->width
2467                                                                                                          - xpaned->last_allocation.width;
2468
2469                                 xpaned->top_left_child_size.height += allocation->height
2470                                                                                                           - xpaned->last_allocation.height;
2471                         }
2472                         else if (!(!xpaned->top_left_child_resize && xpaned->top_right_child_resize))
2473                         {
2474                                 xpaned->top_left_child_size.width = allocation->width
2475                                                                                                         * ((gdouble) xpaned->top_left_child_size.width / (xpaned->last_allocation.width))
2476                                                                                                         + 0.5;
2477
2478                                 xpaned->top_left_child_size.height = allocation->height
2479                                                                                                          * ((gdouble) xpaned->top_left_child_size.height / (xpaned->last_allocation.height))
2480                                                                                                          + 0.5;
2481                         }
2482                 }
2483                 if (xpaned->last_allocation.height > 0)
2484                 {
2485                         if (xpaned->top_left_child_resize && !xpaned->top_right_child_resize)
2486                         {
2487                                 xpaned->top_left_child_size.width += allocation->width - xpaned->last_allocation.width;
2488                                 xpaned->top_left_child_size.height += allocation->height - xpaned->last_allocation.height;
2489                         }
2490                         else if (!(!xpaned->top_left_child_resize && xpaned->top_right_child_resize))
2491                         {
2492                                 xpaned->top_left_child_size.width = allocation->width * ((gdouble) xpaned->top_left_child_size.width / (xpaned->last_allocation.width)) + 0.5;
2493                                 xpaned->top_left_child_size.height = allocation->height * ((gdouble) xpaned->top_left_child_size.height / (xpaned->last_allocation.height)) + 0.5;
2494                         }
2495                 }
2496
2497     }
2498
2499         xpaned->top_left_child_size.width = CLAMP (xpaned->top_left_child_size.width,
2500                                                                                            xpaned->min_position.x,
2501                                                                                            xpaned->max_position.x);
2502         xpaned->top_left_child_size.height = CLAMP (xpaned->top_left_child_size.height,
2503                                                                                                 xpaned->min_position.y,
2504                                                                                                 xpaned->max_position.y);
2505
2506         xpaned->top_right_child_size.width = CLAMP (xpaned->top_right_child_size.width,
2507                                                                                                 xpaned->min_position.x,
2508                                                                                                 xpaned->max_position.x);
2509         xpaned->top_right_child_size.height = CLAMP (xpaned->top_right_child_size.height,
2510                                                                                                  xpaned->min_position.y,
2511                                                                                                  xpaned->max_position.y);
2512
2513         xpaned->bottom_left_child_size.width = CLAMP (xpaned->bottom_left_child_size.width,
2514                                                                                                   xpaned->min_position.x,
2515                                                                                                   xpaned->max_position.x);
2516         xpaned->bottom_left_child_size.height = CLAMP (xpaned->bottom_left_child_size.height,
2517                                                                                                    xpaned->min_position.y,
2518                                                                                                    xpaned->max_position.y);
2519
2520         xpaned->bottom_right_child_size.width = CLAMP (xpaned->bottom_right_child_size.width,
2521                                                                                                    xpaned->min_position.x,
2522                                                                                                    xpaned->max_position.x);
2523         xpaned->bottom_right_child_size.height = CLAMP (xpaned->bottom_right_child_size.height,
2524                                                                                                         xpaned->min_position.y,
2525                                                                                                         xpaned->max_position.y);
2526
2527         gtk_widget_set_child_visible (xpaned->top_left_child, TRUE);
2528         gtk_widget_set_child_visible (xpaned->top_right_child, TRUE);
2529         gtk_widget_set_child_visible (xpaned->bottom_left_child, TRUE);
2530         gtk_widget_set_child_visible (xpaned->bottom_right_child, TRUE);
2531
2532         g_object_freeze_notify (G_OBJECT (xpaned));
2533
2534         if (xpaned->top_left_child_size.width != old_position.x)
2535                 g_object_notify (G_OBJECT (xpaned), "x-position");
2536         if (xpaned->top_left_child_size.height != old_position.y)
2537                 g_object_notify (G_OBJECT (xpaned), "y-position");
2538
2539         if (xpaned->top_right_child_size.width != old_position.x)
2540                 g_object_notify (G_OBJECT (xpaned), "x-position");
2541         if (xpaned->top_right_child_size.height != old_position.y)
2542                 g_object_notify (G_OBJECT (xpaned), "y-position");
2543
2544         if (xpaned->bottom_left_child_size.width != old_position.x)
2545                 g_object_notify (G_OBJECT (xpaned), "x-position");
2546         if (xpaned->bottom_left_child_size.height != old_position.y)
2547                 g_object_notify (G_OBJECT (xpaned), "y-position");
2548
2549         if (xpaned->bottom_right_child_size.width != old_position.x)
2550                 g_object_notify (G_OBJECT (xpaned), "x-position");
2551         if (xpaned->bottom_right_child_size.height != old_position.y)
2552                 g_object_notify (G_OBJECT (xpaned), "y-position");
2553
2554         if (xpaned->min_position.x != old_min_position.x)
2555                 g_object_notify (G_OBJECT (xpaned), "min-x-position");
2556         if (xpaned->min_position.y != old_min_position.y)
2557                 g_object_notify (G_OBJECT (xpaned), "min-y-position");
2558
2559         if (xpaned->max_position.x != old_max_position.x)
2560         g_object_notify (G_OBJECT (xpaned), "max-y-position");
2561         if (xpaned->max_position.y != old_max_position.y)
2562         g_object_notify (G_OBJECT (xpaned), "max-y-position");
2563
2564         g_object_thaw_notify (G_OBJECT (xpaned));
2565
2566         xpaned->last_allocation.width = allocation->width;
2567         xpaned->last_allocation.height = allocation->height;
2568
2569         fX = 100.0f * (float) old_position.x / (float) allocation->width;
2570         fY = 100.0f * (float) old_position.y / (float) allocation->height;
2571 }
2572
2573 static void gtk_xpaned_set_saved_focus (GtkXPaned* xpaned, GtkWidget* widget)
2574 {
2575         if (xpaned->priv->saved_focus)
2576                 g_object_remove_weak_pointer (G_OBJECT (xpaned->priv->saved_focus),
2577                                                                           (gpointer *)&(xpaned->priv->saved_focus));
2578
2579         xpaned->priv->saved_focus = widget;
2580
2581         if (xpaned->priv->saved_focus)
2582                 g_object_add_weak_pointer (G_OBJECT (xpaned->priv->saved_focus),
2583                                                                    (gpointer *)&(xpaned->priv->saved_focus));
2584 }
2585
2586 static void gtk_xpaned_set_first_xpaned (GtkXPaned* xpaned,
2587                                                                                  GtkXPaned* first_xpaned)
2588 {
2589         if (xpaned->priv->first_xpaned)
2590                 g_object_remove_weak_pointer (G_OBJECT (xpaned->priv->first_xpaned),
2591                                                                           (gpointer *)&(xpaned->priv->first_xpaned));
2592
2593         xpaned->priv->first_xpaned = first_xpaned;
2594
2595         if (xpaned->priv->first_xpaned)
2596                 g_object_add_weak_pointer (G_OBJECT (xpaned->priv->first_xpaned),
2597                                                                    (gpointer *)&(xpaned->priv->first_xpaned));
2598 }
2599
2600 static void gtk_xpaned_set_last_top_left_child_focus (GtkXPaned* xpaned,
2601                                                                                                           GtkWidget* widget)
2602 {
2603         if (xpaned->last_top_left_child_focus)
2604                 g_object_remove_weak_pointer (G_OBJECT (xpaned->last_top_left_child_focus),
2605                                                                           (gpointer *)&(xpaned->last_top_left_child_focus));
2606
2607         xpaned->last_top_left_child_focus = widget;
2608
2609         if (xpaned->last_top_left_child_focus)
2610                 g_object_add_weak_pointer (G_OBJECT (xpaned->last_top_left_child_focus),
2611                                                                    (gpointer *)&(xpaned->last_top_left_child_focus));
2612 }
2613
2614 static void gtk_xpaned_set_last_top_right_child_focus (GtkXPaned* xpaned,
2615                                                                                                            GtkWidget *widget)
2616 {
2617         if (xpaned->last_top_right_child_focus)
2618                 g_object_remove_weak_pointer (G_OBJECT (xpaned->last_top_right_child_focus),
2619                                                                           (gpointer *)&(xpaned->last_top_right_child_focus));
2620
2621         xpaned->last_top_right_child_focus = widget;
2622
2623         if (xpaned->last_top_right_child_focus)
2624                 g_object_add_weak_pointer (G_OBJECT (xpaned->last_top_right_child_focus),
2625                                                                    (gpointer *)&(xpaned->last_top_right_child_focus));
2626 }
2627
2628 static void gtk_xpaned_set_last_bottom_left_child_focus (GtkXPaned* xpaned,
2629                                                                                                                  GtkWidget *widget)
2630 {
2631         if (xpaned->last_bottom_left_child_focus)
2632                 g_object_remove_weak_pointer (G_OBJECT (xpaned->last_bottom_left_child_focus),
2633                                                                           (gpointer *)&(xpaned->last_bottom_left_child_focus));
2634
2635         xpaned->last_bottom_left_child_focus = widget;
2636
2637         if (xpaned->last_bottom_left_child_focus)
2638                 g_object_add_weak_pointer (G_OBJECT (xpaned->last_bottom_left_child_focus),
2639                                                                    (gpointer *)&(xpaned->last_bottom_left_child_focus));
2640 }
2641
2642 static void gtk_xpaned_set_last_bottom_right_child_focus (GtkXPaned* xpaned,
2643                                                                                                                  GtkWidget *widget)
2644 {
2645         if (xpaned->last_bottom_right_child_focus)
2646                 g_object_remove_weak_pointer (G_OBJECT (xpaned->last_bottom_right_child_focus),
2647                                                                           (gpointer *)&(xpaned->last_bottom_right_child_focus));
2648
2649         xpaned->last_bottom_right_child_focus = widget;
2650
2651         if (xpaned->last_bottom_right_child_focus)
2652                 g_object_add_weak_pointer (G_OBJECT (xpaned->last_bottom_right_child_focus),
2653                                                                    (gpointer *)&(xpaned->last_bottom_right_child_focus));
2654 }
2655
2656 static GtkWidget* xpaned_get_focus_widget (GtkXPaned* xpaned)
2657 {
2658         GtkWidget* toplevel;
2659
2660         toplevel = gtk_widget_get_toplevel (GTK_WIDGET (xpaned));
2661         if (GTK_WIDGET_TOPLEVEL (toplevel))
2662                 return GTK_WINDOW (toplevel)->focus_widget;
2663
2664         return NULL;
2665 }
2666
2667 static void gtk_xpaned_set_focus_child (GtkContainer* container,
2668                                                                                 GtkWidget* focus_child)
2669 {
2670         GtkXPaned* xpaned;
2671
2672         g_return_if_fail (GTK_IS_XPANED (container));
2673
2674         xpaned = GTK_XPANED (container);
2675
2676         if (focus_child == NULL)
2677         {
2678                 GtkWidget* last_focus;
2679                 GtkWidget* w;
2680
2681                 last_focus = xpaned_get_focus_widget (xpaned);
2682
2683                 if (last_focus)
2684                 {
2685                         /* If there is one or more paned widgets between us and the
2686                         * focus widget, we want the topmost of those as last_focus
2687                         */
2688                         for (w = last_focus; w != GTK_WIDGET (xpaned); w = w->parent)
2689                                 if (GTK_IS_XPANED (w))
2690                                         last_focus = w;
2691
2692                         if (container->focus_child == xpaned->top_left_child)
2693                                 gtk_xpaned_set_last_top_left_child_focus (xpaned, last_focus);
2694                         else if (container->focus_child == xpaned->top_right_child)
2695                                 gtk_xpaned_set_last_top_right_child_focus (xpaned, last_focus);
2696                         else if (container->focus_child == xpaned->bottom_left_child)
2697                                 gtk_xpaned_set_last_bottom_left_child_focus (xpaned, last_focus);
2698                         else if (container->focus_child == xpaned->bottom_right_child)
2699                                 gtk_xpaned_set_last_bottom_right_child_focus (xpaned, last_focus);
2700                 }
2701         }
2702
2703         if (parent_class->set_focus_child)
2704                 (* parent_class->set_focus_child) (container, focus_child);
2705 }
2706
2707 static void gtk_xpaned_get_cycle_chain (GtkXPaned* xpaned,
2708                                                                                 GtkDirectionType direction,
2709                                                                                 GList** widgets)
2710 {
2711         GtkContainer* container = GTK_CONTAINER (xpaned);
2712         GtkWidget* ancestor = NULL;
2713         GList* temp_list = NULL;
2714         GList* list;
2715
2716         if (xpaned->in_recursion)
2717                 return;
2718
2719         g_assert (widgets != NULL);
2720
2721         if (xpaned->last_top_left_child_focus &&
2722                 !gtk_widget_is_ancestor (xpaned->last_top_left_child_focus,
2723                                                                  GTK_WIDGET (xpaned)))
2724         {
2725                 gtk_xpaned_set_last_top_left_child_focus (xpaned, NULL);
2726         }
2727
2728         if (xpaned->last_top_right_child_focus &&
2729                 !gtk_widget_is_ancestor (xpaned->last_top_right_child_focus,
2730                                                                  GTK_WIDGET (xpaned)))
2731         {
2732                 gtk_xpaned_set_last_top_right_child_focus (xpaned, NULL);
2733         }
2734
2735         if (xpaned->last_bottom_left_child_focus &&
2736                 !gtk_widget_is_ancestor (xpaned->last_bottom_left_child_focus,
2737                                                                  GTK_WIDGET (xpaned)))
2738         {
2739                 gtk_xpaned_set_last_bottom_left_child_focus (xpaned, NULL);
2740         }
2741
2742         if (xpaned->last_bottom_right_child_focus &&
2743                 !gtk_widget_is_ancestor (xpaned->last_bottom_right_child_focus,
2744                                                                  GTK_WIDGET (xpaned)))
2745         {
2746                 gtk_xpaned_set_last_bottom_right_child_focus (xpaned, NULL);
2747         }
2748
2749         if (GTK_WIDGET (xpaned)->parent)
2750                 ancestor = gtk_widget_get_ancestor (GTK_WIDGET (xpaned)->parent,
2751                                                                                         GTK_TYPE_XPANED);
2752
2753         /* The idea here is that temp_list is a list of widgets we want to cycle
2754         * to. The list is prioritized so that the first element is our first
2755         * choice, the next our second, and so on.
2756         *
2757         * We can't just use g_list_reverse(), because we want to try
2758         * paned->last_child?_focus before paned->child?, both when we
2759         * are going forward and backward.
2760         */
2761         if (direction == GTK_DIR_TAB_FORWARD)
2762         {
2763                 if (container->focus_child == xpaned->top_left_child)
2764                 {
2765                         temp_list = g_list_append (temp_list, xpaned->last_top_right_child_focus);
2766                         temp_list = g_list_append (temp_list, xpaned->top_right_child);
2767                         temp_list = g_list_append (temp_list, ancestor);
2768                 }
2769                 else if (container->focus_child == xpaned->top_right_child)
2770                 {
2771                         temp_list = g_list_append (temp_list, ancestor);
2772                         temp_list = g_list_append (temp_list, xpaned->last_bottom_left_child_focus);
2773                         temp_list = g_list_append (temp_list, xpaned->bottom_left_child);
2774                 }
2775                 else if (container->focus_child == xpaned->bottom_left_child)
2776                 {
2777                         temp_list = g_list_append (temp_list, ancestor);
2778                         temp_list = g_list_append (temp_list, xpaned->last_bottom_right_child_focus);
2779                         temp_list = g_list_append (temp_list, xpaned->bottom_right_child);
2780                 }
2781                 else if (container->focus_child == xpaned->bottom_right_child)
2782                 {
2783                         temp_list = g_list_append (temp_list, ancestor);
2784                         temp_list = g_list_append (temp_list, xpaned->last_top_left_child_focus);
2785                         temp_list = g_list_append (temp_list, xpaned->top_left_child);
2786                 }
2787                 else
2788                 {
2789                         temp_list = g_list_append (temp_list, xpaned->last_top_left_child_focus);
2790                         temp_list = g_list_append (temp_list, xpaned->top_left_child);
2791                         temp_list = g_list_append (temp_list, xpaned->last_top_right_child_focus);
2792                         temp_list = g_list_append (temp_list, xpaned->top_right_child);
2793                         temp_list = g_list_append (temp_list, xpaned->last_bottom_left_child_focus);
2794                         temp_list = g_list_append (temp_list, xpaned->bottom_left_child);
2795                         temp_list = g_list_append (temp_list, xpaned->last_bottom_right_child_focus);
2796                         temp_list = g_list_append (temp_list, xpaned->bottom_right_child);
2797                         temp_list = g_list_append (temp_list, ancestor);
2798                 }
2799         }
2800         else
2801         {
2802                 if (container->focus_child == xpaned->top_left_child)
2803                 {
2804                         temp_list = g_list_append (temp_list, ancestor);
2805                         temp_list = g_list_append (temp_list, xpaned->last_top_right_child_focus);
2806                         temp_list = g_list_append (temp_list, xpaned->top_right_child);
2807                 }
2808                 else if (container->focus_child == xpaned->top_right_child)
2809                 {
2810                         temp_list = g_list_append (temp_list, xpaned->last_bottom_left_child_focus);
2811                         temp_list = g_list_append (temp_list, xpaned->bottom_left_child);
2812                         temp_list = g_list_append (temp_list, ancestor);
2813                 }
2814                 else if (container->focus_child == xpaned->bottom_right_child)
2815                 {
2816                         temp_list = g_list_append (temp_list, xpaned->last_bottom_left_child_focus);
2817                         temp_list = g_list_append (temp_list, xpaned->bottom_left_child);
2818                         temp_list = g_list_append (temp_list, ancestor);
2819                 }
2820                 else if (container->focus_child == xpaned->top_right_child)
2821                 {
2822                         temp_list = g_list_append (temp_list, xpaned->last_bottom_left_child_focus);
2823                         temp_list = g_list_append (temp_list, xpaned->bottom_left_child);
2824                         temp_list = g_list_append (temp_list, ancestor);
2825                 }
2826                 else
2827                 {
2828                         temp_list = g_list_append (temp_list, xpaned->last_bottom_right_child_focus);
2829                         temp_list = g_list_append (temp_list, xpaned->bottom_right_child);
2830                         temp_list = g_list_append (temp_list, xpaned->last_bottom_left_child_focus);
2831                         temp_list = g_list_append (temp_list, xpaned->bottom_left_child);
2832                         temp_list = g_list_append (temp_list, xpaned->last_top_right_child_focus);
2833                         temp_list = g_list_append (temp_list, xpaned->top_right_child);
2834                         temp_list = g_list_append (temp_list, xpaned->last_top_left_child_focus);
2835                         temp_list = g_list_append (temp_list, xpaned->top_left_child);
2836                         temp_list = g_list_append (temp_list, ancestor);
2837                 }
2838         }
2839
2840         /* Walk the list and expand all the paned widgets. */
2841         for (list = temp_list; list != NULL; list = list->next)
2842         {
2843                 GtkWidget *widget = list->data;
2844
2845                 if (widget)
2846                 {
2847                         if (GTK_IS_XPANED (widget))
2848                         {
2849                                 xpaned->in_recursion = TRUE;
2850                                 gtk_xpaned_get_cycle_chain (GTK_XPANED (widget),
2851                                                                                         direction,
2852                                                                                         widgets);
2853                                 xpaned->in_recursion = FALSE;
2854                         }
2855                         else
2856                         {
2857                                 *widgets = g_list_append (*widgets, widget);
2858                         }
2859                 }
2860         }
2861
2862         g_list_free (temp_list);
2863 }
2864
2865 static gboolean gtk_xpaned_cycle_child_focus (GtkXPaned* xpaned,
2866                                                                                           gboolean reversed)
2867 {
2868         GList* cycle_chain = NULL;
2869         GList* list;
2870
2871         GtkDirectionType direction = reversed ? GTK_DIR_TAB_BACKWARD : GTK_DIR_TAB_FORWARD;
2872
2873         /* ignore f6 if the handle is focused */
2874         if (gtk_widget_is_focus (GTK_WIDGET (xpaned)))
2875                 return TRUE;
2876
2877         /* we can't just let the event propagate up the hierarchy,
2878         * because the paned will want to cycle focus _unless_ an
2879         * ancestor paned handles the event
2880         */
2881         gtk_xpaned_get_cycle_chain (xpaned, direction, &cycle_chain);
2882
2883         for (list = cycle_chain; list != NULL; list = list->next)
2884                 if (gtk_widget_child_focus (GTK_WIDGET (list->data), direction))
2885                         break;
2886
2887         g_list_free (cycle_chain);
2888
2889         return TRUE;
2890 }
2891
2892 static void get_child_xpanes (GtkWidget* widget, GList** xpanes)
2893 {
2894         if (GTK_IS_XPANED (widget))
2895         {
2896                 GtkXPaned* xpaned = GTK_XPANED (widget);
2897
2898                 get_child_xpanes (xpaned->top_left_child, xpanes);
2899                 *xpanes = g_list_prepend (*xpanes, widget);
2900                 get_child_xpanes (xpaned->top_right_child, xpanes);
2901                 *xpanes = g_list_prepend (*xpanes, widget);
2902                 get_child_xpanes (xpaned->bottom_left_child, xpanes);
2903                 *xpanes = g_list_prepend (*xpanes, widget);
2904                 get_child_xpanes (xpaned->bottom_right_child, xpanes);
2905         }
2906         else if (GTK_IS_CONTAINER (widget))
2907         {
2908                 gtk_container_foreach (GTK_CONTAINER (widget),
2909                                                            (GtkCallback)get_child_xpanes,
2910                                                            xpanes);
2911         }
2912 }
2913
2914 static GList* get_all_xpanes (GtkXPaned* xpaned)
2915 {
2916         GtkXPaned* topmost = NULL;
2917         GList* result = NULL;
2918         GtkWidget* w;
2919   
2920         for (w = GTK_WIDGET (xpaned); w != NULL; w = w->parent)
2921         {
2922                 if (GTK_IS_XPANED (w))
2923                         topmost = GTK_XPANED (w);
2924         }
2925
2926         g_assert (topmost);
2927
2928         get_child_xpanes (GTK_WIDGET (topmost), &result);
2929
2930         return g_list_reverse (result);
2931 }
2932
2933 static void gtk_xpaned_find_neighbours (GtkXPaned* xpaned,
2934                                                                                 GtkXPaned** next,
2935                                                                                 GtkXPaned** prev)
2936 {
2937         GList* all_xpanes;
2938         GList* this_link;
2939
2940         all_xpanes = get_all_xpanes (xpaned);
2941         g_assert (all_xpanes);
2942
2943         this_link = g_list_find (all_xpanes, xpaned);
2944
2945         g_assert (this_link);
2946
2947         if (this_link->next)
2948                 *next = this_link->next->data;
2949         else
2950                 *next = all_xpanes->data;
2951
2952         if (this_link->prev)
2953                 *prev = this_link->prev->data;
2954         else
2955                 *prev = g_list_last (all_xpanes)->data;
2956
2957         g_list_free (all_xpanes);
2958 }
2959
2960 static gboolean gtk_xpaned_move_handle (GtkXPaned* xpaned, GtkScrollType scroll)
2961 {
2962         if (gtk_widget_is_focus (GTK_WIDGET (xpaned)))
2963         {
2964                 GdkPoint old_position;
2965                 GdkPoint new_position;
2966                 gint increment;
2967
2968                 enum
2969                 {
2970                         SINGLE_STEP_SIZE = 1,
2971                         PAGE_STEP_SIZE   = 75
2972                 };
2973
2974                 new_position.x = old_position.x = gtk_xpaned_get_position_x (xpaned);
2975                 new_position.y = old_position.y = gtk_xpaned_get_position_y (xpaned);
2976                 increment = 0;
2977
2978                 switch (scroll)
2979                 {
2980                         case GTK_SCROLL_STEP_LEFT:
2981                         case GTK_SCROLL_STEP_UP:
2982                         case GTK_SCROLL_STEP_BACKWARD:
2983                                 increment = - SINGLE_STEP_SIZE;
2984                         break;
2985
2986                         case GTK_SCROLL_STEP_RIGHT:
2987                         case GTK_SCROLL_STEP_DOWN:
2988                         case GTK_SCROLL_STEP_FORWARD:
2989                                 increment = SINGLE_STEP_SIZE;
2990                         break;
2991
2992                         case GTK_SCROLL_PAGE_LEFT:
2993                         case GTK_SCROLL_PAGE_UP:
2994                         case GTK_SCROLL_PAGE_BACKWARD:
2995                                 increment = - PAGE_STEP_SIZE;
2996                         break;
2997
2998                         case GTK_SCROLL_PAGE_RIGHT:
2999                         case GTK_SCROLL_PAGE_DOWN:
3000                         case GTK_SCROLL_PAGE_FORWARD:
3001                                 increment = PAGE_STEP_SIZE;
3002                         break;
3003
3004                         case GTK_SCROLL_START:
3005                                 new_position.x = xpaned->min_position.x;
3006                                 new_position.y = xpaned->min_position.y;
3007                         break;
3008
3009                         case GTK_SCROLL_END:
3010                                 new_position.x = xpaned->max_position.x;
3011                                 new_position.y = xpaned->max_position.y;
3012                         break;
3013
3014                         default:
3015                         break;
3016                 }
3017
3018                 if (increment)
3019                 {
3020                         if (is_rtl (xpaned))
3021                                 increment = -increment;
3022
3023                         new_position.x = old_position.x + increment;
3024                         new_position.y = old_position.y + increment;
3025                 }
3026
3027                 new_position.x = CLAMP (new_position.x,
3028                                                                 xpaned->min_position.x,
3029                                                                 xpaned->max_position.x);
3030
3031                 new_position.y = CLAMP (new_position.y,
3032                                                                 xpaned->min_position.y,
3033                                                                 xpaned->max_position.y);
3034
3035                 if (old_position.x != new_position.x)
3036                         gtk_xpaned_set_position_x (xpaned, new_position.x);
3037
3038                 if (old_position.y != new_position.y)
3039                         gtk_xpaned_set_position_y (xpaned, new_position.y);
3040
3041                 return TRUE;
3042         }
3043
3044         return FALSE;
3045 }
3046
3047 static void gtk_xpaned_restore_focus (GtkXPaned* xpaned)
3048 {
3049         if (gtk_widget_is_focus (GTK_WIDGET (xpaned)))
3050         {
3051                 if (xpaned->priv->saved_focus &&
3052                         GTK_WIDGET_SENSITIVE (xpaned->priv->saved_focus))
3053                 {
3054                         gtk_widget_grab_focus (xpaned->priv->saved_focus);
3055                 }
3056                 else
3057                 {
3058                         /* the saved focus is somehow not available for focusing,
3059                         * try
3060                         *   1) tabbing into the paned widget
3061                         * if that didn't work,
3062                         *   2) unset focus for the window if there is one
3063                         */
3064
3065                         if (!gtk_widget_child_focus (GTK_WIDGET (xpaned), GTK_DIR_TAB_FORWARD))
3066                         {
3067                                 GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (xpaned));
3068               
3069                                 if (GTK_IS_WINDOW (toplevel))
3070                                         gtk_window_set_focus (GTK_WINDOW (toplevel), NULL);
3071                         }
3072                 }
3073                 
3074                 gtk_xpaned_set_saved_focus (xpaned, NULL);
3075                 gtk_xpaned_set_first_xpaned (xpaned, NULL);
3076     }
3077 }
3078
3079 static gboolean gtk_xpaned_accept_position (GtkXPaned* xpaned)
3080 {
3081         if (gtk_widget_is_focus (GTK_WIDGET (xpaned)))
3082         {
3083                 xpaned->original_position.x = -1;
3084                 xpaned->original_position.y = -1;
3085                 gtk_xpaned_restore_focus (xpaned);
3086
3087                 return TRUE;
3088         }
3089
3090         return FALSE;
3091 }
3092
3093 static gboolean gtk_xpaned_cancel_position (GtkXPaned* xpaned)
3094 {
3095         if (gtk_widget_is_focus (GTK_WIDGET (xpaned)))
3096         {
3097                 if (xpaned->original_position.x != -1)
3098                 {
3099                         gtk_xpaned_set_position_x (xpaned, xpaned->original_position.x);
3100                         xpaned->original_position.x = -1;
3101                 }
3102
3103                 if (xpaned->original_position.y != -1)
3104                 {
3105                         gtk_xpaned_set_position_y (xpaned, xpaned->original_position.y);
3106                         xpaned->original_position.y = -1;
3107                 }
3108
3109                 gtk_xpaned_restore_focus (xpaned);
3110                 return TRUE;
3111         }
3112
3113         return FALSE;
3114 }
3115
3116 static gboolean gtk_xpaned_cycle_handle_focus (GtkXPaned* xpaned,
3117                                                                                            gboolean reversed)
3118 {
3119         GtkXPaned* next;
3120         GtkXPaned* prev;
3121
3122         if (gtk_widget_is_focus (GTK_WIDGET (xpaned)))
3123         {
3124                 GtkXPaned* focus = NULL;
3125
3126                 if (!xpaned->priv->first_xpaned)
3127                 {
3128                         /* The first_pane has disappeared. As an ad-hoc solution,
3129                         * we make the currently focused paned the first_paned. To the
3130                         * user this will seem like the paned cycling has been reset.
3131                         */
3132                         gtk_xpaned_set_first_xpaned (xpaned, xpaned);
3133                 }
3134
3135                 gtk_xpaned_find_neighbours (xpaned, &next, &prev);
3136
3137                 if (reversed && prev &&
3138                         prev != xpaned && xpaned != xpaned->priv->first_xpaned)
3139                 {
3140                         focus = prev;
3141                 }
3142                 else if (!reversed &&
3143                                  next &&
3144                                  next != xpaned &&
3145                                  next != xpaned->priv->first_xpaned)
3146                 {
3147                         focus = next;
3148                 }
3149                 else
3150                 {
3151                         gtk_xpaned_accept_position (xpaned);
3152                         return TRUE;
3153                 }
3154
3155                 g_assert (focus);
3156       
3157                 gtk_xpaned_set_saved_focus (focus, xpaned->priv->saved_focus);
3158                 gtk_xpaned_set_first_xpaned (focus, xpaned->priv->first_xpaned);
3159       
3160                 gtk_xpaned_set_saved_focus (xpaned, NULL);
3161                 gtk_xpaned_set_first_xpaned (xpaned, NULL);
3162       
3163                 gtk_widget_grab_focus (GTK_WIDGET (focus));
3164       
3165                 if (!gtk_widget_is_focus (GTK_WIDGET (xpaned)))
3166                 {
3167                         xpaned->original_position.x = -1;
3168                         xpaned->original_position.y = -1;
3169                         focus->original_position.x = gtk_xpaned_get_position_x (focus);
3170                         focus->original_position.y = gtk_xpaned_get_position_y (focus);
3171                 }
3172         }
3173         else
3174     {
3175                 GtkContainer* container = GTK_CONTAINER (xpaned);
3176                 GtkXPaned* focus;
3177                 GtkXPaned* first;
3178                 GtkXPaned* prev;
3179                 GtkXPaned* next;
3180                 GtkWidget* toplevel;
3181
3182                 gtk_xpaned_find_neighbours (xpaned, &next, &prev);
3183
3184                 if (container->focus_child == xpaned->top_left_child)
3185                 {
3186                         if (reversed)
3187                         {
3188                                 focus = prev;
3189                                 first = xpaned;
3190                         }
3191                         else
3192                         {
3193                                 focus = xpaned;
3194                                 first = xpaned;
3195                         }
3196                 }
3197                 else if (container->focus_child == xpaned->top_right_child)
3198                 {
3199                         if (reversed)
3200                         {
3201                                 focus = xpaned;
3202                                 first = next;
3203                         }
3204                         else
3205                         {
3206                                 focus = next;
3207                                 first = next;
3208                         }
3209                 }
3210                 else
3211                 {
3212                         /* Focus is not inside this xpaned, and we don't have focus.
3213                         * Presumably this happened because the application wants us
3214                         * to start keyboard navigating.
3215                         */
3216                         focus = xpaned;
3217
3218                         if (reversed)
3219                                 first = xpaned;
3220                         else
3221                                 first = next;
3222                 }
3223
3224                 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (xpaned));
3225
3226                 if (GTK_IS_WINDOW (toplevel))
3227                         gtk_xpaned_set_saved_focus (focus, GTK_WINDOW (toplevel)->focus_widget);
3228                 gtk_xpaned_set_first_xpaned (focus, first);
3229                 focus->original_position.x = gtk_xpaned_get_position_x (focus);
3230                 focus->original_position.y = gtk_xpaned_get_position_y (focus); 
3231
3232                 gtk_widget_grab_focus (GTK_WIDGET (focus));
3233         }
3234
3235         return TRUE;
3236 }
3237
3238 static gboolean gtk_xpaned_toggle_handle_focus (GtkXPaned* xpaned)
3239 {
3240         /* This function/signal has the wrong name. It is called when you
3241         * press Tab or Shift-Tab and what we do is act as if
3242         * the user pressed Return and then Tab or Shift-Tab
3243         */
3244         if (gtk_widget_is_focus (GTK_WIDGET (xpaned)))
3245                 gtk_xpaned_accept_position (xpaned);
3246
3247   return FALSE;
3248 }
3249
3250 /*#define __GTK_XPANED_C__*/
3251 /*#include "gtkaliasdef.c"*/