Release 950319
[wine] / windows / winpos.c
1 /*
2  * Window position related functions.
3  *
4  * Copyright 1993, 1994, 1995 Alexandre Julliard
5  */
6
7 #include "sysmetrics.h"
8 #include "user.h"
9 #include "win.h"
10 #include "message.h"
11 #include "winpos.h"
12 #include "nonclient.h"
13 #include "stddebug.h"
14 /* #define DEBUG_WIN */
15 #include "debug.h"
16
17 static HWND hwndActive = 0;  /* Currently active window */
18
19
20 /***********************************************************************
21  *           WINPOS_FindIconPos
22  *
23  * Find a suitable place for an iconic window.
24  * The new position is stored into wndPtr->ptIconPos.
25  */
26 static void WINPOS_FindIconPos( HWND hwnd )
27 {
28     RECT rectParent;
29     short x, y, xspacing, yspacing;
30     WND * wndPtr = WIN_FindWndPtr( hwnd );
31
32     if (!wndPtr) return;
33     GetClientRect( wndPtr->hwndParent, &rectParent );
34     if ((wndPtr->ptIconPos.x >= rectParent.left) &&
35         (wndPtr->ptIconPos.x + SYSMETRICS_CXICON < rectParent.right) &&
36         (wndPtr->ptIconPos.y >= rectParent.top) &&
37         (wndPtr->ptIconPos.y + SYSMETRICS_CYICON < rectParent.bottom))
38         return;  /* The icon already has a suitable position */
39
40     xspacing = yspacing = 70;  /* FIXME: This should come from WIN.INI */
41     y = rectParent.bottom;
42     for (;;)
43     {
44         for (x = rectParent.left; x<=rectParent.right-xspacing; x += xspacing)
45         {
46               /* Check if another icon already occupies this spot */
47             HWND hwndChild = GetWindow( wndPtr->hwndParent, GW_CHILD );
48             while (hwndChild)
49             {
50                 WND *childPtr = WIN_FindWndPtr( hwndChild );
51                 if ((childPtr->dwStyle & WS_MINIMIZE) && (hwndChild != hwnd))
52                 {
53                     if ((childPtr->rectWindow.left < x + xspacing) &&
54                         (childPtr->rectWindow.right >= x) &&
55                         (childPtr->rectWindow.top <= y) &&
56                         (childPtr->rectWindow.bottom > y - yspacing))
57                         break;  /* There's a window in there */
58                 }
59                 
60                 hwndChild = childPtr->hwndNext;
61             }
62             if (!hwndChild)
63             {
64                   /* No window was found, so it's OK for us */
65                 wndPtr->ptIconPos.x = x + (xspacing - SYSMETRICS_CXICON) / 2;
66                 wndPtr->ptIconPos.y = y - (yspacing + SYSMETRICS_CYICON) / 2;
67                 return;
68             }
69         }
70         y -= yspacing;
71     }
72 }
73
74
75 /***********************************************************************
76  *           ArrangeIconicWindows   (USER.170)
77  */
78 WORD ArrangeIconicWindows( HWND parent )
79 {
80     RECT rectParent;
81     HWND hwndChild;
82     short x, y, xspacing, yspacing;
83
84     GetClientRect( parent, &rectParent );
85     x = rectParent.left;
86     y = rectParent.bottom;
87     xspacing = yspacing = 70;  /* FIXME: This should come from WIN.INI */
88     hwndChild = GetWindow( parent, GW_CHILD );
89     while (hwndChild)
90     {
91         if (IsIconic( hwndChild ))
92         {
93             SetWindowPos( hwndChild, 0, x + (xspacing - SYSMETRICS_CXICON) / 2,
94                           y - (yspacing + SYSMETRICS_CYICON) / 2, 0, 0,
95                           SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE );
96             if (x <= rectParent.right - xspacing) x += xspacing;
97             else
98             {
99                 x = rectParent.left;
100                 y -= yspacing;
101             }
102         }
103         hwndChild = GetWindow( hwndChild, GW_HWNDNEXT );
104     }
105     return yspacing;
106 }
107
108
109 /***********************************************************************
110  *           GetWindowRect   (USER.32)
111  */
112 void GetWindowRect( HWND hwnd, LPRECT rect ) 
113 {
114     WND * wndPtr = WIN_FindWndPtr( hwnd ); 
115     if (!wndPtr) return;
116     
117     *rect = wndPtr->rectWindow;
118     if (wndPtr->dwStyle & WS_CHILD)
119         MapWindowPoints( wndPtr->hwndParent, 0, (POINT *)rect, 2 );
120 }
121
122
123 /***********************************************************************
124  *           GetClientRect   (USER.33)
125  */
126 void GetClientRect( HWND hwnd, LPRECT rect ) 
127 {
128     WND * wndPtr = WIN_FindWndPtr( hwnd );
129
130     rect->left = rect->top = rect->right = rect->bottom = 0;
131     if (wndPtr) 
132     {
133         rect->right  = wndPtr->rectClient.right - wndPtr->rectClient.left;
134         rect->bottom = wndPtr->rectClient.bottom - wndPtr->rectClient.top;
135     }
136 }
137
138
139 /*******************************************************************
140  *         ClientToScreen   (USER.28)
141  */
142 void ClientToScreen( HWND hwnd, LPPOINT lppnt )
143 {
144     MapWindowPoints( hwnd, 0, lppnt, 1 );
145 }
146
147
148 /*******************************************************************
149  *         ScreenToClient   (USER.29)
150  */
151 void ScreenToClient( HWND hwnd, LPPOINT lppnt )
152 {
153     MapWindowPoints( 0, hwnd, lppnt, 1 );
154 }
155
156
157 /*******************************************************************
158  *         WindowFromPoint   (USER.30)
159  */
160 HWND WindowFromPoint( POINT pt )
161 {
162     HWND hwndRet = 0;
163     HWND hwnd = GetDesktopWindow();
164
165     while(hwnd)
166     {
167           /* If point is in window, and window is visible,   */
168           /* not disabled and not transparent, then explore  */
169           /* its children. Otherwise, go to the next window. */
170
171         WND *wndPtr = WIN_FindWndPtr( hwnd );
172         if ((pt.x >= wndPtr->rectWindow.left) &&
173             (pt.x < wndPtr->rectWindow.right) &&
174             (pt.y >= wndPtr->rectWindow.top) &&
175             (pt.y < wndPtr->rectWindow.bottom) &&
176             !(wndPtr->dwStyle & WS_DISABLED) &&
177             (wndPtr->dwStyle & WS_VISIBLE) &&
178             !(wndPtr->dwExStyle & WS_EX_TRANSPARENT))
179         {
180             hwndRet = hwnd;
181               /* If window is minimized, ignore its children */
182             if (wndPtr->dwStyle & WS_MINIMIZE) break;
183             pt.x -= wndPtr->rectClient.left;
184             pt.y -= wndPtr->rectClient.top;
185             hwnd = wndPtr->hwndChild;
186         }
187         else hwnd = wndPtr->hwndNext;
188     }
189     return hwndRet;
190 }
191
192
193 /*******************************************************************
194  *         ChildWindowFromPoint   (USER.191)
195  */
196 HWND ChildWindowFromPoint( HWND hwndParent, POINT pt )
197 {
198     RECT rect;
199     HWND hwnd;
200     
201     GetWindowRect( hwndParent, &rect );
202     if (!PtInRect( &rect, pt )) return 0;
203     hwnd = GetTopWindow( hwndParent );
204     while (hwnd)
205     {
206         GetWindowRect( hwnd, &rect );
207         if (PtInRect( &rect, pt )) return hwnd;
208         hwnd = GetWindow( hwnd, GW_HWNDNEXT );
209     }
210     return hwndParent;
211 }
212
213
214 /*******************************************************************
215  *         MapWindowPoints   (USER.258)
216  */
217 void MapWindowPoints( HWND hwndFrom, HWND hwndTo, LPPOINT lppt, WORD count )
218 {
219     WND * wndPtr;
220     POINT * curpt;
221     POINT origin = { 0, 0 };
222     WORD i;
223
224       /* Translate source window origin to screen coords */
225     while(hwndFrom)
226     {
227         wndPtr = WIN_FindWndPtr( hwndFrom );
228         origin.x += wndPtr->rectClient.left;
229         origin.y += wndPtr->rectClient.top;
230         hwndFrom = (wndPtr->dwStyle & WS_CHILD) ? wndPtr->hwndParent : 0;
231     }
232
233       /* Translate origin to destination window coords */
234     while(hwndTo)
235     {
236         wndPtr = WIN_FindWndPtr( hwndTo );
237         origin.x -= wndPtr->rectClient.left;
238         origin.y -= wndPtr->rectClient.top;
239         hwndTo = (wndPtr->dwStyle & WS_CHILD) ? wndPtr->hwndParent : 0;
240     }    
241
242       /* Translate points */
243     for (i = 0, curpt = lppt; i < count; i++, curpt++)
244     {
245         curpt->x += origin.x;
246         curpt->y += origin.y;
247     }
248 }
249
250
251 /***********************************************************************
252  *           IsIconic   (USER.31)
253  */
254 BOOL IsIconic(HWND hWnd)
255 {
256     WND * wndPtr = WIN_FindWndPtr(hWnd);
257     if (wndPtr == NULL) return FALSE;
258     return (wndPtr->dwStyle & WS_MINIMIZE) != 0;
259 }
260  
261  
262 /***********************************************************************
263  *           IsZoomed   (USER.272)
264  */
265 BOOL IsZoomed(HWND hWnd)
266 {
267     WND * wndPtr = WIN_FindWndPtr(hWnd);
268     if (wndPtr == NULL) return FALSE;
269     return (wndPtr->dwStyle & WS_MAXIMIZE) != 0;
270 }
271
272
273 /*******************************************************************
274  *         GetActiveWindow    (USER.60)
275  */
276 HWND GetActiveWindow()
277 {
278     return hwndActive;
279 }
280
281
282 /*******************************************************************
283  *         SetActiveWindow    (USER.59)
284  */
285 HWND SetActiveWindow( HWND hwnd )
286 {
287     HWND prev = hwndActive;
288     WND *wndPtr = WIN_FindWndPtr( hwnd );
289     if (!wndPtr || (wndPtr->dwStyle & WS_CHILD)) return 0;
290     SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE );
291     return prev;
292 }
293
294
295 /***********************************************************************
296  *           BringWindowToTop   (USER.45)
297  */
298 BOOL BringWindowToTop( HWND hwnd )
299 {
300     return SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE );
301 }
302
303
304 /***********************************************************************
305  *           MoveWindow   (USER.56)
306  */
307 BOOL MoveWindow( HWND hwnd, short x, short y, short cx, short cy, BOOL repaint)
308 {    
309     int flags = SWP_NOZORDER | SWP_NOACTIVATE;
310     if (!repaint) flags |= SWP_NOREDRAW;
311     dprintf_win(stddeb, "MoveWindow: %d %d,%d %dx%d %d\n", 
312             hwnd, x, y, cx, cy, repaint );
313     return SetWindowPos( hwnd, 0, x, y, cx, cy, flags );
314 }
315
316
317 /***********************************************************************
318  *           ShowWindow   (USER.42)
319  */
320 BOOL ShowWindow( HWND hwnd, int cmd ) 
321 {    
322     WND * wndPtr = WIN_FindWndPtr( hwnd );
323     BOOL wasVisible;
324     POINT maxSize;
325     int swpflags = 0;
326     short x = 0, y = 0, cx = 0, cy = 0;
327
328     if (!wndPtr) return FALSE;
329
330     dprintf_win(stddeb,"ShowWindow: hwnd=%04X, cmd=%d\n", hwnd, cmd);
331
332     wasVisible = (wndPtr->dwStyle & WS_VISIBLE) != 0;
333
334     switch(cmd)
335     {
336         case SW_HIDE:
337             swpflags |= SWP_HIDEWINDOW | SWP_NOSIZE | SWP_NOMOVE | 
338                         SWP_NOACTIVATE | SWP_NOZORDER;
339             break;
340
341         case SW_SHOWMINNOACTIVE:
342             swpflags |= SWP_NOACTIVATE | SWP_NOZORDER;
343             /* fall through */
344         case SW_SHOWMINIMIZED:
345             swpflags |= SWP_SHOWWINDOW;
346             /* fall through */
347         case SW_MINIMIZE:
348             swpflags |= SWP_FRAMECHANGED;
349             if (!(wndPtr->dwStyle & WS_MINIMIZE))
350             {
351                 if (wndPtr->dwStyle & WS_MAXIMIZE)
352                 {
353                     wndPtr->flags |= WIN_RESTORE_MAX;
354                     wndPtr->dwStyle &= ~WS_MAXIMIZE;
355                 }
356                 else
357                 {
358                     wndPtr->flags &= ~WIN_RESTORE_MAX;
359                     wndPtr->rectNormal = wndPtr->rectWindow;
360                 }
361                 wndPtr->dwStyle |= WS_MINIMIZE;
362                 WINPOS_FindIconPos( hwnd );
363                 x  = wndPtr->ptIconPos.x;
364                 y  = wndPtr->ptIconPos.y;
365                 cx = SYSMETRICS_CXICON;
366                 cy = SYSMETRICS_CYICON;
367             }
368             else swpflags |= SWP_NOSIZE | SWP_NOMOVE;
369             break;
370
371         case SW_SHOWMAXIMIZED: /* same as SW_MAXIMIZE: */
372             swpflags |= SWP_SHOWWINDOW | SWP_FRAMECHANGED;
373             if (!(wndPtr->dwStyle & WS_MAXIMIZE))
374             {
375                   /* Store the current position and find the maximized size */
376                 if (!(wndPtr->dwStyle & WS_MINIMIZE))
377                     wndPtr->rectNormal = wndPtr->rectWindow; 
378                 NC_GetMinMaxInfo( hwnd, &maxSize,
379                                   &wndPtr->ptMaxPos, NULL, NULL );
380                 x  = wndPtr->ptMaxPos.x;
381                 y  = wndPtr->ptMaxPos.y;
382                 cx = maxSize.x;
383                 cy = maxSize.y;
384                 wndPtr->dwStyle &= ~WS_MINIMIZE;
385                 wndPtr->dwStyle |= WS_MAXIMIZE;
386             }
387             else swpflags |= SWP_NOSIZE | SWP_NOMOVE;
388             break;
389
390         case SW_SHOWNA:
391             swpflags |= SWP_NOACTIVATE | SWP_NOZORDER;
392             /* fall through */
393         case SW_SHOW:
394             swpflags |= SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE;
395             break;
396
397         case SW_SHOWNOACTIVATE:
398             swpflags |= SWP_NOZORDER;
399             if (GetActiveWindow()) swpflags |= SWP_NOACTIVATE;
400             /* fall through */
401         case SW_SHOWNORMAL:  /* same as SW_NORMAL: */
402         case SW_RESTORE:
403             swpflags |= SWP_SHOWWINDOW | SWP_FRAMECHANGED;
404             if (wndPtr->dwStyle & WS_MINIMIZE)
405             {
406                 wndPtr->ptIconPos.x = wndPtr->rectWindow.left;
407                 wndPtr->ptIconPos.y = wndPtr->rectWindow.top;
408                 wndPtr->dwStyle &= ~WS_MINIMIZE;
409                 if (wndPtr->flags & WIN_RESTORE_MAX)
410                 {
411                     /* Restore to maximized position */
412                     NC_GetMinMaxInfo( hwnd, &maxSize, &wndPtr->ptMaxPos,
413                                       NULL, NULL );
414                     x  = wndPtr->ptMaxPos.x;
415                     y  = wndPtr->ptMaxPos.y;
416                     cx = maxSize.x;
417                     cy = maxSize.y;
418                    wndPtr->dwStyle |= WS_MAXIMIZE;
419                 }
420                 else  /* Restore to normal position */
421                 {
422                     x  = wndPtr->rectNormal.left;
423                     y  = wndPtr->rectNormal.top;
424                     cx = wndPtr->rectNormal.right - wndPtr->rectNormal.left;
425                     cy = wndPtr->rectNormal.bottom - wndPtr->rectNormal.top;
426                 }
427             }
428             else if (wndPtr->dwStyle & WS_MAXIMIZE)
429             {
430                 wndPtr->ptMaxPos.x = wndPtr->rectWindow.left;
431                 wndPtr->ptMaxPos.y = wndPtr->rectWindow.top;
432                 wndPtr->dwStyle &= ~WS_MAXIMIZE;
433                 x  = wndPtr->rectNormal.left;
434                 y  = wndPtr->rectNormal.top;
435                 cx = wndPtr->rectNormal.right - wndPtr->rectNormal.left;
436                 cy = wndPtr->rectNormal.bottom - wndPtr->rectNormal.top;
437             }
438             else swpflags |= SWP_NOSIZE | SWP_NOMOVE;
439             break;
440     }
441
442     SendMessage( hwnd, WM_SHOWWINDOW, (cmd != SW_HIDE), 0 );
443     SetWindowPos( hwnd, HWND_TOP, x, y, cx, cy, swpflags );
444
445       /* Send WM_SIZE and WM_MOVE messages if not already done */
446     if (!(wndPtr->flags & WIN_GOT_SIZEMSG))
447     {
448         int wParam = SIZE_RESTORED;
449         if (wndPtr->dwStyle & WS_MAXIMIZE) wParam = SIZE_MAXIMIZED;
450         else if (wndPtr->dwStyle & WS_MINIMIZE) wParam = SIZE_MINIMIZED;
451         wndPtr->flags |= WIN_GOT_SIZEMSG;
452         SendMessage( hwnd, WM_SIZE, wParam,
453                      MAKELONG(wndPtr->rectClient.right-wndPtr->rectClient.left,
454                             wndPtr->rectClient.bottom-wndPtr->rectClient.top));
455         SendMessage( hwnd, WM_MOVE, 0,
456                    MAKELONG(wndPtr->rectClient.left, wndPtr->rectClient.top) );
457     }
458
459     return wasVisible;
460 }
461
462
463 /***********************************************************************
464  *           GetInternalWindowPos   (USER.460)
465  */
466 WORD GetInternalWindowPos( HWND hwnd, LPRECT rectWnd, LPPOINT ptIcon )
467 {
468     WINDOWPLACEMENT wndpl;
469     if (!GetWindowPlacement( hwnd, &wndpl )) return 0;
470     if (rectWnd) *rectWnd = wndpl.rcNormalPosition;
471     if (ptIcon)  *ptIcon = wndpl.ptMinPosition;
472     return wndpl.showCmd;
473 }
474
475
476 /***********************************************************************
477  *           SetInternalWindowPos   (USER.461)
478  */
479 void SetInternalWindowPos( HWND hwnd, WORD showCmd, LPRECT rect, LPPOINT pt )
480 {
481     WINDOWPLACEMENT wndpl;
482     WND *wndPtr = WIN_FindWndPtr( hwnd );
483
484     wndpl.length  = sizeof(wndpl);
485     wndpl.flags   = (pt != NULL) ? WPF_SETMINPOSITION : 0;
486     wndpl.showCmd = showCmd;
487     if (pt) wndpl.ptMinPosition = *pt;
488     wndpl.rcNormalPosition = (rect != NULL) ? *rect : wndPtr->rectNormal;
489     wndpl.ptMaxPosition = wndPtr->ptMaxPos;
490     SetWindowPlacement( hwnd, &wndpl );
491 }
492
493
494 /***********************************************************************
495  *           GetWindowPlacement   (USER.370)
496  */
497 BOOL GetWindowPlacement( HWND hwnd, WINDOWPLACEMENT *wndpl )
498 {
499     WND *wndPtr = WIN_FindWndPtr( hwnd );
500     if (!wndPtr) return FALSE;
501
502     wndpl->length  = sizeof(*wndpl);
503     wndpl->flags   = 0;
504     wndpl->showCmd = IsZoomed(hwnd) ? SW_SHOWMAXIMIZED : 
505                      (IsIconic(hwnd) ? SW_SHOWMINIMIZED : SW_SHOWNORMAL);
506     wndpl->ptMinPosition = wndPtr->ptIconPos;
507     wndpl->ptMaxPosition = wndPtr->ptMaxPos;
508     wndpl->rcNormalPosition = wndPtr->rectNormal;
509     return TRUE;
510 }
511
512
513 /***********************************************************************
514  *           SetWindowPlacement   (USER.371)
515  */
516 BOOL SetWindowPlacement( HWND hwnd, WINDOWPLACEMENT *wndpl )
517 {
518     WND *wndPtr = WIN_FindWndPtr( hwnd );
519     if (!wndPtr) return FALSE;
520
521     if (wndpl->flags & WPF_SETMINPOSITION)
522         wndPtr->ptIconPos = wndpl->ptMinPosition;
523     if ((wndpl->flags & WPF_RESTORETOMAXIMIZED) &&
524         (wndpl->showCmd == SW_SHOWMINIMIZED)) wndPtr->flags |= WIN_RESTORE_MAX;
525     wndPtr->ptMaxPos   = wndpl->ptMaxPosition;
526     wndPtr->rectNormal = wndpl->rcNormalPosition;
527     ShowWindow( hwnd, wndpl->showCmd );
528     return TRUE;
529 }
530
531
532 /*******************************************************************
533  *         WINPOS_NextWindowFromPoint
534  *
535  *  Looks for next enabled window that is
536  *  a) sibling of hwnd, later in Z-order and encloses pt, or
537  *  b) parent of hwnd
538  */
539 HWND WINPOS_NextWindowFromPoint( HWND hwnd, POINT pt )
540 {
541     WND *wndPtr = WIN_FindWndPtr( hwnd );
542
543     if (!wndPtr->hwndParent) return hwnd;  /* desktop window */
544     ScreenToClient( wndPtr->hwndParent, &pt ); /* make pt relative to parent */
545     for (;;)
546     {
547         if (!wndPtr->hwndNext) break;  /* No more children */
548         hwnd = wndPtr->hwndNext;
549         wndPtr = WIN_FindWndPtr( hwnd );
550         if ((wndPtr->dwStyle & WS_VISIBLE) &&
551             !(wndPtr->dwStyle & WS_DISABLED) &&
552             PtInRect( &wndPtr->rectWindow, pt )) return hwnd;
553     }
554     return wndPtr->hwndParent;
555 }
556
557
558 /*******************************************************************
559  *         WINPOS_ChangeActiveWindow
560  *
561  * Change the active window and send the corresponding messages.
562  */
563 HWND WINPOS_ChangeActiveWindow( HWND hwnd, BOOL mouseMsg )
564 {
565     HWND prevActive = hwndActive;
566     if (hwnd == hwndActive) return 0;
567     if (hwndActive)
568     {
569         if (!SendMessage( hwndActive, WM_NCACTIVATE, FALSE, 0 )) return 0;
570         SendMessage( hwndActive, WM_ACTIVATE, WA_INACTIVE,
571                      MAKELONG( IsIconic(hwndActive), hwnd ) );
572         /* Send WM_ACTIVATEAPP here */
573     }
574
575     hwndActive = hwnd;
576     if (hwndActive)
577     {
578         WND *wndPtr = WIN_FindWndPtr( hwndActive );
579         wndPtr->hwndPrevActive = prevActive;
580
581         /* Send WM_ACTIVATEAPP here */
582         SendMessage( hwnd, WM_NCACTIVATE, TRUE, 0 );
583         SendMessage( hwnd, WM_ACTIVATE, mouseMsg ? WA_CLICKACTIVE : WA_ACTIVE,
584                      MAKELONG( IsIconic(hwnd), prevActive ) );
585     }
586     return prevActive;
587 }
588
589
590 /***********************************************************************
591  *           WINPOS_SendNCCalcSize
592  *
593  * Send a WM_NCCALCSIZE message to a window.
594  * All parameters are read-only except newClientRect.
595  * oldWindowRect, oldClientRect and winpos must be non-NULL only
596  * when calcValidRect is TRUE.
597  */
598 LONG WINPOS_SendNCCalcSize( HWND hwnd, BOOL calcValidRect, RECT *newWindowRect,
599                             RECT *oldWindowRect, RECT *oldClientRect,
600                             WINDOWPOS *winpos, RECT *newClientRect )
601 {
602     NCCALCSIZE_PARAMS *params;
603     HANDLE hparams;
604     LONG result;
605
606     if (!(hparams = USER_HEAP_ALLOC( sizeof(*params) ))) return 0;
607     params = (NCCALCSIZE_PARAMS *) USER_HEAP_LIN_ADDR( hparams );
608     params->rgrc[0] = *newWindowRect;
609     if (calcValidRect)
610     {
611         params->rgrc[1] = *oldWindowRect;
612         params->rgrc[2] = *oldClientRect;
613         params->lppos = winpos;
614     }
615     result = SendMessage( hwnd, WM_NCCALCSIZE, calcValidRect,
616                           USER_HEAP_SEG_ADDR(hparams) );
617     *newClientRect = params->rgrc[0];
618     USER_HEAP_FREE( hparams );
619     return result;
620 }
621
622
623 /***********************************************************************
624  *           WINPOS_HandleWindowPosChanging
625  *
626  * Default handling for a WM_WINDOWPOSCHANGING. Called from DefWindowProc().
627  */
628 LONG WINPOS_HandleWindowPosChanging( WINDOWPOS *winpos )
629 {
630     POINT maxSize;
631     WND *wndPtr = WIN_FindWndPtr( winpos->hwnd );
632     if (!wndPtr || (winpos->flags & SWP_NOSIZE)) return 0;
633     if ((wndPtr->dwStyle & WS_THICKFRAME) ||
634         (wndPtr->dwStyle & (WS_POPUP | WS_CHILD) == 0))
635     {
636         NC_GetMinMaxInfo( winpos->hwnd, &maxSize, NULL, NULL, NULL );
637         winpos->cx = min( winpos->cx, maxSize.x );
638         winpos->cy = min( winpos->cy, maxSize.y );
639     }
640     return 0;
641 }
642
643
644 /***********************************************************************
645  *           WINPOS_MoveWindowZOrder
646  *
647  * Move a window in Z order, invalidating everything that needs it.
648  * Only necessary for windows without associated X window.
649  */
650 static void WINPOS_MoveWindowZOrder( HWND hwnd, HWND hwndAfter )
651 {
652     BOOL movingUp;
653     HWND hwndCur;
654     WND *wndPtr = WIN_FindWndPtr( hwnd );
655
656     /* We have two possible cases:
657      * - The window is moving up: we have to invalidate all areas
658      *   of the window that were covered by other windows
659      * - The window is moving down: we have to invalidate areas
660      *   of other windows covered by this one.
661      */
662
663     if (hwndAfter == HWND_TOP)
664     {
665         movingUp = TRUE;
666     }
667     else if (hwndAfter == HWND_BOTTOM)
668     {
669         if (!wndPtr->hwndNext) return;  /* Already at the bottom */
670         movingUp = FALSE;
671     }
672     else
673     {
674         if (wndPtr->hwndNext == hwndAfter) return;  /* Already placed right */
675
676           /* Determine which window we encounter first in Z-order */
677         hwndCur = GetWindow( wndPtr->hwndParent, GW_CHILD );
678         while ((hwndCur != hwnd) && (hwndCur != hwndAfter))
679             hwndCur = GetWindow( hwndCur, GW_HWNDNEXT );
680         movingUp = (hwndCur == hwndAfter);
681     }
682
683     if (movingUp)
684     {
685         HWND hwndPrevAfter = wndPtr->hwndNext;
686         WIN_UnlinkWindow( hwnd );
687         WIN_LinkWindow( hwnd, hwndAfter );
688         hwndCur = wndPtr->hwndNext;
689         while (hwndCur != hwndPrevAfter)
690         {
691             WND *curPtr = WIN_FindWndPtr( hwndCur );
692             RECT rect = curPtr->rectWindow;
693             OffsetRect( &rect, -wndPtr->rectClient.left,
694                         -wndPtr->rectClient.top );
695             RedrawWindow( hwnd, &rect, 0, RDW_INVALIDATE | RDW_ALLCHILDREN |
696                           RDW_FRAME | RDW_ERASE );
697             hwndCur = curPtr->hwndNext;
698         }
699     }
700     else  /* Moving down */
701     {
702         hwndCur = wndPtr->hwndNext;
703         WIN_UnlinkWindow( hwnd );
704         WIN_LinkWindow( hwnd, hwndAfter );
705         while (hwndCur != hwnd)
706         {
707             WND *curPtr = WIN_FindWndPtr( hwndCur );
708             RECT rect = wndPtr->rectWindow;
709             OffsetRect( &rect, -curPtr->rectClient.left,
710                         -curPtr->rectClient.top );
711             RedrawWindow( hwndCur, &rect, 0, RDW_INVALIDATE | RDW_ALLCHILDREN |
712                           RDW_FRAME | RDW_ERASE );
713             hwndCur = curPtr->hwndNext;
714         }
715     }
716 }
717
718
719 /***********************************************************************
720  *           WINPOS_SetXWindosPos
721  *
722  * SetWindowPos() for an X window. Used by the real SetWindowPos().
723  */
724 static void WINPOS_SetXWindowPos( WINDOWPOS *winpos )
725 {
726     XWindowChanges winChanges;
727     int changeMask = 0;
728     WND *wndPtr = WIN_FindWndPtr( winpos->hwnd );
729
730     if (!(winpos->flags & SWP_NOSIZE))
731     {
732         winChanges.width     = winpos->cx;
733         winChanges.height    = winpos->cy;
734         changeMask |= CWWidth | CWHeight;
735     }
736     if (!(winpos->flags & SWP_NOMOVE))
737     {
738         winChanges.x = winpos->x;
739         winChanges.y = winpos->y;
740         changeMask |= CWX | CWY;
741     }
742     if (!(winpos->flags & SWP_NOZORDER))
743     {
744         if (winpos->hwndInsertAfter == HWND_TOP) winChanges.stack_mode = Above;
745         else winChanges.stack_mode = Below;
746         if ((winpos->hwndInsertAfter != HWND_TOP) &&
747             (winpos->hwndInsertAfter != HWND_BOTTOM))
748         {
749             WND * insertPtr = WIN_FindWndPtr( winpos->hwndInsertAfter );
750             winChanges.sibling = insertPtr->window;
751             changeMask |= CWSibling;
752         }
753         changeMask |= CWStackMode;
754     }
755     if (changeMask)
756         XConfigureWindow( display, wndPtr->window, changeMask, &winChanges );
757 }
758
759
760 /***********************************************************************
761  *           SetWindowPos   (USER.232)
762  */
763 BOOL SetWindowPos( HWND hwnd, HWND hwndInsertAfter, INT x, INT y,
764                    INT cx, INT cy, WORD flags )
765 {
766     HLOCAL hWinPos;
767     WINDOWPOS *winpos;
768     WND *wndPtr;
769     RECT newWindowRect, newClientRect;
770     int result;
771
772       /* Check window handle */
773
774     if (hwnd == GetDesktopWindow()) return FALSE;
775     if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return FALSE;
776
777       /* Check dimensions */
778
779     if (cx <= 0) cx = 1;
780     if (cy <= 0) cy = 1;
781
782       /* Check flags */
783
784     if (hwnd == hwndActive) flags |= SWP_NOACTIVATE;   /* Already active */
785     if ((wndPtr->rectWindow.right - wndPtr->rectWindow.left == cx) &&
786         (wndPtr->rectWindow.bottom - wndPtr->rectWindow.top == cy))
787         flags |= SWP_NOSIZE;    /* Already the right size */
788     if ((wndPtr->rectWindow.left == x) && (wndPtr->rectWindow.top == y))
789         flags |= SWP_NOMOVE;    /* Already the right position */
790
791       /* Check hwndInsertAfter */
792
793     if (!(flags & (SWP_NOZORDER | SWP_NOACTIVATE)))
794     {
795           /* Ignore TOPMOST flags when activating a window */
796           /* _and_ moving it in Z order. */
797         if ((hwndInsertAfter == HWND_TOPMOST) ||
798             (hwndInsertAfter == HWND_NOTOPMOST))
799             hwndInsertAfter = HWND_TOP; 
800     }
801       /* TOPMOST not supported yet */
802     if ((hwndInsertAfter == HWND_TOPMOST) ||
803         (hwndInsertAfter == HWND_NOTOPMOST)) hwndInsertAfter = HWND_TOP;
804       /* hwndInsertAfter must be a sibling of the window */
805     if ((hwndInsertAfter != HWND_TOP) && (hwndInsertAfter != HWND_BOTTOM) &&
806         (GetParent(hwnd) != GetParent(hwndInsertAfter))) return FALSE;
807
808       /* Allocate the WINDOWPOS structure */
809
810     hWinPos = USER_HEAP_ALLOC( sizeof(WINDOWPOS) );
811     if (!hWinPos) return FALSE;
812     winpos = USER_HEAP_LIN_ADDR( hWinPos );
813     winpos->hwnd = hwnd;
814     winpos->hwndInsertAfter = hwndInsertAfter;
815     winpos->x = x;
816     winpos->y = y;
817     winpos->cx = cx;
818     winpos->cy = cy;
819     winpos->flags = flags;
820     
821       /* Send WM_WINDOWPOSCHANGING message */
822
823     if (!(flags & SWP_NOSENDCHANGING))
824         SendMessage( hwnd, WM_WINDOWPOSCHANGING, 0,
825                      USER_HEAP_SEG_ADDR(hWinPos) );
826
827       /* Calculate new position and size */
828
829     newWindowRect = wndPtr->rectWindow;
830     newClientRect = wndPtr->rectClient;
831
832     if (!(winpos->flags & SWP_NOSIZE))
833     {
834         newWindowRect.right  = newWindowRect.left + winpos->cx;
835         newWindowRect.bottom = newWindowRect.top + winpos->cy;
836     }
837     if (!(winpos->flags & SWP_NOMOVE))
838     {
839         newWindowRect.left    = winpos->x;
840         newWindowRect.top     = winpos->y;
841         newWindowRect.right  += winpos->x - wndPtr->rectWindow.left;
842         newWindowRect.bottom += winpos->y - wndPtr->rectWindow.top;
843     }
844
845       /* Reposition window in Z order */
846
847     if (!(winpos->flags & SWP_NOZORDER))
848     {
849         if (wndPtr->window)
850         {
851             WIN_UnlinkWindow( winpos->hwnd );
852             WIN_LinkWindow( winpos->hwnd, hwndInsertAfter );
853         }
854         else WINPOS_MoveWindowZOrder( winpos->hwnd, hwndInsertAfter );
855     }
856
857       /* Send WM_NCCALCSIZE message to get new client area */
858
859     result = WINPOS_SendNCCalcSize( winpos->hwnd, TRUE, &newWindowRect,
860                                     &wndPtr->rectWindow, &wndPtr->rectClient,
861                                     winpos, &newClientRect );
862     /* ....  Should handle result here */
863
864       /* Perform the moving and resizing */
865
866     if (wndPtr->window)
867     {
868         WINPOS_SetXWindowPos( winpos );
869         wndPtr->rectWindow = newWindowRect;
870         wndPtr->rectClient = newClientRect;
871     }
872     else
873     {
874         RECT oldWindowRect = wndPtr->rectWindow;
875
876         wndPtr->rectWindow = newWindowRect;
877         wndPtr->rectClient = newClientRect;
878
879         if (!(flags & SWP_NOREDRAW) &&
880             (!(flags & SWP_NOSIZE) || !(flags & SWP_NOMOVE) ||
881              !(flags & SWP_NOZORDER)))
882         {
883             HRGN hrgn1 = CreateRectRgnIndirect( &oldWindowRect );
884             HRGN hrgn2 = CreateRectRgnIndirect( &wndPtr->rectWindow );
885             HRGN hrgn3 = CreateRectRgn( 0, 0, 0, 0 );
886             CombineRgn( hrgn3, hrgn1, hrgn2, RGN_DIFF );
887             RedrawWindow( wndPtr->hwndParent, NULL, hrgn3,
888                           RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_ERASE );
889             if ((oldWindowRect.left != wndPtr->rectWindow.left) ||
890                 (oldWindowRect.top != wndPtr->rectWindow.top))
891             {
892                 RedrawWindow( winpos->hwnd, NULL, 0, RDW_INVALIDATE |
893                               RDW_FRAME | RDW_ALLCHILDREN | RDW_ERASE );
894             }
895             DeleteObject( hrgn1 );
896             DeleteObject( hrgn2 );
897             DeleteObject( hrgn3 );
898         }
899     }
900
901     if (flags & SWP_SHOWWINDOW)
902     {
903         wndPtr->dwStyle |= WS_VISIBLE;
904         if (wndPtr->window)
905         {
906             XMapWindow( display, wndPtr->window );
907         }
908         else
909         {
910             if (!(flags & SWP_NOREDRAW))
911                 RedrawWindow( winpos->hwnd, NULL, 0,
912                               RDW_INVALIDATE | RDW_FRAME | RDW_ERASE );
913         }
914     }
915     else if (flags & SWP_HIDEWINDOW)
916     {
917         wndPtr->dwStyle &= ~WS_VISIBLE;
918         if (wndPtr->window)
919         {
920             XUnmapWindow( display, wndPtr->window );
921         }
922         else
923         {
924             if (!(flags & SWP_NOREDRAW))
925                 RedrawWindow( wndPtr->hwndParent, &wndPtr->rectWindow, 0,
926                               RDW_INVALIDATE | RDW_FRAME |
927                               RDW_ALLCHILDREN | RDW_ERASE );
928         }
929         if ((winpos->hwnd == GetFocus()) || IsChild(winpos->hwnd, GetFocus()))
930             SetFocus( GetParent(winpos->hwnd) );  /* Revert focus to parent */
931         if (winpos->hwnd == hwndActive)
932         {
933               /* Activate previously active window if possible */
934             HWND newActive = wndPtr->hwndPrevActive;
935             if (!IsWindow(newActive) || (newActive == winpos->hwnd))
936             {
937                 newActive = GetTopWindow(GetDesktopWindow());
938                 if (newActive == winpos->hwnd) newActive = wndPtr->hwndNext;
939             }       
940             WINPOS_ChangeActiveWindow( newActive, FALSE );
941         }
942     }
943
944       /* Activate the window */
945
946     if (!(flags & SWP_NOACTIVATE))
947     {
948         if (!(wndPtr->dwStyle & WS_CHILD))
949             WINPOS_ChangeActiveWindow( winpos->hwnd, FALSE );
950     }
951     
952       /* Repaint the window */
953
954     if (wndPtr->window) MSG_Synchronize();  /* Wait for all expose events */
955     if ((flags & SWP_FRAMECHANGED) && !(flags & SWP_NOREDRAW))
956         RedrawWindow( winpos->hwnd, NULL, 0,
957                       RDW_INVALIDATE | RDW_FRAME | RDW_ERASE );
958     if (!(flags & SWP_DEFERERASE))
959         RedrawWindow( wndPtr->hwndParent, NULL, 0,
960                       RDW_ALLCHILDREN | RDW_ERASENOW );
961
962       /* And last, send the WM_WINDOWPOSCHANGED message */
963
964     if (!(winpos->flags & SWP_NOSENDCHANGING))
965         SendMessage( winpos->hwnd, WM_WINDOWPOSCHANGED, 0,
966                      USER_HEAP_SEG_ADDR(hWinPos) );
967
968     USER_HEAP_FREE( hWinPos );
969     return TRUE;
970 }
971
972                                         
973 /***********************************************************************
974  *           BeginDeferWindowPos   (USER.259)
975  */
976 HDWP BeginDeferWindowPos( INT count )
977 {
978     HDWP handle;
979     DWP *pDWP;
980
981     if (count <= 0) return 0;
982     handle = USER_HEAP_ALLOC( sizeof(DWP) + (count-1)*sizeof(WINDOWPOS) );
983     if (!handle) return 0;
984     pDWP = (DWP *) USER_HEAP_LIN_ADDR( handle );
985     pDWP->actualCount    = 0;
986     pDWP->suggestedCount = count;
987     pDWP->valid          = TRUE;
988     pDWP->wMagic         = DWP_MAGIC;
989     pDWP->hwndParent     = 0;
990     return handle;
991 }
992
993
994 /***********************************************************************
995  *           DeferWindowPos   (USER.260)
996  */
997 HDWP DeferWindowPos( HDWP hdwp, HWND hwnd, HWND hwndAfter, INT x, INT y,
998                      INT cx, INT cy, WORD flags )
999 {
1000     DWP *pDWP;
1001     int i;
1002     HDWP newhdwp = hdwp;
1003
1004     pDWP = (DWP *) USER_HEAP_LIN_ADDR( hdwp );
1005     if (!pDWP) return 0;
1006
1007       /* All the windows of a DeferWindowPos() must have the same parent */
1008
1009     if (pDWP->actualCount == 0) pDWP->hwndParent = GetParent( hwnd );
1010     else if (GetParent( hwnd ) != pDWP->hwndParent)
1011     {
1012         USER_HEAP_FREE( hdwp );
1013         return 0;
1014     }
1015
1016     for (i = 0; i < pDWP->actualCount; i++)
1017     {
1018         if (pDWP->winPos[i].hwnd == hwnd)
1019         {
1020               /* Merge with the other changes */
1021             if (!(flags & SWP_NOZORDER))
1022             {
1023                 pDWP->winPos[i].hwndInsertAfter = hwndAfter;
1024             }
1025             if (!(flags & SWP_NOMOVE))
1026             {
1027                 pDWP->winPos[i].x = x;
1028                 pDWP->winPos[i].y = y;
1029             }                
1030             if (!(flags & SWP_NOSIZE))
1031             {
1032                 pDWP->winPos[i].cx = cx;
1033                 pDWP->winPos[i].cy = cy;
1034             }
1035             pDWP->winPos[i].flags &= flags & (SWP_NOSIZE | SWP_NOMOVE |
1036                                               SWP_NOZORDER | SWP_NOREDRAW |
1037                                               SWP_NOACTIVATE | SWP_NOCOPYBITS |
1038                                               SWP_NOOWNERZORDER);
1039             pDWP->winPos[i].flags |= flags & (SWP_SHOWWINDOW | SWP_HIDEWINDOW |
1040                                               SWP_FRAMECHANGED);
1041             return hdwp;
1042         }
1043     }
1044     if (pDWP->actualCount >= pDWP->suggestedCount)
1045     {
1046         newhdwp = USER_HEAP_REALLOC( hdwp,
1047                       sizeof(DWP) + pDWP->suggestedCount*sizeof(WINDOWPOS) );
1048         if (!newhdwp) return 0;
1049         pDWP = (DWP *) USER_HEAP_LIN_ADDR( newhdwp );
1050         pDWP->suggestedCount++;
1051     }
1052     pDWP->winPos[pDWP->actualCount].hwnd = hwnd;
1053     pDWP->winPos[pDWP->actualCount].hwndInsertAfter = hwndAfter;
1054     pDWP->winPos[pDWP->actualCount].x = x;
1055     pDWP->winPos[pDWP->actualCount].y = y;
1056     pDWP->winPos[pDWP->actualCount].cx = cx;
1057     pDWP->winPos[pDWP->actualCount].cy = cy;
1058     pDWP->winPos[pDWP->actualCount].flags = flags;
1059     pDWP->actualCount++;
1060     return newhdwp;
1061 }
1062
1063
1064 /***********************************************************************
1065  *           EndDeferWindowPos   (USER.261)
1066  */
1067 BOOL EndDeferWindowPos( HDWP hdwp )
1068 {
1069     DWP *pDWP;
1070     WINDOWPOS *winpos;
1071     BOOL res = TRUE;
1072     int i;
1073
1074     pDWP = (DWP *) USER_HEAP_LIN_ADDR( hdwp );
1075     if (!pDWP) return FALSE;
1076     for (i = 0, winpos = pDWP->winPos; i < pDWP->actualCount; i++, winpos++)
1077     {
1078         if (!(res = SetWindowPos( winpos->hwnd, winpos->hwndInsertAfter,
1079                                   winpos->x, winpos->y, winpos->cx, winpos->cy,
1080                                   winpos->flags ))) break;
1081     }
1082     USER_HEAP_FREE( hdwp );
1083     return res;
1084 }
1085
1086
1087 /***********************************************************************
1088  *           TileChildWindows   (USER.199)
1089  */
1090 void TileChildWindows( HWND parent, WORD action )
1091 {
1092     printf("STUB TileChildWindows(%04X, %d)\n", parent, action);
1093 }
1094
1095 /***********************************************************************
1096  *           CascageChildWindows   (USER.198)
1097  */
1098 void CascadeChildWindows( HWND parent, WORD action )
1099 {
1100     printf("STUB CascadeChildWindows(%04X, %d)\n", parent, action);
1101 }