11907
|
1 /*
|
|
2 * gaim
|
|
3 *
|
|
4 * Gaim 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.
|
|
7 *
|
|
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.
|
|
12 *
|
|
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.
|
|
17 *
|
|
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
21 *
|
|
22 */
|
|
23 #include "internal.h"
|
|
24
|
|
25 #ifdef USE_SCREENSAVER
|
|
26 # ifndef _WIN32
|
|
27 # include <X11/Xlib.h>
|
|
28 # include <X11/Xutil.h>
|
|
29 # include <X11/extensions/scrnsaver.h>
|
|
30 # include <gdk/gdkx.h>
|
|
31 # else
|
|
32 # include "idletrack.h"
|
|
33 # endif
|
|
34 #endif /* USE_SCREENSAVER */
|
|
35
|
|
36 #include "connection.h"
|
|
37 #include "debug.h"
|
|
38 #include "log.h"
|
|
39 #include "prefs.h"
|
|
40 #include "savedstatuses.h"
|
|
41 #include "signals.h"
|
|
42
|
|
43 #define IDLEMARK 600 /* 10 minutes! */
|
|
44 #define IDLE_CHECK_INTERVAL 20000 /* 20 seconds */
|
|
45
|
|
46 typedef enum
|
|
47 {
|
|
48 GAIM_IDLE_NOT_AWAY = 0,
|
|
49 GAIM_IDLE_AUTO_AWAY,
|
|
50 GAIM_IDLE_AWAY_BUT_NOT_AUTO_AWAY
|
|
51
|
|
52 } GaimAutoAwayState;
|
|
53
|
11975
|
54 /**
|
|
55 * This is needed for the I'dle Mak'er plugin to work correctly. We
|
|
56 * use it to determine if we're the ones who set our accounts idle
|
|
57 * or if someone else did it (the I'dle Mak'er plugin, for example).
|
|
58 * If our accounts are marked as idle and have_set_idle is FALSE and
|
|
59 * the user moves the mouse, then we will NOT unidle our accounts.
|
|
60 */
|
|
61 static gboolean have_set_idle = FALSE;
|
|
62
|
11907
|
63 #ifdef USE_SCREENSAVER
|
|
64 /**
|
|
65 * Get the number of seconds the user has been idle. In Unix-world
|
|
66 * this is based on the X Windows usage. In MS Windows this is based
|
|
67 * on keyboard/mouse usage.
|
|
68 *
|
|
69 * In Debian bug #271639, jwz says:
|
|
70 *
|
|
71 * Gaim should simply ask xscreensaver how long the user has been idle:
|
|
72 * % xscreensaver-command -time
|
|
73 * XScreenSaver 4.18: screen blanked since Tue Sep 14 14:10:45 2004
|
|
74 *
|
|
75 * Or you can monitor the _SCREENSAVER_STATUS property on root window #0.
|
|
76 * Element 0 is the status (0, BLANK, LOCK), element 1 is the time_t since
|
|
77 * the last state change, and subsequent elements are which hack is running
|
|
78 * on the various screens:
|
|
79 * % xprop -f _SCREENSAVER_STATUS 32ac -root _SCREENSAVER_STATUS
|
|
80 * _SCREENSAVER_STATUS(INTEGER) = BLANK, 1095196626, 10, 237
|
|
81 *
|
|
82 * See watch() in xscreensaver/driver/xscreensaver-command.c.
|
|
83 *
|
|
84 * @return The number of seconds the user has been idle.
|
|
85 */
|
|
86 static int
|
|
87 get_idle_time_from_system()
|
|
88 {
|
|
89 #ifndef _WIN32
|
|
90 static XScreenSaverInfo *mit_info = NULL;
|
|
91 int event_base, error_base;
|
|
92 if (XScreenSaverQueryExtension(GDK_DISPLAY(), &event_base, &error_base)) {
|
|
93 if (mit_info == NULL) {
|
|
94 mit_info = XScreenSaverAllocInfo();
|
|
95 }
|
|
96 XScreenSaverQueryInfo(GDK_DISPLAY(), GDK_ROOT_WINDOW(), mit_info);
|
|
97 return (mit_info->idle) / 1000;
|
|
98 } else
|
|
99 return 0;
|
|
100 #else
|
|
101 return (GetTickCount() - wgaim_get_lastactive()) / 1000;
|
|
102 #endif
|
|
103 }
|
|
104 #endif /* USE_SCREENSAVER */
|
|
105
|
|
106 /*
|
|
107 * This function should be called when you think your idle state
|
|
108 * may have changed. Maybe you're over the 10-minute mark and
|
|
109 * Gaim should start reporting idle time to the server. Maybe
|
|
110 * you've returned from being idle. Maybe your auto-away message
|
|
111 * should be set.
|
|
112 *
|
|
113 * There is no harm to calling this many many times, other than
|
|
114 * it will be kinda slow. This is called every 20 seconds by a
|
|
115 * timer set when an account logs in. It is also called when
|
|
116 * you send an IM, a chat, etc.
|
|
117 *
|
|
118 * This function has 3 sections.
|
|
119 * 1. Get your idle time. It will query XScreenSaver or Windows
|
|
120 * or get the Gaim idle time. Whatever.
|
|
121 * 2. Set or unset your auto-away message.
|
|
122 * 3. Report your current idle time to the IM server.
|
|
123 */
|
|
124 gint
|
|
125 gaim_gtk_idle_check(gpointer data)
|
|
126 {
|
|
127 GaimConnection *gc = (GaimConnection *)data;
|
|
128 gboolean report_idle;
|
|
129 GaimAccount *account;
|
11972
|
130 GaimPresence *presence;
|
11907
|
131 time_t t;
|
|
132 int idle_time;
|
|
133
|
|
134 account = gaim_connection_get_account(gc);
|
|
135
|
11972
|
136 presence = gaim_account_get_presence(account);
|
|
137
|
11907
|
138 gaim_signal_emit(gaim_blist_get_handle(), "update-idle");
|
|
139
|
|
140 time(&t);
|
|
141
|
|
142 report_idle = gaim_prefs_get_bool("/gaim/gtk/idle/report");
|
|
143
|
|
144 #ifdef USE_SCREENSAVER
|
11972
|
145 idle_time = get_idle_time_from_system();
|
11907
|
146 #else
|
11972
|
147 /*
|
|
148 * If Gaim wasn't built with xscreensaver support, then
|
|
149 * fallback to calculating our idle time based on when
|
|
150 * we last sent a message.
|
|
151 */
|
|
152 idle_time = t - gc->last_sent_time;
|
11907
|
153 #endif /* USE_SCREENSAVER */
|
|
154
|
|
155 /* Should we become auto-away? */
|
|
156 if (gaim_prefs_get_bool("/core/away/away_when_idle") &&
|
|
157 (idle_time > (60 * gaim_prefs_get_int("/core/away/mins_before_away")))
|
|
158 && (!gc->is_auto_away))
|
|
159 {
|
|
160 if (gaim_presence_is_available(presence))
|
|
161 {
|
|
162 const char *idleaway_name;
|
|
163 GaimSavedStatus *saved_status;
|
|
164
|
|
165 gaim_debug_info("idle", "Making %s auto-away\n",
|
|
166 gaim_account_get_username(account));
|
|
167
|
|
168 /* Mark our accounts "away" using the idleaway status */
|
|
169 idleaway_name = gaim_prefs_get_string("/core/status/idleaway");
|
|
170 saved_status = gaim_savedstatus_find(idleaway_name);
|
|
171 if (saved_status)
|
|
172 gaim_savedstatus_activate(saved_status);
|
|
173
|
|
174 gc->is_auto_away = GAIM_IDLE_AUTO_AWAY;
|
|
175 } else {
|
|
176 gc->is_auto_away = GAIM_IDLE_AWAY_BUT_NOT_AUTO_AWAY;
|
|
177 }
|
|
178
|
|
179 /* Should we return from being auto-away? */
|
|
180 } else if (gc->is_auto_away &&
|
|
181 idle_time < 60 * gaim_prefs_get_int("/core/away/mins_before_away")) {
|
|
182 if (gc->is_auto_away == GAIM_IDLE_AWAY_BUT_NOT_AUTO_AWAY) {
|
|
183 gc->is_auto_away = GAIM_IDLE_NOT_AWAY;
|
|
184 return TRUE;
|
|
185 }
|
|
186 gc->is_auto_away = GAIM_IDLE_NOT_AWAY;
|
|
187
|
|
188 /* XXX STATUS AWAY CORE/UI */
|
|
189 /* Need to set this connection to available here */
|
|
190 }
|
|
191
|
|
192 /* Deal with reporting idleness to the server, if appropriate */
|
11975
|
193 if (report_idle && idle_time >= IDLEMARK && !have_set_idle && !gaim_presence_is_idle(presence)) {
|
11907
|
194 gaim_debug_info("idle", "Setting %s idle %d seconds\n",
|
|
195 gaim_account_get_username(account), idle_time);
|
11972
|
196 gaim_presence_set_idle(presence, TRUE, time(NULL));
|
11975
|
197 have_set_idle = TRUE;
|
|
198 } else if ((!report_idle || idle_time < IDLEMARK) && have_set_idle && gaim_presence_is_idle(presence)) {
|
11907
|
199 gaim_debug_info("idle", "Setting %s unidle\n",
|
|
200 gaim_account_get_username(account));
|
11972
|
201 gaim_presence_set_idle(presence, FALSE, time(NULL));
|
11975
|
202 have_set_idle = FALSE;
|
11907
|
203 }
|
|
204
|
|
205 return TRUE;
|
|
206 }
|
|
207
|
|
208 static void
|
|
209 im_msg_sent_cb(GaimAccount *account, const char *receiver,
|
|
210 const char *message, void *data)
|
|
211 {
|
|
212 GaimConnection *gc = gaim_account_get_connection(account);
|
|
213
|
|
214 /* After an IM is sent, check our idle time */
|
|
215 gaim_gtk_idle_check(gc);
|
|
216 }
|
|
217
|
|
218 static void
|
|
219 remove_idle_timer(GaimConnection *gc)
|
|
220 {
|
|
221 /* Remove any existing idle_timer */
|
|
222 if (gc->idle_timer > 0)
|
|
223 gaim_timeout_remove(gc->idle_timer);
|
|
224 gc->idle_timer = 0;
|
|
225 }
|
|
226
|
|
227 static void
|
|
228 connection_disconnected_cb(GaimConnection *gc, gpointer user_data)
|
|
229 {
|
|
230 remove_idle_timer(gc);
|
|
231 }
|
|
232
|
|
233 static void
|
|
234 connection_connected_cb(GaimConnection *gc, gpointer user_data)
|
|
235 {
|
|
236 /* Now that we are connected, check for idleness every 20 seconds */
|
|
237 remove_idle_timer(gc);
|
|
238 gc->idle_timer = gaim_timeout_add(IDLE_CHECK_INTERVAL, gaim_gtk_idle_check, gc);
|
|
239
|
|
240 /* Immediately update our idleness, in case we connected while idle */
|
|
241 gaim_gtk_idle_check(gc);
|
|
242 }
|
|
243
|
|
244 void *
|
|
245 gaim_gtk_idle_get_handle()
|
|
246 {
|
|
247 static int handle;
|
|
248
|
|
249 return &handle;
|
|
250 }
|
|
251
|
|
252 void
|
|
253 gaim_gtk_idle_init()
|
|
254 {
|
|
255 gaim_signal_connect(gaim_conversations_get_handle(), "sent-im-msg",
|
|
256 gaim_gtk_idle_get_handle(),
|
|
257 GAIM_CALLBACK(im_msg_sent_cb), NULL);
|
|
258
|
|
259 gaim_signal_connect(gaim_connections_get_handle(), "signed-on",
|
|
260 gaim_gtk_idle_get_handle(),
|
|
261 GAIM_CALLBACK(connection_connected_cb), NULL);
|
|
262 gaim_signal_connect(gaim_connections_get_handle(), "signed-off",
|
|
263 gaim_gtk_idle_get_handle(),
|
|
264 GAIM_CALLBACK(connection_disconnected_cb), NULL);
|
|
265 }
|
|
266
|
|
267 void
|
|
268 gaim_gtk_idle_uninit()
|
|
269 {
|
|
270 gaim_signals_disconnect_by_handle(gaim_gtk_idle_get_handle());
|
|
271 }
|