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