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