on xenial help sign in
Avoid showing the shutdown dialog when turning on the screen if your device is under heavy load.

Specifically, we actually watch the timestamp of input events as they come in to determine how long it's been. This means that if for whatever reason, processing of events get delayed, we don't misinterpret user input. To test this, try running the following command and then turning the screen on and off again: sudo cpulimit -l 1 -c 1 -p `ps ax | grep dbus-daemon | head -n 1 | awk '{print $1;}'` Without this branch, you'll notice that at some point, you see the shutdown dialog in error. Because unity8 couldn't keep up with events and thought 2s passed between power-pressed and power-released events. But if we watch the timestamps, we can avoid that particular fate. Fixes: #1508563 Approved by: Albert Astals Cid, Michael Zanetti

commit30e803cfb79d041cae1d9c3d723bc62c9dab9b56 authorMichael Terry <michael.terry@canonical.com> dateWed 4 Nov 2015, 14:58 (11 years ago) parent00e2272bb1e52c
5 files changed+47−32
plugins/Utils/windowkeysfilter.cpp+15−1 plugins/Utils/windowkeysfilter.h+7 qml/Components/PhysicalKeysMapper.qml+13−20 qml/Shell.qml+2−2 tests/qmltests/Components/tst_PhysicalKeysMapper.qml+10−9
plugins/Utils/windowkeysfilter.cpp+15−1
@@ -21,7 +21,8 @@
2121#include <QQuickWindow>
2222
2323WindowKeysFilter::WindowKeysFilter(QQuickItem *parent)
24− : QQuickItem(parent)
24+ : QQuickItem(parent),
25+ m_currentEventTimestamp(0)
2526{
2627 connect(this, &QQuickItem::windowChanged,
2728 this, &WindowKeysFilter::setupFilterOnWindow);
@@ -36,7 +37,15 @@ bool WindowKeysFilter::eventFilter(QObject *watched, QEvent *event)
3637 if (event->type() == QEvent::KeyPress || event->type() == QEvent::KeyRelease) {
3738 // Let QML see this event and decide if it does not want it
3839 event->accept();
40+
41+ m_currentEventTimestamp = static_cast<QInputEvent*>(event)->timestamp();
42+ Q_EMIT currentEventTimestampChanged();
43+
3944 QCoreApplication::sendEvent(this, event);
45+
46+ m_currentEventTimestamp = 0;
47+ Q_EMIT currentEventTimestampChanged();
48+
4049 return event->isAccepted();
4150 } else {
4251 // Not interested
@@ -56,3 +65,8 @@ void WindowKeysFilter::setupFilterOnWindow(QQuickWindow *window)
5665 m_filteredWindow = window;
5766 }
5867}
68+
69+ulong WindowKeysFilter::currentEventTimestamp() const
70+{
71+ return m_currentEventTimestamp;
72+}
plugins/Utils/windowkeysfilter.h+7
@@ -36,16 +36,23 @@
3636class WindowKeysFilter : public QQuickItem
3737{
3838 Q_OBJECT
39+ Q_PROPERTY(ulong currentEventTimestamp READ currentEventTimestamp NOTIFY currentEventTimestampChanged)
3940public:
4041 WindowKeysFilter(QQuickItem *parent = 0);
4142
4243 bool eventFilter(QObject *watched, QEvent *event) override;
4344
45+ ulong currentEventTimestamp() const;
46+
47+Q_SIGNALS:
48+ void currentEventTimestampChanged();
49+
4450private Q_SLOTS:
4551 void setupFilterOnWindow(QQuickWindow *window);
4652
4753private:
4854 QPointer<QQuickWindow> m_filteredWindow;
55+ ulong m_currentEventTimestamp;
4956};
5057
5158#endif // UNITY_WINDOWKEYSFILTER_H
qml/Components/PhysicalKeysMapper.qml+13−20
@@ -57,27 +57,20 @@ Item {
5757
5858 property bool altPressed: false
5959 property bool altTabPressed: false
60− }
6160
62− Timer {
63− id: powerKeyLongPressTimer
64− interval: root.powerKeyLongPressTime
65− onTriggered: root.powerKeyLongPressed();
61+ property var powerButtonPressStart: 0
6662 }
6763
68− function onKeyPressed(event) {
69− if ((event.key == Qt.Key_PowerDown || event.key == Qt.Key_PowerOff)
70− && (!event.isAutoRepeat || !powerKeyLongPressTimer.running)) {
71−
72− // FIXME: We only consider power key presses if the screen is
73− // on because of bugs 1410830/1409003. The theory is that when
74− // those bugs are encountered, there is a >2s delay between the
75− // power press event and the power release event, which causes
76− // the shutdown dialog to appear on resume. So to avoid that
77− // symptom while we investigate the root cause, we simply won't
78− // initiate any dialogs when the screen is off.
79− if (Powerd.status === Powerd.On) {
80− powerKeyLongPressTimer.restart();
64+ function onKeyPressed(event, currentEventTimestamp) {
65+ if (event.key == Qt.Key_PowerDown || event.key == Qt.Key_PowerOff) {
66+ if (event.isAutoRepeat) {
67+ if (d.powerButtonPressStart > 0
68+ && currentEventTimestamp - d.powerButtonPressStart >= powerKeyLongPressTime) {
69+ d.powerButtonPressStart = 0;
70+ root.powerKeyLongPressed();
71+ }
72+ } else {
73+ d.powerButtonPressStart = currentEventTimestamp;
8174 }
8275 } else if ((event.key == Qt.Key_MediaTogglePlayPause || event.key == Qt.Key_MediaPlay) && !event.isAutoRepeat) {
8376 event.accepted = callManager.handleMediaKey(false);
@@ -113,9 +106,9 @@ Item {
113106 }
114107 }
115108
116− function onKeyReleased(event) {
109+ function onKeyReleased(event, currentEventTimestamp) {
117110 if (event.key == Qt.Key_PowerDown || event.key == Qt.Key_PowerOff) {
118− powerKeyLongPressTimer.stop();
111+ d.powerButtonPressStart = 0;
119112 event.accepted = true;
120113 } else if (event.key == Qt.Key_VolumeDown) {
121114 if (!d.ignoreVolumeEvents) root.volumeDownTriggered();
qml/Shell.qml+2−2
@@ -172,8 +172,8 @@ Item {
172172 }
173173
174174 WindowKeysFilter {
175− Keys.onPressed: physicalKeysMapper.onKeyPressed(event);
176− Keys.onReleased: physicalKeysMapper.onKeyReleased(event);
175+ Keys.onPressed: physicalKeysMapper.onKeyPressed(event, currentEventTimestamp);
176+ Keys.onReleased: physicalKeysMapper.onKeyReleased(event, currentEventTimestamp);
177177 }
178178
179179 HomeKeyWatcher {
tests/qmltests/Components/tst_PhysicalKeysMapper.qml+10−9
@@ -67,26 +67,27 @@ TestCase {
6767 Powerd.setStatus(data.status, Powerd.Unknown);
6868 physicalKeysMapper.powerKeyLongPressTime = 500;
6969
70− physicalKeysMapper.onKeyPressed({ key: Qt.Key_PowerDown, isAutoRepeat: false });
70+ physicalKeysMapper.onKeyPressed({ key: Qt.Key_PowerDown, isAutoRepeat: false }, 100);
7171
7272 // After the first key press the screen is always on
7373 // and the rest of keypresses are auto repeat
7474 Powerd.setStatus(Powerd.On, Powerd.Unknown);
7575
76− for (var i = 0; i < 3; ++i) {
77− wait(10);
78− physicalKeysMapper.onKeyPressed({ key: Qt.Key_PowerDown, isAutoRepeat: true});
79− }
76+ physicalKeysMapper.onKeyPressed({ key: Qt.Key_PowerDown, isAutoRepeat: true}, 300);
77+ physicalKeysMapper.onKeyPressed({ key: Qt.Key_PowerDown, isAutoRepeat: true}, 400);
78+ physicalKeysMapper.onKeyPressed({ key: Qt.Key_PowerDown, isAutoRepeat: true}, 500);
79+ physicalKeysMapper.onKeyPressed({ key: Qt.Key_PowerDown, isAutoRepeat: true}, 599);
8080
8181 // powerKeyLongPressed should not have been emitted yet.
8282 compare(powerSpy.count, 0);
8383
84− for (var i = 0; i < 10; ++i) {
85− wait(50);
86− physicalKeysMapper.onKeyPressed({ key: Qt.Key_PowerDown, isAutoRepeat: true});
87− }
84+ physicalKeysMapper.onKeyPressed({ key: Qt.Key_PowerDown, isAutoRepeat: true}, 600);
8885
8986 compare(powerSpy.count, 1);
87+
88+ // Confirm we only emit once
89+ physicalKeysMapper.onKeyPressed({ key: Qt.Key_PowerDown, isAutoRepeat: true}, 601);
90+ compare(powerSpy.count, 1);
9091 }
9192
9293 function test_screenshotButtons_data() {