nonclient.c 53.5 KB
Newer Older
Alexandre Julliard's avatar
Alexandre Julliard committed
1 2 3 4
/*
 * Non-client area window functions
 *
 * Copyright 1994 Alexandre Julliard
Alexandre Julliard's avatar
Alexandre Julliard committed
5
 *
6 7 8 9 10 11 12 13 14 15 16 17
 * 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
18
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
Alexandre Julliard's avatar
Alexandre Julliard committed
19
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
20

21 22
#include "config.h"

23 24
#include <stdarg.h>

25
#include "windef.h"
26
#include "winbase.h"
27
#include "wingdi.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
28
#include "win.h"
29
#include "user_private.h"
30
#include "controls.h"
31
#include "wine/debug.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
32

33
WINE_DEFAULT_DEBUG_CHANNEL(nonclient);
34

35
static const BYTE lpGrayMask[] = { 0xAA, 0xA0,
36 37 38 39 40 41 42 43 44 45 46 47
                                   0x55, 0x50,
                                   0xAA, 0xA0,
                                   0x55, 0x50,
                                   0xAA, 0xA0,
                                   0x55, 0x50,
                                   0xAA, 0xA0,
                                   0x55, 0x50,
                                   0xAA, 0xA0,
                                   0x55, 0x50};

#define SC_ABOUTWINE            (SC_SCREENSAVE+1)
#define SC_PUTMARK              (SC_SCREENSAVE+2)
Alexandre Julliard's avatar
Alexandre Julliard committed
48

Alexandre Julliard's avatar
Alexandre Julliard committed
49 50
  /* Some useful macros */
#define HAS_DLGFRAME(style,exStyle) \
Alexandre Julliard's avatar
Alexandre Julliard committed
51
    (((exStyle) & WS_EX_DLGMODALFRAME) || \
52
     (((style) & WS_DLGFRAME) && !((style) & WS_THICKFRAME)))
Alexandre Julliard's avatar
Alexandre Julliard committed
53

54
#define HAS_THICKFRAME(style,exStyle) \
Alexandre Julliard's avatar
Alexandre Julliard committed
55
    (((style) & WS_THICKFRAME) && \
56
     !(((style) & (WS_DLGFRAME|WS_BORDER)) == WS_DLGFRAME))
Alexandre Julliard's avatar
Alexandre Julliard committed
57

58 59
#define HAS_THINFRAME(style) \
    (((style) & WS_BORDER) || !((style) & (WS_CHILD | WS_POPUP)))
Alexandre Julliard's avatar
Alexandre Julliard committed
60

61 62 63
#define HAS_BIGFRAME(style,exStyle) \
    (((style) & (WS_THICKFRAME | WS_DLGFRAME)) || \
     ((exStyle) & WS_EX_DLGMODALFRAME))
64

65 66 67 68
#define HAS_STATICOUTERFRAME(style,exStyle) \
    (((exStyle) & (WS_EX_STATICEDGE|WS_EX_DLGMODALFRAME)) == \
     WS_EX_STATICEDGE)

69 70 71 72
#define HAS_ANYFRAME(style,exStyle) \
    (((style) & (WS_THICKFRAME | WS_DLGFRAME | WS_BORDER)) || \
     ((exStyle) & WS_EX_DLGMODALFRAME) || \
     !((style) & (WS_CHILD | WS_POPUP)))
Alexandre Julliard's avatar
Alexandre Julliard committed
73

74
#define HAS_MENU(w)  ((((w)->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD) && ((w)->wIDmenu != 0))
Alexandre Julliard's avatar
Alexandre Julliard committed
75

76

Alexandre Julliard's avatar
Alexandre Julliard committed
77
/******************************************************************************
78
 * NC_AdjustRectOuter
Alexandre Julliard's avatar
Alexandre Julliard committed
79
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
80 81
 * Computes the size of the "outside" parts of the window based on the
 * parameters of the client area.
Alexandre Julliard's avatar
Alexandre Julliard committed
82
 *
83 84
 * PARAMS
 *     LPRECT  rect
Alexandre Julliard's avatar
Alexandre Julliard committed
85
 *     DWORD  style
86
 *     BOOL  menu
Alexandre Julliard's avatar
Alexandre Julliard committed
87
 *     DWORD  exStyle
Alexandre Julliard's avatar
Alexandre Julliard committed
88
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
89 90 91 92
 * NOTES
 *     "Outer" parts of a window means the whole window frame, caption and
 *     menu bar. It does not include "inner" parts of the frame like client
 *     edge, static edge or scroll bars.
Alexandre Julliard's avatar
Alexandre Julliard committed
93 94 95
 *
 *****************************************************************************/

Alexandre Julliard's avatar
Alexandre Julliard committed
96
static void
97
NC_AdjustRectOuter (LPRECT rect, DWORD style, BOOL menu, DWORD exStyle)
Alexandre Julliard's avatar
Alexandre Julliard committed
98
{
99
    int adjust;
Alexandre Julliard's avatar
Alexandre Julliard committed
100 101
    if(style & WS_ICONIC) return;

102
    if ((exStyle & (WS_EX_STATICEDGE|WS_EX_DLGMODALFRAME)) ==
103 104 105 106 107 108 109 110 111 112 113 114 115
        WS_EX_STATICEDGE)
    {
        adjust = 1; /* for the outer frame always present */
    }
    else
    {
        adjust = 0;
        if ((exStyle & WS_EX_DLGMODALFRAME) ||
            (style & (WS_THICKFRAME|WS_DLGFRAME))) adjust = 2; /* outer */
    }
    if (style & WS_THICKFRAME)
        adjust +=  ( GetSystemMetrics (SM_CXFRAME)
                   - GetSystemMetrics (SM_CXDLGFRAME)); /* The resize border */
116
    if ((style & (WS_BORDER|WS_DLGFRAME)) ||
117 118 119 120
        (exStyle & WS_EX_DLGMODALFRAME))
        adjust++; /* The other border */

    InflateRect (rect, adjust, adjust);
121 122

    if ((style & WS_CAPTION) == WS_CAPTION)
Alexandre Julliard's avatar
Alexandre Julliard committed
123
    {
124 125
        if (exStyle & WS_EX_TOOLWINDOW)
            rect->top -= GetSystemMetrics(SM_CYSMCAPTION);
Alexandre Julliard's avatar
Alexandre Julliard committed
126
        else
127
            rect->top -= GetSystemMetrics(SM_CYCAPTION);
Alexandre Julliard's avatar
Alexandre Julliard committed
128
    }
129
    if (menu) rect->top -= GetSystemMetrics(SM_CYMENU);
Alexandre Julliard's avatar
Alexandre Julliard committed
130 131 132 133
}


/******************************************************************************
134
 * NC_AdjustRectInner
Alexandre Julliard's avatar
Alexandre Julliard committed
135 136 137 138
 *
 * Computes the size of the "inside" part of the window based on the
 * parameters of the client area.
 *
139 140
 * PARAMS
 *     LPRECT   rect
Alexandre Julliard's avatar
Alexandre Julliard committed
141 142 143 144 145 146 147 148 149 150 151
 *     DWORD    style
 *     DWORD    exStyle
 *
 * NOTES
 *     "Inner" part of a window means the window frame inside of the flat
 *     window frame. It includes the client edge, the static edge and the
 *     scroll bars.
 *
 *****************************************************************************/

static void
152
NC_AdjustRectInner (LPRECT rect, DWORD style, DWORD exStyle)
Alexandre Julliard's avatar
Alexandre Julliard committed
153 154 155 156
{
    if(style & WS_ICONIC) return;

    if (exStyle & WS_EX_CLIENTEDGE)
157
        InflateRect(rect, GetSystemMetrics(SM_CXEDGE), GetSystemMetrics(SM_CYEDGE));
Alexandre Julliard's avatar
Alexandre Julliard committed
158

159 160 161 162 163 164 165
    if (style & WS_VSCROLL)
    {
        if((exStyle & WS_EX_LEFTSCROLLBAR) != 0)
            rect->left  -= GetSystemMetrics(SM_CXVSCROLL);
        else
            rect->right += GetSystemMetrics(SM_CXVSCROLL);
    }
166
    if (style & WS_HSCROLL) rect->bottom += GetSystemMetrics(SM_CYHSCROLL);
Alexandre Julliard's avatar
Alexandre Julliard committed
167 168 169
}


170 171 172

