nonclient.c 54.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"
28
#include "winnls.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
29
#include "win.h"
30
#include "user_private.h"
31
#include "controls.h"
32
#include "wine/debug.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
33

34
WINE_DEFAULT_DEBUG_CHANNEL(nonclient);
35

36
#define SC_ABOUTWINE            (SC_SCREENSAVE+1)
Alexandre Julliard's avatar
Alexandre Julliard committed
37

Alexandre Julliard's avatar
Alexandre Julliard committed
38 39
  /* Some useful macros */
#define HAS_DLGFRAME(style,exStyle) \
Alexandre Julliard's avatar
Alexandre Julliard committed
40
    (((exStyle) & WS_EX_DLGMODALFRAME) || \
41
     (((style) & WS_DLGFRAME) && !((style) & WS_THICKFRAME)))
Alexandre Julliard's avatar
Alexandre Julliard committed
42

43
#define HAS_THICKFRAME(style,exStyle) \
Alexandre Julliard's avatar
Alexandre Julliard committed
44
    (((style) & WS_THICKFRAME) && \
45
     !(((style) & (WS_DLGFRAME|WS_BORDER)) == WS_DLGFRAME))
Alexandre Julliard's avatar
Alexandre Julliard committed
46

47 48
#define HAS_THINFRAME(style) \
    (((style) & WS_BORDER) || !((style) & (WS_CHILD | WS_POPUP)))
Alexandre Julliard's avatar
Alexandre Julliard committed
49

50 51 52
#define HAS_BIGFRAME(style,exStyle) \
    (((style) & (WS_THICKFRAME | WS_DLGFRAME)) || \
     ((exStyle) & WS_EX_DLGMODALFRAME))
53

54 55 56 57
#define HAS_STATICOUTERFRAME(style,exStyle) \
    (((exStyle) & (WS_EX_STATICEDGE|WS_EX_DLGMODALFRAME)) == \
     WS_EX_STATICEDGE)

58 59 60 61
#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
62

63
#define HAS_MENU(hwnd,style)  ((((style) & (WS_CHILD | WS_POPUP)) != WS_CHILD) && GetMenu(hwnd))
Alexandre Julliard's avatar
Alexandre Julliard committed
64

65

Alexandre Julliard's avatar
Alexandre Julliard committed
66
/******************************************************************************
67
 * NC_AdjustRectOuter
Alexandre Julliard's avatar
Alexandre Julliard committed
68
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
69 70
 * 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
71
 *
72 73
 * PARAMS
 *     LPRECT  rect
Alexandre Julliard's avatar
Alexandre Julliard committed
74
 *     DWORD  style
75
 *     BOOL  menu
Alexandre Julliard's avatar
Alexandre Julliard committed
76
 *     DWORD  exStyle
Alexandre Julliard's avatar
Alexandre Julliard committed
77
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
78 79 80 81
 * 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
82 83 84
 *
 *****************************************************************************/

Alexandre Julliard's avatar
Alexandre Julliard committed
85
static void
86
NC_AdjustRectOuter (LPRECT rect, DWORD style, BOOL menu, DWORD exStyle)
Alexandre Julliard's avatar
Alexandre Julliard committed
87
{
88
    int adjust;
Alexandre Julliard's avatar
Alexandre Julliard committed
89

90
    if ((exStyle & (WS_EX_STATICEDGE|WS_EX_DLGMODALFRAME)) ==
91 92 93 94 95 96 97 98 99 100
        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 */
    }
101
    if ((style & WS_THICKFRAME) && !(exStyle & WS_EX_DLGMODALFRAME))
102 103
        adjust +=  ( GetSystemMetrics (SM_CXFRAME)
                   - GetSystemMetrics (SM_CXDLGFRAME)); /* The resize border */
104
    if ((style & (WS_BORDER|WS_DLGFRAME)) ||
105 106 107 108
        (exStyle & WS_EX_DLGMODALFRAME))
        adjust++; /* The other border */

    InflateRect (rect, adjust, adjust);
109 110

    if ((style & WS_CAPTION) == WS_CAPTION)
Alexandre Julliard's avatar
Alexandre Julliard committed
111
    {
112 113
        if (exStyle & WS_EX_TOOLWINDOW)
            rect->top -= GetSystemMetrics(SM_CYSMCAPTION);
Alexandre Julliard's avatar
Alexandre Julliard committed
114
        else
115
            rect->top -= GetSystemMetrics(SM_CYCAPTION);
Alexandre Julliard's avatar
Alexandre Julliard committed
116
    }
117
    if (menu) rect->top -= GetSystemMetrics(SM_CYMENU);
Alexandre Julliard's avatar
Alexandre Julliard committed
118 119 120 121
}


/******************************************************************************
122
 * NC_AdjustRectInner
Alexandre Julliard's avatar
Alexandre Julliard committed
123 124 125 126
 *
 * Computes the size of the "inside" part of the window based on the
 * parameters of the client area.
 *
127 128
 * PARAMS
 *     LPRECT   rect
Alexandre Julliard's avatar
Alexandre Julliard committed
129 130 131 132 133 134 135 136 137 138 139
 *     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
140
NC_AdjustRectInner (LPRECT rect, DWORD style, DWORD exStyle)
Alexandre Julliard's avatar
Alexandre Julliard committed
141 142
{
    if (exStyle & WS_EX_CLIENTEDGE)
143
        InflateRect(rect, GetSystemMetrics(SM_CXEDGE), GetSystemMetrics(SM_CYEDGE));
Alexandre Julliard's avatar
Alexandre Julliard committed
144

145 146 147 148 149 150 151
    if (style & WS_VSCROLL)
    {
        if((exStyle & WS_EX_LEFTSCROLLBAR) != 0)
            rect->left  -= GetSystemMetrics(SM_CXVSCROLL);
        else
            rect->right += GetSystemMetrics(SM_CXVSCROLL);
    }
152
    if (style & WS_HSCROLL) rect->bottom += GetSystemMetrics(SM_CYHSCROLL);
Alexandre Julliard's avatar
Alexandre Julliard committed
153 154 155
}


156 157 158

static HICON NC_IconForWindow( HWND hwnd )
{
159 160 161
    HICON hIcon = 0;
    WND *wndPtr = WIN_GetPtr( hwnd );

162
    if (wndPtr && wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
163 164 165 166 167
    {
        hIcon = wndPtr->hIconSmall;
        if (!hIcon) hIcon = wndPtr->hIcon;
        WIN_ReleasePtr( wndPtr );
    }
168 169
    if (!hIcon) hIcon = (HICON) GetClassLongPtrW( hwnd, GCLP_HICONSM );
    if (!hIcon) hIcon = (HICON) GetClassLongPtrW( hwnd, GCLP_HICON );
170 171 172 173

    /* If there is no hIcon specified and this is a modal dialog,
     * get the default one.
     */
174 175
    if (!hIcon && (GetWindowLongW( hwnd, GWL_STYLE ) & DS_MODALFRAME))
        hIcon = LoadImageW(0, (LPCWSTR)IDI_WINLOGO, IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR);
176 177 178
    return hIcon;
}

179 180 181 182 183 184
/* 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)
    {
185
        TRIVERTEX vertices[4];
186 187 188 189 190 191
        DWORD colLeft = 
            GetSysColor (active ? COLOR_ACTIVECAPTION : COLOR_INACTIVECAPTION);
        DWORD colRight = 
            GetSysColor (active ? COLOR_GRADIENTACTIVECAPTION 
                                : COLOR_GRADIENTINACTIVECAPTION);
        int buttonsAreaSize = GetSystemMetrics(SM_CYCAPTION) - 1;
192 193 194 195 196 197 198 199 200 201 202 203
        static GRADIENT_RECT mesh[] = {{0, 1}, {1, 2}, {2, 3}};

        vertices[0].Red   = vertices[1].Red   = GetRValue (colLeft) << 8;
        vertices[0].Green = vertices[1].Green = GetGValue (colLeft) << 8;
        vertices[0].Blue  = vertices[1].Blue  = GetBValue (colLeft) << 8;
        vertices[0].Alpha = vertices[1].Alpha = 0xff00;
        vertices[2].Red   = vertices[3].Red   = GetRValue (colRight) << 8;
        vertices[2].Green = vertices[3].Green = GetGValue (colRight) << 8;
        vertices[2].Blue  = vertices[3].Blue  = GetBValue (colRight) << 8;
        vertices[2].Alpha = vertices[3].Alpha = 0xff00;

        if ((dwStyle & WS_SYSMENU)
204 205
            && ((dwStyle & WS_MAXIMIZEBOX) || (dwStyle & WS_MINIMIZEBOX)))
            buttonsAreaSize += 2 * (GetSystemMetrics(SM_CXSIZE) + 1);
206

207 208 209
        /* area behind icon; solid filled with left color */
        vertices[0].x = rect->left;
        vertices[0].y = rect->top;
