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)
232 values.graphics_exposures = True;
233 gc = XCreateGC (GDK_WINDOW_XDISPLAY (window),
234 GDK_WINDOW_XID (window),
235 GCGraphicsExposures, &values);
237 gdk_window_queue_translation (window, dx, dy);
239 XCopyArea (GDK_WINDOW_XDISPLAY (window),
240 GDK_WINDOW_XID (window),
241 GDK_WINDOW_XID (window),
243 dest_rect->x - dx, dest_rect->y - dy,
244 dest_rect->width, dest_rect->height,
245 dest_rect->x, dest_rect->y);
247 XFreeGC (GDK_WINDOW_XDISPLAY (window), gc);
250 tmp_list = obj->children;
253 GdkWindow *child = GDK_WINDOW (tmp_list->data);
254 GdkWindowObject *child_obj = GDK_WINDOW_OBJECT (child);
256 gdk_window_move (child, child_obj->x + dx, child_obj->y + dy);
258 tmp_list = tmp_list->next;
263 compute_intermediate_position (GdkXPositionInfo *position_info,
264 GdkXPositionInfo *new_info,
267 GdkRectangle *new_position)
269 gint new_x0, new_x1, new_y0, new_y1;
271 /* Wrap d_xoffset, d_yoffset into [-32768,32767] range. For the
272 * purposes of subwindow movement, it doesn't matter if we are
273 * off by a factor of 65536, and if we don't do this range
274 * reduction, we'll end up with invalid widths.
276 d_xoffset = (gint16)d_xoffset;
277 d_yoffset = (gint16)d_yoffset;
281 new_x0 = position_info->x + d_xoffset;
282 new_x1 = position_info->x + position_info->width;
286 new_x0 = position_info->x;
287 new_x1 = position_info->x + new_info->width + d_xoffset;
290 new_position->x = new_x0;
291 new_position->width = new_x1 - new_x0;
295 new_y0 = position_info->y + d_yoffset;
296 new_y1 = position_info->y + position_info->height;
300 new_y0 = position_info->y;
301 new_y1 = position_info->y + new_info->height + d_yoffset;
304 new_position->y = new_y0;
305 new_position->height = new_y1 - new_y0;
309 gdk_window_guffaw_scroll (GdkWindow *window,
313 GdkWindowObject *obj = GDK_WINDOW_OBJECT (window);
314 GdkWindowImplX11 *impl = GDK_WINDOW_IMPL_X11 (obj->impl);
316 gint d_xoffset = -dx;
317 gint d_yoffset = -dy;
318 GdkRectangle new_position;
319 GdkXPositionInfo new_info;
320 GdkWindowParentPos parent_pos;
323 gdk_window_compute_parent_pos (impl, &parent_pos);
324 gdk_window_compute_position (impl, &parent_pos, &new_info);
326 parent_pos.x += obj->x;
327 parent_pos.y += obj->y;
328 parent_pos.x11_x += new_info.x;
329 parent_pos.x11_y += new_info.y;
330 parent_pos.clip_rect = new_info.clip_rect;
332 gdk_window_tmp_unset_bg (window);
334 if (dx > 0 || dy > 0)
335 gdk_window_queue_translation (window, MAX (dx, 0), MAX (dy, 0));
337 gdk_window_set_static_gravities (window, TRUE);
339 compute_intermediate_position (&impl->position_info, &new_info, d_xoffset, d_yoffset,
342 XMoveResizeWindow (GDK_WINDOW_XDISPLAY (window),
343 GDK_WINDOW_XID (window),
344 new_position.x, new_position.y, new_position.width, new_position.height);
346 tmp_list = obj->children;
349 GDK_WINDOW_OBJECT(tmp_list->data)->x -= d_xoffset;
350 GDK_WINDOW_OBJECT(tmp_list->data)->y -= d_yoffset;
352 gdk_window_premove (tmp_list->data, &parent_pos);
353 tmp_list = tmp_list->next;
356 XMoveWindow (GDK_WINDOW_XDISPLAY (window),
357 GDK_WINDOW_XID (window),
358 new_position.x - d_xoffset, new_position.y - d_yoffset);
360 if (dx < 0 || dy < 0)
361 gdk_window_queue_translation (window, MIN (dx, 0), MIN (dy, 0));
363 XMoveResizeWindow (GDK_WINDOW_XDISPLAY (window),
364 GDK_WINDOW_XID (window),
365 impl->position_info.x, impl->position_info.y,
366 impl->position_info.width, impl->position_info.height);
368 if (impl->position_info.no_bg)
369 gdk_window_tmp_reset_bg (window);
371 impl->position_info = new_info;
373 tmp_list = obj->children;
376 gdk_window_postmove (tmp_list->data, &parent_pos);
377 tmp_list = tmp_list->next;
383 * @window: a #GdkWindow
384 * @dx: Amount to scroll in the X direction
385 * @dy: Amount to scroll in the Y direction
387 * Scroll the contents of @window, both pixels and children, by the given
388 * amount. @window itself does not move. Portions of the window that the scroll
389 * operation brings in from offscreen areas are invalidated. The invalidated
390 * region may be bigger than what would strictly be necessary. (For X11, a
391 * minimum area will be invalidated if the window has no subwindows, or if the
392 * edges of the window's parent do not extend beyond the edges of the window. In
393 * other cases, a multi-step process is used to scroll the window which may
394 * produce temporary visual artifacts and unnecessary invalidations.)
397 gdk_window_scroll (GdkWindow *window,
401 gboolean can_guffaw_scroll = FALSE;
402 GdkRegion *invalidate_region;
403 GdkWindowImplX11 *impl;
404 GdkWindowObject *obj;
405 GdkRectangle dest_rect;
407 g_return_if_fail (GDK_IS_WINDOW (window));
409 if (GDK_WINDOW_DESTROYED (window))
412 obj = GDK_WINDOW_OBJECT (window);
413 impl = GDK_WINDOW_IMPL_X11 (obj->impl);
415 if (dx == 0 && dy == 0)
418 /* Move the current invalid region */
419 if (obj->update_area)
420 gdk_region_offset (obj->update_area, dx, dy);
422 invalidate_region = gdk_region_rectangle (&impl->position_info.clip_rect);
424 dest_rect = impl->position_info.clip_rect;
427 gdk_rectangle_intersect (&dest_rect, &impl->position_info.clip_rect, &dest_rect);
429 if (dest_rect.width > 0 && dest_rect.height > 0)
431 GdkRegion *tmp_region;
433 tmp_region = gdk_region_rectangle (&dest_rect);
434 gdk_region_subtract (invalidate_region, tmp_region);
435 gdk_region_destroy (tmp_region);
438 gdk_window_invalidate_region (window, invalidate_region, TRUE);
439 gdk_region_destroy (invalidate_region);
441 /* We can guffaw scroll if we are a child window, and the parent
442 * does not extend beyond our edges. Otherwise, we use XCopyArea, then
443 * move any children later
445 if (GDK_WINDOW_TYPE (window) == GDK_WINDOW_CHILD)
447 GdkWindowImplX11 *parent_impl = GDK_WINDOW_IMPL_X11 (obj->parent->impl);
448 can_guffaw_scroll = ((dx == 0 || (obj->x <= 0 && obj->x + impl->width >= parent_impl->width)) &&
449 (dy == 0 || (obj->y <= 0 && obj->y + impl->height >= parent_impl->height)));
452 if (!obj->children || !can_guffaw_scroll)
453 gdk_window_copy_area_scroll (window, &dest_rect, dx, dy);
455 gdk_window_guffaw_scroll (window, dx, dy);
459 _gdk_window_move_resize_child (GdkWindow *window,
465 GdkWindowImplX11 *impl;
466 GdkWindowObject *obj;
467 GdkXPositionInfo new_info;
468 GdkWindowParentPos parent_pos;
471 gint d_xoffset, d_yoffset;
476 g_return_if_fail (window != NULL);
477 g_return_if_fail (GDK_IS_WINDOW (window));
479 impl = GDK_WINDOW_IMPL_X11 (GDK_WINDOW_OBJECT (window)->impl);
480 obj = GDK_WINDOW_OBJECT (window);
485 is_move = dx != 0 || dy != 0;
486 is_resize = impl->width != width || impl->height != height;
488 if (!is_move && !is_resize)
494 impl->height = height;
496 gdk_window_compute_parent_pos (impl, &parent_pos);
497 gdk_window_compute_position (impl, &parent_pos, &new_info);
499 gdk_window_clip_changed (window, &impl->position_info.clip_rect, &new_info.clip_rect);
501 parent_pos.x += obj->x;
502 parent_pos.y += obj->y;
503 parent_pos.x11_x += new_info.x;
504 parent_pos.x11_y += new_info.y;
505 parent_pos.clip_rect = new_info.clip_rect;
507 d_xoffset = new_info.x_offset - impl->position_info.x_offset;
508 d_yoffset = new_info.y_offset - impl->position_info.y_offset;
510 if (d_xoffset != 0 || d_yoffset != 0)
512 GdkRectangle new_position;
514 gdk_window_set_static_gravities (window, TRUE);
516 if (d_xoffset < 0 || d_yoffset < 0)
517 gdk_window_queue_translation (window, MIN (d_xoffset, 0), MIN (d_yoffset, 0));
519 compute_intermediate_position (&impl->position_info, &new_info, d_xoffset, d_yoffset,
522 XMoveResizeWindow (GDK_WINDOW_XDISPLAY (window),
523 GDK_WINDOW_XID (window),
524 new_position.x, new_position.y, new_position.width, new_position.height);
526 tmp_list = obj->children;
529 gdk_window_premove (tmp_list->data, &parent_pos);
530 tmp_list = tmp_list->next;
533 XMoveWindow (GDK_WINDOW_XDISPLAY (window),
534 GDK_WINDOW_XID (window),
535 new_position.x + dx, new_position.y + dy);
537 if (d_xoffset > 0 || d_yoffset > 0)
538 gdk_window_queue_translation (window, MAX (d_xoffset, 0), MAX (d_yoffset, 0));
540 XMoveResizeWindow (GDK_WINDOW_XDISPLAY (window),
541 GDK_WINDOW_XID (window),
542 new_info.x, new_info.y, new_info.width, new_info.height);
544 if (impl->position_info.no_bg)
545 gdk_window_tmp_reset_bg (window);
547 if (!impl->position_info.mapped && new_info.mapped && GDK_WINDOW_IS_MAPPED (obj))
548 XMapWindow (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window));
550 impl->position_info = new_info;
552 tmp_list = obj->children;
555 gdk_window_postmove (tmp_list->data, &parent_pos);
556 tmp_list = tmp_list->next;
561 if (is_move && is_resize)
562 gdk_window_set_static_gravities (window, FALSE);
564 if (impl->position_info.mapped && !new_info.mapped)
565 XUnmapWindow (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window));
567 tmp_list = obj->children;
570 gdk_window_premove (tmp_list->data, &parent_pos);
571 tmp_list = tmp_list->next;
575 XMoveResizeWindow (GDK_WINDOW_XDISPLAY (window),
576 GDK_WINDOW_XID (window),
577 new_info.x, new_info.y, new_info.width, new_info.height);
579 XMoveWindow (GDK_WINDOW_XDISPLAY (window),
580 GDK_WINDOW_XID (window),
581 new_info.x, new_info.y);
583 tmp_list = obj->children;
586 gdk_window_postmove (tmp_list->data, &parent_pos);
587 tmp_list = tmp_list->next;
590 if (impl->position_info.no_bg)
591 gdk_window_tmp_reset_bg (window);
593 if (!impl->position_info.mapped && new_info.mapped && GDK_WINDOW_IS_MAPPED (obj))
594 XMapWindow (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window));
596 impl->position_info = new_info;
601 gdk_window_compute_position (GdkWindowImplX11 *window,
602 GdkWindowParentPos *parent_pos,
603 GdkXPositionInfo *info)
605 GdkWindowObject *wrapper;
609 g_return_if_fail (GDK_IS_WINDOW_IMPL_X11 (window));
611 wrapper = GDK_WINDOW_OBJECT (GDK_DRAWABLE_IMPL_X11 (window)->wrapper);
615 if (window->width <= 32767)
617 info->width = window->width;
618 info->x = parent_pos->x + wrapper->x - parent_pos->x11_x;
624 if (parent_pos->x + wrapper->x < -16384)
626 if (parent_pos->x + wrapper->x + window->width < 16384)
627 info->x = parent_pos->x + wrapper->x + window->width - info->width - parent_pos->x11_x;
629 info->x = -16384 - parent_pos->x11_x;
632 info->x = parent_pos->x + wrapper->x - parent_pos->x11_x;
635 if (window->height <= 32767)
637 info->height = window->height;
638 info->y = parent_pos->y + wrapper->y - parent_pos->x11_y;
643 info->height = 32767;
644 if (parent_pos->y + wrapper->y < -16384)
646 if (parent_pos->y + wrapper->y + window->height < 16384)
647 info->y = parent_pos->y + wrapper->y + window->height - info->height - parent_pos->x11_y;
649 info->y = -16384 - parent_pos->x11_y;
652 info->y = parent_pos->y + wrapper->y - parent_pos->x11_y;
655 parent_x_offset = parent_pos->x11_x - parent_pos->x;
656 parent_y_offset = parent_pos->x11_y - parent_pos->y;
658 info->x_offset = parent_x_offset + info->x - wrapper->x;
659 info->y_offset = parent_y_offset + info->y - wrapper->y;
661 /* We don't considering the clipping of toplevel windows and their immediate children
662 * by their parents, and simply always map those windows.
664 if (parent_pos->clip_rect.width == G_MAXINT)
666 /* Check if the window would wrap around into the visible space in either direction */
667 else if (info->x + parent_x_offset < parent_pos->clip_rect.x + parent_pos->clip_rect.width - 65536 ||
668 info->x + info->width + parent_x_offset > parent_pos->clip_rect.x + 65536 ||
669 info->y + parent_y_offset < parent_pos->clip_rect.y + parent_pos->clip_rect.height - 65536 ||
670 info->y + info->height + parent_y_offset > parent_pos->clip_rect.y + 65536)
671 info->mapped = FALSE;
677 if (GDK_WINDOW_TYPE (wrapper) == GDK_WINDOW_CHILD)
679 info->clip_rect.x = wrapper->x;
680 info->clip_rect.y = wrapper->y;
681 info->clip_rect.width = window->width;
682 info->clip_rect.height = window->height;
684 gdk_rectangle_intersect (&info->clip_rect, &parent_pos->clip_rect, &info->clip_rect);
686 info->clip_rect.x -= wrapper->x;
687 info->clip_rect.y -= wrapper->y;
691 info->clip_rect.x = 0;
692 info->clip_rect.y = 0;
693 info->clip_rect.width = G_MAXINT;
694 info->clip_rect.height = G_MAXINT;
699 gdk_window_compute_parent_pos (GdkWindowImplX11 *window,
700 GdkWindowParentPos *parent_pos)
702 GdkWindowObject *wrapper;
703 GdkWindowObject *parent;
704 GdkRectangle tmp_clip;
706 int clip_xoffset = 0;
707 int clip_yoffset = 0;
709 g_return_if_fail (GDK_IS_WINDOW_IMPL_X11 (window));
712 GDK_WINDOW_OBJECT (GDK_DRAWABLE_IMPL_X11 (window)->wrapper);
716 parent_pos->x11_x = 0;
717 parent_pos->x11_y = 0;
719 /* We take a simple approach here and simply consider toplevel
720 * windows not to clip their children on the right/bottom, since the
721 * size of toplevel windows is not directly under our
722 * control. Clipping only really matters when scrolling and
723 * generally we aren't going to be moving the immediate child of a
724 * toplevel beyond the bounds of that toplevel.
726 * We could go ahead and recompute the clips of toplevel windows and
727 * their descendents when we receive size notification, but it would
728 * probably not be an improvement in most cases.
730 parent_pos->clip_rect.x = 0;
731 parent_pos->clip_rect.y = 0;
732 parent_pos->clip_rect.width = G_MAXINT;
733 parent_pos->clip_rect.height = G_MAXINT;
735 parent = (GdkWindowObject *)wrapper->parent;
736 while (parent && parent->window_type == GDK_WINDOW_CHILD)
738 GdkWindowImplX11 *impl = GDK_WINDOW_IMPL_X11 (parent->impl);
740 tmp_clip.x = - clip_xoffset;
741 tmp_clip.y = - clip_yoffset;
742 tmp_clip.width = impl->width;
743 tmp_clip.height = impl->height;
745 gdk_rectangle_intersect (&parent_pos->clip_rect, &tmp_clip, &parent_pos->clip_rect);
747 parent_pos->x += parent->x;
748 parent_pos->y += parent->y;
749 parent_pos->x11_x += impl->position_info.x;
750 parent_pos->x11_y += impl->position_info.y;
752 clip_xoffset += parent->x;
753 clip_yoffset += parent->y;
755 parent = (GdkWindowObject *)parent->parent;
760 gdk_window_premove (GdkWindow *window,
761 GdkWindowParentPos *parent_pos)
763 GdkWindowImplX11 *impl;
764 GdkWindowObject *obj;
765 GdkXPositionInfo new_info;
767 gint d_xoffset, d_yoffset;
768 GdkWindowParentPos this_pos;
770 obj = (GdkWindowObject *) window;
771 impl = GDK_WINDOW_IMPL_X11 (obj->impl);
773 gdk_window_compute_position (impl, parent_pos, &new_info);
775 gdk_window_clip_changed (window, &impl->position_info.clip_rect, &new_info.clip_rect);
777 this_pos.x = parent_pos->x + obj->x;
778 this_pos.y = parent_pos->y + obj->y;
779 this_pos.x11_x = parent_pos->x11_x + new_info.x;
780 this_pos.x11_y = parent_pos->x11_y + new_info.y;
781 this_pos.clip_rect = new_info.clip_rect;
783 if (impl->position_info.mapped && !new_info.mapped)
784 XUnmapWindow (GDK_DRAWABLE_XDISPLAY (window), GDK_DRAWABLE_XID (window));
786 d_xoffset = new_info.x_offset - impl->position_info.x_offset;
787 d_yoffset = new_info.y_offset - impl->position_info.y_offset;
789 if (d_xoffset != 0 || d_yoffset != 0)
791 GdkRectangle new_position;
793 if (d_xoffset < 0 || d_yoffset < 0)
794 gdk_window_queue_translation (window, MIN (d_xoffset, 0), MIN (d_yoffset, 0));
796 compute_intermediate_position (&impl->position_info, &new_info, d_xoffset, d_yoffset,
799 XMoveResizeWindow (GDK_DRAWABLE_XDISPLAY (window),
800 GDK_DRAWABLE_XID (window),
801 new_position.x, new_position.y, new_position.width, new_position.height);
804 tmp_list = obj->children;
807 gdk_window_premove (tmp_list->data, &this_pos);
808 tmp_list = tmp_list->next;
813 gdk_window_postmove (GdkWindow *window,
814 GdkWindowParentPos *parent_pos)
816 GdkWindowImplX11 *impl;
817 GdkWindowObject *obj;
818 GdkXPositionInfo new_info;
820 gint d_xoffset, d_yoffset;
821 GdkWindowParentPos this_pos;
823 obj = (GdkWindowObject *) window;
824 impl = GDK_WINDOW_IMPL_X11 (obj->impl);
826 gdk_window_compute_position (impl, parent_pos, &new_info);
828 this_pos.x = parent_pos->x + obj->x;
829 this_pos.y = parent_pos->y + obj->y;
830 this_pos.x11_x = parent_pos->x11_x + new_info.x;
831 this_pos.x11_y = parent_pos->x11_y + new_info.y;
832 this_pos.clip_rect = new_info.clip_rect;
834 d_xoffset = new_info.x_offset - impl->position_info.x_offset;
835 d_yoffset = new_info.y_offset - impl->position_info.y_offset;
837 if (d_xoffset != 0 || d_yoffset != 0)
839 if (d_xoffset > 0 || d_yoffset > 0)
840 gdk_window_queue_translation (window, MAX (d_xoffset, 0), MAX (d_yoffset, 0));
842 XMoveResizeWindow (GDK_DRAWABLE_XDISPLAY (window),
843 GDK_DRAWABLE_XID (window),
844 new_info.x, new_info.y, new_info.width, new_info.height);
847 if (!impl->position_info.mapped && new_info.mapped && GDK_WINDOW_IS_MAPPED (obj))
848 XMapWindow (GDK_DRAWABLE_XDISPLAY (window), GDK_DRAWABLE_XID (window));
850 if (impl->position_info.no_bg)
851 gdk_window_tmp_reset_bg (window);
853 impl->position_info = new_info;
855 tmp_list = obj->children;
858 gdk_window_postmove (tmp_list->data, &this_pos);
859 tmp_list = tmp_list->next;
864 expose_serial_predicate (Display *xdisplay,
868 gulong *serial = (gulong *)arg;
870 if (xev->xany.type == Expose)
871 *serial = MIN (*serial, xev->xany.serial);
876 /* Find oldest possible serial for an outstanding expose event
879 find_current_serial (Display *xdisplay)
882 gulong serial = NextRequest (xdisplay);
884 XSync (xdisplay, False);
886 XCheckIfEvent (xdisplay, &xev, expose_serial_predicate, (XPointer)&serial);
892 queue_delete_link (GQueue *queue,
895 if (queue->tail == link)
896 queue->tail = link->prev;
898 queue->head = g_list_remove_link (queue->head, link);
899 g_list_free_1 (link);
904 queue_item_free (GdkWindowQueueItem *item)
906 g_object_unref (item->window);
908 if (item->type == GDK_WINDOW_QUEUE_ANTIEXPOSE)
909 gdk_region_destroy (item->u.antiexpose.area);
915 gdk_window_queue (GdkWindow *window,
916 GdkWindowQueueItem *item)
918 GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (GDK_WINDOW_DISPLAY (window));
920 if (!display_x11->translate_queue)
921 display_x11->translate_queue = g_queue_new ();
923 /* Keep length of queue finite by, if it grows too long,
924 * figuring out the latest relevant serial and discarding
925 * irrelevant queue items.
927 if (display_x11->translate_queue->length >= 64)
929 gulong serial = find_current_serial (GDK_WINDOW_XDISPLAY (window));
930 GList *tmp_list = display_x11->translate_queue->head;
934 GdkWindowQueueItem *item = tmp_list->data;
935 GList *next = tmp_list->next;
937 if (serial > item->serial)
939 queue_delete_link (display_x11->translate_queue, tmp_list);
940 queue_item_free (item);
947 /* Catch the case where someone isn't processing events and there
948 * is an event stuck in the event queue with an old serial:
949 * If we can't reduce the queue length by the above method,
950 * discard anti-expose items. (We can't discard translate
953 if (display_x11->translate_queue->length >= 64)
955 GList *tmp_list = display_x11->translate_queue->head;
959 GdkWindowQueueItem *item = tmp_list->data;
960 GList *next = tmp_list->next;
962 if (item->type == GDK_WINDOW_QUEUE_ANTIEXPOSE)
964 queue_delete_link (display_x11->translate_queue, tmp_list);
965 queue_item_free (item);
972 g_object_ref (window);
974 item->window = window;
975 item->serial = NextRequest (GDK_WINDOW_XDISPLAY (window));
977 g_queue_push_tail (display_x11->translate_queue, item);
981 gdk_window_queue_translation (GdkWindow *window,
985 GdkWindowQueueItem *item = g_new (GdkWindowQueueItem, 1);
986 item->type = GDK_WINDOW_QUEUE_TRANSLATE;
987 item->u.translate.dx = dx;
988 item->u.translate.dy = dy;
990 gdk_window_queue (window, item);
994 _gdk_windowing_window_queue_antiexpose (GdkWindow *window,
997 GdkWindowQueueItem *item = g_new (GdkWindowQueueItem, 1);
998 item->type = GDK_WINDOW_QUEUE_ANTIEXPOSE;
999 item->u.antiexpose.area = area;
1001 gdk_window_queue (window, item);
1007 _gdk_window_process_expose (GdkWindow *window,
1011 GdkWindowImplX11 *impl;
1012 GdkRegion *invalidate_region = gdk_region_rectangle (area);
1013 GdkRegion *clip_region;
1014 GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (GDK_WINDOW_DISPLAY (window));
1015 impl = GDK_WINDOW_IMPL_X11 (GDK_WINDOW_OBJECT (window)->impl);
1017 if (display_x11->translate_queue)
1019 GList *tmp_list = display_x11->translate_queue->head;
1023 GdkWindowQueueItem *item = tmp_list->data;
1024 tmp_list = tmp_list->next;
1026 if (serial < item->serial)
1028 if (item->window == window)
1030 if (item->type == GDK_WINDOW_QUEUE_TRANSLATE)
1031 gdk_region_offset (invalidate_region, item->u.translate.dx, item->u.translate.dy);
1032 else /* anti-expose */
1033 gdk_region_subtract (invalidate_region, item->u.antiexpose.area);
1038 queue_delete_link (display_x11->translate_queue,
1039 display_x11->translate_queue->head);
1040 queue_item_free (item);
1045 clip_region = gdk_region_rectangle (&impl->position_info.clip_rect);
1046 gdk_region_intersect (invalidate_region, clip_region);
1048 if (!gdk_region_empty (invalidate_region))
1049 gdk_window_invalidate_region (window, invalidate_region, FALSE);
1051 gdk_region_destroy (invalidate_region);
1052 gdk_region_destroy (clip_region);
1056 gdk_window_tmp_unset_bg (GdkWindow *window)
1058 GdkWindowImplX11 *impl;
1059 GdkWindowObject *obj;
1061 obj = (GdkWindowObject *) window;
1062 impl = GDK_WINDOW_IMPL_X11 (obj->impl);
1064 impl->position_info.no_bg = TRUE;
1066 if (obj->bg_pixmap != GDK_NO_BG)
1067 XSetWindowBackgroundPixmap (GDK_DRAWABLE_XDISPLAY (window),
1068 GDK_DRAWABLE_XID (window), None);
1072 gdk_window_tmp_reset_bg (GdkWindow *window)
1074 GdkWindowImplX11 *impl;
1075 GdkWindowObject *obj;
1077 obj = (GdkWindowObject *) window;
1078 impl = GDK_WINDOW_IMPL_X11 (obj->impl);
1080 impl->position_info.no_bg = FALSE;
1082 if (obj->bg_pixmap == GDK_NO_BG)
1089 if (obj->bg_pixmap == GDK_PARENT_RELATIVE_BG)
1090 xpixmap = ParentRelative;
1092 xpixmap = GDK_DRAWABLE_XID (obj->bg_pixmap);
1094 XSetWindowBackgroundPixmap (GDK_DRAWABLE_XDISPLAY (window),
1095 GDK_DRAWABLE_XID (window), xpixmap);
1099 XSetWindowBackground (GDK_DRAWABLE_XDISPLAY (window),
1100 GDK_DRAWABLE_XID (window),
1101 obj->bg_color.pixel);
1106 gdk_window_clip_changed (GdkWindow *window, GdkRectangle *old_clip, GdkRectangle *new_clip)
1108 GdkWindowImplX11 *impl;
1109 GdkWindowObject *obj;
1110 GdkRegion *old_clip_region;
1111 GdkRegion *new_clip_region;
1113 if (((GdkWindowObject *)window)->input_only)
1116 obj = (GdkWindowObject *) window;
1117 impl = GDK_WINDOW_IMPL_X11 (obj->impl);
1119 old_clip_region = gdk_region_rectangle (old_clip);
1120 new_clip_region = gdk_region_rectangle (new_clip);
1122 /* We need to update this here because gdk_window_invalidate_region makes
1123 * use if it (through gdk_drawable_get_visible_region
1125 impl->position_info.clip_rect = *new_clip;
1127 /* Trim invalid region of window to new clip rectangle
1129 if (obj->update_area)
1130 gdk_region_intersect (obj->update_area, new_clip_region);
1132 /* Invalidate newly exposed portion of window
1134 gdk_region_subtract (new_clip_region, old_clip_region);
1135 if (!gdk_region_empty (new_clip_region))
1137 gdk_window_tmp_unset_bg (window);
1138 gdk_window_invalidate_region (window, new_clip_region, FALSE);
1141 gdk_region_destroy (new_clip_region);
1142 gdk_region_destroy (old_clip_region);