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