static.c 28.3 KB
Newer Older
Alexandre Julliard's avatar
Alexandre Julliard committed
1 2 3 4 5
/*
 * Static control
 *
 * Copyright  David W. Metcalfe, 1993
 *
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
19 20 21 22 23 24 25 26 27 28
 *
 * NOTES
 *
 * This code was audited for completeness against the documented features
 * of Comctl32.dll version 6.0 on Oct. 4, 2004, by Dimitrie O. Paun.
 * 
 * Unless otherwise noted, we believe this code to be complete, as per
 * the specification mentioned above.
 * If you discover missing features, or bugs, please note them below.
 *
29 30 31 32 33 34 35 36 37 38 39
 * Notes:
 *   - Windows XP introduced new behavior: The background of centered
 *     icons and bitmaps is painted differently. This is only done if
 *     a manifest is present.
 *     Because it has not yet been decided how to implement the two
 *     different modes in Wine, only the Windows XP mode is implemented.
 *   - Controls with SS_SIMPLE but without SS_NOPREFIX:
 *     The text should not be changed. Windows doesn't clear the
 *     client rectangle, so the new text must be larger than the old one.
 *   - The SS_RIGHTJUST style is currently not implemented by Windows
 *     (or it does something different than documented).
40
 *
41 42
 * TODO:
 *   - Animated cursors
Alexandre Julliard's avatar
Alexandre Julliard committed
43
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
44

45 46
#include <stdarg.h>

47
#include "windef.h"
48
#include "winbase.h"
49
#include "wingdi.h"
50
#include "wine/winuser16.h"
51
#include "controls.h"
52
#include "user_private.h"
53
#include "wine/debug.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
54

55
WINE_DEFAULT_DEBUG_CHANNEL(static);
56

57 58 59 60 61
static void STATIC_PaintOwnerDrawfn( HWND hwnd, HDC hdc, DWORD style );
static void STATIC_PaintTextfn( HWND hwnd, HDC hdc, DWORD style );
static void STATIC_PaintRectfn( HWND hwnd, HDC hdc, DWORD style );
static void STATIC_PaintIconfn( HWND hwnd, HDC hdc, DWORD style );
static void STATIC_PaintBitmapfn( HWND hwnd, HDC hdc, DWORD style );
62
static void STATIC_PaintEnhMetafn( HWND hwnd, HDC hdc, DWORD style );
63
static void STATIC_PaintEtchedfn( HWND hwnd, HDC hdc, DWORD style );
64
static LRESULT WINAPI StaticWndProcA( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam );
65
static LRESULT WINAPI StaticWndProcW( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam );
Alexandre Julliard's avatar
Alexandre Julliard committed
66

67
static COLORREF color_3dshadow, color_3ddkshadow, color_3dhighlight;
Alexandre Julliard's avatar
Alexandre Julliard committed
68

69 70 71 72
/* offsets for GetWindowLong for static private information */
#define HFONT_GWL_OFFSET    0
#define HICON_GWL_OFFSET    (sizeof(HFONT))
#define STATIC_EXTRA_BYTES  (HICON_GWL_OFFSET + sizeof(HICON))
Alexandre Julliard's avatar
Alexandre Julliard committed
73

74
typedef void (*pfPaint)( HWND hwnd, HDC hdc, DWORD style );
Alexandre Julliard's avatar
Alexandre Julliard committed
75

76
static const pfPaint staticPaintFunc[SS_TYPEMASK+1] =
Alexandre Julliard's avatar
Alexandre Julliard committed
77
{
Alexandre Julliard's avatar
Alexandre Julliard committed
78 79 80 81 82 83 84 85 86 87
    STATIC_PaintTextfn,      /* SS_LEFT */
    STATIC_PaintTextfn,      /* SS_CENTER */
    STATIC_PaintTextfn,      /* SS_RIGHT */
    STATIC_PaintIconfn,      /* SS_ICON */
    STATIC_PaintRectfn,      /* SS_BLACKRECT */
    STATIC_PaintRectfn,      /* SS_GRAYRECT */
    STATIC_PaintRectfn,      /* SS_WHITERECT */
    STATIC_PaintRectfn,      /* SS_BLACKFRAME */
    STATIC_PaintRectfn,      /* SS_GRAYFRAME */
    STATIC_PaintRectfn,      /* SS_WHITEFRAME */
88
    NULL,                    /* SS_USERITEM */
Alexandre Julliard's avatar
Alexandre Julliard committed
89
    STATIC_PaintTextfn,      /* SS_SIMPLE */
Alexandre Julliard's avatar
Alexandre Julliard committed
90
    STATIC_PaintTextfn,      /* SS_LEFTNOWORDWRAP */
91
    STATIC_PaintOwnerDrawfn, /* SS_OWNERDRAW */
Alexandre Julliard's avatar
Alexandre Julliard committed
92
    STATIC_PaintBitmapfn,    /* SS_BITMAP */
93
    STATIC_PaintEnhMetafn,   /* SS_ENHMETAFILE */
94
    STATIC_PaintEtchedfn,    /* SS_ETCHEDHORZ */
Alexandre Julliard's avatar
Alexandre Julliard committed
95 96
    STATIC_PaintEtchedfn,    /* SS_ETCHEDVERT */
    STATIC_PaintEtchedfn,    /* SS_ETCHEDFRAME */
Alexandre Julliard's avatar
Alexandre Julliard committed
97 98 99
};


100 101 102 103 104 105
/*********************************************************************
 * static class descriptor
 */
const struct builtin_class_descr STATIC_builtin_class =
{
    "Static",            /* name */
106
    CS_DBLCLKS | CS_PARENTDC, /* style  */
107
    StaticWndProcA,      /* procA */
108
    StaticWndProcW,      /* procW */
109
    STATIC_EXTRA_BYTES,  /* extra */
110
    IDC_ARROW,           /* cursor */
111 112 113
    0                    /* brush */
};

