summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorColin Harrison <colin.harrison@virgin.net>2009-08-12 17:48:36 +0100
committerJon TURNEY <jon.turney@dronecode.org.uk>2009-08-12 17:56:06 +0100
commita400dbb38f93030d51afe806b4b20d5ef501c855 (patch)
tree36e1d63819ca51489ac9232b18b5e0cec4f59e9b
parent211511f150ce189681aff176c311fa8f312517e9 (diff)
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>
-rw-r--r--hw/xwin/winms.h3
-rw-r--r--hw/xwin/winmultiwindowicons.c201
2 files changed, 190 insertions, 14 deletions
diff --git a/hw/xwin/winms.h b/hw/xwin/winms.h
index 1ad30dc0b..60f7eb906 100644
--- a/hw/xwin/winms.h
+++ b/hw/xwin/winms.h
@@ -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>
diff --git a/hw/xwin/winmultiwindowicons.c b/hw/xwin/winmultiwindowicons.c
index a23f9624a..e16b2a3c8 100644
--- a/hw/xwin/winmultiwindowicons.c
+++ b/hw/xwin/winmultiwindowicons.c
@@ -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,23 +415,57 @@ 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;
- winMultiWindowGetWMHints (pWin, &hints);
- if (!hints.icon_pixmap) return 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;
- 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);
+
+ 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;
+
+ iconPtr = (PixmapPtr) LookupIDByType (hints.icon_pixmap, RT_PIXMAP);
+ if (!iconPtr) return NULL;
+
/* 15 BPP is really 16BPP as far as we care */
if (bpp == 15)
effBPP = 16;