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
21 #include <wine/test.h>
23 //#include <windows.h>
30 #define NUM_MSG_SEQUENCES 1
31 #define PAGER_SEQ_INDEX 0
33 static HWND parent_wnd
, child1_wnd
, child2_wnd
;
38 static BOOL (WINAPI
*pSetWindowSubclass
)(HWND
, SUBCLASSPROC
, UINT_PTR
, DWORD_PTR
);
40 static struct msg_sequence
*sequences
[NUM_MSG_SEQUENCES
];
42 static const struct message set_child_seq
[] = {
43 { PGM_SETCHILD
, sent
},
44 { WM_WINDOWPOSCHANGING
, sent
},
45 { WM_NCCALCSIZE
, sent
|wparam
, TRUE
},
46 { WM_NOTIFY
, sent
|id
|parent
, 0, 0, PGN_CALCSIZE
},
47 { WM_WINDOWPOSCHANGED
, sent
},
48 { WM_WINDOWPOSCHANGING
, sent
|id
, 0, 0, CHILD1_ID
},
49 { WM_NCCALCSIZE
, sent
|wparam
|id
|optional
, TRUE
, 0, CHILD1_ID
},
50 { WM_CHILDACTIVATE
, sent
|id
, 0, 0, CHILD1_ID
},
51 { WM_WINDOWPOSCHANGED
, sent
|id
, 0, 0, CHILD1_ID
},
52 { WM_SIZE
, sent
|id
|defwinproc
|optional
, 0, 0, CHILD1_ID
},
56 /* This differs from the above message list only in the child window that is
57 * expected to receive the child messages. No message is sent to the old child.
58 * Also child 2 is hidden while child 1 is visible. The pager does not make the
59 * hidden child visible. */
60 static const struct message switch_child_seq
[] = {
61 { PGM_SETCHILD
, sent
},
62 { WM_WINDOWPOSCHANGING
, sent
},
63 { WM_NCCALCSIZE
, sent
|wparam
, TRUE
},
64 { WM_NOTIFY
, sent
|id
|parent
, 0, 0, PGN_CALCSIZE
},
65 { WM_WINDOWPOSCHANGED
, sent
},
66 { WM_WINDOWPOSCHANGING
, sent
|id
, 0, 0, CHILD2_ID
},
67 { WM_NCCALCSIZE
, sent
|wparam
|id
, TRUE
, 0, CHILD2_ID
},
68 { WM_CHILDACTIVATE
, sent
|id
, 0, 0, CHILD2_ID
},
69 { WM_WINDOWPOSCHANGED
, sent
|id
, 0, 0, CHILD2_ID
},
70 { WM_SIZE
, sent
|id
|defwinproc
, 0, 0, CHILD2_ID
},
74 static const struct message set_pos_seq
[] = {
76 { WM_WINDOWPOSCHANGING
, sent
},
77 { WM_NCCALCSIZE
, sent
|wparam
, TRUE
},
78 { WM_NOTIFY
, sent
|id
|parent
, 0, 0, PGN_CALCSIZE
},
79 { WM_WINDOWPOSCHANGED
, sent
},
80 { WM_MOVE
, sent
|optional
},
81 /* The WM_SIZE handler sends WM_WINDOWPOSCHANGING, WM_CHILDACTIVATE
82 * and WM_WINDOWPOSCHANGED (which sends WM_MOVE) to the child.
83 * Another WM_WINDOWPOSCHANGING is sent afterwards.
85 * The 2nd WM_WINDOWPOSCHANGING is unconditional, but the comparison
86 * function is too simple to roll back an accepted message, so we have
87 * to mark the 2nd message optional. */
88 { WM_SIZE
, sent
|optional
},
89 { WM_WINDOWPOSCHANGING
, sent
|id
, 0, 0, CHILD1_ID
}, /* Actually optional. */
90 { WM_CHILDACTIVATE
, sent
|id
, 0, 0, CHILD1_ID
}, /* Actually optional. */
91 { WM_WINDOWPOSCHANGED
, sent
|id
|optional
, TRUE
, 0, CHILD1_ID
},
92 { WM_MOVE
, sent
|id
|optional
|defwinproc
, 0, 0, CHILD1_ID
},
93 { WM_WINDOWPOSCHANGING
, sent
|id
|optional
, 0, 0, CHILD1_ID
}, /* Actually not optional. */
94 { WM_CHILDACTIVATE
, sent
|id
|optional
, 0, 0, CHILD1_ID
}, /* Actually not optional. */
98 static const struct message set_pos_empty_seq
[] = {
103 static LRESULT WINAPI
parent_wnd_proc(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
105 static LONG defwndproc_counter
= 0;
109 /* log system messages, except for painting */
110 if (message
< WM_USER
&&
111 message
!= WM_PAINT
&&
112 message
!= WM_ERASEBKGND
&&
113 message
!= WM_NCPAINT
&&
114 message
!= WM_NCHITTEST
&&
115 message
!= WM_GETTEXT
&&
116 message
!= WM_GETICON
&&
117 message
!= WM_DEVICECHANGE
)
119 msg
.message
= message
;
120 msg
.flags
= sent
|wparam
|lparam
|parent
;
121 if (defwndproc_counter
) msg
.flags
|= defwinproc
;
124 if (message
== WM_NOTIFY
&& lParam
) msg
.id
= ((NMHDR
*)lParam
)->code
;
125 add_message(sequences
, PAGER_SEQ_INDEX
, &msg
);
128 if (message
== WM_NOTIFY
)
130 NMHDR
*nmhdr
= (NMHDR
*)lParam
;
136 NMPGCALCSIZE
*nmpgcs
= (NMPGCALCSIZE
*)lParam
;
137 DWORD style
= GetWindowLongA(nmpgcs
->hdr
.hwndFrom
, GWL_STYLE
);
139 if (style
& PGS_HORZ
)
140 ok(nmpgcs
->dwFlag
== PGF_CALCWIDTH
, "Unexpected flags %#x.\n", nmpgcs
->dwFlag
);
142 ok(nmpgcs
->dwFlag
== PGF_CALCHEIGHT
, "Unexpected flags %#x.\n", nmpgcs
->dwFlag
);
150 defwndproc_counter
++;
151 ret
= DefWindowProcA(hwnd
, message
, wParam
, lParam
);
152 defwndproc_counter
--;
157 static BOOL
register_parent_wnd_class(void)
162 cls
.lpfnWndProc
= parent_wnd_proc
;
165 cls
.hInstance
= GetModuleHandleA(NULL
);
167 cls
.hCursor
= LoadCursorA(0, (LPCSTR
)IDC_ARROW
);
168 cls
.hbrBackground
= GetStockObject(WHITE_BRUSH
);
169 cls
.lpszMenuName
= NULL
;
170 cls
.lpszClassName
= "Pager test parent class";
171 return RegisterClassA(&cls
);
174 static HWND
create_parent_window(void)
176 if (!register_parent_wnd_class())
179 return CreateWindowA("Pager test parent class", "Pager test parent window",
180 WS_OVERLAPPED
| WS_VISIBLE
,
181 0, 0, 200, 200, 0, NULL
, GetModuleHandleA(NULL
), NULL
);
184 static LRESULT WINAPI
pager_subclass_proc(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
186 WNDPROC oldproc
= (WNDPROC
)GetWindowLongPtrA(hwnd
, GWLP_USERDATA
);
187 struct message msg
= { 0 };
189 msg
.message
= message
;
190 msg
.flags
= sent
|wparam
|lparam
;
193 add_message(sequences
, PAGER_SEQ_INDEX
, &msg
);
194 return CallWindowProcA(oldproc
, hwnd
, message
, wParam
, lParam
);
197 static HWND
create_pager_control( DWORD style
)
203 GetClientRect( parent_wnd
, &rect
);
204 hwnd
= CreateWindowA( WC_PAGESCROLLERA
, "pager", WS_CHILD
| WS_BORDER
| WS_VISIBLE
| style
,
205 0, 0, 100, 100, parent_wnd
, 0, GetModuleHandleA(0), 0 );
206 oldproc
= (WNDPROC
)SetWindowLongPtrA(hwnd
, GWLP_WNDPROC
, (LONG_PTR
)pager_subclass_proc
);
207 SetWindowLongPtrA(hwnd
, GWLP_USERDATA
, (LONG_PTR
)oldproc
);
211 static LRESULT WINAPI
child_proc(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
213 static LONG defwndproc_counter
;
214 struct message msg
= { 0 };
217 msg
.message
= message
;
218 msg
.flags
= sent
| wparam
| lparam
;
219 if (defwndproc_counter
)
220 msg
.flags
|= defwinproc
;
224 if (hwnd
== child1_wnd
)
226 else if (hwnd
== child2_wnd
)
231 add_message(sequences
, PAGER_SEQ_INDEX
, &msg
);
233 defwndproc_counter
++;
234 ret
= DefWindowProcA(hwnd
, message
, wParam
, lParam
);
235 defwndproc_counter
--;
240 static BOOL
register_child_wnd_class(void)
245 cls
.lpfnWndProc
= child_proc
;
248 cls
.hInstance
= GetModuleHandleA(NULL
);
250 cls
.hCursor
= LoadCursorA(0, (LPCSTR
)IDC_ARROW
);
251 cls
.hbrBackground
= GetStockObject(WHITE_BRUSH
);
252 cls
.lpszMenuName
= NULL
;
253 cls
.lpszClassName
= "Pager test child class";
254 return RegisterClassA(&cls
);
257 static void test_pager(void)
262 pager
= create_pager_control( PGS_HORZ
);
265 win_skip( "Pager control not supported\n" );
269 register_child_wnd_class();
271 child1_wnd
= CreateWindowA( "Pager test child class", "button", WS_CHILD
| WS_BORDER
| WS_VISIBLE
, 0, 0, 300, 300,
272 pager
, 0, GetModuleHandleA(0), 0 );
273 child2_wnd
= CreateWindowA("Pager test child class", "button", WS_CHILD
| WS_BORDER
, 0, 0, 300, 300,
274 pager
, 0, GetModuleHandleA(0), 0);
276 flush_sequences( sequences
, NUM_MSG_SEQUENCES
);
277 SendMessageA( pager
, PGM_SETCHILD
, 0, (LPARAM
)child1_wnd
);
278 ok_sequence(sequences
, PAGER_SEQ_INDEX
, set_child_seq
, "set 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
);
283 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
284 SendMessageA(pager
, PGM_SETCHILD
, 0, (LPARAM
)child2_wnd
);
285 ok_sequence(sequences
, PAGER_SEQ_INDEX
, switch_child_seq
, "switch to invisible child", FALSE
);
286 GetWindowRect(pager
, &rect
);
287 ok(rect
.right
- rect
.left
== 100 && rect
.bottom
- rect
.top
== 100,
288 "pager resized %dx%d\n", rect
.right
- rect
.left
, rect
.bottom
- rect
.top
);
289 ok(!IsWindowVisible(child2_wnd
), "Child window 2 is visible\n");
291 flush_sequences(sequences
, NUM_MSG_SEQUENCES
);
292 SendMessageA(pager
, PGM_SETCHILD
, 0, (LPARAM
)child1_wnd
);
293 ok_sequence(sequences
, PAGER_SEQ_INDEX
, set_child_seq
, "switch to visible child", FALSE
);
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_seq
, "set pos", TRUE
);
301 GetWindowRect( pager
, &rect
);
302 ok( rect
.right
- rect
.left
== 100 && rect
.bottom
- rect
.top
== 100,
303 "pager resized %dx%d\n", rect
.right
- rect
.left
, rect
.bottom
- rect
.top
);
305 flush_sequences( sequences
, NUM_MSG_SEQUENCES
);
306 SendMessageA( pager
, PGM_SETPOS
, 0, 10 );
307 ok_sequence(sequences
, PAGER_SEQ_INDEX
, set_pos_empty_seq
, "set pos empty", TRUE
);
309 flush_sequences( sequences
, NUM_MSG_SEQUENCES
);
310 SendMessageA( pager
, PGM_SETPOS
, 0, 9 );
311 ok_sequence(sequences
, PAGER_SEQ_INDEX
, set_pos_seq
, "set pos", TRUE
);
313 DestroyWindow( pager
);
315 /* Test if resizing works */
316 pager
= create_pager_control( CCS_NORESIZE
);
317 ok(pager
!= NULL
, "failed to create pager control\n");
319 GetWindowRect( pager
, &rect
);
320 MoveWindow( pager
, 0, 0, 200, 100, TRUE
);
321 GetWindowRect( pager
, &rect2
);
322 ok(rect2
.right
- rect2
.left
> rect
.right
- rect
.left
, "expected pager window to resize, %s\n",
323 wine_dbgstr_rect( &rect2
));
325 DestroyWindow( pager
);
327 pager
= create_pager_control( CCS_NORESIZE
| PGS_HORZ
);
328 ok(pager
!= NULL
, "failed to create pager control\n");
330 GetWindowRect( pager
, &rect
);
331 MoveWindow( pager
, 0, 0, 100, 200, TRUE
);
332 GetWindowRect( pager
, &rect2
);
333 ok(rect2
.bottom
- rect2
.top
> rect
.bottom
- rect
.top
, "expected pager window to resize, %s\n",
334 wine_dbgstr_rect( &rect2
));
336 DestroyWindow( pager
);
341 HMODULE mod
= GetModuleHandleA("comctl32.dll");
343 pSetWindowSubclass
= (void*)GetProcAddress(mod
, (LPSTR
)410);
345 InitCommonControls();
346 init_msg_sequences(sequences
, NUM_MSG_SEQUENCES
);
348 parent_wnd
= create_parent_window();
349 ok(parent_wnd
!= NULL
, "Failed to create parent window!\n");