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