Created new directory src/ui/gui/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 <ui/gui/psppire-marshal.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                                                                                                 psppire_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                                                                                                   psppire_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                                                                                  psppire_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                                                                                                  psppire_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                                                                                           psppire_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                                                                                           psppire_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 void
713 gtk_xpaned_compute_position (GtkXPaned* xpaned,
714                              const GtkAllocation* allocation,
715                              GtkRequisition* top_left_child_req,
716                              GtkRequisition* top_right_child_req,
717                              GtkRequisition* bottom_left_child_req,
718                              GtkRequisition* bottom_right_child_req);
719
720
721 static void gtk_xpaned_size_allocate (GtkWidget* widget,
722                                                                           GtkAllocation* allocation)
723 {
724         GtkXPaned* xpaned = GTK_XPANED (widget);
725         gint border_width = GTK_CONTAINER (xpaned)->border_width;
726         GtkAllocation top_left_child_allocation;
727         GtkAllocation top_right_child_allocation;
728         GtkAllocation bottom_left_child_allocation;
729         GtkAllocation bottom_right_child_allocation;
730         GtkRequisition top_left_child_requisition;
731         GtkRequisition top_right_child_requisition;
732         GtkRequisition bottom_left_child_requisition;
733         GtkRequisition bottom_right_child_requisition;
734         gint handle_size;
735
736         /* determine size of handle(s) */
737         gtk_widget_style_get (widget, "handle-size", &handle_size, NULL);
738
739         widget->allocation = *allocation;
740
741         if (xpaned->top_left_child && GTK_WIDGET_VISIBLE (xpaned->top_left_child) &&
742                 xpaned->top_right_child && GTK_WIDGET_VISIBLE (xpaned->top_right_child) &&
743                 xpaned->bottom_left_child && GTK_WIDGET_VISIBLE (xpaned->bottom_left_child) &&
744                 xpaned->bottom_right_child && GTK_WIDGET_VISIBLE (xpaned->bottom_right_child))
745     {
746                 /* what sizes do the children want to be at least at */
747                 gtk_widget_get_child_requisition (xpaned->top_left_child,
748                                                                                   &top_left_child_requisition);
749                 gtk_widget_get_child_requisition (xpaned->top_right_child,
750                                                                                   &top_right_child_requisition);
751                 gtk_widget_get_child_requisition (xpaned->bottom_left_child,
752                                                                                   &bottom_left_child_requisition);
753                 gtk_widget_get_child_requisition (xpaned->bottom_right_child,
754                                                                                   &bottom_right_child_requisition);
755
756                 /* determine the total requisition-sum of all requisitions of borders,
757                  * handles, children etc. */
758                 gtk_xpaned_compute_position (xpaned,
759                                                                          allocation,
760                                                                          &top_left_child_requisition,
761                                                                          &top_right_child_requisition,
762                                                                          &bottom_left_child_requisition,
763                                                                          &bottom_right_child_requisition);
764
765                 /* calculate the current positions and sizes of the handles */
766                 xpaned->handle_pos_east.x = widget->allocation.x + border_width + xpaned->top_left_child_size.width + handle_size;
767                 xpaned->handle_pos_east.y = widget->allocation.y + border_width + xpaned->top_left_child_size.height;
768                 xpaned->handle_pos_east.width = widget->allocation.width - xpaned->top_left_child_size.width - 2 * border_width - handle_size;
769                 xpaned->handle_pos_east.height = handle_size;
770
771                 xpaned->handle_pos_west.x = widget->allocation.x + border_width;
772                 xpaned->handle_pos_west.y = xpaned->handle_pos_east.y;
773                 xpaned->handle_pos_west.width = widget->allocation.width - xpaned->handle_pos_east.width - 2 * border_width - handle_size;
774                 xpaned->handle_pos_west.height = handle_size;
775
776                 xpaned->handle_pos_north.x = xpaned->handle_pos_east.x - handle_size;
777                 xpaned->handle_pos_north.y = widget->allocation.y + border_width;
778                 xpaned->handle_pos_north.width = handle_size;
779                 xpaned->handle_pos_north.height = xpaned->handle_pos_east.y - widget->allocation.y - border_width;
780
781                 xpaned->handle_pos_south.x = xpaned->handle_pos_north.x;
782                 xpaned->handle_pos_south.y = xpaned->handle_pos_east.y + handle_size;
783                 xpaned->handle_pos_south.width = handle_size;
784                 xpaned->handle_pos_south.height = widget->allocation.height - xpaned->handle_pos_north.height - 2 * border_width - handle_size;
785
786
787 #define CENTRUM 20
788                 xpaned->handle_pos_middle.x = xpaned->handle_pos_north.x ;
789                 xpaned->handle_pos_middle.y = xpaned->handle_pos_east.y ;
790                 xpaned->handle_pos_middle.width = handle_size + CENTRUM ;
791                 xpaned->handle_pos_middle.height = handle_size + CENTRUM;
792
793                 /* set allocation for top-left child */
794                 top_left_child_allocation.x = widget->allocation.x + border_width;
795                 top_left_child_allocation.y = widget->allocation.y + border_width;
796                 top_left_child_allocation.width = xpaned->handle_pos_west.width;
797                 top_left_child_allocation.height = xpaned->handle_pos_north.height;
798
799                 /* set allocation for top-right child */
800                 top_right_child_allocation.x = widget->allocation.x + border_width + handle_size + top_left_child_allocation.width;
801                 top_right_child_allocation.y = widget->allocation.y + border_width;
802                 top_right_child_allocation.width = xpaned->handle_pos_east.width;
803                 top_right_child_allocation.height = xpaned->handle_pos_north.height;
804
805                 /* set allocation for bottom-left child */
806                 bottom_left_child_allocation.x = xpaned->handle_pos_west.x;
807                 bottom_left_child_allocation.y = xpaned->handle_pos_south.y;
808                 bottom_left_child_allocation.width = xpaned->handle_pos_west.width;
809                 bottom_left_child_allocation.height = xpaned->handle_pos_south.height;
810
811                 /* set allocation for bottom-right child */
812                 bottom_right_child_allocation.x = top_right_child_allocation.x;
813                 bottom_right_child_allocation.y = bottom_left_child_allocation.y;
814                 bottom_right_child_allocation.width = xpaned->handle_pos_east.width;
815                 bottom_right_child_allocation.height = xpaned->handle_pos_south.height;
816
817                 if (GTK_WIDGET_REALIZED (widget))
818                 {
819                         if (GTK_WIDGET_MAPPED (widget))
820                         {
821                                 gdk_window_show (xpaned->handle_east);
822                                 gdk_window_show (xpaned->handle_west);
823                                 gdk_window_show (xpaned->handle_north);
824                                 gdk_window_show (xpaned->handle_south);
825                                 gdk_window_show (xpaned->handle_middle);
826                         }
827
828                         gdk_window_move_resize (xpaned->handle_east,
829                                                                         xpaned->handle_pos_east.x,
830                                                                         xpaned->handle_pos_east.y,
831                                                                         xpaned->handle_pos_east.width,
832                                                                         xpaned->handle_pos_east.height);
833
834                         gdk_window_move_resize (xpaned->handle_west,
835                                                                         xpaned->handle_pos_west.x,
836                                                                         xpaned->handle_pos_west.y,
837                                                                         xpaned->handle_pos_west.width,
838                                                                         xpaned->handle_pos_west.height);
839
840                         gdk_window_move_resize (xpaned->handle_north,
841                                                                         xpaned->handle_pos_north.x,
842                                                                         xpaned->handle_pos_north.y,
843                                                                         xpaned->handle_pos_north.width,
844                                                                         xpaned->handle_pos_north.height);
845
846                         gdk_window_move_resize (xpaned->handle_south,
847                                                                         xpaned->handle_pos_south.x,
848                                                                         xpaned->handle_pos_south.y,
849                                                                         xpaned->handle_pos_south.width,
850                                                                         xpaned->handle_pos_south.height);
851
852                         gdk_window_move_resize (xpaned->handle_middle,
853                                                 xpaned->handle_pos_middle.x,
854                                                 xpaned->handle_pos_middle.y,
855                                                 xpaned->handle_pos_middle.width,
856                                                 xpaned->handle_pos_middle.height);
857                 }
858
859                 /* Now allocate the childen, making sure, when resizing not to
860                 * overlap the windows
861                 */
862                 if (GTK_WIDGET_MAPPED (widget))
863                 {
864                         gtk_widget_size_allocate (xpaned->top_right_child, &top_right_child_allocation);
865                         gtk_widget_size_allocate (xpaned->top_left_child, &top_left_child_allocation);
866                         gtk_widget_size_allocate (xpaned->bottom_left_child, &bottom_left_child_allocation);
867                         gtk_widget_size_allocate (xpaned->bottom_right_child, &bottom_right_child_allocation);
868                 }
869         }
870 }
871
872 static void gtk_xpaned_set_property (GObject* object,
873                                                                          guint prop_id,
874                                                                          const GValue* value,
875                                                                          GParamSpec* pspec)
876 {
877         GtkXPaned* xpaned = GTK_XPANED (object);
878   
879         switch (prop_id)
880         {
881                 case PROP_X_POSITION:
882                         gtk_xpaned_set_position_x (xpaned, g_value_get_int (value));
883                 break;
884
885                 case PROP_Y_POSITION:
886                         gtk_xpaned_set_position_y (xpaned, g_value_get_int (value));
887                 break;
888
889                 case PROP_POSITION_SET:
890                         xpaned->position_set = g_value_get_boolean (value);
891                         gtk_widget_queue_resize (GTK_WIDGET (xpaned));
892                 break;
893
894                 default:
895                         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
896                 break;
897         }
898 }
899
900 static void gtk_xpaned_get_property (GObject* object,
901                                                                          guint prop_id,
902                                                                          GValue* value,
903                                                                          GParamSpec* pspec)
904 {
905         GtkXPaned* xpaned = GTK_XPANED (object);
906   
907         switch (prop_id)
908         {
909                 case PROP_X_POSITION:
910                         g_value_set_int (value, xpaned->top_left_child_size.width);
911                 break;
912
913                 case PROP_Y_POSITION:
914                         g_value_set_int (value, xpaned->top_left_child_size.height);
915                 break;
916
917                 case PROP_POSITION_SET:
918                         g_value_set_boolean (value, xpaned->position_set);
919                 break;
920
921                 case PROP_MIN_X_POSITION:
922                         g_value_set_int (value, xpaned->min_position.x);
923                 break;
924
925                 case PROP_MIN_Y_POSITION:
926                         g_value_set_int (value, xpaned->min_position.y);
927                 break;
928
929                 case PROP_MAX_X_POSITION:
930                         g_value_set_int (value, xpaned->max_position.x);
931                 break;
932
933                 case PROP_MAX_Y_POSITION:
934                         g_value_set_int (value, xpaned->max_position.y);
935                 break;
936
937                 default:
938                         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
939                 break;
940         }
941 }
942
943 static void gtk_xpaned_set_child_property (GtkContainer* container,
944                                                                                    GtkWidget* child,
945                                                                                    guint property_id,
946                                                                                    const GValue* value,
947                                                                                    GParamSpec* pspec)
948 {
949         GtkXPaned* xpaned = GTK_XPANED (container);
950         gboolean old_value = FALSE;
951         gboolean new_value = FALSE;
952
953         g_assert (child == xpaned->top_left_child ||
954                           child == xpaned->top_right_child ||
955                           child == xpaned->bottom_left_child ||
956                           child == xpaned->bottom_right_child);
957
958         new_value = g_value_get_boolean (value);
959
960         switch (property_id)
961         {
962                 case CHILD_PROP_RESIZE:
963                         if (child == xpaned->top_left_child)
964                         {
965                                 old_value = xpaned->top_left_child_resize;
966                                 xpaned->top_left_child_resize = new_value;
967                         }
968                         else if (child == xpaned->top_right_child)
969                         {
970                                 old_value = xpaned->top_right_child_resize;
971                                 xpaned->top_right_child_resize = new_value;
972                         }
973                         else if (child == xpaned->bottom_left_child)
974                         {
975                                 old_value = xpaned->bottom_left_child_resize;
976                                 xpaned->bottom_left_child_resize = new_value;
977                         }
978                         else if (child == xpaned->bottom_right_child)
979                         {
980                                 old_value = xpaned->bottom_right_child_resize;
981                                 xpaned->bottom_right_child_resize = new_value;
982                         }
983                 break;
984
985                 case CHILD_PROP_SHRINK :
986                         if (child == xpaned->top_left_child)
987                         {
988                                 old_value = xpaned->top_left_child_shrink;
989                                 xpaned->top_left_child_shrink = new_value;
990                         }
991                         else if (child == xpaned->top_right_child)
992                         {
993                                 old_value = xpaned->top_right_child_shrink;
994                                 xpaned->top_right_child_shrink = new_value;
995                         }
996                         else if (child == xpaned->bottom_left_child)
997                         {
998                                 old_value = xpaned->bottom_left_child_shrink;
999                                 xpaned->bottom_left_child_shrink = new_value;
1000                         }
1001                         else if (child == xpaned->bottom_right_child)
1002                         {
1003                                 old_value = xpaned->bottom_right_child_shrink;
1004                                 xpaned->bottom_right_child_shrink = new_value;
1005                         }
1006                 break;
1007
1008                 default:
1009                         GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container,
1010                                                                                                                   property_id,
1011                                                                                                                   pspec);
1012                         old_value = -1; /* quiet gcc */
1013                 break;
1014         }
1015
1016         if (old_value != new_value)
1017                 gtk_widget_queue_resize (GTK_WIDGET (container));
1018 }
1019
1020 static void gtk_xpaned_get_child_property (GtkContainer* container,
1021                                                                                    GtkWidget* child,
1022                                                                                    guint property_id,
1023                                                                                    GValue* value,
1024                                                                                    GParamSpec* pspec)
1025 {
1026         GtkXPaned* xpaned = GTK_XPANED (container);
1027
1028         g_assert (child == xpaned->top_left_child ||
1029                           child == xpaned->top_right_child ||
1030                           child == xpaned->bottom_left_child ||
1031                           child == xpaned->bottom_right_child);
1032
1033         switch (property_id)
1034         {
1035                 case CHILD_PROP_RESIZE :
1036                         if (child == xpaned->top_left_child)
1037                                 g_value_set_boolean (value, xpaned->top_left_child_resize);
1038                         else if (child == xpaned->top_right_child)
1039                                 g_value_set_boolean (value, xpaned->top_right_child_resize);
1040                         else if (child == xpaned->bottom_left_child)
1041                                 g_value_set_boolean (value, xpaned->bottom_left_child_resize);
1042                         else if (child == xpaned->bottom_right_child)
1043                                 g_value_set_boolean (value, xpaned->bottom_right_child_resize);                 
1044                 break;
1045
1046                 case CHILD_PROP_SHRINK :
1047                         if (child == xpaned->top_left_child)
1048                                 g_value_set_boolean (value, xpaned->top_left_child_shrink);
1049                         else if (child == xpaned->top_right_child)
1050                                 g_value_set_boolean (value, xpaned->top_right_child_shrink);
1051                         else if (child == xpaned->bottom_left_child)
1052                                 g_value_set_boolean (value, xpaned->bottom_left_child_shrink);
1053                         else if (child == xpaned->bottom_right_child)
1054                                 g_value_set_boolean (value, xpaned->bottom_right_child_shrink);
1055                 break;
1056
1057                 default:
1058                         GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container,
1059                                                                                                                   property_id,
1060                                                                                                                   pspec);
1061                 break;
1062         }
1063 }
1064
1065 static void gtk_xpaned_finalize (GObject* object)
1066 {
1067         GtkXPaned* xpaned = GTK_XPANED (object);
1068   
1069         gtk_xpaned_set_saved_focus (xpaned, NULL);
1070         gtk_xpaned_set_first_xpaned (xpaned, NULL);
1071
1072         g_free (xpaned->priv);
1073
1074         G_OBJECT_CLASS (parent_class)->finalize (object);
1075 }
1076
1077 static void gtk_xpaned_realize (GtkWidget* widget)
1078 {
1079         GtkXPaned* xpaned;
1080         GdkWindowAttr attributes_east;
1081         GdkWindowAttr attributes_west;
1082         GdkWindowAttr attributes_north;
1083         GdkWindowAttr attributes_south;
1084         GdkWindowAttr attributes_middle;
1085         gint attributes_mask_east;
1086         gint attributes_mask_west;
1087         gint attributes_mask_north;
1088         gint attributes_mask_south;
1089         gint attributes_mask_middle;
1090
1091         GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
1092         xpaned = GTK_XPANED (widget);
1093
1094         widget->window = gtk_widget_get_parent_window (widget);
1095         g_object_ref (widget->window);
1096   
1097         attributes_east.window_type = GDK_WINDOW_CHILD;
1098         attributes_west.window_type = GDK_WINDOW_CHILD;
1099         attributes_north.window_type = GDK_WINDOW_CHILD;
1100         attributes_south.window_type = GDK_WINDOW_CHILD;
1101         attributes_middle.window_type = GDK_WINDOW_CHILD;
1102
1103         attributes_east.wclass = GDK_INPUT_ONLY;
1104         attributes_west.wclass = GDK_INPUT_ONLY;
1105         attributes_north.wclass = GDK_INPUT_ONLY;
1106         attributes_south.wclass = GDK_INPUT_ONLY;
1107         attributes_middle.wclass = GDK_INPUT_ONLY;
1108
1109         attributes_east.x = xpaned->handle_pos_east.x;
1110         attributes_east.y = xpaned->handle_pos_east.y;
1111         attributes_east.width = xpaned->handle_pos_east.width;
1112         attributes_east.height = xpaned->handle_pos_east.height;
1113
1114         attributes_west.x = xpaned->handle_pos_west.x;
1115         attributes_west.y = xpaned->handle_pos_west.y;
1116         attributes_west.width = xpaned->handle_pos_west.width;
1117         attributes_west.height = xpaned->handle_pos_west.height;
1118
1119         attributes_north.x = xpaned->handle_pos_north.x;
1120         attributes_north.y = xpaned->handle_pos_north.y;
1121         attributes_north.width = xpaned->handle_pos_north.width;
1122         attributes_north.height = xpaned->handle_pos_north.height;
1123
1124         attributes_south.x = xpaned->handle_pos_south.x;
1125         attributes_south.y = xpaned->handle_pos_south.y;
1126         attributes_south.width = xpaned->handle_pos_south.width;
1127         attributes_south.height = xpaned->handle_pos_south.height;
1128
1129         attributes_middle.x = xpaned->handle_pos_middle.x;
1130         attributes_middle.y = xpaned->handle_pos_middle.y;
1131         attributes_middle.width = xpaned->handle_pos_middle.width;
1132         attributes_middle.height = xpaned->handle_pos_middle.height;
1133
1134         attributes_east.cursor = gdk_cursor_new_for_display (gtk_widget_get_display (widget),
1135                                                                                                         xpaned->cursor_type_east);
1136         attributes_west.cursor = gdk_cursor_new_for_display (gtk_widget_get_display (widget),
1137                                                                                                         xpaned->cursor_type_west);
1138         attributes_north.cursor = gdk_cursor_new_for_display (gtk_widget_get_display (widget),
1139                                                                                                         xpaned->cursor_type_north);
1140         attributes_south.cursor = gdk_cursor_new_for_display (gtk_widget_get_display (widget),
1141                                                                                                         xpaned->cursor_type_south);
1142         attributes_middle.cursor = gdk_cursor_new_for_display (gtk_widget_get_display (widget),
1143                                                                                                         xpaned->cursor_type_middle);
1144
1145         attributes_east.event_mask = gtk_widget_get_events (widget);
1146         attributes_west.event_mask = gtk_widget_get_events (widget);
1147         attributes_north.event_mask = gtk_widget_get_events (widget);
1148         attributes_south.event_mask = gtk_widget_get_events (widget);
1149         attributes_middle.event_mask = gtk_widget_get_events (widget);
1150
1151         attributes_east.event_mask |= (GDK_BUTTON_PRESS_MASK |
1152                                                           GDK_BUTTON_RELEASE_MASK |
1153                                                           GDK_ENTER_NOTIFY_MASK |
1154                                                           GDK_LEAVE_NOTIFY_MASK |
1155                                                           GDK_POINTER_MOTION_MASK |
1156                                                           GDK_POINTER_MOTION_HINT_MASK);
1157         attributes_west.event_mask |= (GDK_BUTTON_PRESS_MASK |
1158                                                           GDK_BUTTON_RELEASE_MASK |
1159                                                           GDK_ENTER_NOTIFY_MASK |
1160                                                           GDK_LEAVE_NOTIFY_MASK |
1161                                                           GDK_POINTER_MOTION_MASK |
1162                                                           GDK_POINTER_MOTION_HINT_MASK);
1163         attributes_north.event_mask |= (GDK_BUTTON_PRESS_MASK |
1164                                                           GDK_BUTTON_RELEASE_MASK |
1165                                                           GDK_ENTER_NOTIFY_MASK |
1166                                                           GDK_LEAVE_NOTIFY_MASK |
1167                                                           GDK_POINTER_MOTION_MASK |
1168                                                           GDK_POINTER_MOTION_HINT_MASK);
1169         attributes_south.event_mask |= (GDK_BUTTON_PRESS_MASK |
1170                                                           GDK_BUTTON_RELEASE_MASK |
1171                                                           GDK_ENTER_NOTIFY_MASK |
1172                                                           GDK_LEAVE_NOTIFY_MASK |
1173                                                           GDK_POINTER_MOTION_MASK |
1174                                                           GDK_POINTER_MOTION_HINT_MASK);
1175         attributes_middle.event_mask |= (GDK_BUTTON_PRESS_MASK |
1176                                                           GDK_BUTTON_RELEASE_MASK |
1177                                                           GDK_ENTER_NOTIFY_MASK |
1178                                                           GDK_LEAVE_NOTIFY_MASK |
1179                                                           GDK_POINTER_MOTION_MASK |
1180                                                           GDK_POINTER_MOTION_HINT_MASK);
1181
1182         attributes_mask_east = GDK_WA_X | GDK_WA_Y | GDK_WA_CURSOR;
1183         attributes_mask_west = GDK_WA_X | GDK_WA_Y | GDK_WA_CURSOR;
1184         attributes_mask_north = GDK_WA_X | GDK_WA_Y | GDK_WA_CURSOR;
1185         attributes_mask_south = GDK_WA_X | GDK_WA_Y | GDK_WA_CURSOR;
1186         attributes_mask_middle = GDK_WA_X | GDK_WA_Y | GDK_WA_CURSOR;
1187
1188         xpaned->handle_east = gdk_window_new (widget->window,
1189                                                                                   &attributes_east,
1190                                                                                   attributes_mask_east);
1191         xpaned->handle_west = gdk_window_new (widget->window,
1192                                                                                   &attributes_west,
1193                                                                                   attributes_mask_west);
1194         xpaned->handle_north = gdk_window_new (widget->window,
1195                                                                                   &attributes_north,
1196                                                                                   attributes_mask_north);
1197         xpaned->handle_south = gdk_window_new (widget->window,
1198                                                                                   &attributes_south,
1199                                                                                   attributes_mask_south);
1200         xpaned->handle_middle = gdk_window_new (widget->window,
1201                                                                                   &attributes_middle,
1202                                                                                   attributes_mask_middle);
1203
1204         gdk_window_set_user_data (xpaned->handle_east, xpaned);
1205         gdk_window_set_user_data (xpaned->handle_west, xpaned);
1206         gdk_window_set_user_data (xpaned->handle_north, xpaned);
1207         gdk_window_set_user_data (xpaned->handle_south, xpaned);
1208         gdk_window_set_user_data (xpaned->handle_middle, xpaned);
1209
1210         gdk_cursor_unref (attributes_east.cursor);
1211         gdk_cursor_unref (attributes_west.cursor);
1212         gdk_cursor_unref (attributes_north.cursor);
1213         gdk_cursor_unref (attributes_south.cursor);
1214         gdk_cursor_unref (attributes_middle.cursor);
1215
1216         widget->style = gtk_style_attach (widget->style, widget->window);
1217
1218         if (xpaned->top_left_child && GTK_WIDGET_VISIBLE (xpaned->top_left_child) &&
1219                 xpaned->top_right_child && GTK_WIDGET_VISIBLE (xpaned->top_right_child) &&
1220                 xpaned->bottom_left_child && GTK_WIDGET_VISIBLE (xpaned->bottom_left_child) &&
1221                 xpaned->bottom_right_child && GTK_WIDGET_VISIBLE (xpaned->bottom_right_child))
1222         {
1223                 gdk_window_show (xpaned->handle_east);
1224                 gdk_window_show (xpaned->handle_west);
1225                 gdk_window_show (xpaned->handle_north);
1226                 gdk_window_show (xpaned->handle_south);
1227                 gdk_window_show (xpaned->handle_middle);
1228         }
1229 }
1230
1231 static void gtk_xpaned_unrealize (GtkWidget *widget)
1232 {
1233         GtkXPaned* xpaned = GTK_XPANED (widget);
1234
1235         if (xpaned->xor_gc)
1236         {
1237                 g_object_unref (xpaned->xor_gc);
1238                 xpaned->xor_gc = NULL;
1239         }
1240
1241         if (xpaned->handle_east)
1242         {
1243                 gdk_window_set_user_data (xpaned->handle_east, NULL);
1244                 gdk_window_destroy (xpaned->handle_east);
1245                 xpaned->handle_east = NULL;
1246         }
1247
1248         if (xpaned->handle_west)
1249         {
1250                 gdk_window_set_user_data (xpaned->handle_west, NULL);
1251                 gdk_window_destroy (xpaned->handle_west);
1252                 xpaned->handle_west = NULL;
1253         }
1254
1255         if (xpaned->handle_north)
1256         {
1257                 gdk_window_set_user_data (xpaned->handle_north, NULL);
1258                 gdk_window_destroy (xpaned->handle_north);
1259                 xpaned->handle_north = NULL;
1260         }
1261
1262         if (xpaned->handle_south)
1263         {
1264                 gdk_window_set_user_data (xpaned->handle_south, NULL);
1265                 gdk_window_destroy (xpaned->handle_south);
1266                 xpaned->handle_south = NULL;
1267         }
1268
1269         if (xpaned->handle_middle)
1270         {
1271                 gdk_window_set_user_data (xpaned->handle_middle, NULL);
1272                 gdk_window_destroy (xpaned->handle_middle);
1273                 xpaned->handle_middle = NULL;
1274         }
1275
1276         gtk_xpaned_set_last_top_left_child_focus (xpaned, NULL);
1277         gtk_xpaned_set_last_top_right_child_focus (xpaned, NULL);
1278         gtk_xpaned_set_last_bottom_left_child_focus (xpaned, NULL);
1279         gtk_xpaned_set_last_bottom_right_child_focus (xpaned, NULL);
1280         gtk_xpaned_set_saved_focus (xpaned, NULL);
1281         gtk_xpaned_set_first_xpaned (xpaned, NULL);
1282   
1283         if (GTK_WIDGET_CLASS (parent_class)->unrealize)
1284                 (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
1285 }
1286
1287 static void gtk_xpaned_map (GtkWidget* widget)
1288 {
1289         GtkXPaned* xpaned = GTK_XPANED (widget);
1290
1291         gdk_window_show (xpaned->handle_east);
1292         gdk_window_show (xpaned->handle_west);
1293         gdk_window_show (xpaned->handle_north);
1294         gdk_window_show (xpaned->handle_south);
1295         gdk_window_show (xpaned->handle_middle);
1296
1297         GTK_WIDGET_CLASS (parent_class)->map (widget);
1298 }
1299
1300 static void gtk_xpaned_unmap (GtkWidget* widget)
1301 {
1302         GtkXPaned* xpaned = GTK_XPANED (widget);
1303
1304         gdk_window_hide (xpaned->handle_east);
1305         gdk_window_hide (xpaned->handle_west);
1306         gdk_window_hide (xpaned->handle_north);
1307         gdk_window_hide (xpaned->handle_south);
1308         gdk_window_hide (xpaned->handle_middle);
1309
1310         GTK_WIDGET_CLASS (parent_class)->unmap (widget);
1311 }
1312
1313 static gboolean gtk_xpaned_expose (GtkWidget* widget,
1314                                                                    GdkEventExpose* event)
1315 {
1316         GtkXPaned* xpaned = GTK_XPANED (widget);
1317         gint handle_size;
1318         GdkRectangle horizontalClipArea;
1319         GdkRectangle verticalClipArea;
1320
1321         /* determine size of handle(s) */
1322         gtk_widget_style_get (widget, "handle-size", &handle_size, NULL);
1323
1324         /* I want the handle-"thickness" to be at least 3 */
1325         g_assert (handle_size >= 3);
1326
1327         if (GTK_WIDGET_VISIBLE (widget) && GTK_WIDGET_MAPPED (widget) &&
1328                 xpaned->top_left_child && GTK_WIDGET_VISIBLE (xpaned->top_left_child) &&
1329                 xpaned->top_right_child && GTK_WIDGET_VISIBLE (xpaned->top_right_child) &&
1330                 xpaned->bottom_left_child && GTK_WIDGET_VISIBLE (xpaned->bottom_left_child) &&
1331                 xpaned->bottom_right_child && GTK_WIDGET_VISIBLE (xpaned->bottom_right_child))
1332     {
1333                 GtkStateType state;
1334
1335                 if (gtk_widget_is_focus (widget))
1336                         state = GTK_STATE_SELECTED;
1337                 else if (xpaned->handle_prelit)
1338                         state = GTK_STATE_PRELIGHT;
1339                 else
1340                         state = GTK_WIDGET_STATE (widget);
1341
1342                 horizontalClipArea.x = xpaned->handle_pos_west.x;
1343                 horizontalClipArea.y = xpaned->handle_pos_west.y;
1344                 horizontalClipArea.width = xpaned->handle_pos_west.width + handle_size + xpaned->handle_pos_east.width;
1345                 horizontalClipArea.height = handle_size;
1346
1347                 verticalClipArea.x = xpaned->handle_pos_north.x;
1348                 verticalClipArea.y = xpaned->handle_pos_north.y;
1349                 verticalClipArea.width = handle_size;
1350                 verticalClipArea.height = xpaned->handle_pos_north.height + handle_size + xpaned->handle_pos_south.height;
1351
1352                 gtk_paint_handle (widget->style,
1353                                                   widget->window,
1354                                                   state,
1355                                                   GTK_SHADOW_NONE,
1356                                                   &horizontalClipArea,
1357                                                   widget,
1358                                                   "paned",
1359                                                   xpaned->handle_pos_east.x - handle_size - 256 / 2,
1360                                                   xpaned->handle_pos_west.y + 1,
1361                                                   256 + handle_size,
1362                                                   handle_size - 2,
1363                                                   /*xpaned->handle_pos_west.x,
1364                                                   xpaned->handle_pos_west.y + 1,
1365                                                   xpaned->handle_pos_west.width + handle_size + xpaned->handle_pos_east.width,
1366                                                   handle_size - 2,*/
1367                                                   GTK_ORIENTATION_HORIZONTAL);
1368                 gtk_paint_handle (widget->style,
1369                                                   widget->window,
1370                                                   state,
1371                                                   GTK_SHADOW_NONE,
1372                                                   &verticalClipArea,
1373                                                   widget,
1374                                                   "paned",
1375                                                   xpaned->handle_pos_north.x + 1,
1376                                                   xpaned->handle_pos_south.y - handle_size - 256 / 2,
1377                                                   handle_size - 2,
1378                                                   256 + handle_size,
1379                                                   /*xpaned->handle_pos_north.x + 1,
1380                                                   xpaned->handle_pos_north.y,
1381                                                   handle_size - 2,
1382                                                   xpaned->handle_pos_north.height + handle_size + xpaned->handle_pos_south.height,*/
1383                                                   GTK_ORIENTATION_VERTICAL);
1384         }
1385
1386         /* Chain up to draw children */
1387         GTK_WIDGET_CLASS (parent_class)->expose_event (widget, event);
1388   
1389         return FALSE;
1390 }
1391
1392 static gboolean is_rtl (GtkXPaned* xpaned)
1393 {
1394         if (gtk_widget_get_direction (GTK_WIDGET (xpaned)) == GTK_TEXT_DIR_RTL)
1395                 return TRUE;
1396
1397         return FALSE;
1398 }
1399
1400 static void update_drag (GtkXPaned* xpaned)
1401 {
1402         GdkPoint pos;
1403         gint handle_size;
1404         GtkRequisition size;
1405   
1406         gtk_widget_get_pointer (GTK_WIDGET (xpaned), &pos.x, &pos.y);
1407
1408         if (xpaned->in_drag_vert)
1409         {
1410                 pos.y -= xpaned->drag_pos.y;
1411
1412                 if (is_rtl (xpaned))
1413             {
1414                         gtk_widget_style_get (GTK_WIDGET (xpaned),
1415                                                                   "handle-size", &handle_size,
1416                                                                   NULL);
1417       
1418                         size.height = GTK_WIDGET (xpaned)->allocation.height - pos.y - handle_size;
1419                 }
1420                 else
1421                 {
1422                         size.height = pos.y;
1423                 }
1424
1425                 size.height -= GTK_CONTAINER (xpaned)->border_width;
1426
1427                 size.height = CLAMP (size.height, xpaned->min_position.y, xpaned->max_position.y);
1428
1429                 if (size.height != xpaned->top_left_child_size.height)
1430                         gtk_xpaned_set_position_y (xpaned, size.height);
1431         }
1432
1433         if (xpaned->in_drag_horiz)
1434         {
1435                 pos.x -= xpaned->drag_pos.x;
1436         
1437                 if (is_rtl (xpaned))
1438             {
1439                         gtk_widget_style_get (GTK_WIDGET (xpaned),
1440                                                                   "handle-size", &handle_size,
1441                                                                   NULL);
1442
1443                         size.width = GTK_WIDGET (xpaned)->allocation.width - pos.x - handle_size;
1444                 }
1445                 else
1446                 {
1447                         size.width = pos.x;
1448                 }
1449
1450                 size.width -= GTK_CONTAINER (xpaned)->border_width;
1451
1452                 size.width = CLAMP (size.width, xpaned->min_position.x, xpaned->max_position.x);
1453
1454                 if (size.width != xpaned->top_left_child_size.width)
1455                         gtk_xpaned_set_position_x (xpaned, size.width);
1456         }
1457
1458         if (xpaned->in_drag_vert_and_horiz)
1459         {
1460                 pos.x -= xpaned->drag_pos.x;
1461                 pos.y -= xpaned->drag_pos.y;
1462
1463                 if (is_rtl (xpaned))
1464             {
1465                         gtk_widget_style_get (GTK_WIDGET (xpaned),
1466                                                                   "handle-size", &handle_size,
1467                                                                   NULL);
1468       
1469                         size.width = GTK_WIDGET (xpaned)->allocation.width - pos.x - handle_size;
1470                         size.height = GTK_WIDGET (xpaned)->allocation.height - pos.y - handle_size;
1471                 }
1472                 else
1473                 {
1474                         size.width = pos.x;
1475                         size.height = pos.y;
1476                 }
1477
1478                 size.width -= GTK_CONTAINER (xpaned)->border_width;
1479                 size.height -= GTK_CONTAINER (xpaned)->border_width;
1480
1481                 size.width = CLAMP (size.width, xpaned->min_position.x, xpaned->max_position.x);
1482                 size.height = CLAMP (size.height, xpaned->min_position.y, xpaned->max_position.y);
1483
1484                 if (size.width != xpaned->top_left_child_size.width)
1485                         gtk_xpaned_set_position_x (xpaned, size.width);
1486
1487                 if (size.height != xpaned->top_left_child_size.height)
1488                         gtk_xpaned_set_position_y (xpaned, size.height);
1489         }
1490 }
1491
1492 static gboolean gtk_xpaned_enter (GtkWidget* widget, GdkEventCrossing* event)
1493 {
1494         GtkXPaned* xpaned = GTK_XPANED (widget);
1495
1496         if (xpaned->in_drag_vert ||
1497                 xpaned->in_drag_horiz ||
1498                 xpaned->in_drag_vert_and_horiz)
1499                 update_drag (xpaned);
1500         else
1501         {
1502                 xpaned->handle_prelit = TRUE;
1503
1504                 gtk_widget_queue_draw_area (widget,
1505                                                                         xpaned->handle_pos_east.x,
1506                                                                         xpaned->handle_pos_east.y,
1507                                                                         xpaned->handle_pos_east.width,
1508                                                                         xpaned->handle_pos_east.height);
1509
1510                 gtk_widget_queue_draw_area (widget,
1511                                                                         xpaned->handle_pos_west.x,
1512                                                                         xpaned->handle_pos_west.y,
1513                                                                         xpaned->handle_pos_west.width,
1514                                                                         xpaned->handle_pos_west.height);
1515
1516                 gtk_widget_queue_draw_area (widget,
1517                                                                         xpaned->handle_pos_north.x,
1518                                                                         xpaned->handle_pos_north.y,
1519                                                                         xpaned->handle_pos_north.width,
1520                                                                         xpaned->handle_pos_north.height);
1521
1522                 gtk_widget_queue_draw_area (widget,
1523                                                                         xpaned->handle_pos_south.x,
1524                                                                         xpaned->handle_pos_south.y,
1525                                                                         xpaned->handle_pos_south.width,
1526                                                                         xpaned->handle_pos_south.height);
1527
1528                 gtk_widget_queue_draw_area (widget,
1529                                                                         xpaned->handle_pos_middle.x,
1530                                                                         xpaned->handle_pos_middle.y,
1531                                                                         xpaned->handle_pos_middle.width,
1532                                                                         xpaned->handle_pos_middle.height);
1533         }
1534
1535         return TRUE;
1536 }
1537
1538 static gboolean gtk_xpaned_leave (GtkWidget* widget, GdkEventCrossing* event)
1539 {
1540         GtkXPaned* xpaned = GTK_XPANED (widget);
1541
1542         if (xpaned->in_drag_vert ||
1543                 xpaned->in_drag_horiz ||
1544                 xpaned->in_drag_vert_and_horiz)
1545                 update_drag (xpaned);
1546         else
1547         {
1548                 xpaned->handle_prelit = FALSE;
1549
1550                 gtk_widget_queue_draw_area (widget,
1551                                                                         xpaned->handle_pos_east.x,
1552                                                                         xpaned->handle_pos_east.y,
1553                                                                         xpaned->handle_pos_east.width,
1554                                                                         xpaned->handle_pos_east.height);
1555
1556                 gtk_widget_queue_draw_area (widget,
1557                                                                         xpaned->handle_pos_west.x,
1558                                                                         xpaned->handle_pos_west.y,
1559                                                                         xpaned->handle_pos_west.width,
1560                                                                         xpaned->handle_pos_west.height);
1561
1562                 gtk_widget_queue_draw_area (widget,
1563                                                                         xpaned->handle_pos_north.x,
1564                                                                         xpaned->handle_pos_north.y,
1565                                                                         xpaned->handle_pos_north.width,
1566                                                                         xpaned->handle_pos_north.height);
1567
1568                 gtk_widget_queue_draw_area (widget,
1569                                                                         xpaned->handle_pos_south.x,
1570                                                                         xpaned->handle_pos_south.y,
1571                                                                         xpaned->handle_pos_south.width,
1572                                                                         xpaned->handle_pos_south.height);
1573
1574                 gtk_widget_queue_draw_area (widget,
1575                                                                         xpaned->handle_pos_middle.x,
1576                                                                         xpaned->handle_pos_middle.y,
1577                                                                         xpaned->handle_pos_middle.width,
1578                                                                         xpaned->handle_pos_middle.height);
1579         }
1580
1581         return TRUE;
1582 }
1583
1584 static gboolean gtk_xpaned_focus (GtkWidget* widget, GtkDirectionType direction)
1585 {
1586         gboolean retval;
1587
1588         /* This is a hack, but how can this be done without
1589         * excessive cut-and-paste from gtkcontainer.c?
1590         */
1591
1592         GTK_WIDGET_UNSET_FLAGS (widget, GTK_CAN_FOCUS);
1593         retval = (* GTK_WIDGET_CLASS (parent_class)->focus) (widget, direction);
1594         GTK_WIDGET_SET_FLAGS (widget, GTK_CAN_FOCUS);
1595
1596   return retval;
1597 }
1598
1599 static gboolean gtk_xpaned_button_press (GtkWidget* widget,
1600                                                                                  GdkEventButton* event)
1601 {
1602         GtkXPaned* xpaned = GTK_XPANED (widget);
1603
1604         /* if any child is currently maximized, jump right back */
1605         if (xpaned->maximized[GTK_XPANED_TOP_LEFT]    ||
1606                 xpaned->maximized[GTK_XPANED_TOP_RIGHT]   ||
1607                 xpaned->maximized[GTK_XPANED_BOTTOM_LEFT] ||
1608                 xpaned->maximized[GTK_XPANED_BOTTOM_RIGHT])
1609                 return FALSE;
1610
1611         /* if user is dragging the handles around */
1612         if (!xpaned->in_drag_vert_and_horiz &&
1613                          event->window != xpaned->handle_east &&
1614                          event->window != xpaned->handle_west &&
1615                          event->window != xpaned->handle_north &&
1616                          event->window != xpaned->handle_south &&
1617                          event->window == xpaned->handle_middle &&
1618                          event->button == 1)
1619         {
1620                 xpaned->in_drag_vert_and_horiz = TRUE;
1621
1622                 /* We need a server grab here, not gtk_grab_add(), since
1623                 * we don't want to pass events on to the widget's children */
1624                 if (gdk_pointer_grab (xpaned->handle_middle,
1625                                                           FALSE,
1626                                                           GDK_POINTER_MOTION_HINT_MASK
1627                                                           | GDK_BUTTON1_MOTION_MASK
1628                                                           | GDK_BUTTON_RELEASE_MASK
1629                                                           | GDK_ENTER_NOTIFY_MASK
1630                                                           | GDK_LEAVE_NOTIFY_MASK,
1631                                                           NULL,
1632                                                           NULL,
1633                                                           event->time) == GDK_GRAB_SUCCESS)
1634                 {
1635                 }
1636
1637                 xpaned->drag_pos.x = event->x;
1638                 xpaned->drag_pos.y = event->y;
1639
1640                 return TRUE;
1641         }
1642         else if (!xpaned->in_drag_vert &&
1643                 event->window == xpaned->handle_east &&
1644                 event->window != xpaned->handle_west &&
1645                 event->window != xpaned->handle_north &&
1646                 event->window != xpaned->handle_south &&
1647                 event->window != xpaned->handle_middle &&
1648                 event->button == 1)
1649         {
1650                 xpaned->in_drag_vert = TRUE;
1651
1652                 /* We need a server grab here, not gtk_grab_add(), since
1653                 * we don't want to pass events on to the widget's children */
1654                 if (gdk_pointer_grab (xpaned->handle_east,
1655                                                           FALSE,
1656                                                           GDK_POINTER_MOTION_HINT_MASK
1657                                                           | GDK_BUTTON1_MOTION_MASK
1658                                                           | GDK_BUTTON_RELEASE_MASK
1659                                                           | GDK_ENTER_NOTIFY_MASK
1660                                                           | GDK_LEAVE_NOTIFY_MASK,
1661                                                           NULL,
1662                                                           NULL,
1663                                                           event->time) == GDK_GRAB_SUCCESS)
1664                 {
1665                 }
1666
1667                 xpaned->drag_pos.y = event->y;
1668
1669                 return TRUE;
1670         }
1671         else if (!xpaned->in_drag_vert &&
1672                          event->window != xpaned->handle_east &&
1673                          event->window == xpaned->handle_west &&
1674                          event->window != xpaned->handle_north &&
1675                          event->window != xpaned->handle_south &&
1676                          event->window != xpaned->handle_middle &&
1677                          event->button == 1)
1678         {
1679                 xpaned->in_drag_vert = TRUE;
1680
1681                 /* We need a server grab here, not gtk_grab_add(), since
1682                 * we don't want to pass events on to the widget's children */
1683                 if (gdk_pointer_grab (xpaned->handle_west,
1684                                                           FALSE,
1685                                                           GDK_POINTER_MOTION_HINT_MASK
1686                                                           | GDK_BUTTON1_MOTION_MASK
1687                                                           | GDK_BUTTON_RELEASE_MASK
1688                                                           | GDK_ENTER_NOTIFY_MASK
1689                                                           | GDK_LEAVE_NOTIFY_MASK,
1690                                                           NULL,
1691                                                           NULL,
1692                                                           event->time) == GDK_GRAB_SUCCESS)
1693                 {
1694                 }
1695
1696                 xpaned->drag_pos.y = event->y;
1697
1698                 return TRUE;
1699         }
1700         else if (!xpaned->in_drag_horiz &&
1701                          event->window != xpaned->handle_east &&
1702                          event->window != xpaned->handle_west &&
1703                          event->window == xpaned->handle_north &&
1704                          event->window != xpaned->handle_south &&
1705                          event->window != xpaned->handle_middle &&
1706                          event->button == 1)
1707         {
1708                 xpaned->in_drag_horiz = TRUE;
1709
1710                 /* We need a server grab here, not gtk_grab_add(), since
1711                 * we don't want to pass events on to the widget's children */
1712                 if (gdk_pointer_grab (xpaned->handle_north,
1713                                                           FALSE,
1714                                                           GDK_POINTER_MOTION_HINT_MASK
1715                                                           | GDK_BUTTON1_MOTION_MASK
1716                                                           | GDK_BUTTON_RELEASE_MASK
1717                                                           | GDK_ENTER_NOTIFY_MASK
1718                                                           | GDK_LEAVE_NOTIFY_MASK,
1719                                                           NULL,
1720                                                           NULL,
1721                                                           event->time) == GDK_GRAB_SUCCESS)
1722                 {
1723                 }
1724
1725                 xpaned->drag_pos.x = event->x;
1726
1727                 return TRUE;
1728         }
1729         else if (!xpaned->in_drag_horiz &&
1730                          event->window != xpaned->handle_east &&
1731                          event->window != xpaned->handle_west &&
1732                          event->window != xpaned->handle_north &&
1733                          event->window == xpaned->handle_south &&
1734                          event->window != xpaned->handle_middle &&
1735                          event->button == 1)
1736         {
1737                 xpaned->in_drag_horiz = TRUE;
1738
1739                 /* We need a server grab here, not gtk_grab_add(), since
1740                 * we don't want to pass events on to the widget's children */
1741                 if (gdk_pointer_grab (xpaned->handle_south,
1742                                                           FALSE,
1743                                                           GDK_POINTER_MOTION_HINT_MASK
1744                                                           | GDK_BUTTON1_MOTION_MASK
1745                                                           | GDK_BUTTON_RELEASE_MASK
1746                                                           | GDK_ENTER_NOTIFY_MASK
1747                                                           | GDK_LEAVE_NOTIFY_MASK,
1748                                                           NULL,
1749                                                           NULL,
1750                                                           event->time) == GDK_GRAB_SUCCESS)
1751                 {
1752                 }
1753
1754                 xpaned->drag_pos.x = event->x;
1755
1756                 return TRUE;
1757         }
1758         return FALSE;
1759 }
1760
1761 static gboolean gtk_xpaned_button_release (GtkWidget* widget,
1762                                                                                    GdkEventButton* event)
1763 {
1764         GtkXPaned* xpaned = GTK_XPANED (widget);
1765
1766         if (xpaned->in_drag_vert && (event->button == 1))
1767         {
1768                 xpaned->in_drag_vert = FALSE;
1769                 xpaned->drag_pos.y = -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_horiz && (event->button == 1))
1776         {
1777                 xpaned->in_drag_horiz = FALSE;
1778                 xpaned->drag_pos.x = -1;
1779                 xpaned->position_set = TRUE;
1780                 gdk_display_pointer_ungrab (gtk_widget_get_display (widget),
1781                                                                         event->time);
1782                 return TRUE;
1783     }
1784         else if (xpaned->in_drag_vert_and_horiz && (event->button == 1))
1785         {
1786                 xpaned->in_drag_vert_and_horiz = FALSE;
1787                 xpaned->drag_pos.x = -1;
1788                 xpaned->drag_pos.y = -1;
1789                 xpaned->position_set = TRUE;
1790                 gdk_display_pointer_ungrab (gtk_widget_get_display (widget),
1791                                                                         event->time);
1792                 return TRUE;
1793     }
1794
1795         return FALSE;
1796 }
1797
1798 static gboolean gtk_xpaned_motion (GtkWidget* widget, GdkEventMotion* event)
1799 {
1800         GtkXPaned* xpaned = GTK_XPANED (widget);
1801
1802         if (xpaned->in_drag_vert ||
1803                 xpaned->in_drag_horiz ||
1804                 xpaned->in_drag_vert_and_horiz)
1805
1806         {
1807                 update_drag (xpaned);
1808                 return TRUE;
1809         }
1810
1811         return FALSE;
1812 }
1813
1814 void gtk_xpaned_add_top_left (GtkXPaned* xpaned, GtkWidget *widget)
1815 {
1816         gtk_xpaned_pack_top_left (xpaned, widget, FALSE, TRUE);
1817 }
1818
1819 void gtk_xpaned_add_top_right (GtkXPaned* xpaned, GtkWidget *widget)
1820 {
1821         gtk_xpaned_pack_top_right (xpaned, widget, FALSE, TRUE);
1822 }
1823
1824 void gtk_xpaned_add_bottom_left (GtkXPaned* xpaned, GtkWidget *widget)
1825 {
1826         gtk_xpaned_pack_bottom_left (xpaned, widget, FALSE, TRUE);
1827 }
1828
1829 void gtk_xpaned_add_bottom_right (GtkXPaned* xpaned, GtkWidget *widget)
1830 {
1831         gtk_xpaned_pack_bottom_right (xpaned, widget, FALSE, TRUE);
1832 }
1833
1834 void gtk_xpaned_pack_top_left (GtkXPaned* xpaned,
1835                                                            GtkWidget* child,
1836                                                            gboolean   resize,
1837                                                            gboolean   shrink)
1838 {
1839         g_return_if_fail (GTK_IS_XPANED (xpaned));
1840         g_return_if_fail (GTK_IS_WIDGET (child));
1841
1842         if (!xpaned->top_left_child)
1843         {
1844                 xpaned->top_left_child = child;
1845                 xpaned->top_left_child_resize = resize;
1846                 xpaned->top_left_child_shrink = shrink;
1847
1848                 gtk_widget_set_parent (child, GTK_WIDGET (xpaned));
1849         }
1850 }
1851
1852 void gtk_xpaned_pack_top_right (GtkXPaned* xpaned,
1853                                                                 GtkWidget* child,
1854                                                                 gboolean   resize,
1855                                                                 gboolean   shrink)
1856 {
1857         g_return_if_fail (GTK_IS_XPANED (xpaned));
1858         g_return_if_fail (GTK_IS_WIDGET (child));
1859
1860         if (!xpaned->top_right_child)
1861         {
1862                 xpaned->top_right_child = child;
1863                 xpaned->top_right_child_resize = resize;
1864                 xpaned->top_right_child_shrink = shrink;
1865
1866                 gtk_widget_set_parent (child, GTK_WIDGET (xpaned));
1867         }
1868 }
1869
1870 void gtk_xpaned_pack_bottom_left (GtkXPaned* xpaned,
1871                                                                   GtkWidget* child,
1872                                                                   gboolean   resize,
1873                                                                   gboolean   shrink)
1874 {
1875         g_return_if_fail (GTK_IS_XPANED (xpaned));
1876         g_return_if_fail (GTK_IS_WIDGET (child));
1877
1878         if (!xpaned->bottom_left_child)
1879         {
1880                 xpaned->bottom_left_child = child;
1881                 xpaned->bottom_left_child_resize = resize;
1882                 xpaned->bottom_left_child_shrink = shrink;
1883
1884                 gtk_widget_set_parent (child, GTK_WIDGET (xpaned));
1885         }
1886 }
1887
1888 void gtk_xpaned_pack_bottom_right (GtkXPaned* xpaned,
1889                                                                    GtkWidget* child,
1890                                                                    gboolean   resize,
1891                                                                    gboolean   shrink)
1892 {
1893         g_return_if_fail (GTK_IS_XPANED (xpaned));
1894         g_return_if_fail (GTK_IS_WIDGET (child));
1895
1896         if (!xpaned->bottom_right_child)
1897         {
1898                 xpaned->bottom_right_child = child;
1899                 xpaned->bottom_right_child_resize = resize;
1900                 xpaned->bottom_right_child_shrink = shrink;
1901
1902                 gtk_widget_set_parent (child, GTK_WIDGET (xpaned));
1903         }
1904 }
1905
1906 static void gtk_xpaned_add (GtkContainer* container, GtkWidget* widget)
1907 {
1908         GtkXPaned* xpaned;
1909
1910         g_return_if_fail (GTK_IS_XPANED (container));
1911
1912         xpaned = GTK_XPANED (container);
1913
1914         if (!xpaned->top_left_child)
1915                 gtk_xpaned_add_top_left (xpaned, widget);
1916         else if (!xpaned->top_right_child)
1917                 gtk_xpaned_add_top_right (xpaned, widget);
1918         else if (!xpaned->bottom_left_child)
1919                 gtk_xpaned_add_bottom_left (xpaned, widget);
1920         else if (!xpaned->bottom_right_child)
1921                 gtk_xpaned_add_bottom_right (xpaned, widget);
1922         else
1923                 g_warning ("GtkXPaned cannot have more than 4 children\n");
1924 }
1925
1926 static void gtk_xpaned_remove (GtkContainer* container, GtkWidget* widget)
1927 {
1928         GtkXPaned* xpaned;
1929         gboolean was_visible;
1930
1931         xpaned = GTK_XPANED (container);
1932         was_visible = GTK_WIDGET_VISIBLE (widget);
1933
1934         if (xpaned->top_left_child == widget)
1935         {
1936                 gtk_widget_unparent (widget);
1937
1938                 xpaned->top_left_child = NULL;
1939
1940                 if (was_visible && GTK_WIDGET_VISIBLE (container))
1941                         gtk_widget_queue_resize (GTK_WIDGET (container));
1942         }
1943         else if (xpaned->top_right_child == widget)
1944         {
1945                 gtk_widget_unparent (widget);
1946
1947                 xpaned->top_right_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_left_child == widget)
1953         {
1954                 gtk_widget_unparent (widget);
1955
1956                 xpaned->bottom_left_child = NULL;
1957
1958                 if (was_visible && GTK_WIDGET_VISIBLE (container))
1959                         gtk_widget_queue_resize (GTK_WIDGET (container));
1960         }
1961         else if (xpaned->bottom_right_child == widget)
1962         {
1963                 gtk_widget_unparent (widget);
1964
1965                 xpaned->bottom_right_child = NULL;
1966
1967                 if (was_visible && GTK_WIDGET_VISIBLE (container))
1968                         gtk_widget_queue_resize (GTK_WIDGET (container));
1969         }
1970         else
1971                 g_warning ("GtkXPaned has no more children attached\n");
1972
1973 }
1974
1975 static void gtk_xpaned_forall (GtkContainer* container,
1976                                                            gboolean      include_internals,
1977                                                            GtkCallback   callback,
1978                                                            gpointer      callback_data)
1979 {
1980         GtkXPaned* xpaned;
1981
1982         g_return_if_fail (callback != NULL);
1983
1984         xpaned = GTK_XPANED (container);
1985
1986         if (xpaned->top_left_child)
1987         (*callback) (xpaned->top_left_child, callback_data);
1988         if (xpaned->top_right_child)
1989                 (*callback) (xpaned->top_right_child, callback_data);
1990         if (xpaned->bottom_left_child)
1991         (*callback) (xpaned->bottom_left_child, callback_data);
1992         if (xpaned->bottom_right_child)
1993                 (*callback) (xpaned->bottom_right_child, callback_data);
1994 }
1995
1996 /**
1997  * gtk_xpaned_get_position_x:
1998  * @paned: a #GtkXPaned widget
1999  * 
2000  * Obtains the x-position of the divider.
2001  * 
2002  * Return value: x-position of the divider
2003  **/
2004 gint gtk_xpaned_get_position_x (GtkXPaned* xpaned)
2005 {
2006         g_return_val_if_fail (GTK_IS_XPANED (xpaned), 0);
2007
2008         return xpaned->top_left_child_size.width;
2009 }
2010
2011 /**
2012  * gtk_xpaned_get_position_y:
2013  * @paned: a #GtkXPaned widget
2014  * 
2015  * Obtains the y-position of the divider.
2016  * 
2017  * Return value: y-position of the divider
2018  **/
2019 gint gtk_xpaned_get_position_y (GtkXPaned* xpaned)
2020 {
2021         g_return_val_if_fail (GTK_IS_XPANED (xpaned), 0);
2022
2023         return xpaned->top_left_child_size.height;
2024 }
2025
2026 /**
2027  * gtk_xpaned_set_position_x:
2028  * @paned: a #GtkXPaned widget
2029  * @xposition: pixel x-position of divider, a negative values
2030  *                         of a component mean that the position is unset.
2031  * 
2032  * Sets the x-position of the divider between the four panes.
2033  **/
2034 void gtk_xpaned_set_position_x (GtkXPaned* xpaned, gint xposition)
2035 {
2036         GObject* object;
2037   
2038         g_return_if_fail (GTK_IS_XPANED (xpaned));
2039
2040         /* if any child is currently maximized, jump right back */
2041         if (xpaned->maximized[GTK_XPANED_TOP_LEFT]    ||
2042                 xpaned->maximized[GTK_XPANED_TOP_RIGHT]   ||
2043                 xpaned->maximized[GTK_XPANED_BOTTOM_LEFT] ||
2044                 xpaned->maximized[GTK_XPANED_BOTTOM_RIGHT])
2045                 return;
2046
2047         object = G_OBJECT (xpaned);
2048
2049         if (xposition >= 0)
2050         {
2051                 /* We don't clamp here - the assumption is that
2052                 * if the total allocation changes at the same time
2053                 * as the position, the position set is with reference
2054                 * to the new total size. If only the position changes,
2055                 * then clamping will occur in gtk_paned_compute_position()
2056                 */
2057
2058                 xpaned->top_left_child_size.width = xposition;
2059                 xpaned->position_set = TRUE;
2060         }
2061         else
2062         {
2063                 xpaned->position_set = FALSE;
2064         }
2065
2066         g_object_freeze_notify (object);
2067         g_object_notify (object, "x-position");
2068         g_object_notify (object, "position-set");
2069         g_object_thaw_notify (object);
2070
2071         gtk_widget_queue_resize (GTK_WIDGET (xpaned));
2072 }
2073
2074 /**
2075  * gtk_xpaned_set_position_y:
2076  * @paned: a #GtkXPaned widget
2077  * @yposition: pixel y-position of divider, a negative values
2078  *                         of a component mean that the position is unset.
2079  * 
2080  * Sets the y-position of the divider between the four panes.
2081  **/
2082 void gtk_xpaned_set_position_y (GtkXPaned* xpaned, gint yposition)
2083 {
2084         GObject* object;
2085   
2086         g_return_if_fail (GTK_IS_XPANED (xpaned));
2087
2088         /* if any child is currently maximized, jump right back */
2089         if (xpaned->maximized[GTK_XPANED_TOP_LEFT]    ||
2090                 xpaned->maximized[GTK_XPANED_TOP_RIGHT]   ||
2091                 xpaned->maximized[GTK_XPANED_BOTTOM_LEFT] ||
2092                 xpaned->maximized[GTK_XPANED_BOTTOM_RIGHT])
2093                 return;
2094
2095         object = G_OBJECT (xpaned);
2096
2097         if (yposition >= 0)
2098         {
2099                 /* We don't clamp here - the assumption is that
2100                 * if the total allocation changes at the same time
2101                 * as the position, the position set is with reference
2102                 * to the new total size. If only the position changes,
2103                 * then clamping will occur in gtk_paned_compute_position()
2104                 */
2105
2106                 xpaned->top_left_child_size.height = yposition;
2107                 xpaned->position_set = TRUE;
2108         }
2109         else
2110         {
2111                 xpaned->position_set = FALSE;
2112         }
2113
2114         g_object_freeze_notify (object);
2115         g_object_notify (object, "y-position");
2116         g_object_notify (object, "position-set");
2117         g_object_thaw_notify (object);
2118
2119         gtk_widget_queue_resize (GTK_WIDGET (xpaned));
2120 }
2121
2122 /* this call is private and only intended for internal use! */
2123 void gtk_xpaned_save_unmaximized_x (GtkXPaned* xpaned)
2124 {
2125         xpaned->unmaximized_position.x = gtk_xpaned_get_position_x (xpaned);
2126 }
2127
2128 /* this call is private and only intended for internal use! */
2129 void gtk_xpaned_save_unmaximized_y (GtkXPaned* xpaned)
2130 {
2131         xpaned->unmaximized_position.y = gtk_xpaned_get_position_y (xpaned);
2132 }
2133
2134 /* this call is private and only intended for internal use! */
2135 gint gtk_xpaned_fetch_unmaximized_x (GtkXPaned* xpaned)
2136 {
2137         return xpaned->unmaximized_position.x;
2138 }
2139
2140 /* this call is private and only intended for internal use! */
2141 gint gtk_xpaned_fetch_unmaximized_y (GtkXPaned* xpaned)
2142 {
2143         return xpaned->unmaximized_position.y;
2144 }
2145
2146 /**
2147  * gtk_xpaned_get_top_left_child:
2148  * @xpaned: a #GtkXPaned widget
2149  * 
2150  * Obtains the top-left child of the xpaned widget.
2151  * 
2152  * Return value: top-left child, or %NULL if it is not set.
2153  *
2154  * Since: 2.4
2155  **/
2156 GtkWidget* gtk_xpaned_get_top_left_child (GtkXPaned* xpaned)
2157 {
2158         g_return_val_if_fail (GTK_IS_XPANED (xpaned), NULL);
2159
2160         return xpaned->top_left_child;
2161 }
2162
2163 /**
2164  * gtk_xpaned_get_top_right_child:
2165  * @xpaned: a #GtkXPaned widget
2166  * 
2167  * Obtains the top-right child of the xpaned widget.
2168  * 
2169  * Return value: top-right child, or %NULL if it is not set.
2170  *
2171  * Since: 2.4
2172  **/
2173 GtkWidget* gtk_xpaned_get_top_right_child (GtkXPaned* xpaned)
2174 {
2175         g_return_val_if_fail (GTK_IS_XPANED (xpaned), NULL);
2176
2177         return xpaned->top_right_child;
2178 }
2179
2180 /**
2181  * gtk_xpaned_get_bottom_left_child:
2182  * @xpaned: a #GtkXPaned widget
2183  * 
2184  * Obtains the bottom-left child of the xpaned widget.
2185  * 
2186  * Return value: bottom-left child, or %NULL if it is not set.
2187  *
2188  * Since: 2.4
2189  **/
2190 GtkWidget* gtk_xpaned_get_bottom_left_child (GtkXPaned* xpaned)
2191 {
2192         g_return_val_if_fail (GTK_IS_XPANED (xpaned), NULL);
2193
2194         return xpaned->bottom_left_child;
2195 }
2196
2197 /**
2198  * gtk_xpaned_get_bottom_right_child:
2199  * @xpaned: a #GtkXPaned widget
2200  * 
2201  * Obtains the bottom-right child of the xpaned widget.
2202  * 
2203  * Return value: bottom-right child, or %NULL if it is not set.
2204  *
2205  * Since: 2.4
2206  **/
2207 GtkWidget* gtk_xpaned_get_bottom_right_child (GtkXPaned* xpaned)
2208 {
2209         g_return_val_if_fail (GTK_IS_XPANED (xpaned), NULL);
2210
2211         return xpaned->bottom_right_child;
2212 }
2213
2214 gboolean gtk_xpaned_maximize_top_left (GtkXPaned* xpaned, gboolean maximize)
2215 {
2216         if (maximize)
2217         {
2218                 /* see if any child is already maximized */
2219                 if (!xpaned->maximized[GTK_XPANED_TOP_LEFT] &&
2220                         !xpaned->maximized[GTK_XPANED_TOP_RIGHT] &&
2221                         !xpaned->maximized[GTK_XPANED_BOTTOM_LEFT] &&
2222                         !xpaned->maximized[GTK_XPANED_BOTTOM_RIGHT])
2223                 {
2224                         /* save current position */
2225                         gtk_xpaned_save_unmaximized_x (xpaned);
2226                         gtk_xpaned_save_unmaximized_y (xpaned);
2227
2228                         /* set new maximized position */
2229                         gtk_xpaned_set_position_x (xpaned, xpaned->max_position.x);
2230                         gtk_xpaned_set_position_y (xpaned, xpaned->max_position.y);
2231
2232                         /* mark maximized flag for top-left child */
2233                         xpaned->maximized[GTK_XPANED_TOP_LEFT] = TRUE;
2234
2235                         return TRUE;
2236                 }
2237                 /* already one child maximized, report error */
2238                 else
2239                         return FALSE;
2240         }
2241         else
2242         {
2243                 /* verify that top-left child is really currently maximized */
2244                 if (xpaned->maximized[GTK_XPANED_TOP_LEFT])
2245                 {
2246                         /* clear maximized flat for top-left child */
2247                         xpaned->maximized[GTK_XPANED_TOP_LEFT] = FALSE;
2248
2249                         /* restore unmaximized position */
2250                         gtk_xpaned_set_position_x (xpaned, gtk_xpaned_fetch_unmaximized_x (xpaned));
2251                         gtk_xpaned_set_position_y (xpaned, gtk_xpaned_fetch_unmaximized_y (xpaned));
2252
2253                         return TRUE;
2254                 }
2255                 /* top-left child is currently not maximized, report error */
2256                 else
2257                         return FALSE;
2258         }
2259 }
2260
2261 gboolean gtk_xpaned_maximize_top_right (GtkXPaned* xpaned, gboolean maximize)
2262 {
2263         if (maximize)
2264         {
2265                 /* see if any child is already maximized */
2266                 if (!xpaned->maximized[GTK_XPANED_TOP_LEFT] &&
2267                         !xpaned->maximized[GTK_XPANED_TOP_RIGHT] &&
2268                         !xpaned->maximized[GTK_XPANED_BOTTOM_LEFT] &&
2269                         !xpaned->maximized[GTK_XPANED_BOTTOM_RIGHT])
2270                 {
2271                         /* save current position */
2272                         gtk_xpaned_save_unmaximized_x (xpaned);
2273                         gtk_xpaned_save_unmaximized_y (xpaned);
2274
2275                         /* set new maximized position */
2276                         gtk_xpaned_set_position_x (xpaned, xpaned->min_position.x);
2277                         gtk_xpaned_set_position_y (xpaned, xpaned->max_position.y);
2278                 
2279                         /* mark maximized flag for top-right child */
2280                         xpaned->maximized[GTK_XPANED_TOP_RIGHT] = TRUE;
2281
2282                         return TRUE;
2283                 }
2284                 /* already one child maximized, report error */
2285                 else
2286                         return FALSE;
2287         }
2288         else
2289         {
2290                 /* verify that top-right child is really currently maximized */
2291                 if (xpaned->maximized[GTK_XPANED_TOP_RIGHT])
2292                 {
2293                         /* clear maximized flat for top-right child */
2294                         xpaned->maximized[GTK_XPANED_TOP_RIGHT] = FALSE;
2295
2296                         /* restore unmaximized position */
2297                         gtk_xpaned_set_position_x (xpaned, gtk_xpaned_fetch_unmaximized_x (xpaned));
2298                         gtk_xpaned_set_position_y (xpaned, gtk_xpaned_fetch_unmaximized_y (xpaned));
2299
2300                         return TRUE;
2301                 }
2302                 /* top-right child is currently not maximized, report error */
2303                 else
2304                         return FALSE;
2305         }
2306 }
2307
2308 gboolean gtk_xpaned_maximize_bottom_left (GtkXPaned* xpaned, gboolean maximize)
2309 {
2310         if (maximize)
2311         {
2312                 /* see if any child is already maximized */
2313                 if (!xpaned->maximized[GTK_XPANED_TOP_LEFT] &&
2314                         !xpaned->maximized[GTK_XPANED_TOP_RIGHT] &&
2315                         !xpaned->maximized[GTK_XPANED_BOTTOM_LEFT] &&
2316                         !xpaned->maximized[GTK_XPANED_BOTTOM_RIGHT])
2317                 {
2318                         /* save current position */
2319                         gtk_xpaned_save_unmaximized_x (xpaned);
2320                         gtk_xpaned_save_unmaximized_y (xpaned);
2321
2322                         /* set new maximized position */
2323                         gtk_xpaned_set_position_x (xpaned, xpaned->max_position.x);
2324                         gtk_xpaned_set_position_y (xpaned, xpaned->min_position.y);
2325
2326                         /* mark maximized flag for bottom-left child */
2327                         xpaned->maximized[GTK_XPANED_BOTTOM_LEFT] = TRUE;
2328
2329                         return TRUE;
2330                 }
2331                 /* already one child maximized, report error */
2332                 else
2333                         return FALSE;
2334         }
2335         else
2336         {
2337                 /* verify that bottom-left child is really currently maximized */
2338                 if (xpaned->maximized[GTK_XPANED_BOTTOM_LEFT])
2339                 {
2340                         /* clear maximized flat for bottom-left child */
2341                         xpaned->maximized[GTK_XPANED_BOTTOM_LEFT] = FALSE;
2342
2343                         /* restore unmaximized position */
2344                         gtk_xpaned_set_position_x (xpaned, gtk_xpaned_fetch_unmaximized_x (xpaned));
2345                         gtk_xpaned_set_position_y (xpaned, gtk_xpaned_fetch_unmaximized_y (xpaned));
2346
2347                         return TRUE;
2348                 }
2349                 /* bottom-left child is currently not maximized, report error */
2350                 else
2351                         return FALSE;
2352         }
2353 }
2354
2355 gboolean gtk_xpaned_maximize_bottom_right (GtkXPaned* xpaned, gboolean maximize)
2356 {
2357         if (maximize)
2358         {
2359                 /* see if any child is already maximized */
2360                 if (!xpaned->maximized[GTK_XPANED_TOP_LEFT] &&
2361                         !xpaned->maximized[GTK_XPANED_TOP_RIGHT] &&
2362                         !xpaned->maximized[GTK_XPANED_BOTTOM_LEFT] &&
2363                         !xpaned->maximized[GTK_XPANED_BOTTOM_RIGHT])
2364                 {
2365                         /* save current position */
2366                         gtk_xpaned_save_unmaximized_x (xpaned);
2367                         gtk_xpaned_save_unmaximized_y (xpaned);
2368
2369                         /* set new maximized position */
2370                         gtk_xpaned_set_position_x (xpaned, xpaned->min_position.x);
2371                         gtk_xpaned_set_position_y (xpaned, xpaned->min_position.y);
2372
2373                         /* mark maximized flag for bottom-right child */
2374                         xpaned->maximized[GTK_XPANED_BOTTOM_RIGHT] = TRUE;
2375
2376                         return TRUE;
2377                 }
2378                 /* already one child maximized, report error */
2379                 else
2380                         return FALSE;
2381         }
2382         else
2383         {
2384                 /* verify that bottom-right child is really currently maximized */
2385                 if (xpaned->maximized[GTK_XPANED_BOTTOM_RIGHT])
2386                 {
2387                         /* clear maximized flat for bottom-right child */
2388                         xpaned->maximized[GTK_XPANED_BOTTOM_RIGHT] = FALSE;
2389
2390                         /* restore unmaximized position */
2391                         gtk_xpaned_set_position_x (xpaned, gtk_xpaned_fetch_unmaximized_x (xpaned));
2392                         gtk_xpaned_set_position_y (xpaned, gtk_xpaned_fetch_unmaximized_y (xpaned));
2393
2394                         return TRUE;
2395                 }
2396                 /* bottom-right child is currently not maximized, report error */
2397                 else
2398                         return FALSE;
2399         }
2400 }
2401
2402 void
2403 gtk_xpaned_compute_position (GtkXPaned* xpaned,
2404                              const GtkAllocation* allocation,
2405                              GtkRequisition* top_left_child_req,
2406                              GtkRequisition* top_right_child_req,
2407                              GtkRequisition* bottom_left_child_req,
2408                              GtkRequisition* bottom_right_child_req)
2409 {
2410   GdkPoint old_position;
2411   GdkPoint old_min_position;
2412         GdkPoint old_max_position;
2413         gint handle_size;
2414         gint border_width = GTK_CONTAINER (xpaned)->border_width;
2415         float fX;
2416         float fY;
2417
2418         g_return_if_fail (GTK_IS_XPANED (xpaned));
2419
2420         old_position.x = xpaned->top_left_child_size.width;
2421         old_position.y = xpaned->top_left_child_size.height;
2422         old_min_position.x = xpaned->min_position.x;
2423         old_min_position.y = xpaned->min_position.y;
2424         old_max_position.x = xpaned->max_position.x;
2425         old_max_position.y = xpaned->max_position.y;
2426
2427         fX = 100.0f * (float) old_position.x / (float) allocation->width;
2428         fY = 100.0f * (float) old_position.y / (float) allocation->height;
2429
2430         xpaned->min_position.x = xpaned->top_left_child_shrink ? 0 : top_left_child_req->width;
2431         xpaned->min_position.y = xpaned->top_left_child_shrink ? 0 : top_left_child_req->height;
2432
2433         gtk_widget_style_get (GTK_WIDGET (xpaned), "handle-size", &handle_size, NULL);
2434
2435         xpaned->max_position.x = allocation->width - 2 * border_width - handle_size;
2436         xpaned->max_position.y = allocation->height - 2 * border_width - handle_size;
2437         if (!xpaned->top_left_child_shrink)
2438                 xpaned->max_position.x = MAX (1, xpaned->max_position.x - top_left_child_req->width);
2439         xpaned->max_position.x = MAX (xpaned->min_position.x, xpaned->max_position.x);
2440
2441         if (!xpaned->position_set)
2442         {
2443                 if (xpaned->top_left_child_resize && !xpaned->top_right_child_resize)
2444                 {
2445                         xpaned->top_left_child_size.width = MAX (0, allocation->width - top_right_child_req->width);
2446                         xpaned->top_left_child_size.height = MAX (0, allocation->height - top_right_child_req->height);
2447                 }
2448                 else if (!xpaned->top_left_child_resize && xpaned->top_right_child_resize)
2449                 {
2450                         xpaned->top_left_child_size.width = top_left_child_req->width;
2451                         xpaned->top_left_child_size.height = top_left_child_req->height;
2452                 }
2453                 else if (top_left_child_req->width + top_right_child_req->width != 0)
2454                 {
2455                         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;
2456                 }
2457                 else if (top_left_child_req->height + top_right_child_req->height != 0)
2458                 {
2459                         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;
2460                 }
2461                 else
2462                 {
2463                         xpaned->top_left_child_size.width = allocation->width * 0.5 + 0.5;
2464                         xpaned->top_left_child_size.height = allocation->height * 0.5 + 0.5;
2465                 }
2466         }
2467         else
2468         {
2469                 /* If the position was set before the initial allocation.
2470                 ** (paned->last_allocation <= 0) just clamp it and leave it. */
2471                 if (xpaned->last_allocation.width > 0)
2472                 {
2473                         if (xpaned->top_left_child_resize && !xpaned->top_right_child_resize)
2474                         {
2475                                 xpaned->top_left_child_size.width += allocation->width
2476                                                                                                          - xpaned->last_allocation.width;
2477
2478                                 xpaned->top_left_child_size.height += allocation->height
2479                                                                                                           - xpaned->last_allocation.height;
2480                         }
2481                         else if (!(!xpaned->top_left_child_resize && xpaned->top_right_child_resize))
2482                         {
2483                                 xpaned->top_left_child_size.width = allocation->width
2484                                                                                                         * ((gdouble) xpaned->top_left_child_size.width / (xpaned->last_allocation.width))
2485                                                                                                         + 0.5;
2486
2487                                 xpaned->top_left_child_size.height = allocation->height
2488                                                                                                          * ((gdouble) xpaned->top_left_child_size.height / (xpaned->last_allocation.height))
2489                                                                                                          + 0.5;
2490                         }
2491                 }
2492                 if (xpaned->last_allocation.height > 0)
2493                 {
2494                         if (xpaned->top_left_child_resize && !xpaned->top_right_child_resize)
2495                         {
2496                                 xpaned->top_left_child_size.width += allocation->width - xpaned->last_allocation.width;
2497                                 xpaned->top_left_child_size.height += allocation->height - xpaned->last_allocation.height;
2498                         }
2499                         else if (!(!xpaned->top_left_child_resize && xpaned->top_right_child_resize))
2500                         {
2501                                 xpaned->top_left_child_size.width = allocation->width * ((gdouble) xpaned->top_left_child_size.width / (xpaned->last_allocation.width)) + 0.5;
2502                                 xpaned->top_left_child_size.height = allocation->height * ((gdouble) xpaned->top_left_child_size.height / (xpaned->last_allocation.height)) + 0.5;
2503                         }
2504                 }
2505
2506     }
2507
2508         xpaned->top_left_child_size.width = CLAMP (xpaned->top_left_child_size.width,
2509                                                                                            xpaned->min_position.x,
2510                                                                                            xpaned->max_position.x);
2511         xpaned->top_left_child_size.height = CLAMP (xpaned->top_left_child_size.height,
2512                                                                                                 xpaned->min_position.y,
2513                                                                                                 xpaned->max_position.y);
2514
2515         xpaned->top_right_child_size.width = CLAMP (xpaned->top_right_child_size.width,
2516                                                                                                 xpaned->min_position.x,
2517                                                                                                 xpaned->max_position.x);
2518         xpaned->top_right_child_size.height = CLAMP (xpaned->top_right_child_size.height,
2519                                                                                                  xpaned->min_position.y,
2520                                                                                                  xpaned->max_position.y);
2521
2522         xpaned->bottom_left_child_size.width = CLAMP (xpaned->bottom_left_child_size.width,
2523                                                                                                   xpaned->min_position.x,
2524                                                                                                   xpaned->max_position.x);
2525         xpaned->bottom_left_child_size.height = CLAMP (xpaned->bottom_left_child_size.height,
2526                                                                                                    xpaned->min_position.y,
2527                                                                                                    xpaned->max_position.y);
2528
2529         xpaned->bottom_right_child_size.width = CLAMP (xpaned->bottom_right_child_size.width,
2530                                                                                                    xpaned->min_position.x,
2531                                                                                                    xpaned->max_position.x);
2532         xpaned->bottom_right_child_size.height = CLAMP (xpaned->bottom_right_child_size.height,
2533                                                                                                         xpaned->min_position.y,
2534                                                                                                         xpaned->max_position.y);
2535
2536         gtk_widget_set_child_visible (xpaned->top_left_child, TRUE);
2537         gtk_widget_set_child_visible (xpaned->top_right_child, TRUE);
2538         gtk_widget_set_child_visible (xpaned->bottom_left_child, TRUE);
2539         gtk_widget_set_child_visible (xpaned->bottom_right_child, TRUE);
2540
2541         g_object_freeze_notify (G_OBJECT (xpaned));
2542
2543         if (xpaned->top_left_child_size.width != old_position.x)
2544                 g_object_notify (G_OBJECT (xpaned), "x-position");
2545         if (xpaned->top_left_child_size.height != old_position.y)
2546                 g_object_notify (G_OBJECT (xpaned), "y-position");
2547
2548         if (xpaned->top_right_child_size.width != old_position.x)
2549                 g_object_notify (G_OBJECT (xpaned), "x-position");
2550         if (xpaned->top_right_child_size.height != old_position.y)
2551                 g_object_notify (G_OBJECT (xpaned), "y-position");
2552
2553         if (xpaned->bottom_left_child_size.width != old_position.x)
2554                 g_object_notify (G_OBJECT (xpaned), "x-position");
2555         if (xpaned->bottom_left_child_size.height != old_position.y)
2556                 g_object_notify (G_OBJECT (xpaned), "y-position");
2557
2558         if (xpaned->bottom_right_child_size.width != old_position.x)
2559                 g_object_notify (G_OBJECT (xpaned), "x-position");
2560         if (xpaned->bottom_right_child_size.height != old_position.y)
2561                 g_object_notify (G_OBJECT (xpaned), "y-position");
2562
2563         if (xpaned->min_position.x != old_min_position.x)
2564                 g_object_notify (G_OBJECT (xpaned), "min-x-position");
2565         if (xpaned->min_position.y != old_min_position.y)
2566                 g_object_notify (G_OBJECT (xpaned), "min-y-position");
2567
2568         if (xpaned->max_position.x != old_max_position.x)
2569         g_object_notify (G_OBJECT (xpaned), "max-y-position");
2570         if (xpaned->max_position.y != old_max_position.y)
2571         g_object_notify (G_OBJECT (xpaned), "max-y-position");
2572
2573         g_object_thaw_notify (G_OBJECT (xpaned));
2574
2575         xpaned->last_allocation.width = allocation->width;
2576         xpaned->last_allocation.height = allocation->height;
2577
2578         fX = 100.0f * (float) old_position.x / (float) allocation->width;
2579         fY = 100.0f * (float) old_position.y / (float) allocation->height;
2580 }
2581
2582 static void gtk_xpaned_set_saved_focus (GtkXPaned* xpaned, GtkWidget* widget)
2583 {
2584         if (xpaned->priv->saved_focus)
2585                 g_object_remove_weak_pointer (G_OBJECT (xpaned->priv->saved_focus),
2586                                                                           (gpointer *)&(xpaned->priv->saved_focus));
2587
2588         xpaned->priv->saved_focus = widget;
2589
2590         if (xpaned->priv->saved_focus)
2591                 g_object_add_weak_pointer (G_OBJECT (xpaned->priv->saved_focus),
2592                                                                    (gpointer *)&(xpaned->priv->saved_focus));
2593 }
2594
2595 static void gtk_xpaned_set_first_xpaned (GtkXPaned* xpaned,
2596                                                                                  GtkXPaned* first_xpaned)
2597 {
2598         if (xpaned->priv->first_xpaned)
2599                 g_object_remove_weak_pointer (G_OBJECT (xpaned->priv->first_xpaned),
2600                                                                           (gpointer *)&(xpaned->priv->first_xpaned));
2601
2602         xpaned->priv->first_xpaned = first_xpaned;
2603
2604         if (xpaned->priv->first_xpaned)
2605                 g_object_add_weak_pointer (G_OBJECT (xpaned->priv->first_xpaned),
2606                                                                    (gpointer *)&(xpaned->priv->first_xpaned));
2607 }
2608
2609 static void gtk_xpaned_set_last_top_left_child_focus (GtkXPaned* xpaned,
2610                                                                                                           GtkWidget* widget)
2611 {
2612         if (xpaned->last_top_left_child_focus)
2613                 g_object_remove_weak_pointer (G_OBJECT (xpaned->last_top_left_child_focus),
2614                                                                           (gpointer *)&(xpaned->last_top_left_child_focus));
2615
2616         xpaned->last_top_left_child_focus = widget;
2617
2618         if (xpaned->last_top_left_child_focus)
2619                 g_object_add_weak_pointer (G_OBJECT (xpaned->last_top_left_child_focus),
2620                                                                    (gpointer *)&(xpaned->last_top_left_child_focus));
2621 }
2622
2623 static void gtk_xpaned_set_last_top_right_child_focus (GtkXPaned* xpaned,
2624                                                                                                            GtkWidget *widget)
2625 {
2626         if (xpaned->last_top_right_child_focus)
2627                 g_object_remove_weak_pointer (G_OBJECT (xpaned->last_top_right_child_focus),
2628                                                                           (gpointer *)&(xpaned->last_top_right_child_focus));
2629
2630         xpaned->last_top_right_child_focus = widget;
2631
2632         if (xpaned->last_top_right_child_focus)
2633                 g_object_add_weak_pointer (G_OBJECT (xpaned->last_top_right_child_focus),
2634                                                                    (gpointer *)&(xpaned->last_top_right_child_focus));
2635 }
2636
2637 static void gtk_xpaned_set_last_bottom_left_child_focus (GtkXPaned* xpaned,
2638                                                                                                                  GtkWidget *widget)
2639 {
2640         if (xpaned->last_bottom_left_child_focus)
2641                 g_object_remove_weak_pointer (G_OBJECT (xpaned->last_bottom_left_child_focus),
2642                                                                           (gpointer *)&(xpaned->last_bottom_left_child_focus));
2643
2644         xpaned->last_bottom_left_child_focus = widget;
2645
2646         if (xpaned->last_bottom_left_child_focus)
2647                 g_object_add_weak_pointer (G_OBJECT (xpaned->last_bottom_left_child_focus),
2648                                                                    (gpointer *)&(xpaned->last_bottom_left_child_focus));
2649 }
2650
2651 static void gtk_xpaned_set_last_bottom_right_child_focus (GtkXPaned* xpaned,
2652                                                                                                                  GtkWidget *widget)
2653 {
2654         if (xpaned->last_bottom_right_child_focus)
2655                 g_object_remove_weak_pointer (G_OBJECT (xpaned->last_bottom_right_child_focus),
2656                                                                           (gpointer *)&(xpaned->last_bottom_right_child_focus));
2657
2658         xpaned->last_bottom_right_child_focus = widget;
2659
2660         if (xpaned->last_bottom_right_child_focus)
2661                 g_object_add_weak_pointer (G_OBJECT (xpaned->last_bottom_right_child_focus),
2662                                                                    (gpointer *)&(xpaned->last_bottom_right_child_focus));
2663 }
2664
2665 static GtkWidget* xpaned_get_focus_widget (GtkXPaned* xpaned)
2666 {
2667         GtkWidget* toplevel;
2668
2669         toplevel = gtk_widget_get_toplevel (GTK_WIDGET (xpaned));
2670         if (GTK_WIDGET_TOPLEVEL (toplevel))
2671                 return GTK_WINDOW (toplevel)->focus_widget;
2672
2673         return NULL;
2674 }
2675
2676 static void gtk_xpaned_set_focus_child (GtkContainer* container,
2677                                                                                 GtkWidget* focus_child)
2678 {
2679         GtkXPaned* xpaned;
2680
2681         g_return_if_fail (GTK_IS_XPANED (container));
2682
2683         xpaned = GTK_XPANED (container);
2684
2685         if (focus_child == NULL)
2686         {
2687                 GtkWidget* last_focus;
2688                 GtkWidget* w;
2689
2690                 last_focus = xpaned_get_focus_widget (xpaned);
2691
2692                 if (last_focus)
2693                 {
2694                         /* If there is one or more paned widgets between us and the
2695                         * focus widget, we want the topmost of those as last_focus
2696                         */
2697                         for (w = last_focus; w != GTK_WIDGET (xpaned); w = w->parent)
2698                                 if (GTK_IS_XPANED (w))
2699                                         last_focus = w;
2700
2701                         if (container->focus_child == xpaned->top_left_child)
2702                                 gtk_xpaned_set_last_top_left_child_focus (xpaned, last_focus);
2703                         else if (container->focus_child == xpaned->top_right_child)
2704                                 gtk_xpaned_set_last_top_right_child_focus (xpaned, last_focus);
2705                         else if (container->focus_child == xpaned->bottom_left_child)
2706                                 gtk_xpaned_set_last_bottom_left_child_focus (xpaned, last_focus);
2707                         else if (container->focus_child == xpaned->bottom_right_child)
2708                                 gtk_xpaned_set_last_bottom_right_child_focus (xpaned, last_focus);
2709                 }
2710         }
2711
2712         if (parent_class->set_focus_child)
2713                 (* parent_class->set_focus_child) (container, focus_child);
2714 }
2715
2716 static void gtk_xpaned_get_cycle_chain (GtkXPaned* xpaned,
2717                                                                                 GtkDirectionType direction,
2718                                                                                 GList** widgets)
2719 {
2720         GtkContainer* container = GTK_CONTAINER (xpaned);
2721         GtkWidget* ancestor = NULL;
2722         GList* temp_list = NULL;
2723         GList* list;
2724
2725         if (xpaned->in_recursion)
2726                 return;
2727
2728         g_assert (widgets != NULL);
2729
2730         if (xpaned->last_top_left_child_focus &&
2731                 !gtk_widget_is_ancestor (xpaned->last_top_left_child_focus,
2732                                                                  GTK_WIDGET (xpaned)))
2733         {
2734                 gtk_xpaned_set_last_top_left_child_focus (xpaned, NULL);
2735         }
2736
2737         if (xpaned->last_top_right_child_focus &&
2738                 !gtk_widget_is_ancestor (xpaned->last_top_right_child_focus,
2739                                                                  GTK_WIDGET (xpaned)))
2740         {
2741                 gtk_xpaned_set_last_top_right_child_focus (xpaned, NULL);
2742         }
2743
2744         if (xpaned->last_bottom_left_child_focus &&
2745                 !gtk_widget_is_ancestor (xpaned->last_bottom_left_child_focus,
2746                                                                  GTK_WIDGET (xpaned)))
2747         {
2748                 gtk_xpaned_set_last_bottom_left_child_focus (xpaned, NULL);
2749         }
2750
2751         if (xpaned->last_bottom_right_child_focus &&
2752                 !gtk_widget_is_ancestor (xpaned->last_bottom_right_child_focus,
2753                                                                  GTK_WIDGET (xpaned)))
2754         {
2755                 gtk_xpaned_set_last_bottom_right_child_focus (xpaned, NULL);
2756         }
2757
2758         if (GTK_WIDGET (xpaned)->parent)
2759                 ancestor = gtk_widget_get_ancestor (GTK_WIDGET (xpaned)->parent,
2760                                                                                         GTK_TYPE_XPANED);
2761
2762         /* The idea here is that temp_list is a list of widgets we want to cycle
2763         * to. The list is prioritized so that the first element is our first
2764         * choice, the next our second, and so on.
2765         *
2766         * We can't just use g_list_reverse(), because we want to try
2767         * paned->last_child?_focus before paned->child?, both when we
2768         * are going forward and backward.
2769         */
2770         if (direction == GTK_DIR_TAB_FORWARD)
2771         {
2772                 if (container->focus_child == xpaned->top_left_child)
2773                 {
2774                         temp_list = g_list_append (temp_list, xpaned->last_top_right_child_focus);
2775                         temp_list = g_list_append (temp_list, xpaned->top_right_child);
2776                         temp_list = g_list_append (temp_list, ancestor);
2777                 }
2778                 else if (container->focus_child == xpaned->top_right_child)
2779                 {
2780                         temp_list = g_list_append (temp_list, ancestor);
2781                         temp_list = g_list_append (temp_list, xpaned->last_bottom_left_child_focus);
2782                         temp_list = g_list_append (temp_list, xpaned->bottom_left_child);
2783                 }
2784                 else if (container->focus_child == xpaned->bottom_left_child)
2785                 {
2786                         temp_list = g_list_append (temp_list, ancestor);
2787                         temp_list = g_list_append (temp_list, xpaned->last_bottom_right_child_focus);
2788                         temp_list = g_list_append (temp_list, xpaned->bottom_right_child);
2789                 }
2790                 else if (container->focus_child == xpaned->bottom_right_child)
2791                 {
2792                         temp_list = g_list_append (temp_list, ancestor);
2793                         temp_list = g_list_append (temp_list, xpaned->last_top_left_child_focus);
2794                         temp_list = g_list_append (temp_list, xpaned->top_left_child);
2795                 }
2796                 else
2797                 {
2798                         temp_list = g_list_append (temp_list, xpaned->last_top_left_child_focus);
2799                         temp_list = g_list_append (temp_list, xpaned->top_left_child);
2800                         temp_list = g_list_append (temp_list, xpaned->last_top_right_child_focus);
2801                         temp_list = g_list_append (temp_list, xpaned->top_right_child);
2802                         temp_list = g_list_append (temp_list, xpaned->last_bottom_left_child_focus);
2803                         temp_list = g_list_append (temp_list, xpaned->bottom_left_child);
2804                         temp_list = g_list_append (temp_list, xpaned->last_bottom_right_child_focus);
2805                         temp_list = g_list_append (temp_list, xpaned->bottom_right_child);
2806                         temp_list = g_list_append (temp_list, ancestor);
2807                 }
2808         }
2809         else
2810         {
2811                 if (container->focus_child == xpaned->top_left_child)
2812                 {
2813                         temp_list = g_list_append (temp_list, ancestor);
2814                         temp_list = g_list_append (temp_list, xpaned->last_top_right_child_focus);
2815                         temp_list = g_list_append (temp_list, xpaned->top_right_child);
2816                 }
2817                 else if (container->focus_child == xpaned->top_right_child)
2818                 {
2819                         temp_list = g_list_append (temp_list, xpaned->last_bottom_left_child_focus);
2820                         temp_list = g_list_append (temp_list, xpaned->bottom_left_child);
2821                         temp_list = g_list_append (temp_list, ancestor);
2822                 }
2823                 else if (container->focus_child == xpaned->bottom_right_child)
2824                 {
2825                         temp_list = g_list_append (temp_list, xpaned->last_bottom_left_child_focus);
2826                         temp_list = g_list_append (temp_list, xpaned->bottom_left_child);
2827                         temp_list = g_list_append (temp_list, ancestor);
2828                 }
2829                 else if (container->focus_child == xpaned->top_right_child)
2830                 {
2831                         temp_list = g_list_append (temp_list, xpaned->last_bottom_left_child_focus);
2832                         temp_list = g_list_append (temp_list, xpaned->bottom_left_child);
2833                         temp_list = g_list_append (temp_list, ancestor);
2834                 }
2835                 else
2836                 {
2837                         temp_list = g_list_append (temp_list, xpaned->last_bottom_right_child_focus);
2838                         temp_list = g_list_append (temp_list, xpaned->bottom_right_child);
2839                         temp_list = g_list_append (temp_list, xpaned->last_bottom_left_child_focus);
2840                         temp_list = g_list_append (temp_list, xpaned->bottom_left_child);
2841                         temp_list = g_list_append (temp_list, xpaned->last_top_right_child_focus);
2842                         temp_list = g_list_append (temp_list, xpaned->top_right_child);
2843                         temp_list = g_list_append (temp_list, xpaned->last_top_left_child_focus);
2844                         temp_list = g_list_append (temp_list, xpaned->top_left_child);
2845                         temp_list = g_list_append (temp_list, ancestor);
2846                 }
2847         }
2848
2849         /* Walk the list and expand all the paned widgets. */
2850         for (list = temp_list; list != NULL; list = list->next)
2851         {
2852                 GtkWidget *widget = list->data;
2853
2854                 if (widget)
2855                 {
2856                         if (GTK_IS_XPANED (widget))
2857                         {
2858                                 xpaned->in_recursion = TRUE;
2859                                 gtk_xpaned_get_cycle_chain (GTK_XPANED (widget),
2860                                                                                         direction,
2861                                                                                         widgets);
2862                                 xpaned->in_recursion = FALSE;
2863                         }
2864                         else
2865                         {
2866                                 *widgets = g_list_append (*widgets, widget);
2867                         }
2868                 }
2869         }
2870
2871         g_list_free (temp_list);
2872 }
2873
2874 static gboolean gtk_xpaned_cycle_child_focus (GtkXPaned* xpaned,
2875                                                                                           gboolean reversed)
2876 {
2877         GList* cycle_chain = NULL;
2878         GList* list;
2879
2880         GtkDirectionType direction = reversed ? GTK_DIR_TAB_BACKWARD : GTK_DIR_TAB_FORWARD;
2881
2882         /* ignore f6 if the handle is focused */
2883         if (gtk_widget_is_focus (GTK_WIDGET (xpaned)))
2884                 return TRUE;
2885
2886         /* we can't just let the event propagate up the hierarchy,
2887         * because the paned will want to cycle focus _unless_ an
2888         * ancestor paned handles the event
2889         */
2890         gtk_xpaned_get_cycle_chain (xpaned, direction, &cycle_chain);
2891
2892         for (list = cycle_chain; list != NULL; list = list->next)
2893                 if (gtk_widget_child_focus (GTK_WIDGET (list->data), direction))
2894                         break;
2895
2896         g_list_free (cycle_chain);
2897
2898         return TRUE;
2899 }
2900
2901 static void get_child_xpanes (GtkWidget* widget, GList** xpanes)
2902 {
2903         if (GTK_IS_XPANED (widget))
2904         {
2905                 GtkXPaned* xpaned = GTK_XPANED (widget);
2906
2907                 get_child_xpanes (xpaned->top_left_child, xpanes);
2908                 *xpanes = g_list_prepend (*xpanes, widget);
2909                 get_child_xpanes (xpaned->top_right_child, xpanes);
2910                 *xpanes = g_list_prepend (*xpanes, widget);
2911                 get_child_xpanes (xpaned->bottom_left_child, xpanes);
2912                 *xpanes = g_list_prepend (*xpanes, widget);
2913                 get_child_xpanes (xpaned->bottom_right_child, xpanes);
2914         }
2915         else if (GTK_IS_CONTAINER (widget))
2916         {
2917                 gtk_container_foreach (GTK_CONTAINER (widget),
2918                                                            (GtkCallback)get_child_xpanes,
2919                                                            xpanes);
2920         }
2921 }
2922
2923 static GList* get_all_xpanes (GtkXPaned* xpaned)
2924 {
2925         GtkXPaned* topmost = NULL;
2926         GList* result = NULL;
2927         GtkWidget* w;
2928   
2929         for (w = GTK_WIDGET (xpaned); w != NULL; w = w->parent)
2930         {
2931                 if (GTK_IS_XPANED (w))
2932                         topmost = GTK_XPANED (w);
2933         }
2934
2935         g_assert (topmost);
2936
2937         get_child_xpanes (GTK_WIDGET (topmost), &result);
2938
2939         return g_list_reverse (result);
2940 }
2941
2942 static void gtk_xpaned_find_neighbours (GtkXPaned* xpaned,
2943                                                                                 GtkXPaned** next,
2944                                                                                 GtkXPaned** prev)
2945 {
2946         GList* all_xpanes;
2947         GList* this_link;
2948
2949         all_xpanes = get_all_xpanes (xpaned);
2950         g_assert (all_xpanes);
2951
2952         this_link = g_list_find (all_xpanes, xpaned);
2953
2954         g_assert (this_link);
2955
2956         if (this_link->next)
2957                 *next = this_link->next->data;
2958         else
2959                 *next = all_xpanes->data;
2960
2961         if (this_link->prev)
2962                 *prev = this_link->prev->data;
2963         else
2964                 *prev = g_list_last (all_xpanes)->data;
2965
2966         g_list_free (all_xpanes);
2967 }
2968
2969 static gboolean gtk_xpaned_move_handle (GtkXPaned* xpaned, GtkScrollType scroll)
2970 {
2971         if (gtk_widget_is_focus (GTK_WIDGET (xpaned)))
2972         {
2973                 GdkPoint old_position;
2974                 GdkPoint new_position;
2975                 gint increment;
2976
2977                 enum
2978                 {
2979                         SINGLE_STEP_SIZE = 1,
2980                         PAGE_STEP_SIZE   = 75
2981                 };
2982
2983                 new_position.x = old_position.x = gtk_xpaned_get_position_x (xpaned);
2984                 new_position.y = old_position.y = gtk_xpaned_get_position_y (xpaned);
2985                 increment = 0;
2986
2987                 switch (scroll)
2988                 {
2989                         case GTK_SCROLL_STEP_LEFT:
2990                         case GTK_SCROLL_STEP_UP:
2991                         case GTK_SCROLL_STEP_BACKWARD:
2992                                 increment = - SINGLE_STEP_SIZE;
2993                         break;
2994
2995                         case GTK_SCROLL_STEP_RIGHT:
2996                         case GTK_SCROLL_STEP_DOWN:
2997                         case GTK_SCROLL_STEP_FORWARD:
2998                                 increment = SINGLE_STEP_SIZE;
2999                         break;
3000
3001                         case GTK_SCROLL_PAGE_LEFT:
3002                         case GTK_SCROLL_PAGE_UP:
3003                         case GTK_SCROLL_PAGE_BACKWARD:
3004                                 increment = - PAGE_STEP_SIZE;
3005                         break;
3006
3007                         case GTK_SCROLL_PAGE_RIGHT:
3008                         case GTK_SCROLL_PAGE_DOWN:
3009                         case GTK_SCROLL_PAGE_FORWARD:
3010                                 increment = PAGE_STEP_SIZE;
3011                         break;
3012
3013                         case GTK_SCROLL_START:
3014                                 new_position.x = xpaned->min_position.x;
3015                                 new_position.y = xpaned->min_position.y;
3016                         break;
3017
3018                         case GTK_SCROLL_END:
3019                                 new_position.x = xpaned->max_position.x;
3020                                 new_position.y = xpaned->max_position.y;
3021                         break;
3022
3023                         default:
3024                         break;
3025                 }
3026
3027                 if (increment)
3028                 {
3029                         if (is_rtl (xpaned))
3030                                 increment = -increment;
3031
3032                         new_position.x = old_position.x + increment;
3033                         new_position.y = old_position.y + increment;
3034                 }
3035
3036                 new_position.x = CLAMP (new_position.x,
3037                                                                 xpaned->min_position.x,
3038                                                                 xpaned->max_position.x);
3039
3040                 new_position.y = CLAMP (new_position.y,
3041                                                                 xpaned->min_position.y,
3042                                                                 xpaned->max_position.y);
3043
3044                 if (old_position.x != new_position.x)
3045                         gtk_xpaned_set_position_x (xpaned, new_position.x);
3046
3047                 if (old_position.y != new_position.y)
3048                         gtk_xpaned_set_position_y (xpaned, new_position.y);
3049
3050                 return TRUE;
3051         }
3052
3053         return FALSE;
3054 }
3055
3056 static void gtk_xpaned_restore_focus (GtkXPaned* xpaned)
3057 {
3058         if (gtk_widget_is_focus (GTK_WIDGET (xpaned)))
3059         {
3060                 if (xpaned->priv->saved_focus &&
3061                         GTK_WIDGET_SENSITIVE (xpaned->priv->saved_focus))
3062                 {
3063                         gtk_widget_grab_focus (xpaned->priv->saved_focus);
3064                 }
3065                 else
3066                 {
3067                         /* the saved focus is somehow not available for focusing,
3068                         * try
3069                         *   1) tabbing into the paned widget
3070                         * if that didn't work,
3071                         *   2) unset focus for the window if there is one
3072                         */
3073
3074                         if (!gtk_widget_child_focus (GTK_WIDGET (xpaned), GTK_DIR_TAB_FORWARD))
3075                         {
3076                                 GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (xpaned));
3077               
3078                                 if (GTK_IS_WINDOW (toplevel))
3079                                         gtk_window_set_focus (GTK_WINDOW (toplevel), NULL);
3080                         }
3081                 }
3082                 
3083                 gtk_xpaned_set_saved_focus (xpaned, NULL);
3084                 gtk_xpaned_set_first_xpaned (xpaned, NULL);
3085     }
3086 }
3087
3088 static gboolean gtk_xpaned_accept_position (GtkXPaned* xpaned)
3089 {
3090         if (gtk_widget_is_focus (GTK_WIDGET (xpaned)))
3091         {
3092                 xpaned->original_position.x = -1;
3093                 xpaned->original_position.y = -1;
3094                 gtk_xpaned_restore_focus (xpaned);
3095
3096                 return TRUE;
3097         }
3098
3099         return FALSE;
3100 }
3101
3102 static gboolean gtk_xpaned_cancel_position (GtkXPaned* xpaned)
3103 {
3104         if (gtk_widget_is_focus (GTK_WIDGET (xpaned)))
3105         {
3106                 if (xpaned->original_position.x != -1)
3107                 {
3108                         gtk_xpaned_set_position_x (xpaned, xpaned->original_position.x);
3109                         xpaned->original_position.x = -1;
3110                 }
3111
3112                 if (xpaned->original_position.y != -1)
3113                 {
3114                         gtk_xpaned_set_position_y (xpaned, xpaned->original_position.y);
3115                         xpaned->original_position.y = -1;
3116                 }
3117
3118                 gtk_xpaned_restore_focus (xpaned);
3119                 return TRUE;
3120         }
3121
3122         return FALSE;
3123 }
3124
3125 static gboolean gtk_xpaned_cycle_handle_focus (GtkXPaned* xpaned,
3126                                                                                            gboolean reversed)
3127 {
3128         GtkXPaned* next;
3129         GtkXPaned* prev;
3130
3131         if (gtk_widget_is_focus (GTK_WIDGET (xpaned)))
3132         {
3133                 GtkXPaned* focus = NULL;
3134
3135                 if (!xpaned->priv->first_xpaned)
3136                 {
3137                         /* The first_pane has disappeared. As an ad-hoc solution,
3138                         * we make the currently focused paned the first_paned. To the
3139                         * user this will seem like the paned cycling has been reset.
3140                         */
3141                         gtk_xpaned_set_first_xpaned (xpaned, xpaned);
3142                 }
3143
3144                 gtk_xpaned_find_neighbours (xpaned, &next, &prev);
3145
3146                 if (reversed && prev &&
3147                         prev != xpaned && xpaned != xpaned->priv->first_xpaned)
3148                 {
3149                         focus = prev;
3150                 }
3151                 else if (!reversed &&
3152                                  next &&
3153                                  next != xpaned &&
3154                                  next != xpaned->priv->first_xpaned)
3155                 {
3156                         focus = next;
3157                 }
3158                 else
3159                 {
3160                         gtk_xpaned_accept_position (xpaned);
3161                         return TRUE;
3162                 }
3163
3164                 g_assert (focus);
3165       
3166                 gtk_xpaned_set_saved_focus (focus, xpaned->priv->saved_focus);
3167                 gtk_xpaned_set_first_xpaned (focus, xpaned->priv->first_xpaned);
3168       
3169                 gtk_xpaned_set_saved_focus (xpaned, NULL);
3170                 gtk_xpaned_set_first_xpaned (xpaned, NULL);
3171       
3172                 gtk_widget_grab_focus (GTK_WIDGET (focus));
3173       
3174                 if (!gtk_widget_is_focus (GTK_WIDGET (xpaned)))
3175                 {
3176                         xpaned->original_position.x = -1;
3177                         xpaned->original_position.y = -1;
3178                         focus->original_position.x = gtk_xpaned_get_position_x (focus);
3179                         focus->original_position.y = gtk_xpaned_get_position_y (focus);
3180                 }
3181         }
3182         else
3183     {
3184                 GtkContainer* container = GTK_CONTAINER (xpaned);
3185                 GtkXPaned* focus;
3186                 GtkXPaned* first;
3187                 GtkXPaned* prev;
3188                 GtkXPaned* next;
3189                 GtkWidget* toplevel;
3190
3191                 gtk_xpaned_find_neighbours (xpaned, &next, &prev);
3192
3193                 if (container->focus_child == xpaned->top_left_child)
3194                 {
3195                         if (reversed)
3196                         {
3197                                 focus = prev;
3198                                 first = xpaned;
3199                         }
3200                         else
3201                         {
3202                                 focus = xpaned;
3203                                 first = xpaned;
3204                         }
3205                 }
3206                 else if (container->focus_child == xpaned->top_right_child)
3207                 {
3208                         if (reversed)
3209                         {
3210                                 focus = xpaned;
3211                                 first = next;
3212                         }
3213                         else
3214                         {
3215                                 focus = next;
3216                                 first = next;
3217                         }
3218                 }
3219                 else
3220                 {
3221                         /* Focus is not inside this xpaned, and we don't have focus.
3222                         * Presumably this happened because the application wants us
3223                         * to start keyboard navigating.
3224                         */
3225                         focus = xpaned;
3226
3227                         if (reversed)
3228                                 first = xpaned;
3229                         else
3230                                 first = next;
3231                 }
3232
3233                 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (xpaned));
3234
3235                 if (GTK_IS_WINDOW (toplevel))
3236                         gtk_xpaned_set_saved_focus (focus, GTK_WINDOW (toplevel)->focus_widget);
3237                 gtk_xpaned_set_first_xpaned (focus, first);
3238                 focus->original_position.x = gtk_xpaned_get_position_x (focus);
3239                 focus->original_position.y = gtk_xpaned_get_position_y (focus); 
3240
3241                 gtk_widget_grab_focus (GTK_WIDGET (focus));
3242         }
3243
3244         return TRUE;
3245 }
3246
3247 static gboolean gtk_xpaned_toggle_handle_focus (GtkXPaned* xpaned)
3248 {
3249         /* This function/signal has the wrong name. It is called when you
3250         * press Tab or Shift-Tab and what we do is act as if
3251         * the user pressed Return and then Tab or Shift-Tab
3252         */
3253         if (gtk_widget_is_focus (GTK_WIDGET (xpaned)))
3254                 gtk_xpaned_accept_position (xpaned);
3255
3256   return FALSE;
3257 }
3258
3259 /*#define __GTK_XPANED_C__*/
3260 /*#include "gtkaliasdef.c"*/