static HICON NC_IconForWindow( HWND hwnd )
{
173 174 175
    HICON hIcon = 0;
    WND *wndPtr = WIN_GetPtr( hwnd );

176
    if (wndPtr && wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
177 178 179 180 181
    {
        hIcon = wndPtr->hIconSmall;
        if (!hIcon) hIcon = wndPtr->hIcon;
        WIN_ReleasePtr( wndPtr );
    }
182 183
    if (!hIcon) hIcon = (HICON) GetClassLongPtrW( hwnd, GCLP_HICONSM );
    if (!hIcon) hIcon = (HICON) GetClassLongPtrW( hwnd, GCLP_HICON );
184 185 186 187

    /* If there is no hIcon specified and this is a modal dialog,
     * get the default one.
     */
188 189
    if (!hIcon && (GetWindowLongW( hwnd, GWL_STYLE ) & DS_MODALFRAME))
        hIcon = LoadImageW(0, (LPCWSTR)IDI_WINLOGO, IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR);
190 191 192
    return hIcon;
}

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 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253
/* Draws the bar part(ie the big rectangle) of the caption */
static void NC_DrawCaptionBar (HDC hdc, const RECT *rect, DWORD dwStyle, 
                               BOOL active, BOOL gradient)
{
    if (gradient)
    {
        TRIVERTEX vertices[6];
        DWORD colLeft = 
            GetSysColor (active ? COLOR_ACTIVECAPTION : COLOR_INACTIVECAPTION);
        DWORD colRight = 
            GetSysColor (active ? COLOR_GRADIENTACTIVECAPTION 
                                : COLOR_GRADIENTINACTIVECAPTION);
        int v;
        int buttonsAreaSize = GetSystemMetrics(SM_CYCAPTION) - 1;
        static GRADIENT_RECT mesh[] = {{0, 1}, {2, 3}, {4, 5}};
    
        for (v = 0; v < 3; v++)
        {
            vertices[v].Red = GetRValue (colLeft) << 8;
            vertices[v].Green = GetGValue (colLeft) << 8;
            vertices[v].Blue = GetBValue (colLeft) << 8;
            vertices[v].Alpha = 0x8000;
            vertices[v+3].Red = GetRValue (colRight) << 8;
            vertices[v+3].Green = GetGValue (colRight) << 8;
            vertices[v+3].Blue = GetBValue (colRight) << 8;
            vertices[v+3].Alpha = 0x8000;
        }
    
        if ((dwStyle & WS_SYSMENU) 
            && ((dwStyle & WS_MAXIMIZEBOX) || (dwStyle & WS_MINIMIZEBOX)))
            buttonsAreaSize += 2 * (GetSystemMetrics(SM_CXSIZE) + 1);
        
        /* area behind icon; solid filled with left color */
        vertices[0].x = rect->left;
        vertices[0].y = rect->top;
        if (dwStyle & WS_SYSMENU) 
            vertices[1].x = 
                min (rect->left + GetSystemMetrics(SM_CXSMICON), rect->right);
        else
            vertices[1].x = vertices[0].x;
        vertices[1].y = rect->bottom;
        
        /* area behind text; gradient */
        vertices[2].x = vertices[1].x;
        vertices[2].y = rect->top;
        vertices[3].x = max (vertices[2].x, rect->right - buttonsAreaSize);
        vertices[3].y = rect->bottom;
        
        /* area behind buttons; solid filled with right color */
        vertices[4].x = vertices[3].x;
        vertices[4].y = rect->top;
        vertices[5].x = rect->right;
        vertices[5].y = rect->bottom;
        
        GdiGradientFill (hdc, vertices, 6, mesh, 3, GRADIENT_FILL_RECT_H);
    }
    else
        FillRect (hdc, rect, GetSysColorBrush (active ?
                  COLOR_ACTIVECAPTION : COLOR_INACTIVECAPTION));
}

254
/***********************************************************************
255
 *		DrawCaption (USER32.@) Draws a caption bar
256 257 258 259 260 261 262
 *
 * PARAMS
 *     hwnd   [I]
 *     hdc    [I]
 *     lpRect [I]
 *     uFlags [I]
 *
263 264 265
 * RETURNS
 *     Success:
 *     Failure:
266 267
 */

268 269
BOOL WINAPI
DrawCaption (HWND hwnd, HDC hdc, const RECT *lpRect, UINT uFlags)
270
{
271
    return DrawCaptionTempW (hwnd, hdc, lpRect, 0, 0, NULL, uFlags & 0x103F);
272 273 274 275
}


/***********************************************************************
276
 *		DrawCaptionTempA (USER32.@)
277
 */
278 279 280 281 282 283
BOOL WINAPI DrawCaptionTempA (HWND hwnd, HDC hdc, const RECT *rect, HFONT hFont,
                              HICON hIcon, LPCSTR str, UINT uFlags)
{
    LPWSTR strW;
    INT len;
    BOOL ret = FALSE;
284

285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303
    if (!(uFlags & DC_TEXT) || !str)
        return DrawCaptionTempW( hwnd, hdc, rect, hFont, hIcon, NULL, uFlags );

    len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
    if ((strW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
    {
        MultiByteToWideChar( CP_ACP, 0, str, -1, strW, len );
        ret = DrawCaptionTempW (hwnd, hdc, rect, hFont, hIcon, strW, uFlags);
        HeapFree( GetProcessHeap (), 0, strW );
    }
    return ret;
}


/***********************************************************************
 *		DrawCaptionTempW (USER32.@)
 */
BOOL WINAPI DrawCaptionTempW (HWND hwnd, HDC hdc, const RECT *rect, HFONT hFont,
                              HICON hIcon, LPCWSTR str, UINT uFlags)
304
{
305
    RECT   rc = *rect;
306

307
    TRACE("(%p,%p,%p,%p,%p,%s,%08x)\n",
308
          hwnd, hdc, rect, hFont, hIcon, debugstr_w(str), uFlags);
309 310 311

    /* drawing background */
    if (uFlags & DC_INBUTTON) {
312 313 314 315 316 317 318 319
        FillRect (hdc, &rc, GetSysColorBrush (COLOR_3DFACE));

        if (uFlags & DC_ACTIVE) {
            HBRUSH hbr = SelectObject (hdc, SYSCOLOR_55AABrush);
            PatBlt (hdc, rc.left, rc.top,
                      rc.right-rc.left, rc.bottom-rc.top, 0xFA0089);
            SelectObject (hdc, hbr);
        }
320 321
    }
    else {
322 323
        DWORD style = GetWindowLongW (hwnd, GWL_STYLE);
        NC_DrawCaptionBar (hdc, rect, style, uFlags & DC_ACTIVE, uFlags & DC_GRADIENT);
324 325 326 327 328
    }


    /* drawing icon */
    if ((uFlags & DC_ICON) && !(uFlags & DC_SMALLCAP)) {
329
        POINT pt;
330

331 332
        pt.x = rc.left + 2;
        pt.y = (rc.bottom + rc.top - GetSystemMetrics(SM_CYSMICON)) / 2;
333

334 335 336
        if (!hIcon) hIcon = NC_IconForWindow(hwnd);
        DrawIconEx (hdc, pt.x, pt.y, hIcon, GetSystemMetrics(SM_CXSMICON),
                    GetSystemMetrics(SM_CYSMICON), 0, 0, DI_NORMAL);
337
        rc.left += (rc.bottom - rc.top);
338 339 340 341
    }

    /* drawing text */
    if (uFlags & DC_TEXT) {
342
        HFONT hOldFont;
343

344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379
        if (uFlags & DC_INBUTTON)
            SetTextColor (hdc, GetSysColor (COLOR_BTNTEXT));
        else if (uFlags & DC_ACTIVE)
            SetTextColor (hdc, GetSysColor (COLOR_CAPTIONTEXT));
        else
            SetTextColor (hdc, GetSysColor (COLOR_INACTIVECAPTIONTEXT));

        SetBkMode (hdc, TRANSPARENT);

        if (hFont)
            hOldFont = SelectObject (hdc, hFont);
        else {
            NONCLIENTMETRICSW nclm;
            HFONT hNewFont;
            nclm.cbSize = sizeof(NONCLIENTMETRICSW);
            SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, 0, &nclm, 0);
            hNewFont = CreateFontIndirectW ((uFlags & DC_SMALLCAP) ?
                &nclm.lfSmCaptionFont : &nclm.lfCaptionFont);
            hOldFont = SelectObject (hdc, hNewFont);
        }

        if (str)
            DrawTextW (hdc, str, -1, &rc,
                         DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX | DT_LEFT);
        else {
            WCHAR szText[128];
            INT nLen;
            nLen = GetWindowTextW (hwnd, szText, 128);
            DrawTextW (hdc, szText, nLen, &rc,
                         DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX | DT_LEFT);
        }

        if (hFont)
            SelectObject (hdc, hOldFont);
        else
            DeleteObject (SelectObject (hdc, hOldFont));
380 381 382 383
    }

    /* drawing focus ??? */
    if (uFlags & 0x2000)
384
        FIXME("undocumented flag (0x2000)!\n");
385 386 387 388 389

    return 0;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
390
/***********************************************************************
391
 *		AdjustWindowRect (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
392
 */
393
BOOL WINAPI AdjustWindowRect( LPRECT rect, DWORD style, BOOL menu )
Alexandre Julliard's avatar
Alexandre Julliard committed
394
{
395
    return AdjustWindowRectEx( rect, style, menu, 0 );
Alexandre Julliard's avatar
Alexandre Julliard committed
396 397 398
}


399 400 401 402 403 404
/***********************************************************************
 *		AdjustWindowRectEx (USER32.@)
 */
BOOL WINAPI AdjustWindowRectEx( LPRECT rect, DWORD style, BOOL menu, DWORD exStyle )
{
    /* Correct the window style */
Alexandre Julliard's avatar
Alexandre Julliard committed
405
    style &= (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME | WS_CHILD);
Alexandre Julliard's avatar
Alexandre Julliard committed
406
    exStyle &= (WS_EX_DLGMODALFRAME | WS_EX_CLIENTEDGE |
407
                WS_EX_STATICEDGE | WS_EX_TOOLWINDOW);
Alexandre Julliard's avatar
Alexandre Julliard committed
408 409
    if (exStyle & WS_EX_DLGMODALFRAME) style &= ~WS_THICKFRAME;

410
    TRACE("(%d,%d)-(%d,%d) %08x %d %08x\n",
411 412
          rect->left, rect->top, rect->right, rect->bottom,
          style, menu, exStyle );
Alexandre Julliard's avatar
Alexandre Julliard committed
413

414 415 416
    NC_AdjustRectOuter( rect, style, menu, exStyle );
    NC_AdjustRectInner( rect, style, exStyle );

Alexandre Julliard's avatar
Alexandre Julliard committed
417
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
418 419 420 421 422 423 424 425
}


/***********************************************************************
 *           NC_HandleNCCalcSize
 *
 * Handle a WM_NCCALCSIZE message. Called from DefWindowProc().
 */
426
LRESULT NC_HandleNCCalcSize( HWND hwnd, RECT *winRect )
Alexandre Julliard's avatar
Alexandre Julliard committed
427
{
428
    RECT tmpRect = { 0, 0, 0, 0 };
429
    LRESULT result = 0;
430 431 432
    LONG cls_style = GetClassLongW(hwnd, GCL_STYLE);
    LONG style = GetWindowLongW( hwnd, GWL_STYLE );
    LONG exStyle = GetWindowLongW( hwnd, GWL_EXSTYLE );
Alexandre Julliard's avatar
Alexandre Julliard committed
433

434 435
    if (cls_style & CS_VREDRAW) result |= WVR_VREDRAW;
    if (cls_style & CS_HREDRAW) result |= WVR_HREDRAW;
Alexandre Julliard's avatar
Alexandre Julliard committed
436

437 438
    if (!IsIconic(hwnd))
    {
439
        NC_AdjustRectOuter( &tmpRect, style, FALSE, exStyle );
Alexandre Julliard's avatar
Alexandre Julliard committed
440

441 442 443 444
        winRect->left   -= tmpRect.left;
        winRect->top    -= tmpRect.top;
        winRect->right  -= tmpRect.right;
        winRect->bottom -= tmpRect.bottom;
Alexandre Julliard's avatar
Alexandre Julliard committed
445

446
        if (((style & (WS_CHILD | WS_POPUP)) != WS_CHILD) && GetMenu(hwnd))
447
        {
448
            TRACE("Calling GetMenuBarHeight with hwnd %p, width %d, at (%d, %d).\n",
449
                  hwnd, winRect->right - winRect->left, -tmpRect.left, -tmpRect.top );
Alexandre Julliard's avatar
Alexandre Julliard committed
450

451 452 453
            winRect->top +=
                MENU_GetMenuBarHeight( hwnd,
                                       winRect->right - winRect->left,
454
                                       -tmpRect.left, -tmpRect.top );
455
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
456

457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473
        if( exStyle & WS_EX_CLIENTEDGE)
            if( winRect->right - winRect->left > 2 * GetSystemMetrics(SM_CXEDGE) &&
                   winRect->bottom - winRect->top > 2 * GetSystemMetrics(SM_CYEDGE))
                InflateRect( winRect, - GetSystemMetrics(SM_CXEDGE),
                        - GetSystemMetrics(SM_CYEDGE));

        if (style & WS_VSCROLL)
            if( winRect->right - winRect->left >= GetSystemMetrics(SM_CXVSCROLL)){
                if((exStyle & WS_EX_LEFTSCROLLBAR) != 0)
                    winRect->left  += GetSystemMetrics(SM_CXVSCROLL);
                else
                    winRect->right -= GetSystemMetrics(SM_CXVSCROLL);
            }

        if (style & WS_HSCROLL)
            if( winRect->bottom - winRect->top > GetSystemMetrics(SM_CYHSCROLL))
                    winRect->bottom -= GetSystemMetrics(SM_CYHSCROLL);
474 475 476 477 478 479

        if (winRect->top > winRect->bottom)
            winRect->bottom = winRect->top;

        if (winRect->left > winRect->right)
            winRect->right = winRect->left;
Alexandre Julliard's avatar
Alexandre Julliard committed
480
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
481
    return result;
Alexandre Julliard's avatar
Alexandre Julliard committed
482 483 484 485
}


/***********************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
486
 *           NC_GetInsideRect
Alexandre Julliard's avatar
Alexandre Julliard committed
487
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
488 489 490
 * Get the 'inside' rectangle of a window, i.e. the whole window rectangle
 * but without the borders (if any).
 * The rectangle is in window coordinates (for drawing with GetWindowDC()).
Alexandre Julliard's avatar
Alexandre Julliard committed
491
 */
492
static void NC_GetInsideRect( HWND hwnd, RECT *rect )
Alexandre Julliard's avatar
Alexandre Julliard committed
493
{
494 495
    WND *wndPtr = WIN_GetPtr( hwnd );

496
    if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return;
Alexandre Julliard's avatar
Alexandre Julliard committed
497 498 499 500 501

    rect->top    = rect->left = 0;
    rect->right  = wndPtr->rectWindow.right - wndPtr->rectWindow.left;
    rect->bottom = wndPtr->rectWindow.bottom - wndPtr->rectWindow.top;

502
    if (wndPtr->dwStyle & WS_ICONIC) goto END;
Alexandre Julliard's avatar
Alexandre Julliard committed
503

Alexandre Julliard's avatar
Alexandre Julliard committed
504
    /* Remove frame from rectangle */
505
    if (HAS_THICKFRAME( wndPtr->dwStyle, wndPtr->dwExStyle ))
Alexandre Julliard's avatar
Alexandre Julliard committed
506
    {
507
        InflateRect( rect, -GetSystemMetrics(SM_CXFRAME), -GetSystemMetrics(SM_CYFRAME) );
Alexandre Julliard's avatar
Alexandre Julliard committed
508
    }
509
    else if (HAS_DLGFRAME( wndPtr->dwStyle, wndPtr->dwExStyle ))
Alexandre Julliard's avatar
Alexandre Julliard committed
510
    {
511
        InflateRect( rect, -GetSystemMetrics(SM_CXDLGFRAME), -GetSystemMetrics(SM_CYDLGFRAME));
Alexandre Julliard's avatar
Alexandre Julliard committed
512
    }
513
    else if (HAS_THINFRAME( wndPtr->dwStyle ))
Alexandre Julliard's avatar
Alexandre Julliard committed
514
    {
515
        InflateRect( rect, -GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER) );
Alexandre Julliard's avatar
Alexandre Julliard committed
516 517
    }

518 519
    /* We have additional border information if the window
     * is a child (but not an MDI child) */
520 521
    if ( (wndPtr->dwStyle & WS_CHILD)  &&
         ( (wndPtr->dwExStyle & WS_EX_MDICHILD) == 0 ) )
522
    {
523 524 525 526
        if (wndPtr->dwExStyle & WS_EX_CLIENTEDGE)
            InflateRect (rect, -GetSystemMetrics(SM_CXEDGE), -GetSystemMetrics(SM_CYEDGE));
        if (wndPtr->dwExStyle & WS_EX_STATICEDGE)
            InflateRect (rect, -GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER));
Alexandre Julliard's avatar
Alexandre Julliard committed
527
    }
528

529
END:
530
    WIN_ReleasePtr( wndPtr );
Alexandre Julliard's avatar
Alexandre Julliard committed
531 532 533
}


Alexandre Julliard's avatar
Alexandre Julliard committed
534
/***********************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
535
 * NC_DoNCHitTest
Alexandre Julliard's avatar
Alexandre Julliard committed
536
 *
Andreas Mohr's avatar
Andreas Mohr committed
537
 * Handle a WM_NCHITTEST message. Called from NC_HandleNCHitTest().
Alexandre Julliard's avatar
Alexandre Julliard committed
538
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
539
 * FIXME:  Just a modified copy of the Win 3.1 version.
Alexandre Julliard's avatar
Alexandre Julliard committed
540 541
 */

542
static LRESULT NC_DoNCHitTest (WND *wndPtr, POINT pt )
Alexandre Julliard's avatar
Alexandre Julliard committed
543
{
544 545
    RECT rect, rcClient;
    POINT ptClient;
Alexandre Julliard's avatar
Alexandre Julliard committed
546

547
    TRACE("hwnd=%p pt=%d,%d\n", wndPtr->hwndSelf, pt.x, pt.y );
Alexandre Julliard's avatar
Alexandre Julliard committed
548

549 550
    GetWindowRect(wndPtr->hwndSelf, &rect );
    if (!PtInRect( &rect, pt )) return HTNOWHERE;
Alexandre Julliard's avatar
Alexandre Julliard committed
551 552 553

    if (wndPtr->dwStyle & WS_MINIMIZE) return HTCAPTION;

554 555 556 557 558 559
    /* Check client area */
    ptClient = pt;
    ScreenToClient( wndPtr->hwndSelf, &ptClient );
    GetClientRect( wndPtr->hwndSelf, &rcClient );
    if (PtInRect( &rcClient, ptClient )) return HTCLIENT;

560 561
    /* Check borders */
    if (HAS_THICKFRAME( wndPtr->dwStyle, wndPtr->dwExStyle ))
Alexandre Julliard's avatar
Alexandre Julliard committed
562
    {
563 564
        InflateRect( &rect, -GetSystemMetrics(SM_CXFRAME), -GetSystemMetrics(SM_CYFRAME) );
        if (!PtInRect( &rect, pt ))
Alexandre Julliard's avatar
Alexandre Julliard committed
565
        {
566 567
            /* Check top sizing border */
            if (pt.y < rect.top)
Alexandre Julliard's avatar
Alexandre Julliard committed
568
            {
569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592
                if (pt.x < rect.left+GetSystemMetrics(SM_CXSIZE)) return HTTOPLEFT;
                if (pt.x >= rect.right-GetSystemMetrics(SM_CXSIZE)) return HTTOPRIGHT;
                return HTTOP;
            }
            /* Check bottom sizing border */
            if (pt.y >= rect.bottom)
            {
                if (pt.x < rect.left+GetSystemMetrics(SM_CXSIZE)) return HTBOTTOMLEFT;
                if (pt.x >= rect.right-GetSystemMetrics(SM_CXSIZE)) return HTBOTTOMRIGHT;
                return HTBOTTOM;
            }
            /* Check left sizing border */
            if (pt.x < rect.left)
            {
                if (pt.y < rect.top+GetSystemMetrics(SM_CYSIZE)) return HTTOPLEFT;
                if (pt.y >= rect.bottom-GetSystemMetrics(SM_CYSIZE)) return HTBOTTOMLEFT;
                return HTLEFT;
            }
            /* Check right sizing border */
            if (pt.x >= rect.right)
            {
                if (pt.y < rect.top+GetSystemMetrics(SM_CYSIZE)) return HTTOPRIGHT;
                if (pt.y >= rect.bottom-GetSystemMetrics(SM_CYSIZE)) return HTBOTTOMRIGHT;
                return HTRIGHT;
Alexandre Julliard's avatar
Alexandre Julliard committed
593 594
            }
        }
595 596 597 598 599 600 601 602 603
    }
    else  /* No thick frame */
    {
        if (HAS_DLGFRAME( wndPtr->dwStyle, wndPtr->dwExStyle ))
            InflateRect(&rect, -GetSystemMetrics(SM_CXDLGFRAME), -GetSystemMetrics(SM_CYDLGFRAME));
        else if (HAS_THINFRAME( wndPtr->dwStyle ))
            InflateRect(&rect, -GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER));
        if (!PtInRect( &rect, pt )) return HTBORDER;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
604

605
    /* Check caption */
Alexandre Julliard's avatar
Alexandre Julliard committed
606

607 608 609 610 611 612 613
    if ((wndPtr->dwStyle & WS_CAPTION) == WS_CAPTION)
    {
        if (wndPtr->dwExStyle & WS_EX_TOOLWINDOW)
            rect.top += GetSystemMetrics(SM_CYSMCAPTION) - 1;
        else
            rect.top += GetSystemMetrics(SM_CYCAPTION) - 1;
        if (!PtInRect( &rect, pt ))
Alexandre Julliard's avatar
Alexandre Julliard committed
614
        {
615 616
            BOOL min_or_max_box = (wndPtr->dwStyle & WS_MAXIMIZEBOX) ||
                                  (wndPtr->dwStyle & WS_MINIMIZEBOX);
617 618
            /* Check system menu */
            if ((wndPtr->dwStyle & WS_SYSMENU) && !(wndPtr->dwExStyle & WS_EX_TOOLWINDOW))
Alexandre Julliard's avatar
Alexandre Julliard committed
619
            {
620 621
                if (NC_IconForWindow(wndPtr->hwndSelf))
                    rect.left += GetSystemMetrics(SM_CYCAPTION) - 1;
Alexandre Julliard's avatar
Alexandre Julliard committed
622
            }
623 624 625 626 627 628 629 630 631
            if (pt.x < rect.left) return HTSYSMENU;

            /* Check close button */
            if (wndPtr->dwStyle & WS_SYSMENU)
                rect.right -= GetSystemMetrics(SM_CYCAPTION) - 1;
            if (pt.x > rect.right) return HTCLOSE;

            /* Check maximize box */
            /* In win95 there is automatically a Maximize button when there is a minimize one*/
632
            if (min_or_max_box && !(wndPtr->dwExStyle & WS_EX_TOOLWINDOW))
633 634 635 636 637
                rect.right -= GetSystemMetrics(SM_CXSIZE) + 1;
            if (pt.x > rect.right) return HTMAXBUTTON;

            /* Check minimize box */
            /* In win95 there is automatically a Maximize button when there is a Maximize one*/
638
            if (min_or_max_box && !(wndPtr->dwExStyle & WS_EX_TOOLWINDOW))
639 640 641 642
                rect.right -= GetSystemMetrics(SM_CXSIZE) + 1;

            if (pt.x > rect.right) return HTMINBUTTON;
            return HTCAPTION;
Alexandre Julliard's avatar
Alexandre Julliard committed
643 644 645
        }
    }

Alexandre Julliard's avatar
Alexandre Julliard committed
646 647 648
      /* Check vertical scroll bar */

    if (wndPtr->dwStyle & WS_VSCROLL)
Alexandre Julliard's avatar
Alexandre Julliard committed
649
    {
650
        if((wndPtr->dwExStyle & WS_EX_LEFTSCROLLBAR) != 0)
651
            rcClient.left -= GetSystemMetrics(SM_CXVSCROLL);
652
        else
653 654
            rcClient.right += GetSystemMetrics(SM_CXVSCROLL);
        if (PtInRect( &rcClient, ptClient )) return HTVSCROLL;
Alexandre Julliard's avatar
Alexandre Julliard committed
655
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
656 657 658 659

      /* Check horizontal scroll bar */

    if (wndPtr->dwStyle & WS_HSCROLL)
Alexandre Julliard's avatar
Alexandre Julliard committed
660
    {
661 662 663 664 665 666 667 668 669 670
        rcClient.bottom += GetSystemMetrics(SM_CYHSCROLL);
        if (PtInRect( &rcClient, ptClient ))
        {
            /* Check size box */
            if ((wndPtr->dwStyle & WS_VSCROLL) &&
                ((((wndPtr->dwExStyle & WS_EX_LEFTSCROLLBAR) != 0) && (ptClient.x <= rcClient.left + GetSystemMetrics(SM_CXVSCROLL))) ||
                (((wndPtr->dwExStyle & WS_EX_LEFTSCROLLBAR) == 0) && (ptClient.x >= rcClient.right - GetSystemMetrics(SM_CXVSCROLL)))))
                return HTSIZE;
            return HTHSCROLL;
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
671 672
    }

Alexandre Julliard's avatar
Alexandre Julliard committed
673 674 675
      /* Check menu bar */

    if (HAS_MENU(wndPtr))
Alexandre Julliard's avatar
Alexandre Julliard committed
676
    {
677 678
        if ((ptClient.y < 0) && (ptClient.x >= 0) && (ptClient.x < rcClient.right))
            return HTMENU;
Alexandre Julliard's avatar
Alexandre Julliard committed
679 680
    }

681
    /* Has to return HTNOWHERE if nothing was found
682 683
       Could happen when a window has a customized non client area */
    return HTNOWHERE;
Alexandre Julliard's avatar
Alexandre Julliard committed
684 685 686
}


Alexandre Julliard's avatar
Alexandre Julliard committed
687 688 689 690 691
/***********************************************************************
 * NC_HandleNCHitTest
 *
 * Handle a WM_NCHITTEST message. Called from DefWindowProc().
 */
692
LRESULT NC_HandleNCHitTest (HWND hwnd , POINT pt)
Alexandre Julliard's avatar
Alexandre Julliard committed
693
{
694
    LRESULT retvalue;
695
    WND *wndPtr = WIN_GetPtr( hwnd );
Alexandre Julliard's avatar
Alexandre Julliard committed
696

697
    if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return HTERROR;
Alexandre Julliard's avatar
Alexandre Julliard committed
698

699
    retvalue = NC_DoNCHitTest (wndPtr, pt);
700
    WIN_ReleasePtr( wndPtr );
701
    return retvalue;
Alexandre Julliard's avatar
Alexandre Julliard committed
702 703 704
}


Alexandre Julliard's avatar
Alexandre Julliard committed
705 706
/******************************************************************************
 *
707
 *   NC_DrawSysButton
Alexandre Julliard's avatar
Alexandre Julliard committed
708
 *
709
 *   Draws the system icon.
Alexandre Julliard's avatar
Alexandre Julliard committed
710 711
 *
 *****************************************************************************/
712
BOOL NC_DrawSysButton (HWND hwnd, HDC hdc, BOOL down)
Alexandre Julliard's avatar
Alexandre Julliard committed
713
{
714
    HICON hIcon = NC_IconForWindow( hwnd );
Alexandre Julliard's avatar
Alexandre Julliard committed
715

716
    if (hIcon)
Alexandre Julliard's avatar
Alexandre Julliard committed
717
    {
718 719
        RECT rect;
        NC_GetInsideRect( hwnd, &rect );
720 721 722
        DrawIconEx (hdc, rect.left + 2, rect.top + 1, hIcon,
                    GetSystemMetrics(SM_CXSMICON),
                    GetSystemMetrics(SM_CYSMICON), 0, 0, DI_NORMAL);
Alexandre Julliard's avatar
Alexandre Julliard committed
723
    }
724
    return (hIcon != 0);
Alexandre Julliard's avatar
Alexandre Julliard committed
725 726 727 728 729
}


/******************************************************************************
 *
730
 *   NC_DrawCloseButton
Alexandre Julliard's avatar
Alexandre Julliard committed
731
 *
732
 *   Draws the close button.
Alexandre Julliard's avatar
Alexandre Julliard committed
733
 *
734 735
 *   If bGrayed is true, then draw a disabled Close button
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
736 737
 *****************************************************************************/

738
static void NC_DrawCloseButton (HWND hwnd, HDC hdc, BOOL down, BOOL bGrayed)
Alexandre Julliard's avatar
Alexandre Julliard committed
739
{
740
    RECT rect;
Alexandre Julliard's avatar
Alexandre Julliard committed
741

742 743 744
    NC_GetInsideRect( hwnd, &rect );

    /* A tool window has a smaller Close button */
745
    if (GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_TOOLWINDOW)
Alexandre Julliard's avatar
Alexandre Julliard committed
746
    {
747 748 749
        INT iBmpHeight = 11; /* Windows does not use SM_CXSMSIZE and SM_CYSMSIZE   */
        INT iBmpWidth = 11;  /* it uses 11x11 for  the close button in tool window */
        INT iCaptionHeight = GetSystemMetrics(SM_CYSMCAPTION);
Alexandre Julliard's avatar
Alexandre Julliard committed
750

751 752 753 754
        rect.top = rect.top + (iCaptionHeight - 1 - iBmpHeight) / 2;
        rect.left = rect.right - (iCaptionHeight + 1 + iBmpWidth) / 2;
        rect.bottom = rect.top + iBmpHeight;
        rect.right = rect.left + iBmpWidth;
Alexandre Julliard's avatar
Alexandre Julliard committed
755
    }
756 757 758 759 760 761 762 763 764 765 766
    else
    {
        rect.left = rect.right - GetSystemMetrics(SM_CXSIZE) - 1;
        rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZE) - 1;
        rect.top += 2;
        rect.right -= 2;
    }
    DrawFrameControl( hdc, &rect, DFC_CAPTION,
                      (DFCS_CAPTIONCLOSE |
                       (down ? DFCS_PUSHED : 0) |
                       (bGrayed ? DFCS_INACTIVE : 0)) );
Alexandre Julliard's avatar
Alexandre Julliard committed
767 768 769
}

/******************************************************************************
770
 *   NC_DrawMaxButton
Alexandre Julliard's avatar
Alexandre Julliard committed
771
 *
772
 *   Draws the maximize button for windows.
773
 *   If bGrayed is true, then draw a disabled Maximize button
774
 */
775
static void NC_DrawMaxButton(HWND hwnd,HDC hdc,BOOL down, BOOL bGrayed)
Alexandre Julliard's avatar
Alexandre Julliard committed
776
{
777
    RECT rect;
778 779 780 781 782 783 784
    UINT flags;

    /* never draw maximize box when window has WS_EX_TOOLWINDOW style */
    if (GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_TOOLWINDOW)
        return;

    flags = IsZoomed(hwnd) ? DFCS_CAPTIONRESTORE : DFCS_CAPTIONMAX;
785 786

    NC_GetInsideRect( hwnd, &rect );
787
    if (GetWindowLongW( hwnd, GWL_STYLE) & WS_SYSMENU)
788 789 790 791 792 793 794 795
        rect.right -= GetSystemMetrics(SM_CXSIZE) + 1;
    rect.left = rect.right - GetSystemMetrics(SM_CXSIZE);
    rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZE) - 1;
    rect.top += 2;
    rect.right -= 2;
    if (down) flags |= DFCS_PUSHED;
    if (bGrayed) flags |= DFCS_INACTIVE;
    DrawFrameControl( hdc, &rect, DFC_CAPTION, flags );
Alexandre Julliard's avatar
Alexandre Julliard committed
796 797 798
}

/******************************************************************************
799
 *   NC_DrawMinButton
Alexandre Julliard's avatar
Alexandre Julliard committed
800
 *
801
 *   Draws the minimize button for windows.
802
 *   If bGrayed is true, then draw a disabled Minimize button
803
 */
804
static void  NC_DrawMinButton(HWND hwnd,HDC hdc,BOOL down, BOOL bGrayed)
Alexandre Julliard's avatar
Alexandre Julliard committed
805
{
806
    RECT rect;
807
    UINT flags = DFCS_CAPTIONMIN;
808
    DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
Alexandre Julliard's avatar
Alexandre Julliard committed
809

810 811 812 813
    /* never draw minimize box when window has WS_EX_TOOLWINDOW style */
    if (GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_TOOLWINDOW)
        return;

814 815 816 817 818 819 820 821 822 823 824 825
    NC_GetInsideRect( hwnd, &rect );
    if (style & WS_SYSMENU)
        rect.right -= GetSystemMetrics(SM_CXSIZE) + 1;
    if (style & (WS_MAXIMIZEBOX|WS_MINIMIZEBOX))
        rect.right -= GetSystemMetrics(SM_CXSIZE) - 2;
    rect.left = rect.right - GetSystemMetrics(SM_CXSIZE);
    rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZE) - 1;
    rect.top += 2;
    rect.right -= 2;
    if (down) flags |= DFCS_PUSHED;
    if (bGrayed) flags |= DFCS_INACTIVE;
    DrawFrameControl( hdc, &rect, DFC_CAPTION, flags );
Alexandre Julliard's avatar
Alexandre Julliard committed
826 827 828 829
}

/******************************************************************************
 *
830
 *   NC_DrawFrame
Alexandre Julliard's avatar
Alexandre Julliard committed
831 832 833 834 835
 *
 *   Draw a window frame inside the given rectangle, and update the rectangle.
 *
 *   Bugs
 *        Many.  First, just what IS a frame in Win95?  Note that the 3D look
836
 *        on the outer edge is handled by NC_DoNCPaint.  As is the inner
Alexandre Julliard's avatar
Alexandre Julliard committed
837 838 839 840 841 842 843
 *        edge.  The inner rectangle just inside the frame is handled by the
 *        Caption code.
 *
 *        In short, for most people, this function should be a nop (unless
 *        you LIKE thick borders in Win95/NT4.0 -- I've been working with
 *        them lately, but just to get this code right).  Even so, it doesn't
 *        appear to be so.  It's being worked on...
844
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
845 846
 *****************************************************************************/

847
static void  NC_DrawFrame( HDC  hdc, RECT  *rect, BOOL  active, DWORD style, DWORD exStyle)
Alexandre Julliard's avatar
Alexandre Julliard committed
848
{
849
    INT width, height;
Alexandre Julliard's avatar
Alexandre Julliard committed
850

851 852
    /* Firstly the "thick" frame */
    if (style & WS_THICKFRAME)
Alexandre Julliard's avatar
Alexandre Julliard committed
853
    {
854 855
        width = GetSystemMetrics(SM_CXFRAME) - GetSystemMetrics(SM_CXDLGFRAME);
        height = GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYDLGFRAME);
856 857

        SelectObject( hdc, GetSysColorBrush(active ? COLOR_ACTIVEBORDER :
858
                                            COLOR_INACTIVEBORDER) );
859 860 861 862 863 864 865 866 867 868 869
        /* Draw frame */
        PatBlt( hdc, rect->left, rect->top,
                  rect->right - rect->left, height, PATCOPY );
        PatBlt( hdc, rect->left, rect->top,
                  width, rect->bottom - rect->top, PATCOPY );
        PatBlt( hdc, rect->left, rect->bottom - 1,
                  rect->right - rect->left, -height, PATCOPY );
        PatBlt( hdc, rect->right - 1, rect->top,
                  -width, rect->bottom - rect->top, PATCOPY );

        InflateRect( rect, -width, -height );
Alexandre Julliard's avatar
Alexandre Julliard committed
870
    }
871 872 873 874

    /* Now the other bit of the frame */
    if ((style & (WS_BORDER|WS_DLGFRAME)) ||
        (exStyle & WS_EX_DLGMODALFRAME))
Alexandre Julliard's avatar
Alexandre Julliard committed
875
    {
876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900
        width = GetSystemMetrics(SM_CXDLGFRAME) - GetSystemMetrics(SM_CXEDGE);
        height = GetSystemMetrics(SM_CYDLGFRAME) - GetSystemMetrics(SM_CYEDGE);
        /* This should give a value of 1 that should also work for a border */

        SelectObject( hdc, GetSysColorBrush(
                      (exStyle & (WS_EX_DLGMODALFRAME|WS_EX_CLIENTEDGE)) ?
                          COLOR_3DFACE :
                      (exStyle & WS_EX_STATICEDGE) ?
                          COLOR_WINDOWFRAME :
                      (style & (WS_DLGFRAME|WS_THICKFRAME)) ?
                          COLOR_3DFACE :
                      /* else */
                          COLOR_WINDOWFRAME));

        /* Draw frame */
        PatBlt( hdc, rect->left, rect->top,
                  rect->right - rect->left, height, PATCOPY );
        PatBlt( hdc, rect->left, rect->top,
                  width, rect->bottom - rect->top, PATCOPY );
        PatBlt( hdc, rect->left, rect->bottom - 1,
                  rect->right - rect->left, -height, PATCOPY );
        PatBlt( hdc, rect->right - 1, rect->top,
                  -width, rect->bottom - rect->top, PATCOPY );

        InflateRect( rect, -width, -height );
Alexandre Julliard's avatar
Alexandre Julliard committed
901 902 903
    }
}

Alexandre Julliard's avatar
Alexandre Julliard committed
904

Alexandre Julliard's avatar
Alexandre Julliard committed
905 906
/******************************************************************************
 *
907
 *   NC_DrawCaption
Alexandre Julliard's avatar
Alexandre Julliard committed
908
 *
909
 *   Draw the window caption for windows.
Alexandre Julliard's avatar
Alexandre Julliard committed
910 911 912 913
 *   The correct pen for the window frame must be selected in the DC.
 *
 *****************************************************************************/

914 915
static void  NC_DrawCaption( HDC  hdc, RECT *rect, HWND hwnd, DWORD  style, 
                             DWORD  exStyle, BOOL active )
Alexandre Julliard's avatar
Alexandre Julliard committed
916
{
917
    RECT  r = *rect;
918
    WCHAR buffer[256];
919
    HPEN  hPrevPen;
920
    HMENU hSysMenu;
921
    BOOL gradient = FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
922

923
    hPrevPen = SelectObject( hdc, SYSCOLOR_GetPen(
924 925 926
                     ((exStyle & (WS_EX_STATICEDGE|WS_EX_CLIENTEDGE|
                                 WS_EX_DLGMODALFRAME)) == WS_EX_STATICEDGE) ?
                      COLOR_WINDOWFRAME : COLOR_3DFACE) );
927 928 929
    MoveToEx( hdc, r.left, r.bottom - 1, NULL );
    LineTo( hdc, r.right, r.bottom - 1 );
    SelectObject( hdc, hPrevPen );
Alexandre Julliard's avatar
Alexandre Julliard committed
930 931
    r.bottom--;

932 933
    SystemParametersInfoW (SPI_GETGRADIENTCAPTIONS, 0, &gradient, 0);
    NC_DrawCaptionBar (hdc, rect, style, active, gradient);
Alexandre Julliard's avatar
Alexandre Julliard committed
934

935
    if ((style & WS_SYSMENU) && !(exStyle & WS_EX_TOOLWINDOW)) {
936 937
        if (NC_DrawSysButton (hwnd, hdc, FALSE))
            r.left += GetSystemMetrics(SM_CXSMICON) + 2;
938
    }
939

940
    if (style & WS_SYSMENU)
941
    {
942
        UINT state;
943

944 945 946
        /* Go get the sysmenu */
        hSysMenu = GetSystemMenu(hwnd, FALSE);
        state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
947

948 949 950 951
        /* Draw a grayed close button if disabled or if SC_CLOSE is not there */
        NC_DrawCloseButton (hwnd, hdc, FALSE,
                            (state & (MF_DISABLED | MF_GRAYED)) || (state == 0xFFFFFFFF));
        r.right -= GetSystemMetrics(SM_CYCAPTION) - 1;
952

953 954 955 956
        if ((style & WS_MAXIMIZEBOX) || (style & WS_MINIMIZEBOX))
        {
            /* In win95 the two buttons are always there */
            /* But if the menu item is not in the menu they're disabled*/
957

958 959
            NC_DrawMaxButton( hwnd, hdc, FALSE, (!(style & WS_MAXIMIZEBOX)));
            r.right -= GetSystemMetrics(SM_CXSIZE) + 1;
960

961 962 963
            NC_DrawMinButton( hwnd, hdc, FALSE,  (!(style & WS_MINIMIZEBOX)));
            r.right -= GetSystemMetrics(SM_CXSIZE) + 1;
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
964 965
    }

966
    if (GetWindowTextW( hwnd, buffer, sizeof(buffer)/sizeof(WCHAR) ))
967
    {
968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983
        NONCLIENTMETRICSW nclm;
        HFONT hFont, hOldFont;
        nclm.cbSize = sizeof(nclm);
        SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, 0, &nclm, 0);
        if (exStyle & WS_EX_TOOLWINDOW)
            hFont = CreateFontIndirectW (&nclm.lfSmCaptionFont);
        else
            hFont = CreateFontIndirectW (&nclm.lfCaptionFont);
        hOldFont = SelectObject (hdc, hFont);
        if (active) SetTextColor( hdc, GetSysColor( COLOR_CAPTIONTEXT ) );
        else SetTextColor( hdc, GetSysColor( COLOR_INACTIVECAPTIONTEXT ) );
        SetBkMode( hdc, TRANSPARENT );
        r.left += 2;
        DrawTextW( hdc, buffer, -1, &r,
                     DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX | DT_LEFT );
        DeleteObject (SelectObject (hdc, hOldFont));
Alexandre Julliard's avatar
Alexandre Julliard committed
984 985 986 987 988
    }
}


/******************************************************************************
989
 *   NC_DoNCPaint
Alexandre Julliard's avatar
Alexandre Julliard committed
990
 *
991 992
 *   Paint the non-client area for windows.
 */
993
static void  NC_DoNCPaint( HWND  hwnd, HRGN  clip, BOOL  suppress_menupaint )
Alexandre Julliard's avatar
Alexandre Julliard committed
994
{
995
    HDC hdc;
996
    RECT rfuzz, rect, rectClip;
997
    BOOL active;
998 999 1000
    WND *wndPtr;
    DWORD dwStyle, dwExStyle;
    WORD flags;
1001
    HRGN hrgn;
1002 1003 1004 1005 1006 1007
    RECT rectClient, rectWindow;
    int has_menu;

    if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return;
    has_menu = HAS_MENU(wndPtr);
    dwStyle = wndPtr->dwStyle;
1008
    dwExStyle = wndPtr->dwExStyle;
1009 1010 1011 1012 1013
    flags = wndPtr->flags;
    rectWindow = wndPtr->rectWindow;
    WIN_ReleasePtr( wndPtr );

    if ( dwStyle & WS_MINIMIZE ||
1014
         !WIN_IsWindowDrawable( hwnd, 0 )) return; /* Nothing to do */
Alexandre Julliard's avatar
Alexandre Julliard committed
1015

1016
    active  = flags & WIN_NCACTIVATED;
Alexandre Julliard's avatar
Alexandre Julliard committed
1017

1018
    TRACE("%p %d\n", hwnd, active );
Alexandre Julliard's avatar
Alexandre Julliard committed
1019

1020 1021 1022 1023 1024
    /* MSDN docs are pretty idiotic here, they say app CAN use clipRgn in
       the call to GetDCEx implying that it is allowed not to use it either.
       However, the suggested GetDCEx(    , DCX_WINDOW | DCX_INTERSECTRGN)
       will cause clipRgn to be deleted after ReleaseDC().
       Now, how is the "system" supposed to tell what happened?
1025 1026
     */

1027 1028 1029 1030
    GetClientRect( hwnd, &rectClient );
    MapWindowPoints( hwnd, 0, (POINT *)&rectClient, 2 );
    hrgn = CreateRectRgnIndirect( &rectClient );

1031 1032 1033 1034 1035 1036
    if (clip > (HRGN)1)
    {
        CombineRgn( hrgn, clip, hrgn, RGN_DIFF );
        hdc = GetDCEx( hwnd, hrgn, DCX_USESTYLE | DCX_WINDOW | DCX_INTERSECTRGN );
    }
    else
Alexandre Julliard's avatar
Alexandre Julliard committed
1037
    {
1038
        hdc = GetDCEx( hwnd, hrgn, DCX_USESTYLE | DCX_WINDOW | DCX_EXCLUDERGN );
Alexandre Julliard's avatar
Alexandre Julliard committed
1039 1040
    }

1041 1042
    if (!hdc) return;

Alexandre Julliard's avatar
Alexandre Julliard committed
1043
    rect.top = rect.left = 0;
1044 1045
    rect.right  = rectWindow.right - rectWindow.left;
    rect.bottom = rectWindow.bottom - rectWindow.top;
1046
    GetClipBox( hdc, &rectClip );
1047

1048
    SelectObject( hdc, SYSCOLOR_GetPen(COLOR_WINDOWFRAME) );
Alexandre Julliard's avatar
Alexandre Julliard committed
1049

1050
    if (HAS_STATICOUTERFRAME(dwStyle, dwExStyle)) {
1051
        DrawEdge (hdc, &rect, BDR_SUNKENOUTER, BF_RECT | BF_ADJUST);
1052
    }
1053
    else if (HAS_BIGFRAME( dwStyle, dwExStyle)) {
1054
        DrawEdge (hdc, &rect, EDGE_RAISED, BF_RECT | BF_ADJUST);
1055
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1056

1057
    NC_DrawFrame(hdc, &rect, active, dwStyle, dwExStyle );
1058

1059
    if ((dwStyle & WS_CAPTION) == WS_CAPTION)
1060 1061
    {
        RECT  r = rect;
1062
        if (dwExStyle & WS_EX_TOOLWINDOW) {
1063 1064
            r.bottom = rect.top + GetSystemMetrics(SM_CYSMCAPTION);
            rect.top += GetSystemMetrics(SM_CYSMCAPTION);
Alexandre Julliard's avatar
Alexandre Julliard committed
1065
        }
1066 1067 1068 1069
        else {
            r.bottom = rect.top + GetSystemMetrics(SM_CYCAPTION);
            rect.top += GetSystemMetrics(SM_CYCAPTION);
        }
1070
        if( IntersectRect( &rfuzz, &r, &rectClip ) )
1071
            NC_DrawCaption(hdc, &r, hwnd, dwStyle, dwExStyle, active);
Alexandre Julliard's avatar
Alexandre Julliard committed
1072 1073
    }

1074
    if (has_menu)
Alexandre Julliard's avatar
Alexandre Julliard committed
1075
    {
1076
	RECT r = rect;
1077
	r.bottom = rect.top + GetSystemMetrics(SM_CYMENU);
1078

1079
	TRACE("Calling DrawMenuBar with rect (%d, %d)-(%d, %d)\n",
1080
              r.left, r.top, r.right, r.bottom);
Alexandre Julliard's avatar
Alexandre Julliard committed
1081

Alexandre Julliard's avatar
Alexandre Julliard committed
1082
	rect.top += MENU_DrawMenuBar( hdc, &r, hwnd, suppress_menupaint ) + 1;
Alexandre Julliard's avatar
Alexandre Julliard committed
1083 1084
    }

1085
    TRACE("After MenuBar, rect is (%d, %d)-(%d, %d).\n",
1086
          rect.left, rect.top, rect.right, rect.bottom );
Alexandre Julliard's avatar
Alexandre Julliard committed
1087

1088
    if (dwExStyle & WS_EX_CLIENTEDGE)
1089
	DrawEdge (hdc, &rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
Alexandre Julliard's avatar
Alexandre Julliard committed
1090 1091 1092

    /* Draw the scroll-bars */

1093
    if (dwStyle & WS_VSCROLL)
1094
        SCROLL_DrawScrollBar( hwnd, hdc, SB_VERT, TRUE, TRUE );
1095
    if (dwStyle & WS_HSCROLL)
1096
        SCROLL_DrawScrollBar( hwnd, hdc, SB_HORZ, TRUE, TRUE );
Alexandre Julliard's avatar
Alexandre Julliard committed
1097 1098

    /* Draw the "size-box" */
1099
    if ((dwStyle & WS_VSCROLL) && (dwStyle & WS_HSCROLL))
Alexandre Julliard's avatar
Alexandre Julliard committed
1100
    {
1101
        RECT r = rect;
1102 1103 1104 1105
        if((dwExStyle & WS_EX_LEFTSCROLLBAR) != 0)
            r.right = r.left + GetSystemMetrics(SM_CXVSCROLL) + 1;
        else
            r.left = r.right - GetSystemMetrics(SM_CXVSCROLL) + 1;
1106
        r.top  = r.bottom - GetSystemMetrics(SM_CYHSCROLL) + 1;
1107
        FillRect( hdc, &r,  GetSysColorBrush(COLOR_SCROLLBAR) );
1108
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1109

1110
    ReleaseDC( hwnd, hdc );
Alexandre Julliard's avatar
Alexandre Julliard committed
1111 1112 1113 1114
}



Alexandre Julliard's avatar
Alexandre Julliard committed
1115

Alexandre Julliard's avatar
Alexandre Julliard committed
1116 1117 1118 1119 1120
/***********************************************************************
 *           NC_HandleNCPaint
 *
 * Handle a WM_NCPAINT message. Called from DefWindowProc().
 */
1121
LRESULT NC_HandleNCPaint( HWND hwnd , HRGN clip)
Alexandre Julliard's avatar
Alexandre Julliard committed
1122
{
1123
    DWORD dwStyle = GetWindowLongW( hwnd, GWL_STYLE );
Alexandre Julliard's avatar
Alexandre Julliard committed
1124

1125
    if( dwStyle & WS_VISIBLE )
Alexandre Julliard's avatar
Alexandre Julliard committed
1126
    {
1127
	if( dwStyle & WS_MINIMIZE )
Alexandre Julliard's avatar
Alexandre Julliard committed
1128
	    WINPOS_RedrawIconTitle( hwnd );
Alexandre Julliard's avatar
Alexandre Julliard committed
1129
	else
1130
	    NC_DoNCPaint( hwnd, clip, FALSE );
Alexandre Julliard's avatar
Alexandre Julliard committed
1131
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1132 1133 1134 1135 1136
    return 0;
}


/***********************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
1137
 *           NC_HandleNCActivate
Alexandre Julliard's avatar
Alexandre Julliard committed
1138
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
1139
 * Handle a WM_NCACTIVATE message. Called from DefWindowProc().
Alexandre Julliard's avatar
Alexandre Julliard committed
1140
 */
1141
LRESULT NC_HandleNCActivate( HWND hwnd, WPARAM wParam )
Alexandre Julliard's avatar
Alexandre Julliard committed
1142
{
1143 1144 1145
    WND* wndPtr = WIN_GetPtr( hwnd );

    if (!wndPtr || wndPtr == WND_OTHER_PROCESS) return FALSE;
1146

1147 1148 1149 1150 1151
    /* Lotus Notes draws menu descriptions in the caption of its main
     * window. When it wants to restore original "system" view, it just
     * sends WM_NCACTIVATE message to itself. Any optimizations here in
     * attempt to minimize redrawings lead to a not restored caption.
     */
1152 1153 1154 1155 1156 1157 1158 1159
    if (wParam) wndPtr->flags |= WIN_NCACTIVATED;
    else wndPtr->flags &= ~WIN_NCACTIVATED;
    WIN_ReleasePtr( wndPtr );

    if (IsIconic(hwnd))
        WINPOS_RedrawIconTitle( hwnd );
    else
        NC_DoNCPaint( hwnd, (HRGN)1, FALSE );
Alexandre Julliard's avatar
Alexandre Julliard committed
1160

Alexandre Julliard's avatar
Alexandre Julliard committed
1161 1162
    return TRUE;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1163

Alexandre Julliard's avatar
Alexandre Julliard committed
1164

Alexandre Julliard's avatar
Alexandre Julliard committed
1165 1166 1167 1168 1169
/***********************************************************************
 *           NC_HandleSetCursor
 *
 * Handle a WM_SETCURSOR message. Called from DefWindowProc().
 */
1170
LRESULT NC_HandleSetCursor( HWND hwnd, WPARAM wParam, LPARAM lParam )
Alexandre Julliard's avatar
Alexandre Julliard committed
1171
{
1172
    hwnd = WIN_GetFullHandle( (HWND)wParam );
Alexandre Julliard's avatar
Alexandre Julliard committed
1173

1174
    switch((short)LOWORD(lParam))
Alexandre Julliard's avatar
Alexandre Julliard committed
1175 1176
    {
    case HTERROR:
1177 1178 1179 1180 1181 1182 1183
        {
            WORD msg = HIWORD( lParam );
            if ((msg == WM_LBUTTONDOWN) || (msg == WM_MBUTTONDOWN) ||
                (msg == WM_RBUTTONDOWN) || (msg == WM_XBUTTONDOWN))
                MessageBeep(0);
        }
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
1184 1185

    case HTCLIENT:
1186 1187 1188 1189 1190 1191
        {
            HCURSOR hCursor = (HCURSOR)GetClassLongPtrW(hwnd, GCLP_HCURSOR);
            if(hCursor) {
                SetCursor(hCursor);
                return TRUE;
            }
1192
            return FALSE;
1193
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
1194 1195 1196

    case HTLEFT:
    case HTRIGHT:
1197
        return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZEWE ) );
Alexandre Julliard's avatar
Alexandre Julliard committed
1198 1199 1200

    case HTTOP:
    case HTBOTTOM:
1201
        return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENS ) );
Alexandre Julliard's avatar
Alexandre Julliard committed
1202 1203

    case HTTOPLEFT:
1204
    case HTBOTTOMRIGHT:
1205
        return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENWSE ) );
Alexandre Julliard's avatar
Alexandre Julliard committed
1206 1207 1208

    case HTTOPRIGHT:
    case HTBOTTOMLEFT:
1209
        return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENESW ) );
Alexandre Julliard's avatar
Alexandre Julliard committed
1210 1211 1212
    }

    /* Default cursor: arrow */
