~ted/ubuntu-app-launch/jobs-systemd

« back to all changes in this revision

Viewing changes to libubuntu-app-launch/ubuntu-app-launch.cpp

  • Committer: Ted Gould
  • Date: 2016-11-10 21:56:40 UTC
  • mfrom: (257.1.9 jobs-tests)
  • Revision ID: ted@gould.cx-20161110215640-1c0n3gxhmlrm0gvk
Merge in the tests branch

Show diffs side-by-side

added added

removed removed

Lines of Context:
39
39
#include "appid.h"
40
40
#include "registry.h"
41
41
#include "registry-impl.h"
 
42
#include <algorithm>
42
43
 
43
44
static void free_helper (gpointer value);
44
45
int kill (pid_t pid, int signal) noexcept;
271
272
        gpointer user_data;
272
273
};
273
274
 
274
 
/* The data we keep for each failed observer */
275
 
typedef struct _paused_resumed_observer_t paused_resumed_observer_t;
276
 
struct _paused_resumed_observer_t {
277
 
        GDBusConnection * conn;
278
 
        guint sighandle;
279
 
        UbuntuAppLaunchAppPausedResumedObserver func;
280
 
        gpointer user_data;
281
 
        const gchar * lttng_signal;
282
 
};
283
 
 
284
 
/* The lists of Observers */
285
 
static GList * starting_array = NULL;
286
 
static GList * started_array = NULL;
287
 
static GList * stop_array = NULL;
288
 
static GList * focus_array = NULL;
289
 
static GList * resume_array = NULL;
290
 
static GList * failed_array = NULL;
291
 
static GList * paused_array = NULL;
292
 
static GList * resumed_array = NULL;
293
 
 
294
 
static void
295
 
observer_cb (GDBusConnection * conn, const gchar * sender, const gchar * object, const gchar * interface, const gchar * signal, GVariant * params, gpointer user_data)
296
 
{
297
 
        observer_t * observer = (observer_t *)user_data;
298
 
 
299
 
        const gchar * signalname = NULL;
300
 
        g_variant_get_child(params, 0, "&s", &signalname);
301
 
 
302
 
        ual_tracepoint(observer_start, signalname);
303
 
 
304
 
        gchar * env = NULL;
305
 
        GVariant * envs = g_variant_get_child_value(params, 1);
306
 
        GVariantIter iter;
307
 
        g_variant_iter_init(&iter, envs);
308
 
 
309
 
        gboolean job_found = FALSE;
310
 
        gboolean job_legacy = FALSE;
311
 
        gchar * instance = NULL;
312
 
 
313
 
        while (g_variant_iter_loop(&iter, "s", &env)) {
314
 
                if (g_strcmp0(env, "JOB=application-click") == 0) {
315
 
                        job_found = TRUE;
316
 
                } else if (g_strcmp0(env, "JOB=application-legacy") == 0) {
317
 
                        job_found = TRUE;
318
 
                        job_legacy = TRUE;
319
 
                } else if (g_strcmp0(env, "JOB=application-snap") == 0) {
320
 
                        job_found = TRUE;
321
 
                        job_legacy = TRUE;
322
 
                } else if (g_str_has_prefix(env, "INSTANCE=")) {
323
 
                        instance = g_strdup(env + strlen("INSTANCE="));
324
 
                }
325
 
        }
326
 
 
327
 
        g_variant_unref(envs);
328
 
 
329
 
        if (job_legacy && instance != NULL) {
330
 
                gchar * dash = g_strrstr(instance, "-");
331
 
                if (dash != NULL) {
332
 
                        dash[0] = '\0';
333
 
                }
334
 
        }
335
 
 
336
 
        if (job_found && instance != NULL) {
337
 
                observer->func(instance, observer->user_data);
338
 
        }
339
 
 
340
 
        ual_tracepoint(observer_finish, signalname);
341
 
 
342
 
        g_free(instance);
343
 
}
344
 
 
345
 
/* Creates the observer structure and registers for the signal with
346
 
   GDBus so that we can get a callback */
347
 
static gboolean
348
 
add_app_generic (UbuntuAppLaunchAppObserver observer, gpointer user_data, const gchar * signal, GList ** list)
349
 
{
350
 
        GDBusConnection * conn = gdbus_upstart_ref();
351
 
 
352
 
        if (conn == NULL) {
353
 
                return FALSE;
354
 
        }
355
 
 
356
 
        observer_t * observert = g_new0(observer_t, 1);
357
 
 
358
 
        observert->conn = conn;
359
 
        observert->func = observer;
360
 
        observert->user_data = user_data;
361
 
 
362
 
        *list = g_list_prepend(*list, observert);
363
 
 
364
 
        observert->sighandle = g_dbus_connection_signal_subscribe(conn,
365
 
                NULL, /* sender */
366
 
                DBUS_INTERFACE_UPSTART, /* interface */
367
 
                "EventEmitted", /* signal */
368
 
                DBUS_PATH_UPSTART, /* path */
369
 
                signal, /* arg0 */
370
 
                G_DBUS_SIGNAL_FLAGS_NONE,
371
 
                observer_cb,
372
 
                observert,
373
 
                NULL); /* user data destroy */
374
 
 
375
 
        return TRUE;
376
 
}
 
