From 4d50ed3fe2673e302c7cfce24a153f08d63f9a3b Mon Sep 17 00:00:00 2001 From: Daniel Collin Date: Fri, 6 Jun 2014 10:13:41 +0200 Subject: [PATCH] Added first version of Mac implementation --- include/MiniFB.h | 63 +++++++++++++++ src/macosx/MiniFB.m | 97 +++++++++++++++++++++++ src/macosx/OSXWindow.h | 10 +++ src/macosx/OSXWindow.m | 136 ++++++++++++++++++++++++++++++++ src/macosx/OSXWindowFrameView.h | 8 ++ src/macosx/OSXWindowFrameView.m | 50 ++++++++++++ 6 files changed, 364 insertions(+) create mode 100644 include/MiniFB.h create mode 100644 src/macosx/MiniFB.m create mode 100644 src/macosx/OSXWindow.h create mode 100644 src/macosx/OSXWindow.m create mode 100644 src/macosx/OSXWindowFrameView.h create mode 100644 src/macosx/OSXWindowFrameView.m diff --git a/include/MiniFB.h b/include/MiniFB.h new file mode 100644 index 0000000..d7c2942 --- /dev/null +++ b/include/MiniFB.h @@ -0,0 +1,63 @@ +#ifndef _MINIFB_H_ +#define _MINIFB_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +enum +{ + MFB_KEY_ESC = 0x18, + MFB_KEY_A = 0x41, + MFB_KEY_B = 0x42, + MFB_KEY_C = 0x43, + MFB_KEY_D = 0x44, + MFB_KEY_E = 0x45, + MFB_KEY_F = 0x46, + MFB_KEY_G = 0x47, + MFB_KEY_H = 0x48, + MFB_KEY_I = 0x49, + MFB_KEY_J = 0x4A, + MFB_KEY_K = 0x4B, + MFB_KEY_L = 0x4C, + MFB_KEY_M = 0x4D, + MFB_KEY_N = 0x4E, + MFB_KEY_O = 0x4F, + MFB_KEY_P = 0x50, + MFB_KEY_Q = 0x51, + MFB_KEY_R = 0x52, + MFB_KEY_S = 0x53, + MFB_KEY_T = 0x54, + MFB_KEY_U = 0x55, + MFB_KEY_V = 0x56, + MFB_KEY_W = 0x57, + MFB_KEY_X = 0x58, + MFB_KEY_Y = 0x59, + MFB_KEY_Z = 0x5A, +}; + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#define MFB_RGB(r, g, b) (((unsigned int)r) << 16) | (((unsigned int)g) << 8) | b + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +// Create a window +int mfb_open(const char* name, int width, int height); + +// Update the display. Input buffer is assumed to be a 32-bit buffer of the size given in the open call +// Will return -1 on error, 0 if no key has been pressed otherwise the key code matching the keycode enum +int mfb_update(void* buffer); + +// Close the window +void mfb_close(); + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/macosx/MiniFB.m b/src/macosx/MiniFB.m new file mode 100644 index 0000000..9cefa56 --- /dev/null +++ b/src/macosx/MiniFB.m @@ -0,0 +1,97 @@ + +#include "OSXWindow.h" +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +void* g_updateBuffer = 0; +int g_width = 0; +int g_height = 0; +static NSWindow* window_; + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +int mfb_open(const char* name, int width, int height) +{ + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + + g_width = width; + g_height = height; + + [NSApplication sharedApplication]; + [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular]; + + unsigned int styles = NSResizableWindowMask | NSClosableWindowMask | NSTitledWindowMask; + + NSRect rectangle = NSMakeRect(0, 0, width, height); + window_ = [[OSXWindow alloc] initWithContentRect:rectangle styleMask:styles backing:NSBackingStoreBuffered defer:NO]; + + if (!window_) + return 0; + + [window_ setTitle:[NSString stringWithUTF8String:name]]; + [window_ setReleasedWhenClosed:NO]; + [window_ performSelectorOnMainThread:@selector(makeKeyAndOrderFront:) withObject:nil waitUntilDone:YES]; + + [window_ center]; + + [NSApp activateIgnoringOtherApps:YES]; + + [pool drain]; + + return 1; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +void mfb_close() +{ + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + + if (window_) + [window_ close]; + + [pool drain]; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +static int updateEvents() +{ + int state = 0; + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + NSEvent* event = [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:[NSDate distantPast] inMode:NSDefaultRunLoopMode dequeue:YES]; + if (event) + { + switch ([event type]) + { + case NSKeyDown: + case NSKeyUp: + { + state = -1; + break; + } + + default : + { + [NSApp sendEvent:event]; + break; + } + } + } + [pool release]; + + return state; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +int mfb_update(void* buffer) +{ + g_updateBuffer = buffer; + int state = updateEvents(); + [[window_ contentView] setNeedsDisplay:YES]; + return state; +} diff --git a/src/macosx/OSXWindow.h b/src/macosx/OSXWindow.h new file mode 100644 index 0000000..5314f9c --- /dev/null +++ b/src/macosx/OSXWindow.h @@ -0,0 +1,10 @@ +#import + +// @class OSXWindowFrameView; + +@interface OSXWindow : NSWindow +{ + NSView* childContentView; +} + +@end diff --git a/src/macosx/OSXWindow.m b/src/macosx/OSXWindow.m new file mode 100644 index 0000000..a910e10 --- /dev/null +++ b/src/macosx/OSXWindow.m @@ -0,0 +1,136 @@ +#import "OSXWindow.h" +#import "OSXWindowFrameView.h" + +@implementation OSXWindow + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +- (id)initWithContentRect:(NSRect)contentRect + styleMask:(NSUInteger)windowStyle + backing:(NSBackingStoreType)bufferingType + defer:(BOOL)deferCreation +{ + self = [super + initWithContentRect:contentRect + styleMask:windowStyle + backing:bufferingType + defer:deferCreation]; + if (self) + { + [self setOpaque:YES]; + [self setBackgroundColor:[NSColor clearColor]]; + + [[NSNotificationCenter defaultCenter] + addObserver:self + selector:@selector(mainWindowChanged:) + name:NSWindowDidBecomeMainNotification + object:self]; + + [[NSNotificationCenter defaultCenter] + addObserver:self + selector:@selector(mainWindowChanged:) + name:NSWindowDidResignMainNotification + object:self]; + } + return self; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +- (void)dealloc +{ + [[NSNotificationCenter defaultCenter] + removeObserver:self]; + [super dealloc]; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +- (void)setContentSize:(NSSize)newSize +{ + NSSize sizeDelta = newSize; + NSSize childBoundsSize = [childContentView bounds].size; + sizeDelta.width -= childBoundsSize.width; + sizeDelta.height -= childBoundsSize.height; + + OSXWindowFrameView *frameView = [super contentView]; + NSSize newFrameSize = [frameView bounds].size; + newFrameSize.width += sizeDelta.width; + newFrameSize.height += sizeDelta.height; + + [super setContentSize:newFrameSize]; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +- (void)mainWindowChanged:(NSNotification *)aNotification +{ +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +- (void)setContentView:(NSView *)aView +{ + if ([childContentView isEqualTo:aView]) + { + return; + } + + NSRect bounds = [self frame]; + bounds.origin = NSZeroPoint; + + OSXWindowFrameView *frameView = [super contentView]; + if (!frameView) + { + frameView = [[[OSXWindowFrameView alloc] initWithFrame:bounds] autorelease]; + + [super setContentView:frameView]; + } + + if (childContentView) + { + [childContentView removeFromSuperview]; + } + childContentView = aView; + [childContentView setFrame:[self contentRectForFrameRect:bounds]]; + [childContentView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; + [frameView addSubview:childContentView]; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +- (NSView *)contentView +{ + return childContentView; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +- (BOOL)canBecomeKeyWindow +{ + return YES; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +- (BOOL)canBecomeMainWindow +{ + return YES; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +- (NSRect)contentRectForFrameRect:(NSRect)windowFrame +{ + windowFrame.origin = NSZeroPoint; + return NSInsetRect(windowFrame, 0, 0); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + ++ (NSRect)frameRectForContentRect:(NSRect)windowContentRect styleMask:(NSUInteger)windowStyle +{ + return NSInsetRect(windowContentRect, 0, 0); +} + +@end diff --git a/src/macosx/OSXWindowFrameView.h b/src/macosx/OSXWindowFrameView.h new file mode 100644 index 0000000..96408e9 --- /dev/null +++ b/src/macosx/OSXWindowFrameView.h @@ -0,0 +1,8 @@ +#import + +@interface OSXWindowFrameView : NSView +{ +} + +@end + diff --git a/src/macosx/OSXWindowFrameView.m b/src/macosx/OSXWindowFrameView.m new file mode 100644 index 0000000..1f01a41 --- /dev/null +++ b/src/macosx/OSXWindowFrameView.m @@ -0,0 +1,50 @@ +#import "OSXWindowFrameView.h" + +@implementation OSXWindowFrameView + +extern void* g_updateBuffer; +extern int g_width; +extern int g_height; + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +- (NSRect)resizeRect +{ + const CGFloat resizeBoxSize = 16.0; + const CGFloat contentViewPadding = 5.5; + + NSRect contentViewRect = [[self window] contentRectForFrameRect:[[self window] frame]]; + NSRect resizeRect = NSMakeRect( + NSMaxX(contentViewRect) + contentViewPadding, + NSMinY(contentViewRect) - resizeBoxSize - contentViewPadding, + resizeBoxSize, + resizeBoxSize); + + return resizeRect; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +- (void)drawRect:(NSRect)rect +{ + if (!g_updateBuffer) + return; + + CGContextRef context = [[NSGraphicsContext currentContext] graphicsPort]; + + CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB(); + CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, g_updateBuffer, g_width * g_height * 4, NULL); + + CGImageRef img = CGImageCreate(g_width, g_height, 8, 32, g_width * 4, space, kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Little, + provider, NULL, false, kCGRenderingIntentDefault); + + CGColorSpaceRelease(space); + CGDataProviderRelease(provider); + + CGContextDrawImage(context, CGRectMake(0, 0, g_width, g_height), img); + + CGImageRelease(img); +} + +@end +