[feat] add configuration to minimize to system tray when clicking the close button, refs #4

This commit is contained in:
dijunkun
2025-10-22 17:21:47 +08:00
parent 5fed09c1aa
commit 2f0b0ffc22
12 changed files with 2326 additions and 1940 deletions

112
src/gui/tray/win_tray.cpp Normal file
View File

@@ -0,0 +1,112 @@
#include "win_tray.h"
#include <SDL3/SDL.h>
#include "localization.h"
// callback for the message-only window that handles tray icon messages
static LRESULT CALLBACK MsgWndProc(HWND hwnd, UINT msg, WPARAM wParam,
LPARAM lParam) {
WinTray* tray =
reinterpret_cast<WinTray*>(GetWindowLongPtr(hwnd, GWLP_USERDATA));
if (!tray) {
return DefWindowProc(hwnd, msg, wParam, lParam);
}
if (msg == WM_TRAY_CALLBACK) {
MSG tmpMsg = {};
tmpMsg.message = msg;
tmpMsg.wParam = wParam;
tmpMsg.lParam = lParam;
tray->HandleTrayMessage(&tmpMsg);
return 0;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
WinTray::WinTray(HWND app_hwnd, HICON icon, const std::wstring& tooltip,
int language_index)
: app_hwnd_(app_hwnd),
icon_(icon),
tip_(tooltip),
hwnd_message_only_(nullptr),
language_index_(language_index) {
WNDCLASS wc = {};
wc.lpfnWndProc = MsgWndProc;
wc.hInstance = GetModuleHandle(nullptr);
wc.lpszClassName = L"TrayMessageWindow";
RegisterClass(&wc);
// create a message-only window to receive tray messages
hwnd_message_only_ =
CreateWindowEx(0, wc.lpszClassName, L"TrayMsg", 0, 0, 0, 0, 0,
HWND_MESSAGE, nullptr, wc.hInstance, nullptr);
// store pointer to this WinTray instance in window data
SetWindowLongPtr(hwnd_message_only_, GWLP_USERDATA,
reinterpret_cast<LONG_PTR>(this));
// initialize NOTIFYICONDATA structure
ZeroMemory(&nid_, sizeof(nid_));
nid_.cbSize = sizeof(nid_);
nid_.hWnd = hwnd_message_only_;
nid_.uID = 1;
nid_.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
nid_.uCallbackMessage = WM_TRAY_CALLBACK;
nid_.hIcon = icon_;
wcsncpy_s(nid_.szTip, tip_.c_str(), _TRUNCATE);
}
WinTray::~WinTray() {
RemoveTrayIcon();
if (hwnd_message_only_) DestroyWindow(hwnd_message_only_);
}
void WinTray::MinimizeToTray() {
Shell_NotifyIcon(NIM_ADD, &nid_);
// hide application window
ShowWindow(app_hwnd_, SW_HIDE);
}
void WinTray::RemoveTrayIcon() { Shell_NotifyIcon(NIM_DELETE, &nid_); }
bool WinTray::HandleTrayMessage(MSG* msg) {
if (!msg || msg->message != WM_TRAY_CALLBACK) return false;
switch (LOWORD(msg->lParam)) {
case WM_LBUTTONDBLCLK:
case WM_LBUTTONUP: {
ShowWindow(app_hwnd_, SW_SHOW);
SetForegroundWindow(app_hwnd_);
break;
}
case WM_RBUTTONUP: {
POINT pt;
GetCursorPos(&pt);
HMENU menu = CreatePopupMenu();
AppendMenuW(menu, MF_STRING, 1001,
localization::exit_program[language_index_]);
SetForegroundWindow(hwnd_message_only_);
int cmd =
TrackPopupMenu(menu, TPM_RETURNCMD | TPM_NONOTIFY | TPM_LEFTALIGN,
pt.x, pt.y, 0, hwnd_message_only_, nullptr);
DestroyMenu(menu);
// handle menu command
if (cmd == 1001) {
// exit application
SDL_Event event;
event.type = SDL_EVENT_QUIT;
SDL_PushEvent(&event);
} else if (cmd == 1002) {
ShowWindow(app_hwnd_, SW_SHOW); // show main window
SetForegroundWindow(app_hwnd_);
}
break;
}
}
return true;
}