diff options
Diffstat (limited to 'xorg-server/hw/xwin/winmultiwindowicons.c')
-rw-r--r-- | xorg-server/hw/xwin/winmultiwindowicons.c | 457 |
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) |