Merge lp:~robert-ancell/lightdm/mir-container into lp:lightdm

Proposed by Robert Ancell
Status: Merged
Merged at revision: 2025
Proposed branch: lp:~robert-ancell/lightdm/mir-container
Merge into: lp:lightdm
Diff against target: 560 lines (+156/-35)
17 files modified
src/seat-surfaceflinger.c (+5/-1)
src/seat-unity.c (+4/-1)
src/seat-xdmcp-session.c (+2/-2)
src/seat-xlocal.c (+16/-1)
src/seat-xremote.c (+3/-1)
src/seat-xvnc.c (+2/-2)
src/seat.c (+17/-17)
src/seat.h (+1/-1)
src/session-config.c (+13/-0)
src/session-config.h (+2/-0)
src/session.c (+17/-7)
src/session.h (+4/-1)
tests/Makefile.am (+3/-0)
tests/data/sessions/mir-container.desktop (+6/-0)
tests/scripts/mir-container-session.conf (+54/-0)
tests/src/unity-system-compositor.c (+5/-1)
tests/test-mir-container-session (+2/-0)
To merge this branch: bzr merge lp:~robert-ancell/lightdm/mir-container
Reviewer Review Type Date Requested Status
Robert Ancell Approve
Christopher Townsend (community) Approve
PS Jenkins bot continuous-integration Approve
Review via email: mp+231665@code.launchpad.net

Commit message

Add a new session type 'mir-container' that allows the session to run inside a custom system compositor

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Christopher Townsend (townsend) wrote :

Works well and is better than my solution for the reasons you mentioned.

Thanks!

