nonclient.c 49.3 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 18
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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 "wine/winuser16.h"
29
#include "wownt32.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
30
#include "win.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
31
#include "user.h"
32
#include "dce.h"
33
#include "controls.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
34
#include "cursoricon.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
35 36
#include "winpos.h"
#include "nonclient.h"
37
#include "shellapi.h"
38
#include "wine/debug.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
39

40 41
WINE_DEFAULT_DEBUG_CHANNEL(nonclient);
WINE_DECLARE_DEBUG_CHANNEL(shell);
42

43 44
BOOL NC_DrawGrayButton(HDC hdc, int x, int y);

45
static const BYTE lpGrayMask[] = { 0xAA, 0xA0,
46
		      0x55, 0x50,
47
		      0xAA, 0xA0,
48
		      0x55, 0x50,
49
		      0xAA, 0xA0,
50
		      0x55, 0x50,
51
		      0xAA, 0xA0,
52
		      0x55, 0x50,
53 54 55
		      0xAA, 0xA0,
		      0x55, 0x50};

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

Alexandre Julliard's avatar
Alexandre Julliard committed
59 60
  /* Some useful macros */
#define HAS_DLGFRAME(style,exStyle) \
Alexandre Julliard's avatar
Alexandre Julliard committed
61
    (((exStyle) & WS_EX_DLGMODALFRAME) || \
62
     (((style) & WS_DLGFRAME) && !((style) & WS_THICKFRAME)))
Alexandre Julliard's avatar
Alexandre Julliard committed
63

64
#define HAS_THICKFRAME(style,exStyle) \
Alexandre Julliard's avatar
Alexandre Julliard committed
65
    (((style) & WS_THICKFRAME) && \
66
     !(((style) & (WS_DLGFRAME|WS_BORDER)) == WS_DLGFRAME))
Alexandre Julliard's avatar
Alexandre Julliard committed
67

68 69
#define HAS_THINFRAME(style) \
    (((style) & WS_BORDER) || !((style) & (WS_CHILD | WS_POPUP)))
Alexandre Julliard's avatar
Alexandre Julliard committed
70

71 72 73
#define HAS_BIGFRAME(style,exStyle) \
    (((style) & (WS_THICKFRAME | WS_DLGFRAME)) || \
     ((exStyle) & WS_EX_DLGMODALFRAME))
74

75 76 77 78
#define HAS_STATICOUTERFRAME(style,exStyle) \
    (((exStyle) & (WS_EX_STATICEDGE|WS_EX_DLGMODALFRAME)) == \
     WS_EX_STATICEDGE)

79 80 81 82
#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
83

Alexandre Julliard's avatar
Alexandre Julliard committed
84 85
#define HAS_MENU(w)  (!((w)->dwStyle & WS_CHILD) && ((w)->wIDmenu != 0))

86

Alexandre Julliard's avatar
Alexandre Julliard committed
87
/******************************************************************************
88
 * NC_AdjustRectOuter
Alexandre Julliard's avatar
Alexandre Julliard committed
89
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
90 91
 * 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
92
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
93 94 95
 + PARAMS
 *     LPRECT16  rect
 *     DWORD  style
96
 *     BOOL  menu
Alexandre Julliard's avatar
Alexandre Julliard committed
97
 *     DWORD  exStyle
Alexandre Julliard's avatar
Alexandre Julliard committed
98
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
99 100 101 102
 * 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
103 104 105
 *
 *****************************************************************************/

Alexandre Julliard's avatar
Alexandre Julliard committed
106
static void
107
NC_AdjustRectOuter (LPRECT rect, DWORD style, BOOL menu, DWORD exStyle)
Alexandre Julliard's avatar
Alexandre Julliard committed
108
{
109
    int adjust;
Alexandre Julliard's avatar
Alexandre Julliard committed
110 111
    if(style & WS_ICONIC) return;

112
    if ((exStyle & (WS_EX_STATICEDGE|WS_EX_DLGMODALFRAME)) ==
113 114 115 116 117 118 119 120 121 122 123 124 125
        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 */
126
    if ((style & (WS_BORDER|WS_DLGFRAME)) ||
127 128 129 130
        (exStyle & WS_EX_DLGMODALFRAME))
        adjust++; /* The other border */

    InflateRect (rect, adjust, adjust);
131 132

    if ((style & WS_CAPTION) == WS_CAPTION)
Alexandre Julliard's avatar
Alexandre Julliard committed
133
    {
134 135
        if (exStyle & WS_EX_TOOLWINDOW)
            rect->top -= GetSystemMetrics(SM_CYSMCAPTION);
Alexandre Julliard's avatar
Alexandre Julliard committed
136
        else
137
            rect->top -= GetSystemMetrics(SM_CYCAPTION);
Alexandre Julliard's avatar
Alexandre Julliard committed
138
    }
139
    if (menu) rect->top -= GetSystemMetrics(SM_CYMENU);
Alexandre Julliard's avatar
Alexandre Julliard committed
140 141 142 143
}


/******************************************************************************
144
 * NC_AdjustRectInner
Alexandre Julliard's avatar
Alexandre Julliard committed
145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
 *
 * Computes the size of the "inside" part of the window based on the
 * parameters of the client area.
 *
 + PARAMS
 *     LPRECT16 rect
 *     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
162
NC_AdjustRectInner (LPRECT rect, DWORD style, DWORD exStyle)
Alexandre Julliard's avatar
Alexandre Julliard committed
163 164 165 166
{
    if(style & WS_ICONIC) return;

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

169 170 171 172 173 174 175
    if (style & WS_VSCROLL)
    {
        if((exStyle & WS_EX_LEFTSCROLLBAR) != 0)
            rect->left  -= GetSystemMetrics(SM_CXVSCROLL);
        else
            rect->right += GetSystemMetrics(SM_CXVSCROLL);
    }
176
    if (style & WS_HSCROLL) rect->bottom += GetSystemMetrics(SM_CYHSCROLL);
Alexandre Julliard's avatar
Alexandre Julliard committed
177 178 179
}


180 181 182

static HICON NC_IconForWindow( HWND hwnd )
{
183 184 185 186 187 188 189 190 191 192
    HICON hIcon = 0;
    WND *wndPtr = WIN_GetPtr( hwnd );

    if (wndPtr && wndPtr != WND_OTHER_PROCESS)
    {
        hIcon = wndPtr->hIconSmall;
        if (!hIcon) hIcon = wndPtr->hIcon;
        WIN_ReleasePtr( wndPtr );
    }
    if (!hIcon) hIcon = (HICON) GetClassLongA( hwnd, GCL_HICONSM );
193 194 195 196 197 198
    if (!hIcon) hIcon = (HICON) GetClassLongA( hwnd, GCL_HICON );

    /* If there is no hIcon specified and this is a modal dialog,
     * get the default one.
     */
    if (!hIcon && (GetWindowLongA( hwnd, GWL_STYLE ) & DS_MODALFRAME))
199
        hIcon = LoadImageA(0, (LPSTR)IDI_WINLOGO, IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR);
200 201 202
    return hIcon;
}

203
/***********************************************************************
204
 *		DrawCaption (USER32.@) Draws a caption bar
205 206 207 208 209 210 211
 *
 * PARAMS
 *     hwnd   [I]
 *     hdc    [I]
 *     lpRect [I]
 *     uFlags [I]
 *
212 213 214
 * RETURNS
 *     Success:
 *     Failure:
215 216
 */

217 218
BOOL WINAPI
DrawCaption (HWND hwnd, HDC hdc, const RECT *lpRect, UINT uFlags)
219
{
220
    return DrawCaptionTempA (hwnd, hdc, lpRect, 0, 0, NULL, uFlags & 0x1F);
221 222 223 224
}


/***********************************************************************
225
 *		DrawCaptionTempA (USER32.@)
226
 */
227 228 229 230 231 232
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;
233

234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252
    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)
