macos_system.m 35 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181
  1. #import "macos_system.h"
  2. #import <Cocoa/Cocoa.h>
  3. #include <stdbool.h>
  4. #include <iron_system.h>
  5. #include <iron_gpu.h>
  6. #include <iron_math.h>
  7. #include <iron_video.h>
  8. #include <objc/runtime.h>
  9. #include <mach/mach_time.h>
  10. struct WindowData {
  11. id handle;
  12. id view;
  13. bool fullscreen;
  14. void (*resizeCallback)(int width, int height, void *data);
  15. void *resizeCallbackData;
  16. bool (*closeCallback)(void *data);
  17. void *closeCallbackData;
  18. };
  19. static struct WindowData windows[1] = {};
  20. static bool controlKeyMouseButton = false;
  21. static int mouseX, mouseY;
  22. static bool keyboardShown = false;
  23. static const char *videoFormats[] = {"ogv", NULL};
  24. static NSApplication *myapp;
  25. static NSWindow *window;
  26. static BasicMTKView *view;
  27. static char language[3];
  28. #ifdef WITH_GAMEPAD
  29. static struct HIDManager *hidManager;
  30. #endif
  31. @implementation BasicMTKView
  32. static bool shift = false;
  33. static bool ctrl = false;
  34. static bool alt = false;
  35. static bool cmd = false;
  36. - (void)flagsChanged:(NSEvent *)theEvent {
  37. if (shift) {
  38. iron_internal_keyboard_trigger_key_up(IRON_KEY_SHIFT);
  39. shift = false;
  40. }
  41. if (ctrl) {
  42. iron_internal_keyboard_trigger_key_up(IRON_KEY_CONTROL);
  43. ctrl = false;
  44. }
  45. if (alt) {
  46. iron_internal_keyboard_trigger_key_up(IRON_KEY_ALT);
  47. alt = false;
  48. }
  49. if (cmd) {
  50. iron_internal_keyboard_trigger_key_up(IRON_KEY_META);
  51. cmd = false;
  52. }
  53. if ([theEvent modifierFlags] & NSShiftKeyMask) {
  54. iron_internal_keyboard_trigger_key_down(IRON_KEY_SHIFT);
  55. shift = true;
  56. }
  57. if ([theEvent modifierFlags] & NSControlKeyMask) {
  58. iron_internal_keyboard_trigger_key_down(IRON_KEY_CONTROL);
  59. ctrl = true;
  60. }
  61. if ([theEvent modifierFlags] & NSAlternateKeyMask) {
  62. iron_internal_keyboard_trigger_key_down(IRON_KEY_ALT);
  63. alt = true;
  64. }
  65. if ([theEvent modifierFlags] & NSCommandKeyMask) {
  66. iron_internal_keyboard_trigger_key_down(IRON_KEY_META);
  67. cmd = true;
  68. }
  69. }
  70. - (void)keyDown:(NSEvent *)theEvent {
  71. if ([theEvent isARepeat])
  72. return;
  73. NSString *characters = [theEvent charactersIgnoringModifiers];
  74. if ([characters length]) {
  75. unichar ch = [characters characterAtIndex:0];
  76. switch (ch) { // keys that exist in keydown and keypress events
  77. case 59:
  78. iron_internal_keyboard_trigger_key_down(IRON_KEY_SEMICOLON);
  79. break;
  80. case 91:
  81. iron_internal_keyboard_trigger_key_down(IRON_KEY_OPEN_BRACKET);
  82. break;
  83. case 93:
  84. iron_internal_keyboard_trigger_key_down(IRON_KEY_CLOSE_BRACKET);
  85. break;
  86. case 39:
  87. iron_internal_keyboard_trigger_key_down(IRON_KEY_QUOTE);
  88. break;
  89. case 92:
  90. iron_internal_keyboard_trigger_key_down(IRON_KEY_BACK_SLASH);
  91. break;
  92. case 44:
  93. iron_internal_keyboard_trigger_key_down(IRON_KEY_COMMA);
  94. break;
  95. case 46:
  96. iron_internal_keyboard_trigger_key_down(IRON_KEY_PERIOD);
  97. break;
  98. case 47:
  99. iron_internal_keyboard_trigger_key_down(IRON_KEY_SLASH);
  100. break;
  101. case 96:
  102. iron_internal_keyboard_trigger_key_down(IRON_KEY_BACK_QUOTE);
  103. break;
  104. case 32:
  105. iron_internal_keyboard_trigger_key_down(IRON_KEY_SPACE);
  106. break;
  107. case 34:
  108. iron_internal_keyboard_trigger_key_down(IRON_KEY_DOUBLE_QUOTE);
  109. break;
  110. case 40:
  111. iron_internal_keyboard_trigger_key_down(IRON_KEY_OPEN_PAREN);
  112. break;
  113. case 41:
  114. iron_internal_keyboard_trigger_key_down(IRON_KEY_CLOSE_PAREN);
  115. break;
  116. case 42:
  117. iron_internal_keyboard_trigger_key_down(IRON_KEY_ASTERISK);
  118. break;
  119. case 43:
  120. iron_internal_keyboard_trigger_key_down(IRON_KEY_PLUS);
  121. break;
  122. case 45:
  123. iron_internal_keyboard_trigger_key_down(IRON_KEY_HYPHEN_MINUS);
  124. break;
  125. case 61:
  126. iron_internal_keyboard_trigger_key_down(IRON_KEY_EQUALS);
  127. break;
  128. case 95:
  129. iron_internal_keyboard_trigger_key_down(IRON_KEY_UNDERSCORE);
  130. break;
  131. }
  132. switch (ch) {
  133. case NSRightArrowFunctionKey:
  134. iron_internal_keyboard_trigger_key_down(IRON_KEY_RIGHT);
  135. break;
  136. case NSLeftArrowFunctionKey:
  137. iron_internal_keyboard_trigger_key_down(IRON_KEY_LEFT);
  138. break;
  139. case NSUpArrowFunctionKey:
  140. iron_internal_keyboard_trigger_key_down(IRON_KEY_UP);
  141. break;
  142. case NSDownArrowFunctionKey:
  143. iron_internal_keyboard_trigger_key_down(IRON_KEY_DOWN);
  144. break;
  145. case 27:
  146. iron_internal_keyboard_trigger_key_down(IRON_KEY_ESCAPE);
  147. break;
  148. case NSEnterCharacter:
  149. case NSNewlineCharacter:
  150. case NSCarriageReturnCharacter:
  151. iron_internal_keyboard_trigger_key_down(IRON_KEY_RETURN);
  152. iron_internal_keyboard_trigger_key_press('\n');
  153. break;
  154. case 0x7f:
  155. iron_internal_keyboard_trigger_key_down(IRON_KEY_BACKSPACE);
  156. iron_internal_keyboard_trigger_key_press('\x08');
  157. break;
  158. case 9:
  159. iron_internal_keyboard_trigger_key_down(IRON_KEY_TAB);
  160. iron_internal_keyboard_trigger_key_press('\t');
  161. break;
  162. default:
  163. if (ch == 'x' && [theEvent modifierFlags] & NSCommandKeyMask) {
  164. char *text = iron_internal_cut_callback();
  165. if (text != NULL) {
  166. NSPasteboard *board = [NSPasteboard generalPasteboard];
  167. [board clearContents];
  168. [board setString:[NSString stringWithUTF8String:text] forType:NSStringPboardType];
  169. }
  170. }
  171. if (ch == 'c' && [theEvent modifierFlags] & NSCommandKeyMask) {
  172. char *text = iron_internal_copy_callback();
  173. if (text != NULL) {
  174. iron_copy_to_clipboard(text);
  175. }
  176. }
  177. if (ch == 'v' && [theEvent modifierFlags] & NSCommandKeyMask) {
  178. NSPasteboard *board = [NSPasteboard generalPasteboard];
  179. NSString *data = [board stringForType:NSStringPboardType];
  180. if (data != nil) {
  181. char charData[4096];
  182. strcpy(charData, [data UTF8String]);
  183. iron_internal_paste_callback(charData);
  184. }
  185. }
  186. if (ch >= L'a' && ch <= L'z') {
  187. iron_internal_keyboard_trigger_key_down(ch - L'a' + IRON_KEY_A);
  188. }
  189. else if (ch >= L'A' && ch <= L'Z') {
  190. iron_internal_keyboard_trigger_key_down(ch - L'A' + IRON_KEY_A);
  191. }
  192. else if (ch >= L'0' && ch <= L'9') {
  193. iron_internal_keyboard_trigger_key_down(ch - L'0' + IRON_KEY_0);
  194. }
  195. iron_internal_keyboard_trigger_key_press(ch);
  196. break;
  197. }
  198. }
  199. }
  200. - (void)keyUp:(NSEvent *)theEvent {
  201. NSString *characters = [theEvent charactersIgnoringModifiers];
  202. if ([characters length]) {
  203. unichar ch = [characters characterAtIndex:0];
  204. switch (ch) {
  205. case 59:
  206. iron_internal_keyboard_trigger_key_up(IRON_KEY_SEMICOLON);
  207. break;
  208. case 91:
  209. iron_internal_keyboard_trigger_key_up(IRON_KEY_OPEN_BRACKET);
  210. break;
  211. case 93:
  212. iron_internal_keyboard_trigger_key_up(IRON_KEY_CLOSE_BRACKET);
  213. break;
  214. case 39:
  215. iron_internal_keyboard_trigger_key_up(IRON_KEY_QUOTE);
  216. break;
  217. case 92:
  218. iron_internal_keyboard_trigger_key_up(IRON_KEY_BACK_SLASH);
  219. break;
  220. case 44:
  221. iron_internal_keyboard_trigger_key_up(IRON_KEY_COMMA);
  222. break;
  223. case 46:
  224. iron_internal_keyboard_trigger_key_up(IRON_KEY_PERIOD);
  225. break;
  226. case 47:
  227. iron_internal_keyboard_trigger_key_up(IRON_KEY_SLASH);
  228. break;
  229. case 96:
  230. iron_internal_keyboard_trigger_key_up(IRON_KEY_BACK_QUOTE);
  231. break;
  232. case 45:
  233. iron_internal_keyboard_trigger_key_up(IRON_KEY_HYPHEN_MINUS);
  234. break;
  235. case 61:
  236. iron_internal_keyboard_trigger_key_up(IRON_KEY_EQUALS);
  237. break;
  238. case NSRightArrowFunctionKey:
  239. iron_internal_keyboard_trigger_key_up(IRON_KEY_RIGHT);
  240. break;
  241. case NSLeftArrowFunctionKey:
  242. iron_internal_keyboard_trigger_key_up(IRON_KEY_LEFT);
  243. break;
  244. case NSUpArrowFunctionKey:
  245. iron_internal_keyboard_trigger_key_up(IRON_KEY_UP);
  246. break;
  247. case NSDownArrowFunctionKey:
  248. iron_internal_keyboard_trigger_key_up(IRON_KEY_DOWN);
  249. break;
  250. case 27:
  251. iron_internal_keyboard_trigger_key_up(IRON_KEY_ESCAPE);
  252. break;
  253. case NSEnterCharacter:
  254. case NSNewlineCharacter:
  255. case NSCarriageReturnCharacter:
  256. iron_internal_keyboard_trigger_key_up(IRON_KEY_RETURN);
  257. break;
  258. case 0x7f:
  259. iron_internal_keyboard_trigger_key_up(IRON_KEY_BACKSPACE);
  260. break;
  261. case 9:
  262. iron_internal_keyboard_trigger_key_up(IRON_KEY_TAB);
  263. break;
  264. case 32:
  265. iron_internal_keyboard_trigger_key_up(IRON_KEY_SPACE);
  266. break;
  267. case 34:
  268. iron_internal_keyboard_trigger_key_up(IRON_KEY_DOUBLE_QUOTE);
  269. break;
  270. case 40:
  271. iron_internal_keyboard_trigger_key_up(IRON_KEY_OPEN_PAREN);
  272. break;
  273. case 41:
  274. iron_internal_keyboard_trigger_key_up(IRON_KEY_CLOSE_PAREN);
  275. break;
  276. case 42:
  277. iron_internal_keyboard_trigger_key_up(IRON_KEY_ASTERISK);
  278. break;
  279. case 43:
  280. iron_internal_keyboard_trigger_key_up(IRON_KEY_PLUS);
  281. break;
  282. case 95:
  283. iron_internal_keyboard_trigger_key_up(IRON_KEY_UNDERSCORE);
  284. break;
  285. default:
  286. if (ch >= L'a' && ch <= L'z') {
  287. iron_internal_keyboard_trigger_key_up(ch - L'a' + IRON_KEY_A);
  288. }
  289. else if (ch >= L'A' && ch <= L'Z') {
  290. iron_internal_keyboard_trigger_key_up(ch - L'A' + IRON_KEY_A);
  291. }
  292. else if (ch >= L'0' && ch <= L'9') {
  293. iron_internal_keyboard_trigger_key_up(ch - L'0' + IRON_KEY_0);
  294. }
  295. break;
  296. }
  297. }
  298. }
  299. static int getMouseX(NSEvent *event) {
  300. NSWindow *window = [[NSApplication sharedApplication] mainWindow];
  301. float scale = [window backingScaleFactor];
  302. return (int)([event locationInWindow].x * scale);
  303. }
  304. static int getMouseY(NSEvent *event) {
  305. NSWindow *window = [[NSApplication sharedApplication] mainWindow];
  306. float scale = [window backingScaleFactor];
  307. return (int)(iron_window_height() - [event locationInWindow].y * scale);
  308. }
  309. - (void)mouseDown:(NSEvent *)theEvent {
  310. if ([theEvent modifierFlags] & NSControlKeyMask) {
  311. controlKeyMouseButton = true;
  312. iron_internal_mouse_trigger_press(1, getMouseX(theEvent), getMouseY(theEvent));
  313. }
  314. else {
  315. controlKeyMouseButton = false;
  316. iron_internal_mouse_trigger_press(0, getMouseX(theEvent), getMouseY(theEvent));
  317. }
  318. if ([theEvent subtype] == NSTabletPointEventSubtype) {
  319. iron_internal_pen_trigger_press(getMouseX(theEvent), getMouseY(theEvent), theEvent.pressure);
  320. }
  321. }
  322. - (void)mouseUp:(NSEvent *)theEvent {
  323. if (controlKeyMouseButton) {
  324. iron_internal_mouse_trigger_release(1, getMouseX(theEvent), getMouseY(theEvent));
  325. }
  326. else {
  327. iron_internal_mouse_trigger_release(0, getMouseX(theEvent), getMouseY(theEvent));
  328. }
  329. controlKeyMouseButton = false;
  330. if ([theEvent subtype] == NSTabletPointEventSubtype) {
  331. iron_internal_pen_trigger_release(getMouseX(theEvent), getMouseY(theEvent), theEvent.pressure);
  332. }
  333. }
  334. - (void)mouseMoved:(NSEvent *)theEvent {
  335. iron_internal_mouse_trigger_move(getMouseX(theEvent), getMouseY(theEvent));
  336. }
  337. - (void)mouseDragged:(NSEvent *)theEvent {
  338. iron_internal_mouse_trigger_move(getMouseX(theEvent), getMouseY(theEvent));
  339. if ([theEvent subtype] == NSTabletPointEventSubtype) {
  340. iron_internal_pen_trigger_move(getMouseX(theEvent), getMouseY(theEvent), theEvent.pressure);
  341. }
  342. }
  343. - (void)rightMouseDown:(NSEvent *)theEvent {
  344. iron_internal_mouse_trigger_press(1, getMouseX(theEvent), getMouseY(theEvent));
  345. }
  346. - (void)rightMouseUp:(NSEvent *)theEvent {
  347. iron_internal_mouse_trigger_release(1, getMouseX(theEvent), getMouseY(theEvent));
  348. }
  349. - (void)rightMouseDragged:(NSEvent *)theEvent {
  350. iron_internal_mouse_trigger_move(getMouseX(theEvent), getMouseY(theEvent));
  351. }
  352. - (void)otherMouseDown:(NSEvent *)theEvent {
  353. iron_internal_mouse_trigger_press(2, getMouseX(theEvent), getMouseY(theEvent));
  354. }
  355. - (void)otherMouseUp:(NSEvent *)theEvent {
  356. iron_internal_mouse_trigger_release(2, getMouseX(theEvent), getMouseY(theEvent));
  357. }
  358. - (void)otherMouseDragged:(NSEvent *)theEvent {
  359. iron_internal_mouse_trigger_move(getMouseX(theEvent), getMouseY(theEvent));
  360. }
  361. - (void)scrollWheel:(NSEvent *)theEvent {
  362. int delta = [theEvent deltaY];
  363. iron_internal_mouse_trigger_scroll(-delta);
  364. }
  365. - (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)sender {
  366. NSPasteboard *pboard = [sender draggingPasteboard];
  367. NSDragOperation sourceDragMask = [sender draggingSourceOperationMask];
  368. if ([[pboard types] containsObject:NSURLPboardType]) {
  369. if (sourceDragMask & NSDragOperationLink) {
  370. return NSDragOperationLink;
  371. }
  372. }
  373. return NSDragOperationNone;
  374. }
  375. - (BOOL)performDragOperation:(id<NSDraggingInfo>)sender {
  376. NSPasteboard *pboard = [sender draggingPasteboard];
  377. // NSDragOperation sourceDragMask = [sender draggingSourceOperationMask];
  378. if ([[pboard types] containsObject:NSURLPboardType]) {
  379. NSURL *fileURL = [NSURL URLFromPasteboard:pboard];
  380. wchar_t *filePath = (wchar_t *)[fileURL.path cStringUsingEncoding:NSUTF32LittleEndianStringEncoding];
  381. iron_internal_drop_files_callback(filePath);
  382. }
  383. return YES;
  384. }
  385. - (void)update {
  386. }
  387. - (id)initWithFrame:(NSRect)frameRect {
  388. self = [super initWithFrame:frameRect];
  389. device = MTLCreateSystemDefaultDevice();
  390. commandQueue = [device newCommandQueue];
  391. library = [device newDefaultLibrary];
  392. CAMetalLayer *metalLayer = (CAMetalLayer *)self.layer;
  393. metalLayer.device = device;
  394. metalLayer.pixelFormat = MTLPixelFormatBGRA8Unorm;
  395. metalLayer.framebufferOnly = YES;
  396. metalLayer.opaque = YES;
  397. metalLayer.backgroundColor = nil;
  398. return self;
  399. }
  400. - (BOOL)acceptsFirstResponder {
  401. return YES;
  402. }
  403. - (BOOL)becomeFirstResponder {
  404. return YES;
  405. }
  406. - (BOOL)resignFirstResponder {
  407. return YES;
  408. }
  409. - (void)resize:(NSSize)size {
  410. [self setFrameSize:size];
  411. }
  412. - (CAMetalLayer *)metalLayer {
  413. return (CAMetalLayer *)self.layer;
  414. }
  415. - (id<MTLDevice>)metalDevice {
  416. return device;
  417. }
  418. - (id<MTLCommandQueue>)metalQueue {
  419. return commandQueue;
  420. }
  421. @end
  422. void iron_copy_to_clipboard(const char *text) {
  423. NSPasteboard *board = [NSPasteboard generalPasteboard];
  424. [board clearContents];
  425. [board setString:[NSString stringWithUTF8String:text] forType:NSStringPboardType];
  426. }
  427. #ifdef WITH_GAMEPAD
  428. static void inputValueCallback(void *inContext, IOReturn inResult, void *inSender, IOHIDValueRef inIOHIDValueRef);
  429. static void valueAvailableCallback(void *inContext, IOReturn inResult, void *inSender);
  430. static void reset(struct HIDGamepad *gamepad);
  431. static void initDeviceElements(struct HIDGamepad *gamepad, CFArrayRef elements);
  432. static void buttonChanged(struct HIDGamepad *gamepad, IOHIDElementRef elementRef, IOHIDValueRef valueRef, int buttonIndex);
  433. static void axisChanged(struct HIDGamepad *gamepad, IOHIDElementRef elementRef, IOHIDValueRef valueRef, int axisIndex);
  434. static void cstringFromCFStringRef(CFStringRef string, char *cstr, size_t clen) {
  435. cstr[0] = '\0';
  436. if (string != NULL) {
  437. char temp[256];
  438. if (CFStringGetCString(string, temp, 256, kCFStringEncodingUTF8)) {
  439. temp[iron_mini(255, (int)(clen - 1))] = '\0';
  440. strncpy(cstr, temp, clen);
  441. }
  442. }
  443. }
  444. void HIDGamepad_init(struct HIDGamepad *gamepad) {
  445. reset(gamepad);
  446. }
  447. void HIDGamepad_destroy(struct HIDGamepad *gamepad) {
  448. HIDGamepad_unbind(gamepad);
  449. }
  450. void HIDGamepad_bind(struct HIDGamepad *gamepad, IOHIDDeviceRef inDeviceRef, int inPadIndex) {
  451. gamepad->hidDeviceRef = inDeviceRef;
  452. gamepad->padIndex = inPadIndex;
  453. IOHIDDeviceOpen(gamepad->hidDeviceRef, kIOHIDOptionsTypeSeizeDevice);
  454. IOHIDDeviceRegisterInputValueCallback(gamepad->hidDeviceRef, inputValueCallback, gamepad);
  455. IOHIDDeviceScheduleWithRunLoop(gamepad->hidDeviceRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
  456. gamepad->hidQueueRef = IOHIDQueueCreate(kCFAllocatorDefault, gamepad->hidDeviceRef, 32, kIOHIDOptionsTypeNone);
  457. if (CFGetTypeID(gamepad->hidQueueRef) == IOHIDQueueGetTypeID()) {
  458. IOHIDQueueStart(gamepad->hidQueueRef);
  459. IOHIDQueueRegisterValueAvailableCallback(gamepad->hidQueueRef, valueAvailableCallback, gamepad);
  460. IOHIDQueueScheduleWithRunLoop(gamepad->hidQueueRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
  461. }
  462. CFArrayRef elementCFArrayRef = IOHIDDeviceCopyMatchingElements(gamepad->hidDeviceRef, NULL, kIOHIDOptionsTypeNone);
  463. initDeviceElements(gamepad, elementCFArrayRef);
  464. {
  465. CFNumberRef vendorIdRef = (CFNumberRef)IOHIDDeviceGetProperty(gamepad->hidDeviceRef, CFSTR(kIOHIDVendorIDKey));
  466. CFNumberGetValue(vendorIdRef, kCFNumberIntType, &gamepad->hidDeviceVendorID);
  467. CFNumberRef productIdRef = (CFNumberRef)IOHIDDeviceGetProperty(gamepad->hidDeviceRef, CFSTR(kIOHIDProductIDKey));
  468. CFNumberGetValue(productIdRef, kCFNumberIntType, &gamepad->hidDeviceProductID);
  469. CFStringRef vendorRef = (CFStringRef)IOHIDDeviceGetProperty(gamepad->hidDeviceRef, CFSTR(kIOHIDManufacturerKey));
  470. cstringFromCFStringRef(vendorRef, gamepad->hidDeviceVendor, sizeof(gamepad->hidDeviceVendor));
  471. CFStringRef productRef = (CFStringRef)IOHIDDeviceGetProperty(gamepad->hidDeviceRef, CFSTR(kIOHIDProductKey));
  472. cstringFromCFStringRef(productRef, gamepad->hidDeviceProduct, sizeof(gamepad->hidDeviceProduct));
  473. }
  474. }
  475. static void initDeviceElements(struct HIDGamepad *gamepad, CFArrayRef elements) {
  476. for (CFIndex i = 0, count = CFArrayGetCount(elements); i < count; ++i) {
  477. IOHIDElementRef elementRef = (IOHIDElementRef)CFArrayGetValueAtIndex(elements, i);
  478. IOHIDElementType elemType = IOHIDElementGetType(elementRef);
  479. IOHIDElementCookie cookie = IOHIDElementGetCookie(elementRef);
  480. uint32_t usagePage = IOHIDElementGetUsagePage(elementRef);
  481. uint32_t usage = IOHIDElementGetUsage(elementRef);
  482. // Match up items
  483. switch (usagePage) {
  484. case kHIDPage_GenericDesktop:
  485. switch (usage) {
  486. case kHIDUsage_GD_X: // Left stick X
  487. gamepad->axis[0] = cookie;
  488. break;
  489. case kHIDUsage_GD_Y: // Left stick Y
  490. gamepad->axis[1] = cookie;
  491. break;
  492. case kHIDUsage_GD_Z: // Left trigger
  493. gamepad->axis[4] = cookie;
  494. break;
  495. case kHIDUsage_GD_Rx: // Right stick X
  496. gamepad->axis[2] = cookie;
  497. break;
  498. case kHIDUsage_GD_Ry: // Right stick Y
  499. gamepad->axis[3] = cookie;
  500. break;
  501. case kHIDUsage_GD_Rz: // Right trigger
  502. gamepad->axis[5] = cookie;
  503. break;
  504. case kHIDUsage_GD_Hatswitch:
  505. break;
  506. default:
  507. break;
  508. }
  509. break;
  510. case kHIDPage_Button:
  511. if ((usage >= 1) && (usage <= 15)) {
  512. // Button 1-11
  513. gamepad->buttons[usage - 1] = cookie;
  514. }
  515. break;
  516. default:
  517. break;
  518. }
  519. if (elemType == kIOHIDElementTypeInput_Misc || elemType == kIOHIDElementTypeInput_Button || elemType == kIOHIDElementTypeInput_Axis) {
  520. if (!IOHIDQueueContainsElement(gamepad->hidQueueRef, elementRef))
  521. IOHIDQueueAddElement(gamepad->hidQueueRef, elementRef);
  522. }
  523. }
  524. }
  525. void HIDGamepad_unbind(struct HIDGamepad *gamepad) {
  526. if (gamepad->hidQueueRef) {
  527. IOHIDQueueStop(gamepad->hidQueueRef);
  528. IOHIDQueueUnscheduleFromRunLoop(gamepad->hidQueueRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
  529. }
  530. if (gamepad->hidDeviceRef) {
  531. IOHIDDeviceUnscheduleFromRunLoop(gamepad->hidDeviceRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
  532. IOHIDDeviceClose(gamepad->hidDeviceRef, kIOHIDOptionsTypeSeizeDevice);
  533. }
  534. reset(gamepad);
  535. }
  536. static void reset(struct HIDGamepad *gamepad) {
  537. gamepad->padIndex = -1;
  538. gamepad->hidDeviceRef = NULL;
  539. gamepad->hidQueueRef = NULL;
  540. gamepad->hidDeviceVendor[0] = '\0';
  541. gamepad->hidDeviceProduct[0] = '\0';
  542. gamepad->hidDeviceVendorID = 0;
  543. gamepad->hidDeviceProductID = 0;
  544. memset(gamepad->axis, 0, sizeof(gamepad->axis));
  545. memset(gamepad->buttons, 0, sizeof(gamepad->buttons));
  546. }
  547. static void buttonChanged(struct HIDGamepad *gamepad, IOHIDElementRef elementRef, IOHIDValueRef valueRef, int buttonIndex) {
  548. double rawValue = IOHIDValueGetScaledValue(valueRef, kIOHIDValueScaleTypePhysical);
  549. double min = IOHIDElementGetLogicalMin(elementRef);
  550. double max = IOHIDElementGetLogicalMax(elementRef);
  551. double normalize = (rawValue - min) / (max - min);
  552. iron_internal_gamepad_trigger_button(gamepad->padIndex, buttonIndex, normalize);
  553. }
  554. static void axisChanged(struct HIDGamepad *gamepad, IOHIDElementRef elementRef, IOHIDValueRef valueRef, int axisIndex) {
  555. double rawValue = IOHIDValueGetScaledValue(valueRef, kIOHIDValueScaleTypePhysical);
  556. double min = IOHIDElementGetPhysicalMin(elementRef);
  557. double max = IOHIDElementGetPhysicalMax(elementRef);
  558. double normalize = normalize = (((rawValue - min) / (max - min)) * 2) - 1;
  559. if (axisIndex % 2 == 1) {
  560. normalize = -normalize;
  561. }
  562. iron_internal_gamepad_trigger_axis(gamepad->padIndex, axisIndex, normalize);
  563. }
  564. static void inputValueCallback(void *inContext, IOReturn inResult, void *inSender, IOHIDValueRef inIOHIDValueRef) {}
  565. static void valueAvailableCallback(void *inContext, IOReturn inResult, void *inSender) {
  566. struct HIDGamepad *pad = (struct HIDGamepad *)inContext;
  567. do {
  568. IOHIDValueRef valueRef = IOHIDQueueCopyNextValueWithTimeout((IOHIDQueueRef)inSender, 0.);
  569. if (!valueRef) {
  570. break;
  571. }
  572. IOHIDElementRef elementRef = IOHIDValueGetElement(valueRef);
  573. IOHIDElementCookie cookie = IOHIDElementGetCookie(elementRef);
  574. for (int i = 0, c = sizeof(pad->buttons); i < c; ++i) {
  575. if (cookie == pad->buttons[i]) {
  576. buttonChanged(pad, elementRef, valueRef, i);
  577. break;
  578. }
  579. }
  580. for (int i = 0, c = sizeof(pad->axis); i < c; ++i) {
  581. if (cookie == pad->axis[i]) {
  582. axisChanged(pad, elementRef, valueRef, i);
  583. break;
  584. }
  585. }
  586. CFRelease(valueRef);
  587. } while (1);
  588. }
  589. const char *iron_gamepad_vendor(int gamepad) {
  590. return "unknown";
  591. }
  592. const char *iron_gamepad_product_name(int gamepad) {
  593. return "unknown";
  594. }
  595. static int initHIDManager(struct HIDManager *manager);
  596. static bool addMatchingArray(struct HIDManager *manager, CFMutableArrayRef matchingCFArrayRef, CFDictionaryRef matchingCFDictRef);
  597. static CFMutableDictionaryRef createDeviceMatchingDictionary(struct HIDManager *manager, uint32_t inUsagePage, uint32_t inUsage);
  598. static void deviceConnected(void *inContext, IOReturn inResult, void *inSender, IOHIDDeviceRef inIOHIDDeviceRef);
  599. static void deviceRemoved(void *inContext, IOReturn inResult, void *inSender, IOHIDDeviceRef inIOHIDDeviceRef);
  600. void HIDManager_init(struct HIDManager *manager) {
  601. manager->managerRef = 0x0;
  602. initHIDManager(manager);
  603. }
  604. void HIDManager_destroy(struct HIDManager *manager) {
  605. if (manager->managerRef) {
  606. IOHIDManagerUnscheduleFromRunLoop(manager->managerRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
  607. IOHIDManagerClose(manager->managerRef, kIOHIDOptionsTypeNone);
  608. }
  609. }
  610. static int initHIDManager(struct HIDManager *manager) {
  611. manager->managerRef = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);
  612. if (CFGetTypeID(manager->managerRef) == IOHIDManagerGetTypeID()) {
  613. CFMutableArrayRef matchingCFArrayRef = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
  614. if (matchingCFArrayRef) {
  615. CFDictionaryRef matchingCFDictRef = createDeviceMatchingDictionary(manager, kHIDPage_GenericDesktop, kHIDUsage_GD_Joystick);
  616. addMatchingArray(manager, matchingCFArrayRef, matchingCFDictRef);
  617. matchingCFDictRef = createDeviceMatchingDictionary(manager, kHIDPage_GenericDesktop, kHIDUsage_GD_GamePad);
  618. addMatchingArray(manager, matchingCFArrayRef, matchingCFDictRef);
  619. }
  620. else {
  621. iron_error("%s: CFArrayCreateMutable failed.", __PRETTY_FUNCTION__);
  622. return -1;
  623. }
  624. IOHIDManagerSetDeviceMatchingMultiple(manager->managerRef, matchingCFArrayRef);
  625. CFRelease(matchingCFArrayRef);
  626. IOHIDManagerOpen(manager->managerRef, kIOHIDOptionsTypeNone);
  627. IOHIDManagerRegisterDeviceMatchingCallback(manager->managerRef, deviceConnected, manager);
  628. IOHIDManagerRegisterDeviceRemovalCallback(manager->managerRef, deviceRemoved, manager);
  629. IOHIDManagerScheduleWithRunLoop(manager->managerRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
  630. return 0;
  631. }
  632. return -1;
  633. }
  634. bool addMatchingArray(struct HIDManager *manager, CFMutableArrayRef matchingCFArrayRef, CFDictionaryRef matchingCFDictRef) {
  635. if (matchingCFDictRef) {
  636. CFArrayAppendValue(matchingCFArrayRef, matchingCFDictRef);
  637. CFRelease(matchingCFDictRef);
  638. return true;
  639. }
  640. return false;
  641. }
  642. CFMutableDictionaryRef createDeviceMatchingDictionary(struct HIDManager *manager, uint32_t inUsagePage, uint32_t inUsage) {
  643. CFMutableDictionaryRef result = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
  644. if (result) {
  645. if (inUsagePage) {
  646. CFNumberRef pageCFNumberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &inUsagePage);
  647. if (pageCFNumberRef) {
  648. CFDictionarySetValue(result, CFSTR(kIOHIDDeviceUsagePageKey), pageCFNumberRef);
  649. CFRelease(pageCFNumberRef);
  650. if (inUsage) {
  651. CFNumberRef usageCFNumberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &inUsage);
  652. if (usageCFNumberRef) {
  653. CFDictionarySetValue(result, CFSTR(kIOHIDDeviceUsageKey), usageCFNumberRef);
  654. CFRelease(usageCFNumberRef);
  655. }
  656. }
  657. }
  658. }
  659. }
  660. return result;
  661. }
  662. void deviceConnected(void *inContext, IOReturn inResult, void *inSender, IOHIDDeviceRef inIOHIDDeviceRef) {
  663. struct HIDManager *manager = (struct HIDManager *)inContext;
  664. struct HIDManagerDeviceRecord *device = &manager->devices[0];
  665. for (int i = 0; i < IRON_MAX_HID_DEVICES; ++i, ++device) {
  666. if (!device->connected) {
  667. device->connected = true;
  668. device->device = inIOHIDDeviceRef;
  669. HIDGamepad_bind(&device->pad, inIOHIDDeviceRef, i);
  670. break;
  671. }
  672. }
  673. }
  674. void deviceRemoved(void *inContext, IOReturn inResult, void *inSender, IOHIDDeviceRef inIOHIDDeviceRef) {
  675. struct HIDManager *manager = (struct HIDManager *)inContext;
  676. struct HIDManagerDeviceRecord *device = &manager->devices[0];
  677. for (int i = 0; i < IRON_MAX_HID_DEVICES; ++i, ++device) {
  678. if (device->connected && device->device == inIOHIDDeviceRef) {
  679. device->connected = false;
  680. device->device = NULL;
  681. HIDGamepad_unbind(&device->pad);
  682. break;
  683. }
  684. }
  685. }
  686. #endif
  687. int iron_count_displays(void) {
  688. NSArray *screens = [NSScreen screens];
  689. return (int)[screens count];
  690. }
  691. int iron_primary_display(void) {
  692. NSArray *screens = [NSScreen screens];
  693. NSScreen *mainScreen = [NSScreen mainScreen];
  694. int max_displays = 8;
  695. for (int i = 0; i < max_displays; ++i) {
  696. if (mainScreen == screens[i]) {
  697. return i;
  698. }
  699. }
  700. return -1;
  701. }
  702. void iron_display_init(void) {}
  703. iron_display_mode_t iron_display_current_mode(int display) {
  704. NSArray *screens = [NSScreen screens];
  705. NSScreen *screen = screens[display];
  706. NSRect screenRect = [screen frame];
  707. iron_display_mode_t dm;
  708. dm.width = screenRect.size.width;
  709. dm.height = screenRect.size.height;
  710. dm.frequency = 60;
  711. dm.bits_per_pixel = 32;
  712. NSDictionary *description = [screen deviceDescription];
  713. NSSize displayPixelSize = [[description objectForKey:NSDeviceSize] sizeValue];
  714. NSNumber *screenNumber = [description objectForKey:@"NSScreenNumber"];
  715. CGSize displayPhysicalSize = CGDisplayScreenSize([screenNumber unsignedIntValue]); // in millimeters
  716. double ppi = displayPixelSize.width / (displayPhysicalSize.width * 0.039370); // Convert MM to INCH
  717. dm.pixels_per_inch = round(ppi);
  718. return dm;
  719. }
  720. NSWindow *iron_get_mac_window_handle();
  721. void iron_internal_mouse_lock() {
  722. iron_mouse_hide();
  723. }
  724. void iron_internal_mouse_unlock(void) {
  725. iron_mouse_show();
  726. }
  727. bool iron_mouse_can_lock(void) {
  728. return true;
  729. }
  730. void iron_mouse_show(void) {
  731. CGDisplayShowCursor(kCGDirectMainDisplay);
  732. }
  733. void iron_mouse_hide(void) {
  734. CGDisplayHideCursor(kCGDirectMainDisplay);
  735. }
  736. void iron_mouse_set_position(int x, int y) {
  737. NSWindow *window = iron_get_mac_window_handle();
  738. float scale = [window backingScaleFactor];
  739. NSRect rect = [[NSScreen mainScreen] frame];
  740. CGPoint point;
  741. point.x = window.frame.origin.x + (x / scale);
  742. point.y = rect.size.height - (window.frame.origin.y + (y / scale));
  743. CGDisplayMoveCursorToPoint(0, point);
  744. CGAssociateMouseAndMouseCursorPosition(true);
  745. }
  746. void iron_mouse_get_position(int *x, int *y) {
  747. NSWindow *window = iron_get_mac_window_handle();
  748. NSPoint point = [window mouseLocationOutsideOfEventStream];
  749. *x = (int)point.x;
  750. *y = (int)point.y;
  751. }
  752. void iron_mouse_set_cursor(int cursor_index) {}
  753. void iron_keyboard_show(void) {
  754. keyboardShown = true;
  755. }
  756. void iron_keyboard_hide(void) {
  757. keyboardShown = false;
  758. }
  759. bool iron_keyboard_active(void) {
  760. return keyboardShown;
  761. }
  762. const char *iron_system_id(void) {
  763. return "macOS";
  764. }
  765. const char **iron_video_formats(void) {
  766. return videoFormats;
  767. }
  768. void iron_set_keep_screen_on(bool on) {}
  769. double iron_frequency(void) {
  770. mach_timebase_info_data_t info;
  771. mach_timebase_info(&info);
  772. return (double)info.denom / (double)info.numer / 1e-9;
  773. }
  774. uint64_t iron_timestamp(void) {
  775. return mach_absolute_time();
  776. }
  777. #ifdef WITH_GAMEPAD
  778. bool iron_gamepad_connected(int num) {
  779. return true;
  780. }
  781. void iron_gamepad_rumble(int gamepad, float left, float right) {}
  782. #endif
  783. bool with_autoreleasepool(bool (*f)(void)) {
  784. @autoreleasepool {
  785. return f();
  786. }
  787. }
  788. const char *iron_get_resource_path(void) {
  789. return [[[NSBundle mainBundle] resourcePath] cStringUsingEncoding:NSUTF8StringEncoding];
  790. }
  791. @interface IronApplication : NSApplication {
  792. }
  793. - (void)terminate:(id)sender;
  794. @end
  795. @interface IronAppDelegate : NSObject <NSWindowDelegate> {
  796. }
  797. - (void)windowWillClose:(NSNotification *)notification;
  798. - (void)windowDidResize:(NSNotification *)notification;
  799. - (void)windowWillMiniaturize:(NSNotification *)notification;
  800. - (void)windowDidDeminiaturize:(NSNotification *)notification;
  801. - (void)windowDidResignMain:(NSNotification *)notification;
  802. - (void)windowDidBecomeMain:(NSNotification *)notification;
  803. @end
  804. static IronAppDelegate *delegate;
  805. CAMetalLayer *get_metal_layer(void) {
  806. return [view metalLayer];
  807. }
  808. id get_metal_device(void) {
  809. return [view metalDevice];
  810. }
  811. id get_metal_queue(void) {
  812. return [view metalQueue];
  813. }
  814. bool iron_internal_handle_messages(void) {
  815. NSEvent *event = [myapp nextEventMatchingMask:NSAnyEventMask
  816. untilDate:[NSDate distantPast]
  817. inMode:NSDefaultRunLoopMode
  818. dequeue:YES]; // distantPast: non-blocking
  819. if (event != nil) {
  820. [myapp sendEvent:event];
  821. [myapp updateWindows];
  822. }
  823. // Sleep for a frame to limit the calls when the window is not visible.
  824. if (!window.visible) {
  825. [NSThread sleepForTimeInterval:1.0 / 60];
  826. }
  827. return true;
  828. }
  829. static void createWindow(iron_window_options_t *options) {
  830. int width = options->width / [[NSScreen mainScreen] backingScaleFactor];
  831. int height = options->height / [[NSScreen mainScreen] backingScaleFactor];
  832. int styleMask = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable;
  833. if ((options->features & IRON_WINDOW_FEATURE_RESIZEABLE) || (options->features & IRON_WINDOW_FEATURE_MAXIMIZABLE)) {
  834. styleMask |= NSWindowStyleMaskResizable;
  835. }
  836. if (options->features & IRON_WINDOW_FEATURE_MINIMIZABLE) {
  837. styleMask |= NSWindowStyleMaskMiniaturizable;
  838. }
  839. view = [[BasicMTKView alloc] initWithFrame:NSMakeRect(0, 0, width, height)];
  840. [view registerForDraggedTypes:[NSArray arrayWithObjects:NSURLPboardType, nil]];
  841. window = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, width, height) styleMask:styleMask backing:NSBackingStoreBuffered defer:TRUE];
  842. delegate = [IronAppDelegate alloc];
  843. [window setDelegate:delegate];
  844. [window setTitle:[NSString stringWithCString:options->title encoding:NSUTF8StringEncoding]];
  845. [window setAcceptsMouseMovedEvents:YES];
  846. [[window contentView] addSubview:view];
  847. [window center];
  848. windows[0].handle = window;
  849. windows[0].view = view;
  850. [window makeKeyAndOrderFront:nil];
  851. if (options->mode == IRON_WINDOW_MODE_FULLSCREEN) {
  852. [window toggleFullScreen:nil];
  853. windows[0].fullscreen = true;
  854. }
  855. }
  856. void iron_window_change_window_mode(iron_window_mode_t mode) {
  857. switch (mode) {
  858. case IRON_WINDOW_MODE_WINDOW:
  859. if (windows[0].fullscreen) {
  860. [window toggleFullScreen:nil];
  861. windows[0].fullscreen = false;
  862. }
  863. break;
  864. case IRON_WINDOW_MODE_FULLSCREEN:
  865. if (!windows[0].fullscreen) {
  866. [window toggleFullScreen:nil];
  867. windows[0].fullscreen = true;
  868. }
  869. break;
  870. }
  871. }
  872. void iron_window_set_close_callback(bool (*callback)(void *), void *data) {
  873. windows[0].closeCallback = callback;
  874. windows[0].closeCallbackData = data;
  875. }
  876. static void add_menubar(void) {
  877. NSString *appName = [[NSProcessInfo processInfo] processName];
  878. NSMenu *appMenu = [NSMenu new];
  879. NSString *quitTitle = [@"Quit " stringByAppendingString:appName];
  880. NSMenuItem *quitMenuItem = [[NSMenuItem alloc] initWithTitle:quitTitle action:@selector(terminate:) keyEquivalent:@"q"];
  881. [appMenu addItem:quitMenuItem];
  882. NSMenuItem *appMenuItem = [NSMenuItem new];
  883. [appMenuItem setSubmenu:appMenu];
  884. NSMenu *menubar = [NSMenu new];
  885. [menubar addItem:appMenuItem];
  886. [NSApp setMainMenu:menubar];
  887. }
  888. void iron_init(iron_window_options_t *win) {
  889. @autoreleasepool {
  890. myapp = [IronApplication sharedApplication];
  891. [myapp finishLaunching];
  892. [[NSRunningApplication currentApplication] activateWithOptions:(NSApplicationActivateAllWindows | NSApplicationActivateIgnoringOtherApps)];
  893. NSApp.activationPolicy = NSApplicationActivationPolicyRegular;
  894. add_menubar();
  895. #ifdef WITH_GAMEPAD
  896. hidManager = (struct HIDManager *)malloc(sizeof(struct HIDManager));
  897. HIDManager_init(hidManager);
  898. #endif
  899. }
  900. createWindow(win);
  901. gpu_init(win->depth_bits, true);
  902. }
  903. int iron_window_width() {
  904. NSWindow *window = windows[0].handle;
  905. float scale = [window backingScaleFactor];
  906. return [[window contentView] frame].size.width * scale;
  907. }
  908. int iron_window_height() {
  909. NSWindow *window = windows[0].handle;
  910. float scale = [window backingScaleFactor];
  911. return [[window contentView] frame].size.height * scale;
  912. }
  913. NSWindow *iron_get_mac_window_handle() {
  914. return windows[0].handle;
  915. }
  916. void iron_load_url(const char *url) {
  917. [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[NSString stringWithUTF8String:url]]];
  918. }
  919. const char *iron_language(void) {
  920. NSString *nsstr = [[NSLocale preferredLanguages] objectAtIndex:0];
  921. const char *lang = [nsstr UTF8String];
  922. language[0] = lang[0];
  923. language[1] = lang[1];
  924. language[2] = 0;
  925. return language;
  926. }
  927. void iron_internal_shutdown(void) {}
  928. const char *iron_internal_save_path(void) {
  929. NSArray *paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES);
  930. NSString *resolvedPath = [paths objectAtIndex:0];
  931. NSString *appName = [NSString stringWithUTF8String:iron_application_name()];
  932. resolvedPath = [resolvedPath stringByAppendingPathComponent:appName];
  933. NSFileManager *fileMgr = [[NSFileManager alloc] init];
  934. NSError *error;
  935. [fileMgr createDirectoryAtPath:resolvedPath withIntermediateDirectories:YES attributes:nil error:&error];
  936. resolvedPath = [resolvedPath stringByAppendingString:@"/"];
  937. return [resolvedPath cStringUsingEncoding:NSUTF8StringEncoding];
  938. }
  939. #ifndef IRON_NO_MAIN
  940. int main(int argc, char **argv) {
  941. return kickstart(argc, argv);
  942. }
  943. #endif
  944. @implementation IronApplication
  945. - (void)terminate:(id)sender {
  946. iron_stop();
  947. }
  948. @end
  949. @implementation IronAppDelegate
  950. - (BOOL)windowShouldClose:(NSWindow *)sender {
  951. if (windows[0].closeCallback != NULL) {
  952. if (windows[0].closeCallback(windows[0].closeCallbackData)) {
  953. return YES;
  954. }
  955. else {
  956. return NO;
  957. }
  958. }
  959. return YES;
  960. }
  961. - (void)windowWillClose:(NSNotification *)notification {
  962. iron_stop();
  963. }
  964. void iron_internal_call_resize_callback(int width, int height) {
  965. if (windows[0].resizeCallback != NULL) {
  966. windows[0].resizeCallback(width, height, windows[0].resizeCallbackData);
  967. }
  968. }
  969. - (void)windowDidResize:(NSNotification *)notification {
  970. NSWindow *window = [notification object];
  971. NSSize size = [[window contentView] frame].size;
  972. [view resize:size];
  973. float scale = [window backingScaleFactor];
  974. int w = size.width * scale;
  975. int h = size.height * scale;
  976. gpu_resize(w, h);
  977. iron_internal_call_resize_callback(w, h);
  978. }
  979. - (void)windowWillMiniaturize:(NSNotification *)notification {
  980. iron_internal_background_callback();
  981. }
  982. - (void)windowDidDeminiaturize:(NSNotification *)notification {
  983. iron_internal_foreground_callback();
  984. }
  985. - (void)windowDidResignMain:(NSNotification *)notification {
  986. iron_internal_pause_callback();
  987. }
  988. - (void)windowDidBecomeMain:(NSNotification *)notification {
  989. iron_internal_resume_callback();
  990. }
  991. @end
  992. int iron_window_x() {
  993. return 0;
  994. }
  995. int iron_window_y() {
  996. return 0;
  997. }
  998. void iron_window_resize(int width, int height) {}
  999. void iron_window_move(int x, int y) {}
  1000. void iron_window_change_mode(iron_window_mode_t mode) {}
  1001. void iron_window_destroy() {}
  1002. void iron_window_show() {}
  1003. void iron_window_hide() {}
  1004. void iron_window_set_title(const char *title) {}
  1005. void iron_window_create(iron_window_options_t *win) {}
  1006. void iron_window_set_resize_callback(void (*callback)(int x, int y, void *data), void *data) {
  1007. windows[0].resizeCallback = callback;
  1008. windows[0].resizeCallbackData = data;
  1009. }
  1010. iron_window_mode_t iron_window_get_mode() {
  1011. return IRON_WINDOW_MODE_WINDOW;
  1012. }
  1013. int iron_window_display() {
  1014. return 0;
  1015. }