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