Always draw the main item in full row select.
[wine] / dlls / ttydrv / wnd.c
1 /*
2  * TTY window driver
3  *
4  * Copyright 1998,1999 Patrik Stridvall
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "config.h"
22
23 #include "gdi.h"
24 #include "ttydrv.h"
25 #include "win.h"
26 #include "winpos.h"
27 #include "wine/debug.h"
28 #include "hook.h"
29
30 WINE_DEFAULT_DEBUG_CHANNEL(ttydrv);
31
32 #define SWP_AGG_NOGEOMETRYCHANGE \
33     (SWP_NOSIZE | SWP_NOMOVE | SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE)
34 #define SWP_AGG_NOPOSCHANGE \
35     (SWP_AGG_NOGEOMETRYCHANGE | SWP_NOZORDER)
36 #define SWP_AGG_STATUSFLAGS \
37     (SWP_AGG_NOPOSCHANGE | SWP_FRAMECHANGED | SWP_HIDEWINDOW | SWP_SHOWWINDOW)
38
39 /**********************************************************************
40  *              CreateWindow   (TTYDRV.@)
41  */
42 BOOL TTYDRV_CreateWindow( HWND hwnd, CREATESTRUCTA *cs, BOOL unicode )
43 {
44     BOOL ret;
45     HWND hwndLinkAfter;
46
47 #ifdef WINE_CURSES
48     WND *wndPtr = WIN_GetPtr( hwnd );
49     WINDOW *window;
50     INT cellWidth=8, cellHeight=8; /* FIXME: Hardcoded */
51
52     TRACE("(%x)\n", hwnd);
53
54     /* Only create top-level windows */
55     if (!(wndPtr->dwStyle & WS_CHILD))
56     {
57         if (!wndPtr->parent)  /* desktop */
58             window = root_window;
59         else
60         {
61             int x = wndPtr->rectWindow.left;
62             int y = wndPtr->rectWindow.top;
63             int cx = wndPtr->rectWindow.right - wndPtr->rectWindow.left;
64             int cy = wndPtr->rectWindow.bottom - wndPtr->rectWindow.top;
65
66             window = subwin( root_window, cy/cellHeight, cx/cellWidth,
67                              y/cellHeight, x/cellWidth);
68             werase(window);
69             wrefresh(window);
70         }
71         wndPtr->pDriverData = window;
72     }
73     WIN_ReleasePtr( wndPtr );
74 #else /* defined(WINE_CURSES) */
75     FIXME("(%x): stub\n", hwnd);
76 #endif /* defined(WINE_CURSES) */
77
78     /* Call the WH_CBT hook */
79
80     hwndLinkAfter = ((cs->style & (WS_CHILD|WS_MAXIMIZE)) == WS_CHILD)
81  ? HWND_BOTTOM : HWND_TOP;
82
83     if (HOOK_IsHooked( WH_CBT ))
84     {
85         CBT_CREATEWNDA cbtc;
86         LRESULT lret;
87
88         cbtc.lpcs = cs;
89         cbtc.hwndInsertAfter = hwndLinkAfter;
90         lret = (unicode) ? HOOK_CallHooksW(WH_CBT, HCBT_CREATEWND,
91                                                        (WPARAM)hwnd, (LPARAM)&cbtc)
92                         : HOOK_CallHooksA(WH_CBT, HCBT_CREATEWND,
93                                                        (WPARAM)hwnd, (LPARAM)&cbtc);
94         if (lret)
95         {
96             TRACE("CBT-hook returned !0\n");
97             return FALSE;
98         }
99     }
100
101     if (unicode)
102     {
103         ret = SendMessageW( hwnd, WM_NCCREATE, 0, (LPARAM)cs );
104         if (ret) ret = (SendMessageW( hwnd, WM_CREATE, 0, (LPARAM)cs ) != -1);
105     }
106     else
107     {
108         ret = SendMessageA( hwnd, WM_NCCREATE, 0, (LPARAM)cs );
109         if (ret) ret = (SendMessageA( hwnd, WM_CREATE, 0, (LPARAM)cs ) != -1);
110     }
111     return ret;
112 }
113
114 /***********************************************************************
115  *              DestroyWindow   (TTYDRV.@)
116  */
117 BOOL TTYDRV_DestroyWindow( HWND hwnd )
118 {
119 #ifdef WINE_CURSES
120     WND *wndPtr = WIN_GetPtr( hwnd );
121     WINDOW *window = wndPtr->pDriverData;
122
123     TRACE("(%x)\n", hwnd);
124
125     if (window && window != root_window) delwin(window);
126     wndPtr->pDriverData = NULL;
127     WIN_ReleasePtr( wndPtr );
128 #else /* defined(WINE_CURSES) */
129     FIXME("(%x): stub\n", hwnd);
130 #endif /* defined(WINE_CURSES) */
131     return TRUE;
132 }
133
134
135 /***********************************************************************
136  *           DCE_GetVisRect
137  *
138  * Calculate the visible rectangle of a window (i.e. the client or
139  * window area clipped by the client area of all ancestors) in the
140  * corresponding coordinates. Return FALSE if the visible region is empty.
141  */
142 static BOOL DCE_GetVisRect( WND *wndPtr, BOOL clientArea, RECT *lprect )
143 {
144     *lprect = clientArea ? wndPtr->rectClient : wndPtr->rectWindow;
145
146     if (wndPtr->dwStyle & WS_VISIBLE)
147     {
148         INT xoffset = lprect->left;
149         INT yoffset = lprect->top;
150
151         while ((wndPtr = WIN_FindWndPtr( GetAncestor(wndPtr->hwndSelf,GA_PARENT) )))
152         {
153             if ( (wndPtr->dwStyle & (WS_ICONIC | WS_VISIBLE)) != WS_VISIBLE )
154             {
155                 WIN_ReleaseWndPtr(wndPtr);
156                 goto fail;
157             }
158
159             xoffset += wndPtr->rectClient.left;
160             yoffset += wndPtr->rectClient.top;
161             OffsetRect( lprect, wndPtr->rectClient.left,
162                         wndPtr->rectClient.top );
163
164             if( (wndPtr->rectClient.left >= wndPtr->rectClient.right) ||
165                 (wndPtr->rectClient.top >= wndPtr->rectClient.bottom) ||
166                 (lprect->left >= wndPtr->rectClient.right) ||
167                 (lprect->right <= wndPtr->rectClient.left) ||
168                 (lprect->top >= wndPtr->rectClient.bottom) ||
169                 (lprect->bottom <= wndPtr->rectClient.top) )
170             {
171                 WIN_ReleaseWndPtr(wndPtr);
172                 goto fail;
173             }
174
175             lprect->left = max( lprect->left, wndPtr->rectClient.left );
176             lprect->right = min( lprect->right, wndPtr->rectClient.right );
177             lprect->top = max( lprect->top, wndPtr->rectClient.top );
178             lprect->bottom = min( lprect->bottom, wndPtr->rectClient.bottom );
179
180             WIN_ReleaseWndPtr(wndPtr);
181         }
182         OffsetRect( lprect, -xoffset, -yoffset );
183         return TRUE;
184     }
185
186 fail:
187     SetRectEmpty( lprect );
188     return FALSE;
189 }
190
191
192 /***********************************************************************
193  *           DCE_AddClipRects
194  *
195  * Go through the linked list of windows from pWndStart to pWndEnd,
196  * adding to the clip region the intersection of the target rectangle
197  * with an offset window rectangle.
198  */
199 static void DCE_AddClipRects( HWND parent, HWND end, HRGN hrgnClip, LPRECT lpRect, int x, int y )
200 {
201     RECT rect;
202     WND *pWnd;
203     int i;
204     HWND *list = WIN_ListChildren( parent );
205     HRGN hrgn = 0;
206
207     if (!list) return;
208     for (i = 0; list[i]; i++)
209     {
210         if (list[i] == end) break;
211         if (!(pWnd = WIN_FindWndPtr( list[i] ))) continue;
212         if (pWnd->dwStyle & WS_VISIBLE)
213         {
214             rect.left = pWnd->rectWindow.left + x;
215             rect.top = pWnd->rectWindow.top + y;
216             rect.right = pWnd->rectWindow.right + x;
217             rect.bottom = pWnd->rectWindow.bottom + y;
218             if( IntersectRect( &rect, &rect, lpRect ))
219             {
220                 if (!hrgn) hrgn = CreateRectRgnIndirect( &rect );
221                 else SetRectRgn( hrgn, rect.left, rect.top, rect.right, rect.bottom );
222                 CombineRgn( hrgnClip, hrgnClip, hrgn, RGN_OR );
223             }
224         }
225         WIN_ReleaseWndPtr( pWnd );
226     }
227     if (hrgn) DeleteObject( hrgn );
228     HeapFree( GetProcessHeap(), 0, list );
229 }
230
231
232 /***********************************************************************
233  *           DCE_GetVisRgn
234  *
235  * Return the visible region of a window, i.e. the client or window area
236  * clipped by the client area of all ancestors, and then optionally
237  * by siblings and children.
238  */
239 static HRGN DCE_GetVisRgn( HWND hwnd, WORD flags, HWND hwndChild, WORD cflags )
240 {
241     HRGN hrgnVis = 0;
242     RECT rect;
243     WND *wndPtr = WIN_FindWndPtr( hwnd );
244     WND *childWnd = WIN_FindWndPtr( hwndChild );
245
246     /* Get visible rectangle and create a region with it. */
247
248     if (wndPtr && DCE_GetVisRect(wndPtr, !(flags & DCX_WINDOW), &rect))
249     {
250         if((hrgnVis = CreateRectRgnIndirect( &rect )))
251         {
252             HRGN hrgnClip = CreateRectRgn( 0, 0, 0, 0 );
253             INT xoffset, yoffset;
254
255             if( hrgnClip )
256             {
257                 /* Compute obscured region for the visible rectangle by
258                  * clipping children, siblings, and ancestors. Note that
259                  * DCE_GetVisRect() returns a rectangle either in client
260                  * or in window coordinates (for DCX_WINDOW request). */
261
262                 if (flags & DCX_CLIPCHILDREN)
263                 {
264                     if( flags & DCX_WINDOW )
265                     {
266                         /* adjust offsets since child window rectangles are
267                          * in client coordinates */
268
269                         xoffset = wndPtr->rectClient.left - wndPtr->rectWindow.left;
270                         yoffset = wndPtr->rectClient.top - wndPtr->rectWindow.top;
271                     }
272                     else
273                         xoffset = yoffset = 0;
274
275                     DCE_AddClipRects( wndPtr->hwndSelf, 0, hrgnClip, &rect, xoffset, yoffset );
276                 }
277
278                 /* We may need to clip children of child window, if a window with PARENTDC
279                  * class style and CLIPCHILDREN window style (like in Free Agent 16
280                  * preference dialogs) gets here, we take the region for the parent window
281                  * but apparently still need to clip the children of the child window... */
282
283                 if( (cflags & DCX_CLIPCHILDREN) && childWnd)
284                 {
285                     if( flags & DCX_WINDOW )
286                     {
287                         /* adjust offsets since child window rectangles are
288                          * in client coordinates */
289
290                         xoffset = wndPtr->rectClient.left - wndPtr->rectWindow.left;
291                         yoffset = wndPtr->rectClient.top - wndPtr->rectWindow.top;
292                     }
293                     else
294                         xoffset = yoffset = 0;
295
296                     /* client coordinates of child window */
297                     xoffset += childWnd->rectClient.left;
298                     yoffset += childWnd->rectClient.top;
299
300                     DCE_AddClipRects( childWnd->hwndSelf, 0, hrgnClip,
301                                       &rect, xoffset, yoffset );
302                 }
303
304                 /* sibling window rectangles are in client
305                  * coordinates of the parent window */
306
307                 if (flags & DCX_WINDOW)
308                 {
309                     xoffset = -wndPtr->rectWindow.left;
310                     yoffset = -wndPtr->rectWindow.top;
311                 }
312                 else
313                 {
314                     xoffset = -wndPtr->rectClient.left;
315                     yoffset = -wndPtr->rectClient.top;
316                 }
317
318                 if (flags & DCX_CLIPSIBLINGS && wndPtr->parent )
319                     DCE_AddClipRects( wndPtr->parent, wndPtr->hwndSelf,
320                                       hrgnClip, &rect, xoffset, yoffset );
321
322                 /* Clip siblings of all ancestors that have the
323                  * WS_CLIPSIBLINGS style
324                  */
325
326                 while (wndPtr->parent)
327                 {
328                     WND *ptr = WIN_FindWndPtr( wndPtr->parent );
329                     WIN_ReleaseWndPtr( wndPtr );
330                     wndPtr = ptr;
331                     xoffset -= wndPtr->rectClient.left;
332                     yoffset -= wndPtr->rectClient.top;
333                     if(wndPtr->dwStyle & WS_CLIPSIBLINGS && wndPtr->parent)
334                     {
335                         DCE_AddClipRects( wndPtr->parent, wndPtr->hwndSelf,
336                                           hrgnClip, &rect, xoffset, yoffset );
337                     }
338                 }
339
340                 /* Now once we've got a jumbo clip region we have
341                  * to substract it from the visible rectangle.
342                  */
343                 CombineRgn( hrgnVis, hrgnVis, hrgnClip, RGN_DIFF );
344                 DeleteObject( hrgnClip );
345             }
346             else
347             {
348                 DeleteObject( hrgnVis );
349                 hrgnVis = 0;
350             }
351         }
352     }
353     else
354         hrgnVis = CreateRectRgn(0, 0, 0, 0); /* empty */
355     WIN_ReleaseWndPtr(wndPtr);
356     WIN_ReleaseWndPtr(childWnd);
357     return hrgnVis;
358 }
359
360
361 /***********************************************************************
362  *              GetDC   (TTYDRV.@)
363  *
364  * Set the drawable, origin and dimensions for the DC associated to
365  * a given window.
366  */
367 BOOL TTYDRV_GetDC( HWND hwnd, HDC hdc, HRGN hrgn, DWORD flags )
368 {
369     WND *wndPtr = WIN_FindWndPtr(hwnd);
370     HRGN hrgnVisible = 0;
371     POINT org;
372
373     if (!wndPtr) return FALSE;
374
375     if(flags & DCX_WINDOW)
376     {
377         org.x = wndPtr->rectWindow.left;
378         org.y = wndPtr->rectWindow.top;
379     }
380     else
381     {
382         org.x = wndPtr->rectClient.left;
383         org.y = wndPtr->rectClient.top;
384     }
385
386     SetDCOrg16( hdc, org.x, org.y );
387
388     if (SetHookFlags16( hdc, DCHF_VALIDATEVISRGN ))  /* DC was dirty */
389     {
390         if (flags & DCX_PARENTCLIP)
391         {
392             WND *parentPtr = WIN_FindWndPtr( wndPtr->parent );
393
394             if( wndPtr->dwStyle & WS_VISIBLE && !(parentPtr->dwStyle & WS_MINIMIZE) )
395             {
396                 DWORD dcxFlags;
397
398                 if( parentPtr->dwStyle & WS_CLIPSIBLINGS )
399                     dcxFlags = DCX_CLIPSIBLINGS | (flags & ~(DCX_CLIPCHILDREN | DCX_WINDOW));
400                 else
401                     dcxFlags = flags & ~(DCX_CLIPSIBLINGS | DCX_CLIPCHILDREN | DCX_WINDOW);
402
403                 hrgnVisible = DCE_GetVisRgn( parentPtr->hwndSelf, dcxFlags,
404                                              wndPtr->hwndSelf, flags );
405                 if( flags & DCX_WINDOW )
406                     OffsetRgn( hrgnVisible, -wndPtr->rectWindow.left,
407                                -wndPtr->rectWindow.top );
408                 else
409                     OffsetRgn( hrgnVisible, -wndPtr->rectClient.left,
410                                -wndPtr->rectClient.top );
411             }
412             else
413                 hrgnVisible = CreateRectRgn( 0, 0, 0, 0 );
414             WIN_ReleaseWndPtr(parentPtr);
415         }
416         else
417         {
418             hrgnVisible = DCE_GetVisRgn( hwnd, flags, 0, 0 );
419             OffsetRgn( hrgnVisible, org.x, org.y );
420         }
421         SelectVisRgn16( hdc, hrgnVisible );
422     }
423
424     /* apply additional region operation (if any) */
425
426     if( flags & (DCX_EXCLUDERGN | DCX_INTERSECTRGN) )
427     {
428         if( !hrgnVisible ) hrgnVisible = CreateRectRgn( 0, 0, 0, 0 );
429
430         TRACE("\tsaved VisRgn, clipRgn = %04x\n", hrgn);
431
432         SaveVisRgn16( hdc );
433         CombineRgn( hrgnVisible, hrgn, 0, RGN_COPY );
434         OffsetRgn( hrgnVisible, org.x, org.y );
435         CombineRgn( hrgnVisible, InquireVisRgn16( hdc ), hrgnVisible,
436                       (flags & DCX_INTERSECTRGN) ? RGN_AND : RGN_DIFF );
437         SelectVisRgn16( hdc, hrgnVisible );
438     }
439
440     if (hrgnVisible) DeleteObject( hrgnVisible );
441
442     WIN_ReleaseWndPtr( wndPtr );
443     return TRUE;
444 }
445
446
447 /***********************************************************************
448  *              SetWindowPos   (TTYDRV.@)
449  */
450 BOOL TTYDRV_SetWindowPos( WINDOWPOS *winpos )
451 {
452     WND *wndPtr;
453     RECT newWindowRect, newClientRect;
454     BOOL retvalue;
455     HWND hwndActive = GetForegroundWindow();
456
457     TRACE( "hwnd %04x, swp (%i,%i)-(%i,%i) flags %08x\n",
458            winpos->hwnd, winpos->x, winpos->y,
459            winpos->x + winpos->cx, winpos->y + winpos->cy, winpos->flags);
460
461     /* ------------------------------------------------------------------------ CHECKS */
462
463       /* Check window handle */
464
465     if (winpos->hwnd == GetDesktopWindow()) return FALSE;
466     if (!(wndPtr = WIN_FindWndPtr( winpos->hwnd ))) return FALSE;
467
468     TRACE("\tcurrent (%i,%i)-(%i,%i), style %08x\n",
469           wndPtr->rectWindow.left, wndPtr->rectWindow.top,
470           wndPtr->rectWindow.right, wndPtr->rectWindow.bottom, (unsigned)wndPtr->dwStyle );
471
472     /* Fix redundant flags */
473
474     if(wndPtr->dwStyle & WS_VISIBLE)
475         winpos->flags &= ~SWP_SHOWWINDOW;
476     else
477     {
478         if (!(winpos->flags & SWP_SHOWWINDOW)) winpos->flags |= SWP_NOREDRAW;
479         winpos->flags &= ~SWP_HIDEWINDOW;
480     }
481
482     if ( winpos->cx < 0 ) winpos->cx = 0;
483     if ( winpos->cy < 0 ) winpos->cy = 0;
484
485     if ((wndPtr->rectWindow.right - wndPtr->rectWindow.left == winpos->cx) &&
486         (wndPtr->rectWindow.bottom - wndPtr->rectWindow.top == winpos->cy))
487         winpos->flags |= SWP_NOSIZE;    /* Already the right size */
488
489     if ((wndPtr->rectWindow.left == winpos->x) && (wndPtr->rectWindow.top == winpos->y))
490         winpos->flags |= SWP_NOMOVE;    /* Already the right position */
491
492     if (winpos->hwnd == hwndActive)
493         winpos->flags |= SWP_NOACTIVATE;   /* Already active */
494     else if ( (wndPtr->dwStyle & (WS_POPUP | WS_CHILD)) != WS_CHILD )
495     {
496         if(!(winpos->flags & SWP_NOACTIVATE)) /* Bring to the top when activating */
497         {
498             winpos->flags &= ~SWP_NOZORDER;
499             winpos->hwndInsertAfter = HWND_TOP;
500             goto Pos;
501         }
502     }
503
504     /* Check hwndInsertAfter */
505
506       /* FIXME: TOPMOST not supported yet */
507     if ((winpos->hwndInsertAfter == HWND_TOPMOST) ||
508         (winpos->hwndInsertAfter == HWND_NOTOPMOST)) winpos->hwndInsertAfter = HWND_TOP;
509
510     /* hwndInsertAfter must be a sibling of the window */
511     if ((winpos->hwndInsertAfter != HWND_TOP) && (winpos->hwndInsertAfter != HWND_BOTTOM))
512     {
513         WND* wnd = WIN_FindWndPtr(winpos->hwndInsertAfter);
514
515         if( wnd ) {
516             if( wnd->parent != wndPtr->parent )
517             {
518                 retvalue = FALSE;
519                 WIN_ReleaseWndPtr(wnd);
520                 goto END;
521             }
522             /* don't need to change the Zorder of hwnd if it's already inserted
523              * after hwndInsertAfter or when inserting hwnd after itself.
524              */
525             if ((winpos->hwnd == winpos->hwndInsertAfter) ||
526                 (winpos->hwnd == GetWindow( winpos->hwndInsertAfter, GW_HWNDNEXT )))
527                 winpos->flags |= SWP_NOZORDER;
528         }
529         WIN_ReleaseWndPtr(wnd);
530     }
531
532  Pos:  /* ------------------------------------------------------------------------ MAIN part */
533
534       /* Send WM_WINDOWPOSCHANGING message */
535
536     if (!(winpos->flags & SWP_NOSENDCHANGING))
537         SendMessageA( wndPtr->hwndSelf, WM_WINDOWPOSCHANGING, 0, (LPARAM)winpos );
538
539       /* Calculate new position and size */
540
541     newWindowRect = wndPtr->rectWindow;
542     newClientRect = (wndPtr->dwStyle & WS_MINIMIZE) ? wndPtr->rectWindow
543                                                     : wndPtr->rectClient;
544
545     if (!(winpos->flags & SWP_NOSIZE))
546     {
547         newWindowRect.right  = newWindowRect.left + winpos->cx;
548         newWindowRect.bottom = newWindowRect.top + winpos->cy;
549     }
550     if (!(winpos->flags & SWP_NOMOVE))
551     {
552         newWindowRect.left    = winpos->x;
553         newWindowRect.top     = winpos->y;
554         newWindowRect.right  += winpos->x - wndPtr->rectWindow.left;
555         newWindowRect.bottom += winpos->y - wndPtr->rectWindow.top;
556
557         OffsetRect( &newClientRect, winpos->x - wndPtr->rectWindow.left,
558                     winpos->y - wndPtr->rectWindow.top );
559     }
560
561     if( winpos->hwndInsertAfter == HWND_TOP )
562     {
563         if (GetWindow( wndPtr->hwndSelf, GW_HWNDFIRST ) == wndPtr->hwndSelf)
564             winpos->flags |= SWP_NOZORDER;
565     }
566     else
567         if( winpos->hwndInsertAfter == HWND_BOTTOM )
568         {
569             if (!GetWindow( wndPtr->hwndSelf, GW_HWNDNEXT ))
570                 winpos->flags |= SWP_NOZORDER;
571         }
572         else
573             if( !(winpos->flags & SWP_NOZORDER) )
574                 if( GetWindow(winpos->hwndInsertAfter, GW_HWNDNEXT) == wndPtr->hwndSelf )
575                     winpos->flags |= SWP_NOZORDER;
576
577     /* Common operations */
578
579       /* Send WM_NCCALCSIZE message to get new client area */
580     if( (winpos->flags & (SWP_FRAMECHANGED | SWP_NOSIZE)) != SWP_NOSIZE )
581     {
582         NCCALCSIZE_PARAMS params;
583         WINDOWPOS winposCopy;
584
585         params.rgrc[0] = newWindowRect;
586         params.rgrc[1] = wndPtr->rectWindow;
587         params.rgrc[2] = wndPtr->rectClient;
588         params.lppos = &winposCopy;
589         winposCopy = *winpos;
590
591         SendMessageW( winpos->hwnd, WM_NCCALCSIZE, TRUE, (LPARAM)&params );
592
593         TRACE( "%d,%d-%d,%d\n", params.rgrc[0].left, params.rgrc[0].top,
594                params.rgrc[0].right, params.rgrc[0].bottom );
595
596         /* If the application send back garbage, ignore it */
597         if (params.rgrc[0].left <= params.rgrc[0].right &&
598             params.rgrc[0].top <= params.rgrc[0].bottom)
599             newClientRect = params.rgrc[0];
600
601          /* FIXME: WVR_ALIGNxxx */
602
603         if( newClientRect.left != wndPtr->rectClient.left ||
604             newClientRect.top != wndPtr->rectClient.top )
605             winpos->flags &= ~SWP_NOCLIENTMOVE;
606
607         if( (newClientRect.right - newClientRect.left !=
608              wndPtr->rectClient.right - wndPtr->rectClient.left) ||
609             (newClientRect.bottom - newClientRect.top !=
610              wndPtr->rectClient.bottom - wndPtr->rectClient.top) )
611             winpos->flags &= ~SWP_NOCLIENTSIZE;
612     }
613
614     if(!(winpos->flags & SWP_NOZORDER) && winpos->hwnd != winpos->hwndInsertAfter)
615     {
616         HWND parent = GetAncestor( winpos->hwnd, GA_PARENT );
617         if (parent) WIN_LinkWindow( winpos->hwnd, parent, winpos->hwndInsertAfter );
618     }
619
620     /* FIXME: actually do something with WVR_VALIDRECTS */
621
622     WIN_SetRectangles( winpos->hwnd, &newWindowRect, &newClientRect );
623
624     if( winpos->flags & SWP_SHOWWINDOW )
625         WIN_SetStyle( winpos->hwnd, wndPtr->dwStyle | WS_VISIBLE );
626     else if( winpos->flags & SWP_HIDEWINDOW )
627         WIN_SetStyle( winpos->hwnd, wndPtr->dwStyle & ~WS_VISIBLE );
628
629     /* ------------------------------------------------------------------------ FINAL */
630
631     /* repaint invalidated region (if any)
632      *
633      * FIXME: if SWP_NOACTIVATE is not set then set invalid regions here without any painting
634      *        and force update after ChangeActiveWindow() to avoid painting frames twice.
635      */
636
637     if( !(winpos->flags & SWP_NOREDRAW) )
638     {
639         RedrawWindow( wndPtr->parent, NULL, 0,
640                       RDW_ERASE | RDW_INVALIDATE | RDW_ALLCHILDREN );
641         if (wndPtr->parent == GetDesktopWindow())
642             RedrawWindow( wndPtr->parent, NULL, 0,
643                           RDW_ERASENOW | RDW_NOCHILDREN );
644     }
645
646     if (!(winpos->flags & SWP_NOACTIVATE)) SetActiveWindow( winpos->hwnd );
647
648       /* And last, send the WM_WINDOWPOSCHANGED message */
649
650     TRACE("\tstatus flags = %04x\n", winpos->flags & SWP_AGG_STATUSFLAGS);
651
652     if ((((winpos->flags & SWP_AGG_STATUSFLAGS) != SWP_AGG_NOPOSCHANGE) &&
653           !(winpos->flags & SWP_NOSENDCHANGING)) )
654         SendMessageA( winpos->hwnd, WM_WINDOWPOSCHANGED, 0, (LPARAM)winpos );
655
656     retvalue = TRUE;
657  END:
658     WIN_ReleaseWndPtr(wndPtr);
659     return retvalue;
660 }
661
662
663 /***********************************************************************
664  *              WINPOS_MinMaximize   (internal)
665  *
666  *Lifted from x11 driver
667  */
668 static UINT WINPOS_MinMaximize( HWND hwnd, UINT cmd, LPRECT rect )
669 {
670     UINT swpFlags = 0;
671     WINDOWPLACEMENT wpl;
672
673     TRACE("0x%04x %u\n", hwnd, cmd );
674     FIXME("(%x): stub\n", hwnd);
675
676     wpl.length = sizeof(wpl);
677     GetWindowPlacement( hwnd, &wpl );
678
679     /* If I glark this right, yields an immutable window*/
680     swpFlags = SWP_NOSIZE | SWP_NOMOVE;
681
682     /*cmd handling goes here.  see dlls/x1drv/winpos.c*/
683
684     return swpFlags;
685 }
686
687 /***********************************************************************
688  *              ShowWindow   (TTYDRV.@)
689  *
690  *Lifted from x11 driver
691  *Sets the specified windows' show state.
692  */
693 BOOL TTYDRV_ShowWindow( HWND hwnd, INT cmd )
694 {
695     WND*        wndPtr = WIN_FindWndPtr( hwnd );
696     BOOL        wasVisible, showFlag;
697     RECT        newPos = {0, 0, 0, 0};
698     UINT        swp = 0;
699
700     if (!wndPtr) return FALSE;
701     hwnd = wndPtr->hwndSelf;  /* make it a full handle */
702
703     TRACE("hwnd=%04x, cmd=%d\n", hwnd, cmd);
704
705     wasVisible = (wndPtr->dwStyle & WS_VISIBLE) != 0;
706
707     switch(cmd)
708     {
709         case SW_HIDE:
710             if (!wasVisible) goto END;
711             swp |= SWP_HIDEWINDOW | SWP_NOSIZE | SWP_NOMOVE |
712                         SWP_NOACTIVATE | SWP_NOZORDER;
713             break;
714
715         case SW_SHOWMINNOACTIVE:
716             swp |= SWP_NOACTIVATE | SWP_NOZORDER;
717             /* fall through */
718         case SW_SHOWMINIMIZED:
719             swp |= SWP_SHOWWINDOW;
720             /* fall through */
721         case SW_MINIMIZE:
722             swp |= SWP_FRAMECHANGED;
723             if( !(wndPtr->dwStyle & WS_MINIMIZE) )
724                  swp |= WINPOS_MinMaximize( hwnd, SW_MINIMIZE, &newPos );
725             else swp |= SWP_NOSIZE | SWP_NOMOVE;
726             break;
727
728         case SW_SHOWMAXIMIZED: /* same as SW_MAXIMIZE */
729             swp |= SWP_SHOWWINDOW | SWP_FRAMECHANGED;
730             if( !(wndPtr->dwStyle & WS_MAXIMIZE) )
731                  swp |= WINPOS_MinMaximize( hwnd, SW_MAXIMIZE, &newPos );
732             else swp |= SWP_NOSIZE | SWP_NOMOVE;
733             break;
734
735         case SW_SHOWNA:
736             swp |= SWP_NOACTIVATE | SWP_NOZORDER;
737             /* fall through */
738         case SW_SHOW:
739             swp |= SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE;
740
741             /*
742              * ShowWindow has a little peculiar behavior that if the
743              * window is already the topmost window, it will not
744              * activate it.
745              */
746             if (GetTopWindow((HWND)0)==hwnd && (wasVisible || GetActiveWindow() == hwnd))
747               swp |= SWP_NOACTIVATE;
748
749             break;
750
751         case SW_SHOWNOACTIVATE:
752             swp |= SWP_NOZORDER;
753             if (GetActiveWindow()) swp |= SWP_NOACTIVATE;
754             /* fall through */
755         case SW_SHOWNORMAL:  /* same as SW_NORMAL: */
756         case SW_SHOWDEFAULT: /* FIXME: should have its own handler */
757         case SW_RESTORE:
758             swp |= SWP_SHOWWINDOW | SWP_FRAMECHANGED;
759
760             if( wndPtr->dwStyle & (WS_MINIMIZE | WS_MAXIMIZE) )
761                  swp |= WINPOS_MinMaximize( hwnd, SW_RESTORE, &newPos );
762             else swp |= SWP_NOSIZE | SWP_NOMOVE;
763             break;
764     }
765
766     showFlag = (cmd != SW_HIDE);
767     if (showFlag != wasVisible)
768     {
769         SendMessageA( hwnd, WM_SHOWWINDOW, showFlag, 0 );
770         if (!IsWindow( hwnd )) goto END;
771     }
772
773     /* We can't activate a child window */
774     if ((wndPtr->dwStyle & WS_CHILD) &&
775         !(wndPtr->dwExStyle & WS_EX_MDICHILD))
776         swp |= SWP_NOACTIVATE | SWP_NOZORDER;
777
778     SetWindowPos( hwnd, HWND_TOP, newPos.left, newPos.top,
779                   newPos.right, newPos.bottom, LOWORD(swp) );
780     if (cmd == SW_HIDE)
781     {
782         /* FIXME: This will cause the window to be activated irrespective
783          * of whether it is owned by the same thread. Has to be done
784          * asynchronously.
785          */
786
787         if (hwnd == GetActiveWindow())
788             WINPOS_ActivateOtherWindow(hwnd);
789
790         /* Revert focus to parent */
791         if (hwnd == GetFocus() || IsChild(hwnd, GetFocus()))
792             SetFocus( GetParent(hwnd) );
793     }
794     if (!IsWindow( hwnd )) goto END;
795     else if( wndPtr->dwStyle & WS_MINIMIZE ) WINPOS_ShowIconTitle( hwnd, TRUE );
796
797     if (wndPtr->flags & WIN_NEED_SIZE)
798     {
799         /* should happen only in CreateWindowEx() */
800         int wParam = SIZE_RESTORED;
801
802         wndPtr->flags &= ~WIN_NEED_SIZE;
803         if (wndPtr->dwStyle & WS_MAXIMIZE) wParam = SIZE_MAXIMIZED;
804         else if (wndPtr->dwStyle & WS_MINIMIZE) wParam = SIZE_MINIMIZED;
805         SendMessageA( hwnd, WM_SIZE, wParam,
806                      MAKELONG(wndPtr->rectClient.right-wndPtr->rectClient.left,
807                             wndPtr->rectClient.bottom-wndPtr->rectClient.top));
808         SendMessageA( hwnd, WM_MOVE, 0,
809                    MAKELONG(wndPtr->rectClient.left, wndPtr->rectClient.top) );
810     }
811
812 END:
813     WIN_ReleaseWndPtr(wndPtr);
814     return wasVisible;
815 }