1 /* Unit tests for the progress bar control. 2 * 3 * Copyright 2005 Michael Kaufmann 4 * 5 * This library is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU Lesser General Public 7 * License as published by the Free Software Foundation; either 8 * version 2.1 of the License, or (at your option) any later version. 9 * 10 * This library is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 * Lesser General Public License for more details. 14 * 15 * You should have received a copy of the GNU Lesser General Public 16 * License along with this library; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 18 */ 19 20 #include <stdarg.h> 21 22 #include "windef.h" 23 #include "winbase.h" 24 #include "wingdi.h" 25 #include "winuser.h" 26 #include "commctrl.h" 27 28 #include "wine/test.h" 29 30 #include "v6util.h" 31 32 static HWND hProgressParentWnd; 33 static const char progressTestClass[] = "ProgressBarTestClass"; 34 static BOOL (WINAPI *pInitCommonControlsEx)(const INITCOMMONCONTROLSEX*); 35 36 static HWND create_progress(DWORD style) 37 { 38 return CreateWindowExA(0, PROGRESS_CLASSA, "", WS_VISIBLE | style, 39 0, 0, 100, 20, NULL, NULL, GetModuleHandleA(NULL), 0); 40 } 41 42 /* try to make sure pending X events have been processed before continuing */ 43 static void flush_events(void) 44 { 45 MSG msg; 46 int diff = 100; 47 DWORD time = GetTickCount() + diff; 48 49 while (diff > 0) 50 { 51 if (MsgWaitForMultipleObjects( 0, NULL, FALSE, min(10,diff), QS_ALLINPUT ) == WAIT_TIMEOUT) break; 52 while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg ); 53 diff = time - GetTickCount(); 54 } 55 } 56 57 static LRESULT CALLBACK progress_test_wnd_proc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) 58 { 59 switch(msg) { 60 61 case WM_DESTROY: 62 PostQuitMessage(0); 63 break; 64 65 default: 66 return DefWindowProcA(hWnd, msg, wParam, lParam); 67 } 68 69 return 0L; 70 } 71 72 static WNDPROC progress_wndproc; 73 static BOOL erased; 74 static RECT last_paint_rect; 75 76 static LRESULT CALLBACK progress_subclass_proc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) 77 { 78 if (msg == WM_PAINT) 79 { 80 GetUpdateRect(hWnd, &last_paint_rect, FALSE); 81 } 82 else if (msg == WM_ERASEBKGND) 83 { 84 erased = TRUE; 85 } 86 return CallWindowProcA(progress_wndproc, hWnd, msg, wParam, lParam); 87 } 88 89 90 static void update_window(HWND hWnd) 91 { 92 UpdateWindow(hWnd); 93 ok(!GetUpdateRect(hWnd, NULL, FALSE), "GetUpdateRect must return zero after UpdateWindow\n"); 94 } 95 96 97 static void init(void) 98 { 99 WNDCLASSA wc; 100 RECT rect; 101 BOOL ret; 102 103 wc.style = CS_HREDRAW | CS_VREDRAW; 104 wc.cbClsExtra = 0; 105 wc.cbWndExtra = 0; 106 wc.hInstance = GetModuleHandleA(NULL); 107 wc.hIcon = NULL; 108 wc.hCursor = LoadCursorA(NULL, (LPCSTR)IDC_ARROW); 109 wc.hbrBackground = GetSysColorBrush(COLOR_WINDOW); 110 wc.lpszMenuName = NULL; 111 wc.lpszClassName = progressTestClass; 112 wc.lpfnWndProc = progress_test_wnd_proc; 113 RegisterClassA(&wc); 114 115 SetRect(&rect, 0, 0, 400, 20); 116 ret = AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE); 117 ok(ret, "got %d\n", ret); 118 119 hProgressParentWnd = CreateWindowExA(0, progressTestClass, "Progress Bar Test", WS_OVERLAPPEDWINDOW, 120 CW_USEDEFAULT, CW_USEDEFAULT, rect.right - rect.left, rect.bottom - rect.top, NULL, NULL, GetModuleHandleA(NULL), 0); 121 ok(hProgressParentWnd != NULL, "failed to create parent wnd\n"); 122 123 } 124 125 static void cleanup(void) 126 { 127 MSG msg; 128 129 PostMessageA(hProgressParentWnd, WM_CLOSE, 0, 0); 130 while (GetMessageA(&msg,0,0,0)) { 131 TranslateMessage(&msg); 132 DispatchMessageA(&msg); 133 } 134 135 UnregisterClassA(progressTestClass, GetModuleHandleA(NULL)); 136 } 137 138 139 /* 140 * Tests if a progress bar repaints itself immediately when it receives 141 * some specific messages. 142 */ 143 static void test_redraw(void) 144 { 145 RECT client_rect, rect; 146 HWND hProgressWnd; 147 LRESULT ret; 148 149 GetClientRect(hProgressParentWnd, &rect); 150 hProgressWnd = CreateWindowExA(0, PROGRESS_CLASSA, "", WS_CHILD | WS_VISIBLE, 151 0, 0, rect.right, rect.bottom, hProgressParentWnd, NULL, GetModuleHandleA(NULL), 0); 152 ok(hProgressWnd != NULL, "Failed to create progress bar.\n"); 153 progress_wndproc = (WNDPROC)SetWindowLongPtrA(hProgressWnd, GWLP_WNDPROC, (LPARAM)progress_subclass_proc); 154 155 ShowWindow(hProgressParentWnd, SW_SHOWNORMAL); 156 ok(GetUpdateRect(hProgressParentWnd, NULL, FALSE), "GetUpdateRect: There should be a region that needs to be updated\n"); 157 flush_events(); 158 update_window(hProgressParentWnd); 159 160 SendMessageA(hProgressWnd, PBM_SETRANGE, 0, MAKELPARAM(0, 100)); 161 SendMessageA(hProgressWnd, PBM_SETPOS, 10, 0); 162 SendMessageA(hProgressWnd, PBM_SETSTEP, 20, 0); 163 update_window(hProgressWnd); 164 165 /* PBM_SETPOS */ 166 ok(SendMessageA(hProgressWnd, PBM_SETPOS, 50, 0) == 10, "PBM_SETPOS must return the previous position\n"); 167 ok(!GetUpdateRect(hProgressWnd, NULL, FALSE), "PBM_SETPOS: The progress bar should be redrawn immediately\n"); 168 169 /* PBM_DELTAPOS */ 170 ok(SendMessageA(hProgressWnd, PBM_DELTAPOS, 15, 0) == 50, "PBM_DELTAPOS must return the previous position\n"); 171 ok(!GetUpdateRect(hProgressWnd, NULL, FALSE), "PBM_DELTAPOS: The progress bar should be redrawn immediately\n"); 172 173 /* PBM_SETPOS */ 174 ok(SendMessageA(hProgressWnd, PBM_SETPOS, 80, 0) == 65, "PBM_SETPOS must return the previous position\n"); 175 ok(!GetUpdateRect(hProgressWnd, NULL, FALSE), "PBM_SETPOS: The progress bar should be redrawn immediately\n"); 176 177 /* PBM_STEPIT */ 178 ok(SendMessageA(hProgressWnd, PBM_STEPIT, 0, 0) == 80, "PBM_STEPIT must return the previous position\n"); 179 ok(!GetUpdateRect(hProgressWnd, NULL, FALSE), "PBM_STEPIT: The progress bar should be redrawn immediately\n"); 180 ret = SendMessageA(hProgressWnd, PBM_GETPOS, 0, 0); 181 if (ret == 0) 182 win_skip("PBM_GETPOS needs comctl32 > 4.70\n"); 183 else 184 ok(ret == 100, "PBM_GETPOS returned a wrong position : %d\n", (UINT)ret); 185 186 /* PBM_SETRANGE and PBM_SETRANGE32: 187 Usually the progress bar doesn't repaint itself immediately. If the 188 position is not in the new range, it does. 189 Don't test this, it may change in future Windows versions. */ 190 191 SendMessageA(hProgressWnd, PBM_SETPOS, 0, 0); 192 update_window(hProgressWnd); 193 194 /* increase to 10 - no background erase required */ 195 erased = FALSE; 196 SetRectEmpty(&last_paint_rect); 197 SendMessageA(hProgressWnd, PBM_SETPOS, 10, 0); 198 GetClientRect(hProgressWnd, &client_rect); 199 ok(EqualRect(&last_paint_rect, &client_rect), "last_paint_rect was %s instead of %s\n", 200 wine_dbgstr_rect(&last_paint_rect), wine_dbgstr_rect(&client_rect)); 201 update_window(hProgressWnd); 202 ok(!erased, "Progress bar shouldn't have erased the background\n"); 203 204 /* decrease to 0 - background erase will be required */ 205 erased = FALSE; 206 SetRectEmpty(&last_paint_rect); 207 SendMessageA(hProgressWnd, PBM_SETPOS, 0, 0); 208 GetClientRect(hProgressWnd, &client_rect); 209 ok(EqualRect(&last_paint_rect, &client_rect), "last_paint_rect was %s instead of %s\n", 210 wine_dbgstr_rect(&last_paint_rect), wine_dbgstr_rect(&client_rect)); 211 update_window(hProgressWnd); 212 ok(erased, "Progress bar should have erased the background\n"); 213 214 DestroyWindow(hProgressWnd); 215 } 216 217 static void test_setcolors(void) 218 { 219 HWND progress; 220 COLORREF clr; 221 222 progress = create_progress(PBS_SMOOTH); 223 224 clr = SendMessageA(progress, PBM_SETBARCOLOR, 0, 0); 225 ok(clr == CLR_DEFAULT, "got %x\n", clr); 226 227 clr = SendMessageA(progress, PBM_SETBARCOLOR, 0, RGB(0, 255, 0)); 228 ok(clr == 0, "got %x\n", clr); 229 230 clr = SendMessageA(progress, PBM_SETBARCOLOR, 0, CLR_DEFAULT); 231 ok(clr == RGB(0, 255, 0), "got %x\n", clr); 232 233 clr = SendMessageA(progress, PBM_SETBKCOLOR, 0, 0); 234 ok(clr == CLR_DEFAULT, "got %x\n", clr); 235 236 clr = SendMessageA(progress, PBM_SETBKCOLOR, 0, RGB(255, 0, 0)); 237 ok(clr == 0, "got %x\n", clr); 238 239 clr = SendMessageA(progress, PBM_SETBKCOLOR, 0, CLR_DEFAULT); 240 ok(clr == RGB(255, 0, 0), "got %x\n", clr); 241 242 DestroyWindow(progress); 243 } 244 245 static void test_PBM_STEPIT(void) 246 { 247 struct stepit_test 248 { 249 int min; 250 int max; 251 int step; 252 } stepit_tests[] = 253 { 254 { 3, 15, 5 }, 255 { 3, 15, -5 }, 256 { 3, 15, 50 }, 257 }; 258 HWND progress; 259 int i, j; 260 261 for (i = 0; i < ARRAY_SIZE(stepit_tests); i++) 262 { 263 struct stepit_test *test = &stepit_tests[i]; 264 LRESULT ret; 265 266 progress = create_progress(0); 267 268 ret = SendMessageA(progress, PBM_SETRANGE32, test->min, test->max); 269 ok(ret != 0, "Unexpected return value.\n"); 270 271 SendMessageA(progress, PBM_SETPOS, test->min, 0); 272 SendMessageA(progress, PBM_SETSTEP, test->step, 0); 273 274 for (j = 0; j < test->max; j++) 275 { 276 int pos = SendMessageA(progress, PBM_GETPOS, 0, 0); 277 int current; 278 279 pos += test->step; 280 if (pos > test->max) 281 pos = (pos - test->min) % (test->max - test->min) + test->min; 282 if (pos < test->min) 283 pos = (pos - test->min) % (test->max - test->min) + test->max; 284 285 SendMessageA(progress, PBM_STEPIT, 0, 0); 286 287 current = SendMessageA(progress, PBM_GETPOS, 0, 0); 288 ok(current == pos, "Unexpected position %d, expected %d.\n", current, pos); 289 } 290 291 DestroyWindow(progress); 292 } 293 } 294 295 static void init_functions(void) 296 { 297 HMODULE hComCtl32 = LoadLibraryA("comctl32.dll"); 298 299 #define X(f) p##f = (void*)GetProcAddress(hComCtl32, #f); 300 X(InitCommonControlsEx); 301 #undef X 302 } 303 304 START_TEST(progress) 305 { 306 INITCOMMONCONTROLSEX iccex; 307 ULONG_PTR ctx_cookie; 308 HANDLE hCtx; 309 310 init_functions(); 311 312 iccex.dwSize = sizeof(iccex); 313 iccex.dwICC = ICC_PROGRESS_CLASS; 314 pInitCommonControlsEx(&iccex); 315 316 init(); 317 318 test_redraw(); 319 test_setcolors(); 320 test_PBM_STEPIT(); 321 322 if (!load_v6_module(&ctx_cookie, &hCtx)) 323 return; 324 325 test_setcolors(); 326 test_PBM_STEPIT(); 327 328 unload_v6_module(ctx_cookie, hCtx); 329 330 cleanup(); 331 } 332