soc.2009.vulture: 1b88b86b: Buddy icons now show in IM windows.

gdick at soc.pidgin.im gdick at soc.pidgin.im
Wed Jul 15 15:50:37 EDT 2009


-----------------------------------------------------------------
Revision: 1b88b86b68eb61b4144c403110676524b55fba39
Ancestor: 605ce9ff4bf8a72d960f54b9d7502eabce2d7e20
Author: gdick at soc.pidgin.im
Date: 2009-07-14T16:41:27
Branch: im.pidgin.soc.2009.vulture
URL: http://d.pidgin.im/viewmtn/revision/info/1b88b86b68eb61b4144c403110676524b55fba39

Modified files:
        vulture/purplebicon.c vulture/purplebicon.h
        vulture/purpleconv.c vulture/purplequeue.c
        vulture/purplequeue.h vulture/resource.h
        vulture/vulture-res.rc vulture/vulturebicon.h
        vulture/vultureconv.c vulture/vultureconv.h

ChangeLog: 

Buddy icons now show in IM windows.

-------------- next part --------------
============================================================
--- vulture/purplebicon.c	61ef9c6cdb51afeaccdbdfab3adb8d38c24d4883
+++ vulture/purplebicon.c	1cfad681c114b272db5bb25d91343d6f288a285b
@@ -32,13 +32,17 @@
 
 
 /**
- * Retrieves the buddy icon for a buddy.
+ * Retrieves the buddy icon for a buddy. It is scaled, with its aspect ratio
+ * maintained, so as not to exceed the specified dimensions, unless either of
+ * these is non-positive, in which case no scaling is performed.
  *
  * @param	lpbuddy		Buddy.
+ * @param	cxMax		Maximum width.
+ * @param	cyMax		Maximum height.
  *
  * @return Bitmap handle, or NULL on error.
  */
