2 *Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved.
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:
12 *The above copyright notice and this permission notice shall be
13 *included in all copies or substantial portions of the Software.
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.
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.
28 * Authors: Earle F. Philhower, III
31 #ifdef HAVE_XWIN_CONFIG_H
32 #include <xwin-config.h>
39 #include <X11/Xwindows.h>
41 #include <X11/Xutil.h>
43 #include "winresource.h"
46 #include "winmultiwindowicons.h"
47 #include "winglobals.h"
51 extern HINSTANCE g_hInstance
;
54 * Scale an X icon ZPixmap into a Windoze icon bitmap
58 winScaleXImageToWindowsIcon(int iconSize
,
60 int stride
, XImage
* pixmap
, unsigned char *image
)
62 int row
, column
, effXBPP
, effXDepth
;
63 unsigned char *outPtr
;
64 unsigned char *iconData
= 0;
72 effXBPP
= pixmap
->bits_per_pixel
;
73 if (pixmap
->bits_per_pixel
== 15)
76 effXDepth
= pixmap
->depth
;
77 if (pixmap
->depth
== 15)
80 xStride
= pixmap
->bytes_per_line
;
81 if (stride
== 0 || xStride
== 0) {
82 ErrorF("winScaleXBitmapToWindows - stride or xStride is zero. "
88 iconData
= (unsigned char *) pixmap
->data
;
90 /* Keep aspect ratio */
91 factX
= ((float) pixmap
->width
) / ((float) iconSize
);
92 factY
= ((float) pixmap
->height
) / ((float) iconSize
);
98 /* Out-of-bounds, fill icon with zero */
101 for (row
= 0; row
< iconSize
; row
++) {
102 outPtr
= image
+ stride
* row
;
103 for (column
= 0; column
< iconSize
; column
++) {
104 posX
= factX
* column
;
107 ptr
= (unsigned char *) iconData
+ posY
* xStride
;
111 /* Out of X icon bounds, leave space blank */
112 if (posX
>= pixmap
->width
|| posY
>= pixmap
->height
)
113 ptr
= (unsigned char *) &zero
;
115 if ((*ptr
) & (1 << (posX
& 7)))
127 outPtr
[column
/ 8] &= ~(1 << (7 - (column
& 7)));
146 outPtr
[column
/ 8] |= (1 << (7 - (column
& 7)));
150 else if (effXDepth
== 24 || effXDepth
== 32) {
151 ptr
+= posX
* (effXBPP
/ 8);
153 /* Out of X icon bounds, leave space blank */
154 if (posX
>= pixmap
->width
|| posY
>= pixmap
->height
)
155 ptr
= (unsigned char *) &zero
;
156 color
= (((*ptr
) << 16)
157 + ((*(ptr
+ 1)) << 8)
158 + ((*(ptr
+ 2)) << 0));
161 *(outPtr
++) = *(ptr
++); /* b */
162 *(outPtr
++) = *(ptr
++); /* g */
163 *(outPtr
++) = *(ptr
++); /* r */
164 *(outPtr
++) = (effXDepth
== 32) ? *(ptr
++) : 0x0; /* alpha */
167 *(outPtr
++) = *(ptr
++);
168 *(outPtr
++) = *(ptr
++);
169 *(outPtr
++) = *(ptr
++);
172 color
= ((((*ptr
) >> 2) << 10)
173 + (((*(ptr
+ 1)) >> 2) << 5)
174 + (((*(ptr
+ 2)) >> 2)));
175 *(outPtr
++) = (color
>> 8);
176 *(outPtr
++) = (color
& 255);
179 color
= (((*ptr
))) + (((*(ptr
+ 1)))) + (((*(ptr
+ 2))));
185 outPtr
[column
/ 8] |= (1 << (7 - (column
& 7)));
187 outPtr
[column
/ 8] &= ~(1 << (7 - (column
& 7)));
190 else if (effXDepth
== 16) {
191 ptr
+= posX
* (effXBPP
/ 8);
193 /* Out of X icon bounds, leave space blank */
194 if (posX
>= pixmap
->width
|| posY
>= pixmap
->height
)
195 ptr
= (unsigned char *) &zero
;
196 color
= ((*ptr
) << 8) + (*(ptr
+ 1));
199 *(outPtr
++) = (color
& 31) << 2;
200 *(outPtr
++) = ((color
>> 5) & 31) << 2;
201 *(outPtr
++) = ((color
>> 10) & 31) << 2;
202 *(outPtr
++) = 0; /* resvd */
205 *(outPtr
++) = (color
& 31) << 2;
206 *(outPtr
++) = ((color
>> 5) & 31) << 2;
207 *(outPtr
++) = ((color
>> 10) & 31) << 2;
210 *(outPtr
++) = *(ptr
++);
211 *(outPtr
++) = *(ptr
++);
214 *(outPtr
++) = (((color
& 31)
215 + ((color
>> 5) & 31)
216 + ((color
>> 10) & 31)) / 3) << 2;
220 outPtr
[column
/ 8] |= (1 << (7 - (column
& 7)));
222 outPtr
[column
/ 8] &= ~(1 << (7 - (column
& 7)));
224 } /* end switch(effbpp) */
225 } /* end if effxbpp==16) */
226 } /* end for column */
231 NetWMToWinIconAlpha(uint32_t * icon
)
234 int height
= icon
[1];
235 uint32_t *pixels
= &icon
[2];
237 HDC hdc
= GetDC(NULL
);
238 uint32_t *DIB_pixels
;
240 BITMAPV4HEADER bmh
= { sizeof(bmh
) };
242 /* Define an ARGB pixel format used for Color+Alpha icons */
243 bmh
.bV4Width
= width
;
244 bmh
.bV4Height
= -height
; /* Invert the image */
246 bmh
.bV4BitCount
= 32;
247 bmh
.bV4V4Compression
= BI_BITFIELDS
;
248 bmh
.bV4AlphaMask
= 0xFF000000;
249 bmh
.bV4RedMask
= 0x00FF0000;
250 bmh
.bV4GreenMask
= 0x0000FF00;
251 bmh
.bV4BlueMask
= 0x000000FF;
254 ii
.xHotspot
= 0; /* ignored */
255 ii
.yHotspot
= 0; /* ignored */
256 ii
.hbmColor
= CreateDIBSection(hdc
, (BITMAPINFO
*) &bmh
,
257 DIB_RGB_COLORS
, (void **) &DIB_pixels
, NULL
,
259 ReleaseDC(NULL
, hdc
);
264 ii
.hbmMask
= CreateBitmap(width
, height
, 1, 1, NULL
);
265 memcpy(DIB_pixels
, pixels
, height
* width
* 4);
267 /* CreateIconIndirect() traditionally required DDBitmaps */
268 /* Systems from WinXP accept 32-bit ARGB DIBitmaps with full 8-bit alpha support */
269 /* The icon is created with a DIB + empty DDB mask (an MS example does the same) */
270 result
= CreateIconIndirect(&ii
);
272 DeleteObject(ii
.hbmColor
);
273 DeleteObject(ii
.hbmMask
);
275 winDebug("NetWMToWinIconAlpha - %d x %d = %p\n", icon
[0], icon
[1], result
);
280 NetWMToWinIconThreshold(uint32_t * icon
)
283 int height
= icon
[1];
284 uint32_t *pixels
= &icon
[2];
289 HDC hdc
= GetDC(NULL
);
290 HDC xorDC
= CreateCompatibleDC(hdc
);
291 HDC andDC
= CreateCompatibleDC(hdc
);
294 ii
.xHotspot
= 0; /* ignored */
295 ii
.yHotspot
= 0; /* ignored */
296 ii
.hbmColor
= CreateCompatibleBitmap(hdc
, width
, height
);
297 ii
.hbmMask
= CreateCompatibleBitmap(hdc
, width
, height
);
298 ReleaseDC(NULL
, hdc
);
299 SelectObject(xorDC
, ii
.hbmColor
);
300 SelectObject(andDC
, ii
.hbmMask
);
302 for (row
= 0; row
< height
; row
++) {
303 for (col
= 0; col
< width
; col
++) {
304 if ((*pixels
& 0xFF000000) > 31 << 24) { /* 31 alpha threshold, i.e. opaque above, transparent below */
305 SetPixelV(xorDC
, col
, row
,
306 RGB(((char *) pixels
)[2], ((char *) pixels
)[1],
307 ((char *) pixels
)[0]));
308 SetPixelV(andDC
, col
, row
, RGB(0, 0, 0)); /* black mask */
311 SetPixelV(xorDC
, col
, row
, RGB(0, 0, 0));
312 SetPixelV(andDC
, col
, row
, RGB(255, 255, 255)); /* white mask */
320 result
= CreateIconIndirect(&ii
);
322 DeleteObject(ii
.hbmColor
);
323 DeleteObject(ii
.hbmMask
);
325 winDebug("NetWMToWinIconThreshold - %d x %d = %p\n", icon
[0], icon
[1],
331 NetWMToWinIcon(int bpp
, uint32_t * icon
)
333 static Bool hasIconAlphaChannel
= FALSE
;
334 static BOOL versionChecked
= FALSE
;
336 if (!versionChecked
) {
337 OSVERSIONINFOEX osvi
= { 0 };
338 ULONGLONG dwlConditionMask
= 0;
340 osvi
.dwOSVersionInfoSize
= sizeof(osvi
);
341 osvi
.dwMajorVersion
= 5;
342 osvi
.dwMinorVersion
= 1;
344 /* Windows versions later than XP have icon alpha channel suport, 2000 does not */
345 VER_SET_CONDITION(dwlConditionMask
, VER_MAJORVERSION
,
347 VER_SET_CONDITION(dwlConditionMask
, VER_MINORVERSION
,
349 hasIconAlphaChannel
=
350 VerifyVersionInfo(&osvi
, VER_MAJORVERSION
| VER_MINORVERSION
,
352 versionChecked
= TRUE
;
354 ErrorF("OS has icon alpha channel support: %s\n",
355 hasIconAlphaChannel
? "yes" : "no");
358 if (hasIconAlphaChannel
&& (bpp
== 32))
359 return NetWMToWinIconAlpha(icon
);
361 return NetWMToWinIconThreshold(icon
);
365 * Attempt to create a custom icon from the WM_HINTS bitmaps
370 winXIconToHICON(Display
* pDisplay
, Window id
, int iconSize
)
372 unsigned char *mask
, *image
= NULL
, *imageMask
;
373 unsigned char *dst
, *src
;
375 int biggest_size
= 0;
380 uint32_t *biggest_icon
= NULL
;
382 static Atom _XA_NET_WM_ICON
;
383 static int generation
;
384 uint32_t *icon
, *icon_data
= NULL
;
385 unsigned long int size
;
386 unsigned long int type
;
388 unsigned long int left
;
390 hDC
= GetDC(GetDesktopWindow());
391 planes
= GetDeviceCaps(hDC
, PLANES
);
392 bpp
= GetDeviceCaps(hDC
, BITSPIXEL
);
393 ReleaseDC(GetDesktopWindow(), hDC
);
395 /* Always prefer _NET_WM_ICON icons */
396 if (generation
!= serverGeneration
) {
397 generation
= serverGeneration
;
398 _XA_NET_WM_ICON
= XInternAtom(pDisplay
, "_NET_WM_ICON", FALSE
);
401 if ((XGetWindowProperty(pDisplay
, id
, _XA_NET_WM_ICON
,
403 AnyPropertyType
, &type
, &format
, &size
, &left
,
404 (unsigned char **) &icon_data
) == Success
) &&
405 (icon_data
!= NULL
)) {
406 for (icon
= icon_data
; icon
< &icon_data
[size
] && *icon
;
407 icon
= &icon
[icon
[0] * icon
[1] + 2]) {
408 /* Find an exact match to the size we require... */
409 if (icon
[0] == iconSize
&& icon
[1] == iconSize
) {
410 winDebug("winXIconToHICON: found %lu x %lu NetIcon\n", icon
[0],
412 hIcon
= NetWMToWinIcon(bpp
, icon
);
415 /* Otherwise, find the biggest icon and let Windows scale the size */
416 else if (biggest_size
< icon
[0]) {
418 biggest_size
= icon
[0];
422 if (!hIcon
&& biggest_icon
) {
424 ("winXIconToHICON: selected %lu x %lu NetIcon for scaling to %u x %u\n",
425 biggest_icon
[0], biggest_icon
[1], iconSize
, iconSize
);
427 hIcon
= NetWMToWinIcon(bpp
, biggest_icon
);
434 winDebug("winXIconToHICON: no suitable NetIcon\n");
436 hints
= XGetWMHints(pDisplay
, id
);
438 winDebug("winXIconToHICON: id 0x%x icon_pixmap hint %x\n", id
,
441 if (hints
->icon_pixmap
) {
444 unsigned int width
, height
, border_width
, depth
;
446 XImage
*xImageMask
= NULL
;
448 XGetGeometry(pDisplay
, hints
->icon_pixmap
, &root
, &x
, &y
,
449 &width
, &height
, &border_width
, &depth
);
452 XGetImage(pDisplay
, hints
->icon_pixmap
, 0, 0, width
, height
,
453 0xFFFFFFFF, ZPixmap
);
454 winDebug("winXIconToHICON: id 0x%x icon Ximage 0x%x\n", id
,
457 if (hints
->icon_mask
)
459 XGetImage(pDisplay
, hints
->icon_mask
, 0, 0, width
,
460 height
, 0xFFFFFFFF, ZPixmap
);
463 int effBPP
, stride
, maskStride
;
465 /* 15 BPP is really 16BPP as far as we care */
471 /* Need 16-bit aligned rows for DDBitmaps */
472 stride
= ((iconSize
* effBPP
+ 15) & (~15)) / 8;
474 /* Mask is 1-bit deep */
475 maskStride
= ((iconSize
* 1 + 15) & (~15)) / 8;
477 image
= malloc(stride
* iconSize
);
478 imageMask
= malloc(stride
* iconSize
);
479 mask
= malloc(maskStride
* iconSize
);
481 /* Default to a completely black mask */
482 memset(imageMask
, 0, stride
* iconSize
);
483 memset(mask
, 0, maskStride
* iconSize
);
485 winScaleXImageToWindowsIcon(iconSize
, effBPP
, stride
,
489 winScaleXImageToWindowsIcon(iconSize
, 1, maskStride
,
491 winScaleXImageToWindowsIcon(iconSize
, effBPP
, stride
,
492 xImageMask
, imageMask
);
495 /* Now we need to set all bits of the icon which are not masked */
496 /* on to 0 because Color is really an XOR, not an OR function */
500 for (i
= 0; i
< (stride
* iconSize
); i
++)
507 ii
.xHotspot
= 0; /* ignored */
508 ii
.yHotspot
= 0; /* ignored */
510 /* Create Win32 mask from pixmap shape */
512 CreateBitmap(iconSize
, iconSize
, planes
, 1, mask
);
514 /* Create Win32 bitmap from pixmap */
516 CreateBitmap(iconSize
, iconSize
, planes
, bpp
, image
);
518 /* Merge Win32 mask and bitmap into icon */
519 hIcon
= CreateIconIndirect(&ii
);
521 /* Release Win32 mask and bitmap */
522 DeleteObject(ii
.hbmMask
);
523 DeleteObject(ii
.hbmColor
);
525 /* Free X mask and bitmap */
531 XDestroyImage(xImageMask
);
533 XDestroyImage(xImageIcon
);
543 * Change the Windows window icon
546 #ifdef XWIN_MULTIWINDOW
548 winUpdateIcon(HWND hWnd
, Display
* pDisplay
, Window id
, HICON hIconNew
)
550 HICON hIcon
, hIconSmall
= NULL
, hIconOld
;
552 /* Start with the icon from preferences, if any */
554 hIconSmall
= hIconNew
;
556 /* If we still need an icon, try and get the icon from WM_HINTS */
558 hIcon
= winXIconToHICON(pDisplay
, id
, GetSystemMetrics(SM_CXICON
));
561 winXIconToHICON(pDisplay
, id
, GetSystemMetrics(SM_CXSMICON
));
563 /* If we got the small, but not the large one swap them */
564 if (!hIcon
&& hIconSmall
) {
569 /* Set the large icon */
570 hIconOld
= (HICON
) SendMessage(hWnd
, WM_SETICON
, ICON_BIG
, (LPARAM
) hIcon
);
571 /* Delete the old icon if its not the default */
572 winDestroyIcon(hIconOld
);
574 /* Same for the small icon */
576 (HICON
) SendMessage(hWnd
, WM_SETICON
, ICON_SMALL
, (LPARAM
) hIconSmall
);
577 winDestroyIcon(hIconOld
);
581 winInitGlobalIcons(void)
583 int sm_cx
= GetSystemMetrics(SM_CXICON
);
584 int sm_cxsm
= GetSystemMetrics(SM_CXSMICON
);
586 /* Load default X icon in case it's not ready yet */
588 g_hIconX
= winOverrideDefaultIcon(sm_cx
);
589 g_hSmallIconX
= winOverrideDefaultIcon(sm_cxsm
);
593 g_hIconX
= (HICON
) LoadImage(g_hInstance
,
594 MAKEINTRESOURCE(IDI_XWIN
),
596 GetSystemMetrics(SM_CXICON
),
597 GetSystemMetrics(SM_CYICON
), 0);
598 g_hSmallIconX
= (HICON
) LoadImage(g_hInstance
,
599 MAKEINTRESOURCE(IDI_XWIN
),
601 GetSystemMetrics(SM_CXSMICON
),
602 GetSystemMetrics(SM_CYSMICON
),
608 winSelectIcons(HICON
* pIcon
, HICON
* pSmallIcon
)
610 HICON hIcon
, hSmallIcon
;
612 winInitGlobalIcons();
614 /* Use default X icon */
616 hSmallIcon
= g_hSmallIconX
;
622 *pSmallIcon
= hSmallIcon
;
626 winDestroyIcon(HICON hIcon
)
628 /* Delete the icon if its not one of the application defaults or an override */
631 hIcon
!= g_hSmallIconX
&& !winIconIsOverride(hIcon
))