on xenial help sign in
Make sure no apps have focus if stage is not active/focused
ee21555Marius Gripsgard
plugins/WindowManager/TopLevelWindowModel.cpp+7
@@ -38,6 +38,7 @@ 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{
42{
42}
43}
43
44
@@ -719,3 +720,9 @@ void TopLevelWindowModel::activateTopMostWindowWithoutId(int forbiddenId)
719 }
720 }
720 }
721 }
721}
722}
723+
724+void TopLevelWindowModel::activateNullWindow()
725+{
726+ m_nullWindow->activate();
727+ m_surfaceManager->activate(nullptr);
728+}
plugins/WindowManager/TopLevelWindowModel.h+6
@@ -164,6 +164,11 @@ public:
164 */
164 */
165 Q_INVOKABLE void raiseId(int id);
165 Q_INVOKABLE void raiseId(int id);
166
166
167+ /**
168+ * @brief Raises and focuses a window with no surface
169+ */
170+ Q_INVOKABLE void activateNullWindow();
171+
167Q_SIGNALS:
172Q_SIGNALS:
168 void countChanged();
173 void countChanged();
169 void inputMethodSurfaceChanged(unity::shell::application::MirSurfaceInterface* inputMethodSurface);
174 void inputMethodSurfaceChanged(unity::shell::application::MirSurfaceInterface* inputMethodSurface);
@@ -239,6 +244,7 @@ private:
239 QVector<ModelEntry> m_windowModel;
244 QVector<ModelEntry> m_windowModel;
240 Window* m_inputMethodWindow{nullptr};
245 Window* m_inputMethodWindow{nullptr};
241 Window* m_focusedWindow{nullptr};
246 Window* m_focusedWindow{nullptr};
247+ Window* m_nullWindow;
242
248
243 int m_nextId{1};
249 int m_nextId{1};
244 // Just something big enough that we don't risk running out of unused id numbers.
250 // Just something big enough that we don't risk running out of unused id numbers.
qml/Launcher/Launcher.qml+7−1
@@ -42,6 +42,7 @@ FocusScope {
42
42
43 property bool superPressed: false
43 property bool superPressed: false
44 property bool superTabPressed: false
44 property bool superTabPressed: false
45+ property bool takesFocus: false;
45
46
46 readonly property bool dragging: dragArea.dragging
47 readonly property bool dragging: dragArea.dragging
47 readonly property real dragDistance: dragArea.dragging ? dragArea.touchPosition.x : 0
48 readonly property real dragDistance: dragArea.dragging ? dragArea.touchPosition.x : 0
@@ -65,6 +66,8 @@ FocusScope {
65 }
66 }
66 }
67 }
67
68
69+ onFocusChanged: {if (!focus) { root.takesFocus = false; }}
70+
68 onSuperPressedChanged: {
71 onSuperPressedChanged: {
69 if (state == "drawer")
72 if (state == "drawer")
70 return;
73 return;
@@ -84,6 +87,7 @@ FocusScope {
84 if (superTabPressed) {
87 if (superTabPressed) {
85 switchToNextState("visible")
88 switchToNextState("visible")
86 panel.highlightIndex = -1;
89 panel.highlightIndex = -1;
90+ root.takesFocus = true;
87 root.focus = true;
91 root.focus = true;
88 superPressTimer.stop();
92 superPressTimer.stop();
89 superLongPressTimer.stop();
93 superLongPressTimer.stop();
@@ -128,6 +132,7 @@ FocusScope {
128 } else {
132 } else {
129 switchToNextState("")
133 switchToNextState("")
130 }
134 }
135+ root.focus = false;
131 }
136 }
132
137
133 function fadeOut() {
138 function fadeOut() {
@@ -164,6 +169,7 @@ FocusScope {
164 function openForKeyboardNavigation() {
169 function openForKeyboardNavigation() {
165 panel.highlightIndex = -1; // The BFB
170 panel.highlightIndex = -1; // The BFB
166 drawer.focus = false;
171 drawer.focus = false;
172+ root.takesFocus = true;
167 root.focus = true;
173 root.focus = true;
168 switchToNextState("visible")
174 switchToNextState("visible")
169 }
175 }
@@ -176,6 +182,7 @@ FocusScope {
176 panel.shortcutHintsShown = false;
182 panel.shortcutHintsShown = false;
177 superPressTimer.stop();
183 superPressTimer.stop();
178 superLongPressTimer.stop();
184 superLongPressTimer.stop();
185+ root.takesFocus = true;
179 root.focus = true;
186 root.focus = true;
180 if (focusInputField) {
187 if (focusInputField) {
181 drawer.focusInput();
188 drawer.focusInput();
@@ -232,7 +239,6 @@ FocusScope {
232 root.hide();
239 root.hide();
233 panel.highlightIndex = -2
240 panel.highlightIndex = -2
234 event.accepted = true;
241 event.accepted = true;
235− root.focus = false;
236 }
242 }
237 }
243 }
238
244
qml/Shell.qml+2−2
@@ -173,6 +173,7 @@ StyledItem {
173 } else {
173 } else {
174 startApp(appId);
174 startApp(appId);
175 }
175 }
176+ stage.focus = true;
176 }
177 }
177
178
178 function activateURL(url) {
179 function activateURL(url) {
@@ -309,8 +310,7 @@ StyledItem {
309 interactive: (!greeter || !greeter.shown)
310 interactive: (!greeter || !greeter.shown)
310 && panel.indicators.fullyClosed
311 && panel.indicators.fullyClosed
311 && !notifications.useModal
312 && !notifications.useModal
312−
313+ && !launcher.takesFocus
313− onInteractiveChanged: { if (interactive) { focus = true; } }
314
314
315 suspended: greeter.shown
315 suspended: greeter.shown
316 altTabPressed: physicalKeysMapper.altTabPressed
316 altTabPressed: physicalKeysMapper.altTabPressed
qml/Stage/Stage.qml+16
@@ -89,6 +89,22 @@ FocusScope {
89 Qt.InvertedLandscapeOrientation;
89 Qt.InvertedLandscapeOrientation;
90 }
90 }
91
91
92+ onInteractiveChanged: {
93+ // Stage must have focus before activating windows, including null
94+ if (interactive) {
95+ focus = true;
96+
97+ // Activate focused app once stage is active again
98+ // this makes sure the focused app have focus
99+ if (priv.focusedAppDelegate) {
100+ priv.focusedAppDelegate.window.activate();
101+ }
102+ } else {
103+ // Activate null window once stage is not active this makes
104+ // sure none of the apps have focus when stage is not active
105+ topLevelSurfaceList.activateNullWindow();
106+ }
107+ }
92
108
93 onAltTabPressedChanged: {
109 onAltTabPressedChanged: {
94 root.focus = true;
110 root.focus = true;
tests/qmltests/tst_Shell.qml+14
@@ -3289,6 +3289,20 @@ Rectangle {
3289 tryCompare(appDelegate2.surface, "activeFocus", true);
3289 tryCompare(appDelegate2.surface, "activeFocus", true);
3290 }
3290 }
3291
3291
3292+ function test_launchFromDrawerPutsFocusOnStage() {
3293+ loadShell("desktop");
3294+ shell.usageScenario = "desktop";
3295+ waitForRendering(shell);
3296+ swipeAwayGreeter();
3297+
3298+ keyClick(Qt.Key_A, Qt.MetaModifier);
3299+ typeString("browser");
3300+ keyClick(Qt.Key_Enter);
3301+
3302+ var appRepeater = findChild(shell, "appRepeater");
3303+ tryCompare(appRepeater.itemAt(0), "activeFocus", true);
3304+ }
3305+
3292 function test_maximizedWindowAndMenuInPanel() {
3306 function test_maximizedWindowAndMenuInPanel() {
3293 loadShell("desktop");
3307 loadShell("desktop");
3294 shell.usageScenario = "desktop";
3308 shell.usageScenario = "desktop";