Documentation fixes.
[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(WND* pDesktop, WND* wndPtr, HWND hwndInsertAfter, WORD flags)
561 {
562     WND *w = WIN_LockWndPtr(pDesktop->child);
563
564     WARN("(%04x) hInsertAfter = %04x\n", wndPtr->hwndSelf, hwndInsertAfter );
565
566     if( (wndPtr->dwStyle & WS_POPUP) && wndPtr->owner )
567     {
568         /* make sure this popup stays above the owner */
569
570         HWND hwndLocalPrev = HWND_TOP;
571
572         if( hwndInsertAfter != HWND_TOP )
573         {
574             while( w && w != wndPtr->owner )
575             {
576                 if (w != wndPtr) hwndLocalPrev = w->hwndSelf;
577                 if( hwndLocalPrev == hwndInsertAfter ) break;
578                 WIN_UpdateWndPtr(&w,w->next);
579             }
580             hwndInsertAfter = hwndLocalPrev;
581         }
582     }
583     else if( wndPtr->dwStyle & WS_CHILD )
584         goto END;
585
586     WIN_UpdateWndPtr(&w, pDesktop->child);
587
588     while( w )
589     {
590         if( w == wndPtr ) break;
591
592         if( (w->dwStyle & WS_POPUP) && w->owner == wndPtr )
593         {
594             SetWindowPos(w->hwndSelf, hwndInsertAfter, 0, 0, 0, 0,
595                          SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOSENDCHANGING | SWP_DEFERERASE);
596             hwndInsertAfter = w->hwndSelf;
597         }
598         WIN_UpdateWndPtr(&w, w->next);
599     }
600
601 END:
602     WIN_ReleaseWndPtr(w);
603     return hwndInsertAfter;
604 }
605
606
607 /* fix redundant flags and values in the WINDOWPOS structure */
608 static BOOL fixup_flags( WINDOWPOS *winpos )
609 {
610     WND *wndPtr = WIN_FindWndPtr( winpos->hwnd );
611     BOOL ret = TRUE;
612
613     if (!wndPtr) return FALSE;
614
615     if (wndPtr->dwStyle & WS_VISIBLE) winpos->flags &= ~SWP_SHOWWINDOW;
616     else
617     {
618         winpos->flags &= ~SWP_HIDEWINDOW;
619         if (!(winpos->flags & SWP_SHOWWINDOW)) winpos->flags |= SWP_NOREDRAW;
620     }
621
622     if (winpos->cx < 0) winpos->cx = 0;
623     if (winpos->cy < 0) winpos->cy = 0;
624
625     if ((wndPtr->rectWindow.right - wndPtr->rectWindow.left == winpos->cx) &&
626         (wndPtr->rectWindow.bottom - wndPtr->rectWindow.top == winpos->cy))
627         winpos->flags |= SWP_NOSIZE;    /* Already the right size */
628
629     if ((wndPtr->rectWindow.left == winpos->x) && (wndPtr->rectWindow.top == winpos->y))
630         winpos->flags |= SWP_NOMOVE;    /* Already the right position */
631
632     if (winpos->hwnd == GetForegroundWindow())
633         winpos->flags |= SWP_NOACTIVATE;   /* Already active */
634     else if ((wndPtr->dwStyle & (WS_POPUP | WS_CHILD)) != WS_CHILD)
635     {
636         if (!(winpos->flags & SWP_NOACTIVATE)) /* Bring to the top when activating */
637         {
638             winpos->flags &= ~SWP_NOZORDER;
639             winpos->hwndInsertAfter = HWND_TOP;
640             goto done;
641         }
642     }
643
644     /* Check hwndInsertAfter */
645
646       /* FIXME: TOPMOST not supported yet */
647     if ((winpos->hwndInsertAfter == HWND_TOPMOST) ||
648         (winpos->hwndInsertAfter == HWND_NOTOPMOST)) winpos->hwndInsertAfter = HWND_TOP;
649
650     /* hwndInsertAfter must be a sibling of the window */
651     if ((winpos->hwndInsertAfter != HWND_TOP) && (winpos->hwndInsertAfter != HWND_BOTTOM))
652     {
653         WND* wnd = WIN_FindWndPtr(winpos->hwndInsertAfter);
654         if (wnd)
655         {
656             if (wnd->parent != wndPtr->parent) ret = FALSE;
657             else
658             {
659                 /* don't need to change the Zorder of hwnd if it's already inserted
660                  * after hwndInsertAfter or when inserting hwnd after itself.
661                  */
662                 if ((wnd->next == wndPtr ) || (winpos->hwnd == winpos->hwndInsertAfter))
663                     winpos->flags |= SWP_NOZORDER;
664             }
665             WIN_ReleaseWndPtr(wnd);
666         }
667     }
668  done:
669     WIN_ReleaseWndPtr(wndPtr);
670     return ret;
671 }
672
673
674 /***********************************************************************
675  *              SetWindowPos   (X11DRV.@)
676  */
677 BOOL X11DRV_SetWindowPos( WINDOWPOS *winpos )
678 {
679     WND *wndPtr;
680     RECT newWindowRect, newClientRect;
681     RECT oldWindowRect, oldClientRect;
682     UINT wvrFlags = 0;
683     BOOL bChangePos;
684
685     TRACE( "hwnd %04x, swp (%i,%i)-(%i,%i) flags %08x\n",
686            winpos->hwnd, winpos->x, winpos->y,
687            winpos->x + winpos->cx, winpos->y + winpos->cy, winpos->flags);
688
689     bChangePos = !(winpos->flags & SWP_WINE_NOHOSTMOVE);
690     winpos->flags &= ~SWP_WINE_NOHOSTMOVE;
691
692     /* Check window handle */
693     if (winpos->hwnd == GetDesktopWindow()) return FALSE;
694
695     /* Fix redundant flags */
696     if (!fixup_flags( winpos )) return FALSE;
697
698     SWP_DoWinPosChanging( winpos, &newWindowRect, &newClientRect );
699
700     if (!(wndPtr = WIN_FindWndPtr( winpos->hwnd ))) return FALSE;
701
702     TRACE("\tcurrent (%i,%i)-(%i,%i), style %08x\n",
703           wndPtr->rectWindow.left, wndPtr->rectWindow.top,
704           wndPtr->rectWindow.right, wndPtr->rectWindow.bottom, (unsigned)wndPtr->dwStyle );
705
706     if((winpos->flags & (SWP_NOZORDER | SWP_HIDEWINDOW | SWP_SHOWWINDOW)) != SWP_NOZORDER)
707     {
708         if( wndPtr->parent->hwndSelf == GetDesktopWindow() )
709             winpos->hwndInsertAfter = SWP_DoOwnedPopups( wndPtr->parent, wndPtr,
710                                                          winpos->hwndInsertAfter, winpos->flags );
711     }
712
713     /* Common operations */
714
715     wvrFlags = SWP_DoNCCalcSize( wndPtr, winpos, &newWindowRect, &newClientRect );
716
717     if(!(winpos->flags & SWP_NOZORDER) && winpos->hwnd != winpos->hwndInsertAfter)
718     {
719         if ( WIN_UnlinkWindow( winpos->hwnd ) )
720             WIN_LinkWindow( winpos->hwnd, winpos->hwndInsertAfter );
721     }
722
723     /* Reset active DCEs */
724
725     if( (((winpos->flags & SWP_AGG_NOPOSCHANGE) != SWP_AGG_NOPOSCHANGE) &&
726          wndPtr->dwStyle & WS_VISIBLE) ||
727         (winpos->flags & (SWP_HIDEWINDOW | SWP_SHOWWINDOW)) )
728     {
729         RECT rect;
730
731         UnionRect(&rect, &newWindowRect, &wndPtr->rectWindow);
732         DCE_InvalidateDCE(wndPtr, &rect);
733     }
734
735     oldWindowRect = wndPtr->rectWindow;
736     oldClientRect = wndPtr->rectClient;
737
738     /* Find out if we have to redraw the whole client rect */
739
740     if( oldClientRect.bottom - oldClientRect.top ==
741         newClientRect.bottom - newClientRect.top ) wvrFlags &= ~WVR_VREDRAW;
742
743     if( oldClientRect.right - oldClientRect.left ==
744         newClientRect.right - newClientRect.left ) wvrFlags &= ~WVR_HREDRAW;
745
746     /* FIXME: actually do something with WVR_VALIDRECTS */
747
748     wndPtr->rectWindow = newWindowRect;
749     wndPtr->rectClient = newClientRect;
750
751     if (winpos->flags & SWP_SHOWWINDOW) wndPtr->dwStyle |= WS_VISIBLE;
752     else if (winpos->flags & SWP_HIDEWINDOW)
753     {
754         /* clear the update region */
755         RedrawWindow( winpos->hwnd, NULL, 0, RDW_VALIDATE | RDW_NOFRAME | RDW_NOERASE |
756                                              RDW_NOINTERNALPAINT | RDW_ALLCHILDREN );
757         wndPtr->dwStyle &= ~WS_VISIBLE;
758     }
759
760     if (get_whole_window(wndPtr))  /* don't do anything if X window not created yet */
761     {
762         Display *display = thread_display();
763
764         wine_tsx11_lock();
765         if (!(winpos->flags & SWP_SHOWWINDOW) && (winpos->flags & SWP_HIDEWINDOW))
766         {
767             if (!IsRectEmpty( &oldWindowRect ))
768             {
769                 XUnmapWindow( display, get_whole_window(wndPtr) );
770                 TRACE( "unmapping win %x\n", winpos->hwnd );
771             }
772             else TRACE( "not unmapping zero size win %x\n", winpos->hwnd );
773         }
774         else if ((wndPtr->dwStyle & WS_VISIBLE) &&
775                  !IsRectEmpty( &oldWindowRect ) && IsRectEmpty( &newWindowRect ))
776         {
777             /* resizing to zero size -> unmap */
778             TRACE( "unmapping zero size win %x\n", winpos->hwnd );
779             XUnmapWindow( display, get_whole_window(wndPtr) );
780         }
781
782         if (bChangePos)
783             X11DRV_sync_whole_window_position( display, wndPtr, !(winpos->flags & SWP_NOZORDER) );
784         else
785         {
786             struct x11drv_win_data *data = wndPtr->pDriverData;
787             data->whole_rect = wndPtr->rectWindow;
788             X11DRV_window_to_X_rect( wndPtr, &data->whole_rect );
789         }
790
791         if (X11DRV_sync_client_window_position( display, wndPtr ) ||
792             (winpos->flags & SWP_FRAMECHANGED))
793         {
794             /* if we moved the client area, repaint the whole non-client window */
795             XClearArea( display, get_whole_window(wndPtr), 0, 0, 0, 0, True );
796             winpos->flags |= SWP_FRAMECHANGED;
797         }
798         if (winpos->flags & SWP_SHOWWINDOW)
799         {
800             if (!IsRectEmpty( &newWindowRect ))
801             {
802                 XMapWindow( display, get_whole_window(wndPtr) );
803                 TRACE( "mapping win %x\n", winpos->hwnd );
804             }
805             else TRACE( "not mapping win %x, size is zero\n", winpos->hwnd );
806         }
807         else if ((wndPtr->dwStyle & WS_VISIBLE) &&
808                  IsRectEmpty( &oldWindowRect ) && !IsRectEmpty( &newWindowRect ))
809         {
810             /* resizing from zero size to non-zero -> map */
811             TRACE( "mapping non zero size win %x\n", winpos->hwnd );
812             XMapWindow( display, get_whole_window(wndPtr) );
813         }
814         XFlush( display );  /* FIXME: should not be necessary */
815         wine_tsx11_unlock();
816     }
817
818     /* manually expose the areas that X won't expose because they are still covered by something */
819
820     if (!(winpos->flags & SWP_SHOWWINDOW))
821         expose_covered_parent_area( wndPtr, &oldWindowRect );
822
823     if (wndPtr->dwStyle & WS_VISIBLE)
824         expose_covered_window_area( wndPtr, &oldClientRect, winpos->flags & SWP_FRAMECHANGED );
825
826     WIN_ReleaseWndPtr(wndPtr);
827
828     if (wvrFlags & WVR_REDRAW) RedrawWindow( winpos->hwnd, NULL, 0, RDW_INVALIDATE | RDW_ERASE );
829
830     if (winpos->hwnd == CARET_GetHwnd())
831     {
832         if( winpos->flags & SWP_HIDEWINDOW )
833             HideCaret(winpos->hwnd);
834         else if (winpos->flags & SWP_SHOWWINDOW)
835             ShowCaret(winpos->hwnd);
836     }
837
838     if (!(winpos->flags & SWP_NOACTIVATE))
839         WINPOS_ChangeActiveWindow( winpos->hwnd, FALSE );
840
841       /* And last, send the WM_WINDOWPOSCHANGED message */
842
843     TRACE("\tstatus flags = %04x\n", winpos->flags & SWP_AGG_STATUSFLAGS);
844
845     if (((winpos->flags & SWP_AGG_STATUSFLAGS) != SWP_AGG_NOPOSCHANGE) &&
846           !(winpos->flags & SWP_NOSENDCHANGING))
847         SendMessageA( winpos->hwnd, WM_WINDOWPOSCHANGED, 0, (LPARAM)winpos );
848
849     return TRUE;
850 }
851
852
853 /***********************************************************************
854  *           WINPOS_FindIconPos
855  *
856  * Find a suitable place for an iconic window.
857  */
858 static POINT WINPOS_FindIconPos( WND* wndPtr, POINT pt )
859 {
860     RECT rectParent;
861     short x, y, xspacing, yspacing;
862
863     GetClientRect( wndPtr->parent->hwndSelf, &rectParent );
864     if ((pt.x >= rectParent.left) && (pt.x + GetSystemMetrics(SM_CXICON) < rectParent.right) &&
865         (pt.y >= rectParent.top) && (pt.y + GetSystemMetrics(SM_CYICON) < rectParent.bottom))
866         return pt;  /* The icon already has a suitable position */
867
868     xspacing = GetSystemMetrics(SM_CXICONSPACING);
869     yspacing = GetSystemMetrics(SM_CYICONSPACING);
870
871     y = rectParent.bottom;
872     for (;;)
873     {
874         x = rectParent.left;
875         do
876         {
877               /* Check if another icon already occupies this spot */
878             WND *childPtr = WIN_LockWndPtr(wndPtr->parent->child);
879             while (childPtr)
880             {
881                 if ((childPtr->dwStyle & WS_MINIMIZE) && (childPtr != wndPtr))
882                 {
883                     if ((childPtr->rectWindow.left < x + xspacing) &&
884                         (childPtr->rectWindow.right >= x) &&
885                         (childPtr->rectWindow.top <= y) &&
886                         (childPtr->rectWindow.bottom > y - yspacing))
887                         break;  /* There's a window in there */
888                 }
889                 WIN_UpdateWndPtr(&childPtr,childPtr->next);
890             }
891             WIN_ReleaseWndPtr(childPtr);
892             if (!childPtr) /* No window was found, so it's OK for us */
893             {
894                 pt.x = x + (xspacing - GetSystemMetrics(SM_CXICON)) / 2;
895                 pt.y = y - (yspacing + GetSystemMetrics(SM_CYICON)) / 2;
896                 return pt;
897             }
898             x += xspacing;
899         } while(x <= rectParent.right-xspacing);
900         y -= yspacing;
901     }
902 }
903
904
905
906
907
908 UINT WINPOS_MinMaximize( HWND hwnd, UINT cmd, LPRECT rect )
909 {
910     WND *wndPtr = WIN_FindWndPtr( hwnd );
911     UINT swpFlags = 0;
912     POINT size;
913     WINDOWPLACEMENT wpl;
914
915     TRACE("0x%04x %u\n", hwnd, cmd );
916
917     wpl.length = sizeof(wpl);
918     GetWindowPlacement( hwnd, &wpl );
919
920     size.x = wndPtr->rectWindow.left;
921     size.y = wndPtr->rectWindow.top;
922
923     if (!HOOK_CallHooksA(WH_CBT, HCBT_MINMAX, wndPtr->hwndSelf, cmd))
924     {
925         if( wndPtr->dwStyle & WS_MINIMIZE )
926         {
927             if( !SendMessageA( wndPtr->hwndSelf, WM_QUERYOPEN, 0, 0L ) )
928             {
929                 swpFlags = SWP_NOSIZE | SWP_NOMOVE;
930                 goto done;
931             }
932             swpFlags |= SWP_NOCOPYBITS;
933         }
934         switch( cmd )
935         {
936         case SW_MINIMIZE:
937             if( wndPtr->dwStyle & WS_MAXIMIZE)
938             {
939                 wndPtr->flags |= WIN_RESTORE_MAX;
940                 wndPtr->dwStyle &= ~WS_MAXIMIZE;
941             }
942             else
943                 wndPtr->flags &= ~WIN_RESTORE_MAX;
944             wndPtr->dwStyle |= WS_MINIMIZE;
945
946             X11DRV_set_iconic_state( wndPtr );
947
948             wpl.ptMinPosition = WINPOS_FindIconPos( wndPtr, wpl.ptMinPosition );
949
950             SetRect( rect, wpl.ptMinPosition.x, wpl.ptMinPosition.y,
951                      GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON) );
952             swpFlags |= SWP_NOCOPYBITS;
953             break;
954
955         case SW_MAXIMIZE:
956             WINPOS_GetMinMaxInfo( wndPtr, &size, &wpl.ptMaxPosition, NULL, NULL );
957
958             if( wndPtr->dwStyle & WS_MINIMIZE )
959             {
960                 wndPtr->dwStyle &= ~WS_MINIMIZE;
961                 WINPOS_ShowIconTitle( wndPtr, FALSE );
962                 X11DRV_set_iconic_state( wndPtr );
963             }
964             wndPtr->dwStyle |= WS_MAXIMIZE;
965
966             SetRect( rect, wpl.ptMaxPosition.x, wpl.ptMaxPosition.y, size.x, size.y );
967             break;
968
969         case SW_RESTORE:
970             if( wndPtr->dwStyle & WS_MINIMIZE )
971             {
972                 wndPtr->dwStyle &= ~WS_MINIMIZE;
973                 WINPOS_ShowIconTitle( wndPtr, FALSE );
974                 X11DRV_set_iconic_state( wndPtr );
975
976                 if( wndPtr->flags & WIN_RESTORE_MAX)
977                 {
978                     /* Restore to maximized position */
979                     WINPOS_GetMinMaxInfo( wndPtr, &size, &wpl.ptMaxPosition, NULL, NULL);
980                     wndPtr->dwStyle |= WS_MAXIMIZE;
981                     SetRect( rect, wpl.ptMaxPosition.x, wpl.ptMaxPosition.y, size.x, size.y );
982                     break;
983                 }
984             }
985             else
986                 if( !(wndPtr->dwStyle & WS_MAXIMIZE) )
987                 {
988                     swpFlags = (UINT16)(-1);
989                     goto done;
990                 }
991                 else wndPtr->dwStyle &= ~WS_MAXIMIZE;
992
993             /* Restore to normal position */
994
995             *rect = wpl.rcNormalPosition;
996             rect->right -= rect->left;
997             rect->bottom -= rect->top;
998
999             break;
1000         }
1001     } else swpFlags |= SWP_NOSIZE | SWP_NOMOVE;
1002
1003  done:
1004     WIN_ReleaseWndPtr( wndPtr );
1005     return swpFlags;
1006 }
1007
1008
1009 /***********************************************************************
1010  *              ShowWindow   (X11DRV.@)
1011  */
1012 BOOL X11DRV_ShowWindow( HWND hwnd, INT cmd )
1013 {
1014     WND*        wndPtr = WIN_FindWndPtr( hwnd );
1015     BOOL        wasVisible, showFlag;
1016     RECT        newPos = {0, 0, 0, 0};
1017     UINT        swp = 0;
1018
1019     if (!wndPtr) return FALSE;
1020
1021     TRACE("hwnd=%04x, cmd=%d\n", hwnd, cmd);
1022
1023     wasVisible = (wndPtr->dwStyle & WS_VISIBLE) != 0;
1024
1025     switch(cmd)
1026     {
1027         case SW_HIDE:
1028             if (!wasVisible) goto END;;
1029             swp |= SWP_HIDEWINDOW | SWP_NOSIZE | SWP_NOMOVE | 
1030                         SWP_NOACTIVATE | SWP_NOZORDER;
1031             break;
1032
1033         case SW_SHOWMINNOACTIVE:
1034             swp |= SWP_NOACTIVATE | SWP_NOZORDER;
1035             /* fall through */
1036         case SW_SHOWMINIMIZED:
1037             swp |= SWP_SHOWWINDOW;
1038             /* fall through */
1039         case SW_MINIMIZE:
1040             swp |= SWP_FRAMECHANGED;
1041             if( !(wndPtr->dwStyle & WS_MINIMIZE) )
1042                  swp |= WINPOS_MinMaximize( hwnd, SW_MINIMIZE, &newPos );
1043             else swp |= SWP_NOSIZE | SWP_NOMOVE;
1044             break;
1045
1046         case SW_SHOWMAXIMIZED: /* same as SW_MAXIMIZE */
1047             swp |= SWP_SHOWWINDOW | SWP_FRAMECHANGED;
1048             if( !(wndPtr->dwStyle & WS_MAXIMIZE) )
1049                  swp |= WINPOS_MinMaximize( hwnd, SW_MAXIMIZE, &newPos );
1050             else swp |= SWP_NOSIZE | SWP_NOMOVE;
1051             break;
1052
1053         case SW_SHOWNA:
1054             swp |= SWP_NOACTIVATE | SWP_NOZORDER;
1055             /* fall through */
1056         case SW_SHOW:
1057             swp |= SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE;
1058
1059             /*
1060              * ShowWindow has a little peculiar behavior that if the
1061              * window is already the topmost window, it will not
1062              * activate it.
1063              */
1064             if (GetTopWindow((HWND)0)==hwnd && (wasVisible || GetActiveWindow() == hwnd))
1065               swp |= SWP_NOACTIVATE;
1066
1067             break;
1068
1069         case SW_SHOWNOACTIVATE:
1070             swp |= SWP_NOZORDER;
1071             if (GetActiveWindow()) swp |= SWP_NOACTIVATE;
1072             /* fall through */
1073         case SW_SHOWNORMAL:  /* same as SW_NORMAL: */
1074         case SW_SHOWDEFAULT: /* FIXME: should have its own handler */
1075         case SW_RESTORE:
1076             swp |= SWP_SHOWWINDOW | SWP_FRAMECHANGED;
1077
1078             if( wndPtr->dwStyle & (WS_MINIMIZE | WS_MAXIMIZE) )
1079                  swp |= WINPOS_MinMaximize( hwnd, SW_RESTORE, &newPos );
1080             else swp |= SWP_NOSIZE | SWP_NOMOVE;
1081             break;
1082     }
1083
1084     showFlag = (cmd != SW_HIDE);
1085     if (showFlag != wasVisible)
1086     {
1087         SendMessageA( hwnd, WM_SHOWWINDOW, showFlag, 0 );
1088         if (!IsWindow( hwnd )) goto END;
1089     }
1090
1091     /* We can't activate a child window */
1092     if ((wndPtr->dwStyle & WS_CHILD) &&
1093         !(wndPtr->dwExStyle & WS_EX_MDICHILD))
1094         swp |= SWP_NOACTIVATE | SWP_NOZORDER;
1095
1096     SetWindowPos( hwnd, HWND_TOP, newPos.left, newPos.top,
1097                   newPos.right, newPos.bottom, LOWORD(swp) );
1098     if (cmd == SW_HIDE)
1099     {
1100         /* FIXME: This will cause the window to be activated irrespective
1101          * of whether it is owned by the same thread. Has to be done
1102          * asynchronously.
1103          */
1104
1105         if (hwnd == GetActiveWindow())
1106             WINPOS_ActivateOtherWindow(wndPtr);
1107
1108         /* Revert focus to parent */
1109         if (hwnd == GetFocus() || IsChild(hwnd, GetFocus()))
1110             SetFocus( GetParent(hwnd) );
1111     }
1112     if (!IsWindow( hwnd )) goto END;
1113     else if( wndPtr->dwStyle & WS_MINIMIZE ) WINPOS_ShowIconTitle( wndPtr, TRUE );
1114
1115     if (wndPtr->flags & WIN_NEED_SIZE)
1116     {
1117         /* should happen only in CreateWindowEx() */
1118         int wParam = SIZE_RESTORED;
1119
1120         wndPtr->flags &= ~WIN_NEED_SIZE;
1121         if (wndPtr->dwStyle & WS_MAXIMIZE) wParam = SIZE_MAXIMIZED;
1122         else if (wndPtr->dwStyle & WS_MINIMIZE) wParam = SIZE_MINIMIZED;
1123         SendMessageA( hwnd, WM_SIZE, wParam,
1124                      MAKELONG(wndPtr->rectClient.right-wndPtr->rectClient.left,
1125                             wndPtr->rectClient.bottom-wndPtr->rectClient.top));
1126         SendMessageA( hwnd, WM_MOVE, 0,
1127                    MAKELONG(wndPtr->rectClient.left, wndPtr->rectClient.top) );
1128     }
1129
1130 END:
1131     WIN_ReleaseWndPtr(wndPtr);
1132     return wasVisible;
1133 }
1134
1135
1136 /**********************************************************************
1137  *              X11DRV_MapNotify
1138  */
1139 void X11DRV_MapNotify( HWND hwnd, XMapEvent *event )
1140 {
1141     HWND hwndFocus = GetFocus();
1142     WND *win;
1143
1144     if (!(win = WIN_FindWndPtr( hwnd ))) return;
1145
1146     if ((win->dwStyle & WS_VISIBLE) &&
1147         (win->dwStyle & WS_MINIMIZE) &&
1148         (win->dwExStyle & WS_EX_MANAGED))
1149     {
1150         int x, y;
1151         unsigned int width, height, border, depth;
1152         Window root, top;
1153         RECT rect;
1154
1155         DCE_InvalidateDCE( win, &win->rectWindow );
1156         win->dwStyle &= ~WS_MINIMIZE;
1157         win->dwStyle |= WS_VISIBLE;
1158         WIN_InternalShowOwnedPopups( hwnd, TRUE, TRUE );
1159
1160         if (win->flags & WIN_RESTORE_MAX)
1161             win->dwStyle |= WS_MAXIMIZE;
1162         else
1163             win->dwStyle &= ~WS_MAXIMIZE;
1164
1165         /* FIXME: hack */
1166         wine_tsx11_lock();
1167         XGetGeometry( event->display, get_whole_window(win), &root, &x, &y, &width, &height,
1168                         &border, &depth );
1169         XTranslateCoordinates( event->display, get_whole_window(win), root, 0, 0, &x, &y, &top );
1170         wine_tsx11_unlock();
1171         rect.left   = x;
1172         rect.top    = y;
1173         rect.right  = x + width;
1174         rect.bottom = y + height;
1175         X11DRV_X_to_window_rect( win, &rect );
1176
1177         SendMessageA( hwnd, WM_SHOWWINDOW, SW_RESTORE, 0 );
1178         SetWindowPos( hwnd, 0, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top,
1179                       SWP_NOZORDER | SWP_WINE_NOHOSTMOVE );
1180     }
1181     if (hwndFocus && IsChild( hwnd, hwndFocus )) X11DRV_SetFocus(hwndFocus);  /* FIXME */
1182     WIN_ReleaseWndPtr( win );
1183 }
1184
1185
1186 /**********************************************************************
1187  *              X11DRV_UnmapNotify
1188  */
1189 void X11DRV_UnmapNotify( HWND hwnd, XUnmapEvent *event )
1190 {
1191     WND *win;
1192
1193     if (!(win = WIN_FindWndPtr( hwnd ))) return;
1194
1195     if ((win->dwStyle & WS_VISIBLE) && (win->dwExStyle & WS_EX_MANAGED))
1196     {
1197         EndMenu();
1198         SendMessageA( hwnd, WM_SHOWWINDOW, SW_MINIMIZE, 0 );
1199
1200         win->flags &= ~WIN_RESTORE_MAX;
1201         win->dwStyle |= WS_MINIMIZE;
1202
1203         if (win->dwStyle & WS_MAXIMIZE)
1204         {
1205             win->flags |= WIN_RESTORE_MAX;
1206             win->dwStyle &= ~WS_MAXIMIZE;
1207         }
1208
1209         SetWindowPos( hwnd, 0, 0, 0, GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON),
1210                       SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER | SWP_WINE_NOHOSTMOVE );
1211
1212         WIN_InternalShowOwnedPopups( hwnd, FALSE, TRUE );
1213     }
1214     WIN_ReleaseWndPtr( win );
1215 }
1216
1217
1218 /***********************************************************************
1219  *           query_zorder
1220  *
1221  * Synchronize internal z-order with the window manager's.
1222  */
1223 static BOOL __check_query_condition( WND** pWndA, WND** pWndB )
1224 {
1225     /* return TRUE if we have at least two managed windows */
1226
1227     for( *pWndB = NULL; *pWndA; *pWndA = (*pWndA)->next )
1228         if( ((*pWndA)->dwExStyle & WS_EX_MANAGED) &&
1229             ((*pWndA)->dwStyle & WS_VISIBLE )) break;
1230     if( *pWndA )
1231         for( *pWndB = (*pWndA)->next; *pWndB; *pWndB = (*pWndB)->next )
1232             if( ((*pWndB)->dwExStyle & WS_EX_MANAGED) &&
1233                 ((*pWndB)->dwStyle & WS_VISIBLE )) break;
1234     return ((*pWndB) != NULL);
1235 }
1236
1237 static Window __get_common_ancestor( Display *display, Window A, Window B,
1238                                      Window** children, unsigned* total )
1239 {
1240     /* find the real root window */
1241
1242     Window      root, *childrenB;
1243     unsigned    totalB;
1244
1245     while( A != B && A && B )
1246     {
1247       TSXQueryTree( display, A, &root, &A, children, total );
1248       TSXQueryTree( display, B, &root, &B, &childrenB, &totalB );
1249       if( childrenB ) TSXFree( childrenB );
1250       if( *children ) TSXFree( *children ), *children = NULL;
1251     }
1252
1253     if( A && B )
1254     {
1255         TSXQueryTree( display, A, &root, &B, children, total );
1256         return A;
1257     }
1258     return 0 ;
1259 }
1260
1261 static Window __get_top_decoration( Display *display, Window w, Window ancestor )
1262 {
1263     Window*     children, root, prev = w, parent = w;
1264     unsigned    total;
1265
1266     do
1267     {
1268         w = parent;
1269         TSXQueryTree( display, w, &root, &parent, &children, &total );
1270         if( children ) TSXFree( children );
1271     } while( parent && parent != ancestor );
1272     TRACE("\t%08x -> %08x\n", (unsigned)prev, (unsigned)w );
1273     return ( parent ) ? w : 0 ;
1274 }
1275
1276 static unsigned __td_lookup( Window w, Window* list, unsigned max )
1277 {
1278     unsigned    i;
1279     for( i = max - 1; i >= 0; i-- ) if( list[i] == w ) break;
1280     return i;
1281 }
1282
1283 static HWND query_zorder( Display *display, HWND hWndCheck)
1284 {
1285     HWND      hwndInsertAfter = HWND_TOP;
1286     WND      *pWndCheck = WIN_FindWndPtr(hWndCheck);
1287     WND      *pDesktop = WIN_GetDesktop();
1288     WND      *pWnd, *pWndZ = WIN_LockWndPtr(pDesktop->child);
1289     Window      w, parent, *children = NULL;
1290     unsigned    total, check, pos, best;
1291
1292     if( !__check_query_condition(&pWndZ, &pWnd) )
1293     {
1294         WIN_ReleaseWndPtr(pWndCheck);
1295         WIN_ReleaseWndPtr(pDesktop->child);
1296         WIN_ReleaseDesktop();
1297         return hwndInsertAfter;
1298     }
1299     WIN_LockWndPtr(pWndZ);
1300     WIN_LockWndPtr(pWnd);
1301     WIN_ReleaseWndPtr(pDesktop->child);
1302     WIN_ReleaseDesktop();
1303
1304     parent = __get_common_ancestor( display, get_whole_window(pWndZ),
1305                                     get_whole_window(pWnd), &children, &total );
1306     if( parent && children )
1307     {
1308         /* w is the ancestor if pWndCheck that is a direct descendant of 'parent' */
1309
1310         w = __get_top_decoration( display, get_whole_window(pWndCheck), parent );
1311
1312         if( w != children[total-1] ) /* check if at the top */
1313         {
1314             /* X child at index 0 is at the bottom, at index total-1 is at the top */
1315             check = __td_lookup( w, children, total );
1316             best = total;
1317
1318             for( WIN_UpdateWndPtr(&pWnd,pWndZ); pWnd;WIN_UpdateWndPtr(&pWnd,pWnd->next))
1319             {
1320                 /* go through all windows in Wine z-order... */
1321
1322                 if( pWnd != pWndCheck )
1323                 {
1324                     if( !(pWnd->dwExStyle & WS_EX_MANAGED) ||
1325                         !(w = __get_top_decoration( display, get_whole_window(pWnd), parent )) )
1326                         continue;
1327                     pos = __td_lookup( w, children, total );
1328                     if( pos < best && pos > check )
1329                     {
1330                         /* find a nearest Wine window precedes 
1331                          * pWndCheck in the real z-order... */
1332                         best = pos;
1333                         hwndInsertAfter = pWnd->hwndSelf;
1334                     }
1335                     if( best - check == 1 ) break;
1336                 }
1337             }
1338         }
1339     }
1340     if( children ) TSXFree( children );
1341     WIN_ReleaseWndPtr(pWnd);
1342     WIN_ReleaseWndPtr(pWndZ);
1343     WIN_ReleaseWndPtr(pWndCheck);
1344     return hwndInsertAfter;
1345 }
1346
1347
1348 /***********************************************************************
1349  *              X11DRV_ConfigureNotify
1350  */
1351 void X11DRV_ConfigureNotify( HWND hwnd, XConfigureEvent *event )
1352 {
1353     HWND oldInsertAfter;
1354     struct x11drv_win_data *data;
1355     WND *win;
1356     RECT rect;
1357     WINDOWPOS winpos;
1358     int x = event->x, y = event->y;
1359
1360     if (!(win = WIN_FindWndPtr( hwnd ))) return;
1361     data = win->pDriverData;
1362
1363     /* Get geometry */
1364
1365     if (!event->send_event)  /* normal event, need to map coordinates to the root */
1366     {
1367         Window child;
1368         wine_tsx11_lock();
1369         XTranslateCoordinates( event->display, data->whole_window, root_window,
1370                                0, 0, &x, &y, &child );
1371         wine_tsx11_unlock();
1372     }
1373     rect.left   = x;
1374     rect.top    = y;
1375     rect.right  = x + event->width;
1376     rect.bottom = y + event->height;
1377     TRACE( "win %x new X rect %d,%d,%dx%d (event %d,%d,%dx%d)\n",
1378            hwnd, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top,
1379            event->x, event->y, event->width, event->height );
1380     X11DRV_X_to_window_rect( win, &rect );
1381     WIN_ReleaseWndPtr( win );
1382
1383     winpos.hwnd  = hwnd;
1384     winpos.x     = rect.left;
1385     winpos.y     = rect.top;
1386     winpos.cx    = rect.right - rect.left;
1387     winpos.cy    = rect.bottom - rect.top;
1388     winpos.flags = SWP_NOACTIVATE;
1389
1390     /* Get Z-order (FIXME) */
1391
1392     winpos.hwndInsertAfter = query_zorder( event->display, hwnd );
1393
1394     /* needs to find the first Visible Window above the current one */
1395     oldInsertAfter = hwnd;
1396     for (;;)
1397     {
1398         oldInsertAfter = GetWindow( oldInsertAfter, GW_HWNDPREV );
1399         if (!oldInsertAfter)
1400         {
1401             oldInsertAfter = HWND_TOP;
1402             break;
1403         }
1404         if (GetWindowLongA( oldInsertAfter, GWL_STYLE ) & WS_VISIBLE) break;
1405     }
1406
1407     /* Compare what has changed */
1408
1409     GetWindowRect( hwnd, &rect );
1410     if (rect.left == winpos.x && rect.top == winpos.y) winpos.flags |= SWP_NOMOVE;
1411     else
1412         TRACE( "%04x moving from (%d,%d) to (%d,%d)\n",
1413                hwnd, rect.left, rect.top, winpos.x, winpos.y );
1414
1415     if (rect.right - rect.left == winpos.cx &&
1416         rect.bottom - rect.top == winpos.cy) winpos.flags |= SWP_NOSIZE;
1417     else
1418         TRACE( "%04x resizing from (%dx%d) to (%dx%d)\n",
1419                hwnd, rect.right - rect.left, rect.bottom - rect.top,
1420                winpos.cx, winpos.cy );
1421
1422     if (winpos.hwndInsertAfter == oldInsertAfter) winpos.flags |= SWP_NOZORDER;
1423     else
1424         TRACE( "%04x restacking from after %04x to after %04x\n",
1425                hwnd, oldInsertAfter, winpos.hwndInsertAfter );
1426
1427     /* if nothing changed, don't do anything */
1428     if (winpos.flags == (SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE)) return;
1429
1430     SetWindowPos( hwnd, winpos.hwndInsertAfter, winpos.x, winpos.y,
1431                   winpos.cx, winpos.cy, winpos.flags | SWP_WINE_NOHOSTMOVE );
1432 }
1433
1434
1435 /***********************************************************************
1436  *              SetWindowRgn  (X11DRV.@)
1437  *
1438  * Assign specified region to window (for non-rectangular windows)
1439  */
1440 BOOL X11DRV_SetWindowRgn( HWND hwnd, HRGN hrgn, BOOL redraw )
1441 {
1442     RECT rect;
1443     WND *wndPtr = WIN_FindWndPtr(hwnd);
1444     int ret = FALSE;
1445
1446     if (!wndPtr) return FALSE;
1447
1448     if (wndPtr->hrgnWnd == hrgn)
1449     {
1450         ret = TRUE;
1451         goto done;
1452     }
1453
1454     if (hrgn) /* verify that region really exists */
1455     {
1456         if (GetRgnBox( hrgn, &rect ) == ERROR) goto done;
1457     }
1458
1459     if (wndPtr->hrgnWnd)
1460     {
1461         /* delete previous region */
1462         DeleteObject(wndPtr->hrgnWnd);
1463         wndPtr->hrgnWnd = 0;
1464     }
1465     wndPtr->hrgnWnd = hrgn;
1466
1467 #ifdef HAVE_LIBXSHAPE
1468     {
1469         Display *display = thread_display();
1470         X11DRV_WND_DATA *data = wndPtr->pDriverData;
1471
1472         if (data->whole_window)
1473         {
1474             if (!hrgn)
1475             {
1476                 TSXShapeCombineMask( display, data->whole_window,
1477                                      ShapeBounding, 0, 0, None, ShapeSet );
1478             }
1479             else
1480             {
1481                 XRectangle *aXRect;
1482                 int x_offset, y_offset;
1483                 DWORD size;
1484                 DWORD dwBufferSize = GetRegionData(hrgn, 0, NULL);
1485                 PRGNDATA pRegionData = HeapAlloc(GetProcessHeap(), 0, dwBufferSize);
1486                 if (!pRegionData) goto done;
1487
1488                 GetRegionData(hrgn, dwBufferSize, pRegionData);
1489                 size = pRegionData->rdh.nCount;
1490                 x_offset = wndPtr->rectWindow.left - data->whole_rect.left;
1491                 y_offset = wndPtr->rectWindow.top - data->whole_rect.top;
1492                 /* convert region's "Windows rectangles" to XRectangles */
1493                 aXRect = HeapAlloc(GetProcessHeap(), 0, size * sizeof(*aXRect) );
1494                 if (aXRect)
1495                 {
1496                     XRectangle* pCurrRect = aXRect;
1497                     RECT *pRect = (RECT*) pRegionData->Buffer;
1498                     for (; pRect < ((RECT*) pRegionData->Buffer) + size ; ++pRect, ++pCurrRect)
1499                     {
1500                         pCurrRect->x      = pRect->left + x_offset;
1501                         pCurrRect->y      = pRect->top + y_offset;
1502                         pCurrRect->height = pRect->bottom - pRect->top;
1503                         pCurrRect->width  = pRect->right  - pRect->left;
1504
1505                         TRACE("Rectangle %04d of %04ld data: X=%04d, Y=%04d, Height=%04d, Width=%04d.\n",
1506                               pRect - (RECT*) pRegionData->Buffer,
1507                               size,
1508                               pCurrRect->x,
1509                               pCurrRect->y,
1510                               pCurrRect->height,
1511                               pCurrRect->width);
1512                     }
1513
1514                     /* shape = non-rectangular windows (X11/extensions) */
1515                     TSXShapeCombineRectangles( display, data->whole_window, ShapeBounding,
1516                                                0, 0, aXRect,
1517                                                pCurrRect - aXRect, ShapeSet, YXBanded );
1518                     HeapFree(GetProcessHeap(), 0, aXRect );
1519                 }
1520                 HeapFree(GetProcessHeap(), 0, pRegionData);
1521             }
1522         }
1523     }
1524 #endif  /* HAVE_LIBXSHAPE */
1525
1526     if (redraw) RedrawWindow( hwnd, NULL, 0, RDW_FRAME | RDW_INVALIDATE | RDW_ERASE );
1527     ret = TRUE;
1528
1529  done:
1530     WIN_ReleaseWndPtr(wndPtr);
1531     return ret;
1532 }
1533
1534
1535 /***********************************************************************
1536  *           draw_moving_frame
1537  *
1538  * Draw the frame used when moving or resizing window.
1539  *
1540  * FIXME:  This causes problems in Win95 mode.  (why?)
1541  */
1542 static void draw_moving_frame( HDC hdc, RECT *rect, BOOL thickframe )
1543 {
1544     if (thickframe)
1545     {
1546         const int width = GetSystemMetrics(SM_CXFRAME);
1547         const int height = GetSystemMetrics(SM_CYFRAME);
1548
1549         HBRUSH hbrush = SelectObject( hdc, GetStockObject( GRAY_BRUSH ) );
1550         PatBlt( hdc, rect->left, rect->top,
1551                 rect->right - rect->left - width, height, PATINVERT );
1552         PatBlt( hdc, rect->left, rect->top + height, width,
1553                 rect->bottom - rect->top - height, PATINVERT );
1554         PatBlt( hdc, rect->left + width, rect->bottom - 1,
1555                 rect->right - rect->left - width, -height, PATINVERT );
1556         PatBlt( hdc, rect->right - 1, rect->top, -width,
1557                 rect->bottom - rect->top - height, PATINVERT );
1558         SelectObject( hdc, hbrush );
1559     }
1560     else DrawFocusRect( hdc, rect );
1561 }
1562
1563
1564 /***********************************************************************
1565  *           start_size_move
1566  *
1567  * Initialisation of a move or resize, when initiatied from a menu choice.
1568  * Return hit test code for caption or sizing border.
1569  */
1570 static LONG start_size_move( WND* wndPtr, WPARAM wParam, POINT *capturePoint )
1571 {
1572     LONG hittest = 0;
1573     POINT pt;
1574     MSG msg;
1575     RECT rectWindow;
1576
1577     GetWindowRect(wndPtr->hwndSelf,&rectWindow);
1578
1579     if ((wParam & 0xfff0) == SC_MOVE)
1580     {
1581         /* Move pointer at the center of the caption */
1582         RECT rect;
1583         NC_GetInsideRect( wndPtr->hwndSelf, &rect );
1584         if (wndPtr->dwStyle & WS_SYSMENU)
1585             rect.left += GetSystemMetrics(SM_CXSIZE) + 1;
1586         if (wndPtr->dwStyle & WS_MINIMIZEBOX)
1587             rect.right -= GetSystemMetrics(SM_CXSIZE) + 1;
1588         if (wndPtr->dwStyle & WS_MAXIMIZEBOX)
1589             rect.right -= GetSystemMetrics(SM_CXSIZE) + 1;
1590         pt.x = rectWindow.left + (rect.right - rect.left) / 2;
1591         pt.y = rectWindow.top + rect.top + GetSystemMetrics(SM_CYSIZE)/2;
1592         hittest = HTCAPTION;
1593         *capturePoint = pt;
1594     }
1595     else  /* SC_SIZE */
1596     {
1597         while(!hittest)
1598         {
1599             MSG_InternalGetMessage( &msg, 0, 0, WM_KEYFIRST, WM_MOUSELAST,
1600                                     MSGF_SIZE, PM_REMOVE, FALSE, NULL );
1601             switch(msg.message)
1602             {
1603             case WM_MOUSEMOVE:
1604                 hittest = NC_HandleNCHitTest( wndPtr->hwndSelf, msg.pt );
1605                 if ((hittest < HTLEFT) || (hittest > HTBOTTOMRIGHT))
1606                     hittest = 0;
1607                 break;
1608
1609             case WM_LBUTTONUP:
1610                 return 0;
1611
1612             case WM_KEYDOWN:
1613                 switch(msg.wParam)
1614                 {
1615                 case VK_UP:
1616                     hittest = HTTOP;
1617                     pt.x =(rectWindow.left+rectWindow.right)/2;
1618                     pt.y = rectWindow.top + GetSystemMetrics(SM_CYFRAME) / 2;
1619                     break;
1620                 case VK_DOWN:
1621                     hittest = HTBOTTOM;
1622                     pt.x =(rectWindow.left+rectWindow.right)/2;
1623                     pt.y = rectWindow.bottom - GetSystemMetrics(SM_CYFRAME) / 2;
1624                     break;
1625                 case VK_LEFT:
1626                     hittest = HTLEFT;
1627                     pt.x = rectWindow.left + GetSystemMetrics(SM_CXFRAME) / 2;
1628                     pt.y =(rectWindow.top+rectWindow.bottom)/2;
1629                     break;
1630                 case VK_RIGHT:
1631                     hittest = HTRIGHT;
1632                     pt.x = rectWindow.right - GetSystemMetrics(SM_CXFRAME) / 2;
1633                     pt.y =(rectWindow.top+rectWindow.bottom)/2;
1634                     break;
1635                 case VK_RETURN:
1636                 case VK_ESCAPE: return 0;
1637                 }
1638             }
1639         }
1640         *capturePoint = pt;
1641     }
1642     SetCursorPos( pt.x, pt.y );
1643     NC_HandleSetCursor( wndPtr->hwndSelf,
1644                         wndPtr->hwndSelf, MAKELONG( hittest, WM_MOUSEMOVE ));
1645     return hittest;
1646 }
1647
1648
1649 /***********************************************************************
1650  *           SysCommandSizeMove   (X11DRV.@)
1651  *
1652  * Perform SC_MOVE and SC_SIZE commands.
1653  */
1654 void X11DRV_SysCommandSizeMove( HWND hwnd, WPARAM wParam )
1655 {
1656     MSG msg;
1657     RECT sizingRect, mouseRect, origRect;
1658     HDC hdc;
1659     LONG hittest = (LONG)(wParam & 0x0f);
1660     HCURSOR16 hDragCursor = 0, hOldCursor = 0;
1661     POINT minTrack, maxTrack;
1662     POINT capturePoint, pt;
1663     WND *     wndPtr = WIN_FindWndPtr( hwnd );
1664     BOOL    thickframe = HAS_THICKFRAME( wndPtr->dwStyle, wndPtr->dwExStyle );
1665     BOOL    iconic = wndPtr->dwStyle & WS_MINIMIZE;
1666     BOOL    moved = FALSE;
1667     DWORD     dwPoint = GetMessagePos ();
1668     BOOL DragFullWindows = FALSE;
1669     BOOL grab;
1670     int iWndsLocks;
1671     Display *old_gdi_display = NULL;
1672     Display *display = thread_display();
1673
1674     SystemParametersInfoA(SPI_GETDRAGFULLWINDOWS, 0, &DragFullWindows, 0);
1675
1676     pt.x = SLOWORD(dwPoint);
1677     pt.y = SHIWORD(dwPoint);
1678     capturePoint = pt;
1679
1680     if (IsZoomed(hwnd) || !IsWindowVisible(hwnd) ||
1681         (wndPtr->dwExStyle & WS_EX_MANAGED)) goto END;
1682
1683     if ((wParam & 0xfff0) == SC_MOVE)
1684     {
1685         if (!hittest) hittest = start_size_move( wndPtr, wParam, &capturePoint );
1686         if (!hittest) goto END;
1687     }
1688     else  /* SC_SIZE */
1689     {
1690         if (!thickframe) goto END;
1691         if ( hittest && hittest != HTSYSMENU ) hittest += 2;
1692         else
1693         {
1694             SetCapture(hwnd);
1695             hittest = start_size_move( wndPtr, wParam, &capturePoint );
1696             if (!hittest)
1697             {
1698                 ReleaseCapture();
1699                 goto END;
1700             }
1701         }
1702     }
1703
1704       /* Get min/max info */
1705
1706     WINPOS_GetMinMaxInfo( wndPtr, NULL, NULL, &minTrack, &maxTrack );
1707     sizingRect = wndPtr->rectWindow;
1708     origRect = sizingRect;
1709     if (wndPtr->dwStyle & WS_CHILD)
1710         GetClientRect( wndPtr->parent->hwndSelf, &mouseRect );
1711     else
1712         SetRect(&mouseRect, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));
1713     if (ON_LEFT_BORDER(hittest))
1714     {
1715         mouseRect.left  = max( mouseRect.left, sizingRect.right-maxTrack.x );
1716         mouseRect.right = min( mouseRect.right, sizingRect.right-minTrack.x );
1717     }
1718     else if (ON_RIGHT_BORDER(hittest))
1719     {
1720         mouseRect.left  = max( mouseRect.left, sizingRect.left+minTrack.x );
1721         mouseRect.right = min( mouseRect.right, sizingRect.left+maxTrack.x );
1722     }
1723     if (ON_TOP_BORDER(hittest))
1724     {
1725         mouseRect.top    = max( mouseRect.top, sizingRect.bottom-maxTrack.y );
1726         mouseRect.bottom = min( mouseRect.bottom,sizingRect.bottom-minTrack.y);
1727     }
1728     else if (ON_BOTTOM_BORDER(hittest))
1729     {
1730         mouseRect.top    = max( mouseRect.top, sizingRect.top+minTrack.y );
1731         mouseRect.bottom = min( mouseRect.bottom, sizingRect.top+maxTrack.y );
1732     }
1733     if (wndPtr->dwStyle & WS_CHILD)
1734     {
1735         MapWindowPoints( wndPtr->parent->hwndSelf, 0, (LPPOINT)&mouseRect, 2 );
1736     }
1737
1738     /* Retrieve a default cache DC (without using the window style) */
1739     hdc = GetDCEx( wndPtr->parent->hwndSelf, 0, DCX_CACHE );
1740
1741     if( iconic ) /* create a cursor for dragging */
1742     {
1743         HICON hIcon = GetClassLongA( hwnd, GCL_HICON);
1744         if(!hIcon) hIcon = (HICON)SendMessageA( hwnd, WM_QUERYDRAGICON, 0, 0L);
1745         if( hIcon ) hDragCursor =  CURSORICON_IconToCursor( hIcon, TRUE );
1746         if( !hDragCursor ) iconic = FALSE;
1747     }
1748
1749     /* repaint the window before moving it around */
1750     RedrawWindow( hwnd, NULL, 0, RDW_UPDATENOW | RDW_ALLCHILDREN );
1751
1752     SendMessageA( hwnd, WM_ENTERSIZEMOVE, 0, 0 );
1753     SetCapture( hwnd );
1754
1755     /* grab the server only when moving top-level windows without desktop */
1756     grab = (!DragFullWindows && (root_window == DefaultRootWindow(gdi_display)) &&
1757             (wndPtr->parent->hwndSelf == GetDesktopWindow()));
1758
1759     wine_tsx11_lock();
1760     if (grab)
1761     {
1762         XSync( gdi_display, False );
1763         XGrabServer( display );
1764         XSync( display, False );
1765         /* switch gdi display to the thread display, since the server is grabbed */
1766         old_gdi_display = gdi_display;
1767         gdi_display = display;
1768     }
1769     XGrabPointer( display, get_whole_window(wndPtr), False,
1770                   PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
1771                   GrabModeAsync, GrabModeAsync, get_client_window(wndPtr->parent),
1772                   None, CurrentTime );
1773     wine_tsx11_unlock();
1774
1775     while(1)
1776     {
1777         int dx = 0, dy = 0;
1778
1779         MSG_InternalGetMessage( &msg, 0, 0, WM_KEYFIRST, WM_MOUSELAST,
1780                                 MSGF_SIZE, PM_REMOVE, FALSE, NULL );
1781
1782         /* Exit on button-up, Return, or Esc */
1783         if ((msg.message == WM_LBUTTONUP) ||
1784             ((msg.message == WM_KEYDOWN) &&
1785              ((msg.wParam == VK_RETURN) || (msg.wParam == VK_ESCAPE)))) break;
1786
1787         if ((msg.message != WM_KEYDOWN) && (msg.message != WM_MOUSEMOVE))
1788             continue;  /* We are not interested in other messages */
1789
1790         pt = msg.pt;
1791
1792         if (msg.message == WM_KEYDOWN) switch(msg.wParam)
1793         {
1794         case VK_UP:    pt.y -= 8; break;
1795         case VK_DOWN:  pt.y += 8; break;
1796         case VK_LEFT:  pt.x -= 8; break;
1797         case VK_RIGHT: pt.x += 8; break;
1798         }
1799
1800         pt.x = max( pt.x, mouseRect.left );
1801         pt.x = min( pt.x, mouseRect.right );
1802         pt.y = max( pt.y, mouseRect.top );
1803         pt.y = min( pt.y, mouseRect.bottom );
1804
1805         dx = pt.x - capturePoint.x;
1806         dy = pt.y - capturePoint.y;
1807
1808         if (dx || dy)
1809         {
1810             if( !moved )
1811             {
1812                 moved = TRUE;
1813
1814                 if( iconic ) /* ok, no system popup tracking */
1815                 {
1816                     hOldCursor = SetCursor(hDragCursor);
1817                     ShowCursor( TRUE );
1818                     WINPOS_ShowIconTitle( wndPtr, FALSE );
1819                 }
1820                 else if(!DragFullWindows)
1821                     draw_moving_frame( hdc, &sizingRect, thickframe );
1822             }
1823
1824             if (msg.message == WM_KEYDOWN) SetCursorPos( pt.x, pt.y );
1825             else
1826             {
1827                 RECT newRect = sizingRect;
1828                 WPARAM wpSizingHit = 0;
1829
1830                 if (hittest == HTCAPTION) OffsetRect( &newRect, dx, dy );
1831                 if (ON_LEFT_BORDER(hittest)) newRect.left += dx;
1832                 else if (ON_RIGHT_BORDER(hittest)) newRect.right += dx;
1833                 if (ON_TOP_BORDER(hittest)) newRect.top += dy;
1834                 else if (ON_BOTTOM_BORDER(hittest)) newRect.bottom += dy;
1835                 if(!iconic && !DragFullWindows) draw_moving_frame( hdc, &sizingRect, thickframe );
1836                 capturePoint = pt;
1837
1838                 /* determine the hit location */
1839                 if (hittest >= HTLEFT && hittest <= HTBOTTOMRIGHT)
1840                     wpSizingHit = WMSZ_LEFT + (hittest - HTLEFT);
1841                 SendMessageA( hwnd, WM_SIZING, wpSizingHit, (LPARAM)&newRect );
1842
1843                 if (!iconic)
1844                 {
1845                     if(!DragFullWindows)
1846                         draw_moving_frame( hdc, &newRect, thickframe );
1847                     else {
1848                         /* To avoid any deadlocks, all the locks on the windows
1849                            structures must be suspended before the SetWindowPos */
1850                         iWndsLocks = WIN_SuspendWndsLock();
1851                         SetWindowPos( hwnd, 0, newRect.left, newRect.top,
1852                                       newRect.right - newRect.left,
1853                                       newRect.bottom - newRect.top,
1854                                       ( hittest == HTCAPTION ) ? SWP_NOSIZE : 0 );
1855                         WIN_RestoreWndsLock(iWndsLocks);
1856                     }
1857                 }
1858                 sizingRect = newRect;
1859             }
1860         }
1861     }
1862
1863     ReleaseCapture();
1864     if( iconic )
1865     {
1866         if( moved ) /* restore cursors, show icon title later on */
1867         {
1868             ShowCursor( FALSE );
1869             SetCursor( hOldCursor );
1870         }
1871         DestroyCursor( hDragCursor );
1872     }
1873     else if (moved && !DragFullWindows)
1874         draw_moving_frame( hdc, &sizingRect, thickframe );
1875
1876     ReleaseDC( wndPtr->parent->hwndSelf, hdc );
1877
1878     wine_tsx11_lock();
1879     XUngrabPointer( display, CurrentTime );
1880     if (grab)
1881     {
1882         XSync( display, False );
1883         XUngrabServer( display );
1884         XSync( display, False );
1885         gdi_display = old_gdi_display;
1886     }
1887     wine_tsx11_unlock();
1888
1889     if (HOOK_CallHooksA( WH_CBT, HCBT_MOVESIZE, hwnd, (LPARAM)&sizingRect ))
1890         sizingRect = wndPtr->rectWindow;
1891
1892     SendMessageA( hwnd, WM_EXITSIZEMOVE, 0, 0 );
1893     SendMessageA( hwnd, WM_SETVISIBLE, !IsIconic(hwnd), 0L);
1894
1895     /* window moved or resized */
1896     if (moved)
1897     {
1898         /* To avoid any deadlocks, all the locks on the windows
1899            structures must be suspended before the SetWindowPos */
1900         iWndsLocks = WIN_SuspendWndsLock();
1901
1902         /* if the moving/resizing isn't canceled call SetWindowPos
1903          * with the new position or the new size of the window
1904          */
1905         if (!((msg.message == WM_KEYDOWN) && (msg.wParam == VK_ESCAPE)) )
1906         {
1907             /* NOTE: SWP_NOACTIVATE prevents document window activation in Word 6 */
1908             if(!DragFullWindows)
1909                 SetWindowPos( hwnd, 0, sizingRect.left, sizingRect.top,
1910                               sizingRect.right - sizingRect.left,
1911                               sizingRect.bottom - sizingRect.top,
1912                               ( hittest == HTCAPTION ) ? SWP_NOSIZE : 0 );
1913         }
1914         else
1915         { /* restore previous size/position */
1916             if(DragFullWindows)
1917                 SetWindowPos( hwnd, 0, origRect.left, origRect.top,
1918                               origRect.right - origRect.left,
1919                               origRect.bottom - origRect.top,
1920                               ( hittest == HTCAPTION ) ? SWP_NOSIZE : 0 );
1921         }
1922
1923         WIN_RestoreWndsLock(iWndsLocks);
1924     }
1925
1926     if (IsIconic(hwnd))
1927     {
1928         /* Single click brings up the system menu when iconized */
1929
1930         if( !moved )
1931         {
1932             if( wndPtr->dwStyle & WS_SYSMENU )
1933                 SendMessageA( hwnd, WM_SYSCOMMAND,
1934                               SC_MOUSEMENU + HTSYSMENU, MAKELONG(pt.x,pt.y));
1935         }
1936         else WINPOS_ShowIconTitle( wndPtr, TRUE );
1937     }
1938
1939 END:
1940     WIN_ReleaseWndPtr(wndPtr);
1941 }
1942
1943
1944 /***********************************************************************
1945  *              ForceWindowRaise   (X11DRV.@)
1946  *
1947  * Raise a window on top of the X stacking order, while preserving 
1948  * the correct Windows Z order.
1949  *
1950  * FIXME: this should go away.
1951  */
1952 void X11DRV_ForceWindowRaise( HWND hwnd )
1953 {
1954     XWindowChanges winChanges;
1955     Display *display = thread_display();
1956     WND *wndPrev, *wndPtr = WIN_FindWndPtr( hwnd );
1957
1958     if (!wndPtr) return;
1959
1960     if ((wndPtr->dwExStyle & WS_EX_MANAGED) ||
1961         wndPtr->parent->hwndSelf != GetDesktopWindow() ||
1962         IsRectEmpty( &wndPtr->rectWindow ) ||
1963         !get_whole_window(wndPtr))
1964     {
1965         WIN_ReleaseWndPtr( wndPtr );
1966         return;
1967     }
1968
1969     /* Raise all windows up to wndPtr according to their Z order.
1970      * (it would be easier with sibling-related Below but it doesn't
1971      * work very well with SGI mwm for instance)
1972      */
1973     winChanges.stack_mode = Above;
1974     while (wndPtr)
1975     {
1976         if (!IsRectEmpty( &wndPtr->rectWindow ) && get_whole_window(wndPtr))
1977             TSXReconfigureWMWindow( display, get_whole_window(wndPtr), 0,
1978                                     CWStackMode, &winChanges );
1979         wndPrev = wndPtr->parent->child;
1980         if (wndPrev == wndPtr) break;
1981         while (wndPrev && (wndPrev->next != wndPtr)) wndPrev = wndPrev->next;
1982         WIN_UpdateWndPtr( &wndPtr, wndPrev );
1983     }
1984     WIN_ReleaseWndPtr( wndPtr );
1985 }