chore: remove useless plugin
log: as title
@ -1,4 +1,3 @@
|
||||
#add_subdirectory("datetime")
|
||||
add_subdirectory("shutdown")
|
||||
add_subdirectory("power")
|
||||
add_subdirectory("sound")
|
||||
|
@ -1,41 +0,0 @@
|
||||
|
||||
set(PLUGIN_NAME "datetime")
|
||||
|
||||
project(${PLUGIN_NAME})
|
||||
|
||||
generation_dbus_interface(${CMAKE_CURRENT_SOURCE_DIR}/dbusinterface/xml ${CMAKE_CURRENT_SOURCE_DIR}/dbusinterface/generation_dbus_interface)
|
||||
|
||||
# Sources files
|
||||
file(GLOB_RECURSE SRCS "*.h"
|
||||
"*.cpp"
|
||||
"../../widgets/*.h"
|
||||
"../../widgets/*.cpp"
|
||||
"../../frame/qtdbusextended/*.h"
|
||||
"../../frame/qtdbusextended/*.cpp" "")
|
||||
|
||||
find_package(PkgConfig REQUIRED)
|
||||
find_package(Qt5Widgets REQUIRED)
|
||||
find_package(Qt5Svg REQUIRED)
|
||||
find_package(Qt5DBus REQUIRED)
|
||||
find_package(DtkWidget REQUIRED)
|
||||
|
||||
pkg_check_modules(QGSettings REQUIRED gsettings-qt)
|
||||
|
||||
add_definitions("${QT_DEFINITIONS} -DQT_PLUGIN")
|
||||
add_library(${PLUGIN_NAME} SHARED ${SRCS} datetime.qrc)
|
||||
set_target_properties(${PLUGIN_NAME} PROPERTIES LIBRARY_OUTPUT_DIRECTORY ../)
|
||||
target_include_directories(${PLUGIN_NAME} PUBLIC
|
||||
${DtkWidget_INCLUDE_DIRS}
|
||||
../../interfaces
|
||||
../../frame/qtdbusextended
|
||||
./dbusinterface/
|
||||
./dbusinterface/generation_dbus_interface)
|
||||
|
||||
target_link_libraries(${PLUGIN_NAME} PRIVATE
|
||||
${DtkWidget_LIBRARIES}
|
||||
PkgConfig::QGSettings
|
||||
Qt5::Widgets
|
||||
Qt5::DBus
|
||||
Qt5::Svg)
|
||||
|
||||
install(TARGETS ${PLUGIN_NAME} LIBRARY DESTINATION lib/dde-dock/plugins)
|
@ -1,4 +0,0 @@
|
||||
{
|
||||
"api": "2.0.0",
|
||||
"depends-daemon-dbus-service": "org.deepin.dde.Timedate1"
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
<RCC>
|
||||
<qresource prefix="/icons">
|
||||
<file>resources/icons/background.svg</file>
|
||||
<file>resources/icons/big0.svg</file>
|
||||
<file>resources/icons/big1.svg</file>
|
||||
<file>resources/icons/big2.svg</file>
|
||||
<file>resources/icons/big3.svg</file>
|
||||
<file>resources/icons/big4.svg</file>
|
||||
<file>resources/icons/big5.svg</file>
|
||||
<file>resources/icons/big6.svg</file>
|
||||
<file>resources/icons/big7.svg</file>
|
||||
<file>resources/icons/big8.svg</file>
|
||||
<file>resources/icons/big9.svg</file>
|
||||
<file>resources/icons/small0.svg</file>
|
||||
<file>resources/icons/small1.svg</file>
|
||||
<file>resources/icons/small2.svg</file>
|
||||
<file>resources/icons/small3.svg</file>
|
||||
<file>resources/icons/small4.svg</file>
|
||||
<file>resources/icons/small5.svg</file>
|
||||
<file>resources/icons/small6.svg</file>
|
||||
<file>resources/icons/small7.svg</file>
|
||||
<file>resources/icons/small8.svg</file>
|
||||
<file>resources/icons/small9.svg</file>
|
||||
<file>resources/icons/tips-am.svg</file>
|
||||
<file>resources/icons/tips-pm.svg</file>
|
||||
</qresource>
|
||||
</RCC>
|
@ -1,256 +0,0 @@
|
||||
// Copyright (C) 2011 ~ 2018 Deepin Technology Co., Ltd.
|
||||
// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#include "datetimeplugin.h"
|
||||
#include "../../widgets/tipswidget.h"
|
||||
#include "../../frame/util/utils.h"
|
||||
|
||||
#include <DDBusSender>
|
||||
|
||||
#include <QDebug>
|
||||
#include <QDBusConnectionInterface>
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#define PLUGIN_STATE_KEY "enable"
|
||||
#define TIME_FORMAT_KEY "Use24HourFormat"
|
||||
using namespace Dock;
|
||||
DatetimePlugin::DatetimePlugin(QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_centralWidget(nullptr)
|
||||
, m_dateTipsLabel(nullptr)
|
||||
, m_refershTimer(nullptr)
|
||||
, m_interface(nullptr)
|
||||
, m_pluginLoaded(false)
|
||||
{
|
||||
QDBusConnection sessionBus = QDBusConnection::sessionBus();
|
||||
sessionBus.connect("org.deepin.dde.Timedate1", "/org/deepin/dde/Timedate1", "org.freedesktop.DBus.Properties", "PropertiesChanged", this, SLOT(propertiesChanged()));
|
||||
}
|
||||
|
||||
PluginsItemInterface::PluginSizePolicy DatetimePlugin::pluginSizePolicy() const
|
||||
{
|
||||
return PluginsItemInterface::Custom;
|
||||
}
|
||||
|
||||
const QString DatetimePlugin::pluginName() const
|
||||
{
|
||||
return "datetime";
|
||||
}
|
||||
|
||||
const QString DatetimePlugin::pluginDisplayName() const
|
||||
{
|
||||
return tr("Datetime");
|
||||
}
|
||||
|
||||
void DatetimePlugin::init(PluginProxyInterface *proxyInter)
|
||||
{
|
||||
m_proxyInter = proxyInter;
|
||||
|
||||
// transfer config
|
||||
QSettings settings("deepin", "dde-dock-datetime");
|
||||
if (QFile::exists(settings.fileName())) {
|
||||
Dock::DisplayMode mode = displayMode();
|
||||
const QString key = QString("pos_%1_%2").arg(pluginName()).arg(mode);
|
||||
proxyInter->saveValue(this, key, settings.value(key, mode == Dock::DisplayMode::Fashion ? 6 : -1));
|
||||
QFile::remove(settings.fileName());
|
||||
}
|
||||
|
||||
if (pluginIsDisable()) {
|
||||
return;
|
||||
}
|
||||
|
||||
loadPlugin();
|
||||
}
|
||||
|
||||
void DatetimePlugin::loadPlugin()
|
||||
{
|
||||
if (m_pluginLoaded)
|
||||
return;
|
||||
|
||||
m_pluginLoaded = true;
|
||||
m_dateTipsLabel.reset(new TipsWidget);
|
||||
m_refershTimer = new QTimer(this);
|
||||
m_dateTipsLabel->setObjectName("datetime");
|
||||
|
||||
m_refershTimer->setInterval(1000);
|
||||
m_refershTimer->start();
|
||||
|
||||
m_centralWidget.reset(new DatetimeWidget);
|
||||
|
||||
connect(m_centralWidget.data(), &DatetimeWidget::requestUpdateGeometry, [this] { m_proxyInter->itemUpdate(this, pluginName()); });
|
||||
connect(m_refershTimer, &QTimer::timeout, this, &DatetimePlugin::updateCurrentTimeString);
|
||||
|
||||
m_proxyInter->itemAdded(this, pluginName());
|
||||
|
||||
pluginSettingsChanged();
|
||||
}
|
||||
|
||||
void DatetimePlugin::pluginStateSwitched()
|
||||
{
|
||||
m_proxyInter->saveValue(this, PLUGIN_STATE_KEY, pluginIsDisable());
|
||||
|
||||
refreshPluginItemsVisible();
|
||||
}
|
||||
|
||||
bool DatetimePlugin::pluginIsDisable()
|
||||
{
|
||||
return !(m_proxyInter->getValue(this, PLUGIN_STATE_KEY, true).toBool());
|
||||
}
|
||||
|
||||
int DatetimePlugin::itemSortKey(const QString &itemKey)
|
||||
{
|
||||
Q_UNUSED(itemKey);
|
||||
|
||||
const QString key = QString("pos_%1_%2").arg(itemKey).arg(Dock::Efficient);
|
||||
return m_proxyInter->getValue(this, key, 6).toInt();
|
||||
}
|
||||
|
||||
void DatetimePlugin::setSortKey(const QString &itemKey, const int order)
|
||||
{
|
||||
Q_UNUSED(itemKey);
|
||||
|
||||
const QString key = QString("pos_%1_%2").arg(itemKey).arg(Dock::Efficient);
|
||||
m_proxyInter->saveValue(this, key, order);
|
||||
}
|
||||
|
||||
QWidget *DatetimePlugin::itemWidget(const QString &itemKey)
|
||||
{
|
||||
Q_UNUSED(itemKey);
|
||||
|
||||
return m_centralWidget.data();
|
||||
}
|
||||
|
||||
QWidget *DatetimePlugin::itemTipsWidget(const QString &itemKey)
|
||||
{
|
||||
Q_UNUSED(itemKey);
|
||||
|
||||
return m_dateTipsLabel.data();
|
||||
}
|
||||
|
||||
const QString DatetimePlugin::itemCommand(const QString &itemKey)
|
||||
{
|
||||
Q_UNUSED(itemKey);
|
||||
|
||||
return "dbus-send --print-reply --dest=org.deepin.dde.Widgets1 /org/deepin/dde/Widgets1 org.deepin.dde.Widgets1.Toggle";
|
||||
}
|
||||
|
||||
const QString DatetimePlugin::itemContextMenu(const QString &itemKey)
|
||||
{
|
||||
Q_UNUSED(itemKey);
|
||||
|
||||
QList<QVariant> items;
|
||||
items.reserve(1);
|
||||
|
||||
QMap<QString, QVariant> settings;
|
||||
settings["itemId"] = "settings";
|
||||
if (m_centralWidget->is24HourFormat())
|
||||
settings["itemText"] = tr("12-hour time");
|
||||
else
|
||||
settings["itemText"] = tr("24-hour time");
|
||||
settings["isActive"] = true;
|
||||
items.push_back(settings);
|
||||
|
||||
if (!QFile::exists(ICBC_CONF_FILE)) {
|
||||
QMap<QString, QVariant> open;
|
||||
open["itemId"] = "open";
|
||||
open["itemText"] = tr("Time settings");
|
||||
open["isActive"] = true;
|
||||
items.push_back(open);
|
||||
}
|
||||
|
||||
QMap<QString, QVariant> menu;
|
||||
menu["items"] = items;
|
||||
menu["checkableMenu"] = false;
|
||||
menu["singleCheck"] = false;
|
||||
|
||||
return QJsonDocument::fromVariant(menu).toJson();
|
||||
}
|
||||
|
||||
void DatetimePlugin::invokedMenuItem(const QString &itemKey, const QString &menuId, const bool checked)
|
||||
{
|
||||
Q_UNUSED(itemKey)
|
||||
Q_UNUSED(checked)
|
||||
|
||||
if (menuId == "open") {
|
||||
DDBusSender()
|
||||
.service("org.deepin.dde.ControlCenter1")
|
||||
.interface("org.deepin.dde.ControlCenter1")
|
||||
.path("/org/deepin/dde/ControlCenter1")
|
||||
.method(QString("ShowPage"))
|
||||
.arg(QString("datetime"))
|
||||
.call();
|
||||
} else {
|
||||
const bool value = timedateInterface()->property(TIME_FORMAT_KEY).toBool();
|
||||
timedateInterface()->setProperty(TIME_FORMAT_KEY, !value);
|
||||
m_centralWidget->set24HourFormat(!value);
|
||||
}
|
||||
}
|
||||
|
||||
void DatetimePlugin::pluginSettingsChanged()
|
||||
{
|
||||
if (!m_pluginLoaded)
|
||||
return;
|
||||
|
||||
const bool value = timedateInterface()->property(TIME_FORMAT_KEY).toBool();
|
||||
|
||||
m_proxyInter->saveValue(this, TIME_FORMAT_KEY, value);
|
||||
m_centralWidget->set24HourFormat(value);
|
||||
|
||||
refreshPluginItemsVisible();
|
||||
}
|
||||
|
||||
void DatetimePlugin::updateCurrentTimeString()
|
||||
{
|
||||
const QDateTime currentDateTime = QDateTime::currentDateTime();
|
||||
|
||||
if (m_centralWidget->is24HourFormat())
|
||||
m_dateTipsLabel->setText(currentDateTime.date().toString(Qt::SystemLocaleLongDate) + currentDateTime.toString(" HH:mm:ss"));
|
||||
else
|
||||
m_dateTipsLabel->setText(currentDateTime.date().toString(Qt::SystemLocaleLongDate) + currentDateTime.toString(" hh:mm:ss A"));
|
||||
|
||||
const QString currentString = currentDateTime.toString("yyyy/MM/dd hh:mm");
|
||||
|
||||
if (currentString == m_currentTimeString)
|
||||
return;
|
||||
|
||||
m_currentTimeString = currentString;
|
||||
//当时间显示格式为12小时制且格式为0:00时,当从9:59变到10:00时,插件宽度需要变化
|
||||
m_centralWidget->requestUpdateGeometry();
|
||||
}
|
||||
|
||||
void DatetimePlugin::refreshPluginItemsVisible()
|
||||
{
|
||||
if (!pluginIsDisable()) {
|
||||
|
||||
if (!m_pluginLoaded) {
|
||||
loadPlugin();
|
||||
return;
|
||||
}
|
||||
m_proxyInter->itemAdded(this, pluginName());
|
||||
} else {
|
||||
m_proxyInter->itemRemoved(this, pluginName());
|
||||
}
|
||||
}
|
||||
|
||||
void DatetimePlugin::propertiesChanged()
|
||||
{
|
||||
pluginSettingsChanged();
|
||||
}
|
||||
|
||||
QDBusInterface* DatetimePlugin::timedateInterface()
|
||||
{
|
||||
if (!m_interface) {
|
||||
if (QDBusConnection::sessionBus().interface()->isServiceRegistered("org.deepin.dde.Timedate1")) {
|
||||
m_interface = new QDBusInterface("org.deepin.dde.Timedate1", "/org/deepin/dde/Timedate1", "org.deepin.dde.Timedate1", QDBusConnection::sessionBus(), this);
|
||||
} else {
|
||||
const QString path = QString("/org/deepin/dde/Accounts1/User%1").arg(QString::number(getuid()));
|
||||
QDBusInterface * systemInterface = new QDBusInterface("org.deepin.dde.Accounts1", path, "org.deepin.dde.Accounts1.User",
|
||||
QDBusConnection::systemBus(), this);
|
||||
return systemInterface;
|
||||
}
|
||||
}
|
||||
|
||||
return m_interface;
|
||||
}
|
@ -1,70 +0,0 @@
|
||||
// Copyright (C) 2011 ~ 2018 Deepin Technology Co., Ltd.
|
||||
// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#ifndef DATETIMEPLUGIN_H
|
||||
#define DATETIMEPLUGIN_H
|
||||
|
||||
#include "pluginsiteminterface.h"
|
||||
#include "datetimewidget.h"
|
||||
|
||||
#include <QTimer>
|
||||
#include <QLabel>
|
||||
#include <QSettings>
|
||||
|
||||
namespace Dock{
|
||||
class TipsWidget;
|
||||
}
|
||||
class QDBusInterface;
|
||||
class DatetimePlugin : public QObject, PluginsItemInterface
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_INTERFACES(PluginsItemInterface)
|
||||
Q_PLUGIN_METADATA(IID "com.deepin.dock.PluginsItemInterface" FILE "datetime.json")
|
||||
|
||||
public:
|
||||
explicit DatetimePlugin(QObject *parent = nullptr);
|
||||
|
||||
PluginSizePolicy pluginSizePolicy() const override;
|
||||
|
||||
const QString pluginName() const override;
|
||||
const QString pluginDisplayName() const override;
|
||||
void init(PluginProxyInterface *proxyInter) override;
|
||||
|
||||
void pluginStateSwitched() override;
|
||||
bool pluginIsAllowDisable() override { return true; }
|
||||
bool pluginIsDisable() override;
|
||||
|
||||
int itemSortKey(const QString &itemKey) override;
|
||||
void setSortKey(const QString &itemKey, const int order) override;
|
||||
|
||||
QWidget *itemWidget(const QString &itemKey) override;
|
||||
QWidget *itemTipsWidget(const QString &itemKey) override;
|
||||
|
||||
const QString itemCommand(const QString &itemKey) override;
|
||||
const QString itemContextMenu(const QString &itemKey) override;
|
||||
|
||||
void invokedMenuItem(const QString &itemKey, const QString &menuId, const bool checked) override;
|
||||
|
||||
void pluginSettingsChanged() override;
|
||||
|
||||
private slots:
|
||||
void updateCurrentTimeString();
|
||||
void refreshPluginItemsVisible();
|
||||
void propertiesChanged();
|
||||
|
||||
private:
|
||||
void loadPlugin();
|
||||
QDBusInterface *timedateInterface();
|
||||
|
||||
private:
|
||||
QScopedPointer<DatetimeWidget> m_centralWidget;
|
||||
QScopedPointer<Dock::TipsWidget> m_dateTipsLabel;
|
||||
QTimer *m_refershTimer;
|
||||
QString m_currentTimeString;
|
||||
QDBusInterface *m_interface;
|
||||
bool m_pluginLoaded;
|
||||
};
|
||||
|
||||
#endif // DATETIMEPLUGIN_H
|
@ -1,242 +0,0 @@
|
||||
// Copyright (C) 2011 ~ 2018 Deepin Technology Co., Ltd.
|
||||
// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#include "datetimewidget.h"
|
||||
#include "constants.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QPainter>
|
||||
#include <QDebug>
|
||||
#include <QSvgRenderer>
|
||||
#include <QMouseEvent>
|
||||
#include <DFontSizeManager>
|
||||
#include <DGuiApplicationHelper>
|
||||
|
||||
#define PLUGIN_STATE_KEY "enable"
|
||||
#define TIME_FONT DFontSizeManager::instance()->t4()
|
||||
#define DATE_FONT DFontSizeManager::instance()->t10()
|
||||
|
||||
DWIDGET_USE_NAMESPACE
|
||||
|
||||
DatetimeWidget::DatetimeWidget(QWidget *parent)
|
||||
: QWidget(parent)
|
||||
, m_24HourFormat(false)
|
||||
, m_timeOffset(false)
|
||||
, m_timedateInter(new Timedate("org.deepin.dde.Timedate1", "/org/deepin/dde/Timedate1", QDBusConnection::sessionBus(), this))
|
||||
, m_shortDateFormat("yyyy-MM-dd")
|
||||
, m_shortTimeFormat("hh:mm")
|
||||
{
|
||||
setMinimumSize(PLUGIN_BACKGROUND_MIN_SIZE, PLUGIN_BACKGROUND_MIN_SIZE);
|
||||
setShortDateFormat(m_timedateInter->shortDateFormat());
|
||||
setShortTimeFormat(m_timedateInter->shortTimeFormat());
|
||||
|
||||
connect(m_timedateInter, &Timedate::ShortDateFormatChanged, this, &DatetimeWidget::setShortDateFormat);
|
||||
connect(m_timedateInter, &Timedate::ShortTimeFormatChanged, this, &DatetimeWidget::setShortTimeFormat);
|
||||
//连接日期时间修改信号,更新日期时间插件的布局
|
||||
connect(m_timedateInter, &Timedate::TimeUpdate, this, [ = ]{
|
||||
if (isVisible()) {
|
||||
emit requestUpdateGeometry();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void DatetimeWidget::set24HourFormat(const bool value)
|
||||
{
|
||||
if (m_24HourFormat == value) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_24HourFormat = value;
|
||||
update();
|
||||
|
||||
if (isVisible()) {
|
||||
emit requestUpdateGeometry();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief DatetimeWidget::setShortDateFormat 根据类型设置时间显示格式
|
||||
* @param type 自定义类型
|
||||
*/
|
||||
void DatetimeWidget::setShortDateFormat(int type)
|
||||
{
|
||||
switch (type) {
|
||||
case 0: m_shortDateFormat = "yyyy/M/d"; break;
|
||||
case 1: m_shortDateFormat = "yyyy-M-d"; break;
|
||||
case 2: m_shortDateFormat = "yyyy.M.d"; break;
|
||||
case 3: m_shortDateFormat = "yyyy/MM/dd"; break;
|
||||
case 4: m_shortDateFormat = "yyyy-MM-dd"; break;
|
||||
case 5: m_shortDateFormat = "yyyy.MM.dd"; break;
|
||||
case 6: m_shortDateFormat = "yy/M/d"; break;
|
||||
case 7: m_shortDateFormat = "yy-M-d"; break;
|
||||
case 8: m_shortDateFormat = "yy.M.d"; break;
|
||||
default: m_shortDateFormat = "yyyy-MM-dd"; break;
|
||||
}
|
||||
update();
|
||||
|
||||
if (isVisible()) {
|
||||
emit requestUpdateGeometry();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief DatetimeWidget::setShortTimeFormat 根据类型设置短时间显示格式
|
||||
* @param type 自定义类型
|
||||
*/
|
||||
void DatetimeWidget::setShortTimeFormat(int type)
|
||||
{
|
||||
switch (type) {
|
||||
case 0: m_shortTimeFormat = "h:mm"; break;
|
||||
case 1: m_shortTimeFormat = "hh:mm"; break;
|
||||
default: m_shortTimeFormat = "hh:mm"; break;
|
||||
}
|
||||
update();
|
||||
|
||||
if (isVisible()) {
|
||||
emit requestUpdateGeometry();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief DatetimeWidget::curTimeSize 调整时间日期字体大小
|
||||
* @return 返回时间和日期绘制的区域大小
|
||||
*/
|
||||
QSize DatetimeWidget::curTimeSize() const
|
||||
{
|
||||
const Dock::Position position = qApp->property(PROP_POSITION).value<Dock::Position>();
|
||||
|
||||
m_timeFont = TIME_FONT;
|
||||
m_dateFont = DATE_FONT;
|
||||
QString timeFormat = m_shortTimeFormat;
|
||||
QString dateFormat = m_shortDateFormat;
|
||||
if (!m_24HourFormat) {
|
||||
if (position == Dock::Top || position == Dock::Bottom)
|
||||
timeFormat = timeFormat.append(" AP");
|
||||
else
|
||||
timeFormat = timeFormat.append("\nAP");
|
||||
}
|
||||
|
||||
QString timeString = QDateTime::currentDateTime().toString(timeFormat);
|
||||
QString dateString = QDateTime::currentDateTime().toString(dateFormat);
|
||||
|
||||
QSize timeSize = QFontMetrics(m_timeFont).boundingRect(timeString).size();
|
||||
int maxWidth = std::max(QFontMetrics(m_timeFont).boundingRect(timeString).size().width(), QFontMetrics(m_timeFont).horizontalAdvance(timeString));
|
||||
timeSize.setWidth(maxWidth);
|
||||
|
||||
if (timeString.contains("\n")) {
|
||||
QStringList SL = timeString.split("\n");
|
||||
maxWidth = std::max(QFontMetrics(m_timeFont).boundingRect(SL.at(0)).size().width(), QFontMetrics(m_timeFont).horizontalAdvance(SL.at(0)));
|
||||
timeSize = QSize(maxWidth, QFontMetrics(m_timeFont).boundingRect(SL.at(0)).height() + QFontMetrics(m_timeFont).boundingRect(SL.at(1)).height());
|
||||
}
|
||||
|
||||
QSize dateSize = QFontMetrics(m_dateFont).boundingRect(dateString).size();
|
||||
maxWidth = std::max(QFontMetrics(m_dateFont).boundingRect(dateString).size().width(), QFontMetrics(m_dateFont).horizontalAdvance(dateString));
|
||||
dateSize.setWidth(maxWidth);
|
||||
|
||||
if (position == Dock::Bottom || position == Dock::Top) {
|
||||
while (QFontMetrics(m_timeFont).boundingRect(timeString).height() + QFontMetrics(m_dateFont).boundingRect(dateString).height() > height()) {
|
||||
m_timeFont.setPixelSize(m_timeFont.pixelSize() - 1);
|
||||
maxWidth = std::max(QFontMetrics(m_timeFont).boundingRect(timeString).size().width(), QFontMetrics(m_timeFont).horizontalAdvance(timeString));
|
||||
timeSize.setWidth(maxWidth);
|
||||
if (m_timeFont.pixelSize() - m_dateFont.pixelSize() == 1) {
|
||||
m_dateFont.setPixelSize(m_dateFont.pixelSize() - 1);
|
||||
maxWidth = std::max(QFontMetrics(m_dateFont).boundingRect(dateString).size().width(), QFontMetrics(m_dateFont).horizontalAdvance(dateString));
|
||||
dateSize.setWidth(maxWidth);
|
||||
}
|
||||
}
|
||||
return QSize(std::max(timeSize.width(), dateSize.width()), timeSize.height() + dateSize.height());
|
||||
} else {
|
||||
while (std::max(QFontMetrics(m_timeFont).boundingRect(timeString).size().width(), QFontMetrics(m_dateFont).boundingRect(dateString).size().width()) > (width() - 4)) {
|
||||
m_timeFont.setPixelSize(m_timeFont.pixelSize() - 1);
|
||||
if (m_24HourFormat) {
|
||||
timeSize.setHeight(QFontMetrics(m_timeFont).boundingRect(timeString).size().height());
|
||||
} else {
|
||||
timeSize.setHeight(QFontMetrics(m_timeFont).boundingRect(timeString).size().height() * 2);
|
||||
}
|
||||
if (m_timeFont.pixelSize() - m_dateFont.pixelSize() == 1) {
|
||||
m_dateFont.setPixelSize(m_dateFont.pixelSize() - 1);
|
||||
dateSize.setWidth(QFontMetrics(m_dateFont).boundingRect(dateString).size().height());
|
||||
}
|
||||
}
|
||||
m_timeOffset = (timeSize.height() - dateSize.height()) / 2 ;
|
||||
return QSize(std::max(timeSize.width(), dateSize.width()), timeSize.height() + dateSize.height());
|
||||
}
|
||||
}
|
||||
|
||||
QSize DatetimeWidget::sizeHint() const
|
||||
{
|
||||
return curTimeSize();
|
||||
}
|
||||
|
||||
void DatetimeWidget::resizeEvent(QResizeEvent *event)
|
||||
{
|
||||
if (isVisible())
|
||||
emit requestUpdateGeometry();
|
||||
|
||||
QWidget::resizeEvent(event);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief DatetimeWidget::paintEvent 绘制任务栏时间日期
|
||||
* @param e
|
||||
*/
|
||||
void DatetimeWidget::paintEvent(QPaintEvent *e)
|
||||
{
|
||||
Q_UNUSED(e);
|
||||
const QDateTime current = QDateTime::currentDateTime();
|
||||
|
||||
const Dock::Position position = qApp->property(PROP_POSITION).value<Dock::Position>();
|
||||
QPainter painter(this);
|
||||
painter.setRenderHint(QPainter::Antialiasing);
|
||||
painter.setPen(QPen(palette().brightText(), 1));
|
||||
|
||||
QRect timeRect = rect();
|
||||
QRect dateRect = rect();
|
||||
|
||||
QString format = m_shortTimeFormat;
|
||||
if (!m_24HourFormat) {
|
||||
if (position == Dock::Top || position == Dock::Bottom)
|
||||
format = format.append(" AP");
|
||||
else
|
||||
format = format.append("\nAP");
|
||||
}
|
||||
QString timeStr = current.toString(format);
|
||||
|
||||
format = m_shortDateFormat;
|
||||
QString dateStr = current.toString(format);
|
||||
|
||||
if (position == Dock::Top || position == Dock::Bottom) {
|
||||
// 只处理上下位置的,特殊处理一下藏文,其他的语言如果有问题也可以类似特殊处理一下
|
||||
// Unifont字体有点特殊
|
||||
// 以下的0.23 0.18 0.2 0.13数值是测试过程中微调时间跟日期之间的间距系数,不是特别计算的精确值
|
||||
QLocale locale;
|
||||
int timeHeight = QFontMetrics(m_timeFont).boundingRect(timeStr).height() + 2; // +2只是防止显示在边界的几个像素被截断
|
||||
int dateHeight = QFontMetrics(m_dateFont).boundingRect(dateStr).height() + 2;
|
||||
int marginH = (height() - timeHeight - dateHeight) / 2;
|
||||
|
||||
if (locale.language() == QLocale::Tibetan) {
|
||||
if (m_timeFont.family() == "Noto Serif Tibetan")
|
||||
marginH = marginH + 0.23 * timeHeight;
|
||||
else if (m_timeFont.family() == "Noto Sans Tibetan")
|
||||
marginH = marginH + 0.18 * timeHeight;
|
||||
else if (m_timeFont.family() == "Tibetan Machine Uni")
|
||||
marginH = marginH + 0.2 * timeHeight;
|
||||
} else {
|
||||
if (m_timeFont.family() != "Unifont")
|
||||
marginH = marginH + 0.13 * timeHeight;
|
||||
}
|
||||
|
||||
timeRect = QRect(0, marginH, width(), timeHeight);
|
||||
dateRect = QRect(0, height() - dateHeight - marginH, width(), dateHeight);
|
||||
} else {
|
||||
timeRect.setBottom(rect().center().y() + m_timeOffset);
|
||||
dateRect.setTop(timeRect.bottom());
|
||||
}
|
||||
painter.setFont(m_timeFont);
|
||||
painter.drawText(timeRect, Qt::AlignCenter, timeStr);
|
||||
|
||||
painter.setFont(m_dateFont);
|
||||
painter.drawText(dateRect, Qt::AlignCenter, dateStr);
|
||||
}
|
@ -1,52 +0,0 @@
|
||||
// Copyright (C) 2011 ~ 2018 Deepin Technology Co., Ltd.
|
||||
// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#ifndef DATETIMEWIDGET_H
|
||||
#define DATETIMEWIDGET_H
|
||||
|
||||
#include "org_deepin_dde_timedate1.h"
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
using Timedate = org::deepin::dde::Timedate1;
|
||||
|
||||
class DatetimeWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit DatetimeWidget(QWidget *parent = 0);
|
||||
|
||||
bool is24HourFormat() const { return m_24HourFormat; }
|
||||
QSize sizeHint() const;
|
||||
|
||||
protected:
|
||||
void resizeEvent(QResizeEvent *event);
|
||||
void paintEvent(QPaintEvent *e);
|
||||
|
||||
signals:
|
||||
void requestUpdateGeometry() const;
|
||||
|
||||
public slots:
|
||||
void set24HourFormat(const bool value);
|
||||
|
||||
private Q_SLOTS:
|
||||
void setShortDateFormat(int type);
|
||||
void setShortTimeFormat(int type);
|
||||
|
||||
private:
|
||||
QSize curTimeSize() const;
|
||||
|
||||
private:
|
||||
bool m_24HourFormat;
|
||||
mutable QFont m_timeFont;
|
||||
mutable QFont m_dateFont;
|
||||
mutable int m_timeOffset;
|
||||
Timedate *m_timedateInter;
|
||||
QString m_shortDateFormat;
|
||||
QString m_shortTimeFormat;
|
||||
};
|
||||
|
||||
#endif // DATETIMEWIDGET_H
|
@ -1,72 +0,0 @@
|
||||
// Copyright (C) 2011 ~ 2017 Deepin Technology Co., Ltd.
|
||||
// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#include "zoneinfo.h"
|
||||
|
||||
ZoneInfo::ZoneInfo()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool ZoneInfo::operator ==(const ZoneInfo &what) const
|
||||
{
|
||||
// TODO: 这里只判断这两个成员应该就可以了
|
||||
return m_zoneName == what.m_zoneName &&
|
||||
m_utcOffset == what.m_utcOffset;
|
||||
}
|
||||
|
||||
QDebug operator<<(QDebug argument, const ZoneInfo & info)
|
||||
{
|
||||
argument << info.m_zoneName << ',' << info.m_zoneCity << ',' << info.m_utcOffset << ',';
|
||||
argument << info.i2 << ',' << info.i3 << ',' << info.i4 << endl;
|
||||
|
||||
return argument;
|
||||
}
|
||||
|
||||
QDBusArgument &operator<<(QDBusArgument & argument, const ZoneInfo & info)
|
||||
{
|
||||
argument.beginStructure();
|
||||
argument << info.m_zoneName << info.m_zoneCity << info.m_utcOffset;
|
||||
argument.beginStructure();
|
||||
argument << info.i2 << info.i3 << info.i4;
|
||||
argument.endStructure();
|
||||
argument.endStructure();
|
||||
|
||||
return argument;
|
||||
}
|
||||
|
||||
QDataStream &operator<<(QDataStream & argument, const ZoneInfo & info)
|
||||
{
|
||||
argument << info.m_zoneName << info.m_zoneCity << info.m_utcOffset;
|
||||
argument << info.i2 << info.i3 << info.i4;
|
||||
|
||||
return argument;
|
||||
}
|
||||
|
||||
const QDBusArgument &operator>>(const QDBusArgument & argument, ZoneInfo & info)
|
||||
{
|
||||
argument.beginStructure();
|
||||
argument >> info.m_zoneName >> info.m_zoneCity >> info.m_utcOffset;
|
||||
argument.beginStructure();
|
||||
argument >> info.i2 >> info.i3 >> info.i4;
|
||||
argument.endStructure();
|
||||
argument.endStructure();
|
||||
|
||||
return argument;
|
||||
}
|
||||
|
||||
const QDataStream &operator>>(QDataStream & argument, ZoneInfo & info)
|
||||
{
|
||||
argument >> info.m_zoneName >> info.m_zoneCity >> info.m_utcOffset;
|
||||
argument >> info.i2 >> info.i3 >> info.i4;
|
||||
|
||||
return argument;
|
||||
}
|
||||
|
||||
void registerZoneInfoMetaType()
|
||||
{
|
||||
qRegisterMetaType<ZoneInfo>("ZoneInfo");
|
||||
qDBusRegisterMetaType<ZoneInfo>();
|
||||
}
|
@ -1,46 +0,0 @@
|
||||
// Copyright (C) 2011 ~ 2017 Deepin Technology Co., Ltd.
|
||||
// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#ifndef ZONEINFO_H
|
||||
#define ZONEINFO_H
|
||||
|
||||
#include <QDebug>
|
||||
#include <QDataStream>
|
||||
#include <QString>
|
||||
#include <QDBusArgument>
|
||||
#include <QDBusMetaType>
|
||||
|
||||
class ZoneInfo
|
||||
{
|
||||
public:
|
||||
ZoneInfo();
|
||||
|
||||
friend QDebug operator<<(QDebug argument, const ZoneInfo &info);
|
||||
friend QDBusArgument &operator<<(QDBusArgument &argument, const ZoneInfo &info);
|
||||
friend QDataStream &operator<<(QDataStream &argument, const ZoneInfo &info);
|
||||
friend const QDBusArgument &operator>>(const QDBusArgument &argument, ZoneInfo &info);
|
||||
friend const QDataStream &operator>>(QDataStream &argument, ZoneInfo &info);
|
||||
|
||||
bool operator==(const ZoneInfo &what) const;
|
||||
|
||||
public:
|
||||
inline QString getZoneName() const {return m_zoneName;}
|
||||
inline QString getZoneCity() const {return m_zoneCity;}
|
||||
inline int getUTCOffset() const {return m_utcOffset;}
|
||||
|
||||
private:
|
||||
QString m_zoneName;
|
||||
QString m_zoneCity;
|
||||
int m_utcOffset;
|
||||
qint64 i2;
|
||||
qint64 i3;
|
||||
int i4;
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE(ZoneInfo)
|
||||
|
||||
void registerZoneInfoMetaType();
|
||||
|
||||
#endif // ZONEINFO_H
|
@ -1,62 +0,0 @@
|
||||
<interface name="org.deepin.dde.Timedate1">
|
||||
<signal name="TimeUpdate">
|
||||
</signal>
|
||||
<method name="AddUserTimezone">
|
||||
<arg type="s" direction="in"></arg>
|
||||
</method>
|
||||
<method name="DeleteUserTimezone">
|
||||
<arg type="s" direction="in"></arg>
|
||||
</method>
|
||||
<method name="GetZoneInfo">
|
||||
<arg type="s" direction="in"></arg>
|
||||
<arg type="(ssi(xxi))" direction="out"></arg>
|
||||
<annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value ="ZoneInfo"/>
|
||||
</method>
|
||||
<method name="GetZoneList">
|
||||
<arg type="as" direction="out"></arg>
|
||||
</method>
|
||||
<method name="GetSampleNTPServers">
|
||||
<arg type="as" direction="out"></arg>
|
||||
</method>
|
||||
<method name="SetDate">
|
||||
<arg type="i" direction="in"></arg>
|
||||
<arg type="i" direction="in"></arg>
|
||||
<arg type="i" direction="in"></arg>
|
||||
<arg type="i" direction="in"></arg>
|
||||
<arg type="i" direction="in"></arg>
|
||||
<arg type="i" direction="in"></arg>
|
||||
<arg type="i" direction="in"></arg>
|
||||
</method>
|
||||
<method name="SetLocalRTC">
|
||||
<arg type="b" direction="in"></arg>
|
||||
<arg type="b" direction="in"></arg>
|
||||
</method>
|
||||
<method name="SetNTP">
|
||||
<arg type="b" direction="in"></arg>
|
||||
</method>
|
||||
<method name="SetNTPServer">
|
||||
<arg type="s" direction="in"></arg>
|
||||
</method>
|
||||
<method name="SetTime">
|
||||
<arg type="x" direction="in"></arg>
|
||||
<arg type="b" direction="in"></arg>
|
||||
</method>
|
||||
<method name="SetTimezone">
|
||||
<arg type="s" direction="in"></arg>
|
||||
</method>
|
||||
<property name="CanNTP" type="b" access="read"></property>
|
||||
<property name="NTP" type="b" access="read"></property>
|
||||
<property name="LocalRTC" type="b" access="read"></property>
|
||||
<property name="Timezone" type="s" access="read"></property>
|
||||
<property name="Use24HourFormat" type="b" access="readwrite"></property>
|
||||
<property name="DSTOffset" type="i" access="readwrite"></property>
|
||||
<property name="UserTimezones" type="as" access="read"></property>
|
||||
<property name="NTPServer" type="s" access="read"></property>
|
||||
<property name="WeekdayFormat" type="i" access="readwrite"></property>
|
||||
<property name="ShortDateFormat" type="i" access="readwrite"></property>
|
||||
<property name="LongDateFormat" type="i" access="readwrite"></property>
|
||||
<property name="ShortTimeFormat" type="i" access="readwrite"></property>
|
||||
<property name="LongTimeFormat" type="i" access="readwrite"></property>
|
||||
<property name="WeekBegins" type="i" access="readwrite"></property>
|
||||
</interface>
|
||||
|
@ -1,25 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg width="48px" height="48px" viewBox="0 0 48 48" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<!-- Generator: Sketch 3.8.3 (29802) - http://www.bohemiancoding.com/sketch -->
|
||||
<title>时钟底板</title>
|
||||
<desc>Created with Sketch.</desc>
|
||||
<defs>
|
||||
<circle id="path-1" cx="21" cy="21" r="21"></circle>
|
||||
<filter x="-50%" y="-50%" width="200%" height="200%" filterUnits="objectBoundingBox" id="filter-2">
|
||||
<feOffset dx="0" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
|
||||
<feGaussianBlur stdDeviation="1" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
|
||||
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.2 0" type="matrix" in="shadowBlurOuter1"></feColorMatrix>
|
||||
</filter>
|
||||
</defs>
|
||||
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="时钟底板">
|
||||
<g id="Group-3" transform="translate(3.000000, 3.000000)">
|
||||
<g id="Oval-2">
|
||||
<use fill="black" fill-opacity="1" filter="url(#filter-2)" xlink:href="#path-1"></use>
|
||||
<use fill="#F9AF15" fill-rule="evenodd" xlink:href="#path-1"></use>
|
||||
</g>
|
||||
<circle id="Oval-2" fill="#FFFFFF" cx="21" cy="21" r="18.5"></circle>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 1.4 KiB |
@ -1,12 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg width="8px" height="18px" viewBox="0 0 8 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<!-- Generator: Sketch 3.8.3 (29802) - http://www.bohemiancoding.com/sketch -->
|
||||
<title>数字大0</title>
|
||||
<desc>Created with Sketch.</desc>
|
||||
<defs></defs>
|
||||
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="数字大0" fill="#002422">
|
||||
<path d="M2,7.5079 L0,8.7539 L0,2.5749 L1,1.5039 L2,2.5749 L2,7.5079 Z M2,15.6395 L1,16.5515 L0,15.4805 L0,9.3015 L2,10.3725 L2,15.6395 Z M6.3906,1.002 L5.5296,2.002 L2.4836,2.002 L1.5786,1.002 L2.4836,0.002 L5.5296,0.002 L6.3906,1.002 Z M2.4843,16.0022 L1.5163,17.0022 L2.4843,18.0022 L5.7193,18.0022 L6.5153,17.0022 L5.5303,16.0022 L2.4843,16.0022 Z M5.9997,2.5751 L5.9997,7.5081 L8.0007,8.7531 L8.0007,2.5751 L6.9997,1.5041 L5.9997,2.5751 Z M5.9997,10.3727 L5.9997,15.5827 L6.9997,16.5517 L8.0007,15.4797 L8.0007,9.3007 L5.9997,10.3727 Z" id="Combined-Shape"></path>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 1.1 KiB |
@ -1,12 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg width="8px" height="18px" viewBox="0 0 8 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<!-- Generator: Sketch 3.8.3 (29802) - http://www.bohemiancoding.com/sketch -->
|
||||
<title>数字大1</title>
|
||||
<desc>Created with Sketch.</desc>
|
||||
<defs></defs>
|
||||
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="数字大1" fill="#002422">
|
||||
<path d="M3,2.0018 L3,7.5078 L5,8.7538 L5,0.0018 L3,2.0018 Z M3,10.3727 L3,16.1047 L5,18.0017 L5,9.3007 L3,10.3727 Z" id="Combined-Shape"></path>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 680 B |
@ -1,12 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg width="8px" height="18px" viewBox="0 0 8 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<!-- Generator: Sketch 3.8.3 (29802) - http://www.bohemiancoding.com/sketch -->
|
||||
<title>数字大2</title>
|
||||
<desc>Created with Sketch.</desc>
|
||||
<defs></defs>
|
||||
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="数字大2" fill="#002422">
|
||||
<path d="M2,15.6395 L1,16.5515 L0,15.4805 L0,9.3015 L2,10.3725 L2,15.6395 Z M7,9.002 L5.406,10.002 L2.578,10.002 L1,9.007 L2.484,8.002 L5.53,8.002 L7,9.002 Z M6.3906,1.002 L5.5296,2.002 L-0.0004,2.002 L1.9996,0.002 L5.5296,0.002 L6.3906,1.002 Z M2.4842,16.0022 L1.5162,17.0022 L2.4842,18.0022 L8.0002,18.0022 L5.8112,16.0022 L2.4842,16.0022 Z M8,8.7538 L6,7.5078 L6,2.5748 L7,1.5038 L8,2.5748 L8,8.7538 Z" id="Combined-Shape"></path>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 968 B |
@ -1,12 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg width="8px" height="18px" viewBox="0 0 8 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<!-- Generator: Sketch 3.8.3 (29802) - http://www.bohemiancoding.com/sketch -->
|
||||
<title>数字大3</title>
|
||||
<desc>Created with Sketch.</desc>
|
||||
<defs></defs>
|
||||
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="数字大3" fill="#002422">
|
||||
<path d="M7,9.002 L5.406,10.002 L2.578,10.002 L1,9.007 L2.484,8.002 L5.53,8.002 L7,9.002 Z M6.3906,1.002 L5.5296,2.002 L1.9996,2.002 L-0.0004,0.002 L5.5296,0.002 L6.3906,1.002 Z M1.9999,16.0022 L-0.0001,18.0022 L5.7189,18.0022 L6.5149,17.0022 L5.5299,16.0022 L1.9999,16.0022 Z M8,8.7538 L6,7.5078 L6,2.5748 L7,1.5038 L8,2.5748 L8,8.7538 Z M8,15.4801 L7,16.5521 L6,15.5831 L6,10.3731 L8,9.3011 L8,15.4801 Z" id="Combined-Shape"></path>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 969 B |
@ -1,12 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg width="8px" height="18px" viewBox="0 0 8 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<!-- Generator: Sketch 3.8.3 (29802) - http://www.bohemiancoding.com/sketch -->
|
||||
<title>数字大4</title>
|
||||
<desc>Created with Sketch.</desc>
|
||||
<defs></defs>
|
||||
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="数字大4" fill="#002422">
|
||||
<path d="M2,7.5079 L0,8.7539 L0,0.0019 L2,2.0019 L2,7.5079 Z M7,9.002 L5.406,10.002 L2.578,10.002 L1,9.007 L2.484,8.002 L5.53,8.002 L7,9.002 Z M8,8.7538 L6,7.5078 L6,2.0018 L8,0.0018 L8,8.7538 Z M6.0003,10.3727 L6.0003,16.1047 L8.0003,18.0017 L8.0003,9.3007 L6.0003,10.3727 Z" id="Combined-Shape"></path>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 839 B |
@ -1,12 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg width="8px" height="18px" viewBox="0 0 8 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<!-- Generator: Sketch 3.8.3 (29802) - http://www.bohemiancoding.com/sketch -->
|
||||
<title>数字大5</title>
|
||||
<desc>Created with Sketch.</desc>
|
||||
<defs></defs>
|
||||
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="数字大5" fill="#002422">
|
||||
<path d="M2,7.5079 L0,8.7539 L0,2.5749 L1,1.5039 L2,2.5749 L2,7.5079 Z M7,9.002 L5.406,10.002 L2.578,10.002 L1,9.007 L2.484,8.002 L5.53,8.002 L7,9.002 Z M5.5299,2.002 L2.4839,2.002 L1.5779,1.002 L2.4839,0.002 L7.5299,0.002 L5.5299,2.002 Z M2.4839,16.0022 L0.4839,18.0022 L5.7189,18.0022 L6.5159,17.0022 L5.5299,16.0022 L2.4839,16.0022 Z M8,15.4801 L7,16.5521 L6,15.5831 L6,10.3731 L8,9.3011 L8,15.4801 Z" id="Combined-Shape"></path>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 967 B |
@ -1,12 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg width="8px" height="18px" viewBox="0 0 8 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<!-- Generator: Sketch 3.8.3 (29802) - http://www.bohemiancoding.com/sketch -->
|
||||
<title>数字大6</title>
|
||||
<desc>Created with Sketch.</desc>
|
||||
<defs></defs>
|
||||
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="数字大6" fill="#002422">
|
||||
<path d="M2,7.5079 L0,8.7539 L0,2.5749 L1,1.5039 L2,2.5749 L2,7.5079 Z M2,15.6395 L1,16.5515 L0,15.4805 L0,9.3015 L2,10.3725 L2,15.6395 Z M7,9.002 L5.406,10.002 L2.578,10.002 L1,9.007 L2.484,8.002 L5.53,8.002 L7,9.002 Z M5.5299,2.002 L2.4839,2.002 L1.5779,1.002 L2.4839,0.002 L7.5299,0.002 L5.5299,2.002 Z M2.4838,16.0022 L1.5158,17.0022 L2.4838,18.0022 L5.7188,18.0022 L6.5158,17.0022 L5.5308,16.0022 L2.4838,16.0022 Z M8,15.4801 L7,16.5521 L6,15.5831 L6,10.3731 L8,9.3011 L8,15.4801 Z" id="Combined-Shape"></path>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 1.0 KiB |
@ -1,12 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg width="8px" height="18px" viewBox="0 0 8 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<!-- Generator: Sketch 3.8.3 (29802) - http://www.bohemiancoding.com/sketch -->
|
||||
<title>数字大7</title>
|
||||
<desc>Created with Sketch.</desc>
|
||||
<defs></defs>
|
||||
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="数字大7" fill="#002422">
|
||||
<path d="M5.5299,2.002 L1.9999,2.002 L-0.0001,0.002 L7.5299,0.002 L5.5299,2.002 Z M8,8.7538 L6,7.5078 L6,2.5748 L8,0.5748 L8,8.7538 Z M6,10.3727 L6,16.0537 L8,17.9507 L8,9.3007 L6,10.3727 Z" id="Combined-Shape"></path>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 753 B |
@ -1,12 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg width="8px" height="18px" viewBox="0 0 8 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<!-- Generator: Sketch 3.8.3 (29802) - http://www.bohemiancoding.com/sketch -->
|
||||
<title>数字大8</title>
|
||||
<desc>Created with Sketch.</desc>
|
||||
<defs></defs>
|
||||
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="数字大8" fill="#002422">
|
||||
<path d="M2,7.5079 L0,8.7539 L0,2.5749 L1,1.5039 L2,2.5749 L2,7.5079 L2,7.5079 Z M2,15.6395 L1,16.5515 L0,15.4805 L0,9.3015 L2,10.3725 L2,15.6395 L2,15.6395 Z M7,9.002 L5.406,10.002 L2.578,10.002 L1,9.007 L2.484,8.002 L5.53,8.002 L7,9.002 L7,9.002 Z M6.3906,1.002 L5.5296,2.002 L2.4836,2.002 L1.5786,1.002 L2.4836,0.002 L5.5296,0.002 L6.3906,1.002 L6.3906,1.002 Z M2.4836,16.0022 L1.5156,17.0022 L2.4836,18.0022 L5.7196,18.0022 L6.5156,17.0022 L5.5306,16.0022 L2.4836,16.0022 L2.4836,16.0022 Z M8,8.7538 L6,7.5078 L6,2.5748 L7,1.5038 L8,2.5748 L8,8.7538 L8,8.7538 Z M8,15.4801 L7,16.5521 L6,15.5831 L6,10.3731 L8,9.3011 L8,15.4801 L8,15.4801 Z" id="Combined-Shape"></path>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 1.2 KiB |
@ -1,12 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg width="8px" height="18px" viewBox="0 0 8 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<!-- Generator: Sketch 3.8.3 (29802) - http://www.bohemiancoding.com/sketch -->
|
||||
<title>数字大9</title>
|
||||
<desc>Created with Sketch.</desc>
|
||||
<defs></defs>
|
||||
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="数字大9" fill="#002422">
|
||||
<path d="M2,7.5079 L0,8.7539 L0,2.5749 L1,1.5039 L2,2.5749 L2,7.5079 Z M7,9.002 L5.406,10.002 L2.578,10.002 L1,9.007 L2.484,8.002 L5.53,8.002 L7,9.002 Z M6.3906,1.002 L5.5296,2.002 L2.4836,2.002 L1.5786,1.002 L2.4836,0.002 L5.5296,0.002 L6.3906,1.002 Z M2.4835,16.0022 L0.4835,18.0022 L5.7195,18.0022 L6.5155,17.0022 L5.5295,16.0022 L2.4835,16.0022 Z M8,8.7538 L6,7.5078 L6,2.5748 L7,1.5038 L8,2.5748 L8,8.7538 Z M8,15.4801 L7,16.5521 L6,15.5831 L6,10.3731 L8,9.3011 L8,15.4801 Z" id="Combined-Shape"></path>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 1.0 KiB |
@ -1,12 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg width="5px" height="9px" viewBox="0 0 5 9" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<!-- Generator: Sketch 3.8.3 (29802) - http://www.bohemiancoding.com/sketch -->
|
||||
<title>数字小0</title>
|
||||
<desc>Created with Sketch.</desc>
|
||||
<defs></defs>
|
||||
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="数字小0" fill="#002422">
|
||||
<path d="M-0.0003,1.2581 L-0.0003,4.3581 L0.9997,3.7331 L0.9997,1.2581 L0.4997,0.7201 L-0.0003,1.2581 Z M-0.0003,7.7336 L0.4997,8.2716 L0.9997,7.7336 L0.9997,5.1716 L-0.0003,4.6336 L-0.0003,7.7336 Z M1.2516,0.0017 L0.7246,0.5137 L1.2516,1.0017 L3.7596,1.0017 L4.2886,0.5137 L3.7596,0.0017 L1.2516,0.0017 Z M1.2516,8.0018 L0.7246,8.4908 L1.2516,9.0018 L3.7596,9.0018 L4.2886,8.4908 L3.7596,8.0018 L1.2516,8.0018 Z M4.0002,1.2581 L4.0002,3.7331 L5.0002,4.3581 L5.0002,1.2581 L4.4992,0.7201 L4.0002,1.2581 Z M4.0002,5.1713 L4.0002,7.7333 L4.4992,8.2723 L5.0002,7.7333 L5.0002,4.6333 L4.0002,5.1713 Z" id="Combined-Shape"></path>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 1.1 KiB |
@ -1,12 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg width="5px" height="9px" viewBox="0 0 5 9" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<!-- Generator: Sketch 3.8.3 (29802) - http://www.bohemiancoding.com/sketch -->
|
||||
<title>数字小1</title>
|
||||
<desc>Created with Sketch.</desc>
|
||||
<defs></defs>
|
||||
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="数字小1" fill="#002422">
|
||||
<path d="M2.0004,1.0781 L2.0004,3.7361 L3.0004,4.3591 L3.0004,0.0051 L2.0004,1.0781 Z M2.0004,5.1722 L2.0004,7.9232 L3.0004,9.0002 L3.0004,4.6342 L2.0004,5.1722 Z" id="Combined-Shape"></path>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 724 B |
@ -1,12 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg width="5px" height="9px" viewBox="0 0 5 9" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<!-- Generator: Sketch 3.8.3 (29802) - http://www.bohemiancoding.com/sketch -->
|
||||
<title>数字小2</title>
|
||||
<desc>Created with Sketch.</desc>
|
||||
<defs></defs>
|
||||
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="数字小2" fill="#002422">
|
||||
<path d="M1.2519,0.0017 L0.0399,1.0017 L3.7599,1.0017 L4.2889,0.5137 L3.7599,0.0017 L1.2519,0.0017 Z M0,7.7336 L0.5,8.2716 L1,7.7336 L1,5.2746 L0,4.7366 L0,7.7336 Z M1.2519,4.0022 L0.2799,4.5452 L1.2519,5.0022 L3.7599,5.0022 L4.7319,4.5452 L3.7599,4.0022 L1.2519,4.0022 Z M1.2519,8.0018 L0.7249,8.4908 L1.2519,9.0018 L4.9599,9.0018 L3.9759,8.0018 L1.2519,8.0018 Z M3.9996,1.2581 L3.9996,3.7331 L5.0006,4.2681 L5.0006,1.2581 L4.4996,0.7201 L3.9996,1.2581 Z" id="Combined-Shape"></path>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 1017 B |
@ -1,12 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg width="5px" height="9px" viewBox="0 0 5 9" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<!-- Generator: Sketch 3.8.3 (29802) - http://www.bohemiancoding.com/sketch -->
|
||||
<title>数字小3</title>
|
||||
<desc>Created with Sketch.</desc>
|
||||
<defs></defs>
|
||||
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="数字小3" fill="#002422">
|
||||
<path d="M0.0174,0.0017 L1.0054,1.0017 L3.7384,1.0017 L4.2614,0.5137 L3.7384,0.0017 L0.0174,0.0017 Z M1.0056,8.0018 L0.0176,9.0018 L3.4926,9.0018 L4.0156,8.4908 L3.4926,8.0018 L1.0056,8.0018 Z M1.0056,4.0022 L0.0416,4.5452 L1.0056,5.0022 L3.4926,5.0022 L4.4566,4.5642 L3.4926,4.0022 L1.0056,4.0022 Z M3.9999,1.3058 L3.9999,3.7818 L4.9999,4.4058 L4.9999,1.3058 L4.4999,0.7678 L3.9999,1.3058 Z M3.9999,5.219 L3.9999,7.781 L4.4999,8.32 L4.9999,7.781 L4.9999,4.681 L3.9999,5.219 Z" id="Combined-Shape"></path>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 1.0 KiB |
@ -1,12 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg width="5px" height="9px" viewBox="0 0 5 9" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<!-- Generator: Sketch 3.8.3 (29802) - http://www.bohemiancoding.com/sketch -->
|
||||
<title>数字小4</title>
|
||||
<desc>Created with Sketch.</desc>
|
||||
<defs></defs>
|
||||
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="数字小4" fill="#002422">
|
||||
<path d="M-0.0003,-0.0001 L-0.0003,4.2679 L0.9997,3.7389 L0.9997,1.0019 L-0.0003,-0.0001 Z M1.2516,4.0022 L0.2796,4.5452 L1.2516,5.0022 L3.7596,5.0022 L4.7316,4.5642 L3.7596,4.0022 L1.2516,4.0022 Z M4.0002,1.0016 L4.0002,3.7396 L5.0002,4.3626 L5.0002,0.0086 L4.0002,1.0016 Z M4.0002,5.3207 L4.0002,8.0017 L5.0002,9.0047 L5.0002,4.7827 L4.0002,5.3207 Z" id="Combined-Shape"></path>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 913 B |
@ -1,12 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg width="5px" height="9px" viewBox="0 0 5 9" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<!-- Generator: Sketch 3.8.3 (29802) - http://www.bohemiancoding.com/sketch -->
|
||||
<title>数字小5</title>
|
||||
<desc>Created with Sketch.</desc>
|
||||
<defs></defs>
|
||||
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="数字小5" fill="#002422">
|
||||
<path d="M0,1.2581 L0,4.3581 L1,3.7331 L1,1.2581 L0.5,0.7201 L0,1.2581 Z M1.0503,8.0018 L0.0543,9.0018 L3.7733,9.0018 L4.3023,8.4908 L3.7733,8.0018 L1.0503,8.0018 Z M1.2663,4.0022 L0.2943,4.5452 L1.2663,5.0022 L3.7733,5.0022 L4.7453,4.5452 L3.7733,4.0022 L1.2663,4.0022 Z M1.2663,0.0017 L0.7383,0.5137 L1.2663,1.0017 L3.7733,1.0017 L4.7583,0.0017 L1.2663,0.0017 Z M3.9996,5.3207 L3.9996,7.7337 L4.4996,8.2717 L5.0006,7.7337 L5.0006,4.7827 L3.9996,5.3207 Z" id="Combined-Shape"></path>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 1017 B |
@ -1,12 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg width="5px" height="9px" viewBox="0 0 5 9" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<!-- Generator: Sketch 3.8.3 (29802) - http://www.bohemiancoding.com/sketch -->
|
||||
<title>数字小6</title>
|
||||
<desc>Created with Sketch.</desc>
|
||||
<defs></defs>
|
||||
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="数字小6" fill="#002422">
|
||||
<path d="M0.0003,1.2581 L0.0003,4.3581 L1.0003,3.7331 L1.0003,1.2581 L0.4993,0.7201 L0.0003,1.2581 Z M0.0003,7.7336 L0.4993,8.2716 L1.0003,7.7336 L1.0003,5.3206 L0.0003,4.7826 L0.0003,7.7336 Z M1.2063,4.0022 L0.2343,4.5452 L1.2063,5.0022 L3.7133,5.0022 L4.6853,4.5642 L3.7133,4.0022 L1.2063,4.0022 Z M1.2063,0.0017 L0.6783,0.5137 L1.2063,1.0017 L3.7133,1.0017 L4.6983,0.0017 L1.2063,0.0017 Z M1.2063,8.0018 L0.6783,8.4908 L1.2063,9.0018 L3.7133,9.0018 L4.2423,8.4908 L3.7133,8.0018 L1.2063,8.0018 Z M3.9999,5.3207 L3.9999,7.7337 L4.4999,8.2717 L4.9999,7.7337 L4.9999,4.7827 L3.9999,5.3207 Z" id="Combined-Shape"></path>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 1.1 KiB |
@ -1,12 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg width="5px" height="9px" viewBox="0 0 5 9" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<!-- Generator: Sketch 3.8.3 (29802) - http://www.bohemiancoding.com/sketch -->
|
||||
<title>数字小7</title>
|
||||
<desc>Created with Sketch.</desc>
|
||||
<defs></defs>
|
||||
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="数字小7" fill="#002422">
|
||||
<path d="M0.2481,0.0017 L1.2731,1.0017 L3.7621,1.0017 L4.8161,0.0017 L0.2481,0.0017 Z M4.0002,1.2572 L4.0002,3.7322 L5.0002,4.3572 L5.0002,0.3452 L4.0002,1.2572 Z M4.0002,5.1704 L4.0002,8.0014 L5.0002,8.9984 L5.0002,4.6324 L4.0002,5.1704 Z" id="Combined-Shape"></path>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 801 B |
@ -1,12 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg width="5px" height="9px" viewBox="0 0 5 9" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<!-- Generator: Sketch 3.8.3 (29802) - http://www.bohemiancoding.com/sketch -->
|
||||
<title>数字小8</title>
|
||||
<desc>Created with Sketch.</desc>
|
||||
<defs></defs>
|
||||
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="数字小8" fill="#002422">
|
||||
<path d="M0,1.2563 L0,4.3563 L1,3.7313 L1,1.2563 L0.5,0.7183 L0,1.2563 Z M1,7.7315 L0.5,8.2695 L0,7.7315 L0.006,4.7325 L1.006,5.2705 L1,7.7315 Z M1.2519,4.0022 L0.2799,4.5452 L1.2519,5.0022 L3.7599,5.0022 L4.7319,4.5642 L3.7599,4.0022 L1.2519,4.0022 Z M1.2519,0.0017 L0.7249,0.5137 L1.2519,1.0017 L3.7599,1.0017 L4.2889,0.5137 L3.7599,0.0017 L1.2519,0.0017 Z M1.2519,8.0018 L0.7249,8.4908 L1.2519,9.0018 L3.7599,9.0018 L4.2889,8.4908 L3.7599,8.0018 L1.2519,8.0018 Z M3.9996,1.2563 L3.9996,3.7313 L5.0006,4.3563 L5.0006,1.2563 L4.4996,0.7183 L3.9996,1.2563 Z M5,7.7315 L4.5,8.2695 L4,7.7315 L4.006,5.2705 L5.006,4.7325 L5,7.7315 Z" id="Combined-Shape"></path>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 1.2 KiB |
@ -1,12 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg width="5px" height="9px" viewBox="0 0 5 9" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<!-- Generator: Sketch 3.8.3 (29802) - http://www.bohemiancoding.com/sketch -->
|
||||
<title>数字小9</title>
|
||||
<desc>Created with Sketch.</desc>
|
||||
<defs></defs>
|
||||
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="数字小9" fill="#002422">
|
||||
<path d="M0.0003,1.2563 L0.0003,4.3563 L1.0003,3.8183 L1.0003,1.2563 L0.4993,0.7183 L0.0003,1.2563 Z M1.2522,8.0018 L0.2562,9.0018 L3.7592,9.0018 L4.2882,8.4908 L3.7592,8.0018 L1.2522,8.0018 Z M1.2522,4.0022 L0.2802,4.5452 L1.2522,5.0022 L3.7592,5.0022 L4.7312,4.5642 L3.7592,4.0022 L1.2522,4.0022 Z M1.2522,0.0017 L0.7242,0.5137 L1.2522,1.0017 L3.7592,1.0017 L4.2882,0.5137 L3.7592,0.0017 L1.2522,0.0017 Z M3.9999,1.2563 L3.9999,3.8183 L4.9999,4.3563 L4.9999,1.2563 L4.4999,0.7183 L3.9999,1.2563 Z M3.9999,5.2559 L3.9999,7.7319 L4.4999,8.2699 L4.9999,7.7319 L4.9999,4.6309 L3.9999,5.2559 Z" id="Combined-Shape"></path>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 1.1 KiB |
@ -1,46 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 21.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 10 5" style="enable-background:new 0 0 10 5;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{opacity:0.3;fill:#2EA7E0;}
|
||||
.st1{fill:url(#SVGID_1_);}
|
||||
.st2{opacity:0.5;fill:url(#SVGID_2_);}
|
||||
.st3{fill:#FFFFFF;}
|
||||
.st4{opacity:0.4;}
|
||||
.st5{opacity:0.2;}
|
||||
.st6{fill:#0C0C0C;}
|
||||
.st7{fill:url(#SVGID_3_);}
|
||||
.st8{fill:#002422;}
|
||||
.st9{fill:url(#SVGID_4_);}
|
||||
.st10{fill:url(#SVGID_5_);}
|
||||
.st11{fill:url(#SVGID_6_);}
|
||||
.st12{fill:url(#SVGID_7_);}
|
||||
.st13{fill:#FFBC00;}
|
||||
.st14{fill:url(#SVGID_8_);}
|
||||
.st15{opacity:0.5;fill:url(#SVGID_9_);}
|
||||
.st16{fill:url(#SVGID_10_);}
|
||||
.st17{fill:url(#SVGID_11_);}
|
||||
.st18{fill:url(#SVGID_12_);}
|
||||
.st19{fill:url(#SVGID_13_);}
|
||||
.st20{fill:url(#SVGID_14_);}
|
||||
.st21{opacity:0.5;fill:#231815;}
|
||||
.st22{opacity:0.4;fill:#231815;}
|
||||
.st23{fill:#47E700;}
|
||||
.st24{fill:url(#SVGID_15_);}
|
||||
.st25{opacity:0.4;fill:#47E700;}
|
||||
.st26{opacity:0.7;fill:#2EA7E0;}
|
||||
.st27{opacity:0.48;}
|
||||
.st28{opacity:0.33;}
|
||||
.st29{opacity:0.38;}
|
||||
.st30{opacity:0.5;}
|
||||
.st31{fill:#CF9111;}
|
||||
.st32{fill:#F9AF15;}
|
||||
.st33{fill:#95A6A4;}
|
||||
.st34{opacity:0.5;fill:#00A0E9;}
|
||||
</style>
|
||||
<g>
|
||||
<path class="st33" d="M0,0v5h1V3h2v2h1V0H0z M3,2H1V1h2V2z"/>
|
||||
<polygon class="st33" points="8,0 7,0 6,0 5,0 5,1 5,5 6,5 6,1 7,1 7,5 8,5 8,1 9,1 9,5 10,5 10,1 10,0 9,0 "/>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 1.5 KiB |
@ -1,46 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 21.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 10 5" style="enable-background:new 0 0 10 5;" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{opacity:0.3;fill:#2EA7E0;}
|
||||
.st1{fill:url(#SVGID_1_);}
|
||||
.st2{opacity:0.5;fill:url(#SVGID_2_);}
|
||||
.st3{fill:#FFFFFF;}
|
||||
.st4{opacity:0.4;}
|
||||
.st5{opacity:0.2;}
|
||||
.st6{fill:#0C0C0C;}
|
||||
.st7{fill:url(#SVGID_3_);}
|
||||
.st8{fill:#002422;}
|
||||
.st9{fill:url(#SVGID_4_);}
|
||||
.st10{fill:url(#SVGID_5_);}
|
||||
.st11{fill:url(#SVGID_6_);}
|
||||
.st12{fill:url(#SVGID_7_);}
|
||||
.st13{fill:#FFBC00;}
|
||||
.st14{fill:url(#SVGID_8_);}
|
||||
.st15{opacity:0.5;fill:url(#SVGID_9_);}
|
||||
.st16{fill:url(#SVGID_10_);}
|
||||
.st17{fill:url(#SVGID_11_);}
|
||||
.st18{fill:url(#SVGID_12_);}
|
||||
.st19{fill:url(#SVGID_13_);}
|
||||
.st20{fill:url(#SVGID_14_);}
|
||||
.st21{opacity:0.5;fill:#231815;}
|
||||
.st22{opacity:0.4;fill:#231815;}
|
||||
.st23{fill:#47E700;}
|
||||
.st24{fill:url(#SVGID_15_);}
|
||||
.st25{opacity:0.4;fill:#47E700;}
|
||||
.st26{opacity:0.7;fill:#2EA7E0;}
|
||||
.st27{opacity:0.48;}
|
||||
.st28{opacity:0.33;}
|
||||
.st29{opacity:0.38;}
|
||||
.st30{opacity:0.5;}
|
||||
.st31{fill:#CF9111;}
|
||||
.st32{fill:#F9AF15;}
|
||||
.st33{fill:#95A6A4;}
|
||||
.st34{opacity:0.5;fill:#00A0E9;}
|
||||
</style>
|
||||
<g>
|
||||
<path class="st33" d="M0,5h1V3h3V0H0V5z M1,1h2v1H1V1z"/>
|
||||
<polygon class="st33" points="9,0 8,0 7,0 6,0 5,0 5,1 5,5 6,5 6,1 7,1 7,5 8,5 8,1 9,1 9,5 10,5 10,1 10,0 "/>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 1.5 KiB |
@ -1,76 +0,0 @@
|
||||
|
||||
set(PLUGIN_NAME "tray")
|
||||
|
||||
project(${PLUGIN_NAME})
|
||||
|
||||
generation_dbus_interface(${CMAKE_CURRENT_SOURCE_DIR}/dbusinterface/xml ${CMAKE_CURRENT_SOURCE_DIR}/dbusinterface/generation_dbus_interface)
|
||||
|
||||
# Sources files
|
||||
file(GLOB_RECURSE SRCS "*.h"
|
||||
"*.cpp"
|
||||
"../../widgets/*.h"
|
||||
"../../widgets/*.cpp"
|
||||
"../../frame/util/themeappicon.h"
|
||||
"../../frame/util/themeappicon.cpp"
|
||||
"../../frame/util/dockpopupwindow.h"
|
||||
"../../frame/util/dockpopupwindow.cpp"
|
||||
"../../frame/util/abstractpluginscontroller.h"
|
||||
"../../frame/util/abstractpluginscontroller.cpp"
|
||||
"../../frame/util/pluginloader.h"
|
||||
"../../frame/util/pluginloader.cpp"
|
||||
"../../frame/dbus/sni/*.h"
|
||||
"../../frame/dbus/sni/*.cpp"
|
||||
"../../frame/dbus/dbusmenu.h"
|
||||
"../../frame/dbus/dbusmenu.cpp"
|
||||
"../../frame/dbus/dbusmenumanager.h"
|
||||
"../../frame/dbus/dbusmenumanager.cpp"
|
||||
"../../frame/dbus/dockinterface.h"
|
||||
"../../frame/dbus/dockinterface.cpp"
|
||||
"../../widgets/*.h"
|
||||
"../../widgets/*.cpp"
|
||||
"../../frame/util/imageutil.h"
|
||||
"../../frame/util/imageutil.cpp"
|
||||
"../../frame/util/menudialog.h"
|
||||
"../../frame/util/menudialog.cpp"
|
||||
"../../frame/util/touchsignalmanager.h"
|
||||
"../../frame/util/touchsignalmanager.cpp"
|
||||
"../../frame/controller/proxyplugincontroller.h"
|
||||
"../../frame/controller/proxyplugincontroller.cpp"
|
||||
"../../frame/qtdbusextended/*.h"
|
||||
"../../frame/qtdbusextended/*.cpp"
|
||||
)
|
||||
|
||||
find_package(PkgConfig REQUIRED)
|
||||
find_package(Qt5Widgets REQUIRED)
|
||||
find_package(Qt5Svg REQUIRED)
|
||||
find_package(Qt5DBus REQUIRED)
|
||||
find_package(Qt5X11Extras REQUIRED)
|
||||
find_package(Qt5Concurrent REQUIRED)
|
||||
find_package(DtkWidget REQUIRED)
|
||||
find_package(dbusmenu-qt5 REQUIRED)
|
||||
|
||||
pkg_check_modules(XCB_LIBS REQUIRED xcb-ewmh xcb xcb-image xcb-composite xtst x11 xext xcb-icccm dbusmenu-qt5 xcursor)
|
||||
pkg_check_modules(QGSettings REQUIRED gsettings-qt)
|
||||
|
||||
add_definitions("${QT_DEFINITIONS} -DQT_PLUGIN")
|
||||
add_library(${PLUGIN_NAME} SHARED ${SRCS} tray.qrc)
|
||||
set_target_properties(${PLUGIN_NAME} PROPERTIES LIBRARY_OUTPUT_DIRECTORY ../)
|
||||
target_include_directories(${PLUGIN_NAME} PUBLIC ${DtkWidget_INCLUDE_DIRS}
|
||||
../../interfaces
|
||||
../../frame
|
||||
../../frame/qtdbusextended
|
||||
./dbusinterface
|
||||
./dbusinterface/generation_dbus_interface)
|
||||
|
||||
target_link_libraries(${PLUGIN_NAME} PRIVATE
|
||||
${DtkWidget_LIBRARIES}
|
||||
PkgConfig::QGSettings
|
||||
PkgConfig::XCB_LIBS
|
||||
Qt5::Concurrent
|
||||
Qt5::X11Extras
|
||||
Qt5::Widgets
|
||||
Qt5::DBus
|
||||
Qt5::Svg
|
||||
pthread)
|
||||
|
||||
install(TARGETS ${PLUGIN_NAME} LIBRARY DESTINATION lib/dde-dock/plugins)
|
@ -1,129 +0,0 @@
|
||||
// Copyright (C) 2011 ~ 2018 Deepin Technology Co., Ltd.
|
||||
// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#include "constants.h"
|
||||
#include "abstracttraywidget.h"
|
||||
|
||||
#include <xcb/xproto.h>
|
||||
#include <QMouseEvent>
|
||||
#include <QDebug>
|
||||
|
||||
AbstractTrayWidget::AbstractTrayWidget(QWidget *parent, Qt::WindowFlags f)
|
||||
: QWidget(parent, f)
|
||||
, m_handleMouseReleaseTimer(new QTimer(this))
|
||||
, m_ownerPID(0)
|
||||
{
|
||||
m_handleMouseReleaseTimer->setSingleShot(true);
|
||||
m_handleMouseReleaseTimer->setInterval(10);
|
||||
|
||||
connect(m_handleMouseReleaseTimer, &QTimer::timeout, this, &AbstractTrayWidget::handleMouseRelease);
|
||||
}
|
||||
|
||||
AbstractTrayWidget::~AbstractTrayWidget()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void AbstractTrayWidget::mousePressEvent(QMouseEvent *event)
|
||||
{
|
||||
// call QWidget::mousePressEvent means to show dock-context-menu
|
||||
// when right button of mouse is pressed immediately in fashion mode
|
||||
|
||||
// here we hide the right button press event when it is click in the special area
|
||||
if (event->button() == Qt::RightButton && perfectIconRect().contains(event->pos(), true)) {
|
||||
event->accept();
|
||||
return;
|
||||
}
|
||||
|
||||
QWidget::mousePressEvent(event);
|
||||
}
|
||||
|
||||
void AbstractTrayWidget::mouseReleaseEvent(QMouseEvent *e)
|
||||
{
|
||||
//e->accept();
|
||||
|
||||
// 由于 XWindowTrayWidget 中对 发送鼠标事件到X窗口的函数, 如 sendClick/sendHoverEvent 中
|
||||
// 使用了 setX11PassMouseEvent, 而每次调用 setX11PassMouseEvent 时都会导致产生 mousePress 和 mouseRelease 事件
|
||||
// 因此如果直接在这里处理事件会导致一些问题, 所以使用 Timer 来延迟处理 100 毫秒内的最后一个事件
|
||||
m_lastMouseReleaseData.first = e->pos();
|
||||
m_lastMouseReleaseData.second = e->button();
|
||||
|
||||
m_handleMouseReleaseTimer->start();
|
||||
|
||||
QWidget::mouseReleaseEvent(e);
|
||||
}
|
||||
|
||||
|
||||
void AbstractTrayWidget::handleMouseRelease()
|
||||
{
|
||||
Q_ASSERT(sender() == m_handleMouseReleaseTimer);
|
||||
|
||||
// do not dealwith all mouse event of SystemTray, class SystemTrayItem will handle it
|
||||
if (trayTyep() == SystemTray)
|
||||
return;
|
||||
|
||||
const QPoint point(m_lastMouseReleaseData.first - rect().center());
|
||||
if (point.manhattanLength() > 24)
|
||||
return;
|
||||
|
||||
QPoint globalPos = QCursor::pos();
|
||||
uint8_t buttonIndex = XCB_BUTTON_INDEX_1;
|
||||
|
||||
switch (m_lastMouseReleaseData.second) {
|
||||
case Qt:: MiddleButton:
|
||||
buttonIndex = XCB_BUTTON_INDEX_2;
|
||||
break;
|
||||
case Qt::RightButton:
|
||||
buttonIndex = XCB_BUTTON_INDEX_3;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
sendClick(buttonIndex, globalPos.x(), globalPos.y());
|
||||
|
||||
// left mouse button clicked
|
||||
if (buttonIndex == XCB_BUTTON_INDEX_1) {
|
||||
Q_EMIT clicked();
|
||||
}
|
||||
}
|
||||
|
||||
const QRect AbstractTrayWidget::perfectIconRect() const
|
||||
{
|
||||
const QRect itemRect = rect();
|
||||
const int iconSize = std::min(itemRect.width(), itemRect.height());
|
||||
|
||||
QRect iconRect;
|
||||
iconRect.setWidth(iconSize);
|
||||
iconRect.setHeight(iconSize);
|
||||
iconRect.moveTopLeft(itemRect.center() - iconRect.center());
|
||||
|
||||
return iconRect;
|
||||
}
|
||||
|
||||
void AbstractTrayWidget::resizeEvent(QResizeEvent *event)
|
||||
{
|
||||
QWidget::resizeEvent(event);
|
||||
|
||||
const Dock::Position position = qApp->property(PROP_POSITION).value<Dock::Position>();
|
||||
// 保持横纵比
|
||||
if (position == Dock::Bottom || position == Dock::Top) {
|
||||
setMaximumWidth(height());
|
||||
setMaximumHeight(QWIDGETSIZE_MAX);
|
||||
} else {
|
||||
setMaximumHeight(width());
|
||||
setMaximumWidth(QWIDGETSIZE_MAX);
|
||||
}
|
||||
}
|
||||
|
||||
uint AbstractTrayWidget::getOwnerPID()
|
||||
{
|
||||
return this->m_ownerPID;
|
||||
}
|
||||
|
||||
void AbstractTrayWidget::setOwnerPID(uint PID)
|
||||
{
|
||||
this->m_ownerPID = PID;
|
||||
}
|
@ -1,55 +0,0 @@
|
||||
// Copyright (C) 2011 ~ 2018 Deepin Technology Co., Ltd.
|
||||
// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QWidget>
|
||||
#include <QTimer>
|
||||
#include <QPair>
|
||||
|
||||
class QDBusMessage;
|
||||
class AbstractTrayWidget: public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum TrayType {
|
||||
ApplicationTray,
|
||||
SystemTray,
|
||||
};
|
||||
|
||||
explicit AbstractTrayWidget(QWidget *parent = Q_NULLPTR, Qt::WindowFlags f = Qt::WindowFlags());
|
||||
virtual ~AbstractTrayWidget();
|
||||
|
||||
virtual QString itemKeyForConfig() = 0;
|
||||
virtual void updateIcon() = 0;
|
||||
virtual void sendClick(uint8_t mouseButton, int x, int y) = 0;
|
||||
virtual inline TrayType trayTyep() const { return TrayType::ApplicationTray; } // default is ApplicationTray
|
||||
virtual bool isValid() {return true;}
|
||||
uint getOwnerPID();
|
||||
|
||||
Q_SIGNALS:
|
||||
void iconChanged();
|
||||
void clicked();
|
||||
void needAttention();
|
||||
void requestWindowAutoHide(const bool autoHide);
|
||||
void requestRefershWindowVisible();
|
||||
|
||||
protected:
|
||||
void mousePressEvent(QMouseEvent *event) override;
|
||||
void mouseReleaseEvent(QMouseEvent *e) override;
|
||||
|
||||
void handleMouseRelease();
|
||||
const QRect perfectIconRect() const;
|
||||
void resizeEvent(QResizeEvent *event) override;
|
||||
void setOwnerPID(uint PID);
|
||||
|
||||
private:
|
||||
QTimer *m_handleMouseReleaseTimer;
|
||||
|
||||
QPair<QPoint, Qt::MouseButton> m_lastMouseReleaseData;
|
||||
|
||||
uint m_ownerPID;
|
||||
};
|
||||
|
@ -1,31 +0,0 @@
|
||||
/*
|
||||
* This file was generated by qdbusxml2cpp version 0.8
|
||||
* Command line was: qdbusxml2cpp -c DBusTrayManager -p dbustraymanager org.deepin.dde.TrayManager1.xml
|
||||
*
|
||||
* qdbusxml2cpp is Copyright (C) 2015 Digia Plc and/or its subsidiary(-ies).
|
||||
*
|
||||
* This is an auto-generated file.
|
||||
* This file may have been hand-edited. Look for HAND-EDIT comments
|
||||
* before re-generating it.
|
||||
*/
|
||||
|
||||
#include "dbustraymanager.h"
|
||||
|
||||
/*
|
||||
* Implementation of interface class DBusTrayManager
|
||||
*/
|
||||
|
||||
DBusTrayManager::DBusTrayManager(QObject *parent)
|
||||
: QDBusAbstractInterface("org.deepin.dde.TrayManager1", "/org/deepin/dde/TrayManager1", staticInterfaceName(), QDBusConnection::sessionBus(), parent)
|
||||
{
|
||||
qRegisterMetaType<TrayList>("TrayList");
|
||||
qDBusRegisterMetaType<TrayList>();
|
||||
|
||||
QDBusConnection::sessionBus().connect(this->service(), this->path(), "org.freedesktop.DBus.Properties", "PropertiesChanged","sa{sv}as", this, SLOT(__propertyChanged__(QDBusMessage)));
|
||||
}
|
||||
|
||||
DBusTrayManager::~DBusTrayManager()
|
||||
{
|
||||
QDBusConnection::sessionBus().disconnect(service(), path(), "org.freedesktop.DBus.Properties", "PropertiesChanged", "sa{sv}as", this, SLOT(propertyChanged(QDBusMessage)));
|
||||
}
|
||||
|
@ -1,113 +0,0 @@
|
||||
/*
|
||||
* This file was generated by qdbusxml2cpp version 0.8
|
||||
* Command line was: qdbusxml2cpp -c DBusTrayManager -p dbustraymanager org.deepin.dde.TrayManager1.xml
|
||||
*
|
||||
* qdbusxml2cpp is Copyright (C) 2015 Digia Plc and/or its subsidiary(-ies).
|
||||
*
|
||||
* This is an auto-generated file.
|
||||
* Do not edit! All changes made to it will be lost.
|
||||
*/
|
||||
|
||||
#ifndef DBUSTRAYMANAGER_H_1467094672
|
||||
#define DBUSTRAYMANAGER_H_1467094672
|
||||
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/QByteArray>
|
||||
#include <QtCore/QList>
|
||||
#include <QtCore/QMap>
|
||||
#include <QtCore/QString>
|
||||
#include <QtCore/QStringList>
|
||||
#include <QtCore/QVariant>
|
||||
#include <QtDBus/QtDBus>
|
||||
|
||||
typedef QList<quint32> TrayList;
|
||||
|
||||
/*
|
||||
* Proxy class for interface org.deepin.dde.TrayManager1
|
||||
*/
|
||||
class DBusTrayManager: public QDBusAbstractInterface
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_SLOT void __propertyChanged__(const QDBusMessage& msg)
|
||||
{
|
||||
QList<QVariant> arguments = msg.arguments();
|
||||
if (3 != arguments.count())
|
||||
return;
|
||||
QString interfaceName = msg.arguments().at(0).toString();
|
||||
if (interfaceName !="org.deepin.dde.TrayManager1")
|
||||
return;
|
||||
QVariantMap changedProps = qdbus_cast<QVariantMap>(arguments.at(1).value<QDBusArgument>());
|
||||
foreach(const QString &prop, changedProps.keys()) {
|
||||
const QMetaObject* self = metaObject();
|
||||
for (int i=self->propertyOffset(); i < self->propertyCount(); ++i) {
|
||||
QMetaProperty p = self->property(i);
|
||||
if (p.name() == prop) {
|
||||
Q_EMIT p.notifySignal().invoke(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
public:
|
||||
static inline const char *staticInterfaceName()
|
||||
{ return "org.deepin.dde.TrayManager1"; }
|
||||
|
||||
public:
|
||||
explicit DBusTrayManager(QObject *parent = 0);
|
||||
|
||||
~DBusTrayManager();
|
||||
|
||||
Q_PROPERTY(TrayList TrayIcons READ trayIcons NOTIFY TrayIconsChanged)
|
||||
inline TrayList trayIcons() const
|
||||
{ return qvariant_cast< TrayList >(property("TrayIcons")); }
|
||||
|
||||
public Q_SLOTS: // METHODS
|
||||
inline QDBusPendingReply<> EnableNotification(uint in0, bool in1)
|
||||
{
|
||||
QList<QVariant> argumentList;
|
||||
argumentList << QVariant::fromValue(in0) << QVariant::fromValue(in1);
|
||||
return asyncCallWithArgumentList(QStringLiteral("EnableNotification"), argumentList);
|
||||
}
|
||||
|
||||
inline QDBusPendingReply<QString> GetName(uint in0)
|
||||
{
|
||||
QList<QVariant> argumentList;
|
||||
argumentList << QVariant::fromValue(in0);
|
||||
return asyncCallWithArgumentList(QStringLiteral("GetName"), argumentList);
|
||||
}
|
||||
|
||||
inline QDBusPendingReply<bool> Manage()
|
||||
{
|
||||
QList<QVariant> argumentList;
|
||||
return asyncCallWithArgumentList(QStringLiteral("Manage"), argumentList);
|
||||
}
|
||||
|
||||
inline QDBusPendingReply<> RetryManager()
|
||||
{
|
||||
QList<QVariant> argumentList;
|
||||
return asyncCallWithArgumentList(QStringLiteral("RetryManager"), argumentList);
|
||||
}
|
||||
|
||||
inline QDBusPendingReply<bool> Unmanage()
|
||||
{
|
||||
QList<QVariant> argumentList;
|
||||
return asyncCallWithArgumentList(QStringLiteral("Unmanage"), argumentList);
|
||||
}
|
||||
|
||||
Q_SIGNALS: // SIGNALS
|
||||
void Added(uint in0);
|
||||
void Changed(uint in0);
|
||||
void Inited();
|
||||
void Removed(uint in0);
|
||||
// begin property changed signals
|
||||
void TrayIconsChanged();
|
||||
};
|
||||
|
||||
namespace com {
|
||||
namespace deepin {
|
||||
namespace dde {
|
||||
typedef ::DBusTrayManager TrayManager;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
@ -1,31 +0,0 @@
|
||||
<interface name="org.deepin.dde.TrayManager1">
|
||||
<method name="EnableNotification">
|
||||
<arg type="u" direction="in"></arg>
|
||||
<arg type="b" direction="in"></arg>
|
||||
</method>
|
||||
<method name="GetName">
|
||||
<arg type="u" direction="in"></arg>
|
||||
<arg type="s" direction="out"></arg>
|
||||
</method>
|
||||
<method name="Manage">
|
||||
<arg type="b" direction="out"></arg>
|
||||
</method>
|
||||
<method name="RetryManager"></method>
|
||||
<method name="Unmanage">
|
||||
<arg type="b" direction="out"></arg>
|
||||
</method>
|
||||
<signal name="Removed">
|
||||
<arg type="u"></arg>
|
||||
</signal>
|
||||
<signal name="Added">
|
||||
<arg type="u"></arg>
|
||||
</signal>
|
||||
<signal name="Changed">
|
||||
<arg type="u"></arg>
|
||||
</signal>
|
||||
<signal name="Inited"></signal>
|
||||
<property name="TrayIcons" type="au" access="read">
|
||||
<annotation name="org.qtproject.QtDBus.QtTypeName" value="TrayList"/>
|
||||
</property>
|
||||
</interface>
|
||||
|
@ -1,43 +0,0 @@
|
||||
// Copyright (C) 2011 ~ 2017 Deepin Technology Co., Ltd.
|
||||
// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#include "dbusimagelist.h"
|
||||
|
||||
QDBusArgument &operator<<(QDBusArgument &argument, const DBusImage &image)
|
||||
{
|
||||
argument.beginStructure();
|
||||
argument << image.width << image.height << image.pixels;
|
||||
argument.endStructure();
|
||||
return argument;
|
||||
}
|
||||
|
||||
const QDBusArgument &operator>>(const QDBusArgument &argument, DBusImage &image)
|
||||
{
|
||||
argument.beginStructure();
|
||||
argument >> image.width >> image.height >> image.pixels;
|
||||
argument.endStructure();
|
||||
return argument;
|
||||
}
|
||||
|
||||
void registerDBusImageListMetaType()
|
||||
{
|
||||
qRegisterMetaType<DBusImage>("DBusImage");
|
||||
qDBusRegisterMetaType<DBusImage>();
|
||||
|
||||
qRegisterMetaType<DBusImageList>("DBusImageList");
|
||||
qDBusRegisterMetaType<DBusImageList>();
|
||||
}
|
||||
|
||||
bool operator ==(const DBusImage &a, const DBusImage &b)
|
||||
{
|
||||
return a.width == b.width
|
||||
&& a.height == b.height
|
||||
&& a.pixels == b.pixels;
|
||||
}
|
||||
|
||||
bool operator !=(const DBusImage &a, const DBusImage &b)
|
||||
{
|
||||
return !(a == b);
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
// Copyright (C) 2011 ~ 2017 Deepin Technology Co., Ltd.
|
||||
// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#ifndef DBUSIMAGELIST_H
|
||||
#define DBUSIMAGELIST_H
|
||||
|
||||
#include <QDBusMetaType>
|
||||
#include <QRect>
|
||||
#include <QList>
|
||||
|
||||
struct DBusImage
|
||||
{
|
||||
int width;
|
||||
int height;
|
||||
QByteArray pixels;
|
||||
};
|
||||
Q_DECLARE_METATYPE(DBusImage)
|
||||
|
||||
typedef QList<DBusImage> DBusImageList;
|
||||
Q_DECLARE_METATYPE(DBusImageList)
|
||||
|
||||
QDBusArgument &operator<<(QDBusArgument&, const DBusImage&);
|
||||
const QDBusArgument &operator>>(const QDBusArgument&, DBusImage&);
|
||||
|
||||
bool operator ==(const DBusImage&, const DBusImage&);
|
||||
bool operator !=(const DBusImage&, const DBusImage&);
|
||||
|
||||
void registerDBusImageListMetaType();
|
||||
|
||||
#endif // DBUSIMAGELIST_H
|
@ -1,41 +0,0 @@
|
||||
// Copyright (C) 2011 ~ 2017 Deepin Technology Co., Ltd.
|
||||
// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#include "dbustooltip.h"
|
||||
|
||||
QDBusArgument &operator<<(QDBusArgument &argument, const DBusToolTip &tip)
|
||||
{
|
||||
argument.beginStructure();
|
||||
argument << tip.iconName << tip.iconPixmap << tip.title << tip.description;
|
||||
argument.endStructure();
|
||||
return argument;
|
||||
}
|
||||
|
||||
const QDBusArgument &operator>>(const QDBusArgument &argument, DBusToolTip &tip)
|
||||
{
|
||||
argument.beginStructure();
|
||||
argument >> tip.iconName >> tip.iconPixmap >> tip.title >> tip.description;
|
||||
argument.endStructure();
|
||||
return argument;
|
||||
}
|
||||
|
||||
bool operator ==(const DBusToolTip &a, const DBusToolTip &b)
|
||||
{
|
||||
return a.iconName == b.iconName
|
||||
&& a.iconPixmap == b.iconPixmap
|
||||
&& a.title == b.title
|
||||
&& a.description == b.description;
|
||||
}
|
||||
|
||||
bool operator !=(const DBusToolTip &a, const DBusToolTip &b)
|
||||
{
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
void registerDBusToolTipMetaType()
|
||||
{
|
||||
qRegisterMetaType<DBusToolTip>("DBusToolTip");
|
||||
qDBusRegisterMetaType<DBusToolTip>();
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
// Copyright (C) 2011 ~ 2017 Deepin Technology Co., Ltd.
|
||||
// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#ifndef DBUSTOOLTIP_H
|
||||
#define DBUSTOOLTIP_H
|
||||
|
||||
#include "dbusimagelist.h"
|
||||
|
||||
#include <QDBusMetaType>
|
||||
#include <QRect>
|
||||
#include <QList>
|
||||
|
||||
struct DBusToolTip
|
||||
{
|
||||
QString iconName;
|
||||
DBusImageList iconPixmap;
|
||||
QString title;
|
||||
QString description;
|
||||
};
|
||||
Q_DECLARE_METATYPE(DBusToolTip)
|
||||
|
||||
QDBusArgument &operator<<(QDBusArgument&, const DBusToolTip&);
|
||||
const QDBusArgument &operator>>(const QDBusArgument&, DBusToolTip&);
|
||||
|
||||
bool operator ==(const DBusToolTip&, const DBusToolTip&);
|
||||
bool operator !=(const DBusToolTip&, const DBusToolTip&);
|
||||
|
||||
void registerDBusToolTipMetaType();
|
||||
|
||||
#endif // DBUSTOOLTIP_H
|
@ -1,54 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#include "dockrect.h"
|
||||
#include <QDebug>
|
||||
|
||||
DockRect::DockRect()
|
||||
: x(0)
|
||||
, y(0)
|
||||
, w(0)
|
||||
, h(0)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
QDebug operator<<(QDebug debug, const DockRect &rect)
|
||||
{
|
||||
debug << QString("DockRect(%1, %2, %3, %4)").arg(rect.x)
|
||||
.arg(rect.y)
|
||||
.arg(rect.w)
|
||||
.arg(rect.h);
|
||||
|
||||
return debug;
|
||||
}
|
||||
|
||||
DockRect::operator QRect() const
|
||||
{
|
||||
return QRect(x, y, w, h);
|
||||
}
|
||||
|
||||
QDBusArgument &operator<<(QDBusArgument &arg, const DockRect &rect)
|
||||
{
|
||||
arg.beginStructure();
|
||||
arg << rect.x << rect.y << rect.w << rect.h;
|
||||
arg.endStructure();
|
||||
|
||||
return arg;
|
||||
}
|
||||
|
||||
const QDBusArgument &operator>>(const QDBusArgument &arg, DockRect &rect)
|
||||
{
|
||||
arg.beginStructure();
|
||||
arg >> rect.x >> rect.y >> rect.w >> rect.h;
|
||||
arg.endStructure();
|
||||
|
||||
return arg;
|
||||
}
|
||||
|
||||
void registerDockRectMetaType()
|
||||
{
|
||||
qRegisterMetaType<DockRect>("DockRect");
|
||||
qDBusRegisterMetaType<DockRect>();
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#ifndef DOCKRECT_H
|
||||
#define DOCKRECT_H
|
||||
|
||||
#include <QRect>
|
||||
#include <QDBusMetaType>
|
||||
|
||||
struct DockRect
|
||||
{
|
||||
public:
|
||||
DockRect();
|
||||
operator QRect() const;
|
||||
|
||||
friend QDebug operator<<(QDebug debug, const DockRect &rect);
|
||||
friend const QDBusArgument &operator>>(const QDBusArgument &arg, DockRect &rect);
|
||||
friend QDBusArgument &operator<<(QDBusArgument &arg, const DockRect &rect);
|
||||
|
||||
private:
|
||||
int x;
|
||||
int y;
|
||||
uint w;
|
||||
uint h;
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE(DockRect)
|
||||
|
||||
void registerDockRectMetaType();
|
||||
|
||||
#endif // DOCKRECT_H
|
@ -1,27 +0,0 @@
|
||||
<interface name="org.deepin.dde.Gesture1">
|
||||
<signal name="TouchSinglePressTimeout">
|
||||
<arg name="time" type="i"></arg>
|
||||
<arg name="scalex" type="d"></arg>
|
||||
<arg name="scaley" type="d"></arg>
|
||||
</signal>
|
||||
<signal name="TouchUpOrCancel">
|
||||
<arg name="scalex" type="d"></arg>
|
||||
<arg name="scaley" type="d"></arg>
|
||||
</signal>
|
||||
<signal name="TouchMoving">
|
||||
<arg name="scalex" type="d"></arg>
|
||||
<arg name="scaley" type="d"></arg>
|
||||
</signal>
|
||||
<signal name="TouchPressTimeout">
|
||||
<arg name="fingers" type="i"></arg>
|
||||
<arg name="time" type="i"></arg>
|
||||
<arg name="scalex" type="d"></arg>
|
||||
<arg name="scaley" type="d"></arg>
|
||||
</signal>
|
||||
<signal name="TouchEdgeEvent">
|
||||
<arg name="direction" type="s"></arg>
|
||||
<arg name="scalex" type="d"></arg>
|
||||
<arg name="scaley" type="d"></arg>
|
||||
</signal>
|
||||
</interface>
|
||||
|
@ -1,100 +0,0 @@
|
||||
<interface name="org.deepin.dde.daemon.Dock1">
|
||||
<method name="ActivateWindow">
|
||||
<arg type="u" direction="in"/>
|
||||
</method>
|
||||
<method name="CancelPreviewWindow"/>
|
||||
<method name="CloseWindow">
|
||||
<arg type="u" direction="in"/>
|
||||
</method>
|
||||
<method name="GetDockedAppsDesktopFiles">
|
||||
<arg type="as" direction="out"/>
|
||||
</method>
|
||||
<method name="GetEntryIDs">
|
||||
<arg type="as" direction="out"/>
|
||||
</method>
|
||||
<method name="GetPluginSettings">
|
||||
<arg type="s" direction="out"/>
|
||||
</method>
|
||||
<method name="IsDocked">
|
||||
<arg type="s" direction="in"/>
|
||||
<arg type="b" direction="out"/>
|
||||
</method>
|
||||
<method name="IsOnDock">
|
||||
<arg type="s" direction="in"/>
|
||||
<arg type="b" direction="out"/>
|
||||
</method>
|
||||
<method name="MakeWindowAbove">
|
||||
<arg type="u" direction="in"/>
|
||||
</method>
|
||||
<method name="MaximizeWindow">
|
||||
<arg type="u" direction="in"/>
|
||||
</method>
|
||||
<method name="MinimizeWindow">
|
||||
<arg type="u" direction="in"/>
|
||||
</method>
|
||||
<method name="MoveEntry">
|
||||
<arg type="i" direction="in"/>
|
||||
<arg type="i" direction="in"/>
|
||||
</method>
|
||||
<method name="MoveWindow">
|
||||
<arg type="u" direction="in"/>
|
||||
</method>
|
||||
<method name="PreviewWindow">
|
||||
<arg type="u" direction="in"/>
|
||||
</method>
|
||||
<method name="QueryWindowIdentifyMethod">
|
||||
<arg type="u" direction="in"/>
|
||||
<arg type="s" direction="out"/>
|
||||
</method>
|
||||
<method name="RemovePluginSettings">
|
||||
<arg type="s" direction="in"/>
|
||||
<arg type="as" direction="in"/>
|
||||
</method>
|
||||
<method name="RequestDock">
|
||||
<arg type="s" direction="in"/>
|
||||
<arg type="i" direction="in"/>
|
||||
<arg type="b" direction="out"/>
|
||||
</method>
|
||||
<method name="RequestUndock">
|
||||
<arg type="s" direction="in"/>
|
||||
<arg type="b" direction="out"/>
|
||||
</method>
|
||||
<method name="SetFrontendWindowRect">
|
||||
<arg type="i" direction="in"/>
|
||||
<arg type="i" direction="in"/>
|
||||
<arg type="u" direction="in"/>
|
||||
<arg type="u" direction="in"/>
|
||||
</method>
|
||||
<method name="SetPluginSettings">
|
||||
<arg type="s" direction="in"/>
|
||||
</method>
|
||||
<method name="MergePluginSettings">
|
||||
<arg type="s" direction="in"/>
|
||||
</method>
|
||||
<signal name="ServiceRestarted"/>
|
||||
<signal name="EntryAdded">
|
||||
<arg type="o"/>
|
||||
<arg type="i"/>
|
||||
</signal>
|
||||
<signal name="EntryRemoved">
|
||||
<arg type="s"/>
|
||||
</signal>
|
||||
<signal name="PluginSettingsSynced"/>
|
||||
<signal name="DockAppSettingsSynced"/>
|
||||
<property name="Entries" type="ao" access="read"/>
|
||||
<property name="HideMode" type="i" access="readwrite"/>
|
||||
<property name="DisplayMode" type="i" access="readwrite"/>
|
||||
<property name="Position" type="i" access="readwrite"/>
|
||||
<property name="IconSize" type="u" access="readwrite"/>
|
||||
<property name="WindowSize" type="u" access="readwrite"/>
|
||||
<property name="WindowSizeEfficient" type="u" access="readwrite"/>
|
||||
<property name="WindowSizeFashion" type="u" access="readwrite"/>
|
||||
<property name="ShowTimeout" type="u" access="readwrite"/>
|
||||
<property name="HideTimeout" type="u" access="readwrite"/>
|
||||
<property name="DockedApps" type="as" access="read"/>
|
||||
<property name="HideState" type="i" access="read"/>
|
||||
<property name="FrontendWindowRect" type="(iiuu)" access="read">
|
||||
<annotation name="org.qtproject.QtDBus.QtTypeName" value="DockRect"/>
|
||||
</property>
|
||||
<property name="Opacity" type="d" access="readwrite"/>
|
||||
</interface>
|
@ -1,61 +0,0 @@
|
||||
<interface name="org.kde.StatusNotifierItem">
|
||||
<property access="read" type="s" name="Category"/>
|
||||
<property access="read" type="s" name="Id"/>
|
||||
<property access="read" type="s" name="Title"/>
|
||||
<property access="read" type="s" name="Status"/>
|
||||
<property access="read" type="i" name="WindowId"/>
|
||||
<!-- An additional path to add to the theme search path to find the icons specified above. -->
|
||||
<property access="read" type="s" name="IconThemePath"/>
|
||||
<property access="read" type="o" name="Menu"/>
|
||||
<property access="read" type="b" name="ItemIsMenu"/>
|
||||
<!-- main icon -->
|
||||
<!-- names are preferred over pixmaps -->
|
||||
<property access="read" type="s" name="IconName"/>
|
||||
<!--struct containing width, height and image data-->
|
||||
<property access="read" type="a(iiay)" name="IconPixmap">
|
||||
<annotation value="DBusImageList" name="org.qtproject.QtDBus.QtTypeName"/>
|
||||
</property>
|
||||
<property access="read" type="s" name="OverlayIconName"/>
|
||||
<property access="read" type="a(iiay)" name="OverlayIconPixmap">
|
||||
<annotation value="DBusImageList" name="org.qtproject.QtDBus.QtTypeName"/>
|
||||
</property>
|
||||
<!-- Requesting attention icon -->
|
||||
<property access="read" type="s" name="AttentionIconName"/>
|
||||
<!--same definition as image-->
|
||||
<property access="read" type="a(iiay)" name="AttentionIconPixmap">
|
||||
<annotation value="DBusImageList" name="org.qtproject.QtDBus.QtTypeName"/>
|
||||
</property>
|
||||
<property access="read" type="s" name="AttentionMovieName"/>
|
||||
<!-- tooltip data -->
|
||||
<!--(iiay) is an image-->
|
||||
<property access="read" type="(sa(iiay)ss)" name="ToolTip">
|
||||
<annotation value="DBusToolTip" name="org.qtproject.QtDBus.QtTypeName"/>
|
||||
</property>
|
||||
<!-- interaction: the systemtray wants the application to do something -->
|
||||
<method name="ContextMenu">
|
||||
<!-- we're passing the coordinates of the icon, so the app knows where to put the popup window -->
|
||||
<arg direction="in" type="i" name="x"/>
|
||||
<arg direction="in" type="i" name="y"/>
|
||||
</method>
|
||||
<method name="Activate">
|
||||
<arg direction="in" type="i" name="x"/>
|
||||
<arg direction="in" type="i" name="y"/>
|
||||
</method>
|
||||
<method name="SecondaryActivate">
|
||||
<arg direction="in" type="i" name="x"/>
|
||||
<arg direction="in" type="i" name="y"/>
|
||||
</method>
|
||||
<method name="Scroll">
|
||||
<arg direction="in" type="i" name="delta"/>
|
||||
<arg direction="in" type="s" name="orientation"/>
|
||||
</method>
|
||||
<!-- Signals: the client wants to change something in the status-->
|
||||
<signal name="NewTitle"/>
|
||||
<signal name="NewIcon"/>
|
||||
<signal name="NewAttentionIcon"/>
|
||||
<signal name="NewOverlayIcon"/>
|
||||
<signal name="NewToolTip"/>
|
||||
<signal name="NewStatus">
|
||||
<arg type="s" name="status"/>
|
||||
</signal>
|
||||
</interface>
|
@ -1,406 +0,0 @@
|
||||
// Copyright (C) 2011 ~ 2018 Deepin Technology Co., Ltd.
|
||||
// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#include "abstractcontainer.h"
|
||||
#include "../fashiontrayconstants.h"
|
||||
|
||||
AbstractContainer::AbstractContainer(TrayPlugin *trayPlugin, QWidget *parent)
|
||||
: QWidget(parent)
|
||||
, m_trayPlugin(trayPlugin)
|
||||
, m_wrapperLayout(new QBoxLayout(QBoxLayout::LeftToRight, this))
|
||||
, m_currentDraggingWrapper(nullptr)
|
||||
, m_expand(true)
|
||||
, m_dockPosition(Dock::Position::Bottom)
|
||||
{
|
||||
setAcceptDrops(true);
|
||||
|
||||
m_wrapperLayout->setMargin(0);
|
||||
m_wrapperLayout->setContentsMargins(0, 0, 0, 0);
|
||||
m_wrapperLayout->setSpacing(TraySpace);
|
||||
|
||||
setLayout(m_wrapperLayout);
|
||||
|
||||
setMinimumWidth(TraySpace);
|
||||
setMinimumHeight(TraySpace);
|
||||
}
|
||||
|
||||
void AbstractContainer::refreshVisible()
|
||||
{
|
||||
if (!m_wrapperList.isEmpty()) {
|
||||
//非空保留两边边距
|
||||
if (m_dockPosition == Dock::Position::Top || m_dockPosition == Dock::Position::Bottom) {
|
||||
m_wrapperLayout->setContentsMargins(TraySpace, 0, TraySpace, 0);
|
||||
} else {
|
||||
m_wrapperLayout->setContentsMargins(0, TraySpace, 0, TraySpace);
|
||||
}
|
||||
} else {
|
||||
// 空,保留最小size,可以拖入
|
||||
m_wrapperLayout->setContentsMargins(0, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void AbstractContainer::addWrapper(FashionTrayWidgetWrapper *wrapper)
|
||||
{
|
||||
if (containsWrapper(wrapper)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const int index = whereToInsert(wrapper);
|
||||
m_wrapperLayout->insertWidget(index, wrapper);
|
||||
m_wrapperList.insert(index, wrapper);
|
||||
|
||||
wrapper->setAttention(false);
|
||||
|
||||
connect(wrapper, &FashionTrayWidgetWrapper::attentionChanged, this, &AbstractContainer::onWrapperAttentionhChanged, static_cast<Qt::ConnectionType>(Qt::QueuedConnection | Qt::UniqueConnection));
|
||||
connect(wrapper, &FashionTrayWidgetWrapper::dragStart, this, &AbstractContainer::onWrapperDragStart, Qt::UniqueConnection);
|
||||
connect(wrapper, &FashionTrayWidgetWrapper::dragStop, this, &AbstractContainer::onWrapperDragStop, Qt::UniqueConnection);
|
||||
connect(wrapper, &FashionTrayWidgetWrapper::requestSwapWithDragging, this, &AbstractContainer::onWrapperRequestSwapWithDragging, Qt::UniqueConnection);
|
||||
|
||||
refreshVisible();
|
||||
}
|
||||
|
||||
bool AbstractContainer::removeWrapper(FashionTrayWidgetWrapper *wrapper)
|
||||
{
|
||||
FashionTrayWidgetWrapper *w = takeWrapper(wrapper);
|
||||
if (!w) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// do not delete real tray object, just delete it's wrapper object
|
||||
// the real tray object should be deleted in TrayPlugin class
|
||||
if (!w->absTrayWidget().isNull())
|
||||
w->absTrayWidget()->setParent(nullptr);
|
||||
|
||||
if (w->isDragging()) {
|
||||
w->cancelDragging();
|
||||
}
|
||||
w->deleteLater();
|
||||
|
||||
refreshVisible();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AbstractContainer::removeWrapperByTrayWidget(AbstractTrayWidget *trayWidget)
|
||||
{
|
||||
FashionTrayWidgetWrapper *w = wrapperByTrayWidget(trayWidget);
|
||||
if (!w) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return removeWrapper(w);
|
||||
}
|
||||
|
||||
FashionTrayWidgetWrapper *AbstractContainer::takeWrapper(FashionTrayWidgetWrapper *wrapper)
|
||||
{
|
||||
if (!containsWrapper(wrapper)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (m_currentDraggingWrapper == wrapper) {
|
||||
m_currentDraggingWrapper = nullptr;
|
||||
}
|
||||
|
||||
wrapper->disconnect();
|
||||
m_wrapperLayout->removeWidget(wrapper);
|
||||
m_wrapperList.removeAll(wrapper);
|
||||
|
||||
refreshVisible();
|
||||
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
void AbstractContainer::setDockPosition(const Dock::Position pos)
|
||||
{
|
||||
m_dockPosition = pos;
|
||||
|
||||
if (pos == Dock::Position::Top || pos == Dock::Position::Bottom) {
|
||||
m_wrapperLayout->setDirection(QBoxLayout::Direction::LeftToRight);
|
||||
} else {
|
||||
m_wrapperLayout->setDirection(QBoxLayout::Direction::TopToBottom);
|
||||
}
|
||||
|
||||
refreshVisible();
|
||||
}
|
||||
|
||||
void AbstractContainer::setExpand(const bool expand)
|
||||
{
|
||||
m_expand = expand;
|
||||
|
||||
refreshVisible();
|
||||
}
|
||||
|
||||
//QSize AbstractContainer::sizeHint() const
|
||||
//{
|
||||
// return totalSize();
|
||||
//}
|
||||
|
||||
void AbstractContainer::setItemSize(int itemSize)
|
||||
{
|
||||
m_itemSize = itemSize;
|
||||
|
||||
for (auto w : wrapperList()) {
|
||||
if (dockPosition() == Dock::Top || dockPosition() == Dock::Bottom)
|
||||
w->setFixedSize(m_itemSize, QWIDGETSIZE_MAX);
|
||||
else
|
||||
w->setFixedSize(QWIDGETSIZE_MAX, m_itemSize);
|
||||
}
|
||||
}
|
||||
|
||||
QSize AbstractContainer::totalSize() const
|
||||
{
|
||||
QSize size;
|
||||
|
||||
if (m_dockPosition == Dock::Position::Top || m_dockPosition == Dock::Position::Bottom) {
|
||||
|
||||
int itemSize = qBound(PLUGIN_BACKGROUND_MIN_SIZE, parentWidget()->height(), PLUGIN_BACKGROUND_MAX_SIZE);
|
||||
if (itemSize > m_itemSize)
|
||||
itemSize = m_itemSize;
|
||||
|
||||
size.setWidth(
|
||||
(expand() ? (m_wrapperList.size() * itemSize // 所有托盘图标
|
||||
+ m_wrapperList.size() * TraySpace) : 0 // 所有托盘图标之间 + 一个尾部的 space
|
||||
) + TraySpace
|
||||
);
|
||||
size.setHeight(height());
|
||||
} else {
|
||||
int itemSize = qBound(PLUGIN_BACKGROUND_MIN_SIZE, parentWidget()->width(), PLUGIN_BACKGROUND_MAX_SIZE);
|
||||
if (itemSize > m_itemSize)
|
||||
itemSize = m_itemSize;
|
||||
|
||||
size.setWidth(width());
|
||||
size.setHeight(
|
||||
(expand() ? (m_wrapperList.size() * itemSize // 所有托盘图标
|
||||
+ m_wrapperList.size() * TraySpace) : 0 // 所有托盘图标之间 + 一个尾部的 space
|
||||
) + TraySpace
|
||||
);
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
void AbstractContainer::clearWrapper()
|
||||
{
|
||||
QList<QPointer<FashionTrayWidgetWrapper>> mList = m_wrapperList;
|
||||
|
||||
for (auto wrapper : mList) {
|
||||
removeWrapper(wrapper);
|
||||
}
|
||||
|
||||
m_wrapperList.clear();
|
||||
|
||||
refreshVisible();
|
||||
}
|
||||
|
||||
void AbstractContainer::saveCurrentOrderToConfig()
|
||||
{
|
||||
for (int i = 0; i < m_wrapperList.size(); ++i) {
|
||||
m_trayPlugin->setSortKey(m_wrapperList.at(i)->itemKey(), i + 1);
|
||||
}
|
||||
}
|
||||
|
||||
bool AbstractContainer::isEmpty()
|
||||
{
|
||||
return m_wrapperList.isEmpty();
|
||||
}
|
||||
|
||||
int AbstractContainer::itemCount()
|
||||
{
|
||||
return m_wrapperList.count();
|
||||
}
|
||||
|
||||
bool AbstractContainer::containsWrapper(FashionTrayWidgetWrapper *wrapper)
|
||||
{
|
||||
return m_wrapperList.contains(wrapper);
|
||||
}
|
||||
|
||||
bool AbstractContainer::containsWrapperByTrayWidget(AbstractTrayWidget *trayWidget)
|
||||
{
|
||||
return wrapperByTrayWidget(trayWidget);
|
||||
}
|
||||
|
||||
FashionTrayWidgetWrapper *AbstractContainer::wrapperByTrayWidget(AbstractTrayWidget *trayWidget)
|
||||
{
|
||||
for (auto w : m_wrapperList) {
|
||||
if (w->absTrayWidget() == trayWidget) {
|
||||
return w;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void AbstractContainer::addDraggingWrapper(FashionTrayWidgetWrapper *wrapper)
|
||||
{
|
||||
addWrapper(wrapper);
|
||||
|
||||
if (containsWrapper(wrapper)) {
|
||||
m_currentDraggingWrapper = wrapper;
|
||||
}
|
||||
}
|
||||
|
||||
FashionTrayWidgetWrapper *AbstractContainer::takeDraggingWrapper()
|
||||
{
|
||||
if (!m_currentDraggingWrapper) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return takeWrapper(m_currentDraggingWrapper);
|
||||
}
|
||||
|
||||
int AbstractContainer::whereToInsert(FashionTrayWidgetWrapper *wrapper)
|
||||
{
|
||||
if (m_wrapperList.isEmpty()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
//根据配置文件记录的顺序排序
|
||||
int destSortKey = m_trayPlugin->itemSortKey(wrapper->itemKey());
|
||||
|
||||
if (destSortKey < -1) {
|
||||
return 0;
|
||||
}
|
||||
if (destSortKey == -1) {
|
||||
return m_wrapperList.size();
|
||||
}
|
||||
|
||||
// 当目标插入位置为列表的大小时将从最后面追加到列表中
|
||||
int destIndex = m_wrapperList.size();
|
||||
for (int i = 0; i < m_wrapperList.size(); ++i) {
|
||||
if (destSortKey > m_trayPlugin->itemSortKey(m_wrapperList.at(i)->itemKey())) {
|
||||
continue;
|
||||
}
|
||||
destIndex = i;
|
||||
break;
|
||||
}
|
||||
|
||||
return destIndex;
|
||||
}
|
||||
|
||||
TrayPlugin *AbstractContainer::trayPlugin() const
|
||||
{
|
||||
return m_trayPlugin;
|
||||
}
|
||||
|
||||
QList<QPointer<FashionTrayWidgetWrapper> > AbstractContainer::wrapperList() const
|
||||
{
|
||||
return m_wrapperList;
|
||||
}
|
||||
|
||||
QBoxLayout *AbstractContainer::wrapperLayout() const
|
||||
{
|
||||
return m_wrapperLayout;
|
||||
}
|
||||
|
||||
// replace current WrapperLayout by "layout"
|
||||
// but will not setLayout here, so the caller should handle the new WrapperLayout
|
||||
void AbstractContainer::setWrapperLayout(QBoxLayout *layout)
|
||||
{
|
||||
delete m_wrapperLayout;
|
||||
m_wrapperLayout = layout;
|
||||
}
|
||||
|
||||
bool AbstractContainer::expand() const
|
||||
{
|
||||
return m_expand;
|
||||
}
|
||||
|
||||
Dock::Position AbstractContainer::dockPosition() const
|
||||
{
|
||||
return m_dockPosition;
|
||||
}
|
||||
|
||||
//QSize AbstractContainer::wrapperSize() const
|
||||
//{
|
||||
// return m_wrapperSize;
|
||||
//}
|
||||
|
||||
void AbstractContainer::dragEnterEvent(QDragEnterEvent *event)
|
||||
{
|
||||
if (event->mimeData()->hasFormat(TRAY_ITEM_DRAG_MIMEDATA) && !m_currentDraggingWrapper) {
|
||||
event->accept();
|
||||
Q_EMIT requestDraggingWrapper();
|
||||
return;
|
||||
}
|
||||
|
||||
QWidget::dragEnterEvent(event);
|
||||
}
|
||||
|
||||
void AbstractContainer::paintEvent(QPaintEvent *event)
|
||||
{
|
||||
QWidget::paintEvent(event);
|
||||
|
||||
QPainter p(this);
|
||||
}
|
||||
|
||||
void AbstractContainer::onWrapperAttentionhChanged(const bool attention)
|
||||
{
|
||||
FashionTrayWidgetWrapper *wrapper = dynamic_cast<FashionTrayWidgetWrapper *>(sender());
|
||||
if (!wrapper) {
|
||||
return;
|
||||
}
|
||||
|
||||
Q_EMIT attentionChanged(wrapper, attention);
|
||||
}
|
||||
|
||||
void AbstractContainer::onWrapperDragStart()
|
||||
{
|
||||
FashionTrayWidgetWrapper *wrapper = static_cast<FashionTrayWidgetWrapper *>(sender());
|
||||
|
||||
if (!wrapper) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_currentDraggingWrapper = wrapper;
|
||||
|
||||
Q_EMIT draggingStateChanged(wrapper, true);
|
||||
}
|
||||
|
||||
void AbstractContainer::onWrapperDragStop()
|
||||
{
|
||||
FashionTrayWidgetWrapper *wrapper = static_cast<FashionTrayWidgetWrapper *>(sender());
|
||||
|
||||
if (!wrapper) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_currentDraggingWrapper == wrapper) {
|
||||
m_currentDraggingWrapper = nullptr;
|
||||
} else {
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
|
||||
saveCurrentOrderToConfig();
|
||||
|
||||
Q_EMIT draggingStateChanged(wrapper, false);
|
||||
}
|
||||
|
||||
void AbstractContainer::onWrapperRequestSwapWithDragging()
|
||||
{
|
||||
FashionTrayWidgetWrapper *wrapper = static_cast<FashionTrayWidgetWrapper *>(sender());
|
||||
|
||||
if (!wrapper || wrapper == m_currentDraggingWrapper) {
|
||||
return;
|
||||
}
|
||||
|
||||
// the current dragging wrapper is null means that the dragging wrapper is contains by
|
||||
// another container, so this container need to emit requireDraggingWrapper() signal
|
||||
// to notify FashionTrayItem, the FashionTrayItem will move the dragging wrapper to this container
|
||||
if (!m_currentDraggingWrapper) {
|
||||
Q_EMIT requestDraggingWrapper();
|
||||
// here have to give up if dragging wrapper is still null
|
||||
if (!m_currentDraggingWrapper) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const int indexOfDest = m_wrapperLayout->indexOf(wrapper);
|
||||
const int indexOfDragging = m_wrapperLayout->indexOf(m_currentDraggingWrapper);
|
||||
|
||||
m_wrapperLayout->removeWidget(m_currentDraggingWrapper);
|
||||
m_wrapperLayout->insertWidget(indexOfDest, m_currentDraggingWrapper);
|
||||
|
||||
m_wrapperList.insert(indexOfDest, m_wrapperList.takeAt(indexOfDragging));
|
||||
}
|
@ -1,84 +0,0 @@
|
||||
// Copyright (C) 2011 ~ 2018 Deepin Technology Co., Ltd.
|
||||
// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#ifndef ABSTRACTCONTAINER_H
|
||||
#define ABSTRACTCONTAINER_H
|
||||
|
||||
#include "constants.h"
|
||||
#include "../../trayplugin.h"
|
||||
#include "../fashiontraywidgetwrapper.h"
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
class AbstractContainer : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit AbstractContainer(TrayPlugin *trayPlugin, QWidget *parent = nullptr);
|
||||
|
||||
virtual bool acceptWrapper(FashionTrayWidgetWrapper *wrapper) = 0;
|
||||
virtual void refreshVisible();
|
||||
|
||||
virtual void addWrapper(FashionTrayWidgetWrapper *wrapper);
|
||||
virtual bool removeWrapper(FashionTrayWidgetWrapper *wrapper);
|
||||
virtual bool removeWrapperByTrayWidget(AbstractTrayWidget *trayWidget);
|
||||
virtual FashionTrayWidgetWrapper *takeWrapper(FashionTrayWidgetWrapper *wrapper);
|
||||
virtual void setDockPosition(const Dock::Position pos);
|
||||
virtual void setExpand(const bool expand);
|
||||
virtual QSize totalSize() const;
|
||||
virtual int itemCount();
|
||||
|
||||
int itemSize() {return m_itemSize;}
|
||||
void setItemSize(int itemSize);
|
||||
void clearWrapper();
|
||||
void saveCurrentOrderToConfig();
|
||||
bool isEmpty();
|
||||
bool containsWrapper(FashionTrayWidgetWrapper *wrapper);
|
||||
bool containsWrapperByTrayWidget(AbstractTrayWidget *trayWidget);
|
||||
FashionTrayWidgetWrapper *wrapperByTrayWidget(AbstractTrayWidget *trayWidget);
|
||||
|
||||
void addDraggingWrapper(FashionTrayWidgetWrapper *wrapper);
|
||||
FashionTrayWidgetWrapper *takeDraggingWrapper();
|
||||
|
||||
Q_SIGNALS:
|
||||
void attentionChanged(FashionTrayWidgetWrapper *wrapper, const bool attention);
|
||||
void requestDraggingWrapper();
|
||||
void draggingStateChanged(FashionTrayWidgetWrapper *wrapper, const bool dragging);
|
||||
|
||||
protected:
|
||||
virtual int whereToInsert(FashionTrayWidgetWrapper *wrapper);
|
||||
|
||||
TrayPlugin *trayPlugin() const;
|
||||
QList<QPointer<FashionTrayWidgetWrapper>> wrapperList() const;
|
||||
QBoxLayout *wrapperLayout() const;
|
||||
void setWrapperLayout(QBoxLayout *layout);
|
||||
bool expand() const;
|
||||
Dock::Position dockPosition() const;
|
||||
|
||||
protected:
|
||||
void dragEnterEvent(QDragEnterEvent *event) override;
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
|
||||
private Q_SLOTS:
|
||||
void onWrapperAttentionhChanged(const bool attention);
|
||||
void onWrapperDragStart();
|
||||
void onWrapperDragStop();
|
||||
void onWrapperRequestSwapWithDragging();
|
||||
|
||||
private:
|
||||
TrayPlugin *m_trayPlugin;
|
||||
QBoxLayout *m_wrapperLayout;
|
||||
|
||||
QPointer<FashionTrayWidgetWrapper> m_currentDraggingWrapper;
|
||||
QList<QPointer<FashionTrayWidgetWrapper>> m_wrapperList;
|
||||
|
||||
bool m_expand;
|
||||
Dock::Position m_dockPosition;
|
||||
|
||||
// QSize m_wrapperSize;
|
||||
int m_itemSize = 40;
|
||||
};
|
||||
|
||||
#endif // ABSTRACTCONTAINER_H
|
@ -1,44 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#include "attentioncontainer.h"
|
||||
|
||||
AttentionContainer::AttentionContainer(TrayPlugin *trayPlugin, QWidget *parent)
|
||||
: AbstractContainer(trayPlugin, parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
FashionTrayWidgetWrapper *AttentionContainer::takeAttentionWrapper()
|
||||
{
|
||||
if (isEmpty()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return takeWrapper(wrapperList().first());
|
||||
}
|
||||
|
||||
bool AttentionContainer::acceptWrapper(FashionTrayWidgetWrapper *wrapper)
|
||||
{
|
||||
Q_UNUSED(wrapper);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void AttentionContainer::refreshVisible()
|
||||
{
|
||||
// AbstractContainer::refreshVisible();
|
||||
setContentsMargins(0, 0, 0 ,0);
|
||||
setVisible(!isEmpty());
|
||||
}
|
||||
|
||||
void AttentionContainer::addWrapper(FashionTrayWidgetWrapper *wrapper)
|
||||
{
|
||||
if (!isEmpty()) {
|
||||
qDebug() << "Reject! Already contains a attention wrapper!";
|
||||
return;
|
||||
}
|
||||
|
||||
AbstractContainer::addWrapper(wrapper);
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#ifndef ATTENTIONCONTAINER_H
|
||||
#define ATTENTIONCONTAINER_H
|
||||
|
||||
#include "abstractcontainer.h"
|
||||
|
||||
class AttentionContainer : public AbstractContainer
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit AttentionContainer(TrayPlugin *trayPlugin, QWidget *parent = nullptr);
|
||||
|
||||
FashionTrayWidgetWrapper *takeAttentionWrapper();
|
||||
|
||||
// AbstractContainer interface
|
||||
public:
|
||||
bool acceptWrapper(FashionTrayWidgetWrapper *wrapper) override;
|
||||
void refreshVisible() override;
|
||||
void addWrapper(FashionTrayWidgetWrapper *wrapper) override;
|
||||
};
|
||||
|
||||
#endif // ATTENTIONCONTAINER_H
|
@ -1,77 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#include "holdcontainer.h"
|
||||
#include "../fashiontrayconstants.h"
|
||||
|
||||
HoldContainer::HoldContainer(TrayPlugin *trayPlugin, QWidget *parent)
|
||||
: AbstractContainer(trayPlugin, parent)
|
||||
, m_mainBoxLayout(new QBoxLayout(QBoxLayout::Direction::LeftToRight))
|
||||
{
|
||||
m_mainBoxLayout->setMargin(0);
|
||||
m_mainBoxLayout->setContentsMargins(0, 0, 0, 0);
|
||||
m_mainBoxLayout->setSpacing(TraySpace);
|
||||
|
||||
QBoxLayout *preLayout = wrapperLayout();
|
||||
QBoxLayout *newLayout = new QBoxLayout(QBoxLayout::Direction::LeftToRight);
|
||||
for (int i = 0; i < preLayout->count(); ++i) {
|
||||
newLayout->addItem(preLayout->takeAt(i));
|
||||
}
|
||||
setWrapperLayout(newLayout);
|
||||
|
||||
m_mainBoxLayout->addLayout(newLayout);
|
||||
|
||||
// setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
setLayout(m_mainBoxLayout);
|
||||
}
|
||||
|
||||
bool HoldContainer::acceptWrapper(FashionTrayWidgetWrapper *wrapper)
|
||||
{
|
||||
const QString &key = HoldKeyPrefix + wrapper->absTrayWidget()->itemKeyForConfig();
|
||||
|
||||
return trayPlugin()->getValue(wrapper->itemKey(), key, false).toBool();
|
||||
}
|
||||
|
||||
void HoldContainer::addWrapper(FashionTrayWidgetWrapper *wrapper)
|
||||
{
|
||||
AbstractContainer::addWrapper(wrapper);
|
||||
|
||||
if (containsWrapper(wrapper)) {
|
||||
const QString &key = HoldKeyPrefix + wrapper->absTrayWidget()->itemKeyForConfig();
|
||||
trayPlugin()->saveValue(wrapper->itemKey(), key, true);
|
||||
}
|
||||
}
|
||||
|
||||
void HoldContainer::refreshVisible()
|
||||
{
|
||||
AbstractContainer::refreshVisible();
|
||||
|
||||
setVisible(true);
|
||||
}
|
||||
|
||||
void HoldContainer::setDockPosition(const Dock::Position pos)
|
||||
{
|
||||
if (pos == Dock::Position::Top || pos == Dock::Position::Bottom) {
|
||||
m_mainBoxLayout->setDirection(QBoxLayout::Direction::LeftToRight);
|
||||
} else{
|
||||
m_mainBoxLayout->setDirection(QBoxLayout::Direction::TopToBottom);
|
||||
}
|
||||
|
||||
AbstractContainer::setDockPosition(pos);
|
||||
}
|
||||
|
||||
//QSize HoldContainer::totalSize() const
|
||||
//{
|
||||
// QSize size = AbstractContainer::totalSize();
|
||||
|
||||
// if (expand()) {
|
||||
// if (dockPosition() == Dock::Position::Top || dockPosition() == Dock::Position::Bottom) {
|
||||
// size.setHeight(height());
|
||||
// } else {
|
||||
// size.setWidth(width());
|
||||
// }
|
||||
// }
|
||||
|
||||
// return size;
|
||||
//}
|
@ -1,27 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#ifndef HOLDCONTAINER_H
|
||||
#define HOLDCONTAINER_H
|
||||
|
||||
#include "abstractcontainer.h"
|
||||
|
||||
class HoldContainer : public AbstractContainer
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit HoldContainer(TrayPlugin *trayPlugin, QWidget *parent = nullptr);
|
||||
|
||||
public:
|
||||
bool acceptWrapper(FashionTrayWidgetWrapper *wrapper) override;
|
||||
void addWrapper(FashionTrayWidgetWrapper *wrapper) override;
|
||||
void refreshVisible() override;
|
||||
void setDockPosition(const Dock::Position pos) override;
|
||||
// QSize totalSize() const override;
|
||||
|
||||
private:
|
||||
QBoxLayout *m_mainBoxLayout;
|
||||
};
|
||||
|
||||
#endif // HOLDCONTAINER_H
|
@ -1,291 +0,0 @@
|
||||
// Copyright (C) 2011 ~ 2018 Deepin Technology Co., Ltd.
|
||||
// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#include "normalcontainer.h"
|
||||
#include "../fashiontrayconstants.h"
|
||||
|
||||
NormalContainer::NormalContainer(TrayPlugin *trayPlugin, QWidget *parent)
|
||||
: AbstractContainer(trayPlugin, parent)
|
||||
, m_sizeAnimation(new QVariantAnimation(this))
|
||||
{
|
||||
m_sizeAnimation->setEasingCurve(QEasingCurve::InOutCubic);
|
||||
|
||||
connect(m_sizeAnimation, &QVariantAnimation::valueChanged, [ = ](const QVariant & value) {
|
||||
|
||||
if (m_sizeAnimation->state() != QVariantAnimation::Running)
|
||||
return;
|
||||
|
||||
adjustMaxSize(value.toSize());
|
||||
});
|
||||
|
||||
connect(m_sizeAnimation, &QVariantAnimation::finished, [ = ]() {
|
||||
this->setVisible(expand());
|
||||
});
|
||||
|
||||
connect(DWindowManagerHelper::instance(), &DWindowManagerHelper::hasCompositeChanged, this, &NormalContainer::compositeChanged, Qt::QueuedConnection);
|
||||
|
||||
QTimer::singleShot(1, this, &NormalContainer::compositeChanged);
|
||||
}
|
||||
|
||||
void NormalContainer::compositeChanged()
|
||||
{
|
||||
int duration = DWindowManagerHelper::instance()->hasComposite() ? 300 : 1;
|
||||
if (isEmpty())
|
||||
duration = 0;
|
||||
|
||||
m_sizeAnimation->setDuration(duration);
|
||||
}
|
||||
|
||||
QSize NormalContainer::sizeHint() const
|
||||
{
|
||||
return totalSize();
|
||||
}
|
||||
|
||||
void NormalContainer::resizeEvent(QResizeEvent *event)
|
||||
{
|
||||
if (QPropertyAnimation::Stopped == m_sizeAnimation->state()) {
|
||||
if (dockPosition() == Dock::Top || dockPosition() == Dock::Bottom)
|
||||
setMaximumWidth(totalSize().width());
|
||||
else {
|
||||
setMaximumHeight(totalSize().height());
|
||||
}
|
||||
}
|
||||
|
||||
AbstractContainer::resizeEvent(event);
|
||||
}
|
||||
|
||||
bool NormalContainer::acceptWrapper(FashionTrayWidgetWrapper *wrapper)
|
||||
{
|
||||
Q_UNUSED(wrapper);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void NormalContainer::addWrapper(FashionTrayWidgetWrapper *wrapper)
|
||||
{
|
||||
AbstractContainer::addWrapper(wrapper);
|
||||
|
||||
if (containsWrapper(wrapper)) {
|
||||
const QString &key = HoldKeyPrefix + wrapper->absTrayWidget()->itemKeyForConfig();
|
||||
trayPlugin()->saveValue(wrapper->itemKey(), key, false);
|
||||
}
|
||||
}
|
||||
|
||||
void NormalContainer::refreshVisible()
|
||||
{
|
||||
AbstractContainer::refreshVisible();
|
||||
|
||||
for (auto w : wrapperList()) {
|
||||
if (dockPosition() == Dock::Top || dockPosition() == Dock::Bottom)
|
||||
w->setFixedSize(itemSize(), QWIDGETSIZE_MAX);
|
||||
else
|
||||
w->setFixedSize(QWIDGETSIZE_MAX, itemSize());
|
||||
}
|
||||
|
||||
if (isEmpty()) {
|
||||
// set the minimum size to 1 to avoid can not drag back wrappers when
|
||||
// all wrappers has been drag out
|
||||
setMinimumSize(TraySpace, TraySpace);
|
||||
} else {
|
||||
// set the minimum size back to 0 in order to make the fold animation works correctly
|
||||
setMinimumSize(0, 0);
|
||||
}
|
||||
|
||||
compositeChanged();
|
||||
QSize endSize = expand() ? totalSize() : QSize(0, 0);
|
||||
|
||||
const QPropertyAnimation::State state = m_sizeAnimation->state();
|
||||
|
||||
if (state == QPropertyAnimation::Stopped && size() == endSize) {
|
||||
setVisible(expand());
|
||||
return;
|
||||
}
|
||||
|
||||
if (state == QPropertyAnimation::Running)
|
||||
return m_sizeAnimation->setEndValue(endSize);
|
||||
|
||||
m_sizeAnimation->setStartValue(size());
|
||||
m_sizeAnimation->setEndValue(endSize);
|
||||
|
||||
if (isVisible() == expand()) {
|
||||
// 非x86平台,第一次启动setEndValue时,不进QVariantAnimation::valueChanged
|
||||
adjustMaxSize(endSize);
|
||||
return;
|
||||
}
|
||||
|
||||
if (expand()) {
|
||||
setVisible(true);
|
||||
}
|
||||
|
||||
m_sizeAnimation->start();
|
||||
}
|
||||
|
||||
void NormalContainer::adjustMaxSize(const QSize size)
|
||||
{
|
||||
if (dockPosition() == Dock::Top || dockPosition() == Dock::Bottom) {
|
||||
this->setMaximumWidth(size.width());
|
||||
this->setMaximumHeight(DOCK_MAX_SIZE);
|
||||
} else {
|
||||
this->setMaximumWidth(DOCK_MAX_SIZE);
|
||||
this->setMaximumHeight(size.height());
|
||||
}
|
||||
}
|
||||
|
||||
int NormalContainer::itemCount()
|
||||
{
|
||||
if (expand())
|
||||
return AbstractContainer::itemCount();
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
void NormalContainer::setExpand(const bool expand)
|
||||
{
|
||||
// int itemSize;
|
||||
|
||||
// if (dockPosition() == Dock::Position::Top || dockPosition() == Dock::Position::Bottom)
|
||||
// itemSize = std::min(parentWidget()->height(), PLUGIN_BACKGROUND_MAX_SIZE);
|
||||
// else
|
||||
// itemSize = std::min(parentWidget()->width(), PLUGIN_BACKGROUND_MAX_SIZE);
|
||||
|
||||
for (auto w : wrapperList()) {
|
||||
w->setAttention(false);
|
||||
|
||||
// w->setFixedSize(itemSize, itemSize);
|
||||
}
|
||||
|
||||
AbstractContainer::setExpand(expand);
|
||||
}
|
||||
|
||||
int NormalContainer::whereToInsert(FashionTrayWidgetWrapper *wrapper)
|
||||
{
|
||||
// 如果已经对图标进行过排序则完全按照从配置文件中获取的顺序来插入图标(即父类的实现)
|
||||
if (trayPlugin()->traysSortedInFashionMode()) {
|
||||
return AbstractContainer::whereToInsert(wrapper);
|
||||
}
|
||||
|
||||
// 如果没有对图标进行过排序则使用下面的默认排序算法:
|
||||
// 所有应用图标在系统图标的左侧
|
||||
// 新的应用图标在最左侧的应用图标处插入
|
||||
// 系统图标按插件默认顺序(收缩箭头起从右往左由大到小排)在应用图标右侧插入
|
||||
return whereToInsertByDefault(wrapper);
|
||||
}
|
||||
|
||||
int NormalContainer::whereToInsertByDefault(FashionTrayWidgetWrapper *wrapper) const
|
||||
{
|
||||
int index = 0;
|
||||
switch (wrapper->absTrayWidget()->trayTyep()) {
|
||||
case AbstractTrayWidget::TrayType::ApplicationTray:
|
||||
index = whereToInsertAppTrayByDefault(wrapper);
|
||||
break;
|
||||
case AbstractTrayWidget::TrayType::SystemTray:
|
||||
index = whereToInsertSystemTrayByDefault(wrapper);
|
||||
break;
|
||||
default:
|
||||
Q_UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
int NormalContainer::whereToInsertAppTrayByDefault(FashionTrayWidgetWrapper *wrapper) const
|
||||
{
|
||||
if (wrapperList().isEmpty() || wrapper->absTrayWidget()->trayTyep() != AbstractTrayWidget::TrayType::ApplicationTray) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lastAppTrayIndex = -1;
|
||||
for (int i = 0; i < wrapperList().size(); ++i) {
|
||||
if (wrapperList().at(i)->absTrayWidget()->trayTyep() == AbstractTrayWidget::TrayType::ApplicationTray) {
|
||||
lastAppTrayIndex = i;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
// there is no AppTray
|
||||
if (lastAppTrayIndex == -1) {
|
||||
return 0;
|
||||
}
|
||||
// the inserting tray is not a AppTray
|
||||
if (wrapper->absTrayWidget()->trayTyep() != AbstractTrayWidget::TrayType::ApplicationTray) {
|
||||
return lastAppTrayIndex + 1;
|
||||
}
|
||||
|
||||
int insertIndex = trayPlugin()->itemSortKey(wrapper->itemKey());
|
||||
// invalid index
|
||||
if (insertIndex < -1) {
|
||||
return 0;
|
||||
}
|
||||
for (int i = 0; i < wrapperList().size(); ++i) {
|
||||
if (wrapperList().at(i)->absTrayWidget()->trayTyep() != AbstractTrayWidget::TrayType::ApplicationTray) {
|
||||
insertIndex = i;
|
||||
break;
|
||||
}
|
||||
if (insertIndex > trayPlugin()->itemSortKey(wrapperList().at(i)->itemKey())) {
|
||||
continue;
|
||||
}
|
||||
insertIndex = i;
|
||||
break;
|
||||
}
|
||||
if (insertIndex > lastAppTrayIndex + 1) {
|
||||
insertIndex = lastAppTrayIndex + 1;
|
||||
}
|
||||
|
||||
return insertIndex;
|
||||
}
|
||||
|
||||
int NormalContainer::whereToInsertSystemTrayByDefault(FashionTrayWidgetWrapper *wrapper) const
|
||||
{
|
||||
if (wrapperList().isEmpty()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int firstSystemTrayIndex = -1;
|
||||
for (int i = 0; i < wrapperList().size(); ++i) {
|
||||
if (wrapperList().at(i)->absTrayWidget()->trayTyep() == AbstractTrayWidget::TrayType::SystemTray) {
|
||||
firstSystemTrayIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// there is no SystemTray
|
||||
if (firstSystemTrayIndex == -1) {
|
||||
return wrapperList().size();
|
||||
}
|
||||
// the inserting tray is not a SystemTray
|
||||
if (wrapper->absTrayWidget()->trayTyep() != AbstractTrayWidget::TrayType::SystemTray) {
|
||||
return firstSystemTrayIndex;
|
||||
}
|
||||
|
||||
int insertIndex = trayPlugin()->itemSortKey(wrapper->itemKey());
|
||||
// invalid index
|
||||
if (insertIndex < -1) {
|
||||
return firstSystemTrayIndex;
|
||||
}
|
||||
for (int i = 0; i < wrapperList().size(); ++i) {
|
||||
if (wrapperList().at(i)->absTrayWidget()->trayTyep() != AbstractTrayWidget::TrayType::SystemTray) {
|
||||
continue;
|
||||
}
|
||||
if (insertIndex > trayPlugin()->itemSortKey(wrapperList().at(i)->itemKey())) {
|
||||
continue;
|
||||
}
|
||||
insertIndex = i;
|
||||
break;
|
||||
}
|
||||
if (insertIndex < firstSystemTrayIndex) {
|
||||
return firstSystemTrayIndex;
|
||||
}
|
||||
|
||||
return insertIndex;
|
||||
}
|
||||
void NormalContainer::updateSize()
|
||||
{
|
||||
if (QPropertyAnimation::Stopped == m_sizeAnimation->state()) {
|
||||
if (dockPosition() == Dock::Top || dockPosition() == Dock::Bottom)
|
||||
setMaximumWidth(totalSize().width());
|
||||
else {
|
||||
setMaximumHeight(totalSize().height());
|
||||
}
|
||||
}
|
||||
}
|
@ -1,41 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#ifndef NORMALCONTAINER_H
|
||||
#define NORMALCONTAINER_H
|
||||
|
||||
#include "abstractcontainer.h"
|
||||
|
||||
class NormalContainer : public AbstractContainer
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit NormalContainer(TrayPlugin *trayPlugin, QWidget *parent = nullptr);
|
||||
|
||||
// AbstractContainer interface
|
||||
public:
|
||||
bool acceptWrapper(FashionTrayWidgetWrapper *wrapper) override;
|
||||
void addWrapper(FashionTrayWidgetWrapper *wrapper) override;
|
||||
void refreshVisible() override;
|
||||
void setExpand(const bool expand) override;
|
||||
int itemCount() override;
|
||||
QSize sizeHint() const override;
|
||||
void updateSize();
|
||||
|
||||
protected:
|
||||
int whereToInsert(FashionTrayWidgetWrapper *wrapper) override;
|
||||
void resizeEvent(QResizeEvent *event) override;
|
||||
|
||||
private:
|
||||
int whereToInsertByDefault(FashionTrayWidgetWrapper *wrapper) const;
|
||||
int whereToInsertAppTrayByDefault(FashionTrayWidgetWrapper *wrapper) const;
|
||||
int whereToInsertSystemTrayByDefault(FashionTrayWidgetWrapper *wrapper) const;
|
||||
void compositeChanged();
|
||||
void adjustMaxSize(const QSize size);
|
||||
|
||||
private:
|
||||
mutable QVariantAnimation *m_sizeAnimation;
|
||||
};
|
||||
|
||||
#endif // NORMALCONTAINER_H
|
@ -1,112 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#include "spliteranimated.h"
|
||||
|
||||
#include <QPainter>
|
||||
#include <QPainterPath>
|
||||
#include <QDebug>
|
||||
|
||||
#define OpacityMax 0.3
|
||||
#define OpacityMini 0.1
|
||||
|
||||
SpliterAnimated::SpliterAnimated(QWidget *parent)
|
||||
: QWidget(parent),
|
||||
m_sizeAnimation(new QVariantAnimation(this)),
|
||||
m_currentOpacity(OpacityMini),
|
||||
m_dockPosition(Dock::Position::Bottom)
|
||||
{
|
||||
m_sizeAnimation->setDuration(500);
|
||||
m_sizeAnimation->setLoopCount(-1);
|
||||
|
||||
connect(m_sizeAnimation, &QVariantAnimation::valueChanged, this, &SpliterAnimated::onSizeAnimationValueChanged);
|
||||
}
|
||||
|
||||
void SpliterAnimated::setStartValue(const QVariant &value)
|
||||
{
|
||||
m_sizeAnimation->setStartValue(value);
|
||||
}
|
||||
|
||||
void SpliterAnimated::setEndValue(const QVariant &value)
|
||||
{
|
||||
m_sizeAnimation->setEndValue(value);
|
||||
}
|
||||
|
||||
//void SpliterAnimated::startAnimation()
|
||||
//{
|
||||
// if (!isVisible()) {
|
||||
// return;
|
||||
// }
|
||||
|
||||
// m_currentOpacity = OpacityMini;
|
||||
|
||||
// if (m_dockPosition == Dock::Position::Top || m_dockPosition == Dock::Position::Bottom) {
|
||||
// m_opacityChangeStep = (OpacityMax - OpacityMini) /
|
||||
// (m_sizeAnimation->endValue().toSizeF().height() -
|
||||
// m_sizeAnimation->startValue().toSizeF().height());
|
||||
// } else {
|
||||
// m_opacityChangeStep = (OpacityMax - OpacityMini) /
|
||||
// (m_sizeAnimation->endValue().toSizeF().width() -
|
||||
// m_sizeAnimation->startValue().toSizeF().width());
|
||||
// }
|
||||
|
||||
// m_sizeAnimation->start();
|
||||
|
||||
// update();
|
||||
//}
|
||||
|
||||
//void SpliterAnimated::stopAnimation()
|
||||
//{
|
||||
// m_sizeAnimation->stop();
|
||||
// m_currentOpacity = OpacityMini;
|
||||
|
||||
// update();
|
||||
//}
|
||||
|
||||
void SpliterAnimated::setDockPosition(const Dock::Position position)
|
||||
{
|
||||
m_dockPosition = position;
|
||||
}
|
||||
|
||||
void SpliterAnimated::paintEvent(QPaintEvent *event)
|
||||
{
|
||||
Q_UNUSED(event);
|
||||
|
||||
QSizeF destSize = m_sizeAnimation->state() == QVariantAnimation::Running
|
||||
? m_sizeAnimation->currentValue().toSizeF()
|
||||
: m_sizeAnimation->startValue().toSizeF();
|
||||
|
||||
QRectF destRect(rect().topLeft(), destSize);
|
||||
destRect.moveCenter(QRectF(rect()).center());
|
||||
|
||||
QPainterPath path;
|
||||
path.addRect(destRect);
|
||||
|
||||
QPainter painter(this);
|
||||
painter.setOpacity(m_currentOpacity);
|
||||
painter.fillPath(path, QColor::fromRgb(255, 255, 255));
|
||||
}
|
||||
|
||||
void SpliterAnimated::onSizeAnimationValueChanged(const QVariant &value)
|
||||
{
|
||||
if (m_sizeAnimation->direction() == QVariantAnimation::Direction::Forward) {
|
||||
m_currentOpacity += m_opacityChangeStep;
|
||||
if (m_currentOpacity > OpacityMax) {
|
||||
m_currentOpacity = OpacityMax;
|
||||
}
|
||||
} else {
|
||||
m_currentOpacity -= m_opacityChangeStep;
|
||||
if (m_currentOpacity < OpacityMini) {
|
||||
m_currentOpacity = OpacityMini;
|
||||
}
|
||||
}
|
||||
|
||||
if (value == m_sizeAnimation->endValue()) {
|
||||
m_sizeAnimation->setDirection(QVariantAnimation::Direction::Backward);
|
||||
} else if (value == m_sizeAnimation->startValue()) {
|
||||
m_sizeAnimation->setDirection(QVariantAnimation::Direction::Forward);
|
||||
}
|
||||
|
||||
update();
|
||||
}
|
@ -1,40 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#ifndef SPLITERANIMATED_H
|
||||
#define SPLITERANIMATED_H
|
||||
|
||||
#include <constants.h>
|
||||
|
||||
#include <QWidget>
|
||||
#include <QVariantAnimation>
|
||||
|
||||
class SpliterAnimated : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit SpliterAnimated(QWidget *parent = nullptr);
|
||||
|
||||
void setStartValue(const QVariant &value);
|
||||
void setEndValue(const QVariant &value);
|
||||
// void startAnimation();
|
||||
// void stopAnimation();
|
||||
void setDockPosition(const Dock::Position position);
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
|
||||
private Q_SLOTS:
|
||||
void onSizeAnimationValueChanged(const QVariant &value);
|
||||
|
||||
private:
|
||||
QVariantAnimation *m_sizeAnimation;
|
||||
|
||||
qreal m_opacityChangeStep;
|
||||
qreal m_currentOpacity;
|
||||
|
||||
Dock::Position m_dockPosition;
|
||||
};
|
||||
|
||||
#endif // SPLITERANIMATED_H
|
@ -1,20 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#ifndef FASHIONTRAYCONSTANTS_H
|
||||
#define FASHIONTRAYCONSTANTS_H
|
||||
|
||||
namespace Dock {
|
||||
|
||||
#define SpliterSize 2
|
||||
#define TraySpace 10
|
||||
#define TrayWidgetWidthMin 24
|
||||
#define TrayWidgetHeightMin 24
|
||||
|
||||
|
||||
#define HoldKeyPrefix "holded_"
|
||||
|
||||
}
|
||||
|
||||
#endif // FASHIONTRAYCONSTANTS_H
|
@ -1,199 +0,0 @@
|
||||
// Copyright (C) 2011 ~ 2018 Deepin Technology Co., Ltd.
|
||||
// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#include "fashiontraycontrolwidget.h"
|
||||
|
||||
#include <QMouseEvent>
|
||||
#include <QPainter>
|
||||
#include <QPainterPath>
|
||||
#include <DHiDPIHelper>
|
||||
#include <DStyle>
|
||||
#include <DGuiApplicationHelper>
|
||||
|
||||
#include "../frame/util/imageutil.h"
|
||||
|
||||
DWIDGET_USE_NAMESPACE
|
||||
|
||||
#define ExpandedKey "fashion-tray-expanded"
|
||||
|
||||
FashionTrayControlWidget::FashionTrayControlWidget(Dock::Position position, QWidget *parent)
|
||||
: QWidget(parent),
|
||||
m_expandDelayTimer(new QTimer(this)),
|
||||
m_dockPosition(position),
|
||||
m_expanded(true),
|
||||
m_hover(false),
|
||||
m_pressed(false)
|
||||
{
|
||||
m_expandDelayTimer->setInterval(400);
|
||||
m_expandDelayTimer->setSingleShot(true);
|
||||
|
||||
setDockPostion(m_dockPosition);
|
||||
setExpanded(m_expanded);
|
||||
|
||||
setMinimumSize(PLUGIN_BACKGROUND_MIN_SIZE, PLUGIN_BACKGROUND_MIN_SIZE);
|
||||
setMaximumSize(PLUGIN_BACKGROUND_MAX_SIZE, PLUGIN_BACKGROUND_MAX_SIZE);
|
||||
|
||||
connect(DGuiApplicationHelper::instance(), &DGuiApplicationHelper::themeTypeChanged, this, [ = ] {
|
||||
update();
|
||||
});
|
||||
}
|
||||
|
||||
void FashionTrayControlWidget::setDockPostion(Dock::Position pos)
|
||||
{
|
||||
m_dockPosition = pos;
|
||||
refreshArrowPixmap();
|
||||
}
|
||||
|
||||
bool FashionTrayControlWidget::expanded() const
|
||||
{
|
||||
return m_expanded;
|
||||
}
|
||||
|
||||
void FashionTrayControlWidget::setExpanded(const bool &expanded)
|
||||
{
|
||||
if (m_expanded == expanded) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_expanded = expanded;
|
||||
refreshArrowPixmap();
|
||||
|
||||
Q_EMIT expandChanged(m_expanded);
|
||||
}
|
||||
|
||||
void FashionTrayControlWidget::paintEvent(QPaintEvent *event)
|
||||
{
|
||||
Q_UNUSED(event);
|
||||
|
||||
QPainter painter(this);
|
||||
painter.setRenderHint(QPainter::Antialiasing, true);
|
||||
|
||||
QColor color;
|
||||
if (DGuiApplicationHelper::instance()->themeType() == DGuiApplicationHelper::LightType) {
|
||||
color = Qt::black;
|
||||
painter.setOpacity(0.5);
|
||||
|
||||
if (m_hover) {
|
||||
painter.setOpacity(0.6);
|
||||
}
|
||||
|
||||
if (m_pressed) {
|
||||
painter.setOpacity(0.3);
|
||||
}
|
||||
} else {
|
||||
color = Qt::white;
|
||||
painter.setOpacity(0.1);
|
||||
|
||||
if (m_hover) {
|
||||
painter.setOpacity(0.2);
|
||||
}
|
||||
|
||||
if (m_pressed) {
|
||||
painter.setOpacity(0.05);
|
||||
}
|
||||
}
|
||||
|
||||
// draw background
|
||||
QPainterPath path;
|
||||
if (rect().height() > PLUGIN_BACKGROUND_MIN_SIZE) {
|
||||
DStyleHelper dstyle(style());
|
||||
const int radius = dstyle.pixelMetric(DStyle::PM_FrameRadius);
|
||||
|
||||
int minSize = std::min(width(), height());
|
||||
QRect rc(0, 0, minSize, minSize);
|
||||
rc.moveTo(rect().center() - rc.center());
|
||||
|
||||
path.addRoundedRect(rc, radius, radius);
|
||||
painter.fillPath(path, color);
|
||||
}
|
||||
// reset opacity
|
||||
painter.setOpacity(1);
|
||||
|
||||
// draw arrow pixmap
|
||||
refreshArrowPixmap();
|
||||
QRectF rf = QRectF(rect());
|
||||
QRectF rfp = QRectF(m_arrowPix.rect());
|
||||
QPointF p = rf.center() - rfp.center() / m_arrowPix.devicePixelRatioF();
|
||||
|
||||
painter.drawPixmap(p, m_arrowPix);
|
||||
}
|
||||
|
||||
void FashionTrayControlWidget::mouseReleaseEvent(QMouseEvent *event)
|
||||
{
|
||||
if (m_expandDelayTimer->isActive()) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_expandDelayTimer->start();
|
||||
|
||||
m_pressed = false;
|
||||
update();
|
||||
|
||||
if (event->button() == Qt::LeftButton) {
|
||||
event->accept();
|
||||
setExpanded(!m_expanded);
|
||||
return;
|
||||
}
|
||||
|
||||
QWidget::mouseReleaseEvent(event);
|
||||
}
|
||||
|
||||
void FashionTrayControlWidget::mousePressEvent(QMouseEvent *event)
|
||||
{
|
||||
if (event->button() != Qt::LeftButton) {
|
||||
event->ignore();
|
||||
return QWidget::mousePressEvent(event);
|
||||
}
|
||||
|
||||
m_pressed = true;
|
||||
update();
|
||||
|
||||
QWidget::mousePressEvent(event);
|
||||
}
|
||||
|
||||
void FashionTrayControlWidget::enterEvent(QEvent *event)
|
||||
{
|
||||
m_hover = true;
|
||||
update();
|
||||
|
||||
QWidget::enterEvent(event);
|
||||
}
|
||||
|
||||
void FashionTrayControlWidget::leaveEvent(QEvent *event)
|
||||
{
|
||||
m_hover = false;
|
||||
m_pressed = false;
|
||||
update();
|
||||
|
||||
QWidget::leaveEvent(event);
|
||||
}
|
||||
|
||||
void FashionTrayControlWidget::resizeEvent(QResizeEvent *event)
|
||||
{
|
||||
QWidget::resizeEvent(event);
|
||||
}
|
||||
|
||||
void FashionTrayControlWidget::refreshArrowPixmap()
|
||||
{
|
||||
QString iconPath;
|
||||
|
||||
switch (m_dockPosition) {
|
||||
case Dock::Top:
|
||||
case Dock::Bottom:
|
||||
iconPath = m_expanded ? "arrow-right" : "arrow-left";
|
||||
break;
|
||||
case Dock::Left:
|
||||
case Dock::Right:
|
||||
iconPath = m_expanded ? "arrow-down" : "arrow-up";
|
||||
break;
|
||||
}
|
||||
|
||||
if (height() <= PLUGIN_BACKGROUND_MIN_SIZE && DGuiApplicationHelper::instance()->themeType() == DGuiApplicationHelper::LightType) {
|
||||
iconPath.append("-dark");
|
||||
}
|
||||
|
||||
const auto ratio = devicePixelRatioF();
|
||||
m_arrowPix = ImageUtil::loadSvg(iconPath, ":/icons/resources/", PLUGIN_ICON_MAX_SIZE, ratio);
|
||||
}
|
@ -1,53 +0,0 @@
|
||||
// Copyright (C) 2011 ~ 2018 Deepin Technology Co., Ltd.
|
||||
// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#ifndef FASHIONTRAYCONTROLWIDGET_H
|
||||
#define FASHIONTRAYCONTROLWIDGET_H
|
||||
|
||||
#include "constants.h"
|
||||
|
||||
#include <QLabel>
|
||||
|
||||
/**
|
||||
* @brief The FashionTrayControlWidget class
|
||||
* @note 系统托盘上的展开合并按钮
|
||||
*/
|
||||
class FashionTrayControlWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit FashionTrayControlWidget(Dock::Position position, QWidget *parent = nullptr);
|
||||
|
||||
void setDockPostion(Dock::Position pos);
|
||||
|
||||
bool expanded() const;
|
||||
void setExpanded(const bool &expanded);
|
||||
|
||||
Q_SIGNALS:
|
||||
void expandChanged(const bool expanded);
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
void mouseReleaseEvent(QMouseEvent *event) override;
|
||||
void mousePressEvent(QMouseEvent *event) override;
|
||||
void enterEvent(QEvent *event) override;
|
||||
void leaveEvent(QEvent *event) override;
|
||||
void resizeEvent(QResizeEvent *event) override;
|
||||
|
||||
private:
|
||||
void refreshArrowPixmap();
|
||||
|
||||
private:
|
||||
QTimer *m_expandDelayTimer;
|
||||
QPixmap m_arrowPix;
|
||||
|
||||
Dock::Position m_dockPosition;
|
||||
bool m_expanded;
|
||||
bool m_hover;
|
||||
bool m_pressed;
|
||||
};
|
||||
|
||||
#endif // FASHIONTRAYCONTROLWIDGET_H
|
@ -1,356 +0,0 @@
|
||||
// Copyright (C) 2011 ~ 2018 Deepin Technology Co., Ltd.
|
||||
// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#include "fashiontrayitem.h"
|
||||
#include "fashiontray/fashiontrayconstants.h"
|
||||
#include "system-trays/systemtrayitem.h"
|
||||
#include "containers/abstractcontainer.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QResizeEvent>
|
||||
|
||||
#define ExpandedKey "fashion-tray-expanded"
|
||||
|
||||
int FashionTrayItem::TrayWidgetWidth = PLUGIN_BACKGROUND_MAX_SIZE;
|
||||
int FashionTrayItem::TrayWidgetHeight = PLUGIN_BACKGROUND_MAX_SIZE;
|
||||
|
||||
FashionTrayItem::FashionTrayItem(TrayPlugin *trayPlugin, QWidget *parent)
|
||||
: QWidget(parent),
|
||||
m_mainBoxLayout(new QBoxLayout(QBoxLayout::Direction::LeftToRight, this))
|
||||
, m_attentionDelayTimer(new QTimer(this))
|
||||
, m_trayPlugin(trayPlugin)
|
||||
, m_controlWidget(new FashionTrayControlWidget(trayPlugin->dockPosition(), this))
|
||||
, m_normalContainer(new NormalContainer(m_trayPlugin, this))
|
||||
, m_attentionContainer(new AttentionContainer(m_trayPlugin, this))
|
||||
, m_holdContainer(new HoldContainer(m_trayPlugin, this))
|
||||
, m_leftSpace(new QWidget(this))
|
||||
{
|
||||
setAcceptDrops(true);
|
||||
|
||||
m_normalContainer->setVisible(false);
|
||||
m_attentionContainer->setVisible(false);
|
||||
m_holdContainer->setVisible(false);
|
||||
|
||||
m_mainBoxLayout->setMargin(0);
|
||||
m_mainBoxLayout->setContentsMargins(0, 0, 0, 0);
|
||||
m_mainBoxLayout->setSpacing(0);
|
||||
|
||||
m_leftSpace->setFixedSize(TraySpace, TraySpace);
|
||||
m_leftSpace->setAccessibleName("leftspace");
|
||||
|
||||
m_mainBoxLayout->addWidget(m_leftSpace);
|
||||
m_mainBoxLayout->addWidget(m_normalContainer);
|
||||
m_mainBoxLayout->addWidget(m_controlWidget);
|
||||
m_mainBoxLayout->addWidget(m_holdContainer);
|
||||
m_mainBoxLayout->addWidget(m_attentionContainer);
|
||||
|
||||
setLayout(m_mainBoxLayout);
|
||||
|
||||
m_attentionDelayTimer->setInterval(3000);
|
||||
m_attentionDelayTimer->setSingleShot(true);
|
||||
|
||||
connect(m_controlWidget, &FashionTrayControlWidget::expandChanged, this, &FashionTrayItem::onExpandChanged);
|
||||
connect(m_normalContainer, &NormalContainer::attentionChanged, this, &FashionTrayItem::onWrapperAttentionChanged);
|
||||
connect(m_attentionContainer, &AttentionContainer::attentionChanged, this, &FashionTrayItem::onWrapperAttentionChanged);
|
||||
connect(m_normalContainer, &NormalContainer::requestDraggingWrapper, this, &FashionTrayItem::onRequireDraggingWrapper);
|
||||
connect(m_holdContainer, &HoldContainer::requestDraggingWrapper, this, &FashionTrayItem::onRequireDraggingWrapper);
|
||||
|
||||
// do not call init immediately the TrayPlugin has not be constructed for now
|
||||
QTimer::singleShot(0, this, &FashionTrayItem::init);
|
||||
}
|
||||
|
||||
void FashionTrayItem::setTrayWidgets(const QMap<QString, AbstractTrayWidget *> &itemTrayMap)
|
||||
{
|
||||
clearTrayWidgets();
|
||||
|
||||
for (auto it = itemTrayMap.constBegin(); it != itemTrayMap.constEnd(); ++it) {
|
||||
trayWidgetAdded(it.key(), it.value());
|
||||
}
|
||||
}
|
||||
|
||||
void FashionTrayItem::trayWidgetAdded(const QString &itemKey, AbstractTrayWidget *trayWidget)
|
||||
{
|
||||
if (m_normalContainer->containsWrapperByTrayWidget(trayWidget)) {
|
||||
qDebug() << "Reject! want to insert duplicate trayWidget:" << itemKey << trayWidget;
|
||||
return;
|
||||
}
|
||||
|
||||
FashionTrayWidgetWrapper *wrapper = new FashionTrayWidgetWrapper(itemKey, trayWidget);
|
||||
|
||||
do {
|
||||
if (m_holdContainer->acceptWrapper(wrapper)) {
|
||||
m_holdContainer->addWrapper(wrapper);
|
||||
break;
|
||||
}
|
||||
if (m_normalContainer->acceptWrapper(wrapper)) {
|
||||
m_normalContainer->addWrapper(wrapper);
|
||||
break;
|
||||
}
|
||||
} while (false);
|
||||
|
||||
onExpandChanged(m_controlWidget->expanded());
|
||||
requestResize();
|
||||
}
|
||||
|
||||
void FashionTrayItem::trayWidgetRemoved(AbstractTrayWidget *trayWidget)
|
||||
{
|
||||
bool deleted = false;
|
||||
|
||||
do {
|
||||
if (m_normalContainer->removeWrapperByTrayWidget(trayWidget)) {
|
||||
deleted = true;
|
||||
break;
|
||||
}
|
||||
if (m_attentionContainer->removeWrapperByTrayWidget(trayWidget)) {
|
||||
deleted = true;
|
||||
break;
|
||||
}
|
||||
if (m_holdContainer->removeWrapperByTrayWidget(trayWidget)) {
|
||||
deleted = true;
|
||||
break;
|
||||
}
|
||||
} while (false);
|
||||
|
||||
if (!deleted) {
|
||||
qDebug() << "Error! can not find the tray widget in fashion tray list" << trayWidget;
|
||||
}
|
||||
|
||||
requestResize();
|
||||
}
|
||||
|
||||
void FashionTrayItem::clearTrayWidgets()
|
||||
{
|
||||
m_normalContainer->clearWrapper();
|
||||
m_attentionContainer->clearWrapper();
|
||||
m_holdContainer->clearWrapper();
|
||||
|
||||
requestResize();
|
||||
}
|
||||
|
||||
void FashionTrayItem::setDockPosition(Dock::Position pos)
|
||||
{
|
||||
m_dockpos = pos;
|
||||
m_controlWidget->setDockPostion(pos);
|
||||
SystemTrayItem::setDockPostion(pos);
|
||||
SNITrayWidget::setDockPostion(pos);
|
||||
|
||||
m_normalContainer->setDockPosition(pos);
|
||||
m_attentionContainer->setDockPosition(pos);
|
||||
m_holdContainer->setDockPosition(pos);
|
||||
|
||||
if (pos == Dock::Position::Top || pos == Dock::Position::Bottom) {
|
||||
m_mainBoxLayout->setDirection(QBoxLayout::Direction::LeftToRight);
|
||||
} else {
|
||||
m_mainBoxLayout->setDirection(QBoxLayout::Direction::TopToBottom);
|
||||
}
|
||||
|
||||
requestResize();
|
||||
}
|
||||
|
||||
void FashionTrayItem::onExpandChanged(const bool expand)
|
||||
{
|
||||
m_trayPlugin->saveValue(FASHION_MODE_ITEM_KEY, ExpandedKey, expand);
|
||||
|
||||
m_normalContainer->setExpand(expand);
|
||||
|
||||
m_attentionContainer->setExpand(expand);
|
||||
m_holdContainer->setExpand(expand);
|
||||
|
||||
m_attentionDelayTimer->start();
|
||||
|
||||
attentionWrapperToNormalWrapper();
|
||||
|
||||
requestResize();
|
||||
}
|
||||
|
||||
void FashionTrayItem::setRightSplitVisible(const bool visible)
|
||||
{
|
||||
Q_UNUSED(visible);
|
||||
}
|
||||
|
||||
void FashionTrayItem::onPluginSettingsChanged()
|
||||
{
|
||||
m_controlWidget->setExpanded(m_trayPlugin->getValue(FASHION_MODE_ITEM_KEY, ExpandedKey, true).toBool());
|
||||
}
|
||||
|
||||
void FashionTrayItem::showEvent(QShowEvent *event)
|
||||
{
|
||||
requestResize();
|
||||
|
||||
QWidget::showEvent(event);
|
||||
}
|
||||
|
||||
void FashionTrayItem::hideEvent(QHideEvent *event)
|
||||
{
|
||||
requestResize();
|
||||
|
||||
QWidget::hideEvent(event);
|
||||
}
|
||||
|
||||
void FashionTrayItem::resizeEvent(QResizeEvent *event)
|
||||
{
|
||||
resizeTray();
|
||||
QWidget::resizeEvent(event);
|
||||
}
|
||||
|
||||
void FashionTrayItem::dragEnterEvent(QDragEnterEvent *event)
|
||||
{
|
||||
// accept but do not handle the trays drag event
|
||||
// in order to avoid the for forbidden label displayed on the mouse
|
||||
if (event->mimeData()->hasFormat(TRAY_ITEM_DRAG_MIMEDATA)) {
|
||||
event->accept();
|
||||
return;
|
||||
}
|
||||
|
||||
QWidget::dragEnterEvent(event);
|
||||
}
|
||||
|
||||
void FashionTrayItem::init()
|
||||
{
|
||||
qDebug() << "init Fashion mode tray plugin item";
|
||||
m_controlWidget->setExpanded(m_trayPlugin->getValue(FASHION_MODE_ITEM_KEY, ExpandedKey, true).toBool());
|
||||
setDockPosition(m_trayPlugin->dockPosition());
|
||||
onExpandChanged(m_controlWidget->expanded());
|
||||
}
|
||||
|
||||
void FashionTrayItem::onWrapperAttentionChanged(FashionTrayWidgetWrapper *wrapper, const bool attention)
|
||||
{
|
||||
if (m_controlWidget->expanded()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 在timer处于Active状态期间不设置新的活动图标
|
||||
if (attention && m_attentionDelayTimer->isActive()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (attention) {
|
||||
// ignore the attention which is come from AttentionContainer
|
||||
if (m_attentionContainer->containsWrapper(wrapper)) {
|
||||
return;
|
||||
}
|
||||
// move previous attention wrapper from AttentionContainer to NormalContainer
|
||||
attentionWrapperToNormalWrapper();
|
||||
// move current attention wrapper from NormalContainer to AttentionContainer
|
||||
normalWrapperToAttentionWrapper(wrapper);
|
||||
} else {
|
||||
// only focus the disattention from AttentionContainer
|
||||
if (m_attentionContainer->containsWrapper(wrapper)) {
|
||||
attentionWrapperToNormalWrapper();
|
||||
}
|
||||
}
|
||||
m_attentionDelayTimer->start();
|
||||
|
||||
requestResize();
|
||||
}
|
||||
|
||||
void FashionTrayItem::attentionWrapperToNormalWrapper()
|
||||
{
|
||||
FashionTrayWidgetWrapper *preAttentionWrapper = m_attentionContainer->takeAttentionWrapper();
|
||||
if (preAttentionWrapper) {
|
||||
m_normalContainer->addWrapper(preAttentionWrapper);
|
||||
}
|
||||
}
|
||||
|
||||
void FashionTrayItem::normalWrapperToAttentionWrapper(FashionTrayWidgetWrapper *wrapper)
|
||||
{
|
||||
FashionTrayWidgetWrapper *attentionWrapper = m_normalContainer->takeWrapper(wrapper);
|
||||
if (attentionWrapper) {
|
||||
m_attentionContainer->addWrapper(attentionWrapper);
|
||||
} else {
|
||||
qDebug() << "Warnning: not find the attention wrapper in NormalContainer";
|
||||
}
|
||||
}
|
||||
|
||||
void FashionTrayItem::requestResize()
|
||||
{
|
||||
// 通知dock,当前托盘有几个图标显示,用来计算图标大小
|
||||
m_leftSpace->setVisible(!m_controlWidget->expanded());
|
||||
|
||||
int count = m_normalContainer->itemCount() + m_holdContainer->itemCount() + m_attentionContainer->itemCount();
|
||||
setProperty("TrayVisableItemCount", count + 1); // +1 : m_controlWidget
|
||||
|
||||
resizeTray();
|
||||
}
|
||||
|
||||
void FashionTrayItem::onRequireDraggingWrapper()
|
||||
{
|
||||
AbstractContainer *container = dynamic_cast<AbstractContainer *>(sender());
|
||||
|
||||
if (!container) {
|
||||
return;
|
||||
}
|
||||
|
||||
FashionTrayWidgetWrapper *draggingWrapper = nullptr;
|
||||
do {
|
||||
draggingWrapper = m_normalContainer->takeDraggingWrapper();
|
||||
if (draggingWrapper) {
|
||||
break;
|
||||
}
|
||||
draggingWrapper = m_holdContainer->takeDraggingWrapper();
|
||||
if (draggingWrapper) {
|
||||
break;
|
||||
}
|
||||
} while (false);
|
||||
|
||||
if (!draggingWrapper) {
|
||||
return;
|
||||
}
|
||||
|
||||
container->addDraggingWrapper(draggingWrapper);
|
||||
}
|
||||
|
||||
bool FashionTrayItem::event(QEvent *event)
|
||||
{
|
||||
if (event->type() == QEvent::DynamicPropertyChange) {
|
||||
const QString &propertyName = static_cast<QDynamicPropertyChangeEvent *>(event)->propertyName();
|
||||
if (propertyName == "iconSize") {
|
||||
m_iconSize = property("iconSize").toInt();
|
||||
m_normalContainer->setItemSize(m_iconSize);
|
||||
m_holdContainer->setItemSize(m_iconSize);
|
||||
m_attentionContainer->setItemSize(m_iconSize);
|
||||
|
||||
resizeTray();
|
||||
}
|
||||
}
|
||||
|
||||
return QWidget::event(event);
|
||||
}
|
||||
|
||||
void FashionTrayItem::resizeTray()
|
||||
{
|
||||
if (!m_iconSize)
|
||||
return;
|
||||
|
||||
if (m_dockpos == Dock::Position::Top || m_dockpos == Dock::Position::Bottom) {
|
||||
if (m_attentionContainer->itemCount() != 0){
|
||||
m_mainBoxLayout->setContentsMargins(0, 0, TraySpace, 0);
|
||||
} else {
|
||||
m_mainBoxLayout->setContentsMargins(0, 0, 0, 0);
|
||||
}
|
||||
m_holdContainer->setFixedWidth((m_iconSize + TraySpace) * m_holdContainer->itemCount() + TraySpace);
|
||||
m_holdContainer->setFixedHeight(QWIDGETSIZE_MAX);
|
||||
|
||||
m_attentionContainer->setFixedWidth(m_iconSize * m_attentionContainer->itemCount());
|
||||
m_attentionContainer->setFixedHeight(QWIDGETSIZE_MAX);
|
||||
|
||||
m_controlWidget->setFixedSize(m_iconSize, QWIDGETSIZE_MAX);
|
||||
} else {
|
||||
m_holdContainer->setFixedWidth(QWIDGETSIZE_MAX);
|
||||
if (m_attentionContainer->itemCount() != 0){
|
||||
m_mainBoxLayout->setContentsMargins(0, 0, 0, TraySpace);
|
||||
} else {
|
||||
m_mainBoxLayout->setContentsMargins(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
m_holdContainer->setFixedHeight((m_iconSize + TraySpace) * m_holdContainer->itemCount() + TraySpace);
|
||||
m_attentionContainer->setFixedWidth(QWIDGETSIZE_MAX);
|
||||
m_attentionContainer->setFixedHeight(m_iconSize * m_attentionContainer->itemCount());
|
||||
|
||||
m_controlWidget->setFixedSize(QWIDGETSIZE_MAX, m_iconSize);
|
||||
}
|
||||
|
||||
m_normalContainer->updateSize();
|
||||
}
|
@ -1,84 +0,0 @@
|
||||
// Copyright (C) 2011 ~ 2018 Deepin Technology Co., Ltd.
|
||||
// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#ifndef FASHIONTRAYITEM_H
|
||||
#define FASHIONTRAYITEM_H
|
||||
|
||||
#include "constants.h"
|
||||
#include "../trayplugin.h"
|
||||
#include "fashiontraywidgetwrapper.h"
|
||||
#include "fashiontraycontrolwidget.h"
|
||||
#include "containers/normalcontainer.h"
|
||||
#include "containers/attentioncontainer.h"
|
||||
#include "containers/holdcontainer.h"
|
||||
|
||||
#include <QWidget>
|
||||
#include <QPointer>
|
||||
#include <QBoxLayout>
|
||||
#include <QLabel>
|
||||
|
||||
#include "../abstracttraywidget.h"
|
||||
|
||||
#define FASHION_MODE_ITEM_KEY "fashion-mode-item"
|
||||
|
||||
class FashionTrayItem : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit FashionTrayItem(TrayPlugin *trayPlugin, QWidget *parent = 0);
|
||||
|
||||
void setTrayWidgets(const QMap<QString, AbstractTrayWidget *> &itemTrayMap);
|
||||
void trayWidgetAdded(const QString &itemKey, AbstractTrayWidget *trayWidget);
|
||||
void trayWidgetRemoved(AbstractTrayWidget *trayWidget);
|
||||
void clearTrayWidgets();
|
||||
|
||||
void setDockPosition(Dock::Position pos);
|
||||
|
||||
inline static int trayWidgetWidth() {return TrayWidgetWidth;}
|
||||
inline static int trayWidgetHeight() {return TrayWidgetHeight;}
|
||||
|
||||
public slots:
|
||||
void onExpandChanged(const bool expand);
|
||||
void setRightSplitVisible(const bool visible);
|
||||
void onPluginSettingsChanged();
|
||||
|
||||
protected:
|
||||
void showEvent(QShowEvent *event) override;
|
||||
void hideEvent(QHideEvent *event) override;
|
||||
void resizeEvent(QResizeEvent *event) override;
|
||||
void dragEnterEvent(QDragEnterEvent *event) override;
|
||||
bool event(QEvent *event) override;
|
||||
|
||||
private:
|
||||
void init();
|
||||
void resizeTray();
|
||||
|
||||
private Q_SLOTS:
|
||||
void onWrapperAttentionChanged(FashionTrayWidgetWrapper *wrapper, const bool attention);
|
||||
void attentionWrapperToNormalWrapper();
|
||||
void normalWrapperToAttentionWrapper(FashionTrayWidgetWrapper *wrapper);
|
||||
void requestResize();
|
||||
void onRequireDraggingWrapper();
|
||||
|
||||
private:
|
||||
QBoxLayout *m_mainBoxLayout;
|
||||
QTimer *m_attentionDelayTimer;
|
||||
|
||||
TrayPlugin *m_trayPlugin;
|
||||
FashionTrayControlWidget *m_controlWidget; //展开按钮
|
||||
|
||||
NormalContainer *m_normalContainer; //左侧可展开窗口
|
||||
AttentionContainer *m_attentionContainer;
|
||||
HoldContainer *m_holdContainer; //常驻窗口
|
||||
|
||||
static int TrayWidgetWidth;
|
||||
static int TrayWidgetHeight;
|
||||
QWidget *m_leftSpace;
|
||||
Dock::Position m_dockpos;
|
||||
int m_iconSize = 40;
|
||||
};
|
||||
|
||||
#endif // FASHIONTRAYITEM_H
|
@ -1,269 +0,0 @@
|
||||
// Copyright (C) 2011 ~ 2018 Deepin Technology Co., Ltd.
|
||||
// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#include "fashiontraywidgetwrapper.h"
|
||||
#include "../xembedtraywidget.h"
|
||||
#include "util/touchsignalmanager.h"
|
||||
|
||||
#include <QPainter>
|
||||
#include <QPainterPath>
|
||||
#include <QDebug>
|
||||
#include <QMouseEvent>
|
||||
#include <QDrag>
|
||||
#include <QMimeData>
|
||||
|
||||
#include <DStyle>
|
||||
#include <DGuiApplicationHelper>
|
||||
|
||||
#include "constants.h"
|
||||
|
||||
#define TRAY_ITEM_DRAG_THRESHOLD 20
|
||||
|
||||
DWIDGET_USE_NAMESPACE
|
||||
|
||||
FashionTrayWidgetWrapper::FashionTrayWidgetWrapper(const QString &itemKey, AbstractTrayWidget *absTrayWidget, QWidget *parent)
|
||||
: QWidget(parent)
|
||||
, m_absTrayWidget(absTrayWidget)
|
||||
, m_layout(new QVBoxLayout(this))
|
||||
, m_attention(false)
|
||||
, m_dragging(false)
|
||||
, m_hover(false)
|
||||
, m_pressed(false)
|
||||
, m_itemKey(itemKey)
|
||||
|
||||
{
|
||||
setStyleSheet("background: transparent;");
|
||||
setAcceptDrops(true);
|
||||
setObjectName(itemKey);
|
||||
|
||||
m_layout->setSpacing(0);
|
||||
m_layout->setMargin(0);
|
||||
m_layout->setContentsMargins(0, 0, 0, 0);
|
||||
|
||||
m_layout->addWidget(m_absTrayWidget);
|
||||
|
||||
setLayout(m_layout);
|
||||
|
||||
connect(m_absTrayWidget, &AbstractTrayWidget::needAttention, this, &FashionTrayWidgetWrapper::onTrayWidgetNeedAttention);
|
||||
connect(m_absTrayWidget, &AbstractTrayWidget::clicked, this, &FashionTrayWidgetWrapper::onTrayWidgetClicked);
|
||||
|
||||
setMinimumSize(PLUGIN_BACKGROUND_MIN_SIZE, PLUGIN_BACKGROUND_MIN_SIZE);
|
||||
|
||||
m_absTrayWidget->show();
|
||||
}
|
||||
|
||||
QPointer<AbstractTrayWidget> FashionTrayWidgetWrapper::absTrayWidget() const
|
||||
{
|
||||
return m_absTrayWidget;
|
||||
}
|
||||
|
||||
QString FashionTrayWidgetWrapper::itemKey() const
|
||||
{
|
||||
return m_itemKey;
|
||||
}
|
||||
|
||||
void FashionTrayWidgetWrapper::paintEvent(QPaintEvent *event)
|
||||
{
|
||||
Q_UNUSED(event);
|
||||
|
||||
if (m_dragging) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (rect().height() > PLUGIN_BACKGROUND_MIN_SIZE) {
|
||||
QPainter painter(this);
|
||||
painter.setRenderHint(QPainter::Antialiasing, true);
|
||||
|
||||
QColor color;
|
||||
if (DGuiApplicationHelper::instance()->themeType() == DGuiApplicationHelper::LightType) {
|
||||
color = Qt::black;
|
||||
painter.setOpacity(0.5);
|
||||
|
||||
if (m_hover) {
|
||||
painter.setOpacity(0.6);
|
||||
}
|
||||
|
||||
if (m_pressed) {
|
||||
painter.setOpacity(0.3);
|
||||
}
|
||||
} else {
|
||||
color = Qt::white;
|
||||
painter.setOpacity(0.1);
|
||||
|
||||
if (m_hover) {
|
||||
painter.setOpacity(0.2);
|
||||
}
|
||||
|
||||
if (m_pressed) {
|
||||
painter.setOpacity(0.05);
|
||||
}
|
||||
}
|
||||
|
||||
DStyleHelper dstyle(style());
|
||||
const int radius = dstyle.pixelMetric(DStyle::PM_FrameRadius);
|
||||
|
||||
QPainterPath path;
|
||||
|
||||
int minSize = std::min(width(), height());
|
||||
QRect rc(0, 0, minSize, minSize);
|
||||
rc.moveTo(rect().center() - rc.center());
|
||||
|
||||
path.addRoundedRect(rc, radius, radius);
|
||||
painter.fillPath(path, color);
|
||||
}
|
||||
}
|
||||
|
||||
void FashionTrayWidgetWrapper::mousePressEvent(QMouseEvent *event)
|
||||
{
|
||||
if (event->button() == Qt::MouseButton::LeftButton) {
|
||||
MousePressPoint = event->pos();
|
||||
}
|
||||
|
||||
m_pressed = true;
|
||||
update();
|
||||
|
||||
QWidget::mousePressEvent(event);
|
||||
}
|
||||
|
||||
void FashionTrayWidgetWrapper::mouseMoveEvent(QMouseEvent *event)
|
||||
{
|
||||
handleMouseMove(event);
|
||||
}
|
||||
|
||||
void FashionTrayWidgetWrapper::mouseReleaseEvent(QMouseEvent *event)
|
||||
{
|
||||
m_pressed = false;
|
||||
m_hover = false;
|
||||
update();
|
||||
|
||||
QWidget::mouseReleaseEvent(event);
|
||||
}
|
||||
|
||||
void FashionTrayWidgetWrapper::dragEnterEvent(QDragEnterEvent *event)
|
||||
{
|
||||
if (event->mimeData()->hasFormat(TRAY_ITEM_DRAG_MIMEDATA)) {
|
||||
event->accept();
|
||||
Q_EMIT requestSwapWithDragging();
|
||||
return;
|
||||
}
|
||||
|
||||
QWidget::dragEnterEvent(event);
|
||||
}
|
||||
|
||||
void FashionTrayWidgetWrapper::enterEvent(QEvent *event)
|
||||
{
|
||||
m_hover = true;
|
||||
update();
|
||||
|
||||
QWidget::enterEvent(event);
|
||||
}
|
||||
|
||||
void FashionTrayWidgetWrapper::leaveEvent(QEvent *event)
|
||||
{
|
||||
// Note:
|
||||
// here we should check the mouse position to ensure the mouse is really leaved
|
||||
// because this leaveEvent will also be called if setX11PassMouseEvent(false) is invoked
|
||||
// in XWindowTrayWidget::sendHoverEvent()
|
||||
|
||||
if (qobject_cast<XEmbedTrayWidget *>(m_absTrayWidget) && rect().contains(mapFromGlobal(QCursor::pos()))) {
|
||||
return QWidget::leaveEvent(event);
|
||||
}
|
||||
|
||||
m_hover = false;
|
||||
m_pressed = false;
|
||||
update();
|
||||
|
||||
QWidget::leaveEvent(event);
|
||||
}
|
||||
|
||||
void FashionTrayWidgetWrapper::resizeEvent(QResizeEvent *event)
|
||||
{
|
||||
const Dock::Position position = qApp->property(PROP_POSITION).value<Dock::Position>();
|
||||
// 保持横纵比
|
||||
if (position == Dock::Bottom || position == Dock::Top) {
|
||||
setMaximumWidth(height());
|
||||
setMaximumHeight(QWIDGETSIZE_MAX);
|
||||
} else {
|
||||
setMaximumHeight(width());
|
||||
setMaximumWidth(QWIDGETSIZE_MAX);
|
||||
}
|
||||
|
||||
QWidget::resizeEvent(event);
|
||||
}
|
||||
|
||||
void FashionTrayWidgetWrapper::handleMouseMove(QMouseEvent *event)
|
||||
{
|
||||
if(m_absTrayWidget.isNull())
|
||||
return;
|
||||
|
||||
if (event->buttons() != Qt::MouseButton::LeftButton) {
|
||||
return QWidget::mouseMoveEvent(event);
|
||||
}
|
||||
|
||||
if ((event->pos() - MousePressPoint).manhattanLength() < TRAY_ITEM_DRAG_THRESHOLD) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 如果是触屏事件转换而来并且没有收到后端的延时触屏消息,不进行拖拽
|
||||
if (event->source() == Qt::MouseEventSynthesizedByQt && !TouchSignalManager::instance()->isDragIconPress()) {
|
||||
return;
|
||||
}
|
||||
|
||||
event->accept();
|
||||
|
||||
QDrag drag(this);
|
||||
QMimeData *mimeData = new QMimeData;
|
||||
mimeData->setData(TRAY_ITEM_DRAG_MIMEDATA, m_itemKey.toLocal8Bit());
|
||||
QPixmap pixmap = grab();
|
||||
|
||||
drag.setMimeData(mimeData);
|
||||
drag.setPixmap(pixmap);
|
||||
drag.setHotSpot(pixmap.rect().center() / pixmap.devicePixelRatioF());
|
||||
|
||||
m_absTrayWidget->setVisible(false);
|
||||
m_dragging = true;
|
||||
Q_EMIT dragStart();
|
||||
|
||||
// start drag
|
||||
drag.exec();
|
||||
|
||||
m_absTrayWidget->setVisible(true);
|
||||
m_dragging = false;
|
||||
m_hover = false;
|
||||
m_pressed = false;
|
||||
Q_EMIT dragStop();
|
||||
}
|
||||
|
||||
void FashionTrayWidgetWrapper::onTrayWidgetNeedAttention()
|
||||
{
|
||||
setAttention(true);
|
||||
}
|
||||
|
||||
void FashionTrayWidgetWrapper::onTrayWidgetClicked()
|
||||
{
|
||||
setAttention(false);
|
||||
}
|
||||
|
||||
bool FashionTrayWidgetWrapper::attention() const
|
||||
{
|
||||
return m_attention;
|
||||
}
|
||||
|
||||
void FashionTrayWidgetWrapper::setAttention(bool attention)
|
||||
{
|
||||
m_attention = attention;
|
||||
|
||||
Q_EMIT attentionChanged(m_attention);
|
||||
}
|
||||
|
||||
bool FashionTrayWidgetWrapper::isDragging()
|
||||
{
|
||||
return m_dragging;
|
||||
}
|
||||
|
||||
void FashionTrayWidgetWrapper::cancelDragging()
|
||||
{
|
||||
QDrag::cancel();
|
||||
}
|
@ -1,68 +0,0 @@
|
||||
// Copyright (C) 2011 ~ 2018 Deepin Technology Co., Ltd.
|
||||
// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#ifndef FASHIONTRAYWIDGETWRAPPER_H
|
||||
#define FASHIONTRAYWIDGETWRAPPER_H
|
||||
|
||||
#include "../abstracttraywidget.h"
|
||||
|
||||
#include "org_deepin_dde_gesture1.h"
|
||||
|
||||
#include <QWidget>
|
||||
#include <QVBoxLayout>
|
||||
#include <QPointer>
|
||||
|
||||
using Gesture = org::deepin::dde::Gesture1;
|
||||
|
||||
#define TRAY_ITEM_DRAG_MIMEDATA "TrayItemDragDrop"
|
||||
|
||||
class FashionTrayWidgetWrapper : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
FashionTrayWidgetWrapper(const QString &itemKey, AbstractTrayWidget *absTrayWidget, QWidget *parent = nullptr);
|
||||
|
||||
QPointer<AbstractTrayWidget> absTrayWidget() const;
|
||||
QString itemKey() const;
|
||||
|
||||
bool attention() const;
|
||||
void setAttention(bool attention);
|
||||
bool isDragging();
|
||||
void cancelDragging();
|
||||
|
||||
Q_SIGNALS:
|
||||
void attentionChanged(const bool attention);
|
||||
void dragStart();
|
||||
void dragStop();
|
||||
void requestSwapWithDragging();
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
void mousePressEvent(QMouseEvent *event) override;
|
||||
void mouseMoveEvent(QMouseEvent *event) override;
|
||||
void mouseReleaseEvent(QMouseEvent *event) override;
|
||||
void dragEnterEvent(QDragEnterEvent *event) override;
|
||||
void enterEvent(QEvent *event) override;
|
||||
void leaveEvent(QEvent *event) override;
|
||||
void resizeEvent(QResizeEvent *event) override;
|
||||
|
||||
private:
|
||||
void handleMouseMove(QMouseEvent *event);
|
||||
void onTrayWidgetNeedAttention();
|
||||
void onTrayWidgetClicked();
|
||||
|
||||
private:
|
||||
QPointer<AbstractTrayWidget> m_absTrayWidget;
|
||||
QVBoxLayout *m_layout;
|
||||
|
||||
bool m_attention;
|
||||
bool m_dragging;
|
||||
bool m_hover;
|
||||
bool m_pressed;
|
||||
QString m_itemKey;
|
||||
QPoint MousePressPoint;
|
||||
};
|
||||
|
||||
#endif //FASHIONTRAYWIDGETWRAPPER_H
|
@ -1,274 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#include "indicatortray.h"
|
||||
|
||||
#include <QLabel>
|
||||
#include <QDBusConnection>
|
||||
#include <QJsonObject>
|
||||
#include <QDBusInterface>
|
||||
#include <QDBusReply>
|
||||
#include <QDebug>
|
||||
#include <QApplication>
|
||||
#include <QJsonDocument>
|
||||
#include <QFile>
|
||||
#include <QTimer>
|
||||
#include <QDBusMessage>
|
||||
#include <thread>
|
||||
|
||||
class IndicatorTrayPrivate
|
||||
{
|
||||
public:
|
||||
explicit IndicatorTrayPrivate(IndicatorTray *parent) : q_ptr(parent) {}
|
||||
|
||||
void init();
|
||||
|
||||
void updateContent();
|
||||
|
||||
void initDBus(const QString &indicatorName);
|
||||
|
||||
template<typename Func>
|
||||
void featData(const QString &key,
|
||||
const QJsonObject &data,
|
||||
const char *propertyChangedSlot,
|
||||
Func const &callback)
|
||||
{
|
||||
Q_Q(IndicatorTray);
|
||||
auto dataConfig = data.value(key).toObject();
|
||||
auto dbusService = dataConfig.value("dbus_service").toString();
|
||||
auto dbusPath = dataConfig.value("dbus_path").toString();
|
||||
auto dbusInterface = dataConfig.value("dbus_interface").toString();
|
||||
auto isSystemBus = dataConfig.value("system_dbus").toBool(false);
|
||||
auto bus = isSystemBus ? QDBusConnection::systemBus() : QDBusConnection::sessionBus();
|
||||
|
||||
QDBusInterface interface(dbusService, dbusPath, dbusInterface, bus, q);
|
||||
|
||||
if (dataConfig.contains("dbus_method")) {
|
||||
QString methodName = dataConfig.value("dbus_method").toString();
|
||||
auto ratio = qApp->devicePixelRatio();
|
||||
QDBusReply<QByteArray> reply = interface.call(methodName.toStdString().c_str(), ratio);
|
||||
callback(reply.value());
|
||||
}
|
||||
|
||||
if (dataConfig.contains("dbus_properties")) {
|
||||
auto propertyName = dataConfig.value("dbus_properties").toString();
|
||||
auto propertyNameCStr = propertyName.toStdString();
|
||||
propertyInterfaceNames.insert(key, dbusInterface);
|
||||
propertyNames.insert(key, QString::fromStdString(propertyNameCStr));
|
||||
QDBusConnection::sessionBus().connect(dbusService,
|
||||
dbusPath,
|
||||
"org.freedesktop.DBus.Properties",
|
||||
"PropertiesChanged",
|
||||
"sa{sv}as",
|
||||
q,
|
||||
propertyChangedSlot);
|
||||
|
||||
// FIXME(sbw): hack for qt dbus property changed signal.
|
||||
// see: https://bugreports.qt.io/browse/QTBUG-48008
|
||||
QDBusConnection::sessionBus().connect(dbusService,
|
||||
dbusPath,
|
||||
dbusInterface,
|
||||
QString("%1Changed").arg(propertyName),
|
||||
"s",
|
||||
q,
|
||||
propertyChangedSlot);
|
||||
|
||||
callback(interface.property(propertyNameCStr.c_str()));
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Func>
|
||||
void propertyChanged(const QString &key, const QDBusMessage &msg, Func const &callback)
|
||||
{
|
||||
QList<QVariant> arguments = msg.arguments();
|
||||
if (1 == arguments.count())
|
||||
{
|
||||
const QString &v = msg.arguments().at(0).toString();
|
||||
callback(v);
|
||||
return;
|
||||
} else if (3 != arguments.count()) {
|
||||
qDebug() << "arguments count must be 3";
|
||||
return;
|
||||
}
|
||||
|
||||
QString interfaceName = msg.arguments().at(0).toString();
|
||||
if (interfaceName != propertyInterfaceNames.value(key)) {
|
||||
qDebug() << "interfaceName mismatch" << interfaceName << propertyInterfaceNames.value(key) << key;
|
||||
return;
|
||||
}
|
||||
QVariantMap changedProps = qdbus_cast<QVariantMap>(arguments.at(1).value<QDBusArgument>());
|
||||
if (changedProps.contains(propertyNames.value(key))) {
|
||||
callback(changedProps.value(propertyNames.value(key)));
|
||||
}
|
||||
}
|
||||
|
||||
IndicatorTrayWidget* indicatorTrayWidget = Q_NULLPTR;
|
||||
QString indicatorName;
|
||||
QMap<QString, QString> propertyNames;
|
||||
QMap<QString, QString> propertyInterfaceNames;
|
||||
|
||||
IndicatorTray *q_ptr;
|
||||
Q_DECLARE_PUBLIC(IndicatorTray)
|
||||
};
|
||||
|
||||
void IndicatorTrayPrivate::init()
|
||||
{
|
||||
//Q_Q(IndicatorTray);
|
||||
|
||||
indicatorTrayWidget = new IndicatorTrayWidget(indicatorName);
|
||||
|
||||
initDBus(indicatorName);
|
||||
updateContent();
|
||||
}
|
||||
|
||||
void IndicatorTrayPrivate::updateContent()
|
||||
{
|
||||
indicatorTrayWidget->update();
|
||||
|
||||
Q_EMIT indicatorTrayWidget->iconChanged();
|
||||
}
|
||||
|
||||
void IndicatorTrayPrivate::initDBus(const QString &indicatorName)
|
||||
{
|
||||
Q_Q(IndicatorTray);
|
||||
|
||||
QString filepath = QString("/etc/dde-dock/indicator/%1.json").arg(indicatorName);
|
||||
QFile confFile(filepath);
|
||||
if (!confFile.open(QIODevice::ReadOnly)) {
|
||||
qCritical() << "read indicator config Error";
|
||||
}
|
||||
|
||||
QJsonDocument doc = QJsonDocument::fromJson(confFile.readAll());
|
||||
confFile.close();
|
||||
auto config = doc.object();
|
||||
|
||||
auto delay = config.value("delay").toInt(0);
|
||||
|
||||
qDebug() << "delay load" << delay << indicatorName << q;
|
||||
|
||||
QTimer::singleShot(delay, [ = ]() {
|
||||
auto data = config.value("data").toObject();
|
||||
|
||||
if (data.contains("text")) {
|
||||
featData("text", data, SLOT(textPropertyChanged(QDBusMessage)), [ = ](QVariant v) {
|
||||
if (v.toString().isEmpty()) {
|
||||
Q_EMIT q->removed();
|
||||
return;
|
||||
}
|
||||
else {
|
||||
Q_EMIT q->delayLoaded();
|
||||
}
|
||||
indicatorTrayWidget->setText(v.toString());
|
||||
updateContent();
|
||||
});
|
||||
}
|
||||
|
||||
if (data.contains("icon")) {
|
||||
featData("icon", data, SLOT(iconPropertyChanged(QDBusMessage)), [ = ](QVariant v) {
|
||||
if (v.toByteArray().isEmpty()) {
|
||||
Q_EMIT q->removed();
|
||||
return;
|
||||
}
|
||||
else {
|
||||
Q_EMIT q->delayLoaded();
|
||||
}
|
||||
indicatorTrayWidget->setPixmapData(v.toByteArray());
|
||||
updateContent();
|
||||
});
|
||||
}
|
||||
|
||||
const QJsonObject action = config.value("action").toObject();
|
||||
if (!action.isEmpty() && indicatorTrayWidget)
|
||||
q->connect(indicatorTrayWidget, &IndicatorTrayWidget::clicked, q, [ = ](uint8_t button_index, int x, int y) {
|
||||
std::thread t([=]() -> void {
|
||||
auto triggerConfig = action.value("trigger").toObject();
|
||||
auto dbusService = triggerConfig.value("dbus_service").toString();
|
||||
auto dbusPath = triggerConfig.value("dbus_path").toString();
|
||||
auto dbusInterface = triggerConfig.value("dbus_interface").toString();
|
||||
auto methodName = triggerConfig.value("dbus_method").toString();
|
||||
auto isSystemBus = triggerConfig.value("system_dbus").toBool(false);
|
||||
auto bus = isSystemBus ? QDBusConnection::systemBus() : QDBusConnection::sessionBus();
|
||||
|
||||
QDBusInterface interface(dbusService, dbusPath, dbusInterface, bus);
|
||||
QDBusReply<void> reply = interface.call(methodName, button_index, x, y);
|
||||
if (!reply.isValid()) {
|
||||
qDebug() << interface.call(methodName);
|
||||
}
|
||||
else {
|
||||
qDebug() << reply.error();
|
||||
}
|
||||
});
|
||||
t.detach();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
IndicatorTray::IndicatorTray(const QString &indicatorName, QObject *parent)
|
||||
: QObject(parent)
|
||||
, d_ptr(new IndicatorTrayPrivate(this))
|
||||
{
|
||||
Q_D(IndicatorTray);
|
||||
|
||||
d->indicatorName = indicatorName;
|
||||
d->init();
|
||||
}
|
||||
|
||||
IndicatorTray::~IndicatorTray()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
IndicatorTrayWidget *IndicatorTray::widget()
|
||||
{
|
||||
Q_D(IndicatorTray);
|
||||
|
||||
if (!d->indicatorTrayWidget) {
|
||||
d->init();
|
||||
}
|
||||
|
||||
return d->indicatorTrayWidget;
|
||||
}
|
||||
|
||||
void IndicatorTray::removeWidget()
|
||||
{
|
||||
Q_D(IndicatorTray);
|
||||
|
||||
d->indicatorTrayWidget = nullptr;
|
||||
}
|
||||
|
||||
void IndicatorTray::textPropertyChanged(const QDBusMessage &message)
|
||||
{
|
||||
Q_D(IndicatorTray);
|
||||
|
||||
d->propertyChanged("text", message, [=] (const QVariant &value) {
|
||||
if (value.toString().isEmpty()) {
|
||||
Q_EMIT removed();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!d->indicatorTrayWidget) {
|
||||
d->init();
|
||||
}
|
||||
|
||||
d->indicatorTrayWidget->setText(value.toByteArray());
|
||||
});
|
||||
}
|
||||
|
||||
void IndicatorTray::iconPropertyChanged(const QDBusMessage &message)
|
||||
{
|
||||
Q_D(IndicatorTray);
|
||||
|
||||
d->propertyChanged("icon", message, [=] (const QVariant &value) {
|
||||
if (value.toByteArray().isEmpty()) {
|
||||
Q_EMIT removed();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!d->indicatorTrayWidget) {
|
||||
d->init();
|
||||
}
|
||||
|
||||
d->indicatorTrayWidget->setPixmapData(value.toByteArray());
|
||||
});
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "indicatortraywidget.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QScopedPointer>
|
||||
|
||||
class IndicatorTrayPrivate;
|
||||
class IndicatorTray : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit IndicatorTray(const QString &indicatorName, QObject *parent = nullptr);
|
||||
~IndicatorTray();
|
||||
|
||||
IndicatorTrayWidget *widget();
|
||||
|
||||
void removeWidget();
|
||||
|
||||
signals:
|
||||
void delayLoaded();
|
||||
void removed();
|
||||
|
||||
private slots:
|
||||
void textPropertyChanged(const QDBusMessage &message);
|
||||
void iconPropertyChanged(const QDBusMessage &message);
|
||||
|
||||
private:
|
||||
QScopedPointer<IndicatorTrayPrivate> d_ptr;
|
||||
Q_DECLARE_PRIVATE_D(qGetPtrHelper(d_ptr), IndicatorTray)
|
||||
};
|
@ -1,120 +0,0 @@
|
||||
// Copyright (C) 2011 ~ 2018 Deepin Technology Co., Ltd.
|
||||
// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#include "indicatortraywidget.h"
|
||||
#include "util/utils.h"
|
||||
|
||||
#include <QLabel>
|
||||
#include <QBoxLayout>
|
||||
|
||||
#include <QDBusConnection>
|
||||
#include <QDBusInterface>
|
||||
|
||||
IndicatorTrayWidget::IndicatorTrayWidget(const QString &indicatorName, QWidget *parent, Qt::WindowFlags f)
|
||||
: AbstractTrayWidget(parent, f)
|
||||
, m_indicatorName(indicatorName)
|
||||
, m_gsettings(Utils::ModuleSettingsPtr("keyboard", QByteArray(), this))
|
||||
, m_enableClick(true)
|
||||
{
|
||||
setAttribute(Qt::WA_TranslucentBackground);
|
||||
|
||||
auto layout = new QVBoxLayout(this);
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
m_label = new QLabel(this);
|
||||
|
||||
QPalette p = m_label->palette();
|
||||
p.setColor(QPalette::WindowText, Qt::white);
|
||||
p.setColor(QPalette::Window, Qt::transparent);
|
||||
m_label->setPalette(p);
|
||||
|
||||
m_label->setAttribute(Qt::WA_TranslucentBackground);
|
||||
|
||||
layout->addWidget(m_label, 0, Qt::AlignCenter);
|
||||
setLayout(layout);
|
||||
|
||||
// register dbus
|
||||
auto path = QString("/org/deepin/dde/Dock1/Indicator/") + m_indicatorName;
|
||||
auto interface = QString("org.deepin.dde.Dock1.Indicator.") + m_indicatorName;
|
||||
auto sessionBus = QDBusConnection::sessionBus();
|
||||
sessionBus.registerObject(path,
|
||||
interface,
|
||||
this,
|
||||
QDBusConnection::ExportScriptableSlots);
|
||||
|
||||
if (m_gsettings) {
|
||||
// 显示键盘布局时更新label的状态
|
||||
if (m_gsettings->keys().contains("itemEnable"))
|
||||
enableLabel(m_gsettings->get("itemEnable").toBool());
|
||||
|
||||
connect(m_gsettings, &QGSettings::changed, this, &IndicatorTrayWidget::onGSettingsChanged);
|
||||
}
|
||||
}
|
||||
|
||||
IndicatorTrayWidget::~IndicatorTrayWidget()
|
||||
{
|
||||
}
|
||||
|
||||
QString IndicatorTrayWidget::itemKeyForConfig()
|
||||
{
|
||||
return toIndicatorKey(m_indicatorName);
|
||||
}
|
||||
|
||||
void IndicatorTrayWidget::updateIcon()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void IndicatorTrayWidget::sendClick(uint8_t buttonIndex, int x, int y)
|
||||
{
|
||||
if (m_enableClick)
|
||||
Q_EMIT clicked(buttonIndex, x, y);
|
||||
}
|
||||
|
||||
void IndicatorTrayWidget::enableLabel(bool enable)
|
||||
{
|
||||
QPalette p = m_label->palette();
|
||||
if (!enable) {
|
||||
m_enableClick = false;
|
||||
p.setColor(QPalette::Disabled, QPalette::WindowText, Qt::lightGray);
|
||||
p.setColor(QPalette::Disabled, QPalette::Window, Qt::transparent);
|
||||
m_label->setEnabled(enable);
|
||||
} else {
|
||||
m_enableClick = true;
|
||||
p.setColor(QPalette::Normal, QPalette::BrightText, Qt::white);
|
||||
p.setColor(QPalette::Normal, QPalette::Window, Qt::transparent);
|
||||
m_label->setEnabled(enable);
|
||||
}
|
||||
|
||||
m_label->setPalette(p);
|
||||
m_label->update();
|
||||
}
|
||||
|
||||
void IndicatorTrayWidget::resizeEvent(QResizeEvent *event)
|
||||
{
|
||||
return QWidget::resizeEvent(event);
|
||||
}
|
||||
|
||||
void IndicatorTrayWidget::setPixmapData(const QByteArray &data)
|
||||
{
|
||||
auto rawPixmap = QPixmap::fromImage(QImage::fromData(data));
|
||||
rawPixmap.setDevicePixelRatio(devicePixelRatioF());
|
||||
m_label->setPixmap(rawPixmap);
|
||||
}
|
||||
|
||||
void IndicatorTrayWidget::setText(const QString &text)
|
||||
{
|
||||
m_label->setText(text);
|
||||
}
|
||||
|
||||
void IndicatorTrayWidget::onGSettingsChanged(const QString &key)
|
||||
{
|
||||
Q_UNUSED(key);
|
||||
|
||||
if (m_gsettings && m_gsettings->keys().contains("itemEnable")) {
|
||||
const bool itemEnable = m_gsettings->get("itemEnable").toBool();
|
||||
enableLabel(itemEnable);
|
||||
}
|
||||
}
|
||||
|
@ -1,49 +0,0 @@
|
||||
// Copyright (C) 2011 ~ 2018 Deepin Technology Co., Ltd.
|
||||
// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QScopedPointer>
|
||||
#include <QLabel>
|
||||
|
||||
#include "abstracttraywidget.h"
|
||||
|
||||
class QGSettings;
|
||||
|
||||
class IndicatorTrayWidget: public AbstractTrayWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit IndicatorTrayWidget(const QString &indicatorName, QWidget *parent = Q_NULLPTR, Qt::WindowFlags f = Qt::WindowFlags());
|
||||
~IndicatorTrayWidget();
|
||||
|
||||
QString itemKeyForConfig() override;
|
||||
void updateIcon() override;
|
||||
void sendClick(uint8_t, int, int) override;
|
||||
void enableLabel(bool enable);
|
||||
static QString toIndicatorKey(const QString &indicatorName) { return QString("indicator:%1").arg(indicatorName); }
|
||||
static bool isIndicatorKey(const QString &itemKey) { return itemKey.startsWith("indicator:"); }
|
||||
|
||||
protected:
|
||||
void resizeEvent(QResizeEvent *event) override;
|
||||
|
||||
public Q_SLOTS:
|
||||
Q_SCRIPTABLE void setPixmapData(const QByteArray &data);
|
||||
Q_SCRIPTABLE void setText(const QString &text);
|
||||
|
||||
private slots:
|
||||
void onGSettingsChanged(const QString &key);
|
||||
|
||||
Q_SIGNALS:
|
||||
void clicked(uint8_t, int, int);
|
||||
|
||||
private:
|
||||
QLabel *m_label;
|
||||
|
||||
QString m_indicatorName;
|
||||
const QGSettings *m_gsettings;
|
||||
bool m_enableClick; // 置灰时设置为false,不触发click信号
|
||||
};
|
||||
|
@ -1,3 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20">
|
||||
<polygon fill-rule="evenodd" points="6.659 10.73 5.952 11.437 .563 6.048 5.952 .659 6.659 1.366 1.977 6.048" transform="rotate(-90 9 5)"/>
|
||||
</svg>
|
Before Width: | Height: | Size: 232 B |
@ -1,3 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20">
|
||||
<polygon fill="#FFF" fill-rule="evenodd" points="6.659 10.73 5.952 11.437 .563 6.048 5.952 .659 6.659 1.366 1.977 6.048" transform="rotate(-90 9 5)"/>
|
||||
</svg>
|
Before Width: | Height: | Size: 244 B |
@ -1,3 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20">
|
||||
<polygon fill-rule="evenodd" points="6.596 10.671 5.889 11.378 .5 5.989 5.889 .6 6.596 1.307 1.914 5.989" transform="translate(6 4)"/>
|
||||
</svg>
|
Before Width: | Height: | Size: 228 B |
@ -1,3 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20">
|
||||
<polygon fill="#FFF" fill-rule="evenodd" points="6.596 10.671 5.889 11.378 .5 5.989 5.889 .6 6.596 1.307 1.914 5.989" transform="translate(6 4)"/>
|
||||
</svg>
|
Before Width: | Height: | Size: 240 B |
@ -1,3 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20">
|
||||
<polygon fill-rule="evenodd" points="6.5 10.693 5.793 11.4 .404 6.011 5.793 .622 6.5 1.329 1.818 6.011" transform="matrix(-1 0 0 1 14 3.978)"/>
|
||||
</svg>
|
Before Width: | Height: | Size: 237 B |
@ -1,3 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20">
|
||||
<polygon fill="#FFF" fill-rule="evenodd" points="6.5 10.693 5.793 11.4 .404 6.011 5.793 .622 6.5 1.329 1.818 6.011" transform="matrix(-1 0 0 1 14 3.978)"/>
|
||||
</svg>
|
Before Width: | Height: | Size: 249 B |
@ -1,3 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20">
|
||||
<polygon fill-rule="evenodd" points="6.437 10.73 5.73 11.437 .341 6.048 5.73 .659 6.437 1.366 1.755 6.048" transform="matrix(0 1 1 0 4 6)"/>
|
||||
</svg>
|
Before Width: | Height: | Size: 234 B |
@ -1,3 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20">
|
||||
<polygon fill="#FFF" fill-rule="evenodd" points="6.437 10.73 5.73 11.437 .341 6.048 5.73 .659 6.437 1.366 1.755 6.048" transform="matrix(0 1 1 0 4 6)"/>
|
||||
</svg>
|
Before Width: | Height: | Size: 246 B |
@ -1,766 +0,0 @@
|
||||
// Copyright (C) 2011 ~ 2018 Deepin Technology Co., Ltd.
|
||||
// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#include "snitraywidget.h"
|
||||
#include "util/themeappicon.h"
|
||||
#include "util/utils.h"
|
||||
#include "../../widgets/tipswidget.h"
|
||||
|
||||
#include <dbusmenu-qt5/dbusmenuimporter.h>
|
||||
|
||||
#include <DGuiApplicationHelper>
|
||||
|
||||
#include <QPainter>
|
||||
#include <QApplication>
|
||||
#include <QDBusPendingCall>
|
||||
#include <QtConcurrent>
|
||||
#include <QFuture>
|
||||
|
||||
#include <xcb/xproto.h>
|
||||
|
||||
DGUI_USE_NAMESPACE
|
||||
|
||||
#define IconSize 20
|
||||
|
||||
const QStringList ItemCategoryList {"ApplicationStatus", "Communications", "SystemServices", "Hardware"};
|
||||
const QStringList ItemStatusList {"Passive", "Active", "NeedsAttention"};
|
||||
QPointer<DockPopupWindow> SNITrayWidget::PopupWindow = nullptr;
|
||||
Dock::Position SNITrayWidget::DockPosition = Dock::Position::Top;
|
||||
using namespace Dock;
|
||||
SNITrayWidget::SNITrayWidget(const QString &sniServicePath, QWidget *parent)
|
||||
: AbstractTrayWidget(parent),
|
||||
m_dbusMenuImporter(nullptr),
|
||||
m_menu(nullptr),
|
||||
m_updateIconTimer(new QTimer(this))
|
||||
, m_updateOverlayIconTimer(new QTimer(this))
|
||||
, m_updateAttentionIconTimer(new QTimer(this))
|
||||
, m_sniServicePath(sniServicePath)
|
||||
, m_popupTipsDelayTimer(new QTimer(this))
|
||||
, m_handleMouseReleaseTimer(new QTimer(this))
|
||||
, m_tipsLabel(new TipsWidget(this))
|
||||
{
|
||||
m_popupTipsDelayTimer->setInterval(500);
|
||||
m_popupTipsDelayTimer->setSingleShot(true);
|
||||
m_handleMouseReleaseTimer->setSingleShot(true);
|
||||
m_handleMouseReleaseTimer->setInterval(100);
|
||||
|
||||
connect(m_handleMouseReleaseTimer, &QTimer::timeout, this, &SNITrayWidget::handleMouseRelease);
|
||||
connect(m_popupTipsDelayTimer, &QTimer::timeout, this, &SNITrayWidget::showHoverTips);
|
||||
|
||||
if (PopupWindow.isNull()) {
|
||||
DockPopupWindow *arrowRectangle = new DockPopupWindow(nullptr);
|
||||
arrowRectangle->setShadowBlurRadius(20);
|
||||
arrowRectangle->setRadius(6);
|
||||
arrowRectangle->setShadowYOffset(2);
|
||||
arrowRectangle->setShadowXOffset(0);
|
||||
arrowRectangle->setArrowWidth(18);
|
||||
arrowRectangle->setArrowHeight(10);
|
||||
arrowRectangle->setObjectName("snitraypopup");
|
||||
if (Utils::IS_WAYLAND_DISPLAY) {
|
||||
Qt::WindowFlags flags = arrowRectangle->windowFlags() | Qt::FramelessWindowHint;
|
||||
arrowRectangle->setWindowFlags(flags);
|
||||
}
|
||||
PopupWindow = arrowRectangle;
|
||||
connect(qApp, &QApplication::aboutToQuit, PopupWindow, &DockPopupWindow::deleteLater);
|
||||
}
|
||||
|
||||
if (m_sniServicePath.startsWith("/") || !m_sniServicePath.contains("/")) {
|
||||
qDebug() << "SNI service path invalid";
|
||||
return;
|
||||
}
|
||||
|
||||
QPair<QString, QString> pair = serviceAndPath(m_sniServicePath);
|
||||
m_dbusService = pair.first;
|
||||
m_dbusPath = pair.second;
|
||||
|
||||
QDBusConnection conn = QDBusConnection::sessionBus();
|
||||
setOwnerPID(conn.interface()->servicePid(m_dbusService));
|
||||
|
||||
m_sniInter = new StatusNotifierItem(m_dbusService, m_dbusPath, QDBusConnection::sessionBus(), this);
|
||||
m_sniInter->setSync(false);
|
||||
if (!m_sniInter->isValid()) {
|
||||
qDebug() << "SNI dbus interface is invalid!" << m_dbusService << m_dbusPath << m_sniInter->lastError();
|
||||
return;
|
||||
}
|
||||
|
||||
m_updateIconTimer->setInterval(100);
|
||||
m_updateIconTimer->setSingleShot(true);
|
||||
m_updateOverlayIconTimer->setInterval(500);
|
||||
m_updateOverlayIconTimer->setSingleShot(true);
|
||||
m_updateAttentionIconTimer->setInterval(1000);
|
||||
m_updateAttentionIconTimer->setSingleShot(true);
|
||||
|
||||
connect(DGuiApplicationHelper::instance(), &DGuiApplicationHelper::themeTypeChanged, this, &SNITrayWidget::refreshIcon);
|
||||
connect(m_updateIconTimer, &QTimer::timeout, this, &SNITrayWidget::refreshIcon);
|
||||
connect(m_updateOverlayIconTimer, &QTimer::timeout, this, &SNITrayWidget::refreshOverlayIcon);
|
||||
connect(m_updateAttentionIconTimer, &QTimer::timeout, this, &SNITrayWidget::refreshAttentionIcon);
|
||||
|
||||
// SNI property change
|
||||
// thses signals of properties may not be emit automatically!!
|
||||
// since the SniInter in on async mode we can not call property's getter function to obtain property directly
|
||||
// the way to refresh properties(emit the following signals) is call property's getter function and wait these signals
|
||||
connect(m_sniInter, &StatusNotifierItem::AttentionIconNameChanged, this, &SNITrayWidget::onSNIAttentionIconNameChanged);
|
||||
connect(m_sniInter, &StatusNotifierItem::AttentionIconPixmapChanged, this, &SNITrayWidget::onSNIAttentionIconPixmapChanged);
|
||||
connect(m_sniInter, &StatusNotifierItem::AttentionMovieNameChanged, this, &SNITrayWidget::onSNIAttentionMovieNameChanged);
|
||||
connect(m_sniInter, &StatusNotifierItem::CategoryChanged, this, &SNITrayWidget::onSNICategoryChanged);
|
||||
connect(m_sniInter, &StatusNotifierItem::IconNameChanged, this, &SNITrayWidget::onSNIIconNameChanged);
|
||||
connect(m_sniInter, &StatusNotifierItem::IconPixmapChanged, this, &SNITrayWidget::onSNIIconPixmapChanged);
|
||||
connect(m_sniInter, &StatusNotifierItem::IconThemePathChanged, this, &SNITrayWidget::onSNIIconThemePathChanged);
|
||||
connect(m_sniInter, &StatusNotifierItem::IdChanged, this, &SNITrayWidget::onSNIIdChanged);
|
||||
connect(m_sniInter, &StatusNotifierItem::MenuChanged, this, &SNITrayWidget::onSNIMenuChanged);
|
||||
connect(m_sniInter, &StatusNotifierItem::OverlayIconNameChanged, this, &SNITrayWidget::onSNIOverlayIconNameChanged);
|
||||
connect(m_sniInter, &StatusNotifierItem::OverlayIconPixmapChanged, this, &SNITrayWidget::onSNIOverlayIconPixmapChanged);
|
||||
connect(m_sniInter, &StatusNotifierItem::StatusChanged, this, &SNITrayWidget::onSNIStatusChanged);
|
||||
|
||||
// the following signals can be emit automatically
|
||||
// need refresh cached properties in these slots
|
||||
connect(m_sniInter, &StatusNotifierItem::NewIcon, [ = ] {
|
||||
m_sniIconName = m_sniInter->iconName();
|
||||
m_sniIconPixmap = m_sniInter->iconPixmap();
|
||||
m_sniIconThemePath = m_sniInter->iconThemePath();
|
||||
|
||||
m_updateIconTimer->start();
|
||||
});
|
||||
connect(m_sniInter, &StatusNotifierItem::NewOverlayIcon, [ = ] {
|
||||
m_sniOverlayIconName = m_sniInter->overlayIconName();
|
||||
m_sniOverlayIconPixmap = m_sniInter->overlayIconPixmap();
|
||||
m_sniIconThemePath = m_sniInter->iconThemePath();
|
||||
|
||||
m_updateOverlayIconTimer->start();
|
||||
});
|
||||
connect(m_sniInter, &StatusNotifierItem::NewAttentionIcon, [ = ] {
|
||||
m_sniAttentionIconName = m_sniInter->attentionIconName();
|
||||
m_sniAttentionIconPixmap = m_sniInter->attentionIconPixmap();
|
||||
m_sniIconThemePath = m_sniInter->iconThemePath();
|
||||
|
||||
m_updateAttentionIconTimer->start();
|
||||
});
|
||||
connect(m_sniInter, &StatusNotifierItem::NewStatus, [ = ] {
|
||||
onSNIStatusChanged(m_sniInter->status());
|
||||
});
|
||||
|
||||
initSNIPropertys();
|
||||
}
|
||||
|
||||
QString SNITrayWidget::itemKeyForConfig()
|
||||
{
|
||||
return QString("sni:%1").arg(m_sniId.isEmpty() ? m_sniServicePath : m_sniId);
|
||||
}
|
||||
|
||||
void SNITrayWidget::updateIcon()
|
||||
{
|
||||
m_updateIconTimer->start();
|
||||
}
|
||||
|
||||
void SNITrayWidget::sendClick(uint8_t mouseButton, int x, int y)
|
||||
{
|
||||
switch (mouseButton) {
|
||||
case XCB_BUTTON_INDEX_1: {
|
||||
QFuture<void> future = QtConcurrent::run([ = ] {
|
||||
StatusNotifierItem inter(m_dbusService, m_dbusPath, QDBusConnection::sessionBus());
|
||||
QDBusPendingReply<> reply = inter.Activate(x, y);
|
||||
// try to invoke context menu while calling activate get a error.
|
||||
// primarily work for apps using libappindicator.
|
||||
reply.waitForFinished();
|
||||
if (reply.isError()) {
|
||||
showContextMenu(x,y);
|
||||
}
|
||||
});
|
||||
}
|
||||
break;
|
||||
case XCB_BUTTON_INDEX_2:
|
||||
m_sniInter->SecondaryActivate(x, y);
|
||||
break;
|
||||
case XCB_BUTTON_INDEX_3:
|
||||
showContextMenu(x, y);
|
||||
break;
|
||||
default:
|
||||
qDebug() << "unknown mouse button key";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool SNITrayWidget::isValid()
|
||||
{
|
||||
return m_sniInter->isValid();
|
||||
}
|
||||
|
||||
SNITrayWidget::ItemStatus SNITrayWidget::status()
|
||||
{
|
||||
if (!ItemStatusList.contains(m_sniStatus)) {
|
||||
m_sniStatus = "Active";
|
||||
return ItemStatus::Active;
|
||||
}
|
||||
|
||||
return static_cast<ItemStatus>(ItemStatusList.indexOf(m_sniStatus));
|
||||
}
|
||||
|
||||
SNITrayWidget::ItemCategory SNITrayWidget::category()
|
||||
{
|
||||
if (!ItemCategoryList.contains(m_sniCategory)) {
|
||||
return UnknownCategory;
|
||||
}
|
||||
|
||||
return static_cast<ItemCategory>(ItemCategoryList.indexOf(m_sniCategory));
|
||||
}
|
||||
|
||||
QString SNITrayWidget::toSNIKey(const QString &sniServicePath)
|
||||
{
|
||||
return QString("sni:%1").arg(sniServicePath);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
uint SNITrayWidget::servicePID(const QString &servicePath)
|
||||
{
|
||||
QString serviceName = serviceAndPath(servicePath).first;
|
||||
QDBusConnection conn = QDBusConnection::sessionBus();
|
||||
return conn.interface()->servicePid(serviceName);
|
||||
}
|
||||
|
||||
void SNITrayWidget::initSNIPropertys()
|
||||
{
|
||||
m_sniAttentionIconName = m_sniInter->attentionIconName();
|
||||
m_sniAttentionIconPixmap = m_sniInter->attentionIconPixmap();
|
||||
m_sniAttentionMovieName = m_sniInter->attentionMovieName();
|
||||
m_sniCategory = m_sniInter->category();
|
||||
m_sniIconName = m_sniInter->iconName();
|
||||
m_sniIconPixmap = m_sniInter->iconPixmap();
|
||||
m_sniIconThemePath = m_sniInter->iconThemePath();
|
||||
m_sniMenuPath = m_sniInter->menu();
|
||||
m_sniOverlayIconName = m_sniInter->overlayIconName();
|
||||
m_sniOverlayIconPixmap = m_sniInter->overlayIconPixmap();
|
||||
m_sniStatus = m_sniInter->status();
|
||||
|
||||
// 使用同步的方式获取id,否则在插入的时候无法获取正确的位置
|
||||
m_sniInter->setSync(true);
|
||||
m_sniId = m_sniInter->id();
|
||||
m_sniInter->setSync(false);
|
||||
|
||||
m_updateIconTimer->start();
|
||||
// m_updateOverlayIconTimer->start();
|
||||
// m_updateAttentionIconTimer->start();
|
||||
}
|
||||
|
||||
void SNITrayWidget::initMenu()
|
||||
{
|
||||
const QString &sniMenuPath = m_sniMenuPath.path();
|
||||
if (sniMenuPath.isEmpty()) {
|
||||
qDebug() << "Error: current sni menu path is empty of dbus service:" << m_dbusService << "id:" << m_sniId;
|
||||
return;
|
||||
}
|
||||
|
||||
qDebug() << "using sni service path:" << m_dbusService << "menu path:" << sniMenuPath;
|
||||
|
||||
m_dbusMenuImporter = new DBusMenuImporter(m_dbusService, sniMenuPath, ASYNCHRONOUS, this);
|
||||
|
||||
qDebug() << "generate the sni menu object";
|
||||
|
||||
m_menu = m_dbusMenuImporter->menu();
|
||||
|
||||
qDebug() << "the sni menu obect is:" << m_menu;
|
||||
}
|
||||
|
||||
void SNITrayWidget::refreshIcon()
|
||||
{
|
||||
QPixmap pix = newIconPixmap(Icon);
|
||||
if (pix.isNull()) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_pixmap = pix;
|
||||
update();
|
||||
Q_EMIT iconChanged();
|
||||
|
||||
if (!isVisible()) {
|
||||
Q_EMIT needAttention();
|
||||
}
|
||||
}
|
||||
|
||||
void SNITrayWidget::refreshOverlayIcon()
|
||||
{
|
||||
QPixmap pix = newIconPixmap(OverlayIcon);
|
||||
if (pix.isNull()) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_overlayPixmap = pix;
|
||||
update();
|
||||
Q_EMIT iconChanged();
|
||||
|
||||
if (!isVisible()) {
|
||||
Q_EMIT needAttention();
|
||||
}
|
||||
}
|
||||
|
||||
void SNITrayWidget::refreshAttentionIcon()
|
||||
{
|
||||
/* TODO: A new approach may be needed to deal with attentionIcon */
|
||||
QPixmap pix = newIconPixmap(AttentionIcon);
|
||||
if (pix.isNull()) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_pixmap = pix;
|
||||
update();
|
||||
Q_EMIT iconChanged();
|
||||
|
||||
if (!isVisible()) {
|
||||
Q_EMIT needAttention();
|
||||
}
|
||||
}
|
||||
|
||||
void SNITrayWidget::showContextMenu(int x, int y)
|
||||
{
|
||||
// 这里的PopupWindow属性是置顶的,如果不隐藏,会导致菜单显示不出来
|
||||
hidePopup();
|
||||
|
||||
// ContextMenu does not work
|
||||
if (m_sniMenuPath.path().startsWith("/NO_DBUSMENU")) {
|
||||
m_sniInter->ContextMenu(x, y);
|
||||
} else {
|
||||
if (!m_menu) {
|
||||
qDebug() << "context menu has not be ready, init menu";
|
||||
initMenu();
|
||||
}
|
||||
|
||||
if (m_menu)
|
||||
m_menu->popup(QPoint(x, y));
|
||||
}
|
||||
}
|
||||
|
||||
void SNITrayWidget::onSNIAttentionIconNameChanged(const QString &value)
|
||||
{
|
||||
m_sniAttentionIconName = value;
|
||||
|
||||
m_updateAttentionIconTimer->start();
|
||||
}
|
||||
|
||||
void SNITrayWidget::onSNIAttentionIconPixmapChanged(DBusImageList value)
|
||||
{
|
||||
m_sniAttentionIconPixmap = value;
|
||||
|
||||
m_updateAttentionIconTimer->start();
|
||||
}
|
||||
|
||||
void SNITrayWidget::onSNIAttentionMovieNameChanged(const QString &value)
|
||||
{
|
||||
m_sniAttentionMovieName = value;
|
||||
|
||||
m_updateAttentionIconTimer->start();
|
||||
}
|
||||
|
||||
void SNITrayWidget::onSNICategoryChanged(const QString &value)
|
||||
{
|
||||
m_sniCategory = value;
|
||||
}
|
||||
|
||||
void SNITrayWidget::onSNIIconNameChanged(const QString &value)
|
||||
{
|
||||
m_sniIconName = value;
|
||||
|
||||
m_updateIconTimer->start();
|
||||
}
|
||||
|
||||
void SNITrayWidget::onSNIIconPixmapChanged(DBusImageList value)
|
||||
{
|
||||
m_sniIconPixmap = value;
|
||||
|
||||
m_updateIconTimer->start();
|
||||
}
|
||||
|
||||
void SNITrayWidget::onSNIIconThemePathChanged(const QString &value)
|
||||
{
|
||||
m_sniIconThemePath = value;
|
||||
|
||||
m_updateIconTimer->start();
|
||||
}
|
||||
|
||||
void SNITrayWidget::onSNIIdChanged(const QString &value)
|
||||
{
|
||||
m_sniId = value;
|
||||
}
|
||||
|
||||
void SNITrayWidget::onSNIMenuChanged(const QDBusObjectPath &value)
|
||||
{
|
||||
m_sniMenuPath = value;
|
||||
}
|
||||
|
||||
void SNITrayWidget::onSNIOverlayIconNameChanged(const QString &value)
|
||||
{
|
||||
m_sniOverlayIconName = value;
|
||||
|
||||
m_updateOverlayIconTimer->start();
|
||||
}
|
||||
|
||||
void SNITrayWidget::onSNIOverlayIconPixmapChanged(DBusImageList value)
|
||||
{
|
||||
m_sniOverlayIconPixmap = value;
|
||||
|
||||
m_updateOverlayIconTimer->start();
|
||||
}
|
||||
|
||||
void SNITrayWidget::onSNIStatusChanged(const QString &status)
|
||||
{
|
||||
if (!ItemStatusList.contains(status) || m_sniStatus == status) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_sniStatus = status;
|
||||
|
||||
Q_EMIT statusChanged(static_cast<SNITrayWidget::ItemStatus>(ItemStatusList.indexOf(status)));
|
||||
}
|
||||
|
||||
void SNITrayWidget::paintEvent(QPaintEvent *e)
|
||||
{
|
||||
Q_UNUSED(e);
|
||||
if (m_pixmap.isNull())
|
||||
return;
|
||||
|
||||
QPainter painter;
|
||||
painter.begin(this);
|
||||
painter.setRenderHint(QPainter::Antialiasing);
|
||||
|
||||
const QRectF &rf = QRect(rect());
|
||||
const QRectF &rfp = QRect(m_pixmap.rect());
|
||||
const QPointF &p = rf.center() - rfp.center() / m_pixmap.devicePixelRatioF();
|
||||
painter.drawPixmap(p, m_pixmap);
|
||||
|
||||
if (!m_overlayPixmap.isNull()) {
|
||||
painter.drawPixmap(p, m_overlayPixmap);
|
||||
}
|
||||
|
||||
painter.end();
|
||||
}
|
||||
|
||||
QPixmap SNITrayWidget::newIconPixmap(IconType iconType)
|
||||
{
|
||||
QPixmap pixmap;
|
||||
if (iconType == UnknownIconType) {
|
||||
return pixmap;
|
||||
}
|
||||
|
||||
QString iconName;
|
||||
DBusImageList dbusImageList;
|
||||
|
||||
QString iconThemePath = m_sniIconThemePath;
|
||||
|
||||
switch (iconType) {
|
||||
case Icon:
|
||||
iconName = m_sniIconName;
|
||||
dbusImageList = m_sniIconPixmap;
|
||||
break;
|
||||
case OverlayIcon:
|
||||
iconName = m_sniOverlayIconName;
|
||||
dbusImageList = m_sniOverlayIconPixmap;
|
||||
break;
|
||||
case AttentionIcon:
|
||||
iconName = m_sniAttentionIconName;
|
||||
dbusImageList = m_sniAttentionIconPixmap;
|
||||
break;
|
||||
case AttentionMovieIcon:
|
||||
iconName = m_sniAttentionMovieName;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
const auto ratio = devicePixelRatioF();
|
||||
const int iconSizeScaled = IconSize * ratio;
|
||||
do {
|
||||
// load icon from sni dbus
|
||||
if (!dbusImageList.isEmpty() && !dbusImageList.first().pixels.isEmpty()) {
|
||||
for (DBusImage dbusImage : dbusImageList) {
|
||||
char *image_data = dbusImage.pixels.data();
|
||||
|
||||
if (QSysInfo::ByteOrder == QSysInfo::LittleEndian) {
|
||||
for (int i = 0; i < dbusImage.pixels.size(); i += 4) {
|
||||
*(qint32 *)(image_data + i) = qFromBigEndian(*(qint32 *)(image_data + i));
|
||||
}
|
||||
}
|
||||
|
||||
QImage image((const uchar *)dbusImage.pixels.constData(), dbusImage.width, dbusImage.height, QImage::Format_ARGB32);
|
||||
pixmap = QPixmap::fromImage(image.scaled(iconSizeScaled, iconSizeScaled, Qt::KeepAspectRatio, Qt::SmoothTransformation));
|
||||
pixmap.setDevicePixelRatio(ratio);
|
||||
if (!pixmap.isNull()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// load icon from specified file
|
||||
if (!iconThemePath.isEmpty() && !iconName.isEmpty()) {
|
||||
QDirIterator it(iconThemePath, QDirIterator::Subdirectories);
|
||||
while (it.hasNext()) {
|
||||
it.next();
|
||||
if (it.fileName().startsWith(iconName, Qt::CaseInsensitive)) {
|
||||
QImage image(it.filePath());
|
||||
pixmap = QPixmap::fromImage(image.scaled(iconSizeScaled, iconSizeScaled, Qt::KeepAspectRatio, Qt::SmoothTransformation));
|
||||
pixmap.setDevicePixelRatio(ratio);
|
||||
if (!pixmap.isNull()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!pixmap.isNull()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// load icon from theme
|
||||
// Note: this will ensure return a None-Null pixmap
|
||||
// so, it should be the last fallback
|
||||
if (!iconName.isEmpty()) {
|
||||
// ThemeAppIcon::getIcon 会处理高分屏缩放问题
|
||||
ThemeAppIcon::getIcon(pixmap, iconName, IconSize);
|
||||
if (!pixmap.isNull()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (pixmap.isNull()) {
|
||||
qDebug() << "get icon faild!" << iconType;
|
||||
}
|
||||
} while (false);
|
||||
|
||||
return pixmap;
|
||||
}
|
||||
|
||||
void SNITrayWidget::enterEvent(QEvent *event)
|
||||
{
|
||||
// 触屏不显示hover效果
|
||||
if (!qApp->property(IS_TOUCH_STATE).toBool()) {
|
||||
m_popupTipsDelayTimer->start();
|
||||
}
|
||||
|
||||
AbstractTrayWidget::enterEvent(event);
|
||||
}
|
||||
|
||||
void SNITrayWidget::leaveEvent(QEvent *event)
|
||||
{
|
||||
m_popupTipsDelayTimer->stop();
|
||||
if (m_popupShown && !PopupWindow->model())
|
||||
hidePopup();
|
||||
|
||||
update();
|
||||
|
||||
AbstractTrayWidget::leaveEvent(event);
|
||||
}
|
||||
|
||||
void SNITrayWidget::mousePressEvent(QMouseEvent *event)
|
||||
{
|
||||
// call QWidget::mousePressEvent means to show dock-context-menu
|
||||
// when right button of mouse is pressed immediately in fashion mode
|
||||
|
||||
// here we hide the right button press event when it is click in the special area
|
||||
m_popupTipsDelayTimer->stop();
|
||||
if (event->button() == Qt::RightButton && perfectIconRect().contains(event->pos(), true)) {
|
||||
event->accept();
|
||||
setMouseData(event);
|
||||
return;
|
||||
}
|
||||
|
||||
QWidget::mousePressEvent(event);
|
||||
}
|
||||
|
||||
void SNITrayWidget::mouseReleaseEvent(QMouseEvent *e)
|
||||
{
|
||||
//e->accept();
|
||||
|
||||
// 由于 XWindowTrayWidget 中对 发送鼠标事件到X窗口的函数, 如 sendClick/sendHoverEvent 中
|
||||
// 使用了 setX11PassMouseEvent, 而每次调用 setX11PassMouseEvent 时都会导致产生 mousePress 和 mouseRelease 事件
|
||||
// 因此如果直接在这里处理事件会导致一些问题, 所以使用 Timer 来延迟处理 100 毫秒内的最后一个事件
|
||||
setMouseData(e);
|
||||
|
||||
QWidget::mouseReleaseEvent(e);
|
||||
}
|
||||
|
||||
void SNITrayWidget::handleMouseRelease()
|
||||
{
|
||||
Q_ASSERT(sender() == m_handleMouseReleaseTimer);
|
||||
|
||||
// do not dealwith all mouse event of SystemTray, class SystemTrayItem will handle it
|
||||
if (trayTyep() == SystemTray)
|
||||
return;
|
||||
|
||||
const QPoint point(m_lastMouseReleaseData.first - rect().center());
|
||||
if (point.manhattanLength() > 24)
|
||||
return;
|
||||
|
||||
QPoint globalPos = QCursor::pos();
|
||||
uint8_t buttonIndex = XCB_BUTTON_INDEX_1;
|
||||
|
||||
switch (m_lastMouseReleaseData.second) {
|
||||
case Qt:: MiddleButton:
|
||||
buttonIndex = XCB_BUTTON_INDEX_2;
|
||||
break;
|
||||
case Qt::RightButton:
|
||||
buttonIndex = XCB_BUTTON_INDEX_3;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
sendClick(buttonIndex, globalPos.x(), globalPos.y());
|
||||
|
||||
// left mouse button clicked
|
||||
if (buttonIndex == XCB_BUTTON_INDEX_1) {
|
||||
Q_EMIT clicked();
|
||||
}
|
||||
}
|
||||
|
||||
void SNITrayWidget::showHoverTips()
|
||||
{
|
||||
if (PopupWindow->model())
|
||||
return;
|
||||
|
||||
// if not in geometry area
|
||||
const QRect r(topleftPoint(), size());
|
||||
if (!r.contains(QCursor::pos()))
|
||||
return;
|
||||
|
||||
QProcess p;
|
||||
p.start("qdbus", {m_dbusService});
|
||||
if (!p.waitForFinished(1000)) {
|
||||
qDebug() << "sni dbus service error : " << m_dbusService;
|
||||
return;
|
||||
}
|
||||
|
||||
QDBusInterface infc(m_dbusService, m_dbusPath);
|
||||
QDBusMessage msg = infc.call("Get", "org.kde.StatusNotifierItem", "ToolTip");
|
||||
if (msg.type() == QDBusMessage::ReplyMessage) {
|
||||
QDBusArgument arg = msg.arguments().at(0).value<QDBusVariant>().variant().value<QDBusArgument>();
|
||||
DBusToolTip tooltip = qdbus_cast<DBusToolTip>(arg);
|
||||
|
||||
if (tooltip.title.isEmpty())
|
||||
return;
|
||||
|
||||
// 当提示信息中有换行符时,需要使用setTextList
|
||||
if (tooltip.title.contains('\n'))
|
||||
m_tipsLabel->setTextList(tooltip.title.split('\n'));
|
||||
else
|
||||
m_tipsLabel->setText(tooltip.title);
|
||||
|
||||
m_tipsLabel->setAccessibleName(itemKeyForConfig().replace("sni:",""));
|
||||
|
||||
showPopupWindow(m_tipsLabel);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void SNITrayWidget::hideNonModel()
|
||||
{
|
||||
// auto hide if popup is not model window
|
||||
if (m_popupShown && !PopupWindow->model())
|
||||
hidePopup();
|
||||
}
|
||||
|
||||
void SNITrayWidget::popupWindowAccept()
|
||||
{
|
||||
if (!PopupWindow->isVisible())
|
||||
return;
|
||||
|
||||
hidePopup();
|
||||
}
|
||||
|
||||
void SNITrayWidget::hidePopup()
|
||||
{
|
||||
m_popupTipsDelayTimer->stop();
|
||||
m_popupShown = false;
|
||||
PopupWindow->hide();
|
||||
|
||||
emit PopupWindow->accept();
|
||||
emit requestWindowAutoHide(true);
|
||||
}
|
||||
// 获取在最外层的窗口(MainWindow)中的位置
|
||||
const QPoint SNITrayWidget::topleftPoint() const
|
||||
{
|
||||
QPoint p;
|
||||
const QWidget *w = this;
|
||||
do {
|
||||
p += w->pos();
|
||||
w = qobject_cast<QWidget *>(w->parent());
|
||||
} while (w);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
const QPoint SNITrayWidget::popupMarkPoint() const
|
||||
{
|
||||
QPoint p(topleftPoint());
|
||||
|
||||
const QRect r = rect();
|
||||
const QRect wr = window()->rect();
|
||||
|
||||
switch (DockPosition) {
|
||||
case Dock::Position::Top:
|
||||
p += QPoint(r.width() / 2, r.height() + (wr.height() - r.height()) / 2);
|
||||
break;
|
||||
case Dock::Position::Bottom:
|
||||
p += QPoint(r.width() / 2, 0 - (wr.height() - r.height()) / 2);
|
||||
break;
|
||||
case Dock::Position::Left:
|
||||
p += QPoint(r.width() + (wr.width() - r.width()) / 2, r.height() / 2);
|
||||
break;
|
||||
case Dock::Position::Right:
|
||||
p += QPoint(0 - (wr.width() - r.width()) / 2, r.height() / 2);
|
||||
break;
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
void SNITrayWidget::showPopupWindow(QWidget *const content, const bool model)
|
||||
{
|
||||
m_popupShown = true;
|
||||
|
||||
if (model)
|
||||
emit requestWindowAutoHide(false);
|
||||
|
||||
DockPopupWindow *popup = PopupWindow.data();
|
||||
QWidget *lastContent = popup->getContent();
|
||||
if (lastContent)
|
||||
lastContent->setVisible(false);
|
||||
|
||||
switch (DockPosition) {
|
||||
case Dock::Position::Top: popup->setArrowDirection(DockPopupWindow::ArrowTop); break;
|
||||
case Dock::Position::Bottom: popup->setArrowDirection(DockPopupWindow::ArrowBottom); break;
|
||||
case Dock::Position::Left: popup->setArrowDirection(DockPopupWindow::ArrowLeft); break;
|
||||
case Dock::Position::Right: popup->setArrowDirection(DockPopupWindow::ArrowRight); break;
|
||||
}
|
||||
popup->resize(content->sizeHint());
|
||||
popup->setContent(content);
|
||||
|
||||
QPoint p = popupMarkPoint();
|
||||
if (!popup->isVisible())
|
||||
QMetaObject::invokeMethod(popup, "show", Qt::QueuedConnection, Q_ARG(QPoint, p), Q_ARG(bool, model));
|
||||
else
|
||||
popup->show(p, model);
|
||||
}
|
||||
|
||||
void SNITrayWidget::setMouseData(QMouseEvent *e)
|
||||
{
|
||||
m_lastMouseReleaseData.first = e->pos();
|
||||
m_lastMouseReleaseData.second = e->button();
|
||||
|
||||
m_handleMouseReleaseTimer->start();
|
||||
}
|
@ -1,138 +0,0 @@
|
||||
// Copyright (C) 2011 ~ 2018 Deepin Technology Co., Ltd.
|
||||
// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#ifndef SNITRAYWIDGET_H
|
||||
#define SNITRAYWIDGET_H
|
||||
|
||||
#include "constants.h"
|
||||
#include "abstracttraywidget.h"
|
||||
#include "util/dockpopupwindow.h"
|
||||
|
||||
#include "org_kde_statusnotifieritem.h"
|
||||
|
||||
#include <QMenu>
|
||||
#include <QDBusObjectPath>
|
||||
DWIDGET_USE_NAMESPACE
|
||||
DGUI_USE_NAMESPACE
|
||||
class DBusMenuImporter;
|
||||
namespace Dock {
|
||||
class TipsWidget;
|
||||
}
|
||||
|
||||
using namespace org::kde;
|
||||
|
||||
/**
|
||||
* @brief The SNITrayWidget class
|
||||
* @note 系统托盘第三方程序窗口
|
||||
*/
|
||||
class SNITrayWidget : public AbstractTrayWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum ItemCategory {UnknownCategory = -1, ApplicationStatus, Communications, SystemServices, Hardware};
|
||||
enum ItemStatus {Passive, Active, NeedsAttention};
|
||||
enum IconType {UnknownIconType = -1, Icon, OverlayIcon, AttentionIcon, AttentionMovieIcon};
|
||||
|
||||
public:
|
||||
SNITrayWidget(const QString &sniServicePath, QWidget *parent = Q_NULLPTR);
|
||||
|
||||
QString itemKeyForConfig() override;
|
||||
void updateIcon() override;
|
||||
void sendClick(uint8_t mouseButton, int x, int y) override;
|
||||
|
||||
bool isValid() override;
|
||||
SNITrayWidget::ItemStatus status();
|
||||
SNITrayWidget::ItemCategory category();
|
||||
|
||||
static QString toSNIKey(const QString &sniServicePath);
|
||||
static bool isSNIKey(const QString &itemKey);
|
||||
static QPair<QString, QString> serviceAndPath(const QString &servicePath);
|
||||
static uint servicePID(const QString &servicePath);
|
||||
|
||||
void showHoverTips();
|
||||
const QPoint topleftPoint() const;
|
||||
void showPopupWindow(QWidget *const content, const bool model = false);
|
||||
const QPoint popupMarkPoint() const;
|
||||
|
||||
static void setDockPostion(const Dock::Position pos) { DockPosition = pos; }
|
||||
|
||||
Q_SIGNALS:
|
||||
void statusChanged(SNITrayWidget::ItemStatus status);
|
||||
|
||||
private Q_SLOTS:
|
||||
void initSNIPropertys();
|
||||
void initMenu();
|
||||
void refreshIcon();
|
||||
void refreshOverlayIcon();
|
||||
void refreshAttentionIcon();
|
||||
void showContextMenu(int x, int y);
|
||||
// SNI property change slot
|
||||
void onSNIAttentionIconNameChanged(const QString &value);
|
||||
void onSNIAttentionIconPixmapChanged(DBusImageList value);
|
||||
void onSNIAttentionMovieNameChanged(const QString &value);
|
||||
void onSNICategoryChanged(const QString &value);
|
||||
void onSNIIconNameChanged(const QString &value);
|
||||
void onSNIIconPixmapChanged(DBusImageList value);
|
||||
void onSNIIconThemePathChanged(const QString &value);
|
||||
void onSNIIdChanged(const QString &value);
|
||||
void onSNIMenuChanged(const QDBusObjectPath &value);
|
||||
void onSNIOverlayIconNameChanged(const QString &value);
|
||||
void onSNIOverlayIconPixmapChanged(DBusImageList value);
|
||||
void onSNIStatusChanged(const QString &status);
|
||||
void hidePopup();
|
||||
void hideNonModel();
|
||||
void popupWindowAccept();
|
||||
void enterEvent(QEvent *event) override;
|
||||
void leaveEvent(QEvent *event) override;
|
||||
void mousePressEvent(QMouseEvent *event) override;
|
||||
void mouseReleaseEvent(QMouseEvent *e) override;
|
||||
|
||||
private:
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
QPixmap newIconPixmap(IconType iconType);
|
||||
void setMouseData(QMouseEvent *e);
|
||||
void handleMouseRelease();
|
||||
|
||||
private:
|
||||
StatusNotifierItem *m_sniInter;
|
||||
|
||||
DBusMenuImporter *m_dbusMenuImporter;
|
||||
|
||||
QMenu *m_menu;
|
||||
QTimer *m_updateIconTimer;
|
||||
QTimer *m_updateOverlayIconTimer;
|
||||
QTimer *m_updateAttentionIconTimer;
|
||||
|
||||
QString m_sniServicePath;
|
||||
QString m_dbusService;
|
||||
QString m_dbusPath;
|
||||
|
||||
QPixmap m_pixmap;
|
||||
QPixmap m_overlayPixmap;
|
||||
|
||||
// SNI propertys
|
||||
QString m_sniAttentionIconName;
|
||||
DBusImageList m_sniAttentionIconPixmap;
|
||||
QString m_sniAttentionMovieName;
|
||||
QString m_sniCategory;
|
||||
QString m_sniIconName;
|
||||
DBusImageList m_sniIconPixmap;
|
||||
QString m_sniIconThemePath;
|
||||
QString m_sniId;
|
||||
QDBusObjectPath m_sniMenuPath;
|
||||
QString m_sniOverlayIconName;
|
||||
DBusImageList m_sniOverlayIconPixmap;
|
||||
QString m_sniStatus;
|
||||
QTimer *m_popupTipsDelayTimer;
|
||||
QTimer *m_handleMouseReleaseTimer;
|
||||
QPair<QPoint, Qt::MouseButton> m_lastMouseReleaseData;
|
||||
static Dock::Position DockPosition;
|
||||
static QPointer<DockPopupWindow> PopupWindow;
|
||||
Dock::TipsWidget *m_tipsLabel;
|
||||
bool m_popupShown;
|
||||
};
|
||||
|
||||
#endif /* SNIWIDGET_H */
|
@ -1,496 +0,0 @@
|
||||
// Copyright (C) 2011 ~ 2018 Deepin Technology Co., Ltd.
|
||||
// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#include "systemtrayitem.h"
|
||||
#include "utils.h"
|
||||
|
||||
#include <QProcess>
|
||||
#include <QDebug>
|
||||
#include <QMenu>
|
||||
|
||||
#include <xcb/xproto.h>
|
||||
|
||||
Dock::Position SystemTrayItem::DockPosition = Dock::Position::Top;
|
||||
QPointer<DockPopupWindow> SystemTrayItem::PopupWindow = nullptr;
|
||||
|
||||
SystemTrayItem::SystemTrayItem(PluginsItemInterface *const pluginInter, const QString &itemKey, QWidget *parent)
|
||||
: AbstractTrayWidget(parent)
|
||||
, m_popupShown(false)
|
||||
, m_tapAndHold(false)
|
||||
, m_contextMenu(new QMenu) // 此处设置parent有问题,会导致当前菜单显示透明,因此设置parent为nullptr,在析构函数中释放
|
||||
, m_pluginInter(pluginInter)
|
||||
, m_centralWidget(m_pluginInter->itemWidget(itemKey))
|
||||
, m_popupTipsDelayTimer(new QTimer(this))
|
||||
, m_popupAdjustDelayTimer(new QTimer(this))
|
||||
, m_itemKey(itemKey)
|
||||
, m_gsettings(Utils::ModuleSettingsPtr(pluginInter->pluginName(), QByteArray(), this))
|
||||
{
|
||||
qDebug() << "load tray plugins item: " << m_pluginInter->pluginName() << itemKey << m_centralWidget;
|
||||
|
||||
m_centralWidget->setParent(this);
|
||||
m_centralWidget->setVisible(true);
|
||||
m_centralWidget->installEventFilter(this);
|
||||
|
||||
QBoxLayout *hLayout = new QHBoxLayout(this);
|
||||
hLayout->addWidget(m_centralWidget);
|
||||
hLayout->setSpacing(0);
|
||||
hLayout->setMargin(0);
|
||||
|
||||
setLayout(hLayout);
|
||||
setAccessibleName(m_itemKey);
|
||||
setAttribute(Qt::WA_TranslucentBackground);
|
||||
|
||||
if (PopupWindow.isNull()) {
|
||||
DockPopupWindow *arrowRectangle = new DockPopupWindow(nullptr);
|
||||
arrowRectangle->setShadowBlurRadius(20);
|
||||
arrowRectangle->setRadius(6);
|
||||
arrowRectangle->setShadowYOffset(2);
|
||||
arrowRectangle->setShadowXOffset(0);
|
||||
arrowRectangle->setArrowWidth(18);
|
||||
arrowRectangle->setArrowHeight(10);
|
||||
arrowRectangle->setObjectName("systemtraypopup");
|
||||
if (Utils::IS_WAYLAND_DISPLAY) {
|
||||
Qt::WindowFlags flags = arrowRectangle->windowFlags() | Qt::FramelessWindowHint;
|
||||
arrowRectangle->setWindowFlags(flags);
|
||||
}
|
||||
PopupWindow = arrowRectangle;
|
||||
connect(qApp, &QApplication::aboutToQuit, PopupWindow, &DockPopupWindow::deleteLater);
|
||||
}
|
||||
|
||||
if (Utils::IS_WAYLAND_DISPLAY) {
|
||||
Qt::WindowFlags flags = m_contextMenu->windowFlags() | Qt::FramelessWindowHint;
|
||||
m_contextMenu->setWindowFlags(flags);
|
||||
}
|
||||
// 必须初始化父窗口,否则当主题切换之后再设置父窗口的时候palette会更改为主题切换前的palette
|
||||
if (QWidget *w = m_pluginInter->itemPopupApplet(m_itemKey)) {
|
||||
w->setParent(PopupWindow.data());
|
||||
w->setVisible(false);
|
||||
}
|
||||
|
||||
m_popupTipsDelayTimer->setInterval(500);
|
||||
m_popupTipsDelayTimer->setSingleShot(true);
|
||||
|
||||
m_popupAdjustDelayTimer->setInterval(10);
|
||||
m_popupAdjustDelayTimer->setSingleShot(true);
|
||||
|
||||
connect(m_popupTipsDelayTimer, &QTimer::timeout, this, &SystemTrayItem::showHoverTips);
|
||||
connect(m_popupAdjustDelayTimer, &QTimer::timeout, this, &SystemTrayItem::updatePopupPosition, Qt::QueuedConnection);
|
||||
connect(m_contextMenu, &QMenu::triggered, this, &SystemTrayItem::menuActionClicked);
|
||||
|
||||
if (m_gsettings)
|
||||
connect(m_gsettings, &QGSettings::changed, this, &SystemTrayItem::onGSettingsChanged);
|
||||
|
||||
grabGesture(Qt::TapAndHoldGesture);
|
||||
}
|
||||
|
||||
SystemTrayItem::~SystemTrayItem()
|
||||
{
|
||||
m_contextMenu->deleteLater();
|
||||
if (m_popupShown)
|
||||
popupWindowAccept();
|
||||
}
|
||||
|
||||
QString SystemTrayItem::itemKeyForConfig()
|
||||
{
|
||||
return m_itemKey;
|
||||
}
|
||||
|
||||
void SystemTrayItem::updateIcon()
|
||||
{
|
||||
m_pluginInter->refreshIcon(m_itemKey);
|
||||
}
|
||||
|
||||
void SystemTrayItem::sendClick(uint8_t mouseButton, int x, int y)
|
||||
{
|
||||
Q_UNUSED(mouseButton);
|
||||
Q_UNUSED(x);
|
||||
Q_UNUSED(y);
|
||||
|
||||
// do not process this callback
|
||||
// handle all mouse event in override mouse function
|
||||
}
|
||||
|
||||
QWidget *SystemTrayItem::trayTipsWidget()
|
||||
{
|
||||
if (m_pluginInter->itemTipsWidget(m_itemKey)) {
|
||||
m_pluginInter->itemTipsWidget(m_itemKey)->setAccessibleName(m_pluginInter->pluginName());
|
||||
}
|
||||
|
||||
return m_pluginInter->itemTipsWidget(m_itemKey);
|
||||
}
|
||||
|
||||
QWidget *SystemTrayItem::trayPopupApplet()
|
||||
{
|
||||
if (m_pluginInter->itemPopupApplet(m_itemKey)) {
|
||||
m_pluginInter->itemPopupApplet(m_itemKey)->setAccessibleName(m_pluginInter->pluginName());
|
||||
}
|
||||
|
||||
return m_pluginInter->itemPopupApplet(m_itemKey);
|
||||
}
|
||||
|
||||
const QString SystemTrayItem::trayClickCommand()
|
||||
{
|
||||
return m_pluginInter->itemCommand(m_itemKey);
|
||||
}
|
||||
|
||||
const QString SystemTrayItem::contextMenu() const
|
||||
{
|
||||
return m_pluginInter->itemContextMenu(m_itemKey);
|
||||
}
|
||||
|
||||
void SystemTrayItem::invokedMenuItem(const QString &menuId, const bool checked)
|
||||
{
|
||||
m_pluginInter->invokedMenuItem(m_itemKey, menuId, checked);
|
||||
}
|
||||
|
||||
QWidget *SystemTrayItem::centralWidget() const
|
||||
{
|
||||
return m_centralWidget;
|
||||
}
|
||||
|
||||
void SystemTrayItem::detachPluginWidget()
|
||||
{
|
||||
QWidget *widget = m_pluginInter->itemWidget(m_itemKey);
|
||||
if (widget)
|
||||
widget->setParent(nullptr);
|
||||
}
|
||||
|
||||
bool SystemTrayItem::event(QEvent *event)
|
||||
{
|
||||
if (m_popupShown) {
|
||||
switch (event->type()) {
|
||||
case QEvent::Paint:
|
||||
if (!m_popupAdjustDelayTimer->isActive())
|
||||
m_popupAdjustDelayTimer->start();
|
||||
break;
|
||||
default:;
|
||||
}
|
||||
}
|
||||
|
||||
if (event->type() == QEvent::Gesture)
|
||||
gestureEvent(static_cast<QGestureEvent *>(event));
|
||||
|
||||
return AbstractTrayWidget::event(event);
|
||||
}
|
||||
|
||||
void SystemTrayItem::enterEvent(QEvent *event)
|
||||
{
|
||||
if (checkGSettingsControl()) {
|
||||
//网络需要显示Tips,需要特殊处理。
|
||||
if (m_pluginInter->pluginName() != "network")
|
||||
return;
|
||||
}
|
||||
|
||||
// 触屏不显示hover效果
|
||||
if (!qApp->property(IS_TOUCH_STATE).toBool()) {
|
||||
m_popupTipsDelayTimer->start();
|
||||
}
|
||||
update();
|
||||
|
||||
AbstractTrayWidget::enterEvent(event);
|
||||
}
|
||||
|
||||
void SystemTrayItem::leaveEvent(QEvent *event)
|
||||
{
|
||||
m_popupTipsDelayTimer->stop();
|
||||
|
||||
// auto hide if popup is not model window
|
||||
if (m_popupShown && !PopupWindow->model())
|
||||
hidePopup();
|
||||
|
||||
update();
|
||||
|
||||
AbstractTrayWidget::leaveEvent(event);
|
||||
}
|
||||
|
||||
void SystemTrayItem::mousePressEvent(QMouseEvent *event)
|
||||
{
|
||||
if (checkGSettingsControl()) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_popupTipsDelayTimer->stop();
|
||||
hideNonModel();
|
||||
|
||||
if (event->button() == Qt::RightButton
|
||||
&& perfectIconRect().contains(event->pos(), true)) {
|
||||
return (m_gsettings && (!m_gsettings->keys().contains("menuEnable") || m_gsettings->get("menuEnable").toBool())) ? showContextMenu() : void();
|
||||
}
|
||||
|
||||
AbstractTrayWidget::mousePressEvent(event);
|
||||
}
|
||||
|
||||
void SystemTrayItem::mouseReleaseEvent(QMouseEvent *event)
|
||||
{
|
||||
if (checkGSettingsControl()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (event->button() != Qt::LeftButton) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (checkAndResetTapHoldGestureState() && event->source() == Qt::MouseEventSynthesizedByQt) {
|
||||
qDebug() << "SystemTray: tap and hold gesture detected, ignore the synthesized mouse release event";
|
||||
return;
|
||||
}
|
||||
|
||||
event->accept();
|
||||
|
||||
showPopupApplet(trayPopupApplet());
|
||||
|
||||
if (!trayClickCommand().isEmpty()) {
|
||||
QProcess::startDetached(trayClickCommand());
|
||||
}
|
||||
|
||||
AbstractTrayWidget::mouseReleaseEvent(event);
|
||||
}
|
||||
|
||||
void SystemTrayItem::showEvent(QShowEvent *event)
|
||||
{
|
||||
QTimer::singleShot(0, this, [ = ] {
|
||||
onGSettingsChanged("enable");
|
||||
});
|
||||
|
||||
return AbstractTrayWidget::showEvent(event);
|
||||
}
|
||||
|
||||
const QPoint SystemTrayItem::popupMarkPoint() const
|
||||
{
|
||||
QPoint p(topleftPoint());
|
||||
|
||||
const QRect r = rect();
|
||||
const QRect wr = window()->rect();
|
||||
|
||||
switch (DockPosition) {
|
||||
case Dock::Position::Top:
|
||||
p += QPoint(r.width() / 2, r.height() + (wr.height() - r.height()) / 2);
|
||||
break;
|
||||
case Dock::Position::Bottom:
|
||||
p += QPoint(r.width() / 2, 0 - (wr.height() - r.height()) / 2);
|
||||
break;
|
||||
case Dock::Position::Left:
|
||||
p += QPoint(r.width() + (wr.width() - r.width()) / 2, r.height() / 2);
|
||||
break;
|
||||
case Dock::Position::Right:
|
||||
p += QPoint(0 - (wr.width() - r.width()) / 2, r.height() / 2);
|
||||
break;
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
// 获取在最外层的窗口(MainWindow)中的位置
|
||||
const QPoint SystemTrayItem::topleftPoint() const
|
||||
{
|
||||
QPoint p;
|
||||
const QWidget *w = this;
|
||||
do {
|
||||
p += w->pos();
|
||||
w = qobject_cast<QWidget *>(w->parent());
|
||||
} while (w);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
void SystemTrayItem::hidePopup()
|
||||
{
|
||||
m_popupTipsDelayTimer->stop();
|
||||
m_popupAdjustDelayTimer->stop();
|
||||
m_popupShown = false;
|
||||
PopupWindow->hide();
|
||||
|
||||
DockPopupWindow *popup = PopupWindow.data();
|
||||
QWidget *content = popup->getContent();
|
||||
if (content) {
|
||||
content->setVisible(false);
|
||||
}
|
||||
|
||||
emit PopupWindow->accept();
|
||||
emit requestWindowAutoHide(true);
|
||||
}
|
||||
|
||||
void SystemTrayItem::hideNonModel()
|
||||
{
|
||||
// auto hide if popup is not model window
|
||||
if (m_popupShown && !PopupWindow->model())
|
||||
hidePopup();
|
||||
}
|
||||
|
||||
void SystemTrayItem::popupWindowAccept()
|
||||
{
|
||||
if (!PopupWindow->isVisible())
|
||||
return;
|
||||
|
||||
disconnect(PopupWindow.data(), &DockPopupWindow::accept, this, &SystemTrayItem::popupWindowAccept);
|
||||
|
||||
hidePopup();
|
||||
}
|
||||
|
||||
void SystemTrayItem::showPopupApplet(QWidget *const applet)
|
||||
{
|
||||
if (!applet)
|
||||
return;
|
||||
|
||||
// another model popup window already exists
|
||||
if (PopupWindow->model()) {
|
||||
applet->setVisible(false);
|
||||
return;
|
||||
}
|
||||
|
||||
showPopupWindow(applet, true);
|
||||
}
|
||||
|
||||
void SystemTrayItem::showPopupWindow(QWidget *const content, const bool model)
|
||||
{
|
||||
m_popupShown = true;
|
||||
m_lastPopupWidget = content;
|
||||
|
||||
if (model)
|
||||
emit requestWindowAutoHide(false);
|
||||
|
||||
DockPopupWindow *popup = PopupWindow.data();
|
||||
QWidget *lastContent = popup->getContent();
|
||||
if (lastContent)
|
||||
lastContent->setVisible(false);
|
||||
|
||||
switch (DockPosition) {
|
||||
case Dock::Position::Top: popup->setArrowDirection(DockPopupWindow::ArrowTop); break;
|
||||
case Dock::Position::Bottom: popup->setArrowDirection(DockPopupWindow::ArrowBottom); break;
|
||||
case Dock::Position::Left: popup->setArrowDirection(DockPopupWindow::ArrowLeft); break;
|
||||
case Dock::Position::Right: popup->setArrowDirection(DockPopupWindow::ArrowRight); break;
|
||||
}
|
||||
popup->resize(content->sizeHint());
|
||||
popup->setContent(content);
|
||||
|
||||
QPoint p = popupMarkPoint();
|
||||
if (!popup->isVisible())
|
||||
QMetaObject::invokeMethod(popup, "show", Qt::QueuedConnection, Q_ARG(QPoint, p), Q_ARG(bool, model));
|
||||
else
|
||||
popup->show(p, model);
|
||||
|
||||
connect(popup, &DockPopupWindow::accept, this, &SystemTrayItem::popupWindowAccept, Qt::UniqueConnection);
|
||||
}
|
||||
|
||||
void SystemTrayItem::showHoverTips()
|
||||
{
|
||||
// another model popup window already exists
|
||||
if (PopupWindow->model())
|
||||
return;
|
||||
|
||||
// if not in geometry area
|
||||
const QRect r(topleftPoint(), size());
|
||||
if (!r.contains(QCursor::pos()))
|
||||
return;
|
||||
|
||||
QWidget *const content = trayTipsWidget();
|
||||
if (!content)
|
||||
return;
|
||||
|
||||
showPopupWindow(content);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \sa DockItem::checkAndResetTapHoldGestureState
|
||||
*/
|
||||
bool SystemTrayItem::checkAndResetTapHoldGestureState()
|
||||
{
|
||||
bool ret = m_tapAndHold;
|
||||
m_tapAndHold = false;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void SystemTrayItem::gestureEvent(QGestureEvent *event)
|
||||
{
|
||||
if (!event)
|
||||
return;
|
||||
|
||||
QGesture *gesture = event->gesture(Qt::TapAndHoldGesture);
|
||||
|
||||
if (!gesture)
|
||||
return;
|
||||
|
||||
qDebug() << "SystemTray: got TapAndHoldGesture";
|
||||
|
||||
m_tapAndHold = true;
|
||||
}
|
||||
|
||||
void SystemTrayItem::showContextMenu()
|
||||
{
|
||||
const QString menuJson = contextMenu();
|
||||
if (menuJson.isEmpty())
|
||||
return;
|
||||
|
||||
|
||||
QJsonDocument jsonDocument = QJsonDocument::fromJson(menuJson.toLocal8Bit().data());
|
||||
if (jsonDocument.isNull())
|
||||
return;
|
||||
|
||||
QJsonObject jsonMenu = jsonDocument.object();
|
||||
|
||||
qDeleteAll(m_contextMenu->actions());
|
||||
|
||||
QJsonArray jsonMenuItems = jsonMenu.value("items").toArray();
|
||||
for (auto item : jsonMenuItems) {
|
||||
QJsonObject itemObj = item.toObject();
|
||||
QAction *action = new QAction(itemObj.value("itemText").toString());
|
||||
action->setCheckable(itemObj.value("isCheckable").toBool());
|
||||
action->setChecked(itemObj.value("checked").toBool());
|
||||
action->setData(itemObj.value("itemId").toString());
|
||||
action->setEnabled(itemObj.value("isActive").toBool());
|
||||
m_contextMenu->addAction(action);
|
||||
}
|
||||
|
||||
hidePopup();
|
||||
emit requestWindowAutoHide(false);
|
||||
|
||||
m_contextMenu->exec(QCursor::pos());
|
||||
|
||||
onContextMenuAccepted();
|
||||
}
|
||||
|
||||
void SystemTrayItem::menuActionClicked(QAction *action)
|
||||
{
|
||||
invokedMenuItem(action->data().toString(), true);
|
||||
}
|
||||
|
||||
void SystemTrayItem::onContextMenuAccepted()
|
||||
{
|
||||
emit requestRefershWindowVisible();
|
||||
emit requestWindowAutoHide(true);
|
||||
}
|
||||
|
||||
void SystemTrayItem::updatePopupPosition()
|
||||
{
|
||||
Q_ASSERT(sender() == m_popupAdjustDelayTimer);
|
||||
|
||||
if (!m_popupShown || !PopupWindow->model())
|
||||
return;
|
||||
|
||||
if (PopupWindow->getContent() != m_lastPopupWidget.data())
|
||||
return popupWindowAccept();
|
||||
|
||||
const QPoint p = popupMarkPoint();
|
||||
PopupWindow->show(p, PopupWindow->model());
|
||||
}
|
||||
|
||||
void SystemTrayItem::onGSettingsChanged(const QString &key) {
|
||||
if (key != "enable") {
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_gsettings && m_gsettings->keys().contains("enable")) {
|
||||
const bool visible = m_gsettings->get("enable").toBool();
|
||||
setVisible(visible);
|
||||
emit itemVisibleChanged(visible);
|
||||
}
|
||||
}
|
||||
|
||||
bool SystemTrayItem::checkGSettingsControl() const
|
||||
{
|
||||
// 优先判断com.deepin.dde.dock.module.systemtray的control值是否为true(优先级更高),如果不为true,再判断每一个托盘对应的gsetting配置的control值
|
||||
bool isEnable = Utils::SettingValue("com.deepin.dde.dock.module.systemtray", QByteArray(), "control", false).toBool();
|
||||
return (isEnable || (m_gsettings && m_gsettings->get("control").toBool()));
|
||||
}
|
@ -1,100 +0,0 @@
|
||||
// Copyright (C) 2011 ~ 2018 Deepin Technology Co., Ltd.
|
||||
// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#ifndef SYSTEMTRAYITEM_H
|
||||
#define SYSTEMTRAYITEM_H
|
||||
|
||||
#include "constants.h"
|
||||
#include "../abstracttraywidget.h"
|
||||
#include "util/dockpopupwindow.h"
|
||||
#include "pluginsiteminterface.h"
|
||||
|
||||
#include <QGestureEvent>
|
||||
|
||||
class QGSettings;
|
||||
class QMenu;
|
||||
|
||||
class SystemTrayItem : public AbstractTrayWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
SystemTrayItem(PluginsItemInterface* const pluginInter, const QString &itemKey, QWidget *parent = nullptr);
|
||||
virtual ~SystemTrayItem();
|
||||
|
||||
public:
|
||||
QString itemKeyForConfig() override;
|
||||
void updateIcon() override;
|
||||
void sendClick(uint8_t mouseButton, int x, int y) override;
|
||||
inline TrayType trayTyep() const override { return TrayType::SystemTray; }
|
||||
|
||||
QWidget *trayTipsWidget();
|
||||
QWidget *trayPopupApplet();
|
||||
const QString trayClickCommand();
|
||||
const QString contextMenu() const;
|
||||
void invokedMenuItem(const QString &menuId, const bool checked);
|
||||
|
||||
static void setDockPostion(const Dock::Position pos) { DockPosition = pos; }
|
||||
|
||||
QWidget *centralWidget() const;
|
||||
void detachPluginWidget();
|
||||
void showContextMenu();
|
||||
|
||||
void showPopupApplet(QWidget * const applet);
|
||||
void hidePopup();
|
||||
|
||||
signals:
|
||||
void itemVisibleChanged(bool visible);
|
||||
|
||||
protected:
|
||||
bool event(QEvent *event) override;
|
||||
void enterEvent(QEvent *event) override;
|
||||
void leaveEvent(QEvent *event) override;
|
||||
void mousePressEvent(QMouseEvent *event) override;
|
||||
void mouseReleaseEvent(QMouseEvent *event) override;
|
||||
void showEvent(QShowEvent* event) override;
|
||||
|
||||
protected:
|
||||
const QPoint popupMarkPoint() const;
|
||||
const QPoint topleftPoint() const;
|
||||
|
||||
void hideNonModel();
|
||||
void popupWindowAccept();
|
||||
|
||||
virtual void showPopupWindow(QWidget * const content, const bool model = false);
|
||||
virtual void showHoverTips();
|
||||
|
||||
bool checkAndResetTapHoldGestureState();
|
||||
virtual void gestureEvent(QGestureEvent *event);
|
||||
|
||||
protected Q_SLOTS:
|
||||
void onContextMenuAccepted();
|
||||
|
||||
private:
|
||||
void updatePopupPosition();
|
||||
void onGSettingsChanged(const QString &key);
|
||||
bool checkGSettingsControl() const;
|
||||
void menuActionClicked(QAction *action);
|
||||
|
||||
private:
|
||||
bool m_popupShown;
|
||||
bool m_tapAndHold;
|
||||
QMenu *m_contextMenu;
|
||||
|
||||
PluginsItemInterface* m_pluginInter;
|
||||
QWidget *m_centralWidget;
|
||||
|
||||
QTimer *m_popupTipsDelayTimer;
|
||||
QTimer *m_popupAdjustDelayTimer;
|
||||
|
||||
QPointer<QWidget> m_lastPopupWidget;
|
||||
QString m_itemKey;
|
||||
|
||||
static Dock::Position DockPosition;
|
||||
static QPointer<DockPopupWindow> PopupWindow;
|
||||
const QGSettings* m_gsettings;
|
||||
};
|
||||
|
||||
#endif // SYSTEMTRAYITEM_H
|
@ -1,169 +0,0 @@
|
||||
// Copyright (C) 2011 ~ 2018 Deepin Technology Co., Ltd.
|
||||
// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#include "systemtrayscontroller.h"
|
||||
#include "pluginsiteminterface.h"
|
||||
#include "utils.h"
|
||||
#include "proxyplugincontroller.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QDir>
|
||||
|
||||
SystemTraysController::SystemTraysController(QObject *parent)
|
||||
: AbstractPluginsController(parent)
|
||||
{
|
||||
setObjectName("SystemTray");
|
||||
|
||||
// 将当前对象添加进代理对象列表中,代理对象在加载插件成功后,会调用列表中所有对象的itemAdded方法来添加插件
|
||||
ProxyPluginController::instance(PluginType::QuickPlugin)->addProxyInterface(this);
|
||||
ProxyPluginController::instance(PluginType::SystemTrays)->addProxyInterface(this);
|
||||
|
||||
QMetaObject::invokeMethod(this, [ this ] {
|
||||
// 在加载当前的tray插件之前,所有的插件已经加载,因此此处需要获取代理中已经加载过的插件来加载到当前布局中
|
||||
loadPlugins(ProxyPluginController::instance(PluginType::QuickPlugin));
|
||||
loadPlugins(ProxyPluginController::instance(PluginType::SystemTrays));
|
||||
}, Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
SystemTraysController::~SystemTraysController()
|
||||
{
|
||||
ProxyPluginController::instance(PluginType::QuickPlugin)->removeProxyInterface(this);
|
||||
ProxyPluginController::instance(PluginType::SystemTrays)->removeProxyInterface(this);
|
||||
}
|
||||
|
||||
void SystemTraysController::itemAdded(PluginsItemInterface * const itemInter, const QString &itemKey)
|
||||
{
|
||||
QMap<PluginsItemInterface *, QMap<QString, QObject *>> &mPluginsMap = pluginsMap();
|
||||
|
||||
// check if same item added
|
||||
if (mPluginsMap.contains(itemInter))
|
||||
if (mPluginsMap[itemInter].contains(itemKey))
|
||||
return;
|
||||
|
||||
SystemTrayItem *item = new SystemTrayItem(itemInter, itemKey);
|
||||
connect(item, &SystemTrayItem::itemVisibleChanged, this, [=] (bool visible){
|
||||
if (visible) {
|
||||
emit pluginItemAdded(itemKey, item);
|
||||
} else {
|
||||
emit pluginItemRemoved(itemKey, item);
|
||||
}
|
||||
}, Qt::QueuedConnection);
|
||||
|
||||
mPluginsMap[itemInter][itemKey] = item;
|
||||
|
||||
// 隐藏的插件不加入到布局中
|
||||
if (Utils::SettingValue(QString("com.deepin.dde.dock.module.") + itemInter->pluginName(), QByteArray(), "enable", true).toBool())
|
||||
emit pluginItemAdded(itemKey, item);
|
||||
}
|
||||
|
||||
void SystemTraysController::itemUpdate(PluginsItemInterface * const itemInter, const QString &itemKey)
|
||||
{
|
||||
SystemTrayItem *item = static_cast<SystemTrayItem *>(pluginItemAt(itemInter, itemKey));
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
item->update();
|
||||
|
||||
emit pluginItemUpdated(itemKey, item);
|
||||
}
|
||||
|
||||
void SystemTraysController::itemRemoved(PluginsItemInterface * const itemInter, const QString &itemKey)
|
||||
{
|
||||
SystemTrayItem *item = static_cast<SystemTrayItem *>(pluginItemAt(itemInter, itemKey));
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
item->detachPluginWidget();
|
||||
|
||||
emit pluginItemRemoved(itemKey, item);
|
||||
|
||||
QMap<PluginsItemInterface *, QMap<QString, QObject *>> &mPluginsMap = pluginsMap();
|
||||
mPluginsMap[itemInter].remove(itemKey);
|
||||
|
||||
// do not delete the itemWidget object(specified in the plugin interface)
|
||||
item->centralWidget()->setParent(nullptr);
|
||||
|
||||
// just delete our wrapper object(PluginsItem)
|
||||
item->deleteLater();
|
||||
}
|
||||
|
||||
void SystemTraysController::requestWindowAutoHide(PluginsItemInterface * const itemInter, const QString &itemKey, const bool autoHide)
|
||||
{
|
||||
SystemTrayItem *item = static_cast<SystemTrayItem *>(pluginItemAt(itemInter, itemKey));
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
Q_EMIT item->requestWindowAutoHide(autoHide);
|
||||
}
|
||||
|
||||
void SystemTraysController::requestRefreshWindowVisible(PluginsItemInterface * const itemInter, const QString &itemKey)
|
||||
{
|
||||
SystemTrayItem *item = static_cast<SystemTrayItem *>(pluginItemAt(itemInter, itemKey));
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
Q_EMIT item->requestRefershWindowVisible();
|
||||
}
|
||||
|
||||
void SystemTraysController::requestSetAppletVisible(PluginsItemInterface * const itemInter, const QString &itemKey, const bool visible)
|
||||
{
|
||||
SystemTrayItem *item = static_cast<SystemTrayItem *>(pluginItemAt(itemInter, itemKey));
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
if (visible) {
|
||||
item->showPopupApplet(itemInter->itemPopupApplet(itemKey));
|
||||
} else {
|
||||
item->hidePopup();
|
||||
}
|
||||
}
|
||||
|
||||
int SystemTraysController::systemTrayItemSortKey(const QString &itemKey)
|
||||
{
|
||||
auto inter = pluginInterAt(itemKey);
|
||||
|
||||
if (!inter)
|
||||
return -1;
|
||||
|
||||
return inter->itemSortKey(itemKey);
|
||||
}
|
||||
|
||||
void SystemTraysController::setSystemTrayItemSortKey(const QString &itemKey, const int order)
|
||||
{
|
||||
auto inter = pluginInterAt(itemKey);
|
||||
|
||||
if (!inter)
|
||||
return;
|
||||
|
||||
inter->setSortKey(itemKey, order);
|
||||
}
|
||||
|
||||
const QVariant SystemTraysController::getValueSystemTrayItem(const QString &itemKey, const QString &key, const QVariant &fallback)
|
||||
{
|
||||
auto inter = pluginInterAt(itemKey);
|
||||
|
||||
if (!inter)
|
||||
return QVariant();
|
||||
|
||||
return getValue(inter, key, fallback);
|
||||
}
|
||||
|
||||
void SystemTraysController::saveValueSystemTrayItem(const QString &itemKey, const QString &key, const QVariant &value)
|
||||
{
|
||||
auto inter = pluginInterAt(itemKey);
|
||||
|
||||
if (!inter)
|
||||
return;
|
||||
|
||||
saveValue(inter, key, value);
|
||||
}
|
||||
|
||||
void SystemTraysController::loadPlugins(ProxyPluginController *proxyController)
|
||||
{
|
||||
// 加载已有插件,并将其添加到当前的插件中
|
||||
const QList<PluginsItemInterface *> &pluginsItems = proxyController->pluginsItems();
|
||||
for (PluginsItemInterface *itemInter : pluginsItems)
|
||||
itemAdded(itemInter, proxyController->itemKey(itemInter));
|
||||
}
|
@ -1,52 +0,0 @@
|
||||
// Copyright (C) 2011 ~ 2018 Deepin Technology Co., Ltd.
|
||||
// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#ifndef SYSTEMTRAYSCONTROLLER_H
|
||||
#define SYSTEMTRAYSCONTROLLER_H
|
||||
|
||||
#include "systemtrayitem.h"
|
||||
#include "pluginproxyinterface.h"
|
||||
#include "util/abstractpluginscontroller.h"
|
||||
|
||||
#include <QPluginLoader>
|
||||
#include <QList>
|
||||
#include <QMap>
|
||||
#include <QDBusConnectionInterface>
|
||||
|
||||
class PluginsItemInterface;
|
||||
class ProxyPluginController;
|
||||
|
||||
class SystemTraysController : public AbstractPluginsController
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit SystemTraysController(QObject *parent = nullptr);
|
||||
~SystemTraysController() override;
|
||||
|
||||
// implements PluginProxyInterface
|
||||
void itemAdded(PluginsItemInterface * const itemInter, const QString &itemKey) override;
|
||||
void itemUpdate(PluginsItemInterface * const itemInter, const QString &itemKey) override;
|
||||
void itemRemoved(PluginsItemInterface * const itemInter, const QString &itemKey) override;
|
||||
void requestWindowAutoHide(PluginsItemInterface * const itemInter, const QString &itemKey, const bool autoHide) override;
|
||||
void requestRefreshWindowVisible(PluginsItemInterface * const itemInter, const QString &itemKey) override;
|
||||
void requestSetAppletVisible(PluginsItemInterface * const itemInter, const QString &itemKey, const bool visible) override;
|
||||
|
||||
int systemTrayItemSortKey(const QString &itemKey);
|
||||
void setSystemTrayItemSortKey(const QString &itemKey, const int order);
|
||||
|
||||
const QVariant getValueSystemTrayItem(const QString &itemKey, const QString &key, const QVariant& fallback = QVariant());
|
||||
void saveValueSystemTrayItem(const QString &itemKey, const QString &key, const QVariant &value);
|
||||
|
||||
signals:
|
||||
void pluginItemAdded(const QString &itemKey, AbstractTrayWidget *pluginItem) const;
|
||||
void pluginItemRemoved(const QString &itemKey, AbstractTrayWidget *pluginItem) const;
|
||||
void pluginItemUpdated(const QString &itemKey, AbstractTrayWidget *pluginItem) const;
|
||||
|
||||
private:
|
||||
void loadPlugins(ProxyPluginController *proxyController);
|
||||
};
|
||||
|
||||
#endif // SYSTEMTRAYSCONTROLLER_H
|
@ -1,4 +0,0 @@
|
||||
{
|
||||
"api": "2.0.0",
|
||||
"depends-daemon-dbus-service": "org.deepin.dde.TrayManager1"
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
<RCC>
|
||||
<qresource prefix="/icons">
|
||||
<file>resources/arrow-down.svg</file>
|
||||
<file>resources/arrow-down-dark.svg</file>
|
||||
<file>resources/arrow-up.svg</file>
|
||||
<file>resources/arrow-up-dark.svg</file>
|
||||
<file>resources/arrow-left.svg</file>
|
||||
<file>resources/arrow-left-dark.svg</file>
|
||||
<file>resources/arrow-right.svg</file>
|
||||
<file>resources/arrow-right-dark.svg</file>
|
||||
</qresource>
|
||||
</RCC>
|
@ -1,641 +0,0 @@
|
||||
// Copyright (C) 2011 ~ 2018 Deepin Technology Co., Ltd.
|
||||
// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#include "trayplugin.h"
|
||||
#include "fashiontray/fashiontrayitem.h"
|
||||
#include "snitraywidget.h"
|
||||
#include "utils.h"
|
||||
#include "../widgets/tipswidget.h"
|
||||
|
||||
#include <QDir>
|
||||
#include <QWindow>
|
||||
#include <QWidget>
|
||||
#include <QX11Info>
|
||||
#include <QtConcurrent>
|
||||
#include <QFuture>
|
||||
#include <QFutureWatcher>
|
||||
|
||||
#include <xcb/xcb_icccm.h>
|
||||
#include <X11/Xlib.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"
|
||||
|
||||
#define REGISTERTED_WAY_IS_SNI 1
|
||||
#define REGISTERTED_WAY_IS_XEMBED 2
|
||||
|
||||
using org::kde::StatusNotifierWatcher;
|
||||
using namespace Dock;
|
||||
|
||||
TrayPlugin::TrayPlugin(QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_pluginLoaded(false)
|
||||
, xcb_connection(nullptr)
|
||||
, m_display(nullptr)
|
||||
{
|
||||
if (Utils::IS_WAYLAND_DISPLAY) {
|
||||
int screenp = 0;
|
||||
xcb_connection = xcb_connect(qgetenv("DISPLAY"), &screenp);
|
||||
m_display = XOpenDisplay(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
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_refreshXEmbedItemsTimer->setInterval(0);
|
||||
m_refreshXEmbedItemsTimer->setSingleShot(true);
|
||||
|
||||
m_refreshSNIItemsTimer->setInterval(0);
|
||||
m_refreshSNIItemsTimer->setSingleShot(true);
|
||||
|
||||
connect(m_systemTraysController, &SystemTraysController::pluginItemAdded, this, &TrayPlugin::addTrayWidget);
|
||||
connect(m_systemTraysController, &SystemTraysController::pluginItemRemoved, this, [ = ](const QString & itemKey) { trayRemoved(itemKey); });
|
||||
|
||||
m_trayInter->Manage();
|
||||
|
||||
switchToMode(displayMode());
|
||||
|
||||
// 加载sni,xem,自定义indicator协议以及其他托盘插件
|
||||
QTimer::singleShot(0, this, &TrayPlugin::loadIndicator);
|
||||
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)
|
||||
{
|
||||
Q_UNUSED(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();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief TrayPlugin::initSNI
|
||||
* @note 初始化监听信号绑定
|
||||
*/
|
||||
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();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief TrayPlugin::sniItemsChanged
|
||||
* @note 移除关闭的item,插入新增item
|
||||
*/
|
||||
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)) {
|
||||
m_registertedPID.take(m_trayMap[itemKey]->getOwnerPID());
|
||||
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) {
|
||||
uint pid = SNITrayWidget::servicePID(itemServicePaths.at(i));
|
||||
if (m_registertedPID.value(pid, REGISTERTED_WAY_IS_SNI) == REGISTERTED_WAY_IS_SNI) {
|
||||
traySNIAdded(sinTrayKeyList.at(i), itemServicePaths.at(i));
|
||||
m_registertedPID.insert(pid, REGISTERTED_WAY_IS_SNI);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TrayPlugin::xembedItemsChanged()
|
||||
{
|
||||
QList<quint32> winidList = m_trayInter->trayIcons();
|
||||
QStringList newlyAddedTrayKeyList;
|
||||
QStringList allKeytary;
|
||||
QList<quint32> newlyAddedWindowID;
|
||||
|
||||
for (auto winid : winidList) {
|
||||
uint pid = XEmbedTrayWidget::getWindowPID(winid);
|
||||
allKeytary << XEmbedTrayWidget::toXEmbedKey(winid);
|
||||
|
||||
if (m_registertedPID.value(pid, REGISTERTED_WAY_IS_XEMBED) == REGISTERTED_WAY_IS_XEMBED) {
|
||||
m_registertedPID.insert(pid, REGISTERTED_WAY_IS_XEMBED);
|
||||
newlyAddedWindowID << winid;
|
||||
newlyAddedTrayKeyList << XEmbedTrayWidget::toXEmbedKey(winid);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto tray : m_trayMap.keys()) {
|
||||
if (!allKeytary.contains(tray) && XEmbedTrayWidget::isXEmbedKey(tray)) {
|
||||
m_registertedPID.take(m_trayMap[tray]->getOwnerPID());
|
||||
trayRemoved(tray);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < newlyAddedTrayKeyList.size(); ++i) {
|
||||
trayXEmbedAdded(newlyAddedTrayKeyList.at(i), newlyAddedWindowID.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 = Utils::IS_WAYLAND_DISPLAY ? new XEmbedTrayWidget(winId, xcb_connection, m_display) : 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;
|
||||
}
|
||||
|
||||
// 1、确保服务有效
|
||||
QDBusInterface sniItemDBus(sniServerName, "/" + list.last());
|
||||
if (!sniItemDBus.isValid()) {
|
||||
qDebug() << "sni dbus service error : " << sniServerName;
|
||||
return false;
|
||||
}
|
||||
|
||||
// 部分服务虽然有效,但是在dbus总线上只能看到服务,其他信息都无法获取,这里通过Ping进行二次确认
|
||||
// 参考: https://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces
|
||||
|
||||
// 2、通过Ping接口确认服务是否正常
|
||||
QDBusInterface peerInter(sniServerName, "/" + list.last(), "org.freedesktop.DBus.Peer");
|
||||
QDBusReply<void> reply = peerInter.call("Ping");
|
||||
if (!reply.isValid())
|
||||
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, this);
|
||||
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);
|
||||
}
|
||||
}
|
@ -1,100 +0,0 @@
|
||||
// Copyright (C) 2011 ~ 2018 Deepin Technology Co., Ltd.
|
||||
// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#ifndef TRAYPLUGIN_H
|
||||
#define TRAYPLUGIN_H
|
||||
|
||||
#include "pluginsiteminterface.h"
|
||||
#include "dbus/dbustraymanager.h"
|
||||
#include "xembedtraywidget.h"
|
||||
#include "indicatortray.h"
|
||||
#include "indicatortraywidget.h"
|
||||
#include "snitraywidget.h"
|
||||
#include "system-trays/systemtrayscontroller.h"
|
||||
#include "dbus/sni/statusnotifierwatcher_interface.h"
|
||||
|
||||
#include <QSettings>
|
||||
#include <QLabel>
|
||||
|
||||
#include <mutex>
|
||||
#include <xcb/xcb.h>
|
||||
|
||||
class FashionTrayItem;
|
||||
namespace Dock {
|
||||
class TipsWidget;
|
||||
}
|
||||
|
||||
typedef struct _XDisplay Display;
|
||||
|
||||
class TrayPlugin : public QObject, PluginsItemInterface
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_INTERFACES(PluginsItemInterface)
|
||||
Q_PLUGIN_METADATA(IID "com.deepin.dock.PluginsItemInterface" FILE "tray.json")
|
||||
|
||||
public:
|
||||
explicit TrayPlugin(QObject *parent = nullptr);
|
||||
|
||||
const QString pluginName() const override;
|
||||
void init(PluginProxyInterface *proxyInter) override;
|
||||
bool pluginIsDisable() override;
|
||||
void displayModeChanged(const Dock::DisplayMode mode) override;
|
||||
void positionChanged(const Dock::Position position) override;
|
||||
QWidget *itemWidget(const QString &itemKey) override;
|
||||
QWidget *itemTipsWidget(const QString &itemKey) override;
|
||||
QWidget *itemPopupApplet(const QString &itemKey) override;
|
||||
int itemSortKey(const QString &itemKey) override;
|
||||
void setSortKey(const QString &itemKey, const int order) override;
|
||||
void refreshIcon(const QString &itemKey) override;
|
||||
void pluginSettingsChanged() override;
|
||||
|
||||
Dock::Position dockPosition() const;
|
||||
bool traysSortedInFashionMode();
|
||||
void saveValue(const QString &itemKey, const QString &key, const QVariant &value);
|
||||
const QVariant getValue(const QString &itemKey, const QString &key, const QVariant& fallback = QVariant());
|
||||
|
||||
private:
|
||||
void loadIndicator();
|
||||
bool isSystemTrayItem(const QString &itemKey);
|
||||
QString itemKeyOfTrayWidget(AbstractTrayWidget *trayWidget);
|
||||
Dock::DisplayMode displayMode();
|
||||
|
||||
private slots:
|
||||
void initXEmbed();
|
||||
void initSNI();
|
||||
void addTrayWidget(const QString &itemKey, AbstractTrayWidget *trayWidget);
|
||||
void sniItemsChanged();
|
||||
void xembedItemsChanged();
|
||||
void trayXEmbedAdded(const QString &itemKey, quint32 winId);
|
||||
void traySNIAdded(const QString &itemKey, const QString &sniServicePath);
|
||||
void trayIndicatorAdded(const QString &itemKey, const QString &indicatorName);
|
||||
void trayRemoved(const QString &itemKey, const bool deleteObject = true);
|
||||
void xembedItemChanged(quint32 winId);
|
||||
void switchToMode(const Dock::DisplayMode mode);
|
||||
void onRequestWindowAutoHide(const bool autoHide);
|
||||
void onRequestRefershWindowVisible();
|
||||
void onSNIItemStatusChanged(SNITrayWidget::ItemStatus status);
|
||||
|
||||
private:
|
||||
DBusTrayManager *m_trayInter;
|
||||
org::kde::StatusNotifierWatcher *m_sniWatcher;
|
||||
FashionTrayItem *m_fashionItem;
|
||||
SystemTraysController *m_systemTraysController;
|
||||
QTimer *m_refreshXEmbedItemsTimer;
|
||||
QTimer *m_refreshSNIItemsTimer;
|
||||
|
||||
QMap<QString, AbstractTrayWidget *> m_trayMap;
|
||||
QMap<QString, SNITrayWidget *> m_passiveSNITrayMap; //这个目前好像无用了
|
||||
QMap<QString, IndicatorTray*> m_indicatorMap; //这个有键盘跟license
|
||||
QMap<uint, char> m_registertedPID;
|
||||
|
||||
bool m_pluginLoaded;
|
||||
std::mutex m_sniMutex;
|
||||
|
||||
xcb_connection_t *xcb_connection;
|
||||
Display *m_display;
|
||||
};
|
||||
|
||||
#endif // TRAYPLUGIN_H
|
@ -1,590 +0,0 @@
|
||||
// Copyright (C) 2011 ~ 2018 Deepin Technology Co., Ltd.
|
||||
// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#include "constants.h"
|
||||
#include "xembedtraywidget.h"
|
||||
#include "utils.h"
|
||||
|
||||
#include <QWindow>
|
||||
#include <QPainter>
|
||||
#include <QX11Info>
|
||||
#include <QDebug>
|
||||
#include <QMouseEvent>
|
||||
#include <QProcess>
|
||||
#include <QThread>
|
||||
#include <QApplication>
|
||||
#include <QScreen>
|
||||
#include <QMap>
|
||||
#include <QGuiApplication>
|
||||
|
||||
#include <X11/extensions/shape.h>
|
||||
#include <X11/extensions/XTest.h>
|
||||
#include <X11/Xregion.h>
|
||||
|
||||
#include <xcb/composite.h>
|
||||
#include <xcb/xcb_image.h>
|
||||
#include <xcb/xproto.h>
|
||||
|
||||
#define NORMAL_WINDOW_PROP_NAME "WM_CLASS"
|
||||
#define WINE_WINDOW_PROP_NAME "__wine_prefix"
|
||||
#define IS_WINE_WINDOW_BY_WM_CLASS "explorer.exe"
|
||||
|
||||
static const qreal iconSize = PLUGIN_ICON_MAX_SIZE;
|
||||
|
||||
// this static var hold all suffix of tray widget keys.
|
||||
// that is in order to fix can not show multiple trays provide by one application,
|
||||
// so only one property: AppName is not enough to identify all trays.
|
||||
// here we add a suffix for every tray to fix this problem.
|
||||
// the first suffix is 1, second is 2, etc.
|
||||
// NOTE: the first suffix will be omit when construct the key of tray widget.
|
||||
static QMap<QString, QMap<quint32, int>> AppWinidSuffixMap;
|
||||
|
||||
using namespace Utils;
|
||||
|
||||
const QPoint rawXPosition(const QPoint &scaledPos)
|
||||
{
|
||||
QRect g = qApp->primaryScreen() ? qApp->primaryScreen()->geometry() : QRect();
|
||||
for (auto *screen : qApp->screens())
|
||||
{
|
||||
const QRect &sg = screen->geometry();
|
||||
if (sg.contains(scaledPos))
|
||||
{
|
||||
g = sg;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return g.topLeft() + (scaledPos - g.topLeft()) * qApp->devicePixelRatio();
|
||||
}
|
||||
|
||||
void sni_cleanup_xcb_image(void *data)
|
||||
{
|
||||
xcb_image_destroy(static_cast<xcb_image_t*>(data));
|
||||
}
|
||||
|
||||
XEmbedTrayWidget::XEmbedTrayWidget(quint32 winId, xcb_connection_t *cnn, Display *disp, QWidget *parent)
|
||||
: AbstractTrayWidget(parent)
|
||||
, m_windowId(winId)
|
||||
, m_appName(getAppNameForWindow(winId))
|
||||
, m_valid(true)
|
||||
, m_xcbCnn(cnn)
|
||||
, m_display(disp)
|
||||
{
|
||||
wrapWindow();
|
||||
setOwnerPID(getWindowPID(winId));
|
||||
|
||||
m_updateTimer = new QTimer(this);
|
||||
m_updateTimer->setInterval(100);
|
||||
m_updateTimer->setSingleShot(true);
|
||||
|
||||
m_sendHoverEvent = new QTimer(this);
|
||||
m_sendHoverEvent->setInterval(100);
|
||||
m_sendHoverEvent->setSingleShot(true);
|
||||
|
||||
connect(m_updateTimer, &QTimer::timeout, this, &XEmbedTrayWidget::refershIconImage);
|
||||
|
||||
setMouseTracking(true);
|
||||
connect(m_sendHoverEvent, &QTimer::timeout, this, &XEmbedTrayWidget::sendHoverEvent);
|
||||
|
||||
m_updateTimer->start();
|
||||
}
|
||||
|
||||
XEmbedTrayWidget::~XEmbedTrayWidget()
|
||||
{
|
||||
AppWinidSuffixMap[m_appName].remove(m_windowId);
|
||||
}
|
||||
|
||||
QString XEmbedTrayWidget::itemKeyForConfig()
|
||||
{
|
||||
return QString("window:%1").arg(getAppNameForWindow(m_windowId));
|
||||
}
|
||||
|
||||
void XEmbedTrayWidget::showEvent(QShowEvent *e)
|
||||
{
|
||||
QWidget::showEvent(e);
|
||||
|
||||
m_updateTimer->start();
|
||||
}
|
||||
|
||||
void XEmbedTrayWidget::paintEvent(QPaintEvent *e)
|
||||
{
|
||||
Q_UNUSED(e);
|
||||
if (m_image.isNull())
|
||||
return m_updateTimer->start();
|
||||
|
||||
QPainter painter;
|
||||
painter.begin(this);
|
||||
painter.setRenderHint(QPainter::Antialiasing);
|
||||
|
||||
const QRectF &rf = QRectF(rect());
|
||||
const QRectF &rfp = QRectF(m_image.rect());
|
||||
const QPointF &p = rf.center() - rfp.center() / m_image.devicePixelRatioF();
|
||||
painter.drawImage(p, m_image);
|
||||
|
||||
painter.end();
|
||||
}
|
||||
|
||||
void XEmbedTrayWidget::mouseMoveEvent(QMouseEvent *e)
|
||||
{
|
||||
AbstractTrayWidget::mouseMoveEvent(e);
|
||||
|
||||
// ignore the touchEvent
|
||||
if (e->source() == Qt::MouseEventSynthesizedByQt) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_sendHoverEvent->start();
|
||||
}
|
||||
|
||||
void XEmbedTrayWidget::configContainerPosition()
|
||||
{
|
||||
auto c = IS_WAYLAND_DISPLAY ? m_xcbCnn : QX11Info::connection();
|
||||
if (!c) {
|
||||
qWarning() << "QX11Info::connection() is " << c;
|
||||
return;
|
||||
}
|
||||
|
||||
const QPoint p(rawXPosition(QCursor::pos()));
|
||||
|
||||
const uint32_t containerVals[4] = {uint32_t(p.x()), uint32_t(p.y()), 1, 1};
|
||||
xcb_configure_window(c, m_containerWid,
|
||||
XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y | XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT,
|
||||
containerVals);
|
||||
|
||||
|
||||
// move the actual tray window to {0,0}, because tray icons from some wine
|
||||
// applications (QQ, TIM, etc...) may somehow moved to very long distance positions.
|
||||
const uint32_t trayVals[2] = { 0, 0 };
|
||||
xcb_configure_window(c, m_windowId, XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, trayVals);
|
||||
|
||||
xcb_flush(c);
|
||||
}
|
||||
|
||||
void XEmbedTrayWidget::wrapWindow()
|
||||
{
|
||||
auto c = IS_WAYLAND_DISPLAY ? m_xcbCnn : QX11Info::connection();
|
||||
if (!c) {
|
||||
qWarning() << "QX11Info::connection() is " << c;
|
||||
return;
|
||||
}
|
||||
|
||||
auto cookie = xcb_get_geometry(c, m_windowId);
|
||||
xcb_get_geometry_reply_t *clientGeom(xcb_get_geometry_reply(c, cookie, Q_NULLPTR));
|
||||
if (!clientGeom) {
|
||||
m_valid = false;
|
||||
return;
|
||||
}
|
||||
free(clientGeom);
|
||||
|
||||
//create a container window
|
||||
const auto ratio = devicePixelRatioF();
|
||||
auto screen = xcb_setup_roots_iterator (xcb_get_setup (c)).data;
|
||||
m_containerWid = xcb_generate_id(c);
|
||||
uint32_t values[2];
|
||||
auto mask = XCB_CW_BACK_PIXEL | XCB_CW_OVERRIDE_REDIRECT;
|
||||
values[0] = ParentRelative; //draw a solid background so the embedded icon doesn't get garbage in it
|
||||
values[1] = true; //bypass wM
|
||||
xcb_create_window (c, /* connection */
|
||||
XCB_COPY_FROM_PARENT, /* depth */
|
||||
m_containerWid, /* window Id */
|
||||
screen->root, /* parent window */
|
||||
0, 0, /* x, y */
|
||||
iconSize * ratio, iconSize * ratio, /* width, height */
|
||||
0, /* border_width */
|
||||
XCB_WINDOW_CLASS_INPUT_OUTPUT,/* class */
|
||||
screen->root_visual, /* visual */
|
||||
mask, values); /* masks */
|
||||
|
||||
/*
|
||||
We need the window to exist and be mapped otherwise the child won't render it's contents
|
||||
|
||||
We also need it to exist in the right place to get the clicks working as GTK will check sendEvent locations to see if our window is in the right place. So even though our contents are drawn via compositing we still put this window in the right place
|
||||
|
||||
We can't composite it away anything parented owned by the root window (apparently)
|
||||
Stack Under works in the non composited case, but it doesn't seem to work in kwin's composited case (probably need set relevant NETWM hint)
|
||||
|
||||
As a last resort set opacity to 0 just to make sure this container never appears
|
||||
*/
|
||||
// const uint32_t stackBelowData[] = {XCB_STACK_MODE_BELOW};
|
||||
// xcb_configure_window(c, m_containerWid, XCB_CONFIG_WINDOW_STACK_MODE, stackBelowData);
|
||||
|
||||
if (!IS_WAYLAND_DISPLAY) {
|
||||
QWindow * win = QWindow::fromWinId(m_containerWid);
|
||||
win->setOpacity(0);
|
||||
} else {
|
||||
const char* opacityName = "_NET_WM_WINDOW_OPACITY\0";
|
||||
xcb_intern_atom_cookie_t opacityCookie = xcb_intern_atom(c, false, strlen(opacityName), opacityName);
|
||||
xcb_intern_atom_reply_t *opacityReply = xcb_intern_atom_reply(c, opacityCookie, 0);
|
||||
xcb_atom_t opacityAtom = opacityReply->atom;
|
||||
quint32 opacity = 10;
|
||||
xcb_change_property(c,
|
||||
XCB_PROP_MODE_REPLACE,
|
||||
m_containerWid,
|
||||
opacityAtom,
|
||||
XCB_ATOM_CARDINAL,
|
||||
32,
|
||||
1,
|
||||
(uchar *)&opacity);
|
||||
}
|
||||
|
||||
// setX11PassMouseEvent(true);
|
||||
|
||||
xcb_flush(c);
|
||||
|
||||
xcb_map_window(c, m_containerWid);
|
||||
|
||||
xcb_reparent_window(c, m_windowId,
|
||||
m_containerWid,
|
||||
0, 0);
|
||||
|
||||
/*
|
||||
* Render the embedded window offscreen
|
||||
*/
|
||||
xcb_composite_redirect_window(c, m_windowId, XCB_COMPOSITE_REDIRECT_MANUAL);
|
||||
|
||||
|
||||
/* we grab the window, but also make sure it's automatically reparented back
|
||||
* to the root window if we should die.
|
||||
*/
|
||||
xcb_change_save_set(c, XCB_SET_MODE_INSERT, m_windowId);
|
||||
|
||||
//tell client we're embedding it
|
||||
// xembed_message_send(m_windowId, XEMBED_EMBEDDED_NOTIFY, m_containerWid, 0, 0);
|
||||
|
||||
//move window we're embedding
|
||||
/*
|
||||
const uint32_t windowMoveConfigVals[2] = { 0, 0 };
|
||||
xcb_configure_window(c, m_windowId,
|
||||
XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y,
|
||||
windowMoveCentially quitting the application. Returns onfigVals);
|
||||
*/
|
||||
|
||||
//if the window is a clearly stupid size resize to be something sensible
|
||||
//this is needed as chormium and such when resized just fill the icon with transparent space and only draw in the middle
|
||||
//however spotify does need this as by default the window size is 900px wide.
|
||||
//use an artbitrary heuristic to make sure icons are always sensible
|
||||
// if (clientGeom->width > iconSize || clientGeom->height > iconSize )
|
||||
{
|
||||
const uint32_t windowMoveConfigVals[2] = { uint32_t(iconSize * ratio), uint32_t(iconSize * ratio) };
|
||||
xcb_configure_window(c, m_windowId,
|
||||
XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT,
|
||||
windowMoveConfigVals);
|
||||
}
|
||||
|
||||
//show the embedded window otherwise nothing happens
|
||||
xcb_map_window(c, m_windowId);
|
||||
|
||||
// xcb_clear_area(c, 0, m_windowId, 0, 0, qMin(clientGeom->width, iconSize), qMin(clientGeom->height, iconSize));
|
||||
|
||||
xcb_flush(c);
|
||||
// setWindowOnTop(false);
|
||||
setWindowOnTop(true);
|
||||
setX11PassMouseEvent(true);
|
||||
}
|
||||
|
||||
void XEmbedTrayWidget::sendHoverEvent()
|
||||
{
|
||||
if (!rect().contains(mapFromGlobal(QCursor::pos()))) {
|
||||
return;
|
||||
}
|
||||
|
||||
// fake enter event
|
||||
const QPoint p(rawXPosition(QCursor::pos()));
|
||||
configContainerPosition();
|
||||
setX11PassMouseEvent(false);
|
||||
setWindowOnTop(true);
|
||||
Display *display = IS_WAYLAND_DISPLAY ? m_display : QX11Info::display();
|
||||
if (display) {
|
||||
XTestFakeMotionEvent(display, 0, p.x(), p.y(), CurrentTime);
|
||||
XFlush(display);
|
||||
}
|
||||
|
||||
QTimer::singleShot(100, this, [=] { setX11PassMouseEvent(true); });
|
||||
}
|
||||
|
||||
void XEmbedTrayWidget::updateIcon()
|
||||
{
|
||||
// if (!isVisible() && !m_active)
|
||||
// return;
|
||||
|
||||
m_updateTimer->start();
|
||||
}
|
||||
|
||||
//void TrayWidget::hideIcon()
|
||||
//{
|
||||
// auto c = QX11Info::connection();
|
||||
|
||||
// const uint32_t stackAboveData[] = {XCB_STACK_MODE_BELOW};
|
||||
// xcb_configure_window(c, m_containerWid, XCB_CONFIG_WINDOW_STACK_MODE, stackAboveData);
|
||||
|
||||
// const uint32_t windowMoveConfigVals[2] = {0, 0};
|
||||
// xcb_configure_window(c, m_containerWid,
|
||||
// XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y,
|
||||
// windowMoveConfigVals);
|
||||
|
||||
// hide();
|
||||
//}
|
||||
|
||||
void XEmbedTrayWidget::sendClick(uint8_t mouseButton, int x, int y)
|
||||
{
|
||||
if (isBadWindow())
|
||||
return;
|
||||
|
||||
m_sendHoverEvent->stop();
|
||||
|
||||
const QPoint p(rawXPosition(QPoint(x, y)));
|
||||
configContainerPosition();
|
||||
setX11PassMouseEvent(false);
|
||||
setWindowOnTop(true);
|
||||
|
||||
Display *display = IS_WAYLAND_DISPLAY ? m_display : QX11Info::display();
|
||||
XTestFakeMotionEvent(display, 0, p.x(), p.y(), CurrentTime);
|
||||
XFlush(display);
|
||||
XTestFakeButtonEvent(display, mouseButton, true, CurrentTime);
|
||||
XFlush(display);
|
||||
XTestFakeButtonEvent(display, mouseButton, false, CurrentTime);
|
||||
XFlush(display);
|
||||
QTimer::singleShot(100, this, [=] { setX11PassMouseEvent(true); });
|
||||
}
|
||||
|
||||
// NOTE: WM_NAME may can not obtain successfully
|
||||
QString XEmbedTrayWidget::getWindowProperty(quint32 winId, QString propName)
|
||||
{
|
||||
const auto display = IS_WAYLAND_DISPLAY ? XOpenDisplay(nullptr) : QX11Info::display();
|
||||
if (!display) {
|
||||
qWarning() << "QX11Info::display() is " << display;
|
||||
return QString();
|
||||
}
|
||||
|
||||
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);
|
||||
if (IS_WAYLAND_DISPLAY)
|
||||
XCloseDisplay(display);
|
||||
|
||||
return QString::fromLocal8Bit((char*)prop_return);
|
||||
}
|
||||
|
||||
QString XEmbedTrayWidget::toXEmbedKey(quint32 winId)
|
||||
{
|
||||
return QString("window:%1").arg(winId);
|
||||
}
|
||||
|
||||
bool XEmbedTrayWidget::isXEmbedKey(const QString &itemKey)
|
||||
{
|
||||
return itemKey.startsWith("window:");
|
||||
}
|
||||
|
||||
void XEmbedTrayWidget::refershIconImage()
|
||||
{
|
||||
const auto ratio = devicePixelRatioF();
|
||||
auto c = IS_WAYLAND_DISPLAY ? m_xcbCnn : QX11Info::connection();
|
||||
if (!c) {
|
||||
qWarning() << "QX11Info::connection() is " << c;
|
||||
return;
|
||||
}
|
||||
|
||||
auto cookie = xcb_get_geometry(c, m_windowId);
|
||||
xcb_get_geometry_reply_t *geom(xcb_get_geometry_reply(c, cookie, Q_NULLPTR));
|
||||
if (!geom) {
|
||||
return;
|
||||
}
|
||||
|
||||
xcb_expose_event_t expose;
|
||||
expose.response_type = XCB_EXPOSE;
|
||||
expose.window = m_containerWid;
|
||||
expose.x = 0;
|
||||
expose.y = 0;
|
||||
expose.width = iconSize * ratio;
|
||||
expose.height = iconSize * ratio;
|
||||
xcb_send_event_checked(c, false, m_containerWid, XCB_EVENT_MASK_VISIBILITY_CHANGE, reinterpret_cast<char *>(&expose));
|
||||
xcb_flush(c);
|
||||
|
||||
xcb_image_t *image = xcb_image_get(c, m_windowId, 0, 0, geom->width, geom->height, ~0, XCB_IMAGE_FORMAT_Z_PIXMAP);
|
||||
if (!image) {
|
||||
free(geom);
|
||||
return;
|
||||
}
|
||||
|
||||
QImage qimage(image->data, image->width, image->height, image->stride, QImage::Format_ARGB32, sni_cleanup_xcb_image, image);
|
||||
if (qimage.isNull()) {
|
||||
free(geom);
|
||||
return;
|
||||
}
|
||||
|
||||
m_image = qimage.scaled(iconSize * ratio, iconSize * ratio, Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
||||
m_image.setDevicePixelRatio(ratio);
|
||||
|
||||
update();
|
||||
Q_EMIT iconChanged();
|
||||
|
||||
if (!isVisible()) {
|
||||
Q_EMIT needAttention();
|
||||
}
|
||||
}
|
||||
|
||||
QString XEmbedTrayWidget::getAppNameForWindow(quint32 winId)
|
||||
{
|
||||
QString appName;
|
||||
do {
|
||||
// is normal application
|
||||
appName = getWindowProperty(winId, NORMAL_WINDOW_PROP_NAME);
|
||||
if (!appName.isEmpty() && appName != IS_WINE_WINDOW_BY_WM_CLASS) {
|
||||
break;
|
||||
}
|
||||
|
||||
// is wine application
|
||||
appName = getWindowProperty(winId, WINE_WINDOW_PROP_NAME).split("/").last();
|
||||
if (!appName.isEmpty()) {
|
||||
break;
|
||||
}
|
||||
|
||||
// fallback to window id
|
||||
appName = QString::number(winId);
|
||||
} while (false);
|
||||
|
||||
return appName;
|
||||
}
|
||||
|
||||
//int XEmbedTrayWidget::getTrayWidgetKeySuffix(const QString &appName, quint32 winId)
|
||||
//{
|
||||
// int suffix = AppWinidSuffixMap.value(appName).value(winId, 0);
|
||||
|
||||
// // return the exist suffix
|
||||
// if (suffix != 0) {
|
||||
// return suffix;
|
||||
// }
|
||||
|
||||
// // it is the first window for this application
|
||||
// if (!AppWinidSuffixMap.contains(appName)) {
|
||||
// QMap<quint32, int> winIdSuffixMap;
|
||||
// winIdSuffixMap.insert(winId, 1);
|
||||
// AppWinidSuffixMap.insert(appName, winIdSuffixMap);
|
||||
// return 1;
|
||||
// }
|
||||
|
||||
// QMap<quint32, int> subMap = AppWinidSuffixMap.value(appName);
|
||||
// QList<int> suffixList = subMap.values();
|
||||
|
||||
// // suffix will never be 0
|
||||
// suffixList.removeAll(0);
|
||||
// std::sort(suffixList.begin(), suffixList.end());
|
||||
|
||||
// // get the minimum of useable suffix
|
||||
// int index = 0;
|
||||
// for (; index < suffixList.size(); ++index) {
|
||||
// if (suffixList.at(index) != index + 1) {
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// suffix = index + 1;
|
||||
|
||||
// subMap.insert(winId, suffix);
|
||||
// AppWinidSuffixMap.insert(appName, subMap);
|
||||
|
||||
// return suffix;
|
||||
//}
|
||||
|
||||
void XEmbedTrayWidget::setX11PassMouseEvent(const bool pass)
|
||||
{
|
||||
if (IS_WAYLAND_DISPLAY) {
|
||||
//会导致wayland下鼠标穿透到桌面,所以直接return掉
|
||||
return;
|
||||
}
|
||||
|
||||
if (pass)
|
||||
{
|
||||
XShapeCombineRectangles(QX11Info::display(), m_containerWid, ShapeBounding, 0, 0, nullptr, 0, ShapeSet, YXBanded);
|
||||
XShapeCombineRectangles(QX11Info::display(), m_containerWid, ShapeInput, 0, 0, nullptr, 0, ShapeSet, YXBanded);
|
||||
}
|
||||
else
|
||||
{
|
||||
XRectangle rectangle;
|
||||
rectangle.x = 0;
|
||||
rectangle.y = 0;
|
||||
rectangle.width = 1;
|
||||
rectangle.height = 1;
|
||||
|
||||
XShapeCombineRectangles(QX11Info::display(), m_containerWid, ShapeBounding, 0, 0, &rectangle, 1, ShapeSet, YXBanded);
|
||||
XShapeCombineRectangles(QX11Info::display(), m_containerWid, ShapeInput, 0, 0, &rectangle, 1, ShapeSet, YXBanded);
|
||||
}
|
||||
|
||||
XFlush(QX11Info::display());
|
||||
}
|
||||
|
||||
void XEmbedTrayWidget::setWindowOnTop(const bool top)
|
||||
{
|
||||
auto c = IS_WAYLAND_DISPLAY ? m_xcbCnn : QX11Info::connection();
|
||||
if (!c) {
|
||||
qWarning() << "QX11Info::connection() is " << c;
|
||||
return;
|
||||
}
|
||||
const uint32_t stackAboveData[] = {top ? XCB_STACK_MODE_ABOVE : XCB_STACK_MODE_BELOW};
|
||||
xcb_configure_window(c, m_containerWid, XCB_CONFIG_WINDOW_STACK_MODE, stackAboveData);
|
||||
xcb_flush(c);
|
||||
}
|
||||
|
||||
bool XEmbedTrayWidget::isBadWindow()
|
||||
{
|
||||
auto c = IS_WAYLAND_DISPLAY ? m_xcbCnn : QX11Info::connection();
|
||||
|
||||
auto cookie = xcb_get_geometry(c, m_windowId);
|
||||
xcb_get_geometry_reply_t *clientGeom = xcb_get_geometry_reply(c, cookie, Q_NULLPTR);
|
||||
bool result = clientGeom ? false : true;
|
||||
|
||||
free(clientGeom);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
uint XEmbedTrayWidget::getWindowPID(uint winId)
|
||||
{
|
||||
const auto display = IS_WAYLAND_DISPLAY ? XOpenDisplay(nullptr) : QX11Info::display();
|
||||
if (!display) {
|
||||
qWarning() << "QX11Info::connection() is " << display;
|
||||
return 0;
|
||||
}
|
||||
|
||||
Atom nameAtom = XInternAtom(display, "_NET_WM_PID", 1);
|
||||
Atom type;
|
||||
int format, status;
|
||||
|
||||
unsigned long nitems, after;
|
||||
unsigned char *data;
|
||||
unsigned int pid = 0;
|
||||
|
||||
status = XGetWindowProperty(display, winId, nameAtom, 0, 1024, 0,
|
||||
XInternAtom(display, "CARDINAL", 0), &type, &format, &nitems, &after, &data);
|
||||
if (status == Success && data) {
|
||||
pid = *((uint*)data);
|
||||
XFree(data);
|
||||
}
|
||||
|
||||
if (IS_WAYLAND_DISPLAY)
|
||||
XCloseDisplay(display);
|
||||
|
||||
return pid;
|
||||
}
|
@ -1,67 +0,0 @@
|
||||
// Copyright (C) 2011 ~ 2018 Deepin Technology Co., Ltd.
|
||||
// SPDX-FileCopyrightText: 2018 - 2023 UnionTech Software Technology Co., Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
#ifndef XEMBEDTRAYWIDGET_H
|
||||
#define XEMBEDTRAYWIDGET_H
|
||||
|
||||
#include "abstracttraywidget.h"
|
||||
|
||||
#include <QWidget>
|
||||
#include <QTimer>
|
||||
|
||||
#include <xcb/xcb.h>
|
||||
|
||||
typedef struct _XDisplay Display;
|
||||
|
||||
class XEmbedTrayWidget : public AbstractTrayWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit XEmbedTrayWidget(quint32 winId, xcb_connection_t *cnn = nullptr, Display *disp = nullptr, QWidget *parent = nullptr);
|
||||
~XEmbedTrayWidget();
|
||||
|
||||
QString itemKeyForConfig() override;
|
||||
void updateIcon() override;
|
||||
void sendClick(uint8_t mouseButton, int x, int y) override;
|
||||
|
||||
static QString getWindowProperty(quint32 winId, QString propName);
|
||||
static QString toXEmbedKey(quint32 winId);
|
||||
static uint getWindowPID(quint32 winId);
|
||||
static bool isXEmbedKey(const QString &itemKey);
|
||||
virtual bool isValid() override {return m_valid;}
|
||||
|
||||
private:
|
||||
void showEvent(QShowEvent *e) override;
|
||||
void paintEvent(QPaintEvent *e) override;
|
||||
void mouseMoveEvent(QMouseEvent *e) override;
|
||||
void configContainerPosition();
|
||||
|
||||
void wrapWindow();
|
||||
void sendHoverEvent();
|
||||
void refershIconImage();
|
||||
|
||||
static QString getAppNameForWindow(quint32 winId);
|
||||
|
||||
private slots:
|
||||
void setX11PassMouseEvent(const bool pass);
|
||||
void setWindowOnTop(const bool top);
|
||||
bool isBadWindow();
|
||||
|
||||
private:
|
||||
bool m_active = false;
|
||||
WId m_windowId;
|
||||
WId m_containerWid;
|
||||
QImage m_image;
|
||||
QString m_appName;
|
||||
|
||||
QTimer *m_updateTimer;
|
||||
QTimer *m_sendHoverEvent;
|
||||
bool m_valid;
|
||||
xcb_connection_t *m_xcbCnn;
|
||||
Display* m_display;
|
||||
};
|
||||
|
||||
#endif // XEMBEDTRAYWIDGET_H
|