soc.2009.vulture: ab2e8a21: Show status text in buddy list.

gdick at soc.pidgin.im gdick at soc.pidgin.im
Wed Jul 29 16:05:35 EDT 2009


-----------------------------------------------------------------
Revision: ab2e8a210fef618b45ef09fad85b8750f7bc6175
Ancestor: 064b8c11a5801e9a418c183c6830e59e738a2887
Author: gdick at soc.pidgin.im
Date: 2009-07-29T19:57:44
Branch: im.pidgin.soc.2009.vulture
URL: http://d.pidgin.im/viewmtn/revision/info/ab2e8a210fef618b45ef09fad85b8750f7bc6175

Modified files:
        vulture/purpleblist.c vulture/resource.h
        vulture/vulture-res.rc vulture/vultureblist.c
        vulture/vultureblist.h

ChangeLog: 

Show status text in buddy list.

-------------- next part --------------
============================================================
--- vulture/purpleblist.c	83e5696f6aa63724f75141c830407f63f3e61dcd
+++ vulture/purpleblist.c	4000dfae5d0ab34ce674b793b4acc6e1279d9bf9
@@ -36,6 +36,7 @@ static void DeleteBuddyFromAccount(Purpl
 static BOOL ShouldShowNode(PurpleBlistNode *lpblistnode);
 static void AddCommonMenuItems(HMENU hmenu, PurpleBlistNode *lpblistnode, GList **lplpglistVMA, PurpleConnection *lpconnection, int iProtoIndex, int iExtendedIndex);
 static void DeleteBuddyFromAccount(PurpleBuddy *lpbuddy);
+static void UpdateStatusText(PurpleBlistNode *lpblistnode);
 
 
 
@@ -74,6 +75,7 @@ void PurpleBlistUpdateNode(PurpleBuddyLi
 		lpvbn->lRefCount = 1;
 		lpvbn->lpvbnParent = NULL;
 		lpvbn->bExpanded = FALSE;
+		lpvbn->szStatusText = NULL;
 		InitializeCriticalSection(&lpvbn->cs);
 	}
 
@@ -89,6 +91,8 @@ void PurpleBlistUpdateNode(PurpleBuddyLi
 
 			lpvbn->nodetype = lpblistnode->type;
 
+			UpdateStatusText(lpblistnode);
+
 			switch(lpblistnode->type)
 			{
 			case PURPLE_BLIST_GROUP_NODE:
@@ -107,6 +111,12 @@ void PurpleBlistUpdateNode(PurpleBuddyLi
 				break;
 
 			case PURPLE_BLIST_BUDDY_NODE:
+
+				/* Maybe our contact needs to update its status
+				 * text.
+				 */
+				UpdateStatusText(lpblistnode->parent);
+
 				szNodeText = purple_buddy_get_alias((PurpleBuddy*)lpblistnode);
 
 				if(szNodeText && *szNodeText)
@@ -129,19 +139,22 @@ void PurpleBlistUpdateNode(PurpleBuddyLi
 				if(lpvbn->lpvbnParent && !lpvbn->lpvbnParent->hti)
 					PurpleBlistUpdateNode(lpbuddylist, lpvbn->lpvbnParent->lpblistnode);
 
-				/* If we're a buddy and our contact is
-				 * collapsed, give up at the last minute. We
-				 * still needed all the processing for other
-				 * nodes as if we'd been visible, but we want
-				 * to stop short of actually showing ourselves.
+				/* Update either our own node or our parent's,
+				 * if we're a collapsed buddy.
 				 */
 				if(!PURPLE_BLIST_NODE_IS_BUDDY(lpblistnode) ||
-					(lpblistnode->parent->ui_data &&
+					(lpblistnode->parent &&
+					lpblistnode->parent->ui_data &&
 					((VULTURE_BLIST_NODE*)lpblistnode->parent->ui_data)->bExpanded))
 				{
 					VultureBListNodeAddRef(lpvbn);
 					VulturePostUIMessage(VUIMSG_UPDATEBLISTNODE, lpvbn);
 				}
+				else if(lpblistnode->parent && lpblistnode->parent->ui_data)
+				{
+					VultureBListNodeAddRef(lpblistnode->parent->ui_data);
+					VulturePostUIMessage(VUIMSG_UPDATEBLISTNODE, lpblistnode->parent->ui_data);
+				}
 			}
 		}
 		else if(lpvbn->hti)
@@ -252,6 +265,7 @@ void VultureBListNodeRelease(VULTURE_BLI
 
 		if(lpvblnode->lpvbnParent) VultureBListNodeRelease(lpvblnode->lpvbnParent);
 		if(lpvblnode->szNodeText) g_free(lpvblnode->szNodeText);
+		if(lpvblnode->szStatusText) g_free(lpvblnode->szStatusText);
 		DeleteCriticalSection(&lpvblnode->cs);
 
 		g_free(lpvblnode);
@@ -295,19 +309,31 @@ LPTSTR PurpleBuddyGetStatusText(PurpleBu
 {
 	PurplePlugin *lppluginPrpl;
 
-	/* Find prpl for buddy. */
-	if(lpbuddy && (lppluginPrpl = purple_find_prpl(purple_account_get_protocol_id(lpbuddy->account))))
+	if(!lpbuddy)
+		return NULL;
+
+	if(PURPLE_BUDDY_IS_ONLINE(lpbuddy))
 	{
-		PurplePluginProtocolInfo *lpprplinfo = PURPLE_PLUGIN_PROTOCOL_INFO(lppluginPrpl);
-
-		/* If prpl supports status text, get the text. */
-		if(lpprplinfo && lpprplinfo->status_text)
+		/* Find prpl for buddy. */
+		if((lppluginPrpl = purple_find_prpl(purple_account_get_protocol_id(lpbuddy->account))))
 		{
-			char *szStatus = lpprplinfo->status_text(lpbuddy);
+			PurplePluginProtocolInfo *lpprplinfo = PURPLE_PLUGIN_PROTOCOL_INFO(lppluginPrpl);
 
-			return szStatus ? VultureUTF8ToTCHAR(szStatus) : NULL;
+			/* If prpl supports status text, get the text. */
+			if(lpprplinfo && lpprplinfo->status_text)
+			{
+				char *szStatus = lpprplinfo->status_text(lpbuddy);
+
+				return szStatus ? VultureUTF8ToTCHAR(szStatus) : NULL;
+			}
 		}
 	}
+	else
+	{
+		TCHAR szBuffer[128];
+		LoadString(g_hInstance, IDS_OFFLINE, szBuffer, NUM_ELEMENTS(szBuffer));
+		return g_memdup(szBuffer, sizeof(szBuffer));
+	}
 
 	return NULL;
 }
@@ -322,8 +348,27 @@ void PurpleBuddyStatusChanged(PurpleBudd
  */
 void PurpleBuddyStatusChanged(PurpleBuddy *lpbuddy, PurpleStatus *lpstatusOld, PurpleStatus *lpstatusNew)
 {
+	PurpleConversation *lpconv;
+	VULTURE_BLIST_NODE *lpvbnContact = ((PurpleBlistNode*)lpbuddy)->parent ? ((PurpleBlistNode*)lpbuddy)->parent->ui_data : NULL;
+
+	UpdateStatusText((PurpleBlistNode*)lpbuddy);
+	UpdateStatusText(((PurpleBlistNode*)lpbuddy)->parent);
+
+	if(lpvbnContact)
+	{
+		if(lpvbnContact->bExpanded)
+		{
+			VULTURE_BLIST_NODE *lpvbn = ((PurpleBlistNode*)lpbuddy)->ui_data;
+			VultureBListNodeAddRef(lpvbn);
+			VulturePostUIMessage(VUIMSG_UPDATEBLISTNODE, ((PurpleBlistNode*)lpbuddy)->ui_data);
+		}
+
+		VultureBListNodeAddRef(lpvbnContact);
+		VulturePostUIMessage(VUIMSG_UPDATEBLISTNODE, lpvbnContact);
+	}
+
 	/* Are we speaking to this buddy? */
-	PurpleConversation *lpconv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, lpbuddy->name, lpbuddy->account);
+	lpconv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, lpbuddy->name, lpbuddy->account);
 
 	/* If so, tell the UI to update the status message in the conversation.
 	 */
@@ -576,3 +621,36 @@ static void DeleteBuddyFromAccount(Purpl
 	if(purple_account_is_connected(lpaccount))
 		purple_account_remove_buddy(lpaccount, lpbuddy, purple_buddy_get_group(lpbuddy));
 }
+
+
+/**
+ * Updates the status text cached in a buddy-list node.
+ *
+ * @param	lpblistnode	Buddy-list node.
+ */
+static void UpdateStatusText(PurpleBlistNode *lpblistnode)
+{
+	VULTURE_BLIST_NODE *lpvblistnode;
+
+	if(!lpblistnode || !lpblistnode->ui_data)
+		return;
+
+	lpvblistnode = lpblistnode->ui_data;
+
+	EnterCriticalSection(&lpvblistnode->cs);
+	{
+		if(lpvblistnode->szStatusText) g_free(lpvblistnode->szStatusText);
+		lpvblistnode->szStatusText = NULL;
+
+		if(PURPLE_BLIST_NODE_IS_BUDDY(lpblistnode))
+			lpvblistnode->szStatusText = PurpleBuddyGetStatusText((PurpleBuddy*)lpblistnode);
+		else if(PURPLE_BLIST_NODE_IS_CONTACT(lpblistnode))
+		{
+			PurpleBuddy *lpbuddy = purple_contact_get_priority_buddy((PurpleContact*)lpblistnode);
+
+			if(lpbuddy)
+				lpvblistnode->szStatusText = PurpleBuddyGetStatusText(lpbuddy);
+		}
+	}
+	LeaveCriticalSection(&lpvblistnode->cs);
+}
============================================================
--- vulture/resource.h	c60b43d575373f275229fe49057eb7cc9923cde7
+++ vulture/resource.h	4806444826b8f8ce52dfdfad6cc050a5ecaec786
@@ -76,3 +76,4 @@
 #define IDS_QUERY_DELCONTACT                    8
 #define IDS_BUDDYICON_FILTER                    9
 #define IDS_BUDDYICON_TITLE                     10
+#define IDS_OFFLINE                             11
============================================================
--- vulture/vulture-res.rc	cdc489321f0878a09c10307c09e48a89f520efeb
+++ vulture/vulture-res.rc	e2d01a0597f1e5b47b5809f0b7c72b95e4be85fd
@@ -219,6 +219,7 @@ STRINGTABLE
     IDS_QUERY_DELCONTACT          "Deleting this contact will also delete all buddies associated with it. Do you wish to continue?"
     IDS_BUDDYICON_FILTER          "Image Files\t*.bmp;*.png;*.gif;*.jpg\tAll Files (*.*)\t*.*\t"
     IDS_BUDDYICON_TITLE           "Choose Custom Icon"
+    IDS_OFFLINE                   "Offline"
 }
 
 
============================================================
--- vulture/vultureblist.c	3ef1a8be976cd15568c8b695e2fdc97914dc7aa2
+++ vulture/vultureblist.c	e8956ec9ef47112af9bce18e6e08890b7c17fa00
@@ -60,6 +60,8 @@ static void RemoveNodeRequest(HWND hwndB
 static BOOL RunCommonMenuCmd(HWND hwndBuddies, VULTURE_BLIST_NODE *lpvblistnode, HMENU hmenu, int iCmd);
 static void RunChatMenuCmd(HWND hwndBuddies, VULTURE_BLIST_NODE *lpvblistnode, HMENU hmenu, int iCmd);
 static void RemoveNodeRequest(HWND hwndBuddies, VULTURE_BLIST_NODE *lpvblistnode);
+static void UpdateBListNode(HWND hwndBlistTree, VULTURE_BLIST_NODE *lpvbn);
+static void DrawBListNodeExtra(LPNMTVCUSTOMDRAW lpnmtvcdraw);
 
 
 #define BLIST_MARGIN 6
@@ -272,57 +274,11 @@ static LRESULT CALLBACK MainWndProc(HWND
 				break;
 
 			case VUIMSG_UPDATEBLISTNODE:
-				{
-					HWND hwndBlistTree = GetDlgItem(g_hwndBListDlg, IDC_TREE_BLIST);
-					VULTURE_BLIST_NODE *lpvbn = (VULTURE_BLIST_NODE*)lParam;
+				UpdateBListNode(GetDlgItem(g_hwndBListDlg, IDC_TREE_BLIST), (VULTURE_BLIST_NODE*)lParam);
 
-					EnterCriticalSection(&lpvbn->cs);
-					{
-						TVITEM tvitem;
+				/* Release the reference for this call. */
+				VultureBListNodeRelease((VULTURE_BLIST_NODE*)lParam);
 
-						if(lpvbn->hti)
-						{
-							HTREEITEM htiParent = TreeView_GetParent(hwndBlistTree, lpvbn->hti);
-
-							/* If the parent doesn't match, we need
-							 * to recreate.
-							 */
-							if((lpvbn->lpvbnParent && lpvbn->lpvbnParent->hti != htiParent) ||
-								(!lpvbn->lpvbnParent && htiParent))
-							{
-								RemoveBListNode(hwndBlistTree, lpvbn);
-							}
-						}
-
-
-						/* New node? */
-						if(!lpvbn->hti)
-						{
-							TVINSERTSTRUCT tvis;
-
-							/* We cache this in the tree-view. */
-							VultureBListNodeAddRef(lpvbn);
-
-							tvis.hParent = lpvbn->lpvbnParent ? lpvbn->lpvbnParent->hti : TVI_ROOT;
-							tvis.hInsertAfter = TVI_SORT;
-							tvis.itemex.mask = TVIF_PARAM;
-							tvis.itemex.lParam = (LPARAM)lpvbn;
-
-							lpvbn->hti = TreeView_InsertItem(hwndBlistTree, &tvis);
-						}
-
-						/* Set text. */
-						tvitem.mask = TVIF_TEXT | TVIF_HANDLE;
-						tvitem.hItem = lpvbn->hti;
-						tvitem.pszText = lpvbn->szNodeText;
-						TreeView_SetItem(hwndBlistTree, &tvitem);
-					}
-					LeaveCriticalSection(&lpvbn->cs);
-
-					/* Release the reference for this call. */
-					VultureBListNodeRelease(lpvbn);
-				}
-
 				break;
 
 			case VUIMSG_REMOVEBLISTNODE:
@@ -747,6 +703,31 @@ static INT_PTR CALLBACK BuddyListDlgProc
 					}
 
 					return TRUE;
+
+				case NM_CUSTOMDRAW:
+					{
+						LPNMTVCUSTOMDRAW lpnmtvcdraw = (LPNMTVCUSTOMDRAW)lParam;
+
+						switch(lpnmtvcdraw->nmcd.dwDrawStage)
+						{
+						case CDDS_PREPAINT:
+							/* Ask for notifications for each item. */
+							SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, CDRF_NOTIFYITEMDRAW);
+							break;
+
+						case CDDS_ITEMPREPAINT:
+							/* Tell me when you've finished painting. */
+							SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, CDRF_NOTIFYPOSTPAINT);
+							break;
+
+						case CDDS_ITEMPOSTPAINT:
+							DrawBListNodeExtra(lpnmtvcdraw);
+							SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, CDRF_DODEFAULT);
+							break;
+						}
+					}
+
+					return TRUE;
 				}
 			}
 		}