253
{
254
    RECT   rc = *rect;
255

256
    TRACE("(%p,%p,%p,%p,%p,%s,%08x)\n",
257
          hwnd, hdc, rect, hFont, hIcon, debugstr_w(str), uFlags);
258 259 260

    /* drawing background */
    if (uFlags & DC_INBUTTON) {
261
	FillRect (hdc, &rc, GetSysColorBrush (COLOR_3DFACE));
262 263

	if (uFlags & DC_ACTIVE) {
264 265
	    HBRUSH hbr = SelectObject (hdc, CACHE_GetPattern55AABrush ());
	    PatBlt (hdc, rc.left, rc.top,
266
		      rc.right-rc.left, rc.bottom-rc.top, 0xFA0089);
267
	    SelectObject (hdc, hbr);
268 269 270
	}
    }
    else {
271
	FillRect (hdc, &rc, GetSysColorBrush ((uFlags & DC_ACTIVE) ?
272 273 274 275 276 277
		    COLOR_ACTIVECAPTION : COLOR_INACTIVECAPTION));
    }


    /* drawing icon */
    if ((uFlags & DC_ICON) && !(uFlags & DC_SMALLCAP)) {
278
	POINT pt;
279 280

	pt.x = rc.left + 2;
281
	pt.y = (rc.bottom + rc.top - GetSystemMetrics(SM_CYSMICON)) / 2;
282

283 284 285
        if (!hIcon) hIcon = NC_IconForWindow(hwnd);
        DrawIconEx (hdc, pt.x, pt.y, hIcon, GetSystemMetrics(SM_CXSMICON),
                    GetSystemMetrics(SM_CYSMICON), 0, 0, DI_NORMAL);
286 287 288 289 290
	rc.left += (rc.bottom - rc.top);
    }

    /* drawing text */
    if (uFlags & DC_TEXT) {
291
	HFONT hOldFont;
292 293

	if (uFlags & DC_INBUTTON)
294
	    SetTextColor (hdc, GetSysColor (COLOR_BTNTEXT));
295
	else if (uFlags & DC_ACTIVE)
296
	    SetTextColor (hdc, GetSysColor (COLOR_CAPTIONTEXT));
297
	else
298
	    SetTextColor (hdc, GetSysColor (COLOR_INACTIVECAPTIONTEXT));
299

300
	SetBkMode (hdc, TRANSPARENT);
301 302

	if (hFont)
303
	    hOldFont = SelectObject (hdc, hFont);
304
	else {
305
	    NONCLIENTMETRICSW nclm;
306
	    HFONT hNewFont;
307
	    nclm.cbSize = sizeof(NONCLIENTMETRICSW);
308 309
	    SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, 0, &nclm, 0);
	    hNewFont = CreateFontIndirectW ((uFlags & DC_SMALLCAP) ?
310
		&nclm.lfSmCaptionFont : &nclm.lfCaptionFont);
311
	    hOldFont = SelectObject (hdc, hNewFont);
312 313 314
	}

	if (str)
315
	    DrawTextW (hdc, str, -1, &rc,
316 317
			 DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX | DT_LEFT);
	else {
318
	    WCHAR szText[128];
319
	    INT nLen;
320 321
	    nLen = GetWindowTextW (hwnd, szText, 128);
	    DrawTextW (hdc, szText, nLen, &rc,
322 323 324 325
			 DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX | DT_LEFT);
	}

	if (hFont)
326
	    SelectObject (hdc, hOldFont);
327
	else
328
	    DeleteObject (SelectObject (hdc, hOldFont));
329 330 331 332
    }

    /* drawing focus ??? */
    if (uFlags & 0x2000)
333
	FIXME("undocumented flag (0x2000)!\n");
334 335 336 337 338

    return 0;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
339
/***********************************************************************
340
 *		AdjustWindowRect (USER.102)
Alexandre Julliard's avatar
Alexandre Julliard committed
341
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
342
BOOL16 WINAPI AdjustWindowRect16( LPRECT16 rect, DWORD style, BOOL16 menu )
Alexandre Julliard's avatar
Alexandre Julliard committed
343
{
Alexandre Julliard's avatar
Alexandre Julliard committed
344
    return AdjustWindowRectEx16( rect, style, menu, 0 );
Alexandre Julliard's avatar
Alexandre Julliard committed
345 346 347 348
}


/***********************************************************************
349
 *		AdjustWindowRect (USER32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
350
 */
351
BOOL WINAPI AdjustWindowRect( LPRECT rect, DWORD style, BOOL menu )
Alexandre Julliard's avatar
Alexandre Julliard committed
352
{
353
    return AdjustWindowRectEx( rect, style, menu, 0 );
Alexandre Julliard's avatar
Alexandre Julliard committed
354 355 356 357
}


/***********************************************************************
358
 *		AdjustWindowRectEx (USER.454)
Alexandre Julliard's avatar
Alexandre Julliard committed
359
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
360 361
BOOL16 WINAPI AdjustWindowRectEx16( LPRECT16 rect, DWORD style,
                                    BOOL16 menu, DWORD exStyle )
Alexandre Julliard's avatar
Alexandre Julliard committed
362
{
363 364 365 366 367 368 369 370 371
    RECT rect32;
    BOOL ret;

    CONV_RECT16TO32( rect, &rect32 );
    ret = AdjustWindowRectEx( &rect32, style, menu, exStyle );
    CONV_RECT32TO16( &rect32, rect );
    return ret;
}

Alexandre Julliard's avatar
Alexandre Julliard committed
372

373 374 375 376 377 378
/***********************************************************************
 *		AdjustWindowRectEx (USER32.@)
 */
