1706f2543Smrg/*
2706f2543Smrg *Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved.
3706f2543Smrg *
4706f2543Smrg *Permission is hereby granted, free of charge, to any person obtaining
5706f2543Smrg * a copy of this software and associated documentation files (the
6706f2543Smrg *"Software"), to deal in the Software without restriction, including
7706f2543Smrg *without limitation the rights to use, copy, modify, merge, publish,
8706f2543Smrg *distribute, sublicense, and/or sell copies of the Software, and to
9706f2543Smrg *permit persons to whom the Software is furnished to do so, subject to
10706f2543Smrg *the following conditions:
11706f2543Smrg *
12706f2543Smrg *The above copyright notice and this permission notice shall be
13706f2543Smrg *included in all copies or substantial portions of the Software.
14706f2543Smrg *
15706f2543Smrg *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16706f2543Smrg *EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17706f2543Smrg *MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18706f2543Smrg *NONINFRINGEMENT. IN NO EVENT SHALL THE XFREE86 PROJECT BE LIABLE FOR
19706f2543Smrg *ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
20706f2543Smrg *CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21706f2543Smrg *WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22706f2543Smrg *
23706f2543Smrg *Except as contained in this notice, the name of the XFree86 Project
24706f2543Smrg *shall not be used in advertising or otherwise to promote the sale, use
25706f2543Smrg *or other dealings in this Software without prior written authorization
26706f2543Smrg *from the XFree86 Project.
27706f2543Smrg *
28706f2543Smrg * Authors:	Earle F. Philhower, III
29706f2543Smrg */
30706f2543Smrg
31706f2543Smrg#ifdef HAVE_XWIN_CONFIG_H
32706f2543Smrg#include <xwin-config.h>
33706f2543Smrg#endif
34706f2543Smrg#include "win.h"
35706f2543Smrg#include "dixevents.h"
36706f2543Smrg#include "winmultiwindowclass.h"
37706f2543Smrg#include "winprefs.h"
38706f2543Smrg
39706f2543Smrg#include "propertyst.h"
40706f2543Smrg
41706f2543Smrg#include "propertyst.h"
42706f2543Smrg#include "windowstr.h"
43706f2543Smrg
44706f2543Smrg
45706f2543Smrg/*
46706f2543Smrg * Prototypes for local functions
47706f2543Smrg */
48706f2543Smrg
49706f2543Smrgstatic void
50706f2543SmrgwinScaleXBitmapToWindows (int iconSize, int effBPP,
51706f2543Smrg			  PixmapPtr pixmap, unsigned char *image);
52706f2543Smrg
53706f2543Smrg
54706f2543Smrg/*
55706f2543Smrg * Scale an X icon bitmap into a Windoze icon bitmap
56706f2543Smrg */
57706f2543Smrg
58706f2543Smrgstatic void
59706f2543SmrgwinScaleXBitmapToWindows (int iconSize,
60706f2543Smrg			  int effBPP,
61706f2543Smrg			  PixmapPtr pixmap,
62706f2543Smrg			  unsigned char *image)
63706f2543Smrg{
64706f2543Smrg  int			row, column, effXBPP, effXDepth;
65706f2543Smrg  unsigned char		*outPtr;
66706f2543Smrg  char		*iconData = 0;
67706f2543Smrg  int			stride, xStride;
68706f2543Smrg  float			factX, factY;
69706f2543Smrg  int			posX, posY;
70706f2543Smrg  unsigned char		*ptr;
71706f2543Smrg  unsigned int		zero;
72706f2543Smrg  unsigned int		color;
73706f2543Smrg
74706f2543Smrg  effXBPP = BitsPerPixel(pixmap->drawable.depth);
75706f2543Smrg  effXDepth = pixmap->drawable.depth;
76706f2543Smrg
77706f2543Smrg  if (pixmap->drawable.bitsPerPixel == 15)
78706f2543Smrg    effXBPP = 16;
79706f2543Smrg
80706f2543Smrg  if (pixmap->drawable.depth == 15)
81706f2543Smrg    effXDepth = 16;
82706f2543Smrg
83706f2543Smrg  /* Need 16-bit aligned rows for DDBitmaps */
84706f2543Smrg  stride = ((iconSize * effBPP + 15) & (~15)) / 8;
85706f2543Smrg  xStride = PixmapBytePad (pixmap->drawable.width, pixmap->drawable.depth);
86706f2543Smrg  if (stride == 0 || xStride == 0)
87706f2543Smrg    {
88706f2543Smrg      ErrorF ("winScaleXBitmapToWindows - stride or xStride is zero.  "
89706f2543Smrg	      "Bailing.\n");
90706f2543Smrg      return;
91706f2543Smrg    }
92706f2543Smrg
93706f2543Smrg  /* Allocate memory for icon data */
94706f2543Smrg  iconData = malloc (xStride * pixmap->drawable.height);
95706f2543Smrg  if (!iconData)
96706f2543Smrg    {
97706f2543Smrg      ErrorF ("winScaleXBitmapToWindows - malloc failed for iconData.  "
98706f2543Smrg	      "Bailing.\n");
99706f2543Smrg      return;
100706f2543Smrg    }
101706f2543Smrg
102706f2543Smrg  /* Get icon data */
103706f2543Smrg  miGetImage ((DrawablePtr) &(pixmap->drawable), 0, 0,
104706f2543Smrg	      pixmap->drawable.width, pixmap->drawable.height,
105706f2543Smrg	      ZPixmap, 0xffffffff, iconData);
106706f2543Smrg
107706f2543Smrg  /* Keep aspect ratio */
108706f2543Smrg  factX = ((float)pixmap->drawable.width) / ((float)iconSize);
109706f2543Smrg  factY = ((float)pixmap->drawable.height) / ((float)iconSize);
110706f2543Smrg  if (factX > factY)
111706f2543Smrg    factY = factX;
112706f2543Smrg  else
113706f2543Smrg    factX = factY;
114706f2543Smrg
115706f2543Smrg  /* Out-of-bounds, fill icon with zero */
116706f2543Smrg  zero = 0;
117706f2543Smrg
118706f2543Smrg  for (row = 0; row < iconSize; row++)
119706f2543Smrg    {
120706f2543Smrg      outPtr = image + stride * row;
121706f2543Smrg      for (column = 0; column < iconSize; column++)
122706f2543Smrg	{
123706f2543Smrg	  posX = factX * column;
124706f2543Smrg	  posY = factY * row;
125706f2543Smrg
126706f2543Smrg	  ptr = (unsigned char*) iconData + posY*xStride;
127706f2543Smrg	  if (effXBPP == 1)
128706f2543Smrg	    {
129706f2543Smrg	      ptr += posX / 8;
130706f2543Smrg
131706f2543Smrg	      /* Out of X icon bounds, leave space blank */
132706f2543Smrg	      if (posX >= pixmap->drawable.width
133706f2543Smrg		  || posY >= pixmap->drawable.height)
134706f2543Smrg		ptr = (unsigned char *) &zero;
135706f2543Smrg
136706f2543Smrg	      if ((*ptr) & (1 << (posX & 7)))
137706f2543Smrg		switch (effBPP)
138706f2543Smrg		  {
139706f2543Smrg		  case 32:
140706f2543Smrg		    *(outPtr++) = 0;
141706f2543Smrg		  case 24:
142706f2543Smrg		    *(outPtr++) = 0;
143706f2543Smrg		  case 16:
144706f2543Smrg		    *(outPtr++) = 0;
145706f2543Smrg		  case 8:
146706f2543Smrg		    *(outPtr++) = 0;
147706f2543Smrg		    break;
148706f2543Smrg		  case 1:
149706f2543Smrg		    outPtr[column / 8] &= ~(1 << (7 - (column & 7)));
150706f2543Smrg		    break;
151706f2543Smrg		  }
152706f2543Smrg	      else
153706f2543Smrg		switch (effBPP)
154706f2543Smrg		  {
155706f2543Smrg		  case 32:
156706f2543Smrg		    *(outPtr++) = 255;
157706f2543Smrg		    *(outPtr++) = 255;
158706f2543Smrg		    *(outPtr++) = 255;
159706f2543Smrg		    *(outPtr++) = 0;
160706f2543Smrg		    break;
161706f2543Smrg		  case 24:
162706f2543Smrg		    *(outPtr++) = 255;
163706f2543Smrg		  case 16:
164706f2543Smrg		    *(outPtr++) = 255;
165706f2543Smrg		  case 8:
166706f2543Smrg		    *(outPtr++) = 255;
167706f2543Smrg		    break;
168706f2543Smrg		  case 1:
169706f2543Smrg		    outPtr[column / 8] |= (1 << (7 - (column & 7)));
170706f2543Smrg		    break;
171706f2543Smrg		  }
172706f2543Smrg	    }
173706f2543Smrg	  else if (effXDepth == 24 || effXDepth == 32)
174706f2543Smrg	    {
175706f2543Smrg	      ptr += posX * (effXBPP / 8);
176706f2543Smrg
177706f2543Smrg	      /* Out of X icon bounds, leave space blank */
178706f2543Smrg	      if (posX >= pixmap->drawable.width
179706f2543Smrg		  || posY >= pixmap->drawable.height)
180706f2543Smrg		ptr = (unsigned char *) &zero;
181706f2543Smrg	      color = (((*ptr) << 16)
182706f2543Smrg		       + ((*(ptr + 1)) << 8)
183706f2543Smrg		       + ((*(ptr + 2)) << 0));
184706f2543Smrg	      switch (effBPP)
185706f2543Smrg		{
186706f2543Smrg		case 32:
187706f2543Smrg		  *(outPtr++) = *(ptr++); /* b */
188706f2543Smrg		  *(outPtr++) = *(ptr++); /* g */
189706f2543Smrg		  *(outPtr++) = *(ptr++); /* r */
190706f2543Smrg		  *(outPtr++) = (effXDepth == 32) ? *(ptr++) : 0x0; /* alpha */
191706f2543Smrg		  break;
192706f2543Smrg		case 24:
193706f2543Smrg		  *(outPtr++) = *(ptr++);
194706f2543Smrg		  *(outPtr++) = *(ptr++);
195706f2543Smrg		  *(outPtr++) = *(ptr++);
196706f2543Smrg		  break;
197706f2543Smrg		case 16:
198706f2543Smrg		  color = ((((*ptr) >> 2) << 10)
199706f2543Smrg			   + (((*(ptr + 1)) >> 2) << 5)
200706f2543Smrg			   + (((*(ptr + 2)) >> 2)));
201706f2543Smrg		  *(outPtr++) = (color >> 8);
202706f2543Smrg		  *(outPtr++) = (color & 255);
203706f2543Smrg		  break;
204706f2543Smrg		case 8:
205706f2543Smrg		  color = (((*ptr))) + (((*(ptr + 1)))) + (((*(ptr + 2))));
206706f2543Smrg		  color /= 3;
207706f2543Smrg		  *(outPtr++) = color;
208706f2543Smrg		  break;
209706f2543Smrg		case 1:
210706f2543Smrg		  if (color)
211706f2543Smrg		    outPtr[column / 8] |= (1 << (7 - (column & 7)));
212706f2543Smrg		  else
213706f2543Smrg		    outPtr[column / 8] &= ~(1 << (7 - (column & 7)));
214706f2543Smrg		}
215706f2543Smrg	    }
216706f2543Smrg	  else if (effXDepth == 16)
217706f2543Smrg	    {
218706f2543Smrg	      ptr += posX * (effXBPP / 8);
219706f2543Smrg
220706f2543Smrg	      /* Out of X icon bounds, leave space blank */
221706f2543Smrg	      if (posX >= pixmap->drawable.width
222706f2543Smrg		  || posY >= pixmap->drawable.height)
223706f2543Smrg		ptr = (unsigned char *) &zero;
224706f2543Smrg	      color = ((*ptr) << 8) + (*(ptr + 1));
225706f2543Smrg	      switch (effBPP)
226706f2543Smrg		{
227706f2543Smrg		case 32:
228706f2543Smrg		  *(outPtr++) = (color & 31) << 2;
229706f2543Smrg		  *(outPtr++) = ((color >> 5) & 31) << 2;
230706f2543Smrg		  *(outPtr++) = ((color >> 10) & 31) << 2;
231706f2543Smrg		  *(outPtr++) = 0; /* resvd */
232706f2543Smrg		  break;
233706f2543Smrg		case 24:
234706f2543Smrg		  *(outPtr++) = (color & 31) << 2;
235706f2543Smrg		  *(outPtr++) = ((color >> 5) & 31) << 2;
236706f2543Smrg		  *(outPtr++) = ((color >> 10) & 31) << 2;
237706f2543Smrg		  break;
238706f2543Smrg		case 16:
239706f2543Smrg		  *(outPtr++) = *(ptr++);
240706f2543Smrg		  *(outPtr++) = *(ptr++);
241706f2543Smrg		  break;
242706f2543Smrg		case 8:
243706f2543Smrg		  *(outPtr++) = (((color & 31)
244706f2543Smrg				  + ((color >> 5) & 31)
245706f2543Smrg				  + ((color >> 10) & 31)) / 3) << 2;
246706f2543Smrg		  break;
247706f2543Smrg		case 1:
248706f2543Smrg		  if (color)
249706f2543Smrg		    outPtr[column / 8] |= (1 << (7 - (column & 7)));
250706f2543Smrg		  else
251706f2543Smrg		    outPtr[column / 8] &= ~(1 << (7 - (column & 7)));
252706f2543Smrg		  break;
253706f2543Smrg		} /* end switch(effbpp) */
254706f2543Smrg	    } /* end if effxbpp==16) */
255706f2543Smrg	} /* end for column */
256706f2543Smrg    } /* end for row */
257706f2543Smrg  free (iconData);
258706f2543Smrg}
259706f2543Smrg
260706f2543Smrgstatic HICON
261706f2543SmrgNetWMToWinIconAlpha(uint32_t *icon)
262706f2543Smrg{
263706f2543Smrg  int width = icon[0];
264706f2543Smrg  int height = icon[1];
265706f2543Smrg  uint32_t *pixels = &icon[2];
266706f2543Smrg  HICON result;
267706f2543Smrg  HDC hdc = GetDC(NULL);
268706f2543Smrg  uint32_t *DIB_pixels;
269706f2543Smrg  ICONINFO ii = {TRUE};
270706f2543Smrg  BITMAPV4HEADER bmh = {sizeof(bmh)};
271706f2543Smrg
272706f2543Smrg  /* Define an ARGB pixel format used for Color+Alpha icons */
273706f2543Smrg  bmh.bV4Width = width;
274706f2543Smrg  bmh.bV4Height = -height; /* Invert the image */
275706f2543Smrg  bmh.bV4Planes = 1;
276706f2543Smrg  bmh.bV4BitCount = 32;
277706f2543Smrg  bmh.bV4V4Compression = BI_BITFIELDS;
278706f2543Smrg  bmh.bV4AlphaMask = 0xFF000000;
279706f2543Smrg  bmh.bV4RedMask =   0x00FF0000;
280706f2543Smrg  bmh.bV4GreenMask = 0x0000FF00;
281706f2543Smrg  bmh.bV4BlueMask =  0x000000FF;
282706f2543Smrg
283706f2543Smrg  ii.hbmColor = CreateDIBSection(hdc, (BITMAPINFO*)&bmh,
284706f2543Smrg                DIB_RGB_COLORS, (void**)&DIB_pixels, NULL, 0);
285706f2543Smrg  ReleaseDC(NULL, hdc);
286706f2543Smrg  ii.hbmMask = CreateBitmap(width, height, 1, 1, NULL);
287706f2543Smrg  memcpy(DIB_pixels, pixels, height*width*4);
288706f2543Smrg
289706f2543Smrg  /* CreateIconIndirect() traditionally required DDBitmaps */
290706f2543Smrg  /* Systems from WinXP accept 32-bit ARGB DIBitmaps with full 8-bit alpha support */
291706f2543Smrg  /* The icon is created with a DIB + empty DDB mask (an MS example does the same) */
292706f2543Smrg  result = CreateIconIndirect(&ii);
293706f2543Smrg
294706f2543Smrg  DeleteObject(ii.hbmColor);
295706f2543Smrg  DeleteObject(ii.hbmMask);
296706f2543Smrg
297706f2543Smrg  winDebug("NetWMToWinIconAlpha - %d x %d = %p\n", icon[0], icon[1], result);
298706f2543Smrg  return result;
299706f2543Smrg}
300706f2543Smrg
301706f2543Smrgstatic HICON
302706f2543SmrgNetWMToWinIconThreshold(uint32_t *icon)
303706f2543Smrg{
304706f2543Smrg  int width = icon[0];
305706f2543Smrg  int height = icon[1];
306706f2543Smrg  uint32_t *pixels = &icon[2];
307706f2543Smrg  int row, col;
308706f2543Smrg  HICON result;
309706f2543Smrg  ICONINFO ii = {TRUE};
310706f2543Smrg
311706f2543Smrg  HDC hdc = GetDC(NULL);
312706f2543Smrg  HDC xorDC = CreateCompatibleDC(hdc);
313706f2543Smrg  HDC andDC = CreateCompatibleDC(hdc);
314706f2543Smrg  ii.hbmColor = CreateCompatibleBitmap(hdc, width, height);
315706f2543Smrg  ii.hbmMask = CreateCompatibleBitmap(hdc, width, height);
316706f2543Smrg  ReleaseDC(NULL, hdc);
317706f2543Smrg  SelectObject(xorDC, ii.hbmColor);
318706f2543Smrg  SelectObject(andDC, ii.hbmMask);
319706f2543Smrg
320706f2543Smrg  for (row = 0; row < height; row++) {
321706f2543Smrg    for (col = 0; col < width; col++) {
322706f2543Smrg      if ((*pixels & 0xFF000000) > 31<<24) { /* 31 alpha threshold, i.e. opaque above, transparent below */
323706f2543Smrg	SetPixelV(xorDC, col, row, RGB(((char*)pixels)[2], ((char*)pixels)[1],
324706f2543Smrg		((char*)pixels)[0]));
325706f2543Smrg	SetPixelV(andDC, col, row, RGB(0, 0, 0)); /* black mask */
326706f2543Smrg      }
327706f2543Smrg      else {
328706f2543Smrg	SetPixelV(xorDC, col, row, RGB(0, 0, 0));
329706f2543Smrg	SetPixelV(andDC, col, row, RGB(255, 255, 255)); /* white mask */
330706f2543Smrg      }
331706f2543Smrg      pixels++;
332706f2543Smrg    }
333706f2543Smrg  }
334706f2543Smrg  DeleteDC(xorDC);
335706f2543Smrg  DeleteDC(andDC);
336706f2543Smrg
337706f2543Smrg  result = CreateIconIndirect(&ii);
338706f2543Smrg
339706f2543Smrg  DeleteObject(ii.hbmColor);
340706f2543Smrg  DeleteObject(ii.hbmMask );
341706f2543Smrg
342706f2543Smrg  winDebug("NetWMToWinIconThreshold - %d x %d = %p\n", icon[0], icon[1], result);
343706f2543Smrg  return result;
344706f2543Smrg}
345706f2543Smrg
346706f2543Smrgstatic HICON
347706f2543SmrgNetWMToWinIcon(int bpp, uint32_t *icon)
348706f2543Smrg{
349706f2543Smrg  static Bool hasIconAlphaChannel = FALSE;
350706f2543Smrg  static BOOL versionChecked = FALSE;
351706f2543Smrg
352706f2543Smrg  if (!versionChecked)
353706f2543Smrg    {
354706f2543Smrg      OSVERSIONINFOEX osvi = {0};
355706f2543Smrg      ULONGLONG dwlConditionMask = 0;
356706f2543Smrg
357706f2543Smrg      osvi.dwOSVersionInfoSize = sizeof (osvi);
358706f2543Smrg      osvi.dwMajorVersion = 5;
359706f2543Smrg      osvi.dwMinorVersion = 1;
360706f2543Smrg
361706f2543Smrg      /* Windows versions later than XP have icon alpha channel suport, 2000 does not */
362706f2543Smrg      VER_SET_CONDITION(dwlConditionMask, VER_MAJORVERSION, VER_GREATER_EQUAL);
363706f2543Smrg      VER_SET_CONDITION(dwlConditionMask, VER_MINORVERSION, VER_GREATER_EQUAL);
364706f2543Smrg      hasIconAlphaChannel = VerifyVersionInfo(&osvi, VER_MAJORVERSION | VER_MINORVERSION, dwlConditionMask);
365706f2543Smrg      versionChecked = TRUE;
366706f2543Smrg
367706f2543Smrg      ErrorF("OS has icon alpha channel support: %s\n", hasIconAlphaChannel ? "yes" : "no");
368706f2543Smrg    }
369706f2543Smrg
370706f2543Smrg  if (hasIconAlphaChannel && (bpp==32))
371706f2543Smrg    return NetWMToWinIconAlpha(icon);
372706f2543Smrg  else
373706f2543Smrg    return NetWMToWinIconThreshold(icon);
374706f2543Smrg}
375706f2543Smrg
376706f2543Smrgstatic pointer
377706f2543SmrgGetWindowProp(WindowPtr pWin, Atom name, long int *size_return)
378706f2543Smrg{
379706f2543Smrg  struct _Window	*pwin;
380706f2543Smrg  struct _Property	*prop;
381706f2543Smrg
382706f2543Smrg  if (!pWin || !name) {
383706f2543Smrg    ErrorF ("GetWindowProp - pWin or name was NULL\n");
384706f2543Smrg    return 0;
385706f2543Smrg  }
386706f2543Smrg  pwin = (struct _Window*) pWin;
387706f2543Smrg  if (!pwin->optional) return NULL;
388706f2543Smrg  for (prop = (struct _Property *) pwin->optional->userProps;
389706f2543Smrg       prop;
390706f2543Smrg       prop=prop->next){
391706f2543Smrg    if (prop->propertyName == name) {
392706f2543Smrg      *size_return=prop->size;
393706f2543Smrg      return prop->data;
394706f2543Smrg    }
395706f2543Smrg  }
396706f2543Smrg  return NULL;
397706f2543Smrg}
398706f2543Smrg
399706f2543Smrg/*
400706f2543Smrg * Attempt to create a custom icon from the WM_HINTS bitmaps
401706f2543Smrg */
402706f2543Smrg
403706f2543SmrgHICON
404706f2543SmrgwinXIconToHICON (WindowPtr pWin, int iconSize)
405706f2543Smrg{
406706f2543Smrg  unsigned char		*mask, *image, *imageMask;
407706f2543Smrg  unsigned char		*dst, *src;
408706f2543Smrg  PixmapPtr		iconPtr;
409706f2543Smrg  PixmapPtr		maskPtr;
410706f2543Smrg  int			planes, bpp, effBPP, stride, maskStride, i;
411706f2543Smrg  int			biggest_size = 0;
412706f2543Smrg  HDC			hDC;
413706f2543Smrg  ICONINFO		ii;
414706f2543Smrg  WinXWMHints		hints;
415706f2543Smrg  HICON			hIcon = NULL;
416706f2543Smrg  uint32_t		*biggest_icon = NULL;
417706f2543Smrg
418706f2543Smrg  /* Try to get _NET_WM_ICON icons first */
419706f2543Smrg  static Atom _XA_NET_WM_ICON;
420706f2543Smrg  static int generation;
421706f2543Smrg  uint32_t *icon, *icon_data = NULL;
422706f2543Smrg  long int size=0;
423706f2543Smrg
424706f2543Smrg  hDC = GetDC (GetDesktopWindow ());
425706f2543Smrg  planes = GetDeviceCaps (hDC, PLANES);
426706f2543Smrg  bpp = GetDeviceCaps (hDC, BITSPIXEL);
427706f2543Smrg  ReleaseDC (GetDesktopWindow (), hDC);
428706f2543Smrg
429706f2543Smrg  if (generation != serverGeneration) {
430706f2543Smrg     generation = serverGeneration;
431706f2543Smrg     _XA_NET_WM_ICON = MakeAtom("_NET_WM_ICON", 12, TRUE);
432706f2543Smrg  }
433706f2543Smrg
434706f2543Smrg  if (_XA_NET_WM_ICON) icon_data = GetWindowProp(pWin, _XA_NET_WM_ICON, &size);
435706f2543Smrg  if (icon_data)
436706f2543Smrg    {
437706f2543Smrg      for(icon = icon_data;
438706f2543Smrg	  icon < &icon_data[size] && *icon;
439706f2543Smrg	  icon = &icon[icon[0]*icon[1]+2])
440706f2543Smrg	{
441706f2543Smrg	  if (icon[0]==iconSize && icon[1]==iconSize)
442706f2543Smrg            return NetWMToWinIcon(bpp, icon);
443706f2543Smrg	  /* Find the biggest icon and let Windows scale the size */
444706f2543Smrg	  else if (biggest_size < icon[0])
445706f2543Smrg	    {
446706f2543Smrg	      biggest_icon = icon;
447706f2543Smrg	      biggest_size = icon[0];
448706f2543Smrg	    }
449706f2543Smrg	}
450706f2543Smrg      if (biggest_icon)
451706f2543Smrg	return NetWMToWinIcon(bpp, biggest_icon);
452706f2543Smrg    }
453706f2543Smrg  winDebug("winXIconToHICON - pWin %x: no suitable NetIcon\n",(int)pWin, iconSize);
454706f2543Smrg
455706f2543Smrg  winMultiWindowGetWMHints (pWin, &hints);
456706f2543Smrg  if (!hints.icon_pixmap) return NULL;
457706f2543Smrg
458706f2543Smrg  dixLookupResourceByType((pointer) &iconPtr, hints.icon_pixmap, RT_PIXMAP,
459706f2543Smrg				NullClient, DixUnknownAccess);
460706f2543Smrg
461706f2543Smrg  if (!iconPtr) return NULL;
462706f2543Smrg
463706f2543Smrg  /* 15 BPP is really 16BPP as far as we care */
464706f2543Smrg  if (bpp == 15)
465706f2543Smrg    effBPP = 16;
466706f2543Smrg  else
467706f2543Smrg    effBPP = bpp;
468706f2543Smrg
469706f2543Smrg  /* Need 16-bit aligned rows for DDBitmaps */
470706f2543Smrg  stride = ((iconSize * effBPP + 15) & (~15)) / 8;
471706f2543Smrg
472706f2543Smrg  /* Mask is 1-bit deep */
473706f2543Smrg  maskStride = ((iconSize * 1 + 15) & (~15)) / 8;
474706f2543Smrg
475706f2543Smrg  image = malloc (stride * iconSize);
476706f2543Smrg  imageMask = malloc (stride * iconSize);
477706f2543Smrg  /* Default to a completely black mask */
478706f2543Smrg  mask = calloc (maskStride, iconSize);
479706f2543Smrg
480706f2543Smrg  winScaleXBitmapToWindows (iconSize, effBPP, iconPtr, image);
481706f2543Smrg  dixLookupResourceByType((pointer) &maskPtr, hints.icon_mask, RT_PIXMAP,
482706f2543Smrg				NullClient, DixUnknownAccess);
483706f2543Smrg
484706f2543Smrg  if (maskPtr)
485706f2543Smrg    {
486706f2543Smrg      winScaleXBitmapToWindows (iconSize, 1, maskPtr, mask);
487706f2543Smrg
488706f2543Smrg      winScaleXBitmapToWindows (iconSize, effBPP, maskPtr, imageMask);
489706f2543Smrg
490706f2543Smrg      /* Now we need to set all bits of the icon which are not masked */
491706f2543Smrg      /* on to 0 because Color is really an XOR, not an OR function */
492706f2543Smrg      dst = image;
493706f2543Smrg      src = imageMask;
494706f2543Smrg
495706f2543Smrg      for (i = 0; i < (stride * iconSize); i++)
496706f2543Smrg	if ((*(src++)))
497706f2543Smrg	  *(dst++) = 0;
498706f2543Smrg	else
499706f2543Smrg	  dst++;
500706f2543Smrg    }
501706f2543Smrg
502706f2543Smrg  ii.fIcon = TRUE;
503706f2543Smrg  ii.xHotspot = 0; /* ignored */
504706f2543Smrg  ii.yHotspot = 0; /* ignored */
505706f2543Smrg
506706f2543Smrg  /* Create Win32 mask from pixmap shape */
507706f2543Smrg  ii.hbmMask = CreateBitmap (iconSize, iconSize, planes, 1, mask);
508706f2543Smrg
509706f2543Smrg  /* Create Win32 bitmap from pixmap */
510706f2543Smrg  ii.hbmColor = CreateBitmap (iconSize, iconSize, planes, bpp, image);
511706f2543Smrg
512706f2543Smrg  /* Merge Win32 mask and bitmap into icon */
513706f2543Smrg  hIcon = CreateIconIndirect (&ii);
514706f2543Smrg
515706f2543Smrg  /* Release Win32 mask and bitmap */
516706f2543Smrg  DeleteObject (ii.hbmMask);
517706f2543Smrg  DeleteObject (ii.hbmColor);
518706f2543Smrg
519706f2543Smrg  /* Free X mask and bitmap */
520706f2543Smrg  free (mask);
521706f2543Smrg  free (image);
522706f2543Smrg  free (imageMask);
523706f2543Smrg
524706f2543Smrg  return hIcon;
525706f2543Smrg}
526706f2543Smrg
527706f2543Smrg
528706f2543Smrg
529706f2543Smrg/*
530706f2543Smrg * Change the Windows window icon
531706f2543Smrg */
532706f2543Smrg
533706f2543Smrg#ifdef XWIN_MULTIWINDOW
534706f2543Smrgvoid
535706f2543SmrgwinUpdateIcon (Window id)
536706f2543Smrg{
537706f2543Smrg  WindowPtr		pWin;
538706f2543Smrg  HICON			hIcon, hIconSmall=NULL, hIconOld;
539706f2543Smrg
540706f2543Smrg  dixLookupResourceByType((pointer) &pWin, id, RT_WINDOW, NullClient, DixUnknownAccess);
541706f2543Smrg  if (pWin)
542706f2543Smrg    {
543706f2543Smrg      winWindowPriv(pWin);
544706f2543Smrg      if (pWinPriv->hWnd) {
545706f2543Smrg        hIcon = winOverrideIcon ((unsigned long)pWin);
546706f2543Smrg        if (!hIcon) {
547706f2543Smrg          hIcon = winXIconToHICON (pWin, GetSystemMetrics(SM_CXICON));
548706f2543Smrg          if (!hIcon) {
549706f2543Smrg            hIcon = g_hIconX;
550706f2543Smrg            hIconSmall = g_hSmallIconX;
551706f2543Smrg          } else {
552706f2543Smrg            /* Leave undefined if not found */
553706f2543Smrg            hIconSmall = winXIconToHICON (pWin, GetSystemMetrics(SM_CXSMICON));
554706f2543Smrg          }
555706f2543Smrg        }
556706f2543Smrg
557706f2543Smrg        /* Set the large icon */
558706f2543Smrg        hIconOld = (HICON) SendMessage (pWinPriv->hWnd,
559706f2543Smrg                                        WM_SETICON, ICON_BIG, (LPARAM) hIcon);
560706f2543Smrg
561706f2543Smrg        /* Delete the icon if its not the default */
562706f2543Smrg        winDestroyIcon(hIconOld);
563706f2543Smrg
564706f2543Smrg        /* Same for the small icon */
565706f2543Smrg        hIconOld = (HICON) SendMessage (pWinPriv->hWnd,
566706f2543Smrg                                        WM_SETICON, ICON_SMALL, (LPARAM) hIconSmall);
567706f2543Smrg        winDestroyIcon(hIconOld);
568706f2543Smrg      }
569706f2543Smrg  }
570706f2543Smrg}
571706f2543Smrg
572706f2543Smrgvoid winInitGlobalIcons (void)
573706f2543Smrg{
574706f2543Smrg  int sm_cx = GetSystemMetrics(SM_CXICON);
575706f2543Smrg  int sm_cxsm = GetSystemMetrics(SM_CXSMICON);
576706f2543Smrg  /* Load default X icon in case it's not ready yet */
577706f2543Smrg  if (!g_hIconX)
578706f2543Smrg    {
579706f2543Smrg      g_hIconX = winOverrideDefaultIcon(sm_cx);
580706f2543Smrg      g_hSmallIconX = winOverrideDefaultIcon(sm_cxsm);
581706f2543Smrg    }
582706f2543Smrg
583706f2543Smrg  if (!g_hIconX)
584706f2543Smrg    {
585706f2543Smrg      g_hIconX = (HICON)LoadImage (g_hInstance,
586706f2543Smrg	      MAKEINTRESOURCE(IDI_XWIN),
587706f2543Smrg	      IMAGE_ICON,
588706f2543Smrg	      GetSystemMetrics(SM_CXICON),
589706f2543Smrg	      GetSystemMetrics(SM_CYICON),
590706f2543Smrg	      0);
591706f2543Smrg      g_hSmallIconX = (HICON)LoadImage (g_hInstance,
592706f2543Smrg	      MAKEINTRESOURCE(IDI_XWIN),
593706f2543Smrg	      IMAGE_ICON,
594706f2543Smrg	      GetSystemMetrics(SM_CXSMICON),
595706f2543Smrg	      GetSystemMetrics(SM_CYSMICON),
596706f2543Smrg	      LR_DEFAULTSIZE);
597706f2543Smrg    }
598706f2543Smrg}
599706f2543Smrg
600706f2543Smrgvoid winSelectIcons(WindowPtr pWin, HICON *pIcon, HICON *pSmallIcon)
601706f2543Smrg{
602706f2543Smrg  HICON hIcon, hSmallIcon;
603706f2543Smrg
604706f2543Smrg  winInitGlobalIcons();
605706f2543Smrg
606706f2543Smrg  /* Try and get the icon from WM_HINTS */
607706f2543Smrg  hIcon = winXIconToHICON (pWin, GetSystemMetrics(SM_CXICON));
608706f2543Smrg  hSmallIcon = winXIconToHICON (pWin, GetSystemMetrics(SM_CXSMICON));
609706f2543Smrg
610706f2543Smrg  /* If we got the small, but not the large one swap them */
611706f2543Smrg  if (!hIcon && hSmallIcon)
612706f2543Smrg  {
613706f2543Smrg      hIcon = hSmallIcon;
614706f2543Smrg      hSmallIcon = NULL;
615706f2543Smrg  }
616706f2543Smrg
617706f2543Smrg  /* Use default X icon if no icon loaded from WM_HINTS */
618706f2543Smrg  if (!hIcon) {
619706f2543Smrg    hIcon = g_hIconX;
620706f2543Smrg    hSmallIcon = g_hSmallIconX;
621706f2543Smrg  }
622706f2543Smrg
623706f2543Smrg  if (pIcon)
624706f2543Smrg    *pIcon = hIcon;
625706f2543Smrg  else
626706f2543Smrg    winDestroyIcon(hIcon);
627706f2543Smrg  if (pSmallIcon)
628706f2543Smrg    *pSmallIcon = hSmallIcon;
629706f2543Smrg  else
630706f2543Smrg    winDestroyIcon(hSmallIcon);
631706f2543Smrg}
632706f2543Smrg
633706f2543Smrgvoid winDestroyIcon(HICON hIcon)
634706f2543Smrg{
635706f2543Smrg  /* Delete the icon if its not the default */
636706f2543Smrg  if (hIcon &&
637706f2543Smrg      hIcon != g_hIconX &&
638706f2543Smrg      hIcon != g_hSmallIconX &&
639706f2543Smrg      !winIconIsOverride((unsigned long)hIcon))
640706f2543Smrg    DestroyIcon (hIcon);
641706f2543Smrg}
642706f2543Smrg#endif
643