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

Create a window process for the tray icon #10980

Merged
7 commits merged into from
Aug 20, 2021
Merged

Conversation

leonMSFT
Copy link
Contributor

Currently, the monarch window will show itself when opening the tray icon context menu. This is because a window must be set as the foreground window when the context menu opens, otherwise the menu won't be able to be dismissed when clicking outside of the context menu.

This PR makes the tray icon create a non visible/interactable window for the sole purpose of being set as the foreground window when the tray icon's context menu is opened. Then none of the terminal windows should be set as the foreground window when opening the context menu.

Closes #10936

@ghost ghost added Area-User Interface Issues pertaining to the user interface of the Console or Terminal Issue-Bug It either shouldn't be doing this or needs an investigation. Product-Terminal The new Windows Terminal. labels Aug 18, 2021
Comment on lines 42 to 47
WS_DISABLED,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
HWND_MESSAGE,
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Wasn't actually sure what were the necessary options to make this window process as un-interactable as possible, but I believe WS_DISABLED and maybe HWND_MESSAGE should be good?

Copy link
Member

Choose a reason for hiding this comment

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

IIRC, HWND_MESSAGE is enough to make it totally uninteractable. Though, in the past we've also done:

                hwnd = CreateWindowExW(
                    0, PSEUDO_WINDOW_CLASS, nullptr, WS_OVERLAPPEDWINDOW, 0, 0, 0, 0, HWND_DESKTOP, nullptr, nullptr, nullptr);

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 really only care about the wil::unique_hwnd thing. Rest looks good.

@@ -32,6 +35,7 @@ class TrayIcon
private:
HMENU _CreateTrayContextMenu(winrt::Windows::Foundation::Collections::IMapView<uint64_t, winrt::hstring> peasants);

HWND _trayIconWndProc;
Copy link
Member

Choose a reason for hiding this comment

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

naming this WndProc seems weird - makes me thing it's a handle to the actual wndproc function itself. maybe just

Suggested change
HWND _trayIconWndProc;
HWND _trayIconHwnd;

@@ -20,9 +22,41 @@ TrayIcon::TrayIcon(const HWND owningHwnd) :

