win: system menu: allow user remove menu items

This commit is contained in:
Yuhang Zhao 2023-10-20 10:47:53 +08:00
parent 2cb8ec0aeb
commit 4821e8982f
4 changed files with 111 additions and 24 deletions

View File

@ -40,6 +40,7 @@ foreach(_component ${@PROJECT_NAME@_FIND_COMPONENTS})
if(EXISTS "${__targets_file}")
include("${__targets_file}")
add_library(${__target} ALIAS @PROJECT_NAME@::${__target_full})
list(APPEND _@PROJECT_NAME@_available_components ${_component})
else()
set(@PROJECT_NAME@_FOUND FALSE)
set(@PROJECT_NAME@_NOT_FOUND_MESSAGE "Can't find necessary configuration file for ${__target}, please make sure this component is built successfully and installed properly.")

View File

@ -13,6 +13,7 @@
#include <FramelessHelper/Widgets/standardtitlebar.h>
#include <FramelessHelper/Widgets/framelesswidgetshelper.h>
#include <FramelessHelper/Widgets/standardsystembutton.h>
#include <FramelessHelper/Widgets/private/framelesswidgetshelper_p.h>
#include "../shared/settings.h"
extern template void Settings::set<QRect>(const QString &, const QString &, const QRect &);
@ -134,6 +135,14 @@ void Dialog::setupUi()
#if FRAMELESSHELPER_CONFIG(titlebar)
FramelessWidgetsHelper *helper = FramelessWidgetsHelper::get(this);
helper->setTitleBarWidget(titleBar);
# ifdef Q_OS_WINDOWS
FramelessWidgetsHelperPrivate *helperPriv = FramelessWidgetsHelperPrivate::get(helper);
helperPriv->setProperty(kSysMenuRemoveRestoreVar, true);
helperPriv->setProperty(kSysMenuRemoveSizeVar, true);
helperPriv->setProperty(kSysMenuRemoveMinimizeVar, true);
helperPriv->setProperty(kSysMenuRemoveMaximizeVar, true);
helperPriv->setProperty(kSysMenuRemoveSeparatorVar, true);
# endif
# if (!defined(Q_OS_MACOS) && FRAMELESSHELPER_CONFIG(system_button))
helper->setSystemButton(titleBar->minimizeButton(), SystemButtonType::Minimize);
helper->setSystemButton(titleBar->maximizeButton(), SystemButtonType::Maximize);

View File

