changeset 31:312a745dece6

added letter counter
author Yoshiki Yazawa <yaz@cc.rim.or.jp>
date Sat, 10 May 2008 18:10:58 +0900
parents e740ceed9337
children 92715b489de6
files pidgin-twitter.c
diffstat 1 files changed, 277 insertions(+), 12 deletions(-) [+]
line wrap: on
line diff
--- a/pidgin-twitter.c	Tue May 06 22:11:03 2008 +0900
+++ b/pidgin-twitter.c	Sat May 10 18:10:58 2008 +0900
@@ -29,13 +29,16 @@
 #include "connection.h"
 #include "version.h"
 #include "sound.h"
+#include "gtkconv.h"
 
 #define RECIPIENT   0
 #define SENDER      1
 #define COMMAND     2
 #define PSEUDO      3
 
-#define PIDGINTWITTER_PLUGIN_ID	"pidgin_twitter"
+#define PLUGIN_ID	            "gtk-honeyplanet-pidgin_twitter"
+#define PLUGIN_NAME	            "pidgin-twitter"
+
 #define OPT_PIDGINTWITTER 		"/plugins/pidgin_twitter"
 #define OPT_TRANSLATE_RECIPIENT OPT_PIDGINTWITTER "/translate_recipient"
 #define OPT_TRANSLATE_SENDER    OPT_PIDGINTWITTER "/translate_sender"
@@ -46,17 +49,27 @@
 #define OPT_ESCAPE_PSEUDO       OPT_PIDGINTWITTER "/escape_pseudo"
 #define OPT_USERLIST_RECIPIENT  OPT_PIDGINTWITTER "/userlist_recipient"
 #define OPT_USERLIST_SENDER     OPT_PIDGINTWITTER "/userlist_sender"
+#define OPT_COUNTER             OPT_PIDGINTWITTER "/counter"
+
 #define RECIPIENT_FORMAT        "@<a href='http://twitter.com/%s'>%s</a>"
 #define SENDER_FORMAT           "<a href='http://twitter.com/%s'>%s</a>: "
-#define DEFAULT_LIST             "(list of users: separated with ' ,:;')"
+#define DEFAULT_LIST            "(list of users: separated with ' ,:;')"
+
 
-#define twitter_debug(fmt, ...)	purple_debug(PURPLE_DEBUG_INFO, PIDGINTWITTER_PLUGIN_ID, \
+#define twitter_debug(fmt, ...)	purple_debug(PURPLE_DEBUG_INFO, PLUGIN_NAME, \
                                              fmt, ## __VA_ARGS__);
-#define twitter_error(fmt, ...)	purple_debug(PURPLE_DEBUG_ERROR, PIDGINTWITTER_PLUGIN_ID, \
+#define twitter_error(fmt, ...)	purple_debug(PURPLE_DEBUG_ERROR, PLUGIN_NAME, \
 
 /* globals */
 static GRegex *regp[4];
 
