4 * Copyright 2005 Robert Shearman
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #define NONAMELESSUNION
22 #define NONAMELESSSTRUCT
33 #include "wine/test.h"
35 static ATOM atomMenuCheckClass
;
37 static LRESULT WINAPI
menu_check_wnd_proc(HWND hwnd
, UINT msg
, WPARAM wparam
, LPARAM lparam
)
41 case WM_ENTERMENULOOP
:
42 /* mark window as having entered menu loop */
43 SetWindowLongPtr(hwnd
, GWLP_USERDATA
, TRUE
);
44 /* exit menu modal loop
45 * ( A SendMessage does not work on NT3.51 here ) */
46 return PostMessage(hwnd
, WM_CANCELMODE
, 0, 0);
48 return DefWindowProc(hwnd
, msg
, wparam
, lparam
);
51 /* globals to communicate between test and wndproc */
52 unsigned int MOD_maxid
;
54 int MOD_avec
, MOD_hic
;
57 /* wndproc used by test_menu_ownerdraw() */
58 static LRESULT WINAPI
menu_ownerdraw_wnd_proc(HWND hwnd
, UINT msg
,
59 WPARAM wparam
, LPARAM lparam
)
65 MEASUREITEMSTRUCT
* pmis
= (MEASUREITEMSTRUCT
*)lparam
;
67 trace("WM_MEASUREITEM received %d,%d\n",
68 pmis
->itemWidth
, pmis
->itemHeight
);
69 MOD_odheight
= pmis
->itemHeight
;
70 pmis
->itemWidth
= MOD_SIZE
;
71 pmis
->itemHeight
= MOD_SIZE
;
76 DRAWITEMSTRUCT
* pdis
;
79 char chrs
[]="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
81 pdis
= (DRAWITEMSTRUCT
*) lparam
;
83 trace("WM_DRAWITEM received itemdata %ld item %d rc %ld,%ld-%ld,%ld \n",
85 pdis
->itemID
, pdis
->rcItem
.left
, pdis
->rcItem
.top
,
86 pdis
->rcItem
.right
,pdis
->rcItem
.bottom
);
87 oldpen
=SelectObject( pdis
->hDC
, GetStockObject(
88 pdis
->itemState
& ODS_SELECTED
? WHITE_PEN
:BLACK_PEN
));
89 Rectangle( pdis
->hDC
, pdis
->rcItem
.left
,pdis
->rcItem
.top
,
90 pdis
->rcItem
.right
,pdis
->rcItem
.bottom
);
91 SelectObject( pdis
->hDC
, oldpen
);
93 if( pdis
->itemData
> MOD_maxid
) return TRUE
;
94 /* store the rectangl */
95 MOD_rc
[pdis
->itemData
] = pdis
->rcItem
;
96 /* calculate average character width */
97 GetTextExtentPoint( pdis
->hDC
, chrs
, 52, &sz
);
98 MOD_avec
= (sz
.cx
+ 26)/52;
99 GetTextMetrics( pdis
->hDC
, &tm
);
100 MOD_hic
= tm
.tmHeight
;
101 if( pdis
->itemData
== MOD_maxid
) PostMessage(hwnd
, WM_CANCELMODE
, 0, 0);
106 return DefWindowProc(hwnd
, msg
, wparam
, lparam
);
109 static void register_menu_check_class(void)
117 GetModuleHandle(NULL
),
119 LoadCursor(NULL
, IDC_ARROW
),
120 (HBRUSH
)(COLOR_BTNFACE
+1),
122 TEXT("WineMenuCheck"),
125 atomMenuCheckClass
= RegisterClass(&wc
);
128 /* demonstrates that windows lock the menu object so that it is still valid
129 * even after a client calls DestroyMenu on it */
130 static void test_menu_locked_by_window(void)
134 HWND hwnd
= CreateWindowEx(0, MAKEINTATOM(atomMenuCheckClass
), NULL
,
135 WS_VISIBLE
, CW_USEDEFAULT
, CW_USEDEFAULT
, CW_USEDEFAULT
, CW_USEDEFAULT
,
136 NULL
, NULL
, NULL
, NULL
);
137 ok(hwnd
!= NULL
, "CreateWindowEx failed with error %ld\n", GetLastError());
138 hmenu
= CreateMenu();
139 ok(hmenu
!= NULL
, "CreateMenu failed with error %ld\n", GetLastError());
140 ret
= InsertMenu(hmenu
, 0, MF_STRING
, 0, TEXT("&Test"));
141 ok(ret
, "InsertMenu failed with error %ld\n", GetLastError());
142 ret
= SetMenu(hwnd
, hmenu
);
143 ok(ret
, "SetMenu failed with error %ld\n", GetLastError());
144 ret
= DestroyMenu(hmenu
);
145 ok(ret
, "DestroyMenu failed with error %ld\n", GetLastError());
147 ret
= DrawMenuBar(hwnd
);
149 ok(ret
, "DrawMenuBar failed with error %ld\n", GetLastError());
151 ret
= IsMenu(GetMenu(hwnd
));
152 ok(!ret
, "Menu handle should have been destroyed\n");
154 SendMessage(hwnd
, WM_SYSCOMMAND
, SC_KEYMENU
, 0);
155 /* did we process the WM_INITMENU message? */
156 ret
= GetWindowLongPtr(hwnd
, GWLP_USERDATA
);
158 ok(ret
, "WM_INITMENU should have been sent\n");
164 static void test_menu_ownerdraw(void)
170 HWND hwnd
= CreateWindowEx(0, MAKEINTATOM(atomMenuCheckClass
), NULL
,
171 WS_VISIBLE
, CW_USEDEFAULT
, CW_USEDEFAULT
, CW_USEDEFAULT
, CW_USEDEFAULT
,
172 NULL
, NULL
, NULL
, NULL
);
173 ok(hwnd
!= NULL
, "CreateWindowEx failed with error %ld\n", GetLastError());
175 SetWindowLong( hwnd
, GWL_WNDPROC
, (LONG
)menu_ownerdraw_wnd_proc
);
176 hmenu
= CreatePopupMenu();
177 ok(hmenu
!= NULL
, "CreateMenu failed with error %ld\n", GetLastError());
178 if( !hmenu
) { DestroyWindow(hwnd
);return;}
180 for( j
=0;j
<2;j
++) /* create columns */
181 for(i
=0;i
<2;i
++) { /* create rows */
182 ret
= AppendMenu( hmenu
, MF_OWNERDRAW
|
183 (i
==0 ? MF_MENUBREAK
: 0), k
, (LPCTSTR
) k
);
185 ok( ret
, "AppendMenu failed for %d\n", k
-1);
188 assert( k
<= sizeof(MOD_rc
)/sizeof(RECT
));
189 /* display the menu */
190 ret
= TrackPopupMenu( hmenu
, 0x100, 100,100, 0, hwnd
, NULL
);
192 /* columns have a 4 pixel gap between them */
193 ok( MOD_rc
[0].right
+ 4 == MOD_rc
[2].left
,
194 "item rectangles are not separated by 4 pixels space\n");
195 /* height should be what the MEASUREITEM message has returned */
196 ok( MOD_rc
[0].bottom
- MOD_rc
[0].top
== MOD_SIZE
,
197 "menu item has wrong height: %ld should be %d\n",
198 MOD_rc
[0].bottom
- MOD_rc
[0].top
, MOD_SIZE
);
199 /* no gaps between the rows */
200 ok( MOD_rc
[0].bottom
- MOD_rc
[1].top
== 0,
201 "There should not be a space between the rows, gap is %ld\n",
202 MOD_rc
[0].bottom
- MOD_rc
[1].top
);
203 /* test the correct value of the item height that was sent
204 * by the WM_MEASUREITEM message */
205 ok( MOD_odheight
== HIWORD( GetDialogBaseUnits()) || /* WinNT,2k,XP */
206 MOD_odheight
== MOD_hic
, /* Win95,98,ME */
207 "Wrong height field in MEASUREITEMSTRUCT, expected %d or %d actual %d\n",
208 HIWORD( GetDialogBaseUnits()), MOD_hic
, MOD_odheight
);
209 /* test what MF_MENUBREAK did at the first position. Also show
210 * that an MF_SEPARATOR is ignored in the height calculation. */
211 leftcol
= MOD_rc
[0].left
;
212 ModifyMenu( hmenu
, 0, MF_BYCOMMAND
| MF_OWNERDRAW
| MF_SEPARATOR
, 0, 0);
213 /* display the menu */
214 ret
= TrackPopupMenu( hmenu
, 0x100, 100,100, 0, hwnd
, NULL
);
215 /* left should be 4 pixels less now */
216 ok( leftcol
== MOD_rc
[0].left
+ 4,
217 "columns should be 4 pixels to the left (actual %ld).\n",
218 leftcol
- MOD_rc
[0].left
);
220 ok( MOD_rc
[0].right
- MOD_rc
[0].left
== 2 * MOD_avec
+ MOD_SIZE
,
221 "width of owner drawn menu item is wrong. Got %ld expected %d\n",
222 MOD_rc
[0].right
- MOD_rc
[0].left
, 2*MOD_avec
+ MOD_SIZE
);
224 ok( MOD_rc
[0].bottom
- MOD_rc
[0].top
== MOD_SIZE
,
225 "Height is incorrect. Got %ld expected %d\n",
226 MOD_rc
[0].bottom
- MOD_rc
[0].top
, MOD_SIZE
);
228 /* test width/height of a OD menu bar as well */
229 ret
= DestroyMenu(hmenu
);
230 ok(ret
, "DestroyMenu failed with error %ld\n", GetLastError());
231 hmenu
= CreateMenu();
232 ok(hmenu
!= NULL
, "CreateMenu failed with error %ld\n", GetLastError());
233 if( !hmenu
) { DestroyWindow(hwnd
);return;}
236 ret
= AppendMenu( hmenu
, MF_OWNERDRAW
, i
, 0);
237 ok( ret
, "AppendMenu failed for %d\n", i
);
239 SetMenu( hwnd
, hmenu
);
240 UpdateWindow( hwnd
); /* hack for wine to draw the window + menu */
241 ok(ret
, "SetMenu failed with error %ld\n", GetLastError());
243 ok( MOD_rc
[0].right
- MOD_rc
[0].left
== 2 * MOD_avec
+ MOD_SIZE
,
244 "width of owner drawn menu item is wrong. Got %ld expected %d\n",
245 MOD_rc
[0].right
- MOD_rc
[0].left
, 2*MOD_avec
+ MOD_SIZE
);
247 ok( MOD_rc
[0].bottom
- MOD_rc
[0].top
== GetSystemMetrics( SM_CYMENU
) - 1,
248 "Height of owner drawn menu item is wrong. Got %ld expected %d\n",
249 MOD_rc
[0].bottom
- MOD_rc
[0].top
, GetSystemMetrics( SM_CYMENU
) - 1);
256 register_menu_check_class();
258 test_menu_locked_by_window();
259 test_menu_ownerdraw();