275
/* Function to take a work function and have it execute on a given
 
276
   GMainContext */
 
277
static void executeOnContext (std::shared_ptr<GMainContext> context, std::function<void()> work)
 
278
{
 
279
        if (!context) {
 
280
                work();
 
281
                return;
 
282
        }
 
283
 
 
284
    auto heapWork = new std::function<void()>(work);
 
285
 
 
286
    auto source = std::shared_ptr<GSource>(g_idle_source_new(), [](GSource* src) { g_clear_pointer(&src, g_source_unref); });
 
287
    g_source_set_callback(source.get(),
 
288
                          [](gpointer data) {
 
289
                              auto heapWork = static_cast<std::function<void()>*>(data);
 
290
                              (*heapWork)();
 
291
                              return G_SOURCE_REMOVE;
 
292
                          },
 
293
                          heapWork,
 
294
                          [](gpointer data) {
 
295
                              auto heapWork = static_cast<std::function<void()>*>(data);
 
296
                              delete heapWork;
 
297
                          });
 
298
 
 
299
    g_source_attach(source.get(), context.get());
 
300
}
 
301
 
 
302
/* Map of all the observers listening for app started */
 
303
static std::map<std::pair<UbuntuAppLaunchAppObserver, gpointer>, core::ScopedConnection> appStartedObservers;
377
304
 
378
305
gboolean
379
306
ubuntu_app_launch_observer_add_app_started (UbuntuAppLaunchAppObserver observer, gpointer user_data)
380
307
{
381
 
        return add_app_generic(observer, user_data, "started", &started_array);
382
 
}
 
308
        auto context = std::shared_ptr<GMainContext>(g_main_context_ref_thread_default(), [](GMainContext * context) { g_clear_pointer(&context, g_main_context_unref); });
 
309
 
 
310
        appStartedObservers.emplace(std::make_pair(
 
311
                std::make_pair(observer, user_data),
 
312
                        core::ScopedConnection(
 
313
                                ubuntu::app_launch::Registry::appStarted().connect([context, observer, user_data](std::shared_ptr<ubuntu::app_launch::Application> app, std::shared_ptr<ubuntu::app_launch::Application::Instance> instance) {
 
314
                                        std::string appid = app->appId();
 
315
                                        executeOnContext(context, [appid, observer, user_data]() {
 
316
                                                observer(appid.c_str(), user_data);
 
317
                                        });
 
318
                                })
 
319
                        )
 
320
                ));
 
321
 
 
322
        return TRUE;
 
323
}
 
324
 
 
325
gboolean
 
326
ubuntu_app_launch_observer_delete_app_started (UbuntuAppLaunchAppObserver observer, gpointer user_data)
 
327
{
 
328
        auto iter = appStartedObservers.find(std::make_pair(observer, user_data));
 
329
 
 
330
        if (iter == appStartedObservers.end()) {
 
331
                return FALSE;
 
332
        }
 
333
 
 
334
        appStartedObservers.erase(iter);
 
335
        return TRUE;
 
336
}
 
337
 
 
338
/* Map of all the observers listening for app stopped */
 
339
static std::map<std::pair<UbuntuAppLaunchAppObserver, gpointer>, core::ScopedConnection> appStoppedObservers;
383
340
 
384
341
gboolean
385
342
ubuntu_app_launch_observer_add_app_stop (UbuntuAppLaunchAppObserver observer, gpointer user_data)
386
343
{
387
 
        return add_app_generic(observer, user_data, "stopped", &stop_array);
 
344
        auto context = std::shared_ptr<GMainContext>(g_main_context_ref_thread_default(), [](GMainContext * context) { g_clear_pointer(&context, g_main_context_unref); });
 
345
 
 
346
        appStoppedObservers.emplace(std::make_pair(
 
347
                std::make_pair(observer, user_data),
 
348
                        core::ScopedConnection(
 
349
                                ubuntu::app_launch::Registry::appStopped().connect([context, observer, user_data](std::shared_ptr<ubuntu::app_launch::Application> app, std::shared_ptr<ubuntu::app_launch::Application::Instance> instance) {
 
350
                                        std::string appid = app->appId();
 
351
                                        executeOnContext(context, [appid, observer, user_data]() {
 
352
                                                observer(appid.c_str(), user_data);
 
353
                                        });
 
354
                                })
 
355
                        )
 
356
                ));
 
357
 
 
358
        return TRUE;
388
359
}
389
360
 
390
 
/* Creates the observer structure and registers for the signal with
391
 
   GDBus so that we can get a callback */
392
 
static gboolean
393
 
add_session_generic (UbuntuAppLaunchAppObserver observer, gpointer user_data, const gchar * signal, GList ** list, GDBusSignalCallback session_cb)
 
