diff --git a/ChangeLog b/ChangeLog index b10d3ea2d..dcd1a5f77 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,14 @@ 2026-07-12 Todd White + * Headers/AppKit/NSTrackingArea.h: Give the NSTrackingAreaOptions + constants their AppKit values; the active and later options were off + by the unused 0x08 bit. + * Source/NSTrackingArea.m (-[NSTrackingArea initWithRect:options:owner: + userInfo:]): Retain the userInfo argument rather than the nil ivar, so + -userInfo returns the dictionary that was passed in. + * Tests/gui/NSTrackingArea/basic.m: + * Tests/gui/NSTrackingArea/TestInfo: + New test for the option values, the accessors and copy. * Tests/gui/NSTextView/typingAttributes.m: * Tests/gui/NSTextView/TestInfo: Add tests for the NSTextView typing attributes and related state: the diff --git a/Headers/AppKit/NSTrackingArea.h b/Headers/AppKit/NSTrackingArea.h index 40bc8051f..616b36c83 100644 --- a/Headers/AppKit/NSTrackingArea.h +++ b/Headers/AppKit/NSTrackingArea.h @@ -38,16 +38,16 @@ * Options pulled from Cocoa documentation. */ enum { - NSTrackingMouseEnteredAndExited = 1, - NSTrackingMouseMoved = 2, - NSTrackingCursorUpdate = 4, - NSTrackingActiveWhenFirstResponder = 8, - NSTrackingActiveInKeyWindow = 16, - NSTrackingActiveInActiveApp = 32, - NSTrackingActiveAlways = 64, - NSTrackingAssumeInside = 128, - NSTrackingInVisibleRect = 256, - NSTrackingEnabledDuringMouseDrag = 512 + NSTrackingMouseEnteredAndExited = 0x01, + NSTrackingMouseMoved = 0x02, + NSTrackingCursorUpdate = 0x04, + NSTrackingActiveWhenFirstResponder = 0x10, + NSTrackingActiveInKeyWindow = 0x20, + NSTrackingActiveInActiveApp = 0x40, + NSTrackingActiveAlways = 0x80, + NSTrackingAssumeInside = 0x100, + NSTrackingInVisibleRect = 0x200, + NSTrackingEnabledDuringMouseDrag = 0x400 }; typedef NSUInteger NSTrackingAreaOptions; diff --git a/Source/NSTrackingArea.m b/Source/NSTrackingArea.m index 2a1284840..14a53ac3d 100644 --- a/Source/NSTrackingArea.m +++ b/Source/NSTrackingArea.m @@ -42,7 +42,7 @@ - (id)initWithRect: (NSRect)rect { BOOL flag = (BOOL)(options & NSTrackingAssumeInside); - _userInfo = RETAIN(_userInfo); + _userInfo = RETAIN(userInfo); _options = options; _trackingRect = [[GSTrackingRect alloc] initWithRect:rect tag:0 diff --git a/Tests/gui/NSTrackingArea/TestInfo b/Tests/gui/NSTrackingArea/TestInfo new file mode 100644 index 000000000..e69de29bb diff --git a/Tests/gui/NSTrackingArea/basic.m b/Tests/gui/NSTrackingArea/basic.m new file mode 100644 index 000000000..e2ca42577 --- /dev/null +++ b/Tests/gui/NSTrackingArea/basic.m @@ -0,0 +1,81 @@ +/* Coverage for NSTrackingArea: the option constant values, the rect, options, + * owner and userInfo accessors, and copying. These are plain object + * operations and need no backend. + */ +#include "Testing.h" +#include +#include +#include +#include +#include + +#define EQ(a, b) (fabs((double)(a) - (double)(b)) < 0.001) + +int +main(int argc, char **argv) +{ + CREATE_AUTORELEASE_POOL(arp); + + START_SET("option constants match AppKit") + PASS(NSTrackingMouseEnteredAndExited == 0x01 + && NSTrackingMouseMoved == 0x02 + && NSTrackingCursorUpdate == 0x04, + "the mouse option values are correct"); + PASS(NSTrackingActiveWhenFirstResponder == 0x10 + && NSTrackingActiveInKeyWindow == 0x20 + && NSTrackingActiveInActiveApp == 0x40 + && NSTrackingActiveAlways == 0x80, + "the active option values are correct"); + PASS(NSTrackingAssumeInside == 0x100 + && NSTrackingInVisibleRect == 0x200 + && NSTrackingEnabledDuringMouseDrag == 0x400, + "the remaining option values are correct"); + END_SET("option constants match AppKit") + + START_SET("accessors") + NSDictionary *info = [NSDictionary dictionaryWithObject: @"v" + forKey: @"k"]; + id owner = AUTORELEASE([[NSObject alloc] init]); + NSRect rect = NSMakeRect(10, 20, 30, 40); + NSTrackingAreaOptions opts = + NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways; + NSTrackingArea *a = AUTORELEASE([[NSTrackingArea alloc] + initWithRect: rect options: opts owner: owner userInfo: info]); + + PASS(NSEqualRects([a rect], rect), "the rect reads back"); + PASS(opts == [a options], "the options read back"); + PASS(owner == [a owner], "the owner reads back"); + PASS([[a userInfo] objectForKey: @"k"] != nil, "the userInfo reads back"); + END_SET("accessors") + + START_SET("a nil userInfo is allowed") + id owner = AUTORELEASE([[NSObject alloc] init]); + NSTrackingArea *a = AUTORELEASE([[NSTrackingArea alloc] + initWithRect: NSMakeRect(0, 0, 1, 1) + options: NSTrackingMouseMoved | NSTrackingActiveAlways + owner: owner userInfo: nil]); + + PASS(nil == [a userInfo], "a tracking area with no userInfo returns nil"); + END_SET("a nil userInfo is allowed") + + START_SET("copy preserves the rect, options, owner and userInfo") + NSDictionary *info = [NSDictionary dictionaryWithObject: @"v" + forKey: @"k"]; + id owner = AUTORELEASE([[NSObject alloc] init]); + NSRect rect = NSMakeRect(5, 6, 7, 8); + NSTrackingAreaOptions opts = + NSTrackingCursorUpdate | NSTrackingActiveInKeyWindow; + NSTrackingArea *a = AUTORELEASE([[NSTrackingArea alloc] + initWithRect: rect options: opts owner: owner userInfo: info]); + NSTrackingArea *c = AUTORELEASE([a copy]); + + PASS(c != a, "the copy is a distinct object"); + PASS(NSEqualRects([c rect], rect) && opts == [c options] + && owner == [c owner] + && [[c userInfo] objectForKey: @"k"] != nil, + "the copy keeps the rect, options, owner and userInfo"); + END_SET("copy preserves the rect, options, owner and userInfo") + + DESTROY(arp); + return 0; +}