status.c 26.8 KB
Newer Older
1 2 3
/* Unit test suite for status control.
 *
 * Copyright 2007 Google (Lei Zhang)
4
 * Copyright 2007 Alex Arazi
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
 *
 * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 */

#include <windows.h>
#include <commctrl.h>

#include "wine/test.h"

26 27
#define SUBCLASS_NAME "MyStatusBar"

28
#define expect(expected,got) ok (expected == got,"Expected %d, got %d\n",expected,got)
29 30 31 32
#define expect_rect(_left,_top,_right,_bottom,got) do { \
        RECT exp = {abs(got.left - _left), abs(got.top - _top), \
                    abs(got.right - _right), abs(got.bottom - _bottom)}; \
        ok(exp.left <= 2 && exp.top <= 2 && exp.right <= 2 && exp.bottom <= 2, \
33 34
           "Expected rect (%d,%d)-(%d,%d), got %s\n", _left, _top, _right, _bottom, \
           wine_dbgstr_rect(&(got))); } while (0)
35

36
static HINSTANCE hinst;
37 38 39
static WNDPROC g_status_wndproc;
static RECT g_rcCreated;
static HWND g_hMainWnd;
40
static int g_wmsize_count = 0;
41 42
static INT g_ysize;
static INT g_dpisize;
43 44
static int g_wmdrawitm_ctr;
static WNDPROC g_wndproc_saved;
45

46 47
static BOOL (WINAPI *pInitCommonControlsEx)(const INITCOMMONCONTROLSEX*);

48 49 50 51 52
static HWND create_status_control(DWORD style, DWORD exstyle)
{
    HWND hWndStatus;

    /* make the control */
53
    hWndStatus = CreateWindowExA(exstyle, STATUSCLASSNAMEA, NULL, style,
54 55 56 57
        /* placement */
        0, 0, 300, 20,
        /* parent, etc */
        NULL, NULL, hinst, NULL);
58
    ok(hWndStatus != NULL, "failed to create status wnd\n");
59 60 61
    return hWndStatus;
}

62 63
static LRESULT WINAPI create_test_wndproc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
64 65
    LRESULT ret;

66 67
    if (msg == WM_CREATE)
    {
68 69
        CREATESTRUCTA *cs = (CREATESTRUCTA *)lParam;
        ret = CallWindowProcA(g_status_wndproc, hwnd, msg, wParam, lParam);
70 71 72 73
        GetWindowRect(hwnd, &g_rcCreated);
        MapWindowPoints(HWND_DESKTOP, g_hMainWnd, (LPPOINT)&g_rcCreated, 2);
        ok(cs->x == g_rcCreated.left, "CREATESTRUCT.x modified\n");
        ok(cs->y == g_rcCreated.top, "CREATESTRUCT.y modified\n");
74 75 76
    } else if (msg == WM_SIZE)
    {
        g_wmsize_count++;
77
        ret = CallWindowProcA(g_status_wndproc, hwnd, msg, wParam, lParam);
78
    }
79
    else
80
        ret = CallWindowProcA(g_status_wndproc, hwnd, msg, wParam, lParam);
81 82

    return ret;
83 84
}

85
static void register_subclass(void)
86
{
87
    WNDCLASSEXA cls;
88

89 90
    cls.cbSize = sizeof(WNDCLASSEXA);
    GetClassInfoExA(NULL, STATUSCLASSNAMEA, &cls);
91 92
    g_status_wndproc = cls.lpfnWndProc;
    cls.lpfnWndProc = create_test_wndproc;
93
    cls.lpszClassName = SUBCLASS_NAME;
94
    cls.hInstance = NULL;
95
    ok(RegisterClassExA(&cls), "RegisterClassEx failed\n");
96
}
97

98
static void test_create(void)
99 100 101 102 103
{
    RECT rc;
    HWND hwnd;

    ok((hwnd = CreateWindowA(SUBCLASS_NAME, "", WS_CHILD|WS_VISIBLE|SBARS_SIZEGRIP, 0, 0, 100, 100,
104 105 106 107 108 109 110 111 112 113 114 115
        g_hMainWnd, NULL, NULL, 0)) != NULL, "CreateWindowA failed\n");
    MapWindowPoints(HWND_DESKTOP, g_hMainWnd, (LPPOINT)&rc, 2);
    GetWindowRect(hwnd, &rc);
    MapWindowPoints(HWND_DESKTOP, g_hMainWnd, (LPPOINT)&rc, 2);
    expect_rect(0, 0, 100, 100, g_rcCreated);
    expect(0, rc.left);
    expect(672, rc.right);
    expect(226, rc.bottom);
    /* we don't check rc.top as this may depend on user font settings */
    DestroyWindow(hwnd);
}

