winmultiwindowicons.c revision 05b261ec
1/*
2 *Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved.
3 *
4 *Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files (the
6 *"Software"), to deal in the Software without restriction, including
7 *without limitation the rights to use, copy, modify, merge, publish,
8 *distribute, sublicense, and/or sell copies of the Software, and to
9 *permit persons to whom the Software is furnished to do so, subject to
10 *the following conditions:
11 *
12 *The above copyright notice and this permission notice shall be
13 *included in all copies or substantial portions of the Software.
14 *
15 *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 *EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 *MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 *NONINFRINGEMENT. IN NO EVENT SHALL THE XFREE86 PROJECT BE LIABLE FOR
19 *ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
20 *CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21 *WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 *
23 *Except as contained in this notice, the name of the XFree86 Project
24 *shall not be used in advertising or otherwise to promote the sale, use
25 *or other dealings in this Software without prior written authorization
26 *from the XFree86 Project.
27 *
28 * Authors:	Earle F. Philhower, III
29 */
30
31#ifdef HAVE_XWIN_CONFIG_H
32#include <xwin-config.h>
33#endif
34#include "win.h"
35#include "dixevents.h"
36#include "winmultiwindowclass.h"
37#include "winprefs.h"
38
39
40/*
41 * External global variables
42 */
43
44extern HICON		g_hIconX;
45extern HICON		g_hSmallIconX;
46
47
48/*
49 * Prototypes for local functions
50 */
51
52static void
53winScaleXBitmapToWindows (int iconSize, int effBPP,
54			  PixmapPtr pixmap, unsigned char *image);
55
56
57/*
58 * Scale an X icon bitmap into a Windoze icon bitmap
59 */
60
61static void
62winScaleXBitmapToWindows (int iconSize,
63			  int effBPP,
64			  PixmapPtr pixmap,
65			  unsigned char *image)
66{
67  int			row, column, effXBPP, effXDepth;
68  unsigned char		*outPtr;
69  unsigned char		*iconData = 0;
70  int			stride, xStride;
71  float			factX, factY;
72  int			posX, posY;
73  unsigned char		*ptr;
74  unsigned int		zero;
75  unsigned int		color;
76
77  effXBPP = BitsPerPixel(pixmap->drawable.depth);
78  effXDepth = pixmap->drawable.depth;
79
80  if (pixmap->drawable.bitsPerPixel == 15)
81    effXBPP = 16;
82
83  if (pixmap->drawable.depth == 15)
84    effXDepth = 16;
85
86  /* Need 32-bit aligned rows */
87  stride = ((iconSize * effBPP + 31) & (~31)) / 8;
88  xStride = PixmapBytePad (pixmap->drawable.width, pixmap->drawable.depth);
89  if (stride == 0 || xStride == 0)
90    {
91      ErrorF ("winScaleXBitmapToWindows - stride or xStride is zero.  "
92	      "Bailing.\n");
93      return;
94    }
95
96  /* Allocate memory for icon data */
97  iconData = malloc (xStride * pixmap->drawable.height);
98  if (!iconData)
99    {
100      ErrorF ("winScaleXBitmapToWindows - malloc failed for iconData.  "
101	      "Bailing.\n");
102      return;
103    }
104
105  /* Get icon data */
106  miGetImage ((DrawablePtr) &(pixmap->drawable), 0, 0,
107	      pixmap->drawable.width, pixmap->drawable.height,
108	      ZPixmap, 0xffffffff, iconData);
109
110  /* Keep aspect ratio */
111  factX = ((float)pixmap->drawable.width) / ((float)iconSize);
112  factY = ((float)pixmap->drawable.height) / ((float)iconSize);
113  if (factX > factY)
114    factY = factX;
115  else
116    factX = factY;
117
118  /* Out-of-bounds, fill icon with zero */
119  zero = 0;
120
121  for (row = 0; row < iconSize; row++)
122    {
123      outPtr = image + stride * row;
124      for (column = 0; column < iconSize; column++)
125	{
126	  posX = factX * column;
127	  posY = factY * row;
128
129	  ptr = iconData + posY*xStride;
130	  if (effXBPP == 1)
131	    {
132	      ptr += posX / 8;
133
134	      /* Out of X icon bounds, leave space blank */
135	      if (posX >= pixmap->drawable.width
136		  || posY >= pixmap->drawable.height)
137		ptr = (unsigned char *) &zero;
138
139	      if ((*ptr) & (1 << (posX & 7)))
140		switch (effBPP)
141		  {
142		  case 32:
143		    *(outPtr++) = 0;
144		  case 24:
145		    *(outPtr++) = 0;
146		  case 16:
147		    *(outPtr++) = 0;
148		  case 8:
149		    *(outPtr++) = 0;
150		    break;
151		  case 1:
152		    outPtr[column / 8] &= ~(1 << (7 - (column & 7)));
153		    break;
154		  }
155	      else
156		switch (effBPP)
157		  {
158		  case 32:
159		    *(outPtr++) = 255;
160		    *(outPtr++) = 255;
161		    *(outPtr++) = 255;
162		    *(outPtr++) = 0;
163		    break;
164		  case 24:
165		    *(outPtr++) = 255;
166		  case 16:
167		    *(outPtr++) = 255;
168		  case 8:
169		    *(outPtr++) = 255;
170		    break;
171		  case 1:
172		    outPtr[column / 8] |= (1 << (7 - (column & 7)));
173		    break;
174		  }
175	    }
176	  else if (effXDepth == 24 || effXDepth == 32)
177	    {
178	      ptr += posX * (effXBPP / 8);
179
180	      /* Out of X icon bounds, leave space blank */
181	      if (posX >= pixmap->drawable.width
182		  || posY >= pixmap->drawable.height)
183		ptr = (unsigned char *) &zero;
184	      color = (((*ptr) << 16)
185		       + ((*(ptr + 1)) << 8)
186		       + ((*(ptr + 2)) << 0));
187	      switch (effBPP)
188		{
189		case 32:
190		  *(outPtr++) = *(ptr++); // b
191		  *(outPtr++) = *(ptr++); // g
192		  *(outPtr++) = *(ptr++); // r
193		  *(outPtr++) = 0; // resvd
194		  break;
195		case 24:
196		  *(outPtr++) = *(ptr++);
197		  *(outPtr++) = *(ptr++);
198		  *(outPtr++) = *(ptr++);
199		  break;
200		case 16:
201		  color = ((((*ptr) >> 2) << 10)
202			   + (((*(ptr + 1)) >> 2) << 5)
203			   + (((*(ptr + 2)) >> 2)));
204		  *(outPtr++) = (color >> 8);
205		  *(outPtr++) = (color & 255);
206		  break;
207		case 8:
208		  color = (((*ptr))) + (((*(ptr + 1)))) + (((*(ptr + 2))));
209		  color /= 3;
210		  *(outPtr++) = color;
211		  break;
212		case 1:
213		  if (color)
214		    outPtr[column / 8] |= (1 << (7 - (column & 7)));
215		  else
216		    outPtr[column / 8] &= ~(1 << (7 - (column & 7)));
217		}
218	    }
219	  else if (effXDepth == 16)
220	    {
221	      ptr += posX * (effXBPP / 8);
222
223	      /* Out of X icon bounds, leave space blank */
224	      if (posX >= pixmap->drawable.width
225		  || posY >= pixmap->drawable.height)
226		ptr = (unsigned char *) &zero;
227	      color = ((*ptr) << 8) + (*(ptr + 1));
228	      switch (effBPP)
229		{
230		case 32:
231		  *(outPtr++) = (color & 31) << 2;
232		  *(outPtr++) = ((color >> 5) & 31) << 2;
233		  *(outPtr++) = ((color >> 10) & 31) << 2;
234		  *(outPtr++) = 0; // resvd
235		  break;
236		case 24:
237		  *(outPtr++) = (color & 31) << 2;
238		  *(outPtr++) = ((color >> 5) & 31) << 2;
239		  *(outPtr++) = ((color >> 10) & 31) << 2;
240		  break;
241		case 16:
242		  *(outPtr++) = *(ptr++);
243		  *(outPtr++) = *(ptr++);
244		  break;
245		case 8:
246		  *(outPtr++) = (((color & 31)
247				  + ((color >> 5) & 31)
248				  + ((color >> 10) & 31)) / 3) << 2;
249		  break;
250		case 1:
251		  if (color)
252		    outPtr[column / 8] |= (1 << (7 - (column & 7)));
253		  else
254		    outPtr[column / 8] &= ~(1 << (7 - (column & 7)));
255		  break;
256		} /* end switch(effbpp) */
257	    } /* end if effxbpp==16) */
258	} /* end for column */
259    } /* end for row */
260  free (iconData);
261}
262
263
264/*
265 * Attempt to create a custom icon from the WM_HINTS bitmaps
266 */
267
268HICON
269winXIconToHICON (WindowPtr pWin, int iconSize)
270{
271  unsigned char		*mask, *image, *imageMask;
272  unsigned char		*dst, *src;
273  PixmapPtr		iconPtr;
274  PixmapPtr		maskPtr;
275  int			planes, bpp, effBPP, stride, maskStride, i;
276  HDC			hDC;
277  ICONINFO		ii;
278  WinXWMHints		hints;
279  HICON			hIcon;
280
281  winMultiWindowGetWMHints (pWin, &hints);
282  if (!hints.icon_pixmap) return NULL;
283
284  iconPtr = (PixmapPtr) LookupIDByType (hints.icon_pixmap, RT_PIXMAP);
285
286  if (!iconPtr) return NULL;
287
288  hDC = GetDC (GetDesktopWindow ());
289  planes = GetDeviceCaps (hDC, PLANES);
290  bpp = GetDeviceCaps (hDC, BITSPIXEL);
291  ReleaseDC (GetDesktopWindow (), hDC);
292
293  /* 15 BPP is really 16BPP as far as we care */
294  if (bpp == 15)
295    effBPP = 16;
296  else
297    effBPP = bpp;
298
299  /* Need 32-bit aligned rows */
300  stride = ((iconSize * effBPP + 31) & (~31)) / 8;
301
302  /* Mask is 1-bit deep */
303  maskStride = ((iconSize * 1 + 31) & (~31)) / 8;
304
305  image = (unsigned char * ) malloc (stride * iconSize);
306  imageMask = (unsigned char *) malloc (stride * iconSize);
307  mask = (unsigned char *) malloc (maskStride * iconSize);
308
309  /* Default to a completely black mask */
310  memset (mask, 0, maskStride * iconSize);
311
312  winScaleXBitmapToWindows (iconSize, effBPP, iconPtr, image);
313  maskPtr = (PixmapPtr) LookupIDByType (hints.icon_mask, RT_PIXMAP);
314
315  if (maskPtr)
316    {
317      winScaleXBitmapToWindows (iconSize, 1, maskPtr, mask);
318
319      winScaleXBitmapToWindows (iconSize, effBPP, maskPtr, imageMask);
320
321      /* Now we need to set all bits of the icon which are not masked */
322      /* on to 0 because Color is really an XOR, not an OR function */
323      dst = image;
324      src = imageMask;
325
326      for (i = 0; i < (stride * iconSize); i++)
327	if ((*(src++)))
328	  *(dst++) = 0;
329	else
330	  dst++;
331    }
332
333  ii.fIcon = TRUE;
334  ii.xHotspot = 0; /* ignored */
335  ii.yHotspot = 0; /* ignored */
336
337  /* Create Win32 mask from pixmap shape */
338  ii.hbmMask = CreateBitmap (iconSize, iconSize, planes, 1, mask);
339
340  /* Create Win32 bitmap from pixmap */
341  ii.hbmColor = CreateBitmap (iconSize, iconSize, planes, bpp, image);
342
343  /* Merge Win32 mask and bitmap into icon */
344  hIcon = CreateIconIndirect (&ii);
345
346  /* Release Win32 mask and bitmap */
347  DeleteObject (ii.hbmMask);
348  DeleteObject (ii.hbmColor);
349
350  /* Free X mask and bitmap */
351  free (mask);
352  free (image);
353  free (imageMask);
354
355  return hIcon;
356}
357
358
359
360/*
361 * Change the Windows window icon
362 */
363
364#ifdef XWIN_MULTIWINDOW
365void
366winUpdateIcon (Window id)
367{
368  WindowPtr		pWin;
369  HICON			hIcon, hiconOld;
370
371  pWin = (WindowPtr) LookupIDByType (id, RT_WINDOW);
372  if (!pWin) return;
373  hIcon = (HICON)winOverrideIcon ((unsigned long)pWin);
374
375  if (!hIcon)
376    hIcon = winXIconToHICON (pWin, GetSystemMetrics(SM_CXICON));
377
378  if (hIcon)
379    {
380      winWindowPriv(pWin);
381
382      if (pWinPriv->hWnd)
383	{
384	  hiconOld = (HICON) SetClassLong (pWinPriv->hWnd,
385					   GCL_HICON,
386					   (int) hIcon);
387
388	  /* Delete the icon if its not the default */
389	  winDestroyIcon(hiconOld);
390	}
391    }
392
393  hIcon = winXIconToHICON (pWin, GetSystemMetrics(SM_CXSMICON));
394  if (hIcon)
395    {
396      winWindowPriv(pWin);
397
398      if (pWinPriv->hWnd)
399	{
400	  hiconOld = (HICON) SetClassLong (pWinPriv->hWnd,
401					   GCL_HICONSM,
402					   (int) hIcon);
403	  winDestroyIcon (hiconOld);
404	}
405    }
406}
407
408void winInitGlobalIcons (void)
409{
410  int sm_cx = GetSystemMetrics(SM_CXICON);
411  int sm_cxsm = GetSystemMetrics(SM_CXSMICON);
412  /* Load default X icon in case it's not ready yet */
413  if (!g_hIconX)
414    {
415      g_hIconX = (HICON)winOverrideDefaultIcon(sm_cx);
416      g_hSmallIconX = (HICON)winOverrideDefaultIcon(sm_cxsm);
417    }
418
419  if (!g_hIconX)
420    {
421      g_hIconX = (HICON)LoadImage (g_hInstance,
422	      MAKEINTRESOURCE(IDI_XWIN),
423	      IMAGE_ICON,
424	      GetSystemMetrics(SM_CXICON),
425	      GetSystemMetrics(SM_CYICON),
426	      0);
427      g_hSmallIconX = (HICON)LoadImage (g_hInstance,
428	      MAKEINTRESOURCE(IDI_XWIN),
429	      IMAGE_ICON,
430	      GetSystemMetrics(SM_CXSMICON),
431	      GetSystemMetrics(SM_CYSMICON),
432	      LR_DEFAULTSIZE);
433    }
434}
435
436void winSelectIcons(WindowPtr pWin, HICON *pIcon, HICON *pSmallIcon)
437{
438  HICON hIcon, hSmallIcon;
439
440  winInitGlobalIcons();
441
442  /* Try and get the icon from WM_HINTS */
443  hIcon = winXIconToHICON (pWin, GetSystemMetrics(SM_CXICON));
444  hSmallIcon = winXIconToHICON (pWin, GetSystemMetrics(SM_CXSMICON));
445
446  /* If we got the small, but not the large one swap them */
447  if (!hIcon && hSmallIcon)
448  {
449      hIcon = hSmallIcon;
450      hSmallIcon = NULL;
451  }
452
453  /* Use default X icon if no icon loaded from WM_HINTS */
454  if (!hIcon) {
455    hIcon = g_hIconX;
456    hSmallIcon = g_hSmallIconX;
457  }
458
459  if (pIcon)
460    *pIcon = hIcon;
461  else
462    winDestroyIcon(hIcon);
463  if (pSmallIcon)
464    *pSmallIcon = hSmallIcon;
465  else
466    winDestroyIcon(hSmallIcon);
467}
468
469void winDestroyIcon(HICON hIcon)
470{
471  /* Delete the icon if its not the default */
472  if (hIcon &&
473      hIcon != g_hIconX &&
474      hIcon != g_hSmallIconX &&
475      !winIconIsOverride((unsigned long)hIcon))
476    DestroyIcon (hIcon);
477}
478#endif
479