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