Added first version of Mac implementation

This commit is contained in:
Daniel Collin 2014-06-06 10:13:41 +02:00
parent 1bc99c1547
commit 4d50ed3fe2
6 changed files with 364 additions and 0 deletions

63
include/MiniFB.h Normal file
View File

@ -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

97
src/macosx/MiniFB.m Normal file
View File

@ -0,0 +1,97 @@
#include "OSXWindow.h"
#include <Cocoa/Cocoa.h>
#include <unistd.h>
#include <MiniFB.h>
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
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;
}

10
src/macosx/OSXWindow.h Normal file
View File

@ -0,0 +1,10 @@
#import <Cocoa/Cocoa.h>
// @class OSXWindowFrameView;
@interface OSXWindow : NSWindow
{
NSView* childContentView;
}
@end

136
src/macosx/OSXWindow.m Normal file
View File

@ -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

View File

@ -0,0 +1,8 @@
#import <Cocoa/Cocoa.h>
@interface OSXWindowFrameView : NSView
{
}
@end

View File

@ -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