Merge lp:~dandrader/qtmir/keyState into lp:qtmir

Proposed by Daniel d'Andrada
Status: Superseded
Proposed branch: lp:~dandrader/qtmir/keyState
Merge into: lp:qtmir
Prerequisite: lp:~dandrader/qtmir/allowClientResize
Diff against target: 145 lines (+43/-4)
3 files modified
src/platforms/mirserver/qteventfeeder.cpp (+3/-1)
src/platforms/mirserver/windowmanagementpolicy.cpp (+29/-2)
src/platforms/mirserver/windowmanagementpolicy.h (+11/-1)
To merge this branch: bzr merge lp:~dandrader/qtmir/keyState
Reviewer Review Type Date Requested Status
Gerry Boland (community) Needs Information
Unity8 CI Bot (community) continuous-integration Needs Fixing
Review via email: mp+320373@code.launchpad.net

This proposal has been superseded by a proposal from 2017-03-22.

Commit message

Ensure the window that got a key down also gets the corresponding key up

Otherwise it will be left in a inconsistent state (with a pressed key hanging around).

QQuickWindow's input dispatching doesn't guarantee that for its QQuickItem.
So we have to do it ourselves.

This can happen when qml active focus changes in response to a key press.
Eg: client creates a child window in response to a Ctrl+O. By the time the user
releases the Ctrl, active focus will already be in the child window, so the child window
will get the release event instead of the top-level one.

Description of the change

* Are there any related MPs required for this MP to build/function as expected? Please list.
https://code.launchpad.net/~dandrader/unity8/childWindowFocus/+merge/320044

To post a comment you must log in.
Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Gerry Boland (gerboland) wrote :

If the surface looses active focus, don't we inform Mir? Why not send the key release event then? Would be more efficient than checking on every key_up

Also, please avoid using singleton pattern, it makes testing impossible. And speaking of which, can you add test?

review: Needs Information
Revision history for this message
Daniel d'Andrada (dandrader) wrote :

On 20/03/2017 14:08, Gerry Boland wrote:
> Review: Needs Information
>
> If the surface looses active focus, don't we inform Mir?

It's the other way around. Mir surface focus is what drives qml active
focus. Nowadays qml active focus by itself doesn't carry much meaning in
terms of window management.

> Why not send the key release event then? Would be more efficient than checking on every key_up

Because the key is actually still pressed. If the same window gets focus
again moments later and only then the key is lifted the client would
receive a second key_up event. Unless we keep track of what lies we have
told already to the clients or devise some other special rules.

> Also, please avoid using singleton pattern, it makes testing impossible.

Yeah, that was the easiest (laziest) way to get the two talking (event
feeder and policy). Will see if I can get something nicer. Suggestions?

But before I spend too much time on the implementation details of this
MP I would like to get feedback on the overall approach first.

> And speaking of which, can you add test?

For WindowManagementPolicy?

lp:~dandrader/qtmir/keyState updated
618. By Gerry Boland

Fix FTBFS against miral 1.3.1

Approved by: Daniel d'Andrada, Unity8 CI Bot, Alan Griffiths

619. By Daniel d'Andrada

