changeset 18143:695cb303f688

merge of 'caa48886aab8c94b98936accf9932e04b9864341' and 'f5f51a0bec6148b7230865032d262150af12f625'
author Richard Laager <rlaager@wiktel.com>
date Sun, 17 Jun 2007 02:35:55 +0000
parents 12ab14848af4 (diff) eec2b191ef71 (current diff)
children 1a282f3d8057
files
diffstat 7 files changed, 241 insertions(+), 17 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog.API	Sun Jun 17 02:27:13 2007 +0000
+++ b/ChangeLog.API	Sun Jun 17 02:35:55 2007 +0000
@@ -13,8 +13,6 @@
 		    UIs can now use better scheduling for whole-second timers.  For
 		    example, clients based on the glib event loop can now use
 		    g_timeout_add_seconds.
-		* gtk_imhtml_setup_entry
-		* pidgin_create_window
 		* purple_blist_node_get_type
 		* purple_conversation_do_command
 		* purple_conversation_get_extended_menu
@@ -22,8 +20,6 @@
 		    This is for UIs to use to ensure only one copy is running.
 		* purple_dbus_is_owner
 		* purple_image_data_calculate_filename
-		* pidgin_retrieve_user_info, shows immediate feedback when getting
-		  information about a user.
 		* purple_timeout_add_seconds
 		    Callers should prefer this to purple_timeout_add for timers
 		    longer than 1 second away.  Be aware of the rounding, though.
@@ -31,8 +27,7 @@
 		    Callers should prefer this to purple_timeout_add for timers
 		    longer than 1 second away.  Be aware of the rounding, though.
 		* purple_xfer_get_remote_user
-		* gtk_imhtml_animation_new
-		    Can be used for inserting an animated image into an IMHTML.
+		* purple_pounces_get_all_for_ui
 
 		Changed:
 		* The documentation of the following functions now properly
@@ -68,6 +63,14 @@
 		  GLists.  The passed list is still not modified or freed.
 
 	Pidgin:
+		Added:
+		* gtk_imhtml_setup_entry
+		* pidgin_create_window
+		* pidgin_retrieve_user_info, shows immediate feedback when getting
+		  information about a user.
+		* gtk_imhtml_animation_new
+		    Can be used for inserting an animated image into an IMHTML.
+
 		Changed:
 		* pidgin_append_menu_action returns the menuitem added to the menu.
 		* pidgin_separator returns the separator added to the menu.
--- a/finch/gntpounce.c	Sun Jun 17 02:27:13 2007 +0000
+++ b/finch/gntpounce.c	Sun Jun 17 02:35:55 2007 +0000
@@ -141,8 +141,8 @@
 
 	gnt_tree_remove_all(GNT_TREE(dialog->tree));
 
-	for (pounces = purple_pounces_get_all(); pounces != NULL;
-			pounces = g_list_next(pounces))
+	for (pounces = purple_pounces_get_all_for_ui(FINCH_UI); pounces != NULL;
+			pounces = g_list_delete_link(pounces, pounces))
 	{
 		add_pounce_to_treeview(GNT_TREE(dialog->tree), pounces->data);
 	}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/finch/plugins/pietray.py	Sun Jun 17 02:35:55 2007 +0000
