winpos.c 60.1 KB
Newer Older
1 2 3 4 5
/*
 * Window position related functions.
 *
 * Copyright 1993, 1994, 1995, 2001 Alexandre Julliard
 * Copyright 1995, 1996, 1999 Alex Korobka
6 7 8 9 10 11 12 13 14 15 16 17 18
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 21 22 23
 */

#include "config.h"

24
#include <X11/Xlib.h>
25 26
#ifdef HAVE_LIBXSHAPE
#include <X11/extensions/shape.h>
Alexandre Julliard's avatar
Alexandre Julliard committed
27
#endif /* HAVE_LIBXSHAPE */
28
#include <stdarg.h>
29

30
#include "windef.h"
31 32 33
#include "winbase.h"
#include "wingdi.h"
#include "winuser.h"
34
#include "winerror.h"
35
#include "wownt32.h"
36
#include "wine/wingdi16.h"
37 38 39 40 41

#include "x11drv.h"
#include "win.h"
#include "winpos.h"

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 50 51 52 53 54 55
#define SWP_AGG_STATUSFLAGS \
    (SWP_AGG_NOPOSCHANGE | SWP_FRAMECHANGED | SWP_HIDEWINDOW | SWP_SHOWWINDOW)

#define SWP_EX_NOCOPY       0x0001
#define SWP_EX_PAINTSELF    0x0002
#define SWP_EX_NONCLIENT    0x0004

56
#define HAS_THICKFRAME(style) \
57 58 59 60 61 62 63 64 65 66 67
    (((style) & WS_THICKFRAME) && \
     !(((style) & (WS_DLGFRAME|WS_BORDER)) == WS_DLGFRAME))

#define ON_LEFT_BORDER(hit) \
 (((hit) == HTLEFT) || ((hit) == HTTOPLEFT) || ((hit) == HTBOTTOMLEFT))
#define ON_RIGHT_BORDER(hit) \
 (((hit) == HTRIGHT) || ((hit) == HTTOPRIGHT) || ((hit) == HTBOTTOMRIGHT))
#define ON_TOP_BORDER(hit) \
 (((hit) == HTTOP) || ((hit) == HTTOPLEFT) || ((hit) == HTTOPRIGHT))
#define ON_BOTTOM_BORDER(hit) \
 (((hit) == HTBOTTOM) || ((hit) == HTBOTTOMLEFT) || ((hit) == HTBOTTOMRIGHT))
68

69 70 71 72 73 74 75 76 77 78 79 80
#define _NET_WM_MOVERESIZE_SIZE_TOPLEFT      0
#define _NET_WM_MOVERESIZE_SIZE_TOP          1
#define _NET_WM_MOVERESIZE_SIZE_TOPRIGHT     2
#define _NET_WM_MOVERESIZE_SIZE_RIGHT        3
#define _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT  4
#define _NET_WM_MOVERESIZE_SIZE_BOTTOM       5
#define _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT   6
#define _NET_WM_MOVERESIZE_SIZE_LEFT         7
#define _NET_WM_MOVERESIZE_MOVE              8   /* movement only */
#define _NET_WM_MOVERESIZE_SIZE_KEYBOARD     9   /* size via keyboard */
#define _NET_WM_MOVERESIZE_MOVE_KEYBOARD    10   /* move via keyboard */

81

82 83 84
/***********************************************************************
 *           X11DRV_Expose
 */
85
void X11DRV_Expose( HWND hwnd, XEvent *xev )
86
{
87
    XExposeEvent *event = &xev->xexpose;
88 89
    RECT rect;
    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 94
           hwnd, event->window, event->x, event->y, event->width, event->height );

95 96
    if (!(data = X11DRV_get_win_data( hwnd ))) return;

97 98 99 100 101
    rect.left   = event->x;
    rect.top    = event->y;
    rect.right  = rect.left + event->width;
    rect.bottom = rect.top + event->height;

102 103 104 105
    if (rect.left < data->client_rect.left ||
        rect.top < data->client_rect.top ||
        rect.right > data->client_rect.right ||
        rect.bottom > data->client_rect.bottom) flags |= RDW_FRAME;
106

107 108 109 110 111 112 113 114 115 116 117
    SERVER_START_REQ( update_window_zorder )
    {
        req->window      = hwnd;
        req->rect.left   = rect.left + data->whole_rect.left;
        req->rect.top    = rect.top + data->whole_rect.top;
        req->rect.right  = rect.right + data->whole_rect.left;
        req->rect.bottom = rect.bottom + data->whole_rect.top;
        wine_server_call( req );
    }
    SERVER_END_REQ;

118 119 120
    /* make position relative to client area instead of window */
    OffsetRect( &rect, -data->client_rect.left, -data->client_rect.top );
    RedrawWindow( hwnd, &rect, 0, flags );
121 122 123
}


124 125 126
/***********************************************************************
 *           SWP_DoWinPosChanging
 */
