Xming: Add NET_WM_ICON to native icon conversion
fd.o bugzilla #4491 originally from a patch by Joe Krahn <jkrahn@nc.rr.com> Convert a NET_WM_ICON to a native icon by converting to a native bitmap and then using CreateIconIndirect() Don't use icon alpha on Windows 2000 or if display isn't 32-bit, convert alpha channel to a 1-bit transparency mask using a threshold value Fix warning in winScaleXBitmapToWindows() about signedness of *iconData Signed-off-by: Jon TURNEY <jon.turney@dronecode.org.uk>
This commit is contained in:
parent
211511f150
commit
a400dbb38f
|
@ -35,6 +35,9 @@
|
|||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
#ifndef WINVER
|
||||
#define WINVER 0x0500
|
||||
#endif
|
||||
|
||||
#include <X11/Xwindows.h>
|
||||
#include <windowsx.h>
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
#include "winmultiwindowclass.h"
|
||||
#include "winprefs.h"
|
||||
|
||||
#include "propertyst.h"
|
||||
|
||||
#include "propertyst.h"
|
||||
#include "windowstr.h"
|
||||
|
@ -69,7 +70,7 @@ winScaleXBitmapToWindows (int iconSize,
|
|||
{
|
||||
int row, column, effXBPP, effXDepth;
|
||||
unsigned char *outPtr;
|
||||
unsigned char *iconData = 0;
|
||||
char *iconData = 0;
|
||||
int stride, xStride;
|
||||
float factX, factY;
|
||||
int posX, posY;
|
||||
|
@ -129,7 +130,7 @@ winScaleXBitmapToWindows (int iconSize,
|
|||
posX = factX * column;
|
||||
posY = factY * row;
|
||||
|
||||
ptr = iconData + posY*xStride;
|
||||
ptr = (unsigned char*) iconData + posY*xStride;
|
||||
if (effXBPP == 1)
|
||||
{
|
||||
ptr += posX / 8;
|
||||
|
@ -190,10 +191,10 @@ winScaleXBitmapToWindows (int iconSize,
|
|||
switch (effBPP)
|
||||
{
|
||||
case 32:
|
||||
*(outPtr++) = *(ptr++); // b
|
||||
*(outPtr++) = *(ptr++); // g
|
||||
*(outPtr++) = *(ptr++); // r
|
||||
*(outPtr++) = 0; // resvd
|
||||
*(outPtr++) = *(ptr++); /* b */
|
||||
*(outPtr++) = *(ptr++); /* g */
|
||||
*(outPtr++) = *(ptr++); /* r */
|
||||
*(outPtr++) = (effXDepth == 32) ? *(ptr++) : 0x0; /* alpha */
|
||||
break;
|
||||
case 24:
|
||||
*(outPtr++) = *(ptr++);
|
||||
|
@ -234,7 +235,7 @@ winScaleXBitmapToWindows (int iconSize,
|
|||
*(outPtr++) = (color & 31) << 2;
|
||||
*(outPtr++) = ((color >> 5) & 31) << 2;
|
||||
*(outPtr++) = ((color >> 10) & 31) << 2;
|
||||
*(outPtr++) = 0; // resvd
|
||||
*(outPtr++) = 0; /* resvd */
|
||||
break;
|
||||
case 24:
|
||||
*(outPtr++) = (color & 31) << 2;
|
||||
|
@ -263,6 +264,144 @@ winScaleXBitmapToWindows (int iconSize,
|
|||
free (iconData);
|
||||
}
|
||||
|
||||
static HICON
|
||||
NetWMToWinIconAlpha(uint32_t *icon)
|
||||
{
|
||||
int width = icon[0];
|
||||
int height = icon[1];
|
||||
uint32_t *pixels = &icon[2];
|
||||
HICON result;
|
||||
HDC hdc = GetDC(NULL);
|
||||
uint32_t *DIB_pixels;
|
||||
ICONINFO ii = {TRUE};
|
||||
BITMAPV4HEADER bmh = {sizeof(bmh)};
|
||||
|
||||
/* Define an ARGB pixel format used for Color+Alpha icons */
|
||||
bmh.bV4Width = width;
|
||||
bmh.bV4Height = -height; /* Invert the image */
|
||||
bmh.bV4Planes = 1;
|
||||
bmh.bV4BitCount = 32;
|
||||
bmh.bV4V4Compression = BI_BITFIELDS;
|
||||
bmh.bV4AlphaMask = 0xFF000000;
|
||||
bmh.bV4RedMask = 0x00FF0000;
|
||||
bmh.bV4GreenMask = 0x0000FF00;
|
||||
bmh.bV4BlueMask = 0x000000FF;
|
||||
|
||||
ii.hbmColor = CreateDIBSection(hdc, (BITMAPINFO*)&bmh,
|
||||
DIB_RGB_COLORS, (void**)&DIB_pixels, NULL, 0);
|
||||
ReleaseDC(NULL, hdc);
|
||||
ii.hbmMask = CreateBitmap(width, height, 1, 1, NULL);
|
||||
memcpy(DIB_pixels, pixels, height*width*4);
|
||||
|
||||
/* CreateIconIndirect() traditionally required DDBitmaps */
|
||||
/* Systems from WinXP accept 32-bit ARGB DIBitmaps with full 8-bit alpha support */
|
||||
/* The icon is created with a DIB + empty DDB mask (an MS example does the same) */
|
||||
result = CreateIconIndirect(&ii);
|
||||
|
||||
DeleteObject(ii.hbmColor);
|
||||
DeleteObject(ii.hbmMask);
|
||||
|
||||
winDebug("NetWMToWinIconAlpha - %d x %d = %p\n", icon[0], icon[1], result);
|
||||
return result;
|
||||
}
|
||||
|
||||
static HICON
|
||||
NetWMToWinIconThreshold(uint32_t *icon)
|
||||
{
|
||||
int width = icon[0];
|
||||
int height = icon[1];
|
||||
uint32_t *pixels = &icon[2];
|
||||
int row, col;
|
||||
HICON result;
|
||||
ICONINFO ii = {TRUE};
|
||||
|
||||
HDC hdc = GetDC(NULL);
|
||||
HDC xorDC = CreateCompatibleDC(hdc);
|
||||
HDC andDC = CreateCompatibleDC(hdc);
|
||||
ii.hbmColor = CreateCompatibleBitmap(hdc, width, height);
|
||||
ii.hbmMask = CreateCompatibleBitmap(hdc, width, height);
|
||||
ReleaseDC(NULL, hdc);
|
||||
SelectObject(xorDC, ii.hbmColor);
|
||||
SelectObject(andDC, ii.hbmMask);
|
||||
|
||||
for (row = 0; row < height; row++) {
|
||||
for (col = 0; col < width; col++) {
|
||||
if ((*pixels & 0xFF000000) > 31<<24) { /* 31 alpha threshold, i.e. opaque above, transparent below */
|
||||
SetPixelV(xorDC, col, row, RGB(((char*)pixels)[2], ((char*)pixels)[1],
|
||||
((char*)pixels)[0]));
|
||||
SetPixelV(andDC, col, row, RGB(0, 0, 0)); /* black mask */
|
||||
}
|
||||
else {
|
||||
SetPixelV(xorDC, col, row, RGB(0, 0, 0));
|
||||
SetPixelV(andDC, col, row, RGB(255, 255, 255)); /* white mask */
|
||||
}
|
||||
pixels++;
|
||||
}
|
||||
}
|
||||
DeleteDC(xorDC);
|
||||
DeleteDC(andDC);
|
||||
|
||||
result = CreateIconIndirect(&ii);
|
||||
|
||||
DeleteObject(ii.hbmColor);
|
||||
DeleteObject(ii.hbmMask );
|
||||
|
||||
winDebug("NetWMToWinIconThreshold - %d x %d = %p\n", icon[0], icon[1], result);
|
||||
return result;
|
||||
}
|
||||
|
||||
static HICON
|
||||
NetWMToWinIcon(int bpp, uint32_t *icon)
|
||||
{
|
||||
static Bool hasIconAlphaChannel = FALSE;
|
||||
static BOOL versionChecked = FALSE;
|
||||
|
||||
if (!versionChecked)
|
||||
{
|
||||
OSVERSIONINFOEX osvi = {0};
|
||||
ULONGLONG dwlConditionMask = 0;
|
||||
|
||||
osvi.dwOSVersionInfoSize = sizeof (osvi);
|
||||
osvi.dwMajorVersion = 5;
|
||||
osvi.dwMinorVersion = 1;
|
||||
|
||||
/* Windows versions later than XP have icon alpha channel suport, 2000 does not */
|
||||
VER_SET_CONDITION(dwlConditionMask, VER_MAJORVERSION, VER_GREATER_EQUAL);
|
||||
VER_SET_CONDITION(dwlConditionMask, VER_MINORVERSION, VER_GREATER_EQUAL);
|
||||
hasIconAlphaChannel = VerifyVersionInfo(&osvi, VER_MAJORVERSION | VER_MINORVERSION, dwlConditionMask);
|
||||
versionChecked = TRUE;
|
||||
|
||||
ErrorF("OS has icon alpha channel support: %s\n", hasIconAlphaChannel ? "yes" : "no");
|
||||
}
|
||||
|
||||
if (hasIconAlphaChannel && (bpp==32))
|
||||
return NetWMToWinIconAlpha(icon);
|
||||
else
|
||||
return NetWMToWinIconThreshold(icon);
|
||||
}
|
||||
|
||||
static pointer
|
||||
GetWindowProp(WindowPtr pWin, Atom name, long int *size_return)
|
||||
{
|
||||
struct _Window *pwin;
|
||||
struct _Property *prop;
|
||||
|
||||
if (!pWin || !name) {
|
||||
ErrorF ("GetWindowProp - pWin or name was NULL\n");
|
||||
return 0;
|
||||
}
|
||||
pwin = (struct _Window*) pWin;
|
||||
if (!pwin->optional) return NULL;
|
||||
for (prop = (struct _Property *) pwin->optional->userProps;
|
||||
prop;
|
||||
prop=prop->next){
|
||||
if (prop->propertyName == name) {
|
||||
*size_return=prop->size;
|
||||
return prop->data;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Attempt to create a custom icon from the WM_HINTS bitmaps
|
||||
|
@ -276,10 +415,49 @@ winXIconToHICON (WindowPtr pWin, int iconSize)
|
|||
PixmapPtr iconPtr;
|
||||
PixmapPtr maskPtr;
|
||||
int planes, bpp, effBPP, stride, maskStride, i;
|
||||
int biggest_size = 0;
|
||||
HDC hDC;
|
||||
ICONINFO ii;
|
||||
WinXWMHints hints;
|
||||
HICON hIcon;
|
||||
HICON hIcon = NULL;
|
||||
uint32_t *biggest_icon = NULL;
|
||||
|
||||
/* Try to get _NET_WM_ICON icons first */
|
||||
static Atom _XA_NET_WM_ICON;
|
||||
static int generation;
|
||||
uint32_t *icon, *icon_data = NULL;
|
||||
long int size=0;
|
||||
|
||||
hDC = GetDC (GetDesktopWindow ());
|
||||
planes = GetDeviceCaps (hDC, PLANES);
|
||||
bpp = GetDeviceCaps (hDC, BITSPIXEL);
|
||||
ReleaseDC (GetDesktopWindow (), hDC);
|
||||
|
||||
if (generation != serverGeneration) {
|
||||
generation = serverGeneration;
|
||||
_XA_NET_WM_ICON = MakeAtom("_NET_WM_ICON", 12, TRUE);
|
||||
}
|
||||
|
||||
if (_XA_NET_WM_ICON) icon_data = GetWindowProp(pWin, _XA_NET_WM_ICON, &size);
|
||||
if (icon_data)
|
||||
{
|
||||
for(icon = icon_data;
|
||||
icon < &icon_data[size] && *icon;
|
||||
icon = &icon[icon[0]*icon[1]+2])
|
||||
{
|
||||
if (icon[0]==iconSize && icon[1]==iconSize)
|
||||
return NetWMToWinIcon(bpp, icon);
|
||||
/* Find the biggest icon and let Windows scale the size */
|
||||
else if (biggest_size < icon[0])
|
||||
{
|
||||
biggest_icon = icon;
|
||||
biggest_size = icon[0];
|
||||
}
|
||||
}
|
||||
if (biggest_icon)
|
||||
return NetWMToWinIcon(bpp, biggest_icon);
|
||||
}
|
||||
winDebug("winXIconToHICON - pWin %x: no suitable NetIcon\n",(int)pWin, iconSize);
|
||||
|
||||
winMultiWindowGetWMHints (pWin, &hints);
|
||||
if (!hints.icon_pixmap) return NULL;
|
||||
|
@ -287,12 +465,7 @@ winXIconToHICON (WindowPtr pWin, int iconSize)
|
|||
iconPtr = (PixmapPtr) LookupIDByType (hints.icon_pixmap, RT_PIXMAP);
|
||||
|
||||
if (!iconPtr) return NULL;
|
||||
|
||||
hDC = GetDC (GetDesktopWindow ());
|
||||
planes = GetDeviceCaps (hDC, PLANES);
|
||||
bpp = GetDeviceCaps (hDC, BITSPIXEL);
|
||||
ReleaseDC (GetDesktopWindow (), hDC);
|
||||
|
||||
|
||||
/* 15 BPP is really 16BPP as far as we care */
|
||||
if (bpp == 15)
|
||||
effBPP = 16;
|
||||
|
|
Loading…
Reference in New Issue
Block a user