gdm-manager.c 28.6 KB
Newer Older
1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
 *
 * Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
17
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
 *
 */

#include "config.h"

#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <sys/stat.h>
#include <sys/types.h>

#include <glib.h>
#include <glib/gi18n.h>
34
#include <glib/gstdio.h>
35 36
#include <glib-object.h>

37 38 39 40
#ifdef WITH_SYSTEMD
#include <systemd/sd-login.h>
#endif

41 42
#include "gdm-common.h"

43
#include "gdm-dbus-util.h"
44
#include "gdm-manager.h"
45
#include "gdm-manager-glue.h"
46
#include "gdm-display-store.h"
47
#include "gdm-display-factory.h"
48
#include "gdm-local-display-factory.h"
49
#include "gdm-xdmcp-display-factory.h"
50 51 52

#define GDM_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_MANAGER, GdmManagerPrivate))

53 54 55
#define GDM_DBUS_PATH             "/org/gnome/DisplayManager"
#define GDM_MANAGER_PATH          GDM_DBUS_PATH "/Manager"
#define GDM_MANAGER_DISPLAYS_PATH GDM_DBUS_PATH "/Displays"
56 57 58

struct GdmManagerPrivate
{
59 60
        GdmDisplayStore        *display_store;
        GdmLocalDisplayFactory *local_factory;
61
#ifdef HAVE_LIBXDMCP
62
        GdmXdmcpDisplayFactory *xdmcp_factory;
63
#endif
64
        gboolean                xdmcp_enabled;
65

66
        gboolean                started;
67
        gboolean                wait_for_go;
68
        gboolean                show_local_greeter;
69

70 71 72
        GDBusProxy               *bus_proxy;
        GDBusConnection          *connection;
        GDBusObjectManagerServer *object_manager;
73 74
};

75
enum {
76
        PROP_0,
77 78
        PROP_XDMCP_ENABLED,
        PROP_SHOW_LOCAL_GREETER
79 80
};

81
enum {
82 83 84
        DISPLAY_ADDED,
        DISPLAY_REMOVED,
        LAST_SIGNAL
85 86 87 88
};

static guint signals [LAST_SIGNAL] = { 0, };

89 90 91
static void     gdm_manager_class_init  (GdmManagerClass *klass);
static void     gdm_manager_init        (GdmManager      *manager);
static void     gdm_manager_finalize    (GObject         *object);
92 93 94

static gpointer manager_object = NULL;

95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
static void manager_interface_init (GdmDBusManagerIface *interface);

G_DEFINE_TYPE_WITH_CODE (GdmManager,
                         gdm_manager,
                         GDM_DBUS_TYPE_MANAGER_SKELETON,
                         G_IMPLEMENT_INTERFACE (GDM_DBUS_TYPE_MANAGER,
                                                manager_interface_init));

#ifdef WITH_SYSTEMD
static char *
get_session_id_for_pid_systemd (pid_t    pid,
                                GError **error)
{
        char *session, *gsession;
        int ret;

        session = NULL;
        ret = sd_pid_get_session (pid, &session);
        if (ret < 0) {
                g_set_error (error,
                             GDM_DISPLAY_ERROR,
                             GDM_DISPLAY_ERROR_GETTING_SESSION_INFO,
                             "Error getting session id from systemd: %s",
                             g_strerror (-ret));
                return NULL;
        }

        if (session != NULL) {
                gsession = g_strdup (session);
                free (session);

                return gsession;
        } else {
                return NULL;
        }
}
#endif

#ifdef WITH_CONSOLE_KIT
static char *
get_session_id_for_pid_consolekit (GDBusConnection  *connection,
                                   pid_t             pid,
                                   GError          **error)
{
        GVariant *reply;
        char *retval;

        reply = g_dbus_connection_call_sync (connection,
                                             "org.freedesktop.ConsoleKit",
                                             "/org/freedesktop/ConsoleKit/Manager",
                                             "org.freedesktop.ConsoleKit.Manager",
                                             "GetSessionForUnixProcess",
                                             g_variant_new ("(u)", pid),
                                             G_VARIANT_TYPE ("(o)"),
                                             G_DBUS_CALL_FLAGS_NONE,
                                             -1,
                                             NULL, error);
        if (reply == NULL) {
                return NULL;
        }

        g_variant_get (reply, "(o)", &retval);
        g_variant_unref (reply);

        return retval;
}
#endif

