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