From aa77c6bf96a2071041bdddd261db9026f06b712a Mon Sep 17 00:00:00 2001 From: zhuyonghao Date: Mon, 8 Jul 2024 15:28:27 +0800 Subject: [PATCH] feat: Web page screensaver Add deepin-web-screensaver subroutine. Support users to use custom web pages as screensavers. Log: Add web page screensaver options --- customscreensaver/customscreensaver.pro | 3 +- .../data/deepin-screensaver-config.svg | 181 +++++++++++++++++ .../data/deepin-web-screensaver.desktop | 5 + .../data/org.deepin.webscreensaver.json | 17 ++ .../deepin-web-screensaver.pro | 85 ++++++++ .../generate_translations.sh | 16 ++ .../deepin-web-screensaver/icon.qrc | 5 + .../src/commandlinemanager.cpp | 66 ++++++ .../src/commandlinemanager.h | 41 ++++ .../src/config/contenttitle.cpp | 31 +++ .../src/config/contenttitle.h | 25 +++ .../src/config/selectpathwidget.cpp | 48 +++++ .../src/config/selectpathwidget.h | 36 ++++ .../src/icons/deepin-web-screensaver.jpg | Bin 0 -> 6234 bytes .../src/icons/deepin-web-screensaver@2x.jpg | Bin 0 -> 14824 bytes .../src/icons/deepin-web-screensaver@3x.jpg | Bin 0 -> 25583 bytes .../deepin-web-screensaver/src/main.cpp | 91 +++++++++ .../src/singleinstance.cpp | 121 +++++++++++ .../src/singleinstance.h | 39 ++++ .../src/slideshowconfig.cpp | 76 +++++++ .../src/slideshowconfig.h | 57 ++++++ .../src/slideshowconfigdialog.cpp | 188 ++++++++++++++++++ .../src/slideshowconfigdialog.h | 39 ++++ .../src/slideshowscreensaver.cpp | 109 ++++++++++ .../src/slideshowscreensaver.h | 37 ++++ .../translations/deepin-web-screensaver.ts | 30 +++ .../deepin-web-screensaver_zh_CN.ts | 30 +++ .../deepin-web-screensaver_zh_HK.ts | 30 +++ .../update_translations.sh | 10 + debian/control | 2 +- ...epin-screensaver-xscreensaver-data.install | 3 + 31 files changed, 1419 insertions(+), 2 deletions(-) create mode 100644 customscreensaver/deepin-web-screensaver/data/deepin-screensaver-config.svg create mode 100644 customscreensaver/deepin-web-screensaver/data/deepin-web-screensaver.desktop create mode 100644 customscreensaver/deepin-web-screensaver/data/org.deepin.webscreensaver.json create mode 100644 customscreensaver/deepin-web-screensaver/deepin-web-screensaver.pro create mode 100755 customscreensaver/deepin-web-screensaver/generate_translations.sh create mode 100644 customscreensaver/deepin-web-screensaver/icon.qrc create mode 100644 customscreensaver/deepin-web-screensaver/src/commandlinemanager.cpp create mode 100644 customscreensaver/deepin-web-screensaver/src/commandlinemanager.h create mode 100644 customscreensaver/deepin-web-screensaver/src/config/contenttitle.cpp create mode 100644 customscreensaver/deepin-web-screensaver/src/config/contenttitle.h create mode 100644 customscreensaver/deepin-web-screensaver/src/config/selectpathwidget.cpp create mode 100644 customscreensaver/deepin-web-screensaver/src/config/selectpathwidget.h create mode 100644 customscreensaver/deepin-web-screensaver/src/icons/deepin-web-screensaver.jpg create mode 100644 customscreensaver/deepin-web-screensaver/src/icons/deepin-web-screensaver@2x.jpg create mode 100644 customscreensaver/deepin-web-screensaver/src/icons/deepin-web-screensaver@3x.jpg create mode 100644 customscreensaver/deepin-web-screensaver/src/main.cpp create mode 100644 customscreensaver/deepin-web-screensaver/src/singleinstance.cpp create mode 100644 customscreensaver/deepin-web-screensaver/src/singleinstance.h create mode 100644 customscreensaver/deepin-web-screensaver/src/slideshowconfig.cpp create mode 100644 customscreensaver/deepin-web-screensaver/src/slideshowconfig.h create mode 100644 customscreensaver/deepin-web-screensaver/src/slideshowconfigdialog.cpp create mode 100644 customscreensaver/deepin-web-screensaver/src/slideshowconfigdialog.h create mode 100644 customscreensaver/deepin-web-screensaver/src/slideshowscreensaver.cpp create mode 100644 customscreensaver/deepin-web-screensaver/src/slideshowscreensaver.h create mode 100644 customscreensaver/deepin-web-screensaver/translations/deepin-web-screensaver.ts create mode 100644 customscreensaver/deepin-web-screensaver/translations/deepin-web-screensaver_zh_CN.ts create mode 100644 customscreensaver/deepin-web-screensaver/translations/deepin-web-screensaver_zh_HK.ts create mode 100755 customscreensaver/deepin-web-screensaver/update_translations.sh diff --git a/customscreensaver/customscreensaver.pro b/customscreensaver/customscreensaver.pro index 60aae550..95220710 100644 --- a/customscreensaver/customscreensaver.pro +++ b/customscreensaver/customscreensaver.pro @@ -1,4 +1,5 @@ TEMPLATE = subdirs SUBDIRS += \ saverpic \ - deepin-custom-screensaver + deepin-custom-screensaver \ + deepin-web-screensaver diff --git a/customscreensaver/deepin-web-screensaver/data/deepin-screensaver-config.svg b/customscreensaver/deepin-web-screensaver/data/deepin-screensaver-config.svg new file mode 100644 index 00000000..3e46ba7b --- /dev/null +++ b/customscreensaver/deepin-web-screensaver/data/deepin-screensaver-config.svg @@ -0,0 +1,181 @@ + + + 自定义屏保-96px + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/customscreensaver/deepin-web-screensaver/data/deepin-web-screensaver.desktop b/customscreensaver/deepin-web-screensaver/data/deepin-web-screensaver.desktop new file mode 100644 index 00000000..48600096 --- /dev/null +++ b/customscreensaver/deepin-web-screensaver/data/deepin-web-screensaver.desktop @@ -0,0 +1,5 @@ +[Desktop Entry] +Type=Application +Exec=/usr/lib/deepin-screensaver/modules/deepin-web-screensaver --config +Terminal=false +Name=deepin-web-screensaver-config diff --git a/customscreensaver/deepin-web-screensaver/data/org.deepin.webscreensaver.json b/customscreensaver/deepin-web-screensaver/data/org.deepin.webscreensaver.json new file mode 100644 index 00000000..03f7ace1 --- /dev/null +++ b/customscreensaver/deepin-web-screensaver/data/org.deepin.webscreensaver.json @@ -0,0 +1,17 @@ +{ + "magic": "dsg.config.meta", + "version": "1.0", + "contents": { + "slideshowPath": { + "value": "", + "serial": 0, + "flags": ["global"], + "name": "Web url", + "name[zh_CN]": "网页地址", + "description[zh_CN]":"自定义屏保网页地址", + "description": "Custom screensaver web url", + "permissions": "readwrite", + "visibility": "public" + } + } +} diff --git a/customscreensaver/deepin-web-screensaver/deepin-web-screensaver.pro b/customscreensaver/deepin-web-screensaver/deepin-web-screensaver.pro new file mode 100644 index 00000000..163f722a --- /dev/null +++ b/customscreensaver/deepin-web-screensaver/deepin-web-screensaver.pro @@ -0,0 +1,85 @@ +#------------------------------------------------- +# +# Project created by QtCreator 2021-05-14T10:44:28 +# +#------------------------------------------------- + +QT += core gui dtkcore webenginewidgets network + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +TARGET = deepin-web-screensaver +TEMPLATE = app + +# The following define makes your compiler emit warnings if you use +# any feature of Qt which has been marked as deprecated (the exact warnings +# depend on your compiler). Please consult the documentation of the +# deprecated API in order to know how to port your code away from it. +DEFINES += QT_DEPRECATED_WARNINGS + +# You can also make your code fail to compile if you use deprecated APIs. +# In order to do so, uncomment the following line. +# You can also select to disable deprecated APIs only up to a certain version of Qt. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + +CONFIG += c++11 link_pkgconfig + +PKGCONFIG += x11 dtkwidget + +SOURCES += \ + src/main.cpp \ + src/slideshowscreensaver.cpp \ + src/commandlinemanager.cpp \ + src/slideshowconfig.cpp \ + src/slideshowconfigdialog.cpp \ + src/config/contenttitle.cpp \ + src/config/selectpathwidget.cpp \ + src/singleinstance.cpp + +HEADERS += \ + src/slideshowscreensaver.h \ + src/commandlinemanager.h \ + src/slideshowconfig.h \ + src/slideshowconfigdialog.h \ + src/config/contenttitle.h \ + src/config/selectpathwidget.h \ + src/singleinstance.h + + +#!! 放开注释来更新json配置文件所生成的ts文件 +#DTK_SETTINGS = $${QT.dtkcore.tools}/dtk-settings +#system($$DTK_SETTINGS -o deepin-custom-screensaver_translation.cpp $$PWD/data/deepin-custom-screensaver.json) +#SOURCES += deepin-custom-screensaver_translation.cpp + +TRANSLATIONS += $$PWD/translations/$${TARGET}.ts \ + $$PWD/translations/$${TARGET}_zh_CN.ts \ + $$PWD/translations/$${TARGET}_zh_HK.ts \ + +CONFIG(release, debug|release) { + !system($$PWD/generate_translations.sh): error("Failed to generate translation") +} + +target.path = /usr/lib/deepin-screensaver/modules/ + +translations.path = /usr/share/$${TARGET}/translations +translations.files = translations/*.qm + +desktop.path = /etc/deepin-screensaver/$${TARGET}/ +desktop.files = data/deepin-web-screensaver.desktop + +icons.path = /usr/lib/deepin-screensaver/modules/cover/ +icons.files = src/icons/*.jpg + +INSTALLS += target translations desktop icons + +# DConfig +meta_file.files += \ + $$PWD/data/org.deepin.webscreensaver.json +meta_file.base = $$PWD/data +meta_file.appid = org.deepin.screensaver + +DCONFIG_META_FILES += meta_file +load(dtk_install_dconfig) + +RESOURCES += \ + icon.qrc diff --git a/customscreensaver/deepin-web-screensaver/generate_translations.sh b/customscreensaver/deepin-web-screensaver/generate_translations.sh new file mode 100755 index 00000000..f340a099 --- /dev/null +++ b/customscreensaver/deepin-web-screensaver/generate_translations.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +# SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. +# +# SPDX-License-Identifier: GPL-3.0-or-later + +# this file is used to auto-generate .qm file from .ts file. +# author: shibowen at linuxdeepin.com + +ts_list=(`ls translations/*.ts`) + +for ts in "${ts_list[@]}" +do + printf "\nprocess ${ts}\n" + lrelease "${ts}" +done diff --git a/customscreensaver/deepin-web-screensaver/icon.qrc b/customscreensaver/deepin-web-screensaver/icon.qrc new file mode 100644 index 00000000..f64c8039 --- /dev/null +++ b/customscreensaver/deepin-web-screensaver/icon.qrc @@ -0,0 +1,5 @@ + + + data/deepin-screensaver-config.svg + + diff --git a/customscreensaver/deepin-web-screensaver/src/commandlinemanager.cpp b/customscreensaver/deepin-web-screensaver/src/commandlinemanager.cpp new file mode 100644 index 00000000..c38d2a39 --- /dev/null +++ b/customscreensaver/deepin-web-screensaver/src/commandlinemanager.cpp @@ -0,0 +1,66 @@ +// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "commandlinemanager.h" + +#include + +class CommandLineManagerGlobal : public CommandLineManager {}; +Q_GLOBAL_STATIC(CommandLineManagerGlobal, commandLineManagerGlobal); + +CommandLineManager::CommandLineManager() + : m_commandParser(new QCommandLineParser) +{ + // 必须设置为长选项模式,否则解析时 -window-id 将识别错误 + m_commandParser->setSingleDashWordOptionMode(QCommandLineParser::ParseAsLongOptions); + + initOptions(); +} + +CommandLineManager *CommandLineManager::instance() +{ + return commandLineManagerGlobal; +} + +CommandLineManager::~CommandLineManager() +{ + +} + +void CommandLineManager::initOptions() +{ + QCommandLineOption subWindowOption("window-id", "displays as a child of the given ID window.\nNOTE:is '-window-id',not '--window-id'", "ID"); + QCommandLineOption pathOption(QStringList() << "p" << "path", "set the path of web page.", "PATH"); + QCommandLineOption config(QStringList() << "config", "show config user Interface"); + + m_commandParser->addOption(subWindowOption); + m_commandParser->addOption(pathOption); + m_commandParser->addOption(config); +} + +void CommandLineManager::process(const QStringList &arguments) +{ + m_commandParser->process(arguments); +} + +bool CommandLineManager::isSet(const QString &name) const +{ + return m_commandParser->isSet(name); +} + +QString CommandLineManager::value(const QString &name) const +{ + return m_commandParser->value(name); +} + +QStringList CommandLineManager::positionalArguments() +{ + return m_commandParser->positionalArguments(); +} + +QStringList CommandLineManager::unknownOptionNames() +{ + return m_commandParser->unknownOptionNames(); +} + diff --git a/customscreensaver/deepin-web-screensaver/src/commandlinemanager.h b/customscreensaver/deepin-web-screensaver/src/commandlinemanager.h new file mode 100644 index 00000000..f1e337b5 --- /dev/null +++ b/customscreensaver/deepin-web-screensaver/src/commandlinemanager.h @@ -0,0 +1,41 @@ +// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef COMMANDLINEMANAGER_H +#define COMMANDLINEMANAGER_H + +#include +#include +#include + +class CommandLineManager +{ +public: + static CommandLineManager *instance(); + + ~CommandLineManager(); + + void process(const QStringList &arguments); + + bool isSet(const QString &name) const; + QString value(const QString &name) const; + + QStringList positionalArguments(); + QStringList unknownOptionNames(); + +protected: + explicit CommandLineManager(); + +private: + void initOptions(); + +private: + CommandLineManager(CommandLineManager &) = delete; + CommandLineManager &operator=(CommandLineManager &) = delete; + +private: + QScopedPointer m_commandParser; +}; + +#endif // COMMANDLINEMANAGER_H diff --git a/customscreensaver/deepin-web-screensaver/src/config/contenttitle.cpp b/customscreensaver/deepin-web-screensaver/src/config/contenttitle.cpp new file mode 100644 index 00000000..fe6ad32b --- /dev/null +++ b/customscreensaver/deepin-web-screensaver/src/config/contenttitle.cpp @@ -0,0 +1,31 @@ +// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "contenttitle.h" + +#include + +ContentTitle::ContentTitle(QWidget *parent) : QWidget(parent) +{ + auto layout = new QHBoxLayout(this); + layout->setContentsMargins(0, 0, 0, 0); + layout->setSpacing(10); + + titleLabel = new QLabel; + layout->addWidget(titleLabel, 0, Qt::AlignLeft); + + auto lineLabel = new QLabel; + layout->addWidget(lineLabel); + lineLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); +} + +QLabel *ContentTitle::label() const +{ + return titleLabel; +} + +void ContentTitle::setTitle(const QString &title) +{ + titleLabel->setText(title); +} diff --git a/customscreensaver/deepin-web-screensaver/src/config/contenttitle.h b/customscreensaver/deepin-web-screensaver/src/config/contenttitle.h new file mode 100644 index 00000000..cee97d71 --- /dev/null +++ b/customscreensaver/deepin-web-screensaver/src/config/contenttitle.h @@ -0,0 +1,25 @@ +// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef CONTENTTITLE_H +#define CONTENTTITLE_H + +#include +#include + +class ContentTitle : public QWidget +{ + Q_OBJECT +public: + explicit ContentTitle(QWidget *parent = nullptr); + QLabel *label() const; + +public : + void setTitle(const QString &title); + +protected: + QLabel *titleLabel = nullptr; +}; + +#endif // CONTENTTITLE_H diff --git a/customscreensaver/deepin-web-screensaver/src/config/selectpathwidget.cpp b/customscreensaver/deepin-web-screensaver/src/config/selectpathwidget.cpp new file mode 100644 index 00000000..be78a203 --- /dev/null +++ b/customscreensaver/deepin-web-screensaver/src/config/selectpathwidget.cpp @@ -0,0 +1,48 @@ +// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "selectpathwidget.h" +#include "../slideshowconfig.h" + +#include + +#include +#include + +DWIDGET_USE_NAMESPACE +DCORE_USE_NAMESPACE + +SelectPathWidget::SelectPathWidget(QWidget *parent) + : DWidget(parent) +{ + initOption(); +} + +QString SelectPathWidget::getPath() +{ + return m_selectLineEdit->text(); +} + +void SelectPathWidget::initOption() +{ + QString valueText; + // 路径转换 + if (valueText.startsWith(QStringLiteral("~"))) + valueText.replace(QStringLiteral("~"), QDir::homePath()); + + m_selectTips = new DLabel(tr("Enter web url"), this); + m_selectLineEdit = new DLineEdit(this); + m_selectBtn = new DPushButton(tr("apply"), this); + m_selectBtn->setFocusPolicy(Qt::NoFocus); + + m_url = SlideshowConfig::instance()->slideshowPath(); + m_selectLineEdit->setPlaceholderText(m_url); + + QHBoxLayout *layout = new QHBoxLayout(this); + layout->addWidget(m_selectTips); + layout->addWidget(m_selectLineEdit); + layout->addWidget(m_selectBtn); + + connect(m_selectBtn, &DPushButton::clicked, this, &SelectPathWidget::requsetSetPath); +} diff --git a/customscreensaver/deepin-web-screensaver/src/config/selectpathwidget.h b/customscreensaver/deepin-web-screensaver/src/config/selectpathwidget.h new file mode 100644 index 00000000..45d3d830 --- /dev/null +++ b/customscreensaver/deepin-web-screensaver/src/config/selectpathwidget.h @@ -0,0 +1,36 @@ +// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef SELECTPATHWIDGET_H +#define SELECTPATHWIDGET_H + +#include +#include +#include +#include +#include + +#include + +class TruncateLineEdit; + +class SelectPathWidget : public Dtk::Widget::DWidget +{ + Q_OBJECT +public: + explicit SelectPathWidget(QWidget *parent = nullptr); + QString getPath(); +signals: + void requsetSetPath(); + +private: + void initOption(); +private: + Dtk::Widget::DLabel *m_selectTips = nullptr; + Dtk::Widget::DLineEdit *m_selectLineEdit = nullptr; + Dtk::Widget::DPushButton *m_selectBtn = nullptr; + QString m_url; +}; + +#endif // SELECTPATHWIDGET_H diff --git a/customscreensaver/deepin-web-screensaver/src/icons/deepin-web-screensaver.jpg b/customscreensaver/deepin-web-screensaver/src/icons/deepin-web-screensaver.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7b9757ad8866baa75c352b7f6a386b4b68286ad3 GIT binary patch literal 6234 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 literal 0 HcmV?d00001 diff --git a/customscreensaver/deepin-web-screensaver/src/icons/deepin-web-screensaver@3x.jpg b/customscreensaver/deepin-web-screensaver/src/icons/deepin-web-screensaver@3x.jpg new file mode 100644 index 0000000000000000000000000000000000000000..445d70db41aa424d9d7f0d75bea33b822e8dbdfd GIT binary patch literal 25583 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

