4coder/platform_mac/mac_4ed.m

348 lines
8.1 KiB
Objective-C

/*
* Mr. 4th Dimention - Allen Webster
*
* 28.06.2017
*
* Mac Objective C layer for 4coder
*
*/
// TOP
#include "4ed_defines.h"
#include "4coder_API/version.h"
#define WINDOW_NAME "4coder" VERSION
#undef internal
#undef global
#undef external
#define external
#include "osx_objective_c_to_cpp_links.h"
#import <Cocoa/Cocoa.h>
#import <CoreVideo/CVDisplayLink.h>
#import <IOKit/hid/IOHIDLib.h>
#import <OpenGL/OpenGL.h>
#import <OpenGL/gl.h>
void
osx_post_to_clipboard(char *str){
NSPasteboard *board = [NSPasteboard generalPasteboard];
NSString *utf8_type = @"public.utf8-plain-text";
NSArray<NSString*> *typesArray = [NSArray arrayWithObjects: utf8_type, nil];
[board declareTypes:typesArray owner:nil];
NSString *paste_string = [NSString stringWithUTF8String:str];
[board setString:paste_string forType:utf8_type];
osx.just_posted_to_clipboard = true;
}
void
osx_error_dialogue(char *str){
NSAlert *alert = [[NSAlert alloc] init];
[alert addButtonWithTitle:@"OK"];
NSString *text = [NSString stringWithUTF8String:str];
[alert setMessageText:text];
[alert setAlertStyle:NSCriticalAlertStyle];
[alert runModal];
}
//
// Entry point, OpenGL window setup.
//
@interface AppDelegate : NSObject <NSApplicationDelegate>
@end
@interface My4coderView : NSOpenGLView{
@public
CVDisplayLinkRef displayLink;
}
- (CVReturn)getFrameForTime:(const CVTimeStamp*)time;
@end
#define DISPLINK_SIG(n) CVReturn n(CVDisplayLinkRef link, const CVTimeStamp *now, const CVTimeStamp *output, CVOptionFlags flags_in, CVOptionFlags *flags_out, void *context)
static DISPLINK_SIG(osx_display_link);
@implementation My4coderView
- (void)keyDown:(NSEvent *)event{
NSString *real = [event charactersIgnoringModifiers];
NSString *with_mods = [event characters];
b32 is_dead_key = false;
if (real && !with_mods){
is_dead_key = true;
}
OSX_Keyboard_Modifiers mods = {0};
NSEventModifierFlags flags = [NSEvent modifierFlags];
mods.shift = ((flags & NSEventModifierFlagShift) != 0);
mods.command = ((flags & NSEventModifierFlagCommand) != 0);
mods.control = ((flags & NSEventModifierFlagControl) != 0);
mods.option = ((flags & NSEventModifierFlagOption) != 0);
u32 length = real.length;
for (u32 i = 0; i < length; ++i){
unichar c = [real characterAtIndex:i];
osx_character_input(c, mods);
}
}
- (void)mouseDown:(NSEvent*)event{
NSPoint m = [event locationInWindow];
osx_mouse(m.x, m.y, MouseType_Press);
}
- (void)mouseDragged:(NSEvent*)event{
NSPoint m = [event locationInWindow];
osx_mouse(m.x, m.y, MouseType_Move);
}
- (void)mouseMoved:(NSEvent*)event{
NSPoint m = [event locationInWindow];
osx_mouse(m.x, m.y, MouseType_Move);
}
- (void)mouseUp:(NSEvent*)event{
NSPoint m = [event locationInWindow];
osx_mouse(m.x, m.y, MouseType_Release);
}
- (void)scrollWheel:(NSEvent*)event{
float dx = event.scrollingDeltaX;
float dy = event.scrollingDeltaY;
osx_mouse_wheel(dx, dy);
}
- (CVReturn)getFrameForTime:(const CVTimeStamp*)time{
@autoreleasepool
{
if (osx.running){
NSPasteboard *board = [NSPasteboard generalPasteboard];
if (board.changeCount != osx.prev_clipboard_change_count){
if (!osx.just_posted_to_clipboard){
NSString *utf8_type = @"public.utf8-plain-text";
NSArray *array = [NSArray arrayWithObjects: utf8_type, nil];
NSString *has_string = [board availableTypeFromArray:array];
if (has_string != nil){
NSData *data = [board dataForType: utf8_type];
if (data != nil){
u32 copy_length = data.length;
if (copy_length > 0){
// TODO(allen): Grow clipboard memory if needed.
if (copy_length+1 < osx.clipboard_max){
osx.clipboard_size = copy_length;
[data getBytes: osx.clipboard_data length: copy_length];
((char*)osx.clipboard_data)[copy_length] = 0;
osx.has_clipboard_item = true;
}
}
}
}
}
else{
osx.just_posted_to_clipboard = false;
}
osx.prev_clipboard_change_count = board.changeCount;
}
CGLLockContext([[self openGLContext] CGLContextObj]);
[[self openGLContext] makeCurrentContext];
osx_step();
[[self openGLContext] flushBuffer];
CGLUnlockContext([[self openGLContext] CGLContextObj]);
}
}
return kCVReturnSuccess;
}
- (void)reshape
{
[super reshape];
NSRect rect = [self bounds];
osx_resize(rect.size.width, rect.size.height);
}
- (void)init_gl
{
if(osx.running)
{
return;
}
[self setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
NSOpenGLPixelFormatAttribute attrs[] = {
NSOpenGLPFAOpenGLProfile,
//NSOpenGLProfileVersion3_2Core,
NSOpenGLProfileVersionLegacy,
NSOpenGLPFAColorSize,
24,
NSOpenGLPFAAlphaSize,
8,
NSOpenGLPFAAccelerated,
NSOpenGLPFADoubleBuffer,
0
};
NSOpenGLPixelFormat* format = [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs];
if(format == nil)
{
fprintf(stderr, "Error creating OpenGLPixelFormat\n");
exit(1);
}
NSOpenGLContext* context = [[NSOpenGLContext alloc] initWithFormat:format shareContext:nil];
[self setPixelFormat:format];
[self setOpenGLContext:context];
[context makeCurrentContext];
osx.running = true;
}
- (id)init
{
self = [super init];
if(self == nil)
{
return nil;
}
[self init_gl];
return self;
}
- (void)awakeFromNib
{
[self init_gl];
}
- (void)prepareOpenGL
{
[super prepareOpenGL];
[[self openGLContext] makeCurrentContext];
GLint swapInt = 1;
[[self openGLContext] setValues:&swapInt forParameter:NSOpenGLCPSwapInterval];
CVReturn cvreturn = CVDisplayLinkCreateWithActiveCGDisplays(&displayLink);
cvreturn = CVDisplayLinkSetOutputCallback(displayLink, &osx_display_link, (__bridge void*)(self));
CGLContextObj cglContext = [[self openGLContext] CGLContextObj];
CGLPixelFormatObj cglPixelFormat = [[self pixelFormat] CGLPixelFormatObj];
cvreturn = CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext(displayLink, cglContext, cglPixelFormat);
CVDisplayLinkStart(displayLink);
}
- (void)dealloc
{
[super dealloc];
CVDisplayLinkStop(displayLink);
CVDisplayLinkRelease(displayLink);
}
- (BOOL)acceptsFirstResponder
{
return YES;
}
- (BOOL)becomeFirstResponder
{
return YES;
}
- (BOOL)resignFirstResponder
{
return YES;
}
@end
static
DISPLINK_SIG(osx_display_link){
My4coderView* view = (__bridge My4coderView*)context;
CVReturn result = [view getFrameForTime:output];
return result;
}
@implementation AppDelegate
- (void)applicationDidFinishLaunching:(id)sender
{
}
- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication*)sender
{
return YES;
}
- (void)applicationWillTerminate:(NSApplication*)sender
{
}
@end
void
osx_add_file_listener(char *file_name){
NotImplemented;
}
void
osx_remove_file_listener(char *file_name){
NotImplemented;
}
i32
osx_get_file_change_event(char *buffer, i32 max, i32 *size){
i32 result = 0;
NotImplemented;
return(result);
}
int
main(int argc, char **argv){
memset(&osx, 0, sizeof(osx));
umem clipboard_size = MB(4);
osx.clipboard_data = osx_allocate(clipboard_size);
osx.clipboard_max = clipboard_size;
osx.argc = argc;
osx.argv = argv;
osx_init();
@autoreleasepool{
NSApplication *app = [NSApplication sharedApplication];
[NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
[app setDelegate:[[AppDelegate alloc] init]];
NSRect screenRect = [[NSScreen mainScreen] frame];
float w = 800.f;
float h = 600.f;
NSRect frame = NSMakeRect((screenRect.size.width - w) * 0.5, (screenRect.size.height - h) * 0.5, w, h);
u32 flags = NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask;
NSWindow* window = [[NSWindow alloc] initWithContentRect:frame styleMask:flags backing:NSBackingStoreBuffered defer:NO];
[window setAcceptsMouseMovedEvents:YES];
My4coderView* view = [[My4coderView alloc] init];
[view setFrame:[[window contentView] bounds]];
[view setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
[[window contentView] addSubview:view];
[window setMinSize:NSMakeSize(100, 100)];
[window setTitle:@WINDOW_NAME];
[window makeKeyAndOrderFront:nil];
[NSApp run];
}
return(0);
}
// BOTTOM