on xenial help sign in
Give active focus to child surface qml items
8401926Daniel 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
@@ -899,12 +899,13 @@ FocusScope {
899 priv.updateMainAndSideStageIndexes();
899 priv.updateMainAndSideStageIndexes();
900 }
900 }
901 appDelegate.focus = true;
901 appDelegate.focus = true;
902+ priv.focusedAppDelegate = appDelegate;
902 }
903 }
903
904
904 function updateQmlFocusFromMirSurfaceFocus() {
905 function updateQmlFocusFromMirSurfaceFocus() {
905 if (model.window.focused) {
906 if (model.window.focused) {
906 claimFocus();
907 claimFocus();
907− priv.focusedAppDelegate = appDelegate;
908+ decoratedWindow.focus = true;
908 }
909 }
909 }
910 }
910
911
@@ -1807,6 +1808,14 @@ FocusScope {
1807 boundsItem: boundariesForWindowPlacement
1808 boundsItem: boundariesForWindowPlacement
1808
1809
1809 z: childWindowRepeater.count - model.index
1810 z: childWindowRepeater.count - model.index
1811+
1812+ onFocusChanged: {
1813+ if (focus) {
1814+ // some child surface in this tree got focus.
1815+ // Ensure we also have it at the top-level hierarchy
1816+ appDelegate.claimFocus();
1817+ }
1818+ }
1810 }
1819 }
1811 }
1820 }
1812 }
1821 }
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}