Mercurial > grim > purple-plugin-pack
view nicksaid/nicksaid.c @ 1015:8c6a8f3d1f18 org.guifications.plugins
And fix my stupid mistake.
author | John Bailey <rekkanoryo@rekkanoryo.org> |
---|---|
date | Fri, 03 Jul 2009 11:47:59 -0400 |
parents | b8ccd6f7365a |
children |
line wrap: on
line source
/* * Nicksaid - Record when someone said your nick in a chat. * Copyright (C) 2006-2008 Sadrul Habib Chowdhury <sadrul@users.sourceforge.net> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02111-1301, USA. */ /* If you can't figure out what this line is for, DON'T TOUCH IT. */ #include "../common/pp_internal.h" #define PLUGIN_ID "gtk-plugin_pack-nicksaid" #define PLUGIN_STATIC_NAME "nicksaid" #define PLUGIN_AUTHOR "Sadrul H Chowdhury <sadrul@users.sourceforge.net>" #define PREF_PREFIX "/plugins/gtk/" PLUGIN_ID #define PREF_HLWORDS PREF_PREFIX "/hlwords" #define PREF_CHARS PREF_PREFIX "/chars" #define PREF_TIMESTAMP PREF_PREFIX "/timestamp" #define PREF_DATESTAMP PREF_PREFIX "/datestamp" #define PREF_SHOWWHO PREF_PREFIX "/showwho" #define PREF_SHOWALL PREF_PREFIX "/showall" /* System headers */ #include <string.h> #include <gdk/gdk.h> #include <gtk/gtk.h> /* libpurple headers */ #include <notify.h> /* Pidgin headers */ #include <gtkconv.h> #include <gtkimhtml.h> #include <gtkmenutray.h> #include <gtkplugin.h> #include <gtkutils.h> #include <pidginstock.h> #define DELIMS " .,;|<>?/\\`~!@#$%^&*()_-+={}[]:'\"" static GList *hlwords = NULL; /* Words to highlight on */ #if 0 static void go_next(GtkWidget *w, PidginConversation *gtkconv) { } static void go_previous(GtkWidget *w, PidginConversation *gtkconv) { } #endif typedef struct _NickSaid NickSaid; struct _NickSaid { int offset; char *who; char *what; }; /* <lift src="pidgin/src/util.c"> ??? */ static const gchar * ns_time(void) { static gchar buf[80]; time_t tme; time(&tme); strftime(buf, sizeof(buf), "%H:%M:%S", localtime(&tme)); return buf; } static const gchar * ns_date(void) { static gchar buf[80]; time_t tme; time(&tme); strftime(buf, sizeof(buf), "%Y-%m-%d", localtime(&tme)); return buf; } static const gchar * ns_date_full(void) { gchar *buf; time_t tme; time(&tme); buf = ctime(&tme); buf[strlen(buf) - 1] = '\0'; return buf; } /* <lift/> */ struct _callbackdata { GtkTextView *view; GtkTextIter iter; }; static gboolean draw_line(GtkWidget *widget, GdkEventExpose *event, struct _callbackdata *data); static gboolean remove_line(struct _callbackdata *data) { if (g_signal_handlers_disconnect_matched(G_OBJECT(data->view), G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, data)) { g_object_set_data(G_OBJECT(data->view), "nicksaid:mark", GINT_TO_POINTER(0)); gtk_widget_queue_draw(GTK_WIDGET(data->view)); g_free(data); } return FALSE; } static gboolean draw_line(GtkWidget *widget, GdkEventExpose *event, struct _callbackdata *data) { GtkTextIter iter; GdkRectangle rect, visible_rect; int top, bottom, pad; GdkGC *gc; GtkTextView *view; GdkColor green = {0, 0, 0xffff, 0}; view = data->view; iter = data->iter; gtk_text_view_get_iter_location(view, &iter, &rect); pad = (gtk_text_view_get_pixels_below_lines(view) + gtk_text_view_get_pixels_above_lines(view)) / 2; top = rect.y - pad; bottom = rect.y + rect.height + pad; gtk_text_view_buffer_to_window_coords(view, GTK_TEXT_WINDOW_TEXT, 0, top, 0, &top); gtk_text_view_buffer_to_window_coords(view, GTK_TEXT_WINDOW_TEXT, 0, bottom, 0, &bottom); gtk_text_view_get_visible_rect(view, &visible_rect); gc = gdk_gc_new(GDK_DRAWABLE(event->window)); gdk_gc_set_rgb_fg_color(gc, &green); gdk_draw_line(event->window, gc, 0, top, visible_rect.width, top); gdk_draw_line(event->window, gc, 0, bottom, visible_rect.width, bottom); gdk_gc_unref(gc); if (!g_object_get_data(G_OBJECT(view), "nicksaid:mark")) { g_timeout_add(2500, (GSourceFunc)remove_line, data); g_object_set_data(G_OBJECT(view), "nicksaid:mark", GINT_TO_POINTER(1)); } return FALSE; } static void go_selected(GtkWidget *w, PidginConversation *gtkconv) { GtkTextIter iter; int offset; struct _callbackdata *data; offset = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(w), "nicksaid:offset")) + 1; gtk_text_buffer_get_iter_at_offset(GTK_IMHTML(gtkconv->imhtml)->text_buffer, &iter, offset); gtk_text_view_scroll_to_iter(GTK_TEXT_VIEW(gtkconv->imhtml), &iter, 0, TRUE, 0, 0); data = g_new0(struct _callbackdata, 1); data->view = GTK_TEXT_VIEW(gtkconv->imhtml); data->iter = iter; g_signal_connect(G_OBJECT(gtkconv->imhtml), "expose_event", G_CALLBACK(draw_line), data); gtk_widget_queue_draw(gtkconv->imhtml); } static void clear_list(GtkWidget *w, PidginConversation *gtkconv) { GList *ll, *list; ll = list = g_object_get_data(G_OBJECT(gtkconv->imhtml), "nicksaid:list"); while (list) { NickSaid *said = list->data; g_free(said->who); g_free(said->what); g_free(said); list = list->next; } g_list_free(ll); g_object_set_data(G_OBJECT(gtkconv->imhtml), "nicksaid:list", NULL); } static void show_all(GtkWidget *w, PidginConversation *gtkconv) { GList *list = g_object_get_data(G_OBJECT(gtkconv->imhtml), "nicksaid:list"); GString *str = g_string_new(NULL); while (list) { NickSaid *said = list->data; g_string_append_printf(str, "%s<br/>\n", said->what); list = list->next; } purple_notify_formatted(gtkconv, _("Nicksaid"), _("List of highlighted messages:"), NULL, str->str, NULL, NULL); g_string_free(str, TRUE); } static gboolean generate_popup(GtkWidget *w, GdkEventButton *event, PidginWindow *win) { GtkWidget *menu, *item; PurpleConversation *conv; PidginConversation *gtkconv; GList *list; conv = pidgin_conv_window_get_active_conversation(win); if (purple_conversation_get_type(conv) != PURPLE_CONV_TYPE_CHAT) return FALSE; menu = gtk_menu_new(); gtkconv = PIDGIN_CONVERSATION(conv); list = g_object_get_data(G_OBJECT(gtkconv->imhtml), "nicksaid:list"); if (!list) { item = gtk_menu_item_new_with_label(_("None")); gtk_widget_set_sensitive(item, FALSE); gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); gtk_widget_show(item); } else { #if 0 item = gtk_menu_item_new_with_label(_("Next")); gtk_widget_show(item); gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(go_next), gtkconv); item = gtk_menu_item_new_with_label(_("Previous")); gtk_widget_show(item); gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(go_previous), gtkconv); pidgin_separator(menu); #endif while (list) { NickSaid *said = list->data; item = gtk_menu_item_new_with_label(said->who); gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); gtk_widget_show(item); g_object_set_data(G_OBJECT(item), "nicksaid:offset", GINT_TO_POINTER(said->offset)); g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(go_selected), gtkconv); /* TODO: * If the line to scrollback to is greater /pidgin/gtk/conversations/scrollback_lines, * desensitise the widget so it at least displays.. or something like that. you get the drift. */ list = list->next; } pidgin_separator(menu); item = gtk_menu_item_new_with_label(_("Clear History")); gtk_widget_show(item); gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(clear_list), gtkconv); item = gtk_menu_item_new_with_label(_("Show All")); gtk_widget_show(item); gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); if (purple_prefs_get_bool(PREF_SHOWALL)) g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(show_all), gtkconv); else gtk_widget_set_sensitive(item, FALSE); } gtk_widget_show_all(menu); gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, event->button, event->time); return TRUE; } static gboolean displaying_msg_cb(PurpleAccount *account, const char *name, char **buffer, PurpleConversation *conv, PurpleMessageFlags flags, gpointer null) { PidginConversation *gtkconv; GtkWidget *imhtml; GtkTextIter iter; GList *list; int pos; char *tmp, *who, *prefix = NULL; NickSaid *said; gboolean timestamp = purple_prefs_get_bool(PREF_TIMESTAMP); gboolean datestamp = purple_prefs_get_bool(PREF_DATESTAMP); gboolean showwho = purple_prefs_get_bool(PREF_SHOWWHO); if (!(flags & PURPLE_MESSAGE_NICK) || !PIDGIN_IS_PIDGIN_CONVERSATION(conv) || purple_conversation_get_type(conv) != PURPLE_CONV_TYPE_CHAT) return FALSE; gtkconv = PIDGIN_CONVERSATION(conv); imhtml = gtkconv->imhtml; gtk_text_buffer_get_end_iter(GTK_IMHTML(imhtml)->text_buffer, &iter); pos = gtk_text_iter_get_offset(&iter); list = g_object_get_data(G_OBJECT(imhtml), "nicksaid:list"); tmp = purple_markup_strip_html(*buffer); who = g_strndup(tmp, purple_prefs_get_int(PREF_CHARS)); g_free(tmp); if (!g_utf8_validate(who, -1, (const char **)&tmp)) *tmp = '\0'; if (showwho) { tmp = who; who = g_strdup_printf("%s: %s", name, tmp); g_free(tmp); } if (datestamp && timestamp) { prefix = g_strdup_printf("(%s) ", ns_date_full()); } else if (datestamp && !timestamp) { prefix = g_strdup_printf("(%s) ", ns_date()); } else if (!datestamp && timestamp) { prefix = g_strdup_printf("(%s) ", ns_time()); } said = g_new0(NickSaid, 1); said->offset = pos; if (prefix != NULL) { said->who = g_strdup_printf("%s%s", prefix, who); g_free(who); } else { said->who = who; } if (purple_prefs_get_bool(PREF_SHOWALL)) { said->what = g_strdup_printf("%s<b>%s: </b>%s", prefix ? prefix : "", name, *buffer); } g_free(prefix); list = g_list_prepend(list, said); g_object_set_data(G_OBJECT(imhtml), "nicksaid:list", list); return FALSE; } static GtkWidget * get_tray_icon_for_window(PidginWindow *win) { GtkWidget *w = g_object_get_data(G_OBJECT(win->window), "nicksaid:trayicon"); if (w == NULL) { w = gtk_event_box_new(); #if GTK_CHECK_VERSION(2,4,0) gtk_event_box_set_visible_window(GTK_EVENT_BOX(w), TRUE); #endif gtk_container_add(GTK_CONTAINER(w), gtk_image_new_from_stock(PIDGIN_STOCK_TOOLBAR_MESSAGE_NEW, GTK_ICON_SIZE_MENU)); pidgin_menu_tray_append(PIDGIN_MENU_TRAY(win->menu.tray), w, "Nicksaid"); gtk_widget_show_all(w); g_object_set_data(G_OBJECT(win->window), "nicksaid:trayicon", w); g_signal_connect(G_OBJECT(w), "button_press_event", G_CALLBACK(generate_popup), win); } return w; } static void update_menu_tray(PurpleConversation *conv) { PidginConversation *gtkconv; PidginWindow *win; GtkWidget *icon; if (!PIDGIN_IS_PIDGIN_CONVERSATION(conv)) return; gtkconv = PIDGIN_CONVERSATION(conv); win = gtkconv->win; if (!win) return; icon = get_tray_icon_for_window(win); if (purple_conversation_get_type(conv) != PURPLE_CONV_TYPE_CHAT) gtk_widget_hide_all(icon); else gtk_widget_show_all(icon); } static void deleting_conversation_cb(PurpleConversation *conv, gpointer null) { if (purple_conversation_get_type(conv) != PURPLE_CONV_TYPE_CHAT || !PIDGIN_IS_PIDGIN_CONVERSATION(conv)) return; clear_list(NULL, PIDGIN_CONVERSATION(conv)); } static gboolean rcvd_msg_cb(PurpleAccount *account, const char **who, const char **message, PurpleConversation *conv, PurpleMessageFlags *flags) { char *msg, *delims; GList *iter; if (*flags & PURPLE_MESSAGE_NICK) return FALSE; delims = g_strdup(DELIMS); g_strdelimit(delims, purple_prefs_get_string(PREF_HLWORDS), ' '); msg = g_strdup(*message); g_strdelimit(msg, delims, ' '); g_free(delims); for (iter = hlwords; iter; iter = iter->next) { char *s = g_strstr_len(msg, -1, iter->data); if (s && (s == msg || *(s - 1) == ' ')) { char *e = s + strlen(iter->data); if (*e == ' ' || *e == '\0') { *flags |= PURPLE_MESSAGE_NICK; break; } } } g_free(msg); return FALSE; } static void destroy_list() { while (hlwords) { g_free(hlwords->data); hlwords = g_list_delete_link(hlwords, hlwords); } } static void construct_list() { char *string; const char *s, *e; destroy_list(); string = g_strdup(purple_prefs_get_string(PREF_HLWORDS)); s = string; e = NULL; if (s == NULL) return; while (*s) { while (*s == ' ' || *s == '\t') s++; e = s + 1; while (*e != ' ' && *e != '\t' && *e != '\0') e++; hlwords = g_list_prepend(hlwords, g_strndup(s, e-s)); s = e; } g_free(string); } static void unload_cleanup_gtkconv(PidginConversation *gtkconv, gpointer null) { clear_list(NULL, gtkconv); } static void unload_cleanup_win(PidginWindow *win, gpointer null) { GtkWidget *w = get_tray_icon_for_window(win); g_object_set_data(G_OBJECT(win->window), "nicksaid:trayicon", NULL); gtk_widget_destroy(w); g_list_foreach(pidgin_conv_window_get_gtkconvs(win), (GFunc)unload_cleanup_gtkconv, NULL); } static gboolean plugin_load(PurplePlugin *plugin) { construct_list(); purple_signal_connect(purple_conversations_get_handle(), "receiving-chat-msg", plugin, PURPLE_CALLBACK(rcvd_msg_cb), NULL); purple_signal_connect(pidgin_conversations_get_handle(), "displaying-chat-msg", plugin, PURPLE_CALLBACK(displaying_msg_cb), NULL); purple_signal_connect(pidgin_conversations_get_handle(), "conversation-switched", plugin, PURPLE_CALLBACK(update_menu_tray), NULL); purple_signal_connect(purple_conversations_get_handle(), "deleting-conversation", plugin, PURPLE_CALLBACK(deleting_conversation_cb), NULL); purple_prefs_connect_callback(plugin, PREF_HLWORDS, (PurplePrefCallback)construct_list, NULL); purple_conversation_foreach(update_menu_tray); return TRUE; } static gboolean plugin_unload(PurplePlugin *plugin) { destroy_list(); g_list_foreach(pidgin_conv_windows_get_list(), (GFunc)unload_cleanup_win, NULL); purple_prefs_disconnect_by_handle(plugin); return TRUE; } static PurplePluginPrefFrame * get_plugin_pref_frame(PurplePlugin *plugin) { PurplePluginPrefFrame *frame; PurplePluginPref *pref; frame = purple_plugin_pref_frame_new(); pref = purple_plugin_pref_new_with_label(_("Highlight")); purple_plugin_pref_frame_add(frame, pref); pref = purple_plugin_pref_new_with_name_and_label(PREF_HLWORDS, _("_Words to highlight on\n(separate the words with a blank space)")); purple_plugin_pref_frame_add(frame, pref); pref = purple_plugin_pref_new_with_label(_("Number of displayed characters")); purple_plugin_pref_frame_add(frame, pref); pref = purple_plugin_pref_new_with_name_and_label(PREF_CHARS, _("_Set the number of characters displayed\nin the nicksaid menu")); purple_plugin_pref_set_bounds(pref, 10, 40); purple_plugin_pref_frame_add(frame, pref); pref = purple_plugin_pref_new_with_name_and_label(PREF_SHOWWHO, _("Display who said your name in the nicksaid menu")); purple_plugin_pref_frame_add(frame, pref); pref = purple_plugin_pref_new_with_name_and_label(PREF_TIMESTAMP, _("Display _timestamps in the nicksaid menu")); purple_plugin_pref_frame_add(frame, pref); pref = purple_plugin_pref_new_with_name_and_label(PREF_DATESTAMP, _("_Display _datestamps in the nicksaid menu")); purple_plugin_pref_frame_add(frame, pref); pref = purple_plugin_pref_new_with_name_and_label(PREF_SHOWALL, _("Allow displaying in a separate dialog")); purple_plugin_pref_frame_add(frame, pref); return frame; } static PurplePluginUiInfo prefs_info = { get_plugin_pref_frame, 0, NULL, NULL, NULL, NULL, NULL }; static PurplePluginInfo info = { PURPLE_PLUGIN_MAGIC, /* Magic */ PURPLE_MAJOR_VERSION, /* Purple Major Version */ PURPLE_MINOR_VERSION, /* Purple Minor Version */ PURPLE_PLUGIN_STANDARD, /* plugin type */ PIDGIN_PLUGIN_TYPE, /* ui requirement */ 0, /* flags */ NULL, /* dependencies */ PURPLE_PRIORITY_DEFAULT, /* priority */ PLUGIN_ID, /* plugin id */ NULL, /* name */ PP_VERSION, /* version */ NULL, /* summary */ NULL, /* description */ PLUGIN_AUTHOR, /* author */ PP_WEBSITE, /* website */ plugin_load, /* load */ plugin_unload, /* unload */ NULL, /* destroy */ NULL, /* ui_info */ NULL, /* extra_info */ &prefs_info, /* prefs_info */ NULL, /* actions */ NULL, /* reserved 1 */ NULL, /* reserved 2 */ NULL, /* reserved 3 */ NULL /* reserved 4 */ }; static void init_plugin(PurplePlugin *plugin) { #ifdef ENABLE_NLS bindtextdomain(GETTEXT_PACKAGE, PP_LOCALEDIR); bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8"); #endif /* ENABLE_NLS */ info.name = _("Nicksaid"); info.summary = _("Record when someone said your nick in a chat."); info.description = _("Record when someone said your nick in a chat."); purple_prefs_add_none(PREF_PREFIX); purple_prefs_add_string(PREF_HLWORDS, ""); purple_prefs_add_int(PREF_CHARS, 15); purple_prefs_add_bool(PREF_TIMESTAMP, TRUE); purple_prefs_add_bool(PREF_DATESTAMP, FALSE); purple_prefs_add_bool(PREF_SHOWWHO, TRUE); purple_prefs_add_bool(PREF_SHOWALL, FALSE); } PURPLE_INIT_PLUGIN(PLUGIN_STATIC_NAME, init_plugin, info)