116
static int CALLBACK check_height_font_enumproc(ENUMLOGFONTEXA *enumlf, NEWTEXTMETRICEXA *ntm, DWORD type, LPARAM lParam)
117
{
118 119
    HWND hwndStatus = (HWND)lParam;
    HDC hdc = GetDC(NULL);
120 121 122
    static const int sizes[] = { 6,  7,  8,  9, 10, 11, 12, 13, 15, 16,
                                20, 22, 28, 36, 48, 72};
    DWORD i;
123
    INT y;
124 125 126 127 128
    LPSTR facename = (CHAR *)enumlf->elfFullName;

    /* on win9x, enumlf->elfFullName is only valid for truetype fonts */
    if (type != TRUETYPE_FONTTYPE)
        facename = enumlf->elfLogFont.lfFaceName;
129

130
    for (i = 0; i < ARRAY_SIZE(sizes); i++)
131 132
    {
        HFONT hFont;
133
        TEXTMETRICA tm;
134 135 136 137 138
        HFONT hCtrlFont;
        HFONT hOldFont;
        RECT rcCtrl;

        enumlf->elfLogFont.lfHeight = sizes[i];
139 140
        hFont = CreateFontIndirectA(&enumlf->elfLogFont);
        hCtrlFont = (HFONT)SendMessageA(hwndStatus, WM_SETFONT, (WPARAM)hFont, TRUE);
141 142 143
        hOldFont = SelectObject(hdc, hFont);

        GetClientRect(hwndStatus, &rcCtrl);
144
        GetTextMetricsA(hdc, &tm);
145 146
        y = tm.tmHeight + (tm.tmInternalLeading ? tm.tmInternalLeading : 2) + 4;

147 148 149
        ok( (rcCtrl.bottom == max(y, g_ysize)) || (rcCtrl.bottom == max(y, g_dpisize)),
            "got %d (expected %d or %d) for %s #%d\n",
            rcCtrl.bottom, max(y, g_ysize), max(y, g_dpisize), facename, sizes[i]);
150 151

        SelectObject(hdc, hOldFont);
152
        SendMessageA(hwndStatus, WM_SETFONT, (WPARAM)hCtrlFont, TRUE);
153 154 155 156 157 158
        DeleteObject(hFont);
    }
    ReleaseDC(NULL, hdc);
    return 1;
}

159
static int CALLBACK check_height_family_enumproc(ENUMLOGFONTEXA *enumlf, NEWTEXTMETRICEXA *ntm, DWORD type, LPARAM lParam)
160 161 162
{
    HDC hdc = GetDC(NULL);
    enumlf->elfLogFont.lfHeight = 0;
163
    EnumFontFamiliesExA(hdc, &enumlf->elfLogFont, (FONTENUMPROCA)check_height_font_enumproc, lParam, 0);
164 165 166 167 168 169
    ReleaseDC(NULL, hdc);
    return 1;
}

static void test_height(void)
{
170
    LOGFONTA lf;
171
    HFONT hFont, hFontSm;
172
    RECT rc1, rc2;
173
    HWND hwndStatus = CreateWindowA(SUBCLASS_NAME, NULL, WS_CHILD|WS_VISIBLE,
174
        0, 0, 300, 20, g_hMainWnd, NULL, NULL, NULL);
175
    HDC hdc;
176 177

    GetClientRect(hwndStatus, &rc1);
178
    hFont = CreateFontA(32, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE, ANSI_CHARSET,
179 180 181
        OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, FF_DONTCARE, "Tahoma");

    g_wmsize_count = 0;
182
    SendMessageA(hwndStatus, WM_SETFONT, (WPARAM)hFont, TRUE);
183 184
    if (!g_wmsize_count)
    {
185
        skip("Status control not resized in win95, skipping broken tests.\n");
186 187
        return;
    }
188 189 190
    ok(g_wmsize_count > 0, "WM_SETFONT should issue WM_SIZE\n");

    GetClientRect(hwndStatus, &rc2);
191
    expect_rect(0, 0, 672, 42, rc2); /* GetTextMetrics returns invalid tmInternalLeading for this font */
192 193

    g_wmsize_count = 0;
194
    SendMessageA(hwndStatus, WM_SETFONT, (WPARAM)hFont, TRUE);
195 196 197
    ok(g_wmsize_count > 0, "WM_SETFONT should issue WM_SIZE\n");

    GetClientRect(hwndStatus, &rc2);
198
    expect_rect(0, 0, 672, 42, rc2);
199

200
    /* minheight < fontsize - no effects*/
201 202
    SendMessageA(hwndStatus, SB_SETMINHEIGHT, 12, 0);
    SendMessageA(hwndStatus, WM_SIZE, 0, 0);
203
    GetClientRect(hwndStatus, &rc2);
204
    expect_rect(0, 0, 672, 42, rc2);
205 206

    /* minheight > fontsize - has an effect after WM_SIZE */
207
    SendMessageA(hwndStatus, SB_SETMINHEIGHT, 60, 0);
208
    GetClientRect(hwndStatus, &rc2);
209
    expect_rect(0, 0, 672, 42, rc2);
210
    SendMessageA(hwndStatus, WM_SIZE, 0, 0);
211 212 213 214
    GetClientRect(hwndStatus, &rc2);
    expect_rect(0, 0, 672, 62, rc2);

    /* font changed to smaller than minheight - has an effect */
215
    SendMessageA(hwndStatus, SB_SETMINHEIGHT, 30, 0);
216
    expect_rect(0, 0, 672, 62, rc2);
217
    SendMessageA(hwndStatus, WM_SIZE, 0, 0);
218
    GetClientRect(hwndStatus, &rc2);
219
    expect_rect(0, 0, 672, 42, rc2);
220
    hFontSm = CreateFontA(9, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE, ANSI_CHARSET,
221
        OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, FF_DONTCARE, "Tahoma");
222
    SendMessageA(hwndStatus, WM_SETFONT, (WPARAM)hFontSm, TRUE);
223 224 225
    GetClientRect(hwndStatus, &rc2);
    expect_rect(0, 0, 672, 32, rc2);

226 227
    /* test the height formula */
    ZeroMemory(&lf, sizeof(lf));
228
    SendMessageA(hwndStatus, SB_SETMINHEIGHT, 0, 0);
229
    hdc = GetDC(NULL);
230

231 232 233 234 235 236 237 238 239 240 241
    /* used only for some fonts (tahoma as example) */
    g_ysize = GetSystemMetrics(SM_CYSIZE) + 2;
    if (g_ysize & 1) g_ysize--;     /* The min height is always even */

    g_dpisize = MulDiv(18, GetDeviceCaps(hdc, LOGPIXELSY), 96) + 2;
    if (g_dpisize & 1) g_dpisize--; /* The min height is always even */


    trace("dpi=%d (min height: %d or %d) SM_CYSIZE: %d\n",
            GetDeviceCaps(hdc, LOGPIXELSY), g_ysize, g_dpisize,
            GetSystemMetrics(SM_CYSIZE));
242

243
    EnumFontFamiliesExA(hdc, &lf, (FONTENUMPROCA)check_height_family_enumproc, (LPARAM)hwndStatus, 0);
244 245
    ReleaseDC(NULL, hdc);

246 247
    DestroyWindow(hwndStatus);
    DeleteObject(hFont);
248
    DeleteObject(hFontSm);
249 250
}