+/* prototypes */
+static gboolean is_twitter_conv(PurpleConversation *conv);
+static void attach_to_gtkconv(PidginConversation *gtkconv, gpointer null);
+static void detach_from_gtkconv(PidginConversation *gtkconv, gpointer null);
+static void escape(gchar **str);
+
+
 static void
 escape(gchar **str)
 {
@@ -115,7 +128,8 @@
     twitter_debug("proto = %s\n", proto);
     twitter_debug("recipient = %s\n", recipient);
 
-    if(!strcmp(proto, "prpl-jabber") && !strcmp(recipient, "twitter@twitter.com")) {
+    if(!strcmp(proto, "prpl-jabber") &&
+       !strcmp(recipient, "twitter@twitter.com")) {
         /* escape */
         if(purple_prefs_get_bool(OPT_ESCAPE_PSEUDO)) {
             escape(buffer);
@@ -169,7 +183,8 @@
     const gchar *list;
     gchar **candidates = NULL, **candidate = NULL;
 
-    list = purple_prefs_get_string(which ? OPT_USERLIST_SENDER : OPT_USERLIST_RECIPIENT);
+    list = purple_prefs_get_string(which ? OPT_USERLIST_SENDER :
+                                   OPT_USERLIST_RECIPIENT);
     g_return_if_fail(list != NULL);
     if(!strcmp(list, DEFAULT_LIST))
         return;
@@ -238,6 +253,192 @@
     return FALSE;
 }
 
+static void
+insert_text_cb(GtkTextBuffer *textbuffer, GtkTextIter *position,
+               gchar *new_text, gint new_text_length, gpointer user_data)
+{
+	PidginConversation *gtkconv = (PidginConversation *)user_data;
+	GtkWidget *box, *counter = NULL;
+	gchar *markup = NULL;
+
+	g_return_if_fail(gtkconv != NULL);
+
+    guint count = gtk_text_buffer_get_char_count(textbuffer) +
+        (unsigned int)g_utf8_strlen(new_text, -1);
+
+    twitter_debug("new_text = %s utf8_strlen = %ld new_text_length = %d\n",
+                  new_text, g_utf8_strlen(new_text, -1), new_text_length);
+
+    markup = g_markup_printf_escaped("<span color=\"%s\">%u</span>",
+                                     count<=140 ? "black" : "red",
+                                     count);
+
+	box = gtkconv->toolbar;
+	counter = g_object_get_data(G_OBJECT(box),
+                                PLUGIN_ID "-counter");
+	if (counter)
+        gtk_label_set_markup(GTK_LABEL(counter), markup);
+
+    g_free(markup);
+}
+
+static void
+delete_text_cb(GtkTextBuffer *textbuffer, GtkTextIter *start_pos,
+               GtkTextIter *end_pos, gpointer user_data)
+{
+	PidginConversation *gtkconv = (PidginConversation *)user_data;
+	GtkWidget *box, *counter = NULL;
+	gchar *markup = NULL;
+
+	g_return_if_fail(gtkconv != NULL);
+
+    guint count = gtk_text_buffer_get_char_count(textbuffer) -
+			(gtk_text_iter_get_offset(end_pos) -
+             gtk_text_iter_get_offset(start_pos));
+
+    markup = g_markup_printf_escaped("<span color=\"%s\">%u</span>",
+                                     count<=140 ? "black" : "red",
+                                     count);
+
+	box = gtkconv->toolbar;
+	counter = g_object_get_data(G_OBJECT(box),
+                                PLUGIN_ID "-counter");
+	if (counter)
+        gtk_label_set_markup(GTK_LABEL(counter), markup);
+
+    g_free(markup);
+}
+
+
+static void
+detach_from_window(void)
+{
+    GList *list;
+
+	for (list = pidgin_conv_windows_get_list(); list; list = list->next) {
+		PidginWindow *win = list->data;
+		PurpleConversation *conv = pidgin_conv_window_get_active_conversation(win);
+        if(is_twitter_conv(conv))
+            detach_from_gtkconv(PIDGIN_CONVERSATION(conv), NULL);
+	}
+}
+
+static void
+detach_from_gtkconv(PidginConversation *gtkconv, gpointer null)
+{
+	GtkWidget *box, *counter = NULL, *sep = NULL;
+
+	g_signal_handlers_disconnect_by_func(G_OBJECT(gtkconv->entry_buffer),
+			(GFunc)insert_text_cb, gtkconv);
+	g_signal_handlers_disconnect_by_func(G_OBJECT(gtkconv->entry_buffer),
+			(GFunc)delete_text_cb, gtkconv);
+
+	box = gtkconv->toolbar;
+
+    /* remove counter */
+	counter = g_object_get_data(G_OBJECT(box),
+                                PLUGIN_ID "-counter");
+	if (counter) {
+		gtk_container_remove(GTK_CONTAINER(box), counter);
+        g_object_unref(counter);
+        g_object_set_data(G_OBJECT(box),
+                          PLUGIN_ID "-counter", NULL);
+    }
+    /* remove separator */
+	sep = g_object_get_data(G_OBJECT(box), PLUGIN_ID "-sep");
+	if (sep) {
+		gtk_container_remove(GTK_CONTAINER(box), sep);
+        g_object_unref(sep);
+        g_object_set_data(G_OBJECT(box),
+                          PLUGIN_ID "-sep", NULL);
+    }
+
+	gtk_widget_queue_draw(pidgin_conv_get_window(gtkconv)->window);
+}
+
+static void
+attach_to_window(void)
+{
+    GList *list;
+
+	for (list = pidgin_conv_windows_get_list(); list; list = list->next) {
+		PidginWindow *win = list->data;
+		PurpleConversation *conv = pidgin_conv_window_get_active_conversation(win);
+        if(is_twitter_conv(conv))
+            attach_to_gtkconv(PIDGIN_CONVERSATION(conv), NULL);
+	}
+}
+
+static void
+attach_to_gtkconv(PidginConversation *gtkconv, gpointer null)
+{
+	GtkWidget *box, *sep, *counter;
+
+	box = gtkconv->toolbar;
+	counter = g_object_get_data(G_OBJECT(box),
+                                PLUGIN_ID "-counter");
+	g_return_if_fail(counter == NULL);
+
+    /* make counter object */
+	counter = gtk_label_new(NULL);
+	gtk_widget_set_name(counter, "counter_label");
+	gtk_label_set_text(GTK_LABEL(counter), "0");
+	gtk_box_pack_end(GTK_BOX(box), counter, FALSE, FALSE, 0);
+	gtk_widget_show_all(counter);
+	g_object_set_data(G_OBJECT(box),
+                      PLUGIN_ID "-counter", counter);
+
+    /* make separator object */
+	sep = gtk_vseparator_new();
+	gtk_box_pack_end(GTK_BOX(box), sep, FALSE, FALSE, 0);
+	gtk_widget_show_all(sep);
+	g_object_set_data(G_OBJECT(box),
+                      PLUGIN_ID "-sep", sep);
+
+	/* connect signals, etc. */
+	g_signal_connect(G_OBJECT(gtkconv->entry_buffer), "insert_text",
+			G_CALLBACK(insert_text_cb), gtkconv);
+	g_signal_connect(G_OBJECT(gtkconv->entry_buffer), "delete_range",
+			G_CALLBACK(delete_text_cb), gtkconv);
+
+    /* redraw window */
+	gtk_widget_queue_draw(pidgin_conv_get_window(gtkconv)->window);
+}
+
+static gboolean
+is_twitter_conv(PurpleConversation *conv)
+{
+    const char *name = purple_conversation_get_name(conv);
+    PurpleAccount *account = purple_conversation_get_account(conv);
+    const gchar *proto = purple_account_get_protocol_id(account);
+
+    twitter_debug("is_twitter_conv\n");
+    twitter_debug("name  = %s\n", name);
+    twitter_debug("proto = %s\n", proto);
+
+    if(!strcmp(name, "twitter@twitter.com") &&
+       !strcmp(proto, "prpl-jabber")) {
+        return TRUE;
+    }
+
+    return FALSE;
+}
+
+static void
+conv_created_cb(PurpleConversation *conv, gpointer null)
+{
+	PidginConversation *gtkconv = PIDGIN_CONVERSATION(conv);
+	g_return_if_fail(gtkconv != NULL);
+
+    /* only attach to twitter conversation window */
+    if(is_twitter_conv(conv)) {
+        gboolean enabled = purple_prefs_get_bool(OPT_COUNTER);
+        if(enabled) {
+            attach_to_gtkconv(gtkconv, NULL);
+        }
+    }
+}
+
 static gboolean
 load_plugin(PurplePlugin * plugin)
 {
@@ -246,6 +447,9 @@
                           plugin, PURPLE_CALLBACK(writing_im_cb), NULL);
     purple_signal_connect(purple_conversations_get_handle(), "sending-im-msg",
                           plugin, PURPLE_CALLBACK(sending_im_cb), NULL);
+	purple_signal_connect(purple_conversations_get_handle(),
+                          "conversation-created",
+                          plugin, PURPLE_CALLBACK(conv_created_cb), NULL);
 
     /* compile regex */
     regp[RECIPIENT] = g_regex_new("@([A-Za-z0-9_]+)", 0, 0, NULL);
@@ -257,6 +461,12 @@
         "^\\s*(?:[\"#$%&'()*+,\\-./:;<=>?\\[\\\\\\]_`{|}~]|[^\\s\\x21-\\x7E])*([dDfFgGlLmMnNtTwW]{1})(?:\\Z|\\s+|[^\\x21-\\x7E]+\\Z)",
         G_REGEX_RAW, 0, NULL);
 
+    /* attach counter to the existing twitter window*/
+    gboolean enabled = purple_prefs_get_bool(OPT_COUNTER);
+    if(enabled) {
+        attach_to_window();
+    }
+
     return TRUE;
 }
 
@@ -265,14 +475,42 @@
 {
     twitter_debug("pidgin-twitter unload called\n");
 
+    /* disconnect from signal */
+    purple_signal_disconnect(purple_conversations_get_handle(),
+                             "writing-im-msg",
+                             plugin, PURPLE_CALLBACK(writing_im_cb));
+    purple_signal_disconnect(purple_conversations_get_handle(),
+                             "sending-im-msg",
+                             plugin, PURPLE_CALLBACK(sending_im_cb));
+	purple_signal_disconnect(purple_conversations_get_handle(),
+                             "conversation-created",
+                             plugin, PURPLE_CALLBACK(conv_created_cb));
+
+    /* unreference regp */
     g_regex_unref(regp[RECIPIENT]);
     g_regex_unref(regp[SENDER]);
     g_regex_unref(regp[COMMAND]);
     g_regex_unref(regp[PSEUDO]);
 
+    /* detach from twitter window */
+    detach_from_window();
+
     return TRUE;
 }
 
+static void
+counter_prefs_cb(const char *name, PurplePrefType type,
+							 gconstpointer val, gpointer data)
+{
+    gboolean enabled = purple_prefs_get_bool(OPT_COUNTER);
+    if(enabled) {
+        attach_to_window(); //xxx shoud check whether already attached or not.
+    }
+    else {
+        detach_from_window();
+    }
+}
+
 static PurplePluginPrefFrame *
 get_plugin_pref_frame(PurplePlugin * plugin)
 {
@@ -282,10 +520,9 @@
     PurplePluginPrefFrame *frame = purple_plugin_pref_frame_new();
 
     /* frame title */
-    pref = purple_plugin_pref_new_with_label("Pidgin-Twitter Configuration");
+    pref = purple_plugin_pref_new_with_label("Translation Configurations");
     purple_plugin_pref_frame_add(frame, pref);
 
-
     /* translation settings */
     pref = purple_plugin_pref_new_with_name_and_label(
         OPT_TRANSLATE_RECIPIENT,
@@ -297,12 +534,38 @@
         "Translate sender name to link");
     purple_plugin_pref_frame_add(frame, pref);
 
-    /* escape pseudo command settings */
+
+
+
+
+    /* frame title */
+    pref = purple_plugin_pref_new_with_label("Miscellaneous Configurations");
+    purple_plugin_pref_frame_add(frame, pref);
+
+    /* escape pseudo command setting */
     pref = purple_plugin_pref_new_with_name_and_label(
         OPT_ESCAPE_PSEUDO,
         "Escape pseudo command string");
     purple_plugin_pref_frame_add(frame, pref);
 
+    /* comaescape pseudo command setting */
+    pref = purple_plugin_pref_new_with_name_and_label(
+        OPT_COUNTER,
+        "Show text counter");
+    purple_plugin_pref_frame_add(frame, pref);
+
+    /* xxx */
+	purple_prefs_connect_callback(plugin, OPT_COUNTER,
+								counter_prefs_cb, NULL);
+
+
+
+
+
+    /* frame title */
+    pref = purple_plugin_pref_new_with_label("Sound Configurations");
+    purple_plugin_pref_frame_add(frame, pref);
+
     /* sound settings for recipient */
     pref = purple_plugin_pref_new_with_name_and_label(
         OPT_PLAYSOUND_RECIPIENT,
@@ -334,7 +597,7 @@
 	purple_plugin_pref_frame_add(frame, pref);
 
 
-    /* sound settings for sender */
+    /* sound setting for sender */
     pref = purple_plugin_pref_new_with_name_and_label(
         OPT_PLAYSOUND_SENDER,
         "Play sound if sender of a message is in the sender list");
@@ -380,9 +643,9 @@
     0,                          /**< flags	*/
     NULL,                       /**< deps	*/
     PURPLE_PRIORITY_DEFAULT,    /**< priority	*/
-    PIDGINTWITTER_PLUGIN_ID,    /**< id		*/
+    PLUGIN_ID,                  /**< id		*/
     "Pidgin-Twitter",           /**< name	*/
-    "0.5.2",                    /**< version	*/
+    "0.6.0",                    /**< version	*/
     "replaces usernames with links and play sounds", /**  summary	*/
     "replaces usernames with links and play sounds", /**  desc	*/
     "Yoshiki Yazawa (yaz@honeyplanet.jp)",     /**< author	*/
@@ -413,6 +676,8 @@
     purple_prefs_add_string(OPT_USERLIST_RECIPIENT, DEFAULT_LIST);
     purple_prefs_add_int(OPT_SOUNDID_SENDER, PURPLE_SOUND_POUNCE_DEFAULT);
     purple_prefs_add_string(OPT_USERLIST_SENDER, DEFAULT_LIST);
+
+    purple_prefs_add_bool(OPT_COUNTER, TRUE);
 }
 
 PURPLE_INIT_PLUGIN(pidgin_twitter, init_plugin, info)