winpos.c 59.3 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 19
 *
 * 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
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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
    if (!(wndPtr = WIN_GetPtr( pWinpos->hwnd )) || wndPtr == WND_OTHER_PROCESS) return FALSE;
137 138

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

    *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;
160 161 162 163 164 165 166 167

    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 ));

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

172 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

/***********************************************************************
 *           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;
    }
}


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

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

      /* Send WM_NCCALCSIZE message to get new client area */
    if( (pWinpos->flags & (SWP_FRAMECHANGED | SWP_NOSIZE)) != SWP_NOSIZE )
    {
249 250 251 252 253 254 255 256 257 258 259 260
        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 );

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

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

265 266 267 268
        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) );

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

273
        if( (pNewClientRect->right - pNewClientRect->left !=
274 275 276 277 278 279 280
             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)
281
            pWinpos->flags &= ~SWP_NOCLIENTSIZE;
282 283 284 285 286
        else
            wvrFlags &= ~WVR_VREDRAW;

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

    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 );

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

307

308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329
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;
}

330 331 332 333 334 335 336 337
/***********************************************************************
 *           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.
 */
338
static HWND SWP_DoOwnedPopups(HWND hwnd, HWND hwndInsertAfter)
339
{
340 341
    HWND owner = GetWindow( hwnd, GW_OWNER );
    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 349 350 351
    {
        /* make sure this popup stays above the owner */

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

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

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

372 373 374 375

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

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

387 388 389 390 391 392 393 394 395 396 397
    /* 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;

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

401 402 403 404 405 406 407 408 409 410 411 412 413 414
    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 */

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 420 421 422 423 424
        {
            winpos->flags &= ~SWP_NOZORDER;
            winpos->hwndInsertAfter = HWND_TOP;
        }
    }

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

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

431 432 433 434 435
      /* 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 */
436 437 438 439 440 441 442 443 444 445 446
    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
447
    {
448
        if (GetAncestor( winpos->hwndInsertAfter, GA_PARENT ) != parent) ret = FALSE;
449
        else
450
        {
451 452 453 454 455 456
            /* 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;
457 458 459
        }
    }
 done:
460
    WIN_ReleasePtr( wndPtr );
461 462 463 464
    return ret;
}


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

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

479 480
    new_style = GetWindowLongW( hwnd, GWL_STYLE );
    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 490
                X11DRV_sync_window_style( display, data );
                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 501

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


521 522 523 524 525 526
/***********************************************************************
 *           X11DRV_set_window_pos
 *
 * Set a window position and Z order.
 */
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 533 534
    DWORD old_style, new_style;
    BOOL ret;

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

    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;
        }
    }

559
    if (!(win = WIN_GetPtr( hwnd ))) return FALSE;
560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577
    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;
        req->flags         = swp_flags & ~SWP_WINE_NOHOSTMOVE;
        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;
578 579 580 581 582 583
        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) );
        }
584 585 586 587 588
        ret = !wine_server_call( req );
        new_style = reply->new_style;
    }
    SERVER_END_REQ;

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

602 603 604 605 606 607 608 609 610 611 612
    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 );
613
            invalidate_dce( hwnd, &rect );
614 615
        }

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

        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 */

627
        if (data->whole_window && !(swp_flags & SWP_WINE_NOHOSTMOVE))
628 629 630 631 632 633
        {
            if ((old_style & WS_VISIBLE) && !(new_style & WS_VISIBLE))
            {
                /* window got hidden, unmap it */
                TRACE( "unmapping win %p\n", hwnd );
                wine_tsx11_lock();
634
                XUnmapWindow( display, data->whole_window );
635 636 637 638 639 640 641 642 643 644
                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();
            }
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 652
            if ((new_style & WS_VISIBLE) && !(new_style & WS_MINIMIZE) &&
                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 659
                    X11DRV_sync_window_style( display, data );
                    X11DRV_set_wm_hints( display, data );
660 661 662 663
                    wine_tsx11_lock();
                    XMapWindow( display, data->whole_window );
                    wine_tsx11_unlock();
                }
664 665 666 667 668 669 670 671
                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();
                }
672 673 674 675 676 677 678 679 680 681 682
            }
            wine_tsx11_lock();
            XFlush( display );  /* FIXME: should not be necessary */
            wine_tsx11_unlock();
        }
    }
    WIN_ReleasePtr( win );
    return ret;
}


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

