Merge lp:~nick-dedekind/qtubuntu/1623861.window-focus into lp:qtubuntu

Proposed by Nick Dedekind on 2016-09-21
Status: Merged
Approved by: Daniel d'Andrada on 2016-09-28
Approved revision: 346
Merged at revision: 344
Proposed branch: lp:~nick-dedekind/qtubuntu/1623861.window-focus
Merge into: lp:qtubuntu
Diff against target: 210 lines (+46/-41)
4 files modified
src/ubuntumirclient/input.cpp (+5/-31)
src/ubuntumirclient/input.h (+2/-4)
src/ubuntumirclient/window.cpp (+38/-5)
src/ubuntumirclient/window.h (+1/-1)
To merge this branch: bzr merge lp:~nick-dedekind/qtubuntu/1623861.window-focus
Reviewer Review Type Date Requested Status
Daniel d'Andrada (community) 2016-09-21 Approve on 2016-09-28
Unity8 CI Bot continuous-integration Approve on 2016-09-28
Review via email: mp+306318@code.launchpad.net

Commit Message

Moved focus handling to UbuntuWindow to ensure focus optimization supports multiple windows rather than being application global.

Description of the Change

Moved focus handling to UbuntuWindow to ensure focus optimization supports multiple windows rather than being application global.

 * Are there any related MPs required for this MP to build/function as expected? Please list.
No

 * Did you perform an exploratory manual test run of your code change and any related functionality?
Yes

 * If you changed the packaging (debian), did you subscribe the ubuntu-unity team to this MP?
N/A

To post a comment you must log in.
Unity8 CI Bot (unity8-ci-bot) wrote :

PASSED: Continuous integration, rev:343
https://unity8-jenkins.ubuntu.com/job/lp-qtubuntu-ci/117/
Executed test runs:
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build/2926
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-0-fetch/2954
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=vivid+overlay/2812
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=vivid+overlay/2812/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/2812
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/2812/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=yakkety/2812
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=yakkety/2812/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=vivid+overlay/2812
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=vivid+overlay/2812/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/2812
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/2812/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=yakkety/2812
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=yakkety/2812/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=vivid+overlay/2812
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=vivid+overlay/2812/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/2812
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/2812/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=yakkety/2812
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=yakkety/2812/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://unity8-jenkins.ubuntu.com/job/lp-qtubuntu-ci/117/rebuild

review: Approve (continuous-integration)
Daniel d'Andrada (dandrader) wrote :

Looks good. just one minor thing:

"""
// Mir may have sent a pair of focus lost/gained events, so we need to "peek" into the queue
// so that we don't deactivate windows prematurely.
"""

Please move that comment from UbuntuInput to UbuntuWindow as well (instead of just deleting it). This mPendingFocusGainedEvents scheme is non-obvious and thus deserves a comment.

Your commit message is also too vague. What you did was making the focus-change optimization logic support multiple windows (by moving it to UbuntuWindow and thus making it per-window).

review: Needs Fixing
Nick Dedekind (nick-dedekind) wrote :

> Looks good. just one minor thing:
>
> """
> // Mir may have sent a pair of focus lost/gained events, so we need to "peek"
> into the queue
> // so that we don't deactivate windows prematurely.
> """
>
> Please move that comment from UbuntuInput to UbuntuWindow as well (instead of
> just deleting it). This mPendingFocusGainedEvents scheme is non-obvious and
> thus deserves a comment.

Done

>
> Your commit message is also too vague. What you did was making the focus-
> change optimization logic support multiple windows (by moving it to
> UbuntuWindow and thus making it per-window).

Done

Unity8 CI Bot (unity8-ci-bot) wrote :

PASSED: Continuous integration, rev:344
https://unity8-jenkins.ubuntu.com/job/lp-qtubuntu-ci/126/
Executed test runs:
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build/2975
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-0-fetch/3003
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=vivid+overlay/2861
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=vivid+overlay/2861/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/2861
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/2861/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=yakkety/2861
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=yakkety/2861/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=vivid+overlay/2861
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=vivid+overlay/2861/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/2861
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/2861/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=yakkety/2861
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=yakkety/2861/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=vivid+overlay/2861
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=vivid+overlay/2861/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/2861
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/2861/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=yakkety/2861
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=yakkety/2861/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://unity8-jenkins.ubuntu.com/job/lp-qtubuntu-ci/126/rebuild

