6b9cfb3b9d02900e8a51575bebe0db6d0b8ac6da
[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 <glib/gi18n.h>
26 #include <dbus/dbus-glib.h>
27
28 #include <libtelepathy/tp-helpers.h>
29
30 #include <libmissioncontrol/mission-control.h>
31
32 #include "empathy-idle.h"
33 #include "gossip-utils.h" 
34 #include "gossip-debug.h"
35
36 #define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \
37                        EMPATHY_TYPE_IDLE, EmpathyIdlePriv))
38
39 #define DEBUG_DOMAIN "Idle"
40
41 /* Number of seconds before entering extended autoaway. */
42 #define EXT_AWAY_TIME (30*60)
43
44 enum {
45         LAST_SIGNAL
46 };
47
48 struct _EmpathyIdlePriv {
49         MissionControl *mc;
50         DBusGProxy     *gs_proxy;
51         gboolean        is_idle;
52         McPresence      saved_state;
53         gchar          *saved_status;
54         guint           ext_away_timeout;
55 };
56
57 static void     empathy_idle_class_init      (EmpathyIdleClass *klass);
58 static void     empathy_idle_init            (EmpathyIdle      *idle);
59 static void     idle_finalize                (GObject          *object);
60 static void     idle_session_idle_changed_cb (DBusGProxy       *gs_proxy,
61                                               gboolean          is_idle,
62                                               EmpathyIdle      *idle);
63 static void     idle_ext_away_start          (EmpathyIdle      *idle);
64 static void     idle_ext_away_stop           (EmpathyIdle      *idle);
65 static gboolean idle_ext_away_cb             (EmpathyIdle      *idle);
66
67 //static guint signals[LAST_SIGNAL];
68
69 G_DEFINE_TYPE (EmpathyIdle, empathy_idle, G_TYPE_OBJECT)
70
71 static void
72 empathy_idle_class_init (EmpathyIdleClass *klass)
73 {
74         GObjectClass *object_class = G_OBJECT_CLASS (klass);
75
76         object_class->finalize = idle_finalize;
77
78         g_type_class_add_private (object_class, sizeof (EmpathyIdlePriv));
79 }
80
81 static void
82 empathy_idle_init (EmpathyIdle *idle)
83 {
84         EmpathyIdlePriv *priv;
85
86         priv = GET_PRIV (idle);
87
88         priv->is_idle = FALSE;
89         priv->mc = gossip_mission_control_new ();
90         priv->gs_proxy = dbus_g_proxy_new_for_name (tp_get_bus (),
91                                                     "org.gnome.ScreenSaver",
92                                                     "/org/gnome/ScreenSaver",
93                                                     "org.gnome.ScreenSaver");
94         if (!priv->gs_proxy) {
95                 gossip_debug (DEBUG_DOMAIN, "Failed to get gs proxy");
96                 return;
97         }
98
99         dbus_g_proxy_add_signal (priv->gs_proxy, "SessionIdleChanged",
100                                  G_TYPE_BOOLEAN,
101                                  G_TYPE_INVALID);
102         dbus_g_proxy_connect_signal (priv->gs_proxy, "SessionIdleChanged",
103                                      G_CALLBACK (idle_session_idle_changed_cb),
104                                      idle, NULL);
105 }
106
107 static void
108 idle_finalize (GObject *object)
109 {
110         EmpathyIdlePriv *priv;
111
112         priv = GET_PRIV (object);
113
114         g_free (priv->saved_status);
115         g_object_unref (priv->mc);
116
117         if (priv->gs_proxy) {
118                 g_object_unref (priv->gs_proxy);
119         }
120
121         idle_ext_away_stop (EMPATHY_IDLE (object));
122 }
123
124 EmpathyIdle *
125 empathy_idle_new (void)
126 {
127         static EmpathyIdle *idle = NULL;
128
129         if (!idle) {
130                 idle = g_object_new (EMPATHY_TYPE_IDLE, NULL);
131                 g_object_add_weak_pointer (G_OBJECT (idle), (gpointer) &idle);
132         } else {
133                 g_object_ref (idle);
134         }
135
136         return idle;
137 }
138
139 static void
140 idle_session_idle_changed_cb (DBusGProxy  *gs_proxy,
141                               gboolean     is_idle,
142                               EmpathyIdle *idle)
143 {
144         EmpathyIdlePriv *priv;
145
146         priv = GET_PRIV (idle);
147
148         gossip_debug (DEBUG_DOMAIN, "Session idle state changed, %s -> %s",
149                       priv->is_idle ? "yes" : "no",
150                       is_idle ? "yes" : "no");
151
152         if (is_idle && !priv->is_idle) {
153                 McPresence new_state = MC_PRESENCE_AWAY;
154                 /* We are now idle, set state to away */
155
156                 priv->saved_state = mission_control_get_presence_actual (priv->mc, NULL);
157                 priv->saved_status = mission_control_get_presence_message_actual (priv->mc, NULL);
158
159                 if (priv->saved_state <= MC_PRESENCE_OFFLINE ||
160                     priv->saved_state == MC_PRESENCE_HIDDEN) {
161                         /* We are not online so nothing to do here */
162                         return;
163                 } else if (priv->saved_state == MC_PRESENCE_AWAY ||
164                            priv->saved_state == MC_PRESENCE_EXTENDED_AWAY) {
165                         /* User set away manually, when coming back we restore
166                          * default presence. */
167                         new_state = priv->saved_state;
168                         priv->saved_state = MC_PRESENCE_AVAILABLE;
169                         priv->saved_status = NULL;
170                 }
171
172                 gossip_debug (DEBUG_DOMAIN, "Going to autoaway");
173                 mission_control_set_presence (priv->mc,
174                                               new_state,
175                                               priv->saved_status,
176                                               NULL, NULL);
177                 idle_ext_away_start (idle);
178         } else if (!is_idle && priv->is_idle) {
179                 /* We are no more idle, restore state */
180                 idle_ext_away_stop (idle);
181
182                 gossip_debug (DEBUG_DOMAIN, "Restoring state to %d %s",
183                               priv->saved_state,
184                               priv->saved_status);
185
186                 mission_control_set_presence (priv->mc,
187                                               priv->saved_state,
188                                               priv->saved_status,
189                                               NULL, NULL);
190                 g_free (priv->saved_status);
191                 priv->saved_status = NULL;
192         }
193
194         priv->is_idle = is_idle;
195 }
196
197 static void
198 idle_ext_away_start (EmpathyIdle *idle)
199 {
200         EmpathyIdlePriv *priv;
201
202         priv = GET_PRIV (idle);
203
204         idle_ext_away_stop (idle);
205         priv->ext_away_timeout = g_timeout_add (EXT_AWAY_TIME * 1000,
206                                                 (GSourceFunc) idle_ext_away_cb,
207                                                 idle);
208 }
209
210 static void
211 idle_ext_away_stop (EmpathyIdle *idle)
212 {
213         EmpathyIdlePriv *priv;
214
215         priv = GET_PRIV (idle);
216
217         if (priv->ext_away_timeout) {
218                 g_source_remove (priv->ext_away_timeout);
219                 priv->ext_away_timeout = 0;
220         }
221 }
222
223 static gboolean
224 idle_ext_away_cb (EmpathyIdle *idle)
225 {
226         EmpathyIdlePriv *priv;
227
228         priv = GET_PRIV (idle);
229
230         gossip_debug (DEBUG_DOMAIN, "Going to extended autoaway");
231         mission_control_set_presence (priv->mc,
232                                       MC_PRESENCE_EXTENDED_AWAY,
233                                       priv->saved_status,
234                                       NULL, NULL);
235
236         priv->ext_away_timeout = 0;
237
238         return FALSE;
239 }
240