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"
100 #include <X11/Xatom.h>
101 #include <X11/Xlib.h>
102 #include <X11/Xutil.h>
105 #define NOTIFY_PLUGIN_ID "gtk-x11-notify"
107 static PurplePlugin
*my_plugin
= NULL
;
109 static GdkAtom _Cardinal
= GDK_NONE
;
110 static GdkAtom _PurpleUnseenCount
= GDK_NONE
;
113 /* notification set/unset */
114 static int notify(PurpleConversation
*conv
, gboolean increment
);
115 static void notify_win(PidginWindow
*purplewin
);
116 static void unnotify(PurpleConversation
*conv
, gboolean reset
);
117 static int unnotify_cb(GtkWidget
*widget
, gpointer data
,
118 PurpleConversation
*conv
);
120 /* gtk widget callbacks for prefs panel */
121 static void type_toggle_cb(GtkWidget
*widget
, gpointer data
);
122 static void method_toggle_cb(GtkWidget
*widget
, gpointer data
);
123 static void notify_toggle_cb(GtkWidget
*widget
, gpointer data
);
124 static gboolean
options_entry_cb(GtkWidget
*widget
, GdkEventFocus
*event
,
126 static void apply_method(void);
127 static void apply_notify(void);
129 /* string function */
130 static void handle_string(PidginWindow
*purplewin
);
132 /* count_title function */
133 static void handle_count_title(PidginWindow
*purplewin
);
135 /* count_xprop function */
136 static void handle_count_xprop(PidginWindow
*purplewin
);
138 /* urgent function */
139 static void handle_urgent(PidginWindow
*purplewin
, gboolean set
);
142 static void handle_raise(PidginWindow
*purplewin
);
144 /****************************************/
145 /* Begin doing stuff below this line... */
146 /****************************************/
148 count_messages(PidginWindow
*purplewin
)
151 GList
*convs
= NULL
, *l
;
153 for (convs
= purplewin
->gtkconvs
; convs
!= NULL
; convs
= convs
->next
) {
154 PidginConversation
*conv
= convs
->data
;
155 for (l
= conv
->convs
; l
!= NULL
; l
= l
->next
) {
156 count
+= GPOINTER_TO_INT(purple_conversation_get_data(l
->data
, "notify-message-count"));
164 notify(PurpleConversation
*conv
, gboolean increment
)
168 PidginWindow
*purplewin
= NULL
;
170 if (conv
== NULL
|| PIDGIN_CONVERSATION(conv
) == NULL
)
173 /* We want to remove the notifications, but not reset the counter */
174 unnotify(conv
, FALSE
);
176 purplewin
= PIDGIN_CONVERSATION(conv
)->win
;
178 /* If we aren't doing notifications for this type of conversation, return */
179 if (((purple_conversation_get_type(conv
) == PURPLE_CONV_TYPE_IM
) &&
180 !purple_prefs_get_bool("/plugins/gtk/X11/notify/type_im")) ||
181 ((purple_conversation_get_type(conv
) == PURPLE_CONV_TYPE_CHAT
) &&
182 !purple_prefs_get_bool("/plugins/gtk/X11/notify/type_chat")))
185 g_object_get(G_OBJECT(purplewin
->window
),
186 "has-toplevel-focus", &has_focus
, NULL
);
188 if (purple_prefs_get_bool("/plugins/gtk/X11/notify/type_focused") ||
191 count
= GPOINTER_TO_INT(purple_conversation_get_data(conv
, "notify-message-count"));
193 purple_conversation_set_data(conv
, "notify-message-count", GINT_TO_POINTER(count
));
196 notify_win(purplewin
);
203 notify_win(PidginWindow
*purplewin
)
205 if (count_messages(purplewin
) <= 0)
208 if (purple_prefs_get_bool("/plugins/gtk/X11/notify/method_count"))
209 handle_count_title(purplewin
);
210 if (purple_prefs_get_bool("/plugins/gtk/X11/notify/method_count_xprop"))
211 handle_count_xprop(purplewin
);
212 if (purple_prefs_get_bool("/plugins/gtk/X11/notify/method_string"))
213 handle_string(purplewin
);
214 if (purple_prefs_get_bool("/plugins/gtk/X11/notify/method_urgent"))
215 handle_urgent(purplewin
, TRUE
);
216 if (purple_prefs_get_bool("/plugins/gtk/X11/notify/method_raise"))
217 handle_raise(purplewin
);
221 unnotify(PurpleConversation
*conv
, gboolean reset
)
223 PurpleConversation
*active_conv
= NULL
;
224 PidginWindow
*purplewin
= NULL
;
226 g_return_if_fail(conv
!= NULL
);
227 if (PIDGIN_CONVERSATION(conv
) == NULL
)
230 purplewin
= PIDGIN_CONVERSATION(conv
)->win
;
231 active_conv
= pidgin_conv_window_get_active_conversation(purplewin
);
233 /* reset the conversation window title */
234 purple_conversation_autoset_title(active_conv
);
237 /* Only need to actually remove the urgent hinting here, since
238 * removing it just to have it readded in re-notify is an
239 * unnecessary couple extra RTs to the server */
240 handle_urgent(purplewin
, FALSE
);
241 purple_conversation_set_data(conv
, "notify-message-count", GINT_TO_POINTER(0));
242 /* Same logic as for the urgent hint, xprops are also a RT.
243 * This needs to go here so that it gets the updated message
245 handle_count_xprop(purplewin
);
252 unnotify_cb(GtkWidget
*widget
, gpointer data
, PurpleConversation
*conv
)
254 if (GPOINTER_TO_INT(purple_conversation_get_data(conv
, "notify-message-count")) != 0)
255 unnotify(conv
, TRUE
);
261 message_displayed_cb(PurpleAccount
*account
, const char *who
, char *message
,
262 PurpleConversation
*conv
, PurpleMessageFlags flags
)
264 if ((purple_conversation_get_type(conv
) == PURPLE_CONV_TYPE_CHAT
&&
265 purple_prefs_get_bool("/plugins/gtk/X11/notify/type_chat_nick") &&
266 !(flags
& PURPLE_MESSAGE_NICK
)))
269 if ((flags
& PURPLE_MESSAGE_RECV
) && !(flags
& PURPLE_MESSAGE_DELAYED
))
276 im_sent_im(PurpleAccount
*account
, const char *receiver
, const char *message
)
278 PurpleConversation
*conv
= NULL
;
280 if (purple_prefs_get_bool("/plugins/gtk/X11/notify/notify_send")) {
281 conv
= purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM
, receiver
, account
);
282 unnotify(conv
, TRUE
);
287 chat_sent_im(PurpleAccount
*account
, const char *message
, int id
)
289 PurpleConversation
*conv
= NULL
;
291 if (purple_prefs_get_bool("/plugins/gtk/X11/notify/notify_send")) {
292 conv
= purple_find_chat(purple_account_get_connection(account
), id
);
293 unnotify(conv
, TRUE
);
298 attach_signals(PurpleConversation
*conv
)
300 PidginConversation
*gtkconv
= NULL
;
301 PidginWindow
*gtkwin
= NULL
;
302 GSList
*imhtml_ids
= NULL
, *entry_ids
= NULL
;
305 gtkconv
= PIDGIN_CONVERSATION(conv
);
307 purple_debug_misc("notify", "Failed to find gtkconv\n");
311 gtkwin
= gtkconv
->win
;
313 if (purple_prefs_get_bool("/plugins/gtk/X11/notify/notify_focus")) {
314 /* TODO should really find a way to make this work no matter
315 * where the focus is inside the conv window, without having
316 * to bind to focus-in-event on the g(d|t)kwindow */
317 /* try setting the signal on the focus-in-event for
318 * gtkwin->notebook->container? */
319 id
= g_signal_connect(G_OBJECT(gtkconv
->entry
), "focus-in-event",
320 G_CALLBACK(unnotify_cb
), conv
);
321 entry_ids
= g_slist_append(entry_ids
, GUINT_TO_POINTER(id
));
323 id
= g_signal_connect(G_OBJECT(gtkconv
->imhtml
), "focus-in-event",
324 G_CALLBACK(unnotify_cb
), conv
);
325 imhtml_ids
= g_slist_append(imhtml_ids
, GUINT_TO_POINTER(id
));
328 if (purple_prefs_get_bool("/plugins/gtk/X11/notify/notify_click")) {
329 /* TODO similarly should really find a way to allow for
330 * clicking in other places of the window */
331 id
= g_signal_connect(G_OBJECT(gtkconv
->entry
), "button-press-event",
332 G_CALLBACK(unnotify_cb
), conv
);
333 entry_ids
= g_slist_append(entry_ids
, GUINT_TO_POINTER(id
));
335 id
= g_signal_connect(G_OBJECT(gtkconv
->imhtml
), "button-press-event",
336 G_CALLBACK(unnotify_cb
), conv
);
337 imhtml_ids
= g_slist_append(imhtml_ids
, GUINT_TO_POINTER(id
));
340 if (purple_prefs_get_bool("/plugins/gtk/X11/notify/notify_type")) {
341 id
= g_signal_connect(G_OBJECT(gtkconv
->entry
), "key-press-event",
342 G_CALLBACK(unnotify_cb
), conv
);
343 entry_ids
= g_slist_append(entry_ids
, GUINT_TO_POINTER(id
));
346 purple_conversation_set_data(conv
, "notify-imhtml-signals", imhtml_ids
);
347 purple_conversation_set_data(conv
, "notify-entry-signals", entry_ids
);
353 detach_signals(PurpleConversation
*conv
)
355 PidginConversation
*gtkconv
= NULL
;
356 PidginWindow
*gtkwin
= NULL
;
357 GSList
*ids
= NULL
, *l
;
359 gtkconv
= PIDGIN_CONVERSATION(conv
);
362 gtkwin
= gtkconv
->win
;
364 ids
= purple_conversation_get_data(conv
, "notify-imhtml-signals");
365 for (l
= ids
; l
!= NULL
; l
= l
->next
)
366 g_signal_handler_disconnect(gtkconv
->imhtml
, GPOINTER_TO_INT(l
->data
));
369 ids
= purple_conversation_get_data(conv
, "notify-entry-signals");
370 for (l
= ids
; l
!= NULL
; l
= l
->next
)
371 g_signal_handler_disconnect(gtkconv
->entry
, GPOINTER_TO_INT(l
->data
));
374 purple_conversation_set_data(conv
, "notify-message-count", GINT_TO_POINTER(0));
376 purple_conversation_set_data(conv
, "notify-imhtml-signals", NULL
);
377 purple_conversation_set_data(conv
, "notify-entry-signals", NULL
);
381 conv_created(PurpleConversation
*conv
)
383 purple_conversation_set_data(conv
, "notify-message-count",
386 /* always attach the signals, notify() will take care of conversation
388 attach_signals(conv
);
392 conv_switched(PurpleConversation
*conv
)
395 PidginWindow
*purplewin
= purple_conversation_get_window(new_conv
);
399 * If the conversation was switched, then make sure we re-notify
400 * because Purple will have overwritten our custom window title.
405 printf("conv_switched - %p - %p\n", old_conv
, new_conv
);
406 printf("count - %d\n", count_messages(purplewin
));
407 if (purple_prefs_get_bool("/plugins/gtk/X11/notify/notify_switch"))
408 unnotify(new_conv
, FALSE
);
410 /* if we don't have notification on the window then we don't want to
412 if (count_messages(purplewin
))
413 notify_win(purplewin
);
419 deleting_conv(PurpleConversation
*conv
)
421 PidginWindow
*purplewin
= NULL
;
422 PidginConversation
*gtkconv
= PIDGIN_CONVERSATION(conv
);
427 detach_signals(conv
);
429 purplewin
= gtkconv
->win
;
431 handle_urgent(purplewin
, FALSE
);
432 purple_conversation_set_data(conv
, "notify-message-count", GINT_TO_POINTER(0));
437 /* i think this line crashes */
438 if (count_messages(purplewin
))
439 notify_win(purplewin
);
445 conversation_dragging(PurpleConversation
*active_conv
,
446 PidginWindow
*old_purplewin
,
447 PidginWindow
*new_purplewin
)
449 if (old_purplewin
!= new_purplewin
) {
450 if (old_purplewin
== NULL
) {
452 purple_conversation_autoset_title(active_conv);
453 handle_urgent(new_purplewin, FALSE);
456 if (count_messages(new_purplewin
))
457 notify_win(new_purplewin
);
459 printf("if else count = %d\n", count_messages(new_purplewin
));
460 printf("if else count = %d\n", count_messages(old_purplewin
));
462 PurpleConversation *old_active_conv = NULL;
463 old_active_conv = purple_conv_window_get_active_conversation(new_purplewin);
465 purple_conversation_autoset_title(old_active_conv);
466 handle_urgent(old_purplewin, FALSE);
468 if (count_messages(old_purplewin))
469 notify_win(old_purplewin);
471 purple_conversation_autoset_title(active_conv);
472 handle_urgent(new_purplewin, FALSE);
474 if (count_messages(new_purplewin))
475 notify_win(new_purplewin);
479 printf("else count = %d\n", count_messages(new_purplewin
));
480 printf("else count = %d\n", count_messages(old_purplewin
));
482 purple_conversation_autoset_title(active_conv);
483 handle_urgent(old_purplewin, FALSE);
485 if (count_messages(old_purplewin))
486 notify_win(old_purplewin);
493 handle_string(PidginWindow
*purplewin
)
495 GtkWindow
*window
= NULL
;
498 g_return_if_fail(purplewin
!= NULL
);
500 window
= GTK_WINDOW(purplewin
->window
);
501 g_return_if_fail(window
!= NULL
);
503 g_snprintf(newtitle
, sizeof(newtitle
), "%s%s",
504 purple_prefs_get_string("/plugins/gtk/X11/notify/title_string"),
505 gtk_window_get_title(window
));
506 gtk_window_set_title(window
, newtitle
);
510 handle_count_title(PidginWindow
*purplewin
)
515 g_return_if_fail(purplewin
!= NULL
);
517 window
= GTK_WINDOW(purplewin
->window
);
518 g_return_if_fail(window
!= NULL
);
520 g_snprintf(newtitle
, sizeof(newtitle
), "[%d] %s",
521 count_messages(purplewin
), gtk_window_get_title(window
));
522 gtk_window_set_title(window
, newtitle
);
526 handle_count_xprop(PidginWindow
*purplewin
)
533 window
= purplewin
->window
;
534 g_return_if_fail(window
!= NULL
);
536 if (_PurpleUnseenCount
== GDK_NONE
) {
537 _PurpleUnseenCount
= gdk_atom_intern("_PIDGIN_UNSEEN_COUNT", FALSE
);
540 if (_Cardinal
== GDK_NONE
) {
541 _Cardinal
= gdk_atom_intern("CARDINAL", FALSE
);
544 count
= count_messages(purplewin
);
545 gdkwin
= window
->window
;
547 gdk_property_change(gdkwin
, _PurpleUnseenCount
, _Cardinal
, 32,
548 GDK_PROP_MODE_REPLACE
, (guchar
*) &count
, 1);
553 handle_urgent(PidginWindow
*win
, gboolean set
)
556 pidgin_set_urgent(GTK_WINDOW(win
->window
), set
);
561 handle_raise(PidginWindow
*purplewin
)
563 pidgin_conv_window_raise(purplewin
);
567 type_toggle_cb(GtkWidget
*widget
, gpointer data
)
569 gboolean on
= gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget
));
572 g_snprintf(pref
, sizeof(pref
), "/plugins/gtk/X11/notify/%s",
575 purple_prefs_set_bool(pref
, on
);
579 method_toggle_cb(GtkWidget
*widget
, gpointer data
)
581 gboolean on
= gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget
));
584 g_snprintf(pref
, sizeof(pref
), "/plugins/gtk/X11/notify/%s",
587 purple_prefs_set_bool(pref
, on
);
589 if (!strcmp(data
, "method_string")) {
590 GtkWidget
*entry
= g_object_get_data(G_OBJECT(widget
), "title-entry");
591 gtk_widget_set_sensitive(entry
, on
);
593 purple_prefs_set_string("/plugins/gtk/X11/notify/title_string",
594 gtk_entry_get_text(GTK_ENTRY(entry
)));
601 notify_toggle_cb(GtkWidget
*widget
, gpointer data
)
603 gboolean on
= gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget
));
606 g_snprintf(pref
, sizeof(pref
), "/plugins/gtk/X11/notify/%s",
609 purple_prefs_set_bool(pref
, on
);
615 options_entry_cb(GtkWidget
*widget
, GdkEventFocus
*evt
, gpointer data
)
620 if (!strcmp(data
, "method_string")) {
621 purple_prefs_set_string("/plugins/gtk/X11/notify/title_string",
622 gtk_entry_get_text(GTK_ENTRY(widget
)));
634 PidginWindow
*purplewin
= NULL
;
636 for (convs
= purple_get_conversations(); convs
!= NULL
;
637 convs
= convs
->next
) {
638 PurpleConversation
*conv
= (PurpleConversation
*)convs
->data
;
640 /* remove notifications */
641 unnotify(conv
, FALSE
);
643 purplewin
= PIDGIN_CONVERSATION(conv
)->win
;
644 if (GPOINTER_TO_INT(purple_conversation_get_data(conv
, "notify-message-count")) != 0)
645 /* reattach appropriate notifications */
653 GList
*convs
= purple_get_conversations();
656 PurpleConversation
*conv
= (PurpleConversation
*)convs
->data
;
659 detach_signals(conv
);
660 /* reattach appropriate signals */
661 attach_signals(conv
);
668 get_config_frame(PurplePlugin
*plugin
)
670 GtkWidget
*ret
= NULL
, *frame
= NULL
;
671 GtkWidget
*vbox
= NULL
, *hbox
= NULL
;
672 GtkWidget
*toggle
= NULL
, *entry
= NULL
, *ref
;
674 ret
= gtk_vbox_new(FALSE
, 18);
675 gtk_container_set_border_width(GTK_CONTAINER (ret
), 12);
677 /*---------- "Notify For" ----------*/
678 frame
= pidgin_make_frame(ret
, _("Notify For"));
679 vbox
= gtk_vbox_new(FALSE
, 5);
680 gtk_container_add(GTK_CONTAINER(frame
), vbox
);
682 toggle
= gtk_check_button_new_with_mnemonic(_("_IM windows"));
683 gtk_box_pack_start(GTK_BOX(vbox
), toggle
, FALSE
, FALSE
, 0);
684 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle
),
685 purple_prefs_get_bool("/plugins/gtk/X11/notify/type_im"));
686 g_signal_connect(G_OBJECT(toggle
), "toggled",
687 G_CALLBACK(type_toggle_cb
), "type_im");
689 toggle
= gtk_check_button_new_with_mnemonic(_("C_hat windows"));
690 gtk_box_pack_start(GTK_BOX(vbox
), toggle
, FALSE
, FALSE
, 0);
691 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle
),
692 purple_prefs_get_bool("/plugins/gtk/X11/notify/type_chat"));
693 g_signal_connect(G_OBJECT(toggle
), "toggled",
694 G_CALLBACK(type_toggle_cb
), "type_chat");
697 toggle
= gtk_check_button_new_with_mnemonic(_("\t_Only when someone says your screen name"));
698 gtk_box_pack_start(GTK_BOX(vbox
), toggle
, FALSE
, FALSE
, 0);
699 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle
),
700 purple_prefs_get_bool("/plugins/gtk/X11/notify/type_chat_nick"));
701 g_signal_connect(G_OBJECT(toggle
), "toggled",
702 G_CALLBACK(type_toggle_cb
), "type_chat_nick");
703 gtk_widget_set_sensitive(toggle
, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(ref
)));
704 g_signal_connect(G_OBJECT(ref
), "toggled",
705 G_CALLBACK(pidgin_toggle_sensitive
), toggle
);
707 toggle
= gtk_check_button_new_with_mnemonic(_("_Focused windows"));
708 gtk_box_pack_start(GTK_BOX(vbox
), toggle
, FALSE
, FALSE
, 0);
709 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle
),
710 purple_prefs_get_bool("/plugins/gtk/X11/notify/type_focused"));
711 g_signal_connect(G_OBJECT(toggle
), "toggled",
712 G_CALLBACK(type_toggle_cb
), "type_focused");
714 /*---------- "Notification Methods" ----------*/
715 frame
= pidgin_make_frame(ret
, _("Notification Methods"));
716 vbox
= gtk_vbox_new(FALSE
, 5);
717 gtk_container_add(GTK_CONTAINER(frame
), vbox
);
719 /* String method button */
720 hbox
= gtk_hbox_new(FALSE
, 18);
721 gtk_box_pack_start(GTK_BOX(vbox
), hbox
, FALSE
, FALSE
, 0);
722 toggle
= gtk_check_button_new_with_mnemonic(_("Prepend _string into window title:"));
723 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle
),
724 purple_prefs_get_bool("/plugins/gtk/X11/notify/method_string"));
725 gtk_box_pack_start(GTK_BOX(hbox
), toggle
, FALSE
, FALSE
, 0);
727 entry
= gtk_entry_new();
728 gtk_box_pack_start(GTK_BOX(hbox
), entry
, FALSE
, FALSE
, 0);
729 gtk_entry_set_max_length(GTK_ENTRY(entry
), 10);
730 gtk_widget_set_sensitive(GTK_WIDGET(entry
),
731 purple_prefs_get_bool("/plugins/gtk/X11/notify/method_string"));
732 gtk_entry_set_text(GTK_ENTRY(entry
),
733 purple_prefs_get_string("/plugins/gtk/X11/notify/title_string"));
734 g_object_set_data(G_OBJECT(toggle
), "title-entry", entry
);
735 g_signal_connect(G_OBJECT(toggle
), "toggled",
736 G_CALLBACK(method_toggle_cb
), "method_string");
737 g_signal_connect(G_OBJECT(entry
), "focus-out-event",
738 G_CALLBACK(options_entry_cb
), "method_string");
740 /* Count method button */
741 toggle
= gtk_check_button_new_with_mnemonic(_("Insert c_ount of new messages into window title"));
742 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle
),
743 purple_prefs_get_bool("/plugins/gtk/X11/notify/method_count"));
744 gtk_box_pack_start(GTK_BOX(vbox
), toggle
, FALSE
, FALSE
, 0);
745 g_signal_connect(G_OBJECT(toggle
), "toggled",
746 G_CALLBACK(method_toggle_cb
), "method_count");
749 /* Count xprop method button */
750 toggle
= gtk_check_button_new_with_mnemonic(_("Insert count of new message into _X property"));
751 gtk_box_pack_start(GTK_BOX(vbox
), toggle
, FALSE
, FALSE
, 0);
752 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle
),
753 purple_prefs_get_bool("/plugins/gtk/X11/notify/method_count_xprop"));
754 g_signal_connect(G_OBJECT(toggle
), "toggled",
755 G_CALLBACK(method_toggle_cb
), "method_count_xprop");
757 /* Urgent method button */
758 toggle
= gtk_check_button_new_with_mnemonic(_("Set window manager \"_URGENT\" hint"));
759 gtk_box_pack_start(GTK_BOX(vbox
), toggle
, FALSE
, FALSE
, 0);
760 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle
),
761 purple_prefs_get_bool("/plugins/gtk/X11/notify/method_urgent"));
762 g_signal_connect(G_OBJECT(toggle
), "toggled",
763 G_CALLBACK(method_toggle_cb
), "method_urgent");
766 /* Raise window method button */
767 toggle
= gtk_check_button_new_with_mnemonic(_("R_aise conversation window"));
768 gtk_box_pack_start(GTK_BOX(vbox
), toggle
, FALSE
, FALSE
, 0);
769 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle
),
770 purple_prefs_get_bool("/plugins/gtk/X11/notify/method_raise"));
771 g_signal_connect(G_OBJECT(toggle
), "toggled",
772 G_CALLBACK(method_toggle_cb
), "method_raise");
774 /*---------- "Notification Removals" ----------*/
775 frame
= pidgin_make_frame(ret
, _("Notification Removal"));
776 vbox
= gtk_vbox_new(FALSE
, 5);
777 gtk_container_add(GTK_CONTAINER(frame
), vbox
);
779 /* Remove on focus button */
780 toggle
= gtk_check_button_new_with_mnemonic(_("Remove when conversation window _gains focus"));
781 gtk_box_pack_start(GTK_BOX(vbox
), toggle
, FALSE
, FALSE
, 0);
782 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle
),
783 purple_prefs_get_bool("/plugins/gtk/X11/notify/notify_focus"));
784 g_signal_connect(G_OBJECT(toggle
), "toggled", G_CALLBACK(notify_toggle_cb
), "notify_focus");
786 /* Remove on click button */
787 toggle
= gtk_check_button_new_with_mnemonic(_("Remove when conversation window _receives click"));
788 gtk_box_pack_start(GTK_BOX(vbox
), toggle
, FALSE
, FALSE
, 0);
789 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle
),
790 purple_prefs_get_bool("/plugins/gtk/X11/notify/notify_click"));
791 g_signal_connect(G_OBJECT(toggle
), "toggled",
792 G_CALLBACK(notify_toggle_cb
), "notify_click");
794 /* Remove on type button */
795 toggle
= gtk_check_button_new_with_mnemonic(_("Remove when _typing in conversation window"));
796 gtk_box_pack_start(GTK_BOX(vbox
), toggle
, FALSE
, FALSE
, 0);
797 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle
),
798 purple_prefs_get_bool("/plugins/gtk/X11/notify/notify_type"));
799 g_signal_connect(G_OBJECT(toggle
), "toggled",
800 G_CALLBACK(notify_toggle_cb
), "notify_type");
802 /* Remove on message send button */
803 toggle
= gtk_check_button_new_with_mnemonic(_("Remove when a _message gets sent"));
804 gtk_box_pack_start(GTK_BOX(vbox
), toggle
, FALSE
, FALSE
, 0);
805 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle
),
806 purple_prefs_get_bool("/plugins/gtk/X11/notify/notify_send"));
807 g_signal_connect(G_OBJECT(toggle
), "toggled",
808 G_CALLBACK(notify_toggle_cb
), "notify_send");
811 /* Remove on conversation switch button */
812 toggle
= gtk_check_button_new_with_mnemonic(_("Remove on switch to conversation ta_b"));
813 gtk_box_pack_start(GTK_BOX(vbox
), toggle
, FALSE
, FALSE
, 0);
814 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle
),
815 purple_prefs_get_bool("/plugins/gtk/X11/notify/notify_switch"));
816 g_signal_connect(G_OBJECT(toggle
), "toggled",
817 G_CALLBACK(notify_toggle_cb
), "notify_switch");
820 gtk_widget_show_all(ret
);
825 plugin_load(PurplePlugin
*plugin
)
827 GList
*convs
= purple_get_conversations();
828 void *conv_handle
= purple_conversations_get_handle();
829 void *gtk_conv_handle
= pidgin_conversations_get_handle();
833 purple_signal_connect(gtk_conv_handle
, "displayed-im-msg", plugin
,
834 PURPLE_CALLBACK(message_displayed_cb
), NULL
);
835 purple_signal_connect(gtk_conv_handle
, "displayed-chat-msg", plugin
,
836 PURPLE_CALLBACK(message_displayed_cb
), NULL
);
837 purple_signal_connect(gtk_conv_handle
, "conversation-switched", plugin
,
838 PURPLE_CALLBACK(conv_switched
), NULL
);
839 purple_signal_connect(conv_handle
, "sent-im-msg", plugin
,
840 PURPLE_CALLBACK(im_sent_im
), NULL
);
841 purple_signal_connect(conv_handle
, "sent-chat-msg", plugin
,
842 PURPLE_CALLBACK(chat_sent_im
), NULL
);
843 purple_signal_connect(conv_handle
, "conversation-created", plugin
,
844 PURPLE_CALLBACK(conv_created
), NULL
);
845 purple_signal_connect(conv_handle
, "chat-joined", plugin
,
846 PURPLE_CALLBACK(conv_created
), NULL
);
847 purple_signal_connect(conv_handle
, "deleting-conversation", plugin
,
848 PURPLE_CALLBACK(deleting_conv
), NULL
);
850 purple_signal_connect(gtk_conv_handle
, "conversation-dragging", plugin
,
851 PURPLE_CALLBACK(conversation_dragging
), NULL
);
855 PurpleConversation
*conv
= (PurpleConversation
*)convs
->data
;
858 attach_signals(conv
);
867 plugin_unload(PurplePlugin
*plugin
)
869 GList
*convs
= purple_get_conversations();
872 PurpleConversation
*conv
= (PurpleConversation
*)convs
->data
;
875 detach_signals(conv
);
883 static PidginPluginUiInfo ui_info
=
886 0, /* page_num (Reserved) */
895 static PurplePluginInfo info
=
898 PURPLE_MAJOR_VERSION
,
899 PURPLE_MINOR_VERSION
,
900 PURPLE_PLUGIN_STANDARD
, /**< type */
901 PIDGIN_PLUGIN_TYPE
, /**< ui_requirement */
903 NULL
, /**< dependencies */
904 PURPLE_PRIORITY_DEFAULT
, /**< priority */
906 NOTIFY_PLUGIN_ID
, /**< id */
907 N_("Message Notification"), /**< name */
908 VERSION
, /**< version */
910 N_("Provides a variety of ways of notifying you of unread messages."),
912 N_("Provides a variety of ways of notifying you of unread messages."),
914 "Etan Reisner <deryni@eden.rutgers.edu>\n\t\t\tBrian Tarricone <bjt23@cornell.edu>",
915 PURPLE_WEBSITE
, /**< homepage */
917 plugin_load
, /**< load */
918 plugin_unload
, /**< unload */
919 NULL
, /**< destroy */
921 &ui_info
, /**< ui_info */
922 NULL
, /**< extra_info */
934 init_plugin(PurplePlugin
*plugin
)
936 purple_prefs_add_none("/plugins/gtk");
937 purple_prefs_add_none("/plugins/gtk/X11");
938 purple_prefs_add_none("/plugins/gtk/X11/notify");
940 purple_prefs_add_bool("/plugins/gtk/X11/notify/type_im", TRUE
);
941 purple_prefs_add_bool("/plugins/gtk/X11/notify/type_chat", FALSE
);
942 purple_prefs_add_bool("/plugins/gtk/X11/notify/type_chat_nick", FALSE
);
943 purple_prefs_add_bool("/plugins/gtk/X11/notify/type_focused", FALSE
);
944 purple_prefs_add_bool("/plugins/gtk/X11/notify/method_string", FALSE
);
945 purple_prefs_add_string("/plugins/gtk/X11/notify/title_string", "(*)");
946 purple_prefs_add_bool("/plugins/gtk/X11/notify/method_urgent", FALSE
);
947 purple_prefs_add_bool("/plugins/gtk/X11/notify/method_count", FALSE
);
948 purple_prefs_add_bool("/plugins/gtk/X11/notify/method_count_xprop", FALSE
);
949 purple_prefs_add_bool("/plugins/gtk/X11/notify/method_raise", FALSE
);
950 purple_prefs_add_bool("/plugins/gtk/X11/notify/notify_focus", TRUE
);
951 purple_prefs_add_bool("/plugins/gtk/X11/notify/notify_click", FALSE
);
952 purple_prefs_add_bool("/plugins/gtk/X11/notify/notify_type", TRUE
);
953 purple_prefs_add_bool("/plugins/gtk/X11/notify/notify_send", TRUE
);
954 purple_prefs_add_bool("/plugins/gtk/X11/notify/notify_switch", TRUE
);
957 PURPLE_INIT_PLUGIN(notify
, init_plugin
, info
)