diff options
author | culler <culler> | 2020-08-15 10:22:15 (GMT) |
---|---|---|
committer | culler <culler> | 2020-08-15 10:22:15 (GMT) |
commit | 8b6c8e84302179205f43165ff8e1ce15d2c8860a (patch) | |
tree | 6d81361052d6f4aa86a2c6bfd3d0163c68121b95 | |
parent | 8ac846412241e0914a4bb279bf586c53835e34ab (diff) | |
download | tk-8b6c8e84302179205f43165ff8e1ce15d2c8860a.zip tk-8b6c8e84302179205f43165ff8e1ce15d2c8860a.tar.gz tk-8b6c8e84302179205f43165ff8e1ce15d2c8860a.tar.bz2 |
sync with bug-315104a5c10
-rw-r--r-- | macosx/README | 36 | ||||
-rw-r--r-- | macosx/tkMacOSXColor.c | 9 | ||||
-rw-r--r-- | macosx/tkMacOSXWindowEvent.c | 105 |
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]; + } } /* |