691 692 693
    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);
694

695
    orig_flags = winpos->flags;
696 697
    winpos->flags &= ~SWP_WINE_NOHOSTMOVE;

698 699 700
    /* Check window handle */
    if (winpos->hwnd == GetDesktopWindow()) return FALSE;

701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716
    /* 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;
    }

717 718 719 720
    if (!SWP_DoWinPosChanging( winpos, &newWindowRect, &newClientRect )) return FALSE;

    /* Fix redundant flags */
    if (!fixup_flags( winpos )) return FALSE;
721 722 723

    if((winpos->flags & (SWP_NOZORDER | SWP_HIDEWINDOW | SWP_SHOWWINDOW)) != SWP_NOZORDER)
    {
724 725
        if (GetAncestor( winpos->hwnd, GA_PARENT ) == GetDesktopWindow())
            winpos->hwndInsertAfter = SWP_DoOwnedPopups( winpos->hwnd, winpos->hwndInsertAfter );
726 727 728 729
    }

    /* Common operations */

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 737 738 739 740 741 742
    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 );
    }

743 744 745 746
    if( winpos->flags & SWP_HIDEWINDOW )
        HideCaret(winpos->hwnd);
    else if (winpos->flags & SWP_SHOWWINDOW)
        ShowCaret(winpos->hwnd);
747

748
    if (!(winpos->flags & (SWP_NOACTIVATE|SWP_HIDEWINDOW)))
749 750 751 752 753
    {
        /* child windows get WM_CHILDACTIVATE message */
        if ((GetWindowLongW( winpos->hwnd, GWL_STYLE ) & (WS_CHILD | WS_POPUP)) == WS_CHILD)
            SendMessageA( winpos->hwnd, WM_CHILDACTIVATE, 0, 0 );
        else
754
            SetForegroundWindow( winpos->hwnd );
755
    }
756 757 758 759

      /* And last, send the WM_WINDOWPOSCHANGED message */

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

761
    if (((winpos->flags & SWP_AGG_STATUSFLAGS) != SWP_AGG_NOPOSCHANGE))
762 763 764 765 766 767 768 769 770 771
    {
        /* 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 );
    }
772 773 774 775 776 777 778 779 780 781

    return TRUE;
}


/***********************************************************************
 *           WINPOS_FindIconPos
 *
 * Find a suitable place for an iconic window.
 */
782
static POINT WINPOS_FindIconPos( HWND hwnd, POINT pt )
783
{
784 785 786 787
    RECT rect, rectParent;
    HWND parent, child;
    HRGN hrgn, tmp;
    int xspacing, yspacing;
788

789 790
    parent = GetAncestor( hwnd, GA_PARENT );
    GetClientRect( parent, &rectParent );
791 792 793 794 795 796 797
    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);

798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818
    /* 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)
819
    {
820
        for (rect.left = rectParent.left; rect.left <= rectParent.right - xspacing; rect.left += xspacing)
821
        {
822 823 824
            rect.right = rect.left + xspacing;
            rect.top = rect.bottom - yspacing;
            if (!RectInRegion( hrgn, &rect ))
825
            {
826 827 828 829 830
                /* 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;
831
            }
832
        }
833
    }
834 835 836
    DeleteObject( hrgn );
    pt.x = pt.y = 0;
    return pt;
837
}
838 839 840 841 842





843 844
UINT WINPOS_MinMaximize( HWND hwnd, UINT cmd, LPRECT rect )
{
845
    WND *wndPtr;
846 847
    UINT swpFlags = 0;
    POINT size;
848
    LONG old_style;
849
    WINDOWPLACEMENT wpl;
850

851
    TRACE("%p %u\n", hwnd, cmd );
852

853 854
    wpl.length = sizeof(wpl);
    GetWindowPlacement( hwnd, &wpl );
855

856
    if (HOOK_CallHooks( WH_CBT, HCBT_MINMAX, (WPARAM)hwnd, cmd, TRUE ))
857 858 859 860 861
        return SWP_NOSIZE | SWP_NOMOVE;

    if (IsIconic( hwnd ))
    {
        if (cmd == SW_MINIMIZE) return SWP_NOSIZE | SWP_NOMOVE;
862
        if (!SendMessageW( hwnd, WM_QUERYOPEN, 0, 0 )) return SWP_NOSIZE | SWP_NOMOVE;
863 864 865 866
        swpFlags |= SWP_NOCOPYBITS;
    }

    switch( cmd )
867
    {
868
    case SW_MINIMIZE:
869
        if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return 0;
870 871
        if( wndPtr->dwStyle & WS_MAXIMIZE) wndPtr->flags |= WIN_RESTORE_MAX;
        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 881 882 883
        SetRect( rect, wpl.ptMinPosition.x, wpl.ptMinPosition.y,
                 GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON) );
        swpFlags |= SWP_NOCOPYBITS;
        break;
884

885 886
    case SW_MAXIMIZE:
        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 895
        }
        SetRect( rect, wpl.ptMaxPosition.x, wpl.ptMaxPosition.y, size.x, size.y );
        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 902
            BOOL restore_max;

903
            WINPOS_ShowIconTitle( hwnd, FALSE );
904
            X11DRV_set_iconic_state( hwnd );
905

906 907 908 909
            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)
910 911 912
            {
                /* Restore to maximized position */
                WINPOS_GetMinMaxInfo( hwnd, &size, &wpl.ptMaxPosition, NULL, NULL);
913
                WIN_SetStyle( hwnd, WS_MAXIMIZE, 0 );
914 915
                SetRect( rect, wpl.ptMaxPosition.x, wpl.ptMaxPosition.y, size.x, size.y );
                break;
916
            }
