1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Copyright (C) 2016 Intel Corporation.
5 ** Contact: https://www.qt.io/licensing/
6 **
7 ** This file is part of the QtGui module of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** Commercial License Usage
11 ** Licensees holding valid commercial Qt licenses may use this file in
12 ** accordance with the commercial license agreement provided with the
13 ** Software or, alternatively, in accordance with the terms contained in
14 ** a written agreement between you and The Qt Company. For licensing terms
15 ** and conditions see https://www.qt.io/terms-conditions. For further
16 ** information use the contact form at https://www.qt.io/contact-us.
17 **
18 ** GNU Lesser General Public License Usage
19 ** Alternatively, this file may be used under the terms of the GNU Lesser
20 ** General Public License version 3 as published by the Free Software
21 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
22 ** packaging of this file. Please review the following information to
23 ** ensure the GNU Lesser General Public License version 3 requirements
24 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
25 **
26 ** GNU General Public License Usage
27 ** Alternatively, this file may be used under the terms of the GNU
28 ** General Public License version 2.0 or (at your option) the GNU General
29 ** Public license version 3 or any later version approved by the KDE Free
30 ** Qt Foundation. The licenses are as published by the Free Software
31 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
32 ** included in the packaging of this file. Please review the following
33 ** information to ensure the GNU General Public License requirements will
34 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
35 ** https://www.gnu.org/licenses/gpl-3.0.html.
36 **
37 ** $QT_END_LICENSE$
38 **
39 ****************************************************************************/
40
41 #include "qguiapplication.h"
42
43 #include "private/qguiapplication_p.h"
44 #include <qpa/qplatformintegrationfactory_p.h>
45 #include "private/qevent_p.h"
46 #include "qfont.h"
47 #include "qtouchdevice.h"
48 #include <qpa/qplatformfontdatabase.h>
49 #include <qpa/qplatformwindow.h>
50 #include <qpa/qplatformnativeinterface.h>
51 #include <qpa/qplatformtheme.h>
52 #include <qpa/qplatformintegration.h>
53
54 #include <QtCore/QAbstractEventDispatcher>
55 #include <QtCore/QStandardPaths>
56 #include <QtCore/QVariant>
57 #include <QtCore/private/qcoreapplication_p.h>
58 #include <QtCore/private/qabstracteventdispatcher_p.h>
59 #include <QtCore/qmutex.h>
60 #include <QtCore/private/qthread_p.h>
61 #include <QtCore/private/qlocking_p.h>
62 #include <QtCore/qdir.h>
63 #include <QtCore/qlibraryinfo.h>
64 #include <QtCore/qnumeric.h>
65 #include <QtDebug>
66 #ifndef QT_NO_ACCESSIBILITY
67 #include "qaccessible.h"
68 #endif
69 #include <qpalette.h>
70 #include <qscreen.h>
71 #include "qsessionmanager.h"
72 #include <private/qcolortrclut_p.h>
73 #include <private/qscreen_p.h>
74
75 #include <QtGui/qgenericpluginfactory.h>
76 #include <QtGui/qstylehints.h>
77 #include <QtGui/qinputmethod.h>
78 #include <QtGui/qpixmapcache.h>
79 #include <qpa/qplatforminputcontext.h>
80 #include <qpa/qplatforminputcontext_p.h>
81
82 #include <qpa/qwindowsysteminterface.h>
83 #include <qpa/qwindowsysteminterface_p.h>
84 #include "private/qwindow_p.h"
85 #include "private/qcursor_p.h"
86 #include "private/qopenglcontext_p.h"
87 #include "private/qinputdevicemanager_p.h"
88 #include "private/qinputmethod_p.h"
89 #include "private/qtouchdevice_p.h"
90
91 #include <qpa/qplatformthemefactory_p.h>
92
93 #if QT_CONFIG(draganddrop)
94 #include <qpa/qplatformdrag.h>
95 #include <private/qdnd_p.h>
96 #endif
97
98 #ifndef QT_NO_CURSOR
99 #include <qpa/qplatformcursor.h>
100 #endif
101
102 #include <QtGui/QPixmap>
103
104 #ifndef QT_NO_CLIPBOARD
105 #include <QtGui/QClipboard>
106 #endif
107
108 #if QT_CONFIG(library)
109 #include <QtCore/QLibrary>
110 #endif
111
112 #if defined(Q_OS_MAC)
113 # include "private/qcore_mac_p.h"
114 #elif defined(Q_OS_WIN)
115 # include <QtCore/qt_windows.h>
116 # include <QtCore/QLibraryInfo>
117 #endif // Q_OS_WIN
118
119 #ifdef Q_OS_WASM
120 #include <emscripten.h>
121 #endif
122
123 #include <qtgui_tracepoints_p.h>
124
125 #include <ctype.h>
126
127 QT_BEGIN_NAMESPACE
128
129 // Helper macro for static functions to check on the existence of the application class.
130 #define CHECK_QAPP_INSTANCE(...) \
131 if (Q_LIKELY(QCoreApplication::instance())) { \
132 } else { \
133 qWarning("Must construct a QGuiApplication first."); \
134 return __VA_ARGS__; \
135 }
136
137 Q_CORE_EXPORT void qt_call_post_routines();
138 Q_GUI_EXPORT bool qt_is_gui_used = true;
139
140 Qt::MouseButtons QGuiApplicationPrivate::mouse_buttons = Qt::NoButton;
141 Qt::KeyboardModifiers QGuiApplicationPrivate::modifier_buttons = Qt::NoModifier;
142
143 QPointF QGuiApplicationPrivate::lastCursorPosition(qInf(), qInf());
144
145 QWindow *QGuiApplicationPrivate::currentMouseWindow = nullptr;
146
147 QString QGuiApplicationPrivate::styleOverride;
148
149 Qt::ApplicationState QGuiApplicationPrivate::applicationState = Qt::ApplicationInactive;
150
151 Qt::HighDpiScaleFactorRoundingPolicy QGuiApplicationPrivate::highDpiScaleFactorRoundingPolicy =
152 #ifdef Q_OS_ANDROID
153 // On Android, Qt has newer rounded the scale factor. Preserve
154 // that behavior by disabling rounding by default.
155 Qt::HighDpiScaleFactorRoundingPolicy::PassThrough;
156 #else
157 Qt::HighDpiScaleFactorRoundingPolicy::Round;
158 #endif
159 bool QGuiApplicationPrivate::highDpiScalingUpdated = false;
160
161 QPointer<QWindow> QGuiApplicationPrivate::currentDragWindow;
162
163 QVector<QGuiApplicationPrivate::TabletPointData> QGuiApplicationPrivate::tabletDevicePoints;
164
165 QPlatformIntegration *QGuiApplicationPrivate::platform_integration = nullptr;
166 QPlatformTheme *QGuiApplicationPrivate::platform_theme = nullptr;
167
168 QList<QObject *> QGuiApplicationPrivate::generic_plugin_list;
169
170 #ifndef QT_NO_SESSIONMANAGER
171 bool QGuiApplicationPrivate::is_fallback_session_management_enabled = true;
172 #endif
173
174 enum ApplicationResourceFlags
175 {
176 ApplicationFontExplicitlySet = 0x2
177 };
178
179 static unsigned applicationResourceFlags = 0;
180
181 QIcon *QGuiApplicationPrivate::app_icon = nullptr;
182
183 QString *QGuiApplicationPrivate::platform_name = nullptr;
184 QString *QGuiApplicationPrivate::displayName = nullptr;
185 QString *QGuiApplicationPrivate::desktopFileName = nullptr;
186
187 QPalette *QGuiApplicationPrivate::app_pal = nullptr; // default application palette
188
189 ulong QGuiApplicationPrivate::mousePressTime = 0;
190 Qt::MouseButton QGuiApplicationPrivate::mousePressButton = Qt::NoButton;
191 int QGuiApplicationPrivate::mousePressX = 0;
192 int QGuiApplicationPrivate::mousePressY = 0;
193
194 static int mouseDoubleClickDistance = -1;
195 static int touchDoubleTapDistance = -1;
196
197 QWindow *QGuiApplicationPrivate::currentMousePressWindow = nullptr;
198
199 static Qt::LayoutDirection layout_direction = Qt::LayoutDirectionAuto;
200 static bool force_reverse = false;
201
202 QGuiApplicationPrivate *QGuiApplicationPrivate::self = nullptr;
203 QTouchDevice *QGuiApplicationPrivate::m_fakeTouchDevice = nullptr;
204 int QGuiApplicationPrivate::m_fakeMouseSourcePointId = -1;
205
206 #ifndef QT_NO_CLIPBOARD
207 QClipboard *QGuiApplicationPrivate::qt_clipboard = nullptr;
208 #endif
209
210 QList<QScreen *> QGuiApplicationPrivate::screen_list;
211
212 QWindowList QGuiApplicationPrivate::window_list;
213 QWindow *QGuiApplicationPrivate::focus_window = nullptr;
214
215 static QBasicMutex applicationFontMutex;
216 QFont *QGuiApplicationPrivate::app_font = nullptr;
217 QStyleHints *QGuiApplicationPrivate::styleHints = nullptr;
218 bool QGuiApplicationPrivate::obey_desktop_settings = true;
219
220 QInputDeviceManager *QGuiApplicationPrivate::m_inputDeviceManager = nullptr;
221
222 qreal QGuiApplicationPrivate::m_maxDevicePixelRatio = 0.0;
223
224 static qreal fontSmoothingGamma = 1.7;
225
226 extern void qRegisterGuiVariant();
227 #if QT_CONFIG(animation)
228 extern void qRegisterGuiGetInterpolator();
229 #endif
230
qt_detectRTLLanguage()231 static bool qt_detectRTLLanguage()
232 {
233 return force_reverse ^
234 (QGuiApplication::tr("QT_LAYOUT_DIRECTION",
235 "Translate this string to the string 'LTR' in left-to-right"
236 " languages or to 'RTL' in right-to-left languages (such as Hebrew"
237 " and Arabic) to get proper widget layout.") == QLatin1String("RTL"));
238 }
239
initFontUnlocked()240 static void initFontUnlocked()
241 {
242 if (!QGuiApplicationPrivate::app_font) {
243 if (const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme())
244 if (const QFont *font = theme->font(QPlatformTheme::SystemFont))
245 QGuiApplicationPrivate::app_font = new QFont(*font);
246 }
247 if (!QGuiApplicationPrivate::app_font)
248 QGuiApplicationPrivate::app_font =
249 new QFont(QGuiApplicationPrivate::platformIntegration()->fontDatabase()->defaultFont());
250 }
251
clearFontUnlocked()252 static inline void clearFontUnlocked()
253 {
254 delete QGuiApplicationPrivate::app_font;
255 QGuiApplicationPrivate::app_font = nullptr;
256 }
257
initThemeHints()258 static void initThemeHints()
259 {
260 mouseDoubleClickDistance = QGuiApplicationPrivate::platformTheme()->themeHint(QPlatformTheme::MouseDoubleClickDistance).toInt();
261 touchDoubleTapDistance = QGuiApplicationPrivate::platformTheme()->themeHint(QPlatformTheme::TouchDoubleTapDistance).toInt();
262 }
263
checkNeedPortalSupport()264 static bool checkNeedPortalSupport()
265 {
266 #if QT_CONFIG(dbus)
267 return !QStandardPaths::locate(QStandardPaths::RuntimeLocation, QLatin1String("flatpak-info")).isEmpty() || qEnvironmentVariableIsSet("SNAP");
268 #else
269 return false;
270 #endif // QT_CONFIG(dbus)
271 }
272
273 // Using aggregate initialization instead of ctor so we can have a POD global static
274 #define Q_WINDOW_GEOMETRY_SPECIFICATION_INITIALIZER { Qt::TopLeftCorner, -1, -1, -1, -1 }
275
276 // Geometry specification for top level windows following the convention of the
277 // -geometry command line arguments in X11 (see XParseGeometry).
278 struct QWindowGeometrySpecification
279 {
280 static QWindowGeometrySpecification fromArgument(const QByteArray &a);
281 void applyTo(QWindow *window) const;
282
283 Qt::Corner corner;
284 int xOffset;
285 int yOffset;
286 int width;
287 int height;
288 };
289
290 // Parse a token of a X11 geometry specification "200x100+10-20".
nextGeometryToken(const QByteArray & a,int & pos,char * op)291 static inline int nextGeometryToken(const QByteArray &a, int &pos, char *op)
292 {
293 *op = 0;
294 const int size = a.size();
295 if (pos >= size)
296 return -1;
297
298 *op = a.at(pos);
299 if (*op == '+' || *op == '-' || *op == 'x')
300 pos++;
301 else if (isdigit(*op))
302 *op = 'x'; // If it starts with a digit, it is supposed to be a width specification.
303 else
304 return -1;
305
306 const int numberPos = pos;
307 for ( ; pos < size && isdigit(a.at(pos)); ++pos) ;
308
309 bool ok;
310 const int result = a.mid(numberPos, pos - numberPos).toInt(&ok);
311 return ok ? result : -1;
312 }
313
fromArgument(const QByteArray & a)314 QWindowGeometrySpecification QWindowGeometrySpecification::fromArgument(const QByteArray &a)
315 {
316 QWindowGeometrySpecification result = Q_WINDOW_GEOMETRY_SPECIFICATION_INITIALIZER;
317 int pos = 0;
318 for (int i = 0; i < 4; ++i) {
319 char op;
320 const int value = nextGeometryToken(a, pos, &op);
321 if (value < 0)
322 break;
323 switch (op) {
324 case 'x':
325 (result.width >= 0 ? result.height : result.width) = value;
326 break;
327 case '+':
328 case '-':
329 if (result.xOffset >= 0) {
330 result.yOffset = value;
331 if (op == '-')
332 result.corner = result.corner == Qt::TopRightCorner ? Qt::BottomRightCorner : Qt::BottomLeftCorner;
333 } else {
334 result.xOffset = value;
335 if (op == '-')
336 result.corner = Qt::TopRightCorner;
337 }
338 }
339 }
340 return result;
341 }
342
applyTo(QWindow * window) const343 void QWindowGeometrySpecification::applyTo(QWindow *window) const
344 {
345 QRect windowGeometry = window->frameGeometry();
346 QSize size = windowGeometry.size();
347 if (width >= 0 || height >= 0) {
348 const QSize windowMinimumSize = window->minimumSize();
349 const QSize windowMaximumSize = window->maximumSize();
350 if (width >= 0)
351 size.setWidth(qBound(windowMinimumSize.width(), width, windowMaximumSize.width()));
352 if (height >= 0)
353 size.setHeight(qBound(windowMinimumSize.height(), height, windowMaximumSize.height()));
354 window->resize(size);
355 }
356 if (xOffset >= 0 || yOffset >= 0) {
357 const QRect availableGeometry = window->screen()->virtualGeometry();
358 QPoint topLeft = windowGeometry.topLeft();
359 if (xOffset >= 0) {
360 topLeft.setX(corner == Qt::TopLeftCorner || corner == Qt::BottomLeftCorner ?
361 xOffset :
362 qMax(availableGeometry.right() - size.width() - xOffset, availableGeometry.left()));
363 }
364 if (yOffset >= 0) {
365 topLeft.setY(corner == Qt::TopLeftCorner || corner == Qt::TopRightCorner ?
366 yOffset :
367 qMax(availableGeometry.bottom() - size.height() - yOffset, availableGeometry.top()));
368 }
369 window->setFramePosition(topLeft);
370 }
371 }
372
373 static QWindowGeometrySpecification windowGeometrySpecification = Q_WINDOW_GEOMETRY_SPECIFICATION_INITIALIZER;
374
375 /*!
376 \macro qGuiApp
377 \relates QGuiApplication
378
379 A global pointer referring to the unique application object.
380 Only valid for use when that object is a QGuiApplication.
381
382 \sa QCoreApplication::instance(), qApp
383 */
384
385 /*!
386 \class QGuiApplication
387 \brief The QGuiApplication class manages the GUI application's control
388 flow and main settings.
389
390 \inmodule QtGui
391 \since 5.0
392
393 QGuiApplication contains the main event loop, where all events from the window
394 system and other sources are processed and dispatched. It also handles the
395 application's initialization and finalization, and provides session management.
396 In addition, QGuiApplication handles most of the system-wide and application-wide
397 settings.
398
399 For any GUI application using Qt, there is precisely \b one QGuiApplication
400 object no matter whether the application has 0, 1, 2 or more windows at
401 any given time. For non-GUI Qt applications, use QCoreApplication instead,
402 as it does not depend on the Qt GUI module. For QWidget based Qt applications,
403 use QApplication instead, as it provides some functionality needed for creating
404 QWidget instances.
405
406 The QGuiApplication object is accessible through the instance() function, which
407 returns a pointer equivalent to the global \l qApp pointer.
408
409 QGuiApplication's main areas of responsibility are:
410 \list
411 \li It initializes the application with the user's desktop settings,
412 such as palette(), font() and styleHints(). It keeps
413 track of these properties in case the user changes the desktop
414 globally, for example, through some kind of control panel.
415
416 \li It performs event handling, meaning that it receives events
417 from the underlying window system and dispatches them to the
418 relevant widgets. You can send your own events to windows by
419 using sendEvent() and postEvent().
420
421 \li It parses common command line arguments and sets its internal
422 state accordingly. See the \l{QGuiApplication::QGuiApplication()}
423 {constructor documentation} below for more details.
424
425 \li It provides localization of strings that are visible to the
426 user via translate().
427
428 \li It provides some magical objects like the clipboard().
429
430 \li It knows about the application's windows. You can ask which
431 window is at a certain position using topLevelAt(), get a list of
432 topLevelWindows(), etc.
433
434 \li It manages the application's mouse cursor handling, see
435 setOverrideCursor()
436
437 \li It provides support for sophisticated \l{Session Management}
438 {session management}. This makes it possible for applications
439 to terminate gracefully when the user logs out, to cancel a
440 shutdown process if termination isn't possible and even to
441 preserve the entire application's state for a future session.
442 See isSessionRestored(), sessionId() and commitDataRequest() and
443 saveStateRequest() for details.
444 \endlist
445
446 Since the QGuiApplication object does so much initialization, it \e{must} be
447 created before any other objects related to the user interface are created.
448 QGuiApplication also deals with common command line arguments. Hence, it is
449 usually a good idea to create it \e before any interpretation or
450 modification of \c argv is done in the application itself.
451
452 \table
453 \header
454 \li{2,1} Groups of functions
455
456 \row
457 \li System settings
458 \li desktopSettingsAware(),
459 setDesktopSettingsAware(),
460 styleHints(),
461 palette(),
462 setPalette(),
463 font(),
464 setFont().
465
466 \row
467 \li Event handling
468 \li exec(),
469 processEvents(),
470 exit(),
471 quit().
472 sendEvent(),
473 postEvent(),
474 sendPostedEvents(),
475 removePostedEvents(),
476 hasPendingEvents(),
477 notify().
478
479 \row
480 \li Windows
481 \li allWindows(),
482 topLevelWindows(),
483 focusWindow(),
484 clipboard(),
485 topLevelAt().
486
487 \row
488 \li Advanced cursor handling
489 \li overrideCursor(),
490 setOverrideCursor(),
491 restoreOverrideCursor().
492
493 \row
494 \li Session management
495 \li isSessionRestored(),
496 sessionId(),
497 commitDataRequest(),
498 saveStateRequest().
499
500 \row
501 \li Miscellaneous
502 \li startingUp(),
503 closingDown().
504 \endtable
505
506 \sa QCoreApplication, QAbstractEventDispatcher, QEventLoop
507 */
508
509 /*!
510 Initializes the window system and constructs an application object with
511 \a argc command line arguments in \a argv.
512
513 \warning The data referred to by \a argc and \a argv must stay valid for
514 the entire lifetime of the QGuiApplication object. In addition, \a argc must
515 be greater than zero and \a argv must contain at least one valid character
516 string.
517
518 The global \c qApp pointer refers to this application object. Only one
519 application object should be created.
520
521 This application object must be constructed before any \l{QPaintDevice}
522 {paint devices} (including pixmaps, bitmaps etc.).
523
524 \note \a argc and \a argv might be changed as Qt removes command line
525 arguments that it recognizes.
526
527 \section1 Supported Command Line Options
528
529 All Qt programs automatically support a set of command-line options that
530 allow modifying the way Qt will interact with the windowing system. Some of
531 the options are also accessible via environment variables, which are the
532 preferred form if the application can launch GUI sub-processes or other
533 applications (environment variables will be inherited by child processes).
534 When in doubt, use the environment variables.
535
536 The options currently supported are the following:
537 \list
538
539 \li \c{-platform} \e {platformName[:options]}, specifies the
540 \l{Qt Platform Abstraction} (QPA) plugin.
541
542 Overrides the \c QT_QPA_PLATFORM environment variable.
543 \li \c{-platformpluginpath} \e path, specifies the path to platform
544 plugins.
545
546 Overrides the \c QT_QPA_PLATFORM_PLUGIN_PATH environment variable.
547
548 \li \c{-platformtheme} \e platformTheme, specifies the platform theme.
549
550 Overrides the \c QT_QPA_PLATFORMTHEME environment variable.
551
552 \li \c{-plugin} \e plugin, specifies additional plugins to load. The argument
553 may appear multiple times.
554
555 Concatenated with the plugins in the \c QT_QPA_GENERIC_PLUGINS environment
556 variable.
557
558 \li \c{-qmljsdebugger=}, activates the QML/JS debugger with a specified port.
559 The value must be of format \c{port:1234}\e{[,block]}, where
560 \e block is optional
561 and will make the application wait until a debugger connects to it.
562 \li \c {-qwindowgeometry} \e geometry, specifies window geometry for
563 the main window using the X11-syntax. For example:
564 \c {-qwindowgeometry 100x100+50+50}
565 \li \c {-qwindowicon}, sets the default window icon
566 \li \c {-qwindowtitle}, sets the title of the first window
567 \li \c{-reverse}, sets the application's layout direction to
568 Qt::RightToLeft. This option is intended to aid debugging and should
569 not be used in production. The default value is automatically detected
570 from the user's locale (see also QLocale::textDirection()).
571 \li \c{-session} \e session, restores the application from an earlier
572 \l{Session Management}{session}.
573 \endlist
574
575 The following standard command line options are available for X11:
576
577 \list
578 \li \c {-display} \e {hostname:screen_number}, switches displays on X11.
579
580 Overrides the \c DISPLAY environment variable.
581 \li \c {-geometry} \e geometry, same as \c {-qwindowgeometry}.
582 \endlist
583
584 \section1 Platform-Specific Arguments
585
586 You can specify platform-specific arguments for the \c{-platform} option.
587 Place them after the platform plugin name following a colon as a
588 comma-separated list. For example,
589 \c{-platform windows:dialogs=xp,fontengine=freetype}.
590
591 The following parameters are available for \c {-platform windows}:
592
593 \list
594 \li \c {altgr}, detect the key \c {AltGr} found on some keyboards as
595 Qt::GroupSwitchModifier (since Qt 5.12).
596 \li \c {darkmode=[1|2]} controls how Qt responds to the activation
597 of the \e{Dark Mode for applications} introduced in Windows 10
598 1903 (since Qt 5.15).
599
600 A value of 1 causes Qt to switch the window borders to black
601 when \e{Dark Mode for applications} is activated and no High
602 Contrast Theme is in use. This is intended for applications
603 that implement their own theming.
604
605 A value of 2 will in addition cause the Windows Vista style to
606 be deactivated and switch to the Windows style using a
607 simplified palette in dark mode. This is currently
608 experimental pending the introduction of new style that
609 properly adapts to dark mode.
610
611 \li \c {dialogs=[xp|none]}, \c xp uses XP-style native dialogs and
612 \c none disables them.
613
614 \li \c {dpiawareness=[0|1|2]} Sets the DPI awareness of the process
615 (see \l{High DPI Displays}, since Qt 5.4).
616 \li \c {fontengine=freetype}, uses the FreeType font engine.
617 \li \c {menus=[native|none]}, controls the use of native menus.
618
619 Native menus are implemented using Win32 API and are simpler than
620 QMenu-based menus in for example that they do allow for placing
621 widgets on them or changing properties like fonts and do not
622 provide hover signals. They are mainly intended for Qt Quick.
623 By default, they will be used if the application is not an
624 instance of QApplication or for Qt Quick Controls 2
625 applications (since Qt 5.10).
626
627 \li \c {nocolorfonts} Turn off DirectWrite Color fonts
628 (since Qt 5.8).
629
630 \li \c {nodirectwrite} Turn off DirectWrite fonts (since Qt 5.8).
631
632 \li \c {nomousefromtouch} Ignores mouse events synthesized
633 from touch events by the operating system.
634
635 \li \c {nowmpointer} Switches from Pointer Input Messages handling
636 to legacy mouse handling (since Qt 5.12).
637 \li \c {reverse} Activates Right-to-left mode (experimental).
638 Windows title bars will be shown accordingly in Right-to-left locales
639 (since Qt 5.13).
640 \li \c {tabletabsoluterange=<value>} Sets a value for mouse mode detection
641 of WinTab tablets (Legacy, since Qt 5.3).
642 \endlist
643
644 The following parameter is available for \c {-platform cocoa} (on macOS):
645
646 \list
647 \li \c {fontengine=freetype}, uses the FreeType font engine.
648 \endlist
649
650 For more information about the platform-specific arguments available for
651 embedded Linux platforms, see \l{Qt for Embedded Linux}.
652
653 \sa arguments() QGuiApplication::platformName
654 */
655 #ifdef Q_QDOC
QGuiApplication(int & argc,char ** argv)656 QGuiApplication::QGuiApplication(int &argc, char **argv)
657 #else
658 QGuiApplication::QGuiApplication(int &argc, char **argv, int flags)
659 #endif
660 : QCoreApplication(*new QGuiApplicationPrivate(argc, argv, flags))
661 {
662 d_func()->init();
663
664 QCoreApplicationPrivate::eventDispatcher->startingUp();
665 }
666
667 /*!
668 \internal
669 */
QGuiApplication(QGuiApplicationPrivate & p)670 QGuiApplication::QGuiApplication(QGuiApplicationPrivate &p)
671 : QCoreApplication(p)
672 {
673 }
674
675 /*!
676 Destructs the application.
677 */
~QGuiApplication()678 QGuiApplication::~QGuiApplication()
679 {
680 Q_D(QGuiApplication);
681
682 qt_call_post_routines();
683
684 d->eventDispatcher->closingDown();
685 d->eventDispatcher = nullptr;
686
687 #ifndef QT_NO_CLIPBOARD
688 delete QGuiApplicationPrivate::qt_clipboard;
689 QGuiApplicationPrivate::qt_clipboard = nullptr;
690 #endif
691
692 #ifndef QT_NO_SESSIONMANAGER
693 delete d->session_manager;
694 d->session_manager = nullptr;
695 #endif //QT_NO_SESSIONMANAGER
696
697 QGuiApplicationPrivate::clearPalette();
698 QFontDatabase::removeAllApplicationFonts();
699
700 #ifndef QT_NO_CURSOR
701 d->cursor_list.clear();
702 #endif
703
704 delete QGuiApplicationPrivate::app_icon;
705 QGuiApplicationPrivate::app_icon = nullptr;
706 delete QGuiApplicationPrivate::platform_name;
707 QGuiApplicationPrivate::platform_name = nullptr;
708 delete QGuiApplicationPrivate::displayName;
709 QGuiApplicationPrivate::displayName = nullptr;
710 delete QGuiApplicationPrivate::m_inputDeviceManager;
711 QGuiApplicationPrivate::m_inputDeviceManager = nullptr;
712 delete QGuiApplicationPrivate::desktopFileName;
713 QGuiApplicationPrivate::desktopFileName = nullptr;
714 QGuiApplicationPrivate::mouse_buttons = Qt::NoButton;
715 QGuiApplicationPrivate::modifier_buttons = Qt::NoModifier;
716 QGuiApplicationPrivate::lastCursorPosition = {qInf(), qInf()};
717 QGuiApplicationPrivate::currentMousePressWindow = QGuiApplicationPrivate::currentMouseWindow = nullptr;
718 QGuiApplicationPrivate::applicationState = Qt::ApplicationInactive;
719 QGuiApplicationPrivate::highDpiScalingUpdated = false;
720 QGuiApplicationPrivate::currentDragWindow = nullptr;
721 QGuiApplicationPrivate::tabletDevicePoints.clear();
722 #ifndef QT_NO_SESSIONMANAGER
723 QGuiApplicationPrivate::is_fallback_session_management_enabled = true;
724 #endif
725 QGuiApplicationPrivate::mousePressTime = 0;
726 QGuiApplicationPrivate::mousePressX = QGuiApplicationPrivate::mousePressY = 0;
727 }
728
QGuiApplicationPrivate(int & argc,char ** argv,int flags)729 QGuiApplicationPrivate::QGuiApplicationPrivate(int &argc, char **argv, int flags)
730 : QCoreApplicationPrivate(argc, argv, flags),
731 inputMethod(nullptr),
732 lastTouchType(QEvent::TouchEnd),
733 ownGlobalShareContext(false)
734 {
735 self = this;
736 application_type = QCoreApplicationPrivate::Gui;
737 #ifndef QT_NO_SESSIONMANAGER
738 is_session_restored = false;
739 is_saving_session = false;
740 #endif
741 }
742
743 /*!
744 \property QGuiApplication::applicationDisplayName
745 \brief the user-visible name of this application
746 \since 5.0
747
748 This name is shown to the user, for instance in window titles.
749 It can be translated, if necessary.
750
751 If not set, the application display name defaults to the application name.
752
753 \sa applicationName
754 */
setApplicationDisplayName(const QString & name)755 void QGuiApplication::setApplicationDisplayName(const QString &name)
756 {
757 if (!QGuiApplicationPrivate::displayName) {
758 QGuiApplicationPrivate::displayName = new QString(name);
759 if (qGuiApp) {
760 disconnect(qGuiApp, &QGuiApplication::applicationNameChanged,
761 qGuiApp, &QGuiApplication::applicationDisplayNameChanged);
762
763 if (*QGuiApplicationPrivate::displayName != applicationName())
764 emit qGuiApp->applicationDisplayNameChanged();
765 }
766 } else if (name != *QGuiApplicationPrivate::displayName) {
767 *QGuiApplicationPrivate::displayName = name;
768 if (qGuiApp)
769 emit qGuiApp->applicationDisplayNameChanged();
770 }
771 }
772
applicationDisplayName()773 QString QGuiApplication::applicationDisplayName()
774 {
775 return QGuiApplicationPrivate::displayName ? *QGuiApplicationPrivate::displayName : applicationName();
776 }
777
778 /*!
779 \property QGuiApplication::desktopFileName
780 \brief the base name of the desktop entry for this application
781 \since 5.7
782
783 This is the file name, without the full path, of the desktop entry
784 that represents this application according to the freedesktop desktop
785 entry specification.
786
787 This property gives a precise indication of what desktop entry represents
788 the application and it is needed by the windowing system to retrieve
789 such information without resorting to imprecise heuristics.
790
791 The latest version of the freedesktop desktop entry specification can be obtained
792 \l{http://standards.freedesktop.org/desktop-entry-spec/latest/}{here}.
793 */
setDesktopFileName(const QString & name)794 void QGuiApplication::setDesktopFileName(const QString &name)
795 {
796 if (!QGuiApplicationPrivate::desktopFileName)
797 QGuiApplicationPrivate::desktopFileName = new QString;
798 *QGuiApplicationPrivate::desktopFileName = name;
799 }
800
desktopFileName()801 QString QGuiApplication::desktopFileName()
802 {
803 return QGuiApplicationPrivate::desktopFileName ? *QGuiApplicationPrivate::desktopFileName : QString();
804 }
805
806 /*!
807 Returns the most recently shown modal window. If no modal windows are
808 visible, this function returns zero.
809
810 A modal window is a window which has its
811 \l{QWindow::modality}{modality} property set to Qt::WindowModal
812 or Qt::ApplicationModal. A modal window must be closed before the user can
813 continue with other parts of the program.
814
815 Modal window are organized in a stack. This function returns the modal
816 window at the top of the stack.
817
818 \sa Qt::WindowModality, QWindow::setModality()
819 */
modalWindow()820 QWindow *QGuiApplication::modalWindow()
821 {
822 CHECK_QAPP_INSTANCE(nullptr)
823 if (QGuiApplicationPrivate::self->modalWindowList.isEmpty())
824 return nullptr;
825 return QGuiApplicationPrivate::self->modalWindowList.first();
826 }
827
updateBlockedStatusRecursion(QWindow * window,bool shouldBeBlocked)828 static void updateBlockedStatusRecursion(QWindow *window, bool shouldBeBlocked)
829 {
830 QWindowPrivate *p = qt_window_private(window);
831 if (p->blockedByModalWindow != shouldBeBlocked) {
832 p->blockedByModalWindow = shouldBeBlocked;
833 QEvent e(shouldBeBlocked ? QEvent::WindowBlocked : QEvent::WindowUnblocked);
834 QGuiApplication::sendEvent(window, &e);
835 for (QObject *c : window->children()) {
836 if (c->isWindowType())
837 updateBlockedStatusRecursion(static_cast<QWindow *>(c), shouldBeBlocked);
838 }
839 }
840 }
841
updateBlockedStatus(QWindow * window)842 void QGuiApplicationPrivate::updateBlockedStatus(QWindow *window)
843 {
844 bool shouldBeBlocked = false;
845 const bool popupType = (window->type() == Qt::ToolTip) || (window->type() == Qt::Popup);
846 if (!popupType && !self->modalWindowList.isEmpty())
847 shouldBeBlocked = self->isWindowBlocked(window);
848 updateBlockedStatusRecursion(window, shouldBeBlocked);
849 }
850
851 // Return whether the window needs to be notified about window blocked events.
852 // As opposed to QGuiApplication::topLevelWindows(), embedded windows are
853 // included in this list (QTBUG-18099).
needsWindowBlockedEvent(const QWindow * w)854 static inline bool needsWindowBlockedEvent(const QWindow *w)
855 {
856 return w->isTopLevel() && w->type() != Qt::Desktop;
857 }
858
showModalWindow(QWindow * modal)859 void QGuiApplicationPrivate::showModalWindow(QWindow *modal)
860 {
861 self->modalWindowList.prepend(modal);
862
863 // Send leave for currently entered window if it should be blocked
864 if (currentMouseWindow && !QWindowPrivate::get(currentMouseWindow)->isPopup()) {
865 bool shouldBeBlocked = self->isWindowBlocked(currentMouseWindow);
866 if (shouldBeBlocked) {
867 // Remove the new window from modalWindowList temporarily so leave can go through
868 self->modalWindowList.removeFirst();
869 QEvent e(QEvent::Leave);
870 QGuiApplication::sendEvent(currentMouseWindow, &e);
871 currentMouseWindow = nullptr;
872 self->modalWindowList.prepend(modal);
873 }
874 }
875
876 for (QWindow *window : qAsConst(QGuiApplicationPrivate::window_list)) {
877 if (needsWindowBlockedEvent(window) && !window->d_func()->blockedByModalWindow)
878 updateBlockedStatus(window);
879 }
880
881 updateBlockedStatus(modal);
882 }
883
hideModalWindow(QWindow * window)884 void QGuiApplicationPrivate::hideModalWindow(QWindow *window)
885 {
886 self->modalWindowList.removeAll(window);
887
888 for (QWindow *window : qAsConst(QGuiApplicationPrivate::window_list)) {
889 if (needsWindowBlockedEvent(window) && window->d_func()->blockedByModalWindow)
890 updateBlockedStatus(window);
891 }
892 }
893
894 /*
895 Returns \c true if \a window is blocked by a modal window. If \a
896 blockingWindow is non-zero, *blockingWindow will be set to the blocking
897 window (or to zero if \a window is not blocked).
898 */
isWindowBlocked(QWindow * window,QWindow ** blockingWindow) const899 bool QGuiApplicationPrivate::isWindowBlocked(QWindow *window, QWindow **blockingWindow) const
900 {
901 QWindow *unused = nullptr;
902 if (!blockingWindow)
903 blockingWindow = &unused;
904
905 if (modalWindowList.isEmpty()) {
906 *blockingWindow = nullptr;
907 return false;
908 }
909
910 for (int i = 0; i < modalWindowList.count(); ++i) {
911 QWindow *modalWindow = modalWindowList.at(i);
912
913 // A window is not blocked by another modal window if the two are
914 // the same, or if the window is a child of the modal window.
915 if (window == modalWindow || modalWindow->isAncestorOf(window, QWindow::IncludeTransients)) {
916 *blockingWindow = nullptr;
917 return false;
918 }
919
920 Qt::WindowModality windowModality = modalWindow->modality();
921 switch (windowModality) {
922 case Qt::ApplicationModal:
923 {
924 if (modalWindow != window) {
925 *blockingWindow = modalWindow;
926 return true;
927 }
928 break;
929 }
930 case Qt::WindowModal:
931 {
932 QWindow *w = window;
933 do {
934 QWindow *m = modalWindow;
935 do {
936 if (m == w) {
937 *blockingWindow = m;
938 return true;
939 }
940 QWindow *p = m->parent();
941 if (!p)
942 p = m->transientParent();
943 m = p;
944 } while (m);
945 QWindow *p = w->parent();
946 if (!p)
947 p = w->transientParent();
948 w = p;
949 } while (w);
950 break;
951 }
952 default:
953 Q_ASSERT_X(false, "QGuiApplication", "internal error, a modal widget cannot be modeless");
954 break;
955 }
956 }
957 *blockingWindow = nullptr;
958 return false;
959 }
960
961 /*!
962 Returns the QWindow that receives events tied to focus,
963 such as key events.
964 */
focusWindow()965 QWindow *QGuiApplication::focusWindow()
966 {
967 return QGuiApplicationPrivate::focus_window;
968 }
969
970 /*!
971 \fn QGuiApplication::focusObjectChanged(QObject *focusObject)
972
973 This signal is emitted when final receiver of events tied to focus is changed.
974 \a focusObject is the new receiver.
975
976 \sa focusObject()
977 */
978
979 /*!
980 \fn QGuiApplication::focusWindowChanged(QWindow *focusWindow)
981
982 This signal is emitted when the focused window changes.
983 \a focusWindow is the new focused window.
984
985 \sa focusWindow()
986 */
987
988 /*!
989 Returns the QObject in currently active window that will be final receiver of events
990 tied to focus, such as key events.
991 */
focusObject()992 QObject *QGuiApplication::focusObject()
993 {
994 if (focusWindow())
995 return focusWindow()->focusObject();
996 return nullptr;
997 }
998
999 /*!
1000 \fn QGuiApplication::allWindows()
1001
1002 Returns a list of all the windows in the application.
1003
1004 The list is empty if there are no windows.
1005
1006 \sa topLevelWindows()
1007 */
allWindows()1008 QWindowList QGuiApplication::allWindows()
1009 {
1010 return QGuiApplicationPrivate::window_list;
1011 }
1012
1013 /*!
1014 \fn QGuiApplication::topLevelWindows()
1015
1016 Returns a list of the top-level windows in the application.
1017
1018 \sa allWindows()
1019 */
topLevelWindows()1020 QWindowList QGuiApplication::topLevelWindows()
1021 {
1022 const QWindowList &list = QGuiApplicationPrivate::window_list;
1023 QWindowList topLevelWindows;
1024 for (int i = 0; i < list.size(); ++i) {
1025 QWindow *window = list.at(i);
1026 if (!window->isTopLevel())
1027 continue;
1028
1029 // Desktop windows are special, as each individual desktop window
1030 // will report that it's a top level window, but we don't want to
1031 // include them in the application wide list of top level windows.
1032 if (window->type() == Qt::Desktop)
1033 continue;
1034
1035 // Windows embedded in native windows do not have QWindow parents,
1036 // but they are not true top level windows, so do not include them.
1037 if (window->handle() && window->handle()->isEmbedded())
1038 continue;
1039
1040 topLevelWindows.prepend(window);
1041 }
1042
1043 return topLevelWindows;
1044 }
1045
primaryScreen()1046 QScreen *QGuiApplication::primaryScreen()
1047 {
1048 if (QGuiApplicationPrivate::screen_list.isEmpty())
1049 return nullptr;
1050 return QGuiApplicationPrivate::screen_list.at(0);
1051 }
1052
1053 /*!
1054 Returns a list of all the screens associated with the
1055 windowing system the application is connected to.
1056 */
screens()1057 QList<QScreen *> QGuiApplication::screens()
1058 {
1059 return QGuiApplicationPrivate::screen_list;
1060 }
1061
1062 /*!
1063 Returns the screen at \a point, or \nullptr if outside of any screen.
1064
1065 The \a point is in relation to the virtualGeometry() of each set of virtual
1066 siblings. If the point maps to more than one set of virtual siblings the first
1067 match is returned. If you wish to search only the virtual desktop siblings
1068 of a known screen (for example siblings of the screen of your application
1069 window \c QWidget::windowHandle()->screen()), use QScreen::virtualSiblingAt().
1070
1071 \since 5.10
1072 */
screenAt(const QPoint & point)1073 QScreen *QGuiApplication::screenAt(const QPoint &point)
1074 {
1075 QVarLengthArray<const QScreen *, 8> visitedScreens;
1076 for (const QScreen *screen : QGuiApplication::screens()) {
1077 if (visitedScreens.contains(screen))
1078 continue;
1079
1080 // The virtual siblings include the screen itself, so iterate directly
1081 for (QScreen *sibling : screen->virtualSiblings()) {
1082 if (sibling->geometry().contains(point))
1083 return sibling;
1084
1085 visitedScreens.append(sibling);
1086 }
1087 }
1088
1089 return nullptr;
1090 }
1091
1092 /*!
1093 \fn void QGuiApplication::screenAdded(QScreen *screen)
1094
1095 This signal is emitted whenever a new screen \a screen has been added to the system.
1096
1097 \sa screens(), primaryScreen, screenRemoved()
1098 */
1099
1100 /*!
1101 \fn void QGuiApplication::screenRemoved(QScreen *screen)
1102
1103 This signal is emitted whenever a \a screen is removed from the system. It
1104 provides an opportunity to manage the windows on the screen before Qt falls back
1105 to moving them to the primary screen.
1106
1107 \sa screens(), screenAdded(), QObject::destroyed(), QWindow::setScreen()
1108
1109 \since 5.4
1110 */
1111
1112
1113 /*!
1114 \property QGuiApplication::primaryScreen
1115
1116 \brief the primary (or default) screen of the application.
1117
1118 This will be the screen where QWindows are initially shown, unless otherwise specified.
1119
1120 The primaryScreenChanged signal was introduced in Qt 5.6.
1121
1122 \sa screens()
1123 */
1124
1125 /*!
1126 Returns the highest screen device pixel ratio found on
1127 the system. This is the ratio between physical pixels and
1128 device-independent pixels.
1129
1130 Use this function only when you don't know which window you are targeting.
1131 If you do know the target window, use QWindow::devicePixelRatio() instead.
1132
1133 \sa QWindow::devicePixelRatio()
1134 */
devicePixelRatio() const1135 qreal QGuiApplication::devicePixelRatio() const
1136 {
1137 if (!qFuzzyIsNull(QGuiApplicationPrivate::m_maxDevicePixelRatio))
1138 return QGuiApplicationPrivate::m_maxDevicePixelRatio;
1139
1140 QGuiApplicationPrivate::m_maxDevicePixelRatio = 1.0; // make sure we never return 0.
1141 for (QScreen *screen : qAsConst(QGuiApplicationPrivate::screen_list))
1142 QGuiApplicationPrivate::m_maxDevicePixelRatio = qMax(QGuiApplicationPrivate::m_maxDevicePixelRatio, screen->devicePixelRatio());
1143
1144 return QGuiApplicationPrivate::m_maxDevicePixelRatio;
1145 }
1146
resetCachedDevicePixelRatio()1147 void QGuiApplicationPrivate::resetCachedDevicePixelRatio()
1148 {
1149 m_maxDevicePixelRatio = 0.0;
1150 }
1151
1152 /*!
1153 Returns the top level window at the given position \a pos, if any.
1154 */
topLevelAt(const QPoint & pos)1155 QWindow *QGuiApplication::topLevelAt(const QPoint &pos)
1156 {
1157 if (QScreen *windowScreen = screenAt(pos)) {
1158 const QPoint devicePosition = QHighDpi::toNativePixels(pos, windowScreen);
1159 return windowScreen->handle()->topLevelAt(devicePosition);
1160 }
1161 return nullptr;
1162 }
1163
1164 /*!
1165 \property QGuiApplication::platformName
1166 \brief The name of the underlying platform plugin.
1167
1168 The QPA platform plugins are located in \c {qtbase\src\plugins\platforms}.
1169 At the time of writing, the following platform plugin names are supported:
1170
1171 \list
1172 \li \c android
1173 \li \c cocoa is a platform plugin for \macos.
1174 \li \c directfb
1175 \li \c eglfs is a platform plugin for running Qt5 applications on top of
1176 EGL and OpenGL ES 2.0 without an actual windowing system (like X11
1177 or Wayland). For more information, see \l{EGLFS}.
1178 \li \c ios (also used for tvOS)
1179 \li \c kms is an experimental platform plugin using kernel modesetting
1180 and \l{http://dri.freedesktop.org/wiki/DRM}{DRM} (Direct Rendering
1181 Manager).
1182 \li \c linuxfb writes directly to the framebuffer. For more information,
1183 see \l{LinuxFB}.
1184 \li \c minimal is provided as an examples for developers who want to
1185 write their own platform plugins. However, you can use the plugin to
1186 run GUI applications in environments without a GUI, such as servers.
1187 \li \c minimalegl is an example plugin.
1188 \li \c offscreen
1189 \li \c openwfd
1190 \li \c qnx
1191 \li \c windows
1192 \li \c wayland is a platform plugin for modern Linux desktops and some
1193 embedded systems.
1194 \li \c xcb is the X11 plugin used on regular desktop Linux platforms.
1195 \endlist
1196
1197 For more information about the platform plugins for embedded Linux devices,
1198 see \l{Qt for Embedded Linux}.
1199 */
1200
platformName()1201 QString QGuiApplication::platformName()
1202 {
1203 return QGuiApplicationPrivate::platform_name ?
1204 *QGuiApplicationPrivate::platform_name : QString();
1205 }
1206
1207 Q_LOGGING_CATEGORY(lcQpaPluginLoading, "qt.qpa.plugin");
1208
init_platform(const QString & pluginNamesWithArguments,const QString & platformPluginPath,const QString & platformThemeName,int & argc,char ** argv)1209 static void init_platform(const QString &pluginNamesWithArguments, const QString &platformPluginPath, const QString &platformThemeName, int &argc, char **argv)
1210 {
1211 QStringList plugins = pluginNamesWithArguments.split(QLatin1Char(';'));
1212 QStringList platformArguments;
1213 QStringList availablePlugins = QPlatformIntegrationFactory::keys(platformPluginPath);
1214 for (const auto &pluginArgument : plugins) {
1215 // Split into platform name and arguments
1216 QStringList arguments = pluginArgument.split(QLatin1Char(':'));
1217 const QString name = arguments.takeFirst().toLower();
1218 QString argumentsKey = name;
1219 argumentsKey[0] = argumentsKey.at(0).toUpper();
1220 arguments.append(QLibraryInfo::platformPluginArguments(argumentsKey));
1221
1222 // Create the platform integration.
1223 QGuiApplicationPrivate::platform_integration = QPlatformIntegrationFactory::create(name, arguments, argc, argv, platformPluginPath);
1224 if (Q_UNLIKELY(!QGuiApplicationPrivate::platform_integration)) {
1225 if (availablePlugins.contains(name)) {
1226 qCInfo(lcQpaPluginLoading).nospace().noquote()
1227 << "Could not load the Qt platform plugin \"" << name << "\" in \""
1228 << QDir::toNativeSeparators(platformPluginPath) << "\" even though it was found.";
1229 } else {
1230 qCWarning(lcQpaPluginLoading).nospace().noquote()
1231 << "Could not find the Qt platform plugin \"" << name << "\" in \""
1232 << QDir::toNativeSeparators(platformPluginPath) << "\"";
1233 }
1234 } else {
1235 QGuiApplicationPrivate::platform_name = new QString(name);
1236 platformArguments = arguments;
1237 break;
1238 }
1239 }
1240
1241 if (Q_UNLIKELY(!QGuiApplicationPrivate::platform_integration)) {
1242 QString fatalMessage = QStringLiteral("This application failed to start because no Qt platform plugin could be initialized. "
1243 "Reinstalling the application may fix this problem.\n");
1244
1245 if (!availablePlugins.isEmpty())
1246 fatalMessage += QStringLiteral("\nAvailable platform plugins are: %1.\n").arg(availablePlugins.join(QLatin1String(", ")));
1247
1248 #if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
1249 // Windows: Display message box unless it is a console application
1250 // or debug build showing an assert box.
1251 if (!QLibraryInfo::isDebugBuild() && !GetConsoleWindow())
1252 MessageBox(0, (LPCTSTR)fatalMessage.utf16(), (LPCTSTR)(QCoreApplication::applicationName().utf16()), MB_OK | MB_ICONERROR);
1253 #endif // Q_OS_WIN && !Q_OS_WINRT
1254 qFatal("%s", qPrintable(fatalMessage));
1255
1256 return;
1257 }
1258
1259 // Many platforms have created QScreens at this point. Finish initializing
1260 // QHighDpiScaling to be prepared for early calls to qt_defaultDpi().
1261 if (QGuiApplication::primaryScreen()) {
1262 QGuiApplicationPrivate::highDpiScalingUpdated = true;
1263 QHighDpiScaling::updateHighDpiScaling();
1264 }
1265
1266 // Create the platform theme:
1267
1268 // 1) Fetch the platform name from the environment if present.
1269 QStringList themeNames;
1270 if (!platformThemeName.isEmpty())
1271 themeNames.append(platformThemeName);
1272
1273 // 2) Special case - check whether it's a flatpak or snap app to use xdg-desktop-portal platform theme for portals support
1274 if (checkNeedPortalSupport()) {
1275 themeNames.append(QStringLiteral("xdgdesktopportal"));
1276 }
1277
1278 // 3) Ask the platform integration for a list of theme names
1279 themeNames += QGuiApplicationPrivate::platform_integration->themeNames();
1280 // 4) Look for a theme plugin.
1281 for (const QString &themeName : qAsConst(themeNames)) {
1282 QGuiApplicationPrivate::platform_theme = QPlatformThemeFactory::create(themeName, platformPluginPath);
1283 if (QGuiApplicationPrivate::platform_theme)
1284 break;
1285 }
1286
1287 // 5) If no theme plugin was found ask the platform integration to
1288 // create a theme
1289 if (!QGuiApplicationPrivate::platform_theme) {
1290 for (const QString &themeName : qAsConst(themeNames)) {
1291 QGuiApplicationPrivate::platform_theme = QGuiApplicationPrivate::platform_integration->createPlatformTheme(themeName);
1292 if (QGuiApplicationPrivate::platform_theme)
1293 break;
1294 }
1295 // No error message; not having a theme plugin is allowed.
1296 }
1297
1298 // 6) Fall back on the built-in "null" platform theme.
1299 if (!QGuiApplicationPrivate::platform_theme)
1300 QGuiApplicationPrivate::platform_theme = new QPlatformTheme;
1301
1302 #ifndef QT_NO_PROPERTIES
1303 // Set arguments as dynamic properties on the native interface as
1304 // boolean 'foo' or strings: 'foo=bar'
1305 if (!platformArguments.isEmpty()) {
1306 if (QObject *nativeInterface = QGuiApplicationPrivate::platform_integration->nativeInterface()) {
1307 for (const QString &argument : qAsConst(platformArguments)) {
1308 const int equalsPos = argument.indexOf(QLatin1Char('='));
1309 const QByteArray name =
1310 equalsPos != -1 ? argument.left(equalsPos).toUtf8() : argument.toUtf8();
1311 const QVariant value =
1312 equalsPos != -1 ? QVariant(argument.mid(equalsPos + 1)) : QVariant(true);
1313 nativeInterface->setProperty(name.constData(), value);
1314 }
1315 }
1316 }
1317 #endif
1318
1319 fontSmoothingGamma = QGuiApplicationPrivate::platformIntegration()->styleHint(QPlatformIntegration::FontSmoothingGamma).toReal();
1320 }
1321
init_plugins(const QList<QByteArray> & pluginList)1322 static void init_plugins(const QList<QByteArray> &pluginList)
1323 {
1324 for (int i = 0; i < pluginList.count(); ++i) {
1325 QByteArray pluginSpec = pluginList.at(i);
1326 int colonPos = pluginSpec.indexOf(':');
1327 QObject *plugin;
1328 if (colonPos < 0)
1329 plugin = QGenericPluginFactory::create(QLatin1String(pluginSpec), QString());
1330 else
1331 plugin = QGenericPluginFactory::create(QLatin1String(pluginSpec.mid(0, colonPos)),
1332 QLatin1String(pluginSpec.mid(colonPos+1)));
1333 if (plugin)
1334 QGuiApplicationPrivate::generic_plugin_list.append(plugin);
1335 else
1336 qWarning("No such plugin for spec \"%s\"", pluginSpec.constData());
1337 }
1338 }
1339
1340 #if QT_CONFIG(commandlineparser)
addQtOptions(QList<QCommandLineOption> * options)1341 void QGuiApplicationPrivate::addQtOptions(QList<QCommandLineOption> *options)
1342 {
1343 QCoreApplicationPrivate::addQtOptions(options);
1344
1345 #if defined(Q_OS_UNIX) && !defined(Q_OS_DARWIN)
1346 const QByteArray sessionType = qgetenv("XDG_SESSION_TYPE");
1347 const bool x11 = sessionType == "x11";
1348 // Technically the x11 aliases are only available if platformName is "xcb", but we can't know that here.
1349 #else
1350 const bool x11 = false;
1351 #endif
1352
1353 options->append(QCommandLineOption(QStringLiteral("platform"),
1354 QGuiApplication::tr("QPA plugin. See QGuiApplication documentation for available options for each plugin."), QStringLiteral("platformName[:options]")));
1355 options->append(QCommandLineOption(QStringLiteral("platformpluginpath"),
1356 QGuiApplication::tr("Path to the platform plugins."), QStringLiteral("path")));
1357 options->append(QCommandLineOption(QStringLiteral("platformtheme"),
1358 QGuiApplication::tr("Platform theme."), QStringLiteral("theme")));
1359 options->append(QCommandLineOption(QStringLiteral("plugin"),
1360 QGuiApplication::tr("Additional plugins to load, can be specified multiple times."), QStringLiteral("plugin")));
1361 options->append(QCommandLineOption(QStringLiteral("qwindowgeometry"),
1362 QGuiApplication::tr("Window geometry for the main window, using the X11-syntax, like 100x100+50+50."), QStringLiteral("geometry")));
1363 options->append(QCommandLineOption(QStringLiteral("qwindowicon"),
1364 QGuiApplication::tr("Default window icon."), QStringLiteral("icon")));
1365 options->append(QCommandLineOption(QStringLiteral("qwindowtitle"),
1366 QGuiApplication::tr("Title of the first window."), QStringLiteral("title")));
1367 options->append(QCommandLineOption(QStringLiteral("reverse"),
1368 QGuiApplication::tr("Sets the application's layout direction to Qt::RightToLeft (debugging helper).")));
1369 options->append(QCommandLineOption(QStringLiteral("session"),
1370 QGuiApplication::tr("Restores the application from an earlier session."), QStringLiteral("session")));
1371
1372 if (x11) {
1373 options->append(QCommandLineOption(QStringLiteral("display"),
1374 QGuiApplication::tr("Display name, overrides $DISPLAY."), QStringLiteral("display")));
1375 options->append(QCommandLineOption(QStringLiteral("name"),
1376 QGuiApplication::tr("Instance name according to ICCCM 4.1.2.5."), QStringLiteral("name")));
1377 options->append(QCommandLineOption(QStringLiteral("nograb"),
1378 QGuiApplication::tr("Disable mouse grabbing (useful in debuggers).")));
1379 options->append(QCommandLineOption(QStringLiteral("dograb"),
1380 QGuiApplication::tr("Force mouse grabbing (even when running in a debugger).")));
1381 options->append(QCommandLineOption(QStringLiteral("visual"),
1382 QGuiApplication::tr("ID of the X11 Visual to use."), QStringLiteral("id")));
1383 // Not using the "QStringList names" solution for those aliases, because it makes the first column too wide
1384 options->append(QCommandLineOption(QStringLiteral("geometry"),
1385 QGuiApplication::tr("Alias for --windowgeometry."), QStringLiteral("geometry")));
1386 options->append(QCommandLineOption(QStringLiteral("icon"),
1387 QGuiApplication::tr("Alias for --windowicon."), QStringLiteral("icon")));
1388 options->append(QCommandLineOption(QStringLiteral("title"),
1389 QGuiApplication::tr("Alias for --windowtitle."), QStringLiteral("title")));
1390 }
1391 }
1392 #endif // QT_CONFIG(commandlineparser)
1393
createPlatformIntegration()1394 void QGuiApplicationPrivate::createPlatformIntegration()
1395 {
1396 QHighDpiScaling::initHighDpiScaling();
1397
1398 // Load the platform integration
1399 QString platformPluginPath = QString::fromLocal8Bit(qgetenv("QT_QPA_PLATFORM_PLUGIN_PATH"));
1400
1401
1402 QByteArray platformName;
1403 #ifdef QT_QPA_DEFAULT_PLATFORM_NAME
1404 platformName = QT_QPA_DEFAULT_PLATFORM_NAME;
1405 #endif
1406 #if defined(Q_OS_UNIX) && !defined(Q_OS_DARWIN)
1407 QByteArray sessionType = qgetenv("XDG_SESSION_TYPE");
1408 if (!sessionType.isEmpty()) {
1409 if (sessionType == QByteArrayLiteral("x11") && !platformName.contains(QByteArrayLiteral("xcb"))) {
1410 platformName = QByteArrayLiteral("xcb");
1411 } else if (sessionType == QByteArrayLiteral("wayland") && !platformName.contains(QByteArrayLiteral("wayland"))) {
1412 QByteArray currentDesktop = qgetenv("XDG_CURRENT_DESKTOP").toLower();
1413 QByteArray sessionDesktop = qgetenv("XDG_SESSION_DESKTOP").toLower();
1414 if (currentDesktop.contains("gnome") || sessionDesktop.contains("gnome")) {
1415 qInfo() << "Warning: Ignoring XDG_SESSION_TYPE=wayland on Gnome."
1416 << "Use QT_QPA_PLATFORM=wayland to run on Wayland anyway.";
1417 } else {
1418 platformName = QByteArrayLiteral("wayland");
1419 }
1420 }
1421 }
1422 #ifdef QT_QPA_DEFAULT_PLATFORM_NAME
1423 // Add it as fallback in case XDG_SESSION_TYPE is something wrong
1424 if (!platformName.contains(QT_QPA_DEFAULT_PLATFORM_NAME))
1425 platformName += QByteArrayLiteral(";" QT_QPA_DEFAULT_PLATFORM_NAME);
1426 #endif
1427 #endif
1428
1429 QByteArray platformNameEnv = qgetenv("QT_QPA_PLATFORM");
1430 if (!platformNameEnv.isEmpty()) {
1431 platformName = platformNameEnv;
1432 }
1433
1434 QString platformThemeName = QString::fromLocal8Bit(qgetenv("QT_QPA_PLATFORMTHEME"));
1435
1436 // Get command line params
1437
1438 QString icon;
1439
1440 int j = argc ? 1 : 0;
1441 for (int i=1; i<argc; i++) {
1442 if (!argv[i])
1443 continue;
1444 if (*argv[i] != '-') {
1445 argv[j++] = argv[i];
1446 continue;
1447 }
1448 const bool xcbIsDefault = platformName.startsWith("xcb");
1449 const char *arg = argv[i];
1450 if (arg[1] == '-') // startsWith("--")
1451 ++arg;
1452 if (strcmp(arg, "-platformpluginpath") == 0) {
1453 if (++i < argc)
1454 platformPluginPath = QString::fromLocal8Bit(argv[i]);
1455 } else if (strcmp(arg, "-platform") == 0) {
1456 if (++i < argc)
1457 platformName = argv[i];
1458 } else if (strcmp(arg, "-platformtheme") == 0) {
1459 if (++i < argc)
1460 platformThemeName = QString::fromLocal8Bit(argv[i]);
1461 } else if (strcmp(arg, "-qwindowgeometry") == 0 || (xcbIsDefault && strcmp(arg, "-geometry") == 0)) {
1462 if (++i < argc)
1463 windowGeometrySpecification = QWindowGeometrySpecification::fromArgument(argv[i]);
1464 } else if (strcmp(arg, "-qwindowtitle") == 0 || (xcbIsDefault && strcmp(arg, "-title") == 0)) {
1465 if (++i < argc)
1466 firstWindowTitle = QString::fromLocal8Bit(argv[i]);
1467 } else if (strcmp(arg, "-qwindowicon") == 0 || (xcbIsDefault && strcmp(arg, "-icon") == 0)) {
1468 if (++i < argc) {
1469 icon = QString::fromLocal8Bit(argv[i]);
1470 }
1471 } else {
1472 argv[j++] = argv[i];
1473 }
1474 }
1475
1476 if (j < argc) {
1477 argv[j] = nullptr;
1478 argc = j;
1479 }
1480
1481 init_platform(QLatin1String(platformName), platformPluginPath, platformThemeName, argc, argv);
1482
1483 if (!icon.isEmpty())
1484 forcedWindowIcon = QDir::isAbsolutePath(icon) ? QIcon(icon) : QIcon::fromTheme(icon);
1485 }
1486
1487 /*!
1488 Called from QCoreApplication::init()
1489
1490 Responsible for creating an event dispatcher when QCoreApplication
1491 decides that it needs one (because a custom one has not been set).
1492 */
createEventDispatcher()1493 void QGuiApplicationPrivate::createEventDispatcher()
1494 {
1495 Q_ASSERT(!eventDispatcher);
1496
1497 if (platform_integration == nullptr)
1498 createPlatformIntegration();
1499
1500 // The platform integration should not mess with the event dispatcher
1501 Q_ASSERT(!eventDispatcher);
1502
1503 eventDispatcher = platform_integration->createEventDispatcher();
1504 }
1505
eventDispatcherReady()1506 void QGuiApplicationPrivate::eventDispatcherReady()
1507 {
1508 if (platform_integration == nullptr)
1509 createPlatformIntegration();
1510
1511 platform_integration->initialize();
1512
1513 // All platforms should have added screens at this point. Finish
1514 // QHighDpiScaling initialization if it has not been done so already.
1515 if (!QGuiApplicationPrivate::highDpiScalingUpdated)
1516 QHighDpiScaling::updateHighDpiScaling();
1517 }
1518
init()1519 void QGuiApplicationPrivate::init()
1520 {
1521 Q_TRACE_SCOPE(QGuiApplicationPrivate_init);
1522
1523 #if defined(Q_OS_MACOS)
1524 QMacAutoReleasePool pool;
1525 #endif
1526
1527 QCoreApplicationPrivate::init();
1528
1529 QCoreApplicationPrivate::is_app_running = false; // Starting up.
1530
1531 bool loadTestability = false;
1532 QList<QByteArray> pluginList;
1533 // Get command line params
1534 #ifndef QT_NO_SESSIONMANAGER
1535 QString session_id;
1536 QString session_key;
1537 # if defined(Q_OS_WIN)
1538 wchar_t guidstr[40];
1539 GUID guid;
1540 CoCreateGuid(&guid);
1541 StringFromGUID2(guid, guidstr, 40);
1542 session_id = QString::fromWCharArray(guidstr);
1543 CoCreateGuid(&guid);
1544 StringFromGUID2(guid, guidstr, 40);
1545 session_key = QString::fromWCharArray(guidstr);
1546 # endif
1547 #endif
1548 QString s;
1549 int j = argc ? 1 : 0;
1550 for (int i=1; i<argc; i++) {
1551 if (!argv[i])
1552 continue;
1553 if (*argv[i] != '-') {
1554 argv[j++] = argv[i];
1555 continue;
1556 }
1557 const char *arg = argv[i];
1558 if (arg[1] == '-') // startsWith("--")
1559 ++arg;
1560 if (strcmp(arg, "-plugin") == 0) {
1561 if (++i < argc)
1562 pluginList << argv[i];
1563 } else if (strcmp(arg, "-reverse") == 0) {
1564 force_reverse = true;
1565 #ifdef Q_OS_MAC
1566 } else if (strncmp(arg, "-psn_", 5) == 0) {
1567 // eat "-psn_xxxx" on Mac, which is passed when starting an app from Finder.
1568 // special hack to change working directory (for an app bundle) when running from finder
1569 if (QDir::currentPath() == QLatin1String("/")) {
1570 QCFType<CFURLRef> bundleURL(CFBundleCopyBundleURL(CFBundleGetMainBundle()));
1571 QString qbundlePath = QCFString(CFURLCopyFileSystemPath(bundleURL,
1572 kCFURLPOSIXPathStyle));
1573 if (qbundlePath.endsWith(QLatin1String(".app")))
1574 QDir::setCurrent(qbundlePath.section(QLatin1Char('/'), 0, -2));
1575 }
1576 #endif
1577 #ifndef QT_NO_SESSIONMANAGER
1578 } else if (strcmp(arg, "-session") == 0 && i < argc - 1) {
1579 ++i;
1580 if (argv[i] && *argv[i]) {
1581 session_id = QString::fromLatin1(argv[i]);
1582 int p = session_id.indexOf(QLatin1Char('_'));
1583 if (p >= 0) {
1584 session_key = session_id.mid(p +1);
1585 session_id = session_id.left(p);
1586 }
1587 is_session_restored = true;
1588 }
1589 #endif
1590 } else if (strcmp(arg, "-testability") == 0) {
1591 loadTestability = true;
1592 } else if (strncmp(arg, "-style=", 7) == 0) {
1593 s = QString::fromLocal8Bit(arg + 7);
1594 } else if (strcmp(arg, "-style") == 0 && i < argc - 1) {
1595 s = QString::fromLocal8Bit(argv[++i]);
1596 } else {
1597 argv[j++] = argv[i];
1598 }
1599
1600 if (!s.isEmpty())
1601 styleOverride = s;
1602 }
1603
1604 if (j < argc) {
1605 argv[j] = nullptr;
1606 argc = j;
1607 }
1608
1609 // Load environment exported generic plugins
1610 QByteArray envPlugins = qgetenv("QT_QPA_GENERIC_PLUGINS");
1611 if (!envPlugins.isEmpty())
1612 pluginList += envPlugins.split(',');
1613
1614 if (platform_integration == nullptr)
1615 createPlatformIntegration();
1616
1617 updatePalette();
1618 QFont::initialize();
1619 initThemeHints();
1620
1621 #ifndef QT_NO_CURSOR
1622 QCursorData::initialize();
1623 #endif
1624
1625 // trigger registering of QVariant's GUI types
1626 qRegisterGuiVariant();
1627
1628 #if QT_CONFIG(animation)
1629 // trigger registering of animation interpolators
1630 qRegisterGuiGetInterpolator();
1631 #endif
1632
1633 // set a global share context when enabled unless there is already one
1634 #ifndef QT_NO_OPENGL
1635 if (qApp->testAttribute(Qt::AA_ShareOpenGLContexts) && !qt_gl_global_share_context()) {
1636 QOpenGLContext *ctx = new QOpenGLContext;
1637 ctx->setFormat(QSurfaceFormat::defaultFormat());
1638 ctx->create();
1639 qt_gl_set_global_share_context(ctx);
1640 ownGlobalShareContext = true;
1641 }
1642 #endif
1643
1644 QWindowSystemInterfacePrivate::eventTime.start();
1645
1646 is_app_running = true;
1647 init_plugins(pluginList);
1648 QWindowSystemInterface::flushWindowSystemEvents();
1649
1650 Q_Q(QGuiApplication);
1651 #ifndef QT_NO_SESSIONMANAGER
1652 // connect to the session manager
1653 session_manager = new QSessionManager(q, session_id, session_key);
1654 #endif
1655
1656 #if QT_CONFIG(library)
1657 if (qEnvironmentVariableIntValue("QT_LOAD_TESTABILITY") > 0)
1658 loadTestability = true;
1659
1660 if (loadTestability) {
1661 QLibrary testLib(QStringLiteral("qttestability"));
1662 if (Q_UNLIKELY(!testLib.load())) {
1663 qCritical() << "Library qttestability load failed:" << testLib.errorString();
1664 } else {
1665 typedef void (*TasInitialize)(void);
1666 TasInitialize initFunction = (TasInitialize)testLib.resolve("qt_testability_init");
1667 if (Q_UNLIKELY(!initFunction)) {
1668 qCritical("Library qttestability resolve failed!");
1669 } else {
1670 initFunction();
1671 }
1672 }
1673 }
1674 #else
1675 Q_UNUSED(loadTestability);
1676 #endif // QT_CONFIG(library)
1677
1678 if (layout_direction == Qt::LayoutDirectionAuto || force_reverse)
1679 QGuiApplication::setLayoutDirection(qt_detectRTLLanguage() ? Qt::RightToLeft : Qt::LeftToRight);
1680
1681 if (!QGuiApplicationPrivate::displayName)
1682 QObject::connect(q, &QGuiApplication::applicationNameChanged,
1683 q, &QGuiApplication::applicationDisplayNameChanged);
1684 }
1685
1686 extern void qt_cleanupFontDatabase();
1687
~QGuiApplicationPrivate()1688 QGuiApplicationPrivate::~QGuiApplicationPrivate()
1689 {
1690 is_app_closing = true;
1691 is_app_running = false;
1692
1693 for (int i = 0; i < generic_plugin_list.count(); ++i)
1694 delete generic_plugin_list.at(i);
1695 generic_plugin_list.clear();
1696
1697 clearFontUnlocked();
1698
1699 QFont::cleanup();
1700
1701 #ifndef QT_NO_CURSOR
1702 QCursorData::cleanup();
1703 #endif
1704
1705 layout_direction = Qt::LeftToRight;
1706
1707 cleanupThreadData();
1708
1709 delete QGuiApplicationPrivate::styleHints;
1710 QGuiApplicationPrivate::styleHints = nullptr;
1711 delete inputMethod;
1712
1713 qt_cleanupFontDatabase();
1714
1715 QPixmapCache::clear();
1716
1717 #ifndef QT_NO_OPENGL
1718 if (ownGlobalShareContext) {
1719 delete qt_gl_global_share_context();
1720 qt_gl_set_global_share_context(nullptr);
1721 }
1722 #endif
1723
1724 platform_integration->destroy();
1725
1726 delete platform_theme;
1727 platform_theme = nullptr;
1728 delete platform_integration;
1729 platform_integration = nullptr;
1730
1731 window_list.clear();
1732 screen_list.clear();
1733
1734 self = nullptr;
1735 }
1736
1737 #if 0
1738 #ifndef QT_NO_CURSOR
1739 QCursor *overrideCursor();
1740 void setOverrideCursor(const QCursor &);
1741 void changeOverrideCursor(const QCursor &);
1742 void restoreOverrideCursor();
1743 #endif
1744
1745 static QFont font();
1746 static QFont font(const QWidget*);
1747 static QFont font(const char *className);
1748 static void setFont(const QFont &, const char* className = 0);
1749 static QFontMetrics fontMetrics();
1750
1751 #ifndef QT_NO_CLIPBOARD
1752 static QClipboard *clipboard();
1753 #endif
1754 #endif
1755
1756 /*!
1757 Returns the current state of the modifier keys on the keyboard. The current
1758 state is updated sychronously as the event queue is emptied of events that
1759 will spontaneously change the keyboard state (QEvent::KeyPress and
1760 QEvent::KeyRelease events).
1761
1762 It should be noted this may not reflect the actual keys held on the input
1763 device at the time of calling but rather the modifiers as last reported in
1764 one of the above events. If no keys are being held Qt::NoModifier is
1765 returned.
1766
1767 \sa mouseButtons(), queryKeyboardModifiers()
1768 */
keyboardModifiers()1769 Qt::KeyboardModifiers QGuiApplication::keyboardModifiers()
1770 {
1771 return QGuiApplicationPrivate::modifier_buttons;
1772 }
1773
1774 /*!
1775 \fn Qt::KeyboardModifiers QGuiApplication::queryKeyboardModifiers()
1776
1777 Queries and returns the state of the modifier keys on the keyboard.
1778 Unlike keyboardModifiers, this method returns the actual keys held
1779 on the input device at the time of calling the method.
1780
1781 It does not rely on the keypress events having been received by this
1782 process, which makes it possible to check the modifiers while moving
1783 a window, for instance. Note that in most cases, you should use
1784 keyboardModifiers(), which is faster and more accurate since it contains
1785 the state of the modifiers as they were when the currently processed
1786 event was received.
1787
1788 \sa keyboardModifiers()
1789 */
queryKeyboardModifiers()1790 Qt::KeyboardModifiers QGuiApplication::queryKeyboardModifiers()
1791 {
1792 CHECK_QAPP_INSTANCE(Qt::KeyboardModifiers{})
1793 QPlatformIntegration *pi = QGuiApplicationPrivate::platformIntegration();
1794 return pi->queryKeyboardModifiers();
1795 }
1796
1797 /*!
1798 Returns the current state of the buttons on the mouse. The current state is
1799 updated synchronously as the event queue is emptied of events that will
1800 spontaneously change the mouse state (QEvent::MouseButtonPress and
1801 QEvent::MouseButtonRelease events).
1802
1803 It should be noted this may not reflect the actual buttons held on the
1804 input device at the time of calling but rather the mouse buttons as last
1805 reported in one of the above events. If no mouse buttons are being held
1806 Qt::NoButton is returned.
1807
1808 \sa keyboardModifiers()
1809 */
mouseButtons()1810 Qt::MouseButtons QGuiApplication::mouseButtons()
1811 {
1812 return QGuiApplicationPrivate::mouse_buttons;
1813 }
1814
1815 /*!
1816 Returns the platform's native interface, for platform specific
1817 functionality.
1818 */
platformNativeInterface()1819 QPlatformNativeInterface *QGuiApplication::platformNativeInterface()
1820 {
1821 QPlatformIntegration *pi = QGuiApplicationPrivate::platformIntegration();
1822 return pi ? pi->nativeInterface() : nullptr;
1823 }
1824
1825 /*!
1826 Returns a function pointer from the platformplugin matching \a function
1827 */
platformFunction(const QByteArray & function)1828 QFunctionPointer QGuiApplication::platformFunction(const QByteArray &function)
1829 {
1830 QPlatformIntegration *pi = QGuiApplicationPrivate::platformIntegration();
1831 if (!pi) {
1832 qWarning("QGuiApplication::platformFunction(): Must construct a QGuiApplication before accessing a platform function");
1833 return nullptr;
1834 }
1835
1836 return pi->nativeInterface() ? pi->nativeInterface()->platformFunction(function) : nullptr;
1837 }
1838
1839 /*!
1840 Enters the main event loop and waits until exit() is called, and then
1841 returns the value that was set to exit() (which is 0 if exit() is called
1842 via quit()).
1843
1844 It is necessary to call this function to start event handling. The main
1845 event loop receives events from the window system and dispatches these to
1846 the application widgets.
1847
1848 Generally, no user interaction can take place before calling exec().
1849
1850 To make your application perform idle processing, e.g., executing a special
1851 function whenever there are no pending events, use a QTimer with 0 timeout.
1852 More advanced idle processing schemes can be achieved using processEvents().
1853
1854 We recommend that you connect clean-up code to the
1855 \l{QCoreApplication::}{aboutToQuit()} signal, instead of putting it in your
1856 application's \c{main()} function. This is because, on some platforms, the
1857 QApplication::exec() call may not return.
1858
1859 \sa quitOnLastWindowClosed, quit(), exit(), processEvents(),
1860 QCoreApplication::exec()
1861 */
exec()1862 int QGuiApplication::exec()
1863 {
1864 #ifndef QT_NO_ACCESSIBILITY
1865 QAccessible::setRootObject(qApp);
1866 #endif
1867 return QCoreApplication::exec();
1868 }
1869
captureGlobalModifierState(QEvent * e)1870 void QGuiApplicationPrivate::captureGlobalModifierState(QEvent *e)
1871 {
1872 if (e->spontaneous()) {
1873 // Capture the current mouse and keyboard states. Doing so here is
1874 // required in order to support Qt Test synthesized events. Real mouse
1875 // and keyboard state updates from the platform plugin are managed by
1876 // QGuiApplicationPrivate::process(Mouse|Wheel|Key|Touch|Tablet)Event();
1877 // ### FIXME: Qt Test should not call qapp->notify(), but rather route
1878 // the events through the proper QPA interface. This is required to
1879 // properly generate all other events such as enter/leave etc.
1880 switch (e->type()) {
1881 case QEvent::MouseButtonPress: {
1882 QMouseEvent *me = static_cast<QMouseEvent *>(e);
1883 QGuiApplicationPrivate::modifier_buttons = me->modifiers();
1884 QGuiApplicationPrivate::mouse_buttons |= me->button();
1885 break;
1886 }
1887 case QEvent::MouseButtonDblClick: {
1888 QMouseEvent *me = static_cast<QMouseEvent *>(e);
1889 QGuiApplicationPrivate::modifier_buttons = me->modifiers();
1890 QGuiApplicationPrivate::mouse_buttons |= me->button();
1891 break;
1892 }
1893 case QEvent::MouseButtonRelease: {
1894 QMouseEvent *me = static_cast<QMouseEvent *>(e);
1895 QGuiApplicationPrivate::modifier_buttons = me->modifiers();
1896 QGuiApplicationPrivate::mouse_buttons &= ~me->button();
1897 break;
1898 }
1899 case QEvent::KeyPress:
1900 case QEvent::KeyRelease:
1901 case QEvent::MouseMove:
1902 #if QT_CONFIG(wheelevent)
1903 case QEvent::Wheel:
1904 #endif
1905 case QEvent::TouchBegin:
1906 case QEvent::TouchUpdate:
1907 case QEvent::TouchEnd:
1908 #if QT_CONFIG(tabletevent)
1909 case QEvent::TabletMove:
1910 case QEvent::TabletPress:
1911 case QEvent::TabletRelease:
1912 #endif
1913 {
1914 QInputEvent *ie = static_cast<QInputEvent *>(e);
1915 QGuiApplicationPrivate::modifier_buttons = ie->modifiers();
1916 break;
1917 }
1918 default:
1919 break;
1920 }
1921 }
1922 }
1923
1924 /*! \reimp
1925 */
notify(QObject * object,QEvent * event)1926 bool QGuiApplication::notify(QObject *object, QEvent *event)
1927 {
1928 if (object->isWindowType()) {
1929 if (QGuiApplicationPrivate::sendQWindowEventToQPlatformWindow(static_cast<QWindow *>(object), event))
1930 return true; // Platform plugin ate the event
1931 }
1932
1933 QGuiApplicationPrivate::captureGlobalModifierState(event);
1934
1935 return QCoreApplication::notify(object, event);
1936 }
1937
1938 /*! \reimp
1939 */
event(QEvent * e)1940 bool QGuiApplication::event(QEvent *e)
1941 {
1942 if(e->type() == QEvent::LanguageChange) {
1943 setLayoutDirection(qt_detectRTLLanguage()?Qt::RightToLeft:Qt::LeftToRight);
1944 for (auto *topLevelWindow : QGuiApplication::topLevelWindows()) {
1945 if (topLevelWindow->flags() != Qt::Desktop)
1946 postEvent(topLevelWindow, new QEvent(QEvent::LanguageChange));
1947 }
1948 } else if (e->type() == QEvent::Quit) {
1949 // Close open windows. This is done in order to deliver de-expose
1950 // events while the event loop is still running.
1951 for (QWindow *topLevelWindow : QGuiApplication::topLevelWindows()) {
1952 // Already closed windows will not have a platform window, skip those
1953 if (!topLevelWindow->handle())
1954 continue;
1955 if (!topLevelWindow->close()) {
1956 e->ignore();
1957 return true;
1958 }
1959 }
1960 }
1961
1962 return QCoreApplication::event(e);
1963 }
1964
1965 /*!
1966 \internal
1967 */
compressEvent(QEvent * event,QObject * receiver,QPostEventList * postedEvents)1968 bool QGuiApplication::compressEvent(QEvent *event, QObject *receiver, QPostEventList *postedEvents)
1969 {
1970 return QCoreApplication::compressEvent(event, receiver, postedEvents);
1971 }
1972
sendQWindowEventToQPlatformWindow(QWindow * window,QEvent * event)1973 bool QGuiApplicationPrivate::sendQWindowEventToQPlatformWindow(QWindow *window, QEvent *event)
1974 {
1975 if (!window)
1976 return false;
1977 QPlatformWindow *platformWindow = window->handle();
1978 if (!platformWindow)
1979 return false;
1980 // spontaneous events come from the platform integration already, we don't need to send the events back
1981 if (event->spontaneous())
1982 return false;
1983 // let the platform window do any handling it needs to as well
1984 return platformWindow->windowEvent(event);
1985 }
1986
1987 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
processNativeEvent(QWindow * window,const QByteArray & eventType,void * message,qintptr * result)1988 bool QGuiApplicationPrivate::processNativeEvent(QWindow *window, const QByteArray &eventType, void *message, qintptr *result)
1989 #else
1990 bool QGuiApplicationPrivate::processNativeEvent(QWindow *window, const QByteArray &eventType, void *message, long *result)
1991 #endif
1992 {
1993 return window->nativeEvent(eventType, message, result);
1994 }
1995
processWindowSystemEvent(QWindowSystemInterfacePrivate::WindowSystemEvent * e)1996 void QGuiApplicationPrivate::processWindowSystemEvent(QWindowSystemInterfacePrivate::WindowSystemEvent *e)
1997 {
1998 Q_TRACE_SCOPE(QGuiApplicationPrivate_processWindowSystemEvent, e->type);
1999
2000 switch(e->type) {
2001 case QWindowSystemInterfacePrivate::Mouse:
2002 QGuiApplicationPrivate::processMouseEvent(static_cast<QWindowSystemInterfacePrivate::MouseEvent *>(e));
2003 break;
2004 case QWindowSystemInterfacePrivate::Wheel:
2005 QGuiApplicationPrivate::processWheelEvent(static_cast<QWindowSystemInterfacePrivate::WheelEvent *>(e));
2006 break;
2007 case QWindowSystemInterfacePrivate::Key:
2008 QGuiApplicationPrivate::processKeyEvent(static_cast<QWindowSystemInterfacePrivate::KeyEvent *>(e));
2009 break;
2010 case QWindowSystemInterfacePrivate::Touch:
2011 QGuiApplicationPrivate::processTouchEvent(static_cast<QWindowSystemInterfacePrivate::TouchEvent *>(e));
2012 break;
2013 case QWindowSystemInterfacePrivate::GeometryChange:
2014 QGuiApplicationPrivate::processGeometryChangeEvent(static_cast<QWindowSystemInterfacePrivate::GeometryChangeEvent*>(e));
2015 break;
2016 case QWindowSystemInterfacePrivate::Enter:
2017 QGuiApplicationPrivate::processEnterEvent(static_cast<QWindowSystemInterfacePrivate::EnterEvent *>(e));
2018 break;
2019 case QWindowSystemInterfacePrivate::Leave:
2020 QGuiApplicationPrivate::processLeaveEvent(static_cast<QWindowSystemInterfacePrivate::LeaveEvent *>(e));
2021 break;
2022 case QWindowSystemInterfacePrivate::ActivatedWindow:
2023 QGuiApplicationPrivate::processActivatedEvent(static_cast<QWindowSystemInterfacePrivate::ActivatedWindowEvent *>(e));
2024 break;
2025 case QWindowSystemInterfacePrivate::WindowStateChanged:
2026 QGuiApplicationPrivate::processWindowStateChangedEvent(static_cast<QWindowSystemInterfacePrivate::WindowStateChangedEvent *>(e));
2027 break;
2028 case QWindowSystemInterfacePrivate::WindowScreenChanged:
2029 QGuiApplicationPrivate::processWindowScreenChangedEvent(static_cast<QWindowSystemInterfacePrivate::WindowScreenChangedEvent *>(e));
2030 break;
2031 case QWindowSystemInterfacePrivate::SafeAreaMarginsChanged:
2032 QGuiApplicationPrivate::processSafeAreaMarginsChangedEvent(static_cast<QWindowSystemInterfacePrivate::SafeAreaMarginsChangedEvent *>(e));
2033 break;
2034 case QWindowSystemInterfacePrivate::ApplicationStateChanged: {
2035 QWindowSystemInterfacePrivate::ApplicationStateChangedEvent * changeEvent = static_cast<QWindowSystemInterfacePrivate::ApplicationStateChangedEvent *>(e);
2036 QGuiApplicationPrivate::setApplicationState(changeEvent->newState, changeEvent->forcePropagate); }
2037 break;
2038 case QWindowSystemInterfacePrivate::ApplicationTermination:
2039 QGuiApplicationPrivate::processApplicationTermination(e);
2040 break;
2041 case QWindowSystemInterfacePrivate::FlushEvents: {
2042 QWindowSystemInterfacePrivate::FlushEventsEvent *flushEventsEvent = static_cast<QWindowSystemInterfacePrivate::FlushEventsEvent *>(e);
2043 QWindowSystemInterface::deferredFlushWindowSystemEvents(flushEventsEvent->flags); }
2044 break;
2045 case QWindowSystemInterfacePrivate::Close:
2046 QGuiApplicationPrivate::processCloseEvent(
2047 static_cast<QWindowSystemInterfacePrivate::CloseEvent *>(e));
2048 break;
2049 case QWindowSystemInterfacePrivate::ScreenOrientation:
2050 QGuiApplicationPrivate::processScreenOrientationChange(
2051 static_cast<QWindowSystemInterfacePrivate::ScreenOrientationEvent *>(e));
2052 break;
2053 case QWindowSystemInterfacePrivate::ScreenGeometry:
2054 QGuiApplicationPrivate::processScreenGeometryChange(
2055 static_cast<QWindowSystemInterfacePrivate::ScreenGeometryEvent *>(e));
2056 break;
2057 case QWindowSystemInterfacePrivate::ScreenLogicalDotsPerInch:
2058 QGuiApplicationPrivate::processScreenLogicalDotsPerInchChange(
2059 static_cast<QWindowSystemInterfacePrivate::ScreenLogicalDotsPerInchEvent *>(e));
2060 break;
2061 case QWindowSystemInterfacePrivate::ScreenRefreshRate:
2062 QGuiApplicationPrivate::processScreenRefreshRateChange(
2063 static_cast<QWindowSystemInterfacePrivate::ScreenRefreshRateEvent *>(e));
2064 break;
2065 case QWindowSystemInterfacePrivate::ThemeChange:
2066 QGuiApplicationPrivate::processThemeChanged(
2067 static_cast<QWindowSystemInterfacePrivate::ThemeChangeEvent *>(e));
2068 break;
2069 case QWindowSystemInterfacePrivate::Expose:
2070 QGuiApplicationPrivate::processExposeEvent(static_cast<QWindowSystemInterfacePrivate::ExposeEvent *>(e));
2071 break;
2072 case QWindowSystemInterfacePrivate::Tablet:
2073 QGuiApplicationPrivate::processTabletEvent(
2074 static_cast<QWindowSystemInterfacePrivate::TabletEvent *>(e));
2075 break;
2076 case QWindowSystemInterfacePrivate::TabletEnterProximity:
2077 QGuiApplicationPrivate::processTabletEnterProximityEvent(
2078 static_cast<QWindowSystemInterfacePrivate::TabletEnterProximityEvent *>(e));
2079 break;
2080 case QWindowSystemInterfacePrivate::TabletLeaveProximity:
2081 QGuiApplicationPrivate::processTabletLeaveProximityEvent(
2082 static_cast<QWindowSystemInterfacePrivate::TabletLeaveProximityEvent *>(e));
2083 break;
2084 #ifndef QT_NO_GESTURES
2085 case QWindowSystemInterfacePrivate::Gesture:
2086 QGuiApplicationPrivate::processGestureEvent(
2087 static_cast<QWindowSystemInterfacePrivate::GestureEvent *>(e));
2088 break;
2089 #endif
2090 case QWindowSystemInterfacePrivate::PlatformPanel:
2091 QGuiApplicationPrivate::processPlatformPanelEvent(
2092 static_cast<QWindowSystemInterfacePrivate::PlatformPanelEvent *>(e));
2093 break;
2094 case QWindowSystemInterfacePrivate::FileOpen:
2095 QGuiApplicationPrivate::processFileOpenEvent(
2096 static_cast<QWindowSystemInterfacePrivate::FileOpenEvent *>(e));
2097 break;
2098 #ifndef QT_NO_CONTEXTMENU
2099 case QWindowSystemInterfacePrivate::ContextMenu:
2100 QGuiApplicationPrivate::processContextMenuEvent(
2101 static_cast<QWindowSystemInterfacePrivate::ContextMenuEvent *>(e));
2102 break;
2103 #endif
2104 case QWindowSystemInterfacePrivate::EnterWhatsThisMode:
2105 QGuiApplication::postEvent(QGuiApplication::instance(), new QEvent(QEvent::EnterWhatsThisMode));
2106 break;
2107 default:
2108 qWarning() << "Unknown user input event type:" << e->type;
2109 break;
2110 }
2111 }
2112
2113 /*! \internal
2114
2115 History is silent on why Qt splits mouse events that change position and
2116 button state at the same time. We believe that this was done to emulate mouse
2117 behavior on touch screens. If mouse tracking is enabled, we will get move
2118 events before the button is pressed. A touch panel does not generally give
2119 move events when not pressed, so without event splitting code path we would
2120 only see a press in a new location without any intervening moves. This could
2121 confuse code that is written for a real mouse. The same is true for mouse
2122 release events that change position, see tst_QWidget::touchEventSynthesizedMouseEvent()
2123 and tst_QWindow::generatedMouseMove() auto tests.
2124 */
processMouseEvent(QWindowSystemInterfacePrivate::MouseEvent * e)2125 void QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::MouseEvent *e)
2126 {
2127 QEvent::Type type = QEvent::None;
2128 Qt::MouseButton button = Qt::NoButton;
2129 QWindow *window = e->window.data();
2130 bool positionChanged = QGuiApplicationPrivate::lastCursorPosition != e->globalPos;
2131 bool mouseMove = false;
2132 bool mousePress = false;
2133
2134 if (qIsNaN(e->globalPos.x()) || qIsNaN(e->globalPos.y())) {
2135 qWarning("QGuiApplicationPrivate::processMouseEvent: Got NaN in mouse position");
2136 return;
2137 }
2138
2139 if (e->enhancedMouseEvent()) {
2140 type = e->buttonType;
2141 button = e->button;
2142
2143 if (type == QEvent::NonClientAreaMouseMove || type == QEvent::MouseMove)
2144 mouseMove = true;
2145 else if (type == QEvent::NonClientAreaMouseButtonPress || type == QEvent::MouseButtonPress)
2146 mousePress = true;
2147
2148 if (!mouseMove && positionChanged) {
2149 QWindowSystemInterfacePrivate::MouseEvent moveEvent(window, e->timestamp,
2150 e->localPos, e->globalPos, e->buttons ^ button, e->modifiers, Qt::NoButton,
2151 e->nonClientArea ? QEvent::NonClientAreaMouseMove : QEvent::MouseMove,
2152 e->source, e->nonClientArea);
2153 if (e->synthetic())
2154 moveEvent.flags |= QWindowSystemInterfacePrivate::WindowSystemEvent::Synthetic;
2155 processMouseEvent(&moveEvent); // mouse move excluding state change
2156 processMouseEvent(e); // the original mouse event
2157 return;
2158 }
2159 if (mouseMove && !positionChanged) {
2160 // On Windows, and possibly other platforms, a touchpad can send a mouse move
2161 // that does not change position, between a press and a release. This may
2162 // confuse applications, so we always filter out these mouse events for
2163 // consistent behavior among platforms.
2164 return;
2165 }
2166 } else {
2167 Qt::MouseButtons stateChange = e->buttons ^ mouse_buttons;
2168 if (positionChanged && (stateChange != Qt::NoButton)) {
2169 QWindowSystemInterfacePrivate::MouseEvent moveEvent(window, e->timestamp, e->localPos,
2170 e->globalPos, mouse_buttons, e->modifiers, Qt::NoButton, QEvent::None, e->source,
2171 e->nonClientArea);
2172 if (e->synthetic())
2173 moveEvent.flags |= QWindowSystemInterfacePrivate::WindowSystemEvent::Synthetic;
2174 processMouseEvent(&moveEvent); // mouse move excluding state change
2175 processMouseEvent(e); // the original mouse event
2176 return;
2177 }
2178
2179 // In the compatibility path we deduce event type and button that caused the event
2180 if (positionChanged) {
2181 mouseMove = true;
2182 type = e->nonClientArea ? QEvent::NonClientAreaMouseMove : QEvent::MouseMove;
2183 } else {
2184 // Check to see if a new button has been pressed/released.
2185 for (uint mask = Qt::LeftButton; mask <= Qt::MaxMouseButton; mask <<= 1) {
2186 if (stateChange & mask) {
2187 button = Qt::MouseButton(mask);
2188 break;
2189 }
2190 }
2191 if (button == Qt::NoButton) {
2192 // Ignore mouse events that don't change the current state. This shouldn't
2193 // really happen, getting here can only mean that the stored button state
2194 // is out of sync with the actual physical button state.
2195 return;
2196 }
2197 if (button & e->buttons) {
2198 mousePress = true;
2199 type = e->nonClientArea ? QEvent::NonClientAreaMouseButtonPress
2200 : QEvent::MouseButtonPress;
2201 } else {
2202 type = e->nonClientArea ? QEvent::NonClientAreaMouseButtonRelease
2203 : QEvent::MouseButtonRelease;
2204 }
2205 }
2206 }
2207
2208 modifier_buttons = e->modifiers;
2209 QPointF localPoint = e->localPos;
2210 QPointF globalPoint = e->globalPos;
2211 bool doubleClick = false;
2212
2213 if (mouseMove) {
2214 QGuiApplicationPrivate::lastCursorPosition = globalPoint;
2215 const auto doubleClickDistance = e->source == Qt::MouseEventNotSynthesized ?
2216 mouseDoubleClickDistance : touchDoubleTapDistance;
2217 if (qAbs(globalPoint.x() - mousePressX) > doubleClickDistance ||
2218 qAbs(globalPoint.y() - mousePressY) > doubleClickDistance)
2219 mousePressButton = Qt::NoButton;
2220 } else {
2221 mouse_buttons = e->buttons;
2222 if (mousePress) {
2223 ulong doubleClickInterval = static_cast<ulong>(QGuiApplication::styleHints()->mouseDoubleClickInterval());
2224 doubleClick = e->timestamp - mousePressTime < doubleClickInterval && button == mousePressButton;
2225 mousePressTime = e->timestamp;
2226 mousePressButton = button;
2227 const QPoint point = QGuiApplicationPrivate::lastCursorPosition.toPoint();
2228 mousePressX = point.x();
2229 mousePressY = point.y();
2230 }
2231 }
2232
2233 if (e->nullWindow()) {
2234 window = QGuiApplication::topLevelAt(globalPoint.toPoint());
2235 if (window) {
2236 // Moves and the release following a press must go to the same
2237 // window, even if the cursor has moved on over another window.
2238 if (e->buttons != Qt::NoButton) {
2239 if (!currentMousePressWindow)
2240 currentMousePressWindow = window;
2241 else
2242 window = currentMousePressWindow;
2243 } else if (currentMousePressWindow) {
2244 window = currentMousePressWindow;
2245 currentMousePressWindow = nullptr;
2246 }
2247 QPointF delta = globalPoint - globalPoint.toPoint();
2248 localPoint = window->mapFromGlobal(globalPoint.toPoint()) + delta;
2249 }
2250 }
2251
2252 if (!window)
2253 return;
2254
2255 #ifndef QT_NO_CURSOR
2256 if (!e->synthetic()) {
2257 if (const QScreen *screen = window->screen())
2258 if (QPlatformCursor *cursor = screen->handle()->cursor()) {
2259 const QPointF nativeLocalPoint = QHighDpi::toNativePixels(localPoint, screen);
2260 const QPointF nativeGlobalPoint = QHighDpi::toNativePixels(globalPoint, screen);
2261 QMouseEvent ev(type, nativeLocalPoint, nativeLocalPoint, nativeGlobalPoint,
2262 button, e->buttons, e->modifiers, e->source);
2263 ev.setTimestamp(e->timestamp);
2264 cursor->pointerEvent(ev);
2265 }
2266 }
2267 #endif
2268
2269 QMouseEvent ev(type, localPoint, localPoint, globalPoint, button, e->buttons, e->modifiers, e->source);
2270 ev.setTimestamp(e->timestamp);
2271
2272 if (window->d_func()->blockedByModalWindow && !qApp->d_func()->popupActive()) {
2273 // a modal window is blocking this window, don't allow mouse events through
2274 return;
2275 }
2276
2277 if (doubleClick && (ev.type() == QEvent::MouseButtonPress)) {
2278 // QtBUG-25831, used to suppress delivery in qwidgetwindow.cpp
2279 setMouseEventFlags(&ev, ev.flags() | Qt::MouseEventCreatedDoubleClick);
2280 }
2281
2282 QGuiApplication::sendSpontaneousEvent(window, &ev);
2283 e->eventAccepted = ev.isAccepted();
2284 if (!e->synthetic() && !ev.isAccepted()
2285 && !e->nonClientArea
2286 && qApp->testAttribute(Qt::AA_SynthesizeTouchForUnhandledMouseEvents)) {
2287 if (!m_fakeTouchDevice) {
2288 m_fakeTouchDevice = new QTouchDevice;
2289 QWindowSystemInterface::registerTouchDevice(m_fakeTouchDevice);
2290 }
2291 QList<QWindowSystemInterface::TouchPoint> points;
2292 QWindowSystemInterface::TouchPoint point;
2293 point.id = 1;
2294 point.area = QRectF(globalPoint.x() - 2, globalPoint.y() - 2, 4, 4);
2295
2296 // only translate left button related events to
2297 // avoid strange touch event sequences when several
2298 // buttons are pressed
2299 if (type == QEvent::MouseButtonPress && button == Qt::LeftButton) {
2300 point.state = Qt::TouchPointPressed;
2301 } else if (type == QEvent::MouseButtonRelease && button == Qt::LeftButton) {
2302 point.state = Qt::TouchPointReleased;
2303 } else if (type == QEvent::MouseMove && (e->buttons & Qt::LeftButton)) {
2304 point.state = Qt::TouchPointMoved;
2305 } else {
2306 return;
2307 }
2308
2309 points << point;
2310
2311 QEvent::Type type;
2312 QList<QTouchEvent::TouchPoint> touchPoints =
2313 QWindowSystemInterfacePrivate::fromNativeTouchPoints(points, window, QTouchDevicePrivate::get(m_fakeTouchDevice)->id, &type);
2314
2315 QWindowSystemInterfacePrivate::TouchEvent fake(window, e->timestamp, type, m_fakeTouchDevice, touchPoints, e->modifiers);
2316 fake.flags |= QWindowSystemInterfacePrivate::WindowSystemEvent::Synthetic;
2317 processTouchEvent(&fake);
2318 }
2319 if (doubleClick) {
2320 mousePressButton = Qt::NoButton;
2321 if (!e->window.isNull() || e->nullWindow()) { // QTBUG-36364, check if window closed in response to press
2322 const QEvent::Type doubleClickType = e->nonClientArea ? QEvent::NonClientAreaMouseButtonDblClick : QEvent::MouseButtonDblClick;
2323 QMouseEvent dblClickEvent(doubleClickType, localPoint, localPoint, globalPoint,
2324 button, e->buttons, e->modifiers, e->source);
2325 dblClickEvent.setTimestamp(e->timestamp);
2326 QGuiApplication::sendSpontaneousEvent(window, &dblClickEvent);
2327 }
2328 }
2329 }
2330
processWheelEvent(QWindowSystemInterfacePrivate::WheelEvent * e)2331 void QGuiApplicationPrivate::processWheelEvent(QWindowSystemInterfacePrivate::WheelEvent *e)
2332 {
2333 #if QT_CONFIG(wheelevent)
2334 QWindow *window = e->window.data();
2335 QPointF globalPoint = e->globalPos;
2336 QPointF localPoint = e->localPos;
2337
2338 if (e->nullWindow()) {
2339 window = QGuiApplication::topLevelAt(globalPoint.toPoint());
2340 if (window) {
2341 QPointF delta = globalPoint - globalPoint.toPoint();
2342 localPoint = window->mapFromGlobal(globalPoint.toPoint()) + delta;
2343 }
2344 }
2345
2346 if (!window)
2347 return;
2348
2349 QGuiApplicationPrivate::lastCursorPosition = globalPoint;
2350 modifier_buttons = e->modifiers;
2351
2352 if (window->d_func()->blockedByModalWindow) {
2353 // a modal window is blocking this window, don't allow wheel events through
2354 return;
2355 }
2356
2357 #if QT_DEPRECATED_SINCE(5, 14)
2358 QT_WARNING_PUSH
2359 QT_WARNING_DISABLE_DEPRECATED
2360 QWheelEvent ev(localPoint, globalPoint, e->pixelDelta, e->angleDelta, e->qt4Delta, e->qt4Orientation,
2361 mouse_buttons, e->modifiers, e->phase, e->source, e->inverted);
2362 QT_WARNING_POP
2363 #else
2364 QWheelEvent ev(localPoint, globalPoint, e->pixelDelta, e->angleDelta,
2365 mouse_buttons, e->modifiers, e->phase, e->inverted, e->source);
2366 #endif
2367 ev.setTimestamp(e->timestamp);
2368 QGuiApplication::sendSpontaneousEvent(window, &ev);
2369 #else
2370 Q_UNUSED(e);
2371 #endif // QT_CONFIG(wheelevent)
2372 }
2373
processKeyEvent(QWindowSystemInterfacePrivate::KeyEvent * e)2374 void QGuiApplicationPrivate::processKeyEvent(QWindowSystemInterfacePrivate::KeyEvent *e)
2375 {
2376 QWindow *window = e->window.data();
2377 modifier_buttons = e->modifiers;
2378 if (e->nullWindow()
2379 #if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED)
2380 || e->key == Qt::Key_Back || e->key == Qt::Key_Menu
2381 #endif
2382 ) {
2383 window = QGuiApplication::focusWindow();
2384 }
2385
2386 #if defined(Q_OS_ANDROID)
2387 static bool backKeyPressAccepted = false;
2388 static bool menuKeyPressAccepted = false;
2389 #endif
2390
2391 #if !defined(Q_OS_MACOS)
2392 // FIXME: Include OS X in this code path by passing the key event through
2393 // QPlatformInputContext::filterEvent().
2394 if (e->keyType == QEvent::KeyPress && window) {
2395 if (QWindowSystemInterface::handleShortcutEvent(window, e->timestamp, e->key, e->modifiers,
2396 e->nativeScanCode, e->nativeVirtualKey, e->nativeModifiers, e->unicode, e->repeat, e->repeatCount)) {
2397 #if defined(Q_OS_ANDROID)
2398 backKeyPressAccepted = e->key == Qt::Key_Back;
2399 menuKeyPressAccepted = e->key == Qt::Key_Menu;
2400 #endif
2401 return;
2402 }
2403 }
2404 #endif
2405
2406 QKeyEvent ev(e->keyType, e->key, e->modifiers,
2407 e->nativeScanCode, e->nativeVirtualKey, e->nativeModifiers,
2408 e->unicode, e->repeat, e->repeatCount);
2409 ev.setTimestamp(e->timestamp);
2410
2411 // only deliver key events when we have a window, and no modal window is blocking this window
2412
2413 if (window && !window->d_func()->blockedByModalWindow)
2414 QGuiApplication::sendSpontaneousEvent(window, &ev);
2415 #if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED)
2416 else
2417 ev.setAccepted(false);
2418
2419 if (e->keyType == QEvent::KeyPress) {
2420 backKeyPressAccepted = e->key == Qt::Key_Back && ev.isAccepted();
2421 menuKeyPressAccepted = e->key == Qt::Key_Menu && ev.isAccepted();
2422 } else if (e->keyType == QEvent::KeyRelease) {
2423 if (e->key == Qt::Key_Back && !backKeyPressAccepted && !ev.isAccepted()) {
2424 if (window)
2425 QWindowSystemInterface::handleCloseEvent(window);
2426 } else if (e->key == Qt::Key_Menu && !menuKeyPressAccepted && !ev.isAccepted()) {
2427 platform_theme->showPlatformMenuBar();
2428 }
2429 }
2430 #endif
2431 e->eventAccepted = ev.isAccepted();
2432 }
2433
processEnterEvent(QWindowSystemInterfacePrivate::EnterEvent * e)2434 void QGuiApplicationPrivate::processEnterEvent(QWindowSystemInterfacePrivate::EnterEvent *e)
2435 {
2436 if (!e->enter)
2437 return;
2438 if (e->enter.data()->d_func()->blockedByModalWindow) {
2439 // a modal window is blocking this window, don't allow enter events through
2440 return;
2441 }
2442
2443 currentMouseWindow = e->enter;
2444
2445 QEnterEvent event(e->localPos, e->localPos, e->globalPos);
2446 QCoreApplication::sendSpontaneousEvent(e->enter.data(), &event);
2447 }
2448
processLeaveEvent(QWindowSystemInterfacePrivate::LeaveEvent * e)2449 void QGuiApplicationPrivate::processLeaveEvent(QWindowSystemInterfacePrivate::LeaveEvent *e)
2450 {
2451 if (!e->leave)
2452 return;
2453 if (e->leave.data()->d_func()->blockedByModalWindow) {
2454 // a modal window is blocking this window, don't allow leave events through
2455 return;
2456 }
2457
2458 currentMouseWindow = nullptr;
2459
2460 QEvent event(QEvent::Leave);
2461 QCoreApplication::sendSpontaneousEvent(e->leave.data(), &event);
2462 }
2463
processActivatedEvent(QWindowSystemInterfacePrivate::ActivatedWindowEvent * e)2464 void QGuiApplicationPrivate::processActivatedEvent(QWindowSystemInterfacePrivate::ActivatedWindowEvent *e)
2465 {
2466 QWindow *previous = QGuiApplicationPrivate::focus_window;
2467 QWindow *newFocus = e->activated.data();
2468
2469 if (previous == newFocus)
2470 return;
2471
2472 if (newFocus)
2473 if (QPlatformWindow *platformWindow = newFocus->handle())
2474 if (platformWindow->isAlertState())
2475 platformWindow->setAlertState(false);
2476
2477 QObject *previousFocusObject = previous ? previous->focusObject() : nullptr;
2478
2479 if (previous) {
2480 QFocusEvent focusAboutToChange(QEvent::FocusAboutToChange);
2481 QCoreApplication::sendSpontaneousEvent(previous, &focusAboutToChange);
2482 }
2483
2484 QGuiApplicationPrivate::focus_window = newFocus;
2485 if (!qApp)
2486 return;
2487
2488 if (previous) {
2489 Qt::FocusReason r = e->reason;
2490 if ((r == Qt::OtherFocusReason || r == Qt::ActiveWindowFocusReason) &&
2491 newFocus && (newFocus->flags() & Qt::Popup) == Qt::Popup)
2492 r = Qt::PopupFocusReason;
2493 QFocusEvent focusOut(QEvent::FocusOut, r);
2494 QCoreApplication::sendSpontaneousEvent(previous, &focusOut);
2495 QObject::disconnect(previous, SIGNAL(focusObjectChanged(QObject*)),
2496 qApp, SLOT(_q_updateFocusObject(QObject*)));
2497 } else if (!platformIntegration()->hasCapability(QPlatformIntegration::ApplicationState)) {
2498 setApplicationState(Qt::ApplicationActive);
2499 }
2500
2501 if (QGuiApplicationPrivate::focus_window) {
2502 Qt::FocusReason r = e->reason;
2503 if ((r == Qt::OtherFocusReason || r == Qt::ActiveWindowFocusReason) &&
2504 previous && (previous->flags() & Qt::Popup) == Qt::Popup)
2505 r = Qt::PopupFocusReason;
2506 QFocusEvent focusIn(QEvent::FocusIn, r);
2507 QCoreApplication::sendSpontaneousEvent(QGuiApplicationPrivate::focus_window, &focusIn);
2508 QObject::connect(QGuiApplicationPrivate::focus_window, SIGNAL(focusObjectChanged(QObject*)),
2509 qApp, SLOT(_q_updateFocusObject(QObject*)));
2510 } else if (!platformIntegration()->hasCapability(QPlatformIntegration::ApplicationState)) {
2511 setApplicationState(Qt::ApplicationInactive);
2512 }
2513
2514 if (self) {
2515 self->notifyActiveWindowChange(previous);
2516
2517 if (previousFocusObject != qApp->focusObject())
2518 self->_q_updateFocusObject(qApp->focusObject());
2519 }
2520
2521 emit qApp->focusWindowChanged(newFocus);
2522 if (previous)
2523 emit previous->activeChanged();
2524 if (newFocus)
2525 emit newFocus->activeChanged();
2526 }
2527
processWindowStateChangedEvent(QWindowSystemInterfacePrivate::WindowStateChangedEvent * wse)2528 void QGuiApplicationPrivate::processWindowStateChangedEvent(QWindowSystemInterfacePrivate::WindowStateChangedEvent *wse)
2529 {
2530 if (QWindow *window = wse->window.data()) {
2531 QWindowStateChangeEvent e(wse->oldState);
2532 window->d_func()->windowState = wse->newState;
2533 QGuiApplication::sendSpontaneousEvent(window, &e);
2534 }
2535 }
2536
processWindowScreenChangedEvent(QWindowSystemInterfacePrivate::WindowScreenChangedEvent * wse)2537 void QGuiApplicationPrivate::processWindowScreenChangedEvent(QWindowSystemInterfacePrivate::WindowScreenChangedEvent *wse)
2538 {
2539 if (QWindow *window = wse->window.data()) {
2540 if (window->screen() == wse->screen.data())
2541 return;
2542 if (QWindow *topLevelWindow = window->d_func()->topLevelWindow(QWindow::ExcludeTransients)) {
2543 if (QScreen *screen = wse->screen.data())
2544 topLevelWindow->d_func()->setTopLevelScreen(screen, false /* recreate */);
2545 else // Fall back to default behavior, and try to find some appropriate screen
2546 topLevelWindow->setScreen(nullptr);
2547 }
2548 // we may have changed scaling, so trigger resize event if needed
2549 if (window->handle()) {
2550 QWindowSystemInterfacePrivate::GeometryChangeEvent gce(window, QHighDpi::fromNativePixels(window->handle()->geometry(), window));
2551 processGeometryChangeEvent(&gce);
2552 }
2553 }
2554 }
2555
processSafeAreaMarginsChangedEvent(QWindowSystemInterfacePrivate::SafeAreaMarginsChangedEvent * wse)2556 void QGuiApplicationPrivate::processSafeAreaMarginsChangedEvent(QWindowSystemInterfacePrivate::SafeAreaMarginsChangedEvent *wse)
2557 {
2558 if (wse->window.isNull())
2559 return;
2560
2561 // Handle by forwarding directly to QWindowPrivate, instead of sending spontaneous
2562 // QEvent like most other functions, as there's no QEvent type for the safe area
2563 // change, and we don't want to add one until we know that this is a good API.
2564 qt_window_private(wse->window)->processSafeAreaMarginsChanged();
2565 }
2566
processThemeChanged(QWindowSystemInterfacePrivate::ThemeChangeEvent * tce)2567 void QGuiApplicationPrivate::processThemeChanged(QWindowSystemInterfacePrivate::ThemeChangeEvent *tce)
2568 {
2569 if (self)
2570 self->notifyThemeChanged();
2571 if (QWindow *window = tce->window.data()) {
2572 QEvent e(QEvent::ThemeChange);
2573 QGuiApplication::sendSpontaneousEvent(window, &e);
2574 }
2575 }
2576
processGeometryChangeEvent(QWindowSystemInterfacePrivate::GeometryChangeEvent * e)2577 void QGuiApplicationPrivate::processGeometryChangeEvent(QWindowSystemInterfacePrivate::GeometryChangeEvent *e)
2578 {
2579 if (e->window.isNull())
2580 return;
2581
2582 QWindow *window = e->window.data();
2583 if (!window)
2584 return;
2585
2586 const QRect lastReportedGeometry = window->d_func()->geometry;
2587 const QRect requestedGeometry = e->requestedGeometry;
2588 const QRect actualGeometry = e->newGeometry;
2589
2590 // We send size and move events only if the geometry has changed from
2591 // what was last reported, or if the user tried to set a new geometry,
2592 // but the window manager responded by keeping the old geometry. In the
2593 // latter case we send move/resize events with the same geometry as the
2594 // last reported geometry, to indicate that the window wasn't moved or
2595 // resized. Note that this logic does not apply to the property changes
2596 // of the window, as we don't treat them as part of this request/response
2597 // protocol of QWindow/QPA.
2598 const bool isResize = actualGeometry.size() != lastReportedGeometry.size()
2599 || requestedGeometry.size() != actualGeometry.size();
2600 const bool isMove = actualGeometry.topLeft() != lastReportedGeometry.topLeft()
2601 || requestedGeometry.topLeft() != actualGeometry.topLeft();
2602
2603 window->d_func()->geometry = actualGeometry;
2604
2605 if (isResize || window->d_func()->resizeEventPending) {
2606 QResizeEvent e(actualGeometry.size(), lastReportedGeometry.size());
2607 QGuiApplication::sendSpontaneousEvent(window, &e);
2608
2609 window->d_func()->resizeEventPending = false;
2610
2611 if (actualGeometry.width() != lastReportedGeometry.width())
2612 emit window->widthChanged(actualGeometry.width());
2613 if (actualGeometry.height() != lastReportedGeometry.height())
2614 emit window->heightChanged(actualGeometry.height());
2615 }
2616
2617 if (isMove) {
2618 //### frame geometry
2619 QMoveEvent e(actualGeometry.topLeft(), lastReportedGeometry.topLeft());
2620 QGuiApplication::sendSpontaneousEvent(window, &e);
2621
2622 if (actualGeometry.x() != lastReportedGeometry.x())
2623 emit window->xChanged(actualGeometry.x());
2624 if (actualGeometry.y() != lastReportedGeometry.y())
2625 emit window->yChanged(actualGeometry.y());
2626 }
2627 }
2628
processCloseEvent(QWindowSystemInterfacePrivate::CloseEvent * e)2629 void QGuiApplicationPrivate::processCloseEvent(QWindowSystemInterfacePrivate::CloseEvent *e)
2630 {
2631 if (e->window.isNull())
2632 return;
2633 if (e->window.data()->d_func()->blockedByModalWindow) {
2634 // a modal window is blocking this window, don't allow close events through
2635 return;
2636 }
2637
2638 QCloseEvent event;
2639 QGuiApplication::sendSpontaneousEvent(e->window.data(), &event);
2640
2641 e->eventAccepted = event.isAccepted();
2642 }
2643
processFileOpenEvent(QWindowSystemInterfacePrivate::FileOpenEvent * e)2644 void QGuiApplicationPrivate::processFileOpenEvent(QWindowSystemInterfacePrivate::FileOpenEvent *e)
2645 {
2646 if (e->url.isEmpty())
2647 return;
2648
2649 QFileOpenEvent event(e->url);
2650 QGuiApplication::sendSpontaneousEvent(qApp, &event);
2651 }
2652
tabletDevicePoint(qint64 deviceId)2653 QGuiApplicationPrivate::TabletPointData &QGuiApplicationPrivate::tabletDevicePoint(qint64 deviceId)
2654 {
2655 for (int i = 0; i < tabletDevicePoints.size(); ++i) {
2656 TabletPointData &pointData = tabletDevicePoints[i];
2657 if (pointData.deviceId == deviceId)
2658 return pointData;
2659 }
2660
2661 tabletDevicePoints.append(TabletPointData(deviceId));
2662 return tabletDevicePoints.last();
2663 }
2664
processTabletEvent(QWindowSystemInterfacePrivate::TabletEvent * e)2665 void QGuiApplicationPrivate::processTabletEvent(QWindowSystemInterfacePrivate::TabletEvent *e)
2666 {
2667 #if QT_CONFIG(tabletevent)
2668 TabletPointData &pointData = tabletDevicePoint(e->uid);
2669
2670 QEvent::Type type = QEvent::TabletMove;
2671 if (e->buttons != pointData.state)
2672 type = (e->buttons > pointData.state) ? QEvent::TabletPress : QEvent::TabletRelease;
2673
2674 QWindow *window = e->window.data();
2675 modifier_buttons = e->modifiers;
2676
2677 bool localValid = true;
2678 // If window is null, pick one based on the global position and make sure all
2679 // subsequent events up to the release are delivered to that same window.
2680 // If window is given, just send to that.
2681 if (type == QEvent::TabletPress) {
2682 if (e->nullWindow()) {
2683 window = QGuiApplication::topLevelAt(e->global.toPoint());
2684 localValid = false;
2685 }
2686 if (!window)
2687 return;
2688 pointData.target = window;
2689 } else {
2690 if (e->nullWindow()) {
2691 window = pointData.target;
2692 localValid = false;
2693 }
2694 if (type == QEvent::TabletRelease)
2695 pointData.target = nullptr;
2696 if (!window)
2697 return;
2698 }
2699 QPointF local = e->local;
2700 if (!localValid) {
2701 QPointF delta = e->global - e->global.toPoint();
2702 local = window->mapFromGlobal(e->global.toPoint()) + delta;
2703 }
2704 Qt::MouseButtons stateChange = e->buttons ^ pointData.state;
2705 Qt::MouseButton button = Qt::NoButton;
2706 for (int check = Qt::LeftButton; check <= int(Qt::MaxMouseButton); check = check << 1) {
2707 if (check & stateChange) {
2708 button = Qt::MouseButton(check);
2709 break;
2710 }
2711 }
2712 QTabletEvent tabletEvent(type, local, e->global,
2713 e->device, e->pointerType, e->pressure, e->xTilt, e->yTilt,
2714 e->tangentialPressure, e->rotation, e->z,
2715 e->modifiers, e->uid, button, e->buttons);
2716 tabletEvent.setAccepted(false);
2717 tabletEvent.setTimestamp(e->timestamp);
2718 QGuiApplication::sendSpontaneousEvent(window, &tabletEvent);
2719 pointData.state = e->buttons;
2720 if (!tabletEvent.isAccepted()
2721 && !QWindowSystemInterfacePrivate::TabletEvent::platformSynthesizesMouse
2722 && qApp->testAttribute(Qt::AA_SynthesizeMouseForUnhandledTabletEvents)) {
2723
2724 const QEvent::Type mouseType = [&]() {
2725 switch (type) {
2726 case QEvent::TabletPress: return QEvent::MouseButtonPress;
2727 case QEvent::TabletMove: return QEvent::MouseMove;
2728 case QEvent::TabletRelease: return QEvent::MouseButtonRelease;
2729 default: Q_UNREACHABLE();
2730 }
2731 }();
2732 QWindowSystemInterfacePrivate::MouseEvent mouseEvent(window, e->timestamp, e->local,
2733 e->global, e->buttons, e->modifiers, button, mouseType, Qt::MouseEventSynthesizedByQt);
2734 mouseEvent.flags |= QWindowSystemInterfacePrivate::WindowSystemEvent::Synthetic;
2735 processMouseEvent(&mouseEvent);
2736 }
2737 #else
2738 Q_UNUSED(e)
2739 #endif
2740 }
2741
processTabletEnterProximityEvent(QWindowSystemInterfacePrivate::TabletEnterProximityEvent * e)2742 void QGuiApplicationPrivate::processTabletEnterProximityEvent(QWindowSystemInterfacePrivate::TabletEnterProximityEvent *e)
2743 {
2744 #if QT_CONFIG(tabletevent)
2745 QTabletEvent ev(QEvent::TabletEnterProximity, QPointF(), QPointF(),
2746 e->device, e->pointerType, 0, 0, 0,
2747 0, 0, 0,
2748 Qt::NoModifier, e->uid, Qt::NoButton, tabletDevicePoint(e->uid).state);
2749 ev.setTimestamp(e->timestamp);
2750 QGuiApplication::sendSpontaneousEvent(qGuiApp, &ev);
2751 #else
2752 Q_UNUSED(e)
2753 #endif
2754 }
2755
processTabletLeaveProximityEvent(QWindowSystemInterfacePrivate::TabletLeaveProximityEvent * e)2756 void QGuiApplicationPrivate::processTabletLeaveProximityEvent(QWindowSystemInterfacePrivate::TabletLeaveProximityEvent *e)
2757 {
2758 #if QT_CONFIG(tabletevent)
2759 QTabletEvent ev(QEvent::TabletLeaveProximity, QPointF(), QPointF(),
2760 e->device, e->pointerType, 0, 0, 0,
2761 0, 0, 0,
2762 Qt::NoModifier, e->uid, Qt::NoButton, tabletDevicePoint(e->uid).state);
2763 ev.setTimestamp(e->timestamp);
2764 QGuiApplication::sendSpontaneousEvent(qGuiApp, &ev);
2765 #else
2766 Q_UNUSED(e)
2767 #endif
2768 }
2769
2770 #ifndef QT_NO_GESTURES
processGestureEvent(QWindowSystemInterfacePrivate::GestureEvent * e)2771 void QGuiApplicationPrivate::processGestureEvent(QWindowSystemInterfacePrivate::GestureEvent *e)
2772 {
2773 if (e->window.isNull())
2774 return;
2775
2776 QNativeGestureEvent ev(e->type, e->device, e->pos, e->pos, e->globalPos, e->realValue, e->sequenceId, e->intValue);
2777 ev.setTimestamp(e->timestamp);
2778 QGuiApplication::sendSpontaneousEvent(e->window, &ev);
2779 }
2780 #endif // QT_NO_GESTURES
2781
processPlatformPanelEvent(QWindowSystemInterfacePrivate::PlatformPanelEvent * e)2782 void QGuiApplicationPrivate::processPlatformPanelEvent(QWindowSystemInterfacePrivate::PlatformPanelEvent *e)
2783 {
2784 if (!e->window)
2785 return;
2786
2787 if (e->window->d_func()->blockedByModalWindow) {
2788 // a modal window is blocking this window, don't allow events through
2789 return;
2790 }
2791
2792 QEvent ev(QEvent::PlatformPanel);
2793 QGuiApplication::sendSpontaneousEvent(e->window.data(), &ev);
2794 }
2795
2796 #ifndef QT_NO_CONTEXTMENU
processContextMenuEvent(QWindowSystemInterfacePrivate::ContextMenuEvent * e)2797 void QGuiApplicationPrivate::processContextMenuEvent(QWindowSystemInterfacePrivate::ContextMenuEvent *e)
2798 {
2799 // Widgets do not care about mouse triggered context menu events. Also, do not forward event
2800 // to a window blocked by a modal window.
2801 if (!e->window || e->mouseTriggered || e->window->d_func()->blockedByModalWindow)
2802 return;
2803
2804 QContextMenuEvent ev(QContextMenuEvent::Keyboard, e->pos, e->globalPos, e->modifiers);
2805 QGuiApplication::sendSpontaneousEvent(e->window.data(), &ev);
2806 }
2807 #endif
2808
qHash(const QGuiApplicationPrivate::ActiveTouchPointsKey & k)2809 Q_GUI_EXPORT uint qHash(const QGuiApplicationPrivate::ActiveTouchPointsKey &k)
2810 {
2811 return qHash(k.device) + k.touchPointId;
2812 }
2813
operator ==(const QGuiApplicationPrivate::ActiveTouchPointsKey & a,const QGuiApplicationPrivate::ActiveTouchPointsKey & b)2814 Q_GUI_EXPORT bool operator==(const QGuiApplicationPrivate::ActiveTouchPointsKey &a,
2815 const QGuiApplicationPrivate::ActiveTouchPointsKey &b)
2816 {
2817 return a.device == b.device
2818 && a.touchPointId == b.touchPointId;
2819 }
2820
processTouchEvent(QWindowSystemInterfacePrivate::TouchEvent * e)2821 void QGuiApplicationPrivate::processTouchEvent(QWindowSystemInterfacePrivate::TouchEvent *e)
2822 {
2823 QGuiApplicationPrivate *d = self;
2824 modifier_buttons = e->modifiers;
2825
2826 if (e->touchType == QEvent::TouchCancel) {
2827 // The touch sequence has been canceled (e.g. by the compositor).
2828 // Send the TouchCancel to all windows with active touches and clean up.
2829 QTouchEvent touchEvent(QEvent::TouchCancel, e->device, e->modifiers);
2830 touchEvent.setTimestamp(e->timestamp);
2831 QHash<ActiveTouchPointsKey, ActiveTouchPointsValue>::const_iterator it
2832 = self->activeTouchPoints.constBegin(), ite = self->activeTouchPoints.constEnd();
2833 QSet<QWindow *> windowsNeedingCancel;
2834 while (it != ite) {
2835 QWindow *w = it->window.data();
2836 if (w)
2837 windowsNeedingCancel.insert(w);
2838 ++it;
2839 }
2840 for (QSet<QWindow *>::const_iterator winIt = windowsNeedingCancel.constBegin(),
2841 winItEnd = windowsNeedingCancel.constEnd(); winIt != winItEnd; ++winIt) {
2842 touchEvent.setWindow(*winIt);
2843 QGuiApplication::sendSpontaneousEvent(*winIt, &touchEvent);
2844 }
2845 if (!self->synthesizedMousePoints.isEmpty() && !e->synthetic()) {
2846 for (QHash<QWindow *, SynthesizedMouseData>::const_iterator synthIt = self->synthesizedMousePoints.constBegin(),
2847 synthItEnd = self->synthesizedMousePoints.constEnd(); synthIt != synthItEnd; ++synthIt) {
2848 if (!synthIt->window)
2849 continue;
2850 QWindowSystemInterfacePrivate::MouseEvent fake(synthIt->window.data(),
2851 e->timestamp,
2852 synthIt->pos,
2853 synthIt->screenPos,
2854 Qt::NoButton,
2855 e->modifiers,
2856 Qt::LeftButton,
2857 QEvent::MouseButtonRelease,
2858 Qt::MouseEventSynthesizedByQt);
2859 fake.flags |= QWindowSystemInterfacePrivate::WindowSystemEvent::Synthetic;
2860 processMouseEvent(&fake);
2861 }
2862 self->synthesizedMousePoints.clear();
2863 }
2864 self->activeTouchPoints.clear();
2865 self->lastTouchType = e->touchType;
2866 return;
2867 }
2868
2869 // Prevent sending ill-formed event sequences: Cancel can only be followed by a Begin.
2870 if (self->lastTouchType == QEvent::TouchCancel && e->touchType != QEvent::TouchBegin)
2871 return;
2872
2873 self->lastTouchType = e->touchType;
2874
2875 QWindow *window = e->window.data();
2876 typedef QPair<Qt::TouchPointStates, QList<QTouchEvent::TouchPoint> > StatesAndTouchPoints;
2877 QHash<QWindow *, StatesAndTouchPoints> windowsNeedingEvents;
2878 bool stationaryTouchPointChangedProperty = false;
2879
2880 for (int i = 0; i < e->points.count(); ++i) {
2881 QTouchEvent::TouchPoint touchPoint = e->points.at(i);
2882 // explicitly detach from the original touch point that we got, so even
2883 // if the touchpoint structs are reused, we will make a copy that we'll
2884 // deliver to the user (which might want to store the struct for later use).
2885 touchPoint.d = touchPoint.d->detach();
2886
2887 // update state
2888 QPointer<QWindow> w;
2889 QTouchEvent::TouchPoint previousTouchPoint;
2890 ActiveTouchPointsKey touchInfoKey(e->device, touchPoint.id());
2891 ActiveTouchPointsValue &touchInfo = d->activeTouchPoints[touchInfoKey];
2892 switch (touchPoint.state()) {
2893 case Qt::TouchPointPressed:
2894 if (e->device->type() == QTouchDevice::TouchPad) {
2895 // on touch-pads, send all touch points to the same widget
2896 w = d->activeTouchPoints.isEmpty()
2897 ? QPointer<QWindow>()
2898 : d->activeTouchPoints.constBegin().value().window;
2899 }
2900
2901 if (!w) {
2902 // determine which window this event will go to
2903 if (!window)
2904 window = QGuiApplication::topLevelAt(touchPoint.screenPos().toPoint());
2905 if (!window)
2906 continue;
2907 w = window;
2908 }
2909
2910 touchInfo.window = w;
2911 touchPoint.d->startScreenPos = touchPoint.screenPos();
2912 touchPoint.d->lastScreenPos = touchPoint.screenPos();
2913 touchPoint.d->startNormalizedPos = touchPoint.normalizedPos();
2914 touchPoint.d->lastNormalizedPos = touchPoint.normalizedPos();
2915 if (touchPoint.pressure() < qreal(0.))
2916 touchPoint.d->pressure = qreal(1.);
2917
2918 touchInfo.touchPoint = touchPoint;
2919 break;
2920
2921 case Qt::TouchPointReleased:
2922 w = touchInfo.window;
2923 if (!w)
2924 continue;
2925
2926 previousTouchPoint = touchInfo.touchPoint;
2927 touchPoint.d->startScreenPos = previousTouchPoint.startScreenPos();
2928 touchPoint.d->lastScreenPos = previousTouchPoint.screenPos();
2929 touchPoint.d->startPos = previousTouchPoint.startPos();
2930 touchPoint.d->lastPos = previousTouchPoint.pos();
2931 touchPoint.d->startNormalizedPos = previousTouchPoint.startNormalizedPos();
2932 touchPoint.d->lastNormalizedPos = previousTouchPoint.normalizedPos();
2933 if (touchPoint.pressure() < qreal(0.))
2934 touchPoint.d->pressure = qreal(0.);
2935
2936 break;
2937
2938 default:
2939 w = touchInfo.window;
2940 if (!w)
2941 continue;
2942
2943 previousTouchPoint = touchInfo.touchPoint;
2944 touchPoint.d->startScreenPos = previousTouchPoint.startScreenPos();
2945 touchPoint.d->lastScreenPos = previousTouchPoint.screenPos();
2946 touchPoint.d->startPos = previousTouchPoint.startPos();
2947 touchPoint.d->lastPos = previousTouchPoint.pos();
2948 touchPoint.d->startNormalizedPos = previousTouchPoint.startNormalizedPos();
2949 touchPoint.d->lastNormalizedPos = previousTouchPoint.normalizedPos();
2950 if (touchPoint.pressure() < qreal(0.))
2951 touchPoint.d->pressure = qreal(1.);
2952
2953 // Stationary points might not be delivered down to the receiving item
2954 // and get their position transformed, keep the old values instead.
2955 if (touchPoint.state() == Qt::TouchPointStationary) {
2956 if (touchInfo.touchPoint.velocity() != touchPoint.velocity()) {
2957 touchInfo.touchPoint.setVelocity(touchPoint.velocity());
2958 touchPoint.d->stationaryWithModifiedProperty = true;
2959 stationaryTouchPointChangedProperty = true;
2960 }
2961 if (!qFuzzyCompare(touchInfo.touchPoint.pressure(), touchPoint.pressure())) {
2962 touchInfo.touchPoint.setPressure(touchPoint.pressure());
2963 touchPoint.d->stationaryWithModifiedProperty = true;
2964 stationaryTouchPointChangedProperty = true;
2965 }
2966 } else {
2967 touchInfo.touchPoint = touchPoint;
2968 }
2969 break;
2970 }
2971
2972 Q_ASSERT(w.data() != nullptr);
2973
2974 // make the *scene* functions return the same as the *screen* functions
2975 // Note: touchPoint is a reference to the one from activeTouchPoints,
2976 // so we can modify it as long as we're careful NOT to call setters and
2977 // otherwise NOT to cause the d-pointer to be detached.
2978 touchPoint.d->scenePos = touchPoint.screenPos();
2979 touchPoint.d->startScenePos = touchPoint.startScreenPos();
2980 touchPoint.d->lastScenePos = touchPoint.lastScreenPos();
2981
2982 StatesAndTouchPoints &maskAndPoints = windowsNeedingEvents[w.data()];
2983 maskAndPoints.first |= touchPoint.state();
2984 maskAndPoints.second.append(touchPoint);
2985 }
2986
2987 if (windowsNeedingEvents.isEmpty())
2988 return;
2989
2990 QHash<QWindow *, StatesAndTouchPoints>::ConstIterator it = windowsNeedingEvents.constBegin();
2991 const QHash<QWindow *, StatesAndTouchPoints>::ConstIterator end = windowsNeedingEvents.constEnd();
2992 for (; it != end; ++it) {
2993 QWindow *w = it.key();
2994
2995 QEvent::Type eventType;
2996 switch (it.value().first) {
2997 case Qt::TouchPointPressed:
2998 eventType = QEvent::TouchBegin;
2999 break;
3000 case Qt::TouchPointReleased:
3001 eventType = QEvent::TouchEnd;
3002 break;
3003 case Qt::TouchPointStationary:
3004 // don't send the event if nothing changed
3005 if (!stationaryTouchPointChangedProperty)
3006 continue;
3007 Q_FALLTHROUGH();
3008 default:
3009 eventType = QEvent::TouchUpdate;
3010 break;
3011 }
3012
3013 if (w->d_func()->blockedByModalWindow && !qApp->d_func()->popupActive()) {
3014 // a modal window is blocking this window, don't allow touch events through
3015
3016 // QTBUG-37371 temporary fix; TODO: revisit in 5.4 when we have a forwarding solution
3017 if (eventType == QEvent::TouchEnd) {
3018 // but don't leave dangling state: e.g.
3019 // QQuickWindowPrivate::itemForTouchPointId needs to be cleared.
3020 QTouchEvent touchEvent(QEvent::TouchCancel,
3021 e->device,
3022 e->modifiers);
3023 touchEvent.setTimestamp(e->timestamp);
3024 touchEvent.setWindow(w);
3025 QGuiApplication::sendSpontaneousEvent(w, &touchEvent);
3026 }
3027 continue;
3028 }
3029
3030 QTouchEvent touchEvent(eventType,
3031 e->device,
3032 e->modifiers,
3033 it.value().first, // state flags
3034 it.value().second); // list of touchpoints
3035 touchEvent.setTimestamp(e->timestamp);
3036 touchEvent.setWindow(w);
3037
3038 const int pointCount = touchEvent.touchPoints().count();
3039 for (int i = 0; i < pointCount; ++i) {
3040 QTouchEvent::TouchPoint &touchPoint = touchEvent._touchPoints[i];
3041
3042 // preserve the sub-pixel resolution
3043 const QPointF screenPos = touchPoint.screenPos();
3044 const QPointF delta = screenPos - screenPos.toPoint();
3045
3046 touchPoint.d->pos = w->mapFromGlobal(screenPos.toPoint()) + delta;
3047 if (touchPoint.state() == Qt::TouchPointPressed) {
3048 // touchPoint is actually a reference to one that is stored in activeTouchPoints,
3049 // and we are now going to store the startPos and lastPos there, for the benefit
3050 // of future moves and releases. It's important that the d-pointer is NOT detached.
3051 touchPoint.d->startPos = w->mapFromGlobal(touchPoint.startScreenPos().toPoint()) + delta;
3052 touchPoint.d->lastPos = w->mapFromGlobal(touchPoint.lastScreenPos().toPoint()) + delta;
3053 }
3054 }
3055
3056 QGuiApplication::sendSpontaneousEvent(w, &touchEvent);
3057 if (!e->synthetic() && !touchEvent.isAccepted() && qApp->testAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents)) {
3058 // exclude devices which generate their own mouse events
3059 if (!(touchEvent.device()->capabilities() & QTouchDevice::MouseEmulation)) {
3060 const QList<QTouchEvent::TouchPoint> &touchPoints = touchEvent.touchPoints();
3061 QEvent::Type mouseEventType = QEvent::MouseMove;
3062 Qt::MouseButton button = Qt::NoButton;
3063 Qt::MouseButtons buttons = Qt::LeftButton;
3064 if (eventType == QEvent::TouchBegin && m_fakeMouseSourcePointId < 0)
3065 m_fakeMouseSourcePointId = touchPoints.first().id();
3066 for (const auto &touchPoint : touchPoints) {
3067 if (touchPoint.id() == m_fakeMouseSourcePointId) {
3068 switch (touchPoint.state()) {
3069 case Qt::TouchPointPressed:
3070 mouseEventType = QEvent::MouseButtonPress;
3071 button = Qt::LeftButton;
3072 break;
3073 case Qt::TouchPointReleased:
3074 mouseEventType = QEvent::MouseButtonRelease;
3075 button = Qt::LeftButton;
3076 buttons = Qt::NoButton;
3077 m_fakeMouseSourcePointId = -1;
3078 break;
3079 default:
3080 break;
3081 }
3082 if (touchPoint.state() != Qt::TouchPointReleased) {
3083 self->synthesizedMousePoints.insert(w, SynthesizedMouseData(
3084 touchPoint.pos(), touchPoint.screenPos(), w));
3085 }
3086 // All touch events that are not accepted by the application will be translated to
3087 // left mouse button events instead (see AA_SynthesizeMouseForUnhandledTouchEvents docs).
3088 QWindowSystemInterfacePrivate::MouseEvent fake(w, e->timestamp,
3089 touchPoint.pos(),
3090 touchPoint.screenPos(),
3091 buttons,
3092 e->modifiers,
3093 button,
3094 mouseEventType,
3095 Qt::MouseEventSynthesizedByQt);
3096 fake.flags |= QWindowSystemInterfacePrivate::WindowSystemEvent::Synthetic;
3097 processMouseEvent(&fake);
3098 break;
3099 }
3100 }
3101 if (eventType == QEvent::TouchEnd)
3102 self->synthesizedMousePoints.clear();
3103 }
3104 }
3105 }
3106
3107 // Remove released points from the hash table only after the event is
3108 // delivered. When the receiver is a widget, QApplication will access
3109 // activeTouchPoints during delivery and therefore nothing can be removed
3110 // before sending the event.
3111 for (int i = 0; i < e->points.count(); ++i) {
3112 QTouchEvent::TouchPoint touchPoint = e->points.at(i);
3113 if (touchPoint.state() == Qt::TouchPointReleased)
3114 d->activeTouchPoints.remove(ActiveTouchPointsKey(e->device, touchPoint.id()));
3115 }
3116 }
3117
processScreenOrientationChange(QWindowSystemInterfacePrivate::ScreenOrientationEvent * e)3118 void QGuiApplicationPrivate::processScreenOrientationChange(QWindowSystemInterfacePrivate::ScreenOrientationEvent *e)
3119 {
3120 // This operation only makes sense after the QGuiApplication constructor runs
3121 if (QCoreApplication::startingUp())
3122 return;
3123
3124 if (!e->screen)
3125 return;
3126
3127 QScreen *s = e->screen.data();
3128 s->d_func()->orientation = e->orientation;
3129
3130 updateFilteredScreenOrientation(s);
3131 }
3132
updateFilteredScreenOrientation(QScreen * s)3133 void QGuiApplicationPrivate::updateFilteredScreenOrientation(QScreen *s)
3134 {
3135 Qt::ScreenOrientation o = s->d_func()->orientation;
3136 if (o == Qt::PrimaryOrientation)
3137 o = s->primaryOrientation();
3138 o = Qt::ScreenOrientation(o & s->orientationUpdateMask());
3139 if (o == Qt::PrimaryOrientation)
3140 return;
3141 if (o == s->d_func()->filteredOrientation)
3142 return;
3143 s->d_func()->filteredOrientation = o;
3144 reportScreenOrientationChange(s);
3145 }
3146
reportScreenOrientationChange(QScreen * s)3147 void QGuiApplicationPrivate::reportScreenOrientationChange(QScreen *s)
3148 {
3149 emit s->orientationChanged(s->orientation());
3150
3151 QScreenOrientationChangeEvent event(s, s->orientation());
3152 QCoreApplication::sendEvent(QCoreApplication::instance(), &event);
3153 }
3154
processScreenGeometryChange(QWindowSystemInterfacePrivate::ScreenGeometryEvent * e)3155 void QGuiApplicationPrivate::processScreenGeometryChange(QWindowSystemInterfacePrivate::ScreenGeometryEvent *e)
3156 {
3157 // This operation only makes sense after the QGuiApplication constructor runs
3158 if (QCoreApplication::startingUp())
3159 return;
3160
3161 if (!e->screen)
3162 return;
3163
3164 QScreen *s = e->screen.data();
3165
3166 bool geometryChanged = e->geometry != s->d_func()->geometry;
3167 s->d_func()->geometry = e->geometry;
3168
3169 bool availableGeometryChanged = e->availableGeometry != s->d_func()->availableGeometry;
3170 s->d_func()->availableGeometry = e->availableGeometry;
3171
3172 const Qt::ScreenOrientation primaryOrientation = s->primaryOrientation();
3173 if (geometryChanged)
3174 s->d_func()->updatePrimaryOrientation();
3175
3176 s->d_func()->emitGeometryChangeSignals(geometryChanged, availableGeometryChanged);
3177
3178 if (geometryChanged) {
3179 emit s->physicalSizeChanged(s->physicalSize());
3180 emit s->logicalDotsPerInchChanged(s->logicalDotsPerInch());
3181
3182 if (s->primaryOrientation() != primaryOrientation)
3183 emit s->primaryOrientationChanged(s->primaryOrientation());
3184
3185 if (s->d_func()->orientation == Qt::PrimaryOrientation)
3186 updateFilteredScreenOrientation(s);
3187 }
3188
3189 resetCachedDevicePixelRatio();
3190 }
3191
processScreenLogicalDotsPerInchChange(QWindowSystemInterfacePrivate::ScreenLogicalDotsPerInchEvent * e)3192 void QGuiApplicationPrivate::processScreenLogicalDotsPerInchChange(QWindowSystemInterfacePrivate::ScreenLogicalDotsPerInchEvent *e)
3193 {
3194 // This operation only makes sense after the QGuiApplication constructor runs
3195 if (QCoreApplication::startingUp())
3196 return;
3197
3198 QHighDpiScaling::updateHighDpiScaling();
3199
3200 if (!e->screen)
3201 return;
3202
3203 QScreen *s = e->screen.data();
3204 s->d_func()->logicalDpi = QDpi(e->dpiX, e->dpiY);
3205
3206 emit s->logicalDotsPerInchChanged(s->logicalDotsPerInch());
3207 s->d_func()->updateGeometriesWithSignals();
3208
3209 resetCachedDevicePixelRatio();
3210 }
3211
processScreenRefreshRateChange(QWindowSystemInterfacePrivate::ScreenRefreshRateEvent * e)3212 void QGuiApplicationPrivate::processScreenRefreshRateChange(QWindowSystemInterfacePrivate::ScreenRefreshRateEvent *e)
3213 {
3214 // This operation only makes sense after the QGuiApplication constructor runs
3215 if (QCoreApplication::startingUp())
3216 return;
3217
3218 if (!e->screen)
3219 return;
3220
3221 QScreen *s = e->screen.data();
3222 qreal rate = e->rate;
3223 // safeguard ourselves against buggy platform behavior...
3224 if (rate < 1.0)
3225 rate = 60.0;
3226 if (!qFuzzyCompare(s->d_func()->refreshRate, rate)) {
3227 s->d_func()->refreshRate = rate;
3228 emit s->refreshRateChanged(s->refreshRate());
3229 }
3230 }
3231
processExposeEvent(QWindowSystemInterfacePrivate::ExposeEvent * e)3232 void QGuiApplicationPrivate::processExposeEvent(QWindowSystemInterfacePrivate::ExposeEvent *e)
3233 {
3234 if (!e->window)
3235 return;
3236
3237 QWindow *window = e->window.data();
3238 if (!window)
3239 return;
3240 QWindowPrivate *p = qt_window_private(window);
3241
3242 if (!p->receivedExpose) {
3243 if (p->resizeEventPending) {
3244 // as a convenience for plugins, send a resize event before the first expose event if they haven't done so
3245 // window->geometry() should have a valid size as soon as a handle exists.
3246 QResizeEvent e(window->geometry().size(), p->geometry.size());
3247 QGuiApplication::sendSpontaneousEvent(window, &e);
3248
3249 p->resizeEventPending = false;
3250 }
3251
3252 p->receivedExpose = true;
3253 }
3254
3255 p->exposed = e->isExposed && window->screen();
3256
3257 QExposeEvent exposeEvent(e->region);
3258 QCoreApplication::sendSpontaneousEvent(window, &exposeEvent);
3259 }
3260
3261 #if QT_CONFIG(draganddrop)
3262
3263 /*! \internal
3264
3265 This function updates an internal state to keep the source compatibility.
3266 ### Qt 6 - Won't need after QTBUG-73829
3267 */
updateMouseAndModifierButtonState(Qt::MouseButtons buttons,Qt::KeyboardModifiers modifiers)3268 static void updateMouseAndModifierButtonState(Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers)
3269 {
3270 QGuiApplicationPrivate::mouse_buttons = buttons;
3271 QGuiApplicationPrivate::modifier_buttons = modifiers;
3272 }
3273
processDrag(QWindow * w,const QMimeData * dropData,const QPoint & p,Qt::DropActions supportedActions,Qt::MouseButtons buttons,Qt::KeyboardModifiers modifiers)3274 QPlatformDragQtResponse QGuiApplicationPrivate::processDrag(QWindow *w, const QMimeData *dropData,
3275 const QPoint &p, Qt::DropActions supportedActions,
3276 Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers)
3277 {
3278 updateMouseAndModifierButtonState(buttons, modifiers);
3279
3280 static Qt::DropAction lastAcceptedDropAction = Qt::IgnoreAction;
3281 QPlatformDrag *platformDrag = platformIntegration()->drag();
3282 if (!platformDrag || (w && w->d_func()->blockedByModalWindow)) {
3283 lastAcceptedDropAction = Qt::IgnoreAction;
3284 return QPlatformDragQtResponse(false, lastAcceptedDropAction, QRect());
3285 }
3286
3287 if (!dropData) {
3288 currentDragWindow = nullptr;
3289 QDragLeaveEvent e;
3290 QGuiApplication::sendEvent(w, &e);
3291 lastAcceptedDropAction = Qt::IgnoreAction;
3292 return QPlatformDragQtResponse(false, lastAcceptedDropAction, QRect());
3293 }
3294 QDragMoveEvent me(p, supportedActions, dropData, buttons, modifiers);
3295
3296 if (w != currentDragWindow) {
3297 lastAcceptedDropAction = Qt::IgnoreAction;
3298 if (currentDragWindow) {
3299 QDragLeaveEvent e;
3300 QGuiApplication::sendEvent(currentDragWindow, &e);
3301 }
3302 currentDragWindow = w;
3303 QDragEnterEvent e(p, supportedActions, dropData, buttons, modifiers);
3304 QGuiApplication::sendEvent(w, &e);
3305 if (e.isAccepted() && e.dropAction() != Qt::IgnoreAction)
3306 lastAcceptedDropAction = e.dropAction();
3307 }
3308
3309 // Handling 'DragEnter' should suffice for the application.
3310 if (lastAcceptedDropAction != Qt::IgnoreAction
3311 && (supportedActions & lastAcceptedDropAction)) {
3312 me.setDropAction(lastAcceptedDropAction);
3313 me.accept();
3314 }
3315 QGuiApplication::sendEvent(w, &me);
3316 lastAcceptedDropAction = me.isAccepted() ?
3317 me.dropAction() : Qt::IgnoreAction;
3318 return QPlatformDragQtResponse(me.isAccepted(), lastAcceptedDropAction, me.answerRect());
3319 }
3320
processDrop(QWindow * w,const QMimeData * dropData,const QPoint & p,Qt::DropActions supportedActions,Qt::MouseButtons buttons,Qt::KeyboardModifiers modifiers)3321 QPlatformDropQtResponse QGuiApplicationPrivate::processDrop(QWindow *w, const QMimeData *dropData,
3322 const QPoint &p, Qt::DropActions supportedActions,
3323 Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers)
3324 {
3325 updateMouseAndModifierButtonState(buttons, modifiers);
3326
3327 currentDragWindow = nullptr;
3328
3329 QDropEvent de(p, supportedActions, dropData, buttons, modifiers);
3330 QGuiApplication::sendEvent(w, &de);
3331
3332 Qt::DropAction acceptedAction = de.isAccepted() ? de.dropAction() : Qt::IgnoreAction;
3333 QPlatformDropQtResponse response(de.isAccepted(),acceptedAction);
3334 return response;
3335 }
3336
3337 #endif // QT_CONFIG(draganddrop)
3338
3339 #ifndef QT_NO_CLIPBOARD
3340 /*!
3341 Returns the object for interacting with the clipboard.
3342 */
clipboard()3343 QClipboard * QGuiApplication::clipboard()
3344 {
3345 if (QGuiApplicationPrivate::qt_clipboard == nullptr) {
3346 if (!qApp) {
3347 qWarning("QGuiApplication: Must construct a QGuiApplication before accessing a QClipboard");
3348 return nullptr;
3349 }
3350 QGuiApplicationPrivate::qt_clipboard = new QClipboard(nullptr);
3351 }
3352 return QGuiApplicationPrivate::qt_clipboard;
3353 }
3354 #endif
3355
3356 /*!
3357 \since 5.4
3358 \fn void QGuiApplication::paletteChanged(const QPalette &palette)
3359
3360 This signal is emitted when the \a palette of the application changes.
3361
3362 \sa palette()
3363 */
3364
3365 /*!
3366 Returns the current application palette.
3367
3368 Roles that have not been explicitly set will reflect the system's platform theme.
3369
3370 \sa setPalette()
3371 */
3372
palette()3373 QPalette QGuiApplication::palette()
3374 {
3375 if (!QGuiApplicationPrivate::app_pal)
3376 QGuiApplicationPrivate::updatePalette();
3377
3378 return *QGuiApplicationPrivate::app_pal;
3379 }
3380
updatePalette()3381 void QGuiApplicationPrivate::updatePalette()
3382 {
3383 if (app_pal) {
3384 if (setPalette(*app_pal) && qGuiApp)
3385 qGuiApp->d_func()->handlePaletteChanged();
3386 } else {
3387 setPalette(QPalette());
3388 }
3389 }
3390
clearPalette()3391 void QGuiApplicationPrivate::clearPalette()
3392 {
3393 delete app_pal;
3394 app_pal = nullptr;
3395 }
3396
3397 /*!
3398 Changes the application palette to \a pal.
3399
3400 The color roles from this palette are combined with the system's platform
3401 theme to form the application's final palette.
3402
3403 \sa palette()
3404 */
setPalette(const QPalette & pal)3405 void QGuiApplication::setPalette(const QPalette &pal)
3406 {
3407 if (QGuiApplicationPrivate::setPalette(pal) && qGuiApp)
3408 qGuiApp->d_func()->handlePaletteChanged();
3409 }
3410
setPalette(const QPalette & palette)3411 bool QGuiApplicationPrivate::setPalette(const QPalette &palette)
3412 {
3413 // Resolve the palette against the theme palette, filling in
3414 // any missing roles, while keeping the original resolve mask.
3415 QPalette basePalette = qGuiApp ? qGuiApp->d_func()->basePalette() : Qt::gray;
3416 basePalette.resolve(0); // The base palette only contributes missing colors roles
3417 QPalette resolvedPalette = palette.resolve(basePalette);
3418
3419 if (app_pal && resolvedPalette == *app_pal && resolvedPalette.resolve() == app_pal->resolve())
3420 return false;
3421
3422 if (!app_pal)
3423 app_pal = new QPalette(resolvedPalette);
3424 else
3425 *app_pal = resolvedPalette;
3426
3427 QCoreApplication::setAttribute(Qt::AA_SetPalette, app_pal->resolve() != 0);
3428
3429 return true;
3430 }
3431
3432 /*
3433 Returns the base palette used to fill in missing roles in
3434 the current application palette.
3435
3436 Normally this is the theme palette, but QApplication
3437 overrides this for compatibility reasons.
3438 */
basePalette() const3439 QPalette QGuiApplicationPrivate::basePalette() const
3440 {
3441 return platformTheme() ? *platformTheme()->palette() : Qt::gray;
3442 }
3443
handlePaletteChanged(const char * className)3444 void QGuiApplicationPrivate::handlePaletteChanged(const char *className)
3445 {
3446 if (!className) {
3447 Q_ASSERT(app_pal);
3448 emit qGuiApp->paletteChanged(*QGuiApplicationPrivate::app_pal);
3449 }
3450
3451 if (is_app_running && !is_app_closing) {
3452 QEvent event(QEvent::ApplicationPaletteChange);
3453 QGuiApplication::sendEvent(qGuiApp, &event);
3454 }
3455 }
3456
applyWindowGeometrySpecificationTo(QWindow * window)3457 void QGuiApplicationPrivate::applyWindowGeometrySpecificationTo(QWindow *window)
3458 {
3459 windowGeometrySpecification.applyTo(window);
3460 }
3461
3462 /*!
3463 \since 5.11
3464 \fn void QGuiApplication::fontChanged(const QFont &font)
3465
3466 This signal is emitted when the \a font of the application changes.
3467
3468 \sa font()
3469 */
3470
3471 /*!
3472 Returns the default application font.
3473
3474 \sa setFont()
3475 */
font()3476 QFont QGuiApplication::font()
3477 {
3478 const auto locker = qt_scoped_lock(applicationFontMutex);
3479 if (!QGuiApplicationPrivate::self && !QGuiApplicationPrivate::app_font) {
3480 qWarning("QGuiApplication::font(): no QGuiApplication instance and no application font set.");
3481 return QFont(); // in effect: QFont((QFontPrivate*)nullptr), so no recursion
3482 }
3483 initFontUnlocked();
3484 return *QGuiApplicationPrivate::app_font;
3485 }
3486
3487 /*!
3488 Changes the default application font to \a font.
3489
3490 \sa font()
3491 */
setFont(const QFont & font)3492 void QGuiApplication::setFont(const QFont &font)
3493 {
3494 auto locker = qt_unique_lock(applicationFontMutex);
3495 const bool emitChange = !QGuiApplicationPrivate::app_font
3496 || (*QGuiApplicationPrivate::app_font != font);
3497 if (!QGuiApplicationPrivate::app_font)
3498 QGuiApplicationPrivate::app_font = new QFont(font);
3499 else
3500 *QGuiApplicationPrivate::app_font = font;
3501 applicationResourceFlags |= ApplicationFontExplicitlySet;
3502
3503 if (emitChange && qGuiApp) {
3504 auto font = *QGuiApplicationPrivate::app_font;
3505 locker.unlock();
3506 emit qGuiApp->fontChanged(font);
3507 }
3508 }
3509
3510 /*!
3511 \fn bool QGuiApplication::isRightToLeft()
3512
3513 Returns \c true if the application's layout direction is
3514 Qt::RightToLeft; otherwise returns \c false.
3515
3516 \sa layoutDirection(), isLeftToRight()
3517 */
3518
3519 /*!
3520 \fn bool QGuiApplication::isLeftToRight()
3521
3522 Returns \c true if the application's layout direction is
3523 Qt::LeftToRight; otherwise returns \c false.
3524
3525 \sa layoutDirection(), isRightToLeft()
3526 */
3527
notifyLayoutDirectionChange()3528 void QGuiApplicationPrivate::notifyLayoutDirectionChange()
3529 {
3530 const QWindowList list = QGuiApplication::topLevelWindows();
3531 for (int i = 0; i < list.size(); ++i) {
3532 QEvent ev(QEvent::ApplicationLayoutDirectionChange);
3533 QCoreApplication::sendEvent(list.at(i), &ev);
3534 }
3535 }
3536
notifyActiveWindowChange(QWindow *)3537 void QGuiApplicationPrivate::notifyActiveWindowChange(QWindow *)
3538 {
3539 }
3540
3541 /*!
3542 \property QGuiApplication::windowIcon
3543 \brief the default window icon
3544
3545 \sa QWindow::setIcon(), {Setting the Application Icon}
3546 */
windowIcon()3547 QIcon QGuiApplication::windowIcon()
3548 {
3549 return QGuiApplicationPrivate::app_icon ? *QGuiApplicationPrivate::app_icon : QIcon();
3550 }
3551
setWindowIcon(const QIcon & icon)3552 void QGuiApplication::setWindowIcon(const QIcon &icon)
3553 {
3554 if (!QGuiApplicationPrivate::app_icon)
3555 QGuiApplicationPrivate::app_icon = new QIcon();
3556 *QGuiApplicationPrivate::app_icon = icon;
3557 if (QGuiApplicationPrivate::platform_integration
3558 && QGuiApplicationPrivate::platform_integration->hasCapability(QPlatformIntegration::ApplicationIcon))
3559 QGuiApplicationPrivate::platform_integration->setApplicationIcon(icon);
3560 if (QGuiApplicationPrivate::is_app_running && !QGuiApplicationPrivate::is_app_closing)
3561 QGuiApplicationPrivate::self->notifyWindowIconChanged();
3562 }
3563
notifyWindowIconChanged()3564 void QGuiApplicationPrivate::notifyWindowIconChanged()
3565 {
3566 QEvent ev(QEvent::ApplicationWindowIconChange);
3567 const QWindowList list = QGuiApplication::topLevelWindows();
3568 for (int i = 0; i < list.size(); ++i)
3569 QCoreApplication::sendEvent(list.at(i), &ev);
3570 }
3571
3572
3573
3574 /*!
3575 \property QGuiApplication::quitOnLastWindowClosed
3576
3577 \brief whether the application implicitly quits when the last window is
3578 closed.
3579
3580 The default is \c true.
3581
3582 If this property is \c true, the applications quits when the last visible
3583 primary window (i.e. window with no parent) is closed.
3584
3585 \sa quit(), QWindow::close()
3586 */
3587
setQuitOnLastWindowClosed(bool quit)3588 void QGuiApplication::setQuitOnLastWindowClosed(bool quit)
3589 {
3590 QCoreApplication::setQuitLockEnabled(quit);
3591 }
3592
3593
3594
quitOnLastWindowClosed()3595 bool QGuiApplication::quitOnLastWindowClosed()
3596 {
3597 return QCoreApplication::isQuitLockEnabled();
3598 }
3599
3600
3601 /*!
3602 \fn void QGuiApplication::lastWindowClosed()
3603
3604 This signal is emitted from exec() when the last visible
3605 primary window (i.e. window with no parent) is closed.
3606
3607 By default, QGuiApplication quits after this signal is emitted. This feature
3608 can be turned off by setting \l quitOnLastWindowClosed to \c false.
3609
3610 \sa QWindow::close(), QWindow::isTopLevel()
3611 */
3612
emitLastWindowClosed()3613 void QGuiApplicationPrivate::emitLastWindowClosed()
3614 {
3615 if (qGuiApp && qGuiApp->d_func()->in_exec) {
3616 emit qGuiApp->lastWindowClosed();
3617 }
3618 }
3619
shouldQuit()3620 bool QGuiApplicationPrivate::shouldQuit()
3621 {
3622 const QWindowList processedWindows;
3623 return shouldQuitInternal(processedWindows);
3624 }
3625
shouldQuitInternal(const QWindowList & processedWindows)3626 bool QGuiApplicationPrivate::shouldQuitInternal(const QWindowList &processedWindows)
3627 {
3628 /* if there is no visible top-level window left, we allow the quit */
3629 QWindowList list = QGuiApplication::topLevelWindows();
3630 for (int i = 0; i < list.size(); ++i) {
3631 QWindow *w = list.at(i);
3632 if (processedWindows.contains(w))
3633 continue;
3634 if (w->isVisible() && !w->transientParent())
3635 return false;
3636 }
3637 return true;
3638 }
3639
tryCloseAllWindows()3640 bool QGuiApplicationPrivate::tryCloseAllWindows()
3641 {
3642 return tryCloseRemainingWindows(QWindowList());
3643 }
3644
tryCloseRemainingWindows(QWindowList processedWindows)3645 bool QGuiApplicationPrivate::tryCloseRemainingWindows(QWindowList processedWindows)
3646 {
3647 QWindowList list = QGuiApplication::topLevelWindows();
3648 for (int i = 0; i < list.size(); ++i) {
3649 QWindow *w = list.at(i);
3650 if (w->isVisible() && !processedWindows.contains(w)) {
3651 if (!w->close())
3652 return false;
3653 processedWindows.append(w);
3654 list = QGuiApplication::topLevelWindows();
3655 i = -1;
3656 }
3657 }
3658 return true;
3659 }
3660
processApplicationTermination(QWindowSystemInterfacePrivate::WindowSystemEvent * windowSystemEvent)3661 void QGuiApplicationPrivate::processApplicationTermination(QWindowSystemInterfacePrivate::WindowSystemEvent *windowSystemEvent)
3662 {
3663 QEvent event(QEvent::Quit);
3664 QGuiApplication::sendSpontaneousEvent(QGuiApplication::instance(), &event);
3665 windowSystemEvent->eventAccepted = event.isAccepted();
3666 }
3667
3668 /*!
3669 \since 5.2
3670 \fn Qt::ApplicationState QGuiApplication::applicationState()
3671
3672
3673 Returns the current state of the application.
3674
3675 You can react to application state changes to perform actions such as
3676 stopping/resuming CPU-intensive tasks, freeing/loading resources or
3677 saving/restoring application data.
3678 */
3679
applicationState()3680 Qt::ApplicationState QGuiApplication::applicationState()
3681 {
3682 return QGuiApplicationPrivate::applicationState;
3683 }
3684
3685 /*!
3686 \since 5.14
3687
3688 Sets the high-DPI scale factor rounding policy for the application. The
3689 \a policy decides how non-integer scale factors (such as Windows 150%) are
3690 handled, for applications that have AA_EnableHighDpiScaling enabled.
3691
3692 The two principal options are whether fractional scale factors should
3693 be rounded to an integer or not. Keeping the scale factor as-is will
3694 make the user interface size match the OS setting exactly, but may cause
3695 painting errors, for example with the Windows style.
3696
3697 If rounding is wanted, then which type of rounding should be decided
3698 next. Mathematically correct rounding is supported but may not give
3699 the best visual results: Consider if you want to render 1.5x as 1x
3700 ("small UI") or as 2x ("large UI"). See the Qt::HighDpiScaleFactorRoundingPolicy
3701 enum for a complete list of all options.
3702
3703 This function must be called before creating the application object,
3704 and can be overridden by setting the QT_SCALE_FACTOR_ROUNDING_POLICY
3705 environment variable. The QGuiApplication::highDpiScaleFactorRoundingPolicy()
3706 accessor will reflect the environment, if set.
3707
3708 The default value is Qt::HighDpiScaleFactorRoundingPolicy::Round.
3709 On Qt for Android the default is Qt::HighDpiScaleFactorRoundingPolicy::PassThrough,
3710 which preserves historical behavior from earlier Qt versions.
3711 */
setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy policy)3712 void QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy policy)
3713 {
3714 QGuiApplicationPrivate::highDpiScaleFactorRoundingPolicy = policy;
3715 }
3716
3717 /*!
3718 \since 5.14
3719
3720 Returns the high-DPI scale factor rounding policy.
3721 */
highDpiScaleFactorRoundingPolicy()3722 Qt::HighDpiScaleFactorRoundingPolicy QGuiApplication::highDpiScaleFactorRoundingPolicy()
3723 {
3724 return QGuiApplicationPrivate::highDpiScaleFactorRoundingPolicy;
3725 }
3726
3727 /*!
3728 \since 5.2
3729 \fn void QGuiApplication::applicationStateChanged(Qt::ApplicationState state)
3730
3731 This signal is emitted when the \a state of the application changes.
3732
3733 \sa applicationState()
3734 */
3735
setApplicationState(Qt::ApplicationState state,bool forcePropagate)3736 void QGuiApplicationPrivate::setApplicationState(Qt::ApplicationState state, bool forcePropagate)
3737 {
3738 if ((applicationState == state) && !forcePropagate)
3739 return;
3740
3741 applicationState = state;
3742
3743 switch (state) {
3744 case Qt::ApplicationActive: {
3745 QEvent appActivate(QEvent::ApplicationActivate);
3746 QCoreApplication::sendSpontaneousEvent(qApp, &appActivate);
3747 break; }
3748 case Qt::ApplicationInactive: {
3749 QEvent appDeactivate(QEvent::ApplicationDeactivate);
3750 QCoreApplication::sendSpontaneousEvent(qApp, &appDeactivate);
3751 break; }
3752 default:
3753 break;
3754 }
3755
3756 QApplicationStateChangeEvent event(applicationState);
3757 QCoreApplication::sendSpontaneousEvent(qApp, &event);
3758
3759 emit qApp->applicationStateChanged(applicationState);
3760 }
3761
3762 #ifndef QT_NO_SESSIONMANAGER
3763 // ### Qt6: consider removing the feature or making it less intrusive
3764 /*!
3765 \since 5.6
3766
3767 Returns whether QGuiApplication will use fallback session management.
3768
3769 The default is \c true.
3770
3771 If this is \c true and the session manager allows user interaction,
3772 QGuiApplication will try to close toplevel windows after
3773 commitDataRequest() has been emitted. If a window cannot be closed, session
3774 shutdown will be canceled and the application will keep running.
3775
3776 Fallback session management only benefits applications that have an
3777 "are you sure you want to close this window?" feature or other logic that
3778 prevents closing a toplevel window depending on certain conditions, and
3779 that do nothing to explicitly implement session management. In applications
3780 that \e do implement session management using the proper session management
3781 API, fallback session management interferes and may break session
3782 management logic.
3783
3784 \warning If all windows \e are closed due to fallback session management
3785 and quitOnLastWindowClosed() is \c true, the application will quit before
3786 it is explicitly instructed to quit through the platform's session
3787 management protocol. That violation of protocol may prevent the platform
3788 session manager from saving application state.
3789
3790 \sa setFallbackSessionManagementEnabled(),
3791 QSessionManager::allowsInteraction(), saveStateRequest(),
3792 commitDataRequest(), {Session Management}
3793 */
isFallbackSessionManagementEnabled()3794 bool QGuiApplication::isFallbackSessionManagementEnabled()
3795 {
3796 return QGuiApplicationPrivate::is_fallback_session_management_enabled;
3797 }
3798
3799 /*!
3800 \since 5.6
3801
3802 Sets whether QGuiApplication will use fallback session management to
3803 \a enabled.
3804
3805 \sa isFallbackSessionManagementEnabled()
3806 */
setFallbackSessionManagementEnabled(bool enabled)3807 void QGuiApplication::setFallbackSessionManagementEnabled(bool enabled)
3808 {
3809 QGuiApplicationPrivate::is_fallback_session_management_enabled = enabled;
3810 }
3811 #endif // QT_NO_SESSIONMANAGER
3812
3813 /*!
3814 \since 4.2
3815 \fn void QGuiApplication::commitDataRequest(QSessionManager &manager)
3816
3817 This signal deals with \l{Session Management}{session management}. It is
3818 emitted when the QSessionManager wants the application to commit all its
3819 data.
3820
3821 Usually this means saving all open files, after getting permission from
3822 the user. Furthermore you may want to provide a means by which the user
3823 can cancel the shutdown.
3824
3825 You should not exit the application within this signal. Instead,
3826 the session manager may or may not do this afterwards, depending on the
3827 context.
3828
3829 \warning Within this signal, no user interaction is possible, \e
3830 unless you ask the \a manager for explicit permission. See
3831 QSessionManager::allowsInteraction() and
3832 QSessionManager::allowsErrorInteraction() for details and example
3833 usage.
3834
3835 \note You should use Qt::DirectConnection when connecting to this signal.
3836
3837 \sa setFallbackSessionManagementEnabled(), isSessionRestored(),
3838 sessionId(), saveStateRequest(), {Session Management}
3839 */
3840
3841 /*!
3842 \since 4.2
3843 \fn void QGuiApplication::saveStateRequest(QSessionManager &manager)
3844
3845 This signal deals with \l{Session Management}{session management}. It is
3846 invoked when the \l{QSessionManager}{session manager} wants the application
3847 to preserve its state for a future session.
3848
3849 For example, a text editor would create a temporary file that includes the
3850 current contents of its edit buffers, the location of the cursor and other
3851 aspects of the current editing session.
3852
3853 You should never exit the application within this signal. Instead, the
3854 session manager may or may not do this afterwards, depending on the
3855 context. Furthermore, most session managers will very likely request a saved
3856 state immediately after the application has been started. This permits the
3857 session manager to learn about the application's restart policy.
3858
3859 \warning Within this signal, no user interaction is possible, \e
3860 unless you ask the \a manager for explicit permission. See
3861 QSessionManager::allowsInteraction() and
3862 QSessionManager::allowsErrorInteraction() for details.
3863
3864 \note You should use Qt::DirectConnection when connecting to this signal.
3865
3866 \sa isSessionRestored(), sessionId(), commitDataRequest(), {Session Management}
3867 */
3868
3869 /*!
3870 \fn bool QGuiApplication::isSessionRestored() const
3871
3872 Returns \c true if the application has been restored from an earlier
3873 \l{Session Management}{session}; otherwise returns \c false.
3874
3875 \sa sessionId(), commitDataRequest(), saveStateRequest()
3876 */
3877
3878 /*!
3879 \since 5.0
3880 \fn bool QGuiApplication::isSavingSession() const
3881
3882 Returns \c true if the application is currently saving the
3883 \l{Session Management}{session}; otherwise returns \c false.
3884
3885 This is \c true when commitDataRequest() and saveStateRequest() are emitted,
3886 but also when the windows are closed afterwards by session management.
3887
3888 \sa sessionId(), commitDataRequest(), saveStateRequest()
3889 */
3890
3891 /*!
3892 \fn QString QGuiApplication::sessionId() const
3893
3894 Returns the current \l{Session Management}{session's} identifier.
3895
3896 If the application has been restored from an earlier session, this
3897 identifier is the same as it was in that previous session. The session
3898 identifier is guaranteed to be unique both for different applications
3899 and for different instances of the same application.
3900
3901 \sa isSessionRestored(), sessionKey(), commitDataRequest(), saveStateRequest()
3902 */
3903
3904 /*!
3905 \fn QString QGuiApplication::sessionKey() const
3906
3907 Returns the session key in the current \l{Session Management}{session}.
3908
3909 If the application has been restored from an earlier session, this key is
3910 the same as it was when the previous session ended.
3911
3912 The session key changes every time the session is saved. If the shutdown process
3913 is cancelled, another session key will be used when shutting down again.
3914
3915 \sa isSessionRestored(), sessionId(), commitDataRequest(), saveStateRequest()
3916 */
3917 #ifndef QT_NO_SESSIONMANAGER
isSessionRestored() const3918 bool QGuiApplication::isSessionRestored() const
3919 {
3920 Q_D(const QGuiApplication);
3921 return d->is_session_restored;
3922 }
3923
sessionId() const3924 QString QGuiApplication::sessionId() const
3925 {
3926 Q_D(const QGuiApplication);
3927 return d->session_manager->sessionId();
3928 }
3929
sessionKey() const3930 QString QGuiApplication::sessionKey() const
3931 {
3932 Q_D(const QGuiApplication);
3933 return d->session_manager->sessionKey();
3934 }
3935
isSavingSession() const3936 bool QGuiApplication::isSavingSession() const
3937 {
3938 Q_D(const QGuiApplication);
3939 return d->is_saving_session;
3940 }
3941
commitData()3942 void QGuiApplicationPrivate::commitData()
3943 {
3944 Q_Q(QGuiApplication);
3945 is_saving_session = true;
3946
3947 emit q->commitDataRequest(*session_manager);
3948 if (is_fallback_session_management_enabled && session_manager->allowsInteraction()
3949 && !tryCloseAllWindows()) {
3950 session_manager->cancel();
3951 }
3952
3953 is_saving_session = false;
3954 }
3955
3956
saveState()3957 void QGuiApplicationPrivate::saveState()
3958 {
3959 Q_Q(QGuiApplication);
3960 is_saving_session = true;
3961 emit q->saveStateRequest(*session_manager);
3962 is_saving_session = false;
3963 }
3964 #endif //QT_NO_SESSIONMANAGER
3965
3966 /*!
3967 \since 5.2
3968
3969 Function that can be used to sync Qt state with the Window Systems state.
3970
3971 This function will first empty Qts events by calling QCoreApplication::processEvents(),
3972 then the platform plugin will sync up with the windowsystem, and finally Qts events
3973 will be delived by another call to QCoreApplication::processEvents();
3974
3975 This function is timeconsuming and its use is discouraged.
3976 */
sync()3977 void QGuiApplication::sync()
3978 {
3979 QCoreApplication::processEvents();
3980 if (QGuiApplicationPrivate::platform_integration
3981 && QGuiApplicationPrivate::platform_integration->hasCapability(QPlatformIntegration::SyncState)) {
3982 QGuiApplicationPrivate::platform_integration->sync();
3983 QCoreApplication::processEvents();
3984 QWindowSystemInterface::flushWindowSystemEvents();
3985 }
3986 }
3987
3988 /*!
3989 \property QGuiApplication::layoutDirection
3990 \brief the default layout direction for this application
3991
3992 On system start-up, the default layout direction depends on the
3993 application's language.
3994
3995 The notifier signal was introduced in Qt 5.4.
3996
3997 \sa QWidget::layoutDirection, isLeftToRight(), isRightToLeft()
3998 */
3999
setLayoutDirection(Qt::LayoutDirection direction)4000 void QGuiApplication::setLayoutDirection(Qt::LayoutDirection direction)
4001 {
4002 if (layout_direction == direction || direction == Qt::LayoutDirectionAuto)
4003 return;
4004
4005 layout_direction = direction;
4006
4007 if (qGuiApp) {
4008 emit qGuiApp->layoutDirectionChanged(direction);
4009 QGuiApplicationPrivate::self->notifyLayoutDirectionChange();
4010 }
4011 }
4012
layoutDirection()4013 Qt::LayoutDirection QGuiApplication::layoutDirection()
4014 {
4015 // layout_direction is only ever Qt::LayoutDirectionAuto if setLayoutDirection
4016 // was never called, or called with Qt::LayoutDirectionAuto (which is a no-op).
4017 // In that case we return the default LeftToRight.
4018 return layout_direction == Qt::LayoutDirectionAuto ? Qt::LeftToRight : layout_direction;
4019 }
4020
4021 /*!
4022 \fn QCursor *QGuiApplication::overrideCursor()
4023
4024 Returns the active application override cursor.
4025
4026 This function returns \nullptr if no application cursor has been defined (i.e. the
4027 internal cursor stack is empty).
4028
4029 \sa setOverrideCursor(), restoreOverrideCursor()
4030 */
4031 #ifndef QT_NO_CURSOR
overrideCursor()4032 QCursor *QGuiApplication::overrideCursor()
4033 {
4034 CHECK_QAPP_INSTANCE(nullptr)
4035 return qGuiApp->d_func()->cursor_list.isEmpty() ? nullptr : &qGuiApp->d_func()->cursor_list.first();
4036 }
4037
4038 /*!
4039 Changes the currently active application override cursor to \a cursor.
4040
4041 This function has no effect if setOverrideCursor() was not called.
4042
4043 \sa setOverrideCursor(), overrideCursor(), restoreOverrideCursor(),
4044 QWidget::setCursor()
4045 */
changeOverrideCursor(const QCursor & cursor)4046 void QGuiApplication::changeOverrideCursor(const QCursor &cursor)
4047 {
4048 CHECK_QAPP_INSTANCE()
4049 if (qGuiApp->d_func()->cursor_list.isEmpty())
4050 return;
4051 qGuiApp->d_func()->cursor_list.removeFirst();
4052 setOverrideCursor(cursor);
4053 }
4054 #endif
4055
4056
4057 #ifndef QT_NO_CURSOR
applyCursor(QWindow * w,QCursor c)4058 static inline void applyCursor(QWindow *w, QCursor c)
4059 {
4060 if (const QScreen *screen = w->screen())
4061 if (QPlatformCursor *cursor = screen->handle()->cursor())
4062 cursor->changeCursor(&c, w);
4063 }
4064
unsetCursor(QWindow * w)4065 static inline void unsetCursor(QWindow *w)
4066 {
4067 if (const QScreen *screen = w->screen())
4068 if (QPlatformCursor *cursor = screen->handle()->cursor())
4069 cursor->changeCursor(nullptr, w);
4070 }
4071
applyCursor(const QList<QWindow * > & l,const QCursor & c)4072 static inline void applyCursor(const QList<QWindow *> &l, const QCursor &c)
4073 {
4074 for (int i = 0; i < l.size(); ++i) {
4075 QWindow *w = l.at(i);
4076 if (w->handle() && w->type() != Qt::Desktop)
4077 applyCursor(w, c);
4078 }
4079 }
4080
applyOverrideCursor(const QList<QScreen * > & screens,const QCursor & c)4081 static inline void applyOverrideCursor(const QList<QScreen *> &screens, const QCursor &c)
4082 {
4083 for (QScreen *screen : screens) {
4084 if (QPlatformCursor *cursor = screen->handle()->cursor())
4085 cursor->setOverrideCursor(c);
4086 }
4087 }
4088
clearOverrideCursor(const QList<QScreen * > & screens)4089 static inline void clearOverrideCursor(const QList<QScreen *> &screens)
4090 {
4091 for (QScreen *screen : screens) {
4092 if (QPlatformCursor *cursor = screen->handle()->cursor())
4093 cursor->clearOverrideCursor();
4094 }
4095 }
4096
applyWindowCursor(const QList<QWindow * > & l)4097 static inline void applyWindowCursor(const QList<QWindow *> &l)
4098 {
4099 for (int i = 0; i < l.size(); ++i) {
4100 QWindow *w = l.at(i);
4101 if (w->handle() && w->type() != Qt::Desktop) {
4102 if (qt_window_private(w)->hasCursor) {
4103 applyCursor(w, w->cursor());
4104 } else {
4105 unsetCursor(w);
4106 }
4107 }
4108 }
4109 }
4110
4111 /*!
4112 \fn void QGuiApplication::setOverrideCursor(const QCursor &cursor)
4113
4114 Sets the application override cursor to \a cursor.
4115
4116 Application override cursors are intended for showing the user that the
4117 application is in a special state, for example during an operation that
4118 might take some time.
4119
4120 This cursor will be displayed in all the application's widgets until
4121 restoreOverrideCursor() or another setOverrideCursor() is called.
4122
4123 Application cursors are stored on an internal stack. setOverrideCursor()
4124 pushes the cursor onto the stack, and restoreOverrideCursor() pops the
4125 active cursor off the stack. changeOverrideCursor() changes the curently
4126 active application override cursor.
4127
4128 Every setOverrideCursor() must eventually be followed by a corresponding
4129 restoreOverrideCursor(), otherwise the stack will never be emptied.
4130
4131 Example:
4132 \snippet code/src_gui_kernel_qguiapplication_x11.cpp 0
4133
4134 \sa overrideCursor(), restoreOverrideCursor(), changeOverrideCursor(),
4135 QWidget::setCursor()
4136 */
setOverrideCursor(const QCursor & cursor)4137 void QGuiApplication::setOverrideCursor(const QCursor &cursor)
4138 {
4139 CHECK_QAPP_INSTANCE()
4140 qGuiApp->d_func()->cursor_list.prepend(cursor);
4141 if (QPlatformCursor::capabilities().testFlag(QPlatformCursor::OverrideCursor))
4142 applyOverrideCursor(QGuiApplicationPrivate::screen_list, cursor);
4143 else
4144 applyCursor(QGuiApplicationPrivate::window_list, cursor);
4145 }
4146
4147 /*!
4148 \fn void QGuiApplication::restoreOverrideCursor()
4149
4150 Undoes the last setOverrideCursor().
4151
4152 If setOverrideCursor() has been called twice, calling
4153 restoreOverrideCursor() will activate the first cursor set. Calling this
4154 function a second time restores the original widgets' cursors.
4155
4156 \sa setOverrideCursor(), overrideCursor()
4157 */
restoreOverrideCursor()4158 void QGuiApplication::restoreOverrideCursor()
4159 {
4160 CHECK_QAPP_INSTANCE()
4161 if (qGuiApp->d_func()->cursor_list.isEmpty())
4162 return;
4163 qGuiApp->d_func()->cursor_list.removeFirst();
4164 if (qGuiApp->d_func()->cursor_list.size() > 0) {
4165 QCursor c(qGuiApp->d_func()->cursor_list.value(0));
4166 if (QPlatformCursor::capabilities().testFlag(QPlatformCursor::OverrideCursor))
4167 applyOverrideCursor(QGuiApplicationPrivate::screen_list, c);
4168 else
4169 applyCursor(QGuiApplicationPrivate::window_list, c);
4170 } else {
4171 if (QPlatformCursor::capabilities().testFlag(QPlatformCursor::OverrideCursor))
4172 clearOverrideCursor(QGuiApplicationPrivate::screen_list);
4173 applyWindowCursor(QGuiApplicationPrivate::window_list);
4174 }
4175 }
4176 #endif// QT_NO_CURSOR
4177
4178 /*!
4179 Returns the application's style hints.
4180
4181 The style hints encapsulate a set of platform dependent properties
4182 such as double click intervals, full width selection and others.
4183
4184 The hints can be used to integrate tighter with the underlying platform.
4185
4186 \sa QStyleHints
4187 */
styleHints()4188 QStyleHints *QGuiApplication::styleHints()
4189 {
4190 if (!QGuiApplicationPrivate::styleHints)
4191 QGuiApplicationPrivate::styleHints = new QStyleHints();
4192 return QGuiApplicationPrivate::styleHints;
4193 }
4194
4195 /*!
4196 Sets whether Qt should use the system's standard colors, fonts, etc., to
4197 \a on. By default, this is \c true.
4198
4199 This function must be called before creating the QGuiApplication object, like
4200 this:
4201
4202 \snippet code/src_gui_kernel_qguiapplication.cpp 0
4203
4204 \sa desktopSettingsAware()
4205 */
setDesktopSettingsAware(bool on)4206 void QGuiApplication::setDesktopSettingsAware(bool on)
4207 {
4208 QGuiApplicationPrivate::obey_desktop_settings = on;
4209 }
4210
4211 /*!
4212 Returns \c true if Qt is set to use the system's standard colors, fonts, etc.;
4213 otherwise returns \c false. The default is \c true.
4214
4215 \sa setDesktopSettingsAware()
4216 */
desktopSettingsAware()4217 bool QGuiApplication::desktopSettingsAware()
4218 {
4219 return QGuiApplicationPrivate::obey_desktop_settings;
4220 }
4221
4222 /*!
4223 returns the input method.
4224
4225 The input method returns properties about the state and position of
4226 the virtual keyboard. It also provides information about the position of the
4227 current focused input element.
4228
4229 \sa QInputMethod
4230 */
inputMethod()4231 QInputMethod *QGuiApplication::inputMethod()
4232 {
4233 CHECK_QAPP_INSTANCE(nullptr)
4234 if (!qGuiApp->d_func()->inputMethod)
4235 qGuiApp->d_func()->inputMethod = new QInputMethod();
4236 return qGuiApp->d_func()->inputMethod;
4237 }
4238
4239 /*!
4240 \fn void QGuiApplication::fontDatabaseChanged()
4241
4242 This signal is emitted when application fonts are loaded or removed.
4243
4244 \sa QFontDatabase::addApplicationFont(),
4245 QFontDatabase::addApplicationFontFromData(),
4246 QFontDatabase::removeAllApplicationFonts(),
4247 QFontDatabase::removeApplicationFont()
4248 */
4249
getPixmapCursor(Qt::CursorShape cshape)4250 QPixmap QGuiApplicationPrivate::getPixmapCursor(Qt::CursorShape cshape)
4251 {
4252 Q_UNUSED(cshape);
4253 return QPixmap();
4254 }
4255
notifyThemeChanged()4256 void QGuiApplicationPrivate::notifyThemeChanged()
4257 {
4258 updatePalette();
4259
4260 if (!(applicationResourceFlags & ApplicationFontExplicitlySet)) {
4261 const auto locker = qt_scoped_lock(applicationFontMutex);
4262 clearFontUnlocked();
4263 initFontUnlocked();
4264 }
4265 initThemeHints();
4266 }
4267
4268 #if QT_CONFIG(draganddrop)
notifyDragStarted(const QDrag * drag)4269 void QGuiApplicationPrivate::notifyDragStarted(const QDrag *drag)
4270 {
4271 Q_UNUSED(drag)
4272
4273 }
4274 #endif
4275
colorProfileForA8Text()4276 const QColorTrcLut *QGuiApplicationPrivate::colorProfileForA8Text()
4277 {
4278 #ifdef Q_OS_WIN
4279 if (!m_a8ColorProfile){
4280 QColorTrcLut *cs = QColorTrcLut::fromGamma(2.31); // This is a hard-coded thing for Windows text rendering
4281 m_a8ColorProfile.reset(cs);
4282 }
4283 return m_a8ColorProfile.get();
4284 #else
4285 return colorProfileForA32Text();
4286 #endif
4287 }
4288
colorProfileForA32Text()4289 const QColorTrcLut *QGuiApplicationPrivate::colorProfileForA32Text()
4290 {
4291 if (!m_a32ColorProfile) {
4292 QColorTrcLut *cs = QColorTrcLut::fromGamma(fontSmoothingGamma);
4293 m_a32ColorProfile.reset(cs);
4294 }
4295 return m_a32ColorProfile.get();
4296 }
4297
_q_updateFocusObject(QObject * object)4298 void QGuiApplicationPrivate::_q_updateFocusObject(QObject *object)
4299 {
4300 Q_Q(QGuiApplication);
4301
4302 QPlatformInputContext *inputContext = platformIntegration()->inputContext();
4303 const bool enabled = inputContext && QInputMethodPrivate::objectAcceptsInputMethod(object);
4304
4305 QPlatformInputContextPrivate::setInputMethodAccepted(enabled);
4306 if (inputContext)
4307 inputContext->setFocusObject(object);
4308 emit q->focusObjectChanged(object);
4309 }
4310
4311 enum MouseMasks {
4312 MouseCapsMask = 0xFF,
4313 MouseSourceMaskDst = 0xFF00,
4314 MouseSourceMaskSrc = MouseCapsMask,
4315 MouseSourceShift = 8,
4316 MouseFlagsCapsMask = 0xFF0000,
4317 MouseFlagsShift = 16
4318 };
4319
mouseEventCaps(QMouseEvent * event)4320 int QGuiApplicationPrivate::mouseEventCaps(QMouseEvent *event)
4321 {
4322 return event->caps & MouseCapsMask;
4323 }
4324
mouseEventVelocity(QMouseEvent * event)4325 QVector2D QGuiApplicationPrivate::mouseEventVelocity(QMouseEvent *event)
4326 {
4327 return event->velocity;
4328 }
4329
setMouseEventCapsAndVelocity(QMouseEvent * event,int caps,const QVector2D & velocity)4330 void QGuiApplicationPrivate::setMouseEventCapsAndVelocity(QMouseEvent *event, int caps, const QVector2D &velocity)
4331 {
4332 Q_ASSERT(caps <= MouseCapsMask);
4333 event->caps &= ~MouseCapsMask;
4334 event->caps |= caps & MouseCapsMask;
4335 event->velocity = velocity;
4336 }
4337
mouseEventSource(const QMouseEvent * event)4338 Qt::MouseEventSource QGuiApplicationPrivate::mouseEventSource(const QMouseEvent *event)
4339 {
4340 return Qt::MouseEventSource((event->caps & MouseSourceMaskDst) >> MouseSourceShift);
4341 }
4342
setMouseEventSource(QMouseEvent * event,Qt::MouseEventSource source)4343 void QGuiApplicationPrivate::setMouseEventSource(QMouseEvent *event, Qt::MouseEventSource source)
4344 {
4345 // Mouse event synthesization status is encoded in the caps field because
4346 // QTouchDevice::CapabilityFlag uses only 6 bits from it.
4347 int value = source;
4348 Q_ASSERT(value <= MouseSourceMaskSrc);
4349 event->caps &= ~MouseSourceMaskDst;
4350 event->caps |= (value & MouseSourceMaskSrc) << MouseSourceShift;
4351 }
4352
mouseEventFlags(const QMouseEvent * event)4353 Qt::MouseEventFlags QGuiApplicationPrivate::mouseEventFlags(const QMouseEvent *event)
4354 {
4355 return Qt::MouseEventFlags((event->caps & MouseFlagsCapsMask) >> MouseFlagsShift);
4356 }
4357
setMouseEventFlags(QMouseEvent * event,Qt::MouseEventFlags flags)4358 void QGuiApplicationPrivate::setMouseEventFlags(QMouseEvent *event, Qt::MouseEventFlags flags)
4359 {
4360 // use the 0x00FF0000 byte from caps (containing up to 7 mouse event flags)
4361 unsigned int value = flags;
4362 Q_ASSERT(value <= Qt::MouseEventFlagMask);
4363 event->caps &= ~MouseFlagsCapsMask;
4364 event->caps |= (value & Qt::MouseEventFlagMask) << MouseFlagsShift;
4365 }
4366
inputDeviceManager()4367 QInputDeviceManager *QGuiApplicationPrivate::inputDeviceManager()
4368 {
4369 Q_ASSERT(QGuiApplication::instance());
4370
4371 if (!m_inputDeviceManager)
4372 m_inputDeviceManager = new QInputDeviceManager(QGuiApplication::instance());
4373
4374 return m_inputDeviceManager;
4375 }
4376
4377 #include "moc_qguiapplication.cpp"
4378
4379 QT_END_NAMESPACE
4380