dde-dock/plugins/tray/trayplugin.cpp
Fan PengCheng e2e9211d1c feat: 修改部分函数命名和注释
函数命名变更,部分注释转移到源文件中,方便阅读头文件,去除mock的部分代码文件

Log:
Change-Id: I9cbb7d5a21a60c4643efbf78da7c599d85bd0829
2021-03-23 17:17:02 +08:00

617 lines
18 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* Copyright (C) 2011 ~ 2018 Deepin Technology Co., Ltd.
*
* Author: sbw <sbw@sbw.so>
*
* Maintainer: sbw <sbw@sbw.so>
* listenerri <listenerri@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "trayplugin.h"
#include "fashiontray/fashiontrayitem.h"
#include "snitraywidget.h"
#include "utils.h"
#include <QDir>
#include <QWindow>
#include <QWidget>
#include <QX11Info>
#include <QtConcurrent>
#include <QFuture>
#include <QFutureWatcher>
#include "../widgets/tipswidget.h"
#include "xcb/xcb_icccm.h"
#define PLUGIN_ENABLED_KEY "enable"
#define FASHION_MODE_TRAYS_SORTED "fashion-mode-trays-sorted"
#define SNI_WATCHER_SERVICE "org.kde.StatusNotifierWatcher"
#define SNI_WATCHER_PATH "/StatusNotifierWatcher"
using org::kde::StatusNotifierWatcher;
using namespace Dock;
TrayPlugin::TrayPlugin(QObject *parent)
: QObject(parent)
, m_pluginLoaded(false)
{
}
const QString TrayPlugin::pluginName() const
{
return "tray";
}
void TrayPlugin::init(PluginProxyInterface *proxyInter)
{
// transfex config
QSettings settings("deepin", "dde-dock-shutdown");
if (QFile::exists(settings.fileName())) {
proxyInter->saveValue(this, "enable", settings.value("enable", true));
QFile::remove(settings.fileName());
}
m_proxyInter = proxyInter;
if (pluginIsDisable()) {
qDebug() << "hide tray from config disable!!";
return;
}
if (m_pluginLoaded) {
return;
}
m_pluginLoaded = true;
m_trayInter = new DBusTrayManager(this);
m_sniWatcher = new StatusNotifierWatcher(SNI_WATCHER_SERVICE, SNI_WATCHER_PATH, QDBusConnection::sessionBus(), this);
m_fashionItem = new FashionTrayItem(this);
m_systemTraysController = new SystemTraysController(this);
m_refreshXEmbedItemsTimer = new QTimer(this);
m_refreshSNIItemsTimer = new QTimer(this);
m_tipsLabel = new TipsWidget;
m_refreshXEmbedItemsTimer->setInterval(0);
m_refreshXEmbedItemsTimer->setSingleShot(true);
m_refreshSNIItemsTimer->setInterval(0);
m_refreshSNIItemsTimer->setSingleShot(true);
m_tipsLabel->setObjectName("tray");
m_tipsLabel->setText(tr("System Tray"));
m_tipsLabel->setVisible(false);
connect(m_systemTraysController, &SystemTraysController::pluginItemAdded, this, &TrayPlugin::addTrayWidget);
connect(m_systemTraysController, &SystemTraysController::pluginItemRemoved, this, [ = ](const QString & itemKey) { trayRemoved(itemKey); });
m_trayInter->Manage();
switchToMode(displayMode());
QTimer::singleShot(0, this, &TrayPlugin::loadIndicator);
QTimer::singleShot(0, m_systemTraysController, &SystemTraysController::startLoader);
QTimer::singleShot(0, this, &TrayPlugin::initSNI);
QTimer::singleShot(0, this, &TrayPlugin::initXEmbed);
}
bool TrayPlugin::pluginIsDisable()
{
// NOTE(justforlxz): local config
QSettings enableSetting("deepin", "dde-dock");
enableSetting.beginGroup("tray");
if (!enableSetting.value("enable", true).toBool()) {
return true;
}
if (!m_proxyInter)
return true;
return !m_proxyInter->getValue(this, PLUGIN_ENABLED_KEY, true).toBool();
}
void TrayPlugin::displayModeChanged(const Dock::DisplayMode mode)
{
if (pluginIsDisable()) {
return;
}
switchToMode(displayMode());
}
void TrayPlugin::positionChanged(const Dock::Position position)
{
if (pluginIsDisable()) {
return;
}
m_fashionItem->setDockPosition(position);
}
QWidget *TrayPlugin::itemWidget(const QString &itemKey)
{
if (itemKey == FASHION_MODE_ITEM_KEY) {
return m_fashionItem;
}
return m_trayMap.value(itemKey);
}
QWidget *TrayPlugin::itemTipsWidget(const QString &itemKey)
{
Q_UNUSED(itemKey);
return nullptr;
}
QWidget *TrayPlugin::itemPopupApplet(const QString &itemKey)
{
Q_UNUSED(itemKey);
return nullptr;
}
int TrayPlugin::itemSortKey(const QString &itemKey)
{
// 如果是系统托盘图标则调用内部插件的相应接口
if (isSystemTrayItem(itemKey)) {
return m_systemTraysController->systemTrayItemSortKey(itemKey);
}
const int defaultSort = 0;
AbstractTrayWidget *const trayWidget = m_trayMap.value(itemKey, nullptr);
if (trayWidget == nullptr) {
return defaultSort;
}
const QString key = QString("pos_%1_%2").arg(trayWidget->itemKeyForConfig()).arg(Dock::Efficient);
return m_proxyInter->getValue(this, key, defaultSort).toInt();
}
void TrayPlugin::setSortKey(const QString &itemKey, const int order)
{
if (displayMode() == Dock::DisplayMode::Fashion && !traysSortedInFashionMode()) {
m_proxyInter->saveValue(this, FASHION_MODE_TRAYS_SORTED, true);
}
// 如果是系统托盘图标则调用内部插件的相应接口
if (isSystemTrayItem(itemKey)) {
return m_systemTraysController->setSystemTrayItemSortKey(itemKey, order);
}
AbstractTrayWidget *const trayWidget = m_trayMap.value(itemKey, nullptr);
if (trayWidget == nullptr) {
return;
}
const QString key = QString("pos_%1_%2").arg(trayWidget->itemKeyForConfig()).arg(Dock::Efficient);
m_proxyInter->saveValue(this, key, order);
}
void TrayPlugin::refreshIcon(const QString &itemKey)
{
if (itemKey == FASHION_MODE_ITEM_KEY) {
for (auto trayWidget : m_trayMap.values()) {
if (trayWidget) {
trayWidget->updateIcon();
}
}
return;
}
AbstractTrayWidget *const trayWidget = m_trayMap.value(itemKey);
if (trayWidget) {
trayWidget->updateIcon();
}
}
void TrayPlugin::pluginSettingsChanged()
{
if (pluginIsDisable()) {
return;
}
if (displayMode() == Dock::DisplayMode::Fashion) {
m_fashionItem->onPluginSettingsChanged();
m_fashionItem->clearTrayWidgets();
m_fashionItem->setTrayWidgets(m_trayMap);
}
}
Dock::Position TrayPlugin::dockPosition() const
{
return position();
}
bool TrayPlugin::traysSortedInFashionMode()
{
return m_proxyInter->getValue(this, FASHION_MODE_TRAYS_SORTED, false).toBool();
}
void TrayPlugin::saveValue(const QString &itemKey, const QString &key, const QVariant &value)
{
// 如果是系统托盘图标则调用内部插件的相应接口
if (isSystemTrayItem(itemKey)) {
return m_systemTraysController->saveValueSystemTrayItem(itemKey, key, value);
}
m_proxyInter->saveValue(this, key, value);
}
const QVariant TrayPlugin::getValue(const QString &itemKey, const QString &key, const QVariant &fallback)
{
// 如果是系统托盘图标则调用内部插件的相应接口
if (isSystemTrayItem(itemKey)) {
return m_systemTraysController->getValueSystemTrayItem(itemKey, key, fallback);
}
return m_proxyInter->getValue(this, key, fallback);
}
bool TrayPlugin::isSystemTrayItem(const QString &itemKey)
{
AbstractTrayWidget *const trayWidget = m_trayMap.value(itemKey, nullptr);
if (trayWidget && trayWidget->trayTyep() == AbstractTrayWidget::TrayType::SystemTray) {
return true;
}
return false;
}
QString TrayPlugin::itemKeyOfTrayWidget(AbstractTrayWidget *trayWidget)
{
QString itemKey;
if (displayMode() == Dock::DisplayMode::Fashion) {
itemKey = FASHION_MODE_ITEM_KEY;
} else {
itemKey = m_trayMap.key(trayWidget);
}
return itemKey;
}
Dock::DisplayMode TrayPlugin::displayMode()
{
return Dock::DisplayMode::Fashion;
}
void TrayPlugin::initXEmbed()
{
connect(m_refreshXEmbedItemsTimer, &QTimer::timeout, this, &TrayPlugin::xembedItemsChanged);
connect(m_trayInter, &DBusTrayManager::TrayIconsChanged, this, [ = ] {m_refreshXEmbedItemsTimer->start();});
connect(m_trayInter, &DBusTrayManager::Changed, this, &TrayPlugin::xembedItemChanged);
m_refreshXEmbedItemsTimer->start();
}
void TrayPlugin::initSNI()
{
connect(m_refreshSNIItemsTimer, &QTimer::timeout, this, &TrayPlugin::sniItemsChanged);
connect(m_sniWatcher, &StatusNotifierWatcher::StatusNotifierItemRegistered, this, [ = ] {m_refreshSNIItemsTimer->start();});
connect(m_sniWatcher, &StatusNotifierWatcher::StatusNotifierItemUnregistered, this, [ = ] {m_refreshSNIItemsTimer->start();});
m_refreshSNIItemsTimer->start();
}
void TrayPlugin::sniItemsChanged()
{
const QStringList &itemServicePaths = m_sniWatcher->registeredStatusNotifierItems();
QStringList sinTrayKeyList;
for (auto item : itemServicePaths) {
sinTrayKeyList << SNITrayWidget::toSNIKey(item);
}
for (auto itemKey : m_trayMap.keys()) {
if (!sinTrayKeyList.contains(itemKey) && SNITrayWidget::isSNIKey(itemKey)) {
trayRemoved(itemKey);
}
}
const QList<QString> &passiveSNIKeyList = m_passiveSNITrayMap.keys();
for (auto itemKey : passiveSNIKeyList) {
if (!sinTrayKeyList.contains(itemKey) && SNITrayWidget::isSNIKey(itemKey)) {
m_passiveSNITrayMap.take(itemKey)->deleteLater();
}
}
for (int i = 0; i < sinTrayKeyList.size(); ++i) {
traySNIAdded(sinTrayKeyList.at(i), itemServicePaths.at(i));
}
}
void TrayPlugin::xembedItemsChanged()
{
QList<quint32> winidList = m_trayInter->trayIcons();
QStringList trayKeyList;
for (auto winid : winidList) {
trayKeyList << XEmbedTrayWidget::toXEmbedKey(winid);
}
for (auto tray : m_trayMap.keys()) {
if (!trayKeyList.contains(tray) && XEmbedTrayWidget::isXEmbedKey(tray)) {
trayRemoved(tray);
}
}
for (int i = 0; i < trayKeyList.size(); ++i) {
trayXEmbedAdded(trayKeyList.at(i), winidList.at(i));
}
}
void TrayPlugin::addTrayWidget(const QString &itemKey, AbstractTrayWidget *trayWidget)
{
if (!trayWidget) {
return;
}
if (m_trayMap.contains(itemKey) || m_trayMap.values().contains(trayWidget)) {
return;
}
m_trayMap.insert(itemKey, trayWidget);
if (displayMode() == Dock::Efficient) {
m_proxyInter->itemAdded(this, itemKey);
} else {
m_proxyInter->itemAdded(this, FASHION_MODE_ITEM_KEY);
m_fashionItem->trayWidgetAdded(itemKey, trayWidget);
}
connect(trayWidget, &AbstractTrayWidget::requestWindowAutoHide, this, &TrayPlugin::onRequestWindowAutoHide, Qt::UniqueConnection);
connect(trayWidget, &AbstractTrayWidget::requestRefershWindowVisible, this, &TrayPlugin::onRequestRefershWindowVisible, Qt::UniqueConnection);
}
void TrayPlugin::trayXEmbedAdded(const QString &itemKey, quint32 winId)
{
if (m_trayMap.contains(itemKey) || !XEmbedTrayWidget::isXEmbedKey(itemKey)) {
return;
}
if (!Utils::SettingValue("com.deepin.dde.dock.module.systemtray", QByteArray(), "enable", false).toBool())
return;
AbstractTrayWidget *trayWidget = new XEmbedTrayWidget(winId);
if (trayWidget->isValid())
addTrayWidget(itemKey, trayWidget);
else {
qDebug() << "-- invalid tray windowid" << winId;
}
}
void TrayPlugin::traySNIAdded(const QString &itemKey, const QString &sniServicePath)
{
QFutureWatcher<bool> *watcher = new QFutureWatcher<bool>();
connect(watcher, &QFutureWatcher<int>::finished, this, [=] {
watcher->deleteLater();
if (!watcher->result()) {
return;
}
SNITrayWidget *trayWidget = new SNITrayWidget(sniServicePath);
// TODO(lxz): 在future里已经对dbus进行过检查了这里应该不需要再次检查。
if (!trayWidget->isValid())
return;
std::lock_guard<std::mutex> lock(m_sniMutex);
if (trayWidget->status() == SNITrayWidget::ItemStatus::Passive) {
m_passiveSNITrayMap.insert(itemKey, trayWidget);
} else {
addTrayWidget(itemKey, trayWidget);
}
connect(trayWidget, &SNITrayWidget::statusChanged, this, &TrayPlugin::onSNIItemStatusChanged);
});
// Start the computation.
QFuture<bool> future = QtConcurrent::run([=]() -> bool {
{
std::lock_guard<std::mutex> lock(m_sniMutex);
if (m_trayMap.contains(itemKey) || !SNITrayWidget::isSNIKey(itemKey) || m_passiveSNITrayMap.contains(itemKey)) {
return false;
}
}
if (!Utils::SettingValue("com.deepin.dde.dock.module.systemtray", QByteArray(), "enable", false).toBool())
return false;
if (sniServicePath.startsWith("/") || !sniServicePath.contains("/")) {
qDebug() << "SNI service path invalid";
return false;
}
// NOTE(lxz): The data from the sni daemon is interface/methd
// e.g. org.kde.StatusNotifierItem-1741-1/StatusNotifierItem
const QStringList list = sniServicePath.split("/");
const QString sniServerName = list.first();
if (sniServerName.isEmpty()) {
qWarning() << "SNI service error: " << sniServerName;
return false;
}
QDBusInterface sniItemDBus(sniServerName, "/" + list.last());
if (!sniItemDBus.isValid()) {
qDebug() << "sni dbus service error : " << sniServerName;
return false;
}
return true;
});
watcher->setFuture(future);
}
void TrayPlugin::trayIndicatorAdded(const QString &itemKey, const QString &indicatorName)
{
if (m_trayMap.contains(itemKey) || !IndicatorTrayWidget::isIndicatorKey(itemKey)) {
return;
}
if (!Utils::SettingValue("com.deepin.dde.dock.module.systemtray", QByteArray(), "enable", false).toBool())
return;
IndicatorTray *indicatorTray = nullptr;
if (!m_indicatorMap.keys().contains(indicatorName)) {
indicatorTray = new IndicatorTray(indicatorName);
m_indicatorMap[indicatorName] = indicatorTray;
} else {
indicatorTray = m_indicatorMap[itemKey];
}
connect(indicatorTray, &IndicatorTray::delayLoaded,
indicatorTray, [ = ]() {
addTrayWidget(itemKey, indicatorTray->widget());
}, Qt::UniqueConnection);
connect(indicatorTray, &IndicatorTray::removed, this, [ = ] {
trayRemoved(itemKey);
indicatorTray->removeWidget();
}, Qt::UniqueConnection);
}
void TrayPlugin::trayRemoved(const QString &itemKey, const bool deleteObject)
{
if (!m_trayMap.contains(itemKey)) {
return;
}
AbstractTrayWidget *widget = m_trayMap.take(itemKey);
if (displayMode() == Dock::Efficient) {
m_proxyInter->itemRemoved(this, itemKey);
} else {
m_fashionItem->trayWidgetRemoved(widget);
}
// only delete tray object when it is a tray of applications
// set the parent of the tray object to avoid be deconstructed by parent(DockItem/PluginsItem/TrayPluginsItem)
if (widget->trayTyep() == AbstractTrayWidget::TrayType::SystemTray) {
widget->setParent(nullptr);
} else if (deleteObject) {
widget->deleteLater();
}
}
void TrayPlugin::xembedItemChanged(quint32 winId)
{
QString itemKey = XEmbedTrayWidget::toXEmbedKey(winId);
if (!m_trayMap.contains(itemKey)) {
return;
}
m_trayMap.value(itemKey)->updateIcon();
}
void TrayPlugin::switchToMode(const Dock::DisplayMode mode)
{
if (!m_proxyInter)
return;
if (mode == Dock::Fashion) {
for (auto itemKey : m_trayMap.keys()) {
m_proxyInter->itemRemoved(this, itemKey);
}
if (m_trayMap.isEmpty()) {
m_proxyInter->itemRemoved(this, FASHION_MODE_ITEM_KEY);
} else {
m_fashionItem->setTrayWidgets(m_trayMap);
m_proxyInter->itemAdded(this, FASHION_MODE_ITEM_KEY);
}
} else {
m_fashionItem->clearTrayWidgets();
m_proxyInter->itemRemoved(this, FASHION_MODE_ITEM_KEY);
for (auto itemKey : m_trayMap.keys()) {
m_proxyInter->itemAdded(this, itemKey);
}
}
}
void TrayPlugin::onRequestWindowAutoHide(const bool autoHide)
{
const QString &itemKey = itemKeyOfTrayWidget(static_cast<AbstractTrayWidget *>(sender()));
if (itemKey.isEmpty()) {
return;
}
m_proxyInter->requestWindowAutoHide(this, itemKey, autoHide);
}
void TrayPlugin::onRequestRefershWindowVisible()
{
const QString &itemKey = itemKeyOfTrayWidget(static_cast<AbstractTrayWidget *>(sender()));
if (itemKey.isEmpty()) {
return;
}
m_proxyInter->requestRefreshWindowVisible(this, itemKey);
}
void TrayPlugin::onSNIItemStatusChanged(SNITrayWidget::ItemStatus status)
{
SNITrayWidget *trayWidget = static_cast<SNITrayWidget *>(sender());
if (!trayWidget) {
return;
}
QString itemKey;
do {
itemKey = m_trayMap.key(trayWidget);
if (!itemKey.isEmpty()) {
break;
}
itemKey = m_passiveSNITrayMap.key(trayWidget);
if (itemKey.isEmpty()) {
qDebug() << "Error! not found the status changed SNI tray!";
return;
}
} while (false);
switch (status) {
case SNITrayWidget::Passive: {
m_passiveSNITrayMap.insert(itemKey, trayWidget);
trayRemoved(itemKey, false);
break;
}
case SNITrayWidget::Active:
case SNITrayWidget::NeedsAttention: {
m_passiveSNITrayMap.remove(itemKey);
addTrayWidget(itemKey, trayWidget);
break;
}
default:
break;
}
}
void TrayPlugin::loadIndicator()
{
QDir indicatorConfDir("/etc/dde-dock/indicator");
for (const QFileInfo &fileInfo : indicatorConfDir.entryInfoList({"*.json"}, QDir::Files | QDir::NoDotAndDotDot)) {
const QString &indicatorName = fileInfo.baseName();
trayIndicatorAdded(IndicatorTrayWidget::toIndicatorKey(indicatorName), indicatorName);
}
}