1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qplatformscreen.h"
5#include <QtCore/qdebug.h>
6#include <QtGui/qguiapplication.h>
7#include <qpa/qplatformcursor.h>
8#include <QtGui/private/qguiapplication_p.h>
9#include <qpa/qplatformscreen_p.h>
10#include <qpa/qplatformintegration.h>
11#include <QtGui/qscreen.h>
12#include <QtGui/qwindow.h>
13#include <private/qhighdpiscaling_p.h>
14#include <private/qwindow_p.h>
15
16QT_BEGIN_NAMESPACE
17
18QPlatformScreen::QPlatformScreen()
19 : d_ptr(new QPlatformScreenPrivate)
20{
21 Q_D(QPlatformScreen);
22 d->screen = nullptr;
23}
24
25QPlatformScreen::~QPlatformScreen()
26{
27 Q_D(QPlatformScreen);
28 Q_ASSERT_X(!d->screen, "QPlatformScreen",
29 "QPlatformScreens should be removed via QWindowSystemInterface::handleScreenRemoved()");
30}
31
32/*!
33 This function is called when Qt needs to be able to grab the content of a window.
34
35 Returns the content of the window specified with the WId handle within the boundaries of
36 QRect(x,y,width,height).
37*/
38QPixmap QPlatformScreen::grabWindow(WId window, int x, int y, int width, int height) const
39{
40 Q_UNUSED(window);
41 Q_UNUSED(x);
42 Q_UNUSED(y);
43 Q_UNUSED(width);
44 Q_UNUSED(height);
45 return QPixmap();
46}
47
48/*!
49 Return the given top level window for a given position.
50
51 Default implementation retrieves a list of all top level windows and finds the first window
52 which contains point \a pos
53*/
54QWindow *QPlatformScreen::topLevelAt(const QPoint & pos) const
55{
56 const QWindowList list = QGuiApplication::topLevelWindows();
57 const auto crend = list.crend();
58 for (auto it = list.crbegin(); it != crend; ++it) {
59 QWindow *w = *it;
60 if (w->isVisible() && QHighDpi::toNativePixels(value: w->geometry(), context: w).contains(p: pos))
61 return w;
62 }
63
64 return nullptr;
65}
66
67/*!
68 Return all windows residing on this screen.
69*/
70QWindowList QPlatformScreen::windows() const
71{
72 QWindowList windows;
73 for (QWindow *window : QGuiApplication::allWindows()) {
74 if (platformScreenForWindow(window) != this)
75 continue;
76 windows.append(t: window);
77 }
78 return windows;
79}
80
81/*!
82 Find the sibling screen corresponding to \a globalPos.
83
84 Returns this screen if no suitable screen is found at the position.
85 */
86const QPlatformScreen *QPlatformScreen::screenForPosition(const QPoint &point) const
87{
88 if (!geometry().contains(p: point)) {
89 const auto screens = virtualSiblings();
90 for (const QPlatformScreen *screen : screens) {
91 if (screen->geometry().contains(p: point))
92 return screen;
93 }
94 }
95 return this;
96}
97
98
99/*!
100 Returns a list of all the platform screens that are part of the same
101 virtual desktop.
102
103 Screens part of the same virtual desktop share a common coordinate system,
104 and windows can be freely moved between them.
105*/
106QList<QPlatformScreen *> QPlatformScreen::virtualSiblings() const
107{
108 QList<QPlatformScreen *> list;
109 list << const_cast<QPlatformScreen *>(this);
110 return list;
111}
112
113QScreen *QPlatformScreen::screen() const
114{
115 Q_D(const QPlatformScreen);
116 return d->screen;
117}
118
119/*!
120 Reimplement this function in subclass to return the physical size of the
121 screen, in millimeters. The physical size represents the actual physical
122 dimensions of the display.
123
124 The default implementation takes the pixel size of the screen, considers a
125 resolution of 100 dots per inch, and returns the calculated physical size.
126 A device with a screen that has different resolutions will need to be
127 supported by a suitable reimplementation of this function.
128
129 \sa logcalDpi
130*/
131QSizeF QPlatformScreen::physicalSize() const
132{
133 static const int dpi = 100;
134 return QSizeF(geometry().size()) / dpi * qreal(25.4);
135}
136
137/*!
138 Reimplement this function in subclass to return the logical horizontal
139 and vertical dots per inch metrics of the screen.
140
141 The logical dots per inch metrics are used by Qt to scale the user interface.
142
143 The default implementation returns logicalBaseDpi(), which results in a
144 UI scale factor of 1.0.
145
146 \sa physicalSize
147*/
148QDpi QPlatformScreen::logicalDpi() const
149{
150 return logicalBaseDpi();
151}
152
153// Helper function for accessing the platform screen logical dpi
154// which accounts for QT_FONT_DPI.
155QPair<qreal, qreal> QPlatformScreen::overrideDpi(const QPair<qreal, qreal> &in)
156{
157 static const int overrideDpi = qEnvironmentVariableIntValue(varName: "QT_FONT_DPI");
158 return overrideDpi > 0 ? QDpi(overrideDpi, overrideDpi) : in;
159}
160
161/*!
162 Reimplement to return the base logical DPI for the platform. This
163 DPI value should correspond to a standard-DPI (1x) display. The
164 default implementation returns 96.
165
166 QtGui will use this value (together with logicalDpi) to compute
167 the scale factor when high-DPI scaling is enabled, as follows:
168 factor = logicalDPI / baseDPI
169*/
170QDpi QPlatformScreen::logicalBaseDpi() const
171{
172 return QDpi(96, 96);
173}
174
175/*!
176 Reimplement this function in subclass to return the device pixel ratio
177 for the screen. This is the ratio between physical pixels and the
178 device-independent pixels of the windowing system. The default
179 implementation returns 1.0.
180
181 \sa QPlatformWindow::devicePixelRatio()
182*/
183qreal QPlatformScreen::devicePixelRatio() const
184{
185 return 1.0;
186}
187
188/*!
189 Reimplement this function in subclass to return the vertical refresh rate
190 of the screen, in Hz.
191
192 The default returns 60, a sensible default for modern displays.
193*/
194qreal QPlatformScreen::refreshRate() const
195{
196 return 60;
197}
198
199/*!
200 Reimplement this function in subclass to return the native orientation
201 of the screen, e.g. the orientation where the logo sticker of the device
202 appears the right way up.
203
204 The default implementation returns Qt::PrimaryOrientation.
205*/
206Qt::ScreenOrientation QPlatformScreen::nativeOrientation() const
207{
208 return Qt::PrimaryOrientation;
209}
210
211/*!
212 Reimplement this function in subclass to return the current orientation
213 of the screen, for example based on accelerometer data to determine
214 the device orientation.
215
216 The default implementation returns Qt::PrimaryOrientation.
217*/
218Qt::ScreenOrientation QPlatformScreen::orientation() const
219{
220 return Qt::PrimaryOrientation;
221}
222
223QPlatformScreen * QPlatformScreen::platformScreenForWindow(const QWindow *window)
224{
225 // QTBUG 32681: It can happen during the transition between screens
226 // when one screen is disconnected that the window doesn't have a screen.
227 if (!window->screen())
228 return nullptr;
229 return window->screen()->handle();
230}
231
232/*!
233 Reimplement this function in subclass to return the manufacturer
234 of this screen.
235
236 The default implementation returns an empty string.
237
238 \since 5.9
239*/
240QString QPlatformScreen::manufacturer() const
241{
242 return QString();
243}
244
245/*!
246 Reimplement this function in subclass to return the model
247 of this screen.
248
249 The default implementation returns an empty string.
250
251 \since 5.9
252*/
253QString QPlatformScreen::model() const
254{
255 return QString();
256}
257
258/*!
259 Reimplement this function in subclass to return the serial number
260 of this screen.
261
262 The default implementation returns an empty string.
263
264 \since 5.9
265*/
266QString QPlatformScreen::serialNumber() const
267{
268 return QString();
269}
270
271/*!
272 \class QPlatformScreen
273 \since 4.8
274 \internal
275 \preliminary
276 \ingroup qpa
277
278 \brief The QPlatformScreen class provides an abstraction for visual displays.
279
280 Many window systems has support for retrieving information on the attached displays. To be able
281 to query the display QPA uses QPlatformScreen. Qt its self is most dependent on the
282 physicalSize() function, since this is the function it uses to calculate the dpi to use when
283 converting point sizes to pixels sizes. However, this is unfortunate on some systems, as the
284 native system fakes its dpi size.
285 */
286
287/*! \fn QRect QPlatformScreen::geometry() const = 0
288 Reimplement in subclass to return the pixel geometry of the screen
289*/
290
291/*! \fn QRect QPlatformScreen::availableGeometry() const
292 Reimplement in subclass to return the pixel geometry of the available space
293 This normally is the desktop screen minus the task manager, global menubar etc.
294*/
295
296/*! \fn int QPlatformScreen::depth() const = 0
297 Reimplement in subclass to return current depth of the screen
298*/
299
300/*! \fn QImage::Format QPlatformScreen::format() const = 0
301 Reimplement in subclass to return the image format which corresponds to the screen format
302*/
303
304/*!
305 Reimplement this function in subclass to return the cursor of the screen.
306
307 The default implementation returns \nullptr.
308*/
309QPlatformCursor *QPlatformScreen::cursor() const
310{
311 return nullptr;
312}
313
314/*!
315 Convenience method to resize all the maximized and fullscreen windows
316 of this platform screen.
317*/
318void QPlatformScreen::resizeMaximizedWindows()
319{
320 // 'screen()' still has the old geometry (in device independent pixels),
321 // while 'this' has the new geometry (in native pixels)
322 const QRect oldGeometry = screen()->geometry();
323 const QRect oldAvailableGeometry = screen()->availableGeometry();
324 const QRect newNativeGeometry = this->geometry();
325 const QRect newNativeAvailableGeometry = this->availableGeometry();
326
327 const bool supportsMaximizeUsingFullscreen = QGuiApplicationPrivate::platformIntegration()->hasCapability(cap: QPlatformIntegration::MaximizeUsingFullscreenGeometry);
328
329 for (QWindow *w : windows()) {
330 // Skip non-platform windows, e.g., offscreen windows.
331 if (!w->handle())
332 continue;
333
334 // Set QPlatformWindow size in native pixels, and let the platform's geometry
335 // change signals update the QWindow geomeyry. This way we make sure that the
336 // platform window geometry covers the entire (available) platform screen geometry,
337 // also when fractional DPRs introduce rounding errors in the device independent
338 // QWindow and QScreen sizes.
339 if (supportsMaximizeUsingFullscreen
340 && w->windowState() & Qt::WindowMaximized
341 && w->flags() & Qt::MaximizeUsingFullscreenGeometryHint) {
342 w->handle()->setGeometry(newNativeGeometry);
343 } else if (w->windowState() & Qt::WindowMaximized || w->geometry() == oldAvailableGeometry) {
344 w->handle()->setGeometry(newNativeAvailableGeometry);
345 } else if (w->windowState() & Qt::WindowFullScreen || w->geometry() == oldGeometry) {
346 w->handle()->setGeometry(newNativeGeometry);
347 }
348 }
349}
350
351// i must be power of two
352static int log2(uint i)
353{
354 if (i == 0)
355 return -1;
356
357 int result = 0;
358 while (!(i & 1)) {
359 ++result;
360 i >>= 1;
361 }
362 return result;
363}
364
365int QPlatformScreen::angleBetween(Qt::ScreenOrientation a, Qt::ScreenOrientation b)
366{
367 if (a == Qt::PrimaryOrientation || b == Qt::PrimaryOrientation) {
368 qWarning(msg: "Use QScreen version of %sBetween() when passing Qt::PrimaryOrientation", "angle");
369 return 0;
370 }
371
372 if (a == b)
373 return 0;
374
375 int ia = log2(i: uint(a));
376 int ib = log2(i: uint(b));
377
378 int delta = ia - ib;
379
380 if (delta < 0)
381 delta = delta + 4;
382
383 int angles[] = { 0, 90, 180, 270 };
384 return angles[delta];
385}
386
387QTransform QPlatformScreen::transformBetween(Qt::ScreenOrientation a, Qt::ScreenOrientation b, const QRect &target)
388{
389 if (a == Qt::PrimaryOrientation || b == Qt::PrimaryOrientation) {
390 qWarning(msg: "Use QScreen version of %sBetween() when passing Qt::PrimaryOrientation", "transform");
391 return QTransform();
392 }
393
394 if (a == b)
395 return QTransform();
396
397 int angle = angleBetween(a, b);
398
399 QTransform result;
400 switch (angle) {
401 case 90:
402 result.translate(dx: target.width(), dy: 0);
403 break;
404 case 180:
405 result.translate(dx: target.width(), dy: target.height());
406 break;
407 case 270:
408 result.translate(dx: 0, dy: target.height());
409 break;
410 default:
411 Q_ASSERT(false);
412 }
413 result.rotate(a: angle);
414
415 return result;
416}
417
418QRect QPlatformScreen::mapBetween(Qt::ScreenOrientation a, Qt::ScreenOrientation b, const QRect &rect)
419{
420 if (a == Qt::PrimaryOrientation || b == Qt::PrimaryOrientation) {
421 qWarning(msg: "Use QScreen version of %sBetween() when passing Qt::PrimaryOrientation", "map");
422 return rect;
423 }
424
425 if (a == b)
426 return rect;
427
428 if ((a == Qt::PortraitOrientation || a == Qt::InvertedPortraitOrientation)
429 != (b == Qt::PortraitOrientation || b == Qt::InvertedPortraitOrientation))
430 {
431 return QRect(rect.y(), rect.x(), rect.height(), rect.width());
432 }
433
434 return rect;
435}
436
437/*!
438 Returns a hint about this screen's subpixel layout structure.
439
440 The default implementation queries the \b{QT_SUBPIXEL_AA_TYPE} env variable.
441 This is just a hint because most platforms don't have a way to retrieve the correct value from hardware
442 and instead rely on font configurations.
443*/
444QPlatformScreen::SubpixelAntialiasingType QPlatformScreen::subpixelAntialiasingTypeHint() const
445{
446 static int type = -1;
447 if (type == -1) {
448 QByteArray env = qgetenv(varName: "QT_SUBPIXEL_AA_TYPE");
449 if (env == "RGB")
450 type = QPlatformScreen::Subpixel_RGB;
451 else if (env == "BGR")
452 type = QPlatformScreen::Subpixel_BGR;
453 else if (env == "VRGB")
454 type = QPlatformScreen::Subpixel_VRGB;
455 else if (env == "VBGR")
456 type = QPlatformScreen::Subpixel_VBGR;
457 else
458 type = QPlatformScreen::Subpixel_None;
459 }
460
461 return static_cast<QPlatformScreen::SubpixelAntialiasingType>(type);
462}
463
464/*!
465 Returns the current power state.
466
467 The default implementation always returns PowerStateOn.
468*/
469QPlatformScreen::PowerState QPlatformScreen::powerState() const
470{
471 return PowerStateOn;
472}
473
474/*!
475 Sets the power state for this screen.
476*/
477void QPlatformScreen::setPowerState(PowerState state)
478{
479 Q_UNUSED(state);
480}
481
482/*!
483 Reimplement this function in subclass to return the list
484 of modes for this screen.
485
486 The default implementation returns a list with
487 only one mode from the current screen size and refresh rate.
488
489 \sa QPlatformScreen::geometry
490 \sa QPlatformScreen::refreshRate
491
492 \since 5.9
493*/
494QList<QPlatformScreen::Mode> QPlatformScreen::modes() const
495{
496 QList<QPlatformScreen::Mode> list;
497 list.append(t: {.size: geometry().size(), .refreshRate: refreshRate()});
498 return list;
499}
500
501/*!
502 Reimplement this function in subclass to return the
503 index of the current mode from the modes list.
504
505 The default implementation returns 0.
506
507 \sa QPlatformScreen::modes
508
509 \since 5.9
510*/
511int QPlatformScreen::currentMode() const
512{
513 return 0;
514}
515
516/*!
517 Reimplement this function in subclass to return the preferred
518 mode index from the modes list.
519
520 The default implementation returns 0.
521
522 \sa QPlatformScreen::modes
523
524 \since 5.9
525*/
526int QPlatformScreen::preferredMode() const
527{
528 return 0;
529}
530
531QList<QPlatformScreen *> QPlatformPlaceholderScreen::virtualSiblings() const
532{
533 QList<QPlatformScreen *> siblings;
534
535 if (!m_virtualSibling)
536 return siblings;
537
538 for (QScreen *screen : QGuiApplication::screens()) {
539 if (screen->handle() && screen->handle() != this)
540 siblings << screen->handle();
541 }
542 return siblings;
543}
544
545QT_END_NAMESPACE
546

source code of qtbase/src/gui/kernel/qplatformscreen.cpp