Merge lp:~andreas-pokorny/unity-mir/fix-1240400 into lp:unity-mir
- fix-1240400
- Merge into trunk
Status: | Superseded |
---|---|
Proposed branch: | lp:~andreas-pokorny/unity-mir/fix-1240400 |
Merge into: | lp:unity-mir |
Diff against target: |
1548 lines (+834/-218) 20 files modified
CMakeLists.txt (+1/-0) cmake/LinuxCrossCompile.cmake (+39/-0) cross-compile-chroot.sh (+85/-0) debian/control (+1/-0) scripts/fix-qt-cmake.sh (+10/-0) scripts/setup-partial-armhf-chroot.sh (+67/-0) src/modules/Unity/Application/CMakeLists.txt (+5/-6) src/modules/Unity/Application/application.cpp (+1/-1) src/modules/Unity/Application/application_manager.cpp (+219/-132) src/modules/Unity/Application/application_manager.h (+15/-2) src/modules/Unity/Application/proc_info.cpp (+52/-0) src/modules/Unity/Application/proc_info.h (+48/-0) src/unity-mir/CMakeLists.txt (+3/-5) tests/CMakeLists.txt (+1/-0) tests/application_manager_test.cpp (+137/-64) tests/auto/modules/Unity/Application/CMakeLists.txt (+2/-2) tests/auto/modules/Unity/Application/main.cpp (+5/-6) tests/mock_focus_controller.h (+37/-0) tests/mock_proc_info.h (+37/-0) tests/mock_session.h (+69/-0) |
To merge this branch: | bzr merge lp:~andreas-pokorny/unity-mir/fix-1240400 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Mir development team | Pending | ||
Review via email: mp+207301@code.launchpad.net |
This proposal has been superseded by a proposal from 2014-02-19.
Commit message
Bugfix for unity-mir crash when multiple application instances with the same appId get started & stopped.
This change also introduces further mocks for mir and unity-mir classes and a refactored ApplicationManager. The log traces where extended with more information on the touched application objects.
Description of the change
Bugfix for unity-mir crash when multiple application instances with the same appId get started & stopped.
This change solves the issue to some degree - but cannot solve it entirely - since there is no API yet to get something like an instance id. So closing one application may still close the wrong application.
ApplicationManager had to be refactored. The constructor no longer accesses the QApplication object or connects itself to all the signal sources. This is now encapsulated into a factory class, which also reduces the dependency on mir structures to the FocusController.
- 181. By Alberto Aguirre
-
[cmake] Use XXX_LDFLAGS for libraries found with pkg_check_modules.
Using the pkg given LDFLAGS resolves linking issues when cross-compiling
- 182. By Alberto Aguirre
-
Add dev scripts to support cross-compilation
These scripts are adapted from the mir project.
The build dependencies are parsed from debian/control and
given to debootstrap to setup a basic armhf chroot environment for cross-compilation.These scripts are intended for development purposes only
- 183. By Andreas Pokorny
-
more log traces
- 184. By Andreas Pokorny
-
Adding Proc Info and Mock and a Mir Session Mock for unit testing
- 185. By Andreas Pokorny
-
Fixes Unity8 crash when two instances of the same application are launched
and the second one stops.There is still misbehavior that cannot be resolved without further changes in
upstart-app-launch. I.e. when the second instance is shutdown the existing one
will be closed too, since they use the same appId.The changes in the construction of ApplicationManager where neceessary to
replace the external parts of ApplicationManager with mock objects. - 186. By Andreas Pokorny
-
review findings address
- 187. By Andreas Pokorny
-
Code style changes were not reflected in MockProcInfo
Unmerged revisions
Preview Diff
1 | === modified file 'CMakeLists.txt' |
2 | --- CMakeLists.txt 2014-02-14 15:42:49 +0000 |
3 | +++ CMakeLists.txt 2014-02-19 21:10:08 +0000 |
4 | @@ -59,6 +59,7 @@ |
5 | find_package(Qt5Core REQUIRED) |
6 | find_package(Qt5Quick REQUIRED) |
7 | find_package(Qt5DBus REQUIRED) |
8 | +find_package(Boost 1.50 COMPONENTS system REQUIRED) |
9 | |
10 | find_package(Protobuf REQUIRED) |
11 | if(PROTOBUF_PROTOC_EXECUTABLE STREQUAL "PROTOBUF_PROTOC_EXECUTABLE-NOTFOUND") |
12 | |
13 | === added directory 'cmake' |
14 | === added file 'cmake/LinuxCrossCompile.cmake' |
15 | --- cmake/LinuxCrossCompile.cmake 1970-01-01 00:00:00 +0000 |
16 | +++ cmake/LinuxCrossCompile.cmake 2014-02-19 21:10:08 +0000 |
17 | @@ -0,0 +1,39 @@ |
18 | +set(CMAKE_SYSTEM_NAME Linux) |
19 | +set(CMAKE_SYSTEM_VERSION 1) |
20 | + |
21 | +set(UNITYMIR_CHROOT_DIR $ENV{UNITYMIR_CHROOT_DIR} CACHE STRING "directory containing partial chroot for unity-mir cross-compilation") |
22 | +set(UNITYMIR_ARM_EABI "arm-linux-gnueabihf") |
23 | + |
24 | +set(CMAKE_C_COMPILER /usr/bin/${UNITYMIR_ARM_EABI}-gcc) |
25 | +set(CMAKE_CXX_COMPILER /usr/bin/${UNITYMIR_ARM_EABI}-g++) |
26 | + |
27 | +# where to look to find dependencies in the target environment |
28 | +set(CMAKE_FIND_ROOT_PATH "${UNITYMIR_CHROOT_DIR}") |
29 | + |
30 | +#treat the chroot's includes as system includes |
31 | +include_directories(SYSTEM "${UNITYMIR_CHROOT_DIR}/usr/include" "${UNITYMIR_CHROOT_DIR}/usr/include/${UNITYMIR_ARM_EABI}") |
32 | + |
33 | +list(APPEND CMAKE_SYSTEM_INCLUDE_PATH "${UNITYMIR_CHROOT_DIR}/usr/include" "${UNITYMIR_CHROOT_DIR}/usr/include/${UNITYMIR_ARM_EABI}" ) |
34 | + |
35 | +# Add the chroot libraries as system libraries |
36 | +list(APPEND CMAKE_SYSTEM_LIBRARY_PATH |
37 | + "${UNITYMIR_CHROOT_DIR}/lib" |
38 | + "${UNITYMIR_CHROOT_DIR}/lib/${UNITYMIR_ARM_EABI}" |
39 | + "${UNITYMIR_CHROOT_DIR}/usr/lib" |
40 | + "${UNITYMIR_CHROOT_DIR}/usr/lib/${UNITYMIR_ARM_EABI}" |
41 | +) |
42 | + |
43 | +set(CMAKE_INSTALL_RPATH_USE_LINK_PATH FALSE) |
44 | +set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE) |
45 | +set(CMAKE_EXECUTABLE_RUNTIME_C_FLAG "-Wl,-rpath-link,") |
46 | +set(CMAKE_EXECUTABLE_RUNTIME_CXX_FLAG "-Wl,-rpath-link,") |
47 | +set(CMAKE_INSTALL_RPATH "${UNITYMIR_CHROOT_DIR}/lib:${UNITYMIR_CHROOT_DIR}/lib/${UNITYMIR_ARM_EABI}:${UNITYMIR_CHROOT_DIR}/usr/lib:${UNITYMIR_CHROOT_DIR}/usr/lib/${UNITYMIR_ARM_EABI}:${UNITYMIR_CHROOT_DIR}/usr/lib/${UNITYMIR_ARM_EABI}/mesa-egl") |
48 | + |
49 | +set(ENV{PKG_CONFIG_PATH} "${UNITYMIR_CHROOT_DIR}/usr/lib/pkgconfig:${UNITYMIR_CHROOT_DIR}/usr/lib/${UNITYMIR_ARM_EABI}/pkgconfig") |
50 | +set(ENV{PKG_CONFIG_SYSROOT_DIR} "${UNITYMIR_CHROOT_DIR}") |
51 | + |
52 | +#use only the cross compile system |
53 | +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) |
54 | +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) |
55 | +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) |
56 | + |
57 | |
58 | === added file 'cross-compile-chroot.sh' |
59 | --- cross-compile-chroot.sh 1970-01-01 00:00:00 +0000 |
60 | +++ cross-compile-chroot.sh 2014-02-19 21:10:08 +0000 |
61 | @@ -0,0 +1,85 @@ |
62 | +#!/bin/bash |
63 | +# build script to compile unity-mir for armhf devices |
64 | + |
65 | +set -e |
66 | + |
67 | +usage() { |
68 | + echo "usage: $(basename $0) [-c] [-u]" |
69 | + echo "-c clean before building" |
70 | + echo "-u update partial chroot directory" |
71 | + echo "-h this message" |
72 | +} |
73 | + |
74 | +clean_build_dir() { |
75 | + rm -rf ${1} |
76 | + mkdir ${1} |
77 | +} |
78 | + |
79 | +BUILD_DIR=build-android-arm |
80 | +NUM_JOBS=$(( $(grep -c ^processor /proc/cpuinfo) + 1 )) |
81 | +_do_update_chroot=0 |
82 | + |
83 | +while getopts "cuh" OPTNAME |
84 | +do |
85 | + case $OPTNAME in |
86 | + c ) |
87 | + clean_build_dir ${BUILD_DIR} |
88 | + ;; |
89 | + u ) |
90 | + _do_update_chroot=1 |
91 | + ;; |
92 | + h ) |
93 | + usage |
94 | + exit 0 |
95 | + ;; |
96 | + * ) |
97 | + echo "invalid option specified" |
98 | + usage |
99 | + exit 1 |
100 | + ;; |
101 | + esac |
102 | +done |
103 | + |
104 | + |
105 | +if [ "${UNITYMIR_CHROOT_DIR}" = "" ]; then |
106 | + export UNITYMIR_CHROOT_DIR=$(pwd)/partial-armhf-chroot |
107 | +fi |
108 | + |
109 | +if [ ! -d ${UNITYMIR_CHROOT_DIR} ]; then |
110 | + echo "no partial chroot dir detected. attempting to create one" |
111 | + _do_update_chroot=1 |
112 | +fi |
113 | + |
114 | +if [ ! -d ${BUILD_DIR} ]; then |
115 | + mkdir ${BUILD_DIR} |
116 | +fi |
117 | + |
118 | +if [ ${_do_update_chroot} -eq 1 ] ; then |
119 | + pushd scripts > /dev/null |
120 | + ./setup-partial-armhf-chroot.sh ${UNITYMIR_CHROOT_DIR} |
121 | + popd > /dev/null |
122 | + # force a clean build after an update, since CMake cache maybe out of date |
123 | + clean_build_dir ${BUILD_DIR} |
124 | +fi |
125 | + |
126 | +echo "Using UNITYMIR_CHROOT_DIR: ${UNITYMIR_CHROOT_DIR}" |
127 | + |
128 | +pushd ${BUILD_DIR} > /dev/null |
129 | + |
130 | + export CMAKE_PREFIX_PATH=${UNITYMIR_CHROOT_DIR}/usr/lib/arm-linux-gnueabihf/cmake |
131 | + export PKG_CONFIG_PATH="${UNITYMIR_CHROOT_DIR}/usr/lib/pkgconfig:${UNITYMIR_CHROOT_DIR}/usr/lib/arm-linux-gnueabihf/pkgconfig" |
132 | + export PKG_CONFIG_ALLOW_SYSTEM_CFLAGS=1 |
133 | + export PKG_CONFIG_ALLOW_SYSTEM_LIBS=1 |
134 | + export PKG_CONFIG_SYSROOT_DIR=${UNITYMIR_CHROOT_DIR} |
135 | + export PKG_CONFIG_EXECUTABLE=`which pkg-config` |
136 | + echo "Using PKG_CONFIG_PATH: $PKG_CONFIG_PATH" |
137 | + echo "Using PKG_CONFIG_EXECUTABLE: $PKG_CONFIG_EXECUTABLE" |
138 | + |
139 | + # These are used to make cmake select the host machine QT MOC compiler in the AutoMocInfo module |
140 | + export DEB_HOST_MULTIARCH=arm-linux-gnueabihf |
141 | + export DEB_BUILD_MULTIARCH=$(gcc -dumpmachine) |
142 | + |
143 | + cmake -DCMAKE_TOOLCHAIN_FILE=../cmake/LinuxCrossCompile.cmake .. |
144 | + make -j${NUM_JOBS} |
145 | + |
146 | +popd ${BUILD_DIR} > /dev/null |
147 | |
148 | === modified file 'debian/control' |
149 | --- debian/control 2014-02-14 15:42:49 +0000 |
150 | +++ debian/control 2014-02-19 21:10:08 +0000 |
151 | @@ -6,6 +6,7 @@ |
152 | cmake, |
153 | google-mock (>= 1.6.0+svn437), |
154 | pkg-config, |
155 | + libboost-dev, |
156 | libboost-system-dev, |
157 | libplatform-api1-dev, |
158 | libmirserver-dev (>= 0.1.5), |
159 | |
160 | === added directory 'scripts' |
161 | === added file 'scripts/fix-qt-cmake.sh' |
162 | --- scripts/fix-qt-cmake.sh 1970-01-01 00:00:00 +0000 |
163 | +++ scripts/fix-qt-cmake.sh 2014-02-19 21:10:08 +0000 |
164 | @@ -0,0 +1,10 @@ |
165 | +#!/bin/bash |
166 | + |
167 | +# $1 must contain path to QT cmake files |
168 | +# Given that path, all hardcoded root paths are fixed up |
169 | +for file in $(find ${1} -type f -name \*.cmake) |
170 | +do |
171 | + echo "fixing $file" |
172 | + sed -i 's/NO_DEFAULT_PATH/ONLY_CMAKE_FIND_ROOT_PATH/g' $file |
173 | + sed -i 's/\/usr/${CMAKE_FIND_ROOT_PATH}\/usr/g' $file |
174 | +done |
175 | |
176 | === added file 'scripts/setup-partial-armhf-chroot.sh' |
177 | --- scripts/setup-partial-armhf-chroot.sh 1970-01-01 00:00:00 +0000 |
178 | +++ scripts/setup-partial-armhf-chroot.sh 2014-02-19 21:10:08 +0000 |
179 | @@ -0,0 +1,67 @@ |
180 | +#!/bin/bash |
181 | + |
182 | +set -e |
183 | + |
184 | +if [ -z ${1} ]; then |
185 | + echo "please supply directory to create partial chroot in. (eg, ./setup-partial-armhf-chroot.sh mychroot-dir)" |
186 | + exit |
187 | +fi |
188 | + |
189 | +echo "creating phablet-compatible armhf partial chroot for unity-mir compilation in directory ${1}" |
190 | + |
191 | +if [ ! -d ${1} ]; then |
192 | + mkdir -p ${1} |
193 | +fi |
194 | + |
195 | +DEBCONTROL=$(pwd)/../debian/control |
196 | + |
197 | +pushd ${1} > /dev/null |
198 | + |
199 | +# Empty dpkg status file, so that ALL dependencies are listed with dpkg-checkbuilddeps |
200 | +echo "" > status |
201 | + |
202 | +# Manual error code checking is needed for dpkg-checkbuilddeps |
203 | +set +e |
204 | + |
205 | +# Parse dependencies from debian/control |
206 | +# dpkg-checkbuilddeps returns 1 when dependencies are not met and the list is sent to stderr |
207 | +builddeps=$(dpkg-checkbuilddeps -a armhf --admindir=. ${DEBCONTROL} 2>&1 ) |
208 | +if [ $? -ne 1 ] ; then |
209 | + echo "${builddeps}" |
210 | + exit 2 |
211 | +fi |
212 | + |
213 | +# now turn exit on error option |
214 | +set -e |
215 | + |
216 | +# Sanitize dependencies list for submission to debootstrap |
217 | +# build-essential is not needed as we are cross-compiling |
218 | +builddeps=$(echo ${builddeps} | sed -e 's/dpkg-checkbuilddeps://g' -e 's/Unmet build dependencies://g' -e 's/build-essential:native//g') |
219 | +builddeps=$(echo ${builddeps} | sed 's/([^)]*)//g') |
220 | +# TODO: figure out why debootstrap is not finding libunity-api-dev package - it doesn't seem to be needed for cross-compilation - is it needed in debian/control? |
221 | +builddeps=$(echo ${builddeps} | sed 's/libunity-api-dev//g') |
222 | +builddeps=$(echo ${builddeps} | sed 's/ /,/g') |
223 | + |
224 | +fakeroot debootstrap --include=${builddeps} --arch=armhf --download-only --variant=buildd trusty . |
225 | + |
226 | +# Remove libc libraries that confuse the cross-compiler |
227 | +rm var/cache/apt/archives/libc-dev*.deb |
228 | +rm var/cache/apt/archives/libc6*.deb |
229 | + |
230 | +for deb in var/cache/apt/archives/* ; do |
231 | +if [ ! -d ${deb} ] ; then |
232 | + echo "unpacking: ${deb}" |
233 | + dpkg -x ${deb} . |
234 | +fi |
235 | +done |
236 | + |
237 | +# Fix up symlinks which asssumed the usual root path |
238 | +for broken_symlink in $(find . -name \*.so -type l -xtype l) ; do |
239 | + ln -sf $(pwd)$(readlink ${broken_symlink}) ${broken_symlink} |
240 | +done |
241 | + |
242 | +popd > /dev/null |
243 | + |
244 | +# QT CMake files have hardcoded root paths - fix them up |
245 | +./fix-qt-cmake.sh ${1}/usr/lib/arm-linux-gnueabihf/cmake/ |
246 | + |
247 | |
248 | === modified file 'src/modules/Unity/Application/CMakeLists.txt' |
249 | --- src/modules/Unity/Application/CMakeLists.txt 2014-01-27 11:29:44 +0000 |
250 | +++ src/modules/Unity/Application/CMakeLists.txt 2014-02-19 21:10:08 +0000 |
251 | @@ -31,6 +31,7 @@ |
252 | inputfilterarea.cpp |
253 | processcontroller.h |
254 | processcontroller.cpp |
255 | + proc_info.cpp |
256 | shellinputarea.cpp |
257 | ubuntukeyboardinfo.cpp |
258 | |
259 | @@ -74,12 +75,10 @@ |
260 | ${CMAKE_THREAD_LIBS_INIT} |
261 | |
262 | ${GLIB_LDFLAGS} |
263 | - ${UBUNTU_PLATFORM_API_LIBRARIES} |
264 | - ${MIRCOMMON_LIBRARIES} |
265 | - ${MIRSERVER_LIBRARIES} |
266 | - ${PROCESS_CPP_LIBRARIES} |
267 | - ${UBUNTU_PLATFORM_API_LIBRARIES} |
268 | - ${UPSTART_APP_LAUNCH_LIBRARIES} |
269 | + ${UBUNTU_PLATFORM_API_LDFLAGS} |
270 | + ${MIRSERVER_LDFLAGS} |
271 | + ${PROCESS_CPP_LDFLAGS} |
272 | + ${UPSTART_APP_LAUNCH_LDFLAGS} |
273 | |
274 | ubuntu_application_api_mirserver |
275 | ) |
276 | |
277 | === modified file 'src/modules/Unity/Application/application.cpp' |
278 | --- src/modules/Unity/Application/application.cpp 2014-01-27 11:29:44 +0000 |
279 | +++ src/modules/Unity/Application/application.cpp 2014-02-19 21:10:08 +0000 |
280 | @@ -52,7 +52,7 @@ |
281 | |
282 | Application::~Application() |
283 | { |
284 | - DLOG("Application::~Application"); |
285 | + DLOG("Application::~Application (this=%p)", this); |
286 | delete m_desktopData; |
287 | } |
288 | |
289 | |
290 | === modified file 'src/modules/Unity/Application/application_manager.cpp' |
291 | --- src/modules/Unity/Application/application_manager.cpp 2014-02-11 09:47:56 +0000 |
292 | +++ src/modules/Unity/Application/application_manager.cpp 2014-02-19 21:10:08 +0000 |
293 | @@ -16,6 +16,7 @@ |
294 | |
295 | // local |
296 | #include "application_manager.h" |
297 | +#include "proc_info.h" |
298 | #include "application.h" |
299 | #include "desktopfilereader.h" |
300 | #include "dbuswindowstack.h" |
301 | @@ -51,26 +52,130 @@ |
302 | |
303 | using namespace unity::shell::application; |
304 | |
305 | -ApplicationManager *ApplicationManager::the_application_manager = nullptr; |
306 | +namespace |
307 | +{ |
308 | + |
309 | +QSize get_display_size(std::shared_ptr<mir::graphics::Display> const& display) { |
310 | + // Obtain display size |
311 | + mir::geometry::Rectangles view_area; |
312 | + display->for_each_display_buffer( |
313 | + [&view_area](mir::graphics::DisplayBuffer const& db) |
314 | + { |
315 | + view_area.add(db.view_area()); |
316 | + }); |
317 | + |
318 | + return QSize( |
319 | + view_area.bounding_rectangle().size.width.as_uint32_t(), |
320 | + view_area.bounding_rectangle().size.height.as_uint32_t() |
321 | + ); |
322 | +} |
323 | + |
324 | + |
325 | +void connectToSessionListener(ApplicationManager * manager, SessionListener * listener) |
326 | +{ |
327 | + |
328 | + QObject::connect(listener, &SessionListener::sessionStarting, |
329 | + manager, &ApplicationManager::onSessionStarting); |
330 | + QObject::connect(listener, &SessionListener::sessionStopping, |
331 | + manager, &ApplicationManager::onSessionStopping); |
332 | + QObject::connect(listener, &SessionListener::sessionFocused, |
333 | + manager, &ApplicationManager::onSessionFocused, Qt::QueuedConnection); |
334 | + QObject::connect(listener, &SessionListener::sessionUnfocused, |
335 | + manager, &ApplicationManager::onSessionUnfocused); |
336 | + QObject::connect(listener, &SessionListener::sessionCreatedSurface, |
337 | + manager, &ApplicationManager::onSessionCreatedSurface); |
338 | + QObject::connect(listener, &SessionListener::sessionStarting, |
339 | + manager, &ApplicationManager::onSessionStarting); |
340 | + QObject::connect(listener, &SessionListener::sessionStopping, |
341 | + manager, &ApplicationManager::onSessionStopping); |
342 | + QObject::connect(listener, &SessionListener::sessionFocused, |
343 | + manager, &ApplicationManager::onSessionFocused, Qt::QueuedConnection); |
344 | + QObject::connect(listener, &SessionListener::sessionUnfocused, |
345 | + manager, &ApplicationManager::onSessionUnfocused); |
346 | + QObject::connect(listener, &SessionListener::sessionCreatedSurface, |
347 | + manager, &ApplicationManager::onSessionCreatedSurface); |
348 | +} |
349 | + |
350 | +void connectToSessionAuthorizer(ApplicationManager * manager, SessionAuthorizer * authorizer) |
351 | +{ |
352 | + QObject::connect(authorizer, &SessionAuthorizer::requestAuthorizationForSession, |
353 | + manager, &ApplicationManager::authorizeSession, Qt::BlockingQueuedConnection); |
354 | +} |
355 | + |
356 | + |
357 | +void connectToPlacementStrategy(ApplicationManager * manager, InitialSurfacePlacementStrategy * strategy) |
358 | +{ |
359 | + QObject::connect(strategy, &InitialSurfacePlacementStrategy::requestPlacementForSession, |
360 | + manager, &ApplicationManager::placeSession, Qt::DirectConnection); |
361 | + |
362 | +} |
363 | + |
364 | +void connectToTaskController(ApplicationManager * manager, TaskController * controller) |
365 | +{ |
366 | + QObject::connect(controller, &TaskController::processStartReport, |
367 | + manager, &ApplicationManager::onProcessStartReportReceived); |
368 | + QObject::connect(controller, &TaskController::processStopped, |
369 | + manager, &ApplicationManager::onProcessStopped); |
370 | + QObject::connect(controller, &TaskController::requestFocus, |
371 | + manager, &ApplicationManager::onFocusRequested); |
372 | + QObject::connect(controller, &TaskController::requestResume, |
373 | + manager, &ApplicationManager::onResumeRequested); |
374 | + |
375 | +} |
376 | +} |
377 | + |
378 | +QSharedPointer<ApplicationManager> ApplicationManager::Factory::Factory::create() |
379 | +{ |
380 | + QMirServerApplication* mirServerApplication = dynamic_cast<QMirServerApplication*>(QCoreApplication::instance()); |
381 | + if (mirServerApplication == NULL) { |
382 | + LOG("Need to use QMirServerApplication"); |
383 | + QCoreApplication::quit(); |
384 | + return QSharedPointer<ApplicationManager>(nullptr); |
385 | + } |
386 | + |
387 | + ShellServerConfiguration * mirServer = mirServerApplication->server(); |
388 | + |
389 | + QSize displaySize{get_display_size(mirServer->the_display())}; |
390 | + |
391 | + QSharedPointer<upstart::ApplicationController> appController(new upstart::ApplicationController()); |
392 | + QSharedPointer<TaskController> taskController(new TaskController(nullptr, appController)); |
393 | + QSharedPointer<DesktopFileReader::Factory> fileReaderFactory(new DesktopFileReader::Factory()); |
394 | + QSharedPointer<ProcInfo> procInfo(new ProcInfo()); |
395 | + QSharedPointer<ApplicationManager> appManager( |
396 | + new ApplicationManager( |
397 | + taskController, |
398 | + fileReaderFactory, |
399 | + procInfo, |
400 | + mirServer->the_focus_controller(), |
401 | + displaySize |
402 | + ) |
403 | + ); |
404 | + |
405 | + |
406 | + connectToSessionListener(appManager.data(), mirServer->sessionListener()); |
407 | + connectToSessionAuthorizer(appManager.data(), mirServer->sessionAuthorizer()); |
408 | + connectToPlacementStrategy(appManager.data(), mirServer->placementStrategy()); |
409 | + connectToTaskController(appManager.data(), taskController.data()); |
410 | + |
411 | + return appManager; |
412 | +} |
413 | |
414 | ApplicationManager* ApplicationManager::singleton() |
415 | { |
416 | - if (!the_application_manager) { |
417 | - the_application_manager = new ApplicationManager( |
418 | - QSharedPointer<TaskController>( |
419 | - new TaskController( |
420 | - nullptr, |
421 | - QSharedPointer<ApplicationController>( |
422 | - new upstart::ApplicationController()))), |
423 | - QSharedPointer<DesktopFileReader::Factory>( |
424 | - new DesktopFileReader::Factory())); |
425 | + static QSharedPointer<ApplicationManager> instance; |
426 | + if (!instance) { |
427 | + Factory appFactory; |
428 | + instance = appFactory.create(); |
429 | } |
430 | - return the_application_manager; |
431 | + return instance.data(); |
432 | } |
433 | |
434 | ApplicationManager::ApplicationManager( |
435 | const QSharedPointer<TaskController>& taskController, |
436 | const QSharedPointer<DesktopFileReader::Factory>& desktopFileReaderFactory, |
437 | + const QSharedPointer<ProcInfo>& procInfo, |
438 | + const std::shared_ptr<mir::shell::FocusController> & controller, |
439 | + const QSize & displaySize, |
440 | QObject *parent) |
441 | : ApplicationManagerInterface(parent) |
442 | , m_focusedApplication(nullptr) |
443 | @@ -79,63 +184,18 @@ |
444 | , m_msApplicationToBeFocused(nullptr) |
445 | , m_ssApplicationToBeFocused(nullptr) |
446 | , m_lifecycleExceptions(QStringList() << "com.ubuntu.music") |
447 | + , m_focusController(controller) |
448 | + , m_dbusWindowStack(new DBusWindowStack(this)) |
449 | , m_taskController(taskController) |
450 | , m_desktopFileReaderFactory(desktopFileReaderFactory) |
451 | + , m_procInfo(procInfo) |
452 | , m_gridUnitPx(8) |
453 | , m_fenceNext(false) |
454 | + , m_displaySize(displaySize) |
455 | , m_panelHeight(54) |
456 | { |
457 | DLOG("ApplicationManager::ApplicationManager (this=%p)", this); |
458 | |
459 | - QMirServerApplication* mirServerApplication = dynamic_cast<QMirServerApplication*>(QCoreApplication::instance()); |
460 | - if (mirServerApplication == NULL) { |
461 | - LOG("Need to use QMirServerApplication"); |
462 | - QCoreApplication::quit(); |
463 | - return; |
464 | - } |
465 | - m_mirServer = mirServerApplication->server(); |
466 | - |
467 | - QObject::connect(m_mirServer->sessionListener(), &SessionListener::sessionStarting, |
468 | - this, &ApplicationManager::onSessionStarting); |
469 | - QObject::connect(m_mirServer->sessionListener(), &SessionListener::sessionStopping, |
470 | - this, &ApplicationManager::onSessionStopping); |
471 | - QObject::connect(m_mirServer->sessionListener(), &SessionListener::sessionFocused, |
472 | - this, &ApplicationManager::onSessionFocused, Qt::QueuedConnection); |
473 | - QObject::connect(m_mirServer->sessionListener(), &SessionListener::sessionUnfocused, |
474 | - this, &ApplicationManager::onSessionUnfocused); |
475 | - QObject::connect(m_mirServer->sessionListener(), &SessionListener::sessionCreatedSurface, |
476 | - this, &ApplicationManager::onSessionCreatedSurface); |
477 | - QObject::connect(m_mirServer->sessionAuthorizer(), &SessionAuthorizer::requestAuthorizationForSession, |
478 | - this, &ApplicationManager::authorizeSession, Qt::BlockingQueuedConnection); |
479 | - QObject::connect(m_mirServer->placementStrategy(), &InitialSurfacePlacementStrategy::requestPlacementForSession, |
480 | - this, &ApplicationManager::placeSession, Qt::DirectConnection); |
481 | - |
482 | - QObject::connect(m_taskController.data(), &TaskController::processStartReport, |
483 | - this, &ApplicationManager::onProcessStartReportReceived); |
484 | - QObject::connect(m_taskController.data(), &TaskController::processStopped, |
485 | - this, &ApplicationManager::onProcessStopped); |
486 | - QObject::connect(m_taskController.data(), &TaskController::requestFocus, |
487 | - this, &ApplicationManager::onFocusRequested); |
488 | - QObject::connect(m_taskController.data(), &TaskController::requestResume, |
489 | - this, &ApplicationManager::onResumeRequested); |
490 | - |
491 | - m_dbusWindowStack = new DBusWindowStack(this); |
492 | - |
493 | - std::shared_ptr<mir::graphics::Display> mirDisplay = m_mirServer->the_display(); |
494 | - |
495 | - // Obtain display size |
496 | - mir::geometry::Rectangles view_area; |
497 | - mirDisplay->for_each_display_buffer( |
498 | - [&view_area](mir::graphics::DisplayBuffer const& db) |
499 | - { |
500 | - view_area.add(db.view_area()); |
501 | - }); |
502 | - |
503 | - m_displaySize = QSize( |
504 | - view_area.bounding_rectangle().size.width.as_uint32_t(), |
505 | - view_area.bounding_rectangle().size.height.as_uint32_t() |
506 | - ); |
507 | - |
508 | // Setup panel height |
509 | QByteArray gridUnitString = qgetenv("GRID_UNIT_PX"); |
510 | if (!gridUnitString.isEmpty()) { |
511 | @@ -222,6 +282,7 @@ |
512 | if (application == nullptr) |
513 | return; |
514 | |
515 | + DLOG("ApplicationManager::suspend(this=%p, application(%p)->appId(%s) )",this, application, qPrintable(application->appId())); |
516 | // Present in exceptions list, return. |
517 | if (!m_lifecycleExceptions.filter(application->appId().section('_',0,0)).empty()) |
518 | return; |
519 | @@ -232,8 +293,8 @@ |
520 | |
521 | bool ApplicationManager::focusApplication(const QString &appId) |
522 | { |
523 | - DLOG("ApplicationManager::focusApplication (this=%p, appId=%s)", this, qPrintable(appId)); |
524 | Application *application = findApplication(appId); |
525 | + DLOG("ApplicationManager::focusApplication (this=%p, application=%p, appId=%s)", this, application, qPrintable(appId)); |
526 | |
527 | if (!application) { |
528 | DLOG("No such running application '%s'", qPrintable(appId)); |
529 | @@ -256,7 +317,7 @@ |
530 | move(from, m_applications.length()-1); |
531 | } else { |
532 | if (application->session()) |
533 | - m_mirServer->the_focus_controller()->set_focus_to(application->session()); |
534 | + m_focusController->set_focus_to(application->session()); |
535 | } |
536 | |
537 | // FIXME(dandrader): lying here. The operation is async. So we will only know whether |
538 | @@ -275,7 +336,7 @@ |
539 | // Clear both stages |
540 | m_msApplicationToBeFocused = nullptr; |
541 | m_ssApplicationToBeFocused = nullptr; |
542 | - m_mirServer->the_focus_controller()->set_focus_to(NULL); //FIXME(greyback) |
543 | + m_focusController->set_focus_to(NULL); //FIXME(greyback) |
544 | } |
545 | |
546 | Application* ApplicationManager::startApplication(const QString &appId, |
547 | @@ -294,6 +355,16 @@ |
548 | return nullptr; |
549 | } |
550 | |
551 | + { |
552 | + Application * application = findApplication(appId); |
553 | + if (application) |
554 | + { |
555 | + DLOG("ApplicationManager::startApplication - application already " |
556 | + "exists: (this=%p, app=%p, appId=%s)", |
557 | + this, application, qPrintable(appId)); |
558 | + } |
559 | + } |
560 | + |
561 | Application* application = new Application( |
562 | m_taskController, |
563 | m_desktopFileReaderFactory->createInstanceForAppId(appId), |
564 | @@ -320,7 +391,9 @@ |
565 | this, qPrintable(appId), (failure) ? 'Y' : 'N'); |
566 | |
567 | if (failure) { |
568 | - onProcessStopped(appId, true); |
569 | + DLOG("ApplicationManager::onProcessStartReportReceived handling failure:"); |
570 | + stopStartingApplication(appId); |
571 | + return; |
572 | } |
573 | |
574 | Application *application = findApplication(appId); |
575 | @@ -338,30 +411,23 @@ |
576 | add(application); |
577 | Q_EMIT focusRequested(appId); |
578 | } |
579 | + else { |
580 | + DLOG("ApplicationManager::onProcessStartReportReceived application already found: (app=%p, appId=%s)", application, qPrintable(appId)); |
581 | + } |
582 | } |
583 | |
584 | bool ApplicationManager::stopApplication(const QString &appId) |
585 | { |
586 | - DLOG("ApplicationManager::stopApplication (this=%p, appId=%s)", this, qPrintable(appId)); |
587 | - |
588 | Application *application = findApplication(appId); |
589 | + DLOG("ApplicationManager::stopApplication (this=%p, application=%p, appId=%s)", this, application, qPrintable(appId)); |
590 | |
591 | if (!application) { |
592 | DLOG("No such running application '%s'", qPrintable(appId)); |
593 | return false; |
594 | } |
595 | |
596 | - if (application == m_focusedApplication) { |
597 | - // TODO(greyback) What to do?? Focus next app, or unfocus everything?? |
598 | - m_focusedApplication = NULL; |
599 | - Q_EMIT focusedApplicationIdChanged(); |
600 | - } |
601 | + checkFocusOnRemovedApplication(application); |
602 | |
603 | - if (application == m_mainStageApplication) |
604 | - m_mainStageApplication = nullptr; |
605 | - if (application == m_sideStageApplication) |
606 | - m_sideStageApplication = nullptr; |
607 | - |
608 | remove(application); |
609 | m_dbusWindowStack->WindowDestroyed(0, application->appId()); |
610 | |
611 | @@ -376,37 +442,28 @@ |
612 | return result; |
613 | } |
614 | |
615 | +void ApplicationManager::stopStartingApplication(const QString &appId) |
616 | +{ |
617 | + Application *application = findApplication(appId); |
618 | + |
619 | + if (application && application->state() == Application::Starting) { |
620 | + shutdownApplication(application); |
621 | + } |
622 | + else if (application) { |
623 | + DLOG("onProcessStartReportReceived failure - but application=%p, appId=%s is not in Starting state",application, qPrintable(appId)); |
624 | + } |
625 | +} |
626 | + |
627 | void ApplicationManager::onProcessStopped(const QString &appId, const bool unexpected) |
628 | { |
629 | Application *application = findApplication(appId); |
630 | + DLOG("ApplicationManager::onProcessStopped (this=%p, application=%p, appId=%s)", this, application, qPrintable(appId)); |
631 | |
632 | // if shell did not stop the application, but upstart says it died, we assume the process has been |
633 | // killed, so it can be respawned later. Only exception is if that application is focused or running |
634 | // as then it most likely crashed. Update this logic when upstart gives some failure info. |
635 | if (application) { |
636 | - bool removeApplication = false; |
637 | - |
638 | - if (application == m_focusedApplication) { |
639 | - // Very bad case where focused application dies. Remove from list. Should give error message |
640 | - m_focusedApplication = nullptr; |
641 | - Q_EMIT focusedApplicationIdChanged(); |
642 | - removeApplication = true; |
643 | - } |
644 | - |
645 | - if (application->state() == Application::Running || application->state() == Application::Starting) { |
646 | - // Application probably crashed, else OOM killer struck. Either way state wasn't saved |
647 | - // so just remove application |
648 | - removeApplication = true; |
649 | - } else if (application->state() == Application::Suspended) { |
650 | - application->setState(Application::Stopped); |
651 | - application->setSession(nullptr); |
652 | - } |
653 | - |
654 | - if (removeApplication) { |
655 | - remove(application); |
656 | - m_dbusWindowStack->WindowDestroyed(0, application->appId()); |
657 | - delete application; |
658 | - } |
659 | + shutdownApplication(application); |
660 | } |
661 | |
662 | if (unexpected) { |
663 | @@ -415,6 +472,27 @@ |
664 | } |
665 | } |
666 | |
667 | +void ApplicationManager::shutdownApplication(Application* application) |
668 | +{ |
669 | + bool removeApplication = checkFocusOnRemovedApplication(application); |
670 | + |
671 | + if (application->state() == Application::Running || application->state() == Application::Starting) { |
672 | + // Application probably crashed, else OOM killer struck. Either way state wasn't saved |
673 | + // so just remove application |
674 | + removeApplication = true; |
675 | + } else if (application->state() == Application::Suspended) { |
676 | + application->setState(Application::Stopped); |
677 | + application->setSession(nullptr); |
678 | + } |
679 | + |
680 | + if (removeApplication) { |
681 | + remove(application); |
682 | + m_dbusWindowStack->WindowDestroyed(0, application->appId()); |
683 | + delete application; |
684 | + } |
685 | + |
686 | +} |
687 | + |
688 | void ApplicationManager::onFocusRequested(const QString& appId) |
689 | { |
690 | DLOG("ApplicationManager::onFocusRequested (this=%p, appId=%s)", this, qPrintable(appId)); |
691 | @@ -424,9 +502,9 @@ |
692 | |
693 | void ApplicationManager::onResumeRequested(const QString& appId) |
694 | { |
695 | - DLOG("ApplicationManager::onResumeRequested (this=%p, appId=%s)", this, qPrintable(appId)); |
696 | - |
697 | Application *application = findApplication(appId); |
698 | + DLOG("ApplicationManager::onResumeRequested (this=%p, application=%p, appId=%s)", this, application, qPrintable(appId)); |
699 | + |
700 | |
701 | if (!application) { |
702 | DLOG("ApplicationManager::onResumeRequested: No such running application '%s'", qPrintable(appId)); |
703 | @@ -452,6 +530,7 @@ |
704 | if (app->state() == Application::Starting |
705 | && m_taskController->appIdHasProcessId(app->appId(), pid)) { |
706 | app->setPid(pid); |
707 | + DLOG("ApplicationManager::authorizeSession - connecting: application=%p and pid=%lld", app, pid); |
708 | authorized = true; |
709 | return; |
710 | } |
711 | @@ -463,41 +542,35 @@ |
712 | * notify shell it is starting an application and so shell should allow it. Also reads |
713 | * the --stage parameter to determine the desired stage |
714 | */ |
715 | - QFile cmdline(QString("/proc/%1/cmdline").arg(pid)); |
716 | - if (!cmdline.open(QIODevice::ReadOnly | QIODevice::Text)) { |
717 | + std::unique_ptr<ProcInfo::CommandLine> info = m_procInfo->command_line(pid); |
718 | + if (!info) { |
719 | DLOG("ApplicationManager REJECTED connection from app with pid %lld as unable to read process command", pid); |
720 | return; |
721 | } |
722 | |
723 | - QByteArray command = cmdline.readLine().replace('\0', ' '); |
724 | - |
725 | - // FIXME: special exception for the OSK - maliit-server - not very secure |
726 | - if (command.startsWith("maliit-server") || command.startsWith("/usr/lib/arm-linux-gnueabihf/qt5/libexec/QtWebProcess") |
727 | - || command.startsWith("/usr/bin/signon-ui")) { |
728 | + if (info->starts_with("maliit-server") || info->starts_with("/usr/lib/arm-linux-gnueabihf/qt5/libexec/QtWebProcess") |
729 | + || info->starts_with("/usr/bin/signon-ui")) { |
730 | authorized = true; |
731 | m_fenceNext = true; |
732 | return; |
733 | } |
734 | |
735 | - QString pattern = QRegularExpression::escape("--desktop_file_hint=") + "(\\S+)"; |
736 | - QRegularExpression regExp(pattern); |
737 | - QRegularExpressionMatch regExpMatch = regExp.match(command); |
738 | + boost::optional<QString> desktopFileName{ info->get_parameter("--desktop_file_hint=") }; |
739 | |
740 | - if (!regExpMatch.hasMatch()) { |
741 | + if (!desktopFileName) { |
742 | LOG("ApplicationManager REJECTED connection from app with pid %lld as no desktop_file_hint specified", pid); |
743 | return; |
744 | } |
745 | |
746 | - QString desktopFileName = regExpMatch.captured(1); |
747 | - DLOG("Process supplied desktop_file_hint, loading '%s'", desktopFileName.toLatin1().data()); |
748 | + DLOG("Process supplied desktop_file_hint, loading '%s'", desktopFileName.get().toLatin1().data()); |
749 | |
750 | // FIXME: right now we support --desktop_file_hint=appId for historical reasons. So let's try that in |
751 | // case we didn't get an existing .desktop file path |
752 | DesktopFileReader* desktopData; |
753 | - if (QFileInfo(desktopFileName).exists()) { |
754 | - desktopData = m_desktopFileReaderFactory->createInstanceForDesktopFile(QFileInfo(desktopFileName)); |
755 | + if (QFileInfo(desktopFileName.get()).exists()) { |
756 | + desktopData = m_desktopFileReaderFactory->createInstanceForDesktopFile(QFileInfo(desktopFileName.get())); |
757 | } else { |
758 | - desktopData = m_desktopFileReaderFactory->createInstanceForAppId(desktopFileName); |
759 | + desktopData = m_desktopFileReaderFactory->createInstanceForAppId(desktopFileName.get()); |
760 | } |
761 | |
762 | if (!desktopData->loaded()) { |
763 | @@ -521,18 +594,15 @@ |
764 | |
765 | // if stage supplied in CLI, fetch that |
766 | Application::Stage stage = Application::MainStage; |
767 | - pattern = QRegularExpression::escape("--stage_hint=") + "(\\S+)"; |
768 | - regExp.setPattern(pattern); |
769 | - regExpMatch = regExp.match(command); |
770 | + boost::optional<QString> stageParam = info->get_parameter("--stage_hint="); |
771 | |
772 | - if (regExpMatch.hasMatch() && regExpMatch.captured(1) == "side_stage") { |
773 | + if (stageParam && stageParam.get() == "side_stage") { |
774 | stage = Application::SideStage; |
775 | } |
776 | |
777 | DLOG("Existing process with pid %lld appeared, adding '%s' to application lists", pid, desktopData->name().toLatin1().data()); |
778 | |
779 | - QString argStr(command.data()); |
780 | - QStringList arguments(argStr.split(' ')); |
781 | + QStringList arguments(info->as_string_list()); |
782 | application = new Application(m_taskController, desktopData, Application::Starting, arguments, this); |
783 | application->setPid(pid); |
784 | application->setStage(stage); |
785 | @@ -542,9 +612,9 @@ |
786 | |
787 | void ApplicationManager::placeSession(msh::Session const* session, uint32_t &x, uint32_t &y) |
788 | { |
789 | - DLOG("ApplicationManager::placeSession (this=%p, session=%p)", this, session); |
790 | + Application* application = findApplicationWithSession(session); |
791 | + DLOG("ApplicationManager::placeSession (this=%p, application=%p, session=%p, name=%s)", this, application, session, session?(session->name().c_str()):"null"); |
792 | |
793 | - Application* application = findApplicationWithSession(session); |
794 | |
795 | // Application defaults |
796 | x = 0; |
797 | @@ -569,7 +639,7 @@ |
798 | |
799 | void ApplicationManager::onSessionStarting(std::shared_ptr<msh::Session> const& session) |
800 | { |
801 | - DLOG("ApplicationManager::onSessionStarting (this=%p, application=%s)", this, session->name().c_str()); |
802 | + DLOG("ApplicationManager::onSessionStarting (this=%p, application=%s)", this, session?session->name().c_str():"null"); |
803 | |
804 | if (m_fenceNext) { |
805 | m_fenceNext = false; |
806 | @@ -592,10 +662,11 @@ |
807 | |
808 | void ApplicationManager::onSessionStopping(std::shared_ptr<msh::Session> const& session) |
809 | { |
810 | - DLOG("ApplicationManager::onSessionStopping (this=%p, application=%s)", this, session->name().c_str()); |
811 | - |
812 | // in case application closed not by hand of shell, check again here: |
813 | Application* application = findApplicationWithSession(session); |
814 | + |
815 | + DLOG("ApplicationManager::onSessionStopping (this=%p, application=%p, appId=%s, session name=%s)", this, application, application?qPrintable(application->appId()):"null", session?session->name().c_str():"null"); |
816 | + |
817 | if (application) { |
818 | bool removeApplication = true; |
819 | |
820 | @@ -604,7 +675,7 @@ |
821 | application->setSession(nullptr); |
822 | m_dbusWindowStack->WindowDestroyed(0, application->appId()); |
823 | if (application != m_focusedApplication) { |
824 | - removeApplication = false; |
825 | + removeApplication = false; |
826 | } |
827 | } |
828 | |
829 | @@ -626,8 +697,8 @@ |
830 | |
831 | void ApplicationManager::onSessionFocused(std::shared_ptr<msh::Session> const& session) |
832 | { |
833 | - DLOG("ApplicationManager::onSessionFocused (this=%p, session=%p)", this, session.get()); |
834 | Application* application = findApplicationWithSession(session); |
835 | + DLOG("ApplicationManager::onSessionFocused (this=%p, application=%p, appId=%s, session name=%s)", this, application, application?qPrintable(application->appId()):"null", session?session->name().c_str():"null"); |
836 | |
837 | // Don't give application focus until it has created it's surface, when it is set as state "Running" |
838 | // and only notify shell of focus changes that it actually expects |
839 | @@ -649,7 +720,7 @@ |
840 | |
841 | void ApplicationManager::onSessionUnfocused() |
842 | { |
843 | - DLOG("ApplicationManager::onSessionUnfocused (this=%p)", this); |
844 | + DLOG("ApplicationManager::onSessionUnfocused (this=%p, application=%p)", this, m_focusedApplication); |
845 | if (NULL != m_focusedApplication) { |
846 | Q_ASSERT(m_focusedApplication->focused()); |
847 | m_focusedApplication->setFocused(false); |
848 | @@ -683,7 +754,7 @@ |
849 | |
850 | void ApplicationManager::setFocused(Application *application) |
851 | { |
852 | - DLOG("ApplicationManager::setFocused (appId=%s)", qPrintable(application->appId())); |
853 | + DLOG("ApplicationManager::setFocused (application=%p, appId=%s)", application, qPrintable(application->appId())); |
854 | |
855 | if (application == m_focusedApplication) |
856 | return; |
857 | @@ -769,6 +840,11 @@ |
858 | DASSERT(application != NULL); |
859 | DLOG("ApplicationManager::remove (this=%p, application='%s')", this, qPrintable(application->name())); |
860 | |
861 | + if (application == m_sideStageApplication) |
862 | + m_sideStageApplication = nullptr; |
863 | + if (application == m_mainStageApplication) |
864 | + m_mainStageApplication = nullptr; |
865 | + |
866 | int i = m_applications.indexOf(application); |
867 | if (i != -1) { |
868 | beginRemoveRows(QModelIndex(), i, i); |
869 | @@ -803,3 +879,14 @@ |
870 | |
871 | return QModelIndex(); |
872 | } |
873 | + |
874 | +bool ApplicationManager::checkFocusOnRemovedApplication(Application * application) |
875 | +{ |
876 | + if (application == m_focusedApplication) { |
877 | + // TODO(greyback) What to do?? Focus next app, or unfocus everything?? |
878 | + m_focusedApplication = nullptr; |
879 | + Q_EMIT focusedApplicationIdChanged(); |
880 | + return true; |
881 | + } |
882 | + return false; |
883 | +} |
884 | |
885 | === modified file 'src/modules/Unity/Application/application_manager.h' |
886 | --- src/modules/Unity/Application/application_manager.h 2014-01-27 11:29:44 +0000 |
887 | +++ src/modules/Unity/Application/application_manager.h 2014-02-19 21:10:08 +0000 |
888 | @@ -38,6 +38,7 @@ |
889 | class DBusWindowStack; |
890 | class MirSurfaceManager; |
891 | class TaskController; |
892 | +class ProcInfo; |
893 | |
894 | namespace mir { |
895 | namespace geometry { |
896 | @@ -46,6 +47,7 @@ |
897 | namespace shell { |
898 | class Session; |
899 | class Surface; |
900 | + class FocusController; |
901 | } |
902 | } |
903 | |
904 | @@ -55,6 +57,11 @@ |
905 | Q_FLAGS(ExecFlags) |
906 | |
907 | public: |
908 | + class Factory |
909 | + { |
910 | + public: |
911 | + QSharedPointer<ApplicationManager> create(); |
912 | + }; |
913 | // Mapping enums to Ubuntu Platform API enums. |
914 | enum Flag { |
915 | NoFlag = 0x0, |
916 | @@ -66,6 +73,9 @@ |
917 | |
918 | explicit ApplicationManager(const QSharedPointer<TaskController>& taskController, |
919 | const QSharedPointer<DesktopFileReader::Factory>& desktopFileReaderFactory, |
920 | + const QSharedPointer<ProcInfo>& processInfo, |
921 | + std::shared_ptr<mir::shell::FocusController> const& controller, |
922 | + QSize const& displaySize, |
923 | QObject *parent = 0); |
924 | virtual ~ApplicationManager(); |
925 | |
926 | @@ -122,6 +132,9 @@ |
927 | Application* findLastExecutedApplication(); |
928 | Application* applicationForStage(Application::Stage stage); |
929 | QModelIndex findIndex(Application* application); |
930 | + bool checkFocusOnRemovedApplication(Application* application); |
931 | + void shutdownApplication(Application* application); |
932 | + void stopStartingApplication(const QString &appId); |
933 | |
934 | QList<Application*> m_applications; |
935 | Application* m_focusedApplication; // remove as Mir has API for this |
936 | @@ -130,11 +143,11 @@ |
937 | Application* m_msApplicationToBeFocused; // placeholder store for async focusing |
938 | Application* m_ssApplicationToBeFocused; // placeholder store for async focusing |
939 | QStringList m_lifecycleExceptions; |
940 | - ShellServerConfiguration* m_mirServer; |
941 | + std::shared_ptr<mir::shell::FocusController> m_focusController; |
942 | DBusWindowStack* m_dbusWindowStack; |
943 | QSharedPointer<TaskController> m_taskController; |
944 | QSharedPointer<DesktopFileReader::Factory> m_desktopFileReaderFactory; |
945 | - static ApplicationManager* the_application_manager; |
946 | + QSharedPointer<ProcInfo> m_procInfo; |
947 | int m_gridUnitPx; |
948 | bool m_fenceNext; |
949 | QSize m_displaySize; |
950 | |
951 | === added file 'src/modules/Unity/Application/proc_info.cpp' |
952 | --- src/modules/Unity/Application/proc_info.cpp 1970-01-01 00:00:00 +0000 |
953 | +++ src/modules/Unity/Application/proc_info.cpp 2014-02-19 21:10:08 +0000 |
954 | @@ -0,0 +1,52 @@ |
955 | +/* |
956 | + * Copyright (C) 2014 Canonical, Ltd. |
957 | + * |
958 | + * This program is free software: you can redistribute it and/or modify it under |
959 | + * the terms of the GNU Lesser General Public License version 3, as published by |
960 | + * the Free Software Foundation. |
961 | + * |
962 | + * This program is distributed in the hope that it will be useful, but WITHOUT |
963 | + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
964 | + * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
965 | + * Lesser General Public License for more details. |
966 | + * |
967 | + * You should have received a copy of the GNU Lesser General Public License |
968 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
969 | + */ |
970 | + |
971 | +#include "proc_info.h" |
972 | + |
973 | +#include <QFile> |
974 | +#include <QRegularExpression> |
975 | + |
976 | +ProcInfo::~ProcInfo() { |
977 | +} |
978 | + |
979 | +std::unique_ptr<ProcInfo::CommandLine> ProcInfo::command_line(quint64 pid) { |
980 | + QFile cmdline(QString("/proc/%1/cmdline").arg(pid)); |
981 | + if (!cmdline.open(QIODevice::ReadOnly | QIODevice::Text)) { |
982 | + return nullptr; |
983 | + } |
984 | + |
985 | + return std::unique_ptr<CommandLine>(new CommandLine{ cmdline.readLine().replace('\0', ' ') }); |
986 | +} |
987 | +QStringList ProcInfo::CommandLine::as_string_list() const { |
988 | + return QString(command.data()).split(' '); |
989 | +} |
990 | + |
991 | +bool ProcInfo::CommandLine::starts_with(char const* prefix) const { |
992 | + return command.startsWith(prefix); |
993 | +} |
994 | + |
995 | +boost::optional<QString> ProcInfo::CommandLine::get_parameter(const char* name) const { |
996 | + QString pattern = QRegularExpression::escape(name) + "(\\S+)"; |
997 | + QRegularExpression regExp(pattern); |
998 | + QRegularExpressionMatch regExpMatch = regExp.match(command); |
999 | + |
1000 | + if (!regExpMatch.hasMatch()) { |
1001 | + return boost::optional<QString>{}; |
1002 | + } |
1003 | + |
1004 | + return boost::optional<QString>{regExpMatch.captured(1)}; |
1005 | +} |
1006 | + |
1007 | |
1008 | === added file 'src/modules/Unity/Application/proc_info.h' |
1009 | --- src/modules/Unity/Application/proc_info.h 1970-01-01 00:00:00 +0000 |
1010 | +++ src/modules/Unity/Application/proc_info.h 2014-02-19 21:10:08 +0000 |
1011 | @@ -0,0 +1,48 @@ |
1012 | +/* |
1013 | + * Copyright (C) 2014 Canonical, Ltd. |
1014 | + * |
1015 | + * This program is free software: you can redistribute it and/or modify it under |
1016 | + * the terms of the GNU Lesser General Public License version 3, as published by |
1017 | + * the Free Software Foundation. |
1018 | + * |
1019 | + * This program is distributed in the hope that it will be useful, but WITHOUT |
1020 | + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
1021 | + * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
1022 | + * Lesser General Public License for more details. |
1023 | + * |
1024 | + * You should have received a copy of the GNU Lesser General Public License |
1025 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1026 | + */ |
1027 | + |
1028 | +// Process Information |
1029 | + |
1030 | +#ifndef PROC_INFO_H |
1031 | +#define PROC_INFO_H |
1032 | + |
1033 | +#include <memory> |
1034 | + |
1035 | +#include <boost/optional.hpp> |
1036 | + |
1037 | +#include <QByteArray> |
1038 | +#include <QStringList> |
1039 | + |
1040 | +class QString; |
1041 | + |
1042 | +class ProcInfo |
1043 | +{ |
1044 | +public: |
1045 | + class CommandLine |
1046 | + { |
1047 | + public: |
1048 | + QByteArray command; |
1049 | + |
1050 | + bool starts_with(const char* prefix) const; |
1051 | + boost::optional<QString> get_parameter(const char* name) const; |
1052 | + QStringList as_string_list() const; |
1053 | + }; |
1054 | + virtual std::unique_ptr<CommandLine> command_line(quint64 pid); |
1055 | + virtual ~ProcInfo(); |
1056 | +}; |
1057 | + |
1058 | +#endif |
1059 | + |
1060 | |
1061 | === modified file 'src/unity-mir/CMakeLists.txt' |
1062 | --- src/unity-mir/CMakeLists.txt 2014-02-07 16:10:12 +0000 |
1063 | +++ src/unity-mir/CMakeLists.txt 2014-02-19 21:10:08 +0000 |
1064 | @@ -74,12 +74,10 @@ |
1065 | |
1066 | ${CMAKE_THREAD_LIBS_INIT} |
1067 | |
1068 | - ${UBUNTU_PLATFORM_API_LIBRARIES} |
1069 | - ${MIRCOMMON_LIBRARIES} |
1070 | - ${MIRSERVER_LIBRARIES} |
1071 | + ${UBUNTU_PLATFORM_API_LDFLAGS} |
1072 | + ${MIRSERVER_LDFLAGS} |
1073 | ${PROTOBUF_LIBRARIES} |
1074 | - |
1075 | - boost_system |
1076 | + ${Boost_SYSTEM_LIBRARY_RELEASE} |
1077 | |
1078 | ubuntu_application_api_mirserver) |
1079 | |
1080 | |
1081 | === modified file 'tests/CMakeLists.txt' |
1082 | --- tests/CMakeLists.txt 2014-01-27 11:29:44 +0000 |
1083 | +++ tests/CMakeLists.txt 2014-02-19 21:10:08 +0000 |
1084 | @@ -20,6 +20,7 @@ |
1085 | ${CMAKE_SOURCE_DIR}/src/modules |
1086 | ${GMOCK_INCLUDE_DIR} |
1087 | ${GTEST_INCLUDE_DIR} |
1088 | + ${MIRSERVER_INCLUDE_DIRS} |
1089 | ) |
1090 | |
1091 | add_executable( |
1092 | |
1093 | === modified file 'tests/application_manager_test.cpp' |
1094 | --- tests/application_manager_test.cpp 2014-01-27 11:29:44 +0000 |
1095 | +++ tests/application_manager_test.cpp 2014-02-19 21:10:08 +0000 |
1096 | @@ -19,6 +19,7 @@ |
1097 | |
1098 | #include <Unity/Application/applicationcontroller.h> |
1099 | #include <Unity/Application/taskcontroller.h> |
1100 | +#include <Unity/Application/proc_info.h> |
1101 | |
1102 | #include <core/posix/linux/proc/process/oom_score_adj.h> |
1103 | |
1104 | @@ -29,43 +30,54 @@ |
1105 | #include "mock_desktop_file_reader.h" |
1106 | #include "mock_oom_controller.h" |
1107 | #include "mock_process_controller.h" |
1108 | - |
1109 | -TEST(ApplicationManager, SuspendingAndResumingARunningApplicationResultsInOomScoreAdjustment) |
1110 | +#include "mock_proc_info.h" |
1111 | +#include "mock_session.h" |
1112 | +#include "mock_focus_controller.h" |
1113 | + |
1114 | + |
1115 | +class ApplicationManagerTests : public ::testing::Test |
1116 | { |
1117 | - using namespace ::testing; |
1118 | - |
1119 | - const QString appId("com.canonical.does.not.exist"); |
1120 | - |
1121 | - NiceMock<testing::MockOomController> oomController; |
1122 | - QSharedPointer<ProcessController::OomController> oomControllerPtr( |
1123 | +public: |
1124 | + ApplicationManagerTests() |
1125 | + : processController{ |
1126 | + QSharedPointer<ProcessController::OomController> ( |
1127 | &oomController, |
1128 | - [](ProcessController::OomController*){}); |
1129 | - |
1130 | - NiceMock<testing::MockProcessController> processController(oomControllerPtr); |
1131 | - QSharedPointer<ProcessController> processControllerPtr( |
1132 | - &processController, |
1133 | - [](ProcessController*){}); |
1134 | - |
1135 | - NiceMock<testing::MockApplicationController> appController; |
1136 | - QSharedPointer<ApplicationController> appControllerPtr( |
1137 | - &appController, |
1138 | - [](ApplicationController*){}); |
1139 | - |
1140 | - QSharedPointer<TaskController> taskController( |
1141 | + [](ProcessController::OomController*){}) |
1142 | + }, |
1143 | + applicationManager{ |
1144 | + QSharedPointer<TaskController>{ |
1145 | new TaskController( |
1146 | nullptr, |
1147 | - appControllerPtr, |
1148 | - processControllerPtr |
1149 | - )); |
1150 | - |
1151 | - NiceMock<MockDesktopFileReaderFactory> desktopFileReaderFactory; |
1152 | - QSharedPointer<DesktopFileReader::Factory> desktopFileReaderFactoryPtr( |
1153 | + QSharedPointer<ApplicationController>( |
1154 | + &appController, |
1155 | + [](ApplicationController*){}), |
1156 | + QSharedPointer<ProcessController>( |
1157 | + &processController, |
1158 | + [](ProcessController*){}) |
1159 | + )}, |
1160 | + QSharedPointer<DesktopFileReader::Factory>( |
1161 | &desktopFileReaderFactory, |
1162 | - [](DesktopFileReader::Factory*){}); |
1163 | - |
1164 | - ApplicationManager applicationManager( |
1165 | - taskController, |
1166 | - desktopFileReaderFactoryPtr); |
1167 | + [](DesktopFileReader::Factory*){}), |
1168 | + QSharedPointer<ProcInfo>(&procInfo,[](ProcInfo *){}), |
1169 | + std::shared_ptr<mir::shell::FocusController>(&focusController, [](void*){}), |
1170 | + QSize(400,400) |
1171 | + } |
1172 | + { |
1173 | + } |
1174 | + testing::NiceMock<testing::MockOomController> oomController; |
1175 | + testing::NiceMock<testing::MockProcessController> processController; |
1176 | + testing::NiceMock<testing::MockApplicationController> appController; |
1177 | + testing::NiceMock<testing::MockProcInfo> procInfo; |
1178 | + testing::NiceMock<testing::MockDesktopFileReaderFactory> desktopFileReaderFactory; |
1179 | + testing::NiceMock<testing::MockFocusController> focusController; |
1180 | + ApplicationManager applicationManager; |
1181 | +}; |
1182 | + |
1183 | +TEST_F(ApplicationManagerTests, SuspendingAndResumingARunningApplicationResultsInOomScoreAdjustment) |
1184 | +{ |
1185 | + using namespace ::testing; |
1186 | + |
1187 | + const QString appId("com.canonical.does.not.exist"); |
1188 | |
1189 | EXPECT_CALL(appController, startApplicationWithAppIdAndArgs(_, _)).Times(1); |
1190 | |
1191 | @@ -86,43 +98,12 @@ |
1192 | } |
1193 | |
1194 | // Currently disabled as we need to make sure that we have a corresponding mir session, too. |
1195 | -TEST(ApplicationManager, DISABLED_FocusingRunningApplicationResultsInOomScoreAdjustment) |
1196 | +TEST_F(ApplicationManagerTests, DISABLED_FocusingRunningApplicationResultsInOomScoreAdjustment) |
1197 | { |
1198 | using namespace ::testing; |
1199 | |
1200 | const QString appId("com.canonical.does.not.exist"); |
1201 | |
1202 | - NiceMock<testing::MockOomController> oomController; |
1203 | - QSharedPointer<ProcessController::OomController> oomControllerPtr( |
1204 | - &oomController, |
1205 | - [](ProcessController::OomController*){}); |
1206 | - |
1207 | - NiceMock<testing::MockProcessController> processController(oomControllerPtr); |
1208 | - QSharedPointer<ProcessController> processControllerPtr( |
1209 | - &processController, |
1210 | - [](ProcessController*){}); |
1211 | - |
1212 | - NiceMock<testing::MockApplicationController> appController; |
1213 | - QSharedPointer<ApplicationController> appControllerPtr( |
1214 | - &appController, |
1215 | - [](ApplicationController*){}); |
1216 | - |
1217 | - QSharedPointer<TaskController> taskController( |
1218 | - new TaskController( |
1219 | - nullptr, |
1220 | - appControllerPtr, |
1221 | - processControllerPtr |
1222 | - )); |
1223 | - |
1224 | - NiceMock<MockDesktopFileReaderFactory> desktopFileReaderFactory; |
1225 | - QSharedPointer<DesktopFileReader::Factory> desktopFileReaderFactoryPtr( |
1226 | - &desktopFileReaderFactory, |
1227 | - [](DesktopFileReader::Factory*){}); |
1228 | - |
1229 | - ApplicationManager applicationManager( |
1230 | - taskController, |
1231 | - desktopFileReaderFactoryPtr); |
1232 | - |
1233 | QSet<QString> appIds; |
1234 | |
1235 | for (unsigned int i = 0; i < 50; i++) |
1236 | @@ -135,6 +116,9 @@ |
1237 | ApplicationManager::NoFlag, |
1238 | QStringList()); |
1239 | |
1240 | + std::shared_ptr<mir::shell::Session> mirSession = std::make_shared<MockSession>(appIdFormat.toStdString(), i); |
1241 | + applicationManager.onSessionStarting( mirSession ); |
1242 | + |
1243 | EXPECT_NE(nullptr, application); |
1244 | |
1245 | appIds.insert(appId); |
1246 | @@ -149,3 +133,92 @@ |
1247 | applicationManager.focusApplication(appId); |
1248 | } |
1249 | } |
1250 | + |
1251 | + |
1252 | +TEST_F(ApplicationManagerTests,bug_case_1240400_second_dialer_app_fails_to_authorize_and_gets_mixed_up_with_first_one) |
1253 | +{ |
1254 | + using namespace ::testing; |
1255 | + std::shared_ptr<mir::shell::Surface> aSurface(nullptr); |
1256 | + quint64 firstProcId = 5921; |
1257 | + quint64 secondProcId = 5922; |
1258 | + const char dialer_app_id[] = "dialer-app"; |
1259 | + QByteArray cmdLine( "/usr/bin/dialer-app --desktop_file_hint=dialer-app"); |
1260 | + QByteArray secondcmdLine( "/usr/bin/dialer-app"); |
1261 | + |
1262 | + EXPECT_CALL(procInfo,command_line_(firstProcId)) |
1263 | + .Times(1) |
1264 | + .WillOnce(Return(cmdLine)); |
1265 | + EXPECT_CALL(procInfo,command_line_(secondProcId)) |
1266 | + .Times(1) |
1267 | + .WillOnce(Return(secondcmdLine)); |
1268 | + |
1269 | + bool authed = true; |
1270 | + |
1271 | + std::shared_ptr<mir::shell::Session> mirSession = std::make_shared<MockSession>(dialer_app_id, firstProcId); |
1272 | + applicationManager.authorizeSession(firstProcId, authed); |
1273 | + EXPECT_EQ(true, authed); |
1274 | + applicationManager.onSessionStarting(mirSession); |
1275 | + applicationManager.onSessionCreatedSurface(mirSession.get(),aSurface); |
1276 | + Application * app = applicationManager.findApplication(dialer_app_id); |
1277 | + EXPECT_NE(nullptr,app); |
1278 | + |
1279 | + // now a second session without desktop file is launched: |
1280 | + applicationManager.authorizeSession(secondProcId, authed); |
1281 | + applicationManager.onProcessStartReportReceived(dialer_app_id, true); |
1282 | + |
1283 | + EXPECT_EQ(false,authed); |
1284 | + EXPECT_EQ(app,applicationManager.findApplication(dialer_app_id)); |
1285 | + EXPECT_EQ(QString(dialer_app_id),applicationManager.focusedApplicationId()); |
1286 | +} |
1287 | + |
1288 | +TEST_F(ApplicationManagerTests,application_dies_while_starting) |
1289 | +{ |
1290 | + using namespace ::testing; |
1291 | + quint64 procId = 5921; |
1292 | + const char app_id[] = "my-app"; |
1293 | + QByteArray cmdLine( "/usr/bin/my-app --desktop_file_hint=my-app"); |
1294 | + |
1295 | + EXPECT_CALL(procInfo,command_line_(procId)) |
1296 | + .Times(1) |
1297 | + .WillOnce(Return(cmdLine)); |
1298 | + |
1299 | + bool authed = true; |
1300 | + |
1301 | + std::shared_ptr<mir::shell::Session> mirSession = std::make_shared<MockSession>(app_id, procId); |
1302 | + applicationManager.authorizeSession(procId, authed); |
1303 | + applicationManager.onSessionStarting(mirSession); |
1304 | + Application * beforeFailure = applicationManager.findApplication(app_id); |
1305 | + applicationManager.onProcessStartReportReceived(app_id,true); |
1306 | + Application * afterFailure = applicationManager.findApplication(app_id); |
1307 | + |
1308 | + EXPECT_EQ(true, authed); |
1309 | + EXPECT_NE(nullptr, beforeFailure); |
1310 | + EXPECT_EQ(nullptr, afterFailure); |
1311 | +} |
1312 | + |
1313 | +TEST_F(ApplicationManagerTests,application_start_failure_after_starting) |
1314 | +{ |
1315 | + using namespace ::testing; |
1316 | + quint64 procId = 5921; |
1317 | + std::shared_ptr<mir::shell::Surface> aSurface(nullptr); |
1318 | + const char app_id[] = "my-app"; |
1319 | + QByteArray cmdLine( "/usr/bin/my-app --desktop_file_hint=my-app"); |
1320 | + |
1321 | + EXPECT_CALL(procInfo,command_line_(procId)) |
1322 | + .Times(1) |
1323 | + .WillOnce(Return(cmdLine)); |
1324 | + |
1325 | + bool authed = true; |
1326 | + |
1327 | + std::shared_ptr<mir::shell::Session> mirSession = std::make_shared<MockSession>(app_id, procId); |
1328 | + applicationManager.authorizeSession(procId, authed); |
1329 | + applicationManager.onSessionStarting(mirSession); |
1330 | + Application * beforeFailure = applicationManager.findApplication(app_id); |
1331 | + applicationManager.onSessionCreatedSurface(mirSession.get(), aSurface); |
1332 | + applicationManager.onProcessStartReportReceived(app_id, true); |
1333 | + Application * afterFailure = applicationManager.findApplication(app_id); |
1334 | + |
1335 | + EXPECT_EQ(true, authed); |
1336 | + EXPECT_NE(nullptr, beforeFailure); |
1337 | + EXPECT_EQ(beforeFailure, afterFailure); |
1338 | +} |
1339 | |
1340 | === modified file 'tests/auto/modules/Unity/Application/CMakeLists.txt' |
1341 | --- tests/auto/modules/Unity/Application/CMakeLists.txt 2014-01-27 11:29:44 +0000 |
1342 | +++ tests/auto/modules/Unity/Application/CMakeLists.txt 2014-02-19 21:10:08 +0000 |
1343 | @@ -19,8 +19,8 @@ |
1344 | unity-mir |
1345 | unityapplicationplugin |
1346 | |
1347 | - ${MIRSERVER_LIBRARIES} |
1348 | - ${UPSTART_APP_LAUNCH_LIBRARIES}) |
1349 | + ${MIRSERVER_LDFLAGS} |
1350 | + ${UPSTART_APP_LAUNCH_LDFLAGS}) |
1351 | |
1352 | install( |
1353 | TARGETS unity-mir-test-app |
1354 | |
1355 | === modified file 'tests/auto/modules/Unity/Application/main.cpp' |
1356 | --- tests/auto/modules/Unity/Application/main.cpp 2014-01-27 11:29:44 +0000 |
1357 | +++ tests/auto/modules/Unity/Application/main.cpp 2014-02-19 21:10:08 +0000 |
1358 | @@ -18,6 +18,7 @@ |
1359 | |
1360 | #include "application_manager.h" |
1361 | #include "processcontroller.h" |
1362 | +#include "proc_info.h" |
1363 | #include "taskcontroller.h" |
1364 | #include "upstart/applicationcontroller.h" |
1365 | |
1366 | @@ -44,12 +45,10 @@ |
1367 | |
1368 | void ApplicationManagerTests::testStartStop() |
1369 | { |
1370 | - QSharedPointer<upstart::ApplicationController> appController(new upstart::ApplicationController()); |
1371 | - QSharedPointer<TaskController> taskController(new TaskController(nullptr, appController)); |
1372 | - QSharedPointer<DesktopFileReader::Factory> fileReaderFactory(new DesktopFileReader::Factory()); |
1373 | + ApplicationManager::Factory appFactory; |
1374 | + QSharedPointer<ApplicationManager> manager{appFactory.create()}; |
1375 | |
1376 | - ApplicationManager manager(taskController, fileReaderFactory); |
1377 | - Application *app = manager.startApplication("unity-mir-test-helper-app", QStringList()); |
1378 | + Application *app = manager->startApplication("unity-mir-test-helper-app", QStringList()); |
1379 | QVERIFY(app); |
1380 | QCOMPARE(app->desktopFile(), QString("/usr/share/applications/unity-mir-test-helper-app.desktop")); |
1381 | QCOMPARE(app->name(), QString("My Fake App")); |
1382 | @@ -61,7 +60,7 @@ |
1383 | QString simplifiedCommand = pidCommandLine(app->pid()); |
1384 | QCOMPARE(simplifiedCommand, QString("unity-mir-test-helper-app")); |
1385 | |
1386 | - manager.stopApplication(app->appId()); |
1387 | + manager->stopApplication(app->appId()); |
1388 | |
1389 | QDir d; |
1390 | QTRY_VERIFY(!d.exists(QString("/proc/%1").arg(app->pid()))); |
1391 | |
1392 | === added file 'tests/mock_focus_controller.h' |
1393 | --- tests/mock_focus_controller.h 1970-01-01 00:00:00 +0000 |
1394 | +++ tests/mock_focus_controller.h 2014-02-19 21:10:08 +0000 |
1395 | @@ -0,0 +1,37 @@ |
1396 | +/* |
1397 | + * Copyright (C) 2014 Canonical, Ltd. |
1398 | + * |
1399 | + * This program is free software: you can redistribute it and/or modify it under |
1400 | + * the terms of the GNU Lesser General Public License version 3, as published by |
1401 | + * the Free Software Foundation. |
1402 | + * |
1403 | + * This program is distributed in the hope that it will be useful, but WITHOUT |
1404 | + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
1405 | + * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
1406 | + * Lesser General Public License for more details. |
1407 | + * |
1408 | + * You should have received a copy of the GNU Lesser General Public License |
1409 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1410 | + * |
1411 | + */ |
1412 | + |
1413 | +#ifndef MOCK_MIR_SHELL_FOCUS_CONTROLLER_H |
1414 | +#define MOCK_MIR_SHELL_FOCUS_CONTROLLER_H |
1415 | + |
1416 | +#include <mir/shell/focus_controller.h> |
1417 | +#include <gmock/gmock.h> |
1418 | + |
1419 | +#include <string> |
1420 | + |
1421 | +namespace testing |
1422 | +{ |
1423 | +class MockFocusController : public mir::shell::FocusController |
1424 | +{ |
1425 | +public: |
1426 | + MOCK_METHOD0(focus_next, void()); |
1427 | + MOCK_CONST_METHOD0(focussed_application, std::weak_ptr<mir::shell::Session>()); |
1428 | + MOCK_METHOD1(set_focus_to, void(std::shared_ptr<mir::shell::Session>const&)); |
1429 | +}; |
1430 | +} |
1431 | + |
1432 | +#endif // MOCK_MIR_SHELL_FOCUS_CONTROLLER_H_ |
1433 | |
1434 | === added file 'tests/mock_proc_info.h' |
1435 | --- tests/mock_proc_info.h 1970-01-01 00:00:00 +0000 |
1436 | +++ tests/mock_proc_info.h 2014-02-19 21:10:08 +0000 |
1437 | @@ -0,0 +1,37 @@ |
1438 | +/* |
1439 | + * Copyright (C) 2014 Canonical, Ltd. |
1440 | + * |
1441 | + * This program is free software: you can redistribute it and/or modify it under |
1442 | + * the terms of the GNU Lesser General Public License version 3, as published by |
1443 | + * the Free Software Foundation. |
1444 | + * |
1445 | + * This program is distributed in the hope that it will be useful, but WITHOUT |
1446 | + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
1447 | + * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
1448 | + * Lesser General Public License for more details. |
1449 | + * |
1450 | + * You should have received a copy of the GNU Lesser General Public License |
1451 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1452 | + * |
1453 | + */ |
1454 | + |
1455 | +#ifndef MOCK_PROC_INFO_H |
1456 | +#define MOCK_PROC_INFO_H |
1457 | + |
1458 | +#include <Unity/Application/proc_info.h> |
1459 | + |
1460 | +#include <gmock/gmock.h> |
1461 | + |
1462 | +namespace testing |
1463 | +{ |
1464 | +struct MockProcInfo : public ProcInfo |
1465 | +{ |
1466 | + MOCK_METHOD1(command_line_, QByteArray(quint64)); |
1467 | + std::unique_ptr<CommandLine> command_line(quint64 pid) |
1468 | + { |
1469 | + return std::unique_ptr<CommandLine>(new CommandLine{command_line_(pid)}); |
1470 | + } |
1471 | +}; |
1472 | +} |
1473 | + |
1474 | +#endif // MOCK_OOM_CONTROLLER_H |
1475 | |
1476 | === added file 'tests/mock_session.h' |
1477 | --- tests/mock_session.h 1970-01-01 00:00:00 +0000 |
1478 | +++ tests/mock_session.h 2014-02-19 21:10:08 +0000 |
1479 | @@ -0,0 +1,69 @@ |
1480 | +/* |
1481 | + * Copyright (C) 2014 Canonical, Ltd. |
1482 | + * |
1483 | + * This program is free software: you can redistribute it and/or modify it under |
1484 | + * the terms of the GNU Lesser General Public License version 3, as published by |
1485 | + * the Free Software Foundation. |
1486 | + * |
1487 | + * This program is distributed in the hope that it will be useful, but WITHOUT |
1488 | + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
1489 | + * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
1490 | + * Lesser General Public License for more details. |
1491 | + * |
1492 | + * You should have received a copy of the GNU Lesser General Public License |
1493 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1494 | + * |
1495 | + */ |
1496 | + |
1497 | +#ifndef MOCK_MIR_SHELL_SESSION_H |
1498 | +#define MOCK_MIR_SHELL_SESSION_H |
1499 | + |
1500 | +#include <mir/shell/session.h> |
1501 | +#include <mir/graphics/display_configuration.h> |
1502 | +#include <mir/shell/surface_creation_parameters.h> |
1503 | +#include <gmock/gmock.h> |
1504 | + |
1505 | +#include <string> |
1506 | + |
1507 | +namespace testing |
1508 | +{ |
1509 | +struct MockSession : public mir::shell::Session |
1510 | +{ |
1511 | + MockSession() {} |
1512 | + MockSession(std::string const& sessionName, pid_t processId) |
1513 | + : m_sessionName(sessionName), m_sessionId(processId) |
1514 | + {} |
1515 | + |
1516 | + std::string name() const override |
1517 | + { |
1518 | + return m_sessionName; |
1519 | + } |
1520 | + |
1521 | + pid_t process_id() const override |
1522 | + { |
1523 | + return m_sessionId; |
1524 | + } |
1525 | + |
1526 | + typedef mir::frontend::SurfaceId SurfaceId; |
1527 | + |
1528 | + MOCK_METHOD0(force_requests_to_complete, void()); |
1529 | + |
1530 | + MOCK_CONST_METHOD0(default_surface, std::shared_ptr<mir::shell::Surface>()); |
1531 | + MOCK_CONST_METHOD1(get_surface, std::shared_ptr<mir::frontend::Surface>(SurfaceId)); |
1532 | + |
1533 | + MOCK_METHOD1(take_snapshot, void(mir::shell::SnapshotCallback const&)); |
1534 | + MOCK_METHOD1(set_lifecycle_state, void(MirLifecycleState)); |
1535 | + MOCK_METHOD1(create_surface, SurfaceId(mir::shell::SurfaceCreationParameters const&)); |
1536 | + MOCK_METHOD1(destroy_surface, void (SurfaceId)); |
1537 | + |
1538 | + MOCK_METHOD0(hide, void()); |
1539 | + MOCK_METHOD0(show, void()); |
1540 | + MOCK_METHOD1(send_display_config, void(mir::graphics::DisplayConfiguration const&)); |
1541 | + MOCK_METHOD3(configure_surface, int(SurfaceId, MirSurfaceAttrib, int)); |
1542 | +private: |
1543 | + std::string m_sessionName; |
1544 | + pid_t m_sessionId; |
1545 | +}; |
1546 | +} |
1547 | + |
1548 | +#endif // MOCK_MIR_SHELL_SESSION_H |