Merge lp:~ubuntu-multiseat/lightdm/new-automatic-multiseat into lp:lightdm

Proposed by Laércio de Sousa
Status: Merged
Merged at revision: 2033
Proposed branch: lp:~ubuntu-multiseat/lightdm/new-automatic-multiseat
Merge into: lp:lightdm
Diff against target: 352 lines (+198/-85)
3 files modified
src/lightdm.c (+173/-71)
src/login1.c (+0/-1)
tests/scripts/multi-seat.conf (+25/-13)
To merge this branch: bzr merge lp:~ubuntu-multiseat/lightdm/new-automatic-multiseat
Reviewer Review Type Date Requested Status
Robert Ancell Approve
Review via email: mp+231903@code.launchpad.net

Description of the change

This new branch implements automatic multiseat support in LightDM, following steps 1 & 2 of "Complete porting" section in systemd-logind documentation [1]. This is a rework of old branch lp:~ubuntu-multiseat/lightdm/automatic-multiseat after introduction of login1 service object in upstream revision 2028.

This new implementation has some additional features, added after discussion with Robert Ancell:

 * If logind is running, LightDM won't try to load seats statically as before. Instead, any [Seat:seat*] config sections in lightdm.conf will be loaded on demand, as new seats are added from logind. Since logind returns at least one seat (namely, seat0), start-default-seat condition should never be reached in this case.

 * Seat properties "seat-name" and "xdg-seat" will be both automatically set to return value of function login1_seat_get_id(). It opens the possibility of merging both properties, or deprecating "xdg-seat", in the near future.

At the moment, this branch has some issues:

1. Test scripts have not been added yet.

2. What should it do if a logind seat has property CanGraphical=no?

3. It still doesn't watch PropertyChanged events on logind seats. What should it do if logind seat property CanGraphical changes?

[1] http://www.freedesktop.org/wiki/Software/systemd/writing-display-managers/

To post a comment you must log in.
2036. By Laércio de Sousa

Add a debug message before start monitoring logind for new/removed seats

2037. By Laércio de Sousa

Remove uneeded g_variant_unref() call inside g_variant_iter_loop().

See documentation at https://developer.gnome.org/glib/2.41/glib-GVariant.html#g-variant-iter-loop

2038. By Laércio de Sousa

Add/Update some debug messages.

2039. By Laércio de Sousa

Ensure start-default-seat condition will never be reached when
adding seats from logind.

Revision history for this message
Laércio de Sousa (lbssousa) wrote :

[NEW ISSUE] Should we support simple globbing in seat config sections when loading seats from logind? Examples:

[Seat:seatFoo*] would match any logind seat whose id starts with "seatFoo".

Side effect: [Seat:seat*], or just [Seat:*], would match any seat (including seat0), just like [SeatDefaults] does.

2040. By Laércio de Sousa

Revert changes made in revision 2032.

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

I was also thinking about globbing. We should do it as a separate MP though as it extends the current behaviour. Please open a new bug/mp.

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

> seat = seat_new ("xlocal");

This should use the same logic as before for picking the seat type.

Reading the logind documentation we should ignore seats that have CanGraphical=false. We should watch for property changes on this, but it's not a blocker to landing this branch (since most real world cases probably wont have this change) - we can add it into another MP later.

Needs at least one regression test. tests/scripts/multi-seat.conf breaks with this change (as expected). You will need to add #?*ADD-SEAT lines into this to make it work.

Otherwise looks good.

review: Needs Fixing
2041. By Laércio de Sousa

Update test-multi-seat script to deal with seats added/removed dinamically
from logind.

2042. By Laércio de Sousa

Make seat type configurable for seats added from logind.

2043. By Laércio de Sousa

Fix typo in g_strfreev() call.

Revision history for this message
Laércio de Sousa (lbssousa) wrote :

> > seat = seat_new ("xlocal");
>
> This should use the same logic as before for picking the seat type.

OK. Seat type is configurable now. Done in revisions 2042/2043.

> Reading the logind documentation we should ignore seats that have
> CanGraphical=false. We should watch for property changes on this, but it's not
> a blocker to landing this branch (since most real world cases probably wont
> have this change) - we can add it into another MP later.

OK.

> Needs at least one regression test. tests/scripts/multi-seat.conf breaks with
> this change (as expected). You will need to add #?*ADD-SEAT lines into this to
> make it work.

I'm still learning how to write test scripts for lightdm, nevertheless I've updated test/scripts/multi-seat.conf in revision 2041. For some reason, I was unable to test it in my local VirtualBox VM installation (running "make check" results in 100+ fails in my system). Could you please take a look and tell me if there's any errors in it?

2044. By Laércio de Sousa