@@ -967,7 +948,7 @@ static void SetStatusMsg(HWND hwndStatus
 /**
  * Removes a buddy-list node, doing the requisite housekeeping.
  *
- * @param	hwndStatusDlg	Buddy-list tree-view handle.
+ * @param	hwndBlistTree	Buddy-list tree-view handle.
  * @param	lpvbn		Node to delete.
  */
 static void RemoveBListNode(HWND hwndBlistTree, VULTURE_BLIST_NODE *lpvbn)
@@ -1027,6 +1008,9 @@ static void RunBuddyMenuCmd(HWND hwndBud
 		}
 		LeaveCriticalSection(&lpvblistnode->cs);
 
+		/* Update tree node. */
+		UpdateBListNode(hwndBuddies, lpvblistnode);
+
 		break;
 
 	case IDM_BLIST_CONTEXT_EXPAND:
@@ -1034,6 +1018,9 @@ static void RunBuddyMenuCmd(HWND hwndBud
 		VultureSingleSyncPurpleCall(PC_UPDATEBLISTCHILDREN, lpvblistnode);
 		PostMessage(hwndBuddies, TVM_EXPAND, TVE_EXPAND, (LPARAM)lpvblistnode->hti);
 
+		/* Update tree node. */
+		UpdateBListNode(hwndBuddies, lpvblistnode);
+
 		break;
 	}
 }
