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