]> Pileus Git - ~andy/gtk/blob - gtk/gtkhandlebox.c
Remove an accidentally added include.
[~andy/gtk] / gtk / gtkhandlebox.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  * Copyright (C) 1998 Elliot Lee
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20
21 /*
22  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
23  * file for a list of people on the GTK+ Team.  See the ChangeLog
24  * files for a list of changes.  These files are distributed with
25  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
26  */
27
28 #include <config.h>
29 #include <stdlib.h>
30 #include "gtkhandlebox.h"
31 #include "gtkinvisible.h"
32 #include "gtkmain.h"
33 #include "gtkmarshalers.h"
34 #include "gtkwindow.h"
35 #include "gtkintl.h"
36
37 typedef struct _GtkHandleBoxPrivate GtkHandleBoxPrivate;
38
39 struct _GtkHandleBoxPrivate
40 {
41   gint orig_x;
42   gint orig_y;
43 };
44
45 enum {
46   PROP_0,
47   PROP_SHADOW,
48   PROP_SHADOW_TYPE,
49   PROP_HANDLE_POSITION,
50   PROP_SNAP_EDGE,
51   PROP_SNAP_EDGE_SET
52 };
53
54 #define DRAG_HANDLE_SIZE 10
55 #define CHILDLESS_SIZE  25
56 #define GHOST_HEIGHT 3
57 #define TOLERANCE 5
58
59 enum {
60   SIGNAL_CHILD_ATTACHED,
61   SIGNAL_CHILD_DETACHED,
62   SIGNAL_LAST
63 };
64
65 /* The algorithm for docking and redocking implemented here
66  * has a couple of nice properties:
67  *
68  * 1) During a single drag, docking always occurs at the
69  *    the same cursor position. This means that the users
70  *    motions are reversible, and that you won't
71  *    undock/dock oscillations.
72  *
73  * 2) Docking generally occurs at user-visible features.
74  *    The user, once they figure out to redock, will
75  *    have useful information about doing it again in
76  *    the future.
77  *
78  * Please try to preserve these properties if you
79  * change the algorithm. (And the current algorithm
80  * is far from ideal). Briefly, the current algorithm
81  * for deciding whether the handlebox is docked or not:
82  *
83  * 1) The decision is done by comparing two rectangles - the
84  *    allocation if the widget at the start of the drag,
85  *    and the boundary of hb->bin_window at the start of
86  *    of the drag offset by the distance that the cursor
87  *    has moved.
88  *
89  * 2) These rectangles must have one edge, the "snap_edge"
90  *    of the handlebox, aligned within TOLERANCE.
91  * 
92  * 3) On the other dimension, the extents of one rectangle
93  *    must be contained in the extents of the other,
94  *    extended by tolerance. That is, either we can have:
95  *
96  * <-TOLERANCE-|--------bin_window--------------|-TOLERANCE->
97  *         <--------float_window-------------------->
98  *
99  * or we can have:
100  *
101  * <-TOLERANCE-|------float_window--------------|-TOLERANCE->
102  *          <--------bin_window-------------------->
103  */
104
105 static void gtk_handle_box_class_init     (GtkHandleBoxClass *klass);
106 static void gtk_handle_box_init           (GtkHandleBox      *handle_box);
107 static void gtk_handle_box_set_property   (GObject      *object,
108                                            guint         param_id,
109                                            const GValue *value,
110                                            GParamSpec   *pspec);
111 static void gtk_handle_box_get_property   (GObject     *object,
112                                            guint        param_id,
113                                            GValue      *value,
114                                            GParamSpec  *pspec);
115 static void gtk_handle_box_destroy        (GtkObject         *object);
116 static void gtk_handle_box_map            (GtkWidget         *widget);
117 static void gtk_handle_box_unmap          (GtkWidget         *widget);
118 static void gtk_handle_box_realize        (GtkWidget         *widget);
119 static void gtk_handle_box_unrealize      (GtkWidget         *widget);
120 static void gtk_handle_box_style_set      (GtkWidget         *widget,
121                                            GtkStyle          *previous_style);
122 static void gtk_handle_box_size_request   (GtkWidget         *widget,
123                                            GtkRequisition    *requisition);
124 static void gtk_handle_box_size_allocate  (GtkWidget         *widget,
125                                            GtkAllocation     *real_allocation);
126 static void gtk_handle_box_add            (GtkContainer      *container,
127                                            GtkWidget         *widget);
128 static void gtk_handle_box_remove         (GtkContainer      *container,
129                                            GtkWidget         *widget);
130 static void gtk_handle_box_draw_ghost     (GtkHandleBox      *hb);
131 static void gtk_handle_box_paint          (GtkWidget         *widget,
132                                            GdkEventExpose    *event,
133                                            GdkRectangle      *area);
134 static gint gtk_handle_box_expose         (GtkWidget         *widget,
135                                            GdkEventExpose    *event);
136 static gint gtk_handle_box_button_changed (GtkWidget         *widget,
137                                            GdkEventButton    *event);
138 static gint gtk_handle_box_motion         (GtkWidget         *widget,
139                                            GdkEventMotion    *event);
140 static gint gtk_handle_box_delete_event   (GtkWidget         *widget,
141                                            GdkEventAny       *event);
142 static void gtk_handle_box_reattach       (GtkHandleBox      *hb);
143 static void gtk_handle_box_end_drag       (GtkHandleBox      *hb,
144                                            guint32            time);
145
146
147 static GtkBinClass *parent_class;
148 static guint        handle_box_signals[SIGNAL_LAST] = { 0 };
149
150
151 GType
152 gtk_handle_box_get_type (void)
153 {
154   static GType handle_box_type = 0;
155
156   if (!handle_box_type)
157     {
158       static const GTypeInfo handle_box_info =
159       {
160         sizeof (GtkHandleBoxClass),
161         NULL,           /* base_init */
162         NULL,           /* base_finalize */
163         (GClassInitFunc) gtk_handle_box_class_init,
164         NULL,           /* class_finalize */
165         NULL,           /* class_data */
166         sizeof (GtkHandleBox),
167         0,              /* n_preallocs */
168         (GInstanceInitFunc) gtk_handle_box_init,
169       };
170
171       handle_box_type = g_type_register_static (GTK_TYPE_BIN, "GtkHandleBox",
172                                                 &handle_box_info, 0);
173     }
174
175   return handle_box_type;
176 }
177
178 static void
179 gtk_handle_box_class_init (GtkHandleBoxClass *class)
180 {
181   GObjectClass *gobject_class;
182   GtkObjectClass *object_class;
183   GtkWidgetClass *widget_class;
184   GtkContainerClass *container_class;
185
186   gobject_class = (GObjectClass *) class;
187   object_class = (GtkObjectClass *) class;
188   widget_class = (GtkWidgetClass *) class;
189   container_class = (GtkContainerClass *) class;
190
191   parent_class = g_type_class_peek_parent (class);
192
193   gobject_class->set_property = gtk_handle_box_set_property;
194   gobject_class->get_property = gtk_handle_box_get_property;
195   
196   g_object_class_install_property (gobject_class,
197                                    PROP_SHADOW,
198                                    g_param_spec_enum ("shadow", NULL,
199                                                       P_("Deprecated property, use shadow_type instead"),
200                                                       GTK_TYPE_SHADOW_TYPE,
201                                                       GTK_SHADOW_ETCHED_OUT,
202                                                       G_PARAM_READABLE | G_PARAM_WRITABLE));
203   g_object_class_install_property (gobject_class,
204                                    PROP_SHADOW_TYPE,
205                                    g_param_spec_enum ("shadow_type",
206                                                       P_("Shadow type"),
207                                                       P_("Appearance of the shadow that surrounds the container"),
208                                                       GTK_TYPE_SHADOW_TYPE,
209                                                       GTK_SHADOW_ETCHED_OUT,
210                                                       G_PARAM_READABLE | G_PARAM_WRITABLE));
211   
212   g_object_class_install_property (gobject_class,
213                                    PROP_HANDLE_POSITION,
214                                    g_param_spec_enum ("handle_position",
215                                                       P_("Handle position"),
216                                                       P_("Position of the handle relative to the child widget"),
217                                                       GTK_TYPE_POSITION_TYPE,
218                                                       GTK_POS_LEFT,
219                                                       G_PARAM_READABLE | G_PARAM_WRITABLE));
220   
221   g_object_class_install_property (gobject_class,
222                                    PROP_SNAP_EDGE,
223                                    g_param_spec_enum ("snap_edge",
224                                                       P_("Snap edge"),
225                                                       P_("Side of the handlebox that's lined up with the docking point to dock the handlebox"),
226                                                       GTK_TYPE_POSITION_TYPE,
227                                                       GTK_POS_TOP,
228                                                       G_PARAM_READABLE | G_PARAM_WRITABLE));
229
230   g_object_class_install_property (gobject_class,
231                                    PROP_SNAP_EDGE_SET,
232                                    g_param_spec_boolean ("snap_edge_set",
233                                                          P_("Snap edge set"),
234                                                          P_("Whether to use the value from the snap_edge property or a value derived from handle_position"),
235                                                          FALSE,
236                                                          G_PARAM_READABLE | G_PARAM_WRITABLE));
237
238   object_class->destroy = gtk_handle_box_destroy;
239
240   widget_class->map = gtk_handle_box_map;
241   widget_class->unmap = gtk_handle_box_unmap;
242   widget_class->realize = gtk_handle_box_realize;
243   widget_class->unrealize = gtk_handle_box_unrealize;
244   widget_class->style_set = gtk_handle_box_style_set;
245   widget_class->size_request = gtk_handle_box_size_request;
246   widget_class->size_allocate = gtk_handle_box_size_allocate;
247   widget_class->expose_event = gtk_handle_box_expose;
248   widget_class->button_press_event = gtk_handle_box_button_changed;
249   widget_class->delete_event = gtk_handle_box_delete_event;
250
251   container_class->add = gtk_handle_box_add;
252   container_class->remove = gtk_handle_box_remove;
253
254   class->child_attached = NULL;
255   class->child_detached = NULL;
256
257   handle_box_signals[SIGNAL_CHILD_ATTACHED] =
258     g_signal_new ("child_attached",
259                   G_OBJECT_CLASS_TYPE (gobject_class),
260                   G_SIGNAL_RUN_FIRST,
261                   G_STRUCT_OFFSET (GtkHandleBoxClass, child_attached),
262                   NULL, NULL,
263                   _gtk_marshal_VOID__OBJECT,
264                   G_TYPE_NONE, 1,
265                   GTK_TYPE_WIDGET);
266   handle_box_signals[SIGNAL_CHILD_DETACHED] =
267     g_signal_new ("child_detached",
268                   G_OBJECT_CLASS_TYPE (gobject_class),
269                   G_SIGNAL_RUN_FIRST,
270                   G_STRUCT_OFFSET (GtkHandleBoxClass, child_detached),
271                   NULL, NULL,
272                   _gtk_marshal_VOID__OBJECT,
273                   G_TYPE_NONE, 1,
274                   GTK_TYPE_WIDGET);
275 }
276
277 static GtkHandleBoxPrivate *
278 gtk_handle_box_get_private (GtkHandleBox *hb)
279 {
280   GtkHandleBoxPrivate *private;
281   static GQuark private_quark = 0;
282
283   if (!private_quark)
284     private_quark = g_quark_from_static_string ("gtk-handle-box-private");
285
286   private = g_object_get_qdata (G_OBJECT (hb), private_quark);
287
288   if (!private)
289     {
290       private = g_new0 (GtkHandleBoxPrivate, 1);
291       g_object_set_qdata_full (G_OBJECT (hb), private_quark,
292                                private, g_free);
293     }
294
295   return private;
296 }
297
298 static void
299 gtk_handle_box_init (GtkHandleBox *handle_box)
300 {
301   GTK_WIDGET_UNSET_FLAGS (handle_box, GTK_NO_WINDOW);
302
303   handle_box->bin_window = NULL;
304   handle_box->float_window = NULL;
305   handle_box->shadow_type = GTK_SHADOW_OUT;
306   handle_box->handle_position = GTK_POS_LEFT;
307   handle_box->float_window_mapped = FALSE;
308   handle_box->child_detached = FALSE;
309   handle_box->in_drag = FALSE;
310   handle_box->shrink_on_detach = TRUE;
311   handle_box->snap_edge = -1;
312 }
313
314 static void 
315 gtk_handle_box_set_property (GObject         *object,
316                              guint            prop_id,
317                              const GValue    *value,
318                              GParamSpec      *pspec)
319 {
320   GtkHandleBox *handle_box = GTK_HANDLE_BOX (object);
321
322   switch (prop_id)
323     {
324     case PROP_SHADOW:
325     case PROP_SHADOW_TYPE:
326       gtk_handle_box_set_shadow_type (handle_box, g_value_get_enum (value));
327       break;
328     case PROP_HANDLE_POSITION:
329       gtk_handle_box_set_handle_position (handle_box, g_value_get_enum (value));
330       break;
331     case PROP_SNAP_EDGE:
332       gtk_handle_box_set_snap_edge (handle_box, g_value_get_enum (value));
333       break;
334     case PROP_SNAP_EDGE_SET:
335       if (!g_value_get_boolean (value))
336         gtk_handle_box_set_snap_edge (handle_box, (GtkPositionType)-1);
337       break;
338     default:
339       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
340       break;
341     }
342 }
343
344 static void 
345 gtk_handle_box_get_property (GObject         *object,
346                              guint            prop_id,
347                              GValue          *value,
348                              GParamSpec      *pspec)
349 {
350   GtkHandleBox *handle_box = GTK_HANDLE_BOX (object);
351   
352   switch (prop_id)
353     {
354     case PROP_SHADOW:
355     case PROP_SHADOW_TYPE:
356       g_value_set_enum (value, handle_box->shadow_type);
357       break;
358     case PROP_HANDLE_POSITION:
359       g_value_set_enum (value, handle_box->handle_position);
360       break;
361     case PROP_SNAP_EDGE:
362       g_value_set_enum (value,
363                         (handle_box->snap_edge == -1 ?
364                          GTK_POS_TOP : handle_box->snap_edge));
365       break;
366     case PROP_SNAP_EDGE_SET:
367       g_value_set_boolean (value, handle_box->snap_edge != -1);
368       break;
369     default:
370       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
371       break;
372     }
373 }
374  
375 GtkWidget*
376 gtk_handle_box_new (void)
377 {
378   return g_object_new (GTK_TYPE_HANDLE_BOX, NULL);
379 }
380
381 static void
382 gtk_handle_box_destroy (GtkObject *object)
383 {
384   if (GTK_OBJECT_CLASS (parent_class)->destroy)
385     (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
386 }
387
388 static void
389 gtk_handle_box_map (GtkWidget *widget)
390 {
391   GtkBin *bin;
392   GtkHandleBox *hb;
393
394   GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
395
396   bin = GTK_BIN (widget);
397   hb = GTK_HANDLE_BOX (widget);
398
399   if (bin->child &&
400       GTK_WIDGET_VISIBLE (bin->child) &&
401       !GTK_WIDGET_MAPPED (bin->child))
402     gtk_widget_map (bin->child);
403
404   if (hb->child_detached && !hb->float_window_mapped)
405     {
406       gdk_window_show (hb->float_window);
407       hb->float_window_mapped = TRUE;
408     }
409
410   gdk_window_show (hb->bin_window);
411   gdk_window_show (widget->window);
412 }
413
414 static void
415 gtk_handle_box_unmap (GtkWidget *widget)
416 {
417   GtkHandleBox *hb;
418
419   GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
420
421   hb = GTK_HANDLE_BOX (widget);
422
423   gdk_window_hide (widget->window);
424   if (hb->float_window_mapped)
425     {
426       gdk_window_hide (hb->float_window);
427       hb->float_window_mapped = FALSE;
428     }
429 }
430
431 static void
432 gtk_handle_box_realize (GtkWidget *widget)
433 {
434   GdkWindowAttr attributes;
435   gint attributes_mask;
436   GtkHandleBox *hb;
437
438   hb = GTK_HANDLE_BOX (widget);
439
440   GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
441
442   attributes.x = widget->allocation.x;
443   attributes.y = widget->allocation.y;
444   attributes.width = widget->allocation.width;
445   attributes.height = widget->allocation.height;
446   attributes.window_type = GDK_WINDOW_CHILD;
447   attributes.wclass = GDK_INPUT_OUTPUT;
448   attributes.visual = gtk_widget_get_visual (widget);
449   attributes.colormap = gtk_widget_get_colormap (widget);
450   attributes.event_mask = (gtk_widget_get_events (widget)
451                            | GDK_EXPOSURE_MASK);
452   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
453   widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
454   gdk_window_set_user_data (widget->window, widget);
455
456   attributes.x = 0;
457   attributes.y = 0;
458   attributes.width = widget->allocation.width;
459   attributes.height = widget->allocation.height;
460   attributes.window_type = GDK_WINDOW_CHILD;
461   attributes.event_mask = (gtk_widget_get_events (widget) |
462                            GDK_EXPOSURE_MASK |
463                            GDK_BUTTON1_MOTION_MASK |
464                            GDK_POINTER_MOTION_HINT_MASK |
465                            GDK_BUTTON_PRESS_MASK |
466                             GDK_BUTTON_RELEASE_MASK);
467   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
468   hb->bin_window = gdk_window_new (widget->window, &attributes, attributes_mask);
469   gdk_window_set_user_data (hb->bin_window, widget);
470   if (GTK_BIN (hb)->child)
471     gtk_widget_set_parent_window (GTK_BIN (hb)->child, hb->bin_window);
472   
473   attributes.x = 0;
474   attributes.y = 0;
475   attributes.width = widget->requisition.width;
476   attributes.height = widget->requisition.height;
477   attributes.window_type = GDK_WINDOW_TOPLEVEL;
478   attributes.wclass = GDK_INPUT_OUTPUT;
479   attributes.visual = gtk_widget_get_visual (widget);
480   attributes.colormap = gtk_widget_get_colormap (widget);
481   attributes.event_mask = (gtk_widget_get_events (widget) |
482                            GDK_KEY_PRESS_MASK |
483                            GDK_ENTER_NOTIFY_MASK |
484                            GDK_LEAVE_NOTIFY_MASK |
485                            GDK_FOCUS_CHANGE_MASK |
486                            GDK_STRUCTURE_MASK);
487   attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
488   hb->float_window = gdk_window_new (gtk_widget_get_root_window (widget),
489                                      &attributes, attributes_mask);
490   gdk_window_set_user_data (hb->float_window, widget);
491   gdk_window_set_decorations (hb->float_window, 0);
492   gdk_window_set_type_hint (hb->float_window, GDK_WINDOW_TYPE_HINT_TOOLBAR);
493   
494   widget->style = gtk_style_attach (widget->style, widget->window);
495   gtk_style_set_background (widget->style, widget->window, GTK_WIDGET_STATE (hb));
496   gtk_style_set_background (widget->style, hb->bin_window, GTK_WIDGET_STATE (hb));
497   gtk_style_set_background (widget->style, hb->float_window, GTK_WIDGET_STATE (hb));
498   gdk_window_set_back_pixmap (widget->window, NULL, TRUE);
499 }
500
501 static void
502 gtk_handle_box_unrealize (GtkWidget *widget)
503 {
504   GtkHandleBox *hb = GTK_HANDLE_BOX (widget);
505
506   gdk_window_set_user_data (hb->bin_window, NULL);
507   gdk_window_destroy (hb->bin_window);
508   hb->bin_window = NULL;
509   gdk_window_set_user_data (hb->float_window, NULL);
510   gdk_window_destroy (hb->float_window);
511   hb->float_window = NULL;
512
513   if (GTK_WIDGET_CLASS (parent_class)->unrealize)
514     (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
515 }
516
517 static void
518 gtk_handle_box_style_set (GtkWidget *widget,
519                           GtkStyle  *previous_style)
520 {
521   GtkHandleBox *hb = GTK_HANDLE_BOX (widget);
522
523   if (GTK_WIDGET_REALIZED (widget) &&
524       !GTK_WIDGET_NO_WINDOW (widget))
525     {
526       gtk_style_set_background (widget->style, widget->window,
527                                 widget->state);
528       gtk_style_set_background (widget->style, hb->bin_window, widget->state);
529       gtk_style_set_background (widget->style, hb->float_window, widget->state);
530     }
531 }
532
533 static int
534 effective_handle_position (GtkHandleBox *hb)
535 {
536   int handle_position;
537
538   if (gtk_widget_get_direction (GTK_WIDGET (hb)) == GTK_TEXT_DIR_LTR)
539     handle_position = hb->handle_position;
540   else
541     {
542       switch (hb->handle_position) 
543         {
544         case GTK_POS_LEFT:
545           handle_position = GTK_POS_RIGHT;
546           break;
547         case GTK_POS_RIGHT:
548           handle_position = GTK_POS_LEFT;
549           break;
550         default:
551           handle_position = hb->handle_position;
552           break;
553         }
554     }
555
556   return handle_position;
557 }
558
559 static void
560 gtk_handle_box_size_request (GtkWidget      *widget,
561                              GtkRequisition *requisition)
562 {
563   GtkBin *bin;
564   GtkHandleBox *hb;
565   GtkRequisition child_requisition;
566   gint handle_position;
567
568   bin = GTK_BIN (widget);
569   hb = GTK_HANDLE_BOX (widget);
570
571   handle_position = effective_handle_position (hb);
572
573   if (handle_position == GTK_POS_LEFT ||
574       handle_position == GTK_POS_RIGHT)
575     {
576       requisition->width = DRAG_HANDLE_SIZE;
577       requisition->height = 0;
578     }
579   else
580     {
581       requisition->width = 0;
582       requisition->height = DRAG_HANDLE_SIZE;
583     }
584
585   /* if our child is not visible, we still request its size, since we
586    * won't have any usefull hint for our size otherwise.
587    */
588   if (bin->child)
589     gtk_widget_size_request (bin->child, &child_requisition);
590   else
591     {
592       child_requisition.width = 0;
593       child_requisition.height = 0;
594     }      
595
596   if (hb->child_detached)
597     {
598       /* FIXME: This doesn't work currently */
599       if (!hb->shrink_on_detach)
600         {
601           if (handle_position == GTK_POS_LEFT ||
602               handle_position == GTK_POS_RIGHT)
603             requisition->height += child_requisition.height;
604           else
605             requisition->width += child_requisition.width;
606         }
607       else
608         {
609           if (handle_position == GTK_POS_LEFT ||
610               handle_position == GTK_POS_RIGHT)
611             requisition->height += widget->style->ythickness;
612           else
613             requisition->width += widget->style->xthickness;
614         }
615     }
616   else
617     {
618       requisition->width += GTK_CONTAINER (widget)->border_width * 2;
619       requisition->height += GTK_CONTAINER (widget)->border_width * 2;
620       
621       if (bin->child)
622         {
623           requisition->width += child_requisition.width;
624           requisition->height += child_requisition.height;
625         }
626       else
627         {
628           requisition->width += CHILDLESS_SIZE;
629           requisition->height += CHILDLESS_SIZE;
630         }
631     }
632 }
633
634 static void
635 gtk_handle_box_size_allocate (GtkWidget     *widget,
636                               GtkAllocation *allocation)
637 {
638   GtkBin *bin;
639   GtkHandleBox *hb;
640   GtkRequisition child_requisition;
641   gint handle_position;
642   
643   bin = GTK_BIN (widget);
644   hb = GTK_HANDLE_BOX (widget);
645   
646   handle_position = effective_handle_position (hb);
647
648   if (bin->child)
649     gtk_widget_get_child_requisition (bin->child, &child_requisition);
650   else
651     {
652       child_requisition.width = 0;
653       child_requisition.height = 0;
654     }      
655       
656   widget->allocation = *allocation;
657
658   if (GTK_WIDGET_REALIZED (hb))
659     gdk_window_move_resize (widget->window,
660                             widget->allocation.x,
661                             widget->allocation.y,
662                             widget->allocation.width,
663                             widget->allocation.height);
664
665
666   if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
667     {
668       GtkWidget *child;
669       GtkAllocation child_allocation;
670       guint border_width;
671
672       child = bin->child;
673       border_width = GTK_CONTAINER (widget)->border_width;
674
675       child_allocation.x = border_width;
676       child_allocation.y = border_width;
677       if (handle_position == GTK_POS_LEFT)
678         child_allocation.x += DRAG_HANDLE_SIZE;
679       else if (handle_position == GTK_POS_TOP)
680         child_allocation.y += DRAG_HANDLE_SIZE;
681
682       if (hb->child_detached)
683         {
684           guint float_width;
685           guint float_height;
686           
687           child_allocation.width = child_requisition.width;
688           child_allocation.height = child_requisition.height;
689           
690           float_width = child_allocation.width + 2 * border_width;
691           float_height = child_allocation.height + 2 * border_width;
692           
693           if (handle_position == GTK_POS_LEFT ||
694               handle_position == GTK_POS_RIGHT)
695             float_width += DRAG_HANDLE_SIZE;
696           else
697             float_height += DRAG_HANDLE_SIZE;
698
699           if (GTK_WIDGET_REALIZED (hb))
700             {
701               gdk_window_resize (hb->float_window,
702                                  float_width,
703                                  float_height);
704               gdk_window_move_resize (hb->bin_window,
705                                       0,
706                                       0,
707                                       float_width,
708                                       float_height);
709             }
710         }
711       else
712         {
713           child_allocation.width = MAX (1, (gint)widget->allocation.width - 2 * border_width);
714           child_allocation.height = MAX (1, (gint)widget->allocation.height - 2 * border_width);
715
716           if (handle_position == GTK_POS_LEFT ||
717               handle_position == GTK_POS_RIGHT)
718             child_allocation.width -= DRAG_HANDLE_SIZE;
719           else
720             child_allocation.height -= DRAG_HANDLE_SIZE;
721           
722           if (GTK_WIDGET_REALIZED (hb))
723             gdk_window_move_resize (hb->bin_window,
724                                     0,
725                                     0,
726                                     widget->allocation.width,
727                                     widget->allocation.height);
728         }
729
730       gtk_widget_size_allocate (bin->child, &child_allocation);
731     }
732 }
733
734 static void
735 gtk_handle_box_draw_ghost (GtkHandleBox *hb)
736 {
737   GtkWidget *widget;
738   guint x;
739   guint y;
740   guint width;
741   guint height;
742   gint handle_position;
743
744   widget = GTK_WIDGET (hb);
745   
746   handle_position = effective_handle_position (hb);
747   if (handle_position == GTK_POS_LEFT ||
748       handle_position == GTK_POS_RIGHT)
749     {
750       x = handle_position == GTK_POS_LEFT ? 0 : widget->allocation.width - DRAG_HANDLE_SIZE;
751       y = 0;
752       width = DRAG_HANDLE_SIZE;
753       height = widget->allocation.height;
754     }
755   else
756     {
757       x = 0;
758       y = handle_position == GTK_POS_TOP ? 0 : widget->allocation.height - DRAG_HANDLE_SIZE;
759       width = widget->allocation.width;
760       height = DRAG_HANDLE_SIZE;
761     }
762   gtk_paint_shadow (widget->style,
763                     widget->window,
764                     GTK_WIDGET_STATE (widget),
765                     GTK_SHADOW_ETCHED_IN,
766                     NULL, widget, "handle",
767                     x,
768                     y,
769                     width,
770                     height);
771    if (handle_position == GTK_POS_LEFT ||
772        handle_position == GTK_POS_RIGHT)
773      gtk_paint_hline (widget->style,
774                       widget->window,
775                       GTK_WIDGET_STATE (widget),
776                       NULL, widget, "handlebox",
777                       handle_position == GTK_POS_LEFT ? DRAG_HANDLE_SIZE : 0,
778                       handle_position == GTK_POS_LEFT ? widget->allocation.width : widget->allocation.width - DRAG_HANDLE_SIZE,
779                       widget->allocation.height / 2);
780    else
781      gtk_paint_vline (widget->style,
782                       widget->window,
783                       GTK_WIDGET_STATE (widget),
784                       NULL, widget, "handlebox",
785                       handle_position == GTK_POS_TOP ? DRAG_HANDLE_SIZE : 0,
786                       handle_position == GTK_POS_TOP ? widget->allocation.height : widget->allocation.height - DRAG_HANDLE_SIZE,
787                       widget->allocation.width / 2);
788 }
789
790 static void
791 draw_textured_frame (GtkWidget *widget, GdkWindow *window, GdkRectangle *rect, GtkShadowType shadow,
792                      GdkRectangle *clip)
793 {
794    gtk_paint_handle (widget->style, window, GTK_STATE_NORMAL, shadow,
795                      clip, widget, "handlebox",
796                      rect->x, rect->y, rect->width, rect->height, 
797                      GTK_ORIENTATION_VERTICAL);
798 }
799
800 void
801 gtk_handle_box_set_shadow_type (GtkHandleBox  *handle_box,
802                                 GtkShadowType  type)
803 {
804   g_return_if_fail (GTK_IS_HANDLE_BOX (handle_box));
805
806   if ((GtkShadowType) handle_box->shadow_type != type)
807     {
808       handle_box->shadow_type = type;
809       g_object_notify (G_OBJECT (handle_box), "shadow_type");
810       gtk_widget_queue_resize (GTK_WIDGET (handle_box));
811     }
812 }
813
814 /**
815  * gtk_handle_box_get_shadow_type:
816  * @handle_box: a #GtkHandleBox
817  * 
818  * Gets the type of shadow drawn around the handle box. See
819  * gtk_handle_box_set_shadow_type().
820  *
821  * Return value: the type of shadow currently drawn around the handle box.
822  **/
823 GtkShadowType
824 gtk_handle_box_get_shadow_type (GtkHandleBox *handle_box)
825 {
826   g_return_val_if_fail (GTK_IS_HANDLE_BOX (handle_box), GTK_SHADOW_ETCHED_OUT);
827
828   return handle_box->shadow_type;
829 }
830
831 void        
832 gtk_handle_box_set_handle_position  (GtkHandleBox    *handle_box,
833                                      GtkPositionType  position)
834 {
835   g_return_if_fail (GTK_IS_HANDLE_BOX (handle_box));
836
837   if ((GtkPositionType) handle_box->handle_position != position)
838     {
839       handle_box->handle_position = position;
840       g_object_notify (G_OBJECT (handle_box), "handle_position");
841       gtk_widget_queue_resize (GTK_WIDGET (handle_box));
842     }
843 }
844
845 /**
846  * gtk_handle_box_get_handle_position:
847  * @handle_box: a #GtkHandleBox
848  *
849  * Gets the handle position of the handle box. See
850  * gtk_handle_box_set_handle_position().
851  *
852  * Return value: the current handle position.
853  **/
854 GtkPositionType
855 gtk_handle_box_get_handle_position (GtkHandleBox *handle_box)
856 {
857   g_return_val_if_fail (GTK_IS_HANDLE_BOX (handle_box), GTK_POS_LEFT);
858
859   return handle_box->handle_position;
860 }
861
862 void        
863 gtk_handle_box_set_snap_edge        (GtkHandleBox    *handle_box,
864                                      GtkPositionType  edge)
865 {
866   g_return_if_fail (GTK_IS_HANDLE_BOX (handle_box));
867
868   if (handle_box->snap_edge != edge)
869     {
870       handle_box->snap_edge = edge;
871       
872       g_object_freeze_notify (G_OBJECT (handle_box));
873       g_object_notify (G_OBJECT (handle_box), "snap_edge");
874       g_object_notify (G_OBJECT (handle_box), "snap_edge_set");
875       g_object_thaw_notify (G_OBJECT (handle_box));
876     }
877 }
878
879 /**
880  * gtk_handle_box_get_snap_edge:
881  * @handle_box: a #GtkHandleBox
882  * 
883  * Gets the edge used for determining reattachment of the handle box. See
884  * gtk_handle_box_set_snap_edge().
885  *
886  * Return value: the edge used for determining reattachment, or (GtkPositionType)-1 if this
887  *               is determined (as per default) from the handle position. 
888  **/
889 GtkPositionType
890 gtk_handle_box_get_snap_edge (GtkHandleBox *handle_box)
891 {
892   g_return_val_if_fail (GTK_IS_HANDLE_BOX (handle_box), (GtkPositionType)-1);
893
894   return handle_box->snap_edge;
895 }
896
897 static void
898 gtk_handle_box_paint (GtkWidget      *widget,
899                   
900     GdkEventExpose *event,
901                       GdkRectangle   *area)
902 {
903   GtkBin *bin;
904   GtkHandleBox *hb;
905   guint width;
906   guint height;
907   GdkRectangle rect;
908   GdkRectangle dest;
909   gint handle_position;
910
911   bin = GTK_BIN (widget);
912   hb = GTK_HANDLE_BOX (widget);
913
914   handle_position = effective_handle_position (hb);
915
916   gdk_drawable_get_size (hb->bin_window, &width, &height);
917   
918   if (!event)
919     gtk_paint_box (widget->style,
920                    hb->bin_window,
921                    GTK_WIDGET_STATE (widget),
922                    hb->shadow_type,
923                    area, widget, "handlebox_bin",
924                    0, 0, -1, -1);
925   else
926    gtk_paint_box (widget->style,
927                   hb->bin_window,
928                   GTK_WIDGET_STATE (widget),
929                   hb->shadow_type,
930                   &event->area, widget, "handlebox_bin",
931                   0, 0, -1, -1);
932
933 /* We currently draw the handle _above_ the relief of the handlebox.
934  * it could also be drawn on the same level...
935
936                  hb->handle_position == GTK_POS_LEFT ? DRAG_HANDLE_SIZE : 0,
937                  hb->handle_position == GTK_POS_TOP ? DRAG_HANDLE_SIZE : 0,
938                  width,
939                  height);*/
940
941   switch (handle_position)
942     {
943     case GTK_POS_LEFT:
944       rect.x = 0;
945       rect.y = 0; 
946       rect.width = DRAG_HANDLE_SIZE;
947       rect.height = height;
948       break;
949     case GTK_POS_RIGHT:
950       rect.x = width - DRAG_HANDLE_SIZE; 
951       rect.y = 0;
952       rect.width = DRAG_HANDLE_SIZE;
953       rect.height = height;
954       break;
955     case GTK_POS_TOP:
956       rect.x = 0;
957       rect.y = 0; 
958       rect.width = width;
959       rect.height = DRAG_HANDLE_SIZE;
960       break;
961     case GTK_POS_BOTTOM:
962       rect.x = 0;
963       rect.y = height - DRAG_HANDLE_SIZE;
964       rect.width = width;
965       rect.height = DRAG_HANDLE_SIZE;
966       break;
967     }
968
969   if (gdk_rectangle_intersect (event ? &event->area : area, &rect, &dest))
970     draw_textured_frame (widget, hb->bin_window, &rect,
971                          GTK_SHADOW_OUT,
972                          event ? &event->area : area);
973
974   if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
975     (* GTK_WIDGET_CLASS (parent_class)->expose_event) (widget, event);
976 }
977
978 static gint
979 gtk_handle_box_expose (GtkWidget      *widget,
980                        GdkEventExpose *event)
981 {
982   GtkHandleBox *hb;
983
984   if (GTK_WIDGET_DRAWABLE (widget))
985     {
986       hb = GTK_HANDLE_BOX (widget);
987
988       if (event->window == widget->window)
989         {
990           if (hb->child_detached)
991             gtk_handle_box_draw_ghost (hb);
992         }
993       else
994         gtk_handle_box_paint (widget, event, NULL);
995     }
996   
997   return FALSE;
998 }
999
1000 static GtkWidget *
1001 gtk_handle_box_get_invisible (void)
1002 {
1003   static GtkWidget *handle_box_invisible = NULL;
1004
1005   if (!handle_box_invisible)
1006     {
1007       handle_box_invisible = gtk_invisible_new ();
1008       gtk_widget_show (handle_box_invisible);
1009     }
1010   
1011   return handle_box_invisible;
1012 }
1013
1014 static gboolean
1015 gtk_handle_box_grab_event (GtkWidget    *widget,
1016                            GdkEvent     *event,
1017                            GtkHandleBox *hb)
1018 {
1019   switch (event->type)
1020     {
1021     case GDK_BUTTON_RELEASE:
1022       if (hb->in_drag)          /* sanity check */
1023         {
1024           gtk_handle_box_end_drag (hb, event->button.time);
1025           return TRUE;
1026         }
1027       break;
1028
1029     case GDK_MOTION_NOTIFY:
1030       return gtk_handle_box_motion (GTK_WIDGET (hb), (GdkEventMotion *)event);
1031       break;
1032
1033     default:
1034       break;
1035     }
1036
1037   return FALSE;
1038 }
1039
1040 static gint
1041 gtk_handle_box_button_changed (GtkWidget      *widget,
1042                                GdkEventButton *event)
1043 {
1044   GtkHandleBox *hb;
1045   gboolean event_handled;
1046   GdkCursor *fleur;
1047   gint handle_position;
1048
1049   hb = GTK_HANDLE_BOX (widget);
1050
1051   handle_position = effective_handle_position (hb);
1052
1053   event_handled = FALSE;
1054   if ((event->button == 1) && 
1055       (event->type == GDK_BUTTON_PRESS || event->type == GDK_2BUTTON_PRESS))
1056     {
1057       GtkWidget *child;
1058       gboolean in_handle;
1059       
1060       if (event->window != hb->bin_window)
1061         return FALSE;
1062
1063       child = GTK_BIN (hb)->child;
1064
1065       if (child)
1066         {
1067           switch (handle_position)
1068             {
1069             case GTK_POS_LEFT:
1070               in_handle = event->x < DRAG_HANDLE_SIZE;
1071               break;
1072             case GTK_POS_TOP:
1073               in_handle = event->y < DRAG_HANDLE_SIZE;
1074               break;
1075             case GTK_POS_RIGHT:
1076               in_handle = event->x > 2 * GTK_CONTAINER (hb)->border_width + child->allocation.width;
1077               break;
1078             case GTK_POS_BOTTOM:
1079               in_handle = event->y > 2 * GTK_CONTAINER (hb)->border_width + child->allocation.height;
1080               break;
1081             default:
1082               in_handle = FALSE;
1083               break;
1084             }
1085         }
1086       else
1087         {
1088           in_handle = FALSE;
1089           event_handled = TRUE;
1090         }
1091       
1092       if (in_handle)
1093         {
1094           if (event->type == GDK_BUTTON_PRESS) /* Start a drag */
1095             {
1096               GtkHandleBoxPrivate *private = gtk_handle_box_get_private (hb);
1097               GtkWidget *invisible = gtk_handle_box_get_invisible ();
1098               gint desk_x, desk_y;
1099               gint root_x, root_y;
1100               gint width, height;
1101
1102               gdk_window_get_deskrelative_origin (hb->bin_window, &desk_x, &desk_y);
1103               gdk_window_get_origin (hb->bin_window, &root_x, &root_y);
1104               gdk_drawable_get_size (hb->bin_window, &width, &height);
1105                   
1106               private->orig_x = event->x_root;
1107               private->orig_y = event->y_root;
1108                   
1109               hb->float_allocation.x = root_x - event->x_root;
1110               hb->float_allocation.y = root_y - event->y_root;
1111               hb->float_allocation.width = width;
1112               hb->float_allocation.height = height;
1113               
1114               hb->deskoff_x = desk_x - root_x;
1115               hb->deskoff_y = desk_y - root_y;
1116               
1117               if (gdk_window_is_viewable (widget->window))
1118                 {
1119                   gdk_window_get_origin (widget->window, &root_x, &root_y);
1120                   gdk_drawable_get_size (widget->window, &width, &height);
1121               
1122                   hb->attach_allocation.x = root_x;
1123                   hb->attach_allocation.y = root_y;
1124                   hb->attach_allocation.width = width;
1125                   hb->attach_allocation.height = height;
1126                 }
1127               else
1128                 {
1129                   hb->attach_allocation.x = -1;
1130                   hb->attach_allocation.y = -1;
1131                   hb->attach_allocation.width = 0;
1132                   hb->attach_allocation.height = 0;
1133                 }
1134               hb->in_drag = TRUE;
1135               fleur = gdk_cursor_new_for_display (gtk_widget_get_display (widget),
1136                                                   GDK_FLEUR);
1137               if (gdk_pointer_grab (invisible->window,
1138                                     FALSE,
1139                                     (GDK_BUTTON1_MOTION_MASK |
1140                                      GDK_POINTER_MOTION_HINT_MASK |
1141                                      GDK_BUTTON_RELEASE_MASK),
1142                                     NULL,
1143                                     fleur,
1144                                     event->time) != 0)
1145                 {
1146                   hb->in_drag = FALSE;
1147                 }
1148               else
1149                 {
1150                   gtk_grab_add (invisible);
1151                   g_signal_connect (invisible, "event",
1152                                     G_CALLBACK (gtk_handle_box_grab_event), hb);
1153                 }
1154               
1155               gdk_cursor_unref (fleur);
1156               event_handled = TRUE;
1157             }
1158           else if (hb->child_detached) /* Double click */
1159             {
1160               gtk_handle_box_reattach (hb);
1161             }
1162         }
1163     }
1164   
1165   return event_handled;
1166 }
1167
1168 static gint
1169 gtk_handle_box_motion (GtkWidget      *widget,
1170                        GdkEventMotion *event)
1171 {
1172   GtkHandleBox *hb = GTK_HANDLE_BOX (widget);
1173   gint new_x, new_y;
1174   gint snap_edge;
1175   gboolean is_snapped = FALSE;
1176   gint handle_position;
1177   GdkGeometry geometry;
1178   GdkScreen *screen, *pointer_screen;
1179
1180   if (!hb->in_drag)
1181     return FALSE;
1182   handle_position = effective_handle_position (hb);
1183
1184   /* Calculate the attachment point on the float, if the float
1185    * were detached
1186    */
1187   new_x = 0;
1188   new_y = 0;
1189   screen = gtk_widget_get_screen (widget);
1190   gdk_display_get_pointer (gdk_screen_get_display (screen),
1191                            &pointer_screen, 
1192                            &new_x, &new_y, NULL);
1193   if (pointer_screen != screen)
1194     {
1195       GtkHandleBoxPrivate *private = gtk_handle_box_get_private (hb);
1196
1197       new_x = private->orig_x;
1198       new_y = private->orig_y;
1199     }
1200   
1201   new_x += hb->float_allocation.x;
1202   new_y += hb->float_allocation.y;
1203
1204   snap_edge = hb->snap_edge;
1205   if (snap_edge == -1)
1206     snap_edge = (handle_position == GTK_POS_LEFT ||
1207                  handle_position == GTK_POS_RIGHT) ?
1208       GTK_POS_TOP : GTK_POS_LEFT;
1209
1210   if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL) 
1211     switch (snap_edge) 
1212       {
1213       case GTK_POS_LEFT:
1214         snap_edge = GTK_POS_RIGHT;
1215         break;
1216       case GTK_POS_RIGHT:
1217         snap_edge = GTK_POS_LEFT;
1218         break;
1219       default:
1220         break;
1221       }
1222
1223   /* First, check if the snapped edge is aligned
1224    */
1225   switch (snap_edge)
1226     {
1227     case GTK_POS_TOP:
1228       is_snapped = abs (hb->attach_allocation.y - new_y) < TOLERANCE;
1229       break;
1230     case GTK_POS_BOTTOM:
1231       is_snapped = abs (hb->attach_allocation.y + (gint)hb->attach_allocation.height -
1232                         new_y - (gint)hb->float_allocation.height) < TOLERANCE;
1233       break;
1234     case GTK_POS_LEFT:
1235       is_snapped = abs (hb->attach_allocation.x - new_x) < TOLERANCE;
1236       break;
1237     case GTK_POS_RIGHT:
1238       is_snapped = abs (hb->attach_allocation.x + (gint)hb->attach_allocation.width -
1239                         new_x - (gint)hb->float_allocation.width) < TOLERANCE;
1240       break;
1241     }
1242
1243   /* Next, check if coordinates in the other direction are sufficiently
1244    * aligned
1245    */
1246   if (is_snapped)
1247     {
1248       gint float_pos1 = 0;      /* Initialize to suppress warnings */
1249       gint float_pos2 = 0;
1250       gint attach_pos1 = 0;
1251       gint attach_pos2 = 0;
1252       
1253       switch (snap_edge)
1254         {
1255         case GTK_POS_TOP:
1256         case GTK_POS_BOTTOM:
1257           attach_pos1 = hb->attach_allocation.x;
1258           attach_pos2 = hb->attach_allocation.x + hb->attach_allocation.width;
1259           float_pos1 = new_x;
1260           float_pos2 = new_x + hb->float_allocation.width;
1261           break;
1262         case GTK_POS_LEFT:
1263         case GTK_POS_RIGHT:
1264           attach_pos1 = hb->attach_allocation.y;
1265           attach_pos2 = hb->attach_allocation.y + hb->attach_allocation.height;
1266           float_pos1 = new_y;
1267           float_pos2 = new_y + hb->float_allocation.height;
1268           break;
1269         }
1270
1271       is_snapped = ((attach_pos1 - TOLERANCE < float_pos1) && 
1272                     (attach_pos2 + TOLERANCE > float_pos2)) ||
1273                    ((float_pos1 - TOLERANCE < attach_pos1) &&
1274                     (float_pos2 + TOLERANCE > attach_pos2));
1275     }
1276
1277   if (is_snapped)
1278     {
1279       if (hb->child_detached)
1280         {
1281           hb->child_detached = FALSE;
1282           gdk_window_hide (hb->float_window);
1283           gdk_window_reparent (hb->bin_window, widget->window, 0, 0);
1284           hb->float_window_mapped = FALSE;
1285           g_signal_emit (hb,
1286                          handle_box_signals[SIGNAL_CHILD_ATTACHED],
1287                          0,
1288                          GTK_BIN (hb)->child);
1289           
1290           gtk_widget_queue_resize (widget);
1291         }
1292     }
1293   else
1294     {
1295       gint width, height;
1296
1297       gdk_drawable_get_size (hb->float_window, &width, &height);
1298       new_x += hb->deskoff_x;
1299       new_y += hb->deskoff_y;
1300
1301       switch (handle_position)
1302         {
1303         case GTK_POS_LEFT:
1304           new_y += ((gint)hb->float_allocation.height - height) / 2;
1305           break;
1306         case GTK_POS_RIGHT:
1307           new_x += (gint)hb->float_allocation.width - width;
1308           new_y += ((gint)hb->float_allocation.height - height) / 2;
1309           break;
1310         case GTK_POS_TOP:
1311           new_x += ((gint)hb->float_allocation.width - width) / 2;
1312           break;
1313         case GTK_POS_BOTTOM:
1314           new_x += ((gint)hb->float_allocation.width - width) / 2;
1315           new_y += (gint)hb->float_allocation.height - height;
1316           break;
1317         }
1318
1319       if (hb->child_detached)
1320         {
1321           gdk_window_move (hb->float_window, new_x, new_y);
1322           gdk_window_raise (hb->float_window);
1323         }
1324       else
1325         {
1326           gint width;
1327           gint height;
1328           GtkRequisition child_requisition;
1329
1330           hb->child_detached = TRUE;
1331
1332           if (GTK_BIN (hb)->child)
1333             gtk_widget_get_child_requisition (GTK_BIN (hb)->child, &child_requisition);
1334           else
1335             {
1336               child_requisition.width = 0;
1337               child_requisition.height = 0;
1338             }      
1339
1340           width = child_requisition.width + 2 * GTK_CONTAINER (hb)->border_width;
1341           height = child_requisition.height + 2 * GTK_CONTAINER (hb)->border_width;
1342
1343           if (handle_position == GTK_POS_LEFT || handle_position == GTK_POS_RIGHT)
1344             width += DRAG_HANDLE_SIZE;
1345           else
1346             height += DRAG_HANDLE_SIZE;
1347           
1348           gdk_window_move_resize (hb->float_window, new_x, new_y, width, height);
1349           gdk_window_reparent (hb->bin_window, hb->float_window, 0, 0);
1350           gdk_window_set_geometry_hints (hb->float_window, &geometry, GDK_HINT_POS);
1351           gdk_window_show (hb->float_window);
1352           hb->float_window_mapped = TRUE;
1353 #if     0
1354           /* this extra move is necessary if we use decorations, or our
1355            * window manager insists on decorations.
1356            */
1357           gdk_display_sync (gtk_widget_get_display (widget));
1358           gdk_window_move (hb->float_window, new_x, new_y);
1359           gdk_display_sync (gtk_widget_get_display (widget));
1360 #endif  /* 0 */
1361           g_signal_emit (hb,
1362                          handle_box_signals[SIGNAL_CHILD_DETACHED],
1363                          0,
1364                          GTK_BIN (hb)->child);
1365           gtk_handle_box_draw_ghost (hb);
1366           
1367           gtk_widget_queue_resize (widget);
1368         }
1369     }
1370
1371   return TRUE;
1372 }
1373
1374 static void
1375 gtk_handle_box_add (GtkContainer *container,
1376                     GtkWidget    *widget)
1377 {
1378   gtk_widget_set_parent_window (widget, GTK_HANDLE_BOX (container)->bin_window);
1379   GTK_CONTAINER_CLASS (parent_class)->add (container, widget);
1380 }
1381
1382 static void
1383 gtk_handle_box_remove (GtkContainer *container,
1384                        GtkWidget    *widget)
1385 {
1386   GTK_CONTAINER_CLASS (parent_class)->remove (container, widget);
1387
1388   gtk_handle_box_reattach (GTK_HANDLE_BOX (container));
1389 }
1390
1391 static gint
1392 gtk_handle_box_delete_event (GtkWidget *widget,
1393                              GdkEventAny  *event)
1394 {
1395   GtkHandleBox *hb = GTK_HANDLE_BOX (widget);
1396
1397   if (event->window == hb->float_window)
1398     {
1399       gtk_handle_box_reattach (hb);
1400       
1401       return TRUE;
1402     }
1403
1404   return FALSE;
1405 }
1406
1407 static void
1408 gtk_handle_box_reattach (GtkHandleBox *hb)
1409 {
1410   GtkWidget *widget = GTK_WIDGET (hb);
1411   
1412   if (hb->child_detached)
1413     {
1414       hb->child_detached = FALSE;
1415       if (GTK_WIDGET_REALIZED (hb))
1416         {
1417           gdk_window_hide (hb->float_window);
1418           gdk_window_reparent (hb->bin_window, widget->window, 0, 0);
1419
1420           if (GTK_BIN (hb)->child)
1421             g_signal_emit (hb,
1422                            handle_box_signals[SIGNAL_CHILD_ATTACHED],
1423                            0,
1424                            GTK_BIN (hb)->child);
1425
1426         }
1427       hb->float_window_mapped = FALSE;
1428     }
1429   if (hb->in_drag)
1430     gtk_handle_box_end_drag (hb, GDK_CURRENT_TIME);
1431
1432   gtk_widget_queue_resize (GTK_WIDGET (hb));
1433 }
1434
1435 static void
1436 gtk_handle_box_end_drag (GtkHandleBox *hb,
1437                          guint32       time)
1438 {
1439   GtkWidget *invisible = gtk_handle_box_get_invisible ();
1440                 
1441   hb->in_drag = FALSE;
1442
1443   gtk_grab_remove (invisible);
1444   gdk_pointer_ungrab (time);
1445   g_signal_handlers_disconnect_by_func (invisible,
1446                                         G_CALLBACK (gtk_handle_box_grab_event),
1447                                         hb);
1448  }