diff --git a/CMakeLists.txt b/CMakeLists.txt index e02c012181..897cf042b0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -83,10 +83,6 @@ pkg_check_modules(QMENUMODEL REQUIRED qmenumodel) pkg_check_modules(GD3 REQUIRED gnome-desktop-3.0) pkg_check_modules(UAL REQUIRED ubuntu-app-launch-2) pkg_check_modules(UBUNTUGESTURES REQUIRED UbuntuGestures) -pkg_check_modules(QTDBUSTEST REQUIRED - libqtdbustest-1 - libqtdbusmock-1 - ) ### Check UbuntuGestures private headers. No pkg-config (.pc) file is provided for them find_path(UBUNTUGESTUREPRIV @@ -183,6 +179,10 @@ add_subdirectory(qml) # Tests set(NO_TESTS OFF CACHE BOOL "Disable tests.") if (NOT NO_TESTS) + pkg_check_modules(QTDBUSTEST REQUIRED + libqtdbustest-1 + libqtdbusmock-1 + ) include(CTest) enable_testing() add_subdirectory(tests) diff --git a/debian/control b/debian/control index 2cbb1942d8..8dae4fbdbd 100644 --- a/debian/control +++ b/debian/control @@ -6,20 +6,20 @@ Build-Depends: android-headers, cmake, cmake-extras, - dbus-test-runner, + dbus-test-runner , debhelper (>= 9), dh-apparmor, - doxyqml, + doxyqml , g++:native, - gdb, - graphviz, - gsettings-ubuntu-schemas (>= 0.0.2+14.10.20140815), + gdb , + graphviz , + gsettings-ubuntu-schemas (>= 0.0.2+14.10.20140815) , libandroid-properties-dev, libconnectivity-qt1-dev (>= 0.7.1), libevdev-dev, libgeonames-dev (>= 0.2), libgl1-mesa-dev[!arm64 !armhf] | libgl-dev[!arm64 !armhf], - libgl1-mesa-dri, + libgl1-mesa-dri , libgles2-mesa-dev[arm64 armhf], libglib2.0-dev, libgnome-desktop-3-dev, @@ -29,11 +29,11 @@ Build-Depends: libpam0g-dev, libpulse-dev, libqmenumodel-dev (>= 0.2.12), - libqt5sql5-sqlite, + libqt5sql5-sqlite , libqt5svg5-dev, libqt5xmlpatterns5-dev, - libqtdbusmock1-dev (>= 0.7), - libqtdbustest1-dev, + libqtdbusmock1-dev (>= 0.7) , + libqtdbustest1-dev , libsystemsettings-dev, libubuntu-app-launch2-dev, libubuntu-download-manager-common-dev, @@ -47,32 +47,32 @@ Build-Depends: libxcb1-dev[!arm64 !armhf], libxi-dev[!arm64 !armhf], pkg-config, - python3-all:any, - python3-setuptools, - qml-module-qt-labs-folderlistmodel, - qml-module-qt-labs-settings, - qml-module-qtmultimedia (>= 5.6), - qml-module-qtqml-statemachine, - qml-module-qtquick-layouts, - qml-module-qtquick-xmllistmodel, - qml-module-qtquick2, - qml-module-qtsysteminfo, - qml-module-qttest, - qml-module-ubuntu-components (>= 1.3.2030) | qml-module-ubuntu-components-gles (>= 1.3.2030), - qml-module-ubuntu-layouts, - qml-module-ubuntu-settings-components, - qml-module-ubuntu-test, + python3-all:any , + python3-setuptools , + qml-module-qt-labs-folderlistmodel , + qml-module-qt-labs-settings , + qml-module-qtmultimedia (>= 5.6) , + qml-module-qtqml-statemachine , + qml-module-qtquick-layouts , + qml-module-qtquick-xmllistmodel , + qml-module-qtquick2 , + qml-module-qtsysteminfo , + qml-module-qttest , + qml-module-ubuntu-components (>= 1.3.2030) | qml-module-ubuntu-components-gles (>= 1.3.2030) , + qml-module-ubuntu-layouts , + qml-module-ubuntu-settings-components , + qml-module-ubuntu-test , qtbase5-dev (>= 5.6), qtbase5-dev-tools, qtbase5-private-dev (>= 5.6), - qtdbustest-runner, + qtdbustest-runner , qtdeclarative5-dev (>= 5.6), qtdeclarative5-dev-tools, qtdeclarative5-private-dev (>= 5.6), qtdeclarative5-ubuntu-content1, - ttf-ubuntu-font-family, - ubports-wallpapers, - xvfb, + ttf-ubuntu-font-family , + ubports-wallpapers , + xvfb , Standards-Version: 3.9.4 Homepage: https://github.com/ubports/unity8 Vcs-Git: https://github.com/ubports/unity8 @@ -174,6 +174,7 @@ Description: Unity 8 shell (common files) Package: unity8-autopilot Architecture: all +Build-Profiles: Depends: autopilot-qt5 (>= 1.4), gir1.2-glib-2.0, @@ -199,6 +200,7 @@ Description: Test package for Unity 8 shell Package: unity8-tests Architecture: any Multi-Arch: same +Build-Profiles: Pre-Depends: ${misc:Pre-Depends}, Depends: @@ -266,6 +268,7 @@ Package: unity8-doc Section: doc Architecture: all Multi-Arch: foreign +Build-Profiles: Depends: ${misc:Depends}, Description: Documentation for Unity8 diff --git a/debian/rules b/debian/rules index 6833b6a24e..04a48316f4 100755 --- a/debian/rules +++ b/debian/rules @@ -14,13 +14,17 @@ DEB_HOST_ARCH ?= $(shell dpkg-architecture -qDEB_HOST_ARCH) # Skip tests on the archs they are known to be flaky with current configuration testskip_architectures := arm64 powerpc ppc64el s390x +ifneq (,$(findstring nocheck,$(DEB_BUILD_OPTIONS))) + CONFIGURE_OPTS += "-DNO_TESTS=ON" +endif + %: dh $@ --parallel --fail-missing --with python3 override_dh_auto_configure: # Debian defines CMAKE_INSTALL_LOCALSTATEDIR as /usr/var, which is wrong. # So until Debian bug 719148 is fixed, do it ourselves. - dh_auto_configure -- -DCMAKE_INSTALL_LOCALSTATEDIR="/var" + dh_auto_configure -- -DCMAKE_INSTALL_LOCALSTATEDIR="/var" $(CONFIGURE_OPTS) override_dh_auto_build: # doc is not a default target @@ -39,12 +43,17 @@ endif endif override_dh_install: +ifeq ($(DEB_BUILD_GNU_TYPE),$(DEB_HOST_GNU_TYPE)) # install autopilot tests cd tests/autopilot; \ set -ex; for python in $(shell py3versions -r); do \ $$python setup.py install --root=$(CURDIR)/debian/tmp --install-layout=deb; \ done; \ cd $(CURDIR) +else + rm -f debian/tmp/usr/share/unity8/unlock-device + rm -rf debian/tmp/usr/lib/*/unity8/qml/mocks +endif dh_install -X'*.pyc' --fail-missing # use private lib directories diff --git a/debian/unity8-private.install b/debian/unity8-private.install index 23f86ab8ac..6e9ddd46e4 100644 --- a/debian/unity8-private.install +++ b/debian/unity8-private.install @@ -6,6 +6,7 @@ usr/lib/*/unity8/qml/Greeter usr/lib/*/unity8/qml/LightDM usr/lib/*/unity8/qml/Lights usr/lib/*/unity8/qml/Powerd +usr/lib/*/unity8/qml/ProcessControl usr/lib/*/unity8/qml/ScreenshotDirectory usr/lib/*/unity8/qml/SessionBroadcast usr/lib/*/unity8/qml/UInput diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index 4841bcc529..9601a1bd26 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -18,6 +18,7 @@ add_subdirectory(Greeter) add_subdirectory(LightDM) add_subdirectory(Lights) add_subdirectory(Powerd) +add_subdirectory(ProcessControl) add_subdirectory(ScreenshotDirectory) add_subdirectory(SessionBroadcast) add_subdirectory(Ubuntu) diff --git a/plugins/ProcessControl/CMakeLists.txt b/plugins/ProcessControl/CMakeLists.txt new file mode 100644 index 0000000000..d9e52d569b --- /dev/null +++ b/plugins/ProcessControl/CMakeLists.txt @@ -0,0 +1,21 @@ +add_definitions(-DSM_BUSNAME=sessionBus) + +add_library(ProcessControl-qml MODULE + LocationWatcher.cpp + ProcessControl.cpp + plugin.cpp +) + +target_link_libraries(ProcessControl-qml + Qt5::DBus Qt5::Qml +) + +target_include_directories(ProcessControl-qml PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) + +add_unity8_plugin(ProcessControl 0.1 ProcessControl TARGETS ProcessControl-qml) + +set(DBUS_IFACE_DIR "${CMAKE_INSTALL_PREFIX}/share/dbus-1/interfaces") + +install(FILES com.lomiri.ProcessControl.xml + DESTINATION "${DBUS_IFACE_DIR}" +) diff --git a/plugins/ProcessControl/LocationWatcher.cpp b/plugins/ProcessControl/LocationWatcher.cpp new file mode 100644 index 0000000000..d0e67648e1 --- /dev/null +++ b/plugins/ProcessControl/LocationWatcher.cpp @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2021 UBports Foundation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Authors: Alberto Mardegan + */ + +#include "LocationWatcher.h" + +#include "ProcessControl.h" + +#include +#include +#include +#include + +namespace { +const QString locationServiceName = QStringLiteral("com.ubuntu.location.Service"); +const QString locationObjectPath = QStringLiteral("/com/ubuntu/location/Service"); +const QString propertiesInterface = QStringLiteral("org.freedesktop.DBus.Properties"); +const QString methodPropertiesChanged = QStringLiteral("PropertiesChanged"); +} // namespace + +class LocationWatcherPrivate: public QObject +{ + Q_OBJECT + +public: + LocationWatcherPrivate(ProcessControl *processControl); + +private Q_SLOTS: + void onPropertiesChanged(const QString &interface, + const QVariantMap &changedProps, + const QStringList &invalidatedProps); + +private: + friend class LocationWatcher; + ProcessControl *m_processControl; + QDBusConnection m_connection; + QStringList m_clientApplications; +}; + +LocationWatcherPrivate::LocationWatcherPrivate(ProcessControl *processControl): + QObject(), + m_processControl(processControl), + m_connection(QDBusConnection::systemBus()) +{ + m_connection.connect(locationServiceName, + locationObjectPath, + propertiesInterface, + methodPropertiesChanged, + this, + SLOT(onPropertiesChanged(QString,QVariantMap,QStringList))); +} + +void LocationWatcherPrivate::onPropertiesChanged(const QString &interface, + const QVariantMap &changedProps, + const QStringList &invalidatedProps) +{ + Q_UNUSED(interface); + Q_UNUSED(invalidatedProps); + + qDebug() << Q_FUNC_INFO << changedProps; + const auto i = changedProps.find(QStringLiteral("ClientApplications")); + if (i != changedProps.end()) { + const QStringList appIds = i.value().toStringList(); + qDebug() << "Location clients changed:" << appIds; + /* We need to strip off the version (app IDs are in the form + * "__") */ + m_clientApplications.clear(); + for (const QString &appId: appIds) { + QStringList parts = appId.split('_'); + QString versionLessAppId = parts.mid(0, 2).join('_'); + m_clientApplications.append(versionLessAppId); + } + m_processControl->setAwakenProcesses(m_clientApplications); + } +} + +LocationWatcher::LocationWatcher(ProcessControl *processControl): + QObject(processControl), + d_ptr(new LocationWatcherPrivate(processControl)) +{ +} + +LocationWatcher::~LocationWatcher() = default; + +#include "LocationWatcher.moc" diff --git a/plugins/ProcessControl/LocationWatcher.h b/plugins/ProcessControl/LocationWatcher.h new file mode 100644 index 0000000000..bd3abec3b4 --- /dev/null +++ b/plugins/ProcessControl/LocationWatcher.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2021 UBports Foundation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Authors: Alberto Mardegan + */ + +#ifndef LOMIRI_LOCATIONWATCHER_H +#define LOMIRI_LOCATIONWATCHER_H + +#include +#include + +class ProcessControl; + +class LocationWatcherPrivate; +class LocationWatcher: public QObject +{ + Q_OBJECT + +public: + explicit LocationWatcher(ProcessControl *processControl); + ~LocationWatcher(); + +private: + Q_DECLARE_PRIVATE(LocationWatcher) + QScopedPointer d_ptr; +}; + +#endif // LOMIRI_LOCATIONWATCHER_H diff --git a/plugins/ProcessControl/ProcessControl.cpp b/plugins/ProcessControl/ProcessControl.cpp new file mode 100644 index 0000000000..56e09b2c04 --- /dev/null +++ b/plugins/ProcessControl/ProcessControl.cpp @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2021 UBports Foundation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Authors: Alberto Mardegan + */ + +#include "ProcessControl.h" + +#include + +class ProcessControlPrivate +{ +public: + ProcessControlPrivate(ProcessControl *q); + +private: + friend class ProcessControl; + QStringList m_awakenProcesses; +}; + +ProcessControlPrivate::ProcessControlPrivate(ProcessControl *q) +{ +} + +ProcessControl::ProcessControl(QObject* parent): + QObject(parent), + d_ptr(new ProcessControlPrivate(this)) +{ +} + +ProcessControl::~ProcessControl() = default; + +void ProcessControl::setAwakenProcesses(const QStringList &processes) +{ + Q_D(ProcessControl); + d->m_awakenProcesses = processes; + Q_EMIT awakenProcessesChanged(); +} + +QStringList ProcessControl::awakenProcesses() const +{ + Q_D(const ProcessControl); + return d->m_awakenProcesses; +} diff --git a/plugins/ProcessControl/ProcessControl.h b/plugins/ProcessControl/ProcessControl.h new file mode 100644 index 0000000000..953f5f5173 --- /dev/null +++ b/plugins/ProcessControl/ProcessControl.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2021 UBports Foundation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Authors: Alberto Mardegan + */ + +#ifndef LOMIRI_PROCESSCONTROL_H +#define LOMIRI_PROCESSCONTROL_H + +#include +#include +#include + +class ProcessControlPrivate; +class ProcessControl: public QObject +{ + Q_OBJECT + Q_PROPERTY(QStringList awakenProcesses READ awakenProcesses + NOTIFY awakenProcessesChanged) + +public: + explicit ProcessControl(QObject *parent = 0); + ~ProcessControl(); + + void setAwakenProcesses(const QStringList &processes); + QStringList awakenProcesses() const; + +Q_SIGNALS: + void awakenProcessesChanged(); + +private: + Q_DECLARE_PRIVATE(ProcessControl) + QScopedPointer d_ptr; +}; + +#endif // LOMIRI_PROCESSCONTROL_H diff --git a/plugins/ProcessControl/com.lomiri.ProcessControl.xml b/plugins/ProcessControl/com.lomiri.ProcessControl.xml new file mode 100644 index 0000000000..51cdd7e95a --- /dev/null +++ b/plugins/ProcessControl/com.lomiri.ProcessControl.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + diff --git a/plugins/ProcessControl/plugin.cpp b/plugins/ProcessControl/plugin.cpp new file mode 100644 index 0000000000..679df5e8c7 --- /dev/null +++ b/plugins/ProcessControl/plugin.cpp @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2021 UBports Foundation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Authors: Alberto Mardegan + */ + +#include "plugin.h" + +#include "LocationWatcher.h" +#include "ProcessControl.h" + +#include + +static QObject *service_provider(QQmlEngine *engine, QJSEngine *scriptEngine) +{ + Q_UNUSED(engine); + Q_UNUSED(scriptEngine); + + ProcessControl *processControl = new ProcessControl(); + new LocationWatcher(processControl); + + return processControl; +} + +void ProcessControlPlugin::registerTypes(const char *uri) +{ + Q_ASSERT(uri == QLatin1String("ProcessControl")); + qmlRegisterSingletonType(uri, 0, 1, "ProcessControl", service_provider); +} diff --git a/plugins/ProcessControl/plugin.h b/plugins/ProcessControl/plugin.h new file mode 100644 index 0000000000..745cbc5e2b --- /dev/null +++ b/plugins/ProcessControl/plugin.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2021 UBports Foundation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Authors: Alberto Mardegan + */ + +#ifndef LOMIRI_PROCESSCONTROL_PLUGIN_H +#define LOMIRI_PROCESSCONTROL_PLUGIN_H + +#include +#include + +class ProcessControlPlugin : public QQmlExtensionPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface") + +public: + void registerTypes(const char *uri) override; +}; + +#endif // LOMIRI_PROCESSCONTROL_PLUGIN_H diff --git a/plugins/ProcessControl/qmldir b/plugins/ProcessControl/qmldir new file mode 100644 index 0000000000..8bb58646c7 --- /dev/null +++ b/plugins/ProcessControl/qmldir @@ -0,0 +1,3 @@ +module ProcessControl +plugin ProcessControl-qml +typeinfo ProcessControl.qmltypes diff --git a/qml/Stage/Stage.qml b/qml/Stage/Stage.qml index 8c97bc4497..4e58781f96 100644 --- a/qml/Stage/Stage.qml +++ b/qml/Stage/Stage.qml @@ -27,6 +27,7 @@ import GlobalShortcut 1.0 import GSettings 1.0 import "Spread" import "Spread/MathUtils.js" as MathUtils +import ProcessControl 0.1 import WindowManager 1.0 FocusScope { @@ -465,29 +466,34 @@ FocusScope { Instantiator { model: root.applicationManager delegate: QtObject { + id: applicationDelegate + // TODO: figure out some lifecycle policy, like suspending minimized apps + // or something if running windowed. + // TODO: If the device has a dozen suspended apps because it was running + // in staged mode, when it switches to Windowed mode it will suddenly + // resume all those apps at once. We might want to avoid that. + property var requestedState: root.mode === "windowed" + || (!root.suspended && model.application && priv.focusedAppDelegate && + (priv.focusedAppDelegate.appId === model.application.appId || + priv.mainStageAppId === model.application.appId || + priv.sideStageAppId === model.application.appId)) + ? ApplicationInfoInterface.RequestedRunning + : ApplicationInfoInterface.RequestedSuspended + property bool temporaryAwaken: ProcessControl.awakenProcesses.indexOf(model.application.appId) >= 0 + property var stateBinding: Binding { target: model.application property: "requestedState" - - // TODO: figure out some lifecycle policy, like suspending minimized apps - // or something if running windowed. - // TODO: If the device has a dozen suspended apps because it was running - // in staged mode, when it switches to Windowed mode it will suddenly - // resume all those apps at once. We might want to avoid that. - value: root.mode === "windowed" - || (!root.suspended && model.application && priv.focusedAppDelegate && - (priv.focusedAppDelegate.appId === model.application.appId || - priv.mainStageAppId === model.application.appId || - priv.sideStageAppId === model.application.appId)) - ? ApplicationInfoInterface.RequestedRunning - : ApplicationInfoInterface.RequestedSuspended + value: applicationDelegate.requestedState } property var lifecycleBinding: Binding { target: model.application property: "exemptFromLifecycle" value: model.application - ? (!model.application.isTouchApp || isExemptFromLifecycle(model.application.appId)) + ? (!model.application.isTouchApp || + isExemptFromLifecycle(model.application.appId) || + applicationDelegate.temporaryAwaken) : false }