diff options
Diffstat (limited to 'macosx/tkMacOSXBitmap.c')
-rw-r--r-- | macosx/tkMacOSXBitmap.c | 483 |
1 files changed, 334 insertions, 149 deletions
diff --git a/macosx/tkMacOSXBitmap.c b/macosx/tkMacOSXBitmap.c index 82771d4..62faae1 100644 --- a/macosx/tkMacOSXBitmap.c +++ b/macosx/tkMacOSXBitmap.c @@ -4,33 +4,16 @@ * This file handles the implementation of native bitmaps. * * Copyright (c) 1996-1997 Sun Microsystems, Inc. - * Copyright 2001, Apple Computer, Inc. - * Copyright (c) 2006-2007 Daniel A. Steffen <das@users.sourceforge.net> + * Copyright 2001-2009, Apple Inc. + * Copyright (c) 2006-2009 Daniel A. Steffen <das@users.sourceforge.net> * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkMacOSXBitmap.c,v 1.9 2009/02/27 23:23:36 nijtmans Exp $ + * RCS: @(#) $Id: tkMacOSXBitmap.c,v 1.10 2009/06/29 14:35:01 das Exp $ */ -#include "tkMacOSXInt.h" - -/* - * Depending on the resource type there are different ways to - * draw native icons. - */ -#define TYPE1 0 /* Family icon suite. */ -#define TYPE2 1 /* ICON resource. */ -#define TYPE3 2 /* cicn resource. */ - -/* - * This data structure describes the id and type of a given icon. - * It is used as the source for native icons. - */ -typedef struct { - int id; /* Resource Id for Icon. */ - long int type; /* Type of icon. */ -} NativeIcon; +#include "tkMacOSXPrivate.h" /* * This structure holds information about native bitmaps. @@ -38,9 +21,7 @@ typedef struct { typedef struct { const char *name; /* Name of icon. */ - long int type; /* Type of icon. */ - int id; /* Id of icon. */ - int size; /* Size of icon. */ + OSType iconType; /* OSType of icon. */ } BuiltInIcon; /* @@ -49,24 +30,42 @@ typedef struct { */ static BuiltInIcon builtInIcons[] = { - {"document", TYPE1, kGenericDocumentIconResource, 32}, - {"stationery", TYPE1, kGenericStationeryIconResource, 32}, - {"edition", TYPE1, kGenericEditionFileIconResource, 32}, - {"application", TYPE1, kGenericApplicationIconResource, 32}, - {"accessory", TYPE1, kGenericDeskAccessoryIconResource, 32}, - {"folder", TYPE1, kGenericFolderIconResource, 32}, - {"pfolder", TYPE1, kPrivateFolderIconResource, 32}, - {"trash", TYPE1, kTrashIconResource, 32}, - {"floppy", TYPE1, kFloppyIconResource, 32}, - {"ramdisk", TYPE1, kGenericRAMDiskIconResource, 32}, - {"cdrom", TYPE1, kGenericCDROMIconResource, 32}, - {"preferences", TYPE1, kGenericPreferencesIconResource, 32}, - {"querydoc", TYPE1, kGenericQueryDocumentIconResource, 32}, - {"stop", TYPE2, kStopIcon, 32}, - {"note", TYPE2, kNoteIcon, 32}, - {"caution", TYPE2, kCautionIcon, 32}, - {NULL, 0, 0, 0} + {"document", kGenericDocumentIcon}, + {"stationery", kGenericStationeryIcon}, + {"edition", kGenericEditionFileIcon}, + {"application", kGenericApplicationIcon}, + {"accessory", kGenericDeskAccessoryIcon}, + {"folder", kGenericFolderIcon}, + {"pfolder", kPrivateFolderIcon}, + {"trash", kTrashIcon}, + {"floppy", kGenericFloppyIcon}, + {"ramdisk", kGenericRAMDiskIcon}, + {"cdrom", kGenericCDROMIcon}, + {"preferences", kGenericPreferencesIcon}, + {"querydoc", kGenericQueryDocumentIcon}, + {"stop", kAlertStopIcon}, + {"note", kAlertNoteIcon}, + {"caution", kAlertCautionIcon}, + {NULL} }; + +#define builtInIconSize 32 + +static Tcl_HashTable iconBitmapTable = {}; +typedef struct { + int kind, width, height; + char *value; +} IconBitmap; + +static const char *const iconBitmapOptionStrings[] = { + "-file", "-fileType", "-osType", "-systemType", "-namedImage", + "-imageFile", NULL +}; +enum iconBitmapOptions { + ICON_FILE, ICON_FILETYPE, ICON_OSTYPE, ICON_SYSTEMTYPE, ICON_NAMEDIMAGE, + ICON_IMAGEFILE, +}; + /* *---------------------------------------------------------------------- @@ -94,7 +93,7 @@ TkpDefineNativeBitmaps(void) for (builtInPtr = builtInIcons; builtInPtr->name != NULL; builtInPtr++) { Tcl_HashEntry *predefHashPtr; - const char * name; + Tk_Uid name; int isNew; name = Tk_GetUid(builtInPtr->name); @@ -102,14 +101,9 @@ TkpDefineNativeBitmaps(void) if (isNew) { TkPredefBitmap *predefPtr = (TkPredefBitmap *) ckalloc(sizeof(TkPredefBitmap)); - NativeIcon *nativeIconPtr = (NativeIcon *) - ckalloc(sizeof(NativeIcon)); - - nativeIconPtr->id = builtInPtr->id; - nativeIconPtr->type = builtInPtr->type; - predefPtr->source = nativeIconPtr; - predefPtr->width = builtInPtr->size; - predefPtr->height = builtInPtr->size; + predefPtr->source = UINT2PTR(builtInPtr->iconType); + predefPtr->width = builtInIconSize; + predefPtr->height = builtInIconSize; predefPtr->native = 1; Tcl_SetHashValue(predefHashPtr, predefPtr); } @@ -119,17 +113,54 @@ TkpDefineNativeBitmaps(void) /* *---------------------------------------------------------------------- * + * GetBitmapForIcon -- + * + * Results: + * Bitmap for the given IconRef. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static Pixmap +GetBitmapForIcon( + Display *display, + IconRef icon, + CGSize size) +{ + TkMacOSXDrawingContext dc; + Pixmap pixmap; + + pixmap = Tk_GetPixmap(display, None, size.width, size.height, 0); + if (TkMacOSXSetupDrawingContext(pixmap, NULL, 1, &dc)) { + if (dc.context) { + const CGAffineTransform t = { .a = 1, .b = 0, .c = 0, .d = -1, + .tx = 0, .ty = size.height }; + const CGRect r = { .origin = { .x = 0, .y = 0 }, .size = size }; + + CGContextConcatCTM(dc.context, t); + PlotIconRefInContext(dc.context, &r, kAlignAbsoluteCenter, + kTransformNone, NULL, kPlotIconRefNormalFlags, icon); + } + TkMacOSXRestoreDrawingContext(&dc); + } + return pixmap; +} + +/* + *---------------------------------------------------------------------- + * * TkpCreateNativeBitmap -- * - * Add native bitmaps. + * Create native bitmap. * * Results: - * A standard Tcl result. If an error occurs then TCL_ERROR is - * returned and a message is left in the interp's result. + * Native bitmap. * * Side effects: - * "Name" is entered into the bitmap table and may be used from - * here on to refer to the given bitmap. + * None. * *---------------------------------------------------------------------- */ @@ -139,39 +170,56 @@ TkpCreateNativeBitmap( Display *display, const void *source) /* Info about the icon to build. */ { - Pixmap pix; - Rect destRect; - CGrafPtr savePort; - Boolean portChanged; - const NativeIcon *nativeIconPtr; - - pix = Tk_GetPixmap(display, None, 32, 32, 0); - portChanged = QDSwapPort(TkMacOSXGetDrawablePort(pix), &savePort); - - nativeIconPtr = (const NativeIcon *) source; - SetRect(&destRect, 0, 0, 32, 32); - if (nativeIconPtr->type == TYPE1) { - RGBColor white = {0xFFFF, 0xFFFF, 0xFFFF}; + Pixmap pixmap; + IconRef icon; + OSErr err; - RGBForeColor(&white); - PaintRect(&destRect); - PlotIconID(&destRect, atAbsoluteCenter, ttNone, nativeIconPtr->id); - } else if (nativeIconPtr->type == TYPE2) { - Handle icon = GetIcon(nativeIconPtr->id); - - if (icon != NULL) { - RGBColor black = {0, 0, 0}; - - RGBForeColor(&black); - PlotIcon(&destRect, icon); - ReleaseResource(icon); - } + err = ChkErr(GetIconRef, kOnSystemDisk, kSystemIconsCreator, + PTR2UINT(source), &icon); + if (err == noErr) { + pixmap = GetBitmapForIcon(display, icon, CGSizeMake(builtInIconSize, + builtInIconSize)); + ReleaseIconRef(icon); + } else { + pixmap = Tk_GetPixmap(display, None, builtInIconSize, + builtInIconSize, 0); } + return pixmap; +} + +/* + *---------------------------------------------------------------------- + * + * OSTypeFromString -- + * + * Helper to convert string to OSType. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * t is set to OSType if conversion successful. + * + *---------------------------------------------------------------------- + */ - if (portChanged) { - QDSwapPort(savePort, NULL); +static int +OSTypeFromString(const char *s, OSType *t) { + int result = TCL_ERROR; + Tcl_DString ds; + Tcl_Encoding encoding = Tcl_GetEncoding(NULL, "macRoman"); + + Tcl_UtfToExternalDString(encoding, s, -1, &ds); + if (Tcl_DStringLength(&ds) <= 4) { + char string[4] = {}; + memcpy(string, Tcl_DStringValue(&ds), (size_t) Tcl_DStringLength(&ds)); + *t = (OSType) string[0] << 24 | (OSType) string[1] << 16 | + (OSType) string[2] << 8 | (OSType) string[3]; + result = TCL_OK; } - return pix; + Tcl_DStringFree(&ds); + Tcl_FreeEncoding(encoding); + return result; } /* @@ -179,15 +227,19 @@ TkpCreateNativeBitmap( * * TkpGetNativeAppBitmap -- * - * Add native bitmaps. + * Get a named native bitmap. + * + * Attemps to interpret the given name in order as: + * - name defined by ::tk::mac::iconBitmap + * - NSImage named image name + * - NSImage url string + * - 4-char OSType of IconServices icon * * Results: - * A standard Tcl result. If an error occurs then TCL_ERROR is - * returned and a message is left in the interp's result. + * Native bitmap or None. * * Side effects: - * "Name" is entered into the bitmap table and may be used from - * here on to refer to the given bitmap. + * None. * *---------------------------------------------------------------------- */ @@ -199,74 +251,207 @@ TkpGetNativeAppBitmap( int *width, /* The width & height of the bitmap. */ int *height) { - Pixmap pix; - CGrafPtr savePort; - Boolean portChanged; - Rect destRect; - Handle resource; - int type = -1, destWrote; - Str255 nativeName; - Tcl_Encoding encoding; - - /* - * macRoman is the encoding that the resource fork uses. - */ + Tcl_HashEntry *hPtr; + Pixmap pixmap = None; + NSString *string; + NSImage *image = nil; + NSSize size = { .width = builtInIconSize, .height = builtInIconSize }; - encoding = Tcl_GetEncoding(NULL, "macRoman"); - Tcl_UtfToExternal(NULL, encoding, name, strlen(name), 0, NULL, - (char *) &nativeName[1], 255, NULL, &destWrote, NULL); - nativeName[0] = destWrote; - Tcl_FreeEncoding(encoding); - - resource = GetNamedResource('cicn', nativeName); - if (resource != NULL) { - type = TYPE3; + if (iconBitmapTable.buckets && + (hPtr = Tcl_FindHashEntry(&iconBitmapTable, name))) { + OSType type; + IconBitmap *iconBitmap = Tcl_GetHashValue(hPtr); + name = NULL; + size = NSMakeSize(iconBitmap->width, iconBitmap->height); + switch (iconBitmap->kind) { + case ICON_FILE: + string = [[NSString stringWithUTF8String:iconBitmap->value] + stringByExpandingTildeInPath]; + image = [[NSWorkspace sharedWorkspace] iconForFile:string]; + break; + case ICON_FILETYPE: + string = [NSString stringWithUTF8String:iconBitmap->value]; + image = [[NSWorkspace sharedWorkspace] iconForFileType:string]; + break; + case ICON_OSTYPE: + if (OSTypeFromString(iconBitmap->value, &type) == TCL_OK) { + string = NSFileTypeForHFSTypeCode(type); + image = [[NSWorkspace sharedWorkspace] iconForFileType:string]; + } + break; + case ICON_SYSTEMTYPE: + name = iconBitmap->value; + break; + case ICON_NAMEDIMAGE: + string = [NSString stringWithUTF8String:iconBitmap->value]; + image = [NSImage imageNamed:string]; + break; + case ICON_IMAGEFILE: + string = [[NSString stringWithUTF8String:iconBitmap->value] + stringByExpandingTildeInPath]; + image = [[[NSImage alloc] initWithContentsOfFile:string] + autorelease]; + break; + } + if (image) { + [image setSize:size]; + } } else { - resource = GetNamedResource('ICON', nativeName); - if (resource != NULL) { - type = TYPE2; + string = [NSString stringWithUTF8String:name]; + image = [NSImage imageNamed:string]; + if (!image) { + NSURL *url = [NSURL URLWithString:string]; + if (url) { + image = [[[NSImage alloc] initWithContentsOfURL:url] + autorelease]; + } + } + if (image) { + size = [image size]; } } + if (image) { + TkMacOSXDrawingContext dc; + int depth = 0; - if (resource == NULL) { - return (Pixmap) NULL; - } - - pix = Tk_GetPixmap(display, None, 32, 32, 0); - portChanged = QDSwapPort(TkMacOSXGetDrawablePort(pix), &savePort); - - SetRect(&destRect, 0, 0, 32, 32); - if (type == TYPE2) { - RGBColor black = {0, 0, 0}; +#ifdef MAC_OSX_TK_TODO + for (NSImageRep *r in [image representations]) { + NSInteger bitsPerSample = [r bitsPerSample]; + if (bitsPerSample && bitsPerSample > depth) { + depth = bitsPerSample; + }; + } + if (depth == 1) { + /* TODO: convert BW NSImage to CGImageMask */ + } +#endif + pixmap = Tk_GetPixmap(display, None, size.width, size.height, depth); + *width = size.width; + *height = size.height; + if (TkMacOSXSetupDrawingContext(pixmap, NULL, 1, &dc)) { + if (dc.context) { + CGAffineTransform t = { .a = 1, .b = 0, .c = 0, .d = -1, + .tx = 0, .ty = size.height}; - RGBForeColor(&black); - PlotIcon(&destRect, resource); - ReleaseResource(resource); - } else if (type == TYPE3) { - RGBColor white = {0xFFFF, 0xFFFF, 0xFFFF}; - short id; - ResType theType; - Str255 dummy; + CGContextConcatCTM(dc.context, t); + [NSGraphicsContext saveGraphicsState]; + [NSGraphicsContext setCurrentContext:[NSGraphicsContext + graphicsContextWithGraphicsPort:dc.context flipped:NO]]; + [image drawAtPoint:NSZeroPoint fromRect:NSZeroRect + operation:NSCompositeCopy fraction:1.0]; + [NSGraphicsContext restoreGraphicsState]; + } + TkMacOSXRestoreDrawingContext(&dc); + } + } else if (name) { + OSType iconType; + if (OSTypeFromString(name, &iconType) == TCL_OK) { + IconRef icon; + OSErr err = ChkErr(GetIconRef, kOnSystemDisk, kSystemIconsCreator, + iconType, &icon); + if (err == noErr) { + pixmap = GetBitmapForIcon(display, icon, NSSizeToCGSize(size)); + *width = size.width; + *height = size.height; + ReleaseIconRef(icon); + } + } + } + return pixmap; +} + +/* + *---------------------------------------------------------------------- + * + * TkMacOSXIconBitmapObjCmd -- + * + * Implements the ::tk::mac::iconBitmap command. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * none + * + *---------------------------------------------------------------------- + */ - /* - * We need to first paint the background white. Also, for some reason - * we *must* use GetCIcon instead of GetNamedResource for PlotCIcon to - * work - so we use GetResInfo to get the id. - */ +int +TkMacOSXIconBitmapObjCmd( + ClientData clientData, /* Unused. */ + Tcl_Interp *interp, /* Current interpreter. */ + int objc, /* Number of arguments. */ + Tcl_Obj *const objv[]) /* Argument objects. */ +{ + Tcl_HashEntry *hPtr; + int i = 1, len, isNew, result = TCL_ERROR; + const char *name, *value; + IconBitmap ib, *iconBitmap; - RGBForeColor(&white); - PaintRect(&destRect); - GetResInfo(resource, &id, &theType, dummy); - ReleaseResource(resource); - resource = (Handle) GetCIcon(id); - PlotCIcon(&destRect, (CIconHandle) resource); - DisposeCIcon((CIconHandle) resource); + if (objc != 6) { + Tcl_WrongNumArgs(interp, 1, objv, "name width height " + "-file|-fileType|-osType|-systemType|-namedImage|-imageFile " + "value"); + goto end; } - - *width = 32; - *height = 32; - if (portChanged) { - QDSwapPort(savePort, NULL); + name = Tcl_GetStringFromObj(objv[i++], &len); + if (!len) { + Tcl_AppendResult(interp, "empty bitmap name", NULL); + goto end; + } + if (Tcl_GetIntFromObj(interp, objv[i++], &ib.width) != TCL_OK) { + goto end; + } + if (Tcl_GetIntFromObj(interp, objv[i++], &ib.height) != TCL_OK) { + goto end; + } + if (Tcl_GetIndexFromObj(interp, objv[i++], iconBitmapOptionStrings, + "kind", TCL_EXACT, &ib.kind) != TCL_OK) { + goto end; + } + value = Tcl_GetStringFromObj(objv[i++], &len); + if (!len) { + Tcl_AppendResult(interp, "empty bitmap value", NULL); + goto end; + } +#if 0 + if ((kind == ICON_TYPE || kind == ICON_SYSTEM)) { + Tcl_DString ds; + Tcl_Encoding encoding = Tcl_GetEncoding(NULL, "macRoman"); + Tcl_UtfToExternalDString(encoding, value, -1, &ds); + len = Tcl_DStringLength(&ds); + Tcl_DStringFree(&ds); + Tcl_FreeEncoding(encoding); + if (len > 4) { + Tcl_AppendResult(interp, "invalid bitmap value", NULL); + goto end; + } } - return pix; +#endif + ib.value = ckalloc(len); + strcpy(ib.value, value); + if (!iconBitmapTable.buckets) { + Tcl_InitHashTable(&iconBitmapTable, TCL_STRING_KEYS); + } + hPtr = Tcl_CreateHashEntry(&iconBitmapTable, name, &isNew); + if (!isNew) { + iconBitmap = Tcl_GetHashValue(hPtr); + ckfree(iconBitmap->value); + } else { + iconBitmap = (IconBitmap *) ckalloc(sizeof(IconBitmap)); + Tcl_SetHashValue(hPtr, iconBitmap); + } + *iconBitmap = ib; + result = TCL_OK; +end: + return result; } + +/* + * Local Variables: + * mode: c + * c-basic-offset: 4 + * fill-column: 79 + * coding: utf-8 + * End: + */ |