-/* $Id$
- *
+/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS user32.dll
* FILE: user32/windows/menu.c
/* 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 */
/* Use global popup window because there's no way 2 menus can
* be tracked at the same time. */
static HWND top_popup;
+static HMENU top_popup_hmenu;
/* Flag set by EndMenu() to force an exit from menu tracking */
static BOOL fEndMenu = FALSE;
#define SEPARATOR_HEIGHT (5)
#define MENU_TAB_SPACE (8)
-#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 */
-
typedef struct
{
UINT TrackFlags;
*/
const struct builtin_class_descr POPUPMENU_builtin_class =
{
- POPUPMENU_CLASS_ATOMW, /* name */
+ WC_MENU, /* name */
CS_SAVEBITS | CS_DBLCLKS, /* style */
(WNDPROC) NULL, /* FIXME - procA */
(WNDPROC) PopupMenuWndProcW, /* FIXME - procW */
TRACE("\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 = toupperW(Key);
+ }
+ if ( !ForceMenuChar )
+ {
ItemInfo = Items;
for (i = 0; i < MenuInfo->MenuItemCount; i++, ItemInfo++)
- {
- if ((ItemInfo->Text) && NULL != ItemInfo->dwTypeData)
- {
+ {
+ if ((ItemInfo->lpstr) && NULL != ItemInfo->dwTypeData)
+ {
WCHAR *p = (WCHAR *) ItemInfo->dwTypeData - 2;
do
- {
- p = strchrW(p + 2, '&');
- }
- while (NULL != p && L'&' == p[1]);
- if (NULL != p && (toupperW(p[1]) == Key))
- {
- return i;
- }
- }
- }
- }
+ {
+ p = strchrW (p + 2, '&');
+ }
+ while (p != NULL && p [1] == '&');
+ if (p && (toupperW(p[1]) == toupperW(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);
- }
+ if (HIWORD(MenuChar) == MNC_EXECUTE) return LOWORD(MenuChar);
+ if (HIWORD(MenuChar) == MNC_CLOSE) return (UINT)(-2);
}
-
return (UINT)(-1);
}
*
* Get the size of a bitmap item.
*/
-static void FASTCALL MenuGetBitmapItemSize(PROSMENUITEMINFO lpitem, SIZE *size,
- HWND WndOwner)
+static void FASTCALL MenuGetBitmapItemSize(PROSMENUITEMINFO lpitem, SIZE *size, HWND WndOwner)
{
BITMAP bm;
HBITMAP bmp = lpitem->hbmpItem;
mis.itemWidth = 0;
SendMessageW( hwndOwner, WM_MEASUREITEM, 0, (LPARAM)&mis );
/* Tests reveal that Windows ( Win95 thru WinXP) adds twice the average
- * width of a menufont character to the width of an owner-drawn menu.
+ * width of a menufont character to the width of an owner-drawn menu.
*/
lpitem->Rect.right += mis.itemWidth + 2 * MenuCharSize.cx;
return;
}
- lpitem->XTab = 0;
+ lpitem->dxTab = 0;
if (lpitem->hbmpItem)
{
if( !(MenuInfo->dwStyle & MNS_NOCHECK))
lpitem->Rect.right += 2 * check_bitmap_width;
lpitem->Rect.right += 4 + MenuCharSize.cx;
- lpitem->XTab = lpitem->Rect.right;
+ lpitem->dxTab = lpitem->Rect.right;
lpitem->Rect.right += check_bitmap_width;
} else /* hbmpItem & MenuBar */ {
MenuGetBitmapItemSize(lpitem, &size, hwndOwner );
lpitem->Rect.right += size.cx;
- if( lpitem->Text) lpitem->Rect.right += 2;
+ if( lpitem->lpstr) lpitem->Rect.right += 2;
itemheight = size.cy;
/* Special case: Minimize button doesn't have a space behind it. */
if( !(MenuInfo->dwStyle & MNS_NOCHECK))
lpitem->Rect.right += check_bitmap_width;
lpitem->Rect.right += 4 + MenuCharSize.cx;
- lpitem->XTab = lpitem->Rect.right;
+ lpitem->dxTab = lpitem->Rect.right;
lpitem->Rect.right += check_bitmap_width;
}
/* it must be a text item - unless it's the system menu */
- if (!(lpitem->fType & MF_SYSMENU) && lpitem->Text) {
+ if (!(lpitem->fType & MF_SYSMENU) && lpitem->lpstr) {
HFONT hfontOld = NULL;
RECT rc = lpitem->Rect;
LONG txtheight, txtwidth;
}
if (menuBar) {
txtheight = DrawTextW( hdc, lpitem->dwTypeData, -1, &rc,
- DT_SINGLELINE|DT_CALCRECT);
+ DT_SINGLELINE|DT_CALCRECT);
lpitem->Rect.right += rc.right - rc.left;
itemheight = max( max( itemheight, txtheight),
GetSystemMetrics( SM_CYMENU) - 1);
/* get text size after the tab */
tmpheight = DrawTextW( hdc, p, -1, &tmprc,
DT_SINGLELINE|DT_CALCRECT);
- lpitem->XTab += txtwidth;
+ lpitem->dxTab += txtwidth;
txtheight = max( txtheight, tmpheight);
txtwidth += MenuCharSize.cx + /* space for the tab */
tmprc.right - tmprc.left; /* space for the short cut */
txtheight = DrawTextW( hdc, lpitem->dwTypeData, -1, &rc,
DT_SINGLELINE|DT_CALCRECT);
txtwidth = rc.right - rc.left;
- lpitem->XTab += txtwidth;
+ lpitem->dxTab += txtwidth;
}
lpitem->Rect.right += 2 + txtwidth;
itemheight = max( itemheight,
// }
maxX = max(maxX, lpitem.Rect.right);
orgY = lpitem.Rect.bottom;
- if ((lpitem.Text) && lpitem.XTab )
+ if ((lpitem.lpstr) && lpitem.dxTab )
{
- maxTab = max( maxTab, lpitem.XTab );
- maxTabWidth = max(maxTabWidth, lpitem.Rect.right - lpitem.XTab);
+ maxTab = max( maxTab, lpitem.dxTab );
+ maxTabWidth = max(maxTabWidth, lpitem.Rect.right - lpitem.dxTab);
}
}
if (MenuGetRosMenuItemInfo(MenuInfo->Self, start, &lpitem))
{
lpitem.Rect.right = maxX;
- if ((lpitem.Text) && 0 != lpitem.XTab)
+ if ((lpitem.lpstr) && 0 != lpitem.dxTab)
{
- lpitem.XTab = maxTab;
+ lpitem.dxTab = maxTab;
}
MenuSetRosMenuItemInfo(MenuInfo->Self, start, &lpitem);
}
SystemParametersInfoW (SPI_GETFLATMENU, 0, &flat_menu, 0);
bkgnd = (menuBar && flat_menu) ? COLOR_MENUBAR : COLOR_MENU;
-
+
/* Setup colors */
if (lpitem->fState & MF_HILITE)
* Custom checkmark bitmaps are monochrome but not always 1bpp.
*/
if( !(MenuInfo->dwStyle & MNS_NOCHECK)) {
- bm = (lpitem->fState & MF_CHECKED) ? lpitem->hbmpChecked :
+ bm = (lpitem->fState & MF_CHECKED) ? lpitem->hbmpChecked :
lpitem->hbmpUnchecked;
if (bm) /* we have a custom bitmap */
{
}
/* process text if present */
- if (lpitem->Text)
+ if (lpitem->lpstr)
{
register int i = 0;
HFONT hfontOld = 0;
{
if (L'\t' == Text[i])
{
- rect.left = lpitem->XTab;
+ rect.left = lpitem->dxTab;
uFormat = DT_LEFT | DT_VCENTER | DT_SINGLELINE;
}
else
{
- rect.right = lpitem->XTab;
+ rect.right = lpitem->dxTab;
uFormat = DT_RIGHT | DT_VCENTER | DT_SINGLELINE;
}
if (MenuGetRosMenuInfo(&MenuInfo, hmenu) && MenuInfo.MenuItemCount)
{
UINT u;
-
+
MenuInitRosMenuItemInfo(&ItemInfo);
for (u = 0; u < MenuInfo.MenuItemCount; u++)
}
/* store the owner for DrawItem */
+ if (!IsWindow(hwndOwner))
+ {
+ SetLastError( ERROR_INVALID_WINDOW_HANDLE );
+ return FALSE;
+ }
MenuInfo.WndOwner = hwndOwner;
MenuSetRosMenuInfo(&MenuInfo);
if( flags & TPM_BOTTOMALIGN ) y -= height;
if( flags & TPM_VCENTERALIGN ) y -= height / 2;
- if( x + width > info.rcWork.right)
+ if( x + width > info.rcMonitor.right)
{
if( xanchor && x >= width - xanchor )
x -= width - xanchor;
- if( x + width > info.rcWork.right)
- x = info.rcWork.right - width;
+ if( x + width > info.rcMonitor.right)
+ x = info.rcMonitor.right - width;
}
- if( x < info.rcWork.left ) x = info.rcWork.left;
+ if( x < info.rcMonitor.left ) x = info.rcMonitor.left;
- if( y + height > info.rcWork.bottom)
+ if( y + height > info.rcMonitor.bottom)
{
if( yanchor && y >= height + yanchor )
y -= height + yanchor;
- if( y + height > info.rcWork.bottom)
- y = info.rcWork.bottom - height;
+ if( y + height > info.rcMonitor.bottom)
+ y = info.rcMonitor.bottom - height;
}
- if( y < info.rcWork.top ) y = info.rcWork.top;
+ if( y < info.rcMonitor.top ) y = info.rcMonitor.top;
/* NOTE: In Windows, top menu popup is not owned. */
- MenuInfo.Wnd = CreateWindowExW( 0, POPUPMENU_CLASS_ATOMW, NULL,
+ MenuInfo.Wnd = CreateWindowExW( 0, WC_MENU, NULL,
WS_POPUP, x, y, width, height,
hwndOwner, 0, (HINSTANCE) GetWindowLongPtrW(hwndOwner, GWLP_HINSTANCE),
(LPVOID) MenuInfo.Self);
if ( !MenuInfo.Wnd || ! MenuSetRosMenuInfo(&MenuInfo)) return FALSE;
if (!top_popup) {
top_popup = MenuInfo.Wnd;
+ top_popup_hmenu = hmenu;
}
+ IntNotifyWinEvent(EVENT_SYSTEM_MENUPOPUPSTART, MenuInfo.Wnd, OBJID_CLIENT, CHILDID_SELF, 0);
+
/* Display the window */
SetWindowPos( MenuInfo.Wnd, HWND_TOPMOST, 0, 0, 0, 0,
return TRUE;
}
+
/***********************************************************************
* MenuSelectItem
*/
else hdc = GetDCEx(hmenu->Wnd, 0, DCX_CACHE | DCX_WINDOW);
if (!top_popup) {
top_popup = hmenu->Wnd;
+ top_popup_hmenu = hmenu->Self;
}
SelectObject( hdc, hMenuFont );
MenuCleanupRosMenuItemInfo(&ItemInfo);
}
+//
+// This breaks some test results. Should handle A2U if called!
+//
LRESULT WINAPI PopupMenuWndProcA(HWND Wnd, UINT Message, WPARAM wParam, LPARAM lParam)
{
TRACE("YES! hwnd=%x msg=0x%04x wp=0x%04lx lp=0x%08lx\n", Wnd, Message, wParam, lParam);
+#ifdef __REACTOS__
+ PWND pWnd;
+
+ pWnd = ValidateHwnd(Wnd);
+ if (pWnd)
+ {
+ if (!pWnd->fnid)
+ {
+ NtUserSetWindowFNID(Wnd, FNID_MENU);
+ }
+ }
+#endif
switch(Message)
{
case WM_CREATE:
{
CREATESTRUCTA *cs = (CREATESTRUCTA *) lParam;
- SetWindowLongPtrA(Wnd, 0, (LONG) cs->lpCreateParams);
+ SetWindowLongPtrA(Wnd, 0, (LONG_PTR)cs->lpCreateParams);
return 0;
}
if (Wnd == top_popup)
{
top_popup = NULL;
+ top_popup_hmenu = NULL;
}
+#ifdef __REACTOS__
+ NtUserSetWindowFNID(Wnd, FNID_DESTROY);
+#endif
break;
case WM_SHOWWINDOW:
break;
case MM_GETMENUHANDLE:
- case MN_GETHMENU:
+ case MN_GETHMENU:
return GetWindowLongPtrA(Wnd, 0);
default:
PopupMenuWndProcW(HWND Wnd, UINT Message, WPARAM wParam, LPARAM lParam)
{
TRACE("hwnd=%x msg=0x%04x wp=0x%04lx lp=0x%08lx\n", Wnd, Message, wParam, lParam);
+#ifdef __REACTOS__ // Do this now, remove after Server side is fixed.
+ PWND pWnd;
+
+ pWnd = ValidateHwnd(Wnd);
+ if (pWnd)
+ {
+ if (!pWnd->fnid)
+ {
+ NtUserSetWindowFNID(Wnd, FNID_MENU);
+ }
+ }
+#endif
switch(Message)
{
case WM_CREATE:
{
CREATESTRUCTW *cs = (CREATESTRUCTW *) lParam;
- SetWindowLongPtrW(Wnd, 0, (LONG) cs->lpCreateParams);
+ SetWindowLongPtrW(Wnd, 0, (LONG_PTR)cs->lpCreateParams);
return 0;
}
if (Wnd == top_popup)
{
top_popup = NULL;
+ top_popup_hmenu = NULL;
}
+#ifdef __REACTOS__
+ NtUserSetWindowFNID(Wnd, FNID_DESTROY);
+#endif
break;
case WM_SHOWWINDOW:
SelectObject(DC, GetStockObject(DC_PEN));
SetDCPenColor(DC, GetSysColor(COLOR_3DFACE));
- MoveToEx(DC, Rect->left, Rect->bottom, NULL);
- LineTo(DC, Rect->right, Rect->bottom);
+ MoveToEx(DC, Rect->left, Rect->bottom - 1, NULL);
+ LineTo(DC, Rect->right, Rect->bottom - 1);
if (0 == MenuInfo.MenuItemCount)
{
return Ret;
}
+/**********************************************************************
+ * MENU_EndMenu
+ *
+ * Calls EndMenu() if the hwnd parameter belongs to the menu owner
+ *
+ * Does the (menu stuff) of the default window handling of WM_CANCELMODE
+ */
+void MENU_EndMenu( HWND hwnd )
+{
+ ROSMENUINFO MenuInfo;
+ BOOL Ret = FALSE;
+ if (top_popup_hmenu)
+ Ret = MenuGetRosMenuInfo(&MenuInfo, top_popup_hmenu);
+ if (Ret && hwnd == MenuInfo.WndOwner) EndMenu();
+}
+
/***********************************************************************
* MenuHideSubPopups
*
* Hide the sub-popup menus of this menu.
*/
static void FASTCALL
-MenuHideSubPopups(HWND WndOwner, PROSMENUINFO MenuInfo, BOOL SendMenuSelect)
+MenuHideSubPopups(HWND WndOwner, PROSMENUINFO MenuInfo,
+ BOOL SendMenuSelect, UINT wFlags)
{
ROSMENUINFO SubMenuInfo;
ROSMENUITEMINFO ItemInfo;
TRACE("owner=%x menu=%x 0x%04x\n", WndOwner, MenuInfo, SendMenuSelect);
if (NULL != MenuInfo && NULL != top_popup && NO_SELECTED_ITEM != MenuInfo->FocusedItem)
- {
+ {
MenuInitRosMenuItemInfo(&ItemInfo);
ItemInfo.fMask |= MIIM_FTYPE | MIIM_STATE;
if (! MenuGetRosMenuItemInfo(MenuInfo->Self, MenuInfo->FocusedItem, &ItemInfo)
|| 0 == (ItemInfo.fType & MF_POPUP)
|| 0 == (ItemInfo.fState & MF_MOUSESELECT))
- {
+ {
MenuCleanupRosMenuItemInfo(&ItemInfo);
return;
- }
+ }
ItemInfo.fState &= ~MF_MOUSESELECT;
ItemInfo.fMask |= MIIM_STATE;
MenuSetRosMenuItemInfo(MenuInfo->Self, MenuInfo->FocusedItem, &ItemInfo);
if (MenuGetRosMenuInfo(&SubMenuInfo, ItemInfo.hSubMenu))
- {
- MenuHideSubPopups(WndOwner, &SubMenuInfo, FALSE);
+ {
+ MenuHideSubPopups(WndOwner, &SubMenuInfo, FALSE, wFlags);
MenuSelectItem(WndOwner, &SubMenuInfo, NO_SELECTED_ITEM, SendMenuSelect, NULL);
DestroyWindow(SubMenuInfo.Wnd);
SubMenuInfo.Wnd = NULL;
MenuSetRosMenuInfo(&SubMenuInfo);
- }
- }
+
+ if (!(wFlags & TPM_NONOTIFY))
+ SendMessageW( WndOwner, WM_UNINITMENUPOPUP, (WPARAM)ItemInfo.hSubMenu,
+ MAKELPARAM(0, IS_SYSTEM_MENU(&SubMenuInfo)) );
+ }
+ }
}
/***********************************************************************
* Helper function for menu navigation routines.
*/
static void FASTCALL
-MenuSwitchTracking(MTRACKER* Mt, PROSMENUINFO PtMenuInfo, UINT Index)
+MenuSwitchTracking(MTRACKER* Mt, PROSMENUINFO PtMenuInfo, UINT Index, UINT wFlags)
{
ROSMENUINFO TopMenuInfo;
0 == ((PtMenuInfo->Flags | TopMenuInfo.Flags) & MF_POPUP))
{
/* both are top level menus (system and menu-bar) */
- MenuHideSubPopups(Mt->OwnerWnd, &TopMenuInfo, FALSE);
+ MenuHideSubPopups(Mt->OwnerWnd, &TopMenuInfo, FALSE, wFlags);
MenuSelectItem(Mt->OwnerWnd, &TopMenuInfo, NO_SELECTED_ITEM, FALSE, NULL);
Mt->TopMenu = PtMenuInfo->Self;
}
else
{
- MenuHideSubPopups(Mt->OwnerWnd, PtMenuInfo, FALSE);
+ MenuHideSubPopups(Mt->OwnerWnd, PtMenuInfo, FALSE, wFlags);
}
MenuSelectItem(Mt->OwnerWnd, PtMenuInfo, Index, TRUE, NULL);
{
if (MenuInfo.FocusedItem != Index)
{
- MenuSwitchTracking(Mt, &MenuInfo, Index);
+ MenuSwitchTracking(Mt, &MenuInfo, Index, Flags);
}
/* If the popup menu is not already "popped" */
if (MenuGetRosMenuItemInfo(MenuInfo.Self, Index, &ItemInfo) &&
!(ItemInfo.fType & MF_SEPARATOR))
{
- MenuSwitchTracking(Mt, &MenuInfo, Index);
+ MenuSwitchTracking(Mt, &MenuInfo, Index, Flags);
if (!(ItemInfo.fState & (MFS_DISABLED | MFS_GRAYED)))
Mt->CurrentMenu = MenuShowSubPopup(Mt->OwnerWnd, &MenuInfo, FALSE, Flags);
}
* NOTE: WM_NEXTMENU documented in Win32 is a bit different.
*/
static LRESULT FASTCALL
-MenuDoNextMenu(MTRACKER* Mt, UINT Vk)
+MenuDoNextMenu(MTRACKER* Mt, UINT Vk, UINT wFlags)
{
ROSMENUINFO TopMenuInfo;
ROSMENUINFO MenuInfo;
FALSE, 0 );
if (Mt->CurrentMenu != Mt->TopMenu)
{
- MenuHideSubPopups(Mt->OwnerWnd, &TopMenuInfo, FALSE);
+ MenuHideSubPopups(Mt->OwnerWnd, &TopMenuInfo, FALSE, wFlags);
}
}
if (MenuGetRosMenuInfo(&MenuInfo, MenuPrev))
{
- MenuHideSubPopups(Mt->OwnerWnd, &MenuInfo, TRUE);
+ MenuHideSubPopups(Mt->OwnerWnd, &MenuInfo, TRUE, Flags);
}
Mt->CurrentMenu = MenuPrev;
EndMenu = FALSE;
{
return;
}
- MenuHideSubPopups(Mt->OwnerWnd, &PrevMenuInfo, TRUE);
+ MenuHideSubPopups(Mt->OwnerWnd, &PrevMenuInfo, TRUE, Flags);
Mt->CurrentMenu = MenuPrev;
if (! MenuGetRosMenuInfo(&TopMenuInfo, Mt->TopMenu))
{
/* move menu bar selection if no more popups are left */
- if (! MenuDoNextMenu(Mt, VK_LEFT))
+ if (! MenuDoNextMenu(Mt, VK_LEFT, Flags))
{
MenuMoveSelection(Mt->OwnerWnd, &TopMenuInfo, ITEM_PREV);
}
{
if (Mt->CurrentMenu != Mt->TopMenu)
{
- MenuHideSubPopups(Mt->OwnerWnd, &MenuInfo, FALSE );
+ MenuHideSubPopups(Mt->OwnerWnd, &MenuInfo, FALSE, Flags);
hmenutmp = Mt->CurrentMenu = Mt->TopMenu;
}
else
}
/* try to move to the next item */
- if ( !MenuDoNextMenu(Mt, VK_RIGHT))
+ if ( !MenuDoNextMenu(Mt, VK_RIGHT, Flags))
MenuMoveSelection(Mt->OwnerWnd, &MenuInfo, ITEM_NEXT);
if ( hmenutmp || Mt->TrackFlags & TF_SUSPENDPOPUP )
BOOL fRemove;
INT executedMenuId = -1;
MTRACKER mt;
+ HWND capture_win;
BOOL enterIdleSent = FALSE;
mt.TrackFlags = 0;
if (!IsMenu(hmenu))
{
+ WARN("Invalid menu handle %p\n", hmenu);
SetLastError( ERROR_INVALID_MENU_HANDLE );
return FALSE;
}
fEndMenu = !fRemove;
}
- SetCapture(mt.OwnerWnd);
- (void)NtUserSetGUIThreadHandle(MSQ_STATE_MENUOWNER, mt.OwnerWnd);
+ if (wFlags & TF_ENDMENU) fEndMenu = TRUE;
+
+ /* owner may not be visible when tracking a popup, so use the menu itself */
+ capture_win = (wFlags & TPM_POPUPMENU) ? MenuInfo.Wnd : mt.OwnerWnd;
+ (void)NtUserSetGUIThreadHandle(MSQ_STATE_MENUOWNER, capture_win); // 1
+ SetCapture(capture_win); // 2
- ERR("MenuTrackMenu 1\n");
while (! fEndMenu)
{
+ BOOL ErrorExit = FALSE;
PVOID menu = ValidateHandle(mt.CurrentMenu, VALIDATE_TYPE_MENU);
if (!menu) /* sometimes happens if I do a window manager close */
break;
}
else
{
+ /* ReactOS Check */
+ if (!ValidateHwnd(mt.OwnerWnd) || !ValidateHwnd(MenuInfo.Wnd))
+ {
+ ErrorExit = TRUE; // Do not wait on dead windows, now test_capture_4 works.
+ break;
+ }
if (!enterIdleSent)
{
- HWND win = (wFlags & TPM_ENTERIDLEEX) && (MenuInfo.Flags & MF_POPUP) ? MenuInfo.Wnd : NULL;
+ HWND win = MenuInfo.Flags & MF_POPUP ? MenuInfo.Wnd : NULL;
enterIdleSent = TRUE;
SendMessageW( mt.OwnerWnd, WM_ENTERIDLE, MSGF_MENU, (LPARAM) win);
}
}
}
+ if (ErrorExit) break; // Gracefully dropout.
+
/* check if EndMenu() tried to cancel us, by posting this message */
if (msg.message == WM_CANCELMODE)
{
if (hmenu)
{
executedMenuId = MenuButtonUp( &mt, hmenu, wFlags);
+ TRACE("executedMenuId %d\n", executedMenuId);
/* End the loop if executedMenuId is an item ID */
/* or if the job was done (executedMenuId = 0). */
if (hmenu)
fEndMenu |= !MenuMouseMove( &mt, hmenu, wFlags );
- break;
} /* switch(msg.message) - mouse */
}
{
if (MenuGetRosMenuInfo(&MenuInfo, mt.TopMenu))
{
- MenuHideSubPopups(mt.OwnerWnd, &MenuInfo, FALSE);
+ MenuHideSubPopups(mt.OwnerWnd, &MenuInfo, FALSE, wFlags);
if (MenuInfo.Flags & MF_POPUP)
{
+ IntNotifyWinEvent(EVENT_SYSTEM_MENUPOPUPEND, MenuInfo.Wnd, OBJID_CLIENT, CHILDID_SELF, 0);
DestroyWindow(MenuInfo.Wnd);
MenuInfo.Wnd = NULL;
static BOOL FASTCALL MenuInitTracking(HWND hWnd, HMENU hMenu, BOOL bPopup, UINT wFlags)
{
ROSMENUINFO MenuInfo;
-
+
TRACE("hwnd=%p hmenu=%p\n", hWnd, hMenu);
HideCaret(0);
+ /* This makes the menus of applications built with Delphi work.
+ * It also enables menus to be displayed in more than one window,
+ * but there are some bugs left that need to be fixed in this case.
+ */
+ if (MenuGetRosMenuInfo(&MenuInfo, hMenu))
+ {
+ MenuInfo.Wnd = hWnd;
+ MenuSetRosMenuInfo(&MenuInfo);
+ }
+
/* Send WM_ENTERMENULOOP and WM_INITMENU message only if TPM_NONOTIFY flag is not specified */
if (!(wFlags & TPM_NONOTIFY))
SendMessageW( hWnd, WM_ENTERMENULOOP, bPopup, 0 );
if (!(wFlags & TPM_NONOTIFY))
{
SendMessageW( hWnd, WM_INITMENU, (WPARAM)hMenu, 0 );
+ /* If an app changed/recreated menu bar entries in WM_INITMENU
+ * menu sizes will be recalculated once the menu created/shown.
+ */
- MenuGetRosMenuInfo(&MenuInfo, hMenu);
-
- if (!MenuInfo.Height)
- {
- /* app changed/recreated menu bar entries in WM_INITMENU
- Recalculate menu sizes else clicks will not work */
- SetWindowPos(hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
+ if (!MenuInfo.Height)
+ {
+ /* app changed/recreated menu bar entries in WM_INITMENU
+ Recalculate menu sizes else clicks will not work */
+ SetWindowPos(hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
- }
- /* This makes the menus of applications built with Delphi work.
- * It also enables menus to be displayed in more than one window,
- * but there are some bugs left that need to be fixed in this case.
- */
- if(MenuInfo.Self == hMenu)
- {
- MenuInfo.Wnd = hWnd;
- MenuSetRosMenuInfo(&MenuInfo);
- }
+ }
}
+ IntNotifyWinEvent( EVENT_SYSTEM_MENUSTART,
+ hWnd,
+ MenuInfo.Flags & MF_SYSMENU ? OBJID_SYSMENU : OBJID_MENU,
+ CHILDID_SELF, 0);
return TRUE;
}
/***********************************************************************
* MenuExitTracking
*/
-static BOOL FASTCALL MenuExitTracking(HWND hWnd)
+static BOOL FASTCALL MenuExitTracking(HWND hWnd, BOOL bPopup)
{
TRACE("hwnd=%p\n", hWnd);
- SendMessageW( hWnd, WM_EXITMENULOOP, 0, 0 );
+ IntNotifyWinEvent( EVENT_SYSTEM_MENUEND, hWnd, OBJID_WINDOW, CHILDID_SELF, 0);
+ SendMessageW( hWnd, WM_EXITMENULOOP, bPopup, 0 );
ShowCaret(0);
top_popup = 0;
+ top_popup_hmenu = NULL;
return TRUE;
}
VOID MenuTrackMouseMenuBar( HWND hWnd, ULONG ht, POINT pt)
{
HMENU hMenu = (ht == HTSYSMENU) ? NtUserGetSystemMenu( hWnd, FALSE) : GetMenu(hWnd);
- UINT wFlags = TPM_ENTERIDLEEX | TPM_BUTTONDOWN | TPM_LEFTALIGN | TPM_LEFTBUTTON;
+ UINT wFlags = TPM_BUTTONDOWN | TPM_LEFTALIGN | TPM_LEFTBUTTON;
TRACE("wnd=%p ht=0x%04x (%ld,%ld)\n", hWnd, ht, pt.x, pt.y);
MenuInitTracking(hWnd, hMenu, FALSE, wFlags);
MenuTrackMenu(hMenu, wFlags, pt.x, pt.y, hWnd, NULL);
- MenuExitTracking(hWnd);
+ MenuExitTracking(hWnd, FALSE);
}
}
UINT uItem = NO_SELECTED_ITEM;
HMENU hTrackMenu;
ROSMENUINFO MenuInfo;
- UINT wFlags = TPM_ENTERIDLEEX | TPM_LEFTALIGN | TPM_LEFTBUTTON;
+ UINT wFlags = TPM_LEFTALIGN | TPM_LEFTBUTTON;
TRACE("hwnd %p wParam 0x%04x wChar 0x%04x\n", hwnd, wParam, wChar);
MenuSelectItem( hwnd, &MenuInfo, uItem, TRUE, 0 );
- if (wParam & HTSYSMENU)
- {
- /* prevent sysmenu activation for managed windows on Alt down/up */
-// if (GetPropA( hwnd, "__wine_x11_managed" ))
- wFlags |= TF_ENDMENU; /* schedule end of menu tracking */
- }
- else
+ if (!(wParam & HTSYSMENU) || wChar == ' ')
{
if( uItem == NO_SELECTED_ITEM )
MenuMoveSelection( hwnd, &MenuInfo, ITEM_NEXT );
else
- PostMessageW( hwnd, WM_KEYDOWN, VK_DOWN, 0L );
+ PostMessageW( hwnd, WM_KEYDOWN, VK_RETURN, 0 );
}
track_menu:
MenuTrackMenu( hTrackMenu, wFlags, 0, 0, hwnd, NULL );
- MenuExitTracking( hwnd );
+ MenuExitTracking( hwnd, FALSE );
}
*/
BOOL WINAPI 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);
-}
-
-/**********************************************************************
- * TrackPopupMenu (USER32.@)
- */
-BOOL WINAPI TrackPopupMenu( HMENU Menu, UINT Flags, int x, int y,
- int Reserved, HWND Wnd, CONST RECT *Rect)
{
BOOL ret = FALSE;
+ ROSMENUINFO MenuInfo;
if (!IsMenu(Menu))
{
return FALSE;
}
+ /* ReactOS Check */
+ if (!ValidateHwnd(Wnd))
+ {
+ return FALSE;
+ }
+
+ MenuGetRosMenuInfo(&MenuInfo, Menu);
+ if (IsWindow(MenuInfo.Wnd))
+ {
+ SetLastError( ERROR_POPUP_ALREADY_ACTIVE );
+ return FALSE;
+ }
+
MenuInitTracking(Wnd, Menu, TRUE, Flags);
/* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
SendMessageW(Wnd, WM_INITMENUPOPUP, (WPARAM) Menu, 0);
if (MenuShowPopup(Wnd, Menu, 0, Flags, x, y, 0, 0 ))
- ret = MenuTrackMenu(Menu, Flags | TPM_POPUPMENU, 0, 0, Wnd, Rect);
- MenuExitTracking(Wnd);
+ ret = MenuTrackMenu(Menu, Flags | TPM_POPUPMENU, 0, 0, Wnd,
+ Tpm ? &Tpm->rcExclude : NULL);
+ MenuExitTracking(Wnd, TRUE);
return ret;
}
+/**********************************************************************
+ * TrackPopupMenu (USER32.@)
+ */
+BOOL WINAPI TrackPopupMenu( HMENU Menu, UINT Flags, int x, int y,
+ int Reserved, HWND Wnd, CONST RECT *Rect)
+{
+ return TrackPopupMenuEx( Menu, Flags, x, y, Wnd, NULL);
+}
+
/*
* From MSDN:
* The MFT_BITMAP, MFT_SEPARATOR, and MFT_STRING values cannot be combined
{
mii->fType |= MFT_OWNERDRAW;
mii->fMask |= MIIM_DATA;
- mii->dwItemData = (DWORD) NewItem;
+ mii->dwItemData = (DWORD_PTR) NewItem;
}
else if (Flags & MF_SEPARATOR)
{
User32CallLoadMenuFromKernel(PVOID Arguments, ULONG ArgumentLength)
{
PLOADMENU_CALLBACK_ARGUMENTS Common;
- LRESULT Result;
+ LRESULT Result;
Common = (PLOADMENU_CALLBACK_ARGUMENTS) Arguments;
-
+
Result = (LRESULT)LoadMenuW( Common->hModule,
IS_INTRESOURCE(Common->MenuName[0]) ?
MAKEINTRESOURCE(Common->MenuName[0]) :
MenuGetRosMenuInfo(&MenuInfo, hMenu);
MenuInfo.Height = 0; // make sure to recalc size
MenuSetRosMenuInfo(&MenuInfo);
- /* The wine method doesn't work and I suspect it's more effort
- then hackfix solution
+
SetWindowPos( hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
SWP_NOZORDER | SWP_FRAMECHANGED );
- return TRUE;*/
- // FIXME: hackfix
- DefWndNCPaint(hWnd,(HRGN)-1,-1);
return TRUE;
}
-
/*
* @implemented
*/
guii.cbSize = sizeof(GUITHREADINFO);
if(GetGUIThreadInfo(GetCurrentThreadId(), &guii) && guii.hwndMenuOwner)
{
- PostMessageW(guii.hwndMenuOwner, WM_CANCELMODE, 0, 0);
+ if (!fEndMenu &&
+ top_popup &&
+ guii.hwndMenuOwner != top_popup )
+ {
+ ERR("Capture GUI pti hWnd does not match top_popup!\n");
+ }
+ }
+
+ /* if we are in the menu code, and it is active */
+ if (!fEndMenu && top_popup)
+ {
+ /* terminate the menu handling code */
+ fEndMenu = TRUE;
+
+ /* needs to be posted to wakeup the internal menu handler */
+ /* which will now terminate the menu, in the event that */
+ /* the main window was minimized, or lost focus, so we */
+ /* don't end up with an orphaned menu */
+ PostMessageW( top_popup, WM_CANCELMODE, 0, 0);
}
return TRUE;
}
if (!Wnd)
return NULL;
- return (HMENU)Wnd->IDMenu;
+ return UlongToHandle(Wnd->IDMenu);
}