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}") if(EXISTS "${__targets_file}")
include("${__targets_file}") include("${__targets_file}")
add_library(${__target} ALIAS @PROJECT_NAME@::${__target_full}) add_library(${__target} ALIAS @PROJECT_NAME@::${__target_full})
list(APPEND _@PROJECT_NAME@_available_components ${_component})
else() else()
set(@PROJECT_NAME@_FOUND FALSE) 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.") 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/standardtitlebar.h>
#include <FramelessHelper/Widgets/framelesswidgetshelper.h> #include <FramelessHelper/Widgets/framelesswidgetshelper.h>
#include <FramelessHelper/Widgets/standardsystembutton.h> #include <FramelessHelper/Widgets/standardsystembutton.h>
#include <FramelessHelper/Widgets/private/framelesswidgetshelper_p.h>
#include "../shared/settings.h" #include "../shared/settings.h"
extern template void Settings::set<QRect>(const QString &, const QString &, const QRect &); extern template void Settings::set<QRect>(const QString &, const QString &, const QRect &);
@ -134,6 +135,14 @@ void Dialog::setupUi()
#if FRAMELESSHELPER_CONFIG(titlebar) #if FRAMELESSHELPER_CONFIG(titlebar)
FramelessWidgetsHelper *helper = FramelessWidgetsHelper::get(this); FramelessWidgetsHelper *helper = FramelessWidgetsHelper::get(this);
helper->setTitleBarWidget(titleBar); 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)) # if (!defined(Q_OS_MACOS) && FRAMELESSHELPER_CONFIG(system_button))
helper->setSystemButton(titleBar->minimizeButton(), SystemButtonType::Minimize); helper->setSystemButton(titleBar->minimizeButton(), SystemButtonType::Minimize);
helper->setSystemButton(titleBar->maximizeButton(), SystemButtonType::Maximize); 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 kDontOverrideCursorVar[] = "FRAMELESSHELPER_DONT_OVERRIDE_CURSOR";
[[maybe_unused]] inline constexpr const char kDontToggleMaximizeVar[] = "FRAMELESSHELPER_DONT_TOGGLE_MAXIMIZE"; [[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 kSysMenuDisableMinimizeVar[] = "FRAMELESSHELPER_SYSTEM_MENU_DISABLE_MINIMIZE";
[[maybe_unused]] inline constexpr const char kSysMenuDisableMaximizeVar[] = "FRAMELESSHELPER_SYSTEM_MENU_DISABLE_MAXIMIZE"; [[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 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 enum class Option : quint8
{ {

View File

@ -135,6 +135,9 @@ FRAMELESSHELPER_STRING_CONSTANT(EnableMenuItem)
FRAMELESSHELPER_STRING_CONSTANT(SetMenuDefaultItem) FRAMELESSHELPER_STRING_CONSTANT(SetMenuDefaultItem)
FRAMELESSHELPER_STRING_CONSTANT(HiliteMenuItem) FRAMELESSHELPER_STRING_CONSTANT(HiliteMenuItem)
FRAMELESSHELPER_STRING_CONSTANT(TrackPopupMenu) FRAMELESSHELPER_STRING_CONSTANT(TrackPopupMenu)
FRAMELESSHELPER_STRING_CONSTANT(DrawMenuBar)
FRAMELESSHELPER_STRING_CONSTANT(DeleteMenu)
FRAMELESSHELPER_STRING_CONSTANT(RemoveMenu)
FRAMELESSHELPER_STRING_CONSTANT(ClientToScreen) FRAMELESSHELPER_STRING_CONSTANT(ClientToScreen)
FRAMELESSHELPER_STRING_CONSTANT(DwmEnableBlurBehindWindow) FRAMELESSHELPER_STRING_CONSTANT(DwmEnableBlurBehindWindow)
FRAMELESSHELPER_STRING_CONSTANT(SetWindowCompositionAttribute) 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. // 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 disableRestore = data->callbacks->getProperty(kSysMenuDisableRestoreVar, false).toBool();
const bool disableMinimize = data->callbacks->getProperty(kSysMenuDisableMinimizeVar, false).toBool(); const bool disableMinimize = data->callbacks->getProperty(kSysMenuDisableMinimizeVar, false).toBool();
const bool disableMaximize = data->callbacks->getProperty(kSysMenuDisableMaximizeVar, 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 maxOrFull = (IsMaximized(hWnd) || isFullScreen(windowId));
const bool fixedSize = data->callbacks->isWindowFixedSize(); 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))); ::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 // 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 // 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 // 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. // 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))); ::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_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 // 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") // 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. // can clear the default item for the given menu.
UINT defaultItemId = UINT_MAX; std::optional<UINT> defaultItemId = std::nullopt;
if (WindowsVersionHelper::isWin11OrGreater()) { if (WindowsVersionHelper::isWin11OrGreater()) {
if (maxOrFull) { if (maxOrFull) {
if (!removeRestore) {
defaultItemId = SC_RESTORE; defaultItemId = SC_RESTORE;
}
} else { } else {
if (!removeMaximize) {
defaultItemId = SC_MAXIMIZE; defaultItemId = SC_MAXIMIZE;
} }
} else { }
}
if (!(defaultItemId.has_value() || removeClose)) {
defaultItemId = SC_CLOSE; 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. // 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); 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 // Unhighlight the first menu item after the popup menu is closed, otherwise it will keep
// highlighting until we unhighlight it manually. // highlighting until we unhighlight it manually.
::HiliteMenuItem(hWnd, hMenu, SC_RESTORE, (MF_BYCOMMAND | MFS_UNHILITE)); ::HiliteMenuItem(hWnd, hMenu, SC_RESTORE, (MF_BYCOMMAND | MFS_UNHILITE));
}
if (result == FALSE) { if (result == FALSE) {
// The user canceled the menu, no need to continue. // The user canceled the menu, no need to continue.