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