1
0
mirror of https://gitlab.com/kelteseth/ScreenPlay.git synced 2024-07-05 12:29:05 +02:00

Resolve "Add Wayland layer shell support"

This commit is contained in:
Elias Steurer 2023-10-29 10:26:42 +00:00
parent e2790b9fa2
commit f546c35f44
30 changed files with 257 additions and 692 deletions

1
.gitignore vendored
View File

@ -261,3 +261,4 @@ cython_debug/
/ThirdParty/qml-archive/**
/ThirdParty/qml-plausible/
/ThirdParty/ffmpeg/**
/ThirdParty/qt-layer-shell/**

View File

@ -18,16 +18,28 @@
# Otherwise libglib2 needs interaction
- export DEBIAN_FRONTEND=noninteractive
- apt update -y
- apt install curl wget zip unzip tar git pkg-config libxcb-* libfontconfig-dev apt-transport-https ca-certificates gnupg software-properties-common python3 python3-pip build-essential libgl1-mesa-dev mesa-common-dev lld ninja-build libxkbcommon-* libx11-dev xserver-xorg-dev xorg-dev -y
- wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null | gpg --dearmor - | tee /usr/share/keyrings/kitware-archive-keyring.gpg >/dev/null
- echo 'deb [signed-by=/usr/share/keyrings/kitware-archive-keyring.gpg] https://apt.kitware.com/ubuntu/ focal-rc main' | tee -a /etc/apt/sources.list.d/kitware.list >/dev/null
- apt update -y
- apt install cmake -y
- apt install cmake python3.10-venv libwayland-dev wayland-protocols curl wget zip unzip tar git pkg-config libxcb-* libfontconfig-dev apt-transport-https ca-certificates gnupg software-properties-common python3 python3-pip build-essential libgl1-mesa-dev mesa-common-dev lld ninja-build libxkbcommon-* libx11-dev xserver-xorg-dev xorg-dev -y
- python3 -m venv env
- source env/bin/activate
- python3 -m pip install -U pip
- python3 -m pip install -r Tools/requirements.txt
- python3 Tools/setup.py
- cd ThirdParty
- git clone https://invent.kde.org/frameworks/extra-cmake-modules.git
- cd extra-cmake-modules
- cmake configure .
- make
- make install
- cd ..
- git clone https://invent.kde.org/plasma/layer-shell-qt.git
- cd layer-shell-qt
- cmake configure . -DCMAKE_PREFIX_PATH="./../../../aqt/6.5.2/gcc_64"
- make
- make install
- cd ..
- cd ..
image:
name: ubuntu:20.04
name: ubuntu:22.04
tags:
- gitlab-org-docker
artifacts:

View File

@ -4,6 +4,8 @@
"delgan.qml-format",
"ms-vscode.cpptools-extension-pack",
"ms-vscode.cmake-tools",
"seanwu.vscode-qt-for-python"
"seanwu.vscode-qt-for-python",
"mhutchie.git-graph",
"vadimcn.vscode-lldb"
]
}

2
.vscode/launch.json vendored
View File

@ -23,7 +23,7 @@
"visualizerFile": "${workspaceFolder}/.vscode/qt.natvis.xml"
},
{
"name": "macOS Launch",
"name": "macOS/linux Launch",
"type": "lldb",
"request": "launch",
"program": "${command:cmake.launchTargetPath}",

View File

@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.23.0)
cmake_minimum_required(VERSION 3.22.0)
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMake" ${CMAKE_MODULE_PATH})
include(GetProjectVersion)
@ -25,7 +25,13 @@ endif()
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
set(CMAKE_CXX_STANDARD 20)
set(THIRD_PARTY_PATH "${CMAKE_CURRENT_SOURCE_DIR}/ThirdParty/")
set(THIRD_PARTY_PATH "${CMAKE_CURRENT_SOURCE_DIR}/ThirdParty")
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMake" ${CMAKE_MODULE_PATH})
list(APPEND CMAKE_MODULE_PATH "${THIRD_PARTY_PATH}/ecm/modules")
list(APPEND CMAKE_MODULE_PATH "${THIRD_PARTY_PATH}/ecm/find-modules")
list(APPEND CMAKE_MODULE_PATH "${THIRD_PARTY_PATH}/ecm/kde-modules")
message(STATUS "[PROJECT] CMAKE_MODULE_PATH = ${CMAKE_MODULE_PATH}")
option(OSX_BUNDLE "Enable distribution macOS bundle" OFF)
set(CMAKE_OSX_DEPLOYMENT_TARGET "13.0")
@ -81,6 +87,14 @@ else()
set(DATE_ARG "")
endif()
if(UNIX AND NOT APPLE)
# Fixes QWebEngine linker errors on Ubuntu 22.04
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fuse-ld=gold")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fuse-ld=gold")
endif()
execute_process(
COMMAND ${DATE_COMMAND} ${DATE_ARG}
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
@ -104,14 +118,17 @@ add_compile_definitions(BUILD_DATE="${BUILD_DATE}")
add_compile_definitions(GIT_BRANCH_NAME="${GIT_BRANCH_NAME}")
add_compile_definitions(GIT_COMMIT_HASH="${GIT_COMMIT_HASH}")
if(UNIX AND NOT APPLE)
# Fixes QWebEngine linker errors on Ubuntu 20.04
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fuse-ld=gold")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fuse-ld=gold")
endif()
add_subdirectory(CMake)
add_subdirectory(ThirdParty)
set(ECM_DIR "${THIRD_PARTY_PATH}/ecm")
add_subdirectory(CMake)
if(UNIX AND NOT APPLE)
# Needs to be append, because we include ecm as third party on linux
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMake")
list(APPEND CMAKE_MODULE_PATH "${ECM_DIR}")
list(APPEND CMAKE_MODULE_PATH "${ECM_DIR}/cmake")
else()
endif()
add_subdirectory(Tools)
add_subdirectory(ScreenPlay)
@ -149,6 +166,7 @@ message(STATUS "[PROJECT] CMAKE_VERSION = ${CMAKE_VERSION}")
message(STATUS "[PROJECT] SCREENPLAY_QML_MODULES_PATH = ${SCREENPLAY_QML_MODULES_PATH}")
message(STATUS "[PROJECT] CMAKE_TOOLCHAIN_FILE = ${CMAKE_TOOLCHAIN_FILE}")
message(STATUS "[PROJECT] VCPKG_PATH = ${VCPKG_PATH}")
message(STATUS "[PROJECT] CMAKE_MODULE_PATH = ${CMAKE_MODULE_PATH}")
message(STATUS "[PROJECT] VCPKG_TARGET_TRIPLET = ${VCPKG_TARGET_TRIPLET}")
message(STATUS "[PROJECT] CMAKE_PREFIX_PATH = ${CMAKE_PREFIX_PATH}")
message(STATUS "[OPTION] SCREENPLAY_DEPLOY = ${SCREENPLAY_DEPLOY}")

View File

@ -74,7 +74,7 @@
}
},
{
"name": "linux-debug",
"name": "linux-generic-debug",
"displayName": "ScreenPlay 64bit Debug Linux",
"description": "Linux only!",
"generator": "Ninja",
@ -84,6 +84,40 @@
"lhs": "${hostSystemName}",
"rhs": "Linux"
},
"architecture": {
"value": "x64",
"strategy": "external"
},
"cacheVariables": {
"CMAKE_CXX_COMPILER": "g++",
"CMAKE_C_COMPILER": "gcc",
"CMAKE_BUILD_TYPE": "Debug",
"CMAKE_TOOLCHAIN_FILE": "${sourceDir}/../vcpkg/scripts/buildsystems/vcpkg.cmake",
"VCPKG_TARGET_TRIPLET": "x64-linux",
"SCREENPLAY_STEAM": "OFF",
"SCREENPLAY_TESTS": "OFF"
}
},
{
"name": "linux-relwithdebinfo",
"displayName": "ScreenPlay 64bit RelWithDebInfo Linux",
"inherits": "linux-generic-debug",
"binaryDir": "${sourceDir}/../build_ScreenPlay_Qt_6.5.2_GCC_RelWithDebInfo",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "RelWithDebInfo"
}
},
{
"name": "linux-aqt-debug",
"displayName": "ScreenPlay 64bit Debug Linux using aqt",
"description": "Linux only!",
"generator": "Ninja",
"binaryDir": "${sourceDir}/../build_ScreenPlay_Qt_6.5.2_GCC_Debug",
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Linux"
},
"environment": {
"qt_path": "${sourceDir}/../aqt"
},
@ -101,9 +135,9 @@
}
},
{
"name": "linux-relwithdebinfo",
"displayName": "ScreenPlay 64bit RelWithDebInfo Linux",
"inherits": "linux-debug",
"name": "linux-aqt-relwithdebinfo",
"displayName": "ScreenPlay 64bit RelWithDebInfo Linux using aqt",
"inherits": "linux-ubuntu-debug",
"binaryDir": "${sourceDir}/../build_ScreenPlay_Qt_6.5.2_GCC_RelWithDebInfo",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "RelWithDebInfo"

View File

@ -74,11 +74,11 @@ Here are some ways you can contribute:
<div align="center">
| Feature | Windows | Linux | MacOS |
| Feature | Windows | Linux X11 and Wayland (layer shell) | MacOS |
|------------------------ |--------- |------- |------- |
| __ScreenPlay Main App__ | ✔ | ✔ | ✔ |
| __Steam Binaries__ | ✔ | ❌ | ✔ |
| __Wallpaper__ | ✔ | ❓ Help Needed for Gnome/KDE/etc! | ✔ |
| __Wallpaper__ | ✔ | | ✔ |
| __Widgets__ | ✔ | ✔ | ✔ |
| __Multilanguage (EN,DE,RU,FR,ES,KO,VI,CH_ZN,PT_BR🆕)__ | ✔ | ✔ | ✔ |

View File

@ -101,13 +101,6 @@ public slots:
void setMainWindowEngine(QQmlApplicationEngine* mainWindowEngine);
void setWizards(Wizards* wizards);
private:
bool setupKDE();
bool isKDEInstalled();
void installKDEWallpaper();
void upgradeKDEWallpaper();
void restartKDE();
std::optional<bool> isNewestKDEWallpaperInstalled();
private:
QNetworkAccessManager m_networkAccessManager;
@ -126,8 +119,5 @@ private:
std::shared_ptr<MonitorListModel> m_monitorListModel;
std::shared_ptr<ProfileListModel> m_profileListModel;
std::shared_ptr<InstalledListFilter> m_installedListFilter;
QString m_kdeWallpaperPath;
QString m_appKdeWallapperPath;
};
}

View File

@ -27,7 +27,6 @@ class ScreenPlayManager : public QObject {
Q_PROPERTY(int activeWallpaperCounter READ activeWallpaperCounter WRITE setActiveWallpaperCounter NOTIFY activeWallpaperCounterChanged)
Q_PROPERTY(int activeWidgetsCounter READ activeWidgetsCounter WRITE setActiveWidgetsCounter NOTIFY activeWidgetsCounterChanged)
Q_PROPERTY(bool isKDEConnected READ isKDEConnected WRITE setIsKDEConnected NOTIFY isKDEConnectedChanged)
public:
explicit ScreenPlayManager(QObject* parent = nullptr);
@ -41,8 +40,6 @@ public:
int activeWidgetsCounter() const { return m_activeWidgetsCounter; }
bool isAnotherScreenPlayInstanceRunning() { return m_isAnotherScreenPlayInstanceRunning; }
bool isKDEConnected() const;
void setIsKDEConnected(bool isKDEConnected);
signals:
void activeWallpaperCounterChanged(int activeWallpaperCounter);
@ -55,8 +52,6 @@ signals:
void profilesSaved();
void displayErrorPopup(const QString& msg);
void isKDEConnectedChanged(bool isKDEConnected);
private slots:
bool saveProfiles();
@ -168,7 +163,6 @@ private:
QTimer m_saveLimiter;
const quint16 m_webSocketPort = 16395;
bool m_isKDEConnected = false;
};
}

View File

@ -95,7 +95,6 @@ signals:
void volumeChanged(float volume);
void isLoopingChanged(bool isLooping);
void playbackRateChanged(float playbackRate);
void messageKDECloseWallpaper();
void requestSave();
void requestClose(const QString& appID);

View File

@ -72,6 +72,7 @@ public:
Unknown,
OSX,
Windows,
Wayland,
Cinnamon,
Enlightenment,
Gnome,

View File

@ -200,10 +200,6 @@ void App::init()
m_mainWindowEngine->addImportPath(guiAppInst->applicationDirPath() + "/qml");
guiAppInst->addLibraryPath(guiAppInst->applicationDirPath() + "/qml");
if (m_settings->desktopEnvironment() == Settings::DesktopEnvironment::KDE) {
setupKDE();
}
QQuickStyle::setStyle("Material");
m_mainWindowEngine->load(QUrl(QStringLiteral("qrc:/qml/ScreenPlayApp/main.qml")));
@ -229,112 +225,6 @@ void App::exit()
guiAppInst->quit();
}
bool App::isKDEInstalled()
{
QProcess plasmaShellVersionProcess;
plasmaShellVersionProcess.start("plasmashell", { "--version" });
plasmaShellVersionProcess.waitForFinished();
QString versionOut = plasmaShellVersionProcess.readAll();
if (!versionOut.contains("plasmashell ")) {
qWarning() << "Unable to read plasma shell version. ScreenPlay only works on KDE";
return false;
}
return true;
}
void App::installKDEWallpaper()
{
qInfo() << "Install ScreenPlay KDE Wallpaper";
QProcess process;
process.setWorkingDirectory(m_appKdeWallapperPath);
process.start("plasmapkg2", { "--install", "ScreenPlay" });
process.waitForFinished();
process.terminate();
}
void App::upgradeKDEWallpaper()
{
qInfo() << "Upgrade ScreenPlay KDE Wallpaper";
QProcess process;
process.setWorkingDirectory(m_appKdeWallapperPath);
process.start("plasmapkg2", { "--upgrade", "ScreenPlay" });
process.waitForFinished();
process.terminate();
qInfo() << process.readAllStandardError() << process.readAllStandardOutput();
}
void App::restartKDE()
{
qInfo() << "Restart KDE ";
QProcess process;
process.start("kquitapp5", { "plasmashell" });
process.waitForFinished();
process.terminate();
qInfo() << process.readAllStandardError() << process.readAllStandardOutput();
process.startDetached("kstart5", { "plasmashell" });
qInfo() << process.readAllStandardError() << process.readAllStandardOutput();
}
std::optional<bool> App::isNewestKDEWallpaperInstalled()
{
QFileInfo installedWallpaperMetadata(m_kdeWallpaperPath + "/metadata.desktop");
QSettings installedWallpaperSettings(installedWallpaperMetadata.absoluteFilePath(), QSettings::Format::IniFormat);
installedWallpaperSettings.beginGroup("Desktop Entry");
const QString installedWallpaperVersion = installedWallpaperSettings.value("Version").toString();
installedWallpaperSettings.endGroup();
const QVersionNumber installedVersionNumber = QVersionNumber::fromString(installedWallpaperVersion);
QFileInfo currentWallpaperMetadata(m_appKdeWallapperPath + "/ScreenPlay/metadata.desktop");
QSettings currentWallpaperSettings(currentWallpaperMetadata.absoluteFilePath(), QSettings::Format::IniFormat);
currentWallpaperSettings.beginGroup("Desktop Entry");
const QString currentWallpaperVersion = currentWallpaperSettings.value("Version").toString();
currentWallpaperSettings.endGroup();
const QVersionNumber currentVersionNumber = QVersionNumber::fromString(currentWallpaperVersion);
qInfo() << "installedVersionNumber" << installedVersionNumber << "currentVersionNumber " << currentVersionNumber;
if (installedVersionNumber.isNull() || currentVersionNumber.isNull()) {
qInfo() << "Unable to parse version number from:" << currentWallpaperVersion << installedWallpaperVersion;
qInfo() << "Reinstall ScreenPlay Wallpaper";
return std::nullopt;
} else {
return { installedVersionNumber >= currentVersionNumber };
}
}
/*!
\brief
*/
bool App::setupKDE()
{
m_kdeWallpaperPath = QDir(QDir::homePath() + "/.local/share/plasma/wallpapers/ScreenPlay/").canonicalPath();
m_appKdeWallapperPath = QGuiApplication::instance()->applicationDirPath() + "/kde";
if (!isKDEInstalled())
return false;
QFileInfo installedWallpaperMetadata(m_kdeWallpaperPath + "/metadata.desktop");
if (!installedWallpaperMetadata.exists()) {
installKDEWallpaper();
restartKDE();
return true;
}
if (auto isNewer = isNewestKDEWallpaperInstalled()) {
if (!isNewer.value()) {
upgradeKDEWallpaper();
return true;
}
qInfo() << "All up to date!" << isNewer.value();
return true;
} else {
return false;
}
}
void App::showDockIcon(const bool show)
{
#if defined(Q_OS_OSX)

View File

@ -83,28 +83,6 @@ void ScreenPlayManager::init(
m_monitorListModel = mlm;
m_settings = settings;
if (m_settings->desktopEnvironment() == Settings::DesktopEnvironment::KDE) {
m_websocketServer = std::make_unique<QWebSocketServer>(QStringLiteral("ScreenPlayWebSocket"), QWebSocketServer::SslMode::NonSecureMode);
const bool success = m_websocketServer->listen(QHostAddress::Any, m_webSocketPort);
qInfo() << "Open Websocket:" << success << "port:" << m_webSocketPort;
QObject::connect(m_websocketServer.get(), &QWebSocketServer::newConnection, this, [this]() {
qInfo() << "New Websocket Connection";
auto* socket = m_websocketServer->nextPendingConnection();
QObject::connect(socket, &QWebSocket::textMessageReceived, this, [this](const QString& message) {
qInfo() << "Message:" << message;
});
QObject::connect(socket, &QWebSocket::disconnected, this, [this, socket]() {
m_connections.removeOne(socket);
setIsKDEConnected(false);
qInfo() << "Disconnected connection count: " << m_connections.count();
});
m_connections.push_back(socket);
setIsKDEConnected(true);
// socket->flush();
});
}
// Reset to default settings if we are unable to load
// the existing one
if (!loadProfiles()) {
@ -153,22 +131,6 @@ bool ScreenPlayManager::createWallpaper(
const QString path = QUrl::fromUserInput(absoluteStoragePath).toLocalFile();
const QString appID = ScreenPlayUtil::generateRandomString();
if (m_settings->desktopEnvironment() == Settings::DesktopEnvironment::KDE) {
if (m_connections.empty())
return false;
QJsonObject msg;
msg.insert("command", "replace");
msg.insert("absolutePath", path);
msg.insert("type", static_cast<int>(type));
msg.insert("fillMode", static_cast<int>(fillMode));
msg.insert("volume", volume);
msg.insert("file", file);
m_connections.first()->sendTextMessage(QJsonDocument(msg).toJson());
m_connections.first()->flush();
}
// Only support remove wallpaper that spans over 1 monitor
if (monitorIndex.length() == 1) {
int i = 0;
@ -207,11 +169,7 @@ bool ScreenPlayManager::createWallpaper(
QObject::connect(wallpaper.get(), &ScreenPlayWallpaper::requestSave, this, &ScreenPlayManager::requestSaveProfiles);
QObject::connect(wallpaper.get(), &ScreenPlayWallpaper::requestClose, this, &ScreenPlayManager::removeWallpaper);
QObject::connect(wallpaper.get(), &ScreenPlayWallpaper::error, this, &ScreenPlayManager::displayErrorPopup);
if (m_settings->desktopEnvironment() != Settings::DesktopEnvironment::KDE) {
if (!wallpaper->start()) {
return false;
}
}
m_screenPlayWallpapers.append(wallpaper);
m_monitorListModel->setWallpaperMonitor(wallpaper, monitorIndex);
increaseActiveWallpaperCounter();
@ -286,15 +244,6 @@ bool ScreenPlayManager::removeAllWallpapers()
return false;
}
}
if (m_settings->desktopEnvironment() == Settings::DesktopEnvironment::KDE) {
for (auto& connection : m_connections) {
QJsonObject obj;
obj.insert("command", "quit");
connection->sendTextMessage(QJsonDocument(obj).toJson(QJsonDocument::Compact));
connection->flush();
connection->close();
}
}
emit requestSaveProfiles();
@ -486,9 +435,6 @@ bool ScreenPlayManager::removeWallpaper(const QString& appID)
return false;
}
if (m_settings->desktopEnvironment() == Settings::DesktopEnvironment::Windows || m_settings->desktopEnvironment() == Settings::DesktopEnvironment::OSX)
wallpaper->messageKDECloseWallpaper();
qInfo() << "Remove wallpaper " << wallpaper->file() << "at monitor " << wallpaper->screenNumber();
// The MonitorListModel contains a shared_ptr of this object that needs to be removed
@ -723,19 +669,6 @@ bool ScreenPlayManager::loadProfiles()
return true;
}
bool ScreenPlayManager::isKDEConnected() const
{
return m_isKDEConnected;
}
void ScreenPlayManager::setIsKDEConnected(bool isKDEConnected)
{
if (m_isKDEConnected == isKDEConnected)
return;
m_isKDEConnected = isKDEConnected;
emit isKDEConnectedChanged(isKDEConnected);
}
}
#include "moc_screenplaymanager.cpp"

View File

@ -59,8 +59,8 @@ Settings::Settings(const std::shared_ptr<GlobalVariables>& globalVariables,
setDesktopEnvironment(DesktopEnvironment::OSX);
#endif
#ifdef Q_OS_LINUX
// We only support KDE for now
setDesktopEnvironment(DesktopEnvironment::KDE);
// We only support Wayland wl_roots for now
setDesktopEnvironment(DesktopEnvironment::Wayland);
#endif
qRegisterMetaType<Settings::Language>("Settings::Language");

View File

@ -30,8 +30,8 @@ elseif(APPLE)
src/macintegration.h
src/macwindow.h)
elseif(UNIX)
set(SOURCES src/linuxx11window.cpp)
set(HEADER src/linuxx11window.h)
set(SOURCES src/linuxx11window.cpp src/linuxwaylandwindow.cpp)
set(HEADER src/linuxx11window.h src/linuxwaylandwindow.h)
endif()
set(SOURCES ${SOURCES} main.cpp src/basewindow.cpp)
@ -86,8 +86,12 @@ elseif(UNIX AND NOT APPLE)
endif()
if(UNIX AND NOT APPLE)
include(CopyRecursive)
copy_recursive(${CMAKE_CURRENT_SOURCE_DIR}/kde/ScreenPlay ${CMAKE_BINARY_DIR}/bin/kde/ScreenPlay "*")
find_package(ECM CONFIG REQUIRED NO_MODULE)
set(LayerShellQt "${CMAKE_CURRENT_SOURCE_DIR}/../ThirdParty/layer-shell-qt/")
find_package(LayerShellQt REQUIRED)
target_link_libraries(
${PROJECT_NAME}
PRIVATE LayerShellQtInterface)
endif()
if(APPLE)

View File

@ -1,28 +0,0 @@
# ScreenPlay Wallpaper for KDE Plasma Desktop
One has to install it via the command below. Simply putting it into:
* ~/.local/share/plasma/wallpapers/
Will not work because KDE uses the kpluginindex.json (that is actually a bz2 file. Do not ask why...) to load all available wallpaper.
#### Installation
```
sudo apt install qml-module-qt-websockets qtwebengine5-*
plasmapkg2 --install ScreenPlay
```
#### Application structure
Because Wallpaper and Widgets are already a different application we can extend the logic for KDE. For this we create a local websocket instance to communicate with our main ScreenPlay app.
### Development
1. Make changes
1. `plasmapkg2 --upgrade ScreenPlay`
1. Open Desktop Settings
- Select Wallpaper type Image
1. Close Desktop Settings Window
1. Open Desktop Settings
- Select Wallpaper type ScreenPlay
```
plasmapkg2 --upgrade ScreenPlay ; kquitapp5 plasmashell; kstart5 plasmashell
```

View File

@ -1,15 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" >
<kcfgfile name=""/>
<group name="General">
<entry name="MonitorIndex" type="int">
<label>Monitor Index aaa</label>
<default>0</default>
</entry>
</group>
</kcfg>

View File

@ -1,72 +0,0 @@
import QtQuick 2.15
Rectangle {
anchors.fill: parent
color: "black"
Rectangle {
id: toBeCreated
anchors.fill: parent
color: "black"
opacity: 0
Text {
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
wrapMode: Text.WordWrap
anchors.centerIn: parent
text: qsTr("Please start ScreenPlay before launching the wallpaper")
color: "White"
font.pixelSize: 50
}
OpacityAnimator on opacity {
id: createAnimation
from: 0
to: 1
duration: 1000
onRunningChanged: {
if (!running) {
toBeDeleted.opacity = 1;
toBeCreated.opacity = 0;
destroyAnimation.start();
}
}
}
Component.onCompleted: {
createAnimation.start();
}
}
Rectangle {
id: toBeDeleted
opacity: 0
anchors.fill: parent
color: "black"
Text {
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
wrapMode: Text.WordWrap
anchors.centerIn: parent
text: qsTr("Please start ScreenPlay before launching the wallpaper")
color: "White"
font.pixelSize: 50
}
OpacityAnimator on opacity {
id: destroyAnimation
from: 1
to: 0
duration: 1000
running: false
onRunningChanged: {
if (!running) {
toBeDeleted.opacity = 0;
toBeCreated.opacity = 0;
createAnimation.start();
}
}
}
}
}

View File

@ -1,86 +0,0 @@
import QtQuick 2.0
import QtQuick.Controls 2.12
import QtWebSockets 1.1
import QtWebEngine 1.8
import QtMultimedia 5.12
import Qt.labs.settings 1.1
Rectangle {
id: root
color: "black"
anchors.fill: parent
property string fullContentPath
property real volume: 1
property string fillMode: "Cover"
property string type
property string projectSourceFileAbsolute
property bool loops: true
function stop() {
player1.stop();
player2.stop();
videoOutput1.visible = false;
videoOutput2.visible = false;
root.enabled = false;
}
function play() {
root.enabled = true;
videoOutput2.visible = false;
videoOutput1.visible = true;
//if(wallpaper.configuration.DualPlayback){
player2.source = root.projectSourceFileAbsolute;
player2.play();
player2.pause();
//}
player1.play();
}
MediaPlayer {
id: player1
volume: root.volume
source: root.projectSourceFileAbsolute
onStopped: {
if (!root.enabled)
return;
videoOutput1.visible = false;
videoOutput2.visible = true;
if (player2.source !== root.projectSourceFileAbsolute) {
player2.source = root.projectSourceFileAbsolute;
}
player1.play();
player1.pause();
player2.play();
}
}
MediaPlayer {
id: player2
volume: root.volume
onStopped: {
if (!root.enabled)
return;
videoOutput2.visible = false;
videoOutput1.visible = true;
player2.play();
player2.pause();
player1.play();
}
}
VideoOutput {
id: videoOutput1
fillMode: VideoOutput.PreserveAspectCrop
anchors.fill: parent
source: player1
}
VideoOutput {
id: videoOutput2
fillMode: VideoOutput.PreserveAspectCrop
anchors.fill: parent
source: player2
}
}

View File

@ -1,41 +0,0 @@
import QtQuick 2.0
import QtQuick.Controls 2.12
import QtWebSockets 1.1
import QtWebEngine 1.8
import QtMultimedia 5.12
Rectangle {
id: container
anchors.fill: parent
Loader {
id: wp
anchors.fill: parent
source: "Wallpaper.qml"
property bool connected: false
Timer {
id: connectTimer
interval: 1000
running: true
repeat: true
onTriggered: {
if (!wp.connected) {
console.log("not connected");
wp.source = "";
wp.source = "Wallpaper.qml";
} else {
console.log("connected");
screensaver.visible = false;
connectTimer.stop();
}
}
}
}
Loader {
id: screensaver
anchors.fill: parent
source: "WaitingForScreenplay.qml"
}
}

View File

@ -1,28 +0,0 @@
import QtQuick 2.11
import QtQuick.Controls 2.4 as QQC
import QtQuick.Window 2.0
import QtGraphicalEffects 1.0
import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.plasma.wallpapers.image 2.0 as Wallpaper
import org.kde.kcm 1.1 as KCM
import org.kde.kirigami 2.4 as Kirigami
import org.kde.newstuff 1.1 as NewStuff
Column {
id: root
property alias cfg_MonitorIndex: monitorIndex.text
anchors.fill: parent
spacing: units.largeSpacing
Row {
anchors.horizontalCenter: parent.horizontalCenter
spacing: units.largeSpacing
QQC.TextField {
id: monitorIndex
text: "0"
}
}
}

View File

@ -1,37 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<style type="text/css">
video {
position: absolute;
width: 100%;
height: 100%;
object-fit: fill;
overflow: hidden;
}
body, html{
margin: 0px;
padding: 0px;
overflow: hidden;
background:black;
}
#errorMsg{
position: fixed;
top: 50%;
text-align: center;
left: 0;
width: 100%;
height: 100px;
z-index: 0;
color:white;
font-family: "Segoe UI, Roboto, Arial";
font-weight: lighter;
}
</style>
</head>
<body>
<video id="videoPlayer" oncontextmenu="return false;" width="100%" height="100%" loop autoplay>
<source id="videoSource" type="video/webm" oncontextmenu="return false;" width="100%" height="100%">
</video>
</body>
</html>

