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