summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorculler <culler>2020-08-15 10:22:15 (GMT)
committerculler <culler>2020-08-15 10:22:15 (GMT)
commit8b6c8e84302179205f43165ff8e1ce15d2c8860a (patch)
tree6d81361052d6f4aa86a2c6bfd3d0163c68121b95
parent8ac846412241e0914a4bb279bf586c53835e34ab (diff)
downloadtk-8b6c8e84302179205f43165ff8e1ce15d2c8860a.zip
tk-8b6c8e84302179205f43165ff8e1ce15d2c8860a.tar.gz
tk-8b6c8e84302179205f43165ff8e1ce15d2c8860a.tar.bz2
sync with bug-315104a5c10
-rw-r--r--macosx/README36
-rw-r--r--macosx/tkMacOSXColor.c9
-rw-r--r--macosx/tkMacOSXWindowEvent.c105
3 files changed, 100 insertions, 50 deletions
diff --git a/macosx/README b/macosx/README
index 79025f1..0a02999 100644
--- a/macosx/README
+++ b/macosx/README
@@ -662,15 +662,35 @@ source and destination rectangles for the scrolling. The embedded
windows are redrawn within the DisplayText function by some
conditional code which is only used for macOS.
-6.0 Virtual events on 10.14
-~~~~~~~~~~~~~~~~~~~~~~~~~~~
+6.0 Virtual events on macOS 10.14 and later
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The 10.14 release added support for system appearance changes,
+including a "Dark Mode" that renders all window frames and menus in
+dark colors. Tk 8.6.11 provides three virtual events <<LightAqua>>,
+<<DarkAqua>> and <<AppearanceChanged>>, to allow you to update your Tk
+app's appearance when the system appearance changes. These events are
+generated in [NSView effectiveAppearanceChanged], which is called by
+the Apple window manager when the General Preferences is changed
+either by switching between Light Mode and Dark Mode or by changing
+the Accent Color or Highlight Color.
+
+The <<AppearanceChanged>> virtual event has a data string which can be
+accessed with the %d substitution. The format of the data string is
+that it consists of 6 words:
+ "Appearance XXXX Accent YYYY Highlight ZZZZ"
+For example, the following code will print the current appearance
+name, accent color and highlight color when the <<AppearanceChanged>>
+virtual event fires:
+
+bind . <<AppearanceChanged>> {
+ array set data [split %d]
+ puts " Appearance: $data(Appearance)"
+ puts " Accent: $data(Accent)"
+ puts " Highlight: $data(Highlight)\n"
+}
+
-10.14 supports system appearance changes, and has added a "Dark Mode"
-that casts all window frames and menus as black. Tk 8.6.9 has added two
-virtual events, <<LightAqua>> and <<DarkAqua>>, to allow you to update
-your Tk app's appearance when the system appearance changes. Just bind
-your appearance-updating code to these virtual events and you will see
-it triggered when the system appearance toggles between dark and light.
7.0 Mac Services
~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/macosx/tkMacOSXColor.c b/macosx/tkMacOSXColor.c
index fe0cc2a..974978f 100644
--- a/macosx/tkMacOSXColor.c
+++ b/macosx/tkMacOSXColor.c
@@ -378,23 +378,24 @@ SetCGColorComponents(
MODULE_SCOPE Bool
TkMacOSXInDarkMode(Tk_Window tkwin)
{
- int result = false;
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 101400
if (@available(macOS 10.14, *)) {
TkWindow *winPtr = (TkWindow*) tkwin;
+ NSAppearanceName name;
NSView *view = nil;
if (winPtr && winPtr->privatePtr) {
view = TkMacOSXDrawableView(winPtr->privatePtr);
}
if (view) {
- result = (view.effectiveAppearance == darkAqua);
+ name = [[view effectiveAppearance] name];
} else {
- result = ([NSAppearance currentAppearance] == darkAqua);
+ name = [[NSAppearance currentAppearance] name];
}
+ return (name == NSAppearanceNameDarkAqua);
}
#endif
- return result;
+ return false;
}
/*
diff --git a/macosx/tkMacOSXWindowEvent.c b/macosx/tkMacOSXWindowEvent.c
index 8214731..35b1b49 100644
--- a/macosx/tkMacOSXWindowEvent.c
+++ b/macosx/tkMacOSXWindowEvent.c
@@ -1067,54 +1067,83 @@ ConfigureRestrictProc(
}
/*
- * This method is called when a user changes between light and dark mode. The
- * implementation here generates a Tk virtual event which can be bound to a
- * function that redraws the window in an appropriate style.
+ * In macOS 10.14 and later his method is called when a user changes between
+ * light and dark mode or changes the accent color. The implementation
+ * generates two virtual events. The first is either <<LightAqua>> or
+ * <<DarkAqua>>, depending on the view's current effective appearance. The
+ * second is <<AppearnceChanged>> and has a data string describing the
+ * effective appearance of the view and the current accent and highlight
+ * colors.
*/
+static char *accentNames[] = {
+ "Graphite",
+ "Red",
+ "Orange",
+ "Yellow",
+ "Green",
+ "Blue",
+ "Purple",
+ "Pink",
+};
+
- (void) viewDidChangeEffectiveAppearance
{
- XVirtualEvent event;
- int x, y;
- NSWindow *w = [self window];
- TkWindow *winPtr = TkMacOSXGetTkWindow(w);
- Tk_Window tkwin = (Tk_Window) winPtr;
- static NSAppearanceName lastAppearanceName = nil;
- NSAppearanceName effectiveAppearanceName = [[self effectiveAppearance] name];
- Tk_Uid eventName = NULL;
- if (!winPtr) {
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= 101400
+
+ Tk_Window tkwin = (Tk_Window) TkMacOSXGetTkWindow([self window]);
+ if (!tkwin) {
return;
}
- if (!lastAppearanceName) {
- lastAppearanceName = [[NSAppearance currentAppearance] name];
- return;
+ NSAppearanceName effectiveAppearanceName = [[self effectiveAppearance] name];
+ const char *accentName, *highlightName;
+ NSUserDefaults *preferences = [NSUserDefaults standardUserDefaults];
+ NSString *accent = [preferences stringForKey:@"AppleAccentColor"];
+ NSString *highlight = [[[preferences stringForKey:@"AppleHighlightColor"]
+ componentsSeparatedByString: @" "]
+ objectAtIndex:3];
+ static char *defaultColor = NULL;
+
+ if (!defaultColor) {
+ defaultColor = [NSApp macOSVersion] < 110000 ? "Blue" : "Multicolor";
+
+ /*
+ * AppKit calls this method when the user changes the Accent Color
+ * but not when the user changes the Highlight Color. So we register
+ * to receive KVO notifications for Highlight Color as well.
+ */
+
+ [preferences addObserver:self
+ forKeyPath:@"AppleHighlightColor"
+ options:NSKeyValueObservingOptionNew
+ context:NULL];
}
- if (lastAppearanceName == effectiveAppearanceName) {
- eventName = Tk_GetUid("NewAccentColor");
+ accentName = accent ? accentNames[1 + accent.intValue] : defaultColor;
+ highlightName = highlight ? highlight.UTF8String: defaultColor;
+
+ char data[256];
+ snprintf(data, 256, "Appearance %s Accent %s Highlight %s",
+ effectiveAppearanceName.UTF8String, accentName,
+ highlightName);
+ TkSendVirtualEvent(tkwin, "AppearanceChanged", Tcl_NewStringObj(data, -1));
+ if (effectiveAppearanceName == NSAppearanceNameAqua) {
+ TkSendVirtualEvent(tkwin, "LightAqua", NULL);
} else if (effectiveAppearanceName == NSAppearanceNameDarkAqua) {
- eventName = Tk_GetUid("DarkAqua");
- } else if (effectiveAppearanceName == NSAppearanceNameAqua) {
- eventName = Tk_GetUid("LightAqua");
- } else {
- return;
+ TkSendVirtualEvent(tkwin, "DarkAqua", NULL);
}
- lastAppearanceName = effectiveAppearanceName;
- bzero(&event, sizeof(XVirtualEvent));
- event.type = VirtualEvent;
- event.serial = LastKnownRequestProcessed(Tk_Display(tkwin));
- event.send_event = false;
- event.display = Tk_Display(tkwin);
- event.event = Tk_WindowId(tkwin);
- event.root = XRootWindow(Tk_Display(tkwin), 0);
- event.subwindow = None;
- event.time = TkpGetMS();
- XQueryPointer(NULL, winPtr->window, NULL, NULL,
- &event.x_root, &event.y_root, &x, &y, &event.state);
- Tk_TopCoordsToWindow(tkwin, x, y, &event.x, &event.y);
- event.same_screen = true;
- event.name = eventName;
- Tk_QueueWindowEvent((XEvent *) &event, TCL_QUEUE_TAIL);
+#endif
+}
+
+- (void)observeValueForKeyPath:(NSString *)keyPath
+ ofObject:(id)object
+ change:(NSDictionary *)change
+ context:(void *)context
+{
+ NSUserDefaults *preferences = [NSUserDefaults standardUserDefaults];
+ if (object == preferences && [keyPath isEqualToString:@"AppleHighlightColor"]) {
+ [self viewDidChangeEffectiveAppearance];
+ }
}
/*