static char *
get_session_id_for_pid (GDBusConnection  *connection,
                        pid_t             pid,
                        GError          **error)
{
#ifdef WITH_SYSTEMD
Martin Pitt's avatar
Martin Pitt committed
169
        if (LOGIND_RUNNING()) {
170 171 172 173 174 175 176 177 178 179 180
                return get_session_id_for_pid_systemd (pid, error);
        }
#endif

#ifdef WITH_CONSOLE_KIT
        return get_session_id_for_pid_consolekit (connection, pid, error);
#endif

        return NULL;
}

181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244
#ifdef WITH_SYSTEMD
static gboolean
get_uid_for_systemd_session_id (const char  *session_id,
                                uid_t       *uid,
                                GError     **error)
{
        int ret;

        ret = sd_session_get_uid (session_id, uid);
        if (ret < 0) {
                g_set_error (error,
                             GDM_DISPLAY_ERROR,
                             GDM_DISPLAY_ERROR_GETTING_SESSION_INFO,
                             "Error getting uid for session id %s from systemd: %s",
                             session_id,
                             g_strerror (-ret));
                return FALSE;
        }

        return TRUE;
}
#endif

#ifdef WITH_CONSOLE_KIT
static gboolean
get_uid_for_consolekit_session_id (GDBusConnection  *connection,
                                   const char       *session_id,
                                   uid_t            *out_uid,
                                   GError          **error)
{
        GVariant *reply;
        guint32 uid;

        reply = g_dbus_connection_call_sync (connection,
                                             "org.freedesktop.ConsoleKit",
                                             session_id,
                                             "org.freedesktop.ConsoleKit.Session",
                                             "GetUnixUser",
                                             NULL,
                                             G_VARIANT_TYPE ("(u)"),
                                             G_DBUS_CALL_FLAGS_NONE,
                                             -1,
                                             NULL,
                                             error);
        if (reply == NULL) {
                return FALSE;
        }

        g_variant_get (reply, "(u)", &uid);
        g_variant_unref (reply);

        *out_uid = (uid_t) uid;

        return TRUE;
}
#endif

static gboolean
get_uid_for_session_id (GDBusConnection  *connection,
                        const char       *session_id,
                        uid_t            *uid,
                        GError          **error)
{
#ifdef WITH_SYSTEMD
Martin Pitt's avatar
Martin Pitt committed
245
        if (LOGIND_RUNNING()) {
246 247 248 249 250 251 252 253 254 255 256
                return get_uid_for_systemd_session_id (session_id, uid, error);
        }
#endif

#ifdef WITH_CONSOLE_KIT
        return get_uid_for_consolekit_session_id (connection, session_id, uid, error);
#endif

        return FALSE;
}

257 258 259 260 261 262
static gboolean
lookup_by_session_id (const char *id,
                      GdmDisplay *display,
                      gpointer    user_data)
{
        const char *looking_for = user_data;
263
        const char *current;
264 265

        current = gdm_display_get_session_id (display);
266
        return g_strcmp0 (current, looking_for) == 0;
267 268
}

269 270
static GdmDisplay *
get_display_and_details_for_bus_sender (GdmManager       *self,
271 272 273 274
                                        GDBusConnection  *connection,
                                        const char       *sender,
                                        GPid             *out_pid,
                                        uid_t            *out_uid)
