From ac477132abf4607466f33bfe39695ab03c748a2d Mon Sep 17 00:00:00 2001 From: deepin-ci-robot Date: Fri, 10 Nov 2023 05:55:17 +0000 Subject: [PATCH] sync: from linuxdeepin/dtkgui Synchronize source files from linuxdeepin/dtkgui. Source-pull-request: https://github.com/linuxdeepin/dtkgui/pull/207 --- .reuse/dep5 | 2 +- .syncexclude | 11 ++ include/DtkGui/DDesktopServices | 1 + include/util/ddesktopservices.h | 74 ++++++++ src/util/ddesktopservices_linux.cpp | 217 ++++++++++++++++++++++++ src/util/dicontheme.cpp | 3 + src/util/dsvgrenderer.cpp | 5 +- src/util/private/diconproxyengine.cpp | 2 +- src/util/private/xdgiconproxyengine.cpp | 9 +- 9 files changed, 319 insertions(+), 5 deletions(-) create mode 100644 .syncexclude create mode 100644 include/DtkGui/DDesktopServices create mode 100644 include/util/ddesktopservices.h create mode 100644 src/util/ddesktopservices_linux.cpp diff --git a/.reuse/dep5 b/.reuse/dep5 index 64d6cf6..2badb9b 100644 --- a/.reuse/dep5 +++ b/.reuse/dep5 @@ -9,7 +9,7 @@ Copyright: None License: CC0-1.0 # gitignore -Files: .gitignore +Files: .gitignore .syncexclude Copyright: None License: CC0-1.0 diff --git a/.syncexclude b/.syncexclude new file mode 100644 index 0000000..7b42c60 --- /dev/null +++ b/.syncexclude @@ -0,0 +1,11 @@ +# Paths that will be exclude from synchronize workflow +# Please use relative path which use project directory as root +# Notice that +# * .git +# * debian +# * archlinux +# * .obs +# * .github +# are always ignored +linglong.yaml +conanfile.py diff --git a/include/DtkGui/DDesktopServices b/include/DtkGui/DDesktopServices new file mode 100644 index 0000000..6d5336c --- /dev/null +++ b/include/DtkGui/DDesktopServices @@ -0,0 +1 @@ +#include "ddesktopservices.h" diff --git a/include/util/ddesktopservices.h b/include/util/ddesktopservices.h new file mode 100644 index 0000000..d979322 --- /dev/null +++ b/include/util/ddesktopservices.h @@ -0,0 +1,74 @@ +// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: LGPL-3.0-or-later + +#pragma once + +#include + +#include +#include + +DGUI_BEGIN_NAMESPACE + +class DDesktopServices +{ +public: + +#ifdef Q_OS_LINUX + enum SystemSoundEffect { + SSE_Notifications, + SEE_Screenshot, + SSE_EmptyTrash, + SSE_SendFileComplete, + SSE_BootUp, + SSE_Shutdown, + SSE_Logout, + SSE_WakeUp, + SSE_VolumeChange, + SSE_LowBattery, + SSE_PlugIn, + SSE_PlugOut, + SSE_DeviceAdded, + SSE_DeviceRemoved, + SSE_Error, + }; +#endif + + static bool showFolder(QString localFilePath, const QString &startupId = QString()); + static bool showFolders(const QList localFilePaths, const QString &startupId = QString()); + static bool showFolder(QUrl url, const QString &startupId = QString()); + static bool showFolders(const QList urls, const QString &startupId = QString()); + + static bool showFileItemPropertie(QString localFilePath, const QString &startupId = QString()); + static bool showFileItemProperties(const QList localFilePaths, const QString &startupId = QString()); + static bool showFileItemPropertie(QUrl url, const QString &startupId = QString()); + static bool showFileItemProperties(const QList urls, const QString &startupId = QString()); + + static bool showFileItem(QString localFilePath, const QString &startupId = QString()); + static bool showFileItems(const QList localFilePaths, const QString &startupId = QString()); + static bool showFileItem(QUrl url, const QString &startupId = QString()); + static bool showFileItems(const QList urls, const QString &startupId = QString()); + + static bool trash(QString localFilePath); + static bool trash(const QList localFilePaths); + static bool trash(QUrl urlstartupId); + static bool trash(const QList urls); + +#ifdef Q_OS_LINUX + static bool playSystemSoundEffect(const SystemSoundEffect &effect); + static bool playSystemSoundEffect(const QString &name); + static bool previewSystemSoundEffect(const SystemSoundEffect &effect); + static bool previewSystemSoundEffect(const QString &name); + static QString getNameByEffectType(const SystemSoundEffect &effect); +#endif + + static QString errorMessage(); +}; + +DGUI_END_NAMESPACE + +#ifdef Q_OS_LINUX +Q_DECLARE_METATYPE(DTK_GUI_NAMESPACE::DDesktopServices::SystemSoundEffect) +#endif + diff --git a/src/util/ddesktopservices_linux.cpp b/src/util/ddesktopservices_linux.cpp new file mode 100644 index 0000000..fa3ee74 --- /dev/null +++ b/src/util/ddesktopservices_linux.cpp @@ -0,0 +1,217 @@ +// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: LGPL-3.0-or-later + +#include "ddesktopservices.h" +#include +#include +#include + +DGUI_BEGIN_NAMESPACE + +#define EASY_CALL_DBUS(name) \ + QDBusInterface *interface = fileManager1DBusInterface(); \ + return interface && \ + interface->call(#name, urls2uris(urls), startupId).type() != \ + QDBusMessage::ErrorMessage; + +static const QStringList SOUND_EFFECT_LIST { + "message", + "camera-shutter", + "trash-empty", + "x-deepin-app-sent-to-desktop", + "desktop-login", + "system-shutdown", + "desktop-logout", + "suspend-resume", + "audio-volume-change", + "power-unplug-battery-low", + "power-plug", + "power-unplug", + "device-added", + "device-removed", + "dialog-error", +}; + +static QDBusInterface *fileManager1DBusInterface() +{ + static QDBusInterface interface(QStringLiteral("org.freedesktop.FileManager1"), + QStringLiteral("/org/freedesktop/FileManager1"), + QStringLiteral("org.freedesktop.FileManager1")); + return &interface; +} + +static QStringList urls2uris(const QList &urls) +{ + QStringList list; + + list.reserve(urls.size()); + + for (const QUrl &url : urls) { + list << url.toString(); + } + + return list; +} + +static QList path2urls(const QList &paths) +{ + QList list; + + list.reserve(paths.size()); + + for (const QString &path : paths) { + list << QUrl::fromLocalFile(path); + } + + return list; +} + +static QDBusInterface soundEffectInterface() +{ +#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) + const auto& infc = QDBusConnection::sessionBus().interface(); + QStringList activatableServiceNames = infc->activatableServiceNames(); + bool isNewInterface = activatableServiceNames.contains(QLatin1String("org.deepin.dde.SoundEffect1")); +#else + bool isNewInterface = false; // Qt 5.14 以下就直接用旧的接口 +#endif + const QLatin1String service(isNewInterface ? "org.deepin.dde.SoundEffect1" :"com.deepin.daemon.SoundEffect"); + const QLatin1String path(isNewInterface ? "/org/deepin/dde/SoundEffect1" : "/com/deepin/daemon/SoundEffect"); + const QLatin1String interface(isNewInterface ? "org.deepin.dde.SoundEffect1" :"com.deepin.daemon.SoundEffect"); + + // 使用后端 dbus 接口播放系统音频,音频存放目录: /usr/share/sounds/deepin/stereo/ + return QDBusInterface(service, path, interface); +} + +static bool systemSoundEffectEnabled(const QString &name) +{ + auto soundEffect = soundEffectInterface(); + if (!soundEffect.property("Enabled").toBool()) + return false; + + QDBusReply reply = soundEffect.call("IsSoundEnabled", name); + + return reply.isValid() && reply.value(); +} + +bool DDesktopServices::showFolder(QString localFilePath, const QString &startupId) +{ + return showFolder(QUrl::fromLocalFile(localFilePath), startupId); +} + +bool DDesktopServices::showFolders(const QList localFilePaths, const QString &startupId) +{ + return showFolders(path2urls(localFilePaths), startupId); +} + +bool DDesktopServices::showFolder(QUrl url, const QString &startupId) +{ + return showFolders(QList() << url, startupId); +} + +bool DDesktopServices::showFolders(const QList urls, const QString &startupId) +{ + EASY_CALL_DBUS(ShowFolders) +} + +bool DDesktopServices::showFileItemPropertie(QString localFilePath, const QString &startupId) +{ + return showFileItemPropertie(QUrl::fromLocalFile(localFilePath), startupId); +} + +bool DDesktopServices::showFileItemProperties(const QList localFilePaths, const QString &startupId) +{ + return showFileItemProperties(path2urls(localFilePaths), startupId); +} + +bool DDesktopServices::showFileItemPropertie(QUrl url, const QString &startupId) +{ + return showFileItemProperties(QList() << url, startupId); +} + +bool DDesktopServices::showFileItemProperties(const QList urls, const QString &startupId) +{ + EASY_CALL_DBUS(ShowItemProperties) +} + +bool DDesktopServices::showFileItem(QString localFilePath, const QString &startupId) +{ + return showFileItem(QUrl::fromLocalFile(localFilePath), startupId); +} + +bool DDesktopServices::showFileItems(const QList localFilePaths, const QString &startupId) +{ + return showFileItems(path2urls(localFilePaths), startupId); +} + +bool DDesktopServices::showFileItem(QUrl url, const QString &startupId) +{ + return showFileItems(QList() << url, startupId); +} + +bool DDesktopServices::showFileItems(const QList urls, const QString &startupId) +{ + EASY_CALL_DBUS(ShowItems) +} + +bool DDesktopServices::trash(QString localFilePath) +{ + return trash(QUrl::fromLocalFile(localFilePath)); +} + +bool DDesktopServices::trash(const QList localFilePaths) +{ + return trash(path2urls(localFilePaths)); +} + +bool DDesktopServices::trash(QUrl url) +{ + return trash(QList() << url); +} + +bool DDesktopServices::trash(const QList urls) +{ + QDBusInterface *interface = fileManager1DBusInterface(); + return interface && interface->call("Trash", urls2uris(urls)).type() != QDBusMessage::ErrorMessage; +} + +bool DDesktopServices::playSystemSoundEffect(const DDesktopServices::SystemSoundEffect &effect) +{ + return playSystemSoundEffect(SOUND_EFFECT_LIST.at(static_cast(effect))); +} + +bool DDesktopServices::playSystemSoundEffect(const QString &name) +{ + if (!systemSoundEffectEnabled(name)) + return false; + + return previewSystemSoundEffect(name); +} + +bool DDesktopServices::previewSystemSoundEffect(const DDesktopServices::SystemSoundEffect &effect) +{ + return previewSystemSoundEffect(SOUND_EFFECT_LIST.at(static_cast(effect))); +} + +bool DDesktopServices::previewSystemSoundEffect(const QString &name) +{ + if (name.isEmpty()) { + return false; + } + + // 使用后端 dbus 接口播放系统音频,音频存放目录: /usr/share/sounds/deepin/stereo/ + return soundEffectInterface().call("PlaySound", name).type() != QDBusMessage::ErrorMessage; +} + +QString DDesktopServices::getNameByEffectType(const DDesktopServices::SystemSoundEffect &effect) +{ + return SOUND_EFFECT_LIST.at(static_cast(effect)); +} + +QString DDesktopServices::errorMessage() +{ + return fileManager1DBusInterface()->lastError().message(); +} + +DGUI_END_NAMESPACE diff --git a/src/util/dicontheme.cpp b/src/util/dicontheme.cpp index c31db9d..b78298c 100644 --- a/src/util/dicontheme.cpp +++ b/src/util/dicontheme.cpp @@ -95,6 +95,9 @@ QIconEngine *DIconTheme::createIconEngine(const QString &iconName, Options optio QIcon DIconTheme::findQIcon(const QString &iconName, Options options) { + if (QDir::isAbsolutePath(iconName)) { + return QIcon(iconName); + } auto engine = createIconEngine(iconName, options); // fallback to QIcon::fromTheme if (!options.testFlag(DontFallbackToQIconFromTheme) && !engine) diff --git a/src/util/dsvgrenderer.cpp b/src/util/dsvgrenderer.cpp index fa8d592..f1d3db8 100644 --- a/src/util/dsvgrenderer.cpp +++ b/src/util/dsvgrenderer.cpp @@ -145,7 +145,10 @@ QImage DSvgRendererPrivate::getImage(const QSize &size, const QString &elementId QImage image(size, QImage::Format_ARGB32_Premultiplied); image.fill(Qt::transparent); QPainter pa(&image); - qRenderer->render(&pa, elementId); + if (elementId.isEmpty()) + qRenderer->render(&pa); + else + qRenderer->render(&pa, elementId); return image; #endif } diff --git a/src/util/private/diconproxyengine.cpp b/src/util/private/diconproxyengine.cpp index a06d2d1..f1ced81 100644 --- a/src/util/private/diconproxyengine.cpp +++ b/src/util/private/diconproxyengine.cpp @@ -172,7 +172,7 @@ QString DIconProxyEngine::iconName() const #endif { - return m_iconName; + return m_iconEngine ? m_iconEngine->iconName() : QString(); } QString DIconProxyEngine::proxyKey() diff --git a/src/util/private/xdgiconproxyengine.cpp b/src/util/private/xdgiconproxyengine.cpp index 9488ec9..9b296cb 100644 --- a/src/util/private/xdgiconproxyengine.cpp +++ b/src/util/private/xdgiconproxyengine.cpp @@ -49,6 +49,11 @@ static inline QPixmap entryPixmap(ScalableEntry *color_entry, const QSize &size, if (!color_entry) return QPixmap(); + // init svgIcon with svg absolute path + // force to use svg iconengine + if (color_entry->svgIcon.isNull()) + color_entry->svgIcon = QIcon(color_entry->filename); + if (auto d = color_entry->svgIcon.data_ptr()) if (d->engine) return d->engine->pixmap(size, mode, state); @@ -99,7 +104,7 @@ QPixmap XdgIconProxyEngine::followColorPixmap(ScalableEntry *color_entry, const // 当size为1时表示此svg文件不需要处理ColorScheme标签 if (!cache_color_scheme.isEmpty() && cache_color_scheme[DEEPIN_XDG_THEME::Text].size() == 1) - return color_entry->pixmap(size, mode, state); + return entryPixmap(color_entry, size, mode, state); const DEEPIN_XDG_THEME::PALETTE_MAP &color_scheme = DEEPIN_XDG_THEME::colorScheme.localData(); QPixmap pm = color_scheme == cache_color_scheme ? entryPixmap(color_entry, size, mode, state) : QPixmap(); @@ -144,7 +149,7 @@ QPixmap XdgIconProxyEngine::followColorPixmap(ScalableEntry *color_entry, const if (invalidBuffers) { // 此svg图标无ColorScheme标签时不应该再下面的操作,且应该记录下来,避免后续再处理svg文件内容 entryToColorScheme[cache_key] = DEEPIN_XDG_THEME::PALETTE_MAP({ {DEEPIN_XDG_THEME::Text, "#"} }); - return color_entry->pixmap(size, mode, state); + return entryPixmap(color_entry, size, mode, state); } // use the QSvgIconEngine