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