210 211
        if (dwStyle & WS_SYSMENU)
            vertices[1].x = min (rect->left + GetSystemMetrics(SM_CXSMICON), rect->right);
212 213 214
        else
            vertices[1].x = vertices[0].x;
        vertices[1].y = rect->bottom;
215

216
        /* area behind text; gradient */
217
        vertices[2].x = max (vertices[1].x, rect->right - buttonsAreaSize);
218
        vertices[2].y = rect->top;
219

220
        /* area behind buttons; solid filled with right color */
221 222 223 224
        vertices[3].x = rect->right;
        vertices[3].y = rect->bottom;

        GdiGradientFill (hdc, vertices, 4, mesh, 3, GRADIENT_FILL_RECT_H);
225 226 227 228 229 230
    }
    else
        FillRect (hdc, rect, GetSysColorBrush (active ?
                  COLOR_ACTIVECAPTION : COLOR_INACTIVECAPTION));
}

231
/***********************************************************************
232
 *		DrawCaption (USER32.@) Draws a caption bar
233 234 235 236 237 238 239
 *
 * PARAMS
 *     hwnd   [I]
 *     hdc    [I]
 *     lpRect [I]
 *     uFlags [I]
 *
240 241 242
 * RETURNS
 *     Success:
 *     Failure:
243 244
 */

245 246
BOOL WINAPI
DrawCaption (HWND hwnd, HDC hdc, const RECT *lpRect, UINT uFlags)
247
{
248
    return DrawCaptionTempW (hwnd, hdc, lpRect, 0, 0, NULL, uFlags & 0x103F);
249 250 251 252
}


/***********************************************************************
253
 *		DrawCaptionTempA (USER32.@)
254
 */
255 256 257 258 259 260
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;
261

262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280
    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)
281
{
282
    RECT   rc = *rect;
283

284
    TRACE("(%p,%p,%p,%p,%p,%s,%08x)\n",
285
          hwnd, hdc, rect, hFont, hIcon, debugstr_w(str), uFlags);
286 287 288

    /* drawing background */
    if (uFlags & DC_INBUTTON) {
289 290 291
        FillRect (hdc, &rc, GetSysColorBrush (COLOR_3DFACE));

        if (uFlags & DC_ACTIVE) {
292
            HBRUSH hbr = SelectObject (hdc, SYSCOLOR_Get55AABrush());
293 294 295 296
            PatBlt (hdc, rc.left, rc.top,
                      rc.right-rc.left, rc.bottom-rc.top, 0xFA0089);
            SelectObject (hdc, hbr);
        }
297 298
    }
    else {
299
        DWORD style = GetWindowLongW (hwnd, GWL_STYLE);
300
        NC_DrawCaptionBar (hdc, &rc, style, uFlags & DC_ACTIVE, uFlags & DC_GRADIENT);
301 302 303 304 305
    }


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

308 309
        pt.x = rc.left + 2;
        pt.y = (rc.bottom + rc.top - GetSystemMetrics(SM_CYSMICON)) / 2;
310

311 312 313
        if (!hIcon) hIcon = NC_IconForWindow(hwnd);
        DrawIconEx (hdc, pt.x, pt.y, hIcon, GetSystemMetrics(SM_CXSMICON),
                    GetSystemMetrics(SM_CYSMICON), 0, 0, DI_NORMAL);
314
        rc.left += (rc.bottom - rc.top);
315 316 317 318
    }

    /* drawing text */
    if (uFlags & DC_TEXT) {
319
        HFONT hOldFont;
320

321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356
        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));
357 358 359 360
    }

    /* drawing focus ??? */
    if (uFlags & 0x2000)
361
        FIXME("undocumented flag (0x2000)!\n");
362

363
    return FALSE;
364 365 366
}


Alexandre Julliard's avatar
Alexandre Julliard committed
367
/***********************************************************************
368
 *		AdjustWindowRect (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
369
 */
370
BOOL WINAPI DECLSPEC_HOTPATCH AdjustWindowRect( LPRECT rect, DWORD style, BOOL menu )
Alexandre Julliard's avatar
Alexandre Julliard committed
371
{
372
    return AdjustWindowRectEx( rect, style, menu, 0 );
Alexandre Julliard's avatar
Alexandre Julliard committed
373 374 375
}


376 377 378
/***********************************************************************
 *		AdjustWindowRectEx (USER32.@)
 */
379
BOOL WINAPI DECLSPEC_HOTPATCH AdjustWindowRectEx( LPRECT rect, DWORD style, BOOL menu, DWORD exStyle )
380
{
381 382
    if (style & WS_ICONIC) return TRUE;
    style &= ~(WS_HSCROLL | WS_VSCROLL);
Alexandre Julliard's avatar
Alexandre Julliard committed
383

384
    TRACE("(%s) %08x %d %08x\n", wine_dbgstr_rect(rect), style, menu, exStyle );
Alexandre Julliard's avatar
Alexandre Julliard committed
385

386 387 388
    NC_AdjustRectOuter( rect, style, menu, exStyle );
    NC_AdjustRectInner( rect, style, exStyle );

Alexandre Julliard's avatar
Alexandre Julliard committed
389
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
390 391 392 393 394 395 396 397
}


/***********************************************************************
 *           NC_HandleNCCalcSize
 *
 * Handle a WM_NCCALCSIZE message. Called from DefWindowProc().
 */
398
LRESULT NC_HandleNCCalcSize( HWND hwnd, WPARAM wparam, RECT *winRect )
Alexandre Julliard's avatar
Alexandre Julliard committed
399
{
400
    RECT tmpRect = { 0, 0, 0, 0 };
401
    LRESULT result = 0;
402 403 404
    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
405

406 407 408
    if (winRect == NULL)
        return 0;

409 410
    if (cls_style & CS_VREDRAW) result |= WVR_VREDRAW;
    if (cls_style & CS_HREDRAW) result |= WVR_HREDRAW;
Alexandre Julliard's avatar
Alexandre Julliard committed
411

412
    if (!(style & WS_ICONIC))
413
    {
414
        NC_AdjustRectOuter( &tmpRect, style, FALSE, exStyle );
Alexandre Julliard's avatar
Alexandre Julliard committed
415

416 417 418 419
        winRect->left   -= tmpRect.left;
        winRect->top    -= tmpRect.top;
        winRect->right  -= tmpRect.right;
        winRect->bottom -= tmpRect.bottom;
Alexandre Julliard's avatar
Alexandre Julliard committed
420

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

426 427 428
            winRect->top +=
                MENU_GetMenuBarHeight( hwnd,
                                       winRect->right - winRect->left,
429
                                       -tmpRect.left, -tmpRect.top );
430
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
431

432 433 434 435 436 437 438
        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)
439 440 441 442 443
            if (winRect->right - winRect->left >= GetSystemMetrics(SM_CXVSCROLL))
            {
                /* rectangle is in screen coords when wparam is false */
                if (!wparam && (exStyle & WS_EX_LAYOUTRTL)) exStyle ^= WS_EX_LEFTSCROLLBAR;

444 445 446 447 448 449 450 451 452
                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);
453 454 455 456 457 458

        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
459
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
460
    return result;
Alexandre Julliard's avatar
Alexandre Julliard committed
461 462 463 464
}


/***********************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
465
 *           NC_GetInsideRect
Alexandre Julliard's avatar
Alexandre Julliard committed
466
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
467 468
 * Get the 'inside' rectangle of a window, i.e. the whole window rectangle
 * but without the borders (if any).
Alexandre Julliard's avatar
Alexandre Julliard committed
469
 */
470 471
static void NC_GetInsideRect( HWND hwnd, enum coords_relative relative, RECT *rect,
                              DWORD style, DWORD ex_style )
