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