Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qiosscreen.mm
Go to the documentation of this file.
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#undef QT_NO_FOREACH // this file contains unported legacy Q_FOREACH uses
5
6#include "qiosglobal.h"
7#include "qiosintegration.h"
8#include "qiosscreen.h"
9#include "qioswindow.h"
10#include <qpa/qwindowsysteminterface.h>
12#include "qiosviewcontroller.h"
13#include "quiview.h"
14#include "qiostheme.h"
15#include "quiwindow.h"
16
17#include <QtCore/private/qcore_mac_p.h>
18
19#include <QtGui/qpointingdevice.h>
20#include <QtGui/private/qwindow_p.h>
21#include <QtGui/private/qguiapplication_p.h>
22#include <private/qcoregraphics_p.h>
23#include <qpa/qwindowsysteminterface.h>
24
25#include <sys/sysctl.h>
26
27// -------------------------------------------------------------------------
28
29typedef void (^DisplayLinkBlock)(CADisplayLink *displayLink);
30
31@implementation UIScreen (DisplayLinkBlock)
32- (CADisplayLink*)displayLinkWithBlock:(DisplayLinkBlock)block
33{
34 return [self displayLinkWithTarget:[[block copy] autorelease]
35 selector:@selector(invokeDisplayLinkBlock:)];
36}
37@end
38
39@implementation NSObject (DisplayLinkBlock)
40- (void)invokeDisplayLinkBlock:(CADisplayLink *)sender
41{
42 DisplayLinkBlock block = static_cast<id>(self);
43 block(sender);
44}
45@end
46
47
48// -------------------------------------------------------------------------
49
50#if !defined(Q_OS_VISIONOS)
51static QIOSScreen* qtPlatformScreenFor(UIScreen *uiScreen)
52{
54 QIOSScreen *platformScreen = static_cast<QIOSScreen *>(screen->handle());
55 if (platformScreen->uiScreen() == uiScreen)
56 return platformScreen;
57 }
58
59 return 0;
60}
61
62@interface QIOSScreenTracker : NSObject
63@end
64
65@implementation QIOSScreenTracker
66
67+ (void)load
68{
69 NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
70 [center addObserver:self selector:@selector(screenConnected:)
71 name:UIScreenDidConnectNotification object:nil];
72 [center addObserver:self selector:@selector(screenDisconnected:)
73 name:UIScreenDidDisconnectNotification object:nil];
74 [center addObserver:self selector:@selector(screenModeChanged:)
75 name:UIScreenModeDidChangeNotification object:nil];
76}
77
78+ (void)screenConnected:(NSNotification*)notification
79{
81 return; // Will be added when QIOSIntegration is created
82
83 QWindowSystemInterface::handleScreenAdded(new QIOSScreen([notification object]));
84}
85
86+ (void)screenDisconnected:(NSNotification*)notification
87{
89 return;
90
91 QIOSScreen *screen = qtPlatformScreenFor([notification object]);
92 Q_ASSERT_X(screen, Q_FUNC_INFO, "Screen disconnected that we didn't know about");
93
95}
96
97+ (void)screenModeChanged:(NSNotification*)notification
98{
100 return;
101
102 QIOSScreen *screen = qtPlatformScreenFor([notification object]);
103 Q_ASSERT_X(screen, Q_FUNC_INFO, "Screen changed that we didn't know about");
104
105 screen->updateProperties();
106}
107
108@end
109
110#endif // !defined(Q_OS_VISIONOS)
111
112// -------------------------------------------------------------------------
113
115
116using namespace Qt::StringLiterals;
117
118#if !defined(Q_OS_VISIONOS)
123{
124#if TARGET_OS_SIMULATOR
125 return QString::fromLocal8Bit(qgetenv("SIMULATOR_MODEL_IDENTIFIER"));
126#else
127 static const char key[] = "hw.machine";
128
129 size_t size;
130 sysctlbyname(key, NULL, &size, NULL, 0);
131
132 char value[size];
133 sysctlbyname(key, &value, &size, NULL, 0);
134
136#endif
137}
138#endif // !defined(Q_OS_VISIONOS)
139
140#if defined(Q_OS_VISIONOS)
142{
143#else
145 : m_uiScreen(screen)
146{
147 QString deviceIdentifier = deviceModelIdentifier();
148
149 if (screen == [UIScreen mainScreen] && !deviceIdentifier.startsWith("AppleTV")) {
150 // Based on https://en.wikipedia.org/wiki/List_of_iOS_devices#Display
151
152 // iPhone (1st gen), 3G, 3GS, and iPod Touch (1st–3rd gen) are 18-bit devices
153 static QRegularExpression lowBitDepthDevices("^(iPhone1,[12]|iPhone2,1|iPod[1-3],1)$");
154 m_depth = deviceIdentifier.contains(lowBitDepthDevices) ? 18 : 24;
155
156 static QRegularExpression iPhoneXModels("^iPhone(10,[36])$");
157 static QRegularExpression iPhonePlusModels("^iPhone(7,1|8,2|9,[24]|10,[25])$");
158 static QRegularExpression iPadMiniModels("^iPad(2,[567]|4,[4-9]|5,[12])$");
159
160 if (deviceIdentifier.contains(iPhoneXModels)) {
161 m_physicalDpi = 458;
162 } else if (deviceIdentifier.contains(iPhonePlusModels)) {
163 m_physicalDpi = 401;
164 } else if (deviceIdentifier.startsWith("iPad")) {
165 if (deviceIdentifier.contains(iPadMiniModels))
166 m_physicalDpi = 163 * devicePixelRatio();
167 else
168 m_physicalDpi = 132 * devicePixelRatio();
169 } else {
170 // All normal iPhones, and iPods
171 m_physicalDpi = 163 * devicePixelRatio();
172 }
173 } else {
174 // External display, hard to say
175 m_depth = 24;
176 m_physicalDpi = 96;
177 }
178
179 m_displayLink = [m_uiScreen displayLinkWithBlock:^(CADisplayLink *) { deliverUpdateRequests(); }];
180 m_displayLink.paused = YES; // Enabled when clients call QWindow::requestUpdate()
181 [m_displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
182
183#endif // !defined(Q_OS_VISIONOS))
184
186}
187
189{
190 [m_displayLink invalidate];
191}
192
194{
195#if defined(Q_OS_VISIONOS)
196 return {};
197#else
198 if (m_uiScreen == [UIScreen mainScreen])
199 return QString::fromNSString([UIDevice currentDevice].model) + " built-in display"_L1;
200 else
201 return "External display"_L1;
202#endif
203}
204
206{
207 QRect previousGeometry = m_geometry;
208 QRect previousAvailableGeometry = m_availableGeometry;
209
210#if defined(Q_OS_VISIONOS)
211 // Based on what iPad app reports
212 m_geometry = QRect(0, 0, 1194, 834);
213 m_depth = 24;
214#else
215 m_geometry = QRectF::fromCGRect(m_uiScreen.bounds).toRect();
216
217 if (m_geometry != previousGeometry) {
218 // We can't use the primaryOrientation of screen(), as we haven't reported the new geometry yet
219 Qt::ScreenOrientation primaryOrientation = m_geometry.width() >= m_geometry.height() ?
221
222 // On iPhone 6+ devices, or when display zoom is enabled, the render buffer is scaled
223 // before being output on the physical display. We have to take this into account when
224 // computing the physical size. Note that unlike the native bounds, the physical size
225 // follows the primary orientation of the screen.
226 const QRectF physicalGeometry = mapBetween(nativeOrientation(), primaryOrientation, QRectF::fromCGRect(m_uiScreen.nativeBounds).toRect());
227
228 static const qreal millimetersPerInch = 25.4;
229 m_physicalSize = physicalGeometry.size() / m_physicalDpi * millimetersPerInch;
230 }
231
232#endif // defined(Q_OS_VISIONOS)
233
234 // UIScreen does not provide a consistent accessor for the safe area margins
235 // of the screen, and on visionOS we won't even have a UIScreen, so we report
236 // the available geometry of the screen to be the same as the full geometry.
237 // Safe area margins and maximized state is handled in QIOSWindow::setWindowState.
238 m_availableGeometry = m_geometry;
239
240 // At construction time, we don't yet have an associated QScreen, but we still want
241 // to compute the properties above so they are ready for when the QScreen attaches.
242 // Also, at destruction time the QScreen has already been torn down, so notifying
243 // Qt about changes to the screen will cause asserts in the event delivery system.
244 if (!screen())
245 return;
246
247 if (screen()->orientation() != orientation())
249
250 // Note: The screen orientation change and the geometry changes are not atomic, so when
251 // the former is emitted, the latter has not been reported and reflected in the QScreen
252 // API yet. But conceptually it makes sense that the orientation update happens first,
253 // and the geometry updates caused by auto-rotation happen after that.
254
255 if (m_geometry != previousGeometry || m_availableGeometry != previousAvailableGeometry)
256 QWindowSystemInterface::handleScreenGeometryChange(screen(), m_geometry, m_availableGeometry);
257}
258
260{
261 m_displayLink.paused = paused;
262}
263
264void QIOSScreen::deliverUpdateRequests() const
265{
266 bool pauseUpdates = true;
267
268 QList<QWindow*> windows = QGuiApplication::allWindows();
269 for (int i = 0; i < windows.size(); ++i) {
270 QWindow *window = windows.at(i);
271 if (platformScreenForWindow(window) != this)
272 continue;
273
274 QPlatformWindow *platformWindow = window->handle();
275 if (!platformWindow)
276 continue;
277
278 if (!platformWindow->hasPendingUpdateRequest())
279 continue;
280
281 platformWindow->deliverUpdateRequest();
282
283 // Another update request was triggered, keep the display link running
284 if (platformWindow->hasPendingUpdateRequest())
285 pauseUpdates = false;
286 }
287
288 // Pause the display link if there are no pending update requests
289 m_displayLink.paused = pauseUpdates;
290}
291
293{
294 return m_geometry;
295}
296
298{
299 return m_availableGeometry;
300}
301
303{
304 return m_depth;
305}
306
311
313{
314 return m_physicalSize;
315}
316
318{
319 return QDpi(72, 72);
320}
321
323{
324#if defined(Q_OS_VISIONOS)
325 return 2.0; // Based on what iPad app reports
326#else
327 return [m_uiScreen scale];
328#endif
329}
330
332{
333#if defined(Q_OS_VISIONOS)
334 return 120.0; // Based on what iPad app reports
335#else
336 return m_uiScreen.maximumFramesPerSecond;
337#endif
338}
339
341{
342#if defined(Q_OS_VISIONOS)
343 // Based on iPad app reporting native bounds 1668x2388
345#else
346 CGRect nativeBounds =
347#if defined(Q_OS_IOS)
348 m_uiScreen.nativeBounds;
349#else
350 m_uiScreen.bounds;
351#endif
352
353 // All known iOS devices have a native orientation of portrait, but to
354 // be on the safe side we compare the width and height of the bounds.
355 return nativeBounds.size.width >= nativeBounds.size.height ?
357#endif
358}
359
361{
362 // We don't report UIDevice.currentDevice.orientation here,
363 // as that would report the actual orientation of the device,
364 // even if the orientation of the UI was locked to a subset
365 // of the possible orientations via the app's Info.plist or
366 // via [UIViewController supportedInterfaceOrientations].
367 return m_geometry.width() >= m_geometry.height() ?
369}
370
371QPixmap QIOSScreen::grabWindow(WId window, int x, int y, int width, int height) const
372{
373 if (window && ![reinterpret_cast<id>(window) isKindOfClass:[UIView class]])
374 return QPixmap();
375
376 UIView *view = window ? reinterpret_cast<UIView *>(window)
378
379 if (width < 0)
380 width = qMax(view.bounds.size.width - x, CGFloat(0));
381 if (height < 0)
382 height = qMax(view.bounds.size.height - y, CGFloat(0));
383
384 CGRect captureRect = [view.window convertRect:CGRectMake(x, y, width, height) fromView:view];
385 captureRect = CGRectIntersection(captureRect, view.window.bounds);
386
387 UIGraphicsBeginImageContextWithOptions(captureRect.size, NO, 0.0);
388 CGContextRef context = UIGraphicsGetCurrentContext();
389 CGContextTranslateCTM(context, -captureRect.origin.x, -captureRect.origin.y);
390
391 // Draws the complete view hierarchy of view.window into the given rect, which
392 // needs to be the same aspect ratio as the view.window's size. Since we've
393 // translated the graphics context, and are potentially drawing into a smaller
394 // context than the full window, the resulting image will be a subsection of the
395 // full screen.
396 [view.window drawViewHierarchyInRect:view.window.bounds afterScreenUpdates:NO];
397
398 UIImage *screenshot = UIGraphicsGetImageFromCurrentImageContext();
399 UIGraphicsEndImageContext();
400
401 return QPixmap::fromImage(qt_mac_toQImage(screenshot.CGImage));
402}
403
404#if !defined(Q_OS_VISIONOS)
405UIScreen *QIOSScreen::uiScreen() const
406{
407 return m_uiScreen;
408}
409#endif
410
412
413#include "moc_qiosscreen.cpp"
static QWindowList allWindows()
Returns a list of all the windows in the application.
static QList< QScreen * > screens()
Returns a list of all the screens associated with the windowing system the application is connected t...
static QIOSIntegration * instance()
qreal devicePixelRatio() const override
Reimplement this function in subclass to return the device pixel ratio for the screen.
void setUpdatesPaused(bool)
int depth() const override
Reimplement in subclass to return current depth of the screen.
QRect availableGeometry() const override
Reimplement in subclass to return the pixel geometry of the available space This normally is the desk...
Qt::ScreenOrientation nativeOrientation() const override
Reimplement this function in subclass to return the native orientation of the screen,...
QIOSScreen(UIScreen *screen)
void updateProperties()
qreal refreshRate() const override
Reimplement this function in subclass to return the vertical refresh rate of the screen,...
QImage::Format format() const override
Reimplement in subclass to return the image format which corresponds to the screen format.
QSizeF physicalSize() const override
Reimplement this function in subclass to return the physical size of the screen, in millimeters.
QRect geometry() const override
Reimplement in subclass to return the pixel geometry of the screen.
Qt::ScreenOrientation orientation() const override
Reimplement this function in subclass to return the current orientation of the screen,...
QDpi logicalBaseDpi() const override
Reimplement to return the base logical DPI for the platform.
QPixmap grabWindow(WId window, int x, int y, int width, int height) const override
This function is called when Qt needs to be able to grab the content of a window.
UIScreen * uiScreen() const
QString name() const override
Format
The following image formats are available in Qt.
Definition qimage.h:41
@ Format_ARGB32_Premultiplied
Definition qimage.h:48
qsizetype size() const noexcept
Definition qlist.h:397
Returns a copy of the pixmap that is transformed using the given transformation transform and transfo...
Definition qpixmap.h:27
static QPixmap fromImage(const QImage &image, Qt::ImageConversionFlags flags=Qt::AutoColor)
Converts the given image to a pixmap using the specified flags to control the conversion.
Definition qpixmap.cpp:1437
static QRect mapBetween(Qt::ScreenOrientation a, Qt::ScreenOrientation b, const QRect &rect)
QScreen * screen() const
QWindowList windows() const
Return all windows residing on this screen.
virtual QString model() const
Reimplement this function in subclass to return the model of this screen.
The QPlatformWindow class provides an abstraction for top-level windows.
bool hasPendingUpdateRequest() const
Returns true if the window has a pending update request.
virtual void deliverUpdateRequest()
Delivers an QEvent::UpdateRequest event to the window.
\inmodule QtCore\reentrant
Definition qrect.h:484
\inmodule QtCore\reentrant
Definition qrect.h:30
constexpr int height() const noexcept
Returns the height of the rectangle.
Definition qrect.h:239
constexpr int width() const noexcept
Returns the width of the rectangle.
Definition qrect.h:236
\inmodule QtCore \reentrant
The QScreen class is used to query screen properties. \inmodule QtGui.
Definition qscreen.h:32
QPlatformScreen * handle() const
Get the platform screen handle.
Definition qscreen.cpp:83
\inmodule QtCore
Definition qsize.h:208
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
static QString fromLatin1(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5871
static QString fromLocal8Bit(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5949
static void handleScreenGeometryChange(QScreen *screen, const QRect &newGeometry, const QRect &newAvailableGeometry)
static void handleScreenAdded(QPlatformScreen *screen, bool isPrimary=false)
Should be called by the implementation whenever a new screen is added.
static void handleScreenRemoved(QPlatformScreen *screen)
Should be called by the implementation whenever a screen is removed.
static void handleScreenOrientationChange(QScreen *screen, Qt::ScreenOrientation newOrientation)
\inmodule QtGui
Definition qwindow.h:63
int width
the width of the window's geometry
Definition qwindow.h:82
int height
the height of the window's geometry
Definition qwindow.h:83
p1 load("image.bmp")
Combined button and popup list for selecting options.
ScreenOrientation
Definition qnamespace.h:271
@ LandscapeOrientation
Definition qnamespace.h:274
@ PortraitOrientation
Definition qnamespace.h:273
static void * context
float CGFloat
#define Q_FUNC_INFO
QImage qt_mac_toQImage(CGImageRef image)
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char return DBusMessage return DBusMessage const char return DBusMessage dbus_bool_t return DBusMessage dbus_uint32_t return DBusMessage void
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
QPair< qreal, qreal > QDpi
UIView * rootViewForScreen(QScreen *)
static QString deviceModelIdentifier()
Returns the model identifier of the device.
void(^ DisplayLinkBlock)(CADisplayLink *displayLink)
Definition qiosscreen.mm:29
static QIOSScreen * qtPlatformScreenFor(UIScreen *uiScreen)
Definition qiosscreen.mm:51
constexpr const T & qMax(const T &a, const T &b)
Definition qminmax.h:42
GLint GLint GLint GLint GLint x
[0]
GLuint64 key
GLint GLsizei GLsizei height
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLint GLsizei width
GLint y
struct CGContext * CGContextRef
#define Q_ASSERT_X(cond, x, msg)
Definition qrandom.cpp:48
QScreen * screen
[1]
Definition main.cpp:29
Q_CORE_EXPORT QByteArray qgetenv(const char *varName)
ptrdiff_t qsizetype
Definition qtypes.h:165
double qreal
Definition qtypes.h:187
aWidget window() -> setWindowTitle("New Window Title")
[2]
QQuickView * view
[0]