127
static BOOL SWP_DoWinPosChanging( WINDOWPOS* pWinpos, RECT* pNewWindowRect, RECT* pNewClientRect )
128
{
129 130 131
    WND *wndPtr;

    /* Send WM_WINDOWPOSCHANGING message */
132 133

    if (!(pWinpos->flags & SWP_NOSENDCHANGING))
134
        SendMessageW( pWinpos->hwnd, WM_WINDOWPOSCHANGING, 0, (LPARAM)pWinpos );
135

136 137
    if (!(wndPtr = WIN_GetPtr( pWinpos->hwnd )) ||
        wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return FALSE;
138 139

    /* Calculate new position and size */
140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160

    *pNewWindowRect = wndPtr->rectWindow;
    *pNewClientRect = (wndPtr->dwStyle & WS_MINIMIZE) ? wndPtr->rectWindow
                                                    : wndPtr->rectClient;

    if (!(pWinpos->flags & SWP_NOSIZE))
    {
        pNewWindowRect->right  = pNewWindowRect->left + pWinpos->cx;
        pNewWindowRect->bottom = pNewWindowRect->top + pWinpos->cy;
    }
    if (!(pWinpos->flags & SWP_NOMOVE))
    {
        pNewWindowRect->left    = pWinpos->x;
        pNewWindowRect->top     = pWinpos->y;
        pNewWindowRect->right  += pWinpos->x - wndPtr->rectWindow.left;
        pNewWindowRect->bottom += pWinpos->y - wndPtr->rectWindow.top;

        OffsetRect( pNewClientRect, pWinpos->x - wndPtr->rectWindow.left,
                                    pWinpos->y - wndPtr->rectWindow.top );
    }
    pWinpos->flags |= SWP_NOCLIENTMOVE | SWP_NOCLIENTSIZE;
161 162 163 164 165 166 167 168

    TRACE( "hwnd %p, after %p, swp %d,%d %dx%d flags %08x\n",
           pWinpos->hwnd, pWinpos->hwndInsertAfter, pWinpos->x, pWinpos->y,
           pWinpos->cx, pWinpos->cy, pWinpos->flags );
    TRACE( "current %s style %08lx new %s\n",
           wine_dbgstr_rect( &wndPtr->rectWindow ), wndPtr->dwStyle,
           wine_dbgstr_rect( pNewWindowRect ));

169
    WIN_ReleasePtr( wndPtr );
170 171 172
    return TRUE;
}

173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235

/***********************************************************************
 *           get_valid_rects
 *
 * Compute the valid rects from the old and new client rect and WVR_* flags.
 * Helper for WM_NCCALCSIZE handling.
 */
static inline void get_valid_rects( const RECT *old_client, const RECT *new_client, UINT flags,
                                    RECT *valid )
{
    int cx, cy;

    if (flags & WVR_REDRAW)
    {
        SetRectEmpty( &valid[0] );
        SetRectEmpty( &valid[1] );
        return;
    }

    if (flags & WVR_VALIDRECTS)
    {
        if (!IntersectRect( &valid[0], &valid[0], new_client ) ||
            !IntersectRect( &valid[1], &valid[1], old_client ))
        {
            SetRectEmpty( &valid[0] );
            SetRectEmpty( &valid[1] );
            return;
        }
        flags = WVR_ALIGNLEFT | WVR_ALIGNTOP;
    }
    else
    {
        valid[0] = *new_client;
        valid[1] = *old_client;
    }

    /* make sure the rectangles have the same size */
    cx = min( valid[0].right - valid[0].left, valid[1].right - valid[1].left );
    cy = min( valid[0].bottom - valid[0].top, valid[1].bottom - valid[1].top );

    if (flags & WVR_ALIGNBOTTOM)
    {
        valid[0].top = valid[0].bottom - cy;
        valid[1].top = valid[1].bottom - cy;
    }
    else
    {
        valid[0].bottom = valid[0].top + cy;
        valid[1].bottom = valid[1].top + cy;
    }
    if (flags & WVR_ALIGNRIGHT)
    {
        valid[0].left = valid[0].right - cx;
        valid[1].left = valid[1].right - cx;
    }
    else
    {
        valid[0].right = valid[0].left + cx;
        valid[1].right = valid[1].left + cx;
    }
}


236 237 238
/***********************************************************************
 *           SWP_DoNCCalcSize
 */
239 240
static UINT SWP_DoNCCalcSize( WINDOWPOS* pWinpos, const RECT* pNewWindowRect, RECT* pNewClientRect,
                              RECT *validRects )
241 242
{
    UINT wvrFlags = 0;
243 244 245
    WND *wndPtr;

    if (!(wndPtr = WIN_GetPtr( pWinpos->hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
246 247 248 249

      /* Send WM_NCCALCSIZE message to get new client area */
    if( (pWinpos->flags & (SWP_FRAMECHANGED | SWP_NOSIZE)) != SWP_NOSIZE )
    {
250 251 252 253 254 255 256 257 258 259 260 261
        NCCALCSIZE_PARAMS params;
        WINDOWPOS winposCopy;

        params.rgrc[0] = *pNewWindowRect;
        params.rgrc[1] = wndPtr->rectWindow;
        params.rgrc[2] = wndPtr->rectClient;
        params.lppos = &winposCopy;
        winposCopy = *pWinpos;
        WIN_ReleasePtr( wndPtr );

        wvrFlags = SendMessageW( pWinpos->hwnd, WM_NCCALCSIZE, TRUE, (LPARAM)&params );

262
        *pNewClientRect = params.rgrc[0];
263 264 265

        if (!(wndPtr = WIN_GetPtr( pWinpos->hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;

266 267 268 269
        TRACE( "hwnd %p old win %s old client %s new win %s new client %s\n", pWinpos->hwnd,
               wine_dbgstr_rect(&wndPtr->rectWindow), wine_dbgstr_rect(&wndPtr->rectClient),
               wine_dbgstr_rect(pNewWindowRect), wine_dbgstr_rect(pNewClientRect) );

270 271 272
        if( pNewClientRect->left != wndPtr->rectClient.left ||
            pNewClientRect->top != wndPtr->rectClient.top )
            pWinpos->flags &= ~SWP_NOCLIENTMOVE;
273

274
        if( (pNewClientRect->right - pNewClientRect->left !=
275 276 277 278 279 280 281
             wndPtr->rectClient.right - wndPtr->rectClient.left))
            pWinpos->flags &= ~SWP_NOCLIENTSIZE;
        else
            wvrFlags &= ~WVR_HREDRAW;

        if (pNewClientRect->bottom - pNewClientRect->top !=
             wndPtr->rectClient.bottom - wndPtr->rectClient.top)
282
            pWinpos->flags &= ~SWP_NOCLIENTSIZE;
283 284 285 286 287
        else
            wvrFlags &= ~WVR_VREDRAW;

        validRects[0] = params.rgrc[1];
        validRects[1] = params.rgrc[2];
288 289
    }
    else
290 291 292 293
    {
        if (!(pWinpos->flags & SWP_NOMOVE) &&
            (pNewClientRect->left != wndPtr->rectClient.left ||
             pNewClientRect->top != wndPtr->rectClient.top))
294
            pWinpos->flags &= ~SWP_NOCLIENTMOVE;
295
    }
296 297 298 299 300 301 302 303

    if (pWinpos->flags & (SWP_NOCOPYBITS | SWP_NOREDRAW | SWP_SHOWWINDOW | SWP_HIDEWINDOW))
    {
        SetRectEmpty( &validRects[0] );
        SetRectEmpty( &validRects[1] );
    }
    else get_valid_rects( &wndPtr->rectClient, pNewClientRect, wvrFlags, validRects );

304
    WIN_ReleasePtr( wndPtr );
305 306 307
    return wvrFlags;
}

308

309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330
struct move_owned_info
{
    HWND owner;
    HWND insert_after;
};

static BOOL CALLBACK move_owned_popups( HWND hwnd, LPARAM lparam )
{
    struct move_owned_info *info = (struct move_owned_info *)lparam;

    if (hwnd == info->owner) return FALSE;
    if ((GetWindowLongW( hwnd, GWL_STYLE ) & WS_POPUP) &&
        GetWindow( hwnd, GW_OWNER ) == info->owner)
    {
        SetWindowPos( hwnd, info->insert_after, 0, 0, 0, 0,
                      SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE |
                      SWP_NOSENDCHANGING | SWP_DEFERERASE );
        info->insert_after = hwnd;
    }
    return TRUE;
}

331 332 333 334 335 336 337 338
/***********************************************************************
 *           SWP_DoOwnedPopups
 *
 * fix Z order taking into account owned popups -
 * basically we need to maintain them above the window that owns them
 *
 * FIXME: hide/show owned popups when owner visibility changes.
 */
339
static HWND SWP_DoOwnedPopups(HWND hwnd, HWND hwndInsertAfter)
340
{
341 342
    HWND owner = GetWindow( hwnd, GW_OWNER );
    LONG style = GetWindowLongW( hwnd, GWL_STYLE );
343
    struct move_owned_info info;
344

345
    TRACE("(%p) hInsertAfter = %p\n", hwnd, hwndInsertAfter );
346

347
    if ((style & WS_POPUP) && owner)
348 349 350 351 352
    {
        /* make sure this popup stays above the owner */

        if( hwndInsertAfter != HWND_TOP )
        {
353 354
            HWND hwndLocalPrev = HWND_TOP;
            HWND prev = GetWindow( owner, GW_HWNDPREV );
355

356
            while (prev && prev != hwndInsertAfter)
357
            {
358 359 360
                if (hwndLocalPrev == HWND_TOP && GetWindowLongW( prev, GWL_STYLE ) & WS_VISIBLE)
                    hwndLocalPrev = prev;
                prev = GetWindow( prev, GW_HWNDPREV );
361
            }
362
            if (!prev) hwndInsertAfter = hwndLocalPrev;
363 364
        }
    }
365
    else if (style & WS_CHILD) return hwndInsertAfter;
366

367 368 369 370
    info.owner = hwnd;
    info.insert_after = hwndInsertAfter;
    EnumWindows( move_owned_popups, (LPARAM)&info );
    return info.insert_after;
371 372
}

373 374 375 376

/* fix redundant flags and values in the WINDOWPOS structure */
static BOOL fixup_flags( WINDOWPOS *winpos )
{
377
    HWND parent;
378
    WND *wndPtr = WIN_GetPtr( winpos->hwnd );
379 380
    BOOL ret = TRUE;

381 382 383 384 385
    if (!wndPtr || wndPtr == WND_OTHER_PROCESS)
    {
        SetLastError( ERROR_INVALID_WINDOW_HANDLE );
        return FALSE;
    }
386
    winpos->hwnd = wndPtr->hwndSelf;  /* make it a full handle */
387

388 389 390 391 392 393 394 395 396 397 398
    /* Finally make sure that all coordinates are valid */
    if (winpos->x < -32768) winpos->x = -32768;
    else if (winpos->x > 32767) winpos->x = 32767;
    if (winpos->y < -32768) winpos->y = -32768;
    else if (winpos->y > 32767) winpos->y = 32767;

    if (winpos->cx < 0) winpos->cx = 0;
    else if (winpos->cx > 32767) winpos->cx = 32767;
    if (winpos->cy < 0) winpos->cy = 0;
    else if (winpos->cy > 32767) winpos->cy = 32767;

399 400 401
    parent = GetAncestor( winpos->hwnd, GA_PARENT );
    if (!IsWindowVisible( parent )) winpos->flags |= SWP_NOREDRAW;

402 403 404 405 406 407 408 409 410 411 412 413 414 415
    if (wndPtr->dwStyle & WS_VISIBLE) winpos->flags &= ~SWP_SHOWWINDOW;
    else
    {
        winpos->flags &= ~SWP_HIDEWINDOW;
        if (!(winpos->flags & SWP_SHOWWINDOW)) winpos->flags |= SWP_NOREDRAW;
    }

    if ((wndPtr->rectWindow.right - wndPtr->rectWindow.left == winpos->cx) &&
        (wndPtr->rectWindow.bottom - wndPtr->rectWindow.top == winpos->cy))
        winpos->flags |= SWP_NOSIZE;    /* Already the right size */

    if ((wndPtr->rectWindow.left == winpos->x) && (wndPtr->rectWindow.top == winpos->y))
        winpos->flags |= SWP_NOMOVE;    /* Already the right position */

416
    if ((wndPtr->dwStyle & (WS_POPUP | WS_CHILD)) != WS_CHILD)
417
    {
418
        if (!(winpos->flags & (SWP_NOACTIVATE|SWP_HIDEWINDOW))) /* Bring to the top when activating */
419 420 421 422 423 424 425
        {
            winpos->flags &= ~SWP_NOZORDER;
            winpos->hwndInsertAfter = HWND_TOP;
        }
    }

    /* Check hwndInsertAfter */
426
    if (winpos->flags & SWP_NOZORDER) goto done;
427

428 429 430 431
    /* fix sign extension */
    if (winpos->hwndInsertAfter == (HWND)0xffff) winpos->hwndInsertAfter = HWND_TOPMOST;
    else if (winpos->hwndInsertAfter == (HWND)0xfffe) winpos->hwndInsertAfter = HWND_NOTOPMOST;

432 433 434 435 436
      /* FIXME: TOPMOST not supported yet */
    if ((winpos->hwndInsertAfter == HWND_TOPMOST) ||
        (winpos->hwndInsertAfter == HWND_NOTOPMOST)) winpos->hwndInsertAfter = HWND_TOP;

    /* hwndInsertAfter must be a sibling of the window */
437 438 439 440 441 442 443 444 445 446 447
    if (winpos->hwndInsertAfter == HWND_TOP)
    {
        if (GetWindow(winpos->hwnd, GW_HWNDFIRST) == winpos->hwnd)
            winpos->flags |= SWP_NOZORDER;
    }
    else if (winpos->hwndInsertAfter == HWND_BOTTOM)
    {
        if (GetWindow(winpos->hwnd, GW_HWNDLAST) == winpos->hwnd)
            winpos->flags |= SWP_NOZORDER;
    }
    else
448
    {
449
        if (GetAncestor( winpos->hwndInsertAfter, GA_PARENT ) != parent) ret = FALSE;
450
        else
451
        {
452 453 454 455 456 457
            /* don't need to change the Zorder of hwnd if it's already inserted
             * after hwndInsertAfter or when inserting hwnd after itself.
             */
            if ((winpos->hwnd == winpos->hwndInsertAfter) ||
                (winpos->hwnd == GetWindow( winpos->hwndInsertAfter, GW_HWNDNEXT )))
                winpos->flags |= SWP_NOZORDER;
458 459 460
        }
    }
 done:
461
    WIN_ReleasePtr( wndPtr );
462 463 464 465
    return ret;
}


466 467 468 469 470
/***********************************************************************
 *		SetWindowStyle   (X11DRV.@)
 *
 * Update the X state of a window to reflect a style change
 */
471
void X11DRV_SetWindowStyle( HWND hwnd, DWORD old_style )
472 473
{
    Display *display = thread_display();
474 475
    struct x11drv_win_data *data;
    DWORD new_style, changed;
476

477
    if (hwnd == GetDesktopWindow()) return;
478
    if (!(data = X11DRV_get_win_data( hwnd ))) return;
479

480 481
    new_style = GetWindowLongW( hwnd, GWL_STYLE );
    changed = new_style ^ old_style;
482 483

    if (changed & WS_VISIBLE)
484
    {
485
        if (data->whole_window && X11DRV_is_window_rect_mapped( &data->window_rect ))
486
        {
487
            if (new_style & WS_VISIBLE)
488
            {
489
                TRACE( "mapping win %p\n", hwnd );
490 491
                X11DRV_sync_window_style( display, data );
                X11DRV_set_wm_hints( display, data );
492
                wine_tsx11_lock();
493
                XMapWindow( display, data->whole_window );
494
                wine_tsx11_unlock();
495
            }
496
            /* we don't unmap windows, that causes trouble with the window manager */
497
        }
498
        invalidate_dce( hwnd, &data->window_rect );
499
    }
500 501 502

    if (changed & WS_DISABLED)
    {
503
        if (data->whole_window && data->managed)
504 505 506
        {
            XWMHints *wm_hints;
            wine_tsx11_lock();
507
            if (!(wm_hints = XGetWMHints( display, data->whole_window )))
508 509 510 511
                wm_hints = XAllocWMHints();
            if (wm_hints)
            {
                wm_hints->flags |= InputHint;
512 513
                wm_hints->input = !(new_style & WS_DISABLED);
                XSetWMHints( display, data->whole_window, wm_hints );
514 515 516 517 518
                XFree(wm_hints);
            }
            wine_tsx11_unlock();
        }
    }
519 520 521
}


522 523 524 525 526 527
/***********************************************************************
 *           X11DRV_set_window_pos
 *
 * Set a window position and Z order.
 */
BOOL X11DRV_set_window_pos( HWND hwnd, HWND insert_after, const RECT *rectWindow,
528
                            const RECT *rectClient, UINT swp_flags, const RECT *valid_rects )
529
{
530
    struct x11drv_win_data *data;
531
    RECT new_whole_rect;
532
    WND *win;
533 534 535
    DWORD old_style, new_style;
    BOOL ret;

536
    if (!(data = X11DRV_get_win_data( hwnd ))) return FALSE;
537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559

    new_whole_rect = *rectWindow;
    X11DRV_window_to_X_rect( data, &new_whole_rect );

    if (!IsRectEmpty( &valid_rects[0] ))
    {
        int x_offset = 0, y_offset = 0;

        if (data->whole_window)
        {
            /* the X server will move the bits for us */
            x_offset = data->whole_rect.left - new_whole_rect.left;
            y_offset = data->whole_rect.top - new_whole_rect.top;
        }

        if (x_offset != valid_rects[1].left - valid_rects[0].left ||
            y_offset != valid_rects[1].top - valid_rects[0].top)
        {
            /* FIXME: should copy the window bits here */
            valid_rects = NULL;
        }
    }

560
    if (!(win = WIN_GetPtr( hwnd ))) return FALSE;
561 562 563 564 565 566 567 568 569
    if (win == WND_OTHER_PROCESS)
    {
        if (IsWindow( hwnd )) ERR( "cannot set rectangles of other process window %p\n", hwnd );
        return FALSE;
    }
    SERVER_START_REQ( set_window_pos )
    {
        req->handle        = hwnd;
        req->previous      = insert_after;
570
        req->flags         = swp_flags;
571 572 573 574 575 576 577 578
        req->window.left   = rectWindow->left;
        req->window.top    = rectWindow->top;
        req->window.right  = rectWindow->right;
        req->window.bottom = rectWindow->bottom;
        req->client.left   = rectClient->left;
        req->client.top    = rectClient->top;
        req->client.right  = rectClient->right;
        req->client.bottom = rectClient->bottom;
579 580 581 582 583 584
        if (memcmp( rectWindow, &new_whole_rect, sizeof(RECT) ) || !IsRectEmpty( &valid_rects[0] ))
        {
            wine_server_add_data( req, &new_whole_rect, sizeof(new_whole_rect) );
            if (!IsRectEmpty( &valid_rects[0] ))
                wine_server_add_data( req, valid_rects, 2 * sizeof(*valid_rects) );
        }
585 586 587 588 589
        ret = !wine_server_call( req );
        new_style = reply->new_style;
    }
    SERVER_END_REQ;

590
    if (win == WND_DESKTOP || data->whole_window == DefaultRootWindow(gdi_display))
591 592
    {
        data->whole_rect = data->client_rect = data->window_rect = *rectWindow;
593 594 595 596 597 598 599
        if (win != WND_DESKTOP)
        {
            win->rectWindow   = *rectWindow;
            win->rectClient   = *rectClient;
            win->dwStyle      = new_style;
            WIN_ReleasePtr( win );
        }
600 601
        return ret;
    }
602

603 604 605 606 607 608 609 610 611 612 613
    if (ret)
    {
        Display *display = thread_display();

        /* invalidate DCEs */

        if ((((swp_flags & SWP_AGG_NOPOSCHANGE) != SWP_AGG_NOPOSCHANGE) && (new_style & WS_VISIBLE)) ||
             (swp_flags & (SWP_HIDEWINDOW | SWP_SHOWWINDOW)))
        {
            RECT rect;
            UnionRect( &rect, rectWindow, &win->rectWindow );
614
            invalidate_dce( hwnd, &rect );
615 616
        }

617 618
        win->rectWindow   = *rectWindow;
        win->rectClient   = *rectClient;
619
        old_style         = win->dwStyle;
620 621
        win->dwStyle      = new_style;
        data->window_rect = *rectWindow;
622 623 624 625 626 627

        TRACE( "win %p window %s client %s style %08lx\n",
               hwnd, wine_dbgstr_rect(rectWindow), wine_dbgstr_rect(rectClient), new_style );

        /* FIXME: copy the valid bits */

628
        if (data->whole_window && !data->lock_changes)
629 630 631 632 633 634
        {
            if ((old_style & WS_VISIBLE) && !(new_style & WS_VISIBLE))
            {
                /* window got hidden, unmap it */
                TRACE( "unmapping win %p\n", hwnd );
                wine_tsx11_lock();
635
                XUnmapWindow( display, data->whole_window );
636 637 638 639 640 641 642 643 644 645
                wine_tsx11_unlock();
            }
            else if ((new_style & WS_VISIBLE) && !X11DRV_is_window_rect_mapped( rectWindow ))
            {
                /* resizing to zero size or off screen -> unmap */
                TRACE( "unmapping zero size or off-screen win %p\n", hwnd );
                wine_tsx11_lock();
                XUnmapWindow( display, data->whole_window );
                wine_tsx11_unlock();
            }
646
        }
647

648
        X11DRV_sync_window_position( display, data, swp_flags, rectClient, &new_whole_rect );
649

650
        if (data->whole_window && !data->lock_changes)
651
        {
652 653
            if ((new_style & WS_VISIBLE) && !(new_style & WS_MINIMIZE) &&
                X11DRV_is_window_rect_mapped( rectWindow ))
654
            {
655
                if (!(old_style & WS_VISIBLE))
656
                {
657
                    /* window got shown, map it */
658
                    TRACE( "mapping win %p\n", hwnd );
659 660
                    X11DRV_sync_window_style( display, data );
                    X11DRV_set_wm_hints( display, data );
661 662 663 664
                    wine_tsx11_lock();
                    XMapWindow( display, data->whole_window );
                    wine_tsx11_unlock();
                }
665 666 667 668 669 670 671 672
                else if ((swp_flags & (SWP_NOSIZE | SWP_NOMOVE)) != (SWP_NOSIZE | SWP_NOMOVE))
                {
                    /* resizing from zero size to non-zero -> map */
                    TRACE( "mapping non zero size or off-screen win %p\n", hwnd );
                    wine_tsx11_lock();
                    XMapWindow( display, data->whole_window );
                    wine_tsx11_unlock();
                }
673 674 675 676 677 678 679 680
            }
        }
    }
    WIN_ReleasePtr( win );
    return ret;
}


681
/***********************************************************************
682
 *		SetWindowPos   (X11DRV.@)
683
 */
684
BOOL X11DRV_SetWindowPos( WINDOWPOS *winpos )
685
{
686 687
    RECT newWindowRect, newClientRect, valid_rects[2];
    UINT orig_flags;
688

689 690 691
    TRACE( "hwnd %p, after %p, swp %d,%d %dx%d flags %08x\n",
           winpos->hwnd, winpos->hwndInsertAfter, winpos->x, winpos->y,
           winpos->cx, winpos->cy, winpos->flags);
692

693
    orig_flags = winpos->flags;
694

695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710
    /* First make sure that coordinates are valid for WM_WINDOWPOSCHANGING */
    if (!(winpos->flags & SWP_NOMOVE))
    {
        if (winpos->x < -32768) winpos->x = -32768;
        else if (winpos->x > 32767) winpos->x = 32767;
        if (winpos->y < -32768) winpos->y = -32768;
        else if (winpos->y > 32767) winpos->y = 32767;
    }
    if (!(winpos->flags & SWP_NOSIZE))
    {
        if (winpos->cx < 0) winpos->cx = 0;
        else if (winpos->cx > 32767) winpos->cx = 32767;
        if (winpos->cy < 0) winpos->cy = 0;
        else if (winpos->cy > 32767) winpos->cy = 32767;
    }

711 712 713 714
    if (!SWP_DoWinPosChanging( winpos, &newWindowRect, &newClientRect )) return FALSE;

    /* Fix redundant flags */
    if (!fixup_flags( winpos )) return FALSE;
715 716 717

    if((winpos->flags & (SWP_NOZORDER | SWP_HIDEWINDOW | SWP_SHOWWINDOW)) != SWP_NOZORDER)
    {
718 719
        if (GetAncestor( winpos->hwnd, GA_PARENT ) == GetDesktopWindow())
            winpos->hwndInsertAfter = SWP_DoOwnedPopups( winpos->hwnd, winpos->hwndInsertAfter );
720 721 722 723
    }

    /* Common operations */

724
    SWP_DoNCCalcSize( winpos, &newWindowRect, &newClientRect, valid_rects );
725

726
    if (!X11DRV_set_window_pos( winpos->hwnd, winpos->hwndInsertAfter,
727
                                &newWindowRect, &newClientRect, orig_flags, valid_rects ))
728
        return FALSE;
729

730 731 732 733 734 735 736
    if (!(orig_flags & SWP_SHOWWINDOW))
    {
        UINT rdw_flags = RDW_FRAME | RDW_ERASE;
        if ( !(orig_flags & SWP_DEFERERASE) ) rdw_flags |= RDW_ERASENOW;
        RedrawWindow( winpos->hwnd, NULL, NULL, rdw_flags );
    }

737 738 739 740
    if( winpos->flags & SWP_HIDEWINDOW )
        HideCaret(winpos->hwnd);
    else if (winpos->flags & SWP_SHOWWINDOW)
        ShowCaret(winpos->hwnd);
741

742
    if (!(winpos->flags & (SWP_NOACTIVATE|SWP_HIDEWINDOW)))
743 744 745
    {
        /* child windows get WM_CHILDACTIVATE message */
        if ((GetWindowLongW( winpos->hwnd, GWL_STYLE ) & (WS_CHILD | WS_POPUP)) == WS_CHILD)
746
            SendMessageW( winpos->hwnd, WM_CHILDACTIVATE, 0, 0 );
747
        else
748
            SetForegroundWindow( winpos->hwnd );
749
    }
750 751 752 753

      /* And last, send the WM_WINDOWPOSCHANGED message */

    TRACE("\tstatus flags = %04x\n", winpos->flags & SWP_AGG_STATUSFLAGS);
754

755
    if (((winpos->flags & SWP_AGG_STATUSFLAGS) != SWP_AGG_NOPOSCHANGE))
756 757 758 759 760 761 762 763 764 765
    {
        /* WM_WINDOWPOSCHANGED is sent even if SWP_NOSENDCHANGING is set
           and always contains final window position.
         */
        winpos->x = newWindowRect.left;
        winpos->y = newWindowRect.top;
        winpos->cx = newWindowRect.right - newWindowRect.left;
        winpos->cy = newWindowRect.bottom - newWindowRect.top;
        SendMessageW( winpos->hwnd, WM_WINDOWPOSCHANGED, 0, (LPARAM)winpos );
    }
766 767 768 769 770 771 772 773 774 775

    return TRUE;
}


/***********************************************************************
 *           WINPOS_FindIconPos
 *
 * Find a suitable place for an iconic window.
 */
776
static POINT WINPOS_FindIconPos( HWND hwnd, POINT pt )
777
{
778 779 780 781
    RECT rect, rectParent;
    HWND parent, child;
    HRGN hrgn, tmp;
    int xspacing, yspacing;
782

783 784
    parent = GetAncestor( hwnd, GA_PARENT );
    GetClientRect( parent, &rectParent );
785 786 787 788 789 790 791
    if ((pt.x >= rectParent.left) && (pt.x + GetSystemMetrics(SM_CXICON) < rectParent.right) &&
        (pt.y >= rectParent.top) && (pt.y + GetSystemMetrics(SM_CYICON) < rectParent.bottom))
        return pt;  /* The icon already has a suitable position */

    xspacing = GetSystemMetrics(SM_CXICONSPACING);
    yspacing = GetSystemMetrics(SM_CYICONSPACING);

792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812
    /* Check if another icon already occupies this spot */
    /* FIXME: this is completely inefficient */

    hrgn = CreateRectRgn( 0, 0, 0, 0 );
    tmp = CreateRectRgn( 0, 0, 0, 0 );
    for (child = GetWindow( parent, GW_HWNDFIRST ); child; child = GetWindow( child, GW_HWNDNEXT ))
    {
        WND *childPtr;
        if (child == hwnd) continue;
        if ((GetWindowLongW( child, GWL_STYLE ) & (WS_VISIBLE|WS_MINIMIZE)) != (WS_VISIBLE|WS_MINIMIZE))
            continue;
        if (!(childPtr = WIN_GetPtr( child )) || childPtr == WND_OTHER_PROCESS)
            continue;
        SetRectRgn( tmp, childPtr->rectWindow.left, childPtr->rectWindow.top,
                    childPtr->rectWindow.right, childPtr->rectWindow.bottom );
        CombineRgn( hrgn, hrgn, tmp, RGN_OR );
        WIN_ReleasePtr( childPtr );
    }
    DeleteObject( tmp );

    for (rect.bottom = rectParent.bottom; rect.bottom >= yspacing; rect.bottom -= yspacing)
813
    {
814
        for (rect.left = rectParent.left; rect.left <= rectParent.right - xspacing; rect.left += xspacing)
815
        {
816 817 818
            rect.right = rect.left + xspacing;
            rect.top = rect.bottom - yspacing;
            if (!RectInRegion( hrgn, &rect ))
819
            {
820 821 822 823 824
                /* No window was found, so it's OK for us */
                pt.x = rect.left + (xspacing - GetSystemMetrics(SM_CXICON)) / 2;
                pt.y = rect.top + (yspacing - GetSystemMetrics(SM_CYICON)) / 2;
                DeleteObject( hrgn );
                return pt;
825
            }
826
        }
827
    }
828 829 830
    DeleteObject( hrgn );
    pt.x = pt.y = 0;
    return pt;
831
}
832 833 834 835 836





837 838
UINT WINPOS_MinMaximize( HWND hwnd, UINT cmd, LPRECT rect )
{
839
    WND *wndPtr;
840 841
    UINT swpFlags = 0;
    POINT size;
842
    LONG old_style;
843
    WINDOWPLACEMENT wpl;
844

845
    TRACE("%p %u\n", hwnd, cmd );
846

847 848
    wpl.length = sizeof(wpl);
    GetWindowPlacement( hwnd, &wpl );
849

850
    if (HOOK_CallHooks( WH_CBT, HCBT_MINMAX, (WPARAM)hwnd, cmd, TRUE ))
851 852 853 854
        return SWP_NOSIZE | SWP_NOMOVE;

    if (IsIconic( hwnd ))
    {
855 856 857 858 859 860 861 862
        switch (cmd)
        {
        case SW_SHOWMINNOACTIVE:
        case SW_SHOWMINIMIZED:
        case SW_FORCEMINIMIZE:
        case SW_MINIMIZE:
            return SWP_NOSIZE | SWP_NOMOVE;
        }
863
        if (!SendMessageW( hwnd, WM_QUERYOPEN, 0, 0 )) return SWP_NOSIZE | SWP_NOMOVE;
864 865 866 867
        swpFlags |= SWP_NOCOPYBITS;
    }

    switch( cmd )
868
    {
869 870 871
    case SW_SHOWMINNOACTIVE:
    case SW_SHOWMINIMIZED:
    case SW_FORCEMINIMIZE:
872
    case SW_MINIMIZE:
873
        if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
874 875
        if( wndPtr->dwStyle & WS_MAXIMIZE) wndPtr->flags |= WIN_RESTORE_MAX;
        else wndPtr->flags &= ~WIN_RESTORE_MAX;
876
        WIN_ReleasePtr( wndPtr );
877

878
        WIN_SetStyle( hwnd, WS_MINIMIZE, WS_MAXIMIZE );
879

880
        X11DRV_set_iconic_state( hwnd );
881

882
        wpl.ptMinPosition = WINPOS_FindIconPos( hwnd, wpl.ptMinPosition );
883

884 885 886 887
        SetRect( rect, wpl.ptMinPosition.x, wpl.ptMinPosition.y,
                 GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON) );
        swpFlags |= SWP_NOCOPYBITS;
        break;
888

889
    case SW_MAXIMIZE:
890 891 892
        old_style = GetWindowLongW( hwnd, GWL_STYLE );
        if ((old_style & WS_MAXIMIZE) && (old_style & WS_CHILD)) return SWP_NOSIZE | SWP_NOMOVE;

893
        WINPOS_GetMinMaxInfo( hwnd, &size, &wpl.ptMaxPosition, NULL, NULL );
894

895
        old_style = WIN_SetStyle( hwnd, WS_MAXIMIZE, WS_MINIMIZE );
896
        if (old_style & WS_MINIMIZE)
897 898
        {
            WINPOS_ShowIconTitle( hwnd, FALSE );
899
            X11DRV_set_iconic_state( hwnd );
900 901 902
        }
        SetRect( rect, wpl.ptMaxPosition.x, wpl.ptMaxPosition.y, size.x, size.y );
        break;
903

904
    case SW_RESTORE:
905
        old_style = WIN_SetStyle( hwnd, 0, WS_MINIMIZE | WS_MAXIMIZE );
906
        if (old_style & WS_MINIMIZE)
907
        {
908 909
            BOOL restore_max;

910
            WINPOS_ShowIconTitle( hwnd, FALSE );
911
            X11DRV_set_iconic_state( hwnd );
912

913 914 915 916
            if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
            restore_max = (wndPtr->flags & WIN_RESTORE_MAX) != 0;
            WIN_ReleasePtr( wndPtr );
            if (restore_max)
917 918 919
            {
                /* Restore to maximized position */
                WINPOS_GetMinMaxInfo( hwnd, &size, &wpl.ptMaxPosition, NULL, NULL);
920
                WIN_SetStyle( hwnd, WS_MAXIMIZE, 0 );
921 922
                SetRect( rect, wpl.ptMaxPosition.x, wpl.ptMaxPosition.y, size.x, size.y );
                break;
923
            }
924
        }
925
        else if (!(old_style & WS_MAXIMIZE)) break;
926

927
        /* Restore to normal position */
928

929 930 931
        *rect = wpl.rcNormalPosition;
        rect->right -= rect->left;
        rect->bottom -= rect->top;
932

933 934
        break;
    }
935 936

    return swpFlags;
937 938 939 940
}


/***********************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
941
 *              ShowWindow   (X11DRV.@)
942
 */
943
BOOL X11DRV_ShowWindow( HWND hwnd, INT cmd )
944
{
945
    WND *wndPtr;
946
    HWND parent;
947 948
    LONG style = GetWindowLongW( hwnd, GWL_STYLE );
    BOOL wasVisible = (style & WS_VISIBLE) != 0;
949
    BOOL showFlag = TRUE, state_change = FALSE;
950 951
    RECT newPos = {0, 0, 0, 0};
    UINT swp = 0;
952

953 954
    TRACE("hwnd=%p, cmd=%d, wasVisible %d\n", hwnd, cmd, wasVisible);

955
    switch(cmd)
956
    {
957
        case SW_HIDE:
958 959
            if (!wasVisible) return FALSE;
            showFlag = FALSE;
960 961 962
            swp |= SWP_HIDEWINDOW | SWP_NOSIZE | SWP_NOMOVE;
            if (hwnd != GetActiveWindow())
                swp |= SWP_NOACTIVATE | SWP_NOZORDER;
963 964 965 966 967
	    break;

	case SW_SHOWMINNOACTIVE:
            swp |= SWP_NOACTIVATE | SWP_NOZORDER;
            /* fall through */
968
        case SW_MINIMIZE:
969
        case SW_FORCEMINIMIZE: /* FIXME: Does not work if thread is hung. */
970
            if (style & WS_CHILD) swp |= SWP_NOACTIVATE | SWP_NOZORDER;
971
            /* fall through */
972 973
	case SW_SHOWMINIMIZED:
            swp |= SWP_SHOWWINDOW | SWP_FRAMECHANGED;
974 975 976
            swp |= WINPOS_MinMaximize( hwnd, cmd, &newPos );
            if (style & WS_MINIMIZE) return wasVisible;
            state_change = TRUE;
977 978 979 980
	    break;

	case SW_SHOWMAXIMIZED: /* same as SW_MAXIMIZE */
            swp |= SWP_SHOWWINDOW | SWP_FRAMECHANGED;
981
            swp |= WINPOS_MinMaximize( hwnd, SW_MAXIMIZE, &newPos );
982 983
            if ((style & WS_MAXIMIZE) && (style & WS_CHILD)) return wasVisible;
            state_change = TRUE;
984 985 986
            break;

	case SW_SHOWNA:
987
            swp |= SWP_NOACTIVATE | SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE;
988
            if (style & WS_CHILD) swp |= SWP_NOZORDER;
989
            break;
990
	case SW_SHOW:
991
            if (wasVisible) return TRUE;
992
	    swp |= SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE;
993
            if (style & WS_CHILD) swp |= SWP_NOACTIVATE | SWP_NOZORDER;
994 995
	    break;

996 997
	case SW_RESTORE:
	    swp |= SWP_FRAMECHANGED;
998
            state_change = TRUE;
999
            /* fall through */
1000
	case SW_SHOWNOACTIVATE:
1001
            swp |= SWP_NOACTIVATE | SWP_NOZORDER;
1002 1003 1004
            /* fall through */
	case SW_SHOWNORMAL:  /* same as SW_NORMAL: */
	case SW_SHOWDEFAULT: /* FIXME: should have its own handler */
1005
	    swp |= SWP_SHOWWINDOW;
1006
            if (style & (WS_MINIMIZE | WS_MAXIMIZE))
1007 1008
		 swp |= WINPOS_MinMaximize( hwnd, SW_RESTORE, &newPos );
            else swp |= SWP_NOSIZE | SWP_NOMOVE;
1009
            if (style & WS_CHILD) swp |= SWP_NOACTIVATE | SWP_NOZORDER;
1010
	    break;
1011 1012
    }

1013
    if ((showFlag != wasVisible || cmd == SW_SHOWNA) && !state_change)
1014 1015
    {
        SendMessageW( hwnd, WM_SHOWWINDOW, showFlag, 0 );
1016
        if (!IsWindow( hwnd )) return wasVisible;
1017 1018
    }

1019
    parent = GetAncestor( hwnd, GA_PARENT );
1020
    if (parent && !IsWindowVisible( parent ) && !state_change)
1021 1022 1023 1024 1025 1026 1027
    {
        /* if parent is not visible simply toggle WS_VISIBLE and return */
        if (showFlag) WIN_SetStyle( hwnd, WS_VISIBLE, 0 );
        else WIN_SetStyle( hwnd, 0, WS_VISIBLE );
    }
    else
    {
1028 1029
        if (style & WS_CHILD)
        {
1030
            if (state_change)
1031 1032 1033 1034
            {
                /* it appears that Windows always adds an undocumented 0x8000
                 * flag if the state of a window changes.
                 */
1035
                swp |= SWP_STATECHANGED;
1036 1037
            }
        }
1038 1039 1040 1041

        SetWindowPos( hwnd, HWND_TOP, newPos.left, newPos.top,
                      newPos.right, newPos.bottom, LOWORD(swp) );
    }
1042

1043
    if (cmd == SW_HIDE)
1044
    {
1045 1046
        HWND hFocus;

1047 1048 1049 1050
        /* FIXME: This will cause the window to be activated irrespective
         * of whether it is owned by the same thread. Has to be done
         * asynchronously.
         */
1051

1052
        if (hwnd == GetActiveWindow())
1053
            WINPOS_ActivateOtherWindow(hwnd);
1054

1055
        /* Revert focus to parent */
1056 1057 1058 1059 1060 1061 1062
        hFocus = GetFocus();
        if (hwnd == hFocus || IsChild(hwnd, hFocus))
        {
            HWND parent = GetAncestor(hwnd, GA_PARENT);
            if (parent == GetDesktopWindow()) parent = 0;
            SetFocus(parent);
        }
1063
    }
1064 1065 1066 1067

    if (IsIconic(hwnd)) WINPOS_ShowIconTitle( hwnd, TRUE );

    if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return wasVisible;
1068

1069
    if (wndPtr->flags & WIN_NEED_SIZE)
1070
    {
1071 1072
        /* should happen only in CreateWindowEx() */
	int wParam = SIZE_RESTORED;
1073
        RECT client = wndPtr->rectClient;
1074 1075 1076 1077

	wndPtr->flags &= ~WIN_NEED_SIZE;
	if (wndPtr->dwStyle & WS_MAXIMIZE) wParam = SIZE_MAXIMIZED;
	else if (wndPtr->dwStyle & WS_MINIMIZE) wParam = SIZE_MINIMIZED;
1078 1079 1080 1081 1082
        WIN_ReleasePtr( wndPtr );

        SendMessageW( hwnd, WM_SIZE, wParam,
                      MAKELONG( client.right - client.left, client.bottom - client.top ));
        SendMessageW( hwnd, WM_MOVE, 0, MAKELONG( client.left, client.top ));
1083
    }
1084
    else WIN_ReleasePtr( wndPtr );
1085

1086 1087
    return wasVisible;
}
1088 1089


1090 1091 1092
/**********************************************************************
 *		X11DRV_MapNotify
 */
1093
void X11DRV_MapNotify( HWND hwnd, XEvent *event )
1094
{
1095
    struct x11drv_win_data *data;
1096 1097
    HWND hwndFocus = GetFocus();
    WND *win;
1098

1099 1100
    if (!(data = X11DRV_get_win_data( hwnd ))) return;

1101
    if (!(win = WIN_GetPtr( hwnd ))) return;
1102

1103
    if (data->managed && (win->dwStyle & WS_VISIBLE) && (win->dwStyle & WS_MINIMIZE))
1104
    {
1105 1106 1107
        int x, y;
        unsigned int width, height, border, depth;
        Window root, top;
1108
        RECT rect;
1109
        LONG style = WS_VISIBLE;
1110

1111 1112
        /* FIXME: hack */
        wine_tsx11_lock();
1113
        XGetGeometry( event->xmap.display, data->whole_window, &root, &x, &y, &width, &height,
1114
                        &border, &depth );
1115
        XTranslateCoordinates( event->xmap.display, data->whole_window, root, 0, 0, &x, &y, &top );
1116 1117 1118 1119 1120
        wine_tsx11_unlock();
        rect.left   = x;
        rect.top    = y;
        rect.right  = x + width;
        rect.bottom = y + height;
1121
        X11DRV_X_to_window_rect( data, &rect );
1122

1123
        invalidate_dce( hwnd, &data->window_rect );
1124 1125

        if (win->flags & WIN_RESTORE_MAX) style |= WS_MAXIMIZE;
1126
        WIN_SetStyle( hwnd, style, WS_MINIMIZE );
1127 1128
        WIN_ReleasePtr( win );

1129
        SendMessageW( hwnd, WM_SHOWWINDOW, SW_RESTORE, 0 );
1130
        data->lock_changes++;
1131
        SetWindowPos( hwnd, 0, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top,
1132 1133
                      SWP_NOZORDER );
        data->lock_changes--;
1134
    }
1135
    else WIN_ReleasePtr( win );
1136 1137
    if (hwndFocus && IsChild( hwnd, hwndFocus )) X11DRV_SetFocus(hwndFocus);  /* FIXME */
}
1138 1139


1140 1141
/**********************************************************************
 *              X11DRV_UnmapNotify
1142
 */
1143
void X11DRV_UnmapNotify( HWND hwnd, XEvent *event )
1144
{
1145
    struct x11drv_win_data *data;
1146
    WND *win;
1147

1148 1149
    if (!(data = X11DRV_get_win_data( hwnd ))) return;

1150
    if (!(win = WIN_GetPtr( hwnd ))) return;
1151

1152
    if ((win->dwStyle & WS_VISIBLE) && data->managed &&
1153
        X11DRV_is_window_rect_mapped( &win->rectWindow ))
1154
    {
1155 1156
        if (win->dwStyle & WS_MAXIMIZE)
            win->flags |= WIN_RESTORE_MAX;
1157 1158
        else
            win->flags &= ~WIN_RESTORE_MAX;
1159

1160
        WIN_SetStyle( hwnd, WS_MINIMIZE, WS_MAXIMIZE );
1161 1162 1163
        WIN_ReleasePtr( win );

        EndMenu();
1164
        SendMessageW( hwnd, WM_SHOWWINDOW, SW_MINIMIZE, 0 );
1165
        data->lock_changes++;
1166
        SetWindowPos( hwnd, 0, 0, 0, GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON),
1167 1168
                      SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER );
        data->lock_changes--;
1169
    }
1170
    else WIN_ReleasePtr( win );
1171
}
1172 1173


1174 1175 1176 1177 1178 1179 1180
/***********************************************************************
 *		X11DRV_handle_desktop_resize
 */
void X11DRV_handle_desktop_resize( unsigned int width, unsigned int height )
{
    RECT rect;
    HWND hwnd = GetDesktopWindow();
1181
    struct x11drv_win_data *data;
1182

1183
    if (!(data = X11DRV_get_win_data( hwnd ))) return;
1184 1185 1186 1187
    screen_width  = width;
    screen_height = height;
    TRACE("desktop %p change to (%dx%d)\n", hwnd, width, height);
    SetRect( &rect, 0, 0, width, height );
1188 1189 1190
    data->lock_changes++;
    X11DRV_set_window_pos( hwnd, 0, &rect, &rect, SWP_NOZORDER|SWP_NOMOVE, NULL );
    data->lock_changes--;
1191 1192 1193 1194 1195
    SendMessageTimeoutW( HWND_BROADCAST, WM_DISPLAYCHANGE, screen_depth,
                         MAKELPARAM( width, height ), SMTO_ABORTIFHUNG, 2000, NULL );
}


1196 1197 1198
/***********************************************************************
 *		X11DRV_ConfigureNotify
 */
1199
void X11DRV_ConfigureNotify( HWND hwnd, XEvent *xev )
1200
{
1201
    XConfigureEvent *event = &xev->xconfigure;
1202 1203
    struct x11drv_win_data *data;
    RECT rect;
1204 1205
    UINT flags;
    int cx, cy, x = event->x, y = event->y;
1206

1207
    if (!hwnd) return;
1208
    if (!(data = X11DRV_get_win_data( hwnd ))) return;
1209

1210
    /* Get geometry */
1211

1212
    if (!event->send_event)  /* normal event, need to map coordinates to the root */
1213
    {
1214 1215 1216 1217 1218 1219 1220 1221 1222 1223
        Window child;
        wine_tsx11_lock();
        XTranslateCoordinates( event->display, data->whole_window, root_window,
                               0, 0, &x, &y, &child );
        wine_tsx11_unlock();
    }
    rect.left   = x;
    rect.top    = y;
    rect.right  = x + event->width;
    rect.bottom = y + event->height;
1224
    TRACE( "win %p new X rect %ld,%ld,%ldx%ld (event %d,%d,%dx%d)\n",
1225 1226
           hwnd, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top,
           event->x, event->y, event->width, event->height );
1227
    X11DRV_X_to_window_rect( data, &rect );
1228

1229 1230 1231 1232
    x     = rect.left;
    y     = rect.top;
    cx    = rect.right - rect.left;
    cy    = rect.bottom - rect.top;
1233
    flags = SWP_NOACTIVATE | SWP_NOZORDER;
1234

1235
    /* Compare what has changed */
1236

1237
    GetWindowRect( hwnd, &rect );
1238
    if (rect.left == x && rect.top == y) flags |= SWP_NOMOVE;
1239
    else
1240
        TRACE( "%p moving from (%ld,%ld) to (%d,%d)\n",
1241
               hwnd, rect.left, rect.top, x, y );
1242

1243
    if ((rect.right - rect.left == cx && rect.bottom - rect.top == cy) ||
1244
        IsIconic(hwnd) ||
1245
        (IsRectEmpty( &rect ) && event->width == 1 && event->height == 1))
1246 1247 1248 1249
    {
        if (flags & SWP_NOMOVE) return;  /* if nothing changed, don't do anything */
        flags |= SWP_NOSIZE;
    }
1250
    else
1251
        TRACE( "%p resizing from (%ldx%ld) to (%dx%d)\n",
1252
               hwnd, rect.right - rect.left, rect.bottom - rect.top, cx, cy );
1253

1254
    data->lock_changes++;
1255
    SetWindowPos( hwnd, 0, x, y, cx, cy, flags );
1256
    data->lock_changes--;
1257 1258 1259 1260 1261 1262 1263 1264
}


/***********************************************************************
 *		SetWindowRgn  (X11DRV.@)
 *
 * Assign specified region to window (for non-rectangular windows)
 */
1265
int X11DRV_SetWindowRgn( HWND hwnd, HRGN hrgn, BOOL redraw )
1266
{
1267
    struct x11drv_win_data *data;
1268

1269
    if (!(data = X11DRV_get_win_data( hwnd )))
1270
    {
1271
        if (IsWindow( hwnd ))
1272
            FIXME( "not supported on other thread window %p\n", hwnd );
1273 1274
        SetLastError( ERROR_INVALID_WINDOW_HANDLE );
        return FALSE;
1275 1276 1277
    }

#ifdef HAVE_LIBXSHAPE
1278
    if (data->whole_window)
1279
    {
1280
        Display *display = thread_display();
1281

1282 1283 1284 1285 1286 1287 1288 1289
        if (!hrgn)
        {
            wine_tsx11_lock();
            XShapeCombineMask( display, data->whole_window,
                               ShapeBounding, 0, 0, None, ShapeSet );
            wine_tsx11_unlock();
        }
        else
1290
        {
1291 1292
            RGNDATA *pRegionData = X11DRV_GetRegionData( hrgn, 0 );
            if (pRegionData)
1293
            {
1294
                wine_tsx11_lock();
1295 1296 1297 1298 1299 1300
                XShapeCombineRectangles( display, data->whole_window, ShapeBounding,
                                         data->window_rect.left - data->whole_rect.left,
                                         data->window_rect.top - data->whole_rect.top,
                                         (XRectangle *)pRegionData->Buffer,
                                         pRegionData->rdh.nCount,
                                         ShapeSet, YXBanded );
1301
                wine_tsx11_unlock();
1302
                HeapFree(GetProcessHeap(), 0, pRegionData);
1303 1304 1305 1306 1307
            }
        }
    }
#endif  /* HAVE_LIBXSHAPE */

1308
    invalidate_dce( hwnd, &data->window_rect );
1309
    return TRUE;
1310
}
1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347


/***********************************************************************
 *           draw_moving_frame
 *
 * Draw the frame used when moving or resizing window.
 *
 * FIXME:  This causes problems in Win95 mode.  (why?)
 */
static void draw_moving_frame( HDC hdc, RECT *rect, BOOL thickframe )
{
    if (thickframe)
    {
        const int width = GetSystemMetrics(SM_CXFRAME);
        const int height = GetSystemMetrics(SM_CYFRAME);

        HBRUSH hbrush = SelectObject( hdc, GetStockObject( GRAY_BRUSH ) );
        PatBlt( hdc, rect->left, rect->top,
                rect->right - rect->left - width, height, PATINVERT );
        PatBlt( hdc, rect->left, rect->top + height, width,
                rect->bottom - rect->top - height, PATINVERT );
        PatBlt( hdc, rect->left + width, rect->bottom - 1,
                rect->right - rect->left - width, -height, PATINVERT );
        PatBlt( hdc, rect->right - 1, rect->top, -width,
                rect->bottom - rect->top - height, PATINVERT );
        SelectObject( hdc, hbrush );
    }
    else DrawFocusRect( hdc, rect );
}


/***********************************************************************
 *           start_size_move
 *
 * Initialisation of a move or resize, when initiatied from a menu choice.
 * Return hit test code for caption or sizing border.
 */
1348
static LONG start_size_move( HWND hwnd, WPARAM wParam, POINT *capturePoint, LONG style )
1349 1350 1351 1352 1353 1354
{
    LONG hittest = 0;
    POINT pt;
    MSG msg;
    RECT rectWindow;

1355
    GetWindowRect( hwnd, &rectWindow );
1356 1357 1358 1359

    if ((wParam & 0xfff0) == SC_MOVE)
    {
        /* Move pointer at the center of the caption */
1360 1361 1362 1363 1364
        RECT rect = rectWindow;
        /* Note: to be exactly centered we should take the different types
         * of border into account, but it shouldn't make more that a few pixels
         * of difference so let's not bother with that */
        rect.top += GetSystemMetrics(SM_CYBORDER);
1365
        if (style & WS_SYSMENU)
1366
            rect.left += GetSystemMetrics(SM_CXSIZE) + 1;
1367
        if (style & WS_MINIMIZEBOX)
1368
            rect.right -= GetSystemMetrics(SM_CXSIZE) + 1;
1369
        if (style & WS_MAXIMIZEBOX)
1370
            rect.right -= GetSystemMetrics(SM_CXSIZE) + 1;
1371 1372
        pt.x = (rect.right + rect.left) / 2;
        pt.y = rect.top + GetSystemMetrics(SM_CYSIZE)/2;
1373 1374 1375 1376 1377
        hittest = HTCAPTION;
        *capturePoint = pt;
    }
    else  /* SC_SIZE */
    {
1378
        pt.x = pt.y = 0;
1379 1380
        while(!hittest)
        {
1381 1382 1383
            GetMessageW( &msg, 0, WM_KEYFIRST, WM_MOUSELAST );
            if (CallMsgFilterW( &msg, MSGF_SIZE )) continue;

1384 1385 1386
            switch(msg.message)
            {
            case WM_MOUSEMOVE:
1387 1388 1389
                pt = msg.pt;
                hittest = SendMessageW( hwnd, WM_NCHITTEST, 0, MAKELONG( pt.x, pt.y ) );
                if ((hittest < HTLEFT) || (hittest > HTBOTTOMRIGHT)) hittest = 0;
1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425
                break;

            case WM_LBUTTONUP:
                return 0;

            case WM_KEYDOWN:
                switch(msg.wParam)
                {
                case VK_UP:
                    hittest = HTTOP;
                    pt.x =(rectWindow.left+rectWindow.right)/2;
                    pt.y = rectWindow.top + GetSystemMetrics(SM_CYFRAME) / 2;
                    break;
                case VK_DOWN:
                    hittest = HTBOTTOM;
                    pt.x =(rectWindow.left+rectWindow.right)/2;
                    pt.y = rectWindow.bottom - GetSystemMetrics(SM_CYFRAME) / 2;
                    break;
                case VK_LEFT:
                    hittest = HTLEFT;
                    pt.x = rectWindow.left + GetSystemMetrics(SM_CXFRAME) / 2;
                    pt.y =(rectWindow.top+rectWindow.bottom)/2;
                    break;
                case VK_RIGHT:
                    hittest = HTRIGHT;
                    pt.x = rectWindow.right - GetSystemMetrics(SM_CXFRAME) / 2;
                    pt.y =(rectWindow.top+rectWindow.bottom)/2;
                    break;
                case VK_RETURN:
                case VK_ESCAPE: return 0;
                }
            }
        }
        *capturePoint = pt;
    }
    SetCursorPos( pt.x, pt.y );
1426
    SendMessageW( hwnd, WM_SETCURSOR, (WPARAM)hwnd, MAKELONG( hittest, WM_MOUSEMOVE ));
1427 1428 1429 1430
    return hittest;
}


1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452
/***********************************************************************
 *           set_movesize_capture
 */
static void set_movesize_capture( HWND hwnd )
{
    HWND previous = 0;

    SERVER_START_REQ( set_capture_window )
    {
        req->handle = hwnd;
        req->flags  = CAPTURE_MOVESIZE;
        if (!wine_server_call_err( req ))
        {
            previous = reply->previous;
            hwnd = reply->full_handle;
        }
    }
    SERVER_END_REQ;
    if (previous && previous != hwnd)
        SendMessageW( previous, WM_CAPTURECHANGED, 0, (LPARAM)hwnd );
}

1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479
/***********************************************************************
 *           X11DRV_WMMoveResizeWindow
 *
 * Tells the window manager to initiate a move or resize operation.
 *
 * SEE
 *  http://freedesktop.org/Standards/wm-spec/1.3/ar01s04.html
 *  or search for "_NET_WM_MOVERESIZE"
 */
static void X11DRV_WMMoveResizeWindow( HWND hwnd, int x, int y, int dir )
{
    XEvent xev;
    Display *display = thread_display();

    xev.xclient.type = ClientMessage;
    xev.xclient.window = X11DRV_get_whole_window(hwnd);
    xev.xclient.message_type = x11drv_atom(_NET_WM_MOVERESIZE);
    xev.xclient.serial = 0;
    xev.xclient.display = display;
    xev.xclient.send_event = True;
    xev.xclient.format = 32;
    xev.xclient.data.l[0] = x; /* x coord */
    xev.xclient.data.l[1] = y; /* y coord */
    xev.xclient.data.l[2] = dir; /* direction */
    xev.xclient.data.l[3] = 1; /* button */
    xev.xclient.data.l[4] = 0; /* unused */

1480 1481 1482 1483 1484
    /* need to ungrab the pointer that may have been automatically grabbed
     * with a ButtonPress event */
    wine_tsx11_lock();
    XUngrabPointer( display, CurrentTime );
    XSendEvent(display, root_window, False, SubstructureNotifyMask, &xev);
1485 1486
    wine_tsx11_unlock();
}
1487

1488
/***********************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
1489
 *           SysCommandSizeMove   (X11DRV.@)
1490 1491 1492 1493 1494 1495 1496 1497
 *
 * Perform SC_MOVE and SC_SIZE commands.
 */
void X11DRV_SysCommandSizeMove( HWND hwnd, WPARAM wParam )
{
    MSG msg;
    RECT sizingRect, mouseRect, origRect;
    HDC hdc;
1498
    HWND parent;
1499
    LONG hittest = (LONG)(wParam & 0x0f);
1500
    WPARAM syscommand = wParam & 0xfff0;
1501
    HCURSOR hDragCursor = 0, hOldCursor = 0;
1502 1503
    POINT minTrack, maxTrack;
    POINT capturePoint, pt;
1504
    LONG style = GetWindowLongA( hwnd, GWL_STYLE );
1505
    BOOL    thickframe = HAS_THICKFRAME( style );
1506
    BOOL    iconic = style & WS_MINIMIZE;
1507 1508 1509
    BOOL    moved = FALSE;
    DWORD     dwPoint = GetMessagePos ();
    BOOL DragFullWindows = FALSE;
1510
    BOOL grab;
1511
    Window parent_win, whole_win;
1512
    Display *old_gdi_display = NULL;
1513
    struct x11drv_thread_data *thread_data = x11drv_thread_data();
1514
    struct x11drv_win_data *data;
1515

1516 1517
    pt.x = (short)LOWORD(dwPoint);
    pt.y = (short)HIWORD(dwPoint);
1518 1519
    capturePoint = pt;

1520
    if (IsZoomed(hwnd) || !IsWindowVisible(hwnd)) return;
1521

1522 1523
    if (!(data = X11DRV_get_win_data( hwnd ))) return;

1524
    /* if we are managed then we let the WM do all the work */
1525
    if (data->managed)
1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555
    {
        int dir;
        if (syscommand == SC_MOVE)
        {
            if (!hittest) dir = _NET_WM_MOVERESIZE_MOVE_KEYBOARD;
            else dir = _NET_WM_MOVERESIZE_MOVE;
        }
        else if (!hittest) dir = _NET_WM_MOVERESIZE_SIZE_KEYBOARD;
        else
            switch (hittest)
            {
            case WMSZ_LEFT:        dir = _NET_WM_MOVERESIZE_SIZE_LEFT; break;
            case WMSZ_RIGHT:       dir = _NET_WM_MOVERESIZE_SIZE_RIGHT; break;
            case WMSZ_TOP:         dir = _NET_WM_MOVERESIZE_SIZE_TOP; break;
            case WMSZ_TOPLEFT:     dir = _NET_WM_MOVERESIZE_SIZE_TOPLEFT; break;
            case WMSZ_TOPRIGHT:    dir = _NET_WM_MOVERESIZE_SIZE_TOPRIGHT; break;
            case WMSZ_BOTTOM:      dir = _NET_WM_MOVERESIZE_SIZE_BOTTOM; break;
            case WMSZ_BOTTOMLEFT:  dir = _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT; break;
            case WMSZ_BOTTOMRIGHT: dir = _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT; break;
            default:
                ERR("Invalid hittest value: %ld\n", hittest);
                dir = _NET_WM_MOVERESIZE_SIZE_KEYBOARD;
            }
        X11DRV_WMMoveResizeWindow( hwnd, pt.x, pt.y, dir );
        return;
    }

    SystemParametersInfoA(SPI_GETDRAGFULLWINDOWS, 0, &DragFullWindows, 0);

    if (syscommand == SC_MOVE)
1556
    {
1557 1558
        if (!hittest) hittest = start_size_move( hwnd, wParam, &capturePoint, style );
        if (!hittest) return;
1559 1560 1561
    }
    else  /* SC_SIZE */
    {
1562
        if ( hittest && (syscommand != SC_MOUSEMENU) )
1563
            hittest += (HTLEFT - WMSZ_LEFT);
1564 1565
        else
        {
1566
            set_movesize_capture( hwnd );
1567
            hittest = start_size_move( hwnd, wParam, &capturePoint, style );
1568 1569
            if (!hittest)
            {
1570
                set_movesize_capture(0);
1571
                return;
1572 1573 1574 1575 1576 1577
            }
        }
    }

      /* Get min/max info */

1578
    WINPOS_GetMinMaxInfo( hwnd, NULL, NULL, &minTrack, &maxTrack );
1579 1580 1581 1582 1583 1584 1585 1586
    GetWindowRect( hwnd, &sizingRect );
    if (style & WS_CHILD)
    {
        parent = GetParent(hwnd);
        /* make sizing rect relative to parent */
        MapWindowPoints( 0, parent, (POINT*)&sizingRect, 2 );
        GetClientRect( parent, &mouseRect );
    }
1587
    else
1588 1589
    {
        parent = 0;
1590
        SetRect(&mouseRect, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));
1591 1592 1593
    }
    origRect = sizingRect;

1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613
    if (ON_LEFT_BORDER(hittest))
    {
        mouseRect.left  = max( mouseRect.left, sizingRect.right-maxTrack.x );
        mouseRect.right = min( mouseRect.right, sizingRect.right-minTrack.x );
    }
    else if (ON_RIGHT_BORDER(hittest))
    {
        mouseRect.left  = max( mouseRect.left, sizingRect.left+minTrack.x );
        mouseRect.right = min( mouseRect.right, sizingRect.left+maxTrack.x );
    }
    if (ON_TOP_BORDER(hittest))
    {
        mouseRect.top    = max( mouseRect.top, sizingRect.bottom-maxTrack.y );
        mouseRect.bottom = min( mouseRect.bottom,sizingRect.bottom-minTrack.y);
    }
    else if (ON_BOTTOM_BORDER(hittest))
    {
        mouseRect.top    = max( mouseRect.top, sizingRect.top+minTrack.y );
        mouseRect.bottom = min( mouseRect.bottom, sizingRect.top+maxTrack.y );
    }
1614
    if (parent) MapWindowPoints( parent, 0, (LPPOINT)&mouseRect, 2 );
1615

1616
    /* Retrieve a default cache DC (without using the window style) */
1617
    hdc = GetDCEx( parent, 0, DCX_CACHE );
1618 1619 1620

    if( iconic ) /* create a cursor for dragging */
    {
1621 1622
        hDragCursor = (HCURSOR)GetClassLongPtrW( hwnd, GCLP_HICON);
        if( !hDragCursor ) hDragCursor = (HCURSOR)SendMessageW( hwnd, WM_QUERYDRAGICON, 0, 0L);
1623 1624 1625 1626 1627 1628
        if( !hDragCursor ) iconic = FALSE;
    }

    /* repaint the window before moving it around */
    RedrawWindow( hwnd, NULL, 0, RDW_UPDATENOW | RDW_ALLCHILDREN );

1629
    SendMessageW( hwnd, WM_ENTERSIZEMOVE, 0, 0 );
1630
    set_movesize_capture( hwnd );
1631

1632
    /* grab the server only when moving top-level windows without desktop */
1633
    grab = (!DragFullWindows && !parent && (root_window == DefaultRootWindow(gdi_display)));
1634

1635 1636
    if (grab)
    {
1637
        wine_tsx11_lock();
1638
        XSync( gdi_display, False );
1639 1640
        XGrabServer( thread_data->display );
        XSync( thread_data->display, False );
1641 1642
        /* switch gdi display to the thread display, since the server is grabbed */
        old_gdi_display = gdi_display;
1643
        gdi_display = thread_data->display;
1644
        wine_tsx11_unlock();
1645
    }
1646 1647
    whole_win = X11DRV_get_whole_window( GetAncestor(hwnd,GA_ROOT) );
    parent_win = parent ? X11DRV_get_whole_window( GetAncestor(parent,GA_ROOT) ) : root_window;
1648 1649

    wine_tsx11_lock();
1650
    XGrabPointer( thread_data->display, whole_win, False,
1651
                  PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
1652
                  GrabModeAsync, GrabModeAsync, parent_win, None, CurrentTime );
1653
    wine_tsx11_unlock();
1654
    thread_data->grab_window = whole_win;
1655 1656 1657 1658 1659

    while(1)
    {
        int dx = 0, dy = 0;

1660 1661
        if (!GetMessageW( &msg, 0, WM_KEYFIRST, WM_MOUSELAST )) break;
        if (CallMsgFilterW( &msg, MSGF_SIZE )) continue;
1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698

        /* Exit on button-up, Return, or Esc */
        if ((msg.message == WM_LBUTTONUP) ||
            ((msg.message == WM_KEYDOWN) &&
             ((msg.wParam == VK_RETURN) || (msg.wParam == VK_ESCAPE)))) break;

        if ((msg.message != WM_KEYDOWN) && (msg.message != WM_MOUSEMOVE))
            continue;  /* We are not interested in other messages */

        pt = msg.pt;

        if (msg.message == WM_KEYDOWN) switch(msg.wParam)
        {
        case VK_UP:    pt.y -= 8; break;
        case VK_DOWN:  pt.y += 8; break;
        case VK_LEFT:  pt.x -= 8; break;
        case VK_RIGHT: pt.x += 8; break;
        }

        pt.x = max( pt.x, mouseRect.left );
        pt.x = min( pt.x, mouseRect.right );
        pt.y = max( pt.y, mouseRect.top );
        pt.y = min( pt.y, mouseRect.bottom );

        dx = pt.x - capturePoint.x;
        dy = pt.y - capturePoint.y;

        if (dx || dy)
        {
            if( !moved )
            {
                moved = TRUE;

                if( iconic ) /* ok, no system popup tracking */
                {
                    hOldCursor = SetCursor(hDragCursor);
                    ShowCursor( TRUE );
1699
                    WINPOS_ShowIconTitle( hwnd, FALSE );
1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721
                }
                else if(!DragFullWindows)
                    draw_moving_frame( hdc, &sizingRect, thickframe );
            }

            if (msg.message == WM_KEYDOWN) SetCursorPos( pt.x, pt.y );
            else
            {
                RECT newRect = sizingRect;
                WPARAM wpSizingHit = 0;

                if (hittest == HTCAPTION) OffsetRect( &newRect, dx, dy );
                if (ON_LEFT_BORDER(hittest)) newRect.left += dx;
                else if (ON_RIGHT_BORDER(hittest)) newRect.right += dx;
                if (ON_TOP_BORDER(hittest)) newRect.top += dy;
                else if (ON_BOTTOM_BORDER(hittest)) newRect.bottom += dy;
                if(!iconic && !DragFullWindows) draw_moving_frame( hdc, &sizingRect, thickframe );
                capturePoint = pt;

                /* determine the hit location */
                if (hittest >= HTLEFT && hittest <= HTBOTTOMRIGHT)
                    wpSizingHit = WMSZ_LEFT + (hittest - HTLEFT);
1722
                SendMessageW( hwnd, WM_SIZING, wpSizingHit, (LPARAM)&newRect );
1723 1724 1725 1726 1727

                if (!iconic)
                {
                    if(!DragFullWindows)
                        draw_moving_frame( hdc, &newRect, thickframe );
1728
                    else
1729 1730 1731 1732 1733 1734 1735 1736 1737 1738
                        SetWindowPos( hwnd, 0, newRect.left, newRect.top,
                                      newRect.right - newRect.left,
                                      newRect.bottom - newRect.top,
                                      ( hittest == HTCAPTION ) ? SWP_NOSIZE : 0 );
                }
                sizingRect = newRect;
            }
        }
    }

1739
    set_movesize_capture(0);
1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750
    if( iconic )
    {
        if( moved ) /* restore cursors, show icon title later on */
        {
            ShowCursor( FALSE );
            SetCursor( hOldCursor );
        }
    }
    else if (moved && !DragFullWindows)
        draw_moving_frame( hdc, &sizingRect, thickframe );

1751
    ReleaseDC( parent, hdc );
1752

1753
    wine_tsx11_lock();
1754
    XUngrabPointer( thread_data->display, CurrentTime );
1755 1756
    if (grab)
    {
1757 1758 1759
        XSync( thread_data->display, False );
        XUngrabServer( thread_data->display );
        XSync( thread_data->display, False );
1760 1761
        gdi_display = old_gdi_display;
    }
1762
    wine_tsx11_unlock();
1763
    thread_data->grab_window = None;
1764

1765 1766
    if (HOOK_CallHooks( WH_CBT, HCBT_MOVESIZE, (WPARAM)hwnd, (LPARAM)&sizingRect, TRUE ))
        moved = FALSE;
1767

1768 1769
    SendMessageW( hwnd, WM_EXITSIZEMOVE, 0, 0 );
    SendMessageW( hwnd, WM_SETVISIBLE, !IsIconic(hwnd), 0L);
1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801

    /* window moved or resized */
    if (moved)
    {
        /* if the moving/resizing isn't canceled call SetWindowPos
         * with the new position or the new size of the window
         */
        if (!((msg.message == WM_KEYDOWN) && (msg.wParam == VK_ESCAPE)) )
        {
            /* NOTE: SWP_NOACTIVATE prevents document window activation in Word 6 */
            if(!DragFullWindows)
                SetWindowPos( hwnd, 0, sizingRect.left, sizingRect.top,
                              sizingRect.right - sizingRect.left,
                              sizingRect.bottom - sizingRect.top,
                              ( hittest == HTCAPTION ) ? SWP_NOSIZE : 0 );
        }
        else
        { /* restore previous size/position */
            if(DragFullWindows)
                SetWindowPos( hwnd, 0, origRect.left, origRect.top,
                              origRect.right - origRect.left,
                              origRect.bottom - origRect.top,
                              ( hittest == HTCAPTION ) ? SWP_NOSIZE : 0 );
        }
    }

    if (IsIconic(hwnd))
    {
        /* Single click brings up the system menu when iconized */

        if( !moved )
        {
1802
            if(style & WS_SYSMENU )
1803
                SendMessageW( hwnd, WM_SYSCOMMAND,
1804 1805
                              SC_MOUSEMENU + HTSYSMENU, MAKELONG(pt.x,pt.y));
        }
1806
        else WINPOS_ShowIconTitle( hwnd, TRUE );
1807 1808
    }
}