on xenial help sign in
TopLevelWindowModel: Don't refocus closed Window
7028320Dalton Durst
plugins/WindowManager/TopLevelWindowModel.cpp+19−2
@@ -38,7 +38,8 @@ Q_LOGGING_CATEGORY(TOPLEVELWINDOWMODEL, "toplevelwindowmodel", QtInfoMsg)
38namespace unityapi = unity::shell::application;
38namespace unityapi = unity::shell::application;
39
39
40TopLevelWindowModel::TopLevelWindowModel()
40TopLevelWindowModel::TopLevelWindowModel()
41− : m_nullWindow(createWindow(nullptr))
41+ : m_nullWindow(createWindow(nullptr)),
42+ m_surfaceManagerBusy(false)
42{
43{
43 connect(m_nullWindow, &Window::focusedChanged, this, [this] {
44 connect(m_nullWindow, &Window::focusedChanged, this, [this] {
44 Q_EMIT rootFocusChanged();
45 Q_EMIT rootFocusChanged();
@@ -439,6 +440,10 @@ void TopLevelWindowModel::removeAt(int index)
439 setFocusedWindow(nullptr);
440 setFocusedWindow(nullptr);
440 }
441 }
441
442
443+ if (m_previousWindow == window) {
444+ m_previousWindow = nullptr;
445+ }
446+
442 if (m_closingAllApps) {
447 if (m_closingAllApps) {
443 if (m_windowModel.isEmpty()) {
448 if (m_windowModel.isEmpty()) {
444 Q_EMIT closedAllWindows();
449 Q_EMIT closedAllWindows();
@@ -709,6 +714,7 @@ void TopLevelWindowModel::move(int from, int to)
709}
714}
710void TopLevelWindowModel::onModificationsStarted()
715void TopLevelWindowModel::onModificationsStarted()
711{
716{
717+ m_surfaceManagerBusy = true;
712}
718}
713
719
714void TopLevelWindowModel::onModificationsEnded()
720void TopLevelWindowModel::onModificationsEnded()
@@ -719,6 +725,7 @@ void TopLevelWindowModel::onModificationsEnded()
719 // reset
725 // reset
720 m_focusedWindowChanged = false;
726 m_focusedWindowChanged = false;
721 m_newlyFocusedWindow = nullptr;
727 m_newlyFocusedWindow = nullptr;
728+ m_surfaceManagerBusy = false;
722}
729}
723
730
724void TopLevelWindowModel::activateTopMostWindowWithoutId(int forbiddenId)
731void TopLevelWindowModel::activateTopMostWindowWithoutId(int forbiddenId)
@@ -754,7 +761,14 @@ bool TopLevelWindowModel::rootFocus()
754
761
755void TopLevelWindowModel::setRootFocus(bool focus)
762void TopLevelWindowModel::setRootFocus(bool focus)
756{
763{
757− INFO_MSG << "(" << focus << ")";
764+ INFO_MSG << "(" << focus << "), surfaceManagerBusy is " << m_surfaceManagerBusy;
765+
766+ if (m_surfaceManagerBusy) {
767+ // Something else is probably being focused already, let's not add to
768+ // the noise.
769+ return;
770+ }
771+
758 if (focus) {
772 if (focus) {
759 // Give focus back to previous focused window, only if null window is focused.
773 // Give focus back to previous focused window, only if null window is focused.
760 // If null window is not focused, a different app had taken the focus and we
774 // If null window is not focused, a different app had taken the focus and we
@@ -762,6 +776,9 @@ void TopLevelWindowModel::setRootFocus(bool focus)
762 if (m_previousWindow && !m_previousWindow->focused() && !m_pendingActivation &&
776 if (m_previousWindow && !m_previousWindow->focused() && !m_pendingActivation &&
763 m_nullWindow == m_focusedWindow && m_previousWindow != m_nullWindow) {
777 m_nullWindow == m_focusedWindow && m_previousWindow != m_nullWindow) {
764 m_previousWindow->activate();
778 m_previousWindow->activate();
779+ } else if (!m_pendingActivation) {
780+ // The previous window does not exist any more, focus top window.
781+ activateTopMostWindowWithoutId(-1);
765 }
782 }
766 } else {
783 } else {
767 if (!m_nullWindow->focused()) {
784 if (!m_nullWindow->focused()) {
plugins/WindowManager/TopLevelWindowModel.h+4
@@ -103,6 +103,9 @@ class WINDOWMANAGERQML_EXPORT TopLevelWindowModel : public QAbstractListModel
103 * Setting rootFocus attempts to focus the Window which was focused last -
103 * Setting rootFocus attempts to focus the Window which was focused last -
104 * unless another app is attempting to gain focus (as determined by
104 * unless another app is attempting to gain focus (as determined by
105 * pendingActivation) and that's why we got rootFocus.
105 * pendingActivation) and that's why we got rootFocus.
106+ *
107+ * If the previously-focused Window was closed before rootFocus was set,
108+ * the next available window will be focused.
106 */
109 */
107 Q_PROPERTY(bool rootFocus READ rootFocus WRITE setRootFocus NOTIFY rootFocusChanged)
110 Q_PROPERTY(bool rootFocus READ rootFocus WRITE setRootFocus NOTIFY rootFocusChanged)
108
111
@@ -286,6 +289,7 @@ private:
286
289
287 unity::shell::application::ApplicationManagerInterface* m_applicationManager{nullptr};
290 unity::shell::application::ApplicationManagerInterface* m_applicationManager{nullptr};
288 unity::shell::application::SurfaceManagerInterface *m_surfaceManager{nullptr};
291 unity::shell::application::SurfaceManagerInterface *m_surfaceManager{nullptr};
292+ bool m_surfaceManagerBusy;
289
293
290 enum ModelState {
294 enum ModelState {
291 IdleState,
295 IdleState,
tests/qmltests/Stage/tst_PhoneStage.qml+27
@@ -592,5 +592,32 @@ Item {
592 compare(topLevelSurfaceList.idAt(0), webbrowserSurfaceId);
592 compare(topLevelSurfaceList.idAt(0), webbrowserSurfaceId);
593 compare(webbrowserApp.focused, true);
593 compare(webbrowserApp.focused, true);
594 }
594 }
595+
596+ /*
597+ Ensure that closing a surface while rootFocus is off focuses the
598+ next available surface when rootFocus is given back.
599+
600+ Regression test for https://github.com/ubports/unity8/issues/234
601+
602+ This cannot be tested in tst_TopLevelWindowModel.cpp, the mocks for
603+ it are not advanced enough.
604+ */
605+ function test_closeFocusedAppWithSpreadOpen()
606+ {
607+ var dashApp = ApplicationManager.findApplication("unity8-dash");
608+ var webbrowserSurfaceId = topLevelSurfaceList.nextId;
609+ var webbrowserApp = ApplicationManager.startApplication("morph-browser");
610+ waitUntilAppSurfaceShowsUp(webbrowserSurfaceId);
611+
612+ topLevelSurfaceList.rootFocus = false;
613+
614+ performEdgeSwipeToShowAppSpread();
615+
616+ swipeSurfaceUpwards(webbrowserSurfaceId);
617+ tryCompareFunction(function() { return topLevelSurfaceList.indexForId(webbrowserSurfaceId); }, -1);
618+
619+ topLevelSurfaceList.rootFocus = true;
620+ compare(dashApp.focused, true);
621+ }
595 }
622 }
596}
623}