275
{
276 277 278 279 280 281
        GdmDisplay *display = NULL;
        char       *session_id = NULL;
        GError     *error = NULL;
        int         ret;
        GPid        pid;
        uid_t       caller_uid, session_uid;
282

283
        ret = gdm_dbus_get_pid_for_name (sender, &pid, &error);
284

285 286 287 288 289
        if (!ret) {
                g_debug ("GdmManager: Error while retrieving pid for sender: %s",
                         error->message);
                g_error_free (error);
                goto out;
290 291
        }

292
        ret = gdm_dbus_get_uid_for_name (sender, &caller_uid, &error);
293

294 295 296 297 298
        if (!ret) {
                g_debug ("GdmManager: Error while retrieving uid for sender: %s",
                         error->message);
                g_error_free (error);
                goto out;
299 300
        }

301
        session_id = get_session_id_for_pid (connection, pid, &error);
302

303 304 305 306 307
        if (session_id == NULL) {
                g_debug ("GdmManager: Error while retrieving session id for sender: %s",
                         error->message);
                g_error_free (error);
                goto out;
308 309
        }

310 311 312 313 314
        if (!get_uid_for_session_id (connection, session_id, &session_uid, &error)) {
                g_debug ("GdmManager: Error while retrieving uid for session: %s",
                         error->message);
                g_error_free (error);
                goto out;
315 316
        }

317 318 319
        if (caller_uid != session_uid) {
                g_debug ("GdmManager: uid for sender and uid for session don't match");
                goto out;
320 321
        }

322 323 324 325 326
        display = gdm_display_store_find (self->priv->display_store,
                                          lookup_by_session_id,
                                          (gpointer) session_id);
out:
        g_free (session_id);
327

328
        if (display != NULL) {
329 330
                if (out_pid != NULL)
                        *out_pid = pid;
331

332 333
                if (out_uid != NULL)
                        *out_uid = session_uid;
334
        }
335
        return display;
336 337
}

338 339 340 341 342
static gboolean
gdm_manager_handle_open_session (GdmDBusManager        *manager,
                                 GDBusMethodInvocation *invocation)
{
        GdmManager       *self = GDM_MANAGER (manager);
343 344
        const char       *sender = NULL;
        GError           *error = NULL;
345 346 347 348
        GDBusConnection  *connection;
        GdmDisplay       *display;
        char             *address;
        GPid              pid;
349
        uid_t             uid;
350

351
        g_debug ("GdmManager: trying to open new session");
352

353
        sender = g_dbus_method_invocation_get_sender (invocation);
354
        connection = g_dbus_method_invocation_get_connection (invocation);
355
        display = get_display_and_details_for_bus_sender (self, connection, sender, &pid, &uid);
356 357 358 359 360 361 362 363 364 365

        if (display == NULL) {
                g_dbus_method_invocation_return_error_literal (invocation,
                                                               G_DBUS_ERROR,
                                                               G_DBUS_ERROR_ACCESS_DENIED,
                                                               _("No session available"));

                return TRUE;
        }

366
        address = gdm_display_open_session_sync (display, pid, uid, NULL, &error);
367 368 369 370 371 372 373 374 375 376 377 378 379 380 381

        if (address == NULL) {
                g_dbus_method_invocation_return_gerror (invocation, error);
                g_error_free (error);
                return TRUE;
        }

        gdm_dbus_manager_complete_open_session (GDM_DBUS_MANAGER (manager),
                                                invocation,
                                                address);
        g_free (address);

        return TRUE;
}