TrayIcon::~TrayIcon()
{
DestroyWindow(_trayIconWndProc);
Copy link
Member

Choose a reason for hiding this comment

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

If you make this member a wil::unique_hwnd, it'll clean itself up for you 😉

Comment on lines 42 to 47
WS_DISABLED,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
HWND_MESSAGE,
Copy link
Member

Choose a reason for hiding this comment

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

IIRC, HWND_MESSAGE is enough to make it totally uninteractable. Though, in the past we've also done:

                hwnd = CreateWindowExW(
                    0, PSEUDO_WINDOW_CLASS, nullptr, WS_OVERLAPPEDWINDOW, 0, 0, 0, 0, HWND_DESKTOP, nullptr, nullptr, nullptr);

@ghost ghost added the Needs-Author-Feedback The original author of the issue/PR needs to come back and respond to something label Aug 18, 2021
{
WNDCLASSW wc{};
wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
wc.hInstance = reinterpret_cast<HINSTANCE>(&__ImageBase);
Copy link
Member

Choose a reason for hiding this comment

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

Huh, i suspect this got copied from some other Cascadia stuff. Surprised it wasn't using a wil helper!

@ghost ghost removed the Needs-Author-Feedback The original author of the issue/PR needs to come back and respond to something label Aug 18, 2021
@@ -23,6 +23,37 @@ TrayIcon::~TrayIcon()
RemoveIconFromTray();
}

void TrayIcon::CreateWindowProcess()
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
void TrayIcon::CreateWindowProcess()
void TrayIcon::CreateWindow()

This is sufficient -- it's not a process, after all! 😄


LRESULT CALLBACK TrayIcon::_WindowProc(HWND window, UINT message, WPARAM wparam, LPARAM lparam) noexcept
{
return DefWindowProc(window, message, wparam, lparam);
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 you can actually just literally set, lpfnWndProc = DefWindowProcW above! No need for all this ^^

@vefatica
Copy link

vefatica commented Aug 20, 2021

I don't know if it has been suggested or considered, but if the tray icon gets a window process, it might process WM_MOUSEMOVE by updating NOTIFYICONDATAW::szTip, perhaps with the caption of the current tab.

@leonMSFT
Copy link
Contributor Author

I don't know if it has been suggested or considered, but if the tray icon gets a window process, it might process WM_MOUSEMOVE by updating NOTIFYICONDATAW::szTip, perhaps with the caption of the current tab.

Oh whoa that's a really weird interaction, I'm curious where you've encountered this!
Though, I've given the tray icon window WS_DISABLED to prevent it from receiving user input, and HWND_MESSAGE to make it invisible and ignore broadcast messages, so I believe it should be sufficient?

@vefatica
Copy link

Oh whoa that's a really weird interaction, I'm curious where you've encountered this!
Though, I've given the tray icon window WS_DISABLED to prevent it from receiving user input, and HWND_MESSAGE to make it invisible and ignore broadcast messages, so I believe it should be sufficient?

I've done it several times. In a plugin for a console app (TCC interpreter from JPSoft) I do these things (in various places)

WNDCLASS wndclass = {0}; // global

wndclass.lpfnWndProc = TrayMeWndProc;
wndclass.hInstance = hThisDll;
wndclass.lpszClassName = TRAYME_WND_CLASS;

// Icon and Tip added later
NOTIFYICONDATA nid = {sizeof(NOTIFYICONDATA), NULL, 0, NIF_TIP | NIF_MESSAGE | NIF_ICON, WM_TRAYMESSAGE, NULL, L"", 0};

// tried adding WS_DISABLED; it doesn't hurt
nid.hWnd = hWndTrayMe = CreateWindowEx (0, TRAYME_WND_CLASS, szTrayMeWindowName, 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL); 

// in TrayMeWndProc
case WM_MOUSEMOVE 
        //if ( (dwUtil = GetTickCount()) - dwLastUpdate > 500 ) // see note below
	{
		if ( GetConsoleTitle(szConTitle, MAX_PATH) > 127 ) // shorten with ellipsis in the middle
		{
		        nExtra = lstrlenW(szConTitle) - 127; // nExtra > 0
			szConTitle[61] = L' ';
			szConTitle[62] = szConTitle[63] = szConTitle[64] = L'.';
			szConTitle[65] = L' ';
			lstrcpy(szConTitle + 66, szConTitle + 66 + nExtra); // overlapping copy seems OK
		}
		lstrcpy(nid.szTip, szConTitle);
		Shell_NotifyIcon(NIM_MODIFY, &nid);
	        //dwLastUpdate = dwUtil; 
	}
	return 0;

I first did this in 2004 and on Windows XP and on a much slower machine. I don't recall if the timing mechanism (commented out) was necessary. It doesn't seem necessary today.

Since nid.szTip is only 128 WCHARs, I shorten the Caption if necessary. It winds up "first_part ... last_part".

I also process WM_LBUTTONDOWN (restore, tray icon only shows when minimized/hidden) and WM_RBUTTONDOWN (show a menu of things to do).

I hope that answers your question.

@vefatica
Copy link

vefatica commented Aug 20, 2021

I failed to mention that "case WM_MOUSEMOVE" (WM_LBUTTONDOWN and WM_RIGHTBUTTONDOWN too) is inside

switch (iMsg)
	{
		case WM_TRAYMESSAGE : 
			switch (lParam)

@leonMSFT
Copy link
Contributor Author

Ahh, sorry I misunderstood, I was under the impression that you were trying to let me know that there may be a bug to watch out for where WM_MOUSEMOVE would update szTip, but now I understand that you were suggesting it could be a feature! 😄

@vefatica
Copy link

Right ... just suggesting a feature.

@zadjii-msft zadjii-msft added the AutoMerge Marked for automatic merge by the bot when requirements are met label Aug 20, 2021
@ghost
Copy link

ghost commented Aug 20, 2021

Hello @zadjii-msft!

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 0c901ed into main Aug 20, 2021
@ghost ghost deleted the dev/lelian/notifyicon/withwindowproc branch August 20, 2021 23:24
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-Bug It either shouldn't be doing this or needs an investigation. Product-Terminal The new Windows Terminal.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

right-clicking the tray icon focuses terminal *and* opens menu
4 participants