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