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>
22#include <private/quniquehandle_p.h>
24#include <QtGui/qscreen.h>
26#include <QtCore/qdebug.h>
33#include <shellscalingapi.h>
41 return QDpi(GetDeviceCaps(hdc, LOGPIXELSX), GetDeviceCaps(hdc, LOGPIXELSY));
48 if (SUCCEEDED(GetDpiForMonitor(hMonitor, MDT_EFFECTIVE_DPI, &dpiX, &dpiY)))
49 return QDpi(dpiX, dpiY);
53static std::vector<DISPLAYCONFIG_PATH_INFO>
getPathInfo(
const MONITORINFOEX &viewInfo)
56 std::vector<DISPLAYCONFIG_PATH_INFO> pathInfos;
57 std::vector<DISPLAYCONFIG_MODE_INFO> modeInfos;
61 UINT32 numPathArrayElements;
62 UINT32 numModeInfoArrayElements;
67 if (GetDisplayConfigBufferSizes(QDC_ONLY_ACTIVE_PATHS, &numPathArrayElements,
68 &numModeInfoArrayElements) != ERROR_SUCCESS) {
71 pathInfos.resize(numPathArrayElements);
72 modeInfos.resize(numModeInfoArrayElements);
73 result = QueryDisplayConfig(QDC_ONLY_ACTIVE_PATHS, &numPathArrayElements, pathInfos.data(),
74 &numModeInfoArrayElements, modeInfos.data(),
nullptr);
75 }
while (
result == ERROR_INSUFFICIENT_BUFFER);
77 if (
result != ERROR_SUCCESS)
82 std::remove_if(pathInfos.begin(), pathInfos.end(), [&](
const auto &
path) ->
bool {
83 DISPLAYCONFIG_SOURCE_DEVICE_NAME deviceName;
84 deviceName.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME;
85 deviceName.header.size = sizeof(DISPLAYCONFIG_SOURCE_DEVICE_NAME);
86 deviceName.header.adapterId = path.sourceInfo.adapterId;
87 deviceName.header.id = path.sourceInfo.id;
88 if (DisplayConfigGetDeviceInfo(&deviceName.header) == ERROR_SUCCESS) {
89 return wcscmp(viewInfo.szDevice, deviceName.viewGdiDeviceName) != 0;
94 pathInfos.erase(discardThese, pathInfos.end());
101static float getMonitorSDRWhiteLevel(DISPLAYCONFIG_PATH_TARGET_INFO *targetInfo)
103 const float defaultSdrWhiteLevel = 200.0;
105 return defaultSdrWhiteLevel;
107 DISPLAYCONFIG_SDR_WHITE_LEVEL whiteLevel = {};
108 whiteLevel.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_SDR_WHITE_LEVEL;
109 whiteLevel.header.size =
sizeof(DISPLAYCONFIG_SDR_WHITE_LEVEL);
110 whiteLevel.header.adapterId = targetInfo->adapterId;
111 whiteLevel.header.id = targetInfo->id;
112 if (DisplayConfigGetDeviceInfo(&whiteLevel.header) != ERROR_SUCCESS)
113 return defaultSdrWhiteLevel;
114 return whiteLevel.SDRWhiteLevel * 80.0 / 1000.0;
122struct DiRegKeyHandleTraits
125 static Type invalidValue()
128 return reinterpret_cast<HKEY
>(INVALID_HANDLE_VALUE);
130 static bool close(
Type handle) {
return RegCloseKey(
handle) == ERROR_SUCCESS; }
133using DiRegKeyHandle = QUniqueHandle<DiRegKeyHandleTraits>;
138 const std::vector<DISPLAYCONFIG_PATH_INFO> &pathGroup)
140 if (pathGroup.empty()) {
146 DISPLAYCONFIG_TARGET_DEVICE_NAME deviceName = {};
147 deviceName.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME;
148 deviceName.header.
size =
sizeof(DISPLAYCONFIG_TARGET_DEVICE_NAME);
150 deviceName.header.adapterId = pathGroup[0].targetInfo.adapterId;
151 deviceName.header.id = pathGroup[0].targetInfo.id;
152 if (DisplayConfigGetDeviceInfo(&deviceName.header) == ERROR_SUCCESS) {
156 << u
"Unable to get device information for %1:"_s.arg(pathGroup[0].targetInfo.id)
157 << QSystemError::windowsString();
167 for (
const auto &
path : pathGroup) {
168 DISPLAYCONFIG_TARGET_DEVICE_NAME deviceName = {};
169 deviceName.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME;
170 deviceName.header.
size =
sizeof(DISPLAYCONFIG_TARGET_DEVICE_NAME);
171 deviceName.header.adapterId =
path.targetInfo.adapterId;
172 deviceName.header.id =
path.targetInfo.id;
173 if (DisplayConfigGetDeviceInfo(&deviceName.header) != ERROR_SUCCESS) {
175 << u
"Unable to get device information for %1:"_s.arg(
path.targetInfo.id)
176 << QSystemError::windowsString();
181 constexpr GUID GUID_DEVINTERFACE_MONITOR = {
182 0xe6f07b5f, 0xee97, 0x4a90, { 0xb0, 0x76, 0x33, 0xf5, 0x7b, 0xf4, 0xea, 0xa7 }
184 const HDEVINFO devInfo = SetupDiGetClassDevs(&GUID_DEVINTERFACE_MONITOR,
nullptr,
nullptr,
185 DIGCF_DEVICEINTERFACE);
187 SP_DEVICE_INTERFACE_DATA deviceInterfaceData{};
188 deviceInterfaceData.cbSize =
sizeof(deviceInterfaceData);
190 if (!SetupDiOpenDeviceInterfaceW(devInfo, deviceName.monitorDevicePath, DIODI_NO_ADD,
191 &deviceInterfaceData)) {
193 << u
"Unable to open monitor interface to %1:"_s.arg(
data.deviceName)
194 << QSystemError::windowsString();
198 DWORD requiredSize{ 0 };
199 if (SetupDiGetDeviceInterfaceDetailW(devInfo, &deviceInterfaceData,
nullptr, 0,
200 &requiredSize,
nullptr)
201 || GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
205 const std::unique_ptr<std::byte[]>
storage(
new std::byte[requiredSize]);
206 auto *devicePath =
reinterpret_cast<SP_DEVICE_INTERFACE_DETAIL_DATA_W *
>(
storage.get());
207 devicePath->cbSize =
sizeof(std::remove_pointer_t<
decltype(devicePath)>);
208 SP_DEVINFO_DATA deviceInfoData{};
209 deviceInfoData.cbSize =
sizeof(deviceInfoData);
210 if (!SetupDiGetDeviceInterfaceDetailW(devInfo, &deviceInterfaceData, devicePath,
211 requiredSize,
nullptr, &deviceInfoData)) {
212 qCDebug(lcQpaScreen) << u
"Unable to get monitor metadata for %1:"_s.arg(
data.deviceName)
213 << QSystemError::windowsString();
217 const DiRegKeyHandle edidRegistryKey{ SetupDiOpenDevRegKey(
218 devInfo, &deviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_READ) };
220 if (!edidRegistryKey.isValid())
223 DWORD edidDataSize{ 0 };
224 if (RegQueryValueExW(edidRegistryKey.get(), L
"EDID",
nullptr,
nullptr,
nullptr,
231 edidData.
resize(edidDataSize);
233 if (RegQueryValueExW(edidRegistryKey.get(), L
"EDID",
nullptr,
nullptr,
234 reinterpret_cast<unsigned char *
>(edidData.data()), &edidDataSize)
236 qCDebug(lcQpaScreen) << u
"Unable to get EDID from the Registry for %1:"_s.arg(
238 << QSystemError::windowsString();
244 if (!edid.parse(edidData)) {
245 qCDebug(lcQpaScreen) <<
"Invalid EDID blob for" <<
data.deviceName;
252 manufacturers << edid.manufacturer;
253 models << edid.model;
254 serialNumbers << edid.serialNumber;
258 data.manufacturer = manufacturers.join(u
"|"_s);
259 data.model = models.join(u
"|"_s);
260 data.serialNumber = serialNumbers.join(u
"|"_s);
266 memset(&
info, 0,
sizeof(MONITORINFOEX));
267 info.cbSize =
sizeof(MONITORINFOEX);
268 if (GetMonitorInfo(hMonitor, &
info) == FALSE)
271 data->hMonitor = hMonitor;
276 if (!pathGroup.empty()) {
279 if (
data->name.isEmpty())
281 if (
data->deviceName == u
"WinDisc") {
284 if (
const HDC hdc = CreateDC(
info.szDevice,
nullptr,
nullptr,
nullptr)) {
287 data->depth = GetDeviceCaps(hdc, BITSPIXEL);
289 data->physicalSizeMM =
QSizeF(GetDeviceCaps(hdc, HORZSIZE), GetDeviceCaps(hdc, VERTSIZE));
290 const int refreshRate = GetDeviceCaps(hdc, VREFRESH);
292 data->refreshRateHz = refreshRate;
295 qWarning(
"%s: Unable to obtain handle for monitor '%s', defaulting to %g DPI.",
303 if (!pathGroup.empty()) {
305 const auto &pathInfo = pathGroup[0];
306 switch (pathInfo.targetInfo.rotation) {
307 case DISPLAYCONFIG_ROTATION_IDENTITY:
310 case DISPLAYCONFIG_ROTATION_ROTATE90:
313 case DISPLAYCONFIG_ROTATION_ROTATE180:
316 case DISPLAYCONFIG_ROTATION_ROTATE270:
319 case DISPLAYCONFIG_ROTATION_FORCE_UINT32:
323 if (pathInfo.targetInfo.refreshRate.Numerator && pathInfo.targetInfo.refreshRate.Denominator)
324 data->refreshRateHz =
static_cast<qreal>(pathInfo.targetInfo.refreshRate.Numerator)
325 / pathInfo.targetInfo.refreshRate.Denominator;
327 data->orientation =
data->geometry.height() >
data->geometry.width()
334 if (
info.dwFlags & MONITORINFOF_PRIMARY)
348 int previousIndex = 1;
349 if (
it->deviceIndex.has_value())
350 previousIndex =
it->deviceIndex.value();
352 (*it).deviceIndex = 1;
353 data.deviceIndex = previousIndex + 1;
375#ifndef QT_NO_DEBUG_STREAM
381 dbg <<
"Screen \"" <<
d.name <<
"\" " <<
d.geometry.width() <<
'x' <<
d.geometry.height() <<
'+'
382 <<
d.geometry.x() <<
'+' <<
d.geometry.y() <<
" avail: " <<
d.availableGeometry.width()
383 <<
'x' <<
d.availableGeometry.height() <<
'+' <<
d.availableGeometry.x() <<
'+'
384 <<
d.availableGeometry.y() <<
" physical: " <<
d.physicalSizeMM.width() <<
'x'
385 <<
d.physicalSizeMM.height() <<
" DPI: " <<
d.dpi.first <<
'x' <<
d.dpi.second
386 <<
" Depth: " <<
d.depth <<
" Format: " <<
d.format <<
" hMonitor: " <<
d.hMonitor
387 <<
" device name: " <<
d.deviceName <<
" manufacturer: " <<
d.manufacturer
388 <<
" model: " <<
d.model <<
" serial number: " <<
d.serialNumber;
392 dbg <<
" virtual desktop";
394 dbg <<
" lock screen";
426 HWND hwnd =
reinterpret_cast<HWND
>(
window);
429 GetClientRect(hwnd, &
r);
430 windowSize =
QSize(
r.right -
r.left,
r.bottom -
r.top);
434 hwnd = GetDesktopWindow();
436 windowSize = screenGeometry.
size();
437 x += screenGeometry.
x();
438 y += screenGeometry.
y();
447 HDC display_dc = GetDC(
nullptr);
448 HDC bitmap_dc = CreateCompatibleDC(display_dc);
450 HGDIOBJ null_bitmap = SelectObject(bitmap_dc,
bitmap);
453 HDC window_dc = GetDC(hwnd);
454 BitBlt(bitmap_dc, 0, 0,
width,
height, window_dc,
x,
y, SRCCOPY | CAPTUREBLT);
457 ReleaseDC(hwnd, window_dc);
458 SelectObject(bitmap_dc, null_bitmap);
464 ReleaseDC(
nullptr, display_dc);
487 findPlatformWindowAt(GetDesktopWindow(), screenPoint,
flags))
490 qCDebug(lcQpaScreen) <<__FUNCTION__ << screenPoint <<
" returns " <<
result;
503 QList<QPlatformScreen *>
result;
527 <<
"has had its hMonitor handle changed from"
553 if (orientationChanged)
555 if (geometryChanged) {
573 result |= sibling->geometry();
607 case ORIENTATION_PREFERENCE_NONE:
609 case ORIENTATION_PREFERENCE_LANDSCAPE:
612 case ORIENTATION_PREFERENCE_PORTRAIT:
615 case ORIENTATION_PREFERENCE_LANDSCAPE_FLIPPED:
618 case ORIENTATION_PREFERENCE_PORTRAIT_FLIPPED:
633 QSettings settings(R
"(HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Avalon.Graphics\DISPLAY1)"_L1,
636 switch (registryValue) {
667 if (
message == WM_DISPLAYCHANGE) {
668 qCDebug(lcQpaScreen) <<
"Handling WM_DISPLAYCHANGE";
673 context->screenManager().handleScreenChanges();
676 return DefWindowProc(hwnd,
message, wParam, lParam);
683 qCDebug(lcQpaScreen) <<
"Initializing screen manager";
691 m_displayChangeObserver = CreateWindowEx(0,
reinterpret_cast<LPCWSTR
>(
className.utf16()),
692 nullptr, WS_TILED, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
693 nullptr,
nullptr, GetModuleHandle(
nullptr),
nullptr);
696 qCDebug(lcQpaScreen) <<
"Created display change observer" << m_displayChangeObserver;
703 qCDebug(lcQpaScreen) <<
"Destroying display change observer" << m_displayChangeObserver;
704 DestroyWindow(m_displayChangeObserver);
705 m_displayChangeObserver =
nullptr;
718 for (
int i= 0;
i < screens.
size(); ++
i)
719 if (screens.
at(
i)->data().deviceName == deviceName)
727 for (
int i = 0;
i < screenData.size(); ++
i)
728 if (screenData.at(
i).deviceName == deviceName)
736 QRect geometry =
w->geometry();
737 const QRect oldScreenGeometry =
w->screen()->geometry();
738 const QRect newScreenGeometry = newScreen->geometry();
739 QPoint relativePosition = geometry.
topLeft() - oldScreenGeometry.topLeft();
740 if (oldScreenGeometry.size() != newScreenGeometry.size()) {
744 relativePosition = (
QPointF(relativePosition) * factor).toPoint();
747 w->setGeometry(geometry);
750void QWindowsScreenManager::removeScreen(
int index)
752 qCDebug(lcQpaScreen) <<
"Removing Monitor:" << m_screens.
at(
index)->data();
762 if (
screen != primaryScreen) {
763 unsigned movedWindowCount = 0;
776 if (movedWindowCount)
792 bool primaryScreenChanged =
false;
794 const int existingIndex =
indexOfMonitor(m_screens, newData.deviceName);
795 if (existingIndex != -1) {
796 m_screens.
at(existingIndex)->handleChanges(newData);
797 if (existingIndex == 0)
798 primaryScreenChanged =
true;
804 qCDebug(lcQpaScreen) <<
"New Monitor: " << newData;
810 for (
int i = m_screens.
size() - 1;
i >= 0; --
i) {
815 if (primaryScreenChanged) {
817 theme->refreshFonts();
832 if (scr->geometry().contains(
p))
840 HMONITOR hMonitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONULL);
841 if (hMonitor ==
nullptr)
844 std::find_if(m_screens.
cbegin(), m_screens.
cend(),
847 return s->data().hMonitor == hMonitor
848 && (s->data().flags & QWindowsScreenData::VirtualDesktop) != 0;
850 return it != m_screens.
cend() ? *
it :
nullptr;
void resize(qsizetype size)
Sets the size of the byte array to size bytes.
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 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 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.
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 noexcept
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 handlePrimaryScreenChanged(QPlatformScreen *newPrimary)
Should be called whenever the primary screen changes.
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)
static QString classNamePrefix()
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
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
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLuint GLsizei const GLchar * message
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()
QList< QWindowsScreenData > WindowsScreenDataList
static std::vector< DISPLAYCONFIG_PATH_INFO > getPathInfo(const MONITORINFOEX &viewInfo)
static void moveToVirtualScreen(QWindow *w, const QScreen *newScreen)
static void setMonitorDataFromSetupApi(QWindowsScreenData &data, const std::vector< DISPLAYCONFIG_PATH_INFO > &pathGroup)
static int indexOfMonitor(const QWindowsScreenManager::WindowsScreenList &screens, const QString &deviceName)
static QDpi monitorDPI(HMONITOR hMonitor)
const char className[16]
[1]
QSettings settings("MySoft", "Star Runner")
[0]
Qt::ScreenOrientation orientation
std::optional< int > deviceIndex