382 383 384 385 386 387
static gboolean
gdm_manager_handle_open_reauthentication_channel (GdmDBusManager        *manager,
                                                  GDBusMethodInvocation *invocation,
                                                  const char            *username)
{
        GdmManager       *self = GDM_MANAGER (manager);
388 389
        const char       *sender = NULL;
        GError           *error = NULL;
390 391 392 393
        GDBusConnection  *connection;
        GdmDisplay       *display;
        char             *address;
        GPid              pid;
394
        uid_t             uid;
395 396 397 398 399

        g_debug ("GdmManager: trying to open reauthentication channel for user %s", username);

        sender = g_dbus_method_invocation_get_sender (invocation);
        connection = g_dbus_method_invocation_get_connection (invocation);
400
        display = get_display_and_details_for_bus_sender (self, connection, sender, &pid, &uid);
401 402 403 404 405 406 407 408 409 410 411 412 413

        if (display == NULL) {
                g_dbus_method_invocation_return_error_literal (invocation,
                                                               G_DBUS_ERROR,
                                                               G_DBUS_ERROR_ACCESS_DENIED,
                                                               _("No session available"));

                return TRUE;
        }

        address = gdm_display_open_reauthentication_channel_sync (display,
                                                                  username,
                                                                  pid,
414
                                                                  uid,
415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431
                                                                  NULL,
                                                                  &error);

        if (address == NULL) {
                g_dbus_method_invocation_return_gerror (invocation, error);
                g_error_free (error);
                return TRUE;
        }

        gdm_dbus_manager_complete_open_reauthentication_channel (GDM_DBUS_MANAGER (manager),
                                                                 invocation,
                                                                 address);
        g_free (address);

        return TRUE;
}

432 433 434 435
static void
manager_interface_init (GdmDBusManagerIface *interface)
{
        interface->handle_open_session = gdm_manager_handle_open_session;
436
        interface->handle_open_reauthentication_channel = gdm_manager_handle_open_reauthentication_channel;
437
}
438

439 440 441 442 443 444 445 446 447 448
static void
on_display_removed (GdmDisplayStore *display_store,
                    const char      *id,
                    GdmManager      *manager)
{
        GdmDisplay *display;

        display = gdm_display_store_lookup (display_store, id);

        if (display != NULL) {
449 450
                g_dbus_object_manager_server_unexport (manager->priv->object_manager, id);

451 452 453 454 455 456 457 458 459 460 461 462 463 464
                g_signal_emit (manager, signals[DISPLAY_REMOVED], 0, id);
        }
}

static void
on_display_added (GdmDisplayStore *display_store,
                  const char      *id,
                  GdmManager      *manager)
{
        GdmDisplay *display;

        display = gdm_display_store_lookup (display_store, id);

        if (display != NULL) {
465 466
                g_dbus_object_manager_server_export (manager->priv->object_manager,
                                                     gdm_display_get_object_skeleton (display));
467 468 469 470
                g_signal_emit (manager, signals[DISPLAY_ADDED], 0, id);
        }
}

471 472 473
GQuark
gdm_manager_error_quark (void)
{
474 475 476 477
        static GQuark ret = 0;
        if (ret == 0) {
                ret = g_quark_from_static_string ("gdm_manager_error");
        }
478

479
        return ret;
480 481 482 483
}

static gboolean
listify_display_ids (const char *id,
484 485
                     GdmDisplay *display,
                     GPtrArray **array)
486
{
487
        g_ptr_array_add (*array, g_strdup (id));
488

489 490
        /* return FALSE to continue */
        return FALSE;
491 492 493 494 495 496
}

/*
  Example:
  dbus-send --system --dest=org.gnome.DisplayManager \
  --type=method_call --print-reply --reply-timeout=2000 \
497 498
  /org/gnome/DisplayManager/Displays \
  org.freedesktop.ObjectManager.GetAll
499 500 501
*/
gboolean
gdm_manager_get_displays (GdmManager *manager,
502 503
                          GPtrArray **displays,
                          GError    **error)
504
{
505
        g_return_val_if_fail (GDM_IS_MANAGER (manager), FALSE);
506

507 508 509
        if (displays == NULL) {
                return FALSE;
        }
510

511 512 513 514
        *displays = g_ptr_array_new ();
        gdm_display_store_foreach (manager->priv->display_store,
                                   (GdmDisplayStoreFunc)listify_display_ids,
                                   displays);
515

516
        return TRUE;
517 518
}

519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536
void
gdm_manager_stop (GdmManager *manager)
{
        g_debug ("GdmManager: GDM stopping");

        if (manager->priv->local_factory != NULL) {
                gdm_display_factory_stop (GDM_DISPLAY_FACTORY (manager->priv->local_factory));
        }

#ifdef HAVE_LIBXDMCP
        if (manager->priv->xdmcp_factory != NULL) {
                gdm_display_factory_stop (GDM_DISPLAY_FACTORY (manager->priv->xdmcp_factory));
        }
#endif

        manager->priv->started = FALSE;
}

