Merge lp:~ted/ubuntu-app-launch/app-object-signals into lp:ubuntu-app-launch/16.10
- app-object-signals
- Merge into trunk.16.10
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 | ||||
Related bugs: |
|
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.
Commit message
Description of the change
PS Jenkins bot (ps-jenkins) wrote : | # |
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:/
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
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:/
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 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
1 | === modified file 'libubuntu-app-launch/application-impl-libertine.cpp' |
2 | --- libubuntu-app-launch/application-impl-libertine.cpp 2016-10-03 23:54:20 +0000 |
3 | +++ libubuntu-app-launch/application-impl-libertine.cpp 2016-11-07 20:56:13 +0000 |
4 | @@ -255,8 +255,7 @@ |
5 | } |
6 | catch (std::runtime_error& e) |
7 | { |
8 | - g_debug("Unable to create application for libertine appname '%s': %s", |
9 | - apps.get()[j], e.what()); |
10 | + g_debug("Unable to create application for libertine appname '%s': %s", apps.get()[j], e.what()); |
11 | } |
12 | } |
13 | } |
14 | |
15 | === modified file 'libubuntu-app-launch/libubuntu-app-launch.map' |
16 | --- libubuntu-app-launch/libubuntu-app-launch.map 2016-05-19 16:24:11 +0000 |
17 | +++ libubuntu-app-launch/libubuntu-app-launch.map 2016-11-07 20:56:13 +0000 |
18 | @@ -14,6 +14,7 @@ |
19 | ubuntu::app_launch::Helper::*; |
20 | typeinfo?for?ubuntu::app_launch::Helper; |
21 | typeinfo?name?for?ubuntu::app_launch::Helper; |
22 | + ubuntu::app_launch::operator*; |
23 | ubuntu::app_launch::oom::*; |
24 | }; |
25 | local: |
26 | |
27 | === modified file 'libubuntu-app-launch/registry-impl.cpp' |
28 | --- libubuntu-app-launch/registry-impl.cpp 2016-09-23 22:30:51 +0000 |
29 | +++ libubuntu-app-launch/registry-impl.cpp 2016-11-07 20:56:13 +0000 |
30 | @@ -20,6 +20,7 @@ |
31 | #include "registry-impl.h" |
32 | #include "application-icon-finder.h" |
33 | #include <cgmanager/cgmanager.h> |
34 | +#include <regex> |
35 | #include <upstart.h> |
36 | |
37 | namespace ubuntu |
38 | @@ -36,13 +37,29 @@ |
39 | zgLog_.reset(); |
40 | cgManager_.reset(); |
41 | |
42 | + auto dohandle = [&](guint& handle) { |
43 | + if (handle != 0) |
44 | + { |
45 | + g_dbus_connection_signal_unsubscribe(_dbus.get(), handle); |
46 | + handle = 0; |
47 | + } |
48 | + }; |
49 | + |
50 | + dohandle(handle_appStarted); |
51 | + dohandle(handle_appStopped); |
52 | + dohandle(handle_appFailed); |
53 | + dohandle(handle_appPaused); |
54 | + dohandle(handle_appResumed); |
55 | + dohandle(handle_managerSignalFocus); |
56 | + dohandle(handle_managerSignalResume); |
57 | + dohandle(handle_managerSignalStarting); |
58 | + |
59 | if (_dbus) |
60 | g_dbus_connection_flush_sync(_dbus.get(), nullptr, nullptr); |
61 | _dbus.reset(); |
62 | }) |
63 | , _registry(registry) |
64 | , _iconFinders() |
65 | -// _manager(nullptr) |
66 | { |
67 | auto cancel = thread.getCancellable(); |
68 | _dbus = thread.executeOnThread<std::shared_ptr<GDBusConnection>>([cancel]() { |
69 | @@ -536,24 +553,193 @@ |
70 | return _iconFinders[basePath]; |
71 | } |
72 | |
73 | -#if 0 |
74 | -void |
75 | -Registry::Impl::setManager (Registry::Manager* manager) |
76 | -{ |
77 | - if (_manager != nullptr) |
78 | +/** Structure to track the data needed for upstart events. This cleans |
79 | + up the lifecycle as we're passing this as a pointer through the |
80 | + GLib calls. */ |
81 | +struct upstartEventData |
82 | +{ |
83 | + /** Keeping a weak pointer because the handle is held by |
84 | + the registry implementation. */ |
85 | + std::weak_ptr<Registry> weakReg; |
86 | +}; |
87 | + |
88 | +/** Take the GVariant of parameters and turn them into an application and |
89 | + and instance. Easier to read in the smaller function */ |
90 | +std::tuple<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>> Registry::Impl::managerParams( |
91 | + const std::shared_ptr<GVariant>& params, const std::shared_ptr<Registry>& reg) |
92 | +{ |
93 | + std::shared_ptr<Application> app; |
94 | + std::shared_ptr<Application::Instance> instance; |
95 | + |
96 | + const gchar* cappid = nullptr; |
97 | + g_variant_get(params.get(), "(&s)", &cappid); |
98 | + |
99 | + auto appid = ubuntu::app_launch::AppID::find(reg, cappid); |
100 | + app = ubuntu::app_launch::Application::create(appid, reg); |
101 | + |
102 | + return std::make_tuple(app, instance); |
103 | +} |
104 | + |
105 | +/** Used to store data for manager based signal handlers. Has a link to the |
106 | + registry and the callback to use in a C++ style. */ |
107 | +struct managerEventData |
108 | +{ |
109 | + /* Keeping a weak pointer because the handle is held by |
110 | + the registry implementation. */ |
111 | + std::weak_ptr<Registry> weakReg; |
112 | + std::function<void(const std::shared_ptr<Registry>& reg, |
113 | + const std::shared_ptr<Application>& app, |
114 | + const std::shared_ptr<Application::Instance>& instance, |
115 | + const std::shared_ptr<GDBusConnection>&, |
116 | + const std::string&, |
117 | + const std::shared_ptr<GVariant>&)> |
118 | + func; |
119 | +}; |
120 | + |
121 | +/** Register for a signal for the manager. All of the signals needed this same |
122 | + code so it got pulled out into a function. Takes the same of the signal, the registry |
123 | + that we're using and a function to call after we've messaged all the parameters |
124 | + into being something C++-ish. */ |
125 | +guint Registry::Impl::managerSignalHelper(const std::shared_ptr<Registry>& reg, |
126 | + const std::string& signalname, |
127 | + std::function<void(const std::shared_ptr<Registry>& reg, |
128 | + const std::shared_ptr<Application>& app, |
129 | + const std::shared_ptr<Application::Instance>& instance, |
130 | + const std::shared_ptr<GDBusConnection>&, |
131 | + const std::string&, |
132 | + const std::shared_ptr<GVariant>&)> responsefunc) |
133 | +{ |
134 | + managerEventData* focusdata = new managerEventData{reg, responsefunc}; |
135 | + |
136 | + return g_dbus_connection_signal_subscribe( |
137 | + reg->impl->_dbus.get(), /* bus */ |
138 | + nullptr, /* sender */ |
139 | + "com.canonical.UbuntuAppLaunch", /* interface */ |
140 | + signalname.c_str(), /* signal */ |
141 | + "/", /* path */ |
142 | + nullptr, /* arg0 */ |
143 | + G_DBUS_SIGNAL_FLAGS_NONE, |
144 | + [](GDBusConnection* cconn, const gchar* csender, const gchar*, const gchar*, const gchar*, GVariant* params, |
145 | + gpointer user_data) -> void { |
146 | + auto data = reinterpret_cast<managerEventData*>(user_data); |
147 | + auto reg = data->weakReg.lock(); |
148 | + |
149 | + /* If we're still conneted and the manager has been cleared |
150 | + we'll just be a no-op */ |
151 | + if (!reg->impl->manager_) |
152 | + { |
153 | + return; |
154 | + } |
155 | + |
156 | + auto vparams = std::shared_ptr<GVariant>(g_variant_ref(params), g_variant_unref); |
157 | + auto conn = std::shared_ptr<GDBusConnection>(reinterpret_cast<GDBusConnection*>(g_object_ref(cconn)), |
158 | + [](GDBusConnection* con) { g_clear_object(&con); }); |
159 | + std::string sender = csender; |
160 | + std::shared_ptr<Application> app; |
161 | + std::shared_ptr<Application::Instance> instance; |
162 | + |
163 | + std::tie(app, instance) = managerParams(vparams, reg); |
164 | + |
165 | + data->func(reg, app, instance, conn, sender, vparams); |
166 | + }, |
167 | + focusdata, |
168 | + [](gpointer user_data) { |
169 | + auto data = reinterpret_cast<managerEventData*>(user_data); |
170 | + delete data; |
171 | + }); /* user data destroy */ |
172 | +} |
173 | + |
174 | +/** Set the manager for the registry. This includes tracking the pointer |
175 | + as well as setting up the signals to call back into the manager. The |
176 | + signals are only setup once per registry even if the manager is cleared |
177 | + and changed again. They will just be no-op's in those cases. |
178 | +*/ |
179 | +void Registry::Impl::setManager(std::shared_ptr<Registry::Manager> manager, std::shared_ptr<Registry> reg) |
180 | +{ |
181 | + if (reg->impl->manager_) |
182 | { |
183 | throw std::runtime_error("Already have a manager and trying to set another"); |
184 | } |
185 | |
186 | - _manager = manager; |
187 | + g_debug("Setting a new manager"); |
188 | + reg->impl->manager_ = manager; |
189 | + |
190 | + std::call_once(reg->impl->flag_managerSignals, [reg]() { |
191 | + if (!reg->impl->thread.executeOnThread<bool>([reg]() { |
192 | + reg->impl->handle_managerSignalFocus = managerSignalHelper( |
193 | + reg, "UnityFocusRequest", |
194 | + [](const std::shared_ptr<Registry>& reg, const std::shared_ptr<Application>& app, |
195 | + const std::shared_ptr<Application::Instance>& instance, |
196 | + const std::shared_ptr<GDBusConnection>& conn, const std::string& sender, |
197 | + const std::shared_ptr<GVariant>& params) { |
198 | + /* Nothing to do today */ |
199 | + reg->impl->manager_->focusRequest(app, instance, [](bool response) { |
200 | + /* NOTE: We have no clue what thread this is gonna be |
201 | + executed on, but since we're just talking to the GDBus |
202 | + thread it isn't an issue today. Be careful in changing |
203 | + this code. */ |
204 | + }); |
205 | + }); |
206 | + reg->impl->handle_managerSignalStarting = managerSignalHelper( |
207 | + reg, "UnityStartingBroadcast", |
208 | + [](const std::shared_ptr<Registry>& reg, const std::shared_ptr<Application>& app, |
209 | + const std::shared_ptr<Application::Instance>& instance, |
210 | + const std::shared_ptr<GDBusConnection>& conn, const std::string& sender, |
211 | + const std::shared_ptr<GVariant>& params) { |
212 | + |
213 | + reg->impl->manager_->startingRequest(app, instance, [conn, sender, params](bool response) { |
214 | + /* NOTE: We have no clue what thread this is gonna be |
215 | + executed on, but since we're just talking to the GDBus |
216 | + thread it isn't an issue today. Be careful in changing |
217 | + this code. */ |
218 | + if (response) |
219 | + { |
220 | + g_dbus_connection_emit_signal(conn.get(), sender.c_str(), /* destination */ |
221 | + "/", /* path */ |
222 | + "com.canonical.UbuntuAppLaunch", /* interface */ |
223 | + "UnityStartingSignal", /* signal */ |
224 | + params.get(), /* params, the same */ |
225 | + nullptr); /* error */ |
226 | + } |
227 | + }); |
228 | + }); |
229 | + reg->impl->handle_managerSignalResume = managerSignalHelper( |
230 | + reg, "UnityResumeRequest", |
231 | + [](const std::shared_ptr<Registry>& reg, const std::shared_ptr<Application>& app, |
232 | + const std::shared_ptr<Application::Instance>& instance, |
233 | + const std::shared_ptr<GDBusConnection>& conn, const std::string& sender, |
234 | + const std::shared_ptr<GVariant>& params) { |
235 | + reg->impl->manager_->resumeRequest(app, instance, [conn, sender, params](bool response) { |
236 | + /* NOTE: We have no clue what thread this is gonna be |
237 | + executed on, but since we're just talking to the GDBus |
238 | + thread it isn't an issue today. Be careful in changing |
239 | + this code. */ |
240 | + if (response) |
241 | + { |
242 | + g_dbus_connection_emit_signal(conn.get(), sender.c_str(), /* destination */ |
243 | + "/", /* path */ |
244 | + "com.canonical.UbuntuAppLaunch", /* interface */ |
245 | + "UnityResumeResponse", /* signal */ |
246 | + params.get(), /* params, the same */ |
247 | + nullptr); /* error */ |
248 | + } |
249 | + }); |
250 | + }); |
251 | + |
252 | + return true; |
253 | + })) |
254 | + { |
255 | + g_warning("Unable to install manager signals"); |
256 | + } |
257 | + }); |
258 | } |
259 | |
260 | -void |
261 | -Registry::Impl::clearManager () |
262 | +/** Clear the manager pointer */ |
263 | +void Registry::Impl::clearManager() |
264 | { |
265 | - _manager = nullptr; |
266 | + g_debug("Clearing the manager"); |
267 | + manager_.reset(); |
268 | } |
269 | -#endif |
270 | |
271 | /** App start watching, if we're registered for the signal we |
272 | can't wait on it. We are making this static right now because |
273 | @@ -576,5 +762,301 @@ |
274 | return watchingAppStarting_; |
275 | } |
276 | |
277 | +/** Regex to parse the JOB environment variable from Upstart */ |
278 | +std::regex jobenv_regex{"^JOB=(application\\-(?:click|snap|legacy))$"}; |
279 | +/** Regex to parse the INSTANCE environment variable from Upstart */ |
280 | +std::regex instanceenv_regex{"^INSTANCE=(.*?)(?:\\-([0-9]*))?+$"}; |
281 | + |
282 | +/** Core of most of the events that come from Upstart directly. Includes parsing of the |
283 | + Upstart event environment and calling the appropriate signal with the right Application |
284 | + object and eventually its instance */ |
285 | +void Registry::Impl::upstartEventEmitted( |
286 | + core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>>& signal, |
287 | + std::shared_ptr<GVariant> params, |
288 | + const std::shared_ptr<Registry>& reg) |
289 | +{ |
290 | + std::string jobname; |
291 | + std::string sappid; |
292 | + std::string instance; |
293 | + |
294 | + gchar* env = nullptr; |
295 | + GVariant* envs = g_variant_get_child_value(params.get(), 1); |
296 | + GVariantIter iter; |
297 | + g_variant_iter_init(&iter, envs); |
298 | + |
299 | + while (g_variant_iter_loop(&iter, "s", &env)) |
300 | + { |
301 | + std::smatch match; |
302 | + std::string senv = env; |
303 | + |
304 | + if (std::regex_match(senv, match, jobenv_regex)) |
305 | + { |
306 | + jobname = match[1].str(); |
307 | + } |
308 | + else if (std::regex_match(senv, match, instanceenv_regex)) |
309 | + { |
310 | + sappid = match[1].str(); |
311 | + instance = match[2].str(); |
312 | + } |
313 | + } |
314 | + |
315 | + g_variant_unref(envs); |
316 | + |
317 | + if (jobname.empty()) |
318 | + { |
319 | + return; |
320 | + } |
321 | + |
322 | + g_debug("Upstart Event for job '%s' appid '%s' instance '%s'", jobname.c_str(), sappid.c_str(), instance.c_str()); |
323 | + |
324 | + auto appid = AppID::find(reg, sappid); |
325 | + auto app = Application::create(appid, reg); |
326 | + |
327 | + // TODO: Figure otu creating instances |
328 | + |
329 | + signal(app, {}); |
330 | +} |
331 | + |
332 | +/** Grab the signal object for application startup. If we're not already listing for |
333 | + those signals this sets up a listener for them. */ |
334 | +core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>>& Registry::Impl::appStarted( |
335 | + const std::shared_ptr<Registry>& reg) |
336 | +{ |
337 | + std::call_once(flag_appStarted, [reg]() { |
338 | + reg->impl->thread.executeOnThread<bool>([reg]() { |
339 | + upstartEventData* data = new upstartEventData{reg}; |
340 | + |
341 | + reg->impl->handle_appStarted = g_dbus_connection_signal_subscribe( |
342 | + reg->impl->_dbus.get(), /* bus */ |
343 | + nullptr, /* sender */ |
344 | + DBUS_INTERFACE_UPSTART, /* interface */ |
345 | + "EventEmitted", /* signal */ |
346 | + DBUS_PATH_UPSTART, /* path */ |
347 | + "started", /* arg0 */ |
348 | + G_DBUS_SIGNAL_FLAGS_NONE, |
349 | + [](GDBusConnection*, const gchar*, const gchar*, const gchar*, const gchar*, GVariant* params, |
350 | + gpointer user_data) -> void { |
351 | + auto data = reinterpret_cast<upstartEventData*>(user_data); |
352 | + auto reg = data->weakReg.lock(); |
353 | + auto sparams = std::shared_ptr<GVariant>(g_variant_ref(params), g_variant_unref); |
354 | + reg->impl->upstartEventEmitted(reg->impl->sig_appStarted, sparams, reg); |
355 | + }, /* callback */ |
356 | + data, /* user data */ |
357 | + [](gpointer user_data) { |
358 | + auto data = reinterpret_cast<upstartEventData*>(user_data); |
359 | + delete data; |
360 | + }); /* user data destroy */ |
361 | + |
362 | + return true; |
363 | + }); |
364 | + }); |
365 | + |
366 | + return sig_appStarted; |
367 | +} |
368 | + |
369 | +/** Grab the signal object for application stopping. If we're not already listing for |
370 | + those signals this sets up a listener for them. */ |
371 | +core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>>& Registry::Impl::appStopped( |
372 | + const std::shared_ptr<Registry>& reg) |
373 | +{ |
374 | + std::call_once(flag_appStopped, [reg]() { |
375 | + reg->impl->thread.executeOnThread<bool>([reg]() { |
376 | + upstartEventData* data = new upstartEventData{reg}; |
377 | + |
378 | + reg->impl->handle_appStopped = g_dbus_connection_signal_subscribe( |
379 | + reg->impl->_dbus.get(), /* bus */ |
380 | + nullptr, /* sender */ |
381 | + DBUS_INTERFACE_UPSTART, /* interface */ |
382 | + "EventEmitted", /* signal */ |
383 | + DBUS_PATH_UPSTART, /* path */ |
384 | + "stopped", /* arg0 */ |
385 | + G_DBUS_SIGNAL_FLAGS_NONE, |
386 | + [](GDBusConnection*, const gchar*, const gchar*, const gchar*, const gchar*, GVariant* params, |
387 | + gpointer user_data) -> void { |
388 | + auto data = reinterpret_cast<upstartEventData*>(user_data); |
389 | + auto reg = data->weakReg.lock(); |
390 | + auto sparams = std::shared_ptr<GVariant>(g_variant_ref(params), g_variant_unref); |
391 | + reg->impl->upstartEventEmitted(reg->impl->sig_appStopped, sparams, reg); |
392 | + }, /* callback */ |
393 | + data, /* user data */ |
394 | + [](gpointer user_data) { |
395 | + auto data = reinterpret_cast<upstartEventData*>(user_data); |
396 | + delete data; |
397 | + }); /* user data destroy */ |
398 | + |
399 | + return true; |
400 | + }); |
401 | + }); |
402 | + |
403 | + return sig_appStopped; |
404 | +} |
405 | + |
406 | +/** Grab the signal object for application failing. If we're not already listing for |
407 | + those signals this sets up a listener for them. */ |
408 | +core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>, Registry::FailureType>& |
409 | + Registry::Impl::appFailed(const std::shared_ptr<Registry>& reg) |
410 | +{ |
411 | + std::call_once(flag_appFailed, [reg]() { |
412 | + reg->impl->thread.executeOnThread<bool>([reg]() { |
413 | + upstartEventData* data = new upstartEventData{reg}; |
414 | + |
415 | + reg->impl->handle_appFailed = g_dbus_connection_signal_subscribe( |
416 | + reg->impl->_dbus.get(), /* bus */ |
417 | + nullptr, /* sender */ |
418 | + "com.canonical.UbuntuAppLaunch", /* interface */ |
419 | + "ApplicationFailed", /* signal */ |
420 | + "/", /* path */ |
421 | + nullptr, /* arg0 */ |
422 | + G_DBUS_SIGNAL_FLAGS_NONE, |
423 | + [](GDBusConnection*, const gchar*, const gchar*, const gchar*, const gchar*, GVariant* params, |
424 | + gpointer user_data) -> void { |
425 | + auto data = reinterpret_cast<upstartEventData*>(user_data); |
426 | + auto reg = data->weakReg.lock(); |
427 | + |
428 | + const gchar* sappid = NULL; |
429 | + const gchar* typestr = NULL; |
430 | + |
431 | + Registry::FailureType type = Registry::FailureType::CRASH; |
432 | + g_variant_get(params, "(&s&s)", &sappid, &typestr); |
433 | + |
434 | + if (g_strcmp0("crash", typestr) == 0) |
435 | + { |
436 | + type = Registry::FailureType::CRASH; |
437 | + } |
438 | + else if (g_strcmp0("start-failure", typestr) == 0) |
439 | + { |
440 | + type = Registry::FailureType::START_FAILURE; |
441 | + } |
442 | + else |
443 | + { |
444 | + g_warning("Application failure type '%s' unknown, reporting as a crash", typestr); |
445 | + } |
446 | + |
447 | + auto appid = AppID::find(reg, sappid); |
448 | + auto app = Application::create(appid, reg); |
449 | + |
450 | + /* TODO: Instance issues */ |
451 | + |
452 | + reg->impl->sig_appFailed(app, {}, type); |
453 | + }, /* callback */ |
454 | + data, /* user data */ |
455 | + [](gpointer user_data) { |
456 | + auto data = reinterpret_cast<upstartEventData*>(user_data); |
457 | + delete data; |
458 | + }); /* user data destroy */ |
459 | + |
460 | + return true; |
461 | + }); |
462 | + }); |
463 | + |
464 | + return sig_appFailed; |
465 | +} |
466 | + |
467 | +/** Core handler for pause and resume events. Includes turning the GVariant |
468 | + pid list into a std::vector and getting the application object. */ |
469 | +void Registry::Impl::pauseEventEmitted( |
470 | + core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>, std::vector<pid_t>&>& signal, |
471 | + const std::shared_ptr<GVariant>& params, |
472 | + const std::shared_ptr<Registry>& reg) |
473 | +{ |
474 | + std::vector<pid_t> pids; |
475 | + GVariant* vappid = g_variant_get_child_value(params.get(), 0); |
476 | + GVariant* vpids = g_variant_get_child_value(params.get(), 1); |
477 | + guint64 pid; |
478 | + GVariantIter thispid; |
479 | + g_variant_iter_init(&thispid, vpids); |
480 | + |
481 | + while (g_variant_iter_loop(&thispid, "t", &pid)) |
482 | + { |
483 | + pids.emplace_back(pid); |
484 | + } |
485 | + |
486 | + auto cappid = g_variant_get_string(vappid, NULL); |
487 | + auto appid = ubuntu::app_launch::AppID::find(reg, cappid); |
488 | + auto app = Application::create(appid, reg); |
489 | + |
490 | + /* TODO: Instance */ |
491 | + signal(app, {}, pids); |
492 | + |
493 | + g_variant_unref(vappid); |
494 | + g_variant_unref(vpids); |
495 | + |
496 | + return; |
497 | +} |
498 | + |
499 | +/** Grab the signal object for application paused. If we're not already listing for |
500 | + those signals this sets up a listener for them. */ |
501 | +core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>, std::vector<pid_t>&>& |
502 | + Registry::Impl::appPaused(const std::shared_ptr<Registry>& reg) |
503 | +{ |
504 | + std::call_once(flag_appPaused, [&]() { |
505 | + reg->impl->thread.executeOnThread<bool>([reg]() { |
506 | + upstartEventData* data = new upstartEventData{reg}; |
507 | + |
508 | + reg->impl->handle_appPaused = g_dbus_connection_signal_subscribe( |
509 | + reg->impl->_dbus.get(), /* bus */ |
510 | + nullptr, /* sender */ |
511 | + "com.canonical.UbuntuAppLaunch", /* interface */ |
512 | + "ApplicationPaused", /* signal */ |
513 | + "/", /* path */ |
514 | + nullptr, /* arg0 */ |
515 | + G_DBUS_SIGNAL_FLAGS_NONE, |
516 | + [](GDBusConnection*, const gchar*, const gchar*, const gchar*, const gchar*, GVariant* params, |
517 | + gpointer user_data) -> void { |
518 | + auto data = reinterpret_cast<upstartEventData*>(user_data); |
519 | + auto reg = data->weakReg.lock(); |
520 | + auto sparams = std::shared_ptr<GVariant>(g_variant_ref(params), g_variant_unref); |
521 | + reg->impl->pauseEventEmitted(reg->impl->sig_appPaused, sparams, reg); |
522 | + }, /* callback */ |
523 | + data, /* user data */ |
524 | + [](gpointer user_data) { |
525 | + auto data = reinterpret_cast<upstartEventData*>(user_data); |
526 | + delete data; |
527 | + }); /* user data destroy */ |
528 | + |
529 | + return true; |
530 | + }); |
531 | + }); |
532 | + |
533 | + return sig_appPaused; |
534 | +} |
535 | + |
536 | +/** Grab the signal object for application resumed. If we're not already listing for |
537 | + those signals this sets up a listener for them. */ |
538 | +core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>, std::vector<pid_t>&>& |
539 | + Registry::Impl::appResumed(const std::shared_ptr<Registry>& reg) |
540 | +{ |
541 | + std::call_once(flag_appResumed, [&]() { |
542 | + reg->impl->thread.executeOnThread<bool>([reg]() { |
543 | + upstartEventData* data = new upstartEventData{reg}; |
544 | + |
545 | + reg->impl->handle_appResumed = g_dbus_connection_signal_subscribe( |
546 | + reg->impl->_dbus.get(), /* bus */ |
547 | + nullptr, /* sender */ |
548 | + "com.canonical.UbuntuAppLaunch", /* interface */ |
549 | + "ApplicationResumed", /* signal */ |
550 | + "/", /* path */ |
551 | + nullptr, /* arg0 */ |
552 | + G_DBUS_SIGNAL_FLAGS_NONE, |
553 | + [](GDBusConnection*, const gchar*, const gchar*, const gchar*, const gchar*, GVariant* params, |
554 | + gpointer user_data) -> void { |
555 | + auto data = reinterpret_cast<upstartEventData*>(user_data); |
556 | + auto reg = data->weakReg.lock(); |
557 | + auto sparams = std::shared_ptr<GVariant>(g_variant_ref(params), g_variant_unref); |
558 | + reg->impl->pauseEventEmitted(reg->impl->sig_appResumed, sparams, reg); |
559 | + }, /* callback */ |
560 | + data, /* user data */ |
561 | + [](gpointer user_data) { |
562 | + auto data = reinterpret_cast<upstartEventData*>(user_data); |
563 | + delete data; |
564 | + }); /* user data destroy */ |
565 | + |
566 | + return true; |
567 | + }); |
568 | + }); |
569 | + |
570 | + return sig_appResumed; |
571 | +} |
572 | + |
573 | } // namespace app_launch |
574 | } // namespace ubuntu |
575 | |
576 | === modified file 'libubuntu-app-launch/registry-impl.h' |
577 | --- libubuntu-app-launch/registry-impl.h 2016-09-23 22:30:51 +0000 |
578 | +++ libubuntu-app-launch/registry-impl.h 2016-11-07 20:56:13 +0000 |
579 | @@ -53,10 +53,8 @@ |
580 | std::list<AppID::Package> getClickPackages(); |
581 | std::string getClickDir(const std::string& package); |
582 | |
583 | -#if 0 |
584 | - void setManager (Registry::Manager* manager); |
585 | - void clearManager (); |
586 | -#endif |
587 | + static void setManager(std::shared_ptr<Registry::Manager> manager, std::shared_ptr<Registry> registry); |
588 | + void clearManager(); |
589 | |
590 | /** Shared context thread for events and background tasks |
591 | that UAL subtasks are doing */ |
592 | @@ -82,6 +80,18 @@ |
593 | static std::string printJson(std::shared_ptr<JsonObject> jsonobj); |
594 | static std::string printJson(std::shared_ptr<JsonNode> jsonnode); |
595 | |
596 | + /* Signals to discover what is happening to apps */ |
597 | + core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>>& appStarted( |
598 | + const std::shared_ptr<Registry>& reg); |
599 | + core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>>& appStopped( |
600 | + const std::shared_ptr<Registry>& reg); |
601 | + core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>, FailureType>& appFailed( |
602 | + const std::shared_ptr<Registry>& reg); |
603 | + core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>, std::vector<pid_t>&>& appPaused( |
604 | + const std::shared_ptr<Registry>& reg); |
605 | + core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>, std::vector<pid_t>&>& appResumed( |
606 | + const std::shared_ptr<Registry>& reg); |
607 | + |
608 | /* Signal Hints */ |
609 | /* NOTE: Static because we don't have registry instances in the C |
610 | code right now. We want these to not be static in the future */ |
611 | @@ -89,22 +99,77 @@ |
612 | static bool isWatchingAppStarting(); |
613 | |
614 | private: |
615 | - Registry* _registry; |
616 | -#if 0 |
617 | - Registry::Manager* _manager; |
618 | -#endif |
619 | - |
620 | - std::shared_ptr<ClickDB> _clickDB; |
621 | - std::shared_ptr<ClickUser> _clickUser; |
622 | + Registry* _registry; /**< The Registry that we're spawned from */ |
623 | + std::shared_ptr<Registry::Manager> manager_; /**< Application manager if registered */ |
624 | + |
625 | + std::shared_ptr<ClickDB> _clickDB; /**< Shared instance of the Click Database */ |
626 | + std::shared_ptr<ClickUser> _clickUser; /**< Click database filtered by the current user */ |
627 | + |
628 | + /** Signal object for applications started */ |
629 | + core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>> sig_appStarted; |
630 | + /** Signal object for applications stopped */ |
631 | + core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>> sig_appStopped; |
632 | + /** Signal object for applications failed */ |
633 | + core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>, FailureType> sig_appFailed; |
634 | + /** Signal object for applications paused */ |
635 | + core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>, std::vector<pid_t>&> |
636 | + sig_appPaused; |
637 | + /** Signal object for applications resumed */ |
638 | + core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>, std::vector<pid_t>&> |
639 | + sig_appResumed; |
640 | + |
641 | + guint handle_appStarted{0}; /**< GDBus signal watcher handle for app started signal */ |
642 | + guint handle_appStopped{0}; /**< GDBus signal watcher handle for app stopped signal */ |
643 | + guint handle_appFailed{0}; /**< GDBus signal watcher handle for app failed signal */ |
644 | + guint handle_appPaused{0}; /**< GDBus signal watcher handle for app paused signal */ |
645 | + guint handle_appResumed{0}; /**< GDBus signal watcher handle for app resumed signal */ |
646 | + guint handle_managerSignalFocus{0}; /**< GDBus signal watcher handle for app focused signal */ |
647 | + guint handle_managerSignalResume{0}; /**< GDBus signal watcher handle for app resumed signal */ |
648 | + guint handle_managerSignalStarting{0}; /**< GDBus signal watcher handle for app starting signal */ |
649 | + |
650 | + std::once_flag flag_appStarted; /**< Variable to track to see if signal handlers are installed for application |
651 | + started */ |
652 | + std::once_flag flag_appStopped; /**< Variable to track to see if signal handlers are installed for application |
653 | + stopped */ |
654 | + std::once_flag |
655 | + flag_appFailed; /**< Variable to track to see if signal handlers are installed for application failed */ |
656 | + std::once_flag |
657 | + flag_appPaused; /**< Variable to track to see if signal handlers are installed for application paused */ |
658 | + std::once_flag flag_appResumed; /**< Variable to track to see if signal handlers are installed for application |
659 | + resumed */ |
660 | + std::once_flag flag_managerSignals; /**< Variable to track to see if signal handlers are installed for the manager |
661 | + signals of focused, resumed and starting */ |
662 | + |
663 | + void upstartEventEmitted(core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>>& signal, |
664 | + std::shared_ptr<GVariant> params, |
665 | + const std::shared_ptr<Registry>& reg); |
666 | + void pauseEventEmitted( |
667 | + core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>, std::vector<pid_t>&>& signal, |
668 | + const std::shared_ptr<GVariant>& params, |
669 | + const std::shared_ptr<Registry>& reg); |
670 | + static std::tuple<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>> managerParams( |
671 | + const std::shared_ptr<GVariant>& params, const std::shared_ptr<Registry>& reg); |
672 | + static guint managerSignalHelper(const std::shared_ptr<Registry>& reg, |
673 | + const std::string& signalname, |
674 | + std::function<void(const std::shared_ptr<Registry>& reg, |
675 | + const std::shared_ptr<Application>& app, |
676 | + const std::shared_ptr<Application::Instance>& instance, |
677 | + const std::shared_ptr<GDBusConnection>&, |
678 | + const std::string&, |
679 | + const std::shared_ptr<GVariant>&)> responsefunc); |
680 | |
681 | void initClick(); |
682 | |
683 | + /** Shared instance of the Zeitgeist Log */ |
684 | std::shared_ptr<ZeitgeistLog> zgLog_; |
685 | |
686 | + /** Shared connection to CGManager */ |
687 | std::shared_ptr<GDBusConnection> cgManager_; |
688 | |
689 | void initCGManager(); |
690 | |
691 | + /** All of our icon finders based on the path that they're looking |
692 | + into */ |
693 | std::unordered_map<std::string, std::shared_ptr<IconFinder>> _iconFinders; |
694 | |
695 | /** Getting the Upstart job path is relatively expensive in |
696 | |
697 | === modified file 'libubuntu-app-launch/registry.cpp' |
698 | --- libubuntu-app-launch/registry.cpp 2016-08-26 17:33:34 +0000 |
699 | +++ libubuntu-app-launch/registry.cpp 2016-11-07 20:56:13 +0000 |
700 | @@ -57,7 +57,7 @@ |
701 | instances.splice(instances.begin(), connection->impl->upstartInstancesForJob("application-snap")); |
702 | |
703 | /* Remove the instance ID */ |
704 | - std::transform(instances.begin(), instances.end(), instances.begin(), [](std::string &instancename) -> std::string { |
705 | + std::transform(instances.begin(), instances.end(), instances.begin(), [](std::string& instancename) -> std::string { |
706 | static const std::regex instanceregex("^(.*)-[0-9]*$"); |
707 | std::smatch match; |
708 | if (std::regex_match(instancename, match, instanceregex)) |
709 | @@ -87,7 +87,7 @@ |
710 | |
711 | g_debug("Overall there are %d instances: %s", int(instanceset.size()), |
712 | std::accumulate(instanceset.begin(), instanceset.end(), std::string{}, |
713 | - [](const std::string &instr, std::string instance) { |
714 | + [](const std::string& instr, std::string instance) { |
715 | return instr.empty() ? instance : instr + ", " + instance; |
716 | }) |
717 | .c_str()); |
718 | @@ -127,6 +127,16 @@ |
719 | return list; |
720 | } |
721 | |
722 | +void Registry::setManager(std::shared_ptr<Manager> manager, std::shared_ptr<Registry> registry) |
723 | +{ |
724 | + Registry::Impl::setManager(manager, registry); |
725 | +} |
726 | + |
727 | +void Registry::clearManager() |
728 | +{ |
729 | + impl->clearManager(); |
730 | +} |
731 | + |
732 | std::shared_ptr<Registry> defaultRegistry; |
733 | std::shared_ptr<Registry> Registry::getDefault() |
734 | { |
735 | @@ -143,5 +153,35 @@ |
736 | defaultRegistry.reset(); |
737 | } |
738 | |
739 | +core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>>& Registry::appStarted( |
740 | + const std::shared_ptr<Registry>& reg) |
741 | +{ |
742 | + return reg->impl->appStarted(reg); |
743 | +} |
744 | + |
745 | +core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>>& Registry::appStopped( |
746 | + const std::shared_ptr<Registry>& reg) |
747 | +{ |
748 | + return reg->impl->appStopped(reg); |
749 | +} |
750 | + |
751 | +core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>, Registry::FailureType>& |
752 | + Registry::appFailed(const std::shared_ptr<Registry>& reg) |
753 | +{ |
754 | + return reg->impl->appFailed(reg); |
755 | +} |
756 | + |
757 | +core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>, std::vector<pid_t>&>& |
758 | + Registry::appPaused(const std::shared_ptr<Registry>& reg) |
759 | +{ |
760 | + return reg->impl->appPaused(reg); |
761 | +} |
762 | + |
763 | +core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>, std::vector<pid_t>&>& |
764 | + Registry::appResumed(const std::shared_ptr<Registry>& reg) |
765 | +{ |
766 | + return reg->impl->appResumed(reg); |
767 | +} |
768 | + |
769 | } // namespace app_launch |
770 | } // namespace ubuntu |
771 | |
772 | === modified file 'libubuntu-app-launch/registry.h' |
773 | --- libubuntu-app-launch/registry.h 2016-06-09 14:55:34 +0000 |
774 | +++ libubuntu-app-launch/registry.h 2016-11-07 20:56:13 +0000 |
775 | @@ -73,28 +73,134 @@ |
776 | */ |
777 | static std::list<std::shared_ptr<Application>> installedApps(std::shared_ptr<Registry> registry = getDefault()); |
778 | |
779 | -#if 0 /* TODO -- In next MR */ |
780 | /* Signals to discover what is happening to apps */ |
781 | - core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>> appStarted; |
782 | - core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>> appStopped; |
783 | - core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>, FailureType> appFailed; |
784 | - core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>> appPaused; |
785 | - core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>> appResumed; |
786 | - |
787 | - /* The Application Manager, almost always if you're not Unity8, don't |
788 | - use this API. Testing is a special case. */ |
789 | + /** Get the signal object that is signaled when an application has been |
790 | + started. |
791 | + |
792 | + \note This singal handler is activated on the UAL thread, if you want |
793 | + to execute on a different thread you'll need to move the work. |
794 | + |
795 | + \param reg Registry to get the handler from |
796 | + */ |
797 | + static core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>>& appStarted( |
798 | + const std::shared_ptr<Registry>& reg = getDefault()); |
799 | + |
800 | + /** Get the signal object that is signaled when an application has stopped. |
801 | + |
802 | + \note This singal handler is activated on the UAL thread, if you want |
803 | + to execute on a different thread you'll need to move the work. |
804 | + |
805 | + \param reg Registry to get the handler from |
806 | + */ |
807 | + static core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>>& appStopped( |
808 | + const std::shared_ptr<Registry>& reg = getDefault()); |
809 | + |
810 | + /** Get the signal object that is signaled when an application has failed. |
811 | + |
812 | + \note This singal handler is activated on the UAL thread, if you want |
813 | + to execute on a different thread you'll need to move the work. |
814 | + |
815 | + \param reg Registry to get the handler from |
816 | + */ |
817 | + static core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>, FailureType>& appFailed( |
818 | + const std::shared_ptr<Registry>& reg = getDefault()); |
819 | + |
820 | + /** Get the signal object that is signaled when an application has been |
821 | + paused. |
822 | + |
823 | + \note This singal handler is activated on the UAL thread, if you want |
824 | + to execute on a different thread you'll need to move the work. |
825 | + |
826 | + \param reg Registry to get the handler from |
827 | + */ |
828 | + static core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>, std::vector<pid_t>&>& |
829 | + appPaused(const std::shared_ptr<Registry>& reg = getDefault()); |
830 | + |
831 | + /** Get the signal object that is signaled when an application has been |
832 | + resumed. |
833 | + |
834 | + \note This singal handler is activated on the UAL thread, if you want |
835 | + to execute on a different thread you'll need to move the work. |
836 | + |
837 | + \param reg Registry to get the handler from |
838 | + */ |
839 | + static core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>, std::vector<pid_t>&>& |
840 | + appResumed(const std::shared_ptr<Registry>& reg = getDefault()); |
841 | + |
842 | + /** The Application Manager, almost always if you're not Unity8, don't |
843 | + use this API. Testing is a special case. Subclass this interface and |
844 | + implement these functions. |
845 | + |
846 | + Each function here is being passed a function object that takes a boolean |
847 | + to reply. This will accept or reject the request. The function object |
848 | + can be copied to another thread and executed if needed. |
849 | + */ |
850 | class Manager |
851 | { |
852 | - virtual bool focusRequest (std::shared_ptr<Application> app, std::shared_ptr<Application::Instance> instance) = 0; |
853 | - virtual bool startingRequest (std::shared_ptr<Application> app, std::shared_ptr<Application::Instance> instance) = 0; |
854 | + public: |
855 | + /** Application wishes to startup |
856 | + |
857 | + \note This singal handler is activated on the UAL thread, if you want |
858 | + to execute on a different thread you'll need to move the work. |
859 | + |
860 | + \param app Application requesting startup |
861 | + \param instance Instance of the app, always valid but not useful |
862 | + unless mulit-instance app. |
863 | + \param reply Function object to reply if it is allowed to start |
864 | + */ |
865 | + virtual void startingRequest(std::shared_ptr<Application> app, |
866 | + std::shared_ptr<Application::Instance> instance, |
867 | + std::function<void(bool)> reply) = 0; |
868 | + |
869 | + /** Application wishes to have focus. Usually this occurs when |
870 | + a URL for the application is activated and the running app is |
871 | + requested. |
872 | + |
873 | + \note This singal handler is activated on the UAL thread, if you want |
874 | + to execute on a different thread you'll need to move the work. |
875 | + |
876 | + \param app Application requesting focus |
877 | + \param instance Instance of the app, always valid but not useful |
878 | + unless mulit-instance app. |
879 | + \param reply Function object to reply if it is allowed to focus |
880 | + */ |
881 | + virtual void focusRequest(std::shared_ptr<Application> app, |
882 | + std::shared_ptr<Application::Instance> instance, |
883 | + std::function<void(bool)> reply) = 0; |
884 | + |
885 | + /** Application wishes to resume. Usually this occurs when |
886 | + a URL for the application is activated and the running app is |
887 | + requested. |
888 | + |
889 | + \note This singal handler is activated on the UAL thread, if you want |
890 | + to execute on a different thread you'll need to move the work. |
891 | + |
892 | + \param app Application requesting resume |
893 | + \param instance Instance of the app, always valid but not useful |
894 | + unless mulit-instance app. |
895 | + \param reply Function object to reply if it is allowed to resume |
896 | + */ |
897 | + virtual void resumeRequest(std::shared_ptr<Application> app, |
898 | + std::shared_ptr<Application::Instance> instance, |
899 | + std::function<void(bool)> reply) = 0; |
900 | |
901 | protected: |
902 | Manager() = default; |
903 | }; |
904 | |
905 | - void setManager (Manager* manager); |
906 | - void clearManager (); |
907 | -#endif |
908 | + /** Set the manager of applications, which gives permissions for them to |
909 | + start and gain focus. In almost all cases this should be Unity8 as it |
910 | + will be controlling applications. |
911 | + |
912 | + This function will failure if there is already a manager set. |
913 | + |
914 | + \param manager A reference to the Manager object to call |
915 | + \param registry Registry to register the manager on |
916 | + */ |
917 | + static void setManager(std::shared_ptr<Manager> manager, std::shared_ptr<Registry> registry); |
918 | + |
919 | + /** Remove the current manager on the registry */ |
920 | + void clearManager(); |
921 | |
922 | /* Helper Lists */ |
923 | /** Get a list of all the helpers for a given helper type |
924 | |
925 | === modified file 'libubuntu-app-launch/ubuntu-app-launch.cpp' |
926 | --- libubuntu-app-launch/ubuntu-app-launch.cpp 2016-09-14 21:58:39 +0000 |
927 | +++ libubuntu-app-launch/ubuntu-app-launch.cpp 2016-11-07 20:56:13 +0000 |
928 | @@ -39,6 +39,7 @@ |
929 | #include "appid.h" |
930 | #include "registry.h" |
931 | #include "registry-impl.h" |
932 | +#include <algorithm> |
933 | |
934 | static void free_helper (gpointer value); |
935 | int kill (pid_t pid, int signal) noexcept; |
936 | @@ -271,155 +272,210 @@ |
937 | gpointer user_data; |
938 | }; |
939 | |
940 | -/* The data we keep for each failed observer */ |
941 | -typedef struct _paused_resumed_observer_t paused_resumed_observer_t; |
942 | -struct _paused_resumed_observer_t { |
943 | - GDBusConnection * conn; |
944 | - guint sighandle; |
945 | - UbuntuAppLaunchAppPausedResumedObserver func; |
946 | - gpointer user_data; |
947 | - const gchar * lttng_signal; |
948 | -}; |
949 | - |
950 | -/* The lists of Observers */ |
951 | -static GList * starting_array = NULL; |
952 | -static GList * started_array = NULL; |
953 | -static GList * stop_array = NULL; |
954 | -static GList * focus_array = NULL; |
955 | -static GList * resume_array = NULL; |
956 | -static GList * failed_array = NULL; |
957 | -static GList * paused_array = NULL; |
958 | -static GList * resumed_array = NULL; |
959 | - |
960 | -static void |
961 | -observer_cb (GDBusConnection * conn, const gchar * sender, const gchar * object, const gchar * interface, const gchar * signal, GVariant * params, gpointer user_data) |
962 | -{ |
963 | - observer_t * observer = (observer_t *)user_data; |
964 | - |
965 | - const gchar * signalname = NULL; |
966 | - g_variant_get_child(params, 0, "&s", &signalname); |
967 | - |
968 | - ual_tracepoint(observer_start, signalname); |
969 | - |
970 | - gchar * env = NULL; |
971 | - GVariant * envs = g_variant_get_child_value(params, 1); |
972 | - GVariantIter iter; |
973 | - g_variant_iter_init(&iter, envs); |
974 | - |
975 | - gboolean job_found = FALSE; |
976 | - gboolean job_legacy = FALSE; |
977 | - gchar * instance = NULL; |
978 | - |
979 | - while (g_variant_iter_loop(&iter, "s", &env)) { |
980 | - if (g_strcmp0(env, "JOB=application-click") == 0) { |
981 | - job_found = TRUE; |
982 | - } else if (g_strcmp0(env, "JOB=application-legacy") == 0) { |
983 | - job_found = TRUE; |
984 | - job_legacy = TRUE; |
985 | - } else if (g_strcmp0(env, "JOB=application-snap") == 0) { |
986 | - job_found = TRUE; |
987 | - job_legacy = TRUE; |
988 | - } else if (g_str_has_prefix(env, "INSTANCE=")) { |
989 | - instance = g_strdup(env + strlen("INSTANCE=")); |
990 | - } |
991 | - } |
992 | - |
993 | - g_variant_unref(envs); |
994 | - |
995 | - if (job_legacy && instance != NULL) { |
996 | - gchar * dash = g_strrstr(instance, "-"); |
997 | - if (dash != NULL) { |
998 | - dash[0] = '\0'; |
999 | - } |
1000 | - } |
1001 | - |
1002 | - if (job_found && instance != NULL) { |
1003 | - observer->func(instance, observer->user_data); |
1004 | - } |
1005 | - |
1006 | - ual_tracepoint(observer_finish, signalname); |
1007 | - |
1008 | - g_free(instance); |
1009 | -} |
1010 | - |
1011 | -/* Creates the observer structure and registers for the signal with |
1012 | - GDBus so that we can get a callback */ |
1013 | -static gboolean |
1014 | -add_app_generic (UbuntuAppLaunchAppObserver observer, gpointer user_data, const gchar * signal, GList ** list) |
1015 | -{ |
1016 | - GDBusConnection * conn = gdbus_upstart_ref(); |
1017 | - |
1018 | - if (conn == NULL) { |
1019 | - return FALSE; |
1020 | - } |
1021 | - |
1022 | - observer_t * observert = g_new0(observer_t, 1); |
1023 | - |
1024 | - observert->conn = conn; |
1025 | - observert->func = observer; |
1026 | - observert->user_data = user_data; |
1027 | - |
1028 | - *list = g_list_prepend(*list, observert); |
1029 | - |
1030 | - observert->sighandle = g_dbus_connection_signal_subscribe(conn, |
1031 | - NULL, /* sender */ |
1032 | - DBUS_INTERFACE_UPSTART, /* interface */ |
1033 | - "EventEmitted", /* signal */ |
1034 | - DBUS_PATH_UPSTART, /* path */ |
1035 | - signal, /* arg0 */ |
1036 | - G_DBUS_SIGNAL_FLAGS_NONE, |
1037 | - observer_cb, |
1038 | - observert, |
1039 | - NULL); /* user data destroy */ |
1040 | - |
1041 | - return TRUE; |
1042 | -} |
1043 | +/* Function to take a work function and have it execute on a given |
1044 | + GMainContext */ |
1045 | +static void executeOnContext (std::shared_ptr<GMainContext> context, std::function<void()> work) |
1046 | +{ |
1047 | + if (!context) { |
1048 | + work(); |
1049 | + return; |
1050 | + } |
1051 | + |
1052 | + auto heapWork = new std::function<void()>(work); |
1053 | + |
1054 | + auto source = std::shared_ptr<GSource>(g_idle_source_new(), [](GSource* src) { g_clear_pointer(&src, g_source_unref); }); |
1055 | + g_source_set_callback(source.get(), |
1056 | + [](gpointer data) { |
1057 | + auto heapWork = static_cast<std::function<void()>*>(data); |
1058 | + (*heapWork)(); |
1059 | + return G_SOURCE_REMOVE; |
1060 | + }, |
1061 | + heapWork, |
1062 | + [](gpointer data) { |
1063 | + auto heapWork = static_cast<std::function<void()>*>(data); |
1064 | + delete heapWork; |
1065 | + }); |
1066 | + |
1067 | + g_source_attach(source.get(), context.get()); |
1068 | +} |
1069 | + |
1070 | +/* Map of all the observers listening for app started */ |
1071 | +static std::map<std::pair<UbuntuAppLaunchAppObserver, gpointer>, core::ScopedConnection> appStartedObservers; |
1072 | |
1073 | gboolean |
1074 | ubuntu_app_launch_observer_add_app_started (UbuntuAppLaunchAppObserver observer, gpointer user_data) |
1075 | { |
1076 | - return add_app_generic(observer, user_data, "started", &started_array); |
1077 | -} |
1078 | + auto context = std::shared_ptr<GMainContext>(g_main_context_ref_thread_default(), [](GMainContext * context) { g_clear_pointer(&context, g_main_context_unref); }); |
1079 | + |
1080 | + appStartedObservers.emplace(std::make_pair( |
1081 | + std::make_pair(observer, user_data), |
1082 | + core::ScopedConnection( |
1083 | + 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) { |
1084 | + std::string appid = app->appId(); |
1085 | + executeOnContext(context, [appid, observer, user_data]() { |
1086 | + observer(appid.c_str(), user_data); |
1087 | + }); |
1088 | + }) |
1089 | + ) |
1090 | + )); |
1091 | + |
1092 | + return TRUE; |
1093 | +} |
1094 | + |
1095 | +gboolean |
1096 | +ubuntu_app_launch_observer_delete_app_started (UbuntuAppLaunchAppObserver observer, gpointer user_data) |
1097 | +{ |
1098 | + auto iter = appStartedObservers.find(std::make_pair(observer, user_data)); |
1099 | + |
1100 | + if (iter == appStartedObservers.end()) { |
1101 | + return FALSE; |
1102 | + } |
1103 | + |
1104 | + appStartedObservers.erase(iter); |
1105 | + return TRUE; |
1106 | +} |
1107 | + |
1108 | +/* Map of all the observers listening for app stopped */ |
1109 | +static std::map<std::pair<UbuntuAppLaunchAppObserver, gpointer>, core::ScopedConnection> appStoppedObservers; |
1110 | |
1111 | gboolean |
1112 | ubuntu_app_launch_observer_add_app_stop (UbuntuAppLaunchAppObserver observer, gpointer user_data) |
1113 | { |
1114 | - return add_app_generic(observer, user_data, "stopped", &stop_array); |
1115 | + auto context = std::shared_ptr<GMainContext>(g_main_context_ref_thread_default(), [](GMainContext * context) { g_clear_pointer(&context, g_main_context_unref); }); |
1116 | + |
1117 | + appStoppedObservers.emplace(std::make_pair( |
1118 | + std::make_pair(observer, user_data), |
1119 | + core::ScopedConnection( |
1120 | + 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) { |
1121 | + std::string appid = app->appId(); |
1122 | + executeOnContext(context, [appid, observer, user_data]() { |
1123 | + observer(appid.c_str(), user_data); |
1124 | + }); |
1125 | + }) |
1126 | + ) |
1127 | + )); |
1128 | + |
1129 | + return TRUE; |
1130 | } |
1131 | |
1132 | -/* Creates the observer structure and registers for the signal with |
1133 | - GDBus so that we can get a callback */ |
1134 | -static gboolean |
1135 | -add_session_generic (UbuntuAppLaunchAppObserver observer, gpointer user_data, const gchar * signal, GList ** list, GDBusSignalCallback session_cb) |
1136 | +gboolean |
1137 | +ubuntu_app_launch_observer_delete_app_stop (UbuntuAppLaunchAppObserver observer, gpointer user_data) |
1138 | { |
1139 | - GDBusConnection * conn = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL); |
1140 | + auto iter = appStoppedObservers.find(std::make_pair(observer, user_data)); |
1141 | |
1142 | - if (conn == NULL) { |
1143 | + if (iter == appStoppedObservers.end()) { |
1144 | return FALSE; |
1145 | } |
1146 | |
1147 | - observer_t * observert = g_new0(observer_t, 1); |
1148 | - |
1149 | - observert->conn = conn; |
1150 | - observert->func = observer; |
1151 | - observert->user_data = user_data; |
1152 | - |
1153 | - *list = g_list_prepend(*list, observert); |
1154 | - |
1155 | - observert->sighandle = g_dbus_connection_signal_subscribe(conn, |
1156 | - NULL, /* sender */ |
1157 | - "com.canonical.UbuntuAppLaunch", /* interface */ |
1158 | - signal, /* signal */ |
1159 | - "/", /* path */ |
1160 | - NULL, /* arg0 */ |
1161 | - G_DBUS_SIGNAL_FLAGS_NONE, |
1162 | - session_cb, |
1163 | - observert, |
1164 | - NULL); /* user data destroy */ |
1165 | - |
1166 | + appStoppedObservers.erase(iter); |
1167 | return TRUE; |
1168 | } |
1169 | |
1170 | +class CManager : public ubuntu::app_launch::Registry::Manager |
1171 | +{ |
1172 | +public: |
1173 | + CManager () { |
1174 | + g_debug("Creating the CManager object"); |
1175 | + } |
1176 | + |
1177 | + void startingRequest(std::shared_ptr<ubuntu::app_launch::Application> app, |
1178 | + std::shared_ptr<ubuntu::app_launch::Application::Instance> instance, |
1179 | + std::function<void(bool)> reply) override { |
1180 | + std::string sappid = app->appId(); |
1181 | + g_debug("CManager starting: %s", sappid.c_str()); |
1182 | + |
1183 | + for (const auto &data : startingList) { |
1184 | + executeOnContext(data.context, [data, sappid]() { |
1185 | + data.observer(sappid.c_str(), data.user_data); |
1186 | + }); |
1187 | + } |
1188 | + |
1189 | + reply(true); |
1190 | + } |
1191 | + |
1192 | + void focusRequest(std::shared_ptr<ubuntu::app_launch::Application> app, |
1193 | + std::shared_ptr<ubuntu::app_launch::Application::Instance> instance, |
1194 | + std::function<void(bool)> reply) override { |
1195 | + std::string sappid = app->appId(); |
1196 | + g_debug("CManager focus: %s", sappid.c_str()); |
1197 | + |
1198 | + for (const auto &data : focusList) { |
1199 | + executeOnContext(data.context, [data, sappid]() { |
1200 | + data.observer(sappid.c_str(), data.user_data); |
1201 | + }); |
1202 | + } |
1203 | + |
1204 | + reply(true); |
1205 | + } |
1206 | + |
1207 | + void resumeRequest(std::shared_ptr<ubuntu::app_launch::Application> app, |
1208 | + std::shared_ptr<ubuntu::app_launch::Application::Instance> instance, |
1209 | + std::function<void(bool)> reply) override { |
1210 | + std::string sappid = app->appId(); |
1211 | + g_debug("CManager resume: %s", sappid.c_str()); |
1212 | + |
1213 | + for (const auto &data : resumeList) { |
1214 | + executeOnContext(data.context, [data, sappid]() { |
1215 | + data.observer(sappid.c_str(), data.user_data); |
1216 | + }); |
1217 | + } |
1218 | + |
1219 | + reply(true); |
1220 | + } |
1221 | + |
1222 | +private: |
1223 | + struct ObserverData { |
1224 | + UbuntuAppLaunchAppObserver observer; |
1225 | + gpointer user_data; |
1226 | + std::shared_ptr<GMainContext> context; |
1227 | + |
1228 | + ObserverData(UbuntuAppLaunchAppObserver obs, gpointer ud) |
1229 | + : observer(obs) |
1230 | + , user_data(ud) { |
1231 | + context = std::shared_ptr<GMainContext>(g_main_context_ref_thread_default(), [](GMainContext * context) { g_clear_pointer(&context, g_main_context_unref); }); |
1232 | + } |
1233 | + }; |
1234 | + |
1235 | + std::list<ObserverData> focusList; |
1236 | + std::list<ObserverData> resumeList; |
1237 | + std::list<ObserverData> startingList; |
1238 | + |
1239 | + bool removeList (std::list<ObserverData> &list, UbuntuAppLaunchAppObserver observer, gpointer user_data) { |
1240 | + auto iter = std::find_if(list.begin(), list.end(), [observer, user_data](const ObserverData &data) { |
1241 | + return data.observer == observer && data.user_data == user_data; |
1242 | + }); |
1243 | + |
1244 | + if (iter == list.end()) { |
1245 | + return false; |
1246 | + } |
1247 | + |
1248 | + list.erase(iter); |
1249 | + return true; |
1250 | + } |
1251 | + |
1252 | +public: |
1253 | + void addFocus (UbuntuAppLaunchAppObserver observer, gpointer user_data) { |
1254 | + focusList.emplace_back(ObserverData(observer, user_data)); |
1255 | + } |
1256 | + void addResume (UbuntuAppLaunchAppObserver observer, gpointer user_data) { |
1257 | + resumeList.emplace_back(ObserverData(observer, user_data)); |
1258 | + } |
1259 | + void addStarting (UbuntuAppLaunchAppObserver observer, gpointer user_data) { |
1260 | + startingList.emplace_back(ObserverData(observer, user_data)); |
1261 | + } |
1262 | + bool deleteFocus (UbuntuAppLaunchAppObserver observer, gpointer user_data) { |
1263 | + return removeList(focusList, observer, user_data); |
1264 | + } |
1265 | + bool deleteResume (UbuntuAppLaunchAppObserver observer, gpointer user_data) { |
1266 | + return removeList(resumeList, observer, user_data); |
1267 | + } |
1268 | + bool deleteStarting (UbuntuAppLaunchAppObserver observer, gpointer user_data) { |
1269 | + return removeList(startingList, observer, user_data); |
1270 | + } |
1271 | +}; |
1272 | + |
1273 | +static std::weak_ptr<CManager> cmanager; |
1274 | + |
1275 | /* Generic handler for a bunch of our signals */ |
1276 | static inline void |
1277 | generic_signal_cb (GDBusConnection * conn, const gchar * sender, const gchar * object, const gchar * interface, const gchar * signal, GVariant * params, gpointer user_data) |
1278 | @@ -433,328 +489,158 @@ |
1279 | } |
1280 | } |
1281 | |
1282 | -/* Handle the focus signal when it occurs, call the observer */ |
1283 | -static void |
1284 | -focus_signal_cb (GDBusConnection * conn, const gchar * sender, const gchar * object, const gchar * interface, const gchar * signal, GVariant * params, gpointer user_data) |
1285 | -{ |
1286 | - ual_tracepoint(observer_start, "focus"); |
1287 | - |
1288 | - generic_signal_cb(conn, sender, object, interface, signal, params, user_data); |
1289 | - |
1290 | - ual_tracepoint(observer_finish, "focus"); |
1291 | -} |
1292 | - |
1293 | gboolean |
1294 | ubuntu_app_launch_observer_add_app_focus (UbuntuAppLaunchAppObserver observer, gpointer user_data) |
1295 | { |
1296 | - return add_session_generic(observer, user_data, "UnityFocusRequest", &focus_array, focus_signal_cb); |
1297 | + auto manager = cmanager.lock(); |
1298 | + |
1299 | + if (!manager) { |
1300 | + manager = std::make_shared<CManager>(); |
1301 | + ubuntu::app_launch::Registry::setManager(manager, ubuntu::app_launch::Registry::getDefault()); |
1302 | + cmanager = manager; |
1303 | + } |
1304 | + |
1305 | + manager->addFocus(observer, user_data); |
1306 | + return TRUE; |
1307 | } |
1308 | |
1309 | -/* Handle the resume signal when it occurs, call the observer, then send a signal back when we're done */ |
1310 | -static void |
1311 | -resume_signal_cb (GDBusConnection * conn, const gchar * sender, const gchar * object, const gchar * interface, const gchar * signal, GVariant * params, gpointer user_data) |
1312 | +gboolean |
1313 | +ubuntu_app_launch_observer_delete_app_focus (UbuntuAppLaunchAppObserver observer, gpointer user_data) |
1314 | { |
1315 | - ual_tracepoint(observer_start, "resume"); |
1316 | - |
1317 | - generic_signal_cb(conn, sender, object, interface, signal, params, user_data); |
1318 | - |
1319 | - GError * error = NULL; |
1320 | - g_dbus_connection_emit_signal(conn, |
1321 | - sender, /* destination */ |
1322 | - "/", /* path */ |
1323 | - "com.canonical.UbuntuAppLaunch", /* interface */ |
1324 | - "UnityResumeResponse", /* signal */ |
1325 | - params, /* params, the same */ |
1326 | - &error); |
1327 | - |
1328 | - if (error != NULL) { |
1329 | - g_warning("Unable to emit response signal: %s", error->message); |
1330 | - g_error_free(error); |
1331 | + auto manager = cmanager.lock(); |
1332 | + |
1333 | + if (!manager) { |
1334 | + return FALSE; |
1335 | } |
1336 | |
1337 | - ual_tracepoint(observer_finish, "resume"); |
1338 | + return manager->deleteFocus(observer, user_data) ? TRUE : FALSE; |
1339 | } |
1340 | |
1341 | gboolean |
1342 | ubuntu_app_launch_observer_add_app_resume (UbuntuAppLaunchAppObserver observer, gpointer user_data) |
1343 | { |
1344 | - return add_session_generic(observer, user_data, "UnityResumeRequest", &resume_array, resume_signal_cb); |
1345 | + auto manager = cmanager.lock(); |
1346 | + |
1347 | + if (!manager) { |
1348 | + manager = std::make_shared<CManager>(); |
1349 | + ubuntu::app_launch::Registry::setManager(manager, ubuntu::app_launch::Registry::getDefault()); |
1350 | + cmanager = manager; |
1351 | + } |
1352 | + |
1353 | + manager->addResume(observer, user_data); |
1354 | + return TRUE; |
1355 | } |
1356 | |
1357 | -/* Handle the starting signal when it occurs, call the observer, then send a signal back when we're done */ |
1358 | -static void |
1359 | -starting_signal_cb (GDBusConnection * conn, const gchar * sender, const gchar * object, const gchar * interface, const gchar * signal, GVariant * params, gpointer user_data) |
1360 | +gboolean |
1361 | +ubuntu_app_launch_observer_delete_app_resume (UbuntuAppLaunchAppObserver observer, gpointer user_data) |
1362 | { |
1363 | - ual_tracepoint(observer_start, "starting"); |
1364 | - |
1365 | - generic_signal_cb(conn, sender, object, interface, signal, params, user_data); |
1366 | - |
1367 | - GError * error = NULL; |
1368 | - g_dbus_connection_emit_signal(conn, |
1369 | - sender, /* destination */ |
1370 | - "/", /* path */ |
1371 | - "com.canonical.UbuntuAppLaunch", /* interface */ |
1372 | - "UnityStartingSignal", /* signal */ |
1373 | - params, /* params, the same */ |
1374 | - &error); |
1375 | - |
1376 | - if (error != NULL) { |
1377 | - g_warning("Unable to emit response signal: %s", error->message); |
1378 | - g_error_free(error); |
1379 | + auto manager = cmanager.lock(); |
1380 | + |
1381 | + if (!manager) { |
1382 | + return FALSE; |
1383 | } |
1384 | |
1385 | - ual_tracepoint(observer_finish, "starting"); |
1386 | + return manager->deleteResume(observer, user_data) ? TRUE : FALSE; |
1387 | } |
1388 | |
1389 | gboolean |
1390 | ubuntu_app_launch_observer_add_app_starting (UbuntuAppLaunchAppObserver observer, gpointer user_data) |
1391 | { |
1392 | + auto manager = cmanager.lock(); |
1393 | + |
1394 | + if (!manager) { |
1395 | + manager = std::make_shared<CManager>(); |
1396 | + ubuntu::app_launch::Registry::setManager(manager, ubuntu::app_launch::Registry::getDefault()); |
1397 | + cmanager = manager; |
1398 | + } |
1399 | + |
1400 | ubuntu::app_launch::Registry::Impl::watchingAppStarting(true); |
1401 | - return add_session_generic(observer, user_data, "UnityStartingBroadcast", &starting_array, starting_signal_cb); |
1402 | -} |
1403 | - |
1404 | -/* Handle the failed signal when it occurs, call the observer */ |
1405 | -static void |
1406 | -failed_signal_cb (GDBusConnection * conn, const gchar * sender, const gchar * object, const gchar * interface, const gchar * signal, GVariant * params, gpointer user_data) |
1407 | -{ |
1408 | - failed_observer_t * observer = (failed_observer_t *)user_data; |
1409 | - const gchar * appid = NULL; |
1410 | - const gchar * typestr = NULL; |
1411 | - |
1412 | - ual_tracepoint(observer_start, "failed"); |
1413 | - |
1414 | - if (observer->func != NULL) { |
1415 | - UbuntuAppLaunchAppFailed type = UBUNTU_APP_LAUNCH_APP_FAILED_CRASH; |
1416 | - g_variant_get(params, "(&s&s)", &appid, &typestr); |
1417 | - |
1418 | - if (g_strcmp0("crash", typestr) == 0) { |
1419 | - type = UBUNTU_APP_LAUNCH_APP_FAILED_CRASH; |
1420 | - } else if (g_strcmp0("start-failure", typestr) == 0) { |
1421 | - type = UBUNTU_APP_LAUNCH_APP_FAILED_START_FAILURE; |
1422 | - } else { |
1423 | - g_warning("Application failure type '%s' unknown, reporting as a crash", typestr); |
1424 | - } |
1425 | - |
1426 | - observer->func(appid, type, observer->user_data); |
1427 | - } |
1428 | - |
1429 | - ual_tracepoint(observer_finish, "failed"); |
1430 | -} |
1431 | - |
1432 | -gboolean |
1433 | -ubuntu_app_launch_observer_add_app_failed (UbuntuAppLaunchAppFailedObserver observer, gpointer user_data) |
1434 | -{ |
1435 | - GDBusConnection * conn = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL); |
1436 | - |
1437 | - if (conn == NULL) { |
1438 | - return FALSE; |
1439 | - } |
1440 | - |
1441 | - failed_observer_t * observert = g_new0(failed_observer_t, 1); |
1442 | - |
1443 | - observert->conn = conn; |
1444 | - observert->func = observer; |
1445 | - observert->user_data = user_data; |
1446 | - |
1447 | - failed_array = g_list_prepend(failed_array, observert); |
1448 | - |
1449 | - observert->sighandle = g_dbus_connection_signal_subscribe(conn, |
1450 | - NULL, /* sender */ |
1451 | - "com.canonical.UbuntuAppLaunch", /* interface */ |
1452 | - "ApplicationFailed", /* signal */ |
1453 | - "/", /* path */ |
1454 | - NULL, /* arg0 */ |
1455 | - G_DBUS_SIGNAL_FLAGS_NONE, |
1456 | - failed_signal_cb, |
1457 | - observert, |
1458 | - NULL); /* user data destroy */ |
1459 | - |
1460 | - return TRUE; |
1461 | -} |
1462 | - |
1463 | -/* Handle the paused signal when it occurs, call the observer */ |
1464 | -static void |
1465 | -paused_signal_cb (GDBusConnection * conn, const gchar * sender, const gchar * object, const gchar * interface, const gchar * signal, GVariant * params, gpointer user_data) |
1466 | -{ |
1467 | - paused_resumed_observer_t * observer = (paused_resumed_observer_t *)user_data; |
1468 | - |
1469 | - ual_tracepoint(observer_start, observer->lttng_signal); |
1470 | - |
1471 | - if (observer->func != NULL) { |
1472 | - GArray * pidarray = g_array_new(TRUE, TRUE, sizeof(GPid)); |
1473 | - GVariant * appid = g_variant_get_child_value(params, 0); |
1474 | - GVariant * pids = g_variant_get_child_value(params, 1); |
1475 | - guint64 pid; |
1476 | - GVariantIter thispid; |
1477 | - g_variant_iter_init(&thispid, pids); |
1478 | - |
1479 | - while (g_variant_iter_loop(&thispid, "t", &pid)) { |
1480 | - GPid gpid = (GPid)pid; /* Should be a no-op for most architectures, but just in case */ |
1481 | - g_array_append_val(pidarray, gpid); |
1482 | - } |
1483 | - |
1484 | - observer->func(g_variant_get_string(appid, NULL), (GPid *)pidarray->data, observer->user_data); |
1485 | - |
1486 | - g_array_free(pidarray, TRUE); |
1487 | - g_variant_unref(appid); |
1488 | - g_variant_unref(pids); |
1489 | - } |
1490 | - |
1491 | - ual_tracepoint(observer_finish, observer->lttng_signal); |
1492 | -} |
1493 | - |
1494 | -static gboolean |
1495 | -paused_resumed_generic (UbuntuAppLaunchAppPausedResumedObserver observer, gpointer user_data, GList ** queue, const gchar * signal_name, const gchar * lttng_signal) |
1496 | -{ |
1497 | - GDBusConnection * conn = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL); |
1498 | - |
1499 | - if (conn == NULL) { |
1500 | - return FALSE; |
1501 | - } |
1502 | - |
1503 | - paused_resumed_observer_t * observert = g_new0(paused_resumed_observer_t, 1); |
1504 | - |
1505 | - observert->conn = conn; |
1506 | - observert->func = observer; |
1507 | - observert->user_data = user_data; |
1508 | - observert->lttng_signal = lttng_signal; |
1509 | - |
1510 | - *queue = g_list_prepend(*queue, observert); |
1511 | - |
1512 | - observert->sighandle = g_dbus_connection_signal_subscribe(conn, |
1513 | - NULL, /* sender */ |
1514 | - "com.canonical.UbuntuAppLaunch", /* interface */ |
1515 | - signal_name, /* signal */ |
1516 | - "/", /* path */ |
1517 | - NULL, /* arg0 */ |
1518 | - G_DBUS_SIGNAL_FLAGS_NONE, |
1519 | - paused_signal_cb, |
1520 | - observert, |
1521 | - NULL); /* user data destroy */ |
1522 | - |
1523 | - return TRUE; |
1524 | -} |
1525 | - |
1526 | -gboolean |
1527 | -ubuntu_app_launch_observer_add_app_paused (UbuntuAppLaunchAppPausedResumedObserver observer, gpointer user_data) |
1528 | -{ |
1529 | - return paused_resumed_generic(observer, user_data, &paused_array, "ApplicationPaused", "paused"); |
1530 | -} |
1531 | - |
1532 | -gboolean |
1533 | -ubuntu_app_launch_observer_add_app_resumed (UbuntuAppLaunchAppPausedResumedObserver observer, gpointer user_data) |
1534 | -{ |
1535 | - return paused_resumed_generic(observer, user_data, &resumed_array, "ApplicationResumed", "resumed"); |
1536 | -} |
1537 | - |
1538 | -static gboolean |
1539 | -delete_app_generic (UbuntuAppLaunchAppObserver observer, gpointer user_data, GList ** list) |
1540 | -{ |
1541 | - observer_t * observert = NULL; |
1542 | - GList * look; |
1543 | - |
1544 | - for (look = *list; look != NULL; look = g_list_next(look)) { |
1545 | - observert = (observer_t *)look->data; |
1546 | - |
1547 | - if (observert->func == observer && observert->user_data == user_data) { |
1548 | - break; |
1549 | - } |
1550 | - } |
1551 | - |
1552 | - if (look == NULL) { |
1553 | - return FALSE; |
1554 | - } |
1555 | - |
1556 | - g_dbus_connection_signal_unsubscribe(observert->conn, observert->sighandle); |
1557 | - g_object_unref(observert->conn); |
1558 | - |
1559 | - g_free(observert); |
1560 | - *list = g_list_delete_link(*list, look); |
1561 | - |
1562 | - return TRUE; |
1563 | -} |
1564 | - |
1565 | -gboolean |
1566 | -ubuntu_app_launch_observer_delete_app_started (UbuntuAppLaunchAppObserver observer, gpointer user_data) |
1567 | -{ |
1568 | - return delete_app_generic(observer, user_data, &started_array); |
1569 | -} |
1570 | - |
1571 | -gboolean |
1572 | -ubuntu_app_launch_observer_delete_app_stop (UbuntuAppLaunchAppObserver observer, gpointer user_data) |
1573 | -{ |
1574 | - return delete_app_generic(observer, user_data, &stop_array); |
1575 | -} |
1576 | - |
1577 | -gboolean |
1578 | -ubuntu_app_launch_observer_delete_app_resume (UbuntuAppLaunchAppObserver observer, gpointer user_data) |
1579 | -{ |
1580 | - return delete_app_generic(observer, user_data, &resume_array); |
1581 | -} |
1582 | - |
1583 | -gboolean |
1584 | -ubuntu_app_launch_observer_delete_app_focus (UbuntuAppLaunchAppObserver observer, gpointer user_data) |
1585 | -{ |
1586 | - return delete_app_generic(observer, user_data, &focus_array); |
1587 | + manager->addStarting(observer, user_data); |
1588 | + return TRUE; |
1589 | } |
1590 | |
1591 | gboolean |
1592 | ubuntu_app_launch_observer_delete_app_starting (UbuntuAppLaunchAppObserver observer, gpointer user_data) |
1593 | { |
1594 | + auto manager = cmanager.lock(); |
1595 | + |
1596 | + if (!manager) { |
1597 | + return FALSE; |
1598 | + } |
1599 | + |
1600 | ubuntu::app_launch::Registry::Impl::watchingAppStarting(false); |
1601 | - return delete_app_generic(observer, user_data, &starting_array); |
1602 | + return manager->deleteStarting(observer, user_data) ? TRUE : FALSE; |
1603 | +} |
1604 | + |
1605 | +/* Map of all the observers listening for app stopped */ |
1606 | +static std::map<std::pair<UbuntuAppLaunchAppFailedObserver, gpointer>, core::ScopedConnection> appFailedObservers; |
1607 | + |
1608 | +gboolean |
1609 | +ubuntu_app_launch_observer_add_app_failed (UbuntuAppLaunchAppFailedObserver observer, gpointer user_data) |
1610 | +{ |
1611 | + auto context = std::shared_ptr<GMainContext>(g_main_context_ref_thread_default(), [](GMainContext * context) { g_clear_pointer(&context, g_main_context_unref); }); |
1612 | + |
1613 | + appFailedObservers.emplace(std::make_pair( |
1614 | + std::make_pair(observer, user_data), |
1615 | + core::ScopedConnection( |
1616 | + 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) { |
1617 | + std::string appid = app->appId(); |
1618 | + executeOnContext(context, [appid, type, observer, user_data]() { |
1619 | + UbuntuAppLaunchAppFailed ctype; |
1620 | + |
1621 | + switch (type) { |
1622 | + case ubuntu::app_launch::Registry::FailureType::CRASH: |
1623 | + ctype = UBUNTU_APP_LAUNCH_APP_FAILED_CRASH; |
1624 | + break; |
1625 | + case ubuntu::app_launch::Registry::FailureType::START_FAILURE: |
1626 | + ctype = UBUNTU_APP_LAUNCH_APP_FAILED_START_FAILURE; |
1627 | + break; |
1628 | + } |
1629 | + |
1630 | + observer(appid.c_str(), ctype, user_data); |
1631 | + }); |
1632 | + }) |
1633 | + ) |
1634 | + )); |
1635 | + |
1636 | + return TRUE; |
1637 | } |
1638 | |
1639 | gboolean |
1640 | ubuntu_app_launch_observer_delete_app_failed (UbuntuAppLaunchAppFailedObserver observer, gpointer user_data) |
1641 | { |
1642 | - failed_observer_t * observert = NULL; |
1643 | - GList * look; |
1644 | - |
1645 | - for (look = failed_array; look != NULL; look = g_list_next(look)) { |
1646 | - observert = (failed_observer_t *)look->data; |
1647 | - |
1648 | - if (observert->func == observer && observert->user_data == user_data) { |
1649 | - break; |
1650 | - } |
1651 | - } |
1652 | - |
1653 | - if (look == NULL) { |
1654 | + auto iter = appFailedObservers.find(std::make_pair(observer, user_data)); |
1655 | + |
1656 | + if (iter == appFailedObservers.end()) { |
1657 | return FALSE; |
1658 | } |
1659 | |
1660 | - g_dbus_connection_signal_unsubscribe(observert->conn, observert->sighandle); |
1661 | - g_object_unref(observert->conn); |
1662 | - |
1663 | - g_free(observert); |
1664 | - failed_array = g_list_delete_link(failed_array, look); |
1665 | - |
1666 | + appFailedObservers.erase(iter); |
1667 | return TRUE; |
1668 | } |
1669 | |
1670 | -static gboolean |
1671 | -paused_resumed_delete (UbuntuAppLaunchAppPausedResumedObserver observer, gpointer user_data, GList ** list) |
1672 | +static std::map<std::pair<UbuntuAppLaunchAppPausedResumedObserver, gpointer>, core::ScopedConnection> appPausedObservers; |
1673 | + |
1674 | +gboolean |
1675 | +ubuntu_app_launch_observer_add_app_paused (UbuntuAppLaunchAppPausedResumedObserver observer, gpointer user_data) |
1676 | { |
1677 | - paused_resumed_observer_t * observert = NULL; |
1678 | - GList * look; |
1679 | - |
1680 | - for (look = *list; look != NULL; look = g_list_next(look)) { |
1681 | - observert = (paused_resumed_observer_t *)look->data; |
1682 | - |
1683 | - if (observert->func == observer && observert->user_data == user_data) { |
1684 | - break; |
1685 | - } |
1686 | - } |
1687 | - |
1688 | - if (look == NULL) { |
1689 | - return FALSE; |
1690 | - } |
1691 | - |
1692 | - g_dbus_connection_signal_unsubscribe(observert->conn, observert->sighandle); |
1693 | - g_object_unref(observert->conn); |
1694 | - |
1695 | - g_free(observert); |
1696 | - *list = g_list_delete_link(*list, look); |
1697 | + auto context = std::shared_ptr<GMainContext>(g_main_context_ref_thread_default(), [](GMainContext * context) { g_clear_pointer(&context, g_main_context_unref); }); |
1698 | + |
1699 | + appPausedObservers.emplace(std::make_pair( |
1700 | + std::make_pair(observer, user_data), |
1701 | + core::ScopedConnection( |
1702 | + 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) { |
1703 | + std::vector<pid_t> lpids = pids; |
1704 | + lpids.emplace_back(0); |
1705 | + |
1706 | + std::string appid = app->appId(); |
1707 | + |
1708 | + executeOnContext(context, [appid, observer, user_data, lpids]() { |
1709 | + observer(appid.c_str(), (int *)(lpids.data()), user_data); |
1710 | + }); |
1711 | + }) |
1712 | + ) |
1713 | + )); |
1714 | |
1715 | return TRUE; |
1716 | } |
1717 | @@ -762,13 +648,53 @@ |
1718 | gboolean |
1719 | ubuntu_app_launch_observer_delete_app_paused (UbuntuAppLaunchAppPausedResumedObserver observer, gpointer user_data) |
1720 | { |
1721 | - return paused_resumed_delete(observer, user_data, &paused_array); |
1722 | + auto iter = appPausedObservers.find(std::make_pair(observer, user_data)); |
1723 | + |
1724 | + if (iter == appPausedObservers.end()) { |
1725 | + return FALSE; |
1726 | + } |
1727 | + |
1728 | + appPausedObservers.erase(iter); |
1729 | + return TRUE; |
1730 | +} |
1731 | + |
1732 | +static std::map<std::pair<UbuntuAppLaunchAppPausedResumedObserver, gpointer>, core::ScopedConnection> appResumedObservers; |
1733 | + |
1734 | +gboolean |
1735 | +ubuntu_app_launch_observer_add_app_resumed (UbuntuAppLaunchAppPausedResumedObserver observer, gpointer user_data) |
1736 | +{ |
1737 | + auto context = std::shared_ptr<GMainContext>(g_main_context_ref_thread_default(), [](GMainContext * context) { g_clear_pointer(&context, g_main_context_unref); }); |
1738 | + |
1739 | + appResumedObservers.emplace(std::make_pair( |
1740 | + std::make_pair(observer, user_data), |
1741 | + core::ScopedConnection( |
1742 | + 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) { |
1743 | + std::vector<pid_t> lpids = pids; |
1744 | + lpids.emplace_back(0); |
1745 | + |
1746 | + std::string appid = app->appId(); |
1747 | + |
1748 | + executeOnContext(context, [appid, observer, user_data, lpids]() { |
1749 | + observer(appid.c_str(), (int *)(lpids.data()), user_data); |
1750 | + }); |
1751 | + }) |
1752 | + ) |
1753 | + )); |
1754 | + |
1755 | + return TRUE; |
1756 | } |
1757 | |
1758 | gboolean |
1759 | ubuntu_app_launch_observer_delete_app_resumed (UbuntuAppLaunchAppPausedResumedObserver observer, gpointer user_data) |
1760 | { |
1761 | - return paused_resumed_delete(observer, user_data, &resumed_array); |
1762 | + auto iter = appResumedObservers.find(std::make_pair(observer, user_data)); |
1763 | + |
1764 | + if (iter == appResumedObservers.end()) { |
1765 | + return FALSE; |
1766 | + } |
1767 | + |
1768 | + appResumedObservers.erase(iter); |
1769 | + return TRUE; |
1770 | } |
1771 | |
1772 | typedef void (*per_instance_func_t) (GDBusConnection * con, GVariant * prop_dict, gpointer user_data); |
1773 | |
1774 | === modified file 'tests/CMakeLists.txt' |
1775 | --- tests/CMakeLists.txt 2016-09-14 16:43:36 +0000 |
1776 | +++ tests/CMakeLists.txt 2016-11-07 20:56:13 +0000 |
1777 | @@ -157,6 +157,7 @@ |
1778 | |
1779 | add_custom_target(format-tests |
1780 | COMMAND clang-format -i -style=file |
1781 | + failure-test.cc |
1782 | application-info-desktop.cpp |
1783 | libual-cpp-test.cc |
1784 | list-apps.cpp |
1785 | |
1786 | === modified file 'tests/failure-test.cc' |
1787 | --- tests/failure-test.cc 2016-08-25 18:13:44 +0000 |
1788 | +++ tests/failure-test.cc 2016-11-07 20:56:13 +0000 |
1789 | @@ -17,120 +17,147 @@ |
1790 | * Ted Gould <ted.gould@canonical.com> |
1791 | */ |
1792 | |
1793 | +#include "eventually-fixture.h" |
1794 | +#include "registry.h" |
1795 | +#include <gio/gio.h> |
1796 | +#include <glib/gstdio.h> |
1797 | #include <gtest/gtest.h> |
1798 | -#include <glib/gstdio.h> |
1799 | -#include <gio/gio.h> |
1800 | -#include <ubuntu-app-launch.h> |
1801 | -#include "eventually-fixture.h" |
1802 | |
1803 | class FailureTest : public EventuallyFixture |
1804 | { |
1805 | - private: |
1806 | - GTestDBus * testbus = NULL; |
1807 | - |
1808 | - protected: |
1809 | - virtual void SetUp() { |
1810 | - testbus = g_test_dbus_new(G_TEST_DBUS_NONE); |
1811 | - g_test_dbus_up(testbus); |
1812 | - } |
1813 | - |
1814 | - virtual void TearDown() { |
1815 | - g_test_dbus_down(testbus); |
1816 | - g_clear_object(&testbus); |
1817 | - } |
1818 | +private: |
1819 | + GTestDBus* testbus = NULL; |
1820 | + |
1821 | +protected: |
1822 | + std::shared_ptr<ubuntu::app_launch::Registry> registry; |
1823 | + |
1824 | + virtual void SetUp() |
1825 | + { |
1826 | + /* Click DB test mode */ |
1827 | + g_setenv("TEST_CLICK_DB", "click-db-dir", TRUE); |
1828 | + g_setenv("TEST_CLICK_USER", "test-user", TRUE); |
1829 | + |
1830 | + gchar* linkfarmpath = g_build_filename(CMAKE_SOURCE_DIR, "link-farm", NULL); |
1831 | + g_setenv("UBUNTU_APP_LAUNCH_LINK_FARM", linkfarmpath, TRUE); |
1832 | + g_free(linkfarmpath); |
1833 | + |
1834 | + g_setenv("XDG_DATA_DIRS", CMAKE_SOURCE_DIR, TRUE); |
1835 | + g_setenv("XDG_CACHE_HOME", CMAKE_SOURCE_DIR "/libertine-data", TRUE); |
1836 | + g_setenv("XDG_DATA_HOME", CMAKE_SOURCE_DIR "/libertine-home", TRUE); |
1837 | + |
1838 | + testbus = g_test_dbus_new(G_TEST_DBUS_NONE); |
1839 | + g_test_dbus_up(testbus); |
1840 | + |
1841 | + registry = std::make_shared<ubuntu::app_launch::Registry>(); |
1842 | + } |
1843 | + |
1844 | + virtual void TearDown() |
1845 | + { |
1846 | + registry.reset(); |
1847 | + |
1848 | + g_test_dbus_down(testbus); |
1849 | + g_clear_object(&testbus); |
1850 | + } |
1851 | }; |
1852 | |
1853 | -static void |
1854 | -failed_observer (const gchar * appid, UbuntuAppLaunchAppFailed reason, gpointer user_data) |
1855 | -{ |
1856 | - if (reason == UBUNTU_APP_LAUNCH_APP_FAILED_CRASH) { |
1857 | - std::string * last = static_cast<std::string *>(user_data); |
1858 | - *last = appid; |
1859 | - } |
1860 | -} |
1861 | - |
1862 | TEST_F(FailureTest, CrashTest) |
1863 | { |
1864 | - g_setenv("EXIT_STATUS", "-100", TRUE); |
1865 | - g_setenv("JOB", "application-click", TRUE); |
1866 | - g_setenv("INSTANCE", "foo", TRUE); |
1867 | - |
1868 | - std::string last_observer; |
1869 | - ASSERT_TRUE(ubuntu_app_launch_observer_add_app_failed(failed_observer, &last_observer)); |
1870 | - |
1871 | - /* Status based */ |
1872 | - ASSERT_TRUE(g_spawn_command_line_sync(APP_FAILED_TOOL, NULL, NULL, NULL, NULL)); |
1873 | - |
1874 | - EXPECT_EVENTUALLY_EQ("foo", last_observer); |
1875 | - |
1876 | - last_observer.clear(); |
1877 | - g_unsetenv("EXIT_STATUS"); |
1878 | - g_setenv("EXIT_SIGNAL", "KILL", TRUE); |
1879 | - |
1880 | - /* Signal based */ |
1881 | - ASSERT_TRUE(g_spawn_command_line_sync(APP_FAILED_TOOL, NULL, NULL, NULL, NULL)); |
1882 | - |
1883 | - EXPECT_EVENTUALLY_EQ("foo", last_observer); |
1884 | - |
1885 | - ASSERT_TRUE(ubuntu_app_launch_observer_delete_app_failed(failed_observer, &last_observer)); |
1886 | + g_setenv("EXIT_STATUS", "-100", TRUE); |
1887 | + g_setenv("JOB", "application-click", TRUE); |
1888 | + g_setenv("INSTANCE", "foo", TRUE); |
1889 | + |
1890 | + std::string last_observer; |
1891 | + ubuntu::app_launch::Registry::appFailed(registry).connect( |
1892 | + [&last_observer](std::shared_ptr<ubuntu::app_launch::Application> app, |
1893 | + std::shared_ptr<ubuntu::app_launch::Application::Instance> instance, |
1894 | + ubuntu::app_launch::Registry::FailureType type) { |
1895 | + if (type == ubuntu::app_launch::Registry::FailureType::CRASH) |
1896 | + { |
1897 | + last_observer = app->appId(); |
1898 | + } |
1899 | + }); |
1900 | + |
1901 | + /* Status based */ |
1902 | + ASSERT_TRUE(g_spawn_command_line_sync(APP_FAILED_TOOL, NULL, NULL, NULL, NULL)); |
1903 | + |
1904 | + EXPECT_EVENTUALLY_EQ("foo", last_observer); |
1905 | + |
1906 | + last_observer.clear(); |
1907 | + g_unsetenv("EXIT_STATUS"); |
1908 | + g_setenv("EXIT_SIGNAL", "KILL", TRUE); |
1909 | + |
1910 | + /* Signal based */ |
1911 | + ASSERT_TRUE(g_spawn_command_line_sync(APP_FAILED_TOOL, NULL, NULL, NULL, NULL)); |
1912 | + |
1913 | + EXPECT_EVENTUALLY_EQ("foo", last_observer); |
1914 | } |
1915 | |
1916 | TEST_F(FailureTest, LegacyTest) |
1917 | { |
1918 | - g_setenv("EXIT_STATUS", "-100", TRUE); |
1919 | - g_setenv("JOB", "application-legacy", TRUE); |
1920 | - g_setenv("INSTANCE", "foo-1234", TRUE); |
1921 | - |
1922 | - std::string last_observer; |
1923 | - ASSERT_TRUE(ubuntu_app_launch_observer_add_app_failed(failed_observer, &last_observer)); |
1924 | - |
1925 | - /* Status based */ |
1926 | - ASSERT_TRUE(g_spawn_command_line_sync(APP_FAILED_TOOL, NULL, NULL, NULL, NULL)); |
1927 | - |
1928 | - EXPECT_EVENTUALLY_EQ("foo", last_observer); |
1929 | - |
1930 | - ASSERT_TRUE(ubuntu_app_launch_observer_delete_app_failed(failed_observer, &last_observer)); |
1931 | + g_setenv("EXIT_STATUS", "-100", TRUE); |
1932 | + g_setenv("JOB", "application-legacy", TRUE); |
1933 | + g_setenv("INSTANCE", "foo-1234", TRUE); |
1934 | + |
1935 | + std::string last_observer; |
1936 | + ubuntu::app_launch::Registry::appFailed(registry).connect( |
1937 | + [&last_observer](std::shared_ptr<ubuntu::app_launch::Application> app, |
1938 | + std::shared_ptr<ubuntu::app_launch::Application::Instance> instance, |
1939 | + ubuntu::app_launch::Registry::FailureType type) { |
1940 | + g_debug("Signal handler called"); |
1941 | + if (type == ubuntu::app_launch::Registry::FailureType::CRASH) |
1942 | + { |
1943 | + last_observer = app->appId(); |
1944 | + } |
1945 | + }); |
1946 | + |
1947 | + /* Status based */ |
1948 | + ASSERT_TRUE(g_spawn_command_line_sync(APP_FAILED_TOOL, NULL, NULL, NULL, NULL)); |
1949 | + |
1950 | + EXPECT_EVENTUALLY_EQ("foo", last_observer); |
1951 | } |
1952 | |
1953 | TEST_F(FailureTest, SnapTest) |
1954 | { |
1955 | - g_setenv("EXIT_STATUS", "-100", TRUE); |
1956 | - g_setenv("JOB", "application-snap", TRUE); |
1957 | - g_setenv("INSTANCE", "foo_bar_x123-1234", TRUE); |
1958 | - |
1959 | - std::string last_observer; |
1960 | - ASSERT_TRUE(ubuntu_app_launch_observer_add_app_failed(failed_observer, &last_observer)); |
1961 | - |
1962 | - /* Status based */ |
1963 | - ASSERT_TRUE(g_spawn_command_line_sync(APP_FAILED_TOOL, NULL, NULL, NULL, NULL)); |
1964 | - |
1965 | - EXPECT_EVENTUALLY_EQ("foo_bar_x123", last_observer); |
1966 | - |
1967 | - ASSERT_TRUE(ubuntu_app_launch_observer_delete_app_failed(failed_observer, &last_observer)); |
1968 | -} |
1969 | - |
1970 | -static void |
1971 | -failed_start_observer (const gchar * appid, UbuntuAppLaunchAppFailed reason, gpointer user_data) |
1972 | -{ |
1973 | - if (reason == UBUNTU_APP_LAUNCH_APP_FAILED_START_FAILURE) { |
1974 | - std::string * last = static_cast<std::string *>(user_data); |
1975 | - *last = appid; |
1976 | - } |
1977 | + g_setenv("EXIT_STATUS", "-100", TRUE); |
1978 | + g_setenv("JOB", "application-snap", TRUE); |
1979 | + g_setenv("INSTANCE", "com.test.good_application_1.2.3-1234", TRUE); |
1980 | + |
1981 | + std::string last_observer; |
1982 | + ubuntu::app_launch::Registry::appFailed(registry).connect( |
1983 | + [&last_observer](std::shared_ptr<ubuntu::app_launch::Application> app, |
1984 | + std::shared_ptr<ubuntu::app_launch::Application::Instance> instance, |
1985 | + ubuntu::app_launch::Registry::FailureType type) { |
1986 | + if (type == ubuntu::app_launch::Registry::FailureType::CRASH) |
1987 | + { |
1988 | + last_observer = app->appId(); |
1989 | + } |
1990 | + }); |
1991 | + |
1992 | + /* Status based */ |
1993 | + ASSERT_TRUE(g_spawn_command_line_sync(APP_FAILED_TOOL, NULL, NULL, NULL, NULL)); |
1994 | + |
1995 | + EXPECT_EVENTUALLY_EQ("com.test.good_application_1.2.3", last_observer); |
1996 | } |
1997 | |
1998 | TEST_F(FailureTest, StartTest) |
1999 | { |
2000 | - g_setenv("JOB", "application-click", TRUE); |
2001 | - g_setenv("INSTANCE", "foo", TRUE); |
2002 | - g_unsetenv("EXIT_STATUS"); |
2003 | - g_unsetenv("EXIT_SIGNAL"); |
2004 | - |
2005 | - std::string last_observer; |
2006 | - ASSERT_TRUE(ubuntu_app_launch_observer_add_app_failed(failed_start_observer, &last_observer)); |
2007 | - |
2008 | - ASSERT_TRUE(g_spawn_command_line_sync(APP_FAILED_TOOL, NULL, NULL, NULL, NULL)); |
2009 | - |
2010 | - EXPECT_EVENTUALLY_EQ("foo", last_observer); |
2011 | - |
2012 | - ASSERT_TRUE(ubuntu_app_launch_observer_delete_app_failed(failed_start_observer, &last_observer)); |
2013 | + g_setenv("JOB", "application-click", TRUE); |
2014 | + g_setenv("INSTANCE", "foo", TRUE); |
2015 | + g_unsetenv("EXIT_STATUS"); |
2016 | + g_unsetenv("EXIT_SIGNAL"); |
2017 | + |
2018 | + std::string last_observer; |
2019 | + ubuntu::app_launch::Registry::appFailed(registry).connect( |
2020 | + [&last_observer](std::shared_ptr<ubuntu::app_launch::Application> app, |
2021 | + std::shared_ptr<ubuntu::app_launch::Application::Instance> instance, |
2022 | + ubuntu::app_launch::Registry::FailureType type) { |
2023 | + if (type == ubuntu::app_launch::Registry::FailureType::START_FAILURE) |
2024 | + { |
2025 | + last_observer = app->appId(); |
2026 | + } |
2027 | + }); |
2028 | + |
2029 | + ASSERT_TRUE(g_spawn_command_line_sync(APP_FAILED_TOOL, NULL, NULL, NULL, NULL)); |
2030 | + |
2031 | + EXPECT_EVENTUALLY_EQ("foo", last_observer); |
2032 | } |
2033 | |
2034 | === modified file 'tests/libual-cpp-test.cc' |
2035 | --- tests/libual-cpp-test.cc 2016-09-23 20:36:31 +0000 |
2036 | +++ tests/libual-cpp-test.cc 2016-11-07 20:56:13 +0000 |
2037 | @@ -49,32 +49,68 @@ |
2038 | DbusTestDbusMock* mock = NULL; |
2039 | DbusTestDbusMock* cgmock = NULL; |
2040 | GDBusConnection* bus = NULL; |
2041 | - std::string last_focus_appid; |
2042 | - std::string last_resume_appid; |
2043 | guint resume_timeout = 0; |
2044 | std::shared_ptr<ubuntu::app_launch::Registry> registry; |
2045 | |
2046 | -private: |
2047 | - static void focus_cb(const gchar* appid, gpointer user_data) |
2048 | - { |
2049 | - g_debug("Focus Callback: %s", appid); |
2050 | - LibUAL* _this = static_cast<LibUAL*>(user_data); |
2051 | - _this->last_focus_appid = appid; |
2052 | - } |
2053 | - |
2054 | - static void resume_cb(const gchar* appid, gpointer user_data) |
2055 | - { |
2056 | - g_debug("Resume Callback: %s", appid); |
2057 | - LibUAL* _this = static_cast<LibUAL*>(user_data); |
2058 | - _this->last_resume_appid = appid; |
2059 | - |
2060 | - if (_this->resume_timeout > 0) |
2061 | - { |
2062 | - _this->pause(_this->resume_timeout); |
2063 | - } |
2064 | - } |
2065 | - |
2066 | -protected: |
2067 | + class ManagerMock : public ubuntu::app_launch::Registry::Manager |
2068 | + { |
2069 | + GLib::ContextThread thread; |
2070 | + |
2071 | + public: |
2072 | + ManagerMock() |
2073 | + { |
2074 | + g_debug("Building a Manager Mock"); |
2075 | + } |
2076 | + |
2077 | + ~ManagerMock() |
2078 | + { |
2079 | + g_debug("Freeing a Manager Mock"); |
2080 | + } |
2081 | + |
2082 | + ubuntu::app_launch::AppID lastStartedApp; |
2083 | + ubuntu::app_launch::AppID lastFocusedApp; |
2084 | + ubuntu::app_launch::AppID lastResumedApp; |
2085 | + |
2086 | + bool startingResponse{true}; |
2087 | + bool focusResponse{true}; |
2088 | + bool resumeResponse{true}; |
2089 | + |
2090 | + std::chrono::milliseconds startingTimeout{0}; |
2091 | + std::chrono::milliseconds focusTimeout{0}; |
2092 | + std::chrono::milliseconds resumeTimeout{0}; |
2093 | + |
2094 | + void startingRequest(std::shared_ptr<ubuntu::app_launch::Application> app, |
2095 | + std::shared_ptr<ubuntu::app_launch::Application::Instance> instance, |
2096 | + std::function<void(bool)> reply) override |
2097 | + { |
2098 | + thread.timeout(startingTimeout, [this, app, instance, reply]() { |
2099 | + lastStartedApp = app->appId(); |
2100 | + reply(startingResponse); |
2101 | + }); |
2102 | + } |
2103 | + |
2104 | + void focusRequest(std::shared_ptr<ubuntu::app_launch::Application> app, |
2105 | + std::shared_ptr<ubuntu::app_launch::Application::Instance> instance, |
2106 | + std::function<void(bool)> reply) override |
2107 | + { |
2108 | + thread.timeout(focusTimeout, [this, app, instance, reply]() { |
2109 | + lastFocusedApp = app->appId(); |
2110 | + reply(focusResponse); |
2111 | + }); |
2112 | + } |
2113 | + |
2114 | + void resumeRequest(std::shared_ptr<ubuntu::app_launch::Application> app, |
2115 | + std::shared_ptr<ubuntu::app_launch::Application::Instance> instance, |
2116 | + std::function<void(bool)> reply) override |
2117 | + { |
2118 | + thread.timeout(resumeTimeout, [this, app, instance, reply]() { |
2119 | + lastResumedApp = app->appId(); |
2120 | + reply(resumeResponse); |
2121 | + }); |
2122 | + } |
2123 | + }; |
2124 | + std::weak_ptr<ManagerMock> manager; |
2125 | + |
2126 | /* Useful debugging stuff, but not on by default. You really want to |
2127 | not get all this noise typically */ |
2128 | void debugConnection() |
2129 | @@ -127,13 +163,13 @@ |
2130 | |
2131 | dbus_test_dbus_mock_object_add_method(mock, obj, "GetJobByName", G_VARIANT_TYPE("s"), G_VARIANT_TYPE("o"), |
2132 | "if args[0] == 'application-click':\n" |
2133 | - " ret = dbus.ObjectPath('/com/test/application_click')\n" |
2134 | + " ret = dbus.ObjectPath('/com/test/application_click')\n" |
2135 | "elif args[0] == 'application-snap':\n" |
2136 | - " ret = dbus.ObjectPath('/com/test/application_snap')\n" |
2137 | + " ret = dbus.ObjectPath('/com/test/application_snap')\n" |
2138 | "elif args[0] == 'application-legacy':\n" |
2139 | - " ret = dbus.ObjectPath('/com/test/application_legacy')\n" |
2140 | + " ret = dbus.ObjectPath('/com/test/application_legacy')\n" |
2141 | "elif args[0] == 'untrusted-helper':\n" |
2142 | - " ret = dbus.ObjectPath('/com/test/untrusted/helper')\n", |
2143 | + " ret = dbus.ObjectPath('/com/test/untrusted/helper')\n", |
2144 | NULL); |
2145 | |
2146 | dbus_test_dbus_mock_object_add_method(mock, obj, "SetEnv", G_VARIANT_TYPE("(assb)"), NULL, "", NULL); |
2147 | @@ -272,19 +308,23 @@ |
2148 | /* Make sure we pretend the CG manager is just on our bus */ |
2149 | g_setenv("UBUNTU_APP_LAUNCH_CG_MANAGER_SESSION_BUS", "YES", TRUE); |
2150 | |
2151 | - ASSERT_TRUE(ubuntu_app_launch_observer_add_app_focus(focus_cb, this)); |
2152 | - ASSERT_TRUE(ubuntu_app_launch_observer_add_app_resume(resume_cb, this)); |
2153 | - |
2154 | registry = std::make_shared<ubuntu::app_launch::Registry>(); |
2155 | + |
2156 | + auto smanager = std::make_shared<ManagerMock>(); |
2157 | + manager = smanager; |
2158 | + ubuntu::app_launch::Registry::setManager(smanager, registry); |
2159 | } |
2160 | |
2161 | virtual void TearDown() |
2162 | { |
2163 | - ubuntu_app_launch_observer_delete_app_focus(focus_cb, this); |
2164 | - ubuntu_app_launch_observer_delete_app_resume(resume_cb, this); |
2165 | - |
2166 | registry.reset(); |
2167 | |
2168 | + // NOTE: This should generally always be commented out, but |
2169 | + // it is useful for debugging common errors, so leaving it |
2170 | + // as a comment to make debugging those eaiser. |
2171 | + // |
2172 | + // ubuntu::app_launch::Registry::clearDefault(); |
2173 | + |
2174 | g_clear_object(&mock); |
2175 | g_clear_object(&cgmock); |
2176 | g_clear_object(&service); |
2177 | @@ -793,33 +833,30 @@ |
2178 | #endif |
2179 | } |
2180 | |
2181 | -typedef struct |
2182 | -{ |
2183 | - unsigned int count; |
2184 | - const gchar* name; |
2185 | -} observer_data_t; |
2186 | - |
2187 | -static void observer_cb(const gchar* appid, gpointer user_data) |
2188 | -{ |
2189 | - observer_data_t* data = (observer_data_t*)user_data; |
2190 | - |
2191 | - if (data->name == NULL) |
2192 | - { |
2193 | - data->count++; |
2194 | - } |
2195 | - else if (g_strcmp0(data->name, appid) == 0) |
2196 | - { |
2197 | - data->count++; |
2198 | - } |
2199 | -} |
2200 | - |
2201 | TEST_F(LibUAL, StartStopObserver) |
2202 | { |
2203 | - observer_data_t start_data = {.count = 0, .name = nullptr}; |
2204 | - observer_data_t stop_data = {.count = 0, .name = nullptr}; |
2205 | - |
2206 | - ASSERT_TRUE(ubuntu_app_launch_observer_add_app_started(observer_cb, &start_data)); |
2207 | - ASSERT_TRUE(ubuntu_app_launch_observer_add_app_stop(observer_cb, &stop_data)); |
2208 | + int start_count = 0; |
2209 | + int stop_count = 0; |
2210 | + ubuntu::app_launch::AppID start_appid; |
2211 | + ubuntu::app_launch::AppID stop_appid; |
2212 | + |
2213 | + ubuntu::app_launch::Registry::appStarted(registry).connect( |
2214 | + [&start_count, &start_appid](std::shared_ptr<ubuntu::app_launch::Application> app, |
2215 | + std::shared_ptr<ubuntu::app_launch::Application::Instance> instance) { |
2216 | + if (!start_appid.empty() && !(start_appid == app->appId())) |
2217 | + return; |
2218 | + |
2219 | + start_count++; |
2220 | + }); |
2221 | + |
2222 | + ubuntu::app_launch::Registry::appStopped(registry).connect( |
2223 | + [&stop_count, &stop_appid](std::shared_ptr<ubuntu::app_launch::Application> app, |
2224 | + std::shared_ptr<ubuntu::app_launch::Application::Instance> instance) { |
2225 | + if (!stop_appid.empty() && !(stop_appid == app->appId())) |
2226 | + return; |
2227 | + |
2228 | + stop_count++; |
2229 | + }); |
2230 | |
2231 | DbusTestDbusMockObject* obj = |
2232 | dbus_test_dbus_mock_get_object(mock, "/com/ubuntu/Upstart", "com.ubuntu.Upstart0_6", NULL); |
2233 | @@ -830,7 +867,7 @@ |
2234 | g_variant_new_parsed("('started', ['JOB=application-click', 'INSTANCE=com.test.good_application_1.2.3'])"), |
2235 | NULL); |
2236 | |
2237 | - EXPECT_EVENTUALLY_EQ(1, start_data.count); |
2238 | + EXPECT_EVENTUALLY_EQ(1, start_count); |
2239 | |
2240 | /* Basic stop */ |
2241 | dbus_test_dbus_mock_object_emit_signal( |
2242 | @@ -838,33 +875,41 @@ |
2243 | g_variant_new_parsed("('stopped', ['JOB=application-click', 'INSTANCE=com.test.good_application_1.2.3'])"), |
2244 | NULL); |
2245 | |
2246 | - EXPECT_EVENTUALLY_EQ(1, stop_data.count); |
2247 | + EXPECT_EVENTUALLY_EQ(1, stop_count); |
2248 | |
2249 | /* Start legacy */ |
2250 | - start_data.count = 0; |
2251 | - start_data.name = "multiple"; |
2252 | + start_count = 0; |
2253 | + start_appid = ubuntu::app_launch::AppID{ubuntu::app_launch::AppID::Package::from_raw({}), |
2254 | + ubuntu::app_launch::AppID::AppName::from_raw("multiple"), |
2255 | + ubuntu::app_launch::AppID::Version::from_raw({})}; |
2256 | |
2257 | dbus_test_dbus_mock_object_emit_signal( |
2258 | mock, obj, "EventEmitted", G_VARIANT_TYPE("(sas)"), |
2259 | g_variant_new_parsed("('started', ['JOB=application-legacy', 'INSTANCE=multiple-234235'])"), NULL); |
2260 | |
2261 | - EXPECT_EVENTUALLY_EQ(1, start_data.count); |
2262 | + EXPECT_EVENTUALLY_EQ(1, start_count); |
2263 | |
2264 | /* Legacy stop */ |
2265 | - stop_data.count = 0; |
2266 | - stop_data.name = "bar"; |
2267 | + stop_count = 0; |
2268 | + stop_appid = ubuntu::app_launch::AppID{ubuntu::app_launch::AppID::Package::from_raw({}), |
2269 | + ubuntu::app_launch::AppID::AppName::from_raw("foo"), |
2270 | + ubuntu::app_launch::AppID::Version::from_raw({})}; |
2271 | |
2272 | dbus_test_dbus_mock_object_emit_signal( |
2273 | mock, obj, "EventEmitted", G_VARIANT_TYPE("(sas)"), |
2274 | - g_variant_new_parsed("('stopped', ['JOB=application-legacy', 'INSTANCE=bar-9344321'])"), NULL); |
2275 | + g_variant_new_parsed("('stopped', ['JOB=application-legacy', 'INSTANCE=foo-9344321'])"), NULL); |
2276 | |
2277 | - EXPECT_EVENTUALLY_EQ(1, stop_data.count); |
2278 | + EXPECT_EVENTUALLY_EQ(1, stop_count); |
2279 | |
2280 | /* Test Noise Start */ |
2281 | - start_data.count = 0; |
2282 | - start_data.name = "com.test.good_application_1.2.3"; |
2283 | - stop_data.count = 0; |
2284 | - stop_data.name = "com.test.good_application_1.2.3"; |
2285 | + start_count = 0; |
2286 | + start_appid = ubuntu::app_launch::AppID{ubuntu::app_launch::AppID::Package::from_raw("com.test.good"), |
2287 | + ubuntu::app_launch::AppID::AppName::from_raw("application"), |
2288 | + ubuntu::app_launch::AppID::Version::from_raw("1.2.3")}; |
2289 | + stop_count = 0; |
2290 | + stop_appid = ubuntu::app_launch::AppID{ubuntu::app_launch::AppID::Package::from_raw("com.test.good"), |
2291 | + ubuntu::app_launch::AppID::AppName::from_raw("application"), |
2292 | + ubuntu::app_launch::AppID::Version::from_raw("1.2.3")}; |
2293 | |
2294 | /* A full lifecycle */ |
2295 | dbus_test_dbus_mock_object_emit_signal( |
2296 | @@ -885,46 +930,33 @@ |
2297 | NULL); |
2298 | |
2299 | /* Ensure we just signaled once for each */ |
2300 | - EXPECT_EVENTUALLY_EQ(1, start_data.count); |
2301 | - EXPECT_EVENTUALLY_EQ(1, stop_data.count); |
2302 | - |
2303 | - /* Remove */ |
2304 | - ASSERT_TRUE(ubuntu_app_launch_observer_delete_app_started(observer_cb, &start_data)); |
2305 | - ASSERT_TRUE(ubuntu_app_launch_observer_delete_app_stop(observer_cb, &stop_data)); |
2306 | -} |
2307 | - |
2308 | -static GDBusMessage* filter_starting(GDBusConnection* conn, |
2309 | - GDBusMessage* message, |
2310 | - gboolean incomming, |
2311 | - gpointer user_data) |
2312 | -{ |
2313 | - if (g_strcmp0(g_dbus_message_get_member(message), "UnityStartingSignal") == 0) |
2314 | - { |
2315 | - unsigned int* count = static_cast<unsigned int*>(user_data); |
2316 | - (*count)++; |
2317 | - g_object_unref(message); |
2318 | - return NULL; |
2319 | - } |
2320 | - |
2321 | - return message; |
2322 | -} |
2323 | - |
2324 | -static void starting_observer(const gchar* appid, gpointer user_data) |
2325 | -{ |
2326 | - std::string* last = static_cast<std::string*>(user_data); |
2327 | - *last = appid; |
2328 | - return; |
2329 | + EXPECT_EVENTUALLY_EQ(1, start_count); |
2330 | + EXPECT_EVENTUALLY_EQ(1, stop_count); |
2331 | } |
2332 | |
2333 | TEST_F(LibUAL, StartingResponses) |
2334 | { |
2335 | - std::string last_observer; |
2336 | + /* Get Bus */ |
2337 | + GDBusConnection* session = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL); |
2338 | + |
2339 | + /* Setup filter to count signals out */ |
2340 | unsigned int starting_count = 0; |
2341 | - GDBusConnection* session = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL); |
2342 | - guint filter = g_dbus_connection_add_filter(session, filter_starting, &starting_count, NULL); |
2343 | - |
2344 | - EXPECT_TRUE(ubuntu_app_launch_observer_add_app_starting(starting_observer, &last_observer)); |
2345 | - |
2346 | + guint filter = g_dbus_connection_add_filter( |
2347 | + session, |
2348 | + [](GDBusConnection* conn, GDBusMessage* message, gboolean incomming, gpointer user_data) -> GDBusMessage* { |
2349 | + if (g_strcmp0(g_dbus_message_get_member(message), "UnityStartingSignal") == 0) |
2350 | + { |
2351 | + unsigned int* count = static_cast<unsigned int*>(user_data); |
2352 | + (*count)++; |
2353 | + g_object_unref(message); |
2354 | + return NULL; |
2355 | + } |
2356 | + |
2357 | + return message; |
2358 | + }, |
2359 | + &starting_count, NULL); |
2360 | + |
2361 | + /* Emit a signal */ |
2362 | g_dbus_connection_emit_signal(session, NULL, /* destination */ |
2363 | "/", /* path */ |
2364 | "com.canonical.UbuntuAppLaunch", /* interface */ |
2365 | @@ -932,11 +964,15 @@ |
2366 | g_variant_new("(s)", "com.test.good_application_1.2.3"), /* params, the same */ |
2367 | NULL); |
2368 | |
2369 | - EXPECT_EVENTUALLY_EQ("com.test.good_application_1.2.3", last_observer); |
2370 | + /* Make sure we run our observer */ |
2371 | + EXPECT_EVENTUALLY_EQ(ubuntu::app_launch::AppID(ubuntu::app_launch::AppID::Package::from_raw("com.test.good"), |
2372 | + ubuntu::app_launch::AppID::AppName::from_raw("application"), |
2373 | + ubuntu::app_launch::AppID::Version::from_raw("1.2.3")), |
2374 | + manager.lock()->lastStartedApp); |
2375 | + |
2376 | + /* Make sure we return */ |
2377 | EXPECT_EVENTUALLY_EQ(1, starting_count); |
2378 | |
2379 | - EXPECT_TRUE(ubuntu_app_launch_observer_delete_app_starting(starting_observer, &last_observer)); |
2380 | - |
2381 | g_dbus_connection_remove_filter(session, filter); |
2382 | g_object_unref(session); |
2383 | } |
2384 | @@ -947,8 +983,10 @@ |
2385 | auto app = ubuntu::app_launch::Application::create(appid, registry); |
2386 | app->launch(); |
2387 | |
2388 | - EXPECT_EVENTUALLY_EQ("com.test.good_application_1.2.3", this->last_focus_appid); |
2389 | - EXPECT_EVENTUALLY_EQ("com.test.good_application_1.2.3", this->last_resume_appid); |
2390 | + EXPECT_EVENTUALLY_EQ(ubuntu::app_launch::AppID::parse("com.test.good_application_1.2.3"), |
2391 | + this->manager.lock()->lastFocusedApp); |
2392 | + EXPECT_EVENTUALLY_EQ(ubuntu::app_launch::AppID::parse("com.test.good_application_1.2.3"), |
2393 | + this->manager.lock()->lastResumedApp); |
2394 | } |
2395 | |
2396 | GDBusMessage* filter_func_good(GDBusConnection* conn, GDBusMessage* message, gboolean incomming, gpointer user_data) |
2397 | @@ -982,8 +1020,10 @@ |
2398 | |
2399 | app->launch(uris); |
2400 | |
2401 | - EXPECT_EVENTUALLY_EQ("com.test.good_application_1.2.3", this->last_focus_appid); |
2402 | - EXPECT_EVENTUALLY_EQ("com.test.good_application_1.2.3", this->last_resume_appid); |
2403 | + EXPECT_EVENTUALLY_EQ(ubuntu::app_launch::AppID::parse("com.test.good_application_1.2.3"), |
2404 | + this->manager.lock()->lastFocusedApp); |
2405 | + EXPECT_EVENTUALLY_EQ(ubuntu::app_launch::AppID::parse("com.test.good_application_1.2.3"), |
2406 | + this->manager.lock()->lastResumedApp); |
2407 | |
2408 | g_dbus_connection_remove_filter(session, filter); |
2409 | |
2410 | @@ -1015,8 +1055,10 @@ |
2411 | |
2412 | app->launch(uris); |
2413 | |
2414 | - EXPECT_EVENTUALLY_EQ("com.test.good_application_1.2.3", this->last_focus_appid); |
2415 | - EXPECT_EVENTUALLY_EQ("com.test.good_application_1.2.3", this->last_resume_appid); |
2416 | + EXPECT_EVENTUALLY_EQ(ubuntu::app_launch::AppID::parse("com.test.good_application_1.2.3"), |
2417 | + this->manager.lock()->lastFocusedApp); |
2418 | + EXPECT_EVENTUALLY_EQ(ubuntu::app_launch::AppID::parse("com.test.good_application_1.2.3"), |
2419 | + this->manager.lock()->lastResumedApp); |
2420 | } |
2421 | |
2422 | TEST_F(LibUAL, UnityTimeoutTest) |
2423 | @@ -1028,8 +1070,10 @@ |
2424 | |
2425 | app->launch(); |
2426 | |
2427 | - EXPECT_EVENTUALLY_EQ("com.test.good_application_1.2.3", this->last_resume_appid); |
2428 | - EXPECT_EVENTUALLY_EQ("com.test.good_application_1.2.3", this->last_focus_appid); |
2429 | + EXPECT_EVENTUALLY_EQ(ubuntu::app_launch::AppID::parse("com.test.good_application_1.2.3"), |
2430 | + this->manager.lock()->lastResumedApp); |
2431 | + EXPECT_EVENTUALLY_EQ(ubuntu::app_launch::AppID::parse("com.test.good_application_1.2.3"), |
2432 | + this->manager.lock()->lastFocusedApp); |
2433 | } |
2434 | |
2435 | TEST_F(LibUAL, UnityTimeoutUriTest) |
2436 | @@ -1043,8 +1087,10 @@ |
2437 | |
2438 | app->launch(uris); |
2439 | |
2440 | - EXPECT_EVENTUALLY_EQ("com.test.good_application_1.2.3", this->last_focus_appid); |
2441 | - EXPECT_EVENTUALLY_EQ("com.test.good_application_1.2.3", this->last_resume_appid); |
2442 | + EXPECT_EVENTUALLY_EQ(ubuntu::app_launch::AppID::parse("com.test.good_application_1.2.3"), |
2443 | + this->manager.lock()->lastFocusedApp); |
2444 | + EXPECT_EVENTUALLY_EQ(ubuntu::app_launch::AppID::parse("com.test.good_application_1.2.3"), |
2445 | + this->manager.lock()->lastResumedApp); |
2446 | } |
2447 | |
2448 | GDBusMessage* filter_respawn(GDBusConnection* conn, GDBusMessage* message, gboolean incomming, gpointer user_data) |
2449 | @@ -1077,8 +1123,10 @@ |
2450 | g_debug("Start call time: %d ms", (end - start) / 1000); |
2451 | EXPECT_LT(end - start, 2000 * 1000); |
2452 | |
2453 | - EXPECT_EVENTUALLY_EQ("com.test.good_application_1.2.3", this->last_focus_appid); |
2454 | - EXPECT_EVENTUALLY_EQ("com.test.good_application_1.2.3", this->last_resume_appid); |
2455 | + EXPECT_EVENTUALLY_EQ(ubuntu::app_launch::AppID::parse("com.test.good_application_1.2.3"), |
2456 | + this->manager.lock()->lastFocusedApp); |
2457 | + EXPECT_EVENTUALLY_EQ(ubuntu::app_launch::AppID::parse("com.test.good_application_1.2.3"), |
2458 | + this->manager.lock()->lastResumedApp); |
2459 | |
2460 | g_dbus_connection_remove_filter(session, filter); |
2461 | g_object_unref(session); |
2462 | @@ -1138,23 +1186,21 @@ |
2463 | g_variant_unref(env); |
2464 | } |
2465 | |
2466 | -static void failed_observer(const gchar* appid, UbuntuAppLaunchAppFailed reason, gpointer user_data) |
2467 | -{ |
2468 | - if (reason == UBUNTU_APP_LAUNCH_APP_FAILED_CRASH) |
2469 | - { |
2470 | - std::string* last = static_cast<std::string*>(user_data); |
2471 | - *last = appid; |
2472 | - } |
2473 | - return; |
2474 | -} |
2475 | - |
2476 | TEST_F(LibUAL, FailingObserver) |
2477 | { |
2478 | - std::string last_observer; |
2479 | + ubuntu::app_launch::AppID lastFailedApp; |
2480 | + ubuntu::app_launch::Registry::FailureType lastFailedType; |
2481 | + |
2482 | + ubuntu::app_launch::Registry::appFailed(registry).connect( |
2483 | + [&lastFailedApp, &lastFailedType](std::shared_ptr<ubuntu::app_launch::Application> app, |
2484 | + std::shared_ptr<ubuntu::app_launch::Application::Instance> instance, |
2485 | + ubuntu::app_launch::Registry::FailureType type) { |
2486 | + lastFailedApp = app->appId(); |
2487 | + lastFailedType = type; |
2488 | + }); |
2489 | + |
2490 | GDBusConnection* session = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL); |
2491 | |
2492 | - EXPECT_TRUE(ubuntu_app_launch_observer_add_app_failed(failed_observer, &last_observer)); |
2493 | - |
2494 | g_dbus_connection_emit_signal( |
2495 | session, NULL, /* destination */ |
2496 | "/", /* path */ |
2497 | @@ -1163,9 +1209,10 @@ |
2498 | g_variant_new("(ss)", "com.test.good_application_1.2.3", "crash"), /* params, the same */ |
2499 | NULL); |
2500 | |
2501 | - EXPECT_EVENTUALLY_EQ("com.test.good_application_1.2.3", last_observer); |
2502 | + EXPECT_EVENTUALLY_EQ(ubuntu::app_launch::AppID::parse("com.test.good_application_1.2.3"), lastFailedApp); |
2503 | + EXPECT_EVENTUALLY_EQ(ubuntu::app_launch::Registry::FailureType::CRASH, lastFailedType); |
2504 | |
2505 | - last_observer.clear(); |
2506 | + lastFailedApp = ubuntu::app_launch::AppID(); |
2507 | |
2508 | g_dbus_connection_emit_signal( |
2509 | session, NULL, /* destination */ |
2510 | @@ -1175,9 +1222,9 @@ |
2511 | g_variant_new("(ss)", "com.test.good_application_1.2.3", "blahblah"), /* params, the same */ |
2512 | NULL); |
2513 | |
2514 | - EXPECT_EVENTUALLY_EQ("com.test.good_application_1.2.3", last_observer); |
2515 | + EXPECT_EVENTUALLY_EQ(ubuntu::app_launch::AppID::parse("com.test.good_application_1.2.3"), lastFailedApp); |
2516 | |
2517 | - last_observer.clear(); |
2518 | + lastFailedApp = ubuntu::app_launch::AppID(); |
2519 | |
2520 | g_dbus_connection_emit_signal( |
2521 | session, NULL, /* destination */ |
2522 | @@ -1187,9 +1234,7 @@ |
2523 | g_variant_new("(ss)", "com.test.good_application_1.2.3", "start-failure"), /* params, the same */ |
2524 | NULL); |
2525 | |
2526 | - EXPECT_EVENTUALLY_EQ(true, last_observer.empty()); |
2527 | - |
2528 | - EXPECT_TRUE(ubuntu_app_launch_observer_delete_app_failed(failed_observer, &last_observer)); |
2529 | + EXPECT_EVENTUALLY_EQ(ubuntu::app_launch::Registry::FailureType::START_FAILURE, lastFailedType); |
2530 | |
2531 | g_object_unref(session); |
2532 | } |
2533 | |
2534 | === modified file 'tools/CMakeLists.txt' |
2535 | --- tools/CMakeLists.txt 2016-06-18 18:24:27 +0000 |
2536 | +++ tools/CMakeLists.txt 2016-11-07 20:56:13 +0000 |
2537 | @@ -39,7 +39,7 @@ |
2538 | # ubuntu-app-launch |
2539 | ######################## |
2540 | |
2541 | -add_executable(ubuntu-app-launch ubuntu-app-launch.c) |
2542 | +add_executable(ubuntu-app-launch ubuntu-app-launch.cpp) |
2543 | set_target_properties(ubuntu-app-launch PROPERTIES OUTPUT_NAME "ubuntu-app-launch") |
2544 | target_link_libraries(ubuntu-app-launch ubuntu-launcher) |
2545 | install(TARGETS ubuntu-app-launch RUNTIME DESTINATION "${CMAKE_INSTALL_FULL_BINDIR}") |
2546 | @@ -48,7 +48,7 @@ |
2547 | # ubuntu-app-watch |
2548 | ######################## |
2549 | |
2550 | -add_executable(ubuntu-app-watch ubuntu-app-watch.c) |
2551 | +add_executable(ubuntu-app-watch ubuntu-app-watch.cpp) |
2552 | set_target_properties(ubuntu-app-watch PROPERTIES OUTPUT_NAME "ubuntu-app-watch") |
2553 | target_link_libraries(ubuntu-app-watch ubuntu-launcher) |
2554 | install(TARGETS ubuntu-app-watch RUNTIME DESTINATION "${CMAKE_INSTALL_FULL_BINDIR}") |
2555 | @@ -116,3 +116,22 @@ |
2556 | target_link_libraries(ubuntu-app-usage ubuntu-launcher) |
2557 | install(TARGETS ubuntu-app-usage RUNTIME DESTINATION "${CMAKE_INSTALL_FULL_BINDIR}") |
2558 | |
2559 | +######################## |
2560 | +# Formatting |
2561 | +######################## |
2562 | + |
2563 | +add_custom_target(format-tools |
2564 | + COMMAND clang-format -i -style=file |
2565 | + ubuntu-app-info.cpp |
2566 | + ubuntu-app-launch-appids.cpp |
2567 | + ubuntu-app-launch.cpp |
2568 | + ubuntu-app-list.cpp |
2569 | + ubuntu-app-list-pids.cpp |
2570 | + ubuntu-app-pid.cpp |
2571 | + ubuntu-app-stop.cpp |
2572 | + ubuntu-app-triplet.cpp |
2573 | + ubuntu-app-watch.cpp |
2574 | + ubuntu-helper-list.cpp |
2575 | + ubuntu-helper-start.cpp |
2576 | + ubuntu-helper-stop.cpp |
2577 | +) |
2578 | |
2579 | === modified file 'tools/ubuntu-app-info.cpp' |
2580 | --- tools/ubuntu-app-info.cpp 2016-05-04 14:09:10 +0000 |
2581 | +++ tools/ubuntu-app-info.cpp 2016-11-07 20:56:13 +0000 |
2582 | @@ -17,34 +17,40 @@ |
2583 | * Ted Gould <ted.gould@canonical.com> |
2584 | */ |
2585 | |
2586 | -#include <iostream> |
2587 | #include "libubuntu-app-launch/application.h" |
2588 | #include "libubuntu-app-launch/registry.h" |
2589 | +#include <iostream> |
2590 | |
2591 | -int main(int argc, char* argv[]) |
2592 | +int main(int argc, char *argv[]) |
2593 | { |
2594 | - if (argc != 2) { |
2595 | + if (argc != 2) |
2596 | + { |
2597 | std::cerr << "Usage: " << argv[0] << " (appid)" << std::endl; |
2598 | exit(1); |
2599 | } |
2600 | |
2601 | auto appid = ubuntu::app_launch::AppID::find(argv[1]); |
2602 | - if (appid.empty()) { |
2603 | + if (appid.empty()) |
2604 | + { |
2605 | std::cerr << "Unable to find app for appid: " << argv[1] << std::endl; |
2606 | return 1; |
2607 | } |
2608 | |
2609 | std::shared_ptr<ubuntu::app_launch::Application> app; |
2610 | - try { |
2611 | + try |
2612 | + { |
2613 | app = ubuntu::app_launch::Application::create(appid, ubuntu::app_launch::Registry::getDefault()); |
2614 | if (!app) |
2615 | throw std::runtime_error("Application object is nullptr"); |
2616 | - } catch (std::runtime_error &e) { |
2617 | + } |
2618 | + catch (std::runtime_error &e) |
2619 | + { |
2620 | std::cerr << "Unable to find application for AppID: " << argv[1] << std::endl; |
2621 | exit(1); |
2622 | } |
2623 | |
2624 | - try { |
2625 | + try |
2626 | + { |
2627 | auto info = app->info(); |
2628 | |
2629 | std::cout << "Name: " << info->name().value() << std::endl; |
2630 | @@ -64,8 +70,11 @@ |
2631 | std::cout << " Inv Landscape: " << info->supportedOrientations().invertedLandscape << std::endl; |
2632 | std::cout << "Rotates: " << info->rotatesWindowContents().value() << std::endl; |
2633 | std::cout << "Ubuntu Lifecycle: " << info->supportsUbuntuLifecycle().value() << std::endl; |
2634 | - } catch (std::runtime_error &e) { |
2635 | - std::cerr << "Unable to parse Application info for application '" << std::string(appid) << "': " << e.what() << std::endl; |
2636 | + } |
2637 | + catch (std::runtime_error &e) |
2638 | + { |
2639 | + std::cerr << "Unable to parse Application info for application '" << std::string(appid) << "': " << e.what() |
2640 | + << std::endl; |
2641 | exit(1); |
2642 | } |
2643 | |
2644 | |
2645 | === renamed file 'tools/ubuntu-app-launch.c' => 'tools/ubuntu-app-launch.cpp' |
2646 | --- tools/ubuntu-app-launch.c 2016-02-08 19:03:31 +0000 |
2647 | +++ tools/ubuntu-app-launch.cpp 2016-11-07 20:56:13 +0000 |
2648 | @@ -1,5 +1,5 @@ |
2649 | /* |
2650 | - * Copyright 2013 Canonical Ltd. |
2651 | + * Copyright © 2016 Canonical Ltd. |
2652 | * |
2653 | * This program is free software: you can redistribute it and/or modify it |
2654 | * under the terms of the GNU General Public License version 3, as published |
2655 | @@ -17,71 +17,59 @@ |
2656 | * Ted Gould <ted.gould@canonical.com> |
2657 | */ |
2658 | |
2659 | -#include <glib.h> |
2660 | -#include "libubuntu-app-launch/ubuntu-app-launch.h" |
2661 | - |
2662 | -const gchar * global_appid = NULL; |
2663 | -int retval = 0; |
2664 | - |
2665 | -static void |
2666 | -good_observer (const gchar * appid, gpointer user_data) |
2667 | -{ |
2668 | - if (g_strcmp0(appid, global_appid) != 0) { |
2669 | - return; |
2670 | - } |
2671 | - |
2672 | - g_debug("Application '%s' running", appid); |
2673 | - g_main_loop_quit((GMainLoop *)user_data); |
2674 | -} |
2675 | - |
2676 | -static void |
2677 | -bad_observer (const gchar * appid, UbuntuAppLaunchAppFailed failure_type, gpointer user_data) |
2678 | -{ |
2679 | - if (g_strcmp0(appid, global_appid) != 0) { |
2680 | - return; |
2681 | - } |
2682 | - |
2683 | - g_debug("Application '%s' failed: %s", appid, failure_type == UBUNTU_APP_LAUNCH_APP_FAILED_CRASH ? "crash" : "startup failure"); |
2684 | - retval = -1; |
2685 | - g_main_loop_quit((GMainLoop *)user_data); |
2686 | -} |
2687 | - |
2688 | -int |
2689 | -main (int argc, gchar * argv[]) { |
2690 | - if (argc < 2) { |
2691 | - g_printerr("Usage: %s <app id> [uris]\n", argv[0]); |
2692 | - return 1; |
2693 | - } |
2694 | - |
2695 | - global_appid = argv[1]; |
2696 | - GMainLoop * mainloop = g_main_loop_new(NULL, FALSE); |
2697 | - |
2698 | - gchar ** uris = NULL; |
2699 | - if (argc > 2) { |
2700 | - int i; |
2701 | - |
2702 | - uris = g_new0(gchar *, argc - 1); |
2703 | - |
2704 | - for (i = 2; i < argc; i++) { |
2705 | - uris[i - 2] = argv[i]; |
2706 | - } |
2707 | - } |
2708 | - |
2709 | - ubuntu_app_launch_observer_add_app_started(good_observer, mainloop); |
2710 | - ubuntu_app_launch_observer_add_app_focus(good_observer, mainloop); |
2711 | - |
2712 | - ubuntu_app_launch_observer_add_app_failed(bad_observer, mainloop); |
2713 | - |
2714 | - ubuntu_app_launch_start_application(global_appid, (const gchar * const *)uris); |
2715 | - |
2716 | - g_main_loop_run(mainloop); |
2717 | - |
2718 | - ubuntu_app_launch_observer_delete_app_started(good_observer, mainloop); |
2719 | - ubuntu_app_launch_observer_delete_app_focus(good_observer, mainloop); |
2720 | - ubuntu_app_launch_observer_delete_app_failed(bad_observer, mainloop); |
2721 | - |
2722 | - g_main_loop_unref(mainloop); |
2723 | - g_free(uris); |
2724 | - |
2725 | - return retval; |
2726 | +#include "libubuntu-app-launch/application.h" |
2727 | +#include "libubuntu-app-launch/registry.h" |
2728 | +#include <csignal> |
2729 | +#include <future> |
2730 | +#include <iostream> |
2731 | + |
2732 | +ubuntu::app_launch::AppID global_appid; |
2733 | +std::promise<int> retval; |
2734 | + |
2735 | +int main(int argc, char* argv[]) |
2736 | +{ |
2737 | + if (argc < 2) |
2738 | + { |
2739 | + std::cerr << "Usage: " << argv[0] << " <app id> [uris]" << std::endl; |
2740 | + return 1; |
2741 | + } |
2742 | + |
2743 | + global_appid = ubuntu::app_launch::AppID::find(argv[1]); |
2744 | + |
2745 | + std::vector<ubuntu::app_launch::Application::URL> urls; |
2746 | + for (int i = 2; i < argc; i++) |
2747 | + { |
2748 | + urls.push_back(ubuntu::app_launch::Application::URL::from_raw(argv[i])); |
2749 | + } |
2750 | + |
2751 | + ubuntu::app_launch::Registry::appStarted().connect( |
2752 | + [](std::shared_ptr<ubuntu::app_launch::Application> app, |
2753 | + std::shared_ptr<ubuntu::app_launch::Application::Instance> instance) { |
2754 | + if (app->appId() != global_appid) |
2755 | + { |
2756 | + return; |
2757 | + } |
2758 | + |
2759 | + std::cout << "Started: " << (std::string)app->appId() << std::endl; |
2760 | + retval.set_value(EXIT_SUCCESS); |
2761 | + }); |
2762 | + |
2763 | + ubuntu::app_launch::Registry::appFailed().connect( |
2764 | + [](std::shared_ptr<ubuntu::app_launch::Application> app, |
2765 | + std::shared_ptr<ubuntu::app_launch::Application::Instance> instance, |
2766 | + ubuntu::app_launch::Registry::FailureType type) { |
2767 | + if (app->appId() != global_appid) |
2768 | + { |
2769 | + return; |
2770 | + } |
2771 | + |
2772 | + std::cout << "Failed: " << (std::string)app->appId() << std::endl; |
2773 | + retval.set_value(EXIT_FAILURE); |
2774 | + }); |
2775 | + |
2776 | + auto app = ubuntu::app_launch::Application::create(global_appid, ubuntu::app_launch::Registry::getDefault()); |
2777 | + app->launch(urls); |
2778 | + |
2779 | + std::signal(SIGTERM, [](int signal) -> void { retval.set_value(EXIT_SUCCESS); }); |
2780 | + return retval.get_future().get(); |
2781 | } |
2782 | |
2783 | === modified file 'tools/ubuntu-app-list-pids.cpp' |
2784 | --- tools/ubuntu-app-list-pids.cpp 2016-05-03 01:46:27 +0000 |
2785 | +++ tools/ubuntu-app-list-pids.cpp 2016-11-07 20:56:13 +0000 |
2786 | @@ -30,12 +30,14 @@ |
2787 | } |
2788 | |
2789 | auto appid = ubuntu::app_launch::AppID::find(argv[1]); |
2790 | - if (appid.empty()) { |
2791 | + if (appid.empty()) |
2792 | + { |
2793 | std::cerr << "Unable to find app for appid: " << argv[1] << std::endl; |
2794 | return 1; |
2795 | } |
2796 | |
2797 | - try { |
2798 | + try |
2799 | + { |
2800 | auto app = ubuntu::app_launch::Application::create(appid, ubuntu::app_launch::Registry::getDefault()); |
2801 | |
2802 | for (auto instance : app->instances()) |
2803 | @@ -45,7 +47,9 @@ |
2804 | std::cout << pid << std::endl; |
2805 | } |
2806 | } |
2807 | - } catch (std::runtime_error &e) { |
2808 | + } |
2809 | + catch (std::runtime_error& e) |
2810 | + { |
2811 | std::cerr << "Unable to find application for '" << std::string(appid) << "': " << e.what() << std::endl; |
2812 | return 1; |
2813 | } |
2814 | |
2815 | === modified file 'tools/ubuntu-app-list.cpp' |
2816 | --- tools/ubuntu-app-list.cpp 2016-02-09 21:12:54 +0000 |
2817 | +++ tools/ubuntu-app-list.cpp 2016-11-07 20:56:13 +0000 |
2818 | @@ -17,8 +17,8 @@ |
2819 | * Ted Gould <ted.gould@canonical.com> |
2820 | */ |
2821 | |
2822 | +#include "libubuntu-app-launch/registry.h" |
2823 | #include <iostream> |
2824 | -#include "libubuntu-app-launch/registry.h" |
2825 | |
2826 | int main(int argc, char* argv[]) |
2827 | { |
2828 | |
2829 | === modified file 'tools/ubuntu-app-pid.cpp' |
2830 | --- tools/ubuntu-app-pid.cpp 2016-05-03 01:46:51 +0000 |
2831 | +++ tools/ubuntu-app-pid.cpp 2016-11-07 20:56:13 +0000 |
2832 | @@ -18,8 +18,8 @@ |
2833 | */ |
2834 | |
2835 | #include <iostream> |
2836 | +#include <libubuntu-app-launch/application.h> |
2837 | #include <libubuntu-app-launch/registry.h> |
2838 | -#include <libubuntu-app-launch/application.h> |
2839 | |
2840 | int main(int argc, char* argv[]) |
2841 | { |
2842 | @@ -31,12 +31,14 @@ |
2843 | } |
2844 | |
2845 | auto appid = ubuntu::app_launch::AppID::find(argv[1]); |
2846 | - if (appid.empty()) { |
2847 | + if (appid.empty()) |
2848 | + { |
2849 | std::cerr << "Unable to find app for appid: " << argv[1] << std::endl; |
2850 | return 1; |
2851 | } |
2852 | |
2853 | - try { |
2854 | + try |
2855 | + { |
2856 | auto app = ubuntu::app_launch::Application::create(appid, ubuntu::app_launch::Registry::getDefault()); |
2857 | auto pid = app->instances()[0]->primaryPid(); |
2858 | |
2859 | @@ -47,7 +49,9 @@ |
2860 | |
2861 | std::cout << pid << std::endl; |
2862 | return 0; |
2863 | - } catch (std::runtime_error &e) { |
2864 | + } |
2865 | + catch (std::runtime_error& e) |
2866 | + { |
2867 | std::cerr << "Unable to find application for '" << std::string(appid) << "': " << e.what() << std::endl; |
2868 | return 1; |
2869 | } |
2870 | |
2871 | === modified file 'tools/ubuntu-app-stop.cpp' |
2872 | --- tools/ubuntu-app-stop.cpp 2016-05-03 01:46:27 +0000 |
2873 | +++ tools/ubuntu-app-stop.cpp 2016-11-07 20:56:13 +0000 |
2874 | @@ -30,19 +30,23 @@ |
2875 | } |
2876 | |
2877 | auto appid = ubuntu::app_launch::AppID::find(argv[1]); |
2878 | - if (appid.empty()) { |
2879 | + if (appid.empty()) |
2880 | + { |
2881 | std::cerr << "Unable to find app for appid: " << argv[1] << std::endl; |
2882 | return 1; |
2883 | } |
2884 | |
2885 | - try { |
2886 | + try |
2887 | + { |
2888 | auto app = ubuntu::app_launch::Application::create(appid, ubuntu::app_launch::Registry::getDefault()); |
2889 | |
2890 | for (auto instance : app->instances()) |
2891 | { |
2892 | instance->stop(); |
2893 | } |
2894 | - } catch (std::runtime_error &e) { |
2895 | + } |
2896 | + catch (std::runtime_error& e) |
2897 | + { |
2898 | std::cerr << "Unable to find application for '" << std::string(appid) << "': " << e.what() << std::endl; |
2899 | return 1; |
2900 | } |
2901 | |
2902 | === modified file 'tools/ubuntu-app-triplet.cpp' |
2903 | --- tools/ubuntu-app-triplet.cpp 2016-02-09 21:12:54 +0000 |
2904 | +++ tools/ubuntu-app-triplet.cpp 2016-11-07 20:56:13 +0000 |
2905 | @@ -17,8 +17,8 @@ |
2906 | * Ted Gould <ted.gould@canonical.com> |
2907 | */ |
2908 | |
2909 | +#include "libubuntu-app-launch/application.h" |
2910 | #include <iostream> |
2911 | -#include "libubuntu-app-launch/application.h" |
2912 | |
2913 | int main(int argc, char* argv[]) |
2914 | { |
2915 | |
2916 | === renamed file 'tools/ubuntu-app-watch.c' => 'tools/ubuntu-app-watch.cpp' |
2917 | --- tools/ubuntu-app-watch.c 2016-02-08 19:03:31 +0000 |
2918 | +++ tools/ubuntu-app-watch.cpp 2016-11-07 20:56:13 +0000 |
2919 | @@ -1,5 +1,5 @@ |
2920 | /* |
2921 | - * Copyright 2013 Canonical Ltd. |
2922 | + * Copyright © 2015 Canonical Ltd. |
2923 | * |
2924 | * This program is free software: you can redistribute it and/or modify it |
2925 | * under the terms of the GNU General Public License version 3, as published |
2926 | @@ -17,91 +17,64 @@ |
2927 | * Ted Gould <ted.gould@canonical.com> |
2928 | */ |
2929 | |
2930 | -#include "libubuntu-app-launch/ubuntu-app-launch.h" |
2931 | - |
2932 | -void |
2933 | -starting (const gchar * appid, gpointer user_data) |
2934 | -{ |
2935 | - g_print("Starting %s\n", appid); |
2936 | - return; |
2937 | -} |
2938 | - |
2939 | -void |
2940 | -started (const gchar * appid, gpointer user_data) |
2941 | -{ |
2942 | - g_print("Started %s\n", appid); |
2943 | - return; |
2944 | -} |
2945 | - |
2946 | -void |
2947 | -stopped (const gchar * appid, gpointer user_data) |
2948 | -{ |
2949 | - g_print("Stop %s\n", appid); |
2950 | - return; |
2951 | -} |
2952 | - |
2953 | -void |
2954 | -resumed (const gchar * appid, GPid * pids, gpointer user_data) |
2955 | -{ |
2956 | - g_print("Resumed %s\n", appid); |
2957 | - return; |
2958 | -} |
2959 | - |
2960 | -void |
2961 | -paused (const gchar * appid, GPid * pids, gpointer user_data) |
2962 | -{ |
2963 | - g_print("Paused %s\n", appid); |
2964 | - return; |
2965 | -} |
2966 | - |
2967 | -void |
2968 | -focus (const gchar * appid, gpointer user_data) |
2969 | -{ |
2970 | - g_print("Focus %s\n", appid); |
2971 | - return; |
2972 | -} |
2973 | - |
2974 | -void |
2975 | -fail (const gchar * appid, UbuntuAppLaunchAppFailed failhow, gpointer user_data) |
2976 | -{ |
2977 | - const gchar * failstr = "unknown"; |
2978 | - switch (failhow) { |
2979 | - case UBUNTU_APP_LAUNCH_APP_FAILED_CRASH: |
2980 | - failstr = "crashed"; |
2981 | - break; |
2982 | - case UBUNTU_APP_LAUNCH_APP_FAILED_START_FAILURE: |
2983 | - failstr = "startup"; |
2984 | - break; |
2985 | - } |
2986 | - |
2987 | - g_print("Fail %s (%s)\n", appid, failstr); |
2988 | - return; |
2989 | -} |
2990 | - |
2991 | - |
2992 | -int |
2993 | -main (int argc, gchar * argv[]) |
2994 | -{ |
2995 | - ubuntu_app_launch_observer_add_app_starting(starting, NULL); |
2996 | - ubuntu_app_launch_observer_add_app_started(started, NULL); |
2997 | - ubuntu_app_launch_observer_add_app_stop(stopped, NULL); |
2998 | - ubuntu_app_launch_observer_add_app_focus(focus, NULL); |
2999 | - ubuntu_app_launch_observer_add_app_resumed(resumed, NULL); |
3000 | - ubuntu_app_launch_observer_add_app_paused(paused, NULL); |
3001 | - ubuntu_app_launch_observer_add_app_failed(fail, NULL); |
3002 | - |
3003 | - GMainLoop * mainloop = g_main_loop_new(NULL, FALSE); |
3004 | - g_main_loop_run(mainloop); |
3005 | - |
3006 | - ubuntu_app_launch_observer_delete_app_starting(starting, NULL); |
3007 | - ubuntu_app_launch_observer_delete_app_started(started, NULL); |
3008 | - ubuntu_app_launch_observer_delete_app_stop(stopped, NULL); |
3009 | - ubuntu_app_launch_observer_delete_app_focus(focus, NULL); |
3010 | - ubuntu_app_launch_observer_delete_app_resumed(resumed, NULL); |
3011 | - ubuntu_app_launch_observer_delete_app_paused(paused, NULL); |
3012 | - ubuntu_app_launch_observer_delete_app_failed(fail, NULL); |
3013 | - |
3014 | - g_main_loop_unref(mainloop); |
3015 | - |
3016 | - return 0; |
3017 | +#include "libubuntu-app-launch/registry.h" |
3018 | +#include <csignal> |
3019 | +#include <future> |
3020 | + |
3021 | +std::promise<int> retval; |
3022 | + |
3023 | +int main(int argc, char *argv[]) |
3024 | +{ |
3025 | + ubuntu::app_launch::Registry registry; |
3026 | + |
3027 | + registry.appStarted().connect([](std::shared_ptr<ubuntu::app_launch::Application> app, |
3028 | + std::shared_ptr<ubuntu::app_launch::Application::Instance> instance) { |
3029 | + std::cout << "Started: " << (std::string)app->appId() << std::endl; |
3030 | + }); |
3031 | + registry.appStopped().connect([](std::shared_ptr<ubuntu::app_launch::Application> app, |
3032 | + std::shared_ptr<ubuntu::app_launch::Application::Instance> instance) { |
3033 | + std::cout << "Stopped: " << (std::string)app->appId() << std::endl; |
3034 | + }); |
3035 | + registry.appPaused().connect([](std::shared_ptr<ubuntu::app_launch::Application> app, |
3036 | + std::shared_ptr<ubuntu::app_launch::Application::Instance> instance, |
3037 | + std::vector<pid_t> &pids) { |
3038 | + std::cout << "Paused: " << (std::string)app->appId() << " ("; |
3039 | + |
3040 | + for (auto pid : pids) |
3041 | + { |
3042 | + std::cout << std::to_string(pid) << " "; |
3043 | + } |
3044 | + |
3045 | + std::cout << ")" << std::endl; |
3046 | + }); |
3047 | + registry.appResumed().connect([](std::shared_ptr<ubuntu::app_launch::Application> app, |
3048 | + std::shared_ptr<ubuntu::app_launch::Application::Instance> instance, |
3049 | + std::vector<pid_t> &pids) { |
3050 | + std::cout << "Resumed: " << (std::string)app->appId() << " ("; |
3051 | + |
3052 | + for (auto pid : pids) |
3053 | + { |
3054 | + std::cout << std::to_string(pid) << " "; |
3055 | + } |
3056 | + |
3057 | + std::cout << ")" << std::endl; |
3058 | + }); |
3059 | + registry.appFailed().connect([](std::shared_ptr<ubuntu::app_launch::Application> app, |
3060 | + std::shared_ptr<ubuntu::app_launch::Application::Instance> instance, |
3061 | + ubuntu::app_launch::Registry::FailureType type) { |
3062 | + std::cout << "Failed: " << (std::string)app->appId(); |
3063 | + switch (type) |
3064 | + { |
3065 | + case ubuntu::app_launch::Registry::FailureType::CRASH: |
3066 | + std::cout << " (crash)"; |
3067 | + break; |
3068 | + case ubuntu::app_launch::Registry::FailureType::START_FAILURE: |
3069 | + std::cout << " (start failure)"; |
3070 | + break; |
3071 | + } |
3072 | + std::cout << std::endl; |
3073 | + }); |
3074 | + |
3075 | + std::signal(SIGTERM, [](int signal) -> void { retval.set_value(EXIT_SUCCESS); }); |
3076 | + return retval.get_future().get(); |
3077 | } |
3078 | |
3079 | === modified file 'tools/ubuntu-helper-list.cpp' |
3080 | --- tools/ubuntu-helper-list.cpp 2016-02-09 21:12:54 +0000 |
3081 | +++ tools/ubuntu-helper-list.cpp 2016-11-07 20:56:13 +0000 |
3082 | @@ -17,8 +17,8 @@ |
3083 | * Ted Gould <ted.gould@canonical.com> |
3084 | */ |
3085 | |
3086 | +#include "libubuntu-app-launch/registry.h" |
3087 | #include <iostream> |
3088 | -#include "libubuntu-app-launch/registry.h" |
3089 | |
3090 | int main(int argc, char* argv[]) |
3091 | { |
3092 | |
3093 | === modified file 'tools/ubuntu-helper-start.cpp' |
3094 | --- tools/ubuntu-helper-start.cpp 2016-05-03 01:46:27 +0000 |
3095 | +++ tools/ubuntu-helper-start.cpp 2016-11-07 20:56:13 +0000 |
3096 | @@ -17,9 +17,9 @@ |
3097 | * Ted Gould <ted.gould@canonical.com> |
3098 | */ |
3099 | |
3100 | -#include <iostream> |
3101 | #include "libubuntu-app-launch/helper.h" |
3102 | #include "libubuntu-app-launch/registry.h" |
3103 | +#include <iostream> |
3104 | |
3105 | int main(int argc, char* argv[]) |
3106 | { |
3107 | @@ -31,20 +31,25 @@ |
3108 | |
3109 | auto type = ubuntu::app_launch::Helper::Type::from_raw(argv[1]); |
3110 | auto appid = ubuntu::app_launch::AppID::find(argv[2]); |
3111 | - if (appid.empty()) { |
3112 | + if (appid.empty()) |
3113 | + { |
3114 | std::cerr << "Unable to find helper for appid: " << argv[1] << std::endl; |
3115 | return 1; |
3116 | } |
3117 | |
3118 | auto registry = std::make_shared<ubuntu::app_launch::Registry>(); |
3119 | |
3120 | - try { |
3121 | + try |
3122 | + { |
3123 | auto helper = ubuntu::app_launch::Helper::create(type, appid, registry); |
3124 | |
3125 | helper->launch(); |
3126 | return 0; |
3127 | - } catch (std::runtime_error &e) { |
3128 | - std::cerr << "Unable to find helper for '" << std::string(appid) << "' type '" << type.value() << "': " << e.what() << std::endl; |
3129 | + } |
3130 | + catch (std::runtime_error& e) |
3131 | + { |
3132 | + std::cerr << "Unable to find helper for '" << std::string(appid) << "' type '" << type.value() |
3133 | + << "': " << e.what() << std::endl; |
3134 | return 1; |
3135 | } |
3136 | } |
3137 | |
3138 | === modified file 'tools/ubuntu-helper-stop.cpp' |
3139 | --- tools/ubuntu-helper-stop.cpp 2016-05-03 01:46:27 +0000 |
3140 | +++ tools/ubuntu-helper-stop.cpp 2016-11-07 20:56:13 +0000 |
3141 | @@ -17,9 +17,9 @@ |
3142 | * Ted Gould <ted.gould@canonical.com> |
3143 | */ |
3144 | |
3145 | -#include <iostream> |
3146 | #include "libubuntu-app-launch/helper.h" |
3147 | #include "libubuntu-app-launch/registry.h" |
3148 | +#include <iostream> |
3149 | |
3150 | int main(int argc, char* argv[]) |
3151 | { |
3152 | @@ -31,14 +31,16 @@ |
3153 | |
3154 | auto type = ubuntu::app_launch::Helper::Type::from_raw(argv[1]); |
3155 | auto appid = ubuntu::app_launch::AppID::find(argv[2]); |
3156 | - if (appid.empty()) { |
3157 | + if (appid.empty()) |
3158 | + { |
3159 | std::cerr << "Unable to find helper for appid: " << argv[1] << std::endl; |
3160 | return 1; |
3161 | } |
3162 | |
3163 | auto registry = std::make_shared<ubuntu::app_launch::Registry>(); |
3164 | |
3165 | - try { |
3166 | + try |
3167 | + { |
3168 | auto helper = ubuntu::app_launch::Helper::create(type, appid, registry); |
3169 | |
3170 | for (auto instance : helper->instances()) |
3171 | @@ -47,8 +49,11 @@ |
3172 | } |
3173 | |
3174 | return 0; |
3175 | - } catch (std::runtime_error &e) { |
3176 | - std::cerr << "Unable to find helper for '" << std::string(appid) << "' type '" << type.value() << "': " << e.what() << std::endl; |
3177 | + } |
3178 | + catch (std::runtime_error& e) |
3179 | + { |
3180 | + std::cerr << "Unable to find helper for '" << std::string(appid) << "' type '" << type.value() |
3181 | + << "': " << e.what() << std::endl; |
3182 | return 1; |
3183 | } |
3184 | } |
FAILED: Continuous integration, rev:232 /code.launchpad .net/~ted/ ubuntu- app-launch/ app-object- signals/ +merge/ 294807/ +edit-commit- message
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:/
http:// jenkins. qa.ubuntu. com/job/ ubuntu- app-launch- ci/55/ jenkins. qa.ubuntu. com/job/ ubuntu- app-launch- wily-amd64- ci/55/console jenkins. qa.ubuntu. com/job/ ubuntu- app-launch- wily-armhf- ci/55/console jenkins. qa.ubuntu. com/job/ ubuntu- app-launch- wily-i386- ci/55/console
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/ubuntu- app-launch- ci/55/rebuild
http://