1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
19 * GtkLayout: Widget for scrolling of arbitrary-sized areas.
21 * Copyright Owen Taylor, 1998
25 * Modified by the GTK+ Team and others 1997-1999. See the AUTHORS
26 * file for a list of people on the GTK+ Team. See the ChangeLog
27 * files for a list of changes. These files are distributed with
28 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
33 #include "gtklayout.h"
34 #include "gtksignal.h"
35 #include "gtkprivate.h"
37 typedef struct _GtkLayoutAdjData GtkLayoutAdjData;
38 typedef struct _GtkLayoutChild GtkLayoutChild;
40 struct _GtkLayoutAdjData {
45 struct _GtkLayoutChild {
51 #define IS_ONSCREEN(x,y) ((x >= G_MINSHORT) && (x <= G_MAXSHORT) && \
52 (y >= G_MINSHORT) && (y <= G_MAXSHORT))
54 static void gtk_layout_class_init (GtkLayoutClass *class);
55 static void gtk_layout_init (GtkLayout *layout);
57 static void gtk_layout_realize (GtkWidget *widget);
58 static void gtk_layout_unrealize (GtkWidget *widget);
59 static void gtk_layout_map (GtkWidget *widget);
60 static void gtk_layout_size_request (GtkWidget *widget,
61 GtkRequisition *requisition);
62 static void gtk_layout_size_allocate (GtkWidget *widget,
63 GtkAllocation *allocation);
64 static void gtk_layout_draw (GtkWidget *widget,
66 static gint gtk_layout_expose (GtkWidget *widget,
67 GdkEventExpose *event);
69 static void gtk_layout_remove (GtkContainer *container,
71 static void gtk_layout_forall (GtkContainer *container,
72 gboolean include_internals,
74 gpointer callback_data);
75 static void gtk_layout_set_adjustments (GtkLayout *layout,
79 static void gtk_layout_position_child (GtkLayout *layout,
80 GtkLayoutChild *child);
81 static void gtk_layout_allocate_child (GtkLayout *layout,
82 GtkLayoutChild *child);
83 static void gtk_layout_position_children (GtkLayout *layout);
85 static void gtk_layout_adjust_allocations_recurse (GtkWidget *widget,
87 static void gtk_layout_adjust_allocations (GtkLayout *layout,
93 static void gtk_layout_expose_area (GtkLayout *layout,
98 static void gtk_layout_adjustment_changed (GtkAdjustment *adjustment,
100 static GdkFilterReturn gtk_layout_filter (GdkXEvent *gdk_xevent,
103 static GdkFilterReturn gtk_layout_main_filter (GdkXEvent *gdk_xevent,
107 static GtkWidgetClass *parent_class = NULL;
108 static gboolean gravity_works;
114 gtk_layout_new (GtkAdjustment *hadjustment,
115 GtkAdjustment *vadjustment)
119 layout = gtk_type_new (GTK_TYPE_LAYOUT);
121 gtk_layout_set_adjustments (layout, hadjustment, vadjustment);
123 return GTK_WIDGET (layout);
127 gtk_layout_get_hadjustment (GtkLayout *layout)
129 g_return_val_if_fail (layout != NULL, NULL);
130 g_return_val_if_fail (GTK_IS_LAYOUT (layout), NULL);
132 return layout->hadjustment;
135 gtk_layout_get_vadjustment (GtkLayout *layout)
137 g_return_val_if_fail (layout != NULL, NULL);
138 g_return_val_if_fail (GTK_IS_LAYOUT (layout), NULL);
140 return layout->vadjustment;
144 gtk_layout_set_adjustments (GtkLayout *layout,
148 gboolean need_adjust = FALSE;
150 g_return_if_fail (layout != NULL);
151 g_return_if_fail (GTK_IS_LAYOUT (layout));
154 g_return_if_fail (GTK_IS_ADJUSTMENT (hadj));
156 hadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
158 g_return_if_fail (GTK_IS_ADJUSTMENT (vadj));
160 vadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
162 if (layout->hadjustment && (layout->hadjustment != hadj))
164 gtk_signal_disconnect_by_data (GTK_OBJECT (layout->hadjustment), layout);
165 gtk_object_unref (GTK_OBJECT (layout->hadjustment));
168 if (layout->vadjustment && (layout->vadjustment != vadj))
170 gtk_signal_disconnect_by_data (GTK_OBJECT (layout->vadjustment), layout);
171 gtk_object_unref (GTK_OBJECT (layout->vadjustment));
174 if (layout->hadjustment != hadj)
176 layout->hadjustment = hadj;
177 gtk_object_ref (GTK_OBJECT (layout->hadjustment));
178 gtk_object_sink (GTK_OBJECT (layout->hadjustment));
180 gtk_signal_connect (GTK_OBJECT (layout->hadjustment), "value_changed",
181 (GtkSignalFunc) gtk_layout_adjustment_changed,
186 if (layout->vadjustment != vadj)
188 layout->vadjustment = vadj;
189 gtk_object_ref (GTK_OBJECT (layout->vadjustment));
190 gtk_object_sink (GTK_OBJECT (layout->vadjustment));
192 gtk_signal_connect (GTK_OBJECT (layout->vadjustment), "value_changed",
193 (GtkSignalFunc) gtk_layout_adjustment_changed,
199 gtk_layout_adjustment_changed (NULL, layout);
203 gtk_layout_set_hadjustment (GtkLayout *layout,
204 GtkAdjustment *adjustment)
206 g_return_if_fail (layout != NULL);
207 g_return_if_fail (GTK_IS_LAYOUT (layout));
209 gtk_layout_set_adjustments (layout, adjustment, layout->vadjustment);
214 gtk_layout_set_vadjustment (GtkLayout *layout,
215 GtkAdjustment *adjustment)
217 g_return_if_fail (layout != NULL);
218 g_return_if_fail (GTK_IS_LAYOUT (layout));
220 gtk_layout_set_adjustments (layout, layout->hadjustment, adjustment);
225 gtk_layout_put (GtkLayout *layout,
226 GtkWidget *child_widget,
230 GtkLayoutChild *child;
232 g_return_if_fail (layout != NULL);
233 g_return_if_fail (GTK_IS_LAYOUT (layout));
234 g_return_if_fail (child_widget != NULL);
235 g_return_if_fail (GTK_IS_WIDGET (child_widget));
237 child = g_new (GtkLayoutChild, 1);
239 child->widget = child_widget;
243 layout->children = g_list_append (layout->children, child);
245 gtk_widget_set_parent (child_widget, GTK_WIDGET (layout));
246 if (GTK_WIDGET_REALIZED (layout))
247 gtk_widget_set_parent_window (child->widget, layout->bin_window);
249 if (!IS_ONSCREEN (x, y))
250 GTK_PRIVATE_SET_FLAG (child_widget, GTK_IS_OFFSCREEN);
252 if (GTK_WIDGET_VISIBLE (layout))
254 if (GTK_WIDGET_REALIZED (layout) &&
255 !GTK_WIDGET_REALIZED (child_widget))
256 gtk_widget_realize (child_widget);
258 if (GTK_WIDGET_MAPPED (layout) &&
259 !GTK_WIDGET_MAPPED (child_widget))
260 gtk_widget_map (child_widget);
263 if (GTK_WIDGET_VISIBLE (child_widget) && GTK_WIDGET_VISIBLE (layout))
264 gtk_widget_queue_resize (child_widget);
268 gtk_layout_move (GtkLayout *layout,
269 GtkWidget *child_widget,
274 GtkLayoutChild *child;
276 g_return_if_fail (layout != NULL);
277 g_return_if_fail (GTK_IS_LAYOUT (layout));
279 tmp_list = layout->children;
282 child = tmp_list->data;
283 tmp_list = tmp_list->next;
285 if (child->widget == child_widget)
290 if (GTK_WIDGET_VISIBLE (child_widget) && GTK_WIDGET_VISIBLE (layout))
291 gtk_widget_queue_resize (child_widget);
299 gtk_layout_set_size (GtkLayout *layout,
303 g_return_if_fail (layout != NULL);
304 g_return_if_fail (GTK_IS_LAYOUT (layout));
306 layout->width = width;
307 layout->height = height;
309 layout->hadjustment->upper = layout->width;
310 gtk_signal_emit_by_name (GTK_OBJECT (layout->hadjustment), "changed");
312 layout->vadjustment->upper = layout->height;
313 gtk_signal_emit_by_name (GTK_OBJECT (layout->vadjustment), "changed");
317 gtk_layout_freeze (GtkLayout *layout)
319 g_return_if_fail (layout != NULL);
320 g_return_if_fail (GTK_IS_LAYOUT (layout));
322 layout->freeze_count++;
326 gtk_layout_thaw (GtkLayout *layout)
328 g_return_if_fail (layout != NULL);
329 g_return_if_fail (GTK_IS_LAYOUT (layout));
331 if (layout->freeze_count)
332 if (!(--layout->freeze_count))
334 gtk_layout_position_children (layout);
335 gtk_widget_draw (GTK_WIDGET (layout), NULL);
339 /* Basic Object handling procedures
342 gtk_layout_get_type (void)
344 static GtkType layout_type = 0;
348 static const GtkTypeInfo layout_info =
352 sizeof (GtkLayoutClass),
353 (GtkClassInitFunc) gtk_layout_class_init,
354 (GtkObjectInitFunc) gtk_layout_init,
355 (GtkArgSetFunc) NULL,
356 (GtkArgGetFunc) NULL,
359 layout_type = gtk_type_unique (GTK_TYPE_CONTAINER, &layout_info);
366 gtk_layout_class_init (GtkLayoutClass *class)
368 GtkObjectClass *object_class;
369 GtkWidgetClass *widget_class;
370 GtkContainerClass *container_class;
372 object_class = (GtkObjectClass*) class;
373 widget_class = (GtkWidgetClass*) class;
374 container_class = (GtkContainerClass*) class;
376 parent_class = gtk_type_class (GTK_TYPE_CONTAINER);
378 widget_class->realize = gtk_layout_realize;
379 widget_class->unrealize = gtk_layout_unrealize;
380 widget_class->map = gtk_layout_map;
381 widget_class->size_request = gtk_layout_size_request;
382 widget_class->size_allocate = gtk_layout_size_allocate;
383 widget_class->draw = gtk_layout_draw;
384 widget_class->expose_event = gtk_layout_expose;
386 widget_class->set_scroll_adjustments_signal =
387 gtk_signal_new ("set_scroll_adjustments",
390 GTK_SIGNAL_OFFSET (GtkLayoutClass, set_scroll_adjustments),
391 gtk_marshal_NONE__POINTER_POINTER,
392 GTK_TYPE_NONE, 2, GTK_TYPE_ADJUSTMENT, GTK_TYPE_ADJUSTMENT);
394 container_class->remove = gtk_layout_remove;
395 container_class->forall = gtk_layout_forall;
397 class->set_scroll_adjustments = gtk_layout_set_adjustments;
401 gtk_layout_init (GtkLayout *layout)
403 layout->children = NULL;
406 layout->height = 100;
408 layout->hadjustment = NULL;
409 layout->vadjustment = NULL;
411 layout->bin_window = NULL;
413 layout->configure_serial = 0;
414 layout->scroll_x = 0;
415 layout->scroll_y = 0;
416 layout->visibility = GDK_VISIBILITY_PARTIAL;
418 layout->freeze_count = 0;
425 gtk_layout_realize (GtkWidget *widget)
429 GdkWindowAttr attributes;
430 gint attributes_mask;
432 g_return_if_fail (widget != NULL);
433 g_return_if_fail (GTK_IS_LAYOUT (widget));
435 layout = GTK_LAYOUT (widget);
436 GTK_WIDGET_SET_FLAGS (layout, GTK_REALIZED);
438 attributes.window_type = GDK_WINDOW_CHILD;
439 attributes.x = widget->allocation.x;
440 attributes.y = widget->allocation.y;
441 attributes.width = widget->allocation.width;
442 attributes.height = widget->allocation.height;
443 attributes.wclass = GDK_INPUT_OUTPUT;
444 attributes.visual = gtk_widget_get_visual (widget);
445 attributes.colormap = gtk_widget_get_colormap (widget);
446 attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK;
448 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
450 widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
451 &attributes, attributes_mask);
452 gdk_window_set_user_data (widget->window, widget);
456 attributes.event_mask = GDK_EXPOSURE_MASK |
457 gtk_widget_get_events (widget);
459 layout->bin_window = gdk_window_new (widget->window,
460 &attributes, attributes_mask);
461 gdk_window_set_user_data (layout->bin_window, widget);
463 widget->style = gtk_style_attach (widget->style, widget->window);
464 gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
465 gtk_style_set_background (widget->style, layout->bin_window, GTK_STATE_NORMAL);
467 gdk_window_add_filter (widget->window, gtk_layout_main_filter, layout);
468 gdk_window_add_filter (layout->bin_window, gtk_layout_filter, layout);
470 /* XXX: If we ever get multiple displays for GTK+, then gravity_works
471 * will have to become a widget member. Right now we just
472 * keep it as a global
474 gravity_works = gdk_window_set_static_gravities (layout->bin_window, TRUE);
476 tmp_list = layout->children;
479 GtkLayoutChild *child = tmp_list->data;
480 tmp_list = tmp_list->next;
482 gtk_widget_set_parent_window (child->widget, layout->bin_window);
487 gtk_layout_map (GtkWidget *widget)
492 g_return_if_fail (widget != NULL);
493 g_return_if_fail (GTK_IS_LAYOUT (widget));
495 layout = GTK_LAYOUT (widget);
497 GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
499 tmp_list = layout->children;
502 GtkLayoutChild *child = tmp_list->data;
503 tmp_list = tmp_list->next;
505 if (GTK_WIDGET_VISIBLE (child->widget))
507 if (!GTK_WIDGET_MAPPED (child->widget) &&
508 !GTK_WIDGET_IS_OFFSCREEN (child->widget))
509 gtk_widget_map (child->widget);
513 gdk_window_show (layout->bin_window);
514 gdk_window_show (widget->window);
518 gtk_layout_unrealize (GtkWidget *widget)
522 g_return_if_fail (widget != NULL);
523 g_return_if_fail (GTK_IS_LAYOUT (widget));
525 layout = GTK_LAYOUT (widget);
527 gdk_window_set_user_data (layout->bin_window, NULL);
528 gdk_window_destroy (layout->bin_window);
529 layout->bin_window = NULL;
531 if (GTK_WIDGET_CLASS (parent_class)->unrealize)
532 (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
536 gtk_layout_size_request (GtkWidget *widget,
537 GtkRequisition *requisition)
542 g_return_if_fail (widget != NULL);
543 g_return_if_fail (GTK_IS_LAYOUT (widget));
545 layout = GTK_LAYOUT (widget);
547 requisition->width = 0;
548 requisition->height = 0;
550 tmp_list = layout->children;
554 GtkLayoutChild *child = tmp_list->data;
555 GtkRequisition child_requisition;
557 tmp_list = tmp_list->next;
559 gtk_widget_size_request (child->widget, &child_requisition);
564 gtk_layout_size_allocate (GtkWidget *widget,
565 GtkAllocation *allocation)
570 g_return_if_fail (widget != NULL);
571 g_return_if_fail (GTK_IS_LAYOUT (widget));
573 widget->allocation = *allocation;
575 layout = GTK_LAYOUT (widget);
577 tmp_list = layout->children;
581 GtkLayoutChild *child = tmp_list->data;
582 tmp_list = tmp_list->next;
584 gtk_layout_position_child (layout, child);
585 gtk_layout_allocate_child (layout, child);
588 if (GTK_WIDGET_REALIZED (widget))
590 gdk_window_move_resize (widget->window,
591 allocation->x, allocation->y,
592 allocation->width, allocation->height);
593 gdk_window_move_resize (GTK_LAYOUT(widget)->bin_window,
595 allocation->width, allocation->height);
598 layout->hadjustment->page_size = allocation->width;
599 layout->hadjustment->page_increment = allocation->width / 2;
600 layout->hadjustment->lower = 0;
601 layout->hadjustment->upper = layout->width;
602 gtk_signal_emit_by_name (GTK_OBJECT (layout->hadjustment), "changed");
604 layout->vadjustment->page_size = allocation->height;
605 layout->vadjustment->page_increment = allocation->height / 2;
606 layout->vadjustment->lower = 0;
607 layout->vadjustment->upper = layout->height;
608 gtk_signal_emit_by_name (GTK_OBJECT (layout->vadjustment), "changed");
612 gtk_layout_draw (GtkWidget *widget, GdkRectangle *area)
616 GdkRectangle child_area;
618 g_return_if_fail (widget != NULL);
619 g_return_if_fail (GTK_IS_LAYOUT (widget));
621 layout = GTK_LAYOUT (widget);
623 /* We don't have any way of telling themes about this properly,
624 * so we just assume a background pixmap
626 if (!GTK_WIDGET_APP_PAINTABLE (widget))
627 gdk_window_clear_area (layout->bin_window,
628 area->x, area->y, area->width, area->height);
630 tmp_list = layout->children;
633 GtkLayoutChild *child = tmp_list->data;
634 tmp_list = tmp_list->next;
636 if (gtk_widget_intersect (child->widget, area, &child_area))
637 gtk_widget_draw (child->widget, &child_area);
642 gtk_layout_expose (GtkWidget *widget, GdkEventExpose *event)
646 GdkEventExpose child_event;
648 g_return_val_if_fail (widget != NULL, FALSE);
649 g_return_val_if_fail (GTK_IS_LAYOUT (widget), FALSE);
651 layout = GTK_LAYOUT (widget);
653 if (event->window != layout->bin_window)
656 tmp_list = layout->children;
659 GtkLayoutChild *child = tmp_list->data;
660 tmp_list = tmp_list->next;
662 child_event = *event;
663 if (GTK_WIDGET_DRAWABLE (child->widget) &&
664 GTK_WIDGET_NO_WINDOW (child->widget) &&
665 gtk_widget_intersect (child->widget, &event->area, &child_event.area))
666 gtk_widget_event (child->widget, (GdkEvent*) &child_event);
675 gtk_layout_remove (GtkContainer *container,
680 GtkLayoutChild *child = NULL;
682 g_return_if_fail (container != NULL);
683 g_return_if_fail (GTK_IS_LAYOUT (container));
685 layout = GTK_LAYOUT (container);
687 tmp_list = layout->children;
690 child = tmp_list->data;
691 if (child->widget == widget)
693 tmp_list = tmp_list->next;
698 gtk_widget_unparent (widget);
700 layout->children = g_list_remove_link (layout->children, tmp_list);
701 g_list_free_1 (tmp_list);
705 GTK_PRIVATE_UNSET_FLAG (widget, GTK_IS_OFFSCREEN);
709 gtk_layout_forall (GtkContainer *container,
710 gboolean include_internals,
711 GtkCallback callback,
712 gpointer callback_data)
715 GtkLayoutChild *child;
718 g_return_if_fail (container != NULL);
719 g_return_if_fail (GTK_IS_LAYOUT (container));
720 g_return_if_fail (callback != NULL);
722 layout = GTK_LAYOUT (container);
724 tmp_list = layout->children;
727 child = tmp_list->data;
728 tmp_list = tmp_list->next;
730 (* callback) (child->widget, callback_data);
734 /* Operations on children
738 gtk_layout_position_child (GtkLayout *layout,
739 GtkLayoutChild *child)
744 x = child->x - layout->xoffset;
745 y = child->y - layout->yoffset;
747 if (IS_ONSCREEN (x,y))
749 if (GTK_WIDGET_MAPPED (layout) &&
750 GTK_WIDGET_VISIBLE (child->widget))
752 if (!GTK_WIDGET_MAPPED (child->widget))
753 gtk_widget_map (child->widget);
756 if (GTK_WIDGET_IS_OFFSCREEN (child->widget))
757 GTK_PRIVATE_UNSET_FLAG (child->widget, GTK_IS_OFFSCREEN);
761 if (!GTK_WIDGET_IS_OFFSCREEN (child->widget))
762 GTK_PRIVATE_SET_FLAG (child->widget, GTK_IS_OFFSCREEN);
764 if (GTK_WIDGET_MAPPED (child->widget))
765 gtk_widget_unmap (child->widget);
770 gtk_layout_allocate_child (GtkLayout *layout,
771 GtkLayoutChild *child)
773 GtkAllocation allocation;
774 GtkRequisition requisition;
776 allocation.x = child->x - layout->xoffset;
777 allocation.y = child->y - layout->yoffset;
778 gtk_widget_get_child_requisition (child->widget, &requisition);
779 allocation.width = requisition.width;
780 allocation.height = requisition.height;
782 gtk_widget_size_allocate (child->widget, &allocation);
786 gtk_layout_position_children (GtkLayout *layout)
790 tmp_list = layout->children;
793 GtkLayoutChild *child = tmp_list->data;
794 tmp_list = tmp_list->next;
796 gtk_layout_position_child (layout, child);
801 gtk_layout_adjust_allocations_recurse (GtkWidget *widget,
804 GtkLayoutAdjData *data = cb_data;
806 widget->allocation.x += data->dx;
807 widget->allocation.y += data->dy;
809 if (GTK_WIDGET_NO_WINDOW (widget) &&
810 GTK_IS_CONTAINER (widget))
811 gtk_container_forall (GTK_CONTAINER (widget),
812 gtk_layout_adjust_allocations_recurse,
817 gtk_layout_adjust_allocations (GtkLayout *layout,
822 GtkLayoutAdjData data;
827 tmp_list = layout->children;
830 GtkLayoutChild *child = tmp_list->data;
831 tmp_list = tmp_list->next;
833 child->widget->allocation.x += dx;
834 child->widget->allocation.y += dy;
836 if (GTK_WIDGET_NO_WINDOW (child->widget) &&
837 GTK_IS_CONTAINER (child->widget))
838 gtk_container_forall (GTK_CONTAINER (child->widget),
839 gtk_layout_adjust_allocations_recurse,
846 /* Send a synthetic expose event to the widget
849 gtk_layout_expose_area (GtkLayout *layout,
850 gint x, gint y, gint width, gint height)
852 if (layout->visibility == GDK_VISIBILITY_UNOBSCURED)
854 GdkEventExpose event;
856 event.type = GDK_EXPOSE;
857 event.send_event = TRUE;
858 event.window = layout->bin_window;
863 event.area.width = width;
864 event.area.height = height;
866 gdk_window_ref (event.window);
867 gtk_widget_event (GTK_WIDGET (layout), (GdkEvent *)&event);
868 gdk_window_unref (event.window);
872 #ifdef GDK_WINDOWING_X11
874 /* This function is used to find events to process while scrolling
878 gtk_layout_expose_predicate (Display *display,
882 if ((xevent->type == Expose) ||
883 ((xevent->xany.window == *(Window *)arg) &&
884 (xevent->type == ConfigureNotify)))
892 /* This is the main routine to do the scrolling. Scrolling is
893 * done by "Guffaw" scrolling, as in the Mozilla XFE, with
894 * a few modifications.
896 * The main improvement is that we keep track of whether we
897 * are obscured or not. If not, we ignore the generated expose
898 * events and instead do the exposes ourself, without having
899 * to wait for a roundtrip to the server. This also provides
900 * a limited form of expose-event compression, since we do
901 * the affected area as one big chunk.
903 * Real expose event compression, as in the XFE, could be added
904 * here. It would help opaque drags over the region, and the
907 * Code needs to be added here to do the scrolling on machines
908 * that don't have working WindowGravity. That could be done
910 * - XCopyArea and move the windows, and accept trailing the
911 * background color. (Since it is only a fallback method)
912 * - XmHTML style. As above, but turn off expose events when
913 * not obscured and do the exposures ourself.
914 * - gzilla-style. Move the window continuously, and reset
919 gtk_layout_adjustment_changed (GtkAdjustment *adjustment,
923 #ifdef GDK_WINDOWING_X11
928 widget = GTK_WIDGET (layout);
930 dx = (gint)layout->hadjustment->value - layout->xoffset;
931 dy = (gint)layout->vadjustment->value - layout->yoffset;
933 layout->xoffset = (gint)layout->hadjustment->value;
934 layout->yoffset = (gint)layout->vadjustment->value;
936 if (layout->freeze_count)
939 if (!GTK_WIDGET_MAPPED (layout))
941 gtk_layout_position_children (layout);
945 gtk_layout_adjust_allocations (layout, -dx, -dy);
951 gdk_window_resize (layout->bin_window,
952 widget->allocation.width + dx,
953 widget->allocation.height);
954 gdk_window_move (layout->bin_window, -dx, 0);
955 gdk_window_move_resize (layout->bin_window,
957 widget->allocation.width,
958 widget->allocation.height);
965 gtk_layout_expose_area (layout,
966 MAX ((gint)widget->allocation.width - dx, 0),
968 MIN (dx, widget->allocation.width),
969 widget->allocation.height);
975 gdk_window_move_resize (layout->bin_window,
977 widget->allocation.width - dx,
978 widget->allocation.height);
979 gdk_window_move (layout->bin_window, 0, 0);
980 gdk_window_resize (layout->bin_window,
981 widget->allocation.width,
982 widget->allocation.height);
989 gtk_layout_expose_area (layout,
992 MIN (-dx, widget->allocation.width),
993 widget->allocation.height);
1000 gdk_window_resize (layout->bin_window,
1001 widget->allocation.width,
1002 widget->allocation.height + dy);
1003 gdk_window_move (layout->bin_window, 0, -dy);
1004 gdk_window_move_resize (layout->bin_window,
1006 widget->allocation.width,
1007 widget->allocation.height);
1014 gtk_layout_expose_area (layout,
1016 MAX ((gint)widget->allocation.height - dy, 0),
1017 widget->allocation.width,
1018 MIN (dy, widget->allocation.height));
1024 gdk_window_move_resize (layout->bin_window,
1026 widget->allocation.width,
1027 widget->allocation.height - dy);
1028 gdk_window_move (layout->bin_window, 0, 0);
1029 gdk_window_resize (layout->bin_window,
1030 widget->allocation.width,
1031 widget->allocation.height);
1037 gtk_layout_expose_area (layout,
1040 widget->allocation.width,
1041 MIN (-dy, (gint)widget->allocation.height));
1044 gtk_layout_position_children (layout);
1046 /* We have to make sure that all exposes from this scroll get
1047 * processed before we scroll again, or the expose events will
1048 * have invalid coordinates.
1050 * We also do expose events for other windows, since otherwise
1051 * their updating will fall behind the scrolling
1053 * This also avoids a problem in pre-1.0 GTK where filters don't
1054 * have access to configure events that were compressed.
1059 #ifdef GDK_WINDOWING_X11
1060 while (XCheckIfEvent(GDK_WINDOW_XDISPLAY (layout->bin_window),
1062 gtk_layout_expose_predicate,
1063 (XPointer)&GDK_WINDOW_XWINDOW (layout->bin_window)))
1066 GtkWidget *event_widget;
1068 if ((xevent.xany.window == GDK_WINDOW_XWINDOW (layout->bin_window)) &&
1069 (gtk_layout_filter (&xevent, &event, layout) == GDK_FILTER_REMOVE))
1072 if (xevent.type == Expose)
1074 event.expose.window = gdk_window_lookup (xevent.xany.window);
1075 gdk_window_get_user_data (event.expose.window,
1076 (gpointer *)&event_widget);
1080 event.expose.type = GDK_EXPOSE;
1081 event.expose.area.x = xevent.xexpose.x;
1082 event.expose.area.y = xevent.xexpose.y;
1083 event.expose.area.width = xevent.xexpose.width;
1084 event.expose.area.height = xevent.xexpose.height;
1085 event.expose.count = xevent.xexpose.count;
1087 gdk_window_ref (event.expose.window);
1088 gtk_widget_event (event_widget, &event);
1089 gdk_window_unref (event.expose.window);
1093 #elif defined (GDK_WINDOWING_WIN32)
1094 /* XXX Not implemented */
1098 /* The main event filter. Actually, we probably don't really need
1099 * to install this as a filter at all, since we are calling it
1100 * directly above in the expose-handling hack. But in case scrollbars
1101 * are fixed up in some manner...
1103 * This routine identifies expose events that are generated when
1104 * we've temporarily moved the bin_window_origin, and translates
1105 * them or discards them, depending on whether we are obscured
1108 static GdkFilterReturn
1109 gtk_layout_filter (GdkXEvent *gdk_xevent,
1113 #ifdef GDK_WINDOWING_X11
1118 xevent = (XEvent *)gdk_xevent;
1119 layout = GTK_LAYOUT (data);
1121 switch (xevent->type)
1124 if (xevent->xexpose.serial == layout->configure_serial)
1126 if (layout->visibility == GDK_VISIBILITY_UNOBSCURED)
1127 return GDK_FILTER_REMOVE;
1130 xevent->xexpose.x += layout->scroll_x;
1131 xevent->xexpose.y += layout->scroll_y;
1138 case ConfigureNotify:
1139 if ((xevent->xconfigure.x != 0) || (xevent->xconfigure.y != 0))
1141 layout->configure_serial = xevent->xconfigure.serial;
1142 layout->scroll_x = xevent->xconfigure.x;
1143 layout->scroll_y = xevent->xconfigure.y;
1147 #elif defined (GDK_WINDOWING_WIN32)
1148 /* XXX Not implemented */
1151 return GDK_FILTER_CONTINUE;
1154 /* Although GDK does have a GDK_VISIBILITY_NOTIFY event,
1155 * there is no corresponding event in GTK, so we have
1156 * to get the events from a filter
1158 static GdkFilterReturn
1159 gtk_layout_main_filter (GdkXEvent *gdk_xevent,
1163 #ifdef GDK_WINDOWING_X11
1167 xevent = (XEvent *)gdk_xevent;
1168 layout = GTK_LAYOUT (data);
1170 if (xevent->type == VisibilityNotify)
1172 switch (xevent->xvisibility.state)
1174 case VisibilityFullyObscured:
1175 layout->visibility = GDK_VISIBILITY_FULLY_OBSCURED;
1178 case VisibilityPartiallyObscured:
1179 layout->visibility = GDK_VISIBILITY_PARTIAL;
1182 case VisibilityUnobscured:
1183 layout->visibility = GDK_VISIBILITY_UNOBSCURED;
1187 return GDK_FILTER_REMOVE;
1189 #elif defined (GDK_WINDOWING_WIN32)
1190 /* XXX Not implemented */
1193 return GDK_FILTER_CONTINUE;