1
0
mirror of https://gitlab.com/kelteseth/ScreenPlay.git synced 2024-11-22 10:42:29 +01:00

Fix godot export by using qcoro

This commit is contained in:
Elias Steurer 2023-12-20 15:08:30 +01:00
parent 340562d3ca
commit b92f2298f3
9 changed files with 288 additions and 99 deletions

View File

@ -9,6 +9,7 @@ set(CMAKE_AUTOMOC ON)
include(GenerateCMakeVariableHeader)
set(SOURCES
# cmake-format: sort
src/app.cpp
src/create.cpp
@ -27,6 +28,7 @@ set(SOURCES
src/wizards.cpp)
set(HEADER
# cmake-format: sort
inc/public/ScreenPlay/app.h
inc/public/ScreenPlay/create.h
@ -47,6 +49,7 @@ set(HEADER
inc/public/ScreenPlay/wizards.h)
set(QML
# cmake-format: sort
main.qml
qml/Community/CommunityNavItem.qml
@ -101,6 +104,7 @@ set(QML
qml/Workshop/WorkshopView.qml)
set(TS_FILES
# cmake-format: sort
translations/ScreenPlay_.ts
translations/ScreenPlay_de_DE.ts
@ -117,6 +121,7 @@ set(TS_FILES
translations/ScreenPlay_zh_CN.ts)
set(RESOURCES
# cmake-format: sort
"legal/Font Awesome Free License.txt"
"legal/Qt LGPLv3.txt"
@ -263,15 +268,15 @@ endif()
find_package(
Qt6
COMPONENTS Core
Quick
QuickControls2
Gui
Widgets
WebSockets
Svg
Xml
LinguistTools
Test)
Quick
QuickControls2
Gui
Widgets
WebSockets
Svg
Xml
LinguistTools
Test)
add_library(ScreenPlayApp STATIC)
@ -306,32 +311,34 @@ qt_add_qml_module(
target_link_libraries(
ScreenPlayApp
PUBLIC ScreenPlaySDK
LibArchive::LibArchive
ScreenPlayUtil
ScreenPlayUtilplugin
QArchive
Plausibleplugin
Threads::Threads
Qt6::Quick
Qt6::Gui
Qt6::Widgets
Qt6::Core
Qt6::WebSockets
Qt6::Svg
Qt6::QuickControls2
Qt6::Xml)
LibArchive::LibArchive
ScreenPlayUtil
ScreenPlayUtilplugin
QArchive
Plausibleplugin
Threads::Threads
QCoro6::Qml
Qt6::Quick
Qt6::Gui
Qt6::Widgets
Qt6::Core
Qt6::WebSockets
Qt6::Svg
Qt6::QuickControls2
Qt6::Xml)
if(${SCREENPLAY_STEAM})
target_link_libraries(ScreenPlayApp PUBLIC ScreenPlayWorkshopplugin ScreenPlayWorkshop)
endif()
qt_add_executable(${PROJECT_NAME} main.cpp)
target_link_libraries(${PROJECT_NAME} PRIVATE ScreenPlayApp ScreenPlayAppplugin)
target_link_libraries(${PROJECT_NAME} PRIVATE ScreenPlayApp ScreenPlayAppplugin QCoro6::Qml)
if(${SCREENPLAY_TESTS})
add_executable(tst_ScreenPlay tests/tst_main.cpp)
target_link_libraries(tst_ScreenPlay PRIVATE ScreenPlayApp ScreenPlayAppplugin Qt6::Test)
generate_cmake_variable_header(tst_ScreenPlay)
if(${SCREENPLAY_STEAM})
target_link_libraries(tst_ScreenPlay PUBLIC ScreenPlayWorkshopplugin ScreenPlayWorkshop)
endif()
@ -342,8 +349,8 @@ if(${SCREENPLAY_TESTS})
endif()
if(WIN32
OR UNIX
AND NOT APPLE)
OR UNIX
AND NOT APPLE)
include(CopyRecursive)
set(FONTS_OUT_DIR ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/assets/fonts)
file(MAKE_DIRECTORY ${FONTS_OUT_DIR})
@ -366,6 +373,7 @@ if(WIN32)
# Copy ffmpeg. If the ffmpeg files are missing, start the install_dependencies_XXX for your system!
file(GLOB files "${CMAKE_CURRENT_SOURCE_DIR}/../ThirdParty/ffmpeg/*")
foreach(filename ${files})
configure_file(${filename} ${CMAKE_BINARY_DIR}/bin/ COPYONLY)
endforeach()
@ -375,11 +383,9 @@ if(WIN32)
configure_file(${VCPKG_BIN_PATH}/libssl-3-x64.dll ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/ COPYONLY)
configure_file(${VCPKG_BIN_PATH}/libcrypto-3-x64.dll ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/ COPYONLY)
endif()
if(APPLE)
# Set the path to the icon file
set(APP_ICON_MACOSX ${CMAKE_CURRENT_SOURCE_DIR}/assets/icons/ScreenPlay.icns)
@ -391,6 +397,7 @@ if(APPLE)
# Specify the name of the icon file for the bundle
set(MACOSX_BUNDLE_ICON_FILE ScreenPlay.icns) # Only the file name
# Fore some reason this only works with maually copy
configure_file(${APP_ICON_MACOSX} "${RESOURCES_DIR}/ScreenPlay.icns" COPYONLY)
@ -398,26 +405,26 @@ if(APPLE)
set_target_properties(
${PROJECT_NAME}
PROPERTIES OUTPUT_NAME ${PROJECT_NAME}
MACOSX_BUNDLE TRUE
MACOSX_RPATH TRUE
MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist
MACOSX_FRAMEWORK_IDENTIFIER app.screenplay
XCODE_ATTRIBUTE_LD_RUNPATH_SEARCH_PATHS "@loader_path/Libraries"
RESOURCE "${RESOURCE_FILES};${APP_ICON_MACOSX}" # Include the icon in the resources
XCODE_ATTRIBUTE_ENABLE_HARDENED_RUNTIME TRUE
XCODE_ATTRIBUTE_EXECUTABLE_NAME ${PROJECT_NAME})
MACOSX_BUNDLE TRUE
MACOSX_RPATH TRUE
MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist
MACOSX_FRAMEWORK_IDENTIFIER app.screenplay
XCODE_ATTRIBUTE_LD_RUNPATH_SEARCH_PATHS "@loader_path/Libraries"
RESOURCE "${RESOURCE_FILES};${APP_ICON_MACOSX}" # Include the icon in the resources
XCODE_ATTRIBUTE_ENABLE_HARDENED_RUNTIME TRUE
XCODE_ATTRIBUTE_EXECUTABLE_NAME ${PROJECT_NAME})
add_custom_command(
TARGET ${PROJECT_NAME}
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/../ThirdParty/ffmpeg/ffmpeg
${CMAKE_BINARY_DIR}/bin/ScreenPlay.app/Contents/MacOS/)
${CMAKE_BINARY_DIR}/bin/ScreenPlay.app/Contents/MacOS/)
add_custom_command(
TARGET ${PROJECT_NAME}
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/../ThirdParty/ffmpeg/ffprobe
${CMAKE_BINARY_DIR}/bin/ScreenPlay.app/Contents/MacOS/)
${CMAKE_BINARY_DIR}/bin/ScreenPlay.app/Contents/MacOS/)
# fonts
include(CopyRecursive)
@ -430,7 +437,6 @@ if(APPLE)
set(QM_OUT_DIR "${RESOURCES_DIR}/translations")
file(MAKE_DIRECTORY ${QM_OUT_DIR})
set_source_files_properties(${TS_FILES} PROPERTIES OUTPUT_LOCATION ${QM_OUT_DIR})
endif()
# Must be called here, because we need to change the OUTPUT_LOCATION for macos

