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