917
        }
918
        else if (!(old_style & WS_MAXIMIZE)) break;
919

920
        /* Restore to normal position */
921

922 923 924
        *rect = wpl.rcNormalPosition;
        rect->right -= rect->left;
        rect->bottom -= rect->top;
925

926 927
        break;
    }
928 929

    return swpFlags;
930 931 932 933
}


/***********************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
934
 *              ShowWindow   (X11DRV.@)
935
 */
936
BOOL X11DRV_ShowWindow( HWND hwnd, INT cmd )
937
{
938 939 940 941 942 943
    WND *wndPtr;
    LONG style = GetWindowLongW( hwnd, GWL_STYLE );
    BOOL wasVisible = (style & WS_VISIBLE) != 0;
    BOOL showFlag = TRUE;
    RECT newPos = {0, 0, 0, 0};
    UINT swp = 0;
944

945
    if (hwnd == GetDesktopWindow()) return FALSE;
946

947 948
    TRACE("hwnd=%p, cmd=%d, wasVisible %d\n", hwnd, cmd, wasVisible);

949
    switch(cmd)
950
    {
951
        case SW_HIDE:
952 953
            if (!wasVisible) return FALSE;
            showFlag = FALSE;
954 955 956
            swp |= SWP_HIDEWINDOW | SWP_NOSIZE | SWP_NOMOVE;
            if (hwnd != GetActiveWindow())
                swp |= SWP_NOACTIVATE | SWP_NOZORDER;
957 958 959 960 961 962
	    break;

	case SW_SHOWMINNOACTIVE:
            swp |= SWP_NOACTIVATE | SWP_NOZORDER;
            /* fall through */
	case SW_SHOWMINIMIZED:
963
        case SW_FORCEMINIMIZE: /* FIXME: Does not work if thread is hung. */
964 965 966 967
            swp |= SWP_SHOWWINDOW;
            /* fall through */
	case SW_MINIMIZE:
            swp |= SWP_FRAMECHANGED;
968
            if( !(style & WS_MINIMIZE) )
969 970 971 972 973 974
		 swp |= WINPOS_MinMaximize( hwnd, SW_MINIMIZE, &newPos );
            else swp |= SWP_NOSIZE | SWP_NOMOVE;
	    break;

	case SW_SHOWMAXIMIZED: /* same as SW_MAXIMIZE */
            swp |= SWP_SHOWWINDOW | SWP_FRAMECHANGED;
975
            swp |= WINPOS_MinMaximize( hwnd, SW_MAXIMIZE, &newPos );
976 977 978
            break;

	case SW_SHOWNA:
979
            swp |= SWP_NOACTIVATE | SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE;
980
            if (style & WS_CHILD) swp |= SWP_NOZORDER;
981
            break;
982
	case SW_SHOW:
983
            if (wasVisible) return TRUE;
984 985 986
	    swp |= SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE;
	    break;

987 988 989
	case SW_RESTORE:
	    swp |= SWP_FRAMECHANGED;
            /* fall through */
990
	case SW_SHOWNOACTIVATE:
991
            swp |= SWP_NOACTIVATE | SWP_NOZORDER;
992 993 994
            /* fall through */
	case SW_SHOWNORMAL:  /* same as SW_NORMAL: */
	case SW_SHOWDEFAULT: /* FIXME: should have its own handler */
995
	    swp |= SWP_SHOWWINDOW;
996

997
            if (style & (WS_MINIMIZE | WS_MAXIMIZE))
998 999 1000
		 swp |= WINPOS_MinMaximize( hwnd, SW_RESTORE, &newPos );
            else swp |= SWP_NOSIZE | SWP_NOMOVE;
	    break;
1001 1002
    }

1003
    if ((showFlag != wasVisible || cmd == SW_SHOWNA) && cmd != SW_SHOWMAXIMIZED)
1004 1005
    {
        SendMessageW( hwnd, WM_SHOWWINDOW, showFlag, 0 );
1006
        if (!IsWindow( hwnd )) return wasVisible;
1007 1008
    }

1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023
    if (!IsWindowVisible( GetAncestor( hwnd, GA_PARENT )))
    {
        /* 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
    {
        /* ShowWindow won't activate a not being maximized child window */
        if ((style & WS_CHILD) && cmd != SW_MAXIMIZE)
            swp |= SWP_NOACTIVATE | SWP_NOZORDER;

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

1025
    if (cmd == SW_HIDE)
1026
    {
1027 1028
        HWND hFocus;

1029 1030 1031 1032
        /* FIXME: This will cause the window to be activated irrespective
         * of whether it is owned by the same thread. Has to be done
         * asynchronously.
         */
1033

1034
        if (hwnd == GetActiveWindow())
1035
            WINPOS_ActivateOtherWindow(hwnd);
1036

1037
        /* Revert focus to parent */
1038 1039 1040 1041 1042 1043 1044
        hFocus = GetFocus();
        if (hwnd == hFocus || IsChild(hwnd, hFocus))
        {
            HWND parent = GetAncestor(hwnd, GA_PARENT);
            if (parent == GetDesktopWindow()) parent = 0;
            SetFocus(parent);
        }
1045
    }
1046 1047 1048 1049

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

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

1051
    if (wndPtr->flags & WIN_NEED_SIZE)
1052
    {
1053 1054
        /* should happen only in CreateWindowEx() */
	int wParam = SIZE_RESTORED;
1055
        RECT client = wndPtr->rectClient;
1056 1057 1058 1059

	wndPtr->flags &= ~WIN_NEED_SIZE;
	if (wndPtr->dwStyle & WS_MAXIMIZE) wParam = SIZE_MAXIMIZED;
	else if (wndPtr->dwStyle & WS_MINIMIZE) wParam = SIZE_MINIMIZED;
1060 1061 1062 1063 1064
        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 ));
1065
    }
