win.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735
  1. // in this file, _Rect is os x Rect,
  2. // _Point is os x Point
  3. #define Point _Point
  4. #define Rect _Rect
  5. #include <Carbon/Carbon.h>
  6. #include <QuickTime/QuickTime.h> // for full screen
  7. #undef Rect
  8. #undef Point
  9. #undef nil
  10. #include "dat.h"
  11. #include "fns.h"
  12. #undef log2
  13. #include <draw.h>
  14. #include <memdraw.h>
  15. #include "cursor.h"
  16. #include "keyboard.h"
  17. #include "keycodes.h"
  18. #define Kup Up
  19. #define Kleft Left
  20. #define Kdown Down
  21. #define Kright Right
  22. #define Kalt LAlt
  23. #define Kctl LCtrl
  24. #define Kshift LShift
  25. #define Kpgup Pgup
  26. #define Kpgdown Pgdown
  27. #define Khome Home
  28. #define Kins Ins
  29. #define Kend End
  30. #define rWindowResource 128
  31. extern void flushmemscreen(Rectangle);
  32. Memimage *gscreen;
  33. static int readybit;
  34. static Rendez rend;
  35. static int triedscreen;
  36. ///
  37. // menu
  38. //
  39. static MenuRef windMenu;
  40. static MenuRef viewMenu;
  41. enum {
  42. kQuitCmd = 1,
  43. kFullScreenCmd = 2,
  44. };
  45. static WindowGroupRef winGroup = NULL;
  46. static WindowRef theWindow = NULL;
  47. static CGContextRef context;
  48. static CGDataProviderRef dataProviderRef;
  49. static CGImageRef fullScreenImage;
  50. static CGRect devRect;
  51. static CGRect bounds;
  52. static PasteboardRef appleclip;
  53. static _Rect winRect;
  54. static Boolean altPressed = false;
  55. static Boolean button2 = false;
  56. static Boolean button3 = false;
  57. static Boolean needflush = false;
  58. static int
  59. isready(void*a)
  60. {
  61. return readybit;
  62. }
  63. CGContextRef QuartzContext;
  64. static OSStatus MainWindowEventHandler(EventHandlerCallRef nextHandler, EventRef event, void *userData);
  65. static OSStatus MainWindowCommandHandler(EventHandlerCallRef nextHandler, EventRef event, void *userData);
  66. static void winproc(void *a);
  67. static void flushproc(void *a);
  68. void
  69. screeninit(void)
  70. {
  71. int fmt;
  72. int dx, dy;
  73. ProcessSerialNumber psn = { 0, kCurrentProcess };
  74. TransformProcessType(&psn, kProcessTransformToForegroundApplication);
  75. SetFrontProcess(&psn);
  76. fmt = XBGR32; //XRGB32;
  77. devRect = CGDisplayBounds(CGMainDisplayID());
  78. // devRect.origin.x = 0;
  79. // devRect.origin.y = 0;
  80. // devRect.size.width = 1024;
  81. // devRect.size.height = 768;
  82. dx = devRect.size.width;
  83. dy = devRect.size.height;
  84. if(1){ /* TO DO: new dev draw for changing screen size */
  85. dx = Xsize;
  86. dy = Ysize;
  87. }
  88. gscreen = allocmemimage(Rect(0,0,dx,dy), fmt);
  89. dataProviderRef = CGDataProviderCreateWithData(0, gscreen->data->bdata,
  90. dx * dy * 4, 0);
  91. fullScreenImage = CGImageCreate(dx, dy, 8, 32, dx * 4,
  92. CGColorSpaceCreateDeviceRGB(),
  93. kCGImageAlphaNoneSkipLast,
  94. dataProviderRef, 0, 0, kCGRenderingIntentDefault);
  95. kproc("osxscreen", winproc, nil, 0);
  96. kproc("osxflush", flushproc, nil, 0);
  97. Sleep(&rend, isready, nil);
  98. }
  99. void
  100. window_resized(void)
  101. {
  102. GetWindowBounds(theWindow, kWindowContentRgn, &winRect);
  103. bounds = CGRectMake(0, 0, winRect.right-winRect.left, winRect.bottom - winRect.top);
  104. }
  105. static void
  106. flushproc(void *a)
  107. {
  108. for(;;) {
  109. if(needflush) {
  110. drawqlock();
  111. needflush = false;
  112. QDBeginCGContext(GetWindowPort(theWindow), &context);
  113. CGContextFlush(context);
  114. QDEndCGContext(GetWindowPort(theWindow), &context);
  115. drawqunlock();
  116. }
  117. usleep(33333);
  118. }
  119. }
  120. static void
  121. winproc(void *a)
  122. {
  123. MenuItemIndex index;
  124. int dx, dy;
  125. winRect.left = 30;
  126. winRect.top = 60;
  127. dx = devRect.size.width*0.75; /* devRect is full screen; take only most of it */
  128. dy = devRect.size.height*0.75;
  129. if(1){ /* TO DO */
  130. dx = Xsize;
  131. dy = Ysize;
  132. }
  133. winRect.bottom = winRect.top + dy;
  134. winRect.right = winRect.left + dx;
  135. ClearMenuBar();
  136. InitCursor();
  137. CreateStandardWindowMenu(0, &windMenu);
  138. InsertMenu(windMenu, 0);
  139. CreateNewMenu(1004, 0, &viewMenu);
  140. SetMenuTitleWithCFString(viewMenu, CFSTR("View"));
  141. AppendMenuItemTextWithCFString(viewMenu, CFSTR("Full Screen"), 0,
  142. kFullScreenCmd, &index);
  143. SetMenuItemCommandKey(viewMenu, index, 0, 'F');
  144. AppendMenuItemTextWithCFString(viewMenu, CFSTR("ctrl-opt to return"),
  145. kMenuItemAttrDisabled,
  146. kFullScreenCmd, &index);
  147. InsertMenu(viewMenu, GetMenuID(windMenu));
  148. DrawMenuBar();
  149. uint32_t windowAttrs = 0
  150. | kWindowCloseBoxAttribute
  151. | kWindowCollapseBoxAttribute
  152. // | kWindowResizableAttribute // TO DO
  153. | kWindowStandardHandlerAttribute
  154. // | kWindowFullZoomAttribute // TO DO
  155. ;
  156. CreateNewWindow(kDocumentWindowClass, windowAttrs, &winRect, &theWindow);
  157. CreateWindowGroup(0, &winGroup);
  158. SetWindowGroup(theWindow, winGroup);
  159. SetWindowTitleWithCFString(theWindow, CFSTR("Inferno"));
  160. if(PasteboardCreate(kPasteboardClipboard, &appleclip) != noErr)
  161. sysfatal("pasteboard create failed");
  162. const EventTypeSpec commands[] = {
  163. { kEventClassWindow, kEventWindowClosed },
  164. { kEventClassWindow, kEventWindowBoundsChanged },
  165. { kEventClassCommand, kEventCommandProcess }
  166. };
  167. const EventTypeSpec events[] = {
  168. { kEventClassKeyboard, kEventRawKeyDown },
  169. { kEventClassKeyboard, kEventRawKeyModifiersChanged },
  170. { kEventClassKeyboard, kEventRawKeyRepeat },
  171. { kEventClassMouse, kEventMouseDown },
  172. { kEventClassMouse, kEventMouseUp },
  173. { kEventClassMouse, kEventMouseMoved },
  174. { kEventClassMouse, kEventMouseDragged },
  175. { kEventClassMouse, kEventMouseWheelMoved },
  176. };
  177. InstallApplicationEventHandler (
  178. NewEventHandlerUPP (MainWindowEventHandler),
  179. GetEventTypeCount(events),
  180. events,
  181. NULL,
  182. NULL);
  183. InstallWindowEventHandler (
  184. theWindow,
  185. NewEventHandlerUPP (MainWindowCommandHandler),
  186. GetEventTypeCount(commands),
  187. commands,
  188. theWindow,
  189. NULL);
  190. ShowWindow(theWindow);
  191. ShowMenuBar();
  192. window_resized();
  193. SelectWindow(theWindow);
  194. // Run the event loop
  195. readybit = 1;
  196. Wakeup(&rend);
  197. RunApplicationEventLoop();
  198. }
  199. static int
  200. convert_key(UInt32 key, UInt32 charcode)
  201. {
  202. switch(key) {
  203. case QZ_IBOOK_ENTER:
  204. case QZ_RETURN: return '\n';
  205. case QZ_ESCAPE: return 27;
  206. case QZ_BACKSPACE: return '\b';
  207. case QZ_LALT: return Kalt;
  208. case QZ_LCTRL: return Kctl;
  209. case QZ_LSHIFT: return Kshift;
  210. case QZ_F1: return KF+1;
  211. case QZ_F2: return KF+2;
  212. case QZ_F3: return KF+3;
  213. case QZ_F4: return KF+4;
  214. case QZ_F5: return KF+5;
  215. case QZ_F6: return KF+6;
  216. case QZ_F7: return KF+7;
  217. case QZ_F8: return KF+8;
  218. case QZ_F9: return KF+9;
  219. case QZ_F10: return KF+10;
  220. case QZ_F11: return KF+11;
  221. case QZ_F12: return KF+12;
  222. case QZ_INSERT: return Kins;
  223. case QZ_DELETE: return 0x7F;
  224. case QZ_HOME: return Khome;
  225. case QZ_END: return Kend;
  226. case QZ_KP_PLUS: return '+';
  227. case QZ_KP_MINUS: return '-';
  228. case QZ_TAB: return '\t';
  229. case QZ_PAGEUP: return Kpgup;
  230. case QZ_PAGEDOWN: return Kpgdown;
  231. case QZ_UP: return Kup;
  232. case QZ_DOWN: return Kdown;
  233. case QZ_LEFT: return Kleft;
  234. case QZ_RIGHT: return Kright;
  235. case QZ_KP_MULTIPLY: return '*';
  236. case QZ_KP_DIVIDE: return '/';
  237. case QZ_KP_ENTER: return '\n';
  238. case QZ_KP_PERIOD: return '.';
  239. case QZ_KP0: return '0';
  240. case QZ_KP1: return '1';
  241. case QZ_KP2: return '2';
  242. case QZ_KP3: return '3';
  243. case QZ_KP4: return '4';
  244. case QZ_KP5: return '5';
  245. case QZ_KP6: return '6';
  246. case QZ_KP7: return '7';
  247. case QZ_KP8: return '8';
  248. case QZ_KP9: return '9';
  249. default: return charcode;
  250. }
  251. }
  252. void
  253. sendbuttons(int b, int x, int y)
  254. {
  255. mousetrack(b, x, y, 0);
  256. }
  257. static Ptr fullScreenRestore;
  258. static int amFullScreen = 0;
  259. static WindowRef oldWindow = NULL;
  260. static void
  261. leave_full_screen(void)
  262. {
  263. if(amFullScreen){
  264. EndFullScreen(fullScreenRestore, 0);
  265. theWindow = oldWindow;
  266. ShowWindow(theWindow);
  267. amFullScreen = 0;
  268. window_resized();
  269. Rectangle rect = { { 0, 0 }, { bounds.size.width, bounds.size.height} };
  270. drawqlock();
  271. flushmemscreen(rect);
  272. drawqunlock();
  273. }
  274. }
  275. static void
  276. full_screen(void)
  277. {
  278. if(!amFullScreen){
  279. oldWindow = theWindow;
  280. HideWindow(theWindow);
  281. BeginFullScreen(&fullScreenRestore, 0, 0, 0, &theWindow, 0, 0);
  282. amFullScreen = 1;
  283. window_resized();
  284. Rectangle rect = { { 0, 0 },
  285. { bounds.size.width,
  286. bounds.size.height} };
  287. drawqlock();
  288. flushmemscreen(rect);
  289. drawqunlock();
  290. }
  291. }
  292. static OSStatus
  293. MainWindowEventHandler(EventHandlerCallRef nextHandler, EventRef event, void *userData)
  294. {
  295. OSStatus result = noErr;
  296. result = CallNextEventHandler(nextHandler, event);
  297. UInt32 class = GetEventClass (event);
  298. UInt32 kind = GetEventKind (event);
  299. static uint32_t mousebuttons = 0; // bitmask of buttons currently down
  300. static uint32_t mouseX = 0;
  301. static uint32_t mouseY = 0;
  302. if(class == kEventClassKeyboard) {
  303. char macCharCodes;
  304. UInt32 macKeyCode;
  305. UInt32 macKeyModifiers;
  306. GetEventParameter(event, kEventParamKeyMacCharCodes, typeChar,
  307. NULL, sizeof(macCharCodes), NULL, &macCharCodes);
  308. GetEventParameter(event, kEventParamKeyCode, typeUInt32, NULL,
  309. sizeof(macKeyCode), NULL, &macKeyCode);
  310. GetEventParameter(event, kEventParamKeyModifiers, typeUInt32, NULL,
  311. sizeof(macKeyModifiers), NULL, &macKeyModifiers);
  312. switch(kind) {
  313. case kEventRawKeyModifiersChanged:
  314. if (macKeyModifiers == (controlKey | optionKey)) leave_full_screen();
  315. switch(macKeyModifiers & (optionKey | cmdKey)) {
  316. case (optionKey | cmdKey):
  317. /* due to chording we need to handle the case when both
  318. * modifier keys are pressed at the same time.
  319. * currently it's only 2-3 snarf and the 3-2 noop
  320. */
  321. altPressed = true;
  322. if(mousebuttons & 1 || mousebuttons & 2 || mousebuttons & 4) {
  323. mousebuttons |= 2; /* set button 2 */
  324. mousebuttons |= 4; /* set button 3 */
  325. button2 = true;
  326. button3 = true;
  327. sendbuttons(mousebuttons, mouseX, mouseY);
  328. }
  329. break;
  330. case optionKey:
  331. altPressed = true;
  332. if(mousebuttons & 1 || mousebuttons & 4) {
  333. mousebuttons |= 2; /* set button 2 */
  334. button2 = true;
  335. sendbuttons(mousebuttons, mouseX, mouseY);
  336. }
  337. break;
  338. case cmdKey:
  339. if(mousebuttons & 1 || mousebuttons & 2) {
  340. mousebuttons |= 4; /* set button 3 */
  341. button3 = true;
  342. sendbuttons(mousebuttons, mouseX, mouseY);
  343. }else
  344. gkbdputc(gkbdq, Latin);
  345. break;
  346. case 0:
  347. default:
  348. if(button2 || button3) {
  349. if(button2) {
  350. mousebuttons &= ~2; /* clear button 2 */
  351. button2 = false;
  352. altPressed = false;
  353. }
  354. if(button3) {
  355. mousebuttons &= ~4; /* clear button 3 */
  356. button3 = false;
  357. }
  358. sendbuttons(mousebuttons, mouseX, mouseY);
  359. }
  360. if(altPressed) {
  361. gkbdputc(gkbdq, Kalt);
  362. altPressed = false;
  363. }
  364. break;
  365. }
  366. break;
  367. case kEventRawKeyDown:
  368. case kEventRawKeyRepeat:
  369. if(macKeyModifiers != cmdKey) {
  370. int key;
  371. key = convert_key(macKeyCode, macCharCodes);
  372. if(key != -1)
  373. gkbdputc(gkbdq, key);
  374. }else
  375. result = eventNotHandledErr;
  376. break;
  377. default:
  378. break;
  379. }
  380. }
  381. else if(class == kEventClassMouse) {
  382. _Point mousePos;
  383. GetEventParameter(event, kEventParamMouseLocation, typeQDPoint,
  384. 0, sizeof mousePos, 0, &mousePos);
  385. switch(kind) {
  386. case kEventMouseWheelMoved:
  387. {
  388. int32_t wheeldelta;
  389. GetEventParameter(event,kEventParamMouseWheelDelta,typeSInt32,
  390. 0,sizeof(wheeldelta), 0, &wheeldelta);
  391. mouseX = mousePos.h - winRect.left;
  392. mouseY = mousePos.v - winRect.top;
  393. sendbuttons(wheeldelta>0 ? 8 : 16, mouseX, mouseY);
  394. break;
  395. }
  396. case kEventMouseUp:
  397. case kEventMouseDown:
  398. {
  399. uint32_t buttons;
  400. uint32_t modifiers;
  401. uint32_t clkcnt;
  402. GetEventParameter(event, kEventParamKeyModifiers, typeUInt32,
  403. 0, sizeof(modifiers), 0, &modifiers);
  404. GetEventParameter(event, kEventParamMouseChord, typeUInt32,
  405. 0, sizeof buttons, 0, &buttons);
  406. GetEventParameter(event, kEventParamClickCount, typeUInt32,
  407. 0, sizeof(clkcnt), 0, &clkcnt);
  408. /* simulate other buttons via alt/apple key. like x11 */
  409. if(modifiers & optionKey) {
  410. mousebuttons = ((buttons & 1) ? 2 : 0);
  411. altPressed = false;
  412. } else if(modifiers & cmdKey)
  413. mousebuttons = ((buttons & 1) ? 4 : 0);
  414. else
  415. mousebuttons = (buttons & 1);
  416. mousebuttons |= ((buttons & 2)<<1);
  417. mousebuttons |= ((buttons & 4)>>1);
  418. if(clkcnt > 1)
  419. mousebuttons |= 1<<8;
  420. } /* Fallthrough */
  421. case kEventMouseMoved:
  422. case kEventMouseDragged:
  423. mouseX = mousePos.h - winRect.left;
  424. mouseY = mousePos.v - winRect.top;
  425. sendbuttons(mousebuttons, mouseX, mouseY);
  426. break;
  427. default:
  428. result = eventNotHandledErr;
  429. break;
  430. }
  431. }
  432. return result;
  433. }
  434. //default window command handler (from menus)
  435. static OSStatus
  436. MainWindowCommandHandler(EventHandlerCallRef nextHandler, EventRef event, void *userData)
  437. {
  438. OSStatus result = noErr;
  439. UInt32 class = GetEventClass (event);
  440. UInt32 kind = GetEventKind (event);
  441. result = CallNextEventHandler(nextHandler, event);
  442. if(class == kEventClassCommand) {
  443. HICommand theHICommand;
  444. GetEventParameter(event, kEventParamDirectObject, typeHICommand,
  445. NULL, sizeof(HICommand), NULL, &theHICommand);
  446. switch(theHICommand.commandID) {
  447. case kHICommandQuit:
  448. cleanexit(0);
  449. break;
  450. case kFullScreenCmd:
  451. full_screen();
  452. break;
  453. default:
  454. result = eventNotHandledErr;
  455. break;
  456. }
  457. } else if(class == kEventClassWindow) {
  458. WindowRef window;
  459. _Rect rectPort = {0,0,0,0};
  460. GetEventParameter(event, kEventParamDirectObject, typeWindowRef,
  461. NULL, sizeof(WindowRef), NULL, &window);
  462. if(window)
  463. GetPortBounds(GetWindowPort(window), &rectPort);
  464. switch(kind) {
  465. case kEventWindowClosed:
  466. theWindow = NULL;
  467. cleanexit(0); // only one window
  468. break;
  469. //resize window
  470. case kEventWindowBoundsChanged:
  471. window_resized();
  472. Rectangle rect = { { 0, 0 },
  473. { bounds.size.width,
  474. bounds.size.height} };
  475. drawqlock();
  476. flushmemscreen(rect);
  477. drawqunlock();
  478. break;
  479. default:
  480. result = eventNotHandledErr;
  481. break;
  482. }
  483. }
  484. return result;
  485. }
  486. void
  487. flushmemscreen(Rectangle r)
  488. {
  489. CGRect rbounds;
  490. // sanity check. Trips from the initial "terminal"
  491. if (r.max.x < r.min.x || r.max.y < r.min.y)
  492. return;
  493. rbounds.size.width = r.max.x - r.min.x;
  494. rbounds.size.height = r.max.y - r.min.y;
  495. rbounds.origin.x = r.min.x;
  496. rbounds.origin.y = r.min.y;
  497. if(rbounds.size.width <= 0 || rbounds.size.height <= 0)
  498. return;
  499. QDBeginCGContext(GetWindowPort(theWindow), &context);
  500. // The sub-image is relative to our whole screen image.
  501. CGImageRef subimg = CGImageCreateWithImageInRect(fullScreenImage, rbounds);
  502. // Drawing the sub-image is relative to the window.
  503. rbounds.origin.y = winRect.bottom - winRect.top - r.min.y - rbounds.size.height;
  504. CGContextDrawImage(context, rbounds, subimg);
  505. CGImageRelease(subimg);
  506. QDEndCGContext(GetWindowPort(theWindow), &context);
  507. needflush = true;
  508. }
  509. uchar*
  510. attachscreen(Rectangle *r, ulong *chan, int *depth, int *width, int *softscreen)
  511. {
  512. if(!triedscreen) {
  513. triedscreen = 1;
  514. screeninit(); /* TO DO: call this elsewhere? */
  515. }
  516. *r = gscreen->r;
  517. *chan = gscreen->chan;
  518. *depth = gscreen->depth;
  519. *width = gscreen->width;
  520. *softscreen = 1;
  521. return gscreen->data->bdata;
  522. }
  523. // PAL - no palette handling. Don't intend to either.
  524. void
  525. getcolor(ulong i, ulong *r, ulong *g, ulong *b)
  526. {
  527. // PAL: Certainly wrong to return a grayscale.
  528. *r = i;
  529. *g = i;
  530. *b = i;
  531. }
  532. void
  533. setcolor(ulong index, ulong r, ulong g, ulong b)
  534. {
  535. USED(index); USED(r); USED(g); USED(b);
  536. }
  537. enum{
  538. SnarfSize= 100*1024
  539. };
  540. static char snarf[3*SnarfSize+1];
  541. static Rune rsnarf[SnarfSize+1];
  542. char*
  543. clipread(void)
  544. {
  545. CFDataRef cfdata;
  546. OSStatus err = noErr;
  547. ItemCount nitems;
  548. int i;
  549. char *s;
  550. if(appleclip == NULL)
  551. return nil;
  552. // Wow. This is ridiculously complicated.
  553. PasteboardSynchronize(appleclip);
  554. if((err = PasteboardGetItemCount(appleclip, &nitems)) != noErr) {
  555. fprint(2, "apple pasteboard GetItemCount failed - Error %d\n", err);
  556. return 0;
  557. }
  558. // Yes, based at 1. Silly API.
  559. for(i = 1; i <= nitems; i++) {
  560. PasteboardItemID itemID;
  561. CFArrayRef flavorTypeArray;
  562. CFIndex flavorCount;
  563. if((err = PasteboardGetItemIdentifier(appleclip, i, &itemID)) != noErr){
  564. fprint(2, "Can't get pasteboard item identifier: %d\n", err);
  565. return 0;
  566. }
  567. if((err = PasteboardCopyItemFlavors(appleclip, itemID, &flavorTypeArray))!=noErr){
  568. fprint(2, "Can't copy pasteboard item flavors: %d\n", err);
  569. return 0;
  570. }
  571. flavorCount = CFArrayGetCount(flavorTypeArray);
  572. CFIndex flavorIndex;
  573. for(flavorIndex = 0; flavorIndex < flavorCount; ++flavorIndex){
  574. CFStringRef flavorType;
  575. flavorType = (CFStringRef)CFArrayGetValueAtIndex(flavorTypeArray, flavorIndex);
  576. if (UTTypeConformsTo(flavorType, CFSTR("public.utf16-plain-text"))){
  577. if((err = PasteboardCopyItemFlavorData(appleclip, itemID,
  578. CFSTR("public.utf16-plain-text"), &cfdata)) != noErr){
  579. fprint(2, "apple pasteboard CopyItem failed - Error %d\n", err);
  580. return 0;
  581. }
  582. CFIndex length = CFDataGetLength(cfdata);
  583. if (length > sizeof rsnarf) length = sizeof rsnarf;
  584. CFDataGetBytes(cfdata, CFRangeMake(0, length), (uint8_t *)rsnarf);
  585. snprint(snarf, sizeof snarf, "%.*S", length/sizeof(Rune), rsnarf);
  586. for(s = snarf; *s; s++)
  587. if(*s == '\r')
  588. *s = '\n';
  589. CFRelease(cfdata);
  590. return strdup(snarf);
  591. }
  592. }
  593. }
  594. return 0;
  595. }
  596. int
  597. clipwrite(char *snarf)
  598. {
  599. CFDataRef cfdata;
  600. PasteboardSyncFlags flags;
  601. if(appleclip == NULL)
  602. return 0;
  603. runeseprint(rsnarf, rsnarf+nelem(rsnarf), "%s", snarf);
  604. if(PasteboardClear(appleclip) != noErr){
  605. fprint(2, "apple pasteboard clear failed\n");
  606. return 0;
  607. }
  608. flags = PasteboardSynchronize(appleclip);
  609. if((flags&kPasteboardModified) || !(flags&kPasteboardClientIsOwner)){
  610. fprint(2, "apple pasteboard cannot assert ownership\n");
  611. return 0;
  612. }
  613. cfdata = CFDataCreate(kCFAllocatorDefault, (uchar*)rsnarf, runestrlen(rsnarf)*2);
  614. if(cfdata == nil){
  615. fprint(2, "apple pasteboard cfdatacreate failed\n");
  616. return 0;
  617. }
  618. if(PasteboardPutItemFlavor(appleclip, (PasteboardItemID)1,
  619. CFSTR("public.utf16-plain-text"), cfdata, 0) != noErr){
  620. fprint(2, "apple pasteboard putitem failed\n");
  621. CFRelease(cfdata);
  622. return 0;
  623. }
  624. CFRelease(cfdata);
  625. return 1;
  626. }
  627. void
  628. setpointer(int x, int y)
  629. {
  630. CGPoint pnt;
  631. pnt.x = x + winRect.left;
  632. pnt.y = y + winRect.top;
  633. CGWarpMouseCursorPosition(pnt);
  634. }
  635. void
  636. drawcursor(Drawcursor* c)
  637. {
  638. USED(c);
  639. /* removed, pending extensive change for newer MacOS X */
  640. }