Add settings entry into titlebar context menu (#11404)
<!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request Adds ability for app to change system context menu <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist * [x] Closes #9666 * [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA * [ ] Tests added/passed * [ ] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx * [ ] Schema updated. * [ ] I've discussed this with core contributors already. If not checked, I'm ready to accept this work might be rejected in favor of a different grand plan. Issue number where discussion took place: #xxx <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed
This commit is contained in:
parent
8826cc028b
commit
ab6ba9bdbb
|
@ -9,6 +9,7 @@ BUILDBRANCH
|
|||
BUILDMSG
|
||||
BUILDNUMBER
|
||||
BYPOSITION
|
||||
BYCOMMAND
|
||||
charconv
|
||||
CLASSNOTAVAILABLE
|
||||
cmdletbinding
|
||||
|
@ -85,6 +86,7 @@ LSHIFT
|
|||
MENUCOMMAND
|
||||
MENUDATA
|
||||
MENUINFO
|
||||
MENUITEMINFOW
|
||||
memicmp
|
||||
mptt
|
||||
mov
|
||||
|
|
|
@ -334,6 +334,9 @@ namespace winrt::TerminalApp::implementation
|
|||
_RefreshThemeRoutine();
|
||||
_ApplyStartupTaskStateChange();
|
||||
|
||||
auto args = winrt::make_self<SystemMenuChangeArgs>(RS_(L"SettingsMenuItem"), SystemMenuChangeAction::Add, SystemMenuItemHandler(this, &AppLogic::_OpenSettingsUI));
|
||||
_SystemMenuChangeRequestedHandlers(*this, *args);
|
||||
|
||||
TraceLoggingWrite(
|
||||
g_hTerminalAppProvider,
|
||||
"AppCreated",
|
||||
|
@ -1051,6 +1054,11 @@ namespace winrt::TerminalApp::implementation
|
|||
_SettingsChangedHandlers(*this, nullptr);
|
||||
}
|
||||
|
||||
void AppLogic::_OpenSettingsUI()
|
||||
{
|
||||
_root->OpenSettingsUI();
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Returns a pointer to the global shared settings.
|
||||
[[nodiscard]] CascadiaSettings AppLogic::GetSettings() const noexcept
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include "AppLogic.g.h"
|
||||
#include "FindTargetWindowResult.g.h"
|
||||
#include "SystemMenuChangeArgs.g.h"
|
||||
#include "Jumplist.h"
|
||||
#include "LanguageProfileNotifier.h"
|
||||
#include "TerminalPage.h"
|
||||
|
@ -35,6 +36,17 @@ namespace winrt::TerminalApp::implementation
|
|||
FindTargetWindowResult(id, L""){};
|
||||
};
|
||||
|
||||
struct SystemMenuChangeArgs : SystemMenuChangeArgsT<SystemMenuChangeArgs>
|
||||
{
|
||||
WINRT_PROPERTY(winrt::hstring, Name, L"");
|
||||
WINRT_PROPERTY(SystemMenuChangeAction, Action, SystemMenuChangeAction::Add);
|
||||
WINRT_PROPERTY(SystemMenuItemHandler, Handler, nullptr);
|
||||
|
||||
public:
|
||||
SystemMenuChangeArgs(const winrt::hstring& name, SystemMenuChangeAction action, SystemMenuItemHandler handler = nullptr) :
|
||||
_Name{ name }, _Action{ action }, _Handler{ handler } {};
|
||||
};
|
||||
|
||||
struct AppLogic : AppLogicT<AppLogic, IInitializeWithWindow>
|
||||
{
|
||||
public:
|
||||
|
@ -113,6 +125,7 @@ namespace winrt::TerminalApp::implementation
|
|||
// -------------------------------- WinRT Events ---------------------------------
|
||||
TYPED_EVENT(RequestedThemeChanged, winrt::Windows::Foundation::IInspectable, winrt::Windows::UI::Xaml::ElementTheme);
|
||||
TYPED_EVENT(SettingsChanged, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable);
|
||||
TYPED_EVENT(SystemMenuChangeRequested, winrt::Windows::Foundation::IInspectable, winrt::TerminalApp::SystemMenuChangeArgs);
|
||||
|
||||
private:
|
||||
bool _isUwp{ false };
|
||||
|
@ -163,6 +176,7 @@ namespace winrt::TerminalApp::implementation
|
|||
void _RegisterSettingsChange();
|
||||
fire_and_forget _DispatchReloadSettings();
|
||||
void _ReloadSettings();
|
||||
void _OpenSettingsUI();
|
||||
|
||||
void _ApplyTheme(const Windows::UI::Xaml::ElementTheme& newTheme);
|
||||
|
||||
|
|
|
@ -19,6 +19,20 @@ namespace TerminalApp
|
|||
String WindowName { get; };
|
||||
};
|
||||
|
||||
delegate void SystemMenuItemHandler();
|
||||
|
||||
enum SystemMenuChangeAction
|
||||
{
|
||||
Add = 0,
|
||||
Remove = 1
|
||||
};
|
||||
|
||||
[default_interface] runtimeclass SystemMenuChangeArgs {
|
||||
String Name { get; };
|
||||
SystemMenuChangeAction Action { get; };
|
||||
SystemMenuItemHandler Handler { get; };
|
||||
};
|
||||
|
||||
[default_interface] runtimeclass AppLogic : IDirectKeyListener, IDialogPresenter
|
||||
{
|
||||
AppLogic();
|
||||
|
@ -110,5 +124,6 @@ namespace TerminalApp
|
|||
event Windows.Foundation.TypedEventHandler<Object, Object> CloseRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> OpenSystemMenu;
|
||||
event Windows.Foundation.TypedEventHandler<Object, Object> QuitRequested;
|
||||
event Windows.Foundation.TypedEventHandler<Object, TerminalApp.SystemMenuChangeArgs> SystemMenuChangeRequested;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2111,7 +2111,7 @@ namespace winrt::TerminalApp::implementation
|
|||
{
|
||||
if (target == SettingsTarget::SettingsUI)
|
||||
{
|
||||
_OpenSettingsUI();
|
||||
OpenSettingsUI();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -2759,7 +2759,7 @@ namespace winrt::TerminalApp::implementation
|
|||
// - <none>
|
||||
// Return Value:
|
||||
// - <none>
|
||||
void TerminalPage::_OpenSettingsUI()
|
||||
void TerminalPage::OpenSettingsUI()
|
||||
{
|
||||
// If we're holding the settings tab's switch command, don't create a new one, switch to the existing one.
|
||||
if (!_settingsTab)
|
||||
|
|
|
@ -121,6 +121,8 @@ namespace winrt::TerminalApp::implementation
|
|||
bool IsQuakeWindow() const noexcept;
|
||||
bool IsElevated() const noexcept;
|
||||
|
||||
void OpenSettingsUI();
|
||||
|
||||
WINRT_CALLBACK(PropertyChanged, Windows::UI::Xaml::Data::PropertyChangedEventHandler);
|
||||
|
||||
// -------------------------------- WinRT Events ---------------------------------
|
||||
|
@ -366,8 +368,6 @@ namespace winrt::TerminalApp::implementation
|
|||
|
||||
void _UnZoomIfNeeded();
|
||||
|
||||
void _OpenSettingsUI();
|
||||
|
||||
static int _ComputeScrollDelta(ScrollDirection scrollDirection, const uint32_t rowsToScroll);
|
||||
static uint32_t _ReadSystemRowsToScroll();
|
||||
|
||||
|
|
|
@ -325,6 +325,7 @@ void AppHost::Initialize()
|
|||
_logic.FocusModeChanged({ this, &AppHost::_FocusModeChanged });
|
||||
_logic.AlwaysOnTopChanged({ this, &AppHost::_AlwaysOnTopChanged });
|
||||
_logic.RaiseVisualBell({ this, &AppHost::_RaiseVisualBell });
|
||||
_logic.SystemMenuChangeRequested({ this, &AppHost::_SystemMenuChangeRequested });
|
||||
|
||||
_logic.Create();
|
||||
|
||||
|
@ -1248,6 +1249,27 @@ void AppHost::_OpenSystemMenu(const winrt::Windows::Foundation::IInspectable&,
|
|||
_window->OpenSystemMenu(std::nullopt, std::nullopt);
|
||||
}
|
||||
|
||||
void AppHost::_SystemMenuChangeRequested(const winrt::Windows::Foundation::IInspectable&, const winrt::TerminalApp::SystemMenuChangeArgs& args)
|
||||
{
|
||||
switch (args.Action())
|
||||
{
|
||||
case winrt::TerminalApp::SystemMenuChangeAction::Add:
|
||||
{
|
||||
auto handler = args.Handler();
|
||||
_window->AddToSystemMenu(args.Name(), [handler]() { handler(); });
|
||||
break;
|
||||
}
|
||||
case winrt::TerminalApp::SystemMenuChangeAction::Remove:
|
||||
{
|
||||
_window->RemoveFromSystemMenu(args.Name());
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Method Description:
|
||||
// - Creates a Notification Icon and hooks up its handlers
|
||||
// Arguments:
|
||||
|
|
|
@ -96,6 +96,9 @@ private:
|
|||
void _OpenSystemMenu(const winrt::Windows::Foundation::IInspectable& sender,
|
||||
const winrt::Windows::Foundation::IInspectable& args);
|
||||
|
||||
void _SystemMenuChangeRequested(const winrt::Windows::Foundation::IInspectable& sender,
|
||||
const winrt::TerminalApp::SystemMenuChangeArgs& args);
|
||||
|
||||
winrt::fire_and_forget _QuitRequested(const winrt::Windows::Foundation::IInspectable& sender,
|
||||
const winrt::Windows::Foundation::IInspectable& args);
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ using namespace ::Microsoft::Console::Types;
|
|||
using VirtualKeyModifiers = winrt::Windows::System::VirtualKeyModifiers;
|
||||
|
||||
#define XAML_HOSTING_WINDOW_CLASS_NAME L"CASCADIA_HOSTING_WINDOW_CLASS"
|
||||
#define IDM_SYSTEM_MENU_BEGIN 0x1000
|
||||
|
||||
const UINT WM_TASKBARCREATED = RegisterWindowMessage(L"TaskbarCreated");
|
||||
|
||||
|
@ -321,6 +322,8 @@ void IslandWindow::Initialize()
|
|||
}
|
||||
}
|
||||
|
||||
_systemMenuNextItemId = IDM_SYSTEM_MENU_BEGIN;
|
||||
|
||||
// Enable vintage opacity by removing the XAML emergency backstop, GH#603.
|
||||
// We don't really care if this failed or not.
|
||||
TerminalTrySetTransparentBackground(true);
|
||||
|
@ -608,6 +611,15 @@ long IslandWindow::_calculateTotalSize(const bool isWidth, const long clientSize
|
|||
_NotifyNotificationIconMenuItemSelectedHandlers((HMENU)lparam, (UINT)wparam);
|
||||
return 0;
|
||||
}
|
||||
case WM_SYSCOMMAND:
|
||||
{
|
||||
auto search = _systemMenuItems.find(LOWORD(wparam));
|
||||
if (search != _systemMenuItems.end())
|
||||
{
|
||||
search->second.callback();
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// We'll want to receive this message when explorer.exe restarts
|
||||
// so that we can re-add our icon to the notification area.
|
||||
|
@ -1717,5 +1729,50 @@ void IslandWindow::OpenSystemMenu(const std::optional<int> mouseX, const std::op
|
|||
}
|
||||
}
|
||||
|
||||
void IslandWindow::AddToSystemMenu(const winrt::hstring& itemLabel, winrt::delegate<void()> callback)
|
||||
{
|
||||
const HMENU systemMenu = GetSystemMenu(_window.get(), FALSE);
|
||||
UINT wID = _systemMenuNextItemId;
|
||||
|
||||
MENUITEMINFOW item;
|
||||
item.cbSize = sizeof(MENUITEMINFOW);
|
||||
item.fMask = MIIM_STATE | MIIM_ID | MIIM_STRING;
|
||||
item.fState = MF_ENABLED;
|
||||
item.wID = wID;
|
||||
item.dwTypeData = const_cast<LPWSTR>(itemLabel.c_str());
|
||||
item.cch = static_cast<UINT>(itemLabel.size());
|
||||
|
||||
if (LOG_LAST_ERROR_IF(!InsertMenuItemW(systemMenu, wID, FALSE, &item)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
_systemMenuItems.insert({ wID, { itemLabel, callback } });
|
||||
_systemMenuNextItemId++;
|
||||
}
|
||||
|
||||
void IslandWindow::RemoveFromSystemMenu(const winrt::hstring& itemLabel)
|
||||
{
|
||||
const HMENU systemMenu = GetSystemMenu(_window.get(), FALSE);
|
||||
int itemCount = GetMenuItemCount(systemMenu);
|
||||
if (LOG_LAST_ERROR_IF(itemCount == -1))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
auto it = std::find_if(_systemMenuItems.begin(), _systemMenuItems.end(), [&itemLabel](const std::pair<UINT, SystemMenuItemInfo>& elem) {
|
||||
return elem.second.label == itemLabel;
|
||||
});
|
||||
if (it == _systemMenuItems.end())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (LOG_LAST_ERROR_IF(!DeleteMenu(systemMenu, it->first, MF_BYCOMMAND)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
_systemMenuItems.erase(it->first);
|
||||
}
|
||||
|
||||
DEFINE_EVENT(IslandWindow, DragRegionClicked, _DragRegionClickedHandlers, winrt::delegate<>);
|
||||
DEFINE_EVENT(IslandWindow, WindowCloseButtonClicked, _windowCloseButtonClickedHandler, winrt::delegate<>);
|
||||
|
|
|
@ -8,6 +8,12 @@
|
|||
|
||||
void SetWindowLongWHelper(const HWND hWnd, const int nIndex, const LONG dwNewLong) noexcept;
|
||||
|
||||
struct SystemMenuItemInfo
|
||||
{
|
||||
winrt::hstring label;
|
||||
winrt::delegate<void()> callback;
|
||||
};
|
||||
|
||||
class IslandWindow :
|
||||
public BaseWindow<IslandWindow>
|
||||
{
|
||||
|
@ -54,6 +60,8 @@ public:
|
|||
void SetMinimizeToNotificationAreaBehavior(bool MinimizeToNotificationArea) noexcept;
|
||||
|
||||
void OpenSystemMenu(const std::optional<int> mouseX, const std::optional<int> mouseY) const noexcept;
|
||||
void AddToSystemMenu(const winrt::hstring& itemLabel, winrt::delegate<void()> callback);
|
||||
void RemoveFromSystemMenu(const winrt::hstring& itemLabel);
|
||||
|
||||
DECLARE_EVENT(DragRegionClicked, _DragRegionClickedHandlers, winrt::delegate<>);
|
||||
DECLARE_EVENT(WindowCloseButtonClicked, _windowCloseButtonClickedHandler, winrt::delegate<>);
|
||||
|
@ -131,6 +139,9 @@ protected:
|
|||
|
||||
bool _minimizeToNotificationArea{ false };
|
||||
|
||||
std::unordered_map<UINT, SystemMenuItemInfo> _systemMenuItems;
|
||||
UINT _systemMenuNextItemId;
|
||||
|
||||
private:
|
||||
// This minimum width allows for width the tabs fit
|
||||
static constexpr long minimumWidth = 460L;
|
||||
|
|
Loading…
Reference in New Issue