on xenial help sign in
Give active focus to child surface qml items (LP: #1671072)
31e4f4bDaniel d'Andrada
qml/Stage/ChildWindow.qml+4−1
@@ -18,8 +18,9 @@ import QtQuick 2.4
18import Ubuntu.Components 1.3
18import Ubuntu.Components 1.3
19import Unity.Application 0.1
19import Unity.Application 0.1
20
20
21−Item {
21+FocusScope {
22 id: root
22 id: root
23+ objectName: "childWindow"
23
24
24 // Set from outside.
25 // Set from outside.
25 property var surface
26 property var surface
@@ -141,6 +142,8 @@ Item {
141 // TODO ChildWindow parent will probably want to control those
142 // TODO ChildWindow parent will probably want to control those
142 interactive: true
143 interactive: true
143 consumesInput: true
144 consumesInput: true
145+
146+ focus: true
144 }
147 }
145
148
146 Loader {
149 Loader {
qml/Stage/ChildWindowRepeater.qml+12−1
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright (C) 2016 Canonical, Ltd.
2+ * Copyright (C) 2016-2017 Canonical, Ltd.
3 *
3 *
4 * This program is free software; you can redistribute it and/or modify
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
5 * it under the terms of the GNU General Public License as published by
@@ -21,8 +21,19 @@ Repeater {
21 id: root
21 id: root
22 property Item boundsItem
22 property Item boundsItem
23 delegate: ChildWindowTree {
23 delegate: ChildWindowTree {
24+ id: childWindowTree
24 surface: model.surface
25 surface: model.surface
25 z: root.count - model.index
26 z: root.count - model.index
26 boundsItem: root.boundsItem
27 boundsItem: root.boundsItem
28+ Connections {
29+ target: childWindowTree.surface
30+ onFocusedChanged: {
31+ if (childWindowTree.surface.focused) {
32+ childWindowTree.focus = true;
33+ // focus the Loader
34+ childWindowTree.parent.focus = true;
35+ }
36+ }
37+ }
27 }
38 }
28}
39}
qml/Stage/ChildWindowTree.qml+16−2
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright (C) 2016 Canonical, Ltd.
2+ * Copyright (C) 2016-2017 Canonical, Ltd.
3 *
3 *
4 * This program is free software; you can redistribute it and/or modify
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
5 * it under the terms of the GNU General Public License as published by
@@ -18,7 +18,7 @@ import QtQuick 2.4
18import Ubuntu.Components 1.3
18import Ubuntu.Components 1.3
19import Unity.Application 0.1
19import Unity.Application 0.1
20
20
21−Item {
21+FocusScope {
22 id: root
22 id: root
23
23
24 property alias surface: childWindow.surface
24 property alias surface: childWindow.surface
@@ -100,6 +100,13 @@ Item {
100 onFocusRequested: {
100 onFocusRequested: {
101 root.surface.activate();
101 root.surface.activate();
102 }
102 }
103+ onFocusedChanged: {
104+ if (root.surface.focused) {
105+ childWindow.focus = true;
106+ // Propagate
107+ root.focus = true;
108+ }
109+ }
103 }
110 }
104
111
105 // Using a loader here mainly to circunvent the "ChildWindowTree is instantiated recursively" error from the QML engine
112 // Using a loader here mainly to circunvent the "ChildWindowTree is instantiated recursively" error from the QML engine
@@ -119,5 +126,12 @@ Item {
119 property: "boundsItem"
126 property: "boundsItem"
120 value: root.boundsItem
127 value: root.boundsItem
121 }
128 }
129+ onFocusChanged: {
130+ if (focus) {
131+ // A surface in some ChildWindowTree got focused.
132+ // Propagate
133+ root.focus = true;
134+ }
135+ }
122 }
136 }
123}
137}
qml/Stage/Stage.qml+10−1
@@ -919,12 +919,13 @@ FocusScope {
919 priv.updateMainAndSideStageIndexes();
919 priv.updateMainAndSideStageIndexes();
920 }
920 }
921 appDelegate.focus = true;
921 appDelegate.focus = true;
922+ priv.focusedAppDelegate = appDelegate;
922 }
923 }
923
924
924 function updateQmlFocusFromMirSurfaceFocus() {
925 function updateQmlFocusFromMirSurfaceFocus() {
925 if (model.window.focused) {
926 if (model.window.focused) {
926 claimFocus();
927 claimFocus();
927− priv.focusedAppDelegate = appDelegate;
928+ decoratedWindow.focus = true;
928 }
929 }
929 }
930 }
930
931
@@ -1828,6 +1829,14 @@ FocusScope {
1828 boundsItem: boundariesForWindowPlacement
1829 boundsItem: boundariesForWindowPlacement
1829
1830
1830 z: childWindowRepeater.count - model.index
1831 z: childWindowRepeater.count - model.index
1832+
1833+ onFocusChanged: {
1834+ if (focus) {
1835+ // some child surface in this tree got focus.
1836+ // Ensure we also have it at the top-level hierarchy
1837+ appDelegate.claimFocus();
1838+ }
1839+ }
1831 }
1840 }
1832 }
1841 }
1833 }
1842 }
tests/mocks/Unity/Application/MirSurface.cpp+5
@@ -452,6 +452,11 @@ void MirSurface::setHeightIncrement(int value)
452void MirSurface::close()
452void MirSurface::close()
453{
453{
454 DEBUG_MSG("");
454 DEBUG_MSG("");
455+
456+ for (int i = 0; i < m_childSurfaceList->count(); ++i) {
457+ m_childSurfaceList->get(i)->close();
458+ }
459+
455 if (!m_zombieTimer.isActive()) {
460 if (!m_zombieTimer.isActive()) {
456 m_zombieTimer.start();
461 m_zombieTimer.start();
457 Q_EMIT closeRequested();
462 Q_EMIT closeRequested();
tests/qmltests/Stage/tst_DesktopStage.qml+10
@@ -1057,5 +1057,15 @@ Item {
1057 tap(maxButton);
1057 tap(maxButton);
1058 tryCompare(appDelegate, "state", "maximized");
1058 tryCompare(appDelegate, "state", "maximized");
1059 }
1059 }
1060+
1061+ function test_childWindowGetsActiveFocus() {
1062+ var appDelegate = startApplication("kate");
1063+ appDelegate.surface.openDialog(units.gu(5), units.gu(5), units.gu(30), units.gu(30));
1064+ var childWindow = findChild(appDelegate, "childWindow");
1065+ verify(childWindow);
1066+ var surfaceItem = findChild(childWindow, "surfaceItem");
1067+ verify(surfaceItem);
1068+ tryCompare(surfaceItem, "activeFocus", true);
1069+ }
1060 }
1070 }
1061}
1071}