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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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 
28 #include <glib.h>
29 #include <glib/gi18n.h>
30 #include <glib-object.h>
31 
32 #include "gdm-chooser-session.h"
33 #include "gdm-client.h"
34 
35 #include "gdm-host-chooser-dialog.h"
36 
37 #define GDM_CHOOSER_SESSION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_CHOOSER_SESSION, GdmChooserSessionPrivate))
38 
39 struct GdmChooserSessionPrivate
40 {
41         GdmClient             *client;
42         GdmRemoteGreeter      *remote_greeter;
43         GdmChooser            *chooser;
44         GtkWidget             *chooser_dialog;
45 };
46 
47 enum {
48         PROP_0,
49 };
50 
51 static void     gdm_chooser_session_class_init  (GdmChooserSessionClass *klass);
52 static void     gdm_chooser_session_init        (GdmChooserSession      *chooser_session);
53 static void     gdm_chooser_session_finalize    (GObject                *object);
54 
55 G_DEFINE_TYPE (GdmChooserSession, gdm_chooser_session, G_TYPE_OBJECT)
56 
57 static gpointer session_object = NULL;
58 
59 static gboolean
launch_compiz(GdmChooserSession * session)60 launch_compiz (GdmChooserSession *session)
61 {
62         GError  *error;
63         gboolean ret;
64 
65         g_debug ("GdmChooserSession: Launching compiz");
66 
67         ret = FALSE;
68 
69         error = NULL;
70         g_spawn_command_line_async ("gtk-window-decorator --replace", &error);
71         if (error != NULL) {
72                 g_warning ("Error starting WM: %s", error->message);
73                 g_error_free (error);
74                 goto out;
75         }
76 
77         error = NULL;
78         g_spawn_command_line_async ("compiz --replace", &error);
79         if (error != NULL) {
80                 g_warning ("Error starting WM: %s", error->message);
81                 g_error_free (error);
82                 goto out;
83         }
84 
85         ret = TRUE;
86 
87         /* FIXME: should try to detect if it actually works */
88 
89  out:
90         return ret;
91 }
92 
93 static gboolean
launch_metacity(GdmChooserSession * session)94 launch_metacity (GdmChooserSession *session)
95 {
96         GError  *error;
97         gboolean ret;
98 
99         g_debug ("GdmChooserSession: Launching metacity");
100 
101         ret = FALSE;
102 
103         error = NULL;
104         g_spawn_command_line_async ("metacity --replace", &error);
105         if (error != NULL) {
106                 g_warning ("Error starting WM: %s", error->message);
107                 g_error_free (error);
108                 goto out;
109         }
110 
111         ret = TRUE;
112 
113  out:
114         return ret;
115 }
116 
117 static void
start_window_manager(GdmChooserSession * session)118 start_window_manager (GdmChooserSession *session)
119 {
120         if (! launch_metacity (session)) {
121                 launch_compiz (session);
122         }
123 }
124 
125 static gboolean
start_settings_daemon(GdmChooserSession * session)126 start_settings_daemon (GdmChooserSession *session)
127 {
128         GError  *error;
129         gboolean ret;
130 
131         g_debug ("GdmChooserSession: Launching settings daemon");
132 
133         ret = FALSE;
134 
135         error = NULL;
136         g_spawn_command_line_async (GNOME_SETTINGS_DAEMON_DIR "/gnome-settings-daemon", &error);
137         if (error != NULL) {
138                 g_warning ("Error starting settings daemon: %s", error->message);
139                 g_error_free (error);
140                 goto out;
141         }
142 
143         ret = TRUE;
144 
145  out:
146         return ret;
147 }
148 
149 static void
on_dialog_response(GtkDialog * dialog,int response_id,GdmChooserSession * session)150 on_dialog_response (GtkDialog         *dialog,
151                     int                response_id,
152                     GdmChooserSession *session)
153 {
154         GdmChooserHost *host;
155         GError *error = NULL;
156 
157         host = NULL;
158         switch (response_id) {
159         case GTK_RESPONSE_OK:
160                 host = gdm_host_chooser_dialog_get_host (GDM_HOST_CHOOSER_DIALOG (dialog));
161         case GTK_RESPONSE_NONE:
162                 /* delete event */
163         default:
164                 break;
165         }
166 
167         if (host != NULL) {
168                 char *hostname;
169 
170                 /* only support XDMCP hosts in remote chooser */
171                 g_assert (gdm_chooser_host_get_kind (host) == GDM_CHOOSER_HOST_KIND_XDMCP);
172 
173                 hostname = NULL;
174                 gdm_address_get_hostname (gdm_chooser_host_get_address (host), &hostname);
175                 /* FIXME: fall back to numerical address? */
176                 if (hostname != NULL) {
177                         g_debug ("GdmChooserSession: Selected hostname '%s'", hostname);
178                         gdm_chooser_call_select_hostname_sync (session->priv->chooser,
179                                                                hostname,
180                                                                NULL,
181                                                                &error);
182 
183                         if (error != NULL) {
184                                 g_debug ("GdmChooserSession: %s", error->message);
185                                 g_clear_error (&error);
186                         }
187                         g_free (hostname);
188                 }
189         }
190 
191         gdm_remote_greeter_call_disconnect_sync (session->priv->remote_greeter,
192                                                  NULL,
193                                                  &error);
194         if (error != NULL) {
195                 g_debug ("GdmChooserSession: disconnect failed: %s", error->message);
196         }
197 }
198 
199 gboolean
gdm_chooser_session_start(GdmChooserSession * session,GError ** error)200 gdm_chooser_session_start (GdmChooserSession *session,
201                            GError           **error)
202 {
203         g_return_val_if_fail (GDM_IS_CHOOSER_SESSION (session), FALSE);
204 
205         session->priv->remote_greeter = gdm_client_get_remote_greeter_sync (session->priv->client,
206                                                                             NULL,
207                                                                             error);
208         if (session->priv->remote_greeter == NULL) {
209                 return FALSE;
210         }
211 
212         session->priv->chooser = gdm_client_get_chooser_sync (session->priv->client,
213                                                               NULL,
214                                                               error);
215         if (session->priv->chooser == NULL) {
216                 return FALSE;
217         }
218 
219         start_settings_daemon (session);
220         start_window_manager (session);
221 
222         /* Only support XDMCP on remote choosers */
223         session->priv->chooser_dialog = gdm_host_chooser_dialog_new (GDM_CHOOSER_HOST_KIND_XDMCP);
224         g_signal_connect (session->priv->chooser_dialog,
225                           "response",
226                           G_CALLBACK (on_dialog_response),
227                           session);
228         gtk_widget_show (session->priv->chooser_dialog);
229 
230         return TRUE;
231 }
232 
233 void
gdm_chooser_session_stop(GdmChooserSession * session)234 gdm_chooser_session_stop (GdmChooserSession *session)
235 {
236         g_return_if_fail (GDM_IS_CHOOSER_SESSION (session));
237 
238 }
239 
240 static void
gdm_chooser_session_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)241 gdm_chooser_session_set_property (GObject        *object,
242                                   guint           prop_id,
243                                   const GValue   *value,
244                                   GParamSpec     *pspec)
245 {
246         switch (prop_id) {
247         default:
248                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
249                 break;
250         }
251 }
252 
253 static void
gdm_chooser_session_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)254 gdm_chooser_session_get_property (GObject        *object,
255                                   guint           prop_id,
256                                   GValue         *value,
257                                   GParamSpec     *pspec)
258 {
259         switch (prop_id) {
260         default:
261                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
262                 break;
263         }
264 }
265 
266 static GObject *
gdm_chooser_session_constructor(GType type,guint n_construct_properties,GObjectConstructParam * construct_properties)267 gdm_chooser_session_constructor (GType                  type,
268                                  guint                  n_construct_properties,
269                                  GObjectConstructParam *construct_properties)
270 {
271         GdmChooserSession      *chooser_session;
272 
273         chooser_session = GDM_CHOOSER_SESSION (G_OBJECT_CLASS (gdm_chooser_session_parent_class)->constructor (type,
274                                                                                                                n_construct_properties,
275                                                                                                                construct_properties));
276 
277         return G_OBJECT (chooser_session);
278 }
279 
280 static void
gdm_chooser_session_dispose(GObject * object)281 gdm_chooser_session_dispose (GObject *object)
282 {
283         g_debug ("GdmChooserSession: Disposing chooser_session");
284 
285         G_OBJECT_CLASS (gdm_chooser_session_parent_class)->dispose (object);
286 }
287 
288 static void
gdm_chooser_session_class_init(GdmChooserSessionClass * klass)289 gdm_chooser_session_class_init (GdmChooserSessionClass *klass)
290 {
291         GObjectClass   *object_class = G_OBJECT_CLASS (klass);
292 
293         object_class->get_property = gdm_chooser_session_get_property;
294         object_class->set_property = gdm_chooser_session_set_property;
295         object_class->constructor = gdm_chooser_session_constructor;
296         object_class->dispose = gdm_chooser_session_dispose;
297         object_class->finalize = gdm_chooser_session_finalize;
298 
299         g_type_class_add_private (klass, sizeof (GdmChooserSessionPrivate));
300 }
301 
302 static void
gdm_chooser_session_init(GdmChooserSession * session)303 gdm_chooser_session_init (GdmChooserSession *session)
304 {
305 
306         session->priv = GDM_CHOOSER_SESSION_GET_PRIVATE (session);
307 
308         session->priv->client = gdm_client_new ();
309 }
310 
311 static void
gdm_chooser_session_finalize(GObject * object)312 gdm_chooser_session_finalize (GObject *object)
313 {
314         GdmChooserSession *chooser_session;
315 
316         g_return_if_fail (object != NULL);
317         g_return_if_fail (GDM_IS_CHOOSER_SESSION (object));
318 
319         chooser_session = GDM_CHOOSER_SESSION (object);
320 
321         g_return_if_fail (chooser_session->priv != NULL);
322 
323         g_clear_object (&chooser_session->priv->chooser);
324         g_clear_object (&chooser_session->priv->remote_greeter);
325         g_clear_object (&chooser_session->priv->client);
326 
327         G_OBJECT_CLASS (gdm_chooser_session_parent_class)->finalize (object);
328 }
329 
330 GdmChooserSession *
gdm_chooser_session_new(void)331 gdm_chooser_session_new (void)
332 {
333         if (session_object != NULL) {
334                 g_object_ref (session_object);
335         } else {
336                 session_object = g_object_new (GDM_TYPE_CHOOSER_SESSION, NULL);
337                 g_object_add_weak_pointer (session_object,
338                                            (gpointer *) &session_object);
339         }
340 
341         return GDM_CHOOSER_SESSION (session_object);
342 }
343