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