1
0
mirror of https://gitlab.com/kelteseth/ScreenPlay.git synced 2024-11-25 20:22:39 +01:00

Change ScreenPlayWallpaperLib to win32 only for now

Format documents
Remove sysinfo from logging for now because
it is windows only
This commit is contained in:
Elias Steurer 2023-11-01 12:28:35 +01:00
parent e84e5d250e
commit 33c222da5d
28 changed files with 405 additions and 477 deletions

View File

@ -45,7 +45,6 @@ list(APPEND CMAKE_MODULE_PATH "${THIRD_PARTY_PATH}/ecm/find-modules")
list(APPEND CMAKE_MODULE_PATH "${THIRD_PARTY_PATH}/ecm/kde-modules") list(APPEND CMAKE_MODULE_PATH "${THIRD_PARTY_PATH}/ecm/kde-modules")
message(STATUS "[PROJECT] CMAKE_MODULE_PATH = ${CMAKE_MODULE_PATH}") message(STATUS "[PROJECT] CMAKE_MODULE_PATH = ${CMAKE_MODULE_PATH}")
option(OSX_BUNDLE "Enable distribution macOS bundle" OFF) option(OSX_BUNDLE "Enable distribution macOS bundle" OFF)
set(CMAKE_OSX_DEPLOYMENT_TARGET "13.0") set(CMAKE_OSX_DEPLOYMENT_TARGET "13.0")
@ -74,7 +73,7 @@ set(VCPKG_BIN_PATH "${VCPKG_INSTALLED_PATH}/bin")
option(SCREENPLAY_STEAM "For FOSS distribution so we do not bundle proprietary code." ON) option(SCREENPLAY_STEAM "For FOSS distribution so we do not bundle proprietary code." ON)
option(SCREENPLAY_DEPLOY "Marks this version as an official deploy version. This version uses different import paths and other settings." option(SCREENPLAY_DEPLOY "Marks this version as an official deploy version. This version uses different import paths and other settings."
OFF) OFF)
option(SCREENPLAY_TESTS "Enables UI tests." ON) option(SCREENPLAY_TESTS "Enables UI tests." ON)
option(SCREENPLAY_INSTALLER "Indicates whether an installer via the Qt Installer Framework is created." OFF) option(SCREENPLAY_INSTALLER "Indicates whether an installer via the Qt Installer Framework is created." OFF)
option(SCREENPLAY_GODOT_SUPPORT "Compiles ScreenPlayGodotWallpaper." ON) option(SCREENPLAY_GODOT_SUPPORT "Compiles ScreenPlayGodotWallpaper." ON)
@ -103,14 +102,12 @@ else()
set(DATE_ARG "") set(DATE_ARG "")
endif() endif()
if(UNIX AND NOT APPLE) if(UNIX AND NOT APPLE)
# Fixes QWebEngine linker errors on Ubuntu 22.04 # Fixes QWebEngine linker errors on Ubuntu 22.04
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fuse-ld=gold") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fuse-ld=gold")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fuse-ld=gold") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fuse-ld=gold")
endif() endif()
execute_process( execute_process(
COMMAND ${DATE_COMMAND} ${DATE_ARG} COMMAND ${DATE_COMMAND} ${DATE_ARG}
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
@ -138,10 +135,10 @@ add_subdirectory(ThirdParty)
set(ECM_DIR "${THIRD_PARTY_PATH}/ecm") set(ECM_DIR "${THIRD_PARTY_PATH}/ecm")
add_subdirectory(CMake) add_subdirectory(CMake)
if(UNIX AND NOT APPLE) if(UNIX AND NOT APPLE)
# Needs to be append, because we include ecm as third party on linux # 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 "${CMAKE_CURRENT_SOURCE_DIR}/CMake")
list(APPEND CMAKE_MODULE_PATH "${ECM_DIR}") list(APPEND CMAKE_MODULE_PATH "${ECM_DIR}")
list(APPEND CMAKE_MODULE_PATH "${ECM_DIR}/cmake") list(APPEND CMAKE_MODULE_PATH "${ECM_DIR}/cmake")
else() else()
endif() endif()

View File

@ -101,7 +101,6 @@ public slots:
void setMainWindowEngine(QQmlApplicationEngine* mainWindowEngine); void setMainWindowEngine(QQmlApplicationEngine* mainWindowEngine);
void setWizards(Wizards* wizards); void setWizards(Wizards* wizards);
private: private:
QNetworkAccessManager m_networkAccessManager; QNetworkAccessManager m_networkAccessManager;
std::unique_ptr<QQmlApplicationEngine> m_mainWindowEngine; std::unique_ptr<QQmlApplicationEngine> m_mainWindowEngine;

View File

@ -40,7 +40,6 @@ public:
int activeWidgetsCounter() const { return m_activeWidgetsCounter; } int activeWidgetsCounter() const { return m_activeWidgetsCounter; }
bool isAnotherScreenPlayInstanceRunning() { return m_isAnotherScreenPlayInstanceRunning; } bool isAnotherScreenPlayInstanceRunning() { return m_isAnotherScreenPlayInstanceRunning; }
signals: signals:
void activeWallpaperCounterChanged(int activeWallpaperCounter); void activeWallpaperCounterChanged(int activeWallpaperCounter);
void activeWidgetsCounterChanged(int activeWidgetsCounter); void activeWidgetsCounterChanged(int activeWidgetsCounter);

View File

@ -1,11 +1,11 @@
// SPDX-License-Identifier: LicenseRef-EliasSteurerTachiom OR AGPL-3.0-only // SPDX-License-Identifier: LicenseRef-EliasSteurerTachiom OR AGPL-3.0-only
#include "ScreenPlay/app.h" #include "ScreenPlay/app.h"
#include "ScreenPlayUtil/logginghandler.h"
#include <QCommandLineParser> #include <QCommandLineParser>
#include <QDebug> #include <QDebug>
#include <QGuiApplication> #include <QGuiApplication>
#include <QStyleFactory> #include <QStyleFactory>
#include "ScreenPlayUtil/logginghandler.h"
#if defined(Q_OS_WIN) #if defined(Q_OS_WIN)
#include <sentry.h> #include <sentry.h>

View File

@ -483,8 +483,8 @@ Item {
description: qsTr("If your ScreenPlay missbehaves this is a good way to look for answers. This shows all logs and warning during runtime.") description: qsTr("If your ScreenPlay missbehaves this is a good way to look for answers. This shows all logs and warning during runtime.")
buttonText: qsTr("Show Logs") buttonText: qsTr("Show Logs")
onButtonPressed: { onButtonPressed: {
const logsPath = StandardPaths.writableLocation(StandardPaths.GenericDataLocation) + "/ScreenPlay/Logs" const logsPath = StandardPaths.writableLocation(StandardPaths.GenericDataLocation) + "/ScreenPlay/Logs";
App.util.openFolderInExplorer(logsPath) App.util.openFolderInExplorer(logsPath);
} }
} }

View File

@ -255,7 +255,6 @@ bool Util::fileExists(const QString& filePath) const
return file.isFile(); return file.isFile();
} }
/*! /*!
\brief Takes ownership of \a obj and \a name. Tries to save into a text file \brief Takes ownership of \a obj and \a name. Tries to save into a text file
with of name. with of name.

View File

@ -55,11 +55,11 @@ set(HEADER
inc/public/ScreenPlayUtil/HelpersCommon.h inc/public/ScreenPlayUtil/HelpersCommon.h
inc/public/ScreenPlayUtil/httpfileserver.h inc/public/ScreenPlayUtil/httpfileserver.h
inc/public/ScreenPlayUtil/ListPropertyHelper.h inc/public/ScreenPlayUtil/ListPropertyHelper.h
inc/public/ScreenPlayUtil/logginghandler.h
inc/public/ScreenPlayUtil/projectfile.h inc/public/ScreenPlayUtil/projectfile.h
inc/public/ScreenPlayUtil/PropertyHelpers.h inc/public/ScreenPlayUtil/PropertyHelpers.h
inc/public/ScreenPlayUtil/PtrPropertyHelpers.h inc/public/ScreenPlayUtil/PtrPropertyHelpers.h
inc/public/ScreenPlayUtil/SingletonHelper.h inc/public/ScreenPlayUtil/SingletonHelper.h
inc/public/ScreenPlayUtil/logginghandler.h
inc/public/ScreenPlayUtil/util.h) inc/public/ScreenPlayUtil/util.h)
if(APPLE) if(APPLE)
@ -98,7 +98,10 @@ target_include_directories(
${PROJECT_NAME} ${PROJECT_NAME}
PUBLIC inc/public/ PUBLIC inc/public/
PRIVATE src/) PRIVATE src/)
target_link_libraries(${PROJECT_NAME} PRIVATE Qt6::Core Qt6::Quick PUBLIC fmt::fmt-header-only ScreenPlaySysInfo) target_link_libraries(
${PROJECT_NAME}
PRIVATE Qt6::Core Qt6::Quick
PUBLIC fmt::fmt-header-only)
if(WIN32) if(WIN32)
# Used for query windows monitor data # Used for query windows monitor data

View File

@ -3,13 +3,13 @@
#pragma once #pragma once
#include "ScreenPlayUtil/contenttypes.h" #include "ScreenPlayUtil/contenttypes.h"
#include <QtGlobal>
#include <QJsonArray> #include <QJsonArray>
#include <QJsonObject> #include <QJsonObject>
#include <QMetaEnum> #include <QMetaEnum>
#include <QMetaType> #include <QMetaType>
#include <QString> #include <QString>
#include <QVersionNumber> #include <QVersionNumber>
#include <QtGlobal>
#include <optional> #include <optional>
namespace ScreenPlayUtil { namespace ScreenPlayUtil {

View File

@ -1,5 +1,4 @@
#include "ScreenPlayUtil/logginghandler.h" #include "ScreenPlayUtil/logginghandler.h"
#include "sysinfo.h"
#include <QDateTime> #include <QDateTime>
#include <QDebug> #include <QDebug>
#include <QDir> #include <QDir>
@ -9,10 +8,15 @@
#include <QUrl> #include <QUrl>
#include <fmt/color.h> #include <fmt/color.h>
#ifdef Q_OS_WINDOWS
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include <Windows.h>
#endif
/*! /*!
\class ScreenPlayUtil::LoggingHandler \class ScreenPlayUtil::LoggingHandler
\inmodule core
\brief The LoggingHandler class writes logs to the console and a log file. \brief The LoggingHandler class writes logs to the console and a log file.
*/ */
@ -48,7 +52,6 @@ void LoggingHandler::start()
{ {
Q_ASSERT(!m_logFileName.isEmpty()); Q_ASSERT(!m_logFileName.isEmpty());
// Use hardcoded path for now because QStandardpaths gives us: 'C:/ProgramData/K3000'
QDir directory; QDir directory;
QString cacheDir = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation); QString cacheDir = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation);
directory = QDir(cacheDir + "/ScreenPlay/Logs"); directory = QDir(cacheDir + "/ScreenPlay/Logs");
@ -78,29 +81,6 @@ void LoggingHandler::start()
return; return;
} }
SysInfo sysInfo;
QTextStream stream(&logFile());
stream << "Start ScreenPlay logging " << QDateTime::currentDateTime().toString("dd.MM.yyyy-hh:mm:ss.zzz") << "\n";
stream << "version: 1.0\n";
stream << "buildAbi: " << QSysInfo::buildAbi() << "\n";
stream << "buildCpuArchitecture: " << QSysInfo::buildCpuArchitecture() << "\n";
stream << "currentCpuArchitecture: " << QSysInfo::currentCpuArchitecture() << "\n";
stream << "kernelType: " << QSysInfo::kernelType() << "\n";
stream << "kernelVersion: " << QSysInfo::kernelVersion() << "\n";
stream << "machineHostName: " << QSysInfo::machineHostName() << "\n";
stream << "machineUniqueId: " << QSysInfo::machineUniqueId() << "\n";
stream << "prettyProductName: " << QSysInfo::prettyProductName() << "\n";
stream << "productType: " << QSysInfo::productType() << "\n";
stream << "productVersion: " << QSysInfo::productVersion() << "\n";
stream << "GPU Name: " << sysInfo.gpu()->name() << "\n";
stream << "GPU Vendor: " << sysInfo.gpu()->vendor() << "\n";
stream << "GPU ramSize: " << QString::number(sysInfo.gpu()->ramSize()) << "\n";
stream << "GPU cacheSize: " << QString::number(sysInfo.gpu()->cacheSize()) << "\n";
stream << "GPU maxFrequency: " << QString::number(sysInfo.gpu()->maxFrequency()) << "\n";
stream << QString("Uptime: %1 days %2 hours %3 minutes %4 seconds").arg(sysInfo.uptime()->days()).arg(sysInfo.uptime()->hours()).arg(sysInfo.uptime()->minutes()).arg(sysInfo.uptime()->seconds()) << "\n";
const auto now = QLocale().toString(QDateTime::currentDateTime(), QLocale::FormatType::ShortFormat); const auto now = QLocale().toString(QDateTime::currentDateTime(), QLocale::FormatType::ShortFormat);
const auto message = QString { "[%1] Start logging\n" }.arg(now); const auto message = QString { "[%1] Start logging\n" }.arg(now);
logFile().write(message.toStdString().c_str()); logFile().write(message.toStdString().c_str());