1213
    return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_ARROW ) );
Alexandre Julliard's avatar
Alexandre Julliard committed
1214 1215
}

Alexandre Julliard's avatar
Alexandre Julliard committed
1216 1217 1218
/***********************************************************************
 *           NC_GetSysPopupPos
 */
1219
void NC_GetSysPopupPos( HWND hwnd, RECT* rect )
Alexandre Julliard's avatar
Alexandre Julliard committed
1220
{
1221 1222 1223
    if (IsIconic(hwnd)) GetWindowRect( hwnd, rect );
    else
    {
1224
        WND *wndPtr = WIN_GetPtr( hwnd );
1225
        if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return;
1226 1227 1228 1229

        NC_GetInsideRect( hwnd, rect );
        OffsetRect( rect, wndPtr->rectWindow.left, wndPtr->rectWindow.top);
        if (wndPtr->dwStyle & WS_CHILD)
1230
            ClientToScreen( GetParent(hwnd), (POINT *)rect );
1231 1232
        rect->right = rect->left + GetSystemMetrics(SM_CYCAPTION) - 1;
        rect->bottom = rect->top + GetSystemMetrics(SM_CYCAPTION) - 1;
1233
        WIN_ReleasePtr( wndPtr );
1234
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1235
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1236

1237
/***********************************************************************
1238
 *           NC_TrackMinMaxBox
1239 1240 1241 1242 1243 1244 1245 1246
 *
 * Track a mouse button press on the minimize or maximize box.
 *
 * The big difference between 3.1 and 95 is the disabled button state.
 * In win95 the system button can be disabled, so it can ignore the mouse
 * event.
 *
 */
1247
static void NC_TrackMinMaxBox( HWND hwnd, WORD wParam )
1248 1249 1250 1251 1252
{
    MSG msg;
    HDC hdc = GetWindowDC( hwnd );
    BOOL pressed = TRUE;
    UINT state;
1253
    DWORD wndStyle = GetWindowLongW( hwnd, GWL_STYLE);
1254 1255
    HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);

1256
    void  (*paintButton)(HWND, HDC, BOOL, BOOL);
1257 1258 1259

    if (wParam == HTMINBUTTON)
    {
1260 1261 1262
        /* If the style is not present, do nothing */
        if (!(wndStyle & WS_MINIMIZEBOX))
            return;
1263

1264 1265
        /* Check if the sysmenu item for minimize is there  */
        state = GetMenuState(hSysMenu, SC_MINIMIZE, MF_BYCOMMAND);
1266

1267
        paintButton = &NC_DrawMinButton;
1268 1269 1270
    }
    else
    {
1271 1272 1273
        /* If the style is not present, do nothing */
        if (!(wndStyle & WS_MAXIMIZEBOX))
            return;
1274

1275 1276
        /* Check if the sysmenu item for maximize is there  */
        state = GetMenuState(hSysMenu, SC_MAXIMIZE, MF_BYCOMMAND);
1277

1278
        paintButton = &NC_DrawMaxButton;
1279 1280 1281 1282 1283 1284
    }

    SetCapture( hwnd );

    (*paintButton)( hwnd, hdc, TRUE, FALSE);

1285
    while(1)
1286
    {
1287
        BOOL oldstate = pressed;
1288 1289 1290

        if (!GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST )) break;
        if (CallMsgFilterW( &msg, MSGF_MAX )) continue;
1291

1292 1293
        if(msg.message == WM_LBUTTONUP)
            break;
1294

1295 1296
        if(msg.message != WM_MOUSEMOVE)
            continue;
1297

1298 1299 1300
        pressed = (NC_HandleNCHitTest( hwnd, msg.pt ) == wParam);
        if (pressed != oldstate)
           (*paintButton)( hwnd, hdc, pressed, FALSE);
1301
    }
1302

1303
    if(pressed)
1304
        (*paintButton)(hwnd, hdc, FALSE, FALSE);
1305 1306 1307 1308 1309 1310 1311

    ReleaseCapture();
    ReleaseDC( hwnd, hdc );

    /* If the item minimize or maximize of the sysmenu are not there */
    /* or if the style is not present, do nothing */
    if ((!pressed) || (state == 0xFFFFFFFF))
1312
        return;
1313

1314
    if (wParam == HTMINBUTTON)
1315
        SendMessageW( hwnd, WM_SYSCOMMAND, SC_MINIMIZE, MAKELONG(msg.pt.x,msg.pt.y) );
1316
    else
1317
        SendMessageW( hwnd, WM_SYSCOMMAND,
1318
                      IsZoomed(hwnd) ? SC_RESTORE:SC_MAXIMIZE, MAKELONG(msg.pt.x,msg.pt.y) );
1319 1320
}

