1 #include <Cocoa/Cocoa.h>
4 #define CAML_NAME_SPACE
7 #include <sys/socket.h>
11 #include <caml/mlvalues.h>
12 #include <caml/memory.h>
13 #include <caml/callback.h>
14 #include <caml/alloc.h>
15 #include <caml/fail.h>
40 static int terminating = 0;
41 static pthread_mutex_t terminate_mutex = PTHREAD_MUTEX_INITIALIZER;
42 static int server_fd = -1;
43 static CGFloat backing_scale_factor = -1.0;
45 #if __MAC_OS_X_VERSION_MAX_ALLOWED >= 10120
47 #define NS_CRITICAL_ALERT_STYLE NSAlertStyleCritical
48 #define NS_FULL_SCREEN_WINDOW_MASK NSWindowStyleMaskFullScreen
49 #define NS_DEVICE_INDEPENDENT_MODIFIER_FLAGS_MASK NSEventModifierFlagDeviceIndependentFlagsMask
50 #define NS_FUNCTION_KEY_MASK NSEventModifierFlagFunction
51 #define NS_ALTERNATE_KEY_MASK NSEventModifierFlagOption
52 #define NS_COMMAND_KEY_MASK NSEventModifierFlagCommand
53 #define NS_CLOSABLE_WINDOW_MASK NSWindowStyleMaskClosable
54 #define NS_MINIATURIZABLE_WINDOW_MASK NSWindowStyleMaskMiniaturizable
55 #define NS_TITLED_WINDOW_MASK NSWindowStyleMaskTitled
56 #define NS_RESIZABLE_WINDOW_MASK NSWindowStyleMaskResizable
60 #define NS_CRITICAL_ALERT_STYLE NSCriticalAlertStyle
61 #define NS_FULL_SCREEN_WINDOW_MASK NSFullScreenWindowMask
62 #define NS_DEVICE_INDEPENDENT_MODIFIER_FLAGS_MASK NSDeviceIndependentModifierFlagsMask
63 #define NS_FUNCTION_KEY_MASK NSFunctionKeyMask
64 #define NS_ALTERNATE_KEY_MASK NSAlternateKeyMask
65 #define NS_COMMAND_KEY_MASK NSCommandKeyMask
66 #define NS_CLOSABLE_WINDOW_MASK NSClosableWindowMask
67 #define NS_MINIATURIZABLE_WINDOW_MASK NSMiniaturizableWindowMask
68 #define NS_TITLED_WINDOW_MASK NSTitledWindowMask
69 #define NS_RESIZABLE_WINDOW_MASK NSResizableWindowMask
73 void Abort (NSString *format, ...)
76 va_start (argList, format);
77 NSString *str = [[NSString alloc] initWithFormat:format arguments:argList];
80 NSAlert *alert = [[NSAlert alloc] init];
81 [alert addButtonWithTitle:@"Quit"];
82 [alert setMessageText:@"Internal Error"];
83 [alert setInformativeText:str];
84 [alert setAlertStyle:NS_CRITICAL_ALERT_STYLE];
86 [NSApp terminate:nil];
89 void *caml_main_thread (void *argv)
93 pthread_mutex_lock (&terminate_mutex);
94 if (terminating == 0) {
96 [NSApp performSelectorOnMainThread:@selector(terminate:)
100 pthread_mutex_unlock (&terminate_mutex);
105 NSCursor *GetCursor (int idx)
107 static NSCursor *cursors[5];
108 static BOOL initialised = NO;
110 if (initialised == NO) {
111 cursors[0] = [NSCursor arrowCursor];
112 cursors[1] = [NSCursor pointingHandCursor];
113 cursors[2] = [NSCursor arrowCursor];
114 cursors[3] = [NSCursor closedHandCursor];
115 cursors[4] = [NSCursor IBeamCursor];
122 @implementation NSWindow (CategoryNSWindow)
126 return ([self styleMask] & NS_FULL_SCREEN_WINDOW_MASK) == NS_FULL_SCREEN_WINDOW_MASK;
131 @implementation NSView (CategoryNSView)
133 - (NSPoint)locationFromEvent:(NSEvent *)event
136 [self convertPointToBacking:[self convertPoint:[event locationInWindow] fromView:nil]];
137 NSRect bounds = [self convertRectToBacking:[self bounds]];
138 point.y = bounds.size.height - point.y;
142 - (NSRect)convertFrameToBacking
144 return [self convertRectToBacking:[self frame]];
149 @implementation NSEvent (CategoryNSEvent)
151 - (int)deviceIndependentModifierFlags
153 return [self modifierFlags] & NS_DEVICE_INDEPENDENT_MODIFIER_FLAGS_MASK;
158 @interface Connector : NSObject
160 - (instancetype)initWithFileDescriptor:(int)fd;
162 - (void)notifyReshapeWidth:(int)w height:(int)h;
163 - (void)notifyExpose;
164 - (void)keyDown:(uint32_t)key modifierFlags:(NSEventModifierFlags)mask;
166 - (void)mouseEntered:(NSPoint)loc;
168 - (void)mouseMoved:(NSPoint)aPoint modifierFlags:(NSEventModifierFlags)flags;
169 - (void)mouseDown:(NSUInteger)buttons atPoint:(NSPoint)aPoint modifierFlags:(NSEventModifierFlags)flags;
170 - (void)mouseUp:(NSUInteger)buttons atPoint:(NSPoint)aPoint modifierFlags:(NSEventModifierFlags)flags;
173 @implementation Connector
176 NSFileHandle *fileHandle;
179 - (instancetype)initWithFileDescriptor:(int)fd
182 data = [NSMutableData dataWithLength:32];
183 fileHandle = [[NSFileHandle alloc] initWithFileDescriptor:fd];
187 - (void)setByte:(int8_t)b offset:(int)off
189 [data replaceBytesInRange:NSMakeRange (off, 1) withBytes:&b];
192 - (void)setShort:(int16_t)s offset:(int)off
194 [data replaceBytesInRange:NSMakeRange (off, 2) withBytes:&s];
197 - (void)setInt:(int32_t)n offset:(int)off
199 [data replaceBytesInRange:NSMakeRange (off, 4) withBytes:&n];
204 [fileHandle writeData:data];
207 - (void)notifyReshapeWidth:(int)w height:(int)h
209 [self setByte:EVENT_RESHAPE offset:0];
210 [self setShort:w offset:16];
211 [self setShort:h offset:18];
217 [self setByte:EVENT_EXPOSE offset:0];
221 - (void)keyDown:(uint32_t)key modifierFlags:(NSEventModifierFlags)mask
223 [self setByte:EVENT_KEYDOWN offset:0];
224 [self setInt:key offset:16];
225 [self setInt:mask offset:20];
229 - (void)notifyWinstate:(BOOL)fullScreen
231 [self setByte:EVENT_WINSTATE offset:0];
232 [self setInt:fullScreen offset:16];
238 [self setByte:EVENT_QUIT offset:0];
242 - (void)mouseEntered:(NSPoint)loc
244 [self setByte:EVENT_ENTER offset:0];
245 [self setShort:loc.x offset:16];
246 [self setShort:loc.y offset:20];
252 [self setByte:EVENT_LEAVE offset:0];
256 - (void)mouseDragged:(NSPoint)aPoint modifierFlags:(NSEventModifierFlags)flags
258 [self setByte:EVENT_MOTION offset:0];
259 [self setShort:aPoint.x offset:16];
260 [self setShort:aPoint.y offset:20];
261 [self setInt:flags offset:24];
265 - (void)mouseMoved:(NSPoint)aPoint modifierFlags:(NSEventModifierFlags)flags
267 [self setByte:EVENT_PMOTION offset:0];
268 [self setShort:aPoint.x offset:16];
269 [self setShort:aPoint.y offset:20];
270 [self setInt:flags offset:24];
274 - (void)mouseDown:(NSUInteger)buttons atPoint:(NSPoint)aPoint modifierFlags:(NSEventModifierFlags)flags
276 [self setByte:EVENT_MOUSE offset:0];
277 [self setShort:1 offset:10];
278 [self setInt:buttons offset:12];
279 [self setShort:aPoint.x offset:16];
280 [self setShort:aPoint.y offset:20];
281 [self setInt:flags offset:24];
285 - (void)mouseUp:(NSUInteger)buttons atPoint:(NSPoint)aPoint modifierFlags:(NSEventModifierFlags)flags
287 [self setByte:EVENT_MOUSE offset:0];
288 [self setShort:0 offset:10];
289 [self setInt:buttons offset:12];
290 [self setShort:aPoint.x offset:16];
291 [self setShort:aPoint.y offset:20];
292 [self setInt:flags offset:24];
296 - (void)scrollByDeltaX:(CGFloat)deltaX deltaY:(CGFloat)deltaY
298 [self setByte:EVENT_SCROLL offset:0];
299 [self setInt:(int32_t) deltaX offset:16];
300 [self setInt:(int32_t) deltaY offset:20];
304 - (void)zoom:(CGFloat)z at:(NSPoint)p
306 [self setByte:EVENT_ZOOM offset:0];
307 [self setInt:(int32_t) (z * 1000) offset:16];
308 [self setShort:p.x offset:20];
309 [self setShort:p.y offset:22];
313 - (void)openFile:(NSString *)filename
315 const char *utf8 = [filename UTF8String];
316 unsigned len = [filename lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
317 [self setByte:EVENT_OPEN offset:0];
319 unsigned data_len = [data length] - 4;
321 unsigned chunk_len = MIN (data_len - 4, len - off);
322 [self setShort:chunk_len offset:2];
323 [data replaceBytesInRange:NSMakeRange (4, chunk_len) withBytes:(utf8 + off)];
327 [self setShort:0 offset:2];
333 @interface MyDelegate : NSObject <NSApplicationDelegate, NSWindowDelegate>
338 - (void)applicationWillFinishLaunching:(NSNotification *)not;
339 - (void)applicationDidFinishLaunching:(NSNotification *)not;
340 - (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication;
341 - (void)makeCurrentContext;
345 @interface MyWindow : NSWindow
349 @interface MyView : NSOpenGLView
351 Connector *connector;
355 - (instancetype)initWithFrame:(NSRect)frame connector:(Connector *)aConnector;
356 - (void)setCursor:(NSCursor *)aCursor;
360 @implementation MyView
362 - (instancetype)initWithFrame:(NSRect)frame connector:(Connector *)aConnector
364 NSOpenGLPixelFormatAttribute attrs[] =
366 NSOpenGLPFAAccelerated,
367 NSOpenGLPFADoubleBuffer,
368 NSOpenGLPFAColorSize, 24,
369 NSOpenGLPFAAlphaSize, 8,
370 NSOpenGLPFADepthSize, 24,
373 NSOpenGLPixelFormat *pixFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs];
374 self = [super initWithFrame:frame pixelFormat:pixFormat];
377 connector = aConnector;
378 cursor = [NSCursor arrowCursor];
379 self.allowedTouchTypes = NSTouchTypeMaskDirect | NSTouchTypeMaskIndirect;
380 [self setWantsBestResolutionOpenGLSurface:YES];
386 - (void)setCursor:(NSCursor *)aCursor
391 -(void)resetCursorRects
393 [self addCursorRect:[self bounds] cursor:cursor];
396 - (void)drawRect:(NSRect)bounds
398 // NSLog(@"drawRect: %@", [NSValue valueWithRect:bounds]);
399 [connector notifyExpose];
402 - (void)viewWillMoveToWindow:(NSWindow *)newWindow {
403 NSTrackingArea* trackingArea = [[NSTrackingArea alloc]
404 initWithRect:[self bounds]
405 options:(NSTrackingMouseEnteredAndExited | NSTrackingActiveInActiveApp | NSTrackingInVisibleRect)
408 [self addTrackingArea:trackingArea];
411 - (void)keyDown:(NSEvent *)event
413 // int key = [event keyCode];
414 NSEventModifierFlags mask = [event deviceIndependentModifierFlags];
415 NSString *chars = [event charactersIgnoringModifiers];
416 const uint32_t *c = (uint32_t *) [chars cStringUsingEncoding:NSUTF32LittleEndianStringEncoding];
418 if (*c == 0x7f && !(mask & NS_FUNCTION_KEY_MASK)) {
419 [connector keyDown:0x8 modifierFlags:mask];
421 [connector keyDown:*c modifierFlags:mask];
427 - (void)flagsChanged:(NSEvent *)event
429 NSEventModifierFlags mask = [event deviceIndependentModifierFlags];
430 //NSLog (@"flagsChanged: 0x%lx", mask);
432 [connector keyDown:0 modifierFlags:mask];
436 - (void)mouseDown:(NSEvent *)event
438 [connector mouseDown:BUTTON_LEFT
439 atPoint:[self locationFromEvent:event]
440 modifierFlags:[event deviceIndependentModifierFlags]];
443 - (void)mouseUp:(NSEvent *)event
445 [connector mouseUp:BUTTON_LEFT
446 atPoint:[self locationFromEvent:event]
447 modifierFlags:[event deviceIndependentModifierFlags]];
450 - (void)rightMouseDown:(NSEvent *)event
452 [connector mouseDown:BUTTON_RIGHT
453 atPoint:[self locationFromEvent:event]
454 modifierFlags:[event deviceIndependentModifierFlags]];
457 - (void)rightMouseUp:(NSEvent *)event
459 [connector mouseUp:BUTTON_RIGHT
460 atPoint:[self locationFromEvent:event]
461 modifierFlags:[event deviceIndependentModifierFlags]];
464 - (void)rightMouseDragged:(NSEvent *)event
466 [connector mouseDragged:[self locationFromEvent:event]
467 modifierFlags:[event deviceIndependentModifierFlags]];
470 - (void)mouseDragged:(NSEvent *)event
472 [connector mouseDragged:[self locationFromEvent:event]
473 modifierFlags:[event deviceIndependentModifierFlags]];
476 - (void)mouseMoved:(NSEvent *)event
478 [connector mouseMoved:[self locationFromEvent:event]
479 modifierFlags:[event deviceIndependentModifierFlags]];
482 - (void)mouseEntered:(NSEvent *)event
484 [connector mouseEntered:[self locationFromEvent:event]];
487 - (void)mouseExited:(NSEvent *)event
489 [connector mouseExited];
492 - (void)scrollWheel:(NSEvent *)event
494 CGFloat deltaX = [event scrollingDeltaX];
495 CGFloat deltaY = -[event scrollingDeltaY];
497 if ([event hasPreciseScrollingDeltas]) {
498 [connector scrollByDeltaX:(backing_scale_factor * deltaX)
499 deltaY:(backing_scale_factor * deltaY)];
501 NSPoint loc = [self locationFromEvent:event];
502 NSEventModifierFlags mask = [event deviceIndependentModifierFlags];
504 [connector mouseDown:BUTTON_WHEEL_DOWN atPoint:loc modifierFlags:mask];
505 [connector mouseUp:BUTTON_WHEEL_DOWN atPoint:loc modifierFlags:mask];
506 } else if (deltaY < 0.0) {
507 [connector mouseDown:BUTTON_WHEEL_UP atPoint:loc modifierFlags:mask];
508 [connector mouseUp:BUTTON_WHEEL_UP atPoint:loc modifierFlags:mask];
513 - (void)magnifyWithEvent:(NSEvent *)event
515 [connector zoom:[event magnification] at:[self locationFromEvent:event]];
520 @implementation MyWindow
522 - (BOOL)canBecomeKeyWindow
529 @implementation MyDelegate
533 NSOpenGLContext *glContext;
535 Connector *connector;
538 - (instancetype)initWithArgv:(char **)theArgv fileDescriptor:(int)fd
543 connector = [[Connector alloc] initWithFileDescriptor:fd];
548 - (void)setTitle:(NSString *)title
550 [window setTitle:title];
555 [window makeKeyAndOrderFront:self];
560 return [[window contentView] convertFrameToBacking].size.width;
565 return [[window contentView] convertFrameToBacking].size.height;
568 - (void)applicationWillFinishLaunching:(NSNotification *)not
570 NSLog(@"applicationWillFinishLaunching");
571 id menubar = [NSMenu new];
572 id appMenuItem = [NSMenuItem new];
573 id fileMenuItem = [NSMenuItem new];
574 id windowMenuItem = [NSMenuItem new];
575 id helpMenuItem = [NSMenuItem new];
576 [menubar addItem:appMenuItem];
577 [menubar addItem:fileMenuItem];
578 [menubar addItem:windowMenuItem];
579 [menubar addItem:helpMenuItem];
580 [NSApp setMainMenu:menubar];
581 id appMenu = [NSMenu new];
582 id appName = [[NSProcessInfo processInfo] processName];
583 id aboutMenuItem = [[NSMenuItem alloc] initWithTitle:[@"About " stringByAppendingString:appName]
584 action:@selector(orderFrontStandardAboutPanel:)
586 id hideMenuItem = [[NSMenuItem alloc] initWithTitle:[@"Hide " stringByAppendingString:appName]
587 action:@selector(hide:)
589 id hideOthersMenuItem = [[NSMenuItem alloc] initWithTitle:@"Hide Others"
590 action:@selector(hideOtherApplications:)
592 [hideOthersMenuItem setKeyEquivalentModifierMask:(NS_ALTERNATE_KEY_MASK | NS_COMMAND_KEY_MASK)];
593 id showAllMenuItem = [[NSMenuItem alloc] initWithTitle:@"Show All"
594 action:@selector(unhideAllApplications:)
596 id quitMenuItem = [[NSMenuItem alloc] initWithTitle:[@"Quit " stringByAppendingString:appName]
597 action:@selector(terminate:)
599 [appMenu addItem:aboutMenuItem];
600 [appMenu addItem:[NSMenuItem separatorItem]];
601 [appMenu addItem:hideMenuItem];
602 [appMenu addItem:hideOthersMenuItem];
603 [appMenu addItem:showAllMenuItem];
604 [appMenu addItem:[NSMenuItem separatorItem]];
605 [appMenu addItem:quitMenuItem];
606 [appMenuItem setSubmenu:appMenu];
608 id fileMenu = [[NSMenu alloc] initWithTitle:@"File"];
609 id openMenuItem = [[NSMenuItem alloc] initWithTitle:@"Open..."
610 action:@selector(openDocument:)
612 id closeMenuItem = [[NSMenuItem alloc] initWithTitle:@"Close"
613 action:@selector(performClose:)
615 [fileMenu addItem:openMenuItem];
616 [fileMenu addItem:[NSMenuItem separatorItem]];
617 [fileMenu addItem:closeMenuItem];
618 [fileMenuItem setSubmenu:fileMenu];
620 id windowMenu = [[NSMenu alloc] initWithTitle:@"Window"];
621 id miniaturizeMenuItem = [[NSMenuItem alloc] initWithTitle:@"Minimize"
622 action:@selector(performMiniaturize:)
624 id zoomMenuItem = [[NSMenuItem alloc] initWithTitle:@"Zoom"
625 action:@selector(performZoom:)
628 [windowMenu addItem:miniaturizeMenuItem];
629 [windowMenu addItem:zoomMenuItem];
630 [windowMenuItem setSubmenu:windowMenu];
632 id helpMenu = [[NSMenu alloc] initWithTitle:@"Help"];
633 id reportIssueMenuItem = [[NSMenuItem alloc] initWithTitle:@"Report an issue..."
634 action:@selector(reportIssue:)
636 [helpMenu addItem:reportIssueMenuItem];
637 [helpMenuItem setSubmenu:helpMenu];
639 window = [[MyWindow alloc] initWithContentRect:NSMakeRect(0, 0, 400, 400)
640 styleMask:(NS_CLOSABLE_WINDOW_MASK | NS_MINIATURIZABLE_WINDOW_MASK | NS_TITLED_WINDOW_MASK | NS_RESIZABLE_WINDOW_MASK)
641 backing:NSBackingStoreBuffered
645 [window setAcceptsMouseMovedEvents:YES];
646 [window setDelegate:self];
649 [[NSNotificationCenter defaultCenter] addObserver:self
650 selector:@selector(didEnterFullScreen)
651 name:NSWindowDidEnterFullScreenNotification
653 [[NSNotificationCenter defaultCenter] addObserver:self
654 selector:@selector(didExitFullScreen)
655 name:NSWindowDidExitFullScreenNotification
658 MyView *myView = [[MyView alloc] initWithFrame:[[window contentView] bounds]
659 connector:connector];
661 [window setContentView:myView];
662 [window makeFirstResponder:myView];
664 glContext = [myView openGLContext];
666 [glContext setValues:&swapInt forParameter:NSOpenGLContextParameterSwapInterval];
668 backing_scale_factor = [window backingScaleFactor];
671 - (void)reshape:(NSValue *)val
673 // NSLog (@"reshape: %@ isFullScreen: %d", val, [window isFullScreen]);
674 if ([window isFullScreen]) {
675 [window toggleFullScreen:self];
677 [window setFrame:[window frameRectForContentRect:[val rectValue]]
681 - (void)makeCurrentContext
683 [glContext makeCurrentContext];
684 NSLog (@"OpenGL Version: %s", glGetString(GL_VERSION));
689 [glContext flushBuffer];
692 - (void)didEnterFullScreen
694 // NSLog (@"didEnterFullScreen: %d", [window isFullScreen]);
695 [connector notifyWinstate:YES];
698 - (void)didExitFullScreen
700 // NSLog (@"didExitFullScreen: %d", [window isFullScreen]);
701 [connector notifyWinstate:NO];
706 // NSLog (@"fullscreen: %d", [window isFullScreen]);
707 if ([window isFullScreen] == NO) {
708 [window toggleFullScreen:self];
712 - (void)setCursor:(NSCursor *)aCursor
714 [[window contentView] setCursor: aCursor];
715 [window invalidateCursorRectsForView:[window contentView]];
718 - (void)windowDidResize:(NSNotification *)notification
720 NSRect frame = [[window contentView] convertFrameToBacking];
721 [connector notifyReshapeWidth:frame.size.width height:frame.size.height];
724 - (void)applicationWillTerminate:(NSDictionary *)userInfo
726 pthread_mutex_lock (&terminate_mutex);
727 if (terminating == 0) {
729 [connector notifyQuit];
731 pthread_mutex_unlock (&terminate_mutex);
732 pthread_join (thread, NULL);
735 - (void)windowDidChangeOcclusionState:(NSNotification *)notification
739 - (void)applicationDidFinishLaunching:(NSNotification *)not
741 NSLog(@"applicationDidFinishLaunching");
742 int ret = pthread_create (&thread, NULL, caml_main_thread, argv);
744 Abort (@"pthread_create: %s.", strerror (ret));
748 - (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication
753 - (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename
755 NSLog (@"openFile: %@", filename);
756 [connector openFile:filename];
760 - (void)openDocument:(id)sender
762 NSOpenPanel *openPanel = [NSOpenPanel openPanel];
763 [openPanel beginSheetModalForWindow:window
764 completionHandler:^(NSInteger result){
765 if (result == NSModalResponseOK) {
766 NSString *filename = [[[openPanel URLs] objectAtIndex:0] path];
767 if (filename != nil) {
768 [self application:NSApp openFile:filename];
774 - (void)reportIssue:(id)sender
776 [[NSWorkspace sharedWorkspace]
777 openURL:[NSURL URLWithString:@"https://github.com/moosotc/llpp/issues"]];
782 CAMLprim value ml_mapwin (value unit)
785 [(MyDelegate *)[NSApp delegate] performSelectorOnMainThread:@selector(mapwin)
788 CAMLreturn (Val_unit);
791 CAMLprim value ml_swapb (value unit)
794 [(MyDelegate *)[NSApp delegate] swapb];
795 CAMLreturn (Val_unit);
798 CAMLprim value ml_getw (value unit)
800 return Val_int([(MyDelegate *)[NSApp delegate] getw]);
803 CAMLprim value ml_geth (value unit)
805 return Val_int([(MyDelegate *)[NSApp delegate] geth]);
808 CAMLprim value ml_makecurrentcontext (value unit)
811 [(MyDelegate *)[NSApp delegate] makeCurrentContext];
812 CAMLreturn (Val_unit);
815 CAMLprim value ml_settitle (value title)
818 NSString *str = [NSString stringWithUTF8String:String_val(title)];
819 [(MyDelegate *)[NSApp delegate] performSelectorOnMainThread:@selector(setTitle:)
822 CAMLreturn (Val_unit);
825 CAMLprim value ml_reshape (value w, value h)
828 NSRect r = NSMakeRect (0, 0, Int_val (w), Int_val (h));
829 [(MyDelegate *)[NSApp delegate] performSelectorOnMainThread:@selector(reshape:)
830 withObject:[NSValue valueWithRect:r]
832 CAMLreturn (Val_unit);
835 CAMLprim value ml_fullscreen (value unit)
838 [(MyDelegate *)[NSApp delegate] performSelectorOnMainThread:@selector(fullscreen)
841 CAMLreturn (Val_unit);
844 CAMLprim value ml_setcursor (value curs)
847 // NSLog (@"ml_setcursor: %d", Int_val (curs));
848 NSCursor *cursor = GetCursor (Int_val (curs));
849 [(MyDelegate *)[NSApp delegate] performSelectorOnMainThread:@selector(setCursor:)
852 CAMLreturn (Val_unit);
855 CAMLprim value ml_get_server_fd (value unit)
858 CAMLreturn (Val_int (server_fd));
861 CAMLprim value ml_get_backing_scale_factor (value unit)
864 CAMLreturn (Val_int ((int) backing_scale_factor));
867 CAMLprim value ml_nslog (value str)
870 NSLog (@"%s", String_val (str));
871 CAMLreturn (Val_unit);
874 // HACK to eliminate arg injected by OS X -psn_...
875 int adjust_argv (int argc, char **argv)
877 if (argc > 1 && strncmp (argv[1], "-psn", 4) == 0) {
878 for (unsigned i = 1; i < argc - 1; i ++) {
883 for (int i = 0; i < argc; i ++) {
884 NSLog (@"arg %d: %s", i, argv[i]);
889 void (*wsigladdr (const char *name)) (void)
891 static CFBundleRef framework = NULL;
892 if (framework == NULL)
893 framework = CFBundleGetBundleWithIdentifier (CFSTR ("com.apple.opengl"));
897 size_t namelenp1 = strlen (name) + 1;
898 bytes = CFAllocatorAllocate (CFAllocatorGetDefault(), namelenp1, 0);
899 memcpy (bytes, name, namelenp1);
900 str = CFStringCreateWithCStringNoCopy (NULL, bytes,
901 kCFStringEncodingMacRoman, NULL);
902 void (*ret) (void) = CFBundleGetFunctionPointerForName (framework, str);
907 int main(int argc, char **argv)
911 int ret = socketpair (AF_UNIX, SOCK_STREAM, 0, sv);
913 Abort (@"socketpair: %s", strerror (errno));
915 // NSLog (@"socketpair sv0 %d sv1 %d", sv[0], sv[1]);
917 argc = adjust_argv (argc, argv);
918 [NSApplication sharedApplication];
919 [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
920 id delegate = [[MyDelegate alloc] initWithArgv:argv fileDescriptor:sv[1]];
921 [NSApp setDelegate:delegate];
922 [NSApp activateIgnoringOtherApps:YES];