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/qdir.h>
62#include <QtCore/qlibraryinfo.h>
63#include <QtCore/qnumeric.h>
64#include <QtDebug>
65#ifndef QT_NO_ACCESSIBILITY
66#include "qaccessible.h"
67#endif
68#include <qpalette.h>
69#include <qscreen.h>
70#include "qsessionmanager.h"
71#include <private/qcolortrclut_p.h>
72#include <private/qscreen_p.h>
73
74#include <QtGui/qgenericpluginfactory.h>
75#include <QtGui/qstylehints.h>
76#include <QtGui/qinputmethod.h>
77#include <QtGui/qpixmapcache.h>
78#include <qpa/qplatforminputcontext.h>
79#include <qpa/qplatforminputcontext_p.h>
80
81#include <qpa/qwindowsysteminterface.h>
82#include <qpa/qwindowsysteminterface_p.h>
83#include "private/qwindow_p.h"
84#include "private/qcursor_p.h"
85#include "private/qopenglcontext_p.h"
86#include "private/qinputdevicemanager_p.h"
87#include "private/qinputmethod_p.h"
88#include "private/qtouchdevice_p.h"
89
90#include <qpa/qplatformthemefactory_p.h>
91
92#if QT_CONFIG(draganddrop)
93#include <qpa/qplatformdrag.h>
94#include <private/qdnd_p.h>
95#endif
96
97#ifndef QT_NO_CURSOR
98#include <qpa/qplatformcursor.h>
99#endif
100
101#include <QtGui/QPixmap>
102
103#ifndef QT_NO_CLIPBOARD
104#include <QtGui/QClipboard>
105#endif
106
107#if QT_CONFIG(library)
108#include <QtCore/QLibrary>
109#endif
110
111#if defined(Q_OS_MAC)
112# include "private/qcore_mac_p.h"
113#elif defined(Q_OS_WIN)
114# include <QtCore/qt_windows.h>
115# include <QtCore/QLibraryInfo>
116#endif // Q_OS_WIN
117
118#ifdef Q_OS_WASM
119#include <emscripten.h>
120#endif
121
122#include <qtgui_tracepoints_p.h>
123
124#include <ctype.h>
125
126QT_BEGIN_NAMESPACE
127
128// Helper macro for static functions to check on the existence of the application class.
129#define CHECK_QAPP_INSTANCE(...) \
130 if (Q_LIKELY(QCoreApplication::instance())) { \
131 } else { \
132 qWarning("Must construct a QGuiApplication first."); \
133 return __VA_ARGS__; \
134 }
135
136Q_GUI_EXPORT bool qt_is_gui_used = true;
137
138Qt::MouseButtons QGuiApplicationPrivate::mouse_buttons = Qt::NoButton;
139Qt::KeyboardModifiers QGuiApplicationPrivate::modifier_buttons = Qt::NoModifier;
140
141QPointF QGuiApplicationPrivate::lastCursorPosition(qInf(), qInf());
142
143QWindow *QGuiApplicationPrivate::currentMouseWindow = 0;
144
145QString QGuiApplicationPrivate::styleOverride;
146
147Qt::ApplicationState QGuiApplicationPrivate::applicationState = Qt::ApplicationInactive;
148
149bool QGuiApplicationPrivate::highDpiScalingUpdated = false;
150
151QPointer<QWindow> QGuiApplicationPrivate::currentDragWindow;
152
153QVector<QGuiApplicationPrivate::TabletPointData> QGuiApplicationPrivate::tabletDevicePoints;
154
155QPlatformIntegration *QGuiApplicationPrivate::platform_integration = 0;
156QPlatformTheme *QGuiApplicationPrivate::platform_theme = 0;
157
158QList<QObject *> QGuiApplicationPrivate::generic_plugin_list;
159
160#ifndef QT_NO_SESSIONMANAGER
161bool QGuiApplicationPrivate::is_fallback_session_management_enabled = true;
162#endif
163
164enum ApplicationResourceFlags
165{
166 ApplicationPaletteExplicitlySet = 0x1,
167 ApplicationFontExplicitlySet = 0x2
168};
169
170static unsigned applicationResourceFlags = 0;
171
172QIcon *QGuiApplicationPrivate::app_icon = 0;
173
174QString *QGuiApplicationPrivate::platform_name = 0;
175QString *QGuiApplicationPrivate::displayName = 0;
176QString *QGuiApplicationPrivate::desktopFileName = 0;
177
178QPalette *QGuiApplicationPrivate::app_pal = 0; // default application palette
179
180ulong QGuiApplicationPrivate::mousePressTime = 0;
181Qt::MouseButton QGuiApplicationPrivate::mousePressButton = Qt::NoButton;
182int QGuiApplicationPrivate::mousePressX = 0;
183int QGuiApplicationPrivate::mousePressY = 0;
184
185static int mouseDoubleClickDistance = -1;
186static int touchDoubleTapDistance = -1;
187
188QWindow *QGuiApplicationPrivate::currentMousePressWindow = 0;
189
190static Qt::LayoutDirection layout_direction = Qt::LayoutDirectionAuto;
191static bool force_reverse = false;
192
193QGuiApplicationPrivate *QGuiApplicationPrivate::self = 0;
194QTouchDevice *QGuiApplicationPrivate::m_fakeTouchDevice = 0;
195int QGuiApplicationPrivate::m_fakeMouseSourcePointId = 0;
196
197#ifndef QT_NO_CLIPBOARD
198QClipboard *QGuiApplicationPrivate::qt_clipboard = 0;
199#endif
200
201QList<QScreen *> QGuiApplicationPrivate::screen_list;
202
203QWindowList QGuiApplicationPrivate::window_list;
204QWindow *QGuiApplicationPrivate::focus_window = 0;
205
206static QBasicMutex applicationFontMutex;
207QFont *QGuiApplicationPrivate::app_font = 0;
208QStyleHints *QGuiApplicationPrivate::styleHints = nullptr;
209bool QGuiApplicationPrivate::obey_desktop_settings = true;
210
211QInputDeviceManager *QGuiApplicationPrivate::m_inputDeviceManager = 0;
212
213qreal QGuiApplicationPrivate::m_maxDevicePixelRatio = 0.0;
214
215static qreal fontSmoothingGamma = 1.7;
216
217extern void qRegisterGuiVariant();
218#if QT_CONFIG(animation)
219extern void qRegisterGuiGetInterpolator();
220#endif
221
222static bool qt_detectRTLLanguage()
223{
224 return force_reverse ^
225 (QGuiApplication::tr("QT_LAYOUT_DIRECTION",
226 "Translate this string to the string 'LTR' in left-to-right"
227 " languages or to 'RTL' in right-to-left languages (such as Hebrew"
228 " and Arabic) to get proper widget layout.") == QLatin1String("RTL"));
229}
230
231static void initPalette()
232{
233 if (!QGuiApplicationPrivate::app_pal)
234 if (const QPalette *themePalette = QGuiApplicationPrivate::platformTheme()->palette())
235 QGuiApplicationPrivate::app_pal = new QPalette(*themePalette);
236 if (!QGuiApplicationPrivate::app_pal)
237 QGuiApplicationPrivate::app_pal = new QPalette(Qt::gray);
238}
239
240static inline void clearPalette()
241{
242 delete QGuiApplicationPrivate::app_pal;
243 QGuiApplicationPrivate::app_pal = 0;
244}
245
246static void initFontUnlocked()
247{
248 if (!QGuiApplicationPrivate::app_font) {
249 if (const QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme())
250 if (const QFont *font = theme->font(QPlatformTheme::SystemFont))
251 QGuiApplicationPrivate::app_font = new QFont(*font);
252 }
253 if (!QGuiApplicationPrivate::app_font)
254 QGuiApplicationPrivate::app_font =
255 new QFont(QGuiApplicationPrivate::platformIntegration()->fontDatabase()->defaultFont());
256}
257
258static inline void clearFontUnlocked()
259{
260 delete QGuiApplicationPrivate::app_font;
261 QGuiApplicationPrivate::app_font = 0;
262}
263
264static void initThemeHints()
265{
266 mouseDoubleClickDistance = QGuiApplicationPrivate::platformTheme()->themeHint(QPlatformTheme::MouseDoubleClickDistance).toInt();
267 touchDoubleTapDistance = QGuiApplicationPrivate::platformTheme()->themeHint(QPlatformTheme::TouchDoubleTapDistance).toInt();
268}
269
270static bool checkNeedPortalSupport()
271{
272#if QT_CONFIG(dbus)
273 return !QStandardPaths::locate(QStandardPaths::RuntimeLocation, QLatin1String("flatpak-info")).isEmpty() || qEnvironmentVariableIsSet("SNAP");
274#else
275 return false;
276#endif // QT_CONFIG(dbus)
277}
278
279// Using aggregate initialization instead of ctor so we can have a POD global static
280#define Q_WINDOW_GEOMETRY_SPECIFICATION_INITIALIZER { Qt::TopLeftCorner, -1, -1, -1, -1 }
281
282// Geometry specification for top level windows following the convention of the
283// -geometry command line arguments in X11 (see XParseGeometry).
284struct QWindowGeometrySpecification
285{
286 static QWindowGeometrySpecification fromArgument(const QByteArray &a);
287 void applyTo(QWindow *window) const;
288
289 Qt::Corner corner;
290 int xOffset;
291 int yOffset;
292 int width;
293 int height;
294};
295
296// Parse a token of a X11 geometry specification "200x100+10-20".
297static inline int nextGeometryToken(const QByteArray &a, int &pos, char *op)
298{
299 *op = 0;
300 const int size = a.size();
301 if (pos >= size)
302 return -1;
303
304 *op = a.at(pos);
305 if (*op == '+' || *op == '-' || *op == 'x')
306 pos++;
307 else if (isdigit(*op))
308 *op = 'x'; // If it starts with a digit, it is supposed to be a width specification.
309 else
310 return -1;
311
312 const int numberPos = pos;
313 for ( ; pos < size && isdigit(a.at(pos)); ++pos) ;
314
315 bool ok;
316 const int result = a.mid(numberPos, pos - numberPos).toInt(&ok);
317 return ok ? result : -1;
318}
319
320QWindowGeometrySpecification QWindowGeometrySpecification::fromArgument(const QByteArray &a)
321{
322 QWindowGeometrySpecification result = Q_WINDOW_GEOMETRY_SPECIFICATION_INITIALIZER;
323 int pos = 0;
324 for (int i = 0; i < 4; ++i) {
325 char op;
326 const int value = nextGeometryToken(a, pos, &op);
327 if (value < 0)
328 break;
329 switch (op) {
330 case 'x':
331 (result.width >= 0 ? result.height : result.width) = value;
332 break;
333 case '+':
334 case '-':
335 if (result.xOffset >= 0) {
336 result.yOffset = value;
337 if (op == '-')
338 result.corner = result.corner == Qt::TopRightCorner ? Qt::BottomRightCorner : Qt::BottomLeftCorner;
339 } else {
340 result.xOffset = value;
341 if (op == '-')
342 result.corner = Qt::TopRightCorner;
343 }
344 }
345 }
346 return result;
347}
348
349void QWindowGeometrySpecification::applyTo(QWindow *window) const
350{
351 QRect windowGeometry = window->frameGeometry();
352 QSize size = windowGeometry.size();
353 if (width >= 0 || height >= 0) {
354 const QSize windowMinimumSize = window->minimumSize();
355 const QSize windowMaximumSize = window->maximumSize();
356 if (width >= 0)
357 size.setWidth(qBound(windowMinimumSize.width(), width, windowMaximumSize.width()));
358 if (height >= 0)
359 size.setHeight(qBound(windowMinimumSize.height(), height, windowMaximumSize.height()));
360 window->resize(size);
361 }
362 if (xOffset >= 0 || yOffset >= 0) {
363 const QRect availableGeometry = window->screen()->virtualGeometry();
364 QPoint topLeft = windowGeometry.topLeft();
365 if (xOffset >= 0) {
366 topLeft.setX(corner == Qt::TopLeftCorner || corner == Qt::BottomLeftCorner ?
367 xOffset :
368 qMax(availableGeometry.right() - size.width() - xOffset, availableGeometry.left()));
369 }
370 if (yOffset >= 0) {
371 topLeft.setY(corner == Qt::TopLeftCorner || corner == Qt::TopRightCorner ?
372 yOffset :
373 qMax(availableGeometry.bottom() - size.height() - yOffset, availableGeometry.top()));
374 }
375 window->setFramePosition(topLeft);
376 }
377}
378
379static QWindowGeometrySpecification windowGeometrySpecification = Q_WINDOW_GEOMETRY_SPECIFICATION_INITIALIZER;
380
381/*!
382 \macro qGuiApp
383 \relates QGuiApplication
384
385 A global pointer referring to the unique application object.
386 Only valid for use when that object is a QGuiApplication.
387
388 \sa QCoreApplication::instance(), qApp
389*/
390
391/*!
392 \class QGuiApplication
393 \brief The QGuiApplication class manages the GUI application's control
394 flow and main settings.
395
396 \inmodule QtGui
397 \since 5.0
398
399 QGuiApplication contains the main event loop, where all events from the window
400 system and other sources are processed and dispatched. It also handles the
401 application's initialization and finalization, and provides session management.
402 In addition, QGuiApplication handles most of the system-wide and application-wide
403 settings.
404
405 For any GUI application using Qt, there is precisely \b one QGuiApplication
406 object no matter whether the application has 0, 1, 2 or more windows at
407 any given time. For non-GUI Qt applications, use QCoreApplication instead,
408 as it does not depend on the Qt GUI module. For QWidget based Qt applications,
409 use QApplication instead, as it provides some functionality needed for creating
410 QWidget instances.
411
412 The QGuiApplication object is accessible through the instance() function, which
413 returns a pointer equivalent to the global \l qApp pointer.
414
415 QGuiApplication's main areas of responsibility are:
416 \list
417 \li It initializes the application with the user's desktop settings,
418 such as palette(), font() and styleHints(). It keeps
419 track of these properties in case the user changes the desktop
420 globally, for example, through some kind of control panel.
421
422 \li It performs event handling, meaning that it receives events
423 from the underlying window system and dispatches them to the
424 relevant widgets. You can send your own events to windows by
425 using sendEvent() and postEvent().
426
427 \li It parses common command line arguments and sets its internal
428 state accordingly. See the \l{QGuiApplication::QGuiApplication()}
429 {constructor documentation} below for more details.
430
431 \li It provides localization of strings that are visible to the
432 user via translate().
433
434 \li It provides some magical objects like the clipboard().
435
436 \li It knows about the application's windows. You can ask which
437 window is at a certain position using topLevelAt(), get a list of
438 topLevelWindows(), etc.
439
440 \li It manages the application's mouse cursor handling, see
441 setOverrideCursor()
442
443 \li It provides support for sophisticated \l{Session Management}
444 {session management}. This makes it possible for applications
445 to terminate gracefully when the user logs out, to cancel a
446 shutdown process if termination isn't possible and even to
447 preserve the entire application's state for a future session.
448 See isSessionRestored(), sessionId() and commitDataRequest() and
449 saveStateRequest() for details.
450 \endlist
451
452 Since the QGuiApplication object does so much initialization, it \e{must} be
453 created before any other objects related to the user interface are created.
454 QGuiApplication also deals with common command line arguments. Hence, it is
455 usually a good idea to create it \e before any interpretation or
456 modification of \c argv is done in the application itself.
457
458 \table
459 \header
460 \li{2,1} Groups of functions
461
462 \row
463 \li System settings
464 \li desktopSettingsAware(),
465 setDesktopSettingsAware(),
466 styleHints(),
467 palette(),
468 setPalette(),
469 font(),
470 setFont().
471
472 \row
473 \li Event handling
474 \li exec(),
475 processEvents(),
476 exit(),
477 quit().
478 sendEvent(),
479 postEvent(),
480 sendPostedEvents(),
481 removePostedEvents(),
482 hasPendingEvents(),
483 notify().
484
485 \row
486 \li Windows
487 \li allWindows(),
488 topLevelWindows(),
489 focusWindow(),
490 clipboard(),
491 topLevelAt().
492
493 \row
494 \li Advanced cursor handling
495 \li overrideCursor(),
496 setOverrideCursor(),
497 restoreOverrideCursor().
498
499 \row
500 \li Session management
501 \li isSessionRestored(),
502 sessionId(),
503 commitDataRequest(),
504 saveStateRequest().
505
506 \row
507 \li Miscellaneous
508 \li startingUp(),
509 closingDown().
510 \endtable
511
512 \sa QCoreApplication, QAbstractEventDispatcher, QEventLoop
513*/
514
515/*!
516 Initializes the window system and constructs an application object with
517 \a argc command line arguments in \a argv.
518
519 \warning The data referred to by \a argc and \a argv must stay valid for
520 the entire lifetime of the QGuiApplication object. In addition, \a argc must
521 be greater than zero and \a argv must contain at least one valid character
522 string.
523
524 The global \c qApp pointer refers to this application object. Only one
525 application object should be created.
526
527 This application object must be constructed before any \l{QPaintDevice}
528 {paint devices} (including pixmaps, bitmaps etc.).
529
530 \note \a argc and \a argv might be changed as Qt removes command line
531 arguments that it recognizes.
532
533 \section1 Supported Command Line Options
534
535 All Qt programs automatically support a set of command-line options that
536 allow modifying the way Qt will interact with the windowing system. Some of
537 the options are also accessible via environment variables, which are the
538 preferred form if the application can launch GUI sub-processes or other
539 applications (environment variables will be inherited by child processes).
540 When in doubt, use the environment variables.
541
542 The options currently supported are the following:
543 \list
544
545 \li \c{-platform} \e {platformName[:options]}, specifies the
546 \l{Qt Platform Abstraction} (QPA) plugin.
547
548 Overrides the \c QT_QPA_PLATFORM environment variable.
549 \li \c{-platformpluginpath} \e path, specifies the path to platform
550 plugins.
551
552 Overrides the \c QT_QPA_PLATFORM_PLUGIN_PATH environment variable.
553
554 \li \c{-platformtheme} \e platformTheme, specifies the platform theme.
555
556 Overrides the \c QT_QPA_PLATFORMTHEME environment variable.
557
558 \li \c{-plugin} \e plugin, specifies additional plugins to load. The argument
559 may appear multiple times.
560
561 Concatenated with the plugins in the \c QT_QPA_GENERIC_PLUGINS environment
562 variable.
563
564 \li \c{-qmljsdebugger=}, activates the QML/JS debugger with a specified port.
565 The value must be of format \c{port:1234}\e{[,block]}, where
566 \e block is optional
567 and will make the application wait until a debugger connects to it.
568 \li \c {-qwindowgeometry} \e geometry, specifies window geometry for
569 the main window using the X11-syntax. For example:
570 \c {-qwindowgeometry 100x100+50+50}
571 \li \c {-qwindowicon}, sets the default window icon
572 \li \c {-qwindowtitle}, sets the title of the first window
573 \li \c{-reverse}, sets the application's layout direction to
574 Qt::RightToLeft. This option is intended to aid debugging and should
575 not be used in production. The default value is automatically detected
576 from the user's locale (see also QLocale::textDirection()).
577 \li \c{-session} \e session, restores the application from an earlier
578 \l{Session Management}{session}.
579 \endlist
580
581 The following standard command line options are available for X11:
582
583 \list
584 \li \c {-display} \e {hostname:screen_number}, switches displays on X11.
585
586 Overrides the \c DISPLAY environment variable.
587 \li \c {-geometry} \e geometry, same as \c {-qwindowgeometry}.
588 \endlist
589
590 \section1 Platform-Specific Arguments
591
592 You can specify platform-specific arguments for the \c{-platform} option.
593 Place them after the platform plugin name following a colon as a
594 comma-separated list. For example,
595 \c{-platform windows:dialogs=xp,fontengine=freetype}.
596
597 The following parameters are available for \c {-platform windows}:
598
599 \list
600 \li \c {dialogs=[xp|none]}, \c xp uses XP-style native dialogs and
601 \c none disables them.
602 \li \c {fontengine=freetype}, uses the FreeType font engine.
603 \li \c {menus=[native|none]}, controls the use of native menus.
604
605 Native menus are implemented using Win32 API and are simpler than
606 QMenu-based menus in for example that they do allow for placing
607 widgets on them or changing properties like fonts and do not
608 provide hover signals. They are mainly intended for Qt Quick.
609 By default, they will be used if the application is not an
610 instance of QApplication or for Qt Quick Controls 2
611 applications.
612
613 \li \c {altgr}, detect the key \c {AltGr} found on some keyboards as
614 Qt::GroupSwitchModifier.
615 \endlist
616
617 The following parameter is available for \c {-platform cocoa} (on macOS):
618
619 \list
620 \li \c {fontengine=freetype}, uses the FreeType font engine.
621 \endlist
622
623 For more information about the platform-specific arguments available for
624 embedded Linux platforms, see \l{Qt for Embedded Linux}.
625
626 \sa arguments() QGuiApplication::platformName
627*/
628#ifdef Q_QDOC
629QGuiApplication::QGuiApplication(int &argc, char **argv)
630#else
631QGuiApplication::QGuiApplication(int &argc, char **argv, int flags)
632#endif
633 : QCoreApplication(*new QGuiApplicationPrivate(argc, argv, flags))
634{
635 d_func()->init();
636
637 QCoreApplicationPrivate::eventDispatcher->startingUp();
638}
639
640/*!
641 \internal
642*/
643QGuiApplication::QGuiApplication(QGuiApplicationPrivate &p)
644 : QCoreApplication(p)
645{
646}
647
648/*!
649 Destructs the application.
650*/
651QGuiApplication::~QGuiApplication()
652{
653 Q_D(QGuiApplication);
654
655 d->eventDispatcher->closingDown();
656 d->eventDispatcher = 0;
657
658#ifndef QT_NO_CLIPBOARD
659 delete QGuiApplicationPrivate::qt_clipboard;
660 QGuiApplicationPrivate::qt_clipboard = 0;
661#endif
662
663#ifndef QT_NO_SESSIONMANAGER
664 delete d->session_manager;
665 d->session_manager = 0;
666#endif //QT_NO_SESSIONMANAGER
667
668 clearPalette();
669 QFontDatabase::removeAllApplicationFonts();
670
671#ifndef QT_NO_CURSOR
672 d->cursor_list.clear();
673#endif
674
675 delete QGuiApplicationPrivate::app_icon;
676 QGuiApplicationPrivate::app_icon = 0;
677 delete QGuiApplicationPrivate::platform_name;
678 QGuiApplicationPrivate::platform_name = 0;
679 delete QGuiApplicationPrivate::displayName;
680 QGuiApplicationPrivate::displayName = 0;
681 delete QGuiApplicationPrivate::m_inputDeviceManager;
682 QGuiApplicationPrivate::m_inputDeviceManager = 0;
683 delete QGuiApplicationPrivate::desktopFileName;
684 QGuiApplicationPrivate::desktopFileName = 0;
685 QGuiApplicationPrivate::mouse_buttons = Qt::NoButton;
686 QGuiApplicationPrivate::modifier_buttons = Qt::NoModifier;
687 QGuiApplicationPrivate::lastCursorPosition = {qInf(), qInf()};
688 QGuiApplicationPrivate::currentMousePressWindow = QGuiApplicationPrivate::currentMouseWindow = nullptr;
689 QGuiApplicationPrivate::applicationState = Qt::ApplicationInactive;
690 QGuiApplicationPrivate::highDpiScalingUpdated = false;
691 QGuiApplicationPrivate::currentDragWindow = nullptr;
692 QGuiApplicationPrivate::tabletDevicePoints.clear();
693#ifndef QT_NO_SESSIONMANAGER
694 QGuiApplicationPrivate::is_fallback_session_management_enabled = true;
695#endif
696 QGuiApplicationPrivate::mousePressTime = 0;
697 QGuiApplicationPrivate::mousePressX = QGuiApplicationPrivate::mousePressY = 0;
698}
699
700QGuiApplicationPrivate::QGuiApplicationPrivate(int &argc, char **argv, int flags)
701 : QCoreApplicationPrivate(argc, argv, flags),
702 inputMethod(0),
703 lastTouchType(QEvent::TouchEnd),
704 ownGlobalShareContext(false)
705{
706 self = this;
707 application_type = QCoreApplicationPrivate::Gui;
708#ifndef QT_NO_SESSIONMANAGER
709 is_session_restored = false;
710 is_saving_session = false;
711#endif
712}
713
714/*!
715 \property QGuiApplication::applicationDisplayName
716 \brief the user-visible name of this application
717 \since 5.0
718
719 This name is shown to the user, for instance in window titles.
720 It can be translated, if necessary.
721
722 If not set, the application display name defaults to the application name.
723
724 \sa applicationName
725*/
726void QGuiApplication::setApplicationDisplayName(const QString &name)
727{
728 if (!QGuiApplicationPrivate::displayName) {
729 QGuiApplicationPrivate::displayName = new QString(name);
730 if (qGuiApp) {
731 disconnect(qGuiApp, &QGuiApplication::applicationNameChanged,
732 qGuiApp, &QGuiApplication::applicationDisplayNameChanged);
733
734 if (*QGuiApplicationPrivate::displayName != applicationName())
735 emit qGuiApp->applicationDisplayNameChanged();
736 }
737 } else if (name != *QGuiApplicationPrivate::displayName) {
738 *QGuiApplicationPrivate::displayName = name;
739 if (qGuiApp)
740 emit qGuiApp->applicationDisplayNameChanged();
741 }
742}
743
744QString QGuiApplication::applicationDisplayName()
745{
746 return QGuiApplicationPrivate::displayName ? *QGuiApplicationPrivate::displayName : applicationName();
747}
748
749/*!
750 \property QGuiApplication::desktopFileName
751 \brief the base name of the desktop entry for this application
752 \since 5.7
753
754 This is the file name, without the full path, of the desktop entry
755 that represents this application according to the freedesktop desktop
756 entry specification.
757
758 This property gives a precise indication of what desktop entry represents
759 the application and it is needed by the windowing system to retrieve
760 such information without resorting to imprecise heuristics.
761
762 The latest version of the freedesktop desktop entry specification can be obtained
763 \l{http://standards.freedesktop.org/desktop-entry-spec/latest/}{here}.
764*/
765void QGuiApplication::setDesktopFileName(const QString &name)
766{
767 if (!QGuiApplicationPrivate::desktopFileName)
768 QGuiApplicationPrivate::desktopFileName = new QString;
769 *QGuiApplicationPrivate::desktopFileName = name;
770}
771
772QString QGuiApplication::desktopFileName()
773{
774 return QGuiApplicationPrivate::desktopFileName ? *QGuiApplicationPrivate::desktopFileName : QString();
775}
776
777/*!
778 Returns the most recently shown modal window. If no modal windows are
779 visible, this function returns zero.
780
781 A modal window is a window which has its
782 \l{QWindow::modality}{modality} property set to Qt::WindowModal
783 or Qt::ApplicationModal. A modal window must be closed before the user can
784 continue with other parts of the program.
785
786 Modal window are organized in a stack. This function returns the modal
787 window at the top of the stack.
788
789 \sa Qt::WindowModality, QWindow::setModality()
790*/
791QWindow *QGuiApplication::modalWindow()
792{
793 CHECK_QAPP_INSTANCE(nullptr)
794 if (QGuiApplicationPrivate::self->modalWindowList.isEmpty())
795 return 0;
796 return QGuiApplicationPrivate::self->modalWindowList.first();
797}
798
799static void updateBlockedStatusRecursion(QWindow *window, bool shouldBeBlocked)
800{
801 QWindowPrivate *p = qt_window_private(window);
802 if (p->blockedByModalWindow != shouldBeBlocked) {
803 p->blockedByModalWindow = shouldBeBlocked;
804 QEvent e(shouldBeBlocked ? QEvent::WindowBlocked : QEvent::WindowUnblocked);
805 QGuiApplication::sendEvent(window, &e);
806 for (QObject *c : window->children()) {
807 if (c->isWindowType())
808 updateBlockedStatusRecursion(static_cast<QWindow *>(c), shouldBeBlocked);
809 }
810 }
811}
812
813void QGuiApplicationPrivate::updateBlockedStatus(QWindow *window)
814{
815 bool shouldBeBlocked = false;
816 const bool popupType = (window->type() == Qt::ToolTip) || (window->type() == Qt::Popup);
817 if (!popupType && !self->modalWindowList.isEmpty())
818 shouldBeBlocked = self->isWindowBlocked(window);
819 updateBlockedStatusRecursion(window, shouldBeBlocked);
820}
821
822// Return whether the window needs to be notified about window blocked events.
823// As opposed to QGuiApplication::topLevelWindows(), embedded windows are
824// included in this list (QTBUG-18099).
825static inline bool needsWindowBlockedEvent(const QWindow *w)
826{
827 return w->isTopLevel() && w->type() != Qt::Desktop;
828}
829
830void QGuiApplicationPrivate::showModalWindow(QWindow *modal)
831{
832 self->modalWindowList.prepend(modal);
833
834 // Send leave for currently entered window if it should be blocked
835 if (currentMouseWindow && !QWindowPrivate::get(currentMouseWindow)->isPopup()) {
836 bool shouldBeBlocked = self->isWindowBlocked(currentMouseWindow);
837 if (shouldBeBlocked) {
838 // Remove the new window from modalWindowList temporarily so leave can go through
839 self->modalWindowList.removeFirst();
840 QEvent e(QEvent::Leave);
841 QGuiApplication::sendEvent(currentMouseWindow, &e);
842 currentMouseWindow = 0;
843 self->modalWindowList.prepend(modal);
844 }
845 }
846
847 for (QWindow *window : qAsConst(QGuiApplicationPrivate::window_list)) {
848 if (needsWindowBlockedEvent(window) && !window->d_func()->blockedByModalWindow)
849 updateBlockedStatus(window);
850 }
851
852 updateBlockedStatus(modal);
853}
854
855void QGuiApplicationPrivate::hideModalWindow(QWindow *window)
856{
857 self->modalWindowList.removeAll(window);
858
859 for (QWindow *window : qAsConst(QGuiApplicationPrivate::window_list)) {
860 if (needsWindowBlockedEvent(window) && window->d_func()->blockedByModalWindow)
861 updateBlockedStatus(window);
862 }
863}
864
865/*
866 Returns \c true if \a window is blocked by a modal window. If \a
867 blockingWindow is non-zero, *blockingWindow will be set to the blocking
868 window (or to zero if \a window is not blocked).
869*/
870bool QGuiApplicationPrivate::isWindowBlocked(QWindow *window, QWindow **blockingWindow) const
871{
872 QWindow *unused = 0;
873 if (!blockingWindow)
874 blockingWindow = &unused;
875
876 if (modalWindowList.isEmpty()) {
877 *blockingWindow = 0;
878 return false;
879 }
880
881 for (int i = 0; i < modalWindowList.count(); ++i) {
882 QWindow *modalWindow = modalWindowList.at(i);
883
884 // A window is not blocked by another modal window if the two are
885 // the same, or if the window is a child of the modal window.
886 if (window == modalWindow || modalWindow->isAncestorOf(window, QWindow::IncludeTransients)) {
887 *blockingWindow = 0;
888 return false;
889 }
890
891 Qt::WindowModality windowModality = modalWindow->modality();
892 switch (windowModality) {
893 case Qt::ApplicationModal:
894 {
895 if (modalWindow != window) {
896 *blockingWindow = modalWindow;
897 return true;
898 }
899 break;
900 }
901 case Qt::WindowModal:
902 {
903 QWindow *w = window;
904 do {
905 QWindow *m = modalWindow;
906 do {
907 if (m == w) {
908 *blockingWindow = m;
909 return true;
910 }
911 QWindow *p = m->parent();
912 if (!p)
913 p = m->transientParent();
914 m = p;
915 } while (m);
916 QWindow *p = w->parent();
917 if (!p)
918 p = w->transientParent();
919 w = p;
920 } while (w);
921 break;
922 }
923 default:
924 Q_ASSERT_X(false, "QGuiApplication", "internal error, a modal widget cannot be modeless");
925 break;
926 }
927 }
928 *blockingWindow = 0;
929 return false;
930}
931
932/*!
933 Returns the QWindow that receives events tied to focus,
934 such as key events.
935*/
936QWindow *QGuiApplication::focusWindow()
937{
938 return QGuiApplicationPrivate::focus_window;
939}
940
941/*!
942 \fn QGuiApplication::focusObjectChanged(QObject *focusObject)
943
944 This signal is emitted when final receiver of events tied to focus is changed.
945 \a focusObject is the new receiver.
946
947 \sa focusObject()
948*/
949
950/*!
951 \fn QGuiApplication::focusWindowChanged(QWindow *focusWindow)
952
953 This signal is emitted when the focused window changes.
954 \a focusWindow is the new focused window.
955
956 \sa focusWindow()
957*/
958
959/*!
960 Returns the QObject in currently active window that will be final receiver of events
961 tied to focus, such as key events.
962 */
963QObject *QGuiApplication::focusObject()
964{
965 if (focusWindow())
966 return focusWindow()->focusObject();
967 return 0;
968}
969
970/*!
971 \fn QGuiApplication::allWindows()
972
973 Returns a list of all the windows in the application.
974
975 The list is empty if there are no windows.
976
977 \sa topLevelWindows()
978 */
979QWindowList QGuiApplication::allWindows()
980{
981 return QGuiApplicationPrivate::window_list;
982}
983
984/*!
985 \fn QGuiApplication::topLevelWindows()
986
987 Returns a list of the top-level windows in the application.
988
989 \sa allWindows()
990 */
991QWindowList QGuiApplication::topLevelWindows()
992{
993 const QWindowList &list = QGuiApplicationPrivate::window_list;
994 QWindowList topLevelWindows;
995 for (int i = 0; i < list.size(); ++i) {
996 QWindow *window = list.at(i);
997 if (!window->isTopLevel())
998 continue;
999
1000 // Desktop windows are special, as each individual desktop window
1001 // will report that it's a top level window, but we don't want to
1002 // include them in the application wide list of top level windows.
1003 if (window->type() == Qt::Desktop)
1004 continue;
1005
1006 // Windows embedded in native windows do not have QWindow parents,
1007 // but they are not true top level windows, so do not include them.
1008 if (window->handle() && window->handle()->isEmbedded())
1009 continue;
1010
1011 topLevelWindows.prepend(window);
1012 }
1013
1014 return topLevelWindows;
1015}
1016
1017QScreen *QGuiApplication::primaryScreen()
1018{
1019 if (QGuiApplicationPrivate::screen_list.isEmpty())
1020 return 0;
1021 return QGuiApplicationPrivate::screen_list.at(0);
1022}
1023
1024/*!
1025 Returns a list of all the screens associated with the
1026 windowing system the application is connected to.
1027*/
1028QList<QScreen *> QGuiApplication::screens()
1029{
1030 return QGuiApplicationPrivate::screen_list;
1031}
1032
1033/*!
1034 Returns the screen at \a point, or \nullptr if outside of any screen.
1035
1036 The \a point is in relation to the virtualGeometry() of each set of virtual
1037 siblings. If the point maps to more than one set of virtual siblings the first
1038 match is returned.
1039
1040 \since 5.10
1041*/
1042QScreen *QGuiApplication::screenAt(const QPoint &point)
1043{
1044 QVarLengthArray<const QScreen *, 8> visitedScreens;
1045 for (const QScreen *screen : QGuiApplication::screens()) {
1046 if (visitedScreens.contains(screen))
1047 continue;
1048
1049 // The virtual siblings include the screen itself, so iterate directly
1050 for (QScreen *sibling : screen->virtualSiblings()) {
1051 if (sibling->geometry().contains(point))
1052 return sibling;
1053
1054 visitedScreens.append(sibling);
1055 }
1056 }
1057
1058 return nullptr;
1059}
1060
1061/*!
1062 \fn void QGuiApplication::screenAdded(QScreen *screen)
1063
1064 This signal is emitted whenever a new screen \a screen has been added to the system.
1065
1066 \sa screens(), primaryScreen, screenRemoved()
1067*/
1068
1069/*!
1070 \fn void QGuiApplication::screenRemoved(QScreen *screen)
1071
1072 This signal is emitted whenever a \a screen is removed from the system. It
1073 provides an opportunity to manage the windows on the screen before Qt falls back
1074 to moving them to the primary screen.
1075
1076 \sa screens(), screenAdded(), QObject::destroyed(), QWindow::setScreen()
1077
1078 \since 5.4
1079*/
1080
1081
1082/*!
1083 \property QGuiApplication::primaryScreen
1084
1085 \brief the primary (or default) screen of the application.
1086
1087 This will be the screen where QWindows are initially shown, unless otherwise specified.
1088
1089 The primaryScreenChanged signal was introduced in Qt 5.6.
1090
1091 \sa screens()
1092*/
1093
1094/*!
1095 Returns the highest screen device pixel ratio found on
1096 the system. This is the ratio between physical pixels and
1097 device-independent pixels.
1098
1099 Use this function only when you don't know which window you are targeting.
1100 If you do know the target window, use QWindow::devicePixelRatio() instead.
1101
1102 \sa QWindow::devicePixelRatio()
1103*/
1104qreal QGuiApplication::devicePixelRatio() const
1105{
1106 if (!qFuzzyIsNull(QGuiApplicationPrivate::m_maxDevicePixelRatio))
1107 return QGuiApplicationPrivate::m_maxDevicePixelRatio;
1108
1109 QGuiApplicationPrivate::m_maxDevicePixelRatio = 1.0; // make sure we never return 0.
1110 for (QScreen *screen : qAsConst(QGuiApplicationPrivate::screen_list))
1111 QGuiApplicationPrivate::m_maxDevicePixelRatio = qMax(QGuiApplicationPrivate::m_maxDevicePixelRatio, screen->devicePixelRatio());
1112
1113 return QGuiApplicationPrivate::m_maxDevicePixelRatio;
1114}
1115
1116void QGuiApplicationPrivate::resetCachedDevicePixelRatio()
1117{
1118 m_maxDevicePixelRatio = 0.0;
1119}
1120
1121/*!
1122 Returns the top level window at the given position \a pos, if any.
1123*/
1124QWindow *QGuiApplication::topLevelAt(const QPoint &pos)
1125{
1126 if (QScreen *windowScreen = screenAt(pos)) {
1127 const QPoint devicePosition = QHighDpi::toNativePixels(pos, windowScreen);
1128 return windowScreen->handle()->topLevelAt(devicePosition);
1129 }
1130 return nullptr;
1131}
1132
1133/*!
1134 \property QGuiApplication::platformName
1135 \brief The name of the underlying platform plugin.
1136
1137 The QPA platform plugins are located in \c {qtbase\src\plugins\platforms}.
1138 At the time of writing, the following platform plugin names are supported:
1139
1140 \list
1141 \li \c android
1142 \li \c cocoa is a platform plugin for \macos.
1143 \li \c directfb
1144 \li \c eglfs is a platform plugin for running Qt5 applications on top of
1145 EGL and OpenGL ES 2.0 without an actual windowing system (like X11
1146 or Wayland). For more information, see \l{EGLFS}.
1147 \li \c ios (also used for tvOS)
1148 \li \c kms is an experimental platform plugin using kernel modesetting
1149 and \l{http://dri.freedesktop.org/wiki/DRM}{DRM} (Direct Rendering
1150 Manager).
1151 \li \c linuxfb writes directly to the framebuffer. For more information,
1152 see \l{LinuxFB}.
1153 \li \c minimal is provided as an examples for developers who want to
1154 write their own platform plugins. However, you can use the plugin to
1155 run GUI applications in environments without a GUI, such as servers.
1156 \li \c minimalegl is an example plugin.
1157 \li \c offscreen
1158 \li \c openwfd
1159 \li \c qnx
1160 \li \c windows
1161 \li \c wayland is a platform plugin for modern Linux desktops and some
1162 embedded systems.
1163 \li \c xcb is the X11 plugin used on regular desktop Linux platforms.
1164 \endlist
1165
1166 For more information about the platform plugins for embedded Linux devices,
1167 see \l{Qt for Embedded Linux}.
1168*/
1169
1170QString QGuiApplication::platformName()
1171{
1172 return QGuiApplicationPrivate::platform_name ?
1173 *QGuiApplicationPrivate::platform_name : QString();
1174}
1175
1176Q_LOGGING_CATEGORY(lcQpaPluginLoading, "qt.qpa.plugin");
1177
1178static void init_platform(const QString &pluginNamesWithArguments, const QString &platformPluginPath, const QString &platformThemeName, int &argc, char **argv)
1179{
1180 QStringList plugins = pluginNamesWithArguments.split(QLatin1Char(';'));
1181 QStringList platformArguments;
1182 QStringList availablePlugins = QPlatformIntegrationFactory::keys(platformPluginPath);
1183 for (const auto &pluginArgument : plugins) {
1184 // Split into platform name and arguments
1185 QStringList arguments = pluginArgument.split(QLatin1Char(':'));
1186 const QString name = arguments.takeFirst().toLower();
1187 QString argumentsKey = name;
1188 argumentsKey[0] = argumentsKey.at(0).toUpper();
1189 arguments.append(QLibraryInfo::platformPluginArguments(argumentsKey));
1190
1191 // Create the platform integration.
1192 QGuiApplicationPrivate::platform_integration = QPlatformIntegrationFactory::create(name, arguments, argc, argv, platformPluginPath);
1193 if (Q_UNLIKELY(!QGuiApplicationPrivate::platform_integration)) {
1194 if (availablePlugins.contains(name)) {
1195 qCInfo(lcQpaPluginLoading).nospace().noquote()
1196 << "Could not load the Qt platform plugin \"" << name << "\" in \""
1197 << QDir::toNativeSeparators(platformPluginPath) << "\" even though it was found.";
1198 } else {
1199 qCWarning(lcQpaPluginLoading).nospace().noquote()
1200 << "Could not find the Qt platform plugin \"" << name << "\" in \""
1201 << QDir::toNativeSeparators(platformPluginPath) << "\"";
1202 }
1203 } else {
1204 QGuiApplicationPrivate::platform_name = new QString(name);
1205 platformArguments = arguments;
1206 break;
1207 }
1208 }
1209
1210 if (Q_UNLIKELY(!QGuiApplicationPrivate::platform_integration)) {
1211 QString fatalMessage = QStringLiteral("This application failed to start because no Qt platform plugin could be initialized. "
1212 "Reinstalling the application may fix this problem.\n");
1213
1214 if (!availablePlugins.isEmpty())
1215 fatalMessage += QStringLiteral("\nAvailable platform plugins are: %1.\n").arg(availablePlugins.join(QLatin1String(", ")));
1216
1217#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
1218 // Windows: Display message box unless it is a console application
1219 // or debug build showing an assert box.
1220 if (!QLibraryInfo::isDebugBuild() && !GetConsoleWindow())
1221 MessageBox(0, (LPCTSTR)fatalMessage.utf16(), (LPCTSTR)(QCoreApplication::applicationName().utf16()), MB_OK | MB_ICONERROR);
1222#endif // Q_OS_WIN && !Q_OS_WINRT
1223 qFatal("%s", qPrintable(fatalMessage));
1224
1225 return;
1226 }
1227
1228 // Many platforms have created QScreens at this point. Finish initializing
1229 // QHighDpiScaling to be prepared for early calls to qt_defaultDpi().
1230 if (QGuiApplication::primaryScreen()) {
1231 QGuiApplicationPrivate::highDpiScalingUpdated = true;
1232 QHighDpiScaling::updateHighDpiScaling();
1233 }
1234
1235 // Create the platform theme:
1236
1237 // 1) Fetch the platform name from the environment if present.
1238 QStringList themeNames;
1239 if (!platformThemeName.isEmpty())
1240 themeNames.append(platformThemeName);
1241
1242 // 2) Special case - check whether it's a flatpak or snap app to use xdg-desktop-portal platform theme for portals support
1243 if (checkNeedPortalSupport()) {
1244 themeNames.append(QStringLiteral("xdgdesktopportal"));
1245 }
1246
1247 // 3) Ask the platform integration for a list of theme names
1248 themeNames += QGuiApplicationPrivate::platform_integration->themeNames();
1249 // 4) Look for a theme plugin.
1250 for (const QString &themeName : qAsConst(themeNames)) {
1251 QGuiApplicationPrivate::platform_theme = QPlatformThemeFactory::create(themeName, platformPluginPath);
1252 if (QGuiApplicationPrivate::platform_theme)
1253 break;
1254 }
1255
1256 // 5) If no theme plugin was found ask the platform integration to
1257 // create a theme
1258 if (!QGuiApplicationPrivate::platform_theme) {
1259 for (const QString &themeName : qAsConst(themeNames)) {
1260 QGuiApplicationPrivate::platform_theme = QGuiApplicationPrivate::platform_integration->createPlatformTheme(themeName);
1261 if (QGuiApplicationPrivate::platform_theme)
1262 break;
1263 }
1264 // No error message; not having a theme plugin is allowed.
1265 }
1266
1267 // 6) Fall back on the built-in "null" platform theme.
1268 if (!QGuiApplicationPrivate::platform_theme)
1269 QGuiApplicationPrivate::platform_theme = new QPlatformTheme;
1270
1271#ifndef QT_NO_PROPERTIES
1272 // Set arguments as dynamic properties on the native interface as
1273 // boolean 'foo' or strings: 'foo=bar'
1274 if (!platformArguments.isEmpty()) {
1275 if (QObject *nativeInterface = QGuiApplicationPrivate::platform_integration->nativeInterface()) {
1276 for (const QString &argument : qAsConst(platformArguments)) {
1277 const int equalsPos = argument.indexOf(QLatin1Char('='));
1278 const QByteArray name =
1279 equalsPos != -1 ? argument.left(equalsPos).toUtf8() : argument.toUtf8();
1280 const QVariant value =
1281 equalsPos != -1 ? QVariant(argument.mid(equalsPos + 1)) : QVariant(true);
1282 nativeInterface->setProperty(name.constData(), value);
1283 }
1284 }
1285 }
1286#endif
1287
1288 fontSmoothingGamma = QGuiApplicationPrivate::platformIntegration()->styleHint(QPlatformIntegration::FontSmoothingGamma).toReal();
1289}
1290
1291static void init_plugins(const QList<QByteArray> &pluginList)
1292{
1293 for (int i = 0; i < pluginList.count(); ++i) {
1294 QByteArray pluginSpec = pluginList.at(i);
1295 int colonPos = pluginSpec.indexOf(':');
1296 QObject *plugin;
1297 if (colonPos < 0)
1298 plugin = QGenericPluginFactory::create(QLatin1String(pluginSpec), QString());
1299 else
1300 plugin = QGenericPluginFactory::create(QLatin1String(pluginSpec.mid(0, colonPos)),
1301 QLatin1String(pluginSpec.mid(colonPos+1)));
1302 if (plugin)
1303 QGuiApplicationPrivate::generic_plugin_list.append(plugin);
1304 else
1305 qWarning("No such plugin for spec \"%s\"", pluginSpec.constData());
1306 }
1307}
1308
1309#if QT_CONFIG(commandlineparser)
1310void QGuiApplicationPrivate::addQtOptions(QList<QCommandLineOption> *options)
1311{
1312 QCoreApplicationPrivate::addQtOptions(options);
1313
1314#if defined(Q_OS_UNIX) && !defined(Q_OS_DARWIN)
1315 const QByteArray sessionType = qgetenv("XDG_SESSION_TYPE");
1316 const bool x11 = sessionType == "x11";
1317 // Technically the x11 aliases are only available if platformName is "xcb", but we can't know that here.
1318#else
1319 const bool x11 = false;
1320#endif
1321
1322 options->append(QCommandLineOption(QStringLiteral("platform"),
1323 QGuiApplication::tr("QPA plugin. See QGuiApplication documentation for available options for each plugin."), QStringLiteral("platformName[:options]")));
1324 options->append(QCommandLineOption(QStringLiteral("platformpluginpath"),
1325 QGuiApplication::tr("Path to the platform plugins."), QStringLiteral("path")));
1326 options->append(QCommandLineOption(QStringLiteral("platformtheme"),
1327 QGuiApplication::tr("Platform theme."), QStringLiteral("theme")));
1328 options->append(QCommandLineOption(QStringLiteral("plugin"),
1329 QGuiApplication::tr("Additional plugins to load, can be specified multiple times."), QStringLiteral("plugin")));
1330 options->append(QCommandLineOption(QStringLiteral("qwindowgeometry"),
1331 QGuiApplication::tr("Window geometry for the main window, using the X11-syntax, like 100x100+50+50."), QStringLiteral("geometry")));
1332 options->append(QCommandLineOption(QStringLiteral("qwindowicon"),
1333 QGuiApplication::tr("Default window icon."), QStringLiteral("icon")));
1334 options->append(QCommandLineOption(QStringLiteral("qwindowtitle"),
1335 QGuiApplication::tr("Title of the first window."), QStringLiteral("title")));
1336 options->append(QCommandLineOption(QStringLiteral("reverse"),
1337 QGuiApplication::tr("Sets the application's layout direction to Qt::RightToLeft (debugging helper).")));
1338 options->append(QCommandLineOption(QStringLiteral("session"),
1339 QGuiApplication::tr("Restores the application from an earlier session."), QStringLiteral("session")));
1340
1341 if (x11) {
1342 options->append(QCommandLineOption(QStringLiteral("display"),
1343 QGuiApplication::tr("Display name, overrides $DISPLAY."), QStringLiteral("display")));
1344 options->append(QCommandLineOption(QStringLiteral("name"),
1345 QGuiApplication::tr("Instance name according to ICCCM 4.1.2.5."), QStringLiteral("name")));
1346 options->append(QCommandLineOption(QStringLiteral("nograb"),
1347 QGuiApplication::tr("Disable mouse grabbing (useful in debuggers).")));
1348 options->append(QCommandLineOption(QStringLiteral("dograb"),
1349 QGuiApplication::tr("Force mouse grabbing (even when running in a debugger).")));
1350 options->append(QCommandLineOption(QStringLiteral("visual"),
1351 QGuiApplication::tr("ID of the X11 Visual to use."), QStringLiteral("id")));
1352 // Not using the "QStringList names" solution for those aliases, because it makes the first column too wide
1353 options->append(QCommandLineOption(QStringLiteral("geometry"),
1354 QGuiApplication::tr("Alias for --windowgeometry."), QStringLiteral("geometry")));
1355 options->append(QCommandLineOption(QStringLiteral("icon"),
1356 QGuiApplication::tr("Alias for --windowicon."), QStringLiteral("icon")));
1357 options->append(QCommandLineOption(QStringLiteral("title"),
1358 QGuiApplication::tr("Alias for --windowtitle."), QStringLiteral("title")));
1359 }
1360}
1361#endif // QT_CONFIG(commandlineparser)
1362
1363void QGuiApplicationPrivate::createPlatformIntegration()
1364{
1365 QHighDpiScaling::initHighDpiScaling();
1366
1367 // Load the platform integration
1368 QString platformPluginPath = QString::fromLocal8Bit(qgetenv("QT_QPA_PLATFORM_PLUGIN_PATH"));
1369
1370
1371 QByteArray platformName;
1372#ifdef QT_QPA_DEFAULT_PLATFORM_NAME
1373 platformName = QT_QPA_DEFAULT_PLATFORM_NAME;
1374#endif
1375#if defined(Q_OS_UNIX) && !defined(Q_OS_DARWIN)
1376 QByteArray sessionType = qgetenv("XDG_SESSION_TYPE");
1377 if (!sessionType.isEmpty()) {
1378 if (sessionType == QByteArrayLiteral("x11") && !platformName.contains(QByteArrayLiteral("xcb"))) {
1379 platformName = QByteArrayLiteral("xcb");
1380 } else if (sessionType == QByteArrayLiteral("wayland") && !platformName.contains(QByteArrayLiteral("wayland"))) {
1381 QByteArray currentDesktop = qgetenv("XDG_CURRENT_DESKTOP").toLower();
1382 QByteArray sessionDesktop = qgetenv("XDG_SESSION_DESKTOP").toLower();
1383 if (currentDesktop.contains("gnome") || sessionDesktop.contains("gnome")) {
1384 qInfo() << "Warning: Ignoring XDG_SESSION_TYPE=wayland on Gnome."
1385 << "Use QT_QPA_PLATFORM=wayland to run on Wayland anyway.";
1386 } else {
1387 platformName = QByteArrayLiteral("wayland");
1388 }
1389 }
1390 }
1391#ifdef QT_QPA_DEFAULT_PLATFORM_NAME
1392 // Add it as fallback in case XDG_SESSION_TYPE is something wrong
1393 if (!platformName.contains(QT_QPA_DEFAULT_PLATFORM_NAME))
1394 platformName += QByteArrayLiteral(";" QT_QPA_DEFAULT_PLATFORM_NAME);
1395#endif
1396#endif
1397
1398 QByteArray platformNameEnv = qgetenv("QT_QPA_PLATFORM");
1399 if (!platformNameEnv.isEmpty()) {
1400 platformName = platformNameEnv;
1401 }
1402
1403 QString platformThemeName = QString::fromLocal8Bit(qgetenv("QT_QPA_PLATFORMTHEME"));
1404
1405 // Get command line params
1406
1407 QString icon;
1408
1409 int j = argc ? 1 : 0;
1410 for (int i=1; i<argc; i++) {
1411 if (!argv[i])
1412 continue;
1413 if (*argv[i] != '-') {
1414 argv[j++] = argv[i];
1415 continue;
1416 }
1417 const bool xcbIsDefault = platformName.startsWith("xcb");
1418 const char *arg = argv[i];
1419 if (arg[1] == '-') // startsWith("--")
1420 ++arg;
1421 if (strcmp(arg, "-platformpluginpath") == 0) {
1422 if (++i < argc)
1423 platformPluginPath = QString::fromLocal8Bit(argv[i]);
1424 } else if (strcmp(arg, "-platform") == 0) {
1425 if (++i < argc)
1426 platformName = argv[i];
1427 } else if (strcmp(arg, "-platformtheme") == 0) {
1428 if (++i < argc)
1429 platformThemeName = QString::fromLocal8Bit(argv[i]);
1430 } else if (strcmp(arg, "-qwindowgeometry") == 0 || (xcbIsDefault && strcmp(arg, "-geometry") == 0)) {
1431 if (++i < argc)
1432 windowGeometrySpecification = QWindowGeometrySpecification::fromArgument(argv[i]);
1433 } else if (strcmp(arg, "-qwindowtitle") == 0 || (xcbIsDefault && strcmp(arg, "-title") == 0)) {
1434 if (++i < argc)
1435 firstWindowTitle = QString::fromLocal8Bit(argv[i]);
1436 } else if (strcmp(arg, "-qwindowicon") == 0 || (xcbIsDefault && strcmp(arg, "-icon") == 0)) {
1437 if (++i < argc) {
1438 icon = QString::fromLocal8Bit(argv[i]);
1439 }
1440 } else {
1441 argv[j++] = argv[i];
1442 }
1443 }
1444
1445 if (j < argc) {
1446 argv[j] = 0;
1447 argc = j;
1448 }
1449
1450 init_platform(QLatin1String(platformName), platformPluginPath, platformThemeName, argc, argv);
1451
1452 if (!icon.isEmpty())
1453 forcedWindowIcon = QDir::isAbsolutePath(icon) ? QIcon(icon) : QIcon::fromTheme(icon);
1454}
1455
1456/*!
1457 Called from QCoreApplication::init()
1458
1459 Responsible for creating an event dispatcher when QCoreApplication
1460 decides that it needs one (because a custom one has not been set).
1461*/
1462void QGuiApplicationPrivate::createEventDispatcher()
1463{
1464 Q_ASSERT(!eventDispatcher);
1465
1466 if (platform_integration == 0)
1467 createPlatformIntegration();
1468
1469 // The platform integration should not mess with the event dispatcher
1470 Q_ASSERT(!eventDispatcher);
1471
1472 eventDispatcher = platform_integration->createEventDispatcher();
1473}
1474
1475void QGuiApplicationPrivate::eventDispatcherReady()
1476{
1477 if (platform_integration == 0)
1478 createPlatformIntegration();
1479
1480 platform_integration->initialize();
1481
1482 // All platforms should have added screens at this point. Finish
1483 // QHighDpiScaling initialization if it has not been done so already.
1484 if (!QGuiApplicationPrivate::highDpiScalingUpdated)
1485 QHighDpiScaling::updateHighDpiScaling();
1486}
1487
1488void QGuiApplicationPrivate::init()
1489{
1490 Q_TRACE_SCOPE(QGuiApplicationPrivate_init);
1491
1492#if defined(Q_OS_MACOS)
1493 QMacAutoReleasePool pool;
1494#endif
1495
1496 QCoreApplicationPrivate::init();
1497
1498 QCoreApplicationPrivate::is_app_running = false; // Starting up.
1499
1500 bool loadTestability = false;
1501 QList<QByteArray> pluginList;
1502 // Get command line params
1503#ifndef QT_NO_SESSIONMANAGER
1504 QString session_id;
1505 QString session_key;
1506# if defined(Q_OS_WIN)
1507 wchar_t guidstr[40];
1508 GUID guid;
1509 CoCreateGuid(&guid);
1510 StringFromGUID2(guid, guidstr, 40);
1511 session_id = QString::fromWCharArray(guidstr);
1512 CoCreateGuid(&guid);
1513 StringFromGUID2(guid, guidstr, 40);
1514 session_key = QString::fromWCharArray(guidstr);
1515# endif
1516#endif
1517 QString s;
1518 int j = argc ? 1 : 0;
1519 for (int i=1; i<argc; i++) {
1520 if (!argv[i])
1521 continue;
1522 if (*argv[i] != '-') {
1523 argv[j++] = argv[i];
1524 continue;
1525 }
1526 const char *arg = argv[i];
1527 if (arg[1] == '-') // startsWith("--")
1528 ++arg;
1529 if (strcmp(arg, "-plugin") == 0) {
1530 if (++i < argc)
1531 pluginList << argv[i];
1532 } else if (strcmp(arg, "-reverse") == 0) {
1533 force_reverse = true;
1534#ifdef Q_OS_MAC
1535 } else if (strncmp(arg, "-psn_", 5) == 0) {
1536 // eat "-psn_xxxx" on Mac, which is passed when starting an app from Finder.
1537 // special hack to change working directory (for an app bundle) when running from finder
1538 if (QDir::currentPath() == QLatin1String("/")) {
1539 QCFType<CFURLRef> bundleURL(CFBundleCopyBundleURL(CFBundleGetMainBundle()));
1540 QString qbundlePath = QCFString(CFURLCopyFileSystemPath(bundleURL,
1541 kCFURLPOSIXPathStyle));
1542 if (qbundlePath.endsWith(QLatin1String(".app")))
1543 QDir::setCurrent(qbundlePath.section(QLatin1Char('/'), 0, -2));
1544 }
1545#endif
1546#ifndef QT_NO_SESSIONMANAGER
1547 } else if (strcmp(arg, "-session") == 0 && i < argc - 1) {
1548 ++i;
1549 if (argv[i] && *argv[i]) {
1550 session_id = QString::fromLatin1(argv[i]);
1551 int p = session_id.indexOf(QLatin1Char('_'));
1552 if (p >= 0) {
1553 session_key = session_id.mid(p +1);
1554 session_id = session_id.left(p);
1555 }
1556 is_session_restored = true;
1557 }
1558#endif
1559 } else if (strcmp(arg, "-testability") == 0) {
1560 loadTestability = true;
1561 } else if (strncmp(arg, "-style=", 7) == 0) {
1562 s = QString::fromLocal8Bit(arg + 7);
1563 } else if (strcmp(arg, "-style") == 0 && i < argc - 1) {
1564 s = QString::fromLocal8Bit(argv[++i]);
1565 } else {
1566 argv[j++] = argv[i];
1567 }
1568
1569 if (!s.isEmpty())
1570 styleOverride = s;
1571 }
1572
1573 if (j < argc) {
1574 argv[j] = 0;
1575 argc = j;
1576 }
1577
1578 // Load environment exported generic plugins
1579 QByteArray envPlugins = qgetenv("QT_QPA_GENERIC_PLUGINS");
1580 if (!envPlugins.isEmpty())
1581 pluginList += envPlugins.split(',');
1582
1583 if (platform_integration == 0)
1584 createPlatformIntegration();
1585
1586 initPalette();
1587 QFont::initialize();
1588 initThemeHints();
1589
1590#ifndef QT_NO_CURSOR
1591 QCursorData::initialize();
1592#endif
1593
1594 // trigger registering of QVariant's GUI types
1595 qRegisterGuiVariant();
1596
1597#if QT_CONFIG(animation)
1598 // trigger registering of animation interpolators
1599 qRegisterGuiGetInterpolator();
1600#endif
1601
1602 // set a global share context when enabled unless there is already one
1603#ifndef QT_NO_OPENGL
1604 if (qApp->testAttribute(Qt::AA_ShareOpenGLContexts) && !qt_gl_global_share_context()) {
1605 QOpenGLContext *ctx = new QOpenGLContext;
1606 ctx->setFormat(QSurfaceFormat::defaultFormat());
1607 ctx->create();
1608 qt_gl_set_global_share_context(ctx);
1609 ownGlobalShareContext = true;
1610 }
1611#endif
1612
1613 QWindowSystemInterfacePrivate::eventTime.start();
1614
1615 is_app_running = true;
1616 init_plugins(pluginList);
1617 QWindowSystemInterface::flushWindowSystemEvents();
1618
1619 Q_Q(QGuiApplication);
1620#ifndef QT_NO_SESSIONMANAGER
1621 // connect to the session manager
1622 session_manager = new QSessionManager(q, session_id, session_key);
1623#endif
1624
1625#if QT_CONFIG(library)
1626 if (qEnvironmentVariableIntValue("QT_LOAD_TESTABILITY") > 0)
1627 loadTestability = true;
1628
1629 if (loadTestability) {
1630 QLibrary testLib(QStringLiteral("qttestability"));
1631 if (Q_UNLIKELY(!testLib.load())) {
1632 qCritical() << "Library qttestability load failed:" << testLib.errorString();
1633 } else {
1634 typedef void (*TasInitialize)(void);
1635 TasInitialize initFunction = (TasInitialize)testLib.resolve("qt_testability_init");
1636 if (Q_UNLIKELY(!initFunction)) {
1637 qCritical("Library qttestability resolve failed!");
1638 } else {
1639 initFunction();
1640 }
1641 }
1642 }
1643#else
1644 Q_UNUSED(loadTestability);
1645#endif // QT_CONFIG(library)
1646
1647 if (layout_direction == Qt::LayoutDirectionAuto || force_reverse)
1648 QGuiApplication::setLayoutDirection(qt_detectRTLLanguage() ? Qt::RightToLeft : Qt::LeftToRight);
1649
1650 if (!QGuiApplicationPrivate::displayName)
1651 QObject::connect(q, &QGuiApplication::applicationNameChanged,
1652 q, &QGuiApplication::applicationDisplayNameChanged);
1653}
1654
1655extern void qt_cleanupFontDatabase();
1656
1657QGuiApplicationPrivate::~QGuiApplicationPrivate()
1658{
1659 is_app_closing = true;
1660 is_app_running = false;
1661
1662 for (int i = 0; i < generic_plugin_list.count(); ++i)
1663 delete generic_plugin_list.at(i);
1664 generic_plugin_list.clear();
1665
1666 clearFontUnlocked();
1667
1668 QFont::cleanup();
1669
1670#ifndef QT_NO_CURSOR
1671 QCursorData::cleanup();
1672#endif
1673
1674 layout_direction = Qt::LeftToRight;
1675
1676 cleanupThreadData();
1677
1678 delete QGuiApplicationPrivate::styleHints;
1679 QGuiApplicationPrivate::styleHints = nullptr;
1680 delete inputMethod;
1681
1682 qt_cleanupFontDatabase();
1683
1684 QPixmapCache::clear();
1685
1686#ifndef QT_NO_OPENGL
1687 if (ownGlobalShareContext) {
1688 delete qt_gl_global_share_context();
1689 qt_gl_set_global_share_context(0);
1690 }
1691#endif
1692#ifdef Q_OS_WASM
1693 EM_ASM(
1694 // unmount persistent directory as IDBFS
1695 // see QTBUG-70002
1696 FS.unmount('/home/web_user');
1697 );
1698#endif
1699 platform_integration->destroy();
1700
1701 delete platform_theme;
1702 platform_theme = 0;
1703 delete platform_integration;
1704 platform_integration = 0;
1705
1706 window_list.clear();
1707 screen_list.clear();
1708}
1709
1710#if 0
1711#ifndef QT_NO_CURSOR
1712QCursor *overrideCursor();
1713void setOverrideCursor(const QCursor &);
1714void changeOverrideCursor(const QCursor &);
1715void restoreOverrideCursor();
1716#endif
1717
1718static QFont font();
1719static QFont font(const QWidget*);
1720static QFont font(const char *className);
1721static void setFont(const QFont &, const char* className = 0);
1722static QFontMetrics fontMetrics();
1723
1724#ifndef QT_NO_CLIPBOARD
1725static QClipboard *clipboard();
1726#endif
1727#endif
1728
1729/*!
1730 Returns the current state of the modifier keys on the keyboard. The current
1731 state is updated sychronously as the event queue is emptied of events that
1732 will spontaneously change the keyboard state (QEvent::KeyPress and
1733 QEvent::KeyRelease events).
1734
1735 It should be noted this may not reflect the actual keys held on the input
1736 device at the time of calling but rather the modifiers as last reported in
1737 one of the above events. If no keys are being held Qt::NoModifier is
1738 returned.
1739
1740 \sa mouseButtons(), queryKeyboardModifiers()
1741*/
1742Qt::KeyboardModifiers QGuiApplication::keyboardModifiers()
1743{
1744 return QGuiApplicationPrivate::modifier_buttons;
1745}
1746
1747/*!
1748 \fn Qt::KeyboardModifiers QGuiApplication::queryKeyboardModifiers()
1749
1750 Queries and returns the state of the modifier keys on the keyboard.
1751 Unlike keyboardModifiers, this method returns the actual keys held
1752 on the input device at the time of calling the method.
1753
1754 It does not rely on the keypress events having been received by this
1755 process, which makes it possible to check the modifiers while moving
1756 a window, for instance. Note that in most cases, you should use
1757 keyboardModifiers(), which is faster and more accurate since it contains
1758 the state of the modifiers as they were when the currently processed
1759 event was received.
1760
1761 \sa keyboardModifiers()
1762*/
1763Qt::KeyboardModifiers QGuiApplication::queryKeyboardModifiers()
1764{
1765 CHECK_QAPP_INSTANCE(Qt::KeyboardModifiers(0))
1766 QPlatformIntegration *pi = QGuiApplicationPrivate::platformIntegration();
1767 return pi->queryKeyboardModifiers();
1768}
1769
1770/*!
1771 Returns the current state of the buttons on the mouse. The current state is
1772 updated synchronously as the event queue is emptied of events that will
1773 spontaneously change the mouse state (QEvent::MouseButtonPress and
1774 QEvent::MouseButtonRelease events).
1775
1776 It should be noted this may not reflect the actual buttons held on the
1777 input device at the time of calling but rather the mouse buttons as last
1778 reported in one of the above events. If no mouse buttons are being held
1779 Qt::NoButton is returned.
1780
1781 \sa keyboardModifiers()
1782*/
1783Qt::MouseButtons QGuiApplication::mouseButtons()
1784{
1785 return QGuiApplicationPrivate::mouse_buttons;
1786}
1787
1788/*!
1789 Returns the platform's native interface, for platform specific
1790 functionality.
1791*/
1792QPlatformNativeInterface *QGuiApplication::platformNativeInterface()
1793{
1794 QPlatformIntegration *pi = QGuiApplicationPrivate::platformIntegration();
1795 return pi ? pi->nativeInterface() : 0;
1796}
1797
1798/*!
1799 Returns a function pointer from the platformplugin matching \a function
1800*/
1801QFunctionPointer QGuiApplication::platformFunction(const QByteArray &function)
1802{
1803 QPlatformIntegration *pi = QGuiApplicationPrivate::platformIntegration();
1804 if (!pi) {
1805 qWarning("QGuiApplication::platformFunction(): Must construct a QGuiApplication before accessing a platform function");
1806 return nullptr;
1807 }
1808
1809 return pi->nativeInterface() ? pi->nativeInterface()->platformFunction(function) : nullptr;
1810}
1811
1812/*!
1813 Enters the main event loop and waits until exit() is called, and then
1814 returns the value that was set to exit() (which is 0 if exit() is called
1815 via quit()).
1816
1817 It is necessary to call this function to start event handling. The main
1818 event loop receives events from the window system and dispatches these to
1819 the application widgets.
1820
1821 Generally, no user interaction can take place before calling exec().
1822
1823 To make your application perform idle processing, e.g., executing a special
1824 function whenever there are no pending events, use a QTimer with 0 timeout.
1825 More advanced idle processing schemes can be achieved using processEvents().
1826
1827 We recommend that you connect clean-up code to the
1828 \l{QCoreApplication::}{aboutToQuit()} signal, instead of putting it in your
1829 application's \c{main()} function. This is because, on some platforms, the
1830 QApplication::exec() call may not return.
1831
1832 \sa quitOnLastWindowClosed, quit(), exit(), processEvents(),
1833 QCoreApplication::exec()
1834*/
1835int QGuiApplication::exec()
1836{
1837#ifndef QT_NO_ACCESSIBILITY
1838 QAccessible::setRootObject(qApp);
1839#endif
1840 return QCoreApplication::exec();
1841}
1842
1843/*! \reimp
1844*/
1845bool QGuiApplication::notify(QObject *object, QEvent *event)
1846{
1847 if (object->isWindowType()) {
1848 if (QGuiApplicationPrivate::sendQWindowEventToQPlatformWindow(static_cast<QWindow *>(object), event))
1849 return true; // Platform plugin ate the event
1850 }
1851
1852 return QCoreApplication::notify(object, event);
1853}
1854
1855/*! \reimp
1856*/
1857bool QGuiApplication::event(QEvent *e)
1858{
1859 if(e->type() == QEvent::LanguageChange) {
1860 setLayoutDirection(qt_detectRTLLanguage()?Qt::RightToLeft:Qt::LeftToRight);
1861 }
1862 return QCoreApplication::event(e);
1863}
1864
1865/*!
1866 \internal
1867*/
1868bool QGuiApplication::compressEvent(QEvent *event, QObject *receiver, QPostEventList *postedEvents)
1869{
1870 return QCoreApplication::compressEvent(event, receiver, postedEvents);
1871}
1872
1873bool QGuiApplicationPrivate::sendQWindowEventToQPlatformWindow(QWindow *window, QEvent *event)
1874{
1875 if (!window)
1876 return false;
1877 QPlatformWindow *platformWindow = window->handle();
1878 if (!platformWindow)
1879 return false;
1880 // spontaneous events come from the platform integration already, we don't need to send the events back
1881 if (event->spontaneous())
1882 return false;
1883 // let the platform window do any handling it needs to as well
1884 return platformWindow->windowEvent(event);
1885}
1886
1887#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
1888bool QGuiApplicationPrivate::processNativeEvent(QWindow *window, const QByteArray &eventType, void *message, qintptr *result)
1889#else
1890bool QGuiApplicationPrivate::processNativeEvent(QWindow *window, const QByteArray &eventType, void *message, long *result)
1891#endif
1892{
1893 return window->nativeEvent(eventType, message, result);
1894}
1895
1896void QGuiApplicationPrivate::processWindowSystemEvent(QWindowSystemInterfacePrivate::WindowSystemEvent *e)
1897{
1898 Q_TRACE_SCOPE(QGuiApplicationPrivate_processWindowSystemEvent, e->type);
1899
1900 switch(e->type) {
1901 case QWindowSystemInterfacePrivate::Mouse:
1902 QGuiApplicationPrivate::processMouseEvent(static_cast<QWindowSystemInterfacePrivate::MouseEvent *>(e));
1903 break;
1904 case QWindowSystemInterfacePrivate::Wheel:
1905 QGuiApplicationPrivate::processWheelEvent(static_cast<QWindowSystemInterfacePrivate::WheelEvent *>(e));
1906 break;
1907 case QWindowSystemInterfacePrivate::Key:
1908 QGuiApplicationPrivate::processKeyEvent(static_cast<QWindowSystemInterfacePrivate::KeyEvent *>(e));
1909 break;
1910 case QWindowSystemInterfacePrivate::Touch:
1911 QGuiApplicationPrivate::processTouchEvent(static_cast<QWindowSystemInterfacePrivate::TouchEvent *>(e));
1912 break;
1913 case QWindowSystemInterfacePrivate::GeometryChange:
1914 QGuiApplicationPrivate::processGeometryChangeEvent(static_cast<QWindowSystemInterfacePrivate::GeometryChangeEvent*>(e));
1915 break;
1916 case QWindowSystemInterfacePrivate::Enter:
1917 QGuiApplicationPrivate::processEnterEvent(static_cast<QWindowSystemInterfacePrivate::EnterEvent *>(e));
1918 break;
1919 case QWindowSystemInterfacePrivate::Leave:
1920 QGuiApplicationPrivate::processLeaveEvent(static_cast<QWindowSystemInterfacePrivate::LeaveEvent *>(e));
1921 break;
1922 case QWindowSystemInterfacePrivate::ActivatedWindow:
1923 QGuiApplicationPrivate::processActivatedEvent(static_cast<QWindowSystemInterfacePrivate::ActivatedWindowEvent *>(e));
1924 break;
1925 case QWindowSystemInterfacePrivate::WindowStateChanged:
1926 QGuiApplicationPrivate::processWindowStateChangedEvent(static_cast<QWindowSystemInterfacePrivate::WindowStateChangedEvent *>(e));
1927 break;
1928 case QWindowSystemInterfacePrivate::WindowScreenChanged:
1929 QGuiApplicationPrivate::processWindowScreenChangedEvent(static_cast<QWindowSystemInterfacePrivate::WindowScreenChangedEvent *>(e));
1930 break;
1931 case QWindowSystemInterfacePrivate::SafeAreaMarginsChanged:
1932 QGuiApplicationPrivate::processSafeAreaMarginsChangedEvent(static_cast<QWindowSystemInterfacePrivate::SafeAreaMarginsChangedEvent *>(e));
1933 break;
1934 case QWindowSystemInterfacePrivate::ApplicationStateChanged: {
1935 QWindowSystemInterfacePrivate::ApplicationStateChangedEvent * changeEvent = static_cast<QWindowSystemInterfacePrivate::ApplicationStateChangedEvent *>(e);
1936 QGuiApplicationPrivate::setApplicationState(changeEvent->newState, changeEvent->forcePropagate); }
1937 break;
1938 case QWindowSystemInterfacePrivate::FlushEvents: {
1939 QWindowSystemInterfacePrivate::FlushEventsEvent *flushEventsEvent = static_cast<QWindowSystemInterfacePrivate::FlushEventsEvent *>(e);
1940 QWindowSystemInterface::deferredFlushWindowSystemEvents(flushEventsEvent->flags); }
1941 break;
1942 case QWindowSystemInterfacePrivate::Close:
1943 QGuiApplicationPrivate::processCloseEvent(
1944 static_cast<QWindowSystemInterfacePrivate::CloseEvent *>(e));
1945 break;
1946 case QWindowSystemInterfacePrivate::ScreenOrientation:
1947 QGuiApplicationPrivate::processScreenOrientationChange(
1948 static_cast<QWindowSystemInterfacePrivate::ScreenOrientationEvent *>(e));
1949 break;
1950 case QWindowSystemInterfacePrivate::ScreenGeometry:
1951 QGuiApplicationPrivate::processScreenGeometryChange(
1952 static_cast<QWindowSystemInterfacePrivate::ScreenGeometryEvent *>(e));
1953 break;
1954 case QWindowSystemInterfacePrivate::ScreenLogicalDotsPerInch:
1955 QGuiApplicationPrivate::processScreenLogicalDotsPerInchChange(
1956 static_cast<QWindowSystemInterfacePrivate::ScreenLogicalDotsPerInchEvent *>(e));
1957 break;
1958 case QWindowSystemInterfacePrivate::ScreenRefreshRate:
1959 QGuiApplicationPrivate::processScreenRefreshRateChange(
1960 static_cast<QWindowSystemInterfacePrivate::ScreenRefreshRateEvent *>(e));
1961 break;
1962 case QWindowSystemInterfacePrivate::ThemeChange:
1963 QGuiApplicationPrivate::processThemeChanged(
1964 static_cast<QWindowSystemInterfacePrivate::ThemeChangeEvent *>(e));
1965 break;
1966 case QWindowSystemInterfacePrivate::Expose:
1967 QGuiApplicationPrivate::processExposeEvent(static_cast<QWindowSystemInterfacePrivate::ExposeEvent *>(e));
1968 break;
1969 case QWindowSystemInterfacePrivate::Tablet:
1970 QGuiApplicationPrivate::processTabletEvent(
1971 static_cast<QWindowSystemInterfacePrivate::TabletEvent *>(e));
1972 break;
1973 case QWindowSystemInterfacePrivate::TabletEnterProximity:
1974 QGuiApplicationPrivate::processTabletEnterProximityEvent(
1975 static_cast<QWindowSystemInterfacePrivate::TabletEnterProximityEvent *>(e));
1976 break;
1977 case QWindowSystemInterfacePrivate::TabletLeaveProximity:
1978 QGuiApplicationPrivate::processTabletLeaveProximityEvent(
1979 static_cast<QWindowSystemInterfacePrivate::TabletLeaveProximityEvent *>(e));
1980 break;
1981#ifndef QT_NO_GESTURES
1982 case QWindowSystemInterfacePrivate::Gesture:
1983 QGuiApplicationPrivate::processGestureEvent(
1984 static_cast<QWindowSystemInterfacePrivate::GestureEvent *>(e));
1985 break;
1986#endif
1987 case QWindowSystemInterfacePrivate::PlatformPanel:
1988 QGuiApplicationPrivate::processPlatformPanelEvent(
1989 static_cast<QWindowSystemInterfacePrivate::PlatformPanelEvent *>(e));
1990 break;
1991 case QWindowSystemInterfacePrivate::FileOpen:
1992 QGuiApplicationPrivate::processFileOpenEvent(
1993 static_cast<QWindowSystemInterfacePrivate::FileOpenEvent *>(e));
1994 break;
1995#ifndef QT_NO_CONTEXTMENU
1996 case QWindowSystemInterfacePrivate::ContextMenu:
1997 QGuiApplicationPrivate::processContextMenuEvent(
1998 static_cast<QWindowSystemInterfacePrivate::ContextMenuEvent *>(e));
1999 break;
2000#endif
2001 case QWindowSystemInterfacePrivate::EnterWhatsThisMode:
2002 QGuiApplication::postEvent(QGuiApplication::instance(), new QEvent(QEvent::EnterWhatsThisMode));
2003 break;
2004 default:
2005 qWarning() << "Unknown user input event type:" << e->type;
2006 break;
2007 }
2008}
2009
2010/*! \internal
2011
2012 History is silent on why Qt splits mouse events that change position and
2013 button state at the same time. We believe that this was done to emulate mouse
2014 behavior on touch screens. If mouse tracking is enabled, we will get move
2015 events before the button is pressed. A touch panel does not generally give
2016 move events when not pressed, so without event splitting code path we would
2017 only see a press in a new location without any intervening moves. This could
2018 confuse code that is written for a real mouse. The same is true for mouse
2019 release events that change position, see tst_QWidget::touchEventSynthesizedMouseEvent()
2020 and tst_QWindow::generatedMouseMove() auto tests.
2021*/
2022void QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::MouseEvent *e)
2023{
2024 QEvent::Type type = QEvent::None;
2025 Qt::MouseButton button = Qt::NoButton;
2026 QWindow *window = e->window.data();
2027 bool positionChanged = QGuiApplicationPrivate::lastCursorPosition != e->globalPos;
2028 bool mouseMove = false;
2029 bool mousePress = false;
2030
2031 if (e->enhancedMouseEvent()) {
2032 type = e->buttonType;
2033 button = e->button;
2034
2035 if (type == QEvent::NonClientAreaMouseMove || type == QEvent::MouseMove)
2036 mouseMove = true;
2037 else if (type == QEvent::NonClientAreaMouseButtonPress || type == QEvent::MouseButtonPress)
2038 mousePress = true;
2039
2040 if (!mouseMove && positionChanged) {
2041 QWindowSystemInterfacePrivate::MouseEvent moveEvent(window, e->timestamp,
2042 e->localPos, e->globalPos, e->buttons ^ button, e->modifiers, Qt::NoButton,
2043 e->nonClientArea ? QEvent::NonClientAreaMouseMove : QEvent::MouseMove,
2044 e->source, e->nonClientArea);
2045 if (e->synthetic())
2046 moveEvent.flags |= QWindowSystemInterfacePrivate::WindowSystemEvent::Synthetic;
2047 processMouseEvent(&moveEvent); // mouse move excluding state change
2048 processMouseEvent(e); // the original mouse event
2049 return;
2050 }
2051 } else {
2052 Qt::MouseButtons stateChange = e->buttons ^ mouse_buttons;
2053 if (positionChanged && (stateChange != Qt::NoButton)) {
2054 QWindowSystemInterfacePrivate::MouseEvent moveEvent(window, e->timestamp, e->localPos,
2055 e->globalPos, mouse_buttons, e->modifiers, Qt::NoButton, QEvent::None, e->source,
2056 e->nonClientArea);
2057 if (e->synthetic())
2058 moveEvent.flags |= QWindowSystemInterfacePrivate::WindowSystemEvent::Synthetic;
2059 processMouseEvent(&moveEvent); // mouse move excluding state change
2060 processMouseEvent(e); // the original mouse event
2061 return;
2062 }
2063
2064 // In the compatibility path we deduce event type and button that caused the event
2065 if (positionChanged) {
2066 mouseMove = true;
2067 type = e->nonClientArea ? QEvent::NonClientAreaMouseMove : QEvent::MouseMove;
2068 } else {
2069 // Check to see if a new button has been pressed/released.
2070 for (uint mask = Qt::LeftButton; mask <= Qt::MaxMouseButton; mask <<= 1) {
2071 if (stateChange & mask) {
2072 button = Qt::MouseButton(mask);
2073 break;
2074 }
2075 }
2076 if (button == Qt::NoButton) {
2077 // Ignore mouse events that don't change the current state. This shouldn't
2078 // really happen, getting here can only mean that the stored button state
2079 // is out of sync with the actual physical button state.
2080 return;
2081 }
2082 if (button & e->buttons) {
2083 mousePress = true;
2084 type = e->nonClientArea ? QEvent::NonClientAreaMouseButtonPress
2085 : QEvent::MouseButtonPress;
2086 } else {
2087 type = e->nonClientArea ? QEvent::NonClientAreaMouseButtonRelease
2088 : QEvent::MouseButtonRelease;
2089 }
2090 }
2091 }
2092
2093 modifier_buttons = e->modifiers;
2094 QPointF localPoint = e->localPos;
2095 QPointF globalPoint = e->globalPos;
2096 bool doubleClick = false;
2097
2098 if (mouseMove) {
2099 QGuiApplicationPrivate::lastCursorPosition = globalPoint;
2100 const auto doubleClickDistance = e->source == Qt::MouseEventNotSynthesized ?
2101 mouseDoubleClickDistance : touchDoubleTapDistance;
2102 if (qAbs(globalPoint.x() - mousePressX) > doubleClickDistance ||
2103 qAbs(globalPoint.y() - mousePressY) > doubleClickDistance)
2104 mousePressButton = Qt::NoButton;
2105 } else {
2106 mouse_buttons = e->buttons;
2107 if (mousePress) {
2108 ulong doubleClickInterval = static_cast<ulong>(QGuiApplication::styleHints()->mouseDoubleClickInterval());
2109 doubleClick = e->timestamp - mousePressTime < doubleClickInterval && button == mousePressButton;
2110 mousePressTime = e->timestamp;
2111 mousePressButton = button;
2112 const QPoint point = QGuiApplicationPrivate::lastCursorPosition.toPoint();
2113 mousePressX = point.x();
2114 mousePressY = point.y();
2115 }
2116 }
2117
2118 if (e->nullWindow()) {
2119 window = QGuiApplication::topLevelAt(globalPoint.toPoint());
2120 if (window) {
2121 // Moves and the release following a press must go to the same
2122 // window, even if the cursor has moved on over another window.
2123 if (e->buttons != Qt::NoButton) {
2124 if (!currentMousePressWindow)
2125 currentMousePressWindow = window;
2126 else
2127 window = currentMousePressWindow;
2128 } else if (currentMousePressWindow) {
2129 window = currentMousePressWindow;
2130 currentMousePressWindow = 0;
2131 }
2132 QPointF delta = globalPoint - globalPoint.toPoint();
2133 localPoint = window->mapFromGlobal(globalPoint.toPoint()) + delta;
2134 }
2135 }
2136
2137 if (!window)
2138 return;
2139
2140#ifndef QT_NO_CURSOR
2141 if (!e->synthetic()) {
2142 if (const QScreen *screen = window->screen())
2143 if (QPlatformCursor *cursor = screen->handle()->cursor()) {
2144 const QPointF nativeLocalPoint = QHighDpi::toNativePixels(localPoint, screen);
2145 const QPointF nativeGlobalPoint = QHighDpi::toNativePixels(globalPoint, screen);
2146 QMouseEvent ev(type, nativeLocalPoint, nativeLocalPoint, nativeGlobalPoint,
2147 button, e->buttons, e->modifiers, e->source);
2148 ev.setTimestamp(e->timestamp);
2149 cursor->pointerEvent(ev);
2150 }
2151 }
2152#endif
2153
2154 QMouseEvent ev(type, localPoint, localPoint, globalPoint, button, e->buttons, e->modifiers, e->source);
2155 ev.setTimestamp(e->timestamp);
2156
2157 if (window->d_func()->blockedByModalWindow && !qApp->d_func()->popupActive()) {
2158 // a modal window is blocking this window, don't allow mouse events through
2159 return;
2160 }
2161
2162 if (doubleClick && (ev.type() == QEvent::MouseButtonPress)) {
2163 // QtBUG-25831, used to suppress delivery in qwidgetwindow.cpp
2164 setMouseEventFlags(&ev, ev.flags() | Qt::MouseEventCreatedDoubleClick);
2165 }
2166
2167 QGuiApplication::sendSpontaneousEvent(window, &ev);
2168 e->eventAccepted = ev.isAccepted();
2169 if (!e->synthetic() && !ev.isAccepted()
2170 && !e->nonClientArea
2171 && qApp->testAttribute(Qt::AA_SynthesizeTouchForUnhandledMouseEvents)) {
2172 if (!m_fakeTouchDevice) {
2173 m_fakeTouchDevice = new QTouchDevice;
2174 QWindowSystemInterface::registerTouchDevice(m_fakeTouchDevice);
2175 }
2176 QList<QWindowSystemInterface::TouchPoint> points;
2177 QWindowSystemInterface::TouchPoint point;
2178 point.id = 1;
2179 point.area = QRectF(globalPoint.x() - 2, globalPoint.y() - 2, 4, 4);
2180
2181 // only translate left button related events to
2182 // avoid strange touch event sequences when several
2183 // buttons are pressed
2184 if (type == QEvent::MouseButtonPress && button == Qt::LeftButton) {
2185 point.state = Qt::TouchPointPressed;
2186 } else if (type == QEvent::MouseButtonRelease && button == Qt::LeftButton) {
2187 point.state = Qt::TouchPointReleased;
2188 } else if (type == QEvent::MouseMove && (e->buttons & Qt::LeftButton)) {
2189 point.state = Qt::TouchPointMoved;
2190 } else {
2191 return;
2192 }
2193
2194 points << point;
2195
2196 QEvent::Type type;
2197 QList<QTouchEvent::TouchPoint> touchPoints =
2198 QWindowSystemInterfacePrivate::fromNativeTouchPoints(points, window, QTouchDevicePrivate::get(m_fakeTouchDevice)->id, &type);
2199
2200 QWindowSystemInterfacePrivate::TouchEvent fake(window, e->timestamp, type, m_fakeTouchDevice, touchPoints, e->modifiers);
2201 fake.flags |= QWindowSystemInterfacePrivate::WindowSystemEvent::Synthetic;
2202 processTouchEvent(&fake);
2203 }
2204 if (doubleClick) {
2205 mousePressButton = Qt::NoButton;
2206 if (!e->window.isNull() || e->nullWindow()) { // QTBUG-36364, check if window closed in response to press
2207 const QEvent::Type doubleClickType = e->nonClientArea ? QEvent::NonClientAreaMouseButtonDblClick : QEvent::MouseButtonDblClick;
2208 QMouseEvent dblClickEvent(doubleClickType, localPoint, localPoint, globalPoint,
2209 button, e->buttons, e->modifiers, e->source);
2210 dblClickEvent.setTimestamp(e->timestamp);
2211 QGuiApplication::sendSpontaneousEvent(window, &dblClickEvent);
2212 }
2213 }
2214}
2215
2216void QGuiApplicationPrivate::processWheelEvent(QWindowSystemInterfacePrivate::WheelEvent *e)
2217{
2218#if QT_CONFIG(wheelevent)
2219 QWindow *window = e->window.data();
2220 QPointF globalPoint = e->globalPos;
2221 QPointF localPoint = e->localPos;
2222
2223 if (e->nullWindow()) {
2224 window = QGuiApplication::topLevelAt(globalPoint.toPoint());
2225 if (window) {
2226 QPointF delta = globalPoint - globalPoint.toPoint();
2227 localPoint = window->mapFromGlobal(globalPoint.toPoint()) + delta;
2228 }
2229 }
2230
2231 if (!window)
2232 return;
2233
2234 QGuiApplicationPrivate::lastCursorPosition = globalPoint;
2235 modifier_buttons = e->modifiers;
2236
2237 if (window->d_func()->blockedByModalWindow) {
2238 // a modal window is blocking this window, don't allow wheel events through
2239 return;
2240 }
2241
2242#if QT_DEPRECATED_SINCE(5, 14)
2243 QWheelEvent ev(localPoint, globalPoint, e->pixelDelta, e->angleDelta, e->qt4Delta, e->qt4Orientation,
2244 mouse_buttons, e->modifiers, e->phase, e->source, e->inverted);
2245#else
2246 QWheelEvent ev(localPoint, globalPoint, e->pixelDelta, e->angleDelta,
2247 mouse_buttons, e->modifiers, e->phase, e->inverted, e->source);
2248#endif
2249 ev.setTimestamp(e->timestamp);
2250 QGuiApplication::sendSpontaneousEvent(window, &ev);
2251#else
2252 Q_UNUSED(e);
2253#endif // QT_CONFIG(wheelevent)
2254}
2255
2256void QGuiApplicationPrivate::processKeyEvent(QWindowSystemInterfacePrivate::KeyEvent *e)
2257{
2258 QWindow *window = e->window.data();
2259 modifier_buttons = e->modifiers;
2260 if (e->nullWindow()
2261#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED)
2262 || e->key == Qt::Key_Back || e->key == Qt::Key_Menu
2263#endif
2264 ) {
2265 window = QGuiApplication::focusWindow();
2266 }
2267
2268#if defined(Q_OS_ANDROID)
2269 static bool backKeyPressAccepted = false;
2270 static bool menuKeyPressAccepted = false;
2271#endif
2272
2273#if !defined(Q_OS_OSX)
2274 // FIXME: Include OS X in this code path by passing the key event through
2275 // QPlatformInputContext::filterEvent().
2276 if (e->keyType == QEvent::KeyPress && window) {
2277 if (QWindowSystemInterface::handleShortcutEvent(window, e->timestamp, e->key, e->modifiers,
2278 e->nativeScanCode, e->nativeVirtualKey, e->nativeModifiers, e->unicode, e->repeat, e->repeatCount)) {
2279#if defined(Q_OS_ANDROID)
2280 backKeyPressAccepted = e->key == Qt::Key_Back;
2281 menuKeyPressAccepted = e->key == Qt::Key_Menu;
2282#endif
2283 return;
2284 }
2285 }
2286#endif
2287
2288 QKeyEvent ev(e->keyType, e->key, e->modifiers,
2289 e->nativeScanCode, e->nativeVirtualKey, e->nativeModifiers,
2290 e->unicode, e->repeat, e->repeatCount);
2291 ev.setTimestamp(e->timestamp);
2292
2293 // only deliver key events when we have a window, and no modal window is blocking this window
2294
2295 if (window && !window->d_func()->blockedByModalWindow)
2296 QGuiApplication::sendSpontaneousEvent(window, &ev);
2297#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED)
2298 else
2299 ev.setAccepted(false);
2300
2301 if (e->keyType == QEvent::KeyPress) {
2302 backKeyPressAccepted = e->key == Qt::Key_Back && ev.isAccepted();
2303 menuKeyPressAccepted = e->key == Qt::Key_Menu && ev.isAccepted();
2304 } else if (e->keyType == QEvent::KeyRelease) {
2305 if (e->key == Qt::Key_Back && !backKeyPressAccepted && !ev.isAccepted()) {
2306 if (window)
2307 QWindowSystemInterface::handleCloseEvent(window);
2308 } else if (e->key == Qt::Key_Menu && !menuKeyPressAccepted && !ev.isAccepted()) {
2309 platform_theme->showPlatformMenuBar();
2310 }
2311 }
2312#endif
2313 e->eventAccepted = ev.isAccepted();
2314}
2315
2316void QGuiApplicationPrivate::processEnterEvent(QWindowSystemInterfacePrivate::EnterEvent *e)
2317{
2318 if (!e->enter)
2319 return;
2320 if (e->enter.data()->d_func()->blockedByModalWindow) {
2321 // a modal window is blocking this window, don't allow enter events through
2322 return;
2323 }
2324
2325 currentMouseWindow = e->enter;
2326
2327 QEnterEvent event(e->localPos, e->localPos, e->globalPos);
2328 QCoreApplication::sendSpontaneousEvent(e->enter.data(), &event);
2329}
2330
2331void QGuiApplicationPrivate::processLeaveEvent(QWindowSystemInterfacePrivate::LeaveEvent *e)
2332{
2333 if (!e->leave)
2334 return;
2335 if (e->leave.data()->d_func()->blockedByModalWindow) {
2336 // a modal window is blocking this window, don't allow leave events through
2337 return;
2338 }
2339
2340 currentMouseWindow = 0;
2341
2342 QEvent event(QEvent::Leave);
2343 QCoreApplication::sendSpontaneousEvent(e->leave.data(), &event);
2344}
2345
2346void QGuiApplicationPrivate::processActivatedEvent(QWindowSystemInterfacePrivate::ActivatedWindowEvent *e)
2347{
2348 QWindow *previous = QGuiApplicationPrivate::focus_window;
2349 QWindow *newFocus = e->activated.data();
2350
2351 if (previous == newFocus)
2352 return;
2353
2354 if (newFocus)
2355 if (QPlatformWindow *platformWindow = newFocus->handle())
2356 if (platformWindow->isAlertState())
2357 platformWindow->setAlertState(false);
2358
2359 QObject *previousFocusObject = previous ? previous->focusObject() : 0;
2360
2361 if (previous) {
2362 QFocusEvent focusAboutToChange(QEvent::FocusAboutToChange);
2363 QCoreApplication::sendSpontaneousEvent(previous, &focusAboutToChange);
2364 }
2365
2366 QGuiApplicationPrivate::focus_window = newFocus;
2367 if (!qApp)
2368 return;
2369
2370 if (previous) {
2371 Qt::FocusReason r = e->reason;
2372 if ((r == Qt::OtherFocusReason || r == Qt::ActiveWindowFocusReason) &&
2373 newFocus && (newFocus->flags() & Qt::Popup) == Qt::Popup)
2374 r = Qt::PopupFocusReason;
2375 QFocusEvent focusOut(QEvent::FocusOut, r);
2376 QCoreApplication::sendSpontaneousEvent(previous, &focusOut);
2377 QObject::disconnect(previous, SIGNAL(focusObjectChanged(QObject*)),
2378 qApp, SLOT(_q_updateFocusObject(QObject*)));
2379 } else if (!platformIntegration()->hasCapability(QPlatformIntegration::ApplicationState)) {
2380 setApplicationState(Qt::ApplicationActive);
2381 }
2382
2383 if (QGuiApplicationPrivate::focus_window) {
2384 Qt::FocusReason r = e->reason;
2385 if ((r == Qt::OtherFocusReason || r == Qt::ActiveWindowFocusReason) &&
2386 previous && (previous->flags() & Qt::Popup) == Qt::Popup)
2387 r = Qt::PopupFocusReason;
2388 QFocusEvent focusIn(QEvent::FocusIn, r);
2389 QCoreApplication::sendSpontaneousEvent(QGuiApplicationPrivate::focus_window, &focusIn);
2390 QObject::connect(QGuiApplicationPrivate::focus_window, SIGNAL(focusObjectChanged(QObject*)),
2391 qApp, SLOT(_q_updateFocusObject(QObject*)));
2392 } else if (!platformIntegration()->hasCapability(QPlatformIntegration::ApplicationState)) {
2393 setApplicationState(Qt::ApplicationInactive);
2394 }
2395
2396 if (self) {
2397 self->notifyActiveWindowChange(previous);
2398
2399 if (previousFocusObject != qApp->focusObject())
2400 self->_q_updateFocusObject(qApp->focusObject());
2401 }
2402
2403 emit qApp->focusWindowChanged(newFocus);
2404 if (previous)
2405 emit previous->activeChanged();
2406 if (newFocus)
2407 emit newFocus->activeChanged();
2408}
2409
2410void QGuiApplicationPrivate::processWindowStateChangedEvent(QWindowSystemInterfacePrivate::WindowStateChangedEvent *wse)
2411{
2412 if (QWindow *window = wse->window.data()) {
2413 QWindowStateChangeEvent e(wse->oldState);
2414 window->d_func()->windowState = wse->newState;
2415 QGuiApplication::sendSpontaneousEvent(window, &e);
2416 }
2417}
2418
2419void QGuiApplicationPrivate::processWindowScreenChangedEvent(QWindowSystemInterfacePrivate::WindowScreenChangedEvent *wse)
2420{
2421 if (QWindow *window = wse->window.data()) {
2422 if (window->screen() == wse->screen.data())
2423 return;
2424 if (QWindow *topLevelWindow = window->d_func()->topLevelWindow(QWindow::ExcludeTransients)) {
2425 if (QScreen *screen = wse->screen.data())
2426 topLevelWindow->d_func()->setTopLevelScreen(screen, false /* recreate */);
2427 else // Fall back to default behavior, and try to find some appropriate screen
2428 topLevelWindow->setScreen(0);
2429 }
2430 // we may have changed scaling, so trigger resize event if needed
2431 if (window->handle()) {
2432 QWindowSystemInterfacePrivate::GeometryChangeEvent gce(window, QHighDpi::fromNativePixels(window->handle()->geometry(), window));
2433 processGeometryChangeEvent(&gce);
2434 }
2435 }
2436}
2437
2438void QGuiApplicationPrivate::processSafeAreaMarginsChangedEvent(QWindowSystemInterfacePrivate::SafeAreaMarginsChangedEvent *wse)
2439{
2440 if (wse->window.isNull())
2441 return;
2442
2443 // Handle by forwarding directly to QWindowPrivate, instead of sending spontaneous
2444 // QEvent like most other functions, as there's no QEvent type for the safe area
2445 // change, and we don't want to add one until we know that this is a good API.
2446 qt_window_private(wse->window)->processSafeAreaMarginsChanged();
2447}
2448
2449void QGuiApplicationPrivate::processThemeChanged(QWindowSystemInterfacePrivate::ThemeChangeEvent *tce)
2450{
2451 if (self)
2452 self->notifyThemeChanged();
2453 if (QWindow *window = tce->window.data()) {
2454 QEvent e(QEvent::ThemeChange);
2455 QGuiApplication::sendSpontaneousEvent(window, &e);
2456 }
2457}
2458
2459void QGuiApplicationPrivate::processGeometryChangeEvent(QWindowSystemInterfacePrivate::GeometryChangeEvent *e)
2460{
2461 if (e->window.isNull())
2462 return;
2463
2464 QWindow *window = e->window.data();
2465 if (!window)
2466 return;
2467
2468 const QRect lastReportedGeometry = window->d_func()->geometry;
2469 const QRect requestedGeometry = e->requestedGeometry;
2470 const QRect actualGeometry = e->newGeometry;
2471
2472 // We send size and move events only if the geometry has changed from
2473 // what was last reported, or if the user tried to set a new geometry,
2474 // but the window manager responded by keeping the old geometry. In the
2475 // latter case we send move/resize events with the same geometry as the
2476 // last reported geometry, to indicate that the window wasn't moved or
2477 // resized. Note that this logic does not apply to the property changes
2478 // of the window, as we don't treat them as part of this request/response
2479 // protocol of QWindow/QPA.
2480 const bool isResize = actualGeometry.size() != lastReportedGeometry.size()
2481 || requestedGeometry.size() != actualGeometry.size();
2482 const bool isMove = actualGeometry.topLeft() != lastReportedGeometry.topLeft()
2483 || requestedGeometry.topLeft() != actualGeometry.topLeft();
2484
2485 window->d_func()->geometry = actualGeometry;
2486
2487 if (isResize || window->d_func()->resizeEventPending) {
2488 QResizeEvent e(actualGeometry.size(), lastReportedGeometry.size());
2489 QGuiApplication::sendSpontaneousEvent(window, &e);
2490
2491 window->d_func()->resizeEventPending = false;
2492
2493 if (actualGeometry.width() != lastReportedGeometry.width())
2494 emit window->widthChanged(actualGeometry.width());
2495 if (actualGeometry.height() != lastReportedGeometry.height())
2496 emit window->heightChanged(actualGeometry.height());
2497 }
2498
2499 if (isMove) {
2500 //### frame geometry
2501 QMoveEvent e(actualGeometry.topLeft(), lastReportedGeometry.topLeft());
2502 QGuiApplication::sendSpontaneousEvent(window, &e);
2503
2504 if (actualGeometry.x() != lastReportedGeometry.x())
2505 emit window->xChanged(actualGeometry.x());
2506 if (actualGeometry.y() != lastReportedGeometry.y())
2507 emit window->yChanged(actualGeometry.y());
2508 }
2509}
2510
2511void QGuiApplicationPrivate::processCloseEvent(QWindowSystemInterfacePrivate::CloseEvent *e)
2512{
2513 if (e->window.isNull())
2514 return;
2515 if (e->window.data()->d_func()->blockedByModalWindow) {
2516 // a modal window is blocking this window, don't allow close events through
2517 return;
2518 }
2519
2520 QCloseEvent event;
2521 QGuiApplication::sendSpontaneousEvent(e->window.data(), &event);
2522 if (e->accepted) {
2523 *(e->accepted) = event.isAccepted();
2524 }
2525}
2526
2527void QGuiApplicationPrivate::processFileOpenEvent(QWindowSystemInterfacePrivate::FileOpenEvent *e)
2528{
2529 if (e->url.isEmpty())
2530 return;
2531
2532 QFileOpenEvent event(e->url);
2533 QGuiApplication::sendSpontaneousEvent(qApp, &event);
2534}
2535
2536QGuiApplicationPrivate::TabletPointData &QGuiApplicationPrivate::tabletDevicePoint(qint64 deviceId)
2537{
2538 for (int i = 0; i < tabletDevicePoints.size(); ++i) {
2539 TabletPointData &pointData = tabletDevicePoints[i];
2540 if (pointData.deviceId == deviceId)
2541 return pointData;
2542 }
2543
2544 tabletDevicePoints.append(TabletPointData(deviceId));
2545 return tabletDevicePoints.last();
2546}
2547
2548void QGuiApplicationPrivate::processTabletEvent(QWindowSystemInterfacePrivate::TabletEvent *e)
2549{
2550#if QT_CONFIG(tabletevent)
2551 TabletPointData &pointData = tabletDevicePoint(e->uid);
2552
2553 QEvent::Type type = QEvent::TabletMove;
2554 if (e->buttons != pointData.state)
2555 type = (e->buttons > pointData.state) ? QEvent::TabletPress : QEvent::TabletRelease;
2556
2557 QWindow *window = e->window.data();
2558 modifier_buttons = e->modifiers;
2559
2560 bool localValid = true;
2561 // If window is null, pick one based on the global position and make sure all
2562 // subsequent events up to the release are delivered to that same window.
2563 // If window is given, just send to that.
2564 if (type == QEvent::TabletPress) {
2565 if (e->nullWindow()) {
2566 window = QGuiApplication::topLevelAt(e->global.toPoint());
2567 localValid = false;
2568 }
2569 if (!window)
2570 return;
2571 pointData.target = window;
2572 } else {
2573 if (e->nullWindow()) {
2574 window = pointData.target;
2575 localValid = false;
2576 }
2577 if (type == QEvent::TabletRelease)
2578 pointData.target = nullptr;
2579 if (!window)
2580 return;
2581 }
2582 QPointF local = e->local;
2583 if (!localValid) {
2584 QPointF delta = e->global - e->global.toPoint();
2585 local = window->mapFromGlobal(e->global.toPoint()) + delta;
2586 }
2587 Qt::MouseButtons stateChange = e->buttons ^ pointData.state;
2588 Qt::MouseButton button = Qt::NoButton;
2589 for (int check = Qt::LeftButton; check <= int(Qt::MaxMouseButton); check = check << 1) {
2590 if (check & stateChange) {
2591 button = Qt::MouseButton(check);
2592 break;
2593 }
2594 }
2595 QTabletEvent tabletEvent(type, local, e->global,
2596 e->device, e->pointerType, e->pressure, e->xTilt, e->yTilt,
2597 e->tangentialPressure, e->rotation, e->z,
2598 e->modifiers, e->uid, button, e->buttons);
2599 tabletEvent.setAccepted(false);
2600 tabletEvent.setTimestamp(e->timestamp);
2601 QGuiApplication::sendSpontaneousEvent(window, &tabletEvent);
2602 pointData.state = e->buttons;
2603 if (!tabletEvent.isAccepted()
2604 && !QWindowSystemInterfacePrivate::TabletEvent::platformSynthesizesMouse
2605 && qApp->testAttribute(Qt::AA_SynthesizeMouseForUnhandledTabletEvents)) {
2606
2607 const QEvent::Type mouseType = [&]() {
2608 switch (type) {
2609 case QEvent::TabletPress: return QEvent::MouseButtonPress;
2610 case QEvent::TabletMove: return QEvent::MouseMove;
2611 case QEvent::TabletRelease: return QEvent::MouseButtonRelease;
2612 default: Q_UNREACHABLE();
2613 }
2614 }();
2615 QWindowSystemInterfacePrivate::MouseEvent mouseEvent(window, e->timestamp, e->local,
2616 e->global, e->buttons, e->modifiers, button, mouseType, Qt::MouseEventSynthesizedByQt);
2617 mouseEvent.flags |= QWindowSystemInterfacePrivate::WindowSystemEvent::Synthetic;
2618 processMouseEvent(&mouseEvent);
2619 }
2620#else
2621 Q_UNUSED(e)
2622#endif
2623}
2624
2625void QGuiApplicationPrivate::processTabletEnterProximityEvent(QWindowSystemInterfacePrivate::TabletEnterProximityEvent *e)
2626{
2627#if QT_CONFIG(tabletevent)
2628 QTabletEvent ev(QEvent::TabletEnterProximity, QPointF(), QPointF(),
2629 e->device, e->pointerType, 0, 0, 0,
2630 0, 0, 0,
2631 Qt::NoModifier, e->uid, Qt::NoButton, tabletDevicePoint(e->uid).state);
2632 ev.setTimestamp(e->timestamp);
2633 QGuiApplication::sendSpontaneousEvent(qGuiApp, &ev);
2634#else
2635 Q_UNUSED(e)
2636#endif
2637}
2638
2639void QGuiApplicationPrivate::processTabletLeaveProximityEvent(QWindowSystemInterfacePrivate::TabletLeaveProximityEvent *e)
2640{
2641#if QT_CONFIG(tabletevent)
2642 QTabletEvent ev(QEvent::TabletLeaveProximity, QPointF(), QPointF(),
2643 e->device, e->pointerType, 0, 0, 0,
2644 0, 0, 0,
2645 Qt::NoModifier, e->uid, Qt::NoButton, tabletDevicePoint(e->uid).state);
2646 ev.setTimestamp(e->timestamp);
2647 QGuiApplication::sendSpontaneousEvent(qGuiApp, &ev);
2648#else
2649 Q_UNUSED(e)
2650#endif
2651}
2652
2653#ifndef QT_NO_GESTURES
2654void QGuiApplicationPrivate::processGestureEvent(QWindowSystemInterfacePrivate::GestureEvent *e)
2655{
2656 if (e->window.isNull())
2657 return;
2658
2659 QNativeGestureEvent ev(e->type, e->device, e->pos, e->pos, e->globalPos, e->realValue, e->sequenceId, e->intValue);
2660 ev.setTimestamp(e->timestamp);
2661 QGuiApplication::sendSpontaneousEvent(e->window, &ev);
2662}
2663#endif // QT_NO_GESTURES
2664
2665void QGuiApplicationPrivate::processPlatformPanelEvent(QWindowSystemInterfacePrivate::PlatformPanelEvent *e)
2666{
2667 if (!e->window)
2668 return;
2669
2670 if (e->window->d_func()->blockedByModalWindow) {
2671 // a modal window is blocking this window, don't allow events through
2672 return;
2673 }
2674
2675 QEvent ev(QEvent::PlatformPanel);
2676 QGuiApplication::sendSpontaneousEvent(e->window.data(), &ev);
2677}
2678
2679#ifndef QT_NO_CONTEXTMENU
2680void QGuiApplicationPrivate::processContextMenuEvent(QWindowSystemInterfacePrivate::ContextMenuEvent *e)
2681{
2682 // Widgets do not care about mouse triggered context menu events. Also, do not forward event
2683 // to a window blocked by a modal window.
2684 if (!e->window || e->mouseTriggered || e->window->d_func()->blockedByModalWindow)
2685 return;
2686
2687 QContextMenuEvent ev(QContextMenuEvent::Keyboard, e->pos, e->globalPos, e->modifiers);
2688 QGuiApplication::sendSpontaneousEvent(e->window.data(), &ev);
2689}
2690#endif
2691
2692Q_GUI_EXPORT uint qHash(const QGuiApplicationPrivate::ActiveTouchPointsKey &k)
2693{
2694 return qHash(k.device) + k.touchPointId;
2695}
2696
2697Q_GUI_EXPORT bool operator==(const QGuiApplicationPrivate::ActiveTouchPointsKey &a,
2698 const QGuiApplicationPrivate::ActiveTouchPointsKey &b)
2699{
2700 return a.device == b.device
2701 && a.touchPointId == b.touchPointId;
2702}
2703
2704void QGuiApplicationPrivate::processTouchEvent(QWindowSystemInterfacePrivate::TouchEvent *e)
2705{
2706 QGuiApplicationPrivate *d = self;
2707 modifier_buttons = e->modifiers;
2708
2709 if (e->touchType == QEvent::TouchCancel) {
2710 // The touch sequence has been canceled (e.g. by the compositor).
2711 // Send the TouchCancel to all windows with active touches and clean up.
2712 QTouchEvent touchEvent(QEvent::TouchCancel, e->device, e->modifiers);
2713 touchEvent.setTimestamp(e->timestamp);
2714 QHash<ActiveTouchPointsKey, ActiveTouchPointsValue>::const_iterator it
2715 = self->activeTouchPoints.constBegin(), ite = self->activeTouchPoints.constEnd();
2716 QSet<QWindow *> windowsNeedingCancel;
2717 while (it != ite) {
2718 QWindow *w = it->window.data();
2719 if (w)
2720 windowsNeedingCancel.insert(w);
2721 ++it;
2722 }
2723 for (QSet<QWindow *>::const_iterator winIt = windowsNeedingCancel.constBegin(),
2724 winItEnd = windowsNeedingCancel.constEnd(); winIt != winItEnd; ++winIt) {
2725 touchEvent.setWindow(*winIt);
2726 QGuiApplication::sendSpontaneousEvent(*winIt, &touchEvent);
2727 }
2728 if (!self->synthesizedMousePoints.isEmpty() && !e->synthetic()) {
2729 for (QHash<QWindow *, SynthesizedMouseData>::const_iterator synthIt = self->synthesizedMousePoints.constBegin(),
2730 synthItEnd = self->synthesizedMousePoints.constEnd(); synthIt != synthItEnd; ++synthIt) {
2731 if (!synthIt->window)
2732 continue;
2733 QWindowSystemInterfacePrivate::MouseEvent fake(synthIt->window.data(),
2734 e->timestamp,
2735 synthIt->pos,
2736 synthIt->screenPos,
2737 Qt::NoButton,
2738 e->modifiers,
2739 Qt::LeftButton,
2740 QEvent::MouseButtonRelease,
2741 Qt::MouseEventSynthesizedByQt);
2742 fake.flags |= QWindowSystemInterfacePrivate::WindowSystemEvent::Synthetic;
2743 processMouseEvent(&fake);
2744 }
2745 self->synthesizedMousePoints.clear();
2746 }
2747 self->activeTouchPoints.clear();
2748 self->lastTouchType = e->touchType;
2749 return;
2750 }
2751
2752 // Prevent sending ill-formed event sequences: Cancel can only be followed by a Begin.
2753 if (self->lastTouchType == QEvent::TouchCancel && e->touchType != QEvent::TouchBegin)
2754 return;
2755
2756 self->lastTouchType = e->touchType;
2757
2758 QWindow *window = e->window.data();
2759 typedef QPair<Qt::TouchPointStates, QList<QTouchEvent::TouchPoint> > StatesAndTouchPoints;
2760 QHash<QWindow *, StatesAndTouchPoints> windowsNeedingEvents;
2761 bool