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
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
24 #include "gtkhandlebox.h"
26 #include "gtksignal.h"
27 #include "gtkwindow.h"
30 #define DRAG_HANDLE_SIZE 10
31 #define CHILDLESS_SIZE 25
32 #define GHOST_HEIGHT 3
36 SIGNAL_CHILD_ATTACHED,
37 SIGNAL_CHILD_DETACHED,
41 static void gtk_handle_box_class_init (GtkHandleBoxClass *klass);
42 static void gtk_handle_box_init (GtkHandleBox *handle_box);
43 static void gtk_handle_box_destroy (GtkObject *object);
44 static void gtk_handle_box_map (GtkWidget *widget);
45 static void gtk_handle_box_unmap (GtkWidget *widget);
46 static void gtk_handle_box_realize (GtkWidget *widget);
47 static void gtk_handle_box_unrealize (GtkWidget *widget);
48 static void gtk_handle_box_style_set (GtkWidget *widget,
49 GtkStyle *previous_style);
50 static void gtk_handle_box_size_request (GtkWidget *widget,
51 GtkRequisition *requisition);
52 static void gtk_handle_box_size_allocate (GtkWidget *widget,
53 GtkAllocation *real_allocation);
54 static void gtk_handle_box_add (GtkContainer *container,
56 static void gtk_handle_box_remove (GtkContainer *container,
58 static void gtk_handle_box_draw_ghost (GtkHandleBox *hb);
59 static void gtk_handle_box_paint (GtkWidget *widget,
60 GdkEventExpose *event,
62 static void gtk_handle_box_draw (GtkWidget *widget,
64 static gint gtk_handle_box_expose (GtkWidget *widget,
65 GdkEventExpose *event);
66 static gint gtk_handle_box_button_changed (GtkWidget *widget,
67 GdkEventButton *event);
68 static gint gtk_handle_box_motion (GtkWidget *widget,
69 GdkEventMotion *event);
70 static gint gtk_handle_box_delete_event (GtkWidget *widget,
74 static GtkBinClass *parent_class;
75 static guint handle_box_signals[SIGNAL_LAST] = { 0 };
79 gtk_handle_box_get_type (void)
81 static guint handle_box_type = 0;
85 GtkTypeInfo handle_box_info =
88 sizeof (GtkHandleBox),
89 sizeof (GtkHandleBoxClass),
90 (GtkClassInitFunc) gtk_handle_box_class_init,
91 (GtkObjectInitFunc) gtk_handle_box_init,
92 /* reserved_1 */ NULL,
93 /* reserved_2 */ NULL,
94 (GtkClassInitFunc) NULL,
97 handle_box_type = gtk_type_unique (gtk_bin_get_type (), &handle_box_info);
100 return handle_box_type;
104 gtk_handle_box_class_init (GtkHandleBoxClass *class)
106 GtkObjectClass *object_class;
107 GtkWidgetClass *widget_class;
108 GtkContainerClass *container_class;
110 object_class = (GtkObjectClass *) class;
111 widget_class = (GtkWidgetClass *) class;
112 container_class = (GtkContainerClass *) class;
114 parent_class = gtk_type_class (gtk_bin_get_type ());
116 handle_box_signals[SIGNAL_CHILD_ATTACHED] =
117 gtk_signal_new ("child_attached",
120 GTK_SIGNAL_OFFSET (GtkHandleBoxClass, child_attached),
121 gtk_marshal_NONE__POINTER,
124 handle_box_signals[SIGNAL_CHILD_DETACHED] =
125 gtk_signal_new ("child_detached",
128 GTK_SIGNAL_OFFSET (GtkHandleBoxClass, child_detached),
129 gtk_marshal_NONE__POINTER,
132 gtk_object_class_add_signals (object_class, handle_box_signals, SIGNAL_LAST);
134 object_class->destroy = gtk_handle_box_destroy;
136 widget_class->map = gtk_handle_box_map;
137 widget_class->unmap = gtk_handle_box_unmap;
138 widget_class->realize = gtk_handle_box_realize;
139 widget_class->unrealize = gtk_handle_box_unrealize;
140 widget_class->style_set = gtk_handle_box_style_set;
141 widget_class->size_request = gtk_handle_box_size_request;
142 widget_class->size_allocate = gtk_handle_box_size_allocate;
143 widget_class->draw = gtk_handle_box_draw;
144 widget_class->expose_event = gtk_handle_box_expose;
145 widget_class->button_press_event = gtk_handle_box_button_changed;
146 widget_class->button_release_event = gtk_handle_box_button_changed;
147 widget_class->motion_notify_event = gtk_handle_box_motion;
148 widget_class->delete_event = gtk_handle_box_delete_event;
150 container_class->add = gtk_handle_box_add;
151 container_class->remove = gtk_handle_box_remove;
153 class->child_attached = NULL;
154 class->child_detached = NULL;
158 gtk_handle_box_init (GtkHandleBox *handle_box)
160 GTK_WIDGET_UNSET_FLAGS (handle_box, GTK_NO_WINDOW);
161 GTK_WIDGET_SET_FLAGS (handle_box, GTK_BASIC); /* FIXME: are we really a basic widget? */
163 handle_box->bin_window = NULL;
164 handle_box->float_window = NULL;
165 handle_box->handle_position = GTK_POS_LEFT;
166 handle_box->float_window_mapped = FALSE;
167 handle_box->child_detached = FALSE;
168 handle_box->in_drag = FALSE;
169 handle_box->shrink_on_detach = TRUE;
170 handle_box->dragoff_x = 0;
171 handle_box->dragoff_y = 0;
175 gtk_handle_box_new (void)
177 return GTK_WIDGET (gtk_type_new (gtk_handle_box_get_type ()));
181 gtk_handle_box_destroy (GtkObject *object)
185 g_return_if_fail (object != NULL);
186 g_return_if_fail (GTK_IS_HANDLE_BOX (object));
188 hb = GTK_HANDLE_BOX (object);
190 if (GTK_OBJECT_CLASS (parent_class)->destroy)
191 (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
195 gtk_handle_box_map (GtkWidget *widget)
200 g_return_if_fail (widget != NULL);
201 g_return_if_fail (GTK_IS_HANDLE_BOX (widget));
203 GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
205 bin = GTK_BIN (widget);
206 hb = GTK_HANDLE_BOX (widget);
208 gdk_window_show (hb->bin_window);
209 gdk_window_show (widget->window);
211 if (hb->child_detached && !hb->float_window_mapped)
213 gdk_window_show (hb->float_window);
214 hb->float_window_mapped = TRUE;
218 GTK_WIDGET_VISIBLE (bin->child) &&
219 !GTK_WIDGET_MAPPED (bin->child))
220 gtk_widget_map (bin->child);
224 gtk_handle_box_unmap (GtkWidget *widget)
228 g_return_if_fail (widget != NULL);
229 g_return_if_fail (GTK_IS_HANDLE_BOX (widget));
231 GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
233 hb = GTK_HANDLE_BOX (widget);
235 gdk_window_hide (widget->window);
236 if (hb->float_window_mapped)
238 gdk_window_hide (hb->float_window);
239 hb->float_window_mapped = FALSE;
244 gtk_handle_box_realize (GtkWidget *widget)
246 GdkWindowAttr attributes;
247 gint attributes_mask;
250 g_return_if_fail (widget != NULL);
251 g_return_if_fail (GTK_IS_HANDLE_BOX (widget));
253 hb = GTK_HANDLE_BOX (widget);
255 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
257 attributes.x = widget->allocation.x;
258 attributes.y = widget->allocation.y;
259 attributes.width = widget->allocation.width;
260 attributes.height = widget->allocation.height;
261 attributes.window_type = GDK_WINDOW_CHILD;
262 attributes.wclass = GDK_INPUT_OUTPUT;
263 attributes.visual = gtk_widget_get_visual (widget);
264 attributes.colormap = gtk_widget_get_colormap (widget);
265 attributes.event_mask = (gtk_widget_get_events (widget)
266 | GDK_EXPOSURE_MASK);
267 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
268 widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
269 gdk_window_set_user_data (widget->window, widget);
273 attributes.width = widget->allocation.width;
274 attributes.height = widget->allocation.height;
275 attributes.window_type = GDK_WINDOW_CHILD;
276 attributes.event_mask |= (gtk_widget_get_events (widget) |
278 GDK_BUTTON1_MOTION_MASK |
279 GDK_POINTER_MOTION_HINT_MASK |
280 GDK_BUTTON_PRESS_MASK |
281 GDK_BUTTON_RELEASE_MASK);
282 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
283 hb->bin_window = gdk_window_new (widget->window, &attributes, attributes_mask);
284 gdk_window_set_user_data (hb->bin_window, widget);
285 if (GTK_BIN (hb)->child)
286 gtk_widget_set_parent_window (GTK_BIN (hb)->child, hb->bin_window);
290 attributes.width = widget->requisition.width;
291 attributes.height = widget->requisition.height;
292 attributes.window_type = GDK_WINDOW_TOPLEVEL;
293 attributes.wclass = GDK_INPUT_OUTPUT;
294 attributes.visual = gtk_widget_get_visual (widget);
295 attributes.colormap = gtk_widget_get_colormap (widget);
296 attributes.event_mask = (gtk_widget_get_events (widget) |
298 GDK_ENTER_NOTIFY_MASK |
299 GDK_LEAVE_NOTIFY_MASK |
300 GDK_FOCUS_CHANGE_MASK |
302 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
303 hb->float_window = gdk_window_new (NULL, &attributes, attributes_mask);
304 gdk_window_set_user_data (hb->float_window, widget);
305 gdk_window_set_decorations (hb->float_window, 0);
307 widget->style = gtk_style_attach (widget->style, widget->window);
308 gtk_style_set_background (widget->style, widget->window, GTK_WIDGET_STATE (hb));
309 gtk_style_set_background (widget->style, hb->bin_window, GTK_WIDGET_STATE (hb));
310 gtk_style_set_background (widget->style, hb->float_window, GTK_WIDGET_STATE (hb));
314 gtk_handle_box_unrealize (GtkWidget *widget)
318 g_return_if_fail (widget != NULL);
319 g_return_if_fail (GTK_IS_HANDLE_BOX (widget));
321 hb = GTK_HANDLE_BOX (widget);
323 gdk_window_set_user_data (hb->bin_window, NULL);
324 gdk_window_destroy (hb->bin_window);
325 hb->bin_window = NULL;
326 gdk_window_set_user_data (hb->float_window, NULL);
327 gdk_window_destroy (hb->float_window);
328 hb->float_window = NULL;
330 if (GTK_WIDGET_CLASS (parent_class)->unrealize)
331 (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
335 gtk_handle_box_style_set (GtkWidget *widget,
336 GtkStyle *previous_style)
340 g_return_if_fail (widget != NULL);
341 g_return_if_fail (GTK_IS_HANDLE_BOX (widget));
343 hb = GTK_HANDLE_BOX (widget);
345 if (GTK_WIDGET_REALIZED (widget) &&
346 !GTK_WIDGET_NO_WINDOW (widget))
348 gtk_style_set_background (widget->style, widget->window,
350 gtk_style_set_background (widget->style, hb->bin_window, widget->state);
351 gtk_style_set_background (widget->style, hb->float_window, widget->state);
352 if (GTK_WIDGET_DRAWABLE (widget))
353 gdk_window_clear (widget->window);
358 gtk_handle_box_size_request (GtkWidget *widget,
359 GtkRequisition *requisition)
364 g_return_if_fail (widget != NULL);
365 g_return_if_fail (GTK_IS_HANDLE_BOX (widget));
366 g_return_if_fail (requisition != NULL);
368 bin = GTK_BIN (widget);
369 hb = GTK_HANDLE_BOX (widget);
371 if (hb->handle_position == GTK_POS_LEFT ||
372 hb->handle_position == GTK_POS_RIGHT)
374 requisition->width = DRAG_HANDLE_SIZE;
375 requisition->height = 0;
379 requisition->width = 0;
380 requisition->height = DRAG_HANDLE_SIZE;
383 /* if our child is not visible, we still request its size, since we
384 * won't have any usefull hint for our size otherwise.
387 gtk_widget_size_request (bin->child, &bin->child->requisition);
389 if (hb->child_detached)
391 if (!hb->shrink_on_detach)
393 if (hb->handle_position == GTK_POS_LEFT ||
394 hb->handle_position == GTK_POS_RIGHT)
395 requisition->height += bin->child->requisition.height;
397 requisition->width += bin->child->requisition.width;
401 if (hb->handle_position == GTK_POS_LEFT ||
402 hb->handle_position == GTK_POS_RIGHT)
403 requisition->height += widget->style->klass->ythickness;
405 requisition->width += widget->style->klass->xthickness;
410 requisition->width += GTK_CONTAINER (widget)->border_width * 2;
411 requisition->height += GTK_CONTAINER (widget)->border_width * 2;
415 requisition->width += bin->child->requisition.width;
416 requisition->height += bin->child->requisition.height;
420 requisition->width += CHILDLESS_SIZE;
421 requisition->height += CHILDLESS_SIZE;
427 gtk_handle_box_size_allocate (GtkWidget *widget,
428 GtkAllocation *allocation)
433 g_return_if_fail (widget != NULL);
434 g_return_if_fail (GTK_IS_HANDLE_BOX (widget));
435 g_return_if_fail (allocation != NULL);
437 bin = GTK_BIN (widget);
438 hb = GTK_HANDLE_BOX (widget);
440 widget->allocation.x = allocation->x;
442 if (hb->child_detached)
444 guint max_req_height;
447 max_req_height = MAX (widget->requisition.height,
448 bin->child->requisition.height +
449 2 * widget->style->klass->ythickness);
450 max_req_width = MAX (widget->requisition.width,
451 bin->child->requisition.width +
452 2 * widget->style->klass->xthickness);
454 if (allocation->height > max_req_height)
455 widget->allocation.y = allocation->y +
456 (allocation->height - max_req_height) / 2;
458 widget->allocation.y = allocation->y;
460 widget->allocation.height = MIN (allocation->height, max_req_height);
461 widget->allocation.width = MIN (allocation->width, max_req_width);
465 widget->allocation = *allocation;
468 if (GTK_WIDGET_REALIZED (hb))
469 gdk_window_move_resize (widget->window,
470 widget->allocation.x,
471 widget->allocation.y,
472 widget->allocation.width,
473 widget->allocation.height);
476 if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
479 GtkAllocation child_allocation;
483 border_width = GTK_CONTAINER (widget)->border_width;
485 child_allocation.x = border_width;
486 child_allocation.y = border_width;
487 if (hb->handle_position == GTK_POS_LEFT)
488 child_allocation.x += DRAG_HANDLE_SIZE;
489 else if (hb->handle_position == GTK_POS_TOP)
490 child_allocation.y += DRAG_HANDLE_SIZE;
492 if (hb->child_detached)
497 child_allocation.width = child->requisition.width;
498 child_allocation.height = child->requisition.height;
500 float_width = child_allocation.width + 2 * border_width;
501 float_height = child_allocation.height + 2 * border_width;
503 if (hb->handle_position == GTK_POS_LEFT ||
504 hb->handle_position == GTK_POS_RIGHT)
505 float_width += DRAG_HANDLE_SIZE;
507 float_height += DRAG_HANDLE_SIZE;
509 if (GTK_WIDGET_REALIZED (hb))
511 gdk_window_resize (hb->float_window,
514 gdk_window_move_resize (hb->bin_window,
523 child_allocation.width = MAX (1, widget->allocation.width - 2 * border_width);
524 child_allocation.height = MAX (1, widget->allocation.height - 2 * border_width);
526 if (hb->handle_position == GTK_POS_LEFT ||
527 hb->handle_position == GTK_POS_RIGHT)
528 child_allocation.width -= DRAG_HANDLE_SIZE;
530 child_allocation.height -= DRAG_HANDLE_SIZE;
532 if (GTK_WIDGET_REALIZED (hb))
533 gdk_window_move_resize (hb->bin_window,
536 widget->allocation.width,
537 widget->allocation.height);
540 gtk_widget_size_allocate (bin->child, &child_allocation);
545 gtk_handle_box_draw_ghost (GtkHandleBox *hb)
553 widget = GTK_WIDGET (hb);
555 if (hb->handle_position == GTK_POS_LEFT ||
556 hb->handle_position == GTK_POS_RIGHT)
558 x = hb->handle_position == GTK_POS_LEFT ? 0 : widget->allocation.width;
560 width = DRAG_HANDLE_SIZE;
561 height = widget->allocation.height;
566 y = hb->handle_position == GTK_POS_TOP ? 0 : widget->allocation.height;
567 width = widget->allocation.width;
568 height = DRAG_HANDLE_SIZE;
570 gtk_draw_shadow (widget->style,
572 GTK_WIDGET_STATE (widget),
573 GTK_SHADOW_ETCHED_IN,
579 if (hb->handle_position == GTK_POS_LEFT ||
580 hb->handle_position == GTK_POS_RIGHT)
581 gtk_draw_hline (widget->style,
583 GTK_WIDGET_STATE (widget),
584 hb->handle_position == GTK_POS_LEFT ? DRAG_HANDLE_SIZE : widget->allocation.width - DRAG_HANDLE_SIZE,
585 widget->allocation.width - DRAG_HANDLE_SIZE,
586 widget->allocation.height / 2);
588 gtk_draw_vline (widget->style,
590 GTK_WIDGET_STATE (widget),
591 hb->handle_position == GTK_POS_TOP ? DRAG_HANDLE_SIZE : widget->allocation.height - DRAG_HANDLE_SIZE,
592 widget->allocation.height - DRAG_HANDLE_SIZE,
593 widget->allocation.width / 2);
598 draw_textured_frame (GtkWidget *widget, GdkWindow *window, GdkRectangle *rect, GtkShadowType shadow,
603 GdkGC *light_gc, *dark_gc;
606 if (gdk_rectangle_intersect (rect, clip, &dest))
608 gdk_draw_rectangle (window,
609 widget->style->bg_gc[GTK_STATE_NORMAL],
612 dest.width, dest.height);
614 light_gc = widget->style->light_gc[GTK_STATE_NORMAL];
615 dark_gc = widget->style->dark_gc[GTK_STATE_NORMAL];
617 xthick = widget->style->klass->xthickness;
618 ythick = widget->style->klass->ythickness;
620 gdk_gc_set_clip_rectangle (light_gc, &dest);
621 gdk_gc_set_clip_rectangle (dark_gc, &dest);
623 for (y = rect->y + ythick; y < (rect->y + rect->height - ythick); y += 3)
624 for (x = rect->x + xthick; x < (rect->x + rect->width - xthick); x += 6)
626 gdk_draw_point (window, light_gc, x, y);
627 gdk_draw_point (window, dark_gc, x + 1, y + 1);
629 gdk_draw_point (window, light_gc, x + 3, y + 1);
630 gdk_draw_point (window, dark_gc, x + 4, y + 2);
633 gdk_gc_set_clip_rectangle (light_gc, NULL);
634 gdk_gc_set_clip_rectangle (dark_gc, NULL);
636 gtk_draw_shadow (widget->style, window,
637 GTK_STATE_NORMAL, shadow,
639 rect->width, rect->height);
644 gtk_handle_box_paint (GtkWidget *widget,
645 GdkEventExpose *event,
655 bin = GTK_BIN (widget);
656 hb = GTK_HANDLE_BOX (widget);
658 border_width = GTK_CONTAINER (hb)->border_width;
660 if (hb->child_detached)
662 width = bin->child->allocation.width + 2 * border_width;
663 height = bin->child->allocation.height + 2 * border_width;
665 else if (hb->handle_position == GTK_POS_LEFT ||
666 hb->handle_position == GTK_POS_RIGHT)
668 width = widget->allocation.width - DRAG_HANDLE_SIZE;
669 height = widget->allocation.height;
673 width = widget->allocation.width;
674 height = widget->allocation.height - DRAG_HANDLE_SIZE;
678 gdk_window_clear_area (hb->bin_window,
684 gtk_draw_shadow (widget->style,
686 GTK_WIDGET_STATE (widget),
688 hb->handle_position == GTK_POS_LEFT ? DRAG_HANDLE_SIZE : 0,
689 hb->handle_position == GTK_POS_TOP ? DRAG_HANDLE_SIZE : 0,
695 rect.width = (hb->handle_position == GTK_POS_LEFT) ? DRAG_HANDLE_SIZE : width;
696 rect.height = (hb->handle_position == GTK_POS_TOP) ? DRAG_HANDLE_SIZE : height;
698 draw_textured_frame (widget, hb->bin_window, &rect, GTK_SHADOW_OUT, event ? &event->area : area);
700 if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
702 GdkRectangle child_area;
703 GdkEventExpose child_event;
705 if (!event) /* we were called from draw() */
707 if (gtk_widget_intersect (bin->child, area, &child_area))
708 gtk_widget_draw (bin->child, &child_area);
710 else /* we were called from expose() */
712 child_event = *event;
714 if (GTK_WIDGET_NO_WINDOW (bin->child) &&
715 gtk_widget_intersect (bin->child, &event->area, &child_event.area))
716 gtk_widget_event (bin->child, (GdkEvent *) &child_event);
722 gtk_handle_box_draw (GtkWidget *widget,
727 g_return_if_fail (widget != NULL);
728 g_return_if_fail (GTK_IS_HANDLE_BOX (widget));
729 g_return_if_fail (area != NULL);
731 hb = GTK_HANDLE_BOX (widget);
733 if (GTK_WIDGET_DRAWABLE (widget))
735 if (hb->child_detached)
737 /* The area parameter does not make sense in this case, so we
738 * repaint everything.
741 gtk_handle_box_draw_ghost (hb);
745 area->width = 2 * GTK_CONTAINER (hb)->border_width + DRAG_HANDLE_SIZE;
746 area->height = area->width + GTK_BIN (hb)->child->allocation.height;
747 area->width += GTK_BIN (hb)->child->allocation.width;
749 gtk_handle_box_paint (widget, NULL, area);
752 gtk_handle_box_paint (widget, NULL, area);
757 gtk_handle_box_expose (GtkWidget *widget,
758 GdkEventExpose *event)
762 g_return_val_if_fail (widget != NULL, FALSE);
763 g_return_val_if_fail (GTK_IS_HANDLE_BOX (widget), FALSE);
764 g_return_val_if_fail (event != NULL, FALSE);
766 if (GTK_WIDGET_DRAWABLE (widget))
768 hb = GTK_HANDLE_BOX (widget);
770 if (event->window == widget->window)
772 if (hb->child_detached)
773 gtk_handle_box_draw_ghost (hb);
776 gtk_handle_box_paint (widget, event, NULL);
783 gtk_handle_box_button_changed (GtkWidget *widget,
784 GdkEventButton *event)
787 gboolean event_handled;
790 g_return_val_if_fail (widget != NULL, FALSE);
791 g_return_val_if_fail (GTK_IS_HANDLE_BOX (widget), FALSE);
792 g_return_val_if_fail (event != NULL, FALSE);
794 hb = GTK_HANDLE_BOX (widget);
796 event_handled = FALSE;
797 if (event->button == 1 &&
798 event->type == GDK_BUTTON_PRESS)
803 child = GTK_BIN (hb)->child;
805 switch (hb->handle_position)
808 in_handle = event->x < DRAG_HANDLE_SIZE;
811 in_handle = event->y < DRAG_HANDLE_SIZE;
814 in_handle = event->x > 2 * GTK_CONTAINER (hb)->border_width + child->allocation.width;
817 in_handle = event->y > 2 * GTK_CONTAINER (hb)->border_width + child->allocation.height;
827 event_handled = TRUE;
832 hb->dragoff_x = event->x;
833 hb->dragoff_y = event->y;
835 gtk_grab_add (widget);
837 fleur = gdk_cursor_new (GDK_FLEUR);
838 while (gdk_pointer_grab (hb->bin_window,
840 (GDK_BUTTON1_MOTION_MASK |
841 GDK_POINTER_MOTION_HINT_MASK |
842 GDK_BUTTON_RELEASE_MASK),
845 GDK_CURRENT_TIME) != 0); /* wait for success */
846 gdk_cursor_destroy (fleur);
847 event_handled = TRUE;
850 else if (event->type == GDK_BUTTON_RELEASE &&
853 gdk_pointer_ungrab (GDK_CURRENT_TIME);
854 gtk_grab_remove (widget);
856 event_handled = TRUE;
859 return event_handled;
863 gtk_handle_box_motion (GtkWidget *widget,
864 GdkEventMotion *event)
873 g_return_val_if_fail (widget != NULL, FALSE);
874 g_return_val_if_fail (GTK_IS_HANDLE_BOX (widget), FALSE);
875 g_return_val_if_fail (event != NULL, FALSE);
877 hb = GTK_HANDLE_BOX (widget);
883 gdk_window_get_origin (hb->float_window, &ox, &oy);
886 gdk_window_get_pointer (hb->float_window, &new_x, &new_y, NULL);
889 new_x -= hb->dragoff_x;
890 new_y -= hb->dragoff_y;
893 gdk_window_get_pointer (widget->window, &snap_x, &snap_y, NULL);
895 switch (hb->handle_position)
898 in_handle = (snap_x >= 0 && snap_x <= DRAG_HANDLE_SIZE &&
899 snap_y >= 0 && snap_y <= widget->allocation.height);
902 in_handle = (snap_x >= 0 && snap_x <= widget->allocation.width &&
903 snap_y >= 0 && snap_y <= DRAG_HANDLE_SIZE);
906 in_handle = (snap_x >= widget->allocation.width - DRAG_HANDLE_SIZE && snap_x <= widget->allocation.width &&
907 snap_y >= 0 && snap_y <= widget->allocation.height);
910 in_handle = (snap_x >= 0 && snap_x <= widget->allocation.width &&
911 snap_y >= widget->allocation.height - DRAG_HANDLE_SIZE && snap_y <= widget->allocation.height);
920 if (hb->child_detached)
922 gdk_pointer_ungrab (GDK_CURRENT_TIME);
924 hb->child_detached = FALSE;
925 gdk_window_hide (hb->float_window);
926 gdk_window_reparent (hb->bin_window, widget->window, 0, 0);
927 hb->float_window_mapped = FALSE;
928 gtk_signal_emit (GTK_OBJECT (hb),
929 handle_box_signals[SIGNAL_CHILD_ATTACHED],
930 GTK_BIN (hb)->child);
932 fleur = gdk_cursor_new (GDK_FLEUR);
933 while (gdk_pointer_grab (hb->bin_window,
935 (GDK_BUTTON1_MOTION_MASK |
936 GDK_POINTER_MOTION_HINT_MASK |
937 GDK_BUTTON_RELEASE_MASK),
940 GDK_CURRENT_TIME) != 0); /* wait for success */
941 gdk_cursor_destroy (fleur);
943 gtk_widget_queue_resize (widget);
948 if (hb->child_detached)
950 gdk_window_move (hb->float_window, new_x, new_y);
951 gdk_window_raise (hb->float_window);
958 gdk_pointer_ungrab (GDK_CURRENT_TIME);
960 hb->child_detached = TRUE;
963 gdk_window_get_size (hb->bin_window, &width, &height);
964 gdk_window_move_resize (hb->float_window, new_x, new_y, width, height);
965 gdk_window_reparent (hb->bin_window, hb->float_window, 0, 0);
966 gdk_window_set_hints (hb->float_window, new_x, new_y, 0, 0, 0, 0, GDK_HINT_POS);
967 gdk_window_show (hb->float_window);
968 hb->float_window_mapped = TRUE;
970 /* this extra move is neccessary if we use decorations, or our
971 * window manager insists on decorations.
974 gdk_window_move (hb->float_window, new_x, new_y);
977 gtk_signal_emit (GTK_OBJECT (hb),
978 handle_box_signals[SIGNAL_CHILD_DETACHED],
979 GTK_BIN (hb)->child);
980 gtk_handle_box_draw_ghost (hb);
982 fleur = gdk_cursor_new (GDK_FLEUR);
983 while (gdk_pointer_grab (hb->bin_window,
985 (GDK_BUTTON1_MOTION_MASK |
986 GDK_POINTER_MOTION_HINT_MASK |
987 GDK_BUTTON_RELEASE_MASK),
990 GDK_CURRENT_TIME) != 0); /* wait for success */
991 gdk_cursor_destroy (fleur);
993 gtk_widget_queue_resize (widget);
1001 gtk_handle_box_add (GtkContainer *container,
1004 g_return_if_fail (GTK_IS_HANDLE_BOX (container));
1005 g_return_if_fail (GTK_BIN (container)->child == NULL);
1006 g_return_if_fail (widget->parent == NULL);
1008 gtk_widget_set_parent_window (widget, GTK_HANDLE_BOX (container)->bin_window);
1009 GTK_CONTAINER_CLASS (parent_class)->add (container, widget);
1013 gtk_handle_box_remove (GtkContainer *container,
1018 g_return_if_fail (GTK_IS_HANDLE_BOX (container));
1019 g_return_if_fail (GTK_BIN (container)->child == widget);
1021 hb = GTK_HANDLE_BOX (container);
1023 if (hb->child_detached)
1025 hb->child_detached = FALSE;
1026 if (GTK_WIDGET_REALIZED (hb))
1028 gdk_window_hide (hb->float_window);
1029 gdk_window_reparent (hb->bin_window, GTK_WIDGET (hb)->window, 0, 0);
1031 hb->float_window_mapped = FALSE;
1035 gdk_pointer_ungrab (GDK_CURRENT_TIME);
1036 gtk_grab_remove (GTK_WIDGET (container));
1037 hb->in_drag = FALSE;
1040 GTK_CONTAINER_CLASS (parent_class)->remove (container, widget);
1044 gtk_handle_box_delete_event (GtkWidget *widget,
1049 g_return_val_if_fail (widget != NULL, FALSE);
1050 g_return_val_if_fail (GTK_IS_HANDLE_BOX (widget), FALSE);
1051 g_return_val_if_fail (event != NULL, FALSE);
1053 hb = GTK_HANDLE_BOX (widget);
1054 g_return_val_if_fail (event->window == hb->float_window, FALSE);
1056 hb->child_detached = FALSE;
1057 gdk_window_hide (hb->float_window);
1058 gdk_window_reparent (hb->bin_window, widget->window, 0, 0);
1059 hb->float_window_mapped = FALSE;
1060 gtk_signal_emit (GTK_OBJECT (hb),
1061 handle_box_signals[SIGNAL_CHILD_ATTACHED],
1062 GTK_BIN (hb)->child);
1065 gdk_pointer_ungrab (GDK_CURRENT_TIME);
1066 gtk_grab_remove (widget);
1067 hb->in_drag = FALSE;
1070 gtk_widget_queue_resize (GTK_WIDGET (hb));