Use login1_service_get_instance() more extensively in lightdm.c.

2045. By Laércio de Sousa

Fix mistakes in updated test-multi-seat script.

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

I've pushed this with some changes. The particular things that were causing the tests to break:
- None of the logind created seats were marked with "exit-on-failure" so the daemon didn't stop in the failure tests
- Failure to start any seats didn't cause the daemon to exit like it used to
- The multi-seat test script had "#*?ADD-SEAT" instead of "#?*ADD-SEAT"
- There was a bug in my mock login1 interface that didn't export the seat properties

I also took the opportunity to deprecate the old manual seat method. We'll see if anyone screams and if we need to add it back (my guess is probably not).

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/lightdm.c'
2--- src/lightdm.c 2014-08-22 09:01:20 +0000
3+++ src/lightdm.c 2014-08-26 14:51:50 +0000
4@@ -979,6 +979,96 @@
5 exit (EXIT_FAILURE);
6 }
7
8+static void
9+login1_service_seat_added_cb (Login1Service *service, Login1Seat *login1_seat)
10+{
11+ const gchar *seat_name = login1_seat_get_id (login1_seat);
12+ gchar **groups, **i;
13+ gchar *config_section = NULL;
14+ gchar **types = NULL, **type;
15+ Seat *seat = NULL;
16+
17+ g_debug ("New seat added from logind: %s", seat_name);
18+ groups = config_get_groups (config_get_instance ());
19+
20+ for (i = groups; !config_section && *i; i++)
21+ {
22+ if (g_str_has_prefix (*i, "Seat:") &&
23+ g_str_has_suffix (*i, seat_name))
24+ config_section = *i;
25+ }
26+
27+ if (config_section)
28+ {
29+ g_debug ("Loading properties from config section %s", config_section);
30+ types = config_get_string_list (config_get_instance (), config_section, "type");
31+ }
32+
33+ if (!types)
34+ types = config_get_string_list (config_get_instance (), "SeatDefaults", "type");
35+
36+ for (type = types; !seat && type && *type; type++)
37+ seat = seat_new (*type);
38+
39+ g_strfreev (types);
40+
41+ if (seat)
42+ {
43+ set_seat_properties (seat, NULL);
44+
45+ if (!login1_seat_get_can_multi_session (login1_seat))
46+ {
47+ g_debug ("Seat %s has property CanMultiSession=no", seat_name);
48+ seat_set_property (seat, "allow-user-switching", "false");
49+ }
50+
51+ if (config_section)
52+ set_seat_properties (seat, config_section);
53+
54+ seat_set_property (seat, "seat-name", seat_name);
55+ seat_set_property (seat, "xdg-seat", seat_name);
56+ g_strfreev (groups);
57+ }
58+ else
59+ {
60+ // FIXME: Need to make proper error
61+ g_warning ("Unable to create seat: %s", seat_name);
62+ g_strfreev (groups);
63+ return;
64+ }
65+
66+ if (!display_manager_add_seat (display_manager, seat)) // FIXME: Need to make proper error
67+ g_warning ("Failed to start seat: %s", seat_name);
68+
69+ g_object_unref (seat);
70+}
71+
72+static void
73+login1_service_seat_removed_cb (Login1Service *service, Login1Seat *login1_seat)
74+{
75+ GList *seats, *link;
76+ Seat *seat;
77+ const gchar *seat_name = login1_seat_get_id (login1_seat);
78+
79+ /* Stop all seats matching given xdg-seat property value.
80+ * Copy the list as it might be modified if a seat stops during this loop */
81+ seats = g_list_copy (display_manager_get_seats (display_manager));
82+
83+ /* FIXME: This loop should be uneeded, provided we can ensure
84+ * there's only one Seat object in DisplayManager list
85+ * matching given Login1Seat object id. */
86+ g_debug ("Seat removed from logind: %s", seat_name);
87+ for (link = seats; link; link = link->next)
88+ {
89+ seat = link->data;
90+
91+ if (g_strcmp0 (seat_get_name (seat), seat_name) == 0)
92+ seat_stop (seat);
93+ }
94+
95+ g_list_free (seats);
96+}
97+
98 int
99 main (int argc, char **argv)
100 {
101@@ -986,7 +1076,6 @@
102 GOptionContext *option_context;
103 gboolean result;
104 gchar **groups, **i, *dir;
105- gint n_seats = 0;
106 gboolean test_mode = FALSE;
107 gchar *pid_path = "/var/run/lightdm.pid";
108 gchar *log_dir = NULL;
109@@ -1311,78 +1400,91 @@
110 shared_data_manager_start (shared_data_manager_get_instance ());
111
112 /* Connect to logind */
113- login1_service_connect (login1_service_get_instance ());
114-
115- /* Load the static display entries */
116- groups = config_get_groups (config_get_instance ());
117- for (i = groups; *i; i++)
118- {
119- gchar *config_section = *i;
120- gchar **types;
121- gchar **type;
122- Seat *seat = NULL;
123- const gchar *const seatpfx = "Seat:";
124-
125- if (!g_str_has_prefix (config_section, seatpfx))
126- continue;
127-
128- g_debug ("Loading seat %s", config_section);
129- types = config_get_string_list (config_get_instance (), config_section, "type");
130- if (!types)
131+ if (login1_service_connect (login1_service_get_instance ()))
132+ {
133+ /* Load dynamic seats from logind */
134+ g_debug ("Start monitoring logind for new/removed seats");
135+ g_signal_connect (login1_service_get_instance (), "seat-added", G_CALLBACK (login1_service_seat_added_cb), NULL);
136+ g_signal_connect (login1_service_get_instance (), "seat-removed", G_CALLBACK (login1_service_seat_removed_cb), NULL);
137+
138+ for (link = login1_service_get_seats (login1_service_get_instance ()); link; link = link->next)
139+ login1_service_seat_added_cb (login1_service_get_instance (), (Login1Seat *) link->data);
140+ }
141+ else
142+ {
143+ gint n_seats = 0;
144+
145+ /* Load the static display entries */
146+ groups = config_get_groups (config_get_instance ());
147+ for (i = groups; *i; i++)
148+ {
149+ gchar *config_section = *i;
150+ gchar **types;
151+ gchar **type;
152+ Seat *seat = NULL;
153+ const gchar *const seatpfx = "Seat:";
154+
155+ if (!g_str_has_prefix (config_section, seatpfx))
156+ continue;
157+
158+ g_debug ("Loading seat %s", config_section);
159+ types = config_get_string_list (config_get_instance (), config_section, "type");
160+ if (!types)
161+ types = config_get_string_list (config_get_instance (), "SeatDefaults", "type");
162+ for (type = types; type && *type; type++)
163+ {
164+ seat = seat_new (*type);
165+ if (seat)
166+ break;
167+ }
168+ g_strfreev (types);
169+ if (seat)
170+ {
171+ const gsize seatpfxlen = strlen(seatpfx);
172+ gchar *seatname = config_section + seatpfxlen;
173+
174+ seat_set_property (seat, "seat-name", seatname);
175+
176+ set_seat_properties (seat, config_section);
177+ display_manager_add_seat (display_manager, seat);
178+ g_object_unref (seat);
179+ n_seats++;
180+ }
181+ else
182+ g_warning ("Failed to create seat %s", config_section);
183+ }
184+ g_strfreev (groups);
185+
186+ /* If no seats start a default one */
187+ if (n_seats == 0 && config_get_boolean (config_get_instance (), "LightDM", "start-default-seat"))
188+ {
189+ gchar **types;
190+ gchar **type;
191+ Seat *seat = NULL;
192+
193+ g_debug ("Adding default seat");
194+
195 types = config_get_string_list (config_get_instance (), "SeatDefaults", "type");
196- for (type = types; type && *type; type++)
197- {
198- seat = seat_new (*type);
199- if (seat)
200- break;
201- }
202- g_strfreev (types);
203- if (seat)
204- {
205- const gsize seatpfxlen = strlen(seatpfx);
206- gchar *seatname = config_section + seatpfxlen;
207-
208- seat_set_property (seat, "seat-name", seatname);
209-
210- set_seat_properties (seat, config_section);
211- display_manager_add_seat (display_manager, seat);
212- g_object_unref (seat);
213- n_seats++;
214- }
215- else
216- g_warning ("Failed to create seat %s", config_section);
217- }
218- g_strfreev (groups);
219-
220- /* If no seats start a default one */
221- if (n_seats == 0 && config_get_boolean (config_get_instance (), "LightDM", "start-default-seat"))
222- {
223- gchar **types;
224- gchar **type;
225- Seat *seat = NULL;
226-
227- g_debug ("Adding default seat");
228-
229- types = config_get_string_list (config_get_instance (), "SeatDefaults", "type");
230- for (type = types; type && *type; type++)
231- {
232- seat = seat_new (*type);
233- if (seat)
234- break;
235- }
236- g_strfreev (types);
237- if (seat)
238- {
239- set_seat_properties (seat, NULL);
240- seat_set_property (seat, "exit-on-failure", "true");
241- if (!display_manager_add_seat (display_manager, seat))
242+ for (type = types; type && *type; type++)
243+ {
244+ seat = seat_new (*type);
245+ if (seat)
246+ break;
247+ }
248+ g_strfreev (types);
249+ if (seat)
250+ {
251+ set_seat_properties (seat, NULL);
252+ seat_set_property (seat, "exit-on-failure", "true");
253+ if (!display_manager_add_seat (display_manager, seat))
254+ return EXIT_FAILURE;
255+ g_object_unref (seat);
256+ }
257+ else
258+ {
259+ g_warning ("Failed to create default seat");
260 return EXIT_FAILURE;
261- g_object_unref (seat);
262- }
263- else
264- {
265- g_warning ("Failed to create default seat");
266- return EXIT_FAILURE;
267+ }
268 }
269 }
270
271
272=== modified file 'src/login1.c'
273--- src/login1.c 2014-08-22 01:56:45 +0000
274+++ src/login1.c 2014-08-26 14:51:50 +0000
275@@ -269,7 +269,6 @@
276 seat->priv->can_graphical = g_variant_get_boolean (value);
277 else if (strcmp (name, "CanMultiSession") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_BOOLEAN))
278 seat->priv->can_multi_session = g_variant_get_boolean (value);
279- g_variant_unref (value);
280 }
281 g_variant_iter_free (properties);
282 g_variant_unref (result);
283
284=== modified file 'tests/scripts/multi-seat.conf'
285--- tests/scripts/multi-seat.conf 2014-03-17 18:33:02 +0000
286+++ tests/scripts/multi-seat.conf 2014-08-26 14:51:50 +0000
287@@ -1,17 +1,15 @@
288 #
289-# Check can run two seats at once
290+# Check can run two seats at once (added from logind)
291 #
292
293-[Seat:0]
294-xdg-seat=seat0
295-
296-[Seat:1]
297-xdg-seat=seat1
298-
299 #?*START-DAEMON
300 #?RUNNER DAEMON-START
301
302-# Seat0 starts
303+# Check if seat0 was added
304+#*?LIST-SEATS
305+#?RUNNER LIST-SEATS SEATS=/org/freedesktop/DisplayManager/Seat0
306+
307+# seat0 starts
308 #?XSERVER-0 START VT=7 SEAT=seat0
309 #?*XSERVER-0 INDICATE-READY
310 #?XSERVER-0 INDICATE-READY
311@@ -23,22 +21,36 @@
312 #?GREETER-X-0 CONNECT-TO-DAEMON
313 #?GREETER-X-0 CONNECTED-TO-DAEMON
314
315-# Seat1 starts (can't use VTs)
316-#?XSERVER-1 START SEAT=seat1
317+# Add seat-1 (can't use VTs)
318+#*?ADD-SEAT ID=seat-1 CAN-GRAPHICAL=TRUE CAN-MULTI-SESSION=FALSE
319+
320+# Check if seat-1 was added
321+#*?LIST-SEATS
322+#?RUNNER LIST-SEATS SEATS=/org/freedesktop/DisplayManager/Seat0,/org/freedesktop/DisplayManager/Seat1
323+
324+# seat-1 starts
325+#?XSERVER-1 START SEAT=seat-1
326 #?*XSERVER-1 INDICATE-READY
327 #?XSERVER-1 INDICATE-READY
328 #?XSERVER-1 ACCEPT-CONNECT
329-#?GREETER-X-1 START XDG_SEAT=seat1 XDG_SESSION_CLASS=greeter
330+#?GREETER-X-1 START XDG_SEAT=seat-1 XDG_SESSION_CLASS=greeter
331 #?LOGIN1 ACTIVATE-SESSION SESSION=c1
332 #?XSERVER-1 ACCEPT-CONNECT
333 #?GREETER-X-1 CONNECT-XSERVER
334 #?GREETER-X-1 CONNECT-TO-DAEMON
335 #?GREETER-X-1 CONNECTED-TO-DAEMON
336
337+# Remove seat-1
338+#*REMOVE-SEAT ID=seat-1
339+#?GREETER-X-1 TERMINATE SIGNAL=15
340+#?XSERVER-1 TERMINATE SIGNAL=15
341+
342+# Check if seat-1 was removed
343+#*?LIST-SEATS
344+#?RUNNER LIST-SEATS SEATS=/org/freedesktop/DisplayManager/Seat0
345+
346 # Cleanup
347 #?*STOP-DAEMON
348 #?GREETER-X-0 TERMINATE SIGNAL=15
349-#?GREETER-X-1 TERMINATE SIGNAL=15
350 #?XSERVER-0 TERMINATE SIGNAL=15
351-#?XSERVER-1 TERMINATE SIGNAL=15
352 #?RUNNER DAEMON-EXIT STATUS=0

Subscribers

People subscribed via source and target branches