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 = MAX (1, widget->allocation.width - 2 * border_width);
518 child_allocation.height = MAX (1, 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 draw_textured_frame (GtkWidget *widget, GdkWindow *window, GdkRectangle *rect, GtkShadowType shadow)
596 GdkGC *light_gc, *dark_gc;
598 gdk_draw_rectangle (window,
599 widget->style->bg_gc[GTK_STATE_NORMAL],
602 rect->width, rect->height);
604 light_gc = widget->style->light_gc[GTK_STATE_NORMAL];
605 dark_gc = widget->style->dark_gc[GTK_STATE_NORMAL];
607 xthick = widget->style->klass->xthickness;
608 ythick = widget->style->klass->ythickness;
610 gdk_gc_set_clip_rectangle (light_gc, rect);
611 gdk_gc_set_clip_rectangle (dark_gc, rect);
613 for (y = rect->y + ythick; y < (rect->y + rect->height - ythick); y += 3)
614 for (x = rect->x + xthick; x < (rect->x + rect->width - xthick); x += 6)
616 gdk_draw_point (window, light_gc, x, y);
617 gdk_draw_point (window, dark_gc, x + 1, y + 1);
619 gdk_draw_point (window, light_gc, x + 3, y + 1);
620 gdk_draw_point (window, dark_gc, x + 4, y + 2);
623 gdk_gc_set_clip_rectangle (light_gc, NULL);
624 gdk_gc_set_clip_rectangle (dark_gc, NULL);
626 gtk_draw_shadow (widget->style, window,
627 GTK_STATE_NORMAL, shadow,
629 rect->width, rect->height);
633 gtk_handle_box_paint (GtkWidget *widget,
634 GdkEventExpose *event,
644 bin = GTK_BIN (widget);
645 hb = GTK_HANDLE_BOX (widget);
647 border_width = GTK_CONTAINER (hb)->border_width;
649 if (hb->child_detached)
651 width = bin->child->allocation.width + 2 * border_width;
652 height = bin->child->allocation.height + 2 * border_width;
654 else if (hb->handle_position == GTK_POS_LEFT ||
655 hb->handle_position == GTK_POS_RIGHT)
657 width = widget->allocation.width - DRAG_HANDLE_SIZE;
658 height = widget->allocation.height;
662 width = widget->allocation.width;
663 height = widget->allocation.height - DRAG_HANDLE_SIZE;
667 gdk_window_clear_area (hb->bin_window,
673 gtk_draw_shadow (widget->style,
675 GTK_WIDGET_STATE (widget),
677 hb->handle_position == GTK_POS_LEFT ? DRAG_HANDLE_SIZE : 0,
678 hb->handle_position == GTK_POS_TOP ? DRAG_HANDLE_SIZE : 0,
684 rect.width = (hb->handle_position == GTK_POS_LEFT) ? DRAG_HANDLE_SIZE : width;
685 rect.height = (hb->handle_position == GTK_POS_TOP) ? DRAG_HANDLE_SIZE : height;
687 draw_textured_frame (widget, hb->bin_window, &rect, GTK_SHADOW_OUT);
689 if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
691 GdkRectangle child_area;
692 GdkEventExpose child_event;
694 if (!event) /* we were called from draw() */
696 if (gtk_widget_intersect (bin->child, area, &child_area))
697 gtk_widget_draw (bin->child, &child_area);
699 else /* we were called from expose() */
701 child_event = *event;
703 if (GTK_WIDGET_NO_WINDOW (bin->child) &&
704 gtk_widget_intersect (bin->child, &event->area, &child_event.area))
705 gtk_widget_event (bin->child, (GdkEvent *) &child_event);
711 gtk_handle_box_draw (GtkWidget *widget,
716 g_return_if_fail (widget != NULL);
717 g_return_if_fail (GTK_IS_HANDLE_BOX (widget));
718 g_return_if_fail (area != NULL);
720 hb = GTK_HANDLE_BOX (widget);
722 if (GTK_WIDGET_DRAWABLE (widget))
724 if (hb->child_detached)
726 /* The area parameter does not make sense in this case, so we
727 * repaint everything.
730 gtk_handle_box_draw_ghost (hb);
734 area->width = 2 * GTK_CONTAINER (hb)->border_width + DRAG_HANDLE_SIZE;
735 area->height = area->width + GTK_BIN (hb)->child->allocation.height;
736 area->width += GTK_BIN (hb)->child->allocation.width;
738 gtk_handle_box_paint (widget, NULL, area);
741 gtk_handle_box_paint (widget, NULL, area);
746 gtk_handle_box_expose (GtkWidget *widget,
747 GdkEventExpose *event)
751 g_return_val_if_fail (widget != NULL, FALSE);
752 g_return_val_if_fail (GTK_IS_HANDLE_BOX (widget), FALSE);
753 g_return_val_if_fail (event != NULL, FALSE);
755 if (GTK_WIDGET_DRAWABLE (widget))
757 hb = GTK_HANDLE_BOX (widget);
759 if (event->window == widget->window)
761 if (hb->child_detached)
762 gtk_handle_box_draw_ghost (hb);
765 gtk_handle_box_paint (widget, event, NULL);
772 gtk_handle_box_button_changed (GtkWidget *widget,
773 GdkEventButton *event)
776 gboolean event_handled;
778 g_return_val_if_fail (widget != NULL, FALSE);
779 g_return_val_if_fail (GTK_IS_HANDLE_BOX (widget), FALSE);
780 g_return_val_if_fail (event != NULL, FALSE);
782 hb = GTK_HANDLE_BOX (widget);
784 event_handled = FALSE;
785 if (event->button == 1 &&
786 event->type == GDK_BUTTON_PRESS)
791 child = GTK_BIN (hb)->child;
793 switch (hb->handle_position)
796 in_handle = event->x < DRAG_HANDLE_SIZE;
799 in_handle = event->y < DRAG_HANDLE_SIZE;
802 in_handle = event->x > 2 * GTK_CONTAINER (hb)->border_width + child->allocation.width;
805 in_handle = event->y > 2 * GTK_CONTAINER (hb)->border_width + child->allocation.height;
815 event_handled = TRUE;
820 hb->dragoff_x = event->x;
821 hb->dragoff_y = event->y;
823 gtk_grab_add (widget);
825 while (gdk_pointer_grab (hb->bin_window,
827 (GDK_BUTTON1_MOTION_MASK |
828 GDK_POINTER_MOTION_HINT_MASK |
829 GDK_BUTTON_RELEASE_MASK),
832 GDK_CURRENT_TIME) != 0); /* wait for success */
833 event_handled = TRUE;
836 else if (event->type == GDK_BUTTON_RELEASE &&
839 gdk_pointer_ungrab (GDK_CURRENT_TIME);
840 gtk_grab_remove (widget);
842 event_handled = TRUE;
845 return event_handled;
849 gtk_handle_box_motion (GtkWidget *widget,
850 GdkEventMotion *event)
858 g_return_val_if_fail (widget != NULL, FALSE);
859 g_return_val_if_fail (GTK_IS_HANDLE_BOX (widget), FALSE);
860 g_return_val_if_fail (event != NULL, FALSE);
862 hb = GTK_HANDLE_BOX (widget);
868 gdk_window_get_origin (hb->float_window, &ox, &oy);
871 gdk_window_get_pointer (hb->float_window, &new_x, &new_y, NULL);
874 new_x -= hb->dragoff_x;
875 new_y -= hb->dragoff_y;
878 gdk_window_get_pointer (widget->window, &snap_x, &snap_y, NULL);
880 switch (hb->handle_position)
883 in_handle = (snap_x >= 0 && snap_x <= DRAG_HANDLE_SIZE &&
884 snap_y >= 0 && snap_y <= widget->allocation.height);
887 in_handle = (snap_x >= 0 && snap_x <= widget->allocation.width &&
888 snap_y >= 0 && snap_y <= DRAG_HANDLE_SIZE);
891 in_handle = (snap_x >= widget->allocation.width - DRAG_HANDLE_SIZE && snap_x <= widget->allocation.width &&
892 snap_y >= 0 && snap_y <= widget->allocation.height);
895 in_handle = (snap_x >= 0 && snap_x <= widget->allocation.width &&
896 snap_y >= widget->allocation.height - DRAG_HANDLE_SIZE && snap_y <= widget->allocation.height);
905 if (hb->child_detached)
907 gdk_pointer_ungrab (GDK_CURRENT_TIME);
909 hb->child_detached = FALSE;
910 gdk_window_hide (hb->float_window);
911 gdk_window_reparent (hb->bin_window, widget->window, 0, 0);
912 hb->float_window_mapped = FALSE;
913 gtk_signal_emit (GTK_OBJECT (hb),
914 handle_box_signals[SIGNAL_CHILD_ATTACHED],
915 GTK_BIN (hb)->child);
917 while (gdk_pointer_grab (hb->bin_window,
919 (GDK_BUTTON1_MOTION_MASK |
920 GDK_POINTER_MOTION_HINT_MASK |
921 GDK_BUTTON_RELEASE_MASK),
924 GDK_CURRENT_TIME) != 0); /* wait for success */
926 gtk_widget_queue_resize (widget);
931 if (hb->child_detached)
933 gdk_window_move (hb->float_window, new_x, new_y);
934 gdk_window_raise (hb->float_window);
941 gdk_pointer_ungrab (GDK_CURRENT_TIME);
943 hb->child_detached = TRUE;
946 gdk_window_get_size (hb->bin_window, &width, &height);
947 gdk_window_move_resize (hb->float_window, new_x, new_y, width, height);
948 gdk_window_reparent (hb->bin_window, hb->float_window, 0, 0);
949 gdk_window_set_hints (hb->float_window, new_x, new_y, 0, 0, 0, 0, GDK_HINT_POS);
950 gdk_window_show (hb->float_window);
951 hb->float_window_mapped = TRUE;
953 /* this extra move is neccessary if we use decorations, or our
954 * window manager insists on decorations.
957 gdk_window_move (hb->float_window, new_x, new_y);
960 gtk_signal_emit (GTK_OBJECT (hb),
961 handle_box_signals[SIGNAL_CHILD_DETACHED],
962 GTK_BIN (hb)->child);
963 gtk_handle_box_draw_ghost (hb);
965 while (gdk_pointer_grab (hb->bin_window,
967 (GDK_BUTTON1_MOTION_MASK |
968 GDK_POINTER_MOTION_HINT_MASK |
969 GDK_BUTTON_RELEASE_MASK),
972 GDK_CURRENT_TIME) != 0); /* wait for success */
974 gtk_widget_queue_resize (widget);
982 gtk_handle_box_add (GtkContainer *container,
985 g_return_if_fail (GTK_IS_HANDLE_BOX (container));
986 g_return_if_fail (GTK_BIN (container)->child == NULL);
987 g_return_if_fail (widget->parent == NULL);
989 gtk_widget_set_parent_window (widget, GTK_HANDLE_BOX (container)->bin_window);
990 GTK_CONTAINER_CLASS (parent_class)->add (container, widget);
994 gtk_handle_box_remove (GtkContainer *container,
999 g_return_if_fail (GTK_IS_HANDLE_BOX (container));
1000 g_return_if_fail (GTK_BIN (container)->child == widget);
1002 hb = GTK_HANDLE_BOX (container);
1004 if (hb->child_detached)
1006 hb->child_detached = FALSE;
1007 if (GTK_WIDGET_REALIZED (hb))
1009 gdk_window_hide (hb->float_window);
1010 gdk_window_reparent (hb->bin_window, GTK_WIDGET (hb)->window, 0, 0);
1012 hb->float_window_mapped = FALSE;
1016 gdk_pointer_ungrab (GDK_CURRENT_TIME);
1017 gtk_grab_remove (GTK_WIDGET (container));
1018 hb->in_drag = FALSE;
1021 GTK_CONTAINER_CLASS (parent_class)->remove (container, widget);
1025 gtk_handle_box_delete_event (GtkWidget *widget,
1030 g_return_val_if_fail (widget != NULL, FALSE);
1031 g_return_val_if_fail (GTK_IS_HANDLE_BOX (widget), FALSE);
1032 g_return_val_if_fail (event != NULL, FALSE);
1034 hb = GTK_HANDLE_BOX (widget);
1035 g_return_val_if_fail (event->window == hb->float_window, FALSE);
1037 hb->child_detached = FALSE;
1038 gdk_window_hide (hb->float_window);
1039 gdk_window_reparent (hb->bin_window, widget->window, 0, 0);
1040 hb->float_window_mapped = FALSE;
1041 gtk_signal_emit (GTK_OBJECT (hb),
1042 handle_box_signals[SIGNAL_CHILD_ATTACHED],
1043 GTK_BIN (hb)->child);
1046 gdk_pointer_ungrab (GDK_CURRENT_TIME);
1047 gtk_grab_remove (widget);
1048 hb->in_drag = FALSE;
1051 gtk_widget_queue_resize (GTK_WIDGET (hb));