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/.
31 #include "gtklayout.h"
32 #include "gtksignal.h"
33 #include "gtkprivate.h"
36 typedef struct _GtkLayoutAdjData GtkLayoutAdjData;
37 typedef struct _GtkLayoutChild GtkLayoutChild;
39 struct _GtkLayoutAdjData {
44 struct _GtkLayoutChild {
50 #define IS_ONSCREEN(x,y) ((x >= G_MINSHORT) && (x <= G_MAXSHORT) && \
51 (y >= G_MINSHORT) && (y <= G_MAXSHORT))
53 static void gtk_layout_class_init (GtkLayoutClass *class);
54 static void gtk_layout_init (GtkLayout *layout);
56 static void gtk_layout_realize (GtkWidget *widget);
57 static void gtk_layout_unrealize (GtkWidget *widget);
58 static void gtk_layout_map (GtkWidget *widget);
59 static void gtk_layout_size_request (GtkWidget *widget,
60 GtkRequisition *requisition);
61 static void gtk_layout_size_allocate (GtkWidget *widget,
62 GtkAllocation *allocation);
63 static void gtk_layout_draw (GtkWidget *widget,
65 static gint gtk_layout_expose (GtkWidget *widget,
66 GdkEventExpose *event);
68 static void gtk_layout_remove (GtkContainer *container,
70 static void gtk_layout_forall (GtkContainer *container,
71 gboolean include_internals,
73 gpointer callback_data);
74 static void gtk_layout_set_adjustments (GtkLayout *layout,
78 static void gtk_layout_position_child (GtkLayout *layout,
79 GtkLayoutChild *child);
80 static void gtk_layout_allocate_child (GtkLayout *layout,
81 GtkLayoutChild *child);
82 static void gtk_layout_position_children (GtkLayout *layout);
84 static void gtk_layout_adjust_allocations_recurse (GtkWidget *widget,
86 static void gtk_layout_adjust_allocations (GtkLayout *layout,
92 static void gtk_layout_expose_area (GtkLayout *layout,
97 static void gtk_layout_adjustment_changed (GtkAdjustment *adjustment,
99 static GdkFilterReturn gtk_layout_filter (GdkXEvent *gdk_xevent,
102 static GdkFilterReturn gtk_layout_main_filter (GdkXEvent *gdk_xevent,
106 static gboolean gtk_layout_gravity_works (void);
107 static void gtk_layout_set_static_gravity (GdkWindow *win,
111 static void gtk_layout_add_child_cb (GdkWindow *parent,
114 static void gtk_layout_remove_child_cb (GdkWindow *parent,
119 static GtkWidgetClass *parent_class = NULL;
120 static gboolean gravity_works;
126 gtk_layout_new (GtkAdjustment *hadjustment,
127 GtkAdjustment *vadjustment)
131 layout = gtk_type_new (GTK_TYPE_LAYOUT);
133 gtk_layout_set_adjustments (layout, hadjustment, vadjustment);
135 return GTK_WIDGET (layout);
139 gtk_layout_get_hadjustment (GtkLayout *layout)
141 g_return_val_if_fail (layout != NULL, NULL);
142 g_return_val_if_fail (GTK_IS_LAYOUT (layout), NULL);
144 return layout->hadjustment;
147 gtk_layout_get_vadjustment (GtkLayout *layout)
149 g_return_val_if_fail (layout != NULL, NULL);
150 g_return_val_if_fail (GTK_IS_LAYOUT (layout), NULL);
152 return layout->vadjustment;
156 gtk_layout_set_adjustments (GtkLayout *layout,
160 gboolean need_adjust = FALSE;
162 g_return_if_fail (layout != NULL);
163 g_return_if_fail (GTK_IS_LAYOUT (layout));
166 g_return_if_fail (GTK_IS_ADJUSTMENT (hadj));
168 hadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
170 g_return_if_fail (GTK_IS_ADJUSTMENT (vadj));
172 vadj = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0));
174 if (layout->hadjustment && (layout->hadjustment != hadj))
176 gtk_signal_disconnect_by_data (GTK_OBJECT (layout->hadjustment), layout);
177 gtk_object_unref (GTK_OBJECT (layout->hadjustment));
180 if (layout->vadjustment && (layout->vadjustment != vadj))
182 gtk_signal_disconnect_by_data (GTK_OBJECT (layout->vadjustment), layout);
183 gtk_object_unref (GTK_OBJECT (layout->vadjustment));
186 if (layout->hadjustment != hadj)
188 layout->hadjustment = hadj;
189 gtk_object_ref (GTK_OBJECT (layout->hadjustment));
190 gtk_object_sink (GTK_OBJECT (layout->hadjustment));
192 gtk_signal_connect (GTK_OBJECT (layout->hadjustment), "value_changed",
193 (GtkSignalFunc) gtk_layout_adjustment_changed,
198 if (layout->vadjustment != vadj)
200 layout->vadjustment = vadj;
201 gtk_object_ref (GTK_OBJECT (layout->vadjustment));
202 gtk_object_sink (GTK_OBJECT (layout->vadjustment));
204 gtk_signal_connect (GTK_OBJECT (layout->vadjustment), "value_changed",
205 (GtkSignalFunc) gtk_layout_adjustment_changed,
211 gtk_layout_adjustment_changed (NULL, layout);
215 gtk_layout_set_hadjustment (GtkLayout *layout,
216 GtkAdjustment *adjustment)
218 g_return_if_fail (layout != NULL);
219 g_return_if_fail (GTK_IS_LAYOUT (layout));
221 gtk_layout_set_adjustments (layout, adjustment, layout->vadjustment);
226 gtk_layout_set_vadjustment (GtkLayout *layout,
227 GtkAdjustment *adjustment)
229 g_return_if_fail (layout != NULL);
230 g_return_if_fail (GTK_IS_LAYOUT (layout));
232 gtk_layout_set_adjustments (layout, layout->hadjustment, adjustment);
237 gtk_layout_put (GtkLayout *layout,
238 GtkWidget *child_widget,
242 GtkLayoutChild *child;
244 g_return_if_fail (layout != NULL);
245 g_return_if_fail (GTK_IS_LAYOUT (layout));
246 g_return_if_fail (child_widget != NULL);
247 g_return_if_fail (GTK_IS_WIDGET (child_widget));
249 child = g_new (GtkLayoutChild, 1);
251 child->widget = child_widget;
255 layout->children = g_list_append (layout->children, child);
257 gtk_widget_set_parent (child_widget, GTK_WIDGET (layout));
258 if (GTK_WIDGET_REALIZED (layout))
259 gtk_widget_set_parent_window (child->widget, layout->bin_window);
261 if (!IS_ONSCREEN (x, y))
262 GTK_PRIVATE_SET_FLAG (child_widget, GTK_IS_OFFSCREEN);
264 if (GTK_WIDGET_VISIBLE (layout))
266 if (GTK_WIDGET_REALIZED (layout) &&
267 !GTK_WIDGET_REALIZED (child_widget))
268 gtk_widget_realize (child_widget);
270 if (GTK_WIDGET_MAPPED (layout) &&
271 !GTK_WIDGET_MAPPED (child_widget))
272 gtk_widget_map (child_widget);
275 if (GTK_WIDGET_VISIBLE (child_widget) && GTK_WIDGET_VISIBLE (layout))
276 gtk_widget_queue_resize (child_widget);
280 gtk_layout_move (GtkLayout *layout,
281 GtkWidget *child_widget,
286 GtkLayoutChild *child;
288 g_return_if_fail (layout != NULL);
289 g_return_if_fail (GTK_IS_LAYOUT (layout));
291 tmp_list = layout->children;
294 child = tmp_list->data;
295 tmp_list = tmp_list->next;
297 if (child->widget == child_widget)
302 if (GTK_WIDGET_VISIBLE (child_widget) && GTK_WIDGET_VISIBLE (layout))
303 gtk_widget_queue_resize (child_widget);
311 gtk_layout_set_size (GtkLayout *layout,
315 g_return_if_fail (layout != NULL);
316 g_return_if_fail (GTK_IS_LAYOUT (layout));
318 layout->width = width;
319 layout->height = height;
321 layout->hadjustment->upper = layout->width;
322 gtk_signal_emit_by_name (GTK_OBJECT (layout->hadjustment), "changed");
324 layout->vadjustment->upper = layout->height;
325 gtk_signal_emit_by_name (GTK_OBJECT (layout->vadjustment), "changed");
329 gtk_layout_freeze (GtkLayout *layout)
331 g_return_if_fail (layout != NULL);
332 g_return_if_fail (GTK_IS_LAYOUT (layout));
334 layout->freeze_count++;
338 gtk_layout_thaw (GtkLayout *layout)
340 g_return_if_fail (layout != NULL);
341 g_return_if_fail (GTK_IS_LAYOUT (layout));
343 if (layout->freeze_count)
344 if (!(--layout->freeze_count))
346 gtk_layout_position_children (layout);
347 gtk_widget_draw (GTK_WIDGET (layout), NULL);
351 /* Basic Object handling procedures
354 gtk_layout_get_type (void)
356 static GtkType layout_type = 0;
360 static const GtkTypeInfo layout_info =
364 sizeof (GtkLayoutClass),
365 (GtkClassInitFunc) gtk_layout_class_init,
366 (GtkObjectInitFunc) gtk_layout_init,
367 (GtkArgSetFunc) NULL,
368 (GtkArgGetFunc) NULL,
371 layout_type = gtk_type_unique (GTK_TYPE_CONTAINER, &layout_info);
378 gtk_layout_class_init (GtkLayoutClass *class)
380 GtkObjectClass *object_class;
381 GtkWidgetClass *widget_class;
382 GtkContainerClass *container_class;
384 object_class = (GtkObjectClass*) class;
385 widget_class = (GtkWidgetClass*) class;
386 container_class = (GtkContainerClass*) class;
388 parent_class = gtk_type_class (GTK_TYPE_CONTAINER);
390 widget_class->realize = gtk_layout_realize;
391 widget_class->unrealize = gtk_layout_unrealize;
392 widget_class->map = gtk_layout_map;
393 widget_class->size_request = gtk_layout_size_request;
394 widget_class->size_allocate = gtk_layout_size_allocate;
395 widget_class->draw = gtk_layout_draw;
396 widget_class->expose_event = gtk_layout_expose;
398 widget_class->set_scroll_adjustments_signal =
399 gtk_signal_new ("set_scroll_adjustments",
402 GTK_SIGNAL_OFFSET (GtkLayoutClass, set_scroll_adjustments),
403 gtk_marshal_NONE__POINTER_POINTER,
404 GTK_TYPE_NONE, 2, GTK_TYPE_ADJUSTMENT, GTK_TYPE_ADJUSTMENT);
406 container_class->remove = gtk_layout_remove;
407 container_class->forall = gtk_layout_forall;
409 class->set_scroll_adjustments = gtk_layout_set_adjustments;
413 gtk_layout_init (GtkLayout *layout)
415 layout->children = NULL;
418 layout->height = 100;
420 layout->hadjustment = NULL;
421 layout->vadjustment = NULL;
423 layout->bin_window = NULL;
425 layout->configure_serial = 0;
426 layout->scroll_x = 0;
427 layout->scroll_y = 0;
428 layout->visibility = GDK_VISIBILITY_PARTIAL;
430 layout->freeze_count = 0;
437 gtk_layout_realize (GtkWidget *widget)
441 GdkWindowAttr attributes;
442 gint attributes_mask;
444 g_return_if_fail (widget != NULL);
445 g_return_if_fail (GTK_IS_LAYOUT (widget));
447 layout = GTK_LAYOUT (widget);
448 GTK_WIDGET_SET_FLAGS (layout, GTK_REALIZED);
450 attributes.window_type = GDK_WINDOW_CHILD;
451 attributes.x = widget->allocation.x;
452 attributes.y = widget->allocation.y;
453 attributes.width = widget->allocation.width;
454 attributes.height = widget->allocation.height;
455 attributes.wclass = GDK_INPUT_OUTPUT;
456 attributes.visual = gtk_widget_get_visual (widget);
457 attributes.colormap = gtk_widget_get_colormap (widget);
458 attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK;
460 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
462 widget->window = gdk_window_new (gtk_widget_get_parent_window (widget),
463 &attributes, attributes_mask);
464 gdk_window_set_user_data (widget->window, widget);
468 attributes.event_mask = GDK_EXPOSURE_MASK |
469 gtk_widget_get_events (widget);
471 layout->bin_window = gdk_window_new (widget->window,
472 &attributes, attributes_mask);
473 gdk_window_set_user_data (layout->bin_window, widget);
475 widget->style = gtk_style_attach (widget->style, widget->window);
476 gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
477 gtk_style_set_background (widget->style, layout->bin_window, GTK_STATE_NORMAL);
479 gdk_window_add_filter (widget->window, gtk_layout_main_filter, layout);
480 gdk_window_add_filter (layout->bin_window, gtk_layout_filter, layout);
482 /* XXX: If we ever get multiple displays for GTK+, then gravity_works
483 * will have to become a widget member. Right now we just
484 * keep it as a global
486 gravity_works = gdk_window_set_static_gravities (layout->bin_window, TRUE);
488 tmp_list = layout->children;
491 GtkLayoutChild *child = tmp_list->data;
492 tmp_list = tmp_list->next;
494 gtk_widget_set_parent_window (child->widget, layout->bin_window);
499 gtk_layout_map (GtkWidget *widget)
504 g_return_if_fail (widget != NULL);
505 g_return_if_fail (GTK_IS_LAYOUT (widget));
507 layout = GTK_LAYOUT (widget);
509 GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
511 tmp_list = layout->children;
514 GtkLayoutChild *child = tmp_list->data;
515 tmp_list = tmp_list->next;
517 if (GTK_WIDGET_VISIBLE (child->widget))
519 if (!GTK_WIDGET_MAPPED (child->widget) &&
520 !GTK_WIDGET_IS_OFFSCREEN (child->widget))
521 gtk_widget_map (child->widget);
525 gdk_window_show (layout->bin_window);
526 gdk_window_show (widget->window);
530 gtk_layout_unrealize (GtkWidget *widget)
534 g_return_if_fail (widget != NULL);
535 g_return_if_fail (GTK_IS_LAYOUT (widget));
537 layout = GTK_LAYOUT (widget);
539 gdk_window_set_user_data (layout->bin_window, NULL);
540 gdk_window_destroy (layout->bin_window);
541 layout->bin_window = NULL;
543 if (GTK_WIDGET_CLASS (parent_class)->unrealize)
544 (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
548 gtk_layout_size_request (GtkWidget *widget,
549 GtkRequisition *requisition)
554 g_return_if_fail (widget != NULL);
555 g_return_if_fail (GTK_IS_LAYOUT (widget));
557 layout = GTK_LAYOUT (widget);
559 requisition->width = 0;
560 requisition->height = 0;
562 tmp_list = layout->children;
566 GtkLayoutChild *child = tmp_list->data;
567 GtkRequisition child_requisition;
569 tmp_list = tmp_list->next;
571 gtk_widget_size_request (child->widget, &child_requisition);
576 gtk_layout_size_allocate (GtkWidget *widget,
577 GtkAllocation *allocation)
582 g_return_if_fail (widget != NULL);
583 g_return_if_fail (GTK_IS_LAYOUT (widget));
585 widget->allocation = *allocation;
587 layout = GTK_LAYOUT (widget);
589 tmp_list = layout->children;
593 GtkLayoutChild *child = tmp_list->data;
594 tmp_list = tmp_list->next;
596 gtk_layout_position_child (layout, child);
597 gtk_layout_allocate_child (layout, child);
600 if (GTK_WIDGET_REALIZED (widget))
602 gdk_window_move_resize (widget->window,
603 allocation->x, allocation->y,
604 allocation->width, allocation->height);
605 gdk_window_move_resize (GTK_LAYOUT(widget)->bin_window,
607 allocation->width, allocation->height);
610 layout->hadjustment->page_size = allocation->width;
611 layout->hadjustment->page_increment = allocation->width / 2;
612 layout->hadjustment->lower = 0;
613 layout->hadjustment->upper = layout->width;
614 gtk_signal_emit_by_name (GTK_OBJECT (layout->hadjustment), "changed");
616 layout->vadjustment->page_size = allocation->height;
617 layout->vadjustment->page_increment = allocation->height / 2;
618 layout->vadjustment->lower = 0;
619 layout->vadjustment->upper = layout->height;
620 gtk_signal_emit_by_name (GTK_OBJECT (layout->vadjustment), "changed");
624 gtk_layout_draw (GtkWidget *widget, GdkRectangle *area)
628 GdkRectangle child_area;
630 g_return_if_fail (widget != NULL);
631 g_return_if_fail (GTK_IS_LAYOUT (widget));
633 layout = GTK_LAYOUT (widget);
635 /* We don't have any way of telling themes about this properly,
636 * so we just assume a background pixmap
638 if (!GTK_WIDGET_APP_PAINTABLE (widget))
639 gdk_window_clear_area (layout->bin_window,
640 area->x, area->y, area->width, area->height);
642 tmp_list = layout->children;
645 GtkLayoutChild *child = tmp_list->data;
646 tmp_list = tmp_list->next;
648 if (gtk_widget_intersect (child->widget, area, &child_area))
649 gtk_widget_draw (child->widget, &child_area);
654 gtk_layout_expose (GtkWidget *widget, GdkEventExpose *event)
658 GdkEventExpose child_event;
660 g_return_val_if_fail (widget != NULL, FALSE);
661 g_return_val_if_fail (GTK_IS_LAYOUT (widget), FALSE);
663 layout = GTK_LAYOUT (widget);
665 if (event->window != layout->bin_window)
668 tmp_list = layout->children;
671 GtkLayoutChild *child = tmp_list->data;
672 tmp_list = tmp_list->next;
674 child_event = *event;
675 if (GTK_WIDGET_DRAWABLE (child->widget) &&
676 GTK_WIDGET_NO_WINDOW (child->widget) &&
677 gtk_widget_intersect (child->widget, &event->area, &child_event.area))
678 gtk_widget_event (child->widget, (GdkEvent*) &child_event);
687 gtk_layout_remove (GtkContainer *container,
692 GtkLayoutChild *child = NULL;
694 g_return_if_fail (container != NULL);
695 g_return_if_fail (GTK_IS_LAYOUT (container));
697 layout = GTK_LAYOUT (container);
699 tmp_list = layout->children;
702 child = tmp_list->data;
703 if (child->widget == widget)
705 tmp_list = tmp_list->next;
710 gtk_widget_unparent (widget);
712 layout->children = g_list_remove_link (layout->children, tmp_list);
713 g_list_free_1 (tmp_list);
717 GTK_PRIVATE_UNSET_FLAG (widget, GTK_IS_OFFSCREEN);
721 gtk_layout_forall (GtkContainer *container,
722 gboolean include_internals,
723 GtkCallback callback,
724 gpointer callback_data)
727 GtkLayoutChild *child;
730 g_return_if_fail (container != NULL);
731 g_return_if_fail (GTK_IS_LAYOUT (container));
732 g_return_if_fail (callback != NULL);
734 layout = GTK_LAYOUT (container);
736 tmp_list = layout->children;
739 child = tmp_list->data;
740 tmp_list = tmp_list->next;
742 (* callback) (child->widget, callback_data);
746 /* Operations on children
750 gtk_layout_position_child (GtkLayout *layout,
751 GtkLayoutChild *child)
756 x = child->x - layout->xoffset;
757 y = child->y - layout->yoffset;
759 if (IS_ONSCREEN (x,y))
761 if (GTK_WIDGET_MAPPED (layout) &&
762 GTK_WIDGET_VISIBLE (child->widget))
764 if (!GTK_WIDGET_MAPPED (child->widget))
765 gtk_widget_map (child->widget);
768 if (GTK_WIDGET_IS_OFFSCREEN (child->widget))
769 GTK_PRIVATE_UNSET_FLAG (child->widget, GTK_IS_OFFSCREEN);
773 if (!GTK_WIDGET_IS_OFFSCREEN (child->widget))
774 GTK_PRIVATE_SET_FLAG (child->widget, GTK_IS_OFFSCREEN);
776 if (GTK_WIDGET_MAPPED (child->widget))
777 gtk_widget_unmap (child->widget);
782 gtk_layout_allocate_child (GtkLayout *layout,
783 GtkLayoutChild *child)
785 GtkAllocation allocation;
786 GtkRequisition requisition;
788 allocation.x = child->x - layout->xoffset;
789 allocation.y = child->y - layout->yoffset;
790 gtk_widget_get_child_requisition (child->widget, &requisition);
791 allocation.width = requisition.width;
792 allocation.height = requisition.height;
794 gtk_widget_size_allocate (child->widget, &allocation);
798 gtk_layout_position_children (GtkLayout *layout)
802 tmp_list = layout->children;
805 GtkLayoutChild *child = tmp_list->data;
806 tmp_list = tmp_list->next;
808 gtk_layout_position_child (layout, child);
813 gtk_layout_adjust_allocations_recurse (GtkWidget *widget,
816 GtkLayoutAdjData *data = cb_data;
818 widget->allocation.x += data->dx;
819 widget->allocation.y += data->dy;
821 if (GTK_WIDGET_NO_WINDOW (widget) &&
822 GTK_IS_CONTAINER (widget))
823 gtk_container_forall (GTK_CONTAINER (widget),
824 gtk_layout_adjust_allocations_recurse,
829 gtk_layout_adjust_allocations (GtkLayout *layout,
834 GtkLayoutAdjData data;
839 tmp_list = layout->children;
842 GtkLayoutChild *child = tmp_list->data;
843 tmp_list = tmp_list->next;
845 child->widget->allocation.x += dx;
846 child->widget->allocation.y += dy;
848 if (GTK_WIDGET_NO_WINDOW (child->widget) &&
849 GTK_IS_CONTAINER (child->widget))
850 gtk_container_forall (GTK_CONTAINER (child->widget),
851 gtk_layout_adjust_allocations_recurse,
858 /* Send a synthetic expose event to the widget
861 gtk_layout_expose_area (GtkLayout *layout,
862 gint x, gint y, gint width, gint height)
864 if (layout->visibility == GDK_VISIBILITY_UNOBSCURED)
866 GdkEventExpose event;
868 event.type = GDK_EXPOSE;
869 event.send_event = TRUE;
870 event.window = layout->bin_window;
875 event.area.width = width;
876 event.area.height = height;
878 gdk_window_ref (event.window);
879 gtk_widget_event (GTK_WIDGET (layout), (GdkEvent *)&event);
880 gdk_window_unref (event.window);
884 /* This function is used to find events to process while scrolling
888 gtk_layout_expose_predicate (Display *display,
892 if ((xevent->type == Expose) ||
893 ((xevent->xany.window == *(Window *)arg) &&
894 (xevent->type == ConfigureNotify)))
900 /* This is the main routine to do the scrolling. Scrolling is
901 * done by "Guffaw" scrolling, as in the Mozilla XFE, with
902 * a few modifications.
904 * The main improvement is that we keep track of whether we
905 * are obscured or not. If not, we ignore the generated expose
906 * events and instead do the exposes ourself, without having
907 * to wait for a roundtrip to the server. This also provides
908 * a limited form of expose-event compression, since we do
909 * the affected area as one big chunk.
911 * Real expose event compression, as in the XFE, could be added
912 * here. It would help opaque drags over the region, and the
915 * Code needs to be added here to do the scrolling on machines
916 * that don't have working WindowGravity. That could be done
918 * - XCopyArea and move the windows, and accept trailing the
919 * background color. (Since it is only a fallback method)
920 * - XmHTML style. As above, but turn off expose events when
921 * not obscured and do the exposures ourself.
922 * - gzilla-style. Move the window continuously, and reset
927 gtk_layout_adjustment_changed (GtkAdjustment *adjustment,
935 widget = GTK_WIDGET (layout);
937 dx = (gint)layout->hadjustment->value - layout->xoffset;
938 dy = (gint)layout->vadjustment->value - layout->yoffset;
940 layout->xoffset = (gint)layout->hadjustment->value;
941 layout->yoffset = (gint)layout->vadjustment->value;
943 if (layout->freeze_count)
946 if (!GTK_WIDGET_MAPPED (layout))
948 gtk_layout_position_children (layout);
952 gtk_layout_adjust_allocations (layout, -dx, -dy);
958 gdk_window_resize (layout->bin_window,
959 widget->allocation.width + dx,
960 widget->allocation.height);
961 gdk_window_move (layout->bin_window, -dx, 0);
962 gdk_window_move_resize (layout->bin_window,
964 widget->allocation.width,
965 widget->allocation.height);
972 gtk_layout_expose_area (layout,
973 MAX ((gint)widget->allocation.width - dx, 0),
975 MIN (dx, widget->allocation.width),
976 widget->allocation.height);
982 gdk_window_move_resize (layout->bin_window,
984 widget->allocation.width - dx,
985 widget->allocation.height);
986 gdk_window_move (layout->bin_window, 0, 0);
987 gdk_window_resize (layout->bin_window,
988 widget->allocation.width,
989 widget->allocation.height);
996 gtk_layout_expose_area (layout,
999 MIN (-dx, widget->allocation.width),
1000 widget->allocation.height);
1007 gdk_window_resize (layout->bin_window,
1008 widget->allocation.width,
1009 widget->allocation.height + dy);
1010 gdk_window_move (layout->bin_window, 0, -dy);
1011 gdk_window_move_resize (layout->bin_window,
1013 widget->allocation.width,
1014 widget->allocation.height);
1021 gtk_layout_expose_area (layout,
1023 MAX ((gint)widget->allocation.height - dy, 0),
1024 widget->allocation.width,
1025 MIN (dy, widget->allocation.width));
1031 gdk_window_move_resize (layout->bin_window,
1033 widget->allocation.width,
1034 widget->allocation.height - dy);
1035 gdk_window_move (layout->bin_window, 0, 0);
1036 gdk_window_resize (layout->bin_window,
1037 widget->allocation.width,
1038 widget->allocation.height);
1044 gtk_layout_expose_area (layout,
1047 widget->allocation.height,
1048 MIN (-dy, (gint)widget->allocation.width));
1051 gtk_layout_position_children (layout);
1053 /* We have to make sure that all exposes from this scroll get
1054 * processed before we scroll again, or the expose events will
1055 * have invalid coordinates.
1057 * We also do expose events for other windows, since otherwise
1058 * their updating will fall behind the scrolling
1060 * This also avoids a problem in pre-1.0 GTK where filters don't
1061 * have access to configure events that were compressed.
1065 while (XCheckIfEvent(GDK_WINDOW_XDISPLAY (layout->bin_window),
1067 gtk_layout_expose_predicate,
1068 (XPointer)&GDK_WINDOW_XWINDOW (layout->bin_window)))
1071 GtkWidget *event_widget;
1073 if ((xevent.xany.window == GDK_WINDOW_XWINDOW (layout->bin_window)) &&
1074 (gtk_layout_filter (&xevent, &event, layout) == GDK_FILTER_REMOVE))
1077 if (xevent.type == Expose)
1079 event.expose.window = gdk_window_lookup (xevent.xany.window);
1080 gdk_window_get_user_data (event.expose.window,
1081 (gpointer *)&event_widget);
1085 event.expose.type = GDK_EXPOSE;
1086 event.expose.area.x = xevent.xexpose.x;
1087 event.expose.area.y = xevent.xexpose.y;
1088 event.expose.area.width = xevent.xexpose.width;
1089 event.expose.area.height = xevent.xexpose.height;
1090 event.expose.count = xevent.xexpose.count;
1092 gdk_window_ref (event.expose.window);
1093 gtk_widget_event (event_widget, &event);
1094 gdk_window_unref (event.expose.window);
1100 /* The main event filter. Actually, we probably don't really need
1101 * to install this as a filter at all, since we are calling it
1102 * directly above in the expose-handling hack. But in case scrollbars
1103 * are fixed up in some manner...
1105 * This routine identifies expose events that are generated when
1106 * we've temporarily moved the bin_window_origin, and translates
1107 * them or discards them, depending on whether we are obscured
1110 static GdkFilterReturn
1111 gtk_layout_filter (GdkXEvent *gdk_xevent,
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;
1148 return GDK_FILTER_CONTINUE;
1151 /* Although GDK does have a GDK_VISIBILITY_NOTIFY event,
1152 * there is no corresponding event in GTK, so we have
1153 * to get the events from a filter
1155 static GdkFilterReturn
1156 gtk_layout_main_filter (GdkXEvent *gdk_xevent,
1163 xevent = (XEvent *)gdk_xevent;
1164 layout = GTK_LAYOUT (data);
1166 if (xevent->type == VisibilityNotify)
1168 switch (xevent->xvisibility.state)
1170 case VisibilityFullyObscured:
1171 layout->visibility = GDK_VISIBILITY_FULLY_OBSCURED;
1174 case VisibilityPartiallyObscured:
1175 layout->visibility = GDK_VISIBILITY_PARTIAL;
1178 case VisibilityUnobscured:
1179 layout->visibility = GDK_VISIBILITY_UNOBSCURED;
1183 return GDK_FILTER_REMOVE;
1187 return GDK_FILTER_CONTINUE;