mirror of
https://gitlab.com/kelteseth/ScreenPlay.git
synced 2024-10-06 09:17:07 +02:00
Change to use more functions into windowsintegration
This commit is contained in:
parent
9cb57382ab
commit
1b3fddf1e5
@ -61,21 +61,10 @@ bool ScreenPlayGodotWallpaper::configureWindowGeometry()
|
||||
UtilityFunctions::print("No worker window found");
|
||||
return false;
|
||||
}
|
||||
|
||||
RECT rect {};
|
||||
if (!GetWindowRect(m_hook->windowHandleWorker, &rect)) {
|
||||
UtilityFunctions::print("Unable to get WindoeRect from worker");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 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_hook->zeroPoint = { std::abs(rect.left), std::abs(rect.top) };
|
||||
|
||||
// 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);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -84,7 +73,7 @@ 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<WindowsHook>();
|
||||
m_hook = std::make_unique<WindowsIntegration>();
|
||||
m_hook->windowHandle = hwnd;
|
||||
hideFromTaskbar(hwnd);
|
||||
if (!configureWindowGeometry()) {
|
||||
@ -92,38 +81,13 @@ bool ScreenPlayGodotWallpaper::init(int activeScreen)
|
||||
}
|
||||
ShowWindow(m_hook->windowHandle, SW_HIDE);
|
||||
|
||||
const int borderWidth = 2;
|
||||
const float scaling = m_hook->getScaling(activeScreen); // Assuming getScaling is your own function
|
||||
const int borderOffset = -1;
|
||||
WindowsIntegration windowsIntegration;
|
||||
std::optional<Monitor> monitor = windowsIntegration.setupWallpaperForOneScreen(activeScreen,m_hook->windowHandle,m_hook->windowHandleWorker);
|
||||
displayServer->window_set_size(godot::Vector2((real_t)monitor->size.cx, (real_t)monitor->size.cy));
|
||||
|
||||
WinMonitorStats monitors; // Assuming this is your own function
|
||||
const int width = static_cast<int>(std::abs(monitors.rcMonitors[activeScreen].right - monitors.rcMonitors[activeScreen].left) / scaling) + borderWidth;
|
||||
const int height = static_cast<int>(std::abs(monitors.rcMonitors[activeScreen].top - monitors.rcMonitors[activeScreen].bottom) / scaling) + borderWidth;
|
||||
|
||||
const int x = monitors.rcMonitors[activeScreen].left + m_hook->zeroPoint.x + borderOffset; // Assuming m_zeroPoint is a POINT struct
|
||||
const int y = monitors.rcMonitors[activeScreen].top + m_hook->zeroPoint.y + borderOffset;
|
||||
|
||||
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)) {
|
||||
UtilityFunctions::print("Could not set window pos");
|
||||
return false;
|
||||
}
|
||||
if (!SetWindowPos(m_hook->windowHandle, nullptr, x, y, width, height, SWP_HIDEWINDOW)) {
|
||||
UtilityFunctions::print("Could not set window pos 2");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (SetParent(m_hook->windowHandle, m_hook->windowHandleWorker) == nullptr) {
|
||||
UtilityFunctions::print("Could not attach to parent window");
|
||||
return false;
|
||||
}
|
||||
ShowWindow(m_hook->windowHandle, SW_SHOW);
|
||||
const std::string windowTitle = "ScreenPlayWallpaperGodot";
|
||||
SetWindowText(hwnd, windowTitle.c_str());
|
||||
ShowWindow(m_hook->windowHandle, SW_SHOW);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -60,7 +60,7 @@ private:
|
||||
|
||||
godot::String m_appID = "";
|
||||
godot::String m_projectPath = "";
|
||||
std::unique_ptr<WindowsHook> m_hook;
|
||||
std::unique_ptr<WindowsIntegration> m_hook;
|
||||
double m_timesinceLastRead = 0.0;
|
||||
bool m_pipeConnected = false;
|
||||
bool m_screenPlayConnected = false;
|
||||
|
@ -1,10 +1,7 @@
|
||||
#include "windowsintegration.h"
|
||||
|
||||
WindowsIntegration::WindowsIntegration()
|
||||
{
|
||||
}
|
||||
|
||||
bool WindowsHook::searchWorkerWindowToParentTo()
|
||||
bool WindowsIntegration::searchWorkerWindowToParentTo()
|
||||
{
|
||||
|
||||
HWND progman_hwnd = FindWindowW(L"Progman", L"Program Manager");
|
||||
@ -18,7 +15,7 @@ bool WindowsHook::searchWorkerWindowToParentTo()
|
||||
/*!
|
||||
\brief Returns scaling factor as reported by Windows.
|
||||
*/
|
||||
float WindowsHook::getScaling(const int monitorIndex) const
|
||||
float WindowsIntegration::getScaling(const int monitorIndex) const
|
||||
{
|
||||
// Get all monitors
|
||||
int monitorCount = GetSystemMetrics(SM_CMONITORS);
|
||||
@ -54,14 +51,14 @@ float WindowsHook::getScaling(const int monitorIndex) const
|
||||
}
|
||||
}
|
||||
|
||||
// If we reach here, it means we couldn't find the monitor with the given index or couldn't get the DPI.
|
||||
// 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
|
||||
bool WindowsIntegration::hasWindowScaling() const
|
||||
{
|
||||
auto enumMonitorCallback = [](HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) -> BOOL {
|
||||
int scaling = GetDeviceCaps(hdcMonitor, LOGPIXELSX) / 96;
|
||||
@ -94,25 +91,7 @@ BOOL SearchForWorkerWindow(HWND hwnd, LPARAM lparam)
|
||||
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> WindowsIntegration::GetAllMonitors() {
|
||||
std::vector<Monitor> monitors;
|
||||
|
||||
// Use the static MonitorEnumProc callback for EnumDisplayMonitors
|
||||
@ -120,3 +99,46 @@ std::vector<Monitor> GetAllMonitors() {
|
||||
|
||||
return monitors;
|
||||
}
|
||||
|
||||
BOOL GetMonitorByHandle(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData)
|
||||
{
|
||||
|
||||
auto info = (sEnumInfo*)dwData;
|
||||
if (info->hMonitor == hMonitor)
|
||||
return FALSE;
|
||||
++info->iIndex;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL FindTheDesiredWnd(HWND hWnd, LPARAM lParam)
|
||||
{
|
||||
DWORD dwStyle = (DWORD)GetWindowLong(hWnd, GWL_STYLE);
|
||||
if ((dwStyle & WS_MAXIMIZE) != 0) {
|
||||
*(reinterpret_cast<HWND*>(lParam)) = hWnd;
|
||||
return false; // stop enumerating
|
||||
}
|
||||
return true; // keep enumerating
|
||||
}
|
||||
|
||||
BOOL 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;
|
||||
}
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include <iostream>
|
||||
#include <shellscalingapi.h>
|
||||
#include <vector>
|
||||
#include <optional>
|
||||
|
||||
// Do not sort !
|
||||
#include "WinUser.h"
|
||||
@ -32,33 +33,9 @@ struct Monitor {
|
||||
};
|
||||
|
||||
// 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 CALLBACK MonitorEnumProc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData);
|
||||
BOOL CALLBACK GetMonitorByHandle(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData);
|
||||
BOOL CALLBACK FindTheDesiredWnd(HWND hWnd, LPARAM lParam);
|
||||
BOOL WINAPI SearchForWorkerWindow(HWND hwnd, LPARAM lparam);
|
||||
|
||||
struct WinMonitorStats {
|
||||
@ -96,30 +73,269 @@ struct WinMonitorStats {
|
||||
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 {
|
||||
struct sEnumInfo {
|
||||
int iIndex;
|
||||
HMONITOR hMonitor;
|
||||
};
|
||||
|
||||
|
||||
class WindowsIntegration {
|
||||
public:
|
||||
|
||||
bool searchWorkerWindowToParentTo();
|
||||
float getScaling(const int monitorIndex) const;
|
||||
bool hasWindowScaling() const;
|
||||
HWND windowHandle {};
|
||||
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 {
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
bool success = 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> setupWallpaperForOneScreen(const int activeScreen, HWND windowHwnd, HWND parentWindowHwnd)
|
||||
{
|
||||
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);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
class WindowsIntegration {
|
||||
public:
|
||||
WindowsIntegration();
|
||||
};
|
||||
|
@ -149,12 +149,9 @@ ScreenPlay::WallpaperExitCode WinWindow::start()
|
||||
setupWindowMouseHook();
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
qInfo() << "Setup " << width() << height();
|
||||
m_window.setSource(QUrl("qrc:/qml/ScreenPlayWallpaper/qml/Wallpaper.qml"));
|
||||
|
||||
m_window.show();
|
||||
return ScreenPlay::WallpaperExitCode::Ok;
|
||||
}
|
||||
|
||||
@ -185,96 +182,15 @@ void WinWindow::destroyThis()
|
||||
emit qmlExit();
|
||||
}
|
||||
|
||||
struct sEnumInfo {
|
||||
int iIndex;
|
||||
HMONITOR hMonitor;
|
||||
};
|
||||
|
||||
BOOL CALLBACK GetMonitorByIndex(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData)
|
||||
{
|
||||
auto* info = (sEnumInfo*)dwData;
|
||||
if (--info->iIndex < 0) {
|
||||
info->hMonitor = hMonitor;
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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;
|
||||
|
||||
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());
|
||||
|
||||
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);
|
||||
|
||||
}
|
||||
return;
|
||||
WindowsIntegration windowsIntegration;
|
||||
std::optional<Monitor> monitor = windowsIntegration.setupWallpaperForOneScreen(activeScreen,m_windowHandle,m_windowHandleWorker);
|
||||
setWidth(monitor->size.cx);
|
||||
setHeight(monitor->size.cy);
|
||||
m_window.setWidth(width());
|
||||
m_window.setHeight(height());
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -282,43 +198,12 @@ void WinWindow::setupWallpaperForOneScreen(int activeScreen)
|
||||
*/
|
||||
void WinWindow::setupWallpaperForAllScreens()
|
||||
{
|
||||
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);
|
||||
const int height = std::abs(monitors.rcMonitors[i].top - monitors.rcMonitors[i].bottom);
|
||||
qInfo() << width << height;
|
||||
rect.setWidth(rect.width() + width);
|
||||
rect.setHeight(rect.height() + height);
|
||||
}
|
||||
int offsetX = 0;
|
||||
int offsetY = 0;
|
||||
for (int i = 0; i < monitors.iMonitors.size(); i++) {
|
||||
const int x = monitors.rcMonitors[i].left;
|
||||
const int y = monitors.rcMonitors[i].top;
|
||||
qInfo() << x << y;
|
||||
if (x < offsetX) {
|
||||
offsetX = x;
|
||||
}
|
||||
if (y < offsetY) {
|
||||
offsetY += y;
|
||||
}
|
||||
}
|
||||
if (!SetWindowPos(m_windowHandle, nullptr, offsetX, offsetY, rect.width(), rect.height(), SWP_NOSIZE | SWP_NOMOVE)) {
|
||||
qFatal("Could not set window pos: ");
|
||||
}
|
||||
if (!SetWindowPos(m_windowHandle, nullptr, offsetX, offsetY, rect.width(), rect.height(), SWP_NOSIZE | SWP_NOMOVE)) {
|
||||
qFatal("Could not set window pos: ");
|
||||
}
|
||||
if (SetParent(m_windowHandle, m_windowHandleWorker) == nullptr) {
|
||||
qFatal("Could not attach to parent window");
|
||||
}
|
||||
qInfo() << rect.width() << rect.height() << offsetX << offsetY;
|
||||
m_window.setHeight(rect.height());
|
||||
m_window.setWidth(rect.width());
|
||||
m_window.setY(offsetY);
|
||||
m_window.setX(offsetX + 1920);
|
||||
qInfo() << m_window.geometry();
|
||||
WindowsIntegration windowsIntegration;
|
||||
WindowsIntegration::SpanResult span = windowsIntegration.setupWallpaperForAllScreens(m_windowHandle,m_windowHandleWorker);
|
||||
setWidth(span.width);
|
||||
setHeight(span.height);
|
||||
m_window.setWidth(width());
|
||||
m_window.setHeight(height());
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -326,31 +211,13 @@ void WinWindow::setupWallpaperForAllScreens()
|
||||
*/
|
||||
void WinWindow::setupWallpaperForMultipleScreens(const QVector<int>& activeScreensList)
|
||||
{
|
||||
QRect rect;
|
||||
QScreen* upperLeftScreen { nullptr };
|
||||
// Check for the upper left screen first so we get x and y positions
|
||||
for (const int screen : activeScreensList) {
|
||||
QScreen* screenTmp = QGuiApplication::screens().at(screen);
|
||||
if (upperLeftScreen != nullptr) {
|
||||
if (screenTmp->geometry().x() < upperLeftScreen->geometry().x() || screenTmp->geometry().y() < upperLeftScreen->geometry().y()) {
|
||||
upperLeftScreen = screenTmp;
|
||||
}
|
||||
} else {
|
||||
upperLeftScreen = screenTmp;
|
||||
}
|
||||
rect.setWidth(screenTmp->geometry().width() + rect.width());
|
||||
rect.setHeight(screenTmp->geometry().height() + rect.height());
|
||||
}
|
||||
|
||||
rect.setX(upperLeftScreen->geometry().x());
|
||||
rect.setY(upperLeftScreen->geometry().y());
|
||||
|
||||
if (!SetWindowPos(m_windowHandle, nullptr, rect.x() + m_zeroPoint.x(), rect.y() + m_zeroPoint.y(), rect.width(), rect.height(), SWP_SHOWWINDOW)) {
|
||||
qFatal("Could not set window pos: ");
|
||||
}
|
||||
if (SetParent(m_windowHandle, m_windowHandleWorker) == nullptr) {
|
||||
qFatal("Could not attach to parent window");
|
||||
}
|
||||
std::vector<int> activeScreens(activeScreensList.begin(), activeScreensList.end());
|
||||
WindowsIntegration windowsIntegration;
|
||||
WindowsIntegration::SpanResult span = windowsIntegration.setupWallpaperForMultipleScreens(activeScreens,m_windowHandle,m_windowHandleWorker);
|
||||
setWidth(span.width);
|
||||
setHeight(span.height);
|
||||
m_window.setWidth(width());
|
||||
m_window.setHeight(height());
|
||||
}
|
||||
|
||||
bool WinWindow::searchWorkerWindowToParentTo()
|
||||
@ -364,63 +231,6 @@ bool WinWindow::searchWorkerWindowToParentTo()
|
||||
return EnumWindows(SearchForWorkerWindow, reinterpret_cast<LPARAM>(&m_windowHandleWorker));
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Returns scaling factor as reported by Windows.
|
||||
*/
|
||||
float WinWindow::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 WinWindow::hasWindowScaling() const
|
||||
{
|
||||
const auto screens = QGuiApplication::screens();
|
||||
for (int i = 0; i < screens.count(); i++) {
|
||||
if (getScaling(i) != 1) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Sets the size and the parent to the worker handle to be displayed behind the
|
||||
desktop icons.
|
||||
@ -431,17 +241,6 @@ void WinWindow::configureWindowGeometry()
|
||||
qFatal("No worker window found");
|
||||
}
|
||||
|
||||
RECT rect {};
|
||||
if (!GetWindowRect(m_windowHandleWorker, &rect)) {
|
||||
qFatal("Unable to get WindoeRect from worker");
|
||||
}
|
||||
|
||||
// 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;
|
||||
|
||||
// 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);
|
||||
@ -455,75 +254,9 @@ void WinWindow::configureWindowGeometry()
|
||||
} else if (activeScreensList().length() > 1) {
|
||||
setupWallpaperForMultipleScreens(activeScreensList());
|
||||
}
|
||||
|
||||
|
||||
m_window.show();
|
||||
}
|
||||
|
||||
BOOL CALLBACK FindTheDesiredWnd(HWND hWnd, LPARAM lParam)
|
||||
{
|
||||
DWORD dwStyle = (DWORD)GetWindowLong(hWnd, GWL_STYLE);
|
||||
if ((dwStyle & WS_MAXIMIZE) != 0) {
|
||||
*(reinterpret_cast<HWND*>(lParam)) = hWnd;
|
||||
return false; // stop enumerating
|
||||
}
|
||||
return true; // keep enumerating
|
||||
}
|
||||
|
||||
BOOL CALLBACK GetMonitorByHandle(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData)
|
||||
{
|
||||
Q_UNUSED(hdcMonitor)
|
||||
Q_UNUSED(lprcMonitor)
|
||||
|
||||
auto info = (sEnumInfo*)dwData;
|
||||
if (info->hMonitor == hMonitor)
|
||||
return FALSE;
|
||||
++info->iIndex;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
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.
|
||||
*/
|
||||
void WinWindow::checkForFullScreenWindow()
|
||||
{
|
||||
|
||||
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(m_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
|
||||
if (monitorIndex == wallpaperIndex) {
|
||||
|
||||
setVisualsPaused(true);
|
||||
} else {
|
||||
setVisualsPaused(false);
|
||||
}
|
||||
|
||||
} else {
|
||||
setVisualsPaused(false);
|
||||
}
|
||||
}
|
||||
/*!
|
||||
\brief Custom exit method to force a redraw of the window so that
|
||||
the default desktop wallpaper can be seen agian.
|
||||
@ -554,4 +287,10 @@ void WinWindow::clearComponentCache()
|
||||
m_window.engine()->clearComponentCache();
|
||||
}
|
||||
|
||||
void WinWindow::checkForFullScreenWindow(){
|
||||
bool hasFullscreenWindow = WindowsIntegration().checkForFullScreenWindow(m_windowHandle);
|
||||
|
||||
setVisualsPaused(hasFullscreenWindow);
|
||||
}
|
||||
|
||||
#include "moc_winwindow.cpp"
|
||||
|
@ -55,8 +55,6 @@ private:
|
||||
void setupWindowMouseHook();
|
||||
bool searchWorkerWindowToParentTo();
|
||||
void configureWindowGeometry();
|
||||
bool hasWindowScaling() const;
|
||||
float getScaling(const int monitorIndex) const;
|
||||
|
||||
private slots:
|
||||
void checkForFullScreenWindow();
|
||||
|
Loading…
Reference in New Issue
Block a user