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