BOOL WINAPI AdjustWindowRectEx( LPRECT rect, DWORD style, BOOL menu, DWORD exStyle )
{
    /* Correct the window style */
Alexandre Julliard's avatar
Alexandre Julliard committed
379
    style &= (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME | WS_CHILD);
Alexandre Julliard's avatar
Alexandre Julliard committed
380
    exStyle &= (WS_EX_DLGMODALFRAME | WS_EX_CLIENTEDGE |
381
                WS_EX_STATICEDGE | WS_EX_TOOLWINDOW);
Alexandre Julliard's avatar
Alexandre Julliard committed
382 383
    if (exStyle & WS_EX_DLGMODALFRAME) style &= ~WS_THICKFRAME;

384
    TRACE("(%ld,%ld)-(%ld,%ld) %08lx %d %08lx\n",
385 386
          rect->left, rect->top, rect->right, rect->bottom,
          style, menu, exStyle );
Alexandre Julliard's avatar
Alexandre Julliard committed
387

388 389 390
    NC_AdjustRectOuter( rect, style, menu, exStyle );
    NC_AdjustRectInner( rect, style, exStyle );

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


/***********************************************************************
 *           NC_HandleNCCalcSize
 *
 * Handle a WM_NCCALCSIZE message. Called from DefWindowProc().
 */
400
LONG NC_HandleNCCalcSize( HWND hwnd, RECT *winRect )
Alexandre Julliard's avatar
Alexandre Julliard committed
401
{
402
    RECT tmpRect = { 0, 0, 0, 0 };
Alexandre Julliard's avatar
Alexandre Julliard committed
403
    LONG result = 0;
404 405 406
    LONG cls_style = GetClassLongA(hwnd, GCL_STYLE);
    LONG style = GetWindowLongA( hwnd, GWL_STYLE );
    LONG exStyle = GetWindowLongA( hwnd, GWL_EXSTYLE );
Alexandre Julliard's avatar
Alexandre Julliard committed
407

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

411 412
    if (!IsIconic(hwnd))
    {
413
	NC_AdjustRectOuter( &tmpRect, style, FALSE, exStyle );
Alexandre Julliard's avatar
Alexandre Julliard committed
414 415 416 417 418 419

	winRect->left   -= tmpRect.left;
	winRect->top    -= tmpRect.top;
	winRect->right  -= tmpRect.right;
	winRect->bottom -= tmpRect.bottom;

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

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

431 432 433 434 435 436
	SetRect(&tmpRect, 0, 0, 0, 0);
	NC_AdjustRectInner (&tmpRect, style, exStyle);
	winRect->left   -= tmpRect.left;
	winRect->top    -= tmpRect.top;
	winRect->right  -= tmpRect.right;
	winRect->bottom -= tmpRect.bottom;
437 438 439 440 441 442

        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
443
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
444
    return result;
Alexandre Julliard's avatar
Alexandre Julliard committed
445 446 447 448
}


/***********************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
449
 *           NC_GetInsideRect
Alexandre Julliard's avatar
Alexandre Julliard committed
450
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
451 452 453
 * 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
454
 */
455
void NC_GetInsideRect( HWND hwnd, RECT *rect )
Alexandre Julliard's avatar
Alexandre Julliard committed
456 457 458 459 460 461 462
{
    WND * wndPtr = WIN_FindWndPtr( hwnd );

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

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

Alexandre Julliard's avatar
Alexandre Julliard committed
465
    /* Remove frame from rectangle */
466
    if (HAS_THICKFRAME( wndPtr->dwStyle, wndPtr->dwExStyle ))
Alexandre Julliard's avatar
Alexandre Julliard committed
467
    {
468
        InflateRect( rect, -GetSystemMetrics(SM_CXFRAME), -GetSystemMetrics(SM_CYFRAME) );
Alexandre Julliard's avatar
Alexandre Julliard committed
469
    }
470
    else if (HAS_DLGFRAME( wndPtr->dwStyle, wndPtr->dwExStyle ))
Alexandre Julliard's avatar
Alexandre Julliard committed
471
    {
472
        InflateRect( rect, -GetSystemMetrics(SM_CXDLGFRAME), -GetSystemMetrics(SM_CYDLGFRAME));
Alexandre Julliard's avatar
Alexandre Julliard committed
473
    }
474
    else if (HAS_THINFRAME( wndPtr->dwStyle ))
Alexandre Julliard's avatar
Alexandre Julliard committed
475
    {
476
        InflateRect( rect, -GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER) );
Alexandre Julliard's avatar
Alexandre Julliard committed
477 478
    }

479 480
    /* We have additional border information if the window
     * is a child (but not an MDI child) */
481 482
    if ( (wndPtr->dwStyle & WS_CHILD)  &&
         ( (wndPtr->dwExStyle & WS_EX_MDICHILD) == 0 ) )
483
    {
484 485 486 487
        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
488
    }
489

490 491
END:
    WIN_ReleaseWndPtr(wndPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
492 493 494 495
    return;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
496
/***********************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
497
 * NC_DoNCHitTest
Alexandre Julliard's avatar
Alexandre Julliard committed
498
 *
Andreas Mohr's avatar
Andreas Mohr committed
499
 * Handle a WM_NCHITTEST message. Called from NC_HandleNCHitTest().
Alexandre Julliard's avatar
Alexandre Julliard committed
500
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
501
 * FIXME:  Just a modified copy of the Win 3.1 version.
Alexandre Julliard's avatar
Alexandre Julliard committed
502 503
 */

504
static LONG NC_DoNCHitTest (WND *wndPtr, POINT pt )
Alexandre Julliard's avatar
Alexandre Julliard committed
505
{
506
    RECT rect;
Alexandre Julliard's avatar
Alexandre Julliard committed
507

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

510 511
    GetWindowRect(wndPtr->hwndSelf, &rect );
    if (!PtInRect( &rect, pt )) return HTNOWHERE;
Alexandre Julliard's avatar
Alexandre Julliard committed
512 513 514

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

515 516
    /* Check borders */
    if (HAS_THICKFRAME( wndPtr->dwStyle, wndPtr->dwExStyle ))
Alexandre Julliard's avatar
Alexandre Julliard committed
517
    {
518 519
        InflateRect( &rect, -GetSystemMetrics(SM_CXFRAME), -GetSystemMetrics(SM_CYFRAME) );
        if (!PtInRect( &rect, pt ))
Alexandre Julliard's avatar
Alexandre Julliard committed
520
        {
521 522
            /* Check top sizing border */
            if (pt.y < rect.top)
Alexandre Julliard's avatar
Alexandre Julliard committed
523
            {
524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547
                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
548 549
            }
        }
550 551 552 553 554 555 556 557 558
    }
    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
559

560
    /* Check caption */
Alexandre Julliard's avatar
Alexandre Julliard committed
561

562 563 564 565 566 567 568
    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
569
        {
570 571
            /* Check system menu */
            if ((wndPtr->dwStyle & WS_SYSMENU) && !(wndPtr->dwExStyle & WS_EX_TOOLWINDOW))
Alexandre Julliard's avatar
Alexandre Julliard committed
572
            {
573 574
                if (NC_IconForWindow(wndPtr->hwndSelf))
                    rect.left += GetSystemMetrics(SM_CYCAPTION) - 1;
Alexandre Julliard's avatar
Alexandre Julliard committed
575
            }
576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595
            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*/
            if ((wndPtr->dwStyle & WS_MAXIMIZEBOX)|| (wndPtr->dwStyle & WS_MINIMIZEBOX))
                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*/
            if ((wndPtr->dwStyle & WS_MINIMIZEBOX)||(wndPtr->dwStyle & WS_MAXIMIZEBOX))
                rect.right -= GetSystemMetrics(SM_CXSIZE) + 1;

            if (pt.x > rect.right) return HTMINBUTTON;
            return HTCAPTION;
Alexandre Julliard's avatar
Alexandre Julliard committed
596 597 598 599 600
        }
    }

      /* Check client area */

601 602 603
    ScreenToClient( wndPtr->hwndSelf, &pt );
    GetClientRect( wndPtr->hwndSelf, &rect );
    if (PtInRect( &rect, pt )) return HTCLIENT;
Alexandre Julliard's avatar
Alexandre Julliard committed
604 605 606 607

      /* Check vertical scroll bar */

    if (wndPtr->dwStyle & WS_VSCROLL)
Alexandre Julliard's avatar
Alexandre Julliard committed
608
    {
609 610 611 612 613
        if((wndPtr->dwExStyle & WS_EX_LEFTSCROLLBAR) != 0)
            rect.left -= GetSystemMetrics(SM_CXVSCROLL);
        else
            rect.right += GetSystemMetrics(SM_CXVSCROLL);
        if (PtInRect( &rect, pt )) return HTVSCROLL;
Alexandre Julliard's avatar
Alexandre Julliard committed
614
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
615 616 617 618

      /* Check horizontal scroll bar */

    if (wndPtr->dwStyle & WS_HSCROLL)
Alexandre Julliard's avatar
Alexandre Julliard committed
619
    {
620
	rect.bottom += GetSystemMetrics(SM_CYHSCROLL);
621
	if (PtInRect( &rect, pt ))
Alexandre Julliard's avatar
Alexandre Julliard committed
622 623 624
	{
	      /* Check size box */
	    if ((wndPtr->dwStyle & WS_VSCROLL) &&
625 626
		((((wndPtr->dwExStyle & WS_EX_LEFTSCROLLBAR) != 0) && (pt.x <= rect.left + GetSystemMetrics(SM_CXVSCROLL))) ||
		(((wndPtr->dwExStyle & WS_EX_LEFTSCROLLBAR) == 0) && (pt.x >= rect.right - GetSystemMetrics(SM_CXVSCROLL)))))
Alexandre Julliard's avatar
Alexandre Julliard committed
627 628 629
		return HTSIZE;
	    return HTHSCROLL;
	}
Alexandre Julliard's avatar
Alexandre Julliard committed
630 631
    }

Alexandre Julliard's avatar
Alexandre Julliard committed
632 633 634
      /* Check menu bar */

    if (HAS_MENU(wndPtr))
Alexandre Julliard's avatar
Alexandre Julliard committed
635
    {
Alexandre Julliard's avatar
Alexandre Julliard committed
636 637
	if ((pt.y < 0) && (pt.x >= 0) && (pt.x < rect.right))
	    return HTMENU;
Alexandre Julliard's avatar
Alexandre Julliard committed
638 639
    }

640
    /* Has to return HTNOWHERE if nothing was found
641 642
       Could happen when a window has a customized non client area */
    return HTNOWHERE;
Alexandre Julliard's avatar
Alexandre Julliard committed
643 644 645
}


Alexandre Julliard's avatar
Alexandre Julliard committed
646 647 648 649 650
/***********************************************************************
 * NC_HandleNCHitTest
 *
 * Handle a WM_NCHITTEST message. Called from DefWindowProc().
 */
651
LONG NC_HandleNCHitTest (HWND hwnd , POINT pt)
Alexandre Julliard's avatar
Alexandre Julliard committed
652
{
653
    LONG retvalue;
Alexandre Julliard's avatar
Alexandre Julliard committed
654
    WND *wndPtr = WIN_FindWndPtr (hwnd);
Alexandre Julliard's avatar
Alexandre Julliard committed
655 656 657 658

    if (!wndPtr)
	return HTERROR;

659
    retvalue = NC_DoNCHitTest (wndPtr, pt);
660 661
    WIN_ReleaseWndPtr(wndPtr);
    return retvalue;
Alexandre Julliard's avatar
Alexandre Julliard committed
662 663 664
}


Alexandre Julliard's avatar
Alexandre Julliard committed
665 666
/******************************************************************************
 *
667
 *   NC_DrawSysButton
Alexandre Julliard's avatar
Alexandre Julliard committed
668
 *
669
 *   Draws the system icon.
Alexandre Julliard's avatar
Alexandre Julliard committed
670 671
 *
 *****************************************************************************/
672
BOOL NC_DrawSysButton (HWND hwnd, HDC hdc, BOOL down)
Alexandre Julliard's avatar
Alexandre Julliard committed
673
{
674
    HICON hIcon = NC_IconForWindow( hwnd );
Alexandre Julliard's avatar
Alexandre Julliard committed
675

676
    if (hIcon)
Alexandre Julliard's avatar
Alexandre Julliard committed
677
    {
678 679
        RECT rect;
        NC_GetInsideRect( hwnd, &rect );
680 681 682
        DrawIconEx (hdc, rect.left + 1, rect.top + 1, hIcon,
                    GetSystemMetrics(SM_CXSIZE) - 1,
                    GetSystemMetrics(SM_CYSIZE) - 1, 0, 0, DI_NORMAL);
Alexandre Julliard's avatar
Alexandre Julliard committed
683
    }
684
    return (hIcon != 0);
Alexandre Julliard's avatar
Alexandre Julliard committed
685 686 687 688 689
}


/******************************************************************************
 *
690
 *   NC_DrawCloseButton
Alexandre Julliard's avatar
Alexandre Julliard committed
691
 *
692
 *   Draws the close button.
Alexandre Julliard's avatar
Alexandre Julliard committed
693
 *
694 695
 *   If bGrayed is true, then draw a disabled Close button
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
696 697
 *****************************************************************************/

698
static void NC_DrawCloseButton (HWND hwnd, HDC hdc, BOOL down, BOOL bGrayed)
Alexandre Julliard's avatar
Alexandre Julliard committed
699
{
700
    RECT rect;
Alexandre Julliard's avatar
Alexandre Julliard committed
701

702 703 704 705
    NC_GetInsideRect( hwnd, &rect );

    /* A tool window has a smaller Close button */
    if (GetWindowLongA( hwnd, GWL_EXSTYLE ) & WS_EX_TOOLWINDOW)
Alexandre Julliard's avatar
Alexandre Julliard committed
706
    {
707 708 709
        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
710

711 712 713 714
        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
715
    }
716 717 718 719 720 721 722 723 724 725 726
    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
727 728 729
}

/******************************************************************************
730
 *   NC_DrawMaxButton
Alexandre Julliard's avatar
Alexandre Julliard committed
731
 *
732
 *   Draws the maximize button for windows.
733
 *   If bGrayed is true, then draw a disabled Maximize button
734
 */
735
static void NC_DrawMaxButton(HWND hwnd,HDC hdc,BOOL down, BOOL bGrayed)
Alexandre Julliard's avatar
Alexandre Julliard committed
736
{
737
    RECT rect;
738 739 740 741 742 743 744 745 746 747 748 749
    UINT flags = IsZoomed(hwnd) ? DFCS_CAPTIONRESTORE : DFCS_CAPTIONMAX;

    NC_GetInsideRect( hwnd, &rect );
    if (GetWindowLongA( hwnd, GWL_STYLE) & WS_SYSMENU)
        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
750 751 752
}

/******************************************************************************
753
 *   NC_DrawMinButton
Alexandre Julliard's avatar
Alexandre Julliard committed
754
 *
755
 *   Draws the minimize button for windows.
756
 *   If bGrayed is true, then draw a disabled Minimize button
757
 */
758
static void  NC_DrawMinButton(HWND hwnd,HDC hdc,BOOL down, BOOL bGrayed)
Alexandre Julliard's avatar
Alexandre Julliard committed
759
{
760
    RECT rect;
761 762
    UINT flags = DFCS_CAPTIONMIN;
    DWORD style = GetWindowLongA( hwnd, GWL_STYLE );
Alexandre Julliard's avatar
Alexandre Julliard committed
763

764 765 766 767 768 769 770 771 772 773 774 775
    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
776 777 778 779
}

/******************************************************************************
 *
780
 *   NC_DrawFrame
Alexandre Julliard's avatar
Alexandre Julliard committed
781 782 783 784 785
 *
 *   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
786
 *        on the outer edge is handled by NC_DoNCPaint.  As is the inner
Alexandre Julliard's avatar
Alexandre Julliard committed
787 788 789 790 791 792 793
 *        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...
794
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
795 796
 *****************************************************************************/

797
static void  NC_DrawFrame( HDC  hdc, RECT  *rect, BOOL  active, DWORD style, DWORD exStyle)
Alexandre Julliard's avatar
Alexandre Julliard committed
798
{
799
    INT width, height;
Alexandre Julliard's avatar
Alexandre Julliard committed
800

801 802
    /* Firstly the "thick" frame */
    if (style & WS_THICKFRAME)
Alexandre Julliard's avatar
Alexandre Julliard committed
803
    {
804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819
	width = GetSystemMetrics(SM_CXFRAME) - GetSystemMetrics(SM_CXDLGFRAME);
	height = GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYDLGFRAME);

        SelectObject( hdc, GetSysColorBrush(active ? COLOR_ACTIVEBORDER :
		      COLOR_INACTIVEBORDER) );
        /* 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
820
    }
821 822 823 824

    /* Now the other bit of the frame */
    if ((style & (WS_BORDER|WS_DLGFRAME)) ||
        (exStyle & WS_EX_DLGMODALFRAME))
Alexandre Julliard's avatar
Alexandre Julliard committed
825
    {
826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850
        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
851 852 853
    }
}

Alexandre Julliard's avatar
Alexandre Julliard committed
854

Alexandre Julliard's avatar
Alexandre Julliard committed
855 856
/******************************************************************************
 *
857
 *   NC_DrawCaption
Alexandre Julliard's avatar
Alexandre Julliard committed
858
 *
859
 *   Draw the window caption for windows.
Alexandre Julliard's avatar
Alexandre Julliard committed
860 861 862 863
 *   The correct pen for the window frame must be selected in the DC.
 *
 *****************************************************************************/

864 865
static void  NC_DrawCaption( HDC  hdc, RECT *rect, HWND hwnd, DWORD  style, 
                             DWORD  exStyle, BOOL active )
Alexandre Julliard's avatar
Alexandre Julliard committed
866
{
867
    RECT  r = *rect;
Alexandre Julliard's avatar
Alexandre Julliard committed
868
    char    buffer[256];
869
    HPEN  hPrevPen;
870
    HMENU hSysMenu;
Alexandre Julliard's avatar
Alexandre Julliard committed
871

872
    hPrevPen = SelectObject( hdc, SYSCOLOR_GetPen(
873 874 875
                     ((exStyle & (WS_EX_STATICEDGE|WS_EX_CLIENTEDGE|
                                 WS_EX_DLGMODALFRAME)) == WS_EX_STATICEDGE) ?
                      COLOR_WINDOWFRAME : COLOR_3DFACE) );
876 877 878
    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
879 880
    r.bottom--;

881
    FillRect( hdc, &r, GetSysColorBrush(active ? COLOR_ACTIVECAPTION :
Alexandre Julliard's avatar
Alexandre Julliard committed
882
					    COLOR_INACTIVECAPTION) );
Alexandre Julliard's avatar
Alexandre Julliard committed
883

884
    if ((style & WS_SYSMENU) && !(exStyle & WS_EX_TOOLWINDOW)) {
885
	if (NC_DrawSysButton (hwnd, hdc, FALSE))
886
	    r.left += GetSystemMetrics(SM_CYCAPTION) - 1;
887
    }
888

889
    if (style & WS_SYSMENU)
890 891 892 893 894 895 896 897
    {
	UINT state;

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

	/* Draw a grayed close button if disabled and a normal one if SC_CLOSE is not there */
898 899
	NC_DrawCloseButton (hwnd, hdc, FALSE,
			    ((((state & MF_DISABLED) || (state & MF_GRAYED))) && (state != 0xFFFFFFFF)));
900
	r.right -= GetSystemMetrics(SM_CYCAPTION) - 1;
901 902 903 904 905 906

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

907
	    NC_DrawMaxButton( hwnd, hdc, FALSE, (!(style & WS_MAXIMIZEBOX)));
908
	    r.right -= GetSystemMetrics(SM_CXSIZE) + 1;
909

910
	    NC_DrawMinButton( hwnd, hdc, FALSE,  (!(style & WS_MINIMIZEBOX)));
911 912
	    r.right -= GetSystemMetrics(SM_CXSIZE) + 1;
	}
Alexandre Julliard's avatar
Alexandre Julliard committed
913 914
    }

915 916 917 918 919
    if (GetWindowTextA( hwnd, buffer, sizeof(buffer) )) {
	NONCLIENTMETRICSA nclm;
	HFONT hFont, hOldFont;
	nclm.cbSize = sizeof(NONCLIENTMETRICSA);
	SystemParametersInfoA (SPI_GETNONCLIENTMETRICS, 0, &nclm, 0);
920
	if (exStyle & WS_EX_TOOLWINDOW)
921
	    hFont = CreateFontIndirectA (&nclm.lfSmCaptionFont);
922
	else
923 924 925 926 927
	    hFont = CreateFontIndirectA (&nclm.lfCaptionFont);
	hOldFont = SelectObject (hdc, hFont);
	if (active) SetTextColor( hdc, GetSysColor( COLOR_CAPTIONTEXT ) );
	else SetTextColor( hdc, GetSysColor( COLOR_INACTIVECAPTIONTEXT ) );
	SetBkMode( hdc, TRANSPARENT );
Alexandre Julliard's avatar
Alexandre Julliard committed
928
	r.left += 2;
929
	DrawTextA( hdc, buffer, -1, &r,
Alexandre Julliard's avatar
Alexandre Julliard committed
930
		     DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX | DT_LEFT );
931
	DeleteObject (SelectObject (hdc, hOldFont));
Alexandre Julliard's avatar
Alexandre Julliard committed
932 933 934 935 936 937
    }
}


/******************************************************************************
 *
938
 *   NC_DoNCPaint
Alexandre Julliard's avatar
Alexandre Julliard committed
939
 *
940
 *   Paint the non-client area for windows.  The clip region is
Alexandre Julliard's avatar
Alexandre Julliard committed
941 942 943 944 945 946 947 948
 *   currently ignored.
 *
 *   Bugs
 *        grep -E -A10 -B5 \(95\)\|\(Bugs\)\|\(FIXME\) windows/nonclient.c \
 *           misc/tweak.c controls/menu.c  # :-)
 *
 *****************************************************************************/

949
static void  NC_DoNCPaint( HWND  hwnd, HRGN  clip, BOOL  suppress_menupaint )
Alexandre Julliard's avatar
Alexandre Julliard committed
950
{
951
    HDC hdc;
952
    RECT rfuzz, rect, rectClip;
953
    BOOL active;
954 955 956 957 958 959 960 961 962
    WND *wndPtr;
    DWORD dwStyle, dwExStyle;
    WORD flags;
    RECT rectClient, rectWindow;
    int has_menu;

    if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return;
    has_menu = HAS_MENU(wndPtr);
    dwStyle = wndPtr->dwStyle;
963
    dwExStyle = wndPtr->dwExStyle;
964 965 966 967 968 969
    flags = wndPtr->flags;
    rectClient = wndPtr->rectClient;
    rectWindow = wndPtr->rectWindow;
    WIN_ReleasePtr( wndPtr );

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

972
    active  = flags & WIN_NCACTIVATED;
Alexandre Julliard's avatar
Alexandre Julliard committed
973

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

976 977 978 979 980
    /* 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?
981 982
     */

983 984
    if (!(hdc = GetDCEx( hwnd, (clip > (HRGN)1) ? clip : 0, DCX_USESTYLE | DCX_WINDOW |
			      ((clip > (HRGN)1) ?(DCX_INTERSECTRGN | DCX_KEEPCLIPRGN) : 0) ))) return;
985

Alexandre Julliard's avatar
Alexandre Julliard committed
986

987
    if (ExcludeVisRect16( HDC_16(hdc), rectClient.left-rectWindow.left,
988 989 990
		        rectClient.top-rectWindow.top,
		        rectClient.right-rectWindow.left,
		        rectClient.bottom-rectWindow.top )
Alexandre Julliard's avatar
Alexandre Julliard committed
991 992
	== NULLREGION)
    {
993
	ReleaseDC( hwnd, hdc );
Alexandre Julliard's avatar
Alexandre Julliard committed
994 995 996 997
	return;
    }

    rect.top = rect.left = 0;
998 999
    rect.right  = rectWindow.right - rectWindow.left;
    rect.bottom = rectWindow.bottom - rectWindow.top;
Alexandre Julliard's avatar
Alexandre Julliard committed
1000

1001
    if( clip > (HRGN)1 )
1002 1003 1004 1005 1006 1007 1008
	GetRgnBox( clip, &rectClip );
    else
    {
	clip = 0;
	rectClip = rect;
    }

1009
    SelectObject( hdc, SYSCOLOR_GetPen(COLOR_WINDOWFRAME) );
Alexandre Julliard's avatar
Alexandre Julliard committed
1010

1011
    if (HAS_STATICOUTERFRAME(dwStyle, dwExStyle)) {
1012
        DrawEdge (hdc, &rect, BDR_SUNKENOUTER, BF_RECT | BF_ADJUST);
1013
    }
1014
    else if (HAS_BIGFRAME( dwStyle, dwExStyle)) {
1015
        DrawEdge (hdc, &rect, EDGE_RAISED, BF_RECT | BF_ADJUST);
1016
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1017

1018
    NC_DrawFrame(hdc, &rect, active, dwStyle, dwExStyle );
1019

1020
    if ((dwStyle & WS_CAPTION) == WS_CAPTION)
1021 1022
    {
        RECT  r = rect;
1023
        if (dwExStyle & WS_EX_TOOLWINDOW) {
1024 1025
            r.bottom = rect.top + GetSystemMetrics(SM_CYSMCAPTION);
            rect.top += GetSystemMetrics(SM_CYSMCAPTION);
Alexandre Julliard's avatar
Alexandre Julliard committed
1026
        }
1027 1028 1029 1030 1031
        else {
            r.bottom = rect.top + GetSystemMetrics(SM_CYCAPTION);
            rect.top += GetSystemMetrics(SM_CYCAPTION);
        }
        if( !clip || IntersectRect( &rfuzz, &r, &rectClip ) )
1032
            NC_DrawCaption(hdc, &r, hwnd, dwStyle, dwExStyle, active);
Alexandre Julliard's avatar
Alexandre Julliard committed
1033 1034
    }

1035
    if (has_menu)
Alexandre Julliard's avatar
Alexandre Julliard committed
1036
    {
1037
	RECT r = rect;
1038
	r.bottom = rect.top + GetSystemMetrics(SM_CYMENU);
1039

1040
	TRACE("Calling DrawMenuBar with rect (%ld, %ld)-(%ld, %ld)\n",
1041
              r.left, r.top, r.right, r.bottom);
Alexandre Julliard's avatar
Alexandre Julliard committed
1042

Alexandre Julliard's avatar
Alexandre Julliard committed
1043
	rect.top += MENU_DrawMenuBar( hdc, &r, hwnd, suppress_menupaint ) + 1;
Alexandre Julliard's avatar
Alexandre Julliard committed
1044 1045
    }

1046
    TRACE("After MenuBar, rect is (%ld, %ld)-(%ld, %ld).\n",
1047
          rect.left, rect.top, rect.right, rect.bottom );
Alexandre Julliard's avatar
Alexandre Julliard committed
1048

1049
    if (dwExStyle & WS_EX_CLIENTEDGE)
1050
	DrawEdge (hdc, &rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
Alexandre Julliard's avatar
Alexandre Julliard committed
1051 1052 1053

    /* Draw the scroll-bars */

1054
    if (dwStyle & WS_VSCROLL)
1055
        SCROLL_DrawScrollBar( hwnd, hdc, SB_VERT, TRUE, TRUE );
1056
    if (dwStyle & WS_HSCROLL)
1057
        SCROLL_DrawScrollBar( hwnd, hdc, SB_HORZ, TRUE, TRUE );
Alexandre Julliard's avatar
Alexandre Julliard committed
1058 1059

    /* Draw the "size-box" */
1060
    if ((dwStyle & WS_VSCROLL) && (dwStyle & WS_HSCROLL))
Alexandre Julliard's avatar
Alexandre Julliard committed
1061
    {
1062
        RECT r = rect;
1063 1064 1065 1066
        if((dwExStyle & WS_EX_LEFTSCROLLBAR) != 0)
            r.right = r.left + GetSystemMetrics(SM_CXVSCROLL) + 1;
        else
            r.left = r.right - GetSystemMetrics(SM_CXVSCROLL) + 1;
1067
        r.top  = r.bottom - GetSystemMetrics(SM_CYHSCROLL) + 1;
1068
        FillRect( hdc, &r,  GetSysColorBrush(COLOR_SCROLLBAR) );
1069
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1070

1071
    ReleaseDC( hwnd, hdc );
Alexandre Julliard's avatar
Alexandre Julliard committed
1072 1073 1074 1075
}



Alexandre Julliard's avatar
Alexandre Julliard committed
1076

Alexandre Julliard's avatar
Alexandre Julliard committed
1077 1078 1079 1080 1081
/***********************************************************************
 *           NC_HandleNCPaint
 *
 * Handle a WM_NCPAINT message. Called from DefWindowProc().
 */
1082
LONG NC_HandleNCPaint( HWND hwnd , HRGN clip)
Alexandre Julliard's avatar
Alexandre Julliard committed
1083
{
1084
    DWORD dwStyle = GetWindowLongW( hwnd, GWL_STYLE );
Alexandre Julliard's avatar
Alexandre Julliard committed
1085

1086
    if( dwStyle & WS_VISIBLE )
Alexandre Julliard's avatar
Alexandre Julliard committed
1087
    {
1088
	if( dwStyle & WS_MINIMIZE )
Alexandre Julliard's avatar
Alexandre Julliard committed
1089
	    WINPOS_RedrawIconTitle( hwnd );
Alexandre Julliard's avatar
Alexandre Julliard committed
1090
	else
1091
	    NC_DoNCPaint( hwnd, clip, FALSE );
Alexandre Julliard's avatar
Alexandre Julliard committed
1092
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1093 1094 1095 1096 1097
    return 0;
}


/***********************************************************************
Alexandre Julliard's avatar
Alexandre Julliard committed
1098
 *           NC_HandleNCActivate
Alexandre Julliard's avatar
Alexandre Julliard committed
1099
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
1100
 * Handle a WM_NCACTIVATE message. Called from DefWindowProc().
Alexandre Julliard's avatar
Alexandre Julliard committed
1101
 */
1102
LONG NC_HandleNCActivate( HWND hwnd, WPARAM wParam )
Alexandre Julliard's avatar
Alexandre Julliard committed
1103
{
1104 1105
    WND* wndPtr = WIN_FindWndPtr( hwnd );

1106 1107 1108 1109 1110
    /* 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.
     */
1111
    if (wndPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
1112
    {
Alexandre Julliard's avatar
Alexandre Julliard committed
1113 1114
	if (wParam) wndPtr->flags |= WIN_NCACTIVATED;
	else wndPtr->flags &= ~WIN_NCACTIVATED;
1115
        WIN_ReleaseWndPtr(wndPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1116

1117 1118
	if (IsIconic(hwnd)) 
	    WINPOS_RedrawIconTitle( hwnd );
Alexandre Julliard's avatar
Alexandre Julliard committed
1119
	else
1120
	    NC_DoNCPaint( hwnd, (HRGN)1, FALSE );
Alexandre Julliard's avatar
Alexandre Julliard committed
1121
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1122 1123
    return TRUE;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1124

Alexandre Julliard's avatar
Alexandre Julliard committed
1125

Alexandre Julliard's avatar
Alexandre Julliard committed
1126 1127 1128 1129 1130
/***********************************************************************
 *           NC_HandleSetCursor
 *
 * Handle a WM_SETCURSOR message. Called from DefWindowProc().
 */
1131
LONG NC_HandleSetCursor( HWND hwnd, WPARAM wParam, LPARAM lParam )
Alexandre Julliard's avatar
Alexandre Julliard committed
1132
{
1133
    hwnd = WIN_GetFullHandle( (HWND)wParam );
Alexandre Julliard's avatar
Alexandre Julliard committed
1134 1135 1136 1137 1138 1139 1140 1141

    switch(LOWORD(lParam))
    {
    case HTERROR:
	{
	    WORD msg = HIWORD( lParam );
	    if ((msg == WM_LBUTTONDOWN) || (msg == WM_MBUTTONDOWN) ||
		(msg == WM_RBUTTONDOWN))
1142
		MessageBeep(0);
Alexandre Julliard's avatar
Alexandre Julliard committed
1143 1144 1145 1146 1147
	}
	break;

    case HTCLIENT:
	{
1148
	    HCURSOR hCursor = (HCURSOR)GetClassLongA(hwnd, GCL_HCURSOR);
1149
	    if(hCursor) {
1150
		SetCursor(hCursor);
1151
		return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1152
	    }
1153
            return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1154 1155 1156 1157
	}

    case HTLEFT:
    case HTRIGHT:
1158
	return (LONG)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZEWE ) );
Alexandre Julliard's avatar
Alexandre Julliard committed
1159 1160 1161

    case HTTOP:
    case HTBOTTOM:
1162
	return (LONG)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENS ) );
Alexandre Julliard's avatar
Alexandre Julliard committed
1163 1164

    case HTTOPLEFT:
1165
    case HTBOTTOMRIGHT:
1166
	return (LONG)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENWSE ) );
Alexandre Julliard's avatar
Alexandre Julliard committed
1167 1168 1169

    case HTTOPRIGHT:
    case HTBOTTOMLEFT:
1170
	return (LONG)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENESW ) );
Alexandre Julliard's avatar
Alexandre Julliard committed
1171 1172 1173
    }

    /* Default cursor: arrow */
1174
    return (LONG)SetCursor( LoadCursorA( 0, (LPSTR)IDC_ARROW ) );
Alexandre Julliard's avatar
Alexandre Julliard committed
1175 1176
}

Alexandre Julliard's avatar
Alexandre Julliard committed
1177 1178 1179
/***********************************************************************
 *           NC_GetSysPopupPos
 */
1180
void NC_GetSysPopupPos( HWND hwnd, RECT* rect )
Alexandre Julliard's avatar
Alexandre Julliard committed
1181
{
1182 1183 1184 1185 1186 1187 1188 1189 1190
    if (IsIconic(hwnd)) GetWindowRect( hwnd, rect );
    else
    {
        WND *wndPtr = WIN_FindWndPtr( hwnd );
        if (!wndPtr) return;

        NC_GetInsideRect( hwnd, rect );
        OffsetRect( rect, wndPtr->rectWindow.left, wndPtr->rectWindow.top);
        if (wndPtr->dwStyle & WS_CHILD)
1191
            ClientToScreen( GetParent(hwnd), (POINT *)rect );
1192 1193
        rect->right = rect->left + GetSystemMetrics(SM_CYCAPTION) - 1;
        rect->bottom = rect->top + GetSystemMetrics(SM_CYCAPTION) - 1;
1194 1195
        WIN_ReleaseWndPtr( wndPtr );
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1196
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1197

1198
/***********************************************************************
1199
 *           NC_TrackMinMaxBox
1200 1201 1202 1203 1204 1205 1206 1207
 *
 * 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.
 *
 */
1208
static void NC_TrackMinMaxBox( HWND hwnd, WORD wParam )
1209 1210 1211 1212 1213 1214 1215 1216
{
    MSG msg;
    HDC hdc = GetWindowDC( hwnd );
    BOOL pressed = TRUE;
    UINT state;
    DWORD wndStyle = GetWindowLongA( hwnd, GWL_STYLE);
    HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);

1217
    void  (*paintButton)(HWND, HDC, BOOL, BOOL);
1218 1219 1220 1221 1222 1223 1224 1225 1226

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

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

1228
	paintButton = &NC_DrawMinButton;
1229 1230 1231 1232 1233 1234 1235 1236 1237
    }
    else
    {
	/* If the style is not present, do nothing */
	if (!(wndStyle & WS_MAXIMIZEBOX))
	    return;

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

1239
	paintButton = &NC_DrawMaxButton;
1240 1241 1242 1243 1244 1245
    }

    SetCapture( hwnd );

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

1246
    while(1)
1247 1248
    {
	BOOL oldstate = pressed;
1249 1250 1251

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

1253 1254 1255 1256 1257 1258
	if(msg.message == WM_LBUTTONUP)
	    break;

	if(msg.message != WM_MOUSEMOVE)
	    continue;

1259
	pressed = (NC_HandleNCHitTest( hwnd, msg.pt ) == wParam);
1260 1261
	if (pressed != oldstate)
	   (*paintButton)( hwnd, hdc, pressed, FALSE);
1262
    }
1263

1264 1265
    if(pressed)
	(*paintButton)(hwnd, hdc, FALSE, FALSE);
1266 1267 1268 1269 1270 1271 1272 1273 1274

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

1275
    if (wParam == HTMINBUTTON)
1276
        SendMessageA( hwnd, WM_SYSCOMMAND, SC_MINIMIZE, MAKELONG(msg.pt.x,msg.pt.y) );
1277
    else
1278 1279
        SendMessageA( hwnd, WM_SYSCOMMAND,
                      IsZoomed(hwnd) ? SC_RESTORE:SC_MAXIMIZE, MAKELONG(msg.pt.x,msg.pt.y) );
1280 1281
}

Alexandre Julliard's avatar
Alexandre Julliard committed
1282
/***********************************************************************
1283
 * NC_TrackCloseButton
Alexandre Julliard's avatar
Alexandre Julliard committed
1284 1285 1286
 *
 * Track a mouse button press on the Win95 close button.
 */
1287
static void NC_TrackCloseButton (HWND hwnd, WORD wParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
1288
{
1289
    MSG msg;
1290
    HDC hdc;
1291
    BOOL pressed = TRUE;
1292 1293 1294 1295 1296 1297 1298
    HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
    UINT state;

    if(hSysMenu == 0)
	return;

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

1300 1301 1302 1303 1304
    /* If the item close of the sysmenu is disabled or not there do nothing */
    if((state & MF_DISABLED) || (state & MF_GRAYED) || (state == 0xFFFFFFFF))
	return;

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

1306
    SetCapture( hwnd );
Alexandre Julliard's avatar
Alexandre Julliard committed
1307

1308
    NC_DrawCloseButton (hwnd, hdc, TRUE, FALSE);
Alexandre Julliard's avatar
Alexandre Julliard committed
1309

1310
    while(1)
Alexandre Julliard's avatar
Alexandre Julliard committed
1311
    {
1312
	BOOL oldstate = pressed;
1313 1314 1315

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

1317 1318 1319 1320 1321 1322
	if(msg.message == WM_LBUTTONUP)
	    break;

	if(msg.message != WM_MOUSEMOVE)
	    continue;

1323
	pressed = (NC_HandleNCHitTest( hwnd, msg.pt ) == wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1324
	if (pressed != oldstate)
1325
	   NC_DrawCloseButton (hwnd, hdc, pressed, FALSE);
1326
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1327

1328
    if(pressed)
1329
	NC_DrawCloseButton (hwnd, hdc, FALSE, FALSE);
Alexandre Julliard's avatar
Alexandre Julliard committed
1330 1331

    ReleaseCapture();
1332
    ReleaseDC( hwnd, hdc );
Alexandre Julliard's avatar
Alexandre Julliard committed
1333 1334
    if (!pressed) return;

1335
    SendMessageA( hwnd, WM_SYSCOMMAND, SC_CLOSE, MAKELONG(msg.pt.x,msg.pt.y) );
Alexandre Julliard's avatar
Alexandre Julliard committed
1336 1337 1338
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1339 1340 1341 1342 1343
/***********************************************************************
 *           NC_TrackScrollBar
 *
 * Track a mouse button press on the horizontal or vertical scroll-bar.
 */
1344
static void NC_TrackScrollBar( HWND hwnd, WPARAM wParam, POINT pt )
Alexandre Julliard's avatar
Alexandre Julliard committed
1345
{
1346
    INT scrollbar;
Alexandre Julliard's avatar
Alexandre Julliard committed
1347

Alexandre Julliard's avatar
Alexandre Julliard committed
1348 1349
    if ((wParam & 0xfff0) == SC_HSCROLL)
    {
1350
        if ((wParam & 0x0f) != HTHSCROLL) return;
Alexandre Julliard's avatar
Alexandre Julliard committed
1351 1352 1353 1354
	scrollbar = SB_HORZ;
    }
    else  /* SC_VSCROLL */
    {
1355
        if ((wParam & 0x0f) != HTVSCROLL) return;
Alexandre Julliard's avatar
Alexandre Julliard committed
1356 1357
	scrollbar = SB_VERT;
    }
1358
    SCROLL_TrackScrollBar( hwnd, scrollbar, pt );
Alexandre Julliard's avatar
Alexandre Julliard committed
1359 1360
}

1361

Alexandre Julliard's avatar
Alexandre Julliard committed
1362 1363 1364 1365 1366
/***********************************************************************
 *           NC_HandleNCLButtonDown
 *
 * Handle a WM_NCLBUTTONDOWN message. Called from DefWindowProc().
 */
1367
LONG NC_HandleNCLButtonDown( HWND hwnd, WPARAM wParam, LPARAM lParam )
Alexandre Julliard's avatar
Alexandre Julliard committed
1368
{
1369
    LONG style = GetWindowLongA( hwnd, GWL_STYLE );
Alexandre Julliard's avatar
Alexandre Julliard committed
1370

Alexandre Julliard's avatar
Alexandre Julliard committed
1371 1372
    switch(wParam)  /* Hit test */
    {
Alexandre Julliard's avatar
Alexandre Julliard committed
1373
    case HTCAPTION:
1374
        {
1375
            HWND top = GetAncestor( hwnd, GA_ROOT );
Alexandre Julliard's avatar
Alexandre Julliard committed
1376

1377
            if (FOCUS_MouseActivate( top ) || (GetActiveWindow() == top))
1378 1379 1380
                SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOVE + HTCAPTION, lParam );
            break;
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
1381 1382

    case HTSYSMENU:
1383
	 if( style & WS_SYSMENU )
Alexandre Julliard's avatar
Alexandre Julliard committed
1384
	 {
1385
	     if( !(style & WS_MINIMIZE) )
Alexandre Julliard's avatar
Alexandre Julliard committed
1386
	     {
1387
		HDC hDC = GetWindowDC(hwnd);
1388
		NC_DrawSysButton( hwnd, hDC, TRUE );
1389
		ReleaseDC( hwnd, hDC );
Alexandre Julliard's avatar
Alexandre Julliard committed
1390
	     }
1391
	     SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOUSEMENU + HTSYSMENU, lParam );
Alexandre Julliard's avatar
Alexandre Julliard committed
1392 1393
	 }
	 break;
Alexandre Julliard's avatar
Alexandre Julliard committed
1394 1395

    case HTMENU:
1396
	SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOUSEMENU, lParam );
Alexandre Julliard's avatar
Alexandre Julliard committed
1397 1398
	break;

Alexandre Julliard's avatar
Alexandre Julliard committed
1399
    case HTHSCROLL:
1400
	SendMessageW( hwnd, WM_SYSCOMMAND, SC_HSCROLL + HTHSCROLL, lParam );
Alexandre Julliard's avatar
Alexandre Julliard committed
1401 1402
	break;

Alexandre Julliard's avatar
Alexandre Julliard committed
1403
    case HTVSCROLL:
1404
	SendMessageW( hwnd, WM_SYSCOMMAND, SC_VSCROLL + HTVSCROLL, lParam );
Alexandre Julliard's avatar
Alexandre Julliard committed
1405 1406
	break;

Alexandre Julliard's avatar
Alexandre Julliard committed
1407
    case HTMINBUTTON:
Alexandre Julliard's avatar
Alexandre Julliard committed
1408
    case HTMAXBUTTON:
1409
	NC_TrackMinMaxBox( hwnd, wParam );
Alexandre Julliard's avatar
Alexandre Julliard committed
1410 1411
	break;

Alexandre Julliard's avatar
Alexandre Julliard committed
1412
    case HTCLOSE:
1413
	NC_TrackCloseButton (hwnd, wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1414
	break;
1415

Alexandre Julliard's avatar
Alexandre Julliard committed
1416 1417 1418 1419 1420 1421 1422
    case HTLEFT:
    case HTRIGHT:
    case HTTOP:
    case HTTOPLEFT:
    case HTTOPRIGHT:
    case HTBOTTOM:
    case HTBOTTOMLEFT:
Alexandre Julliard's avatar
Alexandre Julliard committed
1423
    case HTBOTTOMRIGHT:
1424 1425 1426 1427 1428 1429 1430 1431 1432
        /* 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);
Alexandre Julliard's avatar
Alexandre Julliard committed
1433 1434 1435
	break;

    case HTBORDER:
Alexandre Julliard's avatar
Alexandre Julliard committed
1436
	break;
Alexandre Julliard's avatar
Alexandre Julliard committed
1437 1438 1439 1440 1441 1442 1443 1444 1445 1446
    }
    return 0;
}


/***********************************************************************
 *           NC_HandleNCLButtonDblClk
 *
 * Handle a WM_NCLBUTTONDBLCLK message. Called from DefWindowProc().
 */
1447
LONG NC_HandleNCLButtonDblClk( HWND hwnd, WPARAM wParam, LPARAM lParam )
Alexandre Julliard's avatar
Alexandre Julliard committed
1448
{
Alexandre Julliard's avatar
Alexandre Julliard committed
1449 1450 1451 1452
    /*
     * if this is an icon, send a restore since we are handling
     * a double click
     */
1453
    if (IsIconic(hwnd))
Alexandre Julliard's avatar
Alexandre Julliard committed
1454
    {
1455
        SendMessageW( hwnd, WM_SYSCOMMAND, SC_RESTORE, lParam );
Alexandre Julliard's avatar
Alexandre Julliard committed
1456
        return 0;
1457
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1458

Alexandre Julliard's avatar
Alexandre Julliard committed
1459 1460 1461
    switch(wParam)  /* Hit test */
    {
    case HTCAPTION:
Alexandre Julliard's avatar
Alexandre Julliard committed
1462
        /* stop processing if WS_MAXIMIZEBOX is missing */
1463 1464 1465
        if (GetWindowLongA( hwnd, GWL_STYLE ) & WS_MAXIMIZEBOX)
            SendMessageW( hwnd, WM_SYSCOMMAND,
                          IsZoomed(hwnd) ? SC_RESTORE : SC_MAXIMIZE, lParam );
Alexandre Julliard's avatar
Alexandre Julliard committed
1466 1467 1468
	break;

    case HTSYSMENU:
1469
        if (!(GetClassLongW(hwnd, GCL_STYLE) & CS_NOCLOSE))
1470
            SendMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, lParam );
Alexandre Julliard's avatar
Alexandre Julliard committed
1471
	break;
Alexandre Julliard's avatar
Alexandre Julliard committed
1472 1473

    case HTHSCROLL:
1474
        SendMessageW( hwnd, WM_SYSCOMMAND, SC_HSCROLL + HTHSCROLL, lParam );
Alexandre Julliard's avatar
Alexandre Julliard committed
1475 1476 1477
	break;

    case HTVSCROLL:
1478
        SendMessageW( hwnd, WM_SYSCOMMAND, SC_VSCROLL + HTVSCROLL, lParam );
Alexandre Julliard's avatar
Alexandre Julliard committed
1479
	break;
Alexandre Julliard's avatar
Alexandre Julliard committed
1480 1481 1482 1483 1484 1485 1486 1487 1488 1489
    }
    return 0;
}


/***********************************************************************
 *           NC_HandleSysCommand
 *
 * Handle a WM_SYSCOMMAND message. Called from DefWindowProc().
 */
1490
LONG NC_HandleSysCommand( HWND hwnd, WPARAM wParam, LPARAM lParam )
Alexandre Julliard's avatar
Alexandre Julliard committed
1491
{
1492
    TRACE("Handling WM_SYSCOMMAND %x %lx\n", wParam, lParam );
Alexandre Julliard's avatar
Alexandre Julliard committed
1493

1494
    switch (wParam & 0xfff0)
Alexandre Julliard's avatar
Alexandre Julliard committed
1495 1496 1497
    {
    case SC_SIZE:
    case SC_MOVE:
1498 1499
        if (USER_Driver.pSysCommandSizeMove)
            USER_Driver.pSysCommandSizeMove( hwnd, wParam );
Alexandre Julliard's avatar
Alexandre Julliard committed
1500 1501 1502
	break;

    case SC_MINIMIZE:
1503 1504
        if (hwnd == GetForegroundWindow())
            ShowOwnedPopups(hwnd,FALSE);
1505
	ShowWindow( hwnd, SW_MINIMIZE );
Alexandre Julliard's avatar
Alexandre Julliard committed
1506 1507 1508
	break;

    case SC_MAXIMIZE:
1509 1510
        if (IsIconic(hwnd) && hwnd == GetForegroundWindow())
            ShowOwnedPopups(hwnd,TRUE);
1511
	ShowWindow( hwnd, SW_MAXIMIZE );
Alexandre Julliard's avatar
Alexandre Julliard committed
1512 1513 1514
	break;

    case SC_RESTORE:
1515 1516
        if (IsIconic(hwnd) && hwnd == GetForegroundWindow())
            ShowOwnedPopups(hwnd,TRUE);
1517
	ShowWindow( hwnd, SW_RESTORE );
Alexandre Julliard's avatar
Alexandre Julliard committed
1518 1519 1520
	break;

    case SC_CLOSE:
1521
	return SendMessageA( hwnd, WM_CLOSE, 0, 0 );
Alexandre Julliard's avatar
Alexandre Julliard committed
1522 1523 1524

    case SC_VSCROLL:
    case SC_HSCROLL:
1525 1526
        {
            POINT pt;
1527 1528
            pt.x = (short)LOWORD(lParam);
            pt.y = (short)HIWORD(lParam);
1529 1530
            NC_TrackScrollBar( hwnd, wParam, pt );
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
1531
	break;
Alexandre Julliard's avatar
Alexandre Julliard committed
1532

Alexandre Julliard's avatar
Alexandre Julliard committed
1533
    case SC_MOUSEMENU:
1534 1535
        {
            POINT pt;
1536 1537
            pt.x = (short)LOWORD(lParam);
            pt.y = (short)HIWORD(lParam);
1538 1539
            MENU_TrackMouseMenuBar( hwnd, wParam & 0x000F, pt );
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
1540 1541
	break;

Alexandre Julliard's avatar
Alexandre Julliard committed
1542
    case SC_KEYMENU:
1543
        MENU_TrackKbdMenuBar( hwnd, wParam, (WCHAR)lParam );
Alexandre Julliard's avatar
Alexandre Julliard committed
1544
	break;
1545

Alexandre Julliard's avatar
Alexandre Julliard committed
1546
    case SC_TASKLIST:
1547
	WinExec( "taskman.exe", SW_SHOWNORMAL );
Alexandre Julliard's avatar
Alexandre Julliard committed
1548
	break;
Alexandre Julliard's avatar
Alexandre Julliard committed
1549 1550 1551

    case SC_SCREENSAVE:
	if (wParam == SC_ABOUTWINE)
1552 1553 1554 1555 1556
        {
            HMODULE hmodule = LoadLibraryA( "shell32.dll" );
            if (hmodule)
            {
                FARPROC aboutproc = GetProcAddress( hmodule, "ShellAboutA" );
1557
                if (aboutproc) aboutproc( hwnd, PACKAGE_NAME, PACKAGE_STRING, 0 );
1558 1559 1560
                FreeLibrary( hmodule );
            }
        }
1561
	else
1562
	  if (wParam == SC_PUTMARK)
1563
            DPRINTF("Debug mark requested by user\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1564
	break;
1565

Alexandre Julliard's avatar
Alexandre Julliard committed
1566 1567 1568 1569
    case SC_HOTKEY:
    case SC_ARRANGE:
    case SC_NEXTWINDOW:
    case SC_PREVWINDOW:
1570
 	FIXME("unimplemented!\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1571
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
1572 1573 1574
    }
    return 0;
}
1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585

/*************************************************************
*  NC_DrawGrayButton
*
* Stub for the grayed button of the caption
*
*************************************************************/

BOOL NC_DrawGrayButton(HDC hdc, int x, int y)
{
    HBITMAP hMaskBmp;
1586
    HDC hdcMask;
1587 1588 1589
    HBRUSH hOldBrush;

    hMaskBmp = CreateBitmap (12, 10, 1, 1, lpGrayMask);
1590

1591 1592
    if(hMaskBmp == 0)
	return FALSE;
1593

1594
    hdcMask = CreateCompatibleDC (0);
1595
    SelectObject (hdcMask, hMaskBmp);
1596

1597
    /* Draw the grayed bitmap using the mask */
1598
    hOldBrush = SelectObject (hdc, (HGDIOBJ)RGB(128, 128, 128));
1599 1600
    BitBlt (hdc, x, y, 12, 10,
	    hdcMask, 0, 0, 0xB8074A);
1601

1602 1603 1604 1605
    /* Clean up */
    SelectObject (hdc, hOldBrush);
    DeleteObject(hMaskBmp);
    DeleteDC (hdcMask);
1606

1607 1608
    return TRUE;
}
1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677

/***********************************************************************
 *		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)) {
        TRACE("Invalid TITLEBARINFO size: %ld\n", tbi->cbSize);
        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;
}