361
gboolean
 
362
ubuntu_app_launch_observer_delete_app_stop (UbuntuAppLaunchAppObserver observer, gpointer user_data)
394
363
{
395
 
        GDBusConnection * conn = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);
 
364
        auto iter = appStoppedObservers.find(std::make_pair(observer, user_data));
396
365
 
397
 
        if (conn == NULL) {
 
366
        if (iter == appStoppedObservers.end()) {
398
367
                return FALSE;
399
368
        }
400
369
 
401
 
        observer_t * observert = g_new0(observer_t, 1);
402
 
 
403
 
        observert->conn = conn;
404
 
        observert->func = observer;
405
 
        observert->user_data = user_data;
406
 
 
407
 
        *list = g_list_prepend(*list, observert);
408
 
 
409
 
        observert->sighandle = g_dbus_connection_signal_subscribe(conn,
410
 
                NULL, /* sender */
411
 
                "com.canonical.UbuntuAppLaunch", /* interface */
412
 
                signal, /* signal */
413
 
                "/", /* path */
414
 
                NULL, /* arg0 */
415
 
                G_DBUS_SIGNAL_FLAGS_NONE,
416
 
                session_cb,
417
 
                observert,
418
 
                NULL); /* user data destroy */
419
 
 
 
370
        appStoppedObservers.erase(iter);
420
371
        return TRUE;
421
372
}
422
373
 
 
374
class CManager : public ubuntu::app_launch::Registry::Manager
 
375
{
 
376
public:
 
377
        CManager () {
 
378
                g_debug("Creating the CManager object");
 
379
        }
 
380
 
 
381
        void startingRequest(std::shared_ptr<ubuntu::app_launch::Application> app,
 
382
                                     std::shared_ptr<ubuntu::app_launch::Application::Instance> instance,
 
383
                                     std::function<void(bool)> reply) override {
 
384
                std::string sappid = app->appId();
 
385
                g_debug("CManager starting: %s", sappid.c_str());
 
386
 
 
387
                for (const auto &data : startingList) {
 
388
                        executeOnContext(data.context, [data, sappid]() {
 
389
                                data.observer(sappid.c_str(), data.user_data);
 
390
                        });
 
391
                }
 
392
 
 
393
                reply(true);
 
394
        }
 
395
 
 
396
        void focusRequest(std::shared_ptr<ubuntu::app_launch::Application> app,
 
397
                                  std::shared_ptr<ubuntu::app_launch::Application::Instance> instance,
 
398
                                  std::function<void(bool)> reply) override {
 
399
                std::string sappid = app->appId();
 
400
                g_debug("CManager focus: %s", sappid.c_str());
 
401
 
 
402
                for (const auto &data : focusList) {
 
403
                        executeOnContext(data.context, [data, sappid]() {
 
404
                                data.observer(sappid.c_str(), data.user_data);
 
405
                        });
 
406
                }
 
407
 
 
408
                reply(true);
 
409
        }
 
410
 
 
411
        void resumeRequest(std::shared_ptr<ubuntu::app_launch::Application> app,
 
412
                                   std::shared_ptr<ubuntu::app_launch::Application::Instance> instance,
 
413
                                   std::function<void(bool)> reply) override {
 
414
                std::string sappid = app->appId();
 
415
                g_debug("CManager resume: %s", sappid.c_str());
 
416
 
 
417
                for (const auto &data : resumeList) {
 
418
                        executeOnContext(data.context, [data, sappid]() {
 
419
                                data.observer(sappid.c_str(), data.user_data);
 
420
                        });
 
421
                }
 
422
 
 
423
                reply(true);
 
424
        }
 
425
 
 
426
private:
 
427
        struct ObserverData {
 
428
                UbuntuAppLaunchAppObserver observer;
 
429
                gpointer user_data;
 
430
                std::shared_ptr<GMainContext> context;
 
431
 
 
432
                ObserverData(UbuntuAppLaunchAppObserver obs, gpointer ud)
 
433
                        : observer(obs)
 
434
                        , user_data(ud) {
 
435
                        context = std::shared_ptr<GMainContext>(g_main_context_ref_thread_default(), [](GMainContext * context) { g_clear_pointer(&context, g_main_context_unref); });
 
436
                }
 
437
        };
 
438
 
 
439
        std::list<ObserverData> focusList;
 
440
        std::list<ObserverData> resumeList;
 
441
        std::list<ObserverData> startingList;
 
442
 
 
443
        bool removeList (std::list<ObserverData> &list, UbuntuAppLaunchAppObserver observer, gpointer user_data) {
 
444
                auto iter = std::find_if(list.begin(), list.end(), [observer, user_data](const ObserverData &data) {
 
445
                        return data.observer == observer && data.user_data == user_data;
 
446
                });
 
447
 
 
448
                if (iter == list.end()) {
 
449
                        return false;
 
450
                }
 
451
 
 
452
                list.erase(iter);
 
453
                return true;
 
454
        }
 
455
 
 
456
public:
 
457
        void addFocus (UbuntuAppLaunchAppObserver observer, gpointer user_data) {
 
458
                focusList.emplace_back(ObserverData(observer, user_data));
 
459
        }
 
460
        void addResume (UbuntuAppLaunchAppObserver observer, gpointer user_data) {
 
461
                resumeList.emplace_back(ObserverData(observer, user_data));
 
462
        }
 
463
        void addStarting (UbuntuAppLaunchAppObserver observer, gpointer user_data) {
 
464
                startingList.emplace_back(ObserverData(observer, user_data));
 
465
        }
 
466
        bool deleteFocus (UbuntuAppLaunchAppObserver observer, gpointer user_data) {
 
467
                return removeList(focusList, observer, user_data);
 
468
        }
 
469
        bool deleteResume (UbuntuAppLaunchAppObserver observer, gpointer user_data) {
 
470
                return removeList(resumeList, observer, user_data);
 
471
        }
 
472
        bool deleteStarting (UbuntuAppLaunchAppObserver observer, gpointer user_data) {
 
473
                return removeList(startingList, observer, user_data);
 
474
        }
 
475
};
 