Alexandre Julliard's avatar
Alexandre Julliard committed
1321
/***********************************************************************
1322
 * NC_TrackCloseButton
Alexandre Julliard's avatar
Alexandre Julliard committed
1323 1324 1325
 *
 * Track a mouse button press on the Win95 close button.
 */
1326
static void NC_TrackCloseButton (HWND hwnd, WORD wParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
1327
{
1328
    MSG msg;
1329
    HDC hdc;
1330
    BOOL pressed = TRUE;
1331 1332 1333 1334
    HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
    UINT state;

    if(hSysMenu == 0)
1335
        return;
1336 1337

    state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
1338

1339 1340
    /* If the item close of the sysmenu is disabled or not there do nothing */
    if((state & MF_DISABLED) || (state & MF_GRAYED) || (state == 0xFFFFFFFF))
1341
        return;
1342 1343

    hdc = GetWindowDC( hwnd );
Alexandre Julliard's avatar
Alexandre Julliard committed
1344

1345
    SetCapture( hwnd );
Alexandre Julliard's avatar
Alexandre Julliard committed
1346

1347
    NC_DrawCloseButton (hwnd, hdc, TRUE, FALSE);
Alexandre Julliard's avatar
Alexandre Julliard committed
1348

1349
    while(1)
Alexandre Julliard's avatar
Alexandre Julliard committed
1350
    {
1351
        BOOL oldstate = pressed;
1352 1353 1354

        if (!GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST )) break;
        if (CallMsgFilterW( &msg, MSGF_MAX )) continue;
Alexandre Julliard's avatar
Alexandre Julliard committed
1355

1356 1357
        if(msg.message == WM_LBUTTONUP)
            break;
1358

1359 1360
        if(msg.message != WM_MOUSEMOVE)
            continue;
1361

1362 1363 1364
        pressed = (NC_HandleNCHitTest( hwnd, msg.pt ) == wParam);
        if (pressed != oldstate)
           NC_DrawCloseButton (hwnd, hdc, pressed, FALSE);
1365
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1366

1367
    if(pressed)
1368
        NC_DrawCloseButton (hwnd, hdc, FALSE, FALSE);
Alexandre Julliard's avatar
Alexandre Julliard committed
1369 1370

    ReleaseCapture();
1371
    ReleaseDC( hwnd, hdc );
Alexandre Julliard's avatar
Alexandre Julliard committed
1372 1373
    if (!pressed) return;

1374
    SendMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, MAKELONG(msg.pt.x,msg.pt.y) );
Alexandre Julliard's avatar
Alexandre Julliard committed
1375 1376 1377
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1378 1379 1380 1381 1382
/***********************************************************************
 *           NC_TrackScrollBar
 *
 * Track a mouse button press on the horizontal or vertical scroll-bar.
 */
1383
static void NC_TrackScrollBar( HWND hwnd, WPARAM wParam, POINT pt )
Alexandre Julliard's avatar
Alexandre Julliard committed
1384
{
1385
    INT scrollbar;
Alexandre Julliard's avatar
Alexandre Julliard committed
1386

Alexandre Julliard's avatar
Alexandre Julliard committed
1387 1388
    if ((wParam & 0xfff0) == SC_HSCROLL)
    {
1389
        if ((wParam & 0x0f) != HTHSCROLL) return;
Alexandre Julliard's avatar
Alexandre Julliard committed
1390 1391 1392 1393
	scrollbar = SB_HORZ;
    }
    else  /* SC_VSCROLL */
    {
1394
        if ((wParam & 0x0f) != HTVSCROLL) return;
Alexandre Julliard's avatar
Alexandre Julliard committed
1395 1396
	scrollbar = SB_VERT;
    }
1397
    SCROLL_TrackScrollBar( hwnd, scrollbar, pt );
Alexandre Julliard's avatar
Alexandre Julliard committed
1398 1399
}

1400

Alexandre Julliard's avatar
Alexandre Julliard committed
1401 1402 1403 1404 1405
/***********************************************************************
 *           NC_HandleNCLButtonDown
 *
 * Handle a WM_NCLBUTTONDOWN message. Called from DefWindowProc().
 */
1406
LRESULT NC_HandleNCLButtonDown( HWND hwnd, WPARAM wParam, LPARAM lParam )
Alexandre Julliard's avatar
Alexandre Julliard committed
1407
{
1408
    LONG style = GetWindowLongW( hwnd, GWL_STYLE );
Alexandre Julliard's avatar
Alexandre Julliard committed
1409

Alexandre Julliard's avatar
Alexandre Julliard committed
1410 1411
    switch(wParam)  /* Hit test */
    {
Alexandre Julliard's avatar
Alexandre Julliard committed
1412
    case HTCAPTION:
1413
        {
1414
            HWND top = GetAncestor( hwnd, GA_ROOT );
Alexandre Julliard's avatar
Alexandre Julliard committed
1415

1416
            if (FOCUS_MouseActivate( top ) || (GetActiveWindow() == top))
1417 1418 1419
                SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOVE + HTCAPTION, lParam );
            break;
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
1420 1421

    case HTSYSMENU:
1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432
         if( style & WS_SYSMENU )
         {
             if( !(style & WS_MINIMIZE) )
             {
                HDC hDC = GetWindowDC(hwnd);
                NC_DrawSysButton( hwnd, hDC, TRUE );
                ReleaseDC( hwnd, hDC );
             }
             SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOUSEMENU + HTSYSMENU, lParam );
         }
         break;
Alexandre Julliard's avatar
Alexandre Julliard committed
1433 1434

    case HTMENU:
1435 1436
        SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOUSEMENU, lParam );
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
1437

Alexandre Julliard's avatar
Alexandre Julliard committed
1438
    case HTHSCROLL:
1439 1440
        SendMessageW( hwnd, WM_SYSCOMMAND, SC_HSCROLL + HTHSCROLL, lParam );
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
1441

Alexandre Julliard's avatar
Alexandre Julliard committed
1442
    case HTVSCROLL:
1443 1444
        SendMessageW( hwnd, WM_SYSCOMMAND, SC_VSCROLL + HTVSCROLL, lParam );
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
1445

Alexandre Julliard's avatar
Alexandre Julliard committed
1446
    case HTMINBUTTON:
Alexandre Julliard's avatar
Alexandre Julliard committed
1447
    case HTMAXBUTTON:
1448 1449
        NC_TrackMinMaxBox( hwnd, wParam );
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
1450

Alexandre Julliard's avatar
Alexandre Julliard committed
1451
    case HTCLOSE:
1452 1453
        NC_TrackCloseButton (hwnd, wParam);
        break;
1454

Alexandre Julliard's avatar
Alexandre Julliard committed
1455 1456 1457 1458 1459 1460 1461
    case HTLEFT:
    case HTRIGHT:
    case HTTOP:
    case HTTOPLEFT:
    case HTTOPRIGHT:
    case HTBOTTOM:
    case HTBOTTOMLEFT:
Alexandre Julliard's avatar
Alexandre Julliard committed
1462
    case HTBOTTOMRIGHT:
1463 1464 1465 1466 1467 1468 1469 1470 1471
        /* Old comment:
         * "make sure hittest fits into 0xf and doesn't overlap with HTSYSMENU"
         * This was previously done by setting wParam=SC_SIZE + wParam - 2
         */
        /* But that is not what WinNT does. Instead it sends this. This
         * is easy to differentiate from HTSYSMENU, because HTSYSMENU adds
         * SC_MOUSEMENU into wParam.
         */
        SendMessageW( hwnd, WM_SYSCOMMAND, SC_SIZE + wParam - (HTLEFT-WMSZ_LEFT), lParam);
1472
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
1473 1474

    case HTBORDER:
1475
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
1476 1477 1478 1479 1480 1481 1482 1483 1484 1485
    }
    return 0;
}


