2 * Purple buddy notification plugin.
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)
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.
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.
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., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
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
34 * 22:23:53 <deryni> Also I think purple 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
43 * -Added config dialog
44 * -Added control over notification method
45 * -Added control over when to release notification
47 * -Added option to get notification for chats also
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
57 * Thanks to Carles Pina i Estany <carles@pinux.info>
58 * for count of new messages option
60 * From Brian, 20 July 2003:
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
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
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)
82 * Sean, 08 January, 2005:
83 * -Added Raise option, formally in Purple proper
90 #include "conversation.h"
96 #include "gtkplugin.h"
99 #define NOTIFY_PLUGIN_ID "gtk-x11-notify"
101 static PurplePlugin
*my_plugin
= NULL
;
103 static GdkAtom _Cardinal
= GDK_NONE
;
104 static GdkAtom _PurpleUnseenCount
= GDK_NONE
;
107 /* notification set/unset */
108 static int notify(PurpleConversation
*conv
, gboolean increment
);
109 static void notify_win(PidginWindow
*purplewin
, PurpleConversation
*conv
);
110 static void unnotify(PurpleConversation
*conv
, gboolean reset
);
111 static int unnotify_cb(GtkWidget
*widget
, gpointer data
,
112 PurpleConversation
*conv
);
114 /* gtk widget callbacks for prefs panel */
115 static void type_toggle_cb(GtkWidget
*widget
, gpointer data
);
116 static void method_toggle_cb(GtkWidget
*widget
, gpointer data
);
117 static void notify_toggle_cb(GtkWidget
*widget
, gpointer data
);
118 static gboolean
options_entry_cb(GtkWidget
*widget
, GdkEventFocus
*event
,
120 static void apply_method(void);
121 static void apply_notify(void);
123 /* string function */
124 static void handle_string(PidginWindow
*purplewin
);
126 /* count_title function */
127 static void handle_count_title(PidginWindow
*purplewin
);
129 /* count_xprop function */
130 static void handle_count_xprop(PidginWindow
*purplewin
);
132 /* urgent function */
133 static void handle_urgent(PidginWindow
*purplewin
, gboolean set
);
136 static void handle_raise(PidginWindow
*purplewin
);
138 /* present function */
139 static void handle_present(PurpleConversation
*conv
);
141 /****************************************/
142 /* Begin doing stuff below this line... */
143 /****************************************/
145 count_messages(PidginWindow
*purplewin
)
148 GList
*convs
= NULL
, *l
;
150 for (convs
= purplewin
->gtkconvs
; convs
!= NULL
; convs
= convs
->next
) {
151 PidginConversation
*conv
= convs
->data
;
152 for (l
= conv
->convs
; l
!= NULL
; l
= l
->next
) {
153 count
+= GPOINTER_TO_INT(purple_conversation_get_data(l
->data
, "notify-message-count"));
161 notify(PurpleConversation
*conv
, gboolean increment
)
165 PidginWindow
*purplewin
= NULL
;
167 if (conv
== NULL
|| PIDGIN_CONVERSATION(conv
) == NULL
)
170 /* We want to remove the notifications, but not reset the counter */
171 unnotify(conv
, FALSE
);
173 purplewin
= PIDGIN_CONVERSATION(conv
)->win
;
175 /* If we aren't doing notifications for this type of conversation, return */
176 if (((purple_conversation_get_type(conv
) == PURPLE_CONV_TYPE_IM
) &&
177 !purple_prefs_get_bool("/plugins/gtk/X11/notify/type_im")) ||
178 ((purple_conversation_get_type(conv
) == PURPLE_CONV_TYPE_CHAT
) &&
179 !purple_prefs_get_bool("/plugins/gtk/X11/notify/type_chat")))
182 g_object_get(G_OBJECT(purplewin
->window
),
183 "has-toplevel-focus", &has_focus
, NULL
);
185 if (purple_prefs_get_bool("/plugins/gtk/X11/notify/type_focused") ||
188 count
= GPOINTER_TO_INT(purple_conversation_get_data(conv
, "notify-message-count"));
190 purple_conversation_set_data(conv
, "notify-message-count", GINT_TO_POINTER(count
));
193 notify_win(purplewin
, conv
);
200 notify_win(PidginWindow
*purplewin
, PurpleConversation
*conv
)
202 if (count_messages(purplewin
) <= 0)
205 if (purple_prefs_get_bool("/plugins/gtk/X11/notify/method_count"))
206 handle_count_title(purplewin
);
207 if (purple_prefs_get_bool("/plugins/gtk/X11/notify/method_count_xprop"))
208 handle_count_xprop(purplewin
);
209 if (purple_prefs_get_bool("/plugins/gtk/X11/notify/method_string"))
210 handle_string(purplewin
);
211 if (purple_prefs_get_bool("/plugins/gtk/X11/notify/method_urgent"))
212 handle_urgent(purplewin
, TRUE
);
213 if (purple_prefs_get_bool("/plugins/gtk/X11/notify/method_raise"))
214 handle_raise(purplewin
);
215 if (purple_prefs_get_bool("/plugins/gtk/X11/notify/method_present"))
216 handle_present(conv
);
220 unnotify(PurpleConversation
*conv
, gboolean reset
)
222 PurpleConversation
*active_conv
= NULL
;
223 PidginWindow
*purplewin
= NULL
;
225 g_return_if_fail(conv
!= NULL
);
226 if (PIDGIN_CONVERSATION(conv
) == NULL
)
229 purplewin
= PIDGIN_CONVERSATION(conv
)->win
;
230 active_conv
= pidgin_conv_window_get_active_conversation(purplewin
);
232 /* reset the conversation window title */
233 purple_conversation_autoset_title(active_conv
);
236 /* Only need to actually remove the urgent hinting here, since
237 * removing it just to have it readded in re-notify is an
238 * unnecessary couple extra RTs to the server */
239 handle_urgent(purplewin
, FALSE
);
240 purple_conversation_set_data(conv
, "notify-message-count", GINT_TO_POINTER(0));
241 /* Same logic as for the urgent hint, xprops are also a RT.
242 * This needs to go here so that it gets the updated message
244 handle_count_xprop(purplewin
);
251 unnotify_cb(GtkWidget
*widget
, gpointer data
, PurpleConversation
*conv
)
253 if (GPOINTER_TO_INT(purple_conversation_get_data(conv
, "notify-message-count")) != 0)
254 unnotify(conv
, TRUE
);
260 message_displayed_cb(PurpleAccount
*account
, const char *who
, char *message
,
261 PurpleConversation
*conv
, PurpleMessageFlags flags
)
263 PurpleConversationType ct
= purple_conversation_get_type(conv
);
265 /* Ignore anything that's not a received message or a system message */
266 if (!(flags
& (PURPLE_MESSAGE_RECV
|PURPLE_MESSAGE_SYSTEM
)))
268 /* Don't highlight for delayed messages */
269 if ((flags
& PURPLE_MESSAGE_RECV
) && (flags
& PURPLE_MESSAGE_DELAYED
))
271 /* Check whether to highlight for system message for either chat or IM */
272 if (flags
& PURPLE_MESSAGE_SYSTEM
) {
274 case PURPLE_CONV_TYPE_CHAT
:
275 if (!purple_prefs_get_bool("/plugins/gtk/X11/notify/type_chat_sys"))
278 case PURPLE_CONV_TYPE_IM
:
279 if (!purple_prefs_get_bool("/plugins/gtk/X11/notify/type_im_sys"))
283 /* System message not from chat or IM, ignore */
287 /* If it's a chat, check if we should only highlight when nick is mentioned */
288 if (ct
== PURPLE_CONV_TYPE_CHAT
&&
289 purple_prefs_get_bool("/plugins/gtk/X11/notify/type_chat_nick") &&
290 !(flags
& PURPLE_MESSAGE_NICK
))
293 /* Nothing speaks against notifying, do so */
300 im_sent_im(PurpleAccount
*account
, const char *receiver
, const char *message
)
302 PurpleConversation
*conv
= NULL
;
304 if (purple_prefs_get_bool("/plugins/gtk/X11/notify/notify_send")) {
305 conv
= purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM
, receiver
, account
);
306 unnotify(conv
, TRUE
);
311 chat_sent_im(PurpleAccount
*account
, const char *message
, int id
)
313 PurpleConversation
*conv
= NULL
;
315 if (purple_prefs_get_bool("/plugins/gtk/X11/notify/notify_send")) {
316 conv
= purple_find_chat(purple_account_get_connection(account
), id
);
317 unnotify(conv
, TRUE
);
322 attach_signals(PurpleConversation
*conv
)
324 PidginConversation
*gtkconv
= NULL
;
325 GSList
*imhtml_ids
= NULL
, *entry_ids
= NULL
;
328 gtkconv
= PIDGIN_CONVERSATION(conv
);
330 purple_debug_misc("notify", "Failed to find gtkconv\n");
334 if (purple_prefs_get_bool("/plugins/gtk/X11/notify/notify_focus")) {
335 /* TODO should really find a way to make this work no matter
336 * where the focus is inside the conv window, without having
337 * to bind to focus-in-event on the g(d|t)kwindow */
338 /* try setting the signal on the focus-in-event for
339 * gtkwin->notebook->container? */
340 id
= g_signal_connect(G_OBJECT(gtkconv
->entry
), "focus-in-event",
341 G_CALLBACK(unnotify_cb
), conv
);
342 entry_ids
= g_slist_append(entry_ids
, GUINT_TO_POINTER(id
));
344 id
= g_signal_connect(G_OBJECT(gtkconv
->imhtml
), "focus-in-event",
345 G_CALLBACK(unnotify_cb
), conv
);
346 imhtml_ids
= g_slist_append(imhtml_ids
, GUINT_TO_POINTER(id
));
349 if (purple_prefs_get_bool("/plugins/gtk/X11/notify/notify_click")) {
350 /* TODO similarly should really find a way to allow for
351 * clicking in other places of the window */
352 id
= g_signal_connect(G_OBJECT(gtkconv
->entry
), "button-press-event",
353 G_CALLBACK(unnotify_cb
), conv
);
354 entry_ids
= g_slist_append(entry_ids
, GUINT_TO_POINTER(id
));
356 id
= g_signal_connect(G_OBJECT(gtkconv
->imhtml
), "button-press-event",
357 G_CALLBACK(unnotify_cb
), conv
);
358 imhtml_ids
= g_slist_append(imhtml_ids
, GUINT_TO_POINTER(id
));
361 if (purple_prefs_get_bool("/plugins/gtk/X11/notify/notify_type")) {
362 id
= g_signal_connect(G_OBJECT(gtkconv
->entry
), "key-press-event",
363 G_CALLBACK(unnotify_cb
), conv
);
364 entry_ids
= g_slist_append(entry_ids
, GUINT_TO_POINTER(id
));
367 purple_conversation_set_data(conv
, "notify-imhtml-signals", imhtml_ids
);
368 purple_conversation_set_data(conv
, "notify-entry-signals", entry_ids
);
374 detach_signals(PurpleConversation
*conv
)
376 PidginConversation
*gtkconv
= NULL
;
377 GSList
*ids
= NULL
, *l
;
379 gtkconv
= PIDGIN_CONVERSATION(conv
);
383 ids
= purple_conversation_get_data(conv
, "notify-imhtml-signals");
384 for (l
= ids
; l
!= NULL
; l
= l
->next
)
385 g_signal_handler_disconnect(gtkconv
->imhtml
, GPOINTER_TO_INT(l
->data
));
388 ids
= purple_conversation_get_data(conv
, "notify-entry-signals");
389 for (l
= ids
; l
!= NULL
; l
= l
->next
)
390 g_signal_handler_disconnect(gtkconv
->entry
, GPOINTER_TO_INT(l
->data
));
393 purple_conversation_set_data(conv
, "notify-message-count", GINT_TO_POINTER(0));
395 purple_conversation_set_data(conv
, "notify-imhtml-signals", NULL
);
396 purple_conversation_set_data(conv
, "notify-entry-signals", NULL
);
400 conv_created(PurpleConversation
*conv
)
402 purple_conversation_set_data(conv
, "notify-message-count",
405 /* always attach the signals, notify() will take care of conversation
407 attach_signals(conv
);
411 conv_switched(PurpleConversation
*conv
)
414 PidginWindow
*purplewin
= purple_conversation_get_window(new_conv
);
418 * If the conversation was switched, then make sure we re-notify
419 * because Purple will have overwritten our custom window title.
424 printf("conv_switched - %p - %p\n", old_conv
, new_conv
);
425 printf("count - %d\n", count_messages(purplewin
));
426 if (purple_prefs_get_bool("/plugins/gtk/X11/notify/notify_switch"))
427 unnotify(new_conv
, FALSE
);
429 /* if we don't have notification on the window then we don't want to
431 if (count_messages(purplewin
))
432 notify_win(purplewin
);
438 deleting_conv(PurpleConversation
*conv
)
440 PidginWindow
*purplewin
= NULL
;
441 PidginConversation
*gtkconv
= PIDGIN_CONVERSATION(conv
);
446 detach_signals(conv
);
448 purplewin
= gtkconv
->win
;
450 handle_urgent(purplewin
, FALSE
);
451 purple_conversation_set_data(conv
, "notify-message-count", GINT_TO_POINTER(0));
456 /* i think this line crashes */
457 if (count_messages(purplewin
))
458 notify_win(purplewin
);
464 conversation_dragging(PurpleConversation
*active_conv
,
465 PidginWindow
*old_purplewin
,
466 PidginWindow
*new_purplewin
)
468 if (old_purplewin
!= new_purplewin
) {
469 if (old_purplewin
== NULL
) {
471 purple_conversation_autoset_title(active_conv);
472 handle_urgent(new_purplewin, FALSE);
475 if (count_messages(new_purplewin
))
476 notify_win(new_purplewin
);
478 printf("if else count = %d\n", count_messages(new_purplewin
));
479 printf("if else count = %d\n", count_messages(old_purplewin
));
481 PurpleConversation *old_active_conv = NULL;
482 old_active_conv = purple_conv_window_get_active_conversation(new_purplewin);
484 purple_conversation_autoset_title(old_active_conv);
485 handle_urgent(old_purplewin, FALSE);
487 if (count_messages(old_purplewin))
488 notify_win(old_purplewin);
490 purple_conversation_autoset_title(active_conv);
491 handle_urgent(new_purplewin, FALSE);
493 if (count_messages(new_purplewin))
494 notify_win(new_purplewin);
498 printf("else count = %d\n", count_messages(new_purplewin
));
499 printf("else count = %d\n", count_messages(old_purplewin
));
501 purple_conversation_autoset_title(active_conv);
502 handle_urgent(old_purplewin, FALSE);
504 if (count_messages(old_purplewin))
505 notify_win(old_purplewin);
512 handle_string(PidginWindow
*purplewin
)
514 GtkWindow
*window
= NULL
;
517 g_return_if_fail(purplewin
!= NULL
);
519 window
= GTK_WINDOW(purplewin
->window
);
520 g_return_if_fail(window
!= NULL
);
522 g_snprintf(newtitle
, sizeof(newtitle
), "%s%s",
523 purple_prefs_get_string("/plugins/gtk/X11/notify/title_string"),
524 gtk_window_get_title(window
));
525 gtk_window_set_title(window
, newtitle
);
529 handle_count_title(PidginWindow
*purplewin
)
534 g_return_if_fail(purplewin
!= NULL
);
536 window
= GTK_WINDOW(purplewin
->window
);
537 g_return_if_fail(window
!= NULL
);
539 g_snprintf(newtitle
, sizeof(newtitle
), "[%d] %s",
540 count_messages(purplewin
), gtk_window_get_title(window
));
541 gtk_window_set_title(window
, newtitle
);
545 handle_count_xprop(PidginWindow
*purplewin
)
552 window
= purplewin
->window
;
553 g_return_if_fail(window
!= NULL
);
555 if (_PurpleUnseenCount
== GDK_NONE
) {
556 _PurpleUnseenCount
= gdk_atom_intern("_PIDGIN_UNSEEN_COUNT", FALSE
);
559 if (_Cardinal
== GDK_NONE
) {
560 _Cardinal
= gdk_atom_intern("CARDINAL", FALSE
);
563 count
= count_messages(purplewin
);
564 #if GTK_CHECK_VERSION(2,14,0)
565 gdkwin
= gtk_widget_get_window(window
);
567 gdkwin
= window
->window
;
570 gdk_property_change(gdkwin
, _PurpleUnseenCount
, _Cardinal
, 32,
571 GDK_PROP_MODE_REPLACE
, (guchar
*) &count
, 1);
576 handle_urgent(PidginWindow
*purplewin
, gboolean set
)
578 g_return_if_fail(purplewin
!= NULL
);
579 g_return_if_fail(purplewin
->window
!= NULL
);
581 pidgin_set_urgent(GTK_WINDOW(purplewin
->window
), set
);
585 handle_raise(PidginWindow
*purplewin
)
587 pidgin_conv_window_raise(purplewin
);
591 handle_present(PurpleConversation
*conv
)
593 if (pidgin_conv_is_hidden(PIDGIN_CONVERSATION(conv
)))
596 purple_conversation_present(conv
);
600 type_toggle_cb(GtkWidget
*widget
, gpointer data
)
602 gboolean on
= gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget
));
605 g_snprintf(pref
, sizeof(pref
), "/plugins/gtk/X11/notify/%s",
608 purple_prefs_set_bool(pref
, on
);
612 method_toggle_cb(GtkWidget
*widget
, gpointer data
)
614 gboolean on
= gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget
));
617 g_snprintf(pref
, sizeof(pref
), "/plugins/gtk/X11/notify/%s",
620 purple_prefs_set_bool(pref
, on
);
622 if (purple_strequal(data
, "method_string")) {
623 GtkWidget
*entry
= g_object_get_data(G_OBJECT(widget
), "title-entry");
624 gtk_widget_set_sensitive(entry
, on
);
626 purple_prefs_set_string("/plugins/gtk/X11/notify/title_string",
627 gtk_entry_get_text(GTK_ENTRY(entry
)));
634 notify_toggle_cb(GtkWidget
*widget
, gpointer data
)
636 gboolean on
= gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget
));
639 g_snprintf(pref
, sizeof(pref
), "/plugins/gtk/X11/notify/%s",
642 purple_prefs_set_bool(pref
, on
);
648 options_entry_cb(GtkWidget
*widget
, GdkEventFocus
*evt
, gpointer data
)
653 if (purple_strequal(data
, "method_string")) {
654 purple_prefs_set_string("/plugins/gtk/X11/notify/title_string",
655 gtk_entry_get_text(GTK_ENTRY(widget
)));
668 for (convs
= purple_get_conversations(); convs
!= NULL
;
669 convs
= convs
->next
) {
670 PurpleConversation
*conv
= (PurpleConversation
*)convs
->data
;
672 /* remove notifications */
673 unnotify(conv
, FALSE
);
675 if (GPOINTER_TO_INT(purple_conversation_get_data(conv
, "notify-message-count")) != 0)
676 /* reattach appropriate notifications */
684 GList
*convs
= purple_get_conversations();
687 PurpleConversation
*conv
= (PurpleConversation
*)convs
->data
;
690 detach_signals(conv
);
691 /* reattach appropriate signals */
692 attach_signals(conv
);
699 get_config_frame(PurplePlugin
*plugin
)
701 GtkWidget
*ret
= NULL
, *frame
= NULL
;
702 GtkWidget
*vbox
= NULL
, *hbox
= NULL
;
703 GtkWidget
*toggle
= NULL
, *entry
= NULL
, *ref
;
705 ret
= gtk_vbox_new(FALSE
, 18);
706 gtk_container_set_border_width(GTK_CONTAINER (ret
), 12);
708 /*---------- "Notify For" ----------*/
709 frame
= pidgin_make_frame(ret
, _("Notify For"));
710 vbox
= gtk_vbox_new(FALSE
, 5);
711 gtk_container_add(GTK_CONTAINER(frame
), vbox
);
713 toggle
= gtk_check_button_new_with_mnemonic(_("_IM windows"));
714 gtk_box_pack_start(GTK_BOX(vbox
), toggle
, FALSE
, FALSE
, 0);
715 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle
),
716 purple_prefs_get_bool("/plugins/gtk/X11/notify/type_im"));
717 g_signal_connect(G_OBJECT(toggle
), "toggled",
718 G_CALLBACK(type_toggle_cb
), "type_im");
721 toggle
= gtk_check_button_new_with_mnemonic(_("\tS_ystem messages"));
722 gtk_box_pack_start(GTK_BOX(vbox
), toggle
, FALSE
, FALSE
, 0);
723 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle
),
724 purple_prefs_get_bool("/plugins/gtk/X11/notify/type_im_sys"));
725 g_signal_connect(G_OBJECT(toggle
), "toggled",
726 G_CALLBACK(type_toggle_cb
), "type_im_sys");
727 gtk_widget_set_sensitive(toggle
, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(ref
)));
728 g_signal_connect(G_OBJECT(ref
), "toggled",
729 G_CALLBACK(pidgin_toggle_sensitive
), toggle
);
731 toggle
= gtk_check_button_new_with_mnemonic(_("C_hat windows"));
732 gtk_box_pack_start(GTK_BOX(vbox
), toggle
, FALSE
, FALSE
, 0);
733 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle
),
734 purple_prefs_get_bool("/plugins/gtk/X11/notify/type_chat"));
735 g_signal_connect(G_OBJECT(toggle
), "toggled",
736 G_CALLBACK(type_toggle_cb
), "type_chat");
739 toggle
= gtk_check_button_new_with_mnemonic(_("\t_Only when someone says your username"));
740 gtk_box_pack_start(GTK_BOX(vbox
), toggle
, FALSE
, FALSE
, 0);
741 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle
),
742 purple_prefs_get_bool("/plugins/gtk/X11/notify/type_chat_nick"));
743 g_signal_connect(G_OBJECT(toggle
), "toggled",
744 G_CALLBACK(type_toggle_cb
), "type_chat_nick");
745 gtk_widget_set_sensitive(toggle
, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(ref
)));
746 g_signal_connect(G_OBJECT(ref
), "toggled",
747 G_CALLBACK(pidgin_toggle_sensitive
), toggle
);
749 toggle
= gtk_check_button_new_with_mnemonic(_("\tS_ystem messages"));
750 gtk_box_pack_start(GTK_BOX(vbox
), toggle
, FALSE
, FALSE
, 0);
751 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle
),
752 purple_prefs_get_bool("/plugins/gtk/X11/notify/type_chat_sys"));
753 g_signal_connect(G_OBJECT(toggle
), "toggled",
754 G_CALLBACK(type_toggle_cb
), "type_chat_sys");
755 gtk_widget_set_sensitive(toggle
, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(ref
)));
756 g_signal_connect(G_OBJECT(ref
), "toggled",
757 G_CALLBACK(pidgin_toggle_sensitive
), toggle
);
759 toggle
= gtk_check_button_new_with_mnemonic(_("_Focused windows"));
760 gtk_box_pack_start(GTK_BOX(vbox
), toggle
, FALSE
, FALSE
, 0);
761 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle
),
762 purple_prefs_get_bool("/plugins/gtk/X11/notify/type_focused"));
763 g_signal_connect(G_OBJECT(toggle
), "toggled",
764 G_CALLBACK(type_toggle_cb
), "type_focused");
766 /*---------- "Notification Methods" ----------*/
767 frame
= pidgin_make_frame(ret
, _("Notification Methods"));
768 vbox
= gtk_vbox_new(FALSE
, 5);
769 gtk_container_add(GTK_CONTAINER(frame
), vbox
);
771 /* String method button */
772 hbox
= gtk_hbox_new(FALSE
, 18);
773 gtk_box_pack_start(GTK_BOX(vbox
), hbox
, FALSE
, FALSE
, 0);
774 toggle
= gtk_check_button_new_with_mnemonic(_("Prepend _string into window title:"));
775 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle
),
776 purple_prefs_get_bool("/plugins/gtk/X11/notify/method_string"));
777 gtk_box_pack_start(GTK_BOX(hbox
), toggle
, FALSE
, FALSE
, 0);
779 entry
= gtk_entry_new();
780 gtk_box_pack_start(GTK_BOX(hbox
), entry
, FALSE
, FALSE
, 0);
781 gtk_entry_set_max_length(GTK_ENTRY(entry
), 10);
782 gtk_widget_set_sensitive(GTK_WIDGET(entry
),
783 purple_prefs_get_bool("/plugins/gtk/X11/notify/method_string"));
784 gtk_entry_set_text(GTK_ENTRY(entry
),
785 purple_prefs_get_string("/plugins/gtk/X11/notify/title_string"));
786 g_object_set_data(G_OBJECT(toggle
), "title-entry", entry
);
787 g_signal_connect(G_OBJECT(toggle
), "toggled",
788 G_CALLBACK(method_toggle_cb
), "method_string");
789 g_signal_connect(G_OBJECT(entry
), "focus-out-event",
790 G_CALLBACK(options_entry_cb
), "method_string");
792 /* Count method button */
793 toggle
= gtk_check_button_new_with_mnemonic(_("Insert c_ount of new messages into window title"));
794 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle
),
795 purple_prefs_get_bool("/plugins/gtk/X11/notify/method_count"));
796 gtk_box_pack_start(GTK_BOX(vbox
), toggle
, FALSE
, FALSE
, 0);
797 g_signal_connect(G_OBJECT(toggle
), "toggled",
798 G_CALLBACK(method_toggle_cb
), "method_count");
801 /* Count xprop method button */
802 toggle
= gtk_check_button_new_with_mnemonic(_("Insert count of new message into _X property"));
803 gtk_box_pack_start(GTK_BOX(vbox
), toggle
, FALSE
, FALSE
, 0);
804 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle
),
805 purple_prefs_get_bool("/plugins/gtk/X11/notify/method_count_xprop"));
806 g_signal_connect(G_OBJECT(toggle
), "toggled",
807 G_CALLBACK(method_toggle_cb
), "method_count_xprop");
809 /* Urgent method button */
810 toggle
= gtk_check_button_new_with_mnemonic(_("Set window manager \"_URGENT\" hint"));
812 toggle
= gtk_check_button_new_with_mnemonic(_("_Flash window"));
814 gtk_box_pack_start(GTK_BOX(vbox
), toggle
, FALSE
, FALSE
, 0);
815 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle
),
816 purple_prefs_get_bool("/plugins/gtk/X11/notify/method_urgent"));
817 g_signal_connect(G_OBJECT(toggle
), "toggled",
818 G_CALLBACK(method_toggle_cb
), "method_urgent");
820 /* Raise window method button */
821 toggle
= gtk_check_button_new_with_mnemonic(_("R_aise conversation window"));
822 gtk_box_pack_start(GTK_BOX(vbox
), toggle
, FALSE
, FALSE
, 0);
823 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle
),
824 purple_prefs_get_bool("/plugins/gtk/X11/notify/method_raise"));
825 g_signal_connect(G_OBJECT(toggle
), "toggled",
826 G_CALLBACK(method_toggle_cb
), "method_raise");
828 /* Present conversation method button */
829 /* Translators: "Present" as used here is a verb. The plugin presents
830 * the window to the user. */
831 toggle
= gtk_check_button_new_with_mnemonic(_("_Present conversation window"));
832 gtk_box_pack_start(GTK_BOX(vbox
), toggle
, FALSE
, FALSE
, 0);
833 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle
),
834 purple_prefs_get_bool("/plugins/gtk/X11/notify/method_present"));
835 g_signal_connect(G_OBJECT(toggle
), "toggled",
836 G_CALLBACK(method_toggle_cb
), "method_present");
838 /*---------- "Notification Removals" ----------*/
839 frame
= pidgin_make_frame(ret
, _("Notification Removal"));
840 vbox
= gtk_vbox_new(FALSE
, 5);
841 gtk_container_add(GTK_CONTAINER(frame
), vbox
);
843 /* Remove on focus button */
844 toggle
= gtk_check_button_new_with_mnemonic(_("Remove when conversation window _gains focus"));
845 gtk_box_pack_start(GTK_BOX(vbox
), toggle
, FALSE
, FALSE
, 0);
846 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle
),
847 purple_prefs_get_bool("/plugins/gtk/X11/notify/notify_focus"));
848 g_signal_connect(G_OBJECT(toggle
), "toggled", G_CALLBACK(notify_toggle_cb
), "notify_focus");
850 /* Remove on click button */
851 toggle
= gtk_check_button_new_with_mnemonic(_("Remove when conversation window _receives click"));
852 gtk_box_pack_start(GTK_BOX(vbox
), toggle
, FALSE
, FALSE
, 0);
853 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle
),
854 purple_prefs_get_bool("/plugins/gtk/X11/notify/notify_click"));
855 g_signal_connect(G_OBJECT(toggle
), "toggled",
856 G_CALLBACK(notify_toggle_cb
), "notify_click");
858 /* Remove on type button */
859 toggle
= gtk_check_button_new_with_mnemonic(_("Remove when _typing in conversation window"));
860 gtk_box_pack_start(GTK_BOX(vbox
), toggle
, FALSE
, FALSE
, 0);
861 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle
),
862 purple_prefs_get_bool("/plugins/gtk/X11/notify/notify_type"));
863 g_signal_connect(G_OBJECT(toggle
), "toggled",
864 G_CALLBACK(notify_toggle_cb
), "notify_type");
866 /* Remove on message send button */
867 toggle
= gtk_check_button_new_with_mnemonic(_("Remove when a _message gets sent"));
868 gtk_box_pack_start(GTK_BOX(vbox
), toggle
, FALSE
, FALSE
, 0);
869 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle
),
870 purple_prefs_get_bool("/plugins/gtk/X11/notify/notify_send"));
871 g_signal_connect(G_OBJECT(toggle
), "toggled",
872 G_CALLBACK(notify_toggle_cb
), "notify_send");
875 /* Remove on conversation switch button */
876 toggle
= gtk_check_button_new_with_mnemonic(_("Remove on switch to conversation ta_b"));
877 gtk_box_pack_start(GTK_BOX(vbox
), toggle
, FALSE
, FALSE
, 0);
878 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle
),
879 purple_prefs_get_bool("/plugins/gtk/X11/notify/notify_switch"));
880 g_signal_connect(G_OBJECT(toggle
), "toggled",
881 G_CALLBACK(notify_toggle_cb
), "notify_switch");
884 gtk_widget_show_all(ret
);
889 plugin_load(PurplePlugin
*plugin
)
891 GList
*convs
= purple_get_conversations();
892 void *conv_handle
= purple_conversations_get_handle();
893 void *gtk_conv_handle
= pidgin_conversations_get_handle();
897 purple_signal_connect(gtk_conv_handle
, "displayed-im-msg", plugin
,
898 PURPLE_CALLBACK(message_displayed_cb
), NULL
);
899 purple_signal_connect(gtk_conv_handle
, "displayed-chat-msg", plugin
,
900 PURPLE_CALLBACK(message_displayed_cb
), NULL
);
901 purple_signal_connect(gtk_conv_handle
, "conversation-switched", plugin
,
902 PURPLE_CALLBACK(conv_switched
), NULL
);
903 purple_signal_connect(conv_handle
, "sent-im-msg", plugin
,
904 PURPLE_CALLBACK(im_sent_im
), NULL
);
905 purple_signal_connect(conv_handle
, "sent-chat-msg", plugin
,
906 PURPLE_CALLBACK(chat_sent_im
), NULL
);
907 purple_signal_connect(conv_handle
, "conversation-created", plugin
,
908 PURPLE_CALLBACK(conv_created
), NULL
);
909 purple_signal_connect(conv_handle
, "deleting-conversation", plugin
,
910 PURPLE_CALLBACK(deleting_conv
), NULL
);
912 purple_signal_connect(gtk_conv_handle
, "conversation-dragging", plugin
,
913 PURPLE_CALLBACK(conversation_dragging
), NULL
);
917 PurpleConversation
*conv
= (PurpleConversation
*)convs
->data
;
920 attach_signals(conv
);
929 plugin_unload(PurplePlugin
*plugin
)
931 GList
*convs
= purple_get_conversations();
934 PurpleConversation
*conv
= (PurpleConversation
*)convs
->data
;
937 detach_signals(conv
);
945 static PidginPluginUiInfo ui_info
=
948 0, /* page_num (Reserved) */
957 static PurplePluginInfo info
=
960 PURPLE_MAJOR_VERSION
,
961 PURPLE_MINOR_VERSION
,
962 PURPLE_PLUGIN_STANDARD
, /**< type */
963 PIDGIN_PLUGIN_TYPE
, /**< ui_requirement */
965 NULL
, /**< dependencies */
966 PURPLE_PRIORITY_DEFAULT
, /**< priority */
968 NOTIFY_PLUGIN_ID
, /**< id */
969 N_("Message Notification"), /**< name */
970 DISPLAY_VERSION
, /**< version */
972 N_("Provides a variety of ways of notifying you of unread messages."),
974 N_("Provides a variety of ways of notifying you of unread messages."),
976 "Etan Reisner <deryni@eden.rutgers.edu>,\nBrian Tarricone <bjt23@cornell.edu>",
977 PURPLE_WEBSITE
, /**< homepage */
979 plugin_load
, /**< load */
980 plugin_unload
, /**< unload */
981 NULL
, /**< destroy */
983 &ui_info
, /**< ui_info */
984 NULL
, /**< extra_info */
996 init_plugin(PurplePlugin
*plugin
)
998 purple_prefs_add_none("/plugins/gtk");
999 purple_prefs_add_none("/plugins/gtk/X11");
1000 purple_prefs_add_none("/plugins/gtk/X11/notify");
1002 purple_prefs_add_bool("/plugins/gtk/X11/notify/type_im", TRUE
);
1003 purple_prefs_add_bool("/plugins/gtk/X11/notify/type_im_sys", FALSE
);
1004 purple_prefs_add_bool("/plugins/gtk/X11/notify/type_chat", FALSE
);
1005 purple_prefs_add_bool("/plugins/gtk/X11/notify/type_chat_nick", FALSE
);
1006 purple_prefs_add_bool("/plugins/gtk/X11/notify/type_chat_sys", FALSE
);
1007 purple_prefs_add_bool("/plugins/gtk/X11/notify/type_focused", FALSE
);
1008 purple_prefs_add_bool("/plugins/gtk/X11/notify/method_string", FALSE
);
1009 purple_prefs_add_string("/plugins/gtk/X11/notify/title_string", "(*)");
1010 purple_prefs_add_bool("/plugins/gtk/X11/notify/method_urgent", FALSE
);
1011 purple_prefs_add_bool("/plugins/gtk/X11/notify/method_count", FALSE
);
1012 purple_prefs_add_bool("/plugins/gtk/X11/notify/method_count_xprop", FALSE
);
1013 purple_prefs_add_bool("/plugins/gtk/X11/notify/method_raise", FALSE
);
1014 purple_prefs_add_bool("/plugins/gtk/X11/notify/method_present", FALSE
);
1015 purple_prefs_add_bool("/plugins/gtk/X11/notify/notify_focus", TRUE
);
1016 purple_prefs_add_bool("/plugins/gtk/X11/notify/notify_click", FALSE
);
1017 purple_prefs_add_bool("/plugins/gtk/X11/notify/notify_type", TRUE
);
1018 purple_prefs_add_bool("/plugins/gtk/X11/notify/notify_send", TRUE
);
1019 purple_prefs_add_bool("/plugins/gtk/X11/notify/notify_switch", TRUE
);
1022 PURPLE_INIT_PLUGIN(notify
, init_plugin
, info
)