251 252 253 254 255
static void test_status_control(void)
{
    HWND hWndStatus;
    int r;
    int nParts[] = {50, 150, -1};
256 257
    int checkParts[] = {0, 0, 0};
    int borders[] = {0, 0, 0};
258
    RECT rc;
259 260
    CHAR charArray[20];
    HICON hIcon;
261 262
    char ch;
    char chstr[10] = "Inval id";
263
    COLORREF crColor = RGB(0,0,0);
264

265
    hWndStatus = create_status_control(WS_VISIBLE | SBT_TOOLTIPS, 0);
266

267
    /* Divide into parts and set text */
268
    r = SendMessageA(hWndStatus, SB_SETPARTS, 3, (LPARAM)nParts);
269
    expect(TRUE,r);
270
    r = SendMessageA(hWndStatus, SB_SETTEXTA, SBT_POPOUT|0,    (LPARAM)"First");
271
    expect(TRUE,r);
272
    r = SendMessageA(hWndStatus, SB_SETTEXTA, SBT_OWNERDRAW|1, (LPARAM)"Second");
273
    expect(TRUE,r);
274
    r = SendMessageA(hWndStatus, SB_SETTEXTA, SBT_NOBORDERS|2, (LPARAM)"Third");
275
    expect(TRUE,r);
276

277
    /* Get RECT Information */
278
    r = SendMessageA(hWndStatus, SB_GETRECT, 0, (LPARAM)&rc);
279 280 281 282 283 284
    expect(TRUE,r);
    expect(2,rc.top);
    /* The rc.bottom test is system dependent
    expect(22,rc.bottom); */
    expect(0,rc.left);
    expect(50,rc.right);
285
    r = SendMessageA(hWndStatus, SB_GETRECT, -1, (LPARAM)&rc);
286
    expect(FALSE,r);
287
    r = SendMessageA(hWndStatus, SB_GETRECT, 3, (LPARAM)&rc);
288 289
    expect(FALSE,r);
    /* Get text length and text */
290
    r = SendMessageA(hWndStatus, SB_GETTEXTLENGTHA, 0, 0);
291 292 293
    expect(5,LOWORD(r));
    expect(SBT_POPOUT,HIWORD(r));
    r = SendMessageW(hWndStatus, WM_GETTEXTLENGTH, 0, 0);
294
    ok(r == 5, "Expected 5, got %d\n", r);
295
    r = SendMessageA(hWndStatus, SB_GETTEXTLENGTHA, 1, 0);
296 297
    expect(0,LOWORD(r));
    expect(SBT_OWNERDRAW,HIWORD(r));
298
    r = SendMessageA(hWndStatus, SB_GETTEXTLENGTHA, 2, 0);
299
    expect(5,LOWORD(r));
300
    expect(SBT_NOBORDERS,HIWORD(r));
301
    r = SendMessageA(hWndStatus, SB_GETTEXTA, 2, (LPARAM) charArray);
302 303
    ok(strcmp(charArray,"Third") == 0, "Expected Third, got %s\n", charArray);
    expect(5,LOWORD(r));
304
    expect(SBT_NOBORDERS,HIWORD(r));
305 306

    /* Get parts and borders */
307
    r = SendMessageA(hWndStatus, SB_GETPARTS, 3, (LPARAM)checkParts);
308 309 310 311
    ok(r == 3, "Expected 3, got %d\n", r);
    expect(50,checkParts[0]);
    expect(150,checkParts[1]);
    expect(-1,checkParts[2]);
312
    r = SendMessageA(hWndStatus, SB_GETBORDERS, 0, (LPARAM)borders);
313
    ok(r == TRUE, "Expected TRUE, got %d\n", r);
314 315 316 317 318
    expect(0,borders[0]);
    expect(2,borders[1]);
    expect(2,borders[2]);

    /* Test resetting text with different characters */
319
    r = SendMessageA(hWndStatus, SB_SETTEXTA, 0, (LPARAM)"First@Again");
320
    expect(TRUE,r);
321
    r = SendMessageA(hWndStatus, SB_SETTEXTA, 1, (LPARAM)"Invalid\tChars\\7\7");
322
        expect(TRUE,r);
323
    r = SendMessageA(hWndStatus, SB_SETTEXTA, 2, (LPARAM)"InvalidChars\\n\n");
324
        expect(TRUE,r);
325

326
    /* Get text again */
327
    r = SendMessageA(hWndStatus, SB_GETTEXTA, 0, (LPARAM) charArray);
328 329 330
    ok(strcmp(charArray,"First@Again") == 0, "Expected First@Again, got %s\n", charArray);
    expect(11,LOWORD(r));
    expect(0,HIWORD(r));
331
    r = SendMessageA(hWndStatus, SB_GETTEXTA, 1, (LPARAM) charArray);
332 333 334
    ok(strcmp(charArray,"Invalid\tChars\\7 ") == 0, "Expected Invalid\tChars\\7 , got %s\n", charArray);

    expect(16,LOWORD(r));
335
    expect(0,HIWORD(r));
336
    r = SendMessageA(hWndStatus, SB_GETTEXTA, 2, (LPARAM) charArray);
337 338
    ok(strcmp(charArray,"InvalidChars\\n ") == 0, "Expected InvalidChars\\n , got %s\n", charArray);

339 340 341
    expect(15,LOWORD(r));
    expect(0,HIWORD(r));

342 343 344
    /* test more nonprintable chars */
    for(ch = 0x00; ch < 0x7F; ch++) {
        chstr[5] = ch;
345
        r = SendMessageA(hWndStatus, SB_SETTEXTA, 0, (LPARAM)chstr);
346
        expect(TRUE,r);
347
        r = SendMessageA(hWndStatus, SB_GETTEXTA, 0, (LPARAM)charArray);
348
        ok(r == strlen(charArray), "got %d\n", r);
349 350 351 352 353 354
        /* substitution with single space */
        if (ch > 0x00 && ch < 0x20 && ch != '\t')
            chstr[5] = ' ';
        ok(strcmp(charArray, chstr) == 0, "Expected %s, got %s\n", chstr, charArray);
    }

355
    /* Set background color */
356
    crColor = SendMessageA(hWndStatus, SB_SETBKCOLOR , 0, RGB(255,0,0));
357 358 359
    ok(crColor == CLR_DEFAULT ||
       broken(crColor == RGB(0,0,0)), /* win95 */
       "Expected 0x%.8x, got 0x%.8x\n", CLR_DEFAULT, crColor);
360
    crColor = SendMessageA(hWndStatus, SB_SETBKCOLOR , 0, CLR_DEFAULT);
361 362 363
    ok(crColor == RGB(255,0,0) ||
       broken(crColor == RGB(0,0,0)), /* win95 */
       "Expected 0x%.8x, got 0x%.8x\n", RGB(255,0,0), crColor);
364 365

    /* Add an icon to the status bar */
366 367
    hIcon = LoadIconA(NULL, (LPCSTR)IDI_QUESTION);
    r = SendMessageA(hWndStatus, SB_SETICON, 1, 0);
368 369 370
    ok(r != 0 ||
       broken(r == 0), /* win95 */
       "Expected non-zero, got %d\n", r);
371
    r = SendMessageA(hWndStatus, SB_SETICON, 1, (LPARAM) hIcon);
372 373 374
    ok(r != 0 ||
       broken(r == 0), /* win95 */
       "Expected non-zero, got %d\n", r);
375
    r = SendMessageA(hWndStatus, SB_SETICON, 1, 0);
376 377 378
    ok(r != 0 ||
       broken(r == 0), /* win95 */
       "Expected non-zero, got %d\n", r);
379 380

    /* Set the Unicode format */
381
    r = SendMessageA(hWndStatus, SB_SETUNICODEFORMAT, FALSE, 0);
382
    expect(FALSE,r);
383
    r = SendMessageA(hWndStatus, SB_GETUNICODEFORMAT, 0, 0);
384
    expect(FALSE,r);
385
    r = SendMessageA(hWndStatus, SB_SETUNICODEFORMAT, TRUE, 0);
386
    expect(FALSE,r);
387
    r = SendMessageA(hWndStatus, SB_GETUNICODEFORMAT, 0, 0);
388 389 390
    ok(r == TRUE ||
       broken(r == FALSE), /* win95 */
       "Expected TRUE, got %d\n", r);
391 392

    /* Reset number of parts */
393
    r = SendMessageA(hWndStatus, SB_SETPARTS, 2, (LPARAM)nParts);
394
    expect(TRUE,r);
395
    r = SendMessageA(hWndStatus, SB_GETPARTS, 0, 0);
396
    ok(r == 2, "Expected 2, got %d\n", r);
397
    r = SendMessageA(hWndStatus, SB_SETPARTS, 0, 0);
398
    expect(FALSE,r);
399
    r = SendMessageA(hWndStatus, SB_GETPARTS, 0, 0);
400
    ok(r == 2, "Expected 2, got %d\n", r);
401 402

    /* Set the minimum height and get rectangle information again */
403 404
    SendMessageA(hWndStatus, SB_SETMINHEIGHT, 50, 0);
    r = SendMessageA(hWndStatus, WM_SIZE, 0, 0);
405
    expect(0,r);
406
    r = SendMessageA(hWndStatus, SB_GETRECT, 0, (LPARAM)&rc);
407 408 409 410 411 412
    expect(TRUE,r);
    expect(2,rc.top);
    /* The rc.bottom test is system dependent
    expect(22,rc.bottom); */
    expect(0,rc.left);
    expect(50,rc.right);
413
    r = SendMessageA(hWndStatus, SB_GETRECT, -1, (LPARAM)&rc);
414
    expect(FALSE,r);
415
    r = SendMessageA(hWndStatus, SB_GETRECT, 3, (LPARAM)&rc);
416 417 418
    expect(FALSE,r);

    /* Set the ToolTip text */
419
    SendMessageA(hWndStatus, SB_SETTIPTEXTA, 0,(LPARAM) "Tooltip Text");
420
    lstrcpyA(charArray, "apple");
421
    SendMessageA(hWndStatus, SB_GETTIPTEXTA, MAKEWPARAM (0, 20),(LPARAM) charArray);
422 423 424
    ok(strcmp(charArray,"Tooltip Text") == 0 ||
        broken(!strcmp(charArray, "apple")), /* win95 */
        "Expected Tooltip Text, got %s\n", charArray);
425 426

    /* Make simple */
427 428
    SendMessageA(hWndStatus, SB_SIMPLE, TRUE, 0);
    r = SendMessageA(hWndStatus, SB_ISSIMPLE, 0, 0);
429 430 431
    ok(r == TRUE ||
       broken(r == FALSE), /* win95 */
       "Expected TRUE, got %d\n", r);
432 433 434 435

    DestroyWindow(hWndStatus);
}

