1 | /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- |
---|
2 | * |
---|
3 | * Copyright (C) 2007 William Jon McCann <mccann@jhu.edu> |
---|
4 | * |
---|
5 | * This program is free software; you can redistribute it and/or modify |
---|
6 | * it under the terms of the GNU General Public License as published by |
---|
7 | * the Free Software Foundation; either version 2 of the License, or |
---|
8 | * (at your option) any later version. |
---|
9 | * |
---|
10 | * This program is distributed in the hope that it will be useful, |
---|
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
13 | * GNU General Public License for more details. |
---|
14 | * |
---|
15 | * You should have received a copy of the GNU General Public License |
---|
16 | * along with this program; if not, write to the Free Software |
---|
17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
---|
18 | * |
---|
19 | */ |
---|
20 | |
---|
21 | #include "config.h" |
---|
22 | |
---|
23 | #include <stdlib.h> |
---|
24 | #include <stdio.h> |
---|
25 | #include <fcntl.h> |
---|
26 | #include <unistd.h> |
---|
27 | #include <string.h> |
---|
28 | #include <signal.h> |
---|
29 | #include <sys/stat.h> |
---|
30 | #include <sys/types.h> |
---|
31 | |
---|
32 | #include <glib.h> |
---|
33 | #include <glib/gi18n.h> |
---|
34 | #include <glib/gstdio.h> |
---|
35 | #include <glib-object.h> |
---|
36 | #define DBUS_API_SUBJECT_TO_CHANGE |
---|
37 | #include <dbus/dbus-glib.h> |
---|
38 | #include <dbus/dbus-glib-lowlevel.h> |
---|
39 | |
---|
40 | #include "gdm-common.h" |
---|
41 | |
---|
42 | #include "gdm-manager.h" |
---|
43 | #include "gdm-manager-glue.h" |
---|
44 | #include "gdm-display-store.h" |
---|
45 | #include "gdm-display-factory.h" |
---|
46 | #include "gdm-local-display-factory.h" |
---|
47 | #include "gdm-xdmcp-display-factory.h" |
---|
48 | |
---|
49 | #define GDM_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_MANAGER, GdmManagerPrivate)) |
---|
50 | |
---|
51 | #define GDM_DBUS_PATH "/org/gnome/DisplayManager" |
---|
52 | #define GDM_MANAGER_DBUS_PATH GDM_DBUS_PATH "/Manager" |
---|
53 | #define GDM_MANAGER_DBUS_NAME "org.gnome.DisplayManager.Manager" |
---|
54 | |
---|
55 | struct GdmManagerPrivate |
---|
56 | { |
---|
57 | GdmDisplayStore *display_store; |
---|
58 | GdmLocalDisplayFactory *local_factory; |
---|
59 | #ifdef HAVE_LIBXDMCP |
---|
60 | GdmXdmcpDisplayFactory *xdmcp_factory; |
---|
61 | #endif |
---|
62 | gboolean xdmcp_enabled; |
---|
63 | |
---|
64 | gboolean started; |
---|
65 | gboolean wait_for_go; |
---|
66 | gboolean no_console; |
---|
67 | |
---|
68 | DBusGProxy *bus_proxy; |
---|
69 | DBusGConnection *connection; |
---|
70 | }; |
---|
71 | |
---|
72 | enum { |
---|
73 | PROP_0, |
---|
74 | PROP_XDMCP_ENABLED |
---|
75 | }; |
---|
76 | |
---|
77 | enum { |
---|
78 | DISPLAY_ADDED, |
---|
79 | DISPLAY_REMOVED, |
---|
80 | LAST_SIGNAL |
---|
81 | }; |
---|
82 | |
---|
83 | static guint signals [LAST_SIGNAL] = { 0, }; |
---|
84 | |
---|
85 | static void gdm_manager_class_init (GdmManagerClass *klass); |
---|
86 | static void gdm_manager_init (GdmManager *manager); |
---|
87 | static void gdm_manager_finalize (GObject *object); |
---|
88 | |
---|
89 | static gpointer manager_object = NULL; |
---|
90 | |
---|
91 | G_DEFINE_TYPE (GdmManager, gdm_manager, G_TYPE_OBJECT) |
---|
92 | |
---|
93 | GQuark |
---|
94 | gdm_manager_error_quark (void) |
---|
95 | { |
---|
96 | static GQuark ret = 0; |
---|
97 | if (ret == 0) { |
---|
98 | ret = g_quark_from_static_string ("gdm_manager_error"); |
---|
99 | } |
---|
100 | |
---|
101 | return ret; |
---|
102 | } |
---|
103 | |
---|
104 | static gboolean |
---|
105 | listify_display_ids (const char *id, |
---|
106 | GdmDisplay *display, |
---|
107 | GPtrArray **array) |
---|
108 | { |
---|
109 | g_ptr_array_add (*array, g_strdup (id)); |
---|
110 | |
---|
111 | /* return FALSE to continue */ |
---|
112 | return FALSE; |
---|
113 | } |
---|
114 | |
---|
115 | /* |
---|
116 | Example: |
---|
117 | dbus-send --system --dest=org.gnome.DisplayManager \ |
---|
118 | --type=method_call --print-reply --reply-timeout=2000 \ |
---|
119 | /org/gnome/DisplayManager/Manager \ |
---|
120 | org.gnome.DisplayManager.Manager.GetDisplays |
---|
121 | */ |
---|
122 | gboolean |
---|
123 | gdm_manager_get_displays (GdmManager *manager, |
---|
124 | GPtrArray **displays, |
---|
125 | GError **error) |
---|
126 | { |
---|
127 | g_return_val_if_fail (GDM_IS_MANAGER (manager), FALSE); |
---|
128 | |
---|
129 | if (displays == NULL) { |
---|
130 | return FALSE; |
---|
131 | } |
---|
132 | |
---|
133 | *displays = g_ptr_array_new (); |
---|
134 | gdm_display_store_foreach (manager->priv->display_store, |
---|
135 | (GdmDisplayStoreFunc)listify_display_ids, |
---|
136 | displays); |
---|
137 | |
---|
138 | return TRUE; |
---|
139 | } |
---|
140 | |
---|
141 | void |
---|
142 | gdm_manager_stop (GdmManager *manager) |
---|
143 | { |
---|
144 | g_debug ("GdmManager: GDM stopping"); |
---|
145 | |
---|
146 | if (manager->priv->local_factory != NULL) { |
---|
147 | gdm_display_factory_stop (GDM_DISPLAY_FACTORY (manager->priv->local_factory)); |
---|
148 | } |
---|
149 | |
---|
150 | #ifdef HAVE_LIBXDMCP |
---|
151 | if (manager->priv->xdmcp_factory != NULL) { |
---|
152 | gdm_display_factory_stop (GDM_DISPLAY_FACTORY (manager->priv->xdmcp_factory)); |
---|
153 | } |
---|
154 | #endif |
---|
155 | |
---|
156 | manager->priv->started = FALSE; |
---|
157 | } |
---|
158 | |
---|
159 | void |
---|
160 | gdm_manager_start (GdmManager *manager) |
---|
161 | { |
---|
162 | g_debug ("GdmManager: GDM starting to manage displays"); |
---|
163 | |
---|
164 | if (! manager->priv->wait_for_go) { |
---|
165 | gdm_display_factory_start (GDM_DISPLAY_FACTORY (manager->priv->local_factory)); |
---|
166 | } |
---|
167 | |
---|
168 | #ifdef HAVE_LIBXDMCP |
---|
169 | /* Accept remote connections */ |
---|
170 | if (manager->priv->xdmcp_enabled && ! manager->priv->wait_for_go) { |
---|
171 | if (manager->priv->xdmcp_factory != NULL) { |
---|
172 | g_debug ("GdmManager: Accepting XDMCP connections..."); |
---|
173 | gdm_display_factory_start (GDM_DISPLAY_FACTORY (manager->priv->xdmcp_factory)); |
---|
174 | } |
---|
175 | } |
---|
176 | #endif |
---|
177 | |
---|
178 | manager->priv->started = TRUE; |
---|
179 | } |
---|
180 | |
---|
181 | void |
---|
182 | gdm_manager_set_wait_for_go (GdmManager *manager, |
---|
183 | gboolean wait_for_go) |
---|
184 | { |
---|
185 | if (manager->priv->wait_for_go != wait_for_go) { |
---|
186 | manager->priv->wait_for_go = wait_for_go; |
---|
187 | |
---|
188 | if (! wait_for_go) { |
---|
189 | /* we got a go */ |
---|
190 | gdm_display_factory_start (GDM_DISPLAY_FACTORY (manager->priv->local_factory)); |
---|
191 | |
---|
192 | #ifdef HAVE_LIBXDMCP |
---|
193 | if (manager->priv->xdmcp_enabled && manager->priv->xdmcp_factory != NULL) { |
---|
194 | g_debug ("GdmManager: Accepting XDMCP connections..."); |
---|
195 | gdm_display_factory_start (GDM_DISPLAY_FACTORY (manager->priv->xdmcp_factory)); |
---|
196 | } |
---|
197 | #endif |
---|
198 | } |
---|
199 | } |
---|
200 | } |
---|
201 | |
---|
202 | typedef struct { |
---|
203 | const char *service_name; |
---|
204 | GdmManager *manager; |
---|
205 | } RemoveDisplayData; |
---|
206 | |
---|
207 | static gboolean |
---|
208 | remove_display_for_connection (char *id, |
---|
209 | GdmDisplay *display, |
---|
210 | RemoveDisplayData *data) |
---|
211 | { |
---|
212 | g_assert (display != NULL); |
---|
213 | g_assert (data->service_name != NULL); |
---|
214 | |
---|
215 | /* FIXME: compare service name to that of display */ |
---|
216 | #if 0 |
---|
217 | if (strcmp (info->service_name, data->service_name) == 0) { |
---|
218 | remove_session_for_cookie (data->manager, cookie, NULL); |
---|
219 | leader_info_cancel (info); |
---|
220 | return TRUE; |
---|
221 | } |
---|
222 | #endif |
---|
223 | |
---|
224 | return FALSE; |
---|
225 | } |
---|
226 | |
---|
227 | static void |
---|
228 | remove_displays_for_connection (GdmManager *manager, |
---|
229 | const char *service_name) |
---|
230 | { |
---|
231 | RemoveDisplayData data; |
---|
232 | |
---|
233 | data.service_name = service_name; |
---|
234 | data.manager = manager; |
---|
235 | |
---|
236 | gdm_display_store_foreach_remove (manager->priv->display_store, |
---|
237 | (GdmDisplayStoreFunc)remove_display_for_connection, |
---|
238 | &data); |
---|
239 | } |
---|
240 | |
---|
241 | static void |
---|
242 | bus_name_owner_changed (DBusGProxy *bus_proxy, |
---|
243 | const char *service_name, |
---|
244 | const char *old_service_name, |
---|
245 | const char *new_service_name, |
---|
246 | GdmManager *manager) |
---|
247 | { |
---|
248 | if (strlen (new_service_name) == 0) { |
---|
249 | remove_displays_for_connection (manager, old_service_name); |
---|
250 | } |
---|
251 | } |
---|
252 | |
---|
253 | static gboolean |
---|
254 | register_manager (GdmManager *manager) |
---|
255 | { |
---|
256 | GError *error = NULL; |
---|
257 | |
---|
258 | error = NULL; |
---|
259 | manager->priv->connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error); |
---|
260 | if (manager->priv->connection == NULL) { |
---|
261 | if (error != NULL) { |
---|
262 | g_critical ("error getting system bus: %s", error->message); |
---|
263 | g_error_free (error); |
---|
264 | } |
---|
265 | exit (1); |
---|
266 | } |
---|
267 | |
---|
268 | manager->priv->bus_proxy = dbus_g_proxy_new_for_name (manager->priv->connection, |
---|
269 | DBUS_SERVICE_DBUS, |
---|
270 | DBUS_PATH_DBUS, |
---|
271 | DBUS_INTERFACE_DBUS); |
---|
272 | dbus_g_proxy_add_signal (manager->priv->bus_proxy, |
---|
273 | "NameOwnerChanged", |
---|
274 | G_TYPE_STRING, |
---|
275 | G_TYPE_STRING, |
---|
276 | G_TYPE_STRING, |
---|
277 | G_TYPE_INVALID); |
---|
278 | dbus_g_proxy_connect_signal (manager->priv->bus_proxy, |
---|
279 | "NameOwnerChanged", |
---|
280 | G_CALLBACK (bus_name_owner_changed), |
---|
281 | manager, |
---|
282 | NULL); |
---|
283 | |
---|
284 | dbus_g_connection_register_g_object (manager->priv->connection, GDM_MANAGER_DBUS_PATH, G_OBJECT (manager)); |
---|
285 | |
---|
286 | return TRUE; |
---|
287 | } |
---|
288 | |
---|
289 | void |
---|
290 | gdm_manager_set_xdmcp_enabled (GdmManager *manager, |
---|
291 | gboolean enabled) |
---|
292 | { |
---|
293 | g_return_if_fail (GDM_IS_MANAGER (manager)); |
---|
294 | |
---|
295 | if (manager->priv->xdmcp_enabled != enabled) { |
---|
296 | manager->priv->xdmcp_enabled = enabled; |
---|
297 | |
---|
298 | if (manager->priv->xdmcp_enabled) { |
---|
299 | manager->priv->xdmcp_factory = gdm_xdmcp_display_factory_new (manager->priv->display_store); |
---|
300 | if (manager->priv->started) { |
---|
301 | gdm_display_factory_start (GDM_DISPLAY_FACTORY (manager->priv->xdmcp_factory)); |
---|
302 | } |
---|
303 | } else { |
---|
304 | if (manager->priv->started) { |
---|
305 | gdm_display_factory_stop (GDM_DISPLAY_FACTORY (manager->priv->xdmcp_factory)); |
---|
306 | } |
---|
307 | |
---|
308 | g_object_unref (manager->priv->xdmcp_factory); |
---|
309 | manager->priv->xdmcp_factory = NULL; |
---|
310 | } |
---|
311 | } |
---|
312 | |
---|
313 | } |
---|
314 | |
---|
315 | static void |
---|
316 | gdm_manager_set_property (GObject *object, |
---|
317 | guint prop_id, |
---|
318 | const GValue *value, |
---|
319 | GParamSpec *pspec) |
---|
320 | { |
---|
321 | GdmManager *self; |
---|
322 | |
---|
323 | self = GDM_MANAGER (object); |
---|
324 | |
---|
325 | switch (prop_id) { |
---|
326 | case PROP_XDMCP_ENABLED: |
---|
327 | gdm_manager_set_xdmcp_enabled (self, g_value_get_boolean (value)); |
---|
328 | break; |
---|
329 | default: |
---|
330 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
---|
331 | break; |
---|
332 | } |
---|
333 | } |
---|
334 | |
---|
335 | static void |
---|
336 | gdm_manager_get_property (GObject *object, |
---|
337 | guint prop_id, |
---|
338 | GValue *value, |
---|
339 | GParamSpec *pspec) |
---|
340 | { |
---|
341 | GdmManager *self; |
---|
342 | |
---|
343 | self = GDM_MANAGER (object); |
---|
344 | |
---|
345 | switch (prop_id) { |
---|
346 | case PROP_XDMCP_ENABLED: |
---|
347 | g_value_set_boolean (value, self->priv->xdmcp_enabled); |
---|
348 | break; |
---|
349 | default: |
---|
350 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
---|
351 | break; |
---|
352 | } |
---|
353 | } |
---|
354 | |
---|
355 | static GObject * |
---|
356 | gdm_manager_constructor (GType type, |
---|
357 | guint n_construct_properties, |
---|
358 | GObjectConstructParam *construct_properties) |
---|
359 | { |
---|
360 | GdmManager *manager; |
---|
361 | |
---|
362 | manager = GDM_MANAGER (G_OBJECT_CLASS (gdm_manager_parent_class)->constructor (type, |
---|
363 | n_construct_properties, |
---|
364 | construct_properties)); |
---|
365 | |
---|
366 | manager->priv->local_factory = gdm_local_display_factory_new (manager->priv->display_store); |
---|
367 | |
---|
368 | #ifdef HAVE_LIBXDMCP |
---|
369 | if (manager->priv->xdmcp_enabled) { |
---|
370 | manager->priv->xdmcp_factory = gdm_xdmcp_display_factory_new (manager->priv->display_store); |
---|
371 | } |
---|
372 | #endif |
---|
373 | |
---|
374 | return G_OBJECT (manager); |
---|
375 | } |
---|
376 | |
---|
377 | static void |
---|
378 | gdm_manager_class_init (GdmManagerClass *klass) |
---|
379 | { |
---|
380 | GObjectClass *object_class = G_OBJECT_CLASS (klass); |
---|
381 | |
---|
382 | object_class->get_property = gdm_manager_get_property; |
---|
383 | object_class->set_property = gdm_manager_set_property; |
---|
384 | object_class->constructor = gdm_manager_constructor; |
---|
385 | object_class->finalize = gdm_manager_finalize; |
---|
386 | |
---|
387 | signals [DISPLAY_ADDED] = |
---|
388 | g_signal_new ("display-added", |
---|
389 | G_TYPE_FROM_CLASS (object_class), |
---|
390 | G_SIGNAL_RUN_LAST, |
---|
391 | G_STRUCT_OFFSET (GdmManagerClass, display_added), |
---|
392 | NULL, |
---|
393 | NULL, |
---|
394 | g_cclosure_marshal_VOID__STRING, |
---|
395 | G_TYPE_NONE, |
---|
396 | 1, G_TYPE_STRING); |
---|
397 | signals [DISPLAY_REMOVED] = |
---|
398 | g_signal_new ("display-removed", |
---|
399 | G_TYPE_FROM_CLASS (object_class), |
---|
400 | G_SIGNAL_RUN_LAST, |
---|
401 | G_STRUCT_OFFSET (GdmManagerClass, display_removed), |
---|
402 | NULL, |
---|
403 | NULL, |
---|
404 | g_cclosure_marshal_VOID__STRING, |
---|
405 | G_TYPE_NONE, |
---|
406 | 1, G_TYPE_STRING); |
---|
407 | |
---|
408 | g_object_class_install_property (object_class, |
---|
409 | PROP_XDMCP_ENABLED, |
---|
410 | g_param_spec_boolean ("xdmcp-enabled", |
---|
411 | NULL, |
---|
412 | NULL, |
---|
413 | FALSE, |
---|
414 | G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); |
---|
415 | |
---|
416 | g_type_class_add_private (klass, sizeof (GdmManagerPrivate)); |
---|
417 | |
---|
418 | dbus_g_object_type_install_info (GDM_TYPE_MANAGER, &dbus_glib_gdm_manager_object_info); |
---|
419 | } |
---|
420 | |
---|
421 | static void |
---|
422 | gdm_manager_init (GdmManager *manager) |
---|
423 | { |
---|
424 | |
---|
425 | manager->priv = GDM_MANAGER_GET_PRIVATE (manager); |
---|
426 | |
---|
427 | manager->priv->display_store = gdm_display_store_new (); |
---|
428 | } |
---|
429 | |
---|
430 | static void |
---|
431 | gdm_manager_finalize (GObject *object) |
---|
432 | { |
---|
433 | GdmManager *manager; |
---|
434 | |
---|
435 | g_return_if_fail (object != NULL); |
---|
436 | g_return_if_fail (GDM_IS_MANAGER (object)); |
---|
437 | |
---|
438 | manager = GDM_MANAGER (object); |
---|
439 | |
---|
440 | g_return_if_fail (manager->priv != NULL); |
---|
441 | |
---|
442 | #ifdef HAVE_LIBXDMCP |
---|
443 | if (manager->priv->xdmcp_factory != NULL) { |
---|
444 | g_object_unref (manager->priv->xdmcp_factory); |
---|
445 | } |
---|
446 | #endif |
---|
447 | |
---|
448 | gdm_display_store_clear (manager->priv->display_store); |
---|
449 | g_object_unref (manager->priv->display_store); |
---|
450 | |
---|
451 | G_OBJECT_CLASS (gdm_manager_parent_class)->finalize (object); |
---|
452 | } |
---|
453 | |
---|
454 | GdmManager * |
---|
455 | gdm_manager_new (void) |
---|
456 | { |
---|
457 | if (manager_object != NULL) { |
---|
458 | g_object_ref (manager_object); |
---|
459 | } else { |
---|
460 | gboolean res; |
---|
461 | |
---|
462 | manager_object = g_object_new (GDM_TYPE_MANAGER, NULL); |
---|
463 | g_object_add_weak_pointer (manager_object, |
---|
464 | (gpointer *) &manager_object); |
---|
465 | res = register_manager (manager_object); |
---|
466 | if (! res) { |
---|
467 | g_object_unref (manager_object); |
---|
468 | return NULL; |
---|
469 | } |
---|
470 | } |
---|
471 | |
---|
472 | return GDM_MANAGER (manager_object); |
---|
473 | } |
---|