7470a3c8f9f5e9db079ae6fbf39dd37396e3aff2
[reactos.git] / reactos / win32ss / user / user32 / windows / menu.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS user32.dll
4 * FILE: user32/windows/menu.c
5 * PURPOSE: Menus
6 *
7 * PROGRAMMERS: Casper S. Hornstrup
8 * James Tabor
9 */
10
11 /* INCLUDES ******************************************************************/
12
13 #include <user32.h>
14 #include <wine/debug.h>
15
16 LRESULT DefWndNCPaint(HWND hWnd, HRGN hRgn, BOOL Active);
17 BOOL WINAPI GdiValidateHandle(HGDIOBJ hobj);
18
19 WINE_DEFAULT_DEBUG_CHANNEL(menu);
20
21 /* internal popup menu window messages */
22
23 #define MM_SETMENUHANDLE (WM_USER + 0)
24 #define MM_GETMENUHANDLE (WM_USER + 1)
25
26 /* internal flags for menu tracking */
27
28 #define TF_ENDMENU 0x10000
29 #define TF_SUSPENDPOPUP 0x20000
30 #define TF_SKIPREMOVE 0x40000
31
32 #define ITEM_PREV -1
33 #define ITEM_NEXT 1
34
35 /* Internal MenuTrackMenu() flags */
36 #define TPM_INTERNAL 0xF0000000
37 #define TPM_BUTTONDOWN 0x40000000 /* menu was clicked before tracking */
38 #define TPM_POPUPMENU 0x20000000 /* menu is a popup menu */
39
40 /* top and bottom margins for popup menus */
41 #define MENU_TOP_MARGIN 3
42 #define MENU_BOTTOM_MARGIN 2
43
44 #define MENU_TYPE_MASK (MF_STRING | MF_BITMAP | MF_OWNERDRAW | MF_SEPARATOR)
45
46 #define MENU_ITEM_TYPE(flags) ((flags) & MENU_TYPE_MASK)
47
48 #define MNS_STYLE_MASK (MNS_NOCHECK|MNS_MODELESS|MNS_DRAGDROP|MNS_AUTODISMISS|MNS_NOTIFYBYPOS|MNS_CHECKORBMP)
49
50 #define MENUITEMINFO_TYPE_MASK \
51 (MFT_STRING | MFT_BITMAP | MFT_OWNERDRAW | MFT_SEPARATOR | \
52 MFT_MENUBARBREAK | MFT_MENUBREAK | MFT_RADIOCHECK | \
53 MFT_RIGHTORDER | MFT_RIGHTJUSTIFY /* same as MF_HELP */ )
54
55 #define TYPE_MASK (MENUITEMINFO_TYPE_MASK | MF_POPUP | MF_SYSMENU)
56
57 #define STATE_MASK (~TYPE_MASK)
58
59 #define MENUITEMINFO_STATE_MASK (STATE_MASK & ~(MF_BYPOSITION | MF_MOUSESELECT))
60
61 #define MII_STATE_MASK (MFS_GRAYED|MFS_CHECKED|MFS_HILITE|MFS_DEFAULT)
62
63 /* macro to test that flags do not indicate bitmap, ownerdraw or separator */
64 #define IS_STRING_ITEM(flags) (MF_STRING == MENU_ITEM_TYPE(flags))
65 #define IS_MAGIC_BITMAP(id) ((id) && ((INT_PTR)(id) < 12) && ((INT_PTR)(id) >= -1))
66
67 #define IS_SYSTEM_MENU(MenuInfo) \
68 (0 == ((MenuInfo)->fFlags & MNF_POPUP) && 0 != ((MenuInfo)->fFlags & MNF_SYSDESKMN))
69
70 #define IS_SYSTEM_POPUP(MenuInfo) \
71 (0 != ((MenuInfo)->fFlags & MNF_POPUP) && 0 != ((MenuInfo)->fFlags & MNF_SYSDESKMN))
72
73 #define IS_BITMAP_ITEM(flags) (MF_BITMAP == MENU_ITEM_TYPE(flags))
74
75 /* Use global popup window because there's no way 2 menus can
76 * be tracked at the same time. */
77 static HWND top_popup;
78 static HMENU top_popup_hmenu;
79
80 /* Flag set by EndMenu() to force an exit from menu tracking */
81 static BOOL fEndMenu = FALSE;
82
83 #define MENU_ITEM_HBMP_SPACE (5)
84 #define MENU_BAR_ITEMS_SPACE (12)
85 #define SEPARATOR_HEIGHT (5)
86 #define MENU_TAB_SPACE (8)
87
88 typedef struct
89 {
90 UINT TrackFlags;
91 HMENU CurrentMenu; /* current submenu (can be equal to hTopMenu)*/
92 HMENU TopMenu; /* initial menu */
93 HWND OwnerWnd; /* where notifications are sent */
94 POINT Pt;
95 } MTRACKER;
96
97
98 /*********************************************************************
99 * PopupMenu class descriptor
100 */
101 const struct builtin_class_descr POPUPMENU_builtin_class =
102 {
103 WC_MENU, /* name */
104 CS_SAVEBITS | CS_DBLCLKS, /* style */
105 (WNDPROC) NULL, /* FIXME - procA */
106 (WNDPROC) PopupMenuWndProcW, /* FIXME - procW */
107 sizeof(MENUINFO *), /* extra */
108 (LPCWSTR) IDC_ARROW, /* cursor */
109 (HBRUSH)(COLOR_MENU + 1) /* brush */
110 };
111
112 #ifndef GET_WORD
113 #define GET_WORD(ptr) (*(WORD *)(ptr))
114 #endif
115 #ifndef GET_DWORD
116 #define GET_DWORD(ptr) (*(DWORD *)(ptr))
117 #endif
118
119 HFONT hMenuFont = NULL;
120 HFONT hMenuFontBold = NULL;
121
122 /* Dimension of the menu bitmaps */
123 static HBITMAP BmpSysMenu = NULL;
124
125 static SIZE MenuCharSize;
126
127
128 /***********************************************************************
129 * MENU_GetMenu
130 *
131 * Validate the given menu handle and returns the menu structure pointer.
132 */
133 FORCEINLINE PMENU MENU_GetMenu(HMENU hMenu)
134 {
135 return ValidateHandle(hMenu, TYPE_MENU);
136 }
137
138 /***********************************************************************
139 * MENU_FindItem
140 *
141 * Find a menu item. Return a pointer on the item, and modifies *hmenu
142 * in case the item was in a sub-menu.
143 */
144 ITEM *MENU_FindItem( HMENU *hmenu, UINT *nPos, UINT wFlags )
145 {
146 MENU *menu;
147 ITEM *fallback = NULL;
148 UINT fallback_pos = 0;
149 UINT i;
150 PITEM pItem;
151
152 if ((*hmenu == (HMENU)0xffff) || (!(menu = MENU_GetMenu(*hmenu)))) return NULL;
153 if (wFlags & MF_BYPOSITION)
154 {
155 if (*nPos >= menu->cItems) return NULL;
156 pItem = menu->rgItems ? DesktopPtrToUser(menu->rgItems) : NULL;
157 //pItem = &menu->rgItems[*nPos];
158 i = 0;
159 while(pItem) // Do this for now.
160 {
161 if (i < (INT)menu->cItems)
162 {
163 if ( *nPos == i ) return pItem;
164 }
165 pItem = pItem->Next ? DesktopPtrToUser(pItem->Next) : NULL;
166 i++;
167 }
168 }
169 else
170 {
171 PITEM item = menu->rgItems ? DesktopPtrToUser(menu->rgItems) : NULL;
172 for (i = 0; item ,i < menu->cItems; i++, item = item->Next ? DesktopPtrToUser(item->Next) : NULL)//, item++)
173 {
174 if (item->spSubMenu)
175 {
176 PMENU pSubMenu = DesktopPtrToUser(item->spSubMenu);
177 HMENU hsubmenu = UserHMGetHandle(pSubMenu);
178 ITEM *subitem = MENU_FindItem( &hsubmenu, nPos, wFlags );
179 if (subitem)
180 {
181 *hmenu = hsubmenu;
182 return subitem;
183 }
184 else if (item->wID == *nPos)
185 {
186 /* fallback to this item if nothing else found */
187 fallback_pos = i;
188 fallback = item;
189 }
190 }
191 else if (item->wID == *nPos)
192 {
193 *nPos = i;
194 return item;
195 }
196 }
197 }
198
199 if (fallback)
200 *nPos = fallback_pos;
201
202 return fallback;
203 }
204
205 #define MAX_GOINTOSUBMENU (0x10)
206 UINT FASTCALL
207 IntGetMenuDefaultItem(PMENU Menu, BOOL fByPos, UINT gmdiFlags, DWORD *gismc)
208 {
209 UINT x = 0;
210 UINT res = -1;
211 UINT sres;
212 PITEM Item = Menu->rgItems ? DesktopPtrToUser(Menu->rgItems) : NULL;
213
214 while(Item)
215 {
216 if (Item->fState & MFS_DEFAULT)
217 {
218 if (!(gmdiFlags & GMDI_USEDISABLED) &&
219 (Item->fState & MFS_DISABLED) )
220 break;
221
222 res = fByPos ? x : Item->wID;
223
224 if ((*gismc < MAX_GOINTOSUBMENU) &&
225 (gmdiFlags & GMDI_GOINTOPOPUPS) &&
226 Item->spSubMenu)
227 {
228 if (DesktopPtrToUser(Item->spSubMenu) == Menu)
229 break;
230
231 (*gismc)++;
232 sres = IntGetMenuDefaultItem( DesktopPtrToUser(Item->spSubMenu), fByPos, gmdiFlags, gismc);
233 (*gismc)--;
234
235 if(sres > (UINT)-1)
236 res = sres;
237 }
238 break;
239 }
240 Item = Item->Next ? DesktopPtrToUser(Item->Next) : NULL;
241 x++;
242 }
243 return res;
244 }
245
246 static BOOL GetMenuItemInfo_common ( HMENU hmenu,
247 UINT item,
248 BOOL bypos,
249 LPMENUITEMINFOW lpmii,
250 BOOL unicode)
251 {
252 ITEM *pItem = MENU_FindItem (&hmenu, &item, bypos ? MF_BYPOSITION : 0);
253
254 //debug_print_menuitem("GetMenuItemInfo_common: ", pItem, "");
255
256 if (!pItem)
257 {
258 SetLastError( ERROR_MENU_ITEM_NOT_FOUND);
259 //SetLastError(ERROR_INVALID_PARAMETER);
260 return FALSE;
261 }
262
263 if( lpmii->fMask & MIIM_TYPE)
264 {
265 if( lpmii->fMask & ( MIIM_STRING | MIIM_FTYPE | MIIM_BITMAP))
266 {
267 ERR("invalid combination of fMask bits used\n");
268 /* this does not happen on Win9x/ME */
269 SetLastError( ERROR_INVALID_PARAMETER);
270 return FALSE;
271 }
272 lpmii->fType = pItem->fType & MENUITEMINFO_TYPE_MASK;
273 if( pItem->hbmp) lpmii->fType |= MFT_BITMAP;
274 lpmii->hbmpItem = pItem->hbmp; /* not on Win9x/ME */
275 if( lpmii->fType & MFT_BITMAP)
276 {
277 lpmii->dwTypeData = (LPWSTR) pItem->hbmp;
278 lpmii->cch = 0;
279 }
280 else if( lpmii->fType & (MFT_OWNERDRAW | MFT_SEPARATOR))
281 {
282 /* this does not happen on Win9x/ME */
283 lpmii->dwTypeData = 0;
284 lpmii->cch = 0;
285 }
286 }
287
288 /* copy the text string */
289 if ((lpmii->fMask & (MIIM_TYPE|MIIM_STRING)))
290 {
291 if( !pItem->Xlpstr )
292 { // Very strange this fixes a wine test with a crash.
293 if(lpmii->dwTypeData && lpmii->cch && !(GdiValidateHandle((HGDIOBJ)lpmii->dwTypeData)) )
294 {
295 lpmii->cch = 0;
296 if( unicode)
297 *((WCHAR *)lpmii->dwTypeData) = 0;
298 else
299 *((CHAR *)lpmii->dwTypeData) = 0;
300 }
301 }
302 else
303 {
304 int len;
305 LPWSTR text = DesktopPtrToUser(pItem->Xlpstr);
306 if (unicode)
307 {
308 len = strlenW(text);
309 if(lpmii->dwTypeData && lpmii->cch)
310 lstrcpynW(lpmii->dwTypeData, text, lpmii->cch);
311 }
312 else
313 {
314 len = WideCharToMultiByte( CP_ACP, 0, text, -1, NULL, 0, NULL, NULL ) - 1;
315 if(lpmii->dwTypeData && lpmii->cch)
316 if (!WideCharToMultiByte( CP_ACP, 0, text, -1,
317 (LPSTR)lpmii->dwTypeData, lpmii->cch, NULL, NULL ))
318 ((LPSTR)lpmii->dwTypeData)[lpmii->cch - 1] = 0;
319 }
320 /* if we've copied a substring we return its length */
321 if(lpmii->dwTypeData && lpmii->cch)
322 if (lpmii->cch <= len + 1)
323 lpmii->cch--;
324 else
325 lpmii->cch = len;
326 else
327 {
328 /* return length of string */
329 /* not on Win9x/ME if fType & MFT_BITMAP */
330 lpmii->cch = len;
331 }
332 }
333 }
334
335 if (lpmii->fMask & MIIM_FTYPE)
336 lpmii->fType = pItem->fType & MENUITEMINFO_TYPE_MASK;
337
338 if (lpmii->fMask & MIIM_BITMAP)
339 lpmii->hbmpItem = pItem->hbmp;
340
341 if (lpmii->fMask & MIIM_STATE)
342 lpmii->fState = pItem->fState & MII_STATE_MASK; //MENUITEMINFO_STATE_MASK;
343
344 if (lpmii->fMask & MIIM_ID)
345 lpmii->wID = pItem->wID;
346
347 if (lpmii->fMask & MIIM_SUBMENU && pItem->spSubMenu )
348 {
349 PMENU pSubMenu = DesktopPtrToUser(pItem->spSubMenu);
350 HMENU hSubMenu = UserHMGetHandle(pSubMenu);
351 lpmii->hSubMenu = hSubMenu;
352 }
353 else
354 {
355 /* hSubMenu is always cleared
356 * (not on Win9x/ME ) */
357 lpmii->hSubMenu = 0;
358 }
359
360 if (lpmii->fMask & MIIM_CHECKMARKS)
361 {
362 lpmii->hbmpChecked = pItem->hbmpChecked;
363 lpmii->hbmpUnchecked = pItem->hbmpUnchecked;
364 }
365 if (lpmii->fMask & MIIM_DATA)
366 lpmii->dwItemData = pItem->dwItemData;
367
368 return TRUE;
369 }
370
371 /***********************************************************************
372 * MenuGetRosMenuInfo
373 *
374 * Get full information about menu
375 */
376 static BOOL FASTCALL
377 MenuGetRosMenuInfo(PROSMENUINFO MenuInfo, HMENU Menu)
378 {
379 PMENU pMenu;
380 if (!(pMenu = ValidateHandle(Menu, TYPE_MENU))) return FALSE;
381
382 MenuInfo->hbrBack = pMenu->hbrBack;
383 MenuInfo->dwContextHelpID = pMenu->dwContextHelpId;
384 MenuInfo->cyMax = pMenu->cyMax;
385 MenuInfo->dwMenuData = pMenu->dwMenuData;
386 MenuInfo->dwStyle = pMenu->fFlags & MNS_STYLE_MASK;
387
388 MenuInfo->cItems = pMenu->cItems;
389
390 MenuInfo->iItem = pMenu->iItem;
391 MenuInfo->cxMenu = pMenu->cxMenu;
392 MenuInfo->cyMenu = pMenu->cyMenu;
393 MenuInfo->spwndNotify = pMenu->spwndNotify;
394 MenuInfo->cxTextAlign = pMenu->cxTextAlign;
395 MenuInfo->iTop = pMenu->iMaxTop;
396 MenuInfo->iMaxTop = pMenu->iMaxTop;
397 MenuInfo->dwArrowsOn = pMenu->dwArrowsOn;
398
399 MenuInfo->fFlags = pMenu->fFlags;
400 MenuInfo->Self = pMenu->head.h;
401 MenuInfo->TimeToHide = pMenu->TimeToHide;
402 MenuInfo->Wnd = pMenu->hWnd;
403 return TRUE;
404 }
405
406 /***********************************************************************
407 * MenuSetRosMenuInfo
408 *
409 * Set full information about menu
410 */
411 static BOOL FASTCALL
412 MenuSetRosMenuInfo(PROSMENUINFO MenuInfo)
413 {
414 MenuInfo->cbSize = sizeof(ROSMENUINFO);
415 MenuInfo->fMask = MIM_BACKGROUND | MIM_HELPID | MIM_MAXHEIGHT | MIM_MENUDATA | MIM_STYLE;
416
417 return NtUserThunkedMenuInfo(MenuInfo->Self, (LPCMENUINFO)MenuInfo);
418 }
419
420 /***********************************************************************
421 * MenuInitRosMenuItemInfo
422 *
423 * Initialize a buffer for use with MenuGet/SetRosMenuItemInfo
424 */
425 static VOID FASTCALL
426 MenuInitRosMenuItemInfo(PROSMENUITEMINFO ItemInfo)
427 {
428 ZeroMemory(ItemInfo, sizeof(ROSMENUITEMINFO));
429 ItemInfo->cbSize = sizeof(ROSMENUITEMINFO);
430 }
431
432 /***********************************************************************
433 * MenuGetRosMenuItemInfo
434 *
435 * Get full information about a menu item
436 */
437 static BOOL FASTCALL
438 MenuGetRosMenuItemInfo(HMENU Menu, UINT Index, PROSMENUITEMINFO ItemInfo)
439 {
440 PITEM pItem;
441 UINT Save_Mask = ItemInfo->fMask; /* Save the org mask bits. */
442
443 if (ItemInfo->dwTypeData != NULL)
444 {
445 HeapFree(GetProcessHeap(), 0, ItemInfo->dwTypeData);
446 }
447
448 ItemInfo->dwTypeData = NULL;
449
450 if (!(pItem = MENU_FindItem(&Menu, &Index, MF_BYPOSITION)))
451 {
452 ItemInfo->fType = 0;
453 return FALSE;
454 }
455
456 ItemInfo->fType = pItem->fType;
457 ItemInfo->hbmpItem = pItem->hbmp;
458 ItemInfo->hbmpChecked = pItem->hbmpChecked;
459 ItemInfo->hbmpUnchecked = pItem->hbmpUnchecked;
460 ItemInfo->dwItemData = pItem->dwItemData;
461 ItemInfo->wID = pItem->wID;
462 ItemInfo->fState = pItem->fState;
463
464 if (pItem->spSubMenu)
465 {
466 PMENU pSubMenu = DesktopPtrToUser(pItem->spSubMenu);
467 HMENU hSubMenu = UserHMGetHandle(pSubMenu);
468 ItemInfo->hSubMenu = hSubMenu;
469 }
470 else
471 ItemInfo->hSubMenu = NULL;
472
473 if (MENU_ITEM_TYPE(ItemInfo->fType) == MF_STRING)
474 {
475 LPWSTR lpstr = pItem->lpstr.Buffer ? DesktopPtrToUser(pItem->lpstr.Buffer) : NULL;
476 if (lpstr)
477 {
478 ItemInfo->cch = pItem->lpstr.Length / sizeof(WCHAR);
479 ItemInfo->cch++;
480 ItemInfo->dwTypeData = HeapAlloc(GetProcessHeap(), 0, ItemInfo->cch * sizeof(WCHAR));
481 if (ItemInfo->dwTypeData == NULL)
482 {
483 return FALSE;
484 }
485 RtlCopyMemory(ItemInfo->dwTypeData, lpstr, min(ItemInfo->cch * sizeof(WCHAR), pItem->lpstr.MaximumLength));
486 }
487 else
488 {
489 ItemInfo->cch = 0;
490 }
491 }
492
493 ItemInfo->Rect.left = pItem->xItem;
494 ItemInfo->Rect.top = pItem->yItem;
495 ItemInfo->Rect.right = pItem->cxItem; // Do this for now......
496 ItemInfo->Rect.bottom = pItem->cyItem;
497 ItemInfo->dxTab = pItem->dxTab;
498 ItemInfo->lpstr = pItem->lpstr.Buffer;
499 ItemInfo->maxBmpSize.cx = pItem->cxBmp;
500 ItemInfo->maxBmpSize.cy = pItem->cyBmp;
501
502 ItemInfo->fMask = Save_Mask;
503 return TRUE;
504 }
505
506 /***********************************************************************
507 * MenuSetRosMenuItemInfo
508 *
509 * Set selected information about a menu item, need to set the mask bits.
510 */
511 static BOOL FASTCALL
512 MenuSetRosMenuItemInfo(HMENU Menu, UINT Index, PROSMENUITEMINFO ItemInfo)
513 {
514 BOOL Ret;
515
516 if (MENU_ITEM_TYPE(ItemInfo->fType) == MF_STRING &&
517 ItemInfo->dwTypeData != NULL)
518 {
519 ItemInfo->cch = strlenW(ItemInfo->dwTypeData);
520 }
521 Ret = NtUserThunkedMenuItemInfo(Menu, Index, TRUE, FALSE, (LPMENUITEMINFOW)ItemInfo, NULL);
522 return Ret;
523 }
524
525 /***********************************************************************
526 * MenuCleanupRosMenuItemInfo
527 *
528 * Cleanup after use of MenuGet/SetRosMenuItemInfo
529 */
530 static VOID FASTCALL
531 MenuCleanupRosMenuItemInfo(PROSMENUITEMINFO ItemInfo)
532 {
533 if (ItemInfo->dwTypeData != NULL)
534 {
535 HeapFree(GetProcessHeap(), 0, ItemInfo->dwTypeData);
536 ItemInfo->dwTypeData = NULL;
537 }
538 }
539
540 DWORD FASTCALL
541 IntBuildMenuItemList(PMENU MenuObject, PVOID Buffer, ULONG nMax)
542 {
543 DWORD res = 0;
544 ROSMENUITEMINFO mii;
545 PVOID Buf;
546 PITEM CurItem = MenuObject->rgItems ? DesktopPtrToUser(MenuObject->rgItems) : NULL;
547 PWCHAR StrOut;
548 WCHAR NulByte;
549
550 if (0 != nMax)
551 {
552 if (nMax < MenuObject->cItems * sizeof(ROSMENUITEMINFO))
553 {
554 return 0;
555 }
556 StrOut = (PWCHAR)((char *) Buffer + MenuObject->cItems * sizeof(ROSMENUITEMINFO));
557 nMax -= MenuObject->cItems * sizeof(ROSMENUITEMINFO);
558 Buf = Buffer;
559 mii.cbSize = sizeof(ROSMENUITEMINFO);
560 mii.fMask = 0;
561 NulByte = L'\0';
562
563 while (NULL != CurItem)
564 {
565 mii.cch = CurItem->lpstr.Length / sizeof(WCHAR);
566 mii.dwItemData = CurItem->dwItemData;
567 if (0 != CurItem->lpstr.Length)
568 {
569 mii.dwTypeData = StrOut;
570 }
571 else
572 {
573 mii.dwTypeData = NULL;
574 }
575 mii.fState = CurItem->fState;
576 mii.fType = CurItem->fType;
577 mii.wID = CurItem->wID;
578 mii.hbmpChecked = CurItem->hbmpChecked;
579 mii.hbmpItem = CurItem->hbmp;
580 mii.hbmpUnchecked = CurItem->hbmpUnchecked;
581 if (CurItem->spSubMenu)
582 {
583 PMENU pSubMenu = DesktopPtrToUser(CurItem->spSubMenu);
584 HMENU hSubMenu = UserHMGetHandle(pSubMenu);
585 mii.hSubMenu = hSubMenu;
586 }
587 else
588 mii.hSubMenu = NULL;
589 mii.Rect.left = CurItem->xItem;
590 mii.Rect.top = CurItem->yItem;
591 mii.Rect.right = CurItem->cxItem; // Do this for now......
592 mii.Rect.bottom = CurItem->cyItem;
593 mii.dxTab = CurItem->dxTab;
594 mii.lpstr = CurItem->lpstr.Buffer; // Can be read from user side!
595 //mii.maxBmpSize.cx = CurItem->cxBmp;
596 //mii.maxBmpSize.cy = CurItem->cyBmp;
597
598 RtlCopyMemory(Buf, &mii, sizeof(ROSMENUITEMINFO));
599 Buf = (PVOID)((ULONG_PTR)Buf + sizeof(ROSMENUITEMINFO));
600
601 if (0 != CurItem->lpstr.Length && (nMax >= CurItem->lpstr.Length + sizeof(WCHAR)))
602 {
603 LPWSTR lpstr = CurItem->lpstr.Buffer ? DesktopPtrToUser(CurItem->lpstr.Buffer) : NULL;
604 if (lpstr)
605 {
606 /* Copy string */
607 RtlCopyMemory(StrOut, lpstr, CurItem->lpstr.Length);
608
609 StrOut += CurItem->lpstr.Length / sizeof(WCHAR);
610 RtlCopyMemory(StrOut, &NulByte, sizeof(WCHAR));
611 StrOut++;
612 nMax -= CurItem->lpstr.Length + sizeof(WCHAR);
613 }
614 }
615 else if (0 != CurItem->lpstr.Length)
616 {
617 break;
618 }
619
620 CurItem = CurItem->Next ? DesktopPtrToUser(CurItem->Next) : NULL;
621 res++;
622 }
623 }
624 else
625 {
626 while (NULL != CurItem)
627 {
628 res += sizeof(ROSMENUITEMINFO) + CurItem->lpstr.Length + sizeof(WCHAR);
629 CurItem = CurItem->Next ? DesktopPtrToUser(CurItem->Next) : NULL;
630 }
631 }
632 return res;
633 }
634
635 /***********************************************************************
636 * MenuGetAllRosMenuItemInfo
637 *
638 * Get full information about all menu items
639 */
640 static INT FASTCALL
641 MenuGetAllRosMenuItemInfo(HMENU Menu, PROSMENUITEMINFO *ItemInfo)
642 {
643 DWORD BufSize;
644 PMENU pMenu;
645
646 if (!(pMenu = ValidateHandle(Menu, TYPE_MENU))) return -1;
647
648 BufSize = IntBuildMenuItemList(pMenu, (PVOID)1, 0);
649 if (BufSize == (DWORD) -1 || BufSize == 0)
650 {
651 return -1;
652 }
653 *ItemInfo = HeapAlloc(GetProcessHeap(), 0, BufSize);
654 if (NULL == *ItemInfo)
655 {
656 return -1;
657 }
658
659 return IntBuildMenuItemList(pMenu, (PVOID)*ItemInfo, BufSize);
660 }
661
662 /***********************************************************************
663 * MenuCleanupAllRosMenuItemInfo
664 *
665 * Cleanup after use of MenuGetAllRosMenuItemInfo
666 */
667 static VOID FASTCALL
668 MenuCleanupAllRosMenuItemInfo(PROSMENUITEMINFO ItemInfo)
669 {
670 HeapFree(GetProcessHeap(), 0, ItemInfo);
671 }
672
673 /***********************************************************************
674 * MenuInitSysMenuPopup
675 *
676 * Grey the appropriate items in System menu.
677 */
678 void FASTCALL MenuInitSysMenuPopup(HMENU hmenu, DWORD style, DWORD clsStyle, LONG HitTest )
679 {
680 BOOL gray;
681 UINT DefItem;
682 #if 0
683 MENUITEMINFOW mii;
684 #endif
685
686 gray = !(style & WS_THICKFRAME) || (style & (WS_MAXIMIZE | WS_MINIMIZE));
687 EnableMenuItem( hmenu, SC_SIZE, (gray ? MF_GRAYED : MF_ENABLED) );
688 gray = ((style & WS_MAXIMIZE) != 0);
689 EnableMenuItem( hmenu, SC_MOVE, (gray ? MF_GRAYED : MF_ENABLED) );
690 gray = !(style & WS_MINIMIZEBOX) || (style & WS_MINIMIZE);
691 EnableMenuItem( hmenu, SC_MINIMIZE, (gray ? MF_GRAYED : MF_ENABLED) );
692 gray = !(style & WS_MAXIMIZEBOX) || (style & WS_MAXIMIZE);
693 EnableMenuItem( hmenu, SC_MAXIMIZE, (gray ? MF_GRAYED : MF_ENABLED) );
694 gray = !(style & (WS_MAXIMIZE | WS_MINIMIZE));
695 EnableMenuItem( hmenu, SC_RESTORE, (gray ? MF_GRAYED : MF_ENABLED) );
696 gray = (clsStyle & CS_NOCLOSE) != 0;
697
698 /* The menu item must keep its state if it's disabled */
699 if(gray)
700 EnableMenuItem( hmenu, SC_CLOSE, MF_GRAYED);
701
702 /* Set default menu item */
703 if(style & WS_MINIMIZE) DefItem = SC_RESTORE;
704 else if(HitTest == HTCAPTION) DefItem = ((style & (WS_MAXIMIZE | WS_MINIMIZE)) ? SC_RESTORE : SC_MAXIMIZE);
705 else DefItem = SC_CLOSE;
706 #if 0
707 mii.cbSize = sizeof(MENUITEMINFOW);
708 mii.fMask |= MIIM_STATE;
709 if((DefItem != SC_CLOSE) && GetMenuItemInfoW(hmenu, DefItem, FALSE, &mii) &&
710 (mii.fState & (MFS_GRAYED | MFS_DISABLED))) DefItem = SC_CLOSE;
711 #endif
712 SetMenuDefaultItem(hmenu, DefItem, MF_BYCOMMAND);
713 }
714
715 /******************************************************************************
716 *
717 * UINT MenuGetStartOfNextColumn(
718 * PROSMENUINFO MenuInfo)
719 *
720 *****************************************************************************/
721 static UINT MenuGetStartOfNextColumn(
722 PROSMENUINFO MenuInfo)
723 {
724 PROSMENUITEMINFO MenuItems;
725 UINT i;
726
727 i = MenuInfo->iItem;
728 if ( i == NO_SELECTED_ITEM )
729 return i;
730
731 if (MenuGetAllRosMenuItemInfo(MenuInfo->Self, &MenuItems) <= 0)
732 return NO_SELECTED_ITEM;
733
734 for (i++ ; i < MenuInfo->cItems; i++)
735 if (0 != (MenuItems[i].fType & (MF_MENUBREAK | MF_MENUBARBREAK)))
736 return i;
737
738 return NO_SELECTED_ITEM;
739 }
740
741 /******************************************************************************
742 *
743 * UINT MenuGetStartOfPrevColumn(
744 * PROSMENUINFO MenuInfo)
745 *
746 *****************************************************************************/
747
748 static UINT FASTCALL MenuGetStartOfPrevColumn(
749 PROSMENUINFO MenuInfo)
750 {
751 PROSMENUITEMINFO MenuItems;
752 UINT i;
753
754 if (!MenuInfo->iItem || MenuInfo->iItem == NO_SELECTED_ITEM)
755 return NO_SELECTED_ITEM;
756
757 if (MenuGetAllRosMenuItemInfo(MenuInfo->Self, &MenuItems) <= 0)
758 return NO_SELECTED_ITEM;
759
760 /* Find the start of the column */
761 for (i = MenuInfo->iItem;
762 0 != i && 0 == (MenuItems[i].fType & (MF_MENUBREAK | MF_MENUBARBREAK));
763 --i)
764 {
765 ; /* empty */
766 }
767
768 if (i == 0)
769 {
770 MenuCleanupAllRosMenuItemInfo(MenuItems);
771 return NO_SELECTED_ITEM;
772 }
773
774 for (--i; 0 != i; --i)
775 if (MenuItems[i].fType & (MF_MENUBREAK | MF_MENUBARBREAK))
776 break;
777
778 MenuCleanupAllRosMenuItemInfo(MenuItems);
779 TRACE("ret %d.\n", i );
780
781 return i;
782 }
783
784 /***********************************************************************
785 * MenuLoadBitmaps
786 *
787 * Load the arrow bitmap. We can't do this from MenuInit since user32
788 * can also be used (and thus initialized) from text-mode.
789 */
790 static void FASTCALL
791 MenuLoadBitmaps(VOID)
792 {
793 /* Load system buttons bitmaps */
794 if (NULL == BmpSysMenu)
795 {
796 BmpSysMenu = LoadBitmapW(0, MAKEINTRESOURCEW(OBM_CLOSE));
797 }
798 }
799 /////////// Make gpsi OBMI via callback //////////////
800 /***********************************************************************
801 * get_arrow_bitmap
802 */
803 HBITMAP get_arrow_bitmap(void)
804 {
805 static HBITMAP arrow_bitmap;
806
807 if (!arrow_bitmap) arrow_bitmap = LoadBitmapW(0, MAKEINTRESOURCEW(OBM_MNARROW));
808 return arrow_bitmap;
809 }
810
811 /***********************************************************************
812 * get_down_arrow_bitmap DFCS_MENUARROWDOWN
813 */
814 HBITMAP get_down_arrow_bitmap(void)
815 {
816 static HBITMAP arrow_bitmap;
817
818 if (!arrow_bitmap) arrow_bitmap = LoadBitmapW(0, MAKEINTRESOURCEW(OBM_DNARROW));
819 return arrow_bitmap;
820 }
821
822 /***********************************************************************
823 * get_down_arrow_inactive_bitmap DFCS_MENUARROWDOWN | DFCS_INACTIVE
824 */
825 HBITMAP get_down_arrow_inactive_bitmap(void)
826 {
827 static HBITMAP arrow_bitmap;
828
829 if (!arrow_bitmap) arrow_bitmap = LoadBitmapW(0, MAKEINTRESOURCEW(OBM_DNARROWI));
830 return arrow_bitmap;
831 }
832
833 /***********************************************************************
834 * get_up_arrow_bitmap DFCS_MENUARROWUP
835 */
836 HBITMAP get_up_arrow_bitmap(void)
837 {
838 static HBITMAP arrow_bitmap;
839
840 if (!arrow_bitmap) arrow_bitmap = LoadBitmapW(0, MAKEINTRESOURCEW(OBM_UPARROW));
841 return arrow_bitmap;
842 }
843
844 /***********************************************************************
845 * get_up_arrow_inactive_bitmap DFCS_MENUARROWUP | DFCS_INACTIVE
846 */
847 static HBITMAP get_up_arrow_inactive_bitmap(void)
848 {
849 static HBITMAP arrow_bitmap;
850
851 if (!arrow_bitmap) arrow_bitmap = LoadBitmapW(0, MAKEINTRESOURCEW(OBM_UPARROWI));
852 return arrow_bitmap;
853 }
854 ////////////////
855 /***********************************************************************
856 * MenuFindSubMenu
857 *
858 * Find a Sub menu. Return the position of the submenu, and modifies
859 * *hmenu in case it is found in another sub-menu.
860 * If the submenu cannot be found, NO_SELECTED_ITEM is returned.
861 */
862 static UINT FASTCALL MenuFindSubMenu(HMENU *hmenu, HMENU hSubTarget )
863 {
864 PMENU menu, pSubMenu;
865 HMENU hSubMenu;
866 UINT i;
867 PITEM item;
868
869 if (((*hmenu)==(HMENU)0xffff) ||(!(menu = MENU_GetMenu(*hmenu))))
870 return NO_SELECTED_ITEM;
871
872 item = menu->rgItems ? DesktopPtrToUser(menu->rgItems) : NULL;
873 for (i = 0; i < menu->cItems; i++, item = item->Next ? DesktopPtrToUser(item->Next) : NULL)//item++)
874 {
875 if (!item->spSubMenu)
876 continue;
877 else
878 {
879 pSubMenu = DesktopPtrToUser(item->spSubMenu);
880 hSubMenu = UserHMGetHandle(pSubMenu);
881 if (hSubMenu == hSubTarget)
882 {
883 return i;
884 }
885 else
886 {
887 HMENU hsubmenu = hSubMenu;
888 UINT pos = MenuFindSubMenu( &hsubmenu, hSubTarget );
889 if (pos != NO_SELECTED_ITEM)
890 {
891 *hmenu = hsubmenu;
892 return pos;
893 }
894 }
895 }
896 }
897 return NO_SELECTED_ITEM;
898 }
899
900 /***********************************************************************
901 * MENU_AdjustMenuItemRect
902 *
903 * Adjust menu item rectangle according to scrolling state.
904 */
905 static void
906 MENU_AdjustMenuItemRect(PROSMENUINFO menu, LPRECT rect)
907 {
908 if (menu->dwArrowsOn)
909 {
910 UINT arrow_bitmap_height;
911 BITMAP bmp;
912
913 GetObjectW(get_up_arrow_bitmap(), sizeof(bmp), &bmp);
914 arrow_bitmap_height = bmp.bmHeight;
915 rect->top += arrow_bitmap_height - menu->iTop;
916 rect->bottom += arrow_bitmap_height - menu->iTop;
917 }
918 }
919
920 /***********************************************************************
921 * MenuDrawPopupGlyph
922 *
923 * Draws popup magic glyphs (can be found in system menu).
924 */
925 static void FASTCALL
926 MenuDrawPopupGlyph(HDC dc, LPRECT r, INT_PTR popupMagic, BOOL inactive, BOOL hilite)
927 {
928 LOGFONTW lf;
929 HFONT hFont, hOldFont;
930 COLORREF clrsave;
931 INT bkmode;
932 TCHAR symbol;
933 switch (popupMagic)
934 {
935 case (INT_PTR) HBMMENU_POPUP_RESTORE:
936 symbol = '2';
937 break;
938 case (INT_PTR) HBMMENU_POPUP_MINIMIZE:
939 symbol = '0';
940 break;
941 case (INT_PTR) HBMMENU_POPUP_MAXIMIZE:
942 symbol = '1';
943 break;
944 case (INT_PTR) HBMMENU_POPUP_CLOSE:
945 symbol = 'r';
946 break;
947 default:
948 ERR("Invalid popup magic bitmap %d\n", (int)popupMagic);
949 return;
950 }
951 ZeroMemory(&lf, sizeof(LOGFONTW));
952 InflateRect(r, -2, -2);
953 lf.lfHeight = r->bottom - r->top;
954 lf.lfWidth = 0;
955 lf.lfWeight = FW_NORMAL;
956 lf.lfCharSet = DEFAULT_CHARSET;
957 lstrcpy(lf.lfFaceName, TEXT("Marlett"));
958 hFont = CreateFontIndirect(&lf);
959 /* save font and text color */
960 hOldFont = SelectObject(dc, hFont);
961 clrsave = GetTextColor(dc);
962 bkmode = GetBkMode(dc);
963 /* set color and drawing mode */
964 SetBkMode(dc, TRANSPARENT);
965 if (inactive)
966 {
967 /* draw shadow */
968 if (!hilite)
969 {
970 SetTextColor(dc, GetSysColor(COLOR_HIGHLIGHTTEXT));
971 TextOut(dc, r->left + 1, r->top + 1, &symbol, 1);
972 }
973 }
974 SetTextColor(dc, GetSysColor(inactive ? COLOR_GRAYTEXT : (hilite ? COLOR_HIGHLIGHTTEXT : COLOR_MENUTEXT)));
975 /* draw selected symbol */
976 TextOut(dc, r->left, r->top, &symbol, 1);
977 /* restore previous settings */
978 SetTextColor(dc, clrsave);
979 SelectObject(dc, hOldFont);
980 SetBkMode(dc, bkmode);
981 DeleteObject(hFont);
982 }
983
984 /***********************************************************************
985 * MenuFindItemByKey
986 *
987 * Find the menu item selected by a key press.
988 * Return item id, -1 if none, -2 if we should close the menu.
989 */
990 static UINT FASTCALL MenuFindItemByKey(HWND WndOwner, PROSMENUINFO MenuInfo,
991 WCHAR Key, BOOL ForceMenuChar)
992 {
993 ROSMENUINFO SysMenuInfo;
994 PROSMENUITEMINFO Items, ItemInfo;
995 LRESULT MenuChar;
996 UINT i;
997 WORD Flags = 0;
998
999 TRACE("\tlooking for '%c' (0x%02x) in [%p]\n", (char) Key, Key, MenuInfo);
1000
1001 if (NULL == MenuInfo || ! IsMenu(MenuInfo->Self))
1002 {
1003 if (MenuGetRosMenuInfo(&SysMenuInfo, GetSystemMenu(WndOwner, FALSE)))
1004 {
1005 MenuInfo = &SysMenuInfo;
1006 }
1007 else
1008 {
1009 MenuInfo = NULL;
1010 }
1011 }
1012
1013 if (NULL != MenuInfo)
1014 {
1015 if (MenuGetAllRosMenuItemInfo(MenuInfo->Self, &Items) <= 0)
1016 {
1017 return -1;
1018 }
1019 if ( !ForceMenuChar )
1020 {
1021 ItemInfo = Items;
1022 for (i = 0; i < MenuInfo->cItems; i++, ItemInfo++)
1023 {
1024 if ((ItemInfo->lpstr) && NULL != ItemInfo->dwTypeData)
1025 {
1026 WCHAR *p = (WCHAR *) ItemInfo->dwTypeData - 2;
1027 do
1028 {
1029 p = strchrW (p + 2, '&');
1030 }
1031 while (p != NULL && p [1] == '&');
1032 if (p && (toupperW(p[1]) == toupperW(Key))) return i;
1033 }
1034 }
1035 }
1036
1037 Flags |= MenuInfo->fFlags & MNF_POPUP ? MF_POPUP : 0;
1038 Flags |= MenuInfo->fFlags & MNF_SYSDESKMN ? MF_SYSMENU : 0;
1039
1040 MenuChar = SendMessageW(WndOwner, WM_MENUCHAR,
1041 MAKEWPARAM(Key, Flags), (LPARAM) MenuInfo->Self);
1042 if (HIWORD(MenuChar) == MNC_EXECUTE) return LOWORD(MenuChar);
1043 if (HIWORD(MenuChar) == MNC_CLOSE) return (UINT)(-2);
1044 }
1045 return (UINT)(-1);
1046 }
1047
1048 /***********************************************************************
1049 * MenuGetBitmapItemSize
1050 *
1051 * Get the size of a bitmap item.
1052 */
1053 static void FASTCALL MenuGetBitmapItemSize(PROSMENUITEMINFO lpitem, SIZE *size, HWND WndOwner)
1054 {
1055 BITMAP bm;
1056 HBITMAP bmp = lpitem->hbmpItem;
1057
1058 size->cx = size->cy = 0;
1059
1060 /* check if there is a magic menu item associated with this item */
1061 if (IS_MAGIC_BITMAP(bmp))
1062 {
1063 switch((INT_PTR) bmp)
1064 {
1065 case (INT_PTR)HBMMENU_CALLBACK:
1066 {
1067 MEASUREITEMSTRUCT measItem;
1068 measItem.CtlType = ODT_MENU;
1069 measItem.CtlID = 0;
1070 measItem.itemID = lpitem->wID;
1071 measItem.itemWidth = lpitem->Rect.right - lpitem->Rect.left;
1072 measItem.itemHeight = lpitem->Rect.bottom - lpitem->Rect.top;
1073 measItem.itemData = lpitem->dwItemData;
1074 SendMessageW( WndOwner, WM_MEASUREITEM, lpitem->wID, (LPARAM)&measItem);
1075 size->cx = measItem.itemWidth;
1076 size->cy = measItem.itemHeight;
1077 return;
1078 }
1079 break;
1080
1081 case (INT_PTR) HBMMENU_SYSTEM:
1082 if (0 != lpitem->dwItemData)
1083 {
1084 bmp = (HBITMAP) lpitem->dwItemData;
1085 break;
1086 }
1087 /* fall through */
1088 case (INT_PTR) HBMMENU_MBAR_RESTORE:
1089 case (INT_PTR) HBMMENU_MBAR_MINIMIZE:
1090 case (INT_PTR) HBMMENU_MBAR_CLOSE:
1091 case (INT_PTR) HBMMENU_MBAR_MINIMIZE_D:
1092 case (INT_PTR) HBMMENU_MBAR_CLOSE_D:
1093 case (INT_PTR) HBMMENU_POPUP_CLOSE:
1094 case (INT_PTR) HBMMENU_POPUP_RESTORE:
1095 case (INT_PTR) HBMMENU_POPUP_MAXIMIZE:
1096 case (INT_PTR) HBMMENU_POPUP_MINIMIZE:
1097 /* FIXME: Why we need to subtract these magic values? */
1098 /* to make them smaller than the menu bar? */
1099 size->cx = GetSystemMetrics(SM_CXSIZE) - 2;
1100 size->cy = GetSystemMetrics(SM_CYSIZE) - 4;
1101 return;
1102 }
1103 }
1104
1105 if (GetObjectW(bmp, sizeof(BITMAP), &bm))
1106 {
1107 size->cx = bm.bmWidth;
1108 size->cy = bm.bmHeight;
1109 }
1110 }
1111
1112 /***********************************************************************
1113 * MenuDrawBitmapItem
1114 *
1115 * Draw a bitmap item.
1116 */
1117 static void FASTCALL MenuDrawBitmapItem(HDC hdc, PROSMENUITEMINFO lpitem, const RECT *rect,
1118 PROSMENUINFO MenuInfo, HWND WndOwner, UINT odaction, BOOL MenuBar)
1119 {
1120 BITMAP bm;
1121 DWORD rop;
1122 HDC hdcMem;
1123 HBITMAP bmp;
1124 int w = rect->right - rect->left;
1125 int h = rect->bottom - rect->top;
1126 int bmp_xoffset = 0;
1127 int left, top;
1128 HBITMAP hbmToDraw = lpitem->hbmpItem;
1129 bmp = hbmToDraw;
1130
1131 /* Check if there is a magic menu item associated with this item */
1132 if (IS_MAGIC_BITMAP(hbmToDraw))
1133 {
1134 UINT flags = 0;
1135 RECT r;
1136
1137 r = *rect;
1138 switch ((INT_PTR)hbmToDraw)
1139 {
1140 case (INT_PTR)HBMMENU_SYSTEM:
1141 if (lpitem->dwTypeData)
1142 {
1143 bmp = (HBITMAP)lpitem->dwTypeData;
1144 if (!GetObjectW( bmp, sizeof(bm), &bm )) return;
1145 }
1146 else
1147 {
1148 if (!BmpSysMenu) BmpSysMenu = LoadBitmapW(0, MAKEINTRESOURCEW(OBM_CLOSE));
1149 bmp = BmpSysMenu;
1150 if (! GetObjectW(bmp, sizeof(bm), &bm)) return;
1151 /* only use right half of the bitmap */
1152 bmp_xoffset = bm.bmWidth / 2;
1153 bm.bmWidth -= bmp_xoffset;
1154 }
1155 goto got_bitmap;
1156 case (INT_PTR)HBMMENU_MBAR_RESTORE:
1157 flags = DFCS_CAPTIONRESTORE;
1158 break;
1159 case (INT_PTR)HBMMENU_MBAR_MINIMIZE:
1160 r.right += 1;
1161 flags = DFCS_CAPTIONMIN;
1162 break;
1163 case (INT_PTR)HBMMENU_MBAR_MINIMIZE_D:
1164 r.right += 1;
1165 flags = DFCS_CAPTIONMIN | DFCS_INACTIVE;
1166 break;
1167 case (INT_PTR)HBMMENU_MBAR_CLOSE:
1168 flags = DFCS_CAPTIONCLOSE;
1169 break;
1170 case (INT_PTR)HBMMENU_MBAR_CLOSE_D:
1171 flags = DFCS_CAPTIONCLOSE | DFCS_INACTIVE;
1172 break;
1173 case (INT_PTR)HBMMENU_CALLBACK:
1174 {
1175 DRAWITEMSTRUCT drawItem;
1176 POINT origorg;
1177 drawItem.CtlType = ODT_MENU;
1178 drawItem.CtlID = 0;
1179 drawItem.itemID = lpitem->wID;
1180 drawItem.itemAction = odaction;
1181 drawItem.itemState = (lpitem->fState & MF_CHECKED)?ODS_CHECKED:0;
1182 drawItem.itemState |= (lpitem->fState & MF_DEFAULT)?ODS_DEFAULT:0;
1183 drawItem.itemState |= (lpitem->fState & MF_DISABLED)?ODS_DISABLED:0;
1184 drawItem.itemState |= (lpitem->fState & MF_GRAYED)?ODS_GRAYED|ODS_DISABLED:0;
1185 drawItem.itemState |= (lpitem->fState & MF_HILITE)?ODS_SELECTED:0;
1186 //drawItem.itemState |= (!(MenuInfo->fFlags & MNF_UNDERLINE))?ODS_NOACCEL:0;
1187 //drawItem.itemState |= (MenuInfo->fFlags & MNF_INACTIVE)?ODS_INACTIVE:0;
1188 drawItem.hwndItem = (HWND)MenuInfo->Self;
1189 drawItem.hDC = hdc;
1190 drawItem.rcItem = *rect;
1191 drawItem.itemData = lpitem->dwItemData;
1192 /* some applications make this assumption on the DC's origin */
1193 SetViewportOrgEx( hdc, lpitem->Rect.left, lpitem->Rect.top, &origorg);
1194 OffsetRect( &drawItem.rcItem, - lpitem->Rect.left, - lpitem->Rect.top);
1195 SendMessageW( WndOwner, WM_DRAWITEM, 0, (LPARAM)&drawItem);
1196 SetViewportOrgEx( hdc, origorg.x, origorg.y, NULL);
1197 return;
1198 }
1199 break;
1200
1201 case (INT_PTR) HBMMENU_POPUP_CLOSE:
1202 case (INT_PTR) HBMMENU_POPUP_RESTORE:
1203 case (INT_PTR) HBMMENU_POPUP_MAXIMIZE:
1204 case (INT_PTR) HBMMENU_POPUP_MINIMIZE:
1205 MenuDrawPopupGlyph(hdc, &r, (INT_PTR)hbmToDraw, lpitem->fState & MF_GRAYED, lpitem->fState & MF_HILITE);
1206 return;
1207 }
1208 InflateRect(&r, -1, -1);
1209 if (0 != (lpitem->fState & MF_HILITE))
1210 {
1211 flags |= DFCS_PUSHED;
1212 }
1213 DrawFrameControl(hdc, &r, DFC_CAPTION, flags);
1214 return;
1215 }
1216
1217 if (!bmp || !GetObjectW( bmp, sizeof(bm), &bm )) return;
1218
1219 got_bitmap:
1220 hdcMem = CreateCompatibleDC( hdc );
1221 SelectObject( hdcMem, bmp );
1222
1223 /* handle fontsize > bitmap_height */
1224 top = (h>bm.bmHeight) ? rect->top+(h-bm.bmHeight)/2 : rect->top;
1225 left=rect->left;
1226 rop=((lpitem->fState & MF_HILITE) && !IS_MAGIC_BITMAP(hbmToDraw)) ? NOTSRCCOPY : SRCCOPY;
1227 if ((lpitem->fState & MF_HILITE) && lpitem->hbmpItem)
1228 SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
1229 BitBlt( hdc, left, top, w, h, hdcMem, bmp_xoffset, 0, rop );
1230 DeleteDC( hdcMem );
1231 }
1232
1233 /***********************************************************************
1234 * MenuCalcItemSize
1235 *
1236 * Calculate the size of the menu item and store it in lpitem->rect.
1237 */
1238 static void FASTCALL MenuCalcItemSize( HDC hdc, PROSMENUITEMINFO lpitem, PROSMENUINFO MenuInfo, HWND hwndOwner,
1239 INT orgX, INT orgY, BOOL menuBar, BOOL textandbmp)
1240 {
1241 WCHAR *p;
1242 UINT check_bitmap_width = GetSystemMetrics( SM_CXMENUCHECK );
1243 UINT arrow_bitmap_width;
1244 BITMAP bm;
1245 INT itemheight = 0;
1246
1247 TRACE("dc=%x owner=%x (%d,%d)\n", hdc, hwndOwner, orgX, orgY);
1248
1249 GetObjectW( get_arrow_bitmap(), sizeof(bm), &bm );
1250 arrow_bitmap_width = bm.bmWidth;
1251
1252 MenuCharSize.cx = GdiGetCharDimensions( hdc, NULL, &MenuCharSize.cy );
1253
1254 SetRect( &lpitem->Rect, orgX, orgY, orgX, orgY );
1255
1256 if (lpitem->fType & MF_OWNERDRAW)
1257 {
1258 MEASUREITEMSTRUCT mis;
1259 mis.CtlType = ODT_MENU;
1260 mis.CtlID = 0;
1261 mis.itemID = lpitem->wID;
1262 mis.itemData = lpitem->dwItemData;
1263 mis.itemHeight = HIWORD( GetDialogBaseUnits());
1264 mis.itemWidth = 0;
1265 SendMessageW( hwndOwner, WM_MEASUREITEM, 0, (LPARAM)&mis );
1266 /* Tests reveal that Windows ( Win95 thru WinXP) adds twice the average
1267 * width of a menufont character to the width of an owner-drawn menu.
1268 */
1269 lpitem->Rect.right += mis.itemWidth + 2 * MenuCharSize.cx;
1270 if (menuBar) {
1271 /* under at least win95 you seem to be given a standard
1272 height for the menu and the height value is ignored */
1273 lpitem->Rect.bottom += GetSystemMetrics(SM_CYMENUSIZE);
1274 } else
1275 lpitem->Rect.bottom += mis.itemHeight;
1276 // Or this,
1277 //Item->cxBmp = mis.itemWidth;
1278 //Item->cyBmp = mis.itemHeight;
1279 TRACE("id=%04lx size=%dx%d\n",
1280 lpitem->wID, lpitem->Rect.right-lpitem->Rect.left,
1281 lpitem->Rect.bottom-lpitem->Rect.top);
1282 return;
1283 }
1284
1285 if (lpitem->fType & MF_SEPARATOR)
1286 {
1287 lpitem->Rect.bottom += GetSystemMetrics( SM_CYMENUSIZE)/2;//SEPARATOR_HEIGHT;
1288 if( !menuBar)
1289 lpitem->Rect.right += arrow_bitmap_width/*check_bitmap_width*/ + MenuCharSize.cx;
1290 return;
1291 }
1292
1293 lpitem->dxTab = 0;
1294
1295 if (lpitem->hbmpItem)
1296 {
1297 SIZE size;
1298
1299 if (!menuBar) {
1300 MenuGetBitmapItemSize(lpitem, &size, hwndOwner );
1301 /* Keep the size of the bitmap in callback mode to be able
1302 * to draw it correctly */
1303 lpitem->maxBmpSize = size;
1304 MenuInfo->cxTextAlign = max(MenuInfo->cxTextAlign, size.cx);
1305 MenuSetRosMenuInfo(MenuInfo);
1306 lpitem->Rect.right += size.cx + 2;
1307 itemheight = size.cy + 2;
1308
1309 if( !(MenuInfo->dwStyle & MNS_NOCHECK))
1310 lpitem->Rect.right += 2 * check_bitmap_width;
1311 lpitem->Rect.right += 4 + MenuCharSize.cx;
1312 lpitem->dxTab = lpitem->Rect.right;
1313 lpitem->Rect.right += arrow_bitmap_width;//check_bitmap_width;
1314 } else /* hbmpItem & MenuBar */ {
1315 MenuGetBitmapItemSize(lpitem, &size, hwndOwner );
1316 lpitem->Rect.right += size.cx;
1317 if( lpitem->lpstr) lpitem->Rect.right += 2;
1318 itemheight = size.cy;
1319
1320 /* Special case: Minimize button doesn't have a space behind it. */
1321 if (lpitem->hbmpItem == (HBITMAP)HBMMENU_MBAR_MINIMIZE ||
1322 lpitem->hbmpItem == (HBITMAP)HBMMENU_MBAR_MINIMIZE_D)
1323 lpitem->Rect.right -= 1;
1324 }
1325 }
1326 else if (!menuBar) {
1327 if( !(MenuInfo->dwStyle & MNS_NOCHECK))
1328 lpitem->Rect.right += check_bitmap_width;
1329 lpitem->Rect.right += 4 + MenuCharSize.cx;
1330 lpitem->dxTab = lpitem->Rect.right;
1331 lpitem->Rect.right += check_bitmap_width;
1332 }
1333
1334 /* it must be a text item - unless it's the system menu */
1335 if (!(lpitem->fType & MF_SYSMENU) && lpitem->lpstr) {
1336 HFONT hfontOld = NULL;
1337 RECT rc = lpitem->Rect;
1338 LONG txtheight, txtwidth;
1339
1340 if ( lpitem->fState & MFS_DEFAULT ) {
1341 hfontOld = SelectObject( hdc, hMenuFontBold );
1342 }
1343 if (menuBar) {
1344 txtheight = DrawTextW( hdc, lpitem->dwTypeData, -1, &rc,
1345 DT_SINGLELINE|DT_CALCRECT);
1346 lpitem->Rect.right += rc.right - rc.left;
1347 itemheight = max( max( itemheight, txtheight),
1348 GetSystemMetrics( SM_CYMENU) - 1);
1349 lpitem->Rect.right += 2 * MenuCharSize.cx;
1350 } else {
1351 if ((p = strchrW( lpitem->dwTypeData, '\t' )) != NULL) {
1352 RECT tmprc = rc;
1353 LONG tmpheight;
1354 int n = (int)( p - lpitem->dwTypeData);
1355 /* Item contains a tab (only meaningful in popup menus) */
1356 /* get text size before the tab */
1357 txtheight = DrawTextW( hdc, lpitem->dwTypeData, n, &rc,
1358 DT_SINGLELINE|DT_CALCRECT);
1359 txtwidth = rc.right - rc.left;
1360 p += 1; /* advance past the Tab */
1361 /* get text size after the tab */
1362 tmpheight = DrawTextW( hdc, p, -1, &tmprc,
1363 DT_SINGLELINE|DT_CALCRECT);
1364 lpitem->dxTab += txtwidth;
1365 txtheight = max( txtheight, tmpheight);
1366 txtwidth += MenuCharSize.cx + /* space for the tab */
1367 tmprc.right - tmprc.left; /* space for the short cut */
1368 } else {
1369 txtheight = DrawTextW( hdc, lpitem->dwTypeData, -1, &rc,
1370 DT_SINGLELINE|DT_CALCRECT);
1371 txtwidth = rc.right - rc.left;
1372 lpitem->dxTab += txtwidth;
1373 }
1374 lpitem->Rect.right += 2 + txtwidth;
1375 itemheight = max( itemheight,
1376 max( txtheight + 2, MenuCharSize.cy + 4));
1377 }
1378 if (hfontOld) SelectObject (hdc, hfontOld);
1379 } else if( menuBar) {
1380 itemheight = max( itemheight, GetSystemMetrics(SM_CYMENU)-1);
1381 }
1382 lpitem->Rect.bottom += itemheight;
1383 TRACE("(%ld,%ld)-(%ld,%ld)\n", lpitem->Rect.left, lpitem->Rect.top, lpitem->Rect.right, lpitem->Rect.bottom);
1384 }
1385
1386 /***********************************************************************
1387 * MENU_GetMaxPopupHeight
1388 */
1389 static UINT
1390 MENU_GetMaxPopupHeight(PROSMENUINFO lppop)
1391 {
1392 if (lppop->cyMax)
1393 return lppop->cyMax;
1394 return GetSystemMetrics(SM_CYSCREEN) - GetSystemMetrics(SM_CYBORDER);
1395 }
1396
1397 /***********************************************************************
1398 * MenuPopupMenuCalcSize
1399 *
1400 * Calculate the size of a popup menu.
1401 */
1402 static void FASTCALL MenuPopupMenuCalcSize(PROSMENUINFO MenuInfo, HWND WndOwner)
1403 {
1404 ROSMENUITEMINFO lpitem;
1405 HDC hdc;
1406 int start, i;
1407 int orgX, orgY, maxX, maxTab, maxTabWidth, maxHeight;
1408 BOOL textandbmp = FALSE;
1409
1410 MenuInfo->cxMenu = MenuInfo->cyMenu = 0;
1411 if (MenuInfo->cItems == 0)
1412 {
1413 MenuSetRosMenuInfo(MenuInfo);
1414 return;
1415 }
1416
1417 hdc = GetDC(NULL);
1418 SelectObject( hdc, hMenuFont );
1419
1420 start = 0;
1421 maxX = 2 + 1;
1422
1423 MenuInfo->cxTextAlign = 0;
1424
1425 MenuInitRosMenuItemInfo(&lpitem);
1426 while (start < MenuInfo->cItems)
1427 {
1428 orgX = maxX;
1429 orgY = 2;
1430
1431 maxTab = maxTabWidth = 0;
1432
1433 /* Parse items until column break or end of menu */
1434 for (i = start; i < MenuInfo->cItems; i++)
1435 {
1436 if (! MenuGetRosMenuItemInfo(MenuInfo->Self, i, &lpitem))
1437 {
1438 MenuCleanupRosMenuItemInfo(&lpitem);
1439 MenuSetRosMenuInfo(MenuInfo);
1440 return;
1441 }
1442 if (i != start &&
1443 (lpitem.fType & (MF_MENUBREAK | MF_MENUBARBREAK))) break;
1444
1445 if( lpitem.lpstr && lpitem.hbmpItem) textandbmp = TRUE;
1446
1447 MenuCalcItemSize(hdc, &lpitem, MenuInfo, WndOwner, orgX, orgY, FALSE, textandbmp);
1448 if (! MenuSetRosMenuItemInfo(MenuInfo->Self, i, &lpitem))
1449 {
1450 MenuCleanupRosMenuItemInfo(&lpitem);
1451 MenuSetRosMenuInfo(MenuInfo);
1452 return;
1453 }
1454 // Not sure here,, The patch from wine removes this.
1455 // if ((lpitem.fType & MF_MENUBARBREAK) != 0)
1456 // {
1457 // OrgX++;
1458 // }
1459 maxX = max(maxX, lpitem.Rect.right);
1460 orgY = lpitem.Rect.bottom;
1461 if ((lpitem.lpstr) && lpitem.dxTab )
1462 {
1463 maxTab = max( maxTab, lpitem.dxTab );
1464 maxTabWidth = max(maxTabWidth, lpitem.Rect.right - lpitem.dxTab);
1465 }
1466 }
1467
1468 /* Finish the column (set all items to the largest width found) */
1469 maxX = max( maxX, maxTab + maxTabWidth );
1470 while (start < i)
1471 {
1472 if (MenuGetRosMenuItemInfo(MenuInfo->Self, start, &lpitem))
1473 {
1474 lpitem.Rect.right = maxX;
1475 if ((lpitem.lpstr) && 0 != lpitem.dxTab)
1476 {
1477 lpitem.dxTab = maxTab;
1478 }
1479 MenuSetRosMenuItemInfo(MenuInfo->Self, start, &lpitem);
1480 }
1481 start++;
1482 }
1483 MenuInfo->cyMenu = max(MenuInfo->cyMenu, orgY);
1484 }
1485
1486 MenuInfo->cxMenu = maxX;
1487 /* if none of the items have both text and bitmap then
1488 * the text and bitmaps are all aligned on the left. If there is at
1489 * least one item with both text and bitmap then bitmaps are
1490 * on the left and texts left aligned with the right hand side
1491 * of the bitmaps */
1492 if( !textandbmp) MenuInfo->cxTextAlign = 0;
1493
1494 /* space for 3d border */
1495 MenuInfo->cyMenu += MENU_BOTTOM_MARGIN;
1496 MenuInfo->cxMenu += 2;
1497
1498 /* Adjust popup height if it exceeds maximum */
1499 maxHeight = MENU_GetMaxPopupHeight(MenuInfo);
1500 MenuInfo->iMaxTop = MenuInfo->cyMenu - MENU_TOP_MARGIN;
1501 if (MenuInfo->cyMenu >= maxHeight)
1502 {
1503 MenuInfo->cyMenu = maxHeight;
1504 MenuInfo->dwArrowsOn = 1;
1505 }
1506 else
1507 {
1508 MenuInfo->dwArrowsOn = 0;
1509 }
1510
1511 MenuCleanupRosMenuItemInfo(&lpitem);
1512 MenuSetRosMenuInfo(MenuInfo);
1513 ReleaseDC( 0, hdc );
1514 }
1515
1516 /***********************************************************************
1517 * MenuMenuBarCalcSize
1518 *
1519 * FIXME: Word 6 implements its own MDI and its own 'close window' bitmap
1520 * height is off by 1 pixel which causes lengthy window relocations when
1521 * active document window is maximized/restored.
1522 *
1523 * Calculate the size of the menu bar.
1524 */
1525 static void FASTCALL MenuMenuBarCalcSize( HDC hdc, LPRECT lprect,
1526 PROSMENUINFO MenuInfo, HWND hwndOwner )
1527 {
1528 ROSMENUITEMINFO ItemInfo;
1529 int start, i, orgX, orgY, maxY, helpPos;
1530
1531 if ((lprect == NULL) || (MenuInfo == NULL)) return;
1532 if (MenuInfo->cItems == 0) return;
1533 TRACE("left=%ld top=%ld right=%ld bottom=%ld\n", lprect->left, lprect->top, lprect->right, lprect->bottom);
1534 MenuInfo->cxMenu = lprect->right - lprect->left;
1535 MenuInfo->cyMenu = 0;
1536 maxY = lprect->top + 1;
1537 start = 0;
1538 helpPos = -1;
1539
1540 MenuInfo->cxTextAlign = 0;
1541
1542 MenuInitRosMenuItemInfo(&ItemInfo);
1543 while (start < MenuInfo->cItems)
1544 {
1545 if (! MenuGetRosMenuItemInfo(MenuInfo->Self, start, &ItemInfo))
1546 {
1547 MenuCleanupRosMenuItemInfo(&ItemInfo);
1548 return;
1549 }
1550 orgX = lprect->left;
1551 orgY = maxY;
1552
1553 /* Parse items until line break or end of menu */
1554 for (i = start; i < MenuInfo->cItems; i++)
1555 {
1556 if ((helpPos == -1) && (ItemInfo.fType & MF_RIGHTJUSTIFY)) helpPos = i;
1557 if ((i != start) &&
1558 (ItemInfo.fType & (MF_MENUBREAK | MF_MENUBARBREAK))) break;
1559
1560 TRACE("calling MENU_CalcItemSize org=(%d, %d)\n", orgX, orgY);
1561 MenuCalcItemSize(hdc, &ItemInfo, MenuInfo, hwndOwner, orgX, orgY, TRUE, FALSE);
1562 if (! MenuSetRosMenuItemInfo(MenuInfo->Self, i, &ItemInfo))
1563 {
1564 MenuCleanupRosMenuItemInfo(&ItemInfo);
1565 return;
1566 }
1567
1568 if (ItemInfo.Rect.right > lprect->right)
1569 {
1570 if (i != start) break;
1571 else ItemInfo.Rect.right = lprect->right;
1572 }
1573 maxY = max( maxY, ItemInfo.Rect.bottom );
1574 orgX = ItemInfo.Rect.right;
1575 if (i + 1 < MenuInfo->cItems)
1576 {
1577 if (! MenuGetRosMenuItemInfo(MenuInfo->Self, i + 1, &ItemInfo))
1578 {
1579 MenuCleanupRosMenuItemInfo(&ItemInfo);
1580 return;
1581 }
1582 }
1583 }
1584
1585 /* FIXME: Is this really needed? */ /*NO! it is not needed, why make the
1586 HBMMENU_MBAR_CLOSE, MINIMIZE & RESTORE, look the same size as the menu bar! */
1587 #if 0
1588 /* Finish the line (set all items to the largest height found) */
1589 while (start < i)
1590 {
1591 if (MenuGetRosMenuItemInfo(MenuInfo->Self, start, &ItemInfo))
1592 {
1593 ItemInfo.Rect.bottom = maxY;
1594 MenuSetRosMenuItemInfo(MenuInfo->Self, start, &ItemInfo);
1595 }
1596 start++;
1597 }
1598 #else
1599 start = i; /* This works! */
1600 #endif
1601 }
1602
1603 lprect->bottom = maxY;
1604 MenuInfo->cyMenu = lprect->bottom - lprect->top;
1605 MenuSetRosMenuInfo(MenuInfo);
1606
1607 if (helpPos != -1)
1608 {
1609 /* Flush right all items between the MF_RIGHTJUSTIFY and */
1610 /* the last item (if several lines, only move the last line) */
1611 if (! MenuGetRosMenuItemInfo(MenuInfo->Self, MenuInfo->cItems - 1, &ItemInfo))
1612 {
1613 MenuCleanupRosMenuItemInfo(&ItemInfo);
1614 return;
1615 }
1616 orgY = ItemInfo.Rect.top;
1617 orgX = lprect->right;
1618 for (i = MenuInfo->cItems - 1; helpPos <= i; i--)
1619 {
1620 if (i < helpPos)
1621 {
1622 break; /* done */
1623 }
1624 if (ItemInfo.Rect.top != orgY)
1625 {
1626 break; /* Other line */
1627 }
1628 if (orgX <= ItemInfo.Rect.right)
1629 {
1630 break; /* Too far right already */
1631 }
1632 ItemInfo.Rect.left += orgX - ItemInfo.Rect.right;
1633 ItemInfo.Rect.right = orgX;
1634 orgX = ItemInfo.Rect.left;
1635 MenuSetRosMenuItemInfo(MenuInfo->Self, i, &ItemInfo);
1636 if (helpPos + 1 <= i &&
1637 ! MenuGetRosMenuItemInfo(MenuInfo->Self, i - 1, &ItemInfo))
1638 {
1639 MenuCleanupRosMenuItemInfo(&ItemInfo);
1640 return;
1641 }
1642 }
1643 }
1644
1645 MenuCleanupRosMenuItemInfo(&ItemInfo);
1646 }
1647
1648 /***********************************************************************
1649 * MENU_DrawScrollArrows
1650 *
1651 * Draw scroll arrows.
1652 */
1653 static void
1654 MENU_DrawScrollArrows(PROSMENUINFO lppop, HDC hdc)
1655 {
1656 HDC hdcMem = CreateCompatibleDC(hdc);
1657 HBITMAP hOrigBitmap;
1658 UINT arrow_bitmap_width, arrow_bitmap_height;
1659 BITMAP bmp;
1660 RECT rect;
1661
1662 GetObjectW(get_down_arrow_bitmap(), sizeof(bmp), &bmp);
1663 arrow_bitmap_width = bmp.bmWidth;
1664 arrow_bitmap_height = bmp.bmHeight;
1665
1666
1667 if (lppop->iTop)
1668 hOrigBitmap = SelectObject(hdcMem, get_up_arrow_bitmap());
1669 else
1670 hOrigBitmap = SelectObject(hdcMem, get_up_arrow_inactive_bitmap());
1671 rect.left = 0;
1672 rect.top = 0;
1673 rect.right = lppop->cxMenu;
1674 rect.bottom = arrow_bitmap_height;
1675 FillRect(hdc, &rect, GetSysColorBrush(COLOR_MENU));
1676 BitBlt(hdc, (lppop->cxMenu - arrow_bitmap_width) / 2, 0,
1677 arrow_bitmap_width, arrow_bitmap_height, hdcMem, 0, 0, SRCCOPY);
1678 rect.top = lppop->cyMenu - arrow_bitmap_height;
1679 rect.bottom = lppop->cyMenu;
1680 FillRect(hdc, &rect, GetSysColorBrush(COLOR_MENU));
1681 if (lppop->iTop < lppop->iMaxTop - (MENU_GetMaxPopupHeight(lppop) - 2 * arrow_bitmap_height))
1682 SelectObject(hdcMem, get_down_arrow_bitmap());
1683 else
1684 SelectObject(hdcMem, get_down_arrow_inactive_bitmap());
1685 BitBlt(hdc, (lppop->cxMenu - arrow_bitmap_width) / 2,
1686 lppop->cyMenu - arrow_bitmap_height,
1687 arrow_bitmap_width, arrow_bitmap_height, hdcMem, 0, 0, SRCCOPY);
1688 SelectObject(hdcMem, hOrigBitmap);
1689 DeleteDC(hdcMem);
1690 }
1691
1692
1693 /***********************************************************************
1694 * MenuDrawMenuItem
1695 *
1696 * Draw a single menu item.
1697 */
1698 static void FASTCALL MenuDrawMenuItem(HWND hWnd, PROSMENUINFO MenuInfo, HWND WndOwner, HDC hdc,
1699 PROSMENUITEMINFO lpitem, UINT Height, BOOL menuBar, UINT odaction)
1700 {
1701 RECT rect;
1702 PWCHAR Text;
1703 BOOL flat_menu = FALSE;
1704 int bkgnd;
1705 PWND Wnd = ValidateHwnd(hWnd);
1706
1707 if (!Wnd)
1708 return;
1709
1710 if (lpitem->fType & MF_SYSMENU)
1711 {
1712 if ( (Wnd->style & WS_MINIMIZE))
1713 {
1714 UserGetInsideRectNC(Wnd, &rect);
1715 UserDrawSysMenuButton(hWnd, hdc, &rect, lpitem->fState & (MF_HILITE | MF_MOUSESELECT));
1716 }
1717 return;
1718 }
1719
1720 SystemParametersInfoW (SPI_GETFLATMENU, 0, &flat_menu, 0);
1721 bkgnd = (menuBar && flat_menu) ? COLOR_MENUBAR : COLOR_MENU;
1722
1723 /* Setup colors */
1724
1725 if (lpitem->fState & MF_HILITE)
1726 {
1727 if(menuBar && !flat_menu) {
1728 SetTextColor(hdc, GetSysColor(COLOR_MENUTEXT));
1729 SetBkColor(hdc, GetSysColor(COLOR_MENU));
1730 } else {
1731 if (lpitem->fState & MF_GRAYED)
1732 SetTextColor(hdc, GetSysColor(COLOR_GRAYTEXT));
1733 else
1734 SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
1735 SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
1736 }
1737 }
1738 else
1739 {
1740 if (lpitem->fState & MF_GRAYED)
1741 SetTextColor( hdc, GetSysColor( COLOR_GRAYTEXT ) );
1742 else
1743 SetTextColor( hdc, GetSysColor( COLOR_MENUTEXT ) );
1744 SetBkColor( hdc, GetSysColor( bkgnd ) );
1745 }
1746
1747 rect = lpitem->Rect;
1748 MENU_AdjustMenuItemRect(MenuInfo, &rect);
1749
1750 if (lpitem->fType & MF_OWNERDRAW)
1751 {
1752 /*
1753 ** Experimentation under Windows reveals that an owner-drawn
1754 ** menu is given the rectangle which includes the space it requested
1755 ** in its response to WM_MEASUREITEM _plus_ width for a checkmark
1756 ** and a popup-menu arrow. This is the value of lpitem->rect.
1757 ** Windows will leave all drawing to the application except for
1758 ** the popup-menu arrow. Windows always draws that itself, after
1759 ** the menu owner has finished drawing.
1760 */
1761 DRAWITEMSTRUCT dis;
1762
1763 dis.CtlType = ODT_MENU;
1764 dis.CtlID = 0;
1765 dis.itemID = lpitem->wID;
1766 dis.itemData = (DWORD)lpitem->dwItemData;
1767 dis.itemState = 0;
1768 if (lpitem->fState & MF_CHECKED) dis.itemState |= ODS_CHECKED;
1769 if (lpitem->fState & MF_DEFAULT) dis.itemState |= ODS_DEFAULT;
1770 if (lpitem->fState & MF_DISABLED) dis.itemState |= ODS_DISABLED;
1771 if (lpitem->fState & MF_GRAYED) dis.itemState |= ODS_GRAYED | ODS_DISABLED;
1772 if (lpitem->fState & MF_HILITE) dis.itemState |= ODS_SELECTED;
1773 //if (!(MenuInfo->fFlags & MNF_UNDERLINE)) dis.itemState |= ODS_NOACCEL;
1774 //if (MenuInfo->fFlags & MNF_INACTIVE) dis.itemState |= ODS_INACTIVE;
1775 dis.itemAction = odaction; /* ODA_DRAWENTIRE | ODA_SELECT | ODA_FOCUS; */
1776 dis.hwndItem = (HWND) MenuInfo->Self;
1777 dis.hDC = hdc;
1778 dis.rcItem = rect;
1779 TRACE("Ownerdraw: owner=%p itemID=%d, itemState=%d, itemAction=%d, "
1780 "hwndItem=%p, hdc=%p, rcItem={%ld,%ld,%ld,%ld}\n", hWnd,
1781 dis.itemID, dis.itemState, dis.itemAction, dis.hwndItem,
1782 dis.hDC, dis.rcItem.left, dis.rcItem.top, dis.rcItem.right,
1783 dis.rcItem.bottom);
1784 SendMessageW(WndOwner, WM_DRAWITEM, 0, (LPARAM) &dis);
1785 /* Draw the popup-menu arrow */
1786 if (lpitem->hSubMenu)
1787 {
1788 RECT rectTemp;
1789 CopyRect(&rectTemp, &rect);
1790 rectTemp.left = rectTemp.right - GetSystemMetrics(SM_CXMENUCHECK);
1791 DrawFrameControl(hdc, &rectTemp, DFC_MENU, DFCS_MENUARROW);
1792 }
1793 return;
1794 }
1795
1796 if (menuBar && (lpitem->fType & MF_SEPARATOR)) return;
1797
1798 if (lpitem->fState & MF_HILITE)
1799 {
1800 if (flat_menu)
1801 {
1802 InflateRect (&rect, -1, -1);
1803 FillRect(hdc, &rect, GetSysColorBrush(COLOR_MENUHILIGHT));
1804 InflateRect (&rect, 1, 1);
1805 FrameRect(hdc, &rect, GetSysColorBrush(COLOR_HIGHLIGHT));
1806 }
1807 else
1808 {
1809 if(menuBar)
1810 DrawEdge(hdc, &rect, BDR_SUNKENOUTER, BF_RECT);
1811 else
1812 FillRect(hdc, &rect, GetSysColorBrush(COLOR_HIGHLIGHT));
1813 }
1814 }
1815 else
1816 FillRect( hdc, &rect, GetSysColorBrush(bkgnd) );
1817
1818 SetBkMode( hdc, TRANSPARENT );
1819
1820 /* vertical separator */
1821 if (!menuBar && (lpitem->fType & MF_MENUBARBREAK))
1822 {
1823 HPEN oldPen;
1824 RECT rc = rect;
1825
1826 rc.left -= 3;
1827 rc.top = 3;
1828 rc.bottom = Height - 3;
1829 if (flat_menu)
1830 {
1831 oldPen = SelectObject( hdc, GetStockObject(DC_PEN) );
1832 SetDCPenColor(hdc, GetSysColor(COLOR_BTNSHADOW));
1833 MoveToEx( hdc, rc.left, rc.top, NULL );
1834 LineTo( hdc, rc.left, rc.bottom );
1835 SelectObject( hdc, oldPen );
1836 }
1837 else
1838 DrawEdge (hdc, &rc, EDGE_ETCHED, BF_LEFT);
1839 }
1840
1841 /* horizontal separator */
1842 if (lpitem->fType & MF_SEPARATOR)
1843 {
1844 HPEN oldPen;
1845 RECT rc = rect;
1846
1847 rc.left++;
1848 rc.right--;
1849 rc.top += SEPARATOR_HEIGHT / 2;
1850 if (flat_menu)
1851 {
1852 oldPen = SelectObject( hdc, GetStockObject(DC_PEN) );
1853 SetDCPenColor( hdc, GetSysColor(COLOR_BTNSHADOW));
1854 MoveToEx( hdc, rc.left, rc.top, NULL );
1855 LineTo( hdc, rc.right, rc.top );
1856 SelectObject( hdc, oldPen );
1857 }
1858 else
1859 DrawEdge (hdc, &rc, EDGE_ETCHED, BF_TOP);
1860 return;
1861 }
1862
1863 #if 0
1864 /* helper lines for debugging */
1865 /* This is a very good test tool when hacking menus! (JT) 07/16/2006 */
1866 FrameRect(hdc, &rect, GetStockObject(BLACK_BRUSH));
1867 SelectObject(hdc, GetStockObject(DC_PEN));
1868 SetDCPenColor(hdc, GetSysColor(COLOR_WINDOWFRAME));
1869 MoveToEx(hdc, rect.left, (rect.top + rect.bottom) / 2, NULL);
1870 LineTo(hdc, rect.right, (rect.top + rect.bottom) / 2);
1871 #endif
1872
1873 if (!menuBar)
1874 {
1875 HBITMAP bm;
1876 INT y = rect.top + rect.bottom;
1877 RECT rc = rect;
1878 BOOL checked = FALSE;
1879 UINT check_bitmap_width = GetSystemMetrics( SM_CXMENUCHECK );
1880 UINT check_bitmap_height = GetSystemMetrics( SM_CYMENUCHECK );
1881 /* Draw the check mark
1882 *
1883 * FIXME:
1884 * Custom checkmark bitmaps are monochrome but not always 1bpp.
1885 */
1886 if( !(MenuInfo->dwStyle & MNS_NOCHECK)) {
1887 bm = (lpitem->fState & MF_CHECKED) ? lpitem->hbmpChecked :
1888 lpitem->hbmpUnchecked;
1889 if (bm) /* we have a custom bitmap */
1890 {
1891 HDC hdcMem = CreateCompatibleDC( hdc );
1892
1893 SelectObject( hdcMem, bm );
1894 BitBlt( hdc, rc.left, (y - check_bitmap_height) / 2,
1895 check_bitmap_width, check_bitmap_height,
1896 hdcMem, 0, 0, SRCCOPY );
1897 DeleteDC( hdcMem );
1898 checked = TRUE;
1899 }
1900 else if (lpitem->fState & MF_CHECKED) /* standard bitmaps */
1901 {
1902 RECT r;
1903 CopyRect(&r, &rect);
1904 r.right = r.left + GetSystemMetrics(SM_CXMENUCHECK);
1905 DrawFrameControl( hdc, &r, DFC_MENU,
1906 (lpitem->fType & MFT_RADIOCHECK) ?
1907 DFCS_MENUBULLET : DFCS_MENUCHECK);
1908 checked = TRUE;
1909 }
1910 }
1911 if ( lpitem->hbmpItem )
1912 {
1913 RECT bmpRect;
1914 CopyRect(&bmpRect, &rect);
1915 if (!(MenuInfo->dwStyle & MNS_CHECKORBMP) && !(MenuInfo->dwStyle & MNS_NOCHECK))
1916 bmpRect.left += check_bitmap_width + 2;
1917 if (!(checked && (MenuInfo->dwStyle & MNS_CHECKORBMP)))
1918 {
1919 bmpRect.right = bmpRect.left + lpitem->maxBmpSize.cx;
1920 MenuDrawBitmapItem(hdc, lpitem, &bmpRect, MenuInfo, WndOwner, odaction, menuBar);
1921 }
1922 }
1923 /* Draw the popup-menu arrow */
1924 if (lpitem->hSubMenu)
1925 {
1926 RECT rectTemp;
1927 CopyRect(&rectTemp, &rect);
1928 rectTemp.left = rectTemp.right - GetSystemMetrics(SM_CXMENUCHECK);
1929 DrawFrameControl(hdc, &rectTemp, DFC_MENU, DFCS_MENUARROW);
1930 }
1931 rect.left += 4;
1932 if( !(MenuInfo->dwStyle & MNS_NOCHECK))
1933 rect.left += check_bitmap_width;
1934 rect.right -= check_bitmap_width;
1935 }
1936 else if( lpitem->hbmpItem)
1937 { /* Draw the bitmap */
1938 MenuDrawBitmapItem(hdc, lpitem, &rect, MenuInfo, WndOwner, odaction, menuBar);
1939 }
1940
1941 /* process text if present */
1942 if (lpitem->lpstr)
1943 {
1944 register int i = 0;
1945 HFONT hfontOld = 0;
1946
1947 UINT uFormat = menuBar ?
1948 DT_CENTER | DT_VCENTER | DT_SINGLELINE :
1949 DT_LEFT | DT_VCENTER | DT_SINGLELINE;
1950
1951 if((MenuInfo->dwStyle & MNS_CHECKORBMP))
1952 rect.left += max(0, MenuInfo->cxTextAlign - GetSystemMetrics(SM_CXMENUCHECK));
1953 else
1954 rect.left += MenuInfo->cxTextAlign;
1955
1956 if ( lpitem->fState & MFS_DEFAULT )
1957 {
1958 hfontOld = SelectObject(hdc, hMenuFontBold);
1959 }
1960
1961 if (menuBar) {
1962 rect.left += MENU_BAR_ITEMS_SPACE / 2;
1963 rect.right -= MENU_BAR_ITEMS_SPACE / 2;
1964 }
1965
1966 Text = (PWCHAR) lpitem->dwTypeData;
1967 if(Text)
1968 {
1969 for (i = 0; L'\0' != Text[i]; i++)
1970 if (Text[i] == L'\t' || Text[i] == L'\b')
1971 break;
1972 }
1973
1974 if(lpitem->fState & MF_GRAYED)
1975 {
1976 if (!(lpitem->fState & MF_HILITE) )
1977 {
1978 ++rect.left; ++rect.top; ++rect.right; ++rect.bottom;
1979 SetTextColor(hdc, RGB(0xff, 0xff, 0xff));
1980 DrawTextW( hdc, Text, i, &rect, uFormat );
1981 --rect.left; --rect.top; --rect.right; --rect.bottom;
1982 }
1983 SetTextColor(hdc, RGB(0x80, 0x80, 0x80));
1984 }
1985
1986 DrawTextW( hdc, Text, i, &rect, uFormat);
1987
1988 /* paint the shortcut text */
1989 if (!menuBar && L'\0' != Text[i]) /* There's a tab or flush-right char */
1990 {
1991 if (L'\t' == Text[i])
1992 {
1993 rect.left = lpitem->dxTab;
1994 uFormat = DT_LEFT | DT_VCENTER | DT_SINGLELINE;
1995 }
1996 else
1997 {
1998 rect.right = lpitem->dxTab;
1999 uFormat = DT_RIGHT | DT_VCENTER | DT_SINGLELINE;
2000 }
2001
2002 if (lpitem->fState & MF_GRAYED)
2003 {
2004 if (!(lpitem->fState & MF_HILITE) )
2005 {
2006 ++rect.left; ++rect.top; ++rect.right; ++rect.bottom;
2007 SetTextColor(hdc, RGB(0xff, 0xff, 0xff));
2008 DrawTextW( hdc, Text + i + 1, -1, &rect, uFormat);
2009 --rect.left; --rect.top; --rect.right; --rect.bottom;
2010 }
2011 SetTextColor(hdc, RGB(0x80, 0x80, 0x80));
2012 }
2013 DrawTextW( hdc, Text + i + 1, -1, &rect, uFormat );
2014 }
2015
2016 if (hfontOld)
2017 SelectObject (hdc, hfontOld);
2018 }
2019 }
2020
2021 /***********************************************************************
2022 * MenuDrawPopupMenu
2023 *
2024 * Paint a popup menu.
2025 */
2026 static void FASTCALL MenuDrawPopupMenu(HWND hwnd, HDC hdc, HMENU hmenu )
2027 {
2028 HBRUSH hPrevBrush = 0;
2029 RECT rect;
2030
2031 TRACE("wnd=%p dc=%p menu=%p\n", hwnd, hdc, hmenu);
2032
2033 GetClientRect( hwnd, &rect );
2034
2035 if((hPrevBrush = SelectObject( hdc, GetSysColorBrush(COLOR_MENU) ))
2036 && (SelectObject( hdc, hMenuFont)))
2037 {
2038 HPEN hPrevPen;
2039
2040 Rectangle( hdc, rect.left, rect.top, rect.right, rect.bottom );
2041
2042 hPrevPen = SelectObject( hdc, GetStockObject( NULL_PEN ) );
2043 if ( hPrevPen )
2044 {
2045 BOOL flat_menu = FALSE;
2046 ROSMENUINFO MenuInfo;
2047 ROSMENUITEMINFO ItemInfo;
2048
2049 SystemParametersInfoW (SPI_GETFLATMENU, 0, &flat_menu, 0);
2050 if (flat_menu)
2051 FrameRect(hdc, &rect, GetSysColorBrush(COLOR_BTNSHADOW));
2052 else
2053 DrawEdge (hdc, &rect, EDGE_RAISED, BF_RECT);
2054
2055 /* draw menu items */
2056 if (MenuGetRosMenuInfo(&MenuInfo, hmenu) && MenuInfo.cItems)
2057 {
2058 UINT u;
2059 MenuInitRosMenuItemInfo(&ItemInfo);
2060
2061 for (u = 0; u < MenuInfo.cItems; u++)
2062 {
2063 if (MenuGetRosMenuItemInfo(MenuInfo.Self, u, &ItemInfo))
2064 {
2065 HWND WndOwner = MenuInfo.spwndNotify ? MenuInfo.spwndNotify->head.h : NULL;
2066 MenuDrawMenuItem(hwnd, &MenuInfo, WndOwner, hdc, &ItemInfo,
2067 MenuInfo.cyMenu, FALSE, ODA_DRAWENTIRE);
2068 }
2069 }
2070
2071 /* draw scroll arrows */
2072 if (MenuInfo.dwArrowsOn)
2073 MENU_DrawScrollArrows(&MenuInfo, hdc);
2074
2075 MenuSetRosMenuInfo(&MenuInfo);
2076 MenuCleanupRosMenuItemInfo(&ItemInfo);
2077 }
2078 } else
2079 {
2080 SelectObject( hdc, hPrevBrush );
2081 }
2082 }
2083 }
2084
2085 /***********************************************************************
2086 * MenuDrawMenuBar
2087 *
2088 * Paint a menu bar. Returns the height of the menu bar.
2089 * called from [windows/nonclient.c]
2090 */
2091 UINT MenuDrawMenuBar( HDC hDC, LPRECT lprect, HWND hwnd,
2092 BOOL suppress_draw)
2093 {
2094 ROSMENUINFO lppop;
2095 HFONT hfontOld = 0;
2096 HMENU hMenu = GetMenu(hwnd);
2097
2098 if (! MenuGetRosMenuInfo(&lppop, hMenu) || lprect == NULL)
2099 {
2100 return GetSystemMetrics(SM_CYMENU);
2101 }
2102
2103 if (suppress_draw)
2104 {
2105 hfontOld = SelectObject(hDC, hMenuFont);
2106
2107 MenuMenuBarCalcSize(hDC, lprect, &lppop, hwnd);
2108
2109 lprect->bottom = lprect->top + lppop.cyMenu;
2110
2111 if (hfontOld) SelectObject( hDC, hfontOld);
2112 return lppop.cyMenu;
2113 }
2114 else
2115 return DrawMenuBarTemp(hwnd, hDC, lprect, hMenu, NULL);
2116 }
2117
2118
2119 /***********************************************************************
2120 * MenuShowPopup
2121 *
2122 * Display a popup menu.
2123 */
2124 static BOOL FASTCALL MenuShowPopup(HWND hwndOwner, HMENU hmenu, UINT id, UINT flags,
2125 INT x, INT y, INT xanchor, INT yanchor )
2126 {
2127 ROSMENUINFO MenuInfo;
2128 ROSMENUITEMINFO ItemInfo;
2129 UINT width, height;
2130 POINT pt;
2131 HMONITOR monitor;
2132 MONITORINFO info;
2133 DWORD ex_style = 0;
2134
2135 TRACE("owner=%p hmenu=%p id=0x%04x x=0x%04x y=0x%04x xa=0x%04x ya=0x%04x\n",
2136 hwndOwner, hmenu, id, x, y, xanchor, yanchor);
2137
2138 if (! MenuGetRosMenuInfo(&MenuInfo, hmenu)) return FALSE;
2139 if (MenuInfo.iItem != NO_SELECTED_ITEM)
2140 {
2141 MenuInitRosMenuItemInfo(&ItemInfo);
2142 if (MenuGetRosMenuItemInfo(MenuInfo.Self, MenuInfo.iItem, &ItemInfo))
2143 {
2144 ItemInfo.fMask |= MIIM_STATE;
2145 ItemInfo.fState &= ~(MF_HILITE|MF_MOUSESELECT);
2146 MenuSetRosMenuItemInfo(MenuInfo.Self, MenuInfo.iItem, &ItemInfo);
2147 }
2148 MenuCleanupRosMenuItemInfo(&ItemInfo);
2149 MenuInfo.iItem = NO_SELECTED_ITEM;
2150 }
2151
2152 /* store the owner for DrawItem */
2153 if (!IsWindow(hwndOwner))
2154 {
2155 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2156 return FALSE;
2157 }
2158 MenuInfo.spwndNotify = ValidateHwndNoErr(hwndOwner);
2159 MenuSetRosMenuInfo(&MenuInfo);
2160
2161 MenuPopupMenuCalcSize(&MenuInfo, hwndOwner);
2162
2163 /* adjust popup menu pos so that it fits within the desktop */
2164
2165 width = MenuInfo.cxMenu + GetSystemMetrics(SM_CXBORDER);
2166 height = MenuInfo.cyMenu + GetSystemMetrics(SM_CYBORDER);
2167
2168 /* FIXME: should use item rect */
2169 pt.x = x;
2170 pt.y = y;
2171 monitor = MonitorFromPoint( pt, MONITOR_DEFAULTTONEAREST );
2172 info.cbSize = sizeof(info);
2173 GetMonitorInfoW( monitor, &info );
2174
2175 if (flags & TPM_LAYOUTRTL)
2176 {
2177 ex_style = WS_EX_LAYOUTRTL;
2178 flags ^= TPM_RIGHTALIGN;
2179 }
2180 if( flags & TPM_RIGHTALIGN ) x -= width;
2181 if( flags & TPM_CENTERALIGN ) x -= width / 2;
2182
2183 if( flags & TPM_BOTTOMALIGN ) y -= height;
2184 if( flags & TPM_VCENTERALIGN ) y -= height / 2;
2185
2186 if( x + width > info.rcMonitor.right)
2187 {
2188 if( xanchor && x >= width - xanchor )
2189 x -= width - xanchor;
2190
2191 if( x + width > info.rcMonitor.right)
2192 x = info.rcMonitor.right - width;
2193 }
2194 if( x < info.rcMonitor.left ) x = info.rcMonitor.left;
2195
2196 if( y + height > info.rcMonitor.bottom)
2197 {
2198 if( yanchor && y >= height + yanchor )
2199 y -= height + yanchor;
2200
2201 if( y + height > info.rcMonitor.bottom)
2202 y = info.rcMonitor.bottom - height;
2203 }
2204 if( y < info.rcMonitor.top ) y = info.rcMonitor.top;
2205
2206 /* NOTE: In Windows, top menu popup is not owned. */
2207 MenuInfo.Wnd = CreateWindowExW( ex_style, WC_MENU, NULL,
2208 WS_POPUP, x, y, width, height,
2209 hwndOwner, 0, (HINSTANCE) GetWindowLongPtrW(hwndOwner, GWLP_HINSTANCE),
2210 (LPVOID) MenuInfo.Self);
2211 if ( !MenuInfo.Wnd || ! MenuSetRosMenuInfo(&MenuInfo)) return FALSE;
2212 if (!top_popup) {
2213 top_popup = MenuInfo.Wnd;
2214 top_popup_hmenu = hmenu;
2215 }
2216
2217 IntNotifyWinEvent(EVENT_SYSTEM_MENUPOPUPSTART, MenuInfo.Wnd, OBJID_CLIENT, CHILDID_SELF, 0);
2218
2219 /* Display the window */
2220
2221 SetWindowPos( MenuInfo.Wnd, HWND_TOPMOST, 0, 0, 0, 0,
2222 SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
2223 UpdateWindow( MenuInfo.Wnd );
2224 return TRUE;
2225 }
2226
2227 /***********************************************************************
2228 * MENU_EnsureMenuItemVisible
2229 */
2230 void
2231 MENU_EnsureMenuItemVisible(PROSMENUINFO lppop, PROSMENUITEMINFO item, HDC hdc)
2232 {
2233 if (lppop->dwArrowsOn)
2234 {
2235 //ITEM *item = &lppop->items[wIndex];
2236 UINT nMaxHeight = MENU_GetMaxPopupHeight(lppop);
2237 UINT nOldPos = lppop->iTop;
2238 RECT rc;
2239 UINT arrow_bitmap_height;
2240 BITMAP bmp;
2241
2242 GetClientRect(lppop->Wnd, &rc);
2243
2244 GetObjectW(get_down_arrow_bitmap(), sizeof(bmp), &bmp);
2245 arrow_bitmap_height = bmp.bmHeight;
2246
2247 rc.top += arrow_bitmap_height;
2248 rc.bottom -= arrow_bitmap_height + MENU_BOTTOM_MARGIN;
2249
2250 nMaxHeight -= GetSystemMetrics(SM_CYBORDER) + 2 * arrow_bitmap_height;
2251 if (item->Rect.bottom > lppop->iTop + nMaxHeight)
2252 {
2253 lppop->iTop = item->Rect.bottom - nMaxHeight;
2254 ScrollWindow(lppop->Wnd, 0, nOldPos - lppop->iTop, &rc, &rc);
2255 MENU_DrawScrollArrows(lppop, hdc);
2256 }
2257 else if (item->Rect.top - MENU_TOP_MARGIN < lppop->iTop)
2258 {
2259 lppop->iTop = item->Rect.top - MENU_TOP_MARGIN;
2260 ScrollWindow(lppop->Wnd, 0, nOldPos - lppop->iTop, &rc, &rc);
2261 MENU_DrawScrollArrows(lppop, hdc);
2262 }
2263 }
2264 }
2265
2266 /***********************************************************************
2267 * MenuSelectItem
2268 */
2269 static void FASTCALL MenuSelectItem(HWND hwndOwner, PROSMENUINFO hmenu, UINT wIndex,
2270 BOOL sendMenuSelect, HMENU topmenu)
2271 {
2272 ROSMENUITEMINFO ItemInfo;
2273 ROSMENUINFO TopMenuInfo;
2274 HDC hdc;
2275
2276 TRACE("owner=%p menu=%p index=0x%04x select=0x%04x\n", hwndOwner, hmenu, wIndex, sendMenuSelect);
2277
2278 if (!hmenu || !hmenu->cItems || !hmenu->Wnd) return;
2279 if (hmenu->iItem == wIndex) return;
2280 if (hmenu->fFlags & MNF_POPUP) hdc = GetDC(hmenu->Wnd);
2281 else hdc = GetDCEx(hmenu->Wnd, 0, DCX_CACHE | DCX_WINDOW);
2282 if (!top_popup) {
2283 top_popup = hmenu->Wnd;
2284 top_popup_hmenu = hmenu->Self;
2285 }
2286
2287 SelectObject( hdc, hMenuFont );
2288
2289 MenuInitRosMenuItemInfo(&ItemInfo);
2290
2291 /* Clear previous highlighted item */
2292 if (hmenu->iItem != NO_SELECTED_ITEM)
2293 {
2294 if (MenuGetRosMenuItemInfo(hmenu->Self, hmenu->iItem, &ItemInfo))
2295 {
2296 ItemInfo.fMask |= MIIM_STATE;
2297 ItemInfo.fState &= ~(MF_HILITE|MF_MOUSESELECT);
2298 MenuSetRosMenuItemInfo(hmenu->Self, hmenu->iItem, &ItemInfo);
2299 }
2300 //MENU_EnsureMenuItemVisible(hmenu, &ItemInfo, hdc);
2301 MenuDrawMenuItem(hmenu->Wnd, hmenu, hwndOwner, hdc, &ItemInfo,
2302 hmenu->cyMenu, !(hmenu->fFlags & MNF_POPUP),
2303 ODA_SELECT);
2304 }
2305
2306 /* Highlight new item (if any) */
2307 hmenu->iItem = wIndex;
2308 MenuSetRosMenuInfo(hmenu);
2309 if (hmenu->iItem != NO_SELECTED_ITEM)
2310 {
2311 if (MenuGetRosMenuItemInfo(hmenu->Self, hmenu->iItem, &ItemInfo))
2312 {
2313 if (!(ItemInfo.fType & MF_SEPARATOR))
2314 {
2315 ItemInfo.fMask |= MIIM_STATE;
2316 ItemInfo.fState |= MF_HILITE;
2317 MenuSetRosMenuItemInfo(hmenu->Self, hmenu->iItem, &ItemInfo);
2318 MenuDrawMenuItem(hmenu->Wnd, hmenu, hwndOwner, hdc,
2319 &ItemInfo, hmenu->cyMenu, !(hmenu->fFlags & MNF_POPUP),
2320 ODA_SELECT);
2321 }
2322 if (sendMenuSelect)
2323 {
2324 WPARAM wParam = MAKEWPARAM( ItemInfo.hSubMenu ? wIndex : ItemInfo.wID,
2325 ItemInfo.fType | ItemInfo.fState |
2326 (ItemInfo.hSubMenu ? MF_POPUP : 0) |
2327 (hmenu->fFlags & MNF_SYSDESKMN ? MF_SYSMENU : 0 ) );
2328
2329 SendMessageW(hwndOwner, WM_MENUSELECT, wParam, (LPARAM) hmenu->Self);
2330 }
2331 }
2332 }
2333 else if (sendMenuSelect)
2334 {
2335 if(topmenu)
2336 {
2337 int pos;
2338 pos = MenuFindSubMenu(&topmenu, hmenu->Self);
2339 if (pos != NO_SELECTED_ITEM)
2340 {
2341 if (MenuGetRosMenuInfo(&TopMenuInfo, topmenu)
2342 && MenuGetRosMenuItemInfo(topmenu, pos, &ItemInfo))
2343 {
2344 WPARAM wParam = MAKEWPARAM( Pos, ItemInfo.fType | ItemInfo.fState |
2345 (ItemInfo.hSubMenu ? MF_POPUP : 0) |
2346 (TopMenuInfo.fFlags & MNF_SYSDESKMN ? MF_SYSMENU : 0 ) );
2347
2348 SendMessageW(hwndOwner, WM_MENUSELECT, wParam, (LPARAM) topmenu);
2349 }
2350 }
2351 }
2352 }
2353 MenuCleanupRosMenuItemInfo(&ItemInfo);
2354 ReleaseDC(hmenu->Wnd, hdc);
2355 }
2356
2357 /***********************************************************************
2358 * MenuMoveSelection
2359 *
2360 * Moves currently selected item according to the Offset parameter.
2361 * If there is no selection then it should select the last item if
2362 * Offset is ITEM_PREV or the first item if Offset is ITEM_NEXT.
2363 */
2364 static void FASTCALL
2365 MenuMoveSelection(HWND WndOwner, PROSMENUINFO MenuInfo, INT Offset)
2366 {
2367 INT i;
2368 ROSMENUITEMINFO ItemInfo;
2369 INT OrigPos;
2370
2371 TRACE("hwnd=%x menu=%x off=0x%04x\n", WndOwner, MenuInfo, Offset);
2372
2373 /* Prevent looping */
2374 if (0 == MenuInfo->cItems || 0 == Offset)
2375 return;
2376 else if (Offset < -1)
2377 Offset = -1;
2378 else if (Offset > 1)
2379 Offset = 1;
2380
2381 MenuInitRosMenuItemInfo(&ItemInfo);
2382
2383 OrigPos = MenuInfo->iItem;
2384 if (OrigPos == NO_SELECTED_ITEM) /* NO_SELECTED_ITEM is not -1 ! */
2385 {
2386 OrigPos = 0;
2387 i = -1;
2388 }
2389 else
2390 {
2391 i = MenuInfo->iItem;
2392 }
2393
2394 do
2395 {
2396 /* Step */
2397 i += Offset;
2398 /* Clip and wrap around */
2399 if (i < 0)
2400 {
2401 i = MenuInfo->cItems - 1;
2402 }
2403 else if (i >= MenuInfo->cItems)
2404 {
2405 i = 0;
2406 }
2407 /* If this is a good candidate; */
2408 if (MenuGetRosMenuItemInfo(MenuInfo->Self, i, &ItemInfo) &&
2409 0 == (ItemInfo.fType & MF_SEPARATOR))
2410 {
2411 MenuSelectItem(WndOwner, MenuInfo, i, TRUE, NULL);
2412 MenuCleanupRosMenuItemInfo(&ItemInfo);
2413 return;
2414 }
2415 } while (i != OrigPos);
2416
2417 /* Not found */
2418 MenuCleanupRosMenuItemInfo(&ItemInfo);
2419 }
2420
2421 #if 0
2422 LRESULT WINAPI
2423 PopupMenuWndProcW(HWND Wnd, UINT Message, WPARAM wParam, LPARAM lParam)
2424 {
2425 #ifdef __REACTOS__ // Do this now, remove after Server side is fixed.
2426 PWND pWnd;
2427 PPOPUPMENU pPopupMenu;
2428
2429 pWnd = ValidateHwnd(Wnd);
2430 if (pWnd)
2431 {
2432 if (!pWnd->fnid)
2433 {
2434 if (Message != WM_NCCREATE)
2435 {
2436 return DefWindowProcW(Wnd, Message, wParam, lParam);
2437 }
2438 NtUserSetWindowFNID(Wnd, FNID_MENU);
2439 pPopupMenu = HeapAlloc( GetProcessHeap(), 0, sizeof(POPUPMENU) );
2440 pPopupMenu->spwndPopupMenu = pWnd;
2441 SetWindowLongPtrW(Wnd, 0, (LONG_PTR)pPopupMenu);
2442 }
2443 else
2444 {
2445 if (pWnd->fnid != FNID_MENU)
2446 {
2447 ERR("Wrong window class for Menu!\n");
2448 return 0;
2449 }
2450 pPopupMenu = ((PMENUWND)pWnd)->ppopupmenu;
2451 }
2452 }
2453 #endif
2454
2455 TRACE("hwnd=%x msg=0x%04x wp=0x%04lx lp=0x%08lx\n", Wnd, Message, wParam, lParam);
2456
2457 switch(Message)
2458 {
2459 case WM_CREATE:
2460 {
2461 CREATESTRUCTW *cs = (CREATESTRUCTW *) lParam;
2462 pPopupMenu->spmenu = ValidateHandle(cs->lpCreateParams, TYPE_MENU);
2463 return 0;
2464 }
2465
2466 case WM_MOUSEACTIVATE: /* We don't want to be activated */
2467 return MA_NOACTIVATE;
2468
2469 case WM_PAINT:
2470 {
2471 PAINTSTRUCT ps;
2472 BeginPaint(Wnd, &ps);
2473 MenuDrawPopupMenu(Wnd, ps.hdc, pPopupMenu->spmenu->head.h);
2474 EndPaint(Wnd, &ps);
2475 return 0;
2476 }
2477
2478 case WM_PRINTCLIENT:
2479 {
2480 MenuDrawPopupMenu( Wnd, (HDC)wParam, pPopupMenu->spmenu->head.h);
2481 return 0;
2482 }
2483
2484 case WM_ERASEBKGND:
2485 return 1;
2486
2487 case WM_DESTROY:
2488 /* zero out global pointer in case resident popup window was destroyed. */
2489 if (Wnd == top_popup)
2490 {
2491 top_popup = NULL;
2492 top_popup_hmenu = NULL;
2493 }
2494 break;
2495
2496 case WM_NCDESTROY:
2497 {
2498 HeapFree( GetProcessHeap(), 0, pPopupMenu );
2499 SetWindowLongPtrW(Wnd, 0, 0);
2500 NtUserSetWindowFNID(Wnd, FNID_DESTROY);
2501 break;
2502 }
2503
2504 case WM_SHOWWINDOW:
2505 if (0 != wParam)
2506 {
2507 if (!pPopupMenu || !pPopupMenu->spmenu)
2508 {
2509 OutputDebugStringA("no menu to display\n");
2510 }
2511 }
2512 /*else
2513 {
2514 pPopupMenu->spmenu = NULL; ///// WTF?
2515 }*/
2516 break;
2517
2518 case MM_SETMENUHANDLE:
2519 {
2520 PMENU pmenu = ValidateHandle((HMENU)wParam, TYPE_MENU);
2521 if (!pmenu)
2522 {
2523 ERR("Bad Menu Handle\n");
2524 break;
2525 }
2526 pPopupMenu->spmenu = pmenu;
2527 break;
2528 }
2529
2530 case MM_GETMENUHANDLE:
2531 case MN_GETHMENU:
2532 return (LRESULT)(pPopupMenu ? (pPopupMenu->spmenu ? pPopupMenu->spmenu->head.h : NULL) : NULL);
2533
2534 default:
2535 return DefWindowProcW(Wnd, Message, wParam, lParam);
2536 }
2537
2538 return 0;
2539 }
2540 #endif
2541
2542 LRESULT WINAPI
2543 PopupMenuWndProcW(HWND Wnd, UINT Message, WPARAM wParam, LPARAM lParam)
2544 {
2545 #ifdef __REACTOS__ // Do this now, remove after Server side is fixed.
2546 PWND pWnd;
2547
2548 pWnd = ValidateHwnd(Wnd);
2549 if (pWnd)
2550 {
2551 if (!pWnd->fnid)
2552 {
2553 if (Message != WM_NCCREATE)
2554 {
2555 return DefWindowProcW(Wnd, Message, wParam, lParam);
2556 }
2557 NtUserSetWindowFNID(Wnd, FNID_MENU);
2558 }
2559 else
2560 {
2561 if (pWnd->fnid != FNID_MENU)
2562 {
2563 ERR("Wrong window class for Menu!\n");
2564 return 0;
2565 }
2566 }
2567 }
2568 #endif
2569
2570 TRACE("hwnd=%x msg=0x%04x wp=0x%04lx lp=0x%08lx\n", Wnd, Message, wParam, lParam);
2571
2572 switch(Message)
2573 {
2574 case WM_CREATE:
2575 {
2576 CREATESTRUCTW *cs = (CREATESTRUCTW *) lParam;
2577 SetWindowLongPtrW(Wnd, 0, (LONG_PTR)cs->lpCreateParams);
2578 return 0;
2579 }
2580
2581 case WM_MOUSEACTIVATE: /* We don't want to be activated */
2582 return MA_NOACTIVATE;
2583
2584 case WM_PAINT:
2585 {
2586 PAINTSTRUCT ps;
2587 BeginPaint(Wnd, &ps);
2588 MenuDrawPopupMenu(Wnd, ps.hdc, (HMENU)GetWindowLongPtrW(Wnd, 0));
2589 EndPaint(Wnd, &ps);
2590 return 0;
2591 }
2592
2593 case WM_PRINTCLIENT:
2594 {
2595 MenuDrawPopupMenu( Wnd, (HDC)wParam,
2596 (HMENU)GetWindowLongPtrW( Wnd, 0 ) );
2597 return 0;
2598 }
2599
2600 case WM_ERASEBKGND:
2601 return 1;
2602
2603 case WM_DESTROY:
2604 /* zero out global pointer in case resident popup window was destroyed. */
2605 if (Wnd == top_popup)
2606 {
2607 top_popup = NULL;
2608 top_popup_hmenu = NULL;
2609 }
2610 break;
2611
2612 case WM_SHOWWINDOW:
2613 if (0 != wParam)
2614 {
2615 if (0 == GetWindowLongPtrW(Wnd, 0))
2616 {
2617 OutputDebugStringA("no menu to display\n");
2618 }
2619 }
2620 else
2621 {
2622 SetWindowLongPtrW(Wnd, 0, 0);
2623 }
2624 break;
2625
2626 case MM_SETMENUHANDLE:
2627 SetWindowLongPtrW(Wnd, 0, wParam);
2628 break;
2629
2630 case MM_GETMENUHANDLE:
2631 case MN_GETHMENU:
2632 return GetWindowLongPtrW(Wnd, 0);
2633
2634 default:
2635 return DefWindowProcW(Wnd, Message, wParam, lParam);
2636 }
2637
2638 return 0;
2639 }
2640
2641 //
2642 // This breaks some test results. Should handle A2U if called!
2643 //
2644 LRESULT WINAPI PopupMenuWndProcA(HWND Wnd, UINT Message, WPARAM wParam, LPARAM lParam)
2645 {
2646 PWND pWnd;
2647
2648 pWnd = ValidateHwnd(Wnd);
2649 if (pWnd && !pWnd->fnid && Message != WM_NCCREATE)
2650 {
2651 return DefWindowProcA(Wnd, Message, wParam, lParam);
2652 }
2653 TRACE("YES! hwnd=%x msg=0x%04x wp=0x%04lx lp=0x%08lx\n", Wnd, Message, wParam, lParam);
2654
2655 switch(Message)
2656 {
2657 case WM_NCCREATE:
2658 case WM_CREATE:
2659 case WM_MOUSEACTIVATE:
2660 case WM_PAINT:
2661 case WM_PRINTCLIENT:
2662 case WM_ERASEBKGND:
2663 case WM_DESTROY:
2664 case WM_NCDESTROY:
2665 case WM_SHOWWINDOW:
2666 case MM_SETMENUHANDLE:
2667 case MM_GETMENUHANDLE:
2668 case MN_GETHMENU:
2669 return PopupMenuWndProcW(Wnd, Message, wParam, lParam);
2670
2671 default:
2672 return DefWindowProcA(Wnd, Message, wParam, lParam);
2673 }
2674 return 0;
2675 }
2676
2677 /**********************************************************************
2678 * MENU_ParseResource
2679 *
2680 * Parse a standard menu resource and add items to the menu.
2681 * Return a pointer to the end of the resource.
2682 *
2683 * NOTE: flags is equivalent to the mtOption field
2684 */
2685 static LPCSTR MENU_ParseResource( LPCSTR res, HMENU hMenu)
2686 {
2687 WORD flags, id = 0;
2688 HMENU hSubMenu;
2689 LPCWSTR str;
2690 BOOL end = FALSE;
2691
2692 do
2693 {
2694 flags = GET_WORD(res);
2695
2696 /* remove MF_END flag before passing it to AppendMenu()! */
2697 end = (flags & MF_END);
2698 if(end) flags ^= MF_END;
2699
2700 res += sizeof(WORD);
2701 if(!(flags & MF_POPUP))
2702 {
2703 id = GET_WORD(res);
2704 res += sizeof(WORD);
2705 }
2706 str = (LPCWSTR)res;
2707 res += (strlenW(str) + 1) * sizeof(WCHAR);
2708
2709 if (flags & MF_POPUP)
2710 {
2711 hSubMenu = CreatePopupMenu();
2712 if(!hSubMenu) return NULL;
2713 if(!(res = MENU_ParseResource(res, hSubMenu))) return NULL;
2714 AppendMenuW(hMenu, flags, (UINT_PTR)hSubMenu, (LPCWSTR)str);
2715 }
2716 else /* Not a popup */
2717 {
2718 AppendMenuW(hMenu, flags, id, *(LPCWSTR)str ? (LPCWSTR)str : NULL);
2719 }
2720 } while(!end);
2721 return res;
2722 }
2723
2724
2725 /**********************************************************************
2726 * MENUEX_ParseResource
2727 *
2728 * Parse an extended menu resource and add items to the menu.
2729 * Return a pointer to the end of the resource.
2730 */
2731 static LPCSTR MENUEX_ParseResource(LPCSTR res, HMENU hMenu)
2732 {
2733 WORD resinfo;
2734 do
2735 {
2736 MENUITEMINFOW mii;
2737
2738 mii.cbSize = sizeof(mii);
2739 mii.fMask = MIIM_STATE | MIIM_ID | MIIM_TYPE;
2740 mii.fType = GET_DWORD(res);
2741 res += sizeof(DWORD);
2742 mii.fState = GET_DWORD(res);
2743 res += sizeof(DWORD);
2744 mii.wID = GET_DWORD(res);
2745 res += sizeof(DWORD);
2746 resinfo = GET_WORD(res);
2747 res += sizeof(WORD);
2748 /* Align the text on a word boundary. */
2749 res += (~((UINT_PTR)res - 1)) & 1;
2750 mii.dwTypeData = (LPWSTR)res;
2751 mii.cch = strlenW(mii.dwTypeData);
2752 res += (1 + strlenW(mii.dwTypeData)) * sizeof(WCHAR);
2753 /* Align the following fields on a dword boundary. */
2754 res += (~((UINT_PTR)res - 1)) & 3;
2755
2756 TRACE("Menu item: [%08x,%08x,%04x,%04x,%S]\n",
2757 mii.fType, mii.fState, mii.wID, resinfo, mii.dwTypeData);
2758
2759 if (resinfo & 1) /* Pop-up? */
2760 {
2761 /* DWORD helpid = GET_DWORD(res); FIXME: use this. */
2762 res += sizeof(DWORD);
2763 mii.hSubMenu = CreatePopupMenu();
2764 if (!mii.hSubMenu)
2765 {
2766 ERR("CreatePopupMenu failed\n");
2767 return NULL;
2768 }
2769
2770 if (!(res = MENUEX_ParseResource(res, mii.hSubMenu)))
2771 {
2772 ERR("MENUEX_ParseResource failed\n");
2773 DestroyMenu(mii.hSubMenu);
2774 return NULL;
2775 }
2776 mii.fMask |= MIIM_SUBMENU;
2777 }
2778 else if (!mii.dwTypeData[0] && !(mii.fType & MF_SEPARATOR))
2779 {
2780 mii.fType |= MF_SEPARATOR;
2781 }
2782 InsertMenuItemW(hMenu, -1, MF_BYPOSITION, &mii);
2783 } while (!(resinfo & MF_END));
2784 return res;
2785 }
2786
2787 NTSTATUS WINAPI
2788 User32LoadSysMenuTemplateForKernel(PVOID Arguments, ULONG ArgumentLength)
2789 {
2790 HMENU hmenu = LoadMenuW(User32Instance, L"SYSMENU");
2791 LRESULT Result = (LRESULT)hmenu;
2792 MENUINFO menuinfo = {0};
2793 MENUITEMINFOW info = {0};
2794
2795 // removing space for checkboxes from menu
2796 menuinfo.cbSize = sizeof(menuinfo);
2797 menuinfo.fMask = MIM_STYLE;
2798 GetMenuInfo(hmenu, &menuinfo);
2799 menuinfo.dwStyle |= MNS_CHECKORBMP; // test_menu_bmp_and_string MNS_CHECKORBMP
2800 SetMenuInfo(hmenu, &menuinfo);
2801
2802 // adding bitmaps to menu items
2803 info.cbSize = sizeof(info);
2804 info.fMask |= MIIM_BITMAP;
2805 info.hbmpItem = HBMMENU_POPUP_MINIMIZE;
2806 SetMenuItemInfoW(hmenu, SC_MINIMIZE, FALSE, &info);
2807 info.hbmpItem = HBMMENU_POPUP_RESTORE;
2808 SetMenuItemInfoW(hmenu, SC_RESTORE, FALSE, &info);
2809 info.hbmpItem = HBMMENU_POPUP_MAXIMIZE;
2810 SetMenuItemInfoW(hmenu, SC_MAXIMIZE, FALSE, &info);
2811 info.hbmpItem = HBMMENU_POPUP_CLOSE;
2812 SetMenuItemInfoW(hmenu, SC_CLOSE, FALSE, &info);
2813
2814 return(ZwCallbackReturn(&Result, sizeof(LRESULT), STATUS_SUCCESS));
2815 }
2816
2817
2818 BOOL
2819 MenuInit(VOID)
2820 {
2821 NONCLIENTMETRICSW ncm;
2822
2823 /* get the menu font */
2824 if(!hMenuFont || !hMenuFontBold)
2825 {
2826 ncm.cbSize = sizeof(ncm);
2827 if(!SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0))
2828 {
2829 ERR("MenuInit(): SystemParametersInfoW(SPI_GETNONCLIENTMETRICS) failed!\n");
2830 return FALSE;
2831 }
2832
2833 hMenuFont = CreateFontIndirectW(&ncm.lfMenuFont);
2834 if(hMenuFont == NULL)
2835 {
2836 ERR("MenuInit(): CreateFontIndirectW(hMenuFont) failed!\n");
2837 return FALSE;
2838 }
2839
2840 ncm.lfMenuFont.lfWeight = max(ncm.lfMenuFont.lfWeight + 300, 1000);
2841 hMenuFontBold = CreateFontIndirectW(&ncm.lfMenuFont);
2842 if(hMenuFontBold == NULL)
2843 {
2844 ERR("MenuInit(): CreateFontIndirectW(hMenuFontBold) failed!\n");
2845 DeleteObject(hMenuFont);
2846 hMenuFont = NULL;
2847 return FALSE;
2848 }
2849 }
2850
2851 return TRUE;
2852 }
2853
2854 VOID
2855 MenuCleanup(VOID)
2856 {
2857 if (hMenuFont)
2858 {
2859 DeleteObject(hMenuFont);
2860 hMenuFont = NULL;
2861 }
2862
2863 if (hMenuFontBold)
2864 {
2865 DeleteObject(hMenuFontBold);
2866 hMenuFontBold = NULL;
2867 }
2868 }
2869
2870 /***********************************************************************
2871 * DrawMenuBarTemp (USER32.@)
2872 *
2873 * UNDOCUMENTED !!
2874 *
2875 * called by W98SE desk.cpl Control Panel Applet
2876 *
2877 * Not 100% sure about the param names, but close.
2878 *
2879 * @implemented
2880 */
2881 DWORD WINAPI
2882 DrawMenuBarTemp(HWND Wnd, HDC DC, LPRECT Rect, HMENU Menu, HFONT Font)
2883 {
2884 ROSMENUINFO MenuInfo;
2885 ROSMENUITEMINFO ItemInfo;
2886 UINT i;
2887 HFONT FontOld = NULL;
2888 BOOL flat_menu = FALSE;
2889
2890 SystemParametersInfoW (SPI_GETFLATMENU, 0, &flat_menu, 0);
2891
2892 if (NULL == Menu)
2893 {
2894 Menu = GetMenu(Wnd);
2895 }
2896
2897 if (NULL == Font)
2898 {
2899 Font = hMenuFont;
2900 }
2901
2902 if (NULL == Rect || ! MenuGetRosMenuInfo(&MenuInfo, Menu))
2903 {
2904 return GetSystemMetrics(SM_CYMENU);
2905 }
2906
2907 TRACE("(%x, %x, %p, %x, %x)\n", Wnd, DC, Rect, Menu, Font);
2908
2909 FontOld = SelectObject(DC, Font);
2910
2911 if (0 == MenuInfo.cyMenu)
2912 {
2913 MenuMenuBarCalcSize(DC, Rect, &MenuInfo, Wnd);
2914 }
2915
2916 Rect->bottom = Rect->top + MenuInfo.cyMenu;
2917
2918 FillRect(DC, Rect, GetSysColorBrush(flat_menu ? COLOR_MENUBAR : COLOR_MENU));
2919
2920 SelectObject(DC, GetStockObject(DC_PEN));
2921 SetDCPenColor(DC, GetSysColor(COLOR_3DFACE));
2922 MoveToEx(DC, Rect->left, Rect->bottom - 1, NULL);
2923 LineTo(DC, Rect->right, Rect->bottom - 1);
2924
2925 if (0 == MenuInfo.cItems)
2926 {
2927 SelectObject(DC, FontOld);
2928 return GetSystemMetrics(SM_CYMENU);
2929 }
2930
2931 MenuInitRosMenuItemInfo(&ItemInfo);
2932 for (i = 0; i < MenuInfo.cItems; i++)
2933 {
2934 if (MenuGetRosMenuItemInfo(MenuInfo.Self, i, &ItemInfo))
2935 {
2936 MenuDrawMenuItem(Wnd, &MenuInfo, Wnd, DC, &ItemInfo,
2937 MenuInfo.cyMenu, TRUE, ODA_DRAWENTIRE);
2938 }
2939 }
2940 MenuCleanupRosMenuItemInfo(&ItemInfo);
2941
2942 SelectObject(DC, FontOld);
2943
2944 return MenuInfo.cyMenu;
2945 }
2946 #if 0
2947 static BOOL MENU_InitPopup( HWND hwndOwner, HMENU hmenu, UINT flags )
2948 {
2949 POPUPMENU *menu;
2950 DWORD ex_style = 0;
2951
2952 TRACE("owner=%p hmenu=%p\n", hwndOwner, hmenu);
2953
2954 if (!(menu = MENU_GetMenu( hmenu ))) return FALSE;
2955
2956 /* store the owner for DrawItem */
2957 if (!IsWindow( hwndOwner ))
2958 {
2959 SetLastError( ERROR_INVALID_WINDOW_HANDLE );
2960 return FALSE;
2961 }
2962 menu->hwndOwner = hwndOwner;
2963
2964 if (flags & TPM_LAYOUTRTL)
2965 ex_style = WS_EX_LAYOUTRTL;
2966
2967 /* NOTE: In Windows, top menu popup is not owned. */
2968 menu->hWnd = CreateWindowExW( ex_style, (LPCWSTR)POPUPMENU_CLASS_ATOM, NULL,
2969 WS_POPUP, 0, 0, 0, 0,
2970 hwndOwner, 0, (HINSTANCE)GetWindowLongPtrW(hwndOwner, GWLP_HINSTANCE),
2971 (LPVOID)hmenu );
2972 if( !menu->hWnd ) return FALSE;
2973 return TRUE;
2974 }
2975 #endif
2976 /***********************************************************************
2977 * MenuShowSubPopup
2978 *
2979 * Display the sub-menu of the selected item of this menu.
2980 * Return the handle of the submenu, or menu if no submenu to display.
2981 */
2982 static HMENU FASTCALL
2983 MenuShowSubPopup(HWND WndOwner, PROSMENUINFO MenuInfo, BOOL SelectFirst, UINT Flags)
2984 {
2985 extern void FASTCALL NcGetSysPopupPos(HWND Wnd, RECT *Rect);
2986 RECT Rect;
2987 ROSMENUITEMINFO ItemInfo;
2988 ROSMENUINFO SubMenuInfo;
2989 HDC Dc;
2990 HMENU Ret;
2991
2992 TRACE("owner=%x menu=%p 0x%04x\n", WndOwner, MenuInfo, SelectFirst);
2993
2994 if (NO_SELECTED_ITEM == MenuInfo->iItem)
2995 {
2996 return MenuInfo->Self;
2997 }
2998
2999 MenuInitRosMenuItemInfo(&ItemInfo);
3000 if (! MenuGetRosMenuItemInfo(MenuInfo->Self, MenuInfo->iItem, &ItemInfo))
3001 {
3002 MenuCleanupRosMenuItemInfo(&ItemInfo);
3003 return MenuInfo->Self;
3004 }
3005 if (0 == (ItemInfo.hSubMenu) || 0 != (ItemInfo.fState & (MF_GRAYED | MF_DISABLED)))
3006 {
3007 MenuCleanupRosMenuItemInfo(&ItemInfo);
3008 return MenuInfo->Self;
3009 }
3010
3011 /* message must be sent before using item,
3012 because nearly everything may be changed by the application ! */
3013
3014 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
3015 if (0 == (Flags & TPM_NONOTIFY))
3016 {
3017 SendMessageW(WndOwner, WM_INITMENUPOPUP, (WPARAM) ItemInfo.hSubMenu,
3018 MAKELPARAM(MenuInfo->iItem, IS_SYSTEM_MENU(MenuInfo)));
3019 }
3020
3021 if (! MenuGetRosMenuItemInfo(MenuInfo->Self, MenuInfo->iItem, &ItemInfo))
3022 {
3023 MenuCleanupRosMenuItemInfo(&ItemInfo);
3024 return MenuInfo->Self;
3025 }
3026 Rect = ItemInfo.Rect;
3027
3028 /* correct item if modified as a reaction to WM_INITMENUPOPUP message */
3029 if (0 == (ItemInfo.fState & MF_HILITE))
3030 {
3031 if (0 != (MenuInfo->fFlags & MNF_POPUP))
3032 {
3033 Dc = GetDC(MenuInfo->Wnd);
3034 }
3035 else
3036 {
3037 Dc = GetDCEx(MenuInfo->Wnd, 0, DCX_CACHE | DCX_WINDOW);
3038 }
3039
3040 SelectObject(Dc, hMenuFont);
3041 ItemInfo.fMask |= MIIM_STATE;
3042 ItemInfo.fState |= MF_HILITE;
3043 MenuSetRosMenuItemInfo(MenuInfo->Self, MenuInfo->iItem, &ItemInfo);
3044 MenuDrawMenuItem(MenuInfo->Wnd, MenuInfo, WndOwner, Dc, &ItemInfo, MenuInfo->cyMenu,
3045 !(MenuInfo->fFlags & MNF_POPUP), ODA_DRAWENTIRE);
3046 ReleaseDC(MenuInfo->Wnd, Dc);
3047 }
3048
3049 if (0 == ItemInfo.Rect.top && 0 == ItemInfo.Rect.left
3050 && 0 == ItemInfo.Rect.bottom && 0 == ItemInfo.Rect.right)
3051 {
3052 ItemInfo.Rect = Rect;
3053 }
3054
3055 ItemInfo.fMask |= MIIM_STATE;
3056 ItemInfo.fState |= MF_MOUSESELECT;
3057 MenuSetRosMenuItemInfo(MenuInfo->Self, MenuInfo->iItem, &ItemInfo);
3058
3059 if (IS_SYSTEM_MENU(MenuInfo))
3060 {
3061 ERR("Right click on window bar and Draw system menu!\n");
3062 MenuInitSysMenuPopup(ItemInfo.hSubMenu, GetWindowLongPtrW(MenuInfo->Wnd, GWL_STYLE),
3063 GetClassLongPtrW(MenuInfo->Wnd, GCL_STYLE), HTSYSMENU);
3064 if (Flags & TPM_LAYOUTRTL) Rect.left;
3065 NcGetSysPopupPos(MenuInfo->Wnd, &Rect);
3066 Rect.top = Rect.bottom;
3067 Rect.right = GetSystemMetrics(SM_CXSIZE);
3068 Rect.bottom = GetSystemMetrics(SM_CYSIZE);
3069 }
3070 else
3071 {
3072 GetWindowRect(MenuInfo->Wnd, &Rect);
3073 if (0 != (MenuInfo->fFlags & MNF_POPUP))
3074 {
3075 RECT rc = ItemInfo.Rect;
3076
3077 MENU_AdjustMenuItemRect(MenuInfo, &rc);
3078
3079 if(Flags & TPM_LAYOUTRTL)
3080 Rect.left += GetSystemMetrics(SM_CXBORDER);
3081 else
3082 Rect.left += ItemInfo.Rect.right- GetSystemMetrics(SM_CXBORDER);
3083 Rect.top += rc.top - MENU_TOP_MARGIN;//3;
3084 Rect.right = rc.left - rc.right + GetSystemMetrics(SM_CXBORDER);
3085 Rect.bottom = rc.top - rc.bottom - MENU_TOP_MARGIN - MENU_BOTTOM_MARGIN/*2*/
3086 - GetSystemMetrics(SM_CYBORDER);
3087 }
3088 else
3089 {
3090 if(Flags & TPM_LAYOUTRTL)
3091 Rect.left += Rect.right - ItemInfo.Rect.left;
3092 else
3093 Rect.left += ItemInfo.Rect.left;
3094 Rect.top += ItemInfo.Rect.bottom;
3095 Rect.right = ItemInfo.Rect.right - ItemInfo.Rect.left;
3096 Rect.bottom = ItemInfo.Rect.bottom - ItemInfo.Rect.top;
3097 }
3098 }
3099
3100 /* use default alignment for submenus */
3101 Flags &= ~(TPM_CENTERALIGN | TPM_RIGHTALIGN | TPM_VCENTERALIGN | TPM_BOTTOMALIGN);
3102
3103 //MENU_InitPopup( WndOwner, ItemInfo.hSubMenu, Flags );
3104
3105 MenuShowPopup(WndOwner, ItemInfo.hSubMenu, MenuInfo->iItem, Flags,
3106 Rect.left, Rect.top, Rect.right, Rect.bottom );
3107 if (SelectFirst && MenuGetRosMenuInfo(&SubMenuInfo, ItemInfo.hSubMenu))
3108 {
3109 MenuMoveSelection(WndOwner, &SubMenuInfo, ITEM_NEXT);
3110 }
3111
3112 Ret = ItemInfo.hSubMenu;
3113 MenuCleanupRosMenuItemInfo(&ItemInfo);
3114
3115 return Ret;
3116 }
3117
3118 /**********************************************************************
3119 * MENU_EndMenu
3120 *
3121 * Calls EndMenu() if the hwnd parameter belongs to the menu owner
3122 *
3123 * Does the (menu stuff) of the default window handling of WM_CANCELMODE
3124 */
3125 void MENU_EndMenu( HWND hwnd )
3126 {
3127 ROSMENUINFO MenuInfo;
3128 BOOL Ret = FALSE;
3129 if (top_popup_hmenu)
3130 Ret = MenuGetRosMenuInfo(&MenuInfo, top_popup_hmenu);
3131 if (Ret && hwnd == (MenuInfo.spwndNotify ? MenuInfo.spwndNotify->head.h : NULL)) EndMenu();
3132 }
3133
3134 /***********************************************************************
3135 * MenuHideSubPopups
3136 *
3137 * Hide the sub-popup menus of this menu.
3138 */
3139 static void FASTCALL
3140 MenuHideSubPopups(HWND WndOwner, PROSMENUINFO MenuInfo,
3141 BOOL SendMenuSelect, UINT wFlags)
3142 {
3143 ROSMENUINFO SubMenuInfo;
3144 ROSMENUITEMINFO ItemInfo;
3145
3146 TRACE("owner=%x menu=%x 0x%04x\n", WndOwner, MenuInfo, SendMenuSelect);
3147
3148 if (NULL != MenuInfo && NULL != top_popup && NO_SELECTED_ITEM != MenuInfo->iItem)
3149 {
3150 MenuInitRosMenuItemInfo(&ItemInfo);
3151 ItemInfo.fMask |= MIIM_FTYPE | MIIM_STATE;
3152 if (! MenuGetRosMenuItemInfo(MenuInfo->Self, MenuInfo->iItem, &ItemInfo)
3153 || 0 == (ItemInfo.hSubMenu)
3154 || 0 == (ItemInfo.fState & MF_MOUSESELECT))
3155 {
3156 MenuCleanupRosMenuItemInfo(&ItemInfo);
3157 return;
3158 }
3159 ItemInfo.fState &= ~MF_MOUSESELECT;
3160 ItemInfo.fMask |= MIIM_STATE;
3161 MenuSetRosMenuItemInfo(MenuInfo->Self, MenuInfo->iItem, &ItemInfo);
3162 if (MenuGetRosMenuInfo(&SubMenuInfo, ItemInfo.hSubMenu))
3163 {
3164 MenuHideSubPopups(WndOwner, &SubMenuInfo, FALSE, wFlags);
3165 MenuSelectItem(WndOwner, &SubMenuInfo, NO_SELECTED_ITEM, SendMenuSelect, NULL);
3166 DestroyWindow(SubMenuInfo.Wnd);
3167 SubMenuInfo.Wnd = NULL;
3168 MenuSetRosMenuInfo(&SubMenuInfo);
3169
3170 if (!(wFlags & TPM_NONOTIFY))
3171 SendMessageW( WndOwner, WM_UNINITMENUPOPUP, (WPARAM)ItemInfo.hSubMenu,
3172 MAKELPARAM(0, IS_SYSTEM_MENU(&SubMenuInfo)) );
3173 }
3174 }
3175 }
3176
3177 /***********************************************************************
3178 * MenuSwitchTracking
3179 *
3180 * Helper function for menu navigation routines.
3181 */
3182 static void FASTCALL
3183 MenuSwitchTracking(MTRACKER* Mt, PROSMENUINFO PtMenuInfo, UINT Index, UINT wFlags)
3184 {
3185 ROSMENUINFO TopMenuInfo;
3186
3187 TRACE("%x menu=%x 0x%04x\n", Mt, PtMenuInfo->Self, Index);
3188
3189 if (MenuGetRosMenuInfo(&TopMenuInfo, Mt->TopMenu) &&
3190 Mt->TopMenu != PtMenuInfo->Self &&
3191 0 == ((PtMenuInfo->fFlags | TopMenuInfo.fFlags) & MNF_POPUP))
3192 {
3193 /* both are top level menus (system and menu-bar) */
3194 MenuHideSubPopups(Mt->OwnerWnd, &TopMenuInfo, FALSE, wFlags);
3195 MenuSelectItem(Mt->OwnerWnd, &TopMenuInfo, NO_SELECTED_ITEM, FALSE, NULL);
3196 Mt->TopMenu = PtMenuInfo->Self;
3197 }
3198 else
3199 {
3200 MenuHideSubPopups(Mt->OwnerWnd, PtMenuInfo, FALSE, wFlags);
3201 }
3202
3203 MenuSelectItem(Mt->OwnerWnd, PtMenuInfo, Index, TRUE, NULL);
3204 }
3205
3206 /***********************************************************************
3207 * MenuExecFocusedItem
3208 *
3209 * Execute a menu item (for instance when user pressed Enter).
3210 * Return the wID of the executed item. Otherwise, -1 indicating
3211 * that no menu item was executed, -2 if a popup is shown;
3212 * Have to receive the flags for the TrackPopupMenu options to avoid
3213 * sending unwanted message.
3214 *
3215 */
3216 static INT FASTCALL
3217 MenuExecFocusedItem(MTRACKER *Mt, PROSMENUINFO MenuInfo, UINT Flags)
3218 {
3219 ROSMENUITEMINFO ItemInfo;
3220 UINT wID;
3221
3222 TRACE("%p menu=%p\n", Mt, MenuInfo);
3223
3224 if (0 == MenuInfo->cItems || NO_SELECTED_ITEM == MenuInfo->iItem)
3225 {
3226 return -1;
3227 }
3228
3229 MenuInitRosMenuItemInfo(&ItemInfo);
3230 if (! MenuGetRosMenuItemInfo(MenuInfo->Self, MenuInfo->iItem, &ItemInfo))
3231 {
3232 MenuCleanupRosMenuItemInfo(&ItemInfo);
3233 return -1;
3234 }
3235
3236 TRACE("%p %08x %p\n", MenuInfo, ItemInfo.wID, ItemInfo.hSubMenu);
3237
3238 if (0 == (ItemInfo.hSubMenu))
3239 {
3240 if (0 == (ItemInfo.fState & (MF_GRAYED | MF_DISABLED))
3241 && 0 == (ItemInfo.fType & MF_SEPARATOR))
3242 {
3243 /* If TPM_RETURNCMD is set you return the id, but
3244 do not send a message to the owner */
3245 if (0 == (Flags & TPM_RETURNCMD))
3246 {
3247 if (0 != (MenuInfo->fFlags & MNF_SYSDESKMN))
3248 {
3249 PostMessageW(Mt->OwnerWnd, WM_SYSCOMMAND, ItemInfo.wID,
3250 MAKELPARAM((SHORT) Mt->Pt.x, (SHORT) Mt->Pt.y));
3251 }
3252 else
3253 {
3254 ROSMENUINFO topmenuI;
3255 BOOL ret = MenuGetRosMenuInfo(&topmenuI, Mt->TopMenu);
3256 DWORD dwStyle = MenuInfo->dwStyle | (ret ? topmenuI.dwStyle : 0);
3257
3258 if (dwStyle & MNS_NOTIFYBYPOS)
3259 PostMessageW(Mt->OwnerWnd, WM_MENUCOMMAND, MenuInfo->iItem, (LPARAM)MenuInfo->Self);
3260 else
3261 PostMessageW(Mt->OwnerWnd, WM_COMMAND, ItemInfo.wID, 0);
3262 }
3263 }
3264 wID = ItemInfo.wID;
3265 MenuCleanupRosMenuItemInfo(&ItemInfo);
3266 return wID;
3267 }
3268 }
3269 else
3270 {
3271 Mt->CurrentMenu = MenuShowSubPopup(Mt->OwnerWnd, MenuInfo, TRUE, Flags);
3272 return -2;
3273 }
3274
3275 return -1;
3276 }
3277
3278 /***********************************************************************
3279 * MenuButtonDown
3280 *
3281 * Return TRUE if we can go on with menu tracking.
3282 */
3283 static BOOL FASTCALL
3284 MenuButtonDown(MTRACKER* Mt, HMENU PtMenu, UINT Flags)
3285 {
3286 int Index;
3287 ROSMENUINFO MenuInfo;
3288 ROSMENUITEMINFO Item;
3289
3290 TRACE("%x PtMenu=%p\n", Mt, PtMenu);
3291
3292 if (NULL != PtMenu)
3293 {
3294 if (! MenuGetRosMenuInfo(&MenuInfo, PtMenu))
3295 {
3296 return FALSE;
3297 }
3298 if (IS_SYSTEM_MENU(&MenuInfo))
3299 {
3300 Index = 0;
3301 }
3302 else
3303 {
3304 Index = NtUserMenuItemFromPoint(Mt->OwnerWnd, PtMenu, Mt->Pt.x, Mt->Pt.y);
3305 }
3306 MenuInitRosMenuItemInfo(&Item);
3307 if (NO_SELECTED_ITEM == Index || ! MenuGetRosMenuItemInfo(PtMenu, Index, &Item))
3308 {
3309 MenuCleanupRosMenuItemInfo(&Item);
3310 return FALSE;
3311 }
3312
3313 if (!(Item.fType & MF_SEPARATOR) &&
3314 !(Item.fState & (MFS_DISABLED | MFS_GRAYED)) )
3315 {
3316 if (MenuInfo.iItem != Index)
3317 {
3318 MenuSwitchTracking(Mt, &MenuInfo, Index, Flags);
3319 }
3320
3321 /* If the popup menu is not already "popped" */
3322 if (0 == (Item.fState & MF_MOUSESELECT))
3323 {
3324 Mt->CurrentMenu = MenuShowSubPopup(Mt->OwnerWnd, &MenuInfo, FALSE, Flags);
3325 }
3326 }
3327
3328 MenuCleanupRosMenuItemInfo(&Item);
3329
3330 return TRUE;
3331 }
3332
3333 /* else the click was on the menu bar, finish the tracking */
3334
3335 return FALSE;
3336 }
3337
3338 /***********************************************************************
3339 * MenuButtonUp
3340 *
3341 * Return the value of MenuExecFocusedItem if
3342 * the selected item was not a popup. Else open the popup.
3343 * A -1 return value indicates that we go on with menu tracking.
3344 *
3345 */
3346 static INT FASTCALL
3347 MenuButtonUp(MTRACKER *Mt, HMENU PtMenu, UINT Flags)
3348 {
3349 INT Id;
3350 ROSMENUINFO MenuInfo;
3351 ROSMENUITEMINFO ItemInfo;
3352
3353 TRACE("%p hmenu=%x\n", Mt, PtMenu);
3354
3355 if (NULL != PtMenu)
3356 {
3357 Id = 0;
3358 if (! MenuGetRosMenuInfo(&MenuInfo, PtMenu))
3359 {
3360 return -1;
3361 }
3362
3363 if (! IS_SYSTEM_MENU(&MenuInfo))
3364 {
3365 Id = NtUserMenuItemFromPoint(Mt->OwnerWnd, MenuInfo.Self, Mt->Pt.x, Mt->Pt.y);
3366 }
3367 MenuInitRosMenuItemInfo(&ItemInfo);
3368 if (0 <= Id && MenuGetRosMenuItemInfo(MenuInfo.Self, Id, &ItemInfo) &&
3369 MenuInfo.iItem == Id)
3370 {
3371 if (0 == (ItemInfo.hSubMenu))
3372 {
3373 INT ExecutedMenuId = MenuExecFocusedItem(Mt, &MenuInfo, Flags);
3374 MenuCleanupRosMenuItemInfo(&ItemInfo);
3375 return (ExecutedMenuId < 0) ? -1 : ExecutedMenuId;
3376 }
3377 MenuCleanupRosMenuItemInfo(&ItemInfo);
3378
3379 /* If we are dealing with the top-level menu */
3380 /* and this is a click on an already "popped" item: */
3381 /* Stop the menu tracking and close the opened submenus */
3382 if (Mt->TopMenu == MenuInfo.Self && MenuInfo.TimeToHide)
3383 {
3384 MenuCleanupRosMenuItemInfo(&ItemInfo);
3385 return 0;
3386 }
3387 }
3388 MenuCleanupRosMenuItemInfo(&ItemInfo);
3389 MenuInfo.TimeToHide = TRUE;
3390 MenuSetRosMenuInfo(&MenuInfo);
3391 }
3392
3393 return -1;
3394 }
3395
3396 /***********************************************************************
3397 * MenuPtMenu
3398 *
3399 * Walks menu chain trying to find a menu pt maps to.
3400 */
3401 static HMENU FASTCALL
3402 MenuPtMenu(HMENU Menu, POINT Pt)
3403 {
3404 extern LRESULT DefWndNCHitTest(HWND hWnd, POINT Point);
3405 ROSMENUINFO MenuInfo;
3406 ROSMENUITEMINFO ItemInfo;
3407 HMENU Ret = NULL;
3408 INT Ht;
3409
3410 if (! MenuGetRosMenuInfo(&MenuInfo, Menu))
3411 {
3412 return NULL;
3413 }
3414
3415 /* try subpopup first (if any) */
3416 if (NO_SELECTED_ITEM != MenuInfo.iItem)
3417 {
3418 MenuInitRosMenuItemInfo(&ItemInfo);
3419 if (MenuGetRosMenuItemInfo(MenuInfo.Self, MenuInfo.iItem, &ItemInfo) &&
3420 0 != (ItemInfo.hSubMenu) &&
3421 0 != (ItemInfo.fState & MF_MOUSESELECT))
3422 {
3423 Ret = MenuPtMenu(ItemInfo.hSubMenu, Pt);
3424 if (NULL != Ret)
3425 {
3426 MenuCleanupRosMenuItemInfo(&ItemInfo);
3427 return Ret;
3428 }
3429 }
3430 MenuCleanupRosMenuItemInfo(&ItemInfo);
3431 }
3432
3433 /* check the current window (avoiding WM_HITTEST) */
3434 Ht = DefWndNCHitTest(MenuInfo.Wnd, Pt);
3435 if (0 != (MenuInfo.fFlags & MNF_POPUP))
3436 {
3437 if (HTNOWHERE != Ht && HTERROR != Ht)
3438 {
3439 Ret = Menu;
3440 }
3441 }
3442 else if (HTSYSMENU == Ht)
3443 {
3444 Ret = NtUserGetSystemMenu(MenuInfo.Wnd, FALSE);
3445 }
3446 else if (HTMENU == Ht)
3447 {
3448 Ret = GetMenu(MenuInfo.Wnd);
3449 }
3450
3451 return Ret;
3452 }
3453
3454 /***********************************************************************
3455 * MenuMouseMove
3456 *
3457 * Return TRUE if we can go on with menu tracking.
3458 */
3459 static BOOL FASTCALL
3460 MenuMouseMove(MTRACKER *Mt, HMENU PtMenu, UINT Flags)
3461 {
3462 INT Index;
3463 ROSMENUINFO MenuInfo;
3464 ROSMENUITEMINFO ItemInfo;
3465
3466 if (NULL != PtMenu)
3467 {
3468 if (! MenuGetRosMenuInfo(&MenuInfo, PtMenu))
3469 {
3470 return TRUE;
3471 }
3472 if (IS_SYSTEM_MENU(&MenuInfo))
3473 {
3474 Index = 0;
3475 }
3476 else
3477 {
3478 Index = NtUserMenuItemFromPoint(Mt->OwnerWnd, PtMenu, Mt->Pt.x, Mt->Pt.y);
3479 }
3480 }
3481 else
3482 {
3483 Index = NO_SELECTED_ITEM;
3484 }
3485
3486 if (NO_SELECTED_ITEM == Index)
3487 {
3488 if (Mt->CurrentMenu == MenuInfo.Self ||
3489 MenuGetRosMenuInfo(&MenuInfo, Mt->CurrentMenu))
3490 {
3491 MenuSelectItem(Mt->OwnerWnd, &MenuInfo, NO_SELECTED_ITEM,
3492 TRUE, Mt->TopMenu);
3493 }
3494 }
3495 else if (MenuInfo.iItem != Index)
3496 {
3497 MenuInitRosMenuItemInfo(&ItemInfo);
3498 if (MenuGetRosMenuItemInfo(MenuInfo.Self, Index, &ItemInfo) &&
3499 !(ItemInfo.fType & MF_SEPARATOR))
3500 {
3501 MenuSwitchTracking(Mt, &MenuInfo, Index, Flags);
3502 if (!(ItemInfo.fState & (MFS_DISABLED | MFS_GRAYED)))
3503 Mt->CurrentMenu = MenuShowSubPopup(Mt->OwnerWnd, &MenuInfo, FALSE, Flags);
3504 }
3505 MenuCleanupRosMenuItemInfo(&ItemInfo);
3506 }
3507
3508 return TRUE;
3509 }
3510
3511 /***********************************************************************
3512 * MenuGetSubPopup
3513 *
3514 * Return the handle of the selected sub-popup menu (if any).
3515 */
3516 static HMENU FASTCALL
3517 MenuGetSubPopup(HMENU Menu)
3518 {
3519 ROSMENUINFO MenuInfo;
3520 ROSMENUITEMINFO ItemInfo;
3521
3522 if (! MenuGetRosMenuInfo(&MenuInfo, Menu)
3523 || NO_SELECTED_ITEM == MenuInfo.iItem)
3524 {
3525 return NULL;
3526 }
3527
3528 MenuInitRosMenuItemInfo(&ItemInfo);
3529 if (! MenuGetRosMenuItemInfo(MenuInfo.Self, MenuInfo.iItem, &ItemInfo))
3530 {
3531 MenuCleanupRosMenuItemInfo(&ItemInfo);
3532 return NULL;