summaryrefslogtreecommitdiffstats
path: root/macosx/tkMacOSXColor.c
diff options
context:
space:
mode:
Diffstat (limited to 'macosx/tkMacOSXColor.c')
-rw-r--r--macosx/tkMacOSXColor.c461
1 files changed, 228 insertions, 233 deletions
diff --git a/macosx/tkMacOSXColor.c b/macosx/tkMacOSXColor.c
index 4150846..3380087 100644
--- a/macosx/tkMacOSXColor.c
+++ b/macosx/tkMacOSXColor.c
@@ -7,8 +7,8 @@
*
* Copyright (c) 1990-1994 The Regents of the University of California.
* Copyright (c) 1994-1996 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.
@@ -17,11 +17,6 @@
#include "tkMacOSXPrivate.h"
#include "tkColor.h"
-#if MAC_OS_X_VERSION_MIN_REQUIRED < 1040
-/* Undocumented CG API for creating CGPattern from CGImage */
-extern CGPatternRef CGPatternCreateWithImage(CGImageRef img, int i) WEAK_IMPORT_ATTRIBUTE;
-#endif
-
struct SystemColorMapEntry {
const char *name;
ThemeBrush brush;
@@ -176,7 +171,7 @@ static const struct SystemColorMapEntry systemColorMap[] = {
{ NULL, 0, 0, 0 }
};
#define MAX_PIXELCODE 165
-
+
/*
*----------------------------------------------------------------------
*
@@ -202,7 +197,7 @@ GetThemeFromPixelCode(
ThemeTextColor *textColor,
ThemeBackgroundKind *background)
{
- if (code >= MIN_PIXELCODE && code <= MAX_PIXELCODE && code != PIXEL_MAGIC) {
+ if (code >= MIN_PIXELCODE && code <= MAX_PIXELCODE) {
*brush = systemColorMap[code - MIN_PIXELCODE].brush;
*textColor = systemColorMap[code - MIN_PIXELCODE].textColor;
*background = systemColorMap[code - MIN_PIXELCODE].background;
@@ -211,7 +206,8 @@ GetThemeFromPixelCode(
*textColor = 0;
*background = 0;
}
- if (!*brush && !*textColor && !*background && code != PIXEL_MAGIC) {
+ if (!*brush && !*textColor && !*background && code != PIXEL_MAGIC &&
+ code != TRANSPARENT_PIXEL) {
return false;
} else {
return true;
@@ -240,23 +236,45 @@ GetThemeColor(
ThemeBrush brush,
ThemeTextColor textColor,
ThemeBackgroundKind background,
- RGBColor *c)
+ CGColorRef *c)
{
OSStatus err = noErr;
if (brush) {
- err = ChkErr(GetThemeBrushAsColor,
- brush == kThemeBrushMenuBackgroundSelected ?
- kThemeBrushFocusHighlight : brush, 32, true, c);
- } else if (textColor) {
- err = ChkErr(GetThemeTextColor, textColor, 32, true, c);
+ err = ChkErr(HIThemeBrushCreateCGColor, brush, c);
+ /*} else if (textColor) {
+ err = ChkErr(GetThemeTextColor, textColor, 32, true, c);*/
} else {
- c->red = (pixel >> 16) & 0xff;
- c->green = (pixel >> 8) & 0xff;
- c->blue = (pixel ) & 0xff;
- c->red |= c->red << 8;
- c->green |= c->green << 8;
- c->blue |= c->blue << 8;
+ CGFloat rgba[4] = {0, 0, 0, 1};
+
+ switch ((pixel >> 24) & 0xff) {
+ case PIXEL_MAGIC: {
+ unsigned short red, green, blue;
+ red = (pixel >> 16) & 0xff;
+ green = (pixel >> 8) & 0xff;
+ blue = (pixel ) & 0xff;
+ red |= red << 8;
+ green |= green << 8;
+ blue |= blue << 8;
+ rgba[0] = red / 65535.0;
+ rgba[1] = green / 65535.0;
+ rgba[2] = blue / 65535.0;
+ break;
+ }
+ case TRANSPARENT_PIXEL:
+ rgba[3] = 0.0;
+ break;
+ }
+
+ // this attempts to find something roughly fitting for any display
+// *c = CGColorCreateGenericRGB(rgba[0], rgba[1], rgba[2], rgba[3]);
+
+ // may be off for non-main display but in most cases better than prev
+ static CGColorSpaceRef deviceRGBSpace = NULL;
+ if (!deviceRGBSpace) {
+ deviceRGBSpace = CGDisplayCopyColorSpace(CGMainDisplayID());
+ }
+ *c = CGColorCreate(deviceRGBSpace, rgba );
}
return err;
}
@@ -266,14 +284,14 @@ GetThemeColor(
*
* TkSetMacColor --
*
- * Populates a Macintosh RGBColor structure from a X style
- * pixel value.
+ * Creates a CGColorRef from a X style pixel value.
*
* Results:
* Returns false if not a real pixel, true otherwise.
*
* Side effects:
- * The variable macColor is updated to the pixels value.
+ * The variable macColor is set to a new CGColorRef, the caller is
+ * responsible for releasing it!
*
*----------------------------------------------------------------------
*/
@@ -281,8 +299,9 @@ GetThemeColor(
int
TkSetMacColor(
unsigned long pixel, /* Pixel value to convert. */
- RGBColor *macColor) /* Mac color struct to modify. */
+ void *macColor) /* CGColorRef to modify. */
{
+ CGColorRef *color = (CGColorRef*)macColor;
OSStatus err = -1;
ThemeBrush brush;
ThemeTextColor textColor;
@@ -291,7 +310,7 @@ TkSetMacColor(
if (GetThemeFromPixelCode((pixel >> 24) & 0xff, &brush, &textColor,
&background)) {
err = ChkErr(GetThemeColor, pixel, brush, textColor, background,
- macColor);
+ color);
}
return (err == noErr);
}
@@ -299,81 +318,149 @@ TkSetMacColor(
/*
*----------------------------------------------------------------------
*
- * TkMacOSXSetColorInPort --
+ * TkpInitGCCache, TkpFreeGCCache, CopyCachedColor, SetCachedColor --
*
- * Sets fore or back color in the given QD port from an X pixel
- * value, and if the pixel code indicates a system color, sets
- * the corresponding brush, textColor or background via
- * Appearance mgr APIs.
+ * Maintain a per-GC cache of previously converted CGColorRefs
*
* Results:
- * None.
+ * None resp. retained CGColorRef for CopyCachedColor()
*
* Side effects:
- * If penPat is non-NULL it is set to the forground color/pattern.
+ * None.
*
*----------------------------------------------------------------------
*/
void
-TkMacOSXSetColorInPort(
- unsigned long pixel,
- int fg,
- PixPatHandle penPat,
- CGrafPtr port)
+TkpInitGCCache(
+ GC gc)
{
- OSStatus err;
- RGBColor c;
- ThemeBrush brush;
- ThemeTextColor textColor;
- ThemeBackgroundKind background;
- int setPenPat = 0;
+ bzero(TkpGetGCCache(gc), sizeof(TkpGCCache));
+}
- if (GetThemeFromPixelCode((pixel >> 24) & 0xff, &brush, &textColor,
- &background)) {
- CGrafPtr savePort;
- Boolean portChanged;
+void
+TkpFreeGCCache(
+ GC gc)
+{
+ TkpGCCache *gcCache = TkpGetGCCache(gc);
- portChanged = QDSwapPort(port, &savePort);
- err = ChkErr(GetThemeColor, pixel, brush, textColor, background, &c);
- if (err == noErr) {
- if (fg) {
- RGBForeColor(&c);
- if (penPat) {
- MakeRGBPat(penPat, &c);
- setPenPat = 1;
- }
- } else {
- RGBBackColor(&c);
- }
- }
- err = -1;
- if (brush) {
- err = ChkErr(SetThemeBackground,
- brush == kThemeBrushMenuBackgroundSelected ?
- kThemeBrushFocusHighlight : brush, 32, true);
- } else if (textColor && fg) {
- err = ChkErr(SetThemeTextColor, textColor, 32, true);
- } else if (background) {
- Rect bounds;
+ if (gcCache->cachedForegroundColor) {
+ CFRelease(gcCache->cachedForegroundColor);
+ }
+ if (gcCache->cachedBackgroundColor) {
+ CFRelease(gcCache->cachedBackgroundColor);
+ }
+}
- GetPortBounds(port, &bounds);
- err = ChkErr(ApplyThemeBackground, background, &bounds,
- kThemeStateActive, 32, true);
+static CGColorRef
+CopyCachedColor(
+ GC gc,
+ unsigned long pixel)
+{
+ TkpGCCache *gcCache = TkpGetGCCache(gc);
+ CGColorRef cgColor = NULL;
+
+ if (gcCache) {
+ if (gcCache->cachedForeground == pixel) {
+ cgColor = gcCache->cachedForegroundColor;
+ } else if (gcCache->cachedBackground == pixel) {
+ cgColor = gcCache->cachedBackgroundColor;
}
- if (penPat && err == noErr && (brush || background)) {
- GetPortBackPixPat(port, penPat);
- setPenPat = 1;
+ if (cgColor) {
+ CFRetain(cgColor);
}
- if (portChanged) {
- QDSwapPort(savePort, NULL);
+ }
+ return cgColor;
+}
+
+static void
+SetCachedColor(
+ GC gc,
+ unsigned long pixel,
+ CGColorRef cgColor)
+{
+ TkpGCCache *gcCache = TkpGetGCCache(gc);
+
+ if (gcCache && cgColor) {
+ if (gc->foreground == pixel) {
+ if (gcCache->cachedForegroundColor) {
+ CFRelease(gcCache->cachedForegroundColor);
+ }
+ gcCache->cachedForegroundColor = (CGColorRef) CFRetain(cgColor);
+ gcCache->cachedForeground = pixel;
+ } else if (gc->background == pixel) {
+ if (gcCache->cachedBackgroundColor) {
+ CFRelease(gcCache->cachedBackgroundColor);
+ }
+ gcCache->cachedBackgroundColor = (CGColorRef) CFRetain(cgColor);
+ gcCache->cachedBackground = pixel;
}
- } else {
- TkMacOSXDbgMsg("Ignored unknown pixel value 0x%lx", pixel);
}
- if (penPat && !setPenPat) {
- GetPortBackPixPat(port, penPat);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TkMacOSXCreateCGColor --
+ *
+ * Creates a CGColorRef from a X style pixel value.
+ *
+ * Results:
+ * Returns NULL if not a real pixel, CGColorRef otherwise.
+ *
+ * Side effects:
+ * None
+ *
+ *----------------------------------------------------------------------
+ */
+
+CGColorRef
+TkMacOSXCreateCGColor(
+ GC gc,
+ unsigned long pixel) /* Pixel value to convert. */
+{
+ CGColorRef cgColor = CopyCachedColor(gc, pixel);
+
+ if (!cgColor && TkSetMacColor(pixel, &cgColor)) {
+ SetCachedColor(gc, pixel, cgColor);
+ }
+ return cgColor;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TkMacOSXGetNSColor --
+ *
+ * Creates an autoreleased NSColor from a X style pixel value.
+ *
+ * Results:
+ * Returns nil if not a real pixel, NSColor* otherwise.
+ *
+ * Side effects:
+ * None
+ *
+ *----------------------------------------------------------------------
+ */
+
+NSColor*
+TkMacOSXGetNSColor(
+ GC gc,
+ unsigned long pixel) /* Pixel value to convert. */
+{
+ CGColorRef cgColor = TkMacOSXCreateCGColor(gc, pixel);
+ NSColor *nsColor = nil;
+
+ if (cgColor) {
+ NSColorSpace *colorSpace = [[NSColorSpace alloc]
+ initWithCGColorSpace:CGColorGetColorSpace(cgColor)];
+ nsColor = [NSColor colorWithColorSpace:colorSpace
+ components:CGColorGetComponents(cgColor)
+ count:CGColorGetNumberOfComponents(cgColor)];
+ [colorSpace release];
+ CFRelease(cgColor);
}
+ return nsColor;
}
/*
@@ -397,136 +484,52 @@ TkMacOSXSetColorInPort(
void
TkMacOSXSetColorInContext(
+ GC gc,
unsigned long pixel,
CGContextRef context)
{
OSStatus err = -1;
- RGBColor c;
+ CGColorRef cgColor = CopyCachedColor(gc, pixel);
ThemeBrush brush;
ThemeTextColor textColor;
ThemeBackgroundKind background;
- if (GetThemeFromPixelCode((pixel >> 24) & 0xff, &brush, &textColor,
- &background)) {
+ if (!cgColor && GetThemeFromPixelCode((pixel >> 24) & 0xff, &brush,
+ &textColor, &background)) {
if (brush) {
- TK_IF_MAC_OS_X_API (4, HIThemeSetFill,
- err = ChkErr(HIThemeSetFill, brush, NULL, context,
+ err = ChkErr(HIThemeSetFill, brush, NULL, context,
+ kHIThemeOrientationNormal);
+ if (err == noErr) {
+ err = ChkErr(HIThemeSetStroke, brush, NULL, context,
kHIThemeOrientationNormal);
- TK_IF_MAC_OS_X_API_COND (4, HIThemeSetFill, err == noErr,
- err = ChkErr(HIThemeSetStroke, brush, NULL, context,
- kHIThemeOrientationNormal);
- ) TK_ENDIF
- ) TK_ENDIF
+ }
} else if (textColor) {
- TK_IF_MAC_OS_X_API (4, HIThemeSetTextFill,
- err = ChkErr(HIThemeSetTextFill, textColor, NULL, context,
- kHIThemeOrientationNormal);
- ) TK_ENDIF
+ err = ChkErr(HIThemeSetTextFill, textColor, NULL, context,
+ kHIThemeOrientationNormal);
} else if (background) {
- TK_IF_MAC_OS_X_API (3, CGContextGetClipBoundingBox,
- CGRect rect = CGContextGetClipBoundingBox(context);
- HIThemeBackgroundDrawInfo info = { 0, kThemeStateActive,
- background };
-
- TK_IF_MAC_OS_X_API (3, HIThemeApplyBackground,
- TK_IF_HI_TOOLBOX (3, /* c.f. QA1377 */
- err = ChkErr(HIThemeApplyBackground, &rect, &info,
- context, kHIThemeOrientationNormal);
- ) TK_ENDIF
- ) TK_ENDIF
- ) TK_ENDIF
+ CGRect rect = CGContextGetClipBoundingBox(context);
+ HIThemeBackgroundDrawInfo info = { 0, kThemeStateActive,
+ background };
+
+ err = ChkErr(HIThemeApplyBackground, &rect, &info,
+ context, kHIThemeOrientationNormal);
}
if (err == noErr) {
return;
}
-#if MAC_OS_X_VERSION_MIN_REQUIRED < 1040
- /*
- * Convert Appearance theme pattern to CGPattern:
- */
- if ((brush || background) && CGPatternCreateWithImage != NULL) {
- static PixPatHandle pixpat = NULL;
- static GWorldPtr patGWorld = NULL;
- static uint32_t bitmapInfo = 0;
- const short patDim = 16;
- const Rect bounds = {0, 0, patDim, patDim};
- CGrafPtr savePort;
- Boolean portChanged;
- PixMapHandle pixmap;
- long rowbytes;
- CGImageRef img;
- CGColorSpaceRef rgbCspace;
- CGDataProviderRef provider;
-
- if (!pixpat) {
- pixpat = NewPixPat();
- err = ChkErr(NewGWorld, &patGWorld, 32, &bounds, NULL, NULL, 0
-#ifdef __LITTLE_ENDIAN__
- | kNativeEndianPixMap
-#endif
- );
- if (!pixpat || err != noErr || !patGWorld) {
- Tcl_Panic("TkMacOSXSetColorInContext(): "
- "pattern initialization failed !");
- }
- TK_IF_HI_TOOLBOX (4,
- bitmapInfo = kCGBitmapByteOrder32Host;
- ) TK_ENDIF
- }
- portChanged = QDSwapPort(patGWorld, &savePort);
- TkMacOSXSetColorInPort(pixel, 1, pixpat, patGWorld);
-#ifdef TK_MAC_DEBUG
- Rect patBounds;
- GetPixBounds((**pixpat).patMap, &patBounds);
- if (patBounds.right > patDim || patBounds.bottom > patDim) {
- Tcl_Panic("TkMacOSXSetColorInContext(): "
- "pattern larger than expected !");
- }
-#endif /* TK_MAC_DEBUG */
- FillCRect(&bounds, pixpat);
- if (portChanged) {
- QDSwapPort(savePort, NULL);
- }
- pixmap = GetPortPixMap(patGWorld);
- rowbytes = GetPixRowBytes(pixmap);
- provider = CGDataProviderCreateWithData(&patGWorld,
- GetPixBaseAddr(pixmap), rowbytes * patDim, NULL);
- rgbCspace = CGColorSpaceCreateDeviceRGB();
- img = CGImageCreate(patDim, patDim, 8, 32,
- rowbytes, rgbCspace, kCGImageAlphaFirst | bitmapInfo,
- provider, NULL, 0, kCGRenderingIntentDefault);
- CGColorSpaceRelease(rgbCspace);
- CGDataProviderRelease(provider);
- if (img) {
- CGPatternRef pat = CGPatternCreateWithImage(img, 2);
- CGColorSpaceRef patCSpace = CGColorSpaceCreatePattern(NULL);
- const float alpha = 1;
-
- CGContextSetFillColorSpace(context, patCSpace);
- CGContextSetFillPattern(context, pat, &alpha);
- CGContextSetStrokeColorSpace(context, patCSpace);
- CGContextSetStrokePattern(context, pat, &alpha);
- CGColorSpaceRelease(patCSpace);
- CGPatternRelease(pat);
- CGImageRelease(img);
- return;
- }
- }
-#endif /* MAC_OS_X_VERSION_MIN_REQUIRED < 1040 */
- err = ChkErr(GetThemeColor, pixel, brush, textColor, background, &c);
+ err = ChkErr(GetThemeColor, pixel, brush, textColor, background,
+ &cgColor);
if (err == noErr) {
- double r = c.red / 65535.0;
- double g = c.green / 65535.0;
- double b = c.blue / 65535.0;
-
- CGContextSetRGBFillColor(context, r, g, b, 1.0);
- CGContextSetRGBStrokeColor(context, r, g, b, 1.0);
+ SetCachedColor(gc, pixel, cgColor);
}
- } else if (((pixel >> 24) & 0xff) == TRANSPARENT_PIXEL) {
- CGContextSetRGBFillColor(context, 0.0, 0.0, 0.0, 0.0);
- CGContextSetRGBStrokeColor(context, 0.0, 0.0, 0.0, 0.0);
- } else {
+ } else if (!cgColor) {
TkMacOSXDbgMsg("Ignored unknown pixel value 0x%lx", pixel);
}
+ if (cgColor) {
+ CGContextSetFillColorWithColor(context, cgColor);
+ CGContextSetStrokeColorWithColor(context, cgColor);
+ CGColorRelease(cgColor);
+ }
}
/*
@@ -553,8 +556,8 @@ TkpGetColor(
Tk_Uid name) /* Name of color to allocated (in form
* suitable for passing to XParseColor). */
{
- Display *display = Tk_Display(tkwin);
- Colormap colormap = Tk_Colormap(tkwin);
+ Display *display = tkwin != None ? Tk_Display(tkwin) : NULL;
+ Colormap colormap = tkwin!= None ? Tk_Colormap(tkwin) : None;
TkColor *tkColPtr;
XColor color;
@@ -571,7 +574,7 @@ TkpGetColor(
Tcl_DecrRefCount(strPtr);
if (result == TCL_OK) {
OSStatus err;
- RGBColor c;
+ CGColorRef c;
unsigned char pixelCode = idx + MIN_PIXELCODE;
ThemeBrush brush = systemColorMap[idx].brush;
ThemeTextColor textColor = systemColorMap[idx].textColor;
@@ -579,24 +582,38 @@ TkpGetColor(
err = ChkErr(GetThemeColor, 0, brush, textColor, background, &c);
if (err == noErr) {
- color.red = c.red;
- color.green = c.green;
- color.blue = c.blue;
+ const size_t n = CGColorGetNumberOfComponents(c);
+ const CGFloat *rgba = CGColorGetComponents(c);
+
+ switch (n) {
+ case 4:
+ color.red = rgba[0] * 65535.0;
+ color.green = rgba[1] * 65535.0;
+ color.blue = rgba[2] * 65535.0;
+ break;
+ case 2:
+ color.red = color.green = color.blue = rgba[0] * 65535.0;
+ break;
+ default:
+ Tcl_Panic("CGColor with %d components", (int) n);
+ }
color.pixel = ((((((pixelCode << 8)
| ((color.red >> 8) & 0xff)) << 8)
| ((color.green >> 8) & 0xff)) << 8)
| ((color.blue >> 8) & 0xff));
+ CGColorRelease(c);
goto validXColor;
}
+ CGColorRelease(c);
}
}
if (TkParseColor(display, colormap, name, &color) == 0) {
- return (TkColor *) NULL;
+ return NULL;
}
validXColor:
- tkColPtr = (TkColor *) ckalloc(sizeof(TkColor));
+ tkColPtr = ckalloc(sizeof(TkColor));
tkColPtr->color = color;
return tkColPtr;
@@ -630,7 +647,7 @@ TkpGetColorByValue(
XColor *colorPtr) /* Red, green, and blue fields indicate
* desired color. */
{
- TkColor *tkColPtr = (TkColor *) ckalloc(sizeof(TkColor));
+ TkColor *tkColPtr = ckalloc(sizeof(TkColor));
tkColPtr->color.red = colorPtr->red;
tkColPtr->color.green = colorPtr->green;
@@ -639,37 +656,6 @@ TkpGetColorByValue(
return tkColPtr;
}
-#if !TK_DRAW_IN_CONTEXT
-/*
- *----------------------------------------------------------------------
- *
- * TkMacOSXCompareColors --
- *
- * On Mac, color codes may specify symbolic values like "highlight
- * foreground", but we really need the actual values to compare.
- * Maybe see also: "TIP #154: Add Named Colors to Tk".
- *
- * Results:
- * Returns true if both colors are the same, false otherwise.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-int
-TkMacOSXCompareColors(
- unsigned long c1,
- unsigned long c2)
-{
- RGBColor col1, col2;
- return TkSetMacColor(c1,&col1) &&
- TkSetMacColor(c1,&col2) &&
- !memcmp(&col1,&col2,sizeof(col1));
-}
-#endif /* !TK_DRAW_IN_CONTEXT */
-
/*
*----------------------------------------------------------------------
*
@@ -736,3 +722,12 @@ XFreeColors(
*/
return Success;
}
+
+/*
+ * Local Variables:
+ * mode: objc
+ * c-basic-offset: 4
+ * fill-column: 79
+ * coding: utf-8
+ * End:
+ */