]> rtime.felk.cvut.cz Git - sojka/lightdm.git/blob - src/display-manager.c
Rename xlocal seat to local - it supports Mir and Wayland as well as X. The xlocal...
[sojka/lightdm.git] / src / display-manager.c
1 /*
2  * Copyright (C) 2010-2011 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 <config.h>
13
14 #include <stdlib.h>
15 #include <string.h>
16 #include <sys/wait.h>
17
18 #include "display-manager.h"
19 #include "configuration.h"
20 #include "seat-local.h"
21 #include "seat-xremote.h"
22 #include "seat-unity.h"
23 #include "plymouth.h"
24
25 enum {
26     SEAT_ADDED,
27     SEAT_REMOVED,
28     STOPPED,
29     LAST_SIGNAL
30 };
31 static guint signals[LAST_SIGNAL] = { 0 };
32
33 struct DisplayManagerPrivate
34 {
35     /* The seats available */
36     GList *seats;
37
38     /* TRUE if stopping the display manager (waiting for seats to stop) */
39     gboolean stopping;
40
41     /* TRUE if stopped */
42     gboolean stopped;
43 };
44
45 G_DEFINE_TYPE (DisplayManager, display_manager, G_TYPE_OBJECT);
46
47 DisplayManager *
48 display_manager_new (void)
49 {
50     return g_object_new (DISPLAY_MANAGER_TYPE, NULL);
51 }
52
53 GList *
54 display_manager_get_seats (DisplayManager *manager)
55 {
56     return manager->priv->seats;
57 }
58
59 Seat *
60 display_manager_get_seat (DisplayManager *manager, const gchar *name)
61 {
62     GList *link;
63
64     for (link = manager->priv->seats; link; link = link->next)
65     {
66         Seat *seat = link->data;
67
68         if (strcmp (seat_get_name (seat), name) == 0)
69             return seat;
70     }
71
72     return NULL;
73 }
74
75 static void
76 check_stopped (DisplayManager *manager)
77 {
78     if (manager->priv->stopping &&
79         !manager->priv->stopped &&
80         g_list_length (manager->priv->seats) == 0)
81     {
82         manager->priv->stopped = TRUE;
83         g_debug ("Display manager stopped");
84         g_signal_emit (manager, signals[STOPPED], 0);
85     }
86 }
87
88 static void
89 seat_stopped_cb (Seat *seat, DisplayManager *manager)
90 {
91     manager->priv->seats = g_list_remove (manager->priv->seats, seat);
92     g_signal_handlers_disconnect_matched (seat, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, manager);
93
94     if (!manager->priv->stopping)
95         g_signal_emit (manager, signals[SEAT_REMOVED], 0, seat);
96
97     g_object_unref (seat);
98
99     check_stopped (manager);
100 }
101
102 gboolean
103 display_manager_add_seat (DisplayManager *manager, Seat *seat)
104 {
105     gboolean result;
106
107     g_return_val_if_fail (!manager->priv->stopping, FALSE);
108
109     result = seat_start (SEAT (seat));
110     if (!result)
111         return FALSE;
112
113     manager->priv->seats = g_list_append (manager->priv->seats, g_object_ref (seat));
114     g_signal_connect (seat, SEAT_SIGNAL_STOPPED, G_CALLBACK (seat_stopped_cb), manager);
115     g_signal_emit (manager, signals[SEAT_ADDED], 0, seat);
116
117     return TRUE;
118 }
119
120 void
121 display_manager_start (DisplayManager *manager)
122 {
123     g_return_if_fail (manager != NULL);
124
125     /* Disable Plymouth if no X servers are replacing it */
126     if (plymouth_get_is_active ())
127     {
128         g_debug ("Stopping Plymouth, no displays replace it");
129         plymouth_quit (FALSE);
130     }
131 }
132
133 void
134 display_manager_stop (DisplayManager *manager)
135 {
136     GList *seats, *link;
137
138     g_return_if_fail (manager != NULL);
139
140     if (manager->priv->stopping)
141         return;
142
143     g_debug ("Stopping display manager");
144
145     manager->priv->stopping = TRUE;
146
147     /* Stop all the seats. Copy the list as it might be modified if a seat stops during this loop */
148     seats = g_list_copy (manager->priv->seats);
149     for (link = seats; link; link = link->next)
150     {
151         Seat *seat = link->data;
152         seat_stop (seat);
153     }
154     g_list_free (seats);
155
156     check_stopped (manager);
157 }
158
159 static void
160 display_manager_init (DisplayManager *manager)
161 {
162     manager->priv = G_TYPE_INSTANCE_GET_PRIVATE (manager, DISPLAY_MANAGER_TYPE, DisplayManagerPrivate);
163
164     /* Load the seat modules */
165     seat_register_module ("local", SEAT_LOCAL_TYPE);
166     seat_register_module ("xremote", SEAT_XREMOTE_TYPE);
167     seat_register_module ("unity", SEAT_UNITY_TYPE);
168 }
169
170 static void
171 display_manager_finalize (GObject *object)
172 {
173     DisplayManager *self = DISPLAY_MANAGER (object);
174     GList *link;
175
176     for (link = self->priv->seats; link; link = link->next)
177     {
178         Seat *seat = link->data;
179         g_signal_handlers_disconnect_matched (seat, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, self);
180     }
181     g_list_free_full (self->priv->seats, g_object_unref);
182
183     G_OBJECT_CLASS (display_manager_parent_class)->finalize (object);
184 }
185
186 static void
187 display_manager_class_init (DisplayManagerClass *klass)
188 {
189     GObjectClass *object_class = G_OBJECT_CLASS (klass);
190
191     object_class->finalize = display_manager_finalize;
192
193     g_type_class_add_private (klass, sizeof (DisplayManagerPrivate));
194
195     signals[SEAT_ADDED] =
196         g_signal_new (DISPLAY_MANAGER_SIGNAL_SEAT_ADDED,
197                       G_TYPE_FROM_CLASS (klass),
198                       G_SIGNAL_RUN_LAST,
199                       G_STRUCT_OFFSET (DisplayManagerClass, seat_added),
200                       NULL, NULL,
201                       NULL,
202                       G_TYPE_NONE, 1, SEAT_TYPE);
203     signals[SEAT_REMOVED] =
204         g_signal_new (DISPLAY_MANAGER_SIGNAL_SEAT_REMOVED,
205                       G_TYPE_FROM_CLASS (klass),
206                       G_SIGNAL_RUN_LAST,
207                       G_STRUCT_OFFSET (DisplayManagerClass, seat_removed),
208                       NULL, NULL,
209                       NULL,
210                       G_TYPE_NONE, 1, SEAT_TYPE);
211     signals[STOPPED] =
212         g_signal_new (DISPLAY_MANAGER_SIGNAL_STOPPED,
213                       G_TYPE_FROM_CLASS (klass),
214                       G_SIGNAL_RUN_LAST,
215                       G_STRUCT_OFFSET (DisplayManagerClass, stopped),
216                       NULL, NULL,
217                       NULL,
218                       G_TYPE_NONE, 0);
219 }