1
0
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:
Elias Steurer 2023-10-28 21:26:52 +02:00
parent 9cb57382ab
commit 1b3fddf1e5
6 changed files with 338 additions and 399 deletions

View File

@ -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;
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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();
};

View File

@ -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"

View File

@ -55,8 +55,6 @@ private:
void setupWindowMouseHook();
bool searchWorkerWindowToParentTo();
void configureWindowGeometry();
bool hasWindowScaling() const;
float getScaling(const int monitorIndex) const;
private slots:
void checkForFullScreenWindow();