/***********************************************************************
 *           NC_HandleNCLButtonDblClk
 *
 * Handle a WM_NCLBUTTONDBLCLK message. Called from DefWindowProc().
 */
1486
LRESULT NC_HandleNCLButtonDblClk( HWND hwnd, WPARAM wParam, LPARAM lParam )
Alexandre Julliard's avatar
Alexandre Julliard committed
1487
{
Alexandre Julliard's avatar
Alexandre Julliard committed
1488 1489 1490 1491
    /*
     * if this is an icon, send a restore since we are handling
     * a double click
     */
1492
    if (IsIconic(hwnd))
Alexandre Julliard's avatar
Alexandre Julliard committed
1493
    {
1494
        SendMessageW( hwnd, WM_SYSCOMMAND, SC_RESTORE, lParam );
Alexandre Julliard's avatar
Alexandre Julliard committed
1495
        return 0;
1496
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1497

Alexandre Julliard's avatar
Alexandre Julliard committed
1498 1499 1500
    switch(wParam)  /* Hit test */
    {
    case HTCAPTION:
Alexandre Julliard's avatar
Alexandre Julliard committed
1501
        /* stop processing if WS_MAXIMIZEBOX is missing */
1502
        if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_MAXIMIZEBOX)
1503 1504
            SendMessageW( hwnd, WM_SYSCOMMAND,
                          IsZoomed(hwnd) ? SC_RESTORE : SC_MAXIMIZE, lParam );
1505
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
1506 1507

    case HTSYSMENU:
1508 1509 1510
        {
            HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
            UINT state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
1511

1512 1513 1514 1515
            /* If the item close of the sysmenu is disabled or not there do nothing */
            if ((state & (MF_DISABLED | MF_GRAYED)) || (state == 0xFFFFFFFF))
                break;

1516
            SendMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, lParam );
1517 1518
            break;
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
1519 1520

    case HTHSCROLL:
1521
        SendMessageW( hwnd, WM_SYSCOMMAND, SC_HSCROLL + HTHSCROLL, lParam );
1522
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
1523 1524

    case HTVSCROLL:
1525
        SendMessageW( hwnd, WM_SYSCOMMAND, SC_VSCROLL + HTVSCROLL, lParam );
1526
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
1527 1528 1529 1530 1531 1532 1533 1534 1535 1536
    }
    return 0;
}


