Remove a hack for keyboard group switching.
[wine] / windows / winpos.c
1 /*
2  * Window position related functions.
3  *
4  * Copyright 1993, 1994, 1995 Alexandre Julliard
5  *                       1995, 1996, 1999 Alex Korobka
6  */
7
8 #include <string.h>
9 #include "winerror.h"
10 #include "windef.h"
11 #include "wingdi.h"
12 #include "winerror.h"
13 #include "wine/winuser16.h"
14 #include "controls.h"
15 #include "user.h"
16 #include "region.h"
17 #include "win.h"
18 #include "hook.h"
19 #include "message.h"
20 #include "queue.h"
21 #include "winpos.h"
22 #include "dce.h"
23 #include "nonclient.h"
24 #include "debugtools.h"
25 #include "input.h"
26
27 DEFAULT_DEBUG_CHANNEL(win);
28
29 #define HAS_DLGFRAME(style,exStyle) \
30     (((exStyle) & WS_EX_DLGMODALFRAME) || \
31      (((style) & WS_DLGFRAME) && !((style) & WS_BORDER)))
32
33 #define HAS_THICKFRAME(style) \
34     (((style) & WS_THICKFRAME) && \
35      !(((style) & (WS_DLGFRAME|WS_BORDER)) == WS_DLGFRAME))
36
37 #define EMPTYPOINT(pt)          ((*(LONG*)&(pt)) == -1)
38
39 #define PLACE_MIN               0x0001
40 #define PLACE_MAX               0x0002
41 #define PLACE_RECT              0x0004
42
43
44 #define DWP_MAGIC  ((INT)('W' | ('P' << 8) | ('O' << 16) | ('S' << 24)))
45
46 typedef struct
47 {
48     INT       actualCount;
49     INT       suggestedCount;
50     BOOL      valid;
51     INT       wMagic;
52     HWND      hwndParent;
53     WINDOWPOS winPos[1];
54 } DWP;
55
56 /* ----- internal variables ----- */
57
58 static HWND hwndPrevActive  = 0;  /* Previously active window */
59 static HWND hGlobalShellWindow=0; /*the shell*/
60 static HWND hGlobalTaskmanWindow=0;
61 static HWND hGlobalProgmanWindow=0;
62
63 static LPCSTR atomInternalPos;
64
65 extern HQUEUE16 hActiveQueue;
66
67 /***********************************************************************
68  *           WINPOS_CreateInternalPosAtom
69  */
70 BOOL WINPOS_CreateInternalPosAtom()
71 {
72     LPSTR str = "SysIP";
73     atomInternalPos = (LPCSTR)(DWORD)GlobalAddAtomA(str);
74     return (atomInternalPos) ? TRUE : FALSE;
75 }
76
77 /***********************************************************************
78  *           WINPOS_CheckInternalPos
79  *
80  * Called when a window is destroyed.
81  */
82 void WINPOS_CheckInternalPos( HWND hwnd )
83 {
84     LPINTERNALPOS lpPos;
85     MESSAGEQUEUE *pMsgQ = 0;
86     WND *wndPtr = WIN_FindWndPtr( hwnd );
87
88     lpPos = (LPINTERNALPOS) GetPropA( hwnd, atomInternalPos );
89
90     /* Retrieve the message queue associated with this window */
91     pMsgQ = (MESSAGEQUEUE *)QUEUE_Lock( wndPtr->hmemTaskQ );
92     if ( !pMsgQ )
93     {
94         WARN("\tMessage queue not found. Exiting!\n" );
95         WIN_ReleaseWndPtr( wndPtr );
96         return;
97     }
98
99     if( hwnd == hwndPrevActive ) hwndPrevActive = 0;
100
101     if( hwnd == PERQDATA_GetActiveWnd( pMsgQ->pQData ) )
102     {
103         PERQDATA_SetActiveWnd( pMsgQ->pQData, 0 );
104         WARN("\tattempt to activate destroyed window!\n");
105     }
106
107     if( lpPos )
108     {
109         if( IsWindow(lpPos->hwndIconTitle) ) 
110             DestroyWindow( lpPos->hwndIconTitle );
111         HeapFree( GetProcessHeap(), 0, lpPos );
112     }
113
114     QUEUE_Unlock( pMsgQ );
115     WIN_ReleaseWndPtr( wndPtr );
116     return;
117 }
118
119 /***********************************************************************
120  *              ArrangeIconicWindows (USER32.@)
121  */
122 UINT WINAPI ArrangeIconicWindows( HWND parent )
123 {
124     RECT rectParent;
125     HWND hwndChild;
126     INT x, y, xspacing, yspacing;
127
128     GetClientRect( parent, &rectParent );
129     x = rectParent.left;
130     y = rectParent.bottom;
131     xspacing = GetSystemMetrics(SM_CXICONSPACING);
132     yspacing = GetSystemMetrics(SM_CYICONSPACING);
133
134     hwndChild = GetWindow( parent, GW_CHILD );
135     while (hwndChild)
136     {
137         if( IsIconic( hwndChild ) )
138         {
139             WINPOS_ShowIconTitle( hwndChild, FALSE );
140
141             SetWindowPos( hwndChild, 0, x + (xspacing - GetSystemMetrics(SM_CXICON)) / 2,
142                             y - yspacing - GetSystemMetrics(SM_CYICON)/2, 0, 0,
143                             SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE );
144             if( IsWindow(hwndChild) )
145                 WINPOS_ShowIconTitle(hwndChild , TRUE );
146
147             if (x <= rectParent.right - xspacing) x += xspacing;
148             else
149             {
150                 x = rectParent.left;
151                 y -= yspacing;
152             }
153         }
154         hwndChild = GetWindow( hwndChild, GW_HWNDNEXT );
155     }
156     return yspacing;
157 }
158
159
160 /***********************************************************************
161  *              SwitchToThisWindow (USER32.@)
162  */
163 void WINAPI SwitchToThisWindow( HWND hwnd, BOOL restore )
164 {
165     ShowWindow( hwnd, restore ? SW_RESTORE : SW_SHOWMINIMIZED );
166 }
167
168
169 /***********************************************************************
170  *              GetWindowRect (USER32.@)
171  */
172 BOOL WINAPI GetWindowRect( HWND hwnd, LPRECT rect ) 
173 {
174     WND * wndPtr = WIN_FindWndPtr( hwnd );
175     if (!wndPtr) return FALSE;
176     *rect = wndPtr->rectWindow;
177     WIN_ReleaseWndPtr(wndPtr);
178     MapWindowPoints( GetAncestor( hwnd, GA_PARENT ), 0, (POINT *)rect, 2 );
179     TRACE("hwnd %04x (%d,%d)-(%d,%d)\n",
180           hwnd, rect->left, rect->top, rect->right, rect->bottom);
181     return TRUE;
182 }
183
184
185 /***********************************************************************
186  *              GetWindowRgn (USER32.@)
187  */
188 int WINAPI GetWindowRgn ( HWND hwnd, HRGN hrgn )
189 {
190     int nRet = ERROR;
191     WND *wndPtr = WIN_FindWndPtr( hwnd );
192     if (wndPtr)
193     {
194         if (wndPtr->hrgnWnd) nRet = CombineRgn( hrgn, wndPtr->hrgnWnd, 0, RGN_COPY );
195         WIN_ReleaseWndPtr(wndPtr);
196     }
197     return nRet;
198 }
199
200 /***********************************************************************
201  *              SetWindowRgn (USER32.@)
202  */
203 int WINAPI SetWindowRgn( HWND hwnd, HRGN hrgn, BOOL bRedraw )
204 {
205     RECT rect;
206     WND *wndPtr;
207     int ret = FALSE;
208
209     if (USER_Driver.pSetWindowRgn)
210         return USER_Driver.pSetWindowRgn( hwnd, hrgn, bRedraw );
211
212     if (!(wndPtr = WIN_FindWndPtr(hwnd))) return FALSE;
213
214     if (wndPtr->hrgnWnd == hrgn)
215     {
216         ret = TRUE;
217         goto done;
218     }
219
220     if (hrgn) /* verify that region really exists */
221     {
222         if (GetRgnBox( hrgn, &rect ) == ERROR) goto done;
223     }
224
225     if (wndPtr->hrgnWnd)
226     {
227         /* delete previous region */
228         DeleteObject(wndPtr->hrgnWnd);
229         wndPtr->hrgnWnd = 0;
230     }
231     wndPtr->hrgnWnd = hrgn;
232
233     /* Size the window to the rectangle of the new region (if it isn't NULL) */
234     if (hrgn) SetWindowPos( hwnd, 0, rect.left, rect.top,
235                             rect.right  - rect.left, rect.bottom - rect.top,
236                             SWP_NOSIZE | SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOACTIVATE |
237                             SWP_NOZORDER | (bRedraw ? 0 : SWP_NOREDRAW) );
238     ret = TRUE;
239
240  done:
241     WIN_ReleaseWndPtr(wndPtr);
242     return ret;
243 }
244
245
246 /***********************************************************************
247  *              GetClientRect (USER32.@)
248  */
249 BOOL WINAPI GetClientRect( HWND hwnd, LPRECT rect ) 
250 {
251     WND * wndPtr = WIN_FindWndPtr( hwnd );
252
253     rect->left = rect->top = rect->right = rect->bottom = 0;
254     if (!wndPtr) return FALSE;
255     rect->right  = wndPtr->rectClient.right - wndPtr->rectClient.left;
256     rect->bottom = wndPtr->rectClient.bottom - wndPtr->rectClient.top;
257
258     WIN_ReleaseWndPtr(wndPtr);
259     TRACE("hwnd %04x (%d,%d)-(%d,%d)\n",
260           hwnd, rect->left, rect->top, rect->right, rect->bottom);
261     return TRUE;
262 }
263
264
265 /*******************************************************************
266  *              ClientToScreen (USER32.@)
267  */
268 BOOL WINAPI ClientToScreen( HWND hwnd, LPPOINT lppnt )
269 {
270     MapWindowPoints( hwnd, 0, lppnt, 1 );
271     return TRUE;
272 }
273
274
275 /*******************************************************************
276  *              ScreenToClient (USER32.@)
277  */
278 BOOL WINAPI ScreenToClient( HWND hwnd, LPPOINT lppnt )
279 {
280     MapWindowPoints( 0, hwnd, lppnt, 1 );
281     return TRUE;
282 }
283
284
285 /***********************************************************************
286  *           WINPOS_WindowFromPoint
287  *
288  * Find the window and hittest for a given point.
289  */
290 HWND WINPOS_WindowFromPoint( HWND hwndScope, POINT pt, INT *hittest )
291 {
292     WND *wndScope, *wndPtr, *wndTmp;
293     HWND hwnd_ret = 0;
294     POINT xy = pt;
295
296     TRACE("scope %04x %ld,%ld\n", hwndScope, pt.x, pt.y);
297
298     if (!hwndScope) hwndScope = GetDesktopWindow();
299     if (!(wndScope = WIN_FindWndPtr( hwndScope ))) return 0;
300     hwndScope = wndScope->hwndSelf;  /* make it a full handle */
301
302     *hittest = HTERROR;
303     wndPtr = WIN_LockWndPtr(wndScope->child);
304
305     if( wndScope->dwStyle & WS_DISABLED )
306     {
307         *hittest = HTERROR;
308         goto end;
309     }
310
311     if (wndScope->parent)
312         MapWindowPoints( GetDesktopWindow(), wndScope->parent->hwndSelf, &xy, 1 );
313
314     if (xy.x < wndScope->rectClient.left || pt.x >= wndScope->rectClient.right ||
315         xy.y < wndScope->rectClient.top || pt.y >= wndScope->rectClient.bottom ||
316         wndScope->dwStyle & WS_MINIMIZE)
317         goto hittest;
318
319     xy.x -= wndScope->rectClient.left;
320     xy.y -= wndScope->rectClient.top;
321
322     for (;;)
323     {
324         while (wndPtr)
325         {
326             /* If point is in window, and window is visible, and it  */
327             /* is enabled (or it's a top-level window), then explore */
328             /* its children. Otherwise, go to the next window.       */
329
330              if ((wndPtr->dwStyle & WS_VISIBLE) &&
331                 ((wndPtr->dwExStyle & (WS_EX_LAYERED | WS_EX_TRANSPARENT)) != (WS_EX_LAYERED | WS_EX_TRANSPARENT)) &&
332                 (!(wndPtr->dwStyle & WS_DISABLED) ||
333                  ((wndPtr->dwStyle & (WS_POPUP | WS_CHILD)) != WS_CHILD)) &&
334                 (wndPtr->hrgnWnd ?
335                 PtInRegion(wndPtr->hrgnWnd, xy.x - wndPtr->rectWindow.left,
336                            xy.y - wndPtr->rectWindow.top) :
337                 ((xy.x >= wndPtr->rectWindow.left) &&
338                  (xy.x < wndPtr->rectWindow.right) &&
339                  (xy.y >= wndPtr->rectWindow.top) &&
340                  (xy.y < wndPtr->rectWindow.bottom))))
341             {
342                 TRACE("%ld,%ld is inside %04x\n", xy.x, xy.y, wndPtr->hwndSelf);
343                 hwnd_ret = wndPtr->hwndSelf;  /* Got a suitable window */
344
345                 /* If window is minimized or disabled, return at once */
346                 if (wndPtr->dwStyle & WS_MINIMIZE)
347                 {
348                     *hittest = HTCAPTION;
349                     goto end;
350                 }
351                 if (wndPtr->dwStyle & WS_DISABLED)
352                 {
353                     *hittest = HTERROR;
354                     goto end;
355                 }
356
357                 /* If point is not in client area, ignore the children */
358                 if ((xy.x < wndPtr->rectClient.left) ||
359                     (xy.x >= wndPtr->rectClient.right) ||
360                     (xy.y < wndPtr->rectClient.top) ||
361                     (xy.y >= wndPtr->rectClient.bottom)) break;
362
363                 xy.x -= wndPtr->rectClient.left;
364                 xy.y -= wndPtr->rectClient.top;
365                 WIN_UpdateWndPtr(&wndPtr,wndPtr->child);
366             }
367             else
368             {
369                 WIN_UpdateWndPtr(&wndPtr,wndPtr->next);
370             }
371         }
372
373 hittest:
374         /* If nothing found, try the scope window */
375         if (!hwnd_ret) hwnd_ret = hwndScope;
376
377         /* Send the WM_NCHITTEST message (only if to the same task) */
378         if (WIN_IsCurrentThread( hwnd_ret ))
379         {
380             INT res = SendMessageA( hwnd_ret, WM_NCHITTEST, 0, MAKELONG( pt.x, pt.y ) );
381             if (res != HTTRANSPARENT)
382             {
383                 *hittest = res;  /* Found the window */
384                 goto end;
385             }
386         }
387         else
388         {
389             *hittest = HTCLIENT;
390             goto end;
391         }
392
393         if (!(wndTmp = WIN_FindWndPtr( hwnd_ret ))) break;
394
395         /* If no children found in last search, make point relative to parent */
396         if (!wndPtr)
397         {
398             xy.x += wndTmp->rectClient.left;
399             xy.y += wndTmp->rectClient.top;
400         }
401
402         /* Restart the search from the next sibling */
403         WIN_UpdateWndPtr(&wndPtr,wndTmp->next);
404         hwnd_ret = wndTmp->parent ? wndTmp->parent->hwndSelf : 0;
405         WIN_ReleaseWndPtr( wndTmp );
406     }
407
408 end:
409     WIN_ReleaseWndPtr(wndPtr);
410     WIN_ReleaseWndPtr(wndScope);
411     return hwnd_ret;
412 }
413
414
415 /*******************************************************************
416  *              WindowFromPoint (USER32.@)
417  */
418 HWND WINAPI WindowFromPoint( POINT pt )
419 {
420     INT hittest;
421     return WINPOS_WindowFromPoint( 0, pt, &hittest );
422 }
423
424
425 /*******************************************************************
426  *              ChildWindowFromPoint (USER32.@)
427  */
428 HWND WINAPI ChildWindowFromPoint( HWND hwndParent, POINT pt )
429 {
430     return ChildWindowFromPointEx( hwndParent, pt, CWP_ALL );
431 }
432
433 /*******************************************************************
434  *              ChildWindowFromPointEx (USER32.@)
435  */
436 HWND WINAPI ChildWindowFromPointEx( HWND hwndParent, POINT pt, UINT uFlags)
437 {
438     /* pt is in the client coordinates */
439     HWND *list;
440     int i;
441     RECT rect;
442     HWND retvalue = 0;
443
444     GetClientRect( hwndParent, &rect );
445     if (!PtInRect( &rect, pt )) return 0;
446     if (!(list = WIN_ListChildren( hwndParent ))) return 0;
447
448     for (i = 0; list[i] && !retvalue; i++)
449     {
450         WND *wnd = WIN_FindWndPtr( list[i] );
451         if (!wnd) continue;
452         if (PtInRect( &wnd->rectWindow, pt ))
453         {
454             if ( (uFlags & CWP_SKIPINVISIBLE) &&
455                  !(wnd->dwStyle & WS_VISIBLE) );
456             else if ( (uFlags & CWP_SKIPDISABLED) &&
457                       (wnd->dwStyle & WS_DISABLED) );
458             else if ( (uFlags & CWP_SKIPTRANSPARENT) &&
459                       (wnd->dwExStyle & WS_EX_TRANSPARENT) );
460             else retvalue = list[i];
461         }
462         WIN_ReleaseWndPtr( wnd );
463     }
464     HeapFree( GetProcessHeap(), 0, list );
465     if (!retvalue) retvalue = hwndParent;
466     return retvalue;
467 }
468
469
470 /*******************************************************************
471  *         WINPOS_GetWinOffset
472  *
473  * Calculate the offset between the origin of the two windows. Used
474  * to implement MapWindowPoints.
475  */
476 static void WINPOS_GetWinOffset( HWND hwndFrom, HWND hwndTo,
477                                  POINT *offset )
478 {
479     WND * wndPtr = 0;
480
481     offset->x = offset->y = 0;
482     if (hwndFrom == hwndTo ) return;
483
484       /* Translate source window origin to screen coords */
485     if (hwndFrom)
486     {
487         if (!(wndPtr = WIN_FindWndPtr( hwndFrom )))
488         {
489             ERR("bad hwndFrom = %04x\n",hwndFrom);
490             return;
491         }
492         while (wndPtr->parent)
493         {
494             offset->x += wndPtr->rectClient.left;
495             offset->y += wndPtr->rectClient.top;
496             WIN_UpdateWndPtr(&wndPtr,wndPtr->parent);
497         }
498         WIN_ReleaseWndPtr(wndPtr);
499     }
500
501       /* Translate origin to destination window coords */
502     if (hwndTo)
503     {
504         if (!(wndPtr = WIN_FindWndPtr( hwndTo )))
505         {
506             ERR("bad hwndTo = %04x\n", hwndTo );
507             return;
508         }
509         while (wndPtr->parent)
510         {
511             offset->x -= wndPtr->rectClient.left;
512             offset->y -= wndPtr->rectClient.top;
513             WIN_UpdateWndPtr(&wndPtr,wndPtr->parent);
514         }    
515         WIN_ReleaseWndPtr(wndPtr);
516     }
517 }
518
519
520 /*******************************************************************
521  *              MapWindowPoints (USER.258)
522  */
523 void WINAPI MapWindowPoints16( HWND16 hwndFrom, HWND16 hwndTo,
524                                LPPOINT16 lppt, UINT16 count )
525 {
526     POINT offset;
527
528     WINPOS_GetWinOffset( WIN_Handle32(hwndFrom), WIN_Handle32(hwndTo), &offset );
529     while (count--)
530     {
531         lppt->x += offset.x;
532         lppt->y += offset.y;
533         lppt++;
534     }
535 }
536
537
538 /*******************************************************************
539  *              MapWindowPoints (USER32.@)
540  */
541 INT WINAPI MapWindowPoints( HWND hwndFrom, HWND hwndTo,
542                                LPPOINT lppt, UINT count )
543 {
544     POINT offset;
545
546     WINPOS_GetWinOffset( WIN_GetFullHandle(hwndFrom), WIN_GetFullHandle(hwndTo), &offset );
547     while (count--)
548     {
549         lppt->x += offset.x;
550         lppt->y += offset.y;
551         lppt++;
552     }
553     return MAKELONG( LOWORD(offset.x), LOWORD(offset.y) );
554 }
555
556
557 /***********************************************************************
558  *              IsIconic (USER32.@)
559  */
560 BOOL WINAPI IsIconic(HWND hWnd)
561 {
562     BOOL retvalue;
563     WND * wndPtr = WIN_FindWndPtr(hWnd);
564     if (wndPtr == NULL) return FALSE;
565     retvalue = (wndPtr->dwStyle & WS_MINIMIZE) != 0;
566     WIN_ReleaseWndPtr(wndPtr);
567     return retvalue;
568 }
569
570
571 /***********************************************************************
572  *              IsZoomed (USER32.@)
573  */
574 BOOL WINAPI IsZoomed(HWND hWnd)
575 {
576     BOOL retvalue;
577     WND * wndPtr = WIN_FindWndPtr(hWnd);
578     if (wndPtr == NULL) return FALSE;
579     retvalue = (wndPtr->dwStyle & WS_MAXIMIZE) != 0;
580     WIN_ReleaseWndPtr(wndPtr);
581     return retvalue;
582 }
583
584
585 /*******************************************************************
586  *              GetActiveWindow (USER32.@)
587  */
588 HWND WINAPI GetActiveWindow(void)
589 {
590     MESSAGEQUEUE *pCurMsgQ = 0;
591
592     /* Get the messageQ for the current thread */
593     if (!(pCurMsgQ = QUEUE_Current()))
594 {
595         WARN("\tCurrent message queue not found. Exiting!\n" );
596         return 0;
597     }
598
599     /* Return the current active window from the perQ data of the current message Q */
600     return PERQDATA_GetActiveWnd( pCurMsgQ->pQData );
601 }
602
603
604 /*******************************************************************
605  *         WINPOS_CanActivate
606  */
607 static BOOL WINPOS_CanActivate(HWND hwnd)
608 {
609     if (!hwnd) return FALSE;
610     return ((GetWindowLongW( hwnd, GWL_STYLE ) & (WS_DISABLED|WS_VISIBLE|WS_CHILD)) == WS_VISIBLE);
611 }
612
613
614 /*******************************************************************
615  *              SetActiveWindow (USER32.@)
616  */
617 HWND WINAPI SetActiveWindow( HWND hwnd )
618 {
619     HWND prev = 0;
620     WND *wndPtr = WIN_FindWndPtr( hwnd );
621     MESSAGEQUEUE *pMsgQ = 0, *pCurMsgQ = 0;
622
623     if (!wndPtr) return 0;
624
625     if (wndPtr->dwStyle & (WS_DISABLED | WS_CHILD)) goto error;
626
627     /* Get the messageQ for the current thread */
628     if (!(pCurMsgQ = QUEUE_Current()))
629     {
630         WARN("\tCurrent message queue not found. Exiting!\n" );
631         goto error;
632     }
633
634     /* Retrieve the message queue associated with this window */
635     pMsgQ = (MESSAGEQUEUE *)QUEUE_Lock( wndPtr->hmemTaskQ );
636     if ( !pMsgQ )
637     {
638         WARN("\tWindow message queue not found. Exiting!\n" );
639         goto error;
640     }
641
642     /* Make sure that the window is associated with the calling threads
643      * message queue. It must share the same perQ data.
644      */
645     if ( pCurMsgQ->pQData != pMsgQ->pQData )
646     {
647         QUEUE_Unlock( pMsgQ );
648         goto error;
649     }
650
651     /* Save current active window */
652     prev = PERQDATA_GetActiveWnd( pMsgQ->pQData );
653     QUEUE_Unlock( pMsgQ );
654     WIN_ReleaseWndPtr(wndPtr);
655     WINPOS_SetActiveWindow( hwnd, 0, 0 );
656     return prev;
657
658  error:
659     WIN_ReleaseWndPtr(wndPtr);
660     return 0;
661 }
662
663
664 /*******************************************************************
665  *              GetForegroundWindow (USER32.@)
666  */
667 HWND WINAPI GetForegroundWindow(void)
668 {
669     HWND hwndActive = 0;
670
671     /* Get the foreground window (active window of hActiveQueue) */
672     if ( hActiveQueue )
673     {
674         MESSAGEQUEUE *pActiveQueue = QUEUE_Lock( hActiveQueue );
675         if ( pActiveQueue )
676             hwndActive = PERQDATA_GetActiveWnd( pActiveQueue->pQData );
677
678         QUEUE_Unlock( pActiveQueue );
679     }
680
681     return hwndActive;
682 }
683
684 /*******************************************************************
685  *              SetForegroundWindow (USER32.@)
686  */
687 BOOL WINAPI SetForegroundWindow( HWND hwnd )
688 {
689     return WINPOS_ChangeActiveWindow( hwnd, FALSE );
690 }
691
692
693 /*******************************************************************
694  *              AllowSetForegroundWindow (USER32.@)
695  */
696 BOOL WINAPI AllowSetForegroundWindow( DWORD procid )
697 {
698     /* FIXME: If Win98/2000 style SetForegroundWindow behavior is
699      * implemented, then fix this function. */
700     return TRUE;
701 }
702
703
704 /*******************************************************************
705  *              LockSetForegroundWindow (USER32.@)
706  */
707 BOOL WINAPI LockSetForegroundWindow( UINT lockcode )
708 {
709     /* FIXME: If Win98/2000 style SetForegroundWindow behavior is
710      * implemented, then fix this function. */
711     return TRUE;
712 }
713
714
715 /*******************************************************************
716  *              SetShellWindow (USER32.@)
717  */
718 HWND WINAPI SetShellWindow(HWND hwndshell)
719 {   WARN("(hWnd=%08x) semi stub\n",hwndshell );
720
721     hGlobalShellWindow = WIN_GetFullHandle( hwndshell );
722     return hGlobalShellWindow;
723 }
724
725
726 /*******************************************************************
727  *              GetShellWindow (USER32.@)
728  */
729 HWND WINAPI GetShellWindow(void)
730 {   WARN("(hWnd=%x) semi stub\n",hGlobalShellWindow );
731
732     return hGlobalShellWindow;
733 }
734
735
736 /***********************************************************************
737  *              BringWindowToTop (USER32.@)
738  */
739 BOOL WINAPI BringWindowToTop( HWND hwnd )
740 {
741     return SetWindowPos( hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE );
742 }
743
744
745 /***********************************************************************
746  *              MoveWindow (USER32.@)
747  */
748 BOOL WINAPI MoveWindow( HWND hwnd, INT x, INT y, INT cx, INT cy,
749                             BOOL repaint )
750 {    
751     int flags = SWP_NOZORDER | SWP_NOACTIVATE;
752     if (!repaint) flags |= SWP_NOREDRAW;
753     TRACE("%04x %d,%d %dx%d %d\n", 
754             hwnd, x, y, cx, cy, repaint );
755     return SetWindowPos( hwnd, 0, x, y, cx, cy, flags );
756 }
757
758 /***********************************************************************
759  *           WINPOS_InitInternalPos
760  */
761 static LPINTERNALPOS WINPOS_InitInternalPos( WND* wnd, POINT pt, 
762                                              LPRECT restoreRect )
763 {
764     LPINTERNALPOS lpPos = (LPINTERNALPOS) GetPropA( wnd->hwndSelf,
765                                                       atomInternalPos );
766     if( !lpPos )
767     {
768         /* this happens when the window is minimized/maximized 
769          * for the first time (rectWindow is not adjusted yet) */
770
771         lpPos = HeapAlloc( GetProcessHeap(), 0, sizeof(INTERNALPOS) );
772         if( !lpPos ) return NULL;
773
774         SetPropA( wnd->hwndSelf, atomInternalPos, (HANDLE)lpPos );
775         lpPos->hwndIconTitle = 0; /* defer until needs to be shown */
776         CONV_RECT32TO16( &wnd->rectWindow, &lpPos->rectNormal );
777         *(UINT*)&lpPos->ptIconPos = *(UINT*)&lpPos->ptMaxPos = 0xFFFFFFFF;
778     }
779
780     if( wnd->dwStyle & WS_MINIMIZE ) 
781         CONV_POINT32TO16( &pt, &lpPos->ptIconPos );
782     else if( wnd->dwStyle & WS_MAXIMIZE ) 
783         CONV_POINT32TO16( &pt, &lpPos->ptMaxPos );
784     else if( restoreRect ) 
785         CONV_RECT32TO16( restoreRect, &lpPos->rectNormal );
786
787     return lpPos;
788 }
789
790 /***********************************************************************
791  *           WINPOS_RedrawIconTitle
792  */
793 BOOL WINPOS_RedrawIconTitle( HWND hWnd )
794 {
795     LPINTERNALPOS lpPos = (LPINTERNALPOS)GetPropA( hWnd, atomInternalPos );
796     if( lpPos )
797     {
798         if( lpPos->hwndIconTitle )
799         {
800             SendMessageA( lpPos->hwndIconTitle, WM_SHOWWINDOW, TRUE, 0);
801             InvalidateRect( lpPos->hwndIconTitle, NULL, TRUE );
802             return TRUE;
803         }
804     }
805     return FALSE;
806 }
807
808 /***********************************************************************
809  *           WINPOS_ShowIconTitle
810  */
811 BOOL WINPOS_ShowIconTitle( HWND hwnd, BOOL bShow )
812 {
813     LPINTERNALPOS lpPos = (LPINTERNALPOS)GetPropA( hwnd, atomInternalPos );
814
815     if( lpPos && !(GetWindowLongA( hwnd, GWL_EXSTYLE) & WS_EX_MANAGED))
816     {
817         HWND title = lpPos->hwndIconTitle;
818
819         TRACE("0x%04x %i\n", hwnd, (bShow != 0) );
820
821         if( !title )
822             lpPos->hwndIconTitle = title = ICONTITLE_Create( hwnd );
823         if( bShow )
824         {
825             if (!IsWindowVisible(title))
826             {
827                 SendMessageA( title, WM_SHOWWINDOW, TRUE, 0 );
828                 SetWindowPos( title, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
829                               SWP_NOACTIVATE | SWP_NOZORDER | SWP_SHOWWINDOW );
830             }
831         }
832         else ShowWindow( title, SW_HIDE );
833     }
834     return FALSE;
835 }
836
837 /*******************************************************************
838  *           WINPOS_GetMinMaxInfo
839  *
840  * Get the minimized and maximized information for a window.
841  */
842 void WINPOS_GetMinMaxInfo( HWND hwnd, POINT *maxSize, POINT *maxPos,
843                            POINT *minTrack, POINT *maxTrack )
844 {
845     LPINTERNALPOS lpPos;
846     MINMAXINFO MinMax;
847     INT xinc, yinc;
848     LONG style = GetWindowLongA( hwnd, GWL_STYLE );
849     LONG exstyle = GetWindowLongA( hwnd, GWL_EXSTYLE );
850
851     /* Compute default values */
852
853     MinMax.ptMaxSize.x = GetSystemMetrics(SM_CXSCREEN);
854     MinMax.ptMaxSize.y = GetSystemMetrics(SM_CYSCREEN);
855     MinMax.ptMinTrackSize.x = GetSystemMetrics(SM_CXMINTRACK);
856     MinMax.ptMinTrackSize.y = GetSystemMetrics(SM_CYMINTRACK);
857     MinMax.ptMaxTrackSize.x = GetSystemMetrics(SM_CXSCREEN);
858     MinMax.ptMaxTrackSize.y = GetSystemMetrics(SM_CYSCREEN);
859
860     if (HAS_DLGFRAME( style, exstyle ))
861     {
862         xinc = GetSystemMetrics(SM_CXDLGFRAME);
863         yinc = GetSystemMetrics(SM_CYDLGFRAME);
864     }
865     else
866     {
867         xinc = yinc = 0;
868         if (HAS_THICKFRAME(style))
869         {
870             xinc += GetSystemMetrics(SM_CXFRAME);
871             yinc += GetSystemMetrics(SM_CYFRAME);
872         }
873         if (style & WS_BORDER)
874         {
875             xinc += GetSystemMetrics(SM_CXBORDER);
876             yinc += GetSystemMetrics(SM_CYBORDER);
877         }
878     }
879     MinMax.ptMaxSize.x += 2 * xinc;
880     MinMax.ptMaxSize.y += 2 * yinc;
881
882     lpPos = (LPINTERNALPOS)GetPropA( hwnd, atomInternalPos );
883     if( lpPos && !EMPTYPOINT(lpPos->ptMaxPos) )
884         CONV_POINT16TO32( &lpPos->ptMaxPos, &MinMax.ptMaxPosition );
885     else
886     {
887         MinMax.ptMaxPosition.x = -xinc;
888         MinMax.ptMaxPosition.y = -yinc;
889     }
890
891     SendMessageA( hwnd, WM_GETMINMAXINFO, 0, (LPARAM)&MinMax );
892
893       /* Some sanity checks */
894
895     TRACE("%ld %ld / %ld %ld / %ld %ld / %ld %ld\n",
896                       MinMax.ptMaxSize.x, MinMax.ptMaxSize.y,
897                       MinMax.ptMaxPosition.x, MinMax.ptMaxPosition.y,
898                       MinMax.ptMaxTrackSize.x, MinMax.ptMaxTrackSize.y,
899                       MinMax.ptMinTrackSize.x, MinMax.ptMinTrackSize.y);
900     MinMax.ptMaxTrackSize.x = max( MinMax.ptMaxTrackSize.x,
901                                    MinMax.ptMinTrackSize.x );
902     MinMax.ptMaxTrackSize.y = max( MinMax.ptMaxTrackSize.y,
903                                    MinMax.ptMinTrackSize.y );
904
905     if (maxSize) *maxSize = MinMax.ptMaxSize;
906     if (maxPos) *maxPos = MinMax.ptMaxPosition;
907     if (minTrack) *minTrack = MinMax.ptMinTrackSize;
908     if (maxTrack) *maxTrack = MinMax.ptMaxTrackSize;
909 }
910
911 /***********************************************************************
912  *              ShowWindowAsync (USER32.@)
913  *
914  * doesn't wait; returns immediately.
915  * used by threads to toggle windows in other (possibly hanging) threads
916  */
917 BOOL WINAPI ShowWindowAsync( HWND hwnd, INT cmd )
918 {
919     /* FIXME: does ShowWindow() return immediately ? */
920     return ShowWindow(hwnd, cmd);
921 }
922
923
924 /***********************************************************************
925  *              ShowWindow (USER32.@)
926  */
927 BOOL WINAPI ShowWindow( HWND hwnd, INT cmd )
928 {
929     return USER_Driver.pShowWindow( hwnd, cmd );
930 }
931
932
933 /***********************************************************************
934  *              GetInternalWindowPos (USER.460)
935  */
936 UINT16 WINAPI GetInternalWindowPos16( HWND16 hwnd, LPRECT16 rectWnd,
937                                       LPPOINT16 ptIcon )
938 {
939     WINDOWPLACEMENT16 wndpl;
940     if (GetWindowPlacement16( hwnd, &wndpl )) 
941     {
942         if (rectWnd) *rectWnd = wndpl.rcNormalPosition;
943         if (ptIcon)  *ptIcon = wndpl.ptMinPosition;
944         return wndpl.showCmd;
945     }
946     return 0;
947 }
948
949
950 /***********************************************************************
951  *              GetInternalWindowPos (USER32.@)
952  */
953 UINT WINAPI GetInternalWindowPos( HWND hwnd, LPRECT rectWnd,
954                                       LPPOINT ptIcon )
955 {
956     WINDOWPLACEMENT wndpl;
957     if (GetWindowPlacement( hwnd, &wndpl ))
958     {
959         if (rectWnd) *rectWnd = wndpl.rcNormalPosition;
960         if (ptIcon)  *ptIcon = wndpl.ptMinPosition;
961         return wndpl.showCmd;
962     }
963     return 0;
964 }
965
966
967 /***********************************************************************
968  *              GetWindowPlacement (USER32.@)
969  *
970  * Win95:
971  * Fails if wndpl->length of Win95 (!) apps is invalid.
972  */
973 BOOL WINAPI GetWindowPlacement( HWND hwnd, WINDOWPLACEMENT *wndpl )
974 {
975     WND *pWnd = WIN_FindWndPtr( hwnd );
976     LPINTERNALPOS lpPos;
977
978     if(!pWnd ) return FALSE;
979
980     lpPos = WINPOS_InitInternalPos( pWnd, *(LPPOINT)&pWnd->rectWindow.left, &pWnd->rectWindow );
981     wndpl->length  = sizeof(*wndpl);
982     if( pWnd->dwStyle & WS_MINIMIZE )
983         wndpl->showCmd = SW_SHOWMINIMIZED;
984     else
985         wndpl->showCmd = ( pWnd->dwStyle & WS_MAXIMIZE ) ? SW_SHOWMAXIMIZED : SW_SHOWNORMAL ;
986     if( pWnd->flags & WIN_RESTORE_MAX )
987         wndpl->flags = WPF_RESTORETOMAXIMIZED;
988     else
989         wndpl->flags = 0;
990     CONV_POINT16TO32( &lpPos->ptIconPos, &wndpl->ptMinPosition );
991     CONV_POINT16TO32( &lpPos->ptMaxPos, &wndpl->ptMaxPosition );
992     CONV_RECT16TO32( &lpPos->rectNormal, &wndpl->rcNormalPosition );
993     WIN_ReleaseWndPtr(pWnd);
994     return TRUE;
995 }
996
997
998 /***********************************************************************
999  *           WINPOS_SetPlacement
1000  */
1001 static BOOL WINPOS_SetPlacement( HWND hwnd, const WINDOWPLACEMENT *wndpl, UINT flags )
1002 {
1003     WND *pWnd = WIN_FindWndPtr( hwnd );
1004     if( pWnd )
1005     {
1006         LPINTERNALPOS lpPos = (LPINTERNALPOS)WINPOS_InitInternalPos( pWnd,
1007                              *(LPPOINT)&pWnd->rectWindow.left, &pWnd->rectWindow );
1008
1009         if( flags & PLACE_MIN ) CONV_POINT32TO16( &wndpl->ptMinPosition, &lpPos->ptIconPos );
1010         if( flags & PLACE_MAX ) CONV_POINT32TO16( &wndpl->ptMaxPosition, &lpPos->ptMaxPos );
1011         if( flags & PLACE_RECT) CONV_RECT32TO16( &wndpl->rcNormalPosition, &lpPos->rectNormal );
1012
1013         if( pWnd->dwStyle & WS_MINIMIZE )
1014         {
1015             WINPOS_ShowIconTitle( pWnd->hwndSelf, FALSE );
1016             if( wndpl->flags & WPF_SETMINPOSITION && !EMPTYPOINT(lpPos->ptIconPos))
1017                 SetWindowPos( hwnd, 0, lpPos->ptIconPos.x, lpPos->ptIconPos.y,
1018                                 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE );
1019         } 
1020         else if( pWnd->dwStyle & WS_MAXIMIZE )
1021         {
1022             if( !EMPTYPOINT(lpPos->ptMaxPos) )
1023                 SetWindowPos( hwnd, 0, lpPos->ptMaxPos.x, lpPos->ptMaxPos.y,
1024                                 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE );
1025         }
1026         else if( flags & PLACE_RECT )
1027                 SetWindowPos( hwnd, 0, lpPos->rectNormal.left, lpPos->rectNormal.top,
1028                                 lpPos->rectNormal.right - lpPos->rectNormal.left,
1029                                 lpPos->rectNormal.bottom - lpPos->rectNormal.top,
1030                                 SWP_NOZORDER | SWP_NOACTIVATE );
1031
1032         ShowWindow( hwnd, wndpl->showCmd );
1033         if( IsWindow(hwnd) && pWnd->dwStyle & WS_MINIMIZE )
1034         {
1035             if( pWnd->dwStyle & WS_VISIBLE ) WINPOS_ShowIconTitle( pWnd->hwndSelf, TRUE );
1036
1037             /* SDK: ...valid only the next time... */
1038             if( wndpl->flags & WPF_RESTORETOMAXIMIZED ) pWnd->flags |= WIN_RESTORE_MAX;
1039         }
1040         WIN_ReleaseWndPtr(pWnd);
1041         return TRUE;
1042     }
1043     return FALSE;
1044 }
1045
1046
1047 /***********************************************************************
1048  *              SetWindowPlacement (USER32.@)
1049  *
1050  * Win95:
1051  * Fails if wndpl->length of Win95 (!) apps is invalid.
1052  */
1053 BOOL WINAPI SetWindowPlacement( HWND hwnd, const WINDOWPLACEMENT *wpl )
1054 {
1055     if (!wpl) return FALSE;
1056     return WINPOS_SetPlacement( hwnd, wpl, PLACE_MIN | PLACE_MAX | PLACE_RECT );
1057 }
1058
1059
1060 /***********************************************************************
1061  *              AnimateWindow (USER32.@)
1062  *              Shows/Hides a window with an animation
1063  *              NO ANIMATION YET
1064  */
1065 BOOL WINAPI AnimateWindow(HWND hwnd, DWORD dwTime, DWORD dwFlags)
1066 {
1067         FIXME("partial stub\n");
1068
1069         /* If trying to show/hide and it's already   *
1070          * shown/hidden or invalid window, fail with *
1071          * invalid parameter                         */
1072         if(!IsWindow(hwnd) ||
1073            (IsWindowVisible(hwnd) && !(dwFlags & AW_HIDE)) ||
1074            (!IsWindowVisible(hwnd) && (dwFlags & AW_HIDE)))
1075         {
1076                 SetLastError(ERROR_INVALID_PARAMETER);
1077                 return FALSE;
1078         }
1079
1080         ShowWindow(hwnd, (dwFlags & AW_HIDE) ? SW_HIDE : ((dwFlags & AW_ACTIVATE) ? SW_SHOW : SW_SHOWNA));
1081
1082         return TRUE;
1083 }
1084
1085 /***********************************************************************
1086  *              SetInternalWindowPos (USER32.@)
1087  */
1088 void WINAPI SetInternalWindowPos( HWND hwnd, UINT showCmd,
1089                                     LPRECT rect, LPPOINT pt )
1090 {
1091     if( IsWindow(hwnd) )
1092     {
1093         WINDOWPLACEMENT wndpl;
1094         UINT flags;
1095
1096         wndpl.length  = sizeof(wndpl);
1097         wndpl.showCmd = showCmd;
1098         wndpl.flags = flags = 0;
1099
1100         if( pt )
1101         {
1102             flags |= PLACE_MIN;
1103             wndpl.flags |= WPF_SETMINPOSITION;
1104             wndpl.ptMinPosition = *pt;
1105         }
1106         if( rect )
1107         {
1108             flags |= PLACE_RECT;
1109             wndpl.rcNormalPosition = *rect;
1110         }
1111         WINPOS_SetPlacement( hwnd, &wndpl, flags );
1112     }
1113 }
1114
1115 /*******************************************************************
1116  *         WINPOS_SetActiveWindow
1117  *
1118  * SetActiveWindow() back-end. This is the only function that
1119  * can assign active status to a window. It must be called only
1120  * for the top level windows.
1121  */
1122 BOOL WINPOS_SetActiveWindow( HWND hWnd, BOOL fMouse, BOOL fChangeFocus)
1123 {
1124     WND*     wndPtr=0, *wndTemp;
1125     HQUEUE16 hOldActiveQueue, hNewActiveQueue;
1126     MESSAGEQUEUE *pOldActiveQueue = 0, *pNewActiveQueue = 0;
1127     WORD     wIconized = 0;
1128     HWND     hwndActive = 0;
1129     BOOL     bRet = 0;
1130
1131     TRACE("(%04x, %d, %d)\n", hWnd, fMouse, fChangeFocus );
1132
1133     /* Get current active window from the active queue */
1134     if ( hActiveQueue )
1135     {
1136         pOldActiveQueue = QUEUE_Lock( hActiveQueue );
1137         if ( pOldActiveQueue )
1138             hwndActive = PERQDATA_GetActiveWnd( pOldActiveQueue->pQData );
1139     }
1140
1141     if ((wndPtr = WIN_FindWndPtr(hWnd)))
1142         hWnd = wndPtr->hwndSelf;  /* make it a full handle */
1143
1144     /* paranoid checks */
1145     if( hWnd == GetDesktopWindow() || (bRet = (hWnd == hwndActive)) )
1146         goto CLEANUP_END;
1147
1148 /*  if (wndPtr && (GetFastQueue16() != wndPtr->hmemTaskQ))
1149  *      return 0;
1150  */
1151     hOldActiveQueue = hActiveQueue;
1152
1153     if( (wndTemp = WIN_FindWndPtr(hwndActive)) )
1154     {
1155         wIconized = HIWORD(wndTemp->dwStyle & WS_MINIMIZE);
1156         WIN_ReleaseWndPtr(wndTemp);
1157     }
1158     else
1159         TRACE("no current active window.\n");
1160
1161     /* call CBT hook chain */
1162     if (HOOK_IsHooked( WH_CBT ))
1163     {
1164         CBTACTIVATESTRUCT cbt;
1165         cbt.fMouse     = fMouse;
1166         cbt.hWndActive = hwndActive;
1167         if (HOOK_CallHooksA( WH_CBT, HCBT_ACTIVATE, (WPARAM)hWnd, (LPARAM)&cbt )) goto CLEANUP_END;
1168     }
1169
1170     /* set prev active wnd to current active wnd and send notification */
1171     if ((hwndPrevActive = hwndActive) && IsWindow(hwndPrevActive))
1172     {
1173         MESSAGEQUEUE *pTempActiveQueue = 0;
1174         
1175         if (!SendMessageA( hwndPrevActive, WM_NCACTIVATE, FALSE, 0 ))
1176         {
1177             if (GetSysModalWindow16() != WIN_Handle16(hWnd)) goto CLEANUP_END;
1178             /* disregard refusal if hWnd is sysmodal */
1179         }
1180
1181         SendMessageA( hwndPrevActive, WM_ACTIVATE,
1182                         MAKEWPARAM( WA_INACTIVE, wIconized ),
1183                         (LPARAM)hWnd );
1184
1185         /* check if something happened during message processing
1186          * (global active queue may have changed)
1187          */
1188         pTempActiveQueue = QUEUE_Lock( hActiveQueue );
1189         if(!pTempActiveQueue)
1190             goto CLEANUP_END;
1191
1192         hwndActive = PERQDATA_GetActiveWnd( pTempActiveQueue->pQData );
1193         QUEUE_Unlock( pTempActiveQueue );
1194         if( hwndPrevActive != hwndActive )
1195             goto CLEANUP_END;
1196     }
1197
1198     /* Set new active window in the message queue */
1199     hwndActive = hWnd;
1200     if ( wndPtr )
1201     {
1202         pNewActiveQueue = QUEUE_Lock( wndPtr->hmemTaskQ );
1203         if ( pNewActiveQueue )
1204             PERQDATA_SetActiveWnd( pNewActiveQueue->pQData, hwndActive );
1205     }
1206     else /* have to do this or MDI frame activation goes to hell */
1207         if( pOldActiveQueue )
1208             PERQDATA_SetActiveWnd( pOldActiveQueue->pQData, 0 );
1209
1210     /* send palette messages */
1211     if (hWnd && SendMessageW( hWnd, WM_QUERYNEWPALETTE, 0, 0L))
1212         SendMessageW( HWND_BROADCAST, WM_PALETTEISCHANGING, (WPARAM)hWnd, 0 );
1213
1214     /* if prev wnd is minimized redraw icon title */
1215     if( IsIconic( hwndPrevActive ) ) WINPOS_RedrawIconTitle(hwndPrevActive);
1216
1217     /* managed windows will get ConfigureNotify event */  
1218     if (wndPtr && !(wndPtr->dwStyle & WS_CHILD) && !(wndPtr->dwExStyle & WS_EX_MANAGED))
1219     {
1220         /* check Z-order and bring hWnd to the top */
1221         HWND tmp = GetTopWindow(0);
1222         while (tmp && !(GetWindowLongA( tmp, GWL_STYLE ) & WS_VISIBLE))
1223             tmp = GetWindow( tmp, GW_HWNDNEXT );
1224
1225         if( tmp != hWnd )
1226             SetWindowPos(hWnd, HWND_TOP, 0,0,0,0, 
1227                            SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE );
1228         if (!IsWindow(hWnd))  
1229             goto CLEANUP;
1230     }
1231
1232     /* Get a handle to the new active queue */
1233     hNewActiveQueue = wndPtr ? wndPtr->hmemTaskQ : 0;
1234
1235     /* send WM_ACTIVATEAPP if necessary */
1236     if (hOldActiveQueue != hNewActiveQueue)
1237     {
1238         HWND *list, *phwnd;
1239         DWORD old_thread = GetWindowThreadProcessId( hwndPrevActive, NULL );
1240         DWORD new_thread = GetWindowThreadProcessId( hwndActive, NULL );
1241
1242         if ((list = WIN_ListChildren( GetDesktopWindow() )))
1243         {
1244             for (phwnd = list; *phwnd; phwnd++)
1245             {
1246                 if (!IsWindow( *phwnd )) continue;
1247                 if (GetWindowThreadProcessId( *phwnd, NULL ) == old_thread)
1248                     SendMessageW( *phwnd, WM_ACTIVATEAPP, 0, new_thread );
1249             }
1250             HeapFree( GetProcessHeap(), 0, list );
1251         }
1252
1253         hActiveQueue = hNewActiveQueue;
1254
1255         if ((list = WIN_ListChildren( GetDesktopWindow() )))
1256         {
1257             for (phwnd = list; *phwnd; phwnd++)
1258             {
1259                 if (!IsWindow( *phwnd )) continue;
1260                 if (GetWindowThreadProcessId( *phwnd, NULL ) == new_thread)
1261                     SendMessageW( *phwnd, WM_ACTIVATEAPP, 1, old_thread );
1262             }
1263             HeapFree( GetProcessHeap(), 0, list );
1264         }
1265         
1266         if (hWnd && !IsWindow(hWnd)) goto CLEANUP;
1267     }
1268
1269     if (hWnd)
1270     {
1271         /* walk up to the first unowned window */
1272         HWND tmp = GetAncestor( hWnd, GA_ROOTOWNER );
1273         wndTemp = WIN_FindWndPtr( tmp );
1274         /* and set last active owned popup */
1275         wndTemp->hwndLastActive = hWnd;
1276
1277         wIconized = HIWORD(wndTemp->dwStyle & WS_MINIMIZE);
1278         WIN_ReleaseWndPtr(wndTemp);
1279         SendMessageA( hWnd, WM_NCACTIVATE, TRUE, 0 );
1280         SendMessageA( hWnd, WM_ACTIVATE,
1281                  MAKEWPARAM( (fMouse) ? WA_CLICKACTIVE : WA_ACTIVE, wIconized),
1282                  (LPARAM)hwndPrevActive );
1283         if( !IsWindow(hWnd) ) goto CLEANUP;
1284     }
1285
1286     /* change focus if possible */
1287     if ( fChangeFocus )
1288     {
1289         if ( pNewActiveQueue )
1290         {
1291             HWND hOldFocus = PERQDATA_GetFocusWnd( pNewActiveQueue->pQData );
1292
1293             if ( hOldFocus && GetAncestor( hOldFocus, GA_ROOT ) != hwndActive )
1294                 FOCUS_SwitchFocus( pNewActiveQueue, hOldFocus, 
1295                                    (wndPtr && (wndPtr->dwStyle & WS_MINIMIZE))?
1296                                    0 : hwndActive );
1297         }
1298
1299         if ( pOldActiveQueue && 
1300              ( !pNewActiveQueue || 
1301                 pNewActiveQueue->pQData != pOldActiveQueue->pQData ) )
1302         {
1303             HWND hOldFocus = PERQDATA_GetFocusWnd( pOldActiveQueue->pQData );
1304             if ( hOldFocus )
1305                 FOCUS_SwitchFocus( pOldActiveQueue, hOldFocus, 0 );
1306         }
1307     }
1308
1309     if( !hwndPrevActive && wndPtr )
1310     {
1311         if (USER_Driver.pForceWindowRaise) USER_Driver.pForceWindowRaise( wndPtr->hwndSelf );
1312     }
1313
1314     /* if active wnd is minimized redraw icon title */
1315     if( IsIconic(hwndActive) ) WINPOS_RedrawIconTitle(hwndActive);
1316
1317     bRet = (hWnd == hwndActive);  /* Success? */
1318     
1319 CLEANUP: /* Unlock the message queues before returning */
1320
1321     if ( pNewActiveQueue )
1322         QUEUE_Unlock( pNewActiveQueue );
1323
1324 CLEANUP_END:
1325
1326     if ( pOldActiveQueue )
1327         QUEUE_Unlock( pOldActiveQueue );
1328
1329     WIN_ReleaseWndPtr(wndPtr);
1330     return bRet;
1331 }
1332
1333 /*******************************************************************
1334  *         WINPOS_ActivateOtherWindow
1335  *
1336  *  Activates window other than pWnd.
1337  */
1338 BOOL WINPOS_ActivateOtherWindow(HWND hwnd)
1339 {
1340     BOOL bRet = 0;
1341     WND *pWnd;
1342     HWND hwndActive = 0;
1343     HWND hwndTo = 0;
1344     HWND owner;
1345
1346     /* Get current active window from the active queue */
1347     if ( hActiveQueue )
1348     {
1349         MESSAGEQUEUE *pActiveQueue = QUEUE_Lock( hActiveQueue );
1350         if ( pActiveQueue )
1351         {
1352             hwndActive = PERQDATA_GetActiveWnd( pActiveQueue->pQData );
1353             QUEUE_Unlock( pActiveQueue );
1354         }
1355     }
1356
1357     pWnd = WIN_FindWndPtr( hwnd );
1358     hwnd = pWnd->hwndSelf;
1359
1360     if( hwnd == hwndPrevActive )
1361         hwndPrevActive = 0;
1362
1363     if( hwndActive != hwnd &&
1364         ( hwndActive || QUEUE_IsExitingQueue(pWnd->hmemTaskQ)) )
1365     {
1366         WIN_ReleaseWndPtr( pWnd );
1367         return 0;
1368     }
1369
1370     owner = GetWindow( hwnd, GW_OWNER );
1371     if( !(pWnd->dwStyle & WS_POPUP) || !owner ||
1372         !WINPOS_CanActivate((hwndTo = GetAncestor( owner, GA_ROOT ))) )
1373     {
1374         HWND tmp = GetAncestor( hwnd, GA_ROOT );
1375         hwndTo = hwndPrevActive;
1376
1377         while( !WINPOS_CanActivate(hwndTo) )
1378         {
1379             /* by now owned windows should've been taken care of */
1380             tmp = hwndTo = GetWindow( tmp, GW_HWNDNEXT );
1381             if( !hwndTo ) break;
1382         }
1383     }
1384     WIN_ReleaseWndPtr( pWnd );
1385
1386     bRet = WINPOS_SetActiveWindow( hwndTo, FALSE, TRUE );
1387
1388     hwndPrevActive = 0;
1389     return bRet;
1390 }
1391
1392 /*******************************************************************
1393  *         WINPOS_ChangeActiveWindow
1394  *
1395  */
1396 BOOL WINPOS_ChangeActiveWindow( HWND hWnd, BOOL mouseMsg )
1397 {
1398     WND *wndPtr;
1399     HWND hwndActive = 0;
1400
1401     /* Get current active window from the active queue */
1402     if ( hActiveQueue )
1403     {
1404         MESSAGEQUEUE *pActiveQueue = QUEUE_Lock( hActiveQueue );
1405         if ( pActiveQueue )
1406         {
1407             hwndActive = PERQDATA_GetActiveWnd( pActiveQueue->pQData );
1408             QUEUE_Unlock( pActiveQueue );
1409         }
1410     }
1411
1412     if (!hWnd)
1413         return WINPOS_SetActiveWindow( 0, mouseMsg, TRUE );
1414
1415     if (!(wndPtr = WIN_FindWndPtr(hWnd))) return FALSE;
1416     hWnd = wndPtr->hwndSelf;
1417
1418     /* child windows get WM_CHILDACTIVATE message */
1419     if( (wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) == WS_CHILD )
1420     {
1421         WIN_ReleaseWndPtr(wndPtr);
1422         return SendMessageA(hWnd, WM_CHILDACTIVATE, 0, 0L);
1423     }
1424     WIN_ReleaseWndPtr(wndPtr);
1425
1426     if( hWnd == hwndActive ) return FALSE;
1427
1428     return WINPOS_SetActiveWindow(hWnd ,mouseMsg ,TRUE);
1429 }
1430
1431
1432 /***********************************************************************
1433  *           WINPOS_SendNCCalcSize
1434  *
1435  * Send a WM_NCCALCSIZE message to a window.
1436  * All parameters are read-only except newClientRect.
1437  * oldWindowRect, oldClientRect and winpos must be non-NULL only
1438  * when calcValidRect is TRUE.
1439  */
1440 LONG WINPOS_SendNCCalcSize( HWND hwnd, BOOL calcValidRect,
1441                             RECT *newWindowRect, RECT *oldWindowRect,
1442                             RECT *oldClientRect, WINDOWPOS *winpos,
1443                             RECT *newClientRect )
1444 {
1445     NCCALCSIZE_PARAMS params;
1446     WINDOWPOS winposCopy;
1447     LONG result;
1448
1449     params.rgrc[0] = *newWindowRect;
1450     if (calcValidRect)
1451     {
1452         winposCopy = *winpos;
1453         params.rgrc[1] = *oldWindowRect;
1454         params.rgrc[2] = *oldClientRect;
1455         params.lppos = &winposCopy;
1456     }
1457     result = SendMessageA( hwnd, WM_NCCALCSIZE, calcValidRect,
1458                              (LPARAM)&params );
1459     TRACE("%d,%d-%d,%d\n",
1460                  params.rgrc[0].left, params.rgrc[0].top,
1461                  params.rgrc[0].right, params.rgrc[0].bottom );
1462
1463     /* If the application send back garbage, ignore it */
1464     if (params.rgrc[0].left <= params.rgrc[0].right && params.rgrc[0].top <= params.rgrc[0].bottom)
1465         *newClientRect = params.rgrc[0];
1466
1467     return result;
1468 }
1469
1470
1471 /***********************************************************************
1472  *           WINPOS_HandleWindowPosChanging16
1473  *
1474  * Default handling for a WM_WINDOWPOSCHANGING. Called from DefWindowProc().
1475  */
1476 LONG WINPOS_HandleWindowPosChanging16( HWND hwnd, WINDOWPOS16 *winpos )
1477 {
1478     POINT maxSize, minTrack;
1479     LONG style = GetWindowLongA( hwnd, GWL_STYLE );
1480
1481     if (winpos->flags & SWP_NOSIZE) return 0;
1482     if ((style & WS_THICKFRAME) || ((style & (WS_POPUP | WS_CHILD)) == 0))
1483     {
1484         WINPOS_GetMinMaxInfo( hwnd, &maxSize, NULL, &minTrack, NULL );
1485         if (maxSize.x < winpos->cx) winpos->cx = maxSize.x;
1486         if (maxSize.y < winpos->cy) winpos->cy = maxSize.y;
1487         if (!(style & WS_MINIMIZE))
1488         {
1489             if (winpos->cx < minTrack.x ) winpos->cx = minTrack.x;
1490             if (winpos->cy < minTrack.y ) winpos->cy = minTrack.y;
1491         }
1492     }
1493     return 0;
1494 }
1495
1496
1497 /***********************************************************************
1498  *           WINPOS_HandleWindowPosChanging
1499  *
1500  * Default handling for a WM_WINDOWPOSCHANGING. Called from DefWindowProc().
1501  */
1502 LONG WINPOS_HandleWindowPosChanging( HWND hwnd, WINDOWPOS *winpos )
1503 {
1504     POINT maxSize, minTrack;
1505     LONG style = GetWindowLongA( hwnd, GWL_STYLE );
1506
1507     if (winpos->flags & SWP_NOSIZE) return 0;
1508     if ((style & WS_THICKFRAME) || ((style & (WS_POPUP | WS_CHILD)) == 0))
1509     {
1510         WINPOS_GetMinMaxInfo( hwnd, &maxSize, NULL, &minTrack, NULL );
1511         winpos->cx = min( winpos->cx, maxSize.x );
1512         winpos->cy = min( winpos->cy, maxSize.y );
1513         if (!(style & WS_MINIMIZE))
1514         {
1515             if (winpos->cx < minTrack.x ) winpos->cx = minTrack.x;
1516             if (winpos->cy < minTrack.y ) winpos->cy = minTrack.y;
1517         }
1518     }
1519     return 0;
1520 }
1521
1522
1523 /***********************************************************************
1524  *              SetWindowPos (USER32.@)
1525  */
1526 BOOL WINAPI SetWindowPos( HWND hwnd, HWND hwndInsertAfter,
1527                           INT x, INT y, INT cx, INT cy, UINT flags )
1528 {
1529     WINDOWPOS winpos;
1530
1531     winpos.hwnd = hwnd;
1532     winpos.hwndInsertAfter = hwndInsertAfter;
1533     winpos.x = x;
1534     winpos.y = y;
1535     winpos.cx = cx;
1536     winpos.cy = cy;
1537     winpos.flags = flags;
1538     return USER_Driver.pSetWindowPos( &winpos );
1539 }
1540
1541
1542 /***********************************************************************
1543  *              BeginDeferWindowPos (USER32.@)
1544  */
1545 HDWP WINAPI BeginDeferWindowPos( INT count )
1546 {
1547     HDWP handle;
1548     DWP *pDWP;
1549
1550     if (count < 0) 
1551     {
1552         SetLastError(ERROR_INVALID_PARAMETER);
1553         return 0;
1554     }
1555     /* Windows allows zero count, in which case it allocates context for 8 moves */
1556     if (count == 0) count = 8;
1557
1558     handle = USER_HEAP_ALLOC( sizeof(DWP) + (count-1)*sizeof(WINDOWPOS) );
1559     if (!handle) return 0;
1560     pDWP = (DWP *) USER_HEAP_LIN_ADDR( handle );
1561     pDWP->actualCount    = 0;
1562     pDWP->suggestedCount = count;
1563     pDWP->valid          = TRUE;
1564     pDWP->wMagic         = DWP_MAGIC;
1565     pDWP->hwndParent     = 0;
1566     return handle;
1567 }
1568
1569
1570 /***********************************************************************
1571  *              DeferWindowPos (USER32.@)
1572  */
1573 HDWP WINAPI DeferWindowPos( HDWP hdwp, HWND hwnd, HWND hwndAfter,
1574                                 INT x, INT y, INT cx, INT cy,
1575                                 UINT flags )
1576 {
1577     DWP *pDWP;
1578     int i;
1579     HDWP newhdwp = hdwp,retvalue;
1580     /* HWND parent; */
1581     WND *pWnd;
1582
1583     hwnd = WIN_GetFullHandle( hwnd );
1584     if (hwnd == GetDesktopWindow()) return 0;
1585
1586     if (!(pDWP = USER_HEAP_LIN_ADDR( hdwp ))) return 0;
1587
1588     if (!(pWnd = WIN_FindWndPtr( hwnd ))) return 0;
1589
1590 /* Numega Bounds Checker Demo dislikes the following code.
1591    In fact, I've not been able to find any "same parent" requirement in any docu
1592    [AM 980509]
1593  */
1594 #if 0
1595     /* All the windows of a DeferWindowPos() must have the same parent */
1596     parent = pWnd->parent->hwndSelf;
1597     if (pDWP->actualCount == 0) pDWP->hwndParent = parent;
1598     else if (parent != pDWP->hwndParent)
1599     {
1600         USER_HEAP_FREE( hdwp );
1601         retvalue = 0;
1602         goto END;
1603     }
1604 #endif
1605
1606     for (i = 0; i < pDWP->actualCount; i++)
1607     {
1608         if (pDWP->winPos[i].hwnd == hwnd)
1609         {
1610               /* Merge with the other changes */
1611             if (!(flags & SWP_NOZORDER))
1612             {
1613                 pDWP->winPos[i].hwndInsertAfter = hwndAfter;
1614             }
1615             if (!(flags & SWP_NOMOVE))
1616             {
1617                 pDWP->winPos[i].x = x;
1618                 pDWP->winPos[i].y = y;
1619             }                
1620             if (!(flags & SWP_NOSIZE))
1621             {
1622                 pDWP->winPos[i].cx = cx;
1623                 pDWP->winPos[i].cy = cy;
1624             }
1625             pDWP->winPos[i].flags &= flags | ~(SWP_NOSIZE | SWP_NOMOVE |
1626                                                SWP_NOZORDER | SWP_NOREDRAW |
1627                                                SWP_NOACTIVATE | SWP_NOCOPYBITS|
1628                                                SWP_NOOWNERZORDER);
1629             pDWP->winPos[i].flags |= flags & (SWP_SHOWWINDOW | SWP_HIDEWINDOW |
1630                                               SWP_FRAMECHANGED);
1631             retvalue = hdwp;
1632             goto END;
1633         }
1634     }
1635     if (pDWP->actualCount >= pDWP->suggestedCount)
1636     {
1637         newhdwp = USER_HEAP_REALLOC( hdwp,
1638                       sizeof(DWP) + pDWP->suggestedCount*sizeof(WINDOWPOS) );
1639         if (!newhdwp)
1640         {
1641             retvalue = 0;
1642             goto END;
1643         }
1644         pDWP = (DWP *) USER_HEAP_LIN_ADDR( newhdwp );
1645         pDWP->suggestedCount++;
1646     }
1647     pDWP->winPos[pDWP->actualCount].hwnd = hwnd;
1648     pDWP->winPos[pDWP->actualCount].hwndInsertAfter = hwndAfter;
1649     pDWP->winPos[pDWP->actualCount].x = x;
1650     pDWP->winPos[pDWP->actualCount].y = y;
1651     pDWP->winPos[pDWP->actualCount].cx = cx;
1652     pDWP->winPos[pDWP->actualCount].cy = cy;
1653     pDWP->winPos[pDWP->actualCount].flags = flags;
1654     pDWP->actualCount++;
1655     retvalue = newhdwp;
1656 END:
1657     WIN_ReleaseWndPtr(pWnd);
1658     return retvalue;
1659 }
1660
1661
1662 /***********************************************************************
1663  *              EndDeferWindowPos (USER32.@)
1664  */
1665 BOOL WINAPI EndDeferWindowPos( HDWP hdwp )
1666 {
1667     DWP *pDWP;
1668     WINDOWPOS *winpos;
1669     BOOL res = TRUE;
1670     int i;
1671
1672     pDWP = (DWP *) USER_HEAP_LIN_ADDR( hdwp );
1673     if (!pDWP) return FALSE;
1674     for (i = 0, winpos = pDWP->winPos; i < pDWP->actualCount; i++, winpos++)
1675     {
1676         if (!(res = USER_Driver.pSetWindowPos( winpos ))) break;
1677     }
1678     USER_HEAP_FREE( hdwp );
1679     return res;
1680 }
1681
1682
1683 /***********************************************************************
1684  *              TileChildWindows (USER.199)
1685  */
1686 void WINAPI TileChildWindows16( HWND16 parent, WORD action )
1687 {
1688     FIXME("(%04x, %d): stub\n", parent, action);
1689 }
1690
1691 /***********************************************************************
1692  *              CascadeChildWindows (USER.198)
1693  */
1694 void WINAPI CascadeChildWindows16( HWND16 parent, WORD action )
1695 {
1696     FIXME("(%04x, %d): stub\n", parent, action);
1697 }
1698
1699 /***********************************************************************
1700  *              SetProgmanWindow (USER32.@)
1701  */
1702 HWND WINAPI SetProgmanWindow ( HWND hwnd )
1703 {
1704         hGlobalProgmanWindow = hwnd;
1705         return hGlobalProgmanWindow;
1706 }
1707
1708 /***********************************************************************
1709  *              GetProgmanWindow (USER32.@)
1710  */
1711 HWND WINAPI GetProgmanWindow(void)
1712 {
1713         return hGlobalProgmanWindow;
1714 }
1715
1716 /***********************************************************************
1717  *              SetShellWindowEx (USER32.@)
1718  * hwndProgman =  Progman[Program Manager]
1719  *                |-> SHELLDLL_DefView
1720  * hwndListView = |   |-> SysListView32
1721  *                |   |   |-> tooltips_class32
1722  *                |   |
1723  *                |   |-> SysHeader32
1724  *                |   
1725  *                |-> ProxyTarget
1726  */
1727 HWND WINAPI SetShellWindowEx ( HWND hwndProgman, HWND hwndListView )
1728 {
1729         FIXME("0x%08x 0x%08x stub\n",hwndProgman ,hwndListView );
1730         hGlobalShellWindow = hwndProgman;
1731         return hGlobalShellWindow;
1732
1733 }
1734
1735 /***********************************************************************
1736  *              SetTaskmanWindow (USER32.@)
1737  * NOTES
1738  *   hwnd = MSTaskSwWClass 
1739  *          |-> SysTabControl32
1740  */
1741 HWND WINAPI SetTaskmanWindow ( HWND hwnd )
1742 {
1743         hGlobalTaskmanWindow = hwnd;
1744         return hGlobalTaskmanWindow;
1745 }
1746
1747 /***********************************************************************
1748  *              GetTaskmanWindow (USER32.@)
1749  */
1750 HWND WINAPI GetTaskmanWindow(void)
1751 {
1752         return hGlobalTaskmanWindow;
1753 }