1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3 * Copyright (C) 1998 Elliot Lee
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library 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.
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 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the Free
17 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 #include "gtkhandlebox.h"
25 #include "gtksignal.h"
26 #include "gtkwindow.h"
29 #define DRAG_HANDLE_SIZE 10
30 #define CHILDLESS_SIZE 25
31 #define GHOST_HEIGHT 3
35 SIGNAL_CHILD_ATTACHED,
36 SIGNAL_CHILD_DETACHED,
40 typedef void (*SignalChildAttached) (GtkObject *object,
44 static void gtk_handle_box_class_init (GtkHandleBoxClass *klass);
45 static void gtk_handle_box_init (GtkHandleBox *handle_box);
46 static void gtk_handle_box_destroy (GtkObject *object);
47 static void gtk_handle_box_map (GtkWidget *widget);
48 static void gtk_handle_box_unmap (GtkWidget *widget);
49 static void gtk_handle_box_realize (GtkWidget *widget);
50 static void gtk_handle_box_unrealize (GtkWidget *widget);
51 static void gtk_handle_box_size_request (GtkWidget *widget,
52 GtkRequisition *requisition);
53 static void gtk_handle_box_size_allocate (GtkWidget *widget,
54 GtkAllocation *real_allocation);
55 static void gtk_handle_box_add (GtkContainer *container,
57 static void gtk_handle_box_remove (GtkContainer *container,
59 static void gtk_handle_box_draw_ghost (GtkHandleBox *hb);
60 static void gtk_handle_box_paint (GtkWidget *widget,
61 GdkEventExpose *event,
63 static void gtk_handle_box_draw (GtkWidget *widget,
65 static gint gtk_handle_box_expose (GtkWidget *widget,
66 GdkEventExpose *event);
67 static gint gtk_handle_box_button_changed (GtkWidget *widget,
68 GdkEventButton *event);
69 static gint gtk_handle_box_motion (GtkWidget *widget,
70 GdkEventMotion *event);
71 static gint gtk_handle_box_delete_event (GtkWidget *widget,
75 static GtkBinClass *parent_class;
76 static guint handle_box_signals[SIGNAL_LAST] = { 0 };
80 gtk_handle_box_get_type (void)
82 static guint handle_box_type = 0;
86 GtkTypeInfo handle_box_info =
89 sizeof (GtkHandleBox),
90 sizeof (GtkHandleBoxClass),
91 (GtkClassInitFunc) gtk_handle_box_class_init,
92 (GtkObjectInitFunc) gtk_handle_box_init,
97 handle_box_type = gtk_type_unique (gtk_bin_get_type (), &handle_box_info);
100 return handle_box_type;
104 gtk_handle_box_marshal_child_attached (GtkObject *object,
109 SignalChildAttached sfunc = (SignalChildAttached) func;
112 (GtkWidget*) GTK_VALUE_OBJECT (args[0]),
117 gtk_handle_box_class_init (GtkHandleBoxClass *class)
119 GtkObjectClass *object_class;
120 GtkWidgetClass *widget_class;
121 GtkContainerClass *container_class;
123 object_class = (GtkObjectClass *) class;
124 widget_class = (GtkWidgetClass *) class;
125 container_class = (GtkContainerClass *) class;
127 parent_class = gtk_type_class (gtk_bin_get_type ());
129 handle_box_signals[SIGNAL_CHILD_ATTACHED] =
130 gtk_signal_new ("child_attached",
133 GTK_SIGNAL_OFFSET (GtkHandleBoxClass, child_attached),
134 gtk_handle_box_marshal_child_attached,
137 handle_box_signals[SIGNAL_CHILD_DETACHED] =
138 gtk_signal_new ("child_detached",
141 GTK_SIGNAL_OFFSET (GtkHandleBoxClass, child_detached),
142 gtk_handle_box_marshal_child_attached,
145 gtk_object_class_add_signals (object_class, handle_box_signals, SIGNAL_LAST);
147 object_class->destroy = gtk_handle_box_destroy;
149 widget_class->map = gtk_handle_box_map;
150 widget_class->unmap = gtk_handle_box_unmap;
151 widget_class->realize = gtk_handle_box_realize;
152 widget_class->unrealize = gtk_handle_box_unrealize;
153 widget_class->size_request = gtk_handle_box_size_request;
154 widget_class->size_allocate = gtk_handle_box_size_allocate;
155 widget_class->draw = gtk_handle_box_draw;
156 widget_class->expose_event = gtk_handle_box_expose;
157 widget_class->button_press_event = gtk_handle_box_button_changed;
158 widget_class->button_release_event = gtk_handle_box_button_changed;
159 widget_class->motion_notify_event = gtk_handle_box_motion;
160 widget_class->delete_event = gtk_handle_box_delete_event;
162 container_class->add = gtk_handle_box_add;
163 container_class->remove = gtk_handle_box_remove;
165 class->child_attached = NULL;
166 class->child_detached = NULL;
170 gtk_handle_box_init (GtkHandleBox *handle_box)
172 GTK_WIDGET_UNSET_FLAGS (handle_box, GTK_NO_WINDOW);
173 GTK_WIDGET_SET_FLAGS (handle_box, GTK_BASIC); /* FIXME: are we really a basic widget? */
175 handle_box->bin_window = NULL;
176 handle_box->float_window = NULL;
177 handle_box->handle_position = GTK_POS_LEFT;
178 handle_box->float_window_mapped = FALSE;
179 handle_box->child_detached = FALSE;
180 handle_box->in_drag = FALSE;
181 handle_box->fleur_cursor = gdk_cursor_new (GDK_FLEUR);
182 handle_box->dragoff_x = 0;
183 handle_box->dragoff_y = 0;
187 gtk_handle_box_new (void)
189 return GTK_WIDGET (gtk_type_new (gtk_handle_box_get_type ()));
193 gtk_handle_box_destroy (GtkObject *object)
197 g_return_if_fail (object != NULL);
198 g_return_if_fail (GTK_IS_HANDLE_BOX (object));
200 hb = GTK_HANDLE_BOX (object);
202 if (GTK_OBJECT_CLASS (parent_class)->destroy)
203 (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
207 gtk_handle_box_map (GtkWidget *widget)
212 g_return_if_fail (widget != NULL);
213 g_return_if_fail (GTK_IS_HANDLE_BOX (widget));
215 GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
217 bin = GTK_BIN (widget);
218 hb = GTK_HANDLE_BOX (widget);
220 gdk_window_show (hb->bin_window);
221 gdk_window_show (widget->window);
223 if (hb->child_detached && !hb->float_window_mapped)
225 gdk_window_show (hb->float_window);
226 hb->float_window_mapped = TRUE;
230 GTK_WIDGET_VISIBLE (bin->child) &&
231 !GTK_WIDGET_MAPPED (bin->child))
232 gtk_widget_map (bin->child);
236 gtk_handle_box_unmap (GtkWidget *widget)
240 g_return_if_fail (widget != NULL);
241 g_return_if_fail (GTK_IS_HANDLE_BOX (widget));
243 GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
245 hb = GTK_HANDLE_BOX (widget);
247 gdk_window_hide (widget->window);
248 if (hb->float_window_mapped)
250 gdk_window_hide (hb->float_window);
251 hb->float_window_mapped = FALSE;
256 gtk_handle_box_realize (GtkWidget *widget)
258 GdkWindowAttr attributes;
259 gint attributes_mask;
262 g_return_if_fail (widget != NULL);
263 g_return_if_fail (GTK_IS_HANDLE_BOX (widget));
265 hb = GTK_HANDLE_BOX (widget);
267 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
269 attributes.x = widget->allocation.x;
270 attributes.y = widget->allocation.y;
271 attributes.width = widget->allocation.width;
272 attributes.height = widget->allocation.height;
273 attributes.window_type = GDK_WINDOW_CHILD;
274 attributes.wclass = GDK_INPUT_OUTPUT;
275 attributes.visual = gtk_widget_get_visual (widget);
276 attributes.colormap = gtk_widget_get_colormap (widget);
277 attributes.event_mask = (gtk_widget_get_events (widget)
278 | GDK_EXPOSURE_MASK);
279 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
280 widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
281 gdk_window_set_user_data (widget->window, widget);
285 attributes.width = widget->allocation.width;
286 attributes.height = widget->allocation.height;
287 attributes.window_type = GDK_WINDOW_CHILD;
288 attributes.event_mask |= (gtk_widget_get_events (widget) |
290 GDK_BUTTON1_MOTION_MASK |
291 GDK_POINTER_MOTION_HINT_MASK |
292 GDK_BUTTON_PRESS_MASK |
293 GDK_BUTTON_RELEASE_MASK);
294 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
295 hb->bin_window = gdk_window_new (widget->window, &attributes, attributes_mask);
296 gdk_window_set_user_data (hb->bin_window, widget);
297 if (GTK_BIN (hb)->child)
298 gtk_widget_set_parent_window (GTK_BIN (hb)->child, hb->bin_window);
302 attributes.width = widget->requisition.width;
303 attributes.height = widget->requisition.height;
304 attributes.window_type = GDK_WINDOW_TOPLEVEL;
305 attributes.wclass = GDK_INPUT_OUTPUT;
306 attributes.visual = gtk_widget_get_visual (widget);
307 attributes.colormap = gtk_widget_get_colormap (widget);
308 attributes.event_mask = (gtk_widget_get_events (widget) |
310 GDK_ENTER_NOTIFY_MASK |
311 GDK_LEAVE_NOTIFY_MASK |
312 GDK_FOCUS_CHANGE_MASK |
314 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
315 hb->float_window = gdk_window_new (NULL, &attributes, attributes_mask);
316 gdk_window_set_user_data (hb->float_window, widget);
317 gdk_window_set_decorations (hb->float_window, 0);
320 widget->style = gtk_style_attach (widget->style, widget->window);
321 gtk_style_set_background (widget->style, widget->window, GTK_WIDGET_STATE (hb));
322 gtk_style_set_background (widget->style, hb->bin_window, GTK_WIDGET_STATE (hb));
323 gtk_style_set_background (widget->style, hb->float_window, GTK_WIDGET_STATE (hb));
327 gtk_handle_box_unrealize (GtkWidget *widget)
331 g_return_if_fail (widget != NULL);
332 g_return_if_fail (GTK_IS_HANDLE_BOX (widget));
334 hb = GTK_HANDLE_BOX (widget);
336 gdk_window_set_user_data (hb->bin_window, NULL);
337 gdk_window_destroy (hb->bin_window);
338 hb->bin_window = NULL;
339 gdk_window_set_user_data (hb->float_window, NULL);
340 gdk_window_destroy (hb->float_window);
341 hb->float_window = NULL;
343 gdk_cursor_destroy (hb->fleur_cursor);
344 hb->fleur_cursor = NULL;
346 if (GTK_WIDGET_CLASS (parent_class)->unrealize)
347 (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
351 gtk_handle_box_size_request (GtkWidget *widget,
352 GtkRequisition *requisition)
357 g_return_if_fail (widget != NULL);
358 g_return_if_fail (GTK_IS_HANDLE_BOX (widget));
359 g_return_if_fail (requisition != NULL);
361 bin = GTK_BIN (widget);
362 hb = GTK_HANDLE_BOX (widget);
364 if (hb->handle_position == GTK_POS_LEFT ||
365 hb->handle_position == GTK_POS_RIGHT)
367 requisition->width = DRAG_HANDLE_SIZE;
368 requisition->height = 0;
372 requisition->width = 0;
373 requisition->height = DRAG_HANDLE_SIZE;
375 requisition->width += GTK_CONTAINER (widget)->border_width * 2;
376 requisition->height += GTK_CONTAINER (widget)->border_width * 2;
378 /* if our child is not visible, we still request its size, since we
379 * won't have any usefull hint for our size otherwise.
382 gtk_widget_size_request (bin->child, &bin->child->requisition);
384 if (hb->child_detached)
386 if (hb->handle_position == GTK_POS_LEFT ||
387 hb->handle_position == GTK_POS_RIGHT)
388 requisition->height += bin->child->requisition.height;
390 requisition->width += bin->child->requisition.width;
394 requisition->width += bin->child->requisition.width;
395 requisition->height += bin->child->requisition.height;
399 requisition->width += CHILDLESS_SIZE;
400 requisition->height += CHILDLESS_SIZE;
405 gtk_handle_box_size_allocate (GtkWidget *widget,
406 GtkAllocation *allocation)
411 g_return_if_fail (widget != NULL);
412 g_return_if_fail (GTK_IS_HANDLE_BOX (widget));
413 g_return_if_fail (allocation != NULL);
415 bin = GTK_BIN (widget);
416 hb = GTK_HANDLE_BOX (widget);
418 widget->allocation.x = allocation->x;
419 if (allocation->height > widget->requisition.height)
420 widget->allocation.y = allocation->y + (allocation->height - widget->requisition.height) / 2;
422 widget->allocation.y = allocation->y;
423 widget->allocation.height = MIN (allocation->height, widget->requisition.height);
424 widget->allocation.width = MIN (allocation->width, widget->requisition.width);
426 if (GTK_WIDGET_REALIZED (hb))
427 gdk_window_move_resize (widget->window,
428 widget->allocation.x,
429 widget->allocation.y,
430 widget->allocation.width,
431 widget->allocation.height);
434 if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
437 GtkAllocation child_allocation;
441 border_width = GTK_CONTAINER (widget)->border_width;
443 child_allocation.x = border_width;
444 child_allocation.y = border_width;
445 if (hb->handle_position == GTK_POS_LEFT)
446 child_allocation.x += DRAG_HANDLE_SIZE;
447 else if (hb->handle_position == GTK_POS_TOP)
448 child_allocation.y += DRAG_HANDLE_SIZE;
450 if (hb->child_detached)
455 child_allocation.width = child->requisition.width;
456 child_allocation.height = child->requisition.height;
458 float_width = child_allocation.width + 2 * border_width;
459 float_height = child_allocation.height + 2 * border_width;
461 if (hb->handle_position == GTK_POS_LEFT ||
462 hb->handle_position == GTK_POS_RIGHT)
463 float_width += DRAG_HANDLE_SIZE;
465 float_height += DRAG_HANDLE_SIZE;
467 if (GTK_WIDGET_REALIZED (hb))
469 gdk_window_resize (hb->float_window,
472 gdk_window_move_resize (hb->bin_window,
481 child_allocation.width = widget->allocation.width - 2 * border_width;
482 child_allocation.height = widget->allocation.height - 2 * border_width;
484 if (hb->handle_position == GTK_POS_LEFT ||
485 hb->handle_position == GTK_POS_RIGHT)
486 child_allocation.width -= DRAG_HANDLE_SIZE;
488 child_allocation.height -= DRAG_HANDLE_SIZE;
490 if (GTK_WIDGET_REALIZED (hb))
491 gdk_window_move_resize (hb->bin_window,
494 widget->allocation.width,
495 widget->allocation.height);
498 gtk_widget_size_allocate (bin->child, &child_allocation);
503 gtk_handle_box_draw_ghost (GtkHandleBox *hb)
511 widget = GTK_WIDGET (hb);
513 if (hb->handle_position == GTK_POS_LEFT ||
514 hb->handle_position == GTK_POS_RIGHT)
516 x = hb->handle_position == GTK_POS_LEFT ? 0 : widget->allocation.width;
518 width = DRAG_HANDLE_SIZE;
519 height = widget->allocation.height;
524 y = hb->handle_position == GTK_POS_TOP ? 0 : widget->allocation.height;
525 width = widget->allocation.width;
526 height = DRAG_HANDLE_SIZE;
528 gtk_draw_shadow (widget->style,
530 GTK_WIDGET_STATE (widget),
531 GTK_SHADOW_ETCHED_IN,
537 if (hb->handle_position == GTK_POS_LEFT ||
538 hb->handle_position == GTK_POS_RIGHT)
539 gtk_draw_hline (widget->style,
541 GTK_WIDGET_STATE (widget),
542 hb->handle_position == GTK_POS_LEFT ? DRAG_HANDLE_SIZE : widget->allocation.width - DRAG_HANDLE_SIZE,
543 widget->allocation.width - DRAG_HANDLE_SIZE,
544 widget->allocation.height / 2);
546 gtk_draw_vline (widget->style,
548 GTK_WIDGET_STATE (widget),
549 hb->handle_position == GTK_POS_TOP ? DRAG_HANDLE_SIZE : widget->allocation.height - DRAG_HANDLE_SIZE,
550 widget->allocation.height - DRAG_HANDLE_SIZE,
551 widget->allocation.width / 2);
556 gtk_handle_box_paint (GtkWidget *widget,
557 GdkEventExpose *event,
566 bin = GTK_BIN (widget);
567 hb = GTK_HANDLE_BOX (widget);
569 border_width = GTK_CONTAINER (hb)->border_width;
571 if (hb->child_detached)
573 width = bin->child->allocation.width + 2 * border_width;
574 height = bin->child->allocation.height + 2 * border_width;
576 else if (hb->handle_position == GTK_POS_LEFT ||
577 hb->handle_position == GTK_POS_RIGHT)
579 width = widget->allocation.width - DRAG_HANDLE_SIZE;
580 height = widget->allocation.height;
584 width = widget->allocation.width;
585 height = widget->allocation.height - DRAG_HANDLE_SIZE;
588 gdk_window_clear (hb->bin_window);
589 gtk_draw_shadow (widget->style,
591 GTK_WIDGET_STATE (widget),
593 hb->handle_position == GTK_POS_LEFT ? DRAG_HANDLE_SIZE : 0,
594 hb->handle_position == GTK_POS_TOP ? DRAG_HANDLE_SIZE : 0,
598 if (hb->handle_position == GTK_POS_LEFT ||
599 hb->handle_position == GTK_POS_RIGHT)
603 for (x = 1; x < DRAG_HANDLE_SIZE; x += 3)
605 gtk_draw_vline (widget->style,
607 GTK_WIDGET_STATE (widget),
608 widget->style->klass->ythickness,
609 height + DRAG_HANDLE_SIZE - widget->style->klass->ythickness,
610 hb->handle_position == GTK_POS_LEFT ? x : width + x);
611 gtk_draw_hline (widget->style,
613 GTK_WIDGET_STATE (widget),
614 hb->handle_position == GTK_POS_LEFT ? DRAG_HANDLE_SIZE : width,
615 hb->handle_position == GTK_POS_LEFT ? 0 : width + DRAG_HANDLE_SIZE,
617 gtk_draw_hline (widget->style,
619 GTK_WIDGET_STATE (widget),
620 hb->handle_position == GTK_POS_LEFT ? DRAG_HANDLE_SIZE : width,
621 hb->handle_position == GTK_POS_LEFT ? 0 : width + DRAG_HANDLE_SIZE,
622 height - widget->style->klass->ythickness);
628 for (y = 1; y < DRAG_HANDLE_SIZE; y += 3)
630 gtk_draw_hline (widget->style,
632 GTK_WIDGET_STATE (widget),
633 widget->style->klass->xthickness,
634 width + DRAG_HANDLE_SIZE - widget->style->klass->xthickness,
635 hb->handle_position == GTK_POS_TOP ? y : height + y);
636 gtk_draw_vline (widget->style,
638 GTK_WIDGET_STATE (widget),
639 hb->handle_position == GTK_POS_TOP ? DRAG_HANDLE_SIZE : height,
640 hb->handle_position == GTK_POS_TOP ? 0 : height + DRAG_HANDLE_SIZE,
642 gtk_draw_vline (widget->style,
644 GTK_WIDGET_STATE (widget),
645 hb->handle_position == GTK_POS_TOP ? DRAG_HANDLE_SIZE : height,
646 hb->handle_position == GTK_POS_TOP ? 0 : height + DRAG_HANDLE_SIZE,
647 width - widget->style->klass->xthickness);
651 if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
653 GdkRectangle child_area;
654 GdkEventExpose child_event;
656 if (!event) /* we were called from draw() */
658 if (gtk_widget_intersect (bin->child, area, &child_area))
659 gtk_widget_draw (bin->child, &child_area);
661 else /* we were called from expose() */
663 child_event = *event;
665 if (GTK_WIDGET_NO_WINDOW (bin->child) &&
666 gtk_widget_intersect (bin->child, &event->area, &child_event.area))
667 gtk_widget_event (bin->child, (GdkEvent *) &child_event);
673 gtk_handle_box_draw (GtkWidget *widget,
678 g_return_if_fail (widget != NULL);
679 g_return_if_fail (GTK_IS_HANDLE_BOX (widget));
680 g_return_if_fail (area != NULL);
682 hb = GTK_HANDLE_BOX (widget);
684 if (GTK_WIDGET_DRAWABLE (widget))
686 if (hb->child_detached)
688 /* The area parameter does not make sense in this case, so we
689 * repaint everything.
692 gtk_handle_box_draw_ghost (hb);
696 area->width = 2 * GTK_CONTAINER (hb)->border_width + DRAG_HANDLE_SIZE;
697 area->height = area->width + GTK_BIN (hb)->child->allocation.height;
698 area->width += GTK_BIN (hb)->child->allocation.width;
700 gtk_handle_box_paint (widget, NULL, area);
703 gtk_handle_box_paint (widget, NULL, area);
708 gtk_handle_box_expose (GtkWidget *widget,
709 GdkEventExpose *event)
713 g_return_val_if_fail (widget != NULL, FALSE);
714 g_return_val_if_fail (GTK_IS_HANDLE_BOX (widget), FALSE);
715 g_return_val_if_fail (event != NULL, FALSE);
717 if (GTK_WIDGET_DRAWABLE (widget))
719 hb = GTK_HANDLE_BOX (widget);
721 if (event->window == widget->window)
723 if (hb->child_detached)
724 gtk_handle_box_draw_ghost (hb);
727 gtk_handle_box_paint (widget, event, NULL);
734 gtk_handle_box_button_changed (GtkWidget *widget,
735 GdkEventButton *event)
738 gboolean event_handled;
740 g_return_val_if_fail (widget != NULL, FALSE);
741 g_return_val_if_fail (GTK_IS_HANDLE_BOX (widget), FALSE);
742 g_return_val_if_fail (event != NULL, FALSE);
744 hb = GTK_HANDLE_BOX (widget);
746 event_handled = FALSE;
747 if (event->button == 1 &&
748 event->type == GDK_BUTTON_PRESS)
753 child = GTK_BIN (hb)->child;
755 switch (hb->handle_position)
758 in_handle = event->x < DRAG_HANDLE_SIZE;
761 in_handle = event->y < DRAG_HANDLE_SIZE;
764 in_handle = event->x > 2 * GTK_CONTAINER (hb)->border_width + child->allocation.width;
767 in_handle = event->y > 2 * GTK_CONTAINER (hb)->border_width + child->allocation.height;
777 event_handled = TRUE;
782 hb->dragoff_x = event->x;
783 hb->dragoff_y = event->y;
785 gtk_grab_add (widget);
787 while (gdk_pointer_grab (hb->bin_window,
789 (GDK_BUTTON1_MOTION_MASK |
790 GDK_POINTER_MOTION_HINT_MASK |
791 GDK_BUTTON_RELEASE_MASK),
794 GDK_CURRENT_TIME) != 0); /* wait for success */
795 event_handled = TRUE;
798 else if (event->type == GDK_BUTTON_RELEASE &&
801 gdk_pointer_ungrab (GDK_CURRENT_TIME);
802 gtk_grab_remove (widget);
804 event_handled = TRUE;
807 return event_handled;
811 gtk_handle_box_motion (GtkWidget *widget,
812 GdkEventMotion *event)
820 g_return_val_if_fail (widget != NULL, FALSE);
821 g_return_val_if_fail (GTK_IS_HANDLE_BOX (widget), FALSE);
822 g_return_val_if_fail (event != NULL, FALSE);
824 hb = GTK_HANDLE_BOX (widget);
830 gdk_window_get_origin (hb->float_window, &ox, &oy);
833 gdk_window_get_pointer (hb->float_window, &new_x, &new_y, NULL);
836 new_x -= hb->dragoff_x;
837 new_y -= hb->dragoff_y;
840 gdk_window_get_pointer (widget->window, &snap_x, &snap_y, NULL);
842 switch (hb->handle_position)
845 in_handle = (snap_x >= 0 && snap_x <= DRAG_HANDLE_SIZE &&
846 snap_y >= 0 && snap_y <= widget->allocation.height);
849 in_handle = (snap_x >= 0 && snap_x <= widget->allocation.width &&
850 snap_y >= 0 && snap_y <= DRAG_HANDLE_SIZE);
853 in_handle = (snap_x >= widget->allocation.width - DRAG_HANDLE_SIZE && snap_x <= widget->allocation.width &&
854 snap_y >= 0 && snap_y <= widget->allocation.height);
857 in_handle = (snap_x >= 0 && snap_x <= widget->allocation.width &&
858 snap_y >= widget->allocation.height - DRAG_HANDLE_SIZE && snap_y <= widget->allocation.height);
867 if (hb->child_detached)
869 gdk_pointer_ungrab (GDK_CURRENT_TIME);
871 hb->child_detached = FALSE;
872 gdk_window_hide (hb->float_window);
873 gdk_window_reparent (hb->bin_window, widget->window, 0, 0);
874 hb->float_window_mapped = FALSE;
875 gtk_signal_emit (GTK_OBJECT (hb),
876 handle_box_signals[SIGNAL_CHILD_ATTACHED],
877 GTK_BIN (hb)->child);
879 while (gdk_pointer_grab (hb->bin_window,
881 (GDK_BUTTON1_MOTION_MASK |
882 GDK_POINTER_MOTION_HINT_MASK |
883 GDK_BUTTON_RELEASE_MASK),
886 GDK_CURRENT_TIME) != 0); /* wait for success */
888 gtk_widget_queue_resize (widget);
893 if (hb->child_detached)
895 gdk_window_move (hb->float_window, new_x, new_y);
896 gdk_window_raise (hb->float_window);
903 gdk_pointer_ungrab (GDK_CURRENT_TIME);
905 hb->child_detached = TRUE;
908 gdk_window_get_size (hb->bin_window, &width, &height);
909 gdk_window_move_resize (hb->float_window, new_x, new_y, width, height);
910 gdk_window_reparent (hb->bin_window, hb->float_window, 0, 0);
911 gdk_window_set_hints (hb->float_window, new_x, new_y, 0, 0, 0, 0, GDK_HINT_POS);
912 gdk_window_show (hb->float_window);
913 hb->float_window_mapped = TRUE;
915 /* this extra move is neccessary if we use decorations, or our
916 * window manager insists on decorations.
919 gdk_window_move (hb->float_window, new_x, new_y);
922 gtk_signal_emit (GTK_OBJECT (hb),
923 handle_box_signals[SIGNAL_CHILD_DETACHED],
924 GTK_BIN (hb)->child);
925 gtk_handle_box_draw_ghost (hb);
927 while (gdk_pointer_grab (hb->bin_window,
929 (GDK_BUTTON1_MOTION_MASK |
930 GDK_POINTER_MOTION_HINT_MASK |
931 GDK_BUTTON_RELEASE_MASK),
934 GDK_CURRENT_TIME) != 0); /* wait for success */
936 gtk_widget_queue_resize (widget);
944 gtk_handle_box_add (GtkContainer *container,
947 g_return_if_fail (GTK_IS_HANDLE_BOX (container));
948 g_return_if_fail (GTK_BIN (container)->child == NULL);
949 g_return_if_fail (widget->parent == NULL);
951 gtk_widget_set_parent_window (widget, GTK_HANDLE_BOX (container)->bin_window);
952 GTK_CONTAINER_CLASS (parent_class)->add (container, widget);
956 gtk_handle_box_remove (GtkContainer *container,
961 g_return_if_fail (GTK_IS_HANDLE_BOX (container));
962 g_return_if_fail (GTK_BIN (container)->child == widget);
964 hb = GTK_HANDLE_BOX (container);
966 if (hb->child_detached)
968 hb->child_detached = FALSE;
969 if (GTK_WIDGET_REALIZED (hb))
971 gdk_window_hide (hb->float_window);
972 gdk_window_reparent (hb->bin_window, GTK_WIDGET (hb)->window, 0, 0);
974 hb->float_window_mapped = FALSE;
978 gdk_pointer_ungrab (GDK_CURRENT_TIME);
979 gtk_grab_remove (GTK_WIDGET (container));
983 GTK_CONTAINER_CLASS (parent_class)->remove (container, widget);
987 gtk_handle_box_delete_event (GtkWidget *widget,
992 g_return_val_if_fail (widget != NULL, FALSE);
993 g_return_val_if_fail (GTK_IS_HANDLE_BOX (widget), FALSE);
994 g_return_val_if_fail (event != NULL, FALSE);
996 hb = GTK_HANDLE_BOX (widget);
997 g_return_val_if_fail (event->window == hb->float_window, FALSE);
999 hb->child_detached = FALSE;
1000 gdk_window_hide (hb->float_window);
1001 gdk_window_reparent (hb->bin_window, widget->window, 0, 0);
1002 hb->float_window_mapped = FALSE;
1003 gtk_signal_emit (GTK_OBJECT (hb),
1004 handle_box_signals[SIGNAL_CHILD_ATTACHED],
1005 GTK_BIN (hb)->child);
1008 gdk_pointer_ungrab (GDK_CURRENT_TIME);
1009 gtk_grab_remove (widget);
1010 hb->in_drag = FALSE;
1013 gtk_widget_queue_resize (GTK_WIDGET (hb));