diff --git a/dlls/user/menu.c b/dlls/user/menu.c index bc1db93716e..3e2b745e193 100644 --- a/dlls/user/menu.c +++ b/dlls/user/menu.c @@ -159,11 +159,13 @@ typedef struct #define IS_SYSTEM_MENU(menu) \ (!((menu)->wFlags & MF_POPUP) && ((menu)->wFlags & MF_SYSMENU)) -#define TYPE_MASK (MFT_STRING | MFT_BITMAP | MFT_OWNERDRAW | MFT_SEPARATOR | \ - MFT_MENUBARBREAK | MFT_MENUBREAK | MFT_RADIOCHECK | \ - MFT_RIGHTORDER | MFT_RIGHTJUSTIFY | \ - MF_POPUP | MF_SYSMENU | MF_HELP) +#define MENUITEMINFO_TYPE_MASK \ + (MFT_STRING | MFT_BITMAP | MFT_OWNERDRAW | MFT_SEPARATOR | \ + MFT_MENUBARBREAK | MFT_MENUBREAK | MFT_RADIOCHECK | \ + MFT_RIGHTORDER | MFT_RIGHTJUSTIFY /* same as MF_HELP */ ) +#define TYPE_MASK (MENUITEMINFO_TYPE_MASK | MF_POPUP | MF_SYSMENU) #define STATE_MASK (~TYPE_MASK) +#define MENUITEMINFO_STATE_MASK (STATE_MASK & ~(MF_BYPOSITION | MF_MOUSESELECT)) #define WIN_ALLOWED_MENU(style) ((style & (WS_CHILD | WS_POPUP)) != WS_CHILD) @@ -2050,8 +2052,9 @@ static BOOL MENU_SetItemData( MENUITEM *item, UINT flags, UINT_PTR id, flags |= MF_POPUP; /* keep popup */ item->fType = flags & TYPE_MASK; - item->fState = (flags & STATE_MASK) & - ~(MF_HILITE | MF_MOUSESELECT | MF_BYPOSITION); + /* MFS_DEFAULT is not accepted. MF_HILITE is not listed as a valid flag + for ModifyMenu, but Windows accepts it */ + item->fState = flags & MENUITEMINFO_STATE_MASK & ~MFS_DEFAULT; /* Don't call SetRectEmpty here! */ @@ -2123,10 +2126,14 @@ static LPCSTR MENU_ParseResource( LPCSTR res, HMENU hMenu, BOOL unicode ) { WORD flags, id = 0; LPCSTR str; + BOOL end_flag; do { flags = GET_WORD(res); + end_flag = flags & MF_END; + /* Remove MF_END because it has the same value as MF_HILITE */ + flags &= ~MF_END; res += sizeof(WORD); if (!(flags & MF_POPUP)) { @@ -2151,7 +2158,7 @@ static LPCSTR MENU_ParseResource( LPCSTR res, HMENU hMenu, BOOL unicode ) else AppendMenuW( hMenu, flags, id, *(LPCWSTR)str ? (LPCWSTR)str : NULL ); } - } while (!(flags & MF_END)); + } while (!end_flag); return res; } @@ -4352,7 +4359,7 @@ BOOL WINAPI IsMenu(HMENU hmenu) static BOOL GetMenuItemInfo_common ( HMENU hmenu, UINT item, BOOL bypos, LPMENUITEMINFOW lpmii, BOOL unicode) { - MENUITEM *menu = MENU_FindItem (&hmenu, &item, bypos? MF_BYPOSITION : 0); + MENUITEM *menu = MENU_FindItem (&hmenu, &item, bypos ? MF_BYPOSITION : 0); debug_print_menuitem("GetMenuItemInfo_common: ", menu, ""); @@ -4366,7 +4373,7 @@ static BOOL GetMenuItemInfo_common ( HMENU hmenu, UINT item, BOOL bypos, SetLastError( ERROR_INVALID_PARAMETER); return FALSE; } - lpmii->fType = menu->fType & ~MF_POPUP; + lpmii->fType = menu->fType & MENUITEMINFO_TYPE_MASK; if( menu->hbmpItem) lpmii->fType |= MFT_BITMAP; lpmii->hbmpItem = menu->hbmpItem; /* not on Win9x/ME */ if( lpmii->fType & MFT_BITMAP) { @@ -4421,13 +4428,13 @@ static BOOL GetMenuItemInfo_common ( HMENU hmenu, UINT item, BOOL bypos, } if (lpmii->fMask & MIIM_FTYPE) - lpmii->fType = menu->fType & ~MF_POPUP; + lpmii->fType = menu->fType & MENUITEMINFO_TYPE_MASK; if (lpmii->fMask & MIIM_BITMAP) lpmii->hbmpItem = menu->hbmpItem; if (lpmii->fMask & MIIM_STATE) - lpmii->fState = menu->fState; + lpmii->fState = menu->fState & MENUITEMINFO_STATE_MASK; if (lpmii->fMask & MIIM_ID) lpmii->wID = menu->wID; @@ -4524,7 +4531,7 @@ static BOOL SetMenuItemInfo_common(MENUITEM * menu, { if (!menu) return FALSE; - debug_print_menuitem("SetmenuItemInfo_common from: ", menu, ""); + debug_print_menuitem("SetMenuItemInfo_common from: ", menu, ""); if (lpmii->fMask & MIIM_TYPE ) { if( lpmii->fMask & ( MIIM_STRING | MIIM_FTYPE | MIIM_BITMAP)) { @@ -4533,15 +4540,16 @@ static BOOL SetMenuItemInfo_common(MENUITEM * menu, SetLastError( ERROR_INVALID_PARAMETER); return FALSE; } - /* make only MENU_ITEM_TYPE bits in menu->fType equal lpmii->fType */ - menu->fType &= ~MENU_ITEM_TYPE(menu->fType); - menu->fType |= MENU_ITEM_TYPE(lpmii->fType); + + /* Remove the old type bits and replace them with the new ones */ + menu->fType &= ~MENUITEMINFO_TYPE_MASK; + menu->fType |= lpmii->fType & MENUITEMINFO_TYPE_MASK; if (IS_STRING_ITEM(menu->fType)) { HeapFree(GetProcessHeap(), 0, menu->text); set_menu_item_text( menu, lpmii->dwTypeData, unicode ); } else if( (menu->fType) & MFT_BITMAP) - menu->hbmpItem = (HBITMAP)lpmii->dwTypeData; + menu->hbmpItem = HBITMAP_32(LOWORD(lpmii->dwTypeData)); } if (lpmii->fMask & MIIM_FTYPE ) { @@ -4549,8 +4557,8 @@ static BOOL SetMenuItemInfo_common(MENUITEM * menu, SetLastError( ERROR_INVALID_PARAMETER); return FALSE; } - menu->fType &= ~MENU_ITEM_TYPE(menu->fType); - menu->fType |= MENU_ITEM_TYPE(lpmii->fType); + menu->fType &= ~MENUITEMINFO_TYPE_MASK; + menu->fType |= lpmii->fType & MENUITEMINFO_TYPE_MASK; } if (lpmii->fMask & MIIM_STRING ) { /* free the string when used */ @@ -4560,8 +4568,9 @@ static BOOL SetMenuItemInfo_common(MENUITEM * menu, if (lpmii->fMask & MIIM_STATE) { - /* FIXME: MFS_DEFAULT do we have to reset the other menu items? */ - menu->fState = lpmii->fState; + /* Other menu items having MFS_DEFAULT are not converted + to normal items */ + menu->fState = lpmii->fState & MENUITEMINFO_STATE_MASK; } if (lpmii->fMask & MIIM_ID) @@ -4586,9 +4595,6 @@ static BOOL SetMenuItemInfo_common(MENUITEM * menu, if (lpmii->fMask & MIIM_CHECKMARKS) { - if (lpmii->fType & MFT_RADIOCHECK) - menu->fType |= MFT_RADIOCHECK; - menu->hCheckBit = lpmii->hbmpChecked; menu->hUnCheckBit = lpmii->hbmpUnchecked; } diff --git a/dlls/user/tests/menu.c b/dlls/user/tests/menu.c index 23fb1e8eb98..11b75a91ba3 100644 --- a/dlls/user/tests/menu.c +++ b/dlls/user/tests/menu.c @@ -974,7 +974,7 @@ static void test_menu_iteminfo( void ) {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, }, init, OK, ER ) TMII_DONE - + /* Separator */ TMII_INSMI( {, S, MIIM_TYPE, MFT_SEPARATOR, 0, 0, 0, 0, 0, 0, txt, 0, 0, }, OK) TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, }, {, S, MIIM_TYPE, MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, 0, 0, 0, }, @@ -1165,7 +1165,96 @@ static void test_menu_iteminfo( void ) {, S, MIIM_BITMAP|MIIM_FTYPE, MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, string, 80, hbm, }, init, OK, ER ) TMII_DONE - + /* Bitmaps inserted with MIIM_TYPE and MFT_BITMAP: + Only the low word of the dwTypeData is used. + Use a magic bitmap here (Word 95 uses this to create its MDI menu buttons) */ + TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP | MFT_RIGHTJUSTIFY, -1, -1, -1, -1, -1, -1, MAKELONG(HBMMENU_MBAR_CLOSE, 0x1234), -1, -1, }, OK) + TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, }, + {, S, MIIM_TYPE, MFT_BITMAP | MFT_RIGHTJUSTIFY, -9, -9, 0, -9, -9, -9, HBMMENU_MBAR_CLOSE, 0, HBMMENU_MBAR_CLOSE, }, + empty, OK, OK ) + TMII_DONE + /* Type flags */ + TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP | MFT_MENUBARBREAK | MFT_RADIOCHECK | MFT_RIGHTJUSTIFY | MFT_RIGHTORDER, -1, -1, -1, -1, -1, -1, hbm, -1, -1, }, OK) + TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, }, + {, S, MIIM_TYPE, MFT_BITMAP | MFT_MENUBARBREAK | MFT_RADIOCHECK | MFT_RIGHTJUSTIFY | MFT_RIGHTORDER, -9, -9, 0, -9, -9, -9, hbm, 0, hbm, }, + empty, OK, OK ) + TMII_DONE + /* State flags */ + TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP, -1, -1, -1, -1, -1, -1, hbm, -1, -1, }, OK) + TMII_SMII( {, S, MIIM_STATE, -1, MFS_CHECKED | MFS_DEFAULT | MFS_GRAYED | MFS_HILITE, -1, -1, -1, -1, -1, -1, -1, -1, }, OK) + TMII_GMII ( {, S, MIIM_STATE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, }, + {, S, MIIM_STATE, -9, MFS_CHECKED | MFS_DEFAULT | MFS_GRAYED | MFS_HILITE, -9, 0, -9, -9, -9, -9, -9, -9, }, + empty, OK, OK ) + TMII_DONE + /* The style MFT_RADIOCHECK cannot be set with MIIM_CHECKMARKS only */ + TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP, -1, -1, -1, -1, -1, -1, hbm, -1, -1, }, OK) + TMII_SMII( {, S, MIIM_CHECKMARKS, MFT_RADIOCHECK, -1, -1, -1, hbm, hbm, -1, -1, -1, -1, }, OK) + TMII_GMII ( {, S, MIIM_CHECKMARKS | MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, }, + {, S, MIIM_CHECKMARKS | MIIM_TYPE, MFT_BITMAP, -9, -9, 0, hbm, hbm, -9, hbm, 0, hbm, }, + empty, OK, OK ) + TMII_DONE + /* MFT_BITMAP is added automatically by GetMenuItemInfo() for MIIM_TYPE */ + TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP, -1, -1, -1, -1, -1, -1, hbm, -1, -1, }, OK) + TMII_SMII( {, S, MIIM_FTYPE, MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, 0x1234, -1, -1, }, OK) + TMII_GMII ( {, S, MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, }, + {, S, MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, -9, -9, -9, }, + empty, OK, OK ) + TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, }, + {, S, MIIM_TYPE, MFT_BITMAP | MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, hbm, 0, hbm, }, + empty, OK, OK ) + TMII_GMII ( {, S, MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, }, + {, S, MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, -9, -9, -9, }, + empty, OK, OK ) + TMII_SMII( {, S, MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, -1, NULL, }, OK) + TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, }, + {, S, MIIM_TYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, NULL, 0, NULL, }, + empty, OK, OK ) + TMII_DONE + /* Bitmaps inserted with MIIM_TYPE and MFT_BITMAP: + Only the low word of the dwTypeData is used. + Use a magic bitmap here (Word 95 uses this to create its MDI menu buttons) */ + TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP | MFT_RIGHTJUSTIFY, -1, -1, -1, -1, -1, -1, MAKELONG(HBMMENU_MBAR_CLOSE, 0x1234), -1, -1, }, OK) + TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, }, + {, S, MIIM_TYPE, MFT_BITMAP | MFT_RIGHTJUSTIFY, -9, -9, 0, -9, -9, -9, HBMMENU_MBAR_CLOSE, 0, HBMMENU_MBAR_CLOSE, }, + empty, OK, OK ) + TMII_DONE + /* Type flags */ + TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP | MFT_MENUBARBREAK | MFT_RADIOCHECK | MFT_RIGHTJUSTIFY | MFT_RIGHTORDER, -1, -1, -1, -1, -1, -1, hbm, -1, -1, }, OK) + TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, }, + {, S, MIIM_TYPE, MFT_BITMAP | MFT_MENUBARBREAK | MFT_RADIOCHECK | MFT_RIGHTJUSTIFY | MFT_RIGHTORDER, -9, -9, 0, -9, -9, -9, hbm, 0, hbm, }, + empty, OK, OK ) + TMII_DONE + /* State flags */ + TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP, -1, -1, -1, -1, -1, -1, hbm, -1, -1, }, OK) + TMII_SMII( {, S, MIIM_STATE, -1, MFS_CHECKED | MFS_DEFAULT | MFS_GRAYED | MFS_HILITE, -1, -1, -1, -1, -1, -1, -1, -1, }, OK) + TMII_GMII ( {, S, MIIM_STATE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, }, + {, S, MIIM_STATE, -9, MFS_CHECKED | MFS_DEFAULT | MFS_GRAYED | MFS_HILITE, -9, 0, -9, -9, -9, -9, -9, -9, }, + empty, OK, OK ) + TMII_DONE + /* The style MFT_RADIOCHECK cannot be set with MIIM_CHECKMARKS only */ + TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP, -1, -1, -1, -1, -1, -1, hbm, -1, -1, }, OK) + TMII_SMII( {, S, MIIM_CHECKMARKS, MFT_RADIOCHECK, -1, -1, -1, hbm, hbm, -1, -1, -1, -1, }, OK) + TMII_GMII ( {, S, MIIM_CHECKMARKS | MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, }, + {, S, MIIM_CHECKMARKS | MIIM_TYPE, MFT_BITMAP, -9, -9, 0, hbm, hbm, -9, hbm, 0, hbm, }, + empty, OK, OK ) + TMII_DONE + /* MFT_BITMAP is added automatically by GetMenuItemInfo() for MIIM_TYPE */ + TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP, -1, -1, -1, -1, -1, -1, hbm, -1, -1, }, OK) + TMII_SMII( {, S, MIIM_FTYPE, MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, 0x1234, -1, -1, }, OK) + TMII_GMII ( {, S, MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, }, + {, S, MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, -9, -9, -9, }, + empty, OK, OK ) + TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, }, + {, S, MIIM_TYPE, MFT_BITMAP | MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, hbm, 0, hbm, }, + empty, OK, OK ) + TMII_GMII ( {, S, MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, }, + {, S, MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, -9, -9, -9, }, + empty, OK, OK ) + TMII_SMII( {, S, MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, -1, NULL, }, OK) + TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, }, + {, S, MIIM_TYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, NULL, 0, NULL, }, + empty, OK, OK ) + TMII_DONE } while( !(ansi = !ansi) ); DeleteObject( hbm); } @@ -1686,6 +1775,71 @@ static void test_menu_input(void) { DestroyWindow(hWnd); } +void test_menu_flags( void ) +{ + HMENU hMenu, hPopupMenu; + + hMenu = CreateMenu(); + hPopupMenu = CreatePopupMenu(); + + AppendMenu(hMenu, MF_POPUP | MF_STRING, (UINT)hPopupMenu, "Popup"); + + AppendMenu(hPopupMenu, MF_STRING | MF_HILITE | MF_DEFAULT, 101, "Item 1"); + InsertMenu(hPopupMenu, 1, MF_BYPOSITION | MF_STRING | MF_HILITE | MF_DEFAULT, 102, "Item 2"); + AppendMenu(hPopupMenu, MF_STRING, 103, "Item 3"); + ModifyMenu(hPopupMenu, 2, MF_BYPOSITION | MF_STRING | MF_HILITE | MF_DEFAULT, 103, "Item 3"); + + ok(GetMenuState(hPopupMenu, 0, MF_BYPOSITION) & MF_HILITE, + "AppendMenu should accept MF_HILITE\n"); + ok(GetMenuState(hPopupMenu, 1, MF_BYPOSITION) & MF_HILITE, + "InsertMenu should accept MF_HILITE\n"); + ok(GetMenuState(hPopupMenu, 2, MF_BYPOSITION) & MF_HILITE, + "ModifyMenu should accept MF_HILITE\n"); + + ok(!(GetMenuState(hPopupMenu, 0, MF_BYPOSITION) & MF_DEFAULT), + "AppendMenu must not accept MF_DEFAULT\n"); + ok(!(GetMenuState(hPopupMenu, 1, MF_BYPOSITION) & MF_DEFAULT), + "InsertMenu must not accept MF_DEFAULT\n"); + ok(!(GetMenuState(hPopupMenu, 2, MF_BYPOSITION) & MF_DEFAULT), + "ModifyMenu must not accept MF_DEFAULT\n"); + + DestroyMenu(hMenu); +} + +void test_menu_hilitemenuitem( void ) +{ + HMENU hMenu, hPopupMenu; + + hMenu = CreateMenu(); + hPopupMenu = CreatePopupMenu(); + + AppendMenu(hMenu, MF_POPUP | MF_STRING, (UINT)hPopupMenu, "Popup"); + + AppendMenu(hPopupMenu, MF_STRING, 101, "Item 1"); + AppendMenu(hPopupMenu, MF_STRING, 102, "Item 2"); + AppendMenu(hPopupMenu, MF_STRING, 103, "Item 3"); + + HiliteMenuItem(NULL, hPopupMenu, 0, MF_HILITE); + HiliteMenuItem(NULL, hPopupMenu, 1, MF_HILITE); + HiliteMenuItem(NULL, hPopupMenu, 2, MF_HILITE); + HiliteMenuItem(NULL, hPopupMenu, 1, MF_UNHILITE); + + todo_wine + { + ok(GetMenuState(hPopupMenu, 0, MF_BYPOSITION) & MF_HILITE, + "HiliteMenuItem: Item 1 is not hilited\n"); + } + ok(!(GetMenuState(hPopupMenu, 1, MF_BYPOSITION) & MF_HILITE), + "HiliteMenuItem: Item 2 is hilited\n"); + todo_wine + { + ok(GetMenuState(hPopupMenu, 2, MF_BYPOSITION) & MF_HILITE, + "HiliteMenuItem: Item 3 is not hilited\n"); + } + + DestroyMenu(hMenu); +} + START_TEST(menu) { pSetMenuInfo = @@ -1702,4 +1856,6 @@ START_TEST(menu) test_menu_search_bycommand(); test_menu_bmp_and_string(); test_menu_input(); + test_menu_flags(); + test_menu_hilitemenuitem(); }