Skip to content

Instantly share code, notes, and snippets.

@kuon
Created December 20, 2016 17:43
Show Gist options
  • Save kuon/d16ea3aa6085fbe77653103203c90658 to your computer and use it in GitHub Desktop.
Save kuon/d16ea3aa6085fbe77653103203c90658 to your computer and use it in GitHub Desktop.
NSApp fun
#include "nw_private.h"
#include "NWApplication.h"
#include "NWApplicationView.h"
#include "nw_application.h"
#include "nw_keyboard.h"
#include "nw_geometry.h"
#include "nw_opengl.h"
#include "nw_timer.h"
#include "nw_autorelease_pool.h"
void nw_app_run(void)
{
sranddev();
[NWApplication sharedApplication];
[NSMenu setMenuBarVisible : YES];
[NSApp run];
}
nw_string_t *nw_app_language(void)
{
NSAutoreleasePool *pool = [NSAutoreleasePool new];
NSUserDefaults* defs = [NSUserDefaults standardUserDefaults];
NSArray* languages = [defs objectForKey:@"AppleLanguages"];
NSString* preferredLang = [languages objectAtIndex:0];
nw_string_t *res;
if (preferredLang)
res = nw_string_with_utf8((const uint8_t*)[preferredLang UTF8String]);
else
res = nw_str("en");
[pool release];
return res;
}
nw_string_t *nw_app_resource_directory(void)
{
NSAutoreleasePool *pool = [NSAutoreleasePool new];
nw_string_t *path = nw_string_with_utf8((const uint8_t *)[[[NSBundle mainBundle] resourcePath] UTF8String]);
[pool release];
return path;
}
@implementation NWApplication
-(void)exit
{
done = YES;
}
-(id)init
{
if ([super init])
[self initKeymap];
return self;
}
-(void)launch
{
appPool = [NSAutoreleasePool new];
[NSApp setDelegate : self];
[self finishLaunching];
}
-(void)buildMenu
{
NSMenu *rootMenu = [[NSMenu alloc] initWithTitle:@ ""];
[NSApp setMainMenu : rootMenu];
NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:@ "Options" action:nil keyEquivalent:@ ""];
NSMenu *optionMenu = [[NSMenu alloc] initWithTitle:@ "Options"];
[[NSApp mainMenu] addItem : item];
[[NSApp mainMenu] setSubmenu : optionMenu forItem : item];
item = [[NSMenuItem alloc] initWithTitle:@ "Toggle fullscreen mode"
action:@selector(toggleFullScreen)
keyEquivalent:@ "f"];
[item setTarget : self];
[optionMenu addItem : item];
item = [[NSMenuItem alloc] initWithTitle:@ "Reload UI"
action:@selector(reloadUI)
keyEquivalent:@ "r"];
[item setTarget : self];
[optionMenu addItem : item];
}
-(void)reloadUI
{
}
-(void)toggleFullScreen
{
NSDictionary *opts =
[NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:NO], NSFullScreenModeAllScreens, nil];
if ([mainOpenGLView isInFullScreenMode])
{
[mainOpenGLView exitFullScreenModeWithOptions : opts];
[mainWindow makeKeyAndOrderFront : self];
[mainWindow makeFirstResponder : mainOpenGLView];
}
else
[mainOpenGLView enterFullScreenMode :[NSScreen mainScreen] withOptions : opts];
isInFullScreenMode = [mainOpenGLView isInFullScreenMode];
nw_app_resize(nw_size([mainOpenGLView frame].size.width, [mainOpenGLView frame].size.height));
[mainOpenGLContext update];
}
-(void)createMainWindow
{
nw_rect_t nwrect = nw_rect(nw_app_configuration_int_for_key(nw_str("window.x")),
nw_app_configuration_int_for_key(nw_str("window.y")),
nw_app_configuration_int_for_key(nw_str("window.width")),
nw_app_configuration_int_for_key(nw_str("window.height")));
NSRect rect = NSMakeRect(nwrect.origin.x, nwrect.origin.y, nwrect.size.width, nwrect.size.height);
NSUInteger mask = NSTitledWindowMask | NSClosableWindowMask;
if (nw_app_configuration_int_for_key(nw_str("window.resize")))
mask |= NSResizableWindowMask;
mainWindow = [[NSWindow alloc]
initWithContentRect:rect
styleMask:mask
backing:NSBackingStoreBuffered defer:NO];
[mainWindow setDelegate : self];
if (nw_app_configuration_int_for_key(nw_str("window.center")))
[mainWindow center];
[mainWindow setAcceptsMouseMovedEvents : YES];
mainOpenGLView = [[NWApplicationView alloc] initWithFrame:rect];
[mainWindow setContentView : mainOpenGLView];
[mainWindow makeFirstResponder : mainOpenGLView];
}
-(void)createMainOpenGLContext
{
NSOpenGLPixelFormatAttribute attribs[] = {
NSOpenGLPFANoRecovery,
NSOpenGLPFAAccelerated,
NSOpenGLPFADoubleBuffer,
// NSOpenGLPFAFullScreen,
// NSOpenGLPFAScreenMask,CGDisplayIDToOpenGLDisplayMask(kCGDirectMainDisplay),
NSOpenGLPFADepthSize, 16,
NSOpenGLPFAColorSize, 32,
0
};
NSOpenGLPixelFormat *format = [[NSOpenGLPixelFormat alloc]
initWithAttributes:attribs];
if (!format)
nw_fatal("Unable to set pixel format");
mainOpenGLContext = [[NSOpenGLContext alloc] initWithFormat:format
shareContext:nil];
[mainOpenGLContext makeCurrentContext];
CGLContextObj ctx = [mainOpenGLContext CGLContextObj];
int one = nw_app_configuration_int_for_key(nw_str("verticalsync"));
CGLSetParameter(ctx, kCGLCPSwapInterval, &one);
[format release];
[mainOpenGLContext setView : mainOpenGLView];
}
-(BOOL)windowShouldZoom : (NSWindow *)window toFrame : (NSRect)proposedFrame
{
return YES;
}
static void animate(nw_timer_t *timer, void *args)
{
nw_app_animate();
}
-(void)run
{
[self launch];
[self buildMenu];
[self createMainWindow];
[self createMainOpenGLContext];
[mainWindow makeKeyAndOrderFront : self];
if (nw_app_configuration_int_for_key(nw_str("window.fullscreen")))
[self toggleFullScreen];
else if (nw_app_configuration_int_for_key(nw_str("window.zoom")))
[mainWindow setFrame :[[NSScreen mainScreen] visibleFrame] display : NO];
else
nw_app_resize(nw_size([mainOpenGLView frame].size.width, [mainOpenGLView frame].size.height));
nw_app_start();
bool should_animate = nw_app_configuration_int_for_key(nw_str("animation.animate"));
NSDate *until = !should_animate &&
nw_app_configuration_int_for_key(nw_str("waitforevents")) ? [NSDate distantFuture] : nil;
nw_timer_t *animate_timer = NULL;
if (should_animate)
{
animate_timer = nw_new(nw_timer);
nw_timer_schedule(animate_timer, nw_app_configuration_int_for_key(nw_str("animation.duration")), animate, NULL);
}
while (!done)
{
NSAutoreleasePool *pool = [NSAutoreleasePool new];
nw_autorelease_pool_t *nw_pool = nw_new(nw_autorelease_pool);
NSEvent *event = [self nextEventMatchingMask:(NSUInteger) NSAnyEventMask
untilDate:until
inMode:NSDefaultRunLoopMode
dequeue:YES];
[self sendEvent : event];
nw_update_timers();
nw_app_draw();
[mainOpenGLContext flushBuffer];
nw_release(nw_pool);
[pool release];
}
nw_release(animate_timer);
[appPool release];
}
-(void)sendEvent : (NSEvent *)event
{
if (!event || !mainWindow)
return;
NSPoint loc =
isInFullScreenMode ? [NSEvent mouseLocation] : [mainWindow convertScreenToBase :[NSEvent mouseLocation]];
nw_point_t p = nw_point(loc.x, loc.y);
switch ([event type])
{
case NSRightMouseDragged:
case NSLeftMouseDragged:
case NSOtherMouseDragged:
case NSMouseMoved:
nw_app_mouse_moved(p, nw_point([event deltaX], [event deltaY]));
break;
case NSLeftMouseDown:
case NSRightMouseDown:
case NSOtherMouseDown:
nw_app_mouse_down(p, [event buttonNumber] + 1);
break;
case NSLeftMouseUp:
case NSRightMouseUp:
case NSOtherMouseUp:
nw_app_mouse_up(p, [event buttonNumber] + 1);
break;
case NSScrollWheel:
nw_app_mouse_wheel(p, nw_point([event deltaX] *10, [event deltaY] *10));
break;
case NSKeyDown:
nw_app_key_down(KEYMAP[[event keyCode]]);
break;
case NSKeyUp:
nw_app_key_up(KEYMAP[[event keyCode]]);
break;
default:
break;
}
[super sendEvent : event];
}
-(void)windowWillClose : (NSNotification *)notification
{
mainWindow = nil;
nw_app_exit();
}
-(void)windowDidResize : (NSNotification *)notification
{
nw_app_resize(nw_size([mainOpenGLView frame].size.width, [mainOpenGLView frame].size.height));
[mainOpenGLContext update];
[mainWindow makeFirstResponder : mainOpenGLView];
}
-(void)applicationWillTerminate : (NSNotification *)aNotification
{
nw_app_exit();
}
-(void)initKeymap
{
KEYMAP[NW_MACOSX_KEY_ESCAPE] = NW_K_ESCAPE;
KEYMAP[NW_MACOSX_KEY_F1] = NW_K_F1;
KEYMAP[NW_MACOSX_KEY_F2] = NW_K_F2;
KEYMAP[NW_MACOSX_KEY_F3] = NW_K_F3;
KEYMAP[NW_MACOSX_KEY_F4] = NW_K_F4;
KEYMAP[NW_MACOSX_KEY_F5] = NW_K_F5;
KEYMAP[NW_MACOSX_KEY_F6] = NW_K_F6;
KEYMAP[NW_MACOSX_KEY_F7] = NW_K_F7;
KEYMAP[NW_MACOSX_KEY_F8] = NW_K_F8;
KEYMAP[NW_MACOSX_KEY_F9] = NW_K_F9;
KEYMAP[NW_MACOSX_KEY_F10] = NW_K_F10;
KEYMAP[NW_MACOSX_KEY_F11] = NW_K_F11;
KEYMAP[NW_MACOSX_KEY_F12] = NW_K_F12;
KEYMAP[NW_MACOSX_KEY_F13] = NW_K_F13;
KEYMAP[NW_MACOSX_KEY_F14] = NW_K_F14;
KEYMAP[NW_MACOSX_KEY_F15] = NW_K_F15;
KEYMAP[NW_MACOSX_KEY_POWER] = NW_K_POWER;
KEYMAP[NW_MACOSX_KEY_BACKQUOTE] = NW_K_BACKQUOTE;
KEYMAP[NW_MACOSX_KEY_1] = NW_K_1;
KEYMAP[NW_MACOSX_KEY_2] = NW_K_2;
KEYMAP[NW_MACOSX_KEY_3] = NW_K_3;
KEYMAP[NW_MACOSX_KEY_4] = NW_K_4;
KEYMAP[NW_MACOSX_KEY_5] = NW_K_5;
KEYMAP[NW_MACOSX_KEY_6] = NW_K_6;
KEYMAP[NW_MACOSX_KEY_7] = NW_K_7;
KEYMAP[NW_MACOSX_KEY_8] = NW_K_8;
KEYMAP[NW_MACOSX_KEY_9] = NW_K_9;
KEYMAP[NW_MACOSX_KEY_0] = NW_K_0;
KEYMAP[NW_MACOSX_KEY_MINUS] = NW_K_MINUS;
KEYMAP[NW_MACOSX_KEY_EQUALS] = NW_K_EQUALS;
KEYMAP[NW_MACOSX_KEY_BACKSPACE] = NW_K_BACKSPACE;
KEYMAP[NW_MACOSX_KEY_INSERT] = NW_K_INSERT;
KEYMAP[NW_MACOSX_KEY_HOME] = NW_K_HOME;
KEYMAP[NW_MACOSX_KEY_PAGEUP] = NW_K_PAGEUP;
KEYMAP[NW_MACOSX_KEY_NUMLOCK] = NW_K_NUMLOCK;
KEYMAP[NW_MACOSX_KEY_KP_EQUALS] = NW_K_KP_EQUALS;
KEYMAP[NW_MACOSX_KEY_KP_DIVIDE] = NW_K_KP_DIVIDE;
KEYMAP[NW_MACOSX_KEY_KP_MULTIPLY] = NW_K_KP_MULTIPLY;
KEYMAP[NW_MACOSX_KEY_TAB] = NW_K_TAB;
KEYMAP[NW_MACOSX_KEY_q] = NW_K_q;
KEYMAP[NW_MACOSX_KEY_w] = NW_K_w;
KEYMAP[NW_MACOSX_KEY_e] = NW_K_e;
KEYMAP[NW_MACOSX_KEY_r] = NW_K_r;
KEYMAP[NW_MACOSX_KEY_t] = NW_K_t;
KEYMAP[NW_MACOSX_KEY_y] = NW_K_y;
KEYMAP[NW_MACOSX_KEY_u] = NW_K_u;
KEYMAP[NW_MACOSX_KEY_i] = NW_K_i;
KEYMAP[NW_MACOSX_KEY_o] = NW_K_o;
KEYMAP[NW_MACOSX_KEY_p] = NW_K_p;
KEYMAP[NW_MACOSX_KEY_LEFTBRACKET] = NW_K_LEFTBRACKET;
KEYMAP[NW_MACOSX_KEY_RIGHTBRACKET] = NW_K_RIGHTBRACKET;
KEYMAP[NW_MACOSX_KEY_BACKSLASH] = NW_K_BACKSLASH;
KEYMAP[NW_MACOSX_KEY_DELETE] = NW_K_DELETE;
KEYMAP[NW_MACOSX_KEY_END] = NW_K_END;
KEYMAP[NW_MACOSX_KEY_PAGEDOWN] = NW_K_PAGEDOWN;
KEYMAP[NW_MACOSX_KEY_KP7] = NW_K_KP7;
KEYMAP[NW_MACOSX_KEY_KP8] = NW_K_KP8;
KEYMAP[NW_MACOSX_KEY_KP9] = NW_K_KP9;
KEYMAP[NW_MACOSX_KEY_KP_MINUS] = NW_K_KP_MINUS;
KEYMAP[NW_MACOSX_KEY_CAPSLOCK] = NW_K_CAPSLOCK;
KEYMAP[NW_MACOSX_KEY_a] = NW_K_a;
KEYMAP[NW_MACOSX_KEY_s] = NW_K_s;
KEYMAP[NW_MACOSX_KEY_d] = NW_K_d;
KEYMAP[NW_MACOSX_KEY_f] = NW_K_f;
KEYMAP[NW_MACOSX_KEY_g] = NW_K_g;
KEYMAP[NW_MACOSX_KEY_h] = NW_K_h;
KEYMAP[NW_MACOSX_KEY_j] = NW_K_j;
KEYMAP[NW_MACOSX_KEY_k] = NW_K_k;
KEYMAP[NW_MACOSX_KEY_l] = NW_K_l;
KEYMAP[NW_MACOSX_KEY_SEMICOLON] = NW_K_SEMICOLON;
KEYMAP[NW_MACOSX_KEY_QUOTE] = NW_K_QUOTE;
KEYMAP[NW_MACOSX_KEY_RETURN] = NW_K_RETURN;
KEYMAP[NW_MACOSX_KEY_KP4] = NW_K_KP4;
KEYMAP[NW_MACOSX_KEY_KP5] = NW_K_KP5;
KEYMAP[NW_MACOSX_KEY_KP6] = NW_K_KP6;
KEYMAP[NW_MACOSX_KEY_KP_PLUS] = NW_K_KP_PLUS;
KEYMAP[NW_MACOSX_KEY_LSHIFT] = NW_K_LSHIFT;
KEYMAP[NW_MACOSX_KEY_RSHIFT] = NW_K_RSHIFT;
KEYMAP[NW_MACOSX_KEY_z] = NW_K_z;
KEYMAP[NW_MACOSX_KEY_x] = NW_K_x;
KEYMAP[NW_MACOSX_KEY_c] = NW_K_c;
KEYMAP[NW_MACOSX_KEY_v] = NW_K_v;
KEYMAP[NW_MACOSX_KEY_b] = NW_K_b;
KEYMAP[NW_MACOSX_KEY_n] = NW_K_n;
KEYMAP[NW_MACOSX_KEY_m] = NW_K_m;
KEYMAP[NW_MACOSX_KEY_COMMA] = NW_K_COMMA;
KEYMAP[NW_MACOSX_KEY_PERIOD] = NW_K_PERIOD;
KEYMAP[NW_MACOSX_KEY_SLASH] = NW_K_SLASH;
KEYMAP[NW_MACOSX_KEY_UP] = NW_K_UP;
KEYMAP[NW_MACOSX_KEY_KP1] = NW_K_KP1;
KEYMAP[NW_MACOSX_KEY_KP2] = NW_K_KP2;
KEYMAP[NW_MACOSX_KEY_KP3] = NW_K_KP3;
KEYMAP[NW_MACOSX_KEY_KP_ENTER] = NW_K_KP_ENTER;
KEYMAP[NW_MACOSX_KEY_LCTRL] = NW_K_LCTRL;
KEYMAP[NW_MACOSX_KEY_LALT] = NW_K_LALT;
KEYMAP[NW_MACOSX_KEY_LMETA] = NW_K_LMETA;
KEYMAP[NW_MACOSX_KEY_RCTRL] = NW_K_RCTRL;
KEYMAP[NW_MACOSX_KEY_RALT] = NW_K_RALT;
KEYMAP[NW_MACOSX_KEY_RMETA] = NW_K_RMETA;
KEYMAP[NW_MACOSX_KEY_SPACE] = NW_K_SPACE;
KEYMAP[NW_MACOSX_KEY_LEFT] = NW_K_LEFT;
KEYMAP[NW_MACOSX_KEY_DOWN] = NW_K_DOWN;
KEYMAP[NW_MACOSX_KEY_RIGHT] = NW_K_RIGHT;
KEYMAP[NW_MACOSX_KEY_KP0] = NW_K_KP0;
KEYMAP[NW_MACOSX_KEY_KP_PERIOD] = NW_K_KP_PERIOD;
KEYMAP[NW_MACOSX_KEY_IBOOK_ENTER] = NW_K_KP_ENTER;
KEYMAP[NW_MACOSX_KEY_IBOOK_RIGHT] = NW_K_RIGHT;
KEYMAP[NW_MACOSX_KEY_IBOOK_DOWN] = NW_K_DOWN;
KEYMAP[NW_MACOSX_KEY_IBOOK_UP] = NW_K_UP;
KEYMAP[NW_MACOSX_KEY_IBOOK_LEFT] = NW_K_LEFT;
KEYMAP[NW_MACOSX_KEY_KP0] = NW_K_KP0;
KEYMAP[NW_MACOSX_KEY_KP1] = NW_K_KP1;
KEYMAP[NW_MACOSX_KEY_KP2] = NW_K_KP2;
KEYMAP[NW_MACOSX_KEY_KP3] = NW_K_KP3;
KEYMAP[NW_MACOSX_KEY_KP4] = NW_K_KP4;
KEYMAP[NW_MACOSX_KEY_KP5] = NW_K_KP5;
KEYMAP[NW_MACOSX_KEY_KP6] = NW_K_KP6;
KEYMAP[NW_MACOSX_KEY_KP7] = NW_K_KP7;
KEYMAP[NW_MACOSX_KEY_KP8] = NW_K_KP8;
KEYMAP[NW_MACOSX_KEY_KP9] = NW_K_KP9;
KEYMAP[NW_MACOSX_KEY_KP_MINUS] = NW_K_KP_MINUS;
KEYMAP[NW_MACOSX_KEY_KP_PLUS] = NW_K_KP_PLUS;
KEYMAP[NW_MACOSX_KEY_KP_PERIOD] = NW_K_KP_PERIOD;
KEYMAP[NW_MACOSX_KEY_KP_EQUALS] = NW_K_KP_EQUALS;
KEYMAP[NW_MACOSX_KEY_KP_DIVIDE] = NW_K_KP_DIVIDE;
KEYMAP[NW_MACOSX_KEY_KP_MULTIPLY] = NW_K_KP_MULTIPLY;
KEYMAP[NW_MACOSX_KEY_KP_ENTER] = NW_K_KP_ENTER;
}
@end
#include "NWApplicationView.h"
#include "nw_application.h"
@implementation NWApplicationView
-(BOOL)hasMarkedText
{
return NO;
}
-(NSRange)markedRange
{
return NSMakeRange(0, 0);
}
-(NSRange)selectedRange
{
return NSMakeRange(0, 0);
}
-(void)setMarkedText : (id) aString selectedRange : (NSRange)selRange
{
NSString *str;
if ([aString isKindOfClass :[NSString class]])
str = aString;
else if ([aString isKindOfClass :[NSAttributedString class]])
str = [aString string];
else
return;
nw_app_text_input(nw_string_with_utf8((const uint8_t *)[str UTF8String]), true);
}
-(void)unmarkText
{
}
-(NSArray *)validAttributesForMarkedText
{
return [NSArray array];
}
-(NSAttributedString *)attributedSubstringFromRange : (NSRange)theRange
{
return nil;
}
-(NSUInteger)characterIndexForPoint : (NSPoint)thePoint
{
return 0;
}
-(NSRect)firstRectForCharacterRange : (NSRange)theRange
{
return NSZeroRect;
}
-(void)insertText : (id)aString
{
NSString *str;
if ([aString isKindOfClass :[NSString class]])
str = aString;
else if ([aString isKindOfClass :[NSAttributedString class]])
str = [aString string];
else
return;
nw_app_text_input(nw_string_with_utf8((const uint8_t *)[str UTF8String]), false);
}
-(void)doCommandBySelector : (SEL)aSelector
{
[super doCommandBySelector : aSelector];
}
-(NSInteger)conversationIdentifier
{
return (NSInteger)self;
}
-(void)keyDown : (NSEvent *)event
{
[self interpretKeyEvents :[NSArray arrayWithObject : event]];
}
-(void)deleteBackward : (id)sender
{
nw_app_text_event(NW_TEXT_EVENT_DELETE_BACKWARD);
}
-(void)deleteForward : (id)sender
{
nw_app_text_event(NW_TEXT_EVENT_DELETE_FORWARD);
}
-(void)moveLeft : (id)sender
{
nw_app_text_event(NW_TEXT_EVENT_MOVE_LEFT);
}
-(void)moveRight : (id)sender
{
nw_app_text_event(NW_TEXT_EVENT_MOVE_RIGHT);
}
-(void)moveDown : (id)sender
{
nw_app_text_event(NW_TEXT_EVENT_MOVE_DOWN);
}
-(void)moveUp : (id)sender
{
nw_app_text_event(NW_TEXT_EVENT_MOVE_UP);
}
-(void)insertNewline : (id)sender
{
nw_app_text_event(NW_TEXT_EVENT_INSERT_NEWLINE);
}
-(void)insertTab : (id)sender
{
}
-(void)cancelOperation : (id)sender
{
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment