Skip to content

[AppKit] Improve and simplify the manually bound constructors for NSGradient slightly. #22647

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Apr 23, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 50 additions & 50 deletions src/AppKit/NSGradient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@

namespace AppKit {
public partial class NSGradient : NSObject {
static IntPtr selInitWithColorsAtLocationsColorSpace = Selector.GetHandle ("initWithColors:atLocations:colorSpace:");

// The signature of this ObjC method is
// - (id)initWithColorsAndLocations:(NSColor *)firstColor, ... NS_REQUIRES_NIL_TERMINATION;
// where colors and locations (as CGFloats between 0.0 and 1.0) alternate until nil
Expand All @@ -33,82 +31,84 @@ public partial class NSGradient : NSObject {
// Per NSGradient.h, this initializer calls the designated initializer (below) with a
// color space of NSColorSpace.GenericRGBColorSpace, so we will do the same.

/// <param name="colors">To be added.</param>
/// <param name="locations">To be added.</param>
/// <summary>To be added.</summary>
/// <remarks>To be added.</remarks>
/// <summary>Create a new <see cref="NSGradient" /> instance with the specified colors and color locations.</summary>
/// <param name="colors">The colors for the new gradient.</param>
/// <param name="locations">The locations for each color in the new gradient. Each location must be a value between 0.0 and 1.0.</param>
/// <remarks>This gradient is created in the <a cref="NSColorSpace.GenericRGBColorSpace" /> generic RGB color space.</remarks>
public NSGradient (NSColor [] colors, float [] locations) :
this (colors, locations, NSColorSpace.GenericRGBColorSpace)
{
}

/// <param name="colors">To be added.</param>
/// <param name="locations">To be added.</param>
/// <summary>To be added.</summary>
/// <remarks>To be added.</remarks>
/// <summary>Create a new <see cref="NSGradient" /> instance with the specified colors and color locations.</summary>
/// <param name="colors">The colors for the new gradient.</param>
/// <param name="locations">The locations for each color in the new gradient. Each location must be a value between 0.0 and 1.0.</param>
/// <remarks>This gradient is created in the <a cref="NSColorSpace.GenericRGBColorSpace" /> generic RGB color space.</remarks>
public NSGradient (NSColor [] colors, double [] locations) :
this (colors, locations, NSColorSpace.GenericRGBColorSpace)
{
}

/// <param name="colors">To be added.</param>
/// <param name="locations">To be added.</param>
/// <param name="colorSpace">To be added.</param>
/// <summary>To be added.</summary>
/// <remarks>To be added.</remarks>
/// <summary>Create a new <see cref="NSGradient" /> instance with the specified colors and color locations.</summary>
/// <param name="colors">The colors for the new gradient.</param>
/// <param name="locations">The locations for each color in the new gradient. Each location must be a value between 0.0 and 1.0.</param>
/// <remarks>This gradient is created in the <a cref="NSColorSpace.GenericRGBColorSpace" /> generic RGB color space.</remarks>
public NSGradient (NSColor [] colors, nfloat [] locations)
: this (colors, locations, NSColorSpace.GenericRGBColorSpace)
{
}

/// <summary>Create a new <see cref="NSGradient" /> instance with the specified colors and color locations.</summary>
/// <param name="colors">The colors for the new gradient.</param>
/// <param name="locations">The locations for each color in the new gradient. Each location must be a value between 0.0 and 1.0.</param>
/// <param name="colorSpace">The color space for the new gradient.</param>
public NSGradient (NSColor [] colors, float [] locations, NSColorSpace colorSpace)
: this (colors, Array.ConvertAll<float, nfloat> (locations, new Converter<float, nfloat> (a => (nfloat) a)), colorSpace)
{
}

/// <summary>Create a new <see cref="NSGradient" /> instance with the specified colors and color locations.</summary>
/// <param name="colors">The colors for the new gradient.</param>
/// <param name="locations">The locations for each color in the new gradient. Each location must be a value between 0.0 and 1.0.</param>
/// <param name="colorSpace">The color space for the new gradient.</param>
public NSGradient (NSColor [] colors, double [] locations, NSColorSpace colorSpace) : base (NSObjectFlag.Empty)
{
unsafe {
double [] converted = Array.ConvertAll<float, double> (locations, new Converter<float, double> (a => (double) a));
fixed (void* locationPtr = converted) {
Initialize (colors, locationPtr, colorSpace);
if (IntPtr.Size != 8)
throw new PlatformNotSupportedException ("Use the overload that takes an array of 'nfloat' values as locations instead.");

fixed (void* locationPtr = locations) {
Initialize (colors, locations?.Length, (IntPtr) locationPtr, colorSpace);
}
}
}

/// <param name="colors">To be added.</param>
/// <param name="locations">To be added.</param>
/// <param name="colorSpace">To be added.</param>
/// <summary>To be added.</summary>
/// <remarks>To be added.</remarks>
public NSGradient (NSColor [] colors, double [] locations, NSColorSpace colorSpace) : base (NSObjectFlag.Empty)
/// <summary>Create a new <see cref="NSGradient" /> instance with the specified colors and color locations.</summary>
/// <param name="colors">The colors for the new gradient.</param>
/// <param name="locations">The locations for each color in the new gradient. Each location must be a value between 0.0 and 1.0.</param>
/// <param name="colorSpace">The color space for the new gradient.</param>
public NSGradient (NSColor [] colors, nfloat [] locations, NSColorSpace colorSpace)
: base (NSObjectFlag.Empty)
{
unsafe {
fixed (void* locationPtr = locations) {
Initialize (colors, locationPtr, colorSpace);
Initialize (colors, locations?.Length, (IntPtr) locationPtr, colorSpace);
}
}
}

unsafe void Initialize (NSColor [] colors, void* locationPtr, NSColorSpace colorSpace)
void Initialize (NSColor [] colors, int? locationCount, IntPtr locations, NSColorSpace colorSpace)
{
if (colors is null)
throw new ArgumentNullException ("colors");
if (locationPtr is null)
throw new ArgumentNullException ("locationPtr");
if (colorSpace is null)
throw new ArgumentNullException ("colorSpace");
ThrowHelper.ThrowArgumentNullException (nameof (colors));

var nsa_colorArray = NSArray.FromNSObjects (colors);
var nsa_colorArrayHandle = nsa_colorArray.Handle;
var colorSpaceHandle = colorSpace.Handle;
if (locationCount is null)
ThrowHelper.ThrowArgumentNullException (nameof (locations));

IntPtr locations = new IntPtr (locationPtr);
#if NET
if (IsDirectBinding) {
Handle = ObjCRuntime.Messaging.NativeHandle_objc_msgSend_NativeHandle_NativeHandle_NativeHandle (this.Handle, selInitWithColorsAtLocationsColorSpace, nsa_colorArrayHandle, locations, colorSpaceHandle);
} else {
Handle = ObjCRuntime.Messaging.NativeHandle_objc_msgSendSuper_NativeHandle_NativeHandle_NativeHandle (this.SuperHandle, selInitWithColorsAtLocationsColorSpace, nsa_colorArrayHandle, locations, colorSpaceHandle);
}
#else
if (IsDirectBinding) {
Handle = ObjCRuntime.Messaging.IntPtr_objc_msgSend_IntPtr_IntPtr_IntPtr (this.Handle, selInitWithColorsAtLocationsColorSpace, nsa_colorArrayHandle, locations, colorSpaceHandle);
} else {
Handle = ObjCRuntime.Messaging.IntPtr_objc_msgSendSuper_IntPtr_IntPtr_IntPtr (this.SuperHandle, selInitWithColorsAtLocationsColorSpace, nsa_colorArrayHandle, locations, colorSpaceHandle);
}
#endif
nsa_colorArray.Dispose ();
GC.KeepAlive (colorSpace);
if (colors.Length != locationCount)
ThrowHelper.ThrowArgumentOutOfRangeException (nameof (locations), string.Format ("The number of colors ({0}) and the number of locations ({1}) must be equal.", colors.Length, locationCount));

InitializeHandle (_InitWithColorsAtLocationsAndColorSpace (colors, locations, colorSpace), "initWithColors:atLocations:colorSpace:");
}
}
}
Expand Down
5 changes: 4 additions & 1 deletion src/appkit.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8162,7 +8162,10 @@ interface NSGradient : NSSecureCoding, NSCopying {

// See AppKit/NSGradiant.cs
//[Export ("initWithColorsAndLocations:")]
//[Export ("initWithColors:atLocations:colorSpace:")]

[Internal]
[Export ("initWithColors:atLocations:colorSpace:")]
NativeHandle _InitWithColorsAtLocationsAndColorSpace (NSColor [] colorArray, /* CGFloat */ IntPtr locations, NSColorSpace colorSpace);

[Export ("drawFromPoint:toPoint:options:")]
void DrawFromPoint (CGPoint startingPoint, CGPoint endingPoint, NSGradientDrawingOptions options);
Expand Down
1 change: 0 additions & 1 deletion tests/cecil-tests/ConstructorTest.KnownFailures.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ public partial class ConstructorTest {
static HashSet<string> knownFailuresNonDefaultCtorDoesNotCallBaseDefaultCtor = new HashSet<string> {
"AppKit.ActionDispatcher::.ctor(System.EventHandler)",
"AppKit.NSAlertDidEndDispatcher::.ctor(System.Action`1<System.IntPtr>)",
"AppKit.NSGradient::.ctor(AppKit.NSColor[],System.Single[],AppKit.NSColorSpace)",
"AppKit.NSTextContainer::.ctor(CoreGraphics.CGSize,System.Boolean)",
"AVFoundation.InternalAVAudioSessionDelegate::.ctor(AVFoundation.AVAudioSession)",
"CarPlay.CPListSection::.ctor(CarPlay.CPListItem[],System.String,System.String)",
Expand Down
1 change: 0 additions & 1 deletion tests/cecil-tests/SetHandleTest.KnownFailures.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ public partial class SetHandleTest {
static HashSet<string> knownFailuresNobodyCallsHandleSetter = new HashSet<string> {
"AddressBook.ABGroup::.ctor(AddressBook.ABRecord)",
"AppKit.NSBitmapImageRep::.ctor(Foundation.NSObjectFlag,Foundation.NSObjectFlag)",
"AppKit.NSGradient::Initialize(AppKit.NSColor[],System.Void*,AppKit.NSColorSpace)",
"AppKit.NSOpenGLPixelFormat::.ctor(AppKit.NSOpenGLPixelFormatAttribute[])",
"AppKit.NSOpenGLPixelFormat::.ctor(System.Object[])",
"AppKit.NSTextContainer::.ctor(CoreGraphics.CGSize,System.Boolean)",
Expand Down
8 changes: 6 additions & 2 deletions tests/xtro-sharpie/api-annotations-dotnet/macOS-AppKit.ignore
Original file line number Diff line number Diff line change
Expand Up @@ -1498,8 +1498,6 @@
!missing-selector! NSFont::matrix not bound
!missing-selector! NSFontPanel::setWorksWhenModal: not bound
!missing-selector! NSFontPanel::worksWhenModal not bound
!missing-selector! NSGradient::initWithColors:atLocations:colorSpace: not bound
!missing-selector! NSGradient::initWithColorsAndLocations: not bound
!missing-selector! NSImage::initByReferencingURL: not bound
!missing-selector! NSMatrix::sortUsingFunction:context: not bound
!missing-selector! NSMediaLibraryBrowserController::frame not bound
Expand Down Expand Up @@ -1623,3 +1621,9 @@
!incorrect-protocol-member! NSAccessibility::setAccessibilityUserInputLabels: is REQUIRED and should be abstract

# introduced and deprecated in the same version

# This selector uses varargs, which is non-trivial to bind manually,
# so we rely on the very similar 'NSGradient::initWithColorsAndLocations:colorSpace',
# which works fine.
!missing-selector! NSGradient::initWithColorsAndLocations: not bound