436 437 438 439 440
static LRESULT WINAPI ownerdraw_test_wndproc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    LRESULT ret;
    if (msg == WM_DRAWITEM)
        g_wmdrawitm_ctr++;
441
    ret = CallWindowProcA(g_wndproc_saved, hwnd, msg, wParam, lParam);
442 443 444 445 446 447 448 449 450 451 452
    return ret;
}

static void test_status_ownerdraw(void)
{
    HWND hWndStatus;
    int r;
    const char* statustext = "STATUS TEXT";
    LONG oldstyle;

    /* subclass the main window and make sure it is visible */
453
    g_wndproc_saved = (WNDPROC) SetWindowLongPtrA( g_hMainWnd, GWLP_WNDPROC,
454 455 456
                                                  (LONG_PTR)ownerdraw_test_wndproc );
    ok( g_wndproc_saved != 0, "failed to set the WndProc\n");
    SetWindowPos( g_hMainWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE);
457 458
    oldstyle = GetWindowLongA( g_hMainWnd, GWL_STYLE);
    SetWindowLongA( g_hMainWnd, GWL_STYLE, oldstyle | WS_VISIBLE);
459 460 461 462 463
    /* create a status child window */
    ok((hWndStatus = CreateWindowA(SUBCLASS_NAME, "", WS_CHILD|WS_VISIBLE, 0, 0, 100, 100,
                    g_hMainWnd, NULL, NULL, 0)) != NULL, "CreateWindowA failed\n");
    /* set text */
    g_wmdrawitm_ctr = 0;
464
    r = SendMessageA(hWndStatus, SB_SETTEXTA, 0, (LPARAM)statustext);
465 466 467 468
    ok( r == TRUE, "Sendmessage returned %d, expected 1\n", r);
    ok( 0 == g_wmdrawitm_ctr, "got %d drawitem messages expected none\n", g_wmdrawitm_ctr);
    /* set same text, with ownerdraw flag */
    g_wmdrawitm_ctr = 0;
469
    r = SendMessageA(hWndStatus, SB_SETTEXTA, SBT_OWNERDRAW, (LPARAM)statustext);
470 471
    ok( r == TRUE, "Sendmessage returned %d, expected 1\n", r);
    ok( 1 == g_wmdrawitm_ctr, "got %d drawitem messages expected 1\n", g_wmdrawitm_ctr);
472
    /* and again */
473
    g_wmdrawitm_ctr = 0;
474
    r = SendMessageA(hWndStatus, SB_SETTEXTA, SBT_OWNERDRAW, (LPARAM)statustext);
475 476 477 478
    ok( r == TRUE, "Sendmessage returned %d, expected 1\n", r);
    ok( 1 == g_wmdrawitm_ctr, "got %d drawitem messages expected 1\n", g_wmdrawitm_ctr);
    /* clean up */
    DestroyWindow(hWndStatus);
479 480
    SetWindowLongA( g_hMainWnd, GWL_STYLE, oldstyle);
    SetWindowLongPtrA( g_hMainWnd, GWLP_WNDPROC, (LONG_PTR)g_wndproc_saved );
481 482
}

