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