QPA: Add interface for setting the application state explicitly
The motivation for this patch is twofold: 1: we need a way (for iOS/Android) to tell the current window to remove focus from the focus object when the user hides the input panel. Otherwise, if the focus object is e.g a line edit, the cursor will continue to blink inside it, which is wrong. As it stands, telling the active window to deactivate (by calling QWindowSystemInterface::handleWindowActivated(0)), will cause the whole application to deactivate if no windows are active, which is not what we want. 2: Qt currently understands just two application states, Activated and Deactivated. On mobile platforms we can have other states as well, like "suspended" on iOS. So controlling the application state should not depend on window activation, but instead be controlled through a separate API by the platform plugin. This patch will add the following function: QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationState newState) that lets us control the application state from the plugin. This also means that we factor out application state handling from window activation, which also gives us a way to remove focus from a window while keeping the application active. To not break existing desktop platforms that relies on application activation being tied to window activation, we need to make this API opt-in by using a platform integration capability hint. This is not optimal, but found necessary after investigating several other solutions. Which states (other that active/inactive) it makes sense to add to Qt::ApplicationState will be a topic for later patches. Change-Id: Ic6fdd3b66867abb67da43eba04ec86f06d82ff94 Reviewed-by: Friedemann Kleint <Friedemann.Kleint@digia.com> Reviewed-by: Samuel Rødal <samuel.rodal@digia.com>
This commit is contained in:
parent
03b2512598
commit
22077e1609
@ -325,6 +325,13 @@ public:
|
|||||||
|
|
||||||
Q_DECLARE_FLAGS(WindowStates, WindowState)
|
Q_DECLARE_FLAGS(WindowStates, WindowState)
|
||||||
|
|
||||||
|
enum ApplicationState {
|
||||||
|
ApplicationInactive = 0x00000000,
|
||||||
|
ApplicationActive = 0x00000001
|
||||||
|
};
|
||||||
|
|
||||||
|
Q_DECLARE_FLAGS(ApplicationStates, ApplicationState)
|
||||||
|
|
||||||
enum ScreenOrientation {
|
enum ScreenOrientation {
|
||||||
PrimaryOrientation = 0x00000000,
|
PrimaryOrientation = 0x00000000,
|
||||||
PortraitOrientation = 0x00000001,
|
PortraitOrientation = 0x00000001,
|
||||||
|
@ -1782,6 +1782,21 @@
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\enum Qt::ApplicationState
|
||||||
|
|
||||||
|
\keyword application state
|
||||||
|
|
||||||
|
This enum type is used to specify the current state of the application.
|
||||||
|
|
||||||
|
The states are
|
||||||
|
|
||||||
|
\value ApplicationInactive The application is running in the background.
|
||||||
|
\value ApplicationActive The application is running in the foreground.
|
||||||
|
|
||||||
|
\since 5.1
|
||||||
|
*/
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\enum Qt::ScreenOrientation
|
\enum Qt::ScreenOrientation
|
||||||
|
|
||||||
|
@ -111,6 +111,8 @@ bool QGuiApplicationPrivate::tabletState = false;
|
|||||||
QWindow *QGuiApplicationPrivate::tabletPressTarget = 0;
|
QWindow *QGuiApplicationPrivate::tabletPressTarget = 0;
|
||||||
QWindow *QGuiApplicationPrivate::currentMouseWindow = 0;
|
QWindow *QGuiApplicationPrivate::currentMouseWindow = 0;
|
||||||
|
|
||||||
|
Qt::ApplicationState QGuiApplicationPrivate::applicationState = Qt::ApplicationInactive;
|
||||||
|
|
||||||
QPlatformIntegration *QGuiApplicationPrivate::platform_integration = 0;
|
QPlatformIntegration *QGuiApplicationPrivate::platform_integration = 0;
|
||||||
QPlatformTheme *QGuiApplicationPrivate::platform_theme = 0;
|
QPlatformTheme *QGuiApplicationPrivate::platform_theme = 0;
|
||||||
|
|
||||||
@ -1274,6 +1276,9 @@ void QGuiApplicationPrivate::processWindowSystemEvent(QWindowSystemInterfacePriv
|
|||||||
case QWindowSystemInterfacePrivate::WindowStateChanged:
|
case QWindowSystemInterfacePrivate::WindowStateChanged:
|
||||||
QGuiApplicationPrivate::processWindowStateChangedEvent(static_cast<QWindowSystemInterfacePrivate::WindowStateChangedEvent *>(e));
|
QGuiApplicationPrivate::processWindowStateChangedEvent(static_cast<QWindowSystemInterfacePrivate::WindowStateChangedEvent *>(e));
|
||||||
break;
|
break;
|
||||||
|
case QWindowSystemInterfacePrivate::ApplicationStateChanged:
|
||||||
|
QGuiApplicationPrivate::processApplicationStateChangedEvent(static_cast<QWindowSystemInterfacePrivate::ApplicationStateChangedEvent *>(e));
|
||||||
|
break;
|
||||||
case QWindowSystemInterfacePrivate::Close:
|
case QWindowSystemInterfacePrivate::Close:
|
||||||
QGuiApplicationPrivate::processCloseEvent(
|
QGuiApplicationPrivate::processCloseEvent(
|
||||||
static_cast<QWindowSystemInterfacePrivate::CloseEvent *>(e));
|
static_cast<QWindowSystemInterfacePrivate::CloseEvent *>(e));
|
||||||
@ -1567,7 +1572,7 @@ void QGuiApplicationPrivate::processActivatedEvent(QWindowSystemInterfacePrivate
|
|||||||
QCoreApplication::sendSpontaneousEvent(previous, &focusOut);
|
QCoreApplication::sendSpontaneousEvent(previous, &focusOut);
|
||||||
QObject::disconnect(previous, SIGNAL(focusObjectChanged(QObject*)),
|
QObject::disconnect(previous, SIGNAL(focusObjectChanged(QObject*)),
|
||||||
qApp, SLOT(_q_updateFocusObject(QObject*)));
|
qApp, SLOT(_q_updateFocusObject(QObject*)));
|
||||||
} else {
|
} else if (!platformIntegration()->hasCapability(QPlatformIntegration::ApplicationState)) {
|
||||||
QEvent appActivate(QEvent::ApplicationActivate);
|
QEvent appActivate(QEvent::ApplicationActivate);
|
||||||
qApp->sendSpontaneousEvent(qApp, &appActivate);
|
qApp->sendSpontaneousEvent(qApp, &appActivate);
|
||||||
}
|
}
|
||||||
@ -1577,7 +1582,7 @@ void QGuiApplicationPrivate::processActivatedEvent(QWindowSystemInterfacePrivate
|
|||||||
QCoreApplication::sendSpontaneousEvent(QGuiApplicationPrivate::focus_window, &focusIn);
|
QCoreApplication::sendSpontaneousEvent(QGuiApplicationPrivate::focus_window, &focusIn);
|
||||||
QObject::connect(QGuiApplicationPrivate::focus_window, SIGNAL(focusObjectChanged(QObject*)),
|
QObject::connect(QGuiApplicationPrivate::focus_window, SIGNAL(focusObjectChanged(QObject*)),
|
||||||
qApp, SLOT(_q_updateFocusObject(QObject*)));
|
qApp, SLOT(_q_updateFocusObject(QObject*)));
|
||||||
} else {
|
} else if (!platformIntegration()->hasCapability(QPlatformIntegration::ApplicationState)) {
|
||||||
QEvent appActivate(QEvent::ApplicationDeactivate);
|
QEvent appActivate(QEvent::ApplicationDeactivate);
|
||||||
qApp->sendSpontaneousEvent(qApp, &appActivate);
|
qApp->sendSpontaneousEvent(qApp, &appActivate);
|
||||||
}
|
}
|
||||||
@ -1601,6 +1606,24 @@ void QGuiApplicationPrivate::processWindowStateChangedEvent(QWindowSystemInterfa
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QGuiApplicationPrivate::processApplicationStateChangedEvent(QWindowSystemInterfacePrivate::ApplicationStateChangedEvent *e)
|
||||||
|
{
|
||||||
|
if (e->newState == applicationState)
|
||||||
|
return;
|
||||||
|
applicationState = e->newState;
|
||||||
|
|
||||||
|
switch (e->newState) {
|
||||||
|
case Qt::ApplicationActive: {
|
||||||
|
QEvent appActivate(QEvent::ApplicationActivate);
|
||||||
|
qApp->sendSpontaneousEvent(qApp, &appActivate);
|
||||||
|
break; }
|
||||||
|
case Qt::ApplicationInactive: {
|
||||||
|
QEvent appDeactivate(QEvent::ApplicationDeactivate);
|
||||||
|
qApp->sendSpontaneousEvent(qApp, &appDeactivate);
|
||||||
|
break; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void QGuiApplicationPrivate::processThemeChanged(QWindowSystemInterfacePrivate::ThemeChangeEvent *tce)
|
void QGuiApplicationPrivate::processThemeChanged(QWindowSystemInterfacePrivate::ThemeChangeEvent *tce)
|
||||||
{
|
{
|
||||||
if (self)
|
if (self)
|
||||||
|
@ -127,6 +127,8 @@ public:
|
|||||||
static void processActivatedEvent(QWindowSystemInterfacePrivate::ActivatedWindowEvent *e);
|
static void processActivatedEvent(QWindowSystemInterfacePrivate::ActivatedWindowEvent *e);
|
||||||
static void processWindowStateChangedEvent(QWindowSystemInterfacePrivate::WindowStateChangedEvent *e);
|
static void processWindowStateChangedEvent(QWindowSystemInterfacePrivate::WindowStateChangedEvent *e);
|
||||||
|
|
||||||
|
static void processApplicationStateChangedEvent(QWindowSystemInterfacePrivate::ApplicationStateChangedEvent *e);
|
||||||
|
|
||||||
static void processWindowSystemEvent(QWindowSystemInterfacePrivate::WindowSystemEvent *e);
|
static void processWindowSystemEvent(QWindowSystemInterfacePrivate::WindowSystemEvent *e);
|
||||||
|
|
||||||
static void updateFilteredScreenOrientation(QScreen *screen);
|
static void updateFilteredScreenOrientation(QScreen *screen);
|
||||||
@ -199,6 +201,7 @@ public:
|
|||||||
static bool tabletState;
|
static bool tabletState;
|
||||||
static QWindow *tabletPressTarget;
|
static QWindow *tabletPressTarget;
|
||||||
static QWindow *currentMouseWindow;
|
static QWindow *currentMouseWindow;
|
||||||
|
static Qt::ApplicationState applicationState;
|
||||||
|
|
||||||
#ifndef QT_NO_CLIPBOARD
|
#ifndef QT_NO_CLIPBOARD
|
||||||
static QClipboard *qt_clipboard;
|
static QClipboard *qt_clipboard;
|
||||||
|
@ -199,6 +199,13 @@ QPlatformServices *QPlatformIntegration::services() const
|
|||||||
\value MultipleWindows The platform supports multiple QWindows, i.e. does some kind
|
\value MultipleWindows The platform supports multiple QWindows, i.e. does some kind
|
||||||
of compositing either client or server side. Some platforms might only support a
|
of compositing either client or server side. Some platforms might only support a
|
||||||
single fullscreen window.
|
single fullscreen window.
|
||||||
|
|
||||||
|
\value ApplicationState The platform handles the application state explicitly.
|
||||||
|
This means that QEvent::ApplicationActivate and QEvent::ApplicationDeativate
|
||||||
|
will not be posted automatically. Instead, the platform must handle application
|
||||||
|
state explicitly by using QWindowSystemInterface::handleApplicationStateChanged().
|
||||||
|
If not set, application state will follow window activation, which is the normal
|
||||||
|
behavior for desktop platforms.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
@ -88,7 +88,8 @@ public:
|
|||||||
SharedGraphicsCache,
|
SharedGraphicsCache,
|
||||||
BufferQueueingOpenGL,
|
BufferQueueingOpenGL,
|
||||||
WindowMasks,
|
WindowMasks,
|
||||||
MultipleWindows
|
MultipleWindows,
|
||||||
|
ApplicationState
|
||||||
};
|
};
|
||||||
|
|
||||||
virtual ~QPlatformIntegration() { }
|
virtual ~QPlatformIntegration() { }
|
||||||
|
@ -46,6 +46,7 @@
|
|||||||
#include "private/qtouchdevice_p.h"
|
#include "private/qtouchdevice_p.h"
|
||||||
#include <QAbstractEventDispatcher>
|
#include <QAbstractEventDispatcher>
|
||||||
#include <qpa/qplatformdrag.h>
|
#include <qpa/qplatformdrag.h>
|
||||||
|
#include <qpa/qplatformintegration.h>
|
||||||
#include <qdebug.h>
|
#include <qdebug.h>
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
@ -122,6 +123,14 @@ void QWindowSystemInterface::handleWindowStateChanged(QWindow *tlw, Qt::WindowSt
|
|||||||
QWindowSystemInterfacePrivate::handleWindowSystemEvent(e);
|
QWindowSystemInterfacePrivate::handleWindowSystemEvent(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationState newState)
|
||||||
|
{
|
||||||
|
Q_ASSERT(QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::ApplicationState));
|
||||||
|
QWindowSystemInterfacePrivate::ApplicationStateChangedEvent *e =
|
||||||
|
new QWindowSystemInterfacePrivate::ApplicationStateChangedEvent(newState);
|
||||||
|
QWindowSystemInterfacePrivate::handleWindowSystemEvent(e);
|
||||||
|
}
|
||||||
|
|
||||||
void QWindowSystemInterface::handleGeometryChange(QWindow *tlw, const QRect &newRect)
|
void QWindowSystemInterface::handleGeometryChange(QWindow *tlw, const QRect &newRect)
|
||||||
{
|
{
|
||||||
QWindowSystemInterfacePrivate::GeometryChangeEvent *e = new QWindowSystemInterfacePrivate::GeometryChangeEvent(tlw,newRect);
|
QWindowSystemInterfacePrivate::GeometryChangeEvent *e = new QWindowSystemInterfacePrivate::GeometryChangeEvent(tlw,newRect);
|
||||||
|
@ -138,6 +138,8 @@ public:
|
|||||||
static void handleWindowActivated(QWindow *w);
|
static void handleWindowActivated(QWindow *w);
|
||||||
static void handleWindowStateChanged(QWindow *w, Qt::WindowState newState);
|
static void handleWindowStateChanged(QWindow *w, Qt::WindowState newState);
|
||||||
|
|
||||||
|
static void handleApplicationStateChanged(Qt::ApplicationState newState);
|
||||||
|
|
||||||
static void handleExposeEvent(QWindow *tlw, const QRegion ®ion);
|
static void handleExposeEvent(QWindow *tlw, const QRegion ®ion);
|
||||||
|
|
||||||
#ifndef QT_NO_DRAGANDDROP
|
#ifndef QT_NO_DRAGANDDROP
|
||||||
|
@ -88,7 +88,8 @@ public:
|
|||||||
TabletEnterProximity = UserInputEvent | 0x15,
|
TabletEnterProximity = UserInputEvent | 0x15,
|
||||||
TabletLeaveProximity = UserInputEvent | 0x16,
|
TabletLeaveProximity = UserInputEvent | 0x16,
|
||||||
PlatformPanel = UserInputEvent | 0x17,
|
PlatformPanel = UserInputEvent | 0x17,
|
||||||
ContextMenu = UserInputEvent | 0x18
|
ContextMenu = UserInputEvent | 0x18,
|
||||||
|
ApplicationStateChanged = 0x19
|
||||||
};
|
};
|
||||||
|
|
||||||
class WindowSystemEvent {
|
class WindowSystemEvent {
|
||||||
@ -152,6 +153,15 @@ public:
|
|||||||
Qt::WindowState newState;
|
Qt::WindowState newState;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class ApplicationStateChangedEvent : public WindowSystemEvent {
|
||||||
|
public:
|
||||||
|
ApplicationStateChangedEvent(Qt::ApplicationState newState)
|
||||||
|
: WindowSystemEvent(ApplicationStateChanged), newState(newState)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
Qt::ApplicationState newState;
|
||||||
|
};
|
||||||
|
|
||||||
class UserEvent : public WindowSystemEvent {
|
class UserEvent : public WindowSystemEvent {
|
||||||
public:
|
public:
|
||||||
UserEvent(QWindow * w, ulong time, EventType t)
|
UserEvent(QWindow * w, ulong time, EventType t)
|
||||||
|
Loading…
Reference in New Issue
Block a user