1066
    else WIN_ReleasePtr( wndPtr );
1067

1068 1069
    return wasVisible;
}
1070 1071


1072 1073 1074
/**********************************************************************
 *		X11DRV_MapNotify
 */
1075
void X11DRV_MapNotify( HWND hwnd, XEvent *event )
1076
{
1077
    struct x11drv_win_data *data;
1078 1079
    HWND hwndFocus = GetFocus();
    WND *win;
1080

1081 1082
    if (!(data = X11DRV_get_win_data( hwnd ))) return;

1083
    if (!(win = WIN_GetPtr( hwnd ))) return;
1084

1085
    if (data->managed && (win->dwStyle & WS_VISIBLE) && (win->dwStyle & WS_MINIMIZE))
1086
    {
1087 1088 1089
        int x, y;
        unsigned int width, height, border, depth;
        Window root, top;
1090
        RECT rect;
1091
        LONG style = WS_VISIBLE;
1092

1093 1094
        /* FIXME: hack */
        wine_tsx11_lock();
1095
        XGetGeometry( event->xmap.display, data->whole_window, &root, &x, &y, &width, &height,
1096
                        &border, &depth );
1097
        XTranslateCoordinates( event->xmap.display, data->whole_window, root, 0, 0, &x, &y, &top );
1098 1099 1100 1101 1102
        wine_tsx11_unlock();
        rect.left   = x;
        rect.top    = y;
        rect.right  = x + width;
        rect.bottom = y + height;
1103
        X11DRV_X_to_window_rect( data, &rect );
1104

1105
        invalidate_dce( hwnd, &data->window_rect );
1106 1107

        if (win->flags & WIN_RESTORE_MAX) style |= WS_MAXIMIZE;
1108
        WIN_SetStyle( hwnd, style, WS_MINIMIZE );
1109 1110
        WIN_ReleasePtr( win );

1111 1112 1113 1114
        SendMessageA( hwnd, WM_SHOWWINDOW, SW_RESTORE, 0 );
        SetWindowPos( hwnd, 0, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top,
                      SWP_NOZORDER | SWP_WINE_NOHOSTMOVE );
    }
1115
    else WIN_ReleasePtr( win );
1116 1117
    if (hwndFocus && IsChild( hwnd, hwndFocus )) X11DRV_SetFocus(hwndFocus);  /* FIXME */
}
1118 1119