476
 
 
477
static std::weak_ptr<CManager> cmanager;
 
478
 
423
479
/* Generic handler for a bunch of our signals */
424
480
static inline void
425
481
generic_signal_cb (GDBusConnection * conn, const gchar * sender, const gchar * object, const gchar * interface, const gchar * signal, GVariant * params, gpointer user_data)
433
489
        }
434
490
}
435
491
 
436
 
/* Handle the focus signal when it occurs, call the observer */
437
 
static void
438
 
focus_signal_cb (GDBusConnection * conn, const gchar * sender, const gchar * object, const gchar * interface, const gchar * signal, GVariant * params, gpointer user_data)
439
 
{
440
 
        ual_tracepoint(observer_start, "focus");
441
 
 
442
 
        generic_signal_cb(conn, sender, object, interface, signal, params, user_data);
443
 
 
444
 
        ual_tracepoint(observer_finish, "focus");
445
 
}
446
 
 
447
492
gboolean
448
493
ubuntu_app_launch_observer_add_app_focus (UbuntuAppLaunchAppObserver observer, gpointer user_data)
449
494
{
450
 
        return add_session_generic(observer, user_data, "UnityFocusRequest", &focus_array, focus_signal_cb);
 
495
        auto manager = cmanager.lock();
 
496
 
 
497
        if (!manager) {
 
498
                manager = std::make_shared<CManager>();
 
499
                ubuntu::app_launch::Registry::setManager(manager, ubuntu::app_launch::Registry::getDefault());
 
500
                cmanager = manager;
 
501
        }
 
502
 
 
503
        manager->addFocus(observer, user_data);
 
504
        return TRUE;
451
505
}
452
506
 
453
 
/* Handle the resume signal when it occurs, call the observer, then send a signal back when we're done */
454
 
static void
455
 
resume_signal_cb (GDBusConnection * conn, const gchar * sender, const gchar * object, const gchar * interface, const gchar * signal, GVariant * params, gpointer user_data)
 
507
gboolean
 
