Mercurial > pidgin
view plugins/notify.c @ 3572:bdd0bebd2d04
[gaim-migrate @ 3670]
Phase II. No longer do you have to worry about protocol plugins. When
Gaim probes plugins on load, it will detect protocol plugins and add them
to the list of available protocols. When you try to log an account on with
one of them, Gaim will automatically load the plugin--when no more accounts
need the protocol--Gaim will automatically unload it. Protocol plugins are
no longer available in the plugins ui, and no protocols are compiled statically
by default.
committer: Tailor Script <tailor@pidgin.im>
author | Sean Egan <seanegan@gmail.com> |
---|---|
date | Mon, 30 Sep 2002 01:05:18 +0000 |
parents | 154c4a9d9b6d |
children | 03ba413ca20b |
line wrap: on
line source
/* Rewritten by Etan Reisner <deryni@eden.rutgers.edu> * * Added config dialog * Added control over notification method * Added control over when to release notification * * Thanks to Carles Pina i Estany <carles@pinux.info> * for count of new messages option */ /* if my flash messages patch gets merged in can use cnv->local * to notify on new messages also */ #define GAIM_PLUGINS #include "gaim.h" #include <string.h> #include <ctype.h> #include <stdlib.h> #include <gtk/gtk.h> #include <X11/Xlib.h> #include <X11/Xutil.h> #include <X11/Xatom.h> #include <gdk/gdkx.h> guint choice = 1; #define NOTIFY_FOCUS 0x00000001 #define NOTIFY_TYPE 0x00000002 #define NOTIFY_IN_FOCUS 0x00000004 guint method = 1; #define METHOD_STRING 0x00000001 #define METHOD_QUOTE 0x00000002 #define METHOD_URGENT 0x00000004 #define METHOD_COUNT 0x00000008 void *handle; /* I really don't like this but I was having trouble getting any * other way of removing the signal callbacks to work and not crash gaim */ GtkWidget *really_evil_hack; /* GHashTable *hash = NULL; */ GtkWidget *Entry; gchar *title_string = "(*) "; /* predefine some functions, less warnings */ void options(GtkWidget *widget, gpointer data); void un_star(GtkWidget *widget, gpointer data); int un_star_window(GtkWidget *widget, gpointer data); void string_remove(GtkWidget *widget); void count_remove(GtkWidget *widget); void quote_remove(GtkWidget *widget); void urgent_remove(struct conversation *c); int counter (char *buf, int *length); int received_im(struct gaim_connection *gc, char **who, char **what, void *m) { char buf[256]; struct conversation *cnv = find_conversation(*who); GtkWindow *win; char *me = g_strdup(normalize(gc->username)); int revert_to_return; Window focus_return; int c, length; if (!strcmp(me, normalize(*who))) { g_free(me); return 0; } g_free(me); if (cnv == NULL) { if (away_options & OPT_AWAY_QUEUE) return 0; cnv = new_conversation(*who); } win = (GtkWindow *)cnv->window; XGetInputFocus(GDK_WINDOW_XDISPLAY(cnv->window->window), &focus_return, &revert_to_return); if ((choice & NOTIFY_IN_FOCUS) || focus_return != GDK_WINDOW_XWINDOW(cnv->window->window)) { if (method & METHOD_STRING) { strncpy(buf, win->title, sizeof(buf)); if (!strstr(buf, title_string)) { g_snprintf(buf, sizeof(buf), "%s%s", title_string, win->title); gtk_window_set_title(win, buf); } } if (method & METHOD_COUNT) { strncpy(buf, win->title, sizeof(buf)); c = counter(buf, &length); if (!c) { g_snprintf(buf, sizeof(buf), "[1] %s", win->title); } else if (!g_strncasecmp(buf, "[", 1)) { g_snprintf(buf, sizeof(buf), "[%d] %s", c+1, &win->title[3+length]); } gtk_window_set_title(win, buf); } if (method & METHOD_QUOTE) { strncpy(buf, win->title, sizeof(buf)); if (g_strncasecmp(buf, "\"", 1)) { g_snprintf(buf, sizeof(buf), "\"%s\"", win->title); gtk_window_set_title(win, buf); } } if (method & METHOD_URGENT) { /* do it the gdk way for windows compatibility(?) if I can figure it out */ /* Sean says this is a bad thing, and I should try using gtk_property_get first */ /* I'll want to pay attention to note on dev.gnome.org though */ /* gdk_property_change(win->window, WM_HINTS, WM_HINTS, 32, GDK_PROP_MODE_REPLACE, XUrgencyHint, 1); */ XWMHints *hints = XGetWMHints(GDK_WINDOW_XDISPLAY(cnv->window->window), GDK_WINDOW_XWINDOW(cnv->window->window)); hints->flags |= XUrgencyHint; XSetWMHints(GDK_WINDOW_XDISPLAY(cnv->window->window), GDK_WINDOW_XWINDOW(cnv->window->window), hints); } } return 0; } int sent_im(struct gaim_connection *gc, char *who, char **what, void *m) { /* char buf[256]; */ struct conversation *c = find_conversation(who); if (method & METHOD_QUOTE) quote_remove(c->window); if (method & METHOD_COUNT) count_remove(c->window); if (method & METHOD_STRING) string_remove(c->window); if (method & METHOD_URGENT) urgent_remove(c); return 0; } int new_conv(char *who) { struct conversation *c = find_conversation(who); /* g_hash_table_insert(hash, who, GINT_TO_POINTER(choice)); */ if (choice & NOTIFY_FOCUS) { gtk_signal_connect_while_alive(GTK_OBJECT(c->window), "focus-in-event", GTK_SIGNAL_FUNC(un_star), NULL, GTK_OBJECT(really_evil_hack)); gtk_object_set_user_data(GTK_OBJECT(c->window), c); } else { gtk_signal_connect_while_alive(GTK_OBJECT(c->window), "button_press_event", GTK_SIGNAL_FUNC(un_star), NULL, GTK_OBJECT(really_evil_hack)); gtk_object_set_user_data(GTK_OBJECT(c->window), c); gtk_signal_connect_while_alive(GTK_OBJECT(c->text), "button_press_event", GTK_SIGNAL_FUNC(un_star_window), NULL, GTK_OBJECT(really_evil_hack)); gtk_object_set_user_data(GTK_OBJECT(c->text), c); gtk_signal_connect_while_alive(GTK_OBJECT(c->entry), "button_press_event", GTK_SIGNAL_FUNC(un_star_window), NULL, GTK_OBJECT(really_evil_hack)); gtk_object_set_user_data(GTK_OBJECT(c->entry), c); } if (choice & NOTIFY_TYPE) { gtk_signal_connect_while_alive(GTK_OBJECT(c->entry), "key-press-event", GTK_SIGNAL_FUNC(un_star_window), NULL, GTK_OBJECT(really_evil_hack)); gtk_object_set_user_data(GTK_OBJECT(c->entry), (gpointer) c); } return 0; } void un_star(GtkWidget *widget, gpointer data) { struct conversation *c = gtk_object_get_user_data(GTK_OBJECT(widget)); if (method & METHOD_QUOTE) quote_remove(widget); if (method & METHOD_COUNT) count_remove(widget); if (method & METHOD_STRING) string_remove(widget); if (method & METHOD_URGENT) urgent_remove(c); return; } int un_star_window(GtkWidget *widget, gpointer data) { GtkWidget *parent = gtk_widget_get_ancestor(widget, GTK_TYPE_WINDOW); gtk_object_set_user_data(GTK_OBJECT(parent), gtk_object_get_user_data(GTK_OBJECT(widget))); un_star(parent, data); return 0; } /* This function returns the number in [ ]'s or 0 */ int counter (char *buf, int *length) { char temp[256]; int i = 1; *length = 0; /* if (buf[0] != '[') */ /* return (0); */ while (isdigit(buf[i]) && i<sizeof(buf)) { temp[i-1] = buf[i]; (*length)++; i++; } temp[i] = '\0'; if (buf[i] != ']') { *length = 0; return (0); } return (atoi(temp)); } void string_remove(GtkWidget *widget) { char buf[256]; GtkWindow *win = GTK_WINDOW(widget); strncpy(buf, win->title, sizeof(buf)); if (strstr(buf, title_string)) { g_snprintf(buf, sizeof(buf), "%s", &win->title[strlen(title_string)]); gtk_window_set_title(win, buf); } return; } void count_remove(GtkWidget *widget) { char buf[256]; GtkWindow *win = GTK_WINDOW(widget); int length; strncpy(buf, win->title, sizeof(buf)); if (!g_strncasecmp(buf, "[", 1)) { counter(buf, &length); g_snprintf(buf, sizeof(buf), "%s", &win->title[3+length]); gtk_window_set_title(win, buf); } return; } void quote_remove(GtkWidget *widget) { char buf[256]; GtkWindow *win = GTK_WINDOW(widget); strncpy(buf, win->title, sizeof(buf)); if (!g_strncasecmp(buf, "\"", 1)) { g_snprintf(buf, strlen(buf) - 1, "%s", &win->title[1]); gtk_window_set_title(win, buf); } return; } void urgent_remove(struct conversation *c) { GdkWindow *win = c->window->window; XWMHints *hints = XGetWMHints(GDK_WINDOW_XDISPLAY(win), GDK_WINDOW_XWINDOW(win)); hints->flags &= ~XUrgencyHint; XSetWMHints(GDK_WINDOW_XDISPLAY(win), GDK_WINDOW_XWINDOW(win), hints); return; } void save_notify_prefs() { gchar buf[1000]; FILE *fp; snprintf(buf, 1000, "%s/.gaim/.notify", getenv("HOME")); if (!(fp = fopen(buf, "w"))) { do_error_dialog(_("Unable to write to config file"), _("Notify plugin"), GAIM_ERROR); return; } fprintf(fp, "%d=CHOICE\n", choice); fprintf(fp, "%d=METHOD\n", method); fprintf(fp, "%s=STRING\n", title_string); fclose(fp); } void load_notify_prefs() { gchar buf[1000]; gchar **parsed; FILE *fp; g_snprintf(buf, sizeof(buf), "%s/.gaim/.notify", getenv("HOME")); if (!(fp = fopen(buf, "r"))) return; while (fgets(buf, 1000, fp) != NULL) { parsed = g_strsplit(g_strchomp(buf), "=", 2); if (parsed[0] && parsed[1]) { if (!strcmp(parsed[1], "CHOICE")) choice = atoi(parsed[0]); if (!strcmp(parsed[1], "METHOD")) method = atoi(parsed[0]); if (!strcmp(parsed[1], "STRING")) if (title_string != NULL) g_free(title_string); title_string = g_strdup(parsed[0]); } g_strfreev(parsed); } fclose(fp); return; } void options(GtkWidget *widget, gpointer data) { gint option = GPOINTER_TO_INT(data); if (option == 0) choice ^= NOTIFY_FOCUS; else if (option == 1) choice ^= NOTIFY_TYPE; else if (option == 2) { method ^= METHOD_STRING; if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) gtk_widget_set_sensitive(Entry, TRUE); else gtk_widget_set_sensitive(Entry, FALSE); } else if (option == 3) method ^= METHOD_QUOTE; else if (option == 4) method ^= METHOD_URGENT; else if (option == 5) choice ^= NOTIFY_IN_FOCUS; else if (option == 6) method ^= METHOD_COUNT; } char *gaim_plugin_init(GModule *hndl) { handle = hndl; really_evil_hack = gtk_label_new(""); /* hash = g_hash_table_new(g_str_hash, g_int_equal); */ load_notify_prefs(); gaim_signal_connect(handle, event_im_recv, received_im, NULL); gaim_signal_connect(handle, event_im_send, sent_im, NULL); gaim_signal_connect(handle, event_new_conversation, new_conv, NULL); return NULL; } void gaim_plugin_remove() { GList *c = conversations; /* guint options; */ gtk_widget_destroy(really_evil_hack); while (c) { struct conversation *cnv = (struct conversation *)c->data; /* if (options = GPOINTER_TO_INT(g_hash_table_lookup(hash, cnv->name))) { */ un_star(cnv->window, NULL); /* if (options & REMOVE_FOCUS) */ /* gtk_signal_disconnect_by_func(GTK_OBJECT(cnv->window), GTK_SIGNAL_FUNC(un_star), NULL); */ /* else { */ /* gtk_signal_disconnect_by_func(GTK_OBJECT(cnv->window), GTK_SIGNAL_FUNC(un_star), NULL); */ /* gtk_signal_disconnect_by_func(GTK_OBJECT(cnv->text), GTK_SIGNAL_FUNC(un_star_window), NULL); */ /* gtk_signal_disconnect_by_func(GTK_OBJECT(cnv->entry), GTK_SIGNAL_FUNC(un_star_window), NULL); */ /* } */ /* if (options & REMOVE_TYPE) */ /* gtk_signal_disconnect_by_func(GTK_OBJECT(cnv->entry), GTK_SIGNAL_FUNC(un_star_window), NULL); */ /* } */ c = c->next; } } struct gaim_plugin_description desc; struct gaim_plugin_description *gaim_plugin_desc() { desc.api_version = PLUGIN_API_VERSION; desc.name = g_strdup("Message Notification"); desc.version = g_strdup(VERSION); desc.description = g_strdup("Provides a variety of ways of notifying you of unread messages."); desc.authors = g_strdup("Etan Reisner <deryni@eden.rutgers.edu>"); desc.url = g_strdup(WEBSITE); return &desc; } char *name() { return "Visual Notification"; } char *description() { return "Puts an asterisk in the title bar of all conversations" " where you have not responded to a message yet."; } GtkWidget *gaim_plugin_config_gtk() { GtkWidget *ret; GtkWidget *vbox, *hbox; GtkWidget *toggle; ret = gtk_vbox_new(FALSE, 18); gtk_container_set_border_width (GTK_CONTAINER (ret), 12); vbox = make_frame(ret, _("Notification Methods")); hbox = gtk_hbox_new(FALSE, 18); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); toggle = gtk_check_button_new_with_mnemonic(_("Prepend _string into window title:")); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle), method & METHOD_STRING); gtk_signal_connect(GTK_OBJECT(toggle), "toggled", GTK_SIGNAL_FUNC(options), GINT_TO_POINTER(2)); gtk_box_pack_start(GTK_BOX(hbox), toggle, FALSE, FALSE, 0); Entry = gtk_entry_new_with_max_length(7); gtk_widget_set_sensitive(GTK_WIDGET(Entry), method & METHOD_STRING); gtk_box_pack_start(GTK_BOX(hbox), Entry, FALSE, FALSE, 0); gtk_entry_set_text(GTK_ENTRY(Entry), title_string); toggle = gtk_check_button_new_with_mnemonic(_("_Quote window title.")); gtk_box_pack_start(GTK_BOX(vbox), toggle, FALSE, FALSE, 0); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle), method & METHOD_QUOTE); gtk_signal_connect(GTK_OBJECT(toggle), "toggled", GTK_SIGNAL_FUNC(options), GINT_TO_POINTER(3)); toggle = gtk_check_button_new_with_mnemonic(_("Set Window Manager \"_URGENT\" Hint")); gtk_box_pack_start(GTK_BOX(vbox), toggle, FALSE, FALSE, 0); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle), method & METHOD_URGENT); gtk_signal_connect(GTK_OBJECT(toggle), "toggled", GTK_SIGNAL_FUNC(options), GINT_TO_POINTER(4)); toggle = gtk_check_button_new_with_mnemonic(_("Insert _count of new messages into window title")); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle), method & METHOD_COUNT); gtk_box_pack_start(GTK_BOX(vbox), toggle, FALSE, FALSE, 0); gtk_signal_connect(GTK_OBJECT(toggle), "toggled", GTK_SIGNAL_FUNC(options), GINT_TO_POINTER(6)); toggle = gtk_check_button_new_with_mnemonic(_("_Notify even if conversation is in focus.")); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle), choice & NOTIFY_IN_FOCUS); gtk_box_pack_start(GTK_BOX(vbox), toggle, FALSE, FALSE, 0); gtk_signal_connect(GTK_OBJECT(toggle), "toggled", GTK_SIGNAL_FUNC(options), GINT_TO_POINTER(5)); /*--------------*/ vbox = make_frame(ret, _("Notification Removal")); toggle = gtk_check_button_new_with_mnemonic(_("Remove when conversation window gains _focus.")); gtk_box_pack_start(GTK_BOX(vbox), toggle, FALSE, FALSE, 0); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle), choice & NOTIFY_FOCUS); gtk_signal_connect(GTK_OBJECT(toggle), "toggled", GTK_SIGNAL_FUNC(options), GINT_TO_POINTER(0)); toggle = gtk_check_button_new_with_mnemonic(_("Remove when _typing in conversation window")); gtk_box_pack_start(GTK_BOX(vbox), toggle, FALSE, FALSE, 0); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(toggle), choice & NOTIFY_TYPE); gtk_signal_connect(GTK_OBJECT(toggle), "toggled", GTK_SIGNAL_FUNC(options), GINT_TO_POINTER(1)); gtk_widget_show_all(ret); return ret; }