105b261ecSmrg/* 205b261ecSmrg *Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved. 305b261ecSmrg * 405b261ecSmrg *Permission is hereby granted, free of charge, to any person obtaining 505b261ecSmrg * a copy of this software and associated documentation files (the 605b261ecSmrg *"Software"), to deal in the Software without restriction, including 705b261ecSmrg *without limitation the rights to use, copy, modify, merge, publish, 805b261ecSmrg *distribute, sublicense, and/or sell copies of the Software, and to 905b261ecSmrg *permit persons to whom the Software is furnished to do so, subject to 1005b261ecSmrg *the following conditions: 1105b261ecSmrg * 1205b261ecSmrg *The above copyright notice and this permission notice shall be 1305b261ecSmrg *included in all copies or substantial portions of the Software. 1405b261ecSmrg * 1505b261ecSmrg *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 1605b261ecSmrg *EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 1705b261ecSmrg *MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 1805b261ecSmrg *NONINFRINGEMENT. IN NO EVENT SHALL THE XFREE86 PROJECT BE LIABLE FOR 1905b261ecSmrg *ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 2005b261ecSmrg *CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 2105b261ecSmrg *WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 2205b261ecSmrg * 2305b261ecSmrg *Except as contained in this notice, the name of the XFree86 Project 2405b261ecSmrg *shall not be used in advertising or otherwise to promote the sale, use 2505b261ecSmrg *or other dealings in this Software without prior written authorization 2605b261ecSmrg *from the XFree86 Project. 2705b261ecSmrg * 2805b261ecSmrg * Authors: Earle F. Philhower, III 2905b261ecSmrg */ 3005b261ecSmrg 3105b261ecSmrg#ifdef HAVE_XWIN_CONFIG_H 3205b261ecSmrg#include <xwin-config.h> 3305b261ecSmrg#endif 346747b715Smrg 3535c4bbdfSmrg#ifndef WINVER 3635c4bbdfSmrg#define WINVER 0x0500 3735c4bbdfSmrg#endif 3805b261ecSmrg 391b5d61b8Smrg#include <limits.h> 401b5d61b8Smrg#include <stdbool.h> 411b5d61b8Smrg 4235c4bbdfSmrg#include <X11/Xwindows.h> 431b5d61b8Smrg#include <xcb/xcb.h> 441b5d61b8Smrg#include <xcb/xcb_icccm.h> 451b5d61b8Smrg#include <xcb/xcb_image.h> 4605b261ecSmrg 4735c4bbdfSmrg#include "winresource.h" 4835c4bbdfSmrg#include "winprefs.h" 4935c4bbdfSmrg#include "winmsg.h" 5035c4bbdfSmrg#include "winmultiwindowicons.h" 5135c4bbdfSmrg#include "winglobals.h" 521b5d61b8Smrg 5305b261ecSmrg/* 5435c4bbdfSmrg * global variables 5505b261ecSmrg */ 5635c4bbdfSmrgextern HINSTANCE g_hInstance; 5705b261ecSmrg 5805b261ecSmrg/* 5935c4bbdfSmrg * Scale an X icon ZPixmap into a Windoze icon bitmap 6005b261ecSmrg */ 6105b261ecSmrg 6205b261ecSmrgstatic void 6335c4bbdfSmrgwinScaleXImageToWindowsIcon(int iconSize, 6435c4bbdfSmrg int effBPP, 651b5d61b8Smrg int stride, xcb_image_t* pixmap, unsigned char *image) 6605b261ecSmrg{ 6735c4bbdfSmrg int row, column, effXBPP, effXDepth; 6835c4bbdfSmrg unsigned char *outPtr; 6935c4bbdfSmrg unsigned char *iconData = 0; 7035c4bbdfSmrg int xStride; 7135c4bbdfSmrg float factX, factY; 7235c4bbdfSmrg int posX, posY; 7335c4bbdfSmrg unsigned char *ptr; 7435c4bbdfSmrg unsigned int zero; 7535c4bbdfSmrg unsigned int color; 7635c4bbdfSmrg 771b5d61b8Smrg effXBPP = pixmap->bpp; 781b5d61b8Smrg if (pixmap->bpp == 15) 7935c4bbdfSmrg effXBPP = 16; 8035c4bbdfSmrg 8135c4bbdfSmrg effXDepth = pixmap->depth; 8235c4bbdfSmrg if (pixmap->depth == 15) 8335c4bbdfSmrg effXDepth = 16; 8435c4bbdfSmrg 851b5d61b8Smrg xStride = pixmap->stride; 8635c4bbdfSmrg if (stride == 0 || xStride == 0) { 8735c4bbdfSmrg ErrorF("winScaleXBitmapToWindows - stride or xStride is zero. " 8835c4bbdfSmrg "Bailing.\n"); 8935c4bbdfSmrg return; 9005b261ecSmrg } 9105b261ecSmrg 9235c4bbdfSmrg /* Get icon data */ 9335c4bbdfSmrg iconData = (unsigned char *) pixmap->data; 9435c4bbdfSmrg 9535c4bbdfSmrg /* Keep aspect ratio */ 9635c4bbdfSmrg factX = ((float) pixmap->width) / ((float) iconSize); 9735c4bbdfSmrg factY = ((float) pixmap->height) / ((float) iconSize); 9835c4bbdfSmrg if (factX > factY) 9935c4bbdfSmrg factY = factX; 10035c4bbdfSmrg else 10135c4bbdfSmrg factX = factY; 10235c4bbdfSmrg 10335c4bbdfSmrg /* Out-of-bounds, fill icon with zero */ 10435c4bbdfSmrg zero = 0; 10535c4bbdfSmrg 10635c4bbdfSmrg for (row = 0; row < iconSize; row++) { 10735c4bbdfSmrg outPtr = image + stride * row; 10835c4bbdfSmrg for (column = 0; column < iconSize; column++) { 10935c4bbdfSmrg posX = factX * column; 11035c4bbdfSmrg posY = factY * row; 11135c4bbdfSmrg 11235c4bbdfSmrg ptr = (unsigned char *) iconData + posY * xStride; 11335c4bbdfSmrg if (effXBPP == 1) { 11435c4bbdfSmrg ptr += posX / 8; 11535c4bbdfSmrg 11635c4bbdfSmrg /* Out of X icon bounds, leave space blank */ 11735c4bbdfSmrg if (posX >= pixmap->width || posY >= pixmap->height) 11835c4bbdfSmrg ptr = (unsigned char *) &zero; 11935c4bbdfSmrg 12035c4bbdfSmrg if ((*ptr) & (1 << (posX & 7))) 12135c4bbdfSmrg switch (effBPP) { 12235c4bbdfSmrg case 32: 12335c4bbdfSmrg *(outPtr++) = 0; 12435c4bbdfSmrg case 24: 12535c4bbdfSmrg *(outPtr++) = 0; 12635c4bbdfSmrg case 16: 12735c4bbdfSmrg *(outPtr++) = 0; 12835c4bbdfSmrg case 8: 12935c4bbdfSmrg *(outPtr++) = 0; 13035c4bbdfSmrg break; 13135c4bbdfSmrg case 1: 13235c4bbdfSmrg outPtr[column / 8] &= ~(1 << (7 - (column & 7))); 13335c4bbdfSmrg break; 13435c4bbdfSmrg } 13535c4bbdfSmrg else 13635c4bbdfSmrg switch (effBPP) { 13735c4bbdfSmrg case 32: 13835c4bbdfSmrg *(outPtr++) = 255; 13935c4bbdfSmrg *(outPtr++) = 255; 14035c4bbdfSmrg *(outPtr++) = 255; 14135c4bbdfSmrg *(outPtr++) = 0; 14235c4bbdfSmrg break; 14335c4bbdfSmrg case 24: 14435c4bbdfSmrg *(outPtr++) = 255; 14535c4bbdfSmrg case 16: 14635c4bbdfSmrg *(outPtr++) = 255; 14735c4bbdfSmrg case 8: 14835c4bbdfSmrg *(outPtr++) = 255; 14935c4bbdfSmrg break; 15035c4bbdfSmrg case 1: 15135c4bbdfSmrg outPtr[column / 8] |= (1 << (7 - (column & 7))); 15235c4bbdfSmrg break; 15335c4bbdfSmrg } 15435c4bbdfSmrg } 15535c4bbdfSmrg else if (effXDepth == 24 || effXDepth == 32) { 15635c4bbdfSmrg ptr += posX * (effXBPP / 8); 15735c4bbdfSmrg 15835c4bbdfSmrg /* Out of X icon bounds, leave space blank */ 15935c4bbdfSmrg if (posX >= pixmap->width || posY >= pixmap->height) 16035c4bbdfSmrg ptr = (unsigned char *) &zero; 16135c4bbdfSmrg color = (((*ptr) << 16) 16235c4bbdfSmrg + ((*(ptr + 1)) << 8) 16335c4bbdfSmrg + ((*(ptr + 2)) << 0)); 16435c4bbdfSmrg switch (effBPP) { 16535c4bbdfSmrg case 32: 16635c4bbdfSmrg *(outPtr++) = *(ptr++); /* b */ 16735c4bbdfSmrg *(outPtr++) = *(ptr++); /* g */ 16835c4bbdfSmrg *(outPtr++) = *(ptr++); /* r */ 16935c4bbdfSmrg *(outPtr++) = (effXDepth == 32) ? *(ptr++) : 0x0; /* alpha */ 17035c4bbdfSmrg break; 17135c4bbdfSmrg case 24: 17235c4bbdfSmrg *(outPtr++) = *(ptr++); 17335c4bbdfSmrg *(outPtr++) = *(ptr++); 17435c4bbdfSmrg *(outPtr++) = *(ptr++); 17535c4bbdfSmrg break; 17635c4bbdfSmrg case 16: 17735c4bbdfSmrg color = ((((*ptr) >> 2) << 10) 17835c4bbdfSmrg + (((*(ptr + 1)) >> 2) << 5) 17935c4bbdfSmrg + (((*(ptr + 2)) >> 2))); 18035c4bbdfSmrg *(outPtr++) = (color >> 8); 18135c4bbdfSmrg *(outPtr++) = (color & 255); 18235c4bbdfSmrg break; 18335c4bbdfSmrg case 8: 18435c4bbdfSmrg color = (((*ptr))) + (((*(ptr + 1)))) + (((*(ptr + 2)))); 18535c4bbdfSmrg color /= 3; 18635c4bbdfSmrg *(outPtr++) = color; 18735c4bbdfSmrg break; 18835c4bbdfSmrg case 1: 18935c4bbdfSmrg if (color) 19035c4bbdfSmrg outPtr[column / 8] |= (1 << (7 - (column & 7))); 19135c4bbdfSmrg else 19235c4bbdfSmrg outPtr[column / 8] &= ~(1 << (7 - (column & 7))); 19335c4bbdfSmrg } 19435c4bbdfSmrg } 19535c4bbdfSmrg else if (effXDepth == 16) { 19635c4bbdfSmrg ptr += posX * (effXBPP / 8); 19735c4bbdfSmrg 19835c4bbdfSmrg /* Out of X icon bounds, leave space blank */ 19935c4bbdfSmrg if (posX >= pixmap->width || posY >= pixmap->height) 20035c4bbdfSmrg ptr = (unsigned char *) &zero; 20135c4bbdfSmrg color = ((*ptr) << 8) + (*(ptr + 1)); 20235c4bbdfSmrg switch (effBPP) { 20335c4bbdfSmrg case 32: 20435c4bbdfSmrg *(outPtr++) = (color & 31) << 2; 20535c4bbdfSmrg *(outPtr++) = ((color >> 5) & 31) << 2; 20635c4bbdfSmrg *(outPtr++) = ((color >> 10) & 31) << 2; 20735c4bbdfSmrg *(outPtr++) = 0; /* resvd */ 20835c4bbdfSmrg break; 20935c4bbdfSmrg case 24: 21035c4bbdfSmrg *(outPtr++) = (color & 31) << 2; 21135c4bbdfSmrg *(outPtr++) = ((color >> 5) & 31) << 2; 21235c4bbdfSmrg *(outPtr++) = ((color >> 10) & 31) << 2; 21335c4bbdfSmrg break; 21435c4bbdfSmrg case 16: 21535c4bbdfSmrg *(outPtr++) = *(ptr++); 21635c4bbdfSmrg *(outPtr++) = *(ptr++); 21735c4bbdfSmrg break; 21835c4bbdfSmrg case 8: 21935c4bbdfSmrg *(outPtr++) = (((color & 31) 22035c4bbdfSmrg + ((color >> 5) & 31) 22135c4bbdfSmrg + ((color >> 10) & 31)) / 3) << 2; 22235c4bbdfSmrg break; 22335c4bbdfSmrg case 1: 22435c4bbdfSmrg if (color) 22535c4bbdfSmrg outPtr[column / 8] |= (1 << (7 - (column & 7))); 22635c4bbdfSmrg else 22735c4bbdfSmrg outPtr[column / 8] &= ~(1 << (7 - (column & 7))); 22835c4bbdfSmrg break; 22935c4bbdfSmrg } /* end switch(effbpp) */ 23035c4bbdfSmrg } /* end if effxbpp==16) */ 23135c4bbdfSmrg } /* end for column */ 23235c4bbdfSmrg } /* end for row */ 23305b261ecSmrg} 23405b261ecSmrg 2356747b715Smrgstatic HICON 23635c4bbdfSmrgNetWMToWinIconAlpha(uint32_t * icon) 2376747b715Smrg{ 23835c4bbdfSmrg int width = icon[0]; 23935c4bbdfSmrg int height = icon[1]; 24035c4bbdfSmrg uint32_t *pixels = &icon[2]; 24135c4bbdfSmrg HICON result; 24235c4bbdfSmrg HDC hdc = GetDC(NULL); 24335c4bbdfSmrg uint32_t *DIB_pixels; 24435c4bbdfSmrg ICONINFO ii; 24535c4bbdfSmrg BITMAPV4HEADER bmh = { sizeof(bmh) }; 24635c4bbdfSmrg 24735c4bbdfSmrg /* Define an ARGB pixel format used for Color+Alpha icons */ 24835c4bbdfSmrg bmh.bV4Width = width; 24935c4bbdfSmrg bmh.bV4Height = -height; /* Invert the image */ 25035c4bbdfSmrg bmh.bV4Planes = 1; 25135c4bbdfSmrg bmh.bV4BitCount = 32; 25235c4bbdfSmrg bmh.bV4V4Compression = BI_BITFIELDS; 25335c4bbdfSmrg bmh.bV4AlphaMask = 0xFF000000; 25435c4bbdfSmrg bmh.bV4RedMask = 0x00FF0000; 25535c4bbdfSmrg bmh.bV4GreenMask = 0x0000FF00; 25635c4bbdfSmrg bmh.bV4BlueMask = 0x000000FF; 25735c4bbdfSmrg 25835c4bbdfSmrg ii.fIcon = TRUE; 25935c4bbdfSmrg ii.xHotspot = 0; /* ignored */ 26035c4bbdfSmrg ii.yHotspot = 0; /* ignored */ 26135c4bbdfSmrg ii.hbmColor = CreateDIBSection(hdc, (BITMAPINFO *) &bmh, 26235c4bbdfSmrg DIB_RGB_COLORS, (void **) &DIB_pixels, NULL, 26335c4bbdfSmrg 0); 26435c4bbdfSmrg ReleaseDC(NULL, hdc); 26535c4bbdfSmrg 26635c4bbdfSmrg if (!ii.hbmColor) 26735c4bbdfSmrg return NULL; 26835c4bbdfSmrg 26935c4bbdfSmrg ii.hbmMask = CreateBitmap(width, height, 1, 1, NULL); 27035c4bbdfSmrg memcpy(DIB_pixels, pixels, height * width * 4); 27135c4bbdfSmrg 27235c4bbdfSmrg /* CreateIconIndirect() traditionally required DDBitmaps */ 27335c4bbdfSmrg /* Systems from WinXP accept 32-bit ARGB DIBitmaps with full 8-bit alpha support */ 27435c4bbdfSmrg /* The icon is created with a DIB + empty DDB mask (an MS example does the same) */ 27535c4bbdfSmrg result = CreateIconIndirect(&ii); 27635c4bbdfSmrg 27735c4bbdfSmrg DeleteObject(ii.hbmColor); 27835c4bbdfSmrg DeleteObject(ii.hbmMask); 27935c4bbdfSmrg 28035c4bbdfSmrg winDebug("NetWMToWinIconAlpha - %d x %d = %p\n", icon[0], icon[1], result); 28135c4bbdfSmrg return result; 2826747b715Smrg} 2836747b715Smrg 2846747b715Smrgstatic HICON 28535c4bbdfSmrgNetWMToWinIconThreshold(uint32_t * icon) 2866747b715Smrg{ 28735c4bbdfSmrg int width = icon[0]; 28835c4bbdfSmrg int height = icon[1]; 28935c4bbdfSmrg uint32_t *pixels = &icon[2]; 29035c4bbdfSmrg int row, col; 29135c4bbdfSmrg HICON result; 29235c4bbdfSmrg ICONINFO ii; 29335c4bbdfSmrg 29435c4bbdfSmrg HDC hdc = GetDC(NULL); 29535c4bbdfSmrg HDC xorDC = CreateCompatibleDC(hdc); 29635c4bbdfSmrg HDC andDC = CreateCompatibleDC(hdc); 29735c4bbdfSmrg 29835c4bbdfSmrg ii.fIcon = TRUE; 29935c4bbdfSmrg ii.xHotspot = 0; /* ignored */ 30035c4bbdfSmrg ii.yHotspot = 0; /* ignored */ 30135c4bbdfSmrg ii.hbmColor = CreateCompatibleBitmap(hdc, width, height); 30235c4bbdfSmrg ii.hbmMask = CreateCompatibleBitmap(hdc, width, height); 30335c4bbdfSmrg ReleaseDC(NULL, hdc); 30435c4bbdfSmrg SelectObject(xorDC, ii.hbmColor); 30535c4bbdfSmrg SelectObject(andDC, ii.hbmMask); 30635c4bbdfSmrg 30735c4bbdfSmrg for (row = 0; row < height; row++) { 30835c4bbdfSmrg for (col = 0; col < width; col++) { 30935c4bbdfSmrg if ((*pixels & 0xFF000000) > 31 << 24) { /* 31 alpha threshold, i.e. opaque above, transparent below */ 31035c4bbdfSmrg SetPixelV(xorDC, col, row, 31135c4bbdfSmrg RGB(((char *) pixels)[2], ((char *) pixels)[1], 31235c4bbdfSmrg ((char *) pixels)[0])); 31335c4bbdfSmrg SetPixelV(andDC, col, row, RGB(0, 0, 0)); /* black mask */ 31435c4bbdfSmrg } 31535c4bbdfSmrg else { 31635c4bbdfSmrg SetPixelV(xorDC, col, row, RGB(0, 0, 0)); 31735c4bbdfSmrg SetPixelV(andDC, col, row, RGB(255, 255, 255)); /* white mask */ 31835c4bbdfSmrg } 31935c4bbdfSmrg pixels++; 32035c4bbdfSmrg } 3216747b715Smrg } 32235c4bbdfSmrg DeleteDC(xorDC); 32335c4bbdfSmrg DeleteDC(andDC); 3246747b715Smrg 32535c4bbdfSmrg result = CreateIconIndirect(&ii); 3266747b715Smrg 32735c4bbdfSmrg DeleteObject(ii.hbmColor); 32835c4bbdfSmrg DeleteObject(ii.hbmMask); 3296747b715Smrg 33035c4bbdfSmrg winDebug("NetWMToWinIconThreshold - %d x %d = %p\n", icon[0], icon[1], 33135c4bbdfSmrg result); 33235c4bbdfSmrg return result; 3336747b715Smrg} 3346747b715Smrg 3356747b715Smrgstatic HICON 33635c4bbdfSmrgNetWMToWinIcon(int bpp, uint32_t * icon) 3376747b715Smrg{ 3381b5d61b8Smrg static bool hasIconAlphaChannel = FALSE; 3391b5d61b8Smrg static bool versionChecked = FALSE; 34035c4bbdfSmrg 34135c4bbdfSmrg if (!versionChecked) { 34235c4bbdfSmrg OSVERSIONINFOEX osvi = { 0 }; 34335c4bbdfSmrg ULONGLONG dwlConditionMask = 0; 34435c4bbdfSmrg 34535c4bbdfSmrg osvi.dwOSVersionInfoSize = sizeof(osvi); 34635c4bbdfSmrg osvi.dwMajorVersion = 5; 34735c4bbdfSmrg osvi.dwMinorVersion = 1; 34835c4bbdfSmrg 349ed6184dfSmrg /* Windows versions later than XP have icon alpha channel support, 2000 does not */ 35035c4bbdfSmrg VER_SET_CONDITION(dwlConditionMask, VER_MAJORVERSION, 35135c4bbdfSmrg VER_GREATER_EQUAL); 35235c4bbdfSmrg VER_SET_CONDITION(dwlConditionMask, VER_MINORVERSION, 35335c4bbdfSmrg VER_GREATER_EQUAL); 35435c4bbdfSmrg hasIconAlphaChannel = 35535c4bbdfSmrg VerifyVersionInfo(&osvi, VER_MAJORVERSION | VER_MINORVERSION, 35635c4bbdfSmrg dwlConditionMask); 35735c4bbdfSmrg versionChecked = TRUE; 35835c4bbdfSmrg 35935c4bbdfSmrg ErrorF("OS has icon alpha channel support: %s\n", 36035c4bbdfSmrg hasIconAlphaChannel ? "yes" : "no"); 3616747b715Smrg } 3626747b715Smrg 36335c4bbdfSmrg if (hasIconAlphaChannel && (bpp == 32)) 36435c4bbdfSmrg return NetWMToWinIconAlpha(icon); 36535c4bbdfSmrg else 36635c4bbdfSmrg return NetWMToWinIconThreshold(icon); 3676747b715Smrg} 36805b261ecSmrg 36905b261ecSmrg/* 37005b261ecSmrg * Attempt to create a custom icon from the WM_HINTS bitmaps 37105b261ecSmrg */ 37205b261ecSmrg 37335c4bbdfSmrgstatic 3741b5d61b8SmrgHICON 3751b5d61b8SmrgwinXIconToHICON(xcb_connection_t *conn, xcb_window_t id, int iconSize) 37605b261ecSmrg{ 37735c4bbdfSmrg unsigned char *mask, *image = NULL, *imageMask; 37835c4bbdfSmrg unsigned char *dst, *src; 37935c4bbdfSmrg int planes, bpp, i; 38035c4bbdfSmrg unsigned int biggest_size = 0; 38135c4bbdfSmrg HDC hDC; 38235c4bbdfSmrg ICONINFO ii; 3831b5d61b8Smrg xcb_icccm_wm_hints_t hints; 38435c4bbdfSmrg HICON hIcon = NULL; 38535c4bbdfSmrg uint32_t *biggest_icon = NULL; 3861b5d61b8Smrg static xcb_atom_t _XA_NET_WM_ICON; 38735c4bbdfSmrg static int generation; 38835c4bbdfSmrg uint32_t *icon, *icon_data = NULL; 38935c4bbdfSmrg unsigned long int size; 39035c4bbdfSmrg 39135c4bbdfSmrg hDC = GetDC(GetDesktopWindow()); 39235c4bbdfSmrg planes = GetDeviceCaps(hDC, PLANES); 39335c4bbdfSmrg bpp = GetDeviceCaps(hDC, BITSPIXEL); 39435c4bbdfSmrg ReleaseDC(GetDesktopWindow(), hDC); 39535c4bbdfSmrg 39635c4bbdfSmrg /* Always prefer _NET_WM_ICON icons */ 39735c4bbdfSmrg if (generation != serverGeneration) { 3981b5d61b8Smrg xcb_intern_atom_reply_t *atom_reply; 3991b5d61b8Smrg xcb_intern_atom_cookie_t atom_cookie; 4001b5d61b8Smrg const char *atomName = "_NET_WM_ICON"; 4011b5d61b8Smrg 40235c4bbdfSmrg generation = serverGeneration; 4031b5d61b8Smrg 4041b5d61b8Smrg _XA_NET_WM_ICON = XCB_NONE; 4051b5d61b8Smrg 4061b5d61b8Smrg atom_cookie = xcb_intern_atom(conn, 0, strlen(atomName), atomName); 4071b5d61b8Smrg atom_reply = xcb_intern_atom_reply(conn, atom_cookie, NULL); 4081b5d61b8Smrg if (atom_reply) { 4091b5d61b8Smrg _XA_NET_WM_ICON = atom_reply->atom; 4101b5d61b8Smrg free(atom_reply); 4111b5d61b8Smrg } 41205b261ecSmrg } 41305b261ecSmrg 4141b5d61b8Smrg { 4151b5d61b8Smrg xcb_get_property_cookie_t cookie = xcb_get_property(conn, FALSE, id, _XA_NET_WM_ICON, XCB_ATOM_CARDINAL, 0L, INT_MAX); 4161b5d61b8Smrg xcb_get_property_reply_t *reply = xcb_get_property_reply(conn, cookie, NULL); 4171b5d61b8Smrg 4181b5d61b8Smrg if (reply && 4191b5d61b8Smrg ((icon_data = xcb_get_property_value(reply)) != NULL)) { 4201b5d61b8Smrg size = xcb_get_property_value_length(reply)/sizeof(uint32_t); 4211b5d61b8Smrg for (icon = icon_data; icon < &icon_data[size] && *icon; 4221b5d61b8Smrg icon = &icon[icon[0] * icon[1] + 2]) { 42335c4bbdfSmrg winDebug("winXIconToHICON: %u x %u NetIcon\n", icon[0], icon[1]); 42435c4bbdfSmrg 42535c4bbdfSmrg /* Icon data size will overflow an int and thus is bigger than the 42635c4bbdfSmrg property can possibly be */ 42735c4bbdfSmrg if ((INT_MAX/icon[0]) < icon[1]) { 42835c4bbdfSmrg winDebug("winXIconToHICON: _NET_WM_ICON icon data size overflow\n"); 42935c4bbdfSmrg break; 43035c4bbdfSmrg } 43135c4bbdfSmrg 43235c4bbdfSmrg /* Icon data size is bigger than amount of data remaining */ 43335c4bbdfSmrg if (&icon[icon[0] * icon[1] + 2] > &icon_data[size]) { 43435c4bbdfSmrg winDebug("winXIconToHICON: _NET_WM_ICON data is malformed\n"); 43535c4bbdfSmrg break; 43635c4bbdfSmrg } 43735c4bbdfSmrg 43835c4bbdfSmrg /* Found an exact match to the size we require... */ 43935c4bbdfSmrg if (icon[0] == iconSize && icon[1] == iconSize) { 44035c4bbdfSmrg winDebug("winXIconToHICON: selected %d x %d NetIcon\n", 44135c4bbdfSmrg iconSize, iconSize); 44235c4bbdfSmrg hIcon = NetWMToWinIcon(bpp, icon); 44335c4bbdfSmrg break; 44435c4bbdfSmrg } 44535c4bbdfSmrg /* Otherwise, find the biggest icon and let Windows scale the size */ 44635c4bbdfSmrg else if (biggest_size < icon[0]) { 44735c4bbdfSmrg biggest_icon = icon; 44835c4bbdfSmrg biggest_size = icon[0]; 44935c4bbdfSmrg } 45035c4bbdfSmrg } 45105b261ecSmrg 45235c4bbdfSmrg if (!hIcon && biggest_icon) { 45335c4bbdfSmrg winDebug 45435c4bbdfSmrg ("winXIconToHICON: selected %u x %u NetIcon for scaling to %d x %d\n", 45535c4bbdfSmrg biggest_icon[0], biggest_icon[1], iconSize, iconSize); 45635c4bbdfSmrg 45735c4bbdfSmrg hIcon = NetWMToWinIcon(bpp, biggest_icon); 45835c4bbdfSmrg } 45935c4bbdfSmrg 4601b5d61b8Smrg free(reply); 4611b5d61b8Smrg } 46235c4bbdfSmrg } 46335c4bbdfSmrg 46435c4bbdfSmrg if (!hIcon) { 4651b5d61b8Smrg xcb_get_property_cookie_t wm_hints_cookie; 4661b5d61b8Smrg 46735c4bbdfSmrg winDebug("winXIconToHICON: no suitable NetIcon\n"); 46835c4bbdfSmrg 4691b5d61b8Smrg wm_hints_cookie = xcb_icccm_get_wm_hints(conn, id); 4701b5d61b8Smrg if (xcb_icccm_get_wm_hints_reply(conn, wm_hints_cookie, &hints, NULL)) { 47135c4bbdfSmrg winDebug("winXIconToHICON: id 0x%x icon_pixmap hint 0x%x\n", 47235c4bbdfSmrg (unsigned int)id, 4731b5d61b8Smrg (unsigned int)hints.icon_pixmap); 4741b5d61b8Smrg 4751b5d61b8Smrg if (hints.icon_pixmap) { 4761b5d61b8Smrg unsigned int width, height; 4771b5d61b8Smrg xcb_image_t *xImageIcon; 4781b5d61b8Smrg xcb_image_t *xImageMask = NULL; 4791b5d61b8Smrg 4801b5d61b8Smrg xcb_get_geometry_cookie_t geom_cookie = xcb_get_geometry(conn, hints.icon_pixmap); 4811b5d61b8Smrg xcb_get_geometry_reply_t *geom_reply = xcb_get_geometry_reply(conn, geom_cookie, NULL); 4821b5d61b8Smrg 4831b5d61b8Smrg if (geom_reply) { 4841b5d61b8Smrg width = geom_reply->width; 4851b5d61b8Smrg height = geom_reply->height; 4861b5d61b8Smrg 4871b5d61b8Smrg xImageIcon = xcb_image_get(conn, hints.icon_pixmap, 4881b5d61b8Smrg 0, 0, width, height, 4891b5d61b8Smrg 0xFFFFFF, XCB_IMAGE_FORMAT_Z_PIXMAP); 4901b5d61b8Smrg 4911b5d61b8Smrg winDebug("winXIconToHICON: id 0x%x icon Ximage 0x%p\n", 4921b5d61b8Smrg (unsigned int)id, xImageIcon); 4931b5d61b8Smrg 4941b5d61b8Smrg if (hints.icon_mask) 4951b5d61b8Smrg xImageMask = xcb_image_get(conn, hints.icon_mask, 4961b5d61b8Smrg 0, 0, width, height, 4971b5d61b8Smrg 0xFFFFFFFF, XCB_IMAGE_FORMAT_Z_PIXMAP); 4981b5d61b8Smrg 4991b5d61b8Smrg if (xImageIcon) { 50035c4bbdfSmrg int effBPP, stride, maskStride; 50135c4bbdfSmrg 50235c4bbdfSmrg /* 15 BPP is really 16BPP as far as we care */ 50335c4bbdfSmrg if (bpp == 15) 50435c4bbdfSmrg effBPP = 16; 50535c4bbdfSmrg else 50635c4bbdfSmrg effBPP = bpp; 50735c4bbdfSmrg 50835c4bbdfSmrg /* Need 16-bit aligned rows for DDBitmaps */ 50935c4bbdfSmrg stride = ((iconSize * effBPP + 15) & (~15)) / 8; 51035c4bbdfSmrg 51135c4bbdfSmrg /* Mask is 1-bit deep */ 51235c4bbdfSmrg maskStride = ((iconSize * 1 + 15) & (~15)) / 8; 51335c4bbdfSmrg 51435c4bbdfSmrg image = malloc(stride * iconSize); 51535c4bbdfSmrg imageMask = malloc(stride * iconSize); 51635c4bbdfSmrg mask = malloc(maskStride * iconSize); 51735c4bbdfSmrg 51835c4bbdfSmrg /* Default to a completely black mask */ 51935c4bbdfSmrg memset(imageMask, 0, stride * iconSize); 52035c4bbdfSmrg memset(mask, 0, maskStride * iconSize); 52135c4bbdfSmrg 52235c4bbdfSmrg winScaleXImageToWindowsIcon(iconSize, effBPP, stride, 52335c4bbdfSmrg xImageIcon, image); 52435c4bbdfSmrg 52535c4bbdfSmrg if (xImageMask) { 52635c4bbdfSmrg winScaleXImageToWindowsIcon(iconSize, 1, maskStride, 52735c4bbdfSmrg xImageMask, mask); 52835c4bbdfSmrg winScaleXImageToWindowsIcon(iconSize, effBPP, stride, 52935c4bbdfSmrg xImageMask, imageMask); 53035c4bbdfSmrg } 53135c4bbdfSmrg 53235c4bbdfSmrg /* Now we need to set all bits of the icon which are not masked */ 53335c4bbdfSmrg /* on to 0 because Color is really an XOR, not an OR function */ 53435c4bbdfSmrg dst = image; 53535c4bbdfSmrg src = imageMask; 53635c4bbdfSmrg 53735c4bbdfSmrg for (i = 0; i < (stride * iconSize); i++) 53835c4bbdfSmrg if ((*(src++))) 53935c4bbdfSmrg *(dst++) = 0; 54035c4bbdfSmrg else 54135c4bbdfSmrg dst++; 54235c4bbdfSmrg 54335c4bbdfSmrg ii.fIcon = TRUE; 54435c4bbdfSmrg ii.xHotspot = 0; /* ignored */ 54535c4bbdfSmrg ii.yHotspot = 0; /* ignored */ 54635c4bbdfSmrg 54735c4bbdfSmrg /* Create Win32 mask from pixmap shape */ 54835c4bbdfSmrg ii.hbmMask = 54935c4bbdfSmrg CreateBitmap(iconSize, iconSize, planes, 1, mask); 55035c4bbdfSmrg 55135c4bbdfSmrg /* Create Win32 bitmap from pixmap */ 55235c4bbdfSmrg ii.hbmColor = 55335c4bbdfSmrg CreateBitmap(iconSize, iconSize, planes, bpp, image); 55435c4bbdfSmrg 55535c4bbdfSmrg /* Merge Win32 mask and bitmap into icon */ 55635c4bbdfSmrg hIcon = CreateIconIndirect(&ii); 55735c4bbdfSmrg 55835c4bbdfSmrg /* Release Win32 mask and bitmap */ 55935c4bbdfSmrg DeleteObject(ii.hbmMask); 56035c4bbdfSmrg DeleteObject(ii.hbmColor); 56135c4bbdfSmrg 56235c4bbdfSmrg /* Free X mask and bitmap */ 56335c4bbdfSmrg free(mask); 56435c4bbdfSmrg free(image); 56535c4bbdfSmrg free(imageMask); 56635c4bbdfSmrg 56735c4bbdfSmrg if (xImageMask) 5681b5d61b8Smrg xcb_image_destroy(xImageMask); 56935c4bbdfSmrg 5701b5d61b8Smrg xcb_image_destroy(xImageIcon); 5711b5d61b8Smrg } 57235c4bbdfSmrg } 57335c4bbdfSmrg } 57435c4bbdfSmrg } 57535c4bbdfSmrg } 57635c4bbdfSmrg return hIcon; 57735c4bbdfSmrg} 57805b261ecSmrg 57905b261ecSmrg/* 58035c4bbdfSmrg * Change the Windows window icon 58105b261ecSmrg */ 58205b261ecSmrg 58305b261ecSmrgvoid 584ed6184dfSmrgwinUpdateIcon(HWND hWnd, xcb_connection_t *conn, xcb_window_t id, HICON hIconNew) 58505b261ecSmrg{ 58635c4bbdfSmrg HICON hIcon, hIconSmall = NULL, hIconOld; 58735c4bbdfSmrg 5881b5d61b8Smrg if (hIconNew) 5891b5d61b8Smrg { 5901b5d61b8Smrg /* Start with the icon from preferences, if any */ 5911b5d61b8Smrg hIcon = hIconNew; 5921b5d61b8Smrg hIconSmall = hIconNew; 5931b5d61b8Smrg } 5941b5d61b8Smrg else 5951b5d61b8Smrg { 5961b5d61b8Smrg /* If we still need an icon, try and get the icon from WM_HINTS */ 5971b5d61b8Smrg hIcon = winXIconToHICON(conn, id, GetSystemMetrics(SM_CXICON)); 5981b5d61b8Smrg hIconSmall = winXIconToHICON(conn, id, GetSystemMetrics(SM_CXSMICON)); 5991b5d61b8Smrg } 60035c4bbdfSmrg 60135c4bbdfSmrg /* If we got the small, but not the large one swap them */ 60235c4bbdfSmrg if (!hIcon && hIconSmall) { 60335c4bbdfSmrg hIcon = hIconSmall; 60435c4bbdfSmrg hIconSmall = NULL; 60535c4bbdfSmrg } 6066747b715Smrg 60735c4bbdfSmrg /* Set the large icon */ 60835c4bbdfSmrg hIconOld = (HICON) SendMessage(hWnd, WM_SETICON, ICON_BIG, (LPARAM) hIcon); 60935c4bbdfSmrg /* Delete the old icon if its not the default */ 61035c4bbdfSmrg winDestroyIcon(hIconOld); 6116747b715Smrg 61235c4bbdfSmrg /* Same for the small icon */ 61335c4bbdfSmrg hIconOld = 61435c4bbdfSmrg (HICON) SendMessage(hWnd, WM_SETICON, ICON_SMALL, (LPARAM) hIconSmall); 61535c4bbdfSmrg winDestroyIcon(hIconOld); 61605b261ecSmrg} 61705b261ecSmrg 61835c4bbdfSmrgvoid 61935c4bbdfSmrgwinInitGlobalIcons(void) 62005b261ecSmrg{ 62135c4bbdfSmrg int sm_cx = GetSystemMetrics(SM_CXICON); 62235c4bbdfSmrg int sm_cxsm = GetSystemMetrics(SM_CXSMICON); 62335c4bbdfSmrg 62435c4bbdfSmrg /* Load default X icon in case it's not ready yet */ 62535c4bbdfSmrg if (!g_hIconX) { 62635c4bbdfSmrg g_hIconX = winOverrideDefaultIcon(sm_cx); 62735c4bbdfSmrg g_hSmallIconX = winOverrideDefaultIcon(sm_cxsm); 62805b261ecSmrg } 62935c4bbdfSmrg 63035c4bbdfSmrg if (!g_hIconX) { 63135c4bbdfSmrg g_hIconX = (HICON) LoadImage(g_hInstance, 63235c4bbdfSmrg MAKEINTRESOURCE(IDI_XWIN), 63335c4bbdfSmrg IMAGE_ICON, 63435c4bbdfSmrg GetSystemMetrics(SM_CXICON), 63535c4bbdfSmrg GetSystemMetrics(SM_CYICON), 0); 63635c4bbdfSmrg g_hSmallIconX = (HICON) LoadImage(g_hInstance, 63735c4bbdfSmrg MAKEINTRESOURCE(IDI_XWIN), 63835c4bbdfSmrg IMAGE_ICON, 63935c4bbdfSmrg GetSystemMetrics(SM_CXSMICON), 64035c4bbdfSmrg GetSystemMetrics(SM_CYSMICON), 64135c4bbdfSmrg LR_DEFAULTSIZE); 64205b261ecSmrg } 64305b261ecSmrg} 64405b261ecSmrg 64535c4bbdfSmrgvoid 64635c4bbdfSmrgwinSelectIcons(HICON * pIcon, HICON * pSmallIcon) 64705b261ecSmrg{ 64835c4bbdfSmrg HICON hIcon, hSmallIcon; 64935c4bbdfSmrg 65035c4bbdfSmrg winInitGlobalIcons(); 65135c4bbdfSmrg 65235c4bbdfSmrg /* Use default X icon */ 65305b261ecSmrg hIcon = g_hIconX; 65405b261ecSmrg hSmallIcon = g_hSmallIconX; 65535c4bbdfSmrg 65635c4bbdfSmrg if (pIcon) 65735c4bbdfSmrg *pIcon = hIcon; 65835c4bbdfSmrg 65935c4bbdfSmrg if (pSmallIcon) 66035c4bbdfSmrg *pSmallIcon = hSmallIcon; 66105b261ecSmrg} 66205b261ecSmrg 66335c4bbdfSmrgvoid 66435c4bbdfSmrgwinDestroyIcon(HICON hIcon) 66505b261ecSmrg{ 66635c4bbdfSmrg /* Delete the icon if its not one of the application defaults or an override */ 66735c4bbdfSmrg if (hIcon && 66835c4bbdfSmrg hIcon != g_hIconX && 66935c4bbdfSmrg hIcon != g_hSmallIconX && !winIconIsOverride(hIcon)) 67035c4bbdfSmrg DestroyIcon(hIcon); 67105b261ecSmrg} 672