483 484
static void test_gettext(void)
{
485
    HWND hwndStatus = CreateWindowA(SUBCLASS_NAME, NULL, WS_CHILD|WS_VISIBLE,
486 487 488 489
        0, 0, 300, 20, g_hMainWnd, NULL, NULL, NULL);
    char buf[5];
    int r;

490
    r = SendMessageA(hwndStatus, SB_SETTEXTA, 0, (LPARAM)"Text");
491
    expect(TRUE, r);
492
    r = SendMessageA(hwndStatus, WM_GETTEXTLENGTH, 0, 0);
493 494
    expect(4, r);
    /* A size of 0 returns the length of the text */
495
    r = SendMessageA(hwndStatus, WM_GETTEXT, 0, 0);
496
    ok( r == 4 || broken(r == 2) /* win8 */, "Expected 4 got %d\n", r );
497 498
    /* A size of 1 only stores the NULL terminator */
    buf[0] = 0xa;
499
    r = SendMessageA(hwndStatus, WM_GETTEXT, 1, (LPARAM)buf);
500 501
    ok( r == 0 || broken(r == 4), "Expected 0 got %d\n", r );
    if (!r) ok(!buf[0], "expected empty buffer\n");
502
    /* A size of 2 returns a length 1 */
503
    r = SendMessageA(hwndStatus, WM_GETTEXT, 2, (LPARAM)buf);
504
    ok( r == 1 || broken(r == 4), "Expected 1 got %d\n", r );
505
    r = SendMessageA(hwndStatus, WM_GETTEXT, sizeof(buf), (LPARAM)buf);
506 507 508 509 510
    expect(4, r);
    ok(!strcmp(buf, "Text"), "expected Text, got %s\n", buf);
    DestroyWindow(hwndStatus);
}

