AppDelegate.m 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  1. //
  2. // AppDelegate.m
  3. // RootlessForEmulators
  4. //
  5. // Created by Uli Kusterer on 08/03/15.
  6. // Copyright (c) 2015 Uli Kusterer. All rights reserved.
  7. //
  8. #import "AppDelegate.h"
  9. #import "RootlessForEmulators.h"
  10. @interface AppDelegate ()
  11. @property (nonatomic, strong) NSImage* backBuffer;
  12. @property (strong) NSMutableArray* windows;
  13. @property (strong) NSMutableArray* events;
  14. @end
  15. @interface RootlessWindowContentView : NSView
  16. @end
  17. @implementation RootlessWindowContentView
  18. -(void) drawRect:(NSRect)dirtyRect
  19. {
  20. NSImage *bb = [(id)NSApplication.sharedApplication.delegate backBuffer];
  21. NSRect myBox = [self.window contentRectForFrameRect: self.window.frame];
  22. [bb drawAtPoint: NSZeroPoint fromRect: myBox operation: NSCompositeCopy fraction: 1.0];
  23. }
  24. -(void) mouseDown:(NSEvent *)theEvent
  25. {
  26. [(id)NSApplication.sharedApplication.delegate addEvent: theEvent];
  27. }
  28. -(void) mouseDragged:(NSEvent *)theEvent
  29. {
  30. [(id)NSApplication.sharedApplication.delegate addEvent: theEvent];
  31. }
  32. -(void) mouseUp:(NSEvent *)theEvent
  33. {
  34. [(id)NSApplication.sharedApplication.delegate addEvent: theEvent];
  35. }
  36. -(void) rightMouseDown:(NSEvent *)theEvent
  37. {
  38. [(id)NSApplication.sharedApplication.delegate addEvent: theEvent];
  39. }
  40. -(void) rightMouseDragged:(NSEvent *)theEvent
  41. {
  42. [(id)NSApplication.sharedApplication.delegate addEvent: theEvent];
  43. }
  44. -(void) rightMouseUp:(NSEvent *)theEvent
  45. {
  46. [(id)NSApplication.sharedApplication.delegate addEvent: theEvent];
  47. }
  48. -(void) otherMouseDown:(NSEvent *)theEvent
  49. {
  50. [(id)NSApplication.sharedApplication.delegate addEvent: theEvent];
  51. }
  52. -(void) otherMouseDragged:(NSEvent *)theEvent
  53. {
  54. [(id)NSApplication.sharedApplication.delegate addEvent: theEvent];
  55. }
  56. -(void) otherMouseUp:(NSEvent *)theEvent
  57. {
  58. [(id)NSApplication.sharedApplication.delegate addEvent: theEvent];
  59. }
  60. -(void) windowDidMove: (NSNotification*)notif
  61. {
  62. [self setNeedsDisplay: YES];
  63. }
  64. -(void) viewDidMoveToWindow
  65. {
  66. [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(windowDidMove:) name: NSWindowDidMoveNotification object: self.window];
  67. }
  68. @end
  69. @interface RootlessWindowAndFrame : NSObject
  70. {
  71. NSRect mFrame;
  72. NSWindow* mWindow;
  73. }
  74. -(id) initWithWindow: (NSWindow*)wd frame: (NSRect)box;
  75. -(NSRect) frame;
  76. -(NSWindow*) window;
  77. -(void) setWindow: (NSWindow*)wd;
  78. @end
  79. @implementation RootlessWindowAndFrame
  80. -(id) initWithWindow: (NSWindow*)wd frame: (NSRect)box
  81. {
  82. self = [super init];
  83. if( self )
  84. {
  85. mWindow = wd;
  86. mFrame = box;
  87. }
  88. return self;
  89. }
  90. -(NSRect) frame
  91. {
  92. return mFrame;
  93. }
  94. -(NSWindow*) window
  95. {
  96. return mWindow;
  97. }
  98. -(void) setWindow: (NSWindow*)wd
  99. {
  100. mWindow = wd;
  101. }
  102. @end
  103. @implementation AppDelegate
  104. - (void)applicationDidFinishLaunching:(NSNotification *)aNotification
  105. {
  106. NSRect backBufferBox = { NSZeroPoint, [NSScreen.screens.firstObject frame].size };
  107. self.backBuffer = [[NSImage alloc] initWithSize: backBufferBox.size];
  108. [self.backBuffer lockFocus];
  109. [NSColor.blackColor set];
  110. NSRectFillUsingOperation( backBufferBox, NSCompositeCopy );
  111. [self.backBuffer unlockFocus];
  112. self.windows = [[NSMutableArray alloc] init];
  113. self.events = [[NSMutableArray alloc] init];
  114. [NSApplication.sharedApplication setPresentationOptions: NSApplicationPresentationAutoHideDock | NSApplicationPresentationAutoHideMenuBar];
  115. [NSThread detachNewThreadSelector: @selector(emulatorMain) toTarget: self withObject: nil];
  116. }
  117. - (void)applicationWillTerminate:(NSNotification *)aNotification
  118. {
  119. // Insert code here to tear down your application
  120. }
  121. -(void) emulatorMain
  122. {
  123. NSArray* args = [NSProcessInfo processInfo].arguments;
  124. NSInteger numArgs = args.count;
  125. char* emulatorArgs[numArgs];
  126. // First build a buffer with all C strings in it and
  127. // fill the array with their *offsets* in the data as
  128. // the pointers could change every time we append more data.
  129. NSMutableData* stringData = [NSMutableData data];
  130. NSInteger idx = 0;
  131. NSInteger offset = 0;
  132. for( NSString* currArg in args )
  133. {
  134. uint8_t zeroByte = 0;
  135. emulatorArgs[idx] = (char*)offset;
  136. NSData* currCStr = [currArg dataUsingEncoding: NSUTF8StringEncoding];
  137. [stringData appendBytes: currCStr.bytes length: currCStr.length];
  138. [stringData appendBytes: &zeroByte length: 1];
  139. offset += currCStr.length +1;
  140. idx++;
  141. }
  142. // Now that the strings array is stable, turn the offsets into pointers:
  143. char* firstPointer = (char*)[stringData bytes];
  144. for( int x = 0; x < numArgs; x++ )
  145. {
  146. emulatorArgs[x] += (intptr_t)firstPointer;
  147. }
  148. EmulatorMain( numArgs, emulatorArgs );
  149. [NSApplication.sharedApplication performSelectorOnMainThread: @selector(terminate:) withObject: nil waitUntilDone: NO];
  150. }
  151. -(void) addWindow: (RootlessWindowAndFrame*)waf
  152. {
  153. NSWindow* theWindow = [[NSWindow alloc] initWithContentRect: waf.frame styleMask: NSBorderlessWindowMask backing: NSBackingStoreBuffered defer: NO];
  154. theWindow.releasedWhenClosed = NO;
  155. theWindow.opaque = NO;
  156. [theWindow setContentView: [[RootlessWindowContentView alloc] initWithFrame: NSMakeRect(0, 0, 100, 100)]];
  157. [self.windows addObject: theWindow];
  158. [theWindow makeKeyAndOrderFront: self];
  159. waf.window = theWindow;
  160. }
  161. -(void) moveWindow: (RootlessWindowAndFrame*)waf
  162. {
  163. [waf.window setFrame: [waf.window frameRectForContentRect: waf.frame] display: YES];
  164. }
  165. -(void) removeWindow: (NSWindow*)theWindow
  166. {
  167. [theWindow close];
  168. [self.windows removeObject: theWindow];
  169. }
  170. -(void) setBackBuffer: (NSImage *)backBuffer
  171. {
  172. self->_backBuffer = backBuffer;
  173. for( NSWindow* aWindow in self.windows )
  174. [aWindow.contentView setNeedsDisplay: YES];
  175. }
  176. -(void) addEvent: (NSEvent*)evt
  177. {
  178. @synchronized( self )
  179. {
  180. [self.events addObject: evt];
  181. }
  182. }
  183. -(NSEvent*) dequeueNextEvent
  184. {
  185. NSEvent* evt = nil;
  186. @synchronized( self )
  187. {
  188. evt = self.events.firstObject;
  189. if( evt )
  190. [self.events removeObjectAtIndex: 0];
  191. }
  192. return evt;
  193. }
  194. @end
  195. RootlessWindow CreateWindowWithRect( int x, int y, int width, int height )
  196. {
  197. RootlessWindowAndFrame * waf = [[RootlessWindowAndFrame alloc] initWithWindow: nil frame: NSMakeRect(x, y, width, height)];
  198. [(id)NSApplication.sharedApplication.delegate performSelectorOnMainThread: @selector(addWindow:) withObject: waf waitUntilDone: YES];
  199. return (__bridge RootlessWindow)waf.window;
  200. }
  201. void SetWindowRect( RootlessWindow win, int x, int y, int width, int height )
  202. {
  203. RootlessWindowAndFrame * waf = [[RootlessWindowAndFrame alloc] initWithWindow: (__bridge NSWindow*)win frame: NSMakeRect(x, y, width, height)];
  204. [(id)NSApplication.sharedApplication.delegate performSelectorOnMainThread: @selector(moveWindow:) withObject: waf waitUntilDone: YES];
  205. }
  206. void FreeWindow( RootlessWindow win )
  207. {
  208. [(id)NSApplication.sharedApplication.delegate performSelectorOnMainThread: @selector(removeWindow:) withObject: (__bridge NSWindow*)win waitUntilDone: YES];
  209. }
  210. void BackBufferChanged( void* data, int rowBytes, int width, int height )
  211. {
  212. NSImage* newBackBuffer = [[NSImage alloc] initWithSize: NSMakeSize(width, height)];
  213. unsigned char* pixels[4] = { data, NULL, NULL, NULL };
  214. NSBitmapImageRep* bir = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes: pixels pixelsWide:width pixelsHigh: height bitsPerSample: 8 samplesPerPixel: 4 hasAlpha: YES isPlanar: NO colorSpaceName:NSCalibratedRGBColorSpace bitmapFormat: NS32BitLittleEndianBitmapFormat bytesPerRow: rowBytes bitsPerPixel: 32];
  215. [newBackBuffer addRepresentation: bir];
  216. [(id)NSApplication.sharedApplication.delegate performSelectorOnMainThread: @selector(setBackBuffer:) withObject: newBackBuffer waitUntilDone: YES];
  217. }
  218. bool QueryInputDevices( int *outButtonDown, int *outX, int *outY )
  219. {
  220. NSEvent* evt = [(id)NSApplication.sharedApplication.delegate dequeueNextEvent];
  221. if( !evt )
  222. {
  223. return false;
  224. }
  225. if( evt.type == NSLeftMouseDown || evt.type == NSLeftMouseUp || evt.type == NSLeftMouseDragged
  226. || evt.type == NSRightMouseDown || evt.type == NSRightMouseUp || evt.type == NSRightMouseDragged
  227. || evt.type == NSOtherMouseDown || evt.type == NSOtherMouseUp || evt.type == NSOtherMouseDragged )
  228. {
  229. *outButtonDown = (int)evt.buttonNumber;
  230. NSPoint pos = evt.locationInWindow;
  231. pos.x += evt.window.frame.origin.x;
  232. pos.y += evt.window.frame.origin.y;
  233. *outX = pos.x;
  234. *outY = pos.y;
  235. }
  236. return true;
  237. }
  238. void GetScreenSize( int *outWidth, int *outHeight )
  239. {
  240. NSScreen* currScreen = NSScreen.screens.firstObject;
  241. *outWidth = currScreen.frame.size.width;
  242. *outHeight = currScreen.frame.size.height;
  243. }