review: Approve (continuous-integration)
Daniel d'Andrada (dandrader) wrote :

Thanks!

review: Approve
Unity8 CI Bot (unity8-ci-bot) wrote :

PASSED: Continuous integration, rev:345
https://unity8-jenkins.ubuntu.com/job/lp-qtubuntu-ci/129/
Executed test runs:
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build/2978
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-0-fetch/3006
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=vivid+overlay/2864
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=vivid+overlay/2864/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/2864
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/2864/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=yakkety/2864
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=yakkety/2864/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=vivid+overlay/2864
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=vivid+overlay/2864/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/2864
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/2864/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=yakkety/2864
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=yakkety/2864/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=vivid+overlay/2864
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=vivid+overlay/2864/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/2864
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/2864/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=yakkety/2864
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=yakkety/2864/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://unity8-jenkins.ubuntu.com/job/lp-qtubuntu-ci/129/rebuild

review: Approve (continuous-integration)
Daniel d'Andrada (dandrader) wrote :

Please either rebase on top of lp:~gerboland/qtubuntu/stricter-enums or remove the fix you did in the debug message of UbuntuWindow::handleSurfaceVisibilityChanged (the other branch as a better fix for that message).

Otherwise they will conflict.

review: Needs Fixing
346. By Nick Dedekind on 2016-09-28

removed debug fix

Nick Dedekind (nick-dedekind) wrote :

> Please either rebase on top of lp:~gerboland/qtubuntu/stricter-enums or remove
> the fix you did in the debug message of
> UbuntuWindow::handleSurfaceVisibilityChanged (the other branch as a better fix
> for that message).
>
> Otherwise they will conflict.

removed changed.

Nick Dedekind (nick-dedekind) wrote :

> Please either rebase on top of lp:~gerboland/qtubuntu/stricter-enums or remove
> the fix you did in the debug message of
> UbuntuWindow::handleSurfaceVisibilityChanged (the other branch as a better fix
> for that message).
>
> Otherwise they will conflict.

removed changed.

Daniel d'Andrada (dandrader) wrote :