511 512 513 514 515 516 517 518 519 520 521 522 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 548 549 550 551 552 553 554 555 556 557
/* Notify events to parent */
static BOOL g_got_dblclk;
static BOOL g_got_click;
static BOOL g_got_rdblclk;
static BOOL g_got_rclick;

/* Messages to parent */
static BOOL g_got_contextmenu;

static LRESULT WINAPI test_notify_parent_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
   switch(msg)
   {
       case WM_NOTIFY:
       {
           NMHDR *hdr = ((LPNMHDR)lParam);
           switch(hdr->code)
           {
               case NM_DBLCLK: g_got_dblclk = TRUE; break;
               case NM_CLICK: g_got_click = TRUE; break;
               case NM_RDBLCLK: g_got_rdblclk = TRUE; break;
               case NM_RCLICK: g_got_rclick = TRUE; break;
           }

           /* Return zero to indicate default processing */
           return 0;
       }

       case WM_CONTEXTMENU: g_got_contextmenu = TRUE; return 0;

       default:
            return( DefWindowProcA(hwnd, msg, wParam, lParam));
   }

   return 0;
}

/* Test that WM_NOTIFY messages from the status control works correctly */
static void test_notify(void)
{
    HWND hwndParent;
    HWND hwndStatus;
    ATOM atom;
    WNDCLASSA wclass = {0};
    wclass.lpszClassName = "TestNotifyParentClass";
    wclass.lpfnWndProc   = test_notify_parent_proc;
    atom = RegisterClassA(&wclass);
558
    ok(atom, "RegisterClass failed\n");
559 560

    /* create parent */
561
    hwndParent = CreateWindowA(wclass.lpszClassName, "parent", WS_OVERLAPPEDWINDOW,
562 563 564 565
      CW_USEDEFAULT, 0, 300, 20, NULL, NULL, NULL, NULL);
    ok(hwndParent != NULL, "Parent creation failed!\n");

    /* create status bar */
566
    hwndStatus = CreateWindowA(STATUSCLASSNAMEA, NULL, WS_VISIBLE | WS_CHILD,
567 568 569 570 571
      0, 0, 300, 20, hwndParent, NULL, NULL, NULL);
    ok(hwndStatus != NULL, "Status creation failed!\n");

    /* Send various mouse event, and check that we get them */
    g_got_dblclk = FALSE;
572
    SendMessageA(hwndStatus, WM_LBUTTONDBLCLK, 0, 0);
573 574
    ok(g_got_dblclk, "WM_LBUTTONDBLCLK was not processed correctly!\n");
    g_got_rdblclk = FALSE;
575
    SendMessageA(hwndStatus, WM_RBUTTONDBLCLK, 0, 0);
576 577
    ok(g_got_rdblclk, "WM_RBUTTONDBLCLK was not processed correctly!\n");
    g_got_click = FALSE;
578
    SendMessageA(hwndStatus, WM_LBUTTONUP, 0, 0);
579 580 581 582 583
    ok(g_got_click, "WM_LBUTTONUP was not processed correctly!\n");

    /* For R-UP, check that we also get the context menu from the default processing */
    g_got_contextmenu = FALSE;
    g_got_rclick = FALSE;
584
    SendMessageA(hwndStatus, WM_RBUTTONUP, 0, 0);
585 586 587 588
    ok(g_got_rclick, "WM_RBUTTONUP was not processed correctly!\n");
    ok(g_got_contextmenu, "WM_RBUTTONUP did not activate the context menu!\n");
}