@ -395,9 +395,19 @@ Q_NAMESPACE_EXPORT(FRAMELESSHELPER_CORE_API)
[[maybe_unused]] inline constexpr const char kDontOverrideCursorVar[] = "FRAMELESSHELPER_DONT_OVERRIDE_CURSOR";
[[maybe_unused]] inline constexpr const char kDontToggleMaximizeVar[] = "FRAMELESSHELPER_DONT_TOGGLE_MAXIMIZE";
[[maybe_unused]] inline constexpr const char kSysMenuDisableMoveVar[] = "FRAMELESSHELPER_SYSTEM_MENU_DISABLE_MOVE";
[[maybe_unused]] inline constexpr const char kSysMenuDisableSizeVar[] = "FRAMELESSHELPER_SYSTEM_MENU_DISABLE_SIZE";
[[maybe_unused]] inline constexpr const char kSysMenuDisableMinimizeVar[] = "FRAMELESSHELPER_SYSTEM_MENU_DISABLE_MINIMIZE";
[[maybe_unused]] inline constexpr const char kSysMenuDisableMaximizeVar[] = "FRAMELESSHELPER_SYSTEM_MENU_DISABLE_MAXIMIZE";
[[maybe_unused]] inline constexpr const char kSysMenuDisableRestoreVar[] = "FRAMELESSHELPER_SYSTEM_MENU_DISABLE_RESTORE";
[[maybe_unused]] inline constexpr const char kSysMenuDisableCloseVar[] = "FRAMELESSHELPER_SYSTEM_MENU_DISABLE_CLOSE";
[[maybe_unused]] inline constexpr const char kSysMenuRemoveMoveVar[] = "FRAMELESSHELPER_SYSTEM_MENU_REMOVE_MOVE";
[[maybe_unused]] inline constexpr const char kSysMenuRemoveSizeVar[] = "FRAMELESSHELPER_SYSTEM_MENU_REMOVE_SIZE";
[[maybe_unused]] inline constexpr const char kSysMenuRemoveMinimizeVar[] = "FRAMELESSHELPER_SYSTEM_MENU_REMOVE_MINIMIZE";
[[maybe_unused]] inline constexpr const char kSysMenuRemoveMaximizeVar[] = "FRAMELESSHELPER_SYSTEM_MENU_REMOVE_MAXIMIZE";
[[maybe_unused]] inline constexpr const char kSysMenuRemoveRestoreVar[] = "FRAMELESSHELPER_SYSTEM_MENU_REMOVE_RESTORE";
[[maybe_unused]] inline constexpr const char kSysMenuRemoveSeparatorVar[] = "FRAMELESSHELPER_SYSTEM_MENU_REMOVE_SEPARATOR";
[[maybe_unused]] inline constexpr const char kSysMenuRemoveCloseVar[] = "FRAMELESSHELPER_SYSTEM_MENU_REMOVE_CLOSE";
enum class Option : quint8
{

View File

@ -135,6 +135,9 @@ FRAMELESSHELPER_STRING_CONSTANT(EnableMenuItem)
FRAMELESSHELPER_STRING_CONSTANT(SetMenuDefaultItem)
FRAMELESSHELPER_STRING_CONSTANT(HiliteMenuItem)
FRAMELESSHELPER_STRING_CONSTANT(TrackPopupMenu)
FRAMELESSHELPER_STRING_CONSTANT(DrawMenuBar)
FRAMELESSHELPER_STRING_CONSTANT(DeleteMenu)
FRAMELESSHELPER_STRING_CONSTANT(RemoveMenu)
FRAMELESSHELPER_STRING_CONSTANT(ClientToScreen)
FRAMELESSHELPER_STRING_CONSTANT(DwmEnableBlurBehindWindow)
FRAMELESSHELPER_STRING_CONSTANT(SetWindowCompositionAttribute)
@ -1315,11 +1318,45 @@ bool Utils::showSystemMenu(const WId windowId, const QPoint &pos, const bool sel
}
// Tweak the menu items according to the current window status and user settings.
const bool disableClose = data->callbacks->getProperty(kSysMenuDisableCloseVar, false).toBool();
const bool disableRestore = data->callbacks->getProperty(kSysMenuDisableRestoreVar, false).toBool();
const bool disableMinimize = data->callbacks->getProperty(kSysMenuDisableMinimizeVar, false).toBool();
const bool disableMaximize = data->callbacks->getProperty(kSysMenuDisableMaximizeVar, false).toBool();
const bool disableSize = data->callbacks->getProperty(kSysMenuDisableSizeVar, false).toBool();
const bool disableMove = data->callbacks->getProperty(kSysMenuDisableMoveVar, false).toBool();
const bool removeClose = data->callbacks->getProperty(kSysMenuRemoveCloseVar, false).toBool();
const bool removeSeparator = data->callbacks->getProperty(kSysMenuRemoveSeparatorVar, false).toBool();
const bool removeRestore = data->callbacks->getProperty(kSysMenuRemoveRestoreVar, false).toBool();
const bool removeMinimize = data->callbacks->getProperty(kSysMenuRemoveMinimizeVar, false).toBool();
const bool removeMaximize = data->callbacks->getProperty(kSysMenuRemoveMaximizeVar, false).toBool();
const bool removeSize = data->callbacks->getProperty(kSysMenuRemoveSizeVar, false).toBool();
const bool removeMove = data->callbacks->getProperty(kSysMenuRemoveMoveVar, false).toBool();
const bool maxOrFull = (IsMaximized(hWnd) || isFullScreen(windowId));
const bool fixedSize = data->callbacks->isWindowFixedSize();
if (removeClose) {
if (::DeleteMenu(hMenu, SC_CLOSE, MF_BYCOMMAND) == FALSE) {
//WARNING << getSystemErrorMessage(kDeleteMenu);
}
} else {
::EnableMenuItem(hMenu, SC_CLOSE, (MF_BYCOMMAND | (disableClose ? MFS_DISABLED : MFS_ENABLED)));
}
if (removeSeparator) {
if (::DeleteMenu(hMenu, SC_SEPARATOR, MF_BYCOMMAND) == FALSE) {
//WARNING << getSystemErrorMessage(kDeleteMenu);
}
}
if (removeMaximize) {
if (::DeleteMenu(hMenu, SC_MAXIMIZE, MF_BYCOMMAND) == FALSE) {
//WARNING << getSystemErrorMessage(kDeleteMenu);
}
} else {
::EnableMenuItem(hMenu, SC_MAXIMIZE, (MF_BYCOMMAND | ((!maxOrFull && !fixedSize && !disableMaximize) ? MFS_ENABLED : MFS_DISABLED)));
}
if (removeRestore) {
if (::DeleteMenu(hMenu, SC_RESTORE, MF_BYCOMMAND) == FALSE) {
//WARNING << getSystemErrorMessage(kDeleteMenu);
}
} else {
::EnableMenuItem(hMenu, SC_RESTORE, (MF_BYCOMMAND | ((maxOrFull && !fixedSize && !disableRestore) ? MFS_ENABLED : MFS_DISABLED)));
// The first menu item should be selected by default if the menu is brought
// up by keyboard. I don't know how to pre-select a menu item but it seems
@ -1331,33 +1368,63 @@ bool Utils::showSystemMenu(const WId windowId, const QPoint &pos, const bool sel
// highlight bar to indicate the current selected menu item, which will make
// the menu look kind of weird. Currently I don't know how to fix this issue.
::HiliteMenuItem(hWnd, hMenu, SC_RESTORE, (MF_BYCOMMAND | (selectFirstEntry ? MFS_HILITE : MFS_UNHILITE)));
::EnableMenuItem(hMenu, SC_MOVE, (MF_BYCOMMAND | (!maxOrFull ? MFS_ENABLED : MFS_DISABLED)));
::EnableMenuItem(hMenu, SC_SIZE, (MF_BYCOMMAND | ((!maxOrFull && !fixedSize && !(disableMinimize || disableMaximize)) ? MFS_ENABLED : MFS_DISABLED)));
}
if (removeMinimize) {
if (::DeleteMenu(hMenu, SC_MINIMIZE, MF_BYCOMMAND) == FALSE) {
//WARNING << getSystemErrorMessage(kDeleteMenu);
}
} else {
::EnableMenuItem(hMenu, SC_MINIMIZE, (MF_BYCOMMAND | (disableMinimize ? MFS_DISABLED : MFS_ENABLED)));
::EnableMenuItem(hMenu, SC_MAXIMIZE, (MF_BYCOMMAND | ((!maxOrFull && !fixedSize && !disableMaximize) ? MFS_ENABLED : MFS_DISABLED)));
::EnableMenuItem(hMenu, SC_CLOSE, (MF_BYCOMMAND | MFS_ENABLED));
}
if (removeSize) {
if (::DeleteMenu(hMenu, SC_SIZE, MF_BYCOMMAND) == FALSE) {
//WARNING << getSystemErrorMessage(kDeleteMenu);
}
} else {
::EnableMenuItem(hMenu, SC_SIZE, (MF_BYCOMMAND | ((!maxOrFull && !fixedSize && !(disableSize || disableMinimize || disableMaximize)) ? MFS_ENABLED : MFS_DISABLED)));
}
if (removeMove) {
if (::DeleteMenu(hMenu, SC_MOVE, MF_BYCOMMAND) == FALSE) {
//WARNING << getSystemErrorMessage(kDeleteMenu);
}
} else {
::EnableMenuItem(hMenu, SC_MOVE, (MF_BYCOMMAND | ((disableMove || maxOrFull) ? MFS_DISABLED : MFS_ENABLED)));
}
// The default menu item will appear in bold font. There can only be one default
// menu item per menu at most. Set the item ID to "UINT_MAX" (or simply "-1")
// can clear the default item for the given menu.
UINT defaultItemId = UINT_MAX;
std::optional<UINT> defaultItemId = std::nullopt;
if (WindowsVersionHelper::isWin11OrGreater()) {
if (maxOrFull) {
if (!removeRestore) {
defaultItemId = SC_RESTORE;
}
} else {
if (!removeMaximize) {
defaultItemId = SC_MAXIMIZE;
}
} else {
}
}
if (!(defaultItemId.has_value() || removeClose)) {
defaultItemId = SC_CLOSE;
}
::SetMenuDefaultItem(hMenu, defaultItemId, FALSE);
if (::SetMenuDefaultItem(hMenu, defaultItemId.value_or(UINT_MAX), FALSE) == FALSE) {
WARNING << getSystemErrorMessage(kSetMenuDefaultItem);
}
if (::DrawMenuBar(hWnd) == FALSE) {
WARNING << getSystemErrorMessage(kDrawMenuBar);
}
// Popup the system menu at the required position.
const int result = ::TrackPopupMenu(hMenu, (TPM_RETURNCMD | (QGuiApplication::isRightToLeft() ? TPM_RIGHTALIGN : TPM_LEFTALIGN)), pos.x(), pos.y(), 0, hWnd, nullptr);
if (!removeRestore) {
// Unhighlight the first menu item after the popup menu is closed, otherwise it will keep
// highlighting until we unhighlight it manually.
::HiliteMenuItem(hWnd, hMenu, SC_RESTORE, (MF_BYCOMMAND | MFS_UNHILITE));
}
if (result == FALSE) {
// The user canceled the menu, no need to continue.