#include #include "../../external/stb_ds.h" #include "Mw/LowLevel/Cocoa.h" #ifdef __clang__ #pragma clang push #pragma clang diagnostic ignored "-Wdeprecated-declarations" #endif static NSRect rectFlip(NSRect originFrame) { NSScreen* zeroScreen = [[NSScreen screens] objectAtIndex:0]; double screenHeight = [zeroScreen frame].size.height; double originY = originFrame.origin.y; double frameHeight = originFrame.size.height; double destinationY = screenHeight - (originY + frameHeight); NSRect destinationFrame = originFrame; destinationFrame.origin.y = destinationY; return destinationFrame; } static NSPoint pointFlip(NSPoint point) { return rectFlip(NSMakeRect(point.x, point.y, 0, 0)).origin; } static NSRect localRectFlip(NSRect originFrame, NSView* view) { float viewHeight = [view bounds].size.height; NSRect destinationFrame = NSMakeRect(originFrame.origin.x, [view bounds].size.height - (originFrame.origin.y + originFrame.size.height), originFrame.size.width, originFrame.size.height); return destinationFrame; } static NSPoint localPointFlip(NSPoint point, NSView* view) { return localRectFlip(NSMakeRect(point.x, point.y, 0, 0), view).origin; } /* Recursively dispatch a key event to a widget and its children */ static void recursive_dispatch_key(MwLL handle, int* k) { MwWidget h = (MwWidget)handle->common.user; MwLLDispatch(handle, key, k); if(h) { int i; for(i = 0; i < arrlen(h->children); i++) { MwLLDispatch(h->children[i]->lowlevel, key, k); if(arrlen(h->children[i]->children) > 0) { recursive_dispatch_key(h->children[i]->lowlevel, k); } } } }; /* Recursively dispatch a key released event to a widget and its children */ static void recursive_dispatch_key_released(MwLL handle, int* k) { MwWidget h = (MwWidget)handle->common.user; MwLLDispatch(handle, key_released, k); if(h) { int i; for(i = 0; i < arrlen(h->children); i++) { MwLLDispatch(h->children[i]->lowlevel, key_released, k); if(arrlen(h->children[i]->children) > 0) { recursive_dispatch_key_released(h->children[i]->lowlevel, k); } } } }; @implementation MilskoCocoaPixmap + (MilskoCocoaPixmap*)newWithWidth:(int)width height:(int)height { MilskoCocoaPixmap* p = [MilskoCocoaPixmap alloc]; p->width = width; p->height = height; p->image = NULL; p->buf = malloc(width * height * 4); p->rep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:&p->buf pixelsWide:(int)width pixelsHigh:(int)height bitsPerSample:8 samplesPerPixel:4 hasAlpha:YES isPlanar:NO colorSpaceName:NSDeviceRGBColorSpace bytesPerRow:(int)width * 4 bitsPerPixel:32]; assert(p->rep); p->image = [[NSImage alloc] initWithSize:NSMakeSize(width, height)]; assert(p->image); [p->image addRepresentation:p->rep]; return p; } - (void)updateWithData:(unsigned char*)_data { memcpy(self->buf, _data, width * height * 4); if(self->rep) { [self->image removeRepresentation:self->rep]; [self->rep release]; } self->rep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:&self->buf pixelsWide:(int)width pixelsHigh:(int)height bitsPerSample:8 samplesPerPixel:4 hasAlpha:YES isPlanar:NO colorSpaceName:NSDeviceRGBColorSpace bytesPerRow:(int)width * 4 bitsPerPixel:32]; [self->image addRepresentation:self->rep]; } - (void)destroy { free(self->buf); [self->image removeRepresentation:self->rep]; [self->image release]; [self->rep release]; self->image = NULL; self->rep = NULL; } - (NSImage*)image { return self->image; } @end @implementation MilskoCocoa + (MilskoCocoa*)newWithParent:(MwLL)parent x:(int)x y:(int)y width:(int)width height:(int)height handle:(MwLL)r { MilskoCocoa* c = [MilskoCocoa alloc]; NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; [c retain]; /* * MacOS doesn't really have a "default" window position, you're actually * meant to center the window yourself, so if the user passes MwDEFAULT * respond appropriately. Also for child windows just have it be 0. */ if(x == MwDEFAULT) { x = r ? ([[NSScreen mainScreen] frame].size.width / 2.) - (width / 2.) : 0; } if(y == MwDEFAULT) { y = r ? ([[NSScreen mainScreen] frame].size.height / 2.) - (height / 2.) : 0; } c->application = [MilskoCocoaApplication sharedApplication]; c->rect = NSMakeRect(x, y, width, height); if(parent == NULL) { c->window = [[MilskoCocoaWindow alloc] initWithContentRect:rectFlip(c->rect) styleMask:(NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask) backing:NSBackingStoreBuffered defer:NO]; [c->window setDelegate:[[MilskoCocoaWindowDelegate alloc] initWithWin:c->window]]; [c->window retain]; [c->window makeKeyAndOrderFront:c->application]; [c->window makeFirstResponder:c->view]; c->view = [[MilskoCocoaView alloc] initWithFrame:c->rect]; [c->view retain]; [c->window setContentView:c->view]; if([c->application respondsToSelector:@selector(setActivationPolicy:)]) { [c->application setActivationPolicy:0 /* NSApplicationActivationPolicyRegular */]; } [c->application activateIgnoringOtherApps:MwTRUE]; [c->application setDelegate:[[MilskoCocoaApplicationDelegate alloc] initWithAppl:c->application]]; [c->application retain]; [c->view addTrackingRect:c->rect owner:c->view userData:NULL assumeInside:MwFALSE]; } else { MilskoCocoa* p = parent->cocoa.real; c->window = p->window; NSRect rect = localRectFlip(c->rect, p->view); c->view = [[MilskoCocoaView alloc] initWithFrame:rect]; [c->view setBounds:c->rect]; [c->view retain]; [c->view setChild]; [c->view addTrackingRect:c->rect owner:c->view userData:NULL assumeInside:MwFALSE]; [p->view addSubview:c->view]; } [c->window setAcceptsMouseMovedEvents:MwTRUE]; c->handle = [[MilskoFakePointer alloc] initWithFrame:NSMakeRect(0, 0, 1, 1)]; [c->handle retain]; [c->handle setPointer:r]; [c->view addSubview:c->handle]; c->modalSession = [c->application beginModalSessionForWindow:c->window]; c->parent = parent; c->_forceRender = MwTRUE; c->strHash = 0; c->cursorPixmap = NULL; [c->application finishLaunching]; c->pointerLocked = MwFALSE; [pool release]; return c; } - (void)polygonWithPoints:(MwPoint*)points points_count:(int)points_count color:(MwLLColor)color { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; NSGraphicsContext* ctx = [self->view context]; if(ctx) { int i; NSBezierPath* path = [NSBezierPath bezierPath]; /* whatever rect we use for coordinate flipping */ NSRect _rect = parent ? [self->view bounds] : [self->window frame]; NSColor* nscolor = [NSColor colorWithCalibratedRed:color->common.red / 255. green:color->common.green / 255. blue:color->common.blue / 255. alpha:1.0]; [NSGraphicsContext saveGraphicsState]; [NSGraphicsContext setCurrentContext:ctx]; [nscolor setFill]; for(i = 0; i < points_count; i++) { NSPoint p = localPointFlip(NSMakePoint(points[i].x, points[i].y), self->view); if(i == 0) { [path moveToPoint:p]; } else { [path lineToPoint:p]; } } [path closePath]; [path fill]; [NSGraphicsContext restoreGraphicsState]; [self->view setNeedsDisplay:YES]; } [pool release]; }; - (void)lineWithPoints:(MwPoint*)points color:(MwLLColor)color { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; NSGraphicsContext* ctx = [self->view context]; if(ctx) { int i; NSBezierPath* path = [NSBezierPath bezierPath]; /* whatever rect we use for coordinate flipping */ NSRect _rect = parent ? [self->view bounds] : [self->window frame]; NSColor* nscolor = [NSColor colorWithCalibratedRed:color->common.red / 255. green:color->common.green / 255. blue:color->common.blue / 255. alpha:1.0]; [NSGraphicsContext saveGraphicsState]; [NSGraphicsContext setCurrentContext:ctx]; [nscolor setFill]; for(i = 0; i < 2; i++) { NSPoint p = localPointFlip(NSMakePoint(points[i].x, points[i].y), self->view); if(i == 0) { [path moveToPoint:p]; } else { [path lineToPoint:p]; } } [path closePath]; [path stroke]; [NSGraphicsContext restoreGraphicsState]; [self->view setNeedsDisplay:YES]; } [pool release]; }; - (void)getX:(int*)x Y:(int*)y W:(unsigned int*)w H:(unsigned int*)h { NSRect frame; if(parent) { frame = [self->view frame]; } else { frame = [self->window frame]; } frame = rectFlip(frame); *x = frame.origin.x; *y = frame.origin.y; *w = frame.size.width; *h = frame.size.height; }; - (void)setX:(int)x Y:(int)y { NSRect frame; if(parent) { frame = [self->view frame]; } else { frame = [self->window frame]; } frame.origin.x = x; frame.origin.y = y; if(!parent) { frame = rectFlip(frame); [self->window setFrame:frame display:TRUE animate:TRUE]; } else { frame = localRectFlip(frame, parent->cocoa.real->view); [self->view setBounds:frame]; } // [self->view setNeedsDisplay:true]; [self nudge]; }; - (void)setW:(int)w H:(int)h { NSRect frame = [self->window frame]; frame.size.width = w; frame.size.height = h; self->rect = frame; [self->view setFrameSize:frame.size]; if(self->parent) { [self->view setFrame:frame]; } else { [self->window setFrame:frame display:YES animate:false]; } [self nudge]; }; - (int)pending { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; MwBool isPending = [self->application pending]; [NSApp runModalSession:self->modalSession]; [pool release]; return _forceRender || _eventsPending || isPending; }; - (void)getNextEvent { MwLL h = [self->handle pointer]; if(_forceRender) { MwLLDispatch(h, draw, NULL); // [self->view setNeedsDisplay:true]; _forceRender = MwFALSE; } if(_eventsPending) { MwLLDispatch(h, draw, NULL); // [self->view setNeedsDisplay:true]; _eventsPending = MwFALSE; } [self sendClipboardEvent]; if(self->pointerLocked && [self->window isMainWindow] && self->lastEvent) { struct CGPoint pos; pos.x = [window frame].origin.x + [window frame].size.width / 2; pos.y = [window frame].origin.y + [window frame].size.height / 2; CGWarpMouseCursorPosition(pos); } [self->application updateWindows]; }; - (void)sendClipboardEvent { /*NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; NSPasteboard* pasteboard = [NSPasteboard generalPasteboard]; NSArray* items = @[ @"public.utf8-plain-text", @"public.utf16-external-plain-text", @"com.apple.traditional-mac-plain-text", ]; MwLL this = self->handle.pointer; if([pasteboard canReadItemWithDataConformingToTypes:items]) { char* data = NULL; size_t size = 0; for(NSPasteboardItem* item in [pasteboard pasteboardItems]) { for(NSString* it in items) { NSString* itemData = [item stringForType:(NSString*)it]; if(itemData != NULL) { if(strHash != 0 && strHash != [itemData hash]) { char* text = malloc([itemData length]); strncpy(text, [itemData UTF8String], [itemData length]); MwLLDispatch(this, clipboard, text); printf("%s -> %p\n", text, this); free(text); } strHash = [itemData hash]; } } } } [pool release];*/ } - (void)setTitle:(const char*)title { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; [self->window setTitleWithRepresentedFilename:[NSString stringWithUTF8String:title]]; [pool release]; }; - (void)drawPixmap:(MwLLPixmap)pixmap rect:(MwRect*)_rect { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; MilskoCocoaPixmap* p = pixmap->cocoa.real; NSGraphicsContext* ctx = [self->view context]; if(ctx) { [NSGraphicsContext saveGraphicsState]; [NSGraphicsContext setCurrentContext:ctx]; [[p image] drawInRect:localRectFlip(NSMakeRect(_rect->x, _rect->y, _rect->width, _rect->height), self->view) fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1.0]; [NSGraphicsContext restoreGraphicsState]; [self->view setNeedsDisplay:YES]; } [pool release]; }; - (void)setIcon:(MwLLPixmap)pixmap { [self->application setApplicationIconImage:[pixmap->cocoa.real image]]; }; - (void)forceRender { self->_forceRender = MwTRUE; // NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; // NSEvent *event = [NSEvent otherEventWithType:NSApplicationDefined // location:NSMakePoint(0, 0) // modifierFlags:0 // timestamp:0 // windowNumber:0 // context:nil // subtype:0 // data1:0 // data2:0]; // [NSApp postEvent:event atStart:YES]; // [pool release]; }; - (void)setCursor:(MwCursor*)image mask:(MwCursor*)mask { int y, x, ys, xs; unsigned char* di = malloc(image->width * image->height * 4); memset(di, 0, image->width * image->height * 4); if(self->cursorPixmap) { [self->cursorPixmap destroy]; } self->cursorPixmap = [MilskoCocoaPixmap newWithWidth:image->width height:image->height]; xs = -mask->x + image->x; ys = MwCursorDataHeight + mask->y; ys = MwCursorDataHeight + image->y - ys; for(y = 0; y < mask->height; y++) { unsigned int d = mask->data[y]; for(x = mask->width - 1; x >= 0; x--) { int px = 0; int idx = ((y * mask->width) + x) * 4; if(d & 1) { di[idx + 3] = 255; }; d = d >> 1; } } for(y = 0; y < image->height; y++) { unsigned int d = image->data[y]; for(x = image->width - 1; x >= 0; x--) { int px = 0; int idx = ((y * image->width) + x) * 4; if(d & 1) { px = 255; }; di[idx] = px; di[idx + 1] = px; di[idx + 2] = px; d = d >> 1; } } [self->cursorPixmap updateWithData:di]; self->cursor = [[NSCursor alloc] initWithImage:[self->cursorPixmap image] hotSpot:NSMakePoint(image->x, image->y + image->height)]; [self->cursor retain]; [self->cursor pop]; [self->cursor push]; free(di); }; - (void)detachWithPoint:(MwPoint*)point { [self->window setParentWindow:NULL]; }; - (void)show:(int)show { (void)show; }; - (void)makePopupWithParent:(MwLL)_parent { (void)_parent; }; - (void)setSizeHintsWithMinX:(int)minx MinY:(int)miny MaxX:(int)maxx MaxY:(int)maxy { [self->window setMinSize:NSMakeSize(minx, miny)]; [self->window setMaxSize:NSMakeSize(maxx, maxy)]; }; - (void)makeBorderless:(int)toggle { MwU32 mask = [self->window styleMask]; if(toggle) { mask ^= NSBorderlessWindowMask; mask |= NSTitledWindowMask; } else { mask |= NSBorderlessWindowMask; mask ^= NSTitledWindowMask; } [self->window initWithContentRect:self->rect styleMask:mask backing:NSBackingStoreBuffered defer:NO]; }; - (void)focus { [self->window makeMainWindow]; }; - (void)grabPointer:(int)toggle { self->pointerLocked = toggle; }; - (void)setClipboard:(const char*)text { (void)text; // TODO: find out how to do this while supporting 10.4 // NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; // NSPasteboard* pasteboard = [NSPasteboard generalPasteboard]; // [pasteboard declareTypes:[NSArray arrayWithObjects:NSPasteboardTypeString] // owner:nil]; [pasteboard setString:[NSString stringWithUTF8String:text] // forType:NSPasteboardTypeString]; [pool release]; }; - (void)makeToolWindow { /* If my understand of what a "tool window" usually is is correct then I * highly doubt the Mac OS has this and if they did they probably outright * removed it along time ago is this kind of conflicts with modern UX. So * we'll just make it borderless idgaf */ [self makeBorderless:MwTRUE]; }; - (void)getCursorCoord:(MwPoint*)point { NSPoint p = [NSEvent mouseLocation]; point->x = p.x; point->y = p.y; }; - (void)getScreenSize:(MwRect*)_rect { NSScreen* screen = [self->window screen]; _rect->x = [screen frame].origin.x; _rect->y = [screen frame].origin.y; _rect->width = [screen frame].size.width; _rect->height = [screen frame].size.height; }; - (void)destroy { [self->handle release]; [self->window release]; } - (MwLL)getParent { return self->parent; } - (NSView*)getView { return view; } - (NSWindow*)getWindow { return window; } - (void)nudge { MwLL p = self->parent; self->_eventsPending = MwTRUE; if(p) { [p->cocoa.real->view setNeedsDisplay:true]; p = p->cocoa.real->parent; } } - (void)pushCursor { [self->cursor push]; } - (void)popCursor { [self->cursor pop]; } - (MilskoFakePointer*)getHandle { return handle; } @end @implementation MilskoCocoaApplication - (void)sendEvent:(NSEvent*)event { self->doPending = MwTRUE; [super sendEvent:event]; } - (MwBool)pending { if(self->doPending) { self->doPending = MwFALSE; return MwTRUE; } return MwFALSE; } @end @implementation MilskoCocoaView - (id)initWithFrame:(NSRect)frame { givenRect = frame; x = frame.origin.x; y = frame.origin.y; width = frame.size.width; height = frame.size.height; self = [super initWithFrame:frame]; self->space = CGColorSpaceCreateDeviceRGB(); if(width == 0 || height == 0) { self->rep = NULL; self->context = NULL; } else { [self initRepAndContextWithWidth:width Height:height]; } self->_child = MwFALSE; return self; } - (void)setChild { self->_child = MwTRUE; } - (NSGraphicsContext*)context { return self->context; } - (NSBitmapImageRep*)getRep { return self->rep; } - (void)drawRect:(NSRect)dirtyRect { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; NSArray* subviews = [self subviews]; int i; if(self->rep) { [self->rep release]; } if(dirtyRect.size.width && dirtyRect.size.height) { [self initRepAndContextWithWidth:dirtyRect.size.width Height:dirtyRect.size.height]; self->width = dirtyRect.size.width; self->height = dirtyRect.size.height; } else { [pool release]; return; } [self->rep drawInRect:[self bounds]]; [pool release]; } - (void)initRepAndContextWithWidth:(float)w Height:(float)h { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; self->rep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL pixelsWide:w pixelsHigh:h bitsPerSample:8 samplesPerPixel:4 hasAlpha:YES isPlanar:NO colorSpaceName:NSDeviceRGBColorSpace bytesPerRow:w * 4 bitsPerPixel:32]; assert(self->rep); [self->rep retain]; [self->rep setOpaque:MwFALSE]; [self->rep setAlpha:MwTRUE]; self->context = [NSGraphicsContext graphicsContextWithBitmapImageRep:self->rep]; assert(self->context); [self->context retain]; [pool release]; } - (void)destroy { CGColorSpaceRelease(self->space); [self->rep release]; [self->context release]; } - (void)setFrameSize:(NSSize)newSize { [super setFrameSize:newSize]; [self->rep setSize:newSize]; self->width = newSize.width; self->height = newSize.height; } - (BOOL)canBecomeKeyView { return YES; } - (BOOL)acceptsFirstResponder { return YES; } - (NSView*)hitTest:(NSPoint)aPoint { if(self->_child) { return NSPointInRect(aPoint, [self bounds]) ? self : nil; } else { return [super hitTest:aPoint]; } } - (void)handleKeyEvent:(NSEvent*)ev ll:(MwLL)ll down:(MwBool)isDown { int ch; enum { kVK_ANSI_A = 0x00, kVK_ANSI_S = 0x01, kVK_ANSI_D = 0x02, kVK_ANSI_F = 0x03, kVK_ANSI_H = 0x04, kVK_ANSI_G = 0x05, kVK_ANSI_Z = 0x06, kVK_ANSI_X = 0x07, kVK_ANSI_C = 0x08, kVK_ANSI_V = 0x09, kVK_ANSI_B = 0x0B, kVK_ANSI_Q = 0x0C, kVK_ANSI_W = 0x0D, kVK_ANSI_E = 0x0E, kVK_ANSI_R = 0x0F, kVK_ANSI_Y = 0x10, kVK_ANSI_T = 0x11, kVK_ANSI_1 = 0x12, kVK_ANSI_2 = 0x13, kVK_ANSI_3 = 0x14, kVK_ANSI_4 = 0x15, kVK_ANSI_6 = 0x16, kVK_ANSI_5 = 0x17, kVK_ANSI_Equal = 0x18, kVK_ANSI_9 = 0x19, kVK_ANSI_7 = 0x1A, kVK_ANSI_Minus = 0x1B, kVK_ANSI_8 = 0x1C, kVK_ANSI_0 = 0x1D, kVK_ANSI_RightBracket = 0x1E, kVK_ANSI_O = 0x1F, kVK_ANSI_U = 0x20, kVK_ANSI_LeftBracket = 0x21, kVK_ANSI_I = 0x22, kVK_ANSI_P = 0x23, kVK_ANSI_L = 0x25, kVK_ANSI_J = 0x26, kVK_ANSI_Quote = 0x27, kVK_ANSI_K = 0x28, kVK_ANSI_Semicolon = 0x29, kVK_ANSI_Backslash = 0x2A, kVK_ANSI_Comma = 0x2B, kVK_ANSI_Slash = 0x2C, kVK_ANSI_N = 0x2D, kVK_ANSI_M = 0x2E, kVK_ANSI_Period = 0x2F, kVK_ANSI_Grave = 0x32, kVK_Return = 0x24, kVK_Space = 0x31, kVK_Escape = 0x35, kVK_Shift = 0x38, kVK_Control = 0x3B, kVK_RightShift = 0x3C, kVK_RightControl = 0x3E, kVK_LeftArrow = 0x7B, kVK_RightArrow = 0x7C, kVK_DownArrow = 0x7D, kVK_UpArrow = 0x7E }; #define KEY_CASE(x, y) \ case x: \ ch = y; \ break; switch([ev keyCode]) { KEY_CASE(kVK_ANSI_A, 'a') KEY_CASE(kVK_ANSI_B, 'b') KEY_CASE(kVK_ANSI_C, 'c') KEY_CASE(kVK_ANSI_D, 'd') KEY_CASE(kVK_ANSI_E, 'e') KEY_CASE(kVK_ANSI_F, 'f') KEY_CASE(kVK_ANSI_G, 'g') KEY_CASE(kVK_ANSI_H, 'h') KEY_CASE(kVK_ANSI_I, 'i') KEY_CASE(kVK_ANSI_J, 'j') KEY_CASE(kVK_ANSI_K, 'k') KEY_CASE(kVK_ANSI_L, 'l') KEY_CASE(kVK_ANSI_M, 'm') KEY_CASE(kVK_ANSI_N, 'n') KEY_CASE(kVK_ANSI_O, 'o') KEY_CASE(kVK_ANSI_P, 'p') KEY_CASE(kVK_ANSI_Q, 'q') KEY_CASE(kVK_ANSI_R, 'r') KEY_CASE(kVK_ANSI_S, 's') KEY_CASE(kVK_ANSI_T, 't') KEY_CASE(kVK_ANSI_U, 'u') KEY_CASE(kVK_ANSI_V, 'v') KEY_CASE(kVK_ANSI_W, 'w') KEY_CASE(kVK_ANSI_X, 'x') KEY_CASE(kVK_ANSI_Y, 'y') KEY_CASE(kVK_ANSI_Z, 'z') KEY_CASE(kVK_ANSI_0, '0') KEY_CASE(kVK_ANSI_1, '1') KEY_CASE(kVK_ANSI_2, '2') KEY_CASE(kVK_ANSI_3, '3') KEY_CASE(kVK_ANSI_4, '4') KEY_CASE(kVK_ANSI_5, '5') KEY_CASE(kVK_ANSI_6, '6') KEY_CASE(kVK_ANSI_7, '7') KEY_CASE(kVK_ANSI_8, '8') KEY_CASE(kVK_ANSI_9, '9') KEY_CASE(kVK_ANSI_Quote, '\"') KEY_CASE(kVK_ANSI_Grave, '`') KEY_CASE(kVK_ANSI_Backslash, '/') KEY_CASE(kVK_ANSI_Comma, ',') KEY_CASE(kVK_ANSI_Equal, '=') KEY_CASE(kVK_Escape, MwLLKeyEscape) KEY_CASE(kVK_ANSI_LeftBracket, '[') KEY_CASE(kVK_ANSI_Minus, '-') KEY_CASE(kVK_ANSI_Period, '.') KEY_CASE(kVK_Return, MwLLKeyEnter) KEY_CASE(kVK_ANSI_RightBracket, ']') KEY_CASE(kVK_ANSI_Semicolon, ';') KEY_CASE(kVK_ANSI_Slash, '\\') KEY_CASE(kVK_Space, ' ') KEY_CASE(kVK_Control, MwLLKeyControl) KEY_CASE(kVK_RightControl, MwLLKeyControl) KEY_CASE(kVK_Shift, MwLLKeyLeftShift) KEY_CASE(kVK_RightShift, MwLLKeyRightShift) KEY_CASE(kVK_DownArrow, MwLLKeyDown) KEY_CASE(kVK_LeftArrow, MwLLKeyLeft) KEY_CASE(kVK_RightArrow, MwLLKeyRight) KEY_CASE(kVK_UpArrow, MwLLKeyUp) } if(isDown) { recursive_dispatch_key(ll, &ch); } else { recursive_dispatch_key_released(ll, &ch); } [ll->cocoa.real nudge]; } - (void)mouseEntered:(NSEvent*)ev { MwLL h = [((MilskoFakePointer*)[[self subviews] objectAtIndex:0]) pointer]; MwLLDispatch(h, focus_in, NULL); [h->cocoa.real pushCursor]; [super mouseEntered:ev]; } - (void)mouseExited:(NSEvent*)ev { MwLL h = [((MilskoFakePointer*)[[self subviews] objectAtIndex:0]) pointer]; MwLLDispatch(h, focus_out, NULL); [h->cocoa.real popCursor]; [super mouseExited:ev]; } - (void)keyDown:(NSEvent*)ev { MwLL h = [((MilskoFakePointer*)[[self subviews] objectAtIndex:0]) pointer]; [self handleKeyEvent:ev ll:h down:MwTRUE]; [super keyDown:ev]; } - (void)keyUp:(NSEvent*)ev { MwLL h = [((MilskoFakePointer*)[[self subviews] objectAtIndex:0]) pointer]; [self handleKeyEvent:ev ll:h down:MwFALSE]; [super keyUp:ev]; } - (void)mouseMoved:(NSEvent*)ev { MwLLMouse mouse; NSPoint mousePoint = pointFlip([ev locationInWindow]); MwLL this = [((MilskoFakePointer*)[[self subviews] objectAtIndex:0]) pointer]; mouse.button = MwLLMouseLeft; mouse.point.x = mousePoint.x; mouse.point.y = mousePoint.y; MwLLDispatch(this, move, &mouse); [this->cocoa.real nudge]; [super mouseMoved:ev]; } - (BOOL)mouseDownCanMoveWindow { return NO; } - (void)mouseDown:(NSEvent*)ev { MwLLMouse mouse; NSPoint mousePoint = [ev locationInWindow]; MwLL this = [((MilskoFakePointer*)[[self subviews] objectAtIndex:0]) pointer]; mousePoint.y = [[ev window] frame].size.height - mousePoint.y; mouse.button = MwLLMouseLeft; mouse.point.x = mousePoint.x; mouse.point.y = mousePoint.y; MwLLDispatch(this, down, &mouse); [this->cocoa.real nudge]; [super mouseDown:ev]; } - (void)mouseUp:(NSEvent*)ev { MwLLMouse mouse; NSPoint mousePoint = [ev locationInWindow]; MwLL this = [((MilskoFakePointer*)[[self subviews] objectAtIndex:0]) pointer]; mousePoint.y = [[ev window] frame].size.height - mousePoint.y; mouse.button = MwLLMouseLeft; mouse.point.x = mousePoint.x; mouse.point.y = mousePoint.y; MwLLDispatch(this, up, &mouse); [this->cocoa.real nudge]; [super mouseUp:ev]; } - (void)rightMouseDown:(NSEvent*)ev { MwLLMouse mouse; NSPoint mousePoint = [ev locationInWindow]; MwLL this = [((MilskoFakePointer*)[[self subviews] objectAtIndex:0]) pointer]; mousePoint.y = [[ev window] frame].size.height - mousePoint.y; mouse.button = MwLLMouseRight; mouse.point.x = mousePoint.x; mouse.point.y = mousePoint.y; MwLLDispatch(this, down, &mouse); [this->cocoa.real nudge]; [super rightMouseDown:ev]; } - (void)rightMouseUp:(NSEvent*)ev { MwLLMouse mouse; NSPoint mousePoint = [ev locationInWindow]; MwLL this = [((MilskoFakePointer*)[[self subviews] objectAtIndex:0]) pointer]; mousePoint.y = [[ev window] frame].size.height - mousePoint.y; mouse.button = MwLLMouseRight; mouse.point.x = mousePoint.x; mouse.point.y = mousePoint.y; MwLLDispatch(this, up, &mouse); [this->cocoa.real nudge]; [super rightMouseUp:ev]; } @end @implementation MilskoCocoaApplicationDelegate - (MilskoCocoaApplicationDelegate*)initWithAppl:(NSApplication*)_appl { self->appl = _appl; return self; } - (void)applicationDidBecomeActive:(NSNotification*)notification { [self->appl activateIgnoringOtherApps:true]; // printf("test\n"); } - (void)applicationWillFinishLaunching:(NSNotification*)notification { // printf("test\n"); // [self->appl activateIgnoringOtherApps:MwTRUE]; } - (void)applicationDidFinishLaunching:(NSNotification*)notification { // [self->appl activateIgnoringOtherApps:MwTRUE]; } @end @implementation MilskoCocoaWindowDelegate - (NSSize)windowWillResize:(NSWindow*)win toSize:(NSSize)frameSize; { if([[[win contentView] subviews] count] >= 1) { NSView* ptr = [[[win contentView] subviews] objectAtIndex:0]; if([ptr isKindOfClass:[MilskoFakePointer class]]) { MwLL h = [(MilskoFakePointer*)ptr pointer]; MwLLDispatch(h, resize, NULL); // MwLLDispatch(h, draw, NULL); } } return frameSize; } - (void)windowDidBecomeMain:(NSNotification*)notification { if([[[w contentView] subviews] count] != 0) { MwLL h = [((MilskoFakePointer*)[[[w contentView] subviews] objectAtIndex:0]) pointer]; MwLLDispatch(h, focus_in, NULL); } [self->w makeKeyAndOrderFront:nil]; } - (void)windowDidResize:(NSNotification*)notification { (void)notification; } // This will close/terminate the application when the main window is closed. - (void)windowWillClose:(NSNotification*)notification { (void)notification; // MilskoCocoa *window = notification.object; // MwLL handle = [window getHandle].pointer; // MwLLDispatch(handle, close, NULL); [NSApp terminate:nil]; } - (MilskoCocoaWindowDelegate*)initWithWin:(NSWindow*)win { self->w = win; return self; } @end @implementation MilskoFakePointer - (void)setPointer:(void*)pointer { [self setFrame:*(NSRect*)&pointer]; self->ptr = pointer; }; - (void*)pointer { return self->ptr; }; - (void)drawRect:(NSRect)dirtyRect { /* explicitly do nothing */ (void)dirtyRect; } - (void)destroy { } @end @implementation MilskoCocoaWindow - (BOOL)canBecomeKeyWindow { return true; } - (BOOL)canBecomeMainWindow { return true; } @end static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { MwLL r; r = malloc(sizeof(*r)); MwLLCreateCommon(r); MilskoCocoa* o = [MilskoCocoa newWithParent:parent x:x y:y width:width height:height handle:r]; r->cocoa.real = o; return r; } static void MwLLDestroyImpl(MwLL handle) { MilskoCocoa* h = handle->cocoa.real; [h destroy]; MwLLDestroyCommon(handle); free(handle); } static void MwLLBeginDrawImpl(MwLL handle) { (void)handle; } static void MwLLEndDrawImpl(MwLL handle) { (void)handle; } static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, MwLLColor color) { MilskoCocoa* h = handle->cocoa.real; [h polygonWithPoints:points points_count:points_count color:color]; } static void MwLLLineImpl(MwLL handle, MwPoint* points, MwLLColor color) { MilskoCocoa* h = handle->cocoa.real; [h lineWithPoints:points color:color]; } static MwLLColor MwLLAllocColorImpl(MwLL handle, int r, int g, int b) { MwLLColor c = malloc(sizeof(*c)); MwLLColorUpdate(handle, c, r, g, b); return c; } static void MwLLColorUpdateImpl(MwLL handle, MwLLColor c, int r, int g, int b) { (void)handle; c->common.red = r; c->common.green = g; c->common.blue = b; } static void MwLLGetXYWHImpl(MwLL handle, int* x, int* y, unsigned int* w, unsigned int* height) { MilskoCocoa* h = handle->cocoa.real; [h getX:x Y:y W:w H:height]; } static void MwLLSetXYImpl(MwLL handle, int x, int y) { MilskoCocoa* h = handle->cocoa.real; [h setX:x Y:y]; } static void MwLLSetWHImpl(MwLL handle, int w, int height) { MilskoCocoa* h = handle->cocoa.real; [h setW:w H:height]; } static void MwLLFreeColorImpl(MwLLColor color) { free(color); } static int MwLLPendingImpl(MwLL handle) { return [handle->cocoa.real pending]; } static void MwLLNextEventImpl(MwLL handle) { MilskoCocoa* h = handle->cocoa.real; [h getNextEvent]; } static void MwLLSetTitleImpl(MwLL handle, const char* title) { MilskoCocoa* h = handle->cocoa.real; [h setTitle:title]; } static MwLLPixmap MwLLCreatePixmapImpl(MwLL handle, unsigned char* data, int width, int height) { (void)handle; MwLLPixmap r = malloc(sizeof(*r)); memset(r, 0, sizeof(*r)); r->common.raw = malloc(4 * width * height); memcpy(r->common.raw, data, 4 * width * height); r->common.width = width; r->common.height = height; r->cocoa.real = [MilskoCocoaPixmap newWithWidth:width height:height]; MwLLPixmapUpdate(r); return r; } static void MwLLPixmapUpdateImpl(MwLLPixmap pixmap) { MilskoCocoaPixmap* p = pixmap->cocoa.real; [p updateWithData:pixmap->common.raw]; } static void MwLLDestroyPixmapImpl(MwLLPixmap pixmap) { MilskoCocoaPixmap* p = pixmap->cocoa.real; [p destroy]; [p release]; free(pixmap); } static void MwLLDrawPixmapImpl(MwLL handle, MwRect* rect, MwLLPixmap pixmap) { MilskoCocoa* h = handle->cocoa.real; [h drawPixmap:pixmap rect:rect]; MwLLForceRender(handle); } static void MwLLSetIconImpl(MwLL handle, MwLLPixmap pixmap) { MilskoCocoa* h = handle->cocoa.real; [h setIcon:pixmap]; } static void MwLLForceRenderImpl(MwLL handle) { MilskoCocoa* h = handle->cocoa.real; [h forceRender]; } static void MwLLSetCursorImpl(MwLL handle, MwCursor* image, MwCursor* mask) { MilskoCocoa* h = handle->cocoa.real; [h setCursor:image mask:mask]; } static void MwLLDetachImpl(MwLL handle, MwPoint* point) { MilskoCocoa* h = handle->cocoa.real; [h detachWithPoint:point]; } static void MwLLShowImpl(MwLL handle, int show) { MilskoCocoa* h = handle->cocoa.real; [h show:show]; } static void MwLLMakePopupImpl(MwLL handle, MwLL parent) { MilskoCocoa* h = handle->cocoa.real; [h makePopupWithParent:parent]; } static void MwLLSetSizeHintsImpl(MwLL handle, int minx, int miny, int maxx, int maxy) { MilskoCocoa* h = handle->cocoa.real; [h setSizeHintsWithMinX:minx MinY:miny MaxX:maxx MaxY:maxy]; } static void MwLLMakeBorderlessImpl(MwLL handle, int toggle) { MilskoCocoa* h = handle->cocoa.real; [h makeBorderless:toggle]; } static void MwLLFocusImpl(MwLL handle) { MilskoCocoa* h = handle->cocoa.real; [h focus]; } static void MwLLGrabPointerImpl(MwLL handle, int toggle) { MilskoCocoa* h = handle->cocoa.real; [h grabPointer:toggle]; } static void MwLLSetClipboardImpl(MwLL handle, const char* text) { MilskoCocoa* h = handle->cocoa.real; [h setClipboard:text]; } static void MwLLGetClipboardImpl(MwLL handle) { (void)handle; } static void MwLLMakeToolWindowImpl(MwLL handle) { MilskoCocoa* h = handle->cocoa.real; [h makeToolWindow]; } static void MwLLGetCursorCoordImpl(MwLL handle, MwPoint* point) { MilskoCocoa* h = handle->cocoa.real; [h getCursorCoord:point]; } static void MwLLGetScreenSizeImpl(MwLL handle, MwRect* rect) { MilskoCocoa* h = handle->cocoa.real; [h getScreenSize:rect]; } static void MwLLBeginStateChangeImpl(MwLL handle) { MwLLShow(handle, 0); } static void MwLLEndStateChangeImpl(MwLL handle) { MwLLShow(handle, 1); } static int MwLLCocoaCallInitImpl(void) { return 0; } #include "call.c" CALL(Cocoa);