[PATCH 07/11] user: menu item client changes
Thomas Kho
tkho at ucla.edu
Thu Jun 29 15:34:20 CDT 2006
user: menu item client changes
Implement menu item abstraction functions and begin converting menu item
references to use these functions
Thomas Kho
---
dlls/user/menu.c | 243 +++++++++++++++++++++++++++++++++++++++++++++++-------
1 files changed, 212 insertions(+), 31 deletions(-)
diff --git a/dlls/user/menu.c b/dlls/user/menu.c
index c688931..557d2af 100644
--- a/dlls/user/menu.c
+++ b/dlls/user/menu.c
@@ -374,6 +374,128 @@ static NTSTATUS MENU_UpdateMenu(HMENU hM
}
/***********************************************************************
+ * MENU_GetAllMenuItems
+ *
+ * Get a local copy of all menu items for given hMenu
+ * TODO: slow, implement reference counting
+ */
+static NTSTATUS MENU_GetAllMenuItems(HMENU hMenu, MENUITEM **item)
+{
+ int i;
+ unsigned int allocsize;
+ char *tmp;
+ POPUPMENU menu;
+ NTSTATUS ret;
+ if ((ret = MENU_GetMenu(hMenu, &menu)))
+ return ret;
+ if (menu.nItems == 0)
+ {
+ *item = NULL;
+ return 0;
+ }
+ allocsize = sizeof(MENUITEM) * menu.nItems;
+ for (i = 0; i < menu.nItems; i++)
+ if (menu.items[i].text)
+ allocsize += sizeof(WCHAR)*(strlenW(menu.items[i].text)+1);
+ if (!(*item = HeapAlloc(GetProcessHeap(), 0, allocsize)))
+ return STATUS_NO_MEMORY;
+ memcpy(*item, menu.items, sizeof(MENUITEM) * menu.nItems);
+
+ tmp = (char *) *item + menu.nItems * sizeof(MENUITEM);
+ for (i = 0; i < menu.nItems; i++)
+ {
+ if (menu.items[i].text)
+ {
+ memcpy(tmp, menu.items[i].text,
+ sizeof(WCHAR)*(strlenW(menu.items[i].text)+1));
+ (*item)[i].text = (WCHAR *) tmp;
+ tmp += sizeof(WCHAR)*(strlenW(menu.items[i].text)+1);
+ }
+ }
+ return 0;
+}
+
+/***********************************************************************
+ * MENU_GetMenuItem
+ *
+ * Get a local copy of menu item for given hMenu
+ */
+static NTSTATUS MENU_GetMenuItem(HMENU hMenu, unsigned int pos, MENUITEM **item)
+{
+ unsigned int allocsize;
+ POPUPMENU menu;
+ NTSTATUS ret;
+ if ((ret = MENU_GetMenu(hMenu, &menu)))
+ return ret;
+ if (pos >= menu.nItems)
+ {
+ *item = NULL;
+ return 0;
+ }
+ allocsize = sizeof(MENUITEM);
+ if (menu.items[pos].text)
+ allocsize += sizeof(WCHAR)*(strlenW(menu.items[pos].text)+1);
+ if (!(*item = HeapAlloc(GetProcessHeap(), 0, allocsize)))
+ return STATUS_NO_MEMORY;
+ memcpy(*item, &menu.items[pos], sizeof(MENUITEM));
+ if (menu.items[pos].text)
+ {
+ char *dest = (char *) *item + sizeof(MENUITEM);
+ memcpy(dest, menu.items[pos].text,
+ sizeof(WCHAR)*(strlenW(menu.items[pos].text)+1));
+ (*item)->text = (WCHAR *) dest;
+ }
+ return 0;
+}
+
+/***********************************************************************
+ * MENU_UpdateMenuItem
+ *
+ * Get a local copy of menu item for given hMenu
+ */
+static NTSTATUS MENU_UpdateMenuItem(HMENU hMenu, unsigned int pos,
+ MENUITEM *item)
+{
+ POPUPMENU menu;
+ NTSTATUS ret;
+ LPWSTR oldtext;
+ if ((ret = MENU_GetMenu(hMenu, &menu)))
+ return ret;
+ oldtext = menu.items[pos].text;
+ memcpy(&menu.items[pos], item, sizeof(MENUITEM));
+ if (!item->text)
+ {
+ if (oldtext)
+ HeapFree(GetProcessHeap(), 0, oldtext);
+ return 0;
+ }
+ if (oldtext && !strcmpW(oldtext, item->text))
+ {
+ menu.items[pos].text = oldtext;
+ return 0;
+ }
+ if (oldtext)
+ HeapFree(GetProcessHeap(), 0, oldtext);
+ menu.items[pos].text = HeapAlloc(GetProcessHeap(), 0,
+ sizeof(WCHAR)*(strlenW(item->text)+1));
+ if (!menu.items[pos].text)
+ return STATUS_NO_MEMORY;
+ memcpy(menu.items[pos].text, item->text,
+ sizeof(WCHAR)*(strlenW(item->text)+1));
+ return 0;
+}
+
+/***********************************************************************
+ * MENU_ReleaseMenuItem
+ *
+ * Get a local copy of menu item for given hMenu
+ */
+static NTSTATUS MENU_ReleaseMenuItem(MENUITEM *item)
+{
+ return HeapFree(GetProcessHeap(), 0, item);
+}
+
+/***********************************************************************
* get_win_sys_menu
*
* Get the system menu of a window
@@ -536,15 +658,18 @@ HMENU MENU_GetSysMenu( HWND hWnd, HMENU
if (hPopupMenu)
{
+ MENUITEM *item;
if (GetClassLongW(hWnd, GCL_STYLE) & CS_NOCLOSE)
DeleteMenu(hPopupMenu, SC_CLOSE, MF_BYCOMMAND);
InsertMenuW( hMenu, -1, MF_SYSMENU | MF_POPUP | MF_BYPOSITION,
(UINT_PTR)hPopupMenu, NULL );
- MENU_GetMenu(hMenu, menu);
- menu->items[0].fType = MF_SYSMENU | MF_POPUP;
- menu->items[0].fState = 0;
+ MENU_GetMenuItem(hMenu, 0, &item);
+ item->fType = MF_SYSMENU | MF_POPUP;
+ item->fState = 0;
+ MENU_UpdateMenuItem(hMenu, 0, item);
+ MENU_ReleaseMenuItem(item);
if (!MENU_GetMenu(hPopupMenu, menu))
{
menu->wFlags |= MF_SYSMENU;
@@ -601,6 +726,7 @@ static UINT MENU_GetStartOfNextColumn(
POPUPMENU tmpmenu;
POPUPMENU *menu = &tmpmenu;
UINT i;
+ MENUITEM *items;
if(MENU_GetMenu(hMenu, menu))
return NO_SELECTED_ITEM;
@@ -609,11 +735,16 @@ static UINT MENU_GetStartOfNextColumn(
if( i == NO_SELECTED_ITEM )
return i;
+ MENU_GetAllMenuItems(hMenu, &items);
for( ; i < menu->nItems; ++i ) {
- if (menu->items[i].fType & MF_MENUBARBREAK)
+ if (items[i].fType & MF_MENUBARBREAK)
+ {
+ MENU_ReleaseMenuItem(items);
return i;
+ }
}
+ MENU_ReleaseMenuItem(items);
return NO_SELECTED_ITEM;
}
@@ -631,6 +762,7 @@ static UINT MENU_GetStartOfPrevColumn(
POPUPMENU tmpmenu;
POPUPMENU *menu = &tmpmenu;
UINT i;
+ MENUITEM *items;
if( MENU_GetMenu(hMenu, menu) )
return NO_SELECTED_ITEM;
@@ -641,17 +773,22 @@ static UINT MENU_GetStartOfPrevColumn(
/* Find the start of the column */
+ MENU_GetAllMenuItems(hMenu, &items);
for(i = MENU_GetLocalMenu(hMenu)->FocusedItem; i != 0 &&
- !(menu->items[i].fType & MF_MENUBARBREAK);
+ !(items[i].fType & MF_MENUBARBREAK);
--i) ; /* empty */
if(i == 0)
+ {
+ MENU_ReleaseMenuItem(items);
return NO_SELECTED_ITEM;
+ }
for(--i; i != 0; --i) {
- if (menu->items[i].fType & MF_MENUBARBREAK)
+ if (items[i].fType & MF_MENUBARBREAK)
break;
}
+ MENU_ReleaseMenuItem(items);
TRACE("ret %d.\n", i );
@@ -683,7 +820,10 @@ static UINT MENU_FindItem( HMENU *hmenu,
}
else
{
- MENUITEM *item = menu->items;
+ MENUITEM *items;
+ MENUITEM *item;
+ MENU_GetAllMenuItems(*hmenu, &items);
+ item = items;
for (i = 0; i < menu->nItems; i++, item++)
{
if (item->fType & MF_POPUP)
@@ -693,6 +833,7 @@ static UINT MENU_FindItem( HMENU *hmenu,
if (subitem != ITEM_NOT_FOUND)
{
*hmenu = hsubmenu;
+ MENU_ReleaseMenuItem(items);
return subitem;
}
else if (item->wID == *nPos)
@@ -705,9 +846,11 @@ static UINT MENU_FindItem( HMENU *hmenu,
else if (item->wID == *nPos)
{
*nPos = i;
+ MENU_ReleaseMenuItem(items);
return i;
}
}
+ MENU_ReleaseMenuItem(items);
}
if (fallback)
@@ -728,14 +871,16 @@ UINT MENU_FindSubMenu( HMENU *hmenu, HME
POPUPMENU tmpmenu;
POPUPMENU *menu = &tmpmenu;
UINT i;
- MENUITEM *item;
+ MENUITEM *item, *items;
if (((*hmenu)==(HMENU)0xffff) ||
(MENU_GetMenu(*hmenu, menu)))
return NO_SELECTED_ITEM;
- item = menu->items;
+ MENU_GetAllMenuItems(*hmenu, &items);
+ item = items;
for (i = 0; i < menu->nItems; i++, item++) {
if(!(item->fType & MF_POPUP)) continue;
if (item->hSubMenu == hSubTarget) {
+ MENU_ReleaseMenuItem(items);
return i;
}
else {
@@ -743,10 +888,12 @@ UINT MENU_FindSubMenu( HMENU *hmenu, HME
UINT pos = MENU_FindSubMenu( &hsubmenu, hSubTarget );
if (pos != NO_SELECTED_ITEM) {
*hmenu = hsubmenu;
+ MENU_ReleaseMenuItem(items);
return pos;
}
}
}
+ MENU_ReleaseMenuItem(items);
return NO_SELECTED_ITEM;
}
@@ -791,7 +938,7 @@ MENU_AdjustMenuItemRect(HMENU hmenu, LPR
*/
static void MENU_FindItemByCoords( HMENU hmenu, POINT pt, UINT *pos )
{
- MENUITEM *item;
+ MENUITEM *item, *items;
UINT i;
RECT wrect;
RECT rect;
@@ -803,7 +950,8 @@ static void MENU_FindItemByCoords( HMENU
if (!GetWindowRect(menu->hWnd,&wrect)) return;
pt.x -= wrect.left;pt.y -= wrect.top;
- item = menu->items;
+ MENU_GetAllMenuItems(hmenu, &items);
+ item = items;
for (i = 0; i < menu->nItems; i++, item++)
{
rect = item->rect;
@@ -812,9 +960,11 @@ static void MENU_FindItemByCoords( HMENU
(pt.y >= rect.top) && (pt.y < rect.bottom))
{
if (pos) *pos = i;
+ MENU_ReleaseMenuItem(items);
return;
}
}
+ MENU_ReleaseMenuItem(items);
return;
}
@@ -836,15 +986,17 @@ static UINT MENU_FindItemByKey( HWND hwn
{
POPUPMENU tmpmenu;
POPUPMENU *menu = &tmpmenu;
- MENUITEM *item;
+ MENUITEM *item, *items;
LRESULT menuchar;
MENU_GetMenu(hmenu, menu);
- item = menu->items;
if( !forceMenuChar )
{
UINT i;
+ MENU_GetAllMenuItems(hmenu, &items);
+ item = items;
+
for (i = 0; i < menu->nItems; i++, item++)
{
if( item->text)
@@ -855,9 +1007,14 @@ static UINT MENU_FindItemByKey( HWND hwn
p = strchrW (p + 2, '&');
}
while (p != NULL && p [1] == '&');
- if (p && (toupperW(p[1]) == toupperW(key))) return i;
+ if (p && (toupperW(p[1]) == toupperW(key)))
+ {
+ MENU_ReleaseMenuItem(items);
+ return i;
+ }
}
}
+ MENU_ReleaseMenuItem(items);
}
menuchar = SendMessageW( hwndOwner, WM_MENUCHAR,
MAKEWPARAM( key, menu->wFlags ), (LPARAM)hmenu );
@@ -1209,7 +1366,7 @@ MENU_GetMaxPopupHeight(LPPOPUPMENU lppop
*/
static void MENU_PopupMenuCalcSize( HMENU hmenu, HWND hwndOwner )
{
- MENUITEM *lpitem;
+ MENUITEM *lpitem, *items;
HDC hdc;
int start, i;
int orgX, orgY, maxX, maxTab, maxTabWidth, maxHeight;
@@ -1234,9 +1391,10 @@ static void MENU_PopupMenuCalcSize( HMEN
lppop->maxBmpSize.cx = 0;
lppop->maxBmpSize.cy = 0;
+ MENU_GetAllMenuItems(hmenu, &items);
while (start < lppop->nItems)
{
- lpitem = &lppop->items[start];
+ lpitem = &items[start];
orgX = maxX;
if( lpitem->fType & MF_MENUBREAK)
orgX += MENU_COL_SPACE;
@@ -1250,6 +1408,7 @@ static void MENU_PopupMenuCalcSize( HMEN
(lpitem->fType & (MF_MENUBREAK | MF_MENUBARBREAK))) break;
MENU_CalcItemSize( hdc, lpitem, hwndOwner, orgX, orgY, FALSE, lppop );
+ MENU_UpdateMenuItem(hmenu, i, lpitem);
if (lpitem->fType & MF_MENUBARBREAK) orgX++;
maxX = max( maxX, lpitem->rect.right );
@@ -1263,15 +1422,17 @@ static void MENU_PopupMenuCalcSize( HMEN
/* Finish the column (set all items to the largest width found) */
maxX = max( maxX, maxTab + maxTabWidth );
- for (lpitem = &lppop->items[start]; start < i; start++, lpitem++)
+ for (lpitem = &items[start]; start < i; start++, lpitem++)
{
lpitem->rect.right = maxX;
if (IS_STRING_ITEM(lpitem->fType) && lpitem->xTab)
lpitem->xTab = maxTab;
+ MENU_UpdateMenuItem(hmenu, start, lpitem);
}
lppop->Height = max( lppop->Height, orgY );
}
+ MENU_ReleaseMenuItem(items);
lppop->Width = maxX;
@@ -1441,7 +1602,7 @@ static void draw_popup_arrow( HDC hdc, R
/***********************************************************************
* MENU_DrawMenuItem
*
- * Draw a single menu item.
+ * Draw a single menu item. Updates lpitem->rect.
*/
static void MENU_DrawMenuItem( HWND hwnd, HMENU hmenu, HWND hwndOwner, HDC hdc, MENUITEM *lpitem,
UINT height, BOOL menuBar, UINT odaction )
@@ -1822,13 +1983,18 @@ static void MENU_DrawPopupMenu( HWND hwn
/* draw menu items */
if( menu->nItems)
{
- MENUITEM *item;
+ MENUITEM *item, *items;
UINT u;
- item = menu->items;
- for( u = menu->nItems; u > 0; u--, item++)
+ MENU_GetAllMenuItems(hmenu, &items);
+ item = items;
+ for( u = 0; u < menu->nItems; u++, item++)
+ {
MENU_DrawMenuItem( hwnd, hmenu, menu->hwndOwner, hdc,
item, menu->Height, FALSE, ODA_DRAWENTIRE );
+ MENU_UpdateMenuItem(hmenu, u, item);
+ }
+ MENU_ReleaseMenuItem(items);
}
/* draw scroll arrows */
if (MENU_GetLocalMenu(hmenu)->bScrolling)
@@ -1899,7 +2065,11 @@ static BOOL MENU_ShowPopup( HWND hwndOwn
if (MENU_GetMenu( hmenu, menu )) return FALSE;
if (lpm->FocusedItem != NO_SELECTED_ITEM)
{
- menu->items[lpm->FocusedItem].fState &= ~(MF_HILITE|MF_MOUSESELECT);
+ MENUITEM *item;
+ MENU_GetMenuItem(hmenu, lpm->FocusedItem, &item);
+ item->fState &= ~(MF_HILITE|MF_MOUSESELECT);
+ MENU_UpdateMenuItem(hmenu, lpm->FocusedItem, item);
+ MENU_ReleaseMenuItem(item);
lpm->FocusedItem = NO_SELECTED_ITEM;
}
@@ -1967,12 +2137,13 @@ MENU_EnsureMenuItemVisible(HMENU hmenu,
if (lpm->bScrolling)
{
- MENUITEM *item = &lppop->items[wIndex];
UINT nMaxHeight = MENU_GetMaxPopupHeight(lppop);
UINT nOldPos = lpm->nScrollPos;
RECT rc;
UINT arrow_bitmap_height;
BITMAP bmp;
+ MENUITEM *item;
+ MENU_GetMenuItem(hmenu, wIndex, &item);
GetClientRect(lppop->hWnd, &rc);
@@ -1996,6 +2167,7 @@ MENU_EnsureMenuItemVisible(HMENU hmenu,
ScrollWindow(lppop->hWnd, 0, nOldPos - lpm->nScrollPos, &rc, &rc);
MENU_DrawScrollArrows(hmenu, hdc);
}
+ MENU_ReleaseMenuItem(item);
}
}
@@ -2009,6 +2181,7 @@ static void MENU_SelectItem( HWND hwndOw
POPUPMENU tmppop;
LPPOPUPMENU lppop = &tmppop;
LOCALPOPUPMENU *lpm;
+ MENUITEM *items;
HDC hdc;
TRACE("owner=%p menu=%p index=0x%04x select=0x%04x\n", hwndOwner, hmenu, wIndex, sendMenuSelect);
@@ -2024,30 +2197,33 @@ static void MENU_SelectItem( HWND hwndOw
SelectObject( hdc, get_menu_font(FALSE));
+ MENU_GetAllMenuItems(hmenu, &items);
/* Clear previous highlighted item */
if (lpm->FocusedItem != NO_SELECTED_ITEM)
{
- lppop->items[lpm->FocusedItem].fState &= ~(MF_HILITE|MF_MOUSESELECT);
+ items[lpm->FocusedItem].fState &= ~(MF_HILITE|MF_MOUSESELECT);
MENU_DrawMenuItem(lppop->hWnd, hmenu, hwndOwner, hdc,
- &lppop->items[lpm->FocusedItem],
+ &items[lpm->FocusedItem],
lppop->Height, !(lppop->wFlags & MF_POPUP),
ODA_SELECT );
+ MENU_UpdateMenuItem(hmenu, lpm->FocusedItem, &items[lpm->FocusedItem]);
}
/* Highlight new item (if any) */
lpm->FocusedItem = wIndex;
if (lpm->FocusedItem != NO_SELECTED_ITEM)
{
- if(!(lppop->items[wIndex].fType & MF_SEPARATOR)) {
- lppop->items[wIndex].fState |= MF_HILITE;
+ if(!(items[wIndex].fType & MF_SEPARATOR)) {
+ items[wIndex].fState |= MF_HILITE;
MENU_EnsureMenuItemVisible(hmenu, wIndex, hdc);
MENU_DrawMenuItem( lppop->hWnd, hmenu, hwndOwner, hdc,
- &lppop->items[wIndex], lppop->Height,
+ &items[wIndex], lppop->Height,
!(lppop->wFlags & MF_POPUP), ODA_SELECT );
+ MENU_UpdateMenuItem(hmenu, wIndex, &items[wIndex]);
}
if (sendMenuSelect)
{
- MENUITEM *ip = &lppop->items[lpm->FocusedItem];
+ MENUITEM *ip = &items[lpm->FocusedItem];
SendMessageW( hwndOwner, WM_MENUSELECT,
MAKELONG(ip->fType & MF_POPUP ? wIndex: ip->wID,
ip->fType | ip->fState |
@@ -2062,7 +2238,7 @@ static void MENU_SelectItem( HWND hwndOw
POPUPMENU *ptm = &tmpptm;
MENUITEM *ip;
MENU_GetMenu( topmenu, ptm );
- ip = &ptm->items[pos];
+ ip = &items[pos];
SendMessageW( hwndOwner, WM_MENUSELECT, MAKELONG(pos,
ip->fType | ip->fState |
(ptm->wFlags & MF_SYSMENU)), (LPARAM)topmenu);
@@ -2070,6 +2246,7 @@ static void MENU_SelectItem( HWND hwndOw
}
}
ReleaseDC( lppop->hWnd, hdc );
+ MENU_ReleaseMenuItem(items);
}
@@ -2374,9 +2551,13 @@ static HMENU MENU_GetSubPopup( HMENU hme
if (MENU_GetMenu( hmenu, menu )
|| (lpm->FocusedItem == NO_SELECTED_ITEM)) return 0;
- item = &menu->items[lpm->FocusedItem];
+ MENU_GetMenuItem(hmenu, lpm->FocusedItem, &item);
if ((item->fType & MF_POPUP) && (item->fState & MF_MOUSESELECT))
+ {
+ MENU_ReleaseMenuItem(item);
return item->hSubMenu;
+ }
+ MENU_ReleaseMenuItem(item);
return 0;
}
More information about the wine-patches
mailing list