Merge lp:~pete-woods/ubuntu-app-launch/port-some-c-to-cpp into lp:ubuntu-app-launch

Proposed by Pete Woods on 2017-04-04
Status: Needs review
Proposed branch: lp:~pete-woods/ubuntu-app-launch/port-some-c-to-cpp
Merge into: lp:ubuntu-app-launch
Prerequisite: lp:~ci-train-bot/ubuntu-app-launch/ubuntu-app-launch-ubuntu-zesty-2675
Diff against target: 946 lines (+374/-315)
6 files modified
libubuntu-app-launch/CMakeLists.txt (+1/-1)
libubuntu-app-launch/jobs-base.cpp (+0/-23)
libubuntu-app-launch/jobs-base.h (+0/-1)
libubuntu-app-launch/jobs-systemd.cpp (+6/-7)
libubuntu-app-launch/second-exec-core.cpp (+347/-274)
libubuntu-app-launch/second-exec-core.h (+20/-9)
To merge this branch: bzr merge lp:~pete-woods/ubuntu-app-launch/port-some-c-to-cpp
Reviewer Review Type Date Requested Status
unity-api-1-bot continuous-integration Needs Fixing on 2017-04-04
Indicator Applet Developers 2017-04-04 Pending
Review via email: mp+321866@code.launchpad.net

Commit message

Initial port of second-exec-core.c to C++

* Still has remaining lifecycle issue

Description of the change

Initial port of second-exec-core.c to C++

* Still has remaining lifecycle issue

To post a comment you must log in.
310. By Ted Gould on 2017-04-04

