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