Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qiosviewcontroller.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#include "qiosglobal.h"
6
7#include <QtCore/qscopedvaluerollback.h>
8#include <QtCore/private/qcore_mac_p.h>
9#include <QtGui/private/qapplekeymapper_p.h>
10
11#include <QtGui/QGuiApplication>
12#include <QtGui/QWindow>
13#include <QtGui/QScreen>
14
15#include <QtGui/private/qwindow_p.h>
16#include <QtGui/private/qguiapplication_p.h>
17
18#include "qiosintegration.h"
19#include "qiosscreen.h"
20#include "qiosglobal.h"
21#include "qioswindow.h"
22#include "quiview.h"
23
24// -------------------------------------------------------------------------
25
26@interface QIOSViewController ()
28@property (nonatomic, assign) BOOL changingOrientation;
29@end
30
31// -------------------------------------------------------------------------
32
33@interface QIOSDesktopManagerView : UIView
34@end
35
36@implementation QIOSDesktopManagerView
37
38- (instancetype)init
39{
40 if (!(self = [super init]))
41 return nil;
42
43 if (qEnvironmentVariableIntValue("QT_IOS_DEBUG_WINDOW_MANAGEMENT")) {
44 static UIImage *gridPattern = nil;
45 static dispatch_once_t onceToken;
46 dispatch_once(&onceToken, ^{
47 CGFloat dimension = 100.f;
48
49 UIGraphicsBeginImageContextWithOptions(CGSizeMake(dimension, dimension), YES, 0.0f);
50 CGContextRef context = UIGraphicsGetCurrentContext();
51
52 CGContextTranslateCTM(context, -0.5, -0.5);
53
54 #define gridColorWithBrightness(br) \
55 [UIColor colorWithHue:0.6 saturation:0.0 brightness:br alpha:1.0].CGColor
56
57 CGContextSetFillColorWithColor(context, gridColorWithBrightness(0.05));
58 CGContextFillRect(context, CGRectMake(0, 0, dimension, dimension));
59
60 CGFloat gridLines[][2] = { { 10, 0.1 }, { 20, 0.2 }, { 100, 0.3 } };
61 for (size_t l = 0; l < sizeof(gridLines) / sizeof(gridLines[0]); ++l) {
62 CGFloat step = gridLines[l][0];
63 for (int c = step; c <= dimension; c += step) {
64 CGContextMoveToPoint(context, c, 0);
65 CGContextAddLineToPoint(context, c, dimension);
66 CGContextMoveToPoint(context, 0, c);
67 CGContextAddLineToPoint(context, dimension, c);
68 }
69
70 CGFloat brightness = gridLines[l][1];
71 CGContextSetStrokeColorWithColor(context, gridColorWithBrightness(brightness));
72 CGContextStrokePath(context);
73 }
74
75 gridPattern = UIGraphicsGetImageFromCurrentImageContext();
76 UIGraphicsEndImageContext();
77
78 [gridPattern retain];
79 });
80
81 self.backgroundColor = [UIColor colorWithPatternImage:gridPattern];
82 }
83
84 return self;
85}
86
87- (void)didAddSubview:(UIView *)subview
88{
89 Q_UNUSED(subview);
90
91 QT_PREPEND_NAMESPACE(QIOSScreen) *screen = self.qtViewController.platformScreen;
92
93 // The 'window' property of our view is not valid until the window
94 // has been shown, so we have to access it through the QIOSScreen.
95 UIWindow *uiWindow = screen->uiWindow();
96
97 if (uiWindow.hidden) {
98 // Associate UIWindow to screen and show it the first time a QWindow
99 // is mapped to the screen. For external screens this means disabling
100 // mirroring mode and presenting alternate content on the screen.
101 uiWindow.screen = screen->uiScreen();
102 uiWindow.hidden = NO;
103 }
104}
105
106- (void)willRemoveSubview:(UIView *)subview
107{
108 Q_UNUSED(subview);
109
110 Q_ASSERT(self.window);
111 UIWindow *uiWindow = self.window;
112
113 if (uiWindow.screen != [UIScreen mainScreen] && self.subviews.count == 1) {
114 // We're about to remove the last view of an external screen, so go back
115 // to mirror mode, but defer it until after the view has been removed,
116 // to ensure that we don't try to layout the view that's being removed.
117 dispatch_async(dispatch_get_main_queue(), ^{
118 uiWindow.hidden = YES;
119 uiWindow.screen = [UIScreen mainScreen];
120 });
121 }
122}
123
124- (void)layoutSubviews
125{
127 // Despite the OpenGL ES Programming Guide telling us to avoid all
128 // use of OpenGL while in the background, iOS will perform its view
129 // snapshotting for the app switcher after the application has been
130 // backgrounded; once for each orientation. Presumably the expectation
131 // is that no rendering needs to be done to provide an alternate
132 // orientation snapshot, just relayouting of views. But in our case,
133 // or any non-stretchable content case such as a OpenGL based game,
134 // this is not true. Instead of continuing layout, which will send
135 // potentially expensive geometry changes (with isExposed false,
136 // since we're in the background), we short-circuit the snapshotting
137 // here. iOS will still use the latest rendered frame to create the
138 // application switcher thumbnail, but it will be based on the last
139 // active orientation of the application.
140 QIOSScreen *screen = self.qtViewController.platformScreen;
141 qCDebug(lcQpaWindow) << "ignoring layout of subviews while suspended,"
142 << "likely system snapshot of" << screen->screen()->primaryOrientation();
143 return;
144 }
145
146 for (int i = int(self.subviews.count) - 1; i >= 0; --i) {
147 UIView *view = static_cast<UIView *>([self.subviews objectAtIndex:i]);
148 if (![view isKindOfClass:[QUIView class]])
149 continue;
150
151 [self layoutView: static_cast<QUIView *>(view)];
152 }
153}
154
155- (void)layoutView:(QUIView *)view
156{
157 QWindow *window = view.qwindow;
158
159 // Return early if the QIOSWindow is still constructing, as we'll
160 // take care of setting the correct window state in the constructor.
161 if (!window->handle())
162 return;
163
164 // Re-apply window states to update geometry
165 if (window->windowStates() & (Qt::WindowFullScreen | Qt::WindowMaximized))
166 window->handle()->setWindowState(window->windowStates());
167}
168
169// Even if the root view controller has both wantsFullScreenLayout and
170// extendedLayoutIncludesOpaqueBars enabled, iOS will still push the root
171// view down 20 pixels (and shrink the view accordingly) when the in-call
172// statusbar is active (instead of updating the topLayoutGuide). Since
173// we treat the root view controller as our screen, we want to reflect
174// the in-call statusbar as a change in available geometry, not in screen
175// geometry. To simplify the screen geometry mapping code we reset the
176// view modifications that iOS does and take the statusbar height
177// explicitly into account in QIOSScreen::updateProperties().
178
179- (void)setFrame:(CGRect)newFrame
180{
181 Q_UNUSED(newFrame);
182 Q_ASSERT(!self.window || self.window.rootViewController.view == self);
183
184 // When presenting view controllers our view may be temporarily reparented into a UITransitionView
185 // instead of the UIWindow, and the UITransitionView may have a transform set, so we need to do a
186 // mapping even if we still expect to always be the root view-controller.
187 CGRect transformedWindowBounds = [self.superview convertRect:self.window.bounds fromView:self.window];
188 [super setFrame:transformedWindowBounds];
189}
190
191- (void)setBounds:(CGRect)newBounds
192{
193 Q_UNUSED(newBounds);
194 CGRect transformedWindowBounds = [self convertRect:self.window.bounds fromView:self.window];
195 [super setBounds:CGRectMake(0, 0, CGRectGetWidth(transformedWindowBounds), CGRectGetHeight(transformedWindowBounds))];
196}
197
198- (void)setCenter:(CGPoint)newCenter
199{
200 Q_UNUSED(newCenter);
201 [super setCenter:self.window.center];
202}
203
204- (void)didMoveToWindow
205{
206 // The initial frame computed during startup may happen before the view has
207 // a window, meaning our calculations above will be wrong. We ensure that the
208 // frame is set correctly once we have a window to base our calculations on.
209 [self setFrame:self.window.bounds];
210}
211
212@end
213
214// -------------------------------------------------------------------------
215
216@implementation QIOSViewController {
217 BOOL m_updatingProperties;
220}
221
222#ifndef Q_OS_TVOS
223@synthesize prefersStatusBarHidden;
224@synthesize preferredStatusBarUpdateAnimation;
225@synthesize preferredStatusBarStyle;
226#endif
227
228- (instancetype)initWithQIOSScreen:(QT_PREPEND_NAMESPACE(QIOSScreen) *)screen
229{
230 if (self = [self init]) {
231 self.platformScreen = screen;
232
233 self.changingOrientation = NO;
234#ifndef Q_OS_TVOS
235 self.lockedOrientation = UIInterfaceOrientationUnknown;
236
237 // Status bar may be initially hidden at startup through Info.plist
238 self.prefersStatusBarHidden = infoPlistValue(@"UIStatusBarHidden", false);
239 self.preferredStatusBarUpdateAnimation = UIStatusBarAnimationNone;
240 self.preferredStatusBarStyle = UIStatusBarStyle(infoPlistValue(@"UIStatusBarStyle", UIStatusBarStyleDefault));
241#endif
242
244 [self updateProperties];
245 });
246
251 // We may have ignored an earlier layout because the application was suspended,
252 // and we didn't want to render anything at that moment in fear of being killed
253 // due to rendering in the background, so we trigger an explicit layout when
254 // coming out of the suspended state.
255 qCDebug(lcQpaWindow) << "triggering root VC layout when coming out of suspended state";
256 [self.view setNeedsLayout];
257 }
258 }
259 );
260 }
261
262 return self;
263}
264
265- (void)dealloc
266{
269 [super dealloc];
270}
271
272- (void)loadView
273{
274 self.view = [[[QIOSDesktopManagerView alloc] init] autorelease];
275}
276
277- (void)viewDidLoad
278{
279 [super viewDidLoad];
280
282
283#ifndef Q_OS_TVOS
284 NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
285 [center addObserver:self selector:@selector(willChangeStatusBarFrame:)
286 name:UIApplicationWillChangeStatusBarFrameNotification
287 object:qt_apple_sharedApplication()];
288
289 [center addObserver:self selector:@selector(didChangeStatusBarOrientation:)
290 name:UIApplicationDidChangeStatusBarOrientationNotification
291 object:qt_apple_sharedApplication()];
292#endif
293}
294
295- (void)viewDidUnload
296{
297 [[NSNotificationCenter defaultCenter] removeObserver:self name:nil object:nil];
298 [super viewDidUnload];
299}
300
301// -------------------------------------------------------------------------
302
303- (BOOL)shouldAutorotate
304{
305#ifndef Q_OS_TVOS
306 return self.platformScreen && self.platformScreen->uiScreen() == [UIScreen mainScreen] && !self.lockedOrientation;
307#else
308 return NO;
309#endif
310}
311
312- (NSUInteger)supportedInterfaceOrientations
313{
314 // As documented by Apple in the iOS 6.0 release notes, setStatusBarOrientation:animated:
315 // only works if the supportedInterfaceOrientations of the view controller is 0, making
316 // us responsible for ensuring that the status bar orientation is consistent. We enter
317 // this mode when auto-rotation is disabled due to an explicit content orientation being
318 // set on the focus window. Note that this is counter to what the documentation for
319 // supportedInterfaceOrientations says, which states that the method should not return 0.
320 return [self shouldAutorotate] ? UIInterfaceOrientationMaskAll : 0;
321}
322
323- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)orientation duration:(NSTimeInterval)duration
324{
325 self.changingOrientation = YES;
326
327 [super willRotateToInterfaceOrientation:orientation duration:duration];
328}
329
330- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)orientation
331{
332 self.changingOrientation = NO;
333
334 [super didRotateFromInterfaceOrientation:orientation];
335}
336
337- (void)willChangeStatusBarFrame:(NSNotification*)notification
338{
339 Q_UNUSED(notification);
340
341 if (self.view.window.screen != [UIScreen mainScreen])
342 return;
343
344 // Orientation changes will already result in laying out subviews, so we don't
345 // need to do anything extra for frame changes during an orientation change.
346 // Technically we can receive another actual statusbar frame update during the
347 // orientation change that we should react to, but to simplify the logic we
348 // use a simple bool variable instead of a ignoreNextFrameChange approach.
349 if (self.changingOrientation)
350 return;
351
352 // UIKit doesn't have a delegate callback for statusbar changes that's run inside the
353 // animation block, like UIViewController's willAnimateRotationToInterfaceOrientation,
354 // nor does it expose a constant for the duration and easing of the animation. However,
355 // though poking at the various UIStatusBar methods, we can observe that the animation
356 // uses the default easing curve, and runs with a duration of 0.35 seconds.
357 static qreal kUIStatusBarAnimationDuration = 0.35;
358
359 [UIView animateWithDuration:kUIStatusBarAnimationDuration animations:^{
360 [self.view setNeedsLayout];
361 [self.view layoutIfNeeded];
362 }];
363}
364
365- (void)didChangeStatusBarOrientation:(NSNotification *)notification
366{
367 Q_UNUSED(notification);
368
369 if (self.view.window.screen != [UIScreen mainScreen])
370 return;
371
372 // If the statusbar changes orientation due to auto-rotation we don't care,
373 // there will be re-layout anyways. Only if the statusbar changes due to
374 // reportContentOrientation, we need to update the window layout.
375 if (self.changingOrientation)
376 return;
377
378 [self.view setNeedsLayout];
379}
380
381- (void)viewWillLayoutSubviews
382{
384 return;
385
386 if (self.platformScreen)
387 self.platformScreen->updateProperties();
388}
389
390// -------------------------------------------------------------------------
391
392- (void)updateProperties
393{
394 if (!isQtApplication())
395 return;
396
397 if (!self.platformScreen || !self.platformScreen->screen())
398 return;
399
400 // For now we only care about the main screen, as both the statusbar
401 // visibility and orientation is only appropriate for the main screen.
402 if (self.platformScreen->uiScreen() != [UIScreen mainScreen])
403 return;
404
405 // Prevent recursion caused by updating the status bar appearance (position
406 // or visibility), which in turn may cause a layout of our subviews, and
407 // a reset of window-states, which themselves affect the view controller
408 // properties such as the statusbar visibility.
409 if (m_updatingProperties)
410 return;
411
412 QScopedValueRollback<BOOL> updateRollback(m_updatingProperties, YES);
413
414 QWindow *focusWindow = QGuiApplication::focusWindow();
415
416 // If we don't have a focus window we leave the statusbar
417 // as is, so that the user can activate a new window with
418 // the same window state without the status bar jumping
419 // back and forth.
420 if (!focusWindow)
421 return;
422
423 // We only care about changes to focusWindow that involves our screen
424 if (!focusWindow->screen() || focusWindow->screen()->handle() != self.platformScreen)
425 return;
426
427 // All decisions are based on the top level window
428 focusWindow = qt_window_private(focusWindow)->topLevelWindow();
429
430#ifndef Q_OS_TVOS
431
432 // -------------- Status bar style and visbility ---------------
433
434 UIStatusBarStyle oldStatusBarStyle = self.preferredStatusBarStyle;
436 self.preferredStatusBarStyle = UIStatusBarStyleDefault;
437 else
438 self.preferredStatusBarStyle = UIStatusBarStyleLightContent;
439
440 if (self.preferredStatusBarStyle != oldStatusBarStyle)
441 [self setNeedsStatusBarAppearanceUpdate];
442
443 bool currentStatusBarVisibility = self.prefersStatusBarHidden;
444 self.prefersStatusBarHidden = focusWindow->windowState() == Qt::WindowFullScreen;
445
446 if (self.prefersStatusBarHidden != currentStatusBarVisibility) {
447 [self setNeedsStatusBarAppearanceUpdate];
448 [self.view setNeedsLayout];
449 }
450
451
452 // -------------- Content orientation ---------------
453
454 UIApplication *uiApplication = qt_apple_sharedApplication();
455
456 static BOOL kAnimateContentOrientationChanges = YES;
457
458 Qt::ScreenOrientation contentOrientation = focusWindow->contentOrientation();
459 if (contentOrientation != Qt::PrimaryOrientation) {
460 // An explicit content orientation has been reported for the focus window,
461 // so we keep the status bar in sync with content orientation. This will ensure
462 // that the task bar (and associated gestures) are also rotated accordingly.
463
464 if (!self.lockedOrientation) {
465 // We are moving from Qt::PrimaryOrientation to an explicit orientation,
466 // so we need to store the current statusbar orientation, as we need it
467 // later when mapping screen coordinates for QScreen and for returning
468 // to Qt::PrimaryOrientation.
469 self.lockedOrientation = uiApplication.statusBarOrientation;
470 }
471
472 [uiApplication setStatusBarOrientation:
473 UIInterfaceOrientation(fromQtScreenOrientation(contentOrientation))
474 animated:kAnimateContentOrientationChanges];
475
476 } else {
477 // The content orientation is set to Qt::PrimaryOrientation, meaning
478 // that auto-rotation should be enabled. But we may be coming out of
479 // a state of locked orientation, which needs some cleanup before we
480 // can enable auto-rotation again.
481 if (self.lockedOrientation) {
482 // First we need to restore the statusbar to what it was at the
483 // time of locking the orientation, otherwise iOS will be very
484 // confused when it starts doing auto-rotation again.
485 [uiApplication setStatusBarOrientation:self.lockedOrientation
486 animated:kAnimateContentOrientationChanges];
487
488 // Then we can re-enable auto-rotation
489 self.lockedOrientation = UIInterfaceOrientationUnknown;
490
491 // And finally let iOS rotate the root view to match the device orientation
492 [UIViewController attemptRotationToDeviceOrientation];
493 }
494 }
495#endif
496}
497
498- (NSArray*)keyCommands
499{
500 // FIXME: If we are on iOS 13.4 or later we can use UIKey instead of doing this
501 // So it should be safe to remove this entire function and handleShortcut() as
502 // a result
503 NSMutableArray<UIKeyCommand *> *keyCommands = nil;
504 QShortcutMap &shortcutMap = QGuiApplicationPrivate::instance()->shortcutMap;
505 keyCommands = [[NSMutableArray<UIKeyCommand *> alloc] init];
506 const QList<QKeySequence> keys = shortcutMap.keySequences();
507 for (const QKeySequence &seq : keys) {
508 const QString keyString = seq.toString();
509 [keyCommands addObject:[UIKeyCommand
510 keyCommandWithInput:QString(keyString[keyString.length() - 1]).toNSString()
511 modifierFlags:QAppleKeyMapper::toUIKitModifiers(seq[0].keyboardModifiers())
512 action:@selector(handleShortcut:)]];
513 }
514 return keyCommands;
515}
516
517- (void)handleShortcut:(UIKeyCommand *)keyCommand
518{
519 const QString str = QString::fromNSString([keyCommand input]);
520 Qt::KeyboardModifiers qtMods = QAppleKeyMapper::fromUIKitModifiers(keyCommand.modifierFlags);
521 QChar ch = str.isEmpty() ? QChar() : str.at(0);
522 QShortcutMap &shortcutMap = QGuiApplicationPrivate::instance()->shortcutMap;
523 QKeyEvent keyEvent(QEvent::ShortcutOverride, Qt::Key(ch.toUpper().unicode()), qtMods, str);
524 shortcutMap.tryShortcut(&keyEvent);
525}
526
527
528
529@end
530
QPointer< QT_PREPEND_NAMESPACE(QIOSScreen)> platformScreen
static Qt::KeyboardModifiers fromUIKitModifiers(ulong uikitModifiers)
\inmodule QtCore
Definition qchar.h:48
static QCoreApplication * instance() noexcept
Returns a pointer to the application's QCoreApplication (or QGuiApplication/QApplication) instance.
@ ShortcutOverride
Definition qcoreevent.h:158
static QGuiApplicationPrivate * instance()
static Qt::ApplicationState applicationState()
static QWindow * focusWindow()
Returns the QWindow that receives events tied to focus, such as key events.
void focusWindowChanged(QWindow *focusWindow)
This signal is emitted when the focused window changes.
void applicationStateDidChange(Qt::ApplicationState oldState, Qt::ApplicationState newState)
QIOSApplicationState applicationState
static QIOSIntegration * instance()
The QKeyEvent class describes a key event.
Definition qevent.h:423
The QKeySequence class encapsulates a key sequence as used by shortcuts.
Definition qlist.h:74
\inmodule QtCore Represents a handle to a signal-slot (or signal-functor) connection.
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2823
static bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *member)
\threadsafe
Definition qobject.cpp:3099
\inmodule QtCore
Definition qpointer.h:18
Qt::ScreenOrientation primaryOrientation
the primary screen orientation
Definition qscreen.h:61
QPlatformScreen * handle() const
Get the platform screen handle.
Definition qscreen.cpp:83
bool tryShortcut(QKeyEvent *e)
QList< QKeySequence > keySequences(bool getAll=false) const
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:1083
qsizetype count(QChar c, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Definition qstring.cpp:4732
QWindow * topLevelWindow(QWindow::AncestorMode mode=QWindow::IncludeTransients) const
Definition qwindow.cpp:2869
\inmodule QtGui
Definition qwindow.h:63
Qt::WindowFlags flags
the window flags of the window
Definition qwindow.h:79
Qt::ScreenOrientation contentOrientation
the orientation of the window's contents
Definition qwindow.h:95
QString str
[2]
void newState(QList< State > &states, const char *token, const char *lexem, bool pre)
@ WindowFullScreen
Definition qnamespace.h:254
@ WindowMaximized
Definition qnamespace.h:253
ScreenOrientation
Definition qnamespace.h:270
@ PrimaryOrientation
Definition qnamespace.h:271
ApplicationState
Definition qnamespace.h:261
@ ApplicationSuspended
Definition qnamespace.h:262
QTextStream & center(QTextStream &stream)
Calls QTextStream::setFieldAlignment(QTextStream::AlignCenter) on stream and returns stream.
@ MaximizeUsingFullscreenGeometryHint
Definition qnamespace.h:236
QString self
Definition language.cpp:57
static void * context
float CGFloat
unsigned long NSUInteger
bool qt_apple_isApplicationExtension()
Definition qcore_mac.mm:423
AppleApplication * qt_apple_sharedApplication()
Definition qcore_mac.mm:430
#define qApp
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
int infoPlistValue(NSString *key, int defaultValue)
Definition qiosglobal.mm:81
bool isQtApplication()
Definition qiosglobal.mm:17
#define gridColorWithBrightness(br)
QMetaObject::Connection m_appStateChangedConnection
QMetaObject::Connection m_focusWindowChangeConnection
#define qCDebug(category,...)
const GLubyte * c
GLenum GLenum GLenum input
struct CGContext * CGContextRef
static QString keyString(int sym, QChar::Category category)
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
QScreen * screen
[1]
Definition main.cpp:29
Q_CORE_EXPORT int qEnvironmentVariableIntValue(const char *varName, bool *ok=nullptr) noexcept
static QT_BEGIN_NAMESPACE void init(QTextBoundaryFinder::BoundaryType type, QStringView str, QCharAttributes *attributes)
#define Q_UNUSED(x)
double qreal
Definition qtypes.h:92
Q_GUI_EXPORT QWindowPrivate * qt_window_private(QWindow *window)
Definition qwindow.cpp:2864
QT_END_NAMESPACE typedef QT_PREPEND_NAMESPACE(quintptr) WId
QStringList keys
aWidget window() -> setWindowTitle("New Window Title")
[2]
QAction * at
QQuickView * view
[0]