From b389fa89e406ac0ad351b4847ccaefb507fbe268 Mon Sep 17 00:00:00 2001 From: Henri Verbeet Date: Sat, 3 May 2025 17:27:14 +0200 Subject: [PATCH] demos: Make the demos work in the macOS build. --- Makefile.am | 23 ++- configure.ac | 4 + demos/demo.h | 6 +- demos/demo_macos.h | 310 ++++++++++++++++++++++++++++++++ demos/demo_vkd3d.h | 28 +++ demos/make_objc | 143 +++++++++++++++ include/private/appkit.json | 205 +++++++++++++++++++++ include/private/foundation.json | 40 +++++ include/private/quartzcore.json | 40 +++++ 9 files changed, 792 insertions(+), 7 deletions(-) create mode 100644 demos/demo_macos.h create mode 100755 demos/make_objc create mode 100644 include/private/appkit.json create mode 100644 include/private/foundation.json create mode 100644 include/private/quartzcore.json diff --git a/Makefile.am b/Makefile.am index 115c5a3e7..1cfd16198 100644 --- a/Makefile.am +++ b/Makefile.am @@ -4,6 +4,11 @@ AM_CPPFLAGS = -I$(srcdir)/include -I$(srcdir)/include/private -I$(builddir)/incl AM_LDFLAGS = -no-undefined VKD3D_PERL = $(PERL) -w +objc_headers = \ + include/private/appkit.h \ + include/private/foundation.h \ + include/private/quartzcore.h + widl_headers = \ include/vkd3d_d3d12.h \ include/vkd3d_d3d12sdklayers.h \ @@ -323,11 +328,12 @@ vkd3d_demos = \ vkd3d_demos_headers = \ demos/demo.h \ demos/demo_d3d12.h \ + demos/demo_macos.h \ demos/demo_vkd3d.h \ demos/demo_win32.h \ demos/demo_xcb.h -BUILT_SOURCES = $(widl_headers) \ +BUILT_SOURCES = $(objc_headers) $(widl_headers) \ include/private/spirv_grammar.h \ include/private/vkd3d_version.h @@ -549,6 +555,16 @@ endif noinst_HEADERS = $(vkd3d_test_headers) $(vkd3d_demos_headers) +VKD3D_V_PERL = $(vkd3d_v_perl_@AM_V@) +vkd3d_v_perl_ = $(vkd3d_v_perl_@AM_DEFAULT_V@) +vkd3d_v_perl_0 = @echo " PERL " $@; +vkd3d_v_perl_1 = + +CLEANFILES += $(objc_headers) +${objc_headers}: %.h: demos/make_objc %.json + @$(MKDIR_P) $(@D) + $(VKD3D_V_PERL)$(VKD3D_PERL) $^ > $@.tmp && mv $@.tmp $@ + VKD3D_V_WIDL = $(vkd3d_v_widl_@AM_V@) vkd3d_v_widl_ = $(vkd3d_v_widl_@AM_DEFAULT_V@) vkd3d_v_widl_0 = @echo " WIDL " $@; @@ -589,11 +605,6 @@ libvkd3d.pc: $(srcdir)/libs/vkd3d/libvkd3d.pc.in Makefile -e 's![@]PACKAGE_VERSION[@]!$(PACKAGE_VERSION)!g' \ $< > $@ -VKD3D_V_PERL = $(vkd3d_v_perl_@AM_V@) -vkd3d_v_perl_ = $(vkd3d_v_perl_@AM_DEFAULT_V@) -vkd3d_v_perl_0 = @echo " PERL " $@; -vkd3d_v_perl_1 = - include/private/spirv_grammar.h: libs/vkd3d-shader/make_spirv include/private/spirv.core.grammar.json @$(MKDIR_P) $(@D) $(VKD3D_V_PERL)$(VKD3D_PERL) $^ > $@.tmp && mv $@.tmp $@ diff --git a/configure.ac b/configure.ac index 5e3c624e8..6b1bdcee2 100644 --- a/configure.ac +++ b/configure.ac @@ -187,6 +187,10 @@ case $host_os in AC_SUBST([DEMO_LIBS],["-lgdi32"]) AC_SUBST([DEMO_CFLAGS],["-municode"]) ;; + darwin*) + AC_SUBST([DEMO_LIBS],["-framework Foundation -framework AppKit -framework QuartzCore"]) + AC_SUBST([DEMO_CFLAGS],[""]) + ;; *) AS_IF([test "x$enable_demos" = "xyes" -a "x$HAVE_XCB" != "xyes"], [AC_MSG_ERROR([libxcb is required for demos.])]) AC_SUBST([DEMO_LIBS],[$XCB_LIBS]) diff --git a/demos/demo.h b/demos/demo.h index cfc860f6b..2d5aae33a 100644 --- a/demos/demo.h +++ b/demos/demo.h @@ -43,13 +43,17 @@ #define DEMO_ASM_PUSHSECTION ".section rdata\n\t" #define DEMO_ASM_POPSECTION ".text\n\t" #define DEMO_ASM_OBJECT_TYPE(name) +#elif defined(__APPLE__) +#define DEMO_ASM_PUSHSECTION ".pushsection __TEXT,__const\n\t" +#define DEMO_ASM_POPSECTION ".popsection\n\t" +#define DEMO_ASM_OBJECT_TYPE(name) #else #define DEMO_ASM_PUSHSECTION ".pushsection .rodata\n\t" #define DEMO_ASM_POPSECTION ".popsection\n\t" #define DEMO_ASM_OBJECT_TYPE(name) ".type "name", @object\n\t" #endif -#if defined(__WIN32__) && defined(__i386__) +#if (defined(__WIN32__) && defined(__i386__)) || defined(__APPLE__) #define DEMO_ASM_NAME(name) "_"#name #else #define DEMO_ASM_NAME(name) #name diff --git a/demos/demo_macos.h b/demos/demo_macos.h new file mode 100644 index 000000000..cdafb9a66 --- /dev/null +++ b/demos/demo_macos.h @@ -0,0 +1,310 @@ +/* + * Copyright 2025 Henri Verbeet + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +typedef long NSInteger; +typedef unsigned long NSUInteger; + +typedef struct NSPoint +{ + double x, y; +} NSPoint; + +typedef struct NSRect +{ + double x, y; + double w, h; +} NSRect; + +#define BOOL OBJC_BOOL +#include "private/appkit.h" +#include "private/foundation.h" +#include "private/quartzcore.h" +#undef BOOL + +extern const id NSDefaultRunLoopMode; + +enum NSBackingStoreType +{ + NSBackingStoreBuffered = 2, +}; + +enum NSEventType +{ + NSEventTypeKeyDown = 0xa, + NSEventTypeApplicationDefined = 0xf, +}; + +enum NSWindowStyleMask +{ + NSWindowStyleMaskBorderless = 0x0000, + NSWindowStyleMaskTitled = 0x0001, + NSWindowStyleMaskClosable = 0x0002, + NSWindowStyleMaskMiniaturizable = 0x0004, + NSWindowStyleMaskResizable = 0x0008, + NSWindowStyleMaskUtilityWindow = 0x0010, + NSWindowStyleMaskDocModalWindow = 0x0040, + NSWindowStyleMaskNonactivatingPanel = 0x0080, + NSWindowStyleMaskUnifiedTitleAndToolbar = 0x1000, + NSWindowStyleMaskHUDWindow = 0x2000, + NSWindowStyleMaskFullScreen = 0x4000, + NSWindowStyleMaskFullSizeContentView = 0x8000, +}; + +enum +{ + DemoWindowDestroyed, +}; + +struct demo_window_macos +{ + struct demo_window w; + id window; + id layer; +}; + +static struct demo_window_macos *demo_macos_find_macos_window(struct demo *demo, id window) +{ + size_t i; + + for (i = 0; i < demo->window_count; ++i) + { + struct demo_window_macos *window_macos = CONTAINING_RECORD(demo->windows[i], struct demo_window_macos, w); + + if (window_macos->window == window) + return window_macos; + } + + return NULL; +} + +static VkSurfaceKHR demo_window_macos_create_vk_surface(struct demo_window *window, VkInstance vk_instance) +{ + struct demo_window_macos *window_macos = CONTAINING_RECORD(window, struct demo_window_macos, w); + struct VkMetalSurfaceCreateInfoEXT surface_desc; + VkSurfaceKHR vk_surface; + id l, v; + + l = window_macos->layer = CAMetalLayer_layer(); + CAMetalLayer_setContentsScale(l, NSScreen_backingScaleFactor(NSScreen_mainScreen())); + v = NSWindow_contentView(window_macos->window); + NSView_setLayer(v, l); + NSView_setWantsLayer(v, true); + + surface_desc.sType = VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT; + surface_desc.pNext = NULL; + surface_desc.flags = 0; + surface_desc.pLayer = l; + if (vkCreateMetalSurfaceEXT(vk_instance, &surface_desc, NULL, &vk_surface) < 0) + return VK_NULL_HANDLE; + + return vk_surface; +} + +static void demo_window_macos_destroy(struct demo_window *window) +{ + struct demo_window_macos *window_macos = CONTAINING_RECORD(window, struct demo_window_macos, w); + + NSWindow_close(window_macos->window); +} + +static void demo_window_macos_destroyed(struct demo_window_macos *window_macos) +{ + CAMetalLayer_release(window_macos->layer); + NSWindow_release(window_macos->window); + demo_window_cleanup(&window_macos->w); + free(window_macos); +} + +static struct demo_window *demo_window_macos_create(struct demo *demo, + const char *title, unsigned int width, unsigned int height, void *user_data) +{ + unsigned long style = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable; + struct demo_window_macos *window_macos; + NSRect r = {0, 0, width, height}; + double scale; + id w, s; + + if (!(window_macos = malloc(sizeof(*window_macos)))) + return NULL; + + if (!demo_window_init(&window_macos->w, demo, user_data, + demo_window_macos_create_vk_surface, demo_window_macos_destroy)) + { + free(window_macos); + return NULL; + } + + s = NSScreen_mainScreen(); + scale = NSScreen_backingScaleFactor(s); + r.w /= scale; + r.h /= scale; + + w = window_macos->window = class_createInstance(objc_getClass("DemoWindow"), 0); + NSWindow_initWithContentRect(w, r, style, NSBackingStoreBuffered, true, s); + NSWindow_setReleasedWhenClosed(w, false); + NSWindow_setDelegate(w, w); + NSWindow_center(w); + NSWindow_setTitle(w, NSString_stringWithUTF8String(title)); + + NSWindow_makeKeyAndOrderFront(w, nil); + window_macos->layer = nil; + + return &window_macos->w; +} + +static void demo_macos_get_dpi(struct demo *demo, double *dpi_x, double *dpi_y) +{ + *dpi_x = *dpi_y = 96.0 * NSScreen_backingScaleFactor(NSScreen_mainScreen()); +} + +static demo_key demo_key_from_nsevent(id event) +{ + enum vkey + { + kVK_ANSI_A = 0x00, + kVK_Escape = 0x35, + kVK_LeftArrow = 0x7b, + kVK_RightArrow = 0x7c, + kVK_DownArrow = 0x7d, + kVK_UpArrow = 0x7e, + } vkey; + size_t i; + + static const struct + { + enum vkey vkey; + demo_key demo_key; + } + lookup[] = + { + {kVK_ANSI_A, 'a'}, + {kVK_Escape, DEMO_KEY_ESCAPE}, + {kVK_LeftArrow, DEMO_KEY_LEFT}, + {kVK_RightArrow, DEMO_KEY_RIGHT}, + {kVK_UpArrow, DEMO_KEY_UP}, + {kVK_DownArrow, DEMO_KEY_DOWN}, + }; + + vkey = NSEvent_keyCode(event); + for (i = 0; i < ARRAY_SIZE(lookup); ++i) + { + if (lookup[i].vkey == vkey) + return lookup[i].demo_key; + } + + return DEMO_KEY_UNKNOWN; +} + +static void demo_macos_process_events(struct demo *demo) +{ + struct demo_window_macos *window_macos; + struct demo_window *window; + id a, event; + size_t i; + + for (i = 0; i < demo->window_count; ++i) + { + if ((window = demo->windows[i])->expose_func) + window->expose_func(window, window->user_data); + } + + a = NSApplication_sharedApplication(); + while (demo->window_count) + { + if (!demo->idle_func) + { + if (!(event = NSApplication_nextEventMatchingMask(a, ~(uint64_t)0, + NSDate_distantFuture(), NSDefaultRunLoopMode, true))) + break; + } + else if (!(event = NSApplication_nextEventMatchingMask(a, ~(uint64_t)0, nil, NSDefaultRunLoopMode, true))) + { + demo->idle_func(demo, demo->user_data); + continue; + } + + switch (NSEvent_type(event)) + { + case NSEventTypeKeyDown: + if (NSMenu_performKeyEquivalent(NSApplication_mainMenu(a), event)) + continue; + if (!(window_macos = demo_macos_find_macos_window(demo, NSEvent_window(event))) + || !window_macos->w.key_press_func) + break; + window_macos->w.key_press_func(&window_macos->w, + demo_key_from_nsevent(event), window_macos->w.user_data); + continue; + + case NSEventTypeApplicationDefined: + if (NSEvent_subtype(event) != DemoWindowDestroyed + || !(window_macos = demo_macos_find_macos_window(demo, NSEvent_window(event)))) + break; + demo_window_macos_destroyed(window_macos); + continue; + } + + NSApplication_sendEvent(a, event); + } +} + +static void DemoWindow_windowWillClose(id window, SEL sel, id notification) +{ + id event; + + event = NSEvent_otherEventWithType(NSEventTypeApplicationDefined, (NSPoint){0.0, 0.0}, + 0, 0.0, NSWindow_windowNumber(window), nil, DemoWindowDestroyed, 0, 0); + NSApplication_postEvent(NSApplication_sharedApplication(), event, true); +} + +static void demo_macos_cleanup(struct demo *demo) +{ +} + +static bool demo_macos_init(struct demo_macos *macos) +{ + id application, item, menu, submenu; + Class c; + + if ((c = objc_allocateClassPair(objc_getClass("NSWindow"), "DemoWindow", 0))) + { + class_addMethod(c, sel_registerName("windowWillClose:"), (IMP)DemoWindow_windowWillClose, "v@:@"); + objc_registerClassPair(c); + } + + application = NSApplication_sharedApplication(); + NSApplication_setActivationPolicy(application, 0); + + menu = NSMenu_new(); + + submenu = NSMenu_new(); + NSMenu_addItemWithTitle(submenu, NSString_stringWithUTF8String("Quit"), + sel_registerName("terminate:"), NSString_stringWithUTF8String("q")); + + item = NSMenuItem_new(); + NSMenuItem_setSubmenu(item, submenu); + NSMenu_release(submenu); + NSMenu_addItem(menu, item); + NSMenuItem_release(item); + + NSApplication_setMainMenu(application, menu); + NSMenu_release(menu); + + NSApplication_finishLaunching(application); + + return true; +} diff --git a/demos/demo_vkd3d.h b/demos/demo_vkd3d.h index ecd482a35..b97656ecc 100644 --- a/demos/demo_vkd3d.h +++ b/demos/demo_vkd3d.h @@ -19,6 +19,9 @@ #include "config.h" #define VK_NO_PROTOTYPES +#ifdef __APPLE__ +# define VK_USE_PLATFORM_METAL_EXT +#endif #ifdef _WIN32 # define VK_USE_PLATFORM_WIN32_KHR #endif @@ -44,6 +47,9 @@ DECLARE_VK_PFN(vkAcquireNextImageKHR) DECLARE_VK_PFN(vkCreateFence) DECLARE_VK_PFN(vkCreateSwapchainKHR) +#ifdef __APPLE__ +DECLARE_VK_PFN(vkCreateMetalSurfaceEXT) +#endif #ifdef _WIN32 DECLARE_VK_PFN(vkCreateWin32SurfaceKHR) #endif @@ -61,6 +67,12 @@ DECLARE_VK_PFN(vkQueuePresentKHR) DECLARE_VK_PFN(vkResetFences) DECLARE_VK_PFN(vkWaitForFences) +struct demo_macos +{ +#ifdef __APPLE__ +#endif +}; + struct demo_win32 { #ifdef _WIN32 @@ -83,6 +95,7 @@ struct demo { union { + struct demo_macos macos; struct demo_win32 win32; struct demo_xcb xcb; } u; @@ -167,6 +180,9 @@ static inline void demo_window_cleanup(struct demo_window *window) demo_remove_window(window->demo, window); } +#ifdef __APPLE__ +# include "demo_macos.h" +#endif #ifdef _WIN32 # include "demo_win32.h" #endif @@ -200,6 +216,9 @@ static void load_vulkan_procs(void) LOAD_VK_PFN(vkAcquireNextImageKHR) LOAD_VK_PFN(vkCreateFence) LOAD_VK_PFN(vkCreateSwapchainKHR) +#ifdef __APPLE__ + LOAD_VK_PFN(vkCreateMetalSurfaceEXT) +#endif #ifdef _WIN32 LOAD_VK_PFN(vkCreateWin32SurfaceKHR) #endif @@ -244,6 +263,15 @@ static inline void demo_cleanup(struct demo *demo) static inline bool demo_init(struct demo *demo, void *user_data) { +#ifdef __APPLE__ + if (demo_macos_init(&demo->u.macos)) + { + demo->create_window = demo_window_macos_create; + demo->get_dpi = demo_macos_get_dpi; + demo->process_events = demo_macos_process_events; + demo->cleanup = demo_macos_cleanup; + } +#endif #ifdef _WIN32 if (demo_win32_init(&demo->u.win32)) { diff --git a/demos/make_objc b/demos/make_objc new file mode 100755 index 000000000..ee4b88033 --- /dev/null +++ b/demos/make_objc @@ -0,0 +1,143 @@ +#!/usr/bin/perl -w +# +# Copyright 2025 Henri Verbeet +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +use strict; +use warnings; +use JSON; +use open ':utf8'; +binmode STDOUT, ':utf8'; + +sub method_name($) +{ + shift->{selector} =~ s/(:.*)//r; +} + +sub method_parameters($$) +{ + my ($method, $method_type) = @_; + + my $parameters = join ", ", $method_type eq "class" ? () : "id self", + map {"$_->{type} $_->{name}"} @{$method->{parameters}}; + + length $parameters ? $parameters : "void"; +} + +sub send_function($) +{ + shift->{'return-float'} ? "objc_msgSend_fpret" : "objc_msgSend"; +} + +sub invocation_type($$) +{ + my ($method, $method_type) = @_; + + "$method->{'return-type'} (*)(" . join(", ", $method_type eq "class" ? "Class" : "id", "SEL", + map {$_->{type}} @{$method->{parameters}}) . ")"; +} + +sub invocation_parameters($$$) +{ + my ($method, $interface_name, $method_type) = @_; + + join ", ", $method_type eq "class" ? "objc_getClass(\"$interface_name\")" : "self", + "sel_registerName(\"$method->{selector}\")", map {$_->{name}} @{$method->{parameters}}; +} + +sub invocation($$$) +{ + my ($method, $interface_name, $method_type) = @_; + + ($method->{'return-type'} eq "void" ? "" : "return ") + . "((${\invocation_type $method, $method_type})f)" + . "(${\invocation_parameters $method, $interface_name, $method_type});"; +} + +sub print_method($$$) +{ + my ($method, $interface_name, $method_type) = @_; + + print "static inline $method->{'return-type'} " + . "${interface_name}_${\method_name $method}(${\method_parameters $method, $method_type})\n"; + print "{\n"; + print " void *f = ${\send_function $method};\n"; + print " ${\invocation $method, $interface_name, $method_type}\n"; + print "}\n\n"; +} + +sub print_property($$) +{ + my ($property, $interface_name) = @_; + + my $method = + { + 'return-type' => $property->{type}, + 'return-float' => $property->{float}, + selector => $property->{getter} // $property->{name}, + }; + my $method_type = $property->{class} ? "class" : "instance"; + + print_method $method, $interface_name, $method_type; + if (!$property->{readonly}) + { + $method->{'return-type'} = "void"; + $method->{'return-float'} = 0; + $method->{selector} = "set${\ucfirst $property->{name}}:"; + $method->{parameters} = [$property]; + print_method $method, $interface_name, $method_type; + } +} + +sub print_interface(_) +{ + my ($interface) = @_; + + print_method $_, $interface->{name}, "class" foreach (@{$interface->{'class-methods'}}); + print_method $_, $interface->{name}, "instance" foreach (@{$interface->{'instance-methods'}}); + print_property $_, $interface->{name} foreach (@{$interface->{properties}}); +} + +sub print_header($) +{ + my ($grammar) = @_; + + my $guard = "__VKD3D_${\uc $grammar->{name}}_H__"; + + print "/*\n"; + print " * This file is automatically generated.\n"; + print " * The original source is covered by the following license:\n"; + print " *\n"; + print map {" * $_" =~ s/ +$//r . "\n"} @{$grammar->{copyright}}; + print " */\n\n"; + + print "#ifndef $guard\n"; + print "#define $guard\n\n"; + + print "#include \n\n"; + + print_interface foreach (@{$grammar->{interfaces}}); + + print "#endif /* $guard */\n"; +} + +die "No input file specified.\n" unless @ARGV; +print_header do +{ + local $/; + open my $fh, '<', $ARGV[0] or die $!; + decode_json <$fh>; +}; diff --git a/include/private/appkit.json b/include/private/appkit.json new file mode 100644 index 000000000..401b214fd --- /dev/null +++ b/include/private/appkit.json @@ -0,0 +1,205 @@ +{ + "copyright" : [ + "Copyright 2025 Henri Verbeet", + "", + "This library is free software; you can redistribute it and/or", + "modify it under the terms of the GNU Lesser General Public", + "License as published by the Free Software Foundation; either", + "version 2.1 of the License, or (at your option) any later version.", + "", + "This library is distributed in the hope that it will be useful,", + "but WITHOUT ANY WARRANTY; without even the implied warranty of", + "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU", + "Lesser General Public License for more details.", + "", + "You should have received a copy of the GNU Lesser General Public", + "License along with this library; if not, write to the Free Software", + "Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA" + ], + "name" : "AppKit", + "interfaces" : [ + { + "name" : "NSApplication", + "instance-methods" : [ + { + "selector" : "finishLaunching", + "return-type" : "void" + }, + { + "selector" : "nextEventMatchingMask:untilDate:inMode:dequeue:", + "return-type" : "id", + "parameters" : [ + {"type" : "uint64_t", "name" : "mask"}, + {"type" : "id", "name" : "expiration"}, + {"type" : "id", "name" : "mode"}, + {"type" : "BOOL", "name" : "dequeue"} + ] + }, + { + "selector" : "postEvent:atStart:", + "return-type" : "void", + "parameters" : [ + {"type" : "id", "name" : "event"}, + {"type" : "BOOL", "name" : "at_start"} + ] + }, + { + "selector" : "sendEvent:", + "return-type" : "void", + "parameters" : [ + {"type" : "id", "name" : "event"} + ] + }, + { + "selector" : "setActivationPolicy:", + "return-type" : "BOOL", + "parameters" : [ + {"type" : "long", "name" : "policy"} + ] + } + ], + "properties" : [ + {"type" : "id", "name" : "mainMenu"}, + {"type" : "id", "name" : "sharedApplication", "readonly" : true, "class" : true} + ] + }, + { + "name" : "NSEvent", + "class-methods" : [ + { + "selector" : "otherEventWithType:location:modifierFlags:timestamp:windowNumber:context:subtype:data1:data2:", + "return-type" : "id", + "parameters" : [ + {"type" : "unsigned long", "name" : "type"}, + {"type" : "NSPoint", "name" : "location"}, + {"type" : "NSUInteger", "name" : "flags"}, + {"type" : "double", "name" : "time"}, + {"type" : "NSInteger", "name" : "window"}, + {"type" : "id", "name" : "context"}, + {"type" : "short", "name" : "subtype"}, + {"type" : "NSInteger", "name" : "d1"}, + {"type" : "NSInteger", "name" : "d2"} + ] + } + ], + "properties" : [ + {"type" : "unsigned short", "name" : "keyCode", "readonly" : true}, + {"type" : "short", "name" : "subtype", "readonly" : true}, + {"type" : "NSUInteger", "name" : "type", "readonly" : true}, + {"type" : "id", "name" : "window", "readonly" : true} + ] + }, + { + "name" : "NSMenu", + "class-methods" : [ + { + "selector" : "new", + "return-type" : "id" + } + ], + "instance-methods" : [ + { + "selector" : "addItem:", + "return-type" : "void", + "parameters" : [ + {"type" : "id", "name" : "item"} + ] + }, + { + "selector" : "addItemWithTitle:action:keyEquivalent:", + "return-type" : "id", + "parameters" : [ + {"type" : "id", "name" : "title"}, + {"type" : "SEL", "name" : "selector"}, + {"type" : "id", "name" : "key"} + ] + }, + { + "selector" : "performKeyEquivalent:", + "return-type" : "BOOL", + "parameters" : [ + {"type" : "id", "name" : "event"} + ] + }, + { + "selector" : "release", + "return-type" : "void" + } + ] + }, + { + "name" : "NSMenuItem", + "class-methods" : [ + { + "selector" : "new", + "return-type" : "id" + } + ], + "instance-methods" : [ + { + "selector" : "release", + "return-type" : "void" + } + ], + "properties" : [ + {"type" : "id", "name" : "submenu"} + ] + }, + { + "name" : "NSScreen", + "properties" : [ + {"type" : "double", "name" : "backingScaleFactor", "readonly" : true, "float" : true}, + {"type" : "id", "name" : "mainScreen", "readonly" : true, "class" : true} + ] + }, + { + "name" : "NSView", + "properties" : [ + {"type" : "id", "name" : "layer"}, + {"type" : "BOOL", "name" : "wantsLayer"} + ] + }, + { + "name" : "NSWindow", + "instance-methods" : [ + { + "selector" : "center", + "return-type" : "void" + }, + { + "selector" : "close", + "return-type" : "void" + }, + { + "selector" : "initWithContentRect:styleMask:backing:defer:screen:", + "return-type" : "id", + "parameters" : [ + {"type" : "NSRect", "name" : "rect"}, + {"type" : "NSUInteger", "name" : "style"}, + {"type" : "NSUInteger", "name" : "backing_store_type"}, + {"type" : "BOOL", "name" : "defer"}, + {"type" : "id", "name" : "screen"} + ] + }, + { + "selector" : "makeKeyAndOrderFront:", + "return-type" : "void", + "parameters" : [ + {"type" : "id", "name" : "sender"} + ] + }, + { + "selector" : "release", + "return-type" : "void" + } + ], + "properties" : [ + {"type" : "id", "name" : "contentView"}, + {"type" : "id", "name" : "delegate"}, + {"type" : "BOOL", "name" : "releasedWhenClosed", "getter" : "isReleasedWhenClosed"}, + {"type" : "id", "name" : "title"}, + {"type" : "NSInteger", "name" : "windowNumber", "readonly" : true} + ] + } + ] +} diff --git a/include/private/foundation.json b/include/private/foundation.json new file mode 100644 index 000000000..2fa3deea1 --- /dev/null +++ b/include/private/foundation.json @@ -0,0 +1,40 @@ +{ + "copyright" : [ + "Copyright 2025 Henri Verbeet", + "", + "This library is free software; you can redistribute it and/or", + "modify it under the terms of the GNU Lesser General Public", + "License as published by the Free Software Foundation; either", + "version 2.1 of the License, or (at your option) any later version.", + "", + "This library is distributed in the hope that it will be useful,", + "but WITHOUT ANY WARRANTY; without even the implied warranty of", + "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU", + "Lesser General Public License for more details.", + "", + "You should have received a copy of the GNU Lesser General Public", + "License along with this library; if not, write to the Free Software", + "Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA" + ], + "name" : "Foundation", + "interfaces" : [ + { + "name" : "NSDate", + "properties" : [ + {"type" : "id", "name" : "distantFuture", "readonly" : true, "class" : true} + ] + }, + { + "name" : "NSString", + "class-methods" : [ + { + "selector" : "stringWithUTF8String:", + "return-type" : "id", + "parameters" : [ + {"type" : "const char *", "name" : "s"} + ] + } + ] + } + ] +} diff --git a/include/private/quartzcore.json b/include/private/quartzcore.json new file mode 100644 index 000000000..7cc12c9d7 --- /dev/null +++ b/include/private/quartzcore.json @@ -0,0 +1,40 @@ +{ + "copyright" : [ + "Copyright 2025 Henri Verbeet", + "", + "This library is free software; you can redistribute it and/or", + "modify it under the terms of the GNU Lesser General Public", + "License as published by the Free Software Foundation; either", + "version 2.1 of the License, or (at your option) any later version.", + "", + "This library is distributed in the hope that it will be useful,", + "but WITHOUT ANY WARRANTY; without even the implied warranty of", + "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU", + "Lesser General Public License for more details.", + "", + "You should have received a copy of the GNU Lesser General Public", + "License along with this library; if not, write to the Free Software", + "Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA" + ], + "name" : "QuartzCore", + "interfaces" : [ + { + "name" : "CAMetalLayer", + "class-methods" : [ + { + "selector" : "layer", + "return-type" : "id" + } + ], + "instance-methods" : [ + { + "selector" : "release", + "return-type" : "void" + } + ], + "properties" : [ + {"type" : "double", "name" : "contentsScale", "float" : true} + ] + } + ] +}