1120 1121
/**********************************************************************
 *              X11DRV_UnmapNotify
1122
 */
1123
void X11DRV_UnmapNotify( HWND hwnd, XEvent *event )
1124
{
1125
    struct x11drv_win_data *data;
1126
    WND *win;
1127

1128 1129
    if (!(data = X11DRV_get_win_data( hwnd ))) return;

1130
    if (!(win = WIN_GetPtr( hwnd ))) return;
1131

1132
    if ((win->dwStyle & WS_VISIBLE) && data->managed &&
1133
        X11DRV_is_window_rect_mapped( &win->rectWindow ))
1134
    {
1135 1136
        if (win->dwStyle & WS_MAXIMIZE)
            win->flags |= WIN_RESTORE_MAX;
1137 1138
        else
            win->flags &= ~WIN_RESTORE_MAX;
1139

1140
        WIN_SetStyle( hwnd, WS_MINIMIZE, WS_MAXIMIZE );
1141 1142 1143 1144
        WIN_ReleasePtr( win );

        EndMenu();
        SendMessageA( hwnd, WM_SHOWWINDOW, SW_MINIMIZE, 0 );
1145 1146 1147
        SetWindowPos( hwnd, 0, 0, 0, GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON),
                      SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER | SWP_WINE_NOHOSTMOVE );
    }
1148
    else WIN_ReleasePtr( win );
1149
}
1150 1151


1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163
/***********************************************************************
 *		X11DRV_handle_desktop_resize
 */
void X11DRV_handle_desktop_resize( unsigned int width, unsigned int height )
{
    RECT rect;
    HWND hwnd = GetDesktopWindow();

    screen_width  = width;
    screen_height = height;
    TRACE("desktop %p change to (%dx%d)\n", hwnd, width, height);
    SetRect( &rect, 0, 0, width, height );
1164
    X11DRV_set_window_pos( hwnd, 0, &rect, &rect, SWP_NOZORDER|SWP_NOMOVE|SWP_WINE_NOHOSTMOVE, NULL );
1165 1166 1167 1168 1169
    SendMessageTimeoutW( HWND_BROADCAST, WM_DISPLAYCHANGE, screen_depth,
                         MAKELPARAM( width, height ), SMTO_ABORTIFHUNG, 2000, NULL );
}


1170 1171 1172
/***********************************************************************
 *		X11DRV_ConfigureNotify
 */