537 538 539
void
gdm_manager_start (GdmManager *manager)
{
540
        g_debug ("GdmManager: GDM starting to manage displays");
541

542
        if (! manager->priv->wait_for_go && (!manager->priv->xdmcp_enabled || manager->priv->show_local_greeter)) {
543 544
                gdm_display_factory_start (GDM_DISPLAY_FACTORY (manager->priv->local_factory));
        }
545

546
#ifdef HAVE_LIBXDMCP
547 548 549
        /* Accept remote connections */
        if (manager->priv->xdmcp_enabled && ! manager->priv->wait_for_go) {
                if (manager->priv->xdmcp_factory != NULL) {
550
                        g_debug ("GdmManager: Accepting XDMCP connections...");
551 552 553
                        gdm_display_factory_start (GDM_DISPLAY_FACTORY (manager->priv->xdmcp_factory));
                }
        }
554
#endif
555 556

        manager->priv->started = TRUE;
557 558 559 560
}

void
gdm_manager_set_wait_for_go (GdmManager *manager,
561
                             gboolean    wait_for_go)
562
{
563 564 565 566 567
        if (manager->priv->wait_for_go != wait_for_go) {
                manager->priv->wait_for_go = wait_for_go;

                if (! wait_for_go) {
                        /* we got a go */
568 569 570
                        if (!manager->priv->xdmcp_enabled || manager->priv->show_local_greeter) {
                                gdm_display_factory_start (GDM_DISPLAY_FACTORY (manager->priv->local_factory));
                        }
571

572
#ifdef HAVE_LIBXDMCP
573
                        if (manager->priv->xdmcp_enabled && manager->priv->xdmcp_factory != NULL) {
574
                                g_debug ("GdmManager: Accepting XDMCP connections...");
575 576
                                gdm_display_factory_start (GDM_DISPLAY_FACTORY (manager->priv->xdmcp_factory));
                        }
577
#endif
578 579
                }
        }
580 581 582 583 584 585
}

static gboolean
register_manager (GdmManager *manager)
{
        GError *error = NULL;
586
        GDBusObjectManagerServer *object_server;
587 588

        error = NULL;
589 590 591
        manager->priv->connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM,
                                                    NULL,
                                                    &error);
592
        if (manager->priv->connection == NULL) {
593 594
                g_critical ("error getting system bus: %s", error->message);
                g_error_free (error);
595 596 597
                exit (1);
        }

598
        object_server = g_dbus_object_manager_server_new (GDM_MANAGER_DISPLAYS_PATH);
599 600
        g_dbus_object_manager_server_set_connection (object_server, manager->priv->connection);
        manager->priv->object_manager = object_server;
601

602 603 604 605 606 607 608 609 610 611 612
        if (!g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (manager),
                                               manager->priv->connection,
                                               GDM_MANAGER_PATH,
                                               &error)) {
                g_critical ("error exporting interface to %s: %s",
                            GDM_MANAGER_PATH,
                            error->message);
                g_error_free (error);
                exit (1);
        }

613 614 615
        return TRUE;
}

616 617
void
gdm_manager_set_xdmcp_enabled (GdmManager *manager,
618
                               gboolean    enabled)
619
{
620
        g_return_if_fail (GDM_IS_MANAGER (manager));
621

622 623
        if (manager->priv->xdmcp_enabled != enabled) {
                manager->priv->xdmcp_enabled = enabled;
624
#ifdef HAVE_LIBXDMCP
625 626 627 628 629 630 631 632 633 634 635 636 637
                if (manager->priv->xdmcp_enabled) {
                        manager->priv->xdmcp_factory = gdm_xdmcp_display_factory_new (manager->priv->display_store);
                        if (manager->priv->started) {
                                gdm_display_factory_start (GDM_DISPLAY_FACTORY (manager->priv->xdmcp_factory));
                        }
                } else {
                        if (manager->priv->started) {
                                gdm_display_factory_stop (GDM_DISPLAY_FACTORY (manager->priv->xdmcp_factory));
                        }

                        g_object_unref (manager->priv->xdmcp_factory);
                        manager->priv->xdmcp_factory = NULL;
                }
638
#endif
639 640
        }

641 642
}