Alexandre Julliard's avatar
Alexandre Julliard committed
472
{
473
    WIN_GetRectangles( hwnd, relative, rect, NULL );
Alexandre Julliard's avatar
Alexandre Julliard committed
474

475
    if (style & WS_ICONIC) return;
Alexandre Julliard's avatar
Alexandre Julliard committed
476

Alexandre Julliard's avatar
Alexandre Julliard committed
477
    /* Remove frame from rectangle */
478
    if (HAS_THICKFRAME( style, ex_style ))
Alexandre Julliard's avatar
Alexandre Julliard committed
479
    {
480
        InflateRect( rect, -GetSystemMetrics(SM_CXFRAME), -GetSystemMetrics(SM_CYFRAME) );
Alexandre Julliard's avatar
Alexandre Julliard committed
481
    }
482
    else if (HAS_DLGFRAME( style, ex_style ))
Alexandre Julliard's avatar
Alexandre Julliard committed
483
    {
484
        InflateRect( rect, -GetSystemMetrics(SM_CXDLGFRAME), -GetSystemMetrics(SM_CYDLGFRAME));
Alexandre Julliard's avatar
Alexandre Julliard committed
485
    }
486
    else if (HAS_THINFRAME( style ))
Alexandre Julliard's avatar
Alexandre Julliard committed
487
    {
488
        InflateRect( rect, -GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER) );
Alexandre Julliard's avatar
Alexandre Julliard committed
489 490
    }

491 492
    /* We have additional border information if the window
     * is a child (but not an MDI child) */
493
    if ((style & WS_CHILD) && !(ex_style & WS_EX_MDICHILD))
494
    {
495
        if (ex_style & WS_EX_CLIENTEDGE)
496
            InflateRect (rect, -GetSystemMetrics(SM_CXEDGE), -GetSystemMetrics(SM_CYEDGE));
497
        if (ex_style & WS_EX_STATICEDGE)
498
            InflateRect (rect, -GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER));
Alexandre Julliard's avatar
Alexandre Julliard committed
499 500 501 502
    }
}


Alexandre Julliard's avatar
Alexandre Julliard committed
503
/***********************************************************************
504
 * NC_HandleNCHitTest
Alexandre Julliard's avatar
Alexandre Julliard committed
505
 *
506
 * Handle a WM_NCHITTEST message. Called from DefWindowProc().
Alexandre Julliard's avatar
Alexandre Julliard committed
507
 */
