diff --git a/lib/std/os/macos/core_foundation.c3 b/lib/std/os/macos/core_foundation.c3 index cd99d07f1..5474125f9 100644 --- a/lib/std/os/macos/core_foundation.c3 +++ b/lib/std/os/macos/core_foundation.c3 @@ -13,6 +13,26 @@ struct CFRange CFIndex length; } +alias CGFloat = $typefrom(env::ARCH_64_BIT ??? double : float); + +struct CGPoint +{ + CGFloat x; + CGFloat y; +} + +struct CGSize +{ + CGFloat width; + CGFloat height; +} + +struct CGRect +{ + CGPoint origin; + CGSize size; +} + extern fn ZString CFString.getCStringPtr(&self, CFStringEncoding encoding) @cname("CFStringGetCStringPtr"); extern fn ZString CFString.getCString(&self, char* buffer, usz len, CFStringEncoding encoding) @cname("CFStringGetCString"); diff --git a/lib/std/os/macos/objc.c3 b/lib/std/os/macos/objc.c3 index 1f67b6e5b..75c93a87d 100644 --- a/lib/std/os/macos/objc.c3 +++ b/lib/std/os/macos/objc.c3 @@ -18,7 +18,7 @@ macro bool ObjcSelector.equals(ObjcSelector a, ObjcSelector b) => a == b; macro bool ObjcClass.equals(ObjcClass a, ObjcClass b) => a == b; fn ObjcId alloc(ObjcClass cls) => objc::msg_send(cls, SendVoid, "alloc"); -fn void release(ObjcId id) => objc::msg_send(id, SendVoid, "release"); +fn void release(ObjcId id) => objc::msg_send(id, SendVoid, "release"); alias NSUInteger = $typefrom(env::ARCH_64_BIT ??? ulong : uint); alias NSInteger = $typefrom(env::ARCH_64_BIT ??? long : int); @@ -71,20 +71,30 @@ extern fn ObjcIvar getInstanceVariable(ObjcId id, ZString name, void* outValue) extern fn ObjcIvar setInstanceVariable(ObjcId id, ZString name, void* value) @cname("object_setInstanceVariable"); extern fn ObjcClass allocateClassPair(ObjcClass cls, ZString name, uint extraBytes) @cname("objc_allocateClassPair"); -enum StatusItemLength : (double val) +module std::os::macos::objc::ns @if(env::DARWIN) @link(env::DARWIN, "CoreFoundation.framework"); +import std::os::macos::cf; + +enum StatusItemLength : (double val) @deprecated("Use NSStatusItemLength.") { VARIABLE = -1.0, SQUARE = -2.0, } -enum ApplicationActivationPolicy : (int val) +enum ApplicationActivationPolicy : (int val) @deprecated("Use NSApplicationActivationPolicy.") { REGULAR = 0, ACCESSORY = 1, PROHIBITED = 2, } -enum WindowStyleMask : (int val) +enum NSApplicationActivationPolicy : const inline NSInteger +{ + REGULAR = 0, + ACCESSORY = 1, + PROHIBITED = 2, +} + +enum WindowStyleMask : (int val) @deprecated("Use NSWindowStyleMask.") { BORDERLESS = 0, TITLED = 1 << 0, @@ -101,14 +111,21 @@ enum WindowStyleMask : (int val) HUD_WINDOW = 1 << 13 } -enum BackingStore : (int val) +enum BackingStore : (int val) @deprecated("Use NSBackingStoreType.") { RETAINED = 0, NONRETAINED = 1, BUFFERED = 2 } -enum EventType : (long val) +enum NSBackingStoreType : const inline NSUInteger +{ + RETAINED = 0, + NONRETAINED = 1, + BUFFERED = 2 +} + +enum EventType : (long val) @deprecated("Use NSEventType.") { LEFT_MOUSE_DOWN = 1, LEFT_MOUSE_UP = 2, @@ -146,7 +163,45 @@ enum EventType : (long val) CHANGE_MODE = 38, } -fn EventType? event_type_from(int val) +enum NSEventType : const inline NSUInteger +{ + LEFT_MOUSE_DOWN = 1, + LEFT_MOUSE_UP = 2, + RIGHT_MOUSE_DOWN = 3, + RIGHT_MOUSE_UP = 4, + MOUSE_MOVED = 5, + LEFT_MOUSE_DRAGGED = 6, + RIGHT_MOUSE_DRAGGED = 7, + MOUSE_ENTERED = 8, + MOUSE_EXITED = 9, + KEY_DOWN = 10, + KEY_UP = 11, + FLAGS_CHANGED = 12, + APPKIT_DEFINED = 13, + SYSTEM_DEFINED = 14, + APPLICATION_DEFINED = 15, + PERIODIC = 16, + CURSOR_UPDATE = 17, + SCROLL_WHEEL = 22, + TABLET_POINT = 23, + TABLET_PROXIMITY = 24, + OTHER_MOUSE_DOWN = 25, + OTHER_MOUSE_UP = 26, + OTHER_MOUSE_DRAGGED = 27, + GESTURE = 29, + MAGNIFY = 30, + SWIPE = 31, + ROTATE = 18, + BEGIN_GESTURE = 19, + END_GESTURE = 20, + SMART_MAGNIFY = 32, + QUICK_LOOK = 33, + PRESSURE = 34, + DIRECT_TOUCH = 37, + CHANGE_MODE = 38, +} + +fn EventType? event_type_from(int val) @deprecated("Use NSEventType directly.") { switch(val) { @@ -184,11 +239,11 @@ fn EventType? event_type_from(int val) case EventType.PRESSURE.val: return PRESSURE; case EventType.DIRECT_TOUCH.val: return DIRECT_TOUCH; case EventType.CHANGE_MODE.val: return CHANGE_MODE; - default: return UNKNOWN_EVENT?; + default: return objc::UNKNOWN_EVENT?; } } -enum EventMask : (long val) +enum EventMask : (long val) @deprecated("Use NSEventMask.") { LEFT_MOUSE_DOWN = 1 << EventType.LEFT_MOUSE_DOWN.val, LEFT_MOUSE_UP = 1 << EventType.LEFT_MOUSE_UP.val, @@ -224,7 +279,48 @@ enum EventMask : (long val) ANY = long.max, } -enum EventModifierFlag : (int val) +enum NSEventMask : const inline ulong +{ + LEFT_MOUSE_DOWN = 1ul << NSEventType.LEFT_MOUSE_DOWN, + LEFT_MOUSE_UP = 1ul << NSEventType.LEFT_MOUSE_UP, + RIGHT_MOUSE_DOWN = 1ul << NSEventType.RIGHT_MOUSE_DOWN, + RIGHT_MOUSE_UP = 1ul << NSEventType.RIGHT_MOUSE_UP, + MOUSE_MOVED = 1ul << NSEventType.MOUSE_MOVED, + LEFT_MOUSE_DRAGGED = 1ul << NSEventType.LEFT_MOUSE_DRAGGED, + RIGHT_MOUSE_DRAGGED = 1ul << NSEventType.RIGHT_MOUSE_DRAGGED, + MOUSE_ENTERED = 1ul << NSEventType.MOUSE_ENTERED, + MOUSE_EXITED = 1ul << NSEventType.MOUSE_EXITED, + KEY_DOWN = 1ul << NSEventType.KEY_DOWN, + KEY_UP = 1ul << NSEventType.KEY_UP, + FLAGS_CHANGED = 1ul << NSEventType.FLAGS_CHANGED, + APPKIT_DEFINED = 1ul << NSEventType.APPKIT_DEFINED, + SYSTEM_DEFINED = 1ul << NSEventType.SYSTEM_DEFINED, + APPLICATION_DEFINED = 1ul << NSEventType.APPLICATION_DEFINED, + PERIODIC = 1ul << NSEventType.PERIODIC, + CURSOR_UPDATE = 1ul << NSEventType.CURSOR_UPDATE, + ROTATE = 1ul << NSEventType.ROTATE, + BEGIN_GESTURE = 1ul << NSEventType.BEGIN_GESTURE, + END_GESTURE = 1ul << NSEventType.END_GESTURE, + SCROLL_WHEEL = 1ul << NSEventType.SCROLL_WHEEL, + TABLET_POINT = 1ul << NSEventType.TABLET_POINT, + TABLET_PROXIMITY = 1ul << NSEventType.TABLET_PROXIMITY, + OTHER_MOUSE_DOWN = 1ul << NSEventType.OTHER_MOUSE_DOWN, + OTHER_MOUSE_UP = 1ul << NSEventType.OTHER_MOUSE_UP, + OTHER_MOUSE_DRAGGED = 1ul << NSEventType.OTHER_MOUSE_DRAGGED, + GESTURE = 1ul << NSEventType.GESTURE, + MAGNIFY = 1ul << NSEventType.MAGNIFY, + SWIPE = 1ul << NSEventType.SWIPE, + SMART_MAGNIFY = 1ul << NSEventType.SMART_MAGNIFY, + QUICK_LOOK = 1ul << NSEventType.QUICK_LOOK, + PRESSURE = 1ul << NSEventType.PRESSURE, + DIRECT_TOUCH = 1ul << NSEventType.DIRECT_TOUCH, + CHANGE_MODE = 1ul << NSEventType.CHANGE_MODE, + ANY = ulong.max, +} + +fn NSEventMask event_mask_from_type(NSEventType type) => (NSEventMask)1ul << type; + +enum EventModifierFlag : (int val) @deprecated("Use NSEventModifierFlags.") { CAPS_LOCK = 1 << 16, SHIFT = 1 << 17, @@ -236,3 +332,78 @@ enum EventModifierFlag : (int val) HELP = 1 << 22, } +enum NSEventModifierFlags : const inline NSUInteger +{ + CAPS_LOCK = 1 << 16, + SHIFT = 1 << 17, + CONTROL = 1 << 18, + OPTION = 1 << 19, + COMMAND = 1 << 20, + NUMERIC_PAD = 1 << 21, + FUNCTION = 1 << 23, + HELP = 1 << 22, +} + +enum NSWindowCollectionBehavior : const inline NSUInteger +{ + DEFAULT = 0, + CAN_JOIN_ALL_SPACES = 1 << 0, + MOVE_TO_ACTIVE_SPACE = 1 << 1, + MANAGED = 1 << 2, + TRANSIENT = 1 << 3, + STATIONARY = 1 << 4, + PARTICIPATES_IN_CYCLE = 1 << 5, + IGNORES_CYCLE = 1 << 6, + FULL_SCREEN_PRIMARY = 1 << 7, + FULL_SCREEN_AUXILIARY = 1 << 8, + FULL_SCREEN_NONE = 1 << 9, + FULL_SCREEN_ALLOWS_TILING = 1 << 11, + FULL_SCREEN_DISALLOWS_TILING = 1 << 12, + PRIMARY = 1 << 16, + AUXILIARY = 1 << 17, + CAN_JOIN_ALL_APPLICATIONS = 1 << 18, +} + +enum NSWindowLevel : const inline NSInteger +{ + NORMAL = 0, + FLOATING = 3, + SUBMENU = 3, + TORN_OFF_MENU = 3, + MODAL_PANEL = 8, + MAIN_MENU = 24, + STATUS = 25, + POP_UP_MENU = 101, + SCREEN_SAVER = 1000, +} + +enum NSWindowStyleMask : const inline NSUInteger +{ + BORDERLESS = 0, + TITLED = 1 << 0, + CLOSABLE = 1 << 1, + MINIATURIZABLE = 1 << 2, + RESIZABLE = 1 << 3, + TEXTURED_BACKGROUND = 1 << 8, + UNIFIED_TITLE_AND_TOOLBAR = 1 << 12, + FULL_SCREEN = 1 << 14, + FULL_SIZE_CONTENT_VIEW = 1 << 15, + UTILITY_WINDOW = 1 << 4, + DOC_MODAL_WINDOW = 1 << 6, + NONACTIVATING_PANEL = 1 << 7, + HUD_WINDOW = 1 << 13 +} + +enum NSWindowTabbingMode : const inline NSInteger +{ + AUTOMATIC = 0, + DISALLOWED = 2, + PREFERRED = 1, +} + +enum NSStatusItemLength : const inline CGFloat +{ + VARIABLE = -1.0, + SQUARE = -2.0 +} + diff --git a/releasenotes.md b/releasenotes.md index 8099ab436..1fc7497b6 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -39,6 +39,13 @@ - Add sigsegv stacktrace in test and regular errors for Darwin Arm64. #1105 ### Stdlib changes +- Add `CGFloat` `CGPoint` `CGSize` `CGRect` types to core_foundation (macOS). +- Add `NSStatusItem` const enum to ns module (macOS). +- Add `NSWindowCollectionBehavior` `NSWindowLevel` `NSWindowTabbingMode` to objc (macOS). +- Add `ns::eventmask_from_type` function to objc (macOS). +- Deprecate objc enums in favour of const inline enums backed by NS numerical types, and with the NS prefix, to better align with the objc api (macOS). +- Deprecate `event_type_from` function in favour of using NSEvent directly, to better align with the objc api (macOS). +- Add unit tests for objc and core_foundation (macOS). ## 0.7.7 Change list diff --git a/src/compiler_tests/benchmark.c b/src/compiler_tests/benchmark.c index 85e02dd81..f0d1e9d5f 100644 --- a/src/compiler_tests/benchmark.c +++ b/src/compiler_tests/benchmark.c @@ -10,6 +10,7 @@ BenchTime begin; #if USE_PTHREAD + void bench_begin(void) { clock_gettime(CLOCK_MONOTONIC, &begin); diff --git a/test/unit/stdlib/os/macos/core_foundation.c3 b/test/unit/stdlib/os/macos/core_foundation.c3 new file mode 100644 index 000000000..994359e91 --- /dev/null +++ b/test/unit/stdlib/os/macos/core_foundation.c3 @@ -0,0 +1,76 @@ +module std::os::macos::cf @test @if(env::DARWIN); + +fn void test_cgfloat_type() +{ + if (env::ARCH_64_BIT) + { + assert(CGFloat.sizeof == double.sizeof); + } + else + { + assert(CGFloat.sizeof == float.sizeof); + } +} + +fn void test_cgpoint() +{ + CGPoint point = { .x = 10.0, .y = 20.0 }; + + assert(point.x == 10.0); + assert(point.y == 20.0); + + CGPoint point2 = { .x = point.x + 5.0, .y = point.y - 10.0 }; + assert(point2.x == 15.0); + assert(point2.y == 10.0); +} + +fn void test_cgsize() +{ + CGSize size = { .width = 100.0, .height = 200.0 }; + + assert(size.width == 100.0); + assert(size.height == 200.0); + + assert(@typeid(size.width) == CGFloat.typeid); + assert(@typeid(size.height) == CGFloat.typeid); + + CGSize negSize = { .width = -50.0, .height = -75.0 }; + assert(negSize.width == -50.0); + assert(negSize.height == -75.0); +} + +fn void test_cgrect() +{ + CGPoint origin = { .x = 10.0, .y = 20.0 }; + CGSize size = { .width = 100.0, .height = 200.0 }; + CGRect rect = { .origin = origin, .size = size }; + + assert(rect.origin.x == 10.0); + assert(rect.origin.y == 20.0); + assert(rect.size.width == 100.0); + assert(rect.size.height == 200.0); + + CGRect rect2 = { + .origin = { .x = 0.0, .y = 0.0 }, + .size = { .width = 50.0, .height = 75.0 } + }; + assert(rect2.origin.x == 0.0); + assert(rect2.size.width == 50.0); +} + + +fn void test_geometry_struct_sizes() +{ + if (env::ARCH_64_BIT) + { + assert(CGPoint.sizeof == 16); // 2 * double (8 bytes each) + assert(CGSize.sizeof == 16); // 2 * double + assert(CGRect.sizeof == 32); // CGPoint + CGSize + } + else + { + assert(CGPoint.sizeof == 8); // 2 * float (4 bytes each) + assert(CGSize.sizeof == 8); // 2 * float + assert(CGRect.sizeof == 16); // CGPoint + CGSize + } +} diff --git a/test/unit/stdlib/os/macos/objc.c3 b/test/unit/stdlib/os/macos/objc.c3 new file mode 100644 index 000000000..f86c30fa5 --- /dev/null +++ b/test/unit/stdlib/os/macos/objc.c3 @@ -0,0 +1,188 @@ +module std::os::macos::objc @test @if(env::DARWIN); + +fn void test_application_activation_policy() +{ + NSApplicationActivationPolicy regular = NSApplicationActivationPolicy.REGULAR; + NSApplicationActivationPolicy accessory = NSApplicationActivationPolicy.ACCESSORY; + NSApplicationActivationPolicy prohibited = NSApplicationActivationPolicy.PROHIBITED; + + assert(regular == 0); + assert(accessory == 1); + assert(prohibited == 2); +} + +fn void test_backing_store_type() +{ + NSBackingStoreType retained = NSBackingStoreType.RETAINED; + NSBackingStoreType nonretained = NSBackingStoreType.NONRETAINED; + NSBackingStoreType buffered = NSBackingStoreType.BUFFERED; + + assert(retained == 0); + assert(nonretained == 1); + assert(buffered == 2); +} + +fn void test_event_type() +{ + NSEventType keyDown = NSEventType.KEY_DOWN; + NSEventType keyUp = NSEventType.KEY_UP; + NSEventType mouseDown = NSEventType.LEFT_MOUSE_DOWN; + NSEventType smartMagnify = NSEventType.SMART_MAGNIFY; + NSEventType directTouch = NSEventType.DIRECT_TOUCH; + + assert(keyDown == 10); + assert(keyUp == 11); + assert(mouseDown == 1); + assert(smartMagnify == 32); + assert(directTouch == 37); + + NSUInteger raw = 10; + NSEventType converted = (NSEventType)raw; + assert(converted == NSEventType.KEY_DOWN); +} + +fn void test_event_mask_from_type() +{ + NSEventMask maskMouseDown = ns::event_mask_from_type(NSEventType.LEFT_MOUSE_DOWN); + NSEventMask maskKeyDown = ns::event_mask_from_type(NSEventType.KEY_DOWN); + NSEventMask maskKeyUp = ns::event_mask_from_type(NSEventType.KEY_UP); + NSEventMask maskSmartMagnify = ns::event_mask_from_type(NSEventType.SMART_MAGNIFY); + NSEventMask maskDirectTouch = ns::event_mask_from_type(NSEventType.DIRECT_TOUCH); + + assert(maskMouseDown == NSEventMask.LEFT_MOUSE_DOWN); + assert(maskKeyDown == NSEventMask.KEY_DOWN); + assert(maskKeyUp == NSEventMask.KEY_UP); + assert(maskSmartMagnify == NSEventMask.SMART_MAGNIFY); + assert(maskDirectTouch == NSEventMask.DIRECT_TOUCH); + + assert(maskMouseDown == (1ul << 1)); + assert(maskKeyDown == (1ul << 10)); + assert(maskKeyUp == (1ul << 11)); + assert(maskSmartMagnify == (1ul << 32)); + assert(maskDirectTouch == (1ul << 37)); +} + +fn void test_event_mask() +{ + NSEventMask keyDownMask = NSEventMask.KEY_DOWN; + NSEventMask keyUpMask = NSEventMask.KEY_UP; + NSEventMask smartMagnifyMask = NSEventMask.SMART_MAGNIFY; + NSEventMask directTouchMask = NSEventMask.DIRECT_TOUCH; + NSEventMask anyMask = NSEventMask.ANY; + + assert(keyDownMask == (1ul << 10)); + assert(keyUpMask == (1ul << 11)); + assert(smartMagnifyMask == (1ul << 32)); + assert(directTouchMask == (1ul << 37)); + assert(anyMask == ulong.max); + + NSEventMask combined = NSEventMask.KEY_DOWN | NSEventMask.FLAGS_CHANGED; + assert(combined == ((1ul << 10) | (1ul << 12))); +} + + +fn void test_status_item_length() +{ + assert(NSStatusItemLength.VARIABLE == -1.0); + assert(NSStatusItemLength.SQUARE == -2.0); +} + +fn void test_event_modifier_flags() +{ + NSEventModifierFlags shift = NSEventModifierFlags.SHIFT; + NSEventModifierFlags command = NSEventModifierFlags.COMMAND; + NSEventModifierFlags option = NSEventModifierFlags.OPTION; + NSEventModifierFlags control = NSEventModifierFlags.CONTROL; + + assert(shift == (1 << 17)); + assert(command == (1 << 20)); + assert(option == (1 << 19)); + assert(control == (1 << 18)); + + NSUInteger cmdShift = (NSUInteger)command | (NSUInteger)shift; + assert(cmdShift == ((1 << 20) | (1 << 17))); +} + +fn void test_window_style_mask() +{ + NSWindowStyleMask titled = NSWindowStyleMask.TITLED; + NSWindowStyleMask closable = NSWindowStyleMask.CLOSABLE; + NSWindowStyleMask resizable = NSWindowStyleMask.RESIZABLE; + NSWindowStyleMask borderless = NSWindowStyleMask.BORDERLESS; + + assert(titled == (1 << 0)); + assert(closable == (1 << 1)); + assert(resizable == (1 << 3)); + assert(borderless == 0); + + NSWindowStyleMask style = titled | closable | resizable; + assert(style == ((1 << 0) | (1 << 1) | (1 << 3))); +} + +fn void test_window_collection_behavior() +{ + NSWindowCollectionBehavior def = NSWindowCollectionBehavior.DEFAULT; + NSWindowCollectionBehavior canJoin = NSWindowCollectionBehavior.CAN_JOIN_ALL_SPACES; + NSWindowCollectionBehavior managed = NSWindowCollectionBehavior.MANAGED; + NSWindowCollectionBehavior fullscreen = NSWindowCollectionBehavior.FULL_SCREEN_PRIMARY; + NSWindowCollectionBehavior primary = NSWindowCollectionBehavior.PRIMARY; + + assert(def == 0); + assert(canJoin == (1 << 0)); + assert(managed == (1 << 2)); + assert(fullscreen == (1 << 7)); + assert(primary == (1 << 16)); + + NSWindowCollectionBehavior combined = managed | fullscreen; + assert(combined == ((1 << 2) | (1 << 7))); +} + +fn void test_window_level() +{ + NSWindowLevel normal = NSWindowLevel.NORMAL; + NSWindowLevel floating = NSWindowLevel.FLOATING; + NSWindowLevel modalPanel = NSWindowLevel.MODAL_PANEL; + NSWindowLevel screenSaver = NSWindowLevel.SCREEN_SAVER; + + assert(normal == 0); + assert(floating == 3); + assert(modalPanel == 8); + assert(screenSaver == 1000); +} + +fn void test_window_tabbing_mode() +{ + NSWindowTabbingMode automatic = NSWindowTabbingMode.AUTOMATIC; + NSWindowTabbingMode preferred = NSWindowTabbingMode.PREFERRED; + NSWindowTabbingMode disallowed = NSWindowTabbingMode.DISALLOWED; + + assert(automatic == 0); + assert(preferred == 1); + assert(disallowed == 2); +} + +fn void test_nsuinteger_nsinteger_architecture() +{ + if (env::ARCH_64_BIT) + { + assert(NSUInteger.sizeof == ulong.sizeof); + assert(NSInteger.sizeof == long.sizeof); + } + else + { + assert(NSUInteger.sizeof == uint.sizeof); + assert(NSInteger.sizeof == int.sizeof); + } +} + +// EventMask requires 64-bit values even on 32-bit systems +fn void test_event_mask_64bit_values() +{ + NSEventMask smartMagnify = NSEventMask.SMART_MAGNIFY; + NSEventMask directTouch = NSEventMask.DIRECT_TOUCH; + + assert(smartMagnify == (1ul << 32)); + assert(directTouch == (1ul << 37)); + + assert(NSEventMask.sizeof == ulong.sizeof); +}