/***********************************************************************
 *           NC_HandleSysCommand
 *
 * Handle a WM_SYSCOMMAND message. Called from DefWindowProc().
 */
1537
LRESULT NC_HandleSysCommand( HWND hwnd, WPARAM wParam, LPARAM lParam )
Alexandre Julliard's avatar
Alexandre Julliard committed
1538
{
1539
    TRACE("hwnd %p WM_SYSCOMMAND %lx %lx\n", hwnd, wParam, lParam );
1540 1541

    if (!IsWindowEnabled( hwnd )) return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1542

1543 1544 1545
    if (HOOK_CallHooks( WH_CBT, HCBT_SYSCOMMAND, wParam, lParam, TRUE ))
        return 0;

1546
    switch (wParam & 0xfff0)
Alexandre Julliard's avatar
Alexandre Julliard committed
1547 1548 1549
    {
    case SC_SIZE:
    case SC_MOVE:
1550
        USER_Driver->pSysCommandSizeMove( hwnd, wParam );
1551
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
1552 1553

    case SC_MINIMIZE:
1554 1555
        if (hwnd == GetForegroundWindow())
            ShowOwnedPopups(hwnd,FALSE);
1556 1557
        ShowWindow( hwnd, SW_MINIMIZE );
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
1558 1559

    case SC_MAXIMIZE:
1560 1561
        if (IsIconic(hwnd) && hwnd == GetForegroundWindow())
            ShowOwnedPopups(hwnd,TRUE);
1562 1563
        ShowWindow( hwnd, SW_MAXIMIZE );
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
1564 1565

    case SC_RESTORE:
1566 1567
        if (IsIconic(hwnd) && hwnd == GetForegroundWindow())
            ShowOwnedPopups(hwnd,TRUE);
1568 1569
        ShowWindow( hwnd, SW_RESTORE );
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
1570 1571

    case SC_CLOSE:
1572
        return SendMessageW( hwnd, WM_CLOSE, 0, 0 );
Alexandre Julliard's avatar
Alexandre Julliard committed
1573 1574 1575

    case SC_VSCROLL:
    case SC_HSCROLL:
1576 1577
        {
            POINT pt;
1578 1579
            pt.x = (short)LOWORD(lParam);
            pt.y = (short)HIWORD(lParam);
1580 1581
            NC_TrackScrollBar( hwnd, wParam, pt );
        }
1582
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
1583

Alexandre Julliard's avatar
Alexandre Julliard committed
1584
    case SC_MOUSEMENU:
1585 1586
        {
            POINT pt;
1587 1588
            pt.x = (short)LOWORD(lParam);
            pt.y = (short)HIWORD(lParam);
1589 1590
            MENU_TrackMouseMenuBar( hwnd, wParam & 0x000F, pt );
        }
1591
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
1592

Alexandre Julliard's avatar
Alexandre Julliard committed
1593
    case SC_KEYMENU:
1594
        MENU_TrackKbdMenuBar( hwnd, wParam, (WCHAR)lParam );
1595
        break;
1596

Alexandre Julliard's avatar
Alexandre Julliard committed
1597
    case SC_TASKLIST:
1598 1599
        WinExec( "taskman.exe", SW_SHOWNORMAL );
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
1600 1601

    case SC_SCREENSAVE:
1602
        if (wParam == SC_ABOUTWINE)
1603 1604 1605 1606 1607
        {
            HMODULE hmodule = LoadLibraryA( "shell32.dll" );
            if (hmodule)
            {
                FARPROC aboutproc = GetProcAddress( hmodule, "ShellAboutA" );
1608
                if (aboutproc) aboutproc( hwnd, PACKAGE_NAME, PACKAGE_STRING, 0 );
1609 1610 1611
                FreeLibrary( hmodule );
            }
        }
1612 1613
        else
          if (wParam == SC_PUTMARK)
1614
            DPRINTF("Debug mark requested by user\n");
1615
        break;
1616

Alexandre Julliard's avatar
Alexandre Julliard committed
1617 1618 1619 1620
    case SC_HOTKEY:
    case SC_ARRANGE:
    case SC_NEXTWINDOW:
    case SC_PREVWINDOW:
1621
        FIXME("unimplemented WM_SYSCOMMAND %04lx!\n", wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1622
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
1623 1624 1625
    }
    return 0;
}
1626

1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638
/***********************************************************************
 *		GetTitleBarInfo (USER32.@)
 * TODO: Handle STATE_SYSTEM_PRESSED
 */
BOOL WINAPI GetTitleBarInfo(HWND hwnd, PTITLEBARINFO tbi) {
    DWORD dwStyle;
    DWORD dwExStyle;
    RECT wndRect;

    TRACE("(%p %p)\n", hwnd, tbi);

    if(tbi->cbSize != sizeof(TITLEBARINFO)) {
1639
        TRACE("Invalid TITLEBARINFO size: %d\n", tbi->cbSize);
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 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694
        SetLastError(ERROR_INVALID_PARAMETER);
        return FALSE;
    }
    dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
    dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
    NC_GetInsideRect(hwnd, &tbi->rcTitleBar);

    GetWindowRect(hwnd, &wndRect);

    tbi->rcTitleBar.top += wndRect.top;
    tbi->rcTitleBar.left += wndRect.left;
    tbi->rcTitleBar.right += wndRect.left;

    tbi->rcTitleBar.bottom = tbi->rcTitleBar.top;
    if(dwExStyle & WS_EX_TOOLWINDOW)
        tbi->rcTitleBar.bottom += GetSystemMetrics(SM_CYSMCAPTION);
    else {
        tbi->rcTitleBar.bottom += GetSystemMetrics(SM_CYCAPTION);
        tbi->rcTitleBar.left += GetSystemMetrics(SM_CXSIZE);
    }

    ZeroMemory(&tbi->rgstate, sizeof(tbi->rgstate));
    /* Does the title bar always have STATE_SYSTEM_FOCUSABLE?
     * Under XP it seems to
     */
    tbi->rgstate[0] = STATE_SYSTEM_FOCUSABLE;
    if(dwStyle & WS_CAPTION) {
        tbi->rgstate[1] = STATE_SYSTEM_INVISIBLE;
        if(dwStyle & WS_SYSMENU) {
            if(!(dwStyle & (WS_MINIMIZEBOX|WS_MAXIMIZEBOX))) {
                tbi->rgstate[2] = STATE_SYSTEM_INVISIBLE;
                tbi->rgstate[3] = STATE_SYSTEM_INVISIBLE;
            }
            else {
                if(!(dwStyle & WS_MINIMIZEBOX))
                    tbi->rgstate[2] = STATE_SYSTEM_UNAVAILABLE;
                if(!(dwStyle & WS_MAXIMIZEBOX))
                    tbi->rgstate[3] = STATE_SYSTEM_UNAVAILABLE;
            }
            if(!(dwExStyle & WS_EX_CONTEXTHELP))
                tbi->rgstate[4] = STATE_SYSTEM_INVISIBLE;
            if(GetClassLongW(hwnd, GCL_STYLE) & CS_NOCLOSE)
                tbi->rgstate[5] = STATE_SYSTEM_UNAVAILABLE;
        }
        else {
            tbi->rgstate[2] = STATE_SYSTEM_INVISIBLE;
            tbi->rgstate[3] = STATE_SYSTEM_INVISIBLE;
            tbi->rgstate[4] = STATE_SYSTEM_INVISIBLE;
            tbi->rgstate[5] = STATE_SYSTEM_INVISIBLE;
        }
    }
    else
        tbi->rgstate[0] |= STATE_SYSTEM_INVISIBLE;
    return TRUE;
}