mshtml: Add tests for get_scrollLeft.
[wine] / dlls / shell32 / tests / appbar.c
1 /* Unit tests for appbars
2  *
3  * Copyright 2008 Vincent Povirk for CodeWeavers
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 <assert.h>
21 #include <stdarg.h>
22
23 #include <windows.h>
24
25 #include "wine/test.h"
26
27 #define MSG_APPBAR WM_APP
28
29 static const WCHAR testwindow_class[] = {'t','e','s','t','w','i','n','d','o','w',0};
30
31 static HMONITOR (WINAPI *pMonitorFromWindow)(HWND, DWORD);
32
33 struct testwindow_info
34 {
35     RECT desired_rect;
36     UINT edge;
37     RECT allocated_rect;
38 };
39
40 static void testwindow_setpos(HWND hwnd)
41 {
42     struct testwindow_info* info = (struct testwindow_info*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
43     APPBARDATA abd;
44     BOOL ret;
45
46     ok(info != NULL, "got unexpected ABN_POSCHANGED notification\n");
47
48     if (!info)
49     {
50         return;
51     }
52
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)
60     {
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;
77     }
78
79     ret = SHAppBarMessage(ABM_SETPOS, &abd);
80     ok(ret == TRUE, "SHAppBarMessage returned %i\n", ret);
81
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);
84 }
85
86 static LRESULT CALLBACK testwindow_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
87 {
88     switch(msg)
89     {
90         case MSG_APPBAR:
91         {
92             switch(wparam)
93             {
94                 case ABN_POSCHANGED:
95                     testwindow_setpos(hwnd);
96                     break;
97             }
98             return 0;
99         }
100     }
101
102     return DefWindowProc(hwnd, msg, wparam, lparam);
103 }
104
105 /* process any pending messages */
106 static void do_events(void)
107 {
108     MSG msg;
109
110     while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE))
111     {
112         TranslateMessage(&msg);
113         DispatchMessageW(&msg);
114     }
115 }
116
117 static void register_testwindow_class(void)
118 {
119     WNDCLASSEXW cls;
120
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;
129
130     RegisterClassExW(&cls);
131 }
132
133 static void test_setpos(void)
134 {
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;
141
142     screen_width = GetSystemMetrics(SM_CXSCREEN);
143     screen_height = GetSystemMetrics(SM_CYSCREEN);
144
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);
156
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();
161
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();
171
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);
180
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();
190
191     /* the windows are adjusted to they don't overlap */
192     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);
196
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     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);
205
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();
212
213     abd.hWnd = window3;
214     ret = SHAppBarMessage(ABM_NEW, &abd);
215     ok(ret == TRUE, "SHAppBarMessage returned %i\n", ret);
216
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();
226
227     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     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     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);
239
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();
248
249     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     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     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);
261
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();
270
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     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     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);
283
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();
292
293     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     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     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);
305
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);
308
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);
315
316     ok(window2_info.allocated_rect.bottom = expected, "window2's bottom is %i, expected %i\n", window2_info.allocated_rect.bottom, expected);
317
318     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);
322
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);
330
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);
337 }
338
339 static void test_appbarget(void)
340 {
341     APPBARDATA abd;
342     HWND hwnd, foregnd;
343     UINT_PTR ret;
344
345     memset(&abd, 0xcc, sizeof(abd));
346     abd.cbSize = sizeof(abd);
347     abd.uEdge = ABE_BOTTOM;
348
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");
352
353     if (!pMonitorFromWindow)
354     {
355         skip("MonitorFromWindow is not available\n");
356     }
357     else
358     {
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)
363         {
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)
369             {
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");
374             }
375         }
376     }
377
378     memset(&abd, 0xcc, sizeof(abd));
379     abd.cbSize = sizeof(abd);
380     ret = SHAppBarMessage(ABM_GETTASKBARPOS, &abd);
381     if(ret)
382     {
383         ok(abd.hWnd == (HWND)0xcccccccc, "hWnd overwritten\n");
384 todo_wine
385 {
386         ok(abd.uEdge <= ABE_BOTTOM, "uEdge not returned\n");
387         ok(abd.rc.left != 0xcccccccc, "rc not updated\n");
388 }
389     }
390
391     return;
392 }
393
394 START_TEST(appbar)
395 {
396     HMODULE huser32;
397
398     huser32 = GetModuleHandleA("user32.dll");
399     pMonitorFromWindow = (void*)GetProcAddress(huser32, "MonitorFromWindow");
400
401     register_testwindow_class();
402
403     test_setpos();
404     test_appbarget();
405 }