-HBITMAP PurpleGetBuddyIcon(PurpleBuddy *lpbuddy)
+HBITMAP PurpleGetBuddyIcon(PurpleBuddy *lpbuddy, int cxMax, int cyMax)
 {
 	GdkPixbuf *lppixbuf;
 	GdkPixbufLoader *lppbloader;
@@ -47,14 +51,18 @@ HBITMAP PurpleGetBuddyIcon(PurpleBuddy *
 	size_t cbBuddyIconData;
 	guchar *lpucPixbufPixels;
 	int cbPixbufRowstride, cbDIBRowstride;
-	int cx, cy;
-	HDC hdc;
-	HBITMAP hbitmap;
+	int cx, cy, cxScaled, cyScaled;
+	HDC hdc, hdcScreen;
+	HBITMAP hbitmap, hbmOld;
 	BITMAPINFO bmi;
 	BYTE *lpbyBits;
 	int iRow;
 	int iChannels, iBitsPerSample;
+	GError *lpgerror = NULL;
 
+	if(!lpbuddy)
+		return NULL;
+
 	lpbuddyicon = purple_buddy_icons_find(lpbuddy->account, lpbuddy->name);
 
 	if(!lpbuddyicon)
@@ -63,7 +71,7 @@ HBITMAP PurpleGetBuddyIcon(PurpleBuddy *
 	lpvBuddyIconData = purple_buddy_icon_get_data(lpbuddyicon, &cbBuddyIconData);
 
 	lppbloader = gdk_pixbuf_loader_new();
-	gdk_pixbuf_loader_write(lppbloader, lpvBuddyIconData, cbBuddyIconData, NULL);
+	if(!gdk_pixbuf_loader_write(lppbloader, lpvBuddyIconData, cbBuddyIconData, &lpgerror))
 	gdk_pixbuf_loader_close(lppbloader, NULL);
 
 	lppixbuf = gdk_pixbuf_loader_get_pixbuf(lppbloader);
@@ -103,15 +111,15 @@ HBITMAP PurpleGetBuddyIcon(PurpleBuddy *
 	bmi.bmiHeader.biYPelsPerMeter = 0;
 
 	/* Scanlines must start on DWORD boundaries. */
-	cbDIBRowstride = (4 * cx * sizeof(DWORD) + 3) / 4;
+	cbDIBRowstride = (4 * cx * iChannels + 3) / 4;
 
 	lpbyBits = ProcHeapAlloc(cbDIBRowstride * cy);
 
 	/* Bottom-up DIB. */
 	for(iRow = 0; iRow < cy; iRow++)
 	{
-		int cbDIBRowOffest = (cy - iRow) * cbDIBRowstride;
-		int cbPixbufRowOffest = (cy - iRow) * cbDIBRowstride;
+		int cbDIBRowOffest = (cy - iRow - 1) * cbDIBRowstride;
+		int cbPixbufRowOffest = iRow * cbPixbufRowstride;
 		int iCol;
 
 		for(iCol = 0; iCol < cx; iCol++)
@@ -124,20 +132,71 @@ HBITMAP PurpleGetBuddyIcon(PurpleBuddy *
 
 			/* Blue, green, red. */
 			for(iChan = 0; iChan < 3; iChan++)
-				lpbyBits[cbDIBRowOffest + iChan] = lpucPixbufPixels[cbPixbufRowOffest + (2 - iChan)];
+				lpbyBits[cbDIBRowOffest + iCol * iChannels + iChan] = lpucPixbufPixels[cbPixbufRowOffest + iCol * iChannels + (2 - iChan)];
 
 			if(iChannels == 4)
-				lpbyBits[cbDIBRowOffest + 3] = lpucPixbufPixels[cbPixbufRowOffest + 3];
+				lpbyBits[cbDIBRowOffest + iCol * iChannels + 3] = lpucPixbufPixels[cbPixbufRowOffest + iCol * iChannels + 3];
 		}
 	}
 
 	g_object_unref(lppixbuf);
 
-	hdc = GetDC(NULL);
-	hbitmap = CreateDIBitmap(hdc, &bmi.bmiHeader, CBM_INIT, lpbyBits, &bmi, DIB_RGB_COLORS);
-	ReleaseDC(NULL, hdc);
+	/* Scale if necessary. */
+	if(cxMax > 0 && cyMax > 0 && (cx > cxMax || cy > cyMax))
+	{
+		if(cx * cyMax > cy * cxMax)
+		{
+			/* Scale to fit width. */
+			cxScaled = cxMax;
+			cyScaled = MulDiv(cy, cxMax, cx);
+		}
+		else
+		{
+			/* Scaled to fit height. */
+			cxScaled = MulDiv(cx, cyMax, cy);
+			cyScaled = cyMax;
+		}
+	}
+	else
+	{
+		cxScaled = cx;
+		cyScaled = cy;
+	}
 
+	hdcScreen = GetDC(NULL);
+	hdc = CreateCompatibleDC(hdcScreen);
+
+	hbitmap = CreateCompatibleBitmap(hdcScreen, cxScaled, cyScaled);
+	hbmOld = SelectObject(hdc, hbitmap);
+	SetStretchBltMode(hdc, COLORONCOLOR);
+	StretchDIBits(hdc, 0, 0, cxScaled, cyScaled, 0, 0, cx, cy, lpbyBits, &bmi, DIB_RGB_COLORS, SRCCOPY);
+	SelectObject(hdc, hbmOld);
+	
+	DeleteDC(hdc);
+	ReleaseDC(NULL, hdcScreen);
+
 	ProcHeapFree(lpbyBits);
 
 	return hbitmap;
 }
+
+
+/**
+ * Retrieves the buddy icon to be shown for an IM. It is scaled, with its
+ * aspect ratio maintained, so as not to exceed the specified dimensions,
+ * unless either of these is non-positive, in which case no scaling is
+ * performed.
+ *
+ * @param	lpconv	IM conversation.
+ * @param	cxMax	Maximum width.
+ * @param	cyMax	Maximum height.
+ *
+ * @return Bitmap handle, or NULL on error.
+ */
+HBITMAP PurpleGetIMBuddyIcon(PurpleConversation *lpconv, int cxMax, int cyMax)
+{
+	if(!lpconv || lpconv->type != PURPLE_CONV_TYPE_IM)
+		return NULL;
+
+	return PurpleGetBuddyIcon(purple_find_buddy(lpconv->account, lpconv->name), cxMax, cyMax);
+}
============================================================
--- vulture/purplebicon.h	52b0a6a50c6f8b807be05ddbac1b902466a8dca7
+++ vulture/purplebicon.h	61d1e4646d4b768a00c5eb237cbaa032c5cd21d6
@@ -29,7 +29,8 @@
 #include "purple.h"
 
 
-HBITMAP PurpleGetBuddyIcon(PurpleBuddy *lpbuddy);
+HBITMAP PurpleGetBuddyIcon(PurpleBuddy *lpbuddy, int cxMax, int cyMax);
+HBITMAP PurpleGetIMBuddyIcon(PurpleConversation *lpconv, int cxMax, int cyMax);
 
 
 #endif
============================================================
--- vulture/purpleconv.c	1bb4be6687816e6000534a0859b0494c0f8b97fc
+++ vulture/purpleconv.c	311b1df4fdc9391b45c371599a84537395f1d0d4
@@ -53,6 +53,7 @@ void PurpleNewConversation(PurpleConvers
 
 	lpvconv->lpconv = lpconv;
 	lpvconv->hwndContainer = lpvconv->hwndConv = NULL;
+	lpvconv->hbmIcon = NULL;
 
 	/* Cache this, since the UI should not mess with the PurpleConversation
 	 * directly.
============================================================
--- vulture/purplequeue.c	fbdd2c87a68f0e6fb6e96eb54fa4c2adbd45f746
+++ vulture/purplequeue.c	799b95ff480055c663a50cc5b3d7c8f93621a4fe
@@ -33,6 +33,8 @@
 #include "purpleblist.h"
 #include "vultureblist.h"
 #include "vulturedlg.h"
+#include "vulturebicon.h"
+#include "purplebicon.h"
 
 
 /** Queue node representing a libpurple call. */
@@ -258,6 +260,14 @@ static void DispatchPurpleCall(PURPLE_CA
 		
 		break;
 
+	case PC_GETIMBUDDYICON:
+		{
+			VULTURE_GET_IM_BUDDY_ICON *lpvgetimbicon = lppurplecall->lpvParam;
+			lpvgetimbicon->hbmIcon = PurpleGetIMBuddyIcon(lpvgetimbicon->lpvconv->lpconv, lpvgetimbicon->cxMax, lpvgetimbicon->cyMax);
+		}
+		
+		break;
+
 	case PC_QUIT:
 		purple_core_quit();
 		g_main_loop_quit(g_lpgmainloop);
============================================================
--- vulture/purplequeue.h	f0bf6fb7098a47d99424a8113626642eb0219501
+++ vulture/purplequeue.h	b43814d4efcb0e33511f3b359092d4454360f9fa
@@ -79,6 +79,9 @@ enum PURPLE_CALL_ID
 
 	/* (VULTURE_CONV_GET_STRING*) Retrieves the chat's topic. */
 	PC_CHATGETTOPIC,
+
+	/* (VULTURE_GET_IM_BUDDY_ICON*) */
+	PC_GETIMBUDDYICON,
 };
 
 
============================================================
--- vulture/resource.h	182bceccaa34fbadf949daca176c25530e1afcf6
+++ vulture/resource.h	0ad9ca7d3183d5898acafedab6fe097213fc9f6d
@@ -39,3 +39,4 @@
 #define IDC_STATIC_NAME                         40011
 #define IDC_STATIC_STATUS                       40013
 #define IDC_STATIC_TOPIC                        40013
+#define IDC_STATIC_ICON                         40014
============================================================
--- vulture/vulture-res.rc	d6066954a1e5c18392fd0b65e7693ebe1b178b30
+++ vulture/vulture-res.rc	3fd1722bbe5b7004106cb01e70d64450dab506f2
@@ -79,7 +79,7 @@ FONT 8, "Ms Shell Dlg"
     CONTROL         "", IDC_RICHEDIT_CONV, RICHEDIT_CLASS, WS_TABSTOP | WS_VSCROLL | WS_BORDER | ES_AUTOVSCROLL | ES_MULTILINE | ES_READONLY, 5, 35, 245, 180
     CONTROL         "", IDC_RICHEDIT_INPUT, RICHEDIT_CLASS, WS_TABSTOP | WS_BORDER | ES_MULTILINE | ES_WANTRETURN, 5, 190, 245, 40
     CONTROL         "", IDC_TREE_NAMES, WC_TREEVIEW, WS_TABSTOP | WS_BORDER | TVS_INFOTIP | TVS_NOHSCROLL | TVS_FULLROWSELECT, 255, 35, 65, 225
-    CONTROL         "", IDC_STATIC, WC_STATIC, SS_BITMAP, 5, 5, 20, 17
+    CONTROL         "", IDC_STATIC_ICON, WC_STATIC, SS_BITMAP | SS_CENTERIMAGE | SS_SUNKEN, 5, 5, 25, 21
     LTEXT           "", IDC_STATIC_NAME, 40, 5, 275, 8, SS_LEFT
     LTEXT           "", IDC_STATIC_TOPIC, 40, 15, 275, 8, SS_LEFT
 }
@@ -104,7 +104,7 @@ FONT 8, "Ms Shell Dlg"
 {
     CONTROL         "", IDC_RICHEDIT_CONV, RICHEDIT_CLASS, WS_TABSTOP | WS_VSCROLL | WS_BORDER | ES_AUTOVSCROLL | ES_MULTILINE | ES_READONLY, 5, 35, 310, 150
     CONTROL         "", IDC_RICHEDIT_INPUT, RICHEDIT_CLASS, WS_TABSTOP | WS_BORDER | ES_MULTILINE | ES_WANTRETURN, 5, 190, 310, 40
-    CONTROL         "", IDC_STATIC, WC_STATIC, SS_BITMAP, 5, 5, 20, 17
+    CONTROL         "", IDC_STATIC_ICON, WC_STATIC, SS_BITMAP | SS_CENTERIMAGE | SS_SUNKEN, 5, 5, 25, 21
     LTEXT           "", IDC_STATIC_NAME, 40, 5, 275, 8, SS_LEFT
     LTEXT           "", IDC_STATIC_STATUS, 40, 15, 275, 8, SS_LEFT
 }
============================================================
--- vulture/vulturebicon.h	61e9bca7fef802cd5a4962c8cdf68101bcdfcd68
+++ vulture/vulturebicon.h	e725d73b16aedf7eaa9ea29678401ab86a831715
@@ -19,3 +19,23 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
  */
+
+
+#ifndef _VULTURE_VULTUREBICON_H_
+#define _VULTURE_VULTUREBICON_H_
+
+
+#include <windows.h>
+
+#include "vultureconv.h"
+
+
+typedef struct _VULTURE_GET_IM_BUDDY_ICON
+{
+	VULTURE_CONVERSATION	*lpvconv;
+	int			cxMax, cyMax;
+	HBITMAP			hbmIcon;
+} VULTURE_GET_IM_BUDDY_ICON;
+
+
+#endif
============================================================
--- vulture/vultureconv.c	99deff7033c0c81269bbee0615a6ef76d608a1d2
+++ vulture/vultureconv.c	c5f80979a74533b070afd476b3e352042d86bbea
@@ -35,6 +35,7 @@
 #include "vultureblist.h"
 #include "purplemain.h"
 #include "purplequeue.h"
+#include "vulturebicon.h"
 
 
 #define CONVCONTAINERCLASS	TEXT("VULTURECONVCONTAINER")
@@ -59,7 +60,7 @@ static void ResizeActiveConversationWind
 static INT_PTR CALLBACK ChatDlgProc(HWND hwndDlg, UINT uiMsg, WPARAM wParam, LPARAM lParam);
 static INT_PTR CALLBACK ConvCommonDlgProc(HWND hwndDlg, UINT uiMsg, WPARAM wParam, LPARAM lParam);
 static void ResizeActiveConversationWindow(HWND hwndConvContainer, HWND hwndTabs);
-static void RepositionConvControls(HWND hwndConvDlg);
+static void RepositionConvControls(HWND hwndConvDlg, VULTURE_CONVERSATION *lpvconv);
 static LRESULT CALLBACK InputBoxSubclassProc(HWND hwnd, UINT uiMsg, WPARAM wParam, LPARAM lParam);
 static void EnableAppropriateConvWindow(CONVCONTAINERDATA *lpccd);
 static void SetConvTitle(VULTURE_CONVERSATION *lpvconv, HWND hwndTabs, LPTSTR szTitle);
@@ -67,6 +68,7 @@ static INLINE void SortUserList(HWND hwn
 static void FreeChatUser(void *lpvChatUser);
 static int CALLBACK UserListComparator(LPARAM lParam1, LPARAM lParam2, LPARAM lParamUnused);
 static INLINE void SortUserList(HWND hwndTVUsers);
+static void UpdateIMIcon(HWND hwndDlg, VULTURE_CONVERSATION *lpvconv);
 
 
 /**
@@ -423,6 +425,12 @@ static INT_PTR CALLBACK IMDlgProc(HWND h
 	{
 	case WM_INITDIALOG:
 		UpdateIMStatusText(hwndDlg, (VULTURE_CONVERSATION*)lParam);
+
+		/* Get the icon control to the right size. */
+		RepositionConvControls(hwndDlg, (VULTURE_CONVERSATION*)lParam);
+
+		UpdateIMIcon(hwndDlg, (VULTURE_CONVERSATION*)lParam);
+
 		break;
 
 	case WM_PURPLEUIMSG:
@@ -431,6 +439,16 @@ static INT_PTR CALLBACK IMDlgProc(HWND h
 		case VUIMSG_UPDATEIMSTATUSTEXT:
 			UpdateIMStatusText(hwndDlg, (VULTURE_CONVERSATION*)lParam);
 			break;
+
+		case VUIMSG_CONVCHANGED:
+			{
+				VULTURE_CONV_CHANGED *lpvcchanged = (VULTURE_CONV_CHANGED*)lParam;
+
+				if(lpvcchanged->pcut == PURPLE_CONV_UPDATE_ICON)
+					UpdateIMIcon(hwndDlg, lpvcchanged->lpvconv);
+			}
+
+			break;
 		}
 
 		break;
@@ -686,8 +704,28 @@ static INT_PTR CALLBACK ConvCommonDlgPro
 		return TRUE;
 
 	case WM_SIZE:
-		RepositionConvControls(hwndDlg);
+		RepositionConvControls(hwndDlg, (VULTURE_CONVERSATION*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA));
 		return TRUE;
+
+	case WM_DESTROY:
+		{
+			/* Get handle to bitmap in icon control. */
+			HBITMAP hbmPrev = (HBITMAP)SendDlgItemMessage(hwndDlg, IDC_STATIC_ICON, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)NULL);
+
+			lpvconv = (VULTURE_CONVERSATION*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
+			
+			/* On Windows >= XP, the static control sometimes makes
+			 * a copy of the bitmap we send it, in which case we
+			 * have *two* bitmaps to free now.
+			 */
+			if(hbmPrev != lpvconv->hbmIcon && hbmPrev)
+				DeleteObject(hbmPrev);
+
+			if(lpvconv->hbmIcon)
+				DeleteObject(lpvconv->hbmIcon);
+		}
+
+		return TRUE;
 	}
 
 	return FALSE;
@@ -734,12 +772,12 @@ static void ResizeActiveConversationWind
  * Repositions and resizes controls in a conversation window.
  *
  * @param	hwndConvDlg	Conversation window.
+ * @param	lpvconv		Conversation.
  */
-static void RepositionConvControls(HWND hwndConvDlg)
+static void RepositionConvControls(HWND hwndConvDlg, VULTURE_CONVERSATION *lpvconv)
 {
 	RECT rcClient;
-	VULTURE_CONVERSATION *lpvconv = (VULTURE_CONVERSATION*)GetWindowLongPtr(hwndConvDlg, GWLP_USERDATA);
-	HDWP hdwp = BeginDeferWindowPos(lpvconv->convtype == PURPLE_CONV_TYPE_CHAT ? 3 : 2);
+	HDWP hdwp = BeginDeferWindowPos(lpvconv->convtype == PURPLE_CONV_TYPE_CHAT ? 4 : 3);
 	int cxLeft;
 
 	GetClientRect(hwndConvDlg, &rcClient);
@@ -749,6 +787,16 @@ static void RepositionConvControls(HWND 
 
 	hdwp = DeferWindowPos(
 		hdwp,
+		GetDlgItem(hwndConvDlg, IDC_STATIC_ICON),
+		NULL,
+		CONV_DLG_MARGIN,
+		CONV_DLG_MARGIN,
+		CONV_TOP_MARGIN - 2 * CONV_DLG_MARGIN,
+		CONV_TOP_MARGIN - 2 * CONV_DLG_MARGIN,
+		SWP_NOACTIVATE | SWP_NOZORDER);
+
+	hdwp = DeferWindowPos(
+		hdwp,
 		GetDlgItem(hwndConvDlg, IDC_RICHEDIT_CONV),
 		NULL,
 		CONV_DLG_MARGIN,
@@ -1029,3 +1077,42 @@ static INLINE void SortUserList(HWND hwn
 
 	TreeView_SortChildrenCB(hwndTVUsers, &tvsortcb, FALSE);
 }
+
+
+/**
+ * Updates the icon in an IM window.
+ *
+ * @param	hwndDlg		IM dialogue window handle.
+ * @param	lpvconv		Conversation.
+ */
+static void UpdateIMIcon(HWND hwndDlg, VULTURE_CONVERSATION *lpvconv)
+{
+	VULTURE_GET_IM_BUDDY_ICON vgetimbicon;
+	HBITMAP hbmPrev;
+	RECT rcIcon;
+
+	GetClientRect(GetDlgItem(hwndDlg, IDC_STATIC_ICON), &rcIcon);
+	vgetimbicon.cxMax = rcIcon.right - rcIcon.left;
+	vgetimbicon.cyMax = rcIcon.bottom - rcIcon.top;
+
+	vgetimbicon.lpvconv = lpvconv;
+	VultureSingleSyncPurpleCall(PC_GETIMBUDDYICON, &vgetimbicon);
+
+	/* Set new bitmap and retrieve handle to
+	 * old one.
+	 */
+	hbmPrev = (HBITMAP)SendDlgItemMessage(hwndDlg, IDC_STATIC_ICON, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)vgetimbicon.hbmIcon);
+
+	/* On Windows >= XP, the static control
+	 * sometimes makes a copy of the bitmap
+	 * we send it, in which case we have
+	 * *two* bitmaps to free now.
+	 */
+	if(hbmPrev != lpvconv->hbmIcon && hbmPrev)
+		DeleteObject(hbmPrev);
+
+	if(lpvconv->hbmIcon)
+		DeleteObject(lpvconv->hbmIcon);
+
+	lpvconv->hbmIcon = vgetimbicon.hbmIcon;
+}
============================================================
--- vulture/vultureconv.h	908b9437a1729d9f7d08505e29c67aec29850d65
+++ vulture/vultureconv.h	2b228dfe9a1b58d81bd272e02490dcef19b6e842
@@ -39,6 +39,7 @@ typedef struct _VULTURE_CONVERSATION
 	int			iTabIndex;
 	WNDPROC			wndprocInputOrig;
 	PurpleConversationType	convtype;
+	HBITMAP			hbmIcon;
 } VULTURE_CONVERSATION;
 
 


More information about the Commits mailing list