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