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 */
56extern HINSTANCE g_hInstance;
57
58/*
59 * Scale an X icon ZPixmap into a Windoze icon bitmap
60 */
61
62static void
63winScaleXImageToWindowsIcon(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
235static HICON
236NetWMToWinIconAlpha(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
284static HICON
285NetWMToWinIconThreshold(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
335static HICON
336NetWMToWinIcon(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
373static
374HICON
375winXIconToHICON(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
583void
584winUpdateIcon(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
618void
619winInitGlobalIcons(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
645void
646winSelectIcons(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
663void
664winDestroyIcon(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}
672