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
winScaleXImageToWindowsIcon(int iconSize,int effBPP,int stride,xcb_image_t * pixmap,unsigned char * image)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
NetWMToWinIconAlpha(uint32_t * icon)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
NetWMToWinIconThreshold(uint32_t * icon)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
NetWMToWinIcon(int bpp,uint32_t * icon)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
winXIconToHICON(xcb_connection_t * conn,xcb_window_t id,int iconSize)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
winUpdateIcon(HWND hWnd,xcb_connection_t * conn,xcb_window_t id,HICON hIconNew)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
winInitGlobalIcons(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
winSelectIcons(HICON * pIcon,HICON * pSmallIcon)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
winDestroyIcon(HICON hIcon)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 }
672