diff options
author | jan.nijtmans <nijtmans@users.sourceforge.net> | 2020-09-24 14:03:35 (GMT) |
---|---|---|
committer | jan.nijtmans <nijtmans@users.sourceforge.net> | 2020-09-24 14:03:35 (GMT) |
commit | 60091ce863fdbfbf444d6970d44fb50166ccd6fe (patch) | |
tree | 01d9762601541ddc55b930c28b3d547c496b3d67 /macosx | |
parent | e59d11829980b85d1a4c263d108f0a601fce5e5b (diff) | |
parent | 5a024656faa09acb77aa34603e41b1cd5e38fbe5 (diff) | |
download | tk-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.c | 44 | ||||
-rw-r--r-- | macosx/tkMacOSXInit.c | 122 | ||||
-rw-r--r-- | macosx/tkMacOSXMouseEvent.c | 26 | ||||
-rw-r--r-- | macosx/tkMacOSXSubwindows.c | 28 | ||||
-rw-r--r-- | macosx/tkMacOSXTest.c | 30 | ||||
-rw-r--r-- | macosx/tkMacOSXWindowEvent.c | 1 | ||||
-rw-r--r-- | macosx/tkMacOSXWm.c | 8 | ||||
-rw-r--r-- | macosx/ttkMacOSXTheme.c | 78 |
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 } } |