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