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

Proposed by Ted Gould
Status: Merged
Approved by: Marcus Tomlinson
Approved revision: 280
Merged at revision: 277
Proposed branch: lp:~ted/ubuntu-app-launch/jobs-signals
Merge into: lp:ubuntu-app-launch
Prerequisite: lp:~ted/ubuntu-app-launch/abstract-jobs
Diff against target: 1659 lines (+754/-654)
7 files modified
libubuntu-app-launch/jobs-base.cpp (+356/-1)
libubuntu-app-launch/jobs-base.h (+86/-1)
libubuntu-app-launch/jobs-upstart.cpp (+258/-13)
libubuntu-app-launch/jobs-upstart.h (+26/-0)
libubuntu-app-launch/registry-impl.cpp (+0/-554)
libubuntu-app-launch/registry-impl.h (+1/-78)
libubuntu-app-launch/registry.cpp (+27/-7)
To merge this branch: bzr merge lp:~ted/ubuntu-app-launch/jobs-signals
Reviewer Review Type Date Requested Status
Marcus Tomlinson (community) Approve
unity-api-1-bot continuous-integration Needs Fixing
Review via email: mp+310587@code.launchpad.net

Commit message

Move the signals into the jobs classes

Description of the change

This branch reshuffles the signal code from being in the registry implementation to being in the individual job implementations. Actually the base jobs handle the entirely internal UAL events, but the implementations can then implement things further that require getting events from the process manager. This branch just really reshuffles and renames code. No functional changes.

To post a comment you must log in.
Revision history for this message
unity-api-1-bot (unity-api-1-bot) wrote :

PASSED: Continuous integration, rev:278
https://jenkins.canonical.com/unity-api-1/job/lp-ubuntu-app-launch-ci/136/
Executed test runs:
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build/1274
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-0-fetch/1281
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=xenial+overlay/1061
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=xenial+overlay/1061/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=zesty/1061
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=zesty/1061/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=xenial+overlay/1061
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=xenial+overlay/1061/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=zesty/1061
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=zesty/1061/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=xenial+overlay/1061
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=xenial+overlay/1061/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=zesty/1061
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=zesty/1061/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://jenkins.canonical.com/unity-api-1/job/lp-ubuntu-app-launch-ci/136/rebuild

review: Approve (continuous-integration)
279. By Ted Gould

Merge the abstract-jobs branch

Revision history for this message
unity-api-1-bot (unity-api-1-bot) wrote :

PASSED: Continuous integration, rev:279
https://jenkins.canonical.com/unity-api-1/job/lp-ubuntu-app-launch-ci/159/
Executed test runs:
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build/1352
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-0-fetch/1359
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=xenial+overlay/1137
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=xenial+overlay/1137/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=zesty/1137
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=zesty/1137/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=xenial+overlay/1137
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=xenial+overlay/1137/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=zesty/1137
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=zesty/1137/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=xenial+overlay/1137
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=xenial+overlay/1137/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=zesty/1137
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=zesty/1137/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://jenkins.canonical.com/unity-api-1/job/lp-ubuntu-app-launch-ci/159/rebuild

review: Approve (continuous-integration)
280. By Ted Gould

Update to trunk

Revision history for this message
unity-api-1-bot (unity-api-1-bot) wrote :

FAILED: Continuous integration, rev:280
https://jenkins.canonical.com/unity-api-1/job/lp-ubuntu-app-launch-ci/172/
Executed test runs:
    FAILURE: https://jenkins.canonical.com/unity-api-1/job/build/1454/console
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-0-fetch/1461
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=xenial+overlay/1238
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=xenial+overlay/1238/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=zesty/1238
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=zesty/1238/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=xenial+overlay/1238
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=xenial+overlay/1238/artifact/output/*zip*/output.zip
    FAILURE: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=zesty/1238/console
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=xenial+overlay/1238
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=xenial+overlay/1238/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=zesty/1238
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=zesty/1238/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://jenkins.canonical.com/unity-api-1/job/lp-ubuntu-app-launch-ci/172/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Marcus Tomlinson (marcustomlinson) wrote :

Hmmm, so I've left an inline comment about a possible memory leak picked up by cppcheck. This led me to run a few valgrind checks over the tests, and there seem to be a fair bit of complaints. I'll mail you about that to keep this review concentrated.

review: Needs Information
Revision history for this message
Marcus Tomlinson (marcustomlinson) wrote :

3 inline comments.

review: Needs Information
Revision history for this message
Marcus Tomlinson (marcustomlinson) wrote :

Sorry, another 3 inline comments.

review: Needs Information
Revision history for this message
Ted Gould (ted) wrote :

On Fri, 2017-01-20 at 09:10 +0000, Marcus Tomlinson wrote:
> Weird that this deleter is never called during the tests.
>
Yes, I think it must get optimized out to just a call to free since
everything else is basically making the type system happy. It seems
like a very aggressive optimization though.

Revision history for this message
Ted Gould (ted) wrote :

