From 80e2534df4a05a1ab4d56827842bbb8a92d95869 Mon Sep 17 00:00:00 2001 From: Sale Djenic Date: Mon, 23 Aug 2021 13:18:17 +0200 Subject: [PATCH] fix(@desktop/general): (windows) clicking push notification does expand the app but does not open correct channel/chat Windows notifications added in a native way. This change is required as part of the fix for ticket 2996. Fixes: #2996 --- .../StatusNotification/StatusOSNotification.h | 11 +- .../StatusOSNotification.cpp | 128 +++++++++++++++++- 2 files changed, 137 insertions(+), 2 deletions(-) diff --git a/vendor/DOtherSide/lib/include/DOtherSide/StatusNotification/StatusOSNotification.h b/vendor/DOtherSide/lib/include/DOtherSide/StatusNotification/StatusOSNotification.h index 34260407fa..682f1cfdb9 100644 --- a/vendor/DOtherSide/lib/include/DOtherSide/StatusNotification/StatusOSNotification.h +++ b/vendor/DOtherSide/lib/include/DOtherSide/StatusNotification/StatusOSNotification.h @@ -5,7 +5,7 @@ #include #ifdef Q_OS_WIN - +#include "windows.h" #elif defined Q_OS_MACOS class NotificationHelper; #endif @@ -25,6 +25,15 @@ signals: void notificationClicked(QString identifier); #ifdef Q_OS_WIN +public: + QHash m_identifiers; + +private: + bool initNotificationWin(); + void stringToLimitedWCharArray(QString in, wchar_t* target, int maxLength); + +private: + HWND m_hwnd; #elif defined Q_OS_MACOS private: diff --git a/vendor/DOtherSide/lib/src/StatusNotification/StatusOSNotification.cpp b/vendor/DOtherSide/lib/src/StatusNotification/StatusOSNotification.cpp index 23ad89cc19..8e406a3daf 100644 --- a/vendor/DOtherSide/lib/src/StatusNotification/StatusOSNotification.cpp +++ b/vendor/DOtherSide/lib/src/StatusNotification/StatusOSNotification.cpp @@ -1,10 +1,23 @@ #include "DOtherSide/StatusNotification/StatusOSNotification.h" +#ifdef Q_OS_WIN +#include +#include +#include +#include +#include + +static const UINT NOTIFYICONID = 0; + +static std::pair HWND_INSTANCE_PAIR; +#endif + StatusOSNotification::StatusOSNotification(QObject *parent) : QObject(parent) { #ifdef Q_OS_WIN - + m_hwnd = nullptr; + initNotificationWin(); #elif defined Q_OS_MACOS m_notificationHelper = nullptr; initNotificationMacOs(); @@ -21,10 +34,123 @@ StatusOSNotification::~StatusOSNotification() #endif } +#ifdef Q_OS_WIN +LRESULT CALLBACK StatusWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + const int msgInfo = LOWORD(lParam); + + if (hwnd == HWND_INSTANCE_PAIR.first + && HWND_INSTANCE_PAIR.second + && HWND_INSTANCE_PAIR.second->m_identifiers.contains(uMsg) + && msgInfo == NIN_BALLOONUSERCLICK) + { + HWND_INSTANCE_PAIR.second->notificationClicked( + HWND_INSTANCE_PAIR.second->m_identifiers[uMsg]); + return 0; + } + + return DefWindowProc(hwnd, uMsg, wParam, lParam); +} + +void StatusOSNotification::stringToLimitedWCharArray(QString in, wchar_t* target, + int maxLength) +{ + const int length = qMin(maxLength - 1, in.size()); + if (length < in.size()) + in.truncate(length); + in.toWCharArray(target); + target[length] = wchar_t(0); +} + +bool StatusOSNotification::initNotificationWin() +{ + // m_hwnd should be init only once, but that would be a case if we create system + // tray window from here. But since we already have system tray added in the + // app we're just refering to that already added window and listen for events + // on it. HWND of that window may be changed during the runtime and we don't + // have an option to be notified about that, that's why we're searching for + // appropriate HWND each time we need it, and that's why the following two + // lines are commented out. + // + // if (m_hwnd) + // return true; + + const QString cName = "QTrayIconMessageWindowClass"; + LPCSTR className = cName.toStdString().c_str(); + const QString wName = "QTrayIconMessageWindow"; + LPCSTR windowName = wName.toStdString().c_str(); + + const auto appInstance = static_cast(GetModuleHandle(nullptr)); + + WNDCLASSEX wc; + wc.cbSize = sizeof(WNDCLASSEX); + wc.style = CS_HREDRAW | CS_VREDRAW; + wc.lpfnWndProc = StatusWndProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = appInstance; + wc.hCursor = nullptr; + wc.hbrBackground = (HBRUSH)(COLOR_WINDOW); + wc.hIcon = nullptr; + wc.hIconSm = nullptr; + wc.lpszMenuName = nullptr; + wc.lpszClassName = className; + + ATOM atom = RegisterClassEx(&wc); + if (!atom) + printf("StatusOsNotification registering window class failed.\n"); + + m_hwnd = FindWindowExA(0, 0, className, windowName); + if(m_hwnd) + { + HWND_INSTANCE_PAIR = std::make_pair(m_hwnd, this); + return true; + } + + return false; +} +#endif + void StatusOSNotification::showNotification(const QString& title, const QString& message, const QString& identifier) { #ifdef Q_OS_WIN + if (!initNotificationWin()) + { + return; + } + + NOTIFYICONDATA tnd; + memset(&tnd, 0, sizeof(NOTIFYICONDATA)); + tnd.cbSize = sizeof(NOTIFYICONDATA); + tnd.uVersion = NOTIFYICON_VERSION_4; + + QString t = title; + wchar_t wcTitle[64]; + stringToLimitedWCharArray(t, wcTitle, 64); + _bstr_t bT(wcTitle); + const char* cTitle = bT; + + QString m = message; + wchar_t wcMessage[256]; + stringToLimitedWCharArray(m, wcMessage, 256); + _bstr_t bM(wcMessage); + const char* cMessage = bM; + + strncpy_s(tnd.szInfoTitle, sizeof(tnd.szInfoTitle), cTitle, strlen(cTitle)); + strncpy_s(tnd.szInfo, sizeof(tnd.szInfo), cMessage, strlen(cMessage)); + + tnd.uID = NOTIFYICONID; + tnd.hWnd = m_hwnd; + tnd.dwInfoFlags = NIIF_INFO; + tnd.uTimeout = UINT(10000); + tnd.uFlags = NIF_MESSAGE | NIF_INFO | NIF_SHOWTIP; + + uint id = WM_APP + 2 + m_identifiers.size(); + m_identifiers.insert(id, identifier); + tnd.uCallbackMessage = id; + + Shell_NotifyIcon(NIM_MODIFY, &tnd); #elif defined Q_OS_MACOS showNotificationMacOs(title, message, identifier);