View File

@ -7,18 +7,17 @@ set(CMAKE_AUTOMOC ON)
find_package( find_package(
Qt6 Qt6
COMPONENTS COMPONENTS Core
Core Quick
Quick Gui
Gui Widgets
Widgets WebSockets
WebSockets Svg
Svg Multimedia
Multimedia WebEngineCore
WebEngineCore WebEngineQuick
WebEngineQuick WebChannel
WebChannel Positioning)
Positioning)
if(WIN32) if(WIN32)
set(SOURCES src/windowsdesktopproperties.cpp src/winwindow.cpp) set(SOURCES src/windowsdesktopproperties.cpp src/winwindow.cpp)
@ -55,25 +54,18 @@ set(LIB_HEADER)
if(WIN32) if(WIN32)
set(LIB_SOURCES src/windowsintegration.cpp) set(LIB_SOURCES src/windowsintegration.cpp)
set(LIB_HEADER src/windowsintegration.h) set(LIB_HEADER src/windowsintegration.h)
elseif(APPLE) add_library(ScreenPlayWallpaperLib STATIC ${LIB_SOURCES} ${LIB_HEADER})
set(LIB_SOURCES src/macintegration.cpp) target_include_directories(ScreenPlayWallpaperLib PUBLIC src)
set(LIB_HEADER src/macintegration.h)
elseif(UNIX)
#set(LIB_SOURCES src/waylandintegration.cpp)
#set(LIB_HEADER src/waylandintegration.h)
endif()
add_library(ScreenPlayWallpaperLib STATIC ${LIB_SOURCES} ${LIB_HEADER})
target_include_directories(ScreenPlayWallpaperLib PUBLIC src)
if(WIN32)
# Used for query windows monitor data # Used for query windows monitor data
target_link_libraries(ScreenPlayWallpaperLib PUBLIC shcore.lib) target_link_libraries(ScreenPlayWallpaperLib PUBLIC shcore.lib)
endif() endif()
add_executable(
add_executable(${PROJECT_NAME} ${SOURCES} ${HEADER} ${PROJECT_NAME}
src/windowsintegration.h src/windowsintegration.cpp) ${SOURCES}
${HEADER}
src/windowsintegration.h
src/windowsintegration.cpp)
qt_add_qml_module( qt_add_qml_module(
${PROJECT_NAME} ${PROJECT_NAME}
@ -92,34 +84,34 @@ qt_add_qml_module(
target_link_libraries( target_link_libraries(
${PROJECT_NAME} ${PROJECT_NAME}
PRIVATE PRIVATE ScreenPlaySDK
ScreenPlaySDK ScreenPlayUtil
ScreenPlayWallpaperLib ScreenPlayWeatherplugin
ScreenPlayUtil Qt6::Quick
ScreenPlayWeatherplugin Qt6::Gui
Qt6::Quick Qt6::Widgets
Qt6::Gui Qt6::Core
Qt6::Widgets Qt6::WebSockets
Qt6::Core Qt6::Svg
Qt6::WebSockets Qt6::Multimedia
Qt6::Svg Qt6::WebEngineCore
Qt6::Multimedia Qt6::WebEngineQuick)
Qt6::WebEngineCore
Qt6::WebEngineQuick)
if(WIN32) if(WIN32)
target_link_libraries(${PROJECT_NAME} PRIVATE ScreenPlaySysInfoplugin) target_link_libraries(${PROJECT_NAME} PRIVATE ScreenPlaySysInfoplugin ScreenPlayWallpaperLib)
elseif(UNIX AND NOT APPLE) elseif(UNIX AND NOT APPLE)
target_link_libraries(${PROJECT_NAME} PRIVATE X11) target_link_libraries(${PROJECT_NAME} PRIVATE X11)
endif() endif()
if(UNIX AND NOT APPLE) if(UNIX AND NOT APPLE)
find_package(ECM CONFIG REQUIRED NO_MODULE) find_package(
ECM
CONFIG
REQUIRED
NO_MODULE)
set(LayerShellQt "${CMAKE_CURRENT_SOURCE_DIR}/../ThirdParty/layer-shell-qt/") set(LayerShellQt "${CMAKE_CURRENT_SOURCE_DIR}/../ThirdParty/layer-shell-qt/")
find_package(LayerShellQt REQUIRED) find_package(LayerShellQt REQUIRED)
target_link_libraries( target_link_libraries(${PROJECT_NAME} PRIVATE LayerShellQtInterface)
${PROJECT_NAME}
PRIVATE LayerShellQtInterface)
endif() endif()
if(APPLE) if(APPLE)
@ -130,7 +122,7 @@ if(APPLE)
TARGET ${PROJECT_NAME} TARGET ${PROJECT_NAME}
POST_BUILD POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/index.html COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/index.html
${CMAKE_BINARY_DIR}/bin/ScreenPlay.app/Contents/MacOS/) ${CMAKE_BINARY_DIR}/bin/ScreenPlay.app/Contents/MacOS/)
set_target_properties(${PROJECT_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin/ScreenPlay.app/Contents/MacOS/") set_target_properties(${PROJECT_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin/ScreenPlay.app/Contents/MacOS/")
endif() endif()
endif() endif()

View File

@ -20,37 +20,31 @@ set(CMAKE_INTERPROCEDURAL_OPTIMIZATION_RELEASE ON)
# Output compile commands to compile_commands.json (for debugging CMake issues) # Output compile commands to compile_commands.json (for debugging CMake issues)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON) set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
# Build universal lib on macOS # Build universal lib on macOS Note that CMAKE_OSX_ARCHITECTURES must be set before project().
# Note that CMAKE_OSX_ARCHITECTURES must be set before project().
if(APPLE) if(APPLE)
set(CMAKE_OSX_ARCHITECTURES "x86_64;arm64" CACHE STRING "") set(CMAKE_OSX_ARCHITECTURES
"x86_64;arm64"
CACHE STRING "")
endif() endif()
# Main project information # Main project information
project(ScreenPlayGodotWallpaper project(ScreenPlayGodotWallpaper LANGUAGES CXX)
LANGUAGES
CXX
)
# Create our library # Create our library
add_library(${PROJECT_NAME} SHARED) add_library(${PROJECT_NAME} SHARED)
target_compile_features(${PROJECT_NAME} target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_17)
PRIVATE
cxx_std_17
)
# LIB_ARCH is the architecture being built. It is set to the build system's architecture. # LIB_ARCH is the architecture being built. It is set to the build system's architecture. For macOS, we build a universal library (both
# For macOS, we build a universal library (both arm64 and x86_64). # arm64 and x86_64).
set(LIB_ARCH ${CMAKE_SYSTEM_PROCESSOR}) set(LIB_ARCH ${CMAKE_SYSTEM_PROCESSOR})
if(APPLE) if(APPLE)
set(LIB_ARCH "universal") set(LIB_ARCH "universal")
endif() endif()
# LIB_DIR is where the actual library ends up. This is used in both the build directory and the # LIB_DIR is where the actual library ends up. This is used in both the build directory and the install directory and needs to be consistent
# install directory and needs to be consistent with the paths in the gdextension file. # with the paths in the gdextension file. e.g. linux.release.x86_64 = "lib/Linux-x86_64/libGDExtensionTemplate.so"
# e.g. linux.release.x86_64 = "lib/Linux-x86_64/libGDExtensionTemplate.so"
set(LIB_DIR "lib/${CMAKE_SYSTEM_NAME}-${LIB_ARCH}") set(LIB_DIR "lib/${CMAKE_SYSTEM_NAME}-${LIB_ARCH}")
message(STATUS "Building ${PROJECT_NAME} for ${LIB_ARCH} on ${CMAKE_SYSTEM_NAME}") message(STATUS "Building ${PROJECT_NAME} for ${LIB_ARCH} on ${CMAKE_SYSTEM_NAME}")
@ -60,19 +54,15 @@ set(BUILD_OUTPUT_DIR "${PROJECT_BINARY_DIR}/${PROJECT_NAME}/")
set(OUT_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../ScreenPlayGodot/${PROJECT_NAME}/) set(OUT_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../ScreenPlayGodot/${PROJECT_NAME}/)
# Compile directly into our Godot project # Compile directly into our Godot project
set_target_properties(${PROJECT_NAME} set_target_properties(
PROPERTIES ${PROJECT_NAME}
CXX_VISIBILITY_PRESET hidden PROPERTIES CXX_VISIBILITY_PRESET hidden
VISIBILITY_INLINES_HIDDEN true VISIBILITY_INLINES_HIDDEN true
RUNTIME_OUTPUT_DIRECTORY "${OUT_PATH}/${LIB_DIR}" RUNTIME_OUTPUT_DIRECTORY "${OUT_PATH}/${LIB_DIR}"
LIBRARY_OUTPUT_DIRECTORY "${OUT_PATH}/${LIB_DIR}" LIBRARY_OUTPUT_DIRECTORY "${OUT_PATH}/${LIB_DIR}")
)
if(NOT DEFINED CMAKE_DEBUG_POSTFIX) if(NOT DEFINED CMAKE_DEBUG_POSTFIX)
set_target_properties(${PROJECT_NAME} set_target_properties(${PROJECT_NAME} PROPERTIES DEBUG_POSTFIX "-d")
PROPERTIES
DEBUG_POSTFIX "-d"
)
endif() endif()
# Warnings # Warnings
@ -88,34 +78,27 @@ set(INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/${PROJECT_NAME}/")
add_subdirectory(templates) add_subdirectory(templates)
# ccache # ccache Turns on ccache if found
# Turns on ccache if found
include(ccache) include(ccache)
# Formatting # Formatting Adds a custom target to format all the code at once
# Adds a custom target to format all the code at once
include(ClangFormat) include(ClangFormat)
# godot-cpp # godot-cpp From here: https://github.com/godotengine/godot-cpp
# From here: https://github.com/godotengine/godot-cpp
if(NOT EXISTS "${CMAKE_CURRENT_LIST_DIR}/extern/godot-cpp/Makefile") if(NOT EXISTS "${CMAKE_CURRENT_LIST_DIR}/extern/godot-cpp/Makefile")
message( message(
FATAL_ERROR FATAL_ERROR
"[${PROJECT_NAME}] The godot-cpp submodule was not downloaded. Please update submodules: git submodule update --init --recursive." "[${PROJECT_NAME}] The godot-cpp submodule was not downloaded. Please update submodules: git submodule update --init --recursive."
) )
endif() endif()
set(GODOT_CPP_SYSTEM_HEADERS ON CACHE BOOL "" FORCE) set(GODOT_CPP_SYSTEM_HEADERS
ON
CACHE BOOL "" FORCE)
add_subdirectory(extern/godot-cpp) add_subdirectory(extern/godot-cpp)
set_target_properties(godot-cpp set_target_properties(godot-cpp PROPERTIES CXX_VISIBILITY_PRESET hidden # visibility needs to be the same as the main library
PROPERTIES
CXX_VISIBILITY_PRESET hidden # visibility needs to be the same as the main library
) )
target_link_libraries(${PROJECT_NAME} target_link_libraries(${PROJECT_NAME} PRIVATE godot-cpp ScreenPlayWallpaperLib)
PRIVATE
godot-cpp
ScreenPlayWallpaperLib
)

View File

@ -1,20 +1,16 @@
# SPDX-License-Identifier: Unlicense # SPDX-License-Identifier: Unlicense
target_sources(${PROJECT_NAME} target_sources(
PRIVATE ${PROJECT_NAME}
ScreenPlayGodotWallpaper.h PRIVATE ScreenPlayGodotWallpaper.h
ScreenPlayGodotWallpaper.cpp ScreenPlayGodotWallpaper.cpp
WindowsPipe.h WindowsPipe.h
WindowsPipe.cpp WindowsPipe.cpp
RegisterExtension.cpp RegisterExtension.cpp)
)
find_package(Catch2 CONFIG REQUIRED) find_package(Catch2 CONFIG REQUIRED)
target_include_directories(${PROJECT_NAME} target_include_directories(${PROJECT_NAME} PRIVATE "src")
PRIVATE
"src"
)
# Test app. Start WindowsPipeTestServer.py! # Test app. Start WindowsPipeTestServer.py!
add_executable(WindowsPipeTest WindowsPipeTest.cpp WindowsPipe.h WindowsPipe.cpp) add_executable(WindowsPipeTest WindowsPipe.cpp WindowsPipe.h WindowsPipeTest.cpp)
target_link_libraries(WindowsPipeTest PRIVATE Catch2::Catch2 Catch2::Catch2WithMain) target_link_libraries(WindowsPipeTest PRIVATE Catch2::Catch2 Catch2::Catch2WithMain)
target_include_directories(WindowsPipeTest PRIVATE "src") target_include_directories(WindowsPipeTest PRIVATE "src")

View File

@ -82,10 +82,10 @@ bool ScreenPlayGodotWallpaper::init(int activeScreen)
ShowWindow(m_hook->windowHandle, SW_HIDE); ShowWindow(m_hook->windowHandle, SW_HIDE);
WindowsIntegration windowsIntegration; WindowsIntegration windowsIntegration;
auto updateWindowSize = [this, &displayServer](const int width, const int height){ auto updateWindowSize = [this, &displayServer](const int width, const int height) {
displayServer->window_set_size(godot::Vector2((real_t)width, (real_t)height)); displayServer->window_set_size(godot::Vector2((real_t)width, (real_t)height));
}; };
std::optional<Monitor> monitor = windowsIntegration.setupWallpaperForOneScreen(activeScreen,m_hook->windowHandle,m_hook->windowHandleWorker,updateWindowSize); std::optional<Monitor> monitor = windowsIntegration.setupWallpaperForOneScreen(activeScreen, m_hook->windowHandle, m_hook->windowHandleWorker, updateWindowSize);
const std::string windowTitle = "ScreenPlayWallpaperGodot"; const std::string windowTitle = "ScreenPlayWallpaperGodot";
SetWindowText(hwnd, windowTitle.c_str()); SetWindowText(hwnd, windowTitle.c_str());

View File

@ -2,6 +2,10 @@
#pragma once #pragma once
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include "godot_cpp/classes/control.hpp" #include "godot_cpp/classes/control.hpp"
#include "godot_cpp/classes/global_constants.hpp" #include "godot_cpp/classes/global_constants.hpp"
#include "godot_cpp/classes/timer.hpp" #include "godot_cpp/classes/timer.hpp"
@ -14,8 +18,8 @@
#include <vector> #include <vector>
#include "ScreenPlayGodotWallpaper.h" #include "ScreenPlayGodotWallpaper.h"
#include "windowsintegration.h"
#include "WindowsPipe.h" #include "WindowsPipe.h"
#include "windowsintegration.h"
class ScreenPlayGodotWallpaper : public godot::Node { class ScreenPlayGodotWallpaper : public godot::Node {
GDCLASS(ScreenPlayGodotWallpaper, Node) GDCLASS(ScreenPlayGodotWallpaper, Node)
@ -54,7 +58,6 @@ private:
void hideFromTaskbar(HWND hwnd); void hideFromTaskbar(HWND hwnd);
private: private:
OVERLAPPED overlappedRead = {}; OVERLAPPED overlappedRead = {};
OVERLAPPED overlappedWrite = {}; OVERLAPPED overlappedWrite = {};

View File

@ -1,6 +1,7 @@
#include "WindowsPipe.h" #include "WindowsPipe.h"
bool WindowsPipe::connectToPipe() { bool WindowsPipe::connectToPipe()
{
if (m_pipeName.empty()) { if (m_pipeName.empty()) {
std::cerr << "Pipe name not set." << std::endl; std::cerr << "Pipe name not set." << std::endl;
return false; return false;
@ -25,7 +26,8 @@ bool WindowsPipe::connectToPipe() {
return true; return true;
} }
bool WindowsPipe::readFromPipe(std::string& outMessage) { bool WindowsPipe::readFromPipe(std::string& outMessage)
{
char buffer[128]; char buffer[128];
DWORD bytesRead; DWORD bytesRead;
@ -52,8 +54,8 @@ bool WindowsPipe::readFromPipe(std::string& outMessage) {
return true; return true;
} }
bool WindowsPipe::writeToPipe(const std::string& message)
bool WindowsPipe::writeToPipe(const std::string& message) { {
DWORD bytesWritten; DWORD bytesWritten;
if (!WriteFile(m_hPipe, message.c_str(), static_cast<DWORD>(message.size()), &bytesWritten, &m_overlapped)) { if (!WriteFile(m_hPipe, message.c_str(), static_cast<DWORD>(message.size()), &bytesWritten, &m_overlapped)) {

View File

@ -21,7 +21,7 @@ TEST_CASE("Test WindowsPipe with Python echo server", "[WindowsPipe]")
std::string response; std::string response;
REQUIRE(client.readFromPipe(response)); REQUIRE(client.readFromPipe(response));
REQUIRE(response == "pong;"); REQUIRE(response == "pong;");
std::cout << response <<"ok\n"; std::cout << response << "ok\n";
} }
} }
} }

View File

@ -1,18 +1,17 @@
# SPDX-License-Identifier: Unlicense # SPDX-License-Identifier: Unlicense
add_custom_target(templates add_custom_target(templates SOURCES template.debug.gdextension.in template.release.gdextension.in)
SOURCES
template.debug.gdextension.in
template.release.gdextension.in
)
add_dependencies(${PROJECT_NAME} templates) add_dependencies(${PROJECT_NAME} templates)
# We shouldn't be relying on CMAKE_BUILD_TYPE (see https://github.com/asmaloney/GDExtensionTemplate/issues/25) # We shouldn't be relying on CMAKE_BUILD_TYPE (see https://github.com/asmaloney/GDExtensionTemplate/issues/25) But until we fix it here and
# But until we fix it here and in godot-cpp, ensure it's one we expect. # in godot-cpp, ensure it's one we expect.
set(ALLOWED_BUILDS "Debug;Release;debug;release") set(ALLOWED_BUILDS "Debug;Release;debug;release")
if(NOT "${CMAKE_BUILD_TYPE}" IN_LIST ALLOWED_BUILDS) if(NOT
"${CMAKE_BUILD_TYPE}"
IN_LIST
ALLOWED_BUILDS)
message(FATAL_ERROR "CMAKE_BUILD_TYPE must be set to Debug or Release") message(FATAL_ERROR "CMAKE_BUILD_TYPE must be set to Debug or Release")
endif() endif()
@ -28,7 +27,7 @@ endif()
# Generate our project's .gdextension file from the template # Generate our project's .gdextension file from the template
set(OUT_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../../ScreenPlayGodot/${PROJECT_NAME}/) set(OUT_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../../ScreenPlayGodot/${PROJECT_NAME}/)
set(GD_EXTENSION_FILE ${PROJECT_NAME}.gdextension) set(GD_EXTENSION_FILE ${PROJECT_NAME}.gdextension)
#configure_file(${GD_EXTENSION_FILE_INPUT} ${OUT_PATH}/${GD_EXTENSION_FILE}) # configure_file(${GD_EXTENSION_FILE_INPUT} ${OUT_PATH}/${GD_EXTENSION_FILE})
unset(ALLOWED_BUILDS) unset(ALLOWED_BUILDS)
unset(BUILD_TYPE) unset(BUILD_TYPE)

View File

@ -9,15 +9,15 @@
#include "ScreenPlayWallpaper/CMakeVariables.h" #include "ScreenPlayWallpaper/CMakeVariables.h"
#include "ScreenPlayUtil/exitcodes.h" #include "ScreenPlayUtil/exitcodes.h"
#include "ScreenPlayUtil/util.h"
#include "ScreenPlayUtil/logginghandler.h" #include "ScreenPlayUtil/logginghandler.h"
#include "ScreenPlayUtil/util.h"
#if defined(Q_OS_WIN) #if defined(Q_OS_WIN)
#include "src/winwindow.h" #include "src/winwindow.h"
Q_IMPORT_QML_PLUGIN(ScreenPlaySysInfoPlugin) Q_IMPORT_QML_PLUGIN(ScreenPlaySysInfoPlugin)
#elif defined(Q_OS_LINUX) #elif defined(Q_OS_LINUX)
#include "src/linuxx11window.h"
#include "src/linuxwaylandwindow.h" #include "src/linuxwaylandwindow.h"
#include "src/linuxx11window.h"
#elif defined(Q_OS_OSX) #elif defined(Q_OS_OSX)
#include "src/macwindow.h" #include "src/macwindow.h"
#endif #endif
@ -44,9 +44,9 @@ int main(int argc, char* argv[])
#if defined(Q_OS_WIN) #if defined(Q_OS_WIN)
window = std::make_unique<WinWindow>(); window = std::make_unique<WinWindow>();
#elif defined(Q_OS_LINUX) #elif defined(Q_OS_LINUX)
if(platformName == "xcb"){ if (platformName == "xcb") {
window = std::make_unique<LinuxX11Window>(); window = std::make_unique<LinuxX11Window>();
} else if(platformName == "wayland"){ } else if (platformName == "wayland") {
window = std::make_unique<LinuxWaylandWindow>(); window = std::make_unique<LinuxWaylandWindow>();
} }
#elif defined(Q_OS_OSX) #elif defined(Q_OS_OSX)

View File

@ -35,7 +35,6 @@ BaseWindow::BaseWindow()
"VideoCodec", "VideoCodec",
"Error: only enums"); "Error: only enums");
setOSVersion(QSysInfo::productVersion()); setOSVersion(QSysInfo::productVersion());
} }

View File

@ -1,10 +1,10 @@
// SPDX-License-Identifier: LicenseRef-EliasSteurerTachiom OR AGPL-3.0-only // SPDX-License-Identifier: LicenseRef-EliasSteurerTachiom OR AGPL-3.0-only
#include "linuxwaylandwindow.h" #include "linuxwaylandwindow.h"
#include <QScreen>
#include <QGuiApplication> #include <QGuiApplication>
#include <QScreen>
#include <LayerShellQt/Window>
#include <LayerShellQt/Shell> #include <LayerShellQt/Shell>
#include <LayerShellQt/Window>
ScreenPlay::WallpaperExitCode LinuxWaylandWindow::start() ScreenPlay::WallpaperExitCode LinuxWaylandWindow::start()
{ {
@ -22,20 +22,12 @@ ScreenPlay::WallpaperExitCode LinuxWaylandWindow::start()
// Get the Wayland display // Get the Wayland display
if (QGuiApplication::platformName() == "wayland") { if (QGuiApplication::platformName() == "wayland") {
QPlatformNativeInterface *native = QGuiApplication::platformNativeInterface(); 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
));
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(); m_window.show();

View File

@ -1,6 +1,4 @@
#include "windowsintegration.h" #include "windowsintegration.h"
bool WindowsIntegration::searchWorkerWindowToParentTo() bool WindowsIntegration::searchWorkerWindowToParentTo()
{ {
@ -29,20 +27,20 @@ float WindowsIntegration::getScaling(const int monitorIndex) const
ZeroMemory(&displayDevice, sizeof(displayDevice)); ZeroMemory(&displayDevice, sizeof(displayDevice));
displayDevice.cb = sizeof(displayDevice); displayDevice.cb = sizeof(displayDevice);
// Enumerate through monitors until we find the one we're looking for // Enumerate through monitors until we find the one we're looking for
for (int i = 0; EnumDisplayDevices(NULL, i, &displayDevice, 0); i++) { for (int i = 0; EnumDisplayDevices(NULL, i, &displayDevice, 0); i++) {
if (i == monitorIndex) { if (i == monitorIndex) {
DEVMODE devMode; DEVMODE devMode;
ZeroMemory(&devMode, sizeof(devMode)); ZeroMemory(&devMode, sizeof(devMode));
devMode.dmSize = sizeof(devMode); devMode.dmSize = sizeof(devMode);
// Get settings for selected monitor // Get settings for selected monitor
if (!EnumDisplaySettings(displayDevice.DeviceName, ENUM_CURRENT_SETTINGS, &devMode)) { if (!EnumDisplaySettings(displayDevice.DeviceName, ENUM_CURRENT_SETTINGS, &devMode)) {
// Unable to get monitor settings // Unable to get monitor settings
return 1.0f; return 1.0f;
} }
// Get DPI for selected monitor // Get DPI for selected monitor
HMONITOR hMonitor = MonitorFromPoint({ devMode.dmPosition.x, devMode.dmPosition.y }, MONITOR_DEFAULTTONEAREST); HMONITOR hMonitor = MonitorFromPoint({ devMode.dmPosition.x, devMode.dmPosition.y }, MONITOR_DEFAULTTONEAREST);
UINT dpiX = 0, dpiY = 0; UINT dpiX = 0, dpiY = 0;
if (SUCCEEDED(GetDpiForMonitor(hMonitor, MDT_EFFECTIVE_DPI, &dpiX, &dpiY))) { if (SUCCEEDED(GetDpiForMonitor(hMonitor, MDT_EFFECTIVE_DPI, &dpiX, &dpiY))) {
@ -91,15 +89,244 @@ BOOL SearchForWorkerWindow(HWND hwnd, LPARAM lparam)
return TRUE; return TRUE;
} }
std::vector<Monitor> WindowsIntegration::GetAllMonitors() { std::vector<Monitor> WindowsIntegration::GetAllMonitors()
{
std::vector<Monitor> monitors; std::vector<Monitor> monitors;
// Use the static MonitorEnumProc callback for EnumDisplayMonitors // Use the static MonitorEnumProc callback for EnumDisplayMonitors
EnumDisplayMonitors(NULL, NULL, MonitorEnumProc, reinterpret_cast<LPARAM>(&monitors)); EnumDisplayMonitors(NULL, NULL, MonitorEnumProc, reinterpret_cast<LPARAM>(&monitors));
return monitors; return monitors;
} }
int WindowsIntegration::GetMonitorIndex(HMONITOR hMonitor)
{
sEnumInfo info;
info.hMonitor = hMonitor;
if (EnumDisplayMonitors(NULL, NULL, GetMonitorByHandle, (LPARAM)&info))
return -1;
return info.iIndex;
}
/*!
\brief This method is called via a fixed interval to detect if a window completely
covers a monitor. If then sets visualPaused for QML to pause the content.
*/
bool WindowsIntegration::checkForFullScreenWindow(HWND windowHandle)
{
HWND hFoundWnd = nullptr;
EnumWindows(&FindTheDesiredWnd, reinterpret_cast<LPARAM>(&hFoundWnd));
// True if one window has WS_MAXIMIZE
if (hFoundWnd != nullptr) {
DWORD dwFlags = 0;
HMONITOR monitor = MonitorFromWindow(hFoundWnd, dwFlags);
HMONITOR wallpaper = MonitorFromWindow(windowHandle, dwFlags);
int monitorIndex = GetMonitorIndex(monitor);
int wallpaperIndex = GetMonitorIndex(wallpaper);
// qDebug() << monitorIndex << wallpaperIndex;
// If the window that has WS_MAXIMIZE is at the same monitor as this wallpaper
return monitorIndex == wallpaperIndex;
} else {
return false;
}
}
/*
* Adjusting a Window's Position and Size for Different Monitor DPI Scale Factors:
* * Windows allows users to set different DPI (dots per inch) scale factors for each monitor. This DPI scaling can lead to
* discrepancies in the positioning and size of windows, especially if we want to place a window on a monitor with a different
* scale factor than the one it was originally on.
* * In our scenario, we want to move and resize a window (`windowHwnd`) to fit perfectly within a target monitor. However,
* both the window and the target monitor can have different DPI scale factors, so we need to account for these when calculating
* the window's new position and size.
* * Steps:
* * 1. Retrieve the DPI scale factor for the window:
* - This gives us the current scale factor of the window based on its original monitor.
* * 2. Retrieve the DPI scale factor for the target monitor:
* - This gives us the scale factor of the monitor where we want to place the window.
* * 3. Calculate the window's new position:
* - The new position should be relative to the `WorkerW` window's coordinates.
* - Adjust the position based on the ratio of the window's DPI scale factor to the target monitor's DPI scale factor.
* This ensures that the window is positioned correctly on the monitor regardless of any differences in scale factors.
* * 4. Calculate the window's new size:
* - Adjust the size of the window based on the ratio of the window's DPI scale factor to the target monitor's DPI scale factor.
* This ensures that the window fits perfectly within the monitor, taking into account any differences in scale factors.
* * By following this approach, we can accurately position and resize the window on any monitor, regardless of differences in DPI
* scale factors.
*/
std::optional<Monitor> WindowsIntegration::setupWallpaperForOneScreen(const int activeScreen, HWND windowHwnd, HWND parentWindowHwnd, std::function<void(int, int)> updateWindowSize)
{
std::vector<Monitor> monitors = GetAllMonitors();
for (const auto& monitor : monitors) {
monitor.print();
if (monitor.index != activeScreen)
continue;
SetWindowPos(windowHwnd, HWND_TOP,
monitor.position.left, monitor.position.top,
monitor.size.cx, monitor.size.cy,
SWP_NOZORDER | SWP_NOACTIVATE);
// Must be called here to fix window positions!
updateWindowSize(monitor.size.cx, monitor.size.cy);
RECT oldRect;
GetWindowRect(windowHwnd, &oldRect);
std::cout << "Old Window Position: (" << oldRect.left << ", " << oldRect.top << ")" << std::endl;
float windowDpiScaleFactor = static_cast<float>(GetDpiForWindow(windowHwnd)) / 96.0f;
float targetMonitorDpiScaleFactor = monitor.scaleFactor;
std::cout << "Window DPI Scale Factor: " << windowDpiScaleFactor << std::endl;
std::cout << "Target Monitor DPI Scale Factor: " << targetMonitorDpiScaleFactor << std::endl;
SetParent(windowHwnd, parentWindowHwnd);
RECT parentRect;
GetWindowRect(parentWindowHwnd, &parentRect);
std::cout << "WorkerW Window Position: (" << parentRect.left << ", " << parentRect.top << ")" << std::endl;
int newX = static_cast<int>((oldRect.left - parentRect.left) * (windowDpiScaleFactor / targetMonitorDpiScaleFactor));
int newY = static_cast<int>((oldRect.top - parentRect.top) * (windowDpiScaleFactor / targetMonitorDpiScaleFactor));
std::cout << "Calculated New Position: (" << newX << ", " << newY << ")" << std::endl;
int newWidth = static_cast<int>(monitor.size.cx * (windowDpiScaleFactor / targetMonitorDpiScaleFactor));
int newHeight = static_cast<int>(monitor.size.cy * (windowDpiScaleFactor / targetMonitorDpiScaleFactor));
std::cout << "Calculated New Size: (" << newWidth << "x" << newHeight << ")" << std::endl;
SetWindowPos(windowHwnd, NULL, newX, newY, newWidth, newHeight, SWP_NOZORDER | SWP_NOACTIVATE);
return { monitor };
}
return std::nullopt;
}
/**
* Spans the window across multiple monitors.
* * This function takes a vector of monitor indices and adjusts the window's
* size and position to span across the specified monitors. It determines the
* window's new size by finding the bounding rectangle that covers all selected
* monitors. The window's new position is set to the top-left corner of this
* bounding rectangle.
* * Note: This function assumes that all monitors have the same DPI scaling. If
* they don't, the window may not fit perfectly across the monitors.
* * @param activeScreens A vector containing the indices of monitors across
* which the window should span.
* * Usage:
* setupWallpaperForMultipleScreens({0, 1}); // Spans the window across monitors 0 and 1.
* * Internals:
* 1. For each monitor in `activeScreens`, determine its bounding rectangle.
* 2. Compute the window's new width as `rightmost - leftmost` and its new
* height as `bottommost - topmost`.
* 3. Adjust the window's position and size to fit this bounding rectangle.
*/
WindowsIntegration::SpanResult WindowsIntegration::setupWallpaperForMultipleScreens(const std::vector<int>& activeScreens, HWND windowHwnd, HWND parentWindowHwnd)
{
std::vector<Monitor> monitors = GetAllMonitors();
int leftmost = INT_MAX;
int topmost = INT_MAX;
int rightmost = INT_MIN;
int bottommost = INT_MIN;
for (const auto& monitorIndex : activeScreens) {
if (monitorIndex < monitors.size()) {
const Monitor& monitor = monitors[monitorIndex];
leftmost = (std::min)(leftmost, static_cast<int>(monitor.position.left));
topmost = (std::min)(topmost, static_cast<int>(monitor.position.top));
rightmost = (std::max)(rightmost, static_cast<int>(monitor.position.right));
bottommost = (std::max)(bottommost, static_cast<int>(monitor.position.bottom));
}
}
int newWidth = rightmost - leftmost;
int newHeight = bottommost - topmost;
RECT oldRect;
GetWindowRect(windowHwnd, &oldRect);
float windowDpiScaleFactor = static_cast<float>(GetDpiForWindow(windowHwnd)) / 96.0f;
SetParent(windowHwnd, parentWindowHwnd);
RECT parentRect;
GetWindowRect(parentWindowHwnd, &parentRect);
int newX = static_cast<int>((leftmost - parentRect.left) * windowDpiScaleFactor);
int newY = static_cast<int>((topmost - parentRect.top) * windowDpiScaleFactor);
SetWindowPos(windowHwnd, NULL, newX, newY, newWidth, newHeight, SWP_NOZORDER | SWP_NOACTIVATE);
SpanResult result;
result.width = rightmost - leftmost;
result.height = bottommost - topmost;
result.success = true;
return result;
}
/**
* Sets up the wallpaper to span across all connected screens.
* * This function retrieves information about all connected monitors, including their positions, dimensions, and scale factors.
* It then calculates the combined dimensions needed to span the window across all these monitors, taking into account
* the scale factors. The function also handles reparenting the window to the WorkerW window, ensuring it remains below
* other desktop icons. The calculated position and dimensions are adjusted to account for any potential scaling differences
* between the window and the combined monitor setup.
* * @note This function assumes that the window's DPI scale factor is based on a default of 96 DPI. Adjustments are made
* based on this assumption.
* * @note The function currently multiplies the scale factors of all monitors to get an overall scale factor. This may need
* adjustments based on specific application needs.
* * @return SpanResult A structure containing the combined width and height of the monitors, and a success flag indicating
* whether the operation was successful.
* * @retval SpanResult::width The combined width of all monitors after scaling.
* @retval SpanResult::height The combined height of all monitors after scaling.
* @retval SpanResult::success A boolean flag indicating the success of the operation. Currently, it always returns `true`
* assuming all operations are successful. This can be adjusted based on error checks as needed.
*/
WindowsIntegration::SpanResult WindowsIntegration::setupWallpaperForAllScreens(HWND windowHwnd, HWND parentWindowHwnd)
{
std::vector<Monitor> monitors = GetAllMonitors();
int leftmost = INT_MAX;
int topmost = INT_MAX;
int rightmost = INT_MIN;
int bottommost = INT_MIN;
float overallScaleFactor = 1.0f; // assuming default is no scaling
// Calculate the combined dimensions of all monitors
for (const auto& monitor : monitors) {
leftmost = (std::min)(leftmost, static_cast<int>(monitor.position.left));
topmost = (std::min)(topmost, static_cast<int>(monitor.position.top));
rightmost = (std::max)(rightmost, static_cast<int>(monitor.position.right));
bottommost = (std::max)(bottommost, static_cast<int>(monitor.position.bottom));
overallScaleFactor *= monitor.scaleFactor; // Adjust as per your scaling needs
}
int scaledWidth = static_cast<int>((rightmost - leftmost) * overallScaleFactor);
int scaledHeight = static_cast<int>((bottommost - topmost) * overallScaleFactor);
// Set the position and size of the window to span all monitors
SetWindowPos(windowHwnd, HWND_TOP, leftmost, topmost, scaledWidth, scaledHeight, SWP_NOZORDER | SWP_NOACTIVATE);
// Reparenting and scaling logic
RECT oldRect;
GetWindowRect(windowHwnd, &oldRect);
float windowDpiScaleFactor = static_cast<float>(GetDpiForWindow(windowHwnd)) / 96.0f;
SetParent(windowHwnd, parentWindowHwnd);
RECT parentRect;
GetWindowRect(parentWindowHwnd, &parentRect);
int newX = static_cast<int>((oldRect.left - parentRect.left) * (windowDpiScaleFactor / overallScaleFactor));
int newY = static_cast<int>((oldRect.top - parentRect.top) * (windowDpiScaleFactor / overallScaleFactor));
SetWindowPos(windowHwnd, NULL, newX, newY, scaledWidth, scaledHeight, SWP_NOZORDER | SWP_NOACTIVATE);
// Return the combined span of all monitors
SpanResult result;
result.width = scaledWidth;
result.height = scaledHeight;
result.success = true; // Assuming the operations are successful; adjust as needed
return result;
}
BOOL GetMonitorByHandle(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) BOOL GetMonitorByHandle(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData)
{ {
@ -120,10 +347,11 @@ BOOL FindTheDesiredWnd(HWND hWnd, LPARAM lParam)
return true; // keep enumerating return true; // keep enumerating
} }
BOOL MonitorEnumProc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) { BOOL MonitorEnumProc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData)
{
std::vector<Monitor>* pMonitors = reinterpret_cast<std::vector<Monitor>*>(dwData); std::vector<Monitor>* pMonitors = reinterpret_cast<std::vector<Monitor>*>(dwData);
MONITORINFOEX info; MONITORINFOEX info;
info.cbSize = sizeof(info); info.cbSize = sizeof(info);
GetMonitorInfo(hMonitor, &info); GetMonitorInfo(hMonitor, &info);

View File

@ -16,13 +16,14 @@
#include <ShellScalingApi.h> #include <ShellScalingApi.h>
struct Monitor { struct Monitor {
HMONITOR monitorID; // Handle to the monitor HMONITOR monitorID; // Handle to the monitor
int index; // Index of the monitor int index; // Index of the monitor
RECT position; // Monitor's position and size RECT position; // Monitor's position and size
SIZE size; // Monitor's width and height SIZE size; // Monitor's width and height
float scaleFactor; // Scale factor (DPI scaling as a factor, e.g., 1.5 for 150% scaling) float scaleFactor; // Scale factor (DPI scaling as a factor, e.g., 1.5 for 150% scaling)
void print() const { void print() const
{
std::cout << "Monitor Info:" << std::endl; std::cout << "Monitor Info:" << std::endl;
std::cout << "Monitor ID: " << monitorID << std::endl; std::cout << "Monitor ID: " << monitorID << std::endl;
std::cout << "Index: " << index << std::endl; std::cout << "Index: " << index << std::endl;
@ -41,14 +42,12 @@ BOOL WINAPI SearchForWorkerWindow(HWND hwnd, LPARAM lparam);
struct WinMonitorStats { struct WinMonitorStats {
WinMonitorStats() WinMonitorStats()
{ {
EnumDisplayMonitors(NULL, NULL, MonitorEnum, (LPARAM)this); EnumDisplayMonitors(NULL, NULL, MonitorEnum, (LPARAM)this);
} }
static BOOL CALLBACK MonitorEnum(HMONITOR hMon, HDC hdc, LPRECT lprcMonitor, LPARAM pData)
static BOOL CALLBACK MonitorEnum(HMONITOR hMon, HDC hdc, LPRECT lprcMonitor, LPARAM pData)
{ {
WinMonitorStats* pThis = reinterpret_cast<WinMonitorStats*>(pData); WinMonitorStats* pThis = reinterpret_cast<WinMonitorStats*>(pData);
auto scaleFactor = DEVICE_SCALE_FACTOR::DEVICE_SCALE_FACTOR_INVALID; auto scaleFactor = DEVICE_SCALE_FACTOR::DEVICE_SCALE_FACTOR_INVALID;
@ -66,7 +65,7 @@ struct WinMonitorStats {
return TRUE; return TRUE;
} }
std::vector<int> iMonitors; std::vector<size_t> iMonitors;
std::vector<HMONITOR> hMonitors; std::vector<HMONITOR> hMonitors;
std::vector<HDC> hdcMonitors; std::vector<HDC> hdcMonitors;
std::vector<RECT> rcMonitors; std::vector<RECT> rcMonitors;
@ -84,262 +83,24 @@ struct sEnumInfo {
HMONITOR hMonitor; HMONITOR hMonitor;
}; };
struct WindowsIntegration {
class WindowsIntegration {
public:
bool searchWorkerWindowToParentTo();
float getScaling(const int monitorIndex) const;
bool hasWindowScaling() const;
HWND windowHandle {}; HWND windowHandle {};
HWND windowHandleWorker {}; HWND windowHandleWorker {};
Point zeroPoint;
std::vector<Monitor> GetAllMonitors();
int GetMonitorIndex(HMONITOR hMonitor)
{
sEnumInfo info;
info.hMonitor = hMonitor;
if (EnumDisplayMonitors(NULL, NULL, GetMonitorByHandle, (LPARAM)&info))
return -1;
return info.iIndex;
}
/*!
\brief This method is called via a fixed interval to detect if a window completely
covers a monitor. If then sets visualPaused for QML to pause the content.
*/
bool checkForFullScreenWindow(HWND windowHandle)
{
HWND hFoundWnd = nullptr;
EnumWindows(&FindTheDesiredWnd, reinterpret_cast<LPARAM>(&hFoundWnd));
// True if one window has WS_MAXIMIZE
if (hFoundWnd != nullptr) {
DWORD dwFlags = 0;
HMONITOR monitor = MonitorFromWindow(hFoundWnd, dwFlags);
HMONITOR wallpaper = MonitorFromWindow(windowHandle, dwFlags);
int monitorIndex = GetMonitorIndex(monitor);
int wallpaperIndex = GetMonitorIndex(wallpaper);
// qDebug() << monitorIndex << wallpaperIndex;
// If the window that has WS_MAXIMIZE is at the same monitor as this wallpaper
return monitorIndex == wallpaperIndex;
} else {
return false;
}
}
// Define the result structure
struct SpanResult { struct SpanResult {
int width = 0; int width = 0;
int height = 0; int height = 0;
bool success = false; bool success = false;
}; };
/* bool searchWorkerWindowToParentTo();
* Adjusting a Window's Position and Size for Different Monitor DPI Scale Factors: float getScaling(const int monitorIndex) const;
* * Windows allows users to set different DPI (dots per inch) scale factors for each monitor. This DPI scaling can lead to bool hasWindowScaling() const;
* discrepancies in the positioning and size of windows, especially if we want to place a window on a monitor with a different std::vector<Monitor> GetAllMonitors();
* scale factor than the one it was originally on. int GetMonitorIndex(HMONITOR hMonitor);
* * In our scenario, we want to move and resize a window (`windowHwnd`) to fit perfectly within a target monitor. However, bool checkForFullScreenWindow(HWND windowHandle);
* both the window and the target monitor can have different DPI scale factors, so we need to account for these when calculating std::optional<Monitor> setupWallpaperForOneScreen(const int activeScreen, HWND windowHwnd, HWND parentWindowHwnd, std::function<void(int, int)> updateWindowSize);
* the window's new position and size. SpanResult setupWallpaperForMultipleScreens(const std::vector<int>& activeScreens, HWND windowHwnd, HWND parentWindowHwnd);
* * Steps: SpanResult setupWallpaperForAllScreens(HWND windowHwnd, HWND parentWindowHwnd);
* * 1. Retrieve the DPI scale factor for the window:
* - This gives us the current scale factor of the window based on its original monitor.
* * 2. Retrieve the DPI scale factor for the target monitor:
* - This gives us the scale factor of the monitor where we want to place the window.
* * 3. Calculate the window's new position:
* - The new position should be relative to the `WorkerW` window's coordinates.
* - Adjust the position based on the ratio of the window's DPI scale factor to the target monitor's DPI scale factor.
* This ensures that the window is positioned correctly on the monitor regardless of any differences in scale factors.
* * 4. Calculate the window's new size:
* - Adjust the size of the window based on the ratio of the window's DPI scale factor to the target monitor's DPI scale factor.
* This ensures that the window fits perfectly within the monitor, taking into account any differences in scale factors.
* * By following this approach, we can accurately position and resize the window on any monitor, regardless of differences in DPI
* scale factors.
*/
std::optional<Monitor> setupWallpaperForOneScreen(const int activeScreen, HWND windowHwnd, HWND parentWindowHwnd, std::function<void(int,int)>updateWindowSize)
{
std::vector<Monitor> monitors = GetAllMonitors();
for (const auto& monitor : monitors) {
monitor.print();
if (monitor.index != activeScreen)
continue;
SetWindowPos(windowHwnd, HWND_TOP,
monitor.position.left, monitor.position.top,
monitor.size.cx, monitor.size.cy,
SWP_NOZORDER | SWP_NOACTIVATE);
// Must be called here to fix window positions!
updateWindowSize(monitor.size.cx, monitor.size.cy);
RECT oldRect;
GetWindowRect(windowHwnd, &oldRect);
std::cout << "Old Window Position: (" << oldRect.left << ", " << oldRect.top << ")" << std::endl;
float windowDpiScaleFactor = static_cast<float>(GetDpiForWindow(windowHwnd)) / 96.0f;
float targetMonitorDpiScaleFactor = monitor.scaleFactor;
std::cout << "Window DPI Scale Factor: " << windowDpiScaleFactor << std::endl;
std::cout << "Target Monitor DPI Scale Factor: " << targetMonitorDpiScaleFactor << std::endl;
SetParent(windowHwnd, parentWindowHwnd);
RECT parentRect;
GetWindowRect(parentWindowHwnd, &parentRect);
std::cout << "WorkerW Window Position: (" << parentRect.left << ", " << parentRect.top << ")" << std::endl;
int newX = static_cast<int>((oldRect.left - parentRect.left) * (windowDpiScaleFactor / targetMonitorDpiScaleFactor));
int newY = static_cast<int>((oldRect.top - parentRect.top) * (windowDpiScaleFactor / targetMonitorDpiScaleFactor));
std::cout << "Calculated New Position: (" << newX << ", " << newY << ")" << std::endl;
int newWidth = static_cast<int>(monitor.size.cx * (windowDpiScaleFactor / targetMonitorDpiScaleFactor));
int newHeight = static_cast<int>(monitor.size.cy * (windowDpiScaleFactor / targetMonitorDpiScaleFactor));
std::cout << "Calculated New Size: (" << newWidth << "x" << newHeight << ")" << std::endl;
SetWindowPos(windowHwnd, NULL, newX, newY, newWidth, newHeight, SWP_NOZORDER | SWP_NOACTIVATE);
return {monitor};
}
return std::nullopt;
}
/**
* Spans the window across multiple monitors.
*
* This function takes a vector of monitor indices and adjusts the window's
* size and position to span across the specified monitors. It determines the
* window's new size by finding the bounding rectangle that covers all selected
* monitors. The window's new position is set to the top-left corner of this
* bounding rectangle.
*
* Note: This function assumes that all monitors have the same DPI scaling. If
* they don't, the window may not fit perfectly across the monitors.
*
* @param activeScreens A vector containing the indices of monitors across
* which the window should span.
*
* Usage:
* setupWallpaperForMultipleScreens({0, 1}); // Spans the window across monitors 0 and 1.
*
* Internals:
* 1. For each monitor in `activeScreens`, determine its bounding rectangle.
* 2. Compute the window's new width as `rightmost - leftmost` and its new
* height as `bottommost - topmost`.
* 3. Adjust the window's position and size to fit this bounding rectangle.
*/
SpanResult setupWallpaperForMultipleScreens(const std::vector<int>& activeScreens, HWND windowHwnd, HWND parentWindowHwnd)
{
std::vector<Monitor> monitors = GetAllMonitors();
int leftmost = INT_MAX;
int topmost = INT_MAX;
int rightmost = INT_MIN;
int bottommost = INT_MIN;
for (const auto& monitorIndex : activeScreens) {
if (monitorIndex < monitors.size()) {
const Monitor& monitor = monitors[monitorIndex];
leftmost = std::min(leftmost, static_cast<int>(monitor.position.left));
topmost = std::min(topmost, static_cast<int>(monitor.position.top));
rightmost = std::max(rightmost, static_cast<int>(monitor.position.right));
bottommost = std::max(bottommost, static_cast<int>(monitor.position.bottom));
}
}
int newWidth = rightmost - leftmost;
int newHeight = bottommost - topmost;
RECT oldRect;
GetWindowRect(windowHwnd, &oldRect);
float windowDpiScaleFactor = static_cast<float>(GetDpiForWindow(windowHwnd)) / 96.0f;
SetParent(windowHwnd, parentWindowHwnd);
RECT parentRect;
GetWindowRect(parentWindowHwnd, &parentRect);
int newX = static_cast<int>((leftmost - parentRect.left) * windowDpiScaleFactor);
int newY = static_cast<int>((topmost - parentRect.top) * windowDpiScaleFactor);
SetWindowPos(windowHwnd, NULL, newX, newY, newWidth, newHeight, SWP_NOZORDER | SWP_NOACTIVATE);
SpanResult result;
result.width = rightmost - leftmost;
result.height = bottommost - topmost;
result.success = true;
return result;
}
/**
* Sets up the wallpaper to span across all connected screens.
* * This function retrieves information about all connected monitors, including their positions, dimensions, and scale factors.
* It then calculates the combined dimensions needed to span the window across all these monitors, taking into account
* the scale factors. The function also handles reparenting the window to the WorkerW window, ensuring it remains below
* other desktop icons. The calculated position and dimensions are adjusted to account for any potential scaling differences
* between the window and the combined monitor setup.
* * @note This function assumes that the window's DPI scale factor is based on a default of 96 DPI. Adjustments are made
* based on this assumption.
* * @note The function currently multiplies the scale factors of all monitors to get an overall scale factor. This may need
* adjustments based on specific application needs.
* * @return SpanResult A structure containing the combined width and height of the monitors, and a success flag indicating
* whether the operation was successful.
*
* @retval SpanResult::width The combined width of all monitors after scaling.
* @retval SpanResult::height The combined height of all monitors after scaling.
* @retval SpanResult::success A boolean flag indicating the success of the operation. Currently, it always returns `true`
* assuming all operations are successful. This can be adjusted based on error checks as needed.
*/
SpanResult setupWallpaperForAllScreens( HWND windowHwnd, HWND parentWindowHwnd) {
std::vector<Monitor> monitors = GetAllMonitors();
int leftmost = INT_MAX;
int topmost = INT_MAX;
int rightmost = INT_MIN;
int bottommost = INT_MIN;
float overallScaleFactor = 1.0f; // assuming default is no scaling
// Calculate the combined dimensions of all monitors
for (const auto& monitor : monitors) {
leftmost = std::min(leftmost, static_cast<int>(monitor.position.left));
topmost = std::min(topmost, static_cast<int>(monitor.position.top));
rightmost = std::max(rightmost, static_cast<int>(monitor.position.right));
bottommost = std::max(bottommost, static_cast<int>(monitor.position.bottom));
overallScaleFactor *= monitor.scaleFactor; // Adjust as per your scaling needs
}
int scaledWidth = static_cast<int>((rightmost - leftmost) * overallScaleFactor);
int scaledHeight = static_cast<int>((bottommost - topmost) * overallScaleFactor);
// Set the position and size of the window to span all monitors
SetWindowPos(windowHwnd, HWND_TOP, leftmost, topmost, scaledWidth, scaledHeight, SWP_NOZORDER | SWP_NOACTIVATE);
// Reparenting and scaling logic
RECT oldRect;
GetWindowRect(windowHwnd, &oldRect);
float windowDpiScaleFactor = static_cast<float>(GetDpiForWindow(windowHwnd)) / 96.0f;
SetParent(windowHwnd, parentWindowHwnd);
RECT parentRect;
GetWindowRect(parentWindowHwnd, &parentRect);
int newX = static_cast<int>((oldRect.left - parentRect.left) * (windowDpiScaleFactor / overallScaleFactor));
int newY = static_cast<int>((oldRect.top - parentRect.top) * (windowDpiScaleFactor / overallScaleFactor));
SetWindowPos(windowHwnd, NULL, newX, newY, scaledWidth, scaledHeight, SWP_NOZORDER | SWP_NOACTIVATE);
// Return the combined span of all monitors
SpanResult result;
result.width = scaledWidth;
result.height = scaledHeight;
result.success = true; // Assuming the operations are successful; adjust as needed
return result;
}
}; };

View File

@ -1,7 +1,7 @@
// SPDX-License-Identifier: LicenseRef-EliasSteurerTachiom OR AGPL-3.0-only // SPDX-License-Identifier: LicenseRef-EliasSteurerTachiom OR AGPL-3.0-only
#include "winwindow.h" #include "winwindow.h"
#include "windowsintegration.h"
#include "ScreenPlayUtil/projectfile.h" #include "ScreenPlayUtil/projectfile.h"
#include "windowsintegration.h"
#include <QGuiApplication> #include <QGuiApplication>
#include <QtQml> #include <QtQml>
#include <algorithm> #include <algorithm>
@ -16,7 +16,6 @@
\brief ScreenPlayWindow used for the Windows implementation. \brief ScreenPlayWindow used for the Windows implementation.
*/ */
HHOOK g_mouseHook; HHOOK g_mouseHook;
QPoint g_LastMousePosition { 0, 0 }; QPoint g_LastMousePosition { 0, 0 };
QPoint g_globalOffset { 0, 0 }; QPoint g_globalOffset { 0, 0 };
@ -182,18 +181,16 @@ void WinWindow::destroyThis()
emit qmlExit(); emit qmlExit();
} }
void WinWindow::setupWallpaperForOneScreen(int activeScreen) void WinWindow::setupWallpaperForOneScreen(int activeScreen)
{ {
WindowsIntegration windowsIntegration; WindowsIntegration windowsIntegration;
auto updateWindowSize = [this](const int width, const int height){ auto updateWindowSize = [this](const int width, const int height) {
setWidth(width); setWidth(width);
setHeight(height); setHeight(height);
m_window.setWidth(width); m_window.setWidth(width);
m_window.setHeight(height); m_window.setHeight(height);
}; };
std::optional<Monitor> monitor = windowsIntegration.setupWallpaperForOneScreen(activeScreen,m_windowHandle,m_windowHandleWorker,updateWindowSize); std::optional<Monitor> monitor = windowsIntegration.setupWallpaperForOneScreen(activeScreen, m_windowHandle, m_windowHandleWorker, updateWindowSize);
} }
/*! /*!
@ -202,7 +199,7 @@ void WinWindow::setupWallpaperForOneScreen(int activeScreen)
void WinWindow::setupWallpaperForAllScreens() void WinWindow::setupWallpaperForAllScreens()
{ {
WindowsIntegration windowsIntegration; WindowsIntegration windowsIntegration;
WindowsIntegration::SpanResult span = windowsIntegration.setupWallpaperForAllScreens(m_windowHandle,m_windowHandleWorker); WindowsIntegration::SpanResult span = windowsIntegration.setupWallpaperForAllScreens(m_windowHandle, m_windowHandleWorker);
setWidth(span.width); setWidth(span.width);
setHeight(span.height); setHeight(span.height);
m_window.setWidth(width()); m_window.setWidth(width());
@ -216,7 +213,7 @@ void WinWindow::setupWallpaperForMultipleScreens(const QVector<int>& activeScree
{ {
std::vector<int> activeScreens(activeScreensList.begin(), activeScreensList.end()); std::vector<int> activeScreens(activeScreensList.begin(), activeScreensList.end());
WindowsIntegration windowsIntegration; WindowsIntegration windowsIntegration;
WindowsIntegration::SpanResult span = windowsIntegration.setupWallpaperForMultipleScreens(activeScreens,m_windowHandle,m_windowHandleWorker); WindowsIntegration::SpanResult span = windowsIntegration.setupWallpaperForMultipleScreens(activeScreens, m_windowHandle, m_windowHandleWorker);
setWidth(span.width); setWidth(span.width);
setHeight(span.height); setHeight(span.height);
m_window.setWidth(width()); m_window.setWidth(width());
@ -290,7 +287,8 @@ void WinWindow::clearComponentCache()
m_window.engine()->clearComponentCache(); m_window.engine()->clearComponentCache();
} }
void WinWindow::checkForFullScreenWindow(){ void WinWindow::checkForFullScreenWindow()
{
bool hasFullscreenWindow = WindowsIntegration().checkForFullScreenWindow(m_windowHandle); bool hasFullscreenWindow = WindowsIntegration().checkForFullScreenWindow(m_windowHandle);
setVisualsPaused(hasFullscreenWindow); setVisualsPaused(hasFullscreenWindow);

View File

@ -8,8 +8,8 @@
#include <QStringList> #include <QStringList>
#include <QtWebEngineQuick> #include <QtWebEngineQuick>
#include "src/widgetwindow.h"
#include "ScreenPlayUtil/logginghandler.h" #include "ScreenPlayUtil/logginghandler.h"
#include "src/widgetwindow.h"
#if defined(Q_OS_WIN) #if defined(Q_OS_WIN)
Q_IMPORT_QML_PLUGIN(ScreenPlaySysInfoPlugin) Q_IMPORT_QML_PLUGIN(ScreenPlaySysInfoPlugin)
@ -95,7 +95,7 @@ int main(int argc, char* argv[])
#if defined(Q_OS_OSX) #if defined(Q_OS_OSX)
MacUtils::showDockIcon(false); MacUtils::showDockIcon(false);
#endif #endif
logging = std::make_unique<const ScreenPlayUtil::LoggingHandler>("ScreenPlayWidget_"+ appID); logging = std::make_unique<const ScreenPlayUtil::LoggingHandler>("ScreenPlayWidget_" + appID);
const int status = app.exec(); const int status = app.exec();
logging.reset(); logging.reset();
return status; return status;

View File

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