508
ubuntu_app_launch_observer_delete_app_focus (UbuntuAppLaunchAppObserver observer, gpointer user_data)
456
509
{
457
 
        ual_tracepoint(observer_start, "resume");
458
 
 
459
 
        generic_signal_cb(conn, sender, object, interface, signal, params, user_data);
460
 
 
461
 
        GError * error = NULL;
462
 
        g_dbus_connection_emit_signal(conn,
463
 
                sender, /* destination */
464
 
                "/", /* path */
465
 
                "com.canonical.UbuntuAppLaunch", /* interface */
466
 
                "UnityResumeResponse", /* signal */
467
 
                params, /* params, the same */
468
 
                &error);
469
 
 
470
 
        if (error != NULL) {
471
 
                g_warning("Unable to emit response signal: %s", error->message);
472
 
                g_error_free(error);
 
510
        auto manager = cmanager.lock();
 
511
 
 
512
        if (!manager) {
 
513
                return FALSE;
473
514
        }
474
515
 
475
 
        ual_tracepoint(observer_finish, "resume");
 
516
        return manager->deleteFocus(observer, user_data) ? TRUE : FALSE;
476
517
}
477
518
 
478
519
gboolean
479
520
ubuntu_app_launch_observer_add_app_resume (UbuntuAppLaunchAppObserver observer, gpointer user_data)
480
521
{
481
 
        return add_session_generic(observer, user_data, "UnityResumeRequest", &resume_array, resume_signal_cb);
 
522
        auto manager = cmanager.lock();
 
523
 
 
524
        if (!manager) {
 
525
                manager = std::make_shared<CManager>();
 
526
                ubuntu::app_launch::Registry::setManager(manager, ubuntu::app_launch::Registry::getDefault());
 
527
                cmanager = manager;
 
528
        }
 
529
 
 
530
        manager->addResume(observer, user_data);
 
531
        return TRUE;
482
532
}
483
533
 
484
 
/* Handle the starting signal when it occurs, call the observer, then send a signal back when we're done */
485
 
static void
486
 
starting_signal_cb (GDBusConnection * conn, const gchar * sender, const gchar * object, const gchar * interface, const gchar * signal, GVariant * params, gpointer user_data)
 
534
gboolean
 
535
ubuntu_app_launch_observer_delete_app_resume (UbuntuAppLaunchAppObserver observer, gpointer user_data)
487
536
{
488
 
        ual_tracepoint(observer_start, "starting");
489
 
 
490
 
        generic_signal_cb(conn, sender, object, interface, signal, params, user_data);
491
 
 
492
 
        GError * error = NULL;
493
 
        g_dbus_connection_emit_signal(conn,
494
 
                sender, /* destination */
495
 
                "/", /* path */
496
 
                "com.canonical.UbuntuAppLaunch", /* interface */
497
 
                "UnityStartingSignal", /* signal */
498
 
                params, /* params, the same */
499
 
                &error);
500
 
 
501
 
        if (error != NULL) {
502
 
                g_warning("Unable to emit response signal: %s", error->message);
503
 
                g_error_free(error);
 
537
        auto manager = cmanager.lock();
 
538
 
 
539
        if (!manager) {
 
540
                return FALSE;
504
541
        }
505
542
 
506
 
        ual_tracepoint(observer_finish, "starting");
 
543
        return manager->deleteResume(observer, user_data) ? TRUE : FALSE;
507
544
}
508
545
 
509
546
gboolean
510
547
ubuntu_app_launch_observer_add_app_starting (UbuntuAppLaunchAppObserver observer, gpointer user_data)
511
548
{
 
549
        auto manager = cmanager.lock();
 
550
 
 
551
        if (!manager) {
 
552
                manager = std::make_shared<CManager>();
 
553
                ubuntu::app_launch::Registry::setManager(manager, ubuntu::app_launch::Registry::getDefault());
 
554
                cmanager = manager;
 
555
        }
 
556
 
512
557
        ubuntu::app_launch::Registry::Impl::watchingAppStarting(true);
513
 
        return add_session_generic(observer, user_data, "UnityStartingBroadcast", &starting_array, starting_signal_cb);
514
 
}
515
 
 
516
 
/* Handle the failed signal when it occurs, call the observer */
517
 
static void
518
 
failed_signal_cb (GDBusConnection * conn, const gchar * sender, const gchar * object, const gchar * interface, const gchar * signal, GVariant * params, gpointer user_data)
519
 
{
520
 
        failed_observer_t * observer = (failed_observer_t *)user_data;
521
 
        const gchar * appid = NULL;
522
 
        const gchar * typestr = NULL;
523
 
 
524
 
        ual_tracepoint(observer_start, "failed");
525
 
 
526
 
        if (observer->func != NULL) {
527
 
                UbuntuAppLaunchAppFailed type = UBUNTU_APP_LAUNCH_APP_FAILED_CRASH;
528
 
                g_variant_get(params, "(&s&s)", &appid, &typestr);
529
 
 
530
 
                if (g_strcmp0("crash", typestr) == 0) {
531
 
                        type = UBUNTU_APP_LAUNCH_APP_FAILED_CRASH;
532
 
                } else if (g_strcmp0("start-failure", typestr) == 0) {
533
 
                        type = UBUNTU_APP_LAUNCH_APP_FAILED_START_FAILURE;
534
 
                } else {
535
 
                        g_warning("Application failure type '%s' unknown, reporting as a crash", typestr);
536
 
                }
537
 
 
538
 
                observer->func(appid, type, observer->user_data);
539
 
        }
540
 
 
541
 
        ual_tracepoint(observer_finish, "failed");
542
 
}
543
 
 
544
 
gboolean
545
 
ubuntu_app_launch_observer_add_app_failed (UbuntuAppLaunchAppFailedObserver observer, gpointer user_data)
546
 
{
547
 
        GDBusConnection * conn = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);
548
 
 
549
 
        if (conn == NULL) {
550
 
                return FALSE;
551
 
        }
552
 
 
553
 
        failed_observer_t * observert = g_new0(failed_observer_t, 1);
554
 
 
555
 
        observert->conn = conn;
556
 
        observert->func = observer;
557
 
        observert->user_data = user_data;
558
 
 
559
 
        failed_array = g_list_prepend(failed_array, observert);
560
 
 
561
 
        observert->sighandle = g_dbus_connection_signal_subscribe(conn,
562
 
                NULL, /* sender */
563
 
                "com.canonical.UbuntuAppLaunch", /* interface */
564
 
                "ApplicationFailed", /* signal */
565
 
                "/", /* path */
566
 
                NULL, /* arg0 */
567
 
                G_DBUS_SIGNAL_FLAGS_NONE,
568
 
                failed_signal_cb,
569
 
                observert,
570
 
                NULL); /* user data destroy */
571
 
 
572
 
        return TRUE;
573
 
}
574
 
 
575
 
/* Handle the paused signal when it occurs, call the observer */
576
 
static void
577
 
paused_signal_cb (GDBusConnection * conn, const gchar * sender, const gchar * object, const gchar * interface, const gchar * signal, GVariant * params, gpointer user_data)
578
 
{
579
 
        paused_resumed_observer_t * observer = (paused_resumed_observer_t *)user_data;
580
 
 
581
 
        ual_tracepoint(observer_start, observer->lttng_signal);
582
 
 
583
 
        if (observer->func != NULL) {
584
 
                GArray * pidarray = g_array_new(TRUE, TRUE, sizeof(GPid));
585
 
                GVariant * appid = g_variant_get_child_value(params, 0);
586
 
                GVariant * pids = g_variant_get_child_value(params, 1);
587
 
                guint64 pid;
588
 
                GVariantIter thispid;
589
 
                g_variant_iter_init(&thispid, pids);
590
 
 
591
 
                while (g_variant_iter_loop(&thispid, "t", &pid)) {
592
 
                        GPid gpid = (GPid)pid; /* Should be a no-op for most architectures, but just in case */
593
 
                        g_array_append_val(pidarray, gpid);
594
 
                }
595
 
 
596
 
                observer->func(g_variant_get_string(appid, NULL), (GPid *)pidarray->data, observer->user_data);
597
 
 
598
 
                g_array_free(pidarray, TRUE);
599
 
                g_variant_unref(appid);
600
 
                g_variant_unref(pids);
601
 
        }
602
 
 
603
 
        ual_tracepoint(observer_finish, observer->lttng_signal);
604
 
}
605
 
 
606
 
static gboolean
607
 
paused_resumed_generic (UbuntuAppLaunchAppPausedResumedObserver observer, gpointer user_data, GList ** queue, const gchar * signal_name, const gchar * lttng_signal)
608
 
{
609
 
        GDBusConnection * conn = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);
610
 
 
611
 
        if (conn == NULL) {
612
 
                return FALSE;
613
 
        }
614
 
 
615
 
        paused_resumed_observer_t * observert = g_new0(paused_resumed_observer_t, 1);
616
 
 
617
 
        observert->conn = conn;
618
 
        observert->func = observer;
619
 
        observert->user_data = user_data;
620
 
        observert->lttng_signal = lttng_signal;
621
 
 
622
 
        *queue = g_list_prepend(*queue, observert);
623
 
 
624
 
        observert->sighandle = g_dbus_connection_signal_subscribe(conn,
625
 
                NULL, /* sender */
626
 
                "com.canonical.UbuntuAppLaunch", /* interface */
627
 
                signal_name, /* signal */
628
 
                "/", /* path */
629
 
                NULL, /* arg0 */
630
 
                G_DBUS_SIGNAL_FLAGS_NONE,
631
 
                paused_signal_cb,
632
 
                observert,
633
 
                NULL); /* user data destroy */
634
 
 
635
 
        return TRUE;
636
 
}
637
 
 
638
 
