Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add settings entry into titlebar context menu #11404

Merged
4 commits merged into from
Nov 4, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/actions/spelling/allow/apis.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ BUILDBRANCH
BUILDMSG
BUILDNUMBER
BYPOSITION
BYCOMMAND
charconv
CLASSNOTAVAILABLE
cmdletbinding
Expand Down Expand Up @@ -85,6 +86,7 @@ LSHIFT
MENUCOMMAND
MENUDATA
MENUINFO
MENUITEMINFOW
memicmp
mptt
mov
Expand Down
8 changes: 8 additions & 0 deletions src/cascadia/TerminalApp/AppLogic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -1039,6 +1042,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
Expand Down
14 changes: 14 additions & 0 deletions src/cascadia/TerminalApp/AppLogic.h
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -112,6 +124,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 };
Expand Down Expand Up @@ -161,6 +174,7 @@ namespace winrt::TerminalApp::implementation
void _RegisterSettingsChange();
fire_and_forget _DispatchReloadSettings();
void _ReloadSettings();
void _OpenSettingsUI();

void _ApplyTheme(const Windows::UI::Xaml::ElementTheme& newTheme);

Expand Down
15 changes: 15 additions & 0 deletions src/cascadia/TerminalApp/AppLogic.idl
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -109,5 +123,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;
}
}
4 changes: 2 additions & 2 deletions src/cascadia/TerminalApp/TerminalPage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2090,7 +2090,7 @@ namespace winrt::TerminalApp::implementation
{
if (target == SettingsTarget::SettingsUI)
{
_OpenSettingsUI();
OpenSettingsUI();
}
else
{
Expand Down Expand Up @@ -2750,7 +2750,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)
Expand Down
4 changes: 2 additions & 2 deletions src/cascadia/TerminalApp/TerminalPage.h
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,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 ---------------------------------
Expand Down Expand Up @@ -365,8 +367,6 @@ namespace winrt::TerminalApp::implementation

void _UnZoomIfNeeded();

void _OpenSettingsUI();

static int _ComputeScrollDelta(ScrollDirection scrollDirection, const uint32_t rowsToScroll);
static uint32_t _ReadSystemRowsToScroll();

Expand Down
22 changes: 22 additions & 0 deletions src/cascadia/WindowsTerminal/AppHost.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand Down Expand Up @@ -1224,6 +1225,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:
Expand Down
3 changes: 3 additions & 0 deletions src/cascadia/WindowsTerminal/AppHost.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,9 @@ class AppHost
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);

Expand Down
57 changes: 57 additions & 0 deletions src/cascadia/WindowsTerminal/IslandWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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");

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible to add multiple system menu items with the same itemLabel? How would we differentiate between them if we want to remove them?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since user wouldn't be able to differentiate between items with the same label i thought it would make no sense to support it. Are you talking about some kind of a check in add function to prevent this?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah that's true 😄, it should be fine as it is imo then

{
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<>);
11 changes: 11 additions & 0 deletions src/cascadia/WindowsTerminal/IslandWindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -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>
{
Expand Down Expand Up @@ -54,6 +60,8 @@ class IslandWindow :
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<>);
Expand Down Expand Up @@ -131,6 +139,9 @@ class IslandWindow :

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;
Expand Down