40
44
namespace ms = mir::scene;
46
Q_LOGGING_CATEGORY(QTMIR_APPLICATIONS, "qtmir.applications")
42
48
using namespace unity::shell::application;
44
ApplicationManager *ApplicationManager::the_application_manager = nullptr;
46
ApplicationManager* ApplicationManager::singleton()
48
if (!the_application_manager) {
49
the_application_manager = new ApplicationManager();
55
// FIXME: To be removed once shell has fully adopted short appIds!!
56
QString toShortAppIdIfPossible(const QString &appId) {
57
QRegExp longAppIdMask("[a-z0-9][a-z0-9+.-]+_[a-zA-Z0-9+.-]+_[0-9][a-zA-Z0-9.+:~-]*");
58
if (longAppIdMask.exactMatch(appId)) {
59
qWarning() << "WARNING: long App ID encountered:" << appId;
60
// input string a long AppId, chop the version string off the end
61
QStringList parts = appId.split("_");
62
return QString("%1_%2").arg(parts.first()).arg(parts.at(1));
51
return the_application_manager;
54
ApplicationManager::ApplicationManager(QObject *parent)
55
: ApplicationManagerInterface(parent)
56
, m_focusedApplication(nullptr)
57
, m_applicationToBeFocused(nullptr)
58
, m_lifecycleExceptions(QStringList() << "com.ubuntu.music")
59
, m_taskController(TaskController::singleton())
62
DLOG("ApplicationManager::ApplicationManager (this=%p)", this);
64
m_roleNames.insert(RoleSurface, "surface");
65
m_roleNames.insert(RoleFullscreen, "fullscreen");
67
void connectToSessionListener(ApplicationManager *manager, SessionListener *listener)
69
QObject::connect(listener, &SessionListener::sessionStarting,
70
manager, &ApplicationManager::onSessionStarting);
71
QObject::connect(listener, &SessionListener::sessionStopping,
72
manager, &ApplicationManager::onSessionStopping);
73
QObject::connect(listener, &SessionListener::sessionCreatedSurface,
74
manager, &ApplicationManager::onSessionCreatedSurface);
77
void connectToSessionAuthorizer(ApplicationManager *manager, SessionAuthorizer *authorizer)
79
QObject::connect(authorizer, &SessionAuthorizer::requestAuthorizationForSession,
80
manager, &ApplicationManager::authorizeSession, Qt::BlockingQueuedConnection);
83
void connectToTaskController(ApplicationManager *manager, TaskController *controller)
85
QObject::connect(controller, &TaskController::processStarting,
86
manager, &ApplicationManager::onProcessStarting);
87
QObject::connect(controller, &TaskController::processStopped,
88
manager, &ApplicationManager::onProcessStopped);
89
QObject::connect(controller, &TaskController::processFailed,
90
manager, &ApplicationManager::onProcessFailed);
91
QObject::connect(controller, &TaskController::requestFocus,
92
manager, &ApplicationManager::onFocusRequested);
93
QObject::connect(controller, &TaskController::requestResume,
94
manager, &ApplicationManager::onResumeRequested);
99
ApplicationManager* ApplicationManager::Factory::Factory::create()
67
101
NativeInterface *nativeInterface = dynamic_cast<NativeInterface*>(QGuiApplication::platformNativeInterface());
69
m_mirConfig = nativeInterface->m_mirConfig;
71
103
if (!nativeInterface) {
72
LOG("ERROR: Unity.Application QML plugin requires use of the 'mirserver' QPA plugin");
104
qCritical() << "ERROR: Unity.Application QML plugin requires use of the 'mirserver' QPA plugin";
73
105
QGuiApplication::quit();
109
auto mirConfig = nativeInterface->m_mirConfig;
77
111
SessionListener *sessionListener = static_cast<SessionListener*>(nativeInterface->nativeResourceForIntegration("SessionListener"));
78
112
SessionAuthorizer *sessionAuthorizer = static_cast<SessionAuthorizer*>(nativeInterface->nativeResourceForIntegration("SessionAuthorizer"));
79
qDebug() << sessionListener << sessionAuthorizer;
80
QObject::connect(sessionListener, &SessionListener::sessionStarting,
81
this, &ApplicationManager::onSessionStarting);
82
QObject::connect(sessionListener, &SessionListener::sessionStopping,
83
this, &ApplicationManager::onSessionStopping);
84
QObject::connect(sessionListener, &SessionListener::sessionFocused,
85
this, &ApplicationManager::onSessionFocused);
86
QObject::connect(sessionListener, &SessionListener::sessionUnfocused,
87
this, &ApplicationManager::onSessionUnfocused);
88
QObject::connect(sessionListener, &SessionListener::sessionCreatedSurface,
89
this, &ApplicationManager::onSessionCreatedSurface);
90
QObject::connect(sessionAuthorizer, &SessionAuthorizer::requestAuthorizationForSession,
91
this, &ApplicationManager::authorizeSession, Qt::BlockingQueuedConnection);
93
QObject::connect(m_taskController.data(), &TaskController::processStartReport,
94
this, &ApplicationManager::onProcessStartReportReceived);
95
QObject::connect(m_taskController.data(), &TaskController::processStopped,
96
this, &ApplicationManager::onProcessStopped);
97
QObject::connect(m_taskController.data(), &TaskController::requestFocus,
98
this, &ApplicationManager::onFocusRequested);
99
QObject::connect(m_taskController.data(), &TaskController::requestResume,
100
this, &ApplicationManager::onResumeRequested);
102
m_dbusWindowStack = new DBusWindowStack(this);
114
QSharedPointer<upstart::ApplicationController> appController(new upstart::ApplicationController());
115
QSharedPointer<TaskController> taskController(new TaskController(nullptr, appController));
116
QSharedPointer<DesktopFileReader::Factory> fileReaderFactory(new DesktopFileReader::Factory());
117
QSharedPointer<ProcInfo> procInfo(new ProcInfo());
119
// FIXME: We should use a QSharedPointer to wrap this ApplicationManager object, which requires us
120
// to use the data() method to pass the raw pointer to the QML engine. However the QML engine appears
121
// to take ownership of the object, and deletes it when it wants to. This conflicts with the purpose
122
// of the QSharedPointer, and a double-delete results. Trying QQmlEngine::setObjectOwnership on the
123
// object no effect, which it should. Need to investigate why.
124
ApplicationManager* appManager = new ApplicationManager(
131
connectToSessionListener(appManager, sessionListener);
132
connectToSessionAuthorizer(appManager, sessionAuthorizer);
133
connectToTaskController(appManager, taskController.data());
139
ApplicationManager* ApplicationManager::singleton()
141
static ApplicationManager* instance;
144
instance = appFactory.create();
149
ApplicationManager::ApplicationManager(
150
const QSharedPointer<MirServerConfiguration>& mirConfig,
151
const QSharedPointer<TaskController>& taskController,
152
const QSharedPointer<DesktopFileReader::Factory>& desktopFileReaderFactory,
153
const QSharedPointer<ProcInfo>& procInfo,
155
: ApplicationManagerInterface(parent)
156
, m_mirConfig(mirConfig)
157
, m_focusedApplication(nullptr)
158
, m_mainStageApplication(nullptr)
159
, m_sideStageApplication(nullptr)
160
, m_msApplicationToBeFocused(nullptr)
161
, m_ssApplicationToBeFocused(nullptr)
162
, m_lifecycleExceptions(QStringList() << "com.ubuntu.music")
163
, m_dbusWindowStack(new DBusWindowStack(this))
164
, m_taskController(taskController)
165
, m_desktopFileReaderFactory(desktopFileReaderFactory)
166
, m_procInfo(procInfo)
170
qCDebug(QTMIR_APPLICATIONS) << "ApplicationManager::ApplicationManager (this=%p)" << this;
172
m_roleNames.insert(RoleSurface, "surface");
173
m_roleNames.insert(RoleFullscreen, "fullscreen");
105
176
ApplicationManager::~ApplicationManager()
107
DLOG("ApplicationManager::~ApplicationManager");
178
qCDebug(QTMIR_APPLICATIONS) << "ApplicationManager::~ApplicationManager";
110
181
int ApplicationManager::rowCount(const QModelIndex &parent) const
213
287
Q_EMIT suspendedChanged();
215
289
if (m_suspended) {
216
suspendApplication(m_focusedApplication);
290
suspendApplication(m_mainStageApplication);
291
suspendApplication(m_sideStageApplication);
218
resumeApplication(m_focusedApplication);
293
resumeApplication(m_mainStageApplication);
294
resumeApplication(m_sideStageApplication);
222
void ApplicationManager::suspendApplication(Application *application)
298
bool ApplicationManager::suspendApplication(Application *application)
224
300
if (application == nullptr)
226
DLOG("ApplicationManager::suspendApplication (appId=%s)", qPrintable(application->appId()));
302
qCDebug(QTMIR_APPLICATIONS) << "ApplicationManager::suspendApplication - appId=" << application->appId();
228
304
updateScreenshot(application->appId());
230
306
// Present in exceptions list, return.
231
307
if (!m_lifecycleExceptions.filter(application->appId().section('_',0,0)).empty())
234
310
if (application->state() == Application::Running)
235
311
application->setState(Application::Suspended);
238
316
void ApplicationManager::resumeApplication(Application *application)
240
318
if (application == nullptr)
320
qCDebug(QTMIR_APPLICATIONS) << "ApplicationManager::resumeApplication - appId=" << application->appId();
243
322
if (application->state() != Application::Running)
244
323
application->setState(Application::Running);
247
bool ApplicationManager::focusApplication(const QString &appId)
326
bool ApplicationManager::focusApplication(const QString &inputAppId)
249
DLOG("ApplicationManager::focusApplication (this=%p, appId=%s)", this, qPrintable(appId));
328
const QString appId = toShortAppIdIfPossible(inputAppId);
329
qCDebug(QTMIR_APPLICATIONS) << "ApplicationManager::focusApplication - appId=" << appId;
250
330
Application *application = findApplication(appId);
252
332
if (!application) {
253
DLOG("No such running application '%s'", qPrintable(appId));
333
qDebug() << "No such running application with appId=" << appId;
257
m_applicationToBeFocused = application;
337
if (application->stage() == Application::MainStage && m_sideStageApplication)
338
suspendApplication(m_sideStageApplication);
340
if (application->stage() == Application::MainStage)
341
m_msApplicationToBeFocused = application;
343
m_ssApplicationToBeFocused = application;
259
345
if (application->state() == Application::Stopped) {
260
346
// Respawning this app, move to end of application list so onSessionStarting works ok
283
366
void ApplicationManager::unfocusCurrentApplication()
285
DLOG("ApplicationManager::unfocusCurrentApplication (this=%p)", this);
287
m_applicationToBeFocused = nullptr;
289
m_mirConfig->the_focus_controller()->set_focus_to(NULL); //FIXME(greyback)
368
qCDebug(QTMIR_APPLICATIONS) << "ApplicationManager::unfocusCurrentApplication";
370
suspendApplication(m_sideStageApplication);
371
suspendApplication(m_mainStageApplication);
374
m_msApplicationToBeFocused = nullptr;
375
m_ssApplicationToBeFocused = nullptr;
379
* @brief ApplicationManager::startApplication launches an application identified by an "application id" or appId.
381
* Note: due to an implementation detail, appIds come in two forms:
382
* * long appId: $(click_package)_$(application)_$(version)
383
* * short appId: $(click_package)_$(application)
384
* It is expected that the shell uses _only_ short appIds (but long appIds are accepted by this method for legacy
385
* reasons - but be warned, this ability will be removed)
387
* Unless stated otherwise, we always use short appIds in this API.
389
* @param inputAppId AppId of application to launch (long appId supported)
390
* @param arguments Command line arguments to pass to the application to be launched
391
* @return Pointer to Application object representing the launched process. If process already running, return nullptr
292
393
Application* ApplicationManager::startApplication(const QString &appId,
293
394
const QStringList &arguments)
295
396
return startApplication(appId, NoFlag, arguments);
298
Application *ApplicationManager::startApplication(const QString &appId, ExecFlags flags,
399
Application *ApplicationManager::startApplication(const QString &inputAppId, ExecFlags flags,
299
400
const QStringList &arguments)
301
DLOG("ApplicationManager::startApplication (this=%p, appId=%s)", this, qPrintable(appId));
402
QString appId = toShortAppIdIfPossible(inputAppId);
403
qCDebug(QTMIR_APPLICATIONS) << "ApplicationManager::startApplication - this=" << this << "appId" << qPrintable(appId);
405
Application *application = findApplication(appId);
407
qWarning() << "ApplicationManager::startApplication - application appId=" << appId << " already exists";
303
411
if (!m_taskController->start(appId, arguments)) {
304
LOG("Asking Upstart to start application '%s' failed", qPrintable(appId));
412
qWarning() << "Upstart failed to start application with appId" << appId;
308
Application* application = new Application(appId, Application::Starting, arguments, this);
416
application = new Application(
418
m_desktopFileReaderFactory->createInstance(appId, m_taskController->findDesktopFileForAppId(appId)),
419
Application::Starting,
309
423
if (!application->isValid()) {
310
DLOG("Unable to instantiate application with appId '%s'", qPrintable(appId));
424
qWarning() << "Unable to instantiate application with appId" << appId;
320
434
return application;
323
void ApplicationManager::onProcessStartReportReceived(const QString &appId, const bool failure)
437
void ApplicationManager::onProcessStarting(const QString &appId)
325
DLOG("ApplicationManager::onProcessStartReportReceived (this=%p, appId=%s, failure=%c)",
326
this, qPrintable(appId), (failure) ? 'Y' : 'N');
329
onProcessStopped(appId, true);
439
qCDebug(QTMIR_APPLICATIONS) << "ApplicationManager::onProcessStarting - appId=" << appId;
332
441
Application *application = findApplication(appId);
442
if (!application) { // then shell did not start this application, so ubuntu-app-launch must have - add to list
443
application = new Application(
445
m_desktopFileReaderFactory->createInstance(appId, m_taskController->findDesktopFileForAppId(appId)),
446
Application::Starting,
447
QStringList(), this);
334
if (!application) { // if shell did not start this application, but ubuntu-app-launch did
335
application = new Application(appId, Application::Starting, QStringList(), this);
336
449
if (!application->isValid()) {
337
DLOG("Unable to instantiate application with appId '%s'", qPrintable(appId));
450
qWarning() << "Unable to instantiate application with appId" << appId;
340
454
add(application);
341
455
Q_EMIT focusRequested(appId);
458
qWarning() << "ApplicationManager::onProcessStarting application already found with appId" << appId;
345
bool ApplicationManager::stopApplication(const QString &appId)
463
* @brief ApplicationManager::stopApplication - stop a running application and remove from list
465
* @return True if running application was stopped, false if application did not exist or could not be stopped
467
bool ApplicationManager::stopApplication(const QString &inputAppId)
347
DLOG("ApplicationManager::stopApplication (this=%p, appId=%s)", this, qPrintable(appId));
469
const QString appId = toShortAppIdIfPossible(inputAppId);
470
qCDebug(QTMIR_APPLICATIONS) << "ApplicationManager::stopApplication - appId=" << appId;
349
472
Application *application = findApplication(appId);
351
473
if (!application) {
352
DLOG("No such running application '%s'", qPrintable(appId));
474
qCritical() << "No such running application with appId" << appId;
356
478
if (application == m_focusedApplication) {
357
479
// TODO(greyback) What to do?? Focus next app, or unfocus everything??
358
m_focusedApplication = NULL;
480
m_focusedApplication = nullptr;
359
481
Q_EMIT focusedApplicationIdChanged();
362
484
remove(application);
363
m_dbusWindowStack->WindowDestroyed(0, application->appId());
365
bool result = m_taskController->stop(application->appId());
367
LOG_IF(result == false, "FAILED to ask Upstart to stop application '%s'", qPrintable(application->appId()));
485
m_dbusWindowStack->WindowDestroyed(0, appId);
487
bool result = m_taskController->stop(application->longAppId());
489
if (!result && application->pid() > 0) {
490
qWarning() << "FAILED to ask Upstart to stop application with appId" << appId
491
<< "Sending SIGTERM to process:" << application->pid();
492
kill(application->pid(), SIGTERM);
368
496
delete application;
370
// FIXME(dandrader): lying here. The operation is async. So we will only know whether
371
// the focusing was successful once the server replies. Maybe the API in unity-api should
390
void ApplicationManager::onProcessStopped(const QString &appId, const bool unexpected)
392
Application *application = findApplication(appId);
514
void ApplicationManager::onProcessFailed(const QString &appId, const bool duringStartup)
516
/* Applications fail if they fail to launch, crash or are killed. If failed to start, must
517
* immediately remove from list of applications. If crash or kill, instead we set flag on the
518
* Application to indicate it can be resumed.
521
qCDebug(QTMIR_APPLICATIONS) << "ApplicationManager::onProcessStopped - appId=" << appId << "duringStartup=" << duringStartup;
523
Application *application = findApplication(appId);
525
qWarning() << "ApplicationManager::onProcessFailed - upstart reports failure of application" << appId
526
<< "that AppManager is not managing";
530
Q_UNUSED(duringStartup); // FIXME(greyback) upstart reports app that fully started up & crashes as failing during startup??
531
if (application->state() == Application::Starting) {
532
if (application == m_focusedApplication) {
533
m_focusedApplication = nullptr;
534
Q_EMIT focusedApplicationIdChanged();
537
m_dbusWindowStack->WindowDestroyed(0, application->appId());
540
// We need to set flags on the Application to say the app can be resumed, and thus should not be removed
541
// from the list by onProcessStopped.
542
application->setCanBeResumed(true);
543
application->setPid(0);
547
void ApplicationManager::onProcessStopped(const QString &appId)
549
qCDebug(QTMIR_APPLICATIONS) << "ApplicationManager::onProcessStopped - appId=" << appId;
550
Application *application = findApplication(appId);
553
qDebug() << "ApplicationManager::onProcessStopped reports stop of appId=" << appId
554
<< "which AppMan is not managing, ignoring the event";
394
558
// if shell did not stop the application, but ubuntu-app-launch says it died, we assume the process has been
395
559
// killed, so it can be respawned later. Only exception is if that application is focused or running
396
560
// as then it most likely crashed. Update this logic when ubuntu-app-launch gives some failure info.
398
bool removeApplication = false;
400
if (application == m_focusedApplication) {
401
// Very bad case where focused application dies. Remove from list. Should give error message
402
m_focusedApplication = nullptr;
403
Q_EMIT focusedApplicationIdChanged();
404
removeApplication = true;
407
if (application->state() == Application::Running || application->state() == Application::Starting) {
408
// Application probably crashed, else OOM killer struck. Either way state wasn't saved
409
// so just remove application
410
removeApplication = true;
411
} else if (application->state() == Application::Suspended) {
412
application->setState(Application::Stopped);
413
application->setSession(nullptr);
416
if (removeApplication) {
418
m_dbusWindowStack->WindowDestroyed(0, application->appId());
424
// TODO: pop up a message box/notification?
425
LOG("ApplicationManager: application '%s' died unexpectedly!", qPrintable(appId));
561
bool removeApplication = true;
563
if (application == m_focusedApplication) {
564
// Very bad case where focused application dies. Remove from list. Should give error message
565
m_focusedApplication = nullptr;
566
Q_EMIT focusedApplicationIdChanged();
569
// The following scenario is the only time that we do NOT remove the application from the app list:
570
if ((application->state() == Application::Suspended || application->state() == Application::Stopped)
571
&& application->pid() == 0 // i.e. onProcessFailed was called, which resets the PID of this application
572
&& application->canBeResumed()) {
573
removeApplication = false;
576
if (removeApplication) {
577
qCDebug(QTMIR_APPLICATIONS) << "ApplicationManager::onProcessStopped - removing appId=" << appId;
579
m_dbusWindowStack->WindowDestroyed(0, application->appId());
429
584
void ApplicationManager::onFocusRequested(const QString& appId)
431
DLOG("ApplicationManager::onFocusRequested (this=%p, appId=%s)", this, qPrintable(appId));
586
qCDebug(QTMIR_APPLICATIONS) << "ApplicationManager::onFocusRequested - appId=" << appId;
433
588
Q_EMIT focusRequested(appId);
436
591
void ApplicationManager::onResumeRequested(const QString& appId)
438
DLOG("ApplicationManager::onResumeRequested (this=%p, appId=%s)", this, qPrintable(appId));
593
qCDebug(QTMIR_APPLICATIONS) << "ApplicationManager::onResumeRequested - appId=" << appId;
440
595
Application *application = findApplication(appId);
442
597
if (!application) {
443
DLOG("ApplicationManager::onResumeRequested: No such running application '%s'", qPrintable(appId));
598
qCritical() << "ApplicationManager::onResumeRequested: No such running application" << appId;
486
* Hack: Allow applications to be launched externally, but must be executed with the
487
* "desktop_file_hint" parameter attached. This exists until ubuntu-app-launch can
488
* notify shell it is starting an application and so shell should allow it. Also reads
489
* the --stage parameter to determine the desired stage
643
* Hack: Allow applications to be launched without being managed by upstart, where AppManager
644
* itself manages processes executed with a "--desktop_file_hint=/path/to/desktopFile.desktop"
645
* parameter attached. This exists until ubuntu-app-launch can notify shell any application is
646
* and so shell should allow it. Also reads the --stage parameter to determine the desired stage
491
QFile cmdline(QString("/proc/%1/cmdline").arg(pid));
492
if (!cmdline.open(QIODevice::ReadOnly | QIODevice::Text)) {
493
DLOG("ApplicationManager REJECTED connection from app with pid %lld as unable to read process command", pid);
648
std::unique_ptr<ProcInfo::CommandLine> info = m_procInfo->commandLine(pid);
650
qWarning() << "ApplicationManager REJECTED connection from app with pid" << pid
651
<< "as unable to read the process command line";
497
QByteArray command = cmdline.readLine().replace('\0', ' ');
499
// FIXME: special exception for the OSK - maliit-server - not very secure
500
if (command.startsWith("maliit-server") || command.startsWith("/usr/lib/arm-linux-gnueabihf/qt5/libexec/QtWebProcess")
501
|| command.startsWith("/usr/bin/signon-ui")) {
655
if (info->startsWith("maliit-server") || info->contains("qt5/libexec/QtWebProcess")) {
502
656
authorized = true;
507
QString pattern = QRegularExpression::escape("--desktop_file_hint=") + "(\\S+)";
508
QRegularExpression regExp(pattern);
509
QRegularExpressionMatch regExpMatch = regExp.match(command);
511
if (!regExpMatch.hasMatch()) {
512
LOG("ApplicationManager REJECTED connection from app with pid %lld as no desktop_file_hint specified", pid);
516
QString desktopFileName = regExpMatch.captured(1);
517
DLOG("Process supplied desktop_file_hint, loading '%s'", desktopFileName.toLatin1().data());
660
boost::optional<QString> desktopFileName{ info->getParameter("--desktop_file_hint=") };
662
if (!desktopFileName) {
663
qCritical() << "ApplicationManager REJECTED connection from app with pid" << pid
664
<< "as no desktop_file_hint specified";
668
qCDebug(QTMIR_APPLICATIONS) << "Process supplied desktop_file_hint, loading" << desktopFileName;
670
// Guess appId from the desktop file hint
671
QString appId = toShortAppIdIfPossible(desktopFileName.get().remove(QRegExp(".desktop$")).split('/').last());
519
673
// FIXME: right now we support --desktop_file_hint=appId for historical reasons. So let's try that in
520
674
// case we didn't get an existing .desktop file path
521
675
DesktopFileReader* desktopData;
522
if (QFileInfo(desktopFileName).exists()) {
523
desktopData = new DesktopFileReader(QFileInfo(desktopFileName));
676
if (QFileInfo(desktopFileName.get()).exists()) {
677
desktopData = m_desktopFileReaderFactory->createInstance(appId, QFileInfo(desktopFileName.get()));
525
desktopData = new DesktopFileReader(desktopFileName);
679
desktopData = m_desktopFileReaderFactory->createInstance(appId, m_taskController->findDesktopFileForAppId(appId));
528
682
if (!desktopData->loaded()) {
529
683
delete desktopData;
530
LOG("ApplicationManager REJECTED connection from app with pid %lld as desktop_file_hint file not found", pid);
684
qCritical() << "ApplicationManager REJECTED connection from app with pid" << pid
685
<< "as the file specified by the desktop_file_hint argument could not be opened";
547
702
// if stage supplied in CLI, fetch that
548
703
Application::Stage stage = Application::MainStage;
549
pattern = QRegularExpression::escape("--stage=") + "(\\S+)";
550
regExp.setPattern(pattern);
551
regExpMatch = regExp.match(command);
704
boost::optional<QString> stageParam = info->getParameter("--stage_hint=");
553
if (regExpMatch.hasMatch() && regExpMatch.captured(1) == "side_stage") {
706
if (stageParam && stageParam.get() == "side_stage") {
554
707
stage = Application::SideStage;
557
DLOG("Existing process with pid %lld appeared, adding '%s' to application lists", pid, desktopData->name().toLatin1().data());
710
qCDebug(QTMIR_APPLICATIONS) << "New process with pid" << pid << "appeared, adding new application to the"
711
<< "application list with appId:" << desktopData->appId();
559
QString argStr(command.data());
560
QStringList arguments(argStr.split(' '));
561
application = new Application(desktopData, Application::Starting, arguments, this);
713
QStringList arguments(info->asStringList());
714
application = new Application(m_taskController, desktopData, Application::Starting, arguments, this);
562
715
application->setPid(pid);
563
716
application->setStage(stage);
717
application->setCanBeResumed(false);
564
718
add(application);
565
719
authorized = true;
568
722
void ApplicationManager::onSessionStarting(std::shared_ptr<ms::Session> const& session)
570
DLOG("ApplicationManager::onSessionStarting (this=%p, application=%s)", this, session->name().c_str());
724
qCDebug(QTMIR_APPLICATIONS) << "ApplicationManager::onSessionStarting - sessionName=" << session->name().c_str();
726
if (m_fenceNext) { // needed to ignore sessions created by non-user processes (e.g. maliit)
573
727
m_fenceNext = false;
577
731
Application* application = findApplicationWithPid(session->process_id());
578
732
if (application && application->state() != Application::Running) {
579
733
application->setSession(session);
580
m_applicationToBeFocused = application;
734
if (application->stage() == Application::MainStage)
735
m_msApplicationToBeFocused = application;
737
m_ssApplicationToBeFocused = application;
582
DLOG("ApplicationManager::onSessionStarting - unauthorized application!!");
739
qCritical() << "ApplicationManager::onSessionStarting - unauthorized application!!";
586
743
void ApplicationManager::onSessionStopping(std::shared_ptr<ms::Session> const& session)
588
DLOG("ApplicationManager::onSessionStopping (this=%p, application=%s)", this, session->name().c_str());
745
qCDebug(QTMIR_APPLICATIONS) << "ApplicationManager::onSessionStopping - sessionName=" << session->name().c_str();
590
747
// in case application closed not by hand of shell, check again here:
591
748
Application* application = findApplicationWithSession(session);
592
749
if (application) {
593
bool removeApplication = true;
750
/* Can remove the application from the running apps list immediately in these curcumstances:
751
* 1. application is not managed by upstart (this message from Mir is only notice the app has stopped, must do
753
* 2. application is managed by upstart, but has stopped before it managed to create a surface, we can assume
754
* it crashed on startup, and thus cannot be resumed - so remove it.
755
* 3. application is managed by upstart and is in foreground (i.e. has Running state), if Mir reports the
756
* application disconnects, it either crashed or stopped itself. Either case, remove it.
758
if (!application->canBeResumed()
759
|| application->state() == Application::Starting
760
|| application->state() == Application::Running) { qDebug() << "A" << application->canBeResumed() << application->state();
761
m_dbusWindowStack->WindowDestroyed(0, application->appId());
595
if (application->state() != Application::Starting) {
596
application->setState(Application::Stopped);
597
application->setSession(nullptr);
598
m_dbusWindowStack->WindowDestroyed(0, application->appId());
599
if (application != m_focusedApplication) {
600
removeApplication = false;
765
if (application == m_focusedApplication) {
766
m_focusedApplication = nullptr;
767
Q_EMIT focusedApplicationIdChanged();
604
if (removeApplication) {
605
// TODO(greyback) What to do?? Focus next app, or unfocus everything??
606
m_focusedApplication = NULL;
609
Q_EMIT focusedApplicationIdChanged();
614
void ApplicationManager::onSessionFocused(std::shared_ptr<ms::Session> const& session)
616
DLOG("ApplicationManager::onSessionFocused (this=%p, application=%s)", this, session->name().c_str());
617
Application* application = findApplicationWithSession(session);
619
// Don't give application focus until it has created it's surface, when it is set as state "Running"
620
// and only notify shell of focus changes that it actually expects
621
if (application && application->state() != Application::Starting && application == m_applicationToBeFocused
622
&& application != m_focusedApplication) {
623
setFocused(application);
624
QModelIndex appIndex = findIndex(application);
625
Q_EMIT dataChanged(appIndex, appIndex, QVector<int>() << RoleFocused);
627
if (application == nullptr) {
628
DLOG("Invalid application focused, discarding the event");
629
if (NULL != m_focusedApplication)
630
focusApplication(m_focusedApplication->appId());
635
void ApplicationManager::onSessionUnfocused()
637
DLOG("ApplicationManager::onSessionUnfocused (this=%p)", this);
638
if (NULL != m_focusedApplication) {
639
Q_ASSERT(m_focusedApplication->focused());
640
m_focusedApplication->setFocused(false);
642
//suspendApplication(m_focusedApplication);
644
m_focusedApplication = NULL;
645
Q_EMIT focusedApplicationIdChanged();
646
m_dbusWindowStack->FocusedWindowChanged(0, QString(), 0);
648
QModelIndex appIndex = findIndex(m_focusedApplication);
649
Q_EMIT dataChanged(appIndex, appIndex, QVector<int>() << RoleFocused << RoleState);
770
// otherwise, we do not have enough information to make any changes to the model, so await events from
771
// upstart to go further, but set the app state
772
application->setState(Application::Stopped);
653
777
void ApplicationManager::onSessionCreatedSurface(ms::Session const* session,
654
778
std::shared_ptr<ms::Surface> const& surface)
656
DLOG("ApplicationManager::onSessionCreatedSurface (this=%p)", this);
780
qCDebug(QTMIR_APPLICATIONS) << "ApplicationManager::onSessionCreatedSurface - sessionName=" << session->name().c_str();
657
781
Q_UNUSED(surface);
659
783
Application* application = findApplicationWithSession(session);
844
Application* ApplicationManager::applicationForStage(Application::Stage stage)
846
qCDebug(QTMIR_APPLICATIONS) << "ApplicationManager::focusedApplicationForStage" << stage;
848
if (stage == Application::MainStage)
849
return m_mainStageApplication;
851
return m_sideStageApplication;
712
854
void ApplicationManager::add(Application* application)
714
DASSERT(application != NULL);
715
DLOG("ApplicationManager::add (this=%p, application='%s')", this, qPrintable(application->name()));
856
Q_ASSERT(application != nullptr);
857
qCDebug(QTMIR_APPLICATIONS) << "ApplicationManager::add - appId=" << application->appId();
717
859
connect(application, &Application::screenshotChanged, this, &ApplicationManager::screenshotUpdated);
719
861
beginInsertRows(QModelIndex(), m_applications.count(), m_applications.count());
720
862
m_applications.append(application);
723
emit applicationAdded(application->appId());
864
Q_EMIT countChanged();
865
Q_EMIT applicationAdded(application->appId());
724
866
if (m_applications.size() == 1) {
725
emit topmostApplicationChanged(application);
867
Q_EMIT topmostApplicationChanged(application);
868
Q_EMIT emptyChanged();
730
872
void ApplicationManager::remove(Application *application)
732
DASSERT(application != NULL);
733
DLOG("ApplicationManager::remove (this=%p, application='%s')", this, qPrintable(application->name()));
874
Q_ASSERT(application != nullptr);
875
qCDebug(QTMIR_APPLICATIONS) << "ApplicationManager::remove - appId=" << application->appId();
877
if (application == m_sideStageApplication)
878
m_sideStageApplication = nullptr;
879
if (application == m_mainStageApplication)
880
m_mainStageApplication = nullptr;
735
882
int i = m_applications.indexOf(application);
737
884
beginRemoveRows(QModelIndex(), i, i);
738
885
m_applications.removeAt(i);
740
emit applicationRemoved(application->appId());
887
Q_EMIT applicationRemoved(application->appId());
888
Q_EMIT countChanged();
743
emit topmostApplicationChanged(topmostApplication());
890
Q_EMIT topmostApplicationChanged(topmostApplication());
891
Q_EMIT emptyChanged();
749
896
void ApplicationManager::move(int from, int to) {
750
DLOG("ApplicationManager::move (this=%p, from=%d, to=%d)", this, from, to);
897
qCDebug(QTMIR_APPLICATIONS) << "ApplicationManager::move - from=" << from << "to=" << to;
751
898
if (from == to) return;
753
900
if (from >= 0 && from < m_applications.size() && to >= 0 && to < m_applications.size()) {