winmultiwindowicons.c revision 35c4bbdf
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
3935c4bbdfSmrg#include <X11/Xwindows.h>
4035c4bbdfSmrg#include <X11/Xlib.h>
4135c4bbdfSmrg#include <X11/Xutil.h>
4205b261ecSmrg
4335c4bbdfSmrg#include "winresource.h"
4435c4bbdfSmrg#include "winprefs.h"
4535c4bbdfSmrg#include "winmsg.h"
4635c4bbdfSmrg#include "winmultiwindowicons.h"
4735c4bbdfSmrg#include "winglobals.h"
4805b261ecSmrg/*
4935c4bbdfSmrg * global variables
5005b261ecSmrg */
5135c4bbdfSmrgextern HINSTANCE g_hInstance;
5205b261ecSmrg
5305b261ecSmrg/*
5435c4bbdfSmrg * Scale an X icon ZPixmap into a Windoze icon bitmap
5505b261ecSmrg */
5605b261ecSmrg
5705b261ecSmrgstatic void
5835c4bbdfSmrgwinScaleXImageToWindowsIcon(int iconSize,
5935c4bbdfSmrg                            int effBPP,
6035c4bbdfSmrg                            int stride, XImage * pixmap, unsigned char *image)
6105b261ecSmrg{
6235c4bbdfSmrg    int row, column, effXBPP, effXDepth;
6335c4bbdfSmrg    unsigned char *outPtr;
6435c4bbdfSmrg    unsigned char *iconData = 0;
6535c4bbdfSmrg    int xStride;
6635c4bbdfSmrg    float factX, factY;
6735c4bbdfSmrg    int posX, posY;
6835c4bbdfSmrg    unsigned char *ptr;
6935c4bbdfSmrg    unsigned int zero;
7035c4bbdfSmrg    unsigned int color;
7135c4bbdfSmrg
7235c4bbdfSmrg    effXBPP = pixmap->bits_per_pixel;
7335c4bbdfSmrg    if (pixmap->bits_per_pixel == 15)
7435c4bbdfSmrg        effXBPP = 16;
7535c4bbdfSmrg
7635c4bbdfSmrg    effXDepth = pixmap->depth;
7735c4bbdfSmrg    if (pixmap->depth == 15)
7835c4bbdfSmrg        effXDepth = 16;
7935c4bbdfSmrg
8035c4bbdfSmrg    xStride = pixmap->bytes_per_line;
8135c4bbdfSmrg    if (stride == 0 || xStride == 0) {
8235c4bbdfSmrg        ErrorF("winScaleXBitmapToWindows - stride or xStride is zero.  "
8335c4bbdfSmrg               "Bailing.\n");
8435c4bbdfSmrg        return;
8505b261ecSmrg    }
8605b261ecSmrg
8735c4bbdfSmrg    /* Get icon data */
8835c4bbdfSmrg    iconData = (unsigned char *) pixmap->data;
8935c4bbdfSmrg
9035c4bbdfSmrg    /* Keep aspect ratio */
9135c4bbdfSmrg    factX = ((float) pixmap->width) / ((float) iconSize);
9235c4bbdfSmrg    factY = ((float) pixmap->height) / ((float) iconSize);
9335c4bbdfSmrg    if (factX > factY)
9435c4bbdfSmrg        factY = factX;
9535c4bbdfSmrg    else
9635c4bbdfSmrg        factX = factY;
9735c4bbdfSmrg
9835c4bbdfSmrg    /* Out-of-bounds, fill icon with zero */
9935c4bbdfSmrg    zero = 0;
10035c4bbdfSmrg
10135c4bbdfSmrg    for (row = 0; row < iconSize; row++) {
10235c4bbdfSmrg        outPtr = image + stride * row;
10335c4bbdfSmrg        for (column = 0; column < iconSize; column++) {
10435c4bbdfSmrg            posX = factX * column;
10535c4bbdfSmrg            posY = factY * row;
10635c4bbdfSmrg
10735c4bbdfSmrg            ptr = (unsigned char *) iconData + posY * xStride;
10835c4bbdfSmrg            if (effXBPP == 1) {
10935c4bbdfSmrg                ptr += posX / 8;
11035c4bbdfSmrg
11135c4bbdfSmrg                /* Out of X icon bounds, leave space blank */
11235c4bbdfSmrg                if (posX >= pixmap->width || posY >= pixmap->height)
11335c4bbdfSmrg                    ptr = (unsigned char *) &zero;
11435c4bbdfSmrg
11535c4bbdfSmrg                if ((*ptr) & (1 << (posX & 7)))
11635c4bbdfSmrg                    switch (effBPP) {
11735c4bbdfSmrg                    case 32:
11835c4bbdfSmrg                        *(outPtr++) = 0;
11935c4bbdfSmrg                    case 24:
12035c4bbdfSmrg                        *(outPtr++) = 0;
12135c4bbdfSmrg                    case 16:
12235c4bbdfSmrg                        *(outPtr++) = 0;
12335c4bbdfSmrg                    case 8:
12435c4bbdfSmrg                        *(outPtr++) = 0;
12535c4bbdfSmrg                        break;
12635c4bbdfSmrg                    case 1:
12735c4bbdfSmrg                        outPtr[column / 8] &= ~(1 << (7 - (column & 7)));
12835c4bbdfSmrg                        break;
12935c4bbdfSmrg                    }
13035c4bbdfSmrg                else
13135c4bbdfSmrg                    switch (effBPP) {
13235c4bbdfSmrg                    case 32:
13335c4bbdfSmrg                        *(outPtr++) = 255;
13435c4bbdfSmrg                        *(outPtr++) = 255;
13535c4bbdfSmrg                        *(outPtr++) = 255;
13635c4bbdfSmrg                        *(outPtr++) = 0;
13735c4bbdfSmrg                        break;
13835c4bbdfSmrg                    case 24:
13935c4bbdfSmrg                        *(outPtr++) = 255;
14035c4bbdfSmrg                    case 16:
14135c4bbdfSmrg                        *(outPtr++) = 255;
14235c4bbdfSmrg                    case 8:
14335c4bbdfSmrg                        *(outPtr++) = 255;
14435c4bbdfSmrg                        break;
14535c4bbdfSmrg                    case 1:
14635c4bbdfSmrg                        outPtr[column / 8] |= (1 << (7 - (column & 7)));
14735c4bbdfSmrg                        break;
14835c4bbdfSmrg                    }
14935c4bbdfSmrg            }
15035c4bbdfSmrg            else if (effXDepth == 24 || effXDepth == 32) {
15135c4bbdfSmrg                ptr += posX * (effXBPP / 8);
15235c4bbdfSmrg
15335c4bbdfSmrg                /* Out of X icon bounds, leave space blank */
15435c4bbdfSmrg                if (posX >= pixmap->width || posY >= pixmap->height)
15535c4bbdfSmrg                    ptr = (unsigned char *) &zero;
15635c4bbdfSmrg                color = (((*ptr) << 16)
15735c4bbdfSmrg                         + ((*(ptr + 1)) << 8)
15835c4bbdfSmrg                         + ((*(ptr + 2)) << 0));
15935c4bbdfSmrg                switch (effBPP) {
16035c4bbdfSmrg                case 32:
16135c4bbdfSmrg                    *(outPtr++) = *(ptr++);     /* b */
16235c4bbdfSmrg                    *(outPtr++) = *(ptr++);     /* g */
16335c4bbdfSmrg                    *(outPtr++) = *(ptr++);     /* r */
16435c4bbdfSmrg                    *(outPtr++) = (effXDepth == 32) ? *(ptr++) : 0x0;   /* alpha */
16535c4bbdfSmrg                    break;
16635c4bbdfSmrg                case 24:
16735c4bbdfSmrg                    *(outPtr++) = *(ptr++);
16835c4bbdfSmrg                    *(outPtr++) = *(ptr++);
16935c4bbdfSmrg                    *(outPtr++) = *(ptr++);
17035c4bbdfSmrg                    break;
17135c4bbdfSmrg                case 16:
17235c4bbdfSmrg                    color = ((((*ptr) >> 2) << 10)
17335c4bbdfSmrg                             + (((*(ptr + 1)) >> 2) << 5)
17435c4bbdfSmrg                             + (((*(ptr + 2)) >> 2)));
17535c4bbdfSmrg                    *(outPtr++) = (color >> 8);
17635c4bbdfSmrg                    *(outPtr++) = (color & 255);
17735c4bbdfSmrg                    break;
17835c4bbdfSmrg                case 8:
17935c4bbdfSmrg                    color = (((*ptr))) + (((*(ptr + 1)))) + (((*(ptr + 2))));
18035c4bbdfSmrg                    color /= 3;
18135c4bbdfSmrg                    *(outPtr++) = color;
18235c4bbdfSmrg                    break;
18335c4bbdfSmrg                case 1:
18435c4bbdfSmrg                    if (color)
18535c4bbdfSmrg                        outPtr[column / 8] |= (1 << (7 - (column & 7)));
18635c4bbdfSmrg                    else
18735c4bbdfSmrg                        outPtr[column / 8] &= ~(1 << (7 - (column & 7)));
18835c4bbdfSmrg                }
18935c4bbdfSmrg            }
19035c4bbdfSmrg            else if (effXDepth == 16) {
19135c4bbdfSmrg                ptr += posX * (effXBPP / 8);
19235c4bbdfSmrg
19335c4bbdfSmrg                /* Out of X icon bounds, leave space blank */
19435c4bbdfSmrg                if (posX >= pixmap->width || posY >= pixmap->height)
19535c4bbdfSmrg                    ptr = (unsigned char *) &zero;
19635c4bbdfSmrg                color = ((*ptr) << 8) + (*(ptr + 1));
19735c4bbdfSmrg                switch (effBPP) {
19835c4bbdfSmrg                case 32:
19935c4bbdfSmrg                    *(outPtr++) = (color & 31) << 2;
20035c4bbdfSmrg                    *(outPtr++) = ((color >> 5) & 31) << 2;
20135c4bbdfSmrg                    *(outPtr++) = ((color >> 10) & 31) << 2;
20235c4bbdfSmrg                    *(outPtr++) = 0;    /* resvd */
20335c4bbdfSmrg                    break;
20435c4bbdfSmrg                case 24:
20535c4bbdfSmrg                    *(outPtr++) = (color & 31) << 2;
20635c4bbdfSmrg                    *(outPtr++) = ((color >> 5) & 31) << 2;
20735c4bbdfSmrg                    *(outPtr++) = ((color >> 10) & 31) << 2;
20835c4bbdfSmrg                    break;
20935c4bbdfSmrg                case 16:
21035c4bbdfSmrg                    *(outPtr++) = *(ptr++);
21135c4bbdfSmrg                    *(outPtr++) = *(ptr++);
21235c4bbdfSmrg                    break;
21335c4bbdfSmrg                case 8:
21435c4bbdfSmrg                    *(outPtr++) = (((color & 31)
21535c4bbdfSmrg                                    + ((color >> 5) & 31)
21635c4bbdfSmrg                                    + ((color >> 10) & 31)) / 3) << 2;
21735c4bbdfSmrg                    break;
21835c4bbdfSmrg                case 1:
21935c4bbdfSmrg                    if (color)
22035c4bbdfSmrg                        outPtr[column / 8] |= (1 << (7 - (column & 7)));
22135c4bbdfSmrg                    else
22235c4bbdfSmrg                        outPtr[column / 8] &= ~(1 << (7 - (column & 7)));
22335c4bbdfSmrg                    break;
22435c4bbdfSmrg                }               /* end switch(effbpp) */
22535c4bbdfSmrg            }                   /* end if effxbpp==16) */
22635c4bbdfSmrg        }                       /* end for column */
22735c4bbdfSmrg    }                           /* end for row */
22805b261ecSmrg}
22905b261ecSmrg
2306747b715Smrgstatic HICON
23135c4bbdfSmrgNetWMToWinIconAlpha(uint32_t * icon)
2326747b715Smrg{
23335c4bbdfSmrg    int width = icon[0];
23435c4bbdfSmrg    int height = icon[1];
23535c4bbdfSmrg    uint32_t *pixels = &icon[2];
23635c4bbdfSmrg    HICON result;
23735c4bbdfSmrg    HDC hdc = GetDC(NULL);
23835c4bbdfSmrg    uint32_t *DIB_pixels;
23935c4bbdfSmrg    ICONINFO ii;
24035c4bbdfSmrg    BITMAPV4HEADER bmh = { sizeof(bmh) };
24135c4bbdfSmrg
24235c4bbdfSmrg    /* Define an ARGB pixel format used for Color+Alpha icons */
24335c4bbdfSmrg    bmh.bV4Width = width;
24435c4bbdfSmrg    bmh.bV4Height = -height;    /* Invert the image */
24535c4bbdfSmrg    bmh.bV4Planes = 1;
24635c4bbdfSmrg    bmh.bV4BitCount = 32;
24735c4bbdfSmrg    bmh.bV4V4Compression = BI_BITFIELDS;
24835c4bbdfSmrg    bmh.bV4AlphaMask = 0xFF000000;
24935c4bbdfSmrg    bmh.bV4RedMask = 0x00FF0000;
25035c4bbdfSmrg    bmh.bV4GreenMask = 0x0000FF00;
25135c4bbdfSmrg    bmh.bV4BlueMask = 0x000000FF;
25235c4bbdfSmrg
25335c4bbdfSmrg    ii.fIcon = TRUE;
25435c4bbdfSmrg    ii.xHotspot = 0;            /* ignored */
25535c4bbdfSmrg    ii.yHotspot = 0;            /* ignored */
25635c4bbdfSmrg    ii.hbmColor = CreateDIBSection(hdc, (BITMAPINFO *) &bmh,
25735c4bbdfSmrg                                   DIB_RGB_COLORS, (void **) &DIB_pixels, NULL,
25835c4bbdfSmrg                                   0);
25935c4bbdfSmrg    ReleaseDC(NULL, hdc);
26035c4bbdfSmrg
26135c4bbdfSmrg    if (!ii.hbmColor)
26235c4bbdfSmrg      return NULL;
26335c4bbdfSmrg
26435c4bbdfSmrg    ii.hbmMask = CreateBitmap(width, height, 1, 1, NULL);
26535c4bbdfSmrg    memcpy(DIB_pixels, pixels, height * width * 4);
26635c4bbdfSmrg
26735c4bbdfSmrg    /* CreateIconIndirect() traditionally required DDBitmaps */
26835c4bbdfSmrg    /* Systems from WinXP accept 32-bit ARGB DIBitmaps with full 8-bit alpha support */
26935c4bbdfSmrg    /* The icon is created with a DIB + empty DDB mask (an MS example does the same) */
27035c4bbdfSmrg    result = CreateIconIndirect(&ii);
27135c4bbdfSmrg
27235c4bbdfSmrg    DeleteObject(ii.hbmColor);
27335c4bbdfSmrg    DeleteObject(ii.hbmMask);
27435c4bbdfSmrg
27535c4bbdfSmrg    winDebug("NetWMToWinIconAlpha - %d x %d = %p\n", icon[0], icon[1], result);
27635c4bbdfSmrg    return result;
2776747b715Smrg}
2786747b715Smrg
2796747b715Smrgstatic HICON
28035c4bbdfSmrgNetWMToWinIconThreshold(uint32_t * icon)
2816747b715Smrg{
28235c4bbdfSmrg    int width = icon[0];
28335c4bbdfSmrg    int height = icon[1];
28435c4bbdfSmrg    uint32_t *pixels = &icon[2];
28535c4bbdfSmrg    int row, col;
28635c4bbdfSmrg    HICON result;
28735c4bbdfSmrg    ICONINFO ii;
28835c4bbdfSmrg
28935c4bbdfSmrg    HDC hdc = GetDC(NULL);
29035c4bbdfSmrg    HDC xorDC = CreateCompatibleDC(hdc);
29135c4bbdfSmrg    HDC andDC = CreateCompatibleDC(hdc);
29235c4bbdfSmrg
29335c4bbdfSmrg    ii.fIcon = TRUE;
29435c4bbdfSmrg    ii.xHotspot = 0;            /* ignored */
29535c4bbdfSmrg    ii.yHotspot = 0;            /* ignored */
29635c4bbdfSmrg    ii.hbmColor = CreateCompatibleBitmap(hdc, width, height);
29735c4bbdfSmrg    ii.hbmMask = CreateCompatibleBitmap(hdc, width, height);
29835c4bbdfSmrg    ReleaseDC(NULL, hdc);
29935c4bbdfSmrg    SelectObject(xorDC, ii.hbmColor);
30035c4bbdfSmrg    SelectObject(andDC, ii.hbmMask);
30135c4bbdfSmrg
30235c4bbdfSmrg    for (row = 0; row < height; row++) {
30335c4bbdfSmrg        for (col = 0; col < width; col++) {
30435c4bbdfSmrg            if ((*pixels & 0xFF000000) > 31 << 24) {    /* 31 alpha threshold, i.e. opaque above, transparent below */
30535c4bbdfSmrg                SetPixelV(xorDC, col, row,
30635c4bbdfSmrg                          RGB(((char *) pixels)[2], ((char *) pixels)[1],
30735c4bbdfSmrg                              ((char *) pixels)[0]));
30835c4bbdfSmrg                SetPixelV(andDC, col, row, RGB(0, 0, 0));       /* black mask */
30935c4bbdfSmrg            }
31035c4bbdfSmrg            else {
31135c4bbdfSmrg                SetPixelV(xorDC, col, row, RGB(0, 0, 0));
31235c4bbdfSmrg                SetPixelV(andDC, col, row, RGB(255, 255, 255)); /* white mask */
31335c4bbdfSmrg            }
31435c4bbdfSmrg            pixels++;
31535c4bbdfSmrg        }
3166747b715Smrg    }
31735c4bbdfSmrg    DeleteDC(xorDC);
31835c4bbdfSmrg    DeleteDC(andDC);
3196747b715Smrg
32035c4bbdfSmrg    result = CreateIconIndirect(&ii);
3216747b715Smrg
32235c4bbdfSmrg    DeleteObject(ii.hbmColor);
32335c4bbdfSmrg    DeleteObject(ii.hbmMask);
3246747b715Smrg
32535c4bbdfSmrg    winDebug("NetWMToWinIconThreshold - %d x %d = %p\n", icon[0], icon[1],
32635c4bbdfSmrg             result);
32735c4bbdfSmrg    return result;
3286747b715Smrg}
3296747b715Smrg
3306747b715Smrgstatic HICON
33135c4bbdfSmrgNetWMToWinIcon(int bpp, uint32_t * icon)
3326747b715Smrg{
33335c4bbdfSmrg    static Bool hasIconAlphaChannel = FALSE;
33435c4bbdfSmrg    static BOOL versionChecked = FALSE;
33535c4bbdfSmrg
33635c4bbdfSmrg    if (!versionChecked) {
33735c4bbdfSmrg        OSVERSIONINFOEX osvi = { 0 };
33835c4bbdfSmrg        ULONGLONG dwlConditionMask = 0;
33935c4bbdfSmrg
34035c4bbdfSmrg        osvi.dwOSVersionInfoSize = sizeof(osvi);
34135c4bbdfSmrg        osvi.dwMajorVersion = 5;
34235c4bbdfSmrg        osvi.dwMinorVersion = 1;
34335c4bbdfSmrg
34435c4bbdfSmrg        /* Windows versions later than XP have icon alpha channel suport, 2000 does not */
34535c4bbdfSmrg        VER_SET_CONDITION(dwlConditionMask, VER_MAJORVERSION,
34635c4bbdfSmrg                          VER_GREATER_EQUAL);
34735c4bbdfSmrg        VER_SET_CONDITION(dwlConditionMask, VER_MINORVERSION,
34835c4bbdfSmrg                          VER_GREATER_EQUAL);
34935c4bbdfSmrg        hasIconAlphaChannel =
35035c4bbdfSmrg            VerifyVersionInfo(&osvi, VER_MAJORVERSION | VER_MINORVERSION,
35135c4bbdfSmrg                              dwlConditionMask);
35235c4bbdfSmrg        versionChecked = TRUE;
35335c4bbdfSmrg
35435c4bbdfSmrg        ErrorF("OS has icon alpha channel support: %s\n",
35535c4bbdfSmrg               hasIconAlphaChannel ? "yes" : "no");
3566747b715Smrg    }
3576747b715Smrg
35835c4bbdfSmrg    if (hasIconAlphaChannel && (bpp == 32))
35935c4bbdfSmrg        return NetWMToWinIconAlpha(icon);
36035c4bbdfSmrg    else
36135c4bbdfSmrg        return NetWMToWinIconThreshold(icon);
3626747b715Smrg}
36305b261ecSmrg
36405b261ecSmrg/*
36505b261ecSmrg * Attempt to create a custom icon from the WM_HINTS bitmaps
36605b261ecSmrg */
36705b261ecSmrg
36835c4bbdfSmrgstatic
36935c4bbdfSmrg HICON
37035c4bbdfSmrgwinXIconToHICON(Display * pDisplay, Window id, int iconSize)
37105b261ecSmrg{
37235c4bbdfSmrg    unsigned char *mask, *image = NULL, *imageMask;
37335c4bbdfSmrg    unsigned char *dst, *src;
37435c4bbdfSmrg    int planes, bpp, i;
37535c4bbdfSmrg    unsigned int biggest_size = 0;
37635c4bbdfSmrg    HDC hDC;
37735c4bbdfSmrg    ICONINFO ii;
37835c4bbdfSmrg    XWMHints *hints;
37935c4bbdfSmrg    HICON hIcon = NULL;
38035c4bbdfSmrg    uint32_t *biggest_icon = NULL;
38135c4bbdfSmrg    static Atom _XA_NET_WM_ICON;
38235c4bbdfSmrg    static int generation;
38335c4bbdfSmrg    uint32_t *icon, *icon_data = NULL;
38435c4bbdfSmrg    unsigned long int size;
38535c4bbdfSmrg    Atom type;
38635c4bbdfSmrg    int format;
38735c4bbdfSmrg    unsigned long int left;
38835c4bbdfSmrg
38935c4bbdfSmrg    hDC = GetDC(GetDesktopWindow());
39035c4bbdfSmrg    planes = GetDeviceCaps(hDC, PLANES);
39135c4bbdfSmrg    bpp = GetDeviceCaps(hDC, BITSPIXEL);
39235c4bbdfSmrg    ReleaseDC(GetDesktopWindow(), hDC);
39335c4bbdfSmrg
39435c4bbdfSmrg    /* Always prefer _NET_WM_ICON icons */
39535c4bbdfSmrg    if (generation != serverGeneration) {
39635c4bbdfSmrg        generation = serverGeneration;
39735c4bbdfSmrg        _XA_NET_WM_ICON = XInternAtom(pDisplay, "_NET_WM_ICON", FALSE);
39805b261ecSmrg    }
39905b261ecSmrg
40035c4bbdfSmrg    if ((XGetWindowProperty(pDisplay, id, _XA_NET_WM_ICON,
40135c4bbdfSmrg                            0, MAXINT, FALSE,
40235c4bbdfSmrg                            AnyPropertyType, &type, &format, &size, &left,
40335c4bbdfSmrg                            (unsigned char **) &icon_data) == Success) &&
40435c4bbdfSmrg        (icon_data != NULL)) {
40535c4bbdfSmrg        for (icon = icon_data; icon < &icon_data[size] && *icon;
40635c4bbdfSmrg             icon = &icon[icon[0] * icon[1] + 2]) {
40735c4bbdfSmrg            winDebug("winXIconToHICON: %u x %u NetIcon\n", icon[0], icon[1]);
40835c4bbdfSmrg
40935c4bbdfSmrg            /* Icon data size will overflow an int and thus is bigger than the
41035c4bbdfSmrg               property can possibly be */
41135c4bbdfSmrg            if ((INT_MAX/icon[0]) < icon[1]) {
41235c4bbdfSmrg                winDebug("winXIconToHICON: _NET_WM_ICON icon data size overflow\n");
41335c4bbdfSmrg                break;
41435c4bbdfSmrg            }
41535c4bbdfSmrg
41635c4bbdfSmrg            /* Icon data size is bigger than amount of data remaining */
41735c4bbdfSmrg            if (&icon[icon[0] * icon[1] + 2] > &icon_data[size]) {
41835c4bbdfSmrg                winDebug("winXIconToHICON: _NET_WM_ICON data is malformed\n");
41935c4bbdfSmrg                break;
42035c4bbdfSmrg            }
42135c4bbdfSmrg
42235c4bbdfSmrg            /* Found an exact match to the size we require...  */
42335c4bbdfSmrg            if (icon[0] == iconSize && icon[1] == iconSize) {
42435c4bbdfSmrg                winDebug("winXIconToHICON: selected %d x %d NetIcon\n",
42535c4bbdfSmrg                         iconSize, iconSize);
42635c4bbdfSmrg                hIcon = NetWMToWinIcon(bpp, icon);
42735c4bbdfSmrg                break;
42835c4bbdfSmrg            }
42935c4bbdfSmrg            /* Otherwise, find the biggest icon and let Windows scale the size */
43035c4bbdfSmrg            else if (biggest_size < icon[0]) {
43135c4bbdfSmrg                biggest_icon = icon;
43235c4bbdfSmrg                biggest_size = icon[0];
43335c4bbdfSmrg            }
43435c4bbdfSmrg        }
43505b261ecSmrg
43635c4bbdfSmrg        if (!hIcon && biggest_icon) {
43735c4bbdfSmrg            winDebug
43835c4bbdfSmrg                ("winXIconToHICON: selected %u x %u NetIcon for scaling to %d x %d\n",
43935c4bbdfSmrg                 biggest_icon[0], biggest_icon[1], iconSize, iconSize);
44035c4bbdfSmrg
44135c4bbdfSmrg            hIcon = NetWMToWinIcon(bpp, biggest_icon);
44235c4bbdfSmrg        }
44335c4bbdfSmrg
44435c4bbdfSmrg        XFree(icon_data);
44535c4bbdfSmrg    }
44635c4bbdfSmrg
44735c4bbdfSmrg    if (!hIcon) {
44835c4bbdfSmrg        winDebug("winXIconToHICON: no suitable NetIcon\n");
44935c4bbdfSmrg
45035c4bbdfSmrg        hints = XGetWMHints(pDisplay, id);
45135c4bbdfSmrg        if (hints) {
45235c4bbdfSmrg            winDebug("winXIconToHICON: id 0x%x icon_pixmap hint 0x%x\n",
45335c4bbdfSmrg                     (unsigned int)id,
45435c4bbdfSmrg                     (unsigned int)hints->icon_pixmap);
45535c4bbdfSmrg
45635c4bbdfSmrg            if (hints->icon_pixmap) {
45735c4bbdfSmrg                Window root;
45835c4bbdfSmrg                int x, y;
45935c4bbdfSmrg                unsigned int width, height, border_width, depth;
46035c4bbdfSmrg                XImage *xImageIcon;
46135c4bbdfSmrg                XImage *xImageMask = NULL;
46235c4bbdfSmrg
46335c4bbdfSmrg                XGetGeometry(pDisplay, hints->icon_pixmap, &root, &x, &y,
46435c4bbdfSmrg                             &width, &height, &border_width, &depth);
46535c4bbdfSmrg
46635c4bbdfSmrg                xImageIcon =
46735c4bbdfSmrg                    XGetImage(pDisplay, hints->icon_pixmap, 0, 0, width, height,
46835c4bbdfSmrg                              0xFFFFFFFF, ZPixmap);
46935c4bbdfSmrg                winDebug("winXIconToHICON: id 0x%x icon Ximage 0x%p\n",
47035c4bbdfSmrg                         (unsigned int)id, xImageIcon);
47135c4bbdfSmrg
47235c4bbdfSmrg                if (hints->icon_mask)
47335c4bbdfSmrg                    xImageMask =
47435c4bbdfSmrg                        XGetImage(pDisplay, hints->icon_mask, 0, 0, width,
47535c4bbdfSmrg                                  height, 0xFFFFFFFF, ZPixmap);
47635c4bbdfSmrg
47735c4bbdfSmrg                if (xImageIcon) {
47835c4bbdfSmrg                    int effBPP, stride, maskStride;
47935c4bbdfSmrg
48035c4bbdfSmrg                    /* 15 BPP is really 16BPP as far as we care */
48135c4bbdfSmrg                    if (bpp == 15)
48235c4bbdfSmrg                        effBPP = 16;
48335c4bbdfSmrg                    else
48435c4bbdfSmrg                        effBPP = bpp;
48535c4bbdfSmrg
48635c4bbdfSmrg                    /* Need 16-bit aligned rows for DDBitmaps */
48735c4bbdfSmrg                    stride = ((iconSize * effBPP + 15) & (~15)) / 8;
48835c4bbdfSmrg
48935c4bbdfSmrg                    /* Mask is 1-bit deep */
49035c4bbdfSmrg                    maskStride = ((iconSize * 1 + 15) & (~15)) / 8;
49135c4bbdfSmrg
49235c4bbdfSmrg                    image = malloc(stride * iconSize);
49335c4bbdfSmrg                    imageMask = malloc(stride * iconSize);
49435c4bbdfSmrg                    mask = malloc(maskStride * iconSize);
49535c4bbdfSmrg
49635c4bbdfSmrg                    /* Default to a completely black mask */
49735c4bbdfSmrg                    memset(imageMask, 0, stride * iconSize);
49835c4bbdfSmrg                    memset(mask, 0, maskStride * iconSize);
49935c4bbdfSmrg
50035c4bbdfSmrg                    winScaleXImageToWindowsIcon(iconSize, effBPP, stride,
50135c4bbdfSmrg                                                xImageIcon, image);
50235c4bbdfSmrg
50335c4bbdfSmrg                    if (xImageMask) {
50435c4bbdfSmrg                        winScaleXImageToWindowsIcon(iconSize, 1, maskStride,
50535c4bbdfSmrg                                                    xImageMask, mask);
50635c4bbdfSmrg                        winScaleXImageToWindowsIcon(iconSize, effBPP, stride,
50735c4bbdfSmrg                                                    xImageMask, imageMask);
50835c4bbdfSmrg                    }
50935c4bbdfSmrg
51035c4bbdfSmrg                    /* Now we need to set all bits of the icon which are not masked */
51135c4bbdfSmrg                    /* on to 0 because Color is really an XOR, not an OR function */
51235c4bbdfSmrg                    dst = image;
51335c4bbdfSmrg                    src = imageMask;
51435c4bbdfSmrg
51535c4bbdfSmrg                    for (i = 0; i < (stride * iconSize); i++)
51635c4bbdfSmrg                        if ((*(src++)))
51735c4bbdfSmrg                            *(dst++) = 0;
51835c4bbdfSmrg                        else
51935c4bbdfSmrg                            dst++;
52035c4bbdfSmrg
52135c4bbdfSmrg                    ii.fIcon = TRUE;
52235c4bbdfSmrg                    ii.xHotspot = 0;    /* ignored */
52335c4bbdfSmrg                    ii.yHotspot = 0;    /* ignored */
52435c4bbdfSmrg
52535c4bbdfSmrg                    /* Create Win32 mask from pixmap shape */
52635c4bbdfSmrg                    ii.hbmMask =
52735c4bbdfSmrg                        CreateBitmap(iconSize, iconSize, planes, 1, mask);
52835c4bbdfSmrg
52935c4bbdfSmrg                    /* Create Win32 bitmap from pixmap */
53035c4bbdfSmrg                    ii.hbmColor =
53135c4bbdfSmrg                        CreateBitmap(iconSize, iconSize, planes, bpp, image);
53235c4bbdfSmrg
53335c4bbdfSmrg                    /* Merge Win32 mask and bitmap into icon */
53435c4bbdfSmrg                    hIcon = CreateIconIndirect(&ii);
53535c4bbdfSmrg
53635c4bbdfSmrg                    /* Release Win32 mask and bitmap */
53735c4bbdfSmrg                    DeleteObject(ii.hbmMask);
53835c4bbdfSmrg                    DeleteObject(ii.hbmColor);
53935c4bbdfSmrg
54035c4bbdfSmrg                    /* Free X mask and bitmap */
54135c4bbdfSmrg                    free(mask);
54235c4bbdfSmrg                    free(image);
54335c4bbdfSmrg                    free(imageMask);
54435c4bbdfSmrg
54535c4bbdfSmrg                    if (xImageMask)
54635c4bbdfSmrg                        XDestroyImage(xImageMask);
54735c4bbdfSmrg
54835c4bbdfSmrg                    XDestroyImage(xImageIcon);
54935c4bbdfSmrg                }
55035c4bbdfSmrg            }
55135c4bbdfSmrg            XFree(hints);
55235c4bbdfSmrg        }
55335c4bbdfSmrg    }
55435c4bbdfSmrg    return hIcon;
55535c4bbdfSmrg}
55605b261ecSmrg
55705b261ecSmrg/*
55835c4bbdfSmrg * Change the Windows window icon
55905b261ecSmrg */
56005b261ecSmrg
56105b261ecSmrg#ifdef XWIN_MULTIWINDOW
56205b261ecSmrgvoid
56335c4bbdfSmrgwinUpdateIcon(HWND hWnd, Display * pDisplay, Window id, HICON hIconNew)
56405b261ecSmrg{
56535c4bbdfSmrg    HICON hIcon, hIconSmall = NULL, hIconOld;
56635c4bbdfSmrg
56735c4bbdfSmrg    /* Start with the icon from preferences, if any */
56835c4bbdfSmrg    hIcon = hIconNew;
56935c4bbdfSmrg    hIconSmall = hIconNew;
57035c4bbdfSmrg
57135c4bbdfSmrg    /* If we still need an icon, try and get the icon from WM_HINTS */
57235c4bbdfSmrg    if (!hIcon)
57335c4bbdfSmrg        hIcon = winXIconToHICON(pDisplay, id, GetSystemMetrics(SM_CXICON));
57435c4bbdfSmrg    if (!hIconSmall)
57535c4bbdfSmrg        hIconSmall =
57635c4bbdfSmrg            winXIconToHICON(pDisplay, id, GetSystemMetrics(SM_CXSMICON));
57735c4bbdfSmrg
57835c4bbdfSmrg    /* If we got the small, but not the large one swap them */
57935c4bbdfSmrg    if (!hIcon && hIconSmall) {
58035c4bbdfSmrg        hIcon = hIconSmall;
58135c4bbdfSmrg        hIconSmall = NULL;
58235c4bbdfSmrg    }
5836747b715Smrg
58435c4bbdfSmrg    /* Set the large icon */
58535c4bbdfSmrg    hIconOld = (HICON) SendMessage(hWnd, WM_SETICON, ICON_BIG, (LPARAM) hIcon);
58635c4bbdfSmrg    /* Delete the old icon if its not the default */
58735c4bbdfSmrg    winDestroyIcon(hIconOld);
5886747b715Smrg
58935c4bbdfSmrg    /* Same for the small icon */
59035c4bbdfSmrg    hIconOld =
59135c4bbdfSmrg        (HICON) SendMessage(hWnd, WM_SETICON, ICON_SMALL, (LPARAM) hIconSmall);
59235c4bbdfSmrg    winDestroyIcon(hIconOld);
59305b261ecSmrg}
59405b261ecSmrg
59535c4bbdfSmrgvoid
59635c4bbdfSmrgwinInitGlobalIcons(void)
59705b261ecSmrg{
59835c4bbdfSmrg    int sm_cx = GetSystemMetrics(SM_CXICON);
59935c4bbdfSmrg    int sm_cxsm = GetSystemMetrics(SM_CXSMICON);
60035c4bbdfSmrg
60135c4bbdfSmrg    /* Load default X icon in case it's not ready yet */
60235c4bbdfSmrg    if (!g_hIconX) {
60335c4bbdfSmrg        g_hIconX = winOverrideDefaultIcon(sm_cx);
60435c4bbdfSmrg        g_hSmallIconX = winOverrideDefaultIcon(sm_cxsm);
60505b261ecSmrg    }
60635c4bbdfSmrg
60735c4bbdfSmrg    if (!g_hIconX) {
60835c4bbdfSmrg        g_hIconX = (HICON) LoadImage(g_hInstance,
60935c4bbdfSmrg                                     MAKEINTRESOURCE(IDI_XWIN),
61035c4bbdfSmrg                                     IMAGE_ICON,
61135c4bbdfSmrg                                     GetSystemMetrics(SM_CXICON),
61235c4bbdfSmrg                                     GetSystemMetrics(SM_CYICON), 0);
61335c4bbdfSmrg        g_hSmallIconX = (HICON) LoadImage(g_hInstance,
61435c4bbdfSmrg                                          MAKEINTRESOURCE(IDI_XWIN),
61535c4bbdfSmrg                                          IMAGE_ICON,
61635c4bbdfSmrg                                          GetSystemMetrics(SM_CXSMICON),
61735c4bbdfSmrg                                          GetSystemMetrics(SM_CYSMICON),
61835c4bbdfSmrg                                          LR_DEFAULTSIZE);
61905b261ecSmrg    }
62005b261ecSmrg}
62105b261ecSmrg
62235c4bbdfSmrgvoid
62335c4bbdfSmrgwinSelectIcons(HICON * pIcon, HICON * pSmallIcon)
62405b261ecSmrg{
62535c4bbdfSmrg    HICON hIcon, hSmallIcon;
62635c4bbdfSmrg
62735c4bbdfSmrg    winInitGlobalIcons();
62835c4bbdfSmrg
62935c4bbdfSmrg    /* Use default X icon */
63005b261ecSmrg    hIcon = g_hIconX;
63105b261ecSmrg    hSmallIcon = g_hSmallIconX;
63235c4bbdfSmrg
63335c4bbdfSmrg    if (pIcon)
63435c4bbdfSmrg        *pIcon = hIcon;
63535c4bbdfSmrg
63635c4bbdfSmrg    if (pSmallIcon)
63735c4bbdfSmrg        *pSmallIcon = hSmallIcon;
63805b261ecSmrg}
63905b261ecSmrg
64035c4bbdfSmrgvoid
64135c4bbdfSmrgwinDestroyIcon(HICON hIcon)
64205b261ecSmrg{
64335c4bbdfSmrg    /* Delete the icon if its not one of the application defaults or an override */
64435c4bbdfSmrg    if (hIcon &&
64535c4bbdfSmrg        hIcon != g_hIconX &&
64635c4bbdfSmrg        hIcon != g_hSmallIconX && !winIconIsOverride(hIcon))
64735c4bbdfSmrg        DestroyIcon(hIcon);
64805b261ecSmrg}
64905b261ecSmrg#endif
650