508
LRESULT NC_HandleNCHitTest( HWND hwnd, POINT pt )
Alexandre Julliard's avatar
Alexandre Julliard committed
509
{
510
    RECT rect, rcClient;
511
    DWORD style, ex_style;
Alexandre Julliard's avatar
Alexandre Julliard committed
512

513
    TRACE("hwnd=%p pt=%d,%d\n", hwnd, pt.x, pt.y );
Alexandre Julliard's avatar
Alexandre Julliard committed
514

515
    WIN_GetRectangles( hwnd, COORDS_SCREEN, &rect, &rcClient );
516
    if (!PtInRect( &rect, pt )) return HTNOWHERE;
Alexandre Julliard's avatar
Alexandre Julliard committed
517

518 519 520
    style = GetWindowLongW( hwnd, GWL_STYLE );
    ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
    if (style & WS_MINIMIZE) return HTCAPTION;
Alexandre Julliard's avatar
Alexandre Julliard committed
521

522
    if (PtInRect( &rcClient, pt )) return HTCLIENT;
523

524
    /* Check borders */
525
    if (HAS_THICKFRAME( style, ex_style ))
Alexandre Julliard's avatar
Alexandre Julliard committed
526
    {
527 528
        InflateRect( &rect, -GetSystemMetrics(SM_CXFRAME), -GetSystemMetrics(SM_CYFRAME) );
        if (!PtInRect( &rect, pt ))
Alexandre Julliard's avatar
Alexandre Julliard committed
529
        {
530 531
            /* Check top sizing border */
            if (pt.y < rect.top)
Alexandre Julliard's avatar
Alexandre Julliard committed
532
            {
533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556
                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
557 558
            }
        }
559 560 561
    }
    else  /* No thick frame */
    {
562
        if (HAS_DLGFRAME( style, ex_style ))
563
            InflateRect(&rect, -GetSystemMetrics(SM_CXDLGFRAME), -GetSystemMetrics(SM_CYDLGFRAME));
564
        else if (HAS_THINFRAME( style ))
565 566 567
            InflateRect(&rect, -GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER));
        if (!PtInRect( &rect, pt )) return HTBORDER;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
568

569
    /* Check caption */
Alexandre Julliard's avatar
Alexandre Julliard committed
570

571
    if ((style & WS_CAPTION) == WS_CAPTION)
572
    {
573
        if (ex_style & WS_EX_TOOLWINDOW)
574 575 576 577
            rect.top += GetSystemMetrics(SM_CYSMCAPTION) - 1;
        else
            rect.top += GetSystemMetrics(SM_CYCAPTION) - 1;
        if (!PtInRect( &rect, pt ))
Alexandre Julliard's avatar
Alexandre Julliard committed
578
        {
579
            BOOL min_or_max_box = (style & WS_SYSMENU) && (style & (WS_MINIMIZEBOX|WS_MAXIMIZEBOX));
580
            if (ex_style & WS_EX_LAYOUTRTL)
Alexandre Julliard's avatar
Alexandre Julliard committed
581
            {
582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640
                /* Check system menu */
                if ((style & WS_SYSMENU) && !(ex_style & WS_EX_TOOLWINDOW) && NC_IconForWindow(hwnd))
                {
                    rect.right -= GetSystemMetrics(SM_CYCAPTION) - 1;
                    if (pt.x > rect.right) return HTSYSMENU;
                }

                /* Check close button */
                if (style & WS_SYSMENU)
                {
                    rect.left += GetSystemMetrics(SM_CYCAPTION);
                    if (pt.x < rect.left) return HTCLOSE;
                }

                /* Check maximize box */
                /* In win95 there is automatically a Maximize button when there is a minimize one*/
                if (min_or_max_box && !(ex_style & WS_EX_TOOLWINDOW))
                {
                    rect.left += GetSystemMetrics(SM_CXSIZE);
                    if (pt.x < rect.left) return HTMAXBUTTON;
                }

                /* Check minimize box */
                if (min_or_max_box && !(ex_style & WS_EX_TOOLWINDOW))
                {
                    rect.left += GetSystemMetrics(SM_CXSIZE);
                    if (pt.x < rect.left) return HTMINBUTTON;
                }
            }
            else
            {
                /* Check system menu */
                if ((style & WS_SYSMENU) && !(ex_style & WS_EX_TOOLWINDOW) && NC_IconForWindow(hwnd))
                {
                    rect.left += GetSystemMetrics(SM_CYCAPTION) - 1;
                    if (pt.x < rect.left) return HTSYSMENU;
                }

                /* Check close button */
                if (style & WS_SYSMENU)
                {
                    rect.right -= GetSystemMetrics(SM_CYCAPTION);
                    if (pt.x > rect.right) return HTCLOSE;
                }

                /* Check maximize box */
                /* In win95 there is automatically a Maximize button when there is a minimize one*/
                if (min_or_max_box && !(ex_style & WS_EX_TOOLWINDOW))
                {
                    rect.right -= GetSystemMetrics(SM_CXSIZE);
                    if (pt.x > rect.right) return HTMAXBUTTON;
                }

                /* Check minimize box */
                if (min_or_max_box && !(ex_style & WS_EX_TOOLWINDOW))
                {
                    rect.right -= GetSystemMetrics(SM_CXSIZE);
                    if (pt.x > rect.right) return HTMINBUTTON;
                }
Alexandre Julliard's avatar
Alexandre Julliard committed
641
            }
642
            return HTCAPTION;
Alexandre Julliard's avatar
Alexandre Julliard committed
643 644 645
        }
    }

646 647 648 649 650 651
      /* Check menu bar */

    if (HAS_MENU( hwnd, style ) && (pt.y < rcClient.top) &&
        (pt.x >= rcClient.left) && (pt.x < rcClient.right))
        return HTMENU;

Alexandre Julliard's avatar
Alexandre Julliard committed
652 653
      /* Check vertical scroll bar */

654
    if (ex_style & WS_EX_LAYOUTRTL) ex_style ^= WS_EX_LEFTSCROLLBAR;
655
    if (style & WS_VSCROLL)
Alexandre Julliard's avatar
Alexandre Julliard committed
656
    {
657
        if((ex_style & WS_EX_LEFTSCROLLBAR) != 0)
658
            rcClient.left -= GetSystemMetrics(SM_CXVSCROLL);
659
        else
660
            rcClient.right += GetSystemMetrics(SM_CXVSCROLL);
661
        if (PtInRect( &rcClient, pt )) return HTVSCROLL;
Alexandre Julliard's avatar
Alexandre Julliard committed
662
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
663 664 665

      /* Check horizontal scroll bar */

666
    if (style & WS_HSCROLL)
Alexandre Julliard's avatar
Alexandre Julliard committed
667
    {
668
        rcClient.bottom += GetSystemMetrics(SM_CYHSCROLL);
669
        if (PtInRect( &rcClient, pt ))
670 671
        {
            /* Check size box */
672 673 674
            if ((style & WS_VSCROLL) &&
                ((((ex_style & WS_EX_LEFTSCROLLBAR) != 0) && (pt.x <= rcClient.left + GetSystemMetrics(SM_CXVSCROLL))) ||
                (((ex_style & WS_EX_LEFTSCROLLBAR) == 0) && (pt.x >= rcClient.right - GetSystemMetrics(SM_CXVSCROLL)))))
675 676 677
                return HTSIZE;
            return HTHSCROLL;
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
678 679
    }

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


Alexandre Julliard's avatar
Alexandre Julliard committed
686 687
/******************************************************************************
 *
688
 *   NC_DrawSysButton
Alexandre Julliard's avatar
Alexandre Julliard committed
689
 *
690
 *   Draws the system icon.
Alexandre Julliard's avatar
Alexandre Julliard committed
691 692
 *
 *****************************************************************************/
693
BOOL NC_DrawSysButton (HWND hwnd, HDC hdc, BOOL down)
Alexandre Julliard's avatar
Alexandre Julliard committed
694
{
695
    HICON hIcon = NC_IconForWindow( hwnd );
Alexandre Julliard's avatar
Alexandre Julliard committed
696

697
    if (hIcon)
Alexandre Julliard's avatar
Alexandre Julliard committed
698
    {
699
        RECT rect;
700
        POINT pt;
701 702 703
        DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
        DWORD ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );

704
        NC_GetInsideRect( hwnd, COORDS_WINDOW, &rect, style, ex_style );
705 706 707
        pt.x = rect.left + 2;
        pt.y = (rect.top + GetSystemMetrics(SM_CYCAPTION) - GetSystemMetrics(SM_CYSMICON)) / 2;
        DrawIconEx (hdc, pt.x, pt.y, hIcon,
708 709
                    GetSystemMetrics(SM_CXSMICON),
                    GetSystemMetrics(SM_CYSMICON), 0, 0, DI_NORMAL);
Alexandre Julliard's avatar
Alexandre Julliard committed
710
    }
711
    return (hIcon != 0);
Alexandre Julliard's avatar
Alexandre Julliard committed
712 713 714 715 716
}


/******************************************************************************
 *
717
 *   NC_DrawCloseButton
Alexandre Julliard's avatar
Alexandre Julliard committed
718
 *
719
 *   Draws the close button.
Alexandre Julliard's avatar
Alexandre Julliard committed
720
 *
721 722
 *   If bGrayed is true, then draw a disabled Close button
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
723 724
 *****************************************************************************/

725
static void NC_DrawCloseButton (HWND hwnd, HDC hdc, BOOL down, BOOL bGrayed)
Alexandre Julliard's avatar
Alexandre Julliard committed
726
{
727
    RECT rect;
728 729
    DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
    DWORD ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
Alexandre Julliard's avatar
Alexandre Julliard committed
730

731
    NC_GetInsideRect( hwnd, COORDS_WINDOW, &rect, style, ex_style );
732 733

    /* A tool window has a smaller Close button */
734
    if (ex_style & WS_EX_TOOLWINDOW)
Alexandre Julliard's avatar
Alexandre Julliard committed
735
    {
736 737 738
        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
739

740 741 742 743
        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
744
    }
745 746
    else
    {
747 748
        rect.left = rect.right - GetSystemMetrics(SM_CXSIZE);
        rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZE) - 2;
749 750 751 752 753 754 755
        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
756 757 758
}

/******************************************************************************
759
 *   NC_DrawMaxButton
Alexandre Julliard's avatar
Alexandre Julliard committed
760
 *
761
 *   Draws the maximize button for windows.
762
 *   If bGrayed is true, then draw a disabled Maximize button
763
 */
764
static void NC_DrawMaxButton(HWND hwnd,HDC hdc,BOOL down, BOOL bGrayed)
Alexandre Julliard's avatar
Alexandre Julliard committed
765
{
766
    RECT rect;
767
    UINT flags;
768 769
    DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
    DWORD ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
770 771

    /* never draw maximize box when window has WS_EX_TOOLWINDOW style */
772
    if (ex_style & WS_EX_TOOLWINDOW) return;
773

774
    flags = (style & WS_MAXIMIZE) ? DFCS_CAPTIONRESTORE : DFCS_CAPTIONMAX;
775

776
    NC_GetInsideRect( hwnd, COORDS_WINDOW, &rect, style, ex_style );
777
    if (style & WS_SYSMENU)
778
        rect.right -= GetSystemMetrics(SM_CXSIZE);
779
    rect.left = rect.right - GetSystemMetrics(SM_CXSIZE);
780
    rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZE) - 2;
781 782 783 784 785
    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
786 787 788
}

/******************************************************************************
789
 *   NC_DrawMinButton
Alexandre Julliard's avatar
Alexandre Julliard committed
790
 *
791
 *   Draws the minimize button for windows.
792
 *   If bGrayed is true, then draw a disabled Minimize button
793
 */
794
static void  NC_DrawMinButton(HWND hwnd,HDC hdc,BOOL down, BOOL bGrayed)
Alexandre Julliard's avatar
Alexandre Julliard committed
795
{
796
    RECT rect;
797
    UINT flags = DFCS_CAPTIONMIN;
798
    DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
799
    DWORD ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
Alexandre Julliard's avatar
Alexandre Julliard committed
800

801
    /* never draw minimize box when window has WS_EX_TOOLWINDOW style */
802
    if (ex_style & WS_EX_TOOLWINDOW) return;
803

804
    NC_GetInsideRect( hwnd, COORDS_WINDOW, &rect, style, ex_style );
805
    if (style & WS_SYSMENU)
806
        rect.right -= GetSystemMetrics(SM_CXSIZE);
807 808 809
    if (style & (WS_MAXIMIZEBOX|WS_MINIMIZEBOX))
        rect.right -= GetSystemMetrics(SM_CXSIZE) - 2;
    rect.left = rect.right - GetSystemMetrics(SM_CXSIZE);
810
    rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZE) - 2;
811 812 813 814 815
    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
816 817 818 819
}

/******************************************************************************
 *
820
 *   NC_DrawFrame
Alexandre Julliard's avatar
Alexandre Julliard committed
821 822 823 824 825
 *
 *   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
826
 *        on the outer edge is handled by NC_DoNCPaint.  As is the inner
Alexandre Julliard's avatar
Alexandre Julliard committed
827 828 829 830 831 832 833
 *        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...
834
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
835 836
 *****************************************************************************/

837
static void  NC_DrawFrame( HDC  hdc, RECT  *rect, BOOL  active, DWORD style, DWORD exStyle)
Alexandre Julliard's avatar
Alexandre Julliard committed
838
{
839
    INT width, height;
Alexandre Julliard's avatar
Alexandre Julliard committed
840

841 842
    /* Firstly the "thick" frame */
    if (style & WS_THICKFRAME)
Alexandre Julliard's avatar
Alexandre Julliard committed
843
    {
844 845
        width = GetSystemMetrics(SM_CXFRAME) - GetSystemMetrics(SM_CXDLGFRAME);
        height = GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYDLGFRAME);
846 847

        SelectObject( hdc, GetSysColorBrush(active ? COLOR_ACTIVEBORDER :
848
                                            COLOR_INACTIVEBORDER) );
849 850 851 852 853 854 855 856 857 858 859
        /* 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
860
    }
861 862 863 864

    /* Now the other bit of the frame */
    if ((style & (WS_BORDER|WS_DLGFRAME)) ||
        (exStyle & WS_EX_DLGMODALFRAME))
Alexandre Julliard's avatar
Alexandre Julliard committed
865
    {
866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890
        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
891 892 893
    }
}