Merges fine now, thanks!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/ubuntumirclient/input.cpp'
2--- src/ubuntumirclient/input.cpp 2016-08-24 12:40:30 +0000
3+++ src/ubuntumirclient/input.cpp 2016-09-28 10:34:24 +0000
4@@ -188,7 +188,7 @@
5 , mEventFilterType(static_cast<UbuntuNativeInterface*>(
6 integration->nativeInterface())->genericEventFilterType())
7 , mEventType(static_cast<QEvent::Type>(QEvent::registerEventType()))
8- , mLastFocusedWindow(nullptr)
9+ , mLastInputWindow(nullptr)
10 {
11 // Initialize touch device.
12 mTouchDevice = new QTouchDevice;
13@@ -300,17 +300,6 @@
14 {
15 QWindow *window = platformWindow->window();
16
17- const auto eventType = mir_event_get_type(event);
18- if (mir_event_type_surface == eventType) {
19- auto surfaceEvent = mir_event_get_surface_event(event);
20- if (mir_surface_attrib_focus == mir_surface_event_get_attribute(surfaceEvent)) {
21- const bool focused = mir_surface_event_get_attribute_value(surfaceEvent) == mir_surface_focused;
22- if (focused) {
23- mPendingFocusGainedEvents++;
24- }
25- }
26- }
27-
28 QCoreApplication::postEvent(this, new UbuntuEvent(
29 platformWindow, event, mEventType));
30
31@@ -370,7 +359,7 @@
32 switch (touch_action)
33 {
34 case mir_touch_action_down:
35- mLastFocusedWindow = window;
36+ mLastInputWindow = window;
37 touchPoint.state = Qt::TouchPointPressed;
38 break;
39 case mir_touch_action_up:
40@@ -452,7 +441,7 @@
41 ? QEvent::KeyRelease : QEvent::KeyPress;
42
43 if (action == mir_keyboard_action_down)
44- mLastFocusedWindow = window;
45+ mLastInputWindow = window;
46
47 QString text;
48 QVarLengthArray<char, 32> chars(32);
49@@ -605,23 +594,8 @@
50
51 switch (surfaceEventAttribute) {
52 case mir_surface_attrib_focus: {
53- const bool focused = mir_surface_event_get_attribute_value(event) == mir_surface_focused;
54- // Mir may have sent a pair of focus lost/gained events, so we need to "peek" into the queue
55- // so that we don't deactivate windows prematurely.
56- if (focused) {
57- mPendingFocusGainedEvents--;
58- QWindowSystemInterface::handleWindowActivated(window->window(), Qt::ActiveWindowFocusReason);
59-
60- // NB: Since processing of system events is queued, never check qGuiApp->applicationState()
61- // as it might be outdated. Always call handleApplicationStateChanged() with the latest
62- // state regardless.
63- QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationActive);
64-
65- } else if(!mPendingFocusGainedEvents) {
66- qCDebug(ubuntumirclient, "No windows have focus");
67- QWindowSystemInterface::handleWindowActivated(nullptr, Qt::ActiveWindowFocusReason);
68- QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationInactive);
69- }
70+ window->handleSurfaceFocusChanged(
71+ mir_surface_event_get_attribute_value(event) == mir_surface_focused);
72 break;
73 }
74 case mir_surface_attrib_visibility:
75
76=== modified file 'src/ubuntumirclient/input.h'
77--- src/ubuntumirclient/input.h 2016-04-28 14:58:55 +0000
78+++ src/ubuntumirclient/input.h 2016-09-28 10:34:24 +0000
79@@ -19,7 +19,6 @@
80
81 // Qt
82 #include <qpa/qwindowsysteminterface.h>
83-#include <QAtomicInt>
84 #include <QLoggingCategory>
85
86 #include <mir_toolkit/mir_client_library.h>
87@@ -40,7 +39,7 @@
88
89 void postEvent(UbuntuWindow* window, const MirEvent *event);
90 UbuntuClientIntegration* integration() const { return mIntegration; }
91- UbuntuWindow *lastFocusedWindow() const {return mLastFocusedWindow; }
92+ UbuntuWindow *lastInputWindow() const {return mLastInputWindow; }
93
94 protected:
95 void dispatchKeyEvent(UbuntuWindow *window, const MirInputEvent *event);
96@@ -58,8 +57,7 @@
97 const QByteArray mEventFilterType;
98 const QEvent::Type mEventType;
99
100- UbuntuWindow *mLastFocusedWindow;
101- QAtomicInt mPendingFocusGainedEvents;
102+ UbuntuWindow *mLastInputWindow;
103 };
104
105 #endif // UBUNTU_INPUT_H
106
107=== modified file 'src/ubuntumirclient/window.cpp'
108--- src/ubuntumirclient/window.cpp 2016-08-31 01:51:15 +0000
109+++ src/ubuntumirclient/window.cpp 2016-09-28 10:34:24 +0000
110@@ -27,8 +27,10 @@
111 #include <qpa/qwindowsysteminterface.h>
112 #include <QMutexLocker>
113 #include <QSize>
114+#include <QAtomicInt>
115 #include <QtMath>
116 #include <private/qeglconvenience_p.h>
117+#include <private/qguiapplication_p.h>
118
119 // Platform API
120 #include <ubuntu/application/instance.h>
121@@ -179,7 +181,7 @@
122 //NOTE: We cannot have a parentless popup -
123 //try using the last surface to receive input as that will most likely be
124 //the one that caused this popup to be created
125- parent = input->lastFocusedWindow();
126+ parent = input->lastInputWindow();
127 }
128 if (parent) {
129 auto pos = geom.topLeft();
130@@ -399,6 +401,7 @@
131 QSurfaceFormat format() const { return mFormat; }
132
133 bool mNeedsExposeCatchup;
134+ QAtomicInt mPendingFocusGainedEvents;
135
136 QString persistentSurfaceId();
137
138@@ -549,7 +552,8 @@
139
140 void UbuntuSurface::postEvent(const MirEvent *event)
141 {
142- if (mir_event_type_resize == mir_event_get_type(event)) {
143+ const auto eventType = mir_event_get_type(event);
144+ if (mir_event_type_resize == eventType) {
145 // TODO: The current event queue just accumulates all resize events;
146 // It would be nicer if we could update just one event if that event has not been dispatched.
147 // As a workaround, we use the width/height as an identifier of this latest event
148@@ -562,6 +566,14 @@
149 QMutexLocker lock(&mTargetSizeMutex);
150 mTargetSize.rwidth() = width;
151 mTargetSize.rheight() = height;
152+ } else if (mir_event_type_surface == eventType) {
153+ auto surfaceEvent = mir_event_get_surface_event(event);
154+ if (mir_surface_attrib_focus == mir_surface_event_get_attribute(surfaceEvent)) {
155+ const bool focused = mir_surface_event_get_attribute_value(surfaceEvent) == mir_surface_focused;
156+ if (focused) {
157+ mPendingFocusGainedEvents++;
158+ }
159+ }
160 }
161
162 mInput->postEvent(mPlatformWindow, event);
163@@ -647,10 +659,31 @@
164 QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(), geometry().size()));
165 }
166
167-void UbuntuWindow::handleSurfaceFocused()
168+void UbuntuWindow::handleSurfaceFocusChanged(bool focused)
169 {
170- qCDebug(ubuntumirclient, "handleSurfaceFocused(window=%p)", window());
171-
172+ qCDebug(ubuntumirclient, "handleSurfaceFocusChanged(window=%p, focused=%d, pending=%d)", window(), focused, mSurface->mPendingFocusGainedEvents.load());
173+
174+ // Mir may have sent a pair of focus lost/gained events, so we need to "peek" into the queue
175+ // so that we don't deactivate windows prematurely.
176+ if (focused) {
177+ mSurface->mPendingFocusGainedEvents--;
178+ QWindowSystemInterface::handleWindowActivated(window(), Qt::ActiveWindowFocusReason);
179+
180+ // NB: Since processing of system events is queued, never check qGuiApp->applicationState()
181+ // as it might be outdated. Always call handleApplicationStateChanged() with the latest
182+ // state regardless.
183+ QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationActive);
184+
185+ // Flush events so that we update QGuiApplicationPrivate::focus_window immediately
186+ QWindowSystemInterface::flushWindowSystemEvents();
187+
188+ } else if (mSurface->mPendingFocusGainedEvents == 0 && window() == QGuiApplicationPrivate::focus_window) {
189+ QWindowSystemInterface::handleWindowActivated(nullptr, Qt::ActiveWindowFocusReason);
190+ QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationInactive);
191+
192+ // Flush events so that we update QGuiApplicationPrivate::focus_window immediately
193+ QWindowSystemInterface::flushWindowSystemEvents();
194+ }
195 }
196
197 void UbuntuWindow::handleSurfaceVisibilityChanged(bool visible)
198
199=== modified file 'src/ubuntumirclient/window.h'
200--- src/ubuntumirclient/window.h 2016-08-24 12:40:30 +0000
201+++ src/ubuntumirclient/window.h 2016-09-28 10:34:24 +0000
202@@ -63,7 +63,7 @@
203 MirSurface *mirSurface() const;
204 void handleSurfaceResized(int width, int height);
205 void handleSurfaceExposeChange(bool exposed);
206- void handleSurfaceFocused();
207+ void handleSurfaceFocusChanged(bool focused);
208 void handleSurfaceVisibilityChanged(bool visible);
209 void handleSurfaceStateChanged(Qt::WindowState state);
210 void onSwapBuffersDone();

Subscribers

People subscribed via source and target branches