@@ -0,0 +1,183 @@
+#!/usr/bin/env python
+
+# This is a dbus script to show a docklet for Finch. This should work
+# for any 'compatible' purple client.
+#
+# By 'compatible', I mean any client that sets and updates the
+# "unseen-count" data on the conversations.
+#
+# It allows doing the following things:
+#    - It allows changing status.
+#    - It shows the current status and info about unread messages in
+#      the tooltip.
+#    - It can blink on unread IM/Chat messages, and it allows canging
+#      the preference for that.
+# 
+# It requires GTK+ 2.10 or above, since it uses GtkStatusIcon.
+# 
+# Sadrul <sadrul@pidgin.im>
+
+import pygtk
+pygtk.require("2.0")
+import gtk
+import dbus, gobject, dbus.glib
+import os # to get the pkg-config output
+
+bus = dbus.SessionBus()
+obj = bus.get_object(
+    "im.pidgin.purple.PurpleService", "/im/pidgin/purple/PurpleObject")
+purple = dbus.Interface(obj, "im.pidgin.purple.PurpleInterface")
+
+def pack_image_label(menu, image, label):
+	item = gtk.ImageMenuItem(label)
+	if image:
+		img = gtk.Image()
+		img.set_from_stock(image, 1)
+		item.set_image(img)
+	menu.append(item)
+	return item
+
+def activate_primitive_status(item, status):
+	saved = purple.PurpleSavedstatusFindTransientByTypeAndMessage(status, "")
+	if not saved:
+		saved = purple.PurpleSavedstatusNew("", status)
+	purple.PurpleSavedstatusActivate(saved)
+
+def activate_popular_status(item, time):
+	saved = purple.PurpleSavedstatusFindByCreationTime(time)
+	if saved:
+		purple.PurpleSavedstatusActivate(saved)
+
+def generate_status_menu(menu):
+	item = gtk.MenuItem("Available")
+	item.connect("activate", activate_primitive_status, 2)
+	menu.append(item)
+
+	item = gtk.MenuItem("Away")
+	item.connect("activate", activate_primitive_status, 5)
+	menu.append(item)
+
+	item = gtk.MenuItem("Invisible")
+	item.connect("activate", activate_primitive_status, 4)
+	menu.append(item)
+
+	item = gtk.MenuItem("Offline")
+	item.connect("activate", activate_primitive_status, 1)
+	menu.append(item)
+
+	menu.append(gtk.MenuItem())
+
+	popular = purple.PurpleSavedstatusesGetPopular(10)
+	for pop in popular:
+		title = purple.PurpleSavedstatusGetTitle(pop).replace('_', '__')
+		item = gtk.MenuItem(title)
+		item.set_data("timestamp", purple.PurpleSavedstatusGetCreationTime(pop))
+		item.connect("activate", activate_popular_status, purple.PurpleSavedstatusGetCreationTime(pop))
+		menu.append(item)
+
+def toggle_pref(item, pref):
+	purple.PurplePrefsSetBool(pref, item.get_active())
+
+def popup_menu(icon, button, tm, none):
+	menu = gtk.Menu()
+
+	item = gtk.CheckMenuItem("Blink for unread IM")
+	item.set_active(purple.PurplePrefsGetBool("/plugins/dbus/docklet/blink/im"))
+	item.connect("activate", toggle_pref, "/plugins/dbus/docklet/blink/im")
+	menu.append(item)
+
+	item = gtk.CheckMenuItem("Blink for unread Chats")
+	item.set_active(purple.PurplePrefsGetBool("/plugins/dbus/docklet/blink/chat"))
+	item.connect("activate", toggle_pref, "/plugins/dbus/docklet/blink/chat")
+	menu.append(item)
+
+	menu.append(gtk.MenuItem())
+
+	#item = pack_image_label(menu, None, "Change Status...")
+	item = gtk.MenuItem("Change Status...")
+	menu.append(item)
+	submenu = gtk.Menu()
+	item.set_submenu(submenu)
+	generate_status_menu(submenu)
+
+	menu.show_all()
+	menu.popup(None, None, None, button, tm)
+
+def get_status_message():
+	status = purple.PurpleSavedstatusGetCurrent()
+	msg = purple.PurpleSavedstatusGetMessage(status)
+	if msg and len(msg) > 0:
+		text = msg + " "
+	else:
+		text = ""
+	text = text + "(" + {
+		2: "Available",
+		5: "Away",
+		4: "Invisible",
+		1: "Offline"
+	}[purple.PurpleSavedstatusGetType(status)] + ")"
+	return text
+
+def detect_unread_conversations():
+	im = purple.PurplePrefsGetBool("/plugins/dbus/docklet/blink/im")
+	chat = purple.PurplePrefsGetBool("/plugins/dbus/docklet/blink/chat")
+	tooltip = ""
+	blink = False
+	if im and chat:
+		convs = purple.PurpleGetConversations()
+	elif im:
+		convs = purple.PurpleGetIms()
+	elif chat:
+		convs = purple.PurpleGetChats()
+	else:
+		convs = None
+	for conv in convs:
+		count = purple.PurpleConversationGetData(conv, "unseen-count")
+		if count and count > 0:
+			blink = True
+			tooltip = tooltip + "\n" + purple.PurpleConversationGetName(conv) + " (" + str(count) + ")"
+	t.set_from_file(path + "/share/pixmaps/pidgin.png")
+	if blink:
+		# I hate this icon
+		# t.set_from_file(path + "/share/pixmaps/pidgin/tray/22/tray-message.png")
+		tooltip = "\nUnread Messages:" + tooltip
+	# There's going to be some way to expose the client's display name in 2.1.0.
+	# Use that instead of hardcoding Finch here.
+	t.set_tooltip("Finch: " + get_status_message() + tooltip)
+	t.set_blinking(blink)
+
+def conversation_updated(conv, type):
+	detect_unread_conversations()
+
+def savedstatus_changed(new, old):
+	# Change the icon for status perhaps?
+	detect_unread_conversations()
+
+def init_prefs():
+	if not purple.PurplePrefsExists("/plugins/dbus/docklet/blink"):
+		purple.PurplePrefsAddNone("/plugins")
+		purple.PurplePrefsAddNone("/plugins/dbus")
+		purple.PurplePrefsAddNone("/plugins/dbus/docklet")
+		purple.PurplePrefsAddNone("/plugins/dbus/docklet/blink")
+		purple.PurplePrefsAddBool("/plugins/dbus/docklet/blink/im", True)
+		purple.PurplePrefsAddBool("/plugins/dbus/docklet/blink/chat", True)
+
+pkg = os.popen("pkg-config --variable=prefix pidgin")
+path = pkg.readline().rstrip()
+
+bus.add_signal_receiver(conversation_updated,
+  dbus_interface="im.pidgin.purple.PurpleInterface",
+  signal_name="ConversationUpdated")
+
+bus.add_signal_receiver(savedstatus_changed,
+  dbus_interface="im.pidgin.purple.PurpleInterface",
+  signal_name="SavedstatusChanged")
+
+t = gtk.StatusIcon()
+t.connect("popup-menu", popup_menu, None)
+
+init_prefs()
+detect_unread_conversations()
+
+gtk.main ()
+
--- a/libpurple/dbus-analyze-functions.py	Sun Jun 17 02:27:13 2007 +0000
+++ b/libpurple/dbus-analyze-functions.py	Sun Jun 17 02:35:55 2007 +0000
@@ -119,14 +119,19 @@
 
     def processinput(self, type, name):
         const = False
