diff --git a/reactos/ChangeLog b/reactos/ChangeLog index b82d408a3db..16a39332003 100644 --- a/reactos/ChangeLog +++ b/reactos/ChangeLog @@ -1,6 +1,7 @@ 2004-02-22 Ge van Geldorp * Implement keyboard navigation for menus + * Implement system menus 2004-02-22 Casper S. Hornstrup diff --git a/reactos/lib/user32/user32.rc b/reactos/lib/user32/user32.rc index 1ec2aa8ab4b..35b36cfd4ad 100644 --- a/reactos/lib/user32/user32.rc +++ b/reactos/lib/user32/user32.rc @@ -119,20 +119,13 @@ EDITMENU MENU LOADONCALL MOVEABLE DISCARDABLE SYSMENU MENU LOADONCALL MOVEABLE DISCARDABLE { - POPUP "" - { - MENUITEM "&Restore", 61728 - MENUITEM "&Move", 61456 - MENUITEM "&Size", 61440 - MENUITEM "Mi&nimize", 61472 - MENUITEM "Ma&ximize", 61488 - MENUITEM SEPARATOR - MENUITEM "&Close\tAlt-F4", 61536 - //MENUITEM SEPARATOR - //MENUITEM "&Switch to ...\tCtrl-Esc", 61744 - //MENUITEM SEPARATOR - //MENUITEM "&About ReactOS ...", 61761 - } + MENUITEM "&Restore", 61728 + MENUITEM "&Move", 61456 + MENUITEM "&Size", 61440 + MENUITEM "Mi&nimize", 61472 + MENUITEM "Ma&ximize", 61488 + MENUITEM SEPARATOR + MENUITEM "&Close\tAlt-F4", 61536 } ///////////////////////////////////////////////////////////////////////////// diff --git a/reactos/lib/user32/windows/defwnd.c b/reactos/lib/user32/windows/defwnd.c index 6927255d0a6..035fabbba3c 100644 --- a/reactos/lib/user32/windows/defwnd.c +++ b/reactos/lib/user32/windows/defwnd.c @@ -1,4 +1,4 @@ -/* $Id: defwnd.c,v 1.123 2004/01/26 08:44:51 weiden Exp $ +/* $Id: defwnd.c,v 1.124 2004/02/22 23:40:58 gvg Exp $ * * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS user32.dll @@ -817,7 +817,7 @@ DefWndHandleSysCommand(HWND hWnd, WPARAM wParam, POINT Pt) SendMessageA(hWnd, WM_CLOSE, 0, 0); break; case SC_MOUSEMENU: - MenuTrackMouseMenuBar(hWnd, wParam, Pt); + MenuTrackMouseMenuBar(hWnd, wParam & 0x000f, Pt); break; case SC_KEYMENU: MenuTrackKbdMenuBar(hWnd, wParam, Pt.x); diff --git a/reactos/lib/user32/windows/menu.c b/reactos/lib/user32/windows/menu.c index 9af3f8e64de..bd69c6ada5a 100644 --- a/reactos/lib/user32/windows/menu.c +++ b/reactos/lib/user32/windows/menu.c @@ -21,7 +21,7 @@ * 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.49 2004/02/22 18:04:52 gvg Exp $ +/* $Id: menu.c,v 1.50 2004/02/22 23:40:58 gvg Exp $ * * PROJECT: ReactOS user32.dll * FILE: lib/user32/windows/menu.c @@ -1928,6 +1928,35 @@ MenuMoveSelection(HWND WndOwner, PROSMENUINFO MenuInfo, INT Offset) MenuCleanupRosMenuItemInfo(&ItemInfo); } +/*********************************************************************** + * MenuInitSysMenuPopup + * + * Grey the appropriate items in System menu. + */ +static void FASTCALL +MenuInitSysMenuPopup(HMENU Menu, DWORD Style, DWORD ClsStyle ) +{ + BOOL Gray; + + 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) + { + EnableMenuItem(Menu, SC_CLOSE, MF_GRAYED); + } +} + /*********************************************************************** * MenuShowSubPopup * @@ -1937,6 +1966,7 @@ MenuMoveSelection(HWND WndOwner, PROSMENUINFO MenuInfo, INT Offset) 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; @@ -2012,16 +2042,14 @@ MenuShowSubPopup(HWND WndOwner, PROSMENUINFO MenuInfo, BOOL SelectFirst, UINT Fl if (IS_SYSTEM_MENU(MenuInfo)) { -#if 0 /* FIXME */ - MENU_InitSysMenuPopup(item->hSubMenu, - GetWindowLongW( menu->hWnd, GWL_STYLE ), - GetClassLongW( menu->hWnd, GCL_STYLE)); + MenuInitSysMenuPopup(ItemInfo.hSubMenu, + GetWindowLongW(MenuInfo->Wnd, GWL_STYLE ), + GetClassLongW(MenuInfo->Wnd, GCL_STYLE)); - NC_GetSysPopupPos( menu->hWnd, &rect ); - rect.top = rect.bottom; - rect.right = GetSystemMetrics(SM_CXSIZE); - rect.bottom = GetSystemMetrics(SM_CYSIZE); -#endif + NcGetSysPopupPos(MenuInfo->Wnd, &Rect); + Rect.top = Rect.bottom; + Rect.right = GetSystemMetrics(SM_CXSIZE); + Rect.bottom = GetSystemMetrics(SM_CYSIZE); } else { @@ -2345,11 +2373,7 @@ MenuPtMenu(HMENU Menu, POINT Pt) } else if (HTSYSMENU == Ht) { -#if 0 /* FIXME */ - Ret = get_win_sys_menu( menu->hWnd ); -#else - Ret = NULL; -#endif + Ret = NtUserGetSystemMenu(MenuInfo.Wnd, FALSE); } else if (HTMENU == Ht) { @@ -2529,7 +2553,6 @@ MenuGetSubPopup(HMENU Menu) static LRESULT FASTCALL MenuDoNextMenu(MTRACKER* Mt, UINT Vk) { -#if 0 /* FIXME */ ROSMENUINFO TopMenuInfo; ROSMENUINFO MenuInfo; @@ -2579,10 +2602,8 @@ MenuDoNextMenu(MTRACKER* Mt, UINT Vk) } else if (0 != (Style & WS_SYSMENU)) { -#if 0 /* FIXME */ /* switch to the system menu */ - NewMenu = get_win_sys_menu(NewWnd); -#endif + NewMenu = NtUserGetSystemMenu(NewWnd, FALSE); } else { @@ -2598,17 +2619,13 @@ MenuDoNextMenu(MTRACKER* Mt, UINT Vk) { DWORD Style = GetWindowLongW(NewWnd, GWL_STYLE); -#if 0 /* FIXME */ if (0 != (Style & WS_SYSMENU) - && GetSubMenu(get_win_sys_menu(NewWnd), 0) == NewMenu) + && GetSystemMenu(NewWnd, FALSE) == NewMenu) { /* get the real system menu */ - NewMenu = get_win_sys_menu(NewWnd); + NewMenu = NtUserGetSystemMenu(NewWnd, FALSE); } else if (0 != (Style & WS_CHILD) || GetMenu(NewWnd) != NewMenu) -#else - if (0 != (Style & WS_CHILD) || GetMenu(NewWnd) != NewMenu) -#endif { /* FIXME: Not sure what to do here; * perhaps try to track NewMenu as a popup? */ @@ -2647,7 +2664,6 @@ MenuDoNextMenu(MTRACKER* Mt, UINT Vk) return TRUE; } -#endif return FALSE; } @@ -2894,15 +2910,24 @@ 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 0 /* FIXME */ - if (! IsMenu( hmenu )) hmenu = GetSubMenu( get_win_sys_menu(hwndOwner), 0); -#endif + if (NULL == MenuInfo || ! IsMenu(MenuInfo->Self)) + { + if (MenuGetRosMenuInfo(&SysMenuInfo, GetSystemMenu(WndOwner, FALSE))) + { + MenuInfo = &SysMenuInfo; + } + else + { + MenuInfo = NULL; + } + } if (NULL != MenuInfo) { @@ -3328,19 +3353,8 @@ MenuExitTracking(HWND Wnd) VOID MenuTrackMouseMenuBar(HWND Wnd, ULONG Ht, POINT Pt) { -#if 0 /* FIXME */ - HMENU Menu = (ht == HTSYSMENU) ? get_win_sys_menu( Wnd ) : GetMenu( Wnd ); + HMENU Menu = (HTSYSMENU == Ht) ? NtUserGetSystemMenu(Wnd, FALSE) : GetMenu(Wnd); UINT Flags = TPM_ENTERIDLEEX | TPM_BUTTONDOWN | TPM_LEFTALIGN | TPM_LEFTBUTTON; -#else - HMENU Menu; - UINT Flags = TPM_ENTERIDLEEX | TPM_BUTTONDOWN | TPM_LEFTALIGN | TPM_LEFTBUTTON; - - if (HTSYSMENU == Ht) - { - return; - } - Menu = GetMenu(Wnd); -#endif DPRINT("wnd=%p ht=0x%04x (%ld,%ld)\n", Wnd, Ht, pt.x, pt.y); @@ -3760,10 +3774,26 @@ GetSubMenu( if (NtUserMenuItemInfo(hMenu, (UINT)nPos, MF_BYPOSITION, &mi, FALSE)) { - return mi.hSubMenu; + return IsMenu(mi.hSubMenu) ? mi.hSubMenu : NULL; } - return (HMENU)0; + return NULL; +} + +/* + * @implemented + */ +HMENU +STDCALL +GetSystemMenu( + HWND hWnd, + BOOL bRevert) +{ + HMENU TopMenu; + + TopMenu = NtUserGetSystemMenu(hWnd, bRevert); + + return NULL == TopMenu ? NULL : GetSubMenu(TopMenu, 0); } @@ -4259,6 +4289,28 @@ SetMenuItemInfoW( return FALSE; } +/* + * @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 diff --git a/reactos/lib/user32/windows/nonclient.c b/reactos/lib/user32/windows/nonclient.c index 842ae1597b9..b9c90b6f9b6 100644 --- a/reactos/lib/user32/windows/nonclient.c +++ b/reactos/lib/user32/windows/nonclient.c @@ -1321,3 +1321,85 @@ DrawCaptionTempA( UNIMPLEMENTED; return FALSE; } + +/*********************************************************************** + * NcGetInsideRect + * + * Get the 'inside' rectangle of a window, i.e. the whole window rectangle + * but without the borders (if any). + * The rectangle is in window coordinates (for drawing with GetWindowDC()). + */ +static void FASTCALL +NcGetInsideRect(HWND Wnd, RECT *Rect) +{ + DWORD Style; + DWORD ExStyle; + + GetWindowRect(Wnd, Rect); + Rect->right = Rect->right - Rect->left; + Rect->left = 0; + Rect->bottom = Rect->bottom - Rect->top; + Rect->top = 0; + + Style = GetWindowLongW(Wnd, GWL_STYLE); + if (0 != (Style & WS_ICONIC)) + { + return; + } + + /* Remove frame from rectangle */ + ExStyle = GetWindowLongW(Wnd, GWL_EXSTYLE); + if (HAS_THICKFRAME(Style, ExStyle)) + { + InflateRect(Rect, - GetSystemMetrics(SM_CXFRAME), - GetSystemMetrics(SM_CYFRAME)); + } + else if (HAS_DLGFRAME(Style, ExStyle)) + { + InflateRect(Rect, - GetSystemMetrics(SM_CXDLGFRAME), - GetSystemMetrics(SM_CYDLGFRAME)); + } + else if (HAS_THINFRAME(Style, ExStyle)) + { + InflateRect(Rect, - GetSystemMetrics(SM_CXBORDER), - GetSystemMetrics(SM_CYBORDER)); + } + + /* We have additional border information if the window + * is a child (but not an MDI child) */ + if (0 != (Style & WS_CHILD) + && 0 == (ExStyle & WS_EX_MDICHILD)) + { + if (0 != (ExStyle & WS_EX_CLIENTEDGE)) + { + InflateRect(Rect, - GetSystemMetrics(SM_CXEDGE), - GetSystemMetrics(SM_CYEDGE)); + } + if (0 != (ExStyle & WS_EX_STATICEDGE)) + { + InflateRect(Rect, - GetSystemMetrics(SM_CXBORDER), - GetSystemMetrics(SM_CYBORDER)); + } + } +} + +/*********************************************************************** + * NcGetSysPopupPos + */ +void FASTCALL +NcGetSysPopupPos(HWND Wnd, RECT *Rect) +{ + RECT WindowRect; + + if (IsIconic(Wnd)) + { + GetWindowRect(Wnd, Rect); + } + else + { + NcGetInsideRect(Wnd, Rect); + GetWindowRect(Wnd, &WindowRect); + OffsetRect(Rect, WindowRect.left, WindowRect.top); + if (0 != (GetWindowLongW(Wnd, GWL_STYLE) & WS_CHILD)) + { + ClientToScreen(GetParent(Wnd), (POINT *) Rect); + } + Rect->right = Rect->left + GetSystemMetrics(SM_CYCAPTION) - 1; + Rect->bottom = Rect->top + GetSystemMetrics(SM_CYCAPTION) - 1; + } +} diff --git a/reactos/lib/user32/windows/window.c b/reactos/lib/user32/windows/window.c index 953322c341b..18bb95fb406 100644 --- a/reactos/lib/user32/windows/window.c +++ b/reactos/lib/user32/windows/window.c @@ -1,4 +1,4 @@ -/* $Id: window.c,v 1.98 2004/02/02 11:46:41 ea Exp $ +/* $Id: window.c,v 1.99 2004/02/22 23:40:58 gvg Exp $ * * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS user32.dll @@ -1462,45 +1462,6 @@ SetLastErrorEx(DWORD dwErrCode, DWORD dwType) SetLastError(dwErrCode); } -/* - * @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 - */ -HMENU -STDCALL -GetSystemMenu( - HWND hWnd, - BOOL bRevert) -{ - if(!hWnd) - { - SetLastError(ERROR_INVALID_WINDOW_HANDLE); - return (HMENU)0; - } - return NtUserGetSystemMenu(hWnd, bRevert); -} - /* * @implemented */ diff --git a/reactos/subsys/win32k/include/menu.h b/reactos/subsys/win32k/include/menu.h index 83ce0984df6..cc54ecff07a 100644 --- a/reactos/subsys/win32k/include/menu.h +++ b/reactos/subsys/win32k/include/menu.h @@ -101,6 +101,9 @@ IntSetMenuItemRect(PMENU_OBJECT MenuObject, UINT Item, BOOL fByPos, RECT *rcRect BOOL FASTCALL IntCleanupMenus(struct _EPROCESS *Process, PW32PROCESS Win32Process); +BOOL FASTCALL +IntInsertMenuItem(PMENU_OBJECT MenuObject, UINT uItem, BOOL fByPosition, + PROSMENUITEMINFO ItemInfo); NTSTATUS FASTCALL diff --git a/reactos/subsys/win32k/ntuser/menu.c b/reactos/subsys/win32k/ntuser/menu.c index ffddad0ac5e..dddff914113 100644 --- a/reactos/subsys/win32k/ntuser/menu.c +++ b/reactos/subsys/win32k/ntuser/menu.c @@ -16,7 +16,7 @@ * 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.47 2004/02/22 18:04:52 gvg Exp $ +/* $Id: menu.c,v 1.48 2004/02/22 23:40:58 gvg Exp $ * * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel @@ -763,8 +763,8 @@ IntSetMenuItemInfo(PMENU_OBJECT MenuObject, PMENU_ITEM MenuItem, PROSMENUITEMINF } else { - FreeMenuText(MenuItem); - MenuItem->fType = MF_SEPARATOR; + MenuItem->fType |= MF_SEPARATOR; + RtlInitUnicodeString(&MenuItem->Text, NULL); } } else @@ -781,7 +781,7 @@ IntSetMenuItemInfo(PMENU_OBJECT MenuObject, PMENU_ITEM MenuItem, PROSMENUITEMINF return TRUE; } -static BOOL FASTCALL +BOOL FASTCALL IntInsertMenuItem(PMENU_OBJECT MenuObject, UINT uItem, BOOL fByPosition, PROSMENUITEMINFO ItemInfo) { diff --git a/reactos/subsys/win32k/ntuser/window.c b/reactos/subsys/win32k/ntuser/window.c index a6df96b5847..5f58d6ea6c9 100644 --- a/reactos/subsys/win32k/ntuser/window.c +++ b/reactos/subsys/win32k/ntuser/window.c @@ -16,7 +16,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -/* $Id: window.c,v 1.189 2004/02/22 15:14:27 navaraf Exp $ +/* $Id: window.c,v 1.190 2004/02/22 23:40:58 gvg Exp $ * * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel @@ -589,9 +589,10 @@ IntGetParent(PWINDOW_OBJECT Wnd) PMENU_OBJECT FASTCALL IntGetSystemMenu(PWINDOW_OBJECT WindowObject, BOOL bRevert, BOOL RetMenu) { - PMENU_OBJECT MenuObject, NewMenuObject, ret = NULL; + PMENU_OBJECT MenuObject, NewMenuObject, SysMenuObject, ret = NULL; PW32PROCESS W32Process; - HMENU NewMenu; + HMENU NewMenu, SysMenu; + ROSMENUITEMINFO ItemInfo; if(bRevert) { @@ -623,6 +624,7 @@ IntGetSystemMenu(PWINDOW_OBJECT WindowObject, BOOL bRevert, BOOL RetMenu) { WindowObject->SystemMenu = NewMenuObject->MenuInfo.Self; NewMenuObject->MenuInfo.Flags |= MF_SYSMENU; + NewMenuObject->MenuInfo.Wnd = WindowObject->Self; ret = NewMenuObject; //IntReleaseMenuObject(NewMenuObject); } @@ -630,20 +632,53 @@ IntGetSystemMenu(PWINDOW_OBJECT WindowObject, BOOL bRevert, BOOL RetMenu) } else { + SysMenu = NtUserCreateMenu(FALSE); + if (NULL == SysMenu) + { + return NULL; + } + SysMenuObject = IntGetMenuObject(SysMenu); + if (NULL == SysMenuObject) + { + NtUserDestroyMenu(SysMenu); + return NULL; + } + SysMenuObject->MenuInfo.Flags |= MF_SYSMENU; + SysMenuObject->MenuInfo.Wnd = WindowObject->Self; NewMenu = IntLoadSysMenuTemplate(); if(!NewMenu) + { + IntReleaseMenuObject(SysMenuObject); + NtUserDestroyMenu(SysMenu); return NULL; + } MenuObject = IntGetMenuObject(NewMenu); if(!MenuObject) + { + IntReleaseMenuObject(SysMenuObject); + NtUserDestroyMenu(SysMenu); return NULL; + } NewMenuObject = IntCloneMenu(MenuObject); if(NewMenuObject) { - WindowObject->SystemMenu = NewMenuObject->MenuInfo.Self; - NewMenuObject->MenuInfo.Flags |= MF_SYSMENU; - ret = NewMenuObject; - //IntReleaseMenuObject(NewMenuObject); + NewMenuObject->MenuInfo.Flags |= MF_SYSMENU | MF_POPUP; + IntReleaseMenuObject(NewMenuObject); + NtUserSetMenuDefaultItem(NewMenuObject->MenuInfo.Self, SC_CLOSE, FALSE); + + ItemInfo.cbSize = sizeof(MENUITEMINFOW); + ItemInfo.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_STATE | MIIM_SUBMENU; + ItemInfo.fType = MF_POPUP; + ItemInfo.fState = MFS_ENABLED; + ItemInfo.dwTypeData = NULL; + ItemInfo.cch = 0; + ItemInfo.hSubMenu = NewMenuObject->MenuInfo.Self; + IntInsertMenuItem(SysMenuObject, (UINT) -1, TRUE, &ItemInfo); + + WindowObject->SystemMenu = SysMenuObject->MenuInfo.Self; + + ret = SysMenuObject; } IntDestroyMenuObject(MenuObject, FALSE, TRUE); IntReleaseMenuObject(MenuObject); @@ -2317,17 +2352,7 @@ NtUserGetSystemMenu(HWND hWnd, BOOL bRevert) MenuObject = IntGetSystemMenu(WindowObject, bRevert, FALSE); if (MenuObject) { - /* - * Return the handle of the first submenu. - */ - ExAcquireFastMutexUnsafe(&MenuObject->MenuItemsLock); - if (MenuObject->MenuItemList) - { - Result = MenuObject->MenuItemList->hSubMenu; - if (!IntIsMenu(Result)) - Result = 0; - } - ExReleaseFastMutexUnsafe(&MenuObject->MenuItemsLock); + Result = MenuObject->MenuInfo.Self; IntReleaseMenuObject(MenuObject); }