Host: Add GetTopLevelWindowInfo()

And use it for screensaver inhibiting on Linux.
This commit is contained in:
Connor McLaughlin
2022-11-18 18:14:39 +10:00
parent 3d4d2336a9
commit 8d7aea5e19
25 changed files with 133 additions and 126 deletions

View File

@ -44,62 +44,28 @@ DisplayWidget::~DisplayWidget()
#endif
}
qreal DisplayWidget::devicePixelRatioFromScreen() const
{
const QScreen* screen_for_ratio = screen();
if (!screen_for_ratio)
screen_for_ratio = QGuiApplication::primaryScreen();
return screen_for_ratio ? screen_for_ratio->devicePixelRatio() : static_cast<qreal>(1);
}
int DisplayWidget::scaledWindowWidth() const
{
return std::max(static_cast<int>(std::ceil(static_cast<qreal>(width()) * devicePixelRatioFromScreen())), 1);
return std::max(
static_cast<int>(std::ceil(static_cast<qreal>(width()) * QtUtils::GetDevicePixelRatioForWidget(this))), 1);
}
int DisplayWidget::scaledWindowHeight() const
{
return std::max(static_cast<int>(std::ceil(static_cast<qreal>(height()) * devicePixelRatioFromScreen())), 1);
return std::max(
static_cast<int>(std::ceil(static_cast<qreal>(height()) * QtUtils::GetDevicePixelRatioForWidget(this))), 1);
}
std::optional<WindowInfo> DisplayWidget::getWindowInfo()
{
WindowInfo wi;
// Windows and Apple are easy here since there's no display connection.
#if defined(_WIN32)
wi.type = WindowInfo::Type::Win32;
wi.window_handle = reinterpret_cast<void*>(winId());
#elif defined(__APPLE__)
wi.type = WindowInfo::Type::MacOS;
wi.window_handle = reinterpret_cast<void*>(winId());
#else
QPlatformNativeInterface* pni = QGuiApplication::platformNativeInterface();
const QString platform_name = QGuiApplication::platformName();
if (platform_name == QStringLiteral("xcb"))
std::optional<WindowInfo> ret(QtUtils::GetWindowInfoForWidget(this));
if (ret.has_value())
{
wi.type = WindowInfo::Type::X11;
wi.display_connection = pni->nativeResourceForWindow("display", windowHandle());
wi.window_handle = reinterpret_cast<void*>(winId());
m_last_window_width = ret->surface_width;
m_last_window_height = ret->surface_height;
m_last_window_scale = ret->surface_scale;
}
else if (platform_name == QStringLiteral("wayland"))
{
wi.type = WindowInfo::Type::Wayland;
wi.display_connection = pni->nativeResourceForWindow("display", windowHandle());
wi.window_handle = pni->nativeResourceForWindow("surface", windowHandle());
}
else
{
qCritical() << "Unknown PNI platform " << platform_name;
return std::nullopt;
}
#endif
m_last_window_width = wi.surface_width = static_cast<u32>(scaledWindowWidth());
m_last_window_height = wi.surface_height = static_cast<u32>(scaledWindowHeight());
m_last_window_scale = wi.surface_scale = static_cast<float>(devicePixelRatioFromScreen());
return wi;
return ret;
}
void DisplayWidget::updateRelativeMode(bool enabled)
@ -270,7 +236,7 @@ bool DisplayWidget::event(QEvent* event)
if (!m_relative_mouse_enabled)
{
const qreal dpr = devicePixelRatioFromScreen();
const qreal dpr = QtUtils::GetDevicePixelRatioForWidget(this);
const QPoint mouse_pos = mouse_event->pos();
const float scaled_x = static_cast<float>(static_cast<qreal>(mouse_pos.x()) * dpr);
@ -341,7 +307,7 @@ bool DisplayWidget::event(QEvent* event)
{
QWidget::event(event);
const float dpr = devicePixelRatioFromScreen();
const float dpr = QtUtils::GetDevicePixelRatioForWidget(this);
const u32 scaled_width =
static_cast<u32>(std::max(static_cast<int>(std::ceil(static_cast<qreal>(width()) * dpr)), 1));
const u32 scaled_height =

View File

@ -19,7 +19,6 @@ public:
int scaledWindowWidth() const;
int scaledWindowHeight() const;
qreal devicePixelRatioFromScreen() const;
std::optional<WindowInfo> getWindowInfo();

View File

@ -2520,6 +2520,13 @@ void MainWindow::checkForSettingChanges()
updateWindowState();
}
void MainWindow::getWindowInfo(WindowInfo* wi)
{
std::optional<WindowInfo> opt_wi(QtUtils::GetWindowInfoForWidget(this));
if (opt_wi.has_value())
*wi = opt_wi.value();
}
void MainWindow::onCheckForUpdatesActionTriggered()
{
// Wipe out the last version, that way it displays the update if we've previously skipped it.

View File

@ -4,8 +4,10 @@
#include <QtWidgets/QMainWindow>
#include <QtWidgets/QStackedWidget>
#include <memory>
#include <optional>
#include "controllersettingsdialog.h"
#include "common/window_info.h"
#include "core/types.h"
#include "displaywidget.h"
#include "settingsdialog.h"
@ -97,6 +99,7 @@ public Q_SLOTS:
bool requestShutdown(bool allow_confirm = true, bool allow_save_to_state = true, bool save_state = true, bool block_until_done = false);
void requestExit(bool allow_save_to_state = true);
void checkForSettingChanges();
void getWindowInfo(WindowInfo* wi);
void checkForUpdates(bool display_message);

View File

@ -6,6 +6,7 @@
#include "common/log.h"
#include "common/path.h"
#include "common/string_util.h"
#include "common/window_info.h"
#include "core/cheats.h"
#include "core/controller.h"
#include "core/game_database.h"
@ -1757,10 +1758,13 @@ void Host::RequestExit(bool save_state_if_running)
QMetaObject::invokeMethod(g_main_window, "requestExit", Qt::QueuedConnection, Q_ARG(bool, save_state_if_running));
}
void* Host::GetTopLevelWindowHandle()
std::optional<WindowInfo> Host::GetTopLevelWindowInfo()
{
void* ret = nullptr;
QMetaObject::invokeMethod(g_main_window, &MainWindow::getNativeWindowId, Qt::BlockingQueuedConnection, &ret);
// Normally we'd just feed the std::optional all the way through here. But that won't work because of some bug
// in Qt 6.1, and we can't upgrade that because of raging/abusive Win7 users... to anyone still using that dead
// OS, this is a passive-aggressive "screw you".
WindowInfo ret;
QMetaObject::invokeMethod(g_main_window, "getWindowInfo", Qt::BlockingQueuedConnection, Q_ARG(WindowInfo*, &ret));
return ret;
}

View File

@ -6,6 +6,7 @@
#include <QtCore/QCoreApplication>
#include <QtCore/QMetaObject>
#include <QtGui/QDesktopServices>
#include <QtGui/QGuiApplication>
#include <QtGui/QKeyEvent>
#include <QtWidgets/QComboBox>
#include <QtWidgets/QDialog>
@ -22,6 +23,14 @@
#include <array>
#include <map>
#if !defined(_WIN32) && !defined(APPLE)
#include <qpa/qplatformnativeinterface.h>
#endif
#ifdef _WIN32
#include "common/windows_headers.h"
#endif
namespace QtUtils {
QFrame* CreateHorizontalLine(QWidget* parent)
@ -862,4 +871,53 @@ QIcon GetIconForCompatibility(GameDatabase::CompatibilityRating rating)
return QIcon(QStringLiteral(":/icons/star-%1.png").arg(static_cast<u32>(rating)));
}
qreal GetDevicePixelRatioForWidget(const QWidget* widget)
{
const QScreen* screen_for_ratio = widget->screen();
if (!screen_for_ratio)
screen_for_ratio = QGuiApplication::primaryScreen();
return screen_for_ratio ? screen_for_ratio->devicePixelRatio() : static_cast<qreal>(1);
}
std::optional<WindowInfo> GetWindowInfoForWidget(QWidget* widget)
{
WindowInfo wi;
// Windows and Apple are easy here since there's no display connection.
#if defined(_WIN32)
wi.type = WindowInfo::Type::Win32;
wi.window_handle = reinterpret_cast<void*>(widget->winId());
#elif defined(__APPLE__)
wi.type = WindowInfo::Type::MacOS;
wi.window_handle = reinterpret_cast<void*>(widget->winId());
#else
QPlatformNativeInterface* pni = QGuiApplication::platformNativeInterface();
const QString platform_name = QGuiApplication::platformName();
if (platform_name == QStringLiteral("xcb"))
{
wi.type = WindowInfo::Type::X11;
wi.display_connection = pni->nativeResourceForWindow("display", widget->windowHandle());
wi.window_handle = reinterpret_cast<void*>(widget->winId());
}
else if (platform_name == QStringLiteral("wayland"))
{
wi.type = WindowInfo::Type::Wayland;
wi.display_connection = pni->nativeResourceForWindow("display", widget->windowHandle());
wi.window_handle = pni->nativeResourceForWindow("surface", widget->windowHandle());
}
else
{
qCritical() << "Unknown PNI platform " << platform_name;
return std::nullopt;
}
#endif
const qreal dpr = GetDevicePixelRatioForWidget(widget);
wi.surface_width = static_cast<u32>(static_cast<qreal>(widget->width()) * dpr);
wi.surface_height = static_cast<u32>(static_cast<qreal>(widget->height()) * dpr);
wi.surface_scale = static_cast<float>(dpr);
return wi;
}
} // namespace QtUtils

View File

@ -1,4 +1,5 @@
#pragma once
#include "common/window_info.h"
#include "common/types.h"
#include <QtCore/QByteArray>
#include <QtCore/QMetaType>
@ -91,4 +92,10 @@ QIcon GetIconForRegion(DiscRegion region);
QIcon GetIconForEntryType(GameList::EntryType type);
QIcon GetIconForCompatibility(GameDatabase::CompatibilityRating rating);
/// Returns the pixel ratio/scaling factor for a widget.
qreal GetDevicePixelRatioForWidget(const QWidget* widget);
/// Returns the common window info structure for a Qt widget.
std::optional<WindowInfo> GetWindowInfoForWidget(QWidget* widget);
} // namespace QtUtils