1173
void X11DRV_ConfigureNotify( HWND hwnd, XEvent *xev )
1174
{
1175
    XConfigureEvent *event = &xev->xconfigure;
1176 1177
    struct x11drv_win_data *data;
    RECT rect;
1178 1179
    UINT flags;
    int cx, cy, x = event->x, y = event->y;
1180

1181
    if (!hwnd) return;
1182
    if (!(data = X11DRV_get_win_data( hwnd ))) return;
1183

1184
    /* Get geometry */
1185

1186
    if (!event->send_event)  /* normal event, need to map coordinates to the root */
1187
    {
1188 1189 1190 1191 1192 1193 1194 1195 1196 1197
        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;
1198
    TRACE( "win %p new X rect %ld,%ld,%ldx%ld (event %d,%d,%dx%d)\n",
1199 1200
           hwnd, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top,
           event->x, event->y, event->width, event->height );
1201
    X11DRV_X_to_window_rect( data, &rect );
1202

1203 1204 1205 1206 1207
    x     = rect.left;
    y     = rect.top;
    cx    = rect.right - rect.left;
    cy    = rect.bottom - rect.top;
    flags = SWP_NOACTIVATE | SWP_NOZORDER | SWP_WINE_NOHOSTMOVE;
1208

1209
    /* Compare what has changed */
1210

1211
    GetWindowRect( hwnd, &rect );
1212
    if (rect.left == x && rect.top == y) flags |= SWP_NOMOVE;
1213
    else
1214
        TRACE( "%p moving from (%ld,%ld) to (%d,%d)\n",
1215
               hwnd, rect.left, rect.top, x, y );
1216

1217
    if ((rect.right - rect.left == cx && rect.bottom - rect.top == cy) ||
1218
        IsIconic(hwnd) ||
1219
        (IsRectEmpty( &rect ) && event->width == 1 && event->height == 1))
1220 1221 1222 1223
    {
        if (flags & SWP_NOMOVE) return;  /* if nothing changed, don't do anything */
        flags |= SWP_NOSIZE;
    }
1224
    else
1225
        TRACE( "%p resizing from (%ldx%ld) to (%dx%d)\n",
1226
               hwnd, rect.right - rect.left, rect.bottom - rect.top, cx, cy );
1227

1228
    SetWindowPos( hwnd, 0, x, y, cx, cy, flags );
1229 1230 1231 1232 1233 1234 1235 1236
}


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

1241
    if (!(data = X11DRV_get_win_data( hwnd )))
1242
    {
1243
        if (IsWindow( hwnd ))
1244
            FIXME( "not supported on other thread window %p\n", hwnd );
1245 1246
        SetLastError( ERROR_INVALID_WINDOW_HANDLE );
        return FALSE;
1247 1248 1249
    }

#ifdef HAVE_LIBXSHAPE
1250
    if (data->whole_window)
1251
    {
1252
        Display *display = thread_display();
1253

1254 1255 1256 1257 1258 1259 1260 1261
        if (!hrgn)
        {
            wine_tsx11_lock();
            XShapeCombineMask( display, data->whole_window,
                               ShapeBounding, 0, 0, None, ShapeSet );
            wine_tsx11_unlock();
        }
        else
1262
        {
1263 1264
            RGNDATA *pRegionData = X11DRV_GetRegionData( hrgn, 0 );
            if (pRegionData)
1265
            {
1266
                wine_tsx11_lock();
1267 1268 1269 1270 1271 1272
                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 );
1273
                wine_tsx11_unlock();
1274
                HeapFree(GetProcessHeap(), 0, pRegionData);
1275 1276 1277 1278 1279
            }
        }
    }
#endif  /* HAVE_LIBXSHAPE */

1280
    invalidate_dce( hwnd, &data->window_rect );
1281
    return TRUE;
1282
}
1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319


/***********************************************************************
 *           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.
 */
