fix: tray item identify

https://github.com/linuxdeepin/internal-discussion/issues/616

Change-Id: I6fc26d153e82643720ac21111d52cac26fbcff06
This commit is contained in:
listenerri 2019-01-03 14:46:19 +08:00
parent 3c134e5583
commit f7699e3596
Notes: gerrit 2019-01-03 19:00:34 +08:00
Verified+1: <jenkins@deepin.com>
Code-Review+2: listenerri <listenerri@gmail.com>
Submitted-by: listenerri <listenerri@gmail.com>
Submitted-at: Thu, 03 Jan 2019 19:00:33 +0800
Reviewed-on: https://cr.deepin.io/41076
Project: dde/dde-dock
Branch: refs/heads/master
6 changed files with 169 additions and 94 deletions

View File

@ -111,6 +111,42 @@ bool SNITrayWidget::isValid()
return m_sniInter->isValid();
}
QString SNITrayWidget::toSNIKey(const QString &sniServicePath)
{
QString key;
do {
const QPair<QString, QString> &sap = serviceAndPath(sniServicePath);
key = QDBusInterface(sap.first, sap.second).property("Id").toString();
if (!key.isEmpty()) {
break;
}
key = sniServicePath;
} while (false);
return QString("sni:%1").arg(key);
}
bool SNITrayWidget::isSNIKey(const QString &itemKey)
{
return itemKey.startsWith("sni:");
}
QPair<QString, QString> SNITrayWidget::serviceAndPath(const QString &servicePath)
{
QStringList list = servicePath.split("/");
QPair<QString, QString> pair;
pair.first = list.takeFirst();
for (auto i : list) {
pair.second.append("/");
pair.second.append(i);
}
return pair;
}
void SNITrayWidget::initMenu()
{
qDebug() << "using sni service path:" << m_dbusService;
@ -244,20 +280,6 @@ void SNITrayWidget::paintEvent(QPaintEvent *e)
painter.end();
}
QPair<QString, QString> SNITrayWidget::serviceAndPath(const QString &servicePath)
{
QStringList list = servicePath.split("/");
QPair<QString, QString> pair;
pair.first = list.takeFirst();
for (auto i : list) {
pair.second.append("/");
pair.second.append(i);
}
return pair;
}
QPixmap SNITrayWidget::newIconPixmap(IconType iconType)
{
QPixmap pixmap;

View File

@ -50,9 +50,9 @@ public:
bool isValid();
static QString toSNIKey(const QString &sniServicePath) { return QString("sni:%1").arg(sniServicePath); }
static bool isSNIKey(const QString &itemKey) { return itemKey.startsWith("sni:"); }
static QString toSNIServicePath(QString itemKey) { return itemKey.remove("sni:"); }
static QString toSNIKey(const QString &sniServicePath);
static bool isSNIKey(const QString &itemKey);
static QPair<QString, QString> serviceAndPath(const QString &servicePath);
private Q_SLOTS:
void initMenu();
@ -64,7 +64,6 @@ private Q_SLOTS:
private:
QSize sizeHint() const Q_DECL_OVERRIDE;
void paintEvent(QPaintEvent *e) Q_DECL_OVERRIDE;
QPair<QString, QString> serviceAndPath(const QString &servicePath);
QPixmap newIconPixmap(IconType iconType);
private:

View File

@ -166,11 +166,9 @@ bool TrayPlugin::itemAllowContainer(const QString &itemKey)
bool TrayPlugin::itemIsInContainer(const QString &itemKey)
{
const QString widKey = getWindowClass(XWindowTrayWidget::toWinId(itemKey));
const QString &key = "container_" + itemKey;
return m_proxyInter
->getValue(this, widKey.isEmpty() ? itemKey : widKey, false)
.toBool();
return m_proxyInter->getValue(this, key, false).toBool();
}
int TrayPlugin::itemSortKey(const QString &itemKey)
@ -202,9 +200,9 @@ void TrayPlugin::setSortKey(const QString &itemKey, const int order)
void TrayPlugin::setItemIsInContainer(const QString &itemKey, const bool container)
{
const QString widKey = getWindowClass(XWindowTrayWidget::toWinId(itemKey));
const QString &key = "container_" + itemKey;
m_proxyInter->saveValue(this, widKey.isEmpty() ? itemKey : widKey, container);
m_proxyInter->saveValue(this, key, container);
}
void TrayPlugin::refreshIcon(const QString &itemKey)
@ -244,27 +242,6 @@ const QVariant TrayPlugin::getValue(const QString &key, const QVariant &fallback
return m_proxyInter->getValue(this, key, fallback);
}
const QString TrayPlugin::getWindowClass(quint32 winId)
{
auto *connection = QX11Info::connection();
auto *reply = new xcb_icccm_get_wm_class_reply_t;
auto *error = new xcb_generic_error_t;
auto cookie = xcb_icccm_get_wm_class(connection, winId);
auto result = xcb_icccm_get_wm_class_reply(connection, cookie, reply, &error);
QString ret;
if (result == 1) {
ret = QString("%1-%2").arg(reply->class_name).arg(reply->instance_name);
xcb_icccm_get_wm_class_reply_wipe(reply);
}
delete reply;
delete error;
return ret;
}
bool TrayPlugin::isSystemTrayItem(const QString &itemKey)
{
AbstractTrayWidget * const trayWidget = m_trayMap.value(itemKey, nullptr);
@ -297,32 +274,34 @@ void TrayPlugin::sniItemsChanged()
for (auto item : itemServicePaths) {
sinTrayKeyList << SNITrayWidget::toSNIKey(item);
}
for (auto itemKey : m_trayMap.keys())
for (auto itemKey : m_trayMap.keys()) {
if (!sinTrayKeyList.contains(itemKey) && SNITrayWidget::isSNIKey(itemKey)) {
trayRemoved(itemKey);
}
}
for (auto tray : sinTrayKeyList) {
trayAdded(tray);
for (int i = 0; i < sinTrayKeyList.size(); ++i) {
traySNIAdded(sinTrayKeyList.at(i), itemServicePaths.at(i));
}
}
void TrayPlugin::trayListChanged()
{
QList<quint32> winidList = m_trayInter->trayIcons();
QStringList trayList;
QStringList trayKeyList;
for (auto winid : winidList) {
trayList << XWindowTrayWidget::toTrayWidgetId(winid);
trayKeyList << XWindowTrayWidget::toTrayWidgetId(winid);
}
for (auto tray : m_trayMap.keys())
if (!trayList.contains(tray) && XWindowTrayWidget::isWinIdKey(tray)) {
for (auto tray : m_trayMap.keys()) {
if (!trayKeyList.contains(tray) && XWindowTrayWidget::isXWindowKey(tray)) {
trayRemoved(tray);
}
}
for (auto tray : trayList) {
trayAdded(tray);
for (int i = 0; i < trayKeyList.size(); ++i) {
trayXWindowAdded(trayKeyList.at(i), winidList.at(i));
}
}
@ -347,44 +326,53 @@ void TrayPlugin::addTrayWidget(const QString &itemKey, AbstractTrayWidget *trayW
connect(trayWidget, &AbstractTrayWidget::requestRefershWindowVisible, this, &TrayPlugin::onRequestRefershWindowVisible, Qt::UniqueConnection);
}
void TrayPlugin::trayAdded(const QString &itemKey)
void TrayPlugin::trayXWindowAdded(const QString &itemKey, quint32 winId)
{
if (m_trayMap.contains(itemKey)) {
if (m_trayMap.contains(itemKey) || !XWindowTrayWidget::isXWindowKey(itemKey)) {
return;
}
if (XWindowTrayWidget::isWinIdKey(itemKey)) {
auto winId = XWindowTrayWidget::toWinId(itemKey);
getWindowClass(winId);
AbstractTrayWidget *trayWidget = new XWindowTrayWidget(winId);
addTrayWidget(itemKey, trayWidget);
} else if (SNITrayWidget::isSNIKey(itemKey)) {
const QString &sniServicePath = SNITrayWidget::toSNIServicePath(itemKey);
AbstractTrayWidget *trayWidget = new SNITrayWidget(sniServicePath);
connect(trayWidget, &AbstractTrayWidget::iconChanged, this, &TrayPlugin::sniItemIconChanged);
addTrayWidget(itemKey, trayWidget);
} else if (IndicatorTrayWidget::isIndicatorKey(itemKey)) {
IndicatorTray *trayWidget = nullptr;
QString indicatorKey = IndicatorTrayWidget::toIndicatorId(itemKey);
AbstractTrayWidget *trayWidget = new XWindowTrayWidget(winId);
addTrayWidget(itemKey, trayWidget);
}
if (!m_indicatorMap.keys().contains(itemKey)) {
trayWidget = new IndicatorTray(indicatorKey);
m_indicatorMap[indicatorKey] = trayWidget;
}
else {
trayWidget = m_indicatorMap[itemKey];
}
connect(trayWidget, &IndicatorTray::delayLoaded,
trayWidget, [ = ]() {
addTrayWidget(itemKey, trayWidget->widget());
});
connect(trayWidget, &IndicatorTray::removed, this, [=] {
trayRemoved(itemKey);
trayWidget->removeWidget();
});
void TrayPlugin::traySNIAdded(const QString &itemKey, const QString &sniServicePath)
{
if (m_trayMap.contains(itemKey) || !SNITrayWidget::isSNIKey(itemKey)) {
return;
}
AbstractTrayWidget *trayWidget = new SNITrayWidget(sniServicePath);
connect(trayWidget, &AbstractTrayWidget::iconChanged, this, &TrayPlugin::sniItemIconChanged);
addTrayWidget(itemKey, trayWidget);
}
void TrayPlugin::trayIndicatorAdded(const QString &itemKey)
{
if (m_trayMap.contains(itemKey) || !IndicatorTrayWidget::isIndicatorKey(itemKey)) {
return;
}
IndicatorTray *trayWidget = nullptr;
QString indicatorKey = IndicatorTrayWidget::toIndicatorId(itemKey);
if (!m_indicatorMap.keys().contains(itemKey)) {
trayWidget = new IndicatorTray(indicatorKey);
m_indicatorMap[indicatorKey] = trayWidget;
}
else {
trayWidget = m_indicatorMap[itemKey];
}
connect(trayWidget, &IndicatorTray::delayLoaded,
trayWidget, [ = ]() {
addTrayWidget(itemKey, trayWidget->widget());
});
connect(trayWidget, &IndicatorTray::removed, this, [=] {
trayRemoved(itemKey);
trayWidget->removeWidget();
});
}
void TrayPlugin::trayRemoved(const QString &itemKey)
@ -486,6 +474,6 @@ void TrayPlugin::loadIndicator()
QDir indicatorConfDir("/etc/dde-dock/indicator");
for (auto fileInfo : indicatorConfDir.entryInfoList({"*.json"}, QDir::Files | QDir::NoDotAndDotDot)) {
trayAdded(IndicatorTrayWidget::toTrayWidgetId(fileInfo.baseName()));
trayIndicatorAdded(IndicatorTrayWidget::toTrayWidgetId(fileInfo.baseName()));
}
}

View File

@ -66,7 +66,6 @@ public:
private:
void loadIndicator();
const QString getWindowClass(quint32 winId);
bool isSystemTrayItem(const QString &itemKey);
QString itemKeyOfTrayWidget(AbstractTrayWidget *trayWidget);
@ -74,7 +73,9 @@ private slots:
void addTrayWidget(const QString &itemKey, AbstractTrayWidget *trayWidget);
void sniItemsChanged();
void trayListChanged();
void trayAdded(const QString &itemKey);
void trayXWindowAdded(const QString &itemKey, quint32 winId);
void traySNIAdded(const QString &itemKey, const QString &sniServicePath);
void trayIndicatorAdded(const QString &itemKey);
void trayRemoved(const QString &itemKey);
void trayChanged(quint32 winId);
void sniItemIconChanged();

View File

@ -38,6 +38,9 @@
#include <xcb/composite.h>
#include <xcb/xcb_image.h>
#define NORMAL_WINDOW_PROP_NAME "WM_CLASS"
#define WINE_WINDOW_PROP_NAME "__wine_prefix"
static const qreal iconSize = 16;
const QPoint rawXPosition(const QPoint &scaledPos)
@ -318,6 +321,68 @@ void XWindowTrayWidget::sendClick(uint8_t mouseButton, int x, int y)
QTimer::singleShot(100, this, [=] { setX11PassMouseEvent(true); });
}
// NOTE: WM_NAME may can not obtain successfully
QString XWindowTrayWidget::getWindowProperty(quint32 winId, QString propName)
{
const auto display = QX11Info::display();
Atom atom_prop = XInternAtom(display, propName.toLocal8Bit(), true);
if (!atom_prop) {
qDebug() << "Error: get window property failed, invalid property atom";
return QString();
}
Atom actual_type_return;
int actual_format_return;
unsigned long nitems_return;
unsigned long bytes_after_return;
unsigned char *prop_return;
int r = XGetWindowProperty(display, winId, atom_prop, 0, 100, false, AnyPropertyType,
&actual_type_return, &actual_format_return, &nitems_return,
&bytes_after_return, &prop_return);
Q_UNUSED(r);
// qDebug() << (r == Success)
// << actual_type_return
// << actual_format_return
// << nitems_return
// << bytes_after_return
// << QString::fromLocal8Bit((char*)prop_return);
return QString::fromLocal8Bit((char*)prop_return);
}
QString XWindowTrayWidget::toTrayWidgetId(quint32 winId)
{
QString key;
do {
// is wine application
key = getWindowProperty(winId, WINE_WINDOW_PROP_NAME).split("/").last();
if (!key.isEmpty()) {
break;
}
// is normal application
key = getWindowProperty(winId, NORMAL_WINDOW_PROP_NAME);
if (!key.isEmpty()) {
break;
}
// fallback to window id
key = QString::number(winId);
} while (false);
return QString("window:%1").arg(key);
}
bool XWindowTrayWidget::isXWindowKey(const QString &itemKey)
{
return itemKey.startsWith("window:");
}
void XWindowTrayWidget::setActive(const bool active)
{
m_active = active;

View File

@ -22,11 +22,11 @@
#ifndef TRAYWIDGET_H
#define TRAYWIDGET_H
#include "abstracttraywidget.h"
#include <QWidget>
#include <QTimer>
#include <abstracttraywidget.h>
class XWindowTrayWidget : public AbstractTrayWidget
{
Q_OBJECT
@ -40,9 +40,9 @@ public:
const QImage trayImage() Q_DECL_OVERRIDE;
void sendClick(uint8_t mouseButton, int x, int y) Q_DECL_OVERRIDE;
static QString toTrayWidgetId(quint32 winId) { return QString("window:%1").arg(winId); }
static bool isWinIdKey(const QString &itemKey) { return itemKey.startsWith("window:"); }
static quint32 toWinId(QString itemKey) { return itemKey.remove("window:").toUInt() ; }
static QString getWindowProperty(quint32 winId, QString propName);
static QString toTrayWidgetId(quint32 winId);
static bool isXWindowKey(const QString &itemKey);
private:
QSize sizeHint() const Q_DECL_OVERRIDE;