source: proiecte/PPPP/gdm/utils/gdmflexiserver.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: 25.1 KB
Line 
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
2 *
3 * Copyright (C) 2008 William Jon McCann <jmccann@redhat.com>
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 <unistd.h>
26#include <string.h>
27#include <locale.h>
28
29#include <glib/gi18n.h>
30#include <gtk/gtk.h>
31
32#define DBUS_API_SUBJECT_TO_CHANGE
33#include <dbus/dbus-glib.h>
34#include <dbus/dbus-glib-lowlevel.h>
35
36#define GDM_DBUS_NAME                            "org.gnome.DisplayManager"
37#define GDM_DBUS_LOCAL_DISPLAY_FACTORY_PATH      "/org/gnome/DisplayManager/LocalDisplayFactory"
38#define GDM_DBUS_LOCAL_DISPLAY_FACTORY_INTERFACE "org.gnome.DisplayManager.LocalDisplayFactory"
39
40#define CK_NAME      "org.freedesktop.ConsoleKit"
41#define CK_PATH      "/org/freedesktop/ConsoleKit"
42#define CK_INTERFACE "org.freedesktop.ConsoleKit"
43
44#define CK_MANAGER_PATH      "/org/freedesktop/ConsoleKit/Manager"
45#define CK_MANAGER_INTERFACE "org.freedesktop.ConsoleKit.Manager"
46#define CK_SEAT_INTERFACE    "org.freedesktop.ConsoleKit.Seat"
47#define CK_SESSION_INTERFACE "org.freedesktop.ConsoleKit.Session"
48
49static const char *send_command     = NULL;
50static gboolean    use_xnest        = FALSE;
51static gboolean    no_lock          = FALSE;
52static gboolean    debug_in         = FALSE;
53static gboolean    authenticate     = FALSE;
54static gboolean    startnew         = FALSE;
55static gboolean    monte_carlo_pi   = FALSE;
56static gboolean    show_version     = FALSE;
57static char      **args_remaining   = NULL;
58
59/* Keep all config options for compatibility even if they are noops */
60GOptionEntry options [] = {
61        { "command", 'c', 0, G_OPTION_ARG_STRING, &send_command, N_("Ignored - retained for compatibility"), N_("COMMAND") },
62        { "xnest", 'n', 0, G_OPTION_ARG_NONE, &use_xnest, N_("Ignored - retained for compatibility"), NULL },
63        { "no-lock", 'l', 0, G_OPTION_ARG_NONE, &no_lock, N_("Ignored - retained for compatibility"), NULL },
64        { "debug", 'd', 0, G_OPTION_ARG_NONE, &debug_in, N_("Debugging output"), NULL },
65        { "authenticate", 'a', 0, G_OPTION_ARG_NONE, &authenticate, N_("Ignored - retained for compatibility"), NULL },
66        { "startnew", 's', 0, G_OPTION_ARG_NONE, &startnew, N_("Ignored - retained for compatibility"), NULL },
67        { "monte-carlo-pi", 0, 0, G_OPTION_ARG_NONE, &monte_carlo_pi, NULL, NULL },
68        { "version", 0, 0, G_OPTION_ARG_NONE, &show_version, N_("Version of this application"), NULL },
69        { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_STRING_ARRAY, &args_remaining, NULL, NULL },
70        { NULL }
71};
72
73#define GDM_FLEXISERVER_ERROR gdm_flexiserver_error_quark ()
74static GQuark
75gdm_flexiserver_error_quark (void)
76{
77        static GQuark ret = 0;
78        if (ret == 0) {
79                ret = g_quark_from_static_string ("gdm_flexiserver_error");
80        }
81
82        return ret;
83}
84
85static gboolean
86is_program_in_path (const char *program)
87{
88        char *tmp = g_find_program_in_path (program);
89        if (tmp != NULL) {
90                g_free (tmp);
91                return TRUE;
92        } else {
93                return FALSE;
94        }
95}
96
97static void
98maybe_lock_screen (void)
99{
100        gboolean   use_gscreensaver = FALSE;
101        GError    *error            = NULL;
102        char      *command;
103        GdkScreen *screen;
104
105        if (is_program_in_path ("gnome-screensaver-command")) {
106                use_gscreensaver = TRUE;
107        } else if (! is_program_in_path ("xscreensaver-command")) {
108                return;
109        }
110
111        if (use_gscreensaver) {
112                command = g_strdup ("gnome-screensaver-command --lock");
113        } else {
114                command = g_strdup ("xscreensaver-command -lock");
115        }
116
117        screen = gdk_screen_get_default ();
118
119        if (! gdk_spawn_command_line_on_screen (screen, command, &error)) {
120                g_warning ("Cannot lock screen: %s", error->message);
121                g_error_free (error);
122        }
123
124        g_free (command);
125
126        if (! use_gscreensaver) {
127                command = g_strdup ("xscreensaver-command -throttle");
128                if (! gdk_spawn_command_line_on_screen (screen, command, &error)) {
129                        g_warning ("Cannot disable screensaver engines: %s", error->message);
130                        g_error_free (error);
131                }
132
133                g_free (command);
134        }
135}
136
137static void
138calc_pi (void)
139{
140        unsigned long n = 0, h = 0;
141        double x, y;
142        printf ("\n");
143        for (;;) {
144                x = g_random_double ();
145                y = g_random_double ();
146                if (x*x + y*y <= 1)
147                        h++;
148                n++;
149                if ( ! (n & 0xfff))
150                        printf ("pi ~~ %1.10f\t(%lu/%lu * 4) iteration: %lu \r",
151                                ((double)h)/(double)n * 4.0, h, n, n);
152        }
153}
154
155static gboolean
156create_transient_display (DBusConnection *connection,
157                          GError        **error)
158{
159        DBusError       local_error;
160        DBusMessage    *message;
161        DBusMessage    *reply;
162        gboolean        ret;
163        DBusMessageIter iter;
164        const char     *value;
165
166        ret = FALSE;
167        reply = NULL;
168
169        dbus_error_init (&local_error);
170        message = dbus_message_new_method_call (GDM_DBUS_NAME,
171                                                GDM_DBUS_LOCAL_DISPLAY_FACTORY_PATH,
172                                                GDM_DBUS_LOCAL_DISPLAY_FACTORY_INTERFACE,
173                                                "CreateTransientDisplay");
174        if (message == NULL) {
175                g_set_error (error, GDM_FLEXISERVER_ERROR, 0, "Out of memory.");
176                goto out;
177        }
178
179        dbus_error_init (&local_error);
180        reply = dbus_connection_send_with_reply_and_block (connection,
181                                                           message,
182                                                           -1,
183                                                           &local_error);
184        if (reply == NULL) {
185                if (dbus_error_is_set (&local_error)) {
186                        g_warning ("Unable to create transient display: %s", local_error.message);
187                        g_set_error (error, GDM_FLEXISERVER_ERROR, 0, "%s", local_error.message);
188                        dbus_error_free (&local_error);
189                        goto out;
190                }
191        }
192
193        dbus_message_iter_init (reply, &iter);
194        dbus_message_iter_get_basic (&iter, &value);
195        g_debug ("Started %s", value);
196
197        ret = TRUE;
198 out:
199        if (message != NULL) {
200                dbus_message_unref (message);
201        }
202        if (reply != NULL) {
203                dbus_message_unref (reply);
204        }
205
206        return ret;
207}
208
209static gboolean
210get_current_session_id (DBusConnection *connection,
211                        char          **session_id)
212{
213        DBusError       local_error;
214        DBusMessage    *message;
215        DBusMessage    *reply;
216        gboolean        ret;
217        DBusMessageIter iter;
218        const char     *value;
219
220        ret = FALSE;
221        reply = NULL;
222
223        dbus_error_init (&local_error);
224        message = dbus_message_new_method_call (CK_NAME,
225                                                CK_MANAGER_PATH,
226                                                CK_MANAGER_INTERFACE,
227                                                "GetCurrentSession");
228        if (message == NULL) {
229                goto out;
230        }
231
232        dbus_error_init (&local_error);
233        reply = dbus_connection_send_with_reply_and_block (connection,
234                                                           message,
235                                                           -1,
236                                                           &local_error);
237        if (reply == NULL) {
238                if (dbus_error_is_set (&local_error)) {
239                        g_warning ("Unable to determine session: %s", local_error.message);
240                        dbus_error_free (&local_error);
241                        goto out;
242                }
243        }
244
245        dbus_message_iter_init (reply, &iter);
246        dbus_message_iter_get_basic (&iter, &value);
247        if (session_id != NULL) {
248                *session_id = g_strdup (value);
249        }
250
251        ret = TRUE;
252 out:
253        if (message != NULL) {
254                dbus_message_unref (message);
255        }
256        if (reply != NULL) {
257                dbus_message_unref (reply);
258        }
259
260        return ret;
261}
262
263static gboolean
264get_seat_id_for_session (DBusConnection *connection,
265                         const char     *session_id,
266                         char          **seat_id)
267{
268        DBusError       local_error;
269        DBusMessage    *message;
270        DBusMessage    *reply;
271        gboolean        ret;
272        DBusMessageIter iter;
273        const char     *value;
274
275        ret = FALSE;
276        reply = NULL;
277
278        dbus_error_init (&local_error);
279        message = dbus_message_new_method_call (CK_NAME,
280                                                session_id,
281                                                CK_SESSION_INTERFACE,
282                                                "GetSeatId");
283        if (message == NULL) {
284                goto out;
285        }
286
287        dbus_error_init (&local_error);
288        reply = dbus_connection_send_with_reply_and_block (connection,
289                                                           message,
290                                                           -1,
291                                                           &local_error);
292        if (reply == NULL) {
293                if (dbus_error_is_set (&local_error)) {
294                        g_warning ("Unable to determine seat: %s", local_error.message);
295                        dbus_error_free (&local_error);
296                        goto out;
297                }
298        }
299
300        dbus_message_iter_init (reply, &iter);
301        dbus_message_iter_get_basic (&iter, &value);
302        if (seat_id != NULL) {
303                *seat_id = g_strdup (value);
304        }
305
306        ret = TRUE;
307 out:
308        if (message != NULL) {
309                dbus_message_unref (message);
310        }
311        if (reply != NULL) {
312                dbus_message_unref (reply);
313        }
314
315        return ret;
316}
317
318static char *
319get_current_seat_id (DBusConnection *connection)
320{
321        gboolean res;
322        char    *session_id;
323        char    *seat_id;
324
325        session_id = NULL;
326        seat_id = NULL;
327
328        res = get_current_session_id (connection, &session_id);
329        if (res) {
330                res = get_seat_id_for_session (connection, session_id, &seat_id);
331        }
332        g_free (session_id);
333
334        return seat_id;
335}
336
337static gboolean
338activate_session_id (DBusConnection *connection,
339                     const char     *seat_id,
340                     const char     *session_id)
341{
342        DBusError    local_error;
343        DBusMessage *message;
344        DBusMessage *reply;
345        gboolean     ret;
346
347        ret = FALSE;
348        reply = NULL;
349
350        g_debug ("Switching to session %s", session_id);
351
352        dbus_error_init (&local_error);
353        message = dbus_message_new_method_call (CK_NAME,
354                                                seat_id,
355                                                CK_SEAT_INTERFACE,
356                                                "ActivateSession");
357        if (message == NULL) {
358                goto out;
359        }
360
361        if (! dbus_message_append_args (message,
362                                        DBUS_TYPE_OBJECT_PATH, &session_id,
363                                        DBUS_TYPE_INVALID)) {
364                goto out;
365        }
366
367
368        dbus_error_init (&local_error);
369        reply = dbus_connection_send_with_reply_and_block (connection,
370                                                           message,
371                                                           -1,
372                                                           &local_error);
373        if (reply == NULL) {
374                if (dbus_error_is_set (&local_error)) {
375                        g_warning ("Unable to activate session: %s", local_error.message);
376                        dbus_error_free (&local_error);
377                        goto out;
378                }
379        }
380
381        ret = TRUE;
382 out:
383        if (message != NULL) {
384                dbus_message_unref (message);
385        }
386        if (reply != NULL) {
387                dbus_message_unref (reply);
388        }
389
390        return ret;
391}
392
393static gboolean
394session_is_login_window (DBusConnection *connection,
395                         const char     *session_id)
396{
397        DBusError       local_error;
398        DBusMessage    *message;
399        DBusMessage    *reply;
400        gboolean        ret;
401        DBusMessageIter iter;
402        const char     *value;
403
404        ret = FALSE;
405        reply = NULL;
406
407        dbus_error_init (&local_error);
408        message = dbus_message_new_method_call (CK_NAME,
409                                                session_id,
410                                                CK_SESSION_INTERFACE,
411                                                "GetSessionType");
412        if (message == NULL) {
413                goto out;
414        }
415
416        dbus_error_init (&local_error);
417        reply = dbus_connection_send_with_reply_and_block (connection,
418                                                           message,
419                                                           -1,
420                                                           &local_error);
421        if (reply == NULL) {
422                if (dbus_error_is_set (&local_error)) {
423                        g_warning ("Unable to determine seat: %s", local_error.message);
424                        dbus_error_free (&local_error);
425                        goto out;
426                }
427        }
428
429        dbus_message_iter_init (reply, &iter);
430        dbus_message_iter_get_basic (&iter, &value);
431
432        if (value == NULL || value[0] == '\0' || strcmp (value, "LoginWindow") != 0) {
433                goto out;
434        }
435
436        ret = TRUE;
437 out:
438        if (message != NULL) {
439                dbus_message_unref (message);
440        }
441        if (reply != NULL) {
442                dbus_message_unref (reply);
443        }
444
445        return ret;
446}
447
448static gboolean
449seat_can_activate_sessions (DBusConnection *connection,
450                            const char     *seat_id)
451{
452        DBusError       local_error;
453        DBusMessage    *message;
454        DBusMessage    *reply;
455        DBusMessageIter iter;
456        gboolean        can_activate;
457
458        can_activate = FALSE;
459        reply = NULL;
460
461        dbus_error_init (&local_error);
462        message = dbus_message_new_method_call (CK_NAME,
463                                                seat_id,
464                                                CK_SEAT_INTERFACE,
465                                                "CanActivateSessions");
466        if (message == NULL) {
467                goto out;
468        }
469
470        dbus_error_init (&local_error);
471        reply = dbus_connection_send_with_reply_and_block (connection,
472                                                           message,
473                                                           -1,
474                                                           &local_error);
475        if (reply == NULL) {
476                if (dbus_error_is_set (&local_error)) {
477                        g_warning ("Unable to activate session: %s", local_error.message);
478                        dbus_error_free (&local_error);
479                        goto out;
480                }
481        }
482
483        dbus_message_iter_init (reply, &iter);
484        dbus_message_iter_get_basic (&iter, &can_activate);
485
486 out:
487        if (message != NULL) {
488                dbus_message_unref (message);
489        }
490        if (reply != NULL) {
491                dbus_message_unref (reply);
492        }
493
494        return can_activate;
495}
496
497/* from libhal */
498static char **
499get_path_array_from_iter (DBusMessageIter *iter,
500                          int             *num_elements)
501{
502        int count;
503        char **buffer;
504
505        count = 0;
506        buffer = (char **)malloc (sizeof (char *) * 8);
507
508        if (buffer == NULL)
509                goto oom;
510
511        buffer[0] = NULL;
512        while (dbus_message_iter_get_arg_type (iter) == DBUS_TYPE_OBJECT_PATH) {
513                const char *value;
514                char *str;
515
516                if ((count % 8) == 0 && count != 0) {
517                        buffer = realloc (buffer, sizeof (char *) * (count + 8));
518                        if (buffer == NULL)
519                                goto oom;
520                }
521
522                dbus_message_iter_get_basic (iter, &value);
523                str = strdup (value);
524                if (str == NULL)
525                        goto oom;
526
527                buffer[count] = str;
528
529                dbus_message_iter_next (iter);
530                count++;
531        }
532
533        if ((count % 8) == 0) {
534                buffer = realloc (buffer, sizeof (char *) * (count + 1));
535                if (buffer == NULL)
536                        goto oom;
537        }
538
539        buffer[count] = NULL;
540        if (num_elements != NULL)
541                *num_elements = count;
542        return buffer;
543
544oom:
545        g_debug ("%s %d : error allocating memory\n", __FILE__, __LINE__);
546        return NULL;
547
548}
549
550static char **
551seat_get_sessions (DBusConnection *connection,
552                   const char     *seat_id)
553{
554        DBusError       error;
555        DBusMessage    *message;
556        DBusMessage    *reply;
557        DBusMessageIter iter_reply;
558        DBusMessageIter iter_array;
559        char           **sessions;
560
561        sessions = NULL;
562        message = NULL;
563        reply = NULL;
564
565        dbus_error_init (&error);
566        message = dbus_message_new_method_call (CK_NAME,
567                                                seat_id,
568                                                CK_SEAT_INTERFACE,
569                                                "GetSessions");
570        if (message == NULL) {
571                g_debug ("Couldn't allocate the D-Bus message");
572                goto out;
573        }
574
575        dbus_error_init (&error);
576        reply = dbus_connection_send_with_reply_and_block (connection,
577                                                           message,
578                                                           -1, &error);
579        dbus_connection_flush (connection);
580
581        if (dbus_error_is_set (&error)) {
582                g_debug ("ConsoleKit %s raised:\n %s\n\n", error.name, error.message);
583                goto out;
584        }
585
586        if (reply == NULL) {
587                g_debug ("ConsoleKit: No reply for GetSessionsForUser");
588                goto out;
589        }
590
591        dbus_message_iter_init (reply, &iter_reply);
592        if (dbus_message_iter_get_arg_type (&iter_reply) != DBUS_TYPE_ARRAY) {
593                g_debug ("ConsoleKit Wrong reply for GetSessionsForUser - expecting an array.");
594                goto out;
595        }
596
597        dbus_message_iter_recurse (&iter_reply, &iter_array);
598        sessions = get_path_array_from_iter (&iter_array, NULL);
599
600 out:
601        if (message != NULL) {
602                dbus_message_unref (message);
603        }
604        if (reply != NULL) {
605                dbus_message_unref (reply);
606        }
607
608        return sessions;
609}
610
611static char *
612get_login_window_session_id (DBusConnection *connection,
613                             const char     *seat_id)
614{
615        gboolean    can_activate_sessions;
616        char      **sessions;
617        char       *session_id;
618        int         i;
619
620        session_id = NULL;
621        sessions = NULL;
622
623        g_debug ("checking if seat can activate sessions");
624
625        can_activate_sessions = seat_can_activate_sessions (connection, seat_id);
626        if (! can_activate_sessions) {
627                g_debug ("seat is unable to activate sessions");
628                goto out;
629        }
630
631        sessions = seat_get_sessions (connection, seat_id);
632        for (i = 0; sessions [i] != NULL; i++) {
633                char *ssid;
634
635                ssid = sessions [i];
636
637                if (session_is_login_window (connection, ssid)) {
638                        session_id = g_strdup (ssid);
639                        break;
640                }
641        }
642        g_strfreev (sessions);
643
644 out:
645        return session_id;
646}
647
648static gboolean
649goto_login_session (GError **error)
650{
651        gboolean        ret;
652        gboolean        res;
653        char           *session_id;
654        char           *seat_id;
655        DBusError       local_error;
656        DBusConnection *connection;
657
658        ret = FALSE;
659
660        dbus_error_init (&local_error);
661        connection = dbus_bus_get (DBUS_BUS_SYSTEM, &local_error);
662        if (connection == NULL) {
663                g_debug ("Failed to connect to the D-Bus daemon: %s", local_error.message);
664                g_set_error (error, GDM_FLEXISERVER_ERROR, 0, "%s", local_error.message);
665                dbus_error_free (&local_error);
666                return FALSE;
667        }
668
669        /* First look for any existing LoginWindow sessions on the seat.
670           If none are found, create a new one. */
671
672        seat_id = get_current_seat_id (connection);
673        if (seat_id == NULL || seat_id[0] == '\0') {
674                g_debug ("seat id is not set; can't switch sessions");
675                g_set_error (error, GDM_FLEXISERVER_ERROR, 0, _("Could not identify the current session."));
676
677                return FALSE;
678        }
679
680        session_id = get_login_window_session_id (connection, seat_id);
681        if (session_id != NULL) {
682                res = activate_session_id (connection, seat_id, session_id);
683                if (res) {
684                        ret = TRUE;
685                }
686        }
687
688        if (! ret) {
689                res = create_transient_display (connection, error);
690                if (res) {
691                        ret = TRUE;
692                }
693        }
694
695        return ret;
696}
697
698int
699main (int argc, char *argv[])
700{
701        GOptionContext *ctx;
702        gboolean        res;
703        GError         *error;
704
705        bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);
706        bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
707        textdomain (GETTEXT_PACKAGE);
708        setlocale (LC_ALL, "");
709
710        /* Option parsing */
711        ctx = g_option_context_new (_("- New GDM login"));
712        g_option_context_set_translation_domain (ctx, GETTEXT_PACKAGE);
713        g_option_context_add_main_entries (ctx, options, NULL);
714        g_option_context_parse (ctx, &argc, &argv, NULL);
715        g_option_context_free (ctx);
716
717
718        if (show_version) {
719                g_print ("%s %s\n", argv [0], VERSION);
720                exit (1);
721        }
722
723        /* don't support commands other than VERSION */
724        if (send_command != NULL) {
725                if (strcmp (send_command, "VERSION") == 0) {
726                        g_print ("GDM  %s \n", VERSION);
727                        return 0;
728                } else {
729                        g_warning ("No longer supported");
730                }
731                return 1;
732        }
733
734        gtk_init (&argc, &argv);
735
736        if (monte_carlo_pi) {
737                calc_pi ();
738                return 0;
739        }
740
741        if (args_remaining != NULL && args_remaining[0] != NULL) {
742
743        }
744
745        if (use_xnest) {
746                g_warning ("Not yet implemented");
747                return 1;
748        }
749
750        error = NULL;
751        res = goto_login_session (&error);
752        if (! res) {
753                GtkWidget *dialog;
754                char      *message;
755
756                if (error != NULL) {
757                        message = g_strdup_printf ("%s", error->message);
758                        g_error_free (error);
759                } else {
760                        message = g_strdup ("");
761                }
762
763                dialog = gtk_message_dialog_new (NULL,
764                                                 GTK_DIALOG_DESTROY_WITH_PARENT,
765                                                 GTK_MESSAGE_ERROR,
766                                                 GTK_BUTTONS_CLOSE,
767                                                 "%s", _("Unable to start new display"));
768
769                gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
770                                                          "%s", message);
771                g_free (message);
772
773                gtk_window_set_title (GTK_WINDOW (dialog), "");
774                gtk_window_set_icon_name (GTK_WINDOW (dialog), "session-properties");
775                gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
776                gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (dialog)->vbox), 14);
777
778                gtk_dialog_run (GTK_DIALOG (dialog));
779                gtk_widget_destroy (dialog);
780        } else {
781                maybe_lock_screen ();
782        }
783
784        return 1;
785}
Note: See TracBrowser for help on using the repository browser.