mirror of
https://gitlab.com/kelteseth/ScreenPlay.git
synced 2024-10-06 09:17:07 +02:00
Change code to general windowsintegration to be used in godot
Fix monitor setup for scaled monitors
This commit is contained in:
parent
fae6555f5a
commit
9cb57382ab
@ -292,6 +292,7 @@ target_link_libraries(
|
||||
ScreenPlayApp
|
||||
PUBLIC ScreenPlaySDK
|
||||
LibArchive::LibArchive
|
||||
ScreenPlayWallpaperLib
|
||||
ScreenPlayUtil
|
||||
ScreenPlayUtilplugin
|
||||
QArchive
|
||||
|
@ -1,6 +1,7 @@
|
||||
// SPDX-License-Identifier: LicenseRef-EliasSteurerTachiom OR AGPL-3.0-only
|
||||
|
||||
#include "ScreenPlay/monitorlistmodel.h"
|
||||
#include "windowsintegration.h"
|
||||
#include <QGuiApplication>
|
||||
namespace ScreenPlay {
|
||||
|
||||
@ -111,7 +112,7 @@ void MonitorListModel::loadMonitors()
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
QModelIndex index;
|
||||
ScreenPlayUtil::WinMonitorStats monitors;
|
||||
WinMonitorStats monitors;
|
||||
|
||||
// This offset lets us center the monitor selection view in the center
|
||||
int offsetX = 0;
|
||||
|
@ -2,67 +2,18 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QtGlobal>
|
||||
|
||||
#if defined(Q_OS_WIN)
|
||||
|
||||
// Must be first!
|
||||
#include <qt_windows.h>
|
||||
// Do not sort !
|
||||
#include "WinUser.h"
|
||||
#include <ShellScalingApi.h>
|
||||
#endif
|
||||
|
||||
#include "ScreenPlayUtil/contenttypes.h"
|
||||
#include <QtGlobal>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonObject>
|
||||
#include <QMetaEnum>
|
||||
#include <QMetaType>
|
||||
#include <QString>
|
||||
#include <QVersionNumber>
|
||||
#include <cmath>
|
||||
#include <optional>
|
||||
|
||||
namespace ScreenPlayUtil {
|
||||
#if defined(Q_OS_WIN)
|
||||
struct WinMonitorStats {
|
||||
|
||||
WinMonitorStats()
|
||||
{
|
||||
EnumDisplayMonitors(NULL, NULL, MonitorEnum, (LPARAM)this);
|
||||
}
|
||||
|
||||
static BOOL CALLBACK MonitorEnum(HMONITOR hMon, HDC hdc, LPRECT lprcMonitor,
|
||||
LPARAM pData)
|
||||
{
|
||||
WinMonitorStats* pThis = reinterpret_cast<WinMonitorStats*>(pData);
|
||||
auto scaleFactor = DEVICE_SCALE_FACTOR::DEVICE_SCALE_FACTOR_INVALID;
|
||||
GetScaleFactorForMonitor(hMon, &scaleFactor);
|
||||
|
||||
UINT x = 0;
|
||||
UINT y = 0;
|
||||
GetDpiForMonitor(hMon, MONITOR_DPI_TYPE::MDT_RAW_DPI, &x, &y);
|
||||
pThis->sizes.push_back({ x, y });
|
||||
pThis->scaleFactor.push_back(scaleFactor);
|
||||
pThis->hMonitors.push_back(hMon);
|
||||
pThis->hdcMonitors.push_back(hdc);
|
||||
pThis->rcMonitors.push_back(*lprcMonitor);
|
||||
pThis->iMonitors.push_back(pThis->hdcMonitors.size());
|
||||
|
||||
// qInfo() << std::abs(lprcMonitor->right - lprcMonitor->left) << std::abs(lprcMonitor->top - lprcMonitor->bottom);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
std::vector<int> iMonitors;
|
||||
std::vector<HMONITOR> hMonitors;
|
||||
std::vector<HDC> hdcMonitors;
|
||||
std::vector<RECT> rcMonitors;
|
||||
std::vector<DEVICE_SCALE_FACTOR> scaleFactor;
|
||||
std::vector<std::pair<UINT, UINT>> sizes;
|
||||
int index = 0;
|
||||
};
|
||||
#endif
|
||||
QJsonArray fillArray(const QVector<QString>& items);
|
||||
ScreenPlay::SearchType::SearchType getSearchTypeFromInstalledType(const ScreenPlay::InstalledType::InstalledType type);
|
||||
std::optional<ScreenPlay::InstalledType::InstalledType> getInstalledTypeFromString(const QString& type);
|
||||
|
@ -54,8 +54,14 @@ set(LIB_SOURCES)
|
||||
set(LIB_HEADER)
|
||||
|
||||
if(WIN32)
|
||||
set(LIB_SOURCES src/windowshook.cpp)
|
||||
set(LIB_HEADER src/windowshook.h)
|
||||
set(LIB_SOURCES src/windowsintegration.cpp)
|
||||
set(LIB_HEADER src/windowsintegration.h)
|
||||
elseif(APPLE)
|
||||
set(LIB_SOURCES src/macosintegration.cpp)
|
||||
set(LIB_HEADER src/macosintegration.h)
|
||||
elseif(UNIX)
|
||||
set(LIB_SOURCES src/waylandintegration.cpp)
|
||||
set(LIB_HEADER src/waylandintegration.h)
|
||||
endif()
|
||||
|
||||
add_library(ScreenPlayWallpaperLib STATIC ${LIB_SOURCES} ${LIB_HEADER})
|
||||
@ -66,7 +72,9 @@ if(WIN32)
|
||||
target_link_libraries(ScreenPlayWallpaperLib PUBLIC shcore.lib)
|
||||
endif()
|
||||
|
||||
add_executable(${PROJECT_NAME} ${SOURCES} ${HEADER})
|
||||
|
||||
add_executable(${PROJECT_NAME} ${SOURCES} ${HEADER}
|
||||
src/windowsintegration.h src/windowsintegration.cpp)
|
||||
|
||||
qt_add_qml_module(
|
||||
${PROJECT_NAME}
|
||||
|
@ -105,6 +105,7 @@ bool ScreenPlayGodotWallpaper::init(int activeScreen)
|
||||
|
||||
String output = "Setup window activeScreen: " + itos(activeScreen) + " scaling: " + rtos(scaling) + " x: " + itos(x) + " y: " + itos(y) + " width: " + itos(width) + " height: " + itos(height);
|
||||
UtilityFunctions::print(output);
|
||||
displayServer->window_set_size(godot::Vector2((real_t)width, (real_t)height));
|
||||
|
||||
// Must be called twice for some reason when window has scaling...
|
||||
if (!SetWindowPos(m_hook->windowHandle, nullptr, x, y, width, height, SWP_HIDEWINDOW)) {
|
||||
@ -120,7 +121,6 @@ bool ScreenPlayGodotWallpaper::init(int activeScreen)
|
||||
UtilityFunctions::print("Could not attach to parent window");
|
||||
return false;
|
||||
}
|
||||
displayServer->window_set_size(godot::Vector2((real_t)width, (real_t)height));
|
||||
ShowWindow(m_hook->windowHandle, SW_SHOW);
|
||||
const std::string windowTitle = "ScreenPlayWallpaperGodot";
|
||||
SetWindowText(hwnd, windowTitle.c_str());
|
||||
@ -138,7 +138,7 @@ godot::String ScreenPlayGodotWallpaper::read_from_pipe()
|
||||
{
|
||||
std::string outMsg;
|
||||
if (!m_windowsPipe.readFromPipe(outMsg)) {
|
||||
UtilityFunctions::print("Unable to read from pipe");
|
||||
// No new message
|
||||
return "";
|
||||
}
|
||||
return godot::String(outMsg.c_str());
|
||||
|
@ -14,7 +14,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include "ScreenPlayGodotWallpaper.h"
|
||||
#include "windowshook.h"
|
||||
#include "windowsintegration.h"
|
||||
#include "WindowsPipe.h"
|
||||
|
||||
class ScreenPlayGodotWallpaper : public godot::Node {
|
||||
|
@ -6,31 +6,37 @@
|
||||
|
||||
class WindowsPipe {
|
||||
public:
|
||||
WindowsPipe()
|
||||
: m_hPipe(INVALID_HANDLE_VALUE)
|
||||
WindowsPipe()
|
||||
: m_hPipe(INVALID_HANDLE_VALUE)
|
||||
{
|
||||
memset(&m_overlapped, 0, sizeof(m_overlapped));
|
||||
m_overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); // Manual reset event
|
||||
}
|
||||
|
||||
void setPipeName(const std::wstring& pipeName) {
|
||||
void setPipeName(const std::wstring& pipeName)
|
||||
{
|
||||
m_pipeName = pipeName;
|
||||
}
|
||||
|
||||
bool start() {
|
||||
bool start()
|
||||
{
|
||||
return connectToPipe();
|
||||
}
|
||||
|
||||
bool readFromPipe(std::string& outMessage);
|
||||
bool writeToPipe(const std::string& message);
|
||||
|
||||
~WindowsPipe() {
|
||||
void close()
|
||||
{
|
||||
if (m_hPipe != INVALID_HANDLE_VALUE) {
|
||||
CloseHandle(m_hPipe);
|
||||
}
|
||||
}
|
||||
~WindowsPipe()
|
||||
{
|
||||
close();
|
||||
CloseHandle(m_overlapped.hEvent);
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
bool connectToPipe();
|
||||
|
||||
@ -38,5 +44,4 @@ private:
|
||||
HANDLE m_hPipe;
|
||||
OVERLAPPED m_overlapped;
|
||||
std::wstring m_pipeName;
|
||||
|
||||
};
|
||||
|
@ -8,9 +8,7 @@ var send_welcome: bool = false
|
||||
# Pings main ScreenPlay application that
|
||||
# this wallpaper is still active
|
||||
func ping_alive():
|
||||
print("GD: ping_alive")
|
||||
var success = screen_play_wallpaper.send_ping()
|
||||
print("1 ping_alive_screenplay: ", success)
|
||||
if not success:
|
||||
terminate()
|
||||
|
||||
@ -22,10 +20,8 @@ func terminate():
|
||||
# Checks for messages from the main ScreenPlay instance
|
||||
# for example for propery changes or commands like quit
|
||||
func check_messages():
|
||||
print("GD: check_messages")
|
||||
var msg = screen_play_wallpaper.read_from_pipe()
|
||||
if not msg.is_empty():
|
||||
print("message: ", msg)
|
||||
if "quit" in msg:
|
||||
return terminate()
|
||||
|
||||
@ -55,25 +51,23 @@ func _ready():
|
||||
print(path)
|
||||
if not load_scene(path):
|
||||
print("Failed to load the PCK file.")
|
||||
# No not call terminate here because we did not
|
||||
# yet setup via screenplay_manager.init()
|
||||
get_tree().quit()
|
||||
return
|
||||
Engine.set_max_fps(24)
|
||||
|
||||
var ok = screen_play_wallpaper.init(screen_play_wallpaper.get_activeScreensList()[0])
|
||||
|
||||
print("init ", ok)
|
||||
if not ok:
|
||||
printerr("Unable to setup screen")
|
||||
if not screen_play_wallpaper.get_pipeConnected():
|
||||
print("connect to ScreenPlay")
|
||||
var ok_connect_to_named_pipe = screen_play_wallpaper.connect_to_named_pipe()
|
||||
print("connection: ", ok_connect_to_named_pipe)
|
||||
var ok_connect_to_named_pipe = screen_play_wallpaper.connect_to_named_pipe()
|
||||
|
||||
func _process(delta):
|
||||
|
||||
if not send_welcome:
|
||||
if not screen_play_wallpaper.get_screenPlayConnected():
|
||||
print("send_welcome")
|
||||
send_welcome = screen_play_wallpaper.send_welcome()
|
||||
print("send_welcome: ", send_welcome)
|
||||
if send_welcome:
|
||||
check_messages_timer.start()
|
||||
ping_alive_timer.start()
|
||||
|
122
ScreenPlayWallpaper/src/windowsintegration.cpp
Normal file
122
ScreenPlayWallpaper/src/windowsintegration.cpp
Normal file
@ -0,0 +1,122 @@
|
||||
#include "windowsintegration.h"
|
||||
|
||||
WindowsIntegration::WindowsIntegration()
|
||||
{
|
||||
}
|
||||
|
||||
bool WindowsHook::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.
|
||||
*/
|
||||
float WindowsHook::getScaling(const int monitorIndex) const
|
||||
{
|
||||
// Get all monitors
|
||||
int monitorCount = GetSystemMetrics(SM_CMONITORS);
|
||||
|
||||
if (monitorIndex < 0 || monitorIndex >= monitorCount) {
|
||||
// Invalid monitor index
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
DISPLAY_DEVICE displayDevice;
|
||||
ZeroMemory(&displayDevice, sizeof(displayDevice));
|
||||
displayDevice.cb = sizeof(displayDevice);
|
||||
|
||||
// Enumerate through monitors until we find the one we're looking for
|
||||
for (int i = 0; EnumDisplayDevices(NULL, i, &displayDevice, 0); i++) {
|
||||
if (i == monitorIndex) {
|
||||
DEVMODE devMode;
|
||||
ZeroMemory(&devMode, sizeof(devMode));
|
||||
devMode.dmSize = sizeof(devMode);
|
||||
|
||||
// Get settings for selected monitor
|
||||
if (!EnumDisplaySettings(displayDevice.DeviceName, ENUM_CURRENT_SETTINGS, &devMode)) {
|
||||
// Unable to get monitor settings
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
// Get DPI for selected monitor
|
||||
HMONITOR hMonitor = MonitorFromPoint({ devMode.dmPosition.x, devMode.dmPosition.y }, MONITOR_DEFAULTTONEAREST);
|
||||
UINT dpiX = 0, dpiY = 0;
|
||||
if (SUCCEEDED(GetDpiForMonitor(hMonitor, MDT_EFFECTIVE_DPI, &dpiX, &dpiY))) {
|
||||
return (float)dpiX / 96.0f; // Standard DPI is 96
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we reach here, it means we couldn't find the monitor with the given index or couldn't get the DPI.
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Returns true of at least one monitor has active scaling enabled.
|
||||
*/
|
||||
bool WindowsHook::hasWindowScaling() const
|
||||
{
|
||||
auto enumMonitorCallback = [](HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) -> BOOL {
|
||||
int scaling = GetDeviceCaps(hdcMonitor, LOGPIXELSX) / 96;
|
||||
if (scaling != 1) {
|
||||
*(bool*)dwData = true;
|
||||
return false; // Stop enumeration
|
||||
}
|
||||
return true; // Continue enumeration
|
||||
};
|
||||
|
||||
bool hasScaling = false;
|
||||
EnumDisplayMonitors(NULL, NULL, enumMonitorCallback, (LPARAM)&hasScaling);
|
||||
|
||||
return hasScaling;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Searches for the worker window for our window to parent to.
|
||||
*/
|
||||
BOOL SearchForWorkerWindow(HWND hwnd, LPARAM lparam)
|
||||
{
|
||||
// 0xXXXXXXX "" WorkerW
|
||||
// ...
|
||||
// 0xXXXXXXX "" SHELLDLL_DefView
|
||||
// 0xXXXXXXXX "FolderView" SysListView32
|
||||
// 0xXXXXXXXX "" WorkerW <---- We want this one
|
||||
// 0xXXXXXXXX "Program Manager" Progman
|
||||
if (FindWindowExW(hwnd, nullptr, L"SHELLDLL_DefView", nullptr))
|
||||
*reinterpret_cast<HWND*>(lparam) = FindWindowExW(nullptr, hwnd, L"WorkerW", nullptr);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
ResizeResult ResizeWindowToMonitor(HWND hwnd, int monitorIndex)
|
||||
{
|
||||
WinMonitorStats stats;
|
||||
if (monitorIndex >= stats.rcMonitors.size()) {
|
||||
return { 0, 0, 0, 0, false }; // Invalid monitor index
|
||||
}
|
||||
RECT monitorRect = stats.rcMonitors[monitorIndex];
|
||||
int x = monitorRect.left;
|
||||
int y = monitorRect.top;
|
||||
int width = monitorRect.right - monitorRect.left;
|
||||
int height = monitorRect.bottom - monitorRect.top;
|
||||
|
||||
BOOL result = SetWindowPos(hwnd, NULL, x, y, width, height, SWP_NOZORDER | SWP_NOACTIVATE);
|
||||
|
||||
return { x, y, width, height, result != 0 };
|
||||
}
|
||||
|
||||
|
||||
std::vector<Monitor> GetAllMonitors() {
|
||||
std::vector<Monitor> monitors;
|
||||
|
||||
// Use the static MonitorEnumProc callback for EnumDisplayMonitors
|
||||
EnumDisplayMonitors(NULL, NULL, MonitorEnumProc, reinterpret_cast<LPARAM>(&monitors));
|
||||
|
||||
return monitors;
|
||||
}
|
125
ScreenPlayWallpaper/src/windowsintegration.h
Normal file
125
ScreenPlayWallpaper/src/windowsintegration.h
Normal file
@ -0,0 +1,125 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef NOMINMAX
|
||||
#define NOMINMAX
|
||||
#endif
|
||||
#include <windows.h>
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <shellscalingapi.h>
|
||||
#include <vector>
|
||||
|
||||
// Do not sort !
|
||||
#include "WinUser.h"
|
||||
#include <ShellScalingApi.h>
|
||||
|
||||
struct Monitor {
|
||||
HMONITOR monitorID; // Handle to the monitor
|
||||
int index; // Index of the monitor
|
||||
RECT position; // Monitor's position and size
|
||||
SIZE size; // Monitor's width and height
|
||||
float scaleFactor; // Scale factor (DPI scaling as a factor, e.g., 1.5 for 150% scaling)
|
||||
|
||||
void print() const {
|
||||
std::cout << "Monitor Info:" << std::endl;
|
||||
std::cout << "Monitor ID: " << monitorID << std::endl;
|
||||
std::cout << "Index: " << index << std::endl;
|
||||
std::cout << "Position: (" << position.left << ", " << position.top << ", "
|
||||
<< position.right << ", " << position.bottom << ")" << std::endl;
|
||||
std::cout << "Size: (" << size.cx << "x" << size.cy << ")" << std::endl;
|
||||
std::cout << "Scale Factor: " << scaleFactor << std::endl;
|
||||
}
|
||||
};
|
||||
|
||||
// Static callback function for EnumDisplayMonitors
|
||||
static BOOL CALLBACK MonitorEnumProc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) {
|
||||
std::vector<Monitor>* pMonitors = reinterpret_cast<std::vector<Monitor>*>(dwData);
|
||||
|
||||
MONITORINFOEX info;
|
||||
info.cbSize = sizeof(info);
|
||||
GetMonitorInfo(hMonitor, &info);
|
||||
|
||||
UINT dpiX, dpiY;
|
||||
GetDpiForMonitor(hMonitor, MDT_EFFECTIVE_DPI, &dpiX, &dpiY);
|
||||
|
||||
Monitor monitor;
|
||||
monitor.monitorID = hMonitor;
|
||||
monitor.index = pMonitors->size(); // Set index based on the current size of the vector
|
||||
monitor.position = info.rcMonitor;
|
||||
monitor.size.cx = info.rcMonitor.right - info.rcMonitor.left;
|
||||
monitor.size.cy = info.rcMonitor.bottom - info.rcMonitor.top;
|
||||
monitor.scaleFactor = static_cast<float>(dpiX) / 96.0f;
|
||||
|
||||
pMonitors->push_back(monitor);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
std::vector<Monitor> GetAllMonitors();
|
||||
|
||||
|
||||
BOOL WINAPI SearchForWorkerWindow(HWND hwnd, LPARAM lparam);
|
||||
|
||||
struct WinMonitorStats {
|
||||
|
||||
|
||||
WinMonitorStats()
|
||||
{
|
||||
EnumDisplayMonitors(NULL, NULL, MonitorEnum, (LPARAM)this);
|
||||
}
|
||||
|
||||
|
||||
static BOOL CALLBACK MonitorEnum(HMONITOR hMon, HDC hdc, LPRECT lprcMonitor, LPARAM pData)
|
||||
{
|
||||
WinMonitorStats* pThis = reinterpret_cast<WinMonitorStats*>(pData);
|
||||
auto scaleFactor = DEVICE_SCALE_FACTOR::DEVICE_SCALE_FACTOR_INVALID;
|
||||
GetScaleFactorForMonitor(hMon, &scaleFactor);
|
||||
|
||||
UINT x = 0;
|
||||
UINT y = 0;
|
||||
GetDpiForMonitor(hMon, MONITOR_DPI_TYPE::MDT_RAW_DPI, &x, &y);
|
||||
pThis->sizes.push_back({ x, y });
|
||||
pThis->scaleFactor.push_back(scaleFactor);
|
||||
pThis->hMonitors.push_back(hMon);
|
||||
pThis->hdcMonitors.push_back(hdc);
|
||||
pThis->rcMonitors.push_back(*lprcMonitor);
|
||||
pThis->iMonitors.push_back(pThis->hdcMonitors.size());
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
std::vector<int> iMonitors;
|
||||
std::vector<HMONITOR> hMonitors;
|
||||
std::vector<HDC> hdcMonitors;
|
||||
std::vector<RECT> rcMonitors;
|
||||
std::vector<DEVICE_SCALE_FACTOR> scaleFactor;
|
||||
std::vector<std::pair<UINT, UINT>> sizes;
|
||||
};
|
||||
|
||||
struct ResizeResult {
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
bool success = false;
|
||||
};
|
||||
ResizeResult ResizeWindowToMonitor(HWND hwnd, int monitorIndex);
|
||||
|
||||
struct Point {
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
};
|
||||
|
||||
struct WindowsHook {
|
||||
bool searchWorkerWindowToParentTo();
|
||||
float getScaling(const int monitorIndex) const;
|
||||
bool hasWindowScaling() const;
|
||||
HWND windowHandle {};
|
||||
HWND windowHandleWorker {};
|
||||
Point zeroPoint;
|
||||
};
|
||||
|
||||
class WindowsIntegration {
|
||||
public:
|
||||
WindowsIntegration();
|
||||
};
|
@ -1,5 +1,6 @@
|
||||
// SPDX-License-Identifier: LicenseRef-EliasSteurerTachiom OR AGPL-3.0-only
|
||||
#include "winwindow.h"
|
||||
#include "windowsintegration.h"
|
||||
#include "ScreenPlayUtil/projectfile.h"
|
||||
#include <QGuiApplication>
|
||||
#include <QtQml>
|
||||
@ -15,21 +16,6 @@
|
||||
\brief ScreenPlayWindow used for the Windows implementation.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\brief Searches for the worker window for our window to parent to.
|
||||
*/
|
||||
BOOL WINAPI SearchForWorkerWindow(HWND hwnd, LPARAM lparam)
|
||||
{
|
||||
// 0xXXXXXXX "" WorkerW
|
||||
// ...
|
||||
// 0xXXXXXXX "" SHELLDLL_DefView
|
||||
// 0xXXXXXXXX "FolderView" SysListView32
|
||||
// 0xXXXXXXXX "" WorkerW <---- We want this one
|
||||
// 0xXXXXXXXX "Program Manager" Progman
|
||||
if (FindWindowExW(hwnd, nullptr, L"SHELLDLL_DefView", nullptr))
|
||||
*reinterpret_cast<HWND*>(lparam) = FindWindowExW(nullptr, hwnd, L"WorkerW", nullptr);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
HHOOK g_mouseHook;
|
||||
QPoint g_LastMousePosition { 0, 0 };
|
||||
@ -148,6 +134,7 @@ ScreenPlay::WallpaperExitCode WinWindow::start()
|
||||
qRegisterMetaType<WinWindow*>();
|
||||
qmlRegisterSingletonInstance<WinWindow>("ScreenPlayWallpaper", 1, 0, "Wallpaper", this);
|
||||
|
||||
m_window.setResizeMode(QQuickView::ResizeMode::SizeRootObjectToView);
|
||||
configureWindowGeometry();
|
||||
|
||||
// We do not support autopause for multi monitor wallpaper and
|
||||
@ -162,6 +149,12 @@ ScreenPlay::WallpaperExitCode WinWindow::start()
|
||||
setupWindowMouseHook();
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
qInfo() << "Setup " << width() << height();
|
||||
m_window.setSource(QUrl("qrc:/qml/ScreenPlayWallpaper/qml/Wallpaper.qml"));
|
||||
|
||||
return ScreenPlay::WallpaperExitCode::Ok;
|
||||
}
|
||||
|
||||
@ -207,40 +200,81 @@ BOOL CALLBACK GetMonitorByIndex(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMo
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief This method is called if the user want to have one wallpaper on one window.
|
||||
*/
|
||||
/*
|
||||
* 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 (`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:
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
void WinWindow::setupWallpaperForOneScreen(int activeScreen)
|
||||
{
|
||||
std::vector<Monitor> monitors = GetAllMonitors();
|
||||
for (const auto& monitor : monitors) {
|
||||
monitor.print();
|
||||
if (monitor.index != activeScreen)
|
||||
continue;
|
||||
|
||||
const QRect screenRect = QGuiApplication::screens().at(activeScreen)->geometry();
|
||||
const int boderWidth = 2;
|
||||
const float scaling = getScaling(activeScreen);
|
||||
const int borderOffset = -1;
|
||||
SetWindowPos(m_windowHandle, HWND_TOP,
|
||||
monitor.position.left, monitor.position.top,
|
||||
monitor.size.cx, monitor.size.cy,
|
||||
SWP_NOZORDER | SWP_NOACTIVATE);
|
||||
setWidth(monitor.size.cx);
|
||||
setHeight(monitor.size.cy);
|
||||
m_window.setWidth(width());
|
||||
m_window.setHeight(height());
|
||||
|
||||
ScreenPlayUtil::WinMonitorStats monitors;
|
||||
const int width = (std::abs(monitors.rcMonitors[activeScreen].right - monitors.rcMonitors[activeScreen].left) / scaling) + boderWidth;
|
||||
const int height = (std::abs(monitors.rcMonitors[activeScreen].top - monitors.rcMonitors[activeScreen].bottom) / scaling) + boderWidth;
|
||||
RECT oldRect;
|
||||
GetWindowRect(m_windowHandle, &oldRect);
|
||||
std::cout << "Old Window Position: (" << oldRect.left << ", " << oldRect.top << ")" << std::endl;
|
||||
|
||||
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(m_windowHandle, m_windowHandleWorker);
|
||||
RECT 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));
|
||||
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(m_windowHandle, NULL, newX, newY, newWidth, newHeight, SWP_NOZORDER | SWP_NOACTIVATE);
|
||||
|
||||
const int x = monitors.rcMonitors[activeScreen].left + m_zeroPoint.x() + borderOffset;
|
||||
const int y = monitors.rcMonitors[activeScreen].top + m_zeroPoint.y() + borderOffset;
|
||||
qInfo() << QString("Setup window activeScreen: %1 scaling: %2 x: %3 y: %4 width: %5 height: %6").arg(activeScreen).arg(scaling).arg(x).arg(y).arg(width).arg(height);
|
||||
// Also set it in BaseWindow. This is needed for Windows fade in.
|
||||
setWidth(width - boderWidth);
|
||||
setHeight(height - boderWidth);
|
||||
{
|
||||
// Must be called twice for some reason when window has scaling...
|
||||
if (!SetWindowPos(m_windowHandle, nullptr, x, y, width, height, SWP_HIDEWINDOW)) {
|
||||
qFatal("Could not set window pos");
|
||||
}
|
||||
if (!SetWindowPos(m_windowHandle, nullptr, x, y, width, height, SWP_HIDEWINDOW)) {
|
||||
qFatal("Could not set window pos");
|
||||
}
|
||||
}
|
||||
|
||||
if (SetParent(m_windowHandle, m_windowHandleWorker) == nullptr) {
|
||||
qFatal("Could not attach to parent window");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -248,7 +282,7 @@ void WinWindow::setupWallpaperForOneScreen(int activeScreen)
|
||||
*/
|
||||
void WinWindow::setupWallpaperForAllScreens()
|
||||
{
|
||||
ScreenPlayUtil::WinMonitorStats monitors;
|
||||
WinMonitorStats monitors;
|
||||
QRect rect;
|
||||
for (int i = 0; i < monitors.iMonitors.size(); i++) {
|
||||
const int width = std::abs(monitors.rcMonitors[i].right - monitors.rcMonitors[i].left);
|
||||
@ -405,12 +439,12 @@ void WinWindow::configureWindowGeometry()
|
||||
// Windows coordante system begins at 0x0 at the
|
||||
// main monitors upper left and not at the most left top monitor.
|
||||
// This can be easily read from the worker window.
|
||||
m_zeroPoint = { std::abs(rect.left), std::abs(rect.top) };
|
||||
g_globalOffset = m_zeroPoint;
|
||||
// m_zeroPoint = { std::abs(rect.left), std::abs(rect.top) };
|
||||
// g_globalOffset = m_zeroPoint;
|
||||
|
||||
// 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_POPUPWINDOW);
|
||||
SetWindowLongPtr(m_windowHandle, GWL_STYLE, WS_POPUP);
|
||||
|
||||
// Ether for one Screen or for all
|
||||
if ((QGuiApplication::screens().length() == activeScreensList().length()) && (activeScreensList().length() != 1)) {
|
||||
@ -422,12 +456,8 @@ void WinWindow::configureWindowGeometry()
|
||||
setupWallpaperForMultipleScreens(activeScreensList());
|
||||
}
|
||||
|
||||
m_window.setResizeMode(QQuickView::ResizeMode::SizeRootObjectToView);
|
||||
m_window.setWidth(width());
|
||||
m_window.setHeight(height());
|
||||
qInfo() << "Setup " << width() << height();
|
||||
m_window.setSource(QUrl("qrc:/qml/ScreenPlayWallpaper/qml/Wallpaper.qml"));
|
||||
m_window.hide();
|
||||
|
||||
m_window.show();
|
||||
}
|
||||
|
||||
BOOL CALLBACK FindTheDesiredWnd(HWND hWnd, LPARAM lParam)
|
||||
|
Loading…
Reference in New Issue
Block a user