589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617
static void test_sizegrip(void)
{
    HWND hwndStatus;
    LONG style;
    RECT rc, rcClient;
    POINT pt;
    int width, r;

    hwndStatus = CreateWindowA(SUBCLASS_NAME, "", WS_CHILD|WS_VISIBLE|SBARS_SIZEGRIP,
      0, 0, 100, 100, g_hMainWnd, NULL, NULL, NULL);

    style = GetWindowLongPtrA(g_hMainWnd, GWL_STYLE);
    width = GetSystemMetrics(SM_CXVSCROLL);

    GetClientRect(hwndStatus, &rcClient);

    pt.x = rcClient.right;
    pt.y = rcClient.top;
    ClientToScreen(hwndStatus, &pt);
    rc.left = pt.x - width;
    rc.right = pt.x;
    rc.top = pt.y;

    pt.y = rcClient.bottom;
    ClientToScreen(hwndStatus, &pt);
    rc.bottom = pt.y;

    /* check bounds when not maximized */
    r = SendMessageA(hwndStatus, WM_NCHITTEST, 0, MAKELPARAM(rc.left, rc.top));
618
    expect(HTBOTTOMRIGHT, r);
619 620 621
    r = SendMessageA(hwndStatus, WM_NCHITTEST, 0, MAKELPARAM(rc.left - 1, rc.top));
    expect(HTCLIENT, r);
    r = SendMessageA(hwndStatus, WM_NCHITTEST, 0, MAKELPARAM(rc.left, rc.top - 1));
622
    expect(HTBOTTOMRIGHT, r);
623
    r = SendMessageA(hwndStatus, WM_NCHITTEST, 0, MAKELPARAM(rc.right, rc.bottom));
624
    expect(HTBOTTOMRIGHT, r);
625
    r = SendMessageA(hwndStatus, WM_NCHITTEST, 0, MAKELPARAM(rc.right + 1, rc.bottom));
626
    expect(HTBOTTOMRIGHT, r);
627
    r = SendMessageA(hwndStatus, WM_NCHITTEST, 0, MAKELPARAM(rc.right, rc.bottom + 1));
628
    expect(HTBOTTOMRIGHT, r);
629 630 631 632 633 634 635 636 637 638 639 640
    r = SendMessageA(hwndStatus, WM_NCHITTEST, 0, MAKELPARAM(rc.right - 1, rc.bottom - 1));
    expect(HTBOTTOMRIGHT, r);

    /* not maximized and right-to-left */
    SetWindowLongA(hwndStatus, GWL_EXSTYLE, WS_EX_LAYOUTRTL);

    pt.x = rcClient.right;
    ClientToScreen(hwndStatus, &pt);
    rc.left = pt.x + width;
    rc.right = pt.x;

    r = SendMessageA(hwndStatus, WM_NCHITTEST, 0, MAKELPARAM(rc.left, rc.top));
641
    expect(HTBOTTOMLEFT, r);
642 643 644
    r = SendMessageA(hwndStatus, WM_NCHITTEST, 0, MAKELPARAM(rc.left + 1, rc.top));
    expect(HTCLIENT, r);
    r = SendMessageA(hwndStatus, WM_NCHITTEST, 0, MAKELPARAM(rc.left, rc.top - 1));
645
    expect(HTBOTTOMLEFT, r);
646
    r = SendMessageA(hwndStatus, WM_NCHITTEST, 0, MAKELPARAM(rc.right, rc.bottom));
647
    expect(HTBOTTOMLEFT, r);
648
    r = SendMessageA(hwndStatus, WM_NCHITTEST, 0, MAKELPARAM(rc.right - 1, rc.bottom));
649
    expect(HTBOTTOMLEFT, r);
650
    r = SendMessageA(hwndStatus, WM_NCHITTEST, 0, MAKELPARAM(rc.right, rc.bottom + 1));
651
    expect(HTBOTTOMLEFT, r);
652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684
    r = SendMessageA(hwndStatus, WM_NCHITTEST, 0, MAKELPARAM(rc.right + 1, rc.bottom - 1));
    expect(HTBOTTOMLEFT, r);

    /* maximize with left-to-right */
    SetWindowLongA(g_hMainWnd, GWL_STYLE, style|WS_MAXIMIZE);
    SetWindowLongA(hwndStatus, GWL_EXSTYLE, 0);

    GetClientRect(hwndStatus, &rcClient);

    pt.x = rcClient.right;
    pt.y = rcClient.top;
    ClientToScreen(hwndStatus, &pt);
    rc.left = pt.x - width;
    rc.right = pt.x;
    rc.top = pt.y;

    pt.y = rcClient.bottom;
    ClientToScreen(hwndStatus, &pt);
    rc.bottom = pt.y;

    r = SendMessageA(hwndStatus, WM_NCHITTEST, 0, MAKELPARAM(rc.left, rc.top));
    expect(HTCLIENT, r);
    r = SendMessageA(hwndStatus, WM_NCHITTEST, 0, MAKELPARAM(rc.left - 1, rc.top));
    expect(HTCLIENT, r);
    r = SendMessageA(hwndStatus, WM_NCHITTEST, 0, MAKELPARAM(rc.left, rc.top - 1));
    expect(HTNOWHERE, r);
    r = SendMessageA(hwndStatus, WM_NCHITTEST, 0, MAKELPARAM(rc.right, rc.bottom));
    expect(HTNOWHERE, r);
    r = SendMessageA(hwndStatus, WM_NCHITTEST, 0, MAKELPARAM(rc.right + 1, rc.bottom));
    expect(HTNOWHERE, r);
    r = SendMessageA(hwndStatus, WM_NCHITTEST, 0, MAKELPARAM(rc.right, rc.bottom + 1));
    expect(HTNOWHERE, r);
    r = SendMessageA(hwndStatus, WM_NCHITTEST, 0, MAKELPARAM(rc.right - 1, rc.bottom - 1));
685
    expect(HTCLIENT, r);
686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707

    /* maximized with right-to-left */
    SetWindowLongA(hwndStatus, GWL_EXSTYLE, WS_EX_LAYOUTRTL);

    pt.x = rcClient.right;
    ClientToScreen(hwndStatus, &pt);
    rc.left = pt.x + width;
    rc.right = pt.x;

    r = SendMessageA(hwndStatus, WM_NCHITTEST, 0, MAKELPARAM(rc.left, rc.top));
    expect(HTCLIENT, r);
    r = SendMessageA(hwndStatus, WM_NCHITTEST, 0, MAKELPARAM(rc.left + 1, rc.top));
    expect(HTCLIENT, r);
    r = SendMessageA(hwndStatus, WM_NCHITTEST, 0, MAKELPARAM(rc.left, rc.top - 1));
    expect(HTNOWHERE, r);
    r = SendMessageA(hwndStatus, WM_NCHITTEST, 0, MAKELPARAM(rc.right, rc.bottom));
    expect(HTNOWHERE, r);
    r = SendMessageA(hwndStatus, WM_NCHITTEST, 0, MAKELPARAM(rc.right - 1, rc.bottom));
    expect(HTNOWHERE, r);
    r = SendMessageA(hwndStatus, WM_NCHITTEST, 0, MAKELPARAM(rc.right, rc.bottom + 1));
    expect(HTNOWHERE, r);
    r = SendMessageA(hwndStatus, WM_NCHITTEST, 0, MAKELPARAM(rc.right + 1, rc.bottom - 1));
708
    expect(HTCLIENT, r);
709 710 711 712 713

    SetWindowLongA(g_hMainWnd, GWL_STYLE, style);
    DestroyWindow(hwndStatus);
}

