on xenial help sign in
Cherrypick the unity-scope-tool
commitab63f8e65849382125e1c5a65202e816e0973ed8 authorMichal Hruby <michal.mhr@gmail.com> dateFri 20 Dec 2013, 16:27 (13 years ago) parent58c9a3c
10 files changed+460−2
CMakeLists.txt+2 data/CMakeLists.txt+3−2 data/unity-scope-tool.desktop.in+9 debian/control+9 debian/unity-scope-tool.install+3 qml/ScopeTool.qml+179 tools/CMakeLists.txt+11 tools/registry-tracker.cpp+116 tools/registry-tracker.h+44 tools/scopetool.cpp+84
CMakeLists.txt+2
@@ -96,6 +96,7 @@ include(autopilot)
9696declare_autopilot_test(shell unity8.shell ${CMAKE_SOURCE_DIR}/tests/autopilot/)
9797
9898set(SHELL_APP unity8)
99+set(SCOPE_TOOL unity-scope-tool)
99100
100101include_directories(
101102 ${CMAKE_SOURCE_DIR}/include
@@ -105,6 +106,7 @@ include_directories(
105106# add subdirectories to build
106107add_subdirectory(include)
107108add_subdirectory(src)
109+add_subdirectory(tools)
108110add_subdirectory(qml)
109111add_subdirectory(tests)
110112add_subdirectory(plugins)
data/CMakeLists.txt+3−2
@@ -1,7 +1,8 @@
11# generate desktop file
22configure_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)
34
4−# install desktop file
5−install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${SHELL_APP}.desktop
5+# install desktop files
6+install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${SHELL_APP}.desktop {CMAKE_CURRENT_BINARY_DIR}/${SCOPE_TOOL}.desktop
67 DESTINATION ${CMAKE_INSTALL_DATADIR}/applications
78 )
data/unity-scope-tool.desktop.innew file+9
@@ -0,0 +1,9 @@
1+[Desktop Entry]
2+Type=Application
3+Name=Unity Scope Tool
4+GenericName=unity-scope-tool
5+Comment=Developer tool for Unity scopes.
6+Exec=@CMAKE_INSTALL_PREFIX@/@CMAKE_INSTALL_BINDIR@/unity-scope-tool
7+Terminal=false
8+Icon=unity-scope-tool
9+X-Ubuntu-Touch=true
debian/control+9
@@ -59,6 +59,15 @@ Depends: qmenumodel-qml (>= 0.2.7),
5959Description: Indicators client test application
6060 This package contains the client application for indicators used by autopilot
6161
62+Package: unity-dev-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+
6271Package: unity8
6372Architecture: any
6473Provides: 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+179
@@ -0,0 +1,179 @@
1+import QtQuick 2.0
2+import Ubuntu.Components 0.1
3+import Ubuntu.Components.Popups 0.1
4+import Unity 0.1
5+import "Dash"
6+
7+Rectangle {
8+ id: root
9+ width: units.gu(80)
10+ height: units.gu(72)
11+ color: "#88FFFFFF"
12+
13+ // Fake shell object
14+ QtObject {
15+ id: shell
16+ }
17+
18+ // Fake greeter object
19+ QtObject {
20+ id: greeter
21+ property bool shown
22+ }
23+
24+ // Fake panel object
25+ QtObject {
26+ id: panel
27+ signal searchClicked
28+ }
29+
30+
31+ Scopes {
32+ id: scopes
33+ }
34+
35+ Rectangle {
36+ anchors.fill: scopeView
37+ color: "#FCFCFC"
38+ }
39+
40+ GenericScopeView {
41+ id: scopeView
42+
43+ anchors {
44+ top: parent.top
45+ bottom: parent.bottom
46+ left: parent.left
47+ right: controls.left
48+ }
49+
50+ scope: scopes.loaded ? scopes.get(scopeSelector.selectedIndex) : undefined
51+ }
52+
53+ Rectangle {
54+ id: controls
55+ color: "lightgrey"
56+ width: units.gu(40)
57+ anchors {
58+ top: parent.top
59+ bottom: parent.bottom
60+ right: parent.right
61+ }
62+
63+ Column {
64+ anchors { fill: parent; margins: units.gu(1) }
65+ spacing: units.gu(1)
66+
67+ Label {
68+ text: "Search query"
69+ }
70+
71+ TextField {
72+ id: searchField
73+ anchors { left: parent.left; right: parent.right }
74+
75+ onTextChanged: scopeView.scope.searchQuery = text
76+
77+ Connections {
78+ target: scopeView.scope
79+ onSearchQueryChanged: searchField.text = scopeView.scope.searchQuery
80+ }
81+ }
82+
83+ Label {
84+ text: "Scope selection"
85+ height: units.gu(4)
86+ verticalAlignment: Text.AlignBottom
87+ }
88+
89+ OptionSelector {
90+ id: scopeSelector
91+ anchors { left: parent.left; right: parent.right }
92+
93+ model: scopes
94+ delegate: OptionSelectorDelegate {
95+ text: model.title
96+ }
97+ }
98+
99+ Label {
100+ text: "Category"
101+ height: units.gu(4)
102+ verticalAlignment: Text.AlignBottom
103+ }
104+
105+ OptionSelector {
106+ id: categorySelector
107+ anchors { left: parent.left; right: parent.right }
108+
109+ model: scopeView.scope ? scopeView.scope.categories : null
110+ delegate: OptionSelectorDelegate {
111+ text: model.name
112+ }
113+
114+ onSelectedIndexChanged: {
115+ categoryJson.refreshText();
116+ }
117+ }
118+
119+ Repeater {
120+ id: categoryRepeater
121+ model: categorySelector.model
122+ Item {
123+ property var data: model.rawRendererTemplate
124+ property var categoryId: model.categoryId
125+ onDataChanged: {
126+ if (model.index != categorySelector.selectedIndex) return;
127+ categoryJson.refreshText();
128+ }
129+ }
130+ onItemAdded: categoryJson.refreshText()
131+ }
132+
133+ TextArea {
134+ id: categoryJson
135+ width: parent.width
136+ autoSize: true
137+
138+ function refreshText() {
139+ if (categoryRepeater.count > categorySelector.selectedIndex) {
140+ var item = categoryRepeater.itemAt(categorySelector.selectedIndex);
141+ if (item == null) return;
142+ categoryJson.text = JSON.stringify(JSON.parse(item.data), null, " ");
143+ }
144+ }
145+ }
146+
147+ Button {
148+ width: parent.width
149+ text: "Override category"
150+ onClicked: {
151+ PopupUtils.open(categoryEditor)
152+ }
153+ }
154+ }
155+ }
156+
157+ Component {
158+ id: categoryEditor
159+
160+ ComposerSheet {
161+ id: sheet
162+ title: "Editing category definition"
163+
164+ TextArea {
165+ id: categoryEditorArea
166+ anchors.fill: parent
167+ wrapMode: Text.WordWrap
168+ text: categoryJson.text
169+ }
170+
171+ onCancelClicked: PopupUtils.close(sheet)
172+ onConfirmClicked: {
173+ PopupUtils.close(sheet);
174+ var categoryId = categoryRepeater.itemAt(categorySelector.selectedIndex).categoryId;
175+ scopeView.scope.categories.overrideCategoryJson(categoryId, categoryEditorArea.text);
176+ }
177+ }
178+ }
179+}
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, const 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, (char**)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+}