#define MENU_COL_SPACE 4
/* top and bottom margins for popup menus */
-#define MENU_TOP_MARGIN 2 //3
+#define MENU_TOP_MARGIN 3
#define MENU_BOTTOM_MARGIN 2
#define MENU_ITEM_HBMP_SPACE (5)
{
PMENU SubMenu;
+ ASSERT(UserIsEnteredExclusive());
if (pMenu->rgItems) /* recursively destroy submenus */
{
int i;
BOOL FASTCALL
IntDestroyMenuObject(PMENU Menu, BOOL bRecurse)
{
+ ASSERT(UserIsEnteredExclusive());
if (Menu)
{
PWND Window;
ERR("MenuInit(): CreateFontIndirectW(hMenuFont) failed!\n");
return FALSE;
}
- ncm.lfMenuFont.lfWeight = max(ncm.lfMenuFont.lfWeight + 300, 1000);
+ ncm.lfMenuFont.lfWeight = min(ncm.lfMenuFont.lfWeight + (FW_BOLD - FW_NORMAL), FW_HEAVY);
ghMenuFontBold = GreCreateFontIndirectW(&ncm.lfMenuFont);
if (ghMenuFontBold == NULL)
{
drawItem.itemData = lpitem->dwItemData;
/* some applications make this assumption on the DC's origin */
GreSetViewportOrgEx( hdc, lpitem->xItem, lpitem->yItem, &origorg);
- RECTL_vOffsetRect( &drawItem.rcItem, - lpitem->xItem, - lpitem->yItem);
+ RECTL_vOffsetRect(&drawItem.rcItem, -(LONG)lpitem->xItem, -(LONG)lpitem->yItem);
co_IntSendMessage( UserHMGetHandle(WndOwner), WM_DRAWITEM, 0, (LPARAM)&drawItem);
GreSetViewportOrgEx( hdc, origorg.x, origorg.y, NULL);
return;
rop=((lpitem->fState & MF_HILITE) && !IS_MAGIC_BITMAP(hbmToDraw)) ? NOTSRCCOPY : SRCCOPY;
if ((lpitem->fState & MF_HILITE) && lpitem->hbmp)
IntGdiSetBkColor(hdc, IntGetSysColor(COLOR_HIGHLIGHT));
- if (!flat_menu &&
+ if (MenuBar &&
+ !flat_menu &&
(lpitem->fState & (MF_HILITE | MF_GRAYED)) == MF_HILITE)
{
++left;
*/
static void MENU_DrawScrollArrows(PMENU lppop, HDC hdc)
{
- UINT arrow_bitmap_width, arrow_bitmap_height;
- RECT rect, dfcrc;
+ UINT arrow_bitmap_height;
+ RECT rect;
UINT Flags = 0;
- arrow_bitmap_width = gpsi->oembmi[OBI_DNARROW].cx;
arrow_bitmap_height = gpsi->oembmi[OBI_DNARROW].cy;
rect.left = 0;
rect.right = lppop->cxMenu;
rect.bottom = arrow_bitmap_height;
FillRect(hdc, &rect, IntGetSysColorBrush(COLOR_MENU));
- dfcrc.left = (lppop->cxMenu - arrow_bitmap_width) / 2;
- dfcrc.top = 0;
- dfcrc.right = arrow_bitmap_width;
- dfcrc.bottom = arrow_bitmap_height;
- DrawFrameControl(hdc, &dfcrc, DFC_MENU, (lppop->iTop ? 0 : DFCS_INACTIVE)|DFCS_MENUARROWUP);
+ DrawFrameControl(hdc, &rect, DFC_MENU, (lppop->iTop ? 0 : DFCS_INACTIVE)|DFCS_MENUARROWUP);
rect.top = lppop->cyMenu - arrow_bitmap_height;
rect.bottom = lppop->cyMenu;
FillRect(hdc, &rect, IntGetSysColorBrush(COLOR_MENU));
if (!(lppop->iTop < lppop->iMaxTop - (MENU_GetMaxPopupHeight(lppop) - 2 * arrow_bitmap_height)))
Flags = DFCS_INACTIVE;
- dfcrc.left = (lppop->cxMenu - arrow_bitmap_width) / 2;
- dfcrc.top = lppop->cyMenu - arrow_bitmap_height;
- dfcrc.right = arrow_bitmap_width;
- dfcrc.bottom = lppop->cyMenu;
- DrawFrameControl(hdc, &dfcrc, DFC_MENU, Flags|DFCS_MENUARROWDOWN);
+ DrawFrameControl(hdc, &rect, DFC_MENU, Flags|DFCS_MENUARROWDOWN);
}
/***********************************************************************
rc.left++;
rc.right--;
- rc.top = ( rc.top + rc.bottom) / 2;
+ rc.top = (rc.top + rc.bottom) / 2 - 1;
if (flat_menu)
{
oldPen = NtGdiSelectPen( hdc, NtGdiGetStockObject(DC_PEN) );
break;
}
- if (!flat_menu &&
+ if (menuBar &&
+ !flat_menu &&
(lpitem->fState & (MF_HILITE | MF_GRAYED)) == MF_HILITE)
{
RECTL_vOffsetRect(&rect, +1, +1);
}
+ if (!menuBar)
+ --rect.bottom;
+
if(lpitem->fState & MF_GRAYED)
{
if (!(lpitem->fState & MF_HILITE) )
DrawTextW( hdc, Text + i + 1, -1, &rect, uFormat );
}
- if (!flat_menu &&
+ if (!menuBar)
+ ++rect.bottom;
+
+ if (menuBar &&
+ !flat_menu &&
(lpitem->fState & (MF_HILITE | MF_GRAYED)) == MF_HILITE)
{
RECTL_vOffsetRect(&rect, -1, -1);
return TRUE;
}
+
+#define SHOW_DEBUGRECT 0
+
+#if SHOW_DEBUGRECT
+static void DebugRect(const RECT* rectl, COLORREF color)
+{
+ HBRUSH brush;
+ RECT rr;
+ HDC hdc;
+
+ if (!rectl)
+ return;
+
+ hdc = UserGetDCEx(NULL, 0, DCX_USESTYLE);
+
+ brush = IntGdiCreateSolidBrush(color);
+
+ rr = *rectl;
+ RECTL_vInflateRect(&rr, 1, 1);
+ FrameRect(hdc, rectl, brush);
+ FrameRect(hdc, &rr, brush);
+
+ NtGdiDeleteObjectApp(brush);
+ UserReleaseDC(NULL, hdc, TRUE);
+}
+
+static void DebugPoint(INT x, INT y, COLORREF color)
+{
+ RECT rr = {x, y, x, y};
+ DebugRect(&rr, color);
+}
+#endif
+
+static BOOL RECTL_Intersect(const RECT* pRect, INT x, INT y, UINT width, UINT height)
+{
+ RECT other = {x, y, x + width, y + height};
+ RECT dum;
+
+ return RECTL_bIntersectRect(&dum, pRect, &other);
+}
+
+static BOOL MENU_MoveRect(UINT flags, INT* x, INT* y, INT width, INT height, const RECT* pExclude, PMONITOR monitor)
+{
+ /* Figure out if we should move vertical or horizontal */
+ if (flags & TPM_VERTICAL)
+ {
+ /* Move in the vertical direction: TPM_BOTTOMALIGN means drop it above, otherways drop it below */
+ if (flags & TPM_BOTTOMALIGN)
+ {
+ if (pExclude->top - height >= monitor->rcMonitor.top)
+ {
+ *y = pExclude->top - height;
+ return TRUE;
+ }
+ }
+ else
+ {
+ if (pExclude->bottom + height < monitor->rcMonitor.bottom)
+ {
+ *y = pExclude->bottom;
+ return TRUE;
+ }
+ }
+ }
+ else
+ {
+ /* Move in the horizontal direction: TPM_RIGHTALIGN means drop it to the left, otherways go right */
+ if (flags & TPM_RIGHTALIGN)
+ {
+ if (pExclude->left - width >= monitor->rcMonitor.left)
+ {
+ *x = pExclude->left - width;
+ return TRUE;
+ }
+ }
+ else
+ {
+ if (pExclude->right + width < monitor->rcMonitor.right)
+ {
+ *x = pExclude->right;
+ return TRUE;
+ }
+ }
+ }
+ return FALSE;
+}
+
/***********************************************************************
* MenuShowPopup
*
* Display a popup menu.
*/
static BOOL FASTCALL MENU_ShowPopup(PWND pwndOwner, PMENU menu, UINT id, UINT flags,
- INT x, INT y, INT xanchor, INT yanchor )
+ INT x, INT y, const RECT* pExclude)
{
UINT width, height;
- POINT pt;
+ POINT ptx;
PMONITOR monitor;
PWND pWnd;
USER_REFERENCE_ENTRY Ref;
+ BOOL bIsPopup = (flags & TPM_POPUPMENU) != 0;
- TRACE("owner=%p menu=%p id=0x%04x x=0x%04x y=0x%04x xa=0x%04x ya=0x%04x\n",
- pwndOwner, menu, id, x, y, xanchor, yanchor);
+ TRACE("owner=%p menu=%p id=0x%04x x=0x%04x y=0x%04x\n",
+ pwndOwner, menu, id, x, y);
if (menu->iItem != NO_SELECTED_ITEM)
{
menu->iItem = NO_SELECTED_ITEM;
}
+#if SHOW_DEBUGRECT
+ if (pExclude)
+ DebugRect(pExclude, RGB(255, 0, 0));
+#endif
+
menu->dwArrowsOn = 0;
MENU_PopupMenuCalcSize(menu, pwndOwner);
width = menu->cxMenu + UserGetSystemMetrics(SM_CXBORDER);
height = menu->cyMenu + UserGetSystemMetrics(SM_CYBORDER);
- /* FIXME: should use item rect */
- pt.x = x;
- pt.y = y;
- monitor = UserMonitorFromPoint( pt, MONITOR_DEFAULTTONEAREST );
-
- if (flags & TPM_LAYOUTRTL)
+ if (flags & TPM_LAYOUTRTL)
flags ^= TPM_RIGHTALIGN;
- if( flags & TPM_RIGHTALIGN ) x -= width;
- if( flags & TPM_CENTERALIGN ) x -= width / 2;
+ if (flags & TPM_RIGHTALIGN)
+ x -= width;
+ if (flags & TPM_CENTERALIGN)
+ x -= width / 2;
- if( flags & TPM_BOTTOMALIGN ) y -= height;
- if( flags & TPM_VCENTERALIGN ) y -= height / 2;
+ if (flags & TPM_BOTTOMALIGN)
+ y -= height;
+ if (flags & TPM_VCENTERALIGN)
+ y -= height / 2;
- if( x + width > monitor->rcMonitor.right)
- {
- if( xanchor && x >= width - xanchor )
- x -= width - xanchor;
+ /* FIXME: should use item rect */
+ ptx.x = x;
+ ptx.y = y;
+#if SHOW_DEBUGRECT
+ DebugPoint(x, y, RGB(0, 0, 255));
+#endif
+ monitor = UserMonitorFromPoint( ptx, MONITOR_DEFAULTTONEAREST );
- if( x + width > monitor->rcMonitor.right)
+ /* We are off the right side of the screen */
+ if (x + width > monitor->rcMonitor.right)
+ {
+ if ((x - width) < monitor->rcMonitor.left || x >= monitor->rcMonitor.right)
x = monitor->rcMonitor.right - width;
+ else
+ x -= width;
+ }
+
+ /* We are off the left side of the screen */
+ if (x < monitor->rcMonitor.left)
+ {
+ /* Re-orient the menu around the x-axis */
+ x += width;
+
+ if (x < monitor->rcMonitor.left || x >= monitor->rcMonitor.right || bIsPopup)
+ x = monitor->rcMonitor.left;
}
- if( x < monitor->rcMonitor.left ) x = monitor->rcMonitor.left;
- if( y + height > monitor->rcMonitor.bottom)
+ /* Same here, but then the top */
+ if (y < monitor->rcMonitor.top)
{
- if( yanchor && y >= height + yanchor )
- y -= height + yanchor;
+ y += height;
- if( y + height > monitor->rcMonitor.bottom)
+ if (y < monitor->rcMonitor.top || y >= monitor->rcMonitor.bottom || bIsPopup)
+ y = monitor->rcMonitor.top;
+ }
+
+ /* And the bottom */
+ if (y + height > monitor->rcMonitor.bottom)
+ {
+ if ((y - height) < monitor->rcMonitor.top || y >= monitor->rcMonitor.bottom || bIsPopup)
y = monitor->rcMonitor.bottom - height;
+ else
+ y -= height;
}
- if( y < monitor->rcMonitor.top ) y = monitor->rcMonitor.top;
+
+ if (pExclude)
+ {
+ RECT Cleaned;
+
+ if (RECTL_bIntersectRect(&Cleaned, pExclude, &monitor->rcMonitor) &&
+ RECTL_Intersect(&Cleaned, x, y, width, height))
+ {
+ UINT flag_mods[] = {
+ 0, /* First try the 'normal' way */
+ TPM_BOTTOMALIGN | TPM_RIGHTALIGN, /* Then try the opposite side */
+ TPM_VERTICAL, /* Then swap horizontal / vertical */
+ TPM_BOTTOMALIGN | TPM_RIGHTALIGN | TPM_VERTICAL, /* Then the other side again (still swapped hor/ver) */
+ };
+ UINT n;
+ for (n = 0; n < RTL_NUMBER_OF(flag_mods); ++n)
+ {
+ INT tx = x;
+ INT ty = y;
+
+ /* Try to move a bit around */
+ if (MENU_MoveRect(flags ^ flag_mods[n], &tx, &ty, width, height, &Cleaned, monitor) &&
+ !RECTL_Intersect(&Cleaned, tx, ty, width, height))
+ {
+ x = tx;
+ y = ty;
+ break;
+ }
+ }
+ /* If none worked, we go with the original x/y */
+ }
+ }
+
+#if SHOW_DEBUGRECT
+ {
+ RECT rr = {x, y, x + width, y + height};
+ DebugRect(&rr, RGB(0, 255, 0));
+ }
+#endif
pWnd = ValidateHwndNoErr( menu->hWnd );
*/
static PMENU FASTCALL MENU_ShowSubPopup(PWND WndOwner, PMENU Menu, BOOL SelectFirst, UINT Flags)
{
- RECT Rect;
+ RECT Rect, ParentRect;
ITEM *Item;
HDC Dc;
PWND pWnd;
pWnd = ValidateHwndNoErr(Menu->hWnd);
+ /* Grab the rect of our (entire) parent menu, so we can try to not overlap it */
+ if (Menu->fFlags & MNF_POPUP)
+ {
+ if (!IntGetWindowRect(pWnd, &ParentRect))
+ {
+ ERR("No pWnd\n");
+ ParentRect = Rect;
+ }
+ }
+ else
+ {
+ /* Inside the menu bar, we do not want to grab the entire window... */
+ ParentRect = Rect;
+ if (pWnd)
+ RECTL_vOffsetRect(&ParentRect, pWnd->rcWindow.left, pWnd->rcWindow.top);
+ }
+
/* correct item if modified as a reaction to WM_INITMENUPOPUP message */
if (!(Item->fState & MF_HILITE))
{
MENU_InitPopup( WndOwner, Item->spSubMenu, Flags );
MENU_ShowPopup( WndOwner, Item->spSubMenu, Menu->iItem, Flags,
- Rect.left, Rect.top, Rect.right, Rect.bottom );
+ Rect.left, Rect.top, &ParentRect);
if (SelectFirst)
{
MENU_MoveSelection(WndOwner, Item->spSubMenu, ITEM_NEXT);
* Menu tracking code.
*/
static INT FASTCALL MENU_TrackMenu(PMENU pmenu, UINT wFlags, INT x, INT y,
- PWND pwnd, const RECT *lprect )
+ PWND pwnd)
{
MSG msg;
BOOL fRemove;
mt.Pt.x = x;
mt.Pt.y = y;
- TRACE("MTM : hmenu=%p flags=0x%08x (%d,%d) hwnd=%x (%ld,%ld)-(%ld,%ld)\n",
- UserHMGetHandle(pmenu), wFlags, x, y, UserHMGetHandle(pwnd), lprect ? lprect->left : 0, lprect ? lprect->top : 0,
- lprect ? lprect->right : 0, lprect ? lprect->bottom : 0);
+ TRACE("MTM : hmenu=%p flags=0x%08x (%d,%d) hwnd=%x\n",
+ UserHMGetHandle(pmenu), wFlags, x, y, UserHMGetHandle(pwnd));
pti->MessageQueue->QF_flags &= ~QF_ACTIVATIONCHANGE;
MENU_InitTracking(pWnd, pMenu, FALSE, wFlags);
/* fetch the window menu again, it may have changed */
pMenu = (ht == HTSYSMENU) ? get_win_sys_menu( UserHMGetHandle(pWnd) ) : IntGetMenu( UserHMGetHandle(pWnd) );
- MENU_TrackMenu(pMenu, wFlags, pt.x, pt.y, pWnd, NULL);
+ MENU_TrackMenu(pMenu, wFlags, pt.x, pt.y, pWnd);
MENU_ExitTracking(pWnd, FALSE, wFlags);
}
}
}
track_menu:
- MENU_TrackMenu( TrackMenu, wFlags, 0, 0, pwnd, NULL );
+ MENU_TrackMenu( TrackMenu, wFlags, 0, 0, pwnd );
MENU_ExitTracking( pwnd, FALSE, wFlags);
}
if (menu->fFlags & MNF_SYSMENU)
MENU_InitSysMenuPopup( menu, pWnd->style, pWnd->pcls->style, HTSYSMENU);
- if (MENU_ShowPopup(pWnd, menu, 0, wFlags, x, y, 0, 0 ))
- ret = MENU_TrackMenu( menu, wFlags | TPM_POPUPMENU, 0, 0, pWnd,
- lpTpm ? &lpTpm->rcExclude : NULL);
+ if (MENU_ShowPopup(pWnd, menu, 0, wFlags | TPM_POPUPMENU, x, y, lpTpm ? &lpTpm->rcExclude : NULL))
+ ret = MENU_TrackMenu( menu, wFlags | TPM_POPUPMENU, 0, 0, pWnd);
else
{
MsqSetStateWindow(pti, MSQ_STATE_MENUOWNER, NULL);
{
CREATESTRUCTW *cs = (CREATESTRUCTW *) lParam;
pPopupMenu->spmenu = UserGetMenuObject(cs->lpCreateParams);
+ if (pPopupMenu->spmenu)
+ {
+ UserReferenceObject(pPopupMenu->spmenu);
+ }
break;
}
case WM_NCDESTROY:
{
+ if (pPopupMenu->spmenu)
+ {
+ IntReleaseMenuObject(pPopupMenu->spmenu);
+ }
DesktopHeapFree(Wnd->head.rpdesk, pPopupMenu );
((PMENUWND)Wnd)->ppopupmenu = 0;
Wnd->fnid = FNID_DESTROY;
ERR("Bad Menu Handle\n");
break;
}
+ UserReferenceObject(pmenu);
+ if (pPopupMenu->spmenu)
+ {
+ IntReleaseMenuObject(pPopupMenu->spmenu);
+ }
pPopupMenu->spmenu = pmenu;
break;
}
DECLARE_RETURN(HMENU);
TRACE("Enter NtUserGetSystemMenu\n");
- UserEnterShared();
+ UserEnterExclusive();
if (!(Window = UserGetWindowObject(hWnd)))
{