Fixed bug #208
authorSam Lantinga <slouken@libsdl.org>
Thu, 11 May 2006 03:45:55 +0000
changeset 18129c882e94b545
parent 1811 e6de7e5fd451
child 1813 a7cda692b681
Fixed bug #208

So, here's a patch with a reimplementation of QZ_SetIcon() that does what I
described above. I apologize for the delay, I've been quite busy in the last
few days.

It appears to work here on 10.4.5 PPC in the limited testing that I've done;
I'll try to test it on 10.3.9 and 10.2.8 as well, but that might take another
week or so. Please test on i386.

Regarding alpha channels, per-surface alpha, and color keys, the same semantics
as for regular blits to an RGB surface should apply (for the final icon
composited onto the dock), unless I made a mistake - except in one pathological
case: if the icon surface has an alpha channel, its SDL_SRCALPHA flag is not
set (i.e. it has been explicitly cleared, since it's on by default for RGBA
surfaces), and it has a color key, plus an explicit mask was specified (instead
of the one autogenerated from the colorkey), then the color-keyed areas appear
black instead of transparent. I found no elegant way of fixing this, was too
lazy to implement the inelegant one, and decided that it isn't worth the effort
(but if someone disagrees, I can do it).
src/video/quartz/SDL_QuartzWM.m
     1.1 --- a/src/video/quartz/SDL_QuartzWM.m	Thu May 11 03:21:54 2006 +0000
     1.2 +++ b/src/video/quartz/SDL_QuartzWM.m	Thu May 11 03:45:55 2006 +0000
     1.3 @@ -262,68 +262,67 @@
     1.4      NSBitmapImageRep *imgrep;
     1.5      NSImage *img;
     1.6      SDL_Surface *mergedSurface;
     1.7 -    int i,j;
     1.8      NSAutoreleasePool *pool;
     1.9 -    SDL_Rect rrect;
    1.10 -    NSSize imgSize = {icon->w, icon->h};
    1.11 +    Uint8 *pixels;
    1.12 +    SDL_bool iconSrcAlpha;
    1.13 +    Uint8 iconAlphaValue;
    1.14 +    int i, j, maskPitch, index;
    1.15      
    1.16      pool = [ [ NSAutoreleasePool alloc ] init ];
    1.17 -    SDL_GetClipRect(icon, &rrect);
    1.18      
    1.19 -    /* create a big endian RGBA surface */
    1.20 -    mergedSurface = SDL_CreateRGBSurface(SDL_SWSURFACE|SDL_SRCALPHA, 
    1.21 -                    icon->w, icon->h, 32, 0xff<<24, 0xff<<16, 0xff<<8, 0xff<<0);
    1.22 -    if (mergedSurface==NULL) {
    1.23 -        NSLog(@"Error creating surface for merge");
    1.24 -        goto freePool;
    1.25 -    }
    1.26 +    imgrep = [ [ [ NSBitmapImageRep alloc ] initWithBitmapDataPlanes: NULL pixelsWide: icon->w pixelsHigh: icon->h bitsPerSample: 8 samplesPerPixel: 4 hasAlpha: YES isPlanar: NO colorSpaceName: NSDeviceRGBColorSpace bytesPerRow: 4*icon->w bitsPerPixel: 32 ] autorelease ];
    1.27 +    if (imgrep == nil) goto freePool;
    1.28 +    pixels = [ imgrep bitmapData ];
    1.29 +    SDL_memset(pixels, 0, 4*icon->w*icon->h); /* make the background, which will survive in colorkeyed areas, completely transparent */
    1.30      
    1.31 -    if (mergedSurface->pitch != 
    1.32 -        mergedSurface->format->BytesPerPixel * mergedSurface->w) {
    1.33 -        SDL_SetError ("merged surface has wrong format");
    1.34 -        SDL_FreeSurface (mergedSurface);
    1.35 -        goto freePool;
    1.36 -    }
    1.37 +#if SDL_BYTEORDER == SDL_BIG_ENDIAN
    1.38 +#define BYTEORDER_DEPENDENT_RGBA_MASKS 0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF
    1.39 +#else
    1.40 +#define BYTEORDER_DEPENDENT_RGBA_MASKS 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000
    1.41 +#endif
    1.42 +    mergedSurface = SDL_CreateRGBSurfaceFrom(pixels, icon->w, icon->h, 32, 4*icon->w, BYTEORDER_DEPENDENT_RGBA_MASKS);
    1.43 +    if (mergedSurface == NULL) goto freePool;
    1.44      
    1.45 -    if (SDL_BlitSurface(icon,&rrect,mergedSurface,&rrect)) {
    1.46 -        NSLog(@"Error blitting to mergedSurface");
    1.47 -        goto freePool;
    1.48 -    }
    1.49 +    /* blit, with temporarily cleared SRCALPHA flag because we want to copy, not alpha-blend */
    1.50 +    iconSrcAlpha = ((icon->flags & SDL_SRCALPHA) != 0);
    1.51 +    iconAlphaValue = icon->format->alpha;
    1.52 +    SDL_SetAlpha(icon, 0, 255);
    1.53 +    SDL_BlitSurface(icon, NULL, mergedSurface, NULL);
    1.54 +    if (iconSrcAlpha) SDL_SetAlpha(icon, SDL_SRCALPHA, iconAlphaValue);
    1.55      
    1.56 -    if (mask) {
    1.57 -
    1.58 -        Uint32 *pixels = mergedSurface->pixels;
    1.59 -        for (i = 0; i < mergedSurface->h; i++) {
    1.60 -            for (j = 0; j < mergedSurface->w; j++) {
    1.61 -                
    1.62 -                int index = i * mergedSurface->w + j;
    1.63 -                int mindex = index >> 3;
    1.64 -                int bindex = 7 - (index & 0x7);
    1.65 -                
    1.66 -                if (mask[mindex] & (1 << bindex))
    1.67 -                    pixels[index] |= 0x000000FF;
    1.68 -                else
    1.69 -                    pixels[index] &= 0xFFFFFF00;
    1.70 +    SDL_FreeSurface(mergedSurface);
    1.71 +    
    1.72 +    /* apply mask, source alpha, and premultiply color values by alpha */
    1.73 +    maskPitch = (icon->w+7)/8;
    1.74 +    for (i = 0; i < icon->h; i++) {
    1.75 +        for (j = 0; j < icon->w; j++) {
    1.76 +            index = i*4*icon->w + j*4;
    1.77 +            if (!(mask[i*maskPitch + j/8] & (128 >> j%8))) {
    1.78 +                pixels[index + 3] = 0;
    1.79 +            }
    1.80 +            else {
    1.81 +                if (iconSrcAlpha) {
    1.82 +                    if (icon->format->Amask == 0) pixels[index + 3] = icon->format->alpha;
    1.83 +                }
    1.84 +                else {
    1.85 +                    pixels[index + 3] = 255;
    1.86 +                }
    1.87 +            }
    1.88 +            if (pixels[index + 3] < 255) {
    1.89 +                pixels[index + 0] = (Uint16)pixels[index + 0]*pixels[index + 3]/255;
    1.90 +                pixels[index + 1] = (Uint16)pixels[index + 1]*pixels[index + 3]/255;
    1.91 +                pixels[index + 2] = (Uint16)pixels[index + 2]*pixels[index + 3]/255;
    1.92              }
    1.93          }
    1.94      }
    1.95      
    1.96 -    imgrep = [ [ NSBitmapImageRep alloc] 
    1.97 -                    initWithBitmapDataPlanes:(unsigned char **)&mergedSurface->pixels 
    1.98 -                        pixelsWide:icon->w pixelsHigh:icon->h bitsPerSample:8 samplesPerPixel:4 
    1.99 -                        hasAlpha:YES isPlanar:NO colorSpaceName:NSDeviceRGBColorSpace 
   1.100 -                        bytesPerRow:icon->w<<2 bitsPerPixel:32 ];
   1.101 -    
   1.102 -    img = [ [ NSImage alloc ] initWithSize:imgSize ];
   1.103 -    
   1.104 +    img = [ [ [ NSImage alloc ] initWithSize: NSMakeSize(icon->w, icon->h) ] autorelease ];
   1.105 +    if (img == nil) goto freePool;
   1.106      [ img addRepresentation: imgrep ];
   1.107      [ NSApp setApplicationIconImage:img ];
   1.108      
   1.109 -    [ img release ];
   1.110 -    [ imgrep release ];
   1.111 -    SDL_FreeSurface(mergedSurface);
   1.112  freePool:
   1.113 -    [pool release];
   1.114 +    [ pool release ];
   1.115  }
   1.116  
   1.117  int  QZ_IconifyWindow (_THIS) {