]> Pileus Git - ~andy/gtk/blob - gdk/x11/gdkgeometry-x11.c
gtk/gtklayout.c (gtk_layout_realize), gtk/gtkiconview.c
[~andy/gtk] / gdk / x11 / gdkgeometry-x11.c
1 /* GDK - The GIMP Drawing Kit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
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.
8  *
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.
13  *
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.
18  */
19
20 /* gdkgeometry-x11.c: emulation of 32 bit coordinates within the
21  * limits of X. 
22  *
23  * By Owen Taylor <otaylor@redhat.com>
24  * Copyright Red Hat, Inc. 2000
25  *
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:
32  *
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.
36  *
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.
40  *
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:
46  *
47  *     |  VISIBLE  |
48  * 
49  *     |abcdefghijk|
50  *     |abcdefghijk    |   (1) Resize bigger
51  * |    efghijk    |       (2) Move  
52  *     |efghijk    |       (3) Move-resize back to the original size
53  *
54  * Or, going the other way:
55
56  *     |abcdefghijk|
57  * |    abcdefghijk|       (1) Move-resize bigger
58  *     |    abcdefghijk|   (2) Move  
59  *     |    abcdefg|       (4) Resize back to the original size
60  *
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
68  * they come back in.
69  *
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
73  * of a "clip window".
74  *
75  * But, this isn't a perfect API for applications for several reasons:
76  *
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.
80  *
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
83  * window around.
84  *
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.
92  *
93  * So, what we do is set up a mapping from virtual 32 bit window position/size
94  * to:
95  *
96  *  - Real window position/size
97  *  - Offset between virtual coordinates and real coordinates for the window
98  *  - Map state (mapped or unmapped)
99  *
100  * By the following rules:
101  *
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 
107  *
108  * This is implemented in gdk_window_compute_position(). Then the algorithm
109  * for a moving a window (_window_move_resize_child ()) is:
110  * 
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
117  *    positions.
118  *
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.
123  *
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.
130  */
131
132 #include <config.h>
133 #include "gdk.h"                /* For gdk_rectangle_intersect */
134 #include "gdkprivate-x11.h"
135 #include "gdkx.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"
142
143 typedef struct _GdkWindowQueueItem GdkWindowQueueItem;
144 typedef struct _GdkWindowParentPos GdkWindowParentPos;
145
146 typedef enum {
147   GDK_WINDOW_QUEUE_TRANSLATE,
148   GDK_WINDOW_QUEUE_ANTIEXPOSE
149 } GdkWindowQueueType;
150
151 struct _GdkWindowQueueItem
152 {
153   GdkWindow *window;
154   gulong serial;
155   GdkWindowQueueType type;
156   union {
157     struct {
158       GdkRegion *area;
159       gint dx;
160       gint dy;
161     } translate;
162     struct {
163       GdkRegion *area;
164     } antiexpose;
165   } u;
166 };
167
168 struct _GdkWindowParentPos
169 {
170   gint x;
171   gint y;
172   gint x11_x;
173   gint x11_y;
174   GdkRectangle clip_rect;
175 };
176
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,
187                                            GdkRegion          *area,
188                                            gint                dx,
189                                            gint                dy);
190 static void gdk_window_clip_changed       (GdkWindow          *window,
191                                            GdkRectangle       *old_clip,
192                                            GdkRectangle       *new_clip);
193
194 void
195 _gdk_windowing_window_get_offsets (GdkWindow *window,
196                                    gint      *x_offset,
197                                    gint      *y_offset)
198 {
199   GdkWindowImplX11 *impl =
200     GDK_WINDOW_IMPL_X11 (GDK_WINDOW_OBJECT (window)->impl);
201
202   *x_offset = impl->position_info.x_offset;
203   *y_offset = impl->position_info.y_offset;
204 }
205
206 void
207 _gdk_window_init_position (GdkWindow *window)
208 {
209   GdkWindowParentPos parent_pos;
210   GdkWindowImplX11 *impl;
211   
212   g_return_if_fail (GDK_IS_WINDOW (window));
213   
214   impl =
215     GDK_WINDOW_IMPL_X11 (GDK_WINDOW_OBJECT (window)->impl);
216   
217   gdk_window_compute_parent_pos (impl, &parent_pos);
218   gdk_window_compute_position (impl, &parent_pos, &impl->position_info);
219 }
220
221 static void
222 gdk_window_copy_area_scroll (GdkWindow    *window,
223                              GdkRectangle *dest_rect,
224                              gint          dx,
225                              gint          dy)
226 {
227   GdkWindowObject *obj = GDK_WINDOW_OBJECT (window);
228   GList *tmp_list;
229
230   if (dest_rect->width > 0 && dest_rect->height > 0)
231     {
232       GdkGC *gc;
233
234       gc = _gdk_drawable_get_scratch_gc (window, TRUE);
235       
236       gdk_window_queue_translation (window, NULL, dx, dy);
237    
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);
245     }
246
247   tmp_list = obj->children;
248   while (tmp_list)
249     {
250       GdkWindow *child = GDK_WINDOW (tmp_list->data);
251       GdkWindowObject *child_obj = GDK_WINDOW_OBJECT (child);
252           
253       gdk_window_move (child, child_obj->x + dx, child_obj->y + dy);
254       
255       tmp_list = tmp_list->next;
256     }
257 }
258
259 static void
260 compute_intermediate_position (GdkXPositionInfo *position_info,
261                                GdkXPositionInfo *new_info,
262                                gint              d_xoffset,
263                                gint              d_yoffset,
264                                GdkRectangle     *new_position)
265 {
266   gint new_x0, new_x1, new_y0, new_y1;
267   
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.
272    */
273   d_xoffset = (gint16)d_xoffset;
274   d_yoffset = (gint16)d_yoffset;
275   
276   if (d_xoffset < 0)
277     {
278       new_x0 = position_info->x + d_xoffset;
279       new_x1 = position_info->x + position_info->width;
280     }
281   else
282     {
283       new_x0 = position_info->x;
284       new_x1 = position_info->x + new_info->width + d_xoffset;
285     }
286
287   new_position->x = new_x0;
288   new_position->width = new_x1 - new_x0;
289   
290   if (d_yoffset < 0)
291     {
292       new_y0 = position_info->y + d_yoffset;
293       new_y1 = position_info->y + position_info->height;
294     }
295   else
296     {
297       new_y0 = position_info->y;
298       new_y1 = position_info->y + new_info->height + d_yoffset;
299     }
300   
301   new_position->y = new_y0;
302   new_position->height = new_y1 - new_y0;
303 }
304
305 static void
306 gdk_window_guffaw_scroll (GdkWindow    *window,
307                           gint          dx,
308                           gint          dy)
309 {
310   GdkWindowObject *obj = GDK_WINDOW_OBJECT (window);
311   GdkWindowImplX11 *impl = GDK_WINDOW_IMPL_X11 (obj->impl);
312
313   gint d_xoffset = -dx;
314   gint d_yoffset = -dy;
315   GdkRectangle new_position;
316   GdkXPositionInfo new_info;
317   GdkWindowParentPos parent_pos;
318   GList *tmp_list;
319   
320   gdk_window_compute_parent_pos (impl, &parent_pos);
321   gdk_window_compute_position (impl, &parent_pos, &new_info);
322
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;
328
329   _gdk_x11_window_tmp_unset_bg (window, FALSE);;
330
331   if (dx > 0 || dy > 0)
332     gdk_window_queue_translation (window, NULL, MAX (dx, 0), MAX (dy, 0));
333         
334   gdk_window_set_static_gravities (window, TRUE);
335
336   compute_intermediate_position (&impl->position_info, &new_info, d_xoffset, d_yoffset,
337                                  &new_position);
338   
339   XMoveResizeWindow (GDK_WINDOW_XDISPLAY (window),
340                      GDK_WINDOW_XID (window),
341                      new_position.x, new_position.y, new_position.width, new_position.height);
342   
343   tmp_list = obj->children;
344   while (tmp_list)
345     {
346       GDK_WINDOW_OBJECT(tmp_list->data)->x -= d_xoffset;
347       GDK_WINDOW_OBJECT(tmp_list->data)->y -= d_yoffset;
348
349       gdk_window_premove (tmp_list->data, &parent_pos);
350       tmp_list = tmp_list->next;
351     }
352   
353   XMoveWindow (GDK_WINDOW_XDISPLAY (window),
354                GDK_WINDOW_XID (window),
355                new_position.x - d_xoffset, new_position.y - d_yoffset);
356   
357   if (dx < 0 || dy < 0)
358     gdk_window_queue_translation (window, NULL, MIN (dx, 0), MIN (dy, 0));
359   
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);
364   
365   if (impl->position_info.no_bg)
366     _gdk_x11_window_tmp_reset_bg (window, FALSE);
367   
368   impl->position_info = new_info;
369   
370   tmp_list = obj->children;
371   while (tmp_list)
372     {
373       gdk_window_postmove (tmp_list->data, &parent_pos);
374       tmp_list = tmp_list->next;
375     }
376 }
377
378 /**
379  * gdk_window_scroll:
380  * @window: a #GdkWindow
381  * @dx: Amount to scroll in the X direction
382  * @dy: Amount to scroll in the Y direction
383  * 
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.)
392  **/
393 void
394 gdk_window_scroll (GdkWindow *window,
395                    gint       dx,
396                    gint       dy)
397 {
398   gboolean can_guffaw_scroll = FALSE;
399   GdkRegion *invalidate_region;
400   GdkWindowImplX11 *impl;
401   GdkWindowObject *obj;
402   GdkRectangle src_rect, dest_rect;
403   
404   g_return_if_fail (GDK_IS_WINDOW (window));
405
406   if (GDK_WINDOW_DESTROYED (window))
407     return;
408   
409   obj = GDK_WINDOW_OBJECT (window);
410   impl = GDK_WINDOW_IMPL_X11 (obj->impl);  
411
412   if (dx == 0 && dy == 0)
413     return;
414   
415   /* Move the current invalid region */
416   if (obj->update_area)
417     gdk_region_offset (obj->update_area, dx, dy);
418   
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;
422   else
423     {
424       src_rect.x = 0;
425       src_rect.y = 0;
426       src_rect.width = impl->width;
427       src_rect.height = impl->height;
428     }
429   
430   invalidate_region = gdk_region_rectangle (&src_rect);
431
432   dest_rect = src_rect;
433   dest_rect.x += dx;
434   dest_rect.y += dy;
435   gdk_rectangle_intersect (&dest_rect, &src_rect, &dest_rect);
436
437   if (dest_rect.width > 0 && dest_rect.height > 0)
438     {
439       GdkRegion *tmp_region;
440
441       tmp_region = gdk_region_rectangle (&dest_rect);
442       gdk_region_subtract (invalidate_region, tmp_region);
443       gdk_region_destroy (tmp_region);
444     }
445   
446   gdk_window_invalidate_region (window, invalidate_region, TRUE);
447   gdk_region_destroy (invalidate_region);
448
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
452    */
453   if (GDK_WINDOW_TYPE (window) == GDK_WINDOW_CHILD)
454     {
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)));
458     }
459
460   if (!obj->children || !can_guffaw_scroll)
461     gdk_window_copy_area_scroll (window, &dest_rect, dx, dy);
462   else
463     gdk_window_guffaw_scroll (window, dx, dy);
464 }
465
466 /**
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
472  * 
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.
476  * 
477  * Child windows are not moved.
478  * 
479  * Since: 2.8
480  **/
481 void
482 gdk_window_move_region (GdkWindow *window,
483                         GdkRegion *region,
484                         gint       dx,
485                         gint       dy)
486 {
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;
495   GdkGC *gc;
496   
497   g_return_if_fail (GDK_IS_WINDOW (window));
498   g_return_if_fail (region != NULL);
499   
500   if (GDK_WINDOW_DESTROYED (window))
501     return;
502   
503   private = GDK_WINDOW_OBJECT (window);
504   impl = GDK_WINDOW_IMPL_X11 (private->impl);  
505
506   if (dx == 0 && dy == 0)
507     return;
508
509   window_clip = gdk_region_rectangle (&impl->position_info.clip_rect);
510
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);
515
516   gdk_region_subtract (brought_in, src_region);
517   gdk_region_offset (brought_in, dx, dy);
518
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);
524
525   gdk_region_destroy (window_clip);
526
527   /* calculating moving part of current invalid area */
528   moving_invalid_region = NULL;
529   if (private->update_area)
530     {
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);
534     }
535   
536   /* invalidate all of the src region */
537   gdk_window_invalidate_region (window, src_region, FALSE);
538
539   /* un-invalidate destination region */
540   if (private->update_area)
541     gdk_region_subtract (private->update_area, dest_region);
542   
543   /* invalidate moving parts of existing update area */
544   if (moving_invalid_region)
545     {
546       gdk_window_invalidate_region (window, moving_invalid_region, FALSE);
547       gdk_region_destroy (moving_invalid_region);
548     }
549
550   /* invalidate area brought in from off-screen */
551   gdk_window_invalidate_region (window, brought_in, FALSE);
552   gdk_region_destroy (brought_in);
553
554   /* Actually do the moving */
555   gdk_window_queue_translation (window, src_region, dx, dy);
556
557   gc = _gdk_drawable_get_scratch_gc (window, TRUE);
558   gdk_gc_set_clip_region (gc, dest_region);
559   
560   XCopyArea (GDK_WINDOW_XDISPLAY (window),
561              GDK_WINDOW_XID (window),
562              GDK_WINDOW_XID (window),
563              GDK_GC_XGC (gc),
564              dest_extents.x - dx, dest_extents.y - dy,
565              dest_extents.width, dest_extents.height,
566              dest_extents.x, dest_extents.y);
567
568   /* Unset clip region of cached GC */
569   gdk_gc_set_clip_region (gc, NULL);
570   
571   gdk_region_destroy (src_region);
572   gdk_region_destroy (dest_region);
573 }
574
575 static void
576 reset_backgrounds (GdkWindow *window)
577 {
578   GdkWindowObject *obj = (GdkWindowObject *)window;
579
580   _gdk_x11_window_tmp_reset_bg (window, FALSE);
581   
582   if (obj->parent)
583     _gdk_x11_window_tmp_reset_bg ((GdkWindow *)obj->parent, FALSE);
584 }
585
586 void
587 _gdk_window_move_resize_child (GdkWindow *window,
588                                gint       x,
589                                gint       y,
590                                gint       width,
591                                gint       height)
592 {
593   GdkWindowImplX11 *impl;
594   GdkWindowObject *obj;
595   GdkXPositionInfo new_info;
596   GdkWindowParentPos parent_pos;
597   GList *tmp_list;
598   
599   gint d_xoffset, d_yoffset;
600   gint dx, dy;
601   gboolean is_move;
602   gboolean is_resize;
603
604   GdkRectangle old_pos;
605   
606   g_return_if_fail (window != NULL);
607   g_return_if_fail (GDK_IS_WINDOW (window)); 
608
609   impl = GDK_WINDOW_IMPL_X11 (GDK_WINDOW_OBJECT (window)->impl);
610   obj = GDK_WINDOW_OBJECT (window);
611
612   dx = x - obj->x;
613   dy = y - obj->y;
614   
615   is_move = dx != 0 || dy != 0;
616   is_resize = impl->width != width || impl->height != height;
617
618   if (!is_move && !is_resize)
619     return;
620   
621   old_pos.x = obj->x;
622   old_pos.y = obj->y;
623   old_pos.width = impl->width;
624   old_pos.height = impl->height;
625
626   obj->x = x;
627   obj->y = y;
628   impl->width = width;
629   impl->height = height;
630
631   gdk_window_compute_parent_pos (impl, &parent_pos);
632   gdk_window_compute_position (impl, &parent_pos, &new_info);
633
634   gdk_window_clip_changed (window, &impl->position_info.clip_rect, &new_info.clip_rect);
635
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;
641
642   d_xoffset = new_info.x_offset - impl->position_info.x_offset;
643   d_yoffset = new_info.y_offset - impl->position_info.y_offset;
644   
645   if (d_xoffset != 0 || d_yoffset != 0)
646     {
647       GdkRectangle new_position;
648
649       gdk_window_set_static_gravities (window, TRUE);
650
651       if (d_xoffset < 0 || d_yoffset < 0)
652         gdk_window_queue_translation (window, NULL, MIN (d_xoffset, 0), MIN (d_yoffset, 0));
653
654       compute_intermediate_position (&impl->position_info, &new_info, d_xoffset, d_yoffset,
655                                      &new_position);
656       
657       XMoveResizeWindow (GDK_WINDOW_XDISPLAY (window),
658                          GDK_WINDOW_XID (window),
659                          new_position.x, new_position.y, new_position.width, new_position.height);
660       
661       tmp_list = obj->children;
662       while (tmp_list)
663         {
664           gdk_window_premove (tmp_list->data, &parent_pos);
665           tmp_list = tmp_list->next;
666         }
667
668       XMoveWindow (GDK_WINDOW_XDISPLAY (window),
669                    GDK_WINDOW_XID (window),
670                    new_position.x + dx, new_position.y + dy);
671       
672       if (d_xoffset > 0 || d_yoffset > 0)
673         gdk_window_queue_translation (window, NULL, MAX (d_xoffset, 0), MAX (d_yoffset, 0));
674       
675       XMoveResizeWindow (GDK_WINDOW_XDISPLAY (window),
676                          GDK_WINDOW_XID (window),
677                          new_info.x, new_info.y, new_info.width, new_info.height);
678
679       reset_backgrounds (window);
680
681       if (!impl->position_info.mapped && new_info.mapped && GDK_WINDOW_IS_MAPPED (obj))
682         XMapWindow (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window));
683       
684       impl->position_info = new_info;
685       
686       tmp_list = obj->children;
687       while (tmp_list)
688         {
689           gdk_window_postmove (tmp_list->data, &parent_pos);
690           tmp_list = tmp_list->next;
691         }
692     }
693   else
694     {
695       if (is_move && is_resize)
696         gdk_window_set_static_gravities (window, FALSE);
697
698       if (impl->position_info.mapped && !new_info.mapped)
699         XUnmapWindow (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window));
700       
701       tmp_list = obj->children;
702       while (tmp_list)
703         {
704           gdk_window_premove (tmp_list->data, &parent_pos);
705           tmp_list = tmp_list->next;
706         }
707
708       if (is_resize)
709         XMoveResizeWindow (GDK_WINDOW_XDISPLAY (window),
710                            GDK_WINDOW_XID (window),
711                            new_info.x, new_info.y, new_info.width, new_info.height);
712       else
713         XMoveWindow (GDK_WINDOW_XDISPLAY (window),
714                      GDK_WINDOW_XID (window),
715                      new_info.x, new_info.y);
716
717       tmp_list = obj->children;
718       while (tmp_list)
719         {
720           gdk_window_postmove (tmp_list->data, &parent_pos);
721           tmp_list = tmp_list->next;
722         }
723
724       reset_backgrounds (window);
725       
726       if (!impl->position_info.mapped && new_info.mapped && GDK_WINDOW_IS_MAPPED (obj))
727         XMapWindow (GDK_WINDOW_XDISPLAY (window), GDK_WINDOW_XID (window));
728
729       impl->position_info = new_info;
730     }
731
732   if (GDK_WINDOW_IS_MAPPED (obj) && obj->parent)
733     gdk_window_invalidate_rect ((GdkWindow *)obj->parent, &old_pos, FALSE);
734 }
735
736 static void
737 gdk_window_compute_position (GdkWindowImplX11   *window,
738                              GdkWindowParentPos *parent_pos,
739                              GdkXPositionInfo   *info)
740 {
741   GdkWindowObject *wrapper;
742   int parent_x_offset;
743   int parent_y_offset;
744
745   g_return_if_fail (GDK_IS_WINDOW_IMPL_X11 (window));
746
747   wrapper = GDK_WINDOW_OBJECT (GDK_DRAWABLE_IMPL_X11 (window)->wrapper);
748   
749   info->big = FALSE;
750   
751   if (window->width <= 32767)
752     {
753       info->width = window->width;
754       info->x = parent_pos->x + wrapper->x - parent_pos->x11_x;
755     }
756   else
757     {
758       info->big = TRUE;
759       info->width = 32767;
760       if (parent_pos->x + wrapper->x < -16384)
761         {
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;
764           else
765             info->x = -16384 - parent_pos->x11_x;
766         }
767       else
768         info->x = parent_pos->x + wrapper->x - parent_pos->x11_x;
769     }
770
771   if (window->height <= 32767)
772     {
773       info->height = window->height;
774       info->y = parent_pos->y + wrapper->y - parent_pos->x11_y;
775     }
776   else
777     {
778       info->big = TRUE;
779       info->height = 32767;
780       if (parent_pos->y + wrapper->y < -16384)
781         {
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;
784           else
785             info->y = -16384 - parent_pos->x11_y;
786         }
787       else
788         info->y = parent_pos->y + wrapper->y - parent_pos->x11_y;
789     }
790
791   parent_x_offset = parent_pos->x11_x - parent_pos->x;
792   parent_y_offset = parent_pos->x11_y - parent_pos->y;
793   
794   info->x_offset = parent_x_offset + info->x - wrapper->x;
795   info->y_offset = parent_y_offset + info->y - wrapper->y;
796
797   /* We don't considering the clipping of toplevel windows and their immediate children
798    * by their parents, and simply always map those windows.
799    */
800   if (parent_pos->clip_rect.width == G_MAXINT)
801     info->mapped = TRUE;
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;
808   else
809     info->mapped = TRUE;
810
811   info->no_bg = FALSE;
812
813   if (GDK_WINDOW_TYPE (wrapper) == GDK_WINDOW_CHILD)
814     {
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;
819       
820       gdk_rectangle_intersect (&info->clip_rect, &parent_pos->clip_rect, &info->clip_rect);
821
822       info->clip_rect.x -= wrapper->x;
823       info->clip_rect.y -= wrapper->y;
824     }
825   else
826     {
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;
831     }
832 }
833
834 static void
835 gdk_window_compute_parent_pos (GdkWindowImplX11      *window,
836                                GdkWindowParentPos *parent_pos)
837 {
838   GdkWindowObject *wrapper;
839   GdkWindowObject *parent;
840   GdkRectangle tmp_clip;
841   
842   int clip_xoffset = 0;
843   int clip_yoffset = 0;
844
845   g_return_if_fail (GDK_IS_WINDOW_IMPL_X11 (window));
846
847   wrapper =
848     GDK_WINDOW_OBJECT (GDK_DRAWABLE_IMPL_X11 (window)->wrapper);
849   
850   parent_pos->x = 0;
851   parent_pos->y = 0;
852   parent_pos->x11_x = 0;
853   parent_pos->x11_y = 0;
854
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.
861    *
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.
865    */
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;
870
871   parent = (GdkWindowObject *)wrapper->parent;
872   while (parent && parent->window_type == GDK_WINDOW_CHILD)
873     {
874       GdkWindowImplX11 *impl = GDK_WINDOW_IMPL_X11 (parent->impl);
875       
876       tmp_clip.x = - clip_xoffset;
877       tmp_clip.y = - clip_yoffset;
878       tmp_clip.width = impl->width;
879       tmp_clip.height = impl->height;
880
881       gdk_rectangle_intersect (&parent_pos->clip_rect, &tmp_clip, &parent_pos->clip_rect);
882
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;
887
888       clip_xoffset += parent->x;
889       clip_yoffset += parent->y;
890
891       parent = (GdkWindowObject *)parent->parent;
892     }
893 }
894
895 static void
896 gdk_window_premove (GdkWindow          *window,
897                     GdkWindowParentPos *parent_pos)
898 {
899   GdkWindowImplX11 *impl;
900   GdkWindowObject *obj;
901   GdkXPositionInfo new_info;
902   GList *tmp_list;
903   gint d_xoffset, d_yoffset;
904   GdkWindowParentPos this_pos;
905
906   obj = (GdkWindowObject *) window;
907   impl = GDK_WINDOW_IMPL_X11 (obj->impl);
908   
909   gdk_window_compute_position (impl, parent_pos, &new_info);
910
911   gdk_window_clip_changed (window, &impl->position_info.clip_rect, &new_info.clip_rect);
912
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;
918
919   if (impl->position_info.mapped && !new_info.mapped)
920     XUnmapWindow (GDK_DRAWABLE_XDISPLAY (window), GDK_DRAWABLE_XID (window));
921
922   d_xoffset = new_info.x_offset - impl->position_info.x_offset;
923   d_yoffset = new_info.y_offset - impl->position_info.y_offset;
924   
925   if (d_xoffset != 0 || d_yoffset != 0)
926     {
927       GdkRectangle new_position;
928
929       if (d_xoffset < 0 || d_yoffset < 0)
930         gdk_window_queue_translation (window, NULL, MIN (d_xoffset, 0), MIN (d_yoffset, 0));
931
932       compute_intermediate_position (&impl->position_info, &new_info, d_xoffset, d_yoffset,
933                                      &new_position);
934
935       XMoveResizeWindow (GDK_DRAWABLE_XDISPLAY (window),
936                          GDK_DRAWABLE_XID (window),
937                          new_position.x, new_position.y, new_position.width, new_position.height);
938     }
939
940   tmp_list = obj->children;
941   while (tmp_list)
942     {
943       gdk_window_premove (tmp_list->data, &this_pos);
944       tmp_list = tmp_list->next;
945     }
946 }
947
948 static void
949 gdk_window_postmove (GdkWindow          *window,
950                      GdkWindowParentPos *parent_pos)
951 {
952   GdkWindowImplX11 *impl;
953   GdkWindowObject *obj;
954   GdkXPositionInfo new_info;
955   GList *tmp_list;
956   gint d_xoffset, d_yoffset;
957   GdkWindowParentPos this_pos;
958
959   obj = (GdkWindowObject *) window;
960   impl = GDK_WINDOW_IMPL_X11 (obj->impl);
961   
962   gdk_window_compute_position (impl, parent_pos, &new_info);
963
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;
969
970   d_xoffset = new_info.x_offset - impl->position_info.x_offset;
971   d_yoffset = new_info.y_offset - impl->position_info.y_offset;
972   
973   if (d_xoffset != 0 || d_yoffset != 0)
974     {
975       if (d_xoffset > 0 || d_yoffset > 0)
976         gdk_window_queue_translation (window, NULL, MAX (d_xoffset, 0), MAX (d_yoffset, 0));
977         
978       XMoveResizeWindow (GDK_DRAWABLE_XDISPLAY (window),
979                          GDK_DRAWABLE_XID (window),
980                          new_info.x, new_info.y, new_info.width, new_info.height);
981     }
982
983   if (!impl->position_info.mapped && new_info.mapped && GDK_WINDOW_IS_MAPPED (obj))
984     XMapWindow (GDK_DRAWABLE_XDISPLAY (window), GDK_DRAWABLE_XID (window));
985
986   reset_backgrounds (window);
987
988   impl->position_info = new_info;
989
990   tmp_list = obj->children;
991   while (tmp_list)
992     {
993       gdk_window_postmove (tmp_list->data, &this_pos);
994       tmp_list = tmp_list->next;
995     }
996 }
997
998 static Bool
999 expose_serial_predicate (Display *xdisplay,
1000                          XEvent  *xev,
1001                          XPointer arg)
1002 {
1003   gulong *serial = (gulong *)arg;
1004
1005   if (xev->xany.type == Expose)
1006     *serial = MIN (*serial, xev->xany.serial);
1007
1008   return False;
1009 }
1010
1011 /* Find oldest possible serial for an outstanding expose event
1012  */
1013 static gulong
1014 find_current_serial (Display *xdisplay)
1015 {
1016   XEvent xev;
1017   gulong serial = NextRequest (xdisplay);
1018   
1019   XSync (xdisplay, False);
1020
1021   XCheckIfEvent (xdisplay, &xev, expose_serial_predicate, (XPointer)&serial);
1022
1023   return serial;
1024 }
1025
1026 static void
1027 queue_delete_link (GQueue *queue,
1028                    GList  *link)
1029 {
1030   if (queue->tail == link)
1031     queue->tail = link->prev;
1032   
1033   queue->head = g_list_remove_link (queue->head, link);
1034   g_list_free_1 (link);
1035   queue->length--;
1036 }
1037
1038 static void
1039 queue_item_free (GdkWindowQueueItem *item)
1040 {
1041   if (item->window)
1042     {
1043       g_object_remove_weak_pointer (G_OBJECT (item->window),
1044                                     (gpointer *)&(item->window));
1045     }
1046   
1047   if (item->type == GDK_WINDOW_QUEUE_ANTIEXPOSE)
1048     gdk_region_destroy (item->u.antiexpose.area);
1049   else
1050     {
1051       if (item->u.translate.area)
1052         gdk_region_destroy (item->u.translate.area);
1053     }
1054   
1055   g_free (item);
1056 }
1057
1058 static void
1059 gdk_window_queue (GdkWindow          *window,
1060                   GdkWindowQueueItem *item)
1061 {
1062   GdkDisplayX11 *display_x11 = GDK_DISPLAY_X11 (GDK_WINDOW_DISPLAY (window));
1063   
1064   if (!display_x11->translate_queue)
1065     display_x11->translate_queue = g_queue_new ();
1066
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.
1070    */
1071   if (display_x11->translate_queue->length >= 64)
1072     {
1073       gulong serial = find_current_serial (GDK_WINDOW_XDISPLAY (window));
1074       GList *tmp_list = display_x11->translate_queue->head;
1075       
1076       while (tmp_list)
1077         {
1078           GdkWindowQueueItem *item = tmp_list->data;
1079           GList *next = tmp_list->next;
1080           
1081           if (serial > item->serial)
1082             {
1083               queue_delete_link (display_x11->translate_queue, tmp_list);
1084               queue_item_free (item);
1085             }
1086
1087           tmp_list = next;
1088         }
1089     }
1090
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
1095    * items 
1096    */
1097   if (display_x11->translate_queue->length >= 64)
1098     {
1099       GList *tmp_list = display_x11->translate_queue->head;
1100       
1101       while (tmp_list)
1102         {
1103           GdkWindowQueueItem *item = tmp_list->data;
1104           GList *next = tmp_list->next;
1105           
1106           if (item->type == GDK_WINDOW_QUEUE_ANTIEXPOSE)
1107             {
1108               queue_delete_link (display_x11->translate_queue, tmp_list);
1109               queue_item_free (item);
1110             }
1111
1112           tmp_list = next;
1113         }
1114     }
1115
1116   item->window = window;
1117   item->serial = NextRequest (GDK_WINDOW_XDISPLAY (window));
1118   
1119   g_object_add_weak_pointer (G_OBJECT (window),
1120                              (gpointer *)&(item->window));
1121
1122   g_queue_push_tail (display_x11->translate_queue, item);
1123 }
1124
1125 static void
1126 gdk_window_queue_translation (GdkWindow *window,
1127                               GdkRegion *area,
1128                               gint       dx,
1129                               gint       dy)
1130 {
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;
1136
1137   gdk_window_queue (window, item);
1138 }
1139
1140 gboolean
1141 _gdk_windowing_window_queue_antiexpose (GdkWindow *window,
1142                                         GdkRegion *area)
1143 {
1144   GdkWindowQueueItem *item = g_new (GdkWindowQueueItem, 1);
1145   item->type = GDK_WINDOW_QUEUE_ANTIEXPOSE;
1146   item->u.antiexpose.area = area;
1147
1148   gdk_window_queue (window, item);
1149
1150   return TRUE;
1151 }
1152
1153 void
1154 _gdk_window_process_expose (GdkWindow    *window,
1155                             gulong        serial,
1156                             GdkRectangle *area)
1157 {
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);
1163
1164   if (display_x11->translate_queue)
1165     {
1166       GList *tmp_list = display_x11->translate_queue->head;
1167       
1168       while (tmp_list)
1169         {
1170           GdkWindowQueueItem *item = tmp_list->data;
1171           tmp_list = tmp_list->next;
1172           
1173           if (serial < item->serial)
1174             {
1175               if (item->window == window)
1176                 {
1177                   if (item->type == GDK_WINDOW_QUEUE_TRANSLATE)
1178                     {
1179                       if (item->u.translate.area)
1180                         {
1181                           GdkRegion *intersection;
1182                           
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);
1189                         }
1190                       else
1191                         gdk_region_offset (invalidate_region, item->u.translate.dx, item->u.translate.dy);
1192                     }
1193                   else          /* anti-expose */
1194                     {
1195                       gdk_region_subtract (invalidate_region, item->u.antiexpose.area);
1196                     }
1197                 }
1198             }
1199           else
1200             {
1201               queue_delete_link (display_x11->translate_queue, 
1202                                  display_x11->translate_queue->head);
1203               queue_item_free (item);
1204             }
1205         }
1206     }
1207
1208   clip_region = gdk_region_rectangle (&impl->position_info.clip_rect);
1209   gdk_region_intersect (invalidate_region, clip_region);
1210
1211   if (!gdk_region_empty (invalidate_region))
1212     gdk_window_invalidate_region (window, invalidate_region, FALSE);
1213   
1214   gdk_region_destroy (invalidate_region);
1215   gdk_region_destroy (clip_region);
1216 }
1217
1218 static void
1219 gdk_window_clip_changed (GdkWindow *window, GdkRectangle *old_clip, GdkRectangle *new_clip)
1220 {
1221   GdkWindowImplX11 *impl;
1222   GdkWindowObject *obj;
1223   GdkRegion *old_clip_region;
1224   GdkRegion *new_clip_region;
1225   
1226   if (((GdkWindowObject *)window)->input_only)
1227     return;
1228
1229   obj = (GdkWindowObject *) window;
1230   impl = GDK_WINDOW_IMPL_X11 (obj->impl);
1231   
1232   old_clip_region = gdk_region_rectangle (old_clip);
1233   new_clip_region = gdk_region_rectangle (new_clip);
1234
1235   /* We need to update this here because gdk_window_invalidate_region makes
1236    * use if it (through gdk_drawable_get_visible_region
1237    */
1238   impl->position_info.clip_rect = *new_clip;
1239   
1240   /* Trim invalid region of window to new clip rectangle
1241    */
1242   if (obj->update_area)
1243     gdk_region_intersect (obj->update_area, new_clip_region);
1244
1245   /* Invalidate newly exposed portion of window
1246    */
1247   gdk_region_subtract (new_clip_region, old_clip_region);
1248   if (!gdk_region_empty (new_clip_region))
1249     {
1250       _gdk_x11_window_tmp_unset_bg (window, FALSE);;
1251       gdk_window_invalidate_region (window, new_clip_region, FALSE);
1252     }
1253
1254   if (obj->parent)
1255     _gdk_x11_window_tmp_unset_bg ((GdkWindow *)obj->parent, FALSE);
1256   
1257   gdk_region_destroy (new_clip_region);
1258   gdk_region_destroy (old_clip_region);
1259 }
1260
1261 #define __GDK_GEOMETRY_X11_C__
1262 #include "gdkaliasdef.c"