Implement MirSurface::allowClientResize (LP: #1670390)

Approved by: Gerry Boland, Unity8 CI Bot

620. By Alan Griffiths

Reduce dependencies on mirserver by reworking ../Application/mirbuffersgtexture.cpp and ../Application/surfacemanager.cpp

Approved by: Gerry Boland, Unity8 CI Bot

621. By Gerry Boland

Stop MirSurface deleting itself, ensure SurfaceManager alone manages MirSurface lifetimes. Add SurfaceManager test suite.

This fixes bugs where a MirSurface would call deleteLater on itself, but SurfaceManager would have no idea and keep a pointer to that MirSurface in its internal list.

Instead SurfaceManager listens for signals from both miral and the MirSurface itself to decide when to delete it.

Add a test suite to verify MirSurface lifetimes. (LP: #1655644)

Approved by: Daniel d'Andrada, Unity8 CI Bot

622. By Albert Astals Cid

Check for find() result not being null before using it

We do it in onWindowReady, onWindowMoved, onWindowFocusChanged, etc so no reason to not do it in onWindowRemoved

Approved by: Lukáš Tinkl, Unity8 CI Bot

623. By Gerry Boland

Extend timeouts when running under valgrind

When QMirServer is starting up, it spawns a separate thread for Mir to startup and waits for it. As valgrind slows execution greatly, the QMirServer timeout triggers before Mir has started, causing the QMirServer to think it failed and exit.

This patch adds ability to detect when running under valgrind and extending timeouts to suit.

Approved by: Daniel d'Andrada, Unity8 CI Bot

624. By Andreas Pokorny

Attach MirInputDeviceId and the MirCookie to input events

Similar to the tracking of relative motion the cookie and input device ids of mir events are stored in the EventBuilder for later recovery (LP: #1536279, #1668692)

Approved by: Daniel d'Andrada, Unity8 CI Bot

625. By CI Train Bot Account

Releasing 0.5.1+17.04.20170320.1-0ubuntu1

Revision history for this message
Gerry Boland (gerboland) wrote :

> On 20/03/2017 14:08, Gerry Boland wrote:
> > Review: Needs Information
> >
> > If the surface looses active focus, don't we inform Mir?
>
> It's the other way around. Mir surface focus is what drives qml active
> focus. Nowadays qml active focus by itself doesn't carry much meaning in
> terms of window management.

There are more things in the QML scene that just MirSurfaces that can get activeFocus though. When activeFocus does switch to the search box in the AppDrawer (as example), we are indeed telling Mir somehow that the MirSurface has not got input focus (I just tested gedit, the cursor does stop flashing when the text box in the app drawer is focused). Since this bug occurs due to focus changing while modifier key is down, my initial thinking was we could use the focus change to implement a workaround.

What I don't know is if the WMpolicy if notified when the MirSurface it has selected to be focused has lost actual input focus (activeFocus). Do you know?

> > Why not send the key release event then? Would be more efficient than
> checking on every key_up
>
> Because the key is actually still pressed. If the same window gets focus
> again moments later and only then the key is lifted the client would
> receive a second key_up event. Unless we keep track of what lies we have
> told already to the clients or devise some other special rules.

This appears to be a QML subtlety we're working around, as a non-QML Qt shell would not suffer from this issue, right? So could the MirSurfaceItem keep track of the key state itself? If the MSI looses activeFocus, it send key-release to the client. Then if it gets focus again, check if key is still down (not sure how tbh, maybe QML sends the key to the Item again immediately??), and if so, re-send it to client.

I'm not 100% certain what is the best approach yet.

> > Also, please avoid using singleton pattern, it makes testing impossible.
>
> Yeah, that was the easiest (laziest) way to get the two talking (event
> feeder and policy). Will see if I can get something nicer. Suggestions?

Nothing better than the usual piping an object around, so everyone who needs it gets a pointer to it. Sorry :(

> But before I spend too much time on the implementation details of this
> MP I would like to get feedback on the overall approach first.

Ah ok, I hope I've supplied that at least

>
> > And speaking of which, can you add test?
>
> For WindowManagementPolicy?

More the logic you're adding. But please ignore me until you settle on the approach you want.

Revision history for this message
Daniel d'Andrada (dandrader) wrote :

On 21/03/2017 09:37, Gerry Boland wrote:
> This appears to be a QML subtlety we're working around, as a non-QML Qt shell would not suffer from this issue, right?

Yes. As I said, QQuickWindow input dispatching not perfectly suited for
shells.

> So could the MirSurfaceItem keep track of the key state itself?
Sure.

> If the MSI looses activeFocus, it send key-release to the client. Then if it gets focus again, check if key is still down (not sure how tbh, maybe QML sends the key to the Item again immediately??), and if so, re-send it to client.

It can't check the key state, but it can ignore a key-up for a key that
it didn't tell its surface it was down (because lied or whatever).

> I'm not 100% certain what is the best approach yet.

Working around QQuickWindow input dispatching will never be beautiful. So, should I go for the MirSurfaceItem-based key filtering/manipulation?

I'm fine either way. I put in the policy to avoid sending fake input to clients and as a general rule-of-thumb of "putting things in the miral policy"/"keep the policy in the loop".

Revision history for this message
Gerry Boland (gerboland) wrote :

I think I'd prefer using MirSurfaceItem-based key filtering. Since it's working around the QQuickWindow/QML problem, it makes sense to me to confine the workaround in code only used in code exposed to QQuickWindow/QML.

lp:~dandrader/qtmir/keyState updated
626. By Daniel d'Andrada

merge lp:~gerboland/qtmir/availableDesktopAreaTrial

627. By Daniel d'Andrada

Ensure the window that got a key down also gets the corresponding key up

Otherwise it will be left in a inconsistent state (with a pressed key hanging around).

QQuickWindow's input dispatching doesn't guarantee that for its QQuickItem.
So we have to do it ourselves.

This can happen when qml active focus changes in response to a key press.
Eg: client creates a child window in response to a Ctrl+O. By the time the user
releases the Ctrl, active focus will already be in the child window, so the child window
will get the release event instead of the top-level one.

628. By Daniel d'Andrada

Some refactoring as per review feedback

629. By Daniel d'Andrada

update copyright header

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/platforms/mirserver/qteventfeeder.cpp'
2--- src/platforms/mirserver/qteventfeeder.cpp 2017-01-02 14:41:06 +0000
3+++ src/platforms/mirserver/qteventfeeder.cpp 2017-03-20 15:13:20 +0000
4@@ -1,5 +1,5 @@
5 /*
6- * Copyright (C) 2013-2016 Canonical, Ltd.
7+ * Copyright (C) 2013-2017 Canonical, Ltd.
8 *
9 * This program is free software: you can redistribute it and/or modify it under
10 * the terms of the GNU Lesser General Public License version 3, as published by
11@@ -22,6 +22,7 @@
12 #include "tracepoints.h" // generated from tracepoints.tp
13 #include "screen.h" // NEEDED?
14 #include "screensmodel.h"
15+#include "windowmanagementpolicy.h"
16
17 #include <qpa/qplatforminputcontext.h>
18 #include <qpa/qplatformintegration.h>
19@@ -658,6 +659,7 @@
20 keyType = QEvent::KeyPress;
21 break;
22 case mir_keyboard_action_up:
23+ WindowManagementPolicy::instance()->dispatchKeyUp(kev);
24 keyType = QEvent::KeyRelease;
25 break;
26 default:
27
28=== modified file 'src/platforms/mirserver/windowmanagementpolicy.cpp'
29--- src/platforms/mirserver/windowmanagementpolicy.cpp 2017-03-20 15:13:20 +0000
30+++ src/platforms/mirserver/windowmanagementpolicy.cpp 2017-03-20 15:13:20 +0000
31@@ -35,9 +35,17 @@
32 }
33 }
34
35+WindowManagementPolicy *WindowManagementPolicy::m_instance = nullptr;
36+
37 using namespace qtmir;
38 using namespace mir::geometry;
39
40+
41+WindowManagementPolicy *WindowManagementPolicy::instance()
42+{
43+ return m_instance;
44+}
45+
46 WindowManagementPolicy::WindowManagementPolicy(const miral::WindowManagerTools &tools,
47 qtmir::WindowModelNotifier &windowModel,
48 qtmir::WindowController &windowController,
49@@ -49,12 +57,18 @@
50 , m_appNotifier(appNotifier)
51 , m_eventFeeder(new QtEventFeeder(screensModel))
52 {
53+ m_instance = this;
54 qRegisterMetaType<qtmir::NewWindow>();
55 qRegisterMetaType<std::vector<miral::Window>>();
56 qRegisterMetaType<miral::ApplicationInfo>();
57 windowController.setPolicy(this);
58 }
59
60+WindowManagementPolicy::~WindowManagementPolicy()
61+{
62+ m_instance = nullptr;
63+}
64+
65 /* Following are hooks to allow custom policy be imposed */
66 miral::WindowSpecification WindowManagementPolicy::place_new_window(
67 const miral::ApplicationInfo &appInfo,
68@@ -233,9 +247,11 @@
69 {
70 if (mir_keyboard_event_action(event) == mir_keyboard_action_down) {
71 ensureWindowIsActive(window);
72+ m_keyOwners[mir_keyboard_event_key_code(event)] = window;
73+ dispatchInputEvent(window, mir_keyboard_event_input_event(event));
74+ } else {
75+ // Ignore. We did it already in dispatchKeyUp().
76 }
77-
78- dispatchInputEvent(window, mir_keyboard_event_input_event(event));
79 }
80
81 void WindowManagementPolicy::deliver_touch_event(const MirTouchEvent *event,
82@@ -354,3 +370,14 @@
83 });
84 }
85 }
86+
87+void WindowManagementPolicy::dispatchKeyUp(const MirKeyboardEvent *kev)
88+{
89+ xkb_keysym_t keyCode = mir_keyboard_event_key_code(kev);
90+
91+ auto iterator = m_keyOwners.find(keyCode);
92+ if (iterator != m_keyOwners.end()) {
93+ miral::Window window = iterator.value();
94+ dispatchInputEvent(window, mir_keyboard_event_input_event(kev));
95+ }
96+}
97
98=== modified file 'src/platforms/mirserver/windowmanagementpolicy.h'
99--- src/platforms/mirserver/windowmanagementpolicy.h 2017-02-06 09:10:20 +0000
100+++ src/platforms/mirserver/windowmanagementpolicy.h 2017-03-20 15:13:20 +0000
101@@ -1,5 +1,5 @@
102 /*
103- * Copyright (C) 2016 Canonical, Ltd.
104+ * Copyright (C) 2016-2017 Canonical, Ltd.
105 *
106 * This program is free software: you can redistribute it and/or modify it under
107 * the terms of the GNU Lesser General Public License version 3, as published by
108@@ -24,6 +24,7 @@
109 #include "windowcontroller.h"
110 #include "windowmodelnotifier.h"
111
112+#include <QHash>
113 #include <QScopedPointer>
114 #include <QSize>
115
116@@ -39,6 +40,7 @@
117 qtmir::WindowController &windowController,
118 qtmir::AppNotifier &appNotifier,
119 const QSharedPointer<ScreensModel> screensModel);
120+ virtual ~WindowManagementPolicy();
121
122 // From WindowManagementPolicy
123 auto place_new_window(const miral::ApplicationInfo &app_info,
124@@ -84,6 +86,10 @@
125 void ask_client_to_close(const miral::Window &window);
126 void forceClose(const miral::Window &window);
127
128+ void dispatchKeyUp(const MirKeyboardEvent *kev);
129+
130+ static WindowManagementPolicy *instance();
131+
132 Q_SIGNALS:
133
134 private:
135@@ -93,6 +99,10 @@
136 qtmir::WindowModelNotifier &m_windowModel;
137 qtmir::AppNotifier &m_appNotifier;
138 const QScopedPointer<QtEventFeeder> m_eventFeeder;
139+
140+ QHash<xkb_keysym_t, miral::Window> m_keyOwners;
141+
142+ static WindowManagementPolicy *m_instance;
143 };
144
145 #endif // WINDOWMANAGEMENTPOLICY_H

Subscribers

People subscribed via source and target branches