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