1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtGui module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qplatformscreen.h"
41#include <QtCore/qdebug.h>
42#include <QtGui/qguiapplication.h>
43#include <qpa/qplatformcursor.h>
44#include <QtGui/private/qguiapplication_p.h>
45#include <qpa/qplatformscreen_p.h>
46#include <qpa/qplatformintegration.h>
47#include <QtGui/qscreen.h>
48#include <QtGui/qwindow.h>
49#include <private/qhighdpiscaling_p.h>
50
51QT_BEGIN_NAMESPACE
52
53QPlatformScreen::QPlatformScreen()
54 : d_ptr(new QPlatformScreenPrivate)
55{
56 Q_D(QPlatformScreen);
57 d->screen = nullptr;
58}
59
60QPlatformScreen::~QPlatformScreen()
61{
62 Q_D(QPlatformScreen);
63 if (d->screen) {
64 qWarning(msg: "Manually deleting a QPlatformScreen. Call QWindowSystemInterface::handleScreenRemoved instead.");
65 delete d->screen;
66 }
67}
68
69/*!
70 \fn QPixmap QPlatformScreen::grabWindow(WId window, int x, int y, int width, int height) const
71
72 This function is called when Qt needs to be able to grab the content of a window.
73
74 Returns the content of the window specified with the WId handle within the boundaries of
75 QRect(x,y,width,height).
76*/
77QPixmap QPlatformScreen::grabWindow(WId window, int x, int y, int width, int height) const
78{
79 Q_UNUSED(window);
80 Q_UNUSED(x);
81 Q_UNUSED(y);
82 Q_UNUSED(width);
83 Q_UNUSED(height);
84 return QPixmap();
85}
86
87/*!
88 Return the given top level window for a given position.
89
90 Default implementation retrieves a list of all top level windows and finds the first window
91 which contains point \a pos
92*/
93QWindow *QPlatformScreen::topLevelAt(const QPoint & pos) const
94{
95 const QWindowList list = QGuiApplication::topLevelWindows();
96 for (int i = list.size()-1; i >= 0; --i) {
97 QWindow *w = list[i];
98 if (w->isVisible() && QHighDpi::toNativePixels(value: w->geometry(), context: w).contains(p: pos))
99 return w;
100 }
101
102 return nullptr;
103}
104
105/*!
106 Return all windows residing on this screen.
107*/
108QWindowList QPlatformScreen::windows() const
109{
110 QWindowList windows;
111 for (QWindow *window : QGuiApplication::allWindows()) {
112 if (platformScreenForWindow(window) != this)
113 continue;
114 windows.append(t: window);
115 }
116 return windows;
117}
118
119/*!
120 Find the sibling screen corresponding to \a globalPos.
121
122 Returns this screen if no suitable screen is found at the position.
123 */
124const QPlatformScreen *QPlatformScreen::screenForPosition(const QPoint &point) const
125{
126 if (!geometry().contains(p: point)) {
127 const auto screens = virtualSiblings();
128 for (const QPlatformScreen *screen : screens) {
129 if (screen->geometry().contains(p: point))
130 return screen;
131 }
132 }
133 return this;
134}
135
136
137/*!
138 Returns a list of all the platform screens that are part of the same
139 virtual desktop.
140
141 Screens part of the same virtual desktop share a common coordinate system,
142 and windows can be freely moved between them.
143*/
144QList<QPlatformScreen *> QPlatformScreen::virtualSiblings() const
145{
146 QList<QPlatformScreen *> list;
147 list << const_cast<QPlatformScreen *>(this);
148 return list;
149}
150
151QScreen *QPlatformScreen::screen() const
152{
153 Q_D(const QPlatformScreen);
154 return d->screen;
155}
156
157/*!
158 Reimplement this function in subclass to return the physical size of the
159 screen, in millimeters. The physical size represents the actual physical
160 dimensions of the display.
161
162 The default implementation takes the pixel size of the screen, considers a
163 resolution of 100 dots per inch, and returns the calculated physical size.
164 A device with a screen that has different resolutions will need to be
165 supported by a suitable reimplementation of this function.
166
167 \sa logcalDpi
168*/
169QSizeF QPlatformScreen::physicalSize() const
170{
171 static const int dpi = 100;
172 return QSizeF(geometry().size()) / dpi * qreal(25.4);
173}
174
175/*!
176 Reimplement this function in subclass to return the logical horizontal
177 and vertical dots per inch metrics of the screen.
178
179 The logical dots per inch metrics are used by QFont to convert point sizes
180 to pixel sizes.
181
182 The default implementation uses the screen pixel size and physical size to
183 compute the metrics.
184
185 \sa physicalSize
186*/
187QDpi QPlatformScreen::logicalDpi() const
188{
189 QSizeF ps = physicalSize();
190 QSize s = geometry().size();
191
192 if (qFuzzyIsNull(d: ps.width()) || qFuzzyIsNull(d: ps.height()))
193 return QDpi(96, 96);
194 return QDpi(25.4 * s.width() / ps.width(),
195 25.4 * s.height() / ps.height());
196}
197
198// Helper function for accessing the platform screen logical dpi
199// which accounts for QT_FONT_DPI.
200QPair<qreal, qreal> QPlatformScreen::overrideDpi(const QPair<qreal, qreal> &in)
201{
202 static const int overrideDpi = qEnvironmentVariableIntValue(varName: "QT_FONT_DPI");
203 return overrideDpi > 0 ? QDpi(overrideDpi, overrideDpi) : in;
204}
205
206/*!
207 Reimplement to return the base logical DPI for the platform. This
208 DPI value should correspond to a standard-DPI (1x) display. The
209 default implementation returns 96.
210
211 QtGui will use this value (together with logicalDpi) to compute
212 the scale factor when high-DPI scaling is enabled:
213 factor = logicalDPI / baseDPI
214*/
215QDpi QPlatformScreen::logicalBaseDpi() const
216{
217 return QDpi(96, 96);
218}
219
220/*!
221 Reimplement this function in subclass to return the device pixel ratio
222 for the screen. This is the ratio between physical pixels and the
223 device-independent pixels of the windowing system. The default
224 implementation returns 1.0.
225
226 \sa QPlatformWindow::devicePixelRatio()
227 \sa QPlatformScreen::pixelDensity()
228*/
229qreal QPlatformScreen::devicePixelRatio() const
230{
231 return 1.0;
232}
233
234/*!
235 Reimplement this function in subclass to return the pixel density of the
236 screen. This is the scale factor needed to make a low-dpi application
237 usable on this screen. The default implementation returns 1.0.
238
239 Returning something else than 1.0 from this function causes Qt to
240 apply the scale factor to the application's coordinate system.
241 This is different from devicePixelRatio, which reports a scale
242 factor already applied by the windowing system. A platform plugin
243 typically implements one (or none) of these two functions.
244
245 \sa QPlatformWindow::devicePixelRatio()
246*/
247qreal QPlatformScreen::pixelDensity() const
248{
249 return 1.0;
250}
251
252/*!
253 Reimplement this function in subclass to return the vertical refresh rate
254 of the screen, in Hz.
255
256 The default returns 60, a sensible default for modern displays.
257*/
258qreal QPlatformScreen::refreshRate() const
259{
260 return 60;
261}
262
263/*!
264 Reimplement this function in subclass to return the native orientation
265 of the screen, e.g. the orientation where the logo sticker of the device
266 appears the right way up.
267
268 The default implementation returns Qt::PrimaryOrientation.
269*/
270Qt::ScreenOrientation QPlatformScreen::nativeOrientation() const
271{
272 return Qt::PrimaryOrientation;
273}
274
275/*!
276 Reimplement this function in subclass to return the current orientation
277 of the screen, for example based on accelerometer data to determine
278 the device orientation.
279
280 The default implementation returns Qt::PrimaryOrientation.
281*/
282Qt::ScreenOrientation QPlatformScreen::orientation() const
283{
284 return Qt::PrimaryOrientation;
285}
286
287/*
288 Reimplement this function in subclass to filter out unneeded screen
289 orientation updates.
290
291 The orientations will anyway be filtered before QScreen::orientationChanged()
292 is emitted, but the mask can be used by the platform plugin for example to
293 prevent having to have an accelerometer sensor running all the time, or to
294 improve the reported values. As an example of the latter, in case of only
295 Landscape | InvertedLandscape being set in the mask, on a platform that gets
296 its orientation readings from an accelerometer sensor embedded in a handheld
297 device, the platform can report transitions between the two even when the
298 device is held in an orientation that's closer to portrait.
299
300 By default, the orientation update mask is empty, so unless this function
301 has been called with a non-empty mask the platform does not need to report
302 any orientation updates through
303 QWindowSystemInterface::handleScreenOrientationChange().
304*/
305void QPlatformScreen::setOrientationUpdateMask(Qt::ScreenOrientations mask)
306{
307 Q_UNUSED(mask);
308}
309
310QPlatformScreen * QPlatformScreen::platformScreenForWindow(const QWindow *window)
311{
312 // QTBUG 32681: It can happen during the transition between screens
313 // when one screen is disconnected that the window doesn't have a screen.
314 if (!window->screen())
315 return nullptr;
316 return window->screen()->handle();
317}
318
319/*!
320 Reimplement this function in subclass to return the manufacturer
321 of this screen.
322
323 The default implementation returns an empty string.
324
325 \since 5.9
326*/
327QString QPlatformScreen::manufacturer() const
328{
329 return QString();
330}
331
332/*!
333 Reimplement this function in subclass to return the model
334 of this screen.
335
336 The default implementation returns an empty string.
337
338 \since 5.9
339*/
340QString QPlatformScreen::model() const
341{
342 return QString();
343}
344
345/*!
346 Reimplement this function in subclass to return the serial number
347 of this screen.
348
349 The default implementation returns an empty string.
350
351 \since 5.9
352*/
353QString QPlatformScreen::serialNumber() const
354{
355 return QString();
356}
357
358/*!
359 \class QPlatformScreen
360 \since 4.8
361 \internal
362 \preliminary
363 \ingroup qpa
364
365 \brief The QPlatformScreen class provides an abstraction for visual displays.
366
367 Many window systems has support for retrieving information on the attached displays. To be able
368 to query the display QPA uses QPlatformScreen. Qt its self is most dependent on the
369 physicalSize() function, since this is the function it uses to calculate the dpi to use when
370 converting point sizes to pixels sizes. However, this is unfortunate on some systems, as the
371 native system fakes its dpi size.
372
373 QPlatformScreen is also used by the public api QDesktopWidget for information about the desktop.
374 */
375
376/*! \fn QRect QPlatformScreen::geometry() const = 0
377 Reimplement in subclass to return the pixel geometry of the screen
378*/
379
380/*! \fn QRect QPlatformScreen::availableGeometry() const
381 Reimplement in subclass to return the pixel geometry of the available space
382 This normally is the desktop screen minus the task manager, global menubar etc.
383*/
384
385/*! \fn int QPlatformScreen::depth() const = 0
386 Reimplement in subclass to return current depth of the screen
387*/
388
389/*! \fn QImage::Format QPlatformScreen::format() const = 0
390 Reimplement in subclass to return the image format which corresponds to the screen format
391*/
392
393/*!
394 Reimplement this function in subclass to return the cursor of the screen.
395
396 The default implementation returns \nullptr.
397*/
398QPlatformCursor *QPlatformScreen::cursor() const
399{
400 return nullptr;
401}
402
403/*!
404 Convenience method to resize all the maximized and fullscreen windows
405 of this platform screen.
406*/
407void QPlatformScreen::resizeMaximizedWindows()
408{
409 // 'screen()' still has the old geometry info while 'this' has the new geometry info
410 const QRect oldGeometry = screen()->geometry();
411 const QRect oldAvailableGeometry = screen()->availableGeometry();
412 const QRect newGeometry = deviceIndependentGeometry();
413 const QRect newAvailableGeometry = QHighDpi::fromNative(value: availableGeometry(), scaleFactor: QHighDpiScaling::factor(context: this), origin: newGeometry.topLeft());
414
415 const bool supportsMaximizeUsingFullscreen = QGuiApplicationPrivate::platformIntegration()->hasCapability(cap: QPlatformIntegration::MaximizeUsingFullscreenGeometry);
416
417 for (QWindow *w : windows()) {
418 // Skip non-platform windows, e.g., offscreen windows.
419 if (!w->handle())
420 continue;
421
422 if (supportsMaximizeUsingFullscreen
423 && w->windowState() & Qt::WindowMaximized
424 && w->flags() & Qt::MaximizeUsingFullscreenGeometryHint) {
425 w->setGeometry(newGeometry);
426 } else if (w->windowState() & Qt::WindowMaximized || w->geometry() == oldAvailableGeometry) {
427 w->setGeometry(newAvailableGeometry);
428 } else if (w->windowState() & Qt::WindowFullScreen || w->geometry() == oldGeometry) {
429 w->setGeometry(newGeometry);
430 }
431 }
432}
433
434// i must be power of two
435static int log2(uint i)
436{
437 if (i == 0)
438 return -1;
439
440 int result = 0;
441 while (!(i & 1)) {
442 ++result;
443 i >>= 1;
444 }
445 return result;
446}
447
448int QPlatformScreen::angleBetween(Qt::ScreenOrientation a, Qt::ScreenOrientation b)
449{
450 if (a == Qt::PrimaryOrientation || b == Qt::PrimaryOrientation) {
451 qWarning(msg: "Use QScreen version of %sBetween() when passing Qt::PrimaryOrientation", "angle");
452 return 0;
453 }
454
455 if (a == b)
456 return 0;
457
458 int ia = log2(i: uint(a));
459 int ib = log2(i: uint(b));
460
461 int delta = ia - ib;
462
463 if (delta < 0)
464 delta = delta + 4;
465
466 int angles[] = { 0, 90, 180, 270 };
467 return angles[delta];
468}
469
470QTransform QPlatformScreen::transformBetween(Qt::ScreenOrientation a, Qt::ScreenOrientation b, const QRect &target)
471{
472 if (a == Qt::PrimaryOrientation || b == Qt::PrimaryOrientation) {
473 qWarning(msg: "Use QScreen version of %sBetween() when passing Qt::PrimaryOrientation", "transform");
474 return QTransform();
475 }
476
477 if (a == b)
478 return QTransform();
479
480 int angle = angleBetween(a, b);
481
482 QTransform result;
483 switch (angle) {
484 case 90:
485 result.translate(dx: target.width(), dy: 0);
486 break;
487 case 180:
488 result.translate(dx: target.width(), dy: target.height());
489 break;
490 case 270:
491 result.translate(dx: 0, dy: target.height());
492 break;
493 default:
494 Q_ASSERT(false);
495 }
496 result.rotate(a: angle);
497
498 return result;
499}
500
501QRect QPlatformScreen::mapBetween(Qt::ScreenOrientation a, Qt::ScreenOrientation b, const QRect &rect)
502{
503 if (a == Qt::PrimaryOrientation || b == Qt::PrimaryOrientation) {
504 qWarning(msg: "Use QScreen version of %sBetween() when passing Qt::PrimaryOrientation", "map");
505 return rect;
506 }
507
508 if (a == b)
509 return rect;
510
511 if ((a == Qt::PortraitOrientation || a == Qt::InvertedPortraitOrientation)
512 != (b == Qt::PortraitOrientation || b == Qt::InvertedPortraitOrientation))
513 {
514 return QRect(rect.y(), rect.x(), rect.height(), rect.width());
515 }
516
517 return rect;
518}
519
520QRect QPlatformScreen::deviceIndependentGeometry() const
521{
522 qreal scaleFactor = QHighDpiScaling::factor(context: this);
523 QRect nativeGeometry = geometry();
524 return QRect(nativeGeometry.topLeft(), QHighDpi::fromNative(value: nativeGeometry.size(), scaleFactor));
525}
526
527/*!
528 Returns a hint about this screen's subpixel layout structure.
529
530 The default implementation queries the \b{QT_SUBPIXEL_AA_TYPE} env variable.
531 This is just a hint because most platforms don't have a way to retrieve the correct value from hardware
532 and instead rely on font configurations.
533*/
534QPlatformScreen::SubpixelAntialiasingType QPlatformScreen::subpixelAntialiasingTypeHint() const
535{
536 static int type = -1;
537 if (type == -1) {
538 QByteArray env = qgetenv(varName: "QT_SUBPIXEL_AA_TYPE");
539 if (env == "RGB")
540 type = QPlatformScreen::Subpixel_RGB;
541 else if (env == "BGR")
542 type = QPlatformScreen::Subpixel_BGR;
543 else if (env == "VRGB")
544 type = QPlatformScreen::Subpixel_VRGB;
545 else if (env == "VBGR")
546 type = QPlatformScreen::Subpixel_VBGR;
547 else
548 type = QPlatformScreen::Subpixel_None;
549 }
550
551 return static_cast<QPlatformScreen::SubpixelAntialiasingType>(type);
552}
553
554/*!
555 Returns the current power state.
556
557 The default implementation always returns PowerStateOn.
558*/
559QPlatformScreen::PowerState QPlatformScreen::powerState() const
560{
561 return PowerStateOn;
562}
563
564/*!
565 Sets the power state for this screen.
566*/
567void QPlatformScreen::setPowerState(PowerState state)
568{
569 Q_UNUSED(state);
570}
571
572/*!
573 Reimplement this function in subclass to return the list
574 of modes for this screen.
575
576 The default implementation returns a list with
577 only one mode from the current screen size and refresh rate.
578
579 \sa QPlatformScreen::geometry
580 \sa QPlatformScreen::refreshRate
581
582 \since 5.9
583*/
584QVector<QPlatformScreen::Mode> QPlatformScreen::modes() const
585{
586 QVector<QPlatformScreen::Mode> list;
587 list.append(t: {.size: geometry().size(), .refreshRate: refreshRate()});
588 return list;
589}
590
591/*!
592 Reimplement this function in subclass to return the
593 index of the current mode from the modes list.
594
595 The default implementation returns 0.
596
597 \sa QPlatformScreen::modes
598
599 \since 5.9
600*/
601int QPlatformScreen::currentMode() const
602{
603 return 0;
604}
605
606/*!
607 Reimplement this function in subclass to return the preferred
608 mode index from the modes list.
609
610 The default implementation returns 0.
611
612 \sa QPlatformScreen::modes
613
614 \since 5.9
615*/
616int QPlatformScreen::preferredMode() const
617{
618 return 0;
619}
620
621QList<QPlatformScreen *> QPlatformPlaceholderScreen::virtualSiblings() const
622{
623 QList<QPlatformScreen *> siblings;
624
625 if (!m_virtualSibling)
626 return siblings;
627
628 for (QScreen *screen : QGuiApplication::screens()) {
629 if (screen->handle() && screen->handle() != this)
630 siblings << screen->handle();
631 }
632 return siblings;
633}
634
635QT_END_NAMESPACE
636

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