1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * Copyright (C) 2007 Collabora Ltd.
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.
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.
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.
20 * Authors: Xavier Claessens <xclaesse@gmail.com>
27 #include <glib/gi18n.h>
28 #include <dbus/dbus-glib.h>
30 #include <libtelepathy/tp-helpers.h>
31 #include <libmissioncontrol/mc-enum-types.h>
33 #include "empathy-idle.h"
34 #include "empathy-utils.h"
35 #include "empathy-debug.h"
37 #define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \
38 EMPATHY_TYPE_IDLE, EmpathyIdlePriv))
40 #define DEBUG_DOMAIN "Idle"
42 /* Number of seconds before entering extended autoaway. */
43 #define EXT_AWAY_TIME (30*60)
53 struct _EmpathyIdlePriv {
58 McPresence flash_state;
60 McPresence saved_state;
63 gboolean nm_connected;
65 gboolean auto_disconnect;
66 guint ext_away_timeout;
69 static void empathy_idle_class_init (EmpathyIdleClass *klass);
70 static void empathy_idle_init (EmpathyIdle *idle);
71 static void idle_finalize (GObject *object);
72 static void idle_get_property (GObject *object,
76 static void idle_set_property (GObject *object,
80 static void idle_presence_changed_cb (MissionControl *mc,
83 static void idle_session_idle_changed_cb (DBusGProxy *gs_proxy,
86 static void idle_nm_state_change_cb (DBusGProxy *proxy,
89 static void idle_ext_away_start (EmpathyIdle *idle);
90 static void idle_ext_away_stop (EmpathyIdle *idle);
91 static gboolean idle_ext_away_cb (EmpathyIdle *idle);
102 G_DEFINE_TYPE (EmpathyIdle, empathy_idle, G_TYPE_OBJECT)
105 empathy_idle_class_init (EmpathyIdleClass *klass)
107 GObjectClass *object_class = G_OBJECT_CLASS (klass);
109 object_class->finalize = idle_finalize;
110 object_class->get_property = idle_get_property;
111 object_class->set_property = idle_set_property;
113 g_object_class_install_property (object_class,
115 g_param_spec_enum ("state",
119 MC_PRESENCE_AVAILABLE,
121 g_object_class_install_property (object_class,
123 g_param_spec_string ("status",
128 g_object_class_install_property (object_class,
130 g_param_spec_enum ("flash-state",
137 g_object_class_install_property (object_class,
139 g_param_spec_boolean ("auto-away",
140 "Automatic set presence to away",
141 "Should it set presence to away if inactive",
145 g_object_class_install_property (object_class,
146 PROP_AUTO_DISCONNECT,
147 g_param_spec_boolean ("auto-disconnect",
148 "Automatic set presence to offline",
149 "Should it set presence to offline if NM is disconnected",
153 g_type_class_add_private (object_class, sizeof (EmpathyIdlePriv));
157 empathy_idle_init (EmpathyIdle *idle)
159 EmpathyIdlePriv *priv;
160 DBusGConnection *system_bus;
161 GError *error = NULL;
163 priv = GET_PRIV (idle);
165 priv->is_idle = FALSE;
166 priv->mc = empathy_mission_control_new ();
167 priv->state = mission_control_get_presence_actual (priv->mc, NULL);
168 idle_presence_changed_cb (priv->mc, priv->state, idle);
170 dbus_g_proxy_connect_signal (DBUS_G_PROXY (priv->mc),
171 "PresenceStatusActual",
172 G_CALLBACK (idle_presence_changed_cb),
175 priv->gs_proxy = dbus_g_proxy_new_for_name (tp_get_bus (),
176 "org.gnome.ScreenSaver",
177 "/org/gnome/ScreenSaver",
178 "org.gnome.ScreenSaver");
179 if (priv->gs_proxy) {
180 dbus_g_proxy_add_signal (priv->gs_proxy, "SessionIdleChanged",
183 dbus_g_proxy_connect_signal (priv->gs_proxy, "SessionIdleChanged",
184 G_CALLBACK (idle_session_idle_changed_cb),
187 empathy_debug (DEBUG_DOMAIN, "Failed to get gs proxy");
191 system_bus = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
193 empathy_debug (DEBUG_DOMAIN, "Failed to get system bus: %s",
194 error ? error->message : "No error given");
196 priv->nm_proxy = dbus_g_proxy_new_for_name (system_bus,
197 "org.freedesktop.NetworkManager",
198 "/org/freedesktop/NetworkManager",
199 "org.freedesktop.NetworkManager");
201 if (priv->nm_proxy) {
204 dbus_g_proxy_add_signal (priv->nm_proxy, "StateChange",
205 G_TYPE_UINT, G_TYPE_INVALID);
206 dbus_g_proxy_connect_signal (priv->nm_proxy, "StateChange",
207 G_CALLBACK (idle_nm_state_change_cb),
209 dbus_g_proxy_call (priv->nm_proxy, "state",
212 G_TYPE_UINT, &nm_status,
216 /* Can't get actual status, NM is not working. */
217 empathy_debug (DEBUG_DOMAIN,
218 "Couldn't get NM state: %s",
220 g_clear_error (&error);
221 g_object_unref (priv->nm_proxy);
222 priv->nm_proxy = NULL;
223 priv->nm_connected = TRUE;
225 priv->nm_connected = (nm_status == NM_STATE_CONNECTED);
227 empathy_debug (DEBUG_DOMAIN, "NetworkManager connected: %s",
228 priv->nm_connected ? "Yes" : "No");
231 if (!priv->nm_connected) {
232 priv->saved_state = priv->state;
233 priv->saved_status = g_strdup (priv->status);
236 empathy_debug (DEBUG_DOMAIN, "Failed to get nm proxy");
237 priv->nm_connected = TRUE;
242 idle_finalize (GObject *object)
244 EmpathyIdlePriv *priv;
246 priv = GET_PRIV (object);
248 g_free (priv->status);
249 g_free (priv->saved_status);
250 g_object_unref (priv->mc);
252 if (priv->gs_proxy) {
253 g_object_unref (priv->gs_proxy);
256 idle_ext_away_stop (EMPATHY_IDLE (object));
260 idle_get_property (GObject *object,
265 EmpathyIdlePriv *priv;
268 priv = GET_PRIV (object);
269 idle = EMPATHY_IDLE (object);
273 g_value_set_enum (value, empathy_idle_get_state (idle));
276 g_value_set_string (value, empathy_idle_get_status (idle));
278 case PROP_FLASH_STATE:
279 g_value_set_enum (value, empathy_idle_get_flash_state (idle));
282 g_value_set_boolean (value, empathy_idle_get_auto_away (idle));
284 case PROP_AUTO_DISCONNECT:
285 g_value_set_boolean (value, empathy_idle_get_auto_disconnect (idle));
288 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
294 idle_set_property (GObject *object,
299 EmpathyIdlePriv *priv;
302 priv = GET_PRIV (object);
303 idle = EMPATHY_IDLE (object);
307 empathy_idle_set_state (idle, g_value_get_enum (value));
310 empathy_idle_set_status (idle, g_value_get_string (value));
312 case PROP_FLASH_STATE:
313 empathy_idle_set_flash_state (idle, g_value_get_enum (value));
316 empathy_idle_set_auto_away (idle, g_value_get_boolean (value));
319 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
325 empathy_idle_new (void)
327 static EmpathyIdle *idle = NULL;
330 idle = g_object_new (EMPATHY_TYPE_IDLE, NULL);
331 g_object_add_weak_pointer (G_OBJECT (idle), (gpointer) &idle);
340 empathy_idle_get_state (EmpathyIdle *idle)
342 EmpathyIdlePriv *priv;
344 priv = GET_PRIV (idle);
350 empathy_idle_set_state (EmpathyIdle *idle,
353 EmpathyIdlePriv *priv;
355 priv = GET_PRIV (idle);
357 empathy_idle_set_presence (idle, state, priv->status);
361 empathy_idle_get_status (EmpathyIdle *idle)
363 EmpathyIdlePriv *priv;
365 priv = GET_PRIV (idle);
368 return empathy_presence_state_get_default_status (priv->state);
375 empathy_idle_set_status (EmpathyIdle *idle,
378 EmpathyIdlePriv *priv;
380 priv = GET_PRIV (idle);
382 empathy_idle_set_presence (idle, priv->state, status);
386 empathy_idle_get_flash_state (EmpathyIdle *idle)
388 EmpathyIdlePriv *priv;
390 priv = GET_PRIV (idle);
392 return priv->flash_state;
396 empathy_idle_set_flash_state (EmpathyIdle *idle,
399 EmpathyIdlePriv *priv;
401 priv = GET_PRIV (idle);
403 priv->flash_state = state;
405 if (state == MC_PRESENCE_UNSET) {
408 g_object_notify (G_OBJECT (idle), "flash-state");
412 empathy_idle_set_presence (EmpathyIdle *idle,
416 EmpathyIdlePriv *priv;
417 const gchar *default_status;
419 priv = GET_PRIV (idle);
421 empathy_debug (DEBUG_DOMAIN, "Changing presence to %s (%d)",
424 if (!priv->nm_connected) {
425 empathy_debug (DEBUG_DOMAIN,
426 "NM not connected, saving requested presence");
428 g_free (priv->saved_status);
429 priv->saved_state = state;
430 priv->saved_status = g_strdup (status);
434 /* Do not set translated default messages */
435 default_status = empathy_presence_state_get_default_status (state);
436 if (status && strcmp (status, default_status) == 0) {
440 mission_control_set_presence (priv->mc,
447 empathy_idle_get_auto_away (EmpathyIdle *idle)
449 EmpathyIdlePriv *priv = GET_PRIV (idle);
451 return priv->auto_away;
455 empathy_idle_set_auto_away (EmpathyIdle *idle,
458 EmpathyIdlePriv *priv = GET_PRIV (idle);
460 priv->auto_away = auto_away;
462 g_object_notify (G_OBJECT (idle), "auto-away");
466 empathy_idle_get_auto_disconnect (EmpathyIdle *idle)
468 EmpathyIdlePriv *priv = GET_PRIV (idle);
470 return priv->auto_disconnect;
474 empathy_idle_set_auto_disconnect (EmpathyIdle *idle,
475 gboolean auto_disconnect)
477 EmpathyIdlePriv *priv = GET_PRIV (idle);
479 priv->auto_disconnect = auto_disconnect;
481 g_object_notify (G_OBJECT (idle), "auto-disconnect");
485 idle_presence_changed_cb (MissionControl *mc,
489 EmpathyIdlePriv *priv;
491 priv = GET_PRIV (idle);
493 g_free (priv->status);
495 priv->status = mission_control_get_presence_message_actual (priv->mc, NULL);
497 if (G_STR_EMPTY (priv->status)) {
498 g_free (priv->status);
502 g_object_notify (G_OBJECT (idle), "state");
503 g_object_notify (G_OBJECT (idle), "status");
507 idle_session_idle_changed_cb (DBusGProxy *gs_proxy,
511 EmpathyIdlePriv *priv;
513 priv = GET_PRIV (idle);
515 empathy_debug (DEBUG_DOMAIN, "Session idle state changed, %s -> %s",
516 priv->is_idle ? "yes" : "no",
517 is_idle ? "yes" : "no");
519 if (priv->state <= MC_PRESENCE_OFFLINE ||
520 priv->state == MC_PRESENCE_HIDDEN ||
522 /* We are not online or we don't want to go auto away,
523 * nothing to do here */
524 priv->is_idle = is_idle;
528 if (is_idle && !priv->is_idle) {
529 McPresence new_state;
530 /* We are now idle */
532 if (priv->state == MC_PRESENCE_AWAY ||
533 priv->state == MC_PRESENCE_EXTENDED_AWAY) {
534 /* User set away manually, when coming back we restore
535 * default presence. */
536 new_state = priv->state;
537 priv->saved_state = MC_PRESENCE_AVAILABLE;
538 priv->saved_status = NULL;
540 new_state = MC_PRESENCE_AWAY;
541 priv->saved_state = priv->state;
542 priv->saved_status = g_strdup (priv->status);
545 empathy_debug (DEBUG_DOMAIN, "Going to autoaway");
546 empathy_idle_set_state (idle, new_state);
548 idle_ext_away_start (idle);
549 } else if (!is_idle && priv->is_idle) {
550 /* We are no more idle, restore state */
551 idle_ext_away_stop (idle);
553 empathy_debug (DEBUG_DOMAIN, "Restoring state to %d %s",
557 empathy_idle_set_presence (idle,
561 g_free (priv->saved_status);
562 priv->saved_status = NULL;
565 priv->is_idle = is_idle;
569 idle_nm_state_change_cb (DBusGProxy *proxy,
573 EmpathyIdlePriv *priv;
575 priv = GET_PRIV (idle);
577 empathy_debug (DEBUG_DOMAIN, "New network state (%d)", state);
579 if (!priv->auto_disconnect) {
583 if (state != NM_STATE_CONNECTED && priv->nm_connected) {
584 /* We are no more connected */
585 idle_ext_away_stop (idle);
586 g_free (priv->saved_status);
587 priv->saved_state = priv->state;
588 priv->saved_status = g_strdup (priv->status);
590 empathy_idle_set_state (idle, MC_PRESENCE_OFFLINE);
591 priv->nm_connected = FALSE;
593 else if (state == NM_STATE_CONNECTED && !priv->nm_connected) {
594 /* We are now connected */
595 priv->nm_connected = TRUE;
596 empathy_idle_set_presence (idle,
603 idle_ext_away_start (EmpathyIdle *idle)
605 EmpathyIdlePriv *priv;
607 priv = GET_PRIV (idle);
609 idle_ext_away_stop (idle);
610 priv->ext_away_timeout = g_timeout_add (EXT_AWAY_TIME * 1000,
611 (GSourceFunc) idle_ext_away_cb,
616 idle_ext_away_stop (EmpathyIdle *idle)
618 EmpathyIdlePriv *priv;
620 priv = GET_PRIV (idle);
622 if (priv->ext_away_timeout) {
623 g_source_remove (priv->ext_away_timeout);
624 priv->ext_away_timeout = 0;
629 idle_ext_away_cb (EmpathyIdle *idle)
631 EmpathyIdlePriv *priv;
633 priv = GET_PRIV (idle);
635 empathy_debug (DEBUG_DOMAIN, "Going to extended autoaway");
636 empathy_idle_set_state (idle, MC_PRESENCE_EXTENDED_AWAY);
637 priv->ext_away_timeout = 0;