push 4e98c31ec75caed2ea3040ac2e710b58ba1ca0e1
[wine/hacks.git] / dlls / shell32 / tests / appbar.c
blob9991fe284e80b82de773d86a5447cb0664f91a9f
1 /* Unit tests for appbars
3 * Copyright 2008 Vincent Povirk for CodeWeavers
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.
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.
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
20 #include <assert.h>
21 #include <stdarg.h>
23 #include <windows.h>
25 #include "wine/test.h"
27 #define MSG_APPBAR WM_APP
29 static const CHAR testwindow_class[] = "testwindow";
31 static HMONITOR (WINAPI *pMonitorFromWindow)(HWND, DWORD);
33 typedef BOOL (*boolean_function)(void);
35 struct testwindow_info
37 HWND hwnd;
38 BOOL registered;
39 RECT desired_rect;
40 UINT edge;
41 RECT allocated_rect;
44 static struct testwindow_info windows[3];
46 static int expected_bottom;
48 static void testwindow_setpos(HWND hwnd)
50 struct testwindow_info* info = (struct testwindow_info*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
51 APPBARDATA abd;
52 BOOL ret;
54 ok(info != NULL, "got unexpected ABN_POSCHANGED notification\n");
56 if (!info || !info->registered)
58 return;
61 abd.cbSize = sizeof(abd);
62 abd.hWnd = hwnd;
63 abd.uEdge = info->edge;
64 abd.rc = info->desired_rect;
65 ret = SHAppBarMessage(ABM_QUERYPOS, &abd);
66 ok(ret == TRUE, "SHAppBarMessage returned %i\n", ret);
67 switch (info->edge)
69 case ABE_BOTTOM:
70 ok(info->desired_rect.top == abd.rc.top, "ABM_QUERYPOS changed top of rect from %i to %i\n", info->desired_rect.top, abd.rc.top);
71 abd.rc.top = abd.rc.bottom - (info->desired_rect.bottom - info->desired_rect.top);
72 break;
73 case ABE_LEFT:
74 ok(info->desired_rect.right == abd.rc.right, "ABM_QUERYPOS changed right of rect from %i to %i\n", info->desired_rect.top, abd.rc.top);
75 abd.rc.right = abd.rc.left + (info->desired_rect.right - info->desired_rect.left);
76 break;
77 case ABE_RIGHT:
78 ok(info->desired_rect.left == abd.rc.left, "ABM_QUERYPOS changed left of rect from %i to %i\n", info->desired_rect.top, abd.rc.top);
79 abd.rc.left = abd.rc.right - (info->desired_rect.right - info->desired_rect.left);
80 break;
81 case ABE_TOP:
82 ok(info->desired_rect.bottom == abd.rc.bottom, "ABM_QUERYPOS changed bottom of rect from %i to %i\n", info->desired_rect.top, abd.rc.top);
83 abd.rc.bottom = abd.rc.top + (info->desired_rect.bottom - info->desired_rect.top);
84 break;
87 ret = SHAppBarMessage(ABM_SETPOS, &abd);
88 ok(ret == TRUE, "SHAppBarMessage returned %i\n", ret);
90 info->allocated_rect = abd.rc;
91 MoveWindow(hwnd, abd.rc.left, abd.rc.top, abd.rc.right-abd.rc.left, abd.rc.bottom-abd.rc.top, TRUE);
94 static LRESULT CALLBACK testwindow_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
96 switch(msg)
98 case MSG_APPBAR:
100 switch(wparam)
102 case ABN_POSCHANGED:
103 testwindow_setpos(hwnd);
104 break;
106 return 0;
110 return DefWindowProc(hwnd, msg, wparam, lparam);
113 /* process pending messages until a condition is true or 3 seconds pass */
114 static void do_events_until(boolean_function test)
116 MSG msg;
117 UINT_PTR timerid;
118 BOOL timedout=FALSE;
120 timerid = SetTimer(0, 0, 3000, NULL);
122 while (1)
124 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
126 if (msg.hwnd == 0 && msg.message == WM_TIMER && msg.wParam == timerid)
127 timedout = TRUE;
128 TranslateMessage(&msg);
129 DispatchMessageA(&msg);
131 if (timedout || test())
132 break;
133 WaitMessage();
136 KillTimer(0, timerid);
139 /* process any pending messages */
140 static void do_events(void)
142 MSG msg;
144 while (PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE))
146 TranslateMessage(&msg);
147 DispatchMessageA(&msg);
151 static BOOL no_appbars_intersect(void)
153 int i, j;
154 RECT rc;
156 for (i=0; i<2; i++)
158 for (j=i+1; j<3; j++)
160 if (windows[i].registered && windows[j].registered &&
161 IntersectRect(&rc, &windows[i].allocated_rect, &windows[j].allocated_rect))
162 return FALSE;
165 return TRUE;
168 static BOOL got_expected_bottom(void)
170 return (no_appbars_intersect() && windows[1].allocated_rect.bottom == expected_bottom);
173 static void register_testwindow_class(void)
175 WNDCLASSEXA cls;
177 ZeroMemory(&cls, sizeof(cls));
178 cls.cbSize = sizeof(cls);
179 cls.style = 0;
180 cls.lpfnWndProc = testwindow_wndproc;
181 cls.hInstance = NULL;
182 cls.hCursor = LoadCursor(0, IDC_ARROW);
183 cls.hbrBackground = (HBRUSH) COLOR_WINDOW;
184 cls.lpszClassName = testwindow_class;
186 RegisterClassExA(&cls);
189 #define test_window_rects(a, b) \
190 ok(!IntersectRect(&rc, &windows[a].allocated_rect, &windows[b].allocated_rect), \
191 "rectangles intersect (%i,%i,%i,%i)/(%i,%i,%i,%i)\n", \
192 windows[a].allocated_rect.left, windows[a].allocated_rect.top, windows[a].allocated_rect.right, windows[a].allocated_rect.bottom, \
193 windows[b].allocated_rect.left, windows[b].allocated_rect.top, windows[b].allocated_rect.right, windows[b].allocated_rect.bottom)
195 static void test_setpos(void)
197 APPBARDATA abd;
198 RECT rc;
199 int screen_width, screen_height;
200 BOOL ret;
202 screen_width = GetSystemMetrics(SM_CXSCREEN);
203 screen_height = GetSystemMetrics(SM_CYSCREEN);
205 /* create and register windows[0] */
206 windows[0].hwnd = CreateWindowExA(WS_EX_TOOLWINDOW|WS_EX_TOPMOST,
207 testwindow_class, testwindow_class, WS_POPUP|WS_VISIBLE, 0, 0, 0, 0,
208 NULL, NULL, NULL, NULL);
209 ok(windows[0].hwnd != NULL, "couldn't create window\n");
210 do_events();
211 abd.cbSize = sizeof(abd);
212 abd.hWnd = windows[0].hwnd;
213 abd.uCallbackMessage = MSG_APPBAR;
214 ret = SHAppBarMessage(ABM_NEW, &abd);
215 ok(ret == TRUE, "SHAppBarMessage returned %i\n", ret);
217 /* ABM_NEW should return FALSE if the window is already registered */
218 ret = SHAppBarMessage(ABM_NEW, &abd);
219 ok(ret == FALSE, "SHAppBarMessage returned %i\n", ret);
220 do_events();
222 /* dock windows[0] to the bottom of the screen */
223 windows[0].registered = TRUE;
224 windows[0].edge = ABE_BOTTOM;
225 windows[0].desired_rect.left = 0;
226 windows[0].desired_rect.right = screen_width;
227 windows[0].desired_rect.top = screen_height - 15;
228 windows[0].desired_rect.bottom = screen_height;
229 SetWindowLongPtr(windows[0].hwnd, GWLP_USERDATA, (LONG_PTR)&windows[0]);
230 testwindow_setpos(windows[0].hwnd);
231 do_events();
233 /* create and register windows[1] */
234 windows[1].hwnd = CreateWindowExA(WS_EX_TOOLWINDOW|WS_EX_TOPMOST,
235 testwindow_class, testwindow_class, WS_POPUP|WS_VISIBLE, 0, 0, 0, 0,
236 NULL, NULL, NULL, NULL);
237 ok(windows[1].hwnd != NULL, "couldn't create window\n");
238 abd.hWnd = windows[1].hwnd;
239 ret = SHAppBarMessage(ABM_NEW, &abd);
240 ok(ret == TRUE, "SHAppBarMessage returned %i\n", ret);
242 /* dock windows[1] to the bottom of the screen */
243 windows[1].registered = TRUE;
244 windows[1].edge = ABE_BOTTOM;
245 windows[1].desired_rect.left = 0;
246 windows[1].desired_rect.right = screen_width;
247 windows[1].desired_rect.top = screen_height - 10;
248 windows[1].desired_rect.bottom = screen_height;
249 SetWindowLongPtr(windows[1].hwnd, GWLP_USERDATA, (LONG_PTR)&windows[1]);
250 testwindow_setpos(windows[1].hwnd);
252 /* the windows are adjusted to they don't overlap */
253 do_events_until(no_appbars_intersect);
254 test_window_rects(0, 1);
256 /* make windows[0] larger, forcing windows[1] to move out of its way */
257 windows[0].desired_rect.top = screen_height - 20;
258 testwindow_setpos(windows[0].hwnd);
259 do_events_until(no_appbars_intersect);
260 test_window_rects(0, 1);
262 /* create and register windows[2] */
263 windows[2].hwnd = CreateWindowExA(WS_EX_TOOLWINDOW|WS_EX_TOPMOST,
264 testwindow_class, testwindow_class, WS_POPUP|WS_VISIBLE, 0, 0, 0, 0,
265 NULL, NULL, NULL, NULL);
266 ok(windows[2].hwnd != NULL, "couldn't create window\n");
267 do_events();
269 abd.hWnd = windows[2].hwnd;
270 ret = SHAppBarMessage(ABM_NEW, &abd);
271 ok(ret == TRUE, "SHAppBarMessage returned %i\n", ret);
273 /* dock windows[2] to the bottom of the screen */
274 windows[2].registered = TRUE;
275 windows[2].edge = ABE_BOTTOM;
276 windows[2].desired_rect.left = 0;
277 windows[2].desired_rect.right = screen_width;
278 windows[2].desired_rect.top = screen_height - 10;
279 windows[2].desired_rect.bottom = screen_height;
280 SetWindowLongPtr(windows[2].hwnd, GWLP_USERDATA, (LONG_PTR)&windows[2]);
281 testwindow_setpos(windows[2].hwnd);
283 do_events_until(no_appbars_intersect);
284 test_window_rects(0, 1);
285 test_window_rects(0, 2);
286 test_window_rects(1, 2);
288 /* move windows[2] to the right side of the screen */
289 windows[2].edge = ABE_RIGHT;
290 windows[2].desired_rect.left = screen_width - 15;
291 windows[2].desired_rect.right = screen_width;
292 windows[2].desired_rect.top = 0;
293 windows[2].desired_rect.bottom = screen_height;
294 testwindow_setpos(windows[2].hwnd);
296 do_events_until(no_appbars_intersect);
297 test_window_rects(0, 1);
298 test_window_rects(0, 2);
299 test_window_rects(1, 2);
301 /* move windows[1] to the top of the screen */
302 windows[1].edge = ABE_TOP;
303 windows[1].desired_rect.left = 0;
304 windows[1].desired_rect.right = screen_width;
305 windows[1].desired_rect.top = 0;
306 windows[1].desired_rect.bottom = 15;
307 testwindow_setpos(windows[1].hwnd);
309 do_events_until(no_appbars_intersect);
310 test_window_rects(0, 1);
311 test_window_rects(0, 2);
312 test_window_rects(1, 2);
314 /* move windows[1] back to the bottom of the screen */
315 windows[1].edge = ABE_BOTTOM;
316 windows[1].desired_rect.left = 0;
317 windows[1].desired_rect.right = screen_width;
318 windows[1].desired_rect.top = screen_height - 10;
319 windows[1].desired_rect.bottom = screen_height;
320 testwindow_setpos(windows[1].hwnd);
322 do_events_until(no_appbars_intersect);
323 test_window_rects(0, 1);
324 test_window_rects(0, 2);
325 test_window_rects(1, 2);
327 /* removing windows[0] will cause windows[1] to move down into its space */
328 expected_bottom = max(windows[0].allocated_rect.bottom, windows[1].allocated_rect.bottom);
330 abd.hWnd = windows[0].hwnd;
331 ret = SHAppBarMessage(ABM_REMOVE, &abd);
332 ok(ret == TRUE, "SHAppBarMessage returned %i\n", ret);
333 windows[0].registered = FALSE;
334 DestroyWindow(windows[0].hwnd);
336 do_events_until(got_expected_bottom);
338 ok(windows[1].allocated_rect.bottom = expected_bottom, "windows[1]'s bottom is %i, expected %i\n", windows[1].allocated_rect.bottom, expected_bottom);
340 test_window_rects(1, 2);
342 /* remove the other windows */
343 SetWindowLongPtr(windows[1].hwnd, GWLP_USERDATA, 0);
344 abd.hWnd = windows[1].hwnd;
345 ret = SHAppBarMessage(ABM_REMOVE, &abd);
346 ok(ret == TRUE, "SHAppBarMessage returned %i\n", ret);
347 windows[1].registered = FALSE;
348 DestroyWindow(windows[1].hwnd);
350 SetWindowLongPtr(windows[2].hwnd, GWLP_USERDATA, 0);
351 abd.hWnd = windows[2].hwnd;
352 ret = SHAppBarMessage(ABM_REMOVE, &abd);
353 ok(ret == TRUE, "SHAppBarMessage returned %i\n", ret);
354 windows[2].registered = FALSE;
355 DestroyWindow(windows[2].hwnd);
358 static void test_appbarget(void)
360 APPBARDATA abd;
361 HWND hwnd, foregnd;
362 UINT_PTR ret;
364 memset(&abd, 0xcc, sizeof(abd));
365 abd.cbSize = sizeof(abd);
366 abd.uEdge = ABE_BOTTOM;
368 hwnd = (HWND)SHAppBarMessage(ABM_GETAUTOHIDEBAR, &abd);
369 ok(hwnd == NULL || IsWindow(hwnd), "ret %p which is not a window\n", hwnd);
370 ok(abd.hWnd == (HWND)0xcccccccc, "hWnd overwritten\n");
372 if (!pMonitorFromWindow)
374 skip("MonitorFromWindow is not available\n");
376 else
378 /* Presumably one can pass a hwnd with ABM_GETAUTOHIDEBAR to specify a monitor.
379 Pass the foreground window and check */
380 foregnd = GetForegroundWindow();
381 if(foregnd)
383 abd.hWnd = foregnd;
384 hwnd = (HWND)SHAppBarMessage(ABM_GETAUTOHIDEBAR, &abd);
385 ok(hwnd == NULL || IsWindow(hwnd), "ret %p which is not a window\n", hwnd);
386 ok(abd.hWnd == foregnd, "hWnd overwritten\n");
387 if(hwnd)
389 HMONITOR appbar_mon, foregnd_mon;
390 appbar_mon = pMonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
391 foregnd_mon = pMonitorFromWindow(foregnd, MONITOR_DEFAULTTONEAREST);
392 ok(appbar_mon == foregnd_mon, "Windows on different monitors\n");
397 memset(&abd, 0xcc, sizeof(abd));
398 abd.cbSize = sizeof(abd);
399 ret = SHAppBarMessage(ABM_GETTASKBARPOS, &abd);
400 if(ret)
402 ok(abd.hWnd == (HWND)0xcccccccc, "hWnd overwritten\n");
403 todo_wine
405 ok(abd.uEdge <= ABE_BOTTOM, "uEdge not returned\n");
406 ok(abd.rc.left != 0xcccccccc, "rc not updated\n");
410 return;
413 START_TEST(appbar)
415 HMODULE huser32;
417 huser32 = GetModuleHandleA("user32.dll");
418 pMonitorFromWindow = (void*)GetProcAddress(huser32, "MonitorFromWindow");
420 register_testwindow_class();
422 test_setpos();
423 test_appbarget();