mirror of
https://gitlab.winehq.org/wine/vkd3d.git
synced 2025-09-12 18:50:22 -07:00
325 lines
9.6 KiB
C
325 lines
9.6 KiB
C
/*
|
|
* 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_ANSI_F = 0x03,
|
|
kVK_ANSI_W = 0x0d,
|
|
kVK_ANSI_Equal = 0x18,
|
|
kVK_ANSI_Minus = 0x1b,
|
|
kVK_Escape = 0x35,
|
|
kVK_ANSI_KeypadPlus = 0x45,
|
|
kVK_ANSI_KeypadMinus = 0x4e,
|
|
kVK_F1 = 0x7a,
|
|
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_ANSI_F, 'f'},
|
|
{kVK_ANSI_W, 'w'},
|
|
{kVK_ANSI_Equal, '='},
|
|
{kVK_ANSI_Minus, '-'},
|
|
{kVK_Escape, DEMO_KEY_ESCAPE},
|
|
{kVK_ANSI_KeypadPlus, DEMO_KEY_KP_ADD},
|
|
{kVK_ANSI_KeypadMinus, DEMO_KEY_KP_SUBTRACT},
|
|
{kVK_F1, DEMO_KEY_F1},
|
|
{kVK_LeftArrow, DEMO_KEY_LEFT},
|
|
{kVK_RightArrow, DEMO_KEY_RIGHT},
|
|
{kVK_DownArrow, DEMO_KEY_DOWN},
|
|
{kVK_UpArrow, DEMO_KEY_UP},
|
|
};
|
|
|
|
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;
|
|
}
|