aboutsummaryrefslogtreecommitdiff
path: root/xorg-server/hw/xwin/winmultiwindowicons.c
diff options
context:
space:
mode:
Diffstat (limited to 'xorg-server/hw/xwin/winmultiwindowicons.c')
-rw-r--r--xorg-server/hw/xwin/winmultiwindowicons.c457
1 files changed, 240 insertions, 217 deletions
diff --git a/xorg-server/hw/xwin/winmultiwindowicons.c b/xorg-server/hw/xwin/winmultiwindowicons.c
index 0d9d87ed2..11ae40159 100644
--- a/xorg-server/hw/xwin/winmultiwindowicons.c
+++ b/xorg-server/hw/xwin/winmultiwindowicons.c
@@ -37,8 +37,9 @@
#include "winprefs.h"
#include "propertyst.h"
-#include "windowstr.h"
+#include "propertyst.h"
+#include "windowstr.h"
/*
* External global variables
@@ -53,15 +54,9 @@ extern HICON g_hSmallIconX;
*/
static void
-winScaleIconToWindows (int iconSize,
- int effBPP,
- unsigned char *iconData,
- unsigned short width,
- unsigned short height,
- int xStride,
- int effXBPP,
- int effXDepth,
- unsigned char *image);
+winScaleXBitmapToWindows (int iconSize, int effBPP,
+ PixmapPtr pixmap, unsigned char *image);
+
/*
* Scale an X icon bitmap into a Windoze icon bitmap
@@ -73,9 +68,15 @@ winScaleXBitmapToWindows (int iconSize,
PixmapPtr pixmap,
unsigned char *image)
{
- int effXBPP, effXDepth;
- int xStride;
- unsigned char *iconData = 0;
+ int row, column, effXBPP, effXDepth;
+ unsigned char *outPtr;
+ char *iconData = 0;
+ int stride, xStride;
+ float factX, factY;
+ int posX, posY;
+ unsigned char *ptr;
+ unsigned int zero;
+ unsigned int color;
effXBPP = BitsPerPixel(pixmap->drawable.depth);
effXDepth = pixmap->drawable.depth;
@@ -86,10 +87,12 @@ winScaleXBitmapToWindows (int iconSize,
if (pixmap->drawable.depth == 15)
effXDepth = 16;
+ /* Need 16-bit aligned rows for DDBitmaps */
+ stride = ((iconSize * effBPP + 15) & (~15)) / 8;
xStride = PixmapBytePad (pixmap->drawable.width, pixmap->drawable.depth);
- if (xStride == 0)
+ if (stride == 0 || xStride == 0)
{
- ErrorF ("winScaleXBitmapToWindows - xStride is zero. "
+ ErrorF ("winScaleXBitmapToWindows - stride or xStride is zero. "
"Bailing.\n");
return;
}
@@ -108,54 +111,9 @@ winScaleXBitmapToWindows (int iconSize,
pixmap->drawable.width, pixmap->drawable.height,
ZPixmap, 0xffffffff, iconData);
- winScaleIconToWindows(iconSize, effBPP,
- iconData,
- pixmap->drawable.width, pixmap->drawable.height,
- xStride, effXBPP, effXDepth,
- image);
-
- free (iconData);
-}
-
-/*
- * Scale a drawable into a Windoze icon bitmap
- */
-
-static void
-winScaleIconToWindows (int iconSize,
- int effBPP,
- unsigned char *iconData,
- unsigned short width,
- unsigned short height,
- int xStride,
- int effXBPP,
- int effXDepth,
- unsigned char *image)
-{
- int row, column;
- unsigned char *outPtr;
- int stride;
- float factX, factY;
- int posX, posY;
- unsigned char *ptr;
- unsigned int zero;
- unsigned int color;
-
- winDebug("winScaleIconToWindows: scaling from %d x %d @ %d bpp (depth %d) to %d x %d @ %d bpp\n",
- width, height, effXBPP, effXDepth, iconSize, iconSize, effBPP);
-
- /* Need 16-bit aligned rows for DDBitmaps */
- stride = ((iconSize * effBPP + 15) & (~15)) / 8;
- if (stride == 0)
- {
- ErrorF ("winScaleXBitmapToWindows - stride is zero. "
- "Bailing.\n");
- return;
- }
-
/* Keep aspect ratio */
- factX = ((float)width) / ((float)iconSize);
- factY = ((float)height) / ((float)iconSize);
+ factX = ((float)pixmap->drawable.width) / ((float)iconSize);
+ factY = ((float)pixmap->drawable.height) / ((float)iconSize);
if (factX > factY)
factY = factX;
else
@@ -172,14 +130,14 @@ winScaleIconToWindows (int iconSize,
posX = factX * column;
posY = factY * row;
- ptr = iconData + posY*xStride;
+ ptr = (unsigned char*) iconData + posY*xStride;
if (effXBPP == 1)
{
ptr += posX / 8;
/* Out of X icon bounds, leave space blank */
- if (posX >= width
- || posY >= height)
+ if (posX >= pixmap->drawable.width
+ || posY >= pixmap->drawable.height)
ptr = (unsigned char *) &zero;
if ((*ptr) & (1 << (posX & 7)))
@@ -224,8 +182,8 @@ winScaleIconToWindows (int iconSize,
ptr += posX * (effXBPP / 8);
/* Out of X icon bounds, leave space blank */
- if (posX >= width
- || posY >= height)
+ if (posX >= pixmap->drawable.width
+ || posY >= pixmap->drawable.height)
ptr = (unsigned char *) &zero;
color = (((*ptr) << 16)
+ ((*(ptr + 1)) << 8)
@@ -233,10 +191,10 @@ winScaleIconToWindows (int iconSize,
switch (effBPP)
{
case 32:
- *(outPtr++) = *(ptr++); // b
- *(outPtr++) = *(ptr++); // g
- *(outPtr++) = *(ptr++); // r
- *(outPtr++) = (effXDepth == 32) ? *(ptr++) : 0x0; // alpha
+ *(outPtr++) = *(ptr++); /* b */
+ *(outPtr++) = *(ptr++); /* g */
+ *(outPtr++) = *(ptr++); /* r */
+ *(outPtr++) = (effXDepth == 32) ? *(ptr++) : 0x0; /* alpha */
break;
case 24:
*(outPtr++) = *(ptr++);
@@ -267,8 +225,8 @@ winScaleIconToWindows (int iconSize,
ptr += posX * (effXBPP / 8);
/* Out of X icon bounds, leave space blank */
- if (posX >= width
- || posY >= height)
+ if (posX >= pixmap->drawable.width
+ || posY >= pixmap->drawable.height)
ptr = (unsigned char *) &zero;
color = ((*ptr) << 8) + (*(ptr + 1));
switch (effBPP)
@@ -277,7 +235,7 @@ winScaleIconToWindows (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;
@@ -303,6 +261,123 @@ winScaleIconToWindows (int iconSize,
} /* end if effxbpp==16) */
} /* end for column */
} /* end for row */
+ 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
@@ -312,7 +387,7 @@ GetWindowProp(WindowPtr pWin, Atom name, long int *size_return)
struct _Property *prop;
if (!pWin || !name) {
- winDebug("GetWindowProp - pWin or name was NULL\n");
+ ErrorF ("GetWindowProp - pWin or name was NULL\n");
return 0;
}
pwin = (struct _Window*) pWin;
@@ -328,26 +403,6 @@ GetWindowProp(WindowPtr pWin, Atom name, long int *size_return)
return NULL;
}
-static void
-winScaleNetWMIconToWindows (int iconSize,
- int effBPP,
- uint32_t *icondata,
- unsigned char *image)
-{
- int height, width;
- uint32_t *pixels;
-
- width = icondata[0];
- height = icondata[1];
- pixels = &icondata[2];
-
- winScaleIconToWindows(iconSize, effBPP,
- (unsigned char *)pixels,
- width, height,
- width*4, 32, 32,
- image);
-}
-
/*
* Attempt to create a custom icon from the WM_HINTS bitmaps
*/
@@ -355,125 +410,98 @@ winScaleNetWMIconToWindows (int iconSize,
HICON
winXIconToHICON (WindowPtr pWin, int iconSize)
{
- unsigned char *mask, *image;
+ unsigned char *mask, *image, *imageMask;
unsigned char *dst, *src;
PixmapPtr iconPtr;
PixmapPtr maskPtr;
int planes, bpp, effBPP, stride, maskStride, i;
+ int biggest_size = 0;
HDC hDC;
ICONINFO ii;
WinXWMHints hints;
HICON hIcon = NULL;
- Bool net_wm_icon_found = FALSE;
+ uint32_t *biggest_icon = NULL;
- static Atom _XA_NET_WM_ICON = 0;
- uint32_t *icon, *icon_data;
+ /* 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);
-
- /* 15 BPP is really 16BPP as far as we care */
- if (bpp == 15)
- effBPP = 16;
- else
- effBPP = bpp;
-
- /* Need 16-bit aligned rows for DDBitmaps */
- stride = ((iconSize * effBPP + 15) & (~15)) / 8;
- /* Mask is 1-bit deep */
- maskStride = ((iconSize * 1 + 15) & (~15)) / 8;
+ if (generation != serverGeneration) {
+ generation = serverGeneration;
+ _XA_NET_WM_ICON = MakeAtom("_NET_WM_ICON", 12, TRUE);
+ }
- if (!_XA_NET_WM_ICON) _XA_NET_WM_ICON = MakeAtom("_NET_WM_ICON", 12, FALSE);
-
- /* Always prefer _NET_WM_ICON icons */
- icon_data = GetWindowProp(pWin, _XA_NET_WM_ICON, &size);
+ if (_XA_NET_WM_ICON) icon_data = GetWindowProp(pWin, _XA_NET_WM_ICON, &size);
if (icon_data)
{
- uint32_t *best_icon = 0;
- unsigned int best_size = 0;
-
- /*
- For scaling to the required size, choose the smallest icon which is
- bigger than or equal to the required size, failing that, the biggest
- icon which is smaller than the required size
- */
for(icon = icon_data;
- icon < &icon_data[size] && *icon;
- icon = &icon[icon[0]*icon[1]+2])
+ icon < &icon_data[size] && *icon;
+ icon = &icon[icon[0]*icon[1]+2])
{
- unsigned int candidateSize = (icon[0] + icon[1])/2;
- winDebug("winXIconToHICON: pWin%x found %lu x %lu NetIcon\n",(int)pWin,icon[0],icon[1]);
-
- if (((best_size < iconSize) && ((candidateSize > best_size) || (candidateSize >= iconSize)))
- || ((best_size > iconSize) && (candidateSize >= iconSize) && (candidateSize < best_size)))
+ 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])
{
- best_icon = icon;
- best_size = candidateSize;
+ biggest_icon = icon;
+ biggest_size = icon[0];
}
}
-
- if (best_icon)
- {
- winDebug("winXIconToHICON: pWin%x selected %lu x %lu NetIcon for scaling to %u x %u\n",
- (int)pWin, best_icon[0], best_icon[1], iconSize, iconSize );
-
- image = malloc (stride * iconSize);
-
- /* Use a completely black mask, image has alpha */
- mask = calloc (maskStride, iconSize);
-
- winScaleNetWMIconToWindows(iconSize, effBPP, best_icon, image);
- net_wm_icon_found = TRUE;
- }
- else
- {
- winDebug("winXIconToHICON: pWin %x no %d x %d NetIcon\n",(int)pWin,iconSize,iconSize);
- }
+ if (biggest_icon)
+ return NetWMToWinIcon(bpp, biggest_icon);
}
+ winDebug("winXIconToHICON - pWin %x: no suitable NetIcon\n",(int)pWin, iconSize);
- if (!net_wm_icon_found)
- {
- unsigned char *imageMask;
-
- winMultiWindowGetWMHints (pWin, &hints);
- winDebug("winXIconToHICON: pWin 0x%x icon_pixmap hint %x\n", pWin, hints.icon_pixmap);
- if (!hints.icon_pixmap) return NULL;
-
- iconPtr = (PixmapPtr) LookupIDByType (hints.icon_pixmap, RT_PIXMAP);
- winDebug("winXIconToHICON: pWin 0x%x iconPtr 0x%x\n", pWin, iconPtr);
-
- if (!iconPtr) return NULL;
-
- image = malloc (stride * iconSize);
- imageMask = malloc (stride * iconSize);
- /* Default to a completely black mask */
- mask = calloc (maskStride, iconSize);
+ winMultiWindowGetWMHints (pWin, &hints);
+ if (!hints.icon_pixmap) return NULL;
- winScaleXBitmapToWindows (iconSize, effBPP, iconPtr, image);
- maskPtr = (PixmapPtr) LookupIDByType (hints.icon_mask, RT_PIXMAP);
+ iconPtr = (PixmapPtr) LookupIDByType (hints.icon_pixmap, RT_PIXMAP);
+
+ if (!iconPtr) return NULL;
- if (maskPtr)
- {
- winScaleXBitmapToWindows (iconSize, 1, maskPtr, mask);
+ /* 15 BPP is really 16BPP as far as we care */
+ if (bpp == 15)
+ effBPP = 16;
+ else
+ effBPP = bpp;
+
+ /* Need 16-bit aligned rows for DDBitmaps */
+ stride = ((iconSize * effBPP + 15) & (~15)) / 8;
- winScaleXBitmapToWindows (iconSize, effBPP, maskPtr, imageMask);
+ /* Mask is 1-bit deep */
+ maskStride = ((iconSize * 1 + 15) & (~15)) / 8;
- /* Now we need to set all bits of the icon which are not masked */
- /* on to 0 because Color is really an XOR, not an OR function */
- dst = image;
- src = imageMask;
+ image = malloc (stride * iconSize);
+ imageMask = malloc (stride * iconSize);
+ /* Default to a completely black mask */
+ mask = calloc (maskStride, iconSize);
+
+ winScaleXBitmapToWindows (iconSize, effBPP, iconPtr, image);
+ maskPtr = (PixmapPtr) LookupIDByType (hints.icon_mask, RT_PIXMAP);
- for (i = 0; i < (stride * iconSize); i++)
- if ((*(src++)))
- *(dst++) = 0;
- else
- dst++;
- }
- free (imageMask);
+ if (maskPtr)
+ {
+ winScaleXBitmapToWindows (iconSize, 1, maskPtr, mask);
+
+ winScaleXBitmapToWindows (iconSize, effBPP, maskPtr, imageMask);
+
+ /* Now we need to set all bits of the icon which are not masked */
+ /* on to 0 because Color is really an XOR, not an OR function */
+ dst = image;
+ src = imageMask;
+
+ for (i = 0; i < (stride * iconSize); i++)
+ if ((*(src++)))
+ *(dst++) = 0;
+ else
+ dst++;
}
ii.fIcon = TRUE;
@@ -496,13 +524,15 @@ winXIconToHICON (WindowPtr pWin, int iconSize)
/* Free X mask and bitmap */
free (mask);
free (image);
+ free (imageMask);
return hIcon;
}
+
/*
- * Change the Windows window icon
+ * Change the Windows window icon
*/
#ifdef XWIN_MULTIWINDOW
@@ -510,44 +540,37 @@ void
winUpdateIcon (Window id)
{
WindowPtr pWin;
- HICON hIcon, hIconSmall, hiconOld;
+ HICON hIcon, hIconSmall=NULL, hIconOld;
pWin = (WindowPtr) LookupIDByType (id, RT_WINDOW);
if (!pWin) return;
-{
+ {
winWindowPriv(pWin);
- if (!pWinPriv->hWnd) return;
-
- hIcon = (HICON)winOverrideIcon ((unsigned long)pWin);
-
- if (!hIcon)
- hIcon = winXIconToHICON (pWin, GetSystemMetrics(SM_CXICON));
-
- if (hIcon)
- {
- hiconOld = (HICON) SetClassLong (pWinPriv->hWnd,
- GCL_HICON,
- (int) hIcon);
-
- /* Delete the icon if its not the default */
- if (hiconOld != g_hIconX)
- winDestroyIcon(hiconOld);
+ if (pWinPriv->hWnd) {
+ hIcon = winOverrideIcon ((unsigned long)pWin);
+ if (!hIcon) {
+ hIcon = winXIconToHICON (pWin, GetSystemMetrics(SM_CXICON));
+ if (!hIcon) {
+ hIcon = g_hIconX;
+ hIconSmall = g_hSmallIconX;
+ } else {
+ /* Leave undefined if not found */
+ hIconSmall = winXIconToHICON (pWin, GetSystemMetrics(SM_CXSMICON));
+ }
}
-
- hIconSmall = (HICON)winOverrideIcon ((unsigned long)pWin);
- if (!hIconSmall)
- hIconSmall = winXIconToHICON (pWin, GetSystemMetrics(SM_CXSMICON));
+ /* Set the large icon */
+ hIconOld = (HICON) SendMessage (pWinPriv->hWnd,
+ WM_SETICON, ICON_BIG, (LPARAM) hIcon);
- if (hIconSmall)
- {
- hiconOld = (HICON) SetClassLong (pWinPriv->hWnd,
- GCL_HICONSM,
- (int) hIconSmall);
- if (hiconOld != g_hSmallIconX)
- winDestroyIcon (hiconOld);
+ /* Delete the icon if its not the default */
+ winDestroyIcon(hIconOld);
- }
+ /* Same for the small icon */
+ hIconOld = (HICON) SendMessage (pWinPriv->hWnd,
+ WM_SETICON, ICON_SMALL, (LPARAM) hIconSmall);
+ winDestroyIcon(hIconOld);
+ }
}
}
@@ -558,8 +581,8 @@ void winInitGlobalIcons (void)
/* Load default X icon in case it's not ready yet */
if (!g_hIconX)
{
- g_hIconX = (HICON)winOverrideDefaultIcon(sm_cx);
- g_hSmallIconX = (HICON)winOverrideDefaultIcon(sm_cxsm);
+ g_hIconX = winOverrideDefaultIcon(sm_cx);
+ g_hSmallIconX = winOverrideDefaultIcon(sm_cxsm);
}
if (!g_hIconX)