TrayIcon::TrayIcon(
HWND hWnd, UINT trayID, HICON hIcon,
- const std::wstring& tooltip, bool show)
- : initialized_(false), iconVisible_(false)
+ const std::wstring& tooltip, bool show,
+ int callbackId)
+ : initialized_(false), iconVisible_(false), callbackId_(callbackId)
{
Init(hWnd, trayID, hIcon, tooltip, show);
}
void TrayIcon::Init(
HWND hWnd, UINT trayID, HICON hIcon,
- const std::wstring& tooltip, bool show)
+ const std::wstring& tooltip, bool show,
+ int callbackId)
{
+ callbackId_ = callbackId;
if (!hIcon) {
hIcon_ = LoadIcon(0, IDI_APPLICATION);
} else {
void TrayIcon::ShowPopup(
const std::wstring& title,
- const std::wstring& text,
- int callbackID) const
+ const std::wstring& text) const
{
if (!initialized_) {
TrayIconPopup popup;
tnid.uID = trayID_;
tnid.uFlags = NIF_INFO | NIF_SHOWTIP;
tnid.dwInfoFlags = NIIF_INFO | NIIF_NOSOUND | NIIF_LARGE_ICON | NIIF_RESPECT_QUIET_TIME;
- if (callbackID != 0) {
- tnid.uCallbackMessage = callbackID;
- tnid.uFlags |= NIF_MESSAGE;
- }
tnid.uTimeout = 10 * 1000;
StringCchCopy(tnid.szInfoTitle, ARRAY_SIZE(tnid.szInfoTitle), title.c_str());
StringCchCopy(tnid.szInfo, ARRAY_SIZE(tnid.szInfo), text.c_str());
tnid.uID = trayID_;
tnid.uFlags = NIF_ICON | NIF_TIP | NIF_MESSAGE | NIF_SHOWTIP;
tnid.hIcon = hIcon_;
- tnid.uCallbackMessage = WM_TRAYICON;
+ tnid.uCallbackMessage = callbackId_;
if (SUCCEEDED(StringCchCopy(tnid.szTip, ARRAY_SIZE(tnid.szTip), tooltip_.c_str()))) {
- return Shell_NotifyIcon(NIM_ADD, &tnid) != 0;
+ return Shell_NotifyIconW(NIM_ADD, &tnid) != 0;
}
return false;
}
public:
TrayIcon();
TrayIcon(HWND hWnd, UINT trayID, HICON hIcon, const std::wstring& tooltip,
- bool show);
+ bool show, int callbackId = WM_TRAYICON);
~TrayIcon();
void Init(HWND hWnd, UINT trayID, HICON hIcon, const std::wstring& tooltip,
- bool show);
+ bool show, int callbackId = WM_TRAYICON);
void Hide();
void Show();
bool IsShown() const noexcept { return iconVisible_; }
void ChangeText(const std::wstring& tooltip);
void ShowPopup(
const std::wstring& title,
- const std::wstring& text,
- int callbackID = 0) const;
+ const std::wstring& text) const;
private:
void DestroyTrayIcon();
bool RemoveNotifyIcon();
bool ChangeText();
+
mutable std::vector<TrayIconPopup> popupQueue_;
+ int callbackId_;
bool initialized_;
bool iconVisible_;
UINT trayID_;
return false;
}
- if (!muteCtrl_.Init(hWnd_, &trayIcon_)) {
+ if (!muteCtrl_.Init(hWnd_, &wmTray_)) {
return false;
}
ShowWindowsError(_T("LoadIcon"));
return false;
}
- trayIcon_.Init(hWnd_, 0, hTrayIcon_, L"WinMute", true);
+ hUpdateIcon_ = LoadIconW(hglobInstance, MAKEINTRESOURCE(IDI_APPUPDATE));
+ if (hUpdateIcon_ == nullptr) {
+ ShowWindowsError(_T("LoadIcon"));
+ return false;
+ }
+ wmTray_.Init(hWnd_, 0, hTrayIcon_, L"WinMute", true);
+ updateTray_.Init(hWnd_, 1, hUpdateIcon_, L"WinMute Update", false, WM_WINMUTE_UPDATE_POPUP);
quietHours_.Init(hWnd_, settings_);
if (settings_.QueryValue(SettingsKey::MUTE_ON_RDP)
&& IsCurrentSessionRemoteable()) {
- trayIcon_.ShowPopup(
+ wmTray_.ShowPopup(
i18n_.GetTranslationW("popup.remote-session-detected.title"),
i18n_.GetTranslationW("popup.remote-session-detected.text"));
muteCtrl_.SetMute(true);
btDetector_.Unload();
} else {
if (!btDetector_.Init(hWnd_)) {
- trayIcon_.ShowPopup(
+ wmTray_.ShowPopup(
i18n_.GetTranslationW("popup.bluetooth-muting-disabled.title"),
i18n_.GetTranslationW("popup.bluetooth-muting-disabled.text"));
settings_.SetValue(SettingsKey::MUTE_ON_BLUETOOTH, FALSE);
wifiDetector_.Unload();
} else {
if (!wifiDetector_.Init(hWnd_)) {
- trayIcon_.ShowPopup(
+ wmTray_.ShowPopup(
i18n_.GetTranslationW("popup.wlan-muting-disabled.title"),
i18n_.GetTranslationW("popup.wlan-muting-disabled.text"));
settings_.SetValue(SettingsKey::MUTE_ON_WLAN, FALSE);
return;
}
if (!updateChecker->GetUpdateInfo(updateInfo_)) {
- trayIcon_.ShowPopup(
+ wmTray_.ShowPopup(
i18n_.GetTranslationW("popup.error.update-check-failed.title"),
i18n_.GetTranslationW("popup.error.update-check-failed.text"));
} else if (updateInfo_.beta.shouldUpdate && betaUpdates) {
const std::wstring popupText = std::vformat(
i18n_.GetTranslationW("popup.update-available-beta.text"),
std::make_wformat_args(updateInfo_.currentVersion));
- trayIcon_.ShowPopup(popupTitle, popupText, WM_WINMUTE_UPDATE_POPUP);
+ updateTray_.Show();
+ updateTray_.ShowPopup(popupTitle, popupText);
} else if (updateInfo_.beta.shouldUpdate) {
const std::wstring popupTitle = std::vformat(
i18n_.GetTranslationW("popup.update-available.title"),
const std::wstring popupText = std::vformat(
i18n_.GetTranslationW("popup.update-available.text"),
std::make_wformat_args(updateInfo_.currentVersion));
- trayIcon_.ShowPopup(popupTitle, popupText, WM_WINMUTE_UPDATE_POPUP);
+ updateTray_.Show();
+ updateTray_.ShowPopup(popupTitle, popupText);
}
}
LRESULT WinMute::OnTrayIcon(HWND hWnd, WPARAM, LPARAM lParam)
{
- switch (lParam) {
- case WM_LBUTTONUP:
- case WM_RBUTTONUP:
- {
+ if (LOWORD(lParam) == WM_CONTEXTMENU ||
+ lParam == WM_LBUTTONUP ||
+ lParam == WM_RBUTTONUP) {
POINT p = { 0 };
GetCursorPos(&p);
SetForegroundWindow(hWnd);
GetSubMenu(hTrayMenu_, 0),
TPM_NONOTIFY | TPM_TOPALIGN | TPM_LEFTALIGN,
p.x, p.y, hWnd_, nullptr);
- break;
- }
- default:
- break;
}
return TRUE;
}
if (msg == WM_WINMUTE_QUIETHOURS_START) {
muteCtrl_.NotifyQuietHours(true);
if (settings_.QueryValue(SettingsKey::QUIETHOURS_NOTIFICATIONS)) {
- trayIcon_.ShowPopup(
+ wmTray_.ShowPopup(
i18n_.GetTranslationW("popup.quiet-hours-started.title"),
i18n_.GetTranslationW("popup.quiet-hours-started.text"));
}
} else if (msg == WM_WINMUTE_QUIETHOURS_END) {
muteCtrl_.NotifyQuietHours(false);
if (settings_.QueryValue(SettingsKey::QUIETHOURS_NOTIFICATIONS)) {
- trayIcon_.ShowPopup(
+ wmTray_.ShowPopup(
i18n_.GetTranslationW("popup.quiet-hours-ended.title"),
i18n_.GetTranslationW("popup.quiet-hours-ended.text"));
}
i18n_.GetTranslationW("popup.wlan-is-on-mute-list.text"),
std::make_wformat_args(wifiName));
}
- trayIcon_.ShowPopup(
+ wmTray_.ShowPopup(
i18n_.GetTranslationW("popup.workstation-muted.title"),
popupMsg);
delete[] wifiName;
nullptr, nullptr, SW_SHOW);
}
}
+ if (lParam == NIN_BALLOONHIDE || lParam == NIN_BALLOONTIMEOUT || lParam == NIN_BALLOONUSERCLICK) {
+ updateTray_.Hide();
+ }
return 0;
}
return OnSettingChange(hWnd, wParam, lParam);
default:
if (msg == uTaskbarRestart) { // Restore trayicon if explorer.exe crashes
- trayIcon_.Hide();
- trayIcon_.Show();
+ wmTray_.Hide();
+ wmTray_.Show();
}
break;
}
HMENU hTrayMenu_;
HICON hAppIcon_;
HICON hTrayIcon_;
+ HICON hUpdateIcon_;
struct MuteConfig {
MuteConfig();
bool muteOnBluetooth;
} muteConfig_;
- TrayIcon trayIcon_;
+ TrayIcon wmTray_;
+ TrayIcon updateTray_;
WifiDetector wifiDetector_;
WMSettings& settings_;
WMi18n &i18n_;
IDI_SETTINGS ICON "icons\\settings.ico"
+IDI_APPUPDATE ICON "icons\\app-update.ico"
+
/////////////////////////////////////////////////////////////////////////////
//
<ResourceCompile Include="WinMute.rc" />
</ItemGroup>
<ItemGroup>
+ <Image Include="icons\app-update.ico" />
<Image Include="icons\app.ico" />
<Image Include="icons\settings.ico" />
</ItemGroup>
<Image Include="icons\settings.ico">
<Filter>Resource Files</Filter>
</Image>
+ <Image Include="icons\app-update.ico">
+ <Filter>Resource Files</Filter>
+ </Image>
</ItemGroup>
<ItemGroup>
<ClCompile Include="VistaAudio.cpp">
--- /dev/null
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ width="512"
+ height="512"
+ viewBox="0 0 512 512"
+ version="1.1"
+ id="svg1"
+ inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)"
+ sodipodi:docname="app-update.svg"
+ inkscape:export-filename="app-update-512.png"
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:svg="http://www.w3.org/2000/svg">
+ <sodipodi:namedview
+ id="namedview1"
+ pagecolor="#505050"
+ bordercolor="#ffffff"
+ borderopacity="1"
+ inkscape:showpageshadow="0"
+ inkscape:pageopacity="0"
+ inkscape:pagecheckerboard="1"
+ inkscape:deskcolor="#505050"
+ inkscape:document-units="px"
+ showguides="true"
+ inkscape:zoom="1.1228082"
+ inkscape:cx="27.164034"
+ inkscape:cy="216.86696"
+ inkscape:window-width="2560"
+ inkscape:window-height="1009"
+ inkscape:window-x="-8"
+ inkscape:window-y="-8"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="layer1">
+ <sodipodi:guide
+ position="-301.02829,261.98278"
+ orientation="0,-1"
+ id="guide8"
+ inkscape:locked="false" />
+ <sodipodi:guide
+ position="-304.59342,361.48454"
+ orientation="0,-1"
+ id="guide9"
+ inkscape:locked="false" />
+ <sodipodi:guide
+ position="-363.37461,162.87538"
+ orientation="0,-1"
+ id="guide10"
+ inkscape:locked="false" />
+ <sodipodi:guide
+ position="-244.92161,460.34381"
+ orientation="0,-1"
+ id="guide11"
+ inkscape:locked="false" />
+ <sodipodi:guide
+ position="-272.53096,62.23486"
+ orientation="0,-1"
+ id="guide12"
+ inkscape:locked="false" />
+ <sodipodi:guide
+ position="50.76557,477.26566"
+ orientation="1,0"
+ id="guide13"
+ inkscape:locked="false" />
+ <sodipodi:guide
+ position="362.48398,358.81267"
+ orientation="1,0"
+ id="guide14"
+ inkscape:locked="false" />
+ <sodipodi:guide
+ position="224.43726,374.8439"
+ orientation="1,0"
+ id="guide15"
+ inkscape:locked="false" />
+ <sodipodi:guide
+ position="314.25338,449.02337"
+ orientation="1,0"
+ id="guide16"
+ inkscape:locked="false" />
+ <sodipodi:guide
+ position="137.1561,394.43763"
+ orientation="1,0"
+ id="guide17"
+ inkscape:locked="false" />
+ <sodipodi:guide
+ position="98.243542,394.2337"
+ orientation="1,0"
+ id="guide18"
+ inkscape:locked="false" />
+ <sodipodi:guide
+ position="299.13899,400.53137"
+ orientation="1,0"
+ id="guide19"
+ inkscape:locked="false" />
+ </sodipodi:namedview>
+ <defs
+ id="defs1">
+ <rect
+ x="391.87458"
+ y="40.968706"
+ width="56.109314"
+ height="357.14024"
+ id="rect26" />
+ <linearGradient
+ id="swatch22">
+ <stop
+ style="stop-color:#000000;stop-opacity:1;"
+ offset="0.45652175"
+ id="stop22" />
+ </linearGradient>
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#swatch22"
+ id="radialGradient22"
+ cx="206.62624"
+ cy="250.03953"
+ fx="206.62624"
+ fy="250.03953"
+ r="156.80599"
+ gradientTransform="matrix(0.99619803,0,0,1.5243246,0.34028102,-119.52623)"
+ gradientUnits="userSpaceOnUse" />
+ </defs>
+ <g
+ inkscape:label="Ebene 1"
+ inkscape:groupmode="layer"
+ id="layer1">
+ <path
+ d="m 298.6558,51.763601 -159.39296,100.351939 -89.814619,0.60253 0.728548,195.59663 88.693091,1.65266 158.8987,122.40086 z"
+ style="display:inline;fill:url(#radialGradient22);stroke:#e7e7e7;stroke-width:15;stroke-linecap:round;stroke-linejoin:bevel;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
+ id="path26"
+ sodipodi:nodetypes="ccccccc" />
+ <path
+ style="display:inline;fill:#132e3f;fill-opacity:1;stroke:#c0ccf8;stroke-width:8;stroke-dasharray:none;stroke-opacity:1"
+ d="M 447.89768,421.69014 C 235.70893,209.26395 63.39014,45.098196 65.227745,44.931141 L 43.147019,66.306118 421.91096,445.64954 Z"
+ id="path19"
+ inkscape:label="slash"
+ sodipodi:nodetypes="ccccc" />
+ <text
+ xml:space="preserve"
+ id="text26"
+ style="font-size:43.5785px;white-space:pre;shape-inside:url(#rect26);display:none;fill:#122e3f;fill-opacity:1;stroke:#ffffff;stroke-width:1.16262;stroke-linecap:round;stroke-linejoin:bevel;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
+ inkscape:label="Exclamation Mark"
+ transform="matrix(6.992757,0,0,6.7710102,-2420.2895,-308.68022)"><tspan
+ x="391.875"
+ y="81.20562"
+ id="tspan2"><tspan
+ style="font-family:'Cascadia Code';-inkscape-font-specification:'Cascadia Code'"
+ id="tspan1">!</tspan></tspan></text>
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer2"
+ inkscape:label="Ebene 2">
+ <path
+ style="fill:#27fb86;fill-opacity:0.662136;stroke:#00922d;stroke-width:5.43457;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1;paint-order:markers fill stroke"
+ d="m 371.6508,269.07023 c 94.30545,0 94.73608,0 94.73608,0 V 124.9009 h 41.76999 L 412.77487,4.3970993 315.67039,127.07704 h 49.09051 v 141.99319 z"
+ id="path1" />
+ </g>
+</svg>
inkscape:document-units="px"
showguides="true"
inkscape:zoom="1.1228082"
- inkscape:cx="18.257793"
- inkscape:cy="217.75758"
+ inkscape:cx="26.27341"
+ inkscape:cy="216.86696"
inkscape:window-width="2560"
inkscape:window-height="1009"
inkscape:window-x="-8"
transform="matrix(6.992757,0,0,6.7710102,-2420.2895,-308.68022)"><tspan
x="391.875"
y="81.20562"
- id="tspan2"><tspan
+ id="tspan4"><tspan
style="font-family:'Cascadia Code';-inkscape-font-specification:'Cascadia Code'"
- id="tspan1">!</tspan></tspan></text>
+ id="tspan3">!</tspan></tspan></text>
</g>
</svg>
#define IDD_MANAGE_ENDPOINTS 135
#define IDD_DIALOG2 137
#define IDD_MANAGE_ENDPOINTS_ADD 137
+#define IDI_APP_UPDATE 141
+#define IDI_APPUPDATE 141
#define IDC_LINK_HOMEPAGE 1001
#define IDC_LINK_SUPPORT 1002
#define IDC_LINK_PROJECT 1002
#define IDC_CHECK_FOR_UPDATES_ON_STARTUP 1013
#define IDC_OPENLOG 1014
#define IDC_LICENSETEXT 1015
-#define IDC_CHECK_FOR_UPDATES_ON_STARTUP2 1015
#define IDC_CHECK_FOR_BETA_UPDATES 1015
#define IDC_ABOUT_TAB 1016
#define IDC_ABOUTTEXT 1019
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
-#define _APS_NEXT_RESOURCE_VALUE 141
+#define _APS_NEXT_RESOURCE_VALUE 142
#define _APS_NEXT_COMMAND_VALUE 40041
#define _APS_NEXT_CONTROL_VALUE 1072
#define _APS_NEXT_SYMED_VALUE 101