643 644 645 646 647 648 649 650 651
void
gdm_manager_set_show_local_greeter (GdmManager *manager,
                                    gboolean    show_local_greeter)
{
        g_return_if_fail (GDM_IS_MANAGER (manager));

        manager->priv->show_local_greeter = show_local_greeter;
}

652 653
static void
gdm_manager_set_property (GObject      *object,
654 655 656
                          guint         prop_id,
                          const GValue  *value,
                          GParamSpec    *pspec)
657
{
658 659 660 661 662 663 664 665
        GdmManager *self;

        self = GDM_MANAGER (object);

        switch (prop_id) {
        case PROP_XDMCP_ENABLED:
                gdm_manager_set_xdmcp_enabled (self, g_value_get_boolean (value));
                break;
666 667 668
        case PROP_SHOW_LOCAL_GREETER:
                gdm_manager_set_show_local_greeter (self, g_value_get_boolean (value));
                break;
669 670 671 672
        default:
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
                break;
        }
673 674 675 676
}

static void
gdm_manager_get_property (GObject    *object,
677 678 679
                          guint       prop_id,
                          GValue     *value,
                          GParamSpec *pspec)
680
{
681 682 683 684 685 686 687 688
        GdmManager *self;

        self = GDM_MANAGER (object);

        switch (prop_id) {
        case PROP_XDMCP_ENABLED:
                g_value_set_boolean (value, self->priv->xdmcp_enabled);
                break;
689 690 691
        case PROP_SHOW_LOCAL_GREETER:
                g_value_set_boolean (value, self->priv->show_local_greeter);
                break;
692 693 694 695
        default:
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
                break;
        }
696 697
}

698 699
static GObject *
gdm_manager_constructor (GType                  type,
700 701
                         guint                  n_construct_properties,
                         GObjectConstructParam *construct_properties)
702 703 704 705
{
        GdmManager      *manager;

        manager = GDM_MANAGER (G_OBJECT_CLASS (gdm_manager_parent_class)->constructor (type,
706 707
                                                                                       n_construct_properties,
                                                                                       construct_properties));
708

709 710
        gdm_dbus_manager_set_version (GDM_DBUS_MANAGER (manager), PACKAGE_VERSION);

711
        manager->priv->local_factory = gdm_local_display_factory_new (manager->priv->display_store);
712

713
#ifdef HAVE_LIBXDMCP
714 715 716
        if (manager->priv->xdmcp_enabled) {
                manager->priv->xdmcp_factory = gdm_xdmcp_display_factory_new (manager->priv->display_store);
        }
717
#endif
718 719 720 721

        return G_OBJECT (manager);
}

722 723 724
static void
gdm_manager_class_init (GdmManagerClass *klass)
{
725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751
        GObjectClass   *object_class = G_OBJECT_CLASS (klass);

        object_class->get_property = gdm_manager_get_property;
        object_class->set_property = gdm_manager_set_property;
        object_class->constructor = gdm_manager_constructor;
        object_class->finalize = gdm_manager_finalize;

        signals [DISPLAY_ADDED] =
                g_signal_new ("display-added",
                              G_TYPE_FROM_CLASS (object_class),
                              G_SIGNAL_RUN_LAST,
                              G_STRUCT_OFFSET (GdmManagerClass, display_added),
                              NULL,
                              NULL,
                              g_cclosure_marshal_VOID__STRING,
                              G_TYPE_NONE,
                              1, G_TYPE_STRING);
        signals [DISPLAY_REMOVED] =
                g_signal_new ("display-removed",
                              G_TYPE_FROM_CLASS (object_class),
                              G_SIGNAL_RUN_LAST,
                              G_STRUCT_OFFSET (GdmManagerClass, display_removed),
                              NULL,
                              NULL,
                              g_cclosure_marshal_VOID__STRING,
                              G_TYPE_NONE,
                              1, G_TYPE_STRING);
752

753 754 755 756 757
        g_object_class_install_property (object_class,
                                         PROP_XDMCP_ENABLED,
                                         g_param_spec_boolean ("xdmcp-enabled",
                                                               NULL,
                                                               NULL,
758
                                                               FALSE,
759 760
                                                               G_PARAM_READWRITE | G_PARAM_CONSTRUCT));

761
        g_type_class_add_private (klass, sizeof (GdmManagerPrivate));
762 763 764 765 766 767
}

