Sun, 30 Oct 2005 23:36:51 +0000
[gaim-migrate @ 14202]
SF Patch #1339005 from Sadrul
"This patch is a fix for this small bug:
(1) open a new conversation with some buddy in a contact.
(2) open another conversation with another buddy in the
same contact.
(3) now press space/enter on the first buddy in the
buddy-list. you will notice that the active-buddy in
the conversation doesn't change to the buddy you just
activated."
committer: Richard Laager <rlaager@pidgin.im>
| 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 | ||
| 54 | #ifdef USE_SCREENSAVER | |
| 55 | /** | |
| 56 | * Get the number of seconds the user has been idle. In Unix-world | |
| 57 | * this is based on the X Windows usage. In MS Windows this is based | |
| 58 | * on keyboard/mouse usage. | |
| 59 | * | |
| 60 | * In Debian bug #271639, jwz says: | |
| 61 | * | |
| 62 | * Gaim should simply ask xscreensaver how long the user has been idle: | |
| 63 | * % xscreensaver-command -time | |
| 64 | * XScreenSaver 4.18: screen blanked since Tue Sep 14 14:10:45 2004 | |
| 65 | * | |
| 66 | * Or you can monitor the _SCREENSAVER_STATUS property on root window #0. | |
| 67 | * Element 0 is the status (0, BLANK, LOCK), element 1 is the time_t since | |
| 68 | * the last state change, and subsequent elements are which hack is running | |
| 69 | * on the various screens: | |
| 70 | * % xprop -f _SCREENSAVER_STATUS 32ac -root _SCREENSAVER_STATUS | |
| 71 | * _SCREENSAVER_STATUS(INTEGER) = BLANK, 1095196626, 10, 237 | |
| 72 | * | |
| 73 | * See watch() in xscreensaver/driver/xscreensaver-command.c. | |
| 74 | * | |
| 75 | * @return The number of seconds the user has been idle. | |
| 76 | */ | |
| 77 | static int | |
| 78 | get_idle_time_from_system() | |
| 79 | { | |
| 80 | #ifndef _WIN32 | |
| 81 | static XScreenSaverInfo *mit_info = NULL; | |
| 82 | int event_base, error_base; | |
| 83 | if (XScreenSaverQueryExtension(GDK_DISPLAY(), &event_base, &error_base)) { | |
| 84 | if (mit_info == NULL) { | |
| 85 | mit_info = XScreenSaverAllocInfo(); | |
| 86 | } | |
| 87 | XScreenSaverQueryInfo(GDK_DISPLAY(), GDK_ROOT_WINDOW(), mit_info); | |
| 88 | return (mit_info->idle) / 1000; | |
| 89 | } else | |
| 90 | return 0; | |
| 91 | #else | |
| 92 | return (GetTickCount() - wgaim_get_lastactive()) / 1000; | |
| 93 | #endif | |
| 94 | } | |
| 95 | #endif /* USE_SCREENSAVER */ | |
| 96 | ||
| 97 | /* | |
| 98 | * This function should be called when you think your idle state | |
| 99 | * may have changed. Maybe you're over the 10-minute mark and | |
| 100 | * Gaim should start reporting idle time to the server. Maybe | |
| 101 | * you've returned from being idle. Maybe your auto-away message | |
| 102 | * should be set. | |
| 103 | * | |
| 104 | * There is no harm to calling this many many times, other than | |
| 105 | * it will be kinda slow. This is called every 20 seconds by a | |
| 106 | * timer set when an account logs in. It is also called when | |
| 107 | * you send an IM, a chat, etc. | |
| 108 | * | |
| 109 | * This function has 3 sections. | |
| 110 | * 1. Get your idle time. It will query XScreenSaver or Windows | |
| 111 | * or get the Gaim idle time. Whatever. | |
| 112 | * 2. Set or unset your auto-away message. | |
| 113 | * 3. Report your current idle time to the IM server. | |
| 114 | */ | |
| 115 | gint | |
| 116 | gaim_gtk_idle_check(gpointer data) | |
| 117 | { | |
| 118 | GaimConnection *gc = (GaimConnection *)data; | |
| 119 | gboolean report_idle; | |
| 120 | GaimAccount *account; | |
| 121 | time_t t; | |
| 122 | int idle_time; | |
| 123 | ||
| 124 | account = gaim_connection_get_account(gc); | |
| 125 | ||
| 126 | gaim_signal_emit(gaim_blist_get_handle(), "update-idle"); | |
| 127 | ||
| 128 | time(&t); | |
| 129 | ||
| 130 | report_idle = gaim_prefs_get_bool("/gaim/gtk/idle/report"); | |
| 131 | ||
| 132 | #ifdef USE_SCREENSAVER | |
| 133 | idle_time = get_idle_time_from_system(); | |
| 134 | #else | |
| 135 | /* | |
| 136 | * If Gaim wasn't built with xscreensaver support, then | |
| 137 | * fallback to calculating our idle time based on when | |
| 138 | * we last sent a message. | |
| 139 | */ | |
| 140 | idle_time = t - gc->last_sent_time; | |
| 141 | #endif /* USE_SCREENSAVER */ | |
| 142 | ||
| 143 | /* Should we become auto-away? */ | |
| 144 | if (gaim_prefs_get_bool("/core/away/away_when_idle") && | |
| 145 | (idle_time > (60 * gaim_prefs_get_int("/core/away/mins_before_away"))) | |
| 146 | && (!gc->is_auto_away)) | |
| 147 | { | |
| 148 | GaimPresence *presence; | |
| 149 | ||
| 150 | presence = gaim_account_get_presence(account); | |
| 151 | ||
| 152 | if (gaim_presence_is_available(presence)) | |
| 153 | { | |
| 154 | const char *idleaway_name; | |
| 155 | GaimSavedStatus *saved_status; | |
| 156 | ||
| 157 | gaim_debug_info("idle", "Making %s auto-away\n", | |
| 158 | gaim_account_get_username(account)); | |
| 159 | ||
| 160 | /* Mark our accounts "away" using the idleaway status */ | |
| 161 | idleaway_name = gaim_prefs_get_string("/core/status/idleaway"); | |
| 162 | saved_status = gaim_savedstatus_find(idleaway_name); | |
| 163 | if (saved_status) | |
| 164 | gaim_savedstatus_activate(saved_status); | |
| 165 | ||
| 166 | gc->is_auto_away = GAIM_IDLE_AUTO_AWAY; | |
| 167 | } else { | |
| 168 | gc->is_auto_away = GAIM_IDLE_AWAY_BUT_NOT_AUTO_AWAY; | |
| 169 | } | |
| 170 | ||
| 171 | /* Should we return from being auto-away? */ | |
| 172 | } else if (gc->is_auto_away && | |
| 173 | idle_time < 60 * gaim_prefs_get_int("/core/away/mins_before_away")) { | |
| 174 | if (gc->is_auto_away == GAIM_IDLE_AWAY_BUT_NOT_AUTO_AWAY) { | |
| 175 | gc->is_auto_away = GAIM_IDLE_NOT_AWAY; | |
| 176 | return TRUE; | |
| 177 | } | |
| 178 | gc->is_auto_away = GAIM_IDLE_NOT_AWAY; | |
| 179 | ||
| 180 | /* XXX STATUS AWAY CORE/UI */ | |
| 181 | /* Need to set this connection to available here */ | |
| 182 | } | |
| 183 | ||
| 184 | /* Deal with reporting idleness to the server, if appropriate */ | |
| 185 | if (report_idle && idle_time >= IDLEMARK && !gc->is_idle) { | |
| 186 | gaim_debug_info("idle", "Setting %s idle %d seconds\n", | |
| 187 | gaim_account_get_username(account), idle_time); | |
| 188 | serv_set_idle(gc, idle_time); | |
| 189 | gc->is_idle = 1; | |
| 190 | /* LOG system_log(log_idle, gc, NULL, OPT_LOG_BUDDY_IDLE | OPT_LOG_MY_SIGNON); */ | |
| 191 | } else if ((!report_idle || idle_time < IDLEMARK) && gc->is_idle) { | |
| 192 | gaim_debug_info("idle", "Setting %s unidle\n", | |
| 193 | gaim_account_get_username(account)); | |
| 194 | gc->is_idle = 0; | |
| 195 | serv_set_idle(gc, 0); | |
| 196 | /* LOG system_log(log_unidle, gc, NULL, OPT_LOG_BUDDY_IDLE | OPT_LOG_MY_SIGNON); */ | |
| 197 | } | |
| 198 | ||
| 199 | return TRUE; | |
| 200 | } | |
| 201 | ||
| 202 | static void | |
| 203 | im_msg_sent_cb(GaimAccount *account, const char *receiver, | |
| 204 | const char *message, void *data) | |
| 205 | { | |
| 206 | GaimConnection *gc = gaim_account_get_connection(account); | |
| 207 | ||
| 208 | /* After an IM is sent, check our idle time */ | |
| 209 | gaim_gtk_idle_check(gc); | |
| 210 | } | |
| 211 | ||
| 212 | static void | |
| 213 | remove_idle_timer(GaimConnection *gc) | |
| 214 | { | |
| 215 | /* Remove any existing idle_timer */ | |
| 216 | if (gc->idle_timer > 0) | |
| 217 | gaim_timeout_remove(gc->idle_timer); | |
| 218 | gc->idle_timer = 0; | |
| 219 | } | |
| 220 | ||
| 221 | static void | |
| 222 | connection_disconnected_cb(GaimConnection *gc, gpointer user_data) | |
| 223 | { | |
| 224 | remove_idle_timer(gc); | |
| 225 | } | |
| 226 | ||
| 227 | static void | |
| 228 | connection_connected_cb(GaimConnection *gc, gpointer user_data) | |
| 229 | { | |
| 230 | /* Now that we are connected, check for idleness every 20 seconds */ | |
| 231 | remove_idle_timer(gc); | |
| 232 | gc->idle_timer = gaim_timeout_add(IDLE_CHECK_INTERVAL, gaim_gtk_idle_check, gc); | |
| 233 | ||
| 234 | /* Immediately update our idleness, in case we connected while idle */ | |
| 235 | gaim_gtk_idle_check(gc); | |
| 236 | } | |
| 237 | ||
| 238 | void * | |
| 239 | gaim_gtk_idle_get_handle() | |
| 240 | { | |
| 241 | static int handle; | |
| 242 | ||
| 243 | return &handle; | |
| 244 | } | |
| 245 | ||
| 246 | void | |
| 247 | gaim_gtk_idle_init() | |
| 248 | { | |
| 249 | gaim_signal_connect(gaim_conversations_get_handle(), "sent-im-msg", | |
| 250 | gaim_gtk_idle_get_handle(), | |
| 251 | GAIM_CALLBACK(im_msg_sent_cb), NULL); | |
| 252 | ||
| 253 | gaim_signal_connect(gaim_connections_get_handle(), "signed-on", | |
| 254 | gaim_gtk_idle_get_handle(), | |
| 255 | GAIM_CALLBACK(connection_connected_cb), NULL); | |
| 256 | gaim_signal_connect(gaim_connections_get_handle(), "signed-off", | |
| 257 | gaim_gtk_idle_get_handle(), | |
| 258 | GAIM_CALLBACK(connection_disconnected_cb), NULL); | |
| 259 | } | |
| 260 | ||
| 261 | void | |
| 262 | gaim_gtk_idle_uninit() | |
| 263 | { | |
| 264 | gaim_signals_disconnect_by_handle(gaim_gtk_idle_get_handle()); | |
| 265 | } |