11#include <QtCore/qt_windows.h>
13#include <QtCore/qsettings.h>
14#include <QtGui/qpixmap.h>
15#include <QtGui/qguiapplication.h>
16#include <qpa/qwindowsysteminterface.h>
17#include <QtCore/private/qsystemerror_p.h>
18#include <QtGui/private/qedidparser_p.h>
19#include <private/qhighdpiscaling_p.h>
20#include <private/qwindowsfontdatabasebase_p.h>
21#include <private/qpixmap_win_p.h>
23#include <QtGui/qscreen.h>
25#include <QtCore/qdebug.h>
32#include <shellscalingapi.h>
40 return QDpi(GetDeviceCaps(hdc, LOGPIXELSX), GetDeviceCaps(hdc, LOGPIXELSY));
47 if (SUCCEEDED(GetDpiForMonitor(hMonitor, MDT_EFFECTIVE_DPI, &dpiX, &dpiY)))
48 return QDpi(dpiX, dpiY);
52static std::vector<DISPLAYCONFIG_PATH_INFO>
getPathInfo(
const MONITORINFOEX &viewInfo)
55 std::vector<DISPLAYCONFIG_PATH_INFO> pathInfos;
56 std::vector<DISPLAYCONFIG_MODE_INFO> modeInfos;
60 UINT32 numPathArrayElements;
61 UINT32 numModeInfoArrayElements;
66 if (GetDisplayConfigBufferSizes(QDC_ONLY_ACTIVE_PATHS, &numPathArrayElements,
67 &numModeInfoArrayElements) != ERROR_SUCCESS) {
70 pathInfos.resize(numPathArrayElements);
71 modeInfos.resize(numModeInfoArrayElements);
72 result = QueryDisplayConfig(QDC_ONLY_ACTIVE_PATHS, &numPathArrayElements, pathInfos.data(),
73 &numModeInfoArrayElements, modeInfos.data(),
nullptr);
74 }
while (
result == ERROR_INSUFFICIENT_BUFFER);
76 if (
result != ERROR_SUCCESS)
81 std::remove_if(pathInfos.begin(), pathInfos.end(), [&](
const auto &
path) ->
bool {
82 DISPLAYCONFIG_SOURCE_DEVICE_NAME deviceName;
83 deviceName.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME;
84 deviceName.header.size = sizeof(DISPLAYCONFIG_SOURCE_DEVICE_NAME);
85 deviceName.header.adapterId = path.sourceInfo.adapterId;
86 deviceName.header.id = path.sourceInfo.id;
87 if (DisplayConfigGetDeviceInfo(&deviceName.header) == ERROR_SUCCESS) {
88 return wcscmp(viewInfo.szDevice, deviceName.viewGdiDeviceName) != 0;
93 pathInfos.erase(discardThese, pathInfos.end());
100static float getMonitorSDRWhiteLevel(DISPLAYCONFIG_PATH_TARGET_INFO *targetInfo)
102 const float defaultSdrWhiteLevel = 200.0;
104 return defaultSdrWhiteLevel;
106 DISPLAYCONFIG_SDR_WHITE_LEVEL whiteLevel = {};
107 whiteLevel.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_SDR_WHITE_LEVEL;
108 whiteLevel.header.size =
sizeof(DISPLAYCONFIG_SDR_WHITE_LEVEL);
109 whiteLevel.header.adapterId = targetInfo->adapterId;
110 whiteLevel.header.id = targetInfo->id;
111 if (DisplayConfigGetDeviceInfo(&whiteLevel.header) != ERROR_SUCCESS)
112 return defaultSdrWhiteLevel;
113 return whiteLevel.SDRWhiteLevel * 80.0 / 1000.0;
123 if (
handle !=
nullptr &&
handle != INVALID_HANDLE_VALUE)
131 const std::vector<DISPLAYCONFIG_PATH_INFO> &pathGroup)
133 if (pathGroup.empty()) {
139 DISPLAYCONFIG_TARGET_DEVICE_NAME deviceName = {};
140 deviceName.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME;
141 deviceName.header.
size =
sizeof(DISPLAYCONFIG_TARGET_DEVICE_NAME);
143 deviceName.header.adapterId = pathGroup[0].targetInfo.adapterId;
144 deviceName.header.id = pathGroup[0].targetInfo.id;
145 if (DisplayConfigGetDeviceInfo(&deviceName.header) == ERROR_SUCCESS) {
149 << u
"Unable to get device information for %1:"_s.arg(pathGroup[0].targetInfo.id)
150 << QSystemError::windowsString();
160 for (
const auto &
path : pathGroup) {
161 DISPLAYCONFIG_TARGET_DEVICE_NAME deviceName = {};
162 deviceName.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME;
163 deviceName.header.
size =
sizeof(DISPLAYCONFIG_TARGET_DEVICE_NAME);
164 deviceName.header.adapterId =
path.targetInfo.adapterId;
165 deviceName.header.id =
path.targetInfo.id;
166 if (DisplayConfigGetDeviceInfo(&deviceName.header) != ERROR_SUCCESS) {
168 << u
"Unable to get device information for %1:"_s.arg(
path.targetInfo.id)
169 << QSystemError::windowsString();
174 constexpr GUID GUID_DEVINTERFACE_MONITOR = {
175 0xe6f07b5f, 0xee97, 0x4a90, { 0xb0, 0x76, 0x33, 0xf5, 0x7b, 0xf4, 0xea, 0xa7 }
177 const HDEVINFO devInfo = SetupDiGetClassDevs(&GUID_DEVINTERFACE_MONITOR,
nullptr,
nullptr,
178 DIGCF_DEVICEINTERFACE);
180 SP_DEVICE_INTERFACE_DATA deviceInterfaceData{};
181 deviceInterfaceData.cbSize =
sizeof(deviceInterfaceData);
183 if (!SetupDiOpenDeviceInterfaceW(devInfo, deviceName.monitorDevicePath, DIODI_NO_ADD,
184 &deviceInterfaceData)) {
186 << u
"Unable to open monitor interface to %1:"_s.arg(
data.deviceName)
187 << QSystemError::windowsString();
191 DWORD requiredSize{ 0 };
192 if (SetupDiGetDeviceInterfaceDetailW(devInfo, &deviceInterfaceData,
nullptr, 0,
193 &requiredSize,
nullptr)
194 || GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
198 const std::unique_ptr<std::byte[]>
storage(
new std::byte[requiredSize]);
199 auto *devicePath =
reinterpret_cast<SP_DEVICE_INTERFACE_DETAIL_DATA_W *
>(
storage.get());
200 devicePath->cbSize =
sizeof(std::remove_pointer_t<
decltype(devicePath)>);
201 SP_DEVINFO_DATA deviceInfoData{};
202 deviceInfoData.cbSize =
sizeof(deviceInfoData);
203 if (!SetupDiGetDeviceInterfaceDetailW(devInfo, &deviceInterfaceData, devicePath,
204 requiredSize,
nullptr, &deviceInfoData)) {
205 qCDebug(lcQpaScreen) << u
"Unable to get monitor metadata for %1:"_s.arg(
data.deviceName)
206 << QSystemError::windowsString();
211 devInfo, &deviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_READ) };
213 if (!edidRegistryKey || edidRegistryKey.get() == INVALID_HANDLE_VALUE)
216 DWORD edidDataSize{ 0 };
217 if (RegQueryValueExW(edidRegistryKey.get(), L
"EDID",
nullptr,
nullptr,
nullptr,
224 edidData.
resize(edidDataSize);
226 if (RegQueryValueExW(edidRegistryKey.get(), L
"EDID",
nullptr,
nullptr,
227 reinterpret_cast<unsigned char *
>(edidData.
data()), &edidDataSize)
229 qCDebug(lcQpaScreen) << u
"Unable to get EDID from the Registry for %1:"_s.arg(
231 << QSystemError::windowsString();
237 if (!edid.
parse(edidData)) {
238 qCDebug(lcQpaScreen) <<
"Invalid EDID blob for" <<
data.deviceName;
246 models << edid.
model;
251 data.manufacturer = manufacturers.join(u
"|"_s);
252 data.model = models.join(u
"|"_s);
253 data.serialNumber = serialNumbers.join(u
"|"_s);
259 memset(&
info, 0,
sizeof(MONITORINFOEX));
260 info.cbSize =
sizeof(MONITORINFOEX);
261 if (GetMonitorInfo(hMonitor, &
info) == FALSE)
264 data->hMonitor = hMonitor;
269 if (!pathGroup.empty()) {
272 if (
data->name.isEmpty())
274 if (
data->deviceName == u
"WinDisc") {
277 if (
const HDC hdc = CreateDC(
info.szDevice,
nullptr,
nullptr,
nullptr)) {
280 data->depth = GetDeviceCaps(hdc, BITSPIXEL);
282 data->physicalSizeMM =
QSizeF(GetDeviceCaps(hdc, HORZSIZE), GetDeviceCaps(hdc, VERTSIZE));
283 const int refreshRate = GetDeviceCaps(hdc, VREFRESH);
285 data->refreshRateHz = refreshRate;
288 qWarning(
"%s: Unable to obtain handle for monitor '%s', defaulting to %g DPI.",
296 if (!pathGroup.empty()) {
298 const auto &pathInfo = pathGroup[0];
299 switch (pathInfo.targetInfo.rotation) {
300 case DISPLAYCONFIG_ROTATION_IDENTITY:
303 case DISPLAYCONFIG_ROTATION_ROTATE90:
306 case DISPLAYCONFIG_ROTATION_ROTATE180:
309 case DISPLAYCONFIG_ROTATION_ROTATE270:
312 case DISPLAYCONFIG_ROTATION_FORCE_UINT32:
316 if (pathInfo.targetInfo.refreshRate.Numerator && pathInfo.targetInfo.refreshRate.Denominator)
317 data->refreshRateHz =
static_cast<qreal>(pathInfo.targetInfo.refreshRate.Numerator)
318 / pathInfo.targetInfo.refreshRate.Denominator;
320 data->orientation =
data->geometry.height() >
data->geometry.width()
327 if (
info.dwFlags & MONITORINFOF_PRIMARY)
341 int previousIndex = 1;
342 if (
it->deviceIndex.has_value())
343 previousIndex =
it->deviceIndex.value();
345 (*it).deviceIndex = 1;
346 data.deviceIndex = previousIndex + 1;
368#ifndef QT_NO_DEBUG_STREAM
374 dbg <<
"Screen \"" <<
d.name <<
"\" " <<
d.geometry.width() <<
'x' <<
d.geometry.height() <<
'+'
375 <<
d.geometry.x() <<
'+' <<
d.geometry.y() <<
" avail: " <<
d.availableGeometry.width()
376 <<
'x' <<
d.availableGeometry.height() <<
'+' <<
d.availableGeometry.x() <<
'+'
377 <<
d.availableGeometry.y() <<
" physical: " <<
d.physicalSizeMM.width() <<
'x'
378 <<
d.physicalSizeMM.height() <<
" DPI: " <<
d.dpi.first <<
'x' <<
d.dpi.second
379 <<
" Depth: " <<
d.depth <<
" Format: " <<
d.format <<
" hMonitor: " <<
d.hMonitor
380 <<
" device name: " <<
d.deviceName <<
" manufacturer: " <<
d.manufacturer
381 <<
" model: " <<
d.model <<
" serial number: " <<
d.serialNumber;
385 dbg <<
" virtual desktop";
387 dbg <<
" lock screen";
419 HWND hwnd =
reinterpret_cast<HWND
>(
window);
422 GetClientRect(hwnd, &
r);
423 windowSize =
QSize(
r.right -
r.left,
r.bottom -
r.top);
427 hwnd = GetDesktopWindow();
429 windowSize = screenGeometry.
size();
430 x += screenGeometry.
x();
431 y += screenGeometry.
y();
440 HDC display_dc = GetDC(
nullptr);
441 HDC bitmap_dc = CreateCompatibleDC(display_dc);
443 HGDIOBJ null_bitmap = SelectObject(bitmap_dc,
bitmap);
446 HDC window_dc = GetDC(hwnd);
447 BitBlt(bitmap_dc, 0, 0,
width,
height, window_dc,
x,
y, SRCCOPY | CAPTUREBLT);
450 ReleaseDC(hwnd, window_dc);
451 SelectObject(bitmap_dc, null_bitmap);
457 ReleaseDC(
nullptr, display_dc);
480 findPlatformWindowAt(GetDesktopWindow(), screenPoint,
flags))
483 qCDebug(lcQpaScreen) <<__FUNCTION__ << screenPoint <<
" returns " <<
result;
520 <<
"has had its hMonitor handle changed from"
542 if (orientationChanged)
544 if (geometryChanged) {
560 result |= sibling->geometry();
594 case ORIENTATION_PREFERENCE_NONE:
596 case ORIENTATION_PREFERENCE_LANDSCAPE:
599 case ORIENTATION_PREFERENCE_PORTRAIT:
602 case ORIENTATION_PREFERENCE_LANDSCAPE_FLIPPED:
605 case ORIENTATION_PREFERENCE_PORTRAIT_FLIPPED:
620 QSettings settings(R
"(HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Avalon.Graphics\DISPLAY1)"_L1,
623 switch (registryValue) {
654 if (
message == WM_DISPLAYCHANGE) {
655 qCDebug(lcQpaScreen) <<
"Handling WM_DISPLAYCHANGE";
662 return DefWindowProc(hwnd,
message, wParam, lParam);
669 qCDebug(lcQpaScreen) <<
"Initializing screen manager";
677 m_displayChangeObserver = CreateWindowEx(0,
reinterpret_cast<LPCWSTR
>(
className.utf16()),
678 nullptr, WS_TILED, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
679 nullptr,
nullptr, GetModuleHandle(
nullptr),
nullptr);
682 qCDebug(lcQpaScreen) <<
"Created display change observer" << m_displayChangeObserver;
689 DestroyWindow(m_displayChangeObserver);
700 for (
int i = 0;
i < screens.
size(); ++
i)
701 if (screens.
at(
i)->data().serialNumber == serialNumberIn)
709 for (
int i = 0;
i < screenData.
size(); ++
i)
710 if (screenData.
at(
i).serialNumber == serialNumberIn)
718 QRect geometry =
w->geometry();
719 const QRect oldScreenGeometry =
w->screen()->geometry();
722 if (oldScreenGeometry.
size() != newScreenGeometry.
size()) {
726 relativePosition = (
QPointF(relativePosition) * factor).toPoint();
729 w->setGeometry(geometry);
732void QWindowsScreenManager::removeScreen(
int index)
734 qCDebug(lcQpaScreen) <<
"Removing Monitor:" << m_screens.
at(
index)->data();
744 if (
screen != primaryScreen) {
745 unsigned movedWindowCount = 0;
758 if (movedWindowCount)
774 bool primaryScreenChanged =
false;
776 const int existingIndex =
indexOfMonitor(m_screens, newData.serialNumber);
777 if (existingIndex != -1) {
778 m_screens.
at(existingIndex)->handleChanges(newData);
779 if (existingIndex == 0)
780 primaryScreenChanged =
true;
786 qCDebug(lcQpaScreen) <<
"New Monitor: " << newData;
792 for (
int i = m_screens.
size() - 1;
i >= 0; --
i) {
797 if (primaryScreenChanged) {
799 theme->refreshFonts();
814 if (scr->geometry().contains(
p))
822 HMONITOR hMonitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONULL);
823 if (hMonitor ==
nullptr)
826 std::find_if(m_screens.
cbegin(), m_screens.
cend(),
829 return s->data().hMonitor == hMonitor
830 && (s->data().flags & QWindowsScreenData::VirtualDesktop) != 0;
832 return it != m_screens.
cend() ? *
it :
nullptr;
char * data()
\macro QT_NO_CAST_FROM_BYTEARRAY
void resize(qsizetype size)
Sets the size of the byte array to size bytes.
bool parse(const QByteArray &blob)
static QWindowList topLevelWindows()
Returns a list of the top-level windows in the application.
QScreen * primaryScreen
the primary (or default) screen of the application.
qsizetype size() const noexcept
bool isEmpty() const noexcept
void push_back(parameter_type t)
const_reference at(qsizetype i) const noexcept
const_iterator cend() const noexcept
const_iterator cbegin() const noexcept
Returns a copy of the pixmap that is transformed using the given transformation transform and transfo...
\inmodule QtCore\reentrant
\inmodule QtCore\reentrant
constexpr int manhattanLength() const
Returns the sum of the absolute values of x() and y(), traditionally known as the "Manhattan length" ...
\inmodule QtCore\reentrant
constexpr void moveTopLeft(const QPoint &p) noexcept
Moves the rectangle, leaving the top-left corner at the given position.
constexpr int height() const noexcept
Returns the height of the rectangle.
constexpr QPoint topLeft() const noexcept
Returns the position of the rectangle's top-left corner.
constexpr int x() const noexcept
Returns the x-coordinate of the rectangle's left edge.
constexpr QSize size() const noexcept
Returns the size of the rectangle.
constexpr int width() const noexcept
Returns the width of the rectangle.
constexpr int y() const noexcept
Returns the y-coordinate of the rectangle's top edge.
The QScreen class is used to query screen properties. \inmodule QtGui.
QList< QScreen * > virtualSiblings() const
Get the screen's virtual siblings.
QRect geometry
the screen's geometry in pixels
QPlatformScreen * handle() const
Get the platform screen handle.
QVariant value(QAnyStringView key, const QVariant &defaultValue) const
Returns the value for setting key.
constexpr int height() const noexcept
Returns the height.
constexpr int width() const noexcept
Returns the width.
\macro QT_RESTRICTED_CAST_FROM_ASCII
qsizetype size() const
Returns the number of characters in this string.
static QString fromWCharArray(const wchar_t *string, qsizetype size=-1)
static QString number(int, int base=10)
This is an overloaded member function, provided for convenience. It differs from the above function o...
int toInt(bool *ok=nullptr) const
Returns the variant as an int if the variant has userType() \l QMetaType::Int, \l QMetaType::Bool,...
static bool flushWindowSystemEvents(QEventLoop::ProcessEventsFlags flags=QEventLoop::AllEvents)
Make Qt Gui process all events on the event queue immediately.
static void handleWindowScreenChanged(QWindow *window, QScreen *newScreen)
static void handleScreenGeometryChange(QScreen *screen, const QRect &newGeometry, const QRect &newAvailableGeometry)
static void handleScreenAdded(QPlatformScreen *screen, bool isPrimary=false)
Should be called by the implementation whenever a new screen is added.
static void handleScreenRemoved(QPlatformScreen *screen)
Should be called by the implementation whenever a screen is removed.
static void handleScreenOrientationChange(QScreen *screen, Qt::ScreenOrientation newOrientation)
static void handleScreenLogicalDotsPerInchChange(QScreen *screen, qreal newDpiX, qreal newDpiY)
static QWindowsBaseWindow * baseWindowOf(const QWindow *w)
QWindowsScreenManager & screenManager()
static QString classNamePrefix()
QString registerWindowClass(const QWindow *w)
static QWindowsContext * instance()
Platform cursor implementation.
bool handleScreenChanges()
Synchronizes the screen list, adds new screens, removes deleted ones and propagates resolution change...
const QWindowsScreen * screenForHwnd(HWND hwnd) const
const QWindowsScreen * screenAtDp(const QPoint &p) const
const WindowsScreenList & screens() const
static bool isSingleScreen()
static QWindow * windowAt(const QPoint &point, unsigned flags)
QList< QPlatformScreen * > virtualSiblings() const override
Determine siblings in a virtual desktop system.
QWindowsScreen(const QWindowsScreenData &data)
QPixmap grabWindow(WId window, int qX, int qY, int qWidth, int qHeight) const override
This function is called when Qt needs to be able to grab the content of a window.
QRect geometry() const override
Reimplement in subclass to return the pixel geometry of the screen.
QPlatformScreen::SubpixelAntialiasingType subpixelAntialiasingTypeHint() const override
Queries ClearType settings to check the pixel layout.
void handleChanges(const QWindowsScreenData &newData)
Notify QWindowSystemInterface about changes of a screen and synchronize data.
static bool setOrientationPreference(Qt::ScreenOrientation o)
static QRect virtualGeometry(const QPlatformScreen *screen)
QString name() const override
QWindow * topLevelAt(const QPoint &point) const override
Find a top level window taking the flags of ChildWindowFromPointEx.
HMONITOR handle() const override
static Qt::ScreenOrientation orientationPreference()
static QWindowsTheme * instance()
static void displayChanged()
static QWindow * topLevelOf(QWindow *w)
QSet< QString >::iterator it
Combined button and popup list for selecting options.
@ InvertedLandscapeOrientation
@ InvertedPortraitOrientation
bool qFuzzyCompare(qfloat16 p1, qfloat16 p2) noexcept
QPair< qreal, qreal > QDpi
#define qCWarning(category,...)
#define qCDebug(category,...)
GLuint64 GLenum void * handle
GLint GLint GLint GLint GLint x
[0]
GLfloat GLfloat GLfloat w
[0]
GLint GLsizei GLsizei height
GLuint GLsizei const GLchar * message
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLsizei GLfixed GLfixed GLfixed GLfixed const GLubyte * bitmap
GLsizei const GLchar *const * path
QPixmap qt_pixmapFromWinHBITMAP(HBITMAP bitmap, int hbitmapFormat)
#define qPrintable(string)
QLatin1StringView QLatin1String
BOOL QT_WIN_CALLBACK monitorEnumCallback(HMONITOR hMonitor, HDC, LPRECT, LPARAM p)
LRESULT QT_WIN_CALLBACK qDisplayChangeObserverWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
static QDebug operator<<(QDebug dbg, const QWindowsScreenData &d)
static QDpi deviceDPI(HDC hdc)
static WindowsScreenDataList monitorData()
static std::vector< DISPLAYCONFIG_PATH_INFO > getPathInfo(const MONITORINFOEX &viewInfo)
static void moveToVirtualScreen(QWindow *w, const QScreen *newScreen)
std::unique_ptr< std::remove_pointer_t< HKEY >, RegistryHandleDeleter > RegistryHandlePtr
static void setMonitorDataFromSetupApi(QWindowsScreenData &data, const std::vector< DISPLAYCONFIG_PATH_INFO > &pathGroup)
static int indexOfMonitor(const QWindowsScreenManager::WindowsScreenList &screens, const QString &serialNumberIn)
static QDpi monitorDPI(HMONITOR hMonitor)
const char className[16]
[1]
QFileInfo info(fileName)
[8]
QSettings settings("MySoft", "Star Runner")
[0]
Qt::ScreenOrientation orientation
std::optional< int > deviceIndex
void operator()(HKEY handle) const noexcept