feat: 参照dde-weather重构插件,修复显示与弹窗定位

- QML 根元素使用 AppletItem,参照 dde-weather 插件实现
- 使用 Panel.rootObject.dockItemMaxSize 适配任务栏图标尺寸
- dockOrder 设为 21,定位在系统托盘左侧
- 使用 PanelPopup + PanelToolTip + TapHandler 实现点击弹窗和悬停提示
- 弹窗打开前设置 DockPanelPositioner.bounding 修正弹窗定位
- C++ 后端新增 dbusAvailable 属性,D-Bus 不可用时优雅降级
- 使用 isServiceRegistered 正确检测 D-Bus 服务可用性
- install.sh 改用 SCRIPT_DIR 自动定位项目根目录
This commit is contained in:
2026-07-13 20:21:39 +08:00
parent 6654d0d102
commit 9fb80cdfc8
4 changed files with 179 additions and 93 deletions
+22 -4
View File
@@ -6,6 +6,7 @@
#include <pluginfactory.h>
#include <QDBusConnection>
#include <QDBusConnectionInterface>
#include <QDBusPendingReply>
#include <QDebug>
#include <QJsonDocument>
@@ -26,6 +27,7 @@ GraphicsDriverApplet::GraphicsDriverApplet(QObject *parent)
, m_progressTimer(new QTimer(this))
, m_installProgress(0)
, m_isInstalling(false)
, m_dbusAvailable(false)
{
}
@@ -36,15 +38,14 @@ GraphicsDriverApplet::~GraphicsDriverApplet()
bool GraphicsDriverApplet::load()
{
initDBusConnection();
connect(m_progressTimer, &QTimer::timeout, [this]() {
// Poll progress
});
return DApplet::load();
}
bool GraphicsDriverApplet::init()
{
refreshDeviceInfo();
if (m_dbusAvailable) {
refreshDeviceInfo();
}
return DApplet::init();
}
@@ -68,6 +69,11 @@ bool GraphicsDriverApplet::isInstalling() const
return m_isInstalling;
}
bool GraphicsDriverApplet::dbusAvailable() const
{
return m_dbusAvailable;
}
void GraphicsDriverApplet::refreshDeviceInfo()
{
if (!m_dbusInterface || !m_dbusInterface->isValid()) {
@@ -215,6 +221,13 @@ void GraphicsDriverApplet::initDBusConnection()
return;
}
// 检查服务是否已注册
bool registered = bus.interface()->isServiceRegistered(DBUS_SERVICE);
if (!registered) {
qWarning() << "GraphicsDriver D-Bus service is not registered";
return;
}
m_dbusInterface = new QDBusInterface(
DBUS_SERVICE,
DBUS_PATH,
@@ -228,8 +241,13 @@ void GraphicsDriverApplet::initDBusConnection()
return;
}
m_dbusAvailable = true;
emit dbusAvailableChanged();
connect(m_dbusInterface, SIGNAL(ReportProgress(QString)),
this, SLOT(onReportProgress(QString)));
qDebug() << "GraphicsDriver D-Bus connected successfully";
}
void GraphicsDriverApplet::setInstalling(bool installing)
+4
View File
@@ -22,6 +22,7 @@ class GraphicsDriverApplet : public DApplet
Q_PROPERTY(QString deviceInfo READ deviceInfo NOTIFY deviceInfoChanged)
Q_PROPERTY(int installProgress READ installProgress NOTIFY installProgressChanged)
Q_PROPERTY(bool isInstalling READ isInstalling NOTIFY isInstallingChanged)
Q_PROPERTY(bool dbusAvailable READ dbusAvailable NOTIFY dbusAvailableChanged)
public:
explicit GraphicsDriverApplet(QObject *parent = nullptr);
@@ -34,6 +35,7 @@ public:
QString deviceInfo() const;
int installProgress() const;
bool isInstalling() const;
bool dbusAvailable() const;
Q_INVOKABLE void refreshDeviceInfo();
Q_INVOKABLE void prepareInstall(const QString &driverName);
@@ -49,6 +51,7 @@ signals:
void installSuccess();
void installFailed(const QString &error);
void requestReboot();
void dbusAvailableChanged();
private slots:
void onGetDeviceReply(QDBusPendingCallWatcher *call);
@@ -61,6 +64,7 @@ private:
QDBusInterface *m_dbusInterface;
QTimer *m_progressTimer;
bool m_dbusAvailable;
QString m_currentDriver;
QString m_deviceInfo;
+4 -1
View File
@@ -2,8 +2,11 @@
set -e
# 切换到项目根目录
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$SCRIPT_DIR"
echo "=== 构建插件 ==="
cd ~/Documents/projects/JSwitchDisplayApplet
rm -rf build
cmake -Bbuild
cmake --build build
+149 -88
View File
@@ -11,39 +11,70 @@ import org.deepin.ds.dock 1.0
AppletItem {
id: root
objectName: "graphics driver applet"
property int dockOrder: 21
property int dockSize: Panel.rootObject.dockItemMaxSize || 48
property bool useColumnLayout: Panel.position % 2
property int dockOrder: 20
property int dockSize: Panel.rootObject.dockSize || 48
implicitWidth: useColumnLayout ? dockSize : 80
implicitWidth: dockSize
implicitHeight: dockSize
property var applet: Applet
// 访问 C++ 后端
readonly property var applet: Applet
readonly property bool dbusAvailable: applet && applet.dbusAvailable
readonly property string currentDriver: applet ? (applet.currentDriver || qsTr("Unknown")) : qsTr("Unknown")
readonly property string deviceInfo: applet ? (applet.deviceInfo || qsTr("Unknown")) : qsTr("Unknown")
readonly property bool isInstalling: applet ? applet.isInstalling : false
readonly property int installProgress: applet ? applet.installProgress : 0
// 图标区域
Rectangle {
anchors.fill: parent
color: "#3498db"
radius: 8
Text {
anchors.centerIn: parent
text: "GPU"
font.pixelSize: root.dockSize * 0.3
color: "white"
}
}
// 悬停提示
PanelToolTip {
id: toolTip
text: qsTr("Graphics Driver Manager")
text: qsTr("Graphics Driver: ") + root.currentDriver
toolTipX: DockPanelPositioner.x
toolTipY: DockPanelPositioner.y
}
Timer {
id: toolTipShowTimer
interval: 50
onTriggered: {
const point = root.mapToItem(null, root.width / 2, root.height / 2)
toolTip.DockPanelPositioner.bounding = Qt.rect(point.x, point.y, toolTip.width, toolTip.height)
toolTip.open()
}
}
HoverHandler {
onHoveredChanged: {
if (hovered && !driverPopup.popupVisible) {
const point = root.mapToItem(null, root.width / 2, root.height / 2)
toolTip.DockPanelPositioner.bounding = Qt.rect(point.x, point.y, toolTip.width, toolTip.height)
toolTip.open()
toolTipShowTimer.start()
} else {
if (toolTipShowTimer.running) {
toolTipShowTimer.stop()
}
toolTip.close()
}
}
}
// 弹出窗口
PanelPopup {
id: driverPopup
width: 300
height: 360
width: 320
height: 400
popupX: DockPanelPositioner.x
popupY: DockPanelPositioner.y
@@ -53,96 +84,121 @@ AppletItem {
}
}
ColumnLayout {
Control {
id: popupContainer
anchors.fill: parent
anchors.margins: 16
spacing: 12
padding: 16
Text {
text: qsTr("Graphics Driver Manager")
font.pixelSize: 16
font.bold: true
Layout.fillWidth: true
}
Rectangle {
Layout.fillWidth: true
Layout.preferredHeight: 1
color: "#ccc"
}
GroupBox {
Layout.fillWidth: true
title: qsTr("Device Information")
ColumnLayout {
anchors.fill: parent
spacing: 8
Text {
text: "Current Driver: " + (root.applet ? root.applet.currentDriver || "Unknown" : "Unknown")
font.pixelSize: 12
Layout.fillWidth: true
}
Text {
text: "Device Info: " + (root.applet ? root.applet.deviceInfo || "Unknown" : "Unknown")
font.pixelSize: 12
wrapMode: Text.WordWrap
Layout.fillWidth: true
}
}
}
Button {
text: qsTr("Refresh")
Layout.fillWidth: true
onClicked: {
if (root.applet) {
root.applet.refreshDeviceInfo()
}
}
}
Button {
text: qsTr("Test Install")
Layout.fillWidth: true
enabled: root.applet && !root.applet.isInstalling
onClicked: {
if (root.applet) {
root.applet.testInstall()
}
}
}
ColumnLayout {
visible: root.applet && root.applet.isInstalling
Layout.fillWidth: true
spacing: 8
contentItem: ColumnLayout {
spacing: 12
Text {
text: qsTr("Installing... ") + (root.applet ? root.applet.installProgress + "%" : "0%")
font.pixelSize: 12
text: qsTr("Graphics Driver Manager")
font.pixelSize: 16
font.bold: true
Layout.fillWidth: true
}
ProgressBar {
Rectangle {
Layout.fillWidth: true
value: root.applet ? root.applet.installProgress / 100 : 0
Layout.preferredHeight: 1
color: "#cccccc"
}
Button {
text: qsTr("Cancel")
// D-Bus 不可用提示
Rectangle {
Layout.fillWidth: true
onClicked: {
if (root.applet) {
root.applet.cancelInstall()
height: 40
visible: !root.dbusAvailable
color: "#fff3cd"
radius: 6
Text {
anchors.centerIn: parent
text: qsTr("Driver service is not available")
color: "#856404"
font.pixelSize: 12
}
}
// 设备信息
GroupBox {
Layout.fillWidth: true
title: qsTr("Device Information")
visible: root.dbusAvailable
ColumnLayout {
anchors.fill: parent
spacing: 8
Text {
text: qsTr("Current Driver: ") + root.currentDriver
font.pixelSize: 12
Layout.fillWidth: true
}
Text {
text: qsTr("Device: ") + root.deviceInfo
font.pixelSize: 12
wrapMode: Text.WordWrap
Layout.fillWidth: true
}
}
}
}
Item {
Layout.fillHeight: true
// 操作按钮
Button {
text: qsTr("Refresh")
Layout.fillWidth: true
enabled: root.dbusAvailable && !root.isInstalling
onClicked: {
if (root.applet) {
root.applet.refreshDeviceInfo()
}
}
}
Button {
text: qsTr("Test Install")
Layout.fillWidth: true
enabled: root.dbusAvailable && !root.isInstalling
onClicked: {
if (root.applet) {
root.applet.testInstall()
}
}
}
// 安装进度
ColumnLayout {
visible: root.isInstalling
Layout.fillWidth: true
spacing: 8
Text {
text: qsTr("Installing... ") + root.installProgress + "%"
font.pixelSize: 12
}
ProgressBar {
Layout.fillWidth: true
value: root.installProgress / 100
}
Button {
text: qsTr("Cancel")
Layout.fillWidth: true
onClicked: {
if (root.applet) {
root.applet.cancelInstall()
}
}
}
}
Item {
Layout.fillHeight: true
}
}
}
@@ -154,6 +210,7 @@ AppletItem {
}
}
// 点击处理
TapHandler {
acceptedButtons: Qt.LeftButton
gesturePolicy: TapHandler.ReleaseWithinBounds
@@ -163,12 +220,16 @@ AppletItem {
driverPopup.close()
} else {
Panel.requestClosePopup()
// 在打开前设置定位,确保弹窗出现在插件附近
const point = root.mapToItem(null, root.width / 2, root.height / 2)
driverPopup.DockPanelPositioner.bounding = Qt.rect(point.x, point.y, driverPopup.width, driverPopup.height)
driverPopup.open()
}
toolTip.close()
}
}
// 后端信号处理
Connections {
target: root.applet
function onInstallSuccess() {