1 /* GDK - The GIMP Drawing Kit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
20 /* gdkgeometry-x11.c: emulation of 32 bit coordinates within the
23 * By Owen Taylor <otaylor@redhat.com>
24 * Copyright Red Hat, Inc. 2000
26 * The algorithms implemented in this file are an extension of the
27 * idea of guffaw scrolling, a technique (and name) taken from the classic
28 * Netscape source code. The basic idea of guffaw scrolling is a trick
29 * to get around a limitation of X: there is no way of scrolling the
30 * contents of a window. Guffaw scrolling exploits the X concepts of
31 * window gravity and bit gravity:
33 * window gravity: the window gravity of a window affects what happens
34 * to a windows position when _its parent_ is resized, or
35 * moved and resized simultaneously.
37 * bit gravity: the bit gravity of a window affects what happens to
38 * the pixels of a window when _it_ is is resized, or moved and
39 * resized simultaneously.
41 * These were basically intended to do things like have right
42 * justified widgets in a window automatically stay right justified
43 * when the window was resized, but there is also the special
44 * "StaticGravity" which means "do nothing." We can exploit
45 * StaticGravity to scroll a window:
50 * |abcdefghijk | (1) Resize bigger
51 * | efghijk | (2) Move
52 * |efghijk | (3) Move-resize back to the original size
54 * Or, going the other way:
57 * | abcdefghijk| (1) Move-resize bigger
58 * | abcdefghijk| (2) Move
59 * | abcdefg| (4) Resize back to the original size
61 * By using this technique, we can simulate scrolling around in a
62 * large virtual space without having to actually have windows that
63 * big; for the pixels of the window, this is all we have to do. For
64 * subwindows, we have to take care of one other detail - since
65 * coordinates in X are limited to 16 bits, subwindows scrolled off
66 * will wrap around and come back eventually. So, we have to take care
67 * to unmap windows that go outside the 16-bit range and remap them as
70 * Since we are temporarily making the window bigger, this only looks
71 * good if the edges of the window are obscured. Typically, we do
72 * this by making the window we are scrolling the immediate child
75 * But, this isn't a perfect API for applications for several reasons:
77 * - We have to use this inefficient technique even for small windows
78 * if the window _could_ be big.
79 * - Applications have to use a special scrolling API.
81 * What we'd like is to simply have windows with 32 bit coordinates
82 * so applications could scroll in the classic way - just move a big
85 * It turns out that StaticGravity can also be used to achieve emulation
86 * of 32 bit coordinates with only 16 bit coordinates if we expand
87 * our horizons just a bit; what guffaw scrolling really is is a way
88 * to move the contents of a window a different amount than we move
89 * the borders of of the window. In the above example pictures we
90 * ended up with the borders of the window not moving at all, but
91 * that isn't necessary.
93 * So, what we do is set up a mapping from virtual 32 bit window position/size
96 * - Real window position/size
97 * - Offset between virtual coordinates and real coordinates for the window
98 * - Map state (mapped or unmapped)
100 * By the following rules:
102 * - If the window is less than 32767 pixels in width (resp. height), we use it's
103 * virtual width and position.
104 * - Otherwise, we use a width of 32767 and determine the position of the window
105 * so that the portion of the real window [16384, 16383] in _toplevel window
106 * coordinates_ is the same as the portion of the real window
108 * This is implemented in gdk_window_compute_position(). Then the algorithm
109 * for a moving a window (_window_move_resize_child ()) is:
111 * - Compute the new window mappings for the window and all subwindows
112 * - Expand out the boundary of the window and all subwindows by the amount
113 * that the real/virtual offset changes for each window.
114 * (compute_intermediate_position() computes expanded boundary)
115 * - Move the toplevel by the amount that it's contents need to translate.
116 * - Move/resize the window and all subwindows to the newly computed
119 * If we just are scrolling (gdk_window_guffaw_scroll()), then things
120 * are similar, except that the final mappings for the toplevel are
121 * the same as the initial mappings, but we act as if it moved by the
122 * amount we are scrolling by.
124 * Note that we don't have to worry about a clip window in
125 * _gdk_window_move_resize() since we have set up our translation so
126 * that things in the range [16384,16383] in toplevel window
127 * coordinates look exactly as they would if we were simply moving the
128 * windows, and nothing outside this range is going to be visible
129 * unless the user has a _really_ huge screen.
133 #include "gdk.h" /* For gdk_rectangle_intersect */
134 #include "gdkprivate-x11.h"
136 #include "gdkregion.h"
137 #include "gdkinternals.h"
138 #include "gdkscreen-x11.h"
139 #include "gdkdisplay-x11.h"
140 #include "gdkwindow-x11.h"
141 #include "gdkalias.h"
143 typedef struct _GdkWindowQueueItem GdkWindowQueueItem;
144 typedef struct _GdkWindowParentPos GdkWindowParentPos;
147 GDK_WINDOW_QUEUE_TRANSLATE,
148 GDK_WINDOW_QUEUE_ANTIEXPOSE
149 } GdkWindowQueueType;
151 struct _GdkWindowQueueItem
155 GdkWindowQueueType type;
168 struct _GdkWindowParentPos
174 GdkRectangle clip_rect;
177 static void gdk_window_compute_position (GdkWindowImplX11 *window,
178 GdkWindowParentPos *parent_pos,
179 GdkXPositionInfo *info);
180 static void gdk_window_compute_parent_pos (GdkWindowImplX11 *window,
181 GdkWindowParentPos *parent_pos);
182 static void gdk_window_premove (GdkWindow *window,
183 GdkWindowParentPos *parent_pos);
184 static void gdk_window_postmove (GdkWindow *window,
185 GdkWindowParentPos *parent_pos);
186 static void gdk_window_queue_translation (GdkWindow *window,
190 static void gdk_window_clip_changed (GdkWindow *window,
191 GdkRectangle *old_clip,
192 GdkRectangle *new_clip);
195 _gdk_windowing_window_get_offsets (GdkWindow *window,
199 GdkWindowImplX11 *impl =
200 GDK_WINDOW_IMPL_X11 (GDK_WINDOW_OBJECT (window)->impl);
202 *x_offset = impl->position_info.x_offset;
203 *y_offset = impl->position_info.y_offset;
207 _gdk_window_init_position (GdkWindow *window)
209 GdkWindowParentPos parent_pos;
210 GdkWindowImplX11 *impl;
212 g_return_if_fail (GDK_IS_WINDOW (window));
215 GDK_WINDOW_IMPL_X11 (GDK_WINDOW_OBJECT (window)->impl);
217 gdk_window_compute_parent_pos (impl, &parent_pos);
218 gdk_window_compute_position (impl, &parent_pos, &impl->position_info);
222 gdk_window_copy_area_scroll (GdkWindow *window,
223 GdkRectangle *dest_rect,
227 GdkWindowObject *obj = GDK_WINDOW_OBJECT (window);
230 if (dest_rect->width > 0 && dest_rect->height > 0)
234 gc = _gdk_drawable_get_scratch_gc (window, TRUE);
236 gdk_window_queue_translation (window, NULL, dx, dy);
238 XCopyArea (GDK_WINDOW_XDISPLAY (window),
239 GDK_WINDOW_XID (window),
240 GDK_WINDOW_XID (window),
241 gdk_x11_gc_get_xgc (gc),
242 dest_rect->x - dx, dest_rect->y - dy,
243 dest_rect->width, dest_rect->height,
244 dest_rect->x, dest_rect->y);
247 tmp_list = obj->children;
250 GdkWindow *child = GDK_WINDOW (tmp_list->data);
251 GdkWindowObject *child_obj = GDK_WINDOW_OBJECT (child);
253 gdk_window_move (child, child_obj->x + dx, child_obj->y + dy);
255 tmp_list = tmp_list->next;
260 compute_intermediate_position (GdkXPositionInfo *position_info,
261 GdkXPositionInfo *new_info,
264 GdkRectangle *new_position)
266 gint new_x0, new_x1, new_y0, new_y1;
268 /* Wrap d_xoffset, d_yoffset into [-32768,32767] range. For the
269 * purposes of subwindow movement, it doesn't matter if we are
270 * off by a factor of 65536, and if we don't do this range
271 * reduction, we'll end up with invalid widths.
273 d_xoffset = (gint16)d_xoffset;
274 d_yoffset = (gint16)d_yoffset;
278 new_x0 = position_info->x + d_xoffset;
279 new_x1 = position_info->x + position_info->width;
283 new_x0 = position_info->x;
284 new_x1 = position_info->x + new_info->width + d_xoffset;
287 new_position->x = new_x0;
288 new_position->width = new_x1 - new_x0;
292 new_y0 = position_info->y + d_yoffset;
293 new_y1 = position_info->y + position_info->height;
297 new_y0 = position_info->y;
298 new_y1 = position_info->y + new_info->height + d_yoffset;
301 new_position->y = new_y0;
302 new_position->height = new_y1 - new_y0;
306 gdk_window_guffaw_scroll (GdkWindow *window,
310 GdkWindowObject *obj = GDK_WINDOW_OBJECT (window);
311 GdkWindowImplX11 *impl = GDK_WINDOW_IMPL_X11 (obj->impl);
313 gint d_xoffset = -dx;
314 gint d_yoffset = -dy;
315 GdkRectangle new_position;
316 GdkXPositionInfo new_info;
317 GdkWindowParentPos parent_pos;
320 gdk_window_compute_parent_pos (impl, &parent_pos);
321 gdk_window_compute_position (impl, &parent_pos, &new_info);
323 parent_pos.x += obj->x;
324 parent_pos.y += obj->y;
325 parent_pos.x11_x += new_info.x;
326 parent_pos.x11_y += new_info.y;
327 parent_pos.clip_rect = new_info.clip_rect;
329 _gdk_x11_window_tmp_unset_bg (window, FALSE);;
331 if (dx > 0 || dy > 0)
332 gdk_window_queue_translation (window, NULL, MAX (dx, 0), MAX (dy, 0));
334 gdk_window_set_static_gravities (window, TRUE);
336 compute_intermediate_position (&impl->position_info, &new_info, d_xoffset, d_yoffset,
339 XMoveResizeWindow (GDK_WINDOW_XDISPLAY (window),
340 GDK_WINDOW_XID (window),
341 new_position.x, new_position.y, new_position.width, new_position.height);
343 tmp_list = obj->children;
346 GDK_WINDOW_OBJECT(tmp_list->data)->x -= d_xoffset;
347 GDK_WINDOW_OBJECT(tmp_list->data)->y -= d_yoffset;
349 gdk_window_premove (tmp_list->data, &parent_pos);
350 tmp_list = tmp_list->next;
353 XMoveWindow (GDK_WINDOW_XDISPLAY (window),
354 GDK_WINDOW_XID (window),
355 new_position.x - d_xoffset, new_position.y - d_yoffset);
357 if (dx < 0 || dy < 0)
358 gdk_window_queue_translation (window, NULL, MIN (dx, 0), MIN (dy, 0));
360 XMoveResizeWindow (GDK_WINDOW_XDISPLAY (window),
361 GDK_WINDOW_XID (window),
362 impl->position_info.x, impl->position_info.y,
363 impl->position_info.width, impl->position_info.height);
365 if (impl->position_info.no_bg)
366 _gdk_x11_window_tmp_reset_bg (window, FALSE);
368 impl->position_info = new_info;
370 tmp_list = obj->children;
373 gdk_window_postmove (tmp_list->data, &parent_pos);
374 tmp_list = tmp_list->next;
380 * @window: a #GdkWindow
381 * @dx: Amount to scroll in the X direction
382 * @dy: Amount to scroll in the Y direction
384 * Scroll the contents of @window, both pixels and children, by the given
385 * amount. @window itself does not move. Portions of the window that the scroll
386 * operation brings in from offscreen areas are invalidated. The invalidated
387 * region may be bigger than what would strictly be necessary. (For X11, a
388 * minimum area will be invalidated if the window has no subwindows, or if the
389 * edges of the window's parent do not extend beyond the edges of the window. In
390 * other cases, a multi-step process is used to scroll the window which may
391 * produce temporary visual artifacts and unnecessary invalidations.)
394 gdk_window_scroll (GdkWindow *window,
398 gboolean can_guffaw_scroll = FALSE;
399 GdkRegion *invalidate_region;
400 GdkWindowImplX11 *impl;
401 GdkWindowObject *obj;
402 GdkRectangle src_rect, dest_rect;
404 g_return_if_fail (GDK_IS_WINDOW (window));
406 if (GDK_WINDOW_DESTROYED (window))
409 obj = GDK_WINDOW_OBJECT (window);
410 impl = GDK_WINDOW_IMPL_X11 (obj->impl);
412 if (dx == 0 && dy == 0)
415 /* Move the current invalid region */
416 if (obj->update_area)
417 gdk_region_offset (obj->update_area, dx, dy);
419 /* impl->position_info.clip_rect isn't meaningful for toplevels */
420 if (GDK_WINDOW_TYPE (window) == GDK_WINDOW_CHILD)
421 src_rect = impl->position_info.clip_rect;
426 src_rect.width = impl->width;
427 src_rect.height = impl->height;
430 invalidate_region = gdk_region_rectangle (&src_rect);
432 dest_rect = src_rect;
435 gdk_rectangle_intersect (&dest_rect, &src_rect, &dest_rect);
437 if (dest_rect.width > 0 && dest_rect.height > 0)
439 GdkRegion *tmp_region;
441 tmp_region = gdk_region_rectangle (&dest_rect);
442 gdk_region_subtract (invalidate_region, tmp_region);
443 gdk_region_destroy (tmp_region);
446 gdk_window_invalidate_region (window, invalidate_region, TRUE);
447 gdk_region_destroy (invalidate_region);
449 /* We can guffaw scroll if we are a child window, and the parent
450 * does not extend beyond our edges. Otherwise, we use XCopyArea, then
451 * move any children later
453 if (GDK_WINDOW_TYPE (window) == GDK_WINDOW_CHILD)
455 GdkWindowImplX11 *parent_impl = GDK_WINDOW_IMPL_X11 (obj->parent->impl);
456 can_guffaw_scroll = ((dx == 0 || (obj->x <= 0 && obj->x + impl->width >= parent_impl->width)) &&
457 (dy == 0 || (obj->y <= 0 && obj->y + impl->height >= parent_impl->height)));
460 if (!obj->children || !can_guffaw_scroll)
461 gdk_window_copy_area_scroll (window, &dest_rect, dx, dy);
463 gdk_window_guffaw_scroll (window, dx, dy);
467 * gdk_window_move_region:
468 * @window: a #GdkWindow
469 * @region: The #GdkRegion to move
470 * @dx: Amount to move in the X direction
471 * @dy: Amount to move in the Y direction
473 * Move the part of @window indicated by @region by @dy pixels in the Y
474 * direction and @dx pixels in the X direction. The portions of @region
475 * that not covered by the new position of @region are invalidated.
477 * Child windows are not moved.
482 gdk_window_move_region (GdkWindow *window,
487 GdkWindowImplX11 *impl;
488 GdkWindowObject *private;
489 GdkRegion *window_clip;
490 GdkRegion *src_region;
491 GdkRegion *brought_in;
492 GdkRegion *dest_region;
493 GdkRegion *moving_invalid_region;
494 GdkRectangle dest_extents;
497 g_return_if_fail (GDK_IS_WINDOW (window));
498 g_return_if_fail (region != NULL);
500 if (GDK_WINDOW_DESTROYED (window))
503 private = GDK_WINDOW_OBJECT (window);
504 impl = GDK_WINDOW_IMPL_X11 (private->impl);
506 if (dx == 0 && dy == 0)
509 window_clip = gdk_region_rectangle (&impl->position_info.clip_rect);
511 /* compute source regions */
512 src_region = gdk_region_copy (region);
513 brought_in = gdk_region_copy (region);
514 gdk_region_intersect (src_region, window_clip);
516 gdk_region_subtract (brought_in, src_region);
517 gdk_region_offset (brought_in, dx, dy);
519 /* compute destination regions */
520 dest_region = gdk_region_copy (src_region);
521 gdk_region_offset (dest_region, dx, dy);
522 gdk_region_intersect (dest_region, window_clip);
523 gdk_region_get_clipbox (dest_region, &dest_extents);
525 gdk_region_destroy (window_clip);
527 /* calculating moving part of current invalid area */
528 moving_invalid_region = NULL;
529 if (private->update_area)
531 moving_invalid_region = gdk_region_copy (private->update_area);
532 gdk_region_intersect (moving_invalid_region, src_region);
533 gdk_region_offset (moving_invalid_region, dx, dy);
536 /* invalidate all of the src region */
537 gdk_window_invalidate_region (window, src_region, FALSE);
539 /* un-invalidate destination region */
540 if (private->update_area)
541 gdk_region_subtract (private->update_area, dest_region);
543 /* invalidate moving parts of existing update area */
544 if (moving_invalid_region)
546 gdk_window_invalidate_region (window, moving_invalid_region, FALSE);
547 gdk_region_destroy (moving_invalid_region);
550 /* invalidate area brought in from off-screen */
551 gdk_window_invalidate_region (window, brought_in, FALSE);
552 gdk_region_destroy (brought_in);
554 /* Actually do the moving */
555 gdk_window_queue_translation (window, src_region, dx, dy);
557 gc = _gdk_drawable_get_scratch_gc (window, TRUE);
558 gdk_gc_set_clip_region (gc, dest_region);
560 XCopyArea (GDK_WINDOW_XDISPLAY (window),
561 GDK_WINDOW_XID (window),
562 GDK_WINDOW_XID (window),
564 dest_extents.x - dx, dest_extents.y - dy,
565 dest_extents.width, dest_extents.height,
566 dest_extents.x, dest_extents.y);
568 /* Unset clip region of cached GC */
569 gdk_gc_set_clip_region (gc, NULL);
571 gdk_region_destroy (src_region);
572 gdk_region_destroy (dest_region);
576 reset_backgrounds (GdkWindow *window)
578 GdkWindowObject *obj = (GdkWindowObject *)window;
580 _gdk_x11_window_tmp_reset_bg (window, FALSE);
583 _gdk_x11_window_tmp_reset_bg ((GdkWindow *)obj->parent, FALSE);
587 _gdk_window_move_resize_child (GdkWindow *window,
593 GdkWindowImplX11 *impl;
594 GdkWindowObject *obj;
595 GdkXPositionInfo new_info;
596 GdkWindowParentPos parent_pos;
599 gint d_xoffset, d_yoffset;
604 GdkRectangle old_pos;
606 g_return_if_fail (window != NULL);
607 g_return_if_fail (GDK_IS_WINDOW (window));
609 impl = GDK_WINDOW_IMPL_X11 (GDK_WINDOW_OBJECT (window)->impl);
610 obj = GDK_WINDOW_OBJECT (window);
615 is_move = dx != 0 || dy != 0;
616 is_resize = impl->width != width || impl->height != height;
618 if (!is_move && !is_resize)
623 old_pos.width = impl->width;
624 old_pos.height = impl->height;
629 impl->height = height;
631 gdk_window_compute_parent_pos (impl, &parent_pos);
632 gdk_window_compute_position (impl, &parent_pos, &new_info);
634 gdk_window_clip_changed (window, &impl->position_info.clip_rect, &new_info.clip_rect);
636 parent_pos.x += obj->x;
637 parent_pos.y += obj->y;
638 parent_pos.x11_x += new_info.x;
639 parent_pos.x11_y += new_info.y;
640 parent_pos.clip_rect = new_info.clip_rect;
642 d_xoffset = new_info.x_offset - impl->position_info.x_offset;
643 d_yoffset = new_info.y_offset - impl->position_info.y_offset;
645 if (d_xoffset != 0 || d_yoffset != 0)
647 GdkRectangle new_position;
649 gdk_window_set_static_gravities (window, TRUE);
651 if (d_xoffset < 0 || d_yoffset < 0)
652 gdk_window_queue_translation (window, NULL, MIN (d_xoffset, 0), MIN (d_yoffset, 0));
654 compute_intermediate_position (&impl->position_info, &new_info, d_xoffset, d_yoffset,
657 XMoveResizeWindow (GDK_WINDOW_XDISPLAY (window),
658 GDK_WINDOW_XID (window),
659 new_position.x, new_position.y, new_position.width, new_position.height);
661 tmp_list = obj->children;
664 gdk_window_premove (tmp_list->data, &parent_pos);
665 tmp_list = tmp_list->next;
668 XMoveWindow (GDK_WINDOW_XDISPLAY (window),
669 GDK_WINDOW_XID (window),
670 new_position.x + dx, new_position.y + dy);
672 if (d_xoffset > 0 || d_yoffset > 0)
673 gdk_window_queue_translation (window, NULL, MAX (d_xoffset, 0), MAX (d_yoffset, 0));
675 XMoveResizeWindow (GDK_WINDOW_XDISPLAY (window),
676 GDK_WINDOW_XID (window),
677 new_info.x, new_info.y, new_info.width, new_info.height);
679 reset_backgrounds (window);
681 if (!impl->position_info.mapped && new_info.mapped && GDK_WINDOW_IS_MAPPED (obj))
682 XMapWindow (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window));
684 impl->position_info = new_info;
686 tmp_list = obj->children;
689 gdk_window_postmove (tmp_list->data, &parent_pos);
690 tmp_list = tmp_list->next;
695 if (is_move && is_resize)
696 gdk_window_set_static_gravities (window, FALSE);
698 if (impl->position_info.mapped && !new_info.mapped)
699 XUnmapWindow (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window));
701 tmp_list = obj->children;
704 gdk_window_premove (tmp_list->data, &parent_pos);
705 tmp_list = tmp_list->next;
709 XMoveResizeWindow (GDK_WINDOW_XDISPLAY (window),
710 GDK_WINDOW_XID (window),
711 new_info.x, new_info.y, new_info.width, new_info.height);
713 XMoveWindow (GDK_WINDOW_XDISPLAY (window),
714 GDK_WINDOW_XID (window),
715 new_info.x, new_info.y);
717 tmp_list = obj->children;
720 gdk_window_postmove (tmp_list->data, &parent_pos);
721 tmp_list = tmp_list->next;
724 reset_backgrounds (window);
726 if (!impl->position_info.mapped && new_info.mapped && GDK_WINDOW_IS_MAPPED (obj))
727 XMapWindow (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window));
729 impl->position_info = new_info;
732 if (GDK_WINDOW_IS_MAPPED (obj) && obj->parent)
733 gdk_window_invalidate_rect ((GdkWindow *)obj->parent, &old_pos, FALSE);
737 gdk_window_compute_position (GdkWindowImplX11 *window,
738 GdkWindowParentPos *parent_pos,
739 GdkXPositionInfo *info)
741 GdkWindowObject *wrapper;
745 g_return_if_fail (GDK_IS_WINDOW_IMPL_X11 (window));
747 wrapper = GDK_WINDOW_OBJECT (GDK_DRAWABLE_IMPL_X11 (window)->wrapper);
751 if (window->width <= 32767)
753 info->width = window->width;
754 info->x = parent_pos->x + wrapper->x - parent_pos->x11_x;
760 if (parent_pos->x + wrapper->x < -16384)
762 if (parent_pos->x + wrapper->x + window->width < 16384)
763 info->x = parent_pos->x + wrapper->x + window->width - info->width - parent_pos->x11_x;
765 info->x = -16384 - parent_pos->x11_x;
768 info->x = parent_pos->x + wrapper->x - parent_pos->x11_x;
771 if (window->height <= 32767)
773 info->height = window->height;
774 info->y = parent_pos->y + wrapper->y - parent_pos->x11_y;
779 info->height = 32767;
780 if (parent_pos->y + wrapper->y < -16384)
782 if (parent_pos->y + wrapper->y + window->height < 16384)
783 info->y = parent_pos->y + wrapper->y + window->height - info->height - parent_pos->x11_y;
785 info->y = -16384 - parent_pos->x11_y;
788 info->y = parent_pos->y + wrapper->y - parent_pos->x11_y;
791 parent_x_offset = parent_pos->x11_x - parent_pos->x;
792 parent_y_offset = parent_pos->x11_y - parent_pos->y;
794 info->x_offset = parent_x_offset + info->x - wrapper->x;
795 info->y_offset = parent_y_offset + info->y - wrapper->y;
797 /* We don't considering the clipping of toplevel windows and their immediate children
798 * by their parents, and simply always map those windows.
800 if (parent_pos->clip_rect.width == G_MAXINT)
802 /* Check if the window would wrap around into the visible space in either direction */
803 else if (info->x + parent_x_offset < parent_pos->clip_rect.x + parent_pos->clip_rect.width - 65536 ||
804 info->x + info->width + parent_x_offset > parent_pos->clip_rect.x + 65536 ||
805 info->y + parent_y_offset < parent_pos->clip_rect.y + parent_pos->clip_rect.height - 65536 ||
806 info->y + info->height + parent_y_offset > parent_pos->clip_rect.y + 65536)
807 info->mapped = FALSE;
813 if (GDK_WINDOW_TYPE (wrapper) == GDK_WINDOW_CHILD)
815 info->clip_rect.x = wrapper->x;
816 info->clip_rect.y = wrapper->y;
817 info->clip_rect.width = window->width;
818 info->clip_rect.height = window->height;
820 gdk_rectangle_intersect (&info->clip_rect, &parent_pos->clip_rect, &info->clip_rect);
822 info->clip_rect.x -= wrapper->x;
823 info->clip_rect.y -= wrapper->y;
827 info->clip_rect.x = 0;
828 info->clip_rect.y = 0;
829 info->clip_rect.width = G_MAXINT;
830 info->clip_rect.height = G_MAXINT;
835 gdk_window_compute_parent_pos (GdkWindowImplX11 *window,
836 GdkWindowParentPos *parent_pos)
838 GdkWindowObject *wrapper;
839 GdkWindowObject *parent;
840 GdkRectangle tmp_clip;
842 int clip_xoffset = 0;
843 int clip_yoffset = 0;
845 g_return_if_fail (GDK_IS_WINDOW_IMPL_X11 (window));
848 GDK_WINDOW_OBJECT (GDK_DRAWABLE_IMPL_X11 (window)->wrapper);
852 parent_pos->x11_x = 0;
853 parent_pos->x11_y = 0;
855 /* We take a simple approach here and simply consider toplevel
856 * windows not to clip their children on the right/bottom, since the
857 * size of toplevel windows is not directly under our
858 * control. Clipping only really matters when scrolling and
859 * generally we aren't going to be moving the immediate child of a
860 * toplevel beyond the bounds of that toplevel.
862 * We could go ahead and recompute the clips of toplevel windows and
863 * their descendents when we receive size notification, but it would
864 * probably not be an improvement in most cases.
866 parent_pos->clip_rect.x = 0;
867 parent_pos->clip_rect.y = 0;
868 parent_pos->clip_rect.width = G_MAXINT;
869 parent_pos->clip_rect.height = G_MAXINT;
871 parent = (GdkWindowObject *)wrapper->parent;
872 while (parent && parent->window_type == GDK_WINDOW_CHILD)
874 GdkWindowImplX11 *impl = GDK_WINDOW_IMPL_X11 (parent->impl);
876 tmp_clip.x = - clip_xoffset;
877 tmp_clip.y = - clip_yoffset;
878 tmp_clip.width = impl->width;
879 tmp_clip.height = impl->height;
881 gdk_rectangle_intersect (&parent_pos->clip_rect, &tmp_clip, &parent_pos->clip_rect);
883 parent_pos->x += parent->x;
884 parent_pos->y += parent->y;
885 parent_pos->x11_x += impl->position_info.x;
886 parent_pos->x11_y += impl->position_info.y;
888 clip_xoffset += parent->x;
889 clip_yoffset += parent->y;
891 parent = (GdkWindowObject *)parent->parent;
896 gdk_window_premove (GdkWindow *window,
897 GdkWindowParentPos *parent_pos)
899 GdkWindowImplX11 *impl;
900 GdkWindowObject *obj;
901 GdkXPositionInfo new_info;
903 gint d_xoffset, d_yoffset;
904 GdkWindowParentPos this_pos;
906 obj = (GdkWindowObject *) window;
907 impl = GDK_WINDOW_IMPL_X11 (obj->impl);
909 gdk_window_compute_position (impl, parent_pos, &new_info);
911 gdk_window_clip_changed (window, &impl->position_info.clip_rect, &new_info.clip_rect);
913 this_pos.x = parent_pos->x + obj->x;
914 this_pos.y = parent_pos->y + obj->y;
915 this_pos.x11_x = parent_pos->x11_x + new_info.x;
916 this_pos.x11_y = parent_pos->x11_y + new_info.y;
917 this_pos.clip_rect = new_info.clip_rect;
919 if (impl->position_info.mapped && !new_info.mapped)
920 XUnmapWindow (GDK_DRAWABLE_XDISPLAY (window), GDK_DRAWABLE_XID (window));
922 d_xoffset = new_info.x_offset - impl->position_info.x_offset;
923 d_yoffset = new_info.y_offset - impl->position_info.y_offset;
925 if (d_xoffset != 0 || d_yoffset != 0)
927 GdkRectangle new_position;
929 if (d_xoffset < 0 || d_yoffset < 0)
930 gdk_window_queue_translation (window, NULL, MIN (d_xoffset, 0), MIN (d_yoffset, 0));
932 compute_intermediate_position (&impl->position_info, &new_info, d_xoffset, d_yoffset,
935 XMoveResizeWindow (GDK_DRAWABLE_XDISPLAY (window),
936 GDK_DRAWABLE_XID (window),
937 new_position.x, new_position.y, new_position.width, new_position.height);
940 tmp_list = obj->children;
943 gdk_window_premove (tmp_list->data, &this_pos);
944 tmp_list = tmp_list->next;
949 gdk_window_postmove (GdkWindow *window,
950 GdkWindowParentPos *parent_pos)
952 GdkWindowImplX11 *impl;
953 GdkWindowObject *obj;
954 GdkXPositionInfo new_info;
956 gint d_xoffset, d_yoffset;
957 GdkWindowParentPos this_pos;
959 obj = (GdkWindowObject *) window;
960 impl = GDK_WINDOW_IMPL_X11 (obj->impl);
962 gdk_window_compute_position (impl, parent_pos, &new_info);
964 this_pos.x = parent_pos->x + obj->x;
965 this_pos.y = parent_pos->y + obj->y;
966 this_pos.x11_x = parent_pos->x11_x + new_info.x;
967 this_pos.x11_y = parent_pos->x11_y + new_info.y;
968 this_pos.clip_rect = new_info.clip_rect;
970 d_xoffset = new_info.x_offset - impl->position_info.x_offset;
971 d_yoffset = new_info.y_offset - impl->position_info.y_offset;
973 if (d_xoffset != 0 || d_yoffset != 0)
975 if (d_xoffset > 0 || d_yoffset > 0)
976 gdk_window_queue_translation (window, NULL, MAX (d_xoffset, 0), MAX (d_yoffset, 0));
978 XMoveResizeWindow (GDK_DRAWABLE_XDISPLAY (window),
979 GDK_DRAWABLE_XID (window),
980 new_info.x, new_info.y, new_info.width, new_info.height);
983 if (!impl->position_info.mapped && new_info.mapped && GDK_WINDOW_IS_MAPPED (obj))
984 XMapWindow (GDK_DRAWABLE_XDISPLAY (window), GDK_DRAWABLE_XID (window));
986 reset_backgrounds (window);
988 impl->position_info = new_info;
990 tmp_list = obj->children;
993 gdk_window_postmove (tmp_list->data, &this_pos);
994 tmp_list = tmp_list->next;
999 expose_serial_predicate (Display *xdisplay,
1003 gulong *serial = (gulong *)arg;
1005 if (xev->xany.type == Expose)
1006 *serial = MIN (*serial, xev->xany.serial);
1011 /* Find oldest possible serial for an outstanding expose event
1014 find_current_serial (Display *xdisplay)
1017 gulong serial = NextRequest (xdisplay);
1019 XSync (xdisplay, False);
1021 XCheckIfEvent (xdisplay, &xev, expose_serial_predicate, (XPointer)&serial);
1027 queue_delete_link (GQueue *queue,
1030 if (queue->tail == link)
1031 queue->tail = link->prev;
1033 queue->head = g_list_remove_link (queue->head, link);
1034 g_list_free_1 (link);
1039 queue_item_free (GdkWindowQueueItem *item)
1043 g_object_remove_weak_pointer (G_OBJECT (item->window),
1044 (gpointer *)&(item->window));
1047 if (item->type == GDK_WINDOW_QUEUE_ANTIEXPOSE)
1048 gdk_region_destroy (item->u.antiexpose.area);
1051 if (item->u.translate.area)
1052 gdk_region_destroy (item->u.translate.area);
1059 gdk_window_queue (GdkWindow *window,
1060 GdkWindowQueueItem *item)
1062 GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (GDK_WINDOW_DISPLAY (window));
1064 if (!display_x11->translate_queue)
1065 display_x11->translate_queue = g_queue_new ();
1067 /* Keep length of queue finite by, if it grows too long,
1068 * figuring out the latest relevant serial and discarding
1069 * irrelevant queue items.
1071 if (display_x11->translate_queue->length >= 64)
1073 gulong serial = find_current_serial (GDK_WINDOW_XDISPLAY (window));
1074 GList *tmp_list = display_x11->translate_queue->head;
1078 GdkWindowQueueItem *item = tmp_list->data;
1079 GList *next = tmp_list->next;
1081 if (serial > item->serial)
1083 queue_delete_link (display_x11->translate_queue, tmp_list);
1084 queue_item_free (item);
1091 /* Catch the case where someone isn't processing events and there
1092 * is an event stuck in the event queue with an old serial:
1093 * If we can't reduce the queue length by the above method,
1094 * discard anti-expose items. (We can't discard translate
1097 if (display_x11->translate_queue->length >= 64)
1099 GList *tmp_list = display_x11->translate_queue->head;
1103 GdkWindowQueueItem *item = tmp_list->data;
1104 GList *next = tmp_list->next;
1106 if (item->type == GDK_WINDOW_QUEUE_ANTIEXPOSE)
1108 queue_delete_link (display_x11->translate_queue, tmp_list);
1109 queue_item_free (item);
1116 item->window = window;
1117 item->serial = NextRequest (GDK_WINDOW_XDISPLAY (window));
1119 g_object_add_weak_pointer (G_OBJECT (window),
1120 (gpointer *)&(item->window));
1122 g_queue_push_tail (display_x11->translate_queue, item);
1126 gdk_window_queue_translation (GdkWindow *window,
1131 GdkWindowQueueItem *item = g_new (GdkWindowQueueItem, 1);
1132 item->type = GDK_WINDOW_QUEUE_TRANSLATE;
1133 item->u.translate.area = area ? gdk_region_copy (area) : NULL;
1134 item->u.translate.dx = dx;
1135 item->u.translate.dy = dy;
1137 gdk_window_queue (window, item);
1141 _gdk_windowing_window_queue_antiexpose (GdkWindow *window,
1144 GdkWindowQueueItem *item = g_new (GdkWindowQueueItem, 1);
1145 item->type = GDK_WINDOW_QUEUE_ANTIEXPOSE;
1146 item->u.antiexpose.area = area;
1148 gdk_window_queue (window, item);
1154 _gdk_window_process_expose (GdkWindow *window,
1158 GdkWindowImplX11 *impl;
1159 GdkRegion *invalidate_region = gdk_region_rectangle (area);
1160 GdkRegion *clip_region;
1161 GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (GDK_WINDOW_DISPLAY (window));
1162 impl = GDK_WINDOW_IMPL_X11 (GDK_WINDOW_OBJECT (window)->impl);
1164 if (display_x11->translate_queue)
1166 GList *tmp_list = display_x11->translate_queue->head;
1170 GdkWindowQueueItem *item = tmp_list->data;
1171 tmp_list = tmp_list->next;
1173 if (serial < item->serial)
1175 if (item->window == window)
1177 if (item->type == GDK_WINDOW_QUEUE_TRANSLATE)
1179 if (item->u.translate.area)
1181 GdkRegion *intersection;
1183 intersection = gdk_region_copy (invalidate_region);
1184 gdk_region_intersect (intersection, item->u.translate.area);
1185 gdk_region_subtract (invalidate_region, intersection);
1186 gdk_region_offset (intersection, item->u.translate.dx, item->u.translate.dy);
1187 gdk_region_union (invalidate_region, intersection);
1188 gdk_region_destroy (intersection);
1191 gdk_region_offset (invalidate_region, item->u.translate.dx, item->u.translate.dy);
1193 else /* anti-expose */
1195 gdk_region_subtract (invalidate_region, item->u.antiexpose.area);
1201 queue_delete_link (display_x11->translate_queue,
1202 display_x11->translate_queue->head);
1203 queue_item_free (item);
1208 clip_region = gdk_region_rectangle (&impl->position_info.clip_rect);
1209 gdk_region_intersect (invalidate_region, clip_region);
1211 if (!gdk_region_empty (invalidate_region))
1212 gdk_window_invalidate_region (window, invalidate_region, FALSE);
1214 gdk_region_destroy (invalidate_region);
1215 gdk_region_destroy (clip_region);
1219 gdk_window_clip_changed (GdkWindow *window, GdkRectangle *old_clip, GdkRectangle *new_clip)
1221 GdkWindowImplX11 *impl;
1222 GdkWindowObject *obj;
1223 GdkRegion *old_clip_region;
1224 GdkRegion *new_clip_region;
1226 if (((GdkWindowObject *)window)->input_only)
1229 obj = (GdkWindowObject *) window;
1230 impl = GDK_WINDOW_IMPL_X11 (obj->impl);
1232 old_clip_region = gdk_region_rectangle (old_clip);
1233 new_clip_region = gdk_region_rectangle (new_clip);
1235 /* We need to update this here because gdk_window_invalidate_region makes
1236 * use if it (through gdk_drawable_get_visible_region
1238 impl->position_info.clip_rect = *new_clip;
1240 /* Trim invalid region of window to new clip rectangle
1242 if (obj->update_area)
1243 gdk_region_intersect (obj->update_area, new_clip_region);
1245 /* Invalidate newly exposed portion of window
1247 gdk_region_subtract (new_clip_region, old_clip_region);
1248 if (!gdk_region_empty (new_clip_region))
1250 _gdk_x11_window_tmp_unset_bg (window, FALSE);;
1251 gdk_window_invalidate_region (window, new_clip_region, FALSE);
1255 _gdk_x11_window_tmp_unset_bg ((GdkWindow *)obj->parent, FALSE);
1257 gdk_region_destroy (new_clip_region);
1258 gdk_region_destroy (old_clip_region);
1261 #define __GDK_GEOMETRY_X11_C__
1262 #include "gdkaliasdef.c"