gboolean
639
 
ubuntu_app_launch_observer_add_app_paused (UbuntuAppLaunchAppPausedResumedObserver observer, gpointer user_data)
640
 
{
641
 
        return paused_resumed_generic(observer, user_data, &paused_array, "ApplicationPaused", "paused");
642
 
}
643
 
 
644
 
gboolean
645
 
ubuntu_app_launch_observer_add_app_resumed (UbuntuAppLaunchAppPausedResumedObserver observer, gpointer user_data)
646
 
{
647
 
        return paused_resumed_generic(observer, user_data, &resumed_array, "ApplicationResumed", "resumed");
648
 
}
649
 
 
650
 
static gboolean
651
 
delete_app_generic (UbuntuAppLaunchAppObserver observer, gpointer user_data, GList ** list)
652
 
{
653
 
        observer_t * observert = NULL;
654
 
        GList * look;
655
 
 
656
 
        for (look = *list; look != NULL; look = g_list_next(look)) {
657
 
                observert = (observer_t *)look->data;
658
 
 
659
 
                if (observert->func == observer && observert->user_data == user_data) {
660
 
                        break;
661
 
                }
662
 
        }
663
 
 
664
 
        if (look == NULL) {
665
 
                return FALSE;
666
 
        }
667
 
 
668
 
        g_dbus_connection_signal_unsubscribe(observert->conn, observert->sighandle);
669
 
        g_object_unref(observert->conn);
670
 
 
671
 
        g_free(observert);
672
 
        *list = g_list_delete_link(*list, look);
673
 
 
674
 
        return TRUE;
675
 
}
676
 
 
677
 
gboolean
678
 
ubuntu_app_launch_observer_delete_app_started (UbuntuAppLaunchAppObserver observer, gpointer user_data)
679
 
{
680
 
        return delete_app_generic(observer, user_data, &started_array);
681
 
}
682
 
 
683
 
gboolean
684
 
