source: proiecte/PPPP/gdm/daemon/gdm-local-display-factory.c @ 134

Last change on this file since 134 was 134, checked in by (none), 14 years ago

gdm sources with the modifications for webcam

File size: 20.2 KB
Line 
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
26#include <glib.h>
27#include <glib/gi18n.h>
28#include <glib-object.h>
29
30#include "gdm-display-factory.h"
31#include "gdm-local-display-factory.h"
32#include "gdm-local-display-factory-glue.h"
33
34#include "gdm-display-store.h"
35#include "gdm-static-display.h"
36#include "gdm-transient-display.h"
37#include "gdm-static-factory-display.h"
38#include "gdm-product-display.h"
39
40#define GDM_LOCAL_DISPLAY_FACTORY_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_LOCAL_DISPLAY_FACTORY, GdmLocalDisplayFactoryPrivate))
41
42#define CK_SEAT1_PATH                       "/org/freedesktop/ConsoleKit/Seat1"
43
44#define GDM_DBUS_PATH                       "/org/gnome/DisplayManager"
45#define GDM_LOCAL_DISPLAY_FACTORY_DBUS_PATH GDM_DBUS_PATH "/LocalDisplayFactory"
46#define GDM_MANAGER_DBUS_NAME               "org.gnome.DisplayManager.LocalDisplayFactory"
47
48#define HAL_DBUS_NAME                           "org.freedesktop.Hal"
49#define HAL_DBUS_MANAGER_PATH                   "/org/freedesktop/Hal/Manager"
50#define HAL_DBUS_MANAGER_INTERFACE              "org.freedesktop.Hal.Manager"
51#define HAL_DBUS_DEVICE_INTERFACE               "org.freedesktop.Hal.Device"
52#define SEAT_PCI_DEVICE_CLASS                   3
53
54#define MAX_DISPLAY_FAILURES 5
55
56struct GdmLocalDisplayFactoryPrivate
57{
58        DBusGConnection *connection;
59        DBusGProxy      *proxy;
60        GHashTable      *displays;
61
62        /* FIXME: this needs to be per seat? */
63        guint            num_failures;
64};
65
66enum {
67        PROP_0,
68};
69
70static void     gdm_local_display_factory_class_init    (GdmLocalDisplayFactoryClass *klass);
71static void     gdm_local_display_factory_init          (GdmLocalDisplayFactory      *factory);
72static void     gdm_local_display_factory_finalize      (GObject                     *object);
73
74static GdmDisplay *create_display                       (GdmLocalDisplayFactory      *factory);
75
76static gpointer local_display_factory_object = NULL;
77
78G_DEFINE_TYPE (GdmLocalDisplayFactory, gdm_local_display_factory, GDM_TYPE_DISPLAY_FACTORY)
79
80GQuark
81gdm_local_display_factory_error_quark (void)
82{
83        static GQuark ret = 0;
84        if (ret == 0) {
85                ret = g_quark_from_static_string ("gdm_local_display_factory_error");
86        }
87
88        return ret;
89}
90
91static void
92listify_hash (gpointer    key,
93              GdmDisplay *display,
94              GList     **list)
95{
96        *list = g_list_prepend (*list, key);
97}
98
99static int
100sort_nums (gpointer a,
101           gpointer b)
102{
103        guint32 num_a;
104        guint32 num_b;
105
106        num_a = GPOINTER_TO_UINT (a);
107        num_b = GPOINTER_TO_UINT (b);
108
109        if (num_a > num_b) {
110                return 1;
111        } else if (num_a < num_b) {
112                return -1;
113        } else {
114                return 0;
115        }
116}
117
118static guint32
119take_next_display_number (GdmLocalDisplayFactory *factory)
120{
121        GList  *list;
122        GList  *l;
123        guint32 ret;
124
125        ret = 0;
126        list = NULL;
127
128        g_hash_table_foreach (factory->priv->displays, (GHFunc)listify_hash, &list);
129        if (list == NULL) {
130                goto out;
131        }
132
133        /* sort low to high */
134        list = g_list_sort (list, (GCompareFunc)sort_nums);
135
136        g_debug ("GdmLocalDisplayFactory: Found the following X displays:");
137        for (l = list; l != NULL; l = l->next) {
138                g_debug ("GdmLocalDisplayFactory: %u", GPOINTER_TO_UINT (l->data));
139        }
140
141        for (l = list; l != NULL; l = l->next) {
142                guint32 num;
143                num = GPOINTER_TO_UINT (l->data);
144
145                /* always fill zero */
146                if (l->prev == NULL && num != 0) {
147                        ret = 0;
148                        break;
149                }
150                /* now find the first hole */
151                if (l->next == NULL || GPOINTER_TO_UINT (l->next->data) != (num + 1)) {
152                        ret = num + 1;
153                        break;
154                }
155        }
156 out:
157
158        /* now reserve this number */
159        g_debug ("GdmLocalDisplayFactory: Reserving X display: %u", ret);
160        g_hash_table_insert (factory->priv->displays, GUINT_TO_POINTER (ret), NULL);
161
162        return ret;
163}
164
165static void
166on_display_disposed (GdmLocalDisplayFactory *factory,
167                     GdmDisplay             *display)
168{
169        g_debug ("GdmLocalDisplayFactory: Display %p disposed", display);
170}
171
172static void
173store_display (GdmLocalDisplayFactory *factory,
174               guint32                 num,
175               GdmDisplay             *display)
176{
177        GdmDisplayStore *store;
178
179        g_object_weak_ref (G_OBJECT (display), (GWeakNotify)on_display_disposed, factory);
180
181        store = gdm_display_factory_get_display_store (GDM_DISPLAY_FACTORY (factory));
182        gdm_display_store_add (store, display);
183
184        /* now fill our reserved spot */
185        g_hash_table_insert (factory->priv->displays, GUINT_TO_POINTER (num), NULL);
186}
187
188/*
189  Example:
190  dbus-send --system --dest=org.gnome.DisplayManager \
191  --type=method_call --print-reply --reply-timeout=2000 \
192  /org/gnome/DisplayManager/Manager \
193  org.gnome.DisplayManager.Manager.GetDisplays
194*/
195gboolean
196gdm_local_display_factory_create_transient_display (GdmLocalDisplayFactory *factory,
197                                                    char                  **id,
198                                                    GError                **error)
199{
200        gboolean         ret;
201        GdmDisplay      *display;
202        guint32          num;
203
204        g_return_val_if_fail (GDM_IS_LOCAL_DISPLAY_FACTORY (factory), FALSE);
205
206        ret = FALSE;
207
208        num = take_next_display_number (factory);
209
210        g_debug ("GdmLocalDisplayFactory: Creating transient display %d", num);
211
212        display = gdm_transient_display_new (num);
213
214        /* FIXME: don't hardcode seat1? */
215        g_object_set (display, "seat-id", CK_SEAT1_PATH, NULL);
216
217        store_display (factory, num, display);
218
219        if (! gdm_display_manage (display)) {
220                display = NULL;
221                goto out;
222        }
223
224        if (! gdm_display_get_id (display, id, NULL)) {
225                display = NULL;
226                goto out;
227        }
228
229        ret = TRUE;
230 out:
231        /* ref either held by store or not at all */
232        g_object_unref (display);
233
234        return ret;
235}
236
237gboolean
238gdm_local_display_factory_create_product_display (GdmLocalDisplayFactory *factory,
239                                                  const char             *parent_display_id,
240                                                  const char             *relay_address,
241                                                  char                  **id,
242                                                  GError                **error)
243{
244        gboolean    ret;
245        GdmDisplay *display;
246        guint32     num;
247
248        g_return_val_if_fail (GDM_IS_LOCAL_DISPLAY_FACTORY (factory), FALSE);
249
250        ret = FALSE;
251
252        g_debug ("GdmLocalDisplayFactory: Creating product display parent %s address:%s",
253                 parent_display_id, relay_address);
254
255        num = take_next_display_number (factory);
256
257        g_debug ("GdmLocalDisplayFactory: got display num %u", num);
258
259        display = gdm_product_display_new (num, relay_address);
260
261        /* FIXME: don't hardcode seat1? */
262        g_object_set (display, "seat-id", CK_SEAT1_PATH, NULL);
263
264        store_display (factory, num, display);
265
266        if (! gdm_display_manage (display)) {
267                display = NULL;
268                goto out;
269        }
270
271        if (! gdm_display_get_id (display, id, NULL)) {
272                display = NULL;
273                goto out;
274        }
275
276        ret = TRUE;
277 out:
278        /* ref either held by store or not at all */
279        g_object_unref (display);
280
281        return ret;
282}
283
284static void
285on_static_display_status_changed (GdmDisplay             *display,
286                                  GParamSpec             *arg1,
287                                  GdmLocalDisplayFactory *factory)
288{
289        int              status;
290        GdmDisplayStore *store;
291        int              num;
292
293        num = -1;
294        gdm_display_get_x11_display_number (display, &num, NULL);
295        g_assert (num != -1);
296
297        store = gdm_display_factory_get_display_store (GDM_DISPLAY_FACTORY (factory));
298
299        status = gdm_display_get_status (display);
300
301        g_debug ("GdmLocalDisplayFactory: static display status changed: %d", status);
302        switch (status) {
303        case GDM_DISPLAY_FINISHED:
304                /* remove the display number from factory->priv->displays
305                   so that it may be reused */
306                g_hash_table_remove (factory->priv->displays, GUINT_TO_POINTER (num));
307                gdm_display_store_remove (store, display);
308                /* reset num failures */
309                factory->priv->num_failures = 0;
310                create_display (factory);
311                break;
312        case GDM_DISPLAY_FAILED:
313                /* leave the display number in factory->priv->displays
314                   so that it doesn't get reused */
315                gdm_display_store_remove (store, display);
316                factory->priv->num_failures++;
317                if (factory->priv->num_failures > MAX_DISPLAY_FAILURES) {
318                        /* oh shit */
319                        g_warning ("GdmLocalDisplayFactory: maximum number of X display failures reached: check X server log for errors");
320                        exit (1);
321                }
322
323                create_display (factory);
324                break;
325        case GDM_DISPLAY_UNMANAGED:
326                break;
327        case GDM_DISPLAY_PREPARED:
328                break;
329        case GDM_DISPLAY_MANAGED:
330                break;
331        default:
332                g_assert_not_reached ();
333                break;
334        }
335}
336
337static GdmDisplay *
338create_display (GdmLocalDisplayFactory *factory)
339{
340        GdmDisplay *display;
341        guint32     num;
342
343        num = take_next_display_number (factory);
344
345#if 0
346        display = gdm_static_factory_display_new (num);
347#else
348        display = gdm_static_display_new (num);
349#endif
350        if (display == NULL) {
351                g_warning ("Unable to create display: %d", num);
352                return NULL;
353        }
354
355        /* FIXME: don't hardcode seat1? */
356        g_object_set (display, "seat-id", CK_SEAT1_PATH, NULL);
357
358        g_signal_connect (display,
359                          "notify::status",
360                          G_CALLBACK (on_static_display_status_changed),
361                          factory);
362
363        store_display (factory, num, display);
364
365        /* let store own the ref */
366        g_object_unref (display);
367
368        if (! gdm_display_manage (display)) {
369                gdm_display_unmanage (display);
370        }
371
372        return display;
373}
374
375#if 0
376static void
377create_display_for_device (GdmLocalDisplayFactory *factory,
378                           DBusGProxy             *device_proxy)
379{
380        create_display (factory);
381}
382
383static void
384create_displays_for_pci_devices (GdmLocalDisplayFactory *factory)
385{
386        char      **devices;
387        const char *key;
388        const char *value;
389        GError     *error;
390        gboolean    res;
391        int         i;
392
393        g_debug ("GdmLocalDisplayFactory: Getting PCI seat devices");
394
395        key = "info.bus";
396        value = "pci";
397
398        devices = NULL;
399        error = NULL;
400        res = dbus_g_proxy_call (factory->priv->proxy,
401                                 "FindDeviceStringMatch",
402                                 &error,
403                                 G_TYPE_STRING, key,
404                                 G_TYPE_STRING, value,
405                                 G_TYPE_INVALID,
406                                 G_TYPE_STRV, &devices,
407                                 G_TYPE_INVALID);
408        if (! res) {
409                g_warning ("Unable to query HAL: %s", error->message);
410                g_error_free (error);
411        }
412
413        /* now look for pci class 3 */
414        key = "pci.device_class";
415        for (i = 0; devices [i] != NULL; i++) {
416                DBusGProxy *device_proxy;
417                int         class_val;
418
419                device_proxy = dbus_g_proxy_new_for_name (factory->priv->connection,
420                                                          HAL_DBUS_NAME,
421                                                          devices [i],
422                                                          HAL_DBUS_DEVICE_INTERFACE);
423                if (device_proxy == NULL) {
424                        continue;
425                }
426
427                error = NULL;
428                res = dbus_g_proxy_call (device_proxy,
429                                         "GetPropertyInteger",
430                                         &error,
431                                         G_TYPE_STRING, key,
432                                         G_TYPE_INVALID,
433                                         G_TYPE_INT, &class_val,
434                                         G_TYPE_INVALID);
435                if (! res) {
436                        g_warning ("Unable to query HAL: %s", error->message);
437                        g_error_free (error);
438                }
439
440                if (class_val == SEAT_PCI_DEVICE_CLASS) {
441                        g_debug ("GdmLocalDisplayFactory: Found device: %s", devices [i]);
442                        create_display_for_device (factory, device_proxy);
443                }
444
445                g_object_unref (device_proxy);
446        }
447
448        g_strfreev (devices);
449}
450#endif
451
452static gboolean
453gdm_local_display_factory_start (GdmDisplayFactory *base_factory)
454{
455        gboolean                ret;
456        GdmLocalDisplayFactory *factory = GDM_LOCAL_DISPLAY_FACTORY (base_factory);
457
458        g_return_val_if_fail (GDM_IS_LOCAL_DISPLAY_FACTORY (factory), FALSE);
459
460        ret = TRUE;
461
462        /* FIXME: use seat configuration */
463#if 0
464        create_displays_for_pci_devices (factory);
465#else
466        create_display (factory);
467#endif
468
469        return ret;
470}
471
472static gboolean
473gdm_local_display_factory_stop (GdmDisplayFactory *base_factory)
474{
475        GdmLocalDisplayFactory *factory = GDM_LOCAL_DISPLAY_FACTORY (base_factory);
476
477        g_return_val_if_fail (GDM_IS_LOCAL_DISPLAY_FACTORY (factory), FALSE);
478
479        return TRUE;
480}
481
482static void
483gdm_local_display_factory_set_property (GObject       *object,
484                                        guint          prop_id,
485                                        const GValue  *value,
486                                        GParamSpec    *pspec)
487{
488        switch (prop_id) {
489        default:
490                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
491                break;
492        }
493}
494
495static void
496gdm_local_display_factory_get_property (GObject    *object,
497                                        guint       prop_id,
498                                        GValue     *value,
499                                        GParamSpec *pspec)
500{
501        switch (prop_id) {
502        default:
503                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
504                break;
505        }
506}
507
508static gboolean
509register_factory (GdmLocalDisplayFactory *factory)
510{
511        GError *error = NULL;
512
513        error = NULL;
514        factory->priv->connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
515        if (factory->priv->connection == NULL) {
516                if (error != NULL) {
517                        g_critical ("error getting system bus: %s", error->message);
518                        g_error_free (error);
519                }
520                exit (1);
521        }
522
523        dbus_g_connection_register_g_object (factory->priv->connection, GDM_LOCAL_DISPLAY_FACTORY_DBUS_PATH, G_OBJECT (factory));
524
525        return TRUE;
526}
527
528static gboolean
529connect_to_hal (GdmLocalDisplayFactory *factory)
530{
531        factory->priv->proxy = dbus_g_proxy_new_for_name (factory->priv->connection,
532                                                          HAL_DBUS_NAME,
533                                                          HAL_DBUS_MANAGER_PATH,
534                                                          HAL_DBUS_MANAGER_INTERFACE);
535        if (factory->priv->proxy == NULL) {
536                g_warning ("Couldn't create proxy for HAL Manager");
537                return FALSE;
538        }
539
540        return TRUE;
541}
542
543static void
544disconnect_from_hal (GdmLocalDisplayFactory *factory)
545{
546        if (factory->priv->proxy == NULL) {
547                g_object_unref (factory->priv->proxy);
548        }
549}
550
551static GObject *
552gdm_local_display_factory_constructor (GType                  type,
553                                       guint                  n_construct_properties,
554                                       GObjectConstructParam *construct_properties)
555{
556        GdmLocalDisplayFactory      *factory;
557        gboolean                     res;
558
559        factory = GDM_LOCAL_DISPLAY_FACTORY (G_OBJECT_CLASS (gdm_local_display_factory_parent_class)->constructor (type,
560                                                                                                                   n_construct_properties,
561                                                                                                                   construct_properties));
562
563        res = register_factory (factory);
564        if (! res) {
565                g_warning ("Unable to register local display factory with system bus");
566        }
567
568        connect_to_hal (factory);
569
570        return G_OBJECT (factory);
571}
572
573static void
574gdm_local_display_factory_class_init (GdmLocalDisplayFactoryClass *klass)
575{
576        GObjectClass           *object_class = G_OBJECT_CLASS (klass);
577        GdmDisplayFactoryClass *factory_class = GDM_DISPLAY_FACTORY_CLASS (klass);
578
579        object_class->get_property = gdm_local_display_factory_get_property;
580        object_class->set_property = gdm_local_display_factory_set_property;
581        object_class->finalize = gdm_local_display_factory_finalize;
582        object_class->constructor = gdm_local_display_factory_constructor;
583
584        factory_class->start = gdm_local_display_factory_start;
585        factory_class->stop = gdm_local_display_factory_stop;
586
587        g_type_class_add_private (klass, sizeof (GdmLocalDisplayFactoryPrivate));
588
589        dbus_g_object_type_install_info (GDM_TYPE_LOCAL_DISPLAY_FACTORY, &dbus_glib_gdm_local_display_factory_object_info);
590}
591
592static void
593gdm_local_display_factory_init (GdmLocalDisplayFactory *factory)
594{
595        factory->priv = GDM_LOCAL_DISPLAY_FACTORY_GET_PRIVATE (factory);
596
597        factory->priv->displays = g_hash_table_new (NULL, NULL);
598}
599
600static void
601gdm_local_display_factory_finalize (GObject *object)
602{
603        GdmLocalDisplayFactory *factory;
604
605        g_return_if_fail (object != NULL);
606        g_return_if_fail (GDM_IS_LOCAL_DISPLAY_FACTORY (object));
607
608        factory = GDM_LOCAL_DISPLAY_FACTORY (object);
609
610        g_return_if_fail (factory->priv != NULL);
611
612        g_hash_table_destroy (factory->priv->displays);
613
614        disconnect_from_hal (factory);
615
616        G_OBJECT_CLASS (gdm_local_display_factory_parent_class)->finalize (object);
617}
618
619GdmLocalDisplayFactory *
620gdm_local_display_factory_new (GdmDisplayStore *store)
621{
622        if (local_display_factory_object != NULL) {
623                g_object_ref (local_display_factory_object);
624        } else {
625                local_display_factory_object = g_object_new (GDM_TYPE_LOCAL_DISPLAY_FACTORY,
626                                                             "display-store", store,
627                                                             NULL);
628                g_object_add_weak_pointer (local_display_factory_object,
629                                           (gpointer *) &local_display_factory_object);
630        }
631
632        return GDM_LOCAL_DISPLAY_FACTORY (local_display_factory_object);
633}
Note: See TracBrowser for help on using the repository browser.