]> Pileus Git - ~andy/gtk/blob - gdk/win32/gdkgeometry-win32.c
25ce720a6a04b009ded444eea1d198645bed7490
[~andy/gtk] / gdk / win32 / gdkgeometry-win32.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-win32.c: emulation of 32 bit coordinates within the
21  * limits of Win32 GDI. Just a copy of the X11 version, more or less.
22  * Probably totally bogus in functionality. Just a quick hack, to
23  * get the thing to build. Need to write some test code for it.
24  * Well, need to find out what it is supposed to do first ;-)
25  *
26  * The X11 version by Owen Taylor <otaylor@redhat.com>
27  * Copyright Red Hat, Inc. 2000
28  * Win32 hack by Tor Lillqvist <tml@iki.fi>
29  * and Hans Breuer <hans@breuer.org>
30  */
31
32 #include "gdk.h"                /* For gdk_rectangle_intersect */
33 #include "gdkregion.h"
34 #include "gdkregion-generic.h"
35 #include "gdkprivate-win32.h"
36
37 #define SIZE_LIMIT 32000
38
39 typedef struct _GdkWindowQueueItem GdkWindowQueueItem;
40 typedef struct _GdkWindowParentPos GdkWindowParentPos;
41
42 typedef enum {
43   GDK_WINDOW_QUEUE_TRANSLATE,
44   GDK_WINDOW_QUEUE_ANTIEXPOSE
45 } GdkWindowQueueType;
46
47 struct _GdkWindowQueueItem
48 {
49   GdkWindow *window;
50   gulong serial;
51   GdkWindowQueueType type;
52   union {
53     struct {
54       gint dx;
55       gint dy;
56     } translate;
57     struct {
58       GdkRegion *area;
59     } antiexpose;
60   } u;
61 };
62
63 struct _GdkWindowParentPos
64 {
65   gint x;
66   gint y;
67   gint win32_x;
68   gint win32_y;
69   GdkRectangle clip_rect;
70 };
71
72 static void gdk_window_compute_position   (GdkWindowImplWin32          *window,
73                                            GdkWindowParentPos     *parent_pos,
74                                            GdkWin32PositionInfo   *info);
75 static void gdk_window_compute_parent_pos (GdkWindowImplWin32      *window,
76                                            GdkWindowParentPos   *parent_pos);
77 static void gdk_window_premove            (GdkWindow          *window,
78                                            GdkWindowParentPos *parent_pos);
79 static void gdk_window_postmove           (GdkWindow          *window,
80                                            GdkWindowParentPos *parent_pos);
81 static void gdk_window_queue_translation  (GdkWindow          *window,
82                                            gint                dx,
83                                            gint                dy);
84 static void gdk_window_tmp_unset_bg       (GdkWindow          *window);
85 static void gdk_window_tmp_reset_bg       (GdkWindow          *window);
86 static void gdk_window_clip_changed       (GdkWindow          *window,
87                                            GdkRectangle       *old_clip,
88                                            GdkRectangle       *new_clip);
89
90 static GSList *translate_queue = NULL;
91
92 void
93 _gdk_windowing_window_get_offsets (GdkWindow *window,
94                                    gint      *x_offset,
95                                    gint      *y_offset)
96 {
97   GdkWindowImplWin32 *impl =
98     GDK_WINDOW_IMPL_WIN32 (GDK_WINDOW_OBJECT (window)->impl);
99
100   *x_offset = impl->position_info.x_offset;
101   *y_offset = impl->position_info.y_offset;
102 }
103
104 void
105 _gdk_window_init_position (GdkWindow *window)
106 {
107   GdkWindowParentPos parent_pos;
108   GdkWindowImplWin32 *impl;
109   
110   g_return_if_fail (GDK_IS_WINDOW (window));
111   
112   impl = GDK_WINDOW_IMPL_WIN32 (GDK_WINDOW_OBJECT (window)->impl);
113   
114   gdk_window_compute_parent_pos (impl, &parent_pos);
115   gdk_window_compute_position (impl, &parent_pos, &impl->position_info);
116 }
117
118 static void
119 gdk_window_copy_area_scroll (GdkWindow    *window,
120                              GdkRectangle *dest_rect,
121                              gint          dx,
122                              gint          dy)
123 {
124   GdkWindowObject *obj = GDK_WINDOW_OBJECT (window);
125   GList *tmp_list;
126
127   if (dest_rect->width > 0 && dest_rect->height > 0)
128     {
129       RECT clipRect;
130       clipRect.left   = dest_rect->x;
131       clipRect.top    = dest_rect->y;
132       clipRect.right  = clipRect.left + dest_rect->width;
133       clipRect.bottom = clipRect.top + dest_rect->height;
134
135       gdk_window_queue_translation (window, dx, dy);
136
137       if (!ScrollWindowEx (GDK_WINDOW_HWND (window),
138                            dx, dy, /* in: scroll offsets */
139                            NULL, /* in: scroll rect, NULL == entire client area */
140                            &clipRect, /* in: restrict to */
141                            NULL, /* out: update region */
142                            NULL, /* out: update rect */
143                            SW_INVALIDATE))
144         WIN32_API_FAILED ("ScrollWindowEx");
145     }
146
147   tmp_list = obj->children;
148   while (tmp_list)
149     {
150       GdkWindow *child = GDK_WINDOW (tmp_list->data);
151       GdkWindowObject *child_obj = GDK_WINDOW_OBJECT (child);
152           
153       gdk_window_move (child, child_obj->x + dx, child_obj->y + dy);
154       
155       tmp_list = tmp_list->next;
156     }
157 }
158
159 static void
160 compute_intermediate_position (GdkWin32PositionInfo *position_info,
161                                GdkWin32PositionInfo *new_info,
162                                gint              d_xoffset,
163                                gint              d_yoffset,
164                                GdkRectangle     *new_position)
165 {
166   gint new_x0, new_x1, new_y0, new_y1;
167   
168   /* Wrap d_xoffset, d_yoffset into [-32768,32767] range. For the
169    * purposes of subwindow movement, it doesn't matter if we are
170    * off by a factor of 65536, and if we don't do this range
171    * reduction, we'll end up with invalid widths.
172    */
173   d_xoffset = (gint16)d_xoffset;
174   d_yoffset = (gint16)d_yoffset;
175   
176   if (d_xoffset < 0)
177     {
178       new_x0 = position_info->x + d_xoffset;
179       new_x1 = position_info->x + position_info->width;
180     }
181   else
182     {
183       new_x0 = position_info->x;
184       new_x1 = position_info->x + new_info->width + d_xoffset;
185     }
186
187   new_position->x = new_x0;
188   new_position->width = new_x1 - new_x0;
189   
190   if (d_yoffset < 0)
191     {
192       new_y0 = position_info->y + d_yoffset;
193       new_y1 = position_info->y + position_info->height;
194     }
195   else
196     {
197       new_y0 = position_info->y;
198       new_y1 = position_info->y + new_info->height + d_yoffset;
199     }
200   
201   new_position->y = new_y0;
202   new_position->height = new_y1 - new_y0;
203 }
204
205 static void
206 gdk_window_guffaw_scroll (GdkWindow    *window,
207                           gint          dx,
208                           gint          dy)
209 {
210   GdkWindowObject *obj = GDK_WINDOW_OBJECT (window);
211   GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (obj->impl);
212
213   gint d_xoffset = -dx;
214   gint d_yoffset = -dy;
215   GdkRectangle new_position;
216   GdkWin32PositionInfo new_info;
217   GdkWindowParentPos parent_pos;
218   GList *tmp_list;
219   
220   gdk_window_compute_parent_pos (impl, &parent_pos);
221   gdk_window_compute_position (impl, &parent_pos, &new_info);
222
223   parent_pos.x += obj->x;
224   parent_pos.y += obj->y;
225   parent_pos.win32_x += new_info.x;
226   parent_pos.win32_y += new_info.y;
227   parent_pos.clip_rect = new_info.clip_rect;
228
229   gdk_window_tmp_unset_bg (window);
230
231   if (d_xoffset < 0 || d_yoffset < 0)
232     gdk_window_queue_translation (window, MIN (d_xoffset, 0), MIN (d_yoffset, 0));
233         
234   gdk_window_set_static_gravities (window, TRUE);
235
236   compute_intermediate_position (&impl->position_info, &new_info, d_xoffset, d_yoffset,
237                                  &new_position);
238   
239   /* XXX: this is only translating the X11 code. Don't know why the
240    *  window movement needs to be done in three steps there, and here ??
241    */
242   if (!SetWindowPos (GDK_WINDOW_HWND (window), NULL,
243                      new_position.x, new_position.y,
244                        new_position.width, new_position.height,
245                      SWP_NOACTIVATE | SWP_NOZORDER))
246     WIN32_API_FAILED ("SetWindowPos");
247   
248   tmp_list = obj->children;
249   while (tmp_list)
250     {
251       GDK_WINDOW_OBJECT(tmp_list->data)->x -= d_xoffset;
252       GDK_WINDOW_OBJECT(tmp_list->data)->y -= d_yoffset;
253
254       gdk_window_premove (tmp_list->data, &parent_pos);
255       tmp_list = tmp_list->next;
256     }
257   
258   if (!SetWindowPos (GDK_WINDOW_HWND (window), NULL,
259                      new_position.x - d_xoffset, new_position.y - d_yoffset, 1, 1,
260                      SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE))
261     WIN32_API_FAILED ("SetWindowPos");
262
263   if (d_xoffset > 0 || d_yoffset > 0)
264     gdk_window_queue_translation (window, MAX (d_xoffset, 0), MAX (d_yoffset, 0));
265   
266   if (!SetWindowPos (GDK_WINDOW_HWND (window), NULL,
267                      impl->position_info.x, impl->position_info.y,
268                      impl->position_info.width, impl->position_info.height,
269                      SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE))
270     WIN32_API_FAILED ("SetWindowPos");
271   
272   if (impl->position_info.no_bg)
273     gdk_window_tmp_reset_bg (window);
274   
275   impl->position_info = new_info;
276   
277   tmp_list = obj->children;
278   while (tmp_list)
279     {
280       gdk_window_postmove (tmp_list->data, &parent_pos);
281       tmp_list = tmp_list->next;
282     }
283 }
284
285 /**
286  * gdk_window_scroll:
287  * @window: a #GdkWindow
288  * @dx: Amount to scroll in the X direction
289  * @dy: Amount to scroll in the Y direction
290  * 
291  * Scroll the contents of @window, both pixels and children, by the given
292  * amount. @window itself does not move.  Portions of the window that the scroll
293  * operation brings in from offscreen areas are invalidated. The invalidated
294  * region may be bigger than what would strictly be necessary.  (For Win32, a
295  * minimum area will be invalidated if the window has no subwindows, or if the
296  * edges of the window's parent do not extend beyond the edges of the window. In
297  * other cases, a multi-step process is used to scroll the window which may
298  * produce temporary visual artifacts and unnecessary invalidations.)
299  **/
300 void
301 gdk_window_scroll (GdkWindow *window,
302                    gint       dx,
303                    gint       dy)
304 {
305   gboolean can_guffaw_scroll = FALSE;
306   GdkRegion *invalidate_region;
307   GdkWindowImplWin32 *impl;
308   GdkWindowObject *obj;
309   GdkRectangle dest_rect;
310   
311   g_return_if_fail (GDK_IS_WINDOW (window));
312
313   if (GDK_WINDOW_DESTROYED (window))
314     return;
315   
316   obj = GDK_WINDOW_OBJECT (window);
317   impl = GDK_WINDOW_IMPL_WIN32 (obj->impl);  
318
319   if (dx == 0 && dy == 0)
320     return;
321   
322   /* Move the current invalid region */
323   if (obj->update_area)
324     gdk_region_offset (obj->update_area, dx, dy);
325   
326   invalidate_region = gdk_region_rectangle (&impl->position_info.clip_rect);
327   
328   dest_rect = impl->position_info.clip_rect;
329   dest_rect.x += dx;
330   dest_rect.y += dy;
331   gdk_rectangle_intersect (&dest_rect, &impl->position_info.clip_rect, &dest_rect);
332
333   if (dest_rect.width > 0 && dest_rect.height > 0)
334     {
335       GdkRegion *tmp_region;
336
337       tmp_region = gdk_region_rectangle (&dest_rect);
338       gdk_region_subtract (invalidate_region, tmp_region);
339       gdk_region_destroy (tmp_region);
340     }
341   
342   gdk_window_invalidate_region (window, invalidate_region, TRUE);
343   gdk_region_destroy (invalidate_region);
344
345   /* We can guffaw scroll if we are a child window, and the parent
346    * does not extend beyond our edges. Otherwise, we use XCopyArea, then
347    * move any children later
348    */
349   if (GDK_WINDOW_TYPE (window) == GDK_WINDOW_CHILD)
350     {
351       GdkWindowImplWin32 *parent_impl = GDK_WINDOW_IMPL_WIN32 (obj->parent->impl);  
352       can_guffaw_scroll = ((dx == 0 || (obj->x <= 0 && obj->x + impl->width >= parent_impl->width)) &&
353                            (dy == 0 || (obj->y <= 0 && obj->y + impl->height >= parent_impl->height)));
354     }
355
356   if (!obj->children || !can_guffaw_scroll)
357     gdk_window_copy_area_scroll (window, &dest_rect, dx, dy);
358   else
359     gdk_window_guffaw_scroll (window, dx, dy);
360 }
361
362 void
363 _gdk_window_move_resize_child (GdkWindow *window,
364                                gint       x,
365                                gint       y,
366                                gint       width,
367                                gint       height)
368 {
369   GdkWindowImplWin32 *impl;
370   GdkWindowObject *obj;
371   GdkWin32PositionInfo new_info;
372   GdkWindowParentPos parent_pos;
373   GList *tmp_list;
374   gint d_xoffset, d_yoffset;
375   gint dx, dy;
376   gboolean is_move;
377   gboolean is_resize;
378   
379   g_return_if_fail (window != NULL);
380   g_return_if_fail (GDK_IS_WINDOW (window));
381
382   obj = GDK_WINDOW_OBJECT (window);
383   impl = GDK_WINDOW_IMPL_WIN32 (obj->impl);
384   
385   dx = x - obj->x;
386   dy = y - obj->y;
387   
388   is_move = dx != 0 || dy != 0;
389   is_resize = impl->width != width || impl->height != height;
390
391   if (!is_move && !is_resize)
392     return;
393   
394   obj->x = x;
395   obj->y = y;
396   impl->width = width;
397   impl->height = height;
398
399   gdk_window_compute_parent_pos (impl, &parent_pos);
400   gdk_window_compute_position (impl, &parent_pos, &new_info);
401
402   gdk_window_clip_changed (window, &impl->position_info.clip_rect, &new_info.clip_rect);
403
404   parent_pos.x += obj->x;
405   parent_pos.y += obj->y;
406   parent_pos.win32_x += new_info.x;
407   parent_pos.win32_y += new_info.y;
408   parent_pos.clip_rect = new_info.clip_rect;
409
410   d_xoffset = new_info.x_offset - impl->position_info.x_offset;
411   d_yoffset = new_info.y_offset - impl->position_info.y_offset;
412   
413   if (d_xoffset != 0 || d_yoffset != 0)
414     {
415       GdkRectangle new_position;
416
417       gdk_window_set_static_gravities (window, TRUE);
418
419       if (d_xoffset < 0 || d_yoffset < 0)
420         gdk_window_queue_translation (window, MIN (d_xoffset, 0), MIN (d_yoffset, 0));
421
422       compute_intermediate_position (&impl->position_info, &new_info, d_xoffset, d_yoffset,
423                                      &new_position);
424       
425       if (!SetWindowPos (GDK_WINDOW_HWND (window), NULL,
426                          new_position.x, new_position.y, 
427                          new_position.width, new_position.height,
428                          SWP_NOACTIVATE | SWP_NOZORDER))
429         WIN32_API_FAILED ("SetWindowPos");
430         
431       tmp_list = obj->children;
432       while (tmp_list)
433         {
434           gdk_window_premove (tmp_list->data, &parent_pos);
435           tmp_list = tmp_list->next;
436         }
437
438       if (!SetWindowPos (GDK_WINDOW_HWND (window), NULL,
439                          new_position.x + dx, new_position.y + dy, 0, 0,
440                          SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE | SWP_NOREDRAW))
441         WIN32_API_FAILED ("SetWindowPos");
442       
443       if (d_xoffset > 0 || d_yoffset > 0)
444         gdk_window_queue_translation (window, MAX (d_xoffset, 0), MAX (d_yoffset, 0));
445       
446       if (!SetWindowPos (GDK_WINDOW_HWND (window), NULL,
447                          new_info.x, new_info.y, 
448                          new_info.width, new_info.height,
449                          SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOREDRAW))
450         WIN32_API_FAILED ("SetWindowPos");
451       
452       if (impl->position_info.no_bg)
453         gdk_window_tmp_reset_bg (window);
454
455       if (!impl->position_info.mapped && new_info.mapped && GDK_WINDOW_IS_MAPPED (obj))
456         ShowWindow (GDK_WINDOW_HWND (window), SW_SHOWNA);
457       
458       impl->position_info = new_info;
459       
460       tmp_list = obj->children;
461       while (tmp_list)
462         {
463           gdk_window_postmove (tmp_list->data, &parent_pos);
464           tmp_list = tmp_list->next;
465         }
466     }
467   else
468     {
469       if (is_move && is_resize)
470         gdk_window_set_static_gravities (window, FALSE);
471
472       if (impl->position_info.mapped && !new_info.mapped)
473         ShowWindow (GDK_WINDOW_HWND (window), SW_HIDE);
474       
475       tmp_list = obj->children;
476       while (tmp_list)
477         {
478           gdk_window_premove (tmp_list->data, &parent_pos);
479           tmp_list = tmp_list->next;
480         }
481
482       if (!SetWindowPos (GDK_WINDOW_HWND (window), NULL,
483                          new_info.x, new_info.y, 
484                          new_info.width, new_info.height,
485                          SWP_NOACTIVATE | SWP_NOZORDER | 
486                          (is_resize ? 0 : SWP_NOSIZE)))
487         WIN32_API_FAILED ("SetWindowPos");
488
489       tmp_list = obj->children;
490       while (tmp_list)
491         {
492           gdk_window_postmove (tmp_list->data, &parent_pos);
493           tmp_list = tmp_list->next;
494         }
495
496       if (impl->position_info.no_bg)
497         gdk_window_tmp_reset_bg (window);
498
499       if (!impl->position_info.mapped && new_info.mapped && GDK_WINDOW_IS_MAPPED (obj))
500         ShowWindow (GDK_WINDOW_HWND (window), SW_SHOWNA);
501
502       impl->position_info = new_info;
503     }
504 }
505
506 static void
507 gdk_window_compute_position (GdkWindowImplWin32   *window,
508                              GdkWindowParentPos *parent_pos,
509                              GdkWin32PositionInfo   *info)
510 {
511   GdkWindowObject *wrapper;
512   int parent_x_offset;
513   int parent_y_offset;
514
515   g_return_if_fail (GDK_IS_WINDOW_IMPL_WIN32 (window));
516
517   wrapper = GDK_WINDOW_OBJECT (GDK_DRAWABLE_IMPL_WIN32 (window)->wrapper);
518   
519   info->big = FALSE;
520   
521   if (window->width <= SIZE_LIMIT)
522     {
523       info->width = window->width;
524       info->x = parent_pos->x + wrapper->x - parent_pos->win32_x;
525     }
526   else
527     {
528       info->big = TRUE;
529       info->width = SIZE_LIMIT;
530       if (parent_pos->x + wrapper->x < -(SIZE_LIMIT/2))
531         {
532           if (parent_pos->x + wrapper->x + window->width < (SIZE_LIMIT/2))
533             info->x = parent_pos->x + wrapper->x + window->width - SIZE_LIMIT - parent_pos->win32_x;
534           else
535             info->x = -(SIZE_LIMIT/2) - parent_pos->win32_y;
536         }
537       else
538         info->x = parent_pos->x + wrapper->x - parent_pos->win32_x;
539     }
540
541   if (window->height <= SIZE_LIMIT)
542     {
543       info->height = window->height;
544       info->y = parent_pos->y + wrapper->y - parent_pos->win32_y;
545     }
546   else
547     {
548       info->big = TRUE;
549       info->height = SIZE_LIMIT;
550       if (parent_pos->y + wrapper->y < -(SIZE_LIMIT/2))
551         {
552           if (parent_pos->y + wrapper->y + window->height < (SIZE_LIMIT/2))
553             info->y = parent_pos->y + wrapper->y + window->height - SIZE_LIMIT - parent_pos->win32_y;
554           else
555             info->y = -(SIZE_LIMIT/2) - parent_pos->win32_y;
556         }
557       else
558         info->y = parent_pos->y + wrapper->y - parent_pos->win32_y;
559     }
560
561   parent_x_offset = parent_pos->win32_x - parent_pos->x;
562   parent_y_offset = parent_pos->win32_y - parent_pos->y;
563   
564   info->x_offset = parent_x_offset + info->x - wrapper->x;
565   info->y_offset = parent_y_offset + info->y - wrapper->y;
566
567   /* We don't considering the clipping of toplevel windows and their immediate children
568    * by their parents, and simply always map those windows.
569    */
570   if (parent_pos->clip_rect.width == G_MAXINT)
571     info->mapped = TRUE;
572   /* Check if the window would wrap around into the visible space in either direction */
573   else if (info->x + parent_x_offset < parent_pos->clip_rect.x + parent_pos->clip_rect.width - 65536 ||
574       info->x + info->width + parent_x_offset > parent_pos->clip_rect.x + 65536 ||
575       info->y + parent_y_offset < parent_pos->clip_rect.y + parent_pos->clip_rect.height - 65536 ||
576       info->y + info->height + parent_y_offset  > parent_pos->clip_rect.y + 65536)
577     info->mapped = FALSE;
578   else
579     info->mapped = TRUE;
580
581   info->no_bg = FALSE;
582
583   if (GDK_WINDOW_TYPE (wrapper) == GDK_WINDOW_CHILD)
584     {
585       info->clip_rect.x = wrapper->x;
586       info->clip_rect.y = wrapper->y;
587       info->clip_rect.width = window->width;
588       info->clip_rect.height = window->height;
589       
590       gdk_rectangle_intersect (&info->clip_rect, &parent_pos->clip_rect, &info->clip_rect);
591
592       info->clip_rect.x -= wrapper->x;
593       info->clip_rect.y -= wrapper->y;
594     }
595   else
596     {
597       info->clip_rect.x = 0;
598       info->clip_rect.y = 0;
599       info->clip_rect.width = G_MAXINT;
600       info->clip_rect.height = G_MAXINT;
601     }
602 }
603
604 static void
605 gdk_window_compute_parent_pos (GdkWindowImplWin32      *window,
606                                GdkWindowParentPos *parent_pos)
607 {
608   GdkWindowObject *wrapper;
609   GdkWindowObject *parent;
610   GdkRectangle tmp_clip;
611   
612   int clip_xoffset = 0;
613   int clip_yoffset = 0;
614
615   g_return_if_fail (GDK_IS_WINDOW_IMPL_WIN32 (window));
616
617   wrapper = GDK_WINDOW_OBJECT (GDK_DRAWABLE_IMPL_WIN32 (window)->wrapper);
618   
619   parent_pos->x = 0;
620   parent_pos->y = 0;
621   parent_pos->win32_x = 0;
622   parent_pos->win32_y = 0;
623
624   /* We take a simple approach here and simply consider toplevel
625    * windows not to clip their children on the right/bottom, since the
626    * size of toplevel windows is not directly under our
627    * control. Clipping only really matters when scrolling and
628    * generally we aren't going to be moving the immediate child of a
629    * toplevel beyond the bounds of that toplevel.
630    *
631    * We could go ahead and recompute the clips of toplevel windows and
632    * their descendents when we receive size notification, but it would
633    * probably not be an improvement in most cases.
634    */
635   parent_pos->clip_rect.x = 0;
636   parent_pos->clip_rect.y = 0;
637   parent_pos->clip_rect.width = G_MAXINT;
638   parent_pos->clip_rect.height = G_MAXINT;
639
640   parent = (GdkWindowObject *)wrapper->parent;
641   while (parent && parent->window_type == GDK_WINDOW_CHILD)
642     {
643       GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (parent->impl);
644       
645       tmp_clip.x = - clip_xoffset;
646       tmp_clip.y = - clip_yoffset;
647       tmp_clip.width = impl->width;
648       tmp_clip.height = impl->height;
649
650       gdk_rectangle_intersect (&parent_pos->clip_rect, &tmp_clip, &parent_pos->clip_rect);
651
652       parent_pos->x += parent->x;
653       parent_pos->y += parent->y;
654       parent_pos->win32_x += impl->position_info.x;
655       parent_pos->win32_y += impl->position_info.y;
656
657       clip_xoffset += parent->x;
658       clip_yoffset += parent->y;
659
660       parent = (GdkWindowObject *)parent->parent;
661     }
662 }
663
664 static void
665 gdk_window_premove (GdkWindow          *window,
666                     GdkWindowParentPos *parent_pos)
667 {
668   GdkWindowImplWin32 *impl;
669   GdkWindowObject *obj;
670   GdkWin32PositionInfo new_info;
671   GList *tmp_list;
672   gint d_xoffset, d_yoffset;
673   GdkWindowParentPos this_pos;
674
675   obj = (GdkWindowObject *) window;
676   impl = GDK_WINDOW_IMPL_WIN32 (obj->impl);
677   
678   gdk_window_compute_position (impl, parent_pos, &new_info);
679
680   gdk_window_clip_changed (window, &impl->position_info.clip_rect, &new_info.clip_rect);
681
682   this_pos.x = parent_pos->x + obj->x;
683   this_pos.y = parent_pos->y + obj->y;
684   this_pos.win32_x = parent_pos->win32_x + new_info.x;
685   this_pos.win32_y = parent_pos->win32_y + new_info.y;
686   this_pos.clip_rect = new_info.clip_rect;
687
688   if (impl->position_info.mapped && !new_info.mapped)
689     ShowWindow (GDK_WINDOW_HWND (window), SW_HIDE);
690
691   d_xoffset = new_info.x_offset - impl->position_info.x_offset;
692   d_yoffset = new_info.y_offset - impl->position_info.y_offset;
693   
694   if (d_xoffset != 0 || d_yoffset != 0)
695     {
696       GdkRectangle new_position;
697
698       if (d_xoffset < 0 || d_yoffset < 0)
699         gdk_window_queue_translation (window, MIN (d_xoffset, 0), MIN (d_yoffset, 0));
700
701       compute_intermediate_position (&impl->position_info, &new_info, d_xoffset, d_yoffset,
702                                      &new_position);
703
704       if (!SetWindowPos (GDK_WINDOW_HWND (window), NULL,
705                          new_position.x, new_position.y, 
706                          new_position.width, new_position.height,
707                        SWP_NOREDRAW | SWP_NOZORDER | SWP_NOACTIVATE))
708         WIN32_API_FAILED ("SetWindowPos");
709     }
710
711   tmp_list = obj->children;
712   while (tmp_list)
713     {
714       gdk_window_premove (tmp_list->data, &this_pos);
715       tmp_list = tmp_list->next;
716     }
717 }
718
719 static void
720 gdk_window_postmove (GdkWindow          *window,
721                      GdkWindowParentPos *parent_pos)
722 {
723   GdkWindowImplWin32 *impl;
724   GdkWindowObject *obj;
725   GdkWin32PositionInfo new_info;
726   GList *tmp_list;
727   gint d_xoffset, d_yoffset;
728   GdkWindowParentPos this_pos;
729
730   obj = (GdkWindowObject *) window;
731   impl = GDK_WINDOW_IMPL_WIN32 (obj->impl);
732   
733   gdk_window_compute_position (impl, parent_pos, &new_info);
734
735   this_pos.x = parent_pos->x + obj->x;
736   this_pos.y = parent_pos->y + obj->y;
737   this_pos.win32_x = parent_pos->win32_x + new_info.x;
738   this_pos.win32_y = parent_pos->win32_y + new_info.y;
739   this_pos.clip_rect = new_info.clip_rect;
740
741   d_xoffset = new_info.x_offset - impl->position_info.x_offset;
742   d_yoffset = new_info.y_offset - impl->position_info.y_offset;
743   
744   if (d_xoffset != 0 || d_yoffset != 0)
745     {
746       if (d_xoffset > 0 || d_yoffset > 0)
747         gdk_window_queue_translation (window, MAX (d_xoffset, 0), MAX (d_yoffset, 0));
748         
749       if (!SetWindowPos (GDK_WINDOW_HWND (window), NULL,
750                          new_info.x, new_info.y, 
751                          new_info.width, new_info.height,
752                          SWP_NOREDRAW | SWP_NOZORDER | SWP_NOACTIVATE))
753         WIN32_API_FAILED ("SetWindowPos");
754     }
755
756   if (!impl->position_info.mapped && new_info.mapped && GDK_WINDOW_IS_MAPPED (obj))
757     ShowWindow (GDK_WINDOW_HWND (window), SW_SHOWNA);
758
759   if (impl->position_info.no_bg)
760     gdk_window_tmp_reset_bg (window);
761
762   impl->position_info = new_info;
763
764   tmp_list = obj->children;
765   while (tmp_list)
766     {
767       gdk_window_postmove (tmp_list->data, &this_pos);
768       tmp_list = tmp_list->next;
769     }
770 }
771
772 static void
773 gdk_window_queue_translation (GdkWindow *window,
774                               gint       dx,
775                               gint       dy)
776 {
777   GdkWindowQueueItem *item = g_new (GdkWindowQueueItem, 1);
778   item->window = window;
779   item->serial = GetMessageTime ();
780   item->type = GDK_WINDOW_QUEUE_TRANSLATE;
781   item->u.translate.dx = dx;
782   item->u.translate.dy = dy;
783
784   GDK_NOTE (EVENTS, g_print ("gdk_window_queue_translation %#x %ld %d,%d\n",
785                              (guint) GDK_WINDOW_HWND (window),
786                              item->serial,
787                              dx, dy));
788
789   gdk_drawable_ref (window);
790   translate_queue = g_slist_append (translate_queue, item);
791 }
792
793 gboolean
794 _gdk_windowing_window_queue_antiexpose (GdkWindow *window,
795                                         GdkRegion *area)
796 {
797 #if 1
798   GdkWindowQueueItem *item = g_new (GdkWindowQueueItem, 1);
799
800   item->window = window;
801   item->serial = GetMessageTime ();
802   item->type = GDK_WINDOW_QUEUE_ANTIEXPOSE;
803   item->u.antiexpose.area = area;
804
805   GDK_NOTE (EVENTS, g_print ("_gdk_windowing_window_queue_antiexpose %#x %ld %dx%d@+%d+%d\n",
806                              (guint) GDK_WINDOW_HWND (window),
807                              item->serial,
808                              area->extents.x2 - area->extents.x1,
809                              area->extents.y2 - area->extents.y1,
810                              area->extents.x1, area->extents.y1));
811
812   gdk_drawable_ref (window);
813   translate_queue = g_slist_append (translate_queue, item);
814
815   return TRUE;
816 #else
817   GdkRectangle r;
818   HRGN hrgn;
819
820   gdk_region_get_clipbox (area, &r);
821   hrgn = CreateRectRgn(r.x, r.y, r.width+1, r.height+1);
822
823   g_return_val_if_fail (area != NULL, FALSE);
824
825   GDK_NOTE (MISC, g_print ("_gdk_windowing_window_queue_antiexpose %#x\n",
826                            (guint) GDK_WINDOW_HWND (window)));
827
828   /* HB: not quite sure if this is the right thing to do.
829    * (Region not to be proceesed by next WM_PAINT)
830    */
831   ValidateRgn(GDK_WINDOW_HWND (window), hrgn);
832   DeleteObject(hrgn);
833   return TRUE;
834 #endif
835 }
836
837 void
838 _gdk_window_process_expose (GdkWindow    *window,
839                             gulong        serial,
840                             GdkRectangle *area)
841 {
842   GdkWindowImplWin32 *impl;
843   GdkRegion *invalidate_region = gdk_region_rectangle (area);
844   GdkRegion *clip_region;
845   GSList *tmp_list = translate_queue;
846   
847   impl = GDK_WINDOW_IMPL_WIN32 (GDK_WINDOW_OBJECT (window)->impl);
848   
849   GDK_NOTE (EVENTS, g_print ("_gdk_window_process_expose %#x %ld %dx%d@+%d+%d\n",
850                              (guint) GDK_WINDOW_HWND (window), serial,
851                              area->width, area->height, area->x, area->y));
852   
853   while (tmp_list)
854     {
855       GdkWindowQueueItem *item = tmp_list->data;
856       tmp_list = tmp_list->next;
857
858       if (serial < item->serial)
859         {
860           if (item->window == window)
861             {
862               if (item->type == GDK_WINDOW_QUEUE_TRANSLATE)
863                 gdk_region_offset (invalidate_region, - item->u.translate.dx, - item->u.translate.dy);
864               else              /* anti-expose */
865                 gdk_region_subtract (invalidate_region, item->u.antiexpose.area);
866             }
867         }
868       else
869         {
870           GSList *tmp_link = translate_queue;
871           
872           translate_queue = g_slist_remove_link (translate_queue, translate_queue);
873           gdk_drawable_unref (item->window);
874
875           if (item->type == GDK_WINDOW_QUEUE_ANTIEXPOSE)
876             gdk_region_destroy (item->u.antiexpose.area);
877           
878           g_free (item);
879           g_slist_free_1 (tmp_link);
880         }
881     }
882
883   clip_region = gdk_region_rectangle (&impl->position_info.clip_rect);
884   gdk_region_intersect (invalidate_region, clip_region);
885
886   if (!gdk_region_empty (invalidate_region))
887     gdk_window_invalidate_region (window, invalidate_region, FALSE);
888   
889   gdk_region_destroy (invalidate_region);
890   gdk_region_destroy (clip_region);
891 }
892
893 static void
894 gdk_window_tmp_unset_bg (GdkWindow *window)
895 {
896   GdkWindowImplWin32 *impl;
897   GdkWindowObject *obj;
898
899   obj = (GdkWindowObject *) window;
900   impl = GDK_WINDOW_IMPL_WIN32 (obj->impl);
901
902   impl->position_info.no_bg = TRUE;
903
904   /*
905    * The X version sets background = None to avoid updateing for a moment.
906    * Not sure if this could really emulate it.
907    */
908   if (obj->bg_pixmap != GDK_NO_BG)
909     /* handled in WM_ERASEBKGRND proceesing */;
910 }
911
912 static void
913 gdk_window_tmp_reset_bg (GdkWindow *window)
914 {
915   GdkWindowImplWin32 *impl;
916   GdkWindowObject *obj;
917
918   obj = (GdkWindowObject *) window;
919   impl = GDK_WINDOW_IMPL_WIN32 (obj->impl);
920
921   impl->position_info.no_bg = FALSE;
922
923   if (obj->bg_pixmap == GDK_NO_BG)
924     return;
925   
926   if (obj->bg_pixmap)
927     {
928       /* ??? */
929     }
930   else
931     {
932       /* ??? */
933     }
934 }
935
936 static void
937 gdk_window_clip_changed (GdkWindow *window, GdkRectangle *old_clip, GdkRectangle *new_clip)
938 {
939   GdkWindowImplWin32 *impl;
940   GdkWindowObject *obj;
941   GdkRegion *old_clip_region;
942   GdkRegion *new_clip_region;
943   
944   if (((GdkWindowObject *)window)->input_only)
945     return;
946
947   obj = (GdkWindowObject *) window;
948   impl = GDK_WINDOW_IMPL_WIN32 (obj->impl);
949   
950   old_clip_region = gdk_region_rectangle (old_clip);
951   new_clip_region = gdk_region_rectangle (new_clip);
952
953   /* We need to update this here because gdk_window_invalidate_region makes
954    * use if it (through gdk_drawable_get_visible_region
955    */
956   impl->position_info.clip_rect = *new_clip;
957   
958   /* Trim invalid region of window to new clip rectangle
959    */
960   if (obj->update_area)
961     gdk_region_intersect (obj->update_area, new_clip_region);
962
963   /* Invalidate newly exposed portion of window
964    */
965   gdk_region_subtract (new_clip_region, old_clip_region);
966   if (!gdk_region_empty (new_clip_region))
967     {
968       gdk_window_tmp_unset_bg (window);
969       gdk_window_invalidate_region (window, new_clip_region, FALSE);
970     }
971
972   gdk_region_destroy (new_clip_region);
973   gdk_region_destroy (old_clip_region);
974 }