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));
311 gdk_window_set_back_pixmap (widget->window, NULL, TRUE);
315 gtk_handle_box_unrealize (GtkWidget *widget)
319 g_return_if_fail (widget != NULL);
320 g_return_if_fail (GTK_IS_HANDLE_BOX (widget));
322 hb = GTK_HANDLE_BOX (widget);
324 gdk_window_set_user_data (hb->bin_window, NULL);
325 gdk_window_destroy (hb->bin_window);
326 hb->bin_window = NULL;
327 gdk_window_set_user_data (hb->float_window, NULL);
328 gdk_window_destroy (hb->float_window);
329 hb->float_window = NULL;
331 if (GTK_WIDGET_CLASS (parent_class)->unrealize)
332 (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
336 gtk_handle_box_style_set (GtkWidget *widget,
337 GtkStyle *previous_style)
341 g_return_if_fail (widget != NULL);
342 g_return_if_fail (GTK_IS_HANDLE_BOX (widget));
344 hb = GTK_HANDLE_BOX (widget);
346 if (GTK_WIDGET_REALIZED (widget) &&
347 !GTK_WIDGET_NO_WINDOW (widget))
349 gtk_style_set_background (widget->style, widget->window,
351 gtk_style_set_background (widget->style, hb->bin_window, widget->state);
352 gtk_style_set_background (widget->style, hb->float_window, widget->state);
353 if (GTK_WIDGET_DRAWABLE (widget))
354 gdk_window_clear (widget->window);
359 gtk_handle_box_size_request (GtkWidget *widget,
360 GtkRequisition *requisition)
365 g_return_if_fail (widget != NULL);
366 g_return_if_fail (GTK_IS_HANDLE_BOX (widget));
367 g_return_if_fail (requisition != NULL);
369 bin = GTK_BIN (widget);
370 hb = GTK_HANDLE_BOX (widget);
372 if (hb->handle_position == GTK_POS_LEFT ||
373 hb->handle_position == GTK_POS_RIGHT)
375 requisition->width = DRAG_HANDLE_SIZE;
376 requisition->height = 0;
380 requisition->width = 0;
381 requisition->height = DRAG_HANDLE_SIZE;
384 /* if our child is not visible, we still request its size, since we
385 * won't have any usefull hint for our size otherwise.
388 gtk_widget_size_request (bin->child, &bin->child->requisition);
390 if (hb->child_detached)
392 if (!hb->shrink_on_detach)
394 if (hb->handle_position == GTK_POS_LEFT ||
395 hb->handle_position == GTK_POS_RIGHT)
396 requisition->height += bin->child->requisition.height;
398 requisition->width += bin->child->requisition.width;
402 if (hb->handle_position == GTK_POS_LEFT ||
403 hb->handle_position == GTK_POS_RIGHT)
404 requisition->height += widget->style->klass->ythickness;
406 requisition->width += widget->style->klass->xthickness;
411 requisition->width += GTK_CONTAINER (widget)->border_width * 2;
412 requisition->height += GTK_CONTAINER (widget)->border_width * 2;
416 requisition->width += bin->child->requisition.width;
417 requisition->height += bin->child->requisition.height;
421 requisition->width += CHILDLESS_SIZE;
422 requisition->height += CHILDLESS_SIZE;
428 gtk_handle_box_size_allocate (GtkWidget *widget,
429 GtkAllocation *allocation)
434 g_return_if_fail (widget != NULL);
435 g_return_if_fail (GTK_IS_HANDLE_BOX (widget));
436 g_return_if_fail (allocation != NULL);
438 bin = GTK_BIN (widget);
439 hb = GTK_HANDLE_BOX (widget);
441 widget->allocation.x = allocation->x;
443 if (hb->child_detached)
445 guint max_req_height;
448 max_req_height = MAX (widget->requisition.height,
449 bin->child->requisition.height +
450 2 * widget->style->klass->ythickness);
451 max_req_width = MAX (widget->requisition.width,
452 bin->child->requisition.width +
453 2 * widget->style->klass->xthickness);
455 if (allocation->height > max_req_height)
456 widget->allocation.y = allocation->y +
457 (allocation->height - max_req_height) / 2;
459 widget->allocation.y = allocation->y;
461 widget->allocation.height = MIN (allocation->height, max_req_height);
462 widget->allocation.width = MIN (allocation->width, max_req_width);
466 widget->allocation = *allocation;
469 if (GTK_WIDGET_REALIZED (hb))
470 gdk_window_move_resize (widget->window,
471 widget->allocation.x,
472 widget->allocation.y,
473 widget->allocation.width,
474 widget->allocation.height);
477 if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
480 GtkAllocation child_allocation;
484 border_width = GTK_CONTAINER (widget)->border_width;
486 child_allocation.x = border_width;
487 child_allocation.y = border_width;
488 if (hb->handle_position == GTK_POS_LEFT)
489 child_allocation.x += DRAG_HANDLE_SIZE;
490 else if (hb->handle_position == GTK_POS_TOP)
491 child_allocation.y += DRAG_HANDLE_SIZE;
493 if (hb->child_detached)
498 child_allocation.width = child->requisition.width;
499 child_allocation.height = child->requisition.height;
501 float_width = child_allocation.width + 2 * border_width;
502 float_height = child_allocation.height + 2 * border_width;
504 if (hb->handle_position == GTK_POS_LEFT ||
505 hb->handle_position == GTK_POS_RIGHT)
506 float_width += DRAG_HANDLE_SIZE;
508 float_height += DRAG_HANDLE_SIZE;
510 if (GTK_WIDGET_REALIZED (hb))
512 gdk_window_resize (hb->float_window,
515 gdk_window_move_resize (hb->bin_window,
524 child_allocation.width = MAX (1, widget->allocation.width - 2 * border_width);
525 child_allocation.height = MAX (1, widget->allocation.height - 2 * border_width);
527 if (hb->handle_position == GTK_POS_LEFT ||
528 hb->handle_position == GTK_POS_RIGHT)
529 child_allocation.width -= DRAG_HANDLE_SIZE;
531 child_allocation.height -= DRAG_HANDLE_SIZE;
533 if (GTK_WIDGET_REALIZED (hb))
534 gdk_window_move_resize (hb->bin_window,
537 widget->allocation.width,
538 widget->allocation.height);
541 gtk_widget_size_allocate (bin->child, &child_allocation);
546 gtk_handle_box_draw_ghost (GtkHandleBox *hb)
554 widget = GTK_WIDGET (hb);
556 if (hb->handle_position == GTK_POS_LEFT ||
557 hb->handle_position == GTK_POS_RIGHT)
559 x = hb->handle_position == GTK_POS_LEFT ? 0 : widget->allocation.width;
561 width = DRAG_HANDLE_SIZE;
562 height = widget->allocation.height;
567 y = hb->handle_position == GTK_POS_TOP ? 0 : widget->allocation.height;
568 width = widget->allocation.width;
569 height = DRAG_HANDLE_SIZE;
571 gtk_paint_shadow (widget->style,
573 GTK_WIDGET_STATE (widget),
574 GTK_SHADOW_ETCHED_IN,
575 NULL, widget, "handle",
580 if (hb->handle_position == GTK_POS_LEFT ||
581 hb->handle_position == GTK_POS_RIGHT)
582 gtk_paint_hline (widget->style,
584 GTK_WIDGET_STATE (widget),
585 NULL, widget, "handlebox",
586 hb->handle_position == GTK_POS_LEFT ? DRAG_HANDLE_SIZE : widget->allocation.width - DRAG_HANDLE_SIZE,
587 widget->allocation.width - DRAG_HANDLE_SIZE,
588 widget->allocation.height / 2);
590 gtk_paint_vline (widget->style,
592 GTK_WIDGET_STATE (widget),
593 NULL, widget, "handlebox",
594 hb->handle_position == GTK_POS_TOP ? DRAG_HANDLE_SIZE : widget->allocation.height - DRAG_HANDLE_SIZE,
595 widget->allocation.height - DRAG_HANDLE_SIZE,
596 widget->allocation.width / 2);
600 draw_textured_frame (GtkWidget *widget, GdkWindow *window, GdkRectangle *rect, GtkShadowType shadow,
603 gtk_paint_handle(widget->style, window, GTK_STATE_NORMAL, shadow,
604 NULL, widget, "handlebox",
605 rect->x, rect->y, rect->width, rect->height,
606 GTK_ORIENTATION_VERTICAL);
610 gtk_handle_box_paint (GtkWidget *widget,
611 GdkEventExpose *event,
621 bin = GTK_BIN (widget);
622 hb = GTK_HANDLE_BOX (widget);
624 border_width = GTK_CONTAINER (hb)->border_width;
626 if (hb->child_detached)
628 width = bin->child->allocation.width + 2 * border_width;
629 height = bin->child->allocation.height + 2 * border_width;
631 else if (hb->handle_position == GTK_POS_LEFT ||
632 hb->handle_position == GTK_POS_RIGHT)
634 width = widget->allocation.width - DRAG_HANDLE_SIZE;
635 height = widget->allocation.height;
639 width = widget->allocation.width;
640 height = widget->allocation.height - DRAG_HANDLE_SIZE;
644 gtk_paint_box(widget->style,
646 GTK_WIDGET_STATE (widget),
648 area, widget, "handlebox_bin",
651 gtk_paint_box(widget->style,
653 GTK_WIDGET_STATE (widget),
655 &event->area, widget, "handlebox_bin",
658 /* We currently draw the handle _above_ the relief of the handlebox.
659 * it could also be drawn on the same level...
661 hb->handle_position == GTK_POS_LEFT ? DRAG_HANDLE_SIZE : 0,
662 hb->handle_position == GTK_POS_TOP ? DRAG_HANDLE_SIZE : 0,
668 rect.width = (hb->handle_position == GTK_POS_LEFT) ? DRAG_HANDLE_SIZE : width;
669 rect.height = (hb->handle_position == GTK_POS_TOP) ? DRAG_HANDLE_SIZE : height;
671 draw_textured_frame (widget, hb->bin_window, &rect, GTK_SHADOW_OUT, event ? &event->area : area);
673 if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
675 GdkRectangle child_area;
676 GdkEventExpose child_event;
678 if (!event) /* we were called from draw() */
680 if (gtk_widget_intersect (bin->child, area, &child_area))
681 gtk_widget_draw (bin->child, &child_area);
683 else /* we were called from expose() */
685 child_event = *event;
687 if (GTK_WIDGET_NO_WINDOW (bin->child) &&
688 gtk_widget_intersect (bin->child, &event->area, &child_event.area))
689 gtk_widget_event (bin->child, (GdkEvent *) &child_event);
695 gtk_handle_box_draw (GtkWidget *widget,
700 g_return_if_fail (widget != NULL);
701 g_return_if_fail (GTK_IS_HANDLE_BOX (widget));
702 g_return_if_fail (area != NULL);
704 hb = GTK_HANDLE_BOX (widget);
706 if (GTK_WIDGET_DRAWABLE (widget))
708 if (hb->child_detached)
710 /* The area parameter does not make sense in this case, so we
711 * repaint everything.
714 gtk_handle_box_draw_ghost (hb);
718 area->width = 2 * GTK_CONTAINER (hb)->border_width + DRAG_HANDLE_SIZE;
719 area->height = area->width + GTK_BIN (hb)->child->allocation.height;
720 area->width += GTK_BIN (hb)->child->allocation.width;
722 gtk_handle_box_paint (widget, NULL, area);
725 gtk_handle_box_paint (widget, NULL, area);
730 gtk_handle_box_expose (GtkWidget *widget,
731 GdkEventExpose *event)
735 g_return_val_if_fail (widget != NULL, FALSE);
736 g_return_val_if_fail (GTK_IS_HANDLE_BOX (widget), FALSE);
737 g_return_val_if_fail (event != NULL, FALSE);
739 if (GTK_WIDGET_DRAWABLE (widget))
741 hb = GTK_HANDLE_BOX (widget);
743 if (event->window == widget->window)
745 if (hb->child_detached)
746 gtk_handle_box_draw_ghost (hb);
749 gtk_handle_box_paint (widget, event, NULL);
756 gtk_handle_box_button_changed (GtkWidget *widget,
757 GdkEventButton *event)
760 gboolean event_handled;
763 g_return_val_if_fail (widget != NULL, FALSE);
764 g_return_val_if_fail (GTK_IS_HANDLE_BOX (widget), FALSE);
765 g_return_val_if_fail (event != NULL, FALSE);
767 hb = GTK_HANDLE_BOX (widget);
769 if (event->window != hb->bin_window)
772 event_handled = FALSE;
773 if (event->button == 1 &&
774 event->type == GDK_BUTTON_PRESS)
779 child = GTK_BIN (hb)->child;
781 switch (hb->handle_position)
784 in_handle = event->x < DRAG_HANDLE_SIZE;
787 in_handle = event->y < DRAG_HANDLE_SIZE;
790 in_handle = event->x > 2 * GTK_CONTAINER (hb)->border_width + child->allocation.width;
793 in_handle = event->y > 2 * GTK_CONTAINER (hb)->border_width + child->allocation.height;
803 event_handled = TRUE;
808 hb->dragoff_x = event->x;
809 hb->dragoff_y = event->y;
811 gtk_grab_add (widget);
813 fleur = gdk_cursor_new (GDK_FLEUR);
814 while (gdk_pointer_grab (hb->bin_window,
816 (GDK_BUTTON1_MOTION_MASK |
817 GDK_POINTER_MOTION_HINT_MASK |
818 GDK_BUTTON_RELEASE_MASK),
821 GDK_CURRENT_TIME) != 0); /* wait for success */
822 gdk_cursor_destroy (fleur);
823 event_handled = TRUE;
826 else if (event->type == GDK_BUTTON_RELEASE &&
829 gdk_pointer_ungrab (GDK_CURRENT_TIME);
830 gtk_grab_remove (widget);
832 event_handled = TRUE;
835 return event_handled;
839 gtk_handle_box_motion (GtkWidget *widget,
840 GdkEventMotion *event)
849 g_return_val_if_fail (widget != NULL, FALSE);
850 g_return_val_if_fail (GTK_IS_HANDLE_BOX (widget), FALSE);
851 g_return_val_if_fail (event != NULL, FALSE);
853 hb = GTK_HANDLE_BOX (widget);
857 if (event->window != hb->bin_window)
862 gdk_window_get_deskrelative_origin (hb->float_window, &ox, &oy);
865 gdk_window_get_pointer (hb->float_window, &new_x, &new_y, NULL);
868 new_x -= hb->dragoff_x;
869 new_y -= hb->dragoff_y;
872 gdk_window_get_pointer (widget->window, &snap_x, &snap_y, NULL);
874 switch (hb->handle_position)
877 in_handle = (snap_x >= 0 && snap_x <= DRAG_HANDLE_SIZE &&
878 snap_y >= 0 && snap_y <= widget->allocation.height);
881 in_handle = (snap_x >= 0 && snap_x <= widget->allocation.width &&
882 snap_y >= 0 && snap_y <= DRAG_HANDLE_SIZE);
885 in_handle = (snap_x >= widget->allocation.width - DRAG_HANDLE_SIZE && snap_x <= widget->allocation.width &&
886 snap_y >= 0 && snap_y <= widget->allocation.height);
889 in_handle = (snap_x >= 0 && snap_x <= widget->allocation.width &&
890 snap_y >= widget->allocation.height - DRAG_HANDLE_SIZE && snap_y <= widget->allocation.height);
899 if (hb->child_detached)
901 gdk_pointer_ungrab (GDK_CURRENT_TIME);
903 hb->child_detached = FALSE;
904 gdk_window_hide (hb->float_window);
905 gdk_window_reparent (hb->bin_window, widget->window, 0, 0);
906 hb->float_window_mapped = FALSE;
907 gtk_signal_emit (GTK_OBJECT (hb),
908 handle_box_signals[SIGNAL_CHILD_ATTACHED],
909 GTK_BIN (hb)->child);
911 fleur = gdk_cursor_new (GDK_FLEUR);
912 while (gdk_pointer_grab (hb->bin_window,
914 (GDK_BUTTON1_MOTION_MASK |
915 GDK_POINTER_MOTION_HINT_MASK |
916 GDK_BUTTON_RELEASE_MASK),
919 GDK_CURRENT_TIME) != 0); /* wait for success */
920 gdk_cursor_destroy (fleur);
922 gtk_widget_queue_resize (widget);
927 if (hb->child_detached)
929 gdk_window_move (hb->float_window, new_x, new_y);
930 gdk_window_raise (hb->float_window);
937 gdk_pointer_ungrab (GDK_CURRENT_TIME);
939 hb->child_detached = TRUE;
942 gdk_window_get_size (hb->bin_window, &width, &height);
943 gdk_window_move_resize (hb->float_window, new_x, new_y, width, height);
944 gdk_window_reparent (hb->bin_window, hb->float_window, 0, 0);
945 gdk_window_set_hints (hb->float_window, new_x, new_y, 0, 0, 0, 0, GDK_HINT_POS);
946 gdk_window_show (hb->float_window);
947 hb->float_window_mapped = TRUE;
949 /* this extra move is neccessary if we use decorations, or our
950 * window manager insists on decorations.
953 gdk_window_move (hb->float_window, new_x, new_y);
956 gtk_signal_emit (GTK_OBJECT (hb),
957 handle_box_signals[SIGNAL_CHILD_DETACHED],
958 GTK_BIN (hb)->child);
959 gtk_handle_box_draw_ghost (hb);
961 fleur = gdk_cursor_new (GDK_FLEUR);
962 while (gdk_pointer_grab (hb->bin_window,
964 (GDK_BUTTON1_MOTION_MASK |
965 GDK_POINTER_MOTION_HINT_MASK |
966 GDK_BUTTON_RELEASE_MASK),
969 GDK_CURRENT_TIME) != 0); /* wait for success */
970 gdk_cursor_destroy (fleur);
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));