]> git.0d.be Git - empathy.git/blob - libempathy/empathy-idle.c
Remove workaround for mc-enum-types.h not being installed by MC and bump
[empathy.git] / libempathy / empathy-idle.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * Copyright (C) 2007 Collabora Ltd.
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License as
7  * published by the Free Software Foundation; either version 2 of the
8  * License, or (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 GNU
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public
16  * License along with this program; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  * 
20  * Authors: Xavier Claessens <xclaesse@gmail.com>
21  */
22
23 #include <config.h>
24
25 #include <string.h>
26
27 #include <glib/gi18n.h>
28 #include <dbus/dbus-glib.h>
29
30 #include <libtelepathy/tp-helpers.h>
31 #include <libmissioncontrol/mc-enum-types.h>
32
33 #include "empathy-idle.h"
34 #include "empathy-utils.h" 
35 #include "empathy-debug.h"
36
37 #define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \
38                        EMPATHY_TYPE_IDLE, EmpathyIdlePriv))
39
40 #define DEBUG_DOMAIN "Idle"
41
42 /* Number of seconds before entering extended autoaway. */
43 #define EXT_AWAY_TIME (30*60)
44
45 typedef enum {
46         NM_STATE_UNKNOWN,
47         NM_STATE_ASLEEP,
48         NM_STATE_CONNECTING,
49         NM_STATE_CONNECTED,
50         NM_STATE_DISCONNECTED
51 } NMState;
52
53 struct _EmpathyIdlePriv {
54         MissionControl *mc;
55         DBusGProxy     *gs_proxy;
56         DBusGProxy     *nm_proxy;
57         gboolean        is_idle;
58         McPresence      state;
59         McPresence      flash_state;
60         gchar          *status;
61         McPresence      saved_state;
62         gchar          *saved_status;
63         gboolean        nm_connected;
64         guint           ext_away_timeout;
65 };
66
67 static void     empathy_idle_class_init      (EmpathyIdleClass *klass);
68 static void     empathy_idle_init            (EmpathyIdle      *idle);
69 static void     idle_finalize                (GObject          *object);
70 static void     idle_get_property            (GObject          *object,
71                                               guint             param_id,
72                                               GValue           *value,
73                                               GParamSpec       *pspec);
74 static void     idle_set_property            (GObject          *object,
75                                               guint             param_id,
76                                               const GValue     *value,
77                                               GParamSpec       *pspec);
78 static void     idle_presence_changed_cb     (MissionControl   *mc,
79                                               McPresence        state,
80                                               EmpathyIdle      *idle);
81 static void     idle_session_idle_changed_cb (DBusGProxy       *gs_proxy,
82                                               gboolean          is_idle,
83                                               EmpathyIdle      *idle);
84 static void     idle_nm_state_change_cb      (DBusGProxy       *proxy,
85                                               guint             state,
86                                               EmpathyIdle      *idle);
87 static void     idle_ext_away_start          (EmpathyIdle      *idle);
88 static void     idle_ext_away_stop           (EmpathyIdle      *idle);
89 static gboolean idle_ext_away_cb             (EmpathyIdle      *idle);
90
91 enum {
92         PROP_0,
93         PROP_STATE,
94         PROP_STATUS,
95         PROP_FLASH_STATE
96 };
97
98 G_DEFINE_TYPE (EmpathyIdle, empathy_idle, G_TYPE_OBJECT)
99
100 static void
101 empathy_idle_class_init (EmpathyIdleClass *klass)
102 {
103         GObjectClass *object_class = G_OBJECT_CLASS (klass);
104
105         object_class->finalize = idle_finalize;
106         object_class->get_property = idle_get_property;
107         object_class->set_property = idle_set_property;
108
109         g_object_class_install_property (object_class,
110                                          PROP_STATE,
111                                          g_param_spec_enum ("state",
112                                                             "state",
113                                                             "state",
114                                                             MC_TYPE_PRESENCE,
115                                                             MC_PRESENCE_AVAILABLE,
116                                                             G_PARAM_READWRITE));
117         g_object_class_install_property (object_class,
118                                          PROP_STATUS,
119                                          g_param_spec_string ("status",
120                                                               "status",
121                                                               "status",
122                                                               NULL,
123                                                               G_PARAM_READWRITE));
124         g_object_class_install_property (object_class,
125                                          PROP_FLASH_STATE,
126                                          g_param_spec_enum ("flash-state",
127                                                             "flash-state",
128                                                             "flash-state",
129                                                             MC_TYPE_PRESENCE,
130                                                             MC_PRESENCE_UNSET,
131                                                             G_PARAM_READWRITE));
132
133         g_type_class_add_private (object_class, sizeof (EmpathyIdlePriv));
134 }
135
136 static void
137 empathy_idle_init (EmpathyIdle *idle)
138 {
139         EmpathyIdlePriv *priv;
140         DBusGConnection *system_bus;
141         GError          *error = NULL;
142
143         priv = GET_PRIV (idle);
144
145         priv->is_idle = FALSE;
146         priv->mc = empathy_mission_control_new ();
147         priv->state = mission_control_get_presence_actual (priv->mc, NULL);
148         idle_presence_changed_cb (priv->mc, priv->state, idle);
149
150         dbus_g_proxy_connect_signal (DBUS_G_PROXY (priv->mc),
151                                      "PresenceStatusActual",
152                                      G_CALLBACK (idle_presence_changed_cb),
153                                      idle, NULL);
154
155         priv->gs_proxy = dbus_g_proxy_new_for_name (tp_get_bus (),
156                                                     "org.gnome.ScreenSaver",
157                                                     "/org/gnome/ScreenSaver",
158                                                     "org.gnome.ScreenSaver");
159         if (priv->gs_proxy) {
160                 dbus_g_proxy_add_signal (priv->gs_proxy, "SessionIdleChanged",
161                                          G_TYPE_BOOLEAN,
162                                          G_TYPE_INVALID);
163                 dbus_g_proxy_connect_signal (priv->gs_proxy, "SessionIdleChanged",
164                                              G_CALLBACK (idle_session_idle_changed_cb),
165                                              idle, NULL);
166         } else {
167                 empathy_debug (DEBUG_DOMAIN, "Failed to get gs proxy");
168         }
169
170
171         system_bus = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
172         if (!system_bus) {
173                 empathy_debug (DEBUG_DOMAIN, "Failed to get system bus: %s",
174                               error ? error->message : "No error given");
175         } else {
176                 priv->nm_proxy = dbus_g_proxy_new_for_name (system_bus,
177                                                             "org.freedesktop.NetworkManager",
178                                                             "/org/freedesktop/NetworkManager",
179                                                             "org.freedesktop.NetworkManager");
180         }
181         if (priv->nm_proxy) {
182                 guint nm_status;
183
184                 dbus_g_proxy_add_signal (priv->nm_proxy, "StateChange",
185                                          G_TYPE_UINT, G_TYPE_INVALID);
186                 dbus_g_proxy_connect_signal (priv->nm_proxy, "StateChange",
187                                              G_CALLBACK (idle_nm_state_change_cb),
188                                              idle, NULL);
189                 dbus_g_proxy_call (priv->nm_proxy, "state",
190                                    &error,
191                                    G_TYPE_INVALID,
192                                    G_TYPE_UINT, &nm_status,
193                                    G_TYPE_INVALID);
194
195                 if (error) {
196                         /* Can't get actual status, NM is not working. */
197                         empathy_debug (DEBUG_DOMAIN, 
198                                        "Couldn't get NM state: %s",
199                                        error->message);
200                         g_clear_error (&error);
201                         g_object_unref (priv->nm_proxy);
202                         priv->nm_proxy = NULL;
203                         priv->nm_connected = TRUE;
204                 } else {
205                         priv->nm_connected = (nm_status == NM_STATE_CONNECTED);
206
207                         empathy_debug (DEBUG_DOMAIN, "NetworkManager connected: %s",
208                                        priv->nm_connected ? "Yes" : "No");
209                 }
210
211                 if (!priv->nm_connected) {
212                         priv->saved_state = priv->state;
213                         priv->saved_status = g_strdup (priv->status);
214                 }
215         } else {
216                 empathy_debug (DEBUG_DOMAIN, "Failed to get nm proxy");
217                 priv->nm_connected = TRUE;
218         }
219 }
220
221 static void
222 idle_finalize (GObject *object)
223 {
224         EmpathyIdlePriv *priv;
225
226         priv = GET_PRIV (object);
227
228         g_free (priv->status);
229         g_free (priv->saved_status);
230         g_object_unref (priv->mc);
231
232         if (priv->gs_proxy) {
233                 g_object_unref (priv->gs_proxy);
234         }
235
236         idle_ext_away_stop (EMPATHY_IDLE (object));
237 }
238
239 static void
240 idle_get_property (GObject    *object,
241                    guint       param_id,
242                    GValue     *value,
243                    GParamSpec *pspec)
244 {
245         EmpathyIdlePriv *priv;
246         EmpathyIdle     *idle;
247
248         priv = GET_PRIV (object);
249         idle = EMPATHY_IDLE (object);
250
251         switch (param_id) {
252         case PROP_STATE:
253                 g_value_set_enum (value, empathy_idle_get_state (idle));
254                 break;
255         case PROP_STATUS:
256                 g_value_set_string (value, empathy_idle_get_status (idle));
257                 break;
258         case PROP_FLASH_STATE:
259                 g_value_set_enum (value, empathy_idle_get_flash_state (idle));
260                 break;
261         default:
262                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
263                 break;
264         };
265 }
266
267 static void
268 idle_set_property (GObject      *object,
269                    guint         param_id,
270                    const GValue *value,
271                    GParamSpec   *pspec)
272 {
273         EmpathyIdlePriv *priv;
274         EmpathyIdle     *idle;
275
276         priv = GET_PRIV (object);
277         idle = EMPATHY_IDLE (object);
278
279         switch (param_id) {
280         case PROP_STATE:
281                 empathy_idle_set_state (idle, g_value_get_enum (value));
282                 break;
283         case PROP_STATUS:
284                 empathy_idle_set_status (idle, g_value_get_string (value));
285                 break;
286         case PROP_FLASH_STATE:
287                 empathy_idle_set_flash_state (idle, g_value_get_enum (value));
288                 break;
289         default:
290                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
291                 break;
292         };
293 }
294
295 EmpathyIdle *
296 empathy_idle_new (void)
297 {
298         static EmpathyIdle *idle = NULL;
299
300         if (!idle) {
301                 idle = g_object_new (EMPATHY_TYPE_IDLE, NULL);
302                 g_object_add_weak_pointer (G_OBJECT (idle), (gpointer) &idle);
303         } else {
304                 g_object_ref (idle);
305         }
306
307         return idle;
308 }
309
310 McPresence
311 empathy_idle_get_state (EmpathyIdle *idle)
312 {
313         EmpathyIdlePriv *priv;
314
315         priv = GET_PRIV (idle);
316
317         return priv->state;
318 }
319
320 void
321 empathy_idle_set_state (EmpathyIdle *idle,
322                         McPresence   state)
323 {
324         EmpathyIdlePriv *priv;
325
326         priv = GET_PRIV (idle);
327
328         empathy_idle_set_presence (idle, state, priv->status);
329 }
330
331 const gchar *
332 empathy_idle_get_status (EmpathyIdle *idle)
333 {
334         EmpathyIdlePriv *priv;
335
336         priv = GET_PRIV (idle);
337
338         if (!priv->status) {
339                 return empathy_presence_state_get_default_status (priv->state);
340         }
341
342         return priv->status;
343 }
344
345 void
346 empathy_idle_set_status (EmpathyIdle *idle,
347                          const gchar *status)
348 {
349         EmpathyIdlePriv *priv;
350
351         priv = GET_PRIV (idle);
352
353         empathy_idle_set_presence (idle, priv->state, status);
354 }
355
356 McPresence
357 empathy_idle_get_flash_state (EmpathyIdle *idle)
358 {
359         EmpathyIdlePriv *priv;
360
361         priv = GET_PRIV (idle);
362
363         return priv->flash_state;
364 }
365
366 void
367 empathy_idle_set_flash_state (EmpathyIdle *idle,
368                               McPresence   state)
369 {
370         EmpathyIdlePriv *priv;
371
372         priv = GET_PRIV (idle);
373
374         priv->flash_state = state;
375
376         if (state == MC_PRESENCE_UNSET) {
377         }
378
379         g_object_notify (G_OBJECT (idle), "flash-state");
380 }
381
382 void
383 empathy_idle_set_presence (EmpathyIdle *idle,
384                            McPresence   state,
385                            const gchar *status)
386 {
387         EmpathyIdlePriv *priv;
388         const gchar     *default_status;
389
390         priv = GET_PRIV (idle);
391
392         empathy_debug (DEBUG_DOMAIN, "Changing presence to %s (%d)",
393                        status, state);
394
395         if (!priv->nm_connected) {
396                 empathy_debug (DEBUG_DOMAIN,
397                                "NM not connected, saving requested presence");
398
399                 g_free (priv->saved_status);
400                 priv->saved_state = state;
401                 priv->saved_status = g_strdup (status);
402                 return;
403         }
404
405         /* Do not set translated default messages */
406         default_status = empathy_presence_state_get_default_status (state);
407         if (status && strcmp (status, default_status) == 0) {
408                 status = NULL;
409         }
410
411         mission_control_set_presence (priv->mc,
412                                       state,
413                                       status,
414                                       NULL, NULL);
415 }
416
417 static void
418 idle_presence_changed_cb (MissionControl *mc,
419                           McPresence      state,
420                           EmpathyIdle    *idle)
421 {
422         EmpathyIdlePriv *priv;
423
424         priv = GET_PRIV (idle);
425
426         g_free (priv->status);
427         priv->state = state;
428         priv->status = mission_control_get_presence_message_actual (priv->mc, NULL);
429
430         if (G_STR_EMPTY (priv->status)) {
431                 g_free (priv->status);
432                 priv->status = NULL;
433         }
434
435         g_object_notify (G_OBJECT (idle), "state");
436         g_object_notify (G_OBJECT (idle), "status");
437 }
438
439 static void
440 idle_session_idle_changed_cb (DBusGProxy  *gs_proxy,
441                               gboolean     is_idle,
442                               EmpathyIdle *idle)
443 {
444         EmpathyIdlePriv *priv;
445
446         priv = GET_PRIV (idle);
447
448         empathy_debug (DEBUG_DOMAIN, "Session idle state changed, %s -> %s",
449                       priv->is_idle ? "yes" : "no",
450                       is_idle ? "yes" : "no");
451
452         if (priv->state <= MC_PRESENCE_OFFLINE ||
453             priv->state == MC_PRESENCE_HIDDEN) {
454                 /* We are not online so nothing to do here */
455                 priv->is_idle = is_idle;
456                 return;
457         }
458
459         if (is_idle && !priv->is_idle) {
460                 McPresence new_state;
461                 /* We are now idle */
462
463                 if (priv->state == MC_PRESENCE_AWAY ||
464                            priv->state == MC_PRESENCE_EXTENDED_AWAY) {
465                         /* User set away manually, when coming back we restore
466                          * default presence. */
467                         new_state = priv->state;
468                         priv->saved_state = MC_PRESENCE_AVAILABLE;
469                         priv->saved_status = NULL;
470                 } else {
471                         new_state = MC_PRESENCE_AWAY;
472                         priv->saved_state = priv->state;
473                         priv->saved_status = g_strdup (priv->status);
474                 }
475
476                 empathy_debug (DEBUG_DOMAIN, "Going to autoaway");
477                 empathy_idle_set_state (idle, new_state);
478
479                 idle_ext_away_start (idle);
480         } else if (!is_idle && priv->is_idle) {
481                 /* We are no more idle, restore state */
482                 idle_ext_away_stop (idle);
483
484                 empathy_debug (DEBUG_DOMAIN, "Restoring state to %d %s",
485                               priv->saved_state,
486                               priv->saved_status);
487
488                 empathy_idle_set_presence (idle,
489                                            priv->saved_state,
490                                            priv->saved_status);
491
492                 g_free (priv->saved_status);
493                 priv->saved_status = NULL;
494         }
495
496         priv->is_idle = is_idle;
497 }
498
499 static void
500 idle_nm_state_change_cb (DBusGProxy  *proxy,
501                          guint        state,
502                          EmpathyIdle *idle)
503 {
504         EmpathyIdlePriv *priv;
505
506         priv = GET_PRIV (idle);
507
508         empathy_debug (DEBUG_DOMAIN, "New network state (%d)", state);
509
510         if (state != NM_STATE_CONNECTED && priv->nm_connected) {
511                 /* We are no more connected */
512                 idle_ext_away_stop (idle);
513                 g_free (priv->saved_status);
514                 priv->saved_state = priv->state;
515                 priv->saved_status = g_strdup (priv->status);
516
517                 empathy_idle_set_state (idle, MC_PRESENCE_OFFLINE);
518                 priv->nm_connected = FALSE;
519         }
520         else if (state == NM_STATE_CONNECTED && !priv->nm_connected) {
521                 /* We are now connected */
522                 priv->nm_connected = TRUE;
523                 empathy_idle_set_presence (idle,
524                                            priv->saved_state,
525                                            priv->saved_status);
526         }
527 }
528
529 static void
530 idle_ext_away_start (EmpathyIdle *idle)
531 {
532         EmpathyIdlePriv *priv;
533
534         priv = GET_PRIV (idle);
535
536         idle_ext_away_stop (idle);
537         priv->ext_away_timeout = g_timeout_add (EXT_AWAY_TIME * 1000,
538                                                 (GSourceFunc) idle_ext_away_cb,
539                                                 idle);
540 }
541
542 static void
543 idle_ext_away_stop (EmpathyIdle *idle)
544 {
545         EmpathyIdlePriv *priv;
546
547         priv = GET_PRIV (idle);
548
549         if (priv->ext_away_timeout) {
550                 g_source_remove (priv->ext_away_timeout);
551                 priv->ext_away_timeout = 0;
552         }
553 }
554
555 static gboolean
556 idle_ext_away_cb (EmpathyIdle *idle)
557 {
558         EmpathyIdlePriv *priv;
559
560         priv = GET_PRIV (idle);
561
562         empathy_debug (DEBUG_DOMAIN, "Going to extended autoaway");
563         empathy_idle_set_state (idle, MC_PRESENCE_EXTENDED_AWAY);
564         priv->ext_away_timeout = 0;
565
566         return FALSE;
567 }
568