View File

@ -1,114 +0,0 @@
import QtQuick 2.0
import QtQuick.Controls 2.12
import QtWebSockets 1.1
import QtWebEngine 1.8
import QtMultimedia 5.12
import Qt.labs.settings 1.1
import org.kde.plasma.core 2.0 as PlasmaCore
Rectangle {
id: root
color: "orange"
property bool connected: false
Settings {
id: settings
}
Component.onCompleted: {
wallpaper.projectSourceFileAbsolute = settings.value("SP_projectSourceFileAbsolute", "NULL");
// if(root.projectSourceFileAbsolute === "NULL")
// return
wallpaper.type = settings.value("SP_type");
wallpaper.fillMode = settings.value("SP_fillMode");
//wallpaper.volume = settings.value("SP_volume")
wallpaper.play();
}
Wallpaper {
id: wallpaper
anchors.fill: parent
// visible: root.connected
onFullContentPathChanged: settings.setValue("SP_fullContentPath", fullContentPath)
onVolumeChanged: settings.setValue("SP_volume", volume)
onFillModeChanged: settings.setValue("SP_fillMode", fillMode)
onTypeChanged: settings.setValue("SP_type", type)
onProjectSourceFileAbsoluteChanged: settings.setValue("SP_projectSourceFileAbsolute", projectSourceFileAbsolute)
onLoopsChanged: settings.setValue("SP_loops", loops)
}
Timer {
id: reconnectTimer
interval: 1000
running: true
repeat: true
onTriggered: {
if (socket.status === WebSocket.Open)
return;
socket.active = false;
socket.active = true;
reconnectTimer.retryCounter += 1;
}
property int retryCounter: 0
}
WebSocket {
id: socket
url: "ws://127.0.0.1:16395"
onStatusChanged: {
if (socket.status === WebSocket.Open)
socket.sendTextMessage("Hello World from QML wallpaper");
}
onTextMessageReceived: message => {
var obj = JSON.parse(message);
root.connected = true;
txtCommand.text = obj.command;
if (obj.command === "replace") {
socket.sendTextMessage("replace");
wallpaper.type = obj.type;
wallpaper.fillMode = obj.fillMode;
wallpaper.volume = obj.volume;
wallpaper.projectSourceFileAbsolute = "file://" + obj.absolutePath + "/" + obj.file;
print("got: " + root.projectSourceFileAbsolute);
wallpaper.play();
return;
}
if (obj.command === "quit") {
wallpaper.stop();
}
}
}
// WaitingForScreenplay {
// anchors.fill: parent
// visible: !root.connected
// }
Column {
anchors {
horizontalCenter: parent.horizontalCenter
bottom: parent.bottom
margins: 60
}
Text {
id: txtCommand
color: "white"
}
Text {
color: "white"
text: "wallpaper.type: " + wallpaper.type
}
Text {
color: "white"
text: "projectSourceFileAbsolute " + wallpaper.projectSourceFileAbsolute
}
Text {
color: "white"
text: "reconnectTimer.retryCounter : " + reconnectTimer.retryCounter
}
Text {
color: "white"
text: "MonitorIndex: " + wallpaper.configuration.MonitorIndex
}
}
}

