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->shrink_on_detach = TRUE;
182 handle_box->fleur_cursor = gdk_cursor_new (GDK_FLEUR);
183 handle_box->dragoff_x = 0;
184 handle_box->dragoff_y = 0;
188 gtk_handle_box_new (void)
190 return GTK_WIDGET (gtk_type_new (gtk_handle_box_get_type ()));
194 gtk_handle_box_destroy (GtkObject *object)
198 g_return_if_fail (object != NULL);
199 g_return_if_fail (GTK_IS_HANDLE_BOX (object));
201 hb = GTK_HANDLE_BOX (object);
203 if (GTK_OBJECT_CLASS (parent_class)->destroy)
204 (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
208 gtk_handle_box_map (GtkWidget *widget)
213 g_return_if_fail (widget != NULL);
214 g_return_if_fail (GTK_IS_HANDLE_BOX (widget));
216 GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
218 bin = GTK_BIN (widget);
219 hb = GTK_HANDLE_BOX (widget);
221 gdk_window_show (hb->bin_window);
222 gdk_window_show (widget->window);
224 if (hb->child_detached && !hb->float_window_mapped)
226 gdk_window_show (hb->float_window);
227 hb->float_window_mapped = TRUE;
231 GTK_WIDGET_VISIBLE (bin->child) &&
232 !GTK_WIDGET_MAPPED (bin->child))
233 gtk_widget_map (bin->child);
237 gtk_handle_box_unmap (GtkWidget *widget)
241 g_return_if_fail (widget != NULL);
242 g_return_if_fail (GTK_IS_HANDLE_BOX (widget));
244 GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
246 hb = GTK_HANDLE_BOX (widget);
248 gdk_window_hide (widget->window);
249 if (hb->float_window_mapped)
251 gdk_window_hide (hb->float_window);
252 hb->float_window_mapped = FALSE;
257 gtk_handle_box_realize (GtkWidget *widget)
259 GdkWindowAttr attributes;
260 gint attributes_mask;
263 g_return_if_fail (widget != NULL);
264 g_return_if_fail (GTK_IS_HANDLE_BOX (widget));
266 hb = GTK_HANDLE_BOX (widget);
268 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
270 attributes.x = widget->allocation.x;
271 attributes.y = widget->allocation.y;
272 attributes.width = widget->allocation.width;
273 attributes.height = widget->allocation.height;
274 attributes.window_type = GDK_WINDOW_CHILD;
275 attributes.wclass = GDK_INPUT_OUTPUT;
276 attributes.visual = gtk_widget_get_visual (widget);
277 attributes.colormap = gtk_widget_get_colormap (widget);
278 attributes.event_mask = (gtk_widget_get_events (widget)
279 | GDK_EXPOSURE_MASK);
280 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
281 widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
282 gdk_window_set_user_data (widget->window, widget);
286 attributes.width = widget->allocation.width;
287 attributes.height = widget->allocation.height;
288 attributes.window_type = GDK_WINDOW_CHILD;
289 attributes.event_mask |= (gtk_widget_get_events (widget) |
291 GDK_BUTTON1_MOTION_MASK |
292 GDK_POINTER_MOTION_HINT_MASK |
293 GDK_BUTTON_PRESS_MASK |
294 GDK_BUTTON_RELEASE_MASK);
295 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
296 hb->bin_window = gdk_window_new (widget->window, &attributes, attributes_mask);
297 gdk_window_set_user_data (hb->bin_window, widget);
298 if (GTK_BIN (hb)->child)
299 gtk_widget_set_parent_window (GTK_BIN (hb)->child, hb->bin_window);
303 attributes.width = widget->requisition.width;
304 attributes.height = widget->requisition.height;
305 attributes.window_type = GDK_WINDOW_TOPLEVEL;
306 attributes.wclass = GDK_INPUT_OUTPUT;
307 attributes.visual = gtk_widget_get_visual (widget);
308 attributes.colormap = gtk_widget_get_colormap (widget);
309 attributes.event_mask = (gtk_widget_get_events (widget) |
311 GDK_ENTER_NOTIFY_MASK |
312 GDK_LEAVE_NOTIFY_MASK |
313 GDK_FOCUS_CHANGE_MASK |
315 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
316 hb->float_window = gdk_window_new (NULL, &attributes, attributes_mask);
317 gdk_window_set_user_data (hb->float_window, widget);
318 gdk_window_set_decorations (hb->float_window, 0);
321 widget->style = gtk_style_attach (widget->style, widget->window);
322 gtk_style_set_background (widget->style, widget->window, GTK_WIDGET_STATE (hb));
323 gtk_style_set_background (widget->style, hb->bin_window, GTK_WIDGET_STATE (hb));
324 gtk_style_set_background (widget->style, hb->float_window, GTK_WIDGET_STATE (hb));
328 gtk_handle_box_unrealize (GtkWidget *widget)
332 g_return_if_fail (widget != NULL);
333 g_return_if_fail (GTK_IS_HANDLE_BOX (widget));
335 hb = GTK_HANDLE_BOX (widget);
337 gdk_window_set_user_data (hb->bin_window, NULL);
338 gdk_window_destroy (hb->bin_window);
339 hb->bin_window = NULL;
340 gdk_window_set_user_data (hb->float_window, NULL);
341 gdk_window_destroy (hb->float_window);
342 hb->float_window = NULL;
344 gdk_cursor_destroy (hb->fleur_cursor);
345 hb->fleur_cursor = NULL;
347 if (GTK_WIDGET_CLASS (parent_class)->unrealize)
348 (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
352 gtk_handle_box_size_request (GtkWidget *widget,
353 GtkRequisition *requisition)
358 g_return_if_fail (widget != NULL);
359 g_return_if_fail (GTK_IS_HANDLE_BOX (widget));
360 g_return_if_fail (requisition != NULL);
362 bin = GTK_BIN (widget);
363 hb = GTK_HANDLE_BOX (widget);
365 if (hb->handle_position == GTK_POS_LEFT ||
366 hb->handle_position == GTK_POS_RIGHT)
368 requisition->width = DRAG_HANDLE_SIZE;
369 requisition->height = 0;
373 requisition->width = 0;
374 requisition->height = DRAG_HANDLE_SIZE;
377 /* if our child is not visible, we still request its size, since we
378 * won't have any usefull hint for our size otherwise.
381 gtk_widget_size_request (bin->child, &bin->child->requisition);
383 if (hb->child_detached)
385 if (!hb->shrink_on_detach)
387 if (hb->handle_position == GTK_POS_LEFT ||
388 hb->handle_position == GTK_POS_RIGHT)
389 requisition->height += bin->child->requisition.height;
391 requisition->width += bin->child->requisition.width;
395 if (hb->handle_position == GTK_POS_LEFT ||
396 hb->handle_position == GTK_POS_RIGHT)
397 requisition->height += widget->style->klass->ythickness;
399 requisition->width += widget->style->klass->xthickness;
404 requisition->width += GTK_CONTAINER (widget)->border_width * 2;
405 requisition->height += GTK_CONTAINER (widget)->border_width * 2;
409 requisition->width += bin->child->requisition.width;
410 requisition->height += bin->child->requisition.height;
414 requisition->width += CHILDLESS_SIZE;
415 requisition->height += CHILDLESS_SIZE;
421 gtk_handle_box_size_allocate (GtkWidget *widget,
422 GtkAllocation *allocation)
427 g_return_if_fail (widget != NULL);
428 g_return_if_fail (GTK_IS_HANDLE_BOX (widget));
429 g_return_if_fail (allocation != NULL);
431 bin = GTK_BIN (widget);
432 hb = GTK_HANDLE_BOX (widget);
434 widget->allocation.x = allocation->x;
436 if (hb->child_detached)
438 guint max_req_height;
441 max_req_height = MAX (widget->requisition.height,
442 bin->child->requisition.height +
443 2 * widget->style->klass->ythickness);
444 max_req_width = MAX (widget->requisition.width,
445 bin->child->requisition.width +
446 2 * widget->style->klass->xthickness);
448 if (allocation->height > max_req_height)
449 widget->allocation.y = allocation->y +
450 (allocation->height - max_req_height) / 2;
452 widget->allocation.y = allocation->y;
454 widget->allocation.height = MIN (allocation->height, max_req_height);
455 widget->allocation.width = MIN (allocation->width, max_req_width);
459 widget->allocation = *allocation;
462 if (GTK_WIDGET_REALIZED (hb))
463 gdk_window_move_resize (widget->window,
464 widget->allocation.x,
465 widget->allocation.y,
466 widget->allocation.width,
467 widget->allocation.height);
470 if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
473 GtkAllocation child_allocation;
477 border_width = GTK_CONTAINER (widget)->border_width;
479 child_allocation.x = border_width;
480 child_allocation.y = border_width;
481 if (hb->handle_position == GTK_POS_LEFT)
482 child_allocation.x += DRAG_HANDLE_SIZE;
483 else if (hb->handle_position == GTK_POS_TOP)
484 child_allocation.y += DRAG_HANDLE_SIZE;
486 if (hb->child_detached)
491 child_allocation.width = child->requisition.width;
492 child_allocation.height = child->requisition.height;
494 float_width = child_allocation.width + 2 * border_width;
495 float_height = child_allocation.height + 2 * border_width;
497 if (hb->handle_position == GTK_POS_LEFT ||
498 hb->handle_position == GTK_POS_RIGHT)
499 float_width += DRAG_HANDLE_SIZE;
501 float_height += DRAG_HANDLE_SIZE;
503 if (GTK_WIDGET_REALIZED (hb))
505 gdk_window_resize (hb->float_window,
508 gdk_window_move_resize (hb->bin_window,
517 child_allocation.width = widget->allocation.width - 2 * border_width;
518 child_allocation.height = widget->allocation.height - 2 * border_width;
520 if (hb->handle_position == GTK_POS_LEFT ||
521 hb->handle_position == GTK_POS_RIGHT)
522 child_allocation.width -= DRAG_HANDLE_SIZE;
524 child_allocation.height -= DRAG_HANDLE_SIZE;
526 if (GTK_WIDGET_REALIZED (hb))
527 gdk_window_move_resize (hb->bin_window,
530 widget->allocation.width,
531 widget->allocation.height);
534 gtk_widget_size_allocate (bin->child, &child_allocation);
539 gtk_handle_box_draw_ghost (GtkHandleBox *hb)
547 widget = GTK_WIDGET (hb);
549 if (hb->handle_position == GTK_POS_LEFT ||
550 hb->handle_position == GTK_POS_RIGHT)
552 x = hb->handle_position == GTK_POS_LEFT ? 0 : widget->allocation.width;
554 width = DRAG_HANDLE_SIZE;
555 height = widget->allocation.height;
560 y = hb->handle_position == GTK_POS_TOP ? 0 : widget->allocation.height;
561 width = widget->allocation.width;
562 height = DRAG_HANDLE_SIZE;
564 gtk_draw_shadow (widget->style,
566 GTK_WIDGET_STATE (widget),
567 GTK_SHADOW_ETCHED_IN,
573 if (hb->handle_position == GTK_POS_LEFT ||
574 hb->handle_position == GTK_POS_RIGHT)
575 gtk_draw_hline (widget->style,
577 GTK_WIDGET_STATE (widget),
578 hb->handle_position == GTK_POS_LEFT ? DRAG_HANDLE_SIZE : widget->allocation.width - DRAG_HANDLE_SIZE,
579 widget->allocation.width - DRAG_HANDLE_SIZE,
580 widget->allocation.height / 2);
582 gtk_draw_vline (widget->style,
584 GTK_WIDGET_STATE (widget),
585 hb->handle_position == GTK_POS_TOP ? DRAG_HANDLE_SIZE : widget->allocation.height - DRAG_HANDLE_SIZE,
586 widget->allocation.height - DRAG_HANDLE_SIZE,
587 widget->allocation.width / 2);
592 gtk_handle_box_paint (GtkWidget *widget,
593 GdkEventExpose *event,
602 bin = GTK_BIN (widget);
603 hb = GTK_HANDLE_BOX (widget);
605 border_width = GTK_CONTAINER (hb)->border_width;
607 if (hb->child_detached)
609 width = bin->child->allocation.width + 2 * border_width;
610 height = bin->child->allocation.height + 2 * border_width;
612 else if (hb->handle_position == GTK_POS_LEFT ||
613 hb->handle_position == GTK_POS_RIGHT)
615 width = widget->allocation.width - DRAG_HANDLE_SIZE;
616 height = widget->allocation.height;
620 width = widget->allocation.width;
621 height = widget->allocation.height - DRAG_HANDLE_SIZE;
624 gdk_window_clear (hb->bin_window);
625 gtk_draw_shadow (widget->style,
627 GTK_WIDGET_STATE (widget),
629 hb->handle_position == GTK_POS_LEFT ? DRAG_HANDLE_SIZE : 0,
630 hb->handle_position == GTK_POS_TOP ? DRAG_HANDLE_SIZE : 0,
634 if (hb->handle_position == GTK_POS_LEFT ||
635 hb->handle_position == GTK_POS_RIGHT)
639 for (x = 1; x < DRAG_HANDLE_SIZE; x += 3)
641 gtk_draw_vline (widget->style,
643 GTK_WIDGET_STATE (widget),
644 widget->style->klass->ythickness,
645 height + DRAG_HANDLE_SIZE - widget->style->klass->ythickness,
646 hb->handle_position == GTK_POS_LEFT ? x : width + x);
647 gtk_draw_hline (widget->style,
649 GTK_WIDGET_STATE (widget),
650 hb->handle_position == GTK_POS_LEFT ? DRAG_HANDLE_SIZE : width,
651 hb->handle_position == GTK_POS_LEFT ? 0 : width + DRAG_HANDLE_SIZE,
653 gtk_draw_hline (widget->style,
655 GTK_WIDGET_STATE (widget),
656 hb->handle_position == GTK_POS_LEFT ? DRAG_HANDLE_SIZE : width,
657 hb->handle_position == GTK_POS_LEFT ? 0 : width + DRAG_HANDLE_SIZE,
658 height - widget->style->klass->ythickness);
664 for (y = 1; y < DRAG_HANDLE_SIZE; y += 3)
666 gtk_draw_hline (widget->style,
668 GTK_WIDGET_STATE (widget),
669 widget->style->klass->xthickness,
670 width + DRAG_HANDLE_SIZE - widget->style->klass->xthickness,
671 hb->handle_position == GTK_POS_TOP ? y : height + y);
672 gtk_draw_vline (widget->style,
674 GTK_WIDGET_STATE (widget),
675 hb->handle_position == GTK_POS_TOP ? DRAG_HANDLE_SIZE : height,
676 hb->handle_position == GTK_POS_TOP ? 0 : height + DRAG_HANDLE_SIZE,
678 gtk_draw_vline (widget->style,
680 GTK_WIDGET_STATE (widget),
681 hb->handle_position == GTK_POS_TOP ? DRAG_HANDLE_SIZE : height,
682 hb->handle_position == GTK_POS_TOP ? 0 : height + DRAG_HANDLE_SIZE,
683 width - widget->style->klass->xthickness);
687 if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
689 GdkRectangle child_area;
690 GdkEventExpose child_event;
692 if (!event) /* we were called from draw() */
694 if (gtk_widget_intersect (bin->child, area, &child_area))
695 gtk_widget_draw (bin->child, &child_area);
697 else /* we were called from expose() */
699 child_event = *event;
701 if (GTK_WIDGET_NO_WINDOW (bin->child) &&
702 gtk_widget_intersect (bin->child, &event->area, &child_event.area))
703 gtk_widget_event (bin->child, (GdkEvent *) &child_event);
709 gtk_handle_box_draw (GtkWidget *widget,
714 g_return_if_fail (widget != NULL);
715 g_return_if_fail (GTK_IS_HANDLE_BOX (widget));
716 g_return_if_fail (area != NULL);
718 hb = GTK_HANDLE_BOX (widget);
720 if (GTK_WIDGET_DRAWABLE (widget))
722 if (hb->child_detached)
724 /* The area parameter does not make sense in this case, so we
725 * repaint everything.
728 gtk_handle_box_draw_ghost (hb);
732 area->width = 2 * GTK_CONTAINER (hb)->border_width + DRAG_HANDLE_SIZE;
733 area->height = area->width + GTK_BIN (hb)->child->allocation.height;
734 area->width += GTK_BIN (hb)->child->allocation.width;
736 gtk_handle_box_paint (widget, NULL, area);
739 gtk_handle_box_paint (widget, NULL, area);
744 gtk_handle_box_expose (GtkWidget *widget,
745 GdkEventExpose *event)
749 g_return_val_if_fail (widget != NULL, FALSE);
750 g_return_val_if_fail (GTK_IS_HANDLE_BOX (widget), FALSE);
751 g_return_val_if_fail (event != NULL, FALSE);
753 if (GTK_WIDGET_DRAWABLE (widget))
755 hb = GTK_HANDLE_BOX (widget);
757 if (event->window == widget->window)
759 if (hb->child_detached)
760 gtk_handle_box_draw_ghost (hb);
763 gtk_handle_box_paint (widget, event, NULL);
770 gtk_handle_box_button_changed (GtkWidget *widget,
771 GdkEventButton *event)
774 gboolean event_handled;
776 g_return_val_if_fail (widget != NULL, FALSE);
777 g_return_val_if_fail (GTK_IS_HANDLE_BOX (widget), FALSE);
778 g_return_val_if_fail (event != NULL, FALSE);
780 hb = GTK_HANDLE_BOX (widget);
782 event_handled = FALSE;
783 if (event->button == 1 &&
784 event->type == GDK_BUTTON_PRESS)
789 child = GTK_BIN (hb)->child;
791 switch (hb->handle_position)
794 in_handle = event->x < DRAG_HANDLE_SIZE;
797 in_handle = event->y < DRAG_HANDLE_SIZE;
800 in_handle = event->x > 2 * GTK_CONTAINER (hb)->border_width + child->allocation.width;
803 in_handle = event->y > 2 * GTK_CONTAINER (hb)->border_width + child->allocation.height;
813 event_handled = TRUE;
818 hb->dragoff_x = event->x;
819 hb->dragoff_y = event->y;
821 gtk_grab_add (widget);
823 while (gdk_pointer_grab (hb->bin_window,
825 (GDK_BUTTON1_MOTION_MASK |
826 GDK_POINTER_MOTION_HINT_MASK |
827 GDK_BUTTON_RELEASE_MASK),
830 GDK_CURRENT_TIME) != 0); /* wait for success */
831 event_handled = TRUE;
834 else if (event->type == GDK_BUTTON_RELEASE &&
837 gdk_pointer_ungrab (GDK_CURRENT_TIME);
838 gtk_grab_remove (widget);
840 event_handled = TRUE;
843 return event_handled;
847 gtk_handle_box_motion (GtkWidget *widget,
848 GdkEventMotion *event)
856 g_return_val_if_fail (widget != NULL, FALSE);
857 g_return_val_if_fail (GTK_IS_HANDLE_BOX (widget), FALSE);
858 g_return_val_if_fail (event != NULL, FALSE);
860 hb = GTK_HANDLE_BOX (widget);
866 gdk_window_get_origin (hb->float_window, &ox, &oy);
869 gdk_window_get_pointer (hb->float_window, &new_x, &new_y, NULL);
872 new_x -= hb->dragoff_x;
873 new_y -= hb->dragoff_y;
876 gdk_window_get_pointer (widget->window, &snap_x, &snap_y, NULL);
878 switch (hb->handle_position)
881 in_handle = (snap_x >= 0 && snap_x <= DRAG_HANDLE_SIZE &&
882 snap_y >= 0 && snap_y <= widget->allocation.height);
885 in_handle = (snap_x >= 0 && snap_x <= widget->allocation.width &&
886 snap_y >= 0 && snap_y <= DRAG_HANDLE_SIZE);
889 in_handle = (snap_x >= widget->allocation.width - DRAG_HANDLE_SIZE && snap_x <= widget->allocation.width &&
890 snap_y >= 0 && snap_y <= widget->allocation.height);
893 in_handle = (snap_x >= 0 && snap_x <= widget->allocation.width &&
894 snap_y >= widget->allocation.height - DRAG_HANDLE_SIZE && snap_y <= widget->allocation.height);
903 if (hb->child_detached)
905 gdk_pointer_ungrab (GDK_CURRENT_TIME);
907 hb->child_detached = FALSE;
908 gdk_window_hide (hb->float_window);
909 gdk_window_reparent (hb->bin_window, widget->window, 0, 0);
910 hb->float_window_mapped = FALSE;
911 gtk_signal_emit (GTK_OBJECT (hb),
912 handle_box_signals[SIGNAL_CHILD_ATTACHED],
913 GTK_BIN (hb)->child);
915 while (gdk_pointer_grab (hb->bin_window,
917 (GDK_BUTTON1_MOTION_MASK |
918 GDK_POINTER_MOTION_HINT_MASK |
919 GDK_BUTTON_RELEASE_MASK),
922 GDK_CURRENT_TIME) != 0); /* wait for success */
924 gtk_widget_queue_resize (widget);
929 if (hb->child_detached)
931 gdk_window_move (hb->float_window, new_x, new_y);
932 gdk_window_raise (hb->float_window);
939 gdk_pointer_ungrab (GDK_CURRENT_TIME);
941 hb->child_detached = TRUE;
944 gdk_window_get_size (hb->bin_window, &width, &height);
945 gdk_window_move_resize (hb->float_window, new_x, new_y, width, height);
946 gdk_window_reparent (hb->bin_window, hb->float_window, 0, 0);
947 gdk_window_set_hints (hb->float_window, new_x, new_y, 0, 0, 0, 0, GDK_HINT_POS);
948 gdk_window_show (hb->float_window);
949 hb->float_window_mapped = TRUE;
951 /* this extra move is neccessary if we use decorations, or our
952 * window manager insists on decorations.
955 gdk_window_move (hb->float_window, new_x, new_y);
958 gtk_signal_emit (GTK_OBJECT (hb),
959 handle_box_signals[SIGNAL_CHILD_DETACHED],
960 GTK_BIN (hb)->child);
961 gtk_handle_box_draw_ghost (hb);
963 while (gdk_pointer_grab (hb->bin_window,
965 (GDK_BUTTON1_MOTION_MASK |
966 GDK_POINTER_MOTION_HINT_MASK |
967 GDK_BUTTON_RELEASE_MASK),
970 GDK_CURRENT_TIME) != 0); /* wait for success */
972 gtk_widget_queue_resize (widget);
980 gtk_handle_box_add (GtkContainer *container,
983 g_return_if_fail (GTK_IS_HANDLE_BOX (container));
984 g_return_if_fail (GTK_BIN (container)->child == NULL);
985 g_return_if_fail (widget->parent == NULL);
987 gtk_widget_set_parent_window (widget, GTK_HANDLE_BOX (container)->bin_window);
988 GTK_CONTAINER_CLASS (parent_class)->add (container, widget);
992 gtk_handle_box_remove (GtkContainer *container,
997 g_return_if_fail (GTK_IS_HANDLE_BOX (container));
998 g_return_if_fail (GTK_BIN (container)->child == widget);
1000 hb = GTK_HANDLE_BOX (container);
1002 if (hb->child_detached)
1004 hb->child_detached = FALSE;
1005 if (GTK_WIDGET_REALIZED (hb))
1007 gdk_window_hide (hb->float_window);
1008 gdk_window_reparent (hb->bin_window, GTK_WIDGET (hb)->window, 0, 0);
1010 hb->float_window_mapped = FALSE;
1014 gdk_pointer_ungrab (GDK_CURRENT_TIME);
1015 gtk_grab_remove (GTK_WIDGET (container));
1016 hb->in_drag = FALSE;
1019 GTK_CONTAINER_CLASS (parent_class)->remove (container, widget);
1023 gtk_handle_box_delete_event (GtkWidget *widget,
1028 g_return_val_if_fail (widget != NULL, FALSE);
1029 g_return_val_if_fail (GTK_IS_HANDLE_BOX (widget), FALSE);
1030 g_return_val_if_fail (event != NULL, FALSE);
1032 hb = GTK_HANDLE_BOX (widget);
1033 g_return_val_if_fail (event->window == hb->float_window, FALSE);
1035 hb->child_detached = FALSE;
1036 gdk_window_hide (hb->float_window);
1037 gdk_window_reparent (hb->bin_window, widget->window, 0, 0);
1038 hb->float_window_mapped = FALSE;
1039 gtk_signal_emit (GTK_OBJECT (hb),
1040 handle_box_signals[SIGNAL_CHILD_ATTACHED],
1041 GTK_BIN (hb)->child);
1044 gdk_pointer_ungrab (GDK_CURRENT_TIME);
1045 gtk_grab_remove (widget);
1046 hb->in_drag = FALSE;
1049 gtk_widget_queue_resize (GTK_WIDGET (hb));