]> rtime.felk.cvut.cz Git - sojka/lightdm.git/blob - src/seat-unity.c
Fix autologin use case and add a test for it
[sojka/lightdm.git] / src / seat-unity.c
1 /*
2  * Copyright (C) 2012-2013 Robert Ancell.
3  * Author: Robert Ancell <robert.ancell@canonical.com>
4  *
5  * This program is free software: you can redistribute it and/or modify it under
6  * the terms of the GNU General Public License as published by the Free Software
7  * Foundation, either version 3 of the License, or (at your option) any later
8  * version. See http://www.gnu.org/copyleft/gpl.html the full text of the
9  * license.
10  */
11
12 #include <string.h>
13 #include <fcntl.h>
14 #include <errno.h>
15 #include <glib/gstdio.h>
16
17 #include "seat-unity.h"
18 #include "configuration.h"
19 #include "unity-system-compositor.h"
20 #include "x-server-local.h"
21 #include "mir-server.h"
22 #include "vt.h"
23 #include "plymouth.h"
24
25 struct SeatUnityPrivate
26 {
27     /* System compositor */
28     UnitySystemCompositor *compositor;
29
30     /* Next Mir ID to use for a Mir sessions, X server and greeters */
31     gint next_session_id;
32     gint next_x_server_id;
33     gint next_greeter_id;
34
35     /* The currently visible session */
36     Session *active_session;
37     DisplayServer *active_display_server;
38 };
39
40 G_DEFINE_TYPE (SeatUnity, seat_unity, SEAT_TYPE);
41
42 static gboolean
43 seat_unity_get_start_local_sessions (Seat *seat)
44 {
45     return !seat_get_string_property (seat, "xdmcp-manager");
46 }
47
48 static void
49 seat_unity_setup (Seat *seat)
50 {
51     seat_set_can_switch (seat, TRUE);
52     SEAT_CLASS (seat_unity_parent_class)->setup (seat);
53 }
54
55 static void
56 compositor_ready_cb (UnitySystemCompositor *compositor, SeatUnity *seat)
57 {
58     l_debug (seat, "Compositor ready"); 
59     SEAT_CLASS (seat_unity_parent_class)->start (SEAT (seat));
60 }
61
62 static void
63 compositor_stopped_cb (UnitySystemCompositor *compositor, SeatUnity *seat)
64 {
65     g_object_unref (seat->priv->compositor);
66     seat->priv->compositor = NULL;
67
68     if (seat_get_is_stopping (SEAT (seat)))
69     {
70         SEAT_CLASS (seat_unity_parent_class)->stop (SEAT (seat));
71         return;
72     }
73
74     l_debug (seat, "Stopping Unity seat, compositor terminated");
75
76     seat_stop (SEAT (seat));
77 }
78
79 static gboolean
80 seat_unity_start (Seat *seat)
81 {
82     gint vt = -1;
83     int timeout;
84
85     /* Replace Plymouth if it is running */
86     if (plymouth_get_is_active () && plymouth_has_active_vt ())
87     {
88         gint active_vt = vt_get_active ();
89         if (active_vt >= vt_get_min ())
90         {
91             vt = active_vt;
92             plymouth_quit (TRUE);
93         }
94         else
95             l_debug (seat, "Plymouth is running on VT %d, but this is less than the configured minimum of %d so not replacing it", active_vt, vt_get_min ());
96     }
97     if (plymouth_get_is_active ())
98         plymouth_quit (FALSE);
99     if (vt < 0)
100         vt = vt_can_multi_seat () ? vt_get_unused () : 0;
101     if (vt < 0)
102     {
103         l_debug (seat, "Failed to get a VT to run on");
104         return FALSE;
105     }
106
107     timeout = seat_get_integer_property (seat, "unity-compositor-timeout");
108     if (timeout <= 0)
109         timeout = 60;
110
111     SEAT_UNITY (seat)->priv->compositor = unity_system_compositor_new ();
112     g_signal_connect (SEAT_UNITY (seat)->priv->compositor, "ready", G_CALLBACK (compositor_ready_cb), seat);
113     g_signal_connect (SEAT_UNITY (seat)->priv->compositor, "stopped", G_CALLBACK (compositor_stopped_cb), seat);
114     unity_system_compositor_set_command (SEAT_UNITY (seat)->priv->compositor, seat_get_string_property (seat, "unity-compositor-command"));
115     unity_system_compositor_set_vt (SEAT_UNITY (seat)->priv->compositor, vt);
116     unity_system_compositor_set_timeout (SEAT_UNITY (seat)->priv->compositor, timeout);
117
118     return display_server_start (DISPLAY_SERVER (SEAT_UNITY (seat)->priv->compositor));
119 }
120
121 static DisplayServer *
122 create_x_server (Seat *seat)
123 {
124     XServerLocal *x_server;
125     const gchar *command = NULL, *layout = NULL, *config_file = NULL, *xdmcp_manager = NULL, *key_name = NULL;
126     gboolean allow_tcp;
127     gint port = 0;
128     gchar *id;
129
130     l_debug (seat, "Starting X server on Unity compositor");
131
132     x_server = x_server_local_new ();
133
134     command = seat_get_string_property (seat, "xserver-command");
135     if (command)
136         x_server_local_set_command (x_server, command);
137
138     id = g_strdup_printf ("x-%d", SEAT_UNITY (seat)->priv->next_x_server_id);
139     SEAT_UNITY (seat)->priv->next_x_server_id++;
140     x_server_local_set_mir_id (x_server, id);
141     x_server_local_set_mir_socket (x_server, unity_system_compositor_get_socket (SEAT_UNITY (seat)->priv->compositor));
142     g_free (id);
143
144     layout = seat_get_string_property (seat, "xserver-layout");
145     if (layout)
146         x_server_local_set_layout (x_server, layout);
147     
148     x_server_local_set_xdg_seat (x_server, seat_get_name (seat));
149
150     config_file = seat_get_string_property (seat, "xserver-config");
151     if (config_file)
152         x_server_local_set_config (x_server, config_file);
153
154     allow_tcp = seat_get_boolean_property (seat, "xserver-allow-tcp");
155     x_server_local_set_allow_tcp (x_server, allow_tcp);
156
157     xdmcp_manager = seat_get_string_property (seat, "xdmcp-manager");
158     if (xdmcp_manager)
159         x_server_local_set_xdmcp_server (x_server, xdmcp_manager);
160
161     port = seat_get_integer_property (seat, "xdmcp-port");
162     if (port > 0)
163         x_server_local_set_xdmcp_port (x_server, port);
164
165     key_name = seat_get_string_property (seat, "xdmcp-key");
166     if (key_name)
167     {
168         gchar *dir, *path;
169         GKeyFile *keys;
170         gboolean result;
171         GError *error = NULL;
172
173         dir = config_get_string (config_get_instance (), "LightDM", "config-directory");
174         path = g_build_filename (dir, "keys.conf", NULL);
175         g_free (dir);
176
177         keys = g_key_file_new ();
178         result = g_key_file_load_from_file (keys, path, G_KEY_FILE_NONE, &error);
179         if (error)
180             l_debug (seat, "Error getting key %s", error->message);
181         g_clear_error (&error);
182
183         if (result)
184         {
185             gchar *key = NULL;
186
187             if (g_key_file_has_key (keys, "keyring", key_name, NULL))
188                 key = g_key_file_get_string (keys, "keyring", key_name, NULL);
189             else
190                 l_debug (seat, "Key %s not defined", key_name);
191
192             if (key)
193                 x_server_local_set_xdmcp_key (x_server, key);
194             g_free (key);
195         }
196
197         g_free (path);
198         g_key_file_free (keys);
199     }
200
201     return DISPLAY_SERVER (x_server);
202 }
203
204 static DisplayServer *
205 create_mir_server (Seat *seat)
206 {
207     MirServer *mir_server;
208
209     mir_server = mir_server_new ();
210     mir_server_set_parent_socket (mir_server, unity_system_compositor_get_socket (SEAT_UNITY (seat)->priv->compositor));
211
212     return DISPLAY_SERVER (mir_server);
213 }
214
215 static DisplayServer *
216 seat_unity_create_display_server (Seat *seat, const gchar *session_type)
217 {  
218     if (strcmp (session_type, "x") == 0)
219         return create_x_server (seat);
220     else if (strcmp (session_type, "mir") == 0)
221         return create_mir_server (seat);
222     else
223     {
224         l_warning (seat, "Can't create unsupported display server '%s'", session_type);
225         return NULL;
226     }
227 }
228
229 static Greeter *
230 seat_unity_create_greeter_session (Seat *seat)
231 {
232     Greeter *greeter_session;
233     gchar *id;
234     gint vt;
235
236     greeter_session = SEAT_CLASS (seat_unity_parent_class)->create_greeter_session (seat);
237     session_set_env (SESSION (greeter_session), "XDG_SEAT", seat_get_name (seat));
238
239     id = g_strdup_printf ("greeter-%d", SEAT_UNITY (seat)->priv->next_greeter_id);
240     SEAT_UNITY (seat)->priv->next_greeter_id++;
241     session_set_env (SESSION (greeter_session), "MIR_SERVER_NAME", id);
242     g_free (id);
243
244     vt = display_server_get_vt (DISPLAY_SERVER (SEAT_UNITY (seat)->priv->compositor));
245     if (vt >= 0)
246     {
247         gchar *value = g_strdup_printf ("%d", vt);
248         session_set_env (SESSION (greeter_session), "XDG_VTNR", value);
249         g_free (value);
250     }
251
252     return greeter_session;
253 }
254
255 static Session *
256 seat_unity_create_session (Seat *seat)
257 {
258     Session *session;
259     gchar *id;
260     gint vt;
261
262     session = SEAT_CLASS (seat_unity_parent_class)->create_session (seat);
263     session_set_env (session, "XDG_SEAT", seat_get_name (seat));
264
265     id = g_strdup_printf ("session-%d", SEAT_UNITY (seat)->priv->next_session_id);
266     SEAT_UNITY (seat)->priv->next_session_id++;
267     session_set_env (session, "MIR_SERVER_NAME", id);
268     g_free (id);
269
270     vt = display_server_get_vt (DISPLAY_SERVER (SEAT_UNITY (seat)->priv->compositor));
271     if (vt >= 0)
272     {
273         gchar *value = g_strdup_printf ("%d", vt);
274         session_set_env (SESSION (session), "XDG_VTNR", value);
275         g_free (value);
276     }
277
278     return session;
279 }
280
281 static void
282 seat_unity_set_active_session (Seat *seat, Session *session)
283 {
284     DisplayServer *display_server;
285
286     if (session == SEAT_UNITY (seat)->priv->active_session)
287         return;
288     SEAT_UNITY (seat)->priv->active_session = g_object_ref (session);
289
290     display_server = session_get_display_server (session);
291     if (SEAT_UNITY (seat)->priv->active_display_server != display_server)
292     {
293         const gchar *id = NULL;
294
295         SEAT_UNITY (seat)->priv->active_display_server = g_object_ref (display_server);
296
297         if (IS_X_SERVER_LOCAL (display_server))
298             id = x_server_local_get_mir_id (X_SERVER_LOCAL (display_server));
299         else
300             id = session_get_env (session, "MIR_SERVER_NAME");
301
302         if (id)
303         {
304             l_debug (seat, "Switching to Mir session %s", id);
305             unity_system_compositor_set_active_session (SEAT_UNITY (seat)->priv->compositor, id);
306         }
307         else
308             l_warning (seat, "Failed to work out session ID");
309     }
310
311     SEAT_CLASS (seat_unity_parent_class)->set_active_session (seat, session);
312 }
313
314 static Session *
315 seat_unity_get_active_session (Seat *seat)
316 {
317     return SEAT_UNITY (seat)->priv->active_session;
318 }
319
320 static void
321 seat_unity_set_next_session (Seat *seat, Session *session)
322 {
323     DisplayServer *display_server;
324     const gchar *id = NULL;
325
326     if (!session)
327         return;
328
329     display_server = session_get_display_server (session);
330
331     if (IS_X_SERVER_LOCAL (display_server))
332         id = x_server_local_get_mir_id (X_SERVER_LOCAL (display_server));
333     else
334         id = session_get_env (session, "MIR_SERVER_NAME");
335
336     if (id)
337     {
338         l_debug (seat, "Marking Mir session %s as the next session", id);
339         unity_system_compositor_set_next_session (SEAT_UNITY (seat)->priv->compositor, id);
340     }
341     else
342     {
343         l_debug (seat, "Failed to work out session ID to mark");
344     }
345
346     SEAT_CLASS (seat_unity_parent_class)->set_next_session (seat, session);
347 }
348
349 static void
350 seat_unity_run_script (Seat *seat, DisplayServer *display_server, Process *script)
351 {
352     const gchar *path;
353     XServerLocal *x_server;
354
355     x_server = X_SERVER_LOCAL (display_server);
356     path = x_server_local_get_authority_file_path (x_server);
357     process_set_env (script, "DISPLAY", x_server_get_address (X_SERVER (x_server)));
358     process_set_env (script, "XAUTHORITY", path);
359
360     SEAT_CLASS (seat_unity_parent_class)->run_script (seat, display_server, script);
361 }
362
363 static void
364 seat_unity_stop (Seat *seat)
365 {
366     /* Stop the compositor first */
367     if (SEAT_UNITY (seat)->priv->compositor)
368     {
369         display_server_stop (DISPLAY_SERVER (SEAT_UNITY (seat)->priv->compositor));
370         return;
371     }
372
373     SEAT_CLASS (seat_unity_parent_class)->stop (seat);
374 }
375
376 static void
377 seat_unity_init (SeatUnity *seat)
378 {
379     seat->priv = G_TYPE_INSTANCE_GET_PRIVATE (seat, SEAT_UNITY_TYPE, SeatUnityPrivate);
380 }
381
382 static void
383 seat_unity_finalize (GObject *object)
384 {
385     SeatUnity *seat = SEAT_UNITY (object);
386
387     if (seat->priv->compositor)
388         g_object_unref (seat->priv->compositor);
389     if (seat->priv->active_session)
390         g_object_unref (seat->priv->active_session);
391     if (seat->priv->active_display_server)
392         g_object_unref (seat->priv->active_display_server);
393
394     G_OBJECT_CLASS (seat_unity_parent_class)->finalize (object);
395 }
396
397 static void
398 seat_unity_class_init (SeatUnityClass *klass)
399 {
400     GObjectClass *object_class = G_OBJECT_CLASS (klass);
401     SeatClass *seat_class = SEAT_CLASS (klass);
402
403     object_class->finalize = seat_unity_finalize;
404     seat_class->get_start_local_sessions = seat_unity_get_start_local_sessions;
405     seat_class->setup = seat_unity_setup;
406     seat_class->start = seat_unity_start;
407     seat_class->create_display_server = seat_unity_create_display_server;
408     seat_class->create_greeter_session = seat_unity_create_greeter_session;
409     seat_class->create_session = seat_unity_create_session;
410     seat_class->set_active_session = seat_unity_set_active_session;
411     seat_class->get_active_session = seat_unity_get_active_session;
412     seat_class->set_next_session = seat_unity_set_next_session;
413     seat_class->run_script = seat_unity_run_script;
414     seat_class->stop = seat_unity_stop;
415
416     g_type_class_add_private (klass, sizeof (SeatUnityPrivate));
417 }