Import Tk 8.6.11

This commit is contained in:
Steve Dower
2021-03-30 00:54:10 +01:00
parent 42c69189d9
commit 070b8750b0
403 changed files with 21608 additions and 16269 deletions

View File

@@ -30,17 +30,17 @@
* Declaration of functions used only in this file
*/
static int GenerateUpdates(HIShapeRef updateRgn,
CGRect *updateBounds, TkWindow *winPtr);
static int GenerateUpdates(
CGRect *updateBounds, TkWindow *winPtr);
static int GenerateActivateEvents(TkWindow *winPtr,
int activeFlag);
static void DoWindowActivate(ClientData clientData);
#pragma mark TKApplication(TKWindowEvent)
#ifdef TK_MAC_DEBUG_NOTIFICATIONS
extern NSString *NSWindowWillOrderOnScreenNotification;
extern NSString *NSWindowDidOrderOnScreenNotification;
extern NSString *NSWindowWillOrderOnScreenNotification;
#ifdef TK_MAC_DEBUG_NOTIFICATIONS
extern NSString *NSWindowDidOrderOffScreenNotification;
#endif
@@ -90,15 +90,12 @@ extern NSString *NSWindowDidOrderOffScreenNotification;
height = bounds.size.height - wmPtr->yInParent;
flags |= TK_SIZE_CHANGED;
}
if (Tcl_GetServiceMode() != TCL_SERVICE_NONE) {
/*
* Propagate geometry changes immediately.
*/
/*
* Propagate geometry changes immediately.
*/
flags |= TK_MACOSX_HANDLE_EVENT_IMMEDIATELY;
}
TkGenWMConfigureEvent((Tk_Window) winPtr, x, y, width, height, flags);
flags |= TK_MACOSX_HANDLE_EVENT_IMMEDIATELY;
TkGenWMConfigureEvent((Tk_Window)winPtr, x, y, width, height, flags);
}
}
@@ -114,31 +111,29 @@ extern NSString *NSWindowDidOrderOffScreenNotification;
if (winPtr) {
winPtr->wmInfoPtr->hints.initial_state =
TkMacOSXIsWindowZoomed(winPtr) ? ZoomState : NormalState;
Tk_MapWindow((Tk_Window) winPtr);
if (Tcl_GetServiceMode() != TCL_SERVICE_NONE) {
Tk_MapWindow((Tk_Window)winPtr);
/*
* Process all Tk events generated by Tk_MapWindow().
*/
/*
* Process all Tk events generated by Tk_MapWindow().
*/
while (Tcl_ServiceEvent(0)) {}
while (Tcl_DoOneEvent(TCL_IDLE_EVENTS|TCL_DONT_WAIT)) {}
while (Tcl_ServiceEvent(0)) {}
while (Tcl_DoOneEvent(TCL_IDLE_EVENTS)) {}
/*
* NSWindowDidDeminiaturizeNotification is received after
* NSWindowDidBecomeKeyNotification, so activate manually
*/
/*
* NSWindowDidDeminiaturizeNotification is received after
* NSWindowDidBecomeKeyNotification, so activate manually
*/
GenerateActivateEvents(winPtr, 1);
} else {
Tcl_DoWhenIdle(DoWindowActivate, winPtr);
}
GenerateActivateEvents(winPtr, 1);
}
}
- (NSRect)windowWillUseStandardFrame:(NSWindow *)window
defaultFrame:(NSRect)newFrame
{
(void)window;
/*
* This method needs to be implemented in order for [NSWindow isZoomed] to
* give the correct answer. But it suffices to always validate every
@@ -151,6 +146,8 @@ extern NSString *NSWindowDidOrderOffScreenNotification;
- (NSSize)window:(NSWindow *)window
willUseFullScreenContentSize:(NSSize)proposedSize
{
(void)window;
/*
* We don't need to change the proposed size, but we do need to implement
* this method. Otherwise the full screen window will be sized to the
@@ -185,7 +182,7 @@ extern NSString *NSWindowDidOrderOffScreenNotification;
TkWindow *winPtr = TkMacOSXGetTkWindow(w);
if (winPtr) {
Tk_UnmapWindow((Tk_Window) winPtr);
Tk_UnmapWindow((Tk_Window)winPtr);
}
}
@@ -197,7 +194,7 @@ extern NSString *NSWindowDidOrderOffScreenNotification;
TkWindow *winPtr = TkMacOSXGetTkWindow(w);
if (winPtr) {
TkGenWMDestroyEvent((Tk_Window) winPtr);
TkGenWMDestroyEvent((Tk_Window)winPtr);
}
/*
@@ -208,6 +205,34 @@ extern NSString *NSWindowDidOrderOffScreenNotification;
return (winPtr ? NO : YES);
}
- (void) windowBecameVisible: (NSNotification *) notification
{
NSWindow *window = [notification object];
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];
}
#endif
[view addTkDirtyRect:[view bounds]];
Tcl_CancelIdleCall(TkMacOSXDrawAllViews, NULL);
Tcl_DoWhenIdle(TkMacOSXDrawAllViews, NULL);
}
}
- (void) windowMapped: (NSNotification *) notification
{
NSWindow *w = [notification object];
TkWindow *winPtr = TkMacOSXGetTkWindow(w);
if (winPtr) {
while (Tcl_DoOneEvent(TCL_IDLE_EVENTS)) {}
}
}
#ifdef TK_MAC_DEBUG_NOTIFICATIONS
- (void) windowDragStart: (NSNotification *) notification
@@ -221,22 +246,6 @@ extern NSString *NSWindowDidOrderOffScreenNotification;
//BOOL start = [[notification name] isEqualToString:NSWindowWillStartLiveResizeNotification];
}
- (void) windowMapped: (NSNotification *) notification
{
TKLog(@"-[%@(%p) %s] %@", [self class], self, _cmd, notification);
NSWindow *w = [notification object];
TkWindow *winPtr = TkMacOSXGetTkWindow(w);
if (winPtr) {
//Tk_MapWindow((Tk_Window) winPtr);
}
}
- (void) windowBecameVisible: (NSNotification *) notification
{
TKLog(@"-[%@(%p) %s] %@", [self class], self, _cmd, notification);
}
- (void) windowUnmapped: (NSNotification *) notification
{
TKLog(@"-[%@(%p) %s] %@", [self class], self, _cmd, notification);
@@ -244,7 +253,7 @@ extern NSString *NSWindowDidOrderOffScreenNotification;
TkWindow *winPtr = TkMacOSXGetTkWindow(w);
if (winPtr) {
//Tk_UnmapWindow((Tk_Window) winPtr);
//Tk_UnmapWindow((Tk_Window)winPtr);
}
}
@@ -263,6 +272,8 @@ extern NSString *NSWindowDidOrderOffScreenNotification;
observe(NSWindowDidResizeNotification, windowBoundsChanged:);
observe(NSWindowDidDeminiaturizeNotification, windowExpanded:);
observe(NSWindowDidMiniaturizeNotification, windowCollapsed:);
observe(NSWindowWillOrderOnScreenNotification, windowMapped:);
observe(NSWindowDidOrderOnScreenNotification, windowBecameVisible:);
#if !(MAC_OS_X_VERSION_MAX_ALLOWED < 1070)
observe(NSWindowDidEnterFullScreenNotification, windowEnteredFullScreen:);
@@ -273,8 +284,6 @@ extern NSString *NSWindowDidOrderOffScreenNotification;
observe(NSWindowWillMoveNotification, windowDragStart:);
observe(NSWindowWillStartLiveResizeNotification, windowLiveResize:);
observe(NSWindowDidEndLiveResizeNotification, windowLiveResize:);
observe(NSWindowWillOrderOnScreenNotification, windowMapped:);
observe(NSWindowDidOrderOnScreenNotification, windowBecameVisible:);
observe(NSWindowDidOrderOffScreenNotification, windowUnmapped:);
#endif
#undef observe
@@ -288,6 +297,8 @@ extern NSString *NSWindowDidOrderOffScreenNotification;
- (void) applicationActivate: (NSNotification *) notification
{
(void)notification;
#ifdef TK_MAC_DEBUG_NOTIFICATIONS
TKLog(@"-[%@(%p) %s] %@", [self class], self, _cmd, notification);
#endif
@@ -312,14 +323,33 @@ extern NSString *NSWindowDidOrderOffScreenNotification;
- (void) applicationDeactivate: (NSNotification *) notification
{
(void)notification;
#ifdef TK_MAC_DEBUG_NOTIFICATIONS
TKLog(@"-[%@(%p) %s] %@", [self class], self, _cmd, notification);
#endif
/*
* To prevent zombie windows on systems with a TouchBar, set the key window
* to nil if the current key window is not visible. This allows a closed
* Help or About window to be deallocated so it will not reappear as a
* zombie when the app is reactivated.
*/
NSWindow *keywindow = [NSApp keyWindow];
if (keywindow && ![keywindow isVisible]) {
[NSApp _setKeyWindow:nil];
[NSApp _setMainWindow:nil];
}
}
- (BOOL)applicationShouldHandleReopen:(NSApplication *)sender
hasVisibleWindows:(BOOL)flag
{
(void)sender;
(void)flag;
/*
* Allowing the default response means that withdrawn windows will get
* displayed on the screen with unresponsive title buttons. We don't
@@ -352,6 +382,8 @@ extern NSString *NSWindowDidOrderOffScreenNotification;
- (void) displayChanged: (NSNotification *) notification
{
(void)notification;
#ifdef TK_MAC_DEBUG_NOTIFICATIONS
TKLog(@"-[%@(%p) %s] %@", [self class], self, _cmd, notification);
#endif
@@ -368,26 +400,53 @@ extern NSString *NSWindowDidOrderOffScreenNotification;
/*
*----------------------------------------------------------------------
*
* TkpAppIsDrawing --
* TkpWillDrawWidget --
*
* A widget display procedure can call this to determine whether it is
* being run inside of the drawRect method. This is needed for some tests,
* especially of the Text widget, which record data in a global Tcl
* variable and assume that display procedures will be run in a
* predictable sequence as Tcl idle tasks.
* being run inside of the drawRect method. If not, it may be desirable
* for the display procedure to simply clear the REDRAW_PENDING flag
* and return. The widget can be recorded in order to schedule a
* redraw, via and Expose event, from within drawRect.
*
* This is also needed for some tests, especially of the Text widget,
* which record data in a global Tcl variable and assume that display
* procedures will be run in a predictable sequence as Tcl idle tasks.
*
* Results:
* True only while running the drawRect method of a TKContentView;
* True if called from the drawRect method of a TKContentView with
* tkwin NULL or pointing to a widget in the current focusView.
*
* Side effects:
* None
* Currently none. One day the tkwin parameter may be recorded to
* handle redrawing the widget later.
*
*----------------------------------------------------------------------
*/
MODULE_SCOPE Bool
TkpAppIsDrawing(void) {
return [NSApp isDrawing];
int
TkpWillDrawWidget(Tk_Window tkwin) {
int result;
if (tkwin) {
TkWindow *winPtr = (TkWindow *)tkwin;
TKContentView *view = (TKContentView *)TkMacOSXGetNSViewForDrawable(
(Drawable)winPtr->privatePtr);
result = ([NSApp isDrawing] && view == [NSView focusView]);
#if 0
printf("TkpWillDrawWidget: %s %d %d \n", Tk_PathName(tkwin),
[NSApp isDrawing], (view == [NSView focusView]));
if (!result) {
NSRect dirtyRect;
TkMacOSXWinNSBounds(winPtr, view, &dirtyRect);
printf("TkpAppCanDraw: dirtyRect for %s is %s\n",
Tk_PathName(tkwin),
NSStringFromRect(dirtyRect).UTF8String);
[view addTkDirtyRect:dirtyRect];
}
#endif
} else {
result = [NSApp isDrawing];
}
return result;
}
/*
@@ -395,55 +454,39 @@ TkpAppIsDrawing(void) {
*
* GenerateUpdates --
*
* Given a Macintosh update region and a Tk window this function geneates
* Given an update rectangle and a Tk window, this function generates
* an X Expose event for the window if it meets the update region. The
* function will then recursivly have each damaged window generate Expose
* function will then recursively have each damaged window generate Expose
* events for its child windows.
*
* Results:
* True if event(s) are generated - false otherwise.
*
* Side effects:
* Additional events may be place on the Tk event queue.
* Additional events may be placed on the Tk event queue.
*
*----------------------------------------------------------------------
*/
static int
GenerateUpdates(
HIShapeRef updateRgn,
CGRect *updateBounds,
TkWindow *winPtr)
{
TkWindow *childPtr;
XEvent event;
CGRect bounds, damageBounds;
HIShapeRef boundsRgn, damageRgn;
TkMacOSXWinCGBounds(winPtr, &bounds);
if (!CGRectIntersectsRect(bounds, *updateBounds)) {
return 0;
}
if (!HIShapeIntersectsRect(updateRgn, &bounds)) {
return 0;
}
/*
* Compute the bounding box of the area that the damage occured in.
* Compute the bounding box of the area that the damage occurred in.
*/
boundsRgn = HIShapeCreateWithRect(&bounds);
damageRgn = HIShapeCreateIntersection(updateRgn, boundsRgn);
if (HIShapeIsEmpty(damageRgn)) {
CFRelease(damageRgn);
CFRelease(boundsRgn);
return 0;
}
HIShapeGetBounds(damageRgn, &damageBounds);
CFRelease(damageRgn);
CFRelease(boundsRgn);
damageBounds = CGRectIntersection(bounds, *updateBounds);
event.xany.serial = LastKnownRequestProcessed(Tk_Display(winPtr));
event.xany.send_event = false;
event.xany.window = Tk_WindowId(winPtr);
@@ -457,7 +500,7 @@ GenerateUpdates(
Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL);
#ifdef TK_MAC_DEBUG_DRAWING
TKLog(@"Expose %p {{%d, %d}, {%d, %d}}", event.xany.window, event.xexpose.x,
TKLog(@"Exposed %p {{%d, %d}, {%d, %d}}", event.xany.window, event.xexpose.x,
event.xexpose.y, event.xexpose.width, event.xexpose.height);
#endif
@@ -470,7 +513,7 @@ GenerateUpdates(
if (!Tk_IsMapped(childPtr) || Tk_IsTopLevel(childPtr)) {
continue;
}
GenerateUpdates(updateRgn, updateBounds, childPtr);
GenerateUpdates(updateBounds, childPtr);
}
/*
@@ -480,7 +523,7 @@ GenerateUpdates(
if (Tk_IsContainer(winPtr)) {
childPtr = TkpGetOtherWindow(winPtr);
if (childPtr != NULL && Tk_IsMapped(childPtr)) {
GenerateUpdates(updateRgn, updateBounds, childPtr);
GenerateUpdates(updateBounds, childPtr);
}
/*
@@ -491,58 +534,6 @@ GenerateUpdates(
return 1;
}
/*
*----------------------------------------------------------------------
*
* GenerateActivateEvents --
*
* Given a Macintosh window activate event this function generates all the
* X Activate events needed by Tk.
*
* Results:
* True if event(s) are generated - false otherwise.
*
* Side effects:
* Additional events may be place on the Tk event queue.
*
*----------------------------------------------------------------------
*/
int
GenerateActivateEvents(
TkWindow *winPtr,
int activeFlag)
{
TkGenerateActivateEvents(winPtr, activeFlag);
if (activeFlag || ![NSApp isActive]) {
TkMacOSXGenerateFocusEvent(winPtr, activeFlag);
}
return true;
}
/*
*----------------------------------------------------------------------
*
* DoWindowActivate --
*
* Idle handler that calls GenerateActivateEvents().
*
* Results:
* None.
*
* Side effects:
* Additional events may be place on the Tk event queue.
*
*----------------------------------------------------------------------
*/
void
DoWindowActivate(
ClientData clientData)
{
GenerateActivateEvents(clientData, 1);
}
/*
*----------------------------------------------------------------------
*
@@ -555,12 +546,12 @@ DoWindowActivate(
* True if event(s) are generated - false otherwise.
*
* Side effects:
* Additional events may be place on the Tk event queue.
* Additional events may be placed on the Tk event queue.
*
*----------------------------------------------------------------------
*/
MODULE_SCOPE int
static int
TkMacOSXGenerateFocusEvent(
TkWindow *winPtr, /* Root X window for event. */
int activeFlag)
@@ -599,6 +590,35 @@ TkMacOSXGenerateFocusEvent(
return true;
}
/*
*----------------------------------------------------------------------
*
* GenerateActivateEvents --
*
* Given a Macintosh window activate event this function generates all the
* X Activate events needed by Tk.
*
* Results:
* True if event(s) are generated - false otherwise.
*
* Side effects:
* Additional events may be placed on the Tk event queue.
*
*----------------------------------------------------------------------
*/
int
GenerateActivateEvents(
TkWindow *winPtr,
int activeFlag)
{
TkGenerateActivateEvents(winPtr, activeFlag);
if (activeFlag || ![NSApp isActive]) {
TkMacOSXGenerateFocusEvent(winPtr, activeFlag);
}
return true;
}
/*
*----------------------------------------------------------------------
*
@@ -713,7 +733,7 @@ TkGenWMConfigureEvent(
/*
* Now set up the changes structure. Under X we wait for the
* ConfigureNotify to set these values. On the Mac we know imediatly that
* ConfigureNotify to set these values. On the Mac we know immediately that
* this is what we want - so we just set them. However, we need to make
* sure the windows clipping region is marked invalid so the change is
* visible to the subwindow.
@@ -804,7 +824,7 @@ TkWmProtocolEventProc(
if (result != TCL_OK) {
Tcl_AppendObjToErrorInfo(interp, Tcl_ObjPrintf(
"\n (command for \"%s\" window manager protocol)",
Tk_GetAtomName((Tk_Window) winPtr, protocol)));
Tk_GetAtomName((Tk_Window)winPtr, protocol)));
Tcl_BackgroundException(interp, result);
}
Tcl_Release(interp);
@@ -818,8 +838,8 @@ TkWmProtocolEventProc(
* message then just destroy the window.
*/
if (protocol == Tk_InternAtom((Tk_Window) winPtr, "WM_DELETE_WINDOW")) {
Tk_DestroyWindow((Tk_Window) winPtr);
if (protocol == Tk_InternAtom((Tk_Window)winPtr, "WM_DELETE_WINDOW")) {
Tk_DestroyWindow((Tk_Window)winPtr);
}
}
@@ -887,47 +907,38 @@ ExposeRestrictProc(
static Tk_RestrictAction
ConfigureRestrictProc(
ClientData arg,
TCL_UNUSED(void *),
XEvent *eventPtr)
{
return (eventPtr->type==ConfigureNotify ? TK_PROCESS_EVENT : TK_DEFER_EVENT);
}
/*
* If a window gets mapped inside the drawRect method, this will be run as an
* idle task, after drawRect returns, to clean up the mess.
*/
@implementation TKContentView(TKWindowEvent)
static void
RedisplayView(
ClientData clientdata)
- (void) addTkDirtyRect: (NSRect) rect
{
NSView *view = (NSView *) clientdata;
/*
* Make sure that we are not trying to displaying a view that no longer
* exists.
*/
for (NSWindow *w in [NSApp orderedWindows]) {
if ([w contentView] == view) {
[view setNeedsDisplay:YES];
break;
}
}
_tkNeedsDisplay = YES;
_tkDirtyRect = NSUnionRect(_tkDirtyRect, rect);
[NSApp setNeedsToDraw:YES];
}
@implementation TKContentView(TKWindowEvent)
- (void) clearTkDirtyRect
{
_tkNeedsDisplay = NO;
_tkDirtyRect = NSZeroRect;
[NSApp setNeedsToDraw:NO];
}
- (void) drawRect: (NSRect) rect
{
const NSRect *rectsBeingDrawn;
NSInteger rectsBeingDrawnCount;
(void)rect;
#ifdef TK_MAC_DEBUG_DRAWING
TkWindow *winPtr = TkMacOSXGetTkWindow([self window]);
if (winPtr) fprintf(stderr, "drawRect: drawing %s\n",
Tk_PathName(winPtr));
if (winPtr) {
fprintf(stderr, "drawRect: drawing %s in %s\n",
Tk_PathName(winPtr), NSStringFromRect(rect).UTF8String);
}
#endif
/*
@@ -936,37 +947,16 @@ RedisplayView(
*/
if ([NSApp isDrawing]) {
if ([NSApp macMinorVersion] > 13) {
if ([NSApp macOSVersion] > 101300) {
TKLog(@"WARNING: a recursive call to drawRect was aborted.");
}
return;
}
[NSApp setIsDrawing: YES];
[self getRectsBeingDrawn:&rectsBeingDrawn count:&rectsBeingDrawnCount];
CGFloat height = [self bounds].size.height;
HIMutableShapeRef drawShape = HIShapeCreateMutable();
while (rectsBeingDrawnCount--) {
CGRect r = NSRectToCGRect(*rectsBeingDrawn++);
#ifdef TK_MAC_DEBUG_DRAWING
fprintf(stderr, "drawRect: %dx%d@(%d,%d)\n", (int)r.size.width,
(int)r.size.height, (int)r.origin.x, (int)r.origin.y);
#endif
r.origin.y = height - (r.origin.y + r.size.height);
HIShapeUnionWithRect(drawShape, &r);
}
[self generateExposeEvents:(HIShapeRef)drawShape];
CFRelease(drawShape);
[NSApp setIsDrawing: NO];
if ([self needsRedisplay]) {
[self setNeedsRedisplay:NO];
Tcl_DoWhenIdle(RedisplayView, self);
}
[self clearTkDirtyRect];
[self generateExposeEvents:rect];
[NSApp setIsDrawing:NO];
#ifdef TK_MAC_DEBUG_DRAWING
fprintf(stderr, "drawRect: done.\n");
@@ -978,7 +968,7 @@ RedisplayView(
[super setFrameSize: newsize];
NSWindow *w = [self window];
TkWindow *winPtr = TkMacOSXGetTkWindow(w);
Tk_Window tkwin = (Tk_Window) winPtr;
Tk_Window tkwin = (Tk_Window)winPtr;
if (![self inLiveResize] &&
[w respondsToSelector: @selector (tkLayoutChanged)]) {
@@ -1023,13 +1013,14 @@ RedisplayView(
TkMacOSXUpdateClipRgn(winPtr);
/*
* Generate and process expose events to redraw the window.
* Generate and process expose events to redraw the window. To avoid
* crashes, only do this if we are being called from drawRect. See
* ticket [1fa8c3ed8d].
*/
HIRect bounds = NSRectToCGRect([self bounds]);
HIShapeRef shape = HIShapeCreateWithRect(&bounds);
[self generateExposeEvents: shape];
[w displayIfNeeded];
if([NSApp isDrawing] || [self inLiveResize]) {
[self generateExposeEvents: [self bounds]];
}
/*
* Finally, unlock the main autoreleasePool.
@@ -1046,11 +1037,11 @@ RedisplayView(
* pending idle events are processed so the drawing will actually take place.
*/
- (void) generateExposeEvents: (HIShapeRef) shape
- (void) generateExposeEvents: (NSRect) rect
{
unsigned long serial;
CGRect updateBounds;
int updatesNeeded;
CGRect updateBounds;
TkWindow *winPtr = TkMacOSXGetTkWindow([self window]);
ClientData oldArg;
Tk_RestrictProc *oldProc;
@@ -1059,26 +1050,25 @@ RedisplayView(
}
/*
* Generate Tk Expose events.
* Generate Tk Expose events. All of these events will share the same
* serial number.
*/
HIShapeGetBounds(shape, &updateBounds);
/*
* All of these events will share the same serial number.
*/
serial = LastKnownRequestProcessed(Tk_Display(winPtr));
updatesNeeded = GenerateUpdates(shape, &updateBounds, winPtr);
updateBounds = NSRectToCGRect(rect);
updateBounds.origin.y = ([self bounds].size.height - updateBounds.origin.y
- updateBounds.size.height);
updatesNeeded = GenerateUpdates(&updateBounds, winPtr);
if (updatesNeeded) {
serial = LastKnownRequestProcessed(Tk_Display(winPtr));
/*
* First process all of the Expose events.
* Use the ExposeRestrictProc to process only the expose events. This
* will create idle drawing tasks, which we handle before we return.
*/
oldProc = Tk_RestrictEvents(ExposeRestrictProc, UINT2PTR(serial), &oldArg);
while (Tcl_ServiceEvent(TCL_WINDOW_EVENTS)) {};
while (Tcl_ServiceEvent(TCL_WINDOW_EVENTS|TCL_DONT_WAIT)) {};
Tk_RestrictEvents(oldProc, oldArg, &oldArg);
/*
@@ -1090,51 +1080,104 @@ RedisplayView(
* effect.)
*
* Fortunately, Tk schedules all drawing to be done while Tcl is idle.
* So we can do the drawing by processing all of the idle events that
* were created when the expose events were processed.
* So to run any display procs which were scheduled by the expose
* events we process all idle events before returning.
*/
while (Tcl_DoOneEvent(TCL_IDLE_EVENTS)) {}
}
}
/*
* 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 this 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.
*/
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 101400
static const char *const 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;
if (!winPtr) {
Tk_Window tkwin = (Tk_Window)TkMacOSXGetTkWindow([self window]);
if (!tkwin) {
return;
}
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;
if (TkMacOSXInDarkMode(tkwin)) {
event.name = Tk_GetUid("DarkAqua");
} else {
event.name = Tk_GetUid("LightAqua");
NSAppearanceName effectiveAppearanceName = [[self effectiveAppearance] name];
NSUserDefaults *preferences = [NSUserDefaults standardUserDefaults];
static const char *defaultColor = NULL;
if (effectiveAppearanceName == NSAppearanceNameAqua) {
TkSendVirtualEvent(tkwin, "LightAqua", NULL);
} else if (effectiveAppearanceName == NSAppearanceNameDarkAqua) {
TkSendVirtualEvent(tkwin, "DarkAqua", NULL);
}
Tk_QueueWindowEvent((XEvent *) &event, TCL_QUEUE_TAIL);
if ([NSApp macOSVersion] < 101500) {
/*
* Mojave cannot handle the KVO shenanigans that we need for the
* highlight and accent color notifications.
*/
return;
}
if (!defaultColor) {
defaultColor = [NSApp macOSVersion] < 110000 ? "Blue" : "Multicolor";
preferences = [[NSUserDefaults standardUserDefaults] retain];
/*
* 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];
}
NSString *accent = [preferences stringForKey:@"AppleAccentColor"];
NSArray *words = [[preferences stringForKey:@"AppleHighlightColor"]
componentsSeparatedByString: @" "];
NSString *highlight = [words count] > 3 ? [words objectAtIndex:3] : nil;
const char *accentName = accent ? accentNames[1 + accent.intValue] : defaultColor;
const char *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));
}
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context
{
NSUserDefaults *preferences = [NSUserDefaults standardUserDefaults];
if (object == preferences && [keyPath isEqualToString:@"AppleHighlightColor"]) {
if (@available(macOS 10.14, *)) {
[self viewDidChangeEffectiveAppearance];
}
}
}
#endif
/*
* This is no-op on 10.7 and up because Apple has removed this widget, but we
* are leaving it here for backwards compatibility.
@@ -1148,7 +1191,9 @@ RedisplayView(
XVirtualEvent event;
int x, y;
TkWindow *winPtr = TkMacOSXGetTkWindow([self window]);
Tk_Window tkwin = (Tk_Window) winPtr;
Tk_Window tkwin = (Tk_Window)winPtr;
(void)sender;
if (!winPtr){
return;
}
@@ -1169,12 +1214,10 @@ RedisplayView(
Tk_QueueWindowEvent((XEvent *) &event, TCL_QUEUE_TAIL);
}
- (BOOL) isOpaque
{
NSWindow *w = [self window];
return (w && (([w styleMask] & NSTexturedBackgroundWindowMask) ||
![w isOpaque]) ? NO : YES);
}
/*
* On Catalina this is never called and drawRect clips to the rect that
* is passed to it by AppKit.
*/
- (BOOL) wantsDefaultClipping
{
@@ -1193,6 +1236,8 @@ RedisplayView(
- (void) keyDown: (NSEvent *) theEvent
{
(void)theEvent;
#ifdef TK_MAC_DEBUG_EVENTS
TKLog(@"-[%@(%p) %s] %@", [self class], self, _cmd, theEvent);
#endif
@@ -1200,7 +1245,7 @@ RedisplayView(
/*
* When the services menu is opened this is called for each Responder in
* the Responder chain until a service provider is found. The TkContentView
* the Responder chain until a service provider is found. The TKContentView
* should be the first (and generally only) Responder in the chain. We
* return the TkServices object that was created in TkpInit.
*/