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
This commit is contained in:
Sale Djenic 2021-08-23 13:18:17 +02:00 committed by Michał
parent db826f58cf
commit 80e2534df4
2 changed files with 137 additions and 2 deletions

View File

@ -5,7 +5,7 @@
#include <QHash>
#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<uint, QString> m_identifiers;
private:
bool initNotificationWin();
void stringToLimitedWCharArray(QString in, wchar_t* target, int maxLength);
private:
HWND m_hwnd;
#elif defined Q_OS_MACOS
private:

View File

@ -1,10 +1,23 @@
#include "DOtherSide/StatusNotification/StatusOSNotification.h"
#ifdef Q_OS_WIN
#include <shellapi.h>
#include <stdlib.h>
#include <string.h>
#include <winuser.h>
#include <comdef.h>
static const UINT NOTIFYICONID = 0;
static std::pair<HWND, StatusOSNotification *> 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<HINSTANCE>(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);