on xenial help sign in
Added unity-scope-tool, which will help when developing scopes.
91db876Michał Sawicz
CMakeLists.txt+2
@@ -96,6 +96,7 @@ include(autopilot)
96declare_autopilot_test(shell unity8.shell ${CMAKE_SOURCE_DIR}/tests/autopilot/)
96declare_autopilot_test(shell unity8.shell ${CMAKE_SOURCE_DIR}/tests/autopilot/)
97
97
98set(SHELL_APP unity8)
98set(SHELL_APP unity8)
99+set(SCOPE_TOOL unity-scope-tool)
99
100
100include_directories(
101include_directories(
101 ${CMAKE_SOURCE_DIR}/include
102 ${CMAKE_SOURCE_DIR}/include
@@ -105,6 +106,7 @@ include_directories(
105# add subdirectories to build
106# add subdirectories to build
106add_subdirectory(include)
107add_subdirectory(include)
107add_subdirectory(src)
108add_subdirectory(src)
109+add_subdirectory(tools)
108add_subdirectory(qml)
110add_subdirectory(qml)
109add_subdirectory(tests)
111add_subdirectory(tests)
110add_subdirectory(plugins)
112add_subdirectory(plugins)
data/CMakeLists.txt+3−2
@@ -1,7 +1,8 @@
1# generate desktop file
1# generate desktop file
2configure_file(${SHELL_APP}.desktop.in ${CMAKE_CURRENT_BINARY_DIR}/${SHELL_APP}.desktop @ONLY)
2configure_file(${SHELL_APP}.desktop.in ${CMAKE_CURRENT_BINARY_DIR}/${SHELL_APP}.desktop @ONLY)
3+configure_file(${SCOPE_TOOL}.desktop.in ${CMAKE_CURRENT_BINARY_DIR}/${SCOPE_TOOL}.desktop @ONLY)
3
4
4−# install desktop file
5+# install desktop files
5−install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${SHELL_APP}.desktop
6+install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${SHELL_APP}.desktop ${CMAKE_CURRENT_BINARY_DIR}/${SCOPE_TOOL}.desktop
6 DESTINATION ${CMAKE_INSTALL_DATADIR}/applications
7 DESTINATION ${CMAKE_INSTALL_DATADIR}/applications
7 )
8 )
data/unity-scope-tool.desktop.innew file+8
@@ -0,0 +1,8 @@
1+[Desktop Entry]
2+Type=Application
3+Name=Unity Scope Tool
4+Comment=Developer tool for Unity scopes.
5+Exec=@CMAKE_INSTALL_PREFIX@/@CMAKE_INSTALL_BINDIR@/unity-scope-tool
6+Terminal=false
7+Icon=unity-scope-tool
8+X-Ubuntu-Touch=true
debian/control+9
@@ -59,6 +59,15 @@ Depends: qmenumodel-qml (>= 0.2.7),
59Description: Indicators client test application
59Description: Indicators client test application
60 This package contains the client application for indicators used by autopilot
60 This package contains the client application for indicators used by autopilot
61
61
62+Package: unity-scope-tool
63+Architecture: any
64+Depends: unity8 (= ${binary:Version}),
65+ ${misc:Depends},
66+ ${shlibs:Depends},
67+Description: Development tool for Unity scopes
68+ This package contains the development tool for new generation Unity scopes, based
69+ on Unity8.
70+
62Package: unity8
71Package: unity8
63Architecture: any
72Architecture: any
64Provides: indicator-renderer,
73Provides: indicator-renderer,
debian/unity-scope-tool.installnew file+3
@@ -0,0 +1,3 @@
1+usr/bin/unity-scope-tool
2+usr/share/applications/unity-scope-tool.desktop
3+usr/share/unity8/ScopeTool.qml
qml/ScopeTool.qmlnew file+177
@@ -0,0 +1,177 @@
1+/*
2+* Copyright (C) 2013 Canonical, Ltd.
3+*
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
6+* the Free Software Foundation; version 3.
7+*
8+* This program is distributed in the hope that it will be useful,
9+* but WITHOUT ANY WARRANTY; without even the implied warranty of
10+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+* GNU General Public License for more details.
12+*
13+* You should have received a copy of the GNU General Public License
14+* along with this program. If not, see <http://www.gnu.org/licenses/>.
15+*/
16+
17+import QtQuick 2.0
18+import Ubuntu.Components 0.1
19+import Ubuntu.Components.Popups 0.1
20+import Unity 0.1
21+import "Dash"
22+
23+Rectangle {
24+ id: root
25+ width: units.gu(80)
26+ height: units.gu(72)
27+ color: "#88FFFFFF"
28+
29+ // Fake shell object
30+ QtObject {
31+ id: shell
32+ }
33+
34+ // Fake greeter object
35+ QtObject {
36+ id: greeter
37+ property bool shown
38+ }
39+
40+ // Fake panel object
41+ QtObject {
42+ id: panel
43+ signal searchClicked
44+ }
45+
46+
47+ Scopes {
48+ id: scopes
49+ }
50+
51+ Rectangle {
52+ anchors.fill: scopeView
53+ color: "#FCFCFC"
54+ }
55+
56+ GenericScopeView {
57+ id: scopeView
58+
59+ anchors {
60+ top: parent.top
61+ bottom: parent.bottom
62+ left: parent.left
63+ right: controls.left
64+ }
65+
66+ scope: scopes.loaded ? scopes.get(scopeSelector.selectedIndex) : undefined
67+ }
68+
69+ Rectangle {
70+ id: controls
71+ color: "lightgrey"
72+ width: units.gu(40)
73+ anchors {
74+ top: parent.top
75+ bottom: parent.bottom
76+ right: parent.right
77+ }
78+
79+ Column {
80+ anchors { fill: parent; margins: units.gu(1) }
81+ spacing: units.gu(1)
82+
83+ Label {
84+ text: "Search query"
85+ }
86+
87+ TextField {
88+ id: searchField
89+ anchors { left: parent.left; right: parent.right }
90+
91+ onTextChanged: scopeView.scope.searchQuery = text
92+
93+ Connections {
94+ target: scopeView.scope
95+ onSearchQueryChanged: searchField.text = scopeView.scope.searchQuery
96+ }
97+ }
98+
99+ Label {
100+ text: "Scope selection"
101+ height: units.gu(4)
102+ verticalAlignment: Text.AlignBottom
103+ }
104+
105+ OptionSelector {
106+ id: scopeSelector
107+ anchors { left: parent.left; right: parent.right }
108+
109+ model: scopes
110+ delegate: OptionSelectorDelegate {
111+ text: model.title
112+ }
113+ }
114+
115+ Label {
116+ text: "Category"
117+ height: units.gu(4)
118+ verticalAlignment: Text.AlignBottom
119+ }
120+
121+ OptionSelector {
122+ id: categorySelector
123+ anchors { left: parent.left; right: parent.right }
124+ model: scopeView.scope ? scopeView.scope.categories : null
125+
126+ property Item selectedItem
127+
128+ delegate: OptionSelectorDelegate {
129+ id: categoryDelegate
130+ text: model.name
131+ property string categoryId: model.categoryId
132+ property string template: JSON.stringify(JSON.parse(model.rawRendererTemplate), null, " ");
133+
134+ onSelectedChanged: if (selected) categorySelector.selectedItem = categoryDelegate
135+ }
136+ }
137+
138+ TextArea {
139+ id: categoryJson
140+ width: parent.width
141+ autoSize: true
142+ readOnly: true
143+ text: categorySelector.selectedItem && categorySelector.selectedItem.template
144+ }
145+
146+ Button {
147+ width: parent.width
148+ text: "Override category"
149+ onClicked: {
150+ PopupUtils.open(categoryEditor)
151+ }
152+ }
153+ }
154+ }
155+
156+ Component {
157+ id: categoryEditor
158+
159+ ComposerSheet {
160+ id: sheet
161+ title: "Editing category definition"
162+
163+ TextArea {
164+ id: categoryEditorArea
165+ anchors.fill: parent
166+ wrapMode: Text.WordWrap
167+ text: categoryJson.text
168+ }
169+
170+ onCancelClicked: PopupUtils.close(sheet)
171+ onConfirmClicked: {
172+ PopupUtils.close(sheet);
173+ scopeView.scope.categories.overrideCategoryJson(categorySelector.selectedItem.categoryId, categoryEditorArea.text);
174+ }
175+ }
176+ }
177+}
tools/CMakeLists.txtnew file+11
@@ -0,0 +1,11 @@
1+add_executable(${SCOPE_TOOL}
2+ scopetool.cpp
3+ registry-tracker.cpp
4+ )
5+
6+qt5_use_modules(${SCOPE_TOOL} Qml Quick)
7+
8+# install binaries
9+install(TARGETS ${SCOPE_TOOL}
10+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
11+ )
tools/registry-tracker.cppnew file+116
@@ -0,0 +1,116 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * Authors:
5+ * Michal Hruby <michal.hruby@canonical.com>
6+ *
7+ * This program is free software; you can redistribute it and/or modify
8+ * it under the terms of the GNU General Public License as published by
9+ * the Free Software Foundation; version 3.
10+ *
11+ * This program is distributed in the hope that it will be useful,
12+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+ * GNU General Public License for more details.
15+ *
16+ * You should have received a copy of the GNU General Public License
17+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
18+ */
19+
20+// Qt
21+#include <QtGlobal>
22+#include <QDir>
23+
24+// local
25+#include "registry-tracker.h"
26+
27+
28+RegistryTracker::RegistryTracker(QString const& scope_dir):
29+ m_scopeDir(scope_dir),
30+ m_registry(nullptr),
31+ m_endpoints_dir(QDir::temp().filePath("scope-dev-endpoints.XXXXXX"))
32+{
33+ runRegistry();
34+}
35+
36+RegistryTracker::~RegistryTracker()
37+{
38+ if (m_registry.state() != QProcess::NotRunning) {
39+ m_registry.terminate();
40+ m_registry.waitForFinished(5000);
41+ m_registry.kill();
42+ }
43+}
44+
45+#define RUNTIME_CONFIG \
46+"[Runtime]\n" \
47+"Registry.Identity = Registry\n" \
48+"Registry.ConfigFile = %1\n" \
49+"Default.Middleware = Zmq\n" \
50+"Zmq.ConfigFile = %2\n"
51+
52+#define REGISTRY_CONFIG \
53+"[Registry]\n" \
54+"Middleware = Zmq\n" \
55+"Zmq.Endpoint = ipc://%1/Registry\n" \
56+"Zmq.EndpointDir = %2\n" \
57+"Zmq.ConfigFile = %3\n" \
58+"Scope.InstallDir = %4\n" \
59+"Scoperunner.Path = %5\n"
60+
61+#define MW_CONFIG \
62+"[Zmq]\n" \
63+"EndpointDir.Public = %1\n" \
64+"EndpointDir.Private = %2\n"
65+
66+void RegistryTracker::runRegistry()
67+{
68+ QDir tmp(QDir::temp());
69+ m_runtime_config.setFileTemplate(tmp.filePath("Runtime.ini.XXXXXX"));
70+ m_registry_config.setFileTemplate(tmp.filePath("Registry.ini.XXXXXX"));
71+ m_mw_config.setFileTemplate(tmp.filePath("Zmq.ini.XXXXXX"));
72+
73+ if (!m_runtime_config.open() || !m_registry_config.open() || !m_mw_config.open() || !m_endpoints_dir.isValid()) {
74+ qWarning("Unable to open temporary files!");
75+ return;
76+ }
77+
78+ QString scopesLibdir;
79+ {
80+ QProcess pkg_config;
81+ QStringList arguments;
82+ arguments << "--variable=libdir";
83+ arguments << "libunity-scopes";
84+ pkg_config.start("pkg-config", arguments);
85+ pkg_config.waitForFinished();
86+ QByteArray libdir = pkg_config.readAllStandardOutput();
87+ scopesLibdir = QDir(QString::fromLocal8Bit(libdir)).path().trimmed();
88+ }
89+
90+ if (scopesLibdir.size() == 0) {
91+ qWarning("Unable to find libunity-scopes package config file");
92+ return;
93+ }
94+
95+ QString scopeRunnerPath = QDir(scopesLibdir).filePath("scoperunner/scoperunner");
96+
97+ QString runtime_ini = QString(RUNTIME_CONFIG).arg(m_registry_config.fileName()).arg(m_mw_config.fileName());
98+ QString registry_ini = QString(REGISTRY_CONFIG).arg(m_endpoints_dir.path()).arg(m_endpoints_dir.path()).arg(m_mw_config.fileName()).arg(m_scopeDir).arg(scopeRunnerPath);
99+ QString mw_ini = QString(MW_CONFIG).arg(m_endpoints_dir.path()).arg(m_endpoints_dir.path());
100+
101+ m_runtime_config.write(runtime_ini.toUtf8());
102+ m_registry_config.write(registry_ini.toUtf8());
103+ m_mw_config.write(mw_ini.toUtf8());
104+
105+ m_runtime_config.flush();
106+ m_registry_config.flush();
107+ m_mw_config.flush();
108+
109+ qputenv("UNITY_SCOPES_RUNTIME_PATH", m_runtime_config.fileName().toLocal8Bit());
110+
111+ QString registryBin(QDir(scopesLibdir).filePath("scoperegistry/scoperegistry"));
112+ QStringList arguments;
113+ arguments << m_runtime_config.fileName();
114+
115+ m_registry.start(registryBin, arguments);
116+}
tools/registry-tracker.hnew file+44
@@ -0,0 +1,44 @@
1+/*
2+ * Copyright (C) 2013 Canonical, Ltd.
3+ *
4+ * Authors:
5+ * Michal Hruby <michal.hruby@canonical.com>
6+ *
7+ * This program is free software; you can redistribute it and/or modify
8+ * it under the terms of the GNU General Public License as published by
9+ * the Free Software Foundation; version 3.
10+ *
11+ * This program is distributed in the hope that it will be useful,
12+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+ * GNU General Public License for more details.
15+ *
16+ * You should have received a copy of the GNU General Public License
17+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
18+ */
19+
20+// Qt
21+#include <QProcess>
22+#include <QTemporaryFile>
23+#include <QTemporaryDir>
24+#include <QDebug>
25+
26+
27+class RegistryTracker
28+{
29+public:
30+ RegistryTracker(QString const&);
31+ ~RegistryTracker();
32+
33+ QProcess* registry() const;
34+
35+private:
36+ void runRegistry();
37+
38+ QString m_scopeDir;
39+ QProcess m_registry;
40+ QTemporaryDir m_endpoints_dir;
41+ QTemporaryFile m_runtime_config;
42+ QTemporaryFile m_registry_config;
43+ QTemporaryFile m_mw_config;
44+};
tools/scopetool.cppnew file+84
@@ -0,0 +1,84 @@
1+/*
2+ * Copyright (C) 2012 Canonical, Ltd.
3+ *
4+ * Authors:
5+ * Gerry Boland <gerry.boland@canonical.com>
6+ *
7+ * This program is free software; you can redistribute it and/or modify
8+ * it under the terms of the GNU General Public License as published by
9+ * the Free Software Foundation; version 3.
10+ *
11+ * This program is distributed in the hope that it will be useful,
12+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+ * GNU General Public License for more details.
15+ *
16+ * You should have received a copy of the GNU General Public License
17+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
18+ */
19+
20+// Qt
21+#include <QtQuick/QQuickView>
22+#include <QtGui/QGuiApplication>
23+#include <QtQml/QQmlEngine>
24+#include <QtQml/QQmlContext>
25+#include <QScopedPointer>
26+#include <QDebug>
27+#include <libintl.h>
28+
29+
30+// local
31+#include <paths.h>
32+#include "registry-tracker.h"
33+
34+
35+int main(int argc, char *argv[])
36+{
37+ /* Workaround Qt platform integration plugin not advertising itself
38+ as having the following capabilities:
39+ - QPlatformIntegration::ThreadedOpenGL
40+ - QPlatformIntegration::BufferQueueingOpenGL
41+ */
42+ setenv("QML_FORCE_THREADED_RENDERER", "1", 1);
43+ setenv("QML_FIXED_ANIMATION_STEP", "1", 1);
44+
45+ QGuiApplication::setApplicationName("Unity Scope Tool");
46+ QGuiApplication *application;
47+ application = new QGuiApplication(argc, argv);
48+
49+ QStringList arguments = application->arguments();
50+ QString scopesDir;
51+ if (arguments.contains("--scope-dir")) {
52+ int idx = arguments.indexOf("--scope-dir");
53+ scopesDir = arguments[idx+1];
54+ }
55+
56+ QScopedPointer<RegistryTracker> tracker;
57+ if (!scopesDir.isEmpty()) {
58+ tracker.reset(new RegistryTracker(scopesDir));
59+ }
60+
61+ resolveIconTheme();
62+
63+ bindtextdomain("unity8", translationDirectory().toUtf8().data());
64+
65+ QQuickView* view = new QQuickView();
66+ view->setResizeMode(QQuickView::SizeRootObjectToView);
67+ view->setTitle(QGuiApplication::applicationName());
68+ view->engine()->setBaseUrl(QUrl::fromLocalFile(::qmlDirectory()));
69+
70+ QUrl source(::qmlDirectory() + "ScopeTool.qml");
71+ prependImportPaths(view->engine(), ::overrideImportPaths());
72+ appendImportPaths(view->engine(), ::fallbackImportPaths());
73+
74+ view->setSource(source);
75+
76+ view->show();
77+
78+ int result = application->exec();
79+
80+ delete view;
81+ delete application;
82+
83+ return result;
84+}