explorer: Implement ABM_ADD and ABM_REMOVE.
[wine/multimedia.git] / dlls / shell32 / tests / appbar.c
blob108ead33dbe7c9769614edc8c6436da82fcdd6dd
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 WCHAR testwindow_class[] = {'t','e','s','t','w','i','n','d','o','w',0};
31 static HMONITOR (WINAPI *pMonitorFromWindow)(HWND, DWORD);
33 struct testwindow_info
35 RECT desired_rect;
36 UINT edge;
37 RECT allocated_rect;
40 static void testwindow_setpos(HWND hwnd)
42 struct testwindow_info* info = (struct testwindow_info*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
43 APPBARDATA abd;
44 BOOL ret;
46 ok(info != NULL, "got unexpected ABN_POSCHANGED notification\n");
48 if (!info)
50 return;
53 abd.cbSize = sizeof(abd);
54 abd.hWnd = hwnd;
55 abd.uEdge = info->edge;
56 abd.rc = info->desired_rect;
57 ret = SHAppBarMessage(ABM_QUERYPOS, &abd);
58 ok(ret == TRUE, "SHAppBarMessage returned %i\n", ret);
59 switch (info->edge)
61 case ABE_BOTTOM:
62 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);
63 abd.rc.top = abd.rc.bottom - (info->desired_rect.bottom - info->desired_rect.top);
64 break;
65 case ABE_LEFT:
66 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);
67 abd.rc.right = abd.rc.left + (info->desired_rect.right - info->desired_rect.left);
68 break;
69 case ABE_RIGHT:
70 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);
71 abd.rc.left = abd.rc.right - (info->desired_rect.right - info->desired_rect.left);
72 break;
73 case ABE_TOP:
74 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);
75 abd.rc.bottom = abd.rc.top + (info->desired_rect.bottom - info->desired_rect.top);
76 break;
79 ret = SHAppBarMessage(ABM_SETPOS, &abd);
80 ok(ret == TRUE, "SHAppBarMessage returned %i\n", ret);
82 info->allocated_rect = abd.rc;
83 MoveWindow(hwnd, abd.rc.left, abd.rc.top, abd.rc.right-abd.rc.left, abd.rc.bottom-abd.rc.top, TRUE);
86 static LRESULT CALLBACK testwindow_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
88 switch(msg)
90 case MSG_APPBAR:
92 switch(wparam)
94 case ABN_POSCHANGED:
95 testwindow_setpos(hwnd);
96 break;
98 return 0;
102 return DefWindowProc(hwnd, msg, wparam, lparam);
105 /* process any pending messages */
106 static void do_events(void)
108 MSG msg;
110 while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE))
112 TranslateMessage(&msg);
113 DispatchMessageW(&msg);
117 static void register_testwindow_class(void)
119 WNDCLASSEXW cls;
121 ZeroMemory(&cls, sizeof(cls));
122 cls.cbSize = sizeof(cls);
123 cls.style = 0;
124 cls.lpfnWndProc = testwindow_wndproc;
125 cls.hInstance = NULL;
126 cls.hCursor = LoadCursor(0, IDC_ARROW);
127 cls.hbrBackground = (HBRUSH) COLOR_WINDOW;
128 cls.lpszClassName = testwindow_class;
130 RegisterClassExW(&cls);
133 static void test_setpos(void)
135 APPBARDATA abd;
136 RECT rc;
137 int screen_width, screen_height, expected;
138 HWND window1, window2, window3;
139 struct testwindow_info window1_info, window2_info, window3_info;
140 BOOL ret;
142 screen_width = GetSystemMetrics(SM_CXSCREEN);
143 screen_height = GetSystemMetrics(SM_CYSCREEN);
145 /* create and register window1 */
146 window1 = CreateWindowExW(WS_EX_TOOLWINDOW|WS_EX_TOPMOST,
147 testwindow_class, testwindow_class, WS_POPUP|WS_VISIBLE, 0, 0, 0, 0,
148 NULL, NULL, NULL, NULL);
149 ok(window1 != NULL, "couldn't create window\n");
150 do_events();
151 abd.cbSize = sizeof(abd);
152 abd.hWnd = window1;
153 abd.uCallbackMessage = MSG_APPBAR;
154 ret = SHAppBarMessage(ABM_NEW, &abd);
155 ok(ret == TRUE, "SHAppBarMessage returned %i\n", ret);
157 /* ABM_NEW should return FALSE if the window is already registered */
158 ret = SHAppBarMessage(ABM_NEW, &abd);
159 ok(ret == FALSE, "SHAppBarMessage returned %i\n", ret);
160 do_events();
162 /* dock window1 to the bottom of the screen */
163 window1_info.edge = ABE_BOTTOM;
164 window1_info.desired_rect.left = 0;
165 window1_info.desired_rect.right = screen_width;
166 window1_info.desired_rect.top = screen_height - 15;
167 window1_info.desired_rect.bottom = screen_height;
168 SetWindowLongPtr(window1, GWLP_USERDATA, (LONG_PTR)&window1_info);
169 testwindow_setpos(window1);
170 do_events();
172 /* create and register window2 */
173 window2 = CreateWindowExW(WS_EX_TOOLWINDOW|WS_EX_TOPMOST,
174 testwindow_class, testwindow_class, WS_POPUP|WS_VISIBLE, 0, 0, 0, 0,
175 NULL, NULL, NULL, NULL);
176 ok(window2 != NULL, "couldn't create window\n");
177 abd.hWnd = window2;
178 ret = SHAppBarMessage(ABM_NEW, &abd);
179 ok(ret == TRUE, "SHAppBarMessage returned %i\n", ret);
181 /* dock window2 to the bottom of the screen */
182 window2_info.edge = ABE_BOTTOM;
183 window2_info.desired_rect.left = 0;
184 window2_info.desired_rect.right = screen_width;
185 window2_info.desired_rect.top = screen_height - 10;
186 window2_info.desired_rect.bottom = screen_height;
187 SetWindowLongPtr(window2, GWLP_USERDATA, (LONG_PTR)&window2_info);
188 testwindow_setpos(window2);
189 do_events();
191 /* the windows are adjusted to they don't overlap */
192 todo_wine ok(!IntersectRect(&rc, &window1_info.allocated_rect, &window2_info.allocated_rect),
193 "rectangles intersect (%i,%i,%i,%i)/(%i,%i,%i,%i)\n",
194 window1_info.allocated_rect.left, window1_info.allocated_rect.top, window1_info.allocated_rect.right, window1_info.allocated_rect.bottom,
195 window2_info.allocated_rect.left, window2_info.allocated_rect.top, window2_info.allocated_rect.right, window2_info.allocated_rect.bottom);
197 /* make window1 larger, forcing window2 to move out of its way */
198 window1_info.desired_rect.top = screen_height - 20;
199 testwindow_setpos(window1);
200 do_events();
201 todo_wine ok(!IntersectRect(&rc, &window1_info.allocated_rect, &window2_info.allocated_rect),
202 "rectangles intersect (%i,%i,%i,%i)/(%i,%i,%i,%i)\n",
203 window1_info.allocated_rect.left, window1_info.allocated_rect.top, window1_info.allocated_rect.right, window1_info.allocated_rect.bottom,
204 window2_info.allocated_rect.left, window2_info.allocated_rect.top, window2_info.allocated_rect.right, window2_info.allocated_rect.bottom);
206 /* create and register window3 */
207 window3 = CreateWindowExW(WS_EX_TOOLWINDOW|WS_EX_TOPMOST,
208 testwindow_class, testwindow_class, WS_POPUP|WS_VISIBLE, 0, 0, 0, 0,
209 NULL, NULL, NULL, NULL);
210 ok(window3 != NULL, "couldn't create window\n");
211 do_events();
213 abd.hWnd = window3;
214 ret = SHAppBarMessage(ABM_NEW, &abd);
215 ok(ret == TRUE, "SHAppBarMessage returned %i\n", ret);
217 /* dock window3 to the bottom of the screen */
218 window3_info.edge = ABE_BOTTOM;
219 window3_info.desired_rect.left = 0;
220 window3_info.desired_rect.right = screen_width;
221 window3_info.desired_rect.top = screen_height - 10;
222 window3_info.desired_rect.bottom = screen_height;
223 SetWindowLongPtr(window3, GWLP_USERDATA, (LONG_PTR)&window3_info);
224 testwindow_setpos(window3);
225 do_events();
227 todo_wine ok(!IntersectRect(&rc, &window1_info.allocated_rect, &window2_info.allocated_rect),
228 "rectangles intersect (%i,%i,%i,%i)/(%i,%i,%i,%i)\n",
229 window1_info.allocated_rect.left, window1_info.allocated_rect.top, window1_info.allocated_rect.right, window1_info.allocated_rect.bottom,
230 window2_info.allocated_rect.left, window2_info.allocated_rect.top, window2_info.allocated_rect.right, window2_info.allocated_rect.bottom);
231 todo_wine ok(!IntersectRect(&rc, &window1_info.allocated_rect, &window3_info.allocated_rect),
232 "rectangles intersect (%i,%i,%i,%i)/(%i,%i,%i,%i)\n",
233 window1_info.allocated_rect.left, window1_info.allocated_rect.top, window1_info.allocated_rect.right, window1_info.allocated_rect.bottom,
234 window3_info.allocated_rect.left, window3_info.allocated_rect.top, window3_info.allocated_rect.right, window3_info.allocated_rect.bottom);
235 todo_wine ok(!IntersectRect(&rc, &window3_info.allocated_rect, &window2_info.allocated_rect),
236 "rectangles intersect (%i,%i,%i,%i)/(%i,%i,%i,%i)\n",
237 window3_info.allocated_rect.left, window3_info.allocated_rect.top, window3_info.allocated_rect.right, window3_info.allocated_rect.bottom,
238 window2_info.allocated_rect.left, window2_info.allocated_rect.top, window2_info.allocated_rect.right, window2_info.allocated_rect.bottom);
240 /* move window3 to the right side of the screen */
241 window3_info.edge = ABE_RIGHT;
242 window3_info.desired_rect.left = screen_width - 15;
243 window3_info.desired_rect.right = screen_width;
244 window3_info.desired_rect.top = 0;
245 window3_info.desired_rect.bottom = screen_height;
246 testwindow_setpos(window3);
247 do_events();
249 todo_wine ok(!IntersectRect(&rc, &window1_info.allocated_rect, &window2_info.allocated_rect),
250 "rectangles intersect (%i,%i,%i,%i)/(%i,%i,%i,%i)\n",
251 window1_info.allocated_rect.left, window1_info.allocated_rect.top, window1_info.allocated_rect.right, window1_info.allocated_rect.bottom,
252 window2_info.allocated_rect.left, window2_info.allocated_rect.top, window2_info.allocated_rect.right, window2_info.allocated_rect.bottom);
253 todo_wine ok(!IntersectRect(&rc, &window1_info.allocated_rect, &window3_info.allocated_rect),
254 "rectangles intersect (%i,%i,%i,%i)/(%i,%i,%i,%i)\n",
255 window1_info.allocated_rect.left, window1_info.allocated_rect.top, window1_info.allocated_rect.right, window1_info.allocated_rect.bottom,
256 window3_info.allocated_rect.left, window3_info.allocated_rect.top, window3_info.allocated_rect.right, window3_info.allocated_rect.bottom);
257 todo_wine ok(!IntersectRect(&rc, &window3_info.allocated_rect, &window2_info.allocated_rect),
258 "rectangles intersect (%i,%i,%i,%i)/(%i,%i,%i,%i)\n",
259 window3_info.allocated_rect.left, window3_info.allocated_rect.top, window3_info.allocated_rect.right, window3_info.allocated_rect.bottom,
260 window2_info.allocated_rect.left, window2_info.allocated_rect.top, window2_info.allocated_rect.right, window2_info.allocated_rect.bottom);
262 /* move window2 to the top of the screen */
263 window2_info.edge = ABE_TOP;
264 window2_info.desired_rect.left = 0;
265 window2_info.desired_rect.right = screen_width;
266 window2_info.desired_rect.top = 0;
267 window2_info.desired_rect.bottom = 15;
268 testwindow_setpos(window2);
269 do_events();
271 ok(!IntersectRect(&rc, &window1_info.allocated_rect, &window2_info.allocated_rect),
272 "rectangles intersect (%i,%i,%i,%i)/(%i,%i,%i,%i)\n",
273 window1_info.allocated_rect.left, window1_info.allocated_rect.top, window1_info.allocated_rect.right, window1_info.allocated_rect.bottom,
274 window2_info.allocated_rect.left, window2_info.allocated_rect.top, window2_info.allocated_rect.right, window2_info.allocated_rect.bottom);
275 todo_wine ok(!IntersectRect(&rc, &window1_info.allocated_rect, &window3_info.allocated_rect),
276 "rectangles intersect (%i,%i,%i,%i)/(%i,%i,%i,%i)\n",
277 window1_info.allocated_rect.left, window1_info.allocated_rect.top, window1_info.allocated_rect.right, window1_info.allocated_rect.bottom,
278 window3_info.allocated_rect.left, window3_info.allocated_rect.top, window3_info.allocated_rect.right, window3_info.allocated_rect.bottom);
279 todo_wine ok(!IntersectRect(&rc, &window3_info.allocated_rect, &window2_info.allocated_rect),
280 "rectangles intersect (%i,%i,%i,%i)/(%i,%i,%i,%i)\n",
281 window3_info.allocated_rect.left, window3_info.allocated_rect.top, window3_info.allocated_rect.right, window3_info.allocated_rect.bottom,
282 window2_info.allocated_rect.left, window2_info.allocated_rect.top, window2_info.allocated_rect.right, window2_info.allocated_rect.bottom);
284 /* move window2 back to the bottom of the screen */
285 window2_info.edge = ABE_BOTTOM;
286 window2_info.desired_rect.left = 0;
287 window2_info.desired_rect.right = screen_width;
288 window2_info.desired_rect.top = screen_height - 10;
289 window2_info.desired_rect.bottom = screen_height;
290 testwindow_setpos(window2);
291 do_events();
293 todo_wine ok(!IntersectRect(&rc, &window1_info.allocated_rect, &window2_info.allocated_rect),
294 "rectangles intersect (%i,%i,%i,%i)/(%i,%i,%i,%i)\n",
295 window1_info.allocated_rect.left, window1_info.allocated_rect.top, window1_info.allocated_rect.right, window1_info.allocated_rect.bottom,
296 window2_info.allocated_rect.left, window2_info.allocated_rect.top, window2_info.allocated_rect.right, window2_info.allocated_rect.bottom);
297 todo_wine ok(!IntersectRect(&rc, &window1_info.allocated_rect, &window3_info.allocated_rect),
298 "rectangles intersect (%i,%i,%i,%i)/(%i,%i,%i,%i)\n",
299 window1_info.allocated_rect.left, window1_info.allocated_rect.top, window1_info.allocated_rect.right, window1_info.allocated_rect.bottom,
300 window3_info.allocated_rect.left, window3_info.allocated_rect.top, window3_info.allocated_rect.right, window3_info.allocated_rect.bottom);
301 todo_wine ok(!IntersectRect(&rc, &window3_info.allocated_rect, &window2_info.allocated_rect),
302 "rectangles intersect (%i,%i,%i,%i)/(%i,%i,%i,%i)\n",
303 window3_info.allocated_rect.left, window3_info.allocated_rect.top, window3_info.allocated_rect.right, window3_info.allocated_rect.bottom,
304 window2_info.allocated_rect.left, window2_info.allocated_rect.top, window2_info.allocated_rect.right, window2_info.allocated_rect.bottom);
306 /* removing window1 will cause window2 to move down into its space */
307 expected = max(window1_info.allocated_rect.bottom, window2_info.allocated_rect.bottom);
309 SetWindowLongPtr(window1, GWLP_USERDATA, 0); /* don't expect further ABN_POSCHANGED notifications */
310 abd.hWnd = window1;
311 ret = SHAppBarMessage(ABM_REMOVE, &abd);
312 ok(ret == TRUE, "SHAppBarMessage returned %i\n", ret);
313 do_events();
314 DestroyWindow(window1);
316 ok(window2_info.allocated_rect.bottom = expected, "window2's bottom is %i, expected %i\n", window2_info.allocated_rect.bottom, expected);
318 todo_wine ok(!IntersectRect(&rc, &window3_info.allocated_rect, &window2_info.allocated_rect),
319 "rectangles intersect (%i,%i,%i,%i)/(%i,%i,%i,%i)\n",
320 window3_info.allocated_rect.left, window3_info.allocated_rect.top, window3_info.allocated_rect.right, window3_info.allocated_rect.bottom,
321 window2_info.allocated_rect.left, window2_info.allocated_rect.top, window2_info.allocated_rect.right, window2_info.allocated_rect.bottom);
323 /* remove the other windows */
324 SetWindowLongPtr(window2, GWLP_USERDATA, 0);
325 abd.hWnd = window2;
326 ret = SHAppBarMessage(ABM_REMOVE, &abd);
327 ok(ret == TRUE, "SHAppBarMessage returned %i\n", ret);
328 do_events();
329 DestroyWindow(window2);
331 SetWindowLongPtr(window3, GWLP_USERDATA, 0);
332 abd.hWnd = window3;
333 ret = SHAppBarMessage(ABM_REMOVE, &abd);
334 ok(ret == TRUE, "SHAppBarMessage returned %i\n", ret);
335 do_events();
336 DestroyWindow(window3);
339 static void test_appbarget(void)
341 APPBARDATA abd;
342 HWND hwnd, foregnd;
343 UINT_PTR ret;
345 memset(&abd, 0xcc, sizeof(abd));
346 abd.cbSize = sizeof(abd);
347 abd.uEdge = ABE_BOTTOM;
349 hwnd = (HWND)SHAppBarMessage(ABM_GETAUTOHIDEBAR, &abd);
350 ok(hwnd == NULL || IsWindow(hwnd), "ret %p which is not a window\n", hwnd);
351 ok(abd.hWnd == (HWND)0xcccccccc, "hWnd overwritten\n");
353 if (!pMonitorFromWindow)
355 skip("MonitorFromWindow is not available\n");
357 else
359 /* Presumably one can pass a hwnd with ABM_GETAUTOHIDEBAR to specify a monitor.
360 Pass the foreground window and check */
361 foregnd = GetForegroundWindow();
362 if(foregnd)
364 abd.hWnd = foregnd;
365 hwnd = (HWND)SHAppBarMessage(ABM_GETAUTOHIDEBAR, &abd);
366 ok(hwnd == NULL || IsWindow(hwnd), "ret %p which is not a window\n", hwnd);
367 ok(abd.hWnd == foregnd, "hWnd overwritten\n");
368 if(hwnd)
370 HMONITOR appbar_mon, foregnd_mon;
371 appbar_mon = pMonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
372 foregnd_mon = pMonitorFromWindow(foregnd, MONITOR_DEFAULTTONEAREST);
373 ok(appbar_mon == foregnd_mon, "Windows on different monitors\n");
378 memset(&abd, 0xcc, sizeof(abd));
379 abd.cbSize = sizeof(abd);
380 ret = SHAppBarMessage(ABM_GETTASKBARPOS, &abd);
381 if(ret)
383 ok(abd.hWnd == (HWND)0xcccccccc, "hWnd overwritten\n");
384 todo_wine
386 ok(abd.uEdge <= ABE_BOTTOM, "uEdge not returned\n");
387 ok(abd.rc.left != 0xcccccccc, "rc not updated\n");
391 return;
394 START_TEST(appbar)
396 HMODULE huser32;
398 huser32 = GetModuleHandleA("user32.dll");
399 pMonitorFromWindow = (void*)GetProcAddress(huser32, "MonitorFromWindow");
401 register_testwindow_class();
403 test_setpos();
404 test_appbarget();