on xenial help sign in
Add InputMethod to secondary screen
0354171Michael Zanetti
qml/Components/InputMethod.qml+1−1
@@ -59,7 +59,7 @@ Item {
59 }
59 }
60
60
61 state: {
61 state: {
62− if (surfaceItem.surface && surfaceItem.surfaceState != Mir.MinimizedState) {
62+ if (surfaceItem.surface && surfaceItem.surfaceState != Mir.MinimizedState && root.enabled) {
63 return "shown";
63 return "shown";
64 } else {
64 } else {
65 return "hidden";
65 return "hidden";
qml/DisabledScreenNotice.qml+7−4
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright (C) 2015 Canonical, Ltd.
2+ * Copyright (C) 2016 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
@@ -19,15 +19,12 @@ import QtQuick.Layouts 1.1
19import Ubuntu.Components 1.3
19import Ubuntu.Components 1.3
20import QtQuick.Window 2.2
20import QtQuick.Window 2.2
21import "Components"
21import "Components"
22−import "Rotation"
23
22
24Item {
23Item {
25 id: root
24 id: root
26
25
27 property bool infoNoteDisplayed: true
26 property bool infoNoteDisplayed: true
28
27
29− property int physicalOrientation: Screen.orientation
30−
31 WallpaperResolver {
28 WallpaperResolver {
32 width: root.width
29 width: root.width
33 id: wallpaperResolver
30 id: wallpaperResolver
@@ -95,5 +92,11 @@ Item {
95 wrapMode: Text.Wrap
92 wrapMode: Text.Wrap
96 }
93 }
97 }
94 }
95+
96+ InputMethod {
97+ id: inputMethod
98+ objectName: "inputMethod"
99+ anchors.fill: parent
100+ }
98 }
101 }
99}
102}
qml/OrientedShell.qml+17−10
@@ -18,6 +18,7 @@ import QtQuick 2.4
18import QtQuick.Window 2.2
18import QtQuick.Window 2.2
19import Unity.InputInfo 0.1
19import Unity.InputInfo 0.1
20import Unity.Session 0.1
20import Unity.Session 0.1
21+import Unity.Screens 0.1
21import GSettings 1.0
22import GSettings 1.0
22import "Components"
23import "Components"
23import "Rotation"
24import "Rotation"
@@ -78,6 +79,15 @@ Rectangle {
78 deviceFilter: InputInfo.Keyboard
79 deviceFilter: InputInfo.Keyboard
79 }
80 }
80
81
82+ InputDeviceModel {
83+ id: touchScreensModel
84+ deviceFilter: InputInfo.TouchScreen
85+ }
86+
87+ Screens {
88+ id: screens
89+ }
90+
81 property int orientation
91 property int orientation
82 onPhysicalOrientationChanged: {
92 onPhysicalOrientationChanged: {
83 if (!orientationLocked) {
93 if (!orientationLocked) {
@@ -97,8 +107,7 @@ Rectangle {
97 }
107 }
98 // We need to manually update this on startup as the binding
108 // We need to manually update this on startup as the binding
99 // below doesn't seem to have any effect at that stage
109 // below doesn't seem to have any effect at that stage
100− oskSettings.stayHidden = keyboardsModel.count > 0
101− oskSettings.disableHeight = shell.usageScenario == "desktop"
110+ oskSettings.disableHeight = !shell.oskEnabled || shell.usageScenario == "desktop"
102 }
111 }
103
112
104 // we must rotate to a supported orientation regardless of shell's preference
113 // we must rotate to a supported orientation regardless of shell's preference
@@ -106,17 +115,10 @@ Rectangle {
106 (shell.orientation & supportedOrientations) === 0 ? true
115 (shell.orientation & supportedOrientations) === 0 ? true
107 : shell.orientationChangesEnabled
116 : shell.orientationChangesEnabled
108
117
109−
110− Binding {
111− target: oskSettings
112− property: "stayHidden"
113− value: keyboardsModel.count > 0
114− }
115−
116 Binding {
118 Binding {
117 target: oskSettings
119 target: oskSettings
118 property: "disableHeight"
120 property: "disableHeight"
119− value: shell.usageScenario == "desktop"
121+ value: !shell.oskEnabled || shell.usageScenario == "desktop"
120 }
122 }
121
123
122 readonly property int supportedOrientations: shell.supportedOrientations
124 readonly property int supportedOrientations: shell.supportedOrientations
@@ -189,6 +191,11 @@ Rectangle {
189 nativeHeight: root.height
191 nativeHeight: root.height
190 mode: applicationArguments.mode
192 mode: applicationArguments.mode
191 hasMouse: miceModel.count + touchPadModel.count > 0
193 hasMouse: miceModel.count + touchPadModel.count > 0
194+ // TODO: Factor in if the current screen is a touch screen and if the user wants to
195+ // have multiple keyboards around. For now we only enable one keyboard at a time
196+ // thus hiding it here if there is a physical one around or if we have a second
197+ // screen (the virtual touchpad & osk on the phone) attached.
198+ oskEnabled: keyboardsModel.count === 0 && screens.count === 1
192
199
193 // TODO: Factor in the connected input devices (eg: physical keyboard, mouse, touchscreen),
200 // TODO: Factor in the connected input devices (eg: physical keyboard, mouse, touchscreen),
194 // what's the output device (eg: big TV, desktop monitor, phone display), etc.
201 // what's the output device (eg: big TV, desktop monitor, phone display), etc.
qml/Shell.qml+1
@@ -57,6 +57,7 @@ Item {
57 property string usageScenario: "phone" // supported values: "phone", "tablet" or "desktop"
57 property string usageScenario: "phone" // supported values: "phone", "tablet" or "desktop"
58 property string mode: "full-greeter"
58 property string mode: "full-greeter"
59 property bool cursorVisible: false
59 property bool cursorVisible: false
60+ property alias oskEnabled: inputMethod.enabled
60 function updateFocusedAppOrientation() {
61 function updateFocusedAppOrientation() {
61 applicationsDisplayLoader.item.updateFocusedAppOrientation();
62 applicationsDisplayLoader.item.updateFocusedAppOrientation();
62 }
63 }
tests/mocks/Unity/CMakeLists.txt+1
@@ -5,6 +5,7 @@ add_subdirectory(InputInfo)
5add_subdirectory(Launcher)
5add_subdirectory(Launcher)
6add_subdirectory(Notifications)
6add_subdirectory(Notifications)
7add_subdirectory(DashCommunicator)
7add_subdirectory(DashCommunicator)
8+add_subdirectory(Screens)
8
9
9pkg_search_module(GOBJECT gobject-2.0 REQUIRED)
10pkg_search_module(GOBJECT gobject-2.0 REQUIRED)
10pkg_check_modules(SCOPES_API REQUIRED unity-shell-scopes=9)
11pkg_check_modules(SCOPES_API REQUIRED unity-shell-scopes=9)
tests/mocks/Unity/Screens/CMakeLists.txtnew file+14
@@ -0,0 +1,14 @@
1+include_directories(
2+ ${CMAKE_CURRENT_SOURCE_DIR}
3+)
4+
5+set(MockScreens_SOURCES
6+ plugin.cpp
7+ screens.cpp
8+)
9+
10+add_library(MockScreensPlugin MODULE ${MockScreens_SOURCES})
11+
12+qt5_use_modules(MockScreensPlugin Gui Qml)
13+
14+add_unity8_mock(Unity.Screens 0.1 Unity/Screens TARGETS MockScreensPlugin)
tests/mocks/Unity/Screens/plugin.cppnew file+29
@@ -0,0 +1,29 @@
1+/*
2+ * Copyright (C) 2015 Canonical, Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it under
5+ * the terms of the GNU Lesser General Public License version 3, as published by
6+ * the Free Software Foundation.
7+ *
8+ * This program is distributed in the hope that it will be useful, but WITHOUT
9+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11+ * Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#include "plugin.h"
18+#include "screens.h"
19+
20+#include <QScreen>
21+
22+void UnityScreensPlugin::registerTypes(const char* uri)
23+{
24+ Q_ASSERT(QLatin1String(uri) == QLatin1String("Unity.Screens"));
25+
26+ qRegisterMetaType<QScreen*>("QScreen*");
27+
28+ qmlRegisterType<Screens>(uri, 0, 1, "Screens");
29+}
tests/mocks/Unity/Screens/plugin.hnew file+25
@@ -0,0 +1,25 @@
1+/*
2+ * Copyright (C) 2015 Canonical, Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it under
5+ * the terms of the GNU Lesser General Public License version 3, as published by
6+ * the Free Software Foundation.
7+ *
8+ * This program is distributed in the hope that it will be useful, but WITHOUT
9+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11+ * Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#include <QQmlExtensionPlugin>
18+#include <QtQml/qqml.h>
19+
20+class UnityScreensPlugin : public QQmlExtensionPlugin {
21+ Q_OBJECT
22+ Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface/1.0")
23+public:
24+ virtual void registerTypes(const char* uri);
25+};
tests/mocks/Unity/Screens/qmldirnew file+2
@@ -0,0 +1,2 @@
1+module Unity.Screens
2+plugin MockScreensPlugin
tests/mocks/Unity/Screens/screens.cppnew file+71
@@ -0,0 +1,71 @@
1+/*
2+ * Copyright (C) 2015 Canonical, Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it under
5+ * the terms of the GNU Lesser General Public License version 3, as published by
6+ * the Free Software Foundation.
7+ *
8+ * This program is distributed in the hope that it will be useful, but WITHOUT
9+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11+ * Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#include "screens.h"
18+
19+// Qt
20+#include <QGuiApplication>
21+#include <QScreen>
22+#include <QDebug>
23+
24+Q_DECLARE_METATYPE(QScreen*)
25+
26+Screens::Screens(QObject *parent) :
27+ QAbstractListModel(parent)
28+{
29+ // start with one screen attached
30+ m_screenList.append(new Screen());
31+}
32+
33+Screens::~Screens()
34+{
35+ qDeleteAll(m_screenList);
36+ m_screenList.clear();
37+}
38+
39+QHash<int, QByteArray> Screens::roleNames() const
40+{
41+ QHash<int, QByteArray> roles;
42+ roles[ScreenRole] = "screen";
43+ roles[OutputTypeRole] = "outputType";
44+ return roles;
45+}
46+
47+QVariant Screens::data(const QModelIndex &index, int role) const
48+{
49+ if (!index.isValid() || index.row() >= m_screenList.size()) {
50+ return QVariant();
51+ }
52+
53+ switch(role) {
54+ case ScreenRole:
55+ return QVariant::fromValue(m_screenList.at(index.row())->qScreen);
56+ case OutputTypeRole:
57+ return m_screenList.at(index.row())->outputTypes;
58+ }
59+
60+ return QVariant();
61+}
62+
63+int Screens::rowCount(const QModelIndex &) const
64+{
65+ return count();
66+}
67+
68+int Screens::count() const
69+{
70+ return m_screenList.size();
71+}
tests/mocks/Unity/Screens/screens.hnew file+82
@@ -0,0 +1,82 @@
1+/*
2+ * Copyright (C) 2015 Canonical, Ltd.
3+ *
4+ * This program is free software: you can redistribute it and/or modify it under
5+ * the terms of the GNU Lesser General Public License version 3, as published by
6+ * the Free Software Foundation.
7+ *
8+ * This program is distributed in the hope that it will be useful, but WITHOUT
9+ * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY,
10+ * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11+ * Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+#ifndef SCREENS_H
18+#define SCREENS_H
19+
20+#include <QAbstractListModel>
21+#include <QScreen>
22+
23+class Screen;
24+
25+class Screens : public QAbstractListModel
26+{
27+ Q_OBJECT
28+ Q_ENUMS(OutputTypes)
29+
30+ Q_PROPERTY(int count READ count NOTIFY countChanged)
31+
32+public:
33+ enum ItemRoles {
34+ ScreenRole = Qt::UserRole + 1,
35+ OutputTypeRole
36+ };
37+
38+ enum OutputTypes {
39+ Unknown,
40+ VGA,
41+ DVII,
42+ DVID,
43+ DVIA,
44+ Composite,
45+ SVideo,
46+ LVDS,
47+ Component,
48+ NinePinDIN,
49+ DisplayPort,
50+ HDMIA,
51+ HDMIB,
52+ TV,
53+ EDP
54+ };
55+
56+ explicit Screens(QObject *parent = 0);
57+ virtual ~Screens() noexcept;
58+
59+ /* QAbstractItemModel */
60+ QHash<int, QByteArray> roleNames() const override;
61+ QVariant data(const QModelIndex &index, int role = ScreenRole) const override;
62+ int rowCount(const QModelIndex &parent = QModelIndex()) const override;
63+
64+ int count() const;
65+
66+Q_SIGNALS:
67+ void countChanged();
68+ void screenAdded(QScreen *screen);
69+ void screenRemoved(QScreen *screen);
70+
71+private:
72+ QList<Screen *> m_screenList;
73+};
74+
75+class Screen
76+{
77+public:
78+ Screens::OutputTypes outputTypes = Screens::Unknown;
79+ QScreen *qScreen = nullptr;
80+};
81+
82+#endif // SCREENS_H
tests/qmltests/tst_OrientedShell.qml+5−2
@@ -1024,12 +1024,14 @@ Rectangle {
1024
1024
1025 loadShell("mako")
1025 loadShell("mako")
1026 var shell = findChild(orientedShell, "shell");
1026 var shell = findChild(orientedShell, "shell");
1027+ var inputMethod = findChild(shell, "inputMethod");
1027
1028
1028 var oldWidth = orientedShellLoader.width;
1029 var oldWidth = orientedShellLoader.width;
1029 orientedShellLoader.width = data.screenWidth;
1030 orientedShellLoader.width = data.screenWidth;
1030
1031
1031 tryCompare(shell, "usageScenario", "phone");
1032 tryCompare(shell, "usageScenario", "phone");
1033+ tryCompare(inputMethod, "enabled", true);
1032− tryCompare(mockOskSettings, "stayHidden", false);
1034+ tryCompare(mockOskSettings, "disableHeight", false);
1033
1035
1034 if (data.kbd) {
1036 if (data.kbd) {
1035 MockInputDeviceBackend.addMockDevice("/kbd0", InputInfo.Keyboard);
1037 MockInputDeviceBackend.addMockDevice("/kbd0", InputInfo.Keyboard);
@@ -1039,7 +1041,8 @@ Rectangle {
1039 }
1041 }
1040
1042
1041 tryCompare(shell, "usageScenario", data.expectedMode);
1043 tryCompare(shell, "usageScenario", data.expectedMode);
1042− tryCompare(mockOskSettings, "stayHidden", !data.oskExpected);
1044+ tryCompare(inputMethod, "enabled", data.oskExpected);
1045+ tryCompare(mockOskSettings, "disableHeight", data.expectedMode == "desktop" || data.kbd);
1043
1046
1044 if (data.kbd) {
1047 if (data.kbd) {
1045 MockInputDeviceBackend.removeDevice("/kbd0");
1048 MockInputDeviceBackend.removeDevice("/kbd0");