+        unsigned = False
         if type[0] == "const":
             type = type[1:]
             const = True
 
+        if type[0] == "unsigned":
+            type = type[1:]
+            unsigned = True
+
         if len(type) == 1:
             # simple types (int, gboolean, etc.) and enums
             if (type[0] in simpletypes) or ((type[0].startswith("Purple") and not type[0].endswith("Callback"))):
-                return self.inputsimple(type, name)
+                return self.inputsimple(type, name, unsigned)
 
         # pointers ... 
         if (len(type) == 2) and (type[1] == pointer):
@@ -232,9 +237,12 @@
             print "typedef struct _%s %s;" % (type[0], type[0])
             self.knowntypes.append(type[0])
 
-    def inputsimple(self, type, name):
+    def inputsimple(self, type, name, us):
         self.paramshdr.append("%s %s" % (type[0], name))
-        self.inputparams.append(("G_TYPE_INT", name))
+        if us:
+            self.inputparams.append(("G_TYPE_UINT", name))
+        else:
+            self.inputparams.append(("G_TYPE_INT", name))
 
     def inputstring(self, type, name):
         self.paramshdr.append("const char *%s" % name)
@@ -348,10 +356,15 @@
 
     # input parameters
 
-    def inputsimple(self, type, name):
-        self.cdecls.append("\tdbus_int32_t %s;" % name)
-        self.cparams.append(("INT32", name))
-        self.addintype("i", name)
+    def inputsimple(self, type, name, us):
+        if us:
+            self.cdecls.append("\tdbus_int32_t %s;" % name)
+            self.cparams.append(("INT32", name))
+            self.addintype("i", name)
+        else:
+            self.cdecls.append("\tdbus_uint32_t %s;" % name)
+            self.cparams.append(("UINT32", name))
+            self.addintype("u", name)
 
     def inputstring(self, type, name):
         self.cdecls.append("\tconst char *%s;" % name)
--- a/libpurple/pounce.c	Sun Jun 17 02:27:13 2007 +0000
+++ b/libpurple/pounce.c	Sun Jun 17 02:35:55 2007 +0000
@@ -1014,6 +1014,20 @@
 	return pounces;
 }
 
+GList *purple_pounces_get_all_for_ui(const char *ui)
+{
+	GList *list = NULL, *iter;
+	g_return_val_if_fail(ui != NULL, NULL);
+
+	for (iter = pounces; iter; iter = iter->next) {
+		PurplePounce *pounce = iter->data;
+		if (pounce->ui_type && strcmp(pounce->ui_type, ui) == 0)
+			list = g_list_prepend(list, pounce);
+	}
+	list = g_list_reverse(list);
+	return list;
+}
+
 static void
 free_pounce_handler(gpointer user_data)
 {
--- a/libpurple/pounce.h	Sun Jun 17 02:27:13 2007 +0000
+++ b/libpurple/pounce.h	Sun Jun 17 02:35:55 2007 +0000
@@ -343,6 +343,17 @@
 GList *purple_pounces_get_all(void);
 
 /**
+ * Returns a list of registered buddy pounces for the ui-type.
+ *
+ * @param ui  The ID of the UI using the core.
+ *
+ * @return The list of buddy pounces. The list should be freed by
+ *         the caller when it's no longer used.
+ * @since  2.1.0
+ */
+GList *purple_pounces_get_all_for_ui(const char *ui);
+
+/**
  * Returns the buddy pounce subsystem handle.
  *
  * @return The subsystem handle.
--- a/pidgin/gtkpounce.c	Sun Jun 17 02:27:13 2007 +0000
+++ b/pidgin/gtkpounce.c	Sun Jun 17 02:35:55 2007 +0000
@@ -215,8 +215,8 @@
 
 	gtk_list_store_clear(dialog->model);
 
-	for (pounces = purple_pounces_get_all(); pounces != NULL;
-			pounces = g_list_next(pounces))
+	for (pounces = purple_pounces_get_all_for_ui(PIDGIN_UI); pounces != NULL;
+			pounces = g_list_delete_link(pounces, pounces))
 	{
 		add_pounce_to_treeview(dialog->model, pounces->data);
 	}