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