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