View File

@ -1,20 +0,0 @@
[Desktop Entry]
Encoding=UTF-8
Name=ScreenPlay
Keywords=ScreenPlay
Icon=preferences-desktop-wallpaper
Version=0.15.0-RC5
Type=Service
X-KDE-ServiceTypes=Plasma/Wallpaper
X-KDE-ParentApp=
X-KDE-PluginInfo-Name=ScreenPlay
X-KDE-PluginInfo-EnabledByDefault=true
X-KDE-PluginInfo-Version=3
X-KDE-PluginInfo-Website=https://gitlab.com/kelteseth/screenplay
X-Plasma-MainScript=ui/main.qml
MimeType=image/gif;image/png;image/svg+xml;image/svg+xml-compressed;video/x-mng;
X-Plasma-DropMimeTypes=image/gif,image/png,image/svg+xml,image/svg+xml-compressed,video/x-mng

View File

@ -16,6 +16,7 @@
Q_IMPORT_QML_PLUGIN(ScreenPlaySysInfoPlugin)
#elif defined(Q_OS_LINUX)
#include "src/linuxx11window.h"
#include "src/linuxwaylandwindow.h"
#elif defined(Q_OS_OSX)
#include "src/macwindow.h"
#endif
@ -35,13 +36,19 @@ int main(int argc, char* argv[])
#endif
QGuiApplication app(argc, argv);
std::unique_ptr<BaseWindow> window;
const auto platformName = QGuiApplication::platformName();
#if defined(Q_OS_WIN)
WinWindow window;
window = std::make_unique<WinWindow>();
#elif defined(Q_OS_LINUX)
LinuxX11Window window;
if(platformName == "xcb"){
window = std::make_unique<LinuxX11Window>();
} else if(platformName == "wayland"){
window = std::make_unique<LinuxWaylandWindow>();
}
#elif defined(Q_OS_OSX)
MacWindow window;
window = std::make_unique<MacWindow>();
#endif
// If we start with only one argument (app path)
@ -59,17 +66,17 @@ int main(int argc, char* argv[])
"/wallpaper_video_astronaut_vp9", // 4
"/wallpaper_video_nebula_h264" // 5
};
const int index = 5;
const int index = 1;
QString projectPath = exampleContentPath + contentFolder.at(index);
window.setActiveScreensList({ 0 });
window.setProjectPath(projectPath);
window.setAppID("test");
window.setVolume(1);
window.setFillMode("cover");
window.setType(ScreenPlay::InstalledType::InstalledType::VideoWallpaper);
window.setCheckWallpaperVisible(true);
window.setDebugMode(false);
window->setActiveScreensList({ 0 });
window->setProjectPath(projectPath);
window->setAppID("test");
window->setVolume(1);
window->setFillMode("cover");
window->setType(ScreenPlay::InstalledType::InstalledType::VideoWallpaper);
window->setCheckWallpaperVisible(true);
window->setDebugMode(false);
} else {
// 8 parameter + 1 OS working directory as the first default paramter
if (argumentList.length() != 9) {
@ -111,24 +118,24 @@ int main(int argc, char* argv[])
}
appID = appID.remove("appID=");
window.setActiveScreensList(activeScreensList.value());
window.setProjectPath(argumentList.at(2));
window.setAppID(appID);
window.setVolume(volume);
window.setFillMode(argumentList.at(5));
window.setType(installedType);
window.setCheckWallpaperVisible(checkWallpaperVisible);
window.setDebugMode(false);
window->setActiveScreensList(activeScreensList.value());
window->setProjectPath(argumentList.at(2));
window->setAppID(appID);
window->setVolume(volume);
window->setFillMode(argumentList.at(5));
window->setType(installedType);
window->setCheckWallpaperVisible(checkWallpaperVisible);
window->setDebugMode(false);
}
const auto setupStatus = window.setup();
const auto setupStatus = window->setup();
if (setupStatus != ScreenPlay::WallpaperExitCode::Ok) {
return static_cast<int>(setupStatus);
}
const auto startStatus = window.start();
const auto startStatus = window->start();
if (startStatus != ScreenPlay::WallpaperExitCode::Ok) {
return static_cast<int>(startStatus);
}
emit window.qmlStart();
emit window->qmlStart();
return app.exec();
}

