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_x11_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);
399 _gdk_x11_window_scroll (GdkWindow *window,
403 gboolean can_guffaw_scroll = FALSE;
404 GdkRegion *invalidate_region;
405 GdkWindowImplX11 *impl;
406 GdkWindowObject *obj;
407 GdkRectangle src_rect, dest_rect;
409 obj = GDK_WINDOW_OBJECT (window);
410 impl = GDK_WINDOW_IMPL_X11 (obj->impl);
412 /* Move the current invalid region */
413 if (obj->update_area)
414 gdk_region_offset (obj->update_area, dx, dy);
416 /* impl->position_info.clip_rect isn't meaningful for toplevels */
417 if (GDK_WINDOW_TYPE (window) == GDK_WINDOW_CHILD)
418 src_rect = impl->position_info.clip_rect;
423 src_rect.width = impl->width;
424 src_rect.height = impl->height;
427 invalidate_region = gdk_region_rectangle (&src_rect);
429 dest_rect = src_rect;
432 gdk_rectangle_intersect (&dest_rect, &src_rect, &dest_rect);
434 if (dest_rect.width > 0 && dest_rect.height > 0)
436 GdkRegion *tmp_region;
438 tmp_region = gdk_region_rectangle (&dest_rect);
439 gdk_region_subtract (invalidate_region, tmp_region);
440 gdk_region_destroy (tmp_region);
443 gdk_window_invalidate_region (window, invalidate_region, TRUE);
444 gdk_region_destroy (invalidate_region);
446 /* We can guffaw scroll if we are a child window, and the parent
447 * does not extend beyond our edges. Otherwise, we use XCopyArea, then
448 * move any children later
450 if (GDK_WINDOW_TYPE (window) == GDK_WINDOW_CHILD)
452 GdkWindowImplX11 *parent_impl = GDK_WINDOW_IMPL_X11 (obj->parent->impl);
453 can_guffaw_scroll = ((dx == 0 || (obj->x <= 0 && obj->x + impl->width >= parent_impl->width)) &&
454 (dy == 0 || (obj->y <= 0 && obj->y + impl->height >= parent_impl->height)));
457 if (!obj->children || !can_guffaw_scroll)
458 gdk_window_copy_area_scroll (window, &dest_rect, dx, dy);
460 gdk_window_guffaw_scroll (window, dx, dy);
464 _gdk_x11_window_move_region (GdkWindow *window,
465 const GdkRegion *region,
469 GdkWindowImplX11 *impl;
470 GdkWindowObject *private;
471 GdkRegion *window_clip;
472 GdkRegion *src_region;
473 GdkRegion *brought_in;
474 GdkRegion *dest_region;
475 GdkRegion *moving_invalid_region;
476 GdkRectangle dest_extents;
479 private = GDK_WINDOW_OBJECT (window);
480 impl = GDK_WINDOW_IMPL_X11 (private->impl);
482 window_clip = gdk_region_rectangle (&impl->position_info.clip_rect);
484 /* compute source regions */
485 src_region = gdk_region_copy (region);
486 brought_in = gdk_region_copy (region);
487 gdk_region_intersect (src_region, window_clip);
489 gdk_region_subtract (brought_in, src_region);
490 gdk_region_offset (brought_in, dx, dy);
492 /* compute destination regions */
493 dest_region = gdk_region_copy (src_region);
494 gdk_region_offset (dest_region, dx, dy);
495 gdk_region_intersect (dest_region, window_clip);
496 gdk_region_get_clipbox (dest_region, &dest_extents);
498 gdk_region_destroy (window_clip);
500 /* calculating moving part of current invalid area */
501 moving_invalid_region = NULL;
502 if (private->update_area)
504 moving_invalid_region = gdk_region_copy (private->update_area);
505 gdk_region_intersect (moving_invalid_region, src_region);
506 gdk_region_offset (moving_invalid_region, dx, dy);
509 /* invalidate all of the src region */
510 gdk_window_invalidate_region (window, src_region, FALSE);
512 /* un-invalidate destination region */
513 if (private->update_area)
514 gdk_region_subtract (private->update_area, dest_region);
516 /* invalidate moving parts of existing update area */
517 if (moving_invalid_region)
519 gdk_window_invalidate_region (window, moving_invalid_region, FALSE);
520 gdk_region_destroy (moving_invalid_region);
523 /* invalidate area brought in from off-screen */
524 gdk_window_invalidate_region (window, brought_in, FALSE);
525 gdk_region_destroy (brought_in);
527 /* Actually do the moving */
528 gdk_window_queue_translation (window, src_region, dx, dy);
530 gc = _gdk_drawable_get_scratch_gc (window, TRUE);
531 gdk_gc_set_clip_region (gc, dest_region);
533 XCopyArea (GDK_WINDOW_XDISPLAY (window),
534 GDK_WINDOW_XID (window),
535 GDK_WINDOW_XID (window),
537 dest_extents.x - dx, dest_extents.y - dy,
538 dest_extents.width, dest_extents.height,
539 dest_extents.x, dest_extents.y);
541 /* Unset clip region of cached GC */
542 gdk_gc_set_clip_region (gc, NULL);
544 gdk_region_destroy (src_region);
545 gdk_region_destroy (dest_region);
549 reset_backgrounds (GdkWindow *window)
551 GdkWindowObject *obj = (GdkWindowObject *)window;
553 _gdk_x11_window_tmp_reset_bg (window, FALSE);
556 _gdk_x11_window_tmp_reset_bg ((GdkWindow *)obj->parent, FALSE);
560 map_if_needed (GdkWindow *window, GdkXPositionInfo *pos_info)
562 GdkWindowObject *obj = (GdkWindowObject *) window;
563 GdkWindowImplX11 *impl = GDK_WINDOW_IMPL_X11 (obj->impl);
565 if (!impl->position_info.mapped && pos_info->mapped && GDK_WINDOW_IS_MAPPED (obj))
566 XMapWindow (GDK_DRAWABLE_XDISPLAY (window), GDK_DRAWABLE_XID (window));
570 unmap_if_needed (GdkWindow *window, GdkXPositionInfo *pos_info)
572 GdkWindowObject *obj = (GdkWindowObject *) window;
573 GdkWindowImplX11 *impl = GDK_WINDOW_IMPL_X11 (obj->impl);
575 if (impl->position_info.mapped && !pos_info->mapped)
576 XUnmapWindow (GDK_DRAWABLE_XDISPLAY (window), GDK_DRAWABLE_XID (window));
580 _gdk_window_move_resize_child (GdkWindow *window,
586 GdkWindowImplX11 *impl;
587 GdkWindowObject *obj;
588 GdkXPositionInfo new_info;
589 GdkWindowParentPos parent_pos;
591 gint d_xoffset, d_yoffset;
596 GdkRectangle old_pos;
598 g_return_if_fail (window != NULL);
599 g_return_if_fail (GDK_IS_WINDOW (window));
601 impl = GDK_WINDOW_IMPL_X11 (GDK_WINDOW_OBJECT (window)->impl);
602 obj = GDK_WINDOW_OBJECT (window);
607 is_move = dx != 0 || dy != 0;
608 is_resize = impl->width != width || impl->height != height;
610 if (!is_move && !is_resize)
615 old_pos.width = impl->width;
616 old_pos.height = impl->height;
621 impl->height = height;
623 gdk_window_compute_parent_pos (impl, &parent_pos);
624 gdk_window_compute_position (impl, &parent_pos, &new_info);
626 gdk_window_clip_changed (window, &impl->position_info.clip_rect, &new_info.clip_rect);
628 translate_pos (&parent_pos, &parent_pos, obj, &new_info, TRUE);
630 d_xoffset = new_info.x_offset - impl->position_info.x_offset;
631 d_yoffset = new_info.y_offset - impl->position_info.y_offset;
633 if (d_xoffset != 0 || d_yoffset != 0)
635 GdkRectangle new_position;
637 gdk_window_set_static_gravities (window, TRUE);
639 if (d_xoffset < 0 || d_yoffset < 0)
640 gdk_window_queue_translation (window, NULL, MIN (d_xoffset, 0), MIN (d_yoffset, 0));
642 compute_intermediate_position (&impl->position_info, &new_info, d_xoffset, d_yoffset,
645 move_resize (window, &new_position);
647 g_list_foreach (obj->children, (GFunc) gdk_window_premove, &parent_pos);
649 move_relative (window, &new_position, dx, dy);
651 if (d_xoffset > 0 || d_yoffset > 0)
652 gdk_window_queue_translation (window, NULL, MAX (d_xoffset, 0), MAX (d_yoffset, 0));
654 move_resize (window, (GdkRectangle *) &new_info);
656 reset_backgrounds (window);
658 map_if_needed (window, &new_info);
660 impl->position_info = new_info;
662 g_list_foreach (obj->children, (GFunc) gdk_window_postmove, &parent_pos);
666 if (is_move && is_resize)
667 gdk_window_set_static_gravities (window, FALSE);
669 unmap_if_needed (window, &new_info);
671 g_list_foreach (obj->children, (GFunc) gdk_window_premove, &parent_pos);
674 move_resize (window, (GdkRectangle *) &new_info);
676 move (window, &new_info);
678 g_list_foreach (obj->children, (GFunc) gdk_window_postmove, &parent_pos);
680 reset_backgrounds (window);
682 map_if_needed (window, &new_info);
684 impl->position_info = new_info;
687 if (GDK_WINDOW_IS_MAPPED (obj) && obj->parent && !obj->input_only)
688 gdk_window_invalidate_rect ((GdkWindow *)obj->parent, &old_pos, FALSE);
692 gdk_window_compute_position (GdkWindowImplX11 *window,
693 GdkWindowParentPos *parent_pos,
694 GdkXPositionInfo *info)
696 GdkWindowObject *wrapper;
700 g_return_if_fail (GDK_IS_WINDOW_IMPL_X11 (window));
702 wrapper = GDK_WINDOW_OBJECT (GDK_DRAWABLE_IMPL_X11 (window)->wrapper);
706 if (window->width <= 32767)
708 info->width = window->width;
709 info->x = parent_pos->x + wrapper->x - parent_pos->x11_x;
715 if (parent_pos->x + wrapper->x < -16384)
717 if (parent_pos->x + wrapper->x + window->width < 16384)
718 info->x = parent_pos->x + wrapper->x + window->width - info->width - parent_pos->x11_x;
720 info->x = -16384 - parent_pos->x11_x;
723 info->x = parent_pos->x + wrapper->x - parent_pos->x11_x;
726 if (window->height <= 32767)
728 info->height = window->height;
729 info->y = parent_pos->y + wrapper->y - parent_pos->x11_y;
734 info->height = 32767;
735 if (parent_pos->y + wrapper->y < -16384)
737 if (parent_pos->y + wrapper->y + window->height < 16384)
738 info->y = parent_pos->y + wrapper->y + window->height - info->height - parent_pos->x11_y;
740 info->y = -16384 - parent_pos->x11_y;
743 info->y = parent_pos->y + wrapper->y - parent_pos->x11_y;
746 parent_x_offset = parent_pos->x11_x - parent_pos->x;
747 parent_y_offset = parent_pos->x11_y - parent_pos->y;
749 info->x_offset = parent_x_offset + info->x - wrapper->x;
750 info->y_offset = parent_y_offset + info->y - wrapper->y;
752 /* We don't considering the clipping of toplevel windows and their immediate children
753 * by their parents, and simply always map those windows.
755 if (parent_pos->clip_rect.width == G_MAXINT)
757 /* Check if the window would wrap around into the visible space in either direction */
758 else if (info->x + parent_x_offset < parent_pos->clip_rect.x + parent_pos->clip_rect.width - 65536 ||
759 info->x + info->width + parent_x_offset > parent_pos->clip_rect.x + 65536 ||
760 info->y + parent_y_offset < parent_pos->clip_rect.y + parent_pos->clip_rect.height - 65536 ||
761 info->y + info->height + parent_y_offset > parent_pos->clip_rect.y + 65536)
762 info->mapped = FALSE;
768 if (GDK_WINDOW_TYPE (wrapper) == GDK_WINDOW_CHILD)
770 info->clip_rect.x = wrapper->x;
771 info->clip_rect.y = wrapper->y;
772 info->clip_rect.width = window->width;
773 info->clip_rect.height = window->height;
775 gdk_rectangle_intersect (&info->clip_rect, &parent_pos->clip_rect, &info->clip_rect);
777 info->clip_rect.x -= wrapper->x;
778 info->clip_rect.y -= wrapper->y;
782 info->clip_rect.x = 0;
783 info->clip_rect.y = 0;
784 info->clip_rect.width = G_MAXINT;
785 info->clip_rect.height = G_MAXINT;
790 gdk_window_compute_parent_pos (GdkWindowImplX11 *window,
791 GdkWindowParentPos *parent_pos)
793 GdkWindowObject *wrapper;
794 GdkWindowObject *parent;
795 GdkRectangle tmp_clip;
797 int clip_xoffset = 0;
798 int clip_yoffset = 0;
800 g_return_if_fail (GDK_IS_WINDOW_IMPL_X11 (window));
803 GDK_WINDOW_OBJECT (GDK_DRAWABLE_IMPL_X11 (window)->wrapper);
807 parent_pos->x11_x = 0;
808 parent_pos->x11_y = 0;
810 /* We take a simple approach here and simply consider toplevel
811 * windows not to clip their children on the right/bottom, since the
812 * size of toplevel windows is not directly under our
813 * control. Clipping only really matters when scrolling and
814 * generally we aren't going to be moving the immediate child of a
815 * toplevel beyond the bounds of that toplevel.
817 * We could go ahead and recompute the clips of toplevel windows and
818 * their descendents when we receive size notification, but it would
819 * probably not be an improvement in most cases.
821 parent_pos->clip_rect.x = 0;
822 parent_pos->clip_rect.y = 0;
823 parent_pos->clip_rect.width = G_MAXINT;
824 parent_pos->clip_rect.height = G_MAXINT;
826 parent = (GdkWindowObject *)wrapper->parent;
827 while (parent && parent->window_type == GDK_WINDOW_CHILD)
829 GdkWindowImplX11 *impl = GDK_WINDOW_IMPL_X11 (parent->impl);
831 tmp_clip.x = - clip_xoffset;
832 tmp_clip.y = - clip_yoffset;
833 tmp_clip.width = impl->width;
834 tmp_clip.height = impl->height;
836 gdk_rectangle_intersect (&parent_pos->clip_rect, &tmp_clip, &parent_pos->clip_rect);
838 translate_pos (parent_pos, parent_pos, parent,
839 &impl->position_info, FALSE);
841 clip_xoffset += parent->x;
842 clip_yoffset += parent->y;
844 parent = (GdkWindowObject *)parent->parent;
849 gdk_window_premove (GdkWindow *window,
850 GdkWindowParentPos *parent_pos)
852 GdkWindowImplX11 *impl;
853 GdkWindowObject *obj;
854 GdkXPositionInfo new_info;
855 gint d_xoffset, d_yoffset;
856 GdkWindowParentPos this_pos;
858 obj = (GdkWindowObject *) window;
859 impl = GDK_WINDOW_IMPL_X11 (obj->impl);
861 gdk_window_compute_position (impl, parent_pos, &new_info);
863 gdk_window_clip_changed (window, &impl->position_info.clip_rect, &new_info.clip_rect);
865 translate_pos (&this_pos, parent_pos, obj, &new_info, TRUE);
867 unmap_if_needed (window, &new_info);
869 d_xoffset = new_info.x_offset - impl->position_info.x_offset;
870 d_yoffset = new_info.y_offset - impl->position_info.y_offset;
872 if (d_xoffset != 0 || d_yoffset != 0)
874 GdkRectangle new_position;
876 if (d_xoffset < 0 || d_yoffset < 0)
877 gdk_window_queue_translation (window, NULL, MIN (d_xoffset, 0), MIN (d_yoffset, 0));
879 compute_intermediate_position (&impl->position_info, &new_info, d_xoffset, d_yoffset,
882 move_resize (window, &new_position);
885 g_list_foreach (obj->children, (GFunc) gdk_window_premove, &this_pos);
889 gdk_window_postmove (GdkWindow *window,
890 GdkWindowParentPos *parent_pos)
892 GdkWindowImplX11 *impl;
893 GdkWindowObject *obj;
894 GdkXPositionInfo new_info;
895 gint d_xoffset, d_yoffset;
896 GdkWindowParentPos this_pos;
898 obj = (GdkWindowObject *) window;
899 impl = GDK_WINDOW_IMPL_X11 (obj->impl);
901 gdk_window_compute_position (impl, parent_pos, &new_info);
903 translate_pos (&this_pos, parent_pos, obj, &new_info, TRUE);
905 d_xoffset = new_info.x_offset - impl->position_info.x_offset;
906 d_yoffset = new_info.y_offset - impl->position_info.y_offset;
908 if (d_xoffset != 0 || d_yoffset != 0)
910 if (d_xoffset > 0 || d_yoffset > 0)
911 gdk_window_queue_translation (window, NULL, MAX (d_xoffset, 0), MAX (d_yoffset, 0));
913 move_resize (window, (GdkRectangle *) &new_info);
916 map_if_needed (window, &new_info);
918 reset_backgrounds (window);
920 impl->position_info = new_info;
922 g_list_foreach (obj->children, (GFunc) gdk_window_postmove, &this_pos);
926 expose_serial_predicate (Display *xdisplay,
930 gulong *serial = (gulong *)arg;
932 if (xev->xany.type == Expose)
933 *serial = MIN (*serial, xev->xany.serial);
938 /* Find oldest possible serial for an outstanding expose event
941 find_current_serial (Display *xdisplay)
944 gulong serial = NextRequest (xdisplay);
946 XSync (xdisplay, False);
948 XCheckIfEvent (xdisplay, &xev, expose_serial_predicate, (XPointer)&serial);
954 queue_delete_link (GQueue *queue,
957 if (queue->tail == link)
958 queue->tail = link->prev;
960 queue->head = g_list_remove_link (queue->head, link);
961 g_list_free_1 (link);
966 queue_item_free (GdkWindowQueueItem *item)
970 g_object_remove_weak_pointer (G_OBJECT (item->window),
971 (gpointer *)&(item->window));
974 if (item->type == GDK_WINDOW_QUEUE_ANTIEXPOSE)
975 gdk_region_destroy (item->u.antiexpose.area);
978 if (item->u.translate.area)
979 gdk_region_destroy (item->u.translate.area);
986 gdk_window_queue (GdkWindow *window,
987 GdkWindowQueueItem *item)
989 GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (GDK_WINDOW_DISPLAY (window));
991 if (!display_x11->translate_queue)
992 display_x11->translate_queue = g_queue_new ();
994 /* Keep length of queue finite by, if it grows too long,
995 * figuring out the latest relevant serial and discarding
996 * irrelevant queue items.
998 if (display_x11->translate_queue->length >= 64)
1000 gulong serial = find_current_serial (GDK_WINDOW_XDISPLAY (window));
1001 GList *tmp_list = display_x11->translate_queue->head;
1005 GdkWindowQueueItem *item = tmp_list->data;
1006 GList *next = tmp_list->next;
1008 /* an overflow-safe (item->serial < serial) */
1009 if (item->serial - serial > (gulong) G_MAXLONG)
1011 queue_delete_link (display_x11->translate_queue, tmp_list);
1012 queue_item_free (item);
1019 /* Catch the case where someone isn't processing events and there
1020 * is an event stuck in the event queue with an old serial:
1021 * If we can't reduce the queue length by the above method,
1022 * discard anti-expose items. (We can't discard translate
1025 if (display_x11->translate_queue->length >= 64)
1027 GList *tmp_list = display_x11->translate_queue->head;
1031 GdkWindowQueueItem *item = tmp_list->data;
1032 GList *next = tmp_list->next;
1034 if (item->type == GDK_WINDOW_QUEUE_ANTIEXPOSE)
1036 queue_delete_link (display_x11->translate_queue, tmp_list);
1037 queue_item_free (item);
1044 item->window = window;
1045 item->serial = NextRequest (GDK_WINDOW_XDISPLAY (window));
1047 g_object_add_weak_pointer (G_OBJECT (window),
1048 (gpointer *)&(item->window));
1050 g_queue_push_tail (display_x11->translate_queue, item);
1054 gdk_window_queue_translation (GdkWindow *window,
1059 GdkWindowQueueItem *item = g_new (GdkWindowQueueItem, 1);
1060 item->type = GDK_WINDOW_QUEUE_TRANSLATE;
1061 item->u.translate.area = area ? gdk_region_copy (area) : NULL;
1062 item->u.translate.dx = dx;
1063 item->u.translate.dy = dy;
1065 gdk_window_queue (window, item);
1069 _gdk_windowing_window_queue_antiexpose (GdkWindow *window,
1072 GdkWindowQueueItem *item = g_new (GdkWindowQueueItem, 1);
1073 item->type = GDK_WINDOW_QUEUE_ANTIEXPOSE;
1074 item->u.antiexpose.area = area;
1076 gdk_window_queue (window, item);
1082 _gdk_window_process_expose (GdkWindow *window,
1086 GdkWindowImplX11 *impl;
1087 GdkRegion *invalidate_region = gdk_region_rectangle (area);
1088 GdkRegion *clip_region;
1089 GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (GDK_WINDOW_DISPLAY (window));
1090 impl = GDK_WINDOW_IMPL_X11 (GDK_WINDOW_OBJECT (window)->impl);
1092 if (display_x11->translate_queue)
1094 GList *tmp_list = display_x11->translate_queue->head;
1098 GdkWindowQueueItem *item = tmp_list->data;
1099 GList *next = tmp_list->next;
1101 /* an overflow-safe (serial < item->serial) */
1102 if (serial - item->serial > (gulong) G_MAXLONG)
1104 if (item->window == window)
1106 if (item->type == GDK_WINDOW_QUEUE_TRANSLATE)
1108 if (item->u.translate.area)
1110 GdkRegion *intersection;
1112 intersection = gdk_region_copy (invalidate_region);
1113 gdk_region_intersect (intersection, item->u.translate.area);
1114 gdk_region_subtract (invalidate_region, intersection);
1115 gdk_region_offset (intersection, item->u.translate.dx, item->u.translate.dy);
1116 gdk_region_union (invalidate_region, intersection);
1117 gdk_region_destroy (intersection);
1120 gdk_region_offset (invalidate_region, item->u.translate.dx, item->u.translate.dy);
1122 else /* anti-expose */
1124 gdk_region_subtract (invalidate_region, item->u.antiexpose.area);
1130 queue_delete_link (display_x11->translate_queue, tmp_list);
1131 queue_item_free (item);
1137 clip_region = gdk_region_rectangle (&impl->position_info.clip_rect);
1138 gdk_region_intersect (invalidate_region, clip_region);
1140 if (!gdk_region_empty (invalidate_region))
1141 gdk_window_invalidate_region (window, invalidate_region, FALSE);
1143 gdk_region_destroy (invalidate_region);
1144 gdk_region_destroy (clip_region);
1148 gdk_window_clip_changed (GdkWindow *window, GdkRectangle *old_clip, GdkRectangle *new_clip)
1150 GdkWindowImplX11 *impl;
1151 GdkWindowObject *obj;
1152 GdkRegion *old_clip_region;
1153 GdkRegion *new_clip_region;
1155 if (((GdkWindowObject *)window)->input_only)
1158 obj = (GdkWindowObject *) window;
1159 impl = GDK_WINDOW_IMPL_X11 (obj->impl);
1161 old_clip_region = gdk_region_rectangle (old_clip);
1162 new_clip_region = gdk_region_rectangle (new_clip);
1164 /* We need to update this here because gdk_window_invalidate_region makes
1165 * use if it (through gdk_drawable_get_visible_region
1167 impl->position_info.clip_rect = *new_clip;
1169 /* Trim invalid region of window to new clip rectangle
1171 if (obj->update_area)
1172 gdk_region_intersect (obj->update_area, new_clip_region);
1174 /* Invalidate newly exposed portion of window
1176 gdk_region_subtract (new_clip_region, old_clip_region);
1177 if (!gdk_region_empty (new_clip_region))
1179 _gdk_x11_window_tmp_unset_bg (window, FALSE);;
1180 gdk_window_invalidate_region (window, new_clip_region, FALSE);
1184 _gdk_x11_window_tmp_unset_bg ((GdkWindow *)obj->parent, FALSE);
1186 gdk_region_destroy (new_clip_region);
1187 gdk_region_destroy (old_clip_region);
1190 #define __GDK_GEOMETRY_X11_C__
1191 #include "gdkaliasdef.c"