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