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