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