View File

@ -58,7 +58,7 @@ public:
QString ffmpegOutput() const { return m_ffmpegOutput; }
signals:
void createWallpaperStateChanged(Import::State state);
void createWallpaperStateChanged(ScreenPlay::Import::State state);
void progressChanged(float progress);
void abortCreateWallpaper();
void workingDirChanged(QString workingDir);

View File

@ -11,9 +11,7 @@
#include <QString>
#include <QVector>
#include "ScreenPlay/projectsettingslistmodel.h"
#include "ScreenPlay/screenplaywallpaper.h"
#include "ScreenPlay/screenplaywidget.h"
#ifdef Q_OS_WIN
#include <qt_windows.h>

View File

@ -3,11 +3,13 @@
#include "ScreenPlay/CMakeVariables.h"
#include "ScreenPlay/app.h"
#include "ScreenPlayUtil/logginghandler.h"
#include "qcorotask.h"
#include "qml/qcoroqml.h"
#include "qml/qcoroqmltask.h"
#include <QCommandLineParser>
#include <QDebug>
#include <QGuiApplication>
#include <QStyleFactory>
#if defined(Q_OS_WIN)
#include <sentry.h>
#endif
@ -22,7 +24,7 @@ Q_IMPORT_QML_PLUGIN(PlausiblePlugin)
int main(int argc, char* argv[])
{
QCoro::Qml::registerTypes();
#if !defined(Q_OS_LINUX)
qputenv("QT_MEDIA_BACKEND", "ffmpeg");
#endif

View File

@ -2,6 +2,7 @@ import QtQuick
import Qt5Compat.GraphicalEffects
import QtQuick.Controls
import QtQuick.Layouts
import QtQuick.Dialogs
import QtQuick.Controls.Material
import QtQuick.Controls.Material.impl
import ScreenPlayApp
@ -18,71 +19,74 @@ Item {
function indexOfValue(model, value) {
for (var i = 0; i < model.length; i++) {
let ourValue = model[i].value;
let ourValue = model[i].value
if (value === ourValue)
return i;
return i
}
return -1;
return -1
}
// This is used for removing wallpaper. We need to clear
// the preview image/gif so we can release the file for deletion.
function clear() {
imagePreview.source = "";
animatedImagePreview.source = "";
txtHeadline.text = "";
root.state = "inactive";
imagePreview.source = ""
animatedImagePreview.source = ""
txtHeadline.text = ""
root.state = "inactive"
}
width: 400
state: "inactive"
property bool hasPreviewGif: false
onContentFolderNameChanged: {
const item = App.installedListModel.get(root.contentFolderName);
txtHeadline.text = item.m_title;
const previewGiFilePath = Qt.resolvedUrl(item.m_absoluteStoragePath + "/" + item.m_previewGIF);
const previewImageFilePath = Qt.resolvedUrl(item.m_absoluteStoragePath + "/" + item.m_preview);
root.hasPreviewGif = App.util.fileExists(previewGiFilePath);
const item = App.installedListModel.get(root.contentFolderName)
txtHeadline.text = item.m_title
const previewGiFilePath = Qt.resolvedUrl(
item.m_absoluteStoragePath + "/" + item.m_previewGIF)
const previewImageFilePath = Qt.resolvedUrl(
item.m_absoluteStoragePath + "/" + item.m_preview)
root.hasPreviewGif = App.util.fileExists(previewGiFilePath)
if (hasPreviewGif) {
animatedImagePreview.source = previewGiFilePath;
animatedImagePreview.playing = true;
animatedImagePreview.source = previewGiFilePath
animatedImagePreview.playing = true
} else {
imagePreview.source = previewImageFilePath;
imagePreview.source = previewImageFilePath
}
if (App.util.isWidget(root.type) || (monitorSelection.activeMonitors.length > 0)) {
btnLaunchContent.enabled = true;
return;
if (App.util.isWidget(root.type)
|| (monitorSelection.activeMonitors.length > 0)) {
btnLaunchContent.enabled = true
return
}
btnLaunchContent.enabled = false;
btnLaunchContent.enabled = false
}
Connections {
function onSetSidebarItem(folderName, type) {
// Toggle sidebar if clicked on the same content twice
if (root.contentFolderName === folderName && root.state !== "inactive") {
root.state = "inactive";
return;
if (root.contentFolderName === folderName
&& root.state !== "inactive") {
root.state = "inactive"
return
}
root.contentFolderName = folderName;
root.type = type;
root.contentFolderName = folderName
root.type = type
if (App.util.isWallpaper(root.type)) {
if (type === ContentTypes.InstalledType.VideoWallpaper)
root.state = "activeWallpaper";
root.state = "activeWallpaper"
else
root.state = "activeScene";
btnLaunchContent.text = qsTr("Set Wallpaper");
root.state = "activeScene"
btnLaunchContent.text = qsTr("Set Wallpaper")
} else {
root.state = "activeWidget";
btnLaunchContent.text = qsTr("Set Widget");
root.state = "activeWidget"
btnLaunchContent.text = qsTr("Set Widget")
}
}
target: App.util
}
MouseHoverBlocker {
}
MouseHoverBlocker {}
Rectangle {
anchors.fill: parent
@ -329,42 +333,80 @@ Item {
"text": qsTr("Scale-Down")
}]
Component.onCompleted: {
cbVideoFillMode.currentIndex = root.indexOfValue(cbVideoFillMode.model, App.settings.videoFillMode);
cbVideoFillMode.currentIndex = root.indexOfValue(
cbVideoFillMode.model,
App.settings.videoFillMode)
}
}
}
}
MessageDialog {
id: errorDialog
buttons: MessageDialog.Ok
}
Button {
id: btnLaunchContent
objectName: "btnLaunchContent"
enabled: App.util.isWidget(root.type) ? true : monitorSelection.isSelected
Material.background: Material.accent
Material.foreground: "white"
enabled: App.util.isWidget(
root.type) ? true : monitorSelection.isSelected
icon.source: "qrc:/qml/ScreenPlayApp/assets/icons/icon_plus.svg"
icon.color: "white"
font.pointSize: 12
onClicked: {
const item = App.installedListModel.get(root.contentFolderName);
const absoluteStoragePath = item.m_absoluteStoragePath;
const previewImage = item.m_preview;
const item = App.installedListModel.get(
root.contentFolderName)
const absoluteStoragePath = item.m_absoluteStoragePath
const previewImage = item.m_preview
if (App.util.isWallpaper(root.type)) {
let activeMonitors = monitorSelection.getActiveMonitors();
let activeMonitors = monitorSelection.getActiveMonitors(
)
// TODO Alert user to choose a monitor
if (activeMonitors.length === 0)
return;
return
// We only have sliderVolume if it is a VideoWallpaper
let volume = 0;
let volume = 0
if (type === ContentTypes.InstalledType.VideoWallpaper)
volume = Math.round(sliderVolume.slider.value * 100) / 100;
const screenFile = item.m_file;
let success = App.screenPlayManager.createWallpaper(root.type, cbVideoFillMode.currentValue, absoluteStoragePath, previewImage, screenFile, activeMonitors, volume, 1, {}, true);
volume = Math.round(
sliderVolume.slider.value * 100) / 100
if (type === ContentTypes.InstalledType.GodotWallpaper) {
App.util.exportGodotProject(
absoluteStoragePath,
App.globalVariables.godotEditorExecutablePath).then(
result => {
if(!result.success){
errorDialog.text = ("Error exporting Godot")
errorDialog.informativeText = result.messag
errorDialog.open()
return
}
const screenFile = item.m_file
let success = App.screenPlayManager.createWallpaper(
root.type,
cbVideoFillMode.currentValue,
absoluteStoragePath,
previewImage, screenFile,
activeMonitors, volume,
1, {}, true)
})
return
}
const screenFile = item.m_file
let success = App.screenPlayManager.createWallpaper(
root.type, cbVideoFillMode.currentValue,
absoluteStoragePath, previewImage, screenFile,
activeMonitors, volume, 1, {}, true)
}
if (App.util.isWidget(root.type))
App.screenPlayManager.createWidget(type, Qt.point(0, 0), absoluteStoragePath, previewImage, {}, true);
root.state = "inactive";
monitorSelection.reset();
App.screenPlayManager.createWidget(type,
Qt.point(0, 0),
absoluteStoragePath,
previewImage, {},
true)
root.state = "inactive"
monitorSelection.reset()
}
anchors {

View File

@ -6,6 +6,7 @@ set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOMOC ON)
find_package(fmt CONFIG REQUIRED)
# Needed on macos
find_package(Threads REQUIRED)
find_package(LibArchive REQUIRED)
@ -15,6 +16,7 @@ find_package(
REQUIRED)
set(QML
# cmake-format: sort
qml/CloseIcon.qml
qml/ColorImage.qml
@ -41,6 +43,7 @@ set(QML
qml/TextField.qml)
set(SOURCES
# cmake-format: sort
src/archive.cpp
src/contenttypes.cpp
@ -52,6 +55,7 @@ set(SOURCES
src/util.cpp)
set(HEADER
# cmake-format: sort
inc/public/ScreenPlayUtil/archive.h
inc/public/ScreenPlayUtil/contenttypes.h
@ -71,7 +75,7 @@ if(APPLE)
endif()
set(RESOURCES # cmake-format: sort
assets/icons/attach_file.svg assets/icons/description.svg assets/icons/folder.svg)
assets/icons/attach_file.svg assets/icons/description.svg assets/icons/folder.svg)
qt_add_library(
${PROJECT_NAME}
@ -108,12 +112,15 @@ target_include_directories(${PROJECT_NAME}plugin PUBLIC inc/public/ScreenPlayUti
target_link_libraries(
${PROJECT_NAME}
PUBLIC Qt6::Core
Qt6::Quick
Qt6::Gui
fmt::fmt-header-only
LibArchive::LibArchive
QArchive)
PUBLIC
Qt6::Core
Qt6::Quick
Qt6::Gui
QCoro6::Core
QCoro6::Qml
fmt::fmt-header-only
LibArchive::LibArchive
QArchive)
if(WIN32)
# Used for query windows monitor data

View File

@ -26,6 +26,9 @@
#include <optional>
#include "ScreenPlayUtil/contenttypes.h"
#include "qcorotask.h"
#include "qml/qcoroqml.h"
#include "qml/qcoroqmltask.h"
namespace ScreenPlay {
@ -46,6 +49,46 @@ T QStringToEnum(const QString& key, const T defaultValue)
return defaultValue;
}
class GodotExport : public QObject {
Q_OBJECT
QML_ELEMENT
QML_UNCREATABLE("")
Q_CLASSINFO("RegisterEnumClassesUnscoped", "false")
public:
enum class Result {
Failed,
Ok,
};
Q_ENUM(Result)
};
class Result {
Q_GADGET
Q_PROPERTY(bool success READ success WRITE setSuccess)
Q_PROPERTY(QVariant status READ status WRITE setStatus)
Q_PROPERTY(QString messag READ messag WRITE setMessag)
public:
explicit Result() { }
explicit Result(bool success, const QVariant& status = {}, const QString& messag = "")
{
m_success = success;
m_status = status;
m_messag = messag;
}
bool success() const { return m_success; }
void setSuccess(bool success) { m_success = success; }
QString messag() const { return m_messag; }
void setMessag(const QString& messag) { m_messag = messag; }
QVariant status() const { return m_status; }
void setStatus(const QVariant& status) { m_status = status; }
private:
bool m_success;
QString m_messag;
QVariant m_status;
};
class Util : public QObject {
Q_OBJECT
QML_ELEMENT
@ -78,6 +121,7 @@ public:
QStringList getAvailableFillModes() const;
// QML callable functions
Q_INVOKABLE QString toLocal(const QString& url) const;
Q_INVOKABLE QCoro::QmlTask exportGodotProject(const QString& absolutePath, const QString& godotEditorExecutablePath);
Q_INVOKABLE bool isWallpaper(const ScreenPlay::ContentTypes::InstalledType type) const;
Q_INVOKABLE bool isWidget(const ScreenPlay::ContentTypes::InstalledType type) const;

View File

@ -622,4 +622,80 @@ bool Util::copyPreviewThumbnail(QJsonObject& obj, const QString& previewThumbnai
return true;
}
QCoro::QmlTask Util::exportGodotProject(const QString& absolutePath, const QString& godotEditorExecutablePath)
{
return QCoro::QmlTask([this, absolutePath, godotEditorExecutablePath]() -> QCoro::Task<Result> {
QString projectPath = toLocal(absolutePath);
std::optional<QJsonObject> projectOpt = openJsonFileToObject(projectPath + "/project.json");
QJsonObject projectJson;
if (!projectOpt.has_value()) {
co_return Result { false };
}
projectJson = projectOpt.value();
if (!projectJson.contains("version"))
co_return Result { false };
const quint64 version = projectJson.value("version").toInt();
const QString packageFileName = QString("project-v%1.zip").arg(version);
QFileInfo godotPackageFile(projectPath + "/" + packageFileName);
// Skip reexport
if (godotPackageFile.exists())
co_return Result { true };
qInfo() << "No suitable version found for Godot package" << packageFileName << " at" << godotPackageFile.absoluteFilePath() << " exporting a new pck as zip.";
// Prepare the Godot export command
const QList<QString>
godotCmd
= { "--export-pack", "--headless", "Windows Desktop", packageFileName };
QProcess process;
process.setWorkingDirectory(projectPath);
process.setProgram(godotEditorExecutablePath);
process.setArguments(godotCmd);
using namespace QCoro;
auto coro_process = qCoro(process);
qInfo() << "Start" << process.program() << " " << process.arguments() << process.workingDirectory();
co_await coro_process.start();
co_await coro_process.waitForFinished();
// Capture the standard output and error
QString stdoutString = process.readAllStandardOutput();
QString stderrString = process.readAllStandardError();
// If you want to print the output to the console:
if (!stdoutString.isEmpty())
qDebug() << "Output:" << stdoutString;
if (!stderrString.isEmpty())
qDebug() << "Error:" << stderrString;
// Check for errors
if (process.exitStatus() != QProcess::NormalExit || process.exitCode() != 0) {
QString errorMessage = tr("Failed to export Godot project. Error: %1").arg(process.errorString());
qCritical() << errorMessage;
co_return Result { false, {}, errorMessage };
}
// Check if the project.zip file was created
QString zipPath = QDir(projectPath).filePath(packageFileName);
if (!QFile::exists(zipPath)) {
qCritical() << "Expected export file (" << packageFileName << ") was not created.";
co_return Result { false };
}
// Optional: Verify if the .zip file is valid
// (A complete verification would involve extracting the file and checking its contents,
// but for simplicity, we're just checking its size here)
QFileInfo zipInfo(zipPath);
if (zipInfo.size() <= 0) {
qCritical() << "The exported " << packageFileName << " file seems to be invalid.";
co_return Result { false };
}
qInfo() << "exportGodotProject END";
co_return Result { true };
}());
}
}
#include "moc_util.cpp"

View File

@ -4,6 +4,7 @@ FetchContent_Populate(
QArchive
GIT_REPOSITORY https://github.com/antony-jr/QArchive.git
GIT_TAG e587f30507c0e6d92f79a2dc1a6aa7ebb1f8e679
# 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}/QArchive)
@ -12,21 +13,34 @@ FetchContent_Populate(
qml-plausible
GIT_REPOSITORY https://gitlab.com/kelteseth/qml-plausible.git
GIT_TAG 322d8e17cab77b496f0d7fafb19f6dcda4193ed7
# 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}/qml-plausible)
FetchContent_Populate(
qcoro
GIT_REPOSITORY https://github.com/danvratil/qcoro.git
GIT_TAG 12c052e
# 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}/qqcoro)
add_subdirectory(qml-plausible)
add_subdirectory(QArchive)
add_subdirectory(qqcoro)
qcoro_enable_coroutines()
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()