diff options
Diffstat (limited to 'hw/xwin/winmultiwindowicons.c')
-rw-r--r-- | hw/xwin/winmultiwindowicons.c | 516 |
1 files changed, 16 insertions, 500 deletions
diff --git a/hw/xwin/winmultiwindowicons.c b/hw/xwin/winmultiwindowicons.c index 0322d9816..9684512da 100644 --- a/hw/xwin/winmultiwindowicons.c +++ b/hw/xwin/winmultiwindowicons.c @@ -32,510 +32,22 @@ #include <xwin-config.h> #endif -#ifndef WINVER -#define WINVER 0x0500 -#endif - #include <X11/Xwindows.h> #include <X11/Xlib.h> -#include <X11/Xutil.h> +#include <X11/Xlib-xcb.h> #include "winresource.h" #include "winprefs.h" -#include "winmsg.h" #include "winmultiwindowicons.h" #include "winglobals.h" +#include "wmutil/icon_convert.h" + /* * global variables */ extern HINSTANCE g_hInstance; /* - * Scale an X icon ZPixmap into a Windoze icon bitmap - */ - -static void -winScaleXImageToWindowsIcon(int iconSize, - int effBPP, - int stride, XImage * pixmap, unsigned char *image) -{ - int row, column, effXBPP, effXDepth; - unsigned char *outPtr; - unsigned char *iconData = 0; - int xStride; - float factX, factY; - int posX, posY; - unsigned char *ptr; - unsigned int zero; - unsigned int color; - - effXBPP = pixmap->bits_per_pixel; - if (pixmap->bits_per_pixel == 15) - effXBPP = 16; - - effXDepth = pixmap->depth; - if (pixmap->depth == 15) - effXDepth = 16; - - xStride = pixmap->bytes_per_line; - if (stride == 0 || xStride == 0) { - ErrorF("winScaleXBitmapToWindows - stride or xStride is zero. " - "Bailing.\n"); - return; - } - - /* Get icon data */ - iconData = (unsigned char *) pixmap->data; - - /* Keep aspect ratio */ - factX = ((float) pixmap->width) / ((float) iconSize); - factY = ((float) pixmap->height) / ((float) iconSize); - if (factX > factY) - factY = factX; - else - factX = factY; - - /* Out-of-bounds, fill icon with zero */ - zero = 0; - - for (row = 0; row < iconSize; row++) { - outPtr = image + stride * row; - for (column = 0; column < iconSize; column++) { - posX = factX * column; - posY = factY * row; - - ptr = (unsigned char *) iconData + posY * xStride; - if (effXBPP == 1) { - ptr += posX / 8; - - /* Out of X icon bounds, leave space blank */ - if (posX >= pixmap->width || posY >= pixmap->height) - ptr = (unsigned char *) &zero; - - if ((*ptr) & (1 << (posX & 7))) - switch (effBPP) { - case 32: - *(outPtr++) = 0; - case 24: - *(outPtr++) = 0; - case 16: - *(outPtr++) = 0; - case 8: - *(outPtr++) = 0; - break; - case 1: - outPtr[column / 8] &= ~(1 << (7 - (column & 7))); - break; - } - else - switch (effBPP) { - case 32: - *(outPtr++) = 255; - *(outPtr++) = 255; - *(outPtr++) = 255; - *(outPtr++) = 0; - break; - case 24: - *(outPtr++) = 255; - case 16: - *(outPtr++) = 255; - case 8: - *(outPtr++) = 255; - break; - case 1: - outPtr[column / 8] |= (1 << (7 - (column & 7))); - break; - } - } - else if (effXDepth == 24 || effXDepth == 32) { - ptr += posX * (effXBPP / 8); - - /* Out of X icon bounds, leave space blank */ - if (posX >= pixmap->width || posY >= pixmap->height) - ptr = (unsigned char *) &zero; - color = (((*ptr) << 16) - + ((*(ptr + 1)) << 8) - + ((*(ptr + 2)) << 0)); - switch (effBPP) { - case 32: - *(outPtr++) = *(ptr++); /* b */ - *(outPtr++) = *(ptr++); /* g */ - *(outPtr++) = *(ptr++); /* r */ - *(outPtr++) = (effXDepth == 32) ? *(ptr++) : 0x0; /* alpha */ - break; - case 24: - *(outPtr++) = *(ptr++); - *(outPtr++) = *(ptr++); - *(outPtr++) = *(ptr++); - break; - case 16: - color = ((((*ptr) >> 2) << 10) - + (((*(ptr + 1)) >> 2) << 5) - + (((*(ptr + 2)) >> 2))); - *(outPtr++) = (color >> 8); - *(outPtr++) = (color & 255); - break; - case 8: - color = (((*ptr))) + (((*(ptr + 1)))) + (((*(ptr + 2)))); - color /= 3; - *(outPtr++) = color; - break; - case 1: - if (color) - outPtr[column / 8] |= (1 << (7 - (column & 7))); - else - outPtr[column / 8] &= ~(1 << (7 - (column & 7))); - } - } - else if (effXDepth == 16) { - ptr += posX * (effXBPP / 8); - - /* Out of X icon bounds, leave space blank */ - if (posX >= pixmap->width || posY >= pixmap->height) - ptr = (unsigned char *) &zero; - color = ((*ptr) << 8) + (*(ptr + 1)); - switch (effBPP) { - case 32: - *(outPtr++) = (color & 31) << 2; - *(outPtr++) = ((color >> 5) & 31) << 2; - *(outPtr++) = ((color >> 10) & 31) << 2; - *(outPtr++) = 0; /* resvd */ - break; - case 24: - *(outPtr++) = (color & 31) << 2; - *(outPtr++) = ((color >> 5) & 31) << 2; - *(outPtr++) = ((color >> 10) & 31) << 2; - break; - case 16: - *(outPtr++) = *(ptr++); - *(outPtr++) = *(ptr++); - break; - case 8: - *(outPtr++) = (((color & 31) - + ((color >> 5) & 31) - + ((color >> 10) & 31)) / 3) << 2; - break; - case 1: - if (color) - outPtr[column / 8] |= (1 << (7 - (column & 7))); - else - outPtr[column / 8] &= ~(1 << (7 - (column & 7))); - break; - } /* end switch(effbpp) */ - } /* end if effxbpp==16) */ - } /* end for column */ - } /* end for row */ -} - -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; - 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.fIcon = TRUE; - ii.xHotspot = 0; /* ignored */ - ii.yHotspot = 0; /* ignored */ - 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; - - HDC hdc = GetDC(NULL); - HDC xorDC = CreateCompatibleDC(hdc); - HDC andDC = CreateCompatibleDC(hdc); - - ii.fIcon = TRUE; - ii.xHotspot = 0; /* ignored */ - ii.yHotspot = 0; /* ignored */ - 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); -} - -/* - * Attempt to create a custom icon from the WM_HINTS bitmaps - */ - -static - HICON -winXIconToHICON(Display * pDisplay, Window id, int iconSize) -{ - unsigned char *mask, *image = NULL, *imageMask; - unsigned char *dst, *src; - int planes, bpp, i; - int biggest_size = 0; - HDC hDC; - ICONINFO ii; - XWMHints *hints; - HICON hIcon = NULL; - uint32_t *biggest_icon = NULL; - - static Atom _XA_NET_WM_ICON; - static int generation; - uint32_t *icon, *icon_data = NULL; - unsigned long int size; - unsigned long int type; - int format; - unsigned long int left; - - hDC = GetDC(GetDesktopWindow()); - planes = GetDeviceCaps(hDC, PLANES); - bpp = GetDeviceCaps(hDC, BITSPIXEL); - ReleaseDC(GetDesktopWindow(), hDC); - - /* Always prefer _NET_WM_ICON icons */ - if (generation != serverGeneration) { - generation = serverGeneration; - _XA_NET_WM_ICON = XInternAtom(pDisplay, "_NET_WM_ICON", FALSE); - } - - if ((XGetWindowProperty(pDisplay, id, _XA_NET_WM_ICON, - 0, MAXINT, FALSE, - AnyPropertyType, &type, &format, &size, &left, - (unsigned char **) &icon_data) == Success) && - (icon_data != NULL)) { - for (icon = icon_data; icon < &icon_data[size] && *icon; - icon = &icon[icon[0] * icon[1] + 2]) { - /* Find an exact match to the size we require... */ - if (icon[0] == iconSize && icon[1] == iconSize) { - winDebug("winXIconToHICON: found %lu x %lu NetIcon\n", icon[0], - icon[1]); - hIcon = NetWMToWinIcon(bpp, icon); - break; - } - /* Otherwise, find the biggest icon and let Windows scale the size */ - else if (biggest_size < icon[0]) { - biggest_icon = icon; - biggest_size = icon[0]; - } - } - - if (!hIcon && biggest_icon) { - winDebug - ("winXIconToHICON: selected %lu x %lu NetIcon for scaling to %u x %u\n", - biggest_icon[0], biggest_icon[1], iconSize, iconSize); - - hIcon = NetWMToWinIcon(bpp, biggest_icon); - } - - XFree(icon_data); - } - - if (!hIcon) { - winDebug("winXIconToHICON: no suitable NetIcon\n"); - - hints = XGetWMHints(pDisplay, id); - if (hints) { - winDebug("winXIconToHICON: id 0x%x icon_pixmap hint %x\n", id, - hints->icon_pixmap); - - if (hints->icon_pixmap) { - Window root; - int x, y; - unsigned int width, height, border_width, depth; - XImage *xImageIcon; - XImage *xImageMask = NULL; - - XGetGeometry(pDisplay, hints->icon_pixmap, &root, &x, &y, - &width, &height, &border_width, &depth); - - xImageIcon = - XGetImage(pDisplay, hints->icon_pixmap, 0, 0, width, height, - 0xFFFFFFFF, ZPixmap); - winDebug("winXIconToHICON: id 0x%x icon Ximage 0x%x\n", id, - xImageIcon); - - if (hints->icon_mask) - xImageMask = - XGetImage(pDisplay, hints->icon_mask, 0, 0, width, - height, 0xFFFFFFFF, ZPixmap); - - if (xImageIcon) { - int effBPP, stride, maskStride; - - /* 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; - - image = malloc(stride * iconSize); - imageMask = malloc(stride * iconSize); - mask = malloc(maskStride * iconSize); - - /* Default to a completely black mask */ - memset(imageMask, 0, stride * iconSize); - memset(mask, 0, maskStride * iconSize); - - winScaleXImageToWindowsIcon(iconSize, effBPP, stride, - xImageIcon, image); - - if (xImageMask) { - winScaleXImageToWindowsIcon(iconSize, 1, maskStride, - xImageMask, mask); - winScaleXImageToWindowsIcon(iconSize, effBPP, stride, - xImageMask, 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; - ii.xHotspot = 0; /* ignored */ - ii.yHotspot = 0; /* ignored */ - - /* Create Win32 mask from pixmap shape */ - ii.hbmMask = - CreateBitmap(iconSize, iconSize, planes, 1, mask); - - /* Create Win32 bitmap from pixmap */ - ii.hbmColor = - CreateBitmap(iconSize, iconSize, planes, bpp, image); - - /* Merge Win32 mask and bitmap into icon */ - hIcon = CreateIconIndirect(&ii); - - /* Release Win32 mask and bitmap */ - DeleteObject(ii.hbmMask); - DeleteObject(ii.hbmColor); - - /* Free X mask and bitmap */ - free(mask); - free(image); - free(imageMask); - - if (xImageMask) - XDestroyImage(xImageMask); - - XDestroyImage(xImageIcon); - } - } - XFree(hints); - } - } - return hIcon; -} - -/* * Change the Windows window icon */ @@ -545,16 +57,20 @@ winUpdateIcon(HWND hWnd, Display * pDisplay, Window id, HICON hIconNew) { HICON hIcon, hIconSmall = NULL, hIconOld; - /* Start with the icon from preferences, if any */ - hIcon = hIconNew; - hIconSmall = hIconNew; + if (hIconNew) + { + /* Start with the icon from preferences, if any */ + hIcon = hIconNew; + hIconSmall = hIconNew; + } + else + { + /* If we still need an icon, try and get the icon from WM_HINTS */ + xcb_connection_t *conn = XGetXCBConnection(pDisplay); - /* If we still need an icon, try and get the icon from WM_HINTS */ - if (!hIcon) - hIcon = winXIconToHICON(pDisplay, id, GetSystemMetrics(SM_CXICON)); - if (!hIconSmall) - hIconSmall = - winXIconToHICON(pDisplay, id, GetSystemMetrics(SM_CXSMICON)); + hIcon = winXIconToHICON(conn, id, GetSystemMetrics(SM_CXICON)); + hIconSmall = winXIconToHICON(conn, id, GetSystemMetrics(SM_CXSMICON)); + } /* If we got the small, but not the large one swap them */ if (!hIcon && hIconSmall) { |