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 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
40 static void testwindow_setpos(HWND hwnd
)
42 struct testwindow_info
* info
= (struct testwindow_info
*)GetWindowLongPtr(hwnd
, GWLP_USERDATA
);
46 ok(info
!= NULL
, "got unexpected ABN_POSCHANGED notification\n");
53 abd
.cbSize
= sizeof(abd
);
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
);
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
);
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
);
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
);
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
);
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
)
95 testwindow_setpos(hwnd
);
102 return DefWindowProc(hwnd
, msg
, wparam
, lparam
);
105 /* process any pending messages */
106 static void do_events(void)
110 while (PeekMessageW(&msg
, NULL
, 0, 0, PM_REMOVE
))
112 TranslateMessage(&msg
);
113 DispatchMessageW(&msg
);
117 static void register_testwindow_class(void)
121 ZeroMemory(&cls
, sizeof(cls
));
122 cls
.cbSize
= sizeof(cls
);
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)
137 int screen_width
, screen_height
, expected
;
138 HWND window1
, window2
, window3
;
139 struct testwindow_info window1_info
, window2_info
, window3_info
;
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");
151 abd
.cbSize
= sizeof(abd
);
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
);
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
);
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");
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
);
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
);
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");
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
);
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
);
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
);
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
);
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 */
311 ret
= SHAppBarMessage(ABM_REMOVE
, &abd
);
312 ok(ret
== TRUE
, "SHAppBarMessage returned %i\n", ret
);
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);
326 ret
= SHAppBarMessage(ABM_REMOVE
, &abd
);
327 ok(ret
== TRUE
, "SHAppBarMessage returned %i\n", ret
);
329 DestroyWindow(window2
);
331 SetWindowLongPtr(window3
, GWLP_USERDATA
, 0);
333 ret
= SHAppBarMessage(ABM_REMOVE
, &abd
);
334 ok(ret
== TRUE
, "SHAppBarMessage returned %i\n", ret
);
336 DestroyWindow(window3
);
339 static void test_appbarget(void)
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");
359 /* Presumably one can pass a hwnd with ABM_GETAUTOHIDEBAR to specify a monitor.
360 Pass the foreground window and check */
361 foregnd
= GetForegroundWindow();
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");
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
);
383 ok(abd
.hWnd
== (HWND
)0xcccccccc, "hWnd overwritten\n");
386 ok(abd
.uEdge
<= ABE_BOTTOM
, "uEdge not returned\n");
387 ok(abd
.rc
.left
!= 0xcccccccc, "rc not updated\n");
398 huser32
= GetModuleHandleA("user32.dll");
399 pMonitorFromWindow
= (void*)GetProcAddress(huser32
, "MonitorFromWindow");
401 register_testwindow_class();