Merge lp:~ted/ubuntu-app-launch/app-object-signals into lp:ubuntu-app-launch/16.10

Proposed by Ted Gould
Status: Superseded
Proposed branch: lp:~ted/ubuntu-app-launch/app-object-signals
Merge into: lp:ubuntu-app-launch/16.10
Diff against target: 3184 lines (+1583/-880)
22 files modified
libubuntu-app-launch/application-impl-libertine.cpp (+1/-2)
libubuntu-app-launch/libubuntu-app-launch.map (+1/-0)
libubuntu-app-launch/registry-impl.cpp (+493/-11)
libubuntu-app-launch/registry-impl.h (+76/-11)
libubuntu-app-launch/registry.cpp (+42/-2)
libubuntu-app-launch/registry.h (+120/-14)
libubuntu-app-launch/ubuntu-app-launch.cpp (+339/-413)
tests/CMakeLists.txt (+1/-0)
tests/failure-test.cc (+123/-96)
tests/libual-cpp-test.cc (+186/-141)
tools/CMakeLists.txt (+21/-2)
tools/ubuntu-app-info.cpp (+18/-9)
tools/ubuntu-app-launch.cpp (+56/-68)
tools/ubuntu-app-list-pids.cpp (+7/-3)
tools/ubuntu-app-list.cpp (+1/-1)
tools/ubuntu-app-pid.cpp (+8/-4)
tools/ubuntu-app-stop.cpp (+7/-3)
tools/ubuntu-app-triplet.cpp (+1/-1)
tools/ubuntu-app-watch.cpp (+61/-88)
tools/ubuntu-helper-list.cpp (+1/-1)
tools/ubuntu-helper-start.cpp (+10/-5)
tools/ubuntu-helper-stop.cpp (+10/-5)
To merge this branch: bzr merge lp:~ted/ubuntu-app-launch/app-object-signals
Reviewer Review Type Date Requested Status
PS Jenkins bot (community) continuous-integration Needs Fixing
Indicator Applet Developers Pending
Review via email: mp+294807@code.launchpad.net

This proposal supersedes a proposal from 2016-02-08.

This proposal has been superseded by a proposal from 2016-11-07.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

FAILED: Continuous integration, rev:232
No commit message was specified in the merge proposal. Click on the following link and set the commit message (if you want a jenkins rebuild you need to trigger it yourself):
https://code.launchpad.net/~ted/ubuntu-app-launch/app-object-signals/+merge/294807/+edit-commit-message

http://jenkins.qa.ubuntu.com/job/ubuntu-app-launch-ci/55/
Executed test runs:
    FAILURE: http://jenkins.qa.ubuntu.com/job/ubuntu-app-launch-wily-amd64-ci/55/console
    FAILURE: http://jenkins.qa.ubuntu.com/job/ubuntu-app-launch-wily-armhf-ci/55/console
    FAILURE: http://jenkins.qa.ubuntu.com/job/ubuntu-app-launch-wily-i386-ci/55/console

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/ubuntu-app-launch-ci/55/rebuild

review: Needs Fixing (continuous-integration)
234. By Ted Gould

Updated to trunk

235. By Ted Gould

Make the signal access functions

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

FAILED: Continuous integration, rev:234
No commit message was specified in the merge proposal. Click on the following link and set the commit message (if you want a jenkins rebuild you need to trigger it yourself):
https://code.launchpad.net/~ted/ubuntu-app-launch/app-object-signals/+merge/294807/+edit-commit-message

http://jenkins.qa.ubuntu.com/job/ubuntu-app-launch-ci/56/
Executed test runs:
    SUCCESS: http://jenkins.qa.ubuntu.com/job/ubuntu-app-launch-wily-amd64-ci/56
    SUCCESS: http://jenkins.qa.ubuntu.com/job/ubuntu-app-launch-wily-armhf-ci/56
    SUCCESS: http://jenkins.qa.ubuntu.com/job/ubuntu-app-launch-wily-i386-ci/56

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/ubuntu-app-launch-ci/56/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

FAILED: Continuous integration, rev:235
No commit message was specified in the merge proposal. Click on the following link and set the commit message (if you want a jenkins rebuild you need to trigger it yourself):
https://code.launchpad.net/~ted/ubuntu-app-launch/app-object-signals/+merge/294807/+edit-commit-message

http://jenkins.qa.ubuntu.com/job/ubuntu-app-launch-ci/57/
Executed test runs:
    SUCCESS: http://jenkins.qa.ubuntu.com/job/ubuntu-app-launch-wily-amd64-ci/57
    SUCCESS: http://jenkins.qa.ubuntu.com/job/ubuntu-app-launch-wily-armhf-ci/57
    SUCCESS: http://jenkins.qa.ubuntu.com/job/ubuntu-app-launch-wily-i386-ci/57

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/ubuntu-app-launch-ci/57/rebuild

review: Needs Fixing (continuous-integration)
236. By Ted Gould

Adding in stubs to bring out the implementation

237. By Ted Gould

Merging trunk

238. By Ted Gould

Move the signal functions into the implementation

239. By Ted Gould

Building a place to register signals

240. By Ted Gould

Code up starting and stopping, some TODOs

241. By Ted Gould

Port over app started and stopped to C++ interfaces

242. By Ted Gould

Switch to passing in the shared pointer to the registry

243. By Ted Gould

Make sure to grab a copy of the shared pointer

244. By Ted Gould

Move the greed around in our regex

245. By Ted Gould

Switching to a weak pointer

246. By Ted Gould

Make calls with the C library use the current context to not break existing code.

247. By Ted Gould

Moving over pause/resume

248. By Ted Gould

Fixing the watcher

249. By Ted Gould

Migrating over the failed signal

250. By Ted Gould

Apply formatting rules to tools

251. By Ted Gould

Print pids for pause/resume

252. By Ted Gould

Basic foundation for manager signals

253. By Ted Gould

Start to flesh out more of the resume request

254. By Ted Gould

Restructure to use more shared pointers

255. By Ted Gould

Switch the C code to using the manager interface

256. By Ted Gould

Fleshing out the focus handler

257. By Ted Gould

Add a handler for starting

258. By Ted Gould

Refactor into a shared function to do the longer dbus calls

259. By Ted Gould

Restructure so that we can call the right signal

260. By Ted Gould

Make it so that the manager observers execute on their context

261. By Ted Gould

Switch to using a global weak pointer so that it expires with the tracking of the Registry object

262. By Ted Gould

Clean up weak_ptr<> code

263. By Ted Gould

Make sure we wait to install the signals before returning

264. By Ted Gould

Put a warning in about thread safety

265. By Ted Gould

Port tests over to using a manager for focus events

266. By Ted Gould

Fixing the start and stop observer test

267. By Ted Gould

Fix the starting test

268. By Ted Gould

Failing test ported over

269. By Ted Gould

Documentation for registry functions

270. By Ted Gould

More comments

271. By Ted Gould

Variable comments

272. By Ted Gould

A comment on why this comment is there

273. By Ted Gould

Switch failure test over to using the C++ api

274. By Ted Gould

Making sure we connect the signals before returnning

275. By Ted Gould

Fix failure test environment and values to make them work as real applications

276. By Ted Gould

Apply formatting rules to failure-test.cc

277. By Ted Gould

Make gcc6 happy

278. By Ted Gould

Putting additional checks in to make sure we don't use null pointers we don't get locks on.

279. By Ted Gould

Ensure the manager thread shutsdown before the registry to avoid a deadlock

280. By Ted Gould

Merge future trunk

281. By Ted Gould

Remove some of the sing song part of the comments

282. By Ted Gould

Additional comment on lifecycle of replies

283. By Ted Gould

Zesty formatting tools diffs

284. By Ted Gould

Curly init

285. By Ted Gould

Make sure to check for a nullappid or error for g_variant_get()

286. By Ted Gould

Names of the parameters for clarity

287. By Ted Gould

Moar auto!

288. By Ted Gould

Don't specify returning void explicitly

289. By Ted Gould

Use static_cast() for void* casts

290. By Ted Gould

Don't spell well

291. By Ted Gould

Make sure to check for a valid registry

292. By Ted Gould

Comment out unused variables

293. By Ted Gould

Sometimes life would be better if it was more constant

294. By Ted Gould

Me no spell good

295. By Ted Gould

auto auto auto

296. By Ted Gould

Some 'NULL's crept in

297. By Ted Gould

More auto's with GVariants

298. By Ted Gould

Make params constant

299. By Ted Gould

Change setManager to have const& parameters

300. By Ted Gould

Fix the API so that the signal callbacks take pointers

301. By Ted Gould

Note it is on the UAL thread only

302. By Ted Gould

Save some stack data with this context

303. By Ted Gould

Formatting fix

304. By Ted Gould

Use an ensure_cmanager() helper to remove duplicate code

305. By Ted Gould

Putting all the map handling code in a couple templates

306. By Ted Gould

Pull out the request code into individual functions

307. By Ted Gould

Rename a function and add comments

308. By Ted Gould

Expand the usage of observer_delete

309. By Ted Gould

Factor out pause/resume commonality

310. By Ted Gould

I've been overrided by charles

311. By Ted Gould

Update to trunk

312. By Ted Gould

Adding virtual destructors, acc says they're fine.

313. By Ted Gould

Putting this off for gcc 5.4

314. By Ted Gould

Block off more API breaks this time

Unmerged revisions

314. By Ted Gould

Block off more API breaks this time

313. By Ted Gould

Putting this off for gcc 5.4

312. By Ted Gould

Adding virtual destructors, acc says they're fine.

311. By Ted Gould

Update to trunk

310. By Ted Gould

I've been overrided by charles

309. By Ted Gould

Factor out pause/resume commonality

308. By Ted Gould

Expand the usage of observer_delete

307. By Ted Gould

Rename a function and add comments

306. By Ted Gould

Pull out the request code into individual functions

305. By Ted Gould