On Fri, 2017-01-20 at 08:22 +0000, Marcus Tomlinson wrote:
> +    managerEventData* focusdata = new managerEventData{reg,
> > responsefunc};
> cppcheck is concerned about this focusdata pointer leaking memory.
> When is it ever deleted?
>
> >
> > +
> > +    return g_dbus_connection_signal_subscribe(

This function returns a handle, so then when that handle is used for
the unsubscribe the deleter is called. It can also get called if all
references to the connection get dropped.

Revision history for this message
Marcus Tomlinson (marcustomlinson) wrote :

> On Fri, 2017-01-20 at 08:22 +0000, Marcus Tomlinson wrote:
> > +    managerEventData* focusdata = new managerEventData{reg,
> > > responsefunc};
> > cppcheck is concerned about this focusdata pointer leaking memory.
> > When is it ever deleted?
> >
> > >
> > > +
> > > +    return g_dbus_connection_signal_subscribe(
>
> This function returns a handle, so then when that handle is used for
> the unsubscribe the deleter is called. It can also get called if all
> references to the connection get dropped.

Yeah ok, I don't recall this line being flagged up by valgrind so I think we should be good here.

Revision history for this message
Marcus Tomlinson (marcustomlinson) wrote :

Cool, looks good.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'libubuntu-app-launch/jobs-base.cpp'
2--- libubuntu-app-launch/jobs-base.cpp 2017-01-19 03:25:37 +0000
3+++ libubuntu-app-launch/jobs-base.cpp 2017-01-19 03:25:37 +0000
4@@ -37,7 +37,25 @@
5
6 Base::Base(const std::shared_ptr<Registry>& registry)
7 : registry_(registry)
8-{
9+ , dbus_(registry->impl->_dbus)
10+{
11+}
12+
13+Base::~Base()
14+{
15+ auto dohandle = [&](guint& handle) {
16+ if (handle != 0)
17+ {
18+ g_dbus_connection_signal_unsubscribe(dbus_.get(), handle);
19+ handle = 0;
20+ }
21+ };
22+
23+ dohandle(handle_managerSignalFocus);
24+ dohandle(handle_managerSignalResume);
25+ dohandle(handle_managerSignalStarting);
26+ dohandle(handle_appPaused);
27+ dohandle(handle_appResumed);
28 }
29
30 std::shared_ptr<Base> Base::determineFactory(std::shared_ptr<Registry> registry)
31@@ -45,6 +63,343 @@
32 return std::make_shared<jobs::manager::Upstart>(registry);
33 }
34
35+/** Structure to track the data needed for upstart events. This cleans
36+ up the lifecycle as we're passing this as a pointer through the
37+ GLib calls. */
38+struct upstartEventData
39+{
40+ /** Keeping a weak pointer because the handle is held by
41+ the registry implementation. */
42+ std::weak_ptr<Registry> weakReg;
43+};
44+
45+/** Core handler for pause and resume events. Includes turning the GVariant
46+ pid list into a std::vector and getting the application object. */
47+void Base::pauseEventEmitted(core::Signal<const std::shared_ptr<Application>&,
48+ const std::shared_ptr<Application::Instance>&,
49+ const std::vector<pid_t>&>& signal,
50+ const std::shared_ptr<GVariant>& params,
51+ const std::shared_ptr<Registry>& reg)
52+{
53+ std::vector<pid_t> pids;
54+ GVariant* vappid = g_variant_get_child_value(params.get(), 0);
55+ GVariant* vpids = g_variant_get_child_value(params.get(), 1);
56+ guint64 pid;
57+ GVariantIter thispid;
58+ g_variant_iter_init(&thispid, vpids);
59+
60+ while (g_variant_iter_loop(&thispid, "t", &pid))
61+ {
62+ pids.emplace_back(pid);
63+ }
64+
65+ auto cappid = g_variant_get_string(vappid, NULL);
66+ auto appid = ubuntu::app_launch::AppID::find(reg, cappid);
67+ auto app = Application::create(appid, reg);
68+
69+ /* TODO: Instance */
70+ signal(app, {}, pids);
71+
72+ g_variant_unref(vappid);
73+ g_variant_unref(vpids);
74+
75+ return;
76+}
77+
78+/** Grab the signal object for application paused. If we're not already listing for
79+ those signals this sets up a listener for them. */
80+core::Signal<const std::shared_ptr<Application>&,
81+ const std::shared_ptr<Application::Instance>&,
82+ const std::vector<pid_t>&>&
83+ Base::appPaused()
84+{
85+ std::call_once(flag_appPaused, [this]() {
86+ auto reg = registry_.lock();
87+
88+ reg->impl->thread.executeOnThread<bool>([this, reg]() {
89+ upstartEventData* data = new upstartEventData{reg};
90+
91+ handle_appPaused = g_dbus_connection_signal_subscribe(
92+ reg->impl->_dbus.get(), /* bus */
93+ nullptr, /* sender */
94+ "com.canonical.UbuntuAppLaunch", /* interface */
95+ "ApplicationPaused", /* signal */
96+ "/", /* path */
97+ nullptr, /* arg0 */
98+ G_DBUS_SIGNAL_FLAGS_NONE,
99+ [](GDBusConnection*, const gchar*, const gchar*, const gchar*, const gchar*, GVariant* params,
100+ gpointer user_data) -> void {
101+ auto data = reinterpret_cast<upstartEventData*>(user_data);
102+ auto reg = data->weakReg.lock();
103+
104+ if (!reg)
105+ {
106+ g_warning("Registry object invalid!");
107+ return;
108+ }
109+
110+ auto sparams = std::shared_ptr<GVariant>(g_variant_ref(params), g_variant_unref);
111+ auto manager = std::dynamic_pointer_cast<Base>(reg->impl->jobs);
112+ manager->pauseEventEmitted(manager->sig_appPaused, sparams, reg);
113+ }, /* callback */
114+ data, /* user data */
115+ [](gpointer user_data) {
116+ auto data = reinterpret_cast<upstartEventData*>(user_data);
117+ delete data;
118+ }); /* user data destroy */
119+
120+ return true;
121+ });
122+ });
123+
124+ return sig_appPaused;
125+}
126+
127+/** Grab the signal object for application resumed. If we're not already listing for
128+ those signals this sets up a listener for them. */
129+core::Signal<const std::shared_ptr<Application>&,
130+ const std::shared_ptr<Application::Instance>&,
131+ const std::vector<pid_t>&>&
132+ Base::appResumed()
133+{
134+ std::call_once(flag_appResumed, [this]() {
135+ auto reg = registry_.lock();
136+
137+ reg->impl->thread.executeOnThread<bool>([this, reg]() {
138+ upstartEventData* data = new upstartEventData{reg};
139+
140+ handle_appResumed = g_dbus_connection_signal_subscribe(
141+ reg->impl->_dbus.get(), /* bus */
142+ nullptr, /* sender */
143+ "com.canonical.UbuntuAppLaunch", /* interface */
144+ "ApplicationResumed", /* signal */
145+ "/", /* path */
146+ nullptr, /* arg0 */
147+ G_DBUS_SIGNAL_FLAGS_NONE,
148+ [](GDBusConnection*, const gchar*, const gchar*, const gchar*, const gchar*, GVariant* params,
149+ gpointer user_data) -> void {
150+ auto data = reinterpret_cast<upstartEventData*>(user_data);
151+ auto reg = data->weakReg.lock();
152+
153+ if (!reg)
154+ {
155+ g_warning("Registry object invalid!");
156+ return;
157+ }
158+
159+ auto sparams = std::shared_ptr<GVariant>(g_variant_ref(params), g_variant_unref);
160+ auto manager = std::dynamic_pointer_cast<Base>(reg->impl->jobs);
161+ manager->pauseEventEmitted(manager->sig_appResumed, sparams, reg);
162+ }, /* callback */
163+ data, /* user data */
164+ [](gpointer user_data) {
165+ auto data = reinterpret_cast<upstartEventData*>(user_data);
166+ delete data;
167+ }); /* user data destroy */
168+
169+ return true;
170+ });
171+ });
172+
173+ return sig_appResumed;
174+}
175+
176+/** Take the GVariant of parameters and turn them into an application and
177+ and instance. Easier to read in the smaller function */
178+std::tuple<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>> Base::managerParams(
179+ const std::shared_ptr<GVariant>& params, const std::shared_ptr<Registry>& reg)
180+{
181+ std::shared_ptr<Application> app;
182+ std::shared_ptr<Application::Instance> instance;
183+
184+ const gchar* cappid = nullptr;
185+ g_variant_get(params.get(), "(&s)", &cappid);
186+
187+ auto appid = ubuntu::app_launch::AppID::find(reg, cappid);
188+ app = ubuntu::app_launch::Application::create(appid, reg);
189+
190+ return std::make_tuple(app, instance);
191+}
192+
193+/** Used to store data for manager based signal handlers. Has a link to the
194+ registry and the callback to use in a C++ style. */
195+struct managerEventData
196+{
197+ /* Keeping a weak pointer because the handle is held by
198+ the registry implementation. */
199+ std::weak_ptr<Registry> weakReg;
200+ std::function<void(const std::shared_ptr<Registry>& reg,
201+ const std::shared_ptr<Application>& app,
202+ const std::shared_ptr<Application::Instance>& instance,
203+ const std::shared_ptr<GDBusConnection>&,
204+ const std::string&,
205+ const std::shared_ptr<GVariant>&)>
206+ func;
207+};
208+
209+/** Register for a signal for the manager. All of the signals needed this same
210+ code so it got pulled out into a function. Takes the same of the signal, the registry
211+ that we're using and a function to call after we've messaged all the parameters
212+ into being something C++-ish. */
213+guint Base::managerSignalHelper(const std::shared_ptr<Registry>& reg,
214+ const std::string& signalname,
215+ std::function<void(const std::shared_ptr<Registry>& reg,
216+ const std::shared_ptr<Application>& app,
217+ const std::shared_ptr<Application::Instance>& instance,
218+ const std::shared_ptr<GDBusConnection>&,
219+ const std::string&,
220+ const std::shared_ptr<GVariant>&)> responsefunc)
221+{
222+ managerEventData* focusdata = new managerEventData{reg, responsefunc};
223+
224+ return g_dbus_connection_signal_subscribe(
225+ reg->impl->_dbus.get(), /* bus */
226+ nullptr, /* sender */
227+ "com.canonical.UbuntuAppLaunch", /* interface */
228+ signalname.c_str(), /* signal */
229+ "/", /* path */
230+ nullptr, /* arg0 */
231+ G_DBUS_SIGNAL_FLAGS_NONE,
232+ [](GDBusConnection* cconn, const gchar* csender, const gchar*, const gchar*, const gchar*, GVariant* params,
233+ gpointer user_data) -> void {
234+ auto data = reinterpret_cast<managerEventData*>(user_data);
235+ auto reg = data->weakReg.lock();
236+
237+ if (!reg)
238+ {
239+ g_warning("Registry object invalid!");
240+ return;
241+ }
242+
243+ /* If we're still conneted and the manager has been cleared
244+ we'll just be a no-op */
245+ auto ljobs = std::dynamic_pointer_cast<Base>(reg->impl->jobs);
246+ if (!ljobs->manager_)
247+ {
248+ return;
249+ }
250+
251+ auto vparams = std::shared_ptr<GVariant>(g_variant_ref(params), g_variant_unref);
252+ auto conn = std::shared_ptr<GDBusConnection>(reinterpret_cast<GDBusConnection*>(g_object_ref(cconn)),
253+ [](GDBusConnection* con) { g_clear_object(&con); });
254+ std::string sender = csender;
255+ std::shared_ptr<Application> app;
256+ std::shared_ptr<Application::Instance> instance;
257+
258+ std::tie(app, instance) = managerParams(vparams, reg);
259+
260+ data->func(reg, app, instance, conn, sender, vparams);
261+ },
262+ focusdata,
263+ [](gpointer user_data) {
264+ auto data = reinterpret_cast<managerEventData*>(user_data);
265+ delete data;
266+ }); /* user data destroy */
267+}
268+
269+/** Set the manager for the registry. This includes tracking the pointer
270+ as well as setting up the signals to call back into the manager. The
271+ signals are only setup once per registry even if the manager is cleared
272+ and changed again. They will just be no-op's in those cases.
273+*/
274+void Base::setManager(std::shared_ptr<Registry::Manager> manager)
275+{
276+ if (manager_)
277+ {
278+ throw std::runtime_error("Already have a manager and trying to set another");
279+ }
280+
281+ g_debug("Setting a new manager");
282+ manager_ = manager;
283+
284+ std::call_once(flag_managerSignals, [this]() {
285+ auto reg = registry_.lock();
286+
287+ if (!reg)
288+ {
289+ g_warning("Registry object invalid!");
290+ return;
291+ }
292+
293+ if (!reg->impl->thread.executeOnThread<bool>([this, reg]() {
294+ handle_managerSignalFocus = managerSignalHelper(
295+ reg, "UnityFocusRequest",
296+ [](const std::shared_ptr<Registry>& reg, const std::shared_ptr<Application>& app,
297+ const std::shared_ptr<Application::Instance>& instance,
298+ const std::shared_ptr<GDBusConnection>& conn, const std::string& sender,
299+ const std::shared_ptr<GVariant>& params) {
300+ /* Nothing to do today */
301+ std::dynamic_pointer_cast<Base>(reg->impl->jobs)
302+ ->manager_->focusRequest(app, instance, [](bool response) {
303+ /* NOTE: We have no clue what thread this is gonna be
304+ executed on, but since we're just talking to the GDBus
305+ thread it isn't an issue today. Be careful in changing
306+ this code. */
307+ });
308+ });
309+ handle_managerSignalStarting = managerSignalHelper(
310+ reg, "UnityStartingBroadcast",
311+ [](const std::shared_ptr<Registry>& reg, const std::shared_ptr<Application>& app,
312+ const std::shared_ptr<Application::Instance>& instance,
313+ const std::shared_ptr<GDBusConnection>& conn, const std::string& sender,
314+ const std::shared_ptr<GVariant>& params) {
315+
316+ std::dynamic_pointer_cast<Base>(reg->impl->jobs)
317+ ->manager_->startingRequest(app, instance, [conn, sender, params](bool response) {
318+ /* NOTE: We have no clue what thread this is gonna be
319+ executed on, but since we're just talking to the GDBus
320+ thread it isn't an issue today. Be careful in changing
321+ this code. */
322+ if (response)
323+ {
324+ g_dbus_connection_emit_signal(conn.get(), sender.c_str(), /* destination */
325+ "/", /* path */
326+ "com.canonical.UbuntuAppLaunch", /* interface */
327+ "UnityStartingSignal", /* signal */
328+ params.get(), /* params, the same */
329+ nullptr); /* error */
330+ }
331+ });
332+ });
333+ handle_managerSignalResume = managerSignalHelper(
334+ reg, "UnityResumeRequest",
335+ [](const std::shared_ptr<Registry>& reg, const std::shared_ptr<Application>& app,
336+ const std::shared_ptr<Application::Instance>& instance,
337+ const std::shared_ptr<GDBusConnection>& conn, const std::string& sender,
338+ const std::shared_ptr<GVariant>& params) {
339+ std::dynamic_pointer_cast<Base>(reg->impl->jobs)
340+ ->manager_->resumeRequest(app, instance, [conn, sender, params](bool response) {
341+ /* NOTE: We have no clue what thread this is gonna be
342+ executed on, but since we're just talking to the GDBus
343+ thread it isn't an issue today. Be careful in changing
344+ this code. */
345+ if (response)
346+ {
347+ g_dbus_connection_emit_signal(conn.get(), sender.c_str(), /* destination */
348+ "/", /* path */
349+ "com.canonical.UbuntuAppLaunch", /* interface */
350+ "UnityResumeResponse", /* signal */
351+ params.get(), /* params, the same */
352+ nullptr); /* error */
353+ }
354+ });
355+ });
356+
357+ return true;
358+ }))
359+ {
360+ g_warning("Unable to install manager signals");
361+ }
362+ });
363+}
364+
365+/** Clear the manager pointer */
366+void Base::clearManager()
367+{
368+ g_debug("Clearing the manager");
369+ manager_.reset();
370+}
371+
372 } // namespace manager
373
374 namespace instance
375
376=== modified file 'libubuntu-app-launch/jobs-base.h'
377--- libubuntu-app-launch/jobs-base.h 2017-01-19 03:25:37 +0000
378+++ libubuntu-app-launch/jobs-base.h 2017-01-19 03:25:37 +0000
379@@ -18,7 +18,12 @@
380 */
381
382 #pragma once
383+
384 #include "application.h"
385+#include "registry.h"
386+
387+#include <core/signal.h>
388+#include <gio/gio.h>
389
390 namespace ubuntu
391 {
392@@ -88,7 +93,7 @@
393 {
394 public:
395 Base(const std::shared_ptr<Registry>& registry);
396- virtual ~Base() = default;
397+ virtual ~Base();
398
399 virtual std::shared_ptr<Application::Instance> launch(
400 const AppID& appId,
401@@ -109,8 +114,88 @@
402
403 static std::shared_ptr<Base> determineFactory(std::shared_ptr<Registry> registry);
404
405+ /* Signals to apps */
406+ virtual core::Signal<const std::shared_ptr<Application>&, const std::shared_ptr<Application::Instance>&>&
407+ appStarted() = 0;
408+ virtual core::Signal<const std::shared_ptr<Application>&, const std::shared_ptr<Application::Instance>&>&
409+ appStopped() = 0;
410+ virtual core::Signal<const std::shared_ptr<Application>&,
411+ const std::shared_ptr<Application::Instance>&,
412+ Registry::FailureType>&
413+ appFailed() = 0;
414+ virtual core::Signal<const std::shared_ptr<Application>&,
415+ const std::shared_ptr<Application::Instance>&,
416+ const std::vector<pid_t>&>&
417+ appPaused();
418+ virtual core::Signal<const std::shared_ptr<Application>&,
419+ const std::shared_ptr<Application::Instance>&,
420+ const std::vector<pid_t>&>&
421+ appResumed();
422+
423+ /* App manager */
424+ virtual void setManager(std::shared_ptr<Registry::Manager> manager);
425+ virtual void clearManager();
426+
427 protected:
428+ /** A link to the registry */
429 std::weak_ptr<Registry> registry_;
430+
431+ /** The DBus connection we're connecting to */
432+ std::shared_ptr<GDBusConnection> dbus_;
433+
434+ /** Application manager instance */
435+ std::shared_ptr<Registry::Manager> manager_;
436+
437+ /** Signal object for applications started */
438+ core::Signal<const std::shared_ptr<Application>&, const std::shared_ptr<Application::Instance>&> sig_appStarted;
439+ /** Signal object for applications stopped */
440+ core::Signal<const std::shared_ptr<Application>&, const std::shared_ptr<Application::Instance>&> sig_appStopped;
441+ /** Signal object for applications failed */
442+ core::Signal<const std::shared_ptr<Application>&,
443+ const std::shared_ptr<Application::Instance>&,
444+ Registry::FailureType>
445+ sig_appFailed;
446+ /** Signal object for applications paused */
447+ core::Signal<const std::shared_ptr<Application>&,
448+ const std::shared_ptr<Application::Instance>&,
449+ const std::vector<pid_t>&>
450+ sig_appPaused;
451+ /** Signal object for applications resumed */
452+ core::Signal<const std::shared_ptr<Application>&,
453+ const std::shared_ptr<Application::Instance>&,
454+ const std::vector<pid_t>&>
455+ sig_appResumed;
456+
457+private:
458+ guint handle_managerSignalFocus{0}; /**< GDBus signal watcher handle for app focused signal */
459+ guint handle_managerSignalResume{0}; /**< GDBus signal watcher handle for app resumed signal */
460+ guint handle_managerSignalStarting{0}; /**< GDBus signal watcher handle for app starting signal */
461+ guint handle_appPaused{0}; /**< GDBus signal watcher handle for app paused signal */
462+ guint handle_appResumed{0}; /**< GDBus signal watcher handle for app resumed signal */
463+
464+ std::once_flag flag_managerSignals; /**< Variable to track to see if signal handlers are installed for the manager
465+ signals of focused, resumed and starting */
466+ std::once_flag
467+ flag_appPaused; /**< Variable to track to see if signal handlers are installed for application paused */
468+ std::once_flag flag_appResumed; /**< Variable to track to see if signal handlers are installed for application
469+ resumed */
470+
471+ void pauseEventEmitted(core::Signal<const std::shared_ptr<Application>&,
472+ const std::shared_ptr<Application::Instance>&,
473+ const std::vector<pid_t>&>& signal,
474+ const std::shared_ptr<GVariant>& params,
475+ const std::shared_ptr<Registry>& reg);
476+
477+ static std::tuple<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>> managerParams(
478+ const std::shared_ptr<GVariant>& params, const std::shared_ptr<Registry>& reg);
479+ static guint managerSignalHelper(const std::shared_ptr<Registry>& reg,
480+ const std::string& signalname,
481+ std::function<void(const std::shared_ptr<Registry>& reg,
482+ const std::shared_ptr<Application>& app,
483+ const std::shared_ptr<Application::Instance>& instance,
484+ const std::shared_ptr<GDBusConnection>&,
485+ const std::string&,
486+ const std::shared_ptr<GVariant>&)> responsefunc);
487 };
488
489 } // namespace manager
490
491=== modified file 'libubuntu-app-launch/jobs-upstart.cpp'
492--- libubuntu-app-launch/jobs-upstart.cpp 2017-01-19 03:25:37 +0000
493+++ libubuntu-app-launch/jobs-upstart.cpp 2017-01-19 03:25:37 +0000
494@@ -108,7 +108,7 @@
495 }
496
497 g_debug("Getting instance by name: %s", instance_.c_str());
498- GVariant* vinstance_path =
499+ auto vinstance_path =
500 g_dbus_connection_call_sync(registry_->impl->_dbus.get(), /* connection */
501 DBUS_SERVICE_UPSTART, /* service */
502 jobpath.c_str(), /* object path */
503@@ -145,7 +145,7 @@
504 return 0;
505 }
506
507- GVariant* props_tuple =
508+ auto props_tuple =
509 g_dbus_connection_call_sync(registry_->impl->_dbus.get(), /* connection */
510 DBUS_SERVICE_UPSTART, /* service */
511 instance_path.c_str(), /* object path */
512@@ -166,15 +166,15 @@
513 return 0;
514 }
515
516- GVariant* props_dict = g_variant_get_child_value(props_tuple, 0);
517+ auto props_dict = g_variant_get_child_value(props_tuple, 0);
518
519 pid_t retval = 0;
520- GVariant* processes = g_variant_lookup_value(props_dict, "processes", G_VARIANT_TYPE("a(si)"));
521+ auto processes = g_variant_lookup_value(props_dict, "processes", G_VARIANT_TYPE("a(si)"));
522 if (processes != nullptr && g_variant_n_children(processes) > 0)
523 {
524
525- GVariant* first_entry = g_variant_get_child_value(processes, 0);
526- GVariant* pidv = g_variant_get_child_value(first_entry, 1);
527+ auto first_entry = g_variant_get_child_value(processes, 0);
528+ auto pidv = g_variant_get_child_value(first_entry, 1);
529
530 retval = g_variant_get_int32(pidv);
531
532@@ -267,7 +267,7 @@
533 g_variant_builder_add_value(&builder, g_variant_new_boolean(FALSE)); /* wait */
534
535 GError* error = nullptr;
536- GVariant* stop_variant =
537+ auto stop_variant =
538 g_dbus_connection_call_sync(registry_->impl->_dbus.get(), /* Dbus */
539 DBUS_SERVICE_UPSTART, /* Upstart name */
540 jobpath.c_str(), /* path */
541@@ -499,6 +499,17 @@
542
543 Upstart::~Upstart()
544 {
545+ auto dohandle = [&](guint& handle) {
546+ if (handle != 0)
547+ {
548+ g_dbus_connection_signal_unsubscribe(dbus_.get(), handle);
549+ handle = 0;
550+ }
551+ };
552+
553+ dohandle(handle_appStarted);
554+ dohandle(handle_appStopped);
555+ dohandle(handle_appFailed);
556 }
557
558 /** Launch an application and create a new Upstart instance object to track
559@@ -523,6 +534,13 @@
560 return {};
561
562 auto registry = registry_.lock();
563+
564+ if (!registry)
565+ {
566+ g_warning("Registry object invalid!");
567+ return {};
568+ }
569+
570 return registry->impl->thread.executeOnThread<std::shared_ptr<instance::Upstart>>(
571 [&]() -> std::shared_ptr<instance::Upstart> {
572 auto manager = std::dynamic_pointer_cast<manager::Upstart>(registry->impl->jobs);
573@@ -672,6 +690,233 @@
574 return vect;
575 }
576
577+/** Structure to track the data needed for upstart events. This cleans
578+ up the lifecycle as we're passing this as a pointer through the
579+ GLib calls. */
580+struct upstartEventData
581+{
582+ /** Keeping a weak pointer because the handle is held by
583+ the registry implementation. */
584+ std::weak_ptr<Registry> weakReg;
585+};
586+
587+/** Regex to parse the JOB environment variable from Upstart */
588+const std::regex jobenv_regex{"^JOB=(application\\-(?:click|snap|legacy))$"};
589+/** Regex to parse the INSTANCE environment variable from Upstart */
590+const std::regex instanceenv_regex{"^INSTANCE=(.*?)(?:\\-([0-9]*))?+$"};
591+
592+/** Core of most of the events that come from Upstart directly. Includes parsing of the
593+ Upstart event environment and calling the appropriate signal with the right Application
594+ object and eventually its instance */
595+void Upstart::upstartEventEmitted(
596+ core::Signal<const std::shared_ptr<Application>&, const std::shared_ptr<Application::Instance>&>& signal,
597+ std::shared_ptr<GVariant> params,
598+ const std::shared_ptr<Registry>& reg)
599+{
600+ std::string jobname;
601+ std::string sappid;
602+ std::string instance;
603+
604+ gchar* env = nullptr;
605+ auto envs = g_variant_get_child_value(params.get(), 1);
606+ GVariantIter iter;
607+ g_variant_iter_init(&iter, envs);
608+
609+ while (g_variant_iter_loop(&iter, "s", &env))
610+ {
611+ std::smatch match;
612+ std::string senv = env;
613+
614+ if (std::regex_match(senv, match, jobenv_regex))
615+ {
616+ jobname = match[1].str();
617+ }
618+ else if (std::regex_match(senv, match, instanceenv_regex))
619+ {
620+ sappid = match[1].str();
621+ instance = match[2].str();
622+ }
623+ }
624+
625+ g_variant_unref(envs);
626+
627+ if (jobname.empty())
628+ {
629+ return;
630+ }
631+
632+ g_debug("Upstart Event for job '%s' appid '%s' instance '%s'", jobname.c_str(), sappid.c_str(), instance.c_str());
633+
634+ auto appid = AppID::find(reg, sappid);
635+ auto app = Application::create(appid, reg);
636+
637+ // TODO: Figure otu creating instances
638+
639+ signal(app, {});
640+}
641+
642+/** Grab the signal object for application startup. If we're not already listing for
643+ those signals this sets up a listener for them. */
644+core::Signal<const std::shared_ptr<Application>&, const std::shared_ptr<Application::Instance>&>& Upstart::appStarted()
645+{
646+ std::call_once(flag_appStarted, [this]() {
647+ auto reg = registry_.lock();
648+
649+ reg->impl->thread.executeOnThread<bool>([this, reg]() {
650+ upstartEventData* data = new upstartEventData{reg};
651+
652+ handle_appStarted = g_dbus_connection_signal_subscribe(
653+ reg->impl->_dbus.get(), /* bus */
654+ nullptr, /* sender */
655+ DBUS_INTERFACE_UPSTART, /* interface */
656+ "EventEmitted", /* signal */
657+ DBUS_PATH_UPSTART, /* path */
658+ "started", /* arg0 */
659+ G_DBUS_SIGNAL_FLAGS_NONE,
660+ [](GDBusConnection*, const gchar*, const gchar*, const gchar*, const gchar*, GVariant* params,
661+ gpointer user_data) {
662+ auto data = static_cast<upstartEventData*>(user_data);
663+ auto reg = data->weakReg.lock();
664+
665+ if (!reg)
666+ {
667+ g_warning("Registry object invalid!");
668+ return;
669+ }
670+
671+ auto sparams = std::shared_ptr<GVariant>(g_variant_ref(params), g_variant_unref);
672+ auto upstart = std::dynamic_pointer_cast<Upstart>(reg->impl->jobs);
673+ upstart->upstartEventEmitted(upstart->sig_appStarted, sparams, reg);
674+ }, /* callback */
675+ data, /* user data */
676+ [](gpointer user_data) {
677+ auto data = static_cast<upstartEventData*>(user_data);
678+ delete data;
679+ }); /* user data destroy */
680+
681+ return true;
682+ });
683+ });
684+
685+ return sig_appStarted;
686+}
687+
688+/** Grab the signal object for application stopping. If we're not already listing for
689+ those signals this sets up a listener for them. */
690+core::Signal<const std::shared_ptr<Application>&, const std::shared_ptr<Application::Instance>&>& Upstart::appStopped()
691+{
692+ std::call_once(flag_appStopped, [this]() {
693+ auto reg = registry_.lock();
694+
695+ reg->impl->thread.executeOnThread<bool>([this, reg]() {
696+ upstartEventData* data = new upstartEventData{reg};
697+
698+ handle_appStopped = g_dbus_connection_signal_subscribe(
699+ reg->impl->_dbus.get(), /* bus */
700+ nullptr, /* sender */
701+ DBUS_INTERFACE_UPSTART, /* interface */
702+ "EventEmitted", /* signal */
703+ DBUS_PATH_UPSTART, /* path */
704+ "stopped", /* arg0 */
705+ G_DBUS_SIGNAL_FLAGS_NONE,
706+ [](GDBusConnection*, const gchar*, const gchar*, const gchar*, const gchar*, GVariant* params,
707+ gpointer user_data) {
708+ auto data = static_cast<upstartEventData*>(user_data);
709+ auto reg = data->weakReg.lock();
710+
711+ if (!reg)
712+ {
713+ g_warning("Registry object invalid!");
714+ return;
715+ }
716+
717+ auto sparams = std::shared_ptr<GVariant>(g_variant_ref(params), g_variant_unref);
718+ auto upstart = std::dynamic_pointer_cast<Upstart>(reg->impl->jobs);
719+ upstart->upstartEventEmitted(upstart->sig_appStopped, sparams, reg);
720+ }, /* callback */
721+ data, /* user data */
722+ [](gpointer user_data) {
723+ auto data = static_cast<upstartEventData*>(user_data);
724+ delete data;
725+ }); /* user data destroy */
726+
727+ return true;
728+ });
729+ });
730+
731+ return sig_appStopped;
732+}
733+
734+/** Grab the signal object for application failing. If we're not already listing for
735+ those signals this sets up a listener for them. */
736+core::Signal<const std::shared_ptr<Application>&, const std::shared_ptr<Application::Instance>&, Registry::FailureType>&
737+ Upstart::appFailed()
738+{
739+ std::call_once(flag_appFailed, [this]() {
740+ auto reg = registry_.lock();
741+
742+ reg->impl->thread.executeOnThread<bool>([this, reg]() {
743+ upstartEventData* data = new upstartEventData{reg};
744+
745+ handle_appFailed = g_dbus_connection_signal_subscribe(
746+ reg->impl->_dbus.get(), /* bus */
747+ nullptr, /* sender */
748+ "com.canonical.UbuntuAppLaunch", /* interface */
749+ "ApplicationFailed", /* signal */
750+ "/", /* path */
751+ nullptr, /* arg0 */
752+ G_DBUS_SIGNAL_FLAGS_NONE,
753+ [](GDBusConnection*, const gchar*, const gchar*, const gchar*, const gchar*, GVariant* params,
754+ gpointer user_data) {
755+ auto data = static_cast<upstartEventData*>(user_data);
756+ auto reg = data->weakReg.lock();
757+
758+ if (!reg)
759+ {
760+ g_warning("Registry object invalid!");
761+ return;
762+ }
763+
764+ const gchar* sappid = nullptr;
765+ const gchar* typestr = nullptr;
766+
767+ Registry::FailureType type = Registry::FailureType::CRASH;
768+ g_variant_get(params, "(&s&s)", &sappid, &typestr);
769+
770+ if (g_strcmp0("crash", typestr) == 0)
771+ {
772+ type = Registry::FailureType::CRASH;
773+ }
774+ else if (g_strcmp0("start-failure", typestr) == 0)
775+ {
776+ type = Registry::FailureType::START_FAILURE;
777+ }
778+ else
779+ {
780+ g_warning("Application failure type '%s' unknown, reporting as a crash", typestr);
781+ }
782+
783+ auto appid = AppID::find(reg, sappid);
784+ auto app = Application::create(appid, reg);
785+
786+ /* TODO: Instance issues */
787+
788+ auto upstart = std::dynamic_pointer_cast<Upstart>(reg->impl->jobs);
789+ upstart->sig_appFailed(app, {}, type);
790+ }, /* callback */
791+ data, /* user data */
792+ [](gpointer user_data) {
793+ auto data = static_cast<upstartEventData*>(user_data);
794+ delete data;
795+ }); /* user data destroy */
796+
797+ return true;
798+ });
799+ });
800+
801+ return sig_appFailed;
802+}
803+
804 /** Initialize the CGManager connection, including a timeout to disconnect
805 as CGManager doesn't free resources entirely well. So it's better if
806 we connect and disconnect occationally */
807@@ -741,9 +986,9 @@
808
809 g_debug("Looking for cg manager '%s' group '%s'", name, groupname.c_str());
810
811- GVariant* vtpids = g_dbus_connection_call_sync(
812+ auto vtpids = g_dbus_connection_call_sync(
813 lmanager.get(), /* connection */
814- name, /* bus name for direct connection is NULL */
815+ name, /* bus name for direct connection is nullptr */
816 "/org/linuxcontainers/cgmanager", /* object */
817 "org.linuxcontainers.cgmanager0_0", /* interface */
818 "GetTasksRecursive", /* method */
819@@ -792,7 +1037,7 @@
820 auto registry = registry_.lock();
821 auto path = registry->impl->thread.executeOnThread<std::string>([this, &job, &registry]() -> std::string {
822 GError* error = nullptr;
823- GVariant* job_path_variant =
824+ auto job_path_variant =
825 g_dbus_connection_call_sync(registry->impl->_dbus.get(), /* connection */
826 DBUS_SERVICE_UPSTART, /* service */
827 DBUS_PATH_UPSTART, /* path */
828@@ -848,7 +1093,7 @@
829 return registry->impl->thread.executeOnThread<std::list<std::string>>(
830 [this, &job, &jobpath, &registry]() -> std::list<std::string> {
831 GError* error = nullptr;
832- GVariant* instance_tuple =
833+ auto instance_tuple =
834 g_dbus_connection_call_sync(registry->impl->_dbus.get(), /* connection */
835 DBUS_SERVICE_UPSTART, /* service */
836 jobpath.c_str(), /* object path */
837@@ -883,7 +1128,7 @@
838
839 while (g_variant_iter_loop(&instance_iter, "&o", &instance_path))
840 {
841- GVariant* props_tuple =
842+ auto props_tuple =
843 g_dbus_connection_call_sync(registry->impl->_dbus.get(), /* connection */
844 DBUS_SERVICE_UPSTART, /* service */
845 instance_path, /* object path */
846@@ -909,7 +1154,7 @@
847 auto namev = g_variant_lookup_value(props_dict, "name", G_VARIANT_TYPE_STRING);
848 if (namev != nullptr)
849 {
850- auto name = g_variant_get_string(namev, NULL);
851+ auto name = g_variant_get_string(namev, nullptr);
852 g_debug("Adding instance for job '%s': %s", job.c_str(), name);
853 instances.push_back(name);
854 g_variant_unref(namev);
855
856=== modified file 'libubuntu-app-launch/jobs-upstart.h'
857--- libubuntu-app-launch/jobs-upstart.h 2017-01-19 03:25:37 +0000
858+++ libubuntu-app-launch/jobs-upstart.h 2017-01-19 03:25:37 +0000
859@@ -54,6 +54,16 @@
860
861 virtual std::vector<std::shared_ptr<instance::Base>> instances(const AppID& appID, const std::string& job) override;
862
863+ /* Signals to apps */
864+ virtual core::Signal<const std::shared_ptr<Application>&, const std::shared_ptr<Application::Instance>&>&
865+ appStarted() override;
866+ virtual core::Signal<const std::shared_ptr<Application>&, const std::shared_ptr<Application::Instance>&>&
867+ appStopped() override;
868+ virtual core::Signal<const std::shared_ptr<Application>&,
869+ const std::shared_ptr<Application::Instance>&,
870+ Registry::FailureType>&
871+ appFailed() override;
872+
873 std::vector<pid_t> pidsFromCgroup(const std::string& jobpath);
874
875 std::list<std::string> upstartInstancesForJob(const std::string& job);
876@@ -67,6 +77,22 @@
877 /** Getting the Upstart job path is relatively expensive in
878 that it requires a DBus call. Worth keeping a cache of. */
879 std::map<std::string, std::string> upstartJobPathCache_;
880+
881+ guint handle_appStarted{0}; /**< GDBus signal watcher handle for app started signal */
882+ guint handle_appStopped{0}; /**< GDBus signal watcher handle for app stopped signal */
883+ guint handle_appFailed{0}; /**< GDBus signal watcher handle for app failed signal */
884+
885+ std::once_flag flag_appStarted; /**< Variable to track to see if signal handlers are installed for application
886+ started */
887+ std::once_flag flag_appStopped; /**< Variable to track to see if signal handlers are installed for application
888+ stopped */
889+ std::once_flag
890+ flag_appFailed; /**< Variable to track to see if signal handlers are installed for application failed */
891+
892+ void upstartEventEmitted(
893+ core::Signal<const std::shared_ptr<Application>&, const std::shared_ptr<Application::Instance>&>& signal,
894+ std::shared_ptr<GVariant> params,
895+ const std::shared_ptr<Registry>& reg);
896 };
897
898 } // namespace manager
899
900=== modified file 'libubuntu-app-launch/registry-impl.cpp'
901--- libubuntu-app-launch/registry-impl.cpp 2017-01-19 03:25:37 +0000
902+++ libubuntu-app-launch/registry-impl.cpp 2017-01-19 03:25:37 +0000
903@@ -36,23 +36,6 @@
904 zgLog_.reset();
905 jobs.reset();
906
907- auto dohandle = [&](guint& handle) {
908- if (handle != 0)
909- {
910- g_dbus_connection_signal_unsubscribe(_dbus.get(), handle);
911- handle = 0;
912- }
913- };
914-
915- dohandle(handle_appStarted);
916- dohandle(handle_appStopped);
917- dohandle(handle_appFailed);
918- dohandle(handle_appPaused);
919- dohandle(handle_appResumed);
920- dohandle(handle_managerSignalFocus);
921- dohandle(handle_managerSignalResume);
922- dohandle(handle_managerSignalStarting);
923-
924 if (_dbus)
925 g_dbus_connection_flush_sync(_dbus.get(), nullptr, nullptr);
926 _dbus.reset();
927@@ -290,208 +273,6 @@
928 return _iconFinders[basePath];
929 }
930
931-/** Structure to track the data needed for upstart events. This cleans
932- up the lifecycle as we're passing this as a pointer through the
933- GLib calls. */
934-struct upstartEventData
935-{
936- /** Keeping a weak pointer because the handle is held by
937- the registry implementation. */
938- std::weak_ptr<Registry> weakReg;
939-};
940-
941-/** Take the GVariant of parameters and turn them into an application and
942- and instance. Easier to read in the smaller function */
943-std::tuple<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>> Registry::Impl::managerParams(
944- const std::shared_ptr<GVariant>& params, const std::shared_ptr<Registry>& reg)
945-{
946- std::shared_ptr<Application> app;
947- std::shared_ptr<Application::Instance> instance;
948-
949- const gchar* cappid = nullptr;
950- g_variant_get(params.get(), "(&s)", &cappid);
951-
952- if (cappid != nullptr)
953- {
954- auto appid = ubuntu::app_launch::AppID::find(reg, cappid);
955- app = ubuntu::app_launch::Application::create(appid, reg);
956- }
957-
958- return std::make_tuple(app, instance);
959-}
960-
961-/** Used to store data for manager based signal handlers. Has a link to the
962- registry and the callback to use in a C++ style. */
963-struct managerEventData
964-{
965- /* Keeping a weak pointer because the handle is held by
966- the registry implementation. */
967- std::weak_ptr<Registry> weakReg;
968- std::function<void(const std::shared_ptr<Registry>& reg,
969- const std::shared_ptr<Application>& app,
970- const std::shared_ptr<Application::Instance>& instance,
971- const std::shared_ptr<GDBusConnection>& dbus,
972- const std::string& sender,
973- const std::shared_ptr<GVariant>& params)>
974- func;
975-};
976-
977-/** Register for a signal for the manager. All of the signals needed this same
978- code so it got pulled out into a function. Takes the same of the signal, the registry
979- that we're using and a function to call after we've messaged all the parameters
980- into being something C++-ish. */
981-guint Registry::Impl::managerSignalHelper(const std::shared_ptr<Registry>& reg,
982- const std::string& signalname,
983- std::function<void(const std::shared_ptr<Registry>& reg,
984- const std::shared_ptr<Application>& app,
985- const std::shared_ptr<Application::Instance>& instance,
986- const std::shared_ptr<GDBusConnection>& dbus,
987- const std::string& sender,
988- const std::shared_ptr<GVariant>& params)> responsefunc)
989-{
990- auto focusdata = new managerEventData{reg, responsefunc};
991-
992- return g_dbus_connection_signal_subscribe(
993- reg->impl->_dbus.get(), /* bus */
994- nullptr, /* sender */
995- "com.canonical.UbuntuAppLaunch", /* interface */
996- signalname.c_str(), /* signal */
997- "/", /* path */
998- nullptr, /* arg0 */
999- G_DBUS_SIGNAL_FLAGS_NONE,
1000- [](GDBusConnection* cconn, const gchar* csender, const gchar*, const gchar*, const gchar*, GVariant* params,
1001- gpointer user_data) {
1002- auto data = static_cast<managerEventData*>(user_data);
1003- auto reg = data->weakReg.lock();
1004-
1005- if (!reg)
1006- {
1007- g_warning("Registry object invalid!");
1008- return;
1009- }
1010-
1011- /* If we're still connected and the manager has been cleared
1012- we'll just be a no-op */
1013- if (!reg->impl->manager_)
1014- {
1015- return;
1016- }
1017-
1018- auto vparams = std::shared_ptr<GVariant>(g_variant_ref(params), g_variant_unref);
1019- auto conn = std::shared_ptr<GDBusConnection>(reinterpret_cast<GDBusConnection*>(g_object_ref(cconn)),
1020- [](GDBusConnection* con) { g_clear_object(&con); });
1021- std::string sender = csender;
1022- std::shared_ptr<Application> app;
1023- std::shared_ptr<Application::Instance> instance;
1024-
1025- std::tie(app, instance) = managerParams(vparams, reg);
1026-
1027- data->func(reg, app, instance, conn, sender, vparams);
1028- },
1029- focusdata,
1030- [](gpointer user_data) {
1031- auto data = static_cast<managerEventData*>(user_data);
1032- delete data;
1033- }); /* user data destroy */
1034-}
1035-
1036-/** Set the manager for the registry. This includes tracking the pointer
1037- as well as setting up the signals to call back into the manager. The
1038- signals are only setup once per registry even if the manager is cleared
1039- and changed again. They will just be no-op's in those cases.
1040-*/
1041-void Registry::Impl::setManager(const std::shared_ptr<Registry::Manager>& manager, const std::shared_ptr<Registry>& reg)
1042-{
1043- if (!reg)
1044- {
1045- throw std::invalid_argument("Passed null registry to setManager()");
1046- }
1047-
1048- if (reg->impl->manager_)
1049- {
1050- throw std::logic_error("Already have a manager and trying to set another");
1051- }
1052-
1053- g_debug("Setting a new manager");
1054- reg->impl->manager_ = manager;
1055-
1056- std::call_once(reg->impl->flag_managerSignals, [reg]() {
1057- if (!reg->impl->thread.executeOnThread<bool>([reg]() {
1058- reg->impl->handle_managerSignalFocus = managerSignalHelper(
1059- reg, "UnityFocusRequest",
1060- [](const std::shared_ptr<Registry>& reg, const std::shared_ptr<Application>& app,
1061- const std::shared_ptr<Application::Instance>& instance,
1062- const std::shared_ptr<GDBusConnection>& /* conn */, const std::string& /* sender */,
1063- const std::shared_ptr<GVariant>& /* params */) {
1064- /* Nothing to do today */
1065- reg->impl->manager_->focusRequest(app, instance, [](bool response) {
1066- /* NOTE: We have no clue what thread this is gonna be
1067- executed on, but since we're just talking to the GDBus
1068- thread it isn't an issue today. Be careful in changing
1069- this code. */
1070- });
1071- });
1072- reg->impl->handle_managerSignalStarting = managerSignalHelper(
1073- reg, "UnityStartingBroadcast",
1074- [](const std::shared_ptr<Registry>& reg, const std::shared_ptr<Application>& app,
1075- const std::shared_ptr<Application::Instance>& instance,
1076- const std::shared_ptr<GDBusConnection>& conn, const std::string& sender,
1077- const std::shared_ptr<GVariant>& params) {
1078-
1079- reg->impl->manager_->startingRequest(app, instance, [conn, sender, params](bool response) {
1080- /* NOTE: We have no clue what thread this is gonna be
1081- executed on, but since we're just talking to the GDBus
1082- thread it isn't an issue today. Be careful in changing
1083- this code. */
1084- if (response)
1085- {
1086- g_dbus_connection_emit_signal(conn.get(), sender.c_str(), /* destination */
1087- "/", /* path */
1088- "com.canonical.UbuntuAppLaunch", /* interface */
1089- "UnityStartingSignal", /* signal */
1090- params.get(), /* params, the same */
1091- nullptr); /* error */
1092- }
1093- });
1094- });
1095- reg->impl->handle_managerSignalResume = managerSignalHelper(
1096- reg, "UnityResumeRequest",
1097- [](const std::shared_ptr<Registry>& reg, const std::shared_ptr<Application>& app,
1098- const std::shared_ptr<Application::Instance>& instance,
1099- const std::shared_ptr<GDBusConnection>& conn, const std::string& sender,
1100- const std::shared_ptr<GVariant>& params) {
1101- reg->impl->manager_->resumeRequest(app, instance, [conn, sender, params](bool response) {
1102- /* NOTE: We have no clue what thread this is gonna be
1103- executed on, but since we're just talking to the GDBus
1104- thread it isn't an issue today. Be careful in changing
1105- this code. */
1106- if (response)
1107- {
1108- g_dbus_connection_emit_signal(conn.get(), sender.c_str(), /* destination */
1109- "/", /* path */
1110- "com.canonical.UbuntuAppLaunch", /* interface */
1111- "UnityResumeResponse", /* signal */
1112- params.get(), /* params, the same */
1113- nullptr); /* error */
1114- }
1115- });
1116- });
1117-
1118- return true;
1119- }))
1120- {
1121- g_warning("Unable to install manager signals");
1122- }
1123- });
1124-}
1125-
1126-/** Clear the manager pointer */
1127-void Registry::Impl::clearManager()
1128-{
1129- g_debug("Clearing the manager");
1130- manager_.reset();
1131-}
1132-
1133 /** App start watching, if we're registered for the signal we
1134 can't wait on it. We are making this static right now because
1135 we need it to go across the C and C++ APIs smoothly, and those
1136@@ -513,340 +294,5 @@
1137 return watchingAppStarting_;
1138 }
1139
1140-/** Regex to parse the JOB environment variable from Upstart */
1141-const std::regex jobenv_regex{"^JOB=(application\\-(?:click|snap|legacy))$"};
1142-/** Regex to parse the INSTANCE environment variable from Upstart */
1143-const std::regex instanceenv_regex{"^INSTANCE=(.*?)(?:\\-([0-9]*))?+$"};
1144-
1145-/** Core of most of the events that come from Upstart directly. Includes parsing of the
1146- Upstart event environment and calling the appropriate signal with the right Application
1147- object and eventually its instance */
1148-void Registry::Impl::upstartEventEmitted(
1149- core::Signal<const std::shared_ptr<Application>&, const std::shared_ptr<Application::Instance>&>& signal,
1150- const std::shared_ptr<GVariant>& params,
1151- const std::shared_ptr<Registry>& reg)
1152-{
1153- std::string jobname;
1154- std::string sappid;
1155- std::string instance;
1156-
1157- gchar* env = nullptr;
1158- auto envs = g_variant_get_child_value(params.get(), 1);
1159- GVariantIter iter;
1160- g_variant_iter_init(&iter, envs);
1161-
1162- while (g_variant_iter_loop(&iter, "s", &env))
1163- {
1164- std::smatch match;
1165- std::string senv = env;
1166-
1167- if (std::regex_match(senv, match, jobenv_regex))
1168- {
1169- jobname = match[1].str();
1170- }
1171- else if (std::regex_match(senv, match, instanceenv_regex))
1172- {
1173- sappid = match[1].str();
1174- instance = match[2].str();
1175- }
1176- }
1177-
1178- g_variant_unref(envs);
1179-
1180- if (jobname.empty())
1181- {
1182- return;
1183- }
1184-
1185- g_debug("Upstart Event for job '%s' appid '%s' instance '%s'", jobname.c_str(), sappid.c_str(), instance.c_str());
1186-
1187- auto appid = AppID::find(reg, sappid);
1188- auto app = Application::create(appid, reg);
1189-
1190- // TODO: Figure out creating instances
1191-
1192- signal(app, {});
1193-}
1194-
1195-/** Grab the signal object for application startup. If we're not already listing for
1196- those signals this sets up a listener for them. */
1197-core::Signal<const std::shared_ptr<Application>&, const std::shared_ptr<Application::Instance>&>&
1198- Registry::Impl::appStarted(const std::shared_ptr<Registry>& reg)
1199-{
1200- std::call_once(flag_appStarted, [reg]() {
1201- reg->impl->thread.executeOnThread<bool>([reg]() {
1202- auto data = new upstartEventData{reg};
1203-
1204- reg->impl->handle_appStarted = g_dbus_connection_signal_subscribe(
1205- reg->impl->_dbus.get(), /* bus */
1206- nullptr, /* sender */
1207- DBUS_INTERFACE_UPSTART, /* interface */
1208- "EventEmitted", /* signal */
1209- DBUS_PATH_UPSTART, /* path */
1210- "started", /* arg0 */
1211- G_DBUS_SIGNAL_FLAGS_NONE,
1212- [](GDBusConnection*, const gchar*, const gchar*, const gchar*, const gchar*, GVariant* params,
1213- gpointer user_data) {
1214- auto data = static_cast<upstartEventData*>(user_data);
1215- auto reg = data->weakReg.lock();
1216-
1217- if (!reg)
1218- {
1219- g_warning("Registry object invalid!");
1220- return;
1221- }
1222-
1223- auto sparams = std::shared_ptr<GVariant>(g_variant_ref(params), g_variant_unref);
1224- reg->impl->upstartEventEmitted(reg->impl->sig_appStarted, sparams, reg);
1225- }, /* callback */
1226- data, /* user data */
1227- [](gpointer user_data) {
1228- auto data = static_cast<upstartEventData*>(user_data);
1229- delete data;
1230- }); /* user data destroy */
1231-
1232- return true;
1233- });
1234- });
1235-
1236- return sig_appStarted;
1237-}
1238-
1239-/** Grab the signal object for application stopping. If we're not already listing for
1240- those signals this sets up a listener for them. */
1241-core::Signal<const std::shared_ptr<Application>&, const std::shared_ptr<Application::Instance>&>&
1242- Registry::Impl::appStopped(const std::shared_ptr<Registry>& reg)
1243-{
1244- std::call_once(flag_appStopped, [reg]() {
1245- reg->impl->thread.executeOnThread<bool>([reg]() {
1246- auto data = new upstartEventData{reg};
1247-
1248- reg->impl->handle_appStopped = g_dbus_connection_signal_subscribe(
1249- reg->impl->_dbus.get(), /* bus */
1250- nullptr, /* sender */
1251- DBUS_INTERFACE_UPSTART, /* interface */
1252- "EventEmitted", /* signal */
1253- DBUS_PATH_UPSTART, /* path */
1254- "stopped", /* arg0 */
1255- G_DBUS_SIGNAL_FLAGS_NONE,
1256- [](GDBusConnection*, const gchar*, const gchar*, const gchar*, const gchar*, GVariant* params,
1257- gpointer user_data) {
1258- auto data = static_cast<upstartEventData*>(user_data);
1259- auto reg = data->weakReg.lock();
1260-
1261- if (!reg)
1262- {
1263- g_warning("Registry object invalid!");
1264- return;
1265- }
1266-
1267- auto sparams = std::shared_ptr<GVariant>(g_variant_ref(params), g_variant_unref);
1268- reg->impl->upstartEventEmitted(reg->impl->sig_appStopped, sparams, reg);
1269- }, /* callback */
1270- data, /* user data */
1271- [](gpointer user_data) {
1272- auto data = static_cast<upstartEventData*>(user_data);
1273- delete data;
1274- }); /* user data destroy */
1275-
1276- return true;
1277- });
1278- });
1279-
1280- return sig_appStopped;
1281-}
1282-
1283-/** Grab the signal object for application failing. If we're not already listing for
1284- those signals this sets up a listener for them. */
1285-core::Signal<const std::shared_ptr<Application>&, const std::shared_ptr<Application::Instance>&, Registry::FailureType>&
1286- Registry::Impl::appFailed(const std::shared_ptr<Registry>& reg)
1287-{
1288- std::call_once(flag_appFailed, [reg]() {
1289- reg->impl->thread.executeOnThread<bool>([reg]() {
1290- auto data = new upstartEventData{reg};
1291-
1292- reg->impl->handle_appFailed = g_dbus_connection_signal_subscribe(
1293- reg->impl->_dbus.get(), /* bus */
1294- nullptr, /* sender */
1295- "com.canonical.UbuntuAppLaunch", /* interface */
1296- "ApplicationFailed", /* signal */
1297- "/", /* path */
1298- nullptr, /* arg0 */
1299- G_DBUS_SIGNAL_FLAGS_NONE,
1300- [](GDBusConnection*, const gchar*, const gchar*, const gchar*, const gchar*, GVariant* params,
1301- gpointer user_data) {
1302- auto data = static_cast<upstartEventData*>(user_data);
1303- auto reg = data->weakReg.lock();
1304-
1305- if (!reg)
1306- {
1307- g_warning("Registry object invalid!");
1308- return;
1309- }
1310-
1311- const gchar* sappid = nullptr;
1312- const gchar* typestr = nullptr;
1313-
1314- Registry::FailureType type = Registry::FailureType::CRASH;
1315- g_variant_get(params, "(&s&s)", &sappid, &typestr);
1316-
1317- if (g_strcmp0("crash", typestr) == 0)
1318- {
1319- type = Registry::FailureType::CRASH;
1320- }
1321- else if (g_strcmp0("start-failure", typestr) == 0)
1322- {
1323- type = Registry::FailureType::START_FAILURE;
1324- }
1325- else
1326- {
1327- g_warning("Application failure type '%s' unknown, reporting as a crash", typestr);
1328- }
1329-
1330- auto appid = AppID::find(reg, sappid);
1331- auto app = Application::create(appid, reg);
1332-
1333- /* TODO: Instance issues */
1334-
1335- reg->impl->sig_appFailed(app, {}, type);
1336- }, /* callback */
1337- data, /* user data */
1338- [](gpointer user_data) {
1339- auto data = static_cast<upstartEventData*>(user_data);
1340- delete data;
1341- }); /* user data destroy */
1342-
1343- return true;
1344- });
1345- });
1346-
1347- return sig_appFailed;
1348-}
1349-
1350-/** Core handler for pause and resume events. Includes turning the GVariant
1351- pid list into a std::vector and getting the application object. */
1352-void Registry::Impl::pauseEventEmitted(core::Signal<const std::shared_ptr<Application>&,
1353- const std::shared_ptr<Application::Instance>&,
1354- const std::vector<pid_t>&>& signal,
1355- const std::shared_ptr<GVariant>& params,
1356- const std::shared_ptr<Registry>& reg)
1357-{
1358- std::vector<pid_t> pids;
1359- auto vappid = g_variant_get_child_value(params.get(), 0);
1360- auto vpids = g_variant_get_child_value(params.get(), 1);
1361- guint64 pid;
1362- GVariantIter thispid;
1363- g_variant_iter_init(&thispid, vpids);
1364-
1365- while (g_variant_iter_loop(&thispid, "t", &pid))
1366- {
1367- pids.emplace_back(pid);
1368- }
1369-
1370- auto cappid = g_variant_get_string(vappid, nullptr);
1371- auto appid = ubuntu::app_launch::AppID::find(reg, cappid);
1372- auto app = Application::create(appid, reg);
1373-
1374- /* TODO: Instance */
1375- signal(app, {}, pids);
1376-
1377- g_variant_unref(vappid);
1378- g_variant_unref(vpids);
1379-
1380- return;
1381-}
1382-
1383-/** Grab the signal object for application paused. If we're not already listing for
1384- those signals this sets up a listener for them. */
1385-core::Signal<const std::shared_ptr<Application>&,
1386- const std::shared_ptr<Application::Instance>&,
1387- const std::vector<pid_t>&>&
1388- Registry::Impl::appPaused(const std::shared_ptr<Registry>& reg)
1389-{
1390- std::call_once(flag_appPaused, [&]() {
1391- reg->impl->thread.executeOnThread<bool>([reg]() {
1392- auto data = new upstartEventData{reg};
1393-
1394- reg->impl->handle_appPaused = g_dbus_connection_signal_subscribe(
1395- reg->impl->_dbus.get(), /* bus */
1396- nullptr, /* sender */
1397- "com.canonical.UbuntuAppLaunch", /* interface */
1398- "ApplicationPaused", /* signal */
1399- "/", /* path */
1400- nullptr, /* arg0 */
1401- G_DBUS_SIGNAL_FLAGS_NONE,
1402- [](GDBusConnection*, const gchar*, const gchar*, const gchar*, const gchar*, GVariant* params,
1403- gpointer user_data) {
1404- auto data = static_cast<upstartEventData*>(user_data);
1405- auto reg = data->weakReg.lock();
1406-
1407- if (!reg)
1408- {
1409- g_warning("Registry object invalid!");
1410- return;
1411- }
1412-
1413- auto sparams = std::shared_ptr<GVariant>(g_variant_ref(params), g_variant_unref);
1414- reg->impl->pauseEventEmitted(reg->impl->sig_appPaused, sparams, reg);
1415- }, /* callback */
1416- data, /* user data */
1417- [](gpointer user_data) {
1418- auto data = static_cast<upstartEventData*>(user_data);
1419- delete data;
1420- }); /* user data destroy */
1421-
1422- return true;
1423- });
1424- });
1425-
1426- return sig_appPaused;
1427-}
1428-
1429-/** Grab the signal object for application resumed. If we're not already listing for
1430- those signals this sets up a listener for them. */
1431-core::Signal<const std::shared_ptr<Application>&,
1432- const std::shared_ptr<Application::Instance>&,
1433- const std::vector<pid_t>&>&
1434- Registry::Impl::appResumed(const std::shared_ptr<Registry>& reg)
1435-{
1436- std::call_once(flag_appResumed, [&]() {
1437- reg->impl->thread.executeOnThread<bool>([reg]() {
1438- auto data = new upstartEventData{reg};
1439-
1440- reg->impl->handle_appResumed = g_dbus_connection_signal_subscribe(
1441- reg->impl->_dbus.get(), /* bus */
1442- nullptr, /* sender */
1443- "com.canonical.UbuntuAppLaunch", /* interface */
1444- "ApplicationResumed", /* signal */
1445- "/", /* path */
1446- nullptr, /* arg0 */
1447- G_DBUS_SIGNAL_FLAGS_NONE,
1448- [](GDBusConnection*, const gchar*, const gchar*, const gchar*, const gchar*, GVariant* params,
1449- gpointer user_data) {
1450- auto data = static_cast<upstartEventData*>(user_data);
1451- auto reg = data->weakReg.lock();
1452-
1453- if (!reg)
1454- {
1455- g_warning("Registry object invalid!");
1456- return;
1457- }
1458-
1459- auto sparams = std::shared_ptr<GVariant>(g_variant_ref(params), g_variant_unref);
1460- reg->impl->pauseEventEmitted(reg->impl->sig_appResumed, sparams, reg);
1461- }, /* callback */
1462- data, /* user data */
1463- [](gpointer user_data) {
1464- auto data = static_cast<upstartEventData*>(user_data);
1465- delete data;
1466- }); /* user data destroy */
1467-
1468- return true;
1469- });
1470- });
1471-
1472- return sig_appResumed;
1473-}
1474-
1475 } // namespace app_launch
1476 } // namespace ubuntu
1477
1478=== modified file 'libubuntu-app-launch/registry-impl.h'
1479--- libubuntu-app-launch/registry-impl.h 2017-01-19 03:25:37 +0000
1480+++ libubuntu-app-launch/registry-impl.h 2017-01-19 03:25:37 +0000
1481@@ -78,22 +78,6 @@
1482 static std::string printJson(std::shared_ptr<JsonObject> jsonobj);
1483 static std::string printJson(std::shared_ptr<JsonNode> jsonnode);
1484
1485- /* Signals to discover what is happening to apps */
1486- core::Signal<const std::shared_ptr<Application>&, const std::shared_ptr<Application::Instance>&>& appStarted(
1487- const std::shared_ptr<Registry>& reg);
1488- core::Signal<const std::shared_ptr<Application>&, const std::shared_ptr<Application::Instance>&>& appStopped(
1489- const std::shared_ptr<Registry>& reg);
1490- core::Signal<const std::shared_ptr<Application>&, const std::shared_ptr<Application::Instance>&, FailureType>&
1491- appFailed(const std::shared_ptr<Registry>& reg);
1492- core::Signal<const std::shared_ptr<Application>&,
1493- const std::shared_ptr<Application::Instance>&,
1494- const std::vector<pid_t>&>&
1495- appPaused(const std::shared_ptr<Registry>& reg);
1496- core::Signal<const std::shared_ptr<Application>&,
1497- const std::shared_ptr<Application::Instance>&,
1498- const std::vector<pid_t>&>&
1499- appResumed(const std::shared_ptr<Registry>& reg);
1500-
1501 /* Signal Hints */
1502 /* NOTE: Static because we don't have registry instances in the C
1503 code right now. We want these to not be static in the future */
1504@@ -101,72 +85,11 @@
1505 static bool isWatchingAppStarting();
1506
1507 private:
1508- Registry* _registry; /**< The Registry that we're spawned from */
1509- std::shared_ptr<Registry::Manager> manager_; /**< Application manager if registered */
1510+ Registry* _registry; /**< The Registry that we're spawned from */
1511
1512 std::shared_ptr<ClickDB> _clickDB; /**< Shared instance of the Click Database */
1513 std::shared_ptr<ClickUser> _clickUser; /**< Click database filtered by the current user */
1514
1515- /** Signal object for applications started */
1516- core::Signal<const std::shared_ptr<Application>&, const std::shared_ptr<Application::Instance>&> sig_appStarted;
1517- /** Signal object for applications stopped */
1518- core::Signal<const std::shared_ptr<Application>&, const std::shared_ptr<Application::Instance>&> sig_appStopped;
1519- /** Signal object for applications failed */
1520- core::Signal<const std::shared_ptr<Application>&, const std::shared_ptr<Application::Instance>&, FailureType>
1521- sig_appFailed;
1522- /** Signal object for applications paused */
1523- core::Signal<const std::shared_ptr<Application>&,
1524- const std::shared_ptr<Application::Instance>&,
1525- const std::vector<pid_t>&>
1526- sig_appPaused;
1527- /** Signal object for applications resumed */
1528- core::Signal<const std::shared_ptr<Application>&,
1529- const std::shared_ptr<Application::Instance>&,
1530- const std::vector<pid_t>&>
1531- sig_appResumed;
1532-
1533- guint handle_appStarted{0}; /**< GDBus signal watcher handle for app started signal */
1534- guint handle_appStopped{0}; /**< GDBus signal watcher handle for app stopped signal */
1535- guint handle_appFailed{0}; /**< GDBus signal watcher handle for app failed signal */
1536- guint handle_appPaused{0}; /**< GDBus signal watcher handle for app paused signal */
1537- guint handle_appResumed{0}; /**< GDBus signal watcher handle for app resumed signal */
1538- guint handle_managerSignalFocus{0}; /**< GDBus signal watcher handle for app focused signal */
1539- guint handle_managerSignalResume{0}; /**< GDBus signal watcher handle for app resumed signal */
1540- guint handle_managerSignalStarting{0}; /**< GDBus signal watcher handle for app starting signal */
1541-
1542- std::once_flag flag_appStarted; /**< Variable to track to see if signal handlers are installed for application
1543- started */
1544- std::once_flag flag_appStopped; /**< Variable to track to see if signal handlers are installed for application
1545- stopped */
1546- std::once_flag
1547- flag_appFailed; /**< Variable to track to see if signal handlers are installed for application failed */
1548- std::once_flag
1549- flag_appPaused; /**< Variable to track to see if signal handlers are installed for application paused */
1550- std::once_flag flag_appResumed; /**< Variable to track to see if signal handlers are installed for application
1551- resumed */
1552- std::once_flag flag_managerSignals; /**< Variable to track to see if signal handlers are installed for the manager
1553- signals of focused, resumed and starting */
1554-
1555- void upstartEventEmitted(
1556- core::Signal<const std::shared_ptr<Application>&, const std::shared_ptr<Application::Instance>&>& signal,
1557- const std::shared_ptr<GVariant>& params,
1558- const std::shared_ptr<Registry>& reg);
1559- void pauseEventEmitted(core::Signal<const std::shared_ptr<Application>&,
1560- const std::shared_ptr<Application::Instance>&,
1561- const std::vector<pid_t>&>& signal,
1562- const std::shared_ptr<GVariant>& params,
1563- const std::shared_ptr<Registry>& reg);
1564- static std::tuple<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>> managerParams(
1565- const std::shared_ptr<GVariant>& params, const std::shared_ptr<Registry>& reg);
1566- static guint managerSignalHelper(const std::shared_ptr<Registry>& reg,
1567- const std::string& signalname,
1568- std::function<void(const std::shared_ptr<Registry>& reg,
1569- const std::shared_ptr<Application>& app,
1570- const std::shared_ptr<Application::Instance>& instance,
1571- const std::shared_ptr<GDBusConnection>&,
1572- const std::string&,
1573- const std::shared_ptr<GVariant>&)> responsefunc);
1574-
1575 void initClick();
1576
1577 /** Shared instance of the Zeitgeist Log */
1578
1579=== modified file 'libubuntu-app-launch/registry.cpp'
1580--- libubuntu-app-launch/registry.cpp 2017-01-19 03:25:37 +0000
1581+++ libubuntu-app-launch/registry.cpp 2017-01-19 03:25:37 +0000
1582@@ -80,14 +80,29 @@
1583 return list;
1584 }
1585
1586+/* Quick little helper to bundle up standard code */
1587+inline void setJobs(const std::shared_ptr<Registry>& registry)
1588+{
1589+ if (!registry->impl->jobs)
1590+ {
1591+ registry->impl->jobs = jobs::manager::Base::determineFactory(registry);
1592+ }
1593+}
1594+
1595 void Registry::setManager(const std::shared_ptr<Manager>& manager, const std::shared_ptr<Registry>& registry)
1596 {
1597- Registry::Impl::setManager(manager, registry);
1598+ setJobs(registry);
1599+ registry->impl->jobs->setManager(manager);
1600 }
1601
1602 void Registry::clearManager()
1603 {
1604- impl->clearManager();
1605+ if (!impl->jobs)
1606+ {
1607+ return;
1608+ }
1609+
1610+ impl->jobs->clearManager();
1611 }
1612
1613 std::shared_ptr<Registry> defaultRegistry;
1614@@ -109,19 +124,22 @@
1615 core::Signal<const std::shared_ptr<Application>&, const std::shared_ptr<Application::Instance>&>& Registry::appStarted(
1616 const std::shared_ptr<Registry>& reg)
1617 {
1618- return reg->impl->appStarted(reg);
1619+ setJobs(reg);
1620+ return reg->impl->jobs->appStarted();
1621 }
1622
1623 core::Signal<const std::shared_ptr<Application>&, const std::shared_ptr<Application::Instance>&>& Registry::appStopped(
1624 const std::shared_ptr<Registry>& reg)
1625 {
1626- return reg->impl->appStopped(reg);
1627+ setJobs(reg);
1628+ return reg->impl->jobs->appStopped();
1629 }
1630
1631 core::Signal<const std::shared_ptr<Application>&, const std::shared_ptr<Application::Instance>&, Registry::FailureType>&
1632 Registry::appFailed(const std::shared_ptr<Registry>& reg)
1633 {
1634- return reg->impl->appFailed(reg);
1635+ setJobs(reg);
1636+ return reg->impl->jobs->appFailed();
1637 }
1638
1639 core::Signal<const std::shared_ptr<Application>&,
1640@@ -129,7 +147,8 @@
1641 const std::vector<pid_t>&>&
1642 Registry::appPaused(const std::shared_ptr<Registry>& reg)
1643 {
1644- return reg->impl->appPaused(reg);
1645+ setJobs(reg);
1646+ return reg->impl->jobs->appPaused();
1647 }
1648
1649 core::Signal<const std::shared_ptr<Application>&,
1650@@ -137,7 +156,8 @@
1651 const std::vector<pid_t>&>&
1652 Registry::appResumed(const std::shared_ptr<Registry>& reg)
1653 {
1654- return reg->impl->appResumed(reg);
1655+ setJobs(reg);
1656+ return reg->impl->jobs->appResumed();
1657 }
1658
1659 } // namespace app_launch

Subscribers

People subscribed via source and target branches