xserver

xserver with xephyr scale patch
git clone https://git.neptards.moe/u3shit/xserver.git
Log | Files | Refs | README | LICENSE

winmultiwindowicons.c (23010B)


      1 /*
      2  *Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved.
      3  *
      4  *Permission is hereby granted, free of charge, to any person obtaining
      5  * a copy of this software and associated documentation files (the
      6  *"Software"), to deal in the Software without restriction, including
      7  *without limitation the rights to use, copy, modify, merge, publish,
      8  *distribute, sublicense, and/or sell copies of the Software, and to
      9  *permit persons to whom the Software is furnished to do so, subject to
     10  *the following conditions:
     11  *
     12  *The above copyright notice and this permission notice shall be
     13  *included in all copies or substantial portions of the Software.
     14  *
     15  *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
     16  *EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     17  *MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
     18  *NONINFRINGEMENT. IN NO EVENT SHALL THE XFREE86 PROJECT BE LIABLE FOR
     19  *ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
     20  *CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
     21  *WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     22  *
     23  *Except as contained in this notice, the name of the XFree86 Project
     24  *shall not be used in advertising or otherwise to promote the sale, use
     25  *or other dealings in this Software without prior written authorization
     26  *from the XFree86 Project.
     27  *
     28  * Authors:	Earle F. Philhower, III
     29  */
     30 
     31 #ifdef HAVE_XWIN_CONFIG_H
     32 #include <xwin-config.h>
     33 #endif
     34 
     35 #ifndef WINVER
     36 #define WINVER 0x0500
     37 #endif
     38 
     39 #include <limits.h>
     40 #include <stdbool.h>
     41 
     42 #include <X11/Xwindows.h>
     43 #include <xcb/xcb.h>
     44 #include <xcb/xcb_icccm.h>
     45 #include <xcb/xcb_image.h>
     46 
     47 #include "winresource.h"
     48 #include "winprefs.h"
     49 #include "winmsg.h"
     50 #include "winmultiwindowicons.h"
     51 #include "winglobals.h"
     52 
     53 /*
     54  * global variables
     55  */
     56 extern HINSTANCE g_hInstance;
     57 
     58 /*
     59  * Scale an X icon ZPixmap into a Windoze icon bitmap
     60  */
     61 
     62 static void
     63 winScaleXImageToWindowsIcon(int iconSize,
     64                             int effBPP,
     65                             int stride, xcb_image_t* pixmap, unsigned char *image)
     66 {
     67     int row, column, effXBPP, effXDepth;
     68     unsigned char *outPtr;
     69     unsigned char *iconData = 0;
     70     int xStride;
     71     float factX, factY;
     72     int posX, posY;
     73     unsigned char *ptr;
     74     unsigned int zero;
     75     unsigned int color;
     76 
     77     effXBPP = pixmap->bpp;
     78     if (pixmap->bpp == 15)
     79         effXBPP = 16;
     80 
     81     effXDepth = pixmap->depth;
     82     if (pixmap->depth == 15)
     83         effXDepth = 16;
     84 
     85     xStride = pixmap->stride;
     86     if (stride == 0 || xStride == 0) {
     87         ErrorF("winScaleXBitmapToWindows - stride or xStride is zero.  "
     88                "Bailing.\n");
     89         return;
     90     }
     91 
     92     /* Get icon data */
     93     iconData = (unsigned char *) pixmap->data;
     94 
     95     /* Keep aspect ratio */
     96     factX = ((float) pixmap->width) / ((float) iconSize);
     97     factY = ((float) pixmap->height) / ((float) iconSize);
     98     if (factX > factY)
     99         factY = factX;
    100     else
    101         factX = factY;
    102 
    103     /* Out-of-bounds, fill icon with zero */
    104     zero = 0;
    105 
    106     for (row = 0; row < iconSize; row++) {
    107         outPtr = image + stride * row;
    108         for (column = 0; column < iconSize; column++) {
    109             posX = factX * column;
    110             posY = factY * row;
    111 
    112             ptr = (unsigned char *) iconData + posY * xStride;
    113             if (effXBPP == 1) {
    114                 ptr += posX / 8;
    115 
    116                 /* Out of X icon bounds, leave space blank */
    117                 if (posX >= pixmap->width || posY >= pixmap->height)
    118                     ptr = (unsigned char *) &zero;
    119 
    120                 if ((*ptr) & (1 << (posX & 7)))
    121                     switch (effBPP) {
    122                     case 32:
    123                         *(outPtr++) = 0;
    124                     case 24:
    125                         *(outPtr++) = 0;
    126                     case 16:
    127                         *(outPtr++) = 0;
    128                     case 8:
    129                         *(outPtr++) = 0;
    130                         break;
    131                     case 1:
    132                         outPtr[column / 8] &= ~(1 << (7 - (column & 7)));
    133                         break;
    134                     }
    135                 else
    136                     switch (effBPP) {
    137                     case 32:
    138                         *(outPtr++) = 255;
    139                         *(outPtr++) = 255;
    140                         *(outPtr++) = 255;
    141                         *(outPtr++) = 0;
    142                         break;
    143                     case 24:
    144                         *(outPtr++) = 255;
    145                     case 16:
    146                         *(outPtr++) = 255;
    147                     case 8:
    148                         *(outPtr++) = 255;
    149                         break;
    150                     case 1:
    151                         outPtr[column / 8] |= (1 << (7 - (column & 7)));
    152                         break;
    153                     }
    154             }
    155             else if (effXDepth == 24 || effXDepth == 32) {
    156                 ptr += posX * (effXBPP / 8);
    157 
    158                 /* Out of X icon bounds, leave space blank */
    159                 if (posX >= pixmap->width || posY >= pixmap->height)
    160                     ptr = (unsigned char *) &zero;
    161                 color = (((*ptr) << 16)
    162                          + ((*(ptr + 1)) << 8)
    163                          + ((*(ptr + 2)) << 0));
    164                 switch (effBPP) {
    165                 case 32:
    166                     *(outPtr++) = *(ptr++);     /* b */
    167                     *(outPtr++) = *(ptr++);     /* g */
    168                     *(outPtr++) = *(ptr++);     /* r */
    169                     *(outPtr++) = (effXDepth == 32) ? *(ptr++) : 0x0;   /* alpha */
    170                     break;
    171                 case 24:
    172                     *(outPtr++) = *(ptr++);
    173                     *(outPtr++) = *(ptr++);
    174                     *(outPtr++) = *(ptr++);
    175                     break;
    176                 case 16:
    177                     color = ((((*ptr) >> 2) << 10)
    178                              + (((*(ptr + 1)) >> 2) << 5)
    179                              + (((*(ptr + 2)) >> 2)));
    180                     *(outPtr++) = (color >> 8);
    181                     *(outPtr++) = (color & 255);
    182                     break;
    183                 case 8:
    184                     color = (((*ptr))) + (((*(ptr + 1)))) + (((*(ptr + 2))));
    185                     color /= 3;
    186                     *(outPtr++) = color;
    187                     break;
    188                 case 1:
    189                     if (color)
    190                         outPtr[column / 8] |= (1 << (7 - (column & 7)));
    191                     else
    192                         outPtr[column / 8] &= ~(1 << (7 - (column & 7)));
    193                 }
    194             }
    195             else if (effXDepth == 16) {
    196                 ptr += posX * (effXBPP / 8);
    197 
    198                 /* Out of X icon bounds, leave space blank */
    199                 if (posX >= pixmap->width || posY >= pixmap->height)
    200                     ptr = (unsigned char *) &zero;
    201                 color = ((*ptr) << 8) + (*(ptr + 1));
    202                 switch (effBPP) {
    203                 case 32:
    204                     *(outPtr++) = (color & 31) << 2;
    205                     *(outPtr++) = ((color >> 5) & 31) << 2;
    206                     *(outPtr++) = ((color >> 10) & 31) << 2;
    207                     *(outPtr++) = 0;    /* resvd */
    208                     break;
    209                 case 24:
    210                     *(outPtr++) = (color & 31) << 2;
    211                     *(outPtr++) = ((color >> 5) & 31) << 2;
    212                     *(outPtr++) = ((color >> 10) & 31) << 2;
    213                     break;
    214                 case 16:
    215                     *(outPtr++) = *(ptr++);
    216                     *(outPtr++) = *(ptr++);
    217                     break;
    218                 case 8:
    219                     *(outPtr++) = (((color & 31)
    220                                     + ((color >> 5) & 31)
    221                                     + ((color >> 10) & 31)) / 3) << 2;
    222                     break;
    223                 case 1:
    224                     if (color)
    225                         outPtr[column / 8] |= (1 << (7 - (column & 7)));
    226                     else
    227                         outPtr[column / 8] &= ~(1 << (7 - (column & 7)));
    228                     break;
    229                 }               /* end switch(effbpp) */
    230             }                   /* end if effxbpp==16) */
    231         }                       /* end for column */
    232     }                           /* end for row */
    233 }
    234 
    235 static HICON
    236 NetWMToWinIconAlpha(uint32_t * icon)
    237 {
    238     int width = icon[0];
    239     int height = icon[1];
    240     uint32_t *pixels = &icon[2];
    241     HICON result;
    242     HDC hdc = GetDC(NULL);
    243     uint32_t *DIB_pixels;
    244     ICONINFO ii;
    245     BITMAPV4HEADER bmh = { sizeof(bmh) };
    246 
    247     /* Define an ARGB pixel format used for Color+Alpha icons */
    248     bmh.bV4Width = width;
    249     bmh.bV4Height = -height;    /* Invert the image */
    250     bmh.bV4Planes = 1;
    251     bmh.bV4BitCount = 32;
    252     bmh.bV4V4Compression = BI_BITFIELDS;
    253     bmh.bV4AlphaMask = 0xFF000000;
    254     bmh.bV4RedMask = 0x00FF0000;
    255     bmh.bV4GreenMask = 0x0000FF00;
    256     bmh.bV4BlueMask = 0x000000FF;
    257 
    258     ii.fIcon = TRUE;
    259     ii.xHotspot = 0;            /* ignored */
    260     ii.yHotspot = 0;            /* ignored */
    261     ii.hbmColor = CreateDIBSection(hdc, (BITMAPINFO *) &bmh,
    262                                    DIB_RGB_COLORS, (void **) &DIB_pixels, NULL,
    263                                    0);
    264     ReleaseDC(NULL, hdc);
    265 
    266     if (!ii.hbmColor)
    267       return NULL;
    268 
    269     ii.hbmMask = CreateBitmap(width, height, 1, 1, NULL);
    270     memcpy(DIB_pixels, pixels, height * width * 4);
    271 
    272     /* CreateIconIndirect() traditionally required DDBitmaps */
    273     /* Systems from WinXP accept 32-bit ARGB DIBitmaps with full 8-bit alpha support */
    274     /* The icon is created with a DIB + empty DDB mask (an MS example does the same) */
    275     result = CreateIconIndirect(&ii);
    276 
    277     DeleteObject(ii.hbmColor);
    278     DeleteObject(ii.hbmMask);
    279 
    280     winDebug("NetWMToWinIconAlpha - %d x %d = %p\n", icon[0], icon[1], result);
    281     return result;
    282 }
    283 
    284 static HICON
    285 NetWMToWinIconThreshold(uint32_t * icon)
    286 {
    287     int width = icon[0];
    288     int height = icon[1];
    289     uint32_t *pixels = &icon[2];
    290     int row, col;
    291     HICON result;
    292     ICONINFO ii;
    293 
    294     HDC hdc = GetDC(NULL);
    295     HDC xorDC = CreateCompatibleDC(hdc);
    296     HDC andDC = CreateCompatibleDC(hdc);
    297 
    298     ii.fIcon = TRUE;
    299     ii.xHotspot = 0;            /* ignored */
    300     ii.yHotspot = 0;            /* ignored */
    301     ii.hbmColor = CreateCompatibleBitmap(hdc, width, height);
    302     ii.hbmMask = CreateCompatibleBitmap(hdc, width, height);
    303     ReleaseDC(NULL, hdc);
    304     SelectObject(xorDC, ii.hbmColor);
    305     SelectObject(andDC, ii.hbmMask);
    306 
    307     for (row = 0; row < height; row++) {
    308         for (col = 0; col < width; col++) {
    309             if ((*pixels & 0xFF000000) > 31 << 24) {    /* 31 alpha threshold, i.e. opaque above, transparent below */
    310                 SetPixelV(xorDC, col, row,
    311                           RGB(((char *) pixels)[2], ((char *) pixels)[1],
    312                               ((char *) pixels)[0]));
    313                 SetPixelV(andDC, col, row, RGB(0, 0, 0));       /* black mask */
    314             }
    315             else {
    316                 SetPixelV(xorDC, col, row, RGB(0, 0, 0));
    317                 SetPixelV(andDC, col, row, RGB(255, 255, 255)); /* white mask */
    318             }
    319             pixels++;
    320         }
    321     }
    322     DeleteDC(xorDC);
    323     DeleteDC(andDC);
    324 
    325     result = CreateIconIndirect(&ii);
    326 
    327     DeleteObject(ii.hbmColor);
    328     DeleteObject(ii.hbmMask);
    329 
    330     winDebug("NetWMToWinIconThreshold - %d x %d = %p\n", icon[0], icon[1],
    331              result);
    332     return result;
    333 }
    334 
    335 static HICON
    336 NetWMToWinIcon(int bpp, uint32_t * icon)
    337 {
    338     static bool hasIconAlphaChannel = FALSE;
    339     static bool versionChecked = FALSE;
    340 
    341     if (!versionChecked) {
    342         OSVERSIONINFOEX osvi = { 0 };
    343         ULONGLONG dwlConditionMask = 0;
    344 
    345         osvi.dwOSVersionInfoSize = sizeof(osvi);
    346         osvi.dwMajorVersion = 5;
    347         osvi.dwMinorVersion = 1;
    348 
    349         /* Windows versions later than XP have icon alpha channel support, 2000 does not */
    350         VER_SET_CONDITION(dwlConditionMask, VER_MAJORVERSION,
    351                           VER_GREATER_EQUAL);
    352         VER_SET_CONDITION(dwlConditionMask, VER_MINORVERSION,
    353                           VER_GREATER_EQUAL);
    354         hasIconAlphaChannel =
    355             VerifyVersionInfo(&osvi, VER_MAJORVERSION | VER_MINORVERSION,
    356                               dwlConditionMask);
    357         versionChecked = TRUE;
    358 
    359         ErrorF("OS has icon alpha channel support: %s\n",
    360                hasIconAlphaChannel ? "yes" : "no");
    361     }
    362 
    363     if (hasIconAlphaChannel && (bpp == 32))
    364         return NetWMToWinIconAlpha(icon);
    365     else
    366         return NetWMToWinIconThreshold(icon);
    367 }
    368 
    369 /*
    370  * Attempt to create a custom icon from the WM_HINTS bitmaps
    371  */
    372 
    373 static
    374 HICON
    375 winXIconToHICON(xcb_connection_t *conn, xcb_window_t id, int iconSize)
    376 {
    377     unsigned char *mask, *image = NULL, *imageMask;
    378     unsigned char *dst, *src;
    379     int planes, bpp, i;
    380     unsigned int biggest_size = 0;
    381     HDC hDC;
    382     ICONINFO ii;
    383     xcb_icccm_wm_hints_t hints;
    384     HICON hIcon = NULL;
    385     uint32_t *biggest_icon = NULL;
    386     static xcb_atom_t _XA_NET_WM_ICON;
    387     static int generation;
    388     uint32_t *icon, *icon_data = NULL;
    389     unsigned long int size;
    390 
    391     hDC = GetDC(GetDesktopWindow());
    392     planes = GetDeviceCaps(hDC, PLANES);
    393     bpp = GetDeviceCaps(hDC, BITSPIXEL);
    394     ReleaseDC(GetDesktopWindow(), hDC);
    395 
    396     /* Always prefer _NET_WM_ICON icons */
    397     if (generation != serverGeneration) {
    398         xcb_intern_atom_reply_t *atom_reply;
    399         xcb_intern_atom_cookie_t atom_cookie;
    400         const char *atomName = "_NET_WM_ICON";
    401 
    402         generation = serverGeneration;
    403 
    404         _XA_NET_WM_ICON = XCB_NONE;
    405 
    406         atom_cookie = xcb_intern_atom(conn, 0, strlen(atomName), atomName);
    407         atom_reply = xcb_intern_atom_reply(conn, atom_cookie, NULL);
    408         if (atom_reply) {
    409           _XA_NET_WM_ICON = atom_reply->atom;
    410           free(atom_reply);
    411         }
    412     }
    413 
    414     {
    415         xcb_get_property_cookie_t cookie = xcb_get_property(conn, FALSE, id, _XA_NET_WM_ICON, XCB_ATOM_CARDINAL, 0L, INT_MAX);
    416         xcb_get_property_reply_t *reply =  xcb_get_property_reply(conn, cookie, NULL);
    417 
    418         if (reply &&
    419             ((icon_data = xcb_get_property_value(reply)) != NULL)) {
    420           size = xcb_get_property_value_length(reply)/sizeof(uint32_t);
    421           for (icon = icon_data; icon < &icon_data[size] && *icon;
    422                icon = &icon[icon[0] * icon[1] + 2]) {
    423             winDebug("winXIconToHICON: %u x %u NetIcon\n", icon[0], icon[1]);
    424 
    425             /* Icon data size will overflow an int and thus is bigger than the
    426                property can possibly be */
    427             if ((INT_MAX/icon[0]) < icon[1]) {
    428                 winDebug("winXIconToHICON: _NET_WM_ICON icon data size overflow\n");
    429                 break;
    430             }
    431 
    432             /* Icon data size is bigger than amount of data remaining */
    433             if (&icon[icon[0] * icon[1] + 2] > &icon_data[size]) {
    434                 winDebug("winXIconToHICON: _NET_WM_ICON data is malformed\n");
    435                 break;
    436             }
    437 
    438             /* Found an exact match to the size we require...  */
    439             if (icon[0] == iconSize && icon[1] == iconSize) {
    440                 winDebug("winXIconToHICON: selected %d x %d NetIcon\n",
    441                          iconSize, iconSize);
    442                 hIcon = NetWMToWinIcon(bpp, icon);
    443                 break;
    444             }
    445             /* Otherwise, find the biggest icon and let Windows scale the size */
    446             else if (biggest_size < icon[0]) {
    447                 biggest_icon = icon;
    448                 biggest_size = icon[0];
    449             }
    450         }
    451 
    452         if (!hIcon && biggest_icon) {
    453             winDebug
    454                 ("winXIconToHICON: selected %u x %u NetIcon for scaling to %d x %d\n",
    455                  biggest_icon[0], biggest_icon[1], iconSize, iconSize);
    456 
    457             hIcon = NetWMToWinIcon(bpp, biggest_icon);
    458         }
    459 
    460         free(reply);
    461       }
    462     }
    463 
    464     if (!hIcon) {
    465         xcb_get_property_cookie_t wm_hints_cookie;
    466 
    467         winDebug("winXIconToHICON: no suitable NetIcon\n");
    468 
    469         wm_hints_cookie = xcb_icccm_get_wm_hints(conn, id);
    470         if (xcb_icccm_get_wm_hints_reply(conn, wm_hints_cookie, &hints, NULL)) {
    471             winDebug("winXIconToHICON: id 0x%x icon_pixmap hint 0x%x\n",
    472                      (unsigned int)id,
    473                      (unsigned int)hints.icon_pixmap);
    474 
    475             if (hints.icon_pixmap) {
    476                 unsigned int width, height;
    477                 xcb_image_t *xImageIcon;
    478                 xcb_image_t *xImageMask = NULL;
    479 
    480                 xcb_get_geometry_cookie_t geom_cookie = xcb_get_geometry(conn, hints.icon_pixmap);
    481                 xcb_get_geometry_reply_t *geom_reply = xcb_get_geometry_reply(conn, geom_cookie, NULL);
    482 
    483                 if (geom_reply) {
    484                   width = geom_reply->width;
    485                   height = geom_reply->height;
    486 
    487                   xImageIcon = xcb_image_get(conn, hints.icon_pixmap,
    488                                              0, 0, width, height,
    489                                              0xFFFFFF, XCB_IMAGE_FORMAT_Z_PIXMAP);
    490 
    491                   winDebug("winXIconToHICON: id 0x%x icon Ximage 0x%p\n",
    492                            (unsigned int)id, xImageIcon);
    493 
    494                   if (hints.icon_mask)
    495                     xImageMask = xcb_image_get(conn, hints.icon_mask,
    496                                                0, 0, width, height,
    497                                                0xFFFFFFFF, XCB_IMAGE_FORMAT_Z_PIXMAP);
    498 
    499                   if (xImageIcon) {
    500                     int effBPP, stride, maskStride;
    501 
    502                     /* 15 BPP is really 16BPP as far as we care */
    503                     if (bpp == 15)
    504                         effBPP = 16;
    505                     else
    506                         effBPP = bpp;
    507 
    508                     /* Need 16-bit aligned rows for DDBitmaps */
    509                     stride = ((iconSize * effBPP + 15) & (~15)) / 8;
    510 
    511                     /* Mask is 1-bit deep */
    512                     maskStride = ((iconSize * 1 + 15) & (~15)) / 8;
    513 
    514                     image = malloc(stride * iconSize);
    515                     imageMask = malloc(stride * iconSize);
    516                     mask = malloc(maskStride * iconSize);
    517 
    518                     /* Default to a completely black mask */
    519                     memset(imageMask, 0, stride * iconSize);
    520                     memset(mask, 0, maskStride * iconSize);
    521 
    522                     winScaleXImageToWindowsIcon(iconSize, effBPP, stride,
    523                                                 xImageIcon, image);
    524 
    525                     if (xImageMask) {
    526                         winScaleXImageToWindowsIcon(iconSize, 1, maskStride,
    527                                                     xImageMask, mask);
    528                         winScaleXImageToWindowsIcon(iconSize, effBPP, stride,
    529                                                     xImageMask, imageMask);
    530                     }
    531 
    532                     /* Now we need to set all bits of the icon which are not masked */
    533                     /* on to 0 because Color is really an XOR, not an OR function */
    534                     dst = image;
    535                     src = imageMask;
    536 
    537                     for (i = 0; i < (stride * iconSize); i++)
    538                         if ((*(src++)))
    539                             *(dst++) = 0;
    540                         else
    541                             dst++;
    542 
    543                     ii.fIcon = TRUE;
    544                     ii.xHotspot = 0;    /* ignored */
    545                     ii.yHotspot = 0;    /* ignored */
    546 
    547                     /* Create Win32 mask from pixmap shape */
    548                     ii.hbmMask =
    549                         CreateBitmap(iconSize, iconSize, planes, 1, mask);
    550 
    551                     /* Create Win32 bitmap from pixmap */
    552                     ii.hbmColor =
    553                         CreateBitmap(iconSize, iconSize, planes, bpp, image);
    554 
    555                     /* Merge Win32 mask and bitmap into icon */
    556                     hIcon = CreateIconIndirect(&ii);
    557 
    558                     /* Release Win32 mask and bitmap */
    559                     DeleteObject(ii.hbmMask);
    560                     DeleteObject(ii.hbmColor);
    561 
    562                     /* Free X mask and bitmap */
    563                     free(mask);
    564                     free(image);
    565                     free(imageMask);
    566 
    567                     if (xImageMask)
    568                       xcb_image_destroy(xImageMask);
    569 
    570                     xcb_image_destroy(xImageIcon);
    571                   }
    572                 }
    573             }
    574         }
    575     }
    576     return hIcon;
    577 }
    578 
    579 /*
    580  * Change the Windows window icon
    581  */
    582 
    583 void
    584 winUpdateIcon(HWND hWnd, xcb_connection_t *conn, xcb_window_t id, HICON hIconNew)
    585 {
    586     HICON hIcon, hIconSmall = NULL, hIconOld;
    587 
    588     if (hIconNew)
    589       {
    590         /* Start with the icon from preferences, if any */
    591         hIcon = hIconNew;
    592         hIconSmall = hIconNew;
    593       }
    594     else
    595       {
    596         /* If we still need an icon, try and get the icon from WM_HINTS */
    597         hIcon = winXIconToHICON(conn, id, GetSystemMetrics(SM_CXICON));
    598         hIconSmall = winXIconToHICON(conn, id, GetSystemMetrics(SM_CXSMICON));
    599       }
    600 
    601     /* If we got the small, but not the large one swap them */
    602     if (!hIcon && hIconSmall) {
    603         hIcon = hIconSmall;
    604         hIconSmall = NULL;
    605     }
    606 
    607     /* Set the large icon */
    608     hIconOld = (HICON) SendMessage(hWnd, WM_SETICON, ICON_BIG, (LPARAM) hIcon);
    609     /* Delete the old icon if its not the default */
    610     winDestroyIcon(hIconOld);
    611 
    612     /* Same for the small icon */
    613     hIconOld =
    614         (HICON) SendMessage(hWnd, WM_SETICON, ICON_SMALL, (LPARAM) hIconSmall);
    615     winDestroyIcon(hIconOld);
    616 }
    617 
    618 void
    619 winInitGlobalIcons(void)
    620 {
    621     int sm_cx = GetSystemMetrics(SM_CXICON);
    622     int sm_cxsm = GetSystemMetrics(SM_CXSMICON);
    623 
    624     /* Load default X icon in case it's not ready yet */
    625     if (!g_hIconX) {
    626         g_hIconX = winOverrideDefaultIcon(sm_cx);
    627         g_hSmallIconX = winOverrideDefaultIcon(sm_cxsm);
    628     }
    629 
    630     if (!g_hIconX) {
    631         g_hIconX = (HICON) LoadImage(g_hInstance,
    632                                      MAKEINTRESOURCE(IDI_XWIN),
    633                                      IMAGE_ICON,
    634                                      GetSystemMetrics(SM_CXICON),
    635                                      GetSystemMetrics(SM_CYICON), 0);
    636         g_hSmallIconX = (HICON) LoadImage(g_hInstance,
    637                                           MAKEINTRESOURCE(IDI_XWIN),
    638                                           IMAGE_ICON,
    639                                           GetSystemMetrics(SM_CXSMICON),
    640                                           GetSystemMetrics(SM_CYSMICON),
    641                                           LR_DEFAULTSIZE);
    642     }
    643 }
    644 
    645 void
    646 winSelectIcons(HICON * pIcon, HICON * pSmallIcon)
    647 {
    648     HICON hIcon, hSmallIcon;
    649 
    650     winInitGlobalIcons();
    651 
    652     /* Use default X icon */
    653     hIcon = g_hIconX;
    654     hSmallIcon = g_hSmallIconX;
    655 
    656     if (pIcon)
    657         *pIcon = hIcon;
    658 
    659     if (pSmallIcon)
    660         *pSmallIcon = hSmallIcon;
    661 }
    662 
    663 void
    664 winDestroyIcon(HICON hIcon)
    665 {
    666     /* Delete the icon if its not one of the application defaults or an override */
    667     if (hIcon &&
    668         hIcon != g_hIconX &&
    669         hIcon != g_hSmallIconX && !winIconIsOverride(hIcon))
    670         DestroyIcon(hIcon);
    671 }