4 * Purple is the legal property of its developers, whose names are too numerous
5 * to list here. Please refer to the COPYRIGHT file distributed with this
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
25 #include "connection.h"
27 #include "eventloop.h"
31 #include "savedstatuses.h"
36 PURPLE_IDLE_NOT_AWAY
= 0,
37 PURPLE_IDLE_AUTO_AWAY
,
38 PURPLE_IDLE_AWAY_BUT_NOT_AUTO_AWAY
40 } PurpleAutoAwayState
;
42 static PurpleIdleUiOps
*idle_ui_ops
= NULL
;
45 * This is needed for the I'dle Mak'er plugin to work correctly. We
46 * use it to determine if we're the ones who set our accounts idle
47 * or if someone else did it (the I'dle Mak'er plugin, for example).
48 * Basically we just keep track of which accounts were set idle by us,
49 * and then we'll only set these specific accounts unidle when the
52 static GList
*idled_accts
= NULL
;
54 static guint idle_timer
= 0;
56 static time_t last_active_time
= 0;
59 set_account_idle(PurpleAccount
*account
, int time_idle
)
61 PurplePresence
*presence
;
63 presence
= purple_account_get_presence(account
);
65 if (purple_presence_is_idle(presence
))
66 /* This account is already idle! */
69 purple_debug_info("idle", "Setting %s idle %d seconds\n",
70 purple_account_get_username(account
), time_idle
);
71 purple_presence_set_idle(presence
, TRUE
, time(NULL
) - time_idle
);
72 idled_accts
= g_list_prepend(idled_accts
, account
);
76 set_account_unidle(PurpleAccount
*account
)
78 PurplePresence
*presence
;
80 presence
= purple_account_get_presence(account
);
82 idled_accts
= g_list_remove(idled_accts
, account
);
84 if (!purple_presence_is_idle(presence
))
85 /* This account is already unidle! */
88 purple_debug_info("idle", "Setting %s unidle\n",
89 purple_account_get_username(account
));
90 purple_presence_set_idle(presence
, FALSE
, 0);
94 static gboolean no_away
= FALSE
;
95 static gint time_until_next_idle_event
;
97 * This function should be called when you think your idle state
98 * may have changed. Maybe you're over the 10-minute mark and
99 * Purple should start reporting idle time to the server. Maybe
100 * you've returned from being idle. Maybe your auto-away message
103 * There is no harm to calling this many many times, other than
104 * it will be kinda slow. This is called by a timer set when
105 * Purple starts. It is also called when you send an IM, a chat, etc.
107 * This function has 3 sections.
108 * 1. Get your idle time. It will query XScreenSaver or Windows
109 * or use the Purple idle time. Whatever.
110 * 2. Set or unset your auto-away message.
111 * 3. Report your current idle time to the IM server.
117 time_t time_idle
= 0;
119 const gchar
*idle_reporting
;
120 gboolean report_idle
= TRUE
;
121 gint away_seconds
= 0;
122 gint idle_recheck_interval
= 0;
123 gint idle_poll_seconds
= purple_prefs_get_int("/purple/away/mins_before_away") * 60;
124 purple_signal_emit(purple_blist_get_handle(), "update-idle");
126 idle_reporting
= purple_prefs_get_string("/purple/away/idle_reporting");
127 auto_away
= purple_prefs_get_bool("/purple/away/away_when_idle");
129 if (purple_strequal(idle_reporting
, "system") &&
130 (idle_ui_ops
!= NULL
) && (idle_ui_ops
->get_time_idle
!= NULL
))
132 /* Use system idle time (mouse or keyboard movement, etc.) */
133 time_idle
= idle_ui_ops
->get_time_idle();
134 idle_recheck_interval
= 1;
136 else if (purple_strequal(idle_reporting
, "purple"))
138 /* Use 'Purple idle' */
139 time_idle
= time(NULL
) - last_active_time
;
140 idle_recheck_interval
= 0;
144 /* Don't report idle time */
147 /* If we're not reporting idle, we can still do auto-away.
148 * First try "system" and if that isn't possible, use "purple" */
151 if ((idle_ui_ops
!= NULL
) && (idle_ui_ops
->get_time_idle
!= NULL
))
153 time_idle
= idle_ui_ops
->get_time_idle();
154 idle_recheck_interval
= 1;
158 time_idle
= time(NULL
) - last_active_time
;
159 idle_recheck_interval
= 0;
167 purple_savedstatus_set_idleaway(FALSE
);
169 time_until_next_idle_event
= 0;
174 time_until_next_idle_event
= idle_poll_seconds
- time_idle
;
175 if (time_until_next_idle_event
< 0)
177 /* If we're already idle, check again as appropriate. */
178 time_until_next_idle_event
= idle_recheck_interval
;
181 if (auto_away
|| !no_away
)
182 away_seconds
= 60 * purple_prefs_get_int("/purple/away/mins_before_away");
184 if (auto_away
&& time_idle
> away_seconds
)
186 purple_savedstatus_set_idleaway(TRUE
);
189 else if (purple_savedstatus_is_idleaway() && time_idle
< away_seconds
)
191 purple_savedstatus_set_idleaway(FALSE
);
192 if (time_until_next_idle_event
== 0 || (away_seconds
- time_idle
) < time_until_next_idle_event
)
193 time_until_next_idle_event
= away_seconds
- time_idle
;
196 /* Idle reporting stuff */
197 if (report_idle
&& (time_idle
>= idle_poll_seconds
))
200 for (l
= purple_connections_get_all(); l
!= NULL
; l
= l
->next
)
202 PurpleConnection
*gc
= l
->data
;
203 set_account_idle(purple_connection_get_account(gc
), time_idle
);
206 else if (!report_idle
|| (time_idle
< idle_poll_seconds
))
208 while (idled_accts
!= NULL
)
209 set_account_unidle(idled_accts
->data
);
215 * Check idle and set the timer to fire at the next idle-worth event
218 check_idleness_timer(void)
221 if (time_until_next_idle_event
== 0)
225 /* +1 for the boundary,
226 * +1 more for g_timeout_add_seconds rounding. */
227 idle_timer
= g_timeout_add_seconds(time_until_next_idle_event
+ 2, (GSourceFunc
)check_idleness_timer
, NULL
);
233 im_msg_sent_cb(PurpleAccount
*account
, PurpleMessage
*msg
, void *data
)
235 /* Check our idle time after an IM is sent */
240 signing_on_cb(PurpleConnection
*gc
, void *data
)
242 /* When signing on a new account, check if the account should be idle */
247 signing_off_cb(PurpleConnection
*gc
, void *data
)
249 PurpleAccount
*account
;
251 account
= purple_connection_get_account(gc
);
252 set_account_unidle(account
);
256 idle_reporting_cb(const char *name
, PurplePrefType type
, gconstpointer val
, gpointer data
)
259 g_source_remove(idle_timer
);
261 check_idleness_timer();
267 time(&last_active_time
);
271 g_source_remove(idle_timer
);
273 check_idleness_timer();
278 purple_idle_set(time_t time
)
280 last_active_time
= time
;
283 static PurpleIdleUiOps
*
284 purple_idle_ui_ops_copy(PurpleIdleUiOps
*ops
)
286 PurpleIdleUiOps
*ops_new
;
288 g_return_val_if_fail(ops
!= NULL
, NULL
);
290 ops_new
= g_new(PurpleIdleUiOps
, 1);
297 purple_idle_ui_ops_get_type(void)
299 static GType type
= 0;
302 type
= g_boxed_type_register_static("PurpleIdleUiOps",
303 (GBoxedCopyFunc
)purple_idle_ui_ops_copy
,
304 (GBoxedFreeFunc
)g_free
);
311 purple_idle_set_ui_ops(PurpleIdleUiOps
*ops
)
317 purple_idle_get_ui_ops(void)
323 purple_idle_get_handle(void)
330 static gboolean
_do_purple_idle_touch_cb(gpointer data
)
332 int idle_poll_minutes
= purple_prefs_get_int("/purple/away/mins_before_away");
334 /* +1 more for g_timeout_add_seconds rounding. */
335 idle_timer
= g_timeout_add_seconds((idle_poll_minutes
* 60) + 2, (GSourceFunc
)check_idleness_timer
, NULL
);
346 purple_signal_connect(purple_conversations_get_handle(), "sent-im-msg",
347 purple_idle_get_handle(),
348 PURPLE_CALLBACK(im_msg_sent_cb
), NULL
);
349 purple_signal_connect(purple_connections_get_handle(), "signing-on",
350 purple_idle_get_handle(),
351 PURPLE_CALLBACK(signing_on_cb
), NULL
);
352 purple_signal_connect(purple_connections_get_handle(), "signing-off",
353 purple_idle_get_handle(),
354 PURPLE_CALLBACK(signing_off_cb
), NULL
);
356 purple_prefs_connect_callback(purple_idle_get_handle(), "/purple/away/idle_reporting",
357 idle_reporting_cb
, NULL
);
359 /* Initialize the idleness asynchronously so it doesn't check idleness,
360 * and potentially try to change the status before the UI is initialized */
361 g_timeout_add(0, _do_purple_idle_touch_cb
, NULL
);
368 purple_signals_disconnect_by_handle(purple_idle_get_handle());
369 purple_prefs_disconnect_by_handle(purple_idle_get_handle());
371 /* Remove the idle timer */
373 g_source_remove(idle_timer
);