Mercurial > pidgin.yaz
comparison pidgin/plugins/notify.c @ 15374:5fe8042783c1
Rename gtk/ and libgaim/ to pidgin/ and libpurple/
author | Sean Egan <seanegan@gmail.com> |
---|---|
date | Sat, 20 Jan 2007 02:32:10 +0000 |
parents | |
children | bb3bf2f88406 |
comparison
equal
deleted
inserted
replaced
15373:f79e0f4df793 | 15374:5fe8042783c1 |
---|---|
1 /* | |
2 * Gaim buddy notification plugin. | |
3 * | |
4 * Copyright (C) 2000-2001, Eric Warmenhoven (original code) | |
5 * Copyright (C) 2002, Etan Reisner <deryni@eden.rutgers.edu> (rewritten code) | |
6 * Copyright (C) 2003, Christian Hammond (update for changed API) | |
7 * Copyright (C) 2003, Brian Tarricone <bjt23@cornell.edu> (mostly rewritten) | |
8 * Copyright (C) 2003, Mark Doliner (minor cleanup) | |
9 * Copyright (C) 2003, Etan Reisner (largely rewritten again) | |
10 * | |
11 * This program is free software; you can redistribute it and/or modify | |
12 * it under the terms of the GNU General Public License as published by | |
13 * the Free Software Foundation; either version 2 of the License, or | |
14 * (at your option) any later version. | |
15 * | |
16 * This program is distributed in the hope that it will be useful, | |
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
19 * GNU General Public License for more details. | |
20 * | |
21 * You should have received a copy of the GNU General Public License | |
22 * along with this program; if not, write to the Free Software | |
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
24 * | |
25 */ | |
26 | |
27 /* TODO | |
28 * 22:22:17 <seanegan> deryni: speaking of notify.c... you know what else | |
29 * might be a neat feature? | |
30 * 22:22:30 <seanegan> Changing the window icon. | |
31 * 22:23:25 <deryni> seanegan: To what? | |
32 * 22:23:42 <seanegan> deryni: I dunno. Flash it between the regular icon and | |
33 * blank or something. | |
34 * 22:23:53 <deryni> Also I think gaim might re-set that sort of frequently, | |
35 * but I'd have to look. | |
36 * 22:25:16 <seanegan> deryni: I keep my conversations in one workspace and am | |
37 * frequently in an another, and the icon flashing in the pager would be a | |
38 * neat visual clue. | |
39 */ | |
40 | |
41 /* | |
42 * From Etan, 2002: | |
43 * -Added config dialog | |
44 * -Added control over notification method | |
45 * -Added control over when to release notification | |
46 * | |
47 * -Added option to get notification for chats also | |
48 * -Cleaned up code | |
49 * -Added option to notify on click as it's own option | |
50 * rather then as what happens when on focus isn't clicked | |
51 * -Added apply button to change the denotification methods for | |
52 * open conversation windows | |
53 * -Fixed apply to conversations, count now keeps count across applies | |
54 * -Fixed(?) memory leak, and in the process fixed some stupidities | |
55 * -Hit enter when done editing the title string entry box to save it | |
56 * | |
57 * Thanks to Carles Pina i Estany <carles@pinux.info> | |
58 * for count of new messages option | |
59 * | |
60 * From Brian, 20 July 2003: | |
61 * -Use new xml prefs | |
62 * -Better handling of notification states tracking | |
63 * -Better pref change handling | |
64 * -Fixed a possible memleak and possible crash (rare) | |
65 * -Use gtk_window_get_title() rather than gtkwin->title | |
66 * -Other random fixes and cleanups | |
67 * | |
68 * Etan again, 12 August 2003: | |
69 * -Better use of the new xml prefs | |
70 * -Removed all bitmask stuff | |
71 * -Even better pref change handling | |
72 * -Removed unnecessary functions | |
73 * -Reworking of notification/unnotification stuff | |
74 * -Header file include cleanup | |
75 * -General code cleanup | |
76 * | |
77 * Etan yet again, 04 April 2004: | |
78 * -Re-added Urgent option | |
79 * -Re-added unnotify on focus option (still needs work, as it will only | |
80 * react to focus-in events when the entry or history widgets are focused) | |
81 * | |
82 * Sean, 08 January, 2005: | |
83 * -Added Raise option, formally in Gaim proper | |
84 */ | |
85 | |
86 #include "internal.h" | |
87 #include "gtkgaim.h" | |
88 #include "gtkprefs.h" | |
89 | |
90 #include "conversation.h" | |
91 #include "prefs.h" | |
92 #include "signals.h" | |
93 #include "version.h" | |
94 #include "debug.h" | |
95 | |
96 #include "gtkplugin.h" | |
97 #include "gtkutils.h" | |
98 | |
99 #ifndef _WIN32 | |
100 #include <X11/Xatom.h> | |
101 #include <X11/Xlib.h> | |
102 #include <X11/Xutil.h> | |
103 #endif | |
104 | |
105 #define NOTIFY_PLUGIN_ID "gtk-x11-notify" | |
106 | |
107 static GaimPlugin *my_plugin = NULL; | |
108 static GdkAtom _Cardinal = GDK_NONE; | |
109 static GdkAtom _GaimUnseenCount = GDK_NONE; | |
110 | |
111 /* notification set/unset */ | |
112 static int notify(GaimConversation *conv, gboolean increment); | |
113 static void notify_win(GaimGtkWindow *gaimwin); | |
114 static void unnotify(GaimConversation *conv, gboolean reset); | |
115 static int unnotify_cb(GtkWidget *widget, gpointer data, | |
116 GaimConversation *conv); | |
117 | |
118 /* gtk widget callbacks for prefs panel */ | |
119 static void type_toggle_cb(GtkWidget *widget, gpointer data); | |
120 static void method_toggle_cb(GtkWidget *widget, gpointer data); | |
121 static void notify_toggle_cb(GtkWidget *widget, gpointer data); | |
122 static gboolean options_entry_cb(GtkWidget *widget, GdkEventFocus *event, | |
123 gpointer data); | |
124 static void apply_method(void); | |
125 static void apply_notify(void); | |
126 | |
127 /* string function */ | |
128 static void handle_string(GaimGtkWindow *gaimwin); | |
129 | |
130 /* count_title function */ | |
131 static void handle_count_title(GaimGtkWindow *gaimwin); | |
132 | |
133 /* count_xprop function */ | |
134 static void handle_count_xprop(GaimGtkWindow *gaimwin); | |
135 | |
136 /* urgent function */ | |
137 static void handle_urgent(GaimGtkWindow *gaimwin, gboolean set); | |
138 | |
139 /* raise function */ | |
140 static void handle_raise(GaimGtkWindow *gaimwin); | |
141 | |
142 /****************************************/ | |
143 /* Begin doing stuff below this line... */ | |
144 /****************************************/ | |
145 static guint | |
146 count_messages(GaimGtkWindow *gaimwin) | |
147 { | |
148 guint count = 0; | |
149 GList *convs = NULL, *l; | |
150 | |
151 for (convs = gaimwin->gtkconvs; convs != NULL; convs = convs->next) { | |
152 GaimGtkConversation *conv = convs->data; | |
153 for (l = conv->convs; l != NULL; l = l->next) { | |
154 count += GPOINTER_TO_INT(gaim_conversation_get_data(l->data, "notify-message-count")); | |
155 } | |
156 } | |
157 | |
158 return count; | |
159 } | |
160 | |
161 static int | |
162 notify(GaimConversation *conv, gboolean increment) | |
163 { | |
164 gint count; | |
165 gboolean has_focus; | |
166 GaimGtkWindow *gaimwin = NULL; | |
167 | |
168 if (conv == NULL) | |
169 return 0; | |
170 | |
171 /* We want to remove the notifications, but not reset the counter */ | |
172 unnotify(conv, FALSE); | |
173 | |
174 gaimwin = GAIM_GTK_CONVERSATION(conv)->win; | |
175 | |
176 /* If we aren't doing notifications for this type of conversation, return */ | |
177 if (((gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_IM) && | |
178 !gaim_prefs_get_bool("/plugins/gtk/X11/notify/type_im")) || | |
179 ((gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_CHAT) && | |
180 !gaim_prefs_get_bool("/plugins/gtk/X11/notify/type_chat"))) | |
181 return 0; | |
182 | |
183 g_object_get(G_OBJECT(gaimwin->window), | |
184 "has-toplevel-focus", &has_focus, NULL); | |
185 | |
186 if (gaim_prefs_get_bool("/plugins/gtk/X11/notify/type_focused") || | |
187 !has_focus) { | |
188 if (increment) { | |
189 count = GPOINTER_TO_INT(gaim_conversation_get_data(conv, "notify-message-count")); | |
190 count++; | |
191 gaim_conversation_set_data(conv, "notify-message-count", GINT_TO_POINTER(count)); | |
192 } | |
193 | |
194 notify_win(gaimwin); | |
195 } | |
196 | |
197 return 0; | |
198 } | |
199 | |
200 static void | |
201 notify_win(GaimGtkWindow *gaimwin) | |
202 { | |
203 if (count_messages(gaimwin) <= 0) | |
204 return; | |
205 | |
206 if (gaim_prefs_get_bool("/plugins/gtk/X11/notify/method_count")) | |
207 handle_count_title(gaimwin); | |
208 if (gaim_prefs_get_bool("/plugins/gtk/X11/notify/method_count_xprop")) | |
209 handle_count_xprop(gaimwin); | |
210 if (gaim_prefs_get_bool("/plugins/gtk/X11/notify/method_string")) | |
211 handle_string(gaimwin); | |
212 if (gaim_prefs_get_bool("/plugins/gtk/X11/notify/method_urgent")) | |
213 handle_urgent(gaimwin, TRUE); | |
214 if (gaim_prefs_get_bool("/plugins/gtk/X11/notify/method_raise")) | |
215 handle_raise(gaimwin); | |
216 } | |
217 | |
218 static void | |
219 unnotify(GaimConversation *conv, gboolean reset) | |
220 { | |
221 GaimConversation *active_conv = NULL; | |
222 GaimGtkWindow *gaimwin = NULL; | |
223 | |
224 g_return_if_fail(conv != NULL); | |
225 | |
226 gaimwin = GAIM_GTK_CONVERSATION(conv)->win; | |
227 active_conv = gaim_gtk_conv_window_get_active_conversation(gaimwin); | |
228 | |
229 /* reset the conversation window title */ | |
230 gaim_conversation_autoset_title(active_conv); | |
231 | |
232 if (reset) { | |
233 /* Only need to actually remove the urgent hinting here, since | |
234 * removing it just to have it readded in re-notify is an | |
235 * unnecessary couple extra RTs to the server */ | |
236 handle_urgent(gaimwin, FALSE); | |
237 gaim_conversation_set_data(conv, "notify-message-count", GINT_TO_POINTER(0)); | |
238 /* Same logic as for the urgent hint, xprops are also a RT. | |
239 * This needs to go here so that it gets the updated message | |
240 * count. */ | |
241 handle_count_xprop(gaimwin); | |
242 } | |
243 | |
244 return; | |
245 } | |
246 | |
247 static int | |
248 unnotify_cb(GtkWidget *widget, gpointer data, GaimConversation *conv) | |
249 { | |
250 if (GPOINTER_TO_INT(gaim_conversation_get_data(conv, "notify-message-count")) != 0) | |
251 unnotify(conv, TRUE); | |
252 | |
253 return 0; | |
254 } | |
255 | |
256 static gboolean | |
257 message_displayed_cb(GaimAccount *account, const char *who, char *message, | |
258 GaimConversation *conv, GaimMessageFlags flags) | |
259 { | |
260 if ((gaim_conversation_get_type(conv) == GAIM_CONV_TYPE_CHAT && | |
261 gaim_prefs_get_bool("/plugins/gtk/X11/notify/type_chat_nick") && | |
262 !(flags & GAIM_MESSAGE_NICK))) | |
263 return FALSE; | |
264 | |
265 if ((flags & GAIM_MESSAGE_RECV) && !(flags & GAIM_MESSAGE_DELAYED)) | |
266 notify(conv, TRUE); | |
267 | |
268 return FALSE; | |
269 } | |
270 | |
271 static void | |
272 im_sent_im(GaimAccount *account, const char *receiver, const char *message) | |
273 { | |
274 GaimConversation *conv = NULL; | |
275 | |
276 if (gaim_prefs_get_bool("/plugins/gtk/X11/notify/notify_send")) { | |
277 conv = gaim_find_conversation_with_account(GAIM_CONV_TYPE_IM, receiver, account); | |
278 unnotify(conv, TRUE); | |
279 } | |
280 } | |
281 | |
282 static void | |
283 chat_sent_im(GaimAccount *account, const char *message, int id) | |
284 { | |
285 GaimConversation *conv = NULL; | |
286 | |
287 if (gaim_prefs_get_bool("/plugins/gtk/X11/notify/notify_send")) { | |
288 conv = gaim_find_chat(gaim_account_get_connection(account), id); | |
289 unnotify(conv, TRUE); | |
290 } | |
291 } | |
292 | |
293 static int | |
294 attach_signals(GaimConversation *conv) | |
295 { | |
296 GaimGtkConversation *gtkconv = NULL; | |
297 GaimGtkWindow *gtkwin = NULL; | |
298 GSList *imhtml_ids = NULL, *entry_ids = NULL; | |
299 guint id; | |
300 | |
301 gtkconv = GAIM_GTK_CONVERSATION(conv); | |
302 if (!gtkconv) { | |
303 gaim_debug_misc("notify", "Failed to find gtkconv\n"); | |
304 return 0; | |
305 } | |
306 | |
307 gtkwin = gtkconv->win; | |
308 | |
309 if (gaim_prefs_get_bool("/plugins/gtk/X11/notify/notify_focus")) { | |
310 /* TODO should really find a way to make this work no matter | |
311 * where the focus is inside the conv window, without having | |
312 * to bind to focus-in-event on the g(d|t)kwindow */ | |
313 /* try setting the signal on the focus-in-event for | |
314 * gtkwin->notebook->container? */ | |
315 id = g_signal_connect(G_OBJECT(gtkconv->entry), "focus-in-event", | |
316 G_CALLBACK(unnotify_cb), conv); | |
317 entry_ids = g_slist_append(entry_ids, GUINT_TO_POINTER(id)); | |
318 | |
319 id = g_signal_connect(G_OBJECT(gtkconv->imhtml), "focus-in-event", | |
320 G_CALLBACK(unnotify_cb), conv); | |
321 imhtml_ids = g_slist_append(imhtml_ids, GUINT_TO_POINTER(id)); | |
322 } | |
323 | |
324 if (gaim_prefs_get_bool("/plugins/gtk/X11/notify/notify_click")) { | |
325 /* TODO similarly should really find a way to allow for | |
326 * clicking in other places of the window */ | |
327 id = g_signal_connect(G_OBJECT(gtkconv->entry), "button-press-event", | |
328 G_CALLBACK(unnotify_cb), conv); | |
329 entry_ids = g_slist_append(entry_ids, GUINT_TO_POINTER(id)); | |
330 | |
331 id = g_signal_connect(G_OBJECT(gtkconv->imhtml), "button-press-event", | |
332 G_CALLBACK(unnotify_cb), conv); | |
333 imhtml_ids = g_slist_append(imhtml_ids, GUINT_TO_POINTER(id)); | |
334 } | |
335 | |
336 if (gaim_prefs_get_bool("/plugins/gtk/X11/notify/notify_type")) { | |
337 id = g_signal_connect(G_OBJECT(gtkconv->entry), "key-press-event", | |
338 G_CALLBACK(unnotify_cb), conv); | |
339 entry_ids = g_slist_append(entry_ids, GUINT_TO_POINTER(id)); | |
340 } | |
341 | |
342 gaim_conversation_set_data(conv, "notify-imhtml-signals", imhtml_ids); | |
343 gaim_conversation_set_data(conv, "notify-entry-signals", entry_ids); | |
344 | |
345 return 0; | |
346 } | |
347 | |
348 static void | |
349 detach_signals(GaimConversation *conv) | |
350 { | |
351 GaimGtkConversation *gtkconv = NULL; | |
352 GaimGtkWindow *gtkwin = NULL; | |
353 GSList *ids = NULL, *l; | |
354 | |
355 gtkconv = GAIM_GTK_CONVERSATION(conv); | |
356 if (!gtkconv) | |
357 return; | |
358 gtkwin = gtkconv->win; | |
359 | |
360 ids = gaim_conversation_get_data(conv, "notify-imhtml-signals"); | |
361 for (l = ids; l != NULL; l = l->next) | |
362 g_signal_handler_disconnect(gtkconv->imhtml, GPOINTER_TO_INT(l->data)); | |
363 g_slist_free(ids); | |
364 | |
365 ids = gaim_conversation_get_data(conv, "notify-entry-signals"); | |
366 for (l = ids; l != NULL; l = l->next) | |
367 g_signal_handler_disconnect(gtkconv->entry, GPOINTER_TO_INT(l->data)); | |
368 g_slist_free(ids); | |
369 | |
370 gaim_conversation_set_data(conv, "notify-message-count", GINT_TO_POINTER(0)); | |
371 | |
372 gaim_conversation_set_data(conv, "notify-imhtml-signals", NULL); | |
373 gaim_conversation_set_data(conv, "notify-entry-signals", NULL); | |
374 } | |
375 | |
376 static void | |
377 conv_created(GaimConversation *conv) | |
378 { | |
379 gaim_conversation_set_data(conv, "notify-message-count", | |
380 GINT_TO_POINTER(0)); | |
381 | |
382 /* always attach the signals, notify() will take care of conversation | |
383 * type checking */ | |
384 attach_signals(conv); | |
385 } | |
386 | |
387 static void | |
388 conv_switched(GaimConversation *conv) | |
389 { | |
390 #if 0 | |
391 GaimGtkWindow *gaimwin = gaim_conversation_get_window(new_conv); | |
392 #endif | |
393 | |
394 /* | |
395 * If the conversation was switched, then make sure we re-notify | |
396 * because Gaim will have overwritten our custom window title. | |
397 */ | |
398 notify(conv, FALSE); | |
399 | |
400 #if 0 | |
401 printf("conv_switched - %p - %p\n", old_conv, new_conv); | |
402 printf("count - %d\n", count_messages(gaimwin)); | |
403 if (gaim_prefs_get_bool("/plugins/gtk/X11/notify/notify_switch")) | |
404 unnotify(new_conv, FALSE); | |
405 else { | |
406 /* if we don't have notification on the window then we don't want to | |
407 * re-notify it */ | |
408 if (count_messages(gaimwin)) | |
409 notify_win(gaimwin); | |
410 } | |
411 #endif | |
412 } | |
413 | |
414 static void | |
415 deleting_conv(GaimConversation *conv) | |
416 { | |
417 GaimGtkWindow *gaimwin = NULL; | |
418 | |
419 detach_signals(conv); | |
420 | |
421 gaimwin = GAIM_GTK_CONVERSATION(conv)->win; | |
422 | |
423 handle_urgent(gaimwin, FALSE); | |
424 gaim_conversation_set_data(conv, "notify-message-count", GINT_TO_POINTER(0)); | |
425 | |
426 return; | |
427 | |
428 #if 0 | |
429 /* i think this line crashes */ | |
430 if (count_messages(gaimwin)) | |
431 notify_win(gaimwin); | |
432 #endif | |
433 } | |
434 | |
435 #if 0 | |
436 static void | |
437 conversation_dragging(GaimConversation *active_conv, | |
438 GaimGtkWindow *old_gaimwin, | |
439 GaimGtkWindow *new_gaimwin) | |
440 { | |
441 if (old_gaimwin != new_gaimwin) { | |
442 if (old_gaimwin == NULL) { | |
443 /* | |
444 gaim_conversation_autoset_title(active_conv); | |
445 handle_urgent(new_gaimwin, FALSE); | |
446 */ | |
447 | |
448 if (count_messages(new_gaimwin)) | |
449 notify_win(new_gaimwin); | |
450 } else { | |
451 printf("if else count = %d\n", count_messages(new_gaimwin)); | |
452 printf("if else count = %d\n", count_messages(old_gaimwin)); | |
453 /* | |
454 GaimConversation *old_active_conv = NULL; | |
455 old_active_conv = gaim_conv_window_get_active_conversation(new_gaimwin); | |
456 | |
457 gaim_conversation_autoset_title(old_active_conv); | |
458 handle_urgent(old_gaimwin, FALSE); | |
459 | |
460 if (count_messages(old_gaimwin)) | |
461 notify_win(old_gaimwin); | |
462 | |
463 gaim_conversation_autoset_title(active_conv); | |
464 handle_urgent(new_gaimwin, FALSE); | |
465 | |
466 if (count_messages(new_gaimwin)) | |
467 notify_win(new_gaimwin); | |
468 */ | |
469 } | |
470 } else { | |
471 printf("else count = %d\n", count_messages(new_gaimwin)); | |
472 printf("else count = %d\n", count_messages(old_gaimwin)); | |
473 /* | |
474 gaim_conversation_autoset_title(active_conv); | |
475 handle_urgent(old_gaimwin, FALSE); | |
476 | |
477 if (count_messages(old_gaimwin)) | |
478 notify_win(old_gaimwin); | |
479 */ | |
480 } | |
481 } | |
482 #endif | |
483 | |
484 static void | |
485 handle_string(GaimGtkWindow *gaimwin) | |
486 { | |
487 GtkWindow *window = NULL; | |
488 gchar newtitle[256]; | |
489 | |
490 g_return_if_fail(gaimwin != NULL); | |
491 | |
492 window = GTK_WINDOW(gaimwin->window); | |
493 g_return_if_fail(window != NULL); | |
494 | |
495 g_snprintf(newtitle, sizeof(newtitle), "%s%s", | |
496 gaim_prefs_get_string("/plugins/gtk/X11/notify/title_string"), | |
497 gtk_window_get_title(window)); | |
498 gtk_window_set_title(window, newtitle); | |
499 } | |
500 | |
501 static void | |
502 handle_count_title(GaimGtkWindow *gaimwin) | |
503 { | |
504 GtkWindow *window; | |
505 char newtitle[256]; | |
506 | |
507 g_return_if_fail(gaimwin != NULL); | |
508 | |
509 window = GTK_WINDOW(gaimwin->window); | |
510 g_return_if_fail(window != NULL); | |
511 | |
512 g_snprintf(newtitle, sizeof(newtitle), "[%d] %s", | |
513 count_messages(gaimwin), gtk_window_get_title(window)); | |
514 gtk_window_set_title(window, newtitle); | |
515 } | |
516 | |
517 static void | |
518 handle_count_xprop(GaimGtkWindow *gaimwin) | |
519 { | |
520 #ifndef _WIN32 | |
521 guint count; | |
522 GtkWidget *window; | |
523 GdkWindow *gdkwin; | |
524 | |
525 window = gaimwin->window; | |
526 g_return_if_fail(window != NULL); | |
527 | |
528 if (_GaimUnseenCount == GDK_NONE) { | |
529 _GaimUnseenCount = gdk_atom_intern("_GAIM_UNSEEN_COUNT", FALSE); | |
530 } | |
531 | |
532 if (_Cardinal == GDK_NONE) { | |
533 _Cardinal = gdk_atom_intern("CARDINAL", FALSE); | |
534 } | |
535 | |
536 count = count_messages(gaimwin); | |
537 gdkwin = window->window; | |
538 | |
539 gdk_property_change(gdkwin, _GaimUnseenCount, _Cardinal, 32, | |
540 GDK_PROP_MODE_REPLACE, (guchar *) &count, 1); | |
541 #endif | |
542 } | |
543 | |
544 static void | |
545 handle_urgent(GaimGtkWindow *win, gboolean set) | |
546 { | |
547 #ifndef _WIN32 | |
548 gaim_gtk_set_urgent(GTK_WINDOW(win->window), set); | |
549 #endif | |
550 } | |
551 | |
552 static void | |
553 handle_raise(GaimGtkWindow *gaimwin) | |
554 { | |
555 gaim_gtk_conv_window_raise(gaimwin); | |
556 } | |
557 | |
558 static void | |
559 type_toggle_cb(GtkWidget *widget, gpointer data) | |
560 { | |
561 gboolean on = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)); | |
562 gchar pref[256]; | |
563 | |
564 g_snprintf(pref, sizeof(pref), "/plugins/gtk/X11/notify/%s", | |
565 (char *)data); | |
566 | |
567 gaim_prefs_set_bool(pref, on); | |
568 } | |
569 | |
570 static void | |
571 method_toggle_cb(GtkWidget *widget, gpointer data) | |
572 { | |
573 gboolean on = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)); | |
574 gchar pref[256]; | |
575 | |
576 g_snprintf(pref, sizeof(pref), "/plugins/gtk/X11/notify/%s", | |
577 (char *)data); | |
578 | |
579 gaim_prefs_set_bool(pref, on); | |
580 | |
581 if (!strcmp(data, "method_string")) { | |
582 GtkWidget *entry = g_object_get_data(G_OBJECT(widget), "title-entry"); | |
583 gtk_widget_set_sensitive(entry, on); | |
584 | |
585 gaim_prefs_set_string("/plugins/gtk/X11/notify/title_string", | |
586 gtk_entry_get_text(GTK_ENTRY(entry))); | |
587 } | |
588 | |
589 apply_method(); | |
590 } | |
591 | |
592 static void | |
593 notify_toggle_cb(GtkWidget *widget, gpointer data) | |
594 { | |
595 gboolean on = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)); | |
596 gchar pref[256]; | |
597 | |
598 g_snprintf(pref, sizeof(pref), "/plugins/gtk/X11/notify/%s", | |
599 (char *)data); | |
600 | |
601 gaim_prefs_set_bool(pref, on); | |
602 | |
603 apply_notify(); | |
604 } | |
605 | |
606 static gboolean | |
607 options_entry_cb(GtkWidget *widget, GdkEventFocus *evt, gpointer data) | |
608 { | |
609 if (data == NULL) | |
610 return FALSE; | |
611 | |
612 if (!strcmp(data, "method_string")) { | |
613 gaim_prefs_set_string("/plugins/gtk/X11/notify/title_string", | |
614 gtk_entry_get_text(GTK_ENTRY(widget))); | |
615 } | |
616 | |
617 apply_method(); | |
618 | |
619 return FALSE; | |
620 } | |
621 | |
622 static void | |
623 apply_method() | |
624 { | |
625 GList *convs; | |
626 GaimGtkWindow *gaimwin = NULL; | |
627 | |
628 for (convs = gaim_get_conversations(); convs != NULL; | |
629 convs = convs->next) { | |
630 GaimConversation *conv = (GaimConversation *)convs->data; | |
631 | |
632 /* remove notifications */ | |
633 unnotify(conv, FALSE); | |
634 | |
635 gaimwin = GAIM_GTK_CONVERSATION(conv)->win; | |
636 if (GPOINTER_TO_INT(gaim_conversation_get_data(conv, "notify-message-count")) != 0) | |
637 /* reattach appropriate notifications */ | |
638 notify(conv, FALSE); | |
639 } | |
640 } | |
641 | |
642 static void | |
643 apply_notify() | |
644 { | |
645 GList *convs = gaim_get_conversations(); | |
646 | |
647 while (convs) { | |
648 GaimConversation *conv = (GaimConversation *)convs->data; | |
649 | |
650 /* detach signals */ | |
651 detach_signals(conv); | |
652 /* reattach appropriate signals */ | |
653 attach_signals(conv); | |
654 | |
655 convs = convs->next; | |
656 } | |
657 } | |
658 | |
659 static GtkWidget * | |
660 get_config_frame(GaimPlugin *plugin) | |
661 { | |
662 GtkWidget *ret = NULL, *frame = NULL; | |
663 GtkWidget *vbox = NULL, *hbox = NULL; | |
664 GtkWidget *toggle = NULL, *entry = NULL, *ref; | |
665 | |
666 ret = gtk_vbox_new(FALSE, 18); | |
667 gtk_container_set_border_width(GTK_CONTAINER (ret), 12); | |
668 | |
669 /*---------- "Notify For" ----------*/ | |
670 frame = gaim_gtk_make_frame(ret, _("Notify For")); | |
671 vbox = gtk_vbox_new(FALSE, 5); | |
672 gtk_container_add(GTK_CONTAINER(frame), vbox); | |
673 | |
674 toggle = gtk_check_button_new_with_mnemonic(_("_IM windows")); | |
675 gtk_box_pack_start(GTK_BOX(vbox), toggle, FALSE, FALSE, 0); | |
676 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle), | |
677 gaim_prefs_get_bool("/plugins/gtk/X11/notify/type_im")); | |
678 g_signal_connect(G_OBJECT(toggle), "toggled", | |
679 G_CALLBACK(type_toggle_cb), "type_im"); | |
680 | |
681 toggle = gtk_check_button_new_with_mnemonic(_("C_hat windows")); | |
682 gtk_box_pack_start(GTK_BOX(vbox), toggle, FALSE, FALSE, 0); | |
683 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle), | |
684 gaim_prefs_get_bool("/plugins/gtk/X11/notify/type_chat")); | |
685 g_signal_connect(G_OBJECT(toggle), "toggled", | |
686 G_CALLBACK(type_toggle_cb), "type_chat"); | |
687 | |
688 ref = toggle; | |
689 toggle = gtk_check_button_new_with_mnemonic(_("\t_Only when someone says your screen name")); | |
690 gtk_box_pack_start(GTK_BOX(vbox), toggle, FALSE, FALSE, 0); | |
691 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle), | |
692 gaim_prefs_get_bool("/plugins/gtk/X11/notify/type_chat_nick")); | |
693 g_signal_connect(G_OBJECT(toggle), "toggled", | |
694 G_CALLBACK(type_toggle_cb), "type_chat_nick"); | |
695 gtk_widget_set_sensitive(toggle, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(ref))); | |
696 g_signal_connect(G_OBJECT(ref), "toggled", | |
697 G_CALLBACK(gaim_gtk_toggle_sensitive), toggle); | |
698 | |
699 toggle = gtk_check_button_new_with_mnemonic(_("_Focused windows")); | |
700 gtk_box_pack_start(GTK_BOX(vbox), toggle, FALSE, FALSE, 0); | |
701 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle), | |
702 gaim_prefs_get_bool("/plugins/gtk/X11/notify/type_focused")); | |
703 g_signal_connect(G_OBJECT(toggle), "toggled", | |
704 G_CALLBACK(type_toggle_cb), "type_focused"); | |
705 | |
706 /*---------- "Notification Methods" ----------*/ | |
707 frame = gaim_gtk_make_frame(ret, _("Notification Methods")); | |
708 vbox = gtk_vbox_new(FALSE, 5); | |
709 gtk_container_add(GTK_CONTAINER(frame), vbox); | |
710 | |
711 /* String method button */ | |
712 hbox = gtk_hbox_new(FALSE, 18); | |
713 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); | |
714 toggle = gtk_check_button_new_with_mnemonic(_("Prepend _string into window title:")); | |
715 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle), | |
716 gaim_prefs_get_bool("/plugins/gtk/X11/notify/method_string")); | |
717 gtk_box_pack_start(GTK_BOX(hbox), toggle, FALSE, FALSE, 0); | |
718 | |
719 entry = gtk_entry_new(); | |
720 gtk_box_pack_start(GTK_BOX(hbox), entry, FALSE, FALSE, 0); | |
721 gtk_entry_set_max_length(GTK_ENTRY(entry), 10); | |
722 gtk_widget_set_sensitive(GTK_WIDGET(entry), | |
723 gaim_prefs_get_bool("/plugins/gtk/X11/notify/method_string")); | |
724 gtk_entry_set_text(GTK_ENTRY(entry), | |
725 gaim_prefs_get_string("/plugins/gtk/X11/notify/title_string")); | |
726 g_object_set_data(G_OBJECT(toggle), "title-entry", entry); | |
727 g_signal_connect(G_OBJECT(toggle), "toggled", | |
728 G_CALLBACK(method_toggle_cb), "method_string"); | |
729 g_signal_connect(G_OBJECT(entry), "focus-out-event", | |
730 G_CALLBACK(options_entry_cb), "method_string"); | |
731 | |
732 /* Count method button */ | |
733 toggle = gtk_check_button_new_with_mnemonic(_("Insert c_ount of new messages into window title")); | |
734 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle), | |
735 gaim_prefs_get_bool("/plugins/gtk/X11/notify/method_count")); | |
736 gtk_box_pack_start(GTK_BOX(vbox), toggle, FALSE, FALSE, 0); | |
737 g_signal_connect(G_OBJECT(toggle), "toggled", | |
738 G_CALLBACK(method_toggle_cb), "method_count"); | |
739 | |
740 #ifndef _WIN32 | |
741 /* Count xprop method button */ | |
742 toggle = gtk_check_button_new_with_mnemonic(_("Insert count of new message into _X property")); | |
743 gtk_box_pack_start(GTK_BOX(vbox), toggle, FALSE, FALSE, 0); | |
744 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle), | |
745 gaim_prefs_get_bool("/plugins/gtk/X11/notify/method_count_xprop")); | |
746 g_signal_connect(G_OBJECT(toggle), "toggled", | |
747 G_CALLBACK(method_toggle_cb), "method_count_xprop"); | |
748 | |
749 /* Urgent method button */ | |
750 toggle = gtk_check_button_new_with_mnemonic(_("Set window manager \"_URGENT\" hint")); | |
751 gtk_box_pack_start(GTK_BOX(vbox), toggle, FALSE, FALSE, 0); | |
752 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle), | |
753 gaim_prefs_get_bool("/plugins/gtk/X11/notify/method_urgent")); | |
754 g_signal_connect(G_OBJECT(toggle), "toggled", | |
755 G_CALLBACK(method_toggle_cb), "method_urgent"); | |
756 #endif | |
757 | |
758 /* Raise window method button */ | |
759 toggle = gtk_check_button_new_with_mnemonic(_("R_aise conversation window")); | |
760 gtk_box_pack_start(GTK_BOX(vbox), toggle, FALSE, FALSE, 0); | |
761 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle), | |
762 gaim_prefs_get_bool("/plugins/gtk/X11/notify/method_raise")); | |
763 g_signal_connect(G_OBJECT(toggle), "toggled", | |
764 G_CALLBACK(method_toggle_cb), "method_raise"); | |
765 | |
766 /*---------- "Notification Removals" ----------*/ | |
767 frame = gaim_gtk_make_frame(ret, _("Notification Removal")); | |
768 vbox = gtk_vbox_new(FALSE, 5); | |
769 gtk_container_add(GTK_CONTAINER(frame), vbox); | |
770 | |
771 /* Remove on focus button */ | |
772 toggle = gtk_check_button_new_with_mnemonic(_("Remove when conversation window _gains focus")); | |
773 gtk_box_pack_start(GTK_BOX(vbox), toggle, FALSE, FALSE, 0); | |
774 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle), | |
775 gaim_prefs_get_bool("/plugins/gtk/X11/notify/notify_focus")); | |
776 g_signal_connect(G_OBJECT(toggle), "toggled", G_CALLBACK(notify_toggle_cb), "notify_focus"); | |
777 | |
778 /* Remove on click button */ | |
779 toggle = gtk_check_button_new_with_mnemonic(_("Remove when conversation window _receives click")); | |
780 gtk_box_pack_start(GTK_BOX(vbox), toggle, FALSE, FALSE, 0); | |
781 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle), | |
782 gaim_prefs_get_bool("/plugins/gtk/X11/notify/notify_click")); | |
783 g_signal_connect(G_OBJECT(toggle), "toggled", | |
784 G_CALLBACK(notify_toggle_cb), "notify_click"); | |
785 | |
786 /* Remove on type button */ | |
787 toggle = gtk_check_button_new_with_mnemonic(_("Remove when _typing in conversation window")); | |
788 gtk_box_pack_start(GTK_BOX(vbox), toggle, FALSE, FALSE, 0); | |
789 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle), | |
790 gaim_prefs_get_bool("/plugins/gtk/X11/notify/notify_type")); | |
791 g_signal_connect(G_OBJECT(toggle), "toggled", | |
792 G_CALLBACK(notify_toggle_cb), "notify_type"); | |
793 | |
794 /* Remove on message send button */ | |
795 toggle = gtk_check_button_new_with_mnemonic(_("Remove when a _message gets sent")); | |
796 gtk_box_pack_start(GTK_BOX(vbox), toggle, FALSE, FALSE, 0); | |
797 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle), | |
798 gaim_prefs_get_bool("/plugins/gtk/X11/notify/notify_send")); | |
799 g_signal_connect(G_OBJECT(toggle), "toggled", | |
800 G_CALLBACK(notify_toggle_cb), "notify_send"); | |
801 | |
802 #if 0 | |
803 /* Remove on conversation switch button */ | |
804 toggle = gtk_check_button_new_with_mnemonic(_("Remove on switch to conversation ta_b")); | |
805 gtk_box_pack_start(GTK_BOX(vbox), toggle, FALSE, FALSE, 0); | |
806 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle), | |
807 gaim_prefs_get_bool("/plugins/gtk/X11/notify/notify_switch")); | |
808 g_signal_connect(G_OBJECT(toggle), "toggled", | |
809 G_CALLBACK(notify_toggle_cb), "notify_switch"); | |
810 #endif | |
811 | |
812 gtk_widget_show_all(ret); | |
813 return ret; | |
814 } | |
815 | |
816 static gboolean | |
817 plugin_load(GaimPlugin *plugin) | |
818 { | |
819 GList *convs = gaim_get_conversations(); | |
820 void *conv_handle = gaim_conversations_get_handle(); | |
821 void *gtk_conv_handle = gaim_gtk_conversations_get_handle(); | |
822 | |
823 my_plugin = plugin; | |
824 | |
825 gaim_signal_connect(gtk_conv_handle, "displayed-im-msg", plugin, | |
826 GAIM_CALLBACK(message_displayed_cb), NULL); | |
827 gaim_signal_connect(gtk_conv_handle, "displayed-chat-msg", plugin, | |
828 GAIM_CALLBACK(message_displayed_cb), NULL); | |
829 gaim_signal_connect(gtk_conv_handle, "conversation-switched", plugin, | |
830 GAIM_CALLBACK(conv_switched), NULL); | |
831 gaim_signal_connect(conv_handle, "sent-im-msg", plugin, | |
832 GAIM_CALLBACK(im_sent_im), NULL); | |
833 gaim_signal_connect(conv_handle, "sent-chat-msg", plugin, | |
834 GAIM_CALLBACK(chat_sent_im), NULL); | |
835 gaim_signal_connect(conv_handle, "conversation-created", plugin, | |
836 GAIM_CALLBACK(conv_created), NULL); | |
837 gaim_signal_connect(conv_handle, "chat-joined", plugin, | |
838 GAIM_CALLBACK(conv_created), NULL); | |
839 gaim_signal_connect(conv_handle, "deleting-conversation", plugin, | |
840 GAIM_CALLBACK(deleting_conv), NULL); | |
841 #if 0 | |
842 gaim_signal_connect(gtk_conv_handle, "conversation-dragging", plugin, | |
843 GAIM_CALLBACK(conversation_dragging), NULL); | |
844 #endif | |
845 | |
846 while (convs) { | |
847 GaimConversation *conv = (GaimConversation *)convs->data; | |
848 | |
849 /* attach signals */ | |
850 attach_signals(conv); | |
851 | |
852 convs = convs->next; | |
853 } | |
854 | |
855 return TRUE; | |
856 } | |
857 | |
858 static gboolean | |
859 plugin_unload(GaimPlugin *plugin) | |
860 { | |
861 GList *convs = gaim_get_conversations(); | |
862 | |
863 while (convs) { | |
864 GaimConversation *conv = (GaimConversation *)convs->data; | |
865 | |
866 /* kill signals */ | |
867 detach_signals(conv); | |
868 | |
869 convs = convs->next; | |
870 } | |
871 | |
872 return TRUE; | |
873 } | |
874 | |
875 static GaimGtkPluginUiInfo ui_info = | |
876 { | |
877 get_config_frame, | |
878 0 /* page_num (Reserved) */ | |
879 }; | |
880 | |
881 static GaimPluginInfo info = | |
882 { | |
883 GAIM_PLUGIN_MAGIC, | |
884 GAIM_MAJOR_VERSION, | |
885 GAIM_MINOR_VERSION, | |
886 GAIM_PLUGIN_STANDARD, /**< type */ | |
887 GAIM_GTK_PLUGIN_TYPE, /**< ui_requirement */ | |
888 0, /**< flags */ | |
889 NULL, /**< dependencies */ | |
890 GAIM_PRIORITY_DEFAULT, /**< priority */ | |
891 | |
892 NOTIFY_PLUGIN_ID, /**< id */ | |
893 N_("Message Notification"), /**< name */ | |
894 VERSION, /**< version */ | |
895 /** summary */ | |
896 N_("Provides a variety of ways of notifying you of unread messages."), | |
897 /** description */ | |
898 N_("Provides a variety of ways of notifying you of unread messages."), | |
899 /**< author */ | |
900 "Etan Reisner <deryni@eden.rutgers.edu>\n\t\t\tBrian Tarricone <bjt23@cornell.edu>", | |
901 GAIM_WEBSITE, /**< homepage */ | |
902 | |
903 plugin_load, /**< load */ | |
904 plugin_unload, /**< unload */ | |
905 NULL, /**< destroy */ | |
906 | |
907 &ui_info, /**< ui_info */ | |
908 NULL, /**< extra_info */ | |
909 NULL, | |
910 NULL | |
911 }; | |
912 | |
913 static void | |
914 init_plugin(GaimPlugin *plugin) | |
915 { | |
916 gaim_prefs_add_none("/plugins/gtk"); | |
917 gaim_prefs_add_none("/plugins/gtk/X11"); | |
918 gaim_prefs_add_none("/plugins/gtk/X11/notify"); | |
919 | |
920 gaim_prefs_add_bool("/plugins/gtk/X11/notify/type_im", TRUE); | |
921 gaim_prefs_add_bool("/plugins/gtk/X11/notify/type_chat", FALSE); | |
922 gaim_prefs_add_bool("/plugins/gtk/X11/notify/type_chat_nick", FALSE); | |
923 gaim_prefs_add_bool("/plugins/gtk/X11/notify/type_focused", FALSE); | |
924 gaim_prefs_add_bool("/plugins/gtk/X11/notify/method_string", FALSE); | |
925 gaim_prefs_add_string("/plugins/gtk/X11/notify/title_string", "(*)"); | |
926 gaim_prefs_add_bool("/plugins/gtk/X11/notify/method_urgent", FALSE); | |
927 gaim_prefs_add_bool("/plugins/gtk/X11/notify/method_count", FALSE); | |
928 gaim_prefs_add_bool("/plugins/gtk/X11/notify/method_count_xprop", FALSE); | |
929 gaim_prefs_add_bool("/plugins/gtk/X11/notify/method_raise", FALSE); | |
930 gaim_prefs_add_bool("/plugins/gtk/X11/notify/notify_focus", TRUE); | |
931 gaim_prefs_add_bool("/plugins/gtk/X11/notify/notify_click", FALSE); | |
932 gaim_prefs_add_bool("/plugins/gtk/X11/notify/notify_type", TRUE); | |
933 gaim_prefs_add_bool("/plugins/gtk/X11/notify/notify_send", TRUE); | |
934 gaim_prefs_add_bool("/plugins/gtk/X11/notify/notify_switch", TRUE); | |
935 } | |
936 | |
937 GAIM_INIT_PLUGIN(notify, init_plugin, info) |