9lynOR%?zov4)RD>I&0IPMi#{3Ba`h10wo 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≺P(;slNhy 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 literal 0 HcmV?d00001 diff --git a/customscreensaver/deepin-web-screensaver/src/main.cpp b/customscreensaver/deepin-web-screensaver/src/main.cpp new file mode 100644 index 00000000..0e027299 --- /dev/null +++ b/customscreensaver/deepin-web-screensaver/src/main.cpp @@ -0,0 +1,91 @@ +// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "slideshowscreensaver.h" +#include "commandlinemanager.h" +#include "slideshowconfig.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +DWIDGET_USE_NAMESPACE + +int main(int argc, char *argv[]) +{ + auto envType = qEnvironmentVariable("XDG_SESSION_TYPE"); + if (envType.contains("wayland")) { + qInfo() << QDateTime::currentDateTime().toString() << "notes:change wayland to xcb for QT_QPA_PLATFORM."; + qputenv("QT_QPA_PLATFORM", "xcb"); + } + + DApplication a(argc, argv); + a.setOrganizationName("deepin"); + a.loadTranslator(); + + CommandLineManager::instance()->process(a.arguments()); + + if (CommandLineManager::instance()->isSet("window-id")) { + + QString windowId = CommandLineManager::instance()->value("window-id"); + WId windowHwnd = WId(windowId.toULongLong()); + QWindow *window = QWindow::fromWinId(windowHwnd); + + if (!window) { + qDebug() << "Error:not found QWindow by window id:" << windowId; + return -1; + } + + SlideshowScreenSaver screensaver(true); + screensaver.setProperty("_q_embedded_native_parent_handle", QVariant(windowHwnd)); + screensaver.winId(); + screensaver.windowHandle()->setParent(window); + + Display *display = XOpenDisplay(nullptr); + if (!display) { + qWarning() << "can not connect xservice."; + return -1; + } + + Window windowXID(windowHwnd); + XWindowAttributes attr; + XGetWindowAttributes(display, windowXID, &attr); + + screensaver.setGeometry(QRect(0, 0, attr.width, attr.height)); + screensaver.init(); + screensaver.show(); + + return a.exec(); + + } else if (CommandLineManager::instance()->isSet("p")) { + + QString path = CommandLineManager::instance()->value("p"); + SlideshowConfig::instance()->setSlideShowPath(path); + + } else if (CommandLineManager::instance()->isSet("config")) { + qInfo() << "show dconfig dialog"; + if (SlideshowConfig::instance()->startCustomConfig()) + return a.exec(); + return 0; + } else { + SlideshowScreenSaver screensaver; + screensaver.init(); + screensaver.show(); + + return a.exec(); + } + + return 0; +} diff --git a/customscreensaver/deepin-web-screensaver/src/singleinstance.cpp b/customscreensaver/deepin-web-screensaver/src/singleinstance.cpp new file mode 100644 index 00000000..55ff9ab5 --- /dev/null +++ b/customscreensaver/deepin-web-screensaver/src/singleinstance.cpp @@ -0,0 +1,121 @@ +// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "singleinstance.h" + +#include +#include +#include +#include +#include + +SingleInstance::SingleInstance(const QString &name, QObject *parent) + : QObject(parent) + , m_localServer(new QLocalServer) +{ + m_userKey = QString("%1/%2").arg(QStandardPaths::writableLocation(QStandardPaths::RuntimeLocation)).arg(name); + if (m_userKey.isEmpty()) { + m_userKey = QString("%1/%2").arg(QStandardPaths::writableLocation(QStandardPaths::TempLocation)).arg(name); + } + + initConnect(); +} + +SingleInstance::~SingleInstance() +{ + closeServer(); +} + +bool SingleInstance::isSingle() +{ + QLocalSocket localSocket; + localSocket.connectToServer(m_userKey); + + // if connect success, another instance is running. + if (localSocket.waitForConnected(1000)) + return false; + + m_localServer->removeServer(m_userKey); + bool f = m_localServer->listen(m_userKey); + return f; +} + +void SingleInstance::closeServer() +{ + if (m_localServer) { + m_localServer->removeServer(m_localServer->serverName()); + m_localServer->close(); + delete m_localServer; + m_localServer = nullptr; + } +} + +void SingleInstance::sendNewClient() +{ + QByteArray data { nullptr }; + const auto &args = qApp->arguments(); + qDebug() << "new client send data: " << args; + for (const QString &arg : args) { + if (!arg.startsWith("-") && QFile::exists(arg)) { + data.append(QDir(arg).absolutePath().toLocal8Bit().toBase64()); + } else { + data.append(arg.toLocal8Bit().toBase64()); + } + data.append(' '); + } + + if (!data.isEmpty()) + data.chop(1); + + QLocalSocket *socket = getNewClientConnect(data); + socket->deleteLater(); +} + +QLocalSocket *SingleInstance::getNewClientConnect(const QByteArray &message) +{ + QLocalSocket *localSocket = new QLocalSocket; + localSocket->connectToServer(m_userKey); + if (localSocket->waitForConnected(1000)) { + if (localSocket->state() == QLocalSocket::ConnectedState) { + if (localSocket->isValid()) { + localSocket->write(message); + localSocket->flush(); + } + } + } else { + qDebug() << localSocket->errorString(); + } + + return localSocket; +} + +void SingleInstance::handleConnection() +{ + qDebug() << "new connection is coming"; + QLocalSocket *nextPendingConnection = m_localServer->nextPendingConnection(); + connect(nextPendingConnection, SIGNAL(readyRead()), this, SLOT(readData())); +} + +void SingleInstance::readData() +{ + QLocalSocket *socket = qobject_cast(sender()); + + if (!socket) + return; + + QStringList arguments; + for (const QByteArray &arg_base64 : socket->read(2048).split(' ')) { + const QByteArray &arg = QByteArray::fromBase64(arg_base64.simplified()); + if (arg.isEmpty()) + continue; + arguments << QString::fromLocal8Bit(arg); + } + + emit handArguments(arguments); +} + +void SingleInstance::initConnect() +{ + connect(m_localServer, &QLocalServer::newConnection, this, &SingleInstance::handleConnection); +} diff --git a/customscreensaver/deepin-web-screensaver/src/singleinstance.h b/customscreensaver/deepin-web-screensaver/src/singleinstance.h new file mode 100644 index 00000000..96a788b4 --- /dev/null +++ b/customscreensaver/deepin-web-screensaver/src/singleinstance.h @@ -0,0 +1,39 @@ +// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef SINGLEINSTANCE_H +#define SINGLEINSTANCE_H + +#include + +QT_BEGIN_NAMESPACE +class QLocalServer; +class QLocalSocket; +class QCommandLineParser; +QT_END_NAMESPACE + +class SingleInstance : public QObject +{ + Q_OBJECT +public: + explicit SingleInstance(const QString &name, QObject *parent = nullptr); + ~SingleInstance(); + bool isSingle(); + void closeServer(); + void sendNewClient(); + QLocalSocket *getNewClientConnect(const QByteArray &message); +signals: + void handArguments(const QStringList &); +private slots: + void handleConnection(); + void readData(); +private: + void initConnect(); + +protected: + QLocalServer *m_localServer { nullptr }; + QString m_userKey; +}; + +#endif // SINGLEINSTANCE_H diff --git a/customscreensaver/deepin-web-screensaver/src/slideshowconfig.cpp b/customscreensaver/deepin-web-screensaver/src/slideshowconfig.cpp new file mode 100644 index 00000000..a98ee5f3 --- /dev/null +++ b/customscreensaver/deepin-web-screensaver/src/slideshowconfig.cpp @@ -0,0 +1,76 @@ +// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "slideshowconfig.h" +#include "slideshowconfigdialog.h" + +#include +#include +#include + +class SlideshowConfigGlobal : public SlideshowConfig +{ +}; +Q_GLOBAL_STATIC(SlideshowConfigGlobal, slideshowConfig); + +SlideshowConfig::SlideshowConfig(QObject *parent) + : QObject(parent) +{ + m_dCfg = DConfig::create(kCfgAppId, kCfgName, "", this); +} + +SlideshowConfig::~SlideshowConfig() +{ +} + +SlideshowConfig *SlideshowConfig::instance() +{ + return slideshowConfig; +} + +QString SlideshowConfig::slideshowPath() const +{ + QString path; + path = m_dCfg->value(kSlideshowPath, "").toString(); + + // 组策略值为空,使用默认url + if (path.isEmpty()) + path = defaultPath(); + + //path格式修正 + if (path.startsWith(QStringLiteral("https:// "))) + path = defaultPath(); + + return path; +} + +void SlideshowConfig::setSlideShowPath(QString path) +{ + m_dCfg->setValue(kSlideshowPath, path); +} + +bool SlideshowConfig::startCustomConfig() +{ + auto ins = new SingleInstance(qApp->applicationName() + "-config", this); + if (ins->isSingle()) { + SlideShowConfigDialog *configDialog = new SlideShowConfigDialog(); + + connect(ins, &SingleInstance::handArguments, configDialog, [configDialog](){ + configDialog->activateWindow();; + }); + + configDialog->startConfig(); + } else { + ins->sendNewClient(); + return false; + } + + return true; +} + +QString SlideshowConfig::defaultPath() +{ + //用户输入为空时返回 + return "https://uniontech.com"; +} diff --git a/customscreensaver/deepin-web-screensaver/src/slideshowconfig.h b/customscreensaver/deepin-web-screensaver/src/slideshowconfig.h new file mode 100644 index 00000000..c5c45eaf --- /dev/null +++ b/customscreensaver/deepin-web-screensaver/src/slideshowconfig.h @@ -0,0 +1,57 @@ +// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef SLIDESHOWCONFIG_H +#define SLIDESHOWCONFIG_H + +#include +#include +#include +#include + +DCORE_USE_NAMESPACE + +static const char *const kGroupSlideshowPath = "custom_screensaver.path.select_path"; +static const char *const kKeyValue = "value"; + +static const char *const kDeepinScreenSaver = "deepin-screensaver"; + +static constexpr char kCfgAppId[] { "org.deepin.screensaver" }; +static constexpr char kCfgName[] { "org.deepin.webscreensaver" }; + +static constexpr char kSlideshowPath[] { "slideshowPath" }; + +class SlideshowConfig : public QObject +{ + Q_OBJECT + friend class SlideshowScreenSaver; + +public: + enum PlayMode { + Order = 0, + Shuffle = 1 + }; + + static SlideshowConfig *instance(); + + ~SlideshowConfig(); + + QString slideshowPath() const; + void setSlideShowPath(QString path); + + bool startCustomConfig(); + static QString defaultPath(); + +protected: + explicit SlideshowConfig(QObject *parent = nullptr); + +private: + SlideshowConfig(SlideshowConfig &) = delete; + SlideshowConfig &operator=(SlideshowConfig &) = delete; + +private: + DConfig *m_dCfg; +}; + +#endif // SLIDESHOWCONFIG_H diff --git a/customscreensaver/deepin-web-screensaver/src/slideshowconfigdialog.cpp b/customscreensaver/deepin-web-screensaver/src/slideshowconfigdialog.cpp new file mode 100644 index 00000000..076ad470 --- /dev/null +++ b/customscreensaver/deepin-web-screensaver/src/slideshowconfigdialog.cpp @@ -0,0 +1,188 @@ +// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "slideshowconfigdialog.h" +#include "slideshowconfig.h" +#include "config/contenttitle.h" + +#include +#include +#include +#include +#include + +#include +#include +#include + +#define SPECIFYLINEEDITLENGTH 65 + +DCORE_USE_NAMESPACE +DWIDGET_USE_NAMESPACE + +static bool isWayland() +{ + bool ok = false; + auto e = QProcessEnvironment::systemEnvironment(); + QString XDG_SESSION_TYPE = e.value(QStringLiteral("XDG_SESSION_TYPE")); + QString WAYLAND_DISPLAY = e.value(QStringLiteral("WAYLAND_DISPLAY")); + + //在wayland平台下设置固定大小,解决属性框最大化问题 + if (XDG_SESSION_TYPE == QLatin1String("wayland") || + WAYLAND_DISPLAY.contains(QLatin1String("wayland"), Qt::CaseInsensitive)) { + ok = true; + } + return ok; +} + +SlideShowConfigDialog::SlideShowConfigDialog(QWidget *parent) + : DAbstractDialog(false, parent) +{ + setModal(true); + + initUI(); + initConnect(); +} + +SlideShowConfigDialog::~SlideShowConfigDialog() +{ + +} + +void SlideShowConfigDialog::initUI() +{ + auto icon = QIcon(":/data/deepin-screensaver-config.svg"); + setWindowIcon(icon); + + auto mainlayout = new QVBoxLayout(this); + mainlayout->setContentsMargins(0, 0, 0, 0); + mainlayout->setSpacing(0); + + DFrame *contentFrame = new DFrame; + contentFrame->setLineWidth(0); + contentFrame->setContentsMargins(10, 10, 10, 10); + + QVBoxLayout *contentlayout = new QVBoxLayout(contentFrame); + frameBar = new DTitlebar(this); + frameBar->setMenuVisible(false); + frameBar->setTitle(QString()); + frameBar->setIcon(icon); + + contentlayout->setContentsMargins(10, 0, 0, 0); + + mainlayout->addWidget(frameBar); + mainlayout->addWidget(contentFrame); + + // mian title + { + contentlayout->addSpacing(30); + ContentTitle *title = new ContentTitle(contentFrame); + title->setTitle(tr("Custom Web Screensaver")); + title->label()->setForegroundRole(QPalette::BrightText); + DFontSizeManager::instance()->bind(title, DFontSizeManager::T4, QFont::Medium); + contentlayout->addWidget(title); + } + + auto createGroup = [this, contentlayout, contentFrame] + (const QString &text, const QList &contWid) { + DWidget *wid = new DWidget(contentFrame); + + // title + auto title = new ContentTitle(wid); + title->setTitle(text); + DFontSizeManager::instance()->bind(title, DFontSizeManager::T5, QFont::Medium); + + { + QHBoxLayout *hLay = new QHBoxLayout(wid); + hLay->setContentsMargins(10, 0, 0, 0); + hLay->addWidget(title); + contentlayout->addWidget(wid); + } + + QVBoxLayout *bgGpLayout = new QVBoxLayout; + DBackgroundGroup *bgGroup = new DBackgroundGroup(bgGpLayout); + bgGroup->setItemSpacing(1); + bgGroup->setItemMargins(QMargins(0, 0, 0, 0)); + bgGroup->setBackgroundRole(QPalette::Window); + bgGroup->setUseWidgetBackground(false); + contentlayout->addWidget(bgGroup); + + for (QWidget *pwid : contWid) { + QWidget *wrapperWidget = new QWidget(bgGroup); + QHBoxLayout *hLay = new QHBoxLayout(wrapperWidget); + hLay->setContentsMargins(10, 6, 10, 6); + pwid->setParent(wrapperWidget); + hLay->addWidget(pwid); + + bgGpLayout->addWidget(wrapperWidget); + } + + QSpacerItem *spaceItem = new QSpacerItem(0, 20, QSizePolicy::Minimum,QSizePolicy::Expanding); + contentlayout->addItem(spaceItem); + }; + + // path + contentlayout->addSpacing(30); + pathWidget = new SelectPathWidget; + createGroup(tr("Url"), {pathWidget}); + + if (isWayland()) { + // 设置对话框窗口最大最小化按钮隐藏 + this->setWindowFlags(this->windowFlags() & ~Qt::WindowMinMaxButtonsHint); + this->setAttribute(Qt::WA_NativeWindow); + this->windowHandle()->setProperty("_d_dwayland_minimizable", false); + this->windowHandle()->setProperty("_d_dwayland_maximizable", false); + this->windowHandle()->setProperty("_d_dwayland_resizable", false); + } + + setFixedSize(QSize(682, 332)); + return; +} + +void SlideShowConfigDialog::initConnect() +{ + connect(pathWidget, &SelectPathWidget::requsetSetPath, this, &SlideShowConfigDialog::selectPath); +} + +void SlideShowConfigDialog::startConfig() +{ + setWindowFlags(this->windowFlags() & ~Qt::WindowMaximizeButtonHint); + + setAttribute(Qt::WA_DeleteOnClose); + + // remove dialog flag to let dock show window entry. + setWindowFlag(Qt::Dialog, false); + + QScreen *screen = qApp->primaryScreen(); + move(screen->geometry().width() / 2 - this->width() / 2, + screen->geometry().height() / 2 - this->height() / 2); + + setFocus(); + show(); +} + +void SlideShowConfigDialog::mousePressEvent(QMouseEvent *event) +{ + setFocus(); + DAbstractDialog::mouseMoveEvent(event); +} + +void SlideShowConfigDialog::handArguments(const QStringList &) +{ + activateWindow(); +} + +void SlideShowConfigDialog::selectPath() +{ + QString currentPath = pathWidget->getPath(); + + // url为空,则重置为默认值 + if (currentPath.isEmpty()) { + currentPath = SlideshowConfig::defaultPath(); + } + if (!currentPath.startsWith(QStringLiteral("http://")) && !currentPath.startsWith(QStringLiteral("https://"))) + currentPath = QStringLiteral("https://") + currentPath; + + SlideshowConfig::instance()->setSlideShowPath(currentPath); +} diff --git a/customscreensaver/deepin-web-screensaver/src/slideshowconfigdialog.h b/customscreensaver/deepin-web-screensaver/src/slideshowconfigdialog.h new file mode 100644 index 00000000..7b04fc2b --- /dev/null +++ b/customscreensaver/deepin-web-screensaver/src/slideshowconfigdialog.h @@ -0,0 +1,39 @@ +// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef SLIDESHOWCONFIGDIALOG_H +#define SLIDESHOWCONFIGDIALOG_H + +#include "config/selectpathwidget.h" +#include "singleinstance.h" + +#include +#include +#include + +class SlideShowConfigDialog : public DTK_WIDGET_NAMESPACE::DAbstractDialog +{ + Q_OBJECT +public: + explicit SlideShowConfigDialog(QWidget *parent = nullptr); + ~SlideShowConfigDialog(); + void startConfig(); + +protected: + void mousePressEvent(QMouseEvent *event) override; + void handArguments(const QStringList &); +private slots: + void selectPath(); + +private: + void initUI(); + void initConnect(); + +private: + DTK_WIDGET_NAMESPACE::DTitlebar *frameBar = nullptr; + SelectPathWidget *pathWidget = nullptr; + Dtk::Widget::DPushButton *m_confirmBtn = nullptr; +}; + +#endif // SLIDESHOWCONFIGDIALOG_H diff --git a/customscreensaver/deepin-web-screensaver/src/slideshowscreensaver.cpp b/customscreensaver/deepin-web-screensaver/src/slideshowscreensaver.cpp new file mode 100644 index 00000000..e8d2d529 --- /dev/null +++ b/customscreensaver/deepin-web-screensaver/src/slideshowscreensaver.cpp @@ -0,0 +1,109 @@ +// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "slideshowscreensaver.h" +#include "slideshowconfig.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define IMAGE_MAX_SIZE 30 * 1024 * 1024 // Only display image smaller than 30M + +DWIDGET_USE_NAMESPACE + +SlideshowScreenSaver::SlideshowScreenSaver(bool subWindow, QWidget *parent) + : QWebEngineView(parent), m_subWindow(subWindow) +{ + if (m_subWindow) + setWindowFlag(Qt::WindowTransparentForInput, true); +} + +SlideshowScreenSaver::~SlideshowScreenSaver() +{ +} + +void SlideshowScreenSaver::closeEvent(QCloseEvent *event) +{ + for (auto wid : findChildren()) + wid->close(); + + QWidget::closeEvent(event); +} + +bool SlideshowScreenSaver::nativeEventFilter(const QByteArray &eventType, void *message, long *result) +{ + Q_UNUSED(result); + if (eventType == "xcb_generic_event_t") { + xcb_generic_event_t *event = reinterpret_cast(message); + int type = (event->response_type & ~0x80); + if (XCB_CONFIGURE_NOTIFY == type) { + xcb_configure_notify_event_t *ce = reinterpret_cast(event); + qInfo() << "parent window size changed" << ce->width << ce->height; + QSize widSize = mapFromHandle(QSize(ce->width, ce->height)); + if (widSize != size()) { + qInfo() << "update window size:" << widSize; + resize(widSize); + } + } else if (XCB_DESTROY_NOTIFY == type) { + xcb_destroy_notify_event_t *ce = reinterpret_cast(event); + if (ce->window == Window(this->windowHandle()->winId())) { + qInfo() << "parent window closed"; + QMetaObject::invokeMethod(this, "close", Qt::QueuedConnection); + } + } + } + return false; +} + +void SlideshowScreenSaver::init() +{ + connect(this, &QWebEngineView::loadFinished, [&](bool success) { + if (!success) { + if (m_url.startsWith(QStringLiteral("https://"))) + m_url.replace(QStringLiteral("https://"), QStringLiteral("http://")); + SlideshowConfig::instance()->m_dCfg->setValue(kSlideshowPath, m_url); + this->load(QUrl(m_url)); + } + }); + updateViewSize(this->size()); + loadSlideshowImages(); +} + +void SlideshowScreenSaver::loadSlideshowImages() +{ + m_url = SlideshowConfig::instance()->slideshowPath(); + this->load(QUrl(m_url)); +} + +QSize SlideshowScreenSaver::mapFromHandle(const QSize &handleSize) +{ + qreal ratio = devicePixelRatioF(); + qDebug() << "parent window handle size" << handleSize << "devicePixelRatio" << ratio; + + if (ratio > 0 && ratio != 1.0) + return handleSize / ratio; + else + return handleSize; +} + +void SlideshowScreenSaver::updateViewSize(const QSize &size) +{ + QSize updateSize = mapFromHandle(size); + + if (updateSize != size){ + this->resize(updateSize); + } +} diff --git a/customscreensaver/deepin-web-screensaver/src/slideshowscreensaver.h b/customscreensaver/deepin-web-screensaver/src/slideshowscreensaver.h new file mode 100644 index 00000000..bbd9ff90 --- /dev/null +++ b/customscreensaver/deepin-web-screensaver/src/slideshowscreensaver.h @@ -0,0 +1,37 @@ +// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef SLIDESHOWSCREENSAVER_H +#define SLIDESHOWSCREENSAVER_H + +#include +#include +#include +#include + +class SlideshowScreenSaver : public QWebEngineView, public QAbstractNativeEventFilter +{ + Q_OBJECT +public: + explicit SlideshowScreenSaver(bool subWindow = false, QWidget *parent = nullptr); + ~SlideshowScreenSaver() override; + + bool nativeEventFilter(const QByteArray &eventType, void *message, long *result) override; + void init(); + +protected: + void closeEvent(QCloseEvent *event) override; + + QSize mapFromHandle(const QSize &handleSize); + +private: + void loadSlideshowImages(); + void updateViewSize(const QSize &updatesize); + +private: + bool m_subWindow { false }; + QString m_url; +}; + +#endif // SLIDESHOWSCREENSAVER_H diff --git a/customscreensaver/deepin-web-screensaver/translations/deepin-web-screensaver.ts b/customscreensaver/deepin-web-screensaver/translations/deepin-web-screensaver.ts new file mode 100644 index 00000000..ed1cfbe3 --- /dev/null +++ b/customscreensaver/deepin-web-screensaver/translations/deepin-web-screensaver.ts @@ -0,0 +1,30 @@ + + + + + SelectPathWidget + + + Enter web url + Enter web url + + + + apply + apply + + + + SlideShowConfigDialog + + + Custom Web Screensaver + Custom Web Screensaver + + + + Url + Url + + + diff --git a/customscreensaver/deepin-web-screensaver/translations/deepin-web-screensaver_zh_CN.ts b/customscreensaver/deepin-web-screensaver/translations/deepin-web-screensaver_zh_CN.ts new file mode 100644 index 00000000..dc20f293 --- /dev/null +++ b/customscreensaver/deepin-web-screensaver/translations/deepin-web-screensaver_zh_CN.ts @@ -0,0 +1,30 @@ + + + + + SelectPathWidget + + + Enter web url + 输入网站地址 + + + + apply + 应用 + + + + SlideShowConfigDialog + + + Custom Web Screensaver + 自定义Web屏幕保护程序 + + + + Url + 网址 + + + diff --git a/customscreensaver/deepin-web-screensaver/translations/deepin-web-screensaver_zh_HK.ts b/customscreensaver/deepin-web-screensaver/translations/deepin-web-screensaver_zh_HK.ts new file mode 100644 index 00000000..73f6c9c5 --- /dev/null +++ b/customscreensaver/deepin-web-screensaver/translations/deepin-web-screensaver_zh_HK.ts @@ -0,0 +1,30 @@ + + + + + SelectPathWidget + + + Enter web url + 輸入網頁地址 + + + + apply + 應用 + + + + SlideShowConfigDialog + + + Custom Web Screensaver + 自定義網頁荧幕保護程式 + + + + Url + 網址 + + + diff --git a/customscreensaver/deepin-web-screensaver/update_translations.sh b/customscreensaver/deepin-web-screensaver/update_translations.sh new file mode 100755 index 00000000..aaedef54 --- /dev/null +++ b/customscreensaver/deepin-web-screensaver/update_translations.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +# SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. +# +# SPDX-License-Identifier: GPL-3.0-or-later + +# this file is used to auto update ts file. + +lupdate -pro deepin-custom-screensaver.pro -ts translations/deepin-custom-screensaver.ts -no-obsolete +lupdate -pro deepin-custom-screensaver.pro -ts translations/deepin-custom-screensaver_zh_CN.ts -no-obsolete diff --git a/debian/control b/debian/control index e9ae59e3..fc363dad 100644 --- a/debian/control +++ b/debian/control @@ -2,7 +2,7 @@ Source: deepin-screensaver Section: devel Priority: optional Maintainer: Deepin Packages Builder -Build-Depends: debhelper (>=9), qtbase5-dev, qttools5-dev-tools, qtdeclarative5-dev, libqt5x11extras5-dev, libdtkwidget-dev, deepin-desktop-base, libx11-dev, libxss-dev, libxext-dev, libdframeworkdbus-dev, pkg-config, qml-module-qt-labs-platform +Build-Depends: debhelper (>=9), qtbase5-dev, qttools5-dev-tools, qtdeclarative5-dev, libqt5x11extras5-dev, libdtkwidget-dev, deepin-desktop-base, libx11-dev, libxss-dev, libxext-dev, libdframeworkdbus-dev, pkg-config, qml-module-qt-labs-platform, qtwebengine5-dev Standards-Version: 3.9.8 Package: deepin-screensaver diff --git a/debian/deepin-screensaver-xscreensaver-data.install b/debian/deepin-screensaver-xscreensaver-data.install index b428f10b..dce84459 100644 --- a/debian/deepin-screensaver-xscreensaver-data.install +++ b/debian/deepin-screensaver-xscreensaver-data.install @@ -2,3 +2,6 @@ usr/lib/deepin-screensaver/modules/* usr/share/deepin-custom-screensaver/translations/*.qm etc/deepin-screensaver/deepin-custom-screensaver/*.desktop usr/share/dsg/configs/org.deepin.screensaver/org.deepin.customscreensaver.json +usr/share/deepin-web-screensaver/translations/*.qm +etc/deepin-screensaver/deepin-web-screensaver/*.desktop +usr/share/dsg/configs/org.deepin.screensaver/org.deepin.webscreensaver.json \ No newline at end of file