Cleanup registry references to make them consistent (LP: #1676361)

Approved by: Charles Kerr

311. By Ted Gould on 2017-04-04

Watch system folders for apps added and removed (LP: #1630997, #1672392)

Approved by: Marcus Tomlinson, Pete Woods

312. By Ted Gould on 2017-04-04

Wait with a timeout for the libertine service to start

Approved by: Pete Woods

313. By CI Train Bot Account on 2017-04-04

Bump version for new AppID methods

314. By Ted Gould on 2017-04-04

Provide equality operators for Application and Application::Instance objects. (LP: #1677345)

Approved by: Pete Woods

315. By Ted Gould on 2017-04-04

Force GTK and Qt backends when using XMir

Approved by: Pete Woods

316. By CI Train Bot Account on 2017-04-04

Releasing 0.12+17.04.20170404.2-0ubuntu1

317. By Pete Woods on 2017-04-05

Initial port of second-exec-core.c to C++

* Still has remaining lifecycle issue

Unmerged revisions

317. By Pete Woods on 2017-04-05

Initial port of second-exec-core.c to C++

* Still has remaining lifecycle issue

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'libubuntu-app-launch/CMakeLists.txt'
2--- libubuntu-app-launch/CMakeLists.txt 2017-03-20 10:13:50 +0000
3+++ libubuntu-app-launch/CMakeLists.txt 2017-04-05 12:08:51 +0000
4@@ -80,7 +80,7 @@
5
6 set(LAUNCHER_SOURCES
7 ubuntu-app-launch.cpp
8-second-exec-core.c
9+second-exec-core.cpp
10 ubuntu-app-launch-trace.c
11 utils.c
12 utils-shared.c
13
14=== modified file 'libubuntu-app-launch/jobs-base.cpp'
15--- libubuntu-app-launch/jobs-base.cpp 2017-04-05 12:08:51 +0000
16+++ libubuntu-app-launch/jobs-base.cpp 2017-04-05 12:08:51 +0000
17@@ -1053,29 +1053,6 @@
18 }
19 }
20
21-/** Reformat a C++ vector of URLs into a C GStrv of strings
22-
23- \param urls Vector of URLs to make into C strings
24-*/
25-GCharVUPtr Base::urlsToStrv(const std::vector<Application::URL>& urls)
26-{
27- if (urls.empty())
28- {
29- return GCharVUPtr(nullptr, &g_strfreev);
30- }
31-
32- auto array = g_array_new(TRUE, FALSE, sizeof(gchar*));
33-
34- for (auto url : urls)
35- {
36- auto str = g_strdup(url.value().c_str());
37- g_debug("Converting URL: %s", str);
38- g_array_append_val(array, str);
39- }
40-
41- return unique_gcharv((gchar**)g_array_free(array, FALSE));
42-}
43-
44 } // namespace instance
45
46 } // namespace jobs
47
48=== modified file 'libubuntu-app-launch/jobs-base.h'
49--- libubuntu-app-launch/jobs-base.h 2017-04-05 12:08:51 +0000
50+++ libubuntu-app-launch/jobs-base.h 2017-04-05 12:08:51 +0000
51@@ -91,7 +91,6 @@
52 static void oomValueToPid(pid_t pid, const oom::Score oomvalue);
53 static void oomValueToPidHelper(pid_t pid, const oom::Score oomvalue);
54 static std::string pidToOomPath(pid_t pid);
55- static GCharVUPtr urlsToStrv(const std::vector<Application::URL>& urls);
56 };
57
58 } // namespace instance
59
60=== modified file 'libubuntu-app-launch/jobs-systemd.cpp'
61--- libubuntu-app-launch/jobs-systemd.cpp 2017-04-05 12:08:51 +0000
62+++ libubuntu-app-launch/jobs-systemd.cpp 2017-04-05 12:08:51 +0000
63@@ -513,13 +513,12 @@
64 g_debug("Remote error: %s", remote_error);
65 if (g_strcmp0(remote_error, "org.freedesktop.systemd1.UnitExists") == 0)
66 {
67- auto urls = instance::SystemD::urlsToStrv(data->ptr->urls_);
68- second_exec(data->bus.get(), /* DBus */
69- data->ptr->registry_->thread.getCancellable().get(), /* cancellable */
70- data->ptr->primaryPid(), /* primary pid */
71- std::string(data->ptr->appId_).c_str(), /* appid */
72- data->ptr->instance_.c_str(), /* instance */
73- urls.get()); /* urls */
74+ second_exec(data->bus, /* DBus */
75+ data->ptr->registry_->thread.getCancellable(), /* cancellable */
76+ data->ptr->primaryPid(), /* primary pid */
77+ std::string(data->ptr->appId_), /* appid */
78+ data->ptr->instance_, /* instance */
79+ data->ptr->urls_); /* urls */
80 }
81
82 g_free(remote_error);
83
84=== renamed file 'libubuntu-app-launch/second-exec-core.c' => 'libubuntu-app-launch/second-exec-core.cpp'
85--- libubuntu-app-launch/second-exec-core.c 2017-03-14 22:41:03 +0000
86+++ libubuntu-app-launch/second-exec-core.cpp 2017-04-05 12:08:51 +0000
87@@ -1,5 +1,5 @@
88 /*
89- * Copyright 2013 Canonical Ltd.
90+ * Copyright 2013-2017 Canonical Ltd.
91 *
92 * This program is free software: you can redistribute it and/or modify it
93 * under the terms of the GNU General Public License version 3, as published
94@@ -15,138 +15,230 @@
95 *
96 * Authors:
97 * Ted Gould <ted.gould@canonical.com>
98+ * Pete Woods <pete.woods@canonical.com>
99 */
100
101 #include <gio/gio.h>
102 #include "libubuntu-app-launch/ubuntu-app-launch.h"
103-#include "utils.h"
104 #include "second-exec-core.h"
105+#include "signal-unsubscriber.h"
106 #include "ubuntu-app-launch-trace.h"
107 #include "ual-tracepoint.h"
108
109-typedef struct {
110- GDBusConnection * bus;
111- gchar * appid;
112- gchar * instanceid;
113- gchar ** input_uris;
114- GPid app_pid;
115- guint connections_open;
116- GVariant * app_data;
117- gchar * dbus_path;
118- guint64 unity_starttime;
119- GSource * timer;
120- guint signal;
121-} second_exec_t;
122-
123-static void second_exec_complete (second_exec_t * data);
124-
125-static GSource *
126-thread_default_timeout (guint interval, GSourceFunc func, gpointer data)
127-{
128- GSource * src = g_timeout_source_new(interval);
129- GMainContext * context = g_main_context_get_thread_default();
130-
131- g_source_set_callback(src, func, data, NULL);
132-
133- g_source_attach(src, context);
134+#include <unity/util/GlibMemory.h>
135+
136+#include <iomanip>
137+#include <sstream>
138+#include <unordered_map>
139+
140+using namespace std;
141+using namespace unity::util;
142+
143+namespace ubuntu
144+{
145+namespace app_launch
146+{
147+namespace
148+{
149+
150+struct GSourceClear
151+{
152+ void operator()(GSource* source)
153+ {
154+ if (source != nullptr)
155+ {
156+ g_source_destroy(source);
157+ g_source_unref(source);
158+ }
159+ }
160+};
161+
162+
163+class second_exec_t: public enable_shared_from_this<second_exec_t>
164+{
165+public:
166+ second_exec_t(shared_ptr<GDBusConnection> bus, const string& appid, const string& instanceid, const vector<Application::URL>& input_uris, GPid app_pid);
167+
168+ ~second_exec_t();
169+
170+ void
171+ init ();
172+
173+private:
174+ class get_pid_t
175+ {
176+ public:
177+ get_pid_t(const string& name, shared_ptr<GDBusConnection> bus, shared_ptr<second_exec_t> data);
178+
179+ private:
180+ static void
181+ get_pid_cb (GObject * object, GAsyncResult * res, gpointer user_data)
182+ {
183+ ((get_pid_t *)user_data)->get_pid(object, res);
184+ }
185+
186+ void
187+ get_pid (GObject * object, GAsyncResult * res);
188+
189+ string name;
190+
191+ shared_ptr<second_exec_t> data;
192+ };
193+
194+ /* Unity didn't respond in time, continue on */
195+ static gboolean
196+ timer_cb (gpointer user_data);
197+
198+ static void
199+ send_open_cb (GObject * object, GAsyncResult * res, gpointer user_data)
200+ {
201+ ((second_exec_t*) user_data)->send_open(object, res);
202+ }
203+
204+ void
205+ app_id_to_dbus_path ();
206+
207+ void
208+ send_open (GObject * object, GAsyncResult * res);
209+
210+ void
211+ contact_app (GDBusConnection * bus, const string& dbus_name);
212+
213+ void
214+ find_appid_pid ();
215+
216+ void
217+ connection_count_dec ();
218+
219+ static void
220+ unity_resume_cb (GDBusConnection * connection, const gchar * sender, const gchar * path, const gchar * interface, const gchar * signal, GVariant * params, gpointer user_data)
221+ {
222+ ((second_exec_t*) user_data)->unity_resume(connection, sender, path, interface, signal, params);
223+ }
224+
225+ void
226+ unity_resume(GDBusConnection * connection, const gchar * sender, const gchar * path, const gchar * interface, const gchar * signal, GVariant * params);
227+
228+ void
229+ parse_uris ();
230+
231+ static GSourceUPtr
232+ thread_default_timeout (guint interval, GSourceFunc func, gpointer data);
233+
234+ void finish();
235+
236+ static unordered_map<second_exec_t*, shared_ptr<second_exec_t>> SECOND_EXEC_INSTANCES_;
237+
238+ shared_ptr<GDBusConnection> bus_;
239+ string appid_;
240+ string instanceid_;
241+ vector<Application::URL> input_uris_;
242+ GPid app_pid_;
243+ guint connections_open {0};
244+ GVariantSPtr app_data{nullptr, GVariantDeleter()};
245+ string dbus_path;
246+ guint64 unity_starttime {0};
247+ GSourceSPtr timer{nullptr, GSourceClear()};
248+ ManagedDBusSignalConnection signal {DBusSignalUnsubscriber()};
249+};
250+
251+unordered_map<second_exec_t*, shared_ptr<second_exec_t>> second_exec_t::SECOND_EXEC_INSTANCES_;
252+
253+GSourceUPtr
254+second_exec_t::thread_default_timeout (guint interval, GSourceFunc func, gpointer data)
255+{
256+ auto src = unique_glib(g_timeout_source_new(interval));
257+ auto context = unique_glib(g_main_context_get_thread_default());
258+
259+ g_source_set_callback(src.get(), func, data, nullptr);
260+
261+ g_source_attach(src.get(), context.get());
262
263 return src;
264 }
265
266 /* Unity didn't respond in time, continue on */
267-static gboolean
268-timer_cb (gpointer user_data)
269+gboolean
270+second_exec_t::timer_cb (gpointer user_data)
271 {
272- ual_tracepoint(second_exec_resume_timeout, ((second_exec_t *)user_data)->appid);
273+ auto data = (second_exec_t *)user_data;
274+ ual_tracepoint(second_exec_resume_timeout, data->appid_.c_str());
275 g_warning("Unity didn't respond in 500ms to resume the app");
276
277- second_exec_complete(user_data);
278+ data->finish();
279 return G_SOURCE_REMOVE;
280 }
281
282 /* Lower the connection count and process if it gets to zero */
283-static void
284-connection_count_dec (second_exec_t * data)
285+void
286+second_exec_t::connection_count_dec ()
287 {
288- ual_tracepoint(second_exec_connection_complete, data->appid);
289- data->connections_open--;
290- if (data->connections_open == 0) {
291+ ual_tracepoint(second_exec_connection_complete, appid_.c_str());
292+ connections_open--;
293+ if (connections_open == 0) {
294 g_debug("Finished finding connections");
295 /* Check time here, either we've already heard from
296 Unity and we should send the data to the app (quit) or
297 we should wait some more */
298- guint64 timespent = g_get_monotonic_time() - data->unity_starttime;
299+ guint64 timespent = g_get_monotonic_time() - unity_starttime;
300 if (timespent > 500 /* ms */ * 1000 /* ms to us */) {
301- second_exec_complete(data);
302+ finish();
303+ return;
304 } else {
305 g_debug("Timer Set");
306- data->timer = thread_default_timeout(500 - (timespent / 1000), timer_cb, data);
307+ timer = thread_default_timeout(500 - (timespent / 1000), timer_cb, this);
308 }
309 }
310- return;
311 }
312
313 /* Called when Unity is done unfreezing the application, if we're
314 done determining the PID, we can send signals */
315-static void
316-unity_resume_cb (GDBusConnection * connection, const gchar * sender, const gchar * path, const gchar * interface, const gchar * signal, GVariant * params, gpointer user_data)
317+void
318+second_exec_t::unity_resume(GDBusConnection * connection, const gchar * sender, const gchar * path, const gchar * interface, const gchar * signal, GVariant * params)
319 {
320- second_exec_t * data = (second_exec_t *)user_data;
321 g_debug("Unity Completed Resume");
322- ual_tracepoint(second_exec_resume_complete, data->appid);
323-
324- if (data->timer != NULL) {
325- g_source_destroy(data->timer);
326- g_source_unref(data->timer);
327- data->timer = NULL;
328- }
329-
330- if (data->connections_open == 0) {
331- second_exec_complete(data);
332+ ual_tracepoint(second_exec_resume_complete, appid_.c_str());
333+
334+ timer.reset();
335+
336+ if (connections_open == 0) {
337+ finish();
338 } else {
339 /* Make it look like we started *forever* ago */
340- data->unity_starttime = 0;
341+ unity_starttime = 0;
342 }
343-
344- return;
345 }
346
347 /* Turn the input string into something we can send to apps */
348-static void
349-parse_uris (second_exec_t * data)
350+void
351+second_exec_t::parse_uris ()
352 {
353- if (data->app_data != NULL) {
354+ if (app_data) {
355 /* Already done */
356 return;
357 }
358
359- GVariant * uris = NULL;
360+ GVariant * uris = nullptr;
361
362- if (data->input_uris == NULL) {
363- uris = g_variant_new_array(G_VARIANT_TYPE_STRING, NULL, 0);
364+ if (input_uris_.empty()) {
365+ uris = g_variant_new_array(G_VARIANT_TYPE_STRING, nullptr, 0);
366 } else {
367 GVariantBuilder builder;
368 g_variant_builder_init(&builder, G_VARIANT_TYPE_ARRAY);
369
370- int i;
371- for (i = 0; data->input_uris[i] != NULL; i++) {
372- g_variant_builder_add_value(&builder, g_variant_new_string(data->input_uris[i]));
373+ for (const auto& uri: input_uris_) {
374+ g_variant_builder_add_value(&builder, g_variant_new_string(uri.value().c_str()));
375 }
376
377 uris = g_variant_builder_end(&builder);
378 }
379
380- GVariant * platform = g_variant_new_array(G_VARIANT_TYPE("{sv}"), NULL, 0);
381-
382 GVariantBuilder tuple;
383 g_variant_builder_init(&tuple, G_VARIANT_TYPE_TUPLE);
384 g_variant_builder_add_value(&tuple, uris);
385- g_variant_builder_add_value(&tuple, platform);
386-
387- data->app_data = g_variant_builder_end(&tuple);
388- g_variant_ref_sink(data->app_data);
389-
390- return;
391+ g_variant_builder_add_value(&tuple, g_variant_new_array(G_VARIANT_TYPE("{sv}"), nullptr, 0));
392+
393+ app_data = unique_glib(g_variant_ref_sink(g_variant_builder_end(&tuple)));
394 }
395
396 /* Finds us our dbus path to use. Basically this is the name
397@@ -155,322 +247,303 @@
398
399 http://standards.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html#dbus
400 */
401-static void
402-app_id_to_dbus_path (second_exec_t * data)
403+void
404+second_exec_t::app_id_to_dbus_path ()
405 {
406- if (data->dbus_path != NULL) {
407+ if (!dbus_path.empty()) {
408 return;
409 }
410
411- GString * str = g_string_sized_new(strlen(data->appid) + 2); /* base case, we just need a / and a null */
412- g_string_append_c(str, '/');
413-
414- int i;
415- for (i = 0; data->appid[i] != '\0'; i++) {
416- if ((data->appid[i] >= 'a' && data->appid[i] <= 'z') ||
417- (data->appid[i] >= 'A' && data->appid[i] <= 'Z') ||
418- (data->appid[i] >= '0' && data->appid[i] <= '9' && i != 0)) {
419- g_string_append_c(str, data->appid[i]);
420- continue;
421- }
422-
423- g_string_append_printf(str, "_%2x", data->appid[i]);
424+ stringstream str;
425+ auto defaultFlags = str.flags();
426+ str << "/";
427+
428+ bool first = true;
429+ for (const auto c: appid_) {
430+ if ((c >= 'a' && c <= 'z') ||
431+ (c >= 'A' && c <= 'Z') ||
432+ (c >= '0' && c <= '9' && !first))
433+ {
434+ str << c;
435+ }
436+ else
437+ {
438+ str << "_" << setfill('0') << setw(2) << hex << c;
439+ str.flags(defaultFlags);
440+ }
441+ first = false;
442 }
443
444- data->dbus_path = g_string_free(str, FALSE);
445- g_debug("DBus Path: %s", data->dbus_path);
446-
447- return;
448+ dbus_path = str.str();
449+ g_debug("DBus Path: %s", dbus_path.c_str());
450 }
451
452 /* Finish the send and decrement the counter */
453-static void
454-send_open_cb (GObject * object, GAsyncResult * res, gpointer user_data)
455+void
456+second_exec_t::send_open (GObject * object, GAsyncResult * res)
457 {
458- GError * error = NULL;
459+ GError * error = nullptr;
460
461- ual_tracepoint(second_exec_app_contacted, ((second_exec_t *)user_data)->appid);
462+ ual_tracepoint(second_exec_app_contacted, appid_.c_str());
463
464 g_dbus_connection_call_finish(G_DBUS_CONNECTION(object), res, &error);
465
466- if (error != NULL) {
467- ual_tracepoint(second_exec_app_error, ((second_exec_t *)user_data)->appid);
468+ if (error != nullptr) {
469+ ual_tracepoint(second_exec_app_error, appid_.c_str());
470 /* Mostly just to free the error, but printing for debugging */
471 g_debug("Unable to send Open: %s", error->message);
472- g_error_free(error);
473+ g_clear_error(&error);
474 }
475
476- connection_count_dec(user_data);
477- return;
478+ connection_count_dec();
479 }
480
481 /* Sends the Open message to the connection with the URIs we were given */
482-static void
483-contact_app (GDBusConnection * bus, const gchar * dbus_name, second_exec_t * data)
484+void
485+second_exec_t::contact_app (GDBusConnection * bus, const string& dbus_name)
486 {
487- ual_tracepoint(second_exec_contact_app, data->appid, dbus_name);
488+ ual_tracepoint(second_exec_contact_app, appid_.c_str(), dbus_name.c_str());
489
490- parse_uris(data);
491- app_id_to_dbus_path(data);
492+ parse_uris();
493+ app_id_to_dbus_path();
494
495 /* Using the FD.o Application interface */
496 g_dbus_connection_call(bus,
497- dbus_name,
498- data->dbus_path,
499+ dbus_name.c_str(),
500+ dbus_path.c_str(),
501 "org.freedesktop.Application",
502 "Open",
503- data->app_data,
504- NULL,
505- G_DBUS_CALL_FLAGS_NONE,
506- -1,
507- NULL,
508- send_open_cb, data);
509-
510- g_debug("Sending Open request to: %s", dbus_name);
511-
512- return;
513-}
514-
515-typedef struct {
516- gchar * name;
517- second_exec_t * data;
518-} get_pid_t;
519+ app_data.get(),
520+ NULL,
521+ G_DBUS_CALL_FLAGS_NONE,
522+ -1,
523+ NULL,
524+ second_exec_t::send_open_cb, this);
525+
526+ g_debug("Sending Open request to: %s", dbus_name.c_str());
527+}
528+
529+second_exec_t::get_pid_t::get_pid_t(const string& _name, shared_ptr<GDBusConnection> bus, shared_ptr<second_exec_t> _data) :
530+ name(_name), data(_data)
531+{
532+ /* Get the PIDs */
533+ g_dbus_connection_call(bus.get(),
534+ "org.freedesktop.DBus",
535+ "/",
536+ "org.freedesktop.DBus",
537+ "GetConnectionUnixProcessID",
538+ g_variant_new("(s)", name.c_str()),
539+ G_VARIANT_TYPE("(u)"),
540+ G_DBUS_CALL_FLAGS_NONE,
541+ -1,
542+ nullptr,
543+ get_pid_t::get_pid_cb, this);
544+}
545
546 /* Gets the PID for a connection, and if it matches the one we're looking
547 for then it tries to send a message to that connection */
548-static void
549-get_pid_cb (GObject * object, GAsyncResult * res, gpointer user_data)
550+void
551+second_exec_t::get_pid_t::get_pid (GObject * object, GAsyncResult * res)
552 {
553- get_pid_t * data = (get_pid_t *)user_data;
554- GError * error = NULL;
555- GVariant * vpid = NULL;
556-
557- ual_tracepoint(second_exec_got_pid, data->data->appid, data->name);
558-
559- vpid = g_dbus_connection_call_finish(G_DBUS_CONNECTION(object), res, &error);
560-
561- if (error != NULL) {
562- g_warning("Unable to query PID for dbus name '%s': %s", data->name, error->message);
563- g_error_free(error);
564+ GError * error = nullptr;
565+
566+ ual_tracepoint(second_exec_got_pid, data->appid_.c_str(), name.c_str());
567+
568+ auto vpid = unique_glib(g_dbus_connection_call_finish(G_DBUS_CONNECTION(object), res, &error));
569+
570+ if (error != nullptr) {
571+ g_warning("Unable to query PID for dbus name '%s': %s", name.c_str(), error->message);
572+ g_clear_error(&error);
573
574 /* Lowering the connection count, this one is terminal, even if in error */
575- connection_count_dec(data->data);
576-
577- g_free(data->name);
578- g_free(data);
579-
580- return;
581- }
582-
583- guint pid = 0;
584- g_variant_get(vpid, "(u)", &pid);
585- g_variant_unref(vpid);
586-
587- if (pid == data->data->app_pid) {
588- /* Trying to send a message to the connection */
589- contact_app(G_DBUS_CONNECTION(object), data->name, data->data);
590+ data->connection_count_dec();
591 } else {
592- /* See if we can quit now */
593- connection_count_dec(data->data);
594+ GPid pid = 0;
595+ g_variant_get(vpid.get(), "(u)", &pid);
596+
597+ if (pid == data->app_pid_) {
598+ /* Trying to send a message to the connection */
599+ data->contact_app(G_DBUS_CONNECTION(object), name);
600+ } else {
601+ /* See if we can quit now */
602+ data->connection_count_dec();
603+ }
604 }
605
606- g_free(data->name);
607- g_free(data);
608-
609- return;
610+ delete this;
611 }
612
613 /* Starts to look for the PID and the connections for that PID */
614-static void
615-find_appid_pid (GDBusConnection * session, second_exec_t * data)
616+void
617+second_exec_t::find_appid_pid ()
618 {
619- GError * error = NULL;
620+ GError * error = nullptr;
621
622 /* List all the connections on dbus. This sucks that we have to do
623 this, but in the future we should add DBus API to do this lookup
624 instead of having to do it with a bunch of requests */
625- GVariant * listnames = g_dbus_connection_call_sync(session,
626+ auto listnames = unique_glib(g_dbus_connection_call_sync(bus_.get(),
627 "org.freedesktop.DBus",
628 "/",
629 "org.freedesktop.DBus",
630 "ListNames",
631- NULL,
632+ nullptr,
633 G_VARIANT_TYPE("(as)"),
634 G_DBUS_CALL_FLAGS_NONE,
635 -1,
636- NULL,
637- &error);
638+ nullptr,
639+ &error));
640
641- if (error != NULL) {
642+ if (error != nullptr) {
643 g_warning("Unable to get list of names from DBus: %s", error->message);
644- g_error_free(error);
645+ g_clear_error(&error);
646 return;
647 }
648
649 g_debug("Got bus names");
650- ual_tracepoint(second_exec_got_dbus_names, data->appid);
651+ ual_tracepoint(second_exec_got_dbus_names, appid_.c_str());
652
653- g_debug("Primary PID: %d", data->app_pid);
654- ual_tracepoint(second_exec_got_primary_pid, data->appid);
655+ g_debug("Primary PID: %d", app_pid_);
656+ ual_tracepoint(second_exec_got_primary_pid, appid_.c_str());
657
658 /* Get the names */
659- GVariant * names = g_variant_get_child_value(listnames, 0);
660+ auto names = unique_glib(g_variant_get_child_value(listnames.get(), 0));
661 GVariantIter iter;
662- g_variant_iter_init(&iter, names);
663- gchar * name = NULL;
664+ g_variant_iter_init(&iter, names.get());
665+ gchar * name = nullptr;
666
667 while (g_variant_iter_loop(&iter, "s", &name)) {
668 /* We only want to ask each connection once, this makes that so */
669 if (!g_dbus_is_unique_name(name)) {
670 continue;
671 }
672-
673- get_pid_t * pid_data = g_new0(get_pid_t, 1);
674- pid_data->data = data;
675- pid_data->name = g_strdup(name);
676-
677- ual_tracepoint(second_exec_request_pid, data->appid, pid_data->name);
678-
679- /* Get the PIDs */
680- g_dbus_connection_call(session,
681- "org.freedesktop.DBus",
682- "/",
683- "org.freedesktop.DBus",
684- "GetConnectionUnixProcessID",
685- g_variant_new("(s)", name),
686- G_VARIANT_TYPE("(u)"),
687- G_DBUS_CALL_FLAGS_NONE,
688- -1,
689- NULL,
690- get_pid_cb, pid_data);
691-
692- data->connections_open++;
693+
694+ ual_tracepoint(second_exec_request_pid, appid_.c_str(), name);
695+
696+ // FIXME This object deletes itself
697+ new get_pid_t(string(name), bus_, shared_from_this());
698+
699+ connections_open++;
700 }
701-
702- g_variant_unref(names);
703- g_variant_unref(listnames);
704-
705- return;
706-}
707-
708-gboolean
709-second_exec (GDBusConnection * session, GCancellable * cancel, GPid pid, const gchar * app_id, const gchar * instance_id, gchar ** appuris)
710-{
711- ual_tracepoint(second_exec_start, app_id);
712- GError * error = NULL;
713-
714- /* Setup our continuation data */
715- second_exec_t * data = g_new0(second_exec_t, 1);
716- data->appid = g_strdup(app_id);
717- data->instanceid = g_strdup(instance_id);
718- data->input_uris = g_strdupv(appuris);
719- data->bus = g_object_ref(session);
720- data->app_pid = pid;
721+}
722+
723+second_exec_t::second_exec_t(shared_ptr<GDBusConnection> bus, const string& appid, const string& instanceid, const vector<Application::URL>& input_uris, GPid app_pid) :
724+ bus_(bus), appid_(appid), instanceid_(instanceid), input_uris_(input_uris), app_pid_(app_pid)
725+{
726+ // can't use for init, due to shared_from_this restriction
727+}
728+
729+void
730+second_exec_t::init()
731+{
732+ ual_tracepoint(second_exec_start, appid_.c_str());
733
734 /* Set up listening for the unfrozen signal from Unity */
735- data->signal = g_dbus_connection_signal_subscribe(session,
736- NULL, /* sender */
737+ signal = managedDBusSignalConnection(g_dbus_connection_signal_subscribe(bus_.get(),
738+ nullptr, /* sender */
739 "com.canonical.UbuntuAppLaunch", /* interface */
740 "UnityResumeResponse", /* signal */
741 "/", /* path */
742- app_id, /* arg0 */
743+ appid_.c_str(), /* arg0 */
744 G_DBUS_SIGNAL_FLAGS_NONE,
745- unity_resume_cb, data,
746- NULL); /* user data destroy */
747+ second_exec_t::unity_resume_cb, this,
748+ nullptr), /* user data destroy */
749+ bus_);
750
751 g_debug("Sending resume request");
752- ual_tracepoint(second_exec_emit_resume, app_id);
753+ ual_tracepoint(second_exec_emit_resume, appid_.c_str());
754+
755+ GError * error = nullptr;
756
757 /* Send unfreeze to to Unity */
758- g_dbus_connection_emit_signal(session,
759- NULL, /* destination */
760+ g_dbus_connection_emit_signal(bus_.get(),
761+ nullptr, /* destination */
762 "/", /* path */
763 "com.canonical.UbuntuAppLaunch", /* interface */
764 "UnityResumeRequest", /* signal */
765- g_variant_new("(ss)", app_id, instance_id),
766+ g_variant_new("(ss)", appid_.c_str(), instanceid_.c_str()),
767 &error);
768
769 /* Now we start a race, we try to get to the point of knowing who
770 to send things to, and Unity is unfrezing it. When both are
771 done we can send something to the app */
772- data->unity_starttime = g_get_monotonic_time();
773+ unity_starttime = g_get_monotonic_time();
774
775- if (error != NULL) {
776+ if (error != nullptr) {
777 /* On error let's not wait for Unity */
778 g_warning("Unable to signal Unity: %s", error->message);
779- g_error_free(error);
780- error = NULL;
781- data->unity_starttime = 0;
782+ g_clear_error(&error);
783+ unity_starttime = 0;
784 }
785
786 /* If we've got something to give out, start looking for how */
787- if (data->input_uris != NULL) {
788- find_appid_pid(session, data);
789+ if (!input_uris_.empty()) {
790+ find_appid_pid();
791 } else {
792 g_debug("No URIs to send");
793 }
794
795 /* Loop and wait for everything to align */
796- if (data->connections_open == 0) {
797- if (data->unity_starttime == 0) {
798- second_exec_complete(data);
799- } else {
800- data->timer = thread_default_timeout(500, timer_cb, data);
801+ if (connections_open == 0) {
802+ if (unity_starttime != 0) {
803+ timer = thread_default_timeout(500, timer_cb, this);
804+ SECOND_EXEC_INSTANCES_.insert(make_pair(this, shared_from_this()));
805 }
806 }
807-
808- return TRUE;
809-}
810-
811-static void
812-second_exec_complete (second_exec_t * data)
813-{
814- GError * error = NULL;
815- ual_tracepoint(second_exec_emit_focus, data->appid);
816+}
817+
818+void second_exec_t::finish()
819+{
820+ SECOND_EXEC_INSTANCES_.erase(this);
821+}
822+
823+second_exec_t::~second_exec_t()
824+{
825+ GError * error = nullptr;
826+ ual_tracepoint(second_exec_emit_focus, appid_.c_str());
827
828 /* Now that we're done sending the info to the app, we can ask
829 Unity to focus the application. */
830- g_dbus_connection_emit_signal(data->bus,
831- NULL, /* destination */
832+ g_dbus_connection_emit_signal(bus_.get(),
833+ nullptr, /* destination */
834 "/", /* path */
835 "com.canonical.UbuntuAppLaunch", /* interface */
836 "UnityFocusRequest", /* signal */
837- g_variant_new("(ss)", data->appid, data->instanceid),
838+ g_variant_new("(ss)", appid_.c_str(), instanceid_.c_str()),
839 &error);
840
841- if (error != NULL) {
842+ if (error != nullptr)
843+ {
844 g_warning("Unable to request focus to Unity: %s", error->message);
845- g_error_free(error);
846- error = NULL;
847+ g_clear_error(&error);
848 }
849
850 /* Make sure the signal hits the bus */
851- g_dbus_connection_flush_sync(data->bus, NULL, &error);
852+ g_dbus_connection_flush_sync(bus_.get(), nullptr, &error);
853 if (error != NULL) {
854 g_warning("Unable to flush session bus: %s", error->message);
855- g_error_free(error);
856- error = NULL;
857+ g_clear_error(&error);
858 }
859
860- ual_tracepoint(second_exec_finish, data->appid);
861+ ual_tracepoint(second_exec_finish, appid_.c_str());
862 g_debug("Second Exec complete");
863-
864- /* Clean up */
865- if (data->signal != 0)
866- g_dbus_connection_signal_unsubscribe(data->bus, data->signal);
867-
868- if (data->timer != NULL) {
869- g_source_destroy(data->timer);
870- g_source_unref(data->timer);
871- }
872- g_object_unref(data->bus);
873- if (data->app_data != NULL)
874- g_variant_unref(data->app_data);
875- g_free(data->appid);
876- g_free(data->instanceid);
877- g_strfreev(data->input_uris);
878- g_free(data->dbus_path);
879- g_free(data);
880-
881- return;
882+}
883+
884+}
885+
886+void
887+second_exec (shared_ptr<GDBusConnection> session, shared_ptr<GCancellable> cancel, GPid pid, const string& app_id, const string& instance_id, const vector<Application::URL>& appuris)
888+{
889+ auto t = make_shared<second_exec_t>(
890+ session,
891+ app_id,
892+ instance_id,
893+ appuris,
894+ pid
895+ );
896+
897+ t->init();
898+}
899+
900+}
901 }
902
903=== modified file 'libubuntu-app-launch/second-exec-core.h'
904--- libubuntu-app-launch/second-exec-core.h 2016-12-14 23:03:15 +0000
905+++ libubuntu-app-launch/second-exec-core.h 2017-04-05 12:08:51 +0000
906@@ -1,6 +1,5 @@
907-
908 /*
909- * Copyright 2013 Canonical Ltd.
910+ * Copyright 2013-2017 Canonical Ltd.
911 *
912 * This program is free software: you can redistribute it and/or modify it
913 * under the terms of the GNU General Public License version 3, as published
914@@ -16,13 +15,25 @@
915 *
916 * Authors:
917 * Ted Gould <ted.gould@canonical.com>
918+ * Pete Woods <pete.woods@canonical.com>
919 */
920
921+
922+#pragma once
923+
924 #include <gio/gio.h>
925-
926-G_BEGIN_DECLS
927-
928-gboolean second_exec (GDBusConnection * con, GCancellable * cancel, GPid pid, const gchar * app_id, const gchar * instance_id, gchar ** appuris);
929-
930-G_END_DECLS
931-
932+#include <memory>
933+#include <string>
934+#include <vector>
935+
936+#include "application.h"
937+
938+namespace ubuntu
939+{
940+namespace app_launch
941+{
942+
943+void second_exec (std::shared_ptr<GDBusConnection> con, std::shared_ptr<GCancellable> cancel, GPid pid, const std::string& app_id, const std::string& instance_id, const std::vector<Application::URL>& appuris);
944+
945+}
946+}

Subscribers

People subscribed via source and target branches