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