#import "BasicOpenGLView.h" #import #include #include #include #include #include #include #include "windowdata.h" #include bool withAutoreleasepool(bool (*f)(void)) { @autoreleasepool { return f(); } } extern const char *macgetresourcepath(void); const char *macgetresourcepath(void) { return [[[NSBundle mainBundle] resourcePath] cStringUsingEncoding:NSUTF8StringEncoding]; } @interface KincApplication : NSApplication { } - (void)terminate:(id)sender; @end @interface KincAppDelegate : NSObject { } - (void)windowWillClose:(NSNotification *)notification; - (void)windowDidResize:(NSNotification *)notification; - (void)windowWillMiniaturize:(NSNotification *)notification; - (void)windowDidDeminiaturize:(NSNotification *)notification; - (void)windowDidResignMain:(NSNotification *)notification; - (void)windowDidBecomeMain:(NSNotification *)notification; @end static NSApplication *myapp; static NSWindow *window; static BasicOpenGLView *view; static KincAppDelegate *delegate; static struct HIDManager *hidManager; /*struct KoreWindow : public KoreWindowBase { NSWindow* handle; BasicOpenGLView* view; KoreWindow(NSWindow* handle, BasicOpenGLView* view, int x, int y, int width, int height) : KoreWindowBase(x, y, width, height), handle(handle), view(view) { ::view = view; } };*/ #ifdef KINC_METAL CAMetalLayer *getMetalLayer(void) { return [view metalLayer]; } id getMetalDevice(void) { return [view metalDevice]; } id getMetalLibrary(void) { return [view metalLibrary]; } id getMetalQueue(void) { return [view metalQueue]; } #endif bool kinc_internal_handle_messages(void) { NSEvent *event = [myapp nextEventMatchingMask:NSAnyEventMask untilDate:[NSDate distantPast] inMode:NSDefaultRunLoopMode dequeue:YES]; // distantPast: non-blocking if (event != nil) { [myapp sendEvent:event]; [myapp updateWindows]; } // Sleep for a frame to limit the calls when the window is not visible. if (!window.visible) { [NSThread sleepForTimeInterval:1.0 / 60]; } return true; } void swapBuffersMac(int windowId) { #ifndef KINC_METAL [windows[windowId].view switchBuffers]; #endif } static int createWindow(kinc_window_options_t *options) { int width = options->width / [[NSScreen mainScreen] backingScaleFactor]; int height = options->height / [[NSScreen mainScreen] backingScaleFactor]; int styleMask = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable; if ((options->window_features & KINC_WINDOW_FEATURE_RESIZEABLE) || (options->window_features & KINC_WINDOW_FEATURE_MAXIMIZABLE)) { styleMask |= NSWindowStyleMaskResizable; } if (options->window_features & KINC_WINDOW_FEATURE_MINIMIZABLE) { styleMask |= NSWindowStyleMaskMiniaturizable; } view = [[BasicOpenGLView alloc] initWithFrame:NSMakeRect(0, 0, width, height)]; [view registerForDraggedTypes:[NSArray arrayWithObjects:NSURLPboardType, nil]]; window = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, width, height) styleMask:styleMask backing:NSBackingStoreBuffered defer:TRUE]; delegate = [KincAppDelegate alloc]; [window setDelegate:delegate]; [window setTitle:[NSString stringWithCString:options->title encoding:NSUTF8StringEncoding]]; [window setAcceptsMouseMovedEvents:YES]; [[window contentView] addSubview:view]; [window center]; windows[windowCounter].handle = window; windows[windowCounter].view = view; [window makeKeyAndOrderFront:nil]; if (options->mode == KINC_WINDOW_MODE_FULLSCREEN || options->mode == KINC_WINDOW_MODE_EXCLUSIVE_FULLSCREEN) { [window toggleFullScreen:nil]; windows[windowCounter].fullscreen = true; } return windowCounter++; } int kinc_count_windows(void) { return windowCounter; } void kinc_window_change_window_mode(int window_index, kinc_window_mode_t mode) { switch (mode) { case KINC_WINDOW_MODE_WINDOW: if (windows[window_index].fullscreen) { [window toggleFullScreen:nil]; windows[window_index].fullscreen = false; } break; case KINC_WINDOW_MODE_FULLSCREEN: case KINC_WINDOW_MODE_EXCLUSIVE_FULLSCREEN: if (!windows[window_index].fullscreen) { [window toggleFullScreen:nil]; windows[window_index].fullscreen = true; } break; } } void kinc_window_set_close_callback(int window, bool (*callback)(void *), void *data) { windows[window].closeCallback = callback; windows[window].closeCallbackData = data; } static void addMenubar(void) { NSString *appName = [[NSProcessInfo processInfo] processName]; NSMenu *appMenu = [NSMenu new]; NSString *quitTitle = [@"Quit " stringByAppendingString:appName]; NSMenuItem *quitMenuItem = [[NSMenuItem alloc] initWithTitle:quitTitle action:@selector(terminate:) keyEquivalent:@"q"]; [appMenu addItem:quitMenuItem]; NSMenuItem *appMenuItem = [NSMenuItem new]; [appMenuItem setSubmenu:appMenu]; NSMenu *menubar = [NSMenu new]; [menubar addItem:appMenuItem]; [NSApp setMainMenu:menubar]; } #ifdef KINC_KONG void kong_init(void); #endif int kinc_init(const char *name, int width, int height, kinc_window_options_t *win, kinc_framebuffer_options_t *frame) { @autoreleasepool { myapp = [KincApplication sharedApplication]; [myapp finishLaunching]; [[NSRunningApplication currentApplication] activateWithOptions:(NSApplicationActivateAllWindows | NSApplicationActivateIgnoringOtherApps)]; NSApp.activationPolicy = NSApplicationActivationPolicyRegular; hidManager = (struct HIDManager *)malloc(sizeof(struct HIDManager)); HIDManager_init(hidManager); addMenubar(); } // System::_init(name, width, height, &win, &frame); kinc_window_options_t defaultWindowOptions; if (win == NULL) { kinc_window_options_set_defaults(&defaultWindowOptions); win = &defaultWindowOptions; } kinc_framebuffer_options_t defaultFramebufferOptions; if (frame == NULL) { kinc_framebuffer_options_set_defaults(&defaultFramebufferOptions); frame = &defaultFramebufferOptions; } win->width = width; win->height = height; if (win->title == NULL) { win->title = name; } int windowId = createWindow(win); kinc_g4_internal_init(); kinc_g4_internal_init_window(windowId, frame->depth_bits, frame->stencil_bits, true); #ifdef KINC_KONG kong_init(); #endif return 0; } int kinc_window_width(int window_index) { NSWindow *window = windows[window_index].handle; float scale = [window backingScaleFactor]; return [[window contentView] frame].size.width * scale; } int kinc_window_height(int window_index) { NSWindow *window = windows[window_index].handle; float scale = [window backingScaleFactor]; return [[window contentView] frame].size.height * scale; } NSWindow *kinc_get_mac_window_handle(int window_index) { return windows[window_index].handle; } void kinc_load_url(const char *url) { [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[NSString stringWithUTF8String:url]]]; } static char language[3]; const char *kinc_language(void) { NSString *nsstr = [[NSLocale preferredLanguages] objectAtIndex:0]; const char *lang = [nsstr UTF8String]; language[0] = lang[0]; language[1] = lang[1]; language[2] = 0; return language; } void kinc_internal_shutdown(void) {} static const char *getSavePath(void) { NSArray *paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES); NSString *resolvedPath = [paths objectAtIndex:0]; NSString *appName = [NSString stringWithUTF8String:kinc_application_name()]; resolvedPath = [resolvedPath stringByAppendingPathComponent:appName]; NSFileManager *fileMgr = [[NSFileManager alloc] init]; NSError *error; [fileMgr createDirectoryAtPath:resolvedPath withIntermediateDirectories:YES attributes:nil error:&error]; resolvedPath = [resolvedPath stringByAppendingString:@"/"]; return [resolvedPath cStringUsingEncoding:NSUTF8StringEncoding]; } const char *kinc_internal_save_path(void) { return getSavePath(); } #ifndef KINC_NO_MAIN int main(int argc, char **argv) { return kickstart(argc, argv); } #endif @implementation KincApplication - (void)terminate:(id)sender { kinc_stop(); } @end @implementation KincAppDelegate - (BOOL)windowShouldClose:(NSWindow *)sender { if (windows[0].closeCallback != NULL) { if (windows[0].closeCallback(windows[0].closeCallbackData)) { return YES; } else { return NO; } } return YES; } - (void)windowWillClose:(NSNotification *)notification { kinc_stop(); } - (void)windowDidResize:(NSNotification *)notification { NSWindow *window = [notification object]; NSSize size = [[window contentView] frame].size; [view resize:size]; if (windows[0].resizeCallback != NULL) { windows[0].resizeCallback(size.width, size.height, windows[0].resizeCallbackData); } } - (void)windowWillMiniaturize:(NSNotification *)notification { kinc_internal_background_callback(); } - (void)windowDidDeminiaturize:(NSNotification *)notification { kinc_internal_foreground_callback(); } - (void)windowDidResignMain:(NSNotification *)notification { kinc_internal_pause_callback(); } - (void)windowDidBecomeMain:(NSNotification *)notification { kinc_internal_resume_callback(); } @end