Putting all the map handling code in a couple templates

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'libubuntu-app-launch/application-impl-libertine.cpp'
--- libubuntu-app-launch/application-impl-libertine.cpp 2016-10-03 23:54:20 +0000
+++ libubuntu-app-launch/application-impl-libertine.cpp 2016-11-07 20:56:13 +0000
@@ -255,8 +255,7 @@
255 }255 }
256 catch (std::runtime_error& e)256 catch (std::runtime_error& e)
257 {257 {
258 g_debug("Unable to create application for libertine appname '%s': %s",258 g_debug("Unable to create application for libertine appname '%s': %s", apps.get()[j], e.what());
259 apps.get()[j], e.what());
260 }259 }
261 }260 }
262 }261 }
263262
=== modified file 'libubuntu-app-launch/libubuntu-app-launch.map'
--- libubuntu-app-launch/libubuntu-app-launch.map 2016-05-19 16:24:11 +0000
+++ libubuntu-app-launch/libubuntu-app-launch.map 2016-11-07 20:56:13 +0000
@@ -14,6 +14,7 @@
14 ubuntu::app_launch::Helper::*;14 ubuntu::app_launch::Helper::*;
15 typeinfo?for?ubuntu::app_launch::Helper;15 typeinfo?for?ubuntu::app_launch::Helper;
16 typeinfo?name?for?ubuntu::app_launch::Helper;16 typeinfo?name?for?ubuntu::app_launch::Helper;
17 ubuntu::app_launch::operator*;
17 ubuntu::app_launch::oom::*;18 ubuntu::app_launch::oom::*;
18 };19 };
19local:20local:
2021
=== modified file 'libubuntu-app-launch/registry-impl.cpp'
--- libubuntu-app-launch/registry-impl.cpp 2016-09-23 22:30:51 +0000
+++ libubuntu-app-launch/registry-impl.cpp 2016-11-07 20:56:13 +0000
@@ -20,6 +20,7 @@
20#include "registry-impl.h"20#include "registry-impl.h"
21#include "application-icon-finder.h"21#include "application-icon-finder.h"
22#include <cgmanager/cgmanager.h>22#include <cgmanager/cgmanager.h>
23#include <regex>
23#include <upstart.h>24#include <upstart.h>
2425
25namespace ubuntu26namespace ubuntu
@@ -36,13 +37,29 @@
36 zgLog_.reset();37 zgLog_.reset();
37 cgManager_.reset();38 cgManager_.reset();
3839
40 auto dohandle = [&](guint& handle) {
41 if (handle != 0)
42 {
43 g_dbus_connection_signal_unsubscribe(_dbus.get(), handle);
44 handle = 0;
45 }
46 };
47
48 dohandle(handle_appStarted);
49 dohandle(handle_appStopped);
50 dohandle(handle_appFailed);
51 dohandle(handle_appPaused);
52 dohandle(handle_appResumed);
53 dohandle(handle_managerSignalFocus);
54 dohandle(handle_managerSignalResume);
55 dohandle(handle_managerSignalStarting);
56
39 if (_dbus)57 if (_dbus)
40 g_dbus_connection_flush_sync(_dbus.get(), nullptr, nullptr);58 g_dbus_connection_flush_sync(_dbus.get(), nullptr, nullptr);
41 _dbus.reset();59 _dbus.reset();
42 })60 })
43 , _registry(registry)61 , _registry(registry)
44 , _iconFinders()62 , _iconFinders()
45// _manager(nullptr)
46{63{
47 auto cancel = thread.getCancellable();64 auto cancel = thread.getCancellable();
48 _dbus = thread.executeOnThread<std::shared_ptr<GDBusConnection>>([cancel]() {65 _dbus = thread.executeOnThread<std::shared_ptr<GDBusConnection>>([cancel]() {
@@ -536,24 +553,193 @@
536 return _iconFinders[basePath];553 return _iconFinders[basePath];
537}554}
538555
539#if 0556/** Structure to track the data needed for upstart events. This cleans
540void557 up the lifecycle as we're passing this as a pointer through the
541Registry::Impl::setManager (Registry::Manager* manager)558 GLib calls. */
542{559struct upstartEventData
543 if (_manager != nullptr)560{
561 /** Keeping a weak pointer because the handle is held by
562 the registry implementation. */
563 std::weak_ptr<Registry> weakReg;
564};
565
566/** Take the GVariant of parameters and turn them into an application and
567 and instance. Easier to read in the smaller function */
568std::tuple<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>> Registry::Impl::managerParams(
569 const std::shared_ptr<GVariant>& params, const std::shared_ptr<Registry>& reg)
570{
571 std::shared_ptr<Application> app;
572 std::shared_ptr<Application::Instance> instance;
573
574 const gchar* cappid = nullptr;
575 g_variant_get(params.get(), "(&s)", &cappid);
576
577 auto appid = ubuntu::app_launch::AppID::find(reg, cappid);
578 app = ubuntu::app_launch::Application::create(appid, reg);
579
580 return std::make_tuple(app, instance);
581}
582
583/** Used to store data for manager based signal handlers. Has a link to the
584 registry and the callback to use in a C++ style. */
585struct managerEventData
586{
587 /* Keeping a weak pointer because the handle is held by
588 the registry implementation. */
589 std::weak_ptr<Registry> weakReg;
590 std::function<void(const std::shared_ptr<Registry>& reg,
591 const std::shared_ptr<Application>& app,
592 const std::shared_ptr<Application::Instance>& instance,
593 const std::shared_ptr<GDBusConnection>&,
594 const std::string&,
595 const std::shared_ptr<GVariant>&)>
596 func;
597};
598
599/** Register for a signal for the manager. All of the signals needed this same
600 code so it got pulled out into a function. Takes the same of the signal, the registry
601 that we're using and a function to call after we've messaged all the parameters
602 into being something C++-ish. */
603guint Registry::Impl::managerSignalHelper(const std::shared_ptr<Registry>& reg,
604 const std::string& signalname,
605 std::function<void(const std::shared_ptr<Registry>& reg,
606 const std::shared_ptr<Application>& app,
607 const std::shared_ptr<Application::Instance>& instance,
608 const std::shared_ptr<GDBusConnection>&,
609 const std::string&,
610 const std::shared_ptr<GVariant>&)> responsefunc)
611{
612 managerEventData* focusdata = new managerEventData{reg, responsefunc};
613
614 return g_dbus_connection_signal_subscribe(
615 reg->impl->_dbus.get(), /* bus */
616 nullptr, /* sender */
617 "com.canonical.UbuntuAppLaunch", /* interface */
618 signalname.c_str(), /* signal */
619 "/", /* path */
620 nullptr, /* arg0 */
621 G_DBUS_SIGNAL_FLAGS_NONE,
622 [](GDBusConnection* cconn, const gchar* csender, const gchar*, const gchar*, const gchar*, GVariant* params,
623 gpointer user_data) -> void {
624 auto data = reinterpret_cast<managerEventData*>(user_data);
625 auto reg = data->weakReg.lock();
626
627 /* If we're still conneted and the manager has been cleared
628 we'll just be a no-op */
629 if (!reg->impl->manager_)
630 {
631 return;
632 }
633
634 auto vparams = std::shared_ptr<GVariant>(g_variant_ref(params), g_variant_unref);
635 auto conn = std::shared_ptr<GDBusConnection>(reinterpret_cast<GDBusConnection*>(g_object_ref(cconn)),
636 [](GDBusConnection* con) { g_clear_object(&con); });
637 std::string sender = csender;
638 std::shared_ptr<Application> app;
639 std::shared_ptr<Application::Instance> instance;
640
641 std::tie(app, instance) = managerParams(vparams, reg);
642
643 data->func(reg, app, instance, conn, sender, vparams);
644 },
645 focusdata,
646 [](gpointer user_data) {
647 auto data = reinterpret_cast<managerEventData*>(user_data);
648 delete data;
649 }); /* user data destroy */
650}
651
652/** Set the manager for the registry. This includes tracking the pointer
653 as well as setting up the signals to call back into the manager. The
654 signals are only setup once per registry even if the manager is cleared
655 and changed again. They will just be no-op's in those cases.
656*/
657void Registry::Impl::setManager(std::shared_ptr<Registry::Manager> manager, std::shared_ptr<Registry> reg)
658{
659 if (reg->impl->manager_)
544 {660 {
545 throw std::runtime_error("Already have a manager and trying to set another");661 throw std::runtime_error("Already have a manager and trying to set another");
546 }662 }
547663
548 _manager = manager;664 g_debug("Setting a new manager");
665 reg->impl->manager_ = manager;
666
667 std::call_once(reg->impl->flag_managerSignals, [reg]() {
668 if (!reg->impl->thread.executeOnThread<bool>([reg]() {
669 reg->impl->handle_managerSignalFocus = managerSignalHelper(
670 reg, "UnityFocusRequest",
671 [](const std::shared_ptr<Registry>& reg, const std::shared_ptr<Application>& app,
672 const std::shared_ptr<Application::Instance>& instance,
673 const std::shared_ptr<GDBusConnection>& conn, const std::string& sender,
674 const std::shared_ptr<GVariant>& params) {
675 /* Nothing to do today */
676 reg->impl->manager_->focusRequest(app, instance, [](bool response) {
677 /* NOTE: We have no clue what thread this is gonna be
678 executed on, but since we're just talking to the GDBus
679 thread it isn't an issue today. Be careful in changing
680 this code. */
681 });
682 });
683 reg->impl->handle_managerSignalStarting = managerSignalHelper(
684 reg, "UnityStartingBroadcast",
685 [](const std::shared_ptr<Registry>& reg, const std::shared_ptr<Application>& app,
686 const std::shared_ptr<Application::Instance>& instance,
687 const std::shared_ptr<GDBusConnection>& conn, const std::string& sender,
688 const std::shared_ptr<GVariant>& params) {
689
690 reg->impl->manager_->startingRequest(app, instance, [conn, sender, params](bool response) {
691 /* NOTE: We have no clue what thread this is gonna be
692 executed on, but since we're just talking to the GDBus
693 thread it isn't an issue today. Be careful in changing
694 this code. */
695 if (response)
696 {
697 g_dbus_connection_emit_signal(conn.get(), sender.c_str(), /* destination */
698 "/", /* path */
699 "com.canonical.UbuntuAppLaunch", /* interface */
700 "UnityStartingSignal", /* signal */
701 params.get(), /* params, the same */
702 nullptr); /* error */
703 }
704 });
705 });
706 reg->impl->handle_managerSignalResume = managerSignalHelper(
707 reg, "UnityResumeRequest",
708 [](const std::shared_ptr<Registry>& reg, const std::shared_ptr<Application>& app,
709 const std::shared_ptr<Application::Instance>& instance,
710 const std::shared_ptr<GDBusConnection>& conn, const std::string& sender,
711 const std::shared_ptr<GVariant>& params) {
712 reg->impl->manager_->resumeRequest(app, instance, [conn, sender, params](bool response) {
713 /* NOTE: We have no clue what thread this is gonna be
714 executed on, but since we're just talking to the GDBus
715 thread it isn't an issue today. Be careful in changing
716 this code. */
717 if (response)
718 {
719 g_dbus_connection_emit_signal(conn.get(), sender.c_str(), /* destination */
720 "/", /* path */
721 "com.canonical.UbuntuAppLaunch", /* interface */
722 "UnityResumeResponse", /* signal */
723 params.get(), /* params, the same */
724 nullptr); /* error */
725 }
726 });
727 });
728
729 return true;
730 }))
731 {
732 g_warning("Unable to install manager signals");
733 }
734 });
549}735}
550736
551void737/** Clear the manager pointer */
552Registry::Impl::clearManager ()738void Registry::Impl::clearManager()
553{739{
554 _manager = nullptr;740 g_debug("Clearing the manager");
741 manager_.reset();
555}742}
556#endif
557743
558/** App start watching, if we're registered for the signal we744/** App start watching, if we're registered for the signal we
559 can't wait on it. We are making this static right now because745 can't wait on it. We are making this static right now because
@@ -576,5 +762,301 @@
576 return watchingAppStarting_;762 return watchingAppStarting_;
577}763}
578764
765/** Regex to parse the JOB environment variable from Upstart */
766std::regex jobenv_regex{"^JOB=(application\\-(?:click|snap|legacy))$"};
767/** Regex to parse the INSTANCE environment variable from Upstart */
768std::regex instanceenv_regex{"^INSTANCE=(.*?)(?:\\-([0-9]*))?+$"};
769
770/** Core of most of the events that come from Upstart directly. Includes parsing of the
771 Upstart event environment and calling the appropriate signal with the right Application
772 object and eventually its instance */
773void Registry::Impl::upstartEventEmitted(
774 core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>>& signal,
775 std::shared_ptr<GVariant> params,
776 const std::shared_ptr<Registry>& reg)
777{
778 std::string jobname;
779 std::string sappid;
780 std::string instance;
781
782 gchar* env = nullptr;
783 GVariant* envs = g_variant_get_child_value(params.get(), 1);
784 GVariantIter iter;
785 g_variant_iter_init(&iter, envs);
786
787 while (g_variant_iter_loop(&iter, "s", &env))
788 {
789 std::smatch match;
790 std::string senv = env;
791
792 if (std::regex_match(senv, match, jobenv_regex))
793 {
794 jobname = match[1].str();
795 }
796 else if (std::regex_match(senv, match, instanceenv_regex))
797 {
798 sappid = match[1].str();
799 instance = match[2].str();
800 }
801 }
802
803 g_variant_unref(envs);
804
805 if (jobname.empty())
806 {
807 return;
808 }
809
810 g_debug("Upstart Event for job '%s' appid '%s' instance '%s'", jobname.c_str(), sappid.c_str(), instance.c_str());
811
812 auto appid = AppID::find(reg, sappid);
813 auto app = Application::create(appid, reg);
814
815 // TODO: Figure otu creating instances
816
817 signal(app, {});
818}
819
820/** Grab the signal object for application startup. If we're not already listing for
821 those signals this sets up a listener for them. */
822core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>>& Registry::Impl::appStarted(
823 const std::shared_ptr<Registry>& reg)
824{
825 std::call_once(flag_appStarted, [reg]() {
826 reg->impl->thread.executeOnThread<bool>([reg]() {
827 upstartEventData* data = new upstartEventData{reg};
828
829 reg->impl->handle_appStarted = g_dbus_connection_signal_subscribe(
830 reg->impl->_dbus.get(), /* bus */
831 nullptr, /* sender */
832 DBUS_INTERFACE_UPSTART, /* interface */
833 "EventEmitted", /* signal */
834 DBUS_PATH_UPSTART, /* path */
835 "started", /* arg0 */
836 G_DBUS_SIGNAL_FLAGS_NONE,
837 [](GDBusConnection*, const gchar*, const gchar*, const gchar*, const gchar*, GVariant* params,
838 gpointer user_data) -> void {
839 auto data = reinterpret_cast<upstartEventData*>(user_data);
840 auto reg = data->weakReg.lock();
841 auto sparams = std::shared_ptr<GVariant>(g_variant_ref(params), g_variant_unref);
842 reg->impl->upstartEventEmitted(reg->impl->sig_appStarted, sparams, reg);
843 }, /* callback */
844 data, /* user data */
845 [](gpointer user_data) {
846 auto data = reinterpret_cast<upstartEventData*>(user_data);
847 delete data;
848 }); /* user data destroy */
849
850 return true;
851 });
852 });
853
854 return sig_appStarted;
855}
856
857/** Grab the signal object for application stopping. If we're not already listing for
858 those signals this sets up a listener for them. */
859core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>>& Registry::Impl::appStopped(
860 const std::shared_ptr<Registry>& reg)
861{
862 std::call_once(flag_appStopped, [reg]() {
863 reg->impl->thread.executeOnThread<bool>([reg]() {
864 upstartEventData* data = new upstartEventData{reg};
865
866 reg->impl->handle_appStopped = g_dbus_connection_signal_subscribe(
867 reg->impl->_dbus.get(), /* bus */
868 nullptr, /* sender */
869 DBUS_INTERFACE_UPSTART, /* interface */
870 "EventEmitted", /* signal */
871 DBUS_PATH_UPSTART, /* path */
872 "stopped", /* arg0 */
873 G_DBUS_SIGNAL_FLAGS_NONE,
874 [](GDBusConnection*, const gchar*, const gchar*, const gchar*, const gchar*, GVariant* params,
875 gpointer user_data) -> void {
876 auto data = reinterpret_cast<upstartEventData*>(user_data);
877 auto reg = data->weakReg.lock();
878 auto sparams = std::shared_ptr<GVariant>(g_variant_ref(params), g_variant_unref);
879 reg->impl->upstartEventEmitted(reg->impl->sig_appStopped, sparams, reg);
880 }, /* callback */
881 data, /* user data */
882 [](gpointer user_data) {
883 auto data = reinterpret_cast<upstartEventData*>(user_data);
884 delete data;
885 }); /* user data destroy */
886
887 return true;
888 });
889 });
890
891 return sig_appStopped;
892}
893
894/** Grab the signal object for application failing. If we're not already listing for
895 those signals this sets up a listener for them. */
896core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>, Registry::FailureType>&
897 Registry::Impl::appFailed(const std::shared_ptr<Registry>& reg)
898{
899 std::call_once(flag_appFailed, [reg]() {
900 reg->impl->thread.executeOnThread<bool>([reg]() {
901 upstartEventData* data = new upstartEventData{reg};
902
903 reg->impl->handle_appFailed = g_dbus_connection_signal_subscribe(
904 reg->impl->_dbus.get(), /* bus */
905 nullptr, /* sender */
906 "com.canonical.UbuntuAppLaunch", /* interface */
907 "ApplicationFailed", /* signal */
908 "/", /* path */
909 nullptr, /* arg0 */
910 G_DBUS_SIGNAL_FLAGS_NONE,
911 [](GDBusConnection*, const gchar*, const gchar*, const gchar*, const gchar*, GVariant* params,
912 gpointer user_data) -> void {
913 auto data = reinterpret_cast<upstartEventData*>(user_data);
914 auto reg = data->weakReg.lock();
915
916 const gchar* sappid = NULL;
917 const gchar* typestr = NULL;
918
919 Registry::FailureType type = Registry::FailureType::CRASH;
920 g_variant_get(params, "(&s&s)", &sappid, &typestr);
921
922 if (g_strcmp0("crash", typestr) == 0)
923 {
924 type = Registry::FailureType::CRASH;
925 }
926 else if (g_strcmp0("start-failure", typestr) == 0)
927 {
928 type = Registry::FailureType::START_FAILURE;
929 }
930 else
931 {
932 g_warning("Application failure type '%s' unknown, reporting as a crash", typestr);
933 }
934
935 auto appid = AppID::find(reg, sappid);
936 auto app = Application::create(appid, reg);
937
938 /* TODO: Instance issues */
939
940 reg->impl->sig_appFailed(app, {}, type);
941 }, /* callback */
942 data, /* user data */
943 [](gpointer user_data) {
944 auto data = reinterpret_cast<upstartEventData*>(user_data);
945 delete data;
946 }); /* user data destroy */
947
948 return true;
949 });
950 });
951
952 return sig_appFailed;
953}
954
955/** Core handler for pause and resume events. Includes turning the GVariant
956 pid list into a std::vector and getting the application object. */
957void Registry::Impl::pauseEventEmitted(
958 core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>, std::vector<pid_t>&>& signal,
959 const std::shared_ptr<GVariant>& params,
960 const std::shared_ptr<Registry>& reg)
961{
962 std::vector<pid_t> pids;
963 GVariant* vappid = g_variant_get_child_value(params.get(), 0);
964 GVariant* vpids = g_variant_get_child_value(params.get(), 1);
965 guint64 pid;
966 GVariantIter thispid;
967 g_variant_iter_init(&thispid, vpids);
968
969 while (g_variant_iter_loop(&thispid, "t", &pid))
970 {
971 pids.emplace_back(pid);
972 }
973
974 auto cappid = g_variant_get_string(vappid, NULL);
975 auto appid = ubuntu::app_launch::AppID::find(reg, cappid);
976 auto app = Application::create(appid, reg);
977
978 /* TODO: Instance */
979 signal(app, {}, pids);
980
981 g_variant_unref(vappid);
982 g_variant_unref(vpids);
983
984 return;
985}
986
987/** Grab the signal object for application paused. If we're not already listing for
988 those signals this sets up a listener for them. */
989core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>, std::vector<pid_t>&>&
990 Registry::Impl::appPaused(const std::shared_ptr<Registry>& reg)
991{
992 std::call_once(flag_appPaused, [&]() {
993 reg->impl->thread.executeOnThread<bool>([reg]() {
994 upstartEventData* data = new upstartEventData{reg};
995
996 reg->impl->handle_appPaused = g_dbus_connection_signal_subscribe(
997 reg->impl->_dbus.get(), /* bus */
998 nullptr, /* sender */
999 "com.canonical.UbuntuAppLaunch", /* interface */
1000 "ApplicationPaused", /* signal */
1001 "/", /* path */
1002 nullptr, /* arg0 */
1003 G_DBUS_SIGNAL_FLAGS_NONE,
1004 [](GDBusConnection*, const gchar*, const gchar*, const gchar*, const gchar*, GVariant* params,
1005 gpointer user_data) -> void {
1006 auto data = reinterpret_cast<upstartEventData*>(user_data);
1007 auto reg = data->weakReg.lock();
1008 auto sparams = std::shared_ptr<GVariant>(g_variant_ref(params), g_variant_unref);
1009 reg->impl->pauseEventEmitted(reg->impl->sig_appPaused, sparams, reg);
1010 }, /* callback */
1011 data, /* user data */
1012 [](gpointer user_data) {
1013 auto data = reinterpret_cast<upstartEventData*>(user_data);
1014 delete data;
1015 }); /* user data destroy */
1016
1017 return true;
1018 });
1019 });
1020
1021 return sig_appPaused;
1022}
1023
1024/** Grab the signal object for application resumed. If we're not already listing for
1025 those signals this sets up a listener for them. */
1026core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>, std::vector<pid_t>&>&
1027 Registry::Impl::appResumed(const std::shared_ptr<Registry>& reg)
1028{
1029 std::call_once(flag_appResumed, [&]() {
1030 reg->impl->thread.executeOnThread<bool>([reg]() {
1031 upstartEventData* data = new upstartEventData{reg};
1032
1033 reg->impl->handle_appResumed = g_dbus_connection_signal_subscribe(
1034 reg->impl->_dbus.get(), /* bus */
1035 nullptr, /* sender */
1036 "com.canonical.UbuntuAppLaunch", /* interface */
1037 "ApplicationResumed", /* signal */
1038 "/", /* path */
1039 nullptr, /* arg0 */
1040 G_DBUS_SIGNAL_FLAGS_NONE,
1041 [](GDBusConnection*, const gchar*, const gchar*, const gchar*, const gchar*, GVariant* params,
1042 gpointer user_data) -> void {
1043 auto data = reinterpret_cast<upstartEventData*>(user_data);
1044 auto reg = data->weakReg.lock();
1045 auto sparams = std::shared_ptr<GVariant>(g_variant_ref(params), g_variant_unref);
1046 reg->impl->pauseEventEmitted(reg->impl->sig_appResumed, sparams, reg);
1047 }, /* callback */
1048 data, /* user data */
1049 [](gpointer user_data) {
1050 auto data = reinterpret_cast<upstartEventData*>(user_data);
1051 delete data;
1052 }); /* user data destroy */
1053
1054 return true;
1055 });
1056 });
1057
1058 return sig_appResumed;
1059}
1060
579} // namespace app_launch1061} // namespace app_launch
580} // namespace ubuntu1062} // namespace ubuntu
5811063
=== modified file 'libubuntu-app-launch/registry-impl.h'
--- libubuntu-app-launch/registry-impl.h 2016-09-23 22:30:51 +0000
+++ libubuntu-app-launch/registry-impl.h 2016-11-07 20:56:13 +0000
@@ -53,10 +53,8 @@
53 std::list<AppID::Package> getClickPackages();53 std::list<AppID::Package> getClickPackages();
54 std::string getClickDir(const std::string& package);54 std::string getClickDir(const std::string& package);
5555
56#if 056 static void setManager(std::shared_ptr<Registry::Manager> manager, std::shared_ptr<Registry> registry);
57 void setManager (Registry::Manager* manager);57 void clearManager();
58 void clearManager ();
59#endif
6058
61 /** Shared context thread for events and background tasks59 /** Shared context thread for events and background tasks
62 that UAL subtasks are doing */60 that UAL subtasks are doing */
@@ -82,6 +80,18 @@
82 static std::string printJson(std::shared_ptr<JsonObject> jsonobj);80 static std::string printJson(std::shared_ptr<JsonObject> jsonobj);
83 static std::string printJson(std::shared_ptr<JsonNode> jsonnode);81 static std::string printJson(std::shared_ptr<JsonNode> jsonnode);
8482
83 /* Signals to discover what is happening to apps */
84 core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>>& appStarted(
85 const std::shared_ptr<Registry>& reg);
86 core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>>& appStopped(
87 const std::shared_ptr<Registry>& reg);
88 core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>, FailureType>& appFailed(
89 const std::shared_ptr<Registry>& reg);
90 core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>, std::vector<pid_t>&>& appPaused(
91 const std::shared_ptr<Registry>& reg);
92 core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>, std::vector<pid_t>&>& appResumed(
93 const std::shared_ptr<Registry>& reg);
94
85 /* Signal Hints */95 /* Signal Hints */
86 /* NOTE: Static because we don't have registry instances in the C96 /* NOTE: Static because we don't have registry instances in the C
87 code right now. We want these to not be static in the future */97 code right now. We want these to not be static in the future */
@@ -89,22 +99,77 @@
89 static bool isWatchingAppStarting();99 static bool isWatchingAppStarting();
90100
91private:101private:
92 Registry* _registry;102 Registry* _registry; /**< The Registry that we're spawned from */
93#if 0103 std::shared_ptr<Registry::Manager> manager_; /**< Application manager if registered */
94 Registry::Manager* _manager;104
95#endif105 std::shared_ptr<ClickDB> _clickDB; /**< Shared instance of the Click Database */
96106 std::shared_ptr<ClickUser> _clickUser; /**< Click database filtered by the current user */
97 std::shared_ptr<ClickDB> _clickDB;107
98 std::shared_ptr<ClickUser> _clickUser;108 /** Signal object for applications started */
109 core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>> sig_appStarted;
110 /** Signal object for applications stopped */
111 core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>> sig_appStopped;
112 /** Signal object for applications failed */
113 core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>, FailureType> sig_appFailed;
114 /** Signal object for applications paused */
115 core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>, std::vector<pid_t>&>
116 sig_appPaused;
117 /** Signal object for applications resumed */
118 core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>, std::vector<pid_t>&>
119 sig_appResumed;
120
121 guint handle_appStarted{0}; /**< GDBus signal watcher handle for app started signal */
122 guint handle_appStopped{0}; /**< GDBus signal watcher handle for app stopped signal */
123 guint handle_appFailed{0}; /**< GDBus signal watcher handle for app failed signal */
124 guint handle_appPaused{0}; /**< GDBus signal watcher handle for app paused signal */
125 guint handle_appResumed{0}; /**< GDBus signal watcher handle for app resumed signal */
126 guint handle_managerSignalFocus{0}; /**< GDBus signal watcher handle for app focused signal */
127 guint handle_managerSignalResume{0}; /**< GDBus signal watcher handle for app resumed signal */
128 guint handle_managerSignalStarting{0}; /**< GDBus signal watcher handle for app starting signal */
129
130 std::once_flag flag_appStarted; /**< Variable to track to see if signal handlers are installed for application
131 started */
132 std::once_flag flag_appStopped; /**< Variable to track to see if signal handlers are installed for application
133 stopped */
134 std::once_flag
135 flag_appFailed; /**< Variable to track to see if signal handlers are installed for application failed */
136 std::once_flag
137 flag_appPaused; /**< Variable to track to see if signal handlers are installed for application paused */
138 std::once_flag flag_appResumed; /**< Variable to track to see if signal handlers are installed for application
139 resumed */
140 std::once_flag flag_managerSignals; /**< Variable to track to see if signal handlers are installed for the manager
141 signals of focused, resumed and starting */
142
143 void upstartEventEmitted(core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>>& signal,
144 std::shared_ptr<GVariant> params,
145 const std::shared_ptr<Registry>& reg);
146 void pauseEventEmitted(
147 core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>, std::vector<pid_t>&>& signal,
148 const std::shared_ptr<GVariant>& params,
149 const std::shared_ptr<Registry>& reg);
150 static std::tuple<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>> managerParams(
151 const std::shared_ptr<GVariant>& params, const std::shared_ptr<Registry>& reg);
152 static guint managerSignalHelper(const std::shared_ptr<Registry>& reg,
153 const std::string& signalname,
154 std::function<void(const std::shared_ptr<Registry>& reg,
155 const std::shared_ptr<Application>& app,
156 const std::shared_ptr<Application::Instance>& instance,
157 const std::shared_ptr<GDBusConnection>&,
158 const std::string&,
159 const std::shared_ptr<GVariant>&)> responsefunc);
99160
100 void initClick();161 void initClick();
101162
163 /** Shared instance of the Zeitgeist Log */
102 std::shared_ptr<ZeitgeistLog> zgLog_;164 std::shared_ptr<ZeitgeistLog> zgLog_;
103165
166 /** Shared connection to CGManager */
104 std::shared_ptr<GDBusConnection> cgManager_;167 std::shared_ptr<GDBusConnection> cgManager_;
105168
106 void initCGManager();169 void initCGManager();
107170
171 /** All of our icon finders based on the path that they're looking
172 into */
108 std::unordered_map<std::string, std::shared_ptr<IconFinder>> _iconFinders;173 std::unordered_map<std::string, std::shared_ptr<IconFinder>> _iconFinders;
109174
110 /** Getting the Upstart job path is relatively expensive in175 /** Getting the Upstart job path is relatively expensive in
111176
=== modified file 'libubuntu-app-launch/registry.cpp'
--- libubuntu-app-launch/registry.cpp 2016-08-26 17:33:34 +0000
+++ libubuntu-app-launch/registry.cpp 2016-11-07 20:56:13 +0000
@@ -57,7 +57,7 @@
57 instances.splice(instances.begin(), connection->impl->upstartInstancesForJob("application-snap"));57 instances.splice(instances.begin(), connection->impl->upstartInstancesForJob("application-snap"));
5858
59 /* Remove the instance ID */59 /* Remove the instance ID */
60 std::transform(instances.begin(), instances.end(), instances.begin(), [](std::string &instancename) -> std::string {60 std::transform(instances.begin(), instances.end(), instances.begin(), [](std::string& instancename) -> std::string {
61 static const std::regex instanceregex("^(.*)-[0-9]*$");61 static const std::regex instanceregex("^(.*)-[0-9]*$");
62 std::smatch match;62 std::smatch match;
63 if (std::regex_match(instancename, match, instanceregex))63 if (std::regex_match(instancename, match, instanceregex))
@@ -87,7 +87,7 @@
8787
88 g_debug("Overall there are %d instances: %s", int(instanceset.size()),88 g_debug("Overall there are %d instances: %s", int(instanceset.size()),
89 std::accumulate(instanceset.begin(), instanceset.end(), std::string{},89 std::accumulate(instanceset.begin(), instanceset.end(), std::string{},
90 [](const std::string &instr, std::string instance) {90 [](const std::string& instr, std::string instance) {
91 return instr.empty() ? instance : instr + ", " + instance;91 return instr.empty() ? instance : instr + ", " + instance;
92 })92 })
93 .c_str());93 .c_str());
@@ -127,6 +127,16 @@
127 return list;127 return list;
128}128}
129129
130void Registry::setManager(std::shared_ptr<Manager> manager, std::shared_ptr<Registry> registry)
131{
132 Registry::Impl::setManager(manager, registry);
133}
134
135void Registry::clearManager()
136{
137 impl->clearManager();
138}
139
130std::shared_ptr<Registry> defaultRegistry;140std::shared_ptr<Registry> defaultRegistry;
131std::shared_ptr<Registry> Registry::getDefault()141std::shared_ptr<Registry> Registry::getDefault()
132{142{
@@ -143,5 +153,35 @@
143 defaultRegistry.reset();153 defaultRegistry.reset();
144}154}
145155
156core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>>& Registry::appStarted(
157 const std::shared_ptr<Registry>& reg)
158{
159 return reg->impl->appStarted(reg);
160}
161
162core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>>& Registry::appStopped(
163 const std::shared_ptr<Registry>& reg)
164{
165 return reg->impl->appStopped(reg);
166}
167
168core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>, Registry::FailureType>&
169 Registry::appFailed(const std::shared_ptr<Registry>& reg)
170{
171 return reg->impl->appFailed(reg);
172}
173
174core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>, std::vector<pid_t>&>&
175 Registry::appPaused(const std::shared_ptr<Registry>& reg)
176{
177 return reg->impl->appPaused(reg);
178}
179
180core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>, std::vector<pid_t>&>&
181 Registry::appResumed(const std::shared_ptr<Registry>& reg)
182{
183 return reg->impl->appResumed(reg);
184}
185
146} // namespace app_launch186} // namespace app_launch
147} // namespace ubuntu187} // namespace ubuntu
148188
=== modified file 'libubuntu-app-launch/registry.h'
--- libubuntu-app-launch/registry.h 2016-06-09 14:55:34 +0000
+++ libubuntu-app-launch/registry.h 2016-11-07 20:56:13 +0000
@@ -73,28 +73,134 @@
73 */73 */
74 static std::list<std::shared_ptr<Application>> installedApps(std::shared_ptr<Registry> registry = getDefault());74 static std::list<std::shared_ptr<Application>> installedApps(std::shared_ptr<Registry> registry = getDefault());
7575
76#if 0 /* TODO -- In next MR */
77 /* Signals to discover what is happening to apps */76 /* Signals to discover what is happening to apps */
78 core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>> appStarted;77 /** Get the signal object that is signaled when an application has been
79 core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>> appStopped;78 started.
80 core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>, FailureType> appFailed;79
81 core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>> appPaused;80 \note This singal handler is activated on the UAL thread, if you want
82 core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>> appResumed;81 to execute on a different thread you'll need to move the work.
8382
84 /* The Application Manager, almost always if you're not Unity8, don't83 \param reg Registry to get the handler from
85 use this API. Testing is a special case. */84 */
85 static core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>>& appStarted(
86 const std::shared_ptr<Registry>& reg = getDefault());
87
88 /** Get the signal object that is signaled when an application has stopped.
89
90 \note This singal handler is activated on the UAL thread, if you want
91 to execute on a different thread you'll need to move the work.
92
93 \param reg Registry to get the handler from
94 */
95 static core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>>& appStopped(
96 const std::shared_ptr<Registry>& reg = getDefault());
97
98 /** Get the signal object that is signaled when an application has failed.
99
100 \note This singal handler is activated on the UAL thread, if you want
101 to execute on a different thread you'll need to move the work.
102
103 \param reg Registry to get the handler from
104 */
105 static core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>, FailureType>& appFailed(
106 const std::shared_ptr<Registry>& reg = getDefault());
107
108 /** Get the signal object that is signaled when an application has been
109 paused.
110
111 \note This singal handler is activated on the UAL thread, if you want
112 to execute on a different thread you'll need to move the work.
113
114 \param reg Registry to get the handler from
115 */
116 static core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>, std::vector<pid_t>&>&
117 appPaused(const std::shared_ptr<Registry>& reg = getDefault());
118
119 /** Get the signal object that is signaled when an application has been
120 resumed.
121
122 \note This singal handler is activated on the UAL thread, if you want
123 to execute on a different thread you'll need to move the work.
124
125 \param reg Registry to get the handler from
126 */
127 static core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>, std::vector<pid_t>&>&
128 appResumed(const std::shared_ptr<Registry>& reg = getDefault());
129
130 /** The Application Manager, almost always if you're not Unity8, don't
131 use this API. Testing is a special case. Subclass this interface and
132 implement these functions.
133
134 Each function here is being passed a function object that takes a boolean
135 to reply. This will accept or reject the request. The function object
136 can be copied to another thread and executed if needed.
137 */
86 class Manager138 class Manager
87 {139 {
88 virtual bool focusRequest (std::shared_ptr<Application> app, std::shared_ptr<Application::Instance> instance) = 0;140 public:
89 virtual bool startingRequest (std::shared_ptr<Application> app, std::shared_ptr<Application::Instance> instance) = 0;141 /** Application wishes to startup
142
143 \note This singal handler is activated on the UAL thread, if you want
144 to execute on a different thread you'll need to move the work.
145
146 \param app Application requesting startup
147 \param instance Instance of the app, always valid but not useful
148 unless mulit-instance app.
149 \param reply Function object to reply if it is allowed to start
150 */
151 virtual void startingRequest(std::shared_ptr<Application> app,
152 std::shared_ptr<Application::Instance> instance,
153 std::function<void(bool)> reply) = 0;
154
155 /** Application wishes to have focus. Usually this occurs when
156 a URL for the application is activated and the running app is
157 requested.
158
159 \note This singal handler is activated on the UAL thread, if you want
160 to execute on a different thread you'll need to move the work.
161
162 \param app Application requesting focus
163 \param instance Instance of the app, always valid but not useful
164 unless mulit-instance app.
165 \param reply Function object to reply if it is allowed to focus
166 */
167 virtual void focusRequest(std::shared_ptr<Application> app,
168 std::shared_ptr<Application::Instance> instance,
169 std::function<void(bool)> reply) = 0;
170
171 /** Application wishes to resume. Usually this occurs when
172 a URL for the application is activated and the running app is
173 requested.
174
175 \note This singal handler is activated on the UAL thread, if you want
176 to execute on a different thread you'll need to move the work.
177
178 \param app Application requesting resume
179 \param instance Instance of the app, always valid but not useful
180 unless mulit-instance app.
181 \param reply Function object to reply if it is allowed to resume
182 */
183 virtual void resumeRequest(std::shared_ptr<Application> app,
184 std::shared_ptr<Application::Instance> instance,
185 std::function<void(bool)> reply) = 0;
90186
91 protected:187 protected:
92 Manager() = default;188 Manager() = default;
93 };189 };
94190
95 void setManager (Manager* manager);191 /** Set the manager of applications, which gives permissions for them to
96 void clearManager ();192 start and gain focus. In almost all cases this should be Unity8 as it
97#endif193 will be controlling applications.
194
195 This function will failure if there is already a manager set.
196
197 \param manager A reference to the Manager object to call
198 \param registry Registry to register the manager on
199 */
200 static void setManager(std::shared_ptr<Manager> manager, std::shared_ptr<Registry> registry);
201
202 /** Remove the current manager on the registry */
203 void clearManager();
98204
99 /* Helper Lists */205 /* Helper Lists */
100 /** Get a list of all the helpers for a given helper type206 /** Get a list of all the helpers for a given helper type
101207
=== modified file 'libubuntu-app-launch/ubuntu-app-launch.cpp'
--- libubuntu-app-launch/ubuntu-app-launch.cpp 2016-09-14 21:58:39 +0000
+++ libubuntu-app-launch/ubuntu-app-launch.cpp 2016-11-07 20:56:13 +0000
@@ -39,6 +39,7 @@
39#include "appid.h"39#include "appid.h"
40#include "registry.h"40#include "registry.h"
41#include "registry-impl.h"41#include "registry-impl.h"
42#include <algorithm>
4243
43static void free_helper (gpointer value);44static void free_helper (gpointer value);
44int kill (pid_t pid, int signal) noexcept;45int kill (pid_t pid, int signal) noexcept;
@@ -271,155 +272,210 @@
271 gpointer user_data;272 gpointer user_data;
272};273};
273274
274/* The data we keep for each failed observer */275/* Function to take a work function and have it execute on a given
275typedef struct _paused_resumed_observer_t paused_resumed_observer_t;276 GMainContext */
276struct _paused_resumed_observer_t {277static void executeOnContext (std::shared_ptr<GMainContext> context, std::function<void()> work)
277 GDBusConnection * conn;278{
278 guint sighandle;279 if (!context) {
279 UbuntuAppLaunchAppPausedResumedObserver func;280 work();
280 gpointer user_data;281 return;
281 const gchar * lttng_signal;282 }
282};283
283284 auto heapWork = new std::function<void()>(work);
284/* The lists of Observers */285
285static GList * starting_array = NULL;286 auto source = std::shared_ptr<GSource>(g_idle_source_new(), [](GSource* src) { g_clear_pointer(&src, g_source_unref); });
286static GList * started_array = NULL;287 g_source_set_callback(source.get(),
287static GList * stop_array = NULL;288 [](gpointer data) {
288static GList * focus_array = NULL;289 auto heapWork = static_cast<std::function<void()>*>(data);
289static GList * resume_array = NULL;290 (*heapWork)();
290static GList * failed_array = NULL;291 return G_SOURCE_REMOVE;
291static GList * paused_array = NULL;292 },
292static GList * resumed_array = NULL;293 heapWork,
293294 [](gpointer data) {
294static void295 auto heapWork = static_cast<std::function<void()>*>(data);
295observer_cb (GDBusConnection * conn, const gchar * sender, const gchar * object, const gchar * interface, const gchar * signal, GVariant * params, gpointer user_data)296 delete heapWork;
296{297 });
297 observer_t * observer = (observer_t *)user_data;298
298299 g_source_attach(source.get(), context.get());
299 const gchar * signalname = NULL;300}
300 g_variant_get_child(params, 0, "&s", &signalname);301
301302/* Map of all the observers listening for app started */
302 ual_tracepoint(observer_start, signalname);303static std::map<std::pair<UbuntuAppLaunchAppObserver, gpointer>, core::ScopedConnection> appStartedObservers;
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 */
347static gboolean
348add_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}
377304
378gboolean305gboolean
379ubuntu_app_launch_observer_add_app_started (UbuntuAppLaunchAppObserver observer, gpointer user_data)306ubuntu_app_launch_observer_add_app_started (UbuntuAppLaunchAppObserver observer, gpointer user_data)
380{307{
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); });
382}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
325gboolean
326ubuntu_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 */
339static std::map<std::pair<UbuntuAppLaunchAppObserver, gpointer>, core::ScopedConnection> appStoppedObservers;
383340
384gboolean341gboolean
385ubuntu_app_launch_observer_add_app_stop (UbuntuAppLaunchAppObserver observer, gpointer user_data)342ubuntu_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}
389360
390/* Creates the observer structure and registers for the signal with361gboolean
391 GDBus so that we can get a callback */362ubuntu_app_launch_observer_delete_app_stop (UbuntuAppLaunchAppObserver observer, gpointer user_data)
392static gboolean
393add_session_generic (UbuntuAppLaunchAppObserver observer, gpointer user_data, const gchar * signal, GList ** list, GDBusSignalCallback session_cb)
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));
396365
397 if (conn == NULL) {366 if (iter == appStoppedObservers.end()) {
398 return FALSE;367 return FALSE;
399 }368 }
400369
401 observer_t * observert = g_new0(observer_t, 1);370 appStoppedObservers.erase(iter);
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
420 return TRUE;371 return TRUE;
421}372}
422373
374class CManager : public ubuntu::app_launch::Registry::Manager
375{
376public:
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
426private:
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
456public:
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
477static std::weak_ptr<CManager> cmanager;
478
423/* Generic handler for a bunch of our signals */479/* Generic handler for a bunch of our signals */
424static inline void480static inline void
425generic_signal_cb (GDBusConnection * conn, const gchar * sender, const gchar * object, const gchar * interface, const gchar * signal, GVariant * params, gpointer user_data)481generic_signal_cb (GDBusConnection * conn, const gchar * sender, const gchar * object, const gchar * interface, const gchar * signal, GVariant * params, gpointer user_data)
@@ -433,328 +489,158 @@
433 }489 }
434}490}
435491
436/* Handle the focus signal when it occurs, call the observer */
437static void
438focus_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
447gboolean492gboolean
448ubuntu_app_launch_observer_add_app_focus (UbuntuAppLaunchAppObserver observer, gpointer user_data)493ubuntu_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}
452506
453/* Handle the resume signal when it occurs, call the observer, then send a signal back when we're done */507gboolean
454static void508ubuntu_app_launch_observer_delete_app_focus (UbuntuAppLaunchAppObserver observer, gpointer user_data)
455resume_signal_cb (GDBusConnection * conn, const gchar * sender, const gchar * object, const gchar * interface, const gchar * signal, GVariant * params, gpointer user_data)
456{509{
457 ual_tracepoint(observer_start, "resume");510 auto manager = cmanager.lock();
458511
459 generic_signal_cb(conn, sender, object, interface, signal, params, user_data);512 if (!manager) {
460513 return FALSE;
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);
473 }514 }
474515
475 ual_tracepoint(observer_finish, "resume");516 return manager->deleteFocus(observer, user_data) ? TRUE : FALSE;
476}517}
477518
478gboolean519gboolean
479ubuntu_app_launch_observer_add_app_resume (UbuntuAppLaunchAppObserver observer, gpointer user_data)520ubuntu_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}
483533
484/* Handle the starting signal when it occurs, call the observer, then send a signal back when we're done */534gboolean
485static void535ubuntu_app_launch_observer_delete_app_resume (UbuntuAppLaunchAppObserver observer, gpointer user_data)
486starting_signal_cb (GDBusConnection * conn, const gchar * sender, const gchar * object, const gchar * interface, const gchar * signal, GVariant * params, gpointer user_data)
487{536{
488 ual_tracepoint(observer_start, "starting");537 auto manager = cmanager.lock();
489538
490 generic_signal_cb(conn, sender, object, interface, signal, params, user_data);539 if (!manager) {
491540 return FALSE;
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);
504 }541 }
505542
506 ual_tracepoint(observer_finish, "starting");543 return manager->deleteResume(observer, user_data) ? TRUE : FALSE;
507}544}
508545
509gboolean546gboolean
510ubuntu_app_launch_observer_add_app_starting (UbuntuAppLaunchAppObserver observer, gpointer user_data)547ubuntu_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 ubuntu::app_launch::Registry::Impl::watchingAppStarting(true);557 ubuntu::app_launch::Registry::Impl::watchingAppStarting(true);
513 return add_session_generic(observer, user_data, "UnityStartingBroadcast", &starting_array, starting_signal_cb);558 manager->addStarting(observer, user_data);
514}559 return TRUE;
515
516/* Handle the failed signal when it occurs, call the observer */
517static void
518failed_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
544gboolean
545ubuntu_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 */
576static void
577paused_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
606static gboolean
607paused_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
638gboolean
639ubuntu_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
644gboolean
645ubuntu_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
650static gboolean
651delete_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
677gboolean
678ubuntu_app_launch_observer_delete_app_started (UbuntuAppLaunchAppObserver observer, gpointer user_data)
679{
680 return delete_app_generic(observer, user_data, &started_array);
681}
682
683gboolean
684ubuntu_app_launch_observer_delete_app_stop (UbuntuAppLaunchAppObserver observer, gpointer user_data)
685{
686 return delete_app_generic(observer, user_data, &stop_array);
687}
688
689gboolean
690ubuntu_app_launch_observer_delete_app_resume (UbuntuAppLaunchAppObserver observer, gpointer user_data)
691{
692 return delete_app_generic(observer, user_data, &resume_array);
693}
694
695gboolean
696ubuntu_app_launch_observer_delete_app_focus (UbuntuAppLaunchAppObserver observer, gpointer user_data)
697{
698 return delete_app_generic(observer, user_data, &focus_array);
699}560}
700561
701gboolean562gboolean
702ubuntu_app_launch_observer_delete_app_starting (UbuntuAppLaunchAppObserver observer, gpointer user_data)563ubuntu_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 ubuntu::app_launch::Registry::Impl::watchingAppStarting(false);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 */
576static std::map<std::pair<UbuntuAppLaunchAppFailedObserver, gpointer>, core::ScopedConnection> appFailedObservers;
577
578gboolean
579ubuntu_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}
707608
708gboolean609gboolean
709ubuntu_app_launch_observer_delete_app_failed (UbuntuAppLaunchAppFailedObserver observer, gpointer user_data)610ubuntu_app_launch_observer_delete_app_failed (UbuntuAppLaunchAppFailedObserver observer, gpointer user_data)
710{611{
711 failed_observer_t * observert = NULL;612 auto iter = appFailedObservers.find(std::make_pair(observer, user_data));
712 GList * look;613
713614 if (iter == appFailedObservers.end()) {
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) {
723 return FALSE;615 return FALSE;
724 }616 }
725617
726 g_dbus_connection_signal_unsubscribe(observert->conn, observert->sighandle);618 appFailedObservers.erase(iter);
727 g_object_unref(observert->conn);
728
729 g_free(observert);
730 failed_array = g_list_delete_link(failed_array, look);
731
732 return TRUE;619 return TRUE;
733}620}
734621
735static gboolean622static std::map<std::pair<UbuntuAppLaunchAppPausedResumedObserver, gpointer>, core::ScopedConnection> appPausedObservers;
736paused_resumed_delete (UbuntuAppLaunchAppPausedResumedObserver observer, gpointer user_data, GList ** list)623
624gboolean
625ubuntu_app_launch_observer_add_app_paused (UbuntuAppLaunchAppPausedResumedObserver observer, gpointer user_data)
737{626{
738 paused_resumed_observer_t * observert = NULL;627 auto context = std::shared_ptr<GMainContext>(g_main_context_ref_thread_default(), [](GMainContext * context) { g_clear_pointer(&context, g_main_context_unref); });
739 GList * look;628
740629 appPausedObservers.emplace(std::make_pair(
741 for (look = *list; look != NULL; look = g_list_next(look)) {630 std::make_pair(observer, user_data),
742 observert = (paused_resumed_observer_t *)look->data;631 core::ScopedConnection(
743632 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) {
744 if (observert->func == observer && observert->user_data == user_data) {633 std::vector<pid_t> lpids = pids;
745 break;634 lpids.emplace_back(0);
746 }635
747 }636 std::string appid = app->appId();
748637
749 if (look == NULL) {638 executeOnContext(context, [appid, observer, user_data, lpids]() {
750 return FALSE;639 observer(appid.c_str(), (int *)(lpids.data()), user_data);
751 }640 });
752641 })
753 g_dbus_connection_signal_unsubscribe(observert->conn, observert->sighandle);642 )
754 g_object_unref(observert->conn);643 ));
755
756 g_free(observert);
757 *list = g_list_delete_link(*list, look);
758644
759 return TRUE;645 return TRUE;
760}646}
@@ -762,13 +648,53 @@
762gboolean648gboolean
763ubuntu_app_launch_observer_delete_app_paused (UbuntuAppLaunchAppPausedResumedObserver observer, gpointer user_data)649ubuntu_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
661static std::map<std::pair<UbuntuAppLaunchAppPausedResumedObserver, gpointer>, core::ScopedConnection> appResumedObservers;
662
663gboolean
664ubuntu_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}
767686
768gboolean687gboolean
769ubuntu_app_launch_observer_delete_app_resumed (UbuntuAppLaunchAppPausedResumedObserver observer, gpointer user_data)688ubuntu_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}
773699
774typedef void (*per_instance_func_t) (GDBusConnection * con, GVariant * prop_dict, gpointer user_data);700typedef void (*per_instance_func_t) (GDBusConnection * con, GVariant * prop_dict, gpointer user_data);
775701
=== modified file 'tests/CMakeLists.txt'
--- tests/CMakeLists.txt 2016-09-14 16:43:36 +0000
+++ tests/CMakeLists.txt 2016-11-07 20:56:13 +0000
@@ -157,6 +157,7 @@
157157
158add_custom_target(format-tests158add_custom_target(format-tests
159 COMMAND clang-format -i -style=file159 COMMAND clang-format -i -style=file
160 failure-test.cc
160 application-info-desktop.cpp161 application-info-desktop.cpp
161 libual-cpp-test.cc162 libual-cpp-test.cc
162 list-apps.cpp163 list-apps.cpp
163164
=== modified file 'tests/failure-test.cc'
--- tests/failure-test.cc 2016-08-25 18:13:44 +0000
+++ tests/failure-test.cc 2016-11-07 20:56:13 +0000
@@ -17,120 +17,147 @@
17 * Ted Gould <ted.gould@canonical.com>17 * Ted Gould <ted.gould@canonical.com>
18 */18 */
1919
20#include "eventually-fixture.h"
21#include "registry.h"
22#include <gio/gio.h>
23#include <glib/gstdio.h>
20#include <gtest/gtest.h>24#include <gtest/gtest.h>
21#include <glib/gstdio.h>
22#include <gio/gio.h>
23#include <ubuntu-app-launch.h>
24#include "eventually-fixture.h"
2525
26class FailureTest : public EventuallyFixture26class FailureTest : public EventuallyFixture
27{27{
28 private:28private:
29 GTestDBus * testbus = NULL;29 GTestDBus* testbus = NULL;
3030
31 protected:31protected:
32 virtual void SetUp() {32 std::shared_ptr<ubuntu::app_launch::Registry> registry;
33 testbus = g_test_dbus_new(G_TEST_DBUS_NONE);33
34 g_test_dbus_up(testbus);34 virtual void SetUp()
35 }35 {
3636 /* Click DB test mode */
37 virtual void TearDown() {37 g_setenv("TEST_CLICK_DB", "click-db-dir", TRUE);
38 g_test_dbus_down(testbus);38 g_setenv("TEST_CLICK_USER", "test-user", TRUE);
39 g_clear_object(&testbus);39
40 }40 gchar* linkfarmpath = g_build_filename(CMAKE_SOURCE_DIR, "link-farm", NULL);
41 g_setenv("UBUNTU_APP_LAUNCH_LINK_FARM", linkfarmpath, TRUE);
42 g_free(linkfarmpath);
43
44 g_setenv("XDG_DATA_DIRS", CMAKE_SOURCE_DIR, TRUE);
45 g_setenv("XDG_CACHE_HOME", CMAKE_SOURCE_DIR "/libertine-data", TRUE);
46 g_setenv("XDG_DATA_HOME", CMAKE_SOURCE_DIR "/libertine-home", TRUE);
47
48 testbus = g_test_dbus_new(G_TEST_DBUS_NONE);
49 g_test_dbus_up(testbus);
50
51 registry = std::make_shared<ubuntu::app_launch::Registry>();
52 }
53
54 virtual void TearDown()
55 {
56 registry.reset();
57
58 g_test_dbus_down(testbus);
59 g_clear_object(&testbus);
60 }
41};61};
4262
43static void
44failed_observer (const gchar * appid, UbuntuAppLaunchAppFailed reason, gpointer user_data)
45{
46 if (reason == UBUNTU_APP_LAUNCH_APP_FAILED_CRASH) {
47 std::string * last = static_cast<std::string *>(user_data);
48 *last = appid;
49 }
50}
51
52TEST_F(FailureTest, CrashTest)63TEST_F(FailureTest, CrashTest)
53{64{
54 g_setenv("EXIT_STATUS", "-100", TRUE);65 g_setenv("EXIT_STATUS", "-100", TRUE);
55 g_setenv("JOB", "application-click", TRUE);66 g_setenv("JOB", "application-click", TRUE);
56 g_setenv("INSTANCE", "foo", TRUE);67 g_setenv("INSTANCE", "foo", TRUE);
5768
58 std::string last_observer;69 std::string last_observer;
59 ASSERT_TRUE(ubuntu_app_launch_observer_add_app_failed(failed_observer, &last_observer));70 ubuntu::app_launch::Registry::appFailed(registry).connect(
6071 [&last_observer](std::shared_ptr<ubuntu::app_launch::Application> app,
61 /* Status based */72 std::shared_ptr<ubuntu::app_launch::Application::Instance> instance,
62 ASSERT_TRUE(g_spawn_command_line_sync(APP_FAILED_TOOL, NULL, NULL, NULL, NULL));73 ubuntu::app_launch::Registry::FailureType type) {
6374 if (type == ubuntu::app_launch::Registry::FailureType::CRASH)
64 EXPECT_EVENTUALLY_EQ("foo", last_observer);75 {
6576 last_observer = app->appId();
66 last_observer.clear();77 }
67 g_unsetenv("EXIT_STATUS");78 });
68 g_setenv("EXIT_SIGNAL", "KILL", TRUE);79
6980 /* Status based */
70 /* Signal based */81 ASSERT_TRUE(g_spawn_command_line_sync(APP_FAILED_TOOL, NULL, NULL, NULL, NULL));
71 ASSERT_TRUE(g_spawn_command_line_sync(APP_FAILED_TOOL, NULL, NULL, NULL, NULL));82
7283 EXPECT_EVENTUALLY_EQ("foo", last_observer);
73 EXPECT_EVENTUALLY_EQ("foo", last_observer);84
7485 last_observer.clear();
75 ASSERT_TRUE(ubuntu_app_launch_observer_delete_app_failed(failed_observer, &last_observer));86 g_unsetenv("EXIT_STATUS");
87 g_setenv("EXIT_SIGNAL", "KILL", TRUE);
88
89 /* Signal based */
90 ASSERT_TRUE(g_spawn_command_line_sync(APP_FAILED_TOOL, NULL, NULL, NULL, NULL));
91
92 EXPECT_EVENTUALLY_EQ("foo", last_observer);
76}93}
7794
78TEST_F(FailureTest, LegacyTest)95TEST_F(FailureTest, LegacyTest)
79{96{
80 g_setenv("EXIT_STATUS", "-100", TRUE);97 g_setenv("EXIT_STATUS", "-100", TRUE);
81 g_setenv("JOB", "application-legacy", TRUE);98 g_setenv("JOB", "application-legacy", TRUE);
82 g_setenv("INSTANCE", "foo-1234", TRUE);99 g_setenv("INSTANCE", "foo-1234", TRUE);
83100
84 std::string last_observer;101 std::string last_observer;
85 ASSERT_TRUE(ubuntu_app_launch_observer_add_app_failed(failed_observer, &last_observer));102 ubuntu::app_launch::Registry::appFailed(registry).connect(
86103 [&last_observer](std::shared_ptr<ubuntu::app_launch::Application> app,
87 /* Status based */104 std::shared_ptr<ubuntu::app_launch::Application::Instance> instance,
88 ASSERT_TRUE(g_spawn_command_line_sync(APP_FAILED_TOOL, NULL, NULL, NULL, NULL));105 ubuntu::app_launch::Registry::FailureType type) {
89106 g_debug("Signal handler called");
90 EXPECT_EVENTUALLY_EQ("foo", last_observer);107 if (type == ubuntu::app_launch::Registry::FailureType::CRASH)
91108 {
92 ASSERT_TRUE(ubuntu_app_launch_observer_delete_app_failed(failed_observer, &last_observer));109 last_observer = app->appId();
110 }
111 });
112
113 /* Status based */
114 ASSERT_TRUE(g_spawn_command_line_sync(APP_FAILED_TOOL, NULL, NULL, NULL, NULL));
115
116 EXPECT_EVENTUALLY_EQ("foo", last_observer);
93}117}
94118
95TEST_F(FailureTest, SnapTest)119TEST_F(FailureTest, SnapTest)
96{120{
97 g_setenv("EXIT_STATUS", "-100", TRUE);121 g_setenv("EXIT_STATUS", "-100", TRUE);
98 g_setenv("JOB", "application-snap", TRUE);122 g_setenv("JOB", "application-snap", TRUE);
99 g_setenv("INSTANCE", "foo_bar_x123-1234", TRUE);123 g_setenv("INSTANCE", "com.test.good_application_1.2.3-1234", TRUE);
100124
101 std::string last_observer;125 std::string last_observer;
102 ASSERT_TRUE(ubuntu_app_launch_observer_add_app_failed(failed_observer, &last_observer));126 ubuntu::app_launch::Registry::appFailed(registry).connect(
103127 [&last_observer](std::shared_ptr<ubuntu::app_launch::Application> app,
104 /* Status based */128 std::shared_ptr<ubuntu::app_launch::Application::Instance> instance,
105 ASSERT_TRUE(g_spawn_command_line_sync(APP_FAILED_TOOL, NULL, NULL, NULL, NULL));129 ubuntu::app_launch::Registry::FailureType type) {
106130 if (type == ubuntu::app_launch::Registry::FailureType::CRASH)
107 EXPECT_EVENTUALLY_EQ("foo_bar_x123", last_observer);131 {
108132 last_observer = app->appId();
109 ASSERT_TRUE(ubuntu_app_launch_observer_delete_app_failed(failed_observer, &last_observer));133 }
110}134 });
111135
112static void136 /* Status based */
113failed_start_observer (const gchar * appid, UbuntuAppLaunchAppFailed reason, gpointer user_data)137 ASSERT_TRUE(g_spawn_command_line_sync(APP_FAILED_TOOL, NULL, NULL, NULL, NULL));
114{138
115 if (reason == UBUNTU_APP_LAUNCH_APP_FAILED_START_FAILURE) {139 EXPECT_EVENTUALLY_EQ("com.test.good_application_1.2.3", last_observer);
116 std::string * last = static_cast<std::string *>(user_data);
117 *last = appid;
118 }
119}140}
120141
121TEST_F(FailureTest, StartTest)142TEST_F(FailureTest, StartTest)
122{143{
123 g_setenv("JOB", "application-click", TRUE);144 g_setenv("JOB", "application-click", TRUE);
124 g_setenv("INSTANCE", "foo", TRUE);145 g_setenv("INSTANCE", "foo", TRUE);
125 g_unsetenv("EXIT_STATUS");146 g_unsetenv("EXIT_STATUS");
126 g_unsetenv("EXIT_SIGNAL");147 g_unsetenv("EXIT_SIGNAL");
127148
128 std::string last_observer;149 std::string last_observer;
129 ASSERT_TRUE(ubuntu_app_launch_observer_add_app_failed(failed_start_observer, &last_observer));150 ubuntu::app_launch::Registry::appFailed(registry).connect(
130151 [&last_observer](std::shared_ptr<ubuntu::app_launch::Application> app,
131 ASSERT_TRUE(g_spawn_command_line_sync(APP_FAILED_TOOL, NULL, NULL, NULL, NULL));152 std::shared_ptr<ubuntu::app_launch::Application::Instance> instance,
132153 ubuntu::app_launch::Registry::FailureType type) {
133 EXPECT_EVENTUALLY_EQ("foo", last_observer);154 if (type == ubuntu::app_launch::Registry::FailureType::START_FAILURE)
134155 {
135 ASSERT_TRUE(ubuntu_app_launch_observer_delete_app_failed(failed_start_observer, &last_observer));156 last_observer = app->appId();
157 }
158 });
159
160 ASSERT_TRUE(g_spawn_command_line_sync(APP_FAILED_TOOL, NULL, NULL, NULL, NULL));
161
162 EXPECT_EVENTUALLY_EQ("foo", last_observer);
136}163}
137164
=== modified file 'tests/libual-cpp-test.cc'
--- tests/libual-cpp-test.cc 2016-09-23 20:36:31 +0000
+++ tests/libual-cpp-test.cc 2016-11-07 20:56:13 +0000
@@ -49,32 +49,68 @@
49 DbusTestDbusMock* mock = NULL;49 DbusTestDbusMock* mock = NULL;
50 DbusTestDbusMock* cgmock = NULL;50 DbusTestDbusMock* cgmock = NULL;
51 GDBusConnection* bus = NULL;51 GDBusConnection* bus = NULL;
52 std::string last_focus_appid;
53 std::string last_resume_appid;
54 guint resume_timeout = 0;52 guint resume_timeout = 0;
55 std::shared_ptr<ubuntu::app_launch::Registry> registry;53 std::shared_ptr<ubuntu::app_launch::Registry> registry;
5654
57private:55 class ManagerMock : public ubuntu::app_launch::Registry::Manager
58 static void focus_cb(const gchar* appid, gpointer user_data)56 {
59 {57 GLib::ContextThread thread;
60 g_debug("Focus Callback: %s", appid);58
61 LibUAL* _this = static_cast<LibUAL*>(user_data);59 public:
62 _this->last_focus_appid = appid;60 ManagerMock()
63 }61 {
6462 g_debug("Building a Manager Mock");
65 static void resume_cb(const gchar* appid, gpointer user_data)63 }
66 {64
67 g_debug("Resume Callback: %s", appid);65 ~ManagerMock()
68 LibUAL* _this = static_cast<LibUAL*>(user_data);66 {
69 _this->last_resume_appid = appid;67 g_debug("Freeing a Manager Mock");
7068 }
71 if (_this->resume_timeout > 0)69
72 {70 ubuntu::app_launch::AppID lastStartedApp;
73 _this->pause(_this->resume_timeout);71 ubuntu::app_launch::AppID lastFocusedApp;
74 }72 ubuntu::app_launch::AppID lastResumedApp;
75 }73
7674 bool startingResponse{true};
77protected:75 bool focusResponse{true};
76 bool resumeResponse{true};
77
78 std::chrono::milliseconds startingTimeout{0};
79 std::chrono::milliseconds focusTimeout{0};
80 std::chrono::milliseconds resumeTimeout{0};
81
82 void startingRequest(std::shared_ptr<ubuntu::app_launch::Application> app,
83 std::shared_ptr<ubuntu::app_launch::Application::Instance> instance,
84 std::function<void(bool)> reply) override
85 {
86 thread.timeout(startingTimeout, [this, app, instance, reply]() {
87 lastStartedApp = app->appId();
88 reply(startingResponse);
89 });
90 }
91
92 void focusRequest(std::shared_ptr<ubuntu::app_launch::Application> app,
93 std::shared_ptr<ubuntu::app_launch::Application::Instance> instance,
94 std::function<void(bool)> reply) override
95 {
96 thread.timeout(focusTimeout, [this, app, instance, reply]() {
97 lastFocusedApp = app->appId();
98 reply(focusResponse);
99 });
100 }
101
102 void resumeRequest(std::shared_ptr<ubuntu::app_launch::Application> app,
103 std::shared_ptr<ubuntu::app_launch::Application::Instance> instance,
104 std::function<void(bool)> reply) override
105 {
106 thread.timeout(resumeTimeout, [this, app, instance, reply]() {
107 lastResumedApp = app->appId();
108 reply(resumeResponse);
109 });
110 }
111 };
112 std::weak_ptr<ManagerMock> manager;
113
78 /* Useful debugging stuff, but not on by default. You really want to114 /* Useful debugging stuff, but not on by default. You really want to
79 not get all this noise typically */115 not get all this noise typically */
80 void debugConnection()116 void debugConnection()
@@ -127,13 +163,13 @@
127163
128 dbus_test_dbus_mock_object_add_method(mock, obj, "GetJobByName", G_VARIANT_TYPE("s"), G_VARIANT_TYPE("o"),164 dbus_test_dbus_mock_object_add_method(mock, obj, "GetJobByName", G_VARIANT_TYPE("s"), G_VARIANT_TYPE("o"),
129 "if args[0] == 'application-click':\n"165 "if args[0] == 'application-click':\n"
130 " ret = dbus.ObjectPath('/com/test/application_click')\n"166 " ret = dbus.ObjectPath('/com/test/application_click')\n"
131 "elif args[0] == 'application-snap':\n"167 "elif args[0] == 'application-snap':\n"
132 " ret = dbus.ObjectPath('/com/test/application_snap')\n"168 " ret = dbus.ObjectPath('/com/test/application_snap')\n"
133 "elif args[0] == 'application-legacy':\n"169 "elif args[0] == 'application-legacy':\n"
134 " ret = dbus.ObjectPath('/com/test/application_legacy')\n"170 " ret = dbus.ObjectPath('/com/test/application_legacy')\n"
135 "elif args[0] == 'untrusted-helper':\n"171 "elif args[0] == 'untrusted-helper':\n"
136 " ret = dbus.ObjectPath('/com/test/untrusted/helper')\n",172 " ret = dbus.ObjectPath('/com/test/untrusted/helper')\n",
137 NULL);173 NULL);
138174
139 dbus_test_dbus_mock_object_add_method(mock, obj, "SetEnv", G_VARIANT_TYPE("(assb)"), NULL, "", NULL);175 dbus_test_dbus_mock_object_add_method(mock, obj, "SetEnv", G_VARIANT_TYPE("(assb)"), NULL, "", NULL);
@@ -272,19 +308,23 @@
272 /* Make sure we pretend the CG manager is just on our bus */308 /* Make sure we pretend the CG manager is just on our bus */
273 g_setenv("UBUNTU_APP_LAUNCH_CG_MANAGER_SESSION_BUS", "YES", TRUE);309 g_setenv("UBUNTU_APP_LAUNCH_CG_MANAGER_SESSION_BUS", "YES", TRUE);
274310
275 ASSERT_TRUE(ubuntu_app_launch_observer_add_app_focus(focus_cb, this));
276 ASSERT_TRUE(ubuntu_app_launch_observer_add_app_resume(resume_cb, this));
277
278 registry = std::make_shared<ubuntu::app_launch::Registry>();311 registry = std::make_shared<ubuntu::app_launch::Registry>();
312
313 auto smanager = std::make_shared<ManagerMock>();
314 manager = smanager;
315 ubuntu::app_launch::Registry::setManager(smanager, registry);
279 }316 }
280317
281 virtual void TearDown()318 virtual void TearDown()
282 {319 {
283 ubuntu_app_launch_observer_delete_app_focus(focus_cb, this);
284 ubuntu_app_launch_observer_delete_app_resume(resume_cb, this);
285
286 registry.reset();320 registry.reset();
287321
322 // NOTE: This should generally always be commented out, but
323 // it is useful for debugging common errors, so leaving it
324 // as a comment to make debugging those eaiser.
325 //
326 // ubuntu::app_launch::Registry::clearDefault();
327
288 g_clear_object(&mock);328 g_clear_object(&mock);
289 g_clear_object(&cgmock);329 g_clear_object(&cgmock);
290 g_clear_object(&service);330 g_clear_object(&service);
@@ -793,33 +833,30 @@
793#endif833#endif
794}834}
795835
796typedef struct
797{
798 unsigned int count;
799 const gchar* name;
800} observer_data_t;
801
802static void observer_cb(const gchar* appid, gpointer user_data)
803{
804 observer_data_t* data = (observer_data_t*)user_data;
805
806 if (data->name == NULL)
807 {
808 data->count++;
809 }
810 else if (g_strcmp0(data->name, appid) == 0)
811 {
812 data->count++;
813 }
814}
815
816TEST_F(LibUAL, StartStopObserver)836TEST_F(LibUAL, StartStopObserver)
817{837{
818 observer_data_t start_data = {.count = 0, .name = nullptr};838 int start_count = 0;
819 observer_data_t stop_data = {.count = 0, .name = nullptr};839 int stop_count = 0;
820840 ubuntu::app_launch::AppID start_appid;
821 ASSERT_TRUE(ubuntu_app_launch_observer_add_app_started(observer_cb, &start_data));841 ubuntu::app_launch::AppID stop_appid;
822 ASSERT_TRUE(ubuntu_app_launch_observer_add_app_stop(observer_cb, &stop_data));842
843 ubuntu::app_launch::Registry::appStarted(registry).connect(
844 [&start_count, &start_appid](std::shared_ptr<ubuntu::app_launch::Application> app,
845 std::shared_ptr<ubuntu::app_launch::Application::Instance> instance) {
846 if (!start_appid.empty() && !(start_appid == app->appId()))
847 return;
848
849 start_count++;
850 });
851
852 ubuntu::app_launch::Registry::appStopped(registry).connect(
853 [&stop_count, &stop_appid](std::shared_ptr<ubuntu::app_launch::Application> app,
854 std::shared_ptr<ubuntu::app_launch::Application::Instance> instance) {
855 if (!stop_appid.empty() && !(stop_appid == app->appId()))
856 return;
857
858 stop_count++;
859 });
823860
824 DbusTestDbusMockObject* obj =861 DbusTestDbusMockObject* obj =
825 dbus_test_dbus_mock_get_object(mock, "/com/ubuntu/Upstart", "com.ubuntu.Upstart0_6", NULL);862 dbus_test_dbus_mock_get_object(mock, "/com/ubuntu/Upstart", "com.ubuntu.Upstart0_6", NULL);
@@ -830,7 +867,7 @@
830 g_variant_new_parsed("('started', ['JOB=application-click', 'INSTANCE=com.test.good_application_1.2.3'])"),867 g_variant_new_parsed("('started', ['JOB=application-click', 'INSTANCE=com.test.good_application_1.2.3'])"),
831 NULL);868 NULL);
832869
833 EXPECT_EVENTUALLY_EQ(1, start_data.count);870 EXPECT_EVENTUALLY_EQ(1, start_count);
834871
835 /* Basic stop */872 /* Basic stop */
836 dbus_test_dbus_mock_object_emit_signal(873 dbus_test_dbus_mock_object_emit_signal(
@@ -838,33 +875,41 @@
838 g_variant_new_parsed("('stopped', ['JOB=application-click', 'INSTANCE=com.test.good_application_1.2.3'])"),875 g_variant_new_parsed("('stopped', ['JOB=application-click', 'INSTANCE=com.test.good_application_1.2.3'])"),
839 NULL);876 NULL);
840877
841 EXPECT_EVENTUALLY_EQ(1, stop_data.count);878 EXPECT_EVENTUALLY_EQ(1, stop_count);
842879
843 /* Start legacy */880 /* Start legacy */
844 start_data.count = 0;881 start_count = 0;
845 start_data.name = "multiple";882 start_appid = ubuntu::app_launch::AppID{ubuntu::app_launch::AppID::Package::from_raw({}),
883 ubuntu::app_launch::AppID::AppName::from_raw("multiple"),
884 ubuntu::app_launch::AppID::Version::from_raw({})};
846885
847 dbus_test_dbus_mock_object_emit_signal(886 dbus_test_dbus_mock_object_emit_signal(
848 mock, obj, "EventEmitted", G_VARIANT_TYPE("(sas)"),887 mock, obj, "EventEmitted", G_VARIANT_TYPE("(sas)"),
849 g_variant_new_parsed("('started', ['JOB=application-legacy', 'INSTANCE=multiple-234235'])"), NULL);888 g_variant_new_parsed("('started', ['JOB=application-legacy', 'INSTANCE=multiple-234235'])"), NULL);
850889
851 EXPECT_EVENTUALLY_EQ(1, start_data.count);890 EXPECT_EVENTUALLY_EQ(1, start_count);
852891
853 /* Legacy stop */892 /* Legacy stop */
854 stop_data.count = 0;893 stop_count = 0;
855 stop_data.name = "bar";894 stop_appid = ubuntu::app_launch::AppID{ubuntu::app_launch::AppID::Package::from_raw({}),
895 ubuntu::app_launch::AppID::AppName::from_raw("foo"),
896 ubuntu::app_launch::AppID::Version::from_raw({})};
856897
857 dbus_test_dbus_mock_object_emit_signal(898 dbus_test_dbus_mock_object_emit_signal(
858 mock, obj, "EventEmitted", G_VARIANT_TYPE("(sas)"),899 mock, obj, "EventEmitted", G_VARIANT_TYPE("(sas)"),
859 g_variant_new_parsed("('stopped', ['JOB=application-legacy', 'INSTANCE=bar-9344321'])"), NULL);900 g_variant_new_parsed("('stopped', ['JOB=application-legacy', 'INSTANCE=foo-9344321'])"), NULL);
860901
861 EXPECT_EVENTUALLY_EQ(1, stop_data.count);902 EXPECT_EVENTUALLY_EQ(1, stop_count);
862903
863 /* Test Noise Start */904 /* Test Noise Start */
864 start_data.count = 0;905 start_count = 0;
865 start_data.name = "com.test.good_application_1.2.3";906 start_appid = ubuntu::app_launch::AppID{ubuntu::app_launch::AppID::Package::from_raw("com.test.good"),
866 stop_data.count = 0;907 ubuntu::app_launch::AppID::AppName::from_raw("application"),
867 stop_data.name = "com.test.good_application_1.2.3";908 ubuntu::app_launch::AppID::Version::from_raw("1.2.3")};
909 stop_count = 0;
910 stop_appid = ubuntu::app_launch::AppID{ubuntu::app_launch::AppID::Package::from_raw("com.test.good"),
911 ubuntu::app_launch::AppID::AppName::from_raw("application"),
912 ubuntu::app_launch::AppID::Version::from_raw("1.2.3")};
868913
869 /* A full lifecycle */914 /* A full lifecycle */
870 dbus_test_dbus_mock_object_emit_signal(915 dbus_test_dbus_mock_object_emit_signal(
@@ -885,46 +930,33 @@
885 NULL);930 NULL);
886931
887 /* Ensure we just signaled once for each */932 /* Ensure we just signaled once for each */
888 EXPECT_EVENTUALLY_EQ(1, start_data.count);933 EXPECT_EVENTUALLY_EQ(1, start_count);
889 EXPECT_EVENTUALLY_EQ(1, stop_data.count);934 EXPECT_EVENTUALLY_EQ(1, stop_count);
890
891 /* Remove */
892 ASSERT_TRUE(ubuntu_app_launch_observer_delete_app_started(observer_cb, &start_data));
893 ASSERT_TRUE(ubuntu_app_launch_observer_delete_app_stop(observer_cb, &stop_data));
894}
895
896static GDBusMessage* filter_starting(GDBusConnection* conn,
897 GDBusMessage* message,
898 gboolean incomming,
899 gpointer user_data)
900{
901 if (g_strcmp0(g_dbus_message_get_member(message), "UnityStartingSignal") == 0)
902 {
903 unsigned int* count = static_cast<unsigned int*>(user_data);
904 (*count)++;
905 g_object_unref(message);
906 return NULL;
907 }
908
909 return message;
910}
911
912static void starting_observer(const gchar* appid, gpointer user_data)
913{
914 std::string* last = static_cast<std::string*>(user_data);
915 *last = appid;
916 return;
917}935}
918936
919TEST_F(LibUAL, StartingResponses)937TEST_F(LibUAL, StartingResponses)
920{938{
921 std::string last_observer;939 /* Get Bus */
940 GDBusConnection* session = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);
941
942 /* Setup filter to count signals out */
922 unsigned int starting_count = 0;943 unsigned int starting_count = 0;
923 GDBusConnection* session = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);944 guint filter = g_dbus_connection_add_filter(
924 guint filter = g_dbus_connection_add_filter(session, filter_starting, &starting_count, NULL);945 session,
925946 [](GDBusConnection* conn, GDBusMessage* message, gboolean incomming, gpointer user_data) -> GDBusMessage* {
926 EXPECT_TRUE(ubuntu_app_launch_observer_add_app_starting(starting_observer, &last_observer));947 if (g_strcmp0(g_dbus_message_get_member(message), "UnityStartingSignal") == 0)
927948 {
949 unsigned int* count = static_cast<unsigned int*>(user_data);
950 (*count)++;
951 g_object_unref(message);
952 return NULL;
953 }
954
955 return message;
956 },
957 &starting_count, NULL);
958
959 /* Emit a signal */
928 g_dbus_connection_emit_signal(session, NULL, /* destination */960 g_dbus_connection_emit_signal(session, NULL, /* destination */
929 "/", /* path */961 "/", /* path */
930 "com.canonical.UbuntuAppLaunch", /* interface */962 "com.canonical.UbuntuAppLaunch", /* interface */
@@ -932,11 +964,15 @@
932 g_variant_new("(s)", "com.test.good_application_1.2.3"), /* params, the same */964 g_variant_new("(s)", "com.test.good_application_1.2.3"), /* params, the same */
933 NULL);965 NULL);
934966
935 EXPECT_EVENTUALLY_EQ("com.test.good_application_1.2.3", last_observer);967 /* Make sure we run our observer */
968 EXPECT_EVENTUALLY_EQ(ubuntu::app_launch::AppID(ubuntu::app_launch::AppID::Package::from_raw("com.test.good"),
969 ubuntu::app_launch::AppID::AppName::from_raw("application"),
970 ubuntu::app_launch::AppID::Version::from_raw("1.2.3")),
971 manager.lock()->lastStartedApp);
972
973 /* Make sure we return */
936 EXPECT_EVENTUALLY_EQ(1, starting_count);974 EXPECT_EVENTUALLY_EQ(1, starting_count);
937975
938 EXPECT_TRUE(ubuntu_app_launch_observer_delete_app_starting(starting_observer, &last_observer));
939
940 g_dbus_connection_remove_filter(session, filter);976 g_dbus_connection_remove_filter(session, filter);
941 g_object_unref(session);977 g_object_unref(session);
942}978}
@@ -947,8 +983,10 @@
947 auto app = ubuntu::app_launch::Application::create(appid, registry);983 auto app = ubuntu::app_launch::Application::create(appid, registry);
948 app->launch();984 app->launch();
949985
950 EXPECT_EVENTUALLY_EQ("com.test.good_application_1.2.3", this->last_focus_appid);986 EXPECT_EVENTUALLY_EQ(ubuntu::app_launch::AppID::parse("com.test.good_application_1.2.3"),
951 EXPECT_EVENTUALLY_EQ("com.test.good_application_1.2.3", this->last_resume_appid);987 this->manager.lock()->lastFocusedApp);
988 EXPECT_EVENTUALLY_EQ(ubuntu::app_launch::AppID::parse("com.test.good_application_1.2.3"),
989 this->manager.lock()->lastResumedApp);
952}990}
953991
954GDBusMessage* filter_func_good(GDBusConnection* conn, GDBusMessage* message, gboolean incomming, gpointer user_data)992GDBusMessage* filter_func_good(GDBusConnection* conn, GDBusMessage* message, gboolean incomming, gpointer user_data)
@@ -982,8 +1020,10 @@
9821020
983 app->launch(uris);1021 app->launch(uris);
9841022
985 EXPECT_EVENTUALLY_EQ("com.test.good_application_1.2.3", this->last_focus_appid);1023 EXPECT_EVENTUALLY_EQ(ubuntu::app_launch::AppID::parse("com.test.good_application_1.2.3"),
986 EXPECT_EVENTUALLY_EQ("com.test.good_application_1.2.3", this->last_resume_appid);1024 this->manager.lock()->lastFocusedApp);
1025 EXPECT_EVENTUALLY_EQ(ubuntu::app_launch::AppID::parse("com.test.good_application_1.2.3"),
1026 this->manager.lock()->lastResumedApp);
9871027
988 g_dbus_connection_remove_filter(session, filter);1028 g_dbus_connection_remove_filter(session, filter);
9891029
@@ -1015,8 +1055,10 @@
10151055
1016 app->launch(uris);1056 app->launch(uris);
10171057
1018 EXPECT_EVENTUALLY_EQ("com.test.good_application_1.2.3", this->last_focus_appid);1058 EXPECT_EVENTUALLY_EQ(ubuntu::app_launch::AppID::parse("com.test.good_application_1.2.3"),
1019 EXPECT_EVENTUALLY_EQ("com.test.good_application_1.2.3", this->last_resume_appid);1059 this->manager.lock()->lastFocusedApp);
1060 EXPECT_EVENTUALLY_EQ(ubuntu::app_launch::AppID::parse("com.test.good_application_1.2.3"),
1061 this->manager.lock()->lastResumedApp);
1020}1062}
10211063
1022TEST_F(LibUAL, UnityTimeoutTest)1064TEST_F(LibUAL, UnityTimeoutTest)
@@ -1028,8 +1070,10 @@
10281070
1029 app->launch();1071 app->launch();
10301072
1031 EXPECT_EVENTUALLY_EQ("com.test.good_application_1.2.3", this->last_resume_appid);1073 EXPECT_EVENTUALLY_EQ(ubuntu::app_launch::AppID::parse("com.test.good_application_1.2.3"),
1032 EXPECT_EVENTUALLY_EQ("com.test.good_application_1.2.3", this->last_focus_appid);1074 this->manager.lock()->lastResumedApp);
1075 EXPECT_EVENTUALLY_EQ(ubuntu::app_launch::AppID::parse("com.test.good_application_1.2.3"),
1076 this->manager.lock()->lastFocusedApp);
1033}1077}
10341078
1035TEST_F(LibUAL, UnityTimeoutUriTest)1079TEST_F(LibUAL, UnityTimeoutUriTest)
@@ -1043,8 +1087,10 @@
10431087
1044 app->launch(uris);1088 app->launch(uris);
10451089
1046 EXPECT_EVENTUALLY_EQ("com.test.good_application_1.2.3", this->last_focus_appid);1090 EXPECT_EVENTUALLY_EQ(ubuntu::app_launch::AppID::parse("com.test.good_application_1.2.3"),
1047 EXPECT_EVENTUALLY_EQ("com.test.good_application_1.2.3", this->last_resume_appid);1091 this->manager.lock()->lastFocusedApp);
1092 EXPECT_EVENTUALLY_EQ(ubuntu::app_launch::AppID::parse("com.test.good_application_1.2.3"),
1093 this->manager.lock()->lastResumedApp);
1048}1094}
10491095
1050GDBusMessage* filter_respawn(GDBusConnection* conn, GDBusMessage* message, gboolean incomming, gpointer user_data)1096GDBusMessage* filter_respawn(GDBusConnection* conn, GDBusMessage* message, gboolean incomming, gpointer user_data)
@@ -1077,8 +1123,10 @@
1077 g_debug("Start call time: %d ms", (end - start) / 1000);1123 g_debug("Start call time: %d ms", (end - start) / 1000);
1078 EXPECT_LT(end - start, 2000 * 1000);1124 EXPECT_LT(end - start, 2000 * 1000);
10791125
1080 EXPECT_EVENTUALLY_EQ("com.test.good_application_1.2.3", this->last_focus_appid);1126 EXPECT_EVENTUALLY_EQ(ubuntu::app_launch::AppID::parse("com.test.good_application_1.2.3"),
1081 EXPECT_EVENTUALLY_EQ("com.test.good_application_1.2.3", this->last_resume_appid);1127 this->manager.lock()->lastFocusedApp);
1128 EXPECT_EVENTUALLY_EQ(ubuntu::app_launch::AppID::parse("com.test.good_application_1.2.3"),
1129 this->manager.lock()->lastResumedApp);
10821130
1083 g_dbus_connection_remove_filter(session, filter);1131 g_dbus_connection_remove_filter(session, filter);
1084 g_object_unref(session);1132 g_object_unref(session);
@@ -1138,23 +1186,21 @@
1138 g_variant_unref(env);1186 g_variant_unref(env);
1139}1187}
11401188
1141static void failed_observer(const gchar* appid, UbuntuAppLaunchAppFailed reason, gpointer user_data)
1142{
1143 if (reason == UBUNTU_APP_LAUNCH_APP_FAILED_CRASH)
1144 {
1145 std::string* last = static_cast<std::string*>(user_data);
1146 *last = appid;
1147 }
1148 return;
1149}
1150
1151TEST_F(LibUAL, FailingObserver)1189TEST_F(LibUAL, FailingObserver)
1152{1190{
1153 std::string last_observer;1191 ubuntu::app_launch::AppID lastFailedApp;
1192 ubuntu::app_launch::Registry::FailureType lastFailedType;
1193
1194 ubuntu::app_launch::Registry::appFailed(registry).connect(
1195 [&lastFailedApp, &lastFailedType](std::shared_ptr<ubuntu::app_launch::Application> app,
1196 std::shared_ptr<ubuntu::app_launch::Application::Instance> instance,
1197 ubuntu::app_launch::Registry::FailureType type) {
1198 lastFailedApp = app->appId();
1199 lastFailedType = type;
1200 });
1201
1154 GDBusConnection* session = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);1202 GDBusConnection* session = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);
11551203
1156 EXPECT_TRUE(ubuntu_app_launch_observer_add_app_failed(failed_observer, &last_observer));
1157
1158 g_dbus_connection_emit_signal(1204 g_dbus_connection_emit_signal(
1159 session, NULL, /* destination */1205 session, NULL, /* destination */
1160 "/", /* path */1206 "/", /* path */
@@ -1163,9 +1209,10 @@
1163 g_variant_new("(ss)", "com.test.good_application_1.2.3", "crash"), /* params, the same */1209 g_variant_new("(ss)", "com.test.good_application_1.2.3", "crash"), /* params, the same */
1164 NULL);1210 NULL);
11651211
1166 EXPECT_EVENTUALLY_EQ("com.test.good_application_1.2.3", last_observer);1212 EXPECT_EVENTUALLY_EQ(ubuntu::app_launch::AppID::parse("com.test.good_application_1.2.3"), lastFailedApp);
1213 EXPECT_EVENTUALLY_EQ(ubuntu::app_launch::Registry::FailureType::CRASH, lastFailedType);
11671214
1168 last_observer.clear();1215 lastFailedApp = ubuntu::app_launch::AppID();
11691216
1170 g_dbus_connection_emit_signal(1217 g_dbus_connection_emit_signal(
1171 session, NULL, /* destination */1218 session, NULL, /* destination */
@@ -1175,9 +1222,9 @@
1175 g_variant_new("(ss)", "com.test.good_application_1.2.3", "blahblah"), /* params, the same */1222 g_variant_new("(ss)", "com.test.good_application_1.2.3", "blahblah"), /* params, the same */
1176 NULL);1223 NULL);
11771224
1178 EXPECT_EVENTUALLY_EQ("com.test.good_application_1.2.3", last_observer);1225 EXPECT_EVENTUALLY_EQ(ubuntu::app_launch::AppID::parse("com.test.good_application_1.2.3"), lastFailedApp);
11791226
1180 last_observer.clear();1227 lastFailedApp = ubuntu::app_launch::AppID();
11811228
1182 g_dbus_connection_emit_signal(1229 g_dbus_connection_emit_signal(
1183 session, NULL, /* destination */1230 session, NULL, /* destination */
@@ -1187,9 +1234,7 @@
1187 g_variant_new("(ss)", "com.test.good_application_1.2.3", "start-failure"), /* params, the same */1234 g_variant_new("(ss)", "com.test.good_application_1.2.3", "start-failure"), /* params, the same */
1188 NULL);1235 NULL);
11891236
1190 EXPECT_EVENTUALLY_EQ(true, last_observer.empty());1237 EXPECT_EVENTUALLY_EQ(ubuntu::app_launch::Registry::FailureType::START_FAILURE, lastFailedType);
1191
1192 EXPECT_TRUE(ubuntu_app_launch_observer_delete_app_failed(failed_observer, &last_observer));
11931238
1194 g_object_unref(session);1239 g_object_unref(session);
1195}1240}
11961241
=== modified file 'tools/CMakeLists.txt'
--- tools/CMakeLists.txt 2016-06-18 18:24:27 +0000
+++ tools/CMakeLists.txt 2016-11-07 20:56:13 +0000
@@ -39,7 +39,7 @@
39# ubuntu-app-launch39# ubuntu-app-launch
40########################40########################
4141
42add_executable(ubuntu-app-launch ubuntu-app-launch.c)42add_executable(ubuntu-app-launch ubuntu-app-launch.cpp)
43set_target_properties(ubuntu-app-launch PROPERTIES OUTPUT_NAME "ubuntu-app-launch")43set_target_properties(ubuntu-app-launch PROPERTIES OUTPUT_NAME "ubuntu-app-launch")
44target_link_libraries(ubuntu-app-launch ubuntu-launcher)44target_link_libraries(ubuntu-app-launch ubuntu-launcher)
45install(TARGETS ubuntu-app-launch RUNTIME DESTINATION "${CMAKE_INSTALL_FULL_BINDIR}")45install(TARGETS ubuntu-app-launch RUNTIME DESTINATION "${CMAKE_INSTALL_FULL_BINDIR}")
@@ -48,7 +48,7 @@
48# ubuntu-app-watch48# ubuntu-app-watch
49########################49########################
5050
51add_executable(ubuntu-app-watch ubuntu-app-watch.c)51add_executable(ubuntu-app-watch ubuntu-app-watch.cpp)
52set_target_properties(ubuntu-app-watch PROPERTIES OUTPUT_NAME "ubuntu-app-watch")52set_target_properties(ubuntu-app-watch PROPERTIES OUTPUT_NAME "ubuntu-app-watch")
53target_link_libraries(ubuntu-app-watch ubuntu-launcher)53target_link_libraries(ubuntu-app-watch ubuntu-launcher)
54install(TARGETS ubuntu-app-watch RUNTIME DESTINATION "${CMAKE_INSTALL_FULL_BINDIR}")54install(TARGETS ubuntu-app-watch RUNTIME DESTINATION "${CMAKE_INSTALL_FULL_BINDIR}")
@@ -116,3 +116,22 @@
116target_link_libraries(ubuntu-app-usage ubuntu-launcher)116target_link_libraries(ubuntu-app-usage ubuntu-launcher)
117install(TARGETS ubuntu-app-usage RUNTIME DESTINATION "${CMAKE_INSTALL_FULL_BINDIR}")117install(TARGETS ubuntu-app-usage RUNTIME DESTINATION "${CMAKE_INSTALL_FULL_BINDIR}")
118118
119########################
120# Formatting
121########################
122
123add_custom_target(format-tools
124 COMMAND clang-format -i -style=file
125 ubuntu-app-info.cpp
126 ubuntu-app-launch-appids.cpp
127 ubuntu-app-launch.cpp
128 ubuntu-app-list.cpp
129 ubuntu-app-list-pids.cpp
130 ubuntu-app-pid.cpp
131 ubuntu-app-stop.cpp
132 ubuntu-app-triplet.cpp
133 ubuntu-app-watch.cpp
134 ubuntu-helper-list.cpp
135 ubuntu-helper-start.cpp
136 ubuntu-helper-stop.cpp
137)
119138
=== modified file 'tools/ubuntu-app-info.cpp'
--- tools/ubuntu-app-info.cpp 2016-05-04 14:09:10 +0000
+++ tools/ubuntu-app-info.cpp 2016-11-07 20:56:13 +0000
@@ -17,34 +17,40 @@
17 * Ted Gould <ted.gould@canonical.com>17 * Ted Gould <ted.gould@canonical.com>
18 */18 */
1919
20#include <iostream>
21#include "libubuntu-app-launch/application.h"20#include "libubuntu-app-launch/application.h"
22#include "libubuntu-app-launch/registry.h"21#include "libubuntu-app-launch/registry.h"
22#include <iostream>
2323
24int main(int argc, char* argv[])24int main(int argc, char *argv[])
25{25{
26 if (argc != 2) {26 if (argc != 2)
27 {
27 std::cerr << "Usage: " << argv[0] << " (appid)" << std::endl;28 std::cerr << "Usage: " << argv[0] << " (appid)" << std::endl;
28 exit(1);29 exit(1);
29 }30 }
3031
31 auto appid = ubuntu::app_launch::AppID::find(argv[1]);32 auto appid = ubuntu::app_launch::AppID::find(argv[1]);
32 if (appid.empty()) {33 if (appid.empty())
34 {
33 std::cerr << "Unable to find app for appid: " << argv[1] << std::endl;35 std::cerr << "Unable to find app for appid: " << argv[1] << std::endl;
34 return 1;36 return 1;
35 }37 }
3638
37 std::shared_ptr<ubuntu::app_launch::Application> app;39 std::shared_ptr<ubuntu::app_launch::Application> app;
38 try {40 try
41 {
39 app = ubuntu::app_launch::Application::create(appid, ubuntu::app_launch::Registry::getDefault());42 app = ubuntu::app_launch::Application::create(appid, ubuntu::app_launch::Registry::getDefault());
40 if (!app)43 if (!app)
41 throw std::runtime_error("Application object is nullptr");44 throw std::runtime_error("Application object is nullptr");
42 } catch (std::runtime_error &e) {45 }
46 catch (std::runtime_error &e)
47 {
43 std::cerr << "Unable to find application for AppID: " << argv[1] << std::endl;48 std::cerr << "Unable to find application for AppID: " << argv[1] << std::endl;
44 exit(1);49 exit(1);
45 }50 }
4651
47 try {52 try
53 {
48 auto info = app->info();54 auto info = app->info();
4955
50 std::cout << "Name: " << info->name().value() << std::endl;56 std::cout << "Name: " << info->name().value() << std::endl;
@@ -64,8 +70,11 @@
64 std::cout << " Inv Landscape: " << info->supportedOrientations().invertedLandscape << std::endl;70 std::cout << " Inv Landscape: " << info->supportedOrientations().invertedLandscape << std::endl;
65 std::cout << "Rotates: " << info->rotatesWindowContents().value() << std::endl;71 std::cout << "Rotates: " << info->rotatesWindowContents().value() << std::endl;
66 std::cout << "Ubuntu Lifecycle: " << info->supportsUbuntuLifecycle().value() << std::endl;72 std::cout << "Ubuntu Lifecycle: " << info->supportsUbuntuLifecycle().value() << std::endl;
67 } catch (std::runtime_error &e) {73 }
68 std::cerr << "Unable to parse Application info for application '" << std::string(appid) << "': " << e.what() << std::endl;74 catch (std::runtime_error &e)
75 {
76 std::cerr << "Unable to parse Application info for application '" << std::string(appid) << "': " << e.what()
77 << std::endl;
69 exit(1);78 exit(1);
70 }79 }
7180
7281
=== renamed file 'tools/ubuntu-app-launch.c' => 'tools/ubuntu-app-launch.cpp'
--- tools/ubuntu-app-launch.c 2016-02-08 19:03:31 +0000
+++ tools/ubuntu-app-launch.cpp 2016-11-07 20:56:13 +0000
@@ -1,5 +1,5 @@
1/*1/*
2 * Copyright 2013 Canonical Ltd.2 * Copyright © 2016 Canonical Ltd.
3 *3 *
4 * This program is free software: you can redistribute it and/or modify it4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3, as published5 * under the terms of the GNU General Public License version 3, as published
@@ -17,71 +17,59 @@
17 * Ted Gould <ted.gould@canonical.com>17 * Ted Gould <ted.gould@canonical.com>
18 */18 */
1919
20#include <glib.h>20#include "libubuntu-app-launch/application.h"
21#include "libubuntu-app-launch/ubuntu-app-launch.h"21#include "libubuntu-app-launch/registry.h"
2222#include <csignal>
23const gchar * global_appid = NULL;23#include <future>
24int retval = 0;24#include <iostream>
2525
26static void26ubuntu::app_launch::AppID global_appid;
27good_observer (const gchar * appid, gpointer user_data)27std::promise<int> retval;
28{28
29 if (g_strcmp0(appid, global_appid) != 0) {29int main(int argc, char* argv[])
30 return;30{
31 }31 if (argc < 2)
3232 {
33 g_debug("Application '%s' running", appid);33 std::cerr << "Usage: " << argv[0] << " <app id> [uris]" << std::endl;
34 g_main_loop_quit((GMainLoop *)user_data);34 return 1;
35}35 }
3636
37static void37 global_appid = ubuntu::app_launch::AppID::find(argv[1]);
38bad_observer (const gchar * appid, UbuntuAppLaunchAppFailed failure_type, gpointer user_data)38
39{39 std::vector<ubuntu::app_launch::Application::URL> urls;
40 if (g_strcmp0(appid, global_appid) != 0) {40 for (int i = 2; i < argc; i++)
41 return;41 {
42 }42 urls.push_back(ubuntu::app_launch::Application::URL::from_raw(argv[i]));
4343 }
44 g_debug("Application '%s' failed: %s", appid, failure_type == UBUNTU_APP_LAUNCH_APP_FAILED_CRASH ? "crash" : "startup failure");44
45 retval = -1;45 ubuntu::app_launch::Registry::appStarted().connect(
46 g_main_loop_quit((GMainLoop *)user_data);46 [](std::shared_ptr<ubuntu::app_launch::Application> app,
47}47 std::shared_ptr<ubuntu::app_launch::Application::Instance> instance) {
4848 if (app->appId() != global_appid)
49int49 {
50main (int argc, gchar * argv[]) {50 return;
51 if (argc < 2) {51 }
52 g_printerr("Usage: %s <app id> [uris]\n", argv[0]);52
53 return 1;53 std::cout << "Started: " << (std::string)app->appId() << std::endl;
54 }54 retval.set_value(EXIT_SUCCESS);
5555 });
56 global_appid = argv[1];56
57 GMainLoop * mainloop = g_main_loop_new(NULL, FALSE);57 ubuntu::app_launch::Registry::appFailed().connect(
5858 [](std::shared_ptr<ubuntu::app_launch::Application> app,
59 gchar ** uris = NULL;59 std::shared_ptr<ubuntu::app_launch::Application::Instance> instance,
60 if (argc > 2) {60 ubuntu::app_launch::Registry::FailureType type) {
61 int i;61 if (app->appId() != global_appid)
6262 {
63 uris = g_new0(gchar *, argc - 1);63 return;
6464 }
65 for (i = 2; i < argc; i++) {65
66 uris[i - 2] = argv[i];66 std::cout << "Failed: " << (std::string)app->appId() << std::endl;
67 }67 retval.set_value(EXIT_FAILURE);
68 }68 });
6969
70 ubuntu_app_launch_observer_add_app_started(good_observer, mainloop);70 auto app = ubuntu::app_launch::Application::create(global_appid, ubuntu::app_launch::Registry::getDefault());
71 ubuntu_app_launch_observer_add_app_focus(good_observer, mainloop);71 app->launch(urls);
7272
73 ubuntu_app_launch_observer_add_app_failed(bad_observer, mainloop);73 std::signal(SIGTERM, [](int signal) -> void { retval.set_value(EXIT_SUCCESS); });
7474 return retval.get_future().get();
75 ubuntu_app_launch_start_application(global_appid, (const gchar * const *)uris);
76
77 g_main_loop_run(mainloop);
78
79 ubuntu_app_launch_observer_delete_app_started(good_observer, mainloop);
80 ubuntu_app_launch_observer_delete_app_focus(good_observer, mainloop);
81 ubuntu_app_launch_observer_delete_app_failed(bad_observer, mainloop);
82
83 g_main_loop_unref(mainloop);
84 g_free(uris);
85
86 return retval;
87}75}
8876
=== modified file 'tools/ubuntu-app-list-pids.cpp'
--- tools/ubuntu-app-list-pids.cpp 2016-05-03 01:46:27 +0000
+++ tools/ubuntu-app-list-pids.cpp 2016-11-07 20:56:13 +0000
@@ -30,12 +30,14 @@
30 }30 }
3131
32 auto appid = ubuntu::app_launch::AppID::find(argv[1]);32 auto appid = ubuntu::app_launch::AppID::find(argv[1]);
33 if (appid.empty()) {33 if (appid.empty())
34 {
34 std::cerr << "Unable to find app for appid: " << argv[1] << std::endl;35 std::cerr << "Unable to find app for appid: " << argv[1] << std::endl;
35 return 1;36 return 1;
36 }37 }
3738
38 try {39 try
40 {
39 auto app = ubuntu::app_launch::Application::create(appid, ubuntu::app_launch::Registry::getDefault());41 auto app = ubuntu::app_launch::Application::create(appid, ubuntu::app_launch::Registry::getDefault());
4042
41 for (auto instance : app->instances())43 for (auto instance : app->instances())
@@ -45,7 +47,9 @@
45 std::cout << pid << std::endl;47 std::cout << pid << std::endl;
46 }48 }
47 }49 }
48 } catch (std::runtime_error &e) {50 }
51 catch (std::runtime_error& e)
52 {
49 std::cerr << "Unable to find application for '" << std::string(appid) << "': " << e.what() << std::endl;53 std::cerr << "Unable to find application for '" << std::string(appid) << "': " << e.what() << std::endl;
50 return 1;54 return 1;
51 }55 }
5256
=== modified file 'tools/ubuntu-app-list.cpp'
--- tools/ubuntu-app-list.cpp 2016-02-09 21:12:54 +0000
+++ tools/ubuntu-app-list.cpp 2016-11-07 20:56:13 +0000
@@ -17,8 +17,8 @@
17 * Ted Gould <ted.gould@canonical.com>17 * Ted Gould <ted.gould@canonical.com>
18 */18 */
1919
20#include "libubuntu-app-launch/registry.h"
20#include <iostream>21#include <iostream>
21#include "libubuntu-app-launch/registry.h"
2222
23int main(int argc, char* argv[])23int main(int argc, char* argv[])
24{24{
2525
=== modified file 'tools/ubuntu-app-pid.cpp'
--- tools/ubuntu-app-pid.cpp 2016-05-03 01:46:51 +0000
+++ tools/ubuntu-app-pid.cpp 2016-11-07 20:56:13 +0000
@@ -18,8 +18,8 @@
18 */18 */
1919
20#include <iostream>20#include <iostream>
21#include <libubuntu-app-launch/application.h>
21#include <libubuntu-app-launch/registry.h>22#include <libubuntu-app-launch/registry.h>
22#include <libubuntu-app-launch/application.h>
2323
24int main(int argc, char* argv[])24int main(int argc, char* argv[])
25{25{
@@ -31,12 +31,14 @@
31 }31 }
3232
33 auto appid = ubuntu::app_launch::AppID::find(argv[1]);33 auto appid = ubuntu::app_launch::AppID::find(argv[1]);
34 if (appid.empty()) {34 if (appid.empty())
35 {
35 std::cerr << "Unable to find app for appid: " << argv[1] << std::endl;36 std::cerr << "Unable to find app for appid: " << argv[1] << std::endl;
36 return 1;37 return 1;
37 }38 }
3839
39 try {40 try
41 {
40 auto app = ubuntu::app_launch::Application::create(appid, ubuntu::app_launch::Registry::getDefault());42 auto app = ubuntu::app_launch::Application::create(appid, ubuntu::app_launch::Registry::getDefault());
41 auto pid = app->instances()[0]->primaryPid();43 auto pid = app->instances()[0]->primaryPid();
4244
@@ -47,7 +49,9 @@
4749
48 std::cout << pid << std::endl;50 std::cout << pid << std::endl;
49 return 0;51 return 0;
50 } catch (std::runtime_error &e) {52 }
53 catch (std::runtime_error& e)
54 {
51 std::cerr << "Unable to find application for '" << std::string(appid) << "': " << e.what() << std::endl;55 std::cerr << "Unable to find application for '" << std::string(appid) << "': " << e.what() << std::endl;
52 return 1;56 return 1;
53 }57 }
5458
=== modified file 'tools/ubuntu-app-stop.cpp'
--- tools/ubuntu-app-stop.cpp 2016-05-03 01:46:27 +0000
+++ tools/ubuntu-app-stop.cpp 2016-11-07 20:56:13 +0000
@@ -30,19 +30,23 @@
30 }30 }
3131
32 auto appid = ubuntu::app_launch::AppID::find(argv[1]);32 auto appid = ubuntu::app_launch::AppID::find(argv[1]);
33 if (appid.empty()) {33 if (appid.empty())
34 {
34 std::cerr << "Unable to find app for appid: " << argv[1] << std::endl;35 std::cerr << "Unable to find app for appid: " << argv[1] << std::endl;
35 return 1;36 return 1;
36 }37 }
3738
38 try {39 try
40 {
39 auto app = ubuntu::app_launch::Application::create(appid, ubuntu::app_launch::Registry::getDefault());41 auto app = ubuntu::app_launch::Application::create(appid, ubuntu::app_launch::Registry::getDefault());
4042
41 for (auto instance : app->instances())43 for (auto instance : app->instances())
42 {44 {
43 instance->stop();45 instance->stop();
44 }46 }
45 } catch (std::runtime_error &e) {47 }
48 catch (std::runtime_error& e)
49 {
46 std::cerr << "Unable to find application for '" << std::string(appid) << "': " << e.what() << std::endl;50 std::cerr << "Unable to find application for '" << std::string(appid) << "': " << e.what() << std::endl;
47 return 1;51 return 1;
48 }52 }
4953
=== modified file 'tools/ubuntu-app-triplet.cpp'
--- tools/ubuntu-app-triplet.cpp 2016-02-09 21:12:54 +0000
+++ tools/ubuntu-app-triplet.cpp 2016-11-07 20:56:13 +0000
@@ -17,8 +17,8 @@
17 * Ted Gould <ted.gould@canonical.com>17 * Ted Gould <ted.gould@canonical.com>
18 */18 */
1919
20#include "libubuntu-app-launch/application.h"
20#include <iostream>21#include <iostream>
21#include "libubuntu-app-launch/application.h"
2222
23int main(int argc, char* argv[])23int main(int argc, char* argv[])
24{24{
2525
=== renamed file 'tools/ubuntu-app-watch.c' => 'tools/ubuntu-app-watch.cpp'
--- tools/ubuntu-app-watch.c 2016-02-08 19:03:31 +0000
+++ tools/ubuntu-app-watch.cpp 2016-11-07 20:56:13 +0000
@@ -1,5 +1,5 @@
1/*1/*
2 * Copyright 2013 Canonical Ltd.2 * Copyright © 2015 Canonical Ltd.
3 *3 *
4 * This program is free software: you can redistribute it and/or modify it4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3, as published5 * under the terms of the GNU General Public License version 3, as published
@@ -17,91 +17,64 @@
17 * Ted Gould <ted.gould@canonical.com>17 * Ted Gould <ted.gould@canonical.com>
18 */18 */
1919
20#include "libubuntu-app-launch/ubuntu-app-launch.h"20#include "libubuntu-app-launch/registry.h"
2121#include <csignal>
22void22#include <future>
23starting (const gchar * appid, gpointer user_data)23
24{24std::promise<int> retval;
25 g_print("Starting %s\n", appid);25
26 return;26int main(int argc, char *argv[])
27}27{
2828 ubuntu::app_launch::Registry registry;
29void29
30started (const gchar * appid, gpointer user_data)30 registry.appStarted().connect([](std::shared_ptr<ubuntu::app_launch::Application> app,
31{31 std::shared_ptr<ubuntu::app_launch::Application::Instance> instance) {
32 g_print("Started %s\n", appid);32 std::cout << "Started: " << (std::string)app->appId() << std::endl;
33 return;33 });
34}34 registry.appStopped().connect([](std::shared_ptr<ubuntu::app_launch::Application> app,
3535 std::shared_ptr<ubuntu::app_launch::Application::Instance> instance) {
36void36 std::cout << "Stopped: " << (std::string)app->appId() << std::endl;
37stopped (const gchar * appid, gpointer user_data)37 });
38{38 registry.appPaused().connect([](std::shared_ptr<ubuntu::app_launch::Application> app,
39 g_print("Stop %s\n", appid);39 std::shared_ptr<ubuntu::app_launch::Application::Instance> instance,
40 return;40 std::vector<pid_t> &pids) {
41}41 std::cout << "Paused: " << (std::string)app->appId() << " (";
4242
43void43 for (auto pid : pids)
44resumed (const gchar * appid, GPid * pids, gpointer user_data)44 {
45{45 std::cout << std::to_string(pid) << " ";
46 g_print("Resumed %s\n", appid);46 }
47 return;47
48}48 std::cout << ")" << std::endl;
4949 });
50void50 registry.appResumed().connect([](std::shared_ptr<ubuntu::app_launch::Application> app,
51paused (const gchar * appid, GPid * pids, gpointer user_data)51 std::shared_ptr<ubuntu::app_launch::Application::Instance> instance,
52{52 std::vector<pid_t> &pids) {
53 g_print("Paused %s\n", appid);53 std::cout << "Resumed: " << (std::string)app->appId() << " (";
54 return;54
55}55 for (auto pid : pids)
5656 {
57void57 std::cout << std::to_string(pid) << " ";
58focus (const gchar * appid, gpointer user_data)58 }
59{59
60 g_print("Focus %s\n", appid);60 std::cout << ")" << std::endl;
61 return;61 });
62}62 registry.appFailed().connect([](std::shared_ptr<ubuntu::app_launch::Application> app,
6363 std::shared_ptr<ubuntu::app_launch::Application::Instance> instance,
64void64 ubuntu::app_launch::Registry::FailureType type) {
65fail (const gchar * appid, UbuntuAppLaunchAppFailed failhow, gpointer user_data)65 std::cout << "Failed: " << (std::string)app->appId();
66{66 switch (type)
67 const gchar * failstr = "unknown";67 {
68 switch (failhow) {68 case ubuntu::app_launch::Registry::FailureType::CRASH:
69 case UBUNTU_APP_LAUNCH_APP_FAILED_CRASH:69 std::cout << " (crash)";
70 failstr = "crashed";70 break;
71 break;71 case ubuntu::app_launch::Registry::FailureType::START_FAILURE:
72 case UBUNTU_APP_LAUNCH_APP_FAILED_START_FAILURE:72 std::cout << " (start failure)";
73 failstr = "startup";73 break;
74 break;74 }
75 }75 std::cout << std::endl;
7676 });
77 g_print("Fail %s (%s)\n", appid, failstr);77
78 return;78 std::signal(SIGTERM, [](int signal) -> void { retval.set_value(EXIT_SUCCESS); });
79}79 return retval.get_future().get();
80
81
82int
83main (int argc, gchar * argv[])
84{
85 ubuntu_app_launch_observer_add_app_starting(starting, NULL);
86 ubuntu_app_launch_observer_add_app_started(started, NULL);
87 ubuntu_app_launch_observer_add_app_stop(stopped, NULL);
88 ubuntu_app_launch_observer_add_app_focus(focus, NULL);
89 ubuntu_app_launch_observer_add_app_resumed(resumed, NULL);
90 ubuntu_app_launch_observer_add_app_paused(paused, NULL);
91 ubuntu_app_launch_observer_add_app_failed(fail, NULL);
92
93 GMainLoop * mainloop = g_main_loop_new(NULL, FALSE);
94 g_main_loop_run(mainloop);
95
96 ubuntu_app_launch_observer_delete_app_starting(starting, NULL);
97 ubuntu_app_launch_observer_delete_app_started(started, NULL);
98 ubuntu_app_launch_observer_delete_app_stop(stopped, NULL);
99 ubuntu_app_launch_observer_delete_app_focus(focus, NULL);
100 ubuntu_app_launch_observer_delete_app_resumed(resumed, NULL);
101 ubuntu_app_launch_observer_delete_app_paused(paused, NULL);
102 ubuntu_app_launch_observer_delete_app_failed(fail, NULL);
103
104 g_main_loop_unref(mainloop);
105
106 return 0;
107}80}
10881
=== modified file 'tools/ubuntu-helper-list.cpp'
--- tools/ubuntu-helper-list.cpp 2016-02-09 21:12:54 +0000
+++ tools/ubuntu-helper-list.cpp 2016-11-07 20:56:13 +0000
@@ -17,8 +17,8 @@
17 * Ted Gould <ted.gould@canonical.com>17 * Ted Gould <ted.gould@canonical.com>
18 */18 */
1919
20#include "libubuntu-app-launch/registry.h"
20#include <iostream>21#include <iostream>
21#include "libubuntu-app-launch/registry.h"
2222
23int main(int argc, char* argv[])23int main(int argc, char* argv[])
24{24{
2525
=== modified file 'tools/ubuntu-helper-start.cpp'
--- tools/ubuntu-helper-start.cpp 2016-05-03 01:46:27 +0000
+++ tools/ubuntu-helper-start.cpp 2016-11-07 20:56:13 +0000
@@ -17,9 +17,9 @@
17 * Ted Gould <ted.gould@canonical.com>17 * Ted Gould <ted.gould@canonical.com>
18 */18 */
1919
20#include <iostream>
21#include "libubuntu-app-launch/helper.h"20#include "libubuntu-app-launch/helper.h"
22#include "libubuntu-app-launch/registry.h"21#include "libubuntu-app-launch/registry.h"
22#include <iostream>
2323
24int main(int argc, char* argv[])24int main(int argc, char* argv[])
25{25{
@@ -31,20 +31,25 @@
3131
32 auto type = ubuntu::app_launch::Helper::Type::from_raw(argv[1]);32 auto type = ubuntu::app_launch::Helper::Type::from_raw(argv[1]);
33 auto appid = ubuntu::app_launch::AppID::find(argv[2]);33 auto appid = ubuntu::app_launch::AppID::find(argv[2]);
34 if (appid.empty()) {34 if (appid.empty())
35 {
35 std::cerr << "Unable to find helper for appid: " << argv[1] << std::endl;36 std::cerr << "Unable to find helper for appid: " << argv[1] << std::endl;
36 return 1;37 return 1;
37 }38 }
3839
39 auto registry = std::make_shared<ubuntu::app_launch::Registry>();40 auto registry = std::make_shared<ubuntu::app_launch::Registry>();
4041
41 try {42 try
43 {
42 auto helper = ubuntu::app_launch::Helper::create(type, appid, registry);44 auto helper = ubuntu::app_launch::Helper::create(type, appid, registry);
4345
44 helper->launch();46 helper->launch();
45 return 0;47 return 0;
46 } catch (std::runtime_error &e) {48 }
47 std::cerr << "Unable to find helper for '" << std::string(appid) << "' type '" << type.value() << "': " << e.what() << std::endl;49 catch (std::runtime_error& e)
50 {
51 std::cerr << "Unable to find helper for '" << std::string(appid) << "' type '" << type.value()
52 << "': " << e.what() << std::endl;
48 return 1;53 return 1;
49 }54 }
50}55}
5156
=== modified file 'tools/ubuntu-helper-stop.cpp'
--- tools/ubuntu-helper-stop.cpp 2016-05-03 01:46:27 +0000
+++ tools/ubuntu-helper-stop.cpp 2016-11-07 20:56:13 +0000
@@ -17,9 +17,9 @@
17 * Ted Gould <ted.gould@canonical.com>17 * Ted Gould <ted.gould@canonical.com>
18 */18 */
1919
20#include <iostream>
21#include "libubuntu-app-launch/helper.h"20#include "libubuntu-app-launch/helper.h"
22#include "libubuntu-app-launch/registry.h"21#include "libubuntu-app-launch/registry.h"
22#include <iostream>
2323
24int main(int argc, char* argv[])24int main(int argc, char* argv[])
25{25{
@@ -31,14 +31,16 @@
3131
32 auto type = ubuntu::app_launch::Helper::Type::from_raw(argv[1]);32 auto type = ubuntu::app_launch::Helper::Type::from_raw(argv[1]);
33 auto appid = ubuntu::app_launch::AppID::find(argv[2]);33 auto appid = ubuntu::app_launch::AppID::find(argv[2]);
34 if (appid.empty()) {34 if (appid.empty())
35 {
35 std::cerr << "Unable to find helper for appid: " << argv[1] << std::endl;36 std::cerr << "Unable to find helper for appid: " << argv[1] << std::endl;
36 return 1;37 return 1;
37 }38 }
3839
39 auto registry = std::make_shared<ubuntu::app_launch::Registry>();40 auto registry = std::make_shared<ubuntu::app_launch::Registry>();
4041
41 try {42 try
43 {
42 auto helper = ubuntu::app_launch::Helper::create(type, appid, registry);44 auto helper = ubuntu::app_launch::Helper::create(type, appid, registry);
4345
44 for (auto instance : helper->instances())46 for (auto instance : helper->instances())
@@ -47,8 +49,11 @@
47 }49 }
4850
49 return 0;51 return 0;
50 } catch (std::runtime_error &e) {52 }
51 std::cerr << "Unable to find helper for '" << std::string(appid) << "' type '" << type.value() << "': " << e.what() << std::endl;53 catch (std::runtime_error& e)
54 {
55 std::cerr << "Unable to find helper for '" << std::string(appid) << "' type '" << type.value()
56 << "': " << e.what() << std::endl;
52 return 1;57 return 1;
53 }58 }
54}59}

Subscribers

People subscribed via source and target branches