summaryrefslogtreecommitdiffstats
path: root/macosx
diff options
context:
space:
mode:
authorjan.nijtmans <nijtmans@users.sourceforge.net>2020-09-24 14:03:35 (GMT)
committerjan.nijtmans <nijtmans@users.sourceforge.net>2020-09-24 14:03:35 (GMT)
commit60091ce863fdbfbf444d6970d44fb50166ccd6fe (patch)
tree01d9762601541ddc55b930c28b3d547c496b3d67 /macosx
parente59d11829980b85d1a4c263d108f0a601fce5e5b (diff)
parent5a024656faa09acb77aa34603e41b1cd5e38fbe5 (diff)
downloadtk-60091ce863fdbfbf444d6970d44fb50166ccd6fe.zip
tk-60091ce863fdbfbf444d6970d44fb50166ccd6fe.tar.gz
tk-60091ce863fdbfbf444d6970d44fb50166ccd6fe.tar.bz2
Merge 8.6. Change macro names
Diffstat (limited to 'macosx')
-rw-r--r--macosx/tkMacOSXHLEvents.c44
-rw-r--r--macosx/tkMacOSXInit.c122
-rw-r--r--macosx/tkMacOSXMouseEvent.c26
-rw-r--r--macosx/tkMacOSXSubwindows.c28
-rw-r--r--macosx/tkMacOSXTest.c30
-rw-r--r--macosx/tkMacOSXWindowEvent.c1
-rw-r--r--macosx/tkMacOSXWm.c8
-rw-r--r--macosx/ttkMacOSXTheme.c78
8 files changed, 242 insertions, 95 deletions
diff --git a/macosx/tkMacOSXHLEvents.c b/macosx/tkMacOSXHLEvents.c
index 88036ee..258740b 100644
--- a/macosx/tkMacOSXHLEvents.c
+++ b/macosx/tkMacOSXHLEvents.c
@@ -39,6 +39,7 @@ typedef struct AppleEventInfo {
const char *procedure;
Tcl_DString command;
NSAppleEventDescriptor *replyEvent; /* Only used for DoScriptText. */
+ int retryCount;
} AppleEventInfo;
/*
@@ -148,6 +149,7 @@ static const char *scriptTextProc = "::tk::mac::DoScriptText";
AEKeyword keyword;
Tcl_DString pathName;
+
/*
* Do nothing if we don't have an interpreter.
*/
@@ -215,7 +217,13 @@ static const char *scriptTextProc = "::tk::mac::DoScriptText";
AEInfo->interp = _eventInterp;
AEInfo->procedure = openDocumentProc;
AEInfo->replyEvent = nil;
- Tcl_DoWhenIdle(ProcessAppleEvent, (ClientData)AEInfo);
+ AEInfo->retryCount = 0;
+
+ if (Tcl_FindCommand(_eventInterp, "::tk::mac::OpenDocuments", NULL, 0)){
+ ProcessAppleEvent((ClientData)AEInfo);
+ } else {
+ Tcl_CreateTimerHandler(500, ProcessAppleEvent, (ClientData)AEInfo);
+ }
}
- (void) handlePrintDocumentsEvent: (NSAppleEventDescriptor *)event
@@ -232,7 +240,8 @@ static const char *scriptTextProc = "::tk::mac::DoScriptText";
AEInfo->interp = _eventInterp;
AEInfo->procedure = printDocProc;
AEInfo->replyEvent = nil;
- Tcl_DoWhenIdle(ProcessAppleEvent, (ClientData)AEInfo);
+ AEInfo->retryCount = 0;
+ ProcessAppleEvent((ClientData)AEInfo);
}
- (void) handleDoScriptEvent: (NSAppleEventDescriptor *)event
@@ -293,7 +302,8 @@ static const char *scriptTextProc = "::tk::mac::DoScriptText";
AEInfo->interp = _eventInterp;
AEInfo->procedure = scriptFileProc;
AEInfo->replyEvent = nil;
- Tcl_DoWhenIdle(ProcessAppleEvent, (ClientData)AEInfo);
+ AEInfo->retryCount = 0;
+ ProcessAppleEvent((ClientData)AEInfo);
}
}
} else if (noErr == AEGetParamPtr(theDesc, keyDirectObject, typeUTF8Text, &type,
@@ -317,12 +327,13 @@ static const char *scriptTextProc = "::tk::mac::DoScriptText";
Tcl_DStringAppendElement(scriptTextCommand, data);
AEInfo->interp = _eventInterp;
AEInfo->procedure = scriptTextProc;
+ AEInfo->retryCount = 0;
if (Tcl_FindCommand(AEInfo->interp, AEInfo->procedure, NULL, 0)) {
AEInfo->replyEvent = replyEvent;
ProcessAppleEvent((ClientData)AEInfo);
} else {
AEInfo->replyEvent = nil;
- Tcl_DoWhenIdle(ProcessAppleEvent, (ClientData)AEInfo);
+ ProcessAppleEvent((ClientData)AEInfo);
}
}
}
@@ -343,7 +354,8 @@ static const char *scriptTextProc = "::tk::mac::DoScriptText";
AEInfo->interp = _eventInterp;
AEInfo->procedure = launchURLProc;
AEInfo->replyEvent = nil;
- Tcl_DoWhenIdle(ProcessAppleEvent, (ClientData)AEInfo);
+ AEInfo->retryCount = 0;
+ ProcessAppleEvent((ClientData)AEInfo);
}
@end
@@ -378,8 +390,26 @@ static void ProcessAppleEvent(
{
int code;
AppleEventInfo *AEInfo = (AppleEventInfo*) clientData;
- if (!AEInfo->interp ||
- !Tcl_FindCommand(AEInfo->interp, AEInfo->procedure, NULL, 0)) {
+
+ if (!AEInfo->interp) {
+ return;
+ }
+
+ /*
+ * Apple events that are delivered during the app startup can arrive
+ * before the Tcl procedure for handling the events has been defined.
+ * If the command is not found we create a timer handler to process
+ * the event later, hopefully after the command has been created.
+ * We retry up to 2 times before giving up.
+ */
+
+ if (!Tcl_FindCommand(AEInfo->interp, AEInfo->procedure, NULL, 0)) {
+ if (AEInfo->retryCount < 2) {
+ AEInfo->retryCount++;
+ Tcl_CreateTimerHandler(200, ProcessAppleEvent, clientData);
+ } else {
+ ckfree(clientData);
+ }
return;
}
code = Tcl_EvalEx(AEInfo->interp, Tcl_DStringValue(&AEInfo->command),
diff --git a/macosx/tkMacOSXInit.c b/macosx/tkMacOSXInit.c
index 51c1e37..bda5f46 100644
--- a/macosx/tkMacOSXInit.c
+++ b/macosx/tkMacOSXInit.c
@@ -14,10 +14,9 @@
*/
#include "tkMacOSXPrivate.h"
-
-#include <sys/stat.h>
#include <dlfcn.h>
#include <objc/objc-auto.h>
+#include <sys/stat.h>
static char tkLibPath[PATH_MAX + 1] = "";
@@ -145,7 +144,7 @@ static int TkMacOSXGetAppPathCmd(ClientData cd, Tcl_Interp *ip,
*/
[NSApp _lockAutoreleasePool];
- while (Tcl_DoOneEvent(TCL_WINDOW_EVENTS| TCL_DONT_WAIT)) {}
+ while (Tcl_DoOneEvent(TCL_WINDOW_EVENTS|TCL_DONT_WAIT)) {}
[NSApp _unlockAutoreleasePool];
}
@@ -278,15 +277,15 @@ TkpInit(
static int initialized = 0;
/*
- * Since it is possible for TkInit to be called multiple times and we
- * don't want to do the following initialization multiple times we protect
- * against doing it more than once.
+ * TkpInit can be called multiple times with different interpreters. But
+ * The application initialization should only be done onece.
*/
if (!initialized) {
struct stat st;
-
- initialized = 1;
+ Bool shouldOpenConsole = NO;
+ Bool stdinIsNullish = (!isatty(0) &&
+ (fstat(0, &st) || (S_ISCHR(st.st_mode) && st.st_blocks == 0)));
/*
* Initialize/check OS version variable for runtime checks.
@@ -296,6 +295,8 @@ TkpInit(
# error Mac OS X 10.6 required
#endif
+ initialized = 1;
+
#ifdef TK_FRAMEWORK
/*
* When Tk is in a framework, force tcl_findLibrary to look in the
@@ -313,16 +314,6 @@ TkpInit(
#endif
/*
- * FIXME: Close stdin & stdout for remote debugging otherwise we will
- * fight with gdb for stdin & stdout
- */
-
- if (getenv("XCNOSTDIN") != NULL) {
- close(0);
- close(1);
- }
-
- /*
* Instantiate our NSApplication object. This needs to be done before
* we check whether to open a console window.
*/
@@ -337,20 +328,20 @@ TkpInit(
nil]];
[TKApplication sharedApplication];
[pool drain];
- [NSApp _setup:interp];
/*
- * WARNING: The finishLaunching method runs asynchronously, apparently
- * in a separate thread. This creates a race between the
- * initialization of the NSApplication and the initialization of Tk.
- * If Tk wins the race bad things happen with the root window (see
- * below). If the NSApplication wins then an AppleEvent created during
- * launch, e.g. by dropping a file icon on the application icon, will
- * be delivered before the procedure meant to to handle the AppleEvent
- * has been defined. This is now handled by processing the AppleEvent
- * as an idle task. See tkMacOSXHLEvents.c.
+ * WARNING: The finishLaunching method runs asynchronously. This
+ * creates a race between the initialization of the NSApplication and
+ * the initialization of Tk. If Tk wins the race bad things happen
+ * with the root window (see below). If the NSApplication wins then an
+ * AppleEvent created during launch, e.g. by dropping a file icon on
+ * the application icon, will be delivered before the procedure meant
+ * to to handle the AppleEvent has been defined. This is handled in
+ * tkMacOSXHLEvents.c by scheduling a timer event to handle the
+ * ApplEvent later, after the required procedure has been defined.
*/
+ [NSApp _setup:interp];
[NSApp finishLaunching];
/*
@@ -377,36 +368,52 @@ TkpInit(
Tcl_DoOneEvent(TCL_WINDOW_EVENTS | TCL_DONT_WAIT);
/*
- * If we don't have a TTY and stdin is a special character file of
- * length 0, (e.g. /dev/null, which is what Finder sets when double
- * clicking Wish) then use the Tk based console interpreter.
+ * Decide whether to open a console window. If the TK_CONSOLE
+ * environment variable is not defined we only show the console if
+ * stdin is not a tty and there is no startup script.
*/
- if (getenv("TK_CONSOLE") ||
- (!isatty(0) && (fstat(0, &st) ||
- (S_ISCHR(st.st_mode) && st.st_blocks == 0)))) {
+ if (getenv("TK_CONSOLE")) {
+ shouldOpenConsole = YES;
+ } else if (stdinIsNullish && Tcl_GetStartupScript(NULL) == NULL) {
+ const char *intvar = Tcl_GetVar2(interp, "tcl_interactive",
+ NULL, TCL_GLOBAL_ONLY);
+ if (intvar == NULL) {
+ Tcl_SetVar2(interp, "tcl_interactive", NULL, "1",
+ TCL_GLOBAL_ONLY);
+ }
+ shouldOpenConsole = YES;
+ }
+ if (shouldOpenConsole) {
Tk_InitConsoleChannels(interp);
Tcl_RegisterChannel(interp, Tcl_GetStdChannel(TCL_STDIN));
Tcl_RegisterChannel(interp, Tcl_GetStdChannel(TCL_STDOUT));
Tcl_RegisterChannel(interp, Tcl_GetStdChannel(TCL_STDERR));
+ if (Tk_CreateConsoleWindow(interp) == TCL_ERROR) {
+ return TCL_ERROR;
+ }
+ } else if (stdinIsNullish) {
/*
- * Only show the console if we don't have a startup script and
- * tcl_interactive hasn't been set already.
+ * When launched as a macOS application with no console,
+ * redirect stderr and stdout to /dev/null. This avoids waiting
+ * forever for those files to become writable if the underlying
+ * Tcl program tries to write to them with a puts command.
*/
- if (Tcl_GetStartupScript(NULL) == NULL) {
- const char *intvar = Tcl_GetVar2(interp,
- "tcl_interactive", NULL, TCL_GLOBAL_ONLY);
+ FILE *null = fopen("/dev/null", "w");
+ dup2(fileno(null), STDOUT_FILENO);
+ dup2(fileno(null), STDERR_FILENO);
+ }
- if (intvar == NULL) {
- Tcl_SetVar2(interp, "tcl_interactive", NULL, "1",
- TCL_GLOBAL_ONLY);
- }
- }
- if (Tk_CreateConsoleWindow(interp) == TCL_ERROR) {
- return TCL_ERROR;
- }
+ /*
+ * FIXME: Close stdin & stdout for remote debugging if XCNOSTDIN is
+ * set. Otherwise we will fight with gdb for stdin & stdout
+ */
+
+ if (getenv("XCNOSTDIN") != NULL) {
+ close(0);
+ close(1);
}
/*
@@ -416,8 +423,28 @@ TkpInit(
*/
TkMacOSXServices_Init(interp);
+
+ /*
+ * The root window has been created and mapped, but XMapWindow deferred its
+ * call to makeKeyAndOrderFront because the first call to XMapWindow
+ * occurs too early in the initialization process for that. Process idle
+ * tasks now, so the root window is configured, then order it front.
+ */
+
+ while(Tcl_DoOneEvent(TCL_IDLE_EVENTS)) {};
+ for (NSWindow *window in [NSApp windows]) {
+ TkWindow *winPtr = TkMacOSXGetTkWindow(window);
+ if (winPtr && Tk_IsMapped(winPtr)) {
+ [window makeKeyAndOrderFront:NSApp];
+ break;
+ }
+ }
}
+ /*
+ * Initialization steps that are needed for all interpreters.
+ */
+
if (tkLibPath[0] != '\0') {
Tcl_SetVar2(interp, "tk_library", NULL, tkLibPath, TCL_GLOBAL_ONLY);
}
@@ -433,6 +460,7 @@ TkpInit(
TkMacOSXIconBitmapObjCmd, NULL, NULL);
Tcl_CreateObjCommand(interp, "::tk::mac::GetAppPath",
TkMacOSXGetAppPathCmd, NULL, NULL);
+
return TCL_OK;
}
diff --git a/macosx/tkMacOSXMouseEvent.c b/macosx/tkMacOSXMouseEvent.c
index 9e57e7d..6f1b7cd 100644
--- a/macosx/tkMacOSXMouseEvent.c
+++ b/macosx/tkMacOSXMouseEvent.c
@@ -54,6 +54,7 @@ enum {
NSWindow *eventWindow = [theEvent window];
NSEventType eventType = [theEvent type];
NSRect viewFrame = [[eventWindow contentView] frame];
+ NSPoint location = [theEvent locationInWindow];
TkWindow *winPtr = NULL, *grabWinPtr;
Tk_Window tkwin = None, capture, target;
NSPoint local, global;
@@ -71,13 +72,12 @@ enum {
* If this event is not for a Tk toplevel, it should just be passed up the
* responder chain. However, there is an exception for synthesized events,
* which are used in testing. Those events are recognized by having their
- * (unused) pressure field set to the impossible value -1.0.
+ * both the windowNumber and the eventNumber set to -1.
*/
- if (![eventWindow isMemberOfClass:[TKWindow class]]) {
- if (eventWindow && [theEvent pressure] != -1.0) {
+ if (eventWindow && ![eventWindow isMemberOfClass:[TKWindow class]]) {
+ if ([theEvent windowNumber] != -1 || [theEvent eventNumber] != -1)
return theEvent;
- }
}
/*
@@ -85,8 +85,9 @@ enum {
*/
if (eventWindow) {
- inTitleBar = viewFrame.size.height < [theEvent locationInWindow].y;
+ inTitleBar = viewFrame.size.height < location.y;
}
+
button = [theEvent buttonNumber] + Button1;
switch (eventType) {
case NSRightMouseUp:
@@ -101,13 +102,16 @@ enum {
buttonState |= TkGetButtonMask(button);
break;
case NSMouseEntered:
- if (!inTitleBar) {
+ if ([eventWindow respondsToSelector:@selector(mouseInResizeArea)] &&
+ !inTitleBar) {
[(TKWindow *)eventWindow setMouseInResizeArea:YES];
}
break;
case NSMouseExited:
- [(TKWindow *)eventWindow setMouseInResizeArea:NO];
- break;
+ if ([eventWindow respondsToSelector:@selector(mouseInResizeArea)]) {
+ [(TKWindow *)eventWindow setMouseInResizeArea:NO];
+ break;
+ }
case NSLeftMouseUp:
case NSLeftMouseDown:
case NSMouseMoved:
@@ -128,9 +132,9 @@ enum {
* [39cbacb9e8].
*/
- if (eventType == NSLeftMouseDown || eventType == NSLeftMouseDragged) {
- if ([(TKWindow *)eventWindow mouseInResizeArea] &&
- ([eventWindow styleMask] & NSResizableWindowMask)) {
+ if (eventType == NSLeftMouseDown) {
+ if ([eventWindow respondsToSelector:@selector(mouseInResizeArea)] &&
+ [(TKWindow *) eventWindow mouseInResizeArea]) {
/*
* When the left button is pressed in the resize area, we receive
diff --git a/macosx/tkMacOSXSubwindows.c b/macosx/tkMacOSXSubwindows.c
index 002eae6..6ac766c 100644
--- a/macosx/tkMacOSXSubwindows.c
+++ b/macosx/tkMacOSXSubwindows.c
@@ -143,6 +143,7 @@ XMapWindow(
TkWindow *winPtr = macWin->winPtr;
NSWindow *win = TkMacOSXGetNSWindowForDrawable(window);
XEvent event;
+ static Bool initialized = NO;
/*
* Under certain situations it's possible for this function to be called
@@ -172,12 +173,14 @@ XMapWindow(
TkMacOSXApplyWindowAttributes(winPtr, win);
[win setExcludedFromWindowsMenu:NO];
- [NSApp activateIgnoringOtherApps:NO];
+ [NSApp activateIgnoringOtherApps:initialized];
[view addTkDirtyRect: [view bounds]];
- if ([win canBecomeKeyWindow]) {
- [win makeKeyAndOrderFront:NSApp];
- } else {
- [win orderFrontRegardless];
+ if (initialized) {
+ if ([win canBecomeKeyWindow]) {
+ [win makeKeyAndOrderFront:NSApp];
+ } else {
+ [win orderFrontRegardless];
+ }
}
} else {
TkWindow *contWinPtr = TkpGetOtherWindow(winPtr);
@@ -233,11 +236,15 @@ XMapWindow(
* Generate VisibilityNotify events for window and all mapped children.
*/
- event.xany.send_event = False;
- event.xany.display = display;
- event.xvisibility.type = VisibilityNotify;
- event.xvisibility.state = VisibilityUnobscured;
- NotifyVisibility(winPtr, &event);
+ if (initialized) {
+ event.xany.send_event = False;
+ event.xany.display = display;
+ event.xvisibility.type = VisibilityNotify;
+ event.xvisibility.state = VisibilityUnobscured;
+ NotifyVisibility(winPtr, &event);
+ } else {
+ initialized = YES;
+ }
return Success;
}
@@ -308,6 +315,7 @@ XUnmapWindow(
if (!Tk_IsEmbedded(winPtr) &&
winPtr->wmInfoPtr->hints.initial_state!=IconicState) {
[win orderOut:nil];
+ [win setExcludedFromWindowsMenu:YES];
}
TkMacOSXInvalClipRgns((Tk_Window)winPtr);
diff --git a/macosx/tkMacOSXTest.c b/macosx/tkMacOSXTest.c
index 52cda8f..7981f7e 100644
--- a/macosx/tkMacOSXTest.c
+++ b/macosx/tkMacOSXTest.c
@@ -178,8 +178,8 @@ TkTestLogDisplay(
* location. It injects NSEvents into the NSApplication event queue, as
* opposed to adding events to the Tcl queue as event generate would do.
* One application is for testing the grab command. These events have
- * pressure = -1.0 as a signal indicating that they should not be ignored
- * by [NSApp tkProcessMouseEvent].
+ * their unused context property set to 1 as a signal indicating that they
+ * should not be ignored by [NSApp tkProcessMouseEvent].
*
* Results:
* A standard Tcl result.
@@ -197,7 +197,8 @@ PressButtonObjCmd(
int objc,
Tcl_Obj *const objv[])
{
- int x = 0, y = 0, i, value, wNum;
+ int x = 0, y = 0, i, value;
+ NSInteger signal = -1;
CGPoint pt;
NSPoint loc;
NSEvent *motion, *press, *release;
@@ -231,35 +232,40 @@ PressButtonObjCmd(
pt.x = loc.x = x;
pt.y = y;
loc.y = ScreenHeight - y;
- wNum = 0;
+
+ /*
+ * We set the window number and the eventNumber to -1 as a signal to
+ * processMouseEvent.
+ */
+
CGWarpMouseCursorPosition(pt);
motion = [NSEvent mouseEventWithType:NSMouseMoved
location:loc
modifierFlags:0
timestamp:GetCurrentEventTime()
- windowNumber:wNum
+ windowNumber:signal
context:nil
- eventNumber:0
+ eventNumber:signal
clickCount:1
- pressure:-1.0];
+ pressure:0.0];
[NSApp postEvent:motion atStart:NO];
press = [NSEvent mouseEventWithType:NSLeftMouseDown
location:loc
modifierFlags:0
timestamp:GetCurrentEventTime()
- windowNumber:wNum
+ windowNumber:signal
context:nil
- eventNumber:1
+ eventNumber:signal
clickCount:1
- pressure:-1.0];
+ pressure:0.0];
[NSApp postEvent:press atStart:NO];
release = [NSEvent mouseEventWithType:NSLeftMouseUp
location:loc
modifierFlags:0
timestamp:GetCurrentEventTime()
- windowNumber:wNum
+ windowNumber:signal
context:nil
- eventNumber:2
+ eventNumber:signal
clickCount:1
pressure:-1.0];
[NSApp postEvent:release atStart:NO];
diff --git a/macosx/tkMacOSXWindowEvent.c b/macosx/tkMacOSXWindowEvent.c
index 9e6c3dd..fcbd134 100644
--- a/macosx/tkMacOSXWindowEvent.c
+++ b/macosx/tkMacOSXWindowEvent.c
@@ -211,6 +211,7 @@ extern NSString *NSWindowDidOrderOffScreenNotification;
TkWindow *winPtr = TkMacOSXGetTkWindow(window);
if (winPtr) {
TKContentView *view = [window contentView];
+
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 101500
if (@available(macOS 10.15, *)) {
[view viewDidChangeEffectiveAppearance];
diff --git a/macosx/tkMacOSXWm.c b/macosx/tkMacOSXWm.c
index 6b7871f..b55f039 100644
--- a/macosx/tkMacOSXWm.c
+++ b/macosx/tkMacOSXWm.c
@@ -1827,7 +1827,7 @@ WmDeiconifyCmd(
ZoomState : NormalState);
[win setExcludedFromWindowsMenu:NO];
TkMacOSXApplyWindowAttributes(winPtr, win);
- [win orderFront:nil];
+ [win orderFront:NSApp];
if (wmPtr->icon) {
Tk_UnmapWindow((Tk_Window)wmPtr->icon);
}
@@ -6124,6 +6124,8 @@ TkMacOSXMakeRealWindowExist(
NSRect contentRect = NSMakeRect(5 - structureRect.origin.x,
TkMacOSXZeroScreenHeight() - (TkMacOSXZeroScreenTop() + 5 +
structureRect.origin.y + structureRect.size.height + 200), 200, 200);
+ if (wmPtr->hints.initial_state == WithdrawnState) {
+ }
TKWindow *window = [[winClass alloc] initWithContentRect:contentRect
styleMask:styleMask backing:NSBackingStoreBuffered defer:YES];
if (!window) {
@@ -6889,7 +6891,7 @@ ApplyContainerOverrideChanges(
}
} else {
if (wmPtr->macClass == kSimpleWindowClass &&
- oldAttributes == kWindowNoActivatesAttribute) {
+ (oldAttributes & kWindowNoActivatesAttribute)) {
wmPtr->macClass = kDocumentWindowClass;
wmPtr->attributes =
macClassAttrs[kDocumentWindowClass].defaultAttrs;
@@ -6921,7 +6923,7 @@ ApplyContainerOverrideChanges(
[macWindow setExcludedFromWindowsMenu:YES];
[macWindow setStyleMask:styleMask];
if (wmPtr->hints.initial_state == NormalState) {
- [macWindow orderFront:nil];
+ [macWindow orderFront:NSApp];
}
if (wmPtr->container != NULL) {
wmPtr->flags |= WM_TOPMOST;
diff --git a/macosx/ttkMacOSXTheme.c b/macosx/ttkMacOSXTheme.c
index df597f4..3541dd8 100644
--- a/macosx/ttkMacOSXTheme.c
+++ b/macosx/ttkMacOSXTheme.c
@@ -303,9 +303,10 @@ static void GetBackgroundColor(
/*----------------------------------------------------------------------
- * +++ Single Arrow Buttons --
+ * +++ Single Arrow Images --
*
- * Used in ListHeaders and Comboboxes.
+ * Used in ListHeaders and Comboboxes as well as disclosure triangles in
+ * macOS 11.
*/
static void DrawDownArrow(
@@ -352,6 +353,48 @@ static void DrawUpArrow(
CGContextStrokePath(context);
}
+static void DrawClosedDisclosure(
+ CGContextRef context,
+ CGRect bounds,
+ CGFloat inset,
+ CGFloat size,
+ CGFloat *rgba)
+{
+ CGFloat x, y;
+
+ CGContextSetRGBStrokeColor(context, rgba[0], rgba[1], rgba[2], rgba[3]);
+ CGContextSetLineWidth(context, 1.5);
+ x = bounds.origin.x + inset;
+ y = bounds.origin.y + trunc(bounds.size.height / 2);
+ CGContextBeginPath(context);
+ CGPoint arrow[3] = {
+ {x, y - size / 4 - 1}, {x + size / 2, y}, {x, y + size / 4 + 1}
+ };
+ CGContextAddLines(context, arrow, 3);
+ CGContextStrokePath(context);
+}
+
+static void DrawOpenDisclosure(
+ CGContextRef context,
+ CGRect bounds,
+ CGFloat inset,
+ CGFloat size,
+ CGFloat *rgba)
+{
+ CGFloat x, y;
+
+ CGContextSetRGBStrokeColor(context, rgba[0], rgba[1], rgba[2], rgba[3]);
+ CGContextSetLineWidth(context, 1.5);
+ x = bounds.origin.x + inset;
+ y = bounds.origin.y + trunc(bounds.size.height / 2);
+ CGContextBeginPath(context);
+ CGPoint arrow[3] = {
+ {x, y - size / 4}, {x + size / 2, y + size / 2}, {x + size, y - size / 4}
+ };
+ CGContextAddLines(context, arrow, 3);
+ CGContextStrokePath(context);
+}
+
/*----------------------------------------------------------------------
* +++ Double Arrow Buttons --
*
@@ -2101,10 +2144,16 @@ static void TrackElementDraw(
Tcl_GetDoubleFromObj(NULL, elem->valueObj, &value);
factor = RangeToFactor(to);
+ /*
+ * HIThemeTrackDrawInfo uses 2-byte alignment; assigning to a separate
+ * bounds variable avoids UBSan (-fsanitize=alignment) complaints.
+ */
+
+ CGRect bounds = BoxToRect(d, b);
HIThemeTrackDrawInfo info = {
.version = 0,
.kind = data->kind,
- .bounds = BoxToRect(d, b),
+ .bounds = bounds,
.min = from * factor,
.max = to * factor,
.value = value * factor,
@@ -2239,13 +2288,19 @@ static void PbarElementDraw(
Tcl_GetIntFromObj(NULL, pbar->phaseObj, &phase);
factor = RangeToFactor(maximum);
+ /*
+ * HIThemeTrackDrawInfo uses 2-byte alignment; assigning to a separate
+ * bounds variable avoids UBSan (-fsanitize=alignment) complaints.
+ */
+
+ CGRect bounds = BoxToRect(d, b);
HIThemeTrackDrawInfo info = {
.version = 0,
.kind =
(!strcmp("indeterminate",
Tcl_GetString(pbar->modeObj)) && value) ?
kThemeIndeterminateBar : kThemeProgressBar,
- .bounds = BoxToRect(d, b),
+ .bounds = bounds,
.min = 0,
.max = maximum * factor,
.value = value * factor,
@@ -3001,8 +3056,21 @@ static void DisclosureElementDraw(
};
BEGIN_DRAWING(d)
- ChkErr(HIThemeDrawButton, &bounds, &info, dc.context, HIOrientation,
+ if ([NSApp macOSVersion] >= 110000) {
+ CGFloat rgba[4];
+ NSColorSpace *deviceRGB = [NSColorSpace deviceRGBColorSpace];
+ NSColor *stroke = [[NSColor textColor]
+ colorUsingColorSpace: deviceRGB];
+ [stroke getComponents: rgba];
+ if (state & TTK_TREEVIEW_STATE_OPEN) {
+ DrawOpenDisclosure(dc.context, bounds, 2, 8, rgba);
+ } else {
+ DrawClosedDisclosure(dc.context, bounds, 2, 12, rgba);
+ }
+ } else {
+ ChkErr(HIThemeDrawButton, &bounds, &info, dc.context, HIOrientation,
NULL);
+ }
END_DRAWING
}
}