1
0
mirror of https://gitlab.com/kelteseth/ScreenPlay.git synced 2024-10-06 09:17:07 +02:00

Move more functionality into the windowsintegration class

This commit is contained in:
Elias Steurer 2023-11-02 13:25:09 +01:00
parent f982002d80
commit 4db63579a7
6 changed files with 100 additions and 85 deletions

View File

@ -56,13 +56,13 @@ void ScreenPlayGodotWallpaper::hideFromTaskbar(HWND hwnd)
bool ScreenPlayGodotWallpaper::configureWindowGeometry()
{
if (!m_hook->searchWorkerWindowToParentTo()) {
if (!m_windowsIntegration->searchWorkerWindowToParentTo()) {
UtilityFunctions::print("No worker window found");
return false;
}
// WARNING: Setting Window flags must be called *here*!
SetWindowLongPtr(m_hook->windowHandle, GWL_EXSTYLE, WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR | WS_EX_NOACTIVATE | WS_EX_TOOLWINDOW | WS_EX_TRANSPARENT);
SetWindowLongPtr(m_hook->windowHandle, GWL_STYLE, WS_POPUPWINDOW);
SetWindowLongPtr(m_windowsIntegration->windowHandle(), GWL_EXSTYLE, WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR | WS_EX_NOACTIVATE | WS_EX_TOOLWINDOW | WS_EX_TRANSPARENT);
SetWindowLongPtr(m_windowsIntegration->windowHandle(), GWL_STYLE, WS_POPUPWINDOW);
return true;
}
@ -72,23 +72,26 @@ bool ScreenPlayGodotWallpaper::init(int activeScreen)
auto* displayServer = DisplayServer::get_singleton();
int64_t handle_int = displayServer->window_get_native_handle(godot::DisplayServer::HandleType::WINDOW_HANDLE, activeScreen);
HWND hwnd = reinterpret_cast<HWND>(static_cast<intptr_t>(handle_int));
m_hook = std::make_unique<WindowsIntegration>();
m_hook->windowHandle = hwnd;
m_windowsIntegration = std::make_unique<WindowsIntegration>();
m_windowsIntegration->setWindowHandle(hwnd);
hideFromTaskbar(hwnd);
if (!configureWindowGeometry()) {
return false;
}
ShowWindow(m_hook->windowHandle, SW_HIDE);
ShowWindow(m_windowsIntegration->windowHandle(), SW_HIDE);
WindowsIntegration windowsIntegration;
auto updateWindowSize = [this, &displayServer](const int width, const int height) {
auto updateWindowSize = [&displayServer](const int width, const int 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);
const std::optional<Monitor> monitor = windowsIntegration.setupWallpaperForOneScreen(activeScreen, updateWindowSize);
if (!monitor.has_value())
return false;
const std::string windowTitle = "ScreenPlayWallpaperGodot";
SetWindowText(hwnd, windowTitle.c_str());
ShowWindow(m_hook->windowHandle, SW_SHOW);
ShowWindow(m_windowsIntegration->windowHandle(), SW_SHOW);
return true;
}
@ -194,14 +197,14 @@ bool ScreenPlayGodotWallpaper::exit()
{
// Somehow this gets called at editor startup
// so just return if not initialized
if (m_hook) {
if (m_windowsIntegration) {
ShowWindow(m_hook->windowHandle, SW_HIDE);
ShowWindow(m_windowsIntegration->windowHandle(), SW_HIDE);
// Force refresh so that we display the regular
// desktop wallpaper again
ShowWindow(m_hook->windowHandleWorker, SW_SHOW);
ShowWindow(m_hook->windowHandleWorker, SW_HIDE);
ShowWindow(m_windowsIntegration->windowHandleWorker(), SW_SHOW);
ShowWindow(m_windowsIntegration->windowHandleWorker(), SW_HIDE);
}
return true;
}

View File

@ -62,7 +62,7 @@ private:
godot::String m_appID = "";
godot::String m_projectPath = "";
std::unique_ptr<WindowsIntegration> m_hook;
std::unique_ptr<WindowsIntegration> m_windowsIntegration;
double m_timesinceLastRead = 0.0;
bool m_pipeConnected = false;
bool m_screenPlayConnected = false;

View File

@ -1,14 +1,4 @@
#include "windowsintegration.h"
bool WindowsIntegration::searchWorkerWindowToParentTo()
{
HWND progman_hwnd = FindWindowW(L"Progman", L"Program Manager");
const DWORD WM_SPAWN_WORKER = 0x052C;
SendMessageTimeoutW(progman_hwnd, WM_SPAWN_WORKER, 0xD, 0x1, SMTO_NORMAL,
10000, nullptr);
return EnumWindows(SearchForWorkerWindow, reinterpret_cast<LPARAM>(&windowHandleWorker));
}
/*!
\brief Returns scaling factor as reported by Windows.
@ -73,6 +63,15 @@ bool WindowsIntegration::hasWindowScaling() const
return hasScaling;
}
bool WindowsIntegration::searchWorkerWindowToParentTo()
{
HWND progman_hwnd = FindWindowW(L"Progman", L"Program Manager");
const DWORD WM_SPAWN_WORKER = 0x052C;
SendMessageTimeoutW(progman_hwnd, WM_SPAWN_WORKER, 0xD, 0x1, SMTO_NORMAL,
10000, nullptr);
return EnumWindows(SearchForWorkerWindow, reinterpret_cast<LPARAM>(&m_windowHandleWorker));
}
/*!
\brief Searches for the worker window for our window to parent to.
*/
@ -140,7 +139,7 @@ bool WindowsIntegration::checkForFullScreenWindow(HWND windowHandle)
* * 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,
* * In our scenario, we want to move and resize a window (`m_windowHandle`) 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:
@ -159,7 +158,7 @@ bool WindowsIntegration::checkForFullScreenWindow(HWND windowHandle)
* scale factors.
*/
std::optional<Monitor> WindowsIntegration::setupWallpaperForOneScreen(const int activeScreen, HWND windowHwnd, HWND parentWindowHwnd, std::function<void(int, int)> updateWindowSize)
std::optional<Monitor> WindowsIntegration::setupWallpaperForOneScreen(const int activeScreen, std::function<void(int, int)> updateWindowSize)
{
std::vector<Monitor> monitors = GetAllMonitors();
for (const auto& monitor : monitors) {
@ -167,7 +166,7 @@ std::optional<Monitor> WindowsIntegration::setupWallpaperForOneScreen(const int
if (monitor.index != activeScreen)
continue;
SetWindowPos(windowHwnd, HWND_TOP,
SetWindowPos(m_windowHandle, HWND_TOP,
monitor.position.left, monitor.position.top,
monitor.size.cx, monitor.size.cy,
SWP_NOZORDER | SWP_NOACTIVATE);
@ -176,17 +175,17 @@ std::optional<Monitor> WindowsIntegration::setupWallpaperForOneScreen(const int
updateWindowSize(monitor.size.cx, monitor.size.cy);
RECT oldRect;
GetWindowRect(windowHwnd, &oldRect);
GetWindowRect(m_windowHandle, &oldRect);
std::cout << "Old Window Position: (" << oldRect.left << ", " << oldRect.top << ")" << std::endl;
float windowDpiScaleFactor = static_cast<float>(GetDpiForWindow(windowHwnd)) / 96.0f;
float windowDpiScaleFactor = static_cast<float>(GetDpiForWindow(m_windowHandle)) / 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);
SetParent(m_windowHandle, m_windowHandleWorker);
RECT parentRect;
GetWindowRect(parentWindowHwnd, &parentRect);
GetWindowRect(m_windowHandleWorker, &parentRect);
std::cout << "WorkerW Window Position: (" << parentRect.left << ", " << parentRect.top << ")" << std::endl;
int newX = static_cast<int>((oldRect.left - parentRect.left) * (windowDpiScaleFactor / targetMonitorDpiScaleFactor));
@ -197,7 +196,7 @@ std::optional<Monitor> WindowsIntegration::setupWallpaperForOneScreen(const int
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);
SetWindowPos(m_windowHandle, NULL, newX, newY, newWidth, newHeight, SWP_NOZORDER | SWP_NOACTIVATE);
return { monitor };
}
return std::nullopt;
@ -221,7 +220,7 @@ std::optional<Monitor> WindowsIntegration::setupWallpaperForOneScreen(const int
* 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)
WindowsIntegration::SpanResult WindowsIntegration::setupWallpaperForMultipleScreens(const std::vector<int>& activeScreens)
{
std::vector<Monitor> monitors = GetAllMonitors();
@ -244,18 +243,18 @@ WindowsIntegration::SpanResult WindowsIntegration::setupWallpaperForMultipleScre
int newHeight = bottommost - topmost;
RECT oldRect;
GetWindowRect(windowHwnd, &oldRect);
GetWindowRect(m_windowHandle, &oldRect);
float windowDpiScaleFactor = static_cast<float>(GetDpiForWindow(windowHwnd)) / 96.0f;
float windowDpiScaleFactor = static_cast<float>(GetDpiForWindow(m_windowHandle)) / 96.0f;
SetParent(windowHwnd, parentWindowHwnd);
SetParent(m_windowHandle, m_windowHandleWorker);
RECT parentRect;
GetWindowRect(parentWindowHwnd, &parentRect);
GetWindowRect(m_windowHandleWorker, &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);
SetWindowPos(m_windowHandle, NULL, newX, newY, newWidth, newHeight, SWP_NOZORDER | SWP_NOACTIVATE);
SpanResult result;
result.width = rightmost - leftmost;
result.height = bottommost - topmost;
@ -281,7 +280,7 @@ WindowsIntegration::SpanResult WindowsIntegration::setupWallpaperForMultipleScre
* @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)
WindowsIntegration::SpanResult WindowsIntegration::setupWallpaperForAllScreens()
{
std::vector<Monitor> monitors = GetAllMonitors();
@ -304,19 +303,19 @@ WindowsIntegration::SpanResult WindowsIntegration::setupWallpaperForAllScreens(H
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);
SetWindowPos(m_windowHandle, 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);
GetWindowRect(m_windowHandle, &oldRect);
float windowDpiScaleFactor = static_cast<float>(GetDpiForWindow(m_windowHandle)) / 96.0f;
SetParent(m_windowHandle, m_windowHandleWorker);
RECT parentRect;
GetWindowRect(parentWindowHwnd, &parentRect);
GetWindowRect(m_windowHandleWorker, &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);
SetWindowPos(m_windowHandle, NULL, newX, newY, scaledWidth, scaledHeight, SWP_NOZORDER | SWP_NOACTIVATE);
// Return the combined span of all monitors
SpanResult result;
@ -327,6 +326,26 @@ WindowsIntegration::SpanResult WindowsIntegration::setupWallpaperForAllScreens(H
return result;
}
HWND WindowsIntegration::windowHandle() const
{
return m_windowHandle;
}
HWND WindowsIntegration::windowHandleWorker() const
{
return m_windowHandleWorker;
}
void WindowsIntegration::setWindowHandle(HWND windowHandle)
{
m_windowHandle = windowHandle;
}
void WindowsIntegration::setWindowHandleWorker(HWND windowHandleWorker)
{
m_windowHandleWorker = windowHandleWorker;
}
BOOL GetMonitorByHandle(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData)
{

View File

@ -83,11 +83,8 @@ struct sEnumInfo {
HMONITOR hMonitor;
};
struct WindowsIntegration {
HWND windowHandle {};
HWND windowHandleWorker {};
class WindowsIntegration {
public:
struct SpanResult {
int width = 0;
int height = 0;
@ -100,7 +97,15 @@ struct WindowsIntegration {
std::vector<Monitor> GetAllMonitors();
int GetMonitorIndex(HMONITOR hMonitor);
bool checkForFullScreenWindow(HWND windowHandle);
std::optional<Monitor> setupWallpaperForOneScreen(const int activeScreen, HWND windowHwnd, HWND parentWindowHwnd, std::function<void(int, int)> updateWindowSize);
SpanResult setupWallpaperForMultipleScreens(const std::vector<int>& activeScreens, HWND windowHwnd, HWND parentWindowHwnd);
SpanResult setupWallpaperForAllScreens(HWND windowHwnd, HWND parentWindowHwnd);
std::optional<Monitor> setupWallpaperForOneScreen(const int activeScreen, std::function<void(int, int)> updateWindowSize);
SpanResult setupWallpaperForMultipleScreens(const std::vector<int>& activeScreens);
SpanResult setupWallpaperForAllScreens();
HWND windowHandle() const;
HWND windowHandleWorker() const;
void setWindowHandle(HWND windowHandle);
void setWindowHandleWorker(HWND windowHandleWorker);
private:
HWND m_windowHandle {};
HWND m_windowHandleWorker {};
};

View File

@ -1,6 +1,5 @@
// SPDX-License-Identifier: LicenseRef-EliasSteurerTachiom OR AGPL-3.0-only
#include "winwindow.h"
#include "ScreenPlayUtil/projectfile.h"
#include "windowsintegration.h"
#include <QGuiApplication>
#include <QtQml>
@ -124,8 +123,8 @@ ScreenPlay::WallpaperExitCode WinWindow::start()
}
m_windowsDesktopProperties = std::make_unique<WindowsDesktopProperties>();
m_windowHandle = reinterpret_cast<HWND>(m_window.winId());
if (!IsWindow(m_windowHandle)) {
m_windowsIntegration.setWindowHandle(reinterpret_cast<HWND>(m_window.winId()));
if (!IsWindow(m_windowsIntegration.windowHandle())) {
qCritical("Could not get a valid window handle!");
return ScreenPlay::WallpaperExitCode::Invalid_Start_Windows_HandleError;
}
@ -160,12 +159,12 @@ ScreenPlay::WallpaperExitCode WinWindow::start()
void WinWindow::setVisible(bool show)
{
if (show) {
if (!ShowWindow(m_windowHandle, SW_SHOW)) {
if (!ShowWindow(m_windowsIntegration.windowHandle(), SW_SHOW)) {
qDebug() << "Cannot set window handle SW_SHOW";
}
} else {
if (!ShowWindow(m_windowHandle, SW_HIDE)) {
if (!ShowWindow(m_windowsIntegration.windowHandle(), SW_HIDE)) {
qDebug() << "Cannot set window handle SW_HIDE";
}
}
@ -183,14 +182,13 @@ void WinWindow::destroyThis()
void WinWindow::setupWallpaperForOneScreen(int activeScreen)
{
WindowsIntegration windowsIntegration;
auto updateWindowSize = [this](const int width, const int height) {
setWidth(width);
setHeight(height);
m_window.setWidth(width);
m_window.setHeight(height);
};
std::optional<Monitor> monitor = windowsIntegration.setupWallpaperForOneScreen(activeScreen, m_windowHandle, m_windowHandleWorker, updateWindowSize);
std::optional<Monitor> monitor = m_windowsIntegration.setupWallpaperForOneScreen(activeScreen, updateWindowSize);
}
/*!
@ -198,8 +196,7 @@ void WinWindow::setupWallpaperForOneScreen(int activeScreen)
*/
void WinWindow::setupWallpaperForAllScreens()
{
WindowsIntegration windowsIntegration;
WindowsIntegration::SpanResult span = windowsIntegration.setupWallpaperForAllScreens(m_windowHandle, m_windowHandleWorker);
WindowsIntegration::SpanResult span = m_windowsIntegration.setupWallpaperForAllScreens();
setWidth(span.width);
setHeight(span.height);
m_window.setWidth(width());
@ -212,38 +209,30 @@ void WinWindow::setupWallpaperForAllScreens()
void WinWindow::setupWallpaperForMultipleScreens(const QVector<int>& activeScreensList)
{
std::vector<int> activeScreens(activeScreensList.begin(), activeScreensList.end());
WindowsIntegration windowsIntegration;
WindowsIntegration::SpanResult span = windowsIntegration.setupWallpaperForMultipleScreens(activeScreens, m_windowHandle, m_windowHandleWorker);
WindowsIntegration::SpanResult span = m_windowsIntegration.setupWallpaperForMultipleScreens(activeScreens);
setWidth(span.width);
setHeight(span.height);
m_window.setWidth(width());
m_window.setHeight(height());
}
bool WinWindow::searchWorkerWindowToParentTo()
{
HWND progman_hwnd = FindWindowW(L"Progman", L"Program Manager");
const DWORD WM_SPAWN_WORKER = 0x052C;
SendMessageTimeoutW(progman_hwnd, WM_SPAWN_WORKER, 0xD, 0x1, SMTO_NORMAL,
10000, nullptr);
return EnumWindows(SearchForWorkerWindow, reinterpret_cast<LPARAM>(&m_windowHandleWorker));
}
/*!
\brief Sets the size and the parent to the worker handle to be displayed behind the
desktop icons.
*/
void WinWindow::configureWindowGeometry()
{
if (!searchWorkerWindowToParentTo()) {
if (!m_windowsIntegration.searchWorkerWindowToParentTo()) {
qFatal("No worker window found");
}
if (!IsWindow(m_windowsIntegration.windowHandleWorker())) {
qCritical("Could not get a valid window handle wroker!");
return;
}
// WARNING: Setting Window flags must be called *here*!
SetWindowLongPtr(m_windowHandle, GWL_EXSTYLE, WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR | WS_EX_NOACTIVATE | WS_EX_TOOLWINDOW | WS_EX_TRANSPARENT);
SetWindowLongPtr(m_windowHandle, GWL_STYLE, WS_POPUP);
SetWindowLongPtr(m_windowsIntegration.windowHandle(), GWL_EXSTYLE, WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR | WS_EX_NOACTIVATE | WS_EX_TOOLWINDOW | WS_EX_TRANSPARENT);
SetWindowLongPtr(m_windowsIntegration.windowHandle(), GWL_STYLE, WS_POPUP);
// Ether for one Screen or for all
if ((QGuiApplication::screens().length() == activeScreensList().length()) && (activeScreensList().length() != 1)) {
@ -267,12 +256,12 @@ void WinWindow::terminate()
if (type() != InstalledType::VideoWallpaper && type() != InstalledType::GifWallpaper) {
UnhookWindowsHookEx(g_mouseHook);
}
ShowWindow(m_windowHandle, SW_HIDE);
ShowWindow(m_windowsIntegration.windowHandle(), SW_HIDE);
// Force refresh so that we display the regular
// desktop wallpaper again
ShowWindow(m_windowHandleWorker, SW_HIDE);
ShowWindow(m_windowHandleWorker, SW_SHOW);
ShowWindow(m_windowsIntegration.windowHandleWorker(), SW_HIDE);
ShowWindow(m_windowsIntegration.windowHandleWorker(), SW_SHOW);
QGuiApplication::quit();
}
@ -289,7 +278,7 @@ void WinWindow::clearComponentCache()
void WinWindow::checkForFullScreenWindow()
{
bool hasFullscreenWindow = WindowsIntegration().checkForFullScreenWindow(m_windowHandle);
bool hasFullscreenWindow = m_windowsIntegration.checkForFullScreenWindow(m_windowsIntegration.windowHandle());
setVisualsPaused(hasFullscreenWindow);
}

View File

@ -18,6 +18,7 @@
#include "basewindow.h"
#include "windowsdesktopproperties.h"
#include "windowsintegration.h"
class WinWindow : public BaseWindow {
Q_OBJECT
@ -53,7 +54,6 @@ private:
void setupWallpaperForAllScreens();
void setupWallpaperForMultipleScreens(const QVector<int>& activeScreensList);
void setupWindowMouseHook();
bool searchWorkerWindowToParentTo();
void configureWindowGeometry();
private slots:
@ -62,8 +62,7 @@ private slots:
private:
QPoint m_zeroPoint {};
QQuickView m_window;
HWND m_windowHandle {};
HWND m_windowHandleWorker {};
WindowsIntegration m_windowsIntegration;
QTimer m_checkForFullScreenWindowTimer;
QTimer m_reconfigureTimer;
std::unique_ptr<WindowsDesktopProperties> m_windowsDesktopProperties;