1 /* GDK - The GIMP Drawing Kit
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 Lesser 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 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser 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.
20 /* gdkgeometry-x11.c: emulation of 32 bit coordinates within the
23 * By Owen Taylor <otaylor@redhat.com>
24 * Copyright Red Hat, Inc. 2000
26 * The algorithms implemented in this file are an extension of the
27 * idea of guffaw scrolling, a technique (and name) taken from the classic
28 * Netscape source code. The basic idea of guffaw scrolling is a trick
29 * to get around a limitation of X: there is no way of scrolling the
30 * contents of a window. Guffaw scrolling exploits the X concepts of
31 * window gravity and bit gravity:
33 * window gravity: the window gravity of a window affects what happens
34 * to a windows position when _its parent_ is resized, or
35 * moved and resized simultaneously.
37 * bit gravity: the bit gravity of a window affects what happens to
38 * the pixels of a window when _it_ is is resized, or moved and
39 * resized simultaneously.
41 * These were basically intended to do things like have right
42 * justified widgets in a window automatically stay right justified
43 * when the window was resized, but there is also the special
44 * "StaticGravity" which means "do nothing." We can exploit
45 * StaticGravity to scroll a window:
50 * |abcdefghijk | (1) Resize bigger
51 * | efghijk | (2) Move
52 * |efghijk | (3) Move-resize back to the original size
54 * Or, going the other way:
57 * | abcdefghijk| (1) Move-resize bigger
58 * | abcdefghijk| (2) Move
59 * | abcdefg| (4) Resize back to the original size
61 * By using this technique, we can simulate scrolling around in a
62 * large virtual space without having to actually have windows that
63 * big; for the pixels of the window, this is all we have to do. For
64 * subwindows, we have to take care of one other detail - since
65 * coordinates in X are limited to 16 bits, subwindows scrolled off
66 * will wrap around and come back eventually. So, we have to take care
67 * to unmap windows that go outside the 16-bit range and remap them as
70 * Since we are temporarily making the window bigger, this only looks
71 * good if the edges of the window are obscured. Typically, we do
72 * this by making the window we are scrolling the immediate child
75 * But, this isn't a perfect API for applications for several reasons:
77 * - We have to use this inefficient technique even for small windows
78 * if the window _could_ be big.
79 * - Applications have to use a special scrolling API.
81 * What we'd like is to simply have windows with 32 bit coordinates
82 * so applications could scroll in the classic way - just move a big
85 * It turns out that StaticGravity can also be used to achieve emulation
86 * of 32 bit coordinates with only 16 bit coordinates if we expand
87 * our horizons just a bit; what guffaw scrolling really is is a way
88 * to move the contents of a window a different amount than we move
89 * the borders of of the window. In the above example pictures we
90 * ended up with the borders of the window not moving at all, but
91 * that isn't necessary.
93 * So, what we do is set up a mapping from virtual 32 bit window position/size
96 * - Real window position/size
97 * - Offset between virtual coordinates and real coordinates for the window
98 * - Map state (mapped or unmapped)
100 * By the following rules:
102 * - If the window is less than 32767 pixels in width (resp. height), we use it's
103 * virtual width and position.
104 * - Otherwise, we use a width of 32767 and determine the position of the window
105 * so that the portion of the real window [16384, 16383] in _toplevel window
106 * coordinates_ is the same as the portion of the real window
108 * This is implemented in gdk_window_compute_position(). Then the algorithm
109 * for a moving a window (_window_move_resize_child ()) is:
111 * - Compute the new window mappings for the window and all subwindows
112 * - Expand out the boundary of the window and all subwindows by the amount
113 * that the real/virtual offset changes for each window.
114 * (compute_intermediate_position() computes expanded boundary)
115 * - Move the toplevel by the amount that it's contents need to translate.
116 * - Move/resize the window and all subwindows to the newly computed
119 * If we just are scrolling (gdk_window_guffaw_scroll()), then things
120 * are similar, except that the final mappings for the toplevel are
121 * the same as the initial mappings, but we act as if it moved by the
122 * amount we are scrolling by.
124 * Note that we don't have to worry about a clip window in
125 * _gdk_window_move_resize() since we have set up our translation so
126 * that things in the range [16384,16383] in toplevel window
127 * coordinates look exactly as they would if we were simply moving the
128 * windows, and nothing outside this range is going to be visible
129 * unless the user has a _really_ huge screen.
133 #include "gdk.h" /* For gdk_rectangle_intersect */
134 #include "gdkprivate-x11.h"
136 #include "gdkregion.h"
137 #include "gdkinternals.h"
138 #include "gdkscreen-x11.h"
139 #include "gdkdisplay-x11.h"
140 #include "gdkwindow-x11.h"
141 #include "gdkalias.h"
143 typedef struct _GdkWindowQueueItem GdkWindowQueueItem;
144 typedef struct _GdkWindowParentPos GdkWindowParentPos;
147 GDK_WINDOW_QUEUE_TRANSLATE,
148 GDK_WINDOW_QUEUE_ANTIEXPOSE
149 } GdkWindowQueueType;
151 struct _GdkWindowQueueItem
155 GdkWindowQueueType type;
168 struct _GdkWindowParentPos
174 GdkRectangle clip_rect;
177 static void gdk_window_compute_position (GdkWindowImplX11 *window,
178 GdkWindowParentPos *parent_pos,
179 GdkXPositionInfo *info);
180 static void gdk_window_compute_parent_pos (GdkWindowImplX11 *window,
181 GdkWindowParentPos *parent_pos);
182 static void gdk_window_premove (GdkWindow *window,
183 GdkWindowParentPos *parent_pos);
184 static void gdk_window_postmove (GdkWindow *window,
185 GdkWindowParentPos *parent_pos);
186 static void gdk_window_queue_translation (GdkWindow *window,
190 static void gdk_window_clip_changed (GdkWindow *window,
191 GdkRectangle *old_clip,
192 GdkRectangle *new_clip);
195 _gdk_windowing_window_get_offsets (GdkWindow *window,
199 GdkWindowImplX11 *impl =
200 GDK_WINDOW_IMPL_X11 (GDK_WINDOW_OBJECT (window)->impl);
202 *x_offset = impl->position_info.x_offset;
203 *y_offset = impl->position_info.y_offset;
207 _gdk_window_init_position (GdkWindow *window)
209 GdkWindowParentPos parent_pos;
210 GdkWindowImplX11 *impl;
212 g_return_if_fail (GDK_IS_WINDOW (window));
215 GDK_WINDOW_IMPL_X11 (GDK_WINDOW_OBJECT (window)->impl);
217 gdk_window_compute_parent_pos (impl, &parent_pos);
218 gdk_window_compute_position (impl, &parent_pos, &impl->position_info);
222 gdk_window_copy_area_scroll (GdkWindow *window,
223 GdkRectangle *dest_rect,
227 GdkWindowObject *obj = GDK_WINDOW_OBJECT (window);
230 if (dest_rect->width > 0 && dest_rect->height > 0)
234 gc = _gdk_drawable_get_scratch_gc (window, TRUE);
236 gdk_window_queue_translation (window, NULL, dx, dy);
238 XCopyArea (GDK_WINDOW_XDISPLAY (window),
239 GDK_WINDOW_XID (window),
240 GDK_WINDOW_XID (window),
241 gdk_x11_gc_get_xgc (gc),
242 dest_rect->x - dx, dest_rect->y - dy,
243 dest_rect->width, dest_rect->height,
244 dest_rect->x, dest_rect->y);
247 for (l = obj->children; l; l = l->next)
249 GdkWindow *child = (GdkWindow*) l->data;
250 GdkWindowObject *child_obj = GDK_WINDOW_OBJECT (child);
252 gdk_window_move (child, child_obj->x + dx, child_obj->y + dy);
257 compute_intermediate_position (GdkXPositionInfo *position_info,
258 GdkXPositionInfo *new_info,
261 GdkRectangle *new_position)
263 gint new_x0, new_x1, new_y0, new_y1;
265 /* Wrap d_xoffset, d_yoffset into [-32768,32767] range. For the
266 * purposes of subwindow movement, it doesn't matter if we are
267 * off by a factor of 65536, and if we don't do this range
268 * reduction, we'll end up with invalid widths.
270 d_xoffset = (gint16)d_xoffset;
271 d_yoffset = (gint16)d_yoffset;
275 new_x0 = position_info->x + d_xoffset;
276 new_x1 = position_info->x + position_info->width;
280 new_x0 = position_info->x;
281 new_x1 = position_info->x + new_info->width + d_xoffset;
284 new_position->x = new_x0;
285 new_position->width = new_x1 - new_x0;
289 new_y0 = position_info->y + d_yoffset;
290 new_y1 = position_info->y + position_info->height;
294 new_y0 = position_info->y;
295 new_y1 = position_info->y + new_info->height + d_yoffset;
298 new_position->y = new_y0;
299 new_position->height = new_y1 - new_y0;
303 translate_pos (GdkWindowParentPos *dest, GdkWindowParentPos *src,
304 GdkWindowObject *obj, GdkXPositionInfo *pos_info,
307 dest->x = src->x + obj->x;
308 dest->y = src->y + obj->y;
309 dest->x11_x = src->x11_x + pos_info->x;
310 dest->x11_y = src->x11_y + pos_info->y;
313 dest->clip_rect = pos_info->clip_rect;
317 move (GdkWindow *window, GdkXPositionInfo *pos)
319 XMoveWindow (GDK_WINDOW_XDISPLAY (window),
320 GDK_WINDOW_XID (window), pos->x, pos->y);
324 move_relative (GdkWindow *window, GdkRectangle *rect,
327 XMoveWindow (GDK_WINDOW_XDISPLAY (window),
328 GDK_WINDOW_XID (window),
329 rect->x + dx, rect->y + dy);
333 move_resize (GdkWindow *window, GdkRectangle *pos)
335 XMoveResizeWindow (GDK_WINDOW_XDISPLAY (window),
336 GDK_WINDOW_XID (window),
337 pos->x, pos->y, pos->width, pos->height);
341 gdk_window_guffaw_scroll (GdkWindow *window,
345 GdkWindowObject *obj = GDK_WINDOW_OBJECT (window);
346 GdkWindowImplX11 *impl = GDK_WINDOW_IMPL_X11 (obj->impl);
348 gint d_xoffset = -dx;
349 gint d_yoffset = -dy;
350 GdkRectangle new_position;
351 GdkXPositionInfo new_info;
352 GdkWindowParentPos parent_pos;
355 gdk_window_compute_parent_pos (impl, &parent_pos);
356 gdk_window_compute_position (impl, &parent_pos, &new_info);
358 translate_pos (&parent_pos, &parent_pos, obj, &new_info, TRUE);
360 _gdk_x11_window_tmp_unset_bg (window, FALSE);;
362 if (dx > 0 || dy > 0)
363 gdk_window_queue_translation (window, NULL, MAX (dx, 0), MAX (dy, 0));
365 gdk_window_set_static_gravities (window, TRUE);
367 compute_intermediate_position (&impl->position_info, &new_info, d_xoffset, d_yoffset,
370 move_resize (window, &new_position);
372 for (l = obj->children; l; l = l->next)
374 GdkWindow *child = (GdkWindow*) l->data;
375 GdkWindowObject *child_obj = GDK_WINDOW_OBJECT (child);
377 child_obj->x -= d_xoffset;
378 child_obj->y -= d_yoffset;
380 gdk_window_premove (child, &parent_pos);
383 move_relative (window, &new_position, -d_xoffset, -d_yoffset);
385 if (dx < 0 || dy < 0)
386 gdk_window_queue_translation (window, NULL, MIN (dx, 0), MIN (dy, 0));
388 move_resize (window, (GdkRectangle *) &impl->position_info);
390 if (impl->position_info.no_bg)
391 _gdk_x11_window_tmp_reset_bg (window, FALSE);
393 impl->position_info = new_info;
395 g_list_foreach (obj->children, (GFunc) gdk_window_postmove, &parent_pos);
400 * @window: a #GdkWindow
401 * @dx: Amount to scroll in the X direction
402 * @dy: Amount to scroll in the Y direction
404 * Scroll the contents of @window, both pixels and children, by the given
405 * amount. @window itself does not move. Portions of the window that the scroll
406 * operation brings in from offscreen areas are invalidated. The invalidated
407 * region may be bigger than what would strictly be necessary. (For X11, a
408 * minimum area will be invalidated if the window has no subwindows, or if the
409 * edges of the window's parent do not extend beyond the edges of the window. In
410 * other cases, a multi-step process is used to scroll the window which may
411 * produce temporary visual artifacts and unnecessary invalidations.)
414 gdk_window_scroll (GdkWindow *window,
418 gboolean can_guffaw_scroll = FALSE;
419 GdkRegion *invalidate_region;
420 GdkWindowImplX11 *impl;
421 GdkWindowObject *obj;
422 GdkRectangle src_rect, dest_rect;
424 g_return_if_fail (GDK_IS_WINDOW (window));
426 if (GDK_WINDOW_DESTROYED (window))
429 obj = GDK_WINDOW_OBJECT (window);
430 impl = GDK_WINDOW_IMPL_X11 (obj->impl);
432 if (dx == 0 && dy == 0)
435 /* Move the current invalid region */
436 if (obj->update_area)
437 gdk_region_offset (obj->update_area, dx, dy);
439 /* impl->position_info.clip_rect isn't meaningful for toplevels */
440 if (GDK_WINDOW_TYPE (window) == GDK_WINDOW_CHILD)
441 src_rect = impl->position_info.clip_rect;
446 src_rect.width = impl->width;
447 src_rect.height = impl->height;
450 invalidate_region = gdk_region_rectangle (&src_rect);
452 dest_rect = src_rect;
455 gdk_rectangle_intersect (&dest_rect, &src_rect, &dest_rect);
457 if (dest_rect.width > 0 && dest_rect.height > 0)
459 GdkRegion *tmp_region;
461 tmp_region = gdk_region_rectangle (&dest_rect);
462 gdk_region_subtract (invalidate_region, tmp_region);
463 gdk_region_destroy (tmp_region);
466 gdk_window_invalidate_region (window, invalidate_region, TRUE);
467 gdk_region_destroy (invalidate_region);
469 /* We can guffaw scroll if we are a child window, and the parent
470 * does not extend beyond our edges. Otherwise, we use XCopyArea, then
471 * move any children later
473 if (GDK_WINDOW_TYPE (window) == GDK_WINDOW_CHILD)
475 GdkWindowImplX11 *parent_impl = GDK_WINDOW_IMPL_X11 (obj->parent->impl);
476 can_guffaw_scroll = ((dx == 0 || (obj->x <= 0 && obj->x + impl->width >= parent_impl->width)) &&
477 (dy == 0 || (obj->y <= 0 && obj->y + impl->height >= parent_impl->height)));
480 if (!obj->children || !can_guffaw_scroll)
481 gdk_window_copy_area_scroll (window, &dest_rect, dx, dy);
483 gdk_window_guffaw_scroll (window, dx, dy);
487 * gdk_window_move_region:
488 * @window: a #GdkWindow
489 * @region: The #GdkRegion to move
490 * @dx: Amount to move in the X direction
491 * @dy: Amount to move in the Y direction
493 * Move the part of @window indicated by @region by @dy pixels in the Y
494 * direction and @dx pixels in the X direction. The portions of @region
495 * that not covered by the new position of @region are invalidated.
497 * Child windows are not moved.
502 gdk_window_move_region (GdkWindow *window,
507 GdkWindowImplX11 *impl;
508 GdkWindowObject *private;
509 GdkRegion *window_clip;
510 GdkRegion *src_region;
511 GdkRegion *brought_in;
512 GdkRegion *dest_region;
513 GdkRegion *moving_invalid_region;
514 GdkRectangle dest_extents;
517 g_return_if_fail (GDK_IS_WINDOW (window));
518 g_return_if_fail (region != NULL);
520 if (GDK_WINDOW_DESTROYED (window))
523 private = GDK_WINDOW_OBJECT (window);
524 impl = GDK_WINDOW_IMPL_X11 (private->impl);
526 if (dx == 0 && dy == 0)
529 window_clip = gdk_region_rectangle (&impl->position_info.clip_rect);
531 /* compute source regions */
532 src_region = gdk_region_copy (region);
533 brought_in = gdk_region_copy (region);
534 gdk_region_intersect (src_region, window_clip);
536 gdk_region_subtract (brought_in, src_region);
537 gdk_region_offset (brought_in, dx, dy);
539 /* compute destination regions */
540 dest_region = gdk_region_copy (src_region);
541 gdk_region_offset (dest_region, dx, dy);
542 gdk_region_intersect (dest_region, window_clip);
543 gdk_region_get_clipbox (dest_region, &dest_extents);
545 gdk_region_destroy (window_clip);
547 /* calculating moving part of current invalid area */
548 moving_invalid_region = NULL;
549 if (private->update_area)
551 moving_invalid_region = gdk_region_copy (private->update_area);
552 gdk_region_intersect (moving_invalid_region, src_region);
553 gdk_region_offset (moving_invalid_region, dx, dy);
556 /* invalidate all of the src region */
557 gdk_window_invalidate_region (window, src_region, FALSE);
559 /* un-invalidate destination region */
560 if (private->update_area)
561 gdk_region_subtract (private->update_area, dest_region);
563 /* invalidate moving parts of existing update area */
564 if (moving_invalid_region)
566 gdk_window_invalidate_region (window, moving_invalid_region, FALSE);
567 gdk_region_destroy (moving_invalid_region);
570 /* invalidate area brought in from off-screen */
571 gdk_window_invalidate_region (window, brought_in, FALSE);
572 gdk_region_destroy (brought_in);
574 /* Actually do the moving */
575 gdk_window_queue_translation (window, src_region, dx, dy);
577 gc = _gdk_drawable_get_scratch_gc (window, TRUE);
578 gdk_gc_set_clip_region (gc, dest_region);
580 XCopyArea (GDK_WINDOW_XDISPLAY (window),
581 GDK_WINDOW_XID (window),
582 GDK_WINDOW_XID (window),
584 dest_extents.x - dx, dest_extents.y - dy,
585 dest_extents.width, dest_extents.height,
586 dest_extents.x, dest_extents.y);
588 /* Unset clip region of cached GC */
589 gdk_gc_set_clip_region (gc, NULL);
591 gdk_region_destroy (src_region);
592 gdk_region_destroy (dest_region);
596 reset_backgrounds (GdkWindow *window)
598 GdkWindowObject *obj = (GdkWindowObject *)window;
600 _gdk_x11_window_tmp_reset_bg (window, FALSE);
603 _gdk_x11_window_tmp_reset_bg ((GdkWindow *)obj->parent, FALSE);
607 map_if_needed (GdkWindow *window, GdkXPositionInfo *pos_info)
609 GdkWindowObject *obj = (GdkWindowObject *) window;
610 GdkWindowImplX11 *impl = GDK_WINDOW_IMPL_X11 (obj->impl);
612 if (!impl->position_info.mapped && pos_info->mapped && GDK_WINDOW_IS_MAPPED (obj))
613 XMapWindow (GDK_DRAWABLE_XDISPLAY (window), GDK_DRAWABLE_XID (window));
617 unmap_if_needed (GdkWindow *window, GdkXPositionInfo *pos_info)
619 GdkWindowObject *obj = (GdkWindowObject *) window;
620 GdkWindowImplX11 *impl = GDK_WINDOW_IMPL_X11 (obj->impl);
622 if (impl->position_info.mapped && !pos_info->mapped)
623 XUnmapWindow (GDK_DRAWABLE_XDISPLAY (window), GDK_DRAWABLE_XID (window));
627 _gdk_window_move_resize_child (GdkWindow *window,
633 GdkWindowImplX11 *impl;
634 GdkWindowObject *obj;
635 GdkXPositionInfo new_info;
636 GdkWindowParentPos parent_pos;
638 gint d_xoffset, d_yoffset;
643 GdkRectangle old_pos;
645 g_return_if_fail (window != NULL);
646 g_return_if_fail (GDK_IS_WINDOW (window));
648 impl = GDK_WINDOW_IMPL_X11 (GDK_WINDOW_OBJECT (window)->impl);
649 obj = GDK_WINDOW_OBJECT (window);
654 is_move = dx != 0 || dy != 0;
655 is_resize = impl->width != width || impl->height != height;
657 if (!is_move && !is_resize)
662 old_pos.width = impl->width;
663 old_pos.height = impl->height;
668 impl->height = height;
670 gdk_window_compute_parent_pos (impl, &parent_pos);
671 gdk_window_compute_position (impl, &parent_pos, &new_info);
673 gdk_window_clip_changed (window, &impl->position_info.clip_rect, &new_info.clip_rect);
675 translate_pos (&parent_pos, &parent_pos, obj, &new_info, TRUE);
677 d_xoffset = new_info.x_offset - impl->position_info.x_offset;
678 d_yoffset = new_info.y_offset - impl->position_info.y_offset;
680 if (d_xoffset != 0 || d_yoffset != 0)
682 GdkRectangle new_position;
684 gdk_window_set_static_gravities (window, TRUE);
686 if (d_xoffset < 0 || d_yoffset < 0)
687 gdk_window_queue_translation (window, NULL, MIN (d_xoffset, 0), MIN (d_yoffset, 0));
689 compute_intermediate_position (&impl->position_info, &new_info, d_xoffset, d_yoffset,
692 move_resize (window, &new_position);
694 g_list_foreach (obj->children, (GFunc) gdk_window_premove, &parent_pos);
696 move_relative (window, &new_position, dx, dy);
698 if (d_xoffset > 0 || d_yoffset > 0)
699 gdk_window_queue_translation (window, NULL, MAX (d_xoffset, 0), MAX (d_yoffset, 0));
701 move_resize (window, (GdkRectangle *) &new_info);
703 reset_backgrounds (window);
705 map_if_needed (window, &new_info);
707 impl->position_info = new_info;
709 g_list_foreach (obj->children, (GFunc) gdk_window_postmove, &parent_pos);
713 if (is_move && is_resize)
714 gdk_window_set_static_gravities (window, FALSE);
716 unmap_if_needed (window, &new_info);
718 g_list_foreach (obj->children, (GFunc) gdk_window_premove, &parent_pos);
721 move_resize (window, (GdkRectangle *) &new_info);
723 move (window, &new_info);
725 g_list_foreach (obj->children, (GFunc) gdk_window_postmove, &parent_pos);
727 reset_backgrounds (window);
729 map_if_needed (window, &new_info);
731 impl->position_info = new_info;
734 if (GDK_WINDOW_IS_MAPPED (obj) && obj->parent)
735 gdk_window_invalidate_rect ((GdkWindow *)obj->parent, &old_pos, FALSE);
739 gdk_window_compute_position (GdkWindowImplX11 *window,
740 GdkWindowParentPos *parent_pos,
741 GdkXPositionInfo *info)
743 GdkWindowObject *wrapper;
747 g_return_if_fail (GDK_IS_WINDOW_IMPL_X11 (window));
749 wrapper = GDK_WINDOW_OBJECT (GDK_DRAWABLE_IMPL_X11 (window)->wrapper);
753 if (window->width <= 32767)
755 info->width = window->width;
756 info->x = parent_pos->x + wrapper->x - parent_pos->x11_x;
762 if (parent_pos->x + wrapper->x < -16384)
764 if (parent_pos->x + wrapper->x + window->width < 16384)
765 info->x = parent_pos->x + wrapper->x + window->width - info->width - parent_pos->x11_x;
767 info->x = -16384 - parent_pos->x11_x;
770 info->x = parent_pos->x + wrapper->x - parent_pos->x11_x;
773 if (window->height <= 32767)
775 info->height = window->height;
776 info->y = parent_pos->y + wrapper->y - parent_pos->x11_y;
781 info->height = 32767;
782 if (parent_pos->y + wrapper->y < -16384)
784 if (parent_pos->y + wrapper->y + window->height < 16384)
785 info->y = parent_pos->y + wrapper->y + window->height - info->height - parent_pos->x11_y;
787 info->y = -16384 - parent_pos->x11_y;
790 info->y = parent_pos->y + wrapper->y - parent_pos->x11_y;
793 parent_x_offset = parent_pos->x11_x - parent_pos->x;
794 parent_y_offset = parent_pos->x11_y - parent_pos->y;
796 info->x_offset = parent_x_offset + info->x - wrapper->x;
797 info->y_offset = parent_y_offset + info->y - wrapper->y;
799 /* We don't considering the clipping of toplevel windows and their immediate children
800 * by their parents, and simply always map those windows.
802 if (parent_pos->clip_rect.width == G_MAXINT)
804 /* Check if the window would wrap around into the visible space in either direction */
805 else if (info->x + parent_x_offset < parent_pos->clip_rect.x + parent_pos->clip_rect.width - 65536 ||
806 info->x + info->width + parent_x_offset > parent_pos->clip_rect.x + 65536 ||
807 info->y + parent_y_offset < parent_pos->clip_rect.y + parent_pos->clip_rect.height - 65536 ||
808 info->y + info->height + parent_y_offset > parent_pos->clip_rect.y + 65536)
809 info->mapped = FALSE;
815 if (GDK_WINDOW_TYPE (wrapper) == GDK_WINDOW_CHILD)
817 info->clip_rect.x = wrapper->x;
818 info->clip_rect.y = wrapper->y;
819 info->clip_rect.width = window->width;
820 info->clip_rect.height = window->height;
822 gdk_rectangle_intersect (&info->clip_rect, &parent_pos->clip_rect, &info->clip_rect);
824 info->clip_rect.x -= wrapper->x;
825 info->clip_rect.y -= wrapper->y;
829 info->clip_rect.x = 0;
830 info->clip_rect.y = 0;
831 info->clip_rect.width = G_MAXINT;
832 info->clip_rect.height = G_MAXINT;
837 gdk_window_compute_parent_pos (GdkWindowImplX11 *window,
838 GdkWindowParentPos *parent_pos)
840 GdkWindowObject *wrapper;
841 GdkWindowObject *parent;
842 GdkRectangle tmp_clip;
844 int clip_xoffset = 0;
845 int clip_yoffset = 0;
847 g_return_if_fail (GDK_IS_WINDOW_IMPL_X11 (window));
850 GDK_WINDOW_OBJECT (GDK_DRAWABLE_IMPL_X11 (window)->wrapper);
854 parent_pos->x11_x = 0;
855 parent_pos->x11_y = 0;
857 /* We take a simple approach here and simply consider toplevel
858 * windows not to clip their children on the right/bottom, since the
859 * size of toplevel windows is not directly under our
860 * control. Clipping only really matters when scrolling and
861 * generally we aren't going to be moving the immediate child of a
862 * toplevel beyond the bounds of that toplevel.
864 * We could go ahead and recompute the clips of toplevel windows and
865 * their descendents when we receive size notification, but it would
866 * probably not be an improvement in most cases.
868 parent_pos->clip_rect.x = 0;
869 parent_pos->clip_rect.y = 0;
870 parent_pos->clip_rect.width = G_MAXINT;
871 parent_pos->clip_rect.height = G_MAXINT;
873 parent = (GdkWindowObject *)wrapper->parent;
874 while (parent && parent->window_type == GDK_WINDOW_CHILD)
876 GdkWindowImplX11 *impl = GDK_WINDOW_IMPL_X11 (parent->impl);
878 tmp_clip.x = - clip_xoffset;
879 tmp_clip.y = - clip_yoffset;
880 tmp_clip.width = impl->width;
881 tmp_clip.height = impl->height;
883 gdk_rectangle_intersect (&parent_pos->clip_rect, &tmp_clip, &parent_pos->clip_rect);
885 translate_pos (parent_pos, parent_pos, parent,
886 &impl->position_info, FALSE);
888 clip_xoffset += parent->x;
889 clip_yoffset += parent->y;
891 parent = (GdkWindowObject *)parent->parent;
896 gdk_window_premove (GdkWindow *window,
897 GdkWindowParentPos *parent_pos)
899 GdkWindowImplX11 *impl;
900 GdkWindowObject *obj;
901 GdkXPositionInfo new_info;
902 gint d_xoffset, d_yoffset;
903 GdkWindowParentPos this_pos;
905 obj = (GdkWindowObject *) window;
906 impl = GDK_WINDOW_IMPL_X11 (obj->impl);
908 gdk_window_compute_position (impl, parent_pos, &new_info);
910 gdk_window_clip_changed (window, &impl->position_info.clip_rect, &new_info.clip_rect);
912 translate_pos (&this_pos, parent_pos, obj, &new_info, TRUE);
914 unmap_if_needed (window, &new_info);
916 d_xoffset = new_info.x_offset - impl->position_info.x_offset;
917 d_yoffset = new_info.y_offset - impl->position_info.y_offset;
919 if (d_xoffset != 0 || d_yoffset != 0)
921 GdkRectangle new_position;
923 if (d_xoffset < 0 || d_yoffset < 0)
924 gdk_window_queue_translation (window, NULL, MIN (d_xoffset, 0), MIN (d_yoffset, 0));
926 compute_intermediate_position (&impl->position_info, &new_info, d_xoffset, d_yoffset,
929 move_resize (window, &new_position);
932 g_list_foreach (obj->children, (GFunc) gdk_window_premove, &this_pos);
936 gdk_window_postmove (GdkWindow *window,
937 GdkWindowParentPos *parent_pos)
939 GdkWindowImplX11 *impl;
940 GdkWindowObject *obj;
941 GdkXPositionInfo new_info;
942 gint d_xoffset, d_yoffset;
943 GdkWindowParentPos this_pos;
945 obj = (GdkWindowObject *) window;
946 impl = GDK_WINDOW_IMPL_X11 (obj->impl);
948 gdk_window_compute_position (impl, parent_pos, &new_info);
950 translate_pos (&this_pos, parent_pos, obj, &new_info, TRUE);
952 d_xoffset = new_info.x_offset - impl->position_info.x_offset;
953 d_yoffset = new_info.y_offset - impl->position_info.y_offset;
955 if (d_xoffset != 0 || d_yoffset != 0)
957 if (d_xoffset > 0 || d_yoffset > 0)
958 gdk_window_queue_translation (window, NULL, MAX (d_xoffset, 0), MAX (d_yoffset, 0));
960 move_resize (window, (GdkRectangle *) &new_info);
963 map_if_needed (window, &new_info);
965 reset_backgrounds (window);
967 impl->position_info = new_info;
969 g_list_foreach (obj->children, (GFunc) gdk_window_postmove, &this_pos);
973 expose_serial_predicate (Display *xdisplay,
977 gulong *serial = (gulong *)arg;
979 if (xev->xany.type == Expose)
980 *serial = MIN (*serial, xev->xany.serial);
985 /* Find oldest possible serial for an outstanding expose event
988 find_current_serial (Display *xdisplay)
991 gulong serial = NextRequest (xdisplay);
993 XSync (xdisplay, False);
995 XCheckIfEvent (xdisplay, &xev, expose_serial_predicate, (XPointer)&serial);
1001 queue_delete_link (GQueue *queue,
1004 if (queue->tail == link)
1005 queue->tail = link->prev;
1007 queue->head = g_list_remove_link (queue->head, link);
1008 g_list_free_1 (link);
1013 queue_item_free (GdkWindowQueueItem *item)
1017 g_object_remove_weak_pointer (G_OBJECT (item->window),
1018 (gpointer *)&(item->window));
1021 if (item->type == GDK_WINDOW_QUEUE_ANTIEXPOSE)
1022 gdk_region_destroy (item->u.antiexpose.area);
1025 if (item->u.translate.area)
1026 gdk_region_destroy (item->u.translate.area);
1033 gdk_window_queue (GdkWindow *window,
1034 GdkWindowQueueItem *item)
1036 GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (GDK_WINDOW_DISPLAY (window));
1038 if (!display_x11->translate_queue)
1039 display_x11->translate_queue = g_queue_new ();
1041 /* Keep length of queue finite by, if it grows too long,
1042 * figuring out the latest relevant serial and discarding
1043 * irrelevant queue items.
1045 if (display_x11->translate_queue->length >= 64)
1047 gulong serial = find_current_serial (GDK_WINDOW_XDISPLAY (window));
1048 GList *tmp_list = display_x11->translate_queue->head;
1052 GdkWindowQueueItem *item = tmp_list->data;
1053 GList *next = tmp_list->next;
1055 /* an overflow-safe (item->serial < serial) */
1056 if (item->serial - serial > (gulong) G_MAXLONG)
1058 queue_delete_link (display_x11->translate_queue, tmp_list);
1059 queue_item_free (item);
1066 /* Catch the case where someone isn't processing events and there
1067 * is an event stuck in the event queue with an old serial:
1068 * If we can't reduce the queue length by the above method,
1069 * discard anti-expose items. (We can't discard translate
1072 if (display_x11->translate_queue->length >= 64)
1074 GList *tmp_list = display_x11->translate_queue->head;
1078 GdkWindowQueueItem *item = tmp_list->data;
1079 GList *next = tmp_list->next;
1081 if (item->type == GDK_WINDOW_QUEUE_ANTIEXPOSE)
1083 queue_delete_link (display_x11->translate_queue, tmp_list);
1084 queue_item_free (item);
1091 item->window = window;
1092 item->serial = NextRequest (GDK_WINDOW_XDISPLAY (window));
1094 g_object_add_weak_pointer (G_OBJECT (window),
1095 (gpointer *)&(item->window));
1097 g_queue_push_tail (display_x11->translate_queue, item);
1101 gdk_window_queue_translation (GdkWindow *window,
1106 GdkWindowQueueItem *item = g_new (GdkWindowQueueItem, 1);
1107 item->type = GDK_WINDOW_QUEUE_TRANSLATE;
1108 item->u.translate.area = area ? gdk_region_copy (area) : NULL;
1109 item->u.translate.dx = dx;
1110 item->u.translate.dy = dy;
1112 gdk_window_queue (window, item);
1116 _gdk_windowing_window_queue_antiexpose (GdkWindow *window,
1119 GdkWindowQueueItem *item = g_new (GdkWindowQueueItem, 1);
1120 item->type = GDK_WINDOW_QUEUE_ANTIEXPOSE;
1121 item->u.antiexpose.area = area;
1123 gdk_window_queue (window, item);
1129 _gdk_window_process_expose (GdkWindow *window,
1133 GdkWindowImplX11 *impl;
1134 GdkRegion *invalidate_region = gdk_region_rectangle (area);
1135 GdkRegion *clip_region;
1136 GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (GDK_WINDOW_DISPLAY (window));
1137 impl = GDK_WINDOW_IMPL_X11 (GDK_WINDOW_OBJECT (window)->impl);
1139 if (display_x11->translate_queue)
1141 GList *tmp_list = display_x11->translate_queue->head;
1145 GdkWindowQueueItem *item = tmp_list->data;
1146 GList *next = tmp_list->next;
1148 /* an overflow-safe (serial < item->serial) */
1149 if (serial - item->serial > (gulong) G_MAXLONG)
1151 if (item->window == window)
1153 if (item->type == GDK_WINDOW_QUEUE_TRANSLATE)
1155 if (item->u.translate.area)
1157 GdkRegion *intersection;
1159 intersection = gdk_region_copy (invalidate_region);
1160 gdk_region_intersect (intersection, item->u.translate.area);
1161 gdk_region_subtract (invalidate_region, intersection);
1162 gdk_region_offset (intersection, item->u.translate.dx, item->u.translate.dy);
1163 gdk_region_union (invalidate_region, intersection);
1164 gdk_region_destroy (intersection);
1167 gdk_region_offset (invalidate_region, item->u.translate.dx, item->u.translate.dy);
1169 else /* anti-expose */
1171 gdk_region_subtract (invalidate_region, item->u.antiexpose.area);
1177 queue_delete_link (display_x11->translate_queue, tmp_list);
1178 queue_item_free (item);
1184 clip_region = gdk_region_rectangle (&impl->position_info.clip_rect);
1185 gdk_region_intersect (invalidate_region, clip_region);
1187 if (!gdk_region_empty (invalidate_region))
1188 gdk_window_invalidate_region (window, invalidate_region, FALSE);
1190 gdk_region_destroy (invalidate_region);
1191 gdk_region_destroy (clip_region);
1195 gdk_window_clip_changed (GdkWindow *window, GdkRectangle *old_clip, GdkRectangle *new_clip)
1197 GdkWindowImplX11 *impl;
1198 GdkWindowObject *obj;
1199 GdkRegion *old_clip_region;
1200 GdkRegion *new_clip_region;
1202 if (((GdkWindowObject *)window)->input_only)
1205 obj = (GdkWindowObject *) window;
1206 impl = GDK_WINDOW_IMPL_X11 (obj->impl);
1208 old_clip_region = gdk_region_rectangle (old_clip);
1209 new_clip_region = gdk_region_rectangle (new_clip);
1211 /* We need to update this here because gdk_window_invalidate_region makes
1212 * use if it (through gdk_drawable_get_visible_region
1214 impl->position_info.clip_rect = *new_clip;
1216 /* Trim invalid region of window to new clip rectangle
1218 if (obj->update_area)
1219 gdk_region_intersect (obj->update_area, new_clip_region);
1221 /* Invalidate newly exposed portion of window
1223 gdk_region_subtract (new_clip_region, old_clip_region);
1224 if (!gdk_region_empty (new_clip_region))
1226 _gdk_x11_window_tmp_unset_bg (window, FALSE);;
1227 gdk_window_invalidate_region (window, new_clip_region, FALSE);
1231 _gdk_x11_window_tmp_unset_bg ((GdkWindow *)obj->parent, FALSE);
1233 gdk_region_destroy (new_clip_region);
1234 gdk_region_destroy (old_clip_region);
1237 #define __GDK_GEOMETRY_X11_C__
1238 #include "gdkaliasdef.c"