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