review: Approve
Revision history for this message
Robert Ancell (robert-ancell) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/seat-surfaceflinger.c'
2--- src/seat-surfaceflinger.c 2014-07-31 04:59:55 +0000
3+++ src/seat-surfaceflinger.c 2014-08-21 04:16:41 +0000
4@@ -25,8 +25,12 @@
5 }
6
7 static DisplayServer *
8-seat_surfaceflinger_create_display_server (Seat *seat, const gchar *session_type)
9+seat_surfaceflinger_create_display_server (Seat *seat, Session *session)
10 {
11+ const gchar *session_type;
12+
13+ session_type = session_get_session_type (session);
14+
15 /* Allow mir types too, because Mir sessions usually support surfaceflinger
16 as an alternate mode, since Mir is frequently used on phones. */
17 if (strcmp (session_type, "surfaceflinger") == 0 || strcmp (session_type, "mir") == 0)
18
19=== modified file 'src/seat-unity.c'
20--- src/seat-unity.c 2014-08-21 03:07:45 +0000
21+++ src/seat-unity.c 2014-08-21 04:16:41 +0000
22@@ -243,8 +243,11 @@
23 }
24
25 static DisplayServer *
26-seat_unity_create_display_server (Seat *seat, const gchar *session_type)
27+seat_unity_create_display_server (Seat *seat, Session *session)
28 {
29+ const gchar *session_type;
30+
31+ session_type = session_get_session_type (session);
32 if (strcmp (session_type, "x") == 0)
33 return DISPLAY_SERVER (create_x_server (seat));
34 else if (strcmp (session_type, "mir") == 0)
35
36=== modified file 'src/seat-xdmcp-session.c'
37--- src/seat-xdmcp-session.c 2013-10-28 17:19:00 +0000
38+++ src/seat-xdmcp-session.c 2014-08-21 04:16:41 +0000
39@@ -34,13 +34,13 @@
40 }
41
42 static DisplayServer *
43-seat_xdmcp_session_create_display_server (Seat *seat, const gchar *session_type)
44+seat_xdmcp_session_create_display_server (Seat *seat, Session *session)
45 {
46 XAuthority *authority;
47 gchar *host;
48 XServerRemote *x_server;
49
50- if (strcmp (session_type, "x") != 0)
51+ if (strcmp (session_get_session_type (session), "x") != 0)
52 return NULL;
53
54 authority = xdmcp_session_get_authority (SEAT_XDMCP_SESSION (seat)->priv->session);
55
56=== modified file 'src/seat-xlocal.c'
57--- src/seat-xlocal.c 2014-08-21 03:07:45 +0000
58+++ src/seat-xlocal.c 2014-08-21 04:16:41 +0000
59@@ -247,12 +247,27 @@
60 }
61
62 static DisplayServer *
63-seat_xlocal_create_display_server (Seat *seat, const gchar *session_type)
64+seat_xlocal_create_display_server (Seat *seat, Session *session)
65 {
66+ const gchar *session_type;
67+
68+ session_type = session_get_session_type (session);
69 if (strcmp (session_type, "x") == 0)
70 return DISPLAY_SERVER (create_x_server (seat));
71 else if (strcmp (session_type, "mir") == 0)
72 return create_unity_system_compositor (seat);
73+ else if (strcmp (session_type, "mir-container") == 0)
74+ {
75+ DisplayServer *compositor;
76+ const gchar *compositor_command;
77+
78+ compositor = create_unity_system_compositor (seat);
79+ compositor_command = session_config_get_compositor_command (session_get_config (session));
80+ if (compositor_command)
81+ unity_system_compositor_set_command (UNITY_SYSTEM_COMPOSITOR (compositor), compositor_command);
82+
83+ return compositor;
84+ }
85 else
86 {
87 l_warning (seat, "Can't create unsupported display server '%s'", session_type);
88
89=== modified file 'src/seat-xremote.c'
90--- src/seat-xremote.c 2014-07-31 04:59:55 +0000
91+++ src/seat-xremote.c 2014-08-21 04:16:41 +0000
92@@ -25,12 +25,14 @@
93 }
94
95 static DisplayServer *
96-seat_xremote_create_display_server (Seat *seat, const gchar *session_type)
97+seat_xremote_create_display_server (Seat *seat, Session *session)
98 {
99+ const gchar *session_type;
100 XServerRemote *x_server;
101 const gchar *hostname;
102 gint number;
103
104+ session_type = session_get_session_type (session);
105 if (strcmp (session_type, "x") != 0)
106 {
107 l_warning (seat, "X remote seat only supports X display servers, not '%s'", session_type);
108
109=== modified file 'src/seat-xvnc.c'
110--- src/seat-xvnc.c 2013-10-28 17:19:00 +0000
111+++ src/seat-xvnc.c 2014-08-21 04:16:41 +0000
112@@ -34,12 +34,12 @@
113 }
114
115 static DisplayServer *
116-seat_xvnc_create_display_server (Seat *seat, const gchar *session_type)
117+seat_xvnc_create_display_server (Seat *seat, Session *session)
118 {
119 XServerXVNC *x_server;
120 const gchar *command = NULL;
121
122- if (strcmp (session_type, "x") != 0)
123+ if (strcmp (session_get_session_type (session), "x") != 0)
124 return NULL;
125
126 x_server = x_server_xvnc_new ();
127
128=== modified file 'src/seat.c'
129--- src/seat.c 2014-08-21 03:07:45 +0000
130+++ src/seat.c 2014-08-21 04:16:41 +0000
131@@ -78,7 +78,7 @@
132 static GHashTable *seat_modules = NULL;
133
134 // FIXME: Make a get_display_server() that re-uses display servers if supported
135-static DisplayServer *create_display_server (Seat *seat, const gchar *session_type);
136+static DisplayServer *create_display_server (Seat *seat, Session *session);
137 static Greeter *create_greeter_session (Seat *seat);
138 static void start_session (Seat *seat, Session *session);
139
140@@ -527,7 +527,7 @@
141 {
142 DisplayServer *display_server;
143
144- display_server = create_display_server (seat, session_get_session_type (session));
145+ display_server = create_display_server (seat, session);
146 session_set_display_server (session, display_server);
147 if (!display_server_start (display_server))
148 {
149@@ -937,7 +937,7 @@
150 {
151 const gchar *desktop_name;
152
153- session_set_session_type (session, session_config_get_session_type (config));
154+ session_set_config (session, config);
155 session_set_env (session, "XDG_SESSION_DESKTOP", session_name);
156 session_set_env (session, "DESKTOP_SESSION", session_name);
157 session_set_env (session, "GDMSESSION", session_name);
158@@ -1063,7 +1063,7 @@
159 Session *session;
160
161 session = create_session (seat, FALSE);
162- session_set_session_type (session, session_get_session_type (SESSION (greeter)));
163+ session_set_config (session, session_get_config (SESSION (greeter)));
164 session_set_display_server (session, session_get_display_server (SESSION (greeter)));
165
166 return g_object_ref (session);
167@@ -1170,7 +1170,7 @@
168 /* Otherwise start a new display server for this session */
169 else
170 {
171- display_server = create_display_server (seat, session_get_session_type (session));
172+ display_server = create_display_server (seat, session);
173 session_set_display_server (session, display_server);
174 if (!display_server_start (display_server))
175 {
176@@ -1212,7 +1212,7 @@
177 }
178
179 greeter_session = SEAT_GET_CLASS (seat)->create_greeter_session (seat);
180- session_set_session_type (SESSION (greeter_session), session_config_get_session_type (session_config));
181+ session_set_config (SESSION (greeter_session), session_config);
182 seat->priv->sessions = g_list_append (seat->priv->sessions, SESSION (greeter_session));
183 g_signal_connect (greeter_session, "notify::active-username", G_CALLBACK (greeter_active_username_changed_cb), seat);
184 g_signal_connect (greeter_session, "authentication-complete", G_CALLBACK (session_authentication_complete_cb), seat);
185@@ -1326,13 +1326,13 @@
186 }
187
188 static DisplayServer *
189-create_display_server (Seat *seat, const gchar *session_type)
190+create_display_server (Seat *seat, Session *session)
191 {
192 DisplayServer *display_server;
193
194- l_debug (seat, "Creating display server of type %s", session_type);
195+ l_debug (seat, "Creating display server of type %s", session_get_session_type (session));
196
197- display_server = SEAT_GET_CLASS (seat)->create_display_server (seat, session_type);
198+ display_server = SEAT_GET_CLASS (seat)->create_display_server (seat, session);
199 if (!display_server)
200 return NULL;
201
202@@ -1371,7 +1371,7 @@
203 g_object_unref (seat->priv->session_to_activate);
204 seat->priv->session_to_activate = g_object_ref (greeter_session);
205
206- display_server = create_display_server (seat, session_get_session_type (SESSION (greeter_session)));
207+ display_server = create_display_server (seat, SESSION (greeter_session));
208 session_set_display_server (SESSION (greeter_session), display_server);
209
210 return display_server_start (display_server);
211@@ -1403,7 +1403,7 @@
212 if (seat->priv->session_to_activate)
213 g_object_unref (seat->priv->session_to_activate);
214 seat->priv->session_to_activate = g_object_ref (session);
215- display_server = create_display_server (seat, session_get_session_type (session));
216+ display_server = create_display_server (seat, session);
217 session_set_display_server (session, display_server);
218 display_server_start (display_server);
219 }
220@@ -1443,7 +1443,7 @@
221 g_object_unref (seat->priv->session_to_activate);
222 seat->priv->session_to_activate = g_object_ref (greeter_session);
223
224- display_server = create_display_server (seat, session_get_session_type (SESSION (greeter_session)));
225+ display_server = create_display_server (seat, SESSION (greeter_session));
226 session_set_display_server (SESSION (greeter_session), display_server);
227 display_server_start (display_server);
228 }
229@@ -1514,7 +1514,7 @@
230 if (!session)
231 return FALSE;
232
233- display_server = create_display_server (seat, session_get_session_type (session));
234+ display_server = create_display_server (seat, session);
235
236 if (seat->priv->session_to_activate)
237 g_object_unref (seat->priv->session_to_activate);
238@@ -1566,7 +1566,7 @@
239 }
240 else
241 {
242- display_server = create_display_server (seat, session_get_session_type (SESSION (greeter_session)));
243+ display_server = create_display_server (seat, SESSION (greeter_session));
244
245 if (seat->priv->session_to_activate)
246 g_object_unref (seat->priv->session_to_activate);
247@@ -1645,7 +1645,7 @@
248 g_object_unref (seat->priv->session_to_activate);
249 seat->priv->session_to_activate = g_object_ref (session);
250
251- display_server = create_display_server (seat, session_get_session_type (session));
252+ display_server = create_display_server (seat, session);
253 session_set_display_server (session, display_server);
254 if (!display_server || !display_server_start (display_server))
255 {
256@@ -1676,7 +1676,7 @@
257 seat->priv->session_to_activate = g_object_ref (greeter_session);
258 session = SESSION (greeter_session);
259
260- display_server = create_display_server (seat, session_get_session_type (session));
261+ display_server = create_display_server (seat, session);
262 session_set_display_server (session, display_server);
263 if (!display_server || !display_server_start (display_server))
264 {
265@@ -1700,7 +1700,7 @@
266 {
267 DisplayServer *background_display_server;
268
269- background_display_server = create_display_server (seat, session_get_session_type (background_session));
270+ background_display_server = create_display_server (seat, background_session);
271 session_set_display_server (background_session, background_display_server);
272 if (!display_server_start (background_display_server))
273 l_warning (seat, "Failed to start display server for background session");
274
275=== modified file 'src/seat.h'
276--- src/seat.h 2014-08-21 03:07:45 +0000
277+++ src/seat.h 2014-08-21 04:16:41 +0000
278@@ -40,7 +40,7 @@
279
280 void (*setup)(Seat *seat);
281 gboolean (*start)(Seat *seat);
282- DisplayServer *(*create_display_server) (Seat *seat, const gchar *session_type);
283+ DisplayServer *(*create_display_server) (Seat *seat, Session *session);
284 gboolean (*display_server_supports_session_type) (Seat *seat, DisplayServer *display_server, const gchar *session_type);
285 Greeter *(*create_greeter_session) (Seat *seat);
286 Session *(*create_session) (Seat *seat);
287
288=== modified file 'src/session-config.c'
289--- src/session-config.c 2014-04-03 14:24:47 +0000
290+++ src/session-config.c 2014-08-21 04:16:41 +0000
291@@ -21,6 +21,9 @@
292
293 /* Command to run */
294 gchar *command;
295+
296+ /* Compositor command to run (for type mir-container) */
297+ gchar *compositor_command;
298 };
299
300 G_DEFINE_TYPE (SessionConfig, session_config, G_TYPE_OBJECT);
301@@ -54,6 +57,8 @@
302 config->priv->desktop_name = g_key_file_get_string (desktop_file, G_KEY_FILE_DESKTOP_GROUP, "DesktopNames", NULL);
303 if (!config->priv->desktop_name)
304 config->priv->desktop_name = g_key_file_get_string (desktop_file, G_KEY_FILE_DESKTOP_GROUP, "X-LightDM-DesktopName", NULL);
305+ if (!config->priv->compositor_command)
306+ config->priv->compositor_command = g_key_file_get_string (desktop_file, G_KEY_FILE_DESKTOP_GROUP, "X-LightDM-System-Compositor-Command", NULL);
307
308 g_key_file_free (desktop_file);
309
310@@ -81,6 +86,13 @@
311 return config->priv->desktop_name;
312 }
313
314+const gchar *
315+session_config_get_compositor_command (SessionConfig *config)
316+{
317+ g_return_val_if_fail (config != NULL, NULL);
318+ return config->priv->compositor_command;
319+}
320+
321 static void
322 session_config_init (SessionConfig *config)
323 {
324@@ -95,6 +107,7 @@
325 g_free (self->priv->session_type);
326 g_free (self->priv->desktop_name);
327 g_free (self->priv->command);
328+ g_free (self->priv->compositor_command);
329
330 G_OBJECT_CLASS (session_config_parent_class)->finalize (object);
331 }
332
333=== modified file 'src/session-config.h'
334--- src/session-config.h 2013-08-19 00:21:19 +0000
335+++ src/session-config.h 2014-08-21 04:16:41 +0000
336@@ -44,6 +44,8 @@
337
338 const gchar *session_config_get_desktop_name (SessionConfig *config);
339
340+const gchar *session_config_get_compositor_command (SessionConfig *config);
341+
342 G_END_DECLS
343
344 #endif /* SESSION_CONFIG_H_ */
345
346=== modified file 'src/session.c'
347--- src/session.c 2014-03-23 22:41:16 +0000
348+++ src/session.c 2014-08-21 04:16:41 +0000
349@@ -38,8 +38,8 @@
350
351 struct SessionPrivate
352 {
353- /* Session type */
354- gchar *session_type;
355+ /* Configuration for this session */
356+ SessionConfig *config;
357
358 /* Display server running on */
359 DisplayServer *display_server;
360@@ -131,18 +131,27 @@
361 }
362
363 void
364-session_set_session_type (Session *session, const gchar *session_type)
365+session_set_config (Session *session, SessionConfig *config)
366 {
367 g_return_if_fail (session != NULL);
368- g_free (session->priv->session_type);
369- session->priv->session_type = g_strdup (session_type);
370+
371+ if (session->priv->config)
372+ g_object_unref (session->priv->config);
373+ session->priv->config = g_object_ref (config);
374+}
375+
376+SessionConfig *
377+session_get_config (Session *session)
378+{
379+ g_return_val_if_fail (session != NULL, NULL);
380+ return session->priv->config;
381 }
382
383 const gchar *
384 session_get_session_type (Session *session)
385 {
386 g_return_val_if_fail (session != NULL, NULL);
387- return session->priv->session_type;
388+ return session_config_get_session_type (session_get_config (session));
389 }
390
391 void
392@@ -904,7 +913,8 @@
393 Session *self = SESSION (object);
394 int i;
395
396- g_free (self->priv->session_type);
397+ if (self->priv->config)
398+ g_object_unref (self->priv->config);
399 if (self->priv->display_server)
400 g_object_unref (self->priv->display_server);
401 if (self->priv->pid)
402
403=== modified file 'src/session.h'
404--- src/session.h 2014-03-17 16:02:32 +0000
405+++ src/session.h 2014-08-21 04:16:41 +0000
406@@ -18,6 +18,7 @@
407
408 typedef struct Session Session;
409
410+#include "session-config.h"
411 #include "display-server.h"
412 #include "accounts.h"
413 #include "x-authority.h"
414@@ -61,7 +62,9 @@
415
416 Session *session_new (void);
417
418-void session_set_session_type (Session *session, const gchar *session_type);
419+void session_set_config (Session *session, SessionConfig *config);
420+
421+SessionConfig *session_get_config (Session *session);
422
423 const gchar *session_get_session_type (Session *session);
424
425
426=== modified file 'tests/Makefile.am'
427--- tests/Makefile.am 2014-07-31 04:59:55 +0000
428+++ tests/Makefile.am 2014-08-21 04:16:41 +0000
429@@ -187,6 +187,7 @@
430 test-mir-session \
431 test-mir-session-crash \
432 test-mir-session-compositor-crash \
433+ test-mir-container-session \
434 test-unity-compositor-command \
435 test-unity-compositor-not-found \
436 test-unity-compositor-fail-start \
437@@ -337,6 +338,7 @@
438 data/sessions/alternative.desktop \
439 data/sessions/default.desktop \
440 data/sessions/mir.desktop \
441+ data/sessions/mir-container.desktop \
442 data/sessions/named.desktop \
443 data/sessions/surfaceflinger.desktop \
444 scripts/0-additional.conf \
445@@ -440,6 +442,7 @@
446 scripts/login-wrong-password.conf \
447 scripts/login-xserver-crash.conf \
448 scripts/mir-autologin.conf \
449+ scripts/mir-container-session.conf \
450 scripts/mir-greeter.conf \
451 scripts/mir-session.conf \
452 scripts/mir-session-compositor-crash.conf \
453
454=== added file 'tests/data/sessions/mir-container.desktop'
455--- tests/data/sessions/mir-container.desktop 1970-01-01 00:00:00 +0000
456+++ tests/data/sessions/mir-container.desktop 2014-08-21 04:16:41 +0000
457@@ -0,0 +1,6 @@
458+[Desktop Entry]
459+Name=Test Session
460+Comment=LightDM test Mir session
461+Exec=test-session
462+X-LightDM-Session-Type=mir-container
463+X-LightDM-System-Compositor-Command=unity-system-compositor --container
464
465=== added file 'tests/scripts/mir-container-session.conf'
466--- tests/scripts/mir-container-session.conf 1970-01-01 00:00:00 +0000
467+++ tests/scripts/mir-container-session.conf 2014-08-21 04:16:41 +0000
468@@ -0,0 +1,54 @@
469+#
470+# Check can login into a containerised Mir session on a VT based seat
471+#
472+
473+[SeatDefaults]
474+user-session=mir-container
475+
476+#?*START-DAEMON
477+#?RUNNER DAEMON-START
478+
479+# X server starts
480+#?XSERVER-0 START VT=7 SEAT=seat0
481+
482+# Daemon connects when X server is ready
483+#?*XSERVER-0 INDICATE-READY
484+#?XSERVER-0 INDICATE-READY
485+#?XSERVER-0 ACCEPT-CONNECT
486+
487+# Greeter starts
488+#?GREETER-X-0 START XDG_SEAT=seat0 XDG_VTNR=7 XDG_SESSION_CLASS=greeter
489+#?LOGIN1 ACTIVATE-SESSION SESSION=c0
490+#?XSERVER-0 ACCEPT-CONNECT
491+#?GREETER-X-0 CONNECT-XSERVER
492+#?GREETER-X-0 CONNECT-TO-DAEMON
493+#?GREETER-X-0 CONNECTED-TO-DAEMON
494+
495+# Attempt to log into account
496+#?*GREETER-X-0 AUTHENTICATE USERNAME=no-password1
497+#?GREETER-X-0 AUTHENTICATION-COMPLETE USERNAME=no-password1 AUTHENTICATED=TRUE
498+#?*GREETER-X-0 START-SESSION
499+
500+# System compositor starts
501+#?UNITY-SYSTEM-COMPOSITOR START FILE=/run/lightdm-mir-0 VT=8 ENABLE-HARDWARE-CURSOR=TRUE XDG_VTNR=8 CONTAINER=TRUE
502+#?*UNITY-SYSTEM-COMPOSITOR READY
503+
504+# Switch to system compositor
505+#?VT ACTIVATE VT=8
506+
507+# Greeter terminates
508+#?GREETER-X-0 TERMINATE SIGNAL=15
509+#?XSERVER-0 TERMINATE SIGNAL=15
510+
511+# Session starts
512+#?SESSION-MIR-session-0 START XDG_SEAT=seat0 XDG_VTNR=8 XDG_GREETER_DATA_DIR=.*/no-password1 XDG_SESSION_TYPE=mir XDG_SESSION_DESKTOP=mir-container USER=no-password1
513+#?LOGIN1 ACTIVATE-SESSION SESSION=c1
514+
515+# Session shown
516+#?UNITY-SYSTEM-COMPOSITOR SET-ACTIVE-SESSION ID=session-0
517+
518+# Cleanup
519+#?*STOP-DAEMON
520+#?SESSION-MIR-session-0 TERMINATE SIGNAL=15
521+#?UNITY-SYSTEM-COMPOSITOR TERMINATE SIGNAL=15
522+#?RUNNER DAEMON-EXIT STATUS=0
523
524=== modified file 'tests/src/unity-system-compositor.c'
525--- tests/src/unity-system-compositor.c 2014-05-28 20:23:37 +0000
526+++ tests/src/unity-system-compositor.c 2014-08-21 04:16:41 +0000
527@@ -144,7 +144,7 @@
528 {
529 int i;
530 GString *status_text;
531- gboolean test = FALSE;
532+ gboolean test = FALSE, container = FALSE;
533 int vt_number = -1;
534 gboolean enable_hardware_cursor = FALSE;
535 const gchar *file = NULL;
536@@ -188,6 +188,8 @@
537 }
538 else if (strcmp (arg, "--test") == 0)
539 test = TRUE;
540+ else if (strcmp (arg, "--container") == 0)
541+ container = TRUE;
542 else
543 return EXIT_FAILURE;
544 }
545@@ -205,6 +207,8 @@
546 g_string_append_printf (status_text, " XDG_VTNR=%s", g_getenv ("XDG_VTNR"));
547 if (test)
548 g_string_append (status_text, " TEST=TRUE");
549+ if (container)
550+ g_string_append (status_text, " CONTAINER=TRUE");
551 status_notify ("%s", status_text->str);
552 g_string_free (status_text, TRUE);
553
554
555=== added file 'tests/test-mir-container-session'
556--- tests/test-mir-container-session 1970-01-01 00:00:00 +0000
557+++ tests/test-mir-container-session 2014-08-21 04:16:41 +0000
558@@ -0,0 +1,2 @@
559+#!/bin/sh
560+./src/dbus-env ./src/test-runner mir-container-session test-gobject-greeter

Subscribers

People subscribed via source and target branches