Alexandre Julliard's avatar
Alexandre Julliard committed
894

Alexandre Julliard's avatar
Alexandre Julliard committed
895 896
/******************************************************************************
 *
897
 *   NC_DrawCaption
Alexandre Julliard's avatar
Alexandre Julliard committed
898
 *
899
 *   Draw the window caption for windows.
Alexandre Julliard's avatar
Alexandre Julliard committed
900 901 902 903
 *   The correct pen for the window frame must be selected in the DC.
 *
 *****************************************************************************/

904 905
static void  NC_DrawCaption( HDC  hdc, RECT *rect, HWND hwnd, DWORD  style, 
                             DWORD  exStyle, BOOL active )
Alexandre Julliard's avatar
Alexandre Julliard committed
906
{
907
    RECT  r = *rect;
908
    WCHAR buffer[256];
909
    HPEN  hPrevPen;
910
    HMENU hSysMenu;
911
    BOOL gradient = FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
912

913
    hPrevPen = SelectObject( hdc, SYSCOLOR_GetPen(
914 915 916
                     ((exStyle & (WS_EX_STATICEDGE|WS_EX_CLIENTEDGE|
                                 WS_EX_DLGMODALFRAME)) == WS_EX_STATICEDGE) ?
                      COLOR_WINDOWFRAME : COLOR_3DFACE) );
917 918 919
    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
920 921
    r.bottom--;

922
    SystemParametersInfoW (SPI_GETGRADIENTCAPTIONS, 0, &gradient, 0);
923
    NC_DrawCaptionBar (hdc, &r, style, active, gradient);
Alexandre Julliard's avatar
Alexandre Julliard committed
924

925
    if ((style & WS_SYSMENU) && !(exStyle & WS_EX_TOOLWINDOW)) {
926 927
        if (NC_DrawSysButton (hwnd, hdc, FALSE))
            r.left += GetSystemMetrics(SM_CXSMICON) + 2;
928
    }
929

930
    if (style & WS_SYSMENU)
931
    {
932
        UINT state;
933

934 935 936
        /* Go get the sysmenu */
        hSysMenu = GetSystemMenu(hwnd, FALSE);
        state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
937

938 939 940 941
        /* 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;
942

943 944 945 946
        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*/
947

948 949
            NC_DrawMaxButton( hwnd, hdc, FALSE, (!(style & WS_MAXIMIZEBOX)));
            r.right -= GetSystemMetrics(SM_CXSIZE) + 1;
950

951 952 953
            NC_DrawMinButton( hwnd, hdc, FALSE,  (!(style & WS_MINIMIZEBOX)));
            r.right -= GetSystemMetrics(SM_CXSIZE) + 1;
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
954 955
    }

956
    if (GetWindowTextW( hwnd, buffer, sizeof(buffer)/sizeof(WCHAR) ))
957
    {
958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973
        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
974 975 976 977 978
    }
}


/******************************************************************************
979
 *   NC_DoNCPaint
Alexandre Julliard's avatar
Alexandre Julliard committed
980
 *
981 982
 *   Paint the non-client area for windows.
 */
