QSystemTrayIcon/X11: Create tray icon window when system tray appears

... and destroy it otherwise.

Fixes: QTBUG-61898
Fixes: QTBUG-73459
Done-with: Gatis Paeglis <gatis.paeglis@qt.io>
Change-Id: I6bd8f397f7ccdb123f6a60d4fa466f7b0d760dfc
Reviewed-by: Gatis Paeglis <gatis.paeglis@qt.io>
This commit is contained in:
Alexander Volkov 2019-02-04 18:42:35 +03:00 committed by Gatis Paeglis
parent de854aa37f
commit 2947435d87
2 changed files with 57 additions and 22 deletions

View File

@ -69,6 +69,7 @@
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
class QSystemTrayIconSys; class QSystemTrayIconSys;
class QSystemTrayWatcher;
class QPlatformSystemTrayIcon; class QPlatformSystemTrayIcon;
class QToolButton; class QToolButton;
class QLabel; class QLabel;
@ -90,6 +91,8 @@ public:
void showMessage_sys(const QString &title, const QString &msg, const QIcon &icon, void showMessage_sys(const QString &title, const QString &msg, const QIcon &icon,
QSystemTrayIcon::MessageIcon msgIcon, int msecs); QSystemTrayIcon::MessageIcon msgIcon, int msecs);
void destroyIcon();
static bool isSystemTrayAvailable_sys(); static bool isSystemTrayAvailable_sys();
static bool supportsMessages_sys(); static bool supportsMessages_sys();
@ -101,6 +104,7 @@ public:
QSystemTrayIconSys *sys; QSystemTrayIconSys *sys;
QPlatformSystemTrayIcon *qpa_sys; QPlatformSystemTrayIcon *qpa_sys;
bool visible; bool visible;
QSystemTrayWatcher *trayWatcher;
private: private:
void install_sys_qpa(); void install_sys_qpa();

View File

@ -92,9 +92,6 @@ protected:
virtual void resizeEvent(QResizeEvent *) override; virtual void resizeEvent(QResizeEvent *) override;
virtual void moveEvent(QMoveEvent *) override; virtual void moveEvent(QMoveEvent *) override;
private slots:
void systemTrayWindowChanged(QScreen *screen);
private: private:
QSystemTrayIcon *q; QSystemTrayIcon *q;
}; };
@ -116,15 +113,6 @@ QSystemTrayIconSys::QSystemTrayIconSys(QSystemTrayIcon *qIn)
setMouseTracking(true); setMouseTracking(true);
} }
void QSystemTrayIconSys::systemTrayWindowChanged(QScreen *)
{
if (!locateSystemTray()) {
QBalloonTip::hideBalloon();
hide(); // still no luck
destroy();
}
}
QRect QSystemTrayIconSys::globalGeometry() const QRect QSystemTrayIconSys::globalGeometry() const
{ {
return QRect(mapToGlobal(QPoint(0, 0)), size()); return QRect(mapToGlobal(QPoint(0, 0)), size());
@ -199,10 +187,41 @@ void QSystemTrayIconSys::resizeEvent(QResizeEvent *event)
} }
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
class QSystemTrayWatcher: public QObject
{
Q_OBJECT
public:
QSystemTrayWatcher(QSystemTrayIcon *trayIcon)
: QObject(trayIcon)
, mTrayIcon(trayIcon)
{
// This code uses string-based syntax because we want to connect to a signal
// which is defined in XCB plugin - QXcbNativeInterface::systemTrayWindowChanged().
connect(qGuiApp->platformNativeInterface(), SIGNAL(systemTrayWindowChanged(QScreen*)),
this, SLOT(systemTrayWindowChanged(QScreen*)));
}
private slots:
void systemTrayWindowChanged(QScreen *)
{
auto icon = static_cast<QSystemTrayIconPrivate *>(QObjectPrivate::get(mTrayIcon));
icon->destroyIcon();
if (icon->visible && locateSystemTray()) {
icon->sys = new QSystemTrayIconSys(mTrayIcon);
icon->sys->show();
}
}
private:
QSystemTrayIcon *mTrayIcon = nullptr;
};
////////////////////////////////////////////////////////////////////////////
QSystemTrayIconPrivate::QSystemTrayIconPrivate() QSystemTrayIconPrivate::QSystemTrayIconPrivate()
: sys(0), : sys(0),
qpa_sys(QGuiApplicationPrivate::platformTheme()->createPlatformSystemTrayIcon()), qpa_sys(QGuiApplicationPrivate::platformTheme()->createPlatformSystemTrayIcon()),
visible(false) visible(false),
trayWatcher(nullptr)
{ {
} }
@ -213,16 +232,21 @@ QSystemTrayIconPrivate::~QSystemTrayIconPrivate()
void QSystemTrayIconPrivate::install_sys() void QSystemTrayIconPrivate::install_sys()
{ {
Q_Q(QSystemTrayIcon);
if (qpa_sys) { if (qpa_sys) {
install_sys_qpa(); install_sys_qpa();
return; return;
} }
Q_Q(QSystemTrayIcon);
if (!sys && locateSystemTray()) { if (!sys) {
sys = new QSystemTrayIconSys(q); if (!trayWatcher)
QObject::connect(QGuiApplication::platformNativeInterface(), SIGNAL(systemTrayWindowChanged(QScreen*)), trayWatcher = new QSystemTrayWatcher(q);
sys, SLOT(systemTrayWindowChanged(QScreen*)));
sys->show(); if (locateSystemTray()) {
sys = new QSystemTrayIconSys(q);
sys->show();
}
} }
} }
@ -241,14 +265,21 @@ void QSystemTrayIconPrivate::remove_sys()
remove_sys_qpa(); remove_sys_qpa();
return; return;
} }
destroyIcon();
}
void QSystemTrayIconPrivate::destroyIcon()
{
if (!sys) if (!sys)
return; return;
QBalloonTip::hideBalloon(); QBalloonTip::hideBalloon();
sys->hide(); // this should do the trick, but... sys->hide();
delete sys; // wm may resize system tray only for DestroyEvents delete sys;
sys = 0; sys = nullptr;
} }
void QSystemTrayIconPrivate::updateIcon_sys() void QSystemTrayIconPrivate::updateIcon_sys()
{ {
if (qpa_sys) { if (qpa_sys) {