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