983
static void  NC_DoNCPaint( HWND  hwnd, HRGN  clip )
Alexandre Julliard's avatar
Alexandre Julliard committed
984
{
985
    HDC hdc;
986
    RECT rfuzz, rect, rectClip;
987
    BOOL active;
988 989 990
    WND *wndPtr;
    DWORD dwStyle, dwExStyle;
    WORD flags;
991
    HRGN hrgn;
992
    RECT rectClient;
993 994 995

    if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return;
    dwStyle = wndPtr->dwStyle;
996
    dwExStyle = wndPtr->dwExStyle;
997 998 999 1000
    flags = wndPtr->flags;
    WIN_ReleasePtr( wndPtr );

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

1003
    active  = flags & WIN_NCACTIVATED;
Alexandre Julliard's avatar
Alexandre Julliard committed
1004

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

1007 1008 1009 1010 1011
    /* 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?
1012 1013
     */

1014
    WIN_GetRectangles( hwnd, COORDS_SCREEN, NULL, &rectClient );
1015 1016
    hrgn = CreateRectRgnIndirect( &rectClient );

1017 1018 1019 1020 1021 1022
    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
1023
    {
1024
        hdc = GetDCEx( hwnd, hrgn, DCX_USESTYLE | DCX_WINDOW | DCX_EXCLUDERGN );
Alexandre Julliard's avatar
Alexandre Julliard committed
1025 1026
    }

1027 1028
    if (!hdc) return;

1029
    WIN_GetRectangles( hwnd, COORDS_WINDOW, &rect, NULL );
1030
    GetClipBox( hdc, &rectClip );
1031

1032
    SelectObject( hdc, SYSCOLOR_GetPen(COLOR_WINDOWFRAME) );
Alexandre Julliard's avatar
Alexandre Julliard committed
1033

1034
    if (HAS_STATICOUTERFRAME(dwStyle, dwExStyle)) {
1035
        DrawEdge (hdc, &rect, BDR_SUNKENOUTER, BF_RECT | BF_ADJUST);
1036
    }
1037
    else if (HAS_BIGFRAME( dwStyle, dwExStyle)) {
1038
        DrawEdge (hdc, &rect, EDGE_RAISED, BF_RECT | BF_ADJUST);
1039
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1040

1041
    NC_DrawFrame(hdc, &rect, active, dwStyle, dwExStyle );
1042

1043
    if ((dwStyle & WS_CAPTION) == WS_CAPTION)
1044 1045
    {
        RECT  r = rect;
1046
        if (dwExStyle & WS_EX_TOOLWINDOW) {
1047 1048
            r.bottom = rect.top + GetSystemMetrics(SM_CYSMCAPTION);
            rect.top += GetSystemMetrics(SM_CYSMCAPTION);
Alexandre Julliard's avatar
Alexandre Julliard committed
1049
        }
1050 1051 1052 1053
        else {
            r.bottom = rect.top + GetSystemMetrics(SM_CYCAPTION);
            rect.top += GetSystemMetrics(SM_CYCAPTION);
        }
1054
        if( IntersectRect( &rfuzz, &r, &rectClip ) )
1055
            NC_DrawCaption(hdc, &r, hwnd, dwStyle, dwExStyle, active);
Alexandre Julliard's avatar
Alexandre Julliard committed
1056 1057
    }

1058
    if (HAS_MENU( hwnd, dwStyle ))
Alexandre Julliard's avatar
Alexandre Julliard committed
1059
    {
1060
	RECT r = rect;
1061
	r.bottom = rect.top + GetSystemMetrics(SM_CYMENU);
1062

1063
	TRACE("Calling DrawMenuBar with rect (%s)\n", wine_dbgstr_rect(&r));
Alexandre Julliard's avatar
Alexandre Julliard committed
1064

1065
	rect.top += MENU_DrawMenuBar( hdc, &r, hwnd ) + 1;
Alexandre Julliard's avatar
Alexandre Julliard committed
1066 1067
    }

1068
    TRACE("After MenuBar, rect is (%s).\n", wine_dbgstr_rect(&rect));
Alexandre Julliard's avatar
Alexandre Julliard committed
1069

1070
    if (dwExStyle & WS_EX_CLIENTEDGE)
1071
	DrawEdge (hdc, &rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
Alexandre Julliard's avatar
Alexandre Julliard committed
1072 1073 1074

    /* Draw the scroll-bars */

1075
    if (dwStyle & WS_VSCROLL)
1076
        SCROLL_DrawScrollBar( hwnd, hdc, SB_VERT, TRUE, TRUE );
1077
    if (dwStyle & WS_HSCROLL)
1078
        SCROLL_DrawScrollBar( hwnd, hdc, SB_HORZ, TRUE, TRUE );
Alexandre Julliard's avatar
Alexandre Julliard committed
1079 1080

    /* Draw the "size-box" */
1081
    if ((dwStyle & WS_VSCROLL) && (dwStyle & WS_HSCROLL))
Alexandre Julliard's avatar
Alexandre Julliard committed
1082
    {
1083
        RECT r = rect;
1084 1085 1086 1087
        if((dwExStyle & WS_EX_LEFTSCROLLBAR) != 0)
            r.right = r.left + GetSystemMetrics(SM_CXVSCROLL) + 1;
        else
            r.left = r.right - GetSystemMetrics(SM_CXVSCROLL) + 1;
1088
        r.top  = r.bottom - GetSystemMetrics(SM_CYHSCROLL) + 1;
1089
        FillRect( hdc, &r,  GetSysColorBrush(COLOR_SCROLLBAR) );
1090
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1091

1092
    ReleaseDC( hwnd, hdc );
Alexandre Julliard's avatar
Alexandre Julliard committed
1093 1094 1095 1096
}



Alexandre Julliard's avatar
Alexandre Julliard committed
1097

Alexandre Julliard's avatar
Alexandre Julliard committed
1098 1099 1100 1101 1102
/***********************************************************************
 *           NC_HandleNCPaint
 *
 * Handle a WM_NCPAINT message. Called from DefWindowProc().
 */
1103
LRESULT NC_HandleNCPaint( HWND hwnd , HRGN clip)
Alexandre Julliard's avatar
Alexandre Julliard committed
1104
{
1105
    DWORD dwStyle = GetWindowLongW( hwnd, GWL_STYLE );
Alexandre Julliard's avatar
Alexandre Julliard committed
1106

1107
    if( dwStyle & WS_VISIBLE )
Alexandre Julliard's avatar
Alexandre Julliard committed
1108
    {
1109
	if( dwStyle & WS_MINIMIZE )
Alexandre Julliard's avatar
Alexandre Julliard committed
1110
	    WINPOS_RedrawIconTitle( hwnd );
Alexandre Julliard's avatar
Alexandre Julliard committed
1111
	else
1112
	    NC_DoNCPaint( hwnd, clip );
Alexandre Julliard's avatar
Alexandre Julliard committed
1113
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1114 1115 1116 1117 1118
    return 0;
}


/***********************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
1119
 *           NC_HandleNCActivate
Alexandre Julliard's avatar
Alexandre Julliard committed
1120
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
1121
 * Handle a WM_NCACTIVATE message. Called from DefWindowProc().
Alexandre Julliard's avatar
Alexandre Julliard committed
1122
 */
1123
LRESULT NC_HandleNCActivate( HWND hwnd, WPARAM wParam, LPARAM lParam )
Alexandre Julliard's avatar
Alexandre Julliard committed
1124
{
1125 1126 1127
    WND* wndPtr = WIN_GetPtr( hwnd );

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

1129 1130 1131 1132 1133
    /* 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.
     */
1134 1135 1136 1137
    if (wParam) wndPtr->flags |= WIN_NCACTIVATED;
    else wndPtr->flags &= ~WIN_NCACTIVATED;
    WIN_ReleasePtr( wndPtr );

1138 1139 1140 1141 1142 1143 1144 1145
    /* This isn't documented but is reproducible in at least XP SP2 and
     * Outlook 2007 depends on it
     */
    if (lParam != -1)
    {
        if (IsIconic(hwnd))
            WINPOS_RedrawIconTitle( hwnd );
        else
1146
            NC_DoNCPaint( hwnd, (HRGN)1 );
1147
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1148

Alexandre Julliard's avatar
Alexandre Julliard committed
1149 1150
    return TRUE;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1151

Alexandre Julliard's avatar
Alexandre Julliard committed
1152

Alexandre Julliard's avatar
Alexandre Julliard committed
1153 1154 1155 1156 1157
/***********************************************************************
 *           NC_HandleSetCursor
 *
 * Handle a WM_SETCURSOR message. Called from DefWindowProc().
 */
1158
LRESULT NC_HandleSetCursor( HWND hwnd, WPARAM wParam, LPARAM lParam )
Alexandre Julliard's avatar
Alexandre Julliard committed
1159
{
1160
    hwnd = WIN_GetFullHandle( (HWND)wParam );
Alexandre Julliard's avatar
Alexandre Julliard committed
1161

1162
    switch((short)LOWORD(lParam))
Alexandre Julliard's avatar
Alexandre Julliard committed
1163 1164
    {
    case HTERROR:
1165 1166 1167 1168 1169 1170 1171
        {
            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
1172 1173

    case HTCLIENT:
1174 1175 1176 1177 1178 1179
        {
            HCURSOR hCursor = (HCURSOR)GetClassLongPtrW(hwnd, GCLP_HCURSOR);
            if(hCursor) {
                SetCursor(hCursor);
                return TRUE;
            }
1180
            return FALSE;
1181
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
1182 1183 1184

    case HTLEFT:
    case HTRIGHT:
1185
        return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZEWE ) );
Alexandre Julliard's avatar
Alexandre Julliard committed
1186 1187 1188

    case HTTOP:
    case HTBOTTOM:
1189
        return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENS ) );
Alexandre Julliard's avatar
Alexandre Julliard committed
1190 1191

    case HTTOPLEFT:
1192
    case HTBOTTOMRIGHT:
1193
        return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENWSE ) );
Alexandre Julliard's avatar
Alexandre Julliard committed
1194 1195 1196

    case HTTOPRIGHT:
    case HTBOTTOMLEFT:
1197
        return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENESW ) );
Alexandre Julliard's avatar
Alexandre Julliard committed
1198 1199 1200
    }

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

Alexandre Julliard's avatar
Alexandre Julliard committed
1204 1205 1206
/***********************************************************************
 *           NC_GetSysPopupPos
 */
1207
void NC_GetSysPopupPos( HWND hwnd, RECT* rect )
Alexandre Julliard's avatar
Alexandre Julliard committed
1208
{
1209 1210 1211
    if (IsIconic(hwnd)) GetWindowRect( hwnd, rect );
    else
    {
1212 1213
        DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
        DWORD ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
1214

1215
        NC_GetInsideRect( hwnd, COORDS_CLIENT, rect, style, ex_style );
1216 1217
        rect->right = rect->left + GetSystemMetrics(SM_CYCAPTION) - 1;
        rect->bottom = rect->top + GetSystemMetrics(SM_CYCAPTION) - 1;
1218
        MapWindowPoints( hwnd, 0, (POINT *)rect, 2 );
1219
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1220
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1221

1222
/***********************************************************************
1223
 *           NC_TrackMinMaxBox
1224 1225 1226 1227 1228 1229 1230 1231
 *
 * 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.
 *
 */
1232
static void NC_TrackMinMaxBox( HWND hwnd, WORD wParam )
1233 1234 1235 1236 1237
{
    MSG msg;
    HDC hdc = GetWindowDC( hwnd );
    BOOL pressed = TRUE;
    UINT state;
1238
    DWORD wndStyle = GetWindowLongW( hwnd, GWL_STYLE);
1239 1240
    HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);

1241
    void  (*paintButton)(HWND, HDC, BOOL, BOOL);
1242 1243 1244

    if (wParam == HTMINBUTTON)
    {
1245 1246 1247
        /* If the style is not present, do nothing */
        if (!(wndStyle & WS_MINIMIZEBOX))
            return;
1248

1249 1250
        /* Check if the sysmenu item for minimize is there  */
        state = GetMenuState(hSysMenu, SC_MINIMIZE, MF_BYCOMMAND);
1251

1252
        paintButton = NC_DrawMinButton;
1253 1254 1255
    }
    else
    {
1256 1257 1258
        /* If the style is not present, do nothing */
        if (!(wndStyle & WS_MAXIMIZEBOX))
            return;
1259

1260 1261
        /* Check if the sysmenu item for maximize is there  */
        state = GetMenuState(hSysMenu, SC_MAXIMIZE, MF_BYCOMMAND);
1262

1263
        paintButton = NC_DrawMaxButton;
1264 1265 1266 1267 1268 1269
    }

    SetCapture( hwnd );

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

1270
    while(1)
1271
    {
1272
        BOOL oldstate = pressed;
1273 1274 1275

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

1277 1278
        if(msg.message == WM_LBUTTONUP)
            break;
1279

1280 1281
        if(msg.message != WM_MOUSEMOVE)
            continue;
1282

1283 1284 1285
        pressed = (NC_HandleNCHitTest( hwnd, msg.pt ) == wParam);
        if (pressed != oldstate)
           (*paintButton)( hwnd, hdc, pressed, FALSE);
1286
    }
1287

1288
    if(pressed)
1289
        (*paintButton)(hwnd, hdc, FALSE, FALSE);
1290 1291 1292 1293

    ReleaseCapture();
    ReleaseDC( hwnd, hdc );

1294
    /* If the minimize or maximize items of the sysmenu are not there */
1295 1296
    /* or if the style is not present, do nothing */
    if ((!pressed) || (state == 0xFFFFFFFF))
1297
        return;
1298

1299
    if (wParam == HTMINBUTTON)
1300
        SendMessageW( hwnd, WM_SYSCOMMAND, SC_MINIMIZE, MAKELONG(msg.pt.x,msg.pt.y) );
1301
    else
1302
        SendMessageW( hwnd, WM_SYSCOMMAND,
1303
                      IsZoomed(hwnd) ? SC_RESTORE:SC_MAXIMIZE, MAKELONG(msg.pt.x,msg.pt.y) );
1304 1305
}

Alexandre Julliard's avatar
Alexandre Julliard committed
1306
/***********************************************************************
1307
 * NC_TrackCloseButton
Alexandre Julliard's avatar
Alexandre Julliard committed
1308 1309 1310
 *
 * Track a mouse button press on the Win95 close button.
 */
1311
static void NC_TrackCloseButton (HWND hwnd, WPARAM wParam, LPARAM lParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
1312
{
1313
    MSG msg;
1314
    HDC hdc;
1315
    BOOL pressed = TRUE;
1316 1317 1318 1319
    HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
    UINT state;

    if(hSysMenu == 0)
1320
        return;
1321 1322

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

1324
    /* If the close item of the sysmenu is disabled or not present do nothing */
1325
    if((state & MF_DISABLED) || (state & MF_GRAYED) || (state == 0xFFFFFFFF))
1326
        return;
1327 1328

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

1330
    SetCapture( hwnd );
Alexandre Julliard's avatar
Alexandre Julliard committed
1331

1332
    NC_DrawCloseButton (hwnd, hdc, TRUE, FALSE);
Alexandre Julliard's avatar
Alexandre Julliard committed
1333

1334
    while(1)
Alexandre Julliard's avatar
Alexandre Julliard committed
1335
    {
1336
        BOOL oldstate = pressed;
1337 1338 1339

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

1341 1342
        if(msg.message == WM_LBUTTONUP)
            break;
1343

1344 1345
        if(msg.message != WM_MOUSEMOVE)
            continue;
1346

1347 1348 1349
        pressed = (NC_HandleNCHitTest( hwnd, msg.pt ) == wParam);
        if (pressed != oldstate)
           NC_DrawCloseButton (hwnd, hdc, pressed, FALSE);
1350
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1351

1352
    if(pressed)
1353
        NC_DrawCloseButton (hwnd, hdc, FALSE, FALSE);
Alexandre Julliard's avatar
Alexandre Julliard committed
1354 1355

    ReleaseCapture();
1356
    ReleaseDC( hwnd, hdc );
Alexandre Julliard's avatar
Alexandre Julliard committed
1357 1358
    if (!pressed) return;

1359
    SendMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, lParam );
Alexandre Julliard's avatar
Alexandre Julliard committed
1360 1361 1362
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1363 1364 1365 1366 1367
/***********************************************************************
 *           NC_TrackScrollBar
 *
 * Track a mouse button press on the horizontal or vertical scroll-bar.
 */
1368
static void NC_TrackScrollBar( HWND hwnd, WPARAM wParam, POINT pt )
Alexandre Julliard's avatar
Alexandre Julliard committed
1369
{
1370
    INT scrollbar;
Alexandre Julliard's avatar
Alexandre Julliard committed
1371

Alexandre Julliard's avatar
Alexandre Julliard committed
1372 1373
    if ((wParam & 0xfff0) == SC_HSCROLL)
    {
1374
        if ((wParam & 0x0f) != HTHSCROLL) return;
Alexandre Julliard's avatar
Alexandre Julliard committed
1375 1376 1377 1378
	scrollbar = SB_HORZ;
    }
    else  /* SC_VSCROLL */
    {
1379
        if ((wParam & 0x0f) != HTVSCROLL) return;
Alexandre Julliard's avatar
Alexandre Julliard committed
1380 1381
	scrollbar = SB_VERT;
    }
1382
    SCROLL_TrackScrollBar( hwnd, scrollbar, pt );
Alexandre Julliard's avatar
Alexandre Julliard committed
1383 1384
}

1385

Alexandre Julliard's avatar
Alexandre Julliard committed
1386 1387 1388 1389 1390
/***********************************************************************
 *           NC_HandleNCLButtonDown
 *
 * Handle a WM_NCLBUTTONDOWN message. Called from DefWindowProc().
 */
1391
LRESULT NC_HandleNCLButtonDown( HWND hwnd, WPARAM wParam, LPARAM lParam )
Alexandre Julliard's avatar
Alexandre Julliard committed
1392
{
1393
    LONG style = GetWindowLongW( hwnd, GWL_STYLE );
Alexandre Julliard's avatar
Alexandre Julliard committed
1394

Alexandre Julliard's avatar
Alexandre Julliard committed
1395 1396
    switch(wParam)  /* Hit test */
    {
Alexandre Julliard's avatar
Alexandre Julliard committed
1397
    case HTCAPTION:
1398
        {
1399 1400 1401 1402 1403 1404 1405 1406 1407
            HWND top = hwnd, parent;
            while(1)
            {
                if ((GetWindowLongW( top, GWL_STYLE ) & (WS_POPUP|WS_CHILD)) != WS_CHILD)
                    break;
                parent = GetAncestor( top, GA_PARENT );
                if (!parent || parent == GetDesktopWindow()) break;
                top = parent;
            }
Alexandre Julliard's avatar
Alexandre Julliard committed
1408

1409
            if (FOCUS_MouseActivate( top ) || (GetActiveWindow() == top))
1410 1411 1412
                SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOVE + HTCAPTION, lParam );
            break;
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
1413 1414

    case HTSYSMENU:
1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425
         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
1426 1427

    case HTMENU:
1428 1429
        SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOUSEMENU, lParam );
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
1430

Alexandre Julliard's avatar
Alexandre Julliard committed
1431
    case HTHSCROLL:
1432 1433
        SendMessageW( hwnd, WM_SYSCOMMAND, SC_HSCROLL + HTHSCROLL, lParam );
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
1434

Alexandre Julliard's avatar
Alexandre Julliard committed
1435
    case HTVSCROLL:
1436 1437
        SendMessageW( hwnd, WM_SYSCOMMAND, SC_VSCROLL + HTVSCROLL, lParam );
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
1438

Alexandre Julliard's avatar
Alexandre Julliard committed
1439
    case HTMINBUTTON:
Alexandre Julliard's avatar
Alexandre Julliard committed
1440
    case HTMAXBUTTON:
1441 1442
        NC_TrackMinMaxBox( hwnd, wParam );
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
1443

Alexandre Julliard's avatar
Alexandre Julliard committed
1444
    case HTCLOSE:
1445
        NC_TrackCloseButton (hwnd, wParam, lParam);
1446
        break;
1447

Alexandre Julliard's avatar
Alexandre Julliard committed
1448 1449 1450 1451 1452 1453 1454
    case HTLEFT:
    case HTRIGHT:
    case HTTOP:
    case HTTOPLEFT:
    case HTTOPRIGHT:
    case HTBOTTOM:
    case HTBOTTOMLEFT:
Alexandre Julliard's avatar
Alexandre Julliard committed
1455
    case HTBOTTOMRIGHT:
1456 1457 1458 1459 1460 1461 1462 1463 1464
        /* 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);
1465
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
1466 1467

    case HTBORDER:
1468
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
1469 1470 1471 1472 1473
    }
    return 0;
}


1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487
/***********************************************************************
 *           NC_HandleNCRButtonDown
 *
 * Handle a WM_NCRBUTTONDOWN message. Called from DefWindowProc().
 */
LRESULT NC_HandleNCRButtonDown( HWND hwnd, WPARAM wParam, LPARAM lParam )
{
    MSG msg;
    INT hittest = wParam;

    switch (hittest)
    {
    case HTCAPTION:
    case HTSYSMENU:
1488
        if (!GetSystemMenu( hwnd, FALSE )) break;
1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509

        SetCapture( hwnd );
        for (;;)
        {
            if (!GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST )) break;
            if (CallMsgFilterW( &msg, MSGF_MAX )) continue;
            if (msg.message == WM_RBUTTONUP)
            {
                hittest = NC_HandleNCHitTest( hwnd, msg.pt );
                break;
            }
        }
        ReleaseCapture();
        if (hittest == HTCAPTION || hittest == HTSYSMENU)
            SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOUSEMENU + HTSYSMENU, msg.lParam );
        break;
    }
    return 0;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1510 1511 1512 1513 1514
/***********************************************************************
 *           NC_HandleNCLButtonDblClk
 *
 * Handle a WM_NCLBUTTONDBLCLK message. Called from DefWindowProc().
 */
1515
LRESULT NC_HandleNCLButtonDblClk( HWND hwnd, WPARAM wParam, LPARAM lParam )
Alexandre Julliard's avatar
Alexandre Julliard committed
1516
{
Alexandre Julliard's avatar
Alexandre Julliard committed
1517 1518 1519 1520
    /*
     * if this is an icon, send a restore since we are handling
     * a double click
     */
1521
    if (IsIconic(hwnd))
Alexandre Julliard's avatar
Alexandre Julliard committed
1522
    {
1523
        SendMessageW( hwnd, WM_SYSCOMMAND, SC_RESTORE, lParam );
Alexandre Julliard's avatar
Alexandre Julliard committed
1524
        return 0;
1525
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1526

Alexandre Julliard's avatar
Alexandre Julliard committed
1527 1528 1529
    switch(wParam)  /* Hit test */
    {
    case HTCAPTION:
Alexandre Julliard's avatar
Alexandre Julliard committed
1530
        /* stop processing if WS_MAXIMIZEBOX is missing */
1531
        if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_MAXIMIZEBOX)
1532 1533
            SendMessageW( hwnd, WM_SYSCOMMAND,
                          IsZoomed(hwnd) ? SC_RESTORE : SC_MAXIMIZE, lParam );
1534
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
1535 1536

    case HTSYSMENU:
1537 1538 1539
        {
            HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
            UINT state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
1540

1541
            /* If the close item of the sysmenu is disabled or not present do nothing */
1542 1543 1544
            if ((state & (MF_DISABLED | MF_GRAYED)) || (state == 0xFFFFFFFF))
                break;

1545
            SendMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, lParam );
1546 1547
            break;
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
1548 1549

    case HTHSCROLL:
1550
        SendMessageW( hwnd, WM_SYSCOMMAND, SC_HSCROLL + HTHSCROLL, lParam );
1551
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
1552 1553

    case HTVSCROLL:
1554
        SendMessageW( hwnd, WM_SYSCOMMAND, SC_VSCROLL + HTVSCROLL, lParam );
1555
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
1556 1557 1558 1559 1560 1561 1562 1563 1564 1565
    }
    return 0;
}


/***********************************************************************
 *           NC_HandleSysCommand
 *
 * Handle a WM_SYSCOMMAND message. Called from DefWindowProc().
 */
1566
LRESULT NC_HandleSysCommand( HWND hwnd, WPARAM wParam, LPARAM lParam )
Alexandre Julliard's avatar
Alexandre Julliard committed
1567
{
1568
    TRACE("hwnd %p WM_SYSCOMMAND %lx %lx\n", hwnd, wParam, lParam );
1569 1570

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

1572 1573 1574
    if (HOOK_CallHooks( WH_CBT, HCBT_SYSCOMMAND, wParam, lParam, TRUE ))
        return 0;

1575 1576 1577
    if (!USER_Driver->pSysCommand( hwnd, wParam, lParam ))
        return 0;

1578
    switch (wParam & 0xfff0)
Alexandre Julliard's avatar
Alexandre Julliard committed
1579 1580 1581
    {
    case SC_SIZE:
    case SC_MOVE:
1582
        WINPOS_SysCommandSizeMove( hwnd, wParam );
1583
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
1584 1585

    case SC_MINIMIZE:
1586
        if (hwnd == GetActiveWindow())
1587
            ShowOwnedPopups(hwnd,FALSE);
1588 1589
        ShowWindow( hwnd, SW_MINIMIZE );
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
1590 1591

    case SC_MAXIMIZE:
1592
        if (IsIconic(hwnd) && hwnd == GetActiveWindow())
1593
            ShowOwnedPopups(hwnd,TRUE);
1594 1595
        ShowWindow( hwnd, SW_MAXIMIZE );
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
1596 1597

    case SC_RESTORE:
1598
        if (IsIconic(hwnd) && hwnd == GetActiveWindow())
1599
            ShowOwnedPopups(hwnd,TRUE);
1600 1601
        ShowWindow( hwnd, SW_RESTORE );
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
1602 1603

    case SC_CLOSE:
1604
        return SendMessageW( hwnd, WM_CLOSE, 0, 0 );
Alexandre Julliard's avatar
Alexandre Julliard committed
1605 1606 1607

    case SC_VSCROLL:
    case SC_HSCROLL:
1608 1609
        {
            POINT pt;
1610 1611
            pt.x = (short)LOWORD(lParam);
            pt.y = (short)HIWORD(lParam);
1612 1613
            NC_TrackScrollBar( hwnd, wParam, pt );
        }
1614
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
1615

Alexandre Julliard's avatar
Alexandre Julliard committed
1616
    case SC_MOUSEMENU:
1617 1618
        {
            POINT pt;
1619 1620
            pt.x = (short)LOWORD(lParam);
            pt.y = (short)HIWORD(lParam);
1621 1622
            MENU_TrackMouseMenuBar( hwnd, wParam & 0x000F, pt );
        }
1623
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
1624

Alexandre Julliard's avatar
Alexandre Julliard committed
1625
    case SC_KEYMENU:
1626
        MENU_TrackKbdMenuBar( hwnd, wParam, (WCHAR)lParam );
1627
        break;
1628

Alexandre Julliard's avatar
Alexandre Julliard committed
1629
    case SC_TASKLIST:
1630 1631
        WinExec( "taskman.exe", SW_SHOWNORMAL );
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
1632 1633

    case SC_SCREENSAVE:
1634
        if (wParam == SC_ABOUTWINE)
1635 1636 1637 1638
        {
            HMODULE hmodule = LoadLibraryA( "shell32.dll" );
            if (hmodule)
            {
1639 1640 1641
                BOOL (WINAPI *aboutproc)(HWND, LPCSTR, LPCSTR, HICON);

                aboutproc = (void *)GetProcAddress( hmodule, "ShellAboutA" );
1642
                if (aboutproc) aboutproc( hwnd, PACKAGE_STRING, NULL, 0 );
1643 1644 1645
                FreeLibrary( hmodule );
            }
        }
1646
        break;
1647

Alexandre Julliard's avatar
Alexandre Julliard committed
1648 1649 1650 1651
    case SC_HOTKEY:
    case SC_ARRANGE:
    case SC_NEXTWINDOW:
    case SC_PREVWINDOW:
1652
        FIXME("unimplemented WM_SYSCOMMAND %04lx!\n", wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1653
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
1654 1655 1656
    }
    return 0;
}
1657

1658 1659 1660 1661 1662 1663 1664 1665 1666 1667
/***********************************************************************
 *		GetTitleBarInfo (USER32.@)
 * TODO: Handle STATE_SYSTEM_PRESSED
 */
BOOL WINAPI GetTitleBarInfo(HWND hwnd, PTITLEBARINFO tbi) {
    DWORD dwStyle;
    DWORD dwExStyle;

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

1668 1669 1670 1671 1672
    if(!tbi) {
        SetLastError(ERROR_NOACCESS);
        return FALSE;
    }

1673
    if(tbi->cbSize != sizeof(TITLEBARINFO)) {
1674
        TRACE("Invalid TITLEBARINFO size: %d\n", tbi->cbSize);
1675 1676 1677 1678 1679
        SetLastError(ERROR_INVALID_PARAMETER);
        return FALSE;
    }
    dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
    dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
1680
    NC_GetInsideRect(hwnd, COORDS_SCREEN, &tbi->rcTitleBar, dwStyle, dwExStyle);
1681 1682 1683 1684 1685 1686 1687 1688 1689

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

1690
    ZeroMemory(tbi->rgstate, sizeof(tbi->rgstate));
1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723
    /* 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;
}