diff options
Diffstat (limited to 'xorg-server/hw/xwin/winmultiwindowicons.c')
-rw-r--r-- | xorg-server/hw/xwin/winmultiwindowicons.c | 316 |
1 files changed, 231 insertions, 85 deletions
diff --git a/xorg-server/hw/xwin/winmultiwindowicons.c b/xorg-server/hw/xwin/winmultiwindowicons.c index 45ed093ec..0d9d87ed2 100644 --- a/xorg-server/hw/xwin/winmultiwindowicons.c +++ b/xorg-server/hw/xwin/winmultiwindowicons.c @@ -36,6 +36,9 @@ #include "winmultiwindowclass.h" #include "winprefs.h" +#include "propertyst.h" +#include "windowstr.h" + /* * External global variables @@ -50,9 +53,15 @@ extern HICON g_hSmallIconX; */ static void -winScaleXBitmapToWindows (int iconSize, int effBPP, - PixmapPtr pixmap, unsigned char *image); - +winScaleIconToWindows (int iconSize, + int effBPP, + unsigned char *iconData, + unsigned short width, + unsigned short height, + int xStride, + int effXBPP, + int effXDepth, + unsigned char *image); /* * Scale an X icon bitmap into a Windoze icon bitmap @@ -64,15 +73,9 @@ winScaleXBitmapToWindows (int iconSize, PixmapPtr pixmap, unsigned char *image) { - int row, column, effXBPP, effXDepth; - unsigned char *outPtr; - unsigned char *iconData = 0; - int stride, xStride; - float factX, factY; - int posX, posY; - unsigned char *ptr; - unsigned int zero; - unsigned int color; + int effXBPP, effXDepth; + int xStride; + unsigned char *iconData = 0; effXBPP = BitsPerPixel(pixmap->drawable.depth); effXDepth = pixmap->drawable.depth; @@ -83,12 +86,10 @@ winScaleXBitmapToWindows (int iconSize, if (pixmap->drawable.depth == 15) effXDepth = 16; - /* Need 32-bit aligned rows */ - stride = ((iconSize * effBPP + 31) & (~31)) / 8; xStride = PixmapBytePad (pixmap->drawable.width, pixmap->drawable.depth); - if (stride == 0 || xStride == 0) + if (xStride == 0) { - ErrorF ("winScaleXBitmapToWindows - stride or xStride is zero. " + ErrorF ("winScaleXBitmapToWindows - xStride is zero. " "Bailing.\n"); return; } @@ -107,9 +108,54 @@ 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)pixmap->drawable.width) / ((float)iconSize); - factY = ((float)pixmap->drawable.height) / ((float)iconSize); + factX = ((float)width) / ((float)iconSize); + factY = ((float)height) / ((float)iconSize); if (factX > factY) factY = factX; else @@ -132,8 +178,8 @@ winScaleXBitmapToWindows (int iconSize, ptr += posX / 8; /* Out of X icon bounds, leave space blank */ - if (posX >= pixmap->drawable.width - || posY >= pixmap->drawable.height) + if (posX >= width + || posY >= height) ptr = (unsigned char *) &zero; if ((*ptr) & (1 << (posX & 7))) @@ -178,8 +224,8 @@ winScaleXBitmapToWindows (int iconSize, ptr += posX * (effXBPP / 8); /* Out of X icon bounds, leave space blank */ - if (posX >= pixmap->drawable.width - || posY >= pixmap->drawable.height) + if (posX >= width + || posY >= height) ptr = (unsigned char *) &zero; color = (((*ptr) << 16) + ((*(ptr + 1)) << 8) @@ -190,7 +236,7 @@ winScaleXBitmapToWindows (int iconSize, *(outPtr++) = *(ptr++); // b *(outPtr++) = *(ptr++); // g *(outPtr++) = *(ptr++); // r - *(outPtr++) = 0; // resvd + *(outPtr++) = (effXDepth == 32) ? *(ptr++) : 0x0; // alpha break; case 24: *(outPtr++) = *(ptr++); @@ -221,8 +267,8 @@ winScaleXBitmapToWindows (int iconSize, ptr += posX * (effXBPP / 8); /* Out of X icon bounds, leave space blank */ - if (posX >= pixmap->drawable.width - || posY >= pixmap->drawable.height) + if (posX >= width + || posY >= height) ptr = (unsigned char *) &zero; color = ((*ptr) << 8) + (*(ptr + 1)); switch (effBPP) @@ -257,9 +303,50 @@ winScaleXBitmapToWindows (int iconSize, } /* end if effxbpp==16) */ } /* end for column */ } /* end for row */ - free (iconData); } +static pointer +GetWindowProp(WindowPtr pWin, Atom name, long int *size_return) +{ + struct _Window *pwin; + struct _Property *prop; + + if (!pWin || !name) { + winDebug("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; +} + +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 @@ -268,7 +355,7 @@ winScaleXBitmapToWindows (int iconSize, HICON winXIconToHICON (WindowPtr pWin, int iconSize) { - unsigned char *mask, *image, *imageMask; + unsigned char *mask, *image; unsigned char *dst, *src; PixmapPtr iconPtr; PixmapPtr maskPtr; @@ -276,14 +363,12 @@ winXIconToHICON (WindowPtr pWin, int iconSize) HDC hDC; ICONINFO ii; WinXWMHints hints; - HICON hIcon; + HICON hIcon = NULL; + Bool net_wm_icon_found = FALSE; - winMultiWindowGetWMHints (pWin, &hints); - if (!hints.icon_pixmap) return NULL; - - iconPtr = (PixmapPtr) LookupIDByType (hints.icon_pixmap, RT_PIXMAP); - - if (!iconPtr) return NULL; + static Atom _XA_NET_WM_ICON = 0; + uint32_t *icon, *icon_data; + long int size=0; hDC = GetDC (GetDesktopWindow ()); planes = GetDeviceCaps (hDC, PLANES); @@ -296,38 +381,99 @@ winXIconToHICON (WindowPtr pWin, int iconSize) else effBPP = bpp; - /* Need 32-bit aligned rows */ - stride = ((iconSize * effBPP + 31) & (~31)) / 8; + /* Need 16-bit aligned rows for DDBitmaps */ + stride = ((iconSize * effBPP + 15) & (~15)) / 8; /* Mask is 1-bit deep */ - maskStride = ((iconSize * 1 + 31) & (~31)) / 8; + maskStride = ((iconSize * 1 + 15) & (~15)) / 8; - image = (unsigned char * ) malloc (stride * iconSize); - imageMask = (unsigned char *) malloc (stride * iconSize); - mask = (unsigned char *) malloc (maskStride * iconSize); - - /* Default to a completely black mask */ - memset (mask, 0, maskStride * iconSize); + if (!_XA_NET_WM_ICON) _XA_NET_WM_ICON = MakeAtom("_NET_WM_ICON", 12, FALSE); - winScaleXBitmapToWindows (iconSize, effBPP, iconPtr, image); - maskPtr = (PixmapPtr) LookupIDByType (hints.icon_mask, RT_PIXMAP); + /* Always prefer _NET_WM_ICON icons */ + 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]) + { + 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))) + { + best_icon = icon; + best_size = candidateSize; + } + } + + 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 (maskPtr) + if (!net_wm_icon_found) { - 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++; + 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); + + winScaleXBitmapToWindows (iconSize, effBPP, iconPtr, image); + maskPtr = (PixmapPtr) LookupIDByType (hints.icon_mask, RT_PIXMAP); + + 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++; + } + free (imageMask); } ii.fIcon = TRUE; @@ -350,15 +496,13 @@ 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 @@ -366,10 +510,14 @@ void winUpdateIcon (Window id) { WindowPtr pWin; - HICON hIcon, hiconOld; + HICON hIcon, hIconSmall, hiconOld; pWin = (WindowPtr) LookupIDByType (id, RT_WINDOW); if (!pWin) return; +{ + winWindowPriv(pWin); + if (!pWinPriv->hWnd) return; + hIcon = (HICON)winOverrideIcon ((unsigned long)pWin); if (!hIcon) @@ -377,32 +525,30 @@ winUpdateIcon (Window id) if (hIcon) { - winWindowPriv(pWin); + hiconOld = (HICON) SetClassLong (pWinPriv->hWnd, + GCL_HICON, + (int) hIcon); - if (pWinPriv->hWnd) - { - hiconOld = (HICON) SetClassLong (pWinPriv->hWnd, - GCL_HICON, - (int) hIcon); - - /* Delete the icon if its not the default */ - winDestroyIcon(hiconOld); - } + /* Delete the icon if its not the default */ + if (hiconOld != g_hIconX) + winDestroyIcon(hiconOld); } - hIcon = winXIconToHICON (pWin, GetSystemMetrics(SM_CXSMICON)); - if (hIcon) - { - winWindowPriv(pWin); + hIconSmall = (HICON)winOverrideIcon ((unsigned long)pWin); + + if (!hIconSmall) + hIconSmall = winXIconToHICON (pWin, GetSystemMetrics(SM_CXSMICON)); + + if (hIconSmall) + { + hiconOld = (HICON) SetClassLong (pWinPriv->hWnd, + GCL_HICONSM, + (int) hIconSmall); + if (hiconOld != g_hSmallIconX) + winDestroyIcon (hiconOld); - if (pWinPriv->hWnd) - { - hiconOld = (HICON) SetClassLong (pWinPriv->hWnd, - GCL_HICONSM, - (int) hIcon); - winDestroyIcon (hiconOld); - } } + } } void winInitGlobalIcons (void) |