2006-11-26 11:13:41 -07:00
|
|
|
/*
|
|
|
|
*Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved.
|
|
|
|
*
|
|
|
|
*Permission is hereby granted, free of charge, to any person obtaining
|
|
|
|
* a copy of this software and associated documentation files (the
|
|
|
|
*"Software"), to deal in the Software without restriction, including
|
|
|
|
*without limitation the rights to use, copy, modify, merge, publish,
|
|
|
|
*distribute, sublicense, and/or sell copies of the Software, and to
|
|
|
|
*permit persons to whom the Software is furnished to do so, subject to
|
|
|
|
*the following conditions:
|
|
|
|
*
|
|
|
|
*The above copyright notice and this permission notice shall be
|
|
|
|
*included in all copies or substantial portions of the Software.
|
|
|
|
*
|
|
|
|
*THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
|
|
*EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
|
|
*MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
|
|
*NONINFRINGEMENT. IN NO EVENT SHALL THE XFREE86 PROJECT BE LIABLE FOR
|
|
|
|
*ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
|
|
|
*CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
|
|
*WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
*
|
|
|
|
*Except as contained in this notice, the name of the XFree86 Project
|
|
|
|
*shall not be used in advertising or otherwise to promote the sale, use
|
|
|
|
*or other dealings in this Software without prior written authorization
|
|
|
|
*from the XFree86 Project.
|
|
|
|
*
|
|
|
|
* Authors: Earle F. Philhower, III
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef HAVE_XWIN_CONFIG_H
|
|
|
|
#include <xwin-config.h>
|
|
|
|
#endif
|
|
|
|
|
2013-06-07 11:28:45 -06:00
|
|
|
#ifndef WINVER
|
|
|
|
#define WINVER 0x0500
|
|
|
|
#endif
|
|
|
|
|
2017-12-08 08:01:59 -07:00
|
|
|
#include <limits.h>
|
|
|
|
#include <stdbool.h>
|
|
|
|
|
2013-06-07 11:28:45 -06:00
|
|
|
#include <X11/Xwindows.h>
|
|
|
|
#include <X11/Xlib.h>
|
2017-12-08 08:01:59 -07:00
|
|
|
#include <xcb/xcb.h>
|
|
|
|
#include <xcb/xcb_icccm.h>
|
|
|
|
#include <xcb/xcb_image.h>
|
2006-11-26 11:13:41 -07:00
|
|
|
|
2013-06-07 11:28:45 -06:00
|
|
|
#include "winresource.h"
|
|
|
|
#include "winprefs.h"
|
|
|
|
#include "winmsg.h"
|
|
|
|
#include "winmultiwindowicons.h"
|
|
|
|
#include "winglobals.h"
|
2017-12-08 08:01:59 -07:00
|
|
|
|
2006-11-26 11:13:41 -07:00
|
|
|
/*
|
2013-06-07 11:28:45 -06:00
|
|
|
* global variables
|
2006-11-26 11:13:41 -07:00
|
|
|
*/
|
2013-06-07 11:28:45 -06:00
|
|
|
extern HINSTANCE g_hInstance;
|
2006-11-26 11:13:41 -07:00
|
|
|
|
|
|
|
/*
|
2013-06-07 11:28:45 -06:00
|
|
|
* Scale an X icon ZPixmap into a Windoze icon bitmap
|
2006-11-26 11:13:41 -07:00
|
|
|
*/
|
|
|
|
|
|
|
|
static void
|
2013-06-07 11:28:45 -06:00
|
|
|
winScaleXImageToWindowsIcon(int iconSize,
|
|
|
|
int effBPP,
|
2017-12-08 08:01:59 -07:00
|
|
|
int stride, xcb_image_t* pixmap, unsigned char *image)
|
2006-11-26 11:13:41 -07:00
|
|
|
{
|
2012-06-10 07:21:05 -06:00
|
|
|
int row, column, effXBPP, effXDepth;
|
|
|
|
unsigned char *outPtr;
|
2013-06-07 11:28:45 -06:00
|
|
|
unsigned char *iconData = 0;
|
|
|
|
int xStride;
|
2012-06-10 07:21:05 -06:00
|
|
|
float factX, factY;
|
|
|
|
int posX, posY;
|
|
|
|
unsigned char *ptr;
|
|
|
|
unsigned int zero;
|
|
|
|
unsigned int color;
|
|
|
|
|
2017-12-08 08:01:59 -07:00
|
|
|
effXBPP = pixmap->bpp;
|
|
|
|
if (pixmap->bpp == 15)
|
2012-06-10 07:21:05 -06:00
|
|
|
effXBPP = 16;
|
|
|
|
|
2013-06-07 11:28:45 -06:00
|
|
|
effXDepth = pixmap->depth;
|
|
|
|
if (pixmap->depth == 15)
|
2012-06-10 07:21:05 -06:00
|
|
|
effXDepth = 16;
|
|
|
|
|
2017-12-08 08:01:59 -07:00
|
|
|
xStride = pixmap->stride;
|
2012-06-10 07:21:05 -06:00
|
|
|
if (stride == 0 || xStride == 0) {
|
|
|
|
ErrorF("winScaleXBitmapToWindows - stride or xStride is zero. "
|
|
|
|
"Bailing.\n");
|
|
|
|
return;
|
2006-11-26 11:13:41 -07:00
|
|
|
}
|
|
|
|
|
2012-06-10 07:21:05 -06:00
|
|
|
/* Get icon data */
|
2013-06-07 11:28:45 -06:00
|
|
|
iconData = (unsigned char *) pixmap->data;
|
2012-06-10 07:21:05 -06:00
|
|
|
|
|
|
|
/* Keep aspect ratio */
|
2013-06-07 11:28:45 -06:00
|
|
|
factX = ((float) pixmap->width) / ((float) iconSize);
|
|
|
|
factY = ((float) pixmap->height) / ((float) iconSize);
|
2012-06-10 07:21:05 -06:00
|
|
|
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 */
|
2013-06-07 11:28:45 -06:00
|
|
|
if (posX >= pixmap->width || posY >= pixmap->height)
|
2012-06-10 07:21:05 -06:00
|
|
|
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 */
|
2013-06-07 11:28:45 -06:00
|
|
|
if (posX >= pixmap->width || posY >= pixmap->height)
|
2012-06-10 07:21:05 -06:00
|
|
|
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 */
|
2013-06-07 11:28:45 -06:00
|
|
|
if (posX >= pixmap->width || posY >= pixmap->height)
|
2012-06-10 07:21:05 -06:00
|
|
|
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 */
|
2006-11-26 11:13:41 -07:00
|
|
|
}
|
|
|
|
|
2010-07-27 13:02:24 -06:00
|
|
|
static HICON
|
2012-06-10 07:21:05 -06:00
|
|
|
NetWMToWinIconAlpha(uint32_t * icon)
|
2010-07-27 13:02:24 -06:00
|
|
|
{
|
2012-06-10 07:21:05 -06:00
|
|
|
int width = icon[0];
|
|
|
|
int height = icon[1];
|
|
|
|
uint32_t *pixels = &icon[2];
|
|
|
|
HICON result;
|
|
|
|
HDC hdc = GetDC(NULL);
|
|
|
|
uint32_t *DIB_pixels;
|
2013-06-07 11:28:45 -06:00
|
|
|
ICONINFO ii;
|
2012-06-10 07:21:05 -06:00
|
|
|
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;
|
|
|
|
|
2013-06-07 11:28:45 -06:00
|
|
|
ii.fIcon = TRUE;
|
|
|
|
ii.xHotspot = 0; /* ignored */
|
|
|
|
ii.yHotspot = 0; /* ignored */
|
|
|
|
ii.hbmColor = CreateDIBSection(hdc, (BITMAPINFO *) &bmh,
|
2012-06-10 07:21:05 -06:00
|
|
|
DIB_RGB_COLORS, (void **) &DIB_pixels, NULL,
|
|
|
|
0);
|
|
|
|
ReleaseDC(NULL, hdc);
|
2014-05-02 13:27:46 -06:00
|
|
|
|
|
|
|
if (!ii.hbmColor)
|
|
|
|
return NULL;
|
|
|
|
|
2012-06-10 07:21:05 -06:00
|
|
|
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;
|
2010-07-27 13:02:24 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
static HICON
|
2012-06-10 07:21:05 -06:00
|
|
|
NetWMToWinIconThreshold(uint32_t * icon)
|
2010-07-27 13:02:24 -06:00
|
|
|
{
|
2012-06-10 07:21:05 -06:00
|
|
|
int width = icon[0];
|
|
|
|
int height = icon[1];
|
|
|
|
uint32_t *pixels = &icon[2];
|
|
|
|
int row, col;
|
|
|
|
HICON result;
|
2013-06-07 11:28:45 -06:00
|
|
|
ICONINFO ii;
|
2012-06-10 07:21:05 -06:00
|
|
|
|
|
|
|
HDC hdc = GetDC(NULL);
|
|
|
|
HDC xorDC = CreateCompatibleDC(hdc);
|
|
|
|
HDC andDC = CreateCompatibleDC(hdc);
|
|
|
|
|
2013-06-07 11:28:45 -06:00
|
|
|
ii.fIcon = TRUE;
|
|
|
|
ii.xHotspot = 0; /* ignored */
|
|
|
|
ii.yHotspot = 0; /* ignored */
|
2012-06-10 07:21:05 -06:00
|
|
|
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++;
|
|
|
|
}
|
2010-07-27 13:02:24 -06:00
|
|
|
}
|
2012-06-10 07:21:05 -06:00
|
|
|
DeleteDC(xorDC);
|
|
|
|
DeleteDC(andDC);
|
2010-07-27 13:02:24 -06:00
|
|
|
|
2012-06-10 07:21:05 -06:00
|
|
|
result = CreateIconIndirect(&ii);
|
2010-07-27 13:02:24 -06:00
|
|
|
|
2012-06-10 07:21:05 -06:00
|
|
|
DeleteObject(ii.hbmColor);
|
|
|
|
DeleteObject(ii.hbmMask);
|
2010-07-27 13:02:24 -06:00
|
|
|
|
2012-06-10 07:21:05 -06:00
|
|
|
winDebug("NetWMToWinIconThreshold - %d x %d = %p\n", icon[0], icon[1],
|
|
|
|
result);
|
|
|
|
return result;
|
2010-07-27 13:02:24 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
static HICON
|
2012-06-10 07:21:05 -06:00
|
|
|
NetWMToWinIcon(int bpp, uint32_t * icon)
|
2010-07-27 13:02:24 -06:00
|
|
|
{
|
2017-12-08 08:01:59 -07:00
|
|
|
static bool hasIconAlphaChannel = FALSE;
|
|
|
|
static bool versionChecked = FALSE;
|
2012-06-10 07:21:05 -06:00
|
|
|
|
|
|
|
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");
|
2010-07-27 13:02:24 -06:00
|
|
|
}
|
|
|
|
|
2012-06-10 07:21:05 -06:00
|
|
|
if (hasIconAlphaChannel && (bpp == 32))
|
|
|
|
return NetWMToWinIconAlpha(icon);
|
|
|
|
else
|
|
|
|
return NetWMToWinIconThreshold(icon);
|
2010-07-27 13:02:24 -06:00
|
|
|
}
|
|
|
|
|
2006-11-26 11:13:41 -07:00
|
|
|
/*
|
|
|
|
* Attempt to create a custom icon from the WM_HINTS bitmaps
|
|
|
|
*/
|
|
|
|
|
2013-06-07 11:28:45 -06:00
|
|
|
static
|
2017-12-08 08:01:59 -07:00
|
|
|
HICON
|
|
|
|
winXIconToHICON(xcb_connection_t *conn, xcb_window_t id, int iconSize)
|
2006-11-26 11:13:41 -07:00
|
|
|
{
|
2013-06-07 11:28:45 -06:00
|
|
|
unsigned char *mask, *image = NULL, *imageMask;
|
2012-06-10 07:21:05 -06:00
|
|
|
unsigned char *dst, *src;
|
2013-06-07 11:28:45 -06:00
|
|
|
int planes, bpp, i;
|
2014-09-27 11:52:59 -06:00
|
|
|
unsigned int biggest_size = 0;
|
2012-06-10 07:21:05 -06:00
|
|
|
HDC hDC;
|
|
|
|
ICONINFO ii;
|
2017-12-08 08:01:59 -07:00
|
|
|
xcb_icccm_wm_hints_t hints;
|
2012-06-10 07:21:05 -06:00
|
|
|
HICON hIcon = NULL;
|
|
|
|
uint32_t *biggest_icon = NULL;
|
2017-12-08 08:01:59 -07:00
|
|
|
static xcb_atom_t _XA_NET_WM_ICON;
|
2012-06-10 07:21:05 -06:00
|
|
|
static int generation;
|
|
|
|
uint32_t *icon, *icon_data = NULL;
|
2013-06-07 11:28:45 -06:00
|
|
|
unsigned long int size;
|
2012-06-10 07:21:05 -06:00
|
|
|
|
|
|
|
hDC = GetDC(GetDesktopWindow());
|
|
|
|
planes = GetDeviceCaps(hDC, PLANES);
|
|
|
|
bpp = GetDeviceCaps(hDC, BITSPIXEL);
|
|
|
|
ReleaseDC(GetDesktopWindow(), hDC);
|
|
|
|
|
2013-06-07 11:28:45 -06:00
|
|
|
/* Always prefer _NET_WM_ICON icons */
|
2012-06-10 07:21:05 -06:00
|
|
|
if (generation != serverGeneration) {
|
2017-12-08 08:01:59 -07:00
|
|
|
xcb_intern_atom_reply_t *atom_reply;
|
|
|
|
xcb_intern_atom_cookie_t atom_cookie;
|
|
|
|
const char *atomName = "_NET_WM_ICON";
|
|
|
|
|
2012-06-10 07:21:05 -06:00
|
|
|
generation = serverGeneration;
|
2017-12-08 08:01:59 -07:00
|
|
|
|
|
|
|
_XA_NET_WM_ICON = XCB_NONE;
|
|
|
|
|
|
|
|
atom_cookie = xcb_intern_atom(conn, 0, strlen(atomName), atomName);
|
|
|
|
atom_reply = xcb_intern_atom_reply(conn, atom_cookie, NULL);
|
|
|
|
if (atom_reply) {
|
|
|
|
_XA_NET_WM_ICON = atom_reply->atom;
|
|
|
|
free(atom_reply);
|
|
|
|
}
|
2010-07-27 13:02:24 -06:00
|
|
|
}
|
2012-06-10 07:21:05 -06:00
|
|
|
|
2017-12-08 08:01:59 -07:00
|
|
|
{
|
|
|
|
xcb_get_property_cookie_t cookie = xcb_get_property(conn, FALSE, id, _XA_NET_WM_ICON, XCB_ATOM_CARDINAL, 0L, INT_MAX);
|
|
|
|
xcb_get_property_reply_t *reply = xcb_get_property_reply(conn, cookie, NULL);
|
|
|
|
|
|
|
|
if (reply &&
|
|
|
|
((icon_data = xcb_get_property_value(reply)) != NULL)) {
|
|
|
|
size = xcb_get_property_value_length(reply)/sizeof(uint32_t);
|
|
|
|
for (icon = icon_data; icon < &icon_data[size] && *icon;
|
|
|
|
icon = &icon[icon[0] * icon[1] + 2]) {
|
2014-09-27 11:52:59 -06:00
|
|
|
winDebug("winXIconToHICON: %u x %u NetIcon\n", icon[0], icon[1]);
|
|
|
|
|
|
|
|
/* Icon data size will overflow an int and thus is bigger than the
|
|
|
|
property can possibly be */
|
|
|
|
if ((INT_MAX/icon[0]) < icon[1]) {
|
|
|
|
winDebug("winXIconToHICON: _NET_WM_ICON icon data size overflow\n");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Icon data size is bigger than amount of data remaining */
|
|
|
|
if (&icon[icon[0] * icon[1] + 2] > &icon_data[size]) {
|
|
|
|
winDebug("winXIconToHICON: _NET_WM_ICON data is malformed\n");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Found an exact match to the size we require... */
|
2013-06-07 11:28:45 -06:00
|
|
|
if (icon[0] == iconSize && icon[1] == iconSize) {
|
2014-09-27 11:52:59 -06:00
|
|
|
winDebug("winXIconToHICON: selected %d x %d NetIcon\n",
|
|
|
|
iconSize, iconSize);
|
2013-06-07 11:28:45 -06:00
|
|
|
hIcon = NetWMToWinIcon(bpp, icon);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
/* Otherwise, find the biggest icon and let Windows scale the size */
|
2012-06-10 07:21:05 -06:00
|
|
|
else if (biggest_size < icon[0]) {
|
|
|
|
biggest_icon = icon;
|
|
|
|
biggest_size = icon[0];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-07 11:28:45 -06:00
|
|
|
if (!hIcon && biggest_icon) {
|
|
|
|
winDebug
|
2014-09-27 11:52:59 -06:00
|
|
|
("winXIconToHICON: selected %u x %u NetIcon for scaling to %d x %d\n",
|
2013-06-07 11:28:45 -06:00
|
|
|
biggest_icon[0], biggest_icon[1], iconSize, iconSize);
|
|
|
|
|
|
|
|
hIcon = NetWMToWinIcon(bpp, biggest_icon);
|
|
|
|
}
|
2012-06-10 07:21:05 -06:00
|
|
|
|
2017-12-08 08:01:59 -07:00
|
|
|
free(reply);
|
|
|
|
}
|
2013-06-07 11:28:45 -06:00
|
|
|
}
|
2012-06-10 07:21:05 -06:00
|
|
|
|
2013-06-07 11:28:45 -06:00
|
|
|
if (!hIcon) {
|
2017-12-08 08:01:59 -07:00
|
|
|
xcb_get_property_cookie_t wm_hints_cookie;
|
|
|
|
|
2013-06-07 11:28:45 -06:00
|
|
|
winDebug("winXIconToHICON: no suitable NetIcon\n");
|
|
|
|
|
2017-12-08 08:01:59 -07:00
|
|
|
wm_hints_cookie = xcb_icccm_get_wm_hints(conn, id);
|
|
|
|
if (xcb_icccm_get_wm_hints_reply(conn, wm_hints_cookie, &hints, NULL)) {
|
2016-05-29 06:02:34 -06:00
|
|
|
winDebug("winXIconToHICON: id 0x%x icon_pixmap hint 0x%x\n",
|
|
|
|
(unsigned int)id,
|
2017-12-08 08:01:59 -07:00
|
|
|
(unsigned int)hints.icon_pixmap);
|
|
|
|
|
|
|
|
if (hints.icon_pixmap) {
|
|
|
|
unsigned int width, height;
|
|
|
|
xcb_image_t *xImageIcon;
|
|
|
|
xcb_image_t *xImageMask = NULL;
|
|
|
|
|
|
|
|
xcb_get_geometry_cookie_t geom_cookie = xcb_get_geometry(conn, hints.icon_pixmap);
|
|
|
|
xcb_get_geometry_reply_t *geom_reply = xcb_get_geometry_reply(conn, geom_cookie, NULL);
|
|
|
|
|
|
|
|
if (geom_reply) {
|
|
|
|
width = geom_reply->width;
|
|
|
|
height = geom_reply->height;
|
|
|
|
|
|
|
|
xImageIcon = xcb_image_get(conn, hints.icon_pixmap,
|
|
|
|
0, 0, width, height,
|
|
|
|
0xFFFFFF, XCB_IMAGE_FORMAT_Z_PIXMAP);
|
|
|
|
|
|
|
|
winDebug("winXIconToHICON: id 0x%x icon Ximage 0x%p\n",
|
|
|
|
(unsigned int)id, xImageIcon);
|
|
|
|
|
|
|
|
if (hints.icon_mask)
|
|
|
|
xImageMask = xcb_image_get(conn, hints.icon_mask,
|
|
|
|
0, 0, width, height,
|
|
|
|
0xFFFFFFFF, XCB_IMAGE_FORMAT_Z_PIXMAP);
|
|
|
|
|
|
|
|
if (xImageIcon) {
|
2013-06-07 11:28:45 -06:00
|
|
|
int effBPP, stride, maskStride;
|
|
|
|
|
|
|
|
/* 15 BPP is really 16BPP as far as we care */
|
|
|
|
if (bpp == 15)
|
|
|
|
effBPP = 16;
|
|
|
|
else
|
|
|
|
effBPP = bpp;
|
2012-06-10 07:21:05 -06:00
|
|
|
|
2013-06-07 11:28:45 -06:00
|
|
|
/* Need 16-bit aligned rows for DDBitmaps */
|
|
|
|
stride = ((iconSize * effBPP + 15) & (~15)) / 8;
|
2012-06-10 07:21:05 -06:00
|
|
|
|
2013-06-07 11:28:45 -06:00
|
|
|
/* Mask is 1-bit deep */
|
|
|
|
maskStride = ((iconSize * 1 + 15) & (~15)) / 8;
|
2012-06-10 07:21:05 -06:00
|
|
|
|
2013-06-07 11:28:45 -06:00
|
|
|
image = malloc(stride * iconSize);
|
|
|
|
imageMask = malloc(stride * iconSize);
|
|
|
|
mask = malloc(maskStride * iconSize);
|
2012-06-10 07:21:05 -06:00
|
|
|
|
2013-06-07 11:28:45 -06:00
|
|
|
/* Default to a completely black mask */
|
|
|
|
memset(imageMask, 0, stride * iconSize);
|
|
|
|
memset(mask, 0, maskStride * iconSize);
|
2012-06-10 07:21:05 -06:00
|
|
|
|
2013-06-07 11:28:45 -06:00
|
|
|
winScaleXImageToWindowsIcon(iconSize, effBPP, stride,
|
|
|
|
xImageIcon, image);
|
2012-06-10 07:21:05 -06:00
|
|
|
|
2013-06-07 11:28:45 -06:00
|
|
|
if (xImageMask) {
|
|
|
|
winScaleXImageToWindowsIcon(iconSize, 1, maskStride,
|
|
|
|
xImageMask, mask);
|
|
|
|
winScaleXImageToWindowsIcon(iconSize, effBPP, stride,
|
|
|
|
xImageMask, imageMask);
|
|
|
|
}
|
2012-06-10 07:21:05 -06:00
|
|
|
|
2013-06-07 11:28:45 -06:00
|
|
|
/* 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;
|
2012-06-10 07:21:05 -06:00
|
|
|
|
2013-06-07 11:28:45 -06:00
|
|
|
for (i = 0; i < (stride * iconSize); i++)
|
|
|
|
if ((*(src++)))
|
|
|
|
*(dst++) = 0;
|
|
|
|
else
|
|
|
|
dst++;
|
2006-11-26 11:13:41 -07:00
|
|
|
|
2013-06-07 11:28:45 -06:00
|
|
|
ii.fIcon = TRUE;
|
|
|
|
ii.xHotspot = 0; /* ignored */
|
|
|
|
ii.yHotspot = 0; /* ignored */
|
2012-06-10 07:21:05 -06:00
|
|
|
|
2013-06-07 11:28:45 -06:00
|
|
|
/* Create Win32 mask from pixmap shape */
|
|
|
|
ii.hbmMask =
|
|
|
|
CreateBitmap(iconSize, iconSize, planes, 1, mask);
|
2012-06-10 07:21:05 -06:00
|
|
|
|
2013-06-07 11:28:45 -06:00
|
|
|
/* Create Win32 bitmap from pixmap */
|
|
|
|
ii.hbmColor =
|
|
|
|
CreateBitmap(iconSize, iconSize, planes, bpp, image);
|
2012-06-10 07:21:05 -06:00
|
|
|
|
2013-06-07 11:28:45 -06:00
|
|
|
/* Merge Win32 mask and bitmap into icon */
|
|
|
|
hIcon = CreateIconIndirect(&ii);
|
2012-06-10 07:21:05 -06:00
|
|
|
|
2013-06-07 11:28:45 -06:00
|
|
|
/* Release Win32 mask and bitmap */
|
|
|
|
DeleteObject(ii.hbmMask);
|
|
|
|
DeleteObject(ii.hbmColor);
|
2012-06-10 07:21:05 -06:00
|
|
|
|
2013-06-07 11:28:45 -06:00
|
|
|
/* Free X mask and bitmap */
|
|
|
|
free(mask);
|
|
|
|
free(image);
|
|
|
|
free(imageMask);
|
2006-11-26 11:13:41 -07:00
|
|
|
|
2013-06-07 11:28:45 -06:00
|
|
|
if (xImageMask)
|
2017-12-08 08:01:59 -07:00
|
|
|
xcb_image_destroy(xImageMask);
|
2012-06-10 07:21:05 -06:00
|
|
|
|
2017-12-08 08:01:59 -07:00
|
|
|
xcb_image_destroy(xImageIcon);
|
|
|
|
}
|
2013-06-07 11:28:45 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-06-10 07:21:05 -06:00
|
|
|
return hIcon;
|
|
|
|
}
|
2006-11-26 11:13:41 -07:00
|
|
|
|
|
|
|
/*
|
2013-06-07 11:28:45 -06:00
|
|
|
* Change the Windows window icon
|
2006-11-26 11:13:41 -07:00
|
|
|
*/
|
|
|
|
|
|
|
|
void
|
2017-12-08 08:01:59 -07:00
|
|
|
winUpdateIcon(HWND hWnd, xcb_connection_t *conn, Window id, HICON hIconNew)
|
2006-11-26 11:13:41 -07:00
|
|
|
{
|
2012-06-10 07:21:05 -06:00
|
|
|
HICON hIcon, hIconSmall = NULL, hIconOld;
|
|
|
|
|
2017-12-08 08:01:59 -07:00
|
|
|
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 */
|
|
|
|
hIcon = winXIconToHICON(conn, id, GetSystemMetrics(SM_CXICON));
|
|
|
|
hIconSmall = winXIconToHICON(conn, id, GetSystemMetrics(SM_CXSMICON));
|
|
|
|
}
|
2012-06-10 07:21:05 -06:00
|
|
|
|
2013-06-07 11:28:45 -06:00
|
|
|
/* If we got the small, but not the large one swap them */
|
|
|
|
if (!hIcon && hIconSmall) {
|
|
|
|
hIcon = hIconSmall;
|
|
|
|
hIconSmall = NULL;
|
2012-06-10 07:21:05 -06:00
|
|
|
}
|
2013-06-07 11:28:45 -06:00
|
|
|
|
|
|
|
/* Set the large icon */
|
|
|
|
hIconOld = (HICON) SendMessage(hWnd, WM_SETICON, ICON_BIG, (LPARAM) hIcon);
|
|
|
|
/* Delete the old icon if its not the default */
|
|
|
|
winDestroyIcon(hIconOld);
|
|
|
|
|
|
|
|
/* Same for the small icon */
|
|
|
|
hIconOld =
|
|
|
|
(HICON) SendMessage(hWnd, WM_SETICON, ICON_SMALL, (LPARAM) hIconSmall);
|
|
|
|
winDestroyIcon(hIconOld);
|
2012-06-10 07:21:05 -06:00
|
|
|
}
|
2010-07-27 13:02:24 -06:00
|
|
|
|
2012-06-10 07:21:05 -06:00
|
|
|
void
|
|
|
|
winInitGlobalIcons(void)
|
|
|
|
{
|
|
|
|
int sm_cx = GetSystemMetrics(SM_CXICON);
|
|
|
|
int sm_cxsm = GetSystemMetrics(SM_CXSMICON);
|
2010-07-27 13:02:24 -06:00
|
|
|
|
2012-06-10 07:21:05 -06:00
|
|
|
/* Load default X icon in case it's not ready yet */
|
|
|
|
if (!g_hIconX) {
|
|
|
|
g_hIconX = winOverrideDefaultIcon(sm_cx);
|
|
|
|
g_hSmallIconX = winOverrideDefaultIcon(sm_cxsm);
|
|
|
|
}
|
2010-07-27 13:02:24 -06:00
|
|
|
|
2012-06-10 07:21:05 -06:00
|
|
|
if (!g_hIconX) {
|
|
|
|
g_hIconX = (HICON) LoadImage(g_hInstance,
|
|
|
|
MAKEINTRESOURCE(IDI_XWIN),
|
|
|
|
IMAGE_ICON,
|
|
|
|
GetSystemMetrics(SM_CXICON),
|
|
|
|
GetSystemMetrics(SM_CYICON), 0);
|
|
|
|
g_hSmallIconX = (HICON) LoadImage(g_hInstance,
|
|
|
|
MAKEINTRESOURCE(IDI_XWIN),
|
|
|
|
IMAGE_ICON,
|
|
|
|
GetSystemMetrics(SM_CXSMICON),
|
|
|
|
GetSystemMetrics(SM_CYSMICON),
|
|
|
|
LR_DEFAULTSIZE);
|
|
|
|
}
|
2006-11-26 11:13:41 -07:00
|
|
|
}
|
|
|
|
|
2012-06-10 07:21:05 -06:00
|
|
|
void
|
2013-06-07 11:28:45 -06:00
|
|
|
winSelectIcons(HICON * pIcon, HICON * pSmallIcon)
|
2006-11-26 11:13:41 -07:00
|
|
|
{
|
2012-06-10 07:21:05 -06:00
|
|
|
HICON hIcon, hSmallIcon;
|
|
|
|
|
|
|
|
winInitGlobalIcons();
|
|
|
|
|
2013-06-07 11:28:45 -06:00
|
|
|
/* Use default X icon */
|
|
|
|
hIcon = g_hIconX;
|
|
|
|
hSmallIcon = g_hSmallIconX;
|
2006-11-26 11:13:41 -07:00
|
|
|
|
2012-06-10 07:21:05 -06:00
|
|
|
if (pIcon)
|
|
|
|
*pIcon = hIcon;
|
|
|
|
|
|
|
|
if (pSmallIcon)
|
|
|
|
*pSmallIcon = hSmallIcon;
|
2006-11-26 11:13:41 -07:00
|
|
|
}
|
|
|
|
|
2012-06-10 07:21:05 -06:00
|
|
|
void
|
|
|
|
winDestroyIcon(HICON hIcon)
|
2006-11-26 11:13:41 -07:00
|
|
|
{
|
2012-06-10 07:21:05 -06:00
|
|
|
/* Delete the icon if its not one of the application defaults or an override */
|
|
|
|
if (hIcon &&
|
|
|
|
hIcon != g_hIconX &&
|
2014-05-02 13:27:46 -06:00
|
|
|
hIcon != g_hSmallIconX && !winIconIsOverride(hIcon))
|
2012-06-10 07:21:05 -06:00
|
|
|
DestroyIcon(hIcon);
|
2006-11-26 11:13:41 -07:00
|
|
|
}
|