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.
132 #include "gdk.h" /* For gdk_rectangle_intersect */
133 #include "gdkprivate-x11.h"
135 #include "gdkregion.h"
136 #include "gdkinternals.h"
137 #include "gdkscreen-x11.h"
138 #include "gdkdisplay-x11.h"
140 typedef struct _GdkWindowQueueItem GdkWindowQueueItem;
141 typedef struct _GdkWindowParentPos GdkWindowParentPos;
144 GDK_WINDOW_QUEUE_TRANSLATE,
145 GDK_WINDOW_QUEUE_ANTIEXPOSE
146 } GdkWindowQueueType;
148 struct _GdkWindowQueueItem
152 GdkWindowQueueType type;
164 struct _GdkWindowParentPos
170 GdkRectangle clip_rect;
173 static void gdk_window_compute_position (GdkWindowImplX11 *window,
174 GdkWindowParentPos *parent_pos,
175 GdkXPositionInfo *info);
176 static void gdk_window_compute_parent_pos (GdkWindowImplX11 *window,
177 GdkWindowParentPos *parent_pos);
178 static void gdk_window_premove (GdkWindow *window,
179 GdkWindowParentPos *parent_pos);
180 static void gdk_window_postmove (GdkWindow *window,
181 GdkWindowParentPos *parent_pos);
182 static void gdk_window_queue_translation (GdkWindow *window,
185 static void gdk_window_tmp_unset_bg (GdkWindow *window);
186 static void gdk_window_tmp_reset_bg (GdkWindow *window);
187 static void gdk_window_clip_changed (GdkWindow *window,
188 GdkRectangle *old_clip,
189 GdkRectangle *new_clip);
192 _gdk_windowing_window_get_offsets (GdkWindow *window,
196 GdkWindowImplX11 *impl =
197 GDK_WINDOW_IMPL_X11 (GDK_WINDOW_OBJECT (window)->impl);
199 *x_offset = impl->position_info.x_offset;
200 *y_offset = impl->position_info.y_offset;
204 _gdk_window_init_position (GdkWindow *window)
206 GdkWindowParentPos parent_pos;
207 GdkWindowImplX11 *impl;
209 g_return_if_fail (GDK_IS_WINDOW (window));
212 GDK_WINDOW_IMPL_X11 (GDK_WINDOW_OBJECT (window)->impl);
214 gdk_window_compute_parent_pos (impl, &parent_pos);
215 gdk_window_compute_position (impl, &parent_pos, &impl->position_info);
219 gdk_window_copy_area_scroll (GdkWindow *window,
220 GdkRectangle *dest_rect,
224 GdkWindowObject *obj = GDK_WINDOW_OBJECT (window);
227 if (dest_rect->width > 0 && dest_rect->height > 0)
231 gc = _gdk_drawable_get_scratch_gc (window, TRUE);
233 gdk_window_queue_translation (window, dx, dy);
235 XCopyArea (GDK_WINDOW_XDISPLAY (window),
236 GDK_WINDOW_XID (window),
237 GDK_WINDOW_XID (window),
238 gdk_x11_gc_get_xgc (gc),
239 dest_rect->x - dx, dest_rect->y - dy,
240 dest_rect->width, dest_rect->height,
241 dest_rect->x, dest_rect->y);
244 tmp_list = obj->children;
247 GdkWindow *child = GDK_WINDOW (tmp_list->data);
248 GdkWindowObject *child_obj = GDK_WINDOW_OBJECT (child);
250 gdk_window_move (child, child_obj->x + dx, child_obj->y + dy);
252 tmp_list = tmp_list->next;
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 gdk_window_guffaw_scroll (GdkWindow *window,
307 GdkWindowObject *obj = GDK_WINDOW_OBJECT (window);
308 GdkWindowImplX11 *impl = GDK_WINDOW_IMPL_X11 (obj->impl);
310 gint d_xoffset = -dx;
311 gint d_yoffset = -dy;
312 GdkRectangle new_position;
313 GdkXPositionInfo new_info;
314 GdkWindowParentPos parent_pos;
317 gdk_window_compute_parent_pos (impl, &parent_pos);
318 gdk_window_compute_position (impl, &parent_pos, &new_info);
320 parent_pos.x += obj->x;
321 parent_pos.y += obj->y;
322 parent_pos.x11_x += new_info.x;
323 parent_pos.x11_y += new_info.y;
324 parent_pos.clip_rect = new_info.clip_rect;
326 gdk_window_tmp_unset_bg (window);
328 if (dx > 0 || dy > 0)
329 gdk_window_queue_translation (window, MAX (dx, 0), MAX (dy, 0));
331 gdk_window_set_static_gravities (window, TRUE);
333 compute_intermediate_position (&impl->position_info, &new_info, d_xoffset, d_yoffset,
336 XMoveResizeWindow (GDK_WINDOW_XDISPLAY (window),
337 GDK_WINDOW_XID (window),
338 new_position.x, new_position.y, new_position.width, new_position.height);
340 tmp_list = obj->children;
343 GDK_WINDOW_OBJECT(tmp_list->data)->x -= d_xoffset;
344 GDK_WINDOW_OBJECT(tmp_list->data)->y -= d_yoffset;
346 gdk_window_premove (tmp_list->data, &parent_pos);
347 tmp_list = tmp_list->next;
350 XMoveWindow (GDK_WINDOW_XDISPLAY (window),
351 GDK_WINDOW_XID (window),
352 new_position.x - d_xoffset, new_position.y - d_yoffset);
354 if (dx < 0 || dy < 0)
355 gdk_window_queue_translation (window, MIN (dx, 0), MIN (dy, 0));
357 XMoveResizeWindow (GDK_WINDOW_XDISPLAY (window),
358 GDK_WINDOW_XID (window),
359 impl->position_info.x, impl->position_info.y,
360 impl->position_info.width, impl->position_info.height);
362 if (impl->position_info.no_bg)
363 gdk_window_tmp_reset_bg (window);
365 impl->position_info = new_info;
367 tmp_list = obj->children;
370 gdk_window_postmove (tmp_list->data, &parent_pos);
371 tmp_list = tmp_list->next;
377 * @window: a #GdkWindow
378 * @dx: Amount to scroll in the X direction
379 * @dy: Amount to scroll in the Y direction
381 * Scroll the contents of @window, both pixels and children, by the given
382 * amount. @window itself does not move. Portions of the window that the scroll
383 * operation brings in from offscreen areas are invalidated. The invalidated
384 * region may be bigger than what would strictly be necessary. (For X11, a
385 * minimum area will be invalidated if the window has no subwindows, or if the
386 * edges of the window's parent do not extend beyond the edges of the window. In
387 * other cases, a multi-step process is used to scroll the window which may
388 * produce temporary visual artifacts and unnecessary invalidations.)
391 gdk_window_scroll (GdkWindow *window,
395 gboolean can_guffaw_scroll = FALSE;
396 GdkRegion *invalidate_region;
397 GdkWindowImplX11 *impl;
398 GdkWindowObject *obj;
399 GdkRectangle src_rect, dest_rect;
401 g_return_if_fail (GDK_IS_WINDOW (window));
403 if (GDK_WINDOW_DESTROYED (window))
406 obj = GDK_WINDOW_OBJECT (window);
407 impl = GDK_WINDOW_IMPL_X11 (obj->impl);
409 if (dx == 0 && dy == 0)
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_window_move_resize_child (GdkWindow *window,
470 GdkWindowImplX11 *impl;
471 GdkWindowObject *obj;
472 GdkXPositionInfo new_info;
473 GdkWindowParentPos parent_pos;
476 gint d_xoffset, d_yoffset;
481 g_return_if_fail (window != NULL);
482 g_return_if_fail (GDK_IS_WINDOW (window));
484 impl = GDK_WINDOW_IMPL_X11 (GDK_WINDOW_OBJECT (window)->impl);
485 obj = GDK_WINDOW_OBJECT (window);
490 is_move = dx != 0 || dy != 0;
491 is_resize = impl->width != width || impl->height != height;
493 if (!is_move && !is_resize)
499 impl->height = height;
501 gdk_window_compute_parent_pos (impl, &parent_pos);
502 gdk_window_compute_position (impl, &parent_pos, &new_info);
504 gdk_window_clip_changed (window, &impl->position_info.clip_rect, &new_info.clip_rect);
506 parent_pos.x += obj->x;
507 parent_pos.y += obj->y;
508 parent_pos.x11_x += new_info.x;
509 parent_pos.x11_y += new_info.y;
510 parent_pos.clip_rect = new_info.clip_rect;
512 d_xoffset = new_info.x_offset - impl->position_info.x_offset;
513 d_yoffset = new_info.y_offset - impl->position_info.y_offset;
515 if (d_xoffset != 0 || d_yoffset != 0)
517 GdkRectangle new_position;
519 gdk_window_set_static_gravities (window, TRUE);
521 if (d_xoffset < 0 || d_yoffset < 0)
522 gdk_window_queue_translation (window, MIN (d_xoffset, 0), MIN (d_yoffset, 0));
524 compute_intermediate_position (&impl->position_info, &new_info, d_xoffset, d_yoffset,
527 XMoveResizeWindow (GDK_WINDOW_XDISPLAY (window),
528 GDK_WINDOW_XID (window),
529 new_position.x, new_position.y, new_position.width, new_position.height);
531 tmp_list = obj->children;
534 gdk_window_premove (tmp_list->data, &parent_pos);
535 tmp_list = tmp_list->next;
538 XMoveWindow (GDK_WINDOW_XDISPLAY (window),
539 GDK_WINDOW_XID (window),
540 new_position.x + dx, new_position.y + dy);
542 if (d_xoffset > 0 || d_yoffset > 0)
543 gdk_window_queue_translation (window, MAX (d_xoffset, 0), MAX (d_yoffset, 0));
545 XMoveResizeWindow (GDK_WINDOW_XDISPLAY (window),
546 GDK_WINDOW_XID (window),
547 new_info.x, new_info.y, new_info.width, new_info.height);
549 if (impl->position_info.no_bg)
550 gdk_window_tmp_reset_bg (window);
552 if (!impl->position_info.mapped && new_info.mapped && GDK_WINDOW_IS_MAPPED (obj))
553 XMapWindow (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window));
555 impl->position_info = new_info;
557 tmp_list = obj->children;
560 gdk_window_postmove (tmp_list->data, &parent_pos);
561 tmp_list = tmp_list->next;
566 if (is_move && is_resize)
567 gdk_window_set_static_gravities (window, FALSE);
569 if (impl->position_info.mapped && !new_info.mapped)
570 XUnmapWindow (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window));
572 tmp_list = obj->children;
575 gdk_window_premove (tmp_list->data, &parent_pos);
576 tmp_list = tmp_list->next;
580 XMoveResizeWindow (GDK_WINDOW_XDISPLAY (window),
581 GDK_WINDOW_XID (window),
582 new_info.x, new_info.y, new_info.width, new_info.height);
584 XMoveWindow (GDK_WINDOW_XDISPLAY (window),
585 GDK_WINDOW_XID (window),
586 new_info.x, new_info.y);
588 tmp_list = obj->children;
591 gdk_window_postmove (tmp_list->data, &parent_pos);
592 tmp_list = tmp_list->next;
595 if (impl->position_info.no_bg)
596 gdk_window_tmp_reset_bg (window);
598 if (!impl->position_info.mapped && new_info.mapped && GDK_WINDOW_IS_MAPPED (obj))
599 XMapWindow (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window));
601 impl->position_info = new_info;
606 gdk_window_compute_position (GdkWindowImplX11 *window,
607 GdkWindowParentPos *parent_pos,
608 GdkXPositionInfo *info)
610 GdkWindowObject *wrapper;
614 g_return_if_fail (GDK_IS_WINDOW_IMPL_X11 (window));
616 wrapper = GDK_WINDOW_OBJECT (GDK_DRAWABLE_IMPL_X11 (window)->wrapper);
620 if (window->width <= 32767)
622 info->width = window->width;
623 info->x = parent_pos->x + wrapper->x - parent_pos->x11_x;
629 if (parent_pos->x + wrapper->x < -16384)
631 if (parent_pos->x + wrapper->x + window->width < 16384)
632 info->x = parent_pos->x + wrapper->x + window->width - info->width - parent_pos->x11_x;
634 info->x = -16384 - parent_pos->x11_x;
637 info->x = parent_pos->x + wrapper->x - parent_pos->x11_x;
640 if (window->height <= 32767)
642 info->height = window->height;
643 info->y = parent_pos->y + wrapper->y - parent_pos->x11_y;
648 info->height = 32767;
649 if (parent_pos->y + wrapper->y < -16384)
651 if (parent_pos->y + wrapper->y + window->height < 16384)
652 info->y = parent_pos->y + wrapper->y + window->height - info->height - parent_pos->x11_y;
654 info->y = -16384 - parent_pos->x11_y;
657 info->y = parent_pos->y + wrapper->y - parent_pos->x11_y;
660 parent_x_offset = parent_pos->x11_x - parent_pos->x;
661 parent_y_offset = parent_pos->x11_y - parent_pos->y;
663 info->x_offset = parent_x_offset + info->x - wrapper->x;
664 info->y_offset = parent_y_offset + info->y - wrapper->y;
666 /* We don't considering the clipping of toplevel windows and their immediate children
667 * by their parents, and simply always map those windows.
669 if (parent_pos->clip_rect.width == G_MAXINT)
671 /* Check if the window would wrap around into the visible space in either direction */
672 else if (info->x + parent_x_offset < parent_pos->clip_rect.x + parent_pos->clip_rect.width - 65536 ||
673 info->x + info->width + parent_x_offset > parent_pos->clip_rect.x + 65536 ||
674 info->y + parent_y_offset < parent_pos->clip_rect.y + parent_pos->clip_rect.height - 65536 ||
675 info->y + info->height + parent_y_offset > parent_pos->clip_rect.y + 65536)
676 info->mapped = FALSE;
682 if (GDK_WINDOW_TYPE (wrapper) == GDK_WINDOW_CHILD)
684 info->clip_rect.x = wrapper->x;
685 info->clip_rect.y = wrapper->y;
686 info->clip_rect.width = window->width;
687 info->clip_rect.height = window->height;
689 gdk_rectangle_intersect (&info->clip_rect, &parent_pos->clip_rect, &info->clip_rect);
691 info->clip_rect.x -= wrapper->x;
692 info->clip_rect.y -= wrapper->y;
696 info->clip_rect.x = 0;
697 info->clip_rect.y = 0;
698 info->clip_rect.width = G_MAXINT;
699 info->clip_rect.height = G_MAXINT;
704 gdk_window_compute_parent_pos (GdkWindowImplX11 *window,
705 GdkWindowParentPos *parent_pos)
707 GdkWindowObject *wrapper;
708 GdkWindowObject *parent;
709 GdkRectangle tmp_clip;
711 int clip_xoffset = 0;
712 int clip_yoffset = 0;
714 g_return_if_fail (GDK_IS_WINDOW_IMPL_X11 (window));
717 GDK_WINDOW_OBJECT (GDK_DRAWABLE_IMPL_X11 (window)->wrapper);
721 parent_pos->x11_x = 0;
722 parent_pos->x11_y = 0;
724 /* We take a simple approach here and simply consider toplevel
725 * windows not to clip their children on the right/bottom, since the
726 * size of toplevel windows is not directly under our
727 * control. Clipping only really matters when scrolling and
728 * generally we aren't going to be moving the immediate child of a
729 * toplevel beyond the bounds of that toplevel.
731 * We could go ahead and recompute the clips of toplevel windows and
732 * their descendents when we receive size notification, but it would
733 * probably not be an improvement in most cases.
735 parent_pos->clip_rect.x = 0;
736 parent_pos->clip_rect.y = 0;
737 parent_pos->clip_rect.width = G_MAXINT;
738 parent_pos->clip_rect.height = G_MAXINT;
740 parent = (GdkWindowObject *)wrapper->parent;
741 while (parent && parent->window_type == GDK_WINDOW_CHILD)
743 GdkWindowImplX11 *impl = GDK_WINDOW_IMPL_X11 (parent->impl);
745 tmp_clip.x = - clip_xoffset;
746 tmp_clip.y = - clip_yoffset;
747 tmp_clip.width = impl->width;
748 tmp_clip.height = impl->height;
750 gdk_rectangle_intersect (&parent_pos->clip_rect, &tmp_clip, &parent_pos->clip_rect);
752 parent_pos->x += parent->x;
753 parent_pos->y += parent->y;
754 parent_pos->x11_x += impl->position_info.x;
755 parent_pos->x11_y += impl->position_info.y;
757 clip_xoffset += parent->x;
758 clip_yoffset += parent->y;
760 parent = (GdkWindowObject *)parent->parent;
765 gdk_window_premove (GdkWindow *window,
766 GdkWindowParentPos *parent_pos)
768 GdkWindowImplX11 *impl;
769 GdkWindowObject *obj;
770 GdkXPositionInfo new_info;
772 gint d_xoffset, d_yoffset;
773 GdkWindowParentPos this_pos;
775 obj = (GdkWindowObject *) window;
776 impl = GDK_WINDOW_IMPL_X11 (obj->impl);
778 gdk_window_compute_position (impl, parent_pos, &new_info);
780 gdk_window_clip_changed (window, &impl->position_info.clip_rect, &new_info.clip_rect);
782 this_pos.x = parent_pos->x + obj->x;
783 this_pos.y = parent_pos->y + obj->y;
784 this_pos.x11_x = parent_pos->x11_x + new_info.x;
785 this_pos.x11_y = parent_pos->x11_y + new_info.y;
786 this_pos.clip_rect = new_info.clip_rect;
788 if (impl->position_info.mapped && !new_info.mapped)
789 XUnmapWindow (GDK_DRAWABLE_XDISPLAY (window), GDK_DRAWABLE_XID (window));
791 d_xoffset = new_info.x_offset - impl->position_info.x_offset;
792 d_yoffset = new_info.y_offset - impl->position_info.y_offset;
794 if (d_xoffset != 0 || d_yoffset != 0)
796 GdkRectangle new_position;
798 if (d_xoffset < 0 || d_yoffset < 0)
799 gdk_window_queue_translation (window, MIN (d_xoffset, 0), MIN (d_yoffset, 0));
801 compute_intermediate_position (&impl->position_info, &new_info, d_xoffset, d_yoffset,
804 XMoveResizeWindow (GDK_DRAWABLE_XDISPLAY (window),
805 GDK_DRAWABLE_XID (window),
806 new_position.x, new_position.y, new_position.width, new_position.height);
809 tmp_list = obj->children;
812 gdk_window_premove (tmp_list->data, &this_pos);
813 tmp_list = tmp_list->next;
818 gdk_window_postmove (GdkWindow *window,
819 GdkWindowParentPos *parent_pos)
821 GdkWindowImplX11 *impl;
822 GdkWindowObject *obj;
823 GdkXPositionInfo new_info;
825 gint d_xoffset, d_yoffset;
826 GdkWindowParentPos this_pos;
828 obj = (GdkWindowObject *) window;
829 impl = GDK_WINDOW_IMPL_X11 (obj->impl);
831 gdk_window_compute_position (impl, parent_pos, &new_info);
833 this_pos.x = parent_pos->x + obj->x;
834 this_pos.y = parent_pos->y + obj->y;
835 this_pos.x11_x = parent_pos->x11_x + new_info.x;
836 this_pos.x11_y = parent_pos->x11_y + new_info.y;
837 this_pos.clip_rect = new_info.clip_rect;
839 d_xoffset = new_info.x_offset - impl->position_info.x_offset;
840 d_yoffset = new_info.y_offset - impl->position_info.y_offset;
842 if (d_xoffset != 0 || d_yoffset != 0)
844 if (d_xoffset > 0 || d_yoffset > 0)
845 gdk_window_queue_translation (window, MAX (d_xoffset, 0), MAX (d_yoffset, 0));
847 XMoveResizeWindow (GDK_DRAWABLE_XDISPLAY (window),
848 GDK_DRAWABLE_XID (window),
849 new_info.x, new_info.y, new_info.width, new_info.height);
852 if (!impl->position_info.mapped && new_info.mapped && GDK_WINDOW_IS_MAPPED (obj))
853 XMapWindow (GDK_DRAWABLE_XDISPLAY (window), GDK_DRAWABLE_XID (window));
855 if (impl->position_info.no_bg)
856 gdk_window_tmp_reset_bg (window);
858 impl->position_info = new_info;
860 tmp_list = obj->children;
863 gdk_window_postmove (tmp_list->data, &this_pos);
864 tmp_list = tmp_list->next;
869 expose_serial_predicate (Display *xdisplay,
873 gulong *serial = (gulong *)arg;
875 if (xev->xany.type == Expose)
876 *serial = MIN (*serial, xev->xany.serial);
881 /* Find oldest possible serial for an outstanding expose event
884 find_current_serial (Display *xdisplay)
887 gulong serial = NextRequest (xdisplay);
889 XSync (xdisplay, False);
891 XCheckIfEvent (xdisplay, &xev, expose_serial_predicate, (XPointer)&serial);
897 queue_delete_link (GQueue *queue,
900 if (queue->tail == link)
901 queue->tail = link->prev;
903 queue->head = g_list_remove_link (queue->head, link);
904 g_list_free_1 (link);
909 queue_item_free (GdkWindowQueueItem *item)
913 g_object_remove_weak_pointer (G_OBJECT (item->window),
914 (gpointer *)&(item->window));
917 if (item->type == GDK_WINDOW_QUEUE_ANTIEXPOSE)
918 gdk_region_destroy (item->u.antiexpose.area);
924 gdk_window_queue (GdkWindow *window,
925 GdkWindowQueueItem *item)
927 GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (GDK_WINDOW_DISPLAY (window));
929 if (!display_x11->translate_queue)
930 display_x11->translate_queue = g_queue_new ();
932 /* Keep length of queue finite by, if it grows too long,
933 * figuring out the latest relevant serial and discarding
934 * irrelevant queue items.
936 if (display_x11->translate_queue->length >= 64)
938 gulong serial = find_current_serial (GDK_WINDOW_XDISPLAY (window));
939 GList *tmp_list = display_x11->translate_queue->head;
943 GdkWindowQueueItem *item = tmp_list->data;
944 GList *next = tmp_list->next;
946 if (serial > item->serial)
948 queue_delete_link (display_x11->translate_queue, tmp_list);
949 queue_item_free (item);
956 /* Catch the case where someone isn't processing events and there
957 * is an event stuck in the event queue with an old serial:
958 * If we can't reduce the queue length by the above method,
959 * discard anti-expose items. (We can't discard translate
962 if (display_x11->translate_queue->length >= 64)
964 GList *tmp_list = display_x11->translate_queue->head;
968 GdkWindowQueueItem *item = tmp_list->data;
969 GList *next = tmp_list->next;
971 if (item->type == GDK_WINDOW_QUEUE_ANTIEXPOSE)
973 queue_delete_link (display_x11->translate_queue, tmp_list);
974 queue_item_free (item);
981 item->window = window;
982 item->serial = NextRequest (GDK_WINDOW_XDISPLAY (window));
984 g_object_add_weak_pointer (G_OBJECT (window),
985 (gpointer *)&(item->window));
987 g_queue_push_tail (display_x11->translate_queue, item);
991 gdk_window_queue_translation (GdkWindow *window,
995 GdkWindowQueueItem *item = g_new (GdkWindowQueueItem, 1);
996 item->type = GDK_WINDOW_QUEUE_TRANSLATE;
997 item->u.translate.dx = dx;
998 item->u.translate.dy = dy;
1000 gdk_window_queue (window, item);
1004 _gdk_windowing_window_queue_antiexpose (GdkWindow *window,
1007 GdkWindowQueueItem *item = g_new (GdkWindowQueueItem, 1);
1008 item->type = GDK_WINDOW_QUEUE_ANTIEXPOSE;
1009 item->u.antiexpose.area = area;
1011 gdk_window_queue (window, item);
1017 _gdk_window_process_expose (GdkWindow *window,
1021 GdkWindowImplX11 *impl;
1022 GdkRegion *invalidate_region = gdk_region_rectangle (area);
1023 GdkRegion *clip_region;
1024 GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (GDK_WINDOW_DISPLAY (window));
1025 impl = GDK_WINDOW_IMPL_X11 (GDK_WINDOW_OBJECT (window)->impl);
1027 if (display_x11->translate_queue)
1029 GList *tmp_list = display_x11->translate_queue->head;
1033 GdkWindowQueueItem *item = tmp_list->data;
1034 tmp_list = tmp_list->next;
1036 if (serial < item->serial)
1038 if (item->window == window)
1040 if (item->type == GDK_WINDOW_QUEUE_TRANSLATE)
1041 gdk_region_offset (invalidate_region, item->u.translate.dx, item->u.translate.dy);
1042 else /* anti-expose */
1043 gdk_region_subtract (invalidate_region, item->u.antiexpose.area);
1048 queue_delete_link (display_x11->translate_queue,
1049 display_x11->translate_queue->head);
1050 queue_item_free (item);
1055 clip_region = gdk_region_rectangle (&impl->position_info.clip_rect);
1056 gdk_region_intersect (invalidate_region, clip_region);
1058 if (!gdk_region_empty (invalidate_region))
1059 gdk_window_invalidate_region (window, invalidate_region, FALSE);
1061 gdk_region_destroy (invalidate_region);
1062 gdk_region_destroy (clip_region);
1066 gdk_window_tmp_unset_bg (GdkWindow *window)
1068 GdkWindowImplX11 *impl;
1069 GdkWindowObject *obj;
1071 obj = (GdkWindowObject *) window;
1072 impl = GDK_WINDOW_IMPL_X11 (obj->impl);
1074 impl->position_info.no_bg = TRUE;
1076 if (obj->bg_pixmap != GDK_NO_BG)
1077 XSetWindowBackgroundPixmap (GDK_DRAWABLE_XDISPLAY (window),
1078 GDK_DRAWABLE_XID (window), None);
1082 gdk_window_tmp_reset_bg (GdkWindow *window)
1084 GdkWindowImplX11 *impl;
1085 GdkWindowObject *obj;
1087 obj = (GdkWindowObject *) window;
1088 impl = GDK_WINDOW_IMPL_X11 (obj->impl);
1090 impl->position_info.no_bg = FALSE;
1092 if (obj->bg_pixmap == GDK_NO_BG)
1099 if (obj->bg_pixmap == GDK_PARENT_RELATIVE_BG)
1100 xpixmap = ParentRelative;
1102 xpixmap = GDK_DRAWABLE_XID (obj->bg_pixmap);
1104 XSetWindowBackgroundPixmap (GDK_DRAWABLE_XDISPLAY (window),
1105 GDK_DRAWABLE_XID (window), xpixmap);
1109 XSetWindowBackground (GDK_DRAWABLE_XDISPLAY (window),
1110 GDK_DRAWABLE_XID (window),
1111 obj->bg_color.pixel);
1116 gdk_window_clip_changed (GdkWindow *window, GdkRectangle *old_clip, GdkRectangle *new_clip)
1118 GdkWindowImplX11 *impl;
1119 GdkWindowObject *obj;
1120 GdkRegion *old_clip_region;
1121 GdkRegion *new_clip_region;
1123 if (((GdkWindowObject *)window)->input_only)
1126 obj = (GdkWindowObject *) window;
1127 impl = GDK_WINDOW_IMPL_X11 (obj->impl);
1129 old_clip_region = gdk_region_rectangle (old_clip);
1130 new_clip_region = gdk_region_rectangle (new_clip);
1132 /* We need to update this here because gdk_window_invalidate_region makes
1133 * use if it (through gdk_drawable_get_visible_region
1135 impl->position_info.clip_rect = *new_clip;
1137 /* Trim invalid region of window to new clip rectangle
1139 if (obj->update_area)
1140 gdk_region_intersect (obj->update_area, new_clip_region);
1142 /* Invalidate newly exposed portion of window
1144 gdk_region_subtract (new_clip_region, old_clip_region);
1145 if (!gdk_region_empty (new_clip_region))
1147 gdk_window_tmp_unset_bg (window);
1148 gdk_window_invalidate_region (window, new_clip_region, FALSE);
1151 gdk_region_destroy (new_clip_region);
1152 gdk_region_destroy (old_clip_region);