1320
static LONG start_size_move( HWND hwnd, WPARAM wParam, POINT *capturePoint, LONG style )
1321 1322 1323 1324 1325 1326
{
    LONG hittest = 0;
    POINT pt;
    MSG msg;
    RECT rectWindow;

1327
    GetWindowRect( hwnd, &rectWindow );
1328 1329 1330 1331

    if ((wParam & 0xfff0) == SC_MOVE)
    {
        /* Move pointer at the center of the caption */
1332 1333 1334 1335 1336
        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);
1337
        if (style & WS_SYSMENU)
1338
            rect.left += GetSystemMetrics(SM_CXSIZE) + 1;
1339
        if (style & WS_MINIMIZEBOX)
1340
            rect.right -= GetSystemMetrics(SM_CXSIZE) + 1;
1341
        if (style & WS_MAXIMIZEBOX)
1342
            rect.right -= GetSystemMetrics(SM_CXSIZE) + 1;
1343 1344
        pt.x = (rect.right + rect.left) / 2;
        pt.y = rect.top + GetSystemMetrics(SM_CYSIZE)/2;
1345 1346 1347 1348 1349
        hittest = HTCAPTION;
        *capturePoint = pt;
    }
    else  /* SC_SIZE */
    {
1350
        pt.x = pt.y = 0;
1351 1352
        while(!hittest)
        {
1353 1354 1355
            GetMessageW( &msg, 0, WM_KEYFIRST, WM_MOUSELAST );
            if (CallMsgFilterW( &msg, MSGF_SIZE )) continue;

1356 1357 1358
            switch(msg.message)
            {
            case WM_MOUSEMOVE:
1359 1360 1361
                pt = msg.pt;
                hittest = SendMessageW( hwnd, WM_NCHITTEST, 0, MAKELONG( pt.x, pt.y ) );
                if ((hittest < HTLEFT) || (hittest > HTBOTTOMRIGHT)) hittest = 0;
1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397
                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 );
1398
    SendMessageW( hwnd, WM_SETCURSOR, (WPARAM)hwnd, MAKELONG( hittest, WM_MOUSEMOVE ));
1399 1400 1401 1402
    return hittest;
}


1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424
/***********************************************************************
 *           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 );
}

1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451
/***********************************************************************
 *           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 */

1452 1453 1454 1455 1456
    /* 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);
1457 1458
    wine_tsx11_unlock();
}
1459

1460
/***********************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
1461
 *           SysCommandSizeMove   (X11DRV.@)
1462 1463 1464 1465 1466 1467 1468 1469
 *
 * Perform SC_MOVE and SC_SIZE commands.
 */
void X11DRV_SysCommandSizeMove( HWND hwnd, WPARAM wParam )
{
    MSG msg;
    RECT sizingRect, mouseRect, origRect;
    HDC hdc;
1470
    HWND parent;
1471
    LONG hittest = (LONG)(wParam & 0x0f);
1472
    WPARAM syscommand = wParam & 0xfff0;
1473
    HCURSOR hDragCursor = 0, hOldCursor = 0;
1474 1475
    POINT minTrack, maxTrack;
    POINT capturePoint, pt;
1476
    LONG style = GetWindowLongA( hwnd, GWL_STYLE );
1477
    BOOL    thickframe = HAS_THICKFRAME( style );
1478
    BOOL    iconic = style & WS_MINIMIZE;
1479 1480 1481
    BOOL    moved = FALSE;
    DWORD     dwPoint = GetMessagePos ();
    BOOL DragFullWindows = FALSE;
1482
    BOOL grab;
1483
    Window parent_win, whole_win;
1484
    Display *old_gdi_display = NULL;
1485
    struct x11drv_thread_data *thread_data = x11drv_thread_data();
1486
    struct x11drv_win_data *data;
1487

1488 1489
    pt.x = (short)LOWORD(dwPoint);
    pt.y = (short)HIWORD(dwPoint);
1490 1491
    capturePoint = pt;

1492
    if (IsZoomed(hwnd) || !IsWindowVisible(hwnd)) return;
1493

1494 1495
    if (!(data = X11DRV_get_win_data( hwnd ))) return;

1496
    /* if we are managed then we let the WM do all the work */
1497
    if (data->managed)
1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527
    {
        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)
1528
    {
1529 1530
        if (!hittest) hittest = start_size_move( hwnd, wParam, &capturePoint, style );
        if (!hittest) return;
1531 1532 1533
    }
    else  /* SC_SIZE */
    {
1534
        if ( hittest && (syscommand != SC_MOUSEMENU) )
1535
            hittest += (HTLEFT - WMSZ_LEFT);
1536 1537
        else
        {
1538
            set_movesize_capture( hwnd );
1539
            hittest = start_size_move( hwnd, wParam, &capturePoint, style );
1540 1541
            if (!hittest)
            {
1542
                set_movesize_capture(0);
1543
                return;
1544 1545 1546 1547 1548 1549
            }
        }
    }

      /* Get min/max info */

1550
    WINPOS_GetMinMaxInfo( hwnd, NULL, NULL, &minTrack, &maxTrack );
1551 1552 1553 1554 1555 1556 1557 1558
    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 );
    }
1559
    else
1560 1561
    {
        parent = 0;
1562
        SetRect(&mouseRect, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));
1563 1564 1565
    }
    origRect = sizingRect;

1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585
    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 );
    }
