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

Provide the focused tab title in the Tray Icon's context menu #11043

Merged
5 commits merged into from
Sep 3, 2021

Conversation

leonMSFT
Copy link
Contributor

This PR adds a bit more information to each item in the Tray Icon's window selection submenu.
Currently it only shows the window ID and window name if given one.
Now each item will instead show{Window ID} : {Active Tab Title} [{Window Name}]

image

@@ -35,6 +35,7 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation

winrt::Microsoft::Terminal::Remoting::CommandlineArgs InitialArgs();
WINRT_PROPERTY(winrt::hstring, WindowName);
WINRT_PROPERTY(winrt::hstring, ActiveTabTitle);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't actually know what to call this - WindowTitle? FocusedTabTitle?

Copy link
Member

Choose a reason for hiding this comment

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

WindowTitle might be more appropriate, since users can also suppress the "use tab title as window title" behavior (and then the window's title is just Windows Terminal

Copy link
Member

Choose a reason for hiding this comment

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

This one I actually prefer not to be the window title. Imagine, you'd have a list inside of a Terminal tray icon that just says "Windows Terminal, Windows Terminal, Windows Terminal, Windows Terminal, Windows Terminal". Then again, that's my bias. 😄

Copy link
Member

Choose a reason for hiding this comment

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

Yea that's a good point. Plus, I hadn't read to AppHost.cpp:311 yet when I made this comment

@leonMSFT leonMSFT added Area-User Interface Issues pertaining to the user interface of the Console or Terminal Issue-Task It's a feature request, but it doesn't really need a major design. Product-Terminal The new Windows Terminal. labels Aug 26, 2021
Copy link
Member

@zadjii-msft zadjii-msft left a comment

Choose a reason for hiding this comment

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

Alright so I don't love the idea of returning the Peasants out of the Monarch. I just worry that's a potential footgun if people aren't careful.

That being said, we need to return something with multiple values here. We may need to do something like

    struct PeasantInfo{
        UInt64 Id;
        String Name;
        String TabTitle;
    }
    ...
    [default_interface] runtimeclass Monarch {
        ...
        Windows.Foundation.Collections.IMapView<UInt64, PeasantInfo> GetPeasantInfo { get; };
        ...
    }

If we do it like that, then I think WinRT will marshal the entire PeasantInfo struct into the calling process, rather than pass a com_ptr to the object residing in (some other process).

HMU on teams if that sounds insane. Also @DHowett call me out if that's not how winrt works

@@ -35,6 +35,7 @@ namespace winrt::Microsoft::Terminal::Remoting::implementation

winrt::Microsoft::Terminal::Remoting::CommandlineArgs InitialArgs();
WINRT_PROPERTY(winrt::hstring, WindowName);
WINRT_PROPERTY(winrt::hstring, ActiveTabTitle);
Copy link
Member

Choose a reason for hiding this comment

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

WindowTitle might be more appropriate, since users can also suppress the "use tab title as window title" behavior (and then the window's title is just Windows Terminal

Comment on lines 311 to 315
if (_logic.GetShowTitleInTitlebar())
{
_window->UpdateTitle(newTitle);
}
_windowManager.UpdateTitle(newTitle);
Copy link
Member

Choose a reason for hiding this comment

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

Ah okay. I see. You changed the title handling so that we always bubble the focused tab title up. So maybe it should be ActiveTabTitle, not WindowTitle

src/cascadia/WindowsTerminal/AppHost.cpp Show resolved Hide resolved
src/cascadia/Remoting/WindowManager.cpp Outdated Show resolved Hide resolved
@ghost ghost added Needs-Author-Feedback The original author of the issue/PR needs to come back and respond to something and removed Needs-Author-Feedback The original author of the issue/PR needs to come back and respond to something labels Aug 26, 2021
@zadjii-msft zadjii-msft added this to the Terminal v1.12 milestone Aug 26, 2021
Copy link
Member

@zadjii-msft zadjii-msft left a comment

Choose a reason for hiding this comment

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

I dig it, thanks for bearing with me ☺️

@zadjii-msft zadjii-msft added the Needs-Second It's a PR that needs another sign-off label Sep 2, 2021
src/cascadia/Remoting/Monarch.cpp Outdated Show resolved Hide resolved
src/cascadia/Remoting/Monarch.cpp Outdated Show resolved Hide resolved
src/cascadia/Remoting/Monarch.cpp Outdated Show resolved Hide resolved
Comment on lines 863 to 868
// Remove the dead peasants we came across while iterating.
for (const auto& id : peasantsToErase)
{
_peasants.erase(id);
_clearOldMruEntries(id);
}
Copy link
Member

@lhecker lhecker Sep 2, 2021

Choose a reason for hiding this comment

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

I believe the time is nigh to abstract this away, as it's been repeated 3x now in this file.
You can put something like this into the header:

template<typename F>
void _forEachPeasant(F&& func)
{
    using Map = decltype(_peasants);
    using R = std::invoke_result_t<F, Map::key_type, Map::mapped_type>;
    static constexpr auto IsVoid = std::is_void_v<R>;

    std::vector<uint64_t> peasantsToErase;

    for (const auto& [id, p] : _peasants)
    {
        try
        {
            if constexpr (IsVoid)
            {
                func(id, p);
            }
            else
            {
                if (!func(id, p))
                {
                    break;
                }
            }
        }
        catch (const winrt::hresult_error& exception)
        {
            if (exception.code() == 0x800706ba) // The RPC server is unavailable.
            {
                peasantsToErase.emplace_back(id);
            }
            else
            {
                LOG_CAUGHT_EXCEPTION();
                throw;
            }
        }
    }

    for (const auto& id : peasantsToErase)
    {
        _peasants.erase(id);
        _clearOldMruEntries(id);
    }
}

Then use it like that:

Windows::Foundation::Collections::IVectorView<Remoting::PeasantInfo> Monarch::GetPeasantInfos()
{
    std::vector<Remoting::PeasantInfo> names;
    names.reserve(_peasants.size());

    _forEachPeasant([&](const auto& id, const auto& p) {
        names.emplace_back(id, p.WindowName(), p.ActiveTabTitle());
    });

    return winrt::single_threaded_vector(std::move(names)).GetView();
}

bool Monarch::DoesQuakeWindowExist()
{
	  bool result = false;
	  _forEachPeasant([&](const auto& id, const auto& p) {
	      if (p.WindowName() == QuakeWindowName)
	      {
	          result = true;
	      }
	      // In other words:
	      // "continue if we didn't get a positive result"
	      return !result;
	  });
	  return result;
}

Copy link
Member

Choose a reason for hiding this comment

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

I believe you can even replace all usages of _forAllPeasantsIgnoringTheDead with that template.
@zadjii-msft Idk if that's correct. May _forAllPeasantsIgnoringTheDead remove dead peasants?

Copy link
Member

Choose a reason for hiding this comment

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

May _forAllPeasantsIgnoringTheDead remove dead peasants?

Meh, I suppose it could. off the top of my head, I don't remember if there was a specific reason it doesn't. IIRC, for things that were using _forAllPeasantsIgnoringTheDead, it didn't really matter if a peasant had died. I just left the removal for something later on that actually did care if the peasant had died.

Copy link
Member

Choose a reason for hiding this comment

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

I've updated my above template to contain:

catch (const winrt::hresult_error& exception)
{
    if (exception.code() == 0x800706ba) // The RPC server is unavailable.
    {
        peasantsToErase.emplace_back(id);
    }
    else
    {
        LOG_CAUGHT_EXCEPTION();
        throw;
    }
}

What do you think about that?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

If it will replace _forAllPeasantsIgnoringTheDead, it should probably also accept an onError function then?

Copy link
Member

Choose a reason for hiding this comment

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

I think we can just replace _forAllPeasantsIgnoringTheDead a different time. I don't know how important the two TraceLoggingWrite calls are...
Although it would be preferable if _forAllPeasantsIgnoringTheDead was a template as well so that we don't have to use std::function (which prevents inlining).

src/cascadia/WindowsTerminal/TrayIcon.cpp Outdated Show resolved Hide resolved
src/cascadia/WindowsTerminal/TrayIcon.cpp Outdated Show resolved Hide resolved
src/cascadia/WindowsTerminal/TrayIcon.cpp Outdated Show resolved Hide resolved
src/cascadia/WindowsTerminal/TrayIcon.cpp Outdated Show resolved Hide resolved
src/cascadia/Remoting/Peasant.idl Outdated Show resolved Hide resolved
src/cascadia/WindowsTerminal/TrayIcon.cpp Outdated Show resolved Hide resolved
src/cascadia/WindowsTerminal/TrayIcon.cpp Outdated Show resolved Hide resolved
@leonMSFT leonMSFT added AutoMerge Marked for automatic merge by the bot when requirements are met and removed Needs-Second It's a PR that needs another sign-off labels Sep 3, 2021
@ghost
Copy link

ghost commented Sep 3, 2021

Hello @leonMSFT!

Because this pull request has the AutoMerge label, I will be glad to assist with helping to merge this pull request once all check-in policies pass.

p.s. you can customize the way I help with merging this pull request, such as holding this pull request until a specific person approves. Simply @mention me (@msftbot) and give me an instruction to get started! Learn more here.

@ghost ghost merged commit 424414e into main Sep 3, 2021
@ghost ghost deleted the dev/lelian/trayicon/moarinfo branch September 3, 2021 18:32
@lhecker
Copy link
Member

lhecker commented Sep 5, 2021

BTW I realized after this PR was merged that you can also write this:

fmt::memory_buffer out;
fmt::format_to(out, L"#{}", p.Id);

if (!p.TabTitle.empty())
{
    fmt::format_to(out, L": {}", p.TabTitle);
}

if (!p.Name.empty())
{
    fmt::format_to(out, L" [{}]", p.Name);
}

fmt::format_to(out, L"\0");
AppendMenu(submenu, MF_STRING, gsl::narrow<UINT_PTR>(p.Id), out.data());

It doesn't even allocate anything on the heap!

@ghost
Copy link

ghost commented Oct 20, 2021

🎉Windows Terminal Preview v1.12.2922.0 has been released which incorporates this pull request.:tada:

Handy links:

This pull request was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-User Interface Issues pertaining to the user interface of the Console or Terminal AutoMerge Marked for automatic merge by the bot when requirements are met Issue-Task It's a feature request, but it doesn't really need a major design. Product-Terminal The new Windows Terminal.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants