Oops, I forgot this. This is done internally in libgadu, and not doing it
[pidgin-git.git] / libpurple / idle.c
blob909ae72f00ed58fcea87e15f50c07ae2b897f39a
1 /*
2 * purple
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
6 * source distribution.
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
23 #include "internal.h"
25 #include "connection.h"
26 #include "debug.h"
27 #include "eventloop.h"
28 #include "idle.h"
29 #include "log.h"
30 #include "prefs.h"
31 #include "savedstatuses.h"
32 #include "signals.h"
34 typedef enum
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;
44 /**
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
50 * user returns.
52 static GList *idled_accts = NULL;
54 static guint idle_timer = 0;
56 static time_t last_active_time = 0;
58 static void
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! */
67 return;
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);
75 static void
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! */
86 return;
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
101 * should be set.
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.
114 static void
115 check_idleness(void)
117 time_t time_idle;
118 gboolean auto_away;
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;
142 else
144 /* Don't report idle time */
145 time_idle = 0;
146 report_idle = FALSE;
148 /* If we're not reporting idle, we can still do auto-away.
149 * First try "system" and if that isn't possible, use "purple" */
150 if (auto_away)
152 if ((idle_ui_ops != NULL) && (idle_ui_ops->get_time_idle != NULL))
154 time_idle = idle_ui_ops->get_time_idle();
155 idle_recheck_interval = 1;
157 else
159 time_idle = time(NULL) - last_active_time;
160 idle_recheck_interval = 0;
163 else
165 if (!no_away)
167 no_away = TRUE;
168 purple_savedstatus_set_idleaway(FALSE);
170 time_until_next_idle_event = 0;
171 return;
175 time_until_next_idle_event = idle_poll_seconds - time_idle;
176 if (time_until_next_idle_event < 0)
178 /* If we're already idle, check again as appropriate. */
179 time_until_next_idle_event = idle_recheck_interval;
182 if (auto_away || !no_away)
183 away_seconds = 60 * purple_prefs_get_int("/purple/away/mins_before_away");
185 if (auto_away && time_idle > away_seconds)
187 purple_savedstatus_set_idleaway(TRUE);
188 no_away = FALSE;
190 else if (purple_savedstatus_is_idleaway() && time_idle < away_seconds)
192 purple_savedstatus_set_idleaway(FALSE);
193 if (time_until_next_idle_event == 0 || (away_seconds - time_idle) < time_until_next_idle_event)
194 time_until_next_idle_event = away_seconds - time_idle;
197 /* Idle reporting stuff */
198 if (report_idle && (time_idle >= idle_poll_seconds))
200 GList *l;
201 for (l = purple_connections_get_all(); l != NULL; l = l->next)
203 PurpleConnection *gc = l->data;
204 set_account_idle(purple_connection_get_account(gc), time_idle);
207 else if (!report_idle || (time_idle < idle_poll_seconds ))
209 while (idled_accts != NULL)
210 set_account_unidle(idled_accts->data);
216 * Check idle and set the timer to fire at the next idle-worth event
218 static gboolean
219 check_idleness_timer(void)
221 check_idleness();
222 if (time_until_next_idle_event == 0)
223 idle_timer = 0;
224 else
226 /* +1 for the boundary,
227 * +1 more for g_timeout_add_seconds rounding. */
228 idle_timer = purple_timeout_add_seconds(time_until_next_idle_event + 2, (GSourceFunc)check_idleness_timer, NULL);
230 return FALSE;
233 static void
234 im_msg_sent_cb(PurpleAccount *account, const char *receiver,
235 const char *message, void *data)
237 /* Check our idle time after an IM is sent */
238 check_idleness();
241 static void
242 signing_on_cb(PurpleConnection *gc, void *data)
244 /* When signing on a new account, check if the account should be idle */
245 check_idleness();
248 static void
249 signing_off_cb(PurpleConnection *gc, void *data)
251 PurpleAccount *account;
253 account = purple_connection_get_account(gc);
254 set_account_unidle(account);
257 static void
258 idle_reporting_cb(const char *name, PurplePrefType type, gconstpointer val, gpointer data)
260 if (idle_timer)
261 purple_timeout_remove(idle_timer);
262 idle_timer = 0;
263 check_idleness_timer();
266 void
267 purple_idle_touch()
269 time(&last_active_time);
270 if (!no_away)
272 if (idle_timer)
273 purple_timeout_remove(idle_timer);
274 idle_timer = 0;
275 check_idleness_timer();
279 void
280 purple_idle_set(time_t time)
282 last_active_time = time;
285 void
286 purple_idle_set_ui_ops(PurpleIdleUiOps *ops)
288 idle_ui_ops = ops;
291 PurpleIdleUiOps *
292 purple_idle_get_ui_ops(void)
294 return idle_ui_ops;
297 static void *
298 purple_idle_get_handle(void)
300 static int handle;
302 return &handle;
305 static gboolean _do_purple_idle_touch_cb(gpointer data)
307 int idle_poll_minutes = purple_prefs_get_int("/purple/away/mins_before_away");
309 /* +1 more for g_timeout_add_seconds rounding. */
310 idle_timer = purple_timeout_add_seconds((idle_poll_minutes * 60) + 2, (GSourceFunc)check_idleness_timer, NULL);
312 purple_idle_touch();
314 return FALSE;
318 void
319 purple_idle_init()
321 purple_signal_connect(purple_conversations_get_handle(), "sent-im-msg",
322 purple_idle_get_handle(),
323 PURPLE_CALLBACK(im_msg_sent_cb), NULL);
324 purple_signal_connect(purple_connections_get_handle(), "signing-on",
325 purple_idle_get_handle(),
326 PURPLE_CALLBACK(signing_on_cb), NULL);
327 purple_signal_connect(purple_connections_get_handle(), "signing-off",
328 purple_idle_get_handle(),
329 PURPLE_CALLBACK(signing_off_cb), NULL);
331 purple_prefs_connect_callback(purple_idle_get_handle(), "/purple/away/idle_reporting",
332 idle_reporting_cb, NULL);
334 /* Initialize the idleness asynchronously so it doesn't check idleness,
335 * and potentially try to change the status before the UI is initialized */
336 purple_timeout_add(0, _do_purple_idle_touch_cb, NULL);
340 void
341 purple_idle_uninit()
343 purple_signals_disconnect_by_handle(purple_idle_get_handle());
344 purple_prefs_disconnect_by_handle(purple_idle_get_handle());
346 /* Remove the idle timer */
347 if (idle_timer > 0)
348 purple_timeout_remove(idle_timer);
349 idle_timer = 0;