2 * Unit tests for the pager control
4 * Copyright 2012 Alexandre Julliard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #define NUM_MSG_SEQUENCES 1
24 #define PAGER_SEQ_INDEX 0
26 static HWND parent_wnd
, child1_wnd
, child2_wnd
;
31 static BOOL (WINAPI
*pSetWindowSubclass
)(HWND
, SUBCLASSPROC
, UINT_PTR
, DWORD_PTR
);
33 static struct msg_sequence
*sequences
[NUM_MSG_SEQUENCES
];
35 static const struct message set_child_seq
[] = {
36 { PGM_SETCHILD
, sent
},
37 { WM_WINDOWPOSCHANGING
, sent
},
38 { WM_NCCALCSIZE
, sent
|wparam
, TRUE
},
39 { WM_NOTIFY
, sent
|id
|parent
, 0, 0, PGN_CALCSIZE
},
40 { WM_WINDOWPOSCHANGED
, sent
},
41 { WM_WINDOWPOSCHANGING
, sent
|id
, 0, 0, CHILD1_ID
},
42 { WM_NCCALCSIZE
, sent
|wparam
|id
|optional
, TRUE
, 0, CHILD1_ID
},
43 { WM_CHILDACTIVATE
, sent
|id
, 0, 0, CHILD1_ID
},
44 { WM_WINDOWPOSCHANGED
, sent
|id
, 0, 0, CHILD1_ID
},
45 { WM_SIZE
, sent
|id
|defwinproc
|optional
, 0, 0, CHILD1_ID
},
49 /* This differs from the above message list only in the child window that is
50 * expected to receive the child messages. No message is sent to the old child.
51 * Also child 2 is hidden while child 1 is visible. The pager does not make the
52 * hidden child visible. */
53 static const struct message switch_child_seq
[] = {
54 { PGM_SETCHILD
, sent
},
55 { WM_WINDOWPOSCHANGING
, sent
},
56 { WM_NCCALCSIZE
, sent
|wparam
, TRUE
},
57 { WM_NOTIFY
, sent
|id
|parent
, 0, 0, PGN_CALCSIZE
},
58 { WM_WINDOWPOSCHANGED
, sent
},
59 { WM_WINDOWPOSCHANGING
, sent
|id
, 0, 0, CHILD2_ID
},
60 { WM_NCCALCSIZE
, sent
|wparam
|id
, TRUE
, 0, CHILD2_ID
},
61 { WM_CHILDACTIVATE
, sent
|id
, 0, 0, CHILD2_ID
},
62 { WM_WINDOWPOSCHANGED
, sent
|id
, 0, 0, CHILD2_ID
},
63 { WM_SIZE
, sent
|id
|defwinproc
, 0, 0, CHILD2_ID
},
67 static const struct message set_pos_seq
[] = {
69 { WM_WINDOWPOSCHANGING
, sent
},
70 { WM_NCCALCSIZE
, sent
|wparam
, TRUE
},
71 { WM_NOTIFY
, sent
|id
|parent
, 0, 0, PGN_CALCSIZE
},
72 { WM_WINDOWPOSCHANGED
, sent
},
73 { WM_MOVE
, sent
|optional
},
74 /* The WM_SIZE handler sends WM_WINDOWPOSCHANGING, WM_CHILDACTIVATE
75 * and WM_WINDOWPOSCHANGED (which sends WM_MOVE) to the child.
76 * Another WM_WINDOWPOSCHANGING is sent afterwards.
78 * The 2nd WM_WINDOWPOSCHANGING is unconditional, but the comparison
79 * function is too simple to roll back an accepted message, so we have
80 * to mark the 2nd message optional. */
81 { WM_SIZE
, sent
|optional
},
82 { WM_WINDOWPOSCHANGING
, sent
|id
, 0, 0, CHILD1_ID
}, /* Actually optional. */
83 { WM_CHILDACTIVATE
, sent
|id
, 0, 0, CHILD1_ID
}, /* Actually optional. */
84 { WM_WINDOWPOSCHANGED
, sent
|id
|optional
, TRUE
, 0, CHILD1_ID
},
85 { WM_MOVE
, sent
|id
|optional
|defwinproc
, 0, 0, CHILD1_ID
},
86 { WM_WINDOWPOSCHANGING
, sent
|id
|optional
, 0, 0, CHILD1_ID
}, /* Actually not optional. */
87 { WM_CHILDACTIVATE
, sent
|id
|optional
, 0, 0, CHILD1_ID
}, /* Actually not optional. */
91 static const struct message set_pos_empty_seq
[] = {
96 static LRESULT WINAPI
parent_wnd_proc(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
98 static LONG defwndproc_counter
= 0;
102 /* log system messages, except for painting */
103 if (message
< WM_USER
&&
104 message
!= WM_PAINT
&&
105 message
!= WM_ERASEBKGND
&&
106 message
!= WM_NCPAINT
&&
107 message
!= WM_NCHITTEST
&&
108 message
!= WM_GETTEXT
&&
109 message
!= WM_GETICON
&&
110 message
!= WM_DEVICECHANGE
)
112 msg
.message
= message
;
113 msg
.flags
= sent
|wparam
|lparam
|parent
;
114 if (defwndproc_counter
) msg
.flags
|= defwinproc
;
117 if (message
== WM_NOTIFY
&& lParam
) msg
.id
= ((NMHDR
*)lParam
)->code
;
118 add_message(sequences
, PAGER_SEQ_INDEX
, &msg
);
121 if (message
== WM_NOTIFY
)
123 NMHDR
*nmhdr
= (NMHDR
*)lParam
;
129 NMPGCALCSIZE
*nmpgcs
= (NMPGCALCSIZE
*)lParam
;
130 DWORD style
= GetWindowLongA(nmpgcs
->hdr
.hwndFrom
, GWL_STYLE
);
132 if (style
& PGS_HORZ
)
133 ok(nmpgcs
->dwFlag
== PGF_CALCWIDTH
, "Unexpected flags %#x.\n", nmpgcs
->dwFlag
);
135 ok(nmpgcs
->dwFlag
== PGF_CALCHEIGHT
, "Unexpected flags %#x.\n", nmpgcs
->dwFlag
);
143 defwndproc_counter
++;
144 ret
= DefWindowProcA(hwnd
, message
, wParam
, lParam
);
145 defwndproc_counter
--;
150 static BOOL
register_parent_wnd_class(void)
155 cls
.lpfnWndProc
= parent_wnd_proc
;
158 cls
.hInstance
= GetModuleHandleA(NULL
);
160 cls
.hCursor
= LoadCursorA(0, (LPCSTR
)IDC_ARROW
);
161 cls
.hbrBackground
= GetStockObject(WHITE_BRUSH
);
162 cls
.lpszMenuName
= NULL
;
163 cls
.lpszClassName
= "Pager test parent class";
164 return RegisterClassA(&cls
);
167 static HWND
create_parent_window(void)
169 if (!register_parent_wnd_class())
172 return CreateWindowA("Pager test parent class", "Pager test parent window",
173 WS_OVERLAPPED
| WS_VISIBLE
,
174 0, 0, 200, 200, 0, NULL
, GetModuleHandleA(NULL
), NULL
);
177 static LRESULT WINAPI
pager_subclass_proc(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
179 WNDPROC oldproc
= (WNDPROC
)GetWindowLongPtrA(hwnd
, GWLP_USERDATA
);
180 struct message msg
= { 0 };
182 msg
.message
= message
;
183 msg
.flags
= sent
|wparam
|lparam
;
186 add_message(sequences
, PAGER_SEQ_INDEX
, &msg
);
187 return CallWindowProcA(oldproc
, hwnd
, message
, wParam
, lParam
);
190 static HWND
create_pager_control( DWORD style
)
196 GetClientRect( parent_wnd
, &rect
);
197 hwnd
= CreateWindowA( WC_PAGESCROLLERA
, "pager", WS_CHILD
| WS_BORDER
| WS_VISIBLE
| style
,
198 0, 0, 100, 100, parent_wnd
, 0, GetModuleHandleA(0), 0 );
199 oldproc
= (WNDPROC
)SetWindowLongPtrA(hwnd
, GWLP_WNDPROC
, (LONG_PTR
)pager_subclass_proc
);
200 SetWindowLongPtrA(hwnd
, GWLP_USERDATA
, (LONG_PTR
)oldproc
);
204 static LRESULT WINAPI
child_proc(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
206 static LONG defwndproc_counter
;
207 struct message msg
= { 0 };
210 msg
.message
= message
;
211 msg
.flags
= sent
| wparam
| lparam
;
212 if (defwndproc_counter
)
213 msg
.flags
|= defwinproc
;
217 if (hwnd
== child1_wnd
)
219 else if (hwnd
== child2_wnd
)
224 add_message(sequences
, PAGER_SEQ_INDEX
, &msg
);
226 defwndproc_counter
++;
227 ret
= DefWindowProcA(hwnd
, message
, wParam
, lParam
);
228 defwndproc_counter
--;
233 static BOOL
register_child_wnd_class(void)
238 cls
.lpfnWndProc
= child_proc
;
241 cls
.hInstance
= GetModuleHandleA(NULL
);
243 cls
.hCursor
= LoadCursorA(0, (LPCSTR
)IDC_ARROW
);
244 cls
.hbrBackground
= GetStockObject(WHITE_BRUSH
);
245 cls
.lpszMenuName
= NULL
;
246 cls
.lpszClassName
= "Pager test child class";
247 return RegisterClassA(&cls
);
250 static void test_pager(void)
255 pager
= create_pager_control( PGS_HORZ
);
258 win_skip( "Pager control not supported\n" );
262 register_child_wnd_class();
264 child1_wnd
= CreateWindowA( "Pager test child class", "button", WS_CHILD
| WS_BORDER
| WS_VISIBLE
, 0, 0, 300, 300,
265 pager
, 0, GetModuleHandleA(0), 0 );
266 child2_wnd
= CreateWindowA("Pager test child class", "button", WS_CHILD
| WS_BORDER
, 0, 0, 300, 300,
267 pager
, 0, GetModuleHandleA(0), 0);
269 flush_sequences( sequences
, NUM_MSG_SEQUENCES
);
270 SendMessageA( pager
, PGM_SETCHILD
, 0, (LPARAM
)child1_wnd
);
271 ok_sequence(sequences
, PAGER_SEQ_INDEX
, set_child_seq
, "set child", FALSE
);
272 GetWindowRect( pager
, &rect
);
273 ok( rect
.right
- rect
.left
== 100 && rect
.bottom
- rect
.top
== 100,
274 "pager resized %dx%d\n", rect
.right
- rect
.left
, rect
.bottom
- rect
.top
);
276 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
277 SendMessageA(pager
, PGM_SETCHILD
, 0, (LPARAM
)child2_wnd
);
278 ok_sequence(sequences
, PAGER_SEQ_INDEX
, switch_child_seq
, "switch to invisible child", FALSE
);
279 GetWindowRect(pager
, &rect
);
280 ok(rect
.right
- rect
.left
== 100 && rect
.bottom
- rect
.top
== 100,
281 "pager resized %dx%d\n", rect
.right
- rect
.left
, rect
.bottom
- rect
.top
);
282 ok(!IsWindowVisible(child2_wnd
), "Child window 2 is visible\n");
284 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
285 SendMessageA(pager
, PGM_SETCHILD
, 0, (LPARAM
)child1_wnd
);
286 ok_sequence(sequences
, PAGER_SEQ_INDEX
, set_child_seq
, "switch to visible child", FALSE
);
287 GetWindowRect(pager
, &rect
);
288 ok(rect
.right
- rect
.left
== 100 && rect
.bottom
- rect
.top
== 100,
289 "pager resized %dx%d\n", rect
.right
- rect
.left
, rect
.bottom
- rect
.top
);
291 flush_sequences( sequences
, NUM_MSG_SEQUENCES
);
292 SendMessageA( pager
, PGM_SETPOS
, 0, 10 );
293 ok_sequence(sequences
, PAGER_SEQ_INDEX
, set_pos_seq
, "set pos", TRUE
);
294 GetWindowRect( pager
, &rect
);
295 ok( rect
.right
- rect
.left
== 100 && rect
.bottom
- rect
.top
== 100,
296 "pager resized %dx%d\n", rect
.right
- rect
.left
, rect
.bottom
- rect
.top
);
298 flush_sequences( sequences
, NUM_MSG_SEQUENCES
);
299 SendMessageA( pager
, PGM_SETPOS
, 0, 10 );
300 ok_sequence(sequences
, PAGER_SEQ_INDEX
, set_pos_empty_seq
, "set pos empty", TRUE
);
302 flush_sequences( sequences
, NUM_MSG_SEQUENCES
);
303 SendMessageA( pager
, PGM_SETPOS
, 0, 9 );
304 ok_sequence(sequences
, PAGER_SEQ_INDEX
, set_pos_seq
, "set pos", TRUE
);
306 DestroyWindow( pager
);
308 /* Test if resizing works */
309 pager
= create_pager_control( CCS_NORESIZE
);
310 ok(pager
!= NULL
, "failed to create pager control\n");
312 GetWindowRect( pager
, &rect
);
313 MoveWindow( pager
, 0, 0, 200, 100, TRUE
);
314 GetWindowRect( pager
, &rect2
);
315 ok(rect2
.right
- rect2
.left
> rect
.right
- rect
.left
, "expected pager window to resize, %s\n",
316 wine_dbgstr_rect( &rect2
));
318 DestroyWindow( pager
);
320 pager
= create_pager_control( CCS_NORESIZE
| PGS_HORZ
);
321 ok(pager
!= NULL
, "failed to create pager control\n");
323 GetWindowRect( pager
, &rect
);
324 MoveWindow( pager
, 0, 0, 100, 200, TRUE
);
325 GetWindowRect( pager
, &rect2
);
326 ok(rect2
.bottom
- rect2
.top
> rect
.bottom
- rect
.top
, "expected pager window to resize, %s\n",
327 wine_dbgstr_rect( &rect2
));
329 DestroyWindow( pager
);
334 HMODULE mod
= GetModuleHandleA("comctl32.dll");
336 pSetWindowSubclass
= (void*)GetProcAddress(mod
, (LPSTR
)410);
338 InitCommonControls();
339 init_msg_sequences(sequences
, NUM_MSG_SEQUENCES
);
341 parent_wnd
= create_parent_window();
342 ok(parent_wnd
!= NULL
, "Failed to create parent window!\n");