static void
gdm_manager_init (GdmManager *manager)
{

768
        manager->priv = GDM_MANAGER_GET_PRIVATE (manager);
769

770
        manager->priv->display_store = gdm_display_store_new ();
771 772 773 774 775 776 777 778 779 780

        g_signal_connect (G_OBJECT (manager->priv->display_store),
                          "display-added",
                          G_CALLBACK (on_display_added),
                          manager);

        g_signal_connect (G_OBJECT (manager->priv->display_store),
                          "display-removed",
                          G_CALLBACK (on_display_removed),
                          manager);
781 782
}

783 784 785 786 787
static void
unexport_display (const char *id,
                  GdmDisplay *display,
                  GdmManager *manager)
{
788 789
        if (!g_dbus_connection_is_closed (manager->priv->connection))
                g_dbus_object_manager_server_unexport (manager->priv->object_manager, id);
790 791
}

792 793 794
static void
gdm_manager_finalize (GObject *object)
{
795
        GdmManager *manager;
796

797 798
        g_return_if_fail (object != NULL);
        g_return_if_fail (GDM_IS_MANAGER (object));
799

800
        manager = GDM_MANAGER (object);
801

802
        g_return_if_fail (manager->priv != NULL);
803

804
#ifdef HAVE_LIBXDMCP
805
        g_clear_object (&manager->priv->xdmcp_factory);
806
#endif
807
        g_clear_object (&manager->priv->local_factory);
808 809 810 811 812 813 814

        g_signal_handlers_disconnect_by_func (G_OBJECT (manager->priv->display_store),
                                              G_CALLBACK (on_display_added),
                                              manager);
        g_signal_handlers_disconnect_by_func (G_OBJECT (manager->priv->display_store),
                                              G_CALLBACK (on_display_removed),
                                              manager);
815

816 817 818 819 820 821
        if (!g_dbus_connection_is_closed (manager->priv->connection)) {
                gdm_display_store_foreach (manager->priv->display_store,
                                           (GdmDisplayStoreFunc)unexport_display,
                                           manager);
                g_dbus_interface_skeleton_unexport (G_DBUS_INTERFACE_SKELETON (manager));
        }
822

823
        gdm_display_store_clear (manager->priv->display_store);
824

825 826 827 828 829
        g_dbus_object_manager_server_set_connection (manager->priv->object_manager, NULL);

        g_clear_object (&manager->priv->connection);
        g_clear_object (&manager->priv->object_manager);

830
        g_object_unref (manager->priv->display_store);
831

832
        G_OBJECT_CLASS (gdm_manager_parent_class)->finalize (object);
833 834 835 836 837
}

GdmManager *
gdm_manager_new (void)
{
838 839 840 841 842 843 844 845
        if (manager_object != NULL) {
                g_object_ref (manager_object);
        } else {
                gboolean res;

                manager_object = g_object_new (GDM_TYPE_MANAGER, NULL);
                g_object_add_weak_pointer (manager_object,
                                           (gpointer *) &manager_object);
846 847 848 849 850
                res = register_manager (manager_object);
                if (! res) {
                        g_object_unref (manager_object);
                        return NULL;
                }
851
        }
852

853
        return GDM_MANAGER (manager_object);
854
}