2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS user32.dll
4 * FILE: user32/windows/menu.c
7 * PROGRAMMERS: Casper S. Hornstrup
11 /* INCLUDES ******************************************************************/
14 #include <wine/debug.h>
16 LRESULT
DefWndNCPaint(HWND hWnd
, HRGN hRgn
, BOOL Active
);
17 BOOL WINAPI
GdiValidateHandle(HGDIOBJ hobj
);
18 LRESULT
DefWndNCHitTest(HWND hWnd
, POINT Point
);
19 void FASTCALL
NcGetSysPopupPos(HWND Wnd
, RECT
*Rect
);
21 WINE_DEFAULT_DEBUG_CHANNEL(menu
);
23 /* internal popup menu window messages */
25 #define MM_SETMENUHANDLE (WM_USER + 0)
26 #define MM_GETMENUHANDLE (WM_USER + 1)
28 /* internal flags for menu tracking */
30 #define TF_ENDMENU 0x10000
31 #define TF_SUSPENDPOPUP 0x20000
32 #define TF_SKIPREMOVE 0x40000
37 /* Internal MenuTrackMenu() flags */
38 #define TPM_INTERNAL 0xF0000000
39 #define TPM_BUTTONDOWN 0x40000000 /* menu was clicked before tracking */
40 #define TPM_POPUPMENU 0x20000000 /* menu is a popup menu */
42 /* top and bottom margins for popup menus */
43 #define MENU_TOP_MARGIN 3
44 #define MENU_BOTTOM_MARGIN 2
46 #define MENU_TYPE_MASK (MF_STRING | MF_BITMAP | MF_OWNERDRAW | MF_SEPARATOR)
48 #define MENU_ITEM_TYPE(flags) ((flags) & MENU_TYPE_MASK)
50 #define MNS_STYLE_MASK (MNS_NOCHECK|MNS_MODELESS|MNS_DRAGDROP|MNS_AUTODISMISS|MNS_NOTIFYBYPOS|MNS_CHECKORBMP)
52 #define MENUITEMINFO_TYPE_MASK \
53 (MFT_STRING | MFT_BITMAP | MFT_OWNERDRAW | MFT_SEPARATOR | \
54 MFT_MENUBARBREAK | MFT_MENUBREAK | MFT_RADIOCHECK | \
55 MFT_RIGHTORDER | MFT_RIGHTJUSTIFY /* same as MF_HELP */ )
57 #define TYPE_MASK (MENUITEMINFO_TYPE_MASK | MF_POPUP | MF_SYSMENU)
59 #define STATE_MASK (~TYPE_MASK)
61 #define MENUITEMINFO_STATE_MASK (STATE_MASK & ~(MF_BYPOSITION | MF_MOUSESELECT))
63 #define MII_STATE_MASK (MFS_GRAYED|MFS_CHECKED|MFS_HILITE|MFS_DEFAULT)
65 /* macro to test that flags do not indicate bitmap, ownerdraw or separator */
66 #define IS_STRING_ITEM(flags) (MF_STRING == MENU_ITEM_TYPE(flags))
67 #define IS_MAGIC_BITMAP(id) ((id) && ((INT_PTR)(id) < 12) && ((INT_PTR)(id) >= -1))
69 #define IS_SYSTEM_MENU(MenuInfo) \
70 (0 == ((MenuInfo)->fFlags & MNF_POPUP) && 0 != ((MenuInfo)->fFlags & MNF_SYSDESKMN))
72 #define IS_SYSTEM_POPUP(MenuInfo) \
73 (0 != ((MenuInfo)->fFlags & MNF_POPUP) && 0 != ((MenuInfo)->fFlags & MNF_SYSDESKMN))
75 #define IS_BITMAP_ITEM(flags) (MF_BITMAP == MENU_ITEM_TYPE(flags))
77 /* Use global popup window because there's no way 2 menus can
78 * be tracked at the same time. */
79 static HWND top_popup
;
80 static HMENU top_popup_hmenu
;
82 /* Flag set by EndMenu() to force an exit from menu tracking */
83 static BOOL fEndMenu
= FALSE
;
85 #define MENU_ITEM_HBMP_SPACE (5)
86 #define MENU_BAR_ITEMS_SPACE (12)
87 #define SEPARATOR_HEIGHT (5)
88 #define MENU_TAB_SPACE (8)
93 HMENU CurrentMenu
; /* current submenu (can be equal to hTopMenu)*/
94 HMENU TopMenu
; /* initial menu */
95 HWND OwnerWnd
; /* where notifications are sent */
100 /*********************************************************************
101 * PopupMenu class descriptor
103 const struct builtin_class_descr POPUPMENU_builtin_class
=
106 CS_SAVEBITS
| CS_DBLCLKS
, /* style */
107 (WNDPROC
) NULL
, /* FIXME - procA */
108 (WNDPROC
) PopupMenuWndProcW
, /* FIXME - procW */
109 sizeof(MENUINFO
*), /* extra */
110 (LPCWSTR
) IDC_ARROW
, /* cursor */
111 (HBRUSH
)(COLOR_MENU
+ 1) /* brush */
115 #define GET_WORD(ptr) (*(WORD *)(ptr))
118 #define GET_DWORD(ptr) (*(DWORD *)(ptr))
121 HFONT hMenuFont
= NULL
;
122 HFONT hMenuFontBold
= NULL
;
124 /* Dimension of the menu bitmaps */
125 static HBITMAP BmpSysMenu
= NULL
;
127 static SIZE MenuCharSize
;
130 /***********************************************************************
133 * Validate the given menu handle and returns the menu structure pointer.
135 FORCEINLINE PMENU
MENU_GetMenu(HMENU hMenu
)
137 return ValidateHandleNoErr(hMenu
, TYPE_MENU
);
140 /***********************************************************************
143 * Get the system menu of a window
145 static HMENU
get_win_sys_menu( HWND hwnd
)
148 WND
*win
= ValidateHwnd( hwnd
);
151 ret
= win
->SystemMenu
;
156 /***********************************************************************
159 * Find a menu item. Return a pointer on the item, and modifies *hmenu
160 * in case the item was in a sub-menu.
162 ITEM
*MENU_FindItem( HMENU
*hmenu
, UINT
*nPos
, UINT wFlags
)
165 ITEM
*fallback
= NULL
;
166 UINT fallback_pos
= 0;
170 if ((*hmenu
== (HMENU
)0xffff) || (!(menu
= MENU_GetMenu(*hmenu
)))) return NULL
;
171 if (wFlags
& MF_BYPOSITION
)
173 if (*nPos
>= menu
->cItems
) return NULL
;
174 pItem
= menu
->rgItems
? DesktopPtrToUser(menu
->rgItems
) : NULL
;
175 if (pItem
) pItem
= &pItem
[*nPos
];
180 PITEM item
= menu
->rgItems
? DesktopPtrToUser(menu
->rgItems
) : NULL
;
181 for (i
= 0; item
, i
< menu
->cItems
; i
++, item
++)
185 PMENU pSubMenu
= DesktopPtrToUser(item
->spSubMenu
);
186 HMENU hsubmenu
= UserHMGetHandle(pSubMenu
);
187 ITEM
*subitem
= MENU_FindItem( &hsubmenu
, nPos
, wFlags
);
193 else if (item
->wID
== *nPos
)
195 /* fallback to this item if nothing else found */
200 else if (item
->wID
== *nPos
)
209 *nPos
= fallback_pos
;
214 #define MAX_GOINTOSUBMENU (0x10)
216 IntGetMenuDefaultItem(PMENU Menu
, BOOL fByPos
, UINT gmdiFlags
, DWORD
*gismc
)
219 PITEM Item
= Menu
->rgItems
? DesktopPtrToUser(Menu
->rgItems
) : NULL
;
222 if (!Item
) return -1;
224 while ( !( Item
->fState
& MFS_DEFAULT
) )
227 if (i
>= Menu
->cItems
) return -1;
230 /* default: don't return disabled items */
231 if ( (!(GMDI_USEDISABLED
& gmdiFlags
)) && (Item
->fState
& MFS_DISABLED
)) return -1;
233 /* search rekursiv when needed */
234 if ( (Item
->fType
& MF_POPUP
) && (gmdiFlags
& GMDI_GOINTOPOPUPS
) && Item
->spSubMenu
)
238 ret
= IntGetMenuDefaultItem( DesktopPtrToUser(Item
->spSubMenu
), fByPos
, gmdiFlags
, gismc
);
240 if ( -1 != ret
) return ret
;
242 /* when item not found in submenu, return the popup item */
244 return ( fByPos
) ? i
: Item
->wID
;
247 static BOOL
GetMenuItemInfo_common ( HMENU hmenu
,
250 LPMENUITEMINFOW lpmii
,
253 ITEM
*pItem
= MENU_FindItem (&hmenu
, &item
, bypos
? MF_BYPOSITION
: 0);
255 //debug_print_menuitem("GetMenuItemInfo_common: ", pItem, "");
259 SetLastError( ERROR_MENU_ITEM_NOT_FOUND
);
263 if( lpmii
->fMask
& MIIM_TYPE
)
265 if( lpmii
->fMask
& ( MIIM_STRING
| MIIM_FTYPE
| MIIM_BITMAP
))
267 ERR("invalid combination of fMask bits used\n");
268 /* this does not happen on Win9x/ME */
269 SetLastError( ERROR_INVALID_PARAMETER
);
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
)
277 lpmii
->dwTypeData
= (LPWSTR
) pItem
->hbmp
;
280 else if( lpmii
->fType
& (MFT_OWNERDRAW
| MFT_SEPARATOR
))
282 /* this does not happen on Win9x/ME */
283 lpmii
->dwTypeData
= 0;
288 /* copy the text string */
289 if ((lpmii
->fMask
& (MIIM_TYPE
|MIIM_STRING
)))
292 { // Very strange this fixes a wine test with a crash.
293 if(lpmii
->dwTypeData
&& lpmii
->cch
&& !(GdiValidateHandle((HGDIOBJ
)lpmii
->dwTypeData
)) )
297 *((WCHAR
*)lpmii
->dwTypeData
) = 0;
299 *((CHAR
*)lpmii
->dwTypeData
) = 0;
305 LPWSTR text
= DesktopPtrToUser(pItem
->Xlpstr
);
309 if(lpmii
->dwTypeData
&& lpmii
->cch
)
310 lstrcpynW(lpmii
->dwTypeData
, text
, lpmii
->cch
);
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;
320 /* if we've copied a substring we return its length */
321 if(lpmii
->dwTypeData
&& lpmii
->cch
)
322 if (lpmii
->cch
<= len
+ 1)
328 /* return length of string */
329 /* not on Win9x/ME if fType & MFT_BITMAP */
335 if (lpmii
->fMask
& MIIM_FTYPE
)
336 lpmii
->fType
= pItem
->fType
& MENUITEMINFO_TYPE_MASK
;
338 if (lpmii
->fMask
& MIIM_BITMAP
)
339 lpmii
->hbmpItem
= pItem
->hbmp
;
341 if (lpmii
->fMask
& MIIM_STATE
)
342 lpmii
->fState
= pItem
->fState
& MENUITEMINFO_STATE_MASK
;
344 if (lpmii
->fMask
& MIIM_ID
)
345 lpmii
->wID
= pItem
->wID
;
347 if (lpmii
->fMask
& MIIM_SUBMENU
&& pItem
->spSubMenu
)
349 PMENU pSubMenu
= DesktopPtrToUser(pItem
->spSubMenu
);
350 HMENU hSubMenu
= UserHMGetHandle(pSubMenu
);
351 lpmii
->hSubMenu
= hSubMenu
;
355 /* hSubMenu is always cleared
356 * (not on Win9x/ME ) */
360 if (lpmii
->fMask
& MIIM_CHECKMARKS
)
362 lpmii
->hbmpChecked
= pItem
->hbmpChecked
;
363 lpmii
->hbmpUnchecked
= pItem
->hbmpUnchecked
;
365 if (lpmii
->fMask
& MIIM_DATA
)
366 lpmii
->dwItemData
= pItem
->dwItemData
;
371 /***********************************************************************
374 * Get full information about menu
377 MenuGetRosMenuInfo(PROSMENUINFO MenuInfo
, HMENU Menu
)
380 if (!(pMenu
= ValidateHandleNoErr(Menu
, TYPE_MENU
))) return FALSE
;
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
;
388 MenuInfo
->cItems
= pMenu
->cItems
;
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
;
399 MenuInfo
->fFlags
= pMenu
->fFlags
;
400 MenuInfo
->Self
= pMenu
->head
.h
;
401 MenuInfo
->TimeToHide
= pMenu
->TimeToHide
;
402 MenuInfo
->Wnd
= pMenu
->hWnd
;
406 /***********************************************************************
409 * Set full information about menu
412 MenuSetRosMenuInfo(PROSMENUINFO MenuInfo
)
414 MenuInfo
->cbSize
= sizeof(ROSMENUINFO
);
415 MenuInfo
->fMask
= MIM_BACKGROUND
| MIM_HELPID
| MIM_MAXHEIGHT
| MIM_MENUDATA
| MIM_STYLE
;
417 return NtUserThunkedMenuInfo(MenuInfo
->Self
, (LPCMENUINFO
)MenuInfo
);
420 /***********************************************************************
421 * MenuInitRosMenuItemInfo
423 * Initialize a buffer for use with MenuGet/SetRosMenuItemInfo
426 MenuInitRosMenuItemInfo(PROSMENUITEMINFO ItemInfo
)
428 ZeroMemory(ItemInfo
, sizeof(ROSMENUITEMINFO
));
429 ItemInfo
->cbSize
= sizeof(ROSMENUITEMINFO
);
432 /***********************************************************************
433 * MenuGetRosMenuItemInfo
435 * Get full information about a menu item
438 MenuGetRosMenuItemInfo(HMENU Menu
, UINT Index
, PROSMENUITEMINFO ItemInfo
)
441 UINT Save_Mask
= ItemInfo
->fMask
; /* Save the org mask bits. */
443 if (ItemInfo
->dwTypeData
!= NULL
)
445 HeapFree(GetProcessHeap(), 0, ItemInfo
->dwTypeData
);
448 ItemInfo
->dwTypeData
= NULL
;
450 if (!(pItem
= MENU_FindItem(&Menu
, &Index
, MF_BYPOSITION
)))
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
;
464 if (pItem
->spSubMenu
)
466 PMENU pSubMenu
= DesktopPtrToUser(pItem
->spSubMenu
);
467 HMENU hSubMenu
= UserHMGetHandle(pSubMenu
);
468 ItemInfo
->hSubMenu
= hSubMenu
;
471 ItemInfo
->hSubMenu
= NULL
;
473 if (MENU_ITEM_TYPE(ItemInfo
->fType
) == MF_STRING
)
475 LPWSTR lpstr
= pItem
->lpstr
.Buffer
? DesktopPtrToUser(pItem
->lpstr
.Buffer
) : NULL
;
478 ItemInfo
->cch
= pItem
->lpstr
.Length
/ sizeof(WCHAR
);
480 ItemInfo
->dwTypeData
= HeapAlloc(GetProcessHeap(), 0, ItemInfo
->cch
* sizeof(WCHAR
));
481 if (ItemInfo
->dwTypeData
== NULL
)
485 RtlCopyMemory(ItemInfo
->dwTypeData
, lpstr
, min(ItemInfo
->cch
* sizeof(WCHAR
), pItem
->lpstr
.MaximumLength
));
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
;
502 ItemInfo
->fMask
= Save_Mask
;
506 /***********************************************************************
507 * MenuSetRosMenuItemInfo
509 * Set selected information about a menu item, need to set the mask bits.
512 MenuSetRosMenuItemInfo(HMENU Menu
, UINT Index
, PROSMENUITEMINFO ItemInfo
)
516 if (MENU_ITEM_TYPE(ItemInfo
->fType
) == MF_STRING
&&
517 ItemInfo
->dwTypeData
!= NULL
)
519 ItemInfo
->cch
= strlenW(ItemInfo
->dwTypeData
);
521 if (ItemInfo
->hSubMenu
)
523 if (!IsMenu(ItemInfo
->hSubMenu
)) ItemInfo
->hSubMenu
= NULL
;
525 Ret
= NtUserThunkedMenuItemInfo(Menu
, Index
, TRUE
, FALSE
, (LPMENUITEMINFOW
)ItemInfo
, NULL
);
529 /***********************************************************************
530 * MenuCleanupRosMenuItemInfo
532 * Cleanup after use of MenuGet/SetRosMenuItemInfo
535 MenuCleanupRosMenuItemInfo(PROSMENUITEMINFO ItemInfo
)
537 if (ItemInfo
->dwTypeData
!= NULL
)
539 HeapFree(GetProcessHeap(), 0, ItemInfo
->dwTypeData
);
540 ItemInfo
->dwTypeData
= NULL
;
544 /***********************************************************************
545 * MenuInitSysMenuPopup
547 * Grey the appropriate items in System menu.
549 void FASTCALL
MenuInitSysMenuPopup(HMENU hmenu
, DWORD style
, DWORD clsStyle
, LONG HitTest
)
557 gray
= !(style
& WS_THICKFRAME
) || (style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
558 EnableMenuItem( hmenu
, SC_SIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
559 gray
= ((style
& WS_MAXIMIZE
) != 0);
560 EnableMenuItem( hmenu
, SC_MOVE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
561 gray
= !(style
& WS_MINIMIZEBOX
) || (style
& WS_MINIMIZE
);
562 EnableMenuItem( hmenu
, SC_MINIMIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
563 gray
= !(style
& WS_MAXIMIZEBOX
) || (style
& WS_MAXIMIZE
);
564 EnableMenuItem( hmenu
, SC_MAXIMIZE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
565 gray
= !(style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
566 EnableMenuItem( hmenu
, SC_RESTORE
, (gray
? MF_GRAYED
: MF_ENABLED
) );
567 gray
= (clsStyle
& CS_NOCLOSE
) != 0;
569 /* The menu item must keep its state if it's disabled */
571 EnableMenuItem( hmenu
, SC_CLOSE
, MF_GRAYED
);
573 /* Set default menu item */
574 if(style
& WS_MINIMIZE
) DefItem
= SC_RESTORE
;
575 else if(HitTest
== HTCAPTION
) DefItem
= ((style
& (WS_MAXIMIZE
| WS_MINIMIZE
)) ? SC_RESTORE
: SC_MAXIMIZE
);
576 else DefItem
= SC_CLOSE
;
578 mii
.cbSize
= sizeof(MENUITEMINFOW
);
579 mii
.fMask
|= MIIM_STATE
;
580 if((DefItem
!= SC_CLOSE
) && GetMenuItemInfoW(hmenu
, DefItem
, FALSE
, &mii
) &&
581 (mii
.fState
& (MFS_GRAYED
| MFS_DISABLED
))) DefItem
= SC_CLOSE
;
583 SetMenuDefaultItem(hmenu
, DefItem
, MF_BYCOMMAND
);
586 /******************************************************************************
588 * UINT MenuGetStartOfNextColumn(
589 * PROSMENUINFO MenuInfo)
591 *****************************************************************************/
593 static UINT
MENU_GetStartOfNextColumn(
596 MENU
*menu
= MENU_GetMenu(hMenu
);
601 return NO_SELECTED_ITEM
;
604 if( i
== NO_SELECTED_ITEM
)
607 pItem
= menu
->rgItems
? DesktopPtrToUser(menu
->rgItems
) : NULL
;
608 if (!pItem
) return NO_SELECTED_ITEM
;
609 for( ; i
< menu
->cItems
; ++i
) {
610 if (pItem
[i
].fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))
614 return NO_SELECTED_ITEM
;
617 /******************************************************************************
619 * UINT MenuGetStartOfPrevColumn(
620 * PROSMENUINFO MenuInfo)
622 *****************************************************************************/
623 static UINT
MENU_GetStartOfPrevColumn(
626 MENU
*menu
= MENU_GetMenu(hMenu
);
631 return NO_SELECTED_ITEM
;
633 if( menu
->iItem
== 0 || menu
->iItem
== NO_SELECTED_ITEM
)
634 return NO_SELECTED_ITEM
;
636 pItem
= menu
->rgItems
? DesktopPtrToUser(menu
->rgItems
) : NULL
;
637 if (!pItem
) return NO_SELECTED_ITEM
;
639 /* Find the start of the column */
641 for(i
= menu
->iItem
; i
!= 0 &&
642 !(pItem
[i
].fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
));
646 return NO_SELECTED_ITEM
;
648 for(--i
; i
!= 0; --i
) {
649 if (pItem
[i
].fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))
653 TRACE("ret %d.\n", i
);
658 /***********************************************************************
661 * Load the arrow bitmap. We can't do this from MenuInit since user32
662 * can also be used (and thus initialized) from text-mode.
665 MenuLoadBitmaps(VOID
)
667 /* Load system buttons bitmaps */
668 if (NULL
== BmpSysMenu
)
670 BmpSysMenu
= LoadBitmapW(0, MAKEINTRESOURCEW(OBM_CLOSE
));
673 /////////// Make gpsi OBMI via callback //////////////
674 /***********************************************************************
677 HBITMAP
get_arrow_bitmap(void)
679 static HBITMAP arrow_bitmap
;
681 if (!arrow_bitmap
) arrow_bitmap
= LoadBitmapW(0, MAKEINTRESOURCEW(OBM_MNARROW
));
685 /***********************************************************************
686 * get_down_arrow_bitmap DFCS_MENUARROWDOWN
688 HBITMAP
get_down_arrow_bitmap(void)
690 static HBITMAP arrow_bitmap
;
692 if (!arrow_bitmap
) arrow_bitmap
= LoadBitmapW(0, MAKEINTRESOURCEW(OBM_DNARROW
));
696 /***********************************************************************
697 * get_down_arrow_inactive_bitmap DFCS_MENUARROWDOWN | DFCS_INACTIVE
699 HBITMAP
get_down_arrow_inactive_bitmap(void)
701 static HBITMAP arrow_bitmap
;
703 if (!arrow_bitmap
) arrow_bitmap
= LoadBitmapW(0, MAKEINTRESOURCEW(OBM_DNARROWI
));
707 /***********************************************************************
708 * get_up_arrow_bitmap DFCS_MENUARROWUP
710 HBITMAP
get_up_arrow_bitmap(void)
712 static HBITMAP arrow_bitmap
;
714 if (!arrow_bitmap
) arrow_bitmap
= LoadBitmapW(0, MAKEINTRESOURCEW(OBM_UPARROW
));
718 /***********************************************************************
719 * get_up_arrow_inactive_bitmap DFCS_MENUARROWUP | DFCS_INACTIVE
721 static HBITMAP
get_up_arrow_inactive_bitmap(void)
723 static HBITMAP arrow_bitmap
;
725 if (!arrow_bitmap
) arrow_bitmap
= LoadBitmapW(0, MAKEINTRESOURCEW(OBM_UPARROWI
));
729 /***********************************************************************
732 * Find a Sub menu. Return the position of the submenu, and modifies
733 * *hmenu in case it is found in another sub-menu.
734 * If the submenu cannot be found, NO_SELECTED_ITEM is returned.
736 static UINT FASTCALL
MenuFindSubMenu(HMENU
*hmenu
, HMENU hSubTarget
)
738 PMENU menu
, pSubMenu
;
743 if (((*hmenu
)==(HMENU
)0xffff) ||(!(menu
= MENU_GetMenu(*hmenu
))))
744 return NO_SELECTED_ITEM
;
746 item
= menu
->rgItems
? DesktopPtrToUser(menu
->rgItems
) : NULL
;
747 for (i
= 0; i
< menu
->cItems
; i
++, item
++)
749 if (!item
->spSubMenu
)
753 pSubMenu
= DesktopPtrToUser(item
->spSubMenu
);
754 hSubMenu
= UserHMGetHandle(pSubMenu
);
755 if (hSubMenu
== hSubTarget
)
761 HMENU hsubmenu
= hSubMenu
;
762 UINT pos
= MenuFindSubMenu( &hsubmenu
, hSubTarget
);
763 if (pos
!= NO_SELECTED_ITEM
)
771 return NO_SELECTED_ITEM
;
774 /***********************************************************************
775 * MENU_AdjustMenuItemRect
777 * Adjust menu item rectangle according to scrolling state.
780 MENU_AdjustMenuItemRect(PROSMENUINFO menu
, LPRECT rect
)
782 if (menu
->dwArrowsOn
)
784 UINT arrow_bitmap_height
;
787 GetObjectW(get_up_arrow_bitmap(), sizeof(bmp
), &bmp
);
788 arrow_bitmap_height
= bmp
.bmHeight
;
789 rect
->top
+= arrow_bitmap_height
- menu
->iTop
;
790 rect
->bottom
+= arrow_bitmap_height
- menu
->iTop
;
794 /***********************************************************************
797 * Draws popup magic glyphs (can be found in system menu).
800 MenuDrawPopupGlyph(HDC dc
, LPRECT r
, INT_PTR popupMagic
, BOOL inactive
, BOOL hilite
)
803 HFONT hFont
, hOldFont
;
809 case (INT_PTR
) HBMMENU_POPUP_RESTORE
:
812 case (INT_PTR
) HBMMENU_POPUP_MINIMIZE
:
815 case (INT_PTR
) HBMMENU_POPUP_MAXIMIZE
:
818 case (INT_PTR
) HBMMENU_POPUP_CLOSE
:
822 ERR("Invalid popup magic bitmap %d\n", (int)popupMagic
);
825 ZeroMemory(&lf
, sizeof(LOGFONTW
));
826 InflateRect(r
, -2, -2);
827 lf
.lfHeight
= r
->bottom
- r
->top
;
829 lf
.lfWeight
= FW_NORMAL
;
830 lf
.lfCharSet
= DEFAULT_CHARSET
;
831 lstrcpy(lf
.lfFaceName
, TEXT("Marlett"));
832 hFont
= CreateFontIndirect(&lf
);
833 /* save font and text color */
834 hOldFont
= SelectObject(dc
, hFont
);
835 clrsave
= GetTextColor(dc
);
836 bkmode
= GetBkMode(dc
);
837 /* set color and drawing mode */
838 SetBkMode(dc
, TRANSPARENT
);
844 SetTextColor(dc
, GetSysColor(COLOR_HIGHLIGHTTEXT
));
845 TextOut(dc
, r
->left
+ 1, r
->top
+ 1, &symbol
, 1);
848 SetTextColor(dc
, GetSysColor(inactive
? COLOR_GRAYTEXT
: (hilite
? COLOR_HIGHLIGHTTEXT
: COLOR_MENUTEXT
)));
849 /* draw selected symbol */
850 TextOut(dc
, r
->left
, r
->top
, &symbol
, 1);
851 /* restore previous settings */
852 SetTextColor(dc
, clrsave
);
853 SelectObject(dc
, hOldFont
);
854 SetBkMode(dc
, bkmode
);
858 /***********************************************************************
861 * Find the menu item selected by a key press.
862 * Return item id, -1 if none, -2 if we should close the menu.
864 static UINT FASTCALL
MENU_FindItemByKey(HWND WndOwner
, HMENU hmenu
,
865 WCHAR Key
, BOOL ForceMenuChar
)
870 TRACE("\tlooking for '%c' (0x%02x) in [%p]\n", (char)Key
, Key
, hmenu
);
872 if (!IsMenu( hmenu
)) hmenu
= GetSubMenu( get_win_sys_menu(WndOwner
), 0);
875 MENU
*menu
= MENU_GetMenu( hmenu
);
876 ITEM
*item
= menu
->rgItems
? DesktopPtrToUser(menu
->rgItems
) : NULL
;
881 BOOL cjk
= GetSystemMetrics( SM_DBCSENABLED
);
883 for (i
= 0; i
< menu
->cItems
; i
++, item
++)
885 LPWSTR text
= item
->Xlpstr
? DesktopPtrToUser(item
->Xlpstr
) : NULL
;
888 const WCHAR
*p
= text
- 2;
891 const WCHAR
*q
= p
+ 2;
892 p
= strchrW (q
, '&');
893 if (!p
&& cjk
) p
= strchrW (q
, '\036'); /* Japanese Win16 */
895 while (p
!= NULL
&& p
[1] == '&');
896 if (p
&& (toupperW(p
[1]) == toupperW(Key
))) return i
;
901 Flags
|= menu
->fFlags
& MNF_POPUP
? MF_POPUP
: 0;
902 Flags
|= menu
->fFlags
& MNF_SYSDESKMN
? MF_SYSMENU
: 0;
904 MenuChar
= SendMessageW(WndOwner
, WM_MENUCHAR
,
905 MAKEWPARAM(Key
, Flags
), (LPARAM
) hmenu
);
906 if (HIWORD(MenuChar
) == MNC_EXECUTE
) return LOWORD(MenuChar
);
907 if (HIWORD(MenuChar
) == MNC_CLOSE
) return (UINT
)(-2);
912 /***********************************************************************
913 * MenuGetBitmapItemSize
915 * Get the size of a bitmap item.
917 static void FASTCALL
MenuGetBitmapItemSize(PROSMENUITEMINFO lpitem
, SIZE
*size
, HWND WndOwner
)
920 HBITMAP bmp
= lpitem
->hbmpItem
;
922 size
->cx
= size
->cy
= 0;
924 /* check if there is a magic menu item associated with this item */
925 if (IS_MAGIC_BITMAP(bmp
))
927 switch((INT_PTR
) bmp
)
929 case (INT_PTR
)HBMMENU_CALLBACK
:
931 MEASUREITEMSTRUCT measItem
;
932 measItem
.CtlType
= ODT_MENU
;
934 measItem
.itemID
= lpitem
->wID
;
935 measItem
.itemWidth
= lpitem
->Rect
.right
- lpitem
->Rect
.left
;
936 measItem
.itemHeight
= lpitem
->Rect
.bottom
- lpitem
->Rect
.top
;
937 measItem
.itemData
= lpitem
->dwItemData
;
938 SendMessageW( WndOwner
, WM_MEASUREITEM
, lpitem
->wID
, (LPARAM
)&measItem
);
939 size
->cx
= measItem
.itemWidth
;
940 size
->cy
= measItem
.itemHeight
;
945 case (INT_PTR
) HBMMENU_SYSTEM
:
946 if (0 != lpitem
->dwItemData
)
948 bmp
= (HBITMAP
) lpitem
->dwItemData
;
952 case (INT_PTR
) HBMMENU_MBAR_RESTORE
:
953 case (INT_PTR
) HBMMENU_MBAR_MINIMIZE
:
954 case (INT_PTR
) HBMMENU_MBAR_CLOSE
:
955 case (INT_PTR
) HBMMENU_MBAR_MINIMIZE_D
:
956 case (INT_PTR
) HBMMENU_MBAR_CLOSE_D
:
957 case (INT_PTR
) HBMMENU_POPUP_CLOSE
:
958 case (INT_PTR
) HBMMENU_POPUP_RESTORE
:
959 case (INT_PTR
) HBMMENU_POPUP_MAXIMIZE
:
960 case (INT_PTR
) HBMMENU_POPUP_MINIMIZE
:
961 /* FIXME: Why we need to subtract these magic values? */
962 /* to make them smaller than the menu bar? */
963 size
->cx
= GetSystemMetrics(SM_CXSIZE
) - 2;
964 size
->cy
= GetSystemMetrics(SM_CYSIZE
) - 4;
969 if (GetObjectW(bmp
, sizeof(BITMAP
), &bm
))
971 size
->cx
= bm
.bmWidth
;
972 size
->cy
= bm
.bmHeight
;
976 /***********************************************************************
979 * Draw a bitmap item.
981 static void FASTCALL
MenuDrawBitmapItem(HDC hdc
, PROSMENUITEMINFO lpitem
, const RECT
*rect
,
982 PROSMENUINFO MenuInfo
, HWND WndOwner
, UINT odaction
, BOOL MenuBar
)
988 int w
= rect
->right
- rect
->left
;
989 int h
= rect
->bottom
- rect
->top
;
992 HBITMAP hbmToDraw
= lpitem
->hbmpItem
;
995 /* Check if there is a magic menu item associated with this item */
996 if (IS_MAGIC_BITMAP(hbmToDraw
))
1002 switch ((INT_PTR
)hbmToDraw
)
1004 case (INT_PTR
)HBMMENU_SYSTEM
:
1005 if (lpitem
->dwTypeData
)
1007 bmp
= (HBITMAP
)lpitem
->dwTypeData
;
1008 if (!GetObjectW( bmp
, sizeof(bm
), &bm
)) return;
1012 if (!BmpSysMenu
) BmpSysMenu
= LoadBitmapW(0, MAKEINTRESOURCEW(OBM_CLOSE
));
1014 if (! GetObjectW(bmp
, sizeof(bm
), &bm
)) return;
1015 /* only use right half of the bitmap */
1016 bmp_xoffset
= bm
.bmWidth
/ 2;
1017 bm
.bmWidth
-= bmp_xoffset
;
1020 case (INT_PTR
)HBMMENU_MBAR_RESTORE
:
1021 flags
= DFCS_CAPTIONRESTORE
;
1023 case (INT_PTR
)HBMMENU_MBAR_MINIMIZE
:
1025 flags
= DFCS_CAPTIONMIN
;
1027 case (INT_PTR
)HBMMENU_MBAR_MINIMIZE_D
:
1029 flags
= DFCS_CAPTIONMIN
| DFCS_INACTIVE
;
1031 case (INT_PTR
)HBMMENU_MBAR_CLOSE
:
1032 flags
= DFCS_CAPTIONCLOSE
;
1034 case (INT_PTR
)HBMMENU_MBAR_CLOSE_D
:
1035 flags
= DFCS_CAPTIONCLOSE
| DFCS_INACTIVE
;
1037 case (INT_PTR
)HBMMENU_CALLBACK
:
1039 DRAWITEMSTRUCT drawItem
;
1041 drawItem
.CtlType
= ODT_MENU
;
1043 drawItem
.itemID
= lpitem
->wID
;
1044 drawItem
.itemAction
= odaction
;
1045 drawItem
.itemState
= (lpitem
->fState
& MF_CHECKED
)?ODS_CHECKED
:0;
1046 drawItem
.itemState
|= (lpitem
->fState
& MF_DEFAULT
)?ODS_DEFAULT
:0;
1047 drawItem
.itemState
|= (lpitem
->fState
& MF_DISABLED
)?ODS_DISABLED
:0;
1048 drawItem
.itemState
|= (lpitem
->fState
& MF_GRAYED
)?ODS_GRAYED
|ODS_DISABLED
:0;
1049 drawItem
.itemState
|= (lpitem
->fState
& MF_HILITE
)?ODS_SELECTED
:0;
1050 //drawItem.itemState |= (!(MenuInfo->fFlags & MNF_UNDERLINE))?ODS_NOACCEL:0;
1051 //drawItem.itemState |= (MenuInfo->fFlags & MNF_INACTIVE)?ODS_INACTIVE:0;
1052 drawItem
.hwndItem
= (HWND
)MenuInfo
->Self
;
1054 drawItem
.rcItem
= *rect
;
1055 drawItem
.itemData
= lpitem
->dwItemData
;
1056 /* some applications make this assumption on the DC's origin */
1057 SetViewportOrgEx( hdc
, lpitem
->Rect
.left
, lpitem
->Rect
.top
, &origorg
);
1058 OffsetRect( &drawItem
.rcItem
, - lpitem
->Rect
.left
, - lpitem
->Rect
.top
);
1059 SendMessageW( WndOwner
, WM_DRAWITEM
, 0, (LPARAM
)&drawItem
);
1060 SetViewportOrgEx( hdc
, origorg
.x
, origorg
.y
, NULL
);
1065 case (INT_PTR
) HBMMENU_POPUP_CLOSE
:
1066 case (INT_PTR
) HBMMENU_POPUP_RESTORE
:
1067 case (INT_PTR
) HBMMENU_POPUP_MAXIMIZE
:
1068 case (INT_PTR
) HBMMENU_POPUP_MINIMIZE
:
1069 MenuDrawPopupGlyph(hdc
, &r
, (INT_PTR
)hbmToDraw
, lpitem
->fState
& MF_GRAYED
, lpitem
->fState
& MF_HILITE
);
1072 InflateRect(&r
, -1, -1);
1073 if (0 != (lpitem
->fState
& MF_HILITE
))
1075 flags
|= DFCS_PUSHED
;
1077 DrawFrameControl(hdc
, &r
, DFC_CAPTION
, flags
);
1081 if (!bmp
|| !GetObjectW( bmp
, sizeof(bm
), &bm
)) return;
1084 hdcMem
= CreateCompatibleDC( hdc
);
1085 SelectObject( hdcMem
, bmp
);
1087 /* handle fontsize > bitmap_height */
1088 top
= (h
>bm
.bmHeight
) ? rect
->top
+(h
-bm
.bmHeight
)/2 : rect
->top
;
1090 rop
=((lpitem
->fState
& MF_HILITE
) && !IS_MAGIC_BITMAP(hbmToDraw
)) ? NOTSRCCOPY
: SRCCOPY
;
1091 if ((lpitem
->fState
& MF_HILITE
) && lpitem
->hbmpItem
)
1092 SetBkColor(hdc
, GetSysColor(COLOR_HIGHLIGHT
));
1093 BitBlt( hdc
, left
, top
, w
, h
, hdcMem
, bmp_xoffset
, 0, rop
);
1097 /***********************************************************************
1100 * Calculate the size of the menu item and store it in lpitem->rect.
1102 static void FASTCALL
MenuCalcItemSize( HDC hdc
, PROSMENUITEMINFO lpitem
, PROSMENUINFO MenuInfo
, HWND hwndOwner
,
1103 INT orgX
, INT orgY
, BOOL menuBar
, BOOL textandbmp
)
1106 UINT check_bitmap_width
= GetSystemMetrics( SM_CXMENUCHECK
);
1107 UINT arrow_bitmap_width
;
1111 TRACE("dc=%x owner=%x (%d,%d)\n", hdc
, hwndOwner
, orgX
, orgY
);
1113 GetObjectW( get_arrow_bitmap(), sizeof(bm
), &bm
);
1114 arrow_bitmap_width
= bm
.bmWidth
;
1116 MenuCharSize
.cx
= GdiGetCharDimensions( hdc
, NULL
, &MenuCharSize
.cy
);
1118 SetRect( &lpitem
->Rect
, orgX
, orgY
, orgX
, orgY
);
1120 if (lpitem
->fType
& MF_OWNERDRAW
)
1122 MEASUREITEMSTRUCT mis
;
1123 mis
.CtlType
= ODT_MENU
;
1125 mis
.itemID
= lpitem
->wID
;
1126 mis
.itemData
= lpitem
->dwItemData
;
1127 mis
.itemHeight
= HIWORD( GetDialogBaseUnits());
1129 SendMessageW( hwndOwner
, WM_MEASUREITEM
, 0, (LPARAM
)&mis
);
1130 /* Tests reveal that Windows ( Win95 thru WinXP) adds twice the average
1131 * width of a menufont character to the width of an owner-drawn menu.
1133 lpitem
->Rect
.right
+= mis
.itemWidth
+ 2 * MenuCharSize
.cx
;
1135 /* under at least win95 you seem to be given a standard
1136 height for the menu and the height value is ignored */
1137 lpitem
->Rect
.bottom
+= GetSystemMetrics(SM_CYMENUSIZE
);
1139 lpitem
->Rect
.bottom
+= mis
.itemHeight
;
1141 //Item->cxBmp = mis.itemWidth;
1142 //Item->cyBmp = mis.itemHeight;
1143 TRACE("id=%04lx size=%dx%d\n",
1144 lpitem
->wID
, lpitem
->Rect
.right
-lpitem
->Rect
.left
,
1145 lpitem
->Rect
.bottom
-lpitem
->Rect
.top
);
1149 if (lpitem
->fType
& MF_SEPARATOR
)
1151 lpitem
->Rect
.bottom
+= GetSystemMetrics( SM_CYMENUSIZE
)/2;//SEPARATOR_HEIGHT;
1153 lpitem
->Rect
.right
+= arrow_bitmap_width
/*check_bitmap_width*/ + MenuCharSize
.cx
;
1159 if (lpitem
->hbmpItem
)
1164 MenuGetBitmapItemSize(lpitem
, &size
, hwndOwner
);
1165 /* Keep the size of the bitmap in callback mode to be able
1166 * to draw it correctly */
1167 lpitem
->maxBmpSize
= size
;
1168 MenuInfo
->cxTextAlign
= max(MenuInfo
->cxTextAlign
, size
.cx
);
1169 MenuSetRosMenuInfo(MenuInfo
);
1170 lpitem
->Rect
.right
+= size
.cx
+ 2;
1171 itemheight
= size
.cy
+ 2;
1173 if( !(MenuInfo
->dwStyle
& MNS_NOCHECK
))
1174 lpitem
->Rect
.right
+= 2 * check_bitmap_width
;
1175 lpitem
->Rect
.right
+= 4 + MenuCharSize
.cx
;
1176 lpitem
->dxTab
= lpitem
->Rect
.right
;
1177 lpitem
->Rect
.right
+= arrow_bitmap_width
;//check_bitmap_width;
1178 } else /* hbmpItem & MenuBar */ {
1179 MenuGetBitmapItemSize(lpitem
, &size
, hwndOwner
);
1180 lpitem
->Rect
.right
+= size
.cx
;
1181 if( lpitem
->lpstr
) lpitem
->Rect
.right
+= 2;
1182 itemheight
= size
.cy
;
1184 /* Special case: Minimize button doesn't have a space behind it. */
1185 if (lpitem
->hbmpItem
== (HBITMAP
)HBMMENU_MBAR_MINIMIZE
||
1186 lpitem
->hbmpItem
== (HBITMAP
)HBMMENU_MBAR_MINIMIZE_D
)
1187 lpitem
->Rect
.right
-= 1;
1190 else if (!menuBar
) {
1191 if( !(MenuInfo
->dwStyle
& MNS_NOCHECK
))
1192 lpitem
->Rect
.right
+= check_bitmap_width
;
1193 lpitem
->Rect
.right
+= 4 + MenuCharSize
.cx
;
1194 lpitem
->dxTab
= lpitem
->Rect
.right
;
1195 lpitem
->Rect
.right
+= check_bitmap_width
;
1198 /* it must be a text item - unless it's the system menu */
1199 if (!(lpitem
->fType
& MF_SYSMENU
) && lpitem
->lpstr
) {
1200 HFONT hfontOld
= NULL
;
1201 RECT rc
= lpitem
->Rect
;
1202 LONG txtheight
, txtwidth
;
1204 if ( lpitem
->fState
& MFS_DEFAULT
) {
1205 hfontOld
= SelectObject( hdc
, hMenuFontBold
);
1208 txtheight
= DrawTextW( hdc
, lpitem
->dwTypeData
, -1, &rc
,
1209 DT_SINGLELINE
|DT_CALCRECT
);
1210 lpitem
->Rect
.right
+= rc
.right
- rc
.left
;
1211 itemheight
= max( max( itemheight
, txtheight
),
1212 GetSystemMetrics( SM_CYMENU
) - 1);
1213 lpitem
->Rect
.right
+= 2 * MenuCharSize
.cx
;
1215 if ((p
= strchrW( lpitem
->dwTypeData
, '\t' )) != NULL
) {
1218 int n
= (int)( p
- lpitem
->dwTypeData
);
1219 /* Item contains a tab (only meaningful in popup menus) */
1220 /* get text size before the tab */
1221 txtheight
= DrawTextW( hdc
, lpitem
->dwTypeData
, n
, &rc
,
1222 DT_SINGLELINE
|DT_CALCRECT
);
1223 txtwidth
= rc
.right
- rc
.left
;
1224 p
+= 1; /* advance past the Tab */
1225 /* get text size after the tab */
1226 tmpheight
= DrawTextW( hdc
, p
, -1, &tmprc
,
1227 DT_SINGLELINE
|DT_CALCRECT
);
1228 lpitem
->dxTab
+= txtwidth
;
1229 txtheight
= max( txtheight
, tmpheight
);
1230 txtwidth
+= MenuCharSize
.cx
+ /* space for the tab */
1231 tmprc
.right
- tmprc
.left
; /* space for the short cut */
1233 txtheight
= DrawTextW( hdc
, lpitem
->dwTypeData
, -1, &rc
,
1234 DT_SINGLELINE
|DT_CALCRECT
);
1235 txtwidth
= rc
.right
- rc
.left
;
1236 lpitem
->dxTab
+= txtwidth
;
1238 lpitem
->Rect
.right
+= 2 + txtwidth
;
1239 itemheight
= max( itemheight
,
1240 max( txtheight
+ 2, MenuCharSize
.cy
+ 4));
1242 if (hfontOld
) SelectObject (hdc
, hfontOld
);
1243 } else if( menuBar
) {
1244 itemheight
= max( itemheight
, GetSystemMetrics(SM_CYMENU
)-1);
1246 lpitem
->Rect
.bottom
+= itemheight
;
1247 TRACE("(%ld,%ld)-(%ld,%ld)\n", lpitem
->Rect
.left
, lpitem
->Rect
.top
, lpitem
->Rect
.right
, lpitem
->Rect
.bottom
);
1250 /***********************************************************************
1251 * MENU_GetMaxPopupHeight
1254 MENU_GetMaxPopupHeight(PROSMENUINFO lppop
)
1257 return lppop
->cyMax
;
1258 return GetSystemMetrics(SM_CYSCREEN
) - GetSystemMetrics(SM_CYBORDER
);
1261 /***********************************************************************
1262 * MenuPopupMenuCalcSize
1264 * Calculate the size of a popup menu.
1266 static void FASTCALL
MenuPopupMenuCalcSize(PROSMENUINFO MenuInfo
, HWND WndOwner
)
1268 ROSMENUITEMINFO lpitem
;
1271 int orgX
, orgY
, maxX
, maxTab
, maxTabWidth
, maxHeight
;
1272 BOOL textandbmp
= FALSE
;
1274 MenuInfo
->cxMenu
= MenuInfo
->cyMenu
= 0;
1275 if (MenuInfo
->cItems
== 0)
1277 MenuSetRosMenuInfo(MenuInfo
);
1282 SelectObject( hdc
, hMenuFont
);
1287 MenuInfo
->cxTextAlign
= 0;
1289 MenuInitRosMenuItemInfo(&lpitem
);
1290 while (start
< MenuInfo
->cItems
)
1295 maxTab
= maxTabWidth
= 0;
1297 /* Parse items until column break or end of menu */
1298 for (i
= start
; i
< MenuInfo
->cItems
; i
++)
1300 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
, &lpitem
))
1302 MenuCleanupRosMenuItemInfo(&lpitem
);
1303 MenuSetRosMenuInfo(MenuInfo
);
1307 (lpitem
.fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
1309 if( lpitem
.lpstr
&& lpitem
.hbmpItem
) textandbmp
= TRUE
;
1311 MenuCalcItemSize(hdc
, &lpitem
, MenuInfo
, WndOwner
, orgX
, orgY
, FALSE
, textandbmp
);
1312 if (! MenuSetRosMenuItemInfo(MenuInfo
->Self
, i
, &lpitem
))
1314 MenuCleanupRosMenuItemInfo(&lpitem
);
1315 MenuSetRosMenuInfo(MenuInfo
);
1318 // Not sure here,, The patch from wine removes this.
1319 // if ((lpitem.fType & MF_MENUBARBREAK) != 0)
1323 maxX
= max(maxX
, lpitem
.Rect
.right
);
1324 orgY
= lpitem
.Rect
.bottom
;
1325 if ((lpitem
.lpstr
) && lpitem
.dxTab
)
1327 maxTab
= max( maxTab
, lpitem
.dxTab
);
1328 maxTabWidth
= max(maxTabWidth
, lpitem
.Rect
.right
- lpitem
.dxTab
);
1332 /* Finish the column (set all items to the largest width found) */
1333 maxX
= max( maxX
, maxTab
+ maxTabWidth
);
1336 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, start
, &lpitem
))
1338 lpitem
.Rect
.right
= maxX
;
1339 if ((lpitem
.lpstr
) && 0 != lpitem
.dxTab
)
1341 lpitem
.dxTab
= maxTab
;
1343 MenuSetRosMenuItemInfo(MenuInfo
->Self
, start
, &lpitem
);
1347 MenuInfo
->cyMenu
= max(MenuInfo
->cyMenu
, orgY
);
1350 MenuInfo
->cxMenu
= maxX
;
1351 /* if none of the items have both text and bitmap then
1352 * the text and bitmaps are all aligned on the left. If there is at
1353 * least one item with both text and bitmap then bitmaps are
1354 * on the left and texts left aligned with the right hand side
1356 if( !textandbmp
) MenuInfo
->cxTextAlign
= 0;
1358 /* space for 3d border */
1359 MenuInfo
->cyMenu
+= MENU_BOTTOM_MARGIN
;
1360 MenuInfo
->cxMenu
+= 2;
1362 /* Adjust popup height if it exceeds maximum */
1363 maxHeight
= MENU_GetMaxPopupHeight(MenuInfo
);
1364 MenuInfo
->iMaxTop
= MenuInfo
->cyMenu
- MENU_TOP_MARGIN
;
1365 if (MenuInfo
->cyMenu
>= maxHeight
)
1367 MenuInfo
->cyMenu
= maxHeight
;
1368 MenuInfo
->dwArrowsOn
= 1;
1372 MenuInfo
->dwArrowsOn
= 0;
1375 MenuCleanupRosMenuItemInfo(&lpitem
);
1376 MenuSetRosMenuInfo(MenuInfo
);
1377 ReleaseDC( 0, hdc
);
1380 /***********************************************************************
1381 * MenuMenuBarCalcSize
1383 * FIXME: Word 6 implements its own MDI and its own 'close window' bitmap
1384 * height is off by 1 pixel which causes lengthy window relocations when
1385 * active document window is maximized/restored.
1387 * Calculate the size of the menu bar.
1389 static void FASTCALL
MenuMenuBarCalcSize( HDC hdc
, LPRECT lprect
,
1390 PROSMENUINFO MenuInfo
, HWND hwndOwner
)
1392 ROSMENUITEMINFO ItemInfo
;
1393 int start
, i
, orgX
, orgY
, maxY
, helpPos
;
1395 if ((lprect
== NULL
) || (MenuInfo
== NULL
)) return;
1396 if (MenuInfo
->cItems
== 0) return;
1397 TRACE("lprect %p %s\n", lprect
, wine_dbgstr_rect( lprect
));
1398 MenuInfo
->cxMenu
= lprect
->right
- lprect
->left
;
1399 MenuInfo
->cyMenu
= 0;
1400 maxY
= lprect
->top
+ 1;
1404 MenuInfo
->cxTextAlign
= 0;
1406 MenuInitRosMenuItemInfo(&ItemInfo
);
1407 while (start
< MenuInfo
->cItems
)
1409 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, start
, &ItemInfo
))
1411 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1414 orgX
= lprect
->left
;
1417 /* Parse items until line break or end of menu */
1418 for (i
= start
; i
< MenuInfo
->cItems
; i
++)
1420 if ((helpPos
== -1) && (ItemInfo
.fType
& MF_RIGHTJUSTIFY
)) helpPos
= i
;
1422 (ItemInfo
.fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))) break;
1424 TRACE("calling MENU_CalcItemSize org=(%d, %d)\n", orgX
, orgY
);
1425 MenuCalcItemSize(hdc
, &ItemInfo
, MenuInfo
, hwndOwner
, orgX
, orgY
, TRUE
, FALSE
);
1426 if (! MenuSetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
))
1428 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1432 if (ItemInfo
.Rect
.right
> lprect
->right
)
1434 if (i
!= start
) break;
1435 else ItemInfo
.Rect
.right
= lprect
->right
;
1437 maxY
= max( maxY
, ItemInfo
.Rect
.bottom
);
1438 orgX
= ItemInfo
.Rect
.right
;
1439 if (i
+ 1 < MenuInfo
->cItems
)
1441 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
+ 1, &ItemInfo
))
1443 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1449 /* FIXME: Is this really needed? */ /*NO! it is not needed, why make the
1450 HBMMENU_MBAR_CLOSE, MINIMIZE & RESTORE, look the same size as the menu bar! */
1452 /* Finish the line (set all items to the largest height found) */
1455 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, start
, &ItemInfo
))
1457 ItemInfo
.Rect
.bottom
= maxY
;
1458 MenuSetRosMenuItemInfo(MenuInfo
->Self
, start
, &ItemInfo
);
1463 start
= i
; /* This works! */
1467 lprect
->bottom
= maxY
;
1468 MenuInfo
->cyMenu
= lprect
->bottom
- lprect
->top
;
1469 MenuSetRosMenuInfo(MenuInfo
);
1473 /* Flush right all items between the MF_RIGHTJUSTIFY and */
1474 /* the last item (if several lines, only move the last line) */
1475 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->cItems
- 1, &ItemInfo
))
1477 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1480 orgY
= ItemInfo
.Rect
.top
;
1481 orgX
= lprect
->right
;
1482 for (i
= MenuInfo
->cItems
- 1; helpPos
<= i
; i
--)
1488 if (ItemInfo
.Rect
.top
!= orgY
)
1490 break; /* Other line */
1492 if (orgX
<= ItemInfo
.Rect
.right
)
1494 break; /* Too far right already */
1496 ItemInfo
.Rect
.left
+= orgX
- ItemInfo
.Rect
.right
;
1497 ItemInfo
.Rect
.right
= orgX
;
1498 orgX
= ItemInfo
.Rect
.left
;
1499 MenuSetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
);
1500 if (helpPos
+ 1 <= i
&&
1501 ! MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
- 1, &ItemInfo
))
1503 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1509 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1512 /***********************************************************************
1513 * MENU_DrawScrollArrows
1515 * Draw scroll arrows.
1518 MENU_DrawScrollArrows(PROSMENUINFO lppop
, HDC hdc
)
1520 HDC hdcMem
= CreateCompatibleDC(hdc
);
1521 HBITMAP hOrigBitmap
;
1522 UINT arrow_bitmap_width
, arrow_bitmap_height
;
1526 GetObjectW(get_down_arrow_bitmap(), sizeof(bmp
), &bmp
);
1527 arrow_bitmap_width
= bmp
.bmWidth
;
1528 arrow_bitmap_height
= bmp
.bmHeight
;
1532 hOrigBitmap
= SelectObject(hdcMem
, get_up_arrow_bitmap());
1534 hOrigBitmap
= SelectObject(hdcMem
, get_up_arrow_inactive_bitmap());
1537 rect
.right
= lppop
->cxMenu
;
1538 rect
.bottom
= arrow_bitmap_height
;
1539 FillRect(hdc
, &rect
, GetSysColorBrush(COLOR_MENU
));
1540 BitBlt(hdc
, (lppop
->cxMenu
- arrow_bitmap_width
) / 2, 0,
1541 arrow_bitmap_width
, arrow_bitmap_height
, hdcMem
, 0, 0, SRCCOPY
);
1542 rect
.top
= lppop
->cyMenu
- arrow_bitmap_height
;
1543 rect
.bottom
= lppop
->cyMenu
;
1544 FillRect(hdc
, &rect
, GetSysColorBrush(COLOR_MENU
));
1545 if (lppop
->iTop
< lppop
->iMaxTop
- (MENU_GetMaxPopupHeight(lppop
) - 2 * arrow_bitmap_height
))
1546 SelectObject(hdcMem
, get_down_arrow_bitmap());
1548 SelectObject(hdcMem
, get_down_arrow_inactive_bitmap());
1549 BitBlt(hdc
, (lppop
->cxMenu
- arrow_bitmap_width
) / 2,
1550 lppop
->cyMenu
- arrow_bitmap_height
,
1551 arrow_bitmap_width
, arrow_bitmap_height
, hdcMem
, 0, 0, SRCCOPY
);
1552 SelectObject(hdcMem
, hOrigBitmap
);
1556 /***********************************************************************
1559 * Draw a single menu item.
1561 static void FASTCALL
MenuDrawMenuItem(HWND hWnd
, PROSMENUINFO MenuInfo
, HWND WndOwner
, HDC hdc
,
1562 PROSMENUITEMINFO lpitem
, UINT Height
, BOOL menuBar
, UINT odaction
)
1566 BOOL flat_menu
= FALSE
;
1568 PWND Wnd
= ValidateHwndNoErr(hWnd
);
1573 if (lpitem
->fType
& MF_SYSMENU
)
1575 if ( (Wnd
->style
& WS_MINIMIZE
))
1577 UserGetInsideRectNC(Wnd
, &rect
);
1578 UserDrawSysMenuButton(hWnd
, hdc
, &rect
, lpitem
->fState
& (MF_HILITE
| MF_MOUSESELECT
));
1583 SystemParametersInfoW (SPI_GETFLATMENU
, 0, &flat_menu
, 0);
1584 bkgnd
= (menuBar
&& flat_menu
) ? COLOR_MENUBAR
: COLOR_MENU
;
1588 if (lpitem
->fState
& MF_HILITE
)
1590 if(menuBar
&& !flat_menu
) {
1591 SetTextColor(hdc
, GetSysColor(COLOR_MENUTEXT
));
1592 SetBkColor(hdc
, GetSysColor(COLOR_MENU
));
1594 if (lpitem
->fState
& MF_GRAYED
)
1595 SetTextColor(hdc
, GetSysColor(COLOR_GRAYTEXT
));
1597 SetTextColor(hdc
, GetSysColor(COLOR_HIGHLIGHTTEXT
));
1598 SetBkColor(hdc
, GetSysColor(COLOR_HIGHLIGHT
));
1603 if (lpitem
->fState
& MF_GRAYED
)
1604 SetTextColor( hdc
, GetSysColor( COLOR_GRAYTEXT
) );
1606 SetTextColor( hdc
, GetSysColor( COLOR_MENUTEXT
) );
1607 SetBkColor( hdc
, GetSysColor( bkgnd
) );
1610 TRACE("rect=%s\n", wine_dbgstr_rect( &lpitem
->Rect
));
1611 rect
= lpitem
->Rect
;
1612 MENU_AdjustMenuItemRect(MenuInfo
, &rect
);
1614 if (lpitem
->fType
& MF_OWNERDRAW
)
1617 ** Experimentation under Windows reveals that an owner-drawn
1618 ** menu is given the rectangle which includes the space it requested
1619 ** in its response to WM_MEASUREITEM _plus_ width for a checkmark
1620 ** and a popup-menu arrow. This is the value of lpitem->rect.
1621 ** Windows will leave all drawing to the application except for
1622 ** the popup-menu arrow. Windows always draws that itself, after
1623 ** the menu owner has finished drawing.
1627 dis
.CtlType
= ODT_MENU
;
1629 dis
.itemID
= lpitem
->wID
;
1630 dis
.itemData
= (DWORD
)lpitem
->dwItemData
;
1632 if (lpitem
->fState
& MF_CHECKED
) dis
.itemState
|= ODS_CHECKED
;
1633 if (lpitem
->fState
& MF_DEFAULT
) dis
.itemState
|= ODS_DEFAULT
;
1634 if (lpitem
->fState
& MF_DISABLED
) dis
.itemState
|= ODS_DISABLED
;
1635 if (lpitem
->fState
& MF_GRAYED
) dis
.itemState
|= ODS_GRAYED
| ODS_DISABLED
;
1636 if (lpitem
->fState
& MF_HILITE
) dis
.itemState
|= ODS_SELECTED
;
1637 //if (!(MenuInfo->fFlags & MNF_UNDERLINE)) dis.itemState |= ODS_NOACCEL;
1638 //if (MenuInfo->fFlags & MNF_INACTIVE) dis.itemState |= ODS_INACTIVE;
1639 dis
.itemAction
= odaction
; /* ODA_DRAWENTIRE | ODA_SELECT | ODA_FOCUS; */
1640 dis
.hwndItem
= (HWND
) MenuInfo
->Self
;
1643 TRACE("Ownerdraw: owner=%p itemID=%d, itemState=%d, itemAction=%d, "
1644 "hwndItem=%p, hdc=%p, rcItem={%ld,%ld,%ld,%ld}\n", hWnd
,
1645 dis
.itemID
, dis
.itemState
, dis
.itemAction
, dis
.hwndItem
,
1646 dis
.hDC
, dis
.rcItem
.left
, dis
.rcItem
.top
, dis
.rcItem
.right
,
1648 SendMessageW(WndOwner
, WM_DRAWITEM
, 0, (LPARAM
) &dis
);
1649 /* Draw the popup-menu arrow */
1650 if (lpitem
->hSubMenu
)
1653 CopyRect(&rectTemp
, &rect
);
1654 rectTemp
.left
= rectTemp
.right
- GetSystemMetrics(SM_CXMENUCHECK
);
1655 DrawFrameControl(hdc
, &rectTemp
, DFC_MENU
, DFCS_MENUARROW
);
1660 if (menuBar
&& (lpitem
->fType
& MF_SEPARATOR
)) return;
1662 if (lpitem
->fState
& MF_HILITE
)
1666 InflateRect (&rect
, -1, -1);
1667 FillRect(hdc
, &rect
, GetSysColorBrush(COLOR_MENUHILIGHT
));
1668 InflateRect (&rect
, 1, 1);
1669 FrameRect(hdc
, &rect
, GetSysColorBrush(COLOR_HIGHLIGHT
));
1674 DrawEdge(hdc
, &rect
, BDR_SUNKENOUTER
, BF_RECT
);
1676 FillRect(hdc
, &rect
, GetSysColorBrush(COLOR_HIGHLIGHT
));
1680 FillRect( hdc
, &rect
, GetSysColorBrush(bkgnd
) );
1682 SetBkMode( hdc
, TRANSPARENT
);
1684 /* vertical separator */
1685 if (!menuBar
&& (lpitem
->fType
& MF_MENUBARBREAK
))
1692 rc
.bottom
= Height
- 3;
1695 oldPen
= SelectObject( hdc
, GetStockObject(DC_PEN
) );
1696 SetDCPenColor(hdc
, GetSysColor(COLOR_BTNSHADOW
));
1697 MoveToEx( hdc
, rc
.left
, rc
.top
, NULL
);
1698 LineTo( hdc
, rc
.left
, rc
.bottom
);
1699 SelectObject( hdc
, oldPen
);
1702 DrawEdge (hdc
, &rc
, EDGE_ETCHED
, BF_LEFT
);
1705 /* horizontal separator */
1706 if (lpitem
->fType
& MF_SEPARATOR
)
1713 rc
.top
+= SEPARATOR_HEIGHT
/ 2;
1716 oldPen
= SelectObject( hdc
, GetStockObject(DC_PEN
) );
1717 SetDCPenColor( hdc
, GetSysColor(COLOR_BTNSHADOW
));
1718 MoveToEx( hdc
, rc
.left
, rc
.top
, NULL
);
1719 LineTo( hdc
, rc
.right
, rc
.top
);
1720 SelectObject( hdc
, oldPen
);
1723 DrawEdge (hdc
, &rc
, EDGE_ETCHED
, BF_TOP
);
1728 /* helper lines for debugging */
1729 /* This is a very good test tool when hacking menus! (JT) 07/16/2006 */
1730 FrameRect(hdc
, &rect
, GetStockObject(BLACK_BRUSH
));
1731 SelectObject(hdc
, GetStockObject(DC_PEN
));
1732 SetDCPenColor(hdc
, GetSysColor(COLOR_WINDOWFRAME
));
1733 MoveToEx(hdc
, rect
.left
, (rect
.top
+ rect
.bottom
) / 2, NULL
);
1734 LineTo(hdc
, rect
.right
, (rect
.top
+ rect
.bottom
) / 2);
1740 INT y
= rect
.top
+ rect
.bottom
;
1742 BOOL checked
= FALSE
;
1743 UINT check_bitmap_width
= GetSystemMetrics( SM_CXMENUCHECK
);
1744 UINT check_bitmap_height
= GetSystemMetrics( SM_CYMENUCHECK
);
1745 /* Draw the check mark
1748 * Custom checkmark bitmaps are monochrome but not always 1bpp.
1750 if( !(MenuInfo
->dwStyle
& MNS_NOCHECK
)) {
1751 bm
= (lpitem
->fState
& MF_CHECKED
) ? lpitem
->hbmpChecked
:
1752 lpitem
->hbmpUnchecked
;
1753 if (bm
) /* we have a custom bitmap */
1755 HDC hdcMem
= CreateCompatibleDC( hdc
);
1757 SelectObject( hdcMem
, bm
);
1758 BitBlt( hdc
, rc
.left
, (y
- check_bitmap_height
) / 2,
1759 check_bitmap_width
, check_bitmap_height
,
1760 hdcMem
, 0, 0, SRCCOPY
);
1764 else if (lpitem
->fState
& MF_CHECKED
) /* standard bitmaps */
1767 CopyRect(&r
, &rect
);
1768 r
.right
= r
.left
+ GetSystemMetrics(SM_CXMENUCHECK
);
1769 DrawFrameControl( hdc
, &r
, DFC_MENU
,
1770 (lpitem
->fType
& MFT_RADIOCHECK
) ?
1771 DFCS_MENUBULLET
: DFCS_MENUCHECK
);
1775 if ( lpitem
->hbmpItem
)
1778 CopyRect(&bmpRect
, &rect
);
1779 if (!(MenuInfo
->dwStyle
& MNS_CHECKORBMP
) && !(MenuInfo
->dwStyle
& MNS_NOCHECK
))
1780 bmpRect
.left
+= check_bitmap_width
+ 2;
1781 if (!(checked
&& (MenuInfo
->dwStyle
& MNS_CHECKORBMP
)))
1783 bmpRect
.right
= bmpRect
.left
+ lpitem
->maxBmpSize
.cx
;
1784 MenuDrawBitmapItem(hdc
, lpitem
, &bmpRect
, MenuInfo
, WndOwner
, odaction
, menuBar
);
1787 /* Draw the popup-menu arrow */
1788 if (lpitem
->hSubMenu
)
1791 CopyRect(&rectTemp
, &rect
);
1792 rectTemp
.left
= rectTemp
.right
- GetSystemMetrics(SM_CXMENUCHECK
);
1793 DrawFrameControl(hdc
, &rectTemp
, DFC_MENU
, DFCS_MENUARROW
);
1796 if( !(MenuInfo
->dwStyle
& MNS_NOCHECK
))
1797 rect
.left
+= check_bitmap_width
;
1798 rect
.right
-= check_bitmap_width
;
1800 else if( lpitem
->hbmpItem
)
1801 { /* Draw the bitmap */
1802 MenuDrawBitmapItem(hdc
, lpitem
, &rect
, MenuInfo
, WndOwner
, odaction
, menuBar
);
1805 /* process text if present */
1811 UINT uFormat
= menuBar
?
1812 DT_CENTER
| DT_VCENTER
| DT_SINGLELINE
:
1813 DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
;
1815 if((MenuInfo
->dwStyle
& MNS_CHECKORBMP
))
1816 rect
.left
+= max(0, (int)(MenuInfo
->cxTextAlign
- GetSystemMetrics(SM_CXMENUCHECK
)));
1818 rect
.left
+= MenuInfo
->cxTextAlign
;
1820 if ( lpitem
->fState
& MFS_DEFAULT
)
1822 hfontOld
= SelectObject(hdc
, hMenuFontBold
);
1826 rect
.left
+= MENU_BAR_ITEMS_SPACE
/ 2;
1827 rect
.right
-= MENU_BAR_ITEMS_SPACE
/ 2;
1830 Text
= (PWCHAR
) lpitem
->dwTypeData
;
1833 for (i
= 0; L
'\0' != Text
[i
]; i
++)
1834 if (Text
[i
] == L
'\t' || Text
[i
] == L
'\b')
1838 if(lpitem
->fState
& MF_GRAYED
)
1840 if (!(lpitem
->fState
& MF_HILITE
) )
1842 ++rect
.left
; ++rect
.top
; ++rect
.right
; ++rect
.bottom
;
1843 SetTextColor(hdc
, RGB(0xff, 0xff, 0xff));
1844 DrawTextW( hdc
, Text
, i
, &rect
, uFormat
);
1845 --rect
.left
; --rect
.top
; --rect
.right
; --rect
.bottom
;
1847 SetTextColor(hdc
, RGB(0x80, 0x80, 0x80));
1850 DrawTextW( hdc
, Text
, i
, &rect
, uFormat
);
1852 /* paint the shortcut text */
1853 if (!menuBar
&& L
'\0' != Text
[i
]) /* There's a tab or flush-right char */
1855 if (L
'\t' == Text
[i
])
1857 rect
.left
= lpitem
->dxTab
;
1858 uFormat
= DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
;
1862 rect
.right
= lpitem
->dxTab
;
1863 uFormat
= DT_RIGHT
| DT_VCENTER
| DT_SINGLELINE
;
1866 if (lpitem
->fState
& MF_GRAYED
)
1868 if (!(lpitem
->fState
& MF_HILITE
) )
1870 ++rect
.left
; ++rect
.top
; ++rect
.right
; ++rect
.bottom
;
1871 SetTextColor(hdc
, RGB(0xff, 0xff, 0xff));
1872 DrawTextW( hdc
, Text
+ i
+ 1, -1, &rect
, uFormat
);
1873 --rect
.left
; --rect
.top
; --rect
.right
; --rect
.bottom
;
1875 SetTextColor(hdc
, RGB(0x80, 0x80, 0x80));
1877 DrawTextW( hdc
, Text
+ i
+ 1, -1, &rect
, uFormat
);
1881 SelectObject (hdc
, hfontOld
);
1885 /***********************************************************************
1888 * Paint a popup menu.
1890 static void FASTCALL
MenuDrawPopupMenu(HWND hwnd
, HDC hdc
, HMENU hmenu
)
1892 HBRUSH hPrevBrush
= 0;
1895 TRACE("wnd=%p dc=%p menu=%p\n", hwnd
, hdc
, hmenu
);
1897 GetClientRect( hwnd
, &rect
);
1899 if((hPrevBrush
= SelectObject( hdc
, GetSysColorBrush(COLOR_MENU
) ))
1900 && (SelectObject( hdc
, hMenuFont
)))
1904 Rectangle( hdc
, rect
.left
, rect
.top
, rect
.right
, rect
.bottom
);
1906 hPrevPen
= SelectObject( hdc
, GetStockObject( NULL_PEN
) );
1909 BOOL flat_menu
= FALSE
;
1910 ROSMENUINFO MenuInfo
;
1911 ROSMENUITEMINFO ItemInfo
;
1913 SystemParametersInfoW (SPI_GETFLATMENU
, 0, &flat_menu
, 0);
1915 FrameRect(hdc
, &rect
, GetSysColorBrush(COLOR_BTNSHADOW
));
1917 DrawEdge (hdc
, &rect
, EDGE_RAISED
, BF_RECT
);
1919 /* draw menu items */
1920 //TRACE("hmenu %p Style %08x\n", hmenu, menu->dwStyle);
1921 if (MenuGetRosMenuInfo(&MenuInfo
, hmenu
) && MenuInfo
.cItems
)
1924 MenuInitRosMenuItemInfo(&ItemInfo
);
1926 for (u
= 0; u
< MenuInfo
.cItems
; u
++)
1928 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, u
, &ItemInfo
))
1930 HWND WndOwner
= MenuInfo
.spwndNotify
? MenuInfo
.spwndNotify
->head
.h
: NULL
;
1931 MenuDrawMenuItem(hwnd
, &MenuInfo
, WndOwner
, hdc
, &ItemInfo
,
1932 MenuInfo
.cyMenu
, FALSE
, ODA_DRAWENTIRE
);
1936 /* draw scroll arrows */
1937 if (MenuInfo
.dwArrowsOn
)
1938 MENU_DrawScrollArrows(&MenuInfo
, hdc
);
1940 MenuSetRosMenuInfo(&MenuInfo
);
1941 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1945 SelectObject( hdc
, hPrevBrush
);
1950 /***********************************************************************
1953 * Paint a menu bar. Returns the height of the menu bar.
1954 * called from [windows/nonclient.c]
1956 UINT
MenuDrawMenuBar( HDC hDC
, LPRECT lprect
, HWND hwnd
,
1961 HMENU hMenu
= GetMenu(hwnd
);
1963 if (! MenuGetRosMenuInfo(&lppop
, hMenu
) || lprect
== NULL
)
1965 return GetSystemMetrics(SM_CYMENU
);
1970 hfontOld
= SelectObject(hDC
, hMenuFont
);
1972 MenuMenuBarCalcSize(hDC
, lprect
, &lppop
, hwnd
);
1974 lprect
->bottom
= lprect
->top
+ lppop
.cyMenu
;
1976 if (hfontOld
) SelectObject( hDC
, hfontOld
);
1977 return lppop
.cyMenu
;
1980 return DrawMenuBarTemp(hwnd
, hDC
, lprect
, hMenu
, NULL
);
1983 /***********************************************************************
1986 * Popup menu initialization before WM_ENTERMENULOOP.
1988 static BOOL
MENU_InitPopup( HWND hwndOwner
, HMENU hmenu
, UINT flags
)
1992 ROSMENUINFO MenuInfo
;
1994 TRACE("owner=%p hmenu=%p\n", hwndOwner
, hmenu
);
1996 if (!(menu
= MENU_GetMenu( hmenu
))) return FALSE
;
1998 /* store the owner for DrawItem */
1999 if (!IsWindow( hwndOwner
))
2001 SetLastError( ERROR_INVALID_WINDOW_HANDLE
);
2004 MenuGetRosMenuInfo(&MenuInfo
, menu
->head
.h
);
2005 //menu->hwndOwner = hwndOwner;
2006 MenuInfo
.spwndNotify
= ValidateHwndNoErr( hwndOwner
);
2008 if (flags
& TPM_LAYOUTRTL
)
2009 ex_style
= WS_EX_LAYOUTRTL
;
2011 /* NOTE: In Windows, top menu popup is not owned. */
2012 //menu->hWnd = CreateWindowExW( ex_style, WC_MENU, NULL,
2013 MenuInfo
.Wnd
= CreateWindowExW( ex_style
, WC_MENU
, NULL
,
2014 WS_POPUP
, 0, 0, 0, 0,
2015 hwndOwner
, 0, (HINSTANCE
)GetWindowLongPtrW(hwndOwner
, GWLP_HINSTANCE
),
2017 MenuSetRosMenuInfo(&MenuInfo
);
2018 if( !menu
->hWnd
) return FALSE
;
2022 /***********************************************************************
2025 * Display a popup menu.
2027 static BOOL FASTCALL
MenuShowPopup(HWND hwndOwner
, HMENU hmenu
, UINT id
, UINT flags
,
2028 INT x
, INT y
, INT xanchor
, INT yanchor
)
2030 ROSMENUINFO MenuInfo
;
2031 ROSMENUITEMINFO ItemInfo
;
2037 TRACE("owner=%p hmenu=%p id=0x%04x x=0x%04x y=0x%04x xa=0x%04x ya=0x%04x\n",
2038 hwndOwner
, hmenu
, id
, x
, y
, xanchor
, yanchor
);
2040 if (! MenuGetRosMenuInfo(&MenuInfo
, hmenu
)) return FALSE
;
2041 if (MenuInfo
.iItem
!= NO_SELECTED_ITEM
)
2043 MenuInitRosMenuItemInfo(&ItemInfo
);
2044 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, MenuInfo
.iItem
, &ItemInfo
))
2046 ItemInfo
.fMask
|= MIIM_STATE
;
2047 ItemInfo
.fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
2048 MenuSetRosMenuItemInfo(MenuInfo
.Self
, MenuInfo
.iItem
, &ItemInfo
);
2050 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2051 MenuInfo
.iItem
= NO_SELECTED_ITEM
;
2054 //menu->dwArrowsOn = 0;
2055 MenuInfo
.dwArrowsOn
= 0;
2056 MenuSetRosMenuInfo(&MenuInfo
);
2057 MenuPopupMenuCalcSize(&MenuInfo
, hwndOwner
);
2059 /* adjust popup menu pos so that it fits within the desktop */
2061 width
= MenuInfo
.cxMenu
+ GetSystemMetrics(SM_CXBORDER
);
2062 height
= MenuInfo
.cyMenu
+ GetSystemMetrics(SM_CYBORDER
);
2064 /* FIXME: should use item rect */
2067 monitor
= MonitorFromPoint( pt
, MONITOR_DEFAULTTONEAREST
);
2068 info
.cbSize
= sizeof(info
);
2069 GetMonitorInfoW( monitor
, &info
);
2071 if (flags
& TPM_LAYOUTRTL
)
2072 flags
^= TPM_RIGHTALIGN
;
2074 if( flags
& TPM_RIGHTALIGN
) x
-= width
;
2075 if( flags
& TPM_CENTERALIGN
) x
-= width
/ 2;
2077 if( flags
& TPM_BOTTOMALIGN
) y
-= height
;
2078 if( flags
& TPM_VCENTERALIGN
) y
-= height
/ 2;
2080 if( x
+ width
> info
.rcMonitor
.right
)
2082 if( xanchor
&& x
>= width
- xanchor
)
2083 x
-= width
- xanchor
;
2085 if( x
+ width
> info
.rcMonitor
.right
)
2086 x
= info
.rcMonitor
.right
- width
;
2088 if( x
< info
.rcMonitor
.left
) x
= info
.rcMonitor
.left
;
2090 if( y
+ height
> info
.rcMonitor
.bottom
)
2092 if( yanchor
&& y
>= height
+ yanchor
)
2093 y
-= height
+ yanchor
;
2095 if( y
+ height
> info
.rcMonitor
.bottom
)
2096 y
= info
.rcMonitor
.bottom
- height
;
2098 if( y
< info
.rcMonitor
.top
) y
= info
.rcMonitor
.top
;
2101 top_popup
= MenuInfo
.Wnd
;
2102 top_popup_hmenu
= hmenu
;
2104 /* Display the window */
2106 SetWindowPos( MenuInfo
.Wnd
, HWND_TOPMOST
, x
, y
, width
, height
,
2107 SWP_SHOWWINDOW
| SWP_NOACTIVATE
);
2108 UpdateWindow( MenuInfo
.Wnd
);
2110 IntNotifyWinEvent(EVENT_SYSTEM_MENUPOPUPSTART
, MenuInfo
.Wnd
, OBJID_CLIENT
, CHILDID_SELF
, 0);
2115 /***********************************************************************
2116 * MENU_EnsureMenuItemVisible
2119 MENU_EnsureMenuItemVisible(PROSMENUINFO lppop
, PROSMENUITEMINFO item
, HDC hdc
)
2121 if (lppop
->dwArrowsOn
)
2123 //ITEM *item = &lppop->items[wIndex];
2124 UINT nMaxHeight
= MENU_GetMaxPopupHeight(lppop
);
2125 UINT nOldPos
= lppop
->iTop
;
2127 UINT arrow_bitmap_height
;
2130 GetClientRect(lppop
->Wnd
, &rc
);
2132 GetObjectW(get_down_arrow_bitmap(), sizeof(bmp
), &bmp
);
2133 arrow_bitmap_height
= bmp
.bmHeight
;
2135 rc
.top
+= arrow_bitmap_height
;
2136 rc
.bottom
-= arrow_bitmap_height
+ MENU_BOTTOM_MARGIN
;
2138 nMaxHeight
-= GetSystemMetrics(SM_CYBORDER
) + 2 * arrow_bitmap_height
;
2139 if (item
->Rect
.bottom
> lppop
->iTop
+ nMaxHeight
)
2141 lppop
->iTop
= item
->Rect
.bottom
- nMaxHeight
;
2142 ScrollWindow(lppop
->Wnd
, 0, nOldPos
- lppop
->iTop
, &rc
, &rc
);
2143 MENU_DrawScrollArrows(lppop
, hdc
);
2145 else if (item
->Rect
.top
- MENU_TOP_MARGIN
< lppop
->iTop
)
2147 lppop
->iTop
= item
->Rect
.top
- MENU_TOP_MARGIN
;
2148 ScrollWindow(lppop
->Wnd
, 0, nOldPos
- lppop
->iTop
, &rc
, &rc
);
2149 MENU_DrawScrollArrows(lppop
, hdc
);
2154 /***********************************************************************
2157 static void FASTCALL
MenuSelectItem(HWND hwndOwner
, PROSMENUINFO hmenu
, UINT wIndex
,
2158 BOOL sendMenuSelect
, HMENU topmenu
)
2160 ROSMENUITEMINFO ItemInfo
;
2161 ROSMENUINFO TopMenuInfo
;
2164 TRACE("owner=%p menu=%p index=0x%04x select=0x%04x\n", hwndOwner
, hmenu
, wIndex
, sendMenuSelect
);
2166 if (!hmenu
|| !hmenu
->cItems
|| !hmenu
->Wnd
) return;
2167 if (hmenu
->iItem
== wIndex
) return;
2168 if (hmenu
->fFlags
& MNF_POPUP
) hdc
= GetDC(hmenu
->Wnd
);
2169 else hdc
= GetDCEx(hmenu
->Wnd
, 0, DCX_CACHE
| DCX_WINDOW
);
2171 top_popup
= hmenu
->Wnd
;
2172 top_popup_hmenu
= hmenu
->Self
;
2175 SelectObject( hdc
, hMenuFont
);
2177 MenuInitRosMenuItemInfo(&ItemInfo
);
2179 /* Clear previous highlighted item */
2180 if (hmenu
->iItem
!= NO_SELECTED_ITEM
)
2182 if (MenuGetRosMenuItemInfo(hmenu
->Self
, hmenu
->iItem
, &ItemInfo
))
2184 ItemInfo
.fMask
|= MIIM_STATE
;
2185 ItemInfo
.fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
2186 MenuSetRosMenuItemInfo(hmenu
->Self
, hmenu
->iItem
, &ItemInfo
);
2188 //MENU_EnsureMenuItemVisible(hmenu, &ItemInfo, hdc);
2189 MenuDrawMenuItem(hmenu
->Wnd
, hmenu
, hwndOwner
, hdc
, &ItemInfo
,
2190 hmenu
->cyMenu
, !(hmenu
->fFlags
& MNF_POPUP
),
2194 /* Highlight new item (if any) */
2195 hmenu
->iItem
= wIndex
;
2196 MenuSetRosMenuInfo(hmenu
);
2197 if (hmenu
->iItem
!= NO_SELECTED_ITEM
)
2199 if (MenuGetRosMenuItemInfo(hmenu
->Self
, hmenu
->iItem
, &ItemInfo
))
2201 if (!(ItemInfo
.fType
& MF_SEPARATOR
))
2203 ItemInfo
.fMask
|= MIIM_STATE
;
2204 ItemInfo
.fState
|= MF_HILITE
;
2205 MenuSetRosMenuItemInfo(hmenu
->Self
, hmenu
->iItem
, &ItemInfo
);
2206 MenuDrawMenuItem(hmenu
->Wnd
, hmenu
, hwndOwner
, hdc
,
2207 &ItemInfo
, hmenu
->cyMenu
, !(hmenu
->fFlags
& MNF_POPUP
),
2212 WPARAM wParam
= MAKEWPARAM( ItemInfo
.hSubMenu
? wIndex
: ItemInfo
.wID
,
2213 ItemInfo
.fType
| ItemInfo
.fState
|
2214 (ItemInfo
.hSubMenu
? MF_POPUP
: 0) |
2215 (hmenu
->fFlags
& MNF_SYSDESKMN
? MF_SYSMENU
: 0 ) );
2217 SendMessageW(hwndOwner
, WM_MENUSELECT
, wParam
, (LPARAM
) hmenu
->Self
);
2221 else if (sendMenuSelect
)
2226 pos
= MenuFindSubMenu(&topmenu
, hmenu
->Self
);
2227 if (pos
!= NO_SELECTED_ITEM
)
2229 if (MenuGetRosMenuInfo(&TopMenuInfo
, topmenu
)
2230 && MenuGetRosMenuItemInfo(topmenu
, pos
, &ItemInfo
))
2232 WPARAM wParam
= MAKEWPARAM( Pos
, ItemInfo
.fType
| ItemInfo
.fState
|
2233 (ItemInfo
.hSubMenu
? MF_POPUP
: 0) |
2234 (TopMenuInfo
.fFlags
& MNF_SYSDESKMN
? MF_SYSMENU
: 0 ) );
2236 SendMessageW(hwndOwner
, WM_MENUSELECT
, wParam
, (LPARAM
) topmenu
);
2241 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2242 ReleaseDC(hmenu
->Wnd
, hdc
);
2245 /***********************************************************************
2248 * Moves currently selected item according to the Offset parameter.
2249 * If there is no selection then it should select the last item if
2250 * Offset is ITEM_PREV or the first item if Offset is ITEM_NEXT.
2252 static void FASTCALL
2253 MenuMoveSelection(HWND WndOwner
, PROSMENUINFO MenuInfo
, INT Offset
)
2256 ROSMENUITEMINFO ItemInfo
;
2259 TRACE("hwnd=%x menu=%x off=0x%04x\n", WndOwner
, MenuInfo
, Offset
);
2261 /* Prevent looping */
2262 if (0 == MenuInfo
->cItems
|| 0 == Offset
)
2264 else if (Offset
< -1)
2266 else if (Offset
> 1)
2269 MenuInitRosMenuItemInfo(&ItemInfo
);
2271 OrigPos
= MenuInfo
->iItem
;
2272 if (OrigPos
== NO_SELECTED_ITEM
) /* NO_SELECTED_ITEM is not -1 ! */
2279 i
= MenuInfo
->iItem
;
2286 /* Clip and wrap around */
2289 i
= MenuInfo
->cItems
- 1;
2291 else if (i
>= MenuInfo
->cItems
)
2295 /* If this is a good candidate; */
2296 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
) &&
2297 0 == (ItemInfo
.fType
& MF_SEPARATOR
))
2299 MenuSelectItem(WndOwner
, MenuInfo
, i
, TRUE
, NULL
);
2300 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2303 } while (i
!= OrigPos
);
2306 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2311 PopupMenuWndProcW(HWND Wnd
, UINT Message
, WPARAM wParam
, LPARAM lParam
)
2313 #ifdef __REACTOS__ // Do this now, remove after Server side is fixed.
2315 PPOPUPMENU pPopupMenu
;
2317 pWnd
= ValidateHwndNoErr(Wnd
);
2322 if (Message
!= WM_NCCREATE
)
2324 return DefWindowProcW(Wnd
, Message
, wParam
, lParam
);
2326 NtUserSetWindowFNID(Wnd
, FNID_MENU
);
2327 pPopupMenu
= HeapAlloc( GetProcessHeap(), 0, sizeof(POPUPMENU
) );
2328 pPopupMenu
->spwndPopupMenu
= pWnd
;
2329 SetWindowLongPtrW(Wnd
, 0, (LONG_PTR
)pPopupMenu
);
2333 if (pWnd
->fnid
!= FNID_MENU
)
2335 ERR("Wrong window class for Menu!\n");
2338 pPopupMenu
= ((PMENUWND
)pWnd
)->ppopupmenu
;
2343 TRACE("hwnd=%x msg=0x%04x wp=0x%04lx lp=0x%08lx\n", Wnd
, Message
, wParam
, lParam
);
2349 CREATESTRUCTW
*cs
= (CREATESTRUCTW
*) lParam
;
2350 pPopupMenu
->spmenu
= ValidateHandle(cs
->lpCreateParams
, TYPE_MENU
);
2354 case WM_MOUSEACTIVATE
: /* We don't want to be activated */
2355 return MA_NOACTIVATE
;
2360 BeginPaint(Wnd
, &ps
);
2361 MenuDrawPopupMenu(Wnd
, ps
.hdc
, pPopupMenu
->spmenu
->head
.h
);
2366 case WM_PRINTCLIENT
:
2368 MenuDrawPopupMenu( Wnd
, (HDC
)wParam
, pPopupMenu
->spmenu
->head
.h
);
2376 /* zero out global pointer in case resident popup window was destroyed. */
2377 if (Wnd
== top_popup
)
2380 top_popup_hmenu
= NULL
;
2386 HeapFree( GetProcessHeap(), 0, pPopupMenu
);
2387 SetWindowLongPtrW(Wnd
, 0, 0);
2388 NtUserSetWindowFNID(Wnd
, FNID_DESTROY
);
2395 if (!pPopupMenu
|| !pPopupMenu
->spmenu
)
2397 OutputDebugStringA("no menu to display\n");
2402 pPopupMenu->spmenu = NULL; ///// WTF?
2406 case MM_SETMENUHANDLE
:
2408 PMENU pmenu
= ValidateHandle((HMENU
)wParam
, TYPE_MENU
);
2411 ERR("Bad Menu Handle\n");
2414 pPopupMenu
->spmenu
= pmenu
;
2418 case MM_GETMENUHANDLE
:
2420 return (LRESULT
)(pPopupMenu
? (pPopupMenu
->spmenu
? pPopupMenu
->spmenu
->head
.h
: NULL
) : NULL
);
2423 return DefWindowProcW(Wnd
, Message
, wParam
, lParam
);
2431 PopupMenuWndProcW(HWND Wnd
, UINT Message
, WPARAM wParam
, LPARAM lParam
)
2433 #ifdef __REACTOS__ // Do this now, remove after Server side is fixed.
2436 pWnd
= ValidateHwnd(Wnd
);
2441 if (Message
!= WM_NCCREATE
)
2443 return DefWindowProcW(Wnd
, Message
, wParam
, lParam
);
2445 NtUserSetWindowFNID(Wnd
, FNID_MENU
);
2449 if (pWnd
->fnid
!= FNID_MENU
)
2451 ERR("Wrong window class for Menu!\n");
2458 TRACE("hwnd=%x msg=0x%04x wp=0x%04lx lp=0x%08lx\n", Wnd
, Message
, wParam
, lParam
);
2464 CREATESTRUCTW
*cs
= (CREATESTRUCTW
*) lParam
;
2465 SetWindowLongPtrW(Wnd
, 0, (LONG_PTR
)cs
->lpCreateParams
);
2469 case WM_MOUSEACTIVATE
: /* We don't want to be activated */
2470 return MA_NOACTIVATE
;
2475 BeginPaint(Wnd
, &ps
);
2476 MenuDrawPopupMenu(Wnd
, ps
.hdc
, (HMENU
)GetWindowLongPtrW(Wnd
, 0));
2481 case WM_PRINTCLIENT
:
2483 MenuDrawPopupMenu( Wnd
, (HDC
)wParam
,
2484 (HMENU
)GetWindowLongPtrW( Wnd
, 0 ) );
2492 /* zero out global pointer in case resident popup window was destroyed. */
2493 if (Wnd
== top_popup
)
2496 top_popup_hmenu
= NULL
;
2502 NtUserSetWindowFNID(Wnd
, FNID_DESTROY
);
2509 if (0 == GetWindowLongPtrW(Wnd
, 0))
2511 OutputDebugStringA("no menu to display\n");
2516 SetWindowLongPtrW(Wnd
, 0, 0);
2520 case MM_SETMENUHANDLE
:
2521 SetWindowLongPtrW(Wnd
, 0, wParam
);
2524 case MM_GETMENUHANDLE
:
2526 return GetWindowLongPtrW(Wnd
, 0);
2529 return DefWindowProcW(Wnd
, Message
, wParam
, lParam
);
2536 // This breaks some test results. Should handle A2U if called!
2538 LRESULT WINAPI
PopupMenuWndProcA(HWND Wnd
, UINT Message
, WPARAM wParam
, LPARAM lParam
)
2542 pWnd
= ValidateHwnd(Wnd
);
2543 if (pWnd
&& !pWnd
->fnid
&& Message
!= WM_NCCREATE
)
2545 return DefWindowProcA(Wnd
, Message
, wParam
, lParam
);
2547 TRACE("YES! hwnd=%x msg=0x%04x wp=0x%04lx lp=0x%08lx\n", Wnd
, Message
, wParam
, lParam
);
2553 case WM_MOUSEACTIVATE
:
2555 case WM_PRINTCLIENT
:
2560 case MM_SETMENUHANDLE
:
2561 case MM_GETMENUHANDLE
:
2563 return PopupMenuWndProcW(Wnd
, Message
, wParam
, lParam
);
2566 return DefWindowProcA(Wnd
, Message
, wParam
, lParam
);
2571 /**********************************************************************
2572 * MENU_ParseResource
2574 * Parse a standard menu resource and add items to the menu.
2575 * Return a pointer to the end of the resource.
2577 * NOTE: flags is equivalent to the mtOption field
2579 static LPCSTR
MENU_ParseResource( LPCSTR res
, HMENU hMenu
)
2588 flags
= GET_WORD(res
);
2590 /* remove MF_END flag before passing it to AppendMenu()! */
2591 end
= (flags
& MF_END
);
2592 if(end
) flags
^= MF_END
;
2594 res
+= sizeof(WORD
);
2595 if(!(flags
& MF_POPUP
))
2598 res
+= sizeof(WORD
);
2601 res
+= (strlenW(str
) + 1) * sizeof(WCHAR
);
2603 if (flags
& MF_POPUP
)
2605 hSubMenu
= CreatePopupMenu();
2606 if(!hSubMenu
) return NULL
;
2607 if(!(res
= MENU_ParseResource(res
, hSubMenu
))) return NULL
;
2608 AppendMenuW(hMenu
, flags
, (UINT_PTR
)hSubMenu
, (LPCWSTR
)str
);
2610 else /* Not a popup */
2612 AppendMenuW(hMenu
, flags
, id
, *(LPCWSTR
)str
? (LPCWSTR
)str
: NULL
);
2618 /**********************************************************************
2619 * MENUEX_ParseResource
2621 * Parse an extended menu resource and add items to the menu.
2622 * Return a pointer to the end of the resource.
2624 static LPCSTR
MENUEX_ParseResource(LPCSTR res
, HMENU hMenu
)
2631 mii
.cbSize
= sizeof(mii
);
2632 mii
.fMask
= MIIM_STATE
| MIIM_ID
| MIIM_TYPE
;
2633 mii
.fType
= GET_DWORD(res
);
2634 res
+= sizeof(DWORD
);
2635 mii
.fState
= GET_DWORD(res
);
2636 res
+= sizeof(DWORD
);
2637 mii
.wID
= GET_DWORD(res
);
2638 res
+= sizeof(DWORD
);
2639 resinfo
= GET_WORD(res
);
2640 res
+= sizeof(WORD
);
2641 /* Align the text on a word boundary. */
2642 res
+= (~((UINT_PTR
)res
- 1)) & 1;
2643 mii
.dwTypeData
= (LPWSTR
)res
;
2644 mii
.cch
= strlenW(mii
.dwTypeData
);
2645 res
+= (1 + strlenW(mii
.dwTypeData
)) * sizeof(WCHAR
);
2646 /* Align the following fields on a dword boundary. */
2647 res
+= (~((UINT_PTR
)res
- 1)) & 3;
2649 TRACE("Menu item: [%08x,%08x,%04x,%04x,%S]\n",
2650 mii
.fType
, mii
.fState
, mii
.wID
, resinfo
, mii
.dwTypeData
);
2652 if (resinfo
& 1) /* Pop-up? */
2654 /* DWORD helpid = GET_DWORD(res); FIXME: use this. */
2655 res
+= sizeof(DWORD
);
2656 mii
.hSubMenu
= CreatePopupMenu();
2659 ERR("CreatePopupMenu failed\n");
2663 if (!(res
= MENUEX_ParseResource(res
, mii
.hSubMenu
)))
2665 ERR("MENUEX_ParseResource failed\n");
2666 DestroyMenu(mii
.hSubMenu
);
2669 mii
.fMask
|= MIIM_SUBMENU
;
2671 else if (!mii
.dwTypeData
[0] && !(mii
.fType
& MF_SEPARATOR
))
2673 mii
.fType
|= MF_SEPARATOR
;
2675 InsertMenuItemW(hMenu
, -1, MF_BYPOSITION
, &mii
);
2676 } while (!(resinfo
& MF_END
));
2681 /***********************************************************************
2682 * DrawMenuBarTemp (USER32.@)
2686 * called by W98SE desk.cpl Control Panel Applet
2688 * Not 100% sure about the param names, but close.
2693 DrawMenuBarTemp(HWND Wnd
, HDC DC
, LPRECT Rect
, HMENU Menu
, HFONT Font
)
2695 ROSMENUINFO MenuInfo
;
2696 ROSMENUITEMINFO ItemInfo
;
2698 HFONT FontOld
= NULL
;
2699 BOOL flat_menu
= FALSE
;
2701 SystemParametersInfoW (SPI_GETFLATMENU
, 0, &flat_menu
, 0);
2705 Menu
= GetMenu(Wnd
);
2713 if (NULL
== Rect
|| ! MenuGetRosMenuInfo(&MenuInfo
, Menu
))
2715 return GetSystemMetrics(SM_CYMENU
);
2718 TRACE("(%x, %x, %p, %x, %x)\n", Wnd
, DC
, Rect
, Menu
, Font
);
2720 FontOld
= SelectObject(DC
, Font
);
2722 if (0 == MenuInfo
.cyMenu
)
2724 MenuMenuBarCalcSize(DC
, Rect
, &MenuInfo
, Wnd
);
2727 Rect
->bottom
= Rect
->top
+ MenuInfo
.cyMenu
;
2729 FillRect(DC
, Rect
, GetSysColorBrush(flat_menu
? COLOR_MENUBAR
: COLOR_MENU
));
2731 SelectObject(DC
, GetStockObject(DC_PEN
));
2732 SetDCPenColor(DC
, GetSysColor(COLOR_3DFACE
));
2733 MoveToEx(DC
, Rect
->left
, Rect
->bottom
- 1, NULL
);
2734 LineTo(DC
, Rect
->right
, Rect
->bottom
- 1);
2736 if (0 == MenuInfo
.cItems
)
2738 SelectObject(DC
, FontOld
);
2739 return GetSystemMetrics(SM_CYMENU
);
2742 MenuInitRosMenuItemInfo(&ItemInfo
);
2743 for (i
= 0; i
< MenuInfo
.cItems
; i
++)
2745 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, i
, &ItemInfo
))
2747 MenuDrawMenuItem(Wnd
, &MenuInfo
, Wnd
, DC
, &ItemInfo
,
2748 MenuInfo
.cyMenu
, TRUE
, ODA_DRAWENTIRE
);
2751 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2753 SelectObject(DC
, FontOld
);
2755 return MenuInfo
.cyMenu
;
2759 /***********************************************************************
2762 * Display the sub-menu of the selected item of this menu.
2763 * Return the handle of the submenu, or menu if no submenu to display.
2765 static HMENU FASTCALL
2766 MenuShowSubPopup(HWND WndOwner
, PROSMENUINFO MenuInfo
, BOOL SelectFirst
, UINT Flags
)
2769 ROSMENUITEMINFO ItemInfo
;
2770 ROSMENUINFO SubMenuInfo
;
2774 TRACE("owner=%x menu=%p 0x%04x\n", WndOwner
, MenuInfo
, SelectFirst
);
2776 if (NO_SELECTED_ITEM
== MenuInfo
->iItem
)
2778 return MenuInfo
->Self
;
2781 MenuInitRosMenuItemInfo(&ItemInfo
);
2782 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->iItem
, &ItemInfo
))
2784 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2785 return MenuInfo
->Self
;
2787 if (0 == (ItemInfo
.hSubMenu
) || 0 != (ItemInfo
.fState
& (MF_GRAYED
| MF_DISABLED
)))
2789 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2790 return MenuInfo
->Self
;
2793 /* message must be sent before using item,
2794 because nearly everything may be changed by the application ! */
2796 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
2797 if (0 == (Flags
& TPM_NONOTIFY
))
2799 SendMessageW(WndOwner
, WM_INITMENUPOPUP
, (WPARAM
) ItemInfo
.hSubMenu
,
2800 MAKELPARAM(MenuInfo
->iItem
, IS_SYSTEM_MENU(MenuInfo
)));
2803 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->iItem
, &ItemInfo
))
2805 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2806 return MenuInfo
->Self
;
2808 Rect
= ItemInfo
.Rect
;
2810 /* correct item if modified as a reaction to WM_INITMENUPOPUP message */
2811 if (0 == (ItemInfo
.fState
& MF_HILITE
))
2813 if (0 != (MenuInfo
->fFlags
& MNF_POPUP
))
2815 Dc
= GetDC(MenuInfo
->Wnd
);
2819 Dc
= GetDCEx(MenuInfo
->Wnd
, 0, DCX_CACHE
| DCX_WINDOW
);
2822 SelectObject(Dc
, hMenuFont
);
2823 ItemInfo
.fMask
|= MIIM_STATE
;
2824 ItemInfo
.fState
|= MF_HILITE
;
2825 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->iItem
, &ItemInfo
);
2826 MenuDrawMenuItem(MenuInfo
->Wnd
, MenuInfo
, WndOwner
, Dc
, &ItemInfo
, MenuInfo
->cyMenu
,
2827 !(MenuInfo
->fFlags
& MNF_POPUP
), ODA_DRAWENTIRE
);
2828 ReleaseDC(MenuInfo
->Wnd
, Dc
);
2831 if (0 == ItemInfo
.Rect
.top
&& 0 == ItemInfo
.Rect
.left
2832 && 0 == ItemInfo
.Rect
.bottom
&& 0 == ItemInfo
.Rect
.right
)
2834 ItemInfo
.Rect
= Rect
;
2837 ItemInfo
.fMask
|= MIIM_STATE
;
2838 ItemInfo
.fState
|= MF_MOUSESELECT
;
2839 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->iItem
, &ItemInfo
);
2841 if (IS_SYSTEM_MENU(MenuInfo
))
2843 ERR("Right click on window bar and Draw system menu!\n");
2844 MenuInitSysMenuPopup(ItemInfo
.hSubMenu
, GetWindowLongPtrW(MenuInfo
->Wnd
, GWL_STYLE
),
2845 GetClassLongPtrW(MenuInfo
->Wnd
, GCL_STYLE
), HTSYSMENU
);
2846 if (Flags
& TPM_LAYOUTRTL
) Rect
.left
;
2847 NcGetSysPopupPos(MenuInfo
->Wnd
, &Rect
);
2848 Rect
.top
= Rect
.bottom
;
2849 Rect
.right
= GetSystemMetrics(SM_CXSIZE
);
2850 Rect
.bottom
= GetSystemMetrics(SM_CYSIZE
);
2854 GetWindowRect(MenuInfo
->Wnd
, &Rect
);
2855 if (0 != (MenuInfo
->fFlags
& MNF_POPUP
))
2857 RECT rc
= ItemInfo
.Rect
;
2859 MENU_AdjustMenuItemRect(MenuInfo
, &rc
);
2861 if(Flags
& TPM_LAYOUTRTL
)
2862 Rect
.left
+= GetSystemMetrics(SM_CXBORDER
);
2864 Rect
.left
+= ItemInfo
.Rect
.right
- GetSystemMetrics(SM_CXBORDER
);
2865 Rect
.top
+= rc
.top
- MENU_TOP_MARGIN
;//3;
2866 Rect
.right
= rc
.left
- rc
.right
+ GetSystemMetrics(SM_CXBORDER
);
2867 Rect
.bottom
= rc
.top
- rc
.bottom
- MENU_TOP_MARGIN
- MENU_BOTTOM_MARGIN
/*2*/
2868 - GetSystemMetrics(SM_CYBORDER
);
2872 if(Flags
& TPM_LAYOUTRTL
)
2873 Rect
.left
+= Rect
.right
- ItemInfo
.Rect
.left
;
2875 Rect
.left
+= ItemInfo
.Rect
.left
;
2876 Rect
.top
+= ItemInfo
.Rect
.bottom
;
2877 Rect
.right
= ItemInfo
.Rect
.right
- ItemInfo
.Rect
.left
;
2878 Rect
.bottom
= ItemInfo
.Rect
.bottom
- ItemInfo
.Rect
.top
;
2882 /* use default alignment for submenus */
2883 Flags
&= ~(TPM_CENTERALIGN
| TPM_RIGHTALIGN
| TPM_VCENTERALIGN
| TPM_BOTTOMALIGN
);
2885 MENU_InitPopup( WndOwner
, ItemInfo
.hSubMenu
, Flags
);
2887 MenuShowPopup(WndOwner
, ItemInfo
.hSubMenu
, MenuInfo
->iItem
, Flags
,
2888 Rect
.left
, Rect
.top
, Rect
.right
, Rect
.bottom
);
2889 if (SelectFirst
&& MenuGetRosMenuInfo(&SubMenuInfo
, ItemInfo
.hSubMenu
))
2891 MenuMoveSelection(WndOwner
, &SubMenuInfo
, ITEM_NEXT
);
2894 Ret
= ItemInfo
.hSubMenu
;
2895 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2900 /**********************************************************************
2903 * Calls EndMenu() if the hwnd parameter belongs to the menu owner
2905 * Does the (menu stuff) of the default window handling of WM_CANCELMODE
2907 void MENU_EndMenu( HWND hwnd
)
2910 menu
= top_popup_hmenu
? MENU_GetMenu( top_popup_hmenu
) : NULL
;
2911 if (menu
&& ( hwnd
== menu
->hWnd
|| hwnd
== (menu
->spwndNotify
? menu
->spwndNotify
->head
.h
: NULL
)) )
2915 /***********************************************************************
2918 * Hide the sub-popup menus of this menu.
2920 static void FASTCALL
2921 MenuHideSubPopups(HWND WndOwner
, PROSMENUINFO MenuInfo
,
2922 BOOL SendMenuSelect
, UINT wFlags
)
2924 ROSMENUINFO SubMenuInfo
;
2925 ROSMENUITEMINFO ItemInfo
;
2927 TRACE("owner=%x menu=%x 0x%04x\n", WndOwner
, MenuInfo
, SendMenuSelect
);
2929 if (NULL
!= MenuInfo
&& NULL
!= top_popup
&& NO_SELECTED_ITEM
!= MenuInfo
->iItem
)
2931 MenuInitRosMenuItemInfo(&ItemInfo
);
2932 ItemInfo
.fMask
|= MIIM_FTYPE
| MIIM_STATE
;
2933 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->iItem
, &ItemInfo
)
2934 || 0 == (ItemInfo
.hSubMenu
)
2935 || 0 == (ItemInfo
.fState
& MF_MOUSESELECT
))
2937 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2940 ItemInfo
.fState
&= ~MF_MOUSESELECT
;
2941 ItemInfo
.fMask
|= MIIM_STATE
;
2942 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->iItem
, &ItemInfo
);
2943 if (MenuGetRosMenuInfo(&SubMenuInfo
, ItemInfo
.hSubMenu
))
2945 MenuHideSubPopups(WndOwner
, &SubMenuInfo
, FALSE
, wFlags
);
2946 MenuSelectItem(WndOwner
, &SubMenuInfo
, NO_SELECTED_ITEM
, SendMenuSelect
, NULL
);
2947 DestroyWindow(SubMenuInfo
.Wnd
);
2948 SubMenuInfo
.Wnd
= NULL
;
2949 MenuSetRosMenuInfo(&SubMenuInfo
);
2951 if (!(wFlags
& TPM_NONOTIFY
))
2952 SendMessageW( WndOwner
, WM_UNINITMENUPOPUP
, (WPARAM
)ItemInfo
.hSubMenu
,
2953 MAKELPARAM(0, IS_SYSTEM_MENU(&SubMenuInfo
)) );
2958 /***********************************************************************
2959 * MenuSwitchTracking
2961 * Helper function for menu navigation routines.
2963 static void FASTCALL
2964 MenuSwitchTracking(MTRACKER
* Mt
, PROSMENUINFO PtMenuInfo
, UINT Index
, UINT wFlags
)
2966 ROSMENUINFO TopMenuInfo
;
2968 TRACE("%x menu=%x 0x%04x\n", Mt
, PtMenuInfo
->Self
, Index
);
2970 if (MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
) &&
2971 Mt
->TopMenu
!= PtMenuInfo
->Self
&&
2972 0 == ((PtMenuInfo
->fFlags
| TopMenuInfo
.fFlags
) & MNF_POPUP
))
2974 /* both are top level menus (system and menu-bar) */
2975 MenuHideSubPopups(Mt
->OwnerWnd
, &TopMenuInfo
, FALSE
, wFlags
);
2976 MenuSelectItem(Mt
->OwnerWnd
, &TopMenuInfo
, NO_SELECTED_ITEM
, FALSE
, NULL
);
2977 Mt
->TopMenu
= PtMenuInfo
->Self
;
2981 MenuHideSubPopups(Mt
->OwnerWnd
, PtMenuInfo
, FALSE
, wFlags
);
2984 MenuSelectItem(Mt
->OwnerWnd
, PtMenuInfo
, Index
, TRUE
, NULL
);
2987 /***********************************************************************
2988 * MenuExecFocusedItem
2990 * Execute a menu item (for instance when user pressed Enter).
2991 * Return the wID of the executed item. Otherwise, -1 indicating
2992 * that no menu item was executed, -2 if a popup is shown;
2993 * Have to receive the flags for the TrackPopupMenu options to avoid
2994 * sending unwanted message.
2998 MenuExecFocusedItem(MTRACKER
*Mt
, PROSMENUINFO MenuInfo
, UINT Flags
)
3000 ROSMENUITEMINFO ItemInfo
;
3003 TRACE("%p menu=%p\n", Mt
, MenuInfo
);
3005 if (0 == MenuInfo
->cItems
|| NO_SELECTED_ITEM
== MenuInfo
->iItem
)
3010 MenuInitRosMenuItemInfo(&ItemInfo
);
3011 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->iItem
, &ItemInfo
))
3013 MenuCleanupRosMenuItemInfo(&ItemInfo
);
3017 TRACE("%p %08x %p\n", MenuInfo
, ItemInfo
.wID
, ItemInfo
.hSubMenu
);
3019 if (0 == (ItemInfo
.hSubMenu
))
3021 if (0 == (ItemInfo
.fState
& (MF_GRAYED
| MF_DISABLED
))
3022 && 0 == (ItemInfo
.fType
& MF_SEPARATOR
))
3024 /* If TPM_RETURNCMD is set you return the id, but
3025 do not send a message to the owner */
3026 if (0 == (Flags
& TPM_RETURNCMD
))
3028 if (0 != (MenuInfo
->fFlags
& MNF_SYSDESKMN
))
3030 PostMessageW(Mt
->OwnerWnd
, WM_SYSCOMMAND
, ItemInfo
.wID
,
3031 MAKELPARAM((SHORT
) Mt
->Pt
.x
, (SHORT
) Mt
->Pt
.y
));
3035 ROSMENUINFO topmenuI
;
3036 BOOL ret
= MenuGetRosMenuInfo(&topmenuI
, Mt
->TopMenu
);
3037 DWORD dwStyle
= MenuInfo
->dwStyle
| (ret
? topmenuI
.dwStyle
: 0);
3039 if (dwStyle
& MNS_NOTIFYBYPOS
)
3040 PostMessageW(Mt
->OwnerWnd
, WM_MENUCOMMAND
, MenuInfo
->iItem
, (LPARAM
)MenuInfo
->Self
);
3042 PostMessageW(Mt
->OwnerWnd
, WM_COMMAND
, ItemInfo
.wID
, 0);
3046 MenuCleanupRosMenuItemInfo(&ItemInfo
);
3052 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, MenuInfo
, TRUE
, Flags
);