ubuntu_app_launch_observer_delete_app_stop (UbuntuAppLaunchAppObserver observer, gpointer user_data)
685
 
{
686
 
        return delete_app_generic(observer, user_data, &stop_array);
687
 
}
688
 
 
689
 
gboolean
690
 
ubuntu_app_launch_observer_delete_app_resume (UbuntuAppLaunchAppObserver observer, gpointer user_data)
691
 
{
692
 
        return delete_app_generic(observer, user_data, &resume_array);
693
 
}
694
 
 
695
 
gboolean
696
 
ubuntu_app_launch_observer_delete_app_focus (UbuntuAppLaunchAppObserver observer, gpointer user_data)
697
 
{
698
 
        return delete_app_generic(observer, user_data, &focus_array);
 
558
        manager->addStarting(observer, user_data);
 
559
        return TRUE;
699
560
}
700
561
 
701
562
gboolean
702
563
ubuntu_app_launch_observer_delete_app_starting (UbuntuAppLaunchAppObserver observer, gpointer user_data)
703
564
{
 
565
        auto manager = cmanager.lock();
 
566
 
 
567
        if (!manager) {
 
568
                return FALSE;
 
569
        }
 
570
 
704
571
        ubuntu::app_launch::Registry::Impl::watchingAppStarting(false);
705
 
        return delete_app_generic(observer, user_data, &starting_array);
 
572
        return manager->deleteStarting(observer, user_data) ? TRUE : FALSE;
 
573
}
 
574
 
 
575
/* Map of all the observers listening for app stopped */
 
576
static std::map<std::pair<UbuntuAppLaunchAppFailedObserver, gpointer>, core::ScopedConnection> appFailedObservers;
 
577
 
 
578
gboolean
 
579
ubuntu_app_launch_observer_add_app_failed (UbuntuAppLaunchAppFailedObserver observer, gpointer user_data)
 
580
{
 
581
        auto context = std::shared_ptr<GMainContext>(g_main_context_ref_thread_default(), [](GMainContext * context) { g_clear_pointer(&context, g_main_context_unref); });
 
582
 
 
583
        appFailedObservers.emplace(std::make_pair(
 
584
                std::make_pair(observer, user_data),
 
585
                        core::ScopedConnection(
 
586
                                ubuntu::app_launch::Registry::appFailed().connect([context, observer, user_data](std::shared_ptr<ubuntu::app_launch::Application> app, std::shared_ptr<ubuntu::app_launch::Application::Instance> instance, ubuntu::app_launch::Registry::FailureType type) {
 
587
                                        std::string appid = app->appId();
 
588
                                        executeOnContext(context, [appid, type, observer, user_data]() {
 
589
                                                UbuntuAppLaunchAppFailed ctype;
 
590
 
 
591
                                                switch (type) {
 
592
                                                case ubuntu::app_launch::Registry::FailureType::CRASH:
 
593
                                                        ctype = UBUNTU_APP_LAUNCH_APP_FAILED_CRASH;
 
594
                                                        break;
 
595
                                                case ubuntu::app_launch::Registry::FailureType::START_FAILURE:
 
596
                                                        ctype = UBUNTU_APP_LAUNCH_APP_FAILED_START_FAILURE;
 
597
                                                        break;
 
598
                                                }
 
599
 
 
600
                                                observer(appid.c_str(), ctype, user_data);
 
601
                                        });
 
602
                                })
 
603
                        )
 
604
                ));
 
605
 
 
606
        return TRUE;
706
607
}
707
608
 
