Skip to content

feat(tray): quick-access panel on tray icon left click - #146

Merged
PhoenixNil merged 1 commit into
mainfrom
feature/tray-panel
Oct 3, 2026
Merged

PhoenixNil merged 1 commit into
mainfrom
feature/tray-panel

Conversation

@PhoenixNil

Copy link
Copy Markdown
Owner

What changed

  • Tray panel (Views/TrayPanelWindow, Views/TrayPanelControl, ViewModels/TrayPanelViewModel): left-clicking the tray icon opens a borderless acrylic panel above the icon. It has start/stop, the current node with protocol and status, a smart/global routing switch, system proxy and TUN toggles, and buttons for the main window and exit. Clicking the icon again closes it, and so does a light dismiss.
  • ActiveAcrylicBackdrop: a custom SystemBackdrop. The stock DesktopAcrylicBackdrop drops to a flat fallback colour as soon as the window loses activation, and that is exactly when the panel's slide-out starts. The stock backdrop can also get light/dark wrong when the app theme is forced against the system theme.
  • Double-click restores the main window: the panel takes activation on the first click, so Windows may not treat the second click as part of a double-click. IsSecondTrayClick therefore detects a second click within the double-click time, near the same point, on both the shell's click report and the panel's light dismiss.
  • RestoreFromTray now calls SetForegroundWindow: Activate() does not bring a background tray app to the front, so the window sometimes only flashed on the taskbar.
  • Dialogs: DialogService now resolves its XamlRoot through GetDialogXamlRoot. If the window is in the tray or under the panel, it closes the panel and shows the full window before the dialog opens. Example: the TUN elevation prompt started from the panel.
  • Small VM plumbing: MainViewModel.DisplayedServer, a public ControlPanelViewModel.IsCustomConfigActive with change notification, and ShowForJumpList renamed to ShowFullWindow. New strings are in both zh-CN and en-US .resw.

Why

Right now any tray click restores the full window, even for quick actions like toggling the proxy or switching routing mode. The panel handles those without leaving the tray.

Reviewer notes

  • During a double-click the panel shows briefly before the window takes over. That is deliberate: the panel opens on the click itself instead of waiting out the double-click time.
  • The double-click / foreground-lock handling has been compiled but not yet fully verified on a real machine. Please try double-clicking both from the idle tray and with the panel already open.
  • Please also check that the WinRT-heavy panel code works under NativeAOT. The build-x64 CI job covers the publish, and a real run of the AOT build is worth doing.

🤖 Generated with Claude Code

A left click on the tray icon now opens a borderless acrylic panel with
connect/disconnect, the current node, smart/global routing, and the
system proxy / TUN switches. A double-click still restores the main window.

The panel takes activation on the first click, so Windows can miss the
second click of a double-click. The double-click is therefore recognised
in-app: a second click near the same point within the double-click time
closes the panel and restores the window. RestoreFromTray now also calls
SetForegroundWindow, because Activate alone leaves a background tray app
behind the taskbar.

Dialogs raised while the window is hidden or under the panel bring the
full window back first, so they are not left unseen.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 3, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-03T06:39:44.121541Z 51de2d5 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 51de2d52a3

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread MainWindow.xaml.cs
Comment on lines +324 to +327
panel.LightDismissed += (_, _) =>
{
if (IsSecondTrayClick())
CloseTrayPanelAndRestore();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Gate restoration on an actual second left-click

When the panel loses activation within the double-click interval while the pointer remains over the tray icon, this handler treats any light dismiss as a second click because IsSecondTrayClick checks only elapsed time and cursor position. For example, right-clicking the icon to open its context menu or quickly pressing Alt+Tab after opening the panel restores the full main window and steals focus even though no second left-click occurred. Track an actual tray-button event rather than inferring one from every deactivation.

Useful? React with 👍 / 👎.

Comment on lines +161 to +162
var restingY = work.Y + work.Height - margin - visibleBottom;
StartSlide(restingY, SlideInMs, decelerates: true, OnShowCompleted);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Anchor the panel to the actual taskbar edge

The project supports Windows 10, where users can dock the taskbar to the top, left, or right, but this always computes the resting position from the bottom of the primary work area (and the adjacent code always anchors it to the right). In those supported layouts the panel opens in an unrelated bottom-right corner and slides from the bottom of the display rather than from behind/above the notification area. Derive both the edge and coordinates from the taskbar or tray-icon rectangle.

Useful? React with 👍 / 👎.

@PhoenixNil
PhoenixNil merged commit 391c2f7 into main Oct 3, 2026
6 checks passed
@PhoenixNil
PhoenixNil deleted the feature/tray-panel branch October 3, 2026 13:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant