diff options
Diffstat (limited to 'macosx/tkMacOSXColor.c')
-rw-r--r-- | macosx/tkMacOSXColor.c | 824 |
1 files changed, 393 insertions, 431 deletions
diff --git a/macosx/tkMacOSXColor.c b/macosx/tkMacOSXColor.c index 40b537e..acbfa0e 100644 --- a/macosx/tkMacOSXColor.c +++ b/macosx/tkMacOSXColor.c @@ -1,5 +1,5 @@ /* - * tkMacOSXColor.c -- + * TkMacOSXColor.c -- * * This file maintains a database of color values for the Tk * toolkit, in order to avoid round-trips to the server to @@ -9,6 +9,7 @@ * Copyright (c) 1994-1996 Sun Microsystems, Inc. * Copyright 2001-2009, Apple Inc. * Copyright (c) 2006-2009 Daniel A. Steffen <das@users.sourceforge.net> + * Copyright (c) 2020 Marc Culler * * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. @@ -16,286 +17,272 @@ #include "tkMacOSXPrivate.h" #include "tkColor.h" +#include "tkMacOSXColor.h" + +static Tcl_HashTable systemColors; +static int numSystemColors; +static int rgbColorIndex; +static int controlAccentIndex; +static int selectedTabTextIndex; +static Bool useFakeAccentColor = NO; +static SystemColorDatum **systemColorIndex; +#if MAC_OS_X_VERSION_MAX_ALLOWED >= 101400 +static NSAppearance *lightAqua = nil; +static NSAppearance *darkAqua = nil; +#endif +static NSColorSpace* sRGB = NULL; +static const CGFloat WINDOWBACKGROUND[4] = + {236.0 / 255, 236.0 / 255, 236.0 / 255, 1.0}; -/* - * The colorType specifies how the color value should be interpreted. For the - * unique rgbColor entry, the RGB values are generated from the pixel value of - * an XColor. The ttkBackground and semantic types are dynamic, meaning - * that they change when dark mode is enabled on OSX 10.13 and later. - */ +void initColorTable() +{ + NSAutoreleasePool *pool = [NSAutoreleasePool new]; + Tcl_InitHashTable(&systemColors, TCL_STRING_KEYS); + SystemColorDatum *entry, *oldEntry; + Tcl_HashSearch search; + Tcl_HashEntry *hPtr; + int newPtr, index = 0; + NSColorList *systemColorList = [NSColorList colorListNamed:@"System"]; + NSString *key; -enum colorType { - clearColor, /* There should be only one of these. */ - rgbColor, /* There should be only one of these. */ - appearance, /* There should be only one of these. */ - HIBrush, /* The value is a HITheme brush color table index. */ - HIText, /* The value is a HITheme text color table index. */ - HIBackground, /* The value is a HITheme background color table index. */ - ttkBackground, /* The value can be used as a parameter.*/ - semantic, /* The value can be used as a parameter.*/ -}; +#if MAC_OS_X_VERSION_MAX_ALLOWED >= 101400 + if (@available(macOS 10.14, *)) { + darkAqua = [NSAppearance appearanceNamed:NSAppearanceNameDarkAqua]; + lightAqua = [NSAppearance appearanceNamed:NSAppearanceNameAqua]; + } +#endif -/* + /* + * Build a hash table for looking up a color by its name. + * First add all of the static entries from tkMacOSXColor.h + */ - */ + for (entry = systemColorData; entry->name != NULL; entry++) { + hPtr = Tcl_CreateHashEntry(&systemColors, entry->name, &newPtr); + if (entry->type == semantic) { + NSString *colorName = [[NSString alloc] + initWithCString:entry->macName + encoding:NSUTF8StringEncoding]; + SEL colorSelector = NSSelectorFromString(colorName); + if (![NSColor respondsToSelector:colorSelector]) { + if ([colorName isEqualToString:@"controlAccentColor"]) { + useFakeAccentColor = YES; + } else if (![colorName isEqualToString:@"selectedTabTextColor"]) { + /* Uncomment to print all unsupported colors: */ + /* printf("Unsupported color %s\n", colorName.UTF8String); */ + continue; + } + } + entry->selector = [colorName retain]; + } + if (newPtr == 0) { + oldEntry = (SystemColorDatum *) Tcl_GetHashValue(hPtr); + entry->index = oldEntry->index; + [oldEntry->selector release]; + } else { + entry->index = index++; + } + Tcl_SetHashValue(hPtr, entry); + } -struct SystemColorMapEntry { - const char *name; - enum colorType type; - long value; -}; /* unsigned char pixelCode; */ + /* + * Add all of the colors in the System ColorList. + */ -/* - * Array of system color definitions: the array index is required to equal the - * color's (pixelCode - MIN_PIXELCODE), i.e. the array order needs to be kept - * in sync with the public pixel code values in tkMacOSXPort.h ! - */ + for (key in [systemColorList allKeys]) { + int length = [key lengthOfBytesUsingEncoding:NSUTF8StringEncoding]; + char *name; + entry = (SystemColorDatum *)ckalloc(sizeof(SystemColorDatum)); + bzero(entry, sizeof(SystemColorDatum)); + name = (char *)ckalloc(length + 1); + strcpy(name, key.UTF8String); + name[0] = toupper(name[0]); + if (!strcmp(name, "WindowBackgroundColor")) { + + /* + * Avoid black windows on old systems. + */ + + continue; + } + entry->type=semantic; + entry->name = name; + entry->selector = [key retain]; + hPtr = Tcl_CreateHashEntry(&systemColors, entry->name, &newPtr); + if (newPtr == 0) { + oldEntry = (SystemColorDatum *) Tcl_GetHashValue(hPtr); + entry->index = oldEntry->index; + [oldEntry->selector release]; + } else { + entry->index = index++; + } + Tcl_SetHashValue(hPtr, entry); + } -#define MIN_PIXELCODE 30 -static const struct SystemColorMapEntry systemColorMap[] = { - { "Transparent", clearColor, 0 }, /* 30: TRANSPARENT_PIXEL */ - { "Highlight", HIBrush, kThemeBrushPrimaryHighlightColor }, /* 31 */ - { "HighlightSecondary", HIBrush, kThemeBrushSecondaryHighlightColor }, /* 32 */ - { "HighlightText", HIBrush, kThemeBrushBlack }, /* 33 */ - { "HighlightAlternate", HIBrush, kThemeBrushAlternatePrimaryHighlightColor }, /* 34 */ - { "ButtonText", HIText, kThemeTextColorPushButtonActive }, /* 35 */ - { "PrimaryHighlightColor", HIBrush, kThemeBrushPrimaryHighlightColor }, /* 36 */ - { "ButtonFace", HIBrush, kThemeBrushButtonFaceActive }, /* 37 */ - { "SecondaryHighlightColor", HIBrush, kThemeBrushSecondaryHighlightColor }, /* 38 */ - { "ButtonFrame", HIBrush, kThemeBrushButtonFrameActive }, /* 39 */ - { "AlternatePrimaryHighlightColor", HIBrush, kThemeBrushAlternatePrimaryHighlightColor }, /* 40 */ - { "WindowBody", HIBrush, kThemeBrushDocumentWindowBackground }, /* 41 */ - { "SheetBackground", HIBrush, kThemeBrushSheetBackground }, /* 42 */ - { "MenuActive", HIBrush, kThemeBrushMenuBackgroundSelected }, /* 43 */ - { "Black", HIBrush, kThemeBrushBlack }, /* 44 */ - { "MenuActiveText", HIText, kThemeTextColorMenuItemSelected }, /* 45 */ - { "White", HIBrush, kThemeBrushWhite }, /* 46 */ - { "Menu", HIBrush, kThemeBrushMenuBackground }, /* 47 */ - { "DialogBackgroundActive", HIBrush, kThemeBrushDialogBackgroundActive }, /* 48 */ - { "MenuDisabled", HIText, kThemeTextColorMenuItemDisabled }, /* 49 */ - { "DialogBackgroundInactive", HIBrush, kThemeBrushDialogBackgroundInactive }, /* 50 */ - { "MenuText", HIText, kThemeTextColorMenuItemActive }, /* 51 */ - { "AppearanceColor", appearance, 0 }, /* 52: APPEARANCE_PIXEL */ - { "AlertBackgroundActive", HIBrush, kThemeBrushAlertBackgroundActive }, /* 53 */ - { "AlertBackgroundInactive", HIBrush, kThemeBrushAlertBackgroundInactive }, /* 54 */ - { "ModelessDialogBackgroundActive", HIBrush, kThemeBrushModelessDialogBackgroundActive }, /* 55 */ - { "ModelessDialogBackgroundInactive", HIBrush, kThemeBrushModelessDialogBackgroundInactive }, /* 56 */ - { "UtilityWindowBackgroundActive", HIBrush, kThemeBrushUtilityWindowBackgroundActive }, /* 57 */ - { "UtilityWindowBackgroundInactive", HIBrush, kThemeBrushUtilityWindowBackgroundInactive }, /* 58 */ - { "ListViewSortColumnBackground", HIBrush, kThemeBrushListViewSortColumnBackground }, /* 59 */ - { "ListViewBackground", HIBrush, kThemeBrushListViewBackground }, /* 60 */ - { "IconLabelBackground", HIBrush, kThemeBrushIconLabelBackground }, /* 61 */ - { "ListViewSeparator", HIBrush, kThemeBrushListViewSeparator }, /* 62 */ - { "ChasingArrows", HIBrush, kThemeBrushChasingArrows }, /* 63 */ - { "DragHilite", HIBrush, kThemeBrushDragHilite }, /* 64 */ - { "DocumentWindowBackground", HIBrush, kThemeBrushDocumentWindowBackground }, /* 65 */ - { "FinderWindowBackground", HIBrush, kThemeBrushFinderWindowBackground }, /* 66 */ - { "ScrollBarDelimiterActive", HIBrush, kThemeBrushScrollBarDelimiterActive }, /* 67 */ - { "ScrollBarDelimiterInactive", HIBrush, kThemeBrushScrollBarDelimiterInactive }, /* 68 */ - { "FocusHighlight", HIBrush, kThemeBrushFocusHighlight }, /* 69 */ - { "PopupArrowActive", HIBrush, kThemeBrushPopupArrowActive }, /* 70 */ - { "PopupArrowPressed", HIBrush, kThemeBrushPopupArrowPressed }, /* 71 */ - { "PopupArrowInactive", HIBrush, kThemeBrushPopupArrowInactive }, /* 72 */ - { "AppleGuideCoachmark", HIBrush, kThemeBrushAppleGuideCoachmark }, /* 73 */ - { "IconLabelBackgroundSelected", HIBrush, kThemeBrushIconLabelBackgroundSelected }, /* 74 */ - { "StaticAreaFill", HIBrush, kThemeBrushStaticAreaFill }, /* 75 */ - { "ActiveAreaFill", HIBrush, kThemeBrushActiveAreaFill }, /* 76 */ - { "ButtonFrameActive", HIBrush, kThemeBrushButtonFrameActive }, /* 77 */ - { "ButtonFrameInactive", HIBrush, kThemeBrushButtonFrameInactive }, /* 78 */ - { "ButtonFaceActive", HIBrush, kThemeBrushButtonFaceActive }, /* 79 */ - { "ButtonFaceInactive", HIBrush, kThemeBrushButtonFaceInactive }, /* 80 */ - { "ButtonFacePressed", HIBrush, kThemeBrushButtonFacePressed }, /* 81 */ - { "ButtonActiveDarkShadow", HIBrush, kThemeBrushButtonActiveDarkShadow }, /* 82 */ - { "ButtonActiveDarkHighlight", HIBrush, kThemeBrushButtonActiveDarkHighlight }, /* 83 */ - { "ButtonActiveLightShadow", HIBrush, kThemeBrushButtonActiveLightShadow }, /* 84 */ - { "ButtonActiveLightHighlight", HIBrush, kThemeBrushButtonActiveLightHighlight }, /* 85 */ - { "ButtonInactiveDarkShadow", HIBrush, kThemeBrushButtonInactiveDarkShadow }, /* 86 */ - { "ButtonInactiveDarkHighlight", HIBrush, kThemeBrushButtonInactiveDarkHighlight }, /* 87 */ - { "ButtonInactiveLightShadow", HIBrush, kThemeBrushButtonInactiveLightShadow }, /* 88 */ - { "ButtonInactiveLightHighlight", HIBrush, kThemeBrushButtonInactiveLightHighlight }, /* 89 */ - { "ButtonPressedDarkShadow", HIBrush, kThemeBrushButtonPressedDarkShadow }, /* 90 */ - { "ButtonPressedDarkHighlight", HIBrush, kThemeBrushButtonPressedDarkHighlight }, /* 91 */ - { "ButtonPressedLightShadow", HIBrush, kThemeBrushButtonPressedLightShadow }, /* 92 */ - { "ButtonPressedLightHighlight", HIBrush, kThemeBrushButtonPressedLightHighlight }, /* 93 */ - { "BevelActiveLight", HIBrush, kThemeBrushBevelActiveLight }, /* 94 */ - { "BevelActiveDark", HIBrush, kThemeBrushBevelActiveDark }, /* 95 */ - { "BevelInactiveLight", HIBrush, kThemeBrushBevelInactiveLight }, /* 96 */ - { "BevelInactiveDark", HIBrush, kThemeBrushBevelInactiveDark }, /* 97 */ - { "NotificationWindowBackground", HIBrush, kThemeBrushNotificationWindowBackground }, /* 98 */ - { "MovableModalBackground", HIBrush, kThemeBrushMovableModalBackground }, /* 99 */ - { "SheetBackgroundOpaque", HIBrush, kThemeBrushSheetBackgroundOpaque }, /* 100 */ - { "DrawerBackground", HIBrush, kThemeBrushDrawerBackground }, /* 101 */ - { "ToolbarBackground", HIBrush, kThemeBrushToolbarBackground }, /* 102 */ - { "SheetBackgroundTransparent", HIBrush, kThemeBrushSheetBackgroundTransparent }, /* 103 */ - { "MenuBackground", HIBrush, kThemeBrushMenuBackground }, /* 104 */ - { "Pixel", rgbColor, 0 }, /* 105: PIXEL_MAGIC */ - { "MenuBackgroundSelected", HIBrush, kThemeBrushMenuBackgroundSelected }, /* 106 */ - { "ListViewOddRowBackground", HIBrush, kThemeBrushListViewOddRowBackground }, /* 107 */ - { "ListViewEvenRowBackground", HIBrush, kThemeBrushListViewEvenRowBackground }, /* 108 */ - { "ListViewColumnDivider", HIBrush, kThemeBrushListViewColumnDivider }, /* 109 */ - { "BlackText", HIText, kThemeTextColorBlack }, /* 110 */ - { "DialogActiveText", HIText, kThemeTextColorDialogActive }, /* 111 */ - { "DialogInactiveText", HIText, kThemeTextColorDialogInactive }, /* 112 */ - { "AlertActiveText", HIText, kThemeTextColorAlertActive }, /* 113 */ - { "AlertInactiveText", HIText, kThemeTextColorAlertInactive }, /* 114 */ - { "ModelessDialogActiveText", HIText, kThemeTextColorModelessDialogActive }, /* 115 */ - { "ModelessDialogInactiveText", HIText, kThemeTextColorModelessDialogInactive }, /* 116 */ - { "WindowHeaderActiveText", HIText, kThemeTextColorWindowHeaderActive }, /* 117 */ - { "WindowHeaderInactiveText", HIText, kThemeTextColorWindowHeaderInactive }, /* 118 */ - { "PlacardActiveText", HIText, kThemeTextColorPlacardActive }, /* 119 */ - { "PlacardInactiveText", HIText, kThemeTextColorPlacardInactive }, /* 120 */ - { "PlacardPressedText", HIText, kThemeTextColorPlacardPressed }, /* 121 */ - { "PushButtonActiveText", HIText, kThemeTextColorPushButtonActive }, /* 122 */ - { "PushButtonInactiveText", HIText, kThemeTextColorPushButtonInactive }, /* 123 */ - { "PushButtonPressedText", HIText, kThemeTextColorPushButtonPressed }, /* 124 */ - { "BevelButtonActiveText", HIText, kThemeTextColorBevelButtonActive }, /* 125 */ - { "BevelButtonInactiveText", HIText, kThemeTextColorBevelButtonInactive }, /* 126 */ - { "BevelButtonPressedText", HIText, kThemeTextColorBevelButtonPressed }, /* 127 */ - { "PopupButtonActiveText", HIText, kThemeTextColorPopupButtonActive }, /* 128 */ - { "PopupButtonInactiveText", HIText, kThemeTextColorPopupButtonInactive }, /* 129 */ - { "PopupButtonPressedText", HIText, kThemeTextColorPopupButtonPressed }, /* 130 */ - { "IconLabelText", HIText, kThemeTextColorIconLabel }, /* 131 */ - { "ListViewText", HIText, kThemeTextColorListView }, /* 132 */ - { "DocumentWindowTitleActiveText", HIText, kThemeTextColorDocumentWindowTitleActive }, /* 133 */ - { "DocumentWindowTitleInactiveText", HIText, kThemeTextColorDocumentWindowTitleInactive }, /* 134 */ - { "MovableModalWindowTitleActiveText", HIText, kThemeTextColorMovableModalWindowTitleActive }, /* 135 */ - { "MovableModalWindowTitleInactiveText",HIText, kThemeTextColorMovableModalWindowTitleInactive }, /* 136 */ - { "UtilityWindowTitleActiveText", HIText, kThemeTextColorUtilityWindowTitleActive }, /* 137 */ - { "UtilityWindowTitleInactiveText", HIText, kThemeTextColorUtilityWindowTitleInactive }, /* 138 */ - { "PopupWindowTitleActiveText", HIText, kThemeTextColorPopupWindowTitleActive }, /* 139 */ - { "PopupWindowTitleInactiveText", HIText, kThemeTextColorPopupWindowTitleInactive }, /* 140 */ - { "RootMenuActiveText", HIText, kThemeTextColorRootMenuActive }, /* 141 */ - { "RootMenuSelectedText", HIText, kThemeTextColorRootMenuSelected }, /* 142 */ - { "RootMenuDisabledText", HIText, kThemeTextColorRootMenuDisabled }, /* 143 */ - { "MenuItemActiveText", HIText, kThemeTextColorMenuItemActive }, /* 144 */ - { "MenuItemSelectedText", HIText, kThemeTextColorMenuItemSelected }, /* 145 */ - { "MenuItemDisabledText", HIText, kThemeTextColorMenuItemDisabled }, /* 146 */ - { "PopupLabelActiveText", HIText, kThemeTextColorPopupLabelActive }, /* 147 */ - { "PopupLabelInactiveText", HIText, kThemeTextColorPopupLabelInactive }, /* 148 */ - { "TabFrontActiveText", HIText, kThemeTextColorTabFrontActive }, /* 149 */ - { "TabNonFrontActiveText", HIText, kThemeTextColorTabNonFrontActive }, /* 150 */ - { "TabNonFrontPressedText", HIText, kThemeTextColorTabNonFrontPressed }, /* 151 */ - { "TabFrontInactiveText", HIText, kThemeTextColorTabFrontInactive }, /* 152 */ - { "TabNonFrontInactiveText", HIText, kThemeTextColorTabNonFrontInactive }, /* 153 */ - { "IconLabelSelectedText", HIText, kThemeTextColorIconLabelSelected }, /* 154 */ - { "BevelButtonStickyActiveText", HIText, kThemeTextColorBevelButtonStickyActive }, /* 155 */ - { "BevelButtonStickyInactiveText", HIText, kThemeTextColorBevelButtonStickyInactive }, /* 156 */ - { "NotificationText", HIText, kThemeTextColorNotification }, /* 157 */ - { "SystemDetailText", HIText, kThemeTextColorSystemDetail }, /* 158 */ - { "WhiteText", HIText, kThemeTextColorWhite }, /* 159 */ - { "TabPaneBackground", HIBackground, kThemeBackgroundTabPane }, /* 160 */ - { "PlacardBackground", HIBackground, kThemeBackgroundPlacard }, /* 161 */ - { "WindowHeaderBackground", HIBackground, kThemeBackgroundWindowHeader }, /* 162 */ - { "ListViewWindowHeaderBackground", HIBackground, kThemeBackgroundListViewWindowHeader }, /* 163 */ - { "SecondaryGroupBoxBackground", HIBackground, kThemeBackgroundSecondaryGroupBox }, /* 164 */ - { "MetalBackground", HIBackground, kThemeBackgroundMetal }, /* 165 */ + /* + * Build an array for looking up a color by its index. + */ + + numSystemColors = index; + systemColorIndex = (SystemColorDatum **)ckalloc(numSystemColors * sizeof(SystemColorDatum *)); + for (hPtr = Tcl_FirstHashEntry(&systemColors, &search); hPtr != NULL; + hPtr = Tcl_NextHashEntry(&search)) { + entry = (SystemColorDatum *) Tcl_GetHashValue(hPtr); + if (entry == NULL) { + Tcl_Panic("Unsupported semantic color with no supported backup!"); + } + systemColorIndex[entry->index] = entry; + } /* - * Colors based on "semantic" NSColors. + * Remember the indexes of some special entries. */ - { "WindowBackgroundColor", ttkBackground, 0 }, /* 166 */ - { "WindowBackgroundColor1", ttkBackground, 1 }, /* 167 */ - { "WindowBackgroundColor2", ttkBackground, 2 }, /* 168 */ - { "WindowBackgroundColor3", ttkBackground, 3 }, /* 169 */ - { "WindowBackgroundColor4", ttkBackground, 4 }, /* 170 */ - { "WindowBackgroundColor5", ttkBackground, 5 }, /* 171 */ - { "WindowBackgroundColor6", ttkBackground, 6 }, /* 172 */ - { "WindowBackgroundColor7", ttkBackground, 7 }, /* 173 */ - { "TextColor", semantic, 0 }, /* 174 */ - { "SelectedTextColor", semantic, 1 }, /* 175 */ - { "LabelColor", semantic, 2 }, /* 176 */ - { "ControlTextColor", semantic, 3 }, /* 177 */ - { "DisabledControlTextColor", semantic, 4 }, /* 178 */ - { "SelectedTabTextColor", semantic, 5 }, /* 179 */ - { "TextBackgroundColor", semantic, 6 }, /* 180 */ - { "SelectedTextBackgroundColor", semantic, 7 }, /* 181 */ - { "ControlAccentColor", semantic, 8 }, /* 182 */ - /* Apple's SecondaryLabelColor is the same as their LabelColor so we roll our own. */ - { "SecondaryLabelColor", ttkBackground, 14 }, /* 183 */ - { "LinkColor", semantic, 9 }, /* 184 */ - { NULL, 0, 0 } -}; -#define FIRST_SEMANTIC_COLOR 166 -#define MAX_PIXELCODE 184 + hPtr = Tcl_FindHashEntry(&systemColors, "Pixel"); + entry = (SystemColorDatum *) Tcl_GetHashValue(hPtr); + rgbColorIndex = entry->index; + hPtr = Tcl_FindHashEntry(&systemColors, "ControlAccentColor"); + entry = (SystemColorDatum *) Tcl_GetHashValue(hPtr); + controlAccentIndex = entry->index; + hPtr = Tcl_FindHashEntry(&systemColors, "SelectedTabTextColor"); + entry = (SystemColorDatum *) Tcl_GetHashValue(hPtr); + selectedTabTextIndex = entry->index; + [pool drain]; +} + +/* + *---------------------------------------------------------------------- + * + * TkMacOSXRGBPixel -- + * + * Return an unsigned long value suitable for use in the pixel + * field of an XColor with the specified red, green and blue + * intensities. The inputs are cast as unsigned longs but are + * expected to have values representable by an unsigned char. + * + * This is called in the TkpGetPixel macro, used in xcolor.c, + * and in ImageGetPixel. + * + * Results: + * An unsigned long that can be used as the pixel field of an XColor. + * + * Side effects: + * None. + *---------------------------------------------------------------------- + */ +MODULE_SCOPE +unsigned long +TkMacOSXRGBPixel( + unsigned long red, + unsigned long green, + unsigned long blue) +{ + MacPixel p; + p.pixel.colortype = rgbColor; + p.pixel.value = ((red & 0xff) << 16) | + ((green & 0xff) << 8) | + (blue & 0xff); + return p.ulong; +} /* *---------------------------------------------------------------------- * - * GetEntryFromPixelCode -- + * TkMacOSXClearPixel -- * - * Extract a SystemColorMapEntry from the table. + * Return the unsigned long value that appears in the pixel + * field of the XColor for systemTransparentColor. + * + * This is used in tkMacOSXImage.c. * * Results: - * Returns false if the code is out of bounds. + * The unsigned long that appears in the pixel field of the XColor + * for systemTransparentPixel. * * Side effects: * None. + *---------------------------------------------------------------------- + */ +MODULE_SCOPE +unsigned long TkMacOSXClearPixel( + void) +{ + MacPixel p; + p.pixel.value = 0; + p.pixel.colortype = clearColor; + return p.ulong; +} + + +/* + *---------------------------------------------------------------------- + * + * GetEntryFromPixel -- + * + * Look up a SystemColorDatum which describes the XColor with + * the specified value as its pixel field. + * + * Results: + * A pointer to a SystemColorDatum, or NULL if the pixel value is + * invalid. + * + * Side effects: + * None * *---------------------------------------------------------------------- */ -static bool -GetEntryFromPixelCode( - unsigned char code, - struct SystemColorMapEntry *entry) +SystemColorDatum* +GetEntryFromPixel( + unsigned long pixel) { - if (code >= MIN_PIXELCODE && code <= MAX_PIXELCODE) { - *entry = systemColorMap[code - MIN_PIXELCODE]; - return true; + MacPixel p; + int index = rgbColorIndex; + + p.ulong = pixel; + if (p.pixel.colortype != rgbColor) { + index = p.pixel.value; + } + if (index < numSystemColors) { + return systemColorIndex[index]; } else { - return false; + return NULL; } } + /* *---------------------------------------------------------------------- * - * SetCGColorComponents -- + * GetRGBA -- * - * Set the components of a CGColorRef from an XColor pixel value and a - * system color map entry. The pixel value is only used in the case where - * the color is of type rgbColor. In that case the normalized XColor RGB - * values are copied into the CGColorRef. + * Given a SystemColorDatum and a pointer to an array of 4 CGFloats, store + * the associated RGBA color values in the array. In the case of the + * RGBColor datum, the unsigned long pixel value containing the RGB values + * must also be provided as the pixel parameter. Otherwise the pixel + * parameter is ignored. * * Results: - * OSStatus + * None * * Side effects: - * None. + * The array rgba is filled in. * *---------------------------------------------------------------------- */ -static NSColorSpace* sRGB = NULL; -static CGFloat windowBackground[4] = - {236.0 / 255, 236.0 / 255, 236.0 / 255, 1.0}; - -static OSStatus -SetCGColorComponents( - struct SystemColorMapEntry entry, +static void +GetRGBA( + SystemColorDatum *entry, unsigned long pixel, - CGColorRef *c) + CGFloat *rgba) { - OSStatus err = noErr; NSColor *bgColor, *color = nil; - CGFloat rgba[4] = {0, 0, 0, 1}; if (!sRGB) { sRGB = [NSColorSpace sRGBColorSpace]; } - - /* - * This function is called before our autorelease pool is set up, - * so it needs its own pool. - */ - - NSAutoreleasePool *pool = [NSAutoreleasePool new]; - - switch (entry.type) { - case HIBrush: - err = ChkErr(HIThemeBrushCreateCGColor, entry.value, c); - return err; + switch (entry->type) { case rgbColor: rgba[0] = ((pixel >> 16) & 0xff) / 255.0; rgba[1] = ((pixel >> 8) & 0xff) / 255.0; @@ -308,9 +295,9 @@ SetCGColorComponents( * windowBackGroundColor. */ - if ([NSApp macMinorVersion] < 14) { - for (int i=0; i<3; i++) { - rgba[i] = windowBackground[i]; + if ([NSApp macOSVersion] < 101400) { + for (int i = 0; i < 3; i++) { + rgba[i] = WINDOWBACKGROUND[i]; } } else { bgColor = [[NSColor windowBackgroundColor] colorUsingColorSpace:sRGB]; @@ -318,104 +305,80 @@ SetCGColorComponents( } if (rgba[0] + rgba[1] + rgba[2] < 1.5) { for (int i=0; i<3; i++) { - rgba[i] += entry.value*8.0 / 255.0; + rgba[i] += entry->value*8.0 / 255.0; } } else { for (int i=0; i<3; i++) { - rgba[i] -= entry.value*8.0 / 255.0; + rgba[i] -= entry->value*8.0 / 255.0; } } break; case semantic: - switch (entry.value) { - case 0: - color = [[NSColor textColor] colorUsingColorSpace:sRGB]; - break; - case 1: - color = [[NSColor selectedTextColor] colorUsingColorSpace:sRGB]; - break; - case 2: - if ([NSApp macMinorVersion] > 9) { -#if MAC_OS_X_VERSION_MAX_ALLOWED > 1090 - color = [[NSColor labelColor] colorUsingColorSpace:sRGB]; + if (entry->index == controlAccentIndex && useFakeAccentColor) { +#if MAC_OS_X_VERSION_MIN_REQUIRED < 101400 + color = [[NSColor colorForControlTint: [NSColor currentControlTint]] + colorUsingColorSpace:sRGB]; #endif - } else { - color = [[NSColor textColor] colorUsingColorSpace:sRGB]; - } - break; - case 3: - color = [[NSColor controlTextColor] colorUsingColorSpace:sRGB]; - break; - case 4: - color = [[NSColor disabledControlTextColor] - colorUsingColorSpace:sRGB]; - break; - case 5: - if ([NSApp macMinorVersion] > 6) { + } else if (entry->index == selectedTabTextIndex) { + int OSVersion = [NSApp macOSVersion]; + if (OSVersion > 100600 && OSVersion < 110000) { color = [[NSColor whiteColor] colorUsingColorSpace:sRGB]; - } else { - color = [[NSColor blackColor] colorUsingColorSpace:sRGB]; } - break; - case 6: - color = [[NSColor textBackgroundColor] colorUsingColorSpace:sRGB]; - break; - case 7: - color = [[NSColor selectedTextBackgroundColor] - colorUsingColorSpace:sRGB]; - break; - case 8: -#if MAC_OS_X_VERSION_MAX_ALLOWED >= 101400 - if (@available(macOS 14, *)) { - color = [[NSColor controlAccentColor] colorUsingColorSpace:sRGB]; -#else - if(false) { -#endif - } else { - color = [[NSColor - colorForControlTint:[NSColor currentControlTint]] - colorUsingColorSpace: sRGB]; - } - break; - case 9: - if ([NSApp macMinorVersion] >= 10) { -#if MAC_OS_X_VERSION_MAX_ALLOWED >= 101000 - color = [[NSColor linkColor] colorUsingColorSpace:sRGB]; -#endif - } else { - color = [[NSColor blueColor] colorUsingColorSpace:sRGB]; - } - break; - default: - if ([NSApp macMinorVersion] >= 10) { -#if MAC_OS_X_VERSION_MAX_ALLOWED >= 101000 - color = [[NSColor labelColor] colorUsingColorSpace:sRGB]; -#endif - } else { - color = [[NSColor textColor] colorUsingColorSpace:sRGB]; - } - break; + } else { + color = [[NSColor valueForKey:entry->selector] colorUsingColorSpace:sRGB]; } [color getComponents: rgba]; break; case clearColor: - rgba[3] = 0.0; + rgba[3] = 0; + default: break; + } +} + +/* + *---------------------------------------------------------------------- + * + * SetCGColorComponents -- + * + * Set the components of a CGColorRef from an XColor pixel value and a + * SystemColorDatum. The pixel value is only used in the case where + * the color is of type rgbColor. In that case the normalized XColor RGB + * values are copied into the CGColorRef. Otherwise the components are + * computed from the SystemColorDatum. + * + * Results: + * True if the function succeeds, false otherwise. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static Bool +SetCGColorComponents( + SystemColorDatum *entry, + unsigned long pixel, + CGColorRef *c) +{ + CGFloat rgba[4] = {0, 0, 0, 1}; /* - * There are no HITheme functions which convert Text or background colors - * to CGColors. (GetThemeTextColor has been removed, and it was never - * possible with backgrounds.) If we get one of these we return black. + * This function is called before our autorelease pool is set up, + * so it needs its own pool. */ - case HIText: - case HIBackground: - default: - break; + NSAutoreleasePool *pool = [NSAutoreleasePool new]; + + if (entry->type == HIBrush) { + OSStatus err = ChkErr(HIThemeBrushCreateCGColor, entry->value, c); + return err == noErr; } + GetRGBA(entry, pixel, rgba); *c = CGColorCreate(sRGB.CGColorSpace, rgba); [pool drain]; - return err; + return true; } /* @@ -437,27 +400,24 @@ SetCGColorComponents( MODULE_SCOPE Bool TkMacOSXInDarkMode(Tk_Window tkwin) { - int result = false; #if MAC_OS_X_VERSION_MAX_ALLOWED >= 101400 - static NSAppearanceName darkAqua = @"NSAppearanceNameDarkAqua"; - - if ([NSApp macMinorVersion] >= 14) { + if (@available(macOS 10.14, *)) { TkWindow *winPtr = (TkWindow*) tkwin; + NSAppearanceName name; NSView *view = nil; if (winPtr && winPtr->privatePtr) { - view = TkMacOSXDrawableView(winPtr->privatePtr); + view = TkMacOSXGetNSViewForDrawable((Drawable)winPtr->privatePtr); } if (view) { - result = [view.effectiveAppearance.name isEqualToString:darkAqua]; + name = [[view effectiveAppearance] name]; } else { - result = [[NSAppearance currentAppearance].name - isEqualToString:darkAqua]; + name = [[NSAppearance currentAppearance] name]; } + return (name == NSAppearanceNameDarkAqua); } #endif - - return result; + return false; } /* @@ -465,14 +425,13 @@ TkMacOSXInDarkMode(Tk_Window tkwin) * * TkSetMacColor -- * - * Sets the components of a CGColorRef from an XColor pixel value. - * The high order byte of the pixel value is used as an index into - * the system color table, and then SetCGColorComponents is called - * with the table entry and the pixel value. + * Sets the components of a CGColorRef from an XColor pixel value. The + * pixel value is used to look up the color in the system color table, and + * then SetCGColorComponents is called with the table entry and the pixel + * value. * * Results: - * Returns false if the high order byte is not a valid index, true - * otherwise. + * Returns false if the color is not found, true otherwise. * * Side effects: * The variable macColor is set to a new CGColorRef, the caller is @@ -487,13 +446,13 @@ TkSetMacColor( void *macColor) /* CGColorRef to modify. */ { CGColorRef *color = (CGColorRef*)macColor; - OSStatus err = -1; - struct SystemColorMapEntry entry; + SystemColorDatum *entry = GetEntryFromPixel(pixel); - if (GetEntryFromPixelCode((pixel >> 24) & 0xff, &entry)) { - err = ChkErr(SetCGColorComponents, entry, pixel, color); + if (entry) { + return SetCGColorComponents(entry, pixel, color); + } else { + return false; } - return (err == noErr); } /* @@ -506,7 +465,7 @@ TkSetMacColor( * Results: * None resp. retained CGColorRef for CopyCachedColor() * - * Side effects:M + * Side effects: * None. * *---------------------------------------------------------------------- @@ -614,9 +573,10 @@ TkMacOSXCreateCGColor( * TkMacOSXGetNSColor -- * * Creates an autoreleased NSColor from a X style pixel value. + * The return value is nil if the pixel value is invalid. * * Results: - * Returns nil if not a real pixel, NSColor* otherwise. + * A possibly nil pointer to an NSColor. * * Side effects: * None @@ -650,10 +610,9 @@ TkMacOSXGetNSColor( * * TkMacOSXSetColorInContext -- * - * Sets fill and stroke color in the given CG context from an X - * pixel value, or if the pixel code indicates a system color, - * sets the corresponding brush, textColor or background via - * HITheme APIs if available or Appearance mgr APIs. + * Sets the fill and stroke colors in the given CGContext to the CGColor + * which corresponds to the XColor having the specified value for its pixel + * field. * * Results: * None. @@ -672,37 +631,20 @@ TkMacOSXSetColorInContext( { OSStatus err = noErr; CGColorRef cgColor = nil; - struct SystemColorMapEntry entry; - CGRect rect; - int code = (pixel >> 24) & 0xff; - HIThemeBackgroundDrawInfo info = {0, kThemeStateActive, 0};; + SystemColorDatum *entry = GetEntryFromPixel(pixel); - if (code < FIRST_SEMANTIC_COLOR) { - cgColor = CopyCachedColor(gc, pixel); - } - if (!cgColor && GetEntryFromPixelCode(code, &entry)) { - switch (entry.type) { + if (entry) { + switch (entry->type) { case HIBrush: - err = ChkErr(HIThemeSetFill, entry.value, NULL, context, + err = ChkErr(HIThemeSetFill, entry->value, NULL, context, kHIThemeOrientationNormal); if (err == noErr) { - err = ChkErr(HIThemeSetStroke, entry.value, NULL, context, + err = ChkErr(HIThemeSetStroke, entry->value, NULL, context, kHIThemeOrientationNormal); } break; - case HIText: - err = ChkErr(HIThemeSetTextFill, entry.value, NULL, context, - kHIThemeOrientationNormal); - break; - case HIBackground: - info.kind = entry.value; - rect = CGContextGetClipBoundingBox(context); - err = ChkErr(HIThemeApplyBackground, &rect, &info, - context, kHIThemeOrientationNormal); - break; default: - err = ChkErr(SetCGColorComponents, entry, pixel, &cgColor); - if (err == noErr) { + if (SetCGColorComponents(entry, pixel, &cgColor)){ SetCachedColor(gc, pixel, cgColor); } break; @@ -723,15 +665,20 @@ TkMacOSXSetColorInContext( * * TkpGetColor -- * - * Allocate a new TkColor for the color with the given name. + * Create a new TkColor for the color with the given name, for use in the + * specified window. The colormap field is set to lightColormap if the + * window has a LightAqua appearance, or darkColormap if the window has a + * DarkAqua appearance. TkColors with different colormaps are managed + * separately in the per-display table of TkColors maintained by Tk. + * + * This function is called by Tk_GetColor. * * Results: * Returns a newly allocated TkColor, or NULL on failure. * * Side effects: - * May invalidate the colormap cache associated with tkwin upon - * allocating a new colormap entry. Allocates a new TkColor - * structure. + * + * Allocates memory for the TkColor structure. * *---------------------------------------------------------------------- */ @@ -742,31 +689,68 @@ TkpGetColor( Tk_Uid name) /* Name of color to be allocated (in form * suitable for passing to XParseColor). */ { - Display *display = tkwin != None ? Tk_Display(tkwin) : NULL; - Colormap colormap = tkwin!= None ? Tk_Colormap(tkwin) : None; + Display *display = NULL; TkColor *tkColPtr; XColor color; + Colormap colormap = tkwin ? Tk_Colormap(tkwin) : noColormap; + NSView *view = nil; + static Bool initialized = NO; + static NSColorSpace* sRGB = NULL; + + if (!initialized) { + initialized = YES; + sRGB = [NSColorSpace sRGBColorSpace]; + initColorTable(); + } + if (tkwin) { + display = Tk_Display(tkwin); + Drawable d = Tk_WindowId(tkwin); + view = TkMacOSXGetNSViewForDrawable(d); + } /* - * Check to see if this is a system color. Otherwise, XParseColor - * will do all the work. + * Check to see if this is a system color. If not, just call XParseColor. */ if (strncasecmp(name, "system", 6) == 0) { - Tcl_Obj *strPtr = Tcl_NewStringObj(name+6, -1); - int idx, result; - - result = Tcl_GetIndexFromObjStruct(NULL, strPtr, systemColorMap, - sizeof(struct SystemColorMapEntry), NULL, TCL_EXACT, &idx); - Tcl_DecrRefCount(strPtr); - if (result == TCL_OK) { - OSStatus err; + Tcl_HashEntry *hPtr = Tcl_FindHashEntry(&systemColors, name + 6); + MacPixel p; + + if (hPtr != NULL) { + SystemColorDatum *entry = (SystemColorDatum *)Tcl_GetHashValue(hPtr); CGColorRef c; - unsigned char pixelCode = idx + MIN_PIXELCODE; - struct SystemColorMapEntry entry = systemColorMap[idx]; - err = ChkErr(SetCGColorComponents, entry, 0, &c); - if (err == noErr) { + p.pixel.colortype = entry->type; + p.pixel.value = entry->index; + color.pixel = p.ulong; + if (entry->type == semantic) { + CGFloat rgba[4]; +#if MAC_OS_X_VERSION_MAX_ALLOWED >= 101400 + if (@available(macOS 10.14, *)) { + NSAppearance *savedAppearance = [NSAppearance currentAppearance]; + NSAppearance *windowAppearance = savedAppearance; + if (view) { + windowAppearance = [view effectiveAppearance]; + } + if ([windowAppearance name] == NSAppearanceNameDarkAqua) { + colormap = darkColormap; + } else { + colormap = lightColormap; + } + [NSAppearance setCurrentAppearance:windowAppearance]; + GetRGBA(entry, p.ulong, rgba); + [NSAppearance setCurrentAppearance:savedAppearance]; + } else { + GetRGBA(entry, p.ulong, rgba); + } +#else + GetRGBA(entry, p.ulong, rgba); +#endif + color.red = rgba[0] * 65535.0; + color.green = rgba[1] * 65535.0; + color.blue = rgba[2] * 65535.0; + goto validXColor; + } else if (SetCGColorComponents(entry, 0, &c)) { const size_t n = CGColorGetNumberOfComponents(c); const CGFloat *rgba = CGColorGetComponents(c); @@ -782,25 +766,19 @@ TkpGetColor( 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 NULL; } validXColor: tkColPtr = (TkColor *)ckalloc(sizeof(TkColor)); + tkColPtr->colormap = colormap; tkColPtr->color = color; - return tkColPtr; } @@ -809,36 +787,35 @@ validXColor: * * TkpGetColorByValue -- * - * Given a desired set of red-green-blue intensities for a color, - * locate a pixel value to use to draw that color in a given - * window. + * Given an pointer to an XColor, construct a TkColor whose red, green and + * blue intensities match those of the XColor as closely as possible. For + * the Macintosh, this means that the colortype bitfield of the pixel + * value will be RGBColor and that the color intensities stored in its + * 24-bit value bitfield are computed from the 16-bit red green and blue + * values in the XColor by dividing by 256. * * Results: - * The return value is a pointer to an TkColor structure that - * indicates the closest red, blue, and green intensities available - * to those specified in colorPtr, and also specifies a pixel - * value to use to draw in that color. + * A pointer to a newly allocated TkColor structure. * * Side effects: * May invalidate the colormap cache for the specified window. - * Allocates a new TkColor structure. + * Allocates memory for a TkColor structure. * *---------------------------------------------------------------------- */ TkColor * TkpGetColorByValue( - Tk_Window tkwin, /* Window in which color will be used. */ + TCL_UNUSED(Tk_Window), /* Window in which color will be used. */ XColor *colorPtr) /* Red, green, and blue fields indicate * desired color. */ { TkColor *tkColPtr = (TkColor *)ckalloc(sizeof(TkColor)); - (void)tkwin; tkColPtr->color.red = colorPtr->red; tkColPtr->color.green = colorPtr->green; tkColPtr->color.blue = colorPtr->blue; - tkColPtr->color.pixel = TkpGetPixel(&tkColPtr->color); + tkColPtr->color.pixel = TkpGetPixel(colorPtr); return tkColPtr; } @@ -862,11 +839,9 @@ TkpGetColorByValue( Status XAllocColor( Display *display, /* Display. */ - Colormap map, /* Not used. */ + TCL_UNUSED(Colormap), /* Not used. */ XColor *colorPtr) /* XColor struct to modify. */ { - (void)map; - display->request++; colorPtr->pixel = TkpGetPixel(colorPtr); return 1; @@ -874,52 +849,39 @@ XAllocColor( Colormap XCreateColormap( - Display *display, /* Display. */ - Window window, /* X window. */ - Visual *visual, /* Not used. */ - int alloc) /* Not used. */ + TCL_UNUSED(Display *), /* Display. */ + TCL_UNUSED(Window), /* X window. */ + TCL_UNUSED(Visual *), /* Not used. */ + TCL_UNUSED(int)) /* Not used. */ { - static Colormap index = 1; - (void)display; - (void)window; - (void)visual; - (void)alloc; + static Colormap index = 16; /* - * Just return a new value each time. + * Just return a new value each time, large enough that it will not + * conflict with any value of the macColormap enum. */ return index++; } int XFreeColormap( - Display* display, /* Display. */ - Colormap colormap) /* Colormap. */ + TCL_UNUSED(Display *), /* Display. */ + TCL_UNUSED(Colormap)) /* Colormap. */ { - (void)display; - (void)colormap; - return Success; } int XFreeColors( - Display* display, /* Display. */ - Colormap colormap, /* Colormap. */ - unsigned long* pixels, /* Array of pixels. */ - int npixels, /* Number of pixels. */ - unsigned long planes) /* Number of pixel planes. */ + TCL_UNUSED(Display *), /* Display. */ + TCL_UNUSED(Colormap), /* Colormap. */ + TCL_UNUSED(unsigned long *), /* Array of pixels. */ + TCL_UNUSED(int), /* Number of pixels. */ + TCL_UNUSED(unsigned long)) /* Number of pixel planes. */ { - (void)display; - (void)colormap; - (void)pixels; - (void)npixels; - (void)planes; - /* - * The Macintosh version of Tk uses TrueColor. Nothing - * needs to be done to release colors as there really is - * no colormap in the Tk sense. + * Nothing needs to be done to release colors as there really is no + * colormap in the Tk sense. */ return Success; } |