708
609
gboolean
709
610
ubuntu_app_launch_observer_delete_app_failed (UbuntuAppLaunchAppFailedObserver observer, gpointer user_data)
710
611
{
711
 
        failed_observer_t * observert = NULL;
712
 
        GList * look;
713
 
 
714
 
        for (look = failed_array; look != NULL; look = g_list_next(look)) {
715
 
                observert = (failed_observer_t *)look->data;
716
 
 
717
 
                if (observert->func == observer && observert->user_data == user_data) {
718
 
                        break;
719
 
                }
720
 
        }
721
 
 
722
 
        if (look == NULL) {
 
612
        auto iter = appFailedObservers.find(std::make_pair(observer, user_data));
 
613
 
 
614
        if (iter == appFailedObservers.end()) {
723
615
                return FALSE;
724
616
        }
725
617
 
726
 
        g_dbus_connection_signal_unsubscribe(observert->conn, observert->sighandle);
727
 
        g_object_unref(observert->conn);
728
 
 
729
 
        g_free(observert);
730
 
        failed_array = g_list_delete_link(failed_array, look);
731
 
 
 
618
        appFailedObservers.erase(iter);
732
619
        return TRUE;
733
620
}
734
621
 
735
 
static gboolean
736
 
paused_resumed_delete (UbuntuAppLaunchAppPausedResumedObserver observer, gpointer user_data, GList ** list)
 
622
static std::map<std::pair<UbuntuAppLaunchAppPausedResumedObserver, gpointer>, core::ScopedConnection> appPausedObservers;
 
623
 
 
624
gboolean
 
625
ubuntu_app_launch_observer_add_app_paused (UbuntuAppLaunchAppPausedResumedObserver observer, gpointer user_data)
737
626
{
738
 
        paused_resumed_observer_t * observert = NULL;
739
 
        GList * look;
740
 
 
741
 
        for (look = *list; look != NULL; look = g_list_next(look)) {
742
 
                observert = (paused_resumed_observer_t *)look->data;
743
 
 
744
 
                if (observert->func == observer && observert->user_data == user_data) {
745
 
                        break;
746
 
                }
747
 
        }
748
 
 
749
 
        if (look == NULL) {
750
 
                return FALSE;
751
 
        }
752
 
 
753
 
        g_dbus_connection_signal_unsubscribe(observert->conn, observert->sighandle);
754
 
        g_object_unref(observert->conn);
755
 
 
756
 
        g_free(observert);
757
 
        *list = g_list_delete_link(*list, look);
 
627
        auto context = std::shared_ptr<GMainContext>(g_main_context_ref_thread_default(), [](GMainContext * context) { g_clear_pointer(&context, g_main_context_unref); });
 
628
 
 
629
        appPausedObservers.emplace(std::make_pair(
 
630
                std::make_pair(observer, user_data),
 
631
                        core::ScopedConnection(
 
632
                                ubuntu::app_launch::Registry::appPaused().connect([context, observer, user_data](std::shared_ptr<ubuntu::app_launch::Application> app, std::shared_ptr<ubuntu::app_launch::Application::Instance> instance, std::vector<pid_t> &pids) {
 
633
                                        std::vector<pid_t> lpids = pids;
 
634
                                        lpids.emplace_back(0);
 
635
 
 
636
                                        std::string appid = app->appId();
 
637
 
 
638
                                        executeOnContext(context, [appid, observer, user_data, lpids]() {
 
639
                                                observer(appid.c_str(), (int *)(lpids.data()), user_data);
 
640
                                        });
 
641
                                })
 
642
                        )
 
643
                ));
758
644
 
759
645
        return TRUE;
760
646
}
762
648
gboolean
763
649
ubuntu_app_launch_observer_delete_app_paused (UbuntuAppLaunchAppPausedResumedObserver observer, gpointer user_data)
764
650
{
765
 
        return paused_resumed_delete(observer, user_data, &paused_array);
 
651
        auto iter = appPausedObservers.find(std::make_pair(observer, user_data));
 
652
 
 
653
        if (iter == appPausedObservers.end()) {
 
654
                return FALSE;
 
655
        }
 
656
 
 
657
        appPausedObservers.erase(iter);
 
658
        return TRUE;
 
659
}
 
660
 
 
661
static std::map<std::pair<UbuntuAppLaunchAppPausedResumedObserver, gpointer>, core::ScopedConnection> appResumedObservers;
 
662
 
 
663
gboolean
 
664
ubuntu_app_launch_observer_add_app_resumed (UbuntuAppLaunchAppPausedResumedObserver observer, gpointer user_data)
 
665
{
 
666
        auto context = std::shared_ptr<GMainContext>(g_main_context_ref_thread_default(), [](GMainContext * context) { g_clear_pointer(&context, g_main_context_unref); });
 
667
 
 
668
        appResumedObservers.emplace(std::make_pair(
 
669
                std::make_pair(observer, user_data),
 
670
                        core::ScopedConnection(
 
671
                                ubuntu::app_launch::Registry::appResumed().connect([context, observer, user_data](std::shared_ptr<ubuntu::app_launch::Application> app, std::shared_ptr<ubuntu::app_launch::Application::Instance> instance, std::vector<pid_t>& pids) {
 
672
                                        std::vector<pid_t> lpids = pids;
 
673
                                        lpids.emplace_back(0);
 
674
 
 
675
                                        std::string appid = app->appId();
 
676
 
 
677
                                        executeOnContext(context, [appid, observer, user_data, lpids]() {
 
678
                                                observer(appid.c_str(), (int *)(lpids.data()), user_data);
 
679
                                        });
 
680
                                })
 
681
                        )
 
682
                ));
 
683
 
 
684
        return TRUE;
766
685
}
767
686
 
768
687
gboolean
769
688
ubuntu_app_launch_observer_delete_app_resumed (UbuntuAppLaunchAppPausedResumedObserver observer, gpointer user_data)
770
689
{
771
 
        return paused_resumed_delete(observer, user_data, &resumed_array);
 
690
        auto iter = appResumedObservers.find(std::make_pair(observer, user_data));
 
691
 
 
692
        if (iter == appResumedObservers.end()) {
 
693
                return FALSE;
 
694
        }
 
695
 
 
696
        appResumedObservers.erase(iter);
 
697
        return TRUE;
772
698
}
773
699
 
774
700
typedef void (*per_instance_func_t) (GDBusConnection * con, GVariant * prop_dict, gpointer user_data);