1586
    if (parent) MapWindowPoints( parent, 0, (LPPOINT)&mouseRect, 2 );
1587

1588
    /* Retrieve a default cache DC (without using the window style) */
1589
    hdc = GetDCEx( parent, 0, DCX_CACHE );
1590 1591 1592

    if( iconic ) /* create a cursor for dragging */
    {
1593 1594
        hDragCursor = (HCURSOR)GetClassLongPtrW( hwnd, GCLP_HICON);
        if( !hDragCursor ) hDragCursor = (HCURSOR)SendMessageW( hwnd, WM_QUERYDRAGICON, 0, 0L);
1595 1596 1597 1598 1599 1600
        if( !hDragCursor ) iconic = FALSE;
    }

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

1601
    SendMessageA( hwnd, WM_ENTERSIZEMOVE, 0, 0 );
1602
    set_movesize_capture( hwnd );
1603

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

1607 1608
    if (grab)
    {
1609
        wine_tsx11_lock();
1610
        XSync( gdi_display, False );
1611 1612
        XGrabServer( thread_data->display );
        XSync( thread_data->display, False );
1613 1614
        /* switch gdi display to the thread display, since the server is grabbed */
        old_gdi_display = gdi_display;
1615
        gdi_display = thread_data->display;
1616
        wine_tsx11_unlock();
1617
    }
1618 1619
    whole_win = X11DRV_get_whole_window( GetAncestor(hwnd,GA_ROOT) );
    parent_win = parent ? X11DRV_get_whole_window( GetAncestor(parent,GA_ROOT) ) : root_window;
1620 1621

    wine_tsx11_lock();
1622
    XGrabPointer( thread_data->display, whole_win, False,
1623
                  PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
1624
                  GrabModeAsync, GrabModeAsync, parent_win, None, CurrentTime );
1625
    wine_tsx11_unlock();
1626
    thread_data->grab_window = whole_win;
1627 1628 1629 1630 1631

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

1632 1633
        if (!GetMessageW( &msg, 0, WM_KEYFIRST, WM_MOUSELAST )) break;
        if (CallMsgFilterW( &msg, MSGF_SIZE )) continue;
1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670

        /* 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 );
1671
                    WINPOS_ShowIconTitle( hwnd, FALSE );
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 1699
                }
                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);
                SendMessageA( hwnd, WM_SIZING, wpSizingHit, (LPARAM)&newRect );

                if (!iconic)
                {
                    if(!DragFullWindows)
                        draw_moving_frame( hdc, &newRect, thickframe );
1700
                    else
1701 1702 1703 1704 1705 1706 1707 1708 1709 1710
                        SetWindowPos( hwnd, 0, newRect.left, newRect.top,
                                      newRect.right - newRect.left,
                                      newRect.bottom - newRect.top,
                                      ( hittest == HTCAPTION ) ? SWP_NOSIZE : 0 );
                }
                sizingRect = newRect;
            }
        }
    }

1711
    set_movesize_capture(0);
1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722
    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 );

1723
    ReleaseDC( parent, hdc );
1724

1725
    wine_tsx11_lock();
1726
    XUngrabPointer( thread_data->display, CurrentTime );
1727 1728
    if (grab)
    {
1729 1730 1731
        XSync( thread_data->display, False );
        XUngrabServer( thread_data->display );
        XSync( thread_data->display, False );
1732 1733
        gdi_display = old_gdi_display;
    }
1734
    wine_tsx11_unlock();
1735
    thread_data->grab_window = None;
1736

1737 1738
    if (HOOK_CallHooks( WH_CBT, HCBT_MOVESIZE, (WPARAM)hwnd, (LPARAM)&sizingRect, TRUE ))
        moved = FALSE;
1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773

    SendMessageA( hwnd, WM_EXITSIZEMOVE, 0, 0 );
    SendMessageA( hwnd, WM_SETVISIBLE, !IsIconic(hwnd), 0L);

    /* 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 )
        {
1774
            if(style & WS_SYSMENU )
1775 1776 1777
                SendMessageA( hwnd, WM_SYSCOMMAND,
                              SC_MOUSEMENU + HTSYSMENU, MAKELONG(pt.x,pt.y));
        }
1778
        else WINPOS_ShowIconTitle( hwnd, TRUE );
1779 1780
    }
}