114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
static void setup_clipping(HWND hwnd, HDC hdc, HRGN *orig)
{
    RECT rc;
    HRGN hrgn;

    /* Native control has always a clipping region set (this may be because
     * builtin controls uses CS_PARENTDC) and an application depends on it
     */
    hrgn = CreateRectRgn(0, 0, 1, 1);
    if (GetClipRgn(hdc, hrgn) != 1)
    {
        DeleteObject(hrgn);
        *orig = NULL;
    } else
        *orig = hrgn;

    GetClientRect(hwnd, &rc);
    DPtoLP(hdc, (POINT *)&rc, 2);
    IntersectClipRect(hdc, rc.left, rc.top, rc.right, rc.bottom);
}

static void restore_clipping(HDC hdc, HRGN hrgn)
{
    SelectClipRgn(hdc, hrgn);
    if (hrgn != NULL)
        DeleteObject(hrgn);
}
141

Alexandre Julliard's avatar
Alexandre Julliard committed
142 143 144 145 146
/***********************************************************************
 *           STATIC_SetIcon
 *
 * Set the icon for an SS_ICON control.
 */
147
static HICON STATIC_SetIcon( HWND hwnd, HICON hicon, DWORD style )
Alexandre Julliard's avatar
Alexandre Julliard committed
148
{
149
    HICON prevIcon;
150
    CURSORICONINFO * info;
151

152
    if ((style & SS_TYPEMASK) != SS_ICON) return 0;
153
    info = hicon?(CURSORICONINFO *) GlobalLock16(HICON_16(hicon)):NULL;
Alexandre Julliard's avatar
Alexandre Julliard committed
154
    if (hicon && !info) {
155 156
        WARN("hicon != 0, but info == 0\n");
        return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
157
    }
158
    prevIcon = (HICON)SetWindowLongPtrW( hwnd, HICON_GWL_OFFSET, (LONG_PTR)hicon );
159
    if (hicon && !(style & SS_CENTERIMAGE) && !(style & SS_REALSIZECONTROL))
Alexandre Julliard's avatar
Alexandre Julliard committed
160
    {
161 162 163 164 165 166 167 168 169 170 171 172 173 174
        /* Windows currently doesn't implement SS_RIGHTJUST */
        /*
        if ((style & SS_RIGHTJUST) != 0)
        {
            RECT wr;
            GetWindowRect(hwnd, &wr);
            SetWindowPos( hwnd, 0, wr.right - info->nWidth, wr.bottom - info->nHeight,
                          info->nWidth, info->nHeight, SWP_NOACTIVATE | SWP_NOZORDER );
        }
        else */
        {
            SetWindowPos( hwnd, 0, 0, 0, info->nWidth, info->nHeight,
                          SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER );
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
175
    }
176
    if (info) GlobalUnlock16(HICON_16(hicon));
Alexandre Julliard's avatar
Alexandre Julliard committed
177
    return prevIcon;
Alexandre Julliard's avatar
Alexandre Julliard committed
178 179
}

Alexandre Julliard's avatar
Alexandre Julliard committed
180 181 182 183 184
/***********************************************************************
 *           STATIC_SetBitmap
 *
 * Set the bitmap for an SS_BITMAP control.
 */
185
static HBITMAP STATIC_SetBitmap( HWND hwnd, HBITMAP hBitmap, DWORD style )
Alexandre Julliard's avatar
Alexandre Julliard committed
186
{
187
    HBITMAP hOldBitmap;
Alexandre Julliard's avatar
Alexandre Julliard committed
188

189
    if ((style & SS_TYPEMASK) != SS_BITMAP) return 0;
190
    if (hBitmap && GetObjectType(hBitmap) != OBJ_BITMAP) {
191 192
        WARN("hBitmap != 0, but it's not a bitmap\n");
        return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
193
    }
194
    hOldBitmap = (HBITMAP)SetWindowLongPtrW( hwnd, HICON_GWL_OFFSET, (LONG_PTR)hBitmap );
195
    if (hBitmap && !(style & SS_CENTERIMAGE) && !(style & SS_REALSIZECONTROL))
Alexandre Julliard's avatar
Alexandre Julliard committed
196
    {
197
        BITMAP bm;
198
        GetObjectW(hBitmap, sizeof(bm), &bm);
199 200 201 202 203 204 205 206 207 208 209 210 211 212 213
        /* Windows currently doesn't implement SS_RIGHTJUST */
        /*
        if ((style & SS_RIGHTJUST) != 0)
        {
            RECT wr;
            GetWindowRect(hwnd, &wr);
            SetWindowPos( hwnd, 0, wr.right - bm.bmWidth, wr.bottom - bm.bmHeight,
                          bm.bmWidth, bm.bmHeight, SWP_NOACTIVATE | SWP_NOZORDER );
        }
        else */
        {
            SetWindowPos( hwnd, 0, 0, 0, bm.bmWidth, bm.bmHeight,
                          SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER );
        }
	
Alexandre Julliard's avatar
Alexandre Julliard committed
214
    }
215
    return hOldBitmap;
Alexandre Julliard's avatar
Alexandre Julliard committed
216 217
}

218 219 220 221 222 223 224 225 226
/***********************************************************************
 *           STATIC_SetEnhMetaFile
 *
 * Set the enhanced metafile for an SS_ENHMETAFILE control.
 */
static HENHMETAFILE STATIC_SetEnhMetaFile( HWND hwnd, HENHMETAFILE hEnhMetaFile, DWORD style )
{
    if ((style & SS_TYPEMASK) != SS_ENHMETAFILE) return 0;
    if (hEnhMetaFile && GetObjectType(hEnhMetaFile) != OBJ_ENHMETAFILE) {
227
        WARN("hEnhMetaFile != 0, but it's not an enhanced metafile\n");
228 229 230 231 232
        return 0;
    }
    return (HENHMETAFILE)SetWindowLongPtrW( hwnd, HICON_GWL_OFFSET, (LONG_PTR)hEnhMetaFile );
}

233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258
/***********************************************************************
 *           STATIC_GetImage
 *
 * Gets the bitmap for an SS_BITMAP control, the icon/cursor for an
 * SS_ICON control or the enhanced metafile for an SS_ENHMETAFILE control.
 */
static HANDLE STATIC_GetImage( HWND hwnd, WPARAM wParam, DWORD style )
{
    switch(style & SS_TYPEMASK)
    {
        case SS_ICON:
            if ((wParam != IMAGE_ICON) &&
                (wParam != IMAGE_CURSOR)) return NULL;
            break;
        case SS_BITMAP:
            if (wParam != IMAGE_BITMAP) return NULL;
            break;
        case SS_ENHMETAFILE:
            if (wParam != IMAGE_ENHMETAFILE) return NULL;
            break;
        default:
            return NULL;
    }
    return (HANDLE)GetWindowLongPtrW( hwnd, HICON_GWL_OFFSET );
}

Alexandre Julliard's avatar
Alexandre Julliard committed
259
/***********************************************************************
260
 *           STATIC_LoadIconA
Alexandre Julliard's avatar
Alexandre Julliard committed
261 262 263
 *
 * Load the icon for an SS_ICON control.
 */
264
static HICON STATIC_LoadIconA( HWND hwnd, LPCSTR name, DWORD style )
Alexandre Julliard's avatar
Alexandre Julliard committed
265
{
266
    HINSTANCE hInstance = (HINSTANCE)GetWindowLongPtrW( hwnd, GWLP_HINSTANCE );
267 268 269 270 271 272 273 274 275 276 277 278 279 280
    if ((style & SS_REALSIZEIMAGE) != 0)
    {
        return LoadImageA(hInstance, name, IMAGE_ICON, 0, 0, LR_SHARED);
    }
    else
    {
        HICON hicon = LoadIconA( hInstance, name );
        if (!hicon) hicon = LoadCursorA( hInstance, name );
        if (!hicon) hicon = LoadIconA( 0, name );
        /* Windows doesn't try to load a standard cursor,
           probably because most IDs for standard cursors conflict
           with the IDs for standard icons anyway */
        return hicon;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
281 282
}

Alexandre Julliard's avatar
Alexandre Julliard committed
283
/***********************************************************************
284 285 286 287
 *           STATIC_LoadIconW
 *
 * Load the icon for an SS_ICON control.
 */
288
static HICON STATIC_LoadIconW( HWND hwnd, LPCWSTR name, DWORD style )
289
{
290
    HINSTANCE hInstance = (HINSTANCE)GetWindowLongPtrW( hwnd, GWLP_HINSTANCE );
291 292 293 294 295 296 297 298 299 300 301 302 303 304
    if ((style & SS_REALSIZEIMAGE) != 0)
    {
        return LoadImageW(hInstance, name, IMAGE_ICON, 0, 0, LR_SHARED);
    }
    else
    {
        HICON hicon = LoadIconW( hInstance, name );
        if (!hicon) hicon = LoadCursorW( hInstance, name );
        if (!hicon) hicon = LoadIconW( 0, name );
        /* Windows doesn't try to load a standard cursor,
           probably because most IDs for standard cursors conflict
           with the IDs for standard icons anyway */
        return hicon;
    }
305 306 307 308
}

/***********************************************************************
 *           STATIC_LoadBitmapA
Alexandre Julliard's avatar
Alexandre Julliard committed
309 310 311
 *
 * Load the bitmap for an SS_BITMAP control.
 */
312
static HBITMAP STATIC_LoadBitmapA( HWND hwnd, LPCSTR name )
Alexandre Julliard's avatar
Alexandre Julliard committed
313
{
314
    HINSTANCE hInstance = (HINSTANCE)GetWindowLongPtrW( hwnd, GWLP_HINSTANCE );
315 316
    /* Windows doesn't try to load OEM Bitmaps (hInstance == NULL) */
    return LoadBitmapA( hInstance, name );
Alexandre Julliard's avatar
Alexandre Julliard committed
317 318
}

319 320 321 322 323
/***********************************************************************
 *           STATIC_LoadBitmapW
 *
 * Load the bitmap for an SS_BITMAP control.
 */
324
static HBITMAP STATIC_LoadBitmapW( HWND hwnd, LPCWSTR name )
325
{
326
    HINSTANCE hInstance = (HINSTANCE)GetWindowLongPtrW( hwnd, GWLP_HINSTANCE );
327 328
    /* Windows doesn't try to load OEM Bitmaps (hInstance == NULL) */
    return LoadBitmapW( hInstance, name );
329
}
Alexandre Julliard's avatar
Alexandre Julliard committed
330

331 332 333 334 335 336 337 338 339 340 341 342 343 344
/***********************************************************************
 *           STATIC_TryPaintFcn
 *
 * Try to immediately paint the control.
 */
static VOID STATIC_TryPaintFcn(HWND hwnd, LONG full_style)
{
    LONG style = full_style & SS_TYPEMASK;
    RECT rc;

    GetClientRect( hwnd, &rc );
    if (!IsRectEmpty(&rc) && IsWindowVisible(hwnd) && staticPaintFunc[style])
    {
	HDC hdc;
345 346
        HRGN hOrigClipping;

347
	hdc = GetDC( hwnd );
348
        setup_clipping(hwnd, hdc, &hOrigClipping);
349
	(staticPaintFunc[style])( hwnd, hdc, full_style );
350
        restore_clipping(hdc, hOrigClipping);
351 352 353 354
	ReleaseDC( hwnd, hdc );
    }
}

355 356
static HBRUSH STATIC_SendWmCtlColorStatic(HWND hwnd, HDC hdc)
{
357 358 359 360 361
    HBRUSH hBrush;
    HWND parent = GetParent(hwnd);

    if (!parent) parent = hwnd;
    hBrush = (HBRUSH) SendMessageW( parent,
362 363 364 365 366
                    WM_CTLCOLORSTATIC, (WPARAM)hdc, (LPARAM)hwnd );
    if (!hBrush) /* did the app forget to call DefWindowProc ? */
    {
        /* FIXME: DefWindowProc should return different colors if a
                  manifest is present */
367
        hBrush = (HBRUSH)DefWindowProcW( parent, WM_CTLCOLORSTATIC,
368 369 370 371 372
                                        (WPARAM)hdc, (LPARAM)hwnd);
    }
    return hBrush;
}

373
static VOID STATIC_InitColours(void)
374 375 376 377 378 379
{
    color_3ddkshadow  = GetSysColor(COLOR_3DDKSHADOW);
    color_3dshadow    = GetSysColor(COLOR_3DSHADOW);
    color_3dhighlight = GetSysColor(COLOR_3DHIGHLIGHT);
}

380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400
/***********************************************************************
 *           hasTextStyle
 *
 * Tests if the control displays text.
 */
static BOOL hasTextStyle( DWORD style )
{
    switch(style & SS_TYPEMASK)
    {
        case SS_SIMPLE:
        case SS_LEFT:
        case SS_LEFTNOWORDWRAP:
        case SS_CENTER:
        case SS_RIGHT:
        case SS_OWNERDRAW:
            return TRUE;
    }
    
    return FALSE;
}

Alexandre Julliard's avatar
Alexandre Julliard committed
401
/***********************************************************************
402
 *           StaticWndProc_common
Alexandre Julliard's avatar
Alexandre Julliard committed
403
 */
404
static LRESULT StaticWndProc_common( HWND hwnd, UINT uMsg, WPARAM wParam,
405
                                     LPARAM lParam, BOOL unicode )
Alexandre Julliard's avatar
Alexandre Julliard committed
406
{
Alexandre Julliard's avatar
Alexandre Julliard committed
407
    LRESULT lResult = 0;
408
    LONG full_style = GetWindowLongW( hwnd, GWL_STYLE );
409
    LONG style = full_style & SS_TYPEMASK;
Alexandre Julliard's avatar
Alexandre Julliard committed
410

Alexandre Julliard's avatar
Alexandre Julliard committed
411 412
    switch (uMsg)
    {
Alexandre Julliard's avatar
Alexandre Julliard committed
413
    case WM_CREATE:
Alexandre Julliard's avatar
Alexandre Julliard committed
414
        if (style < 0L || style > SS_TYPEMASK)
Alexandre Julliard's avatar
Alexandre Julliard committed
415
        {
416
            ERR("Unknown style 0x%02x\n", style );
417
            return -1;
Alexandre Julliard's avatar
Alexandre Julliard committed
418
        }
419
        STATIC_InitColours();
Alexandre Julliard's avatar
Alexandre Julliard committed
420 421 422
        break;

    case WM_NCDESTROY:
423 424 425 426
        if (style == SS_ICON) {
/*
 * FIXME
 *           DestroyIcon32( STATIC_SetIcon( wndPtr, 0 ) );
427
 *
428 429 430 431
 * We don't want to do this yet because DestroyIcon32 is broken. If the icon
 * had already been loaded by the application the last thing we want to do is
 * GlobalFree16 the handle.
 */
432 433 434 435
            break;
        }
        else return unicode ? DefWindowProcW(hwnd, uMsg, wParam, lParam) :
                              DefWindowProcA(hwnd, uMsg, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
436

437 438 439 440
    case WM_ERASEBKGND:
        /* do all painting in WM_PAINT like Windows does */
        return 1;

441
    case WM_PRINTCLIENT:
Alexandre Julliard's avatar
Alexandre Julliard committed
442 443
    case WM_PAINT:
        {
444
            PAINTSTRUCT ps;
445
            HDC hdc = wParam ? (HDC)wParam : BeginPaint(hwnd, &ps);
Alexandre Julliard's avatar
Alexandre Julliard committed
446
            if (staticPaintFunc[style])
447 448 449
            {
                HRGN hOrigClipping;
                setup_clipping(hwnd, hdc, &hOrigClipping);
450
                (staticPaintFunc[style])( hwnd, hdc, full_style );
451 452
                restore_clipping(hdc, hOrigClipping);
            }
453
            if (!wParam) EndPaint(hwnd, &ps);
Alexandre Julliard's avatar
Alexandre Julliard committed
454 455 456 457
        }
        break;

    case WM_ENABLE:
458 459 460 461 462 463 464 465 466 467 468
        STATIC_TryPaintFcn( hwnd, full_style );
        if (full_style & SS_NOTIFY) {
            if (wParam) {
                SendMessageW( GetParent(hwnd), WM_COMMAND,
                              MAKEWPARAM( GetWindowLongPtrW(hwnd,GWLP_ID), STN_ENABLE ), (LPARAM)hwnd);
            }
            else {
                SendMessageW( GetParent(hwnd), WM_COMMAND,
                              MAKEWPARAM( GetWindowLongPtrW(hwnd,GWLP_ID), STN_DISABLE ), (LPARAM)hwnd);
            }
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
469 470 471
        break;

    case WM_SYSCOLORCHANGE:
472
        STATIC_InitColours();
473
        STATIC_TryPaintFcn( hwnd, full_style );
Alexandre Julliard's avatar
Alexandre Julliard committed
474 475
        break;

476
    case WM_NCCREATE:
477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523
        {
            LPCSTR textA;
            LPCWSTR textW;
    
            if (full_style & SS_SUNKEN)
                SetWindowLongW( hwnd, GWL_EXSTYLE,
                                GetWindowLongW( hwnd, GWL_EXSTYLE ) | WS_EX_STATICEDGE );

            if(unicode)
            {
                textA = NULL;
                textW = ((LPCREATESTRUCTW)lParam)->lpszName;
            }
            else
            {
                textA = ((LPCREATESTRUCTA)lParam)->lpszName;
                textW = NULL;
            }

            switch (style) {
            case SS_ICON:
                {
                    HICON hIcon;
                    if(unicode)
                       hIcon = STATIC_LoadIconW(hwnd, textW, full_style);
                    else
                       hIcon = STATIC_LoadIconA(hwnd, textA, full_style);
                    STATIC_SetIcon(hwnd, hIcon, full_style);
                }
                break;
            case SS_BITMAP:
                {
                    HBITMAP hBitmap;
                    if(unicode)
                        hBitmap = STATIC_LoadBitmapW(hwnd, textW);
                    else
                        hBitmap = STATIC_LoadBitmapA(hwnd, textA);
                    STATIC_SetBitmap(hwnd, hBitmap, full_style);
                }
                break;
            }
            /* SS_ENHMETAFILE: Despite what MSDN says, Windows does not load
               the enhanced metafile that was specified as the window text. */
        }
        return unicode ? DefWindowProcW(hwnd, uMsg, wParam, lParam) :
                         DefWindowProcA(hwnd, uMsg, wParam, lParam);

Alexandre Julliard's avatar
Alexandre Julliard committed
524
    case WM_SETTEXT:
525
        if (hasTextStyle( full_style ))
526 527 528
        {
	    if (HIWORD(lParam))
	    {
529 530 531 532 533
	        if(unicode)
		     lResult = DefWindowProcW( hwnd, uMsg, wParam, lParam );
                else
                    lResult = DefWindowProcA( hwnd, uMsg, wParam, lParam );
	        STATIC_TryPaintFcn( hwnd, full_style );
534 535
	    }
	}
536
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
537 538

    case WM_SETFONT:
539 540 541 542
        if (hasTextStyle( full_style ))
        {
            SetWindowLongPtrW( hwnd, HFONT_GWL_OFFSET, wParam );
            if (LOWORD(lParam))
543
                RedrawWindow( hwnd, NULL, 0, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_ALLCHILDREN );
544
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
545
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
546

Alexandre Julliard's avatar
Alexandre Julliard committed
547
    case WM_GETFONT:
548
        return GetWindowLongPtrW( hwnd, HFONT_GWL_OFFSET );
Alexandre Julliard's avatar
Alexandre Julliard committed
549

Alexandre Julliard's avatar
Alexandre Julliard committed
550
    case WM_NCHITTEST:
551 552
        if (full_style & SS_NOTIFY)
           return HTCLIENT;
553
        else
554
           return HTTRANSPARENT;
Alexandre Julliard's avatar
Alexandre Julliard committed
555

Alexandre Julliard's avatar
Alexandre Julliard committed
556
    case WM_GETDLGCODE:
557
        return DLGC_STATIC;
Alexandre Julliard's avatar
Alexandre Julliard committed
558

559 560 561 562
    case WM_LBUTTONDOWN:
    case WM_NCLBUTTONDOWN:
        if (full_style & SS_NOTIFY)
            SendMessageW( GetParent(hwnd), WM_COMMAND,
563
                          MAKEWPARAM( GetWindowLongPtrW(hwnd,GWLP_ID), STN_CLICKED ), (LPARAM)hwnd);
564 565 566 567 568 569
        return 0;

    case WM_LBUTTONDBLCLK:
    case WM_NCLBUTTONDBLCLK:
        if (full_style & SS_NOTIFY)
            SendMessageW( GetParent(hwnd), WM_COMMAND,
570
                          MAKEWPARAM( GetWindowLongPtrW(hwnd,GWLP_ID), STN_DBLCLK ), (LPARAM)hwnd);
571 572
        return 0;

Alexandre Julliard's avatar
Alexandre Julliard committed
573
    case STM_GETIMAGE:
574 575
        return (LRESULT)STATIC_GetImage( hwnd, wParam, full_style );
    
Alexandre Julliard's avatar
Alexandre Julliard committed
576
    case STM_GETICON16:
577
    case STM_GETICON:
578
        return (LRESULT)STATIC_GetImage( hwnd, IMAGE_ICON, full_style );
Alexandre Julliard's avatar
Alexandre Julliard committed
579

Alexandre Julliard's avatar
Alexandre Julliard committed
580
    case STM_SETIMAGE:
581 582
        switch(wParam) {
	case IMAGE_BITMAP:
583
	    lResult = (LRESULT)STATIC_SetBitmap( hwnd, (HBITMAP)lParam, full_style );
584
	    break;
585
	case IMAGE_ENHMETAFILE:
586
	    lResult = (LRESULT)STATIC_SetEnhMetaFile( hwnd, (HENHMETAFILE)lParam, full_style );
587
	    break;
588
	case IMAGE_ICON:
589
	case IMAGE_CURSOR:
590
	    lResult = (LRESULT)STATIC_SetIcon( hwnd, (HICON)lParam, full_style );
591 592
	    break;
	default:
593
	    FIXME("STM_SETIMAGE: Unhandled type %lx\n", wParam);
594 595
	    break;
	}
596
        STATIC_TryPaintFcn( hwnd, full_style );
Alexandre Julliard's avatar
Alexandre Julliard committed
597
	break;
Alexandre Julliard's avatar
Alexandre Julliard committed
598

Alexandre Julliard's avatar
Alexandre Julliard committed
599
    case STM_SETICON16:
600
    case STM_SETICON:
601
        lResult = (LRESULT)STATIC_SetIcon( hwnd, (HICON)wParam, full_style );
602
        STATIC_TryPaintFcn( hwnd, full_style );
Alexandre Julliard's avatar
Alexandre Julliard committed
603
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
604

Alexandre Julliard's avatar
Alexandre Julliard committed
605
    default:
606 607
        return unicode ? DefWindowProcW(hwnd, uMsg, wParam, lParam) :
                         DefWindowProcA(hwnd, uMsg, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
608
    }
609 610 611 612 613 614 615 616
    return lResult;
}

/***********************************************************************
 *           StaticWndProcA
 */
static LRESULT WINAPI StaticWndProcA( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
617 618
    if (!IsWindow( hWnd )) return 0;
    return StaticWndProc_common(hWnd, uMsg, wParam, lParam, FALSE);
619 620 621 622 623 624 625
}

/***********************************************************************
 *           StaticWndProcW
 */
static LRESULT WINAPI StaticWndProcW( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
626 627
    if (!IsWindow( hWnd )) return 0;
    return StaticWndProc_common(hWnd, uMsg, wParam, lParam, TRUE);
Alexandre Julliard's avatar
Alexandre Julliard committed
628 629
}

630
static void STATIC_PaintOwnerDrawfn( HWND hwnd, HDC hdc, DWORD style )
631 632
{
  DRAWITEMSTRUCT dis;
633
  HFONT font, oldFont = NULL;
634
  UINT id = (UINT)GetWindowLongPtrW( hwnd, GWLP_ID );
635 636

  dis.CtlType    = ODT_STATIC;
637
  dis.CtlID      = id;
638 639
  dis.itemID     = 0;
  dis.itemAction = ODA_DRAWENTIRE;
640
  dis.itemState  = IsWindowEnabled(hwnd) ? 0 : ODS_DISABLED;
641
  dis.hwndItem   = hwnd;
642 643
  dis.hDC        = hdc;
  dis.itemData   = 0;
644
  GetClientRect( hwnd, &dis.rcItem );
645

646 647
  font = (HFONT)GetWindowLongPtrW( hwnd, HFONT_GWL_OFFSET );
  if (font) oldFont = SelectObject( hdc, font );
648
  SendMessageW( GetParent(hwnd), WM_CTLCOLORSTATIC, (WPARAM)hdc, (LPARAM)hwnd );
649
  SendMessageW( GetParent(hwnd), WM_DRAWITEM, id, (LPARAM)&dis );
650
  if (font) SelectObject( hdc, oldFont );
651
}
Alexandre Julliard's avatar
Alexandre Julliard committed
652

653
static void STATIC_PaintTextfn( HWND hwnd, HDC hdc, DWORD style )
Alexandre Julliard's avatar
Alexandre Julliard committed
654
{
655 656
    RECT rc;
    HBRUSH hBrush;
657
    HFONT hFont, hOldFont = NULL;
Alexandre Julliard's avatar
Alexandre Julliard committed
658
    WORD wFormat;
659
    INT len, buf_size;
660
    WCHAR *text;
Alexandre Julliard's avatar
Alexandre Julliard committed
661

662
    GetClientRect( hwnd, &rc);
Alexandre Julliard's avatar
Alexandre Julliard committed
663

Alexandre Julliard's avatar
Alexandre Julliard committed
664
    switch (style & SS_TYPEMASK)
Alexandre Julliard's avatar
Alexandre Julliard committed
665 666
    {
    case SS_LEFT:
667
	wFormat = DT_LEFT | DT_EXPANDTABS | DT_WORDBREAK;
Alexandre Julliard's avatar
Alexandre Julliard committed
668 669 670
	break;

    case SS_CENTER:
671
	wFormat = DT_CENTER | DT_EXPANDTABS | DT_WORDBREAK;
Alexandre Julliard's avatar
Alexandre Julliard committed
672 673 674
	break;

    case SS_RIGHT:
675
	wFormat = DT_RIGHT | DT_EXPANDTABS | DT_WORDBREAK;
Alexandre Julliard's avatar
Alexandre Julliard committed
676 677 678
	break;

    case SS_SIMPLE:
679
        wFormat = DT_LEFT | DT_SINGLELINE;
Alexandre Julliard's avatar
Alexandre Julliard committed
680 681 682
	break;

    case SS_LEFTNOWORDWRAP:
683
        wFormat = DT_LEFT | DT_EXPANDTABS;
Alexandre Julliard's avatar
Alexandre Julliard committed
684
	break;
Alexandre Julliard's avatar
Alexandre Julliard committed
685 686 687

    default:
        return;
Alexandre Julliard's avatar
Alexandre Julliard committed
688 689 690
    }

    if (style & SS_NOPREFIX)
691
        wFormat |= DT_NOPREFIX;
692

693 694 695 696 697 698 699 700 701 702 703 704 705
    if ((style & SS_TYPEMASK) != SS_SIMPLE)
    {
        if (style & SS_CENTERIMAGE)
            wFormat |= DT_SINGLELINE | DT_VCENTER;
        if (style & SS_EDITCONTROL)
            wFormat |= DT_EDITCONTROL;
        if (style & SS_ENDELLIPSIS)
            wFormat |= DT_SINGLELINE | DT_END_ELLIPSIS;
        if (style & SS_PATHELLIPSIS)
            wFormat |= DT_SINGLELINE | DT_PATH_ELLIPSIS;
        if (style & SS_WORDELLIPSIS)
            wFormat |= DT_SINGLELINE | DT_WORD_ELLIPSIS;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
706

707 708
    if ((hFont = (HFONT)GetWindowLongPtrW( hwnd, HFONT_GWL_OFFSET )))
        hOldFont = (HFONT)SelectObject( hdc, hFont );
709

710 711 712
    /* SS_SIMPLE controls: WM_CTLCOLORSTATIC is sent, but the returned
                           brush is not used */
    hBrush = STATIC_SendWmCtlColorStatic(hwnd, hdc);
713

714
    if ((style & SS_TYPEMASK) != SS_SIMPLE)
715
    {
716
        FillRect( hdc, &rc, hBrush );
717
        if (!IsWindowEnabled(hwnd)) SetTextColor(hdc, GetSysColor(COLOR_GRAYTEXT));
718
    }
719

720
    buf_size = 256;
721 722
    if (!(text = HeapAlloc( GetProcessHeap(), 0, buf_size * sizeof(WCHAR) )))
        goto no_TextOut;
723 724 725 726

    while ((len = InternalGetWindowText( hwnd, text, buf_size )) == buf_size - 1)
    {
        buf_size *= 2;
727 728
        if (!(text = HeapReAlloc( GetProcessHeap(), 0, text, buf_size * sizeof(WCHAR) )))
            goto no_TextOut;
729 730
    }

731 732
    if (!len) goto no_TextOut;

733 734 735 736 737 738 739 740 741 742 743 744
    if (((style & SS_TYPEMASK) == SS_SIMPLE) && (style & SS_NOPREFIX))
    {
        /* Windows uses the faster ExtTextOut() to draw the text and
           to paint the whole client rectangle with the text background
           color. Reference: "Static Controls" by Kyle Marsh, 1992 */
        ExtTextOutW( hdc, rc.left, rc.top, ETO_CLIPPED | ETO_OPAQUE,
                     &rc, text, len, NULL );
    }
    else
    {
        DrawTextW( hdc, text, -1, &rc, wFormat );
    }
745

746
no_TextOut:
747
    HeapFree( GetProcessHeap(), 0, text );
748

749 750
    if (hFont)
        SelectObject( hdc, hOldFont );
Alexandre Julliard's avatar
Alexandre Julliard committed
751 752
}

753
static void STATIC_PaintRectfn( HWND hwnd, HDC hdc, DWORD style )
Alexandre Julliard's avatar
Alexandre Julliard committed
754
{
755 756
    RECT rc;
    HBRUSH hBrush;
Alexandre Julliard's avatar
Alexandre Julliard committed
757

758
    GetClientRect( hwnd, &rc);
759

760
    /* FIXME: send WM_CTLCOLORSTATIC */
761
    switch (style & SS_TYPEMASK)
Alexandre Julliard's avatar
Alexandre Julliard committed
762 763
    {
    case SS_BLACKRECT:
764
	hBrush = CreateSolidBrush(color_3ddkshadow);
765
        FillRect( hdc, &rc, hBrush );
Alexandre Julliard's avatar
Alexandre Julliard committed
766 767
	break;
    case SS_GRAYRECT:
768
	hBrush = CreateSolidBrush(color_3dshadow);
769
        FillRect( hdc, &rc, hBrush );
Alexandre Julliard's avatar
Alexandre Julliard committed
770 771
	break;
    case SS_WHITERECT:
772
	hBrush = CreateSolidBrush(color_3dhighlight);
773
        FillRect( hdc, &rc, hBrush );
Alexandre Julliard's avatar
Alexandre Julliard committed
774 775
	break;
    case SS_BLACKFRAME:
776
	hBrush = CreateSolidBrush(color_3ddkshadow);
777
        FrameRect( hdc, &rc, hBrush );
Alexandre Julliard's avatar
Alexandre Julliard committed
778 779
	break;
    case SS_GRAYFRAME:
780
	hBrush = CreateSolidBrush(color_3dshadow);
781
        FrameRect( hdc, &rc, hBrush );
Alexandre Julliard's avatar
Alexandre Julliard committed
782 783
	break;
    case SS_WHITEFRAME:
784
	hBrush = CreateSolidBrush(color_3dhighlight);
785
        FrameRect( hdc, &rc, hBrush );
Alexandre Julliard's avatar
Alexandre Julliard committed
786
	break;
Alexandre Julliard's avatar
Alexandre Julliard committed
787 788
    default:
        return;
Alexandre Julliard's avatar
Alexandre Julliard committed
789
    }
790
    DeleteObject( hBrush );
Alexandre Julliard's avatar
Alexandre Julliard committed
791 792 793
}


794
static void STATIC_PaintIconfn( HWND hwnd, HDC hdc, DWORD style )
Alexandre Julliard's avatar
Alexandre Julliard committed
795
{
796
    RECT rc, iconRect;
797
    HBRUSH hbrush;
798
    HICON hIcon;
799
    CURSORICONINFO * info;
Alexandre Julliard's avatar
Alexandre Julliard committed
800

801
    GetClientRect( hwnd, &rc );
802
    hbrush = STATIC_SendWmCtlColorStatic(hwnd, hdc);
803
    hIcon = (HICON)GetWindowLongPtrW( hwnd, HICON_GWL_OFFSET );
804 805
    info = hIcon ? (CURSORICONINFO *)GlobalLock16(HICON_16(hIcon)) : NULL;
    if (!hIcon || !info)
806
    {
807
        FillRect(hdc, &rc, hbrush);
808 809 810
    }
    else
    {
811 812 813 814 815 816 817
        if (style & SS_CENTERIMAGE)
        {
            iconRect.left = (rc.right - rc.left) / 2 - info->nWidth / 2;
            iconRect.top = (rc.bottom - rc.top) / 2 - info->nHeight / 2;
            iconRect.right = iconRect.left + info->nWidth;
            iconRect.bottom = iconRect.top + info->nHeight;
        }
818 819
        else
            iconRect = rc;
820
        FillRect( hdc, &rc, hbrush );
821 822
        DrawIconEx( hdc, iconRect.left, iconRect.top, hIcon, iconRect.right - iconRect.left,
                    iconRect.bottom - iconRect.top, 0, NULL, DI_NORMAL );
823
    }
824
    if (info) GlobalUnlock16(HICON_16(hIcon));
Alexandre Julliard's avatar
Alexandre Julliard committed
825
}
Alexandre Julliard's avatar
Alexandre Julliard committed
826

827
static void STATIC_PaintBitmapfn(HWND hwnd, HDC hdc, DWORD style )
Alexandre Julliard's avatar
Alexandre Julliard committed
828
{
829
    HDC hMemDC;
830
    HBITMAP hBitmap, oldbitmap;
831
    HBRUSH hbrush;
Alexandre Julliard's avatar
Alexandre Julliard committed
832

833
    /* message is still sent, even if the returned brush is not used */
834
    hbrush = STATIC_SendWmCtlColorStatic(hwnd, hdc);
835

836 837 838
    if ((hBitmap = (HBITMAP)GetWindowLongPtrW( hwnd, HICON_GWL_OFFSET ))
         && (GetObjectType(hBitmap) == OBJ_BITMAP)
         && (hMemDC = CreateCompatibleDC( hdc )))
839
    {
840
        BITMAP bm;
841 842 843 844 845
        RECT rcClient;
        LOGBRUSH brush;

        GetObjectW(hBitmap, sizeof(bm), &bm);
        oldbitmap = SelectObject(hMemDC, hBitmap);
Alexandre Julliard's avatar
Alexandre Julliard committed
846

847 848 849 850 851 852 853 854
        /* Set the background color for monochrome bitmaps
           to the color of the background brush */
        if (GetObjectW( hbrush, sizeof(brush), &brush ))
        {
            if (brush.lbStyle == BS_SOLID)
                SetBkColor(hdc, brush.lbColor);
        }
        GetClientRect(hwnd, &rcClient);
855 856
        if (style & SS_CENTERIMAGE)
        {
857
            INT x, y;
858 859
            x = (rcClient.right - rcClient.left)/2 - bm.bmWidth/2;
            y = (rcClient.bottom - rcClient.top)/2 - bm.bmHeight/2;
860 861 862
            FillRect( hdc, &rcClient, hbrush );
            BitBlt(hdc, x, y, bm.bmWidth, bm.bmHeight, hMemDC, 0, 0,
                   SRCCOPY);
863 864 865
        }
        else
        {
866 867 868
            StretchBlt(hdc, 0, 0, rcClient.right - rcClient.left,
                       rcClient.bottom - rcClient.top, hMemDC,
                       0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY);
869
        }
870 871 872 873 874 875 876 877
        SelectObject(hMemDC, oldbitmap);
        DeleteDC(hMemDC);
    }
    else
    {
        RECT rcClient;
        GetClientRect( hwnd, &rcClient );
        FillRect( hdc, &rcClient, hbrush );
Alexandre Julliard's avatar
Alexandre Julliard committed
878 879
    }
}
Alexandre Julliard's avatar
Alexandre Julliard committed
880 881


882 883 884
static void STATIC_PaintEnhMetafn(HWND hwnd, HDC hdc, DWORD style )
{
    HENHMETAFILE hEnhMetaFile;
885 886 887 888 889 890
    RECT rc;
    HBRUSH hbrush;
    
    GetClientRect(hwnd, &rc);
    hbrush = STATIC_SendWmCtlColorStatic(hwnd, hdc);
    FillRect(hdc, &rc, hbrush);
891 892
    if ((hEnhMetaFile = (HENHMETAFILE)GetWindowLongPtrW( hwnd, HICON_GWL_OFFSET )))
    {
893 894 895 896
        /* The control's current font is not selected into the
           device context! */
        if (GetObjectType(hEnhMetaFile) == OBJ_ENHMETAFILE)
            PlayEnhMetaFile(hdc, hEnhMetaFile, &rc);
897 898 899 900
    }
}


901
static void STATIC_PaintEtchedfn( HWND hwnd, HDC hdc, DWORD style )
Alexandre Julliard's avatar
Alexandre Julliard committed
902
{
903
    RECT rc;
Alexandre Julliard's avatar
Alexandre Julliard committed
904

905
    /* FIXME: sometimes (not always) sends WM_CTLCOLORSTATIC */
906 907
    GetClientRect( hwnd, &rc );
    switch (style & SS_TYPEMASK)
Alexandre Julliard's avatar
Alexandre Julliard committed
908 909
    {
	case SS_ETCHEDHORZ:
910
	    DrawEdge(hdc,&rc,EDGE_ETCHED,BF_TOP|BF_BOTTOM);
Alexandre Julliard's avatar
Alexandre Julliard committed
911 912
	    break;
	case SS_ETCHEDVERT:
913
	    DrawEdge(hdc,&rc,EDGE_ETCHED,BF_LEFT|BF_RIGHT);
Alexandre Julliard's avatar
Alexandre Julliard committed
914 915
	    break;
	case SS_ETCHEDFRAME:
916
	    DrawEdge (hdc, &rc, EDGE_ETCHED, BF_RECT);
Alexandre Julliard's avatar
Alexandre Julliard committed
917 918 919
	    break;
    }
}