714 715 716 717 718 719 720 721 722
static void init_functions(void)
{
    HMODULE hComCtl32 = LoadLibraryA("comctl32.dll");

#define X(f) p##f = (void*)GetProcAddress(hComCtl32, #f);
    X(InitCommonControlsEx);
#undef X
}

723 724
START_TEST(status)
{
725 726 727 728
    INITCOMMONCONTROLSEX iccex;

    init_functions();

729 730
    hinst = GetModuleHandleA(NULL);

731 732 733 734
    iccex.dwSize = sizeof(iccex);
    iccex.dwICC  = ICC_BAR_CLASSES;
    pInitCommonControlsEx(&iccex);

735
    g_hMainWnd = CreateWindowExA(0, WC_STATICA, "", WS_OVERLAPPEDWINDOW,
736 737 738 739
      CW_USEDEFAULT, CW_USEDEFAULT, 672+2*GetSystemMetrics(SM_CXSIZEFRAME),
      226+GetSystemMetrics(SM_CYCAPTION)+2*GetSystemMetrics(SM_CYSIZEFRAME),
      NULL, NULL, GetModuleHandleA(NULL), 0);

740 741
    register_subclass();

742
    test_status_control();
743
    test_create();
744
    test_height();
745
    test_status_ownerdraw();
746
    test_gettext();
747
    test_notify();
748
    test_sizegrip();
749
}