mirror of
https://github.com/linuxdeepin/dde-dock.git
synced 2025-06-02 15:45:21 +00:00

完成插件区域的引用图标加载、快捷设置的展示、老插件的加载等功能 Log: 完成特效模式下右侧插件区域的功能 Influence: v23任务栏右侧插件区域 Task: https://pms.uniontech.com/task-view-110311.html Change-Id: I1599907d4529c57070ee2e21b70cc0c17f132e5e
509 lines
14 KiB
C++
509 lines
14 KiB
C++
/*
|
||
* Copyright (C) 2011 ~ 2018 Deepin Technology Co., Ltd.
|
||
*
|
||
* Author: listenerri <listenerri@gmail.com>
|
||
*
|
||
* Maintainer: listenerri <listenerri@gmail.com>
|
||
*
|
||
* This program is free software: you can redistribute it and/or modify
|
||
* it under the terms of the GNU General Public License as published by
|
||
* the Free Software Foundation, either version 3 of the License, or
|
||
* any later version.
|
||
*
|
||
* This program is distributed in the hope that it will be useful,
|
||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
* GNU General Public License for more details.
|
||
*
|
||
* You should have received a copy of the GNU General Public License
|
||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||
*/
|
||
|
||
#include "systempluginitem.h"
|
||
#include "utils.h"
|
||
#include "dockpopupwindow.h"
|
||
|
||
#include <QProcess>
|
||
#include <QDebug>
|
||
#include <QPointer>
|
||
|
||
#include <xcb/xproto.h>
|
||
|
||
Dock::Position SystemPluginItem::DockPosition = Dock::Position::Top;
|
||
QPointer<DockPopupWindow> SystemPluginItem::PopupWindow = nullptr;
|
||
|
||
SystemPluginItem::SystemPluginItem(PluginsItemInterface *const pluginInter, const QString &itemKey, QWidget *parent)
|
||
: BaseTrayWidget(parent)
|
||
, m_popupShown(false)
|
||
, m_tapAndHold(false)
|
||
, 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");
|
||
PopupWindow = arrowRectangle;
|
||
connect(qApp, &QApplication::aboutToQuit, PopupWindow, &DockPopupWindow::deleteLater);
|
||
}
|
||
|
||
// 必须初始化父窗口,否则当主题切换之后再设置父窗口的时候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, &SystemPluginItem::showHoverTips);
|
||
connect(m_popupAdjustDelayTimer, &QTimer::timeout, this, &SystemPluginItem::updatePopupPosition, Qt::QueuedConnection);
|
||
connect(&m_contextMenu, &QMenu::triggered, this, &SystemPluginItem::menuActionClicked);
|
||
|
||
if (m_gsettings)
|
||
connect(m_gsettings, &QGSettings::changed, this, &SystemPluginItem::onGSettingsChanged);
|
||
|
||
grabGesture(Qt::TapAndHoldGesture);
|
||
}
|
||
|
||
SystemPluginItem::~SystemPluginItem()
|
||
{
|
||
if (m_popupShown)
|
||
popupWindowAccept();
|
||
}
|
||
|
||
QString SystemPluginItem::itemKeyForConfig()
|
||
{
|
||
return m_itemKey;
|
||
}
|
||
|
||
void SystemPluginItem::updateIcon()
|
||
{
|
||
m_pluginInter->refreshIcon(m_itemKey);
|
||
}
|
||
|
||
void SystemPluginItem::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 *SystemPluginItem::trayTipsWidget()
|
||
{
|
||
if (m_pluginInter->itemTipsWidget(m_itemKey)) {
|
||
m_pluginInter->itemTipsWidget(m_itemKey)->setAccessibleName(m_pluginInter->pluginName());
|
||
}
|
||
|
||
return m_pluginInter->itemTipsWidget(m_itemKey);
|
||
}
|
||
|
||
QWidget *SystemPluginItem::trayPopupApplet()
|
||
{
|
||
if (m_pluginInter->itemPopupApplet(m_itemKey)) {
|
||
m_pluginInter->itemPopupApplet(m_itemKey)->setAccessibleName(m_pluginInter->pluginName());
|
||
}
|
||
|
||
return m_pluginInter->itemPopupApplet(m_itemKey);
|
||
}
|
||
|
||
const QString SystemPluginItem::trayClickCommand()
|
||
{
|
||
return m_pluginInter->itemCommand(m_itemKey);
|
||
}
|
||
|
||
const QString SystemPluginItem::contextMenu() const
|
||
{
|
||
return m_pluginInter->itemContextMenu(m_itemKey);
|
||
}
|
||
|
||
void SystemPluginItem::invokedMenuItem(const QString &menuId, const bool checked)
|
||
{
|
||
m_pluginInter->invokedMenuItem(m_itemKey, menuId, checked);
|
||
}
|
||
|
||
QWidget *SystemPluginItem::centralWidget() const
|
||
{
|
||
return m_centralWidget;
|
||
}
|
||
|
||
void SystemPluginItem::detachPluginWidget()
|
||
{
|
||
QWidget *widget = m_pluginInter->itemWidget(m_itemKey);
|
||
if (widget)
|
||
widget->setParent(nullptr);
|
||
}
|
||
|
||
bool SystemPluginItem::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 BaseTrayWidget::event(event);
|
||
}
|
||
|
||
void SystemPluginItem::enterEvent(QEvent *event)
|
||
{
|
||
if (checkGSettingsControl()) {
|
||
//网络需要显示Tips,需要特殊处理。
|
||
if (m_pluginInter->pluginName() != "network")
|
||
return;
|
||
}
|
||
|
||
// 触屏不显示hover效果
|
||
if (!qApp->property(IS_TOUCH_STATE).toBool()) {
|
||
m_popupTipsDelayTimer->start();
|
||
}
|
||
update();
|
||
|
||
BaseTrayWidget::enterEvent(event);
|
||
}
|
||
|
||
void SystemPluginItem::leaveEvent(QEvent *event)
|
||
{
|
||
m_popupTipsDelayTimer->stop();
|
||
|
||
// auto hide if popup is not model window
|
||
if (m_popupShown && !PopupWindow->model())
|
||
hidePopup();
|
||
|
||
update();
|
||
|
||
BaseTrayWidget::leaveEvent(event);
|
||
}
|
||
|
||
void SystemPluginItem::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();
|
||
}
|
||
|
||
BaseTrayWidget::mousePressEvent(event);
|
||
}
|
||
|
||
void SystemPluginItem::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());
|
||
}
|
||
|
||
BaseTrayWidget::mouseReleaseEvent(event);
|
||
}
|
||
|
||
void SystemPluginItem::showEvent(QShowEvent *event)
|
||
{
|
||
QTimer::singleShot(0, this, [ = ] {
|
||
onGSettingsChanged("enable");
|
||
});
|
||
|
||
return BaseTrayWidget::showEvent(event);
|
||
}
|
||
|
||
const QPoint SystemPluginItem::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 SystemPluginItem::topleftPoint() const
|
||
{
|
||
QPoint p;
|
||
const QWidget *w = this;
|
||
do {
|
||
p += w->pos();
|
||
w = qobject_cast<QWidget *>(w->parent());
|
||
} while (w);
|
||
|
||
return p;
|
||
}
|
||
|
||
void SystemPluginItem::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 SystemPluginItem::hideNonModel()
|
||
{
|
||
// auto hide if popup is not model window
|
||
if (m_popupShown && !PopupWindow->model())
|
||
hidePopup();
|
||
}
|
||
|
||
void SystemPluginItem::popupWindowAccept()
|
||
{
|
||
if (!PopupWindow->isVisible())
|
||
return;
|
||
|
||
disconnect(PopupWindow.data(), &DockPopupWindow::accept, this, &SystemPluginItem::popupWindowAccept);
|
||
|
||
hidePopup();
|
||
}
|
||
|
||
void SystemPluginItem::showPopupApplet(QWidget *const applet)
|
||
{
|
||
if (!applet)
|
||
return;
|
||
|
||
// another model popup window already exists
|
||
if (PopupWindow->model()) {
|
||
applet->setVisible(false);
|
||
return;
|
||
}
|
||
|
||
showPopupWindow(applet, true);
|
||
}
|
||
|
||
void SystemPluginItem::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, &SystemPluginItem::popupWindowAccept, Qt::UniqueConnection);
|
||
}
|
||
|
||
void SystemPluginItem::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 SystemPluginItem::checkAndResetTapHoldGestureState()
|
||
{
|
||
bool ret = m_tapAndHold;
|
||
m_tapAndHold = false;
|
||
return ret;
|
||
}
|
||
|
||
void SystemPluginItem::gestureEvent(QGestureEvent *event)
|
||
{
|
||
if (!event)
|
||
return;
|
||
|
||
QGesture *gesture = event->gesture(Qt::TapAndHoldGesture);
|
||
|
||
if (!gesture)
|
||
return;
|
||
|
||
qDebug() << "SystemTray: got TapAndHoldGesture";
|
||
|
||
m_tapAndHold = true;
|
||
}
|
||
|
||
void SystemPluginItem::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 SystemPluginItem::menuActionClicked(QAction *action)
|
||
{
|
||
invokedMenuItem(action->data().toString(), true);
|
||
}
|
||
|
||
void SystemPluginItem::onContextMenuAccepted()
|
||
{
|
||
emit requestRefershWindowVisible();
|
||
emit requestWindowAutoHide(true);
|
||
}
|
||
|
||
void SystemPluginItem::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 SystemPluginItem::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 SystemPluginItem::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()));
|
||
}
|
||
|
||
QPixmap SystemPluginItem::icon()
|
||
{
|
||
return QPixmap();
|
||
}
|