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 "qscreen.h" |
41 | #include "qscreen_p.h" |
42 | #include "qpixmap.h" |
43 | #include "qguiapplication_p.h" |
44 | #include <qpa/qplatformscreen.h> |
45 | #include <qpa/qplatformscreen_p.h> |
46 | |
47 | #include <QtCore/QDebug> |
48 | #include <QtCore/private/qobject_p.h> |
49 | #include "qhighdpiscaling_p.h" |
50 | |
51 | QT_BEGIN_NAMESPACE |
52 | |
53 | /*! |
54 | \class QScreen |
55 | \since 5.0 |
56 | \brief The QScreen class is used to query screen properties. |
57 | \inmodule QtGui |
58 | |
59 | A note on logical vs physical dots per inch: physical DPI is based on the |
60 | actual physical pixel sizes when available, and is useful for print preview |
61 | and other cases where it's desirable to know the exact physical dimensions |
62 | of screen displayed contents. |
63 | |
64 | Logical dots per inch are used to convert font and user interface elements |
65 | from point sizes to pixel sizes, and might be different from the physical |
66 | dots per inch. The logical dots per inch are sometimes user-settable in the |
67 | desktop environment's settings panel, to let the user globally control UI |
68 | and font sizes in different applications. |
69 | |
70 | \inmodule QtGui |
71 | */ |
72 | |
73 | QScreen::QScreen(QPlatformScreen *screen) |
74 | : QObject(*new QScreenPrivate(), nullptr) |
75 | { |
76 | Q_D(QScreen); |
77 | d->setPlatformScreen(screen); |
78 | } |
79 | |
80 | void QScreenPrivate::updateGeometriesWithSignals() |
81 | { |
82 | const QRect oldGeometry = geometry; |
83 | const QRect oldAvailableGeometry = availableGeometry; |
84 | updateHighDpi(); |
85 | emitGeometryChangeSignals(geometryChanged: oldGeometry != geometry, availableGeometryChanged: oldAvailableGeometry != availableGeometry); |
86 | } |
87 | |
88 | void QScreenPrivate::emitGeometryChangeSignals(bool geometryChanged, bool availableGeometryChanged) |
89 | { |
90 | Q_Q(QScreen); |
91 | if (geometryChanged) |
92 | emit q->geometryChanged(geometry); |
93 | |
94 | if (availableGeometryChanged) |
95 | emit q->availableGeometryChanged(geometry: availableGeometry); |
96 | |
97 | if (geometryChanged || availableGeometryChanged) { |
98 | const auto siblings = q->virtualSiblings(); |
99 | for (QScreen* sibling : siblings) |
100 | emit sibling->virtualGeometryChanged(rect: sibling->virtualGeometry()); |
101 | } |
102 | |
103 | if (geometryChanged) |
104 | emit q->physicalDotsPerInchChanged(dpi: q->physicalDotsPerInch()); |
105 | } |
106 | |
107 | void QScreenPrivate::setPlatformScreen(QPlatformScreen *screen) |
108 | { |
109 | Q_Q(QScreen); |
110 | platformScreen = screen; |
111 | platformScreen->d_func()->screen = q; |
112 | orientation = platformScreen->orientation(); |
113 | |
114 | logicalDpi = QPlatformScreen::overrideDpi(in: platformScreen->logicalDpi()); |
115 | |
116 | refreshRate = platformScreen->refreshRate(); |
117 | // safeguard ourselves against buggy platform behavior... |
118 | if (refreshRate < 1.0) |
119 | refreshRate = 60.0; |
120 | |
121 | updateHighDpi(); |
122 | |
123 | updatePrimaryOrientation(); // derived from the geometry |
124 | |
125 | filteredOrientation = orientation; |
126 | if (filteredOrientation == Qt::PrimaryOrientation) |
127 | filteredOrientation = primaryOrientation; |
128 | } |
129 | |
130 | |
131 | /*! |
132 | Destroys the screen. |
133 | */ |
134 | QScreen::~QScreen() |
135 | { |
136 | // Remove screen |
137 | const bool wasPrimary = QGuiApplication::primaryScreen() == this; |
138 | QGuiApplicationPrivate::screen_list.removeOne(t: this); |
139 | QGuiApplicationPrivate::resetCachedDevicePixelRatio(); |
140 | |
141 | if (!qGuiApp) |
142 | return; |
143 | |
144 | QScreen *newPrimaryScreen = QGuiApplication::primaryScreen(); |
145 | if (wasPrimary && newPrimaryScreen) |
146 | emit qGuiApp->primaryScreenChanged(screen: newPrimaryScreen); |
147 | |
148 | // Allow clients to manage windows that are affected by the screen going |
149 | // away, before we fall back to moving them to the primary screen. |
150 | emit qApp->screenRemoved(screen: this); |
151 | |
152 | if (QGuiApplication::closingDown()) |
153 | return; |
154 | |
155 | bool movingFromVirtualSibling = newPrimaryScreen |
156 | && newPrimaryScreen->handle()->virtualSiblings().contains(t: handle()); |
157 | |
158 | // Move any leftover windows to the primary screen |
159 | const auto allWindows = QGuiApplication::allWindows(); |
160 | for (QWindow *window : allWindows) { |
161 | if (!window->isTopLevel() || window->screen() != this) |
162 | continue; |
163 | |
164 | const bool wasVisible = window->isVisible(); |
165 | window->setScreen(newPrimaryScreen); |
166 | |
167 | // Re-show window if moved from a virtual sibling screen. Otherwise |
168 | // leave it up to the application developer to show the window. |
169 | if (movingFromVirtualSibling) |
170 | window->setVisible(wasVisible); |
171 | } |
172 | } |
173 | |
174 | /*! |
175 | Get the platform screen handle. |
176 | |
177 | \sa {Qt Platform Abstraction}{Qt Platform Abstraction (QPA)} |
178 | */ |
179 | QPlatformScreen *QScreen::handle() const |
180 | { |
181 | Q_D(const QScreen); |
182 | return d->platformScreen; |
183 | } |
184 | |
185 | /*! |
186 | \property QScreen::name |
187 | \brief a user presentable string representing the screen |
188 | |
189 | For example, on X11 these correspond to the XRandr screen names, |
190 | typically "VGA1", "HDMI1", etc. |
191 | */ |
192 | QString QScreen::name() const |
193 | { |
194 | Q_D(const QScreen); |
195 | return d->platformScreen->name(); |
196 | } |
197 | |
198 | /*! |
199 | \property QScreen::manufacturer |
200 | \brief the manufacturer of the screen |
201 | |
202 | \since 5.9 |
203 | */ |
204 | QString QScreen::manufacturer() const |
205 | { |
206 | Q_D(const QScreen); |
207 | return d->platformScreen->manufacturer(); |
208 | } |
209 | |
210 | /*! |
211 | \property QScreen::model |
212 | \brief the model of the screen |
213 | |
214 | \since 5.9 |
215 | */ |
216 | QString QScreen::model() const |
217 | { |
218 | Q_D(const QScreen); |
219 | return d->platformScreen->model(); |
220 | } |
221 | |
222 | /*! |
223 | \property QScreen::serialNumber |
224 | \brief the serial number of the screen |
225 | |
226 | \since 5.9 |
227 | */ |
228 | QString QScreen::serialNumber() const |
229 | { |
230 | Q_D(const QScreen); |
231 | return d->platformScreen->serialNumber(); |
232 | } |
233 | |
234 | /*! |
235 | \property QScreen::depth |
236 | \brief the color depth of the screen |
237 | */ |
238 | int QScreen::depth() const |
239 | { |
240 | Q_D(const QScreen); |
241 | return d->platformScreen->depth(); |
242 | } |
243 | |
244 | /*! |
245 | \property QScreen::size |
246 | \brief the pixel resolution of the screen |
247 | */ |
248 | QSize QScreen::size() const |
249 | { |
250 | Q_D(const QScreen); |
251 | return d->geometry.size(); |
252 | } |
253 | |
254 | /*! |
255 | \property QScreen::physicalDotsPerInchX |
256 | \brief the number of physical dots or pixels per inch in the horizontal direction |
257 | |
258 | This value represents the actual horizontal pixel density on the screen's display. |
259 | Depending on what information the underlying system provides the value might not be |
260 | entirely accurate. |
261 | |
262 | \sa physicalDotsPerInchY() |
263 | */ |
264 | qreal QScreen::physicalDotsPerInchX() const |
265 | { |
266 | return size().width() / physicalSize().width() * qreal(25.4); |
267 | } |
268 | |
269 | /*! |
270 | \property QScreen::physicalDotsPerInchY |
271 | \brief the number of physical dots or pixels per inch in the vertical direction |
272 | |
273 | This value represents the actual vertical pixel density on the screen's display. |
274 | Depending on what information the underlying system provides the value might not be |
275 | entirely accurate. |
276 | |
277 | \sa physicalDotsPerInchX() |
278 | */ |
279 | qreal QScreen::physicalDotsPerInchY() const |
280 | { |
281 | return size().height() / physicalSize().height() * qreal(25.4); |
282 | } |
283 | |
284 | /*! |
285 | \property QScreen::physicalDotsPerInch |
286 | \brief the number of physical dots or pixels per inch |
287 | |
288 | This value represents the pixel density on the screen's display. |
289 | Depending on what information the underlying system provides the value might not be |
290 | entirely accurate. |
291 | |
292 | This is a convenience property that's simply the average of the physicalDotsPerInchX |
293 | and physicalDotsPerInchY properties. |
294 | |
295 | \sa physicalDotsPerInchX() |
296 | \sa physicalDotsPerInchY() |
297 | */ |
298 | qreal QScreen::physicalDotsPerInch() const |
299 | { |
300 | QSize sz = size(); |
301 | QSizeF psz = physicalSize(); |
302 | return ((sz.height() / psz.height()) + (sz.width() / psz.width())) * qreal(25.4 * 0.5); |
303 | } |
304 | |
305 | /*! |
306 | \property QScreen::logicalDotsPerInchX |
307 | \brief the number of logical dots or pixels per inch in the horizontal direction |
308 | |
309 | This value is used to convert font point sizes to pixel sizes. |
310 | |
311 | \sa logicalDotsPerInchY() |
312 | */ |
313 | qreal QScreen::logicalDotsPerInchX() const |
314 | { |
315 | Q_D(const QScreen); |
316 | if (QHighDpiScaling::isActive()) |
317 | return QHighDpiScaling::logicalDpi(screen: this).first; |
318 | return d->logicalDpi.first; |
319 | } |
320 | |
321 | /*! |
322 | \property QScreen::logicalDotsPerInchY |
323 | \brief the number of logical dots or pixels per inch in the vertical direction |
324 | |
325 | This value is used to convert font point sizes to pixel sizes. |
326 | |
327 | \sa logicalDotsPerInchX() |
328 | */ |
329 | qreal QScreen::logicalDotsPerInchY() const |
330 | { |
331 | Q_D(const QScreen); |
332 | if (QHighDpiScaling::isActive()) |
333 | return QHighDpiScaling::logicalDpi(screen: this).second; |
334 | return d->logicalDpi.second; |
335 | } |
336 | |
337 | /*! |
338 | \property QScreen::logicalDotsPerInch |
339 | \brief the number of logical dots or pixels per inch |
340 | |
341 | This value can be used to convert font point sizes to pixel sizes. |
342 | |
343 | This is a convenience property that's simply the average of the logicalDotsPerInchX |
344 | and logicalDotsPerInchY properties. |
345 | |
346 | \sa logicalDotsPerInchX() |
347 | \sa logicalDotsPerInchY() |
348 | */ |
349 | qreal QScreen::logicalDotsPerInch() const |
350 | { |
351 | Q_D(const QScreen); |
352 | QDpi dpi = QHighDpiScaling::isActive() ? QHighDpiScaling::logicalDpi(screen: this) : d->logicalDpi; |
353 | return (dpi.first + dpi.second) * qreal(0.5); |
354 | } |
355 | |
356 | /*! |
357 | \property QScreen::devicePixelRatio |
358 | \brief the screen's ratio between physical pixels and device-independent pixels |
359 | \since 5.5 |
360 | |
361 | Returns the ratio between physical pixels and device-independent pixels for the screen. |
362 | |
363 | Common values are 1.0 on normal displays and 2.0 on "retina" displays. |
364 | Higher values are also possible. |
365 | |
366 | \sa QWindow::devicePixelRatio(), QGuiApplication::devicePixelRatio() |
367 | */ |
368 | qreal QScreen::devicePixelRatio() const |
369 | { |
370 | Q_D(const QScreen); |
371 | return d->platformScreen->devicePixelRatio() * QHighDpiScaling::factor(context: this); |
372 | } |
373 | |
374 | /*! |
375 | \property QScreen::physicalSize |
376 | \brief the screen's physical size (in millimeters) |
377 | |
378 | The physical size represents the actual physical dimensions of the |
379 | screen's display. |
380 | |
381 | Depending on what information the underlying system provides the value |
382 | might not be entirely accurate. |
383 | */ |
384 | QSizeF QScreen::physicalSize() const |
385 | { |
386 | Q_D(const QScreen); |
387 | return d->platformScreen->physicalSize(); |
388 | } |
389 | |
390 | /*! |
391 | \property QScreen::availableSize |
392 | \brief the screen's available size in pixels |
393 | |
394 | The available size is the size excluding window manager reserved areas |
395 | such as task bars and system menus. |
396 | */ |
397 | QSize QScreen::availableSize() const |
398 | { |
399 | Q_D(const QScreen); |
400 | return d->availableGeometry.size(); |
401 | } |
402 | |
403 | /*! |
404 | \property QScreen::geometry |
405 | \brief the screen's geometry in pixels |
406 | |
407 | As an example this might return QRect(0, 0, 1280, 1024), or in a |
408 | virtual desktop setting QRect(1280, 0, 1280, 1024). |
409 | */ |
410 | QRect QScreen::geometry() const |
411 | { |
412 | Q_D(const QScreen); |
413 | return d->geometry; |
414 | } |
415 | |
416 | /*! |
417 | \property QScreen::availableGeometry |
418 | \brief the screen's available geometry in pixels |
419 | |
420 | The available geometry is the geometry excluding window manager reserved areas |
421 | such as task bars and system menus. |
422 | |
423 | Note, on X11 this will return the true available geometry only on systems with one monitor and |
424 | if window manager has set _NET_WORKAREA atom. In all other cases this is equal to geometry(). |
425 | This is a limitation in X11 window manager specification. |
426 | */ |
427 | QRect QScreen::availableGeometry() const |
428 | { |
429 | Q_D(const QScreen); |
430 | return d->availableGeometry; |
431 | } |
432 | |
433 | /*! |
434 | Get the screen's virtual siblings. |
435 | |
436 | The virtual siblings are the screen instances sharing the same virtual desktop. |
437 | They share a common coordinate system, and windows can freely be moved or |
438 | positioned across them without having to be re-created. |
439 | */ |
440 | QList<QScreen *> QScreen::virtualSiblings() const |
441 | { |
442 | Q_D(const QScreen); |
443 | const QList<QPlatformScreen *> platformScreens = d->platformScreen->virtualSiblings(); |
444 | QList<QScreen *> screens; |
445 | screens.reserve(alloc: platformScreens.count()); |
446 | for (QPlatformScreen *platformScreen : platformScreens) |
447 | screens << platformScreen->screen(); |
448 | return screens; |
449 | } |
450 | |
451 | /*! |
452 | \property QScreen::virtualSize |
453 | \brief the pixel size of the virtual desktop to which this screen belongs |
454 | |
455 | Returns the pixel size of the virtual desktop corresponding to this screen. |
456 | |
457 | This is the combined size of the virtual siblings' individual geometries. |
458 | |
459 | \sa virtualSiblings() |
460 | */ |
461 | QSize QScreen::virtualSize() const |
462 | { |
463 | return virtualGeometry().size(); |
464 | } |
465 | |
466 | /*! |
467 | \property QScreen::virtualGeometry |
468 | \brief the pixel geometry of the virtual desktop to which this screen belongs |
469 | |
470 | Returns the pixel geometry of the virtual desktop corresponding to this screen. |
471 | |
472 | This is the union of the virtual siblings' individual geometries. |
473 | |
474 | \sa virtualSiblings() |
475 | */ |
476 | QRect QScreen::virtualGeometry() const |
477 | { |
478 | QRect result; |
479 | const auto screens = virtualSiblings(); |
480 | for (QScreen *screen : screens) |
481 | result |= screen->geometry(); |
482 | return result; |
483 | } |
484 | |
485 | /*! |
486 | \property QScreen::availableVirtualSize |
487 | \brief the available size of the virtual desktop to which this screen belongs |
488 | |
489 | Returns the available pixel size of the virtual desktop corresponding to this screen. |
490 | |
491 | This is the combined size of the virtual siblings' individual available geometries. |
492 | |
493 | \sa availableSize(), virtualSiblings() |
494 | */ |
495 | QSize QScreen::availableVirtualSize() const |
496 | { |
497 | return availableVirtualGeometry().size(); |
498 | } |
499 | |
500 | /*! |
501 | \property QScreen::availableVirtualGeometry |
502 | \brief the available geometry of the virtual desktop to which this screen belongs |
503 | |
504 | Returns the available geometry of the virtual desktop corresponding to this screen. |
505 | |
506 | This is the union of the virtual siblings' individual available geometries. |
507 | |
508 | \sa availableGeometry(), virtualSiblings() |
509 | */ |
510 | QRect QScreen::availableVirtualGeometry() const |
511 | { |
512 | QRect result; |
513 | const auto screens = virtualSiblings(); |
514 | for (QScreen *screen : screens) |
515 | result |= screen->availableGeometry(); |
516 | return result; |
517 | } |
518 | |
519 | /*! |
520 | Sets the orientations that the application is interested in receiving |
521 | updates for in conjunction with this screen. |
522 | |
523 | For example, to receive orientation() updates and thus have |
524 | orientationChanged() signals being emitted for LandscapeOrientation and |
525 | InvertedLandscapeOrientation, call setOrientationUpdateMask() with |
526 | \a{mask} set to Qt::LandscapeOrientation | Qt::InvertedLandscapeOrientation. |
527 | |
528 | The default, 0, means no orientationChanged() signals are fired. |
529 | */ |
530 | void QScreen::setOrientationUpdateMask(Qt::ScreenOrientations mask) |
531 | { |
532 | Q_D(QScreen); |
533 | d->orientationUpdateMask = mask; |
534 | d->platformScreen->setOrientationUpdateMask(mask); |
535 | QGuiApplicationPrivate::updateFilteredScreenOrientation(screen: this); |
536 | } |
537 | |
538 | /*! |
539 | Returns the currently set orientation update mask. |
540 | |
541 | \sa setOrientationUpdateMask() |
542 | */ |
543 | Qt::ScreenOrientations QScreen::orientationUpdateMask() const |
544 | { |
545 | Q_D(const QScreen); |
546 | return d->orientationUpdateMask; |
547 | } |
548 | |
549 | /*! |
550 | \property QScreen::orientation |
551 | \brief the screen orientation |
552 | |
553 | The screen orientation represents the physical orientation |
554 | of the display. For example, the screen orientation of a mobile device |
555 | will change based on how it is being held. A change to the orientation |
556 | might or might not trigger a change to the primary orientation of the screen. |
557 | |
558 | Changes to this property will be filtered by orientationUpdateMask(), |
559 | so in order to receive orientation updates the application must first |
560 | call setOrientationUpdateMask() with a mask of the orientations it wants |
561 | to receive. |
562 | |
563 | Qt::PrimaryOrientation is never returned. |
564 | |
565 | \sa primaryOrientation() |
566 | */ |
567 | Qt::ScreenOrientation QScreen::orientation() const |
568 | { |
569 | Q_D(const QScreen); |
570 | return d->filteredOrientation; |
571 | } |
572 | |
573 | /*! |
574 | \property QScreen::refreshRate |
575 | \brief the approximate vertical refresh rate of the screen in Hz |
576 | */ |
577 | qreal QScreen::refreshRate() const |
578 | { |
579 | Q_D(const QScreen); |
580 | return d->refreshRate; |
581 | } |
582 | |
583 | /*! |
584 | \property QScreen::primaryOrientation |
585 | \brief the primary screen orientation |
586 | |
587 | The primary screen orientation is Qt::LandscapeOrientation |
588 | if the screen geometry's width is greater than or equal to its |
589 | height, or Qt::PortraitOrientation otherwise. This property might |
590 | change when the screen orientation was changed (i.e. when the |
591 | display is rotated). |
592 | The behavior is however platform dependent and can often be specified in |
593 | an application manifest file. |
594 | |
595 | */ |
596 | Qt::ScreenOrientation QScreen::primaryOrientation() const |
597 | { |
598 | Q_D(const QScreen); |
599 | return d->primaryOrientation; |
600 | } |
601 | |
602 | /*! |
603 | \property QScreen::nativeOrientation |
604 | \brief the native screen orientation |
605 | \since 5.2 |
606 | |
607 | The native orientation of the screen is the orientation where the logo |
608 | sticker of the device appears the right way up, or Qt::PrimaryOrientation |
609 | if the platform does not support this functionality. |
610 | |
611 | The native orientation is a property of the hardware, and does not change. |
612 | */ |
613 | Qt::ScreenOrientation QScreen::nativeOrientation() const |
614 | { |
615 | Q_D(const QScreen); |
616 | return d->platformScreen->nativeOrientation(); |
617 | } |
618 | |
619 | /*! |
620 | Convenience function to compute the angle of rotation to get from |
621 | rotation \a a to rotation \a b. |
622 | |
623 | The result will be 0, 90, 180, or 270. |
624 | |
625 | Qt::PrimaryOrientation is interpreted as the screen's primaryOrientation(). |
626 | */ |
627 | int QScreen::angleBetween(Qt::ScreenOrientation a, Qt::ScreenOrientation b) const |
628 | { |
629 | if (a == Qt::PrimaryOrientation) |
630 | a = primaryOrientation(); |
631 | |
632 | if (b == Qt::PrimaryOrientation) |
633 | b = primaryOrientation(); |
634 | |
635 | return QPlatformScreen::angleBetween(a, b); |
636 | } |
637 | |
638 | /*! |
639 | Convenience function to compute a transform that maps from the coordinate system |
640 | defined by orientation \a a into the coordinate system defined by orientation |
641 | \a b and target dimensions \a target. |
642 | |
643 | Example, \a a is Qt::Landscape, \a b is Qt::Portrait, and \a target is QRect(0, 0, w, h) |
644 | the resulting transform will be such that the point QPoint(0, 0) is mapped to QPoint(0, w), |
645 | and QPoint(h, w) is mapped to QPoint(0, h). Thus, the landscape coordinate system QRect(0, 0, h, w) |
646 | is mapped (with a 90 degree rotation) into the portrait coordinate system QRect(0, 0, w, h). |
647 | |
648 | Qt::PrimaryOrientation is interpreted as the screen's primaryOrientation(). |
649 | */ |
650 | QTransform QScreen::transformBetween(Qt::ScreenOrientation a, Qt::ScreenOrientation b, const QRect &target) const |
651 | { |
652 | if (a == Qt::PrimaryOrientation) |
653 | a = primaryOrientation(); |
654 | |
655 | if (b == Qt::PrimaryOrientation) |
656 | b = primaryOrientation(); |
657 | |
658 | return QPlatformScreen::transformBetween(a, b, target); |
659 | } |
660 | |
661 | /*! |
662 | Maps the rect between two screen orientations. |
663 | |
664 | This will flip the x and y dimensions of the rectangle \a{rect} if the orientation \a{a} is |
665 | Qt::PortraitOrientation or Qt::InvertedPortraitOrientation and orientation \a{b} is |
666 | Qt::LandscapeOrientation or Qt::InvertedLandscapeOrientation, or vice versa. |
667 | |
668 | Qt::PrimaryOrientation is interpreted as the screen's primaryOrientation(). |
669 | */ |
670 | QRect QScreen::mapBetween(Qt::ScreenOrientation a, Qt::ScreenOrientation b, const QRect &rect) const |
671 | { |
672 | if (a == Qt::PrimaryOrientation) |
673 | a = primaryOrientation(); |
674 | |
675 | if (b == Qt::PrimaryOrientation) |
676 | b = primaryOrientation(); |
677 | |
678 | return QPlatformScreen::mapBetween(a, b, rect); |
679 | } |
680 | |
681 | /*! |
682 | Convenience function that returns \c true if \a o is either portrait or inverted portrait; |
683 | otherwise returns \c false. |
684 | |
685 | Qt::PrimaryOrientation is interpreted as the screen's primaryOrientation(). |
686 | */ |
687 | bool QScreen::isPortrait(Qt::ScreenOrientation o) const |
688 | { |
689 | return o == Qt::PortraitOrientation || o == Qt::InvertedPortraitOrientation |
690 | || (o == Qt::PrimaryOrientation && primaryOrientation() == Qt::PortraitOrientation); |
691 | } |
692 | |
693 | /*! |
694 | Convenience function that returns \c true if \a o is either landscape or inverted landscape; |
695 | otherwise returns \c false. |
696 | |
697 | Qt::PrimaryOrientation is interpreted as the screen's primaryOrientation(). |
698 | */ |
699 | bool QScreen::isLandscape(Qt::ScreenOrientation o) const |
700 | { |
701 | return o == Qt::LandscapeOrientation || o == Qt::InvertedLandscapeOrientation |
702 | || (o == Qt::PrimaryOrientation && primaryOrientation() == Qt::LandscapeOrientation); |
703 | } |
704 | |
705 | /*! |
706 | \fn void QScreen::orientationChanged(Qt::ScreenOrientation orientation) |
707 | |
708 | This signal is emitted when the orientation of the screen |
709 | changes with \a orientation as an argument. |
710 | |
711 | \sa orientation() |
712 | */ |
713 | |
714 | /*! |
715 | \fn void QScreen::primaryOrientationChanged(Qt::ScreenOrientation orientation) |
716 | |
717 | This signal is emitted when the primary orientation of the screen |
718 | changes with \a orientation as an argument. |
719 | |
720 | \sa primaryOrientation() |
721 | */ |
722 | |
723 | void QScreenPrivate::updatePrimaryOrientation() |
724 | { |
725 | primaryOrientation = geometry.width() >= geometry.height() ? Qt::LandscapeOrientation : Qt::PortraitOrientation; |
726 | } |
727 | |
728 | /*! |
729 | Returns the screen at \a point within the set of \l QScreen::virtualSiblings(), |
730 | or \c nullptr if outside of any screen. |
731 | |
732 | The \a point is in relation to the virtualGeometry() of each set of virtual |
733 | siblings. |
734 | |
735 | \since 5.15 |
736 | */ |
737 | QScreen *QScreen::virtualSiblingAt(QPoint point) |
738 | { |
739 | const auto &siblings = virtualSiblings(); |
740 | for (QScreen *sibling : siblings) { |
741 | if (sibling->geometry().contains(p: point)) |
742 | return sibling; |
743 | } |
744 | return nullptr; |
745 | } |
746 | |
747 | /*! |
748 | Creates and returns a pixmap constructed by grabbing the contents |
749 | of the given \a window restricted by QRect(\a x, \a y, \a width, |
750 | \a height). |
751 | |
752 | The arguments (\a{x}, \a{y}) specify the offset in the window, |
753 | whereas (\a{width}, \a{height}) specify the area to be copied. If |
754 | \a width is negative, the function copies everything to the right |
755 | border of the window. If \a height is negative, the function |
756 | copies everything to the bottom of the window. |
757 | |
758 | The offset and size arguments are specified in device independent |
759 | pixels. The returned pixmap may be larger than the requested size |
760 | when grabbing from a high-DPI screen. Call QPixmap::devicePixelRatio() |
761 | to determine if this is the case. |
762 | |
763 | The window system identifier (\c WId) can be retrieved using the |
764 | QWidget::winId() function. The rationale for using a window |
765 | identifier and not a QWidget, is to enable grabbing of windows |
766 | that are not part of the application, window system frames, and so |
767 | on. |
768 | |
769 | \warning Grabbing windows that are not part of the application is |
770 | not supported on systems such as iOS, where sandboxing/security |
771 | prevents reading pixels of windows not owned by the application. |
772 | |
773 | The grabWindow() function grabs pixels from the screen, not from |
774 | the window, i.e. if there is another window partially or entirely |
775 | over the one you grab, you get pixels from the overlying window, |
776 | too. The mouse cursor is generally not grabbed. |
777 | |
778 | Note on X11 that if the given \a window doesn't have the same depth |
779 | as the root window, and another window partially or entirely |
780 | obscures the one you grab, you will \e not get pixels from the |
781 | overlying window. The contents of the obscured areas in the |
782 | pixmap will be undefined and uninitialized. |
783 | |
784 | On Windows Vista and above grabbing a layered window, which is |
785 | created by setting the Qt::WA_TranslucentBackground attribute, will |
786 | not work. Instead grabbing the desktop widget should work. |
787 | |
788 | \warning In general, grabbing an area outside the screen is not |
789 | safe. This depends on the underlying window system. |
790 | */ |
791 | |
792 | QPixmap QScreen::grabWindow(WId window, int x, int y, int width, int height) |
793 | { |
794 | const QPlatformScreen *platformScreen = handle(); |
795 | if (!platformScreen) { |
796 | qWarning(msg: "invoked with handle==0" ); |
797 | return QPixmap(); |
798 | } |
799 | const qreal factor = QHighDpiScaling::factor(context: this); |
800 | if (qFuzzyCompare(p1: factor, p2: 1)) |
801 | return platformScreen->grabWindow(window, x, y, width, height); |
802 | |
803 | const QPoint nativePos = QHighDpi::toNative(value: QPoint(x, y), scaleFactor: factor); |
804 | QSize nativeSize(width, height); |
805 | if (nativeSize.isValid()) |
806 | nativeSize = QHighDpi::toNative(value: nativeSize, scaleFactor: factor); |
807 | QPixmap result = |
808 | platformScreen->grabWindow(window, x: nativePos.x(), y: nativePos.y(), |
809 | width: nativeSize.width(), height: nativeSize.height()); |
810 | result.setDevicePixelRatio(result.devicePixelRatio() * factor); |
811 | return result; |
812 | } |
813 | |
814 | #ifndef QT_NO_DEBUG_STREAM |
815 | |
816 | static inline void formatRect(QDebug &debug, const QRect r) |
817 | { |
818 | debug << r.width() << 'x' << r.height() |
819 | << Qt::forcesign << r.x() << r.y() << Qt::noforcesign; |
820 | } |
821 | |
822 | Q_GUI_EXPORT QDebug operator<<(QDebug debug, const QScreen *screen) |
823 | { |
824 | const QDebugStateSaver saver(debug); |
825 | debug.nospace(); |
826 | debug << "QScreen(" << (const void *)screen; |
827 | if (screen) { |
828 | debug << ", name=" << screen->name(); |
829 | if (debug.verbosity() > 2) { |
830 | if (screen == QGuiApplication::primaryScreen()) |
831 | debug << ", primary" ; |
832 | debug << ", geometry=" ; |
833 | formatRect(debug, r: screen->geometry()); |
834 | debug << ", available=" ; |
835 | formatRect(debug, r: screen->availableGeometry()); |
836 | debug << ", logical DPI=" << screen->logicalDotsPerInchX() |
837 | << ',' << screen->logicalDotsPerInchY() |
838 | << ", physical DPI=" << screen->physicalDotsPerInchX() |
839 | << ',' << screen->physicalDotsPerInchY() |
840 | << ", devicePixelRatio=" << screen->devicePixelRatio() |
841 | << ", orientation=" << screen->orientation() |
842 | << ", physical size=" << screen->physicalSize().width() |
843 | << 'x' << screen->physicalSize().height() << "mm" ; |
844 | } |
845 | } |
846 | debug << ')'; |
847 | return debug; |
848 | } |
849 | #endif // !QT_NO_DEBUG_STREAM |
850 | |
851 | QT_END_NAMESPACE |
852 | |