* ReactOS kernel
* Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
*
+ * Partly based on Wine code
+ * Copyright 1993 Martin Ayotte
+ * Copyright 1994 Alexandre Julliard
+ * Copyright 1997 Morten Welinder
+ *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-/* $Id: menu.c,v 1.9 2003/07/26 15:48:47 dwelch Exp $
+/* $Id$
*
* PROJECT: ReactOS user32.dll
* FILE: lib/user32/windows/menu.c
/* INCLUDES ******************************************************************/
-#include <windows.h>
#include <user32.h>
+#define NDEBUG
#include <debug.h>
-#include <string.h>
-#include <draw.h>
-#include <window.h>
+
+/* internal popup menu window messages */
+#define MM_SETMENUHANDLE (WM_USER + 0)
+#define MM_GETMENUHANDLE (WM_USER + 1)
+
+/* Internal MenuTrackMenu() flags */
+#define TPM_INTERNAL 0xF0000000
+#define TPM_ENTERIDLEEX 0x80000000 /* set owner window for WM_ENTERIDLE */
+#define TPM_BUTTONDOWN 0x40000000 /* menu was clicked before tracking */
+#define TPM_POPUPMENU 0x20000000 /* menu is a popup menu */
/* TYPES *********************************************************************/
-typedef struct _MENUITEM
-{
- UINT Type;
- UINT State;
- UINT Id;
- HMENU SubMenu;
- HBITMAP CheckBit;
- HBITMAP UnCheckBit;
- LPWSTR Text;
- ULONG ItemData;
- ULONG TypeData;
- HBITMAP BmpItem;
- RECT Rect;
- UINT XTab;
-} MENUITEM, *PMENUITEM;
+#define MENU_TYPE_MASK (MF_STRING | MF_BITMAP | MF_OWNERDRAW | MF_SEPARATOR)
-typedef struct _POPUP_MENU
-{
- ULONG Magic;
- MENUITEM* Items;
- ULONG NrItems;
- ULONG Width;
- ULONG Height;
- ULONG FocusedItem;
- ULONG Flags;
- HWND hWnd;
- HWND hWndOwner;
-} POPUP_MENU, *PPOPUP_MENU;
+#define MENU_ITEM_TYPE(flags) ((flags) & MENU_TYPE_MASK)
+#define IS_STRING_ITEM(flags) (MF_STRING == MENU_ITEM_TYPE(flags))
+#define IS_BITMAP_ITEM(flags) (MF_BITMAP == MENU_ITEM_TYPE(flags))
-static HFONT hMenuFont = 0;
+#define IS_SYSTEM_MENU(MenuInfo) \
+ (0 == ((MenuInfo)->Flags & MF_POPUP) && 0 != ((MenuInfo)->Flags & MF_SYSMENU))
-#define MENU_TYPE_MASK ((MF_STRING | MF_BITMAP | MF_OWNERDRAW | MF_SEPARATOR))
+#define IS_SYSTEM_POPUP(MenuInfo) \
+ (0 != ((MenuInfo)->Flags & MF_POPUP) && 0 != ((MenuInfo)->Flags & MF_SYSMENU))
+
+#define IS_MAGIC_ITEM(Bmp) ((int) Bmp <12)
#define MENU_BAR_ITEMS_SPACE (12)
#define SEPARATOR_HEIGHT (5)
#define MENU_TAB_SPACE (8)
-static ULONG ArrowBitmapWidth, ArrowBitmapHeight;
+#define ITEM_PREV -1
+#define ITEM_NEXT 1
-static HANDLE hStdMnArrow;
+#ifndef MF_END
+#define MF_END (0x0080)
+#endif
-static HANDLE hMenuFontBold;
+#ifndef MIIM_STRING
+#define MIIM_STRING (0x00000040)
+#endif
-#define MENU_MAGIC (0x554D)
+#define MAKEINTATOMA(atom) ((LPCSTR)((ULONG_PTR)((WORD)(atom))))
+#define MAKEINTATOMW(atom) ((LPCWSTR)((ULONG_PTR)((WORD)(atom))))
+#define POPUPMENU_CLASS_ATOMA MAKEINTATOMA(32768) /* PopupMenu */
+#define POPUPMENU_CLASS_ATOMW MAKEINTATOMW(32768) /* PopupMenu */
-BOOL EndMenuCalled = FALSE;
-HWND hTopPopupWnd = 0;
+/* internal flags for menu tracking */
-HANDLE hMenuDefSysPopup = 0;
+#define TF_ENDMENU 0x0001
+#define TF_SUSPENDPOPUP 0x0002
+#define TF_SKIPREMOVE 0x0004
-#define NO_SELECTED_ITEM (0xffff)
+typedef struct
+{
+ UINT TrackFlags;
+ HMENU CurrentMenu; /* current submenu (can be equal to hTopMenu)*/
+ HMENU TopMenu; /* initial menu */
+ HWND OwnerWnd; /* where notifications are sent */
+ POINT Pt;
+} MTRACKER;
-/* FUNCTIONS *****************************************************************/
+static LRESULT WINAPI PopupMenuWndProcW(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
-static BOOL
-MenuIsStringItem(ULONG TypeData)
+/*********************************************************************
+ * PopupMenu class descriptor
+ */
+const struct builtin_class_descr POPUPMENU_builtin_class =
+{
+ POPUPMENU_CLASS_ATOMW, /* name */
+ CS_SAVEBITS | CS_DBLCLKS, /* style */
+ (WNDPROC) PopupMenuWndProcW, /* FIXME - procW */
+ (WNDPROC) NULL, /* FIXME - procA */
+ sizeof(MENUINFO *), /* extra */
+ (LPCWSTR) IDC_ARROW, /* cursor */
+ (HBRUSH)(COLOR_MENU + 1) /* brush */
+};
+
+
+/* INTERNAL FUNCTIONS ********************************************************/
+
+/* Rip the fun and easy to use and fun WINE unicode string manipulation routines.
+ * Of course I didnt copy the ASM code because we want this to be portable
+ * and it needs to go away.
+ */
+
+#ifndef GET_WORD
+#define GET_WORD(ptr) (*(WORD *)(ptr))
+#endif
+#ifndef GET_DWORD
+#define GET_DWORD(ptr) (*(DWORD *)(ptr))
+#endif
+
+HFONT hMenuFont = NULL;
+HFONT hMenuFontBold = NULL;
+
+/* Flag set by EndMenu() to force an exit from menu tracking */
+static BOOL fEndMenu = FALSE;
+
+/* Use global popup window because there's no way 2 menus can
+ * be tracked at the same time. */
+static HWND TopPopup;
+
+/* Dimension of the menu bitmaps */
+static WORD ArrowBitmapWidth = 0, ArrowBitmapHeight = 0;
+
+static HBITMAP StdMnArrow = NULL;
+static HBITMAP BmpSysMenu = NULL;
+
+/***********************************************************************
+ * MenuGetRosMenuInfo
+ *
+ * Get full information about menu
+ */
+static BOOL FASTCALL
+MenuGetRosMenuInfo(PROSMENUINFO MenuInfo, HMENU Menu)
{
- return((TypeData & MENU_TYPE_MASK) == MF_STRING);
+ MenuInfo->cbSize = sizeof(ROSMENUINFO);
+ MenuInfo->fMask = MIM_BACKGROUND | MIM_HELPID | MIM_MAXHEIGHT | MIM_MENUDATA | MIM_STYLE;
+
+ return NtUserMenuInfo(Menu, MenuInfo, FALSE);
}
-BOOL
-MenuInit(VOID)
+/***********************************************************************
+ * MenuSetRosMenuInfo
+ *
+ * Set full information about menu
+ */
+static BOOL FASTCALL
+MenuSetRosMenuInfo(PROSMENUINFO MenuInfo)
{
- NONCLIENTMETRICSW ncm;
- BITMAP bm;
+ MenuInfo->cbSize = sizeof(ROSMENUINFO);
+ MenuInfo->fMask = MIM_BACKGROUND | MIM_HELPID | MIM_MAXHEIGHT | MIM_MENUDATA | MIM_STYLE;
- hStdMnArrow = LoadBitmapA(0, MAKEINTRESOURCEA(OBM_MNARROW));
- if (hStdMnArrow == NULL)
- {
- return(FALSE);
- }
- GetObjectA(hStdMnArrow, sizeof(bm), &bm);
- ArrowBitmapWidth = bm.bmWidth;
- ArrowBitmapHeight = bm.bmHeight;
+ return NtUserMenuInfo(MenuInfo->Self, MenuInfo, TRUE);
+}
+
+/***********************************************************************
+ * MenuInitRosMenuItemInfo
+ *
+ * Initialize a buffer for use with MenuGet/SetRosMenuItemInfo
+ */
+static VOID FASTCALL
+MenuInitRosMenuItemInfo(PROSMENUITEMINFO ItemInfo)
+{
+ ZeroMemory(ItemInfo, sizeof(ROSMENUITEMINFO));
+ ItemInfo->cbSize = sizeof(ROSMENUITEMINFO);
+}
- if (!SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0))
+/***********************************************************************
+ * MenuGetRosMenuItemInfo
+ *
+ * Get full information about a menu item
+ */
+static BOOL FASTCALL
+MenuGetRosMenuItemInfo(HMENU Menu, UINT Index, PROSMENUITEMINFO ItemInfo)
+{
+ if (ItemInfo->dwTypeData != NULL)
{
- return(FALSE);
+ HeapFree(GetProcessHeap(), 0, ItemInfo->dwTypeData);
}
- hMenuFont = CreateFontIndirect(&ncm.lfMenuFont);
- if (hMenuFont == NULL)
+ ItemInfo->fMask = MIIM_BITMAP | MIIM_CHECKMARKS | MIIM_DATA | MIIM_FTYPE
+ | MIIM_ID | MIIM_STATE | MIIM_STRING | MIIM_SUBMENU | MIIM_TYPE;
+ ItemInfo->dwTypeData = NULL;
+
+ if (! NtUserMenuItemInfo(Menu, Index, TRUE, ItemInfo, FALSE))
{
- return(FALSE);
+ ItemInfo->fType = 0;
+ return FALSE;
}
- ncm.lfMenuFont.lfWeight = max(ncm.lfMenuFont.lfWeight + 300, 1000);
-
- hMenuFontBold = CreateFontIndirect(&ncm.lfMenuFont);
- if (hMenuFontBold == NULL)
+ if (MENU_ITEM_TYPE(ItemInfo->fType) == MF_STRING)
{
- return(FALSE);
+ ItemInfo->cch++;
+ ItemInfo->dwTypeData = HeapAlloc(GetProcessHeap(), 0,
+ ItemInfo->cch * sizeof(WCHAR));
+ if (NULL == ItemInfo->dwTypeData)
+ {
+ return FALSE;
+ }
+
+ if (! NtUserMenuItemInfo(Menu, Index, TRUE, ItemInfo, FALSE))
+ {
+ ItemInfo->fType = 0;
+ return FALSE;
+ }
}
- return(TRUE);
+ return TRUE;
}
-static BOOL
-MenuIsMenu(PPOPUP_MENU Menu)
+/***********************************************************************
+ * MenuSetRosMenuItemInfo
+ *
+ * Set full information about a menu item
+ */
+static BOOL FASTCALL
+MenuSetRosMenuItemInfo(HMENU Menu, UINT Index, PROSMENUITEMINFO ItemInfo)
{
- return(Menu->Magic == MENU_MAGIC);
+ BOOL Ret;
+
+ if (MENU_ITEM_TYPE(ItemInfo->fType) == MF_STRING &&
+ ItemInfo->dwTypeData != NULL)
+ {
+ ItemInfo->cch = wcslen(ItemInfo->dwTypeData);
+ }
+ ItemInfo->fMask = MIIM_BITMAP | MIIM_CHECKMARKS | MIIM_DATA | MIIM_FTYPE
+ | MIIM_ID | MIIM_STATE | MIIM_STRING | MIIM_SUBMENU | MIIM_TYPE;
+
+
+ Ret = NtUserMenuItemInfo(Menu, Index, TRUE, ItemInfo, TRUE);
+
+ return Ret;
}
-static PPOPUP_MENU
-MenuGetMenu(HMENU hMenu)
+/***********************************************************************
+ * MenuCleanupRosMenuItemInfo
+ *
+ * Cleanup after use of MenuGet/SetRosMenuItemInfo
+ */
+static VOID FASTCALL
+MenuCleanupRosMenuItemInfo(PROSMENUITEMINFO ItemInfo)
{
- PPOPUP_MENU Menu;
- Menu = (PPOPUP_MENU)hMenu;
- return(Menu);
+ if (ItemInfo->dwTypeData != NULL)
+ {
+ HeapFree(GetProcessHeap(), 0, ItemInfo->dwTypeData);
+ }
}
-static MENUITEM*
-MenuFindItem(HMENU* hMenu, UINT* nPos, UINT wFlags)
+/***********************************************************************
+ * MenuGetAllRosMenuItemInfo
+ *
+ * Get full information about all menu items
+ */
+static INT FASTCALL
+MenuGetAllRosMenuItemInfo(HMENU Menu, PROSMENUITEMINFO *ItemInfo)
{
- POPUP_MENU* Menu;
- ULONG i;
+ DWORD BufSize;
- if ((ULONG)(*hMenu) == 0xFFFF || (Menu = MenuGetMenu(*hMenu)) == NULL)
- {
- return(NULL);
- }
- if (wFlags & MF_BYPOSITION)
+ BufSize = NtUserBuildMenuItemList(Menu, (VOID *) 1, 0, 0);
+ if (BufSize <= 0)
{
- if ((*nPos) >= Menu->NrItems)
- {
- return(NULL);
- }
- return(&Menu->Items[*nPos]);
+ return -1;
}
- else
+ *ItemInfo = HeapAlloc(GetProcessHeap(), 0, BufSize);
+ if (NULL == *ItemInfo)
{
- MENUITEM* Item = Menu->Items;
- for (i = 0; i < Menu->NrItems; i++)
- {
- if (Item->Id == (*nPos))
- {
- *nPos = i;
- return(Item);
- }
- else if (Item->Type & MF_POPUP)
- {
- HMENU SubMenu = Item->SubMenu;
- MENUITEM* SubItem = MenuFindItem(&SubMenu, nPos, wFlags);
- if (SubItem)
- {
- *hMenu = SubMenu;
- return(SubItem);
- }
- }
- }
+ return -1;
}
- return(NULL);
-}
-
-/*
- * @implemented
- */
-WINBOOL STDCALL
-AppendMenuA(HMENU hMenu,
- UINT uFlags,
- UINT_PTR uIDNewItem,
- LPCSTR lpNewItem)
-{
- DPRINT("AppendMenuA(hMenu 0x%X, uFlags 0x%X, uIDNewItem %d, "
- "lpNewItem %s\n", hMenu, uFlags, uIDNewItem, lpNewItem);
- return(InsertMenuA(hMenu, -1, uFlags | MF_BYPOSITION, uIDNewItem,
- lpNewItem));
+ return NtUserBuildMenuItemList(Menu, *ItemInfo, BufSize, 0);
}
-
-/*
- * @implemented
+/***********************************************************************
+ * MenuCleanupAllRosMenuItemInfo
+ *
+ * Cleanup after use of MenuGetAllRosMenuItemInfo
*/
-WINBOOL STDCALL
-AppendMenuW(HMENU hMenu,
- UINT uFlags,
- UINT_PTR uIDNewItem,
- LPCWSTR lpNewItem)
+static VOID FASTCALL
+MenuCleanupAllRosMenuItemInfo(PROSMENUITEMINFO ItemInfo)
{
- DPRINT("AppendMenuW(hMenu 0x%X, uFlags 0x%X, uIDNewItem %d, "
- "lpNewItem %S\n", hMenu, uFlags, uIDNewItem, lpNewItem);
- return(InsertMenuW(hMenu, -1, uFlags | MF_BYPOSITION, uIDNewItem,
- lpNewItem));
+ HeapFree(GetProcessHeap(), 0, ItemInfo);
}
-/*
- * @implemented
+/***********************************************************************
+ * MenuLoadBitmaps
+ *
+ * Load the arrow bitmap. We can't do this from MenuInit since user32
+ * can also be used (and thus initialized) from text-mode.
*/
-DWORD STDCALL
-CheckMenuItem(HMENU hmenu,
- UINT uIDCheckItem,
- UINT uCheck)
+static void FASTCALL
+MenuLoadBitmaps(VOID)
{
- MENUITEM* Item;
- DWORD Ret;
-
- DPRINT("CheckMenuItem(hmenu 0x%X, uIDCheckItem %d, uCheck %d",
- hmenu, uIDCheckItem, uCheck);
- if ((Item = MenuFindItem(&hmenu, &uIDCheckItem, uCheck)) == NULL)
- {
- return(-1);
- }
- Ret = Item->State & MF_CHECKED;
- if (uCheck & MF_CHECKED)
+ /* Load menu bitmaps */
+ if (NULL == StdMnArrow)
{
- Item->State |= MF_CHECKED;
+ StdMnArrow = LoadBitmapW(0, MAKEINTRESOURCEW(OBM_MNARROW));
+
+ if (NULL != StdMnArrow)
+ {
+ BITMAP bm;
+ GetObjectW(StdMnArrow, sizeof(BITMAP), &bm);
+ ArrowBitmapWidth = bm.bmWidth;
+ ArrowBitmapHeight = bm.bmHeight;
+ }
}
- else
+
+ /* Load system buttons bitmaps */
+ if (NULL == BmpSysMenu)
{
- Item->State &= ~MF_CHECKED;
+ BmpSysMenu = LoadBitmapW(0, MAKEINTRESOURCEW(OBM_CLOSE));
}
- return(Ret);
}
-
-/*
- * @unimplemented
+/***********************************************************************
+ * MenuGetBitmapItemSize
+ *
+ * Get the size of a bitmap item.
*/
-WINBOOL STDCALL
-CheckMenuRadioItem(HMENU hmenu,
- UINT idFirst,
- UINT idLast,
- UINT idCheck,
- UINT uFlags)
+static void FASTCALL
+MenuGetBitmapItemSize(UINT Id, DWORD Data, SIZE *Size)
{
- PMENUITEM First, Last, Check;
- HMENU FirstMenu = hmenu;
- HMENU LastMenu = hmenu;
- HMENU CheckMenu = hmenu;
+ BITMAP Bm;
+ HBITMAP Bmp = (HBITMAP) Id;
- DPRINT("CheckMenuRadioItem(hmenu %X, idFirst %d, idLast %d, idCheck %d "
- "uFlags %d", hmenu, idFirst, idLast, idCheck, uFlags);
-
- First = MenuFindItem(&FirstMenu, &idFirst, uFlags);
- Last = MenuFindItem(&LastMenu, &idLast, uFlags);
- Check = MenuFindItem(&CheckMenu, &idCheck, uFlags);
+ Size->cx = Size->cy = 0;
- if (First == NULL || Last == NULL || Check == NULL ||
- First > Last || FirstMenu != LastMenu || FirstMenu != CheckMenu ||
- Check > Last || Check < Last)
+ /* check if there is a magic menu item associated with this item */
+ if (0 != Id && IS_MAGIC_ITEM(Id))
{
- return(FALSE);
+ switch((INT_PTR) LOWORD(Id))
+ {
+ case (INT_PTR) HBMMENU_SYSTEM:
+ if (0 != Data)
+ {
+ Bmp = (HBITMAP) Data;
+ break;
+ }
+ /* fall through */
+ case (INT_PTR) HBMMENU_MBAR_RESTORE:
+ case (INT_PTR) HBMMENU_MBAR_MINIMIZE:
+ case (INT_PTR) HBMMENU_MBAR_MINIMIZE_D:
+ case (INT_PTR) HBMMENU_MBAR_CLOSE:
+ case (INT_PTR) HBMMENU_MBAR_CLOSE_D:
+ /* FIXME: Why we need to subtract these magic values? */
+ Size->cx = GetSystemMetrics(SM_CXSIZE) - 2;
+ Size->cy = GetSystemMetrics(SM_CYSIZE) - 4;
+ return;
+ case (INT_PTR) HBMMENU_CALLBACK:
+ case (INT_PTR) HBMMENU_POPUP_CLOSE:
+ case (INT_PTR) HBMMENU_POPUP_RESTORE:
+ case (INT_PTR) HBMMENU_POPUP_MAXIMIZE:
+ case (INT_PTR) HBMMENU_POPUP_MINIMIZE:
+ default:
+ DPRINT("Magic menu bitmap not implemented\n");
+ return;
+ }
}
- while (First < Last)
+
+ if (GetObjectW(Bmp, sizeof(BITMAP), &Bm))
{
- if (First == Check)
- {
- First->TypeData |= MFT_RADIOCHECK;
- First->State |= MFS_CHECKED;
- }
- else
- {
- First->TypeData &= ~MFT_RADIOCHECK;
- First->State &= ~MFS_CHECKED;
- }
- First++;
+ Size->cx = Bm.bmWidth;
+ Size->cy = Bm.bmHeight;
}
- return(TRUE);
}
-
-/*
- * @implemented
+/***********************************************************************
+ * MenuDrawBitmapItem
+ *
+ * Draw a bitmap item.
*/
-HMENU STDCALL
-CreateMenu(VOID)
+static void FASTCALL
+MenuDrawBitmapItem(HDC Dc, PROSMENUITEMINFO Item, const RECT *Rect, BOOL MenuBar)
{
- PPOPUP_MENU Menu;
-
- Menu = HeapAlloc(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(POPUP_MENU));
- Menu->Magic = MENU_MAGIC;
- Menu->FocusedItem = NO_SELECTED_ITEM;
+ BITMAP Bm;
+ DWORD Rop;
+ HDC DcMem;
+ HBITMAP Bmp = (HBITMAP) Item->hbmpItem;
+ int w = Rect->right - Rect->left;
+ int h = Rect->bottom - Rect->top;
+ int BmpXoffset = 0;
+ int Left, Top;
+
+ /* Check if there is a magic menu item associated with this item */
+ if (IS_MAGIC_ITEM(Item->hbmpItem))
+ {
+ UINT Flags = 0;
+ RECT r;
+
+ r = *Rect;
+ switch ((int) Item->hbmpItem)
+ {
+ case (INT_PTR) HBMMENU_SYSTEM:
+ if (NULL != Item->hbmpItem)
+ {
+ Bmp = Item->hbmpItem;
+ if (! GetObjectW(Bmp, sizeof(BITMAP), &Bm))
+ {
+ return;
+ }
+ }
+ else
+ {
+ Bmp = BmpSysMenu;
+ if (! GetObjectW(Bmp, sizeof(BITMAP), &Bm))
+ {
+ return;
+ }
+ /* only use right half of the bitmap */
+ BmpXoffset = Bm.bmWidth / 2;
+ Bm.bmWidth -= BmpXoffset;
+ }
+ goto got_bitmap;
+ case (INT_PTR) HBMMENU_MBAR_RESTORE:
+ Flags = DFCS_CAPTIONRESTORE;
+ break;
+ case (INT_PTR) HBMMENU_MBAR_MINIMIZE:
+ r.right += 1;
+ Flags = DFCS_CAPTIONMIN;
+ break;
+ case (INT_PTR) HBMMENU_MBAR_MINIMIZE_D:
+ r.right += 1;
+ Flags = DFCS_CAPTIONMIN | DFCS_INACTIVE;
+ break;
+ case (INT_PTR) HBMMENU_MBAR_CLOSE:
+ Flags = DFCS_CAPTIONCLOSE;
+ break;
+ case (INT_PTR) HBMMENU_MBAR_CLOSE_D:
+ Flags = DFCS_CAPTIONCLOSE | DFCS_INACTIVE;
+ break;
+ case (INT_PTR) HBMMENU_CALLBACK:
+ case (INT_PTR) HBMMENU_POPUP_CLOSE:
+ case (INT_PTR) HBMMENU_POPUP_RESTORE:
+ case (INT_PTR) HBMMENU_POPUP_MAXIMIZE:
+ case (INT_PTR) HBMMENU_POPUP_MINIMIZE:
+ default:
+ DPRINT("Magic menu bitmap not implemented\n");
+ return;
+ }
+ InflateRect(&r, -1, -1);
+ if (0 != (Item->fState & MF_HILITE))
+ {
+ Flags |= DFCS_PUSHED;
+ }
+ DrawFrameControl(Dc, &r, DFC_CAPTION, Flags);
+ return;
+ }
- return (HMENU)Menu;
-}
+ if (NULL == Bmp || ! GetObjectW(Bmp, sizeof(BITMAP), &Bm))
+ {
+ return;
+ }
+got_bitmap:
+ DcMem = CreateCompatibleDC(Dc);
+ SelectObject(DcMem, Bmp);
-/*
- * @implemented
+ /* handle fontsize > bitmap_height */
+ Top = (Bm.bmHeight < h) ? Rect->top + (h - Bm.bmHeight) / 2 : Rect->top;
+ Left = Rect->left;
+ Rop = (0 != (Item->fState & MF_HILITE) && ! IS_MAGIC_ITEM(Item->hbmpItem)) ? NOTSRCCOPY : SRCCOPY;
+ if (0 != (Item->fState & MF_HILITE) && IS_BITMAP_ITEM(Item->fType))
+ {
+ SetBkColor(Dc, GetSysColor(COLOR_HIGHLIGHT));
+ }
+ BitBlt(Dc, Left, Top, w, h, DcMem, BmpXoffset, 0, Rop);
+ DeleteDC(DcMem);
+}
+
+/***********************************************************************
+ * MenuDrawMenuItem
+ *
+ * Draw a single menu item.
*/
-HMENU STDCALL
-CreatePopupMenu(VOID)
+static void FASTCALL
+MenuDrawMenuItem(HWND Wnd, PROSMENUINFO MenuInfo, HWND WndOwner, HDC Dc,
+ PROSMENUITEMINFO Item, UINT Height, BOOL MenuBar, UINT Action)
{
- HMENU hMenu;
- PPOPUP_MENU Menu;
+ RECT Rect;
+ PWCHAR Text;
- hMenu = CreateMenu();
- Menu = MenuGetMenu(hMenu);
- Menu->Flags |= MF_POPUP;
+ if (0 != (Item->fType & MF_SYSMENU))
+ {
+ if (! IsIconic(Wnd))
+ {
+ UserGetInsideRectNC(Wnd, &Rect);
+ UserDrawSysMenuButton(Wnd, Dc, &Rect,
+ Item->fState & (MF_HILITE | MF_MOUSESELECT));
+ }
- return (HMENU)Menu;
-}
+ return;
+ }
+ /* Setup colors */
-/*
- * @implemented
- */
-WINBOOL STDCALL
-DeleteMenu(HMENU hMenu,
- UINT uPosition,
- UINT uFlags)
-{
- PMENUITEM Item;
+ if (0 != (Item->fState & MF_HILITE))
+ {
+ if (MenuBar)
+ {
+ SetTextColor(Dc, GetSysColor(COLOR_MENUTEXT));
+ SetBkColor(Dc, GetSysColor(COLOR_MENU));
+ }
+ else
+ {
+ if (0 != (Item->fState & MF_GRAYED))
+ {
+ SetTextColor(Dc, GetSysColor(COLOR_GRAYTEXT));
+ }
+ else
+ {
+ SetTextColor(Dc, GetSysColor(COLOR_HIGHLIGHTTEXT));
+ }
+ SetBkColor(Dc, GetSysColor(COLOR_HIGHLIGHT));
+ }
+ }
+ else
+ {
+ if (0 != (Item->fState & MF_GRAYED))
+ {
+ SetTextColor(Dc, GetSysColor(COLOR_GRAYTEXT));
+ }
+ else
+ {
+ SetTextColor(Dc, GetSysColor(COLOR_MENUTEXT));
+ }
+ SetBkColor(Dc, GetSysColor(COLOR_MENU));
+ }
- Item = MenuFindItem(&hMenu, &uPosition, uFlags);
- if (Item == NULL)
+ if (0 != (Item->fType & MF_OWNERDRAW))
{
- return(FALSE);
+ /*
+ ** Experimentation under Windows reveals that an owner-drawn
+ ** menu is given the rectangle which includes the space it requested
+ ** in its response to WM_MEASUREITEM _plus_ width for a checkmark
+ ** and a popup-menu arrow. This is the value of lpitem->rect.
+ ** Windows will leave all drawing to the application except for
+ ** the popup-menu arrow. Windows always draws that itself, after
+ ** the menu owner has finished drawing.
+ */
+ DRAWITEMSTRUCT dis;
+
+ dis.CtlType = ODT_MENU;
+ dis.CtlID = 0;
+ dis.itemID = Item->wID;
+ dis.itemData = (DWORD)Item->dwItemData;
+ dis.itemState = 0;
+ if (0 != (Item->fState & MF_CHECKED))
+ {
+ dis.itemState |= ODS_CHECKED;
+ }
+ if (0 != (Item->fState & MF_GRAYED))
+ {
+ dis.itemState |= ODS_GRAYED | ODS_DISABLED;
+ }
+ if (0 != (Item->fState & MF_HILITE))
+ {
+ dis.itemState |= ODS_SELECTED;
+ }
+ dis.itemAction = Action; /* ODA_DRAWENTIRE | ODA_SELECT | ODA_FOCUS; */
+ dis.hwndItem = (HWND) MenuInfo->Self;
+ dis.hDC = Dc;
+ dis.rcItem = Item->Rect;
+ DPRINT("Ownerdraw: owner=%p itemID=%d, itemState=%d, itemAction=%d, "
+ "hwndItem=%p, hdc=%p, rcItem={%ld,%ld,%ld,%ld}\n", Wnd,
+ dis.itemID, dis.itemState, dis.itemAction, dis.hwndItem,
+ dis.hDC, dis.rcItem.left, dis.rcItem.top, dis.rcItem.right,
+ dis.rcItem.bottom);
+ SendMessageW(WndOwner, WM_DRAWITEM, 0, (LPARAM) &dis);
+ /* Fall through to draw popup-menu arrow */
}
- if (Item->TypeData & MF_POPUP)
+
+ DPRINT("rect={%ld,%ld,%ld,%ld}\n", Item->Rect.left, Item->Rect.top,
+ Item->Rect.right, Item->Rect.bottom);
+
+ if (MenuBar && 0 != (Item->fType & MF_SEPARATOR))
{
- DestroyMenu(Item->SubMenu);
+ return;
}
- RemoveMenu(hMenu, uPosition, uFlags | MF_BYPOSITION);
- return(TRUE);
-}
-VOID
-MenuFreeItemData(PMENUITEM Item)
-{
- if (MenuIsStringItem(Item->TypeData) && Item->Text != NULL)
+ Rect = Item->Rect;
+
+ if (0 == (Item->fType & MF_OWNERDRAW))
{
- HeapFree(GetProcessHeap(), 0, Item->Text);
+ if (Item->fState & MF_HILITE)
+ {
+ if (MenuBar)
+ {
+ DrawEdge(Dc, &Rect, BDR_SUNKENOUTER, BF_RECT);
+ }
+ else
+ {
+ FillRect(Dc, &Rect, GetSysColorBrush(COLOR_HIGHLIGHT));
+ }
+ }
+ else
+ {
+ FillRect(Dc, &Rect, GetSysColorBrush(COLOR_MENU));
+ }
}
-}
-/*
- * @unimplemented
- */
-WINBOOL STDCALL
-DestroyMenu(HMENU hMenu)
-{
- PPOPUP_MENU Menu;
+ SetBkMode(Dc, TRANSPARENT);
- if (hMenu == NULL || hMenu == hMenuDefSysPopup)
+ if (0 == (Item->fType & MF_OWNERDRAW))
{
- return(FALSE);
+ /* vertical separator */
+ if (! MenuBar && 0 != (Item->fType & MF_MENUBARBREAK))
+ {
+ RECT rc = Rect;
+ rc.top = 3;
+ rc.bottom = Height - 3;
+ DrawEdge(Dc, &rc, EDGE_ETCHED, BF_LEFT);
+ }
+
+ /* horizontal separator */
+ if (0 != (Item->fType & MF_SEPARATOR))
+ {
+ RECT rc = Rect;
+ rc.left++;
+ rc.right--;
+ rc.top += SEPARATOR_HEIGHT / 2;
+ DrawEdge(Dc, &rc, EDGE_ETCHED, BF_TOP);
+
+ return;
+ }
}
- Menu = MenuGetMenu(hMenu);
- if (hTopPopupWnd != NULL && hMenu == (HMENU)GetWindowLong(hTopPopupWnd, 0))
+
+#if 0
+ /* helper lines for debugging */
+ FrameRect(Dc, &Rect, GetStockObject(BLACK_BRUSH));
+ SelectObject(Dc, SYSCOLOR_GetPen(COLOR_WINDOWFRAME));
+ MoveToEx(Dc, Rect.left, (Rect.top + Rect.bottom) / 2, NULL);
+ LineTo(Dc, Rect.right, (Rect.top + Rect.bottom) / 2);
+#endif
+
+ if (! MenuBar)
{
- SetWindowLong(hTopPopupWnd, 0, 0);
+ INT y = Rect.top + Rect.bottom;
+ UINT CheckBitmapWidth = GetSystemMetrics(SM_CXMENUCHECK);
+ UINT CheckBitmapHeight = GetSystemMetrics(SM_CYMENUCHECK);
+
+ if (0 == (Item->fType & MF_OWNERDRAW))
+ {
+ /* Draw the check mark
+ *
+ * FIXME:
+ * Custom checkmark bitmaps are monochrome but not always 1bpp.
+ */
+ HBITMAP bm = 0 != (Item->fState & MF_CHECKED) ? Item->hbmpChecked : Item->hbmpUnchecked;
+ if (NULL != bm) /* we have a custom bitmap */
+ {
+ HDC DcMem = CreateCompatibleDC(Dc);
+ SelectObject(DcMem, bm);
+ BitBlt(Dc, Rect.left, (y - CheckBitmapHeight) / 2,
+ CheckBitmapWidth, CheckBitmapHeight,
+ DcMem, 0, 0, SRCCOPY);
+ DeleteDC(DcMem);
+ }
+ else if (0 != (Item->fState & MF_CHECKED)) /* standard bitmaps */
+ {
+ RECT r;
+ HBITMAP bm = CreateBitmap(CheckBitmapWidth, CheckBitmapHeight, 1, 1, NULL);
+ HDC DcMem = CreateCompatibleDC(Dc);
+ SelectObject(DcMem, bm);
+ SetRect( &r, 0, 0, CheckBitmapWidth, CheckBitmapHeight);
+ DrawFrameControl(DcMem, &r, DFC_MENU,
+ 0 != (Item->fType & MFT_RADIOCHECK) ?
+ DFCS_MENUBULLET : DFCS_MENUCHECK);
+ BitBlt(Dc, Rect.left, (y - r.bottom) / 2, r.right, r.bottom,
+ DcMem, 0, 0, SRCCOPY );
+ DeleteDC(DcMem);
+ DeleteObject(bm);
+ }
+ }
+
+ /* Draw the popup-menu arrow */
+ if (0 != (Item->fType & MF_POPUP))
+ {
+ HDC DcMem = CreateCompatibleDC(Dc);
+ HBITMAP OrigBitmap;
+
+ OrigBitmap = SelectObject(DcMem, StdMnArrow);
+ BitBlt(Dc, Rect.right - ArrowBitmapWidth - 1,
+ (y - ArrowBitmapHeight) / 2,
+ ArrowBitmapWidth, ArrowBitmapHeight,
+ DcMem, 0, 0, SRCCOPY);
+ SelectObject(DcMem, OrigBitmap);
+ DeleteDC(DcMem);
+ }
+
+ Rect.left += CheckBitmapWidth;
+ Rect.right -= ArrowBitmapWidth;
}
- if (!MenuIsMenu(Menu))
+
+ /* Done for owner-drawn */
+ if (0 != (Item->fType & MF_OWNERDRAW))
{
- return(FALSE);
+ return;
}
- if ((Menu->Flags & MF_POPUP) && (Menu->hWnd != NULL) &&
- (hTopPopupWnd == NULL || Menu->hWnd != hTopPopupWnd))
+
+ /* Draw the item text or bitmap */
+ if (IS_BITMAP_ITEM(Item->fType))
{
- DestroyWindow(Menu->hWnd);
+ MenuDrawBitmapItem(Dc, Item, &Rect, MenuBar);
+ return;
}
-
- if (Menu->Items != NULL)
+ /* No bitmap - process text if present */
+ else if (IS_STRING_ITEM(Item->fType))
{
- PMENUITEM Item = Menu->Items;
- ULONG i;
- for (i = Menu->NrItems; i > 0; i--, Item++)
+ register int i;
+ HFONT FontOld = NULL;
+
+ UINT uFormat = MenuBar ? DT_CENTER | DT_VCENTER | DT_SINGLELINE
+ : DT_LEFT | DT_VCENTER | DT_SINGLELINE;
+
+ if (0 != (Item->fState & MFS_DEFAULT))
+ {
+ FontOld = SelectObject(Dc, hMenuFontBold);
+ }
+
+ if (MenuBar)
+ {
+ Rect.left += MENU_BAR_ITEMS_SPACE / 2;
+ Rect.right -= MENU_BAR_ITEMS_SPACE / 2;
+ }
+
+ Text = (PWCHAR) Item->dwTypeData;
+ for (i = 0; L'\0' != Text[i]; i++)
+ {
+ if (L'\t' == Text[i] || L'\b' == Text[i])
+ {
+ break;
+ }
+ }
+
+ if (0 != (Item->fState & MF_GRAYED))
{
- if (Item->TypeData & MF_POPUP)
+ if (0 == (Item->fState & MF_HILITE))
{
- DestroyMenu(Item->SubMenu);
+ ++Rect.left; ++Rect.top; ++Rect.right; ++Rect.bottom;
+ SetTextColor(Dc, RGB(0xff, 0xff, 0xff));
+ DrawTextW(Dc, Text, i, &Rect, uFormat);
+ --Rect.left; --Rect.top; --Rect.right; --Rect.bottom;
}
- MenuFreeItemData(Item);
- }
- HeapFree(GetProcessHeap(), 0, Menu->Items);
+ SetTextColor(Dc, RGB(0x80, 0x80, 0x80));
+ }
+
+ DrawTextW(Dc, Text, i, &Rect, uFormat);
+
+ /* paint the shortcut text */
+ if (! MenuBar && L'\0' != Text[i]) /* There's a tab or flush-right char */
+ {
+ if (L'\t' == Text[i])
+ {
+ Rect.left = Item->XTab;
+ uFormat = DT_LEFT | DT_VCENTER | DT_SINGLELINE;
+ }
+ else
+ {
+ uFormat = DT_RIGHT | DT_VCENTER | DT_SINGLELINE;
+ }
+
+ if (0 != (Item->fState & MF_GRAYED))
+ {
+ if (0 == (Item->fState & MF_HILITE))
+ {
+ ++Rect.left; ++Rect.top; ++Rect.right; ++Rect.bottom;
+ SetTextColor(Dc, RGB(0xff, 0xff, 0xff));
+ DrawTextW(Dc, Text + i + 1, -1, &Rect, uFormat);
+ --Rect.left; --Rect.top; --Rect.right; --Rect.bottom;
+ }
+ SetTextColor(Dc, RGB(0x80, 0x80, 0x80));
+ }
+ DrawTextW(Dc, Text + i + 1, -1, &Rect, uFormat);
+ }
+
+ if (NULL != FontOld)
+ {
+ SelectObject(Dc, FontOld);
+ }
}
- HeapFree(GetProcessHeap(), 0, Menu);
- return(TRUE);
}
-
-/*
- * @implemented
+/***********************************************************************
+ * MenuDrawPopupMenu
+ *
+ * Paint a popup menu.
*/
-WINBOOL STDCALL
-DrawMenuBar(HWND hWnd)
+static void FASTCALL
+MenuDrawPopupMenu(HWND Wnd, HDC Dc, HMENU Menu)
{
- ULONG Style;
- ULONG MenuId;
- PPOPUP_MENU Menu;
+ HBRUSH PrevBrush = NULL;
+ HPEN PrevPen;
+ RECT Rect;
+ ROSMENUINFO MenuInfo;
+ ROSMENUITEMINFO ItemInfo;
+ UINT u;
+
+ DPRINT("wnd=%x dc=%x menu=%x\n", Wnd, Dc, Menu);
- Style = GetWindowLong(hWnd, GWL_STYLE);
- MenuId = GetWindowLong(hWnd, GWL_ID);
-
- if (!(Style & WS_CHILD) && MenuId != 0)
+ GetClientRect(Wnd, &Rect);
+
+ if (NULL != (PrevBrush = SelectObject(Dc, GetSysColorBrush(COLOR_MENU)))
+ && NULL != SelectObject(Dc, hMenuFont))
{
- Menu = MenuGetMenu((HMENU)MenuId);
+ Rectangle(Dc, Rect.left, Rect.top, Rect.right, Rect.bottom);
- Menu->Height = 0;
- Menu->hWndOwner = hWnd;
- SetWindowPos(hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
- SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED);
- return(TRUE);
- }
- return(FALSE);
-}
+ PrevPen = SelectObject(Dc, GetStockObject(NULL_PEN));
+ if (NULL != PrevPen)
+ {
+ DrawEdge(Dc, &Rect, EDGE_RAISED, BF_RECT);
+ /* draw menu items */
-/*
- * @implemented
- */
-UINT STDCALL
-EnableMenuItem(HMENU hMenu,
- UINT uIDEnableItem,
- UINT uEnable)
-{
- PPOPUP_MENU Menu;
- PMENUITEM Item;
- UINT OldFlags;
+ if (MenuGetRosMenuInfo(&MenuInfo, Menu) && 0 != MenuInfo.MenuItemCount)
+ {
+ MenuInitRosMenuItemInfo(&ItemInfo);
- Menu = MenuGetMenu(hMenu);
- if (Menu == NULL)
- {
- return(-1);
- }
- Item = MenuFindItem(&hMenu, &uIDEnableItem, uEnable);
- if (Item == NULL)
- {
- return(-1);
+ for (u = 0; u < MenuInfo.MenuItemCount; u++)
+ {
+ if (MenuGetRosMenuItemInfo(MenuInfo.Self, u, &ItemInfo))
+ {
+ MenuDrawMenuItem(Wnd, &MenuInfo, MenuInfo.WndOwner, Dc, &ItemInfo,
+ MenuInfo.Height, FALSE, ODA_DRAWENTIRE);
+ }
+ }
+
+ MenuCleanupRosMenuItemInfo(&ItemInfo);
+ }
+ }
+ else
+ {
+ SelectObject(Dc, PrevBrush);
+ }
}
- OldFlags = Item->State & (MF_GRAYED | MF_DISABLED);
- Item->State ^= (OldFlags ^ uEnable) & (MF_GRAYED | MF_DISABLED);
- return(OldFlags);
}
-BOOL STATIC
-MenuIsMenuActive(VOID)
+static LRESULT WINAPI
+PopupMenuWndProcW(HWND Wnd, UINT Message, WPARAM wParam, LPARAM lParam)
{
- return(hTopPopupWnd != NULL && IsWindowVisible(hTopPopupWnd));
-}
+ DPRINT("hwnd=%x msg=0x%04x wp=0x%04x lp=0x%08lx\n", Wnd, Message, wParam, lParam);
-/*
- * @implemented
- */
-WINBOOL STDCALL
-EndMenu(VOID)
-{
- if (!EndMenuCalled && MenuIsMenuActive())
+ switch(Message)
{
- EndMenuCalled = TRUE;
+ case WM_CREATE:
+ {
+ CREATESTRUCTW *cs = (CREATESTRUCTW *) lParam;
+ SetWindowLongW(Wnd, 0, (LONG) cs->lpCreateParams);
+ return 0;
+ }
+
+ case WM_MOUSEACTIVATE: /* We don't want to be activated */
+ return MA_NOACTIVATE;
+
+ case WM_PAINT:
+ {
+ PAINTSTRUCT ps;
+ BeginPaint(Wnd, &ps);
+ MenuDrawPopupMenu(Wnd, ps.hdc, (HMENU)GetWindowLongW(Wnd, 0));
+ EndPaint(Wnd, &ps);
+ return 0;
+ }
+
+ case WM_ERASEBKGND:
+ return 1;
+
+ case WM_DESTROY:
+ /* zero out global pointer in case resident popup window was destroyed. */
+ if (Wnd == TopPopup)
+ {
+ TopPopup = NULL;
+ }
+ break;
+
+ case WM_SHOWWINDOW:
+ if (0 != wParam)
+ {
+ if (0 == GetWindowLongW(Wnd, 0))
+ {
+ OutputDebugStringA("no menu to display\n");
+ }
+ }
+ else
+ {
+ SetWindowLongW(Wnd, 0, 0);
+ }
+ break;
+
+ case MM_SETMENUHANDLE:
+ SetWindowLongW(Wnd, 0, wParam);
+ break;
+
+ case MM_GETMENUHANDLE:
+ return GetWindowLongW(Wnd, 0);
- PostMessageA(hTopPopupWnd, WM_CANCELMODE, 0, 0);
+ default:
+ return DefWindowProcW(Wnd, Message, wParam, lParam);
}
- return(TRUE);
-}
+ return 0;
+}
-/*
- * @implemented
+/**********************************************************************
+ * MENUEX_ParseResource
+ *
+ * Parse an extended menu resource and add items to the menu.
+ * Return a pointer to the end of the resource.
+ *
+ * FIXME - should we be passing an LPCSTR to a predominantly UNICODE function?
*/
-HMENU STDCALL
-GetMenu(HWND hWnd)
+static LPCSTR MENUEX_ParseResource( LPCSTR res, HMENU hMenu)
{
- return((HMENU)GetWindowLong(hWnd, GWL_ID));
+ WORD resinfo;
+
+ do
+ {
+ MENUITEMINFOW mii;
+
+ mii.cbSize = sizeof(mii);
+ mii.fMask = MIIM_STATE | MIIM_ID | MIIM_TYPE;
+ mii.fType = GET_DWORD(res);
+ res += sizeof(DWORD);
+ mii.fState = GET_DWORD(res);
+ res += sizeof(DWORD);
+ mii.wID = GET_DWORD(res);
+ res += sizeof(DWORD);
+ resinfo = GET_WORD(res);
+ res += sizeof(WORD);
+ /* Align the text on a word boundary. */
+ res += (~((int)res - 1)) & 1;
+ mii.dwTypeData = (LPWSTR) res;
+ res += (1 + wcslen(mii.dwTypeData)) * sizeof(WCHAR);
+ /* Align the following fields on a dword boundary. */
+ res += (~((int)res - 1)) & 3;
+
+ if (resinfo & 1) /* Pop-up? */
+ {
+ /* DWORD helpid = GET_DWORD(res); FIXME: use this. */
+ res += sizeof(DWORD);
+ mii.hSubMenu = CreatePopupMenu();
+ if (!mii.hSubMenu)
+ return NULL;
+ if (!(res = MENUEX_ParseResource(res, mii.hSubMenu)))
+ {
+ DestroyMenu(mii.hSubMenu);
+ return NULL;
+ }
+ mii.fMask |= MIIM_SUBMENU;
+ mii.fType |= MF_POPUP;
+ }
+ else if(!*mii.dwTypeData && !(mii.fType & MF_SEPARATOR))
+ {
+ DbgPrint("WARN: Converting NULL menu item %04x, type %04x to SEPARATOR\n",
+ mii.wID, mii.fType);
+ mii.fType |= MF_SEPARATOR;
+ }
+ InsertMenuItemW(hMenu, -1, MF_BYPOSITION, &mii);
+ }
+ while (!(resinfo & MF_END));
+ return res;
}
-/*
- * @unimplemented
+/**********************************************************************
+ * MENU_ParseResource
+ *
+ * Parse a standard menu resource and add items to the menu.
+ * Return a pointer to the end of the resource.
+ *
+ * NOTE: flags is equivalent to the mtOption field
*/
-WINBOOL
-STDCALL
-GetMenuBarInfo(
- HWND hwnd,
- LONG idObject,
- LONG idItem,
- PMENUBARINFO pmbi)
+static LPCSTR MENU_ParseResource( LPCSTR res, HMENU hMenu, BOOL unicode )
{
- UNIMPLEMENTED;
- return FALSE;
-}
+ WORD flags, id = 0;
+ HMENU hSubMenu;
+ LPCSTR str;
+ BOOL end = FALSE;
+ do
+ {
+ flags = GET_WORD(res);
-/*
- * @implemented
- */
-LONG STDCALL
-GetMenuCheckMarkDimensions(VOID)
-{
- return(MAKELONG(GetSystemMetrics(SM_CXMENUCHECK),
- GetSystemMetrics(SM_CYMENUCHECK)));
-}
+ /* remove MF_END flag before passing it to AppendMenu()! */
+ end = (flags & MF_END);
+ if(end) flags ^= MF_END;
+ res += sizeof(WORD);
+ if(!(flags & MF_POPUP))
+ {
+ id = GET_WORD(res);
+ res += sizeof(WORD);
+ }
+ str = res;
+ if(!unicode)
+ res += strlen(str) + 1;
+ else
+ res += (wcslen((LPCWSTR)str) + 1) * sizeof(WCHAR);
+ if (flags & MF_POPUP)
+ {
+ hSubMenu = CreatePopupMenu();
+ if(!hSubMenu) return NULL;
+ if(!(res = MENU_ParseResource(res, hSubMenu, unicode)))
+ return NULL;
+ if(!unicode)
+ AppendMenuA(hMenu, flags, (UINT)hSubMenu, str);
+ else
+ AppendMenuW(hMenu, flags, (UINT)hSubMenu, (LPCWSTR)str);
+ }
+ else /* Not a popup */
+ {
+ if(!unicode)
+ AppendMenuA(hMenu, flags, id, *str ? str : NULL);
+ else
+ AppendMenuW(hMenu, flags, id,
+ *(LPCWSTR)str ? (LPCWSTR)str : NULL);
+ }
+ } while(!end);
-/*
- * @unimplemented
- */
-UINT
-STDCALL
-GetMenuDefaultItem(
- HMENU hMenu,
- UINT fByPos,
- UINT gmdiFlags)
-{
- UNIMPLEMENTED;
- return 0;
+ return res;
}
-/*
- * @unimplemented
- */
-WINBOOL
-STDCALL
-GetMenuInfo(
- HMENU hmenu,
- LPCMENUINFO lpcmi)
+NTSTATUS STDCALL
+User32LoadSysMenuTemplateForKernel(PVOID Arguments, ULONG ArgumentLength)
{
- UNIMPLEMENTED;
- return FALSE;
+ LRESULT Result;
+ Result = (LRESULT)LoadMenuW(User32Instance, L"SYSMENU");
+ return(ZwCallbackReturn(&Result, sizeof(LRESULT), STATUS_SUCCESS));
}
-/*
- * @unimplemented
- */
-int
-STDCALL
-GetMenuItemCount(
- HMENU hMenu)
+BOOL
+MenuInit(VOID)
{
- UNIMPLEMENTED;
- return 0;
-}
+ NONCLIENTMETRICSW ncm;
+ /* get the menu font */
+ if(!hMenuFont || !hMenuFontBold)
+ {
+ ncm.cbSize = sizeof(ncm);
+ if(!SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0))
+ {
+ DbgPrint("MenuInit(): SystemParametersInfoW(SPI_GETNONCLIENTMETRICS) failed!\n");
+ return FALSE;
+ }
-/*
- * @unimplemented
- */
-UINT
-STDCALL
-GetMenuItemID(
- HMENU hMenu,
- int nPos)
-{
- UNIMPLEMENTED;
- return 0;
-}
+ hMenuFont = CreateFontIndirectW(&ncm.lfMenuFont);
+ if(hMenuFont == NULL)
+ {
+ DbgPrint("MenuInit(): CreateFontIndirectW(hMenuFont) failed!\n");
+ return FALSE;
+ }
+ ncm.lfMenuFont.lfWeight = max(ncm.lfMenuFont.lfWeight + 300, 1000);
+ hMenuFontBold = CreateFontIndirectW(&ncm.lfMenuFont);
+ if(hMenuFontBold == NULL)
+ {
+ DbgPrint("MenuInit(): CreateFontIndirectW(hMenuFontBold) failed!\n");
+ DeleteObject(hMenuFont);
+ hMenuFont = NULL;
+ return FALSE;
+ }
+ }
-/*
- * @unimplemented
- */
-WINBOOL
-STDCALL
-GetMenuItemInfoA(
- HMENU hMenu,
- UINT uItem,
- WINBOOL fByPosition,
- LPMENUITEMINFO lpmii)
-{
- UNIMPLEMENTED;
- return FALSE;
+ return TRUE;
}
-/*
- * @unimplemented
- */
-WINBOOL
-STDCALL
-GetMenuItemInfoW(
- HMENU hMenu,
- UINT uItem,
- WINBOOL fByPosition,
- LPMENUITEMINFO lpmii)
+VOID
+MenuCleanup(VOID)
{
- UNIMPLEMENTED;
- return FALSE;
+ if (hMenuFont)
+ {
+ DeleteObject(hMenuFont);
+ hMenuFont = NULL;
+ }
+
+ if (hMenuFontBold)
+ {
+ DeleteObject(hMenuFontBold);
+ hMenuFontBold = NULL;
+ }
}
-/*
- * @unimplemented
- */
-WINBOOL
-STDCALL
-GetMenuItemRect(
- HWND hWnd,
- HMENU hMenu,
- UINT uItem,
- LPRECT lprcItem)
-{
- UNIMPLEMENTED;
- return FALSE;
-}
-
-/*
- * @unimplemented
+/***********************************************************************
+ * MenuCalcItemSize
+ *
+ * Calculate the size of the menu item and store it in ItemInfo->rect.
*/
-UINT
-STDCALL
-GetMenuState(
- HMENU hMenu,
- UINT uId,
- UINT uFlags)
+static void FASTCALL
+MenuCalcItemSize(HDC Dc, PROSMENUITEMINFO ItemInfo, HWND WndOwner,
+ INT OrgX, INT OrgY, BOOL MenuBar)
{
- UNIMPLEMENTED;
- return 0;
-}
+ PWCHAR p;
+ UINT CheckBitmapWidth = GetSystemMetrics(SM_CXMENUCHECK);
+ DPRINT("dc=%x owner=%x (%d,%d)\n", Dc, WndOwner, OrgX, OrgY);
-/*
- * @unimplemented
- */
-int
-STDCALL
-GetMenuStringA(
- HMENU hMenu,
- UINT uIDItem,
- LPSTR lpString,
- int nMaxCount,
- UINT uFlag)
-{
- UNIMPLEMENTED;
- return 0;
-}
+ SetRect(&ItemInfo->Rect, OrgX, OrgY, OrgX, OrgY);
+ if (0 != (ItemInfo->fType & MF_OWNERDRAW))
+ {
+ /*
+ ** Experimentation under Windows reveals that an owner-drawn
+ ** menu is expected to return the size of the content part of
+ ** the menu item, not including the checkmark nor the submenu
+ ** arrow. Windows adds those values itself and returns the
+ ** enlarged rectangle on subsequent WM_DRAWITEM messages.
+ */
+ MEASUREITEMSTRUCT mis;
+ mis.CtlType = ODT_MENU;
+ mis.CtlID = 0;
+ mis.itemID = ItemInfo->wID;
+ mis.itemData = (DWORD)ItemInfo->dwItemData;
+ mis.itemHeight = 0;
+ mis.itemWidth = 0;
+ SendMessageW(WndOwner, WM_MEASUREITEM, 0, (LPARAM) &mis);
+ ItemInfo->Rect.right += mis.itemWidth;
-/*
- * @unimplemented
- */
-int
-STDCALL
-GetMenuStringW(
- HMENU hMenu,
- UINT uIDItem,
- LPWSTR lpString,
- int nMaxCount,
- UINT uFlag)
-{
- UNIMPLEMENTED;
- return 0;
-}
+ if (MenuBar)
+ {
+ ItemInfo->Rect.right += MENU_BAR_ITEMS_SPACE;
+ /* under at least win95 you seem to be given a standard
+ height for the menu and the height value is ignored */
-/*
- * @unimplemented
- */
-HMENU
-STDCALL
-GetSubMenu(
- HMENU hMenu,
- int nPos)
-{
- UNIMPLEMENTED;
- return (HMENU)0;
-}
+ ItemInfo->Rect.bottom += GetSystemMetrics(SM_CYMENU) - 1;
+ }
+ else
+ {
+ ItemInfo->Rect.bottom += mis.itemHeight;
+ }
+ DPRINT("id=%04x size=%dx%d\n", ItemInfo->wID, mis.itemWidth, mis.itemHeight);
+ /* Fall through to get check/arrow width calculation. */
+ }
-/*
- * @unimplemented
- */
-WINBOOL
-STDCALL
-HiliteMenuItem(
- HWND hwnd,
- HMENU hmenu,
- UINT uItemHilite,
- UINT uHilite)
-{
- UNIMPLEMENTED;
- return FALSE;
-}
+ if (0 != (ItemInfo->fType & MF_SEPARATOR))
+ {
+ ItemInfo->Rect.bottom += SEPARATOR_HEIGHT;
+ return;
+ }
+ if (! MenuBar)
+ {
+ ItemInfo->Rect.right += 2 * CheckBitmapWidth;
+ if (0 != (ItemInfo->fType & MF_POPUP))
+ {
+ ItemInfo->Rect.right += ArrowBitmapWidth;
+ }
+ }
-/*
- * @unimplemented
- */
-WINBOOL
-STDCALL
-InsertMenuA(
- HMENU hMenu,
- UINT uPosition,
- UINT uFlags,
- UINT_PTR uIDNewItem,
- LPCSTR lpNewItem)
-{
- UNIMPLEMENTED;
- return FALSE;
-}
+ if (0 != (ItemInfo->fType & MF_OWNERDRAW))
+ {
+ return;
+ }
+ if (IS_BITMAP_ITEM(ItemInfo->fType))
+ {
+ SIZE Size;
-/*
- * @unimplemented
- */
-WINBOOL
-STDCALL
-InsertMenuItemA(
- HMENU hMenu,
- UINT uItem,
- WINBOOL fByPosition,
- LPCMENUITEMINFO lpmii)
-{
- UNIMPLEMENTED;
- return FALSE;
-}
+ MenuGetBitmapItemSize((int) ItemInfo->hbmpItem, (DWORD) ItemInfo->hbmpItem, &Size);
+ ItemInfo->Rect.right += Size.cx;
+ ItemInfo->Rect.bottom += Size.cy;
+ /* Leave space for the sunken border */
+ ItemInfo->Rect.right += 2;
+ ItemInfo->Rect.bottom += 2;
-/*
- * @unimplemented
- */
-WINBOOL
-STDCALL
-InsertMenuItemW(
- HMENU hMenu,
- UINT uItem,
- WINBOOL fByPosition,
- LPCMENUITEMINFO lpmii)
-{
- UNIMPLEMENTED;
- return FALSE;
-}
+ /* Special case: Minimize button doesn't have a space behind it. */
+ if (ItemInfo->hbmpItem == (HBITMAP)HBMMENU_MBAR_MINIMIZE ||
+ ItemInfo->hbmpItem == (HBITMAP)HBMMENU_MBAR_MINIMIZE_D)
+ ItemInfo->Rect.right -= 1;
+ }
+ /* it must be a text item - unless it's the system menu */
+ if (0 == (ItemInfo->fType & MF_SYSMENU) && IS_STRING_ITEM(ItemInfo->fType))
+ {
+ SIZE Size;
-/*
- * @unimplemented
- */
-WINBOOL
-STDCALL
-InsertMenuW(
- HMENU hMenu,
- UINT uPosition,
- UINT uFlags,
- UINT_PTR uIDNewItem,
- LPCWSTR lpNewItem)
-{
- UNIMPLEMENTED;
- return FALSE;
-}
+ GetTextExtentPoint32W(Dc, (LPWSTR) ItemInfo->dwTypeData,
+ wcslen((LPWSTR) ItemInfo->dwTypeData), &Size);
+ ItemInfo->Rect.right += Size.cx;
+ ItemInfo->Rect.bottom += max(Size.cy, GetSystemMetrics(SM_CYMENU) - 1);
+ ItemInfo->XTab = 0;
-/*
- * @unimplemented
- */
-WINBOOL
-STDCALL
-IsMenu(
- HMENU hMenu)
-{
- UNIMPLEMENTED;
- return FALSE;
-}
+ if (MenuBar)
+ {
+ ItemInfo->Rect.right += MENU_BAR_ITEMS_SPACE;
+ }
+ else if ((p = wcschr((LPWSTR) ItemInfo->dwTypeData, L'\t' )) != NULL)
+ {
+ /* Item contains a tab (only meaningful in popup menus) */
+ GetTextExtentPoint32W(Dc, (LPWSTR) ItemInfo->dwTypeData,
+ (int)(p - (LPWSTR) ItemInfo->dwTypeData), &Size);
+ ItemInfo->XTab = CheckBitmapWidth + MENU_TAB_SPACE + Size.cx;
+ ItemInfo->Rect.right += MENU_TAB_SPACE;
+ }
+ else
+ {
+ if (NULL != wcschr((LPWSTR) ItemInfo->dwTypeData, L'\b'))
+ {
+ ItemInfo->Rect.right += MENU_TAB_SPACE;
+ }
+ ItemInfo->XTab = ItemInfo->Rect.right - CheckBitmapWidth
+ - ArrowBitmapWidth;
+ }
+ }
+ DPRINT("(%ld,%ld)-(%ld,%ld)\n", ItemInfo->Rect.left, ItemInfo->Rect.top, ItemInfo->Rect.right, ItemInfo->Rect.bottom);
+}
-/*
- * @implemented
+/***********************************************************************
+ * MenuPopupMenuCalcSize
+ *
+ * Calculate the size of a popup menu.
*/
-HMENU STDCALL
-LoadMenuA(HINSTANCE hInstance,
- LPCSTR lpMenuName)
+static void FASTCALL
+MenuPopupMenuCalcSize(PROSMENUINFO MenuInfo, HWND WndOwner)
{
- HANDLE Resource = FindResourceA(hInstance, lpMenuName, MAKEINTRESOURCEA(4));
- if (Resource == NULL)
+ ROSMENUITEMINFO ItemInfo;
+ HDC Dc;
+ int Start, i;
+ int OrgX, OrgY, MaxX, MaxTab, MaxTabWidth;
+
+ MenuInfo->Width = MenuInfo->Height = 0;
+ if (0 == MenuInfo->MenuItemCount)
{
- return(NULL);
+ MenuSetRosMenuInfo(MenuInfo);
+ return;
}
- return(LoadMenuIndirectA((PVOID)LoadResource(hInstance, Resource)));
-}
+ Dc = GetDC(NULL);
+ SelectObject(Dc, hMenuFont);
-/*
- * @unimplemented
- */
-HMENU
-STDCALL
-LoadMenuIndirectA(
- CONST MENUTEMPLATE *lpMenuTemplate)
-{
- UNIMPLEMENTED;
- return (HMENU)0;
-}
+ Start = 0;
+ MaxX = 2 + 1;
+ MenuInitRosMenuItemInfo(&ItemInfo);
+ while (Start < MenuInfo->MenuItemCount)
+ {
+ OrgX = MaxX;
+ OrgY = 2;
-/*
- * @unimplemented
- */
-HMENU
-STDCALL
-LoadMenuIndirectW(
- CONST MENUTEMPLATE *lpMenuTemplate)
-{
- UNIMPLEMENTED;
- return (HMENU)0;
-}
+ MaxTab = MaxTabWidth = 0;
+ /* Parse items until column break or end of menu */
+ for (i = Start; i < MenuInfo->MenuItemCount; i++)
+ {
+ if (! MenuGetRosMenuItemInfo(MenuInfo->Self, i, &ItemInfo))
+ {
+ MenuCleanupRosMenuItemInfo(&ItemInfo);
+ MenuSetRosMenuInfo(MenuInfo);
+ return;
+ }
+ if (i != Start &&
+ 0 != (ItemInfo.fType & (MF_MENUBREAK | MF_MENUBARBREAK)))
+ {
+ break;
+ }
+
+ MenuCalcItemSize(Dc, &ItemInfo, WndOwner, OrgX, OrgY, FALSE);
+ if (! MenuSetRosMenuItemInfo(MenuInfo->Self, i, &ItemInfo))
+ {
+ MenuCleanupRosMenuItemInfo(&ItemInfo);
+ MenuSetRosMenuInfo(MenuInfo);
+ return;
+ }
+
+ if (0 != (ItemInfo.fType & MF_MENUBARBREAK))
+ {
+ OrgX++;
+ }
+ MaxX = max(MaxX, ItemInfo.Rect.right);
+ OrgY = ItemInfo.Rect.bottom;
+ if (IS_STRING_ITEM(ItemInfo.fType) && 0 != ItemInfo.XTab)
+ {
+ MaxTab = max(MaxTab, ItemInfo.XTab);
+ MaxTabWidth = max(MaxTabWidth, ItemInfo.Rect.right - ItemInfo.XTab);
+ }
+ }
+
+ /* Finish the column (set all items to the largest width found) */
+ MaxX = max(MaxX, MaxTab + MaxTabWidth);
+ while (Start < i)
+ {
+ if (MenuGetRosMenuItemInfo(MenuInfo->Self, Start, &ItemInfo))
+ {
+ ItemInfo.Rect.right = MaxX;
+ if (IS_STRING_ITEM(ItemInfo.fType) && 0 != ItemInfo.XTab)
+ {
+ ItemInfo.XTab = MaxTab;
+ }
+ MenuSetRosMenuItemInfo(MenuInfo->Self, Start, &ItemInfo);
+ }
+ Start++;
+ }
+ MenuInfo->Height = max(MenuInfo->Height, OrgY);
+ }
-/*
- * @implemented
+ MenuInfo->Width = MaxX;
+
+ /* space for 3d border */
+ MenuInfo->Height += 2;
+ MenuInfo->Width += 2;
+
+ ReleaseDC(NULL, Dc);
+ MenuCleanupRosMenuItemInfo(&ItemInfo);
+ MenuSetRosMenuInfo(MenuInfo);
+}
+
+/***********************************************************************
+ * MenuMenuBarCalcSize
+ *
+ * FIXME: Word 6 implements its own MDI and its own 'close window' bitmap
+ * height is off by 1 pixel which causes lengthy window relocations when
+ * active document window is maximized/restored.
+ *
+ * Calculate the size of the menu bar.
*/
-HMENU STDCALL
-LoadMenuW(HINSTANCE hInstance,
- LPCWSTR lpMenuName)
+static void FASTCALL
+MenuMenuBarCalcSize(HDC Dc, LPRECT Rect, PROSMENUINFO MenuInfo, HWND WndOwner)
{
- HANDLE Resource = FindResourceW(hInstance, lpMenuName, RT_MENU);
- if (Resource == NULL)
+ ROSMENUITEMINFO ItemInfo;
+ int Start, i, OrgX, OrgY, MaxY, HelpPos;
+
+ if (NULL == Rect || NULL == MenuInfo)
{
- return(NULL);
+ return;
+ }
+ if (0 == MenuInfo->MenuItemCount)
+ {
+ return;
}
- return(LoadMenuIndirectW((PVOID)LoadResource(hInstance, Resource)));
-}
+ DPRINT("left=%ld top=%ld right=%ld bottom=%ld\n",
+ Rect->left, Rect->top, Rect->right, Rect->bottom);
+ MenuInfo->Width = Rect->right - Rect->left;
+ MenuInfo->Height = 0;
+ MaxY = Rect->top + 1;
+ Start = 0;
+ HelpPos = -1;
+ MenuInitRosMenuItemInfo(&ItemInfo);
+ while (Start < MenuInfo->MenuItemCount)
+ {
+ if (! MenuGetRosMenuItemInfo(MenuInfo->Self, Start, &ItemInfo))
+ {
+ MenuCleanupRosMenuItemInfo(&ItemInfo);
+ return;
+ }
+ OrgX = Rect->left;
+ OrgY = MaxY;
+
+ /* Parse items until line break or end of menu */
+ for (i = Start; i < MenuInfo->MenuItemCount; i++)
+ {
+ if (-1 == HelpPos && 0 != (ItemInfo.fType & MF_RIGHTJUSTIFY))
+ {
+ HelpPos = i;
+ }
+ if (i != Start &&
+ 0 != (ItemInfo.fType & (MF_MENUBREAK | MF_MENUBARBREAK)))
+ {
+ break;
+ }
+
+ DPRINT("calling MENU_CalcItemSize org=(%d, %d)\n", OrgX, OrgY);
+ MenuCalcItemSize(Dc, &ItemInfo, WndOwner, OrgX, OrgY, TRUE);
+ if (! MenuSetRosMenuItemInfo(MenuInfo->Self, i, &ItemInfo))
+ {
+ MenuCleanupRosMenuItemInfo(&ItemInfo);
+ return;
+ }
+
+ if (ItemInfo.Rect.right > Rect->right)
+ {
+ if (i != Start)
+ {
+ break;
+ }
+ else
+ {
+ ItemInfo.Rect.right = Rect->right;
+ }
+ }
+ MaxY = max(MaxY, ItemInfo.Rect.bottom );
+ OrgX = ItemInfo.Rect.right;
+ if (i + 1 < MenuInfo->MenuItemCount)
+ {
+ if (! MenuGetRosMenuItemInfo(MenuInfo->Self, i + 1, &ItemInfo))
+ {
+ MenuCleanupRosMenuItemInfo(&ItemInfo);
+ return;
+ }
+ }
+ }
-/*
- * @unimplemented
- */
-int
-STDCALL
-MenuItemFromPoint(
- HWND hWnd,
- HMENU hMenu,
- POINT ptScreen)
-{
- UNIMPLEMENTED;
- return 0;
-}
+/* FIXME: Is this really needed? */
+#if 0
+ /* Finish the line (set all items to the largest height found) */
+ while (Start < i)
+ {
+ if (MenuGetRosMenuItemInfo(MenuInfo->Self, Start, &ItemInfo))
+ {
+ ItemInfo.Rect.bottom = MaxY;
+ MenuSetRosMenuItemInfo(MenuInfo->Self, Start, &ItemInfo);
+ }
+ Start++;
+ }
+#else
+ Start = i;
+#endif
+ }
+ Rect->bottom = MaxY;
+ MenuInfo->Height = Rect->bottom - Rect->top;
+ MenuSetRosMenuInfo(MenuInfo);
-/*
- * @unimplemented
- */
-WINBOOL
-STDCALL
-ModifyMenuA(
- HMENU hMnu,
- UINT uPosition,
- UINT uFlags,
- UINT_PTR uIDNewItem,
- LPCSTR lpNewItem)
-{
- UNIMPLEMENTED;
- return FALSE;
-}
+ if (-1 != HelpPos)
+ {
+ /* Flush right all items between the MF_RIGHTJUSTIFY and */
+ /* the last item (if several lines, only move the last line) */
+ if (! MenuGetRosMenuItemInfo(MenuInfo->Self, MenuInfo->MenuItemCount - 1, &ItemInfo))
+ {
+ MenuCleanupRosMenuItemInfo(&ItemInfo);
+ return;
+ }
+ OrgY = ItemInfo.Rect.top;
+ OrgX = Rect->right;
+ for (i = MenuInfo->MenuItemCount - 1; HelpPos <= i; i--)
+ {
+ if (i < HelpPos)
+ {
+ break; /* done */
+ }
+ if (ItemInfo.Rect.top != OrgY)
+ {
+ break; /* Other line */
+ }
+ if (OrgX <= ItemInfo.Rect.right)
+ {
+ break; /* Too far right already */
+ }
+ ItemInfo.Rect.left += OrgX - ItemInfo.Rect.right;
+ ItemInfo.Rect.right = OrgX;
+ OrgX = ItemInfo.Rect.left;
+ MenuSetRosMenuItemInfo(MenuInfo->Self, i, &ItemInfo);
+ if (HelpPos + 1 <= i &&
+ ! MenuGetRosMenuItemInfo(MenuInfo->Self, i - 1, &ItemInfo))
+ {
+ MenuCleanupRosMenuItemInfo(&ItemInfo);
+ return;
+ }
+ }
+ }
+ MenuCleanupRosMenuItemInfo(&ItemInfo);
+}
-/*
- * @unimplemented
+/***********************************************************************
+ * DrawMenuBarTemp (USER32.@)
+ *
+ * UNDOCUMENTED !!
+ *
+ * called by W98SE desk.cpl Control Panel Applet
+ *
+ * Not 100% sure about the param names, but close.
+ *
+ * @implemented
*/
-WINBOOL
-STDCALL
-ModifyMenuW(
- HMENU hMnu,
- UINT uPosition,
- UINT uFlags,
- UINT_PTR uIDNewItem,
- LPCWSTR lpNewItem)
+DWORD WINAPI
+DrawMenuBarTemp(HWND Wnd, HDC DC, LPRECT Rect, HMENU Menu, HFONT Font)
{
- UNIMPLEMENTED;
- return FALSE;
-}
+ ROSMENUINFO MenuInfo;
+ ROSMENUITEMINFO ItemInfo;
+ UINT i;
+ HFONT FontOld = NULL;
+ if (NULL == Menu)
+ {
+ Menu = GetMenu(Wnd);
+ }
-/*
- * @unimplemented
- */
-WINBOOL
-STDCALL
-RemoveMenu(
- HMENU hMenu,
- UINT uPosition,
- UINT uFlags)
-{
- UNIMPLEMENTED;
- return FALSE;
-}
+ if (NULL == Font)
+ {
+ Font = hMenuFont;
+ }
+ if (NULL == Rect || ! MenuGetRosMenuInfo(&MenuInfo, Menu))
+ {
+ return GetSystemMetrics(SM_CYMENU);
+ }
-/*
- * @unimplemented
- */
-WINBOOL
-STDCALL
-SetMenu(
- HWND hWnd,
- HMENU hMenu)
-{
- UNIMPLEMENTED;
- return FALSE;
-}
+ DPRINT("(%x, %x, %p, %x, %x)\n", Wnd, DC, Rect, Menu, Font);
+ FontOld = SelectObject(DC, Font);
-/*
- * @unimplemented
- */
-WINBOOL
-STDCALL
-SetMenuDefaultItem(
- HMENU hMenu,
- UINT uItem,
- UINT fByPos)
-{
- UNIMPLEMENTED;
- return FALSE;
-}
+ if (0 == MenuInfo.Height)
+ {
+ MenuMenuBarCalcSize(DC, Rect, &MenuInfo, Wnd);
+ }
+ Rect->bottom = Rect->top + MenuInfo.Height;
-/*
- * @unimplemented
- */
-WINBOOL
-STDCALL
-SetMenuInfo(
- HMENU hmenu,
- LPCMENUINFO lpcmi)
-{
- UNIMPLEMENTED;
- return FALSE;
-}
+ FillRect(DC, Rect, GetSysColorBrush(COLOR_MENU));
+ SelectObject(DC, GetSysColorPen(COLOR_3DFACE));
+ MoveToEx(DC, Rect->left, Rect->bottom, NULL);
+ LineTo(DC, Rect->right, Rect->bottom);
-/*
- * @unimplemented
- */
-WINBOOL
-STDCALL
-SetMenuItemBitmaps(
- HMENU hMenu,
- UINT uPosition,
- UINT uFlags,
- HBITMAP hBitmapUnchecked,
- HBITMAP hBitmapChecked)
-{
- UNIMPLEMENTED;
- return FALSE;
-}
+ if (0 == MenuInfo.MenuItemCount)
+ {
+ SelectObject(DC, FontOld);
+ return GetSystemMetrics(SM_CYMENU);
+ }
+ MenuInitRosMenuItemInfo(&ItemInfo);
+ for (i = 0; i < MenuInfo.MenuItemCount; i++)
+ {
+ if (MenuGetRosMenuItemInfo(MenuInfo.Self, i, &ItemInfo))
+ {
+ MenuDrawMenuItem(Wnd, &MenuInfo, Wnd, DC, &ItemInfo,
+ MenuInfo.Height, TRUE, ODA_DRAWENTIRE);
+ }
+ }
+ MenuCleanupRosMenuItemInfo(&ItemInfo);
-/*
- * @unimplemented
- */
-WINBOOL
-STDCALL
-SetMenuItemInfoA(
- HMENU hMenu,
- UINT uItem,
- WINBOOL fByPosition,
- LPMENUITEMINFO lpmii)
-{
- UNIMPLEMENTED;
- return FALSE;
+ SelectObject(DC, FontOld);
+
+ return MenuInfo.Height;
}
-/*
- * @unimplemented
+/***********************************************************************
+ * MenuDrawMenuBar
+ *
+ * Paint a menu bar. Returns the height of the menu bar.
+ * called from [windows/nonclient.c]
*/
-WINBOOL
-STDCALL
-SetMenuItemInfoW(
- HMENU hMenu,
- UINT uItem,
- WINBOOL fByPosition,
- LPMENUITEMINFO lpmii)
+UINT MenuDrawMenuBar(HDC DC, LPRECT Rect, HWND Wnd, BOOL SuppressDraw)
{
- UNIMPLEMENTED;
- return FALSE;
-}
+ ROSMENUINFO MenuInfo;
+ HFONT FontOld = NULL;
+ HMENU Menu = GetMenu(Wnd);
+ if (NULL == Rect || ! MenuGetRosMenuInfo(&MenuInfo, Menu))
+ {
+ return GetSystemMetrics(SM_CYMENU);
+ }
-/*
- * @unimplemented
- */
-WINBOOL
-STDCALL
-TrackPopupMenu(
- HMENU hMenu,
- UINT uFlags,
- int x,
- int y,
- int nReserved,
- HWND hWnd,
- CONST RECT *prcRect)
-{
- UNIMPLEMENTED;
- return FALSE;
-}
+ if (SuppressDraw)
+ {
+ FontOld = SelectObject(DC, hMenuFont);
+ MenuMenuBarCalcSize(DC, Rect, &MenuInfo, Wnd);
-/*
- * @unimplemented
- */
-WINBOOL
-STDCALL
-TrackPopupMenuEx(
- HMENU hmenu,
- UINT fuFlags,
- int x,
- int y,
- HWND hwnd,
- LPTPMPARAMS lptpm)
-{
- UNIMPLEMENTED;
- return FALSE;
-}
+ Rect->bottom = Rect->top + MenuInfo.Height;
-static BOOL
-MenuIsBitmapItem(ULONG TypeData)
-{
- return((TypeData & MENU_TYPE_MASK) == MF_BITMAP);
+ if (NULL != FontOld)
+ {
+ SelectObject(DC, FontOld);
+ }
+ return MenuInfo.Height;
+ }
+ else
+ {
+ return DrawMenuBarTemp(Wnd, DC, Rect, Menu, NULL);
+ }
}
-static BOOL
-MenuIsMagicItem(LPWSTR Text)
+/***********************************************************************
+ * MenuInitTracking
+ */
+static BOOL FASTCALL
+MenuInitTracking(HWND Wnd, HMENU Menu, BOOL Popup, UINT Flags)
{
- return(LOWORD((ULONG)Text) < 12);
-}
+ DPRINT("Wnd=%p Menu=%p\n", Wnd, Menu);
-static HBITMAP
-MenuLoadMagicItem(ULONG Id, ULONG Hilite, ULONG ItemData)
-{
- UNIMPLEMENTED;
- return(NULL);
-}
+ HideCaret(0);
-static VOID
-MenuCalcItemSize(HDC hDC, PMENUITEM Item, HWND hWndOwner, LONG orgX,
- LONG orgY, BOOL MenuBar)
-{
- ULONG CheckBitmapWidth = GetSystemMetrics(SM_CXMENUCHECK);
+ /* Send WM_ENTERMENULOOP and WM_INITMENU message only if TPM_NONOTIFY flag is not specified */
+ if (0 == (Flags & TPM_NONOTIFY))
+ {
+ SendMessageW(Wnd, WM_ENTERMENULOOP, Popup, 0);
+ }
- SetRect(&Item->Rect, orgX, orgY, orgX, orgY);
+ SendMessageW(Wnd, WM_SETCURSOR, (WPARAM) Wnd, HTCAPTION);
- if (Item->TypeData & MF_OWNERDRAW)
+ if (0 == (Flags & TPM_NONOTIFY))
{
- MEASUREITEMSTRUCT mis;
+ ROSMENUINFO MenuInfo;
- mis.CtlType = ODT_MENU;
- mis.CtlID = 0;
- mis.itemID = Item->Id;
- mis.itemData = Item->ItemData;
- mis.itemHeight = 0;
- mis.itemWidth = 0;
- SendMessageA(hWndOwner, WM_MEASUREITEM, 0, (LPARAM)&mis);
- Item->Rect.right += mis.itemWidth;
+ SendMessageW(Wnd, WM_INITMENU, (WPARAM)Menu, 0);
- if (MenuBar)
- {
- Item->Rect.right += MENU_BAR_ITEMS_SPACE;
+ if (MenuGetRosMenuInfo(&MenuInfo, Menu) && 0 == MenuInfo.Height)
+ {
+ /* app changed/recreated menu bar entries in WM_INITMENU
+ Recalculate menu sizes else clicks will not work */
+ SetWindowPos(Wnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
+ SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
- Item->Rect.bottom += GetSystemMetrics(SM_CYMENU);
- }
- else
- {
- Item->Rect.bottom += mis.itemHeight;
- }
+ }
}
- if (Item->ItemData & MF_SEPARATOR)
+ return TRUE;
+}
+
+
+/***********************************************************************
+ * MenuShowPopup
+ *
+ * Display a popup menu.
+ */
+static BOOL FASTCALL
+MenuShowPopup(HWND WndOwner, HMENU Menu, UINT Id,
+ INT X, INT Y, INT XAnchor, INT YAnchor )
+{
+ ROSMENUINFO MenuInfo;
+ ROSMENUITEMINFO ItemInfo;
+ UINT Width, Height;
+
+ DPRINT("owner=%x hmenu=%x id=0x%04x x=0x%04x y=0x%04x xa=0x%04x ya=0x%04x\n",
+ WndOwner, Menu, Id, X, Y, XAnchor, YAnchor);
+
+ if (! MenuGetRosMenuInfo(&MenuInfo, Menu))
{
- Item->Rect.bottom += SEPARATOR_HEIGHT;
- return;
+ return FALSE;
}
- if (!MenuBar)
+ if (NO_SELECTED_ITEM != MenuInfo.FocusedItem)
{
- Item->Rect.right += 2 * CheckBitmapWidth;
- if (Item->TypeData & MF_POPUP)
- {
- Item->Rect.right += ArrowBitmapWidth;
- }
+ MenuInitRosMenuItemInfo(&ItemInfo);
+ if (MenuGetRosMenuItemInfo(MenuInfo.Self, MenuInfo.FocusedItem, &ItemInfo))
+ {
+ ItemInfo.fState &= ~(MF_HILITE|MF_MOUSESELECT);
+ MenuSetRosMenuItemInfo(MenuInfo.Self, MenuInfo.FocusedItem, &ItemInfo);
+ }
+ MenuCleanupRosMenuItemInfo(&ItemInfo);
+ MenuInfo.FocusedItem = NO_SELECTED_ITEM;
}
- if (Item->TypeData & MF_OWNERDRAW)
+ /* store the owner for DrawItem */
+ MenuInfo.WndOwner = WndOwner;
+ MenuSetRosMenuInfo(&MenuInfo);
+
+ MenuPopupMenuCalcSize(&MenuInfo, WndOwner);
+
+ /* adjust popup menu pos so that it fits within the desktop */
+
+ Width = MenuInfo.Width + GetSystemMetrics(SM_CXBORDER);
+ Height = MenuInfo.Height + GetSystemMetrics(SM_CYBORDER);
+
+ if (GetSystemMetrics(SM_CXSCREEN ) < X + Width)
{
- return;
+ if (0 != XAnchor)
+ {
+ X -= Width - XAnchor;
+ }
+ if (GetSystemMetrics(SM_CXSCREEN) < X + Width)
+ {
+ X = GetSystemMetrics(SM_CXSCREEN) - Width;
+ }
+ }
+ if (X < 0 )
+ {
+ X = 0;
}
- if (MenuIsBitmapItem(Item->TypeData))
+ if (GetSystemMetrics(SM_CYSCREEN) < Y + Height)
+ {
+ if (0 != YAnchor)
+ {
+ Y -= Height + YAnchor;
+ }
+ if (GetSystemMetrics(SM_CYSCREEN) < Y + Height)
+ {
+ Y = GetSystemMetrics(SM_CYSCREEN) - Height;
+ }
+ }
+ if (Y < 0 )
{
- HBITMAP Bmp;
- BITMAP Bm;
+ Y = 0;
+ }
- if (MenuIsMagicItem(Item->Text))
- {
- Bmp = MenuLoadMagicItem((LONG)Item->Text,
- Item->TypeData & MF_HILITE,
- Item->ItemData);
- }
- else
- {
- Bmp = (HBITMAP)Item->Text;
- }
- if (GetObjectA(Bmp, sizeof(Bm), &Bm))
- {
- Item->Rect.right += Bm.bmWidth;
- Item->Rect.bottom += Bm.bmHeight;
- }
+ /* NOTE: In Windows, top menu popup is not owned. */
+ MenuInfo.Wnd = CreateWindowExW(0, POPUPMENU_CLASS_ATOMW, NULL,
+ WS_POPUP, X, Y, Width, Height,
+ WndOwner, 0, (HINSTANCE) GetWindowLongW(WndOwner, GWL_HINSTANCE),
+ (LPVOID) MenuInfo.Self);
+ if (NULL == MenuInfo.Wnd || ! MenuSetRosMenuInfo(&MenuInfo))
+ {
+ return FALSE;
}
-
- if (MenuIsStringItem(Item->TypeData))
+ if (NULL == TopPopup)
{
- SIZE size;
- LPWSTR p;
+ TopPopup = MenuInfo.Wnd;
+ }
- GetTextExtentPoint32W(hDC, Item->Text, wcslen(Item->Text), &size);
+ /* Display the window */
+ SetWindowPos(MenuInfo.Wnd, HWND_TOPMOST, 0, 0, 0, 0,
+ SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
+ UpdateWindow(MenuInfo.Wnd);
- Item->Rect.right += size.cx;
- Item->Rect.bottom += max(size.cy, GetSystemMetrics(SM_CYMENU));
- Item->XTab = 0;
+ return TRUE;
+}
- if (MenuBar)
- {
- Item->Rect.right += MENU_BAR_ITEMS_SPACE;
- }
- else if ((p = wcschr(Item->Text, '\t')) != NULL)
- {
- GetTextExtentPoint32W(hDC, Item->Text, (LONG)(p - Item->Text),
- &size);
- Item->XTab = CheckBitmapWidth + MENU_TAB_SPACE + size.cx;
- Item->Rect.right += MENU_TAB_SPACE;
- }
- else
- {
- if (wcschr(Item->Text, '\b') != NULL)
- {
- Item->Rect.right += MENU_TAB_SPACE;
- }
- Item->XTab = Item->Rect.right - CheckBitmapWidth - ArrowBitmapWidth;
- }
+/***********************************************************************
+ * MenuFindSubMenu
+ *
+ * Find a Sub menu. Return the position of the submenu, and modifies
+ * *hmenu in case it is found in another sub-menu.
+ * If the submenu cannot be found, NO_SELECTED_ITEM is returned.
+ */
+static UINT FASTCALL
+MenuFindSubMenu(HMENU *Menu, HMENU SubTarget)
+{
+ ROSMENUINFO MenuInfo;
+ ROSMENUITEMINFO ItemInfo;
+ UINT i;
+ HMENU SubMenu;
+ UINT Pos;
+
+ if ((HMENU) 0xffff == *Menu
+ || ! MenuGetRosMenuInfo(&MenuInfo, *Menu))
+ {
+ return NO_SELECTED_ITEM;
+ }
+
+ MenuInitRosMenuItemInfo(&ItemInfo);
+ for (i = 0; i < MenuInfo.MenuItemCount; i++)
+ {
+ if (! MenuGetRosMenuItemInfo(MenuInfo.Self, i, &ItemInfo))
+ {
+ MenuCleanupRosMenuItemInfo(&ItemInfo);
+ return NO_SELECTED_ITEM;
+ }
+ if (0 == (ItemInfo.fType & MF_POPUP))
+ {
+ continue;
+ }
+ if (ItemInfo.hSubMenu == SubTarget)
+ {
+ MenuCleanupRosMenuItemInfo(&ItemInfo);
+ return i;
+ }
+ SubMenu = ItemInfo.hSubMenu;
+ Pos = MenuFindSubMenu(&SubMenu, SubTarget);
+ if (NO_SELECTED_ITEM != Pos)
+ {
+ *Menu = SubMenu;
+ return Pos;
+ }
}
+ MenuCleanupRosMenuItemInfo(&ItemInfo);
+
+ return NO_SELECTED_ITEM;
}
-static VOID
-MenuMenuBarCalcSize(HDC hDC, LPRECT Rect, PPOPUP_MENU Menu, HWND hWndOwner)
+/***********************************************************************
+ * MenuSelectItem
+ */
+static void FASTCALL
+MenuSelectItem(HWND WndOwner, PROSMENUINFO MenuInfo, UINT Index,
+ BOOL SendMenuSelect, HMENU TopMenu)
{
- LONG maxY, start, helpPos, orgX, orgY, i;
- PMENUITEM Item;
+ HDC Dc;
+ ROSMENUITEMINFO ItemInfo;
+ ROSMENUINFO TopMenuInfo;
+ int Pos;
+
+ DPRINT("owner=%x menu=%p index=0x%04x select=0x%04x\n", WndOwner, MenuInfo, Index, SendMenuSelect);
- if (Rect == NULL || Menu == NULL)
+ if (NULL == MenuInfo || 0 == MenuInfo->MenuItemCount || NULL == MenuInfo->Wnd)
{
return;
}
- if (Menu->NrItems == 0)
+
+ if (MenuInfo->FocusedItem == Index)
{
return;
}
- Menu->Width = Rect->right - Rect->left;
- Menu->Height = 0;
- maxY = Rect->top + 1;
- start = 0;
- helpPos = -1;
- while (start < Menu->NrItems)
+
+ if (0 != (MenuInfo->Flags & MF_POPUP))
+ {
+ Dc = GetDC(MenuInfo->Wnd);
+ }
+ else
{
- Item = Menu->Items + start;
+ Dc = GetDCEx(MenuInfo->Wnd, 0, DCX_CACHE | DCX_WINDOW);
+ }
- orgX = Rect->left;
- orgY = maxY;
+ if (NULL == TopPopup)
+ {
+ TopPopup = MenuInfo->Wnd;
+ }
- for (i = start; i < Menu->NrItems; i++, Item++)
- {
- if (helpPos == -1 && Item->TypeData & MF_RIGHTJUSTIFY)
- {
- helpPos = i;
- }
- if (i != start && Item->TypeData & (MF_MENUBREAK | MF_MENUBARBREAK))
- {
- break;
- }
- MenuCalcItemSize(hDC, Item, hWndOwner, orgX, orgY, TRUE);
- if (Item->Rect.right > Rect->right)
- {
- if (i != start)
- {
- break;
- }
- else
- {
- Item->Rect.right = Rect->right;
- }
- }
- maxY = max(maxY, Item->Rect.bottom);
- orgX = Item->Rect.right;
- }
+ SelectObject(Dc, hMenuFont);
+ MenuInitRosMenuItemInfo(&ItemInfo);
- for (;start < i; start++)
- {
- Menu->Items[start].Rect.bottom = maxY;
- }
+ /* Clear previous highlighted item */
+ if (NO_SELECTED_ITEM != MenuInfo->FocusedItem)
+ {
+ if (MenuGetRosMenuItemInfo(MenuInfo->Self, MenuInfo->FocusedItem, &ItemInfo))
+ {
+ ItemInfo.fState &= ~(MF_HILITE|MF_MOUSESELECT);
+ MenuSetRosMenuItemInfo(MenuInfo->Self, MenuInfo->FocusedItem, &ItemInfo);
+ }
+ MenuDrawMenuItem(MenuInfo->Wnd, MenuInfo, WndOwner, Dc, &ItemInfo,
+ MenuInfo->Height, ! (MenuInfo->Flags & MF_POPUP),
+ ODA_SELECT);
+ }
+
+ /* Highlight new item (if any) */
+ MenuInfo->FocusedItem = Index;
+ MenuSetRosMenuInfo(MenuInfo);
+ if (NO_SELECTED_ITEM != MenuInfo->FocusedItem)
+ {
+ if (MenuGetRosMenuItemInfo(MenuInfo->Self, MenuInfo->FocusedItem, &ItemInfo))
+ {
+ if (0 == (ItemInfo.fType & MF_SEPARATOR))
+ {
+ ItemInfo.fState |= MF_HILITE;
+ MenuSetRosMenuItemInfo(MenuInfo->Self, MenuInfo->FocusedItem, &ItemInfo);
+ MenuDrawMenuItem(MenuInfo->Wnd, MenuInfo, WndOwner, Dc,
+ &ItemInfo, MenuInfo->Height, ! (MenuInfo->Flags & MF_POPUP),
+ ODA_SELECT);
+ }
+ if (SendMenuSelect)
+ {
+ SendMessageW(WndOwner, WM_MENUSELECT,
+ MAKELONG(ItemInfo.fType & MF_POPUP ? Index : ItemInfo.wID,
+ ItemInfo.fType | ItemInfo.fState | MF_MOUSESELECT |
+ (MenuInfo->Flags & MF_SYSMENU)), (LPARAM) MenuInfo->Self);
+ }
+ }
+ }
+ else if (SendMenuSelect)
+ {
+ if (NULL != TopMenu)
+ {
+ Pos = MenuFindSubMenu(&TopMenu, MenuInfo->Self);
+ if (NO_SELECTED_ITEM != Pos)
+ {
+ if (MenuGetRosMenuInfo(&TopMenuInfo, TopMenu)
+ && MenuGetRosMenuItemInfo(TopMenu, Pos, &ItemInfo))
+ {
+ SendMessageW(WndOwner, WM_MENUSELECT,
+ MAKELONG(Pos, ItemInfo.fType | ItemInfo.fState
+ | MF_MOUSESELECT
+ | (TopMenuInfo.Flags & MF_SYSMENU)),
+ (LPARAM) TopMenu);
+ }
+ }
+ }
+ }
+
+ MenuCleanupRosMenuItemInfo(&ItemInfo);
+ ReleaseDC(MenuInfo->Wnd, Dc);
+}
+
+/***********************************************************************
+ * MenuMoveSelection
+ *
+ * Moves currently selected item according to the Offset parameter.
+ * If there is no selection then it should select the last item if
+ * Offset is ITEM_PREV or the first item if Offset is ITEM_NEXT.
+ */
+static void FASTCALL
+MenuMoveSelection(HWND WndOwner, PROSMENUINFO MenuInfo, INT Offset)
+{
+ INT i;
+ ROSMENUITEMINFO ItemInfo;
+ INT OrigPos;
+
+ DPRINT("hwnd=%x menu=%x off=0x%04x\n", WndOwner, MenuInfo, Offset);
+
+ /* Prevent looping */
+ if (0 == MenuInfo->MenuItemCount || 0 == Offset)
+ return;
+ else if (Offset < -1)
+ Offset = -1;
+ else if (Offset > 1)
+ Offset = 1;
+
+ MenuInitRosMenuItemInfo(&ItemInfo);
+
+ OrigPos = MenuInfo->FocusedItem;
+ if (OrigPos == NO_SELECTED_ITEM) /* NO_SELECTED_ITEM is not -1 ! */
+ {
+ OrigPos = 0;
+ i = -1;
+ }
+ else
+ {
+ i = MenuInfo->FocusedItem;
}
- Rect->bottom = maxY;
- Menu->Height = Rect->bottom - Rect->top;
+ do
+ {
+ /* Step */
+ i += Offset;
+ /* Clip and wrap around */
+ if (i < 0)
+ {
+ i = MenuInfo->MenuItemCount - 1;
+ }
+ else if (i >= MenuInfo->MenuItemCount)
+ {
+ i = 0;
+ }
+ /* If this is a good candidate; */
+ if (MenuGetRosMenuItemInfo(MenuInfo->Self, i, &ItemInfo) &&
+ 0 == (ItemInfo.fType & MF_SEPARATOR) &&
+ 0 == (ItemInfo.fState & (MFS_DISABLED | MFS_GRAYED)) )
+ {
+ MenuSelectItem(WndOwner, MenuInfo, i, TRUE, NULL);
+ MenuCleanupRosMenuItemInfo(&ItemInfo);
+ return;
+ }
+ } while (i != OrigPos);
+
+ /* Not found */
+ MenuCleanupRosMenuItemInfo(&ItemInfo);
+}
- Item = Menu->Items + Menu->NrItems - 1;
- orgY = Item->Rect.top;
- orgX = Rect->right;
- for (i = Menu->NrItems; i >= helpPos; i--, Item--)
+/***********************************************************************
+ * MenuInitSysMenuPopup
+ *
+ * Grey the appropriate items in System menu.
+ */
+void FASTCALL
+MenuInitSysMenuPopup(HMENU Menu, DWORD Style, DWORD ClsStyle, LONG HitTest )
+{
+ BOOL Gray;
+ UINT DefItem;
+ #if 0
+ MENUITEMINFOW mii;
+ #endif
+
+ Gray = 0 == (Style & WS_THICKFRAME) || 0 != (Style & (WS_MAXIMIZE | WS_MINIMIZE));
+ EnableMenuItem(Menu, SC_SIZE, (Gray ? MF_GRAYED : MF_ENABLED));
+ Gray = 0 != (Style & WS_MAXIMIZE);
+ EnableMenuItem(Menu, SC_MOVE, (Gray ? MF_GRAYED : MF_ENABLED));
+ Gray = 0 == (Style & WS_MINIMIZEBOX) || 0 != (Style & WS_MINIMIZE);
+ EnableMenuItem(Menu, SC_MINIMIZE, (Gray ? MF_GRAYED : MF_ENABLED));
+ Gray = 0 == (Style & WS_MAXIMIZEBOX) || 0 != (Style & WS_MAXIMIZE);
+ EnableMenuItem(Menu, SC_MAXIMIZE, (Gray ? MF_GRAYED : MF_ENABLED));
+ Gray = 0 == (Style & (WS_MAXIMIZE | WS_MINIMIZE));
+ EnableMenuItem(Menu, SC_RESTORE, (Gray ? MF_GRAYED : MF_ENABLED));
+ Gray = 0 != (ClsStyle & CS_NOCLOSE);
+
+ /* The menu item must keep its state if it's disabled */
+ if (Gray)
{
- if (helpPos == -1 || helpPos > i)
- {
- break;
- }
- if (Item->Rect.top != orgY)
- {
- break;
- }
- if (Item->Rect.right >= orgX)
- {
- break;
- }
- Item->Rect.left += orgX - Item->Rect.right;
- Item->Rect.right = orgX;
- orgX = Item->Rect.left;
+ EnableMenuItem(Menu, SC_CLOSE, MF_GRAYED);
+ }
+
+ /* Set default menu item */
+ if(Style & WS_MINIMIZE)
+ {
+ DefItem = SC_RESTORE;
+ }
+ else
+ {
+ if(HitTest == HTCAPTION)
+ {
+ DefItem = ((Style & (WS_MAXIMIZE | WS_MINIMIZE)) ? SC_RESTORE : SC_MAXIMIZE);
}
+ else
+ {
+ DefItem = SC_CLOSE;
+ }
+ }
+ #if 0
+ mii.cbSize = sizeof(MENUITEMINFOW);
+ mii.fMask = MIIM_STATE;
+ if((DefItem != SC_CLOSE) && GetMenuItemInfoW(Menu, DefItem, FALSE, &mii) &&
+ (mii.fState & (MFS_GRAYED | MFS_DISABLED)))
+ {
+ DefItem = SC_CLOSE;
+ }
+ #endif
+ SetMenuDefaultItem(Menu, DefItem, MF_BYCOMMAND);
}
-VOID STATIC
-MenuDrawMenuItem(HWND hWnd, HMENU hMenu, HWND hWndOwner, HDC hDC,
- PMENUITEM Item, ULONG Height, BOOL MenuBar, ULONG OdAction)
+/***********************************************************************
+ * MenuShowSubPopup
+ *
+ * Display the sub-menu of the selected item of this menu.
+ * Return the handle of the submenu, or menu if no submenu to display.
+ */
+static HMENU FASTCALL
+MenuShowSubPopup(HWND WndOwner, PROSMENUINFO MenuInfo, BOOL SelectFirst, UINT Flags)
{
+ extern void FASTCALL NcGetSysPopupPos(HWND Wnd, RECT *Rect);
RECT Rect;
+ ROSMENUITEMINFO ItemInfo;
+ ROSMENUINFO SubMenuInfo;
+ HDC Dc;
+ HMENU Ret;
- if (Item->ItemData & MF_SYSMENU)
+ DPRINT("owner=%x menu=%p 0x%04x\n", WndOwner, MenuInfo, SelectFirst);
+
+ if (NO_SELECTED_ITEM == MenuInfo->FocusedItem)
{
- if (!IsIconic(hWnd))
- {
- UserDrawSysMenuButton(hWnd, hDC,
- Item->State & (MF_HILITE | MF_MOUSESELECT));
- }
- return;
+ return MenuInfo->Self;
}
- if (Item->ItemData & MF_OWNERDRAW)
+ MenuInitRosMenuItemInfo(&ItemInfo);
+ if (! MenuGetRosMenuItemInfo(MenuInfo->Self, MenuInfo->FocusedItem, &ItemInfo))
{
- DRAWITEMSTRUCT dis;
-
- dis.CtlType = ODT_MENU;
- dis.CtlID = 0;
- dis.itemID = Item->Id;
- dis.itemData = (ULONG)Item->ItemData;
- dis.itemState = 0;
- if (Item->State & MF_CHECKED)
- {
- dis.itemState |= ODS_CHECKED;
- }
- if (Item->State & MF_GRAYED)
- {
- dis.itemState |= ODS_GRAYED;
- }
- if (Item->State & MF_HILITE)
- {
- dis.itemState |= ODS_SELECTED;
- }
- dis.itemAction = OdAction;
- dis.hDC = hDC;
- dis.rcItem = Item->Rect;
- SendMessageA(hWndOwner, WM_DRAWITEM, 0, (LPARAM)&dis);
+ MenuCleanupRosMenuItemInfo(&ItemInfo);
+ return MenuInfo->Self;
+ }
+ if (0 == (ItemInfo.fType & MF_POPUP) || 0 != (ItemInfo.fState & (MF_GRAYED | MF_DISABLED)))
+ {
+ MenuCleanupRosMenuItemInfo(&ItemInfo);
+ return MenuInfo->Self;
}
- if (MenuBar && (Item->TypeData & MF_SEPARATOR))
+ /* message must be sent before using item,
+ because nearly everything may be changed by the application ! */
+
+ /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
+ if (0 == (Flags & TPM_NONOTIFY))
{
- return;
+ SendMessageW(WndOwner, WM_INITMENUPOPUP, (WPARAM) ItemInfo.hSubMenu,
+ MAKELONG(MenuInfo->FocusedItem, IS_SYSTEM_MENU(MenuInfo)));
}
- Rect = Item->Rect;
+ if (! MenuGetRosMenuItemInfo(MenuInfo->Self, MenuInfo->FocusedItem, &ItemInfo))
+ {
+ MenuCleanupRosMenuItemInfo(&ItemInfo);
+ return MenuInfo->Self;
+ }
+ Rect = ItemInfo.Rect;
- if (!(Item->TypeData & MF_OWNERDRAW))
+ /* correct item if modified as a reaction to WM_INITMENUPOPUP message */
+ if (0 == (ItemInfo.fState & MF_HILITE))
{
- if (Item->State & MF_HILITE)
- {
- if (!MenuIsBitmapItem(Item->TypeData))
- {
- FillRect(hDC, &Rect, GetSysColorBrush(COLOR_HIGHLIGHT));
- }
- }
+ if (0 != (MenuInfo->Flags & MF_POPUP))
+ {
+ Dc = GetDC(MenuInfo->Wnd);
+ }
else
- {
- FillRect(hDC, &Rect, GetSysColorBrush(COLOR_MENU));
- }
- }
+ {
+ Dc = GetDCEx(MenuInfo->Wnd, 0, DCX_CACHE | DCX_WINDOW);
+ }
+
+ SelectObject(Dc, hMenuFont);
- SetBkMode(hDC, TRANSPARENT);
+ ItemInfo.fState |= MF_HILITE;
+ MenuSetRosMenuItemInfo(MenuInfo->Self, MenuInfo->FocusedItem, &ItemInfo);
+ MenuDrawMenuItem(MenuInfo->Wnd, MenuInfo, WndOwner, Dc, &ItemInfo, MenuInfo->Height,
+ ! (MenuInfo->Flags & MF_POPUP), ODA_DRAWENTIRE);
+ ReleaseDC(MenuInfo->Wnd, Dc);
+ }
- if (!(Item->TypeData & MF_OWNERDRAW))
+ if (0 == ItemInfo.Rect.top && 0 == ItemInfo.Rect.left
+ && 0 == ItemInfo.Rect.bottom && 0 == ItemInfo.Rect.right)
{
- if (!MenuBar && (Item->TypeData & MF_MENUBARBREAK))
- {
- SelectObject(hDC, GetSysColorPen(COLOR_WINDOWFRAME));
- MoveToEx(hDC, Rect.left, 0, NULL);
- LineTo(hDC, Rect.left, Height);
- }
- if (Item->TypeData & MF_SEPARATOR)
- {
- SelectObject(hDC, GetSysColorPen(COLOR_WINDOWFRAME));
- MoveToEx(hDC, Rect.left, Rect.right + (SEPARATOR_HEIGHT / 2), NULL);
- LineTo(hDC, Rect.right, Rect.top + (SEPARATOR_HEIGHT / 2));
- return;
- }
+ ItemInfo.Rect = Rect;
}
- if (Item->State & MF_HILITE)
+ ItemInfo.fState |= MF_MOUSESELECT;
+
+ MenuSetRosMenuItemInfo(MenuInfo->Self, MenuInfo->FocusedItem, &ItemInfo);
+
+ if (IS_SYSTEM_MENU(MenuInfo))
{
- SetTextColor(hDC, GetSysColor(COLOR_HIGHLIGHTTEXT));
- if (!MenuIsBitmapItem(Item->Type))
- {
- SetBkColor(hDC, GetSysColor(COLOR_HIGHLIGHT));
- }
+ MenuInitSysMenuPopup(ItemInfo.hSubMenu, GetWindowLongW(MenuInfo->Wnd, GWL_STYLE),
+ GetClassLongW(MenuInfo->Wnd, GCL_STYLE), HTSYSMENU);
+
+ NcGetSysPopupPos(MenuInfo->Wnd, &Rect);
+ Rect.top = Rect.bottom;
+ Rect.right = GetSystemMetrics(SM_CXSIZE);
+ Rect.bottom = GetSystemMetrics(SM_CYSIZE);
}
else
{
- if (Item->State & MF_GRAYED)
+ GetWindowRect(MenuInfo->Wnd, &Rect);
+ if (0 != (MenuInfo->Flags & MF_POPUP))
{
- SetTextColor(hDC, GetSysColor(COLOR_GRAYTEXT));
- }
+ Rect.left += ItemInfo.Rect.right - GetSystemMetrics(SM_CXBORDER);
+ Rect.top += ItemInfo.Rect.top;
+ Rect.right = ItemInfo.Rect.left - ItemInfo.Rect.right + GetSystemMetrics(SM_CXBORDER);
+ Rect.bottom = ItemInfo.Rect.top - ItemInfo.Rect.bottom;
+ }
else
- {
- SetTextColor(hDC, GetSysColor(COLOR_MENUTEXT));
- }
- SetBkColor(hDC, GetSysColor(COLOR_MENU));
+ {
+ Rect.left += ItemInfo.Rect.left;
+ Rect.top += ItemInfo.Rect.bottom;
+ Rect.right = ItemInfo.Rect.right - ItemInfo.Rect.left;
+ Rect.bottom = ItemInfo.Rect.bottom - ItemInfo.Rect.top;
+ }
}
- if (!MenuBar)
+ MenuShowPopup(WndOwner, ItemInfo.hSubMenu, MenuInfo->FocusedItem,
+ Rect.left, Rect.top, Rect.right, Rect.bottom );
+ if (SelectFirst && MenuGetRosMenuInfo(&SubMenuInfo, ItemInfo.hSubMenu))
{
- LONG y = Rect.top + Rect.bottom;
- ULONG CheckBitmapWidth = GetSystemMetrics(SM_CXMENUCHECK);
- ULONG CheckBitmapHeight = GetSystemMetrics(SM_CYMENUCHECK);
-
- if (!(Item->TypeData & MF_OWNERDRAW))
- {
- HBITMAP bm;
- if (Item->TypeData & MF_CHECKED)
- {
- bm = Item->CheckBit;
- }
- else
- {
- bm = Item->UnCheckBit;
- }
- if (bm)
- {
- HDC hDCMem = CreateCompatibleDC(hDC);
- SelectObject(hDCMem, bm);
- BitBlt(hDC,
- Rect.left,
- (y - CheckBitmapHeight) / 2,
- CheckBitmapWidth,
- CheckBitmapHeight,
- hDCMem,
- 0,
- 0,
- SRCCOPY);
- DeleteDC(hDCMem);
- }
- else if (Item->TypeData & MF_CHECKED)
- {
- RECT r;
- ULONG Type;
- HBITMAP bm = CreateBitmap(CheckBitmapWidth, CheckBitmapHeight,
- 1, 1, NULL);
- HDC hDCMem = CreateCompatibleDC(hDC);
- SelectObject(hDCMem, bm);
- SetRect(&r, 0, 0, CheckBitmapWidth, CheckBitmapHeight);
- if (Item->TypeData & MFT_RADIOCHECK)
- {
- Type = DFCS_MENUBULLET;
- }
- else
- {
- Type = DFCS_MENUCHECK;
- }
- DrawFrameControl(hDCMem, &r, DFC_MENU, Type);
- BitBlt(hDC, Rect.left, (y - r.bottom) / 2, r.right, r.bottom,
- hDCMem, 0, 0, SRCCOPY);
- DeleteDC(hDCMem);
- DeleteObject(bm);
- }
- }
+ MenuMoveSelection(WndOwner, &SubMenuInfo, ITEM_NEXT);
+ }
- if (Item->TypeData & MF_POPUP)
- {
- HDC hDCMem = CreateCompatibleDC(hDC);
-
- SelectObject(hDCMem, hStdMnArrow);
- BitBlt(hDC,
- Rect.right - ArrowBitmapWidth - 1,
- (y - ArrowBitmapHeight) / 2,
- ArrowBitmapWidth,
- ArrowBitmapHeight,
- hDCMem,
- 0,
- 0,
- SRCCOPY);
- DeleteDC(hDCMem);
- }
+ Ret = ItemInfo.hSubMenu;
+ MenuCleanupRosMenuItemInfo(&ItemInfo);
- Rect.left += CheckBitmapWidth;
- Rect.right -= ArrowBitmapWidth;
+ return Ret;
+}
+
+/***********************************************************************
+ * MenuHideSubPopups
+ *
+ * Hide the sub-popup menus of this menu.
+ */
+static void FASTCALL
+MenuHideSubPopups(HWND WndOwner, PROSMENUINFO MenuInfo, BOOL SendMenuSelect)
+{
+ ROSMENUINFO SubMenuInfo;
+ ROSMENUITEMINFO ItemInfo;
+
+ DPRINT("owner=%x menu=%x 0x%04x\n", WndOwner, MenuInfo, SendMenuSelect);
+
+ if (NULL != MenuInfo && NULL != TopPopup && NO_SELECTED_ITEM != MenuInfo->FocusedItem)
+ {
+ MenuInitRosMenuItemInfo(&ItemInfo);
+ if (! MenuGetRosMenuItemInfo(MenuInfo->Self, MenuInfo->FocusedItem, &ItemInfo)
+ || 0 == (ItemInfo.fType & MF_POPUP)
+ || 0 == (ItemInfo.fState & MF_MOUSESELECT))
+ {
+ MenuCleanupRosMenuItemInfo(&ItemInfo);
+ return;
+ }
+ ItemInfo.fState &= ~MF_MOUSESELECT;
+ MenuSetRosMenuItemInfo(MenuInfo->Self, MenuInfo->FocusedItem, &ItemInfo);
+ if (MenuGetRosMenuInfo(&SubMenuInfo, ItemInfo.hSubMenu))
+ {
+ MenuHideSubPopups(WndOwner, &SubMenuInfo, FALSE);
+ MenuSelectItem(WndOwner, &SubMenuInfo, NO_SELECTED_ITEM, SendMenuSelect, NULL);
+ DestroyWindow(SubMenuInfo.Wnd);
+ SubMenuInfo.Wnd = NULL;
+ MenuSetRosMenuInfo(&SubMenuInfo);
+ }
}
+}
- if (Item->TypeData & MF_OWNERDRAW)
+/***********************************************************************
+ * MenuSwitchTracking
+ *
+ * Helper function for menu navigation routines.
+ */
+static void FASTCALL
+MenuSwitchTracking(MTRACKER* Mt, PROSMENUINFO PtMenuInfo, UINT Index)
+{
+ ROSMENUINFO TopMenuInfo;
+
+ DPRINT("%x menu=%x 0x%04x\n", Mt, PtMenuInfo->Self, Index);
+
+ if (MenuGetRosMenuInfo(&TopMenuInfo, Mt->TopMenu) &&
+ Mt->TopMenu != PtMenuInfo->Self &&
+ 0 == ((PtMenuInfo->Flags | TopMenuInfo.Flags) & MF_POPUP))
{
- return;
+ /* both are top level menus (system and menu-bar) */
+ MenuHideSubPopups(Mt->OwnerWnd, &TopMenuInfo, FALSE);
+ MenuSelectItem(Mt->OwnerWnd, &TopMenuInfo, NO_SELECTED_ITEM, FALSE, NULL);
+ Mt->TopMenu = PtMenuInfo->Self;
+ }
+ else
+ {
+ MenuHideSubPopups(Mt->OwnerWnd, PtMenuInfo, FALSE);
}
- if (MenuIsBitmapItem(Item->TypeData))
+ MenuSelectItem(Mt->OwnerWnd, PtMenuInfo, Index, TRUE, NULL);
+}
+
+/***********************************************************************
+ * MenuExecFocusedItem
+ *
+ * Execute a menu item (for instance when user pressed Enter).
+ * Return the wID of the executed item. Otherwise, -1 indicating
+ * that no menu item was executed;
+ * Have to receive the flags for the TrackPopupMenu options to avoid
+ * sending unwanted message.
+ *
+ */
+static INT FASTCALL
+MenuExecFocusedItem(MTRACKER *Mt, PROSMENUINFO MenuInfo, UINT Flags)
+{
+ ROSMENUITEMINFO ItemInfo;
+ UINT wID;
+
+ DPRINT("%p menu=%p\n", Mt, MenuInfo);
+
+ if (0 == MenuInfo->MenuItemCount || NO_SELECTED_ITEM == MenuInfo->FocusedItem)
{
- LONG left, top, w, h;
- ULONG Rop;
- HBITMAP ResBmp = 0;
- HDC hDCMem = CreateCompatibleDC(hDC);
+ return -1;
+ }
- if (MenuIsMagicItem(Item->Text))
- {
- ResBmp = MenuLoadMagicItem((LONG)Item->Text, Item->State & MF_HILITE,
- Item->ItemData);
- }
- else
- {
- ResBmp = (HBITMAP)Item->Text;
- }
+ MenuInitRosMenuItemInfo(&ItemInfo);
+ if (! MenuGetRosMenuItemInfo(MenuInfo->Self, MenuInfo->FocusedItem, &ItemInfo))
+ {
+ MenuCleanupRosMenuItemInfo(&ItemInfo);
+ return -1;
+ }
- if (ResBmp)
- {
- BITMAP Bm;
+ DPRINT("%p %08x %p\n", MenuInfo, ItemInfo.wID, ItemInfo.hSubMenu);
- GetObjectA(ResBmp, sizeof(Bm), &Bm);
- SelectObject(hDCMem, ResBmp);
- h = Rect.bottom - Rect.top;
- if (h > Bm.bmHeight)
- {
- top = Rect.top + (h - Bm.bmHeight) / 2;
- }
- else
- {
- top = Rect.top;
- }
- w = Rect.right - Rect.left;
- left = Rect.left;
- left++;
- w -= 2;
- if ((Item->State & MF_HILITE) && !MenuIsMagicItem(Item->Text) &&
- !MenuBar)
- {
- Rop = MERGEPAINT;
- }
- else
+ if (0 == (ItemInfo.fType & MF_POPUP))
+ {
+ if (0 == (ItemInfo.fState & (MF_GRAYED | MF_DISABLED))
+ && 0 == (ItemInfo.fType & MF_SEPARATOR))
+ {
+ /* If TPM_RETURNCMD is set you return the id, but
+ do not send a message to the owner */
+ if (0 == (Flags & TPM_RETURNCMD))
{
- Rop = SRCCOPY;
- }
- BitBlt(hDC, left, top, w, h, hDCMem, 0, 0, Rop);
- }
- DeleteDC(hDCMem);
- return;
+ if (0 != (MenuInfo->Flags & MF_SYSMENU))
+ {
+ PostMessageW(Mt->OwnerWnd, WM_SYSCOMMAND, ItemInfo.wID,
+ MAKELPARAM((SHORT) Mt->Pt.x, (SHORT) Mt->Pt.y));
+ }
+ else
+ {
+ PostMessageW(Mt->OwnerWnd, WM_COMMAND, ItemInfo.wID, 0);
+ }
+ }
+ wID = ItemInfo.wID;
+ MenuCleanupRosMenuItemInfo(&ItemInfo);
+ return wID;
+ }
}
- else if (MenuIsStringItem(Item->Type))
+ else
{
- LONG i;
- HFONT hFontOld = 0;
- UINT Format = (MenuBar) ? DT_CENTER | DT_VCENTER | DT_SINGLELINE :
- DT_LEFT | DT_VCENTER | DT_SINGLELINE;
+ Mt->CurrentMenu = MenuShowSubPopup(Mt->OwnerWnd, MenuInfo, TRUE, Flags);
+ }
- if (Item->State & MFS_DEFAULT)
- {
- hFontOld = SelectObject(hDC, hMenuFontBold);
- }
+ return -1;
+}
- if (MenuBar)
- {
- Rect.left += MENU_BAR_ITEMS_SPACE / 2;
- Rect.right += MENU_BAR_ITEMS_SPACE / 2;
- i = wcslen(Item->Text);
- }
+/***********************************************************************
+ * MenuButtonDown
+ *
+ * Return TRUE if we can go on with menu tracking.
+ */
+static BOOL FASTCALL
+MenuButtonDown(MTRACKER* Mt, HMENU PtMenu, UINT Flags)
+{
+ int Index;
+ ROSMENUINFO MenuInfo;
+ ROSMENUITEMINFO Item;
+
+ DPRINT("%x PtMenu=%p\n", Mt, PtMenu);
+
+ if (NULL != PtMenu)
+ {
+ if (! MenuGetRosMenuInfo(&MenuInfo, PtMenu))
+ {
+ return FALSE;
+ }
+ if (IS_SYSTEM_MENU(&MenuInfo))
+ {
+ Index = 0;
+ }
else
+ {
+ Index = NtUserMenuItemFromPoint(Mt->OwnerWnd, PtMenu, Mt->Pt.x, Mt->Pt.y);
+ }
+ MenuInitRosMenuItemInfo(&Item);
+ if (NO_SELECTED_ITEM == Index || ! MenuGetRosMenuItemInfo(PtMenu, Index, &Item))
+ {
+ MenuCleanupRosMenuItemInfo(&Item);
+ return FALSE;
+ }
+
+ if (!(Item.fType & MF_SEPARATOR) &&
+ !(Item.fState & (MFS_DISABLED | MFS_GRAYED)) )
{
- for (i = 0; i < wcslen(Item->Text); i++)
- {
- if (Item->Text[i] == '\t' || Item->Text[i] == '\b')
- {
- break;
- }
- }
- }
+ if (MenuInfo.FocusedItem != Index)
+ {
+ MenuSwitchTracking(Mt, &MenuInfo, Index);
+ }
- DrawTextW(hDC, Item->Text, i, &Rect, Format);
+ /* If the popup menu is not already "popped" */
+ if (0 == (Item.fState & MF_MOUSESELECT))
+ {
+ Mt->CurrentMenu = MenuShowSubPopup(Mt->OwnerWnd, &MenuInfo, FALSE, Flags);
+ }
+ }
- if (Item->Text[i] != '\0')
- {
- if (Item->Text[i] == '\t')
- {
- Rect.left = Item->XTab;
- Format = DT_LEFT | DT_VCENTER | DT_SINGLELINE;
- }
- else
- {
- Format = DT_RIGHT | DT_VCENTER | DT_SINGLELINE;
- }
- DrawTextW(hDC, Item->Text + i + 1, -1, &Rect, Format);
- }
+ MenuCleanupRosMenuItemInfo(&Item);
- if (hFontOld != 0)
- {
- SelectObject(hDC, hFontOld);
- }
+ return TRUE;
}
+
+ /* else the click was on the menu bar, finish the tracking */
+
+ return FALSE;
}
-UINT
-MenuDrawMenuBar(HDC hDC, LPRECT Rect, HWND hWnd, BOOL Draw)
+/***********************************************************************
+ * MenuButtonUp
+ *
+ * Return the value of MenuExecFocusedItem if
+ * the selected item was not a popup. Else open the popup.
+ * A -1 return value indicates that we go on with menu tracking.
+ *
+ */
+static INT FASTCALL
+MenuButtonUp(MTRACKER *Mt, HMENU PtMenu, UINT Flags)
{
- ULONG MenuID;
- PPOPUP_MENU Menu;
- HFONT hFontOld;
- ULONG i;
+ UINT Id;
+ ROSMENUINFO MenuInfo;
+ ROSMENUITEMINFO ItemInfo;
- MenuID = GetWindowLong(hWnd, GWL_ID);
- Menu = MenuGetMenu((HMENU)MenuID);
+ DPRINT("%p hmenu=%x\n", Mt, PtMenu);
- if (Menu == NULL || Rect == NULL)
+ if (NULL != PtMenu)
{
- return(GetSystemMetrics(SM_CYMENU));
+ Id = 0;
+ if (! MenuGetRosMenuInfo(&MenuInfo, PtMenu))
+ {
+ return -1;
+ }
+
+ if (! IS_SYSTEM_MENU(&MenuInfo))
+ {
+ Id = NtUserMenuItemFromPoint(Mt->OwnerWnd, MenuInfo.Self, Mt->Pt.x, Mt->Pt.y);
+ }
+ MenuInitRosMenuItemInfo(&ItemInfo);
+ if (0 <= Id && MenuGetRosMenuItemInfo(MenuInfo.Self, Id, &ItemInfo) &&
+ MenuInfo.FocusedItem == Id)
+ {
+ if (0 == (ItemInfo.fType & MF_POPUP))
+ {
+ MenuCleanupRosMenuItemInfo(&ItemInfo);
+ return MenuExecFocusedItem(Mt, &MenuInfo, Flags);
+ }
+ MenuCleanupRosMenuItemInfo(&ItemInfo);
+
+ /* If we are dealing with the top-level menu */
+ /* and this is a click on an already "popped" item: */
+ /* Stop the menu tracking and close the opened submenus */
+ if (Mt->TopMenu == MenuInfo.Self && MenuInfo.TimeToHide)
+ {
+ MenuCleanupRosMenuItemInfo(&ItemInfo);
+ return 0;
+ }
+ }
+ MenuCleanupRosMenuItemInfo(&ItemInfo);
+ MenuInfo.TimeToHide = TRUE;
+ MenuSetRosMenuInfo(&MenuInfo);
}
- hFontOld = SelectObject(hDC, hMenuFont);
+ return -1;
+}
+
+/***********************************************************************
+ * MenuPtMenu
+ *
+ * Walks menu chain trying to find a menu pt maps to.
+ */
+static HMENU FASTCALL
+MenuPtMenu(HMENU Menu, POINT Pt)
+{
+ extern LRESULT DefWndNCHitTest(HWND hWnd, POINT Point);
+ ROSMENUINFO MenuInfo;
+ ROSMENUITEMINFO ItemInfo;
+ HMENU Ret = NULL;
+ INT Ht;
- if (Menu->Height == 0)
+ if (! MenuGetRosMenuInfo(&MenuInfo, Menu))
{
- MenuMenuBarCalcSize(hDC, Rect, Menu, hWnd);
+ return NULL;
}
- Rect->bottom = Rect->top + Menu->Height;
+ /* try subpopup first (if any) */
+ if (NO_SELECTED_ITEM != MenuInfo.FocusedItem)
+ {
+ MenuInitRosMenuItemInfo(&ItemInfo);
+ if (MenuGetRosMenuItemInfo(MenuInfo.Self, MenuInfo.FocusedItem, &ItemInfo) &&
+ 0 != (ItemInfo.fType & MF_POPUP) &&
+ 0 != (ItemInfo.fState & MF_MOUSESELECT))
+ {
+ Ret = MenuPtMenu(ItemInfo.hSubMenu, Pt);
+ if (NULL != Ret)
+ {
+ MenuCleanupRosMenuItemInfo(&ItemInfo);
+ return Ret;
+ }
+ }
+ MenuCleanupRosMenuItemInfo(&ItemInfo);
+ }
- if (!Draw)
+ /* check the current window (avoiding WM_HITTEST) */
+ Ht = DefWndNCHitTest(MenuInfo.Wnd, Pt);
+ if (0 != (MenuInfo.Flags & MF_POPUP))
+ {
+ if (HTNOWHERE != Ht && HTERROR != Ht)
+ {
+ Ret = Menu;
+ }
+ }
+ else if (HTSYSMENU == Ht)
+ {
+ Ret = NtUserGetSystemMenu(MenuInfo.Wnd, FALSE);
+ }
+ else if (HTMENU == Ht)
{
- SelectObject(hDC, hFontOld);
- return(Menu->Height);
+ Ret = GetMenu(MenuInfo.Wnd);
}
- FillRect(hDC, Rect, GetSysColorBrush(COLOR_MENU));
+ return Ret;
+}
- SelectObject(hDC, GetSysColorPen(COLOR_WINDOWFRAME));
- MoveToEx(hDC, Rect->left, Rect->bottom, NULL);
- LineTo(hDC, Rect->right, Rect->bottom);
+/***********************************************************************
+ * MenuMouseMove
+ *
+ * Return TRUE if we can go on with menu tracking.
+ */
+static BOOL FASTCALL
+MenuMouseMove(MTRACKER *Mt, HMENU PtMenu, UINT Flags)
+{
+ UINT Index;
+ ROSMENUINFO MenuInfo;
+ ROSMENUITEMINFO ItemInfo;
- if (Menu->NrItems == 0)
+ if (NULL != PtMenu)
+ {
+ if (! MenuGetRosMenuInfo(&MenuInfo, PtMenu))
+ {
+ return TRUE;
+ }
+ if (IS_SYSTEM_MENU(&MenuInfo))
+ {
+ Index = 0;
+ }
+ else
+ {
+ Index = NtUserMenuItemFromPoint(Mt->OwnerWnd, PtMenu, Mt->Pt.x, Mt->Pt.y);
+ }
+ }
+ else
{
- SelectObject(hDC, hFontOld);
- return(GetSystemMetrics(SM_CYMENU));
+ Index = NO_SELECTED_ITEM;
}
- for (i = 0; i < Menu->NrItems; i++)
+ if (NO_SELECTED_ITEM == Index)
+ {
+ if (Mt->CurrentMenu == MenuInfo.Self ||
+ MenuGetRosMenuInfo(&MenuInfo, Mt->CurrentMenu))
+ {
+ MenuSelectItem(Mt->OwnerWnd, &MenuInfo, NO_SELECTED_ITEM,
+ TRUE, Mt->TopMenu);
+ }
+ }
+ else if (MenuInfo.FocusedItem != Index)
{
- MenuDrawMenuItem(hWnd, (HMENU)MenuID, hWnd, hDC,
- Menu->Items + i, Menu->Height, TRUE, ODA_DRAWENTIRE);
+ MenuInitRosMenuItemInfo(&ItemInfo);
+ if (MenuGetRosMenuItemInfo(MenuInfo.Self, Index, &ItemInfo) &&
+ !(ItemInfo.fType & MF_SEPARATOR) &&
+ !(ItemInfo.fState & (MFS_DISABLED | MFS_GRAYED)) )
+ {
+ MenuSwitchTracking(Mt, &MenuInfo, Index);
+ Mt->CurrentMenu = MenuShowSubPopup(Mt->OwnerWnd, &MenuInfo, FALSE, Flags);
+ }
+ MenuCleanupRosMenuItemInfo(&ItemInfo);
}
- SelectObject(hDC, hFontOld);
- return(Menu->Height);
+ return TRUE;
}
-ULONG
-MenuGetMenuBarHeight(HWND hWnd, ULONG MenuBarWidth, LONG OrgX, LONG OrgY)
+/******************************************************************************
+ *
+ * UINT MenuGetStartOfNextColumn(PROSMENUINFO MenuInfo)
+ */
+static UINT MenuGetStartOfNextColumn(PROSMENUINFO MenuInfo)
{
- ULONG MenuId;
- PPOPUP_MENU Menu;
- RECT Rect;
- HDC hDC;
+ UINT i;
+ PROSMENUITEMINFO MenuItems;
- MenuId = GetWindowLong(hWnd, GWL_ID);
- Menu = MenuGetMenu((HMENU)MenuId);
- if (Menu == NULL)
+ i = MenuInfo->FocusedItem;
+ if (NO_SELECTED_ITEM == i)
{
- return(0);
+ return i;
}
- hDC = GetDCEx(hWnd, 0, DCX_CACHE | DCX_WINDOW);
- SelectObject(hDC, hMenuFont);
- SetRect(&Rect, OrgX, OrgY, OrgX + MenuBarWidth,
- OrgY + GetSystemMetrics(SM_CYMENU));
- MenuMenuBarCalcSize(hDC, &Rect, Menu, hWnd);
- ReleaseDC(hWnd, hDC);
- return(Menu->Height);
+
+ if (MenuGetAllRosMenuItemInfo(MenuInfo->Self, &MenuItems) <= 0)
+ {
+ return NO_SELECTED_ITEM;
+ }
+
+ for (i++ ; i < MenuInfo->MenuItemCount; i++)
+ {
+ if (0 != (MenuItems[i].fType & MF_MENUBARBREAK))
+ {
+ return i;
+ }
+ }
+
+ return NO_SELECTED_ITEM;
+}
+
+/******************************************************************************
+ *
+ * UINT MenuGetStartOfPrevColumn(PROSMENUINFO MenuInfo)
+ */
+static UINT FASTCALL
+MenuGetStartOfPrevColumn(PROSMENUINFO MenuInfo)
+{
+ UINT i;
+ PROSMENUITEMINFO MenuItems;
+
+ if (0 == MenuInfo->FocusedItem || NO_SELECTED_ITEM == MenuInfo->FocusedItem)
+ {
+ return NO_SELECTED_ITEM;
+ }
+
+ if (MenuGetAllRosMenuItemInfo(MenuInfo->Self, &MenuItems) <= 0)
+ {
+ return NO_SELECTED_ITEM;
+ }
+
+ /* Find the start of the column */
+
+ for (i = MenuInfo->FocusedItem;
+ 0 != i && 0 == (MenuItems[i].fType & MF_MENUBARBREAK);
+ --i)
+ {
+ ; /* empty */
+ }
+
+ if (0 == i)
+ {
+ MenuCleanupAllRosMenuItemInfo(MenuItems);
+ return NO_SELECTED_ITEM;
+ }
+
+ for (--i; 0 != i; --i)
+ {
+ if (MenuItems[i].fType & MF_MENUBARBREAK)
+ {
+ break;
+ }
+ }
+
+ MenuCleanupAllRosMenuItemInfo(MenuItems);
+ DPRINT("ret %d.\n", i );
+
+ return i;
+}
+
+/***********************************************************************
+ * MenuGetSubPopup
+ *
+ * Return the handle of the selected sub-popup menu (if any).
+ */
+static HMENU FASTCALL
+MenuGetSubPopup(HMENU Menu)
+{
+ ROSMENUINFO MenuInfo;
+ ROSMENUITEMINFO ItemInfo;
+
+ if (! MenuGetRosMenuInfo(&MenuInfo, Menu)
+ || NO_SELECTED_ITEM == MenuInfo.FocusedItem)
+ {
+ return NULL;
+ }
+
+ MenuInitRosMenuItemInfo(&ItemInfo);
+ if (! MenuGetRosMenuItemInfo(MenuInfo.Self, MenuInfo.FocusedItem, &ItemInfo))
+ {
+ MenuCleanupRosMenuItemInfo(&ItemInfo);
+ return NULL;
+ }
+ if (0 != (ItemInfo.fType & MF_POPUP) && 0 != (ItemInfo.fState & MF_MOUSESELECT))
+ {
+ MenuCleanupRosMenuItemInfo(&ItemInfo);
+ return ItemInfo.hSubMenu;
+ }
+
+ MenuCleanupRosMenuItemInfo(&ItemInfo);
+ return NULL;
+}
+
+/***********************************************************************
+ * MenuDoNextMenu
+ *
+ * NOTE: WM_NEXTMENU documented in Win32 is a bit different.
+ */
+static LRESULT FASTCALL
+MenuDoNextMenu(MTRACKER* Mt, UINT Vk)
+{
+ ROSMENUINFO TopMenuInfo;
+ ROSMENUINFO MenuInfo;
+
+ if (! MenuGetRosMenuInfo(&TopMenuInfo, Mt->TopMenu))
+ {
+ return (LRESULT) FALSE;
+ }
+
+ if ((VK_LEFT == Vk && 0 == TopMenuInfo.FocusedItem)
+ || (VK_RIGHT == Vk && TopMenuInfo.FocusedItem == TopMenuInfo.MenuItemCount - 1))
+ {
+ MDINEXTMENU NextMenu;
+ HMENU NewMenu;
+ HWND NewWnd;
+ UINT Id = 0;
+
+ NextMenu.hmenuIn = (IS_SYSTEM_MENU(&TopMenuInfo)) ? GetSubMenu(Mt->TopMenu, 0) : Mt->TopMenu;
+ NextMenu.hmenuNext = NULL;
+ NextMenu.hwndNext = NULL;
+ SendMessageW(Mt->OwnerWnd, WM_NEXTMENU, Vk, (LPARAM) &NextMenu);
+
+ DPRINT("%p [%p] -> %p [%p]\n",
+ Mt->CurrentMenu, Mt->OwnerWnd, NextMenu.hmenuNext, NextMenu.hwndNext );
+
+ if (NULL == NextMenu.hmenuNext || NULL == NextMenu.hwndNext)
+ {
+ DWORD Style = GetWindowLongW(Mt->OwnerWnd, GWL_STYLE);
+ NewWnd = Mt->OwnerWnd;
+ if (IS_SYSTEM_MENU(&TopMenuInfo))
+ {
+ /* switch to the menu bar */
+
+ if (0 != (Style & WS_CHILD)
+ || NULL == (NewMenu = GetMenu(NewWnd)))
+ {
+ return FALSE;
+ }
+
+ if (VK_LEFT == Vk)
+ {
+ if (! MenuGetRosMenuInfo(&MenuInfo, NewMenu))
+ {
+ return FALSE;
+ }
+ Id = MenuInfo.MenuItemCount - 1;
+ }
+ }
+ else if (0 != (Style & WS_SYSMENU))
+ {
+ /* switch to the system menu */
+ NewMenu = NtUserGetSystemMenu(NewWnd, FALSE);
+ }
+ else
+ {
+ return FALSE;
+ }
+ }
+ else /* application returned a new menu to switch to */
+ {
+ NewMenu = NextMenu.hmenuNext;
+ NewWnd = NextMenu.hwndNext;
+
+ if (IsMenu(NewMenu) && IsWindow(NewWnd))
+ {
+ DWORD Style = GetWindowLongW(NewWnd, GWL_STYLE);
+
+ if (0 != (Style & WS_SYSMENU)
+ && GetSystemMenu(NewWnd, FALSE) == NewMenu)
+ {
+ /* get the real system menu */
+ NewMenu = NtUserGetSystemMenu(NewWnd, FALSE);
+ }
+ else if (0 != (Style & WS_CHILD) || GetMenu(NewWnd) != NewMenu)
+ {
+ /* FIXME: Not sure what to do here;
+ * perhaps try to track NewMenu as a popup? */
+
+ DPRINT(" -- got confused.\n");
+ return FALSE;
+ }
+ }
+ else
+ {
+ return FALSE;
+ }
+ }
+
+ if (NewMenu != Mt->TopMenu)
+ {
+ MenuSelectItem(Mt->OwnerWnd, &TopMenuInfo, NO_SELECTED_ITEM,
+ FALSE, 0 );
+ if (Mt->CurrentMenu != Mt->TopMenu)
+ {
+ MenuHideSubPopups(Mt->OwnerWnd, &TopMenuInfo, FALSE);
+ }
+ }
+
+ if (NewWnd != Mt->OwnerWnd)
+ {
+ Mt->OwnerWnd = NewWnd;
+ SetCapture(Mt->OwnerWnd);
+ NtUserSetGUIThreadHandle(MSQ_STATE_MENUOWNER, Mt->OwnerWnd);
+ }
+
+ Mt->TopMenu = Mt->CurrentMenu = NewMenu; /* all subpopups are hidden */
+ if (MenuGetRosMenuInfo(&TopMenuInfo, Mt->TopMenu))
+ {
+ MenuSelectItem(Mt->OwnerWnd, &TopMenuInfo, Id, TRUE, 0);
+ }
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/***********************************************************************
+ * MenuSuspendPopup
+ *
+ * The idea is not to show the popup if the next input message is
+ * going to hide it anyway.
+ */
+static BOOL FASTCALL
+MenuSuspendPopup(MTRACKER* Mt, UINT Message)
+{
+ MSG Msg;
+
+ Msg.hwnd = Mt->OwnerWnd;
+
+ PeekMessageW(&Msg, 0, 0, 0, PM_NOYIELD | PM_REMOVE);
+ Mt->TrackFlags |= TF_SKIPREMOVE;
+
+ switch (Message)
+ {
+ case WM_KEYDOWN:
+ PeekMessageW(&Msg, 0, 0, 0, PM_NOYIELD | PM_NOREMOVE);
+ if (WM_KEYUP == Msg.message || WM_PAINT == Msg.message)
+ {
+ PeekMessageW(&Msg, 0, 0, 0, PM_NOYIELD | PM_REMOVE);
+ PeekMessageW(&Msg, 0, 0, 0, PM_NOYIELD | PM_NOREMOVE);
+ if (WM_KEYDOWN == Msg.message
+ && (VK_LEFT == Msg.wParam || VK_RIGHT == Msg.wParam))
+ {
+ Mt->TrackFlags |= TF_SUSPENDPOPUP;
+ return TRUE;
+ }
+ }
+ break;
+ }
+
+ /* failures go through this */
+ Mt->TrackFlags &= ~TF_SUSPENDPOPUP;
+
+ return FALSE;
+}
+
+/***********************************************************************
+ * MenuKeyEscape
+ *
+ * Handle a VK_ESCAPE key event in a menu.
+ */
+static BOOL FASTCALL
+MenuKeyEscape(MTRACKER *Mt, UINT Flags)
+{
+ BOOL EndMenu = TRUE;
+ ROSMENUINFO MenuInfo;
+ HMENU MenuTmp, MenuPrev;
+
+ if (Mt->CurrentMenu != Mt->TopMenu)
+ {
+ if (MenuGetRosMenuInfo(&MenuInfo, Mt->CurrentMenu)
+ && 0 != (MenuInfo.Flags & MF_POPUP))
+ {
+ MenuPrev = MenuTmp = Mt->TopMenu;
+
+ /* close topmost popup */
+ while (MenuTmp != Mt->CurrentMenu)
+ {
+ MenuPrev = MenuTmp;
+ MenuTmp = MenuGetSubPopup(MenuPrev);
+ }
+
+ if (MenuGetRosMenuInfo(&MenuInfo, MenuPrev))
+ {
+ MenuHideSubPopups(Mt->OwnerWnd, &MenuInfo, TRUE);
+ }
+ Mt->CurrentMenu = MenuPrev;
+ EndMenu = FALSE;
+ }
+ }
+
+ return EndMenu;
+}
+
+/***********************************************************************
+ * MenuKeyLeft
+ *
+ * Handle a VK_LEFT key event in a menu.
+ */
+static void FASTCALL
+MenuKeyLeft(MTRACKER* Mt, UINT Flags)
+{
+ ROSMENUINFO MenuInfo;
+ ROSMENUINFO TopMenuInfo;
+ ROSMENUINFO PrevMenuInfo;
+ HMENU MenuTmp, MenuPrev;
+ UINT PrevCol;
+
+ MenuPrev = MenuTmp = Mt->TopMenu;
+
+ if (! MenuGetRosMenuInfo(&MenuInfo, Mt->CurrentMenu))
+ {
+ return;
+ }
+
+ /* Try to move 1 column left (if possible) */
+ if (NO_SELECTED_ITEM != (PrevCol = MenuGetStartOfPrevColumn(&MenuInfo)))
+ {
+ if (MenuGetRosMenuInfo(&MenuInfo, Mt->CurrentMenu))
+ {
+ MenuSelectItem(Mt->OwnerWnd, &MenuInfo, PrevCol, TRUE, 0);
+ }
+ return;
+ }
+
+ /* close topmost popup */
+ while (MenuTmp != Mt->CurrentMenu)
+ {
+ MenuPrev = MenuTmp;
+ MenuTmp = MenuGetSubPopup(MenuPrev);
+ }
+
+ if (! MenuGetRosMenuInfo(&PrevMenuInfo, MenuPrev))
+ {
+ return;
+ }
+ MenuHideSubPopups(Mt->OwnerWnd, &PrevMenuInfo, TRUE);
+ Mt->CurrentMenu = MenuPrev;
+
+ if (! MenuGetRosMenuInfo(&TopMenuInfo, Mt->TopMenu))
+ {
+ return;
+ }
+ if ((MenuPrev == Mt->TopMenu) && 0 == (TopMenuInfo.Flags & MF_POPUP))
+ {
+ /* move menu bar selection if no more popups are left */
+
+ if (! MenuDoNextMenu(Mt, VK_LEFT))
+ {
+ MenuMoveSelection(Mt->OwnerWnd, &TopMenuInfo, ITEM_PREV);
+ }
+
+ if (MenuPrev != MenuTmp || 0 != (Mt->TrackFlags & TF_SUSPENDPOPUP))
+ {
+ /* A sublevel menu was displayed - display the next one
+ * unless there is another displacement coming up */
+
+ if (! MenuSuspendPopup(Mt, WM_KEYDOWN)
+ && MenuGetRosMenuInfo(&TopMenuInfo, Mt->TopMenu))
+ {
+ Mt->CurrentMenu = MenuShowSubPopup(Mt->OwnerWnd, &TopMenuInfo,
+ TRUE, Flags);
+ }
+ }
+ }
+}
+
+/***********************************************************************
+ * MenuKeyRight
+ *
+ * Handle a VK_RIGHT key event in a menu.
+ */
+static void FASTCALL
+MenuKeyRight(MTRACKER *Mt, UINT Flags)
+{
+ HMENU MenuTmp;
+ ROSMENUINFO MenuInfo;
+ ROSMENUINFO CurrentMenuInfo;
+ UINT NextCol;
+
+ DPRINT("MenuKeyRight called, cur %p, top %p.\n",
+ Mt->CurrentMenu, Mt->TopMenu);
+
+ if (! MenuGetRosMenuInfo(&MenuInfo, Mt->TopMenu))
+ {
+ return;
+ }
+ if (0 != (MenuInfo.Flags & MF_POPUP) || (Mt->CurrentMenu != Mt->TopMenu))
+ {
+ /* If already displaying a popup, try to display sub-popup */
+
+ MenuTmp = Mt->CurrentMenu;
+ if (MenuGetRosMenuInfo(&CurrentMenuInfo, Mt->CurrentMenu))
+ {
+ Mt->CurrentMenu = MenuShowSubPopup(Mt->OwnerWnd, &CurrentMenuInfo, TRUE, Flags);
+ }
+
+ /* if subpopup was displayed then we are done */
+ if (MenuTmp != Mt->CurrentMenu)
+ {
+ return;
+ }
+ }
+
+ if (! MenuGetRosMenuInfo(&CurrentMenuInfo, Mt->CurrentMenu))
+ {
+ return;
+ }
+
+ /* Check to see if there's another column */
+ if (NO_SELECTED_ITEM != (NextCol = MenuGetStartOfNextColumn(&CurrentMenuInfo)))
+ {
+ DPRINT("Going to %d.\n", NextCol);
+ if (MenuGetRosMenuInfo(&MenuInfo, Mt->CurrentMenu))
+ {
+ MenuSelectItem(Mt->OwnerWnd, &MenuInfo, NextCol, TRUE, 0);
+ }
+ return;
+ }
+
+ if (0 == (MenuInfo.Flags & MF_POPUP)) /* menu bar tracking */
+ {
+ if (Mt->CurrentMenu != Mt->TopMenu)
+ {
+ MenuHideSubPopups(Mt->OwnerWnd, &MenuInfo, FALSE );
+ MenuTmp = Mt->CurrentMenu = Mt->TopMenu;
+ }
+ else
+ {
+ MenuTmp = NULL;
+ }
+
+ /* try to move to the next item */
+ if (! MenuDoNextMenu(Mt, VK_RIGHT))
+ {
+ MenuMoveSelection(Mt->OwnerWnd, &MenuInfo, ITEM_NEXT);
+ }
+
+ if (NULL != MenuTmp || 0 != (Mt->TrackFlags & TF_SUSPENDPOPUP))
+ {
+ if (! MenuSuspendPopup(Mt, WM_KEYDOWN)
+ && MenuGetRosMenuInfo(&MenuInfo, Mt->TopMenu))
+ {
+ Mt->CurrentMenu = MenuShowSubPopup(Mt->OwnerWnd, &MenuInfo,
+ TRUE, Flags);
+ }
+ }
+ }
+}
+
+/***********************************************************************
+ * MenuFindItemByKey
+ *
+ * Find the menu item selected by a key press.
+ * Return item id, -1 if none, -2 if we should close the menu.
+ */
+static UINT FASTCALL
+MenuFindItemByKey(HWND WndOwner, PROSMENUINFO MenuInfo,
+ WCHAR Key, BOOL ForceMenuChar)
+{
+ ROSMENUINFO SysMenuInfo;
+ PROSMENUITEMINFO Items, ItemInfo;
+ LRESULT MenuChar;
+ UINT i;
+
+ DPRINT("\tlooking for '%c' (0x%02x) in [%p]\n", (char) Key, Key, MenuInfo);
+
+ if (NULL == MenuInfo || ! IsMenu(MenuInfo->Self))
+ {
+ if (MenuGetRosMenuInfo(&SysMenuInfo, GetSystemMenu(WndOwner, FALSE)))
+ {
+ MenuInfo = &SysMenuInfo;
+ }
+ else
+ {
+ MenuInfo = NULL;
+ }
+ }
+
+ if (NULL != MenuInfo)
+ {
+ if (MenuGetAllRosMenuItemInfo(MenuInfo->Self, &Items) <= 0)
+ {
+ return -1;
+ }
+ if (! ForceMenuChar)
+ {
+ Key = towupper(Key);
+ ItemInfo = Items;
+ for (i = 0; i < MenuInfo->MenuItemCount; i++, ItemInfo++)
+ {
+ if (IS_STRING_ITEM(ItemInfo->fType) && NULL != ItemInfo->dwTypeData)
+ {
+ WCHAR *p = (WCHAR *) ItemInfo->dwTypeData - 2;
+ do
+ {
+ p = wcschr(p + 2, '&');
+ }
+ while (NULL != p && L'&' == p[1]);
+ if (NULL != p && (towupper(p[1]) == Key))
+ {
+ return i;
+ }
+ }
+ }
+ }
+
+ MenuChar = SendMessageW(WndOwner, WM_MENUCHAR,
+ MAKEWPARAM(Key, MenuInfo->Flags), (LPARAM) MenuInfo->Self);
+ if (2 == HIWORD(MenuChar))
+ {
+ return LOWORD(MenuChar);
+ }
+ if (1 == HIWORD(MenuChar))
+ {
+ return (UINT) (-2);
+ }
+ }
+
+ return (UINT)(-1);
+}
+
+/***********************************************************************
+ * MenuTrackMenu
+ *
+ * Menu tracking code.
+ */
+static INT FASTCALL
+MenuTrackMenu(HMENU Menu, UINT Flags, INT x, INT y,
+ HWND Wnd, const RECT *Rect )
+{
+ MSG Msg;
+ ROSMENUINFO MenuInfo;
+ ROSMENUITEMINFO ItemInfo;
+ BOOL fRemove;
+ INT ExecutedMenuId = -1;
+ MTRACKER Mt;
+ BOOL EnterIdleSent = FALSE;
+
+ Mt.TrackFlags = 0;
+ Mt.CurrentMenu = Menu;
+ Mt.TopMenu = Menu;
+ Mt.OwnerWnd = Wnd;
+ Mt.Pt.x = x;
+ Mt.Pt.y = y;
+
+ DPRINT("Menu=%x Flags=0x%08x (%d,%d) Wnd=%x (%ld,%ld)-(%ld,%ld)\n",
+ Menu, Flags, x, y, Wnd, Rect ? Rect->left : 0, Rect ? Rect->top : 0,
+ Rect ? Rect->right : 0, Rect ? Rect->bottom : 0);
+
+ fEndMenu = FALSE;
+ if (! MenuGetRosMenuInfo(&MenuInfo, Menu))
+ {
+ return FALSE;
+ }
+
+ if (0 != (Flags & TPM_BUTTONDOWN))
+ {
+ /* Get the result in order to start the tracking or not */
+ fRemove = MenuButtonDown(&Mt, Menu, Flags);
+ fEndMenu = ! fRemove;
+ }
+
+ SetCapture(Mt.OwnerWnd);
+ NtUserSetGUIThreadHandle(MSQ_STATE_MENUOWNER, Mt.OwnerWnd);
+
+ while (! fEndMenu)
+ {
+ /* we have to keep the message in the queue until it's
+ * clear that menu loop is not over yet. */
+
+ for (;;)
+ {
+ if (PeekMessageW(&Msg, 0, 0, 0, PM_NOREMOVE))
+ {
+ if (! CallMsgFilterW(&Msg, MSGF_MENU))
+ {
+ break;
+ }
+ /* remove the message from the queue */
+ PeekMessageW(&Msg, 0, Msg.message, Msg.message, PM_REMOVE );
+ }
+ else
+ {
+ if (! EnterIdleSent)
+ {
+ HWND Win = (0 != (Flags & TPM_ENTERIDLEEX)
+ && 0 != (MenuInfo.Flags & MF_POPUP)) ? MenuInfo.Wnd : NULL;
+ EnterIdleSent = TRUE;
+ SendMessageW(Mt.OwnerWnd, WM_ENTERIDLE, MSGF_MENU, (LPARAM) Win);
+ }
+ WaitMessage();
+ }
+ }
+
+ /* check if EndMenu() tried to cancel us, by posting this message */
+ if (WM_CANCELMODE == Msg.message)
+ {
+ /* we are now out of the loop */
+ fEndMenu = TRUE;
+
+ /* remove the message from the queue */
+ PeekMessageW(&Msg, 0, Msg.message, Msg.message, PM_REMOVE);
+
+ /* break out of internal loop, ala ESCAPE */
+ break;
+ }
+
+ TranslateMessage(&Msg);
+ Mt.Pt = Msg.pt;
+
+ if (Msg.hwnd == MenuInfo.Wnd || WM_TIMER != Msg.message)
+ {
+ EnterIdleSent = FALSE;
+ }
+
+ fRemove = FALSE;
+ if (WM_MOUSEFIRST <= Msg.message && Msg.message <= WM_MOUSELAST)
+ {
+ /*
+ * Use the mouse coordinates in lParam instead of those in the MSG
+ * struct to properly handle synthetic messages. They are already
+ * in screen coordinates.
+ */
+ Mt.Pt.x = (short) LOWORD(Msg.lParam);
+ Mt.Pt.y = (short) HIWORD(Msg.lParam);
+
+ /* Find a menu for this mouse event */
+ Menu = MenuPtMenu(Mt.TopMenu, Mt.Pt);
+
+ switch(Msg.message)
+ {
+ /* no WM_NC... messages in captured state */
+
+ case WM_RBUTTONDBLCLK:
+ case WM_RBUTTONDOWN:
+ if (0 == (Flags & TPM_RIGHTBUTTON))
+ {
+ break;
+ }
+ /* fall through */
+ case WM_LBUTTONDBLCLK:
+ case WM_LBUTTONDOWN:
+ /* If the message belongs to the menu, removes it from the queue */
+ /* Else, end menu tracking */
+ fRemove = MenuButtonDown(&Mt, Menu, Flags);
+ fEndMenu = ! fRemove;
+ break;
+
+ case WM_RBUTTONUP:
+ if (0 == (Flags & TPM_RIGHTBUTTON))
+ {
+ break;
+ }
+ /* fall through */
+ case WM_LBUTTONUP:
+ /* Check if a menu was selected by the mouse */
+ if (NULL != Menu)
+ {
+ ExecutedMenuId = MenuButtonUp(&Mt, Menu, Flags);
+
+ /* End the loop if ExecutedMenuId is an item ID */
+ /* or if the job was done (ExecutedMenuId = 0). */
+ fEndMenu = fRemove = (-1 != ExecutedMenuId);
+ }
+ else
+ {
+ /* No menu was selected by the mouse */
+ /* if the function was called by TrackPopupMenu, continue
+ with the menu tracking. If not, stop it */
+ fEndMenu = (0 != (Flags & TPM_POPUPMENU) ? FALSE : TRUE);
+ }
+ break;
+
+ case WM_MOUSEMOVE:
+ if (Menu)
+ {
+ fEndMenu |= ! MenuMouseMove(&Mt, Menu, Flags);
+ }
+ break;
+
+ } /* switch(Msg.message) - mouse */
+ }
+ else if (WM_KEYFIRST <= Msg.message && Msg.message <= WM_KEYLAST)
+ {
+ fRemove = TRUE; /* Keyboard messages are always removed */
+ switch(Msg.message)
+ {
+ case WM_KEYDOWN:
+ switch(Msg.wParam)
+ {
+ case VK_HOME:
+ case VK_END:
+ if (MenuGetRosMenuInfo(&MenuInfo, Mt.CurrentMenu))
+ {
+ MenuSelectItem(Mt.OwnerWnd, &MenuInfo, NO_SELECTED_ITEM,
+ FALSE, 0 );
+ }
+ /* fall through */
+
+ case VK_UP:
+ if (MenuGetRosMenuInfo(&MenuInfo, Mt.CurrentMenu))
+ {
+ MenuMoveSelection(Mt.OwnerWnd, &MenuInfo,
+ VK_HOME == Msg.wParam ? ITEM_NEXT : ITEM_PREV);
+ }
+ break;
+
+ case VK_DOWN: /* If on menu bar, pull-down the menu */
+ if (MenuGetRosMenuInfo(&MenuInfo, Mt.CurrentMenu))
+ {
+ if (0 == (MenuInfo.Flags & MF_POPUP))
+ {
+ if (MenuGetRosMenuInfo(&MenuInfo, Mt.TopMenu))
+ {
+ Mt.CurrentMenu = MenuShowSubPopup(Mt.OwnerWnd, &MenuInfo,
+ TRUE, Flags);
+ }
+ }
+ else /* otherwise try to move selection */
+ {
+ MenuMoveSelection(Mt.OwnerWnd, &MenuInfo, ITEM_NEXT);
+ }
+ }
+ break;
+
+ case VK_LEFT:
+ MenuKeyLeft(&Mt, Flags);
+ break;
+
+ case VK_RIGHT:
+ MenuKeyRight(&Mt, Flags);
+ break;
+
+ case VK_ESCAPE:
+ fEndMenu = MenuKeyEscape(&Mt, Flags);
+ break;
+
+ case VK_F1:
+ {
+ HELPINFO hi;
+ hi.cbSize = sizeof(HELPINFO);
+ hi.iContextType = HELPINFO_MENUITEM;
+ if (MenuGetRosMenuInfo(&MenuInfo, Mt.CurrentMenu))
+ {
+ if (NO_SELECTED_ITEM == MenuInfo.FocusedItem)
+ {
+ hi.iCtrlId = 0;
+ }
+ else
+ {
+ MenuInitRosMenuItemInfo(&ItemInfo);
+ if (MenuGetRosMenuItemInfo(MenuInfo.Self,
+ MenuInfo.FocusedItem,
+ &ItemInfo))
+ {
+ hi.iCtrlId = ItemInfo.wID;
+ }
+ else
+ {
+ hi.iCtrlId = 0;
+ }
+ MenuCleanupRosMenuItemInfo(&ItemInfo);
+ }
+ }
+ hi.hItemHandle = Menu;
+ hi.dwContextId = MenuInfo.dwContextHelpID;
+ hi.MousePos = Msg.pt;
+ SendMessageW(Wnd, WM_HELP, 0, (LPARAM) &hi);
+ break;
+ }
+
+ default:
+ break;
+ }
+ break; /* WM_KEYDOWN */
+
+ case WM_SYSKEYDOWN:
+ switch (Msg.wParam)
+ {
+ DbgPrint("Menu.c WM_SYSKEYDOWN wPram %d\n",Msg.wParam);
+ case VK_MENU:
+ fEndMenu = TRUE;
+ break;
+ case VK_LMENU:
+ fEndMenu = TRUE;
+ break;
+ }
+ break; /* WM_SYSKEYDOWN */
+
+ case WM_CHAR:
+ {
+ UINT Pos;
+
+ if (! MenuGetRosMenuInfo(&MenuInfo, Mt.CurrentMenu))
+ {
+ break;
+ }
+ if (L'\r' == Msg.wParam || L' ' == Msg.wParam)
+ {
+ ExecutedMenuId = MenuExecFocusedItem(&Mt, &MenuInfo, Flags);
+ fEndMenu = (ExecutedMenuId != -1);
+ break;
+ }
+
+ /* Hack to avoid control chars. */
+ /* We will find a better way real soon... */
+ if (Msg.wParam < 32)
+ {
+ break;
+ }
+
+ Pos = MenuFindItemByKey(Mt.OwnerWnd, &MenuInfo,
+ LOWORD(Msg.wParam), FALSE);
+ if ((UINT) -2 == Pos)
+ {
+ fEndMenu = TRUE;
+ }
+ else if ((UINT) -1 == Pos)
+ {
+ MessageBeep(0);
+ }
+ else
+ {
+ MenuSelectItem(Mt.OwnerWnd, &MenuInfo, Pos, TRUE, 0);
+ ExecutedMenuId = MenuExecFocusedItem(&Mt, &MenuInfo, Flags);
+ fEndMenu = (-1 != ExecutedMenuId);
+ }
+ }
+ break;
+ } /* switch(msg.message) - kbd */
+ }
+ else
+ {
+ DispatchMessageW(&Msg);
+ }
+
+ if (! fEndMenu)
+ {
+ fRemove = TRUE;
+ }
+
+ /* finally remove message from the queue */
+
+ if (fRemove && 0 == (Mt.TrackFlags & TF_SKIPREMOVE))
+ {
+ PeekMessageW(&Msg, 0, Msg.message, Msg.message, PM_REMOVE);
+ }
+ else
+ {
+ Mt.TrackFlags &= ~TF_SKIPREMOVE;
+ }
+ }
+
+ NtUserSetGUIThreadHandle(MSQ_STATE_MENUOWNER, NULL);
+ SetCapture(NULL); /* release the capture */
+
+ /* If dropdown is still painted and the close box is clicked on
+ then the menu will be destroyed as part of the DispatchMessage above.
+ This will then invalidate the menu handle in Mt.hTopMenu. We should
+ check for this first. */
+ if (IsMenu(Mt.TopMenu))
+ {
+ if (IsWindow(Mt.OwnerWnd))
+ {
+ if (MenuGetRosMenuInfo(&MenuInfo, Mt.TopMenu))
+ {
+ MenuHideSubPopups(Mt.OwnerWnd, &MenuInfo, FALSE);
+
+ if (0 != (MenuInfo.Flags & MF_POPUP))
+ {
+ DestroyWindow(MenuInfo.Wnd);
+ MenuInfo.Wnd = NULL;
+ }
+ MenuSelectItem(Mt.OwnerWnd, &MenuInfo, NO_SELECTED_ITEM, FALSE, NULL);
+ }
+
+ SendMessageW(Mt.OwnerWnd, WM_MENUSELECT, MAKELONG(0, 0xffff), 0);
+ }
+
+ if (MenuGetRosMenuInfo(&MenuInfo, Mt.TopMenu))
+ {
+ /* Reset the variable for hiding menu */
+ MenuInfo.TimeToHide = FALSE;
+ MenuSetRosMenuInfo(&MenuInfo);
+ }
+ }
+
+ /* The return value is only used by TrackPopupMenu */
+ return (-1 != ExecutedMenuId) ? ExecutedMenuId : 0;
+}
+
+/***********************************************************************
+ * MenuExitTracking
+ */
+static BOOL FASTCALL
+MenuExitTracking(HWND Wnd)
+{
+ DPRINT("hwnd=%p\n", Wnd);
+
+ SendMessageW(Wnd, WM_EXITMENULOOP, 0, 0);
+ ShowCaret(0);
+ return TRUE;
}
+
VOID
-MenuTrackMouseMenuBar(HWND hWnd, ULONG Ht, POINT Pt)
+MenuTrackMouseMenuBar(HWND Wnd, ULONG Ht, POINT Pt)
{
+ HMENU Menu = (HTSYSMENU == Ht) ? NtUserGetSystemMenu(Wnd, FALSE) : GetMenu(Wnd);
+ UINT Flags = TPM_ENTERIDLEEX | TPM_BUTTONDOWN | TPM_LEFTALIGN | TPM_LEFTBUTTON;
+
+ DPRINT("wnd=%p ht=0x%04x (%ld,%ld)\n", Wnd, Ht, Pt.x, Pt.y);
+
+ if (IsMenu(Menu))
+ {
+ /* map point to parent client coordinates */
+ HWND Parent = GetAncestor(Wnd, GA_PARENT );
+ if (Parent != GetDesktopWindow())
+ {
+ ScreenToClient(Parent, &Pt);
+ }
+
+ MenuInitTracking(Wnd, Menu, FALSE, Flags);
+ MenuTrackMenu(Menu, Flags, Pt.x, Pt.y, Wnd, NULL);
+ MenuExitTracking(Wnd);
+ }
}
+
VOID
MenuTrackKbdMenuBar(HWND hWnd, ULONG wParam, ULONG Key)
{
}
+
+/* FUNCTIONS *****************************************************************/
+
+/*static BOOL
+MenuIsStringItem(ULONG TypeData)
+{
+ return(MF_STRING == MENU_ITEM_TYPE(ItemInfo->fType));
+}*/
+
+
+/*
+ * @implemented
+ */
+BOOL STDCALL
+AppendMenuA(HMENU hMenu,
+ UINT uFlags,
+ UINT_PTR uIDNewItem,
+ LPCSTR lpNewItem)
+{
+ return(InsertMenuA(hMenu, -1, uFlags | MF_BYPOSITION, uIDNewItem,
+ lpNewItem));
+}
+
+
+/*
+ * @implemented
+ */
+BOOL STDCALL
+AppendMenuW(HMENU hMenu,
+ UINT uFlags,
+ UINT_PTR uIDNewItem,
+ LPCWSTR lpNewItem)
+{
+ return(InsertMenuW(hMenu, -1, uFlags | MF_BYPOSITION, uIDNewItem,
+ lpNewItem));
+}
+
+
+/*
+ * @implemented
+ */
+DWORD STDCALL
+CheckMenuItem(HMENU hmenu,
+ UINT uIDCheckItem,
+ UINT uCheck)
+{
+ return NtUserCheckMenuItem(hmenu, uIDCheckItem, uCheck);
+}
+
+
+/*
+ * @implemented
+ */
+BOOL STDCALL
+CheckMenuRadioItem(HMENU hmenu,
+ UINT idFirst,
+ UINT idLast,
+ UINT idCheck,
+ UINT uFlags)
+{
+ ROSMENUINFO mi;
+ PROSMENUITEMINFO Items;
+ int i;
+ BOOL ret = FALSE;
+
+ mi.cbSize = sizeof(MENUINFO);
+
+ UNIMPLEMENTED;
+
+ if(idFirst > idLast) return ret;
+
+ if(!NtUserMenuInfo(hmenu, &mi, FALSE)) return ret;
+
+ if(MenuGetAllRosMenuItemInfo(mi.Self, &Items) <= 0) return ret;
+
+ for (i = 0 ; i < mi.MenuItemCount; i++)
+ {
+ if (0 != (Items[i].fType & MF_MENUBARBREAK)) break;
+ if ( i >= idFirst && i <= idLast )
+ {
+ if ( i == idCheck)
+ {
+ Items[i].fType |= MFT_RADIOCHECK;
+ Items[i].fState |= MFS_CHECKED;
+ }
+ else
+ {
+ Items[i].fType &= ~MFT_RADIOCHECK;
+ Items[i].fState &= ~MFS_CHECKED;
+ }
+ if(!MenuSetRosMenuItemInfo(mi.Self, i ,&Items[i]))
+ break;
+ }
+ if ( i == mi.MenuItemCount) ret = TRUE;
+ }
+ MenuCleanupRosMenuItemInfo(Items);
+ return ret;
+}
+
+
+/*
+ * @implemented
+ */
+HMENU STDCALL
+CreateMenu(VOID)
+{
+ MenuLoadBitmaps();
+ return NtUserCreateMenu(FALSE);
+}
+
+
+/*
+ * @implemented
+ */
+HMENU STDCALL
+CreatePopupMenu(VOID)
+{
+ MenuLoadBitmaps();
+ return NtUserCreateMenu(TRUE);
+}
+
+
+/*
+ * @implemented
+ */
+BOOL STDCALL
+DeleteMenu(HMENU hMenu,
+ UINT uPosition,
+ UINT uFlags)
+{
+ return NtUserDeleteMenu(hMenu, uPosition, uFlags);
+}
+
+
+/*
+ * @implemented
+ */
+BOOL STDCALL
+DestroyMenu(HMENU hMenu)
+{
+ return NtUserDestroyMenu(hMenu);
+}
+
+
+/*
+ * @implemented
+ */
+BOOL STDCALL
+DrawMenuBar(HWND hWnd)
+{
+ return (BOOL)NtUserCallHwndLock(hWnd, HWNDLOCK_ROUTINE_DRAWMENUBAR);
+}
+
+
+/*
+ * @implemented
+ */
+BOOL STDCALL
+EnableMenuItem(HMENU hMenu,
+ UINT uIDEnableItem,
+ UINT uEnable)
+{
+ return NtUserEnableMenuItem(hMenu, uIDEnableItem, uEnable);
+}
+
+/*
+ * @implemented
+ */
+BOOL STDCALL
+EndMenu(VOID)
+{
+ GUITHREADINFO guii;
+ guii.cbSize = sizeof(GUITHREADINFO);
+ if(GetGUIThreadInfo(GetCurrentThreadId(), &guii) && guii.hwndMenuOwner)
+ {
+ PostMessageW(guii.hwndMenuOwner, WM_CANCELMODE, 0, 0);
+ }
+ return TRUE;
+}
+
+
+/*
+ * @implemented
+ */
+HMENU STDCALL
+GetMenu(HWND hWnd)
+{
+ return NtUserGetMenu(hWnd);
+}
+
+
+/*
+ * @implemented
+ */
+BOOL STDCALL
+GetMenuBarInfo(HWND hwnd,
+ LONG idObject,
+ LONG idItem,
+ PMENUBARINFO pmbi)
+{
+ return (BOOL)NtUserGetMenuBarInfo(hwnd, idObject, idItem, pmbi);
+}
+
+
+/*
+ * @implemented
+ */
+LONG STDCALL
+GetMenuCheckMarkDimensions(VOID)
+{
+ return(MAKELONG(GetSystemMetrics(SM_CXMENUCHECK),
+ GetSystemMetrics(SM_CYMENUCHECK)));
+}
+
+
+/*
+ * @implemented
+ */
+UINT STDCALL
+GetMenuDefaultItem(HMENU hMenu,
+ UINT fByPos,
+ UINT gmdiFlags)
+{
+ return NtUserGetMenuDefaultItem(hMenu, fByPos, gmdiFlags);
+}
+
+
+/*
+ * @implemented
+ */
+BOOL STDCALL
+GetMenuInfo(HMENU hmenu,
+ LPMENUINFO lpcmi)
+{
+ ROSMENUINFO mi;
+ BOOL res = FALSE;
+
+ if(!lpcmi || (lpcmi->cbSize != sizeof(MENUINFO)))
+ return FALSE;
+
+ RtlZeroMemory(&mi, sizeof(MENUINFO));
+ mi.cbSize = sizeof(MENUINFO);
+ mi.fMask = lpcmi->fMask;
+
+ res = NtUserMenuInfo(hmenu, &mi, FALSE);
+
+ memcpy(lpcmi, &mi, sizeof(MENUINFO));
+ return res;
+}
+
+
+/*
+ * @implemented
+ */
+int STDCALL
+GetMenuItemCount(HMENU Menu)
+{
+ ROSMENUINFO MenuInfo;
+
+ return MenuGetRosMenuInfo(&MenuInfo, Menu) ? MenuInfo.MenuItemCount : 0;
+}
+
+
+/*
+ * @implemented
+ */
+UINT STDCALL
+GetMenuItemID(HMENU hMenu,
+ int nPos)
+{
+ ROSMENUITEMINFO mii;
+
+ mii.cbSize = sizeof(MENUITEMINFOW);
+ mii.fMask = MIIM_ID | MIIM_SUBMENU;
+
+ if (! NtUserMenuItemInfo(hMenu, nPos, MF_BYPOSITION, &mii, FALSE))
+ {
+ return -1;
+ }
+
+ if (NULL != mii.hSubMenu)
+ {
+ return -1;
+ }
+ if (0 == mii.wID)
+ {
+ return -1;
+ }
+
+ return mii.wID;
+}
+
+
+/*
+ * @implemented
+ */
+BOOL STDCALL
+GetMenuItemInfoA(
+ HMENU Menu,
+ UINT Item,
+ BOOL ByPosition,
+ LPMENUITEMINFOA mii)
+{
+ LPSTR AnsiBuffer;
+ MENUITEMINFOW miiW;
+
+ if (mii->cbSize != sizeof(MENUITEMINFOA) &&
+ mii->cbSize != sizeof(MENUITEMINFOA) - sizeof(HBITMAP))
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+
+ if ((mii->fMask & (MIIM_STRING | MIIM_TYPE)) == 0)
+ {
+ /* No text requested, just pass on */
+ return NtUserMenuItemInfo(Menu, Item, ByPosition, (PROSMENUITEMINFO) mii, FALSE);
+ }
+
+ RtlCopyMemory(&miiW, mii, mii->cbSize);
+ AnsiBuffer = mii->dwTypeData;
+
+ if (AnsiBuffer != NULL)
+ {
+ miiW.dwTypeData = RtlAllocateHeap(GetProcessHeap(), 0,
+ miiW.cch * sizeof(WCHAR));
+ if (miiW.dwTypeData == NULL)
+ return FALSE;
+ }
+
+ if (!NtUserMenuItemInfo(Menu, Item, ByPosition, (PROSMENUITEMINFO)&miiW, FALSE))
+ {
+ HeapFree(GetProcessHeap(), 0, miiW.dwTypeData);
+ return FALSE;
+ }
+
+ if (AnsiBuffer != NULL)
+ {
+ if (IS_STRING_ITEM(miiW.fType))
+ {
+ WideCharToMultiByte(CP_ACP, 0, miiW.dwTypeData, miiW.cch, AnsiBuffer,
+ mii->cch, NULL, NULL);
+ }
+ RtlFreeHeap(GetProcessHeap(), 0, miiW.dwTypeData);
+ }
+
+ RtlCopyMemory(mii, &miiW, miiW.cbSize);
+ if (AnsiBuffer)
+ {
+ mii->dwTypeData = AnsiBuffer;
+ mii->cch = strlen(AnsiBuffer);
+ }
+ return TRUE;
+}
+
+
+/*
+ * @implemented
+ */
+BOOL STDCALL
+GetMenuItemInfoW(
+ HMENU Menu,
+ UINT Item,
+ BOOL ByPosition,
+ LPMENUITEMINFOW mii)
+{
+ return NtUserMenuItemInfo(Menu, Item, ByPosition, (PROSMENUITEMINFO) mii, FALSE);
+}
+
+
+/*
+ * @implemented
+ */
+BOOL STDCALL
+GetMenuItemRect(HWND hWnd,
+ HMENU hMenu,
+ UINT uItem,
+ LPRECT lprcItem)
+{
+ return NtUserGetMenuItemRect( hWnd, hMenu, uItem, lprcItem);
+}
+
+
+/*
+ * @implemented
+ */
+UINT
+STDCALL
+GetMenuState(
+ HMENU hMenu,
+ UINT uId,
+ UINT uFlags)
+{
+ ROSMENUINFO MenuInfo;
+ ROSMENUITEMINFO mii;
+
+ mii.cbSize = sizeof(MENUITEMINFOW);
+ mii.fMask = MIIM_STATE | MIIM_TYPE | MIIM_SUBMENU;
+ mii.dwTypeData = NULL;
+
+ SetLastError(0);
+ if(NtUserMenuItemInfo(hMenu, uId, uFlags, &mii, FALSE))
+ {
+ UINT nSubItems = 0;
+ if(mii.hSubMenu)
+ {
+ if (! MenuGetRosMenuInfo(&MenuInfo, mii.hSubMenu))
+ {
+ return (UINT) -1;
+ }
+ nSubItems = MenuInfo.MenuItemCount;
+
+ /* FIXME - ported from wine, does that work (0xff)? */
+ if(GetLastError() != ERROR_INVALID_MENU_HANDLE)
+ return (nSubItems << 8) | ((mii.fState | mii.fType) & 0xff);
+
+ return (UINT)-1; /* Invalid submenu */
+ }
+
+ /* FIXME - ported from wine, does that work? */
+ return (mii.fType | mii.fState);
+ }
+
+ return (UINT)-1;
+}
+
+
+/*
+ * @implemented
+ */
+int
+STDCALL
+GetMenuStringA(
+ HMENU hMenu,
+ UINT uIDItem,
+ LPSTR lpString,
+ int nMaxCount,
+ UINT uFlag)
+{
+ MENUITEMINFOA mii;
+ mii.dwTypeData = lpString;
+ mii.fMask = MIIM_STRING;
+ mii.fType = MF_STRING;
+ mii.cbSize = sizeof(MENUITEMINFOA);
+ mii.cch = nMaxCount;
+
+ if(!(GetMenuItemInfoA( hMenu, uIDItem, (BOOL)(MF_BYPOSITION & uFlag),&mii)))
+ return 0;
+ else
+ return mii.cch;
+}
+
+
+/*
+ * @implemented
+ */
+int
+STDCALL
+GetMenuStringW(
+ HMENU hMenu,
+ UINT uIDItem,
+ LPWSTR lpString,
+ int nMaxCount,
+ UINT uFlag)
+{
+ MENUITEMINFOW miiW;
+ miiW.dwTypeData = lpString;
+ miiW.fMask = MIIM_STRING;
+ miiW.cbSize = sizeof(MENUITEMINFOW);
+ miiW.cch = nMaxCount;
+
+ if(!(GetMenuItemInfoW( hMenu, uIDItem, (BOOL)(MF_BYPOSITION & uFlag),&miiW)))
+ return 0;
+ else
+ return miiW.cch;
+}
+
+
+/*
+ * @implemented
+ */
+HMENU
+STDCALL
+GetSubMenu(
+ HMENU hMenu,
+ int nPos)
+{
+ ROSMENUITEMINFO mi;
+
+ mi.cbSize = sizeof(MENUITEMINFOW);
+ mi.fMask = MIIM_SUBMENU;
+
+ if (NtUserMenuItemInfo(hMenu, (UINT)nPos, MF_BYPOSITION, &mi, FALSE))
+ {
+ return IsMenu(mi.hSubMenu) ? mi.hSubMenu : NULL;
+ }
+
+ return NULL;
+}
+
+/*
+ * @implemented
+ */
+HMENU
+STDCALL
+GetSystemMenu(
+ HWND hWnd,
+ BOOL bRevert)
+{
+ HMENU TopMenu;
+
+ TopMenu = NtUserGetSystemMenu(hWnd, bRevert);
+
+ return NULL == TopMenu ? NULL : GetSubMenu(TopMenu, 0);
+}
+
+
+/*
+ * @implemented
+ */
+BOOL
+STDCALL
+HiliteMenuItem(
+ HWND hwnd,
+ HMENU hmenu,
+ UINT uItemHilite,
+ UINT uHilite)
+{
+ return NtUserHiliteMenuItem(hwnd, hmenu, uItemHilite, uHilite);
+}
+
+
+/*
+ * @implemented
+ */
+BOOL
+STDCALL
+InsertMenuA(
+ HMENU hMenu,
+ UINT uPosition,
+ UINT uFlags,
+ UINT_PTR uIDNewItem,
+ LPCSTR lpNewItem)
+{
+ MENUITEMINFOA mii;
+ mii.cbSize = sizeof(MENUITEMINFOA);
+ mii.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_STATE;
+ mii.fType = 0;
+ mii.fState = MFS_ENABLED;
+
+ if(uFlags & MF_BITMAP)
+ {
+ mii.fType |= MFT_BITMAP;
+ mii.fMask |= MIIM_BITMAP;
+ mii.hbmpItem = (HBITMAP) lpNewItem;
+ }
+ else if(uFlags & MF_OWNERDRAW)
+ {
+ mii.fType |= MFT_OWNERDRAW;
+ mii.fMask |= MIIM_DATA;
+ mii.dwItemData = (DWORD) lpNewItem;
+ }
+ else
+ {
+ mii.fMask |= MIIM_TYPE;
+ mii.dwTypeData = (LPSTR)lpNewItem;
+ mii.cch = (NULL == lpNewItem ? 0 : strlen(lpNewItem));
+ }
+
+ if(uFlags & MF_RIGHTJUSTIFY)
+ {
+ mii.fType |= MFT_RIGHTJUSTIFY;
+ }
+ if(uFlags & MF_MENUBREAK)
+ {
+ mii.fType |= MFT_MENUBREAK;
+ }
+ if(uFlags & MF_MENUBARBREAK)
+ {
+ mii.fType |= MFT_MENUBARBREAK;
+ }
+ if(uFlags & MF_DISABLED)
+ {
+ mii.fState |= MFS_DISABLED;
+ }
+ if(uFlags & MF_GRAYED)
+ {
+ mii.fState |= MFS_GRAYED;
+ }
+
+ if(uFlags & MF_POPUP)
+ {
+ mii.fType |= MF_POPUP;
+ mii.fMask |= MIIM_SUBMENU;
+ mii.hSubMenu = (HMENU)uIDNewItem;
+ }
+ else
+ {
+ mii.fMask |= MIIM_ID;
+ mii.wID = (UINT)uIDNewItem;
+ }
+ return InsertMenuItemA(hMenu, uPosition, (BOOL)((MF_BYPOSITION & uFlags) > 0), &mii);
+}
+
+
+/*
+ * @implemented
+ */
+BOOL
+STDCALL
+InsertMenuItemA(
+ HMENU hMenu,
+ UINT uItem,
+ BOOL fByPosition,
+ LPCMENUITEMINFOA lpmii)
+{
+ MENUITEMINFOW mi;
+ UNICODE_STRING MenuText;
+ BOOL res = FALSE;
+ BOOL CleanHeap = FALSE;
+ NTSTATUS Status;
+
+ if((lpmii->cbSize == sizeof(MENUITEMINFOA)) ||
+ (lpmii->cbSize == sizeof(MENUITEMINFOA) - sizeof(HBITMAP)))
+ {
+ RtlMoveMemory ( &mi, lpmii, lpmii->cbSize );
+
+ /* copy the text string */
+ if((mi.fMask & (MIIM_TYPE | MIIM_STRING)) &&
+ (MENU_ITEM_TYPE(mi.fType) == MF_STRING) && mi.dwTypeData)
+ {
+ Status = RtlCreateUnicodeStringFromAsciiz(&MenuText, (LPSTR)mi.dwTypeData);
+ if (!NT_SUCCESS (Status))
+ {
+ SetLastError (RtlNtStatusToDosError(Status));
+ return FALSE;
+ }
+ mi.dwTypeData = MenuText.Buffer;
+ mi.cch = MenuText.Length / sizeof(WCHAR);
+ CleanHeap = TRUE;
+ }
+
+ res = NtUserInsertMenuItem(hMenu, uItem, fByPosition, &mi);
+
+ if ( CleanHeap ) RtlFreeUnicodeString ( &MenuText );
+ }
+ return res;
+}
+
+
+/*
+ * @implemented
+ */
+BOOL
+STDCALL
+InsertMenuItemW(
+ HMENU hMenu,
+ UINT uItem,
+ BOOL fByPosition,
+ LPCMENUITEMINFOW lpmii)
+{
+ MENUITEMINFOW mi;
+ UNICODE_STRING MenuText;
+ BOOL res = FALSE;
+ mi.hbmpItem = (HBITMAP)0;
+
+ /* while we could just pass 'lpmii' to win32k, we make a copy so that
+ if a bad user passes bad data, we crash his process instead of the
+ entire kernel */
+
+ if((lpmii->cbSize == sizeof(MENUITEMINFOW)) ||
+ (lpmii->cbSize == sizeof(MENUITEMINFOW) - sizeof(HBITMAP)))
+ {
+ memcpy(&mi, lpmii, lpmii->cbSize);
+
+ /* copy the text string */
+ if((mi.fMask & (MIIM_TYPE | MIIM_STRING)) &&
+ (MENU_ITEM_TYPE(mi.fType) == MF_STRING) &&
+ mi.dwTypeData != NULL)
+ {
+ RtlInitUnicodeString(&MenuText, (PWSTR)lpmii->dwTypeData);
+ mi.dwTypeData = MenuText.Buffer;
+ mi.cch = MenuText.Length / sizeof(WCHAR);
+ };
+
+ res = NtUserInsertMenuItem(hMenu, uItem, fByPosition, &mi);
+ }
+ return res;
+}
+
+
+/*
+ * @implemented
+ */
+BOOL
+STDCALL
+InsertMenuW(
+ HMENU hMenu,
+ UINT uPosition,
+ UINT uFlags,
+ UINT_PTR uIDNewItem,
+ LPCWSTR lpNewItem)
+{
+ MENUITEMINFOW mii;
+ mii.cbSize = sizeof(MENUITEMINFOW);
+ mii.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_STATE;
+ mii.fType = 0;
+ mii.fState = MFS_ENABLED;
+
+ if(uFlags & MF_BITMAP)
+ {
+ mii.fType |= MFT_BITMAP;
+ mii.fMask |= MIIM_BITMAP;
+ mii.hbmpItem = (HBITMAP) lpNewItem;
+ }
+ else if(uFlags & MF_OWNERDRAW)
+ {
+ mii.fType |= MFT_OWNERDRAW;
+ mii.fMask |= MIIM_DATA;
+ mii.dwItemData = (DWORD) lpNewItem;
+ }
+ else
+ {
+ mii.fMask |= MIIM_TYPE;
+ mii.dwTypeData = (LPWSTR)lpNewItem;
+ mii.cch = (NULL == lpNewItem ? 0 : wcslen(lpNewItem));
+ }
+
+ if(uFlags & MF_RIGHTJUSTIFY)
+ {
+ mii.fType |= MFT_RIGHTJUSTIFY;
+ }
+ if(uFlags & MF_MENUBREAK)
+ {
+ mii.fType |= MFT_MENUBREAK;
+ }
+ if(uFlags & MF_MENUBARBREAK)
+ {
+ mii.fType |= MFT_MENUBARBREAK;
+ }
+ if(uFlags & MF_DISABLED)
+ {
+ mii.fState |= MFS_DISABLED;
+ }
+ if(uFlags & MF_GRAYED)
+ {
+ mii.fState |= MFS_GRAYED;
+ }
+
+ if(uFlags & MF_POPUP)
+ {
+ mii.fType |= MF_POPUP;
+ mii.fMask |= MIIM_SUBMENU;
+ mii.hSubMenu = (HMENU)uIDNewItem;
+ }
+ else
+ {
+ mii.fMask |= MIIM_ID;
+ mii.wID = (UINT)uIDNewItem;
+ }
+ return InsertMenuItemW(hMenu, uPosition, (BOOL)((MF_BYPOSITION & uFlags) > 0), &mii);
+}
+
+
+/*
+ * @implemented
+ */
+BOOL
+STDCALL
+IsMenu(
+ HMENU Menu)
+{
+ ROSMENUINFO MenuInfo;
+
+ return MenuGetRosMenuInfo(&MenuInfo, Menu);
+}
+
+
+/*
+ * @implemented
+ */
+HMENU STDCALL
+LoadMenuA(HINSTANCE hInstance,
+ LPCSTR lpMenuName)
+{
+ HANDLE Resource = FindResourceA(hInstance, lpMenuName, MAKEINTRESOURCEA(4));
+ if (Resource == NULL)
+ {
+ return(NULL);
+ }
+ return(LoadMenuIndirectA((PVOID)LoadResource(hInstance, Resource)));
+}
+
+
+/*
+ * @implemented
+ */
+HMENU STDCALL
+LoadMenuIndirectA(CONST MENUTEMPLATE *lpMenuTemplate)
+{
+ return(LoadMenuIndirectW(lpMenuTemplate));
+}
+
+
+/*
+ * @implemented
+ */
+HMENU STDCALL
+LoadMenuIndirectW(CONST MENUTEMPLATE *lpMenuTemplate)
+{
+ HMENU hMenu;
+ WORD version, offset;
+ LPCSTR p = (LPCSTR)lpMenuTemplate;
+
+ version = GET_WORD(p);
+ p += sizeof(WORD);
+
+ switch (version)
+ {
+ case 0: /* standard format is version of 0 */
+ offset = GET_WORD(p);
+ p += sizeof(WORD) + offset;
+ if (!(hMenu = CreateMenu())) return 0;
+ if (!MENU_ParseResource(p, hMenu, TRUE))
+ {
+ DestroyMenu(hMenu);
+ return 0;
+ }
+ return hMenu;
+ case 1: /* extended format is version of 1 */
+ offset = GET_WORD(p);
+ p += sizeof(WORD) + offset;
+ if (!(hMenu = CreateMenu())) return 0;
+ if (!MENUEX_ParseResource(p, hMenu))
+ {
+ DestroyMenu( hMenu );
+ return 0;
+ }
+ return hMenu;
+ default:
+ DbgPrint("LoadMenuIndirectW(): version %d not supported.\n", version);
+ return 0;
+ }
+}
+
+
+/*
+ * @implemented
+ */
+HMENU STDCALL
+LoadMenuW(HINSTANCE hInstance,
+ LPCWSTR lpMenuName)
+{
+ HANDLE Resource = FindResourceW(hInstance, lpMenuName, RT_MENU);
+ if (Resource == NULL)
+ {
+ return(NULL);
+ }
+ return(LoadMenuIndirectW((PVOID)LoadResource(hInstance, Resource)));
+}
+
+
+/*
+ * @implemented
+ */
+int
+STDCALL
+MenuItemFromPoint(
+ HWND hWnd,
+ HMENU hMenu,
+ POINT ptScreen)
+{
+ return NtUserMenuItemFromPoint(hWnd, hMenu, ptScreen.x, ptScreen.y);
+}
+
+
+/*
+ * @implemented
+ */
+BOOL
+STDCALL
+ModifyMenuA(
+ HMENU hMnu,
+ UINT uPosition,
+ UINT uFlags,
+ UINT_PTR uIDNewItem,
+ LPCSTR lpNewItem)
+{
+ MENUITEMINFOA mii;
+ memset( &mii, 0, sizeof(mii) );
+ mii.cbSize = sizeof(MENUITEMINFOA);
+ mii.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_STATE;
+ mii.fType = 0;
+ mii.fState = MFS_ENABLED;
+
+ UNIMPLEMENTED;
+
+ if(!GetMenuItemInfoA( hMnu,
+ uPosition,
+ (BOOL)(MF_BYPOSITION & uFlags),
+ &mii)) return FALSE;
+
+ if(uFlags & MF_BITMAP)
+ {
+ mii.fType |= MFT_BITMAP;
+ mii.fMask |= MIIM_BITMAP;
+ mii.hbmpItem = (HBITMAP) lpNewItem;
+ }
+ else if(uFlags & MF_OWNERDRAW)
+ {
+ mii.fType |= MFT_OWNERDRAW;
+ mii.fMask |= MIIM_DATA;
+ mii.dwItemData = (DWORD) lpNewItem;
+ }
+ else /* Default action MF_STRING. */
+ {
+ if(mii.dwTypeData != NULL)
+ {
+ HeapFree(GetProcessHeap(),0, mii.dwTypeData);
+ }
+ /* Item beginning with a backspace is a help item */
+ if (*lpNewItem == '\b')
+ {
+ mii.fType |= MF_HELP;
+ lpNewItem++;
+ }
+ mii.fMask |= MIIM_TYPE;
+ mii.dwTypeData = (LPSTR)lpNewItem;
+ mii.cch = (NULL == lpNewItem ? 0 : strlen(lpNewItem));
+ }
+
+ if(uFlags & MF_RIGHTJUSTIFY)
+ {
+ mii.fType |= MFT_RIGHTJUSTIFY;
+ }
+ if(uFlags & MF_MENUBREAK)
+ {
+ mii.fType |= MFT_MENUBREAK;
+ }
+ if(uFlags & MF_MENUBARBREAK)
+ {
+ mii.fType |= MFT_MENUBARBREAK;
+ }
+ if(uFlags & MF_DISABLED)
+ {
+ mii.fState |= MFS_DISABLED;
+ }
+ if(uFlags & MF_GRAYED)
+ {
+ mii.fState |= MFS_GRAYED;
+ }
+
+ if ((mii.fType & MF_POPUP) && (uFlags & MF_POPUP) && (mii.hSubMenu != (HMENU)uIDNewItem))
+ NtUserDestroyMenu( mii.hSubMenu ); /* ModifyMenu() spec */
+
+ if(uFlags & MF_POPUP)
+ {
+ mii.fType |= MF_POPUP;
+ mii.fMask |= MIIM_SUBMENU;
+ mii.hSubMenu = (HMENU)uIDNewItem;
+ }
+ else
+ {
+ mii.fMask |= MIIM_ID;
+ mii.wID = (UINT)uIDNewItem;
+ }
+
+ return SetMenuItemInfoA( hMnu,
+ uPosition,
+ (BOOL)(MF_BYPOSITION & uFlags),
+ &mii);
+}
+
+
+/*
+ * @implemented
+ */
+BOOL
+STDCALL
+ModifyMenuW(
+ HMENU hMnu,
+ UINT uPosition,
+ UINT uFlags,
+ UINT_PTR uIDNewItem,
+ LPCWSTR lpNewItem)
+{
+ MENUITEMINFOW mii;
+ memset ( &mii, 0, sizeof(mii) );
+ mii.cbSize = sizeof(MENUITEMINFOW);
+ mii.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_STATE;
+ mii.fState = MFS_ENABLED;
+
+ UNIMPLEMENTED;
+
+ if(!NtUserMenuItemInfo( hMnu,
+ uPosition,
+ (BOOL)(MF_BYPOSITION & uFlags),
+ (PROSMENUITEMINFO) &mii,
+ FALSE)) return FALSE;
+
+ if(uFlags & MF_BITMAP)
+ {
+ mii.fType |= MFT_BITMAP;
+ mii.fMask |= MIIM_BITMAP;
+ mii.hbmpItem = (HBITMAP) lpNewItem;
+ }
+ else if(uFlags & MF_OWNERDRAW)
+ {
+ mii.fType |= MFT_OWNERDRAW;
+ mii.fMask |= MIIM_DATA;
+ mii.dwItemData = (DWORD) lpNewItem;
+ }
+ else
+ {
+ /*if(mii.dwTypeData != NULL)
+ {
+ HeapFree(GetProcessHeap(),0, mii.dwTypeData);
+ }*/
+ if (*lpNewItem == '\b')
+ {
+ mii.fType |= MF_HELP;
+ lpNewItem++;
+ }
+ mii.fMask |= MIIM_TYPE;
+ mii.dwTypeData = (LPWSTR)lpNewItem;
+ mii.cch = (NULL == lpNewItem ? 0 : wcslen(lpNewItem));
+ }
+
+ if(uFlags & MF_RIGHTJUSTIFY)
+ {
+ mii.fType |= MFT_RIGHTJUSTIFY;
+ }
+ if(uFlags & MF_MENUBREAK)
+ {
+ mii.fType |= MFT_MENUBREAK;
+ }
+ if(uFlags & MF_MENUBARBREAK)
+ {
+ mii.fType |= MFT_MENUBARBREAK;
+ }
+ if(uFlags & MF_DISABLED)
+ {
+ mii.fState |= MFS_DISABLED;
+ }
+ if(uFlags & MF_GRAYED)
+ {
+ mii.fState |= MFS_GRAYED;
+ }
+
+ if ((mii.fType & MF_POPUP) && (uFlags & MF_POPUP) && (mii.hSubMenu != (HMENU)uIDNewItem))
+ NtUserDestroyMenu( mii.hSubMenu );
+
+ if(uFlags & MF_POPUP)
+ {
+ mii.fType |= MF_POPUP;
+ mii.fMask |= MIIM_SUBMENU;
+ mii.hSubMenu = (HMENU)uIDNewItem;
+ }
+ else
+ {
+ mii.fMask |= MIIM_ID;
+ mii.wID = (UINT)uIDNewItem;
+ }
+
+ return SetMenuItemInfoW( hMnu,
+ uPosition,
+ (BOOL)(MF_BYPOSITION & uFlags),
+ &mii);
+}
+
+
+/*
+ * @implemented
+ */
+BOOL
+STDCALL
+RemoveMenu(
+ HMENU hMenu,
+ UINT uPosition,
+ UINT uFlags)
+{
+ return NtUserRemoveMenu(hMenu, uPosition, uFlags);
+}
+
+
+/*
+ * @implemented
+ */
+BOOL STDCALL
+SetMenu(HWND hWnd,
+ HMENU hMenu)
+{
+ return NtUserSetMenu(hWnd, hMenu, TRUE);
+}
+
+
+/*
+ * @implemented
+ */
+BOOL
+STDCALL
+SetMenuDefaultItem(
+ HMENU hMenu,
+ UINT uItem,
+ UINT fByPos)
+{
+ return NtUserSetMenuDefaultItem(hMenu, uItem, fByPos);
+}
+
+
+/*
+ * @implemented
+ */
+BOOL
+STDCALL
+SetMenuInfo(
+ HMENU hmenu,
+ LPCMENUINFO lpcmi)
+{
+ ROSMENUINFO mi;
+ BOOL res = FALSE;
+ if(lpcmi->cbSize != sizeof(MENUINFO))
+ return res;
+
+ memcpy(&mi, lpcmi, sizeof(MENUINFO));
+ return NtUserMenuInfo(hmenu, &mi, TRUE);
+}
+
+
+/*
+ * @implemented
+ */
+BOOL
+STDCALL
+SetMenuItemBitmaps(
+ HMENU hMenu,
+ UINT uPosition,
+ UINT uFlags,
+ HBITMAP hBitmapUnchecked,
+ HBITMAP hBitmapChecked)
+{
+ ROSMENUITEMINFO uItem;
+
+ if(!(NtUserMenuItemInfo(hMenu, uPosition,
+ (BOOL)(MF_BYPOSITION & uFlags), &uItem, FALSE))) return FALSE;
+
+ if (!hBitmapChecked && !hBitmapUnchecked)
+ {
+ uItem.fState &= ~MF_USECHECKBITMAPS;
+ }
+ else /* Install new bitmaps */
+ {
+ uItem.hbmpChecked = hBitmapChecked;
+ uItem.hbmpUnchecked = hBitmapUnchecked;
+ uItem.fState |= MF_USECHECKBITMAPS;
+ }
+ return NtUserMenuItemInfo(hMenu, uPosition,
+ (BOOL)(MF_BYPOSITION & uFlags), &uItem, TRUE);
+}
+
+
+/*
+ * @implemented
+ */
+BOOL
+STDCALL
+SetMenuItemInfoA(
+ HMENU hMenu,
+ UINT uItem,
+ BOOL fByPosition,
+ LPCMENUITEMINFOA lpmii)
+{
+ MENUITEMINFOW MenuItemInfoW;
+ UNICODE_STRING UnicodeString;
+ ULONG Result;
+
+ RtlCopyMemory(&MenuItemInfoW, lpmii, min(lpmii->cbSize, sizeof(MENUITEMINFOW)));
+
+ if ((MenuItemInfoW.fMask & (MIIM_TYPE | MIIM_STRING)) &&
+ (MENU_ITEM_TYPE(MenuItemInfoW.fType) == MF_STRING) &&
+ MenuItemInfoW.dwTypeData != NULL)
+ {
+ RtlCreateUnicodeStringFromAsciiz(&UnicodeString,
+ (LPSTR)MenuItemInfoW.dwTypeData);
+ MenuItemInfoW.dwTypeData = UnicodeString.Buffer;
+ MenuItemInfoW.cch = UnicodeString.Length / sizeof(WCHAR);
+ }
+ else
+ {
+ UnicodeString.Buffer = NULL;
+ }
+
+ Result = NtUserMenuItemInfo(hMenu, uItem, fByPosition,
+ (PROSMENUITEMINFO)&MenuItemInfoW, TRUE);
+
+ if (UnicodeString.Buffer != NULL)
+ {
+ RtlFreeUnicodeString(&UnicodeString);
+ }
+
+ return Result;
+}
+
+
+/*
+ * @implemented
+ */
+BOOL
+STDCALL
+SetMenuItemInfoW(
+ HMENU hMenu,
+ UINT uItem,
+ BOOL fByPosition,
+ LPCMENUITEMINFOW lpmii)
+{
+ MENUITEMINFOW MenuItemInfoW;
+
+ RtlCopyMemory(&MenuItemInfoW, lpmii, min(lpmii->cbSize, sizeof(MENUITEMINFOW)));
+ if (0 != (MenuItemInfoW.fMask & MIIM_STRING))
+ {
+ MenuItemInfoW.cch = wcslen(MenuItemInfoW.dwTypeData);
+ }
+
+ return NtUserMenuItemInfo(hMenu, uItem, fByPosition,
+ (PROSMENUITEMINFO)&MenuItemInfoW, TRUE);
+}
+
+/*
+ * @implemented
+ */
+BOOL
+STDCALL
+SetSystemMenu (
+ HWND hwnd,
+ HMENU hMenu)
+{
+ if(!hwnd)
+ {
+ SetLastError(ERROR_INVALID_WINDOW_HANDLE);
+ return FALSE;
+ }
+ if(!hMenu)
+ {
+ SetLastError(ERROR_INVALID_MENU_HANDLE);
+ return FALSE;
+ }
+ return NtUserSetSystemMenu(hwnd, hMenu);
+}
+
+
+/*
+ * @implemented
+ */
+BOOL
+STDCALL
+TrackPopupMenu(
+ HMENU Menu,
+ UINT Flags,
+ int x,
+ int y,
+ int Reserved,
+ HWND Wnd,
+ CONST RECT *Rect)
+{
+ BOOL ret = FALSE;
+
+ MenuInitTracking(Wnd, Menu, TRUE, Flags);
+
+ /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
+ if (0 == (Flags & TPM_NONOTIFY))
+ {
+ SendMessageW(Wnd, WM_INITMENUPOPUP, (WPARAM) Menu, 0);
+ }
+
+ if (MenuShowPopup(Wnd, Menu, 0, x, y, 0, 0 ))
+ {
+ ret = MenuTrackMenu(Menu, Flags | TPM_POPUPMENU, 0, 0, Wnd, Rect);
+ }
+ MenuExitTracking(Wnd);
+
+ return ret;
+}
+
+
+/*
+ * @unimplemented
+ */
+BOOL
+STDCALL
+TrackPopupMenuEx(
+ HMENU Menu,
+ UINT Flags,
+ int x,
+ int y,
+ HWND Wnd,
+ LPTPMPARAMS Tpm)
+{
+ /* Not fully implemented */
+ return TrackPopupMenu(Menu, Flags, x, y, 0, Wnd,
+ NULL != Tpm ? &Tpm->rcExclude : NULL);
+}
+
+
+/*
+ * @implemented
+ */
+BOOL
+STDCALL
+SetMenuContextHelpId(HMENU hmenu,
+ DWORD dwContextHelpId)
+{
+ return NtUserSetMenuContextHelpId(hmenu, dwContextHelpId);
+}
+
+
+/*
+ * @implemented
+ */
+DWORD
+STDCALL
+GetMenuContextHelpId(HMENU hmenu)
+{
+ ROSMENUINFO mi;
+ mi.cbSize = sizeof(ROSMENUINFO);
+ mi.fMask = MIM_HELPID;
+
+ if(NtUserMenuInfo(hmenu, &mi, FALSE))
+ {
+ return mi.dwContextHelpID;
+ }
+ return 0;
+}
+
+/*
+ * @unimplemented
+ */
+LRESULT
+STDCALL
+MenuWindowProcA(
+ HWND hWnd,
+ UINT Msg,
+ WPARAM wParam,
+ LPARAM lParam
+ )
+{
+ UNIMPLEMENTED;
+ return FALSE;
+}
+
+/*
+ * @unimplemented
+ */
+LRESULT
+STDCALL
+MenuWindowProcW(
+ HWND hWnd,
+ UINT Msg,
+ WPARAM wParam,
+ LPARAM lParam
+ )
+{
+ UNIMPLEMENTED;
+ return FALSE;
+}
+
+/*
+ * @implemented
+ */
+BOOL
+STDCALL
+ChangeMenuW(
+ HMENU hMenu,
+ UINT cmd,
+ LPCWSTR lpszNewItem,
+ UINT cmdInsert,
+ UINT flags)
+{
+ /*
+ FIXME: Word passes the item id in 'cmd' and 0 or 0xffff as cmdInsert
+ for MF_DELETE. We should check the parameters for all others
+ MF_* actions also (anybody got a doc on ChangeMenu?).
+ */
+
+ switch(flags & (MF_APPEND | MF_DELETE | MF_CHANGE | MF_REMOVE | MF_INSERT))
+ {
+ case MF_APPEND :
+ return AppendMenuW(hMenu, flags &~ MF_APPEND, cmdInsert, lpszNewItem);
+
+ case MF_DELETE :
+ return DeleteMenu(hMenu, cmd, flags &~ MF_DELETE);
+
+ case MF_CHANGE :
+ return ModifyMenuW(hMenu, cmd, flags &~ MF_CHANGE, cmdInsert, lpszNewItem);
+
+ case MF_REMOVE :
+ return RemoveMenu(hMenu, flags & MF_BYPOSITION ? cmd : cmdInsert,
+ flags &~ MF_REMOVE);
+
+ default : /* MF_INSERT */
+ return InsertMenuW(hMenu, cmd, flags, cmdInsert, lpszNewItem);
+ };
+}
+
+/*
+ * @implemented
+ */
+BOOL
+STDCALL
+ChangeMenuA(
+ HMENU hMenu,
+ UINT cmd,
+ LPCSTR lpszNewItem,
+ UINT cmdInsert,
+ UINT flags)
+{
+ /*
+ FIXME: Word passes the item id in 'cmd' and 0 or 0xffff as cmdInsert
+ for MF_DELETE. We should check the parameters for all others
+ MF_* actions also (anybody got a doc on ChangeMenu?).
+ */
+
+ switch(flags & (MF_APPEND | MF_DELETE | MF_CHANGE | MF_REMOVE | MF_INSERT))
+ {
+ case MF_APPEND :
+ return AppendMenuA(hMenu, flags &~ MF_APPEND, cmdInsert, lpszNewItem);
+
+ case MF_DELETE :
+ return DeleteMenu(hMenu, cmd, flags &~ MF_DELETE);
+
+ case MF_CHANGE :
+ return ModifyMenuA(hMenu, cmd, flags &~ MF_CHANGE, cmdInsert, lpszNewItem);
+
+ case MF_REMOVE :
+ return RemoveMenu(hMenu, flags & MF_BYPOSITION ? cmd : cmdInsert,
+ flags &~ MF_REMOVE);
+
+ default : /* MF_INSERT */
+ return InsertMenuA(hMenu, cmd, flags, cmdInsert, lpszNewItem);
+ };
+}