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
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
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
);
54 ok(info
!= NULL
, "got unexpected ABN_POSCHANGED notification\n");
56 if (!info
|| !info
->registered
)
61 abd
.cbSize
= sizeof(abd
);
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
);
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
);
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
);
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
);
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
);
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
)
103 testwindow_setpos(hwnd
);
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
)
120 timerid
= SetTimer(0, 0, 3000, NULL
);
124 while (PeekMessageA(&msg
, NULL
, 0, 0, PM_REMOVE
))
126 if (msg
.hwnd
== 0 && msg
.message
== WM_TIMER
&& msg
.wParam
== timerid
)
128 TranslateMessage(&msg
);
129 DispatchMessageA(&msg
);
131 if (timedout
|| test())
136 KillTimer(0, timerid
);
139 /* process any pending messages */
140 static void do_events(void)
144 while (PeekMessageA(&msg
, NULL
, 0, 0, PM_REMOVE
))
146 TranslateMessage(&msg
);
147 DispatchMessageA(&msg
);
151 static BOOL
no_appbars_intersect(void)
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
))
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)
177 ZeroMemory(&cls
, sizeof(cls
));
178 cls
.cbSize
= sizeof(cls
);
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)
199 int screen_width
, screen_height
;
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");
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
);
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
);
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");
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)
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");
378 /* Presumably one can pass a hwnd with ABM_GETAUTOHIDEBAR to specify a monitor.
379 Pass the foreground window and check */
380 foregnd
= GetForegroundWindow();
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");
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
);
402 ok(abd
.hWnd
== (HWND
)0xcccccccc, "hWnd overwritten\n");
405 ok(abd
.uEdge
<= ABE_BOTTOM
, "uEdge not returned\n");
406 ok(abd
.rc
.left
!= 0xcccccccc, "rc not updated\n");
417 huser32
= GetModuleHandleA("user32.dll");
418 pMonitorFromWindow
= (void*)GetProcAddress(huser32
, "MonitorFromWindow");
420 register_testwindow_class();