271
272
gpointer user_data;
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;
279
UbuntuAppLaunchAppPausedResumedObserver func;
281
const gchar * lttng_signal;
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;
295
observer_cb (GDBusConnection * conn, const gchar * sender, const gchar * object, const gchar * interface, const gchar * signal, GVariant * params, gpointer user_data)
297
observer_t * observer = (observer_t *)user_data;
299
const gchar * signalname = NULL;
300
g_variant_get_child(params, 0, "&s", &signalname);
302
ual_tracepoint(observer_start, signalname);
305
GVariant * envs = g_variant_get_child_value(params, 1);
307
g_variant_iter_init(&iter, envs);
309
gboolean job_found = FALSE;
310
gboolean job_legacy = FALSE;
311
gchar * instance = NULL;
313
while (g_variant_iter_loop(&iter, "s", &env)) {
314
if (g_strcmp0(env, "JOB=application-click") == 0) {
316
} else if (g_strcmp0(env, "JOB=application-legacy") == 0) {
319
} else if (g_strcmp0(env, "JOB=application-snap") == 0) {
322
} else if (g_str_has_prefix(env, "INSTANCE=")) {
323
instance = g_strdup(env + strlen("INSTANCE="));
327
g_variant_unref(envs);
329
if (job_legacy && instance != NULL) {
330
gchar * dash = g_strrstr(instance, "-");
336
if (job_found && instance != NULL) {
337
observer->func(instance, observer->user_data);
340
ual_tracepoint(observer_finish, signalname);
345
/* Creates the observer structure and registers for the signal with
346
GDBus so that we can get a callback */
348
add_app_generic (UbuntuAppLaunchAppObserver observer, gpointer user_data, const gchar * signal, GList ** list)
350
GDBusConnection * conn = gdbus_upstart_ref();
356
observer_t * observert = g_new0(observer_t, 1);
358
observert->conn = conn;
359
observert->func = observer;
360
observert->user_data = user_data;
362
*list = g_list_prepend(*list, observert);
364
observert->sighandle = g_dbus_connection_signal_subscribe(conn,
366
DBUS_INTERFACE_UPSTART, /* interface */
367
"EventEmitted", /* signal */
368
DBUS_PATH_UPSTART, /* path */
370
G_DBUS_SIGNAL_FLAGS_NONE,
373
NULL); /* user data destroy */
275
/* Function to take a work function and have it execute on a given
277
static void executeOnContext (std::shared_ptr<GMainContext> context, std::function<void()> work)
284
auto heapWork = new std::function<void()>(work);
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(),
289
auto heapWork = static_cast<std::function<void()>*>(data);
291
return G_SOURCE_REMOVE;
295
auto heapWork = static_cast<std::function<void()>*>(data);
299
g_source_attach(source.get(), context.get());
302
/* Map of all the observers listening for app started */
303
static std::map<std::pair<UbuntuAppLaunchAppObserver, gpointer>, core::ScopedConnection> appStartedObservers;
379
306
ubuntu_app_launch_observer_add_app_started (UbuntuAppLaunchAppObserver observer, gpointer user_data)
381
return add_app_generic(observer, user_data, "started", &started_array);
308
auto context = std::shared_ptr<GMainContext>(g_main_context_ref_thread_default(), [](GMainContext * context) { g_clear_pointer(&context, g_main_context_unref); });
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);
326
ubuntu_app_launch_observer_delete_app_started (UbuntuAppLaunchAppObserver observer, gpointer user_data)
328
auto iter = appStartedObservers.find(std::make_pair(observer, user_data));
330
if (iter == appStartedObservers.end()) {
334
appStartedObservers.erase(iter);
338
/* Map of all the observers listening for app stopped */
339
static std::map<std::pair<UbuntuAppLaunchAppObserver, gpointer>, core::ScopedConnection> appStoppedObservers;
385
342
ubuntu_app_launch_observer_add_app_stop (UbuntuAppLaunchAppObserver observer, gpointer user_data)
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); });
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);
390
/* Creates the observer structure and registers for the signal with
391
GDBus so that we can get a callback */
393
add_session_generic (UbuntuAppLaunchAppObserver observer, gpointer user_data, const gchar * signal, GList ** list, GDBusSignalCallback session_cb)
362
ubuntu_app_launch_observer_delete_app_stop (UbuntuAppLaunchAppObserver observer, gpointer user_data)
395
GDBusConnection * conn = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);
364
auto iter = appStoppedObservers.find(std::make_pair(observer, user_data));
366
if (iter == appStoppedObservers.end()) {
401
observer_t * observert = g_new0(observer_t, 1);
403
observert->conn = conn;
404
observert->func = observer;
405
observert->user_data = user_data;
407
*list = g_list_prepend(*list, observert);
409
observert->sighandle = g_dbus_connection_signal_subscribe(conn,
411
"com.canonical.UbuntuAppLaunch", /* interface */
415
G_DBUS_SIGNAL_FLAGS_NONE,
418
NULL); /* user data destroy */
370
appStoppedObservers.erase(iter);
374
class CManager : public ubuntu::app_launch::Registry::Manager
378
g_debug("Creating the CManager object");
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());
387
for (const auto &data : startingList) {
388
executeOnContext(data.context, [data, sappid]() {
389
data.observer(sappid.c_str(), data.user_data);
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());
402
for (const auto &data : focusList) {
403
executeOnContext(data.context, [data, sappid]() {
404
data.observer(sappid.c_str(), data.user_data);
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());
417
for (const auto &data : resumeList) {
418
executeOnContext(data.context, [data, sappid]() {
419
data.observer(sappid.c_str(), data.user_data);
427
struct ObserverData {
428
UbuntuAppLaunchAppObserver observer;
430
std::shared_ptr<GMainContext> context;
432
ObserverData(UbuntuAppLaunchAppObserver obs, gpointer ud)
435
context = std::shared_ptr<GMainContext>(g_main_context_ref_thread_default(), [](GMainContext * context) { g_clear_pointer(&context, g_main_context_unref); });
439
std::list<ObserverData> focusList;
440
std::list<ObserverData> resumeList;
441
std::list<ObserverData> startingList;
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;
448
if (iter == list.end()) {
457
void addFocus (UbuntuAppLaunchAppObserver observer, gpointer user_data) {
458
focusList.emplace_back(ObserverData(observer, user_data));
460
void addResume (UbuntuAppLaunchAppObserver observer, gpointer user_data) {
461
resumeList.emplace_back(ObserverData(observer, user_data));
463
void addStarting (UbuntuAppLaunchAppObserver observer, gpointer user_data) {
464
startingList.emplace_back(ObserverData(observer, user_data));
466
bool deleteFocus (UbuntuAppLaunchAppObserver observer, gpointer user_data) {
467
return removeList(focusList, observer, user_data);
469
bool deleteResume (UbuntuAppLaunchAppObserver observer, gpointer user_data) {
470
return removeList(resumeList, observer, user_data);
472
bool deleteStarting (UbuntuAppLaunchAppObserver observer, gpointer user_data) {
473
return removeList(startingList, observer, user_data);
477
static std::weak_ptr<CManager> cmanager;
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)
436
/* Handle the focus signal when it occurs, call the observer */
438
focus_signal_cb (GDBusConnection * conn, const gchar * sender, const gchar * object, const gchar * interface, const gchar * signal, GVariant * params, gpointer user_data)
440
ual_tracepoint(observer_start, "focus");
442
generic_signal_cb(conn, sender, object, interface, signal, params, user_data);
444
ual_tracepoint(observer_finish, "focus");
448
493
ubuntu_app_launch_observer_add_app_focus (UbuntuAppLaunchAppObserver observer, gpointer user_data)
450
return add_session_generic(observer, user_data, "UnityFocusRequest", &focus_array, focus_signal_cb);
495
auto manager = cmanager.lock();
498
manager = std::make_shared<CManager>();
499
ubuntu::app_launch::Registry::setManager(manager, ubuntu::app_launch::Registry::getDefault());
503
manager->addFocus(observer, user_data);
453
/* Handle the resume signal when it occurs, call the observer, then send a signal back when we're done */
455
resume_signal_cb (GDBusConnection * conn, const gchar * sender, const gchar * object, const gchar * interface, const gchar * signal, GVariant * params, gpointer user_data)
508
ubuntu_app_launch_observer_delete_app_focus (UbuntuAppLaunchAppObserver observer, gpointer user_data)
457
ual_tracepoint(observer_start, "resume");
459
generic_signal_cb(conn, sender, object, interface, signal, params, user_data);
461
GError * error = NULL;
462
g_dbus_connection_emit_signal(conn,
463
sender, /* destination */
465
"com.canonical.UbuntuAppLaunch", /* interface */
466
"UnityResumeResponse", /* signal */
467
params, /* params, the same */
471
g_warning("Unable to emit response signal: %s", error->message);
510
auto manager = cmanager.lock();
475
ual_tracepoint(observer_finish, "resume");
516
return manager->deleteFocus(observer, user_data) ? TRUE : FALSE;
479
520
ubuntu_app_launch_observer_add_app_resume (UbuntuAppLaunchAppObserver observer, gpointer user_data)
481
return add_session_generic(observer, user_data, "UnityResumeRequest", &resume_array, resume_signal_cb);
522
auto manager = cmanager.lock();
525
manager = std::make_shared<CManager>();
526
ubuntu::app_launch::Registry::setManager(manager, ubuntu::app_launch::Registry::getDefault());
530
manager->addResume(observer, user_data);
484
/* Handle the starting signal when it occurs, call the observer, then send a signal back when we're done */
486
starting_signal_cb (GDBusConnection * conn, const gchar * sender, const gchar * object, const gchar * interface, const gchar * signal, GVariant * params, gpointer user_data)
535
ubuntu_app_launch_observer_delete_app_resume (UbuntuAppLaunchAppObserver observer, gpointer user_data)
488
ual_tracepoint(observer_start, "starting");
490
generic_signal_cb(conn, sender, object, interface, signal, params, user_data);
492
GError * error = NULL;
493
g_dbus_connection_emit_signal(conn,
494
sender, /* destination */
496
"com.canonical.UbuntuAppLaunch", /* interface */
497
"UnityStartingSignal", /* signal */
498
params, /* params, the same */
502
g_warning("Unable to emit response signal: %s", error->message);
537
auto manager = cmanager.lock();
506
ual_tracepoint(observer_finish, "starting");
543
return manager->deleteResume(observer, user_data) ? TRUE : FALSE;
510
547
ubuntu_app_launch_observer_add_app_starting (UbuntuAppLaunchAppObserver observer, gpointer user_data)
549
auto manager = cmanager.lock();
552
manager = std::make_shared<CManager>();
553
ubuntu::app_launch::Registry::setManager(manager, ubuntu::app_launch::Registry::getDefault());
512
557
ubuntu::app_launch::Registry::Impl::watchingAppStarting(true);
513
return add_session_generic(observer, user_data, "UnityStartingBroadcast", &starting_array, starting_signal_cb);
516
/* Handle the failed signal when it occurs, call the observer */
518
failed_signal_cb (GDBusConnection * conn, const gchar * sender, const gchar * object, const gchar * interface, const gchar * signal, GVariant * params, gpointer user_data)
520
failed_observer_t * observer = (failed_observer_t *)user_data;
521
const gchar * appid = NULL;
522
const gchar * typestr = NULL;
524
ual_tracepoint(observer_start, "failed");
526
if (observer->func != NULL) {
527
UbuntuAppLaunchAppFailed type = UBUNTU_APP_LAUNCH_APP_FAILED_CRASH;
528
g_variant_get(params, "(&s&s)", &appid, &typestr);
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;
535
g_warning("Application failure type '%s' unknown, reporting as a crash", typestr);
538
observer->func(appid, type, observer->user_data);
541
ual_tracepoint(observer_finish, "failed");
545
ubuntu_app_launch_observer_add_app_failed (UbuntuAppLaunchAppFailedObserver observer, gpointer user_data)
547
GDBusConnection * conn = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);
553
failed_observer_t * observert = g_new0(failed_observer_t, 1);
555
observert->conn = conn;
556
observert->func = observer;
557
observert->user_data = user_data;
559
failed_array = g_list_prepend(failed_array, observert);
561
observert->sighandle = g_dbus_connection_signal_subscribe(conn,
563
"com.canonical.UbuntuAppLaunch", /* interface */
564
"ApplicationFailed", /* signal */
567
G_DBUS_SIGNAL_FLAGS_NONE,
570
NULL); /* user data destroy */
575
/* Handle the paused signal when it occurs, call the observer */
577
paused_signal_cb (GDBusConnection * conn, const gchar * sender, const gchar * object, const gchar * interface, const gchar * signal, GVariant * params, gpointer user_data)
579
paused_resumed_observer_t * observer = (paused_resumed_observer_t *)user_data;
581
ual_tracepoint(observer_start, observer->lttng_signal);
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);
588
GVariantIter thispid;
589
g_variant_iter_init(&thispid, pids);
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);
596
observer->func(g_variant_get_string(appid, NULL), (GPid *)pidarray->data, observer->user_data);
598
g_array_free(pidarray, TRUE);
599
g_variant_unref(appid);
600
g_variant_unref(pids);
603
ual_tracepoint(observer_finish, observer->lttng_signal);
607
paused_resumed_generic (UbuntuAppLaunchAppPausedResumedObserver observer, gpointer user_data, GList ** queue, const gchar * signal_name, const gchar * lttng_signal)
609
GDBusConnection * conn = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);
615
paused_resumed_observer_t * observert = g_new0(paused_resumed_observer_t, 1);
617
observert->conn = conn;
618
observert->func = observer;
619
observert->user_data = user_data;
620
observert->lttng_signal = lttng_signal;
622
*queue = g_list_prepend(*queue, observert);
624
observert->sighandle = g_dbus_connection_signal_subscribe(conn,
626
"com.canonical.UbuntuAppLaunch", /* interface */
627
signal_name, /* signal */
630
G_DBUS_SIGNAL_FLAGS_NONE,
633
NULL); /* user data destroy */
639
ubuntu_app_launch_observer_add_app_paused (UbuntuAppLaunchAppPausedResumedObserver observer, gpointer user_data)
641
return paused_resumed_generic(observer, user_data, &paused_array, "ApplicationPaused", "paused");
645
ubuntu_app_launch_observer_add_app_resumed (UbuntuAppLaunchAppPausedResumedObserver observer, gpointer user_data)
647
return paused_resumed_generic(observer, user_data, &resumed_array, "ApplicationResumed", "resumed");
651
delete_app_generic (UbuntuAppLaunchAppObserver observer, gpointer user_data, GList ** list)
653
observer_t * observert = NULL;
656
for (look = *list; look != NULL; look = g_list_next(look)) {
657
observert = (observer_t *)look->data;
659
if (observert->func == observer && observert->user_data == user_data) {
668
g_dbus_connection_signal_unsubscribe(observert->conn, observert->sighandle);
669
g_object_unref(observert->conn);
672
*list = g_list_delete_link(*list, look);
678
ubuntu_app_launch_observer_delete_app_started (UbuntuAppLaunchAppObserver observer, gpointer user_data)
680
return delete_app_generic(observer, user_data, &started_array);
684
ubuntu_app_launch_observer_delete_app_stop (UbuntuAppLaunchAppObserver observer, gpointer user_data)
686
return delete_app_generic(observer, user_data, &stop_array);
690
ubuntu_app_launch_observer_delete_app_resume (UbuntuAppLaunchAppObserver observer, gpointer user_data)
692
return delete_app_generic(observer, user_data, &resume_array);
696
ubuntu_app_launch_observer_delete_app_focus (UbuntuAppLaunchAppObserver observer, gpointer user_data)
698
return delete_app_generic(observer, user_data, &focus_array);
558
manager->addStarting(observer, user_data);
702
563
ubuntu_app_launch_observer_delete_app_starting (UbuntuAppLaunchAppObserver observer, gpointer user_data)
565
auto manager = cmanager.lock();
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;
575
/* Map of all the observers listening for app stopped */
576
static std::map<std::pair<UbuntuAppLaunchAppFailedObserver, gpointer>, core::ScopedConnection> appFailedObservers;
579
ubuntu_app_launch_observer_add_app_failed (UbuntuAppLaunchAppFailedObserver observer, gpointer user_data)
581
auto context = std::shared_ptr<GMainContext>(g_main_context_ref_thread_default(), [](GMainContext * context) { g_clear_pointer(&context, g_main_context_unref); });
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;
592
case ubuntu::app_launch::Registry::FailureType::CRASH:
593
ctype = UBUNTU_APP_LAUNCH_APP_FAILED_CRASH;
595
case ubuntu::app_launch::Registry::FailureType::START_FAILURE:
596
ctype = UBUNTU_APP_LAUNCH_APP_FAILED_START_FAILURE;
600
observer(appid.c_str(), ctype, user_data);
709
610
ubuntu_app_launch_observer_delete_app_failed (UbuntuAppLaunchAppFailedObserver observer, gpointer user_data)
711
failed_observer_t * observert = NULL;
714
for (look = failed_array; look != NULL; look = g_list_next(look)) {
715
observert = (failed_observer_t *)look->data;
717
if (observert->func == observer && observert->user_data == user_data) {
612
auto iter = appFailedObservers.find(std::make_pair(observer, user_data));
614
if (iter == appFailedObservers.end()) {
726
g_dbus_connection_signal_unsubscribe(observert->conn, observert->sighandle);
727
g_object_unref(observert->conn);
730
failed_array = g_list_delete_link(failed_array, look);
618
appFailedObservers.erase(iter);
736
paused_resumed_delete (UbuntuAppLaunchAppPausedResumedObserver observer, gpointer user_data, GList ** list)
622
static std::map<std::pair<UbuntuAppLaunchAppPausedResumedObserver, gpointer>, core::ScopedConnection> appPausedObservers;
625
ubuntu_app_launch_observer_add_app_paused (UbuntuAppLaunchAppPausedResumedObserver observer, gpointer user_data)
738
paused_resumed_observer_t * observert = NULL;
741
for (look = *list; look != NULL; look = g_list_next(look)) {
742
observert = (paused_resumed_observer_t *)look->data;
744
if (observert->func == observer && observert->user_data == user_data) {
753
g_dbus_connection_signal_unsubscribe(observert->conn, observert->sighandle);
754
g_object_unref(observert->conn);
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); });
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);
636
std::string appid = app->appId();
638
executeOnContext(context, [appid, observer, user_data, lpids]() {
639
observer(appid.c_str(), (int *)(lpids.data()), user_data);