INT21_GetFreeDiskSpace(): The drive parameter is found in the DL
[wine] / dlls / x11drv / winpos.c
1 /*
2  * Window position related functions.
3  *
4  * Copyright 1993, 1994, 1995, 2001 Alexandre Julliard
5  * Copyright 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 "config.h"
23
24 #include <X11/Xlib.h>
25 #ifdef HAVE_LIBXSHAPE
26 #include <X11/IntrinsicP.h>
27 #include <X11/extensions/shape.h>
28 #endif /* HAVE_LIBXSHAPE */
29 #include <stdarg.h>
30
31 #include "windef.h"
32 #include "winbase.h"
33 #include "wingdi.h"
34 #include "winuser.h"
35 #include "winerror.h"
36 #include "wownt32.h"
37
38 #include "x11drv.h"
39 #include "win.h"
40 #include "winpos.h"
41 #include "dce.h"
42 #include "cursoricon.h"
43 #include "nonclient.h"
44
45 #include "wine/server.h"
46 #include "wine/debug.h"
47
48 WINE_DEFAULT_DEBUG_CHANNEL(x11drv);
49
50 #define SWP_AGG_NOGEOMETRYCHANGE \
51     (SWP_NOSIZE | SWP_NOMOVE | SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE)
52 #define SWP_AGG_NOPOSCHANGE \
53     (SWP_AGG_NOGEOMETRYCHANGE | SWP_NOZORDER)
54 #define SWP_AGG_STATUSFLAGS \
55     (SWP_AGG_NOPOSCHANGE | SWP_FRAMECHANGED | SWP_HIDEWINDOW | SWP_SHOWWINDOW)
56
57 #define SWP_EX_NOCOPY       0x0001
58 #define SWP_EX_PAINTSELF    0x0002
59 #define SWP_EX_NONCLIENT    0x0004
60
61 #define HAS_THICKFRAME(style,exStyle) \
62     (((style) & WS_THICKFRAME) && \
63      !(((style) & (WS_DLGFRAME|WS_BORDER)) == WS_DLGFRAME))
64
65 #define ON_LEFT_BORDER(hit) \
66  (((hit) == HTLEFT) || ((hit) == HTTOPLEFT) || ((hit) == HTBOTTOMLEFT))
67 #define ON_RIGHT_BORDER(hit) \
68  (((hit) == HTRIGHT) || ((hit) == HTTOPRIGHT) || ((hit) == HTBOTTOMRIGHT))
69 #define ON_TOP_BORDER(hit) \
70  (((hit) == HTTOP) || ((hit) == HTTOPLEFT) || ((hit) == HTTOPRIGHT))
71 #define ON_BOTTOM_BORDER(hit) \
72  (((hit) == HTBOTTOM) || ((hit) == HTBOTTOMLEFT) || ((hit) == HTBOTTOMRIGHT))
73
74
75 /***********************************************************************
76  *              clip_children
77  *
78  * Clip all children of a given window out of the visible region
79  */
80 static int clip_children( HWND parent, HWND last, HRGN hrgn, int whole_window )
81 {
82     HWND *list;
83     WND *ptr;
84     HRGN rectRgn;
85     int i, x, y, ret = SIMPLEREGION;
86
87     /* first check if we have anything to do */
88     if (!(list = WIN_ListChildren( parent ))) return ret;
89     for (i = 0; list[i] && list[i] != last; i++)
90         if (GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE) break;
91     if (!list[i] || list[i] == last) goto done; /* no children to clip */
92
93     if (whole_window)
94     {
95         WND *win = WIN_FindWndPtr( parent );
96         x = win->rectWindow.left - win->rectClient.left;
97         y = win->rectWindow.top - win->rectClient.top;
98         WIN_ReleaseWndPtr( win );
99     }
100     else x = y = 0;
101
102     rectRgn = CreateRectRgn( 0, 0, 0, 0 );
103
104     for ( ; list[i] && list[i] != last; i++)
105     {
106         if (!(ptr = WIN_FindWndPtr( list[i] ))) continue;
107         if (ptr->dwStyle & WS_VISIBLE)
108         {
109             SetRectRgn( rectRgn, ptr->rectWindow.left + x, ptr->rectWindow.top + y,
110                         ptr->rectWindow.right + x, ptr->rectWindow.bottom + y );
111             if ((ret = CombineRgn( hrgn, hrgn, rectRgn, RGN_DIFF )) == NULLREGION)
112             {
113                 WIN_ReleaseWndPtr( ptr );
114                 break;  /* no need to go on, region is empty */
115             }
116         }
117         WIN_ReleaseWndPtr( ptr );
118     }
119     DeleteObject( rectRgn );
120  done:
121     HeapFree( GetProcessHeap(), 0, list );
122     return ret;
123 }
124
125
126 /***********************************************************************
127  *              get_visible_region
128  *
129  * Compute the visible region of a window
130  */
131 static HRGN get_visible_region( WND *win, HWND top, UINT flags, int mode )
132 {
133     HRGN rgn;
134     RECT rect;
135     int xoffset, yoffset;
136     X11DRV_WND_DATA *data = win->pDriverData;
137
138     if (flags & DCX_WINDOW)
139     {
140         xoffset = win->rectWindow.left;
141         yoffset = win->rectWindow.top;
142     }
143     else
144     {
145         xoffset = win->rectClient.left;
146         yoffset = win->rectClient.top;
147     }
148
149     if (flags & DCX_PARENTCLIP)
150         GetClientRect( win->parent, &rect );
151     else if (flags & DCX_WINDOW)
152         rect = data->whole_rect;
153     else
154         rect = win->rectClient;
155
156     /* vis region is relative to the start of the client/window area */
157     OffsetRect( &rect, -xoffset, -yoffset );
158
159     if (!(rgn = CreateRectRgn( rect.left, rect.top, rect.right, rect.bottom ))) return 0;
160
161     if ((flags & DCX_CLIPCHILDREN) && (mode != ClipByChildren))
162     {
163         /* we need to clip children by hand */
164         if (clip_children( win->hwndSelf, 0, rgn, (flags & DCX_WINDOW) ) == NULLREGION) return rgn;
165     }
166
167     if (top && top != win->hwndSelf)  /* need to clip siblings of ancestors */
168     {
169         WND *parent, *ptr = WIN_FindWndPtr( win->hwndSelf );
170         HRGN tmp = 0;
171
172         OffsetRgn( rgn, xoffset, yoffset );
173         for (;;)
174         {
175             if (ptr->dwStyle & WS_CLIPSIBLINGS)
176             {
177                 if (clip_children( ptr->parent, ptr->hwndSelf, rgn, FALSE ) == NULLREGION) break;
178             }
179             if (ptr->hwndSelf == top) break;
180             if (!(parent = WIN_FindWndPtr( ptr->parent ))) break;
181             WIN_ReleaseWndPtr( ptr );
182             ptr = parent;
183             /* clip to parent client area */
184             if (tmp) SetRectRgn( tmp, 0, 0, ptr->rectClient.right - ptr->rectClient.left,
185                                  ptr->rectClient.bottom - ptr->rectClient.top );
186             else tmp = CreateRectRgn( 0, 0, ptr->rectClient.right - ptr->rectClient.left,
187                                       ptr->rectClient.bottom - ptr->rectClient.top );
188             CombineRgn( rgn, rgn, tmp, RGN_AND );
189             OffsetRgn( rgn, ptr->rectClient.left, ptr->rectClient.top );
190             xoffset += ptr->rectClient.left;
191             yoffset += ptr->rectClient.top;
192         }
193         WIN_ReleaseWndPtr( ptr );
194         /* make it relative to the target window again */
195         OffsetRgn( rgn, -xoffset, -yoffset );
196         if (tmp) DeleteObject( tmp );
197     }
198
199     return rgn;
200 }
201
202
203 /***********************************************************************
204  *              get_covered_region
205  *
206  * Compute the portion of 'rgn' that is covered by non-clipped siblings.
207  * This is the area that is covered from X point of view, but may still need
208  * to be exposed.
209  * 'rgn' must be relative to the client area of the parent of 'win'.
210  */
211 static int get_covered_region( WND *win, HRGN rgn )
212 {
213     HRGN tmp;
214     int ret;
215     WND *parent, *ptr = WIN_FindWndPtr( win->hwndSelf );
216     int xoffset = 0, yoffset = 0;
217
218     tmp = CreateRectRgn( 0, 0, 0, 0 );
219     CombineRgn( tmp, rgn, 0, RGN_COPY );
220
221     /* to make things easier we actually build the uncovered
222      * area by removing all siblings and then we subtract that
223      * from the total region to get the covered area */
224     for (;;)
225     {
226         if (!(ptr->dwStyle & WS_CLIPSIBLINGS))
227         {
228             if (clip_children( ptr->parent, ptr->hwndSelf, tmp, FALSE ) == NULLREGION) break;
229         }
230         if (!(parent = WIN_FindWndPtr( ptr->parent ))) break;
231         WIN_ReleaseWndPtr( ptr );
232         ptr = parent;
233         OffsetRgn( tmp, ptr->rectClient.left, ptr->rectClient.top );
234         xoffset += ptr->rectClient.left;
235         yoffset += ptr->rectClient.top;
236     }
237     WIN_ReleaseWndPtr( ptr );
238     /* make it relative to the target window again */
239     OffsetRgn( tmp, -xoffset, -yoffset );
240
241     /* now subtract the computed region from the original one */
242     ret = CombineRgn( rgn, rgn, tmp, RGN_DIFF );
243     DeleteObject( tmp );
244     return ret;
245 }
246
247
248 /***********************************************************************
249  *              expose_window
250  *
251  * Expose a region of a given window.
252  */
253 static void expose_window( HWND hwnd, RECT *rect, HRGN rgn, int flags )
254 {
255     POINT offset;
256     HWND top = 0;
257     HWND *list;
258     int i;
259
260     /* find the top most parent that doesn't clip children or siblings and
261      * invalidate the area on its parent, including all children */
262     if ((list = WIN_ListParents( hwnd )))
263     {
264         HWND current = hwnd;
265         LONG style = GetWindowLongW( hwnd, GWL_STYLE );
266         for (i = 0; list[i] && list[i] != GetDesktopWindow(); i++)
267         {
268             if (!(style & WS_CLIPSIBLINGS)) top = current;
269             style = GetWindowLongW( list[i], GWL_STYLE );
270             if (!(style & WS_CLIPCHILDREN)) top = current;
271             current = list[i];
272         }
273
274         if (top)
275         {
276             /* find the parent of the top window, reusing the parent list */
277             if (top == hwnd) i = 0;
278             else
279             {
280                 for (i = 0; list[i]; i++) if (list[i] == top) break;
281                 if (list[i] && list[i+1]) i++;
282             }
283             if (list[i] != GetDesktopWindow()) top = list[i];
284             flags &= ~RDW_FRAME;  /* parent will invalidate children frame anyway */
285             flags |= RDW_ALLCHILDREN;
286         }
287         HeapFree( GetProcessHeap(), 0, list );
288     }
289
290     if (!top) top = hwnd;
291
292     /* make coords relative to top */
293     offset.x = offset.y = 0;
294     MapWindowPoints( hwnd, top, &offset, 1 );
295
296     if (rect)
297     {
298         OffsetRect( rect, offset.x, offset.y );
299         RedrawWindow( top, rect, 0, flags );
300     }
301     else
302     {
303         OffsetRgn( rgn, offset.x, offset.y );
304         RedrawWindow( top, NULL, rgn, flags );
305     }
306 }
307
308
309 /***********************************************************************
310  *              expose_covered_parent_area
311  *
312  * Expose the parent area that has been uncovered by moving/hiding a
313  * given window, but that is still covered by other siblings (the area
314  * not covered by siblings will be exposed automatically by X).
315  */
316 static void expose_covered_parent_area( WND *win, const RECT *old_rect )
317 {
318     int ret = SIMPLEREGION;
319     HRGN hrgn = CreateRectRgnIndirect( old_rect );
320
321     if (win->dwStyle & WS_VISIBLE)
322     {
323         HRGN tmp = CreateRectRgnIndirect( &win->rectWindow );
324         ret = CombineRgn( hrgn, hrgn, tmp, RGN_DIFF );
325         DeleteObject( tmp );
326     }
327
328     if (ret != NULLREGION)
329     {
330         if (get_covered_region( win, hrgn ) != NULLREGION)
331             expose_window( win->parent, NULL, hrgn, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN );
332     }
333     DeleteObject( hrgn );
334 }
335
336
337 /***********************************************************************
338  *              expose_covered_window_area
339  *
340  * Expose the area of a window that is covered by other siblings.
341  */
342 static void expose_covered_window_area( WND *win, const RECT *old_client_rect, BOOL frame )
343 {
344     HRGN hrgn;
345     int ret = SIMPLEREGION;
346
347     if (frame)
348         hrgn = CreateRectRgn( win->rectWindow.left - win->rectClient.left,
349                               win->rectWindow.top - win->rectClient.top,
350                               win->rectWindow.right - win->rectWindow.left,
351                               win->rectWindow.bottom - win->rectWindow.top );
352     else
353         hrgn = CreateRectRgn( 0, 0,
354                               win->rectClient.right - win->rectClient.left,
355                               win->rectClient.bottom - win->rectClient.top );
356
357     /* if the client rect didn't move we don't need to repaint it all */
358     if (old_client_rect->left == win->rectClient.left &&
359         old_client_rect->top == win->rectClient.top)
360     {
361         RECT rc;
362
363         if (IntersectRect( &rc, old_client_rect, &win->rectClient ))
364         {
365             HRGN tmp;
366             /* subtract the unchanged client area from the region to expose */
367             OffsetRect( &rc, -win->rectClient.left, -win->rectClient.top );
368             if ((tmp = CreateRectRgnIndirect( &rc )))
369             {
370                 ret = CombineRgn( hrgn, hrgn, tmp, RGN_DIFF );
371                 DeleteObject( tmp );
372             }
373         }
374     }
375
376     if (ret != NULLREGION)
377     {
378         if (get_covered_region( win, hrgn ) != NULLREGION)
379             expose_window( win->hwndSelf, NULL, hrgn,
380                            RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
381     }
382
383     DeleteObject( hrgn );
384 }
385
386
387 /***********************************************************************
388  *           X11DRV_Expose
389  */
390 void X11DRV_Expose( HWND hwnd, XExposeEvent *event )
391 {
392     RECT rect;
393     struct x11drv_win_data *data;
394     int flags = RDW_INVALIDATE | RDW_ERASE;
395     WND *win;
396
397     TRACE( "win %p (%lx) %d,%d %dx%d\n",
398            hwnd, event->window, event->x, event->y, event->width, event->height );
399
400     rect.left   = event->x;
401     rect.top    = event->y;
402     rect.right  = rect.left + event->width;
403     rect.bottom = rect.top + event->height;
404
405     if (!(win = WIN_GetPtr( hwnd ))) return;
406     data = win->pDriverData;
407
408     if (event->window != data->client_window)  /* whole window or icon window */
409     {
410         flags |= RDW_FRAME;
411         /* make position relative to client area instead of window */
412         OffsetRect( &rect, -data->client_rect.left, -data->client_rect.top );
413     }
414     WIN_ReleasePtr( win );
415
416     expose_window( hwnd, &rect, 0, flags );
417 }
418
419
420 /***********************************************************************
421  *              GetDC (X11DRV.@)
422  *
423  * Set the drawable, origin and dimensions for the DC associated to
424  * a given window.
425  */
426 BOOL X11DRV_GetDC( HWND hwnd, HDC hdc, HRGN hrgn, DWORD flags )
427 {
428     WND *win = WIN_GetPtr( hwnd );
429     HWND top = 0;
430     X11DRV_WND_DATA *data = win->pDriverData;
431     Drawable drawable;
432     BOOL visible;
433     POINT org, drawable_org;
434     int mode = IncludeInferiors;
435
436     /* don't clip siblings if using parent clip region */
437     if (flags & DCX_PARENTCLIP) flags &= ~DCX_CLIPSIBLINGS;
438
439     /* find the top parent in the hierarchy that isn't clipping siblings */
440     visible = (win->dwStyle & WS_VISIBLE) != 0;
441
442     if (visible)
443     {
444         HWND *list = WIN_ListParents( hwnd );
445         if (list)
446         {
447             int i;
448             for (i = 0; list[i] != GetDesktopWindow(); i++)
449             {
450                 LONG style = GetWindowLongW( list[i], GWL_STYLE );
451                 if (!(style & WS_VISIBLE))
452                 {
453                     visible = FALSE;
454                     top = 0;
455                     break;
456                 }
457                 if (!(style & WS_CLIPSIBLINGS)) top = list[i];
458             }
459             HeapFree( GetProcessHeap(), 0, list );
460         }
461         if (!top && visible && !(flags & DCX_CLIPSIBLINGS)) top = hwnd;
462     }
463
464     if (top)
465     {
466         HWND parent = GetAncestor( top, GA_PARENT );
467         org.x = org.y = 0;
468         if (flags & DCX_WINDOW)
469         {
470             org.x = win->rectWindow.left - win->rectClient.left;
471             org.y = win->rectWindow.top - win->rectClient.top;
472         }
473         MapWindowPoints( hwnd, parent, &org, 1 );
474         drawable_org.x = drawable_org.y = 0;
475         MapWindowPoints( parent, 0, &drawable_org, 1 );
476         /* have to use the parent so that we include siblings */
477         if (parent) drawable = X11DRV_get_client_window( parent );
478         else drawable = root_window;
479     }
480     else
481     {
482         if (IsIconic( hwnd ))
483         {
484             drawable = data->icon_window ? data->icon_window : data->whole_window;
485             org.x = 0;
486             org.y = 0;
487             drawable_org = org;
488         }
489         else if (flags & DCX_WINDOW)
490         {
491             drawable = data->whole_window;
492             org.x = win->rectWindow.left - data->whole_rect.left;
493             org.y = win->rectWindow.top - data->whole_rect.top;
494             drawable_org.x = data->whole_rect.left - win->rectClient.left;
495             drawable_org.y = data->whole_rect.top - win->rectClient.top;
496         }
497         else
498         {
499             drawable = data->client_window;
500             org.x = 0;
501             org.y = 0;
502             drawable_org = org;
503             if (flags & DCX_CLIPCHILDREN) mode = ClipByChildren;  /* can use X11 clipping */
504         }
505         MapWindowPoints( hwnd, 0, &drawable_org, 1 );
506     }
507
508     X11DRV_SetDrawable( hdc, drawable, mode, &org, &drawable_org );
509
510     if (flags & (DCX_EXCLUDERGN | DCX_INTERSECTRGN) ||
511         SetHookFlags16( HDC_16(hdc), DCHF_VALIDATEVISRGN ))  /* DC was dirty */
512     {
513         /* need to recompute the visible region */
514         HRGN visRgn;
515
516         if (visible)
517         {
518             visRgn = get_visible_region( win, top, flags, mode );
519
520             if (flags & (DCX_EXCLUDERGN | DCX_INTERSECTRGN))
521                 CombineRgn( visRgn, visRgn, hrgn,
522                             (flags & DCX_INTERSECTRGN) ? RGN_AND : RGN_DIFF );
523         }
524         else visRgn = CreateRectRgn( 0, 0, 0, 0 );
525
526         SelectVisRgn16( HDC_16(hdc), HRGN_16(visRgn) );
527         DeleteObject( visRgn );
528     }
529
530     WIN_ReleasePtr( win );
531     return TRUE;
532 }
533
534
535 /***********************************************************************
536  *              ReleaseDC (X11DRV.@)
537  */
538 void X11DRV_ReleaseDC( HWND hwnd, HDC hdc )
539 {
540     POINT org;
541
542     org.x = org.y = 0;
543     X11DRV_SetDrawable( hdc, root_window, IncludeInferiors, &org, &org );
544 }
545
546
547 /***********************************************************************
548  *           SWP_DoWinPosChanging
549  */
550 static BOOL SWP_DoWinPosChanging( WINDOWPOS* pWinpos, RECT* pNewWindowRect, RECT* pNewClientRect )
551 {
552     WND *wndPtr;
553
554     /* Send WM_WINDOWPOSCHANGING message */
555
556     if (!(pWinpos->flags & SWP_NOSENDCHANGING))
557         SendMessageA( pWinpos->hwnd, WM_WINDOWPOSCHANGING, 0, (LPARAM)pWinpos );
558
559     if (!(wndPtr = WIN_GetPtr( pWinpos->hwnd )) || wndPtr == WND_OTHER_PROCESS) return FALSE;
560
561     /* Calculate new position and size */
562
563     *pNewWindowRect = wndPtr->rectWindow;
564     *pNewClientRect = (wndPtr->dwStyle & WS_MINIMIZE) ? wndPtr->rectWindow
565                                                     : wndPtr->rectClient;
566
567     if (!(pWinpos->flags & SWP_NOSIZE))
568     {
569         pNewWindowRect->right  = pNewWindowRect->left + pWinpos->cx;
570         pNewWindowRect->bottom = pNewWindowRect->top + pWinpos->cy;
571     }
572     if (!(pWinpos->flags & SWP_NOMOVE))
573     {
574         pNewWindowRect->left    = pWinpos->x;
575         pNewWindowRect->top     = pWinpos->y;
576         pNewWindowRect->right  += pWinpos->x - wndPtr->rectWindow.left;
577         pNewWindowRect->bottom += pWinpos->y - wndPtr->rectWindow.top;
578
579         OffsetRect( pNewClientRect, pWinpos->x - wndPtr->rectWindow.left,
580                                     pWinpos->y - wndPtr->rectWindow.top );
581     }
582     pWinpos->flags |= SWP_NOCLIENTMOVE | SWP_NOCLIENTSIZE;
583     WIN_ReleasePtr( wndPtr );
584     return TRUE;
585 }
586
587 /***********************************************************************
588  *           SWP_DoNCCalcSize
589  */
590 static UINT SWP_DoNCCalcSize( WINDOWPOS* pWinpos, RECT* pNewWindowRect, RECT* pNewClientRect )
591 {
592     UINT wvrFlags = 0;
593     WND *wndPtr;
594
595     if (!(wndPtr = WIN_GetPtr( pWinpos->hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
596
597       /* Send WM_NCCALCSIZE message to get new client area */
598     if( (pWinpos->flags & (SWP_FRAMECHANGED | SWP_NOSIZE)) != SWP_NOSIZE )
599     {
600         NCCALCSIZE_PARAMS params;
601         WINDOWPOS winposCopy;
602
603         params.rgrc[0] = *pNewWindowRect;
604         params.rgrc[1] = wndPtr->rectWindow;
605         params.rgrc[2] = wndPtr->rectClient;
606         params.lppos = &winposCopy;
607         winposCopy = *pWinpos;
608         WIN_ReleasePtr( wndPtr );
609
610         wvrFlags = SendMessageW( pWinpos->hwnd, WM_NCCALCSIZE, TRUE, (LPARAM)&params );
611
612         TRACE( "(%ld,%ld)-(%ld,%ld)\n", params.rgrc[0].left, params.rgrc[0].top,
613                params.rgrc[0].right, params.rgrc[0].bottom );
614
615         /* If the application send back garbage, ignore it */
616         if (params.rgrc[0].left <= params.rgrc[0].right &&
617             params.rgrc[0].top <= params.rgrc[0].bottom)
618             *pNewClientRect = params.rgrc[0];
619
620          /* FIXME: WVR_ALIGNxxx */
621
622         if (!(wndPtr = WIN_GetPtr( pWinpos->hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
623
624         if( pNewClientRect->left != wndPtr->rectClient.left ||
625             pNewClientRect->top != wndPtr->rectClient.top )
626             pWinpos->flags &= ~SWP_NOCLIENTMOVE;
627
628         if( (pNewClientRect->right - pNewClientRect->left !=
629              wndPtr->rectClient.right - wndPtr->rectClient.left) ||
630             (pNewClientRect->bottom - pNewClientRect->top !=
631              wndPtr->rectClient.bottom - wndPtr->rectClient.top) )
632             pWinpos->flags &= ~SWP_NOCLIENTSIZE;
633     }
634     else
635     {
636         if (!(pWinpos->flags & SWP_NOMOVE) &&
637             (pNewClientRect->left != wndPtr->rectClient.left ||
638              pNewClientRect->top != wndPtr->rectClient.top))
639             pWinpos->flags &= ~SWP_NOCLIENTMOVE;
640     }
641     WIN_ReleasePtr( wndPtr );
642     return wvrFlags;
643 }
644
645
646 /***********************************************************************
647  *           SWP_DoOwnedPopups
648  *
649  * fix Z order taking into account owned popups -
650  * basically we need to maintain them above the window that owns them
651  *
652  * FIXME: hide/show owned popups when owner visibility changes.
653  */
654 static HWND SWP_DoOwnedPopups(HWND hwnd, HWND hwndInsertAfter)
655 {
656     HWND *list = NULL;
657     HWND owner = GetWindow( hwnd, GW_OWNER );
658     LONG style = GetWindowLongW( hwnd, GWL_STYLE );
659
660     WARN("(%p) hInsertAfter = %p\n", hwnd, hwndInsertAfter );
661
662     if ((style & WS_POPUP) && owner)
663     {
664         /* make sure this popup stays above the owner */
665
666         HWND hwndLocalPrev = HWND_TOP;
667
668         if( hwndInsertAfter != HWND_TOP )
669         {
670             if ((list = WIN_ListChildren( GetDesktopWindow() )))
671             {
672                 int i;
673                 for (i = 0; list[i]; i++)
674                 {
675                     if (list[i] == owner) break;
676                     if (list[i] != hwnd) hwndLocalPrev = list[i];
677                     if (hwndLocalPrev == hwndInsertAfter) break;
678                 }
679                 hwndInsertAfter = hwndLocalPrev;
680             }
681         }
682     }
683     else if (style & WS_CHILD) return hwndInsertAfter;
684
685     if (!list) list = WIN_ListChildren( GetDesktopWindow() );
686     if (list)
687     {
688         int i;
689         for (i = 0; list[i]; i++)
690         {
691             if (list[i] == hwnd) break;
692             if ((GetWindowLongW( list[i], GWL_STYLE ) & WS_POPUP) &&
693                 GetWindow( list[i], GW_OWNER ) == hwnd)
694             {
695                 SetWindowPos( list[i], hwndInsertAfter, 0, 0, 0, 0,
696                               SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE |
697                               SWP_NOSENDCHANGING | SWP_DEFERERASE );
698                 hwndInsertAfter = list[i];
699             }
700         }
701         HeapFree( GetProcessHeap(), 0, list );
702     }
703
704     return hwndInsertAfter;
705 }
706
707
708 /* fix redundant flags and values in the WINDOWPOS structure */
709 static BOOL fixup_flags( WINDOWPOS *winpos )
710 {
711     WND *wndPtr = WIN_GetPtr( winpos->hwnd );
712     BOOL ret = TRUE;
713
714     if (!wndPtr || wndPtr == WND_OTHER_PROCESS)
715     {
716         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
717         return FALSE;
718     }
719     winpos->hwnd = wndPtr->hwndSelf;  /* make it a full handle */
720
721     if (wndPtr->dwStyle & WS_VISIBLE) winpos->flags &= ~SWP_SHOWWINDOW;
722     else
723     {
724         winpos->flags &= ~SWP_HIDEWINDOW;
725         if (!(winpos->flags & SWP_SHOWWINDOW)) winpos->flags |= SWP_NOREDRAW;
726     }
727
728     if (winpos->cx < 0) winpos->cx = 0;
729     if (winpos->cy < 0) winpos->cy = 0;
730
731     if ((wndPtr->rectWindow.right - wndPtr->rectWindow.left == winpos->cx) &&
732         (wndPtr->rectWindow.bottom - wndPtr->rectWindow.top == winpos->cy))
733         winpos->flags |= SWP_NOSIZE;    /* Already the right size */
734
735     if ((wndPtr->rectWindow.left == winpos->x) && (wndPtr->rectWindow.top == winpos->y))
736         winpos->flags |= SWP_NOMOVE;    /* Already the right position */
737
738     if (winpos->hwnd == GetForegroundWindow())
739         winpos->flags |= SWP_NOACTIVATE;   /* Already active */
740     else if ((wndPtr->dwStyle & (WS_POPUP | WS_CHILD)) != WS_CHILD)
741     {
742         if (!(winpos->flags & SWP_NOACTIVATE)) /* Bring to the top when activating */
743         {
744             winpos->flags &= ~SWP_NOZORDER;
745             winpos->hwndInsertAfter = HWND_TOP;
746             goto done;
747         }
748     }
749
750     /* Check hwndInsertAfter */
751     if (winpos->flags & SWP_NOZORDER) goto done;
752
753     /* fix sign extension */
754     if (winpos->hwndInsertAfter == (HWND)0xffff) winpos->hwndInsertAfter = HWND_TOPMOST;
755     else if (winpos->hwndInsertAfter == (HWND)0xfffe) winpos->hwndInsertAfter = HWND_NOTOPMOST;
756
757       /* FIXME: TOPMOST not supported yet */
758     if ((winpos->hwndInsertAfter == HWND_TOPMOST) ||
759         (winpos->hwndInsertAfter == HWND_NOTOPMOST)) winpos->hwndInsertAfter = HWND_TOP;
760
761     /* hwndInsertAfter must be a sibling of the window */
762     if ((winpos->hwndInsertAfter != HWND_TOP) && (winpos->hwndInsertAfter != HWND_BOTTOM))
763     {
764         if (GetAncestor( winpos->hwndInsertAfter, GA_PARENT ) != wndPtr->parent) ret = FALSE;
765         else
766         {
767             /* don't need to change the Zorder of hwnd if it's already inserted
768              * after hwndInsertAfter or when inserting hwnd after itself.
769              */
770             if ((winpos->hwnd == winpos->hwndInsertAfter) ||
771                 (winpos->hwnd == GetWindow( winpos->hwndInsertAfter, GW_HWNDNEXT )))
772                 winpos->flags |= SWP_NOZORDER;
773         }
774     }
775  done:
776     WIN_ReleasePtr( wndPtr );
777     return ret;
778 }
779
780
781 /***********************************************************************
782  *              set_visible_style
783  *
784  * Set/clear the WS_VISIBLE style of a window and map/unmap the X window.
785  */
786 static void set_visible_style( HWND hwnd, BOOL set )
787 {
788     WND *win;
789
790     if (!(win = WIN_GetPtr( hwnd ))) return;
791     if (win == WND_OTHER_PROCESS) return;
792
793     TRACE( "hwnd %p (%lx) set %d visible %d empty %d\n",
794            hwnd, get_whole_window(win),
795            set, (win->dwStyle & WS_VISIBLE) != 0, IsRectEmpty(&win->rectWindow) );
796
797     if (set)
798     {
799         if (win->dwStyle & WS_VISIBLE) goto done;
800         WIN_SetStyle( hwnd, win->dwStyle | WS_VISIBLE );
801         if (!IsRectEmpty( &win->rectWindow ) && get_whole_window(win) && is_window_top_level(win))
802         {
803             Display *display = thread_display();
804             X11DRV_sync_window_style( display, win );
805             X11DRV_set_wm_hints( display, win );
806             TRACE( "mapping win %p\n", hwnd );
807             wine_tsx11_lock();
808             XMapWindow( display, get_whole_window(win) );
809             wine_tsx11_unlock();
810         }
811     }
812     else
813     {
814         if (!(win->dwStyle & WS_VISIBLE)) goto done;
815         WIN_SetStyle( hwnd, win->dwStyle & ~WS_VISIBLE );
816         if (!IsRectEmpty( &win->rectWindow ) && get_whole_window(win) && is_window_top_level(win))
817         {
818             TRACE( "unmapping win %p\n", hwnd );
819             wine_tsx11_lock();
820             XUnmapWindow( thread_display(), get_whole_window(win) );
821             wine_tsx11_unlock();
822         }
823     }
824  done:
825     WIN_ReleasePtr( win );
826 }
827
828
829 /***********************************************************************
830  *              SetWindowStyle   (X11DRV.@)
831  *
832  * Update the X state of a window to reflect a style change
833  */
834 void X11DRV_SetWindowStyle( HWND hwnd, LONG oldStyle )
835 {
836     Display *display = thread_display();
837     WND *wndPtr;
838     LONG changed;
839
840     if (hwnd == GetDesktopWindow()) return;
841     if (!(wndPtr = WIN_GetPtr( hwnd ))) return;
842     if (wndPtr == WND_OTHER_PROCESS) return;
843
844     changed = wndPtr->dwStyle ^ oldStyle;
845
846     if (changed & WS_VISIBLE)
847     {
848         if (!IsRectEmpty( &wndPtr->rectWindow ))
849         {
850             if (wndPtr->dwStyle & WS_VISIBLE)
851             {
852                 TRACE( "mapping win %p\n", hwnd );
853                 if (is_window_top_level(wndPtr))
854                 {
855                     X11DRV_sync_window_style( display, wndPtr );
856                     X11DRV_set_wm_hints( display, wndPtr );
857                 }
858                 wine_tsx11_lock();
859                 XMapWindow( display, get_whole_window(wndPtr) );
860                 wine_tsx11_unlock();
861             }
862             else if (!is_window_top_level(wndPtr))  /* don't unmap managed windows */
863             {
864                 TRACE( "unmapping win %p\n", hwnd );
865                 wine_tsx11_lock();
866                 XUnmapWindow( display, get_whole_window(wndPtr) );
867                 wine_tsx11_unlock();
868             }
869         }
870     }
871
872     if (changed & WS_DISABLED)
873     {
874         if (wndPtr->dwExStyle & WS_EX_MANAGED)
875         {
876             XWMHints *wm_hints;
877             wine_tsx11_lock();
878             if (!(wm_hints = XGetWMHints( display, get_whole_window(wndPtr) )))
879                 wm_hints = XAllocWMHints();
880             if (wm_hints)
881             {
882                 wm_hints->flags |= InputHint;
883                 wm_hints->input = !(wndPtr->dwStyle & WS_DISABLED);
884                 XSetWMHints( display, get_whole_window(wndPtr), wm_hints );
885                 XFree(wm_hints);
886             }
887             wine_tsx11_unlock();
888         }
889     }
890     WIN_ReleasePtr(wndPtr);
891 }
892
893
894 /***********************************************************************
895  *              SetWindowPos   (X11DRV.@)
896  */
897 BOOL X11DRV_SetWindowPos( WINDOWPOS *winpos )
898 {
899     WND *wndPtr;
900     RECT newWindowRect, newClientRect;
901     RECT oldWindowRect, oldClientRect;
902     UINT wvrFlags = 0;
903     BOOL bChangePos;
904
905     TRACE( "hwnd %p, after %p, swp %d,%d %dx%d flags %08x\n",
906            winpos->hwnd, winpos->hwndInsertAfter, winpos->x, winpos->y,
907            winpos->cx, winpos->cy, winpos->flags);
908
909     bChangePos = !(winpos->flags & SWP_WINE_NOHOSTMOVE);
910     winpos->flags &= ~SWP_WINE_NOHOSTMOVE;
911
912     /* Check window handle */
913     if (winpos->hwnd == GetDesktopWindow()) return FALSE;
914
915     if (!SWP_DoWinPosChanging( winpos, &newWindowRect, &newClientRect )) return FALSE;
916
917     /* Fix redundant flags */
918     if (!fixup_flags( winpos )) return FALSE;
919
920     if (!(wndPtr = WIN_FindWndPtr( winpos->hwnd ))) return FALSE;
921
922     TRACE("\tcurrent (%ld,%ld)-(%ld,%ld), style %08x\n",
923           wndPtr->rectWindow.left, wndPtr->rectWindow.top,
924           wndPtr->rectWindow.right, wndPtr->rectWindow.bottom, (unsigned)wndPtr->dwStyle );
925
926     if((winpos->flags & (SWP_NOZORDER | SWP_HIDEWINDOW | SWP_SHOWWINDOW)) != SWP_NOZORDER)
927     {
928         if (GetAncestor( winpos->hwnd, GA_PARENT ) == GetDesktopWindow())
929             winpos->hwndInsertAfter = SWP_DoOwnedPopups( winpos->hwnd, winpos->hwndInsertAfter );
930     }
931
932     /* Common operations */
933
934     wvrFlags = SWP_DoNCCalcSize( winpos, &newWindowRect, &newClientRect );
935
936     if(!(winpos->flags & SWP_NOZORDER) && winpos->hwnd != winpos->hwndInsertAfter)
937     {
938         HWND parent = GetAncestor( winpos->hwnd, GA_PARENT );
939         if (parent) WIN_LinkWindow( winpos->hwnd, parent, winpos->hwndInsertAfter );
940     }
941
942     /* Reset active DCEs */
943
944     if( (((winpos->flags & SWP_AGG_NOPOSCHANGE) != SWP_AGG_NOPOSCHANGE) &&
945          wndPtr->dwStyle & WS_VISIBLE) ||
946         (winpos->flags & (SWP_HIDEWINDOW | SWP_SHOWWINDOW)) )
947     {
948         RECT rect;
949
950         UnionRect(&rect, &newWindowRect, &wndPtr->rectWindow);
951         DCE_InvalidateDCE(wndPtr->hwndSelf, &rect);
952     }
953
954     oldWindowRect = wndPtr->rectWindow;
955     oldClientRect = wndPtr->rectClient;
956
957     /* Find out if we have to redraw the whole client rect */
958
959     if( oldClientRect.bottom - oldClientRect.top ==
960         newClientRect.bottom - newClientRect.top ) wvrFlags &= ~WVR_VREDRAW;
961
962     if( oldClientRect.right - oldClientRect.left ==
963         newClientRect.right - newClientRect.left ) wvrFlags &= ~WVR_HREDRAW;
964
965     /* FIXME: actually do something with WVR_VALIDRECTS */
966
967     WIN_SetRectangles( winpos->hwnd, &newWindowRect, &newClientRect );
968
969     if (get_whole_window(wndPtr))  /* don't do anything if X window not created yet */
970     {
971         Display *display = thread_display();
972
973         if (!(winpos->flags & SWP_SHOWWINDOW) && (winpos->flags & SWP_HIDEWINDOW))
974         {
975             /* clear the update region */
976             RedrawWindow( winpos->hwnd, NULL, 0, RDW_VALIDATE | RDW_NOFRAME |
977                           RDW_NOERASE | RDW_NOINTERNALPAINT | RDW_ALLCHILDREN );
978             set_visible_style( winpos->hwnd, FALSE );
979         }
980         else if ((wndPtr->dwStyle & WS_VISIBLE) &&
981                  !IsRectEmpty( &oldWindowRect ) && IsRectEmpty( &newWindowRect ))
982         {
983             /* resizing to zero size -> unmap */
984             TRACE( "unmapping zero size win %p\n", winpos->hwnd );
985             wine_tsx11_lock();
986             XUnmapWindow( display, get_whole_window(wndPtr) );
987             wine_tsx11_unlock();
988         }
989
990         wine_tsx11_lock();
991         if (bChangePos)
992             X11DRV_sync_whole_window_position( display, wndPtr, !(winpos->flags & SWP_NOZORDER) );
993         else
994         {
995             struct x11drv_win_data *data = wndPtr->pDriverData;
996             data->whole_rect = wndPtr->rectWindow;
997             X11DRV_window_to_X_rect( wndPtr, &data->whole_rect );
998         }
999
1000         if (X11DRV_sync_client_window_position( display, wndPtr ) ||
1001             (winpos->flags & SWP_FRAMECHANGED))
1002         {
1003             /* if we moved the client area, repaint the whole non-client window */
1004             XClearArea( display, get_whole_window(wndPtr), 0, 0, 0, 0, True );
1005             winpos->flags |= SWP_FRAMECHANGED;
1006         }
1007         if (winpos->flags & SWP_SHOWWINDOW)
1008         {
1009             set_visible_style( winpos->hwnd, TRUE );
1010         }
1011         else if ((wndPtr->dwStyle & WS_VISIBLE) &&
1012                  IsRectEmpty( &oldWindowRect ) && !IsRectEmpty( &newWindowRect ))
1013         {
1014             /* resizing from zero size to non-zero -> map */
1015             TRACE( "mapping non zero size win %p\n", winpos->hwnd );
1016             XMapWindow( display, get_whole_window(wndPtr) );
1017         }
1018         XFlush( display );  /* FIXME: should not be necessary */
1019         wine_tsx11_unlock();
1020     }
1021     else  /* no X window, simply toggle the window style */
1022     {
1023         if (winpos->flags & SWP_SHOWWINDOW)
1024             set_visible_style( winpos->hwnd, TRUE );
1025         else if (winpos->flags & SWP_HIDEWINDOW)
1026             set_visible_style( winpos->hwnd, FALSE );
1027     }
1028
1029     /* manually expose the areas that X won't expose because they are still covered by something */
1030
1031     if (!(winpos->flags & SWP_SHOWWINDOW))
1032         expose_covered_parent_area( wndPtr, &oldWindowRect );
1033
1034     if (wndPtr->dwStyle & WS_VISIBLE)
1035         expose_covered_window_area( wndPtr, &oldClientRect, winpos->flags & SWP_FRAMECHANGED );
1036
1037     WIN_ReleaseWndPtr(wndPtr);
1038
1039     if (wvrFlags & WVR_REDRAW) RedrawWindow( winpos->hwnd, NULL, 0, RDW_INVALIDATE | RDW_ERASE );
1040
1041     if( winpos->flags & SWP_HIDEWINDOW )
1042         HideCaret(winpos->hwnd);
1043     else if (winpos->flags & SWP_SHOWWINDOW)
1044         ShowCaret(winpos->hwnd);
1045
1046     if (!(winpos->flags & SWP_NOACTIVATE))
1047     {
1048         /* child windows get WM_CHILDACTIVATE message */
1049         if ((GetWindowLongW( winpos->hwnd, GWL_STYLE ) & (WS_CHILD | WS_POPUP)) == WS_CHILD)
1050             SendMessageA( winpos->hwnd, WM_CHILDACTIVATE, 0, 0 );
1051         else
1052             SetForegroundWindow( winpos->hwnd );
1053     }
1054
1055       /* And last, send the WM_WINDOWPOSCHANGED message */
1056
1057     TRACE("\tstatus flags = %04x\n", winpos->flags & SWP_AGG_STATUSFLAGS);
1058
1059     if (((winpos->flags & SWP_AGG_STATUSFLAGS) != SWP_AGG_NOPOSCHANGE))
1060         SendMessageA( winpos->hwnd, WM_WINDOWPOSCHANGED, 0, (LPARAM)winpos );
1061         /* WM_WINDOWPOSCHANGED is send even if SWP_NOSENDCHANGING is set */
1062
1063     return TRUE;
1064 }
1065
1066
1067 /***********************************************************************
1068  *           WINPOS_FindIconPos
1069  *
1070  * Find a suitable place for an iconic window.
1071  */
1072 static POINT WINPOS_FindIconPos( WND* wndPtr, POINT pt )
1073 {
1074     RECT rectParent;
1075     HWND *list;
1076     short x, y, xspacing, yspacing;
1077
1078     GetClientRect( wndPtr->parent, &rectParent );
1079     if ((pt.x >= rectParent.left) && (pt.x + GetSystemMetrics(SM_CXICON) < rectParent.right) &&
1080         (pt.y >= rectParent.top) && (pt.y + GetSystemMetrics(SM_CYICON) < rectParent.bottom))
1081         return pt;  /* The icon already has a suitable position */
1082
1083     xspacing = GetSystemMetrics(SM_CXICONSPACING);
1084     yspacing = GetSystemMetrics(SM_CYICONSPACING);
1085
1086     list = WIN_ListChildren( wndPtr->parent );
1087     y = rectParent.bottom;
1088     for (;;)
1089     {
1090         x = rectParent.left;
1091         do
1092         {
1093             /* Check if another icon already occupies this spot */
1094             /* FIXME: this is completely inefficient */
1095             if (list)
1096             {
1097                 int i;
1098                 WND *childPtr;
1099
1100                 for (i = 0; list[i]; i++)
1101                 {
1102                     if (list[i] == wndPtr->hwndSelf) continue;
1103                     if (!IsIconic( list[i] )) continue;
1104                     if (!(childPtr = WIN_FindWndPtr( list[i] ))) continue;
1105                     if ((childPtr->rectWindow.left < x + xspacing) &&
1106                         (childPtr->rectWindow.right >= x) &&
1107                         (childPtr->rectWindow.top <= y) &&
1108                         (childPtr->rectWindow.bottom > y - yspacing))
1109                     {
1110                         WIN_ReleaseWndPtr( childPtr );
1111                         break;  /* There's a window in there */
1112                     }
1113                     WIN_ReleaseWndPtr( childPtr );
1114                 }
1115                 if (list[i])
1116                 {
1117                     /* found something here, try next spot */
1118                     x += xspacing;
1119                     continue;
1120                 }
1121             }
1122
1123             /* No window was found, so it's OK for us */
1124             pt.x = x + (xspacing - GetSystemMetrics(SM_CXICON)) / 2;
1125             pt.y = y - (yspacing + GetSystemMetrics(SM_CYICON)) / 2;
1126             HeapFree( GetProcessHeap(), 0, list );
1127             return pt;
1128
1129         } while(x <= rectParent.right-xspacing);
1130         y -= yspacing;
1131     }
1132 }
1133
1134
1135
1136
1137
1138 UINT WINPOS_MinMaximize( HWND hwnd, UINT cmd, LPRECT rect )
1139 {
1140     WND *wndPtr;
1141     UINT swpFlags = 0;
1142     POINT size;
1143     LONG old_style;
1144     WINDOWPLACEMENT wpl;
1145
1146     TRACE("%p %u\n", hwnd, cmd );
1147
1148     wpl.length = sizeof(wpl);
1149     GetWindowPlacement( hwnd, &wpl );
1150
1151     if (HOOK_CallHooks( WH_CBT, HCBT_MINMAX, (WPARAM)hwnd, cmd, TRUE ))
1152         return SWP_NOSIZE | SWP_NOMOVE;
1153
1154     if (IsIconic( hwnd ))
1155     {
1156         if (cmd == SW_MINIMIZE) return SWP_NOSIZE | SWP_NOMOVE;
1157         if (!SendMessageA( hwnd, WM_QUERYOPEN, 0, 0 )) return SWP_NOSIZE | SWP_NOMOVE;
1158         swpFlags |= SWP_NOCOPYBITS;
1159     }
1160
1161     if (!(wndPtr = WIN_FindWndPtr( hwnd ))) return 0;
1162
1163     size.x = wndPtr->rectWindow.left;
1164     size.y = wndPtr->rectWindow.top;
1165
1166     switch( cmd )
1167     {
1168     case SW_MINIMIZE:
1169         if( wndPtr->dwStyle & WS_MAXIMIZE) wndPtr->flags |= WIN_RESTORE_MAX;
1170         else wndPtr->flags &= ~WIN_RESTORE_MAX;
1171
1172         WIN_SetStyle( hwnd, (wndPtr->dwStyle & ~WS_MAXIMIZE) | WS_MINIMIZE );
1173
1174         X11DRV_set_iconic_state( wndPtr );
1175
1176         wpl.ptMinPosition = WINPOS_FindIconPos( wndPtr, wpl.ptMinPosition );
1177
1178         SetRect( rect, wpl.ptMinPosition.x, wpl.ptMinPosition.y,
1179                  GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON) );
1180         swpFlags |= SWP_NOCOPYBITS;
1181         break;
1182
1183     case SW_MAXIMIZE:
1184         WINPOS_GetMinMaxInfo( hwnd, &size, &wpl.ptMaxPosition, NULL, NULL );
1185
1186         old_style = WIN_SetStyle( hwnd, (wndPtr->dwStyle & ~WS_MINIMIZE) | WS_MAXIMIZE );
1187         if (old_style & WS_MINIMIZE)
1188         {
1189             WINPOS_ShowIconTitle( hwnd, FALSE );
1190             X11DRV_set_iconic_state( wndPtr );
1191         }
1192         SetRect( rect, wpl.ptMaxPosition.x, wpl.ptMaxPosition.y, size.x, size.y );
1193         break;
1194
1195     case SW_RESTORE:
1196         old_style = WIN_SetStyle( hwnd, wndPtr->dwStyle & ~(WS_MINIMIZE|WS_MAXIMIZE) );
1197         if (old_style & WS_MINIMIZE)
1198         {
1199             WINPOS_ShowIconTitle( hwnd, FALSE );
1200             X11DRV_set_iconic_state( wndPtr );
1201
1202             if( wndPtr->flags & WIN_RESTORE_MAX)
1203             {
1204                 /* Restore to maximized position */
1205                 WINPOS_GetMinMaxInfo( hwnd, &size, &wpl.ptMaxPosition, NULL, NULL);
1206                 WIN_SetStyle( hwnd, wndPtr->dwStyle | WS_MAXIMIZE );
1207                 SetRect( rect, wpl.ptMaxPosition.x, wpl.ptMaxPosition.y, size.x, size.y );
1208                 break;
1209             }
1210         }
1211         else if (!(old_style & WS_MAXIMIZE)) break;
1212
1213         /* Restore to normal position */
1214
1215         *rect = wpl.rcNormalPosition;
1216         rect->right -= rect->left;
1217         rect->bottom -= rect->top;
1218
1219         break;
1220     }
1221
1222     WIN_ReleaseWndPtr( wndPtr );
1223     return swpFlags;
1224 }
1225
1226
1227 /***********************************************************************
1228  *              ShowWindow   (X11DRV.@)
1229  */
1230 BOOL X11DRV_ShowWindow( HWND hwnd, INT cmd )
1231 {
1232     WND*        wndPtr = WIN_FindWndPtr( hwnd );
1233     BOOL        wasVisible, showFlag;
1234     RECT        newPos = {0, 0, 0, 0};
1235     UINT        swp = 0;
1236
1237     if (!wndPtr) return FALSE;
1238     hwnd = wndPtr->hwndSelf;  /* make it a full handle */
1239
1240     TRACE("hwnd=%p, cmd=%d\n", hwnd, cmd);
1241
1242     wasVisible = (wndPtr->dwStyle & WS_VISIBLE) != 0;
1243
1244     switch(cmd)
1245     {
1246         case SW_HIDE:
1247             if (!wasVisible) goto END;
1248             swp |= SWP_HIDEWINDOW | SWP_NOSIZE | SWP_NOMOVE |
1249                         SWP_NOACTIVATE | SWP_NOZORDER;
1250             break;
1251
1252         case SW_SHOWMINNOACTIVE:
1253             swp |= SWP_NOACTIVATE | SWP_NOZORDER;
1254             /* fall through */
1255         case SW_SHOWMINIMIZED:
1256         case SW_FORCEMINIMIZE: /* FIXME: Does not work if thread is hung. */
1257             swp |= SWP_SHOWWINDOW;
1258             /* fall through */
1259         case SW_MINIMIZE:
1260             swp |= SWP_FRAMECHANGED;
1261             if( !(wndPtr->dwStyle & WS_MINIMIZE) )
1262                  swp |= WINPOS_MinMaximize( hwnd, SW_MINIMIZE, &newPos );
1263             else swp |= SWP_NOSIZE | SWP_NOMOVE;
1264             break;
1265
1266         case SW_SHOWMAXIMIZED: /* same as SW_MAXIMIZE */
1267             swp |= SWP_SHOWWINDOW | SWP_FRAMECHANGED;
1268             if( !(wndPtr->dwStyle & WS_MAXIMIZE) )
1269                  swp |= WINPOS_MinMaximize( hwnd, SW_MAXIMIZE, &newPos );
1270             else swp |= SWP_NOSIZE | SWP_NOMOVE;
1271             break;
1272
1273         case SW_SHOWNA:
1274             swp |= SWP_NOACTIVATE | SWP_NOZORDER;
1275             /* fall through */
1276         case SW_SHOW:
1277             swp |= SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE;
1278
1279             /*
1280              * ShowWindow has a little peculiar behavior that if the
1281              * window is already the topmost window, it will not
1282              * activate it.
1283              */
1284             if (GetTopWindow(NULL)==hwnd && (wasVisible || GetActiveWindow() == hwnd))
1285               swp |= SWP_NOACTIVATE;
1286
1287             break;
1288
1289         case SW_SHOWNOACTIVATE:
1290             swp |= SWP_NOACTIVATE | SWP_NOZORDER;
1291             /* fall through */
1292         case SW_SHOWNORMAL:  /* same as SW_NORMAL: */
1293         case SW_SHOWDEFAULT: /* FIXME: should have its own handler */
1294         case SW_RESTORE:
1295             swp |= SWP_SHOWWINDOW | SWP_FRAMECHANGED;
1296
1297             if( wndPtr->dwStyle & (WS_MINIMIZE | WS_MAXIMIZE) )
1298                  swp |= WINPOS_MinMaximize( hwnd, SW_RESTORE, &newPos );
1299             else swp |= SWP_NOSIZE | SWP_NOMOVE;
1300             break;
1301     }
1302
1303     showFlag = (cmd != SW_HIDE);
1304     if (showFlag != wasVisible)
1305     {
1306         SendMessageA( hwnd, WM_SHOWWINDOW, showFlag, 0 );
1307         if (!IsWindow( hwnd )) goto END;
1308     }
1309
1310     /* We can't activate a child window */
1311     if ((wndPtr->dwStyle & WS_CHILD) &&
1312         !(wndPtr->dwExStyle & WS_EX_MDICHILD))
1313         swp |= SWP_NOACTIVATE | SWP_NOZORDER;
1314
1315     SetWindowPos( hwnd, HWND_TOP, newPos.left, newPos.top,
1316                   newPos.right, newPos.bottom, LOWORD(swp) );
1317     if (cmd == SW_HIDE)
1318     {
1319         /* FIXME: This will cause the window to be activated irrespective
1320          * of whether it is owned by the same thread. Has to be done
1321          * asynchronously.
1322          */
1323
1324         if (hwnd == GetActiveWindow())
1325             WINPOS_ActivateOtherWindow(hwnd);
1326
1327         /* Revert focus to parent */
1328         if (hwnd == GetFocus() || IsChild(hwnd, GetFocus()))
1329             SetFocus( GetParent(hwnd) );
1330     }
1331     if (!IsWindow( hwnd )) goto END;
1332     else if( wndPtr->dwStyle & WS_MINIMIZE ) WINPOS_ShowIconTitle( hwnd, TRUE );
1333
1334     if (wndPtr->flags & WIN_NEED_SIZE)
1335     {
1336         /* should happen only in CreateWindowEx() */
1337         int wParam = SIZE_RESTORED;
1338
1339         wndPtr->flags &= ~WIN_NEED_SIZE;
1340         if (wndPtr->dwStyle & WS_MAXIMIZE) wParam = SIZE_MAXIMIZED;
1341         else if (wndPtr->dwStyle & WS_MINIMIZE) wParam = SIZE_MINIMIZED;
1342         SendMessageA( hwnd, WM_SIZE, wParam,
1343                      MAKELONG(wndPtr->rectClient.right-wndPtr->rectClient.left,
1344                             wndPtr->rectClient.bottom-wndPtr->rectClient.top));
1345         SendMessageA( hwnd, WM_MOVE, 0,
1346                    MAKELONG(wndPtr->rectClient.left, wndPtr->rectClient.top) );
1347     }
1348
1349 END:
1350     WIN_ReleaseWndPtr(wndPtr);
1351     return wasVisible;
1352 }
1353
1354
1355 /**********************************************************************
1356  *              X11DRV_MapNotify
1357  */
1358 void X11DRV_MapNotify( HWND hwnd, XMapEvent *event )
1359 {
1360     HWND hwndFocus = GetFocus();
1361     WND *win;
1362
1363     if (!(win = WIN_GetPtr( hwnd ))) return;
1364
1365     if ((win->dwStyle & WS_VISIBLE) &&
1366         (win->dwStyle & WS_MINIMIZE) &&
1367         (win->dwExStyle & WS_EX_MANAGED))
1368     {
1369         int x, y;
1370         unsigned int width, height, border, depth;
1371         Window root, top;
1372         RECT rect;
1373         LONG style = (win->dwStyle & ~(WS_MINIMIZE|WS_MAXIMIZE)) | WS_VISIBLE;
1374
1375         /* FIXME: hack */
1376         wine_tsx11_lock();
1377         XGetGeometry( event->display, get_whole_window(win), &root, &x, &y, &width, &height,
1378                         &border, &depth );
1379         XTranslateCoordinates( event->display, get_whole_window(win), root, 0, 0, &x, &y, &top );
1380         wine_tsx11_unlock();
1381         rect.left   = x;
1382         rect.top    = y;
1383         rect.right  = x + width;
1384         rect.bottom = y + height;
1385         X11DRV_X_to_window_rect( win, &rect );
1386
1387         DCE_InvalidateDCE( hwnd, &win->rectWindow );
1388
1389         if (win->flags & WIN_RESTORE_MAX) style |= WS_MAXIMIZE;
1390         WIN_SetStyle( hwnd, style );
1391         WIN_ReleasePtr( win );
1392
1393         SendMessageA( hwnd, WM_SHOWWINDOW, SW_RESTORE, 0 );
1394         SetWindowPos( hwnd, 0, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top,
1395                       SWP_NOZORDER | SWP_WINE_NOHOSTMOVE );
1396     }
1397     else WIN_ReleasePtr( win );
1398     if (hwndFocus && IsChild( hwnd, hwndFocus )) X11DRV_SetFocus(hwndFocus);  /* FIXME */
1399 }
1400
1401
1402 /**********************************************************************
1403  *              X11DRV_UnmapNotify
1404  */
1405 void X11DRV_UnmapNotify( HWND hwnd, XUnmapEvent *event )
1406 {
1407     WND *win;
1408
1409     if (!(win = WIN_GetPtr( hwnd ))) return;
1410
1411     if ((win->dwStyle & WS_VISIBLE) && (win->dwExStyle & WS_EX_MANAGED))
1412     {
1413         if (win->dwStyle & WS_MAXIMIZE)
1414             win->flags |= WIN_RESTORE_MAX;
1415         else
1416             win->flags &= ~WIN_RESTORE_MAX;
1417
1418         WIN_SetStyle( hwnd, (win->dwStyle & ~WS_MAXIMIZE) | WS_MINIMIZE );
1419         WIN_ReleasePtr( win );
1420
1421         EndMenu();
1422         SendMessageA( hwnd, WM_SHOWWINDOW, SW_MINIMIZE, 0 );
1423         SetWindowPos( hwnd, 0, 0, 0, GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON),
1424                       SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER | SWP_WINE_NOHOSTMOVE );
1425     }
1426     else WIN_ReleasePtr( win );
1427 }
1428
1429
1430 /***********************************************************************
1431  *           query_zorder
1432  *
1433  * Synchronize internal z-order with the window manager's.
1434  */
1435 static Window __get_common_ancestor( Display *display, Window A, Window B,
1436                                      Window** children, unsigned* total )
1437 {
1438     /* find the real root window */
1439
1440     Window      root, *childrenB;
1441     unsigned    totalB;
1442
1443     wine_tsx11_lock();
1444     while( A != B && A && B )
1445     {
1446       XQueryTree( display, A, &root, &A, children, total );
1447       XQueryTree( display, B, &root, &B, &childrenB, &totalB );
1448       if( childrenB ) XFree( childrenB );
1449       if( *children ) XFree( *children ), *children = NULL;
1450     }
1451
1452     if( A && B )
1453     {
1454         XQueryTree( display, A, &root, &B, children, total );
1455         wine_tsx11_unlock();
1456         return A;
1457     }
1458     wine_tsx11_unlock();
1459     return 0 ;
1460 }
1461
1462 static Window __get_top_decoration( Display *display, Window w, Window ancestor )
1463 {
1464     Window*     children, root, prev = w, parent = w;
1465     unsigned    total;
1466
1467     wine_tsx11_lock();
1468     do
1469     {
1470         w = parent;
1471         XQueryTree( display, w, &root, &parent, &children, &total );
1472         if( children ) XFree( children );
1473     } while( parent && parent != ancestor );
1474     wine_tsx11_unlock();
1475     TRACE("\t%08x -> %08x\n", (unsigned)prev, (unsigned)w );
1476     return ( parent ) ? w : 0 ;
1477 }
1478
1479 static unsigned __td_lookup( Window w, Window* list, unsigned max )
1480 {
1481     unsigned    i;
1482     for( i = max; i > 0; i-- ) if( list[i - 1] == w ) break;
1483     return i;
1484 }
1485
1486 static HWND query_zorder( Display *display, HWND hWndCheck)
1487 {
1488     HWND      hwndInsertAfter = HWND_TOP;
1489     Window      w, parent, *children = NULL;
1490     unsigned    total, check, pos, best;
1491     HWND *list = WIN_ListChildren( GetDesktopWindow() );
1492     HWND hwndA = 0, hwndB = 0;
1493     int i;
1494
1495     /* find at least two managed windows */
1496     if (!list) return 0;
1497     for (i = 0; list[i]; i++)
1498     {
1499         if (!(GetWindowLongW( list[i], GWL_EXSTYLE ) & WS_EX_MANAGED)) continue;
1500         if (!(GetWindowLongW( list[i], GWL_STYLE ) & WS_VISIBLE)) continue;
1501         if (!hwndA) hwndA = list[i];
1502         else
1503         {
1504             hwndB = list[i];
1505             break;
1506         }
1507     }
1508     if (!hwndA || !hwndB) goto done;
1509
1510     parent = __get_common_ancestor( display, X11DRV_get_whole_window(hwndA),
1511                                     X11DRV_get_whole_window(hwndB), &children, &total );
1512     if( parent && children )
1513     {
1514         /* w is the ancestor if hWndCheck that is a direct descendant of 'parent' */
1515
1516         w = __get_top_decoration( display, X11DRV_get_whole_window(hWndCheck), parent );
1517
1518         if( w != children[total-1] ) /* check if at the top */
1519         {
1520             /* X child at index 0 is at the bottom, at index total-1 is at the top */
1521             check = __td_lookup( w, children, total );
1522             best = total;
1523
1524             /* go through all windows in Wine z-order... */
1525             for (i = 0; list[i]; i++)
1526             {
1527                 if (list[i] == hWndCheck) continue;
1528                 if (!(GetWindowLongW( list[i], GWL_EXSTYLE ) & WS_EX_MANAGED)) continue;
1529                 if (!(w = __get_top_decoration( display, X11DRV_get_whole_window(list[i]),
1530                                                 parent ))) continue;
1531                 pos = __td_lookup( w, children, total );
1532                 if( pos < best && pos > check )
1533                 {
1534                     /* find a nearest Wine window precedes hWndCheck in the real z-order */
1535                     best = pos;
1536                     hwndInsertAfter = list[i];
1537                 }
1538                 if( best - check == 1 ) break;
1539             }
1540         }
1541     }
1542     wine_tsx11_lock();
1543     if( children ) XFree( children );
1544     wine_tsx11_unlock();
1545
1546  done:
1547     HeapFree( GetProcessHeap(), 0, list );
1548     return hwndInsertAfter;
1549 }
1550
1551
1552 /***********************************************************************
1553  *              X11DRV_ConfigureNotify
1554  */
1555 void X11DRV_ConfigureNotify( HWND hwnd, XConfigureEvent *event )
1556 {
1557     HWND oldInsertAfter;
1558     struct x11drv_win_data *data;
1559     WND *win;
1560     RECT rect;
1561     WINDOWPOS winpos;
1562     int x = event->x, y = event->y;
1563
1564     if (!(win = WIN_GetPtr( hwnd ))) return;
1565     data = win->pDriverData;
1566
1567     /* Get geometry */
1568
1569     if (!event->send_event)  /* normal event, need to map coordinates to the root */
1570     {
1571         Window child;
1572         wine_tsx11_lock();
1573         XTranslateCoordinates( event->display, data->whole_window, root_window,
1574                                0, 0, &x, &y, &child );
1575         wine_tsx11_unlock();
1576     }
1577     rect.left   = x;
1578     rect.top    = y;
1579     rect.right  = x + event->width;
1580     rect.bottom = y + event->height;
1581     TRACE( "win %p new X rect %ld,%ld,%ldx%ld (event %d,%d,%dx%d)\n",
1582            hwnd, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top,
1583            event->x, event->y, event->width, event->height );
1584     X11DRV_X_to_window_rect( win, &rect );
1585     WIN_ReleasePtr( win );
1586
1587     winpos.hwnd  = hwnd;
1588     winpos.x     = rect.left;
1589     winpos.y     = rect.top;
1590     winpos.cx    = rect.right - rect.left;
1591     winpos.cy    = rect.bottom - rect.top;
1592     winpos.flags = SWP_NOACTIVATE;
1593
1594     /* Get Z-order (FIXME) */
1595
1596     winpos.hwndInsertAfter = query_zorder( event->display, hwnd );
1597
1598     /* needs to find the first Visible Window above the current one */
1599     oldInsertAfter = hwnd;
1600     for (;;)
1601     {
1602         oldInsertAfter = GetWindow( oldInsertAfter, GW_HWNDPREV );
1603         if (!oldInsertAfter)
1604         {
1605             oldInsertAfter = HWND_TOP;
1606             break;
1607         }
1608         if (GetWindowLongA( oldInsertAfter, GWL_STYLE ) & WS_VISIBLE) break;
1609     }
1610
1611     /* Compare what has changed */
1612
1613     GetWindowRect( hwnd, &rect );
1614     if (rect.left == winpos.x && rect.top == winpos.y) winpos.flags |= SWP_NOMOVE;
1615     else
1616         TRACE( "%p moving from (%ld,%ld) to (%d,%d)\n",
1617                hwnd, rect.left, rect.top, winpos.x, winpos.y );
1618
1619     if ((rect.right - rect.left == winpos.cx && rect.bottom - rect.top == winpos.cy) ||
1620         IsIconic(hwnd) ||
1621         (IsRectEmpty( &rect ) && winpos.cx == 1 && winpos.cy == 1))
1622         winpos.flags |= SWP_NOSIZE;
1623     else
1624         TRACE( "%p resizing from (%ldx%ld) to (%dx%d)\n",
1625                hwnd, rect.right - rect.left, rect.bottom - rect.top,
1626                winpos.cx, winpos.cy );
1627
1628     if (winpos.hwndInsertAfter == oldInsertAfter) winpos.flags |= SWP_NOZORDER;
1629     else
1630         TRACE( "%p restacking from after %p to after %p\n",
1631                hwnd, oldInsertAfter, winpos.hwndInsertAfter );
1632
1633     /* if nothing changed, don't do anything */
1634     if (winpos.flags == (SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE)) return;
1635
1636     SetWindowPos( hwnd, winpos.hwndInsertAfter, winpos.x, winpos.y,
1637                   winpos.cx, winpos.cy, winpos.flags | SWP_WINE_NOHOSTMOVE );
1638 }
1639
1640
1641 /***********************************************************************
1642  *              SetWindowRgn  (X11DRV.@)
1643  *
1644  * Assign specified region to window (for non-rectangular windows)
1645  */
1646 int X11DRV_SetWindowRgn( HWND hwnd, HRGN hrgn, BOOL redraw )
1647 {
1648     WND *wndPtr;
1649
1650     if ((wndPtr = WIN_GetPtr( hwnd )) == WND_OTHER_PROCESS)
1651     {
1652         if (IsWindow( hwnd ))
1653             FIXME( "not supported on other process window %p\n", hwnd );
1654         wndPtr = NULL;
1655     }
1656     if (!wndPtr)
1657     {
1658         SetLastError( ERROR_INVALID_WINDOW_HANDLE );
1659         return FALSE;
1660     }
1661
1662     if (wndPtr->hrgnWnd == hrgn)
1663     {
1664         WIN_ReleasePtr( wndPtr );
1665         return TRUE;
1666     }
1667
1668     if (wndPtr->hrgnWnd)
1669     {
1670         /* delete previous region */
1671         DeleteObject(wndPtr->hrgnWnd);
1672         wndPtr->hrgnWnd = 0;
1673     }
1674     wndPtr->hrgnWnd = hrgn;
1675
1676 #ifdef HAVE_LIBXSHAPE
1677     {
1678         Display *display = thread_display();
1679         X11DRV_WND_DATA *data = wndPtr->pDriverData;
1680
1681         if (data->whole_window)
1682         {
1683             if (!hrgn)
1684             {
1685                 wine_tsx11_lock();
1686                 XShapeCombineMask( display, data->whole_window,
1687                                    ShapeBounding, 0, 0, None, ShapeSet );
1688                 wine_tsx11_unlock();
1689             }
1690             else
1691             {
1692                 XRectangle *aXRect;
1693                 int x_offset, y_offset;
1694                 DWORD size;
1695                 DWORD dwBufferSize = GetRegionData(hrgn, 0, NULL);
1696                 PRGNDATA pRegionData = HeapAlloc(GetProcessHeap(), 0, dwBufferSize);
1697                 if (!pRegionData)
1698                 {
1699                     WIN_ReleasePtr( wndPtr );
1700                     return TRUE;
1701                 }
1702                 GetRegionData(hrgn, dwBufferSize, pRegionData);
1703                 size = pRegionData->rdh.nCount;
1704                 x_offset = wndPtr->rectWindow.left - data->whole_rect.left;
1705                 y_offset = wndPtr->rectWindow.top - data->whole_rect.top;
1706                 /* convert region's "Windows rectangles" to XRectangles */
1707                 aXRect = HeapAlloc(GetProcessHeap(), 0, size * sizeof(*aXRect) );
1708                 if (aXRect)
1709                 {
1710                     XRectangle* pCurrRect = aXRect;
1711                     RECT *pRect = (RECT*) pRegionData->Buffer;
1712                     for (; pRect < ((RECT*) pRegionData->Buffer) + size ; ++pRect, ++pCurrRect)
1713                     {
1714                         pCurrRect->x      = pRect->left + x_offset;
1715                         pCurrRect->y      = pRect->top + y_offset;
1716                         pCurrRect->height = pRect->bottom - pRect->top;
1717                         pCurrRect->width  = pRect->right  - pRect->left;
1718
1719                         TRACE("Rectangle %04d of %04ld data: X=%04d, Y=%04d, Height=%04d, Width=%04d.\n",
1720                               pRect - (RECT*) pRegionData->Buffer,
1721                               size,
1722                               pCurrRect->x,
1723                               pCurrRect->y,
1724                               pCurrRect->height,
1725                               pCurrRect->width);
1726                     }
1727
1728                     /* shape = non-rectangular windows (X11/extensions) */
1729                     wine_tsx11_lock();
1730                     XShapeCombineRectangles( display, data->whole_window, ShapeBounding,
1731                                              0, 0, aXRect,
1732                                              pCurrRect - aXRect, ShapeSet, YXBanded );
1733                     wine_tsx11_unlock();
1734                     HeapFree(GetProcessHeap(), 0, aXRect );
1735                 }
1736                 HeapFree(GetProcessHeap(), 0, pRegionData);
1737             }
1738         }
1739     }
1740 #endif  /* HAVE_LIBXSHAPE */
1741
1742     WIN_ReleasePtr( wndPtr );
1743     if (redraw) RedrawWindow( hwnd, NULL, 0, RDW_FRAME | RDW_INVALIDATE | RDW_ERASE );
1744     return TRUE;
1745 }
1746
1747
1748 /***********************************************************************
1749  *           draw_moving_frame
1750  *
1751  * Draw the frame used when moving or resizing window.
1752  *
1753  * FIXME:  This causes problems in Win95 mode.  (why?)
1754  */
1755 static void draw_moving_frame( HDC hdc, RECT *rect, BOOL thickframe )
1756 {
1757     if (thickframe)
1758     {
1759         const int width = GetSystemMetrics(SM_CXFRAME);
1760         const int height = GetSystemMetrics(SM_CYFRAME);
1761
1762         HBRUSH hbrush = SelectObject( hdc, GetStockObject( GRAY_BRUSH ) );
1763         PatBlt( hdc, rect->left, rect->top,
1764                 rect->right - rect->left - width, height, PATINVERT );
1765         PatBlt( hdc, rect->left, rect->top + height, width,
1766                 rect->bottom - rect->top - height, PATINVERT );
1767         PatBlt( hdc, rect->left + width, rect->bottom - 1,
1768                 rect->right - rect->left - width, -height, PATINVERT );
1769         PatBlt( hdc, rect->right - 1, rect->top, -width,
1770                 rect->bottom - rect->top - height, PATINVERT );
1771         SelectObject( hdc, hbrush );
1772     }
1773     else DrawFocusRect( hdc, rect );
1774 }
1775
1776
1777 /***********************************************************************
1778  *           start_size_move
1779  *
1780  * Initialisation of a move or resize, when initiatied from a menu choice.
1781  * Return hit test code for caption or sizing border.
1782  */
1783 static LONG start_size_move( HWND hwnd, WPARAM wParam, POINT *capturePoint, LONG style )
1784 {
1785     LONG hittest = 0;
1786     POINT pt;
1787     MSG msg;
1788     RECT rectWindow;
1789
1790     GetWindowRect( hwnd, &rectWindow );
1791
1792     if ((wParam & 0xfff0) == SC_MOVE)
1793     {
1794         /* Move pointer at the center of the caption */
1795         RECT rect;
1796         NC_GetInsideRect( hwnd, &rect );
1797         if (style & WS_SYSMENU)
1798             rect.left += GetSystemMetrics(SM_CXSIZE) + 1;
1799         if (style & WS_MINIMIZEBOX)
1800             rect.right -= GetSystemMetrics(SM_CXSIZE) + 1;
1801         if (style & WS_MAXIMIZEBOX)
1802             rect.right -= GetSystemMetrics(SM_CXSIZE) + 1;
1803         pt.x = rectWindow.left + (rect.right - rect.left) / 2;
1804         pt.y = rectWindow.top + rect.top + GetSystemMetrics(SM_CYSIZE)/2;
1805         hittest = HTCAPTION;
1806         *capturePoint = pt;
1807     }
1808     else  /* SC_SIZE */
1809     {
1810         while(!hittest)
1811         {
1812             GetMessageW( &msg, 0, WM_KEYFIRST, WM_MOUSELAST );
1813             if (CallMsgFilterW( &msg, MSGF_SIZE )) continue;
1814
1815             switch(msg.message)
1816             {
1817             case WM_MOUSEMOVE:
1818                 hittest = NC_HandleNCHitTest( hwnd, msg.pt );
1819                 if ((hittest < HTLEFT) || (hittest > HTBOTTOMRIGHT))
1820                     hittest = 0;
1821                 break;
1822
1823             case WM_LBUTTONUP:
1824                 return 0;
1825
1826             case WM_KEYDOWN:
1827                 switch(msg.wParam)
1828                 {
1829                 case VK_UP:
1830                     hittest = HTTOP;
1831                     pt.x =(rectWindow.left+rectWindow.right)/2;
1832                     pt.y = rectWindow.top + GetSystemMetrics(SM_CYFRAME) / 2;
1833                     break;
1834                 case VK_DOWN:
1835                     hittest = HTBOTTOM;
1836                     pt.x =(rectWindow.left+rectWindow.right)/2;
1837                     pt.y = rectWindow.bottom - GetSystemMetrics(SM_CYFRAME) / 2;
1838                     break;
1839                 case VK_LEFT:
1840                     hittest = HTLEFT;
1841                     pt.x = rectWindow.left + GetSystemMetrics(SM_CXFRAME) / 2;
1842                     pt.y =(rectWindow.top+rectWindow.bottom)/2;
1843                     break;
1844                 case VK_RIGHT:
1845                     hittest = HTRIGHT;
1846                     pt.x = rectWindow.right - GetSystemMetrics(SM_CXFRAME) / 2;
1847                     pt.y =(rectWindow.top+rectWindow.bottom)/2;
1848                     break;
1849                 case VK_RETURN:
1850                 case VK_ESCAPE: return 0;
1851                 }
1852             }
1853         }
1854         *capturePoint = pt;
1855     }
1856     SetCursorPos( pt.x, pt.y );
1857     NC_HandleSetCursor( hwnd, (WPARAM)hwnd, MAKELONG( hittest, WM_MOUSEMOVE ));
1858     return hittest;
1859 }
1860
1861
1862 /***********************************************************************
1863  *           set_movesize_capture
1864  */
1865 static void set_movesize_capture( HWND hwnd )
1866 {
1867     HWND previous = 0;
1868
1869     SERVER_START_REQ( set_capture_window )
1870     {
1871         req->handle = hwnd;
1872         req->flags  = CAPTURE_MOVESIZE;
1873         if (!wine_server_call_err( req ))
1874         {
1875             previous = reply->previous;
1876             hwnd = reply->full_handle;
1877         }
1878     }
1879     SERVER_END_REQ;
1880     if (previous && previous != hwnd)
1881         SendMessageW( previous, WM_CAPTURECHANGED, 0, (LPARAM)hwnd );
1882 }
1883
1884
1885 /***********************************************************************
1886  *           SysCommandSizeMove   (X11DRV.@)
1887  *
1888  * Perform SC_MOVE and SC_SIZE commands.
1889  */
1890 void X11DRV_SysCommandSizeMove( HWND hwnd, WPARAM wParam )
1891 {
1892     MSG msg;
1893     RECT sizingRect, mouseRect, origRect;
1894     HDC hdc;
1895     HWND parent;
1896     LONG hittest = (LONG)(wParam & 0x0f);
1897     HCURSOR hDragCursor = 0, hOldCursor = 0;
1898     POINT minTrack, maxTrack;
1899     POINT capturePoint, pt;
1900     LONG style = GetWindowLongA( hwnd, GWL_STYLE );
1901     LONG exstyle = GetWindowLongA( hwnd, GWL_EXSTYLE );
1902     BOOL    thickframe = HAS_THICKFRAME( style, exstyle );
1903     BOOL    iconic = style & WS_MINIMIZE;
1904     BOOL    moved = FALSE;
1905     DWORD     dwPoint = GetMessagePos ();
1906     BOOL DragFullWindows = FALSE;
1907     BOOL grab;
1908     int iWndsLocks;
1909     Display *old_gdi_display = NULL;
1910     Display *display = thread_display();
1911
1912     SystemParametersInfoA(SPI_GETDRAGFULLWINDOWS, 0, &DragFullWindows, 0);
1913
1914     pt.x = (short)LOWORD(dwPoint);
1915     pt.y = (short)HIWORD(dwPoint);
1916     capturePoint = pt;
1917
1918     if (IsZoomed(hwnd) || !IsWindowVisible(hwnd) || (exstyle & WS_EX_MANAGED)) return;
1919
1920     if ((wParam & 0xfff0) == SC_MOVE)
1921     {
1922         if (!hittest) hittest = start_size_move( hwnd, wParam, &capturePoint, style );
1923         if (!hittest) return;
1924     }
1925     else  /* SC_SIZE */
1926     {
1927         if (!thickframe) return;
1928         if ( hittest && ((wParam & 0xfff0) != SC_MOUSEMENU) )
1929             hittest += (HTLEFT - WMSZ_LEFT);
1930         else
1931         {
1932             set_movesize_capture( hwnd );
1933             hittest = start_size_move( hwnd, wParam, &capturePoint, style );
1934             if (!hittest)
1935             {
1936                 set_movesize_capture(0);
1937                 return;
1938             }
1939         }
1940     }
1941
1942       /* Get min/max info */
1943
1944     WINPOS_GetMinMaxInfo( hwnd, NULL, NULL, &minTrack, &maxTrack );
1945     GetWindowRect( hwnd, &sizingRect );
1946     if (style & WS_CHILD)
1947     {
1948         parent = GetParent(hwnd);
1949         /* make sizing rect relative to parent */
1950         MapWindowPoints( 0, parent, (POINT*)&sizingRect, 2 );
1951         GetClientRect( parent, &mouseRect );
1952     }
1953     else
1954     {
1955         parent = 0;
1956         SetRect(&mouseRect, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));
1957     }
1958     origRect = sizingRect;
1959
1960     if (ON_LEFT_BORDER(hittest))
1961     {
1962         mouseRect.left  = max( mouseRect.left, sizingRect.right-maxTrack.x );
1963         mouseRect.right = min( mouseRect.right, sizingRect.right-minTrack.x );
1964     }
1965     else if (ON_RIGHT_BORDER(hittest))
1966     {
1967         mouseRect.left  = max( mouseRect.left, sizingRect.left+minTrack.x );
1968         mouseRect.right = min( mouseRect.right, sizingRect.left+maxTrack.x );
1969     }
1970     if (ON_TOP_BORDER(hittest))
1971     {
1972         mouseRect.top    = max( mouseRect.top, sizingRect.bottom-maxTrack.y );
1973         mouseRect.bottom = min( mouseRect.bottom,sizingRect.bottom-minTrack.y);
1974     }
1975     else if (ON_BOTTOM_BORDER(hittest))
1976     {
1977         mouseRect.top    = max( mouseRect.top, sizingRect.top+minTrack.y );
1978         mouseRect.bottom = min( mouseRect.bottom, sizingRect.top+maxTrack.y );
1979     }
1980     if (parent) MapWindowPoints( parent, 0, (LPPOINT)&mouseRect, 2 );
1981
1982     /* Retrieve a default cache DC (without using the window style) */
1983     hdc = GetDCEx( parent, 0, DCX_CACHE );
1984
1985     if( iconic ) /* create a cursor for dragging */
1986     {
1987         hDragCursor = (HCURSOR)GetClassLongA( hwnd, GCL_HICON);
1988         if( !hDragCursor ) hDragCursor = (HCURSOR)SendMessageA( hwnd, WM_QUERYDRAGICON, 0, 0L);
1989         if( !hDragCursor ) iconic = FALSE;
1990     }
1991
1992     /* repaint the window before moving it around */
1993     RedrawWindow( hwnd, NULL, 0, RDW_UPDATENOW | RDW_ALLCHILDREN );
1994
1995     SendMessageA( hwnd, WM_ENTERSIZEMOVE, 0, 0 );
1996     set_movesize_capture( hwnd );
1997
1998     /* grab the server only when moving top-level windows without desktop */
1999     grab = (!DragFullWindows && !parent && (root_window == DefaultRootWindow(gdi_display)));
2000
2001     wine_tsx11_lock();
2002     if (grab)
2003     {
2004         XSync( gdi_display, False );
2005         XGrabServer( display );
2006         XSync( display, False );
2007         /* switch gdi display to the thread display, since the server is grabbed */
2008         old_gdi_display = gdi_display;
2009         gdi_display = display;
2010     }
2011     XGrabPointer( display, X11DRV_get_whole_window(hwnd), False,
2012                   PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
2013                   GrabModeAsync, GrabModeAsync,
2014                   parent ? X11DRV_get_client_window(parent) : root_window,
2015                   None, CurrentTime );
2016     wine_tsx11_unlock();
2017
2018     while(1)
2019     {
2020         int dx = 0, dy = 0;
2021
2022         if (!GetMessageW( &msg, 0, WM_KEYFIRST, WM_MOUSELAST )) break;
2023         if (CallMsgFilterW( &msg, MSGF_SIZE )) continue;
2024
2025         /* Exit on button-up, Return, or Esc */
2026         if ((msg.message == WM_LBUTTONUP) ||
2027             ((msg.message == WM_KEYDOWN) &&
2028              ((msg.wParam == VK_RETURN) || (msg.wParam == VK_ESCAPE)))) break;
2029
2030         if ((msg.message != WM_KEYDOWN) && (msg.message != WM_MOUSEMOVE))
2031             continue;  /* We are not interested in other messages */
2032
2033         pt = msg.pt;
2034
2035         if (msg.message == WM_KEYDOWN) switch(msg.wParam)
2036         {
2037         case VK_UP:    pt.y -= 8; break;
2038         case VK_DOWN:  pt.y += 8; break;
2039         case VK_LEFT:  pt.x -= 8; break;
2040         case VK_RIGHT: pt.x += 8; break;
2041         }
2042
2043         pt.x = max( pt.x, mouseRect.left );
2044         pt.x = min( pt.x, mouseRect.right );
2045         pt.y = max( pt.y, mouseRect.top );
2046         pt.y = min( pt.y, mouseRect.bottom );
2047
2048         dx = pt.x - capturePoint.x;
2049         dy = pt.y - capturePoint.y;
2050
2051         if (dx || dy)
2052         {
2053             if( !moved )
2054             {
2055                 moved = TRUE;
2056
2057                 if( iconic ) /* ok, no system popup tracking */
2058                 {
2059                     hOldCursor = SetCursor(hDragCursor);
2060                     ShowCursor( TRUE );
2061                     WINPOS_ShowIconTitle( hwnd, FALSE );
2062                 }
2063                 else if(!DragFullWindows)
2064                     draw_moving_frame( hdc, &sizingRect, thickframe );
2065             }
2066
2067             if (msg.message == WM_KEYDOWN) SetCursorPos( pt.x, pt.y );
2068             else
2069             {
2070                 RECT newRect = sizingRect;
2071                 WPARAM wpSizingHit = 0;
2072
2073                 if (hittest == HTCAPTION) OffsetRect( &newRect, dx, dy );
2074                 if (ON_LEFT_BORDER(hittest)) newRect.left += dx;
2075                 else if (ON_RIGHT_BORDER(hittest)) newRect.right += dx;
2076                 if (ON_TOP_BORDER(hittest)) newRect.top += dy;
2077                 else if (ON_BOTTOM_BORDER(hittest)) newRect.bottom += dy;
2078                 if(!iconic && !DragFullWindows) draw_moving_frame( hdc, &sizingRect, thickframe );
2079                 capturePoint = pt;
2080
2081                 /* determine the hit location */
2082                 if (hittest >= HTLEFT && hittest <= HTBOTTOMRIGHT)
2083                     wpSizingHit = WMSZ_LEFT + (hittest - HTLEFT);
2084                 SendMessageA( hwnd, WM_SIZING, wpSizingHit, (LPARAM)&newRect );
2085
2086                 if (!iconic)
2087                 {
2088                     if(!DragFullWindows)
2089                         draw_moving_frame( hdc, &newRect, thickframe );
2090                     else {
2091                         /* To avoid any deadlocks, all the locks on the windows
2092                            structures must be suspended before the SetWindowPos */
2093                         iWndsLocks = WIN_SuspendWndsLock();
2094                         SetWindowPos( hwnd, 0, newRect.left, newRect.top,
2095                                       newRect.right - newRect.left,
2096                                       newRect.bottom - newRect.top,
2097                                       ( hittest == HTCAPTION ) ? SWP_NOSIZE : 0 );
2098                         WIN_RestoreWndsLock(iWndsLocks);
2099                     }
2100                 }
2101                 sizingRect = newRect;
2102             }
2103         }
2104     }
2105
2106     set_movesize_capture(0);
2107     if( iconic )
2108     {
2109         if( moved ) /* restore cursors, show icon title later on */
2110         {
2111             ShowCursor( FALSE );
2112             SetCursor( hOldCursor );
2113         }
2114     }
2115     else if (moved && !DragFullWindows)
2116         draw_moving_frame( hdc, &sizingRect, thickframe );
2117
2118     ReleaseDC( parent, hdc );
2119
2120     wine_tsx11_lock();
2121     XUngrabPointer( display, CurrentTime );
2122     if (grab)
2123     {
2124         XSync( display, False );
2125         XUngrabServer( display );
2126         XSync( display, False );
2127         gdi_display = old_gdi_display;
2128     }
2129     wine_tsx11_unlock();
2130
2131     if (HOOK_CallHooks( WH_CBT, HCBT_MOVESIZE, (WPARAM)hwnd, (LPARAM)&sizingRect, TRUE ))
2132         moved = FALSE;
2133
2134     SendMessageA( hwnd, WM_EXITSIZEMOVE, 0, 0 );
2135     SendMessageA( hwnd, WM_SETVISIBLE, !IsIconic(hwnd), 0L);
2136
2137     /* window moved or resized */
2138     if (moved)
2139     {
2140         /* To avoid any deadlocks, all the locks on the windows
2141            structures must be suspended before the SetWindowPos */
2142         iWndsLocks = WIN_SuspendWndsLock();
2143
2144         /* if the moving/resizing isn't canceled call SetWindowPos
2145          * with the new position or the new size of the window
2146          */
2147         if (!((msg.message == WM_KEYDOWN) && (msg.wParam == VK_ESCAPE)) )
2148         {
2149             /* NOTE: SWP_NOACTIVATE prevents document window activation in Word 6 */
2150             if(!DragFullWindows)
2151                 SetWindowPos( hwnd, 0, sizingRect.left, sizingRect.top,
2152                               sizingRect.right - sizingRect.left,
2153                               sizingRect.bottom - sizingRect.top,
2154                               ( hittest == HTCAPTION ) ? SWP_NOSIZE : 0 );
2155         }
2156         else
2157         { /* restore previous size/position */
2158             if(DragFullWindows)
2159                 SetWindowPos( hwnd, 0, origRect.left, origRect.top,
2160                               origRect.right - origRect.left,
2161                               origRect.bottom - origRect.top,
2162                               ( hittest == HTCAPTION ) ? SWP_NOSIZE : 0 );
2163         }
2164
2165         WIN_RestoreWndsLock(iWndsLocks);
2166     }
2167
2168     if (IsIconic(hwnd))
2169     {
2170         /* Single click brings up the system menu when iconized */
2171
2172         if( !moved )
2173         {
2174             if(style & WS_SYSMENU )
2175                 SendMessageA( hwnd, WM_SYSCOMMAND,
2176                               SC_MOUSEMENU + HTSYSMENU, MAKELONG(pt.x,pt.y));
2177         }
2178         else WINPOS_ShowIconTitle( hwnd, TRUE );
2179     }
2180 }
2181
2182
2183 /***********************************************************************
2184  *              ForceWindowRaise   (X11DRV.@)
2185  *
2186  * Raise a window on top of the X stacking order, while preserving
2187  * the correct Windows Z order.
2188  *
2189  * FIXME: this should go away.
2190  */
2191 void X11DRV_ForceWindowRaise( HWND hwnd )
2192 {
2193     int i = 0;
2194     HWND *list;
2195     XWindowChanges winChanges;
2196     Display *display = thread_display();
2197     WND *wndPtr = WIN_FindWndPtr( hwnd );
2198
2199     if (!wndPtr) return;
2200
2201     if ((wndPtr->dwExStyle & WS_EX_MANAGED) ||
2202         wndPtr->parent != GetDesktopWindow() ||
2203         IsRectEmpty( &wndPtr->rectWindow ) ||
2204         !get_whole_window(wndPtr))
2205     {
2206         WIN_ReleaseWndPtr( wndPtr );
2207         return;
2208     }
2209     WIN_ReleaseWndPtr( wndPtr );
2210
2211     /* Raise all windows up to wndPtr according to their Z order.
2212      * (it would be easier with sibling-related Below but it doesn't
2213      * work very well with SGI mwm for instance)
2214      */
2215     winChanges.stack_mode = Above;
2216     if (!(list = WIN_ListChildren( GetDesktopWindow() ))) return;
2217     while (list[i] && list[i] != hwnd) i++;
2218     if (list[i])
2219     {
2220         for ( ; i >= 0; i--)
2221         {
2222             WND *ptr = WIN_FindWndPtr( list[i] );
2223             if (!ptr) continue;
2224             if (!IsRectEmpty( &ptr->rectWindow ) && get_whole_window(ptr))
2225             {
2226                 wine_tsx11_lock();
2227                 XReconfigureWMWindow( display, get_whole_window(ptr), 0, CWStackMode, &winChanges );
2228                 wine_tsx11_unlock();
2229             }
2230             WIN_ReleaseWndPtr( ptr );
2231         }
2232     }
2233     HeapFree( GetProcessHeap(), 0, list );
2234 }