From da01deb0ac01b37656e021b9d5d696c5de7b0afb Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Wed, 10 Apr 2013 13:55:50 +0200 Subject: Implement alertion state for windows. Add QWindow::alert() and QPlatformWindow::setAlertState(). Add logic to clear alertion state when the window becomes active. The platform plugins then only need to implement a setter and a cheap getter and need not handle activation. Prototypically implement X11 and Windows. Task-number: QTBUG-30416 Change-Id: Ia70c4722d812462a21f4034b7d52735c9f2bc49c Reviewed-by: Jerome Pasion Reviewed-by: Gunnar Sletta --- src/gui/kernel/qguiapplication.cpp | 5 ++++ src/gui/kernel/qplatformwindow.cpp | 26 ++++++++++++++++++++ src/gui/kernel/qplatformwindow.h | 3 +++ src/gui/kernel/qwindow.cpp | 30 ++++++++++++++++++++++++ src/gui/kernel/qwindow.h | 3 +++ src/gui/kernel/qwindow_p.h | 1 + src/plugins/platforms/windows/qwindowswindow.cpp | 13 ++++++++++ src/plugins/platforms/windows/qwindowswindow.h | 5 +++- src/plugins/platforms/xcb/qxcbwindow.cpp | 14 +++++++++++ src/plugins/platforms/xcb/qxcbwindow.h | 5 +++- src/widgets/kernel/qapplication_qpa.cpp | 12 +++++++++- 11 files changed, 114 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp index b05ba28e48..fba516c135 100644 --- a/src/gui/kernel/qguiapplication.cpp +++ b/src/gui/kernel/qguiapplication.cpp @@ -1592,6 +1592,11 @@ void QGuiApplicationPrivate::processActivatedEvent(QWindowSystemInterfacePrivate if (previous == newFocus) return; + if (newFocus) + if (QPlatformWindow *platformWindow = newFocus->handle()) + if (platformWindow->isAlertState()) + platformWindow->setAlertState(false); + QObject *previousFocusObject = previous ? previous->focusObject() : 0; if (previous) { diff --git a/src/gui/kernel/qplatformwindow.cpp b/src/gui/kernel/qplatformwindow.cpp index bfb6ab5a68..1e8ac60cca 100644 --- a/src/gui/kernel/qplatformwindow.cpp +++ b/src/gui/kernel/qplatformwindow.cpp @@ -462,6 +462,32 @@ QString QPlatformWindow::formatWindowTitle(const QString &title, const QString & return fullTitle; } +/*! + Reimplement this method to set whether the window demands attention + (for example, by flashing the taskbar icon) depending on \a enabled. + + \sa isAlertState() + \since 5.1 +*/ + +void QPlatformWindow::setAlertState(bool enable) +{ + Q_UNUSED(enable) +} + +/*! + Reimplement this method return whether the window is in + an alert state. + + \sa setAlertState() + \since 5.1 +*/ + +bool QPlatformWindow::isAlertState() const +{ + return false; +} + /*! Helper function to get initial geometry on windowing systems which do not do smart positioning and also do not provide a means of centering a diff --git a/src/gui/kernel/qplatformwindow.h b/src/gui/kernel/qplatformwindow.h index 7ade461890..7dfbae036f 100644 --- a/src/gui/kernel/qplatformwindow.h +++ b/src/gui/kernel/qplatformwindow.h @@ -128,6 +128,9 @@ public: virtual void setFrameStrutEventsEnabled(bool enabled); virtual bool frameStrutEventsEnabled() const; + virtual void setAlertState(bool enabled); + virtual bool isAlertState() const; + static QRect initialGeometry(const QWindow *w, const QRect &initialGeometry, int defaultWidth, int defaultHeight); diff --git a/src/gui/kernel/qwindow.cpp b/src/gui/kernel/qwindow.cpp index 2307df37ac..8c9bc575bd 100644 --- a/src/gui/kernel/qwindow.cpp +++ b/src/gui/kernel/qwindow.cpp @@ -58,6 +58,7 @@ #include +#include #include #include @@ -2150,6 +2151,33 @@ QWindow *QWindow::fromWinId(WId id) return window; } +/*! + Causes an alert to be shown for \a msec miliseconds. If \a msec is \c 0 (the + default), then the alert is shown indefinitely until the window becomes + active again. + + In alert state, the window indicates that it demands attention, for example by + flashing or bouncing the taskbar entry. + + \since 5.1 +*/ + +void QWindow::alert(int msec) +{ + Q_D(QWindow); + if (!d->platformWindow || d->platformWindow->isAlertState()) + return; + d->platformWindow->setAlertState(true); + if (d->platformWindow->isAlertState() && msec) + QTimer::singleShot(msec, this, SLOT(_q_clearAlert())); +} + +void QWindowPrivate::_q_clearAlert() +{ + if (platformWindow && platformWindow->isAlertState()) + platformWindow->setAlertState(false); +} + #ifndef QT_NO_CURSOR /*! \brief set the cursor shape for this window @@ -2233,3 +2261,5 @@ void QWindowPrivate::applyCursor() #endif // QT_NO_CURSOR QT_END_NAMESPACE + +#include "moc_qwindow.cpp" diff --git a/src/gui/kernel/qwindow.h b/src/gui/kernel/qwindow.h index 1b63e185f8..9b1ed2c702 100644 --- a/src/gui/kernel/qwindow.h +++ b/src/gui/kernel/qwindow.h @@ -290,6 +290,8 @@ public Q_SLOTS: Q_REVISION(1) void setMaximumWidth(int w); Q_REVISION(1) void setMaximumHeight(int h); + void alert(int msec); + Q_SIGNALS: void screenChanged(QScreen *screen); void modalityChanged(Qt::WindowModality modality); @@ -346,6 +348,7 @@ protected: QWindow(QWindowPrivate &dd, QWindow *parent); private: + Q_PRIVATE_SLOT(d_func(), void _q_clearAlert()) QPlatformSurface *surfaceHandle() const; Q_DISABLE_COPY(QWindow) diff --git a/src/gui/kernel/qwindow_p.h b/src/gui/kernel/qwindow_p.h index e32d45acca..ea2cb722ab 100644 --- a/src/gui/kernel/qwindow_p.h +++ b/src/gui/kernel/qwindow_p.h @@ -125,6 +125,7 @@ public: virtual QWindow *eventReceiver() { Q_Q(QWindow); return q; } void updateVisibility(); + void _q_clearAlert(); QWindow::SurfaceType surfaceType; Qt::WindowFlags windowFlags; diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp index 9b2b67619d..2a5e08cf41 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -1802,6 +1802,19 @@ QWindowsWindow *QWindowsWindow::childAt(const QPoint &clientPoint, unsigned cwex } #ifndef Q_OS_WINCE +void QWindowsWindow::setAlertState(bool enabled) +{ + if (isAlertState() == enabled) + return; + if (enabled) { + alertWindow(0); + setFlag(AlertState); + } else { + stopAlertWindow(); + clearFlag(AlertState); + } +} + void QWindowsWindow::alertWindow(int durationMs) { DWORD timeOutMs = GetCaretBlinkTime(); diff --git a/src/plugins/platforms/windows/qwindowswindow.h b/src/plugins/platforms/windows/qwindowswindow.h index 1148440f05..2117ca50b8 100644 --- a/src/plugins/platforms/windows/qwindowswindow.h +++ b/src/plugins/platforms/windows/qwindowswindow.h @@ -132,7 +132,8 @@ public: SynchronousGeometryChangeEvent = 0x400, WithinSetStyle = 0x800, WithinDestroy = 0x1000, - TouchRegistered = 0x2000 + TouchRegistered = 0x2000, + AlertState = 0x4000 }; struct WindowData @@ -255,6 +256,8 @@ public: void setWindowIcon(const QIcon &icon); #ifndef Q_OS_WINCE + void setAlertState(bool enabled); + bool isAlertState() const { return testFlag(AlertState); } void alertWindow(int durationMs = 0); void stopAlertWindow(); #endif diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index 5af6a9ec9d..68ccbfb8c0 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -189,6 +189,7 @@ QXcbWindow::QXcbWindow(QWindow *window) , m_usingSyncProtocol(false) , m_deferredActivation(false) , m_embedded(false) + , m_alertState(false) , m_netWmUserTimeWindow(XCB_NONE) , m_dirtyFrameMargins(false) #if defined(XCB_USE_EGL) @@ -2047,4 +2048,17 @@ void QXcbWindow::setMask(const QRegion ®ion) #endif // !QT_NO_SHAPE +void QXcbWindow::setAlertState(bool enabled) +{ + if (m_alertState == enabled) + return; + const NetWmStates oldState = netWmStates(); + m_alertState = enabled; + if (enabled) { + setNetWmStates(oldState | NetWmStateDemandsAttention); + } else { + setNetWmStates(oldState & ~NetWmStateDemandsAttention); + } +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/xcb/qxcbwindow.h b/src/plugins/platforms/xcb/qxcbwindow.h index f4bd2d96ff..300596845e 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.h +++ b/src/plugins/platforms/xcb/qxcbwindow.h @@ -56,7 +56,6 @@ QT_BEGIN_NAMESPACE class QXcbScreen; class QXcbEGLSurface; class QIcon; - class QXcbWindow : public QXcbObject, public QPlatformWindow { public: @@ -120,6 +119,9 @@ public: void setMask(const QRegion ®ion); #endif // !QT_NO_SHAPE + void setAlertState(bool enabled); + bool isAlertState() const { return m_alertState; } + xcb_window_t xcb_window() const { return m_window; } uint depth() const { return m_depth; } QImage::Format imageFormat() const { return m_imageFormat; } @@ -194,6 +196,7 @@ private: bool m_deferredExpose; bool m_configureNotifyPending; bool m_embedded; + bool m_alertState; xcb_window_t m_netWmUserTimeWindow; QSurfaceFormat m_format; diff --git a/src/widgets/kernel/qapplication_qpa.cpp b/src/widgets/kernel/qapplication_qpa.cpp index 54eb443c43..0d929f367b 100644 --- a/src/widgets/kernel/qapplication_qpa.cpp +++ b/src/widgets/kernel/qapplication_qpa.cpp @@ -55,6 +55,7 @@ #include #include #include +#include #include #include @@ -410,8 +411,17 @@ void QApplication::beep() { } -void QApplication::alert(QWidget *, int) +void QApplication::alert(QWidget *widget, int duration) { + if (widget) { + if (widget->window()->isActiveWindow()&& !widget->window()->windowState() & Qt::WindowMinimized) + return; + if (QWindow *window= QApplicationPrivate::windowForWidget(widget)) + window->alert(duration); + } else { + foreach (QWidget *topLevel, topLevelWidgets()) + QApplication::alert(topLevel, duration); + } } void qt_init(QApplicationPrivate *priv, int type) -- cgit v1.2.3