View File

@ -27,7 +27,7 @@ Rectangle {
loader.source = "qrc:/qml/ScreenPlayWallpaper/qml/MultimediaView.qml";
}
}
if (Qt.platform.os === "windows") {
if (Qt.platform.os === "windows" || Qt.platform.os === "linux") {
loader.source = "qrc:/qml/ScreenPlayWallpaper/qml/MultimediaView.qml";
}
break;

View File

@ -0,0 +1,70 @@
// SPDX-License-Identifier: LicenseRef-EliasSteurerTachiom OR AGPL-3.0-only
#include "linuxwaylandwindow.h"
#include <QScreen>
#include <QGuiApplication>
#include <LayerShellQt/Window>
#include <LayerShellQt/Shell>
ScreenPlay::WallpaperExitCode LinuxWaylandWindow::start()
{
if (!debugMode()) {
connect(m_sdk.get(), &ScreenPlaySDK::sdkDisconnected, this, &LinuxWaylandWindow::destroyThis);
}
qmlRegisterSingletonInstance<LinuxWaylandWindow>("ScreenPlayWallpaper", 1, 0, "Wallpaper", this);
QDir workingDir(QGuiApplication::instance()->applicationDirPath());
m_window.engine()->addImportPath(workingDir.path() + "/qml");
m_window.setResizeMode(QQuickView::ResizeMode::SizeRootObjectToView);
m_window.setSource(QUrl("qrc:/qml/ScreenPlayWallpaper/qml/Wallpaper.qml"));
// Get the Wayland display
if (QGuiApplication::platformName() == "wayland") {
QPlatformNativeInterface *native = QGuiApplication::platformNativeInterface();
auto *layerShell = LayerShellQt::Window::get(&m_window);
layerShell->setLayer(LayerShellQt::Window::LayerBackground);
layerShell->setAnchors(static_cast<QFlags<LayerShellQt::Window::Anchor>>(
LayerShellQt::Window::Anchor::AnchorTop |
LayerShellQt::Window::Anchor::AnchorBottom |
LayerShellQt::Window::Anchor::AnchorLeft |
LayerShellQt::Window::Anchor::AnchorRight
));
}
m_window.show();
return ScreenPlay::WallpaperExitCode::Ok;
}
void LinuxWaylandWindow::setupWallpaperForOneScreen(int activeScreen)
{
}
void LinuxWaylandWindow::setupWallpaperForAllScreens()
{
}
void LinuxWaylandWindow::setupWallpaperForMultipleScreens(const QVector<int>& activeScreensList)
{
}
void LinuxWaylandWindow::setVisible(bool show)
{
m_window.setVisible(show);
}
void LinuxWaylandWindow::destroyThis()
{
QCoreApplication::quit();
}
void LinuxWaylandWindow::terminate()
{
QCoreApplication::quit();
}

View File

@ -0,0 +1,35 @@
// SPDX-License-Identifier: LicenseRef-EliasSteurerTachiom OR AGPL-3.0-only
#pragma once
#include <QDebug>
#include <QObject>
#include <QQmlContext>
#include <QQmlEngine>
#include <QQuickView>
#include <QScreen>
#include <QSettings>
#include <QString>
#include <QVector>
#include "basewindow.h"
class LinuxWaylandWindow : public BaseWindow {
Q_OBJECT
public:
ScreenPlay::WallpaperExitCode start() override;
signals:
public slots:
void setVisible(bool show) override;
void destroyThis() override;
void terminate() override;
private:
QQuickView m_window;
void setupWallpaperForOneScreen(int activeScreen);
void setupWallpaperForAllScreens();
void setupWallpaperForMultipleScreens(const QVector<int>& activeScreensList);
};

View File

@ -16,5 +16,19 @@ FetchContent_Populate(
# https://bugreports.qt.io/browse/QTCREATORBUG-27083
SOURCE_DIR ${THIRD_PARTY_PATH}/qml-plausible)
add_subdirectory(qml-plausible)
add_subdirectory(QArchive)
if(UNIX AND NOT APPLE)
FetchContent_Populate(
qt-layer-shell
GIT_REPOSITORY https://github.com/KDE/layer-shell-qt.git
GIT_TAG 721c0ae334554eb2396a2d4d3358f896b8c77412
# Workaround because: 1. QtCreator cannot handle QML_ELEMENT stuff when it is in bin folder
# https://bugreports.qt.io/browse/QTCREATORBUG-27083
SOURCE_DIR ${THIRD_PARTY_PATH}/qt-layer-shell)
add_subdirectory(qt-layer-shell)
endif()

View File

@ -44,16 +44,18 @@ class commands_list():
def download(aqt_path: Path, qt_platform: Path):
qt_packages = ""
if system() == "Windows":
os = "windows"
elif system() == "Darwin":
os = "mac"
elif system() == "Linux":
qt_packages = "qtwaylandcompositor "
os = "linux"
# python -m aqt list-qt windows desktop --modules 6.5.2 win64_msvc2019_64
qt_packages = "qt3d qtquick3d qtconnectivity qt5compat qtimageformats qtmultimedia qtshadertools qtwebchannel qtwebengine qtwebsockets qtwebview qtpositioning"
# Windows: python -m aqt list-qt windows desktop --modules 6.5.2 win64_msvc2019_64
# Linux: python3 -m aqt list-qt linux desktop --modules 6.5.2 gcc_64
qt_packages += "qt3d qtquick3d qtconnectivity qt5compat qtimageformats qtmultimedia qtshadertools qtwebchannel qtwebengine qtwebsockets qtwebview qtpositioning"
print(f"Downloading: {qt_packages} to {aqt_path}")
execute(f"{defines.PYTHON_EXECUTABLE} -m aqt install-qt -O {aqt_path} {os} desktop {defines.QT_VERSION} {qt_platform} -m {qt_packages}")