@@ -1175,3 +1162,116 @@ static void RemoveNodeRequest(HWND hwndB
 	if(bDelete)
 		VultureSingleSyncPurpleCall(PC_REMOVEBLISTNODE, lpvblistnode);
 }
+
+
+/**
+ * Updates a buddy-list node in the tree, according to its data.
+ *
+ * @param	hwndBlistTree	Buddy-list tree-view handle.
+ * @param	lpvbn		Node to update.
+ */
+static void UpdateBListNode(HWND hwndBlistTree, VULTURE_BLIST_NODE *lpvbn)
+{
+	EnterCriticalSection(&lpvbn->cs);
+	{
+		TVITEMEX tvitemex;
+
+		if(lpvbn->hti)
+		{
+			HTREEITEM htiParent = TreeView_GetParent(hwndBlistTree, lpvbn->hti);
+
+			/* If the parent doesn't match, we need
+			 * to recreate.
+			 */
+			if((lpvbn->lpvbnParent && lpvbn->lpvbnParent->hti != htiParent) ||
+				(!lpvbn->lpvbnParent && htiParent))
+			{
+				RemoveBListNode(hwndBlistTree, lpvbn);
+			}
+		}
+
+
+		/* New node? */
+		if(!lpvbn->hti)
+		{
+			TVINSERTSTRUCT tvis;
+
+			/* We cache this in the tree-view. */
+			VultureBListNodeAddRef(lpvbn);
+
+			tvis.hParent = lpvbn->lpvbnParent ? lpvbn->lpvbnParent->hti : TVI_ROOT;
+			tvis.hInsertAfter = TVI_SORT;
+			tvis.itemex.mask = TVIF_PARAM;
+			tvis.itemex.lParam = (LPARAM)lpvbn;
+
+			lpvbn->hti = TreeView_InsertItem(hwndBlistTree, &tvis);
+		}
+
+		/* Set text and height. */
+		tvitemex.mask = TVIF_HANDLE | TVIF_INTEGRAL;
+		tvitemex.hItem = lpvbn->hti;
+		tvitemex.iIntegral =
+			((lpvbn->nodetype == PURPLE_BLIST_CONTACT_NODE && lpvbn->bExpanded) || lpvbn->nodetype == PURPLE_BLIST_GROUP_NODE) ?
+			1 :
+			2;
+		TreeView_SetItem(hwndBlistTree, &tvitemex);
+	}
+	LeaveCriticalSection(&lpvbn->cs);
+}
+
+
+/**
+ * Draws custom stuff for a buddy-list node.
+ *
+ * @param	lpnmtvcdraw	Custom-draw data for node.
+ */
+static void DrawBListNodeExtra(LPNMTVCUSTOMDRAW lpnmtvcdraw)
+{
+	RECT rcText, rcClient;
+	COLORREF crOldFG, crOldBG;
+	VULTURE_BLIST_NODE *lpvblistnode = (VULTURE_BLIST_NODE*)lpnmtvcdraw->nmcd.lItemlParam;
+
+	GetClientRect(lpnmtvcdraw->nmcd.hdr.hwndFrom, &rcClient);
+
+	/* Get the rectangle in which the control would render its text if it
+	 * were doing so itself, and extend it to the right width.
+	 */
+	TreeView_GetItemRect(lpnmtvcdraw->nmcd.hdr.hwndFrom, (HTREEITEM)lpnmtvcdraw->nmcd.dwItemSpec, &rcText, TRUE);
+	rcText.right = rcClient.right;
+	InflateRect(&rcText, -1, -1);
+
+	crOldBG = SetBkColor(lpnmtvcdraw->nmcd.hdc, lpnmtvcdraw->clrTextBk);
+	crOldFG = SetTextColor(lpnmtvcdraw->nmcd.hdc, lpnmtvcdraw->clrText);
+
+	EnterCriticalSection(&lpvblistnode->cs);
+	{
+		if(lpvblistnode->szStatusText &&
+			((lpvblistnode->nodetype == PURPLE_BLIST_CONTACT_NODE && !lpvblistnode->bExpanded) ||
+			lpvblistnode->nodetype == PURPLE_BLIST_BUDDY_NODE))
+		{
+			HTREEITEM htiSel, htiDrop;
+
+			/* Render main text. */
+			if(lpvblistnode->szNodeText)
+				DrawText(lpnmtvcdraw->nmcd.hdc, lpvblistnode->szNodeText, -1, &rcText, DT_END_ELLIPSIS | DT_SINGLELINE);
+
+			/* Render secondary text. */
+			htiSel = TreeView_GetSelection(lpnmtvcdraw->nmcd.hdr.hwndFrom);
+			htiDrop = TreeView_GetDropHilight(lpnmtvcdraw->nmcd.hdr.hwndFrom);
+			if(htiDrop != (HTREEITEM)lpnmtvcdraw->nmcd.dwItemSpec &&
+				 (htiSel != (HTREEITEM)lpnmtvcdraw->nmcd.dwItemSpec || htiDrop != NULL))
+				SetTextColor(lpnmtvcdraw->nmcd.hdc, 0x808080);
+			DrawText(lpnmtvcdraw->nmcd.hdc, lpvblistnode->szStatusText, -1, &rcText, DT_BOTTOM | DT_END_ELLIPSIS | DT_SINGLELINE);
+		}
+		else
+		{
+			/* No secondary text; render main text only. */
+			if(lpvblistnode->szNodeText)
+				DrawText(lpnmtvcdraw->nmcd.hdc, lpvblistnode->szNodeText, -1, &rcText, DT_VCENTER | DT_END_ELLIPSIS | DT_SINGLELINE);
+		}
+	}
+	LeaveCriticalSection(&lpvblistnode->cs);
+
+	SetTextColor(lpnmtvcdraw->nmcd.hdc, crOldFG);
+	SetBkColor(lpnmtvcdraw->nmcd.hdc, crOldBG);
+}
============================================================
--- vulture/vultureblist.h	166afd028ea80d8397fe633ecd5396a3236e6d9e
+++ vulture/vultureblist.h	516f25b18eb0dc962795616b27cea8c7e491c601
@@ -35,10 +35,13 @@ typedef struct _VULTURE_BLIST_NODE
 	PurpleBlistNode			*lpblistnode;
 	PurpleBlistNodeType		nodetype;
 	LPTSTR				szNodeText;
+	LPTSTR				szStatusText;
 	HTREEITEM			hti;
 	struct _VULTURE_BLIST_NODE	*lpvbnParent;
 	LONG				lRefCount;
 	CRITICAL_SECTION		cs;
+
+	/* For contacts. */
 	BOOL				bExpanded;
 } VULTURE_BLIST_NODE;
 


More information about the Commits mailing list