| /* | |
| * $Id: carbon.c,v 1.2 2005/08/06 21:09:03 phil Exp $ | |
| * Mac OS X Carbon support for XY display simulator | |
| * John Dundas <dundas@caltech.edu> | |
| * December 2004 | |
| * | |
| * This is a simplistic driver under Mac OS Carbon for the XY display | |
| * simulator. | |
| * | |
| * A more interesting driver would use OpenGL directly. | |
| */ | |
| #include <Carbon/Carbon.h> | |
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| #include "ws.h" | |
| #include "display.h" | |
| #include <sys/types.h> | |
| #include <sys/time.h> | |
| #define ARRAYLEN(a) (sizeof (a) / sizeof (a[0])) | |
| #ifndef PIX_SIZE | |
| #define PIX_SIZE 1 | |
| #endif | |
| /* | |
| * light pen location | |
| * see ws.h for full description | |
| */ | |
| int ws_lp_x = -1; | |
| int ws_lp_y = -1; | |
| static RGBColor blckColor = { 0x0000, 0x0000, 0x0000 }; | |
| static RGBColor whteColor = { 0xFFFF, 0xFFFF, 0xFFFF }; | |
| static WindowRef mainWind; | |
| static RgnHandle rgn; | |
| static MouseTrackingRef mouseRef; | |
| static int xpixels, ypixels; | |
| static int buttons = 0; /* tracks state of all buttons */ | |
| static EventTargetRef EventDispatchTarget; | |
| void MyEventWait ( EventTimeout timeout ) /* double */ | |
| { | |
| EventRef theEvent; | |
| if (ReceiveNextEvent (0, NULL, timeout, true, &theEvent) == noErr) { | |
| SendEventToEventTarget (theEvent, EventDispatchTarget); | |
| ReleaseEvent (theEvent); | |
| } | |
| } | |
| static pascal OSStatus doMouseEvent ( EventHandlerCallRef handlerRef, | |
| EventRef event, | |
| void *userData ) | |
| { | |
| OSStatus err = eventNotHandledErr; | |
| Point start; | |
| GrafPtr prevPort; | |
| /* make sure the display is the current grafport */ | |
| if (!QDSwapPort (GetWindowPort (mainWind), &prevPort)) | |
| prevPort = NULL; | |
| switch (GetEventKind (event)) { | |
| case kEventMouseEntered: | |
| if (ActiveNonFloatingWindow () != mainWind) | |
| break; | |
| SetThemeCursor (kThemeCrossCursor); | |
| break; | |
| case kEventMouseExited: | |
| if (ActiveNonFloatingWindow () != mainWind) | |
| break; | |
| SetThemeCursor (kThemeArrowCursor); | |
| break; | |
| case kEventMouseDown: | |
| GetEventParameter (event, kEventParamMouseLocation, | |
| typeQDPoint, NULL, sizeof (typeQDPoint), NULL, &start); | |
| GlobalToLocal (&start); | |
| ws_lp_x = start.h; | |
| ws_lp_y = ypixels - start.v; | |
| display_lp_sw = 1; | |
| break; | |
| case kEventMouseUp: | |
| display_lp_sw = 0; | |
| ws_lp_x = ws_lp_y = -1; | |
| break; | |
| default: | |
| break; | |
| } | |
| if (prevPort) | |
| SetPort (prevPort); | |
| return (err); | |
| } | |
| static pascal OSStatus updateWindow ( EventHandlerCallRef handlerRef, | |
| EventRef event, | |
| void *userData ) | |
| { | |
| OSStatus err = eventNotHandledErr; | |
| switch (GetEventKind (event)) { | |
| case kEventWindowActivated: | |
| /* update menus */ | |
| break; | |
| case kEventWindowClose: /* Override window close */ | |
| err = noErr; | |
| break; | |
| case kEventWindowDrawContent: | |
| display_repaint (); | |
| err = noErr; | |
| default: | |
| break; | |
| } | |
| return (err); | |
| } | |
| static pascal OSStatus doKbdEvent ( EventHandlerCallRef handlerRef, | |
| EventRef event, | |
| void *userData ) | |
| { | |
| UInt32 c, m; | |
| char key; | |
| GetEventParameter (event, kEventParamKeyCode, | |
| typeUInt32, NULL, sizeof (typeUInt32), NULL, &c); | |
| GetEventParameter (event, kEventParamKeyMacCharCodes, | |
| typeChar, NULL, sizeof (typeChar), NULL, &key); | |
| GetEventParameter (event, kEventParamKeyModifiers, | |
| typeUInt32, NULL, sizeof (typeUInt32), NULL, &m); | |
| /* Keys with meta-modifiers are not allowed at this time. */ | |
| #define KEY_MODIFIERS (cmdKey | optionKey | kEventKeyModifierFnMask) | |
| if (m & KEY_MODIFIERS) | |
| return (eventNotHandledErr); | |
| switch (GetEventKind (event)) { | |
| case kEventRawKeyRepeat: | |
| case kEventRawKeyDown: | |
| display_keydown (key); | |
| break; | |
| case kEventRawKeyUp: | |
| display_keyup (key); | |
| break; | |
| default: | |
| break; | |
| } | |
| return (noErr); | |
| } | |
| int ws_init ( const char *crtname, /* crt type name */ | |
| int xp, /* screen size in pixels */ | |
| int yp, | |
| int colors, /* colors to support (not used) */ | |
| void *dptr) | |
| { | |
| WindowAttributes windowAttrs; | |
| Rect r; | |
| CFStringRef str; | |
| static MouseTrackingRegionID mouseID = { 'AAPL', 0 }; | |
| static const EventTypeSpec moEvent[] = { | |
| { kEventClassMouse, kEventMouseEntered }, | |
| { kEventClassMouse, kEventMouseExited }, | |
| { kEventClassMouse, kEventMouseDown }, | |
| { kEventClassMouse, kEventMouseUp }, | |
| }; | |
| static const EventTypeSpec wuEvent[] = { | |
| { kEventClassWindow, kEventWindowDrawContent }, | |
| { kEventClassWindow, kEventWindowClose }, | |
| { kEventClassWindow, kEventWindowActivated}, | |
| }; | |
| static const EventTypeSpec kdEvent[] = { | |
| { kEventClassKeyboard, kEventRawKeyDown }, | |
| { kEventClassKeyboard, kEventRawKeyRepeat }, | |
| { kEventClassKeyboard, kEventRawKeyUp}, | |
| }; | |
| xpixels = xp; /* save screen size */ | |
| ypixels = yp; | |
| r.top = 100; r.left = 100; r.bottom = r.top + yp; r.right = r.left + xp; | |
| /* should check this r against GetQDGlobalsScreenBits (&screen); */ | |
| windowAttrs = kWindowCollapseBoxAttribute | kWindowStandardHandlerAttribute; | |
| if (CreateNewWindow (kDocumentWindowClass, windowAttrs, &r, &mainWind) != noErr) | |
| return (0); | |
| if (str = CFStringCreateWithCString (kCFAllocatorDefault, crtname, | |
| kCFStringEncodingASCII)) { | |
| SetWindowTitleWithCFString (mainWind, str); | |
| CFRelease (str); | |
| } | |
| SetPortWindowPort (mainWind); | |
| /* | |
| * Setup to handle events | |
| */ | |
| EventDispatchTarget = GetEventDispatcherTarget (); | |
| InstallEventHandler (GetWindowEventTarget (mainWind), | |
| NewEventHandlerUPP (doMouseEvent), ARRAYLEN(moEvent), | |
| (EventTypeSpec *) &moEvent, NULL, NULL); | |
| InstallEventHandler (GetWindowEventTarget (mainWind), | |
| NewEventHandlerUPP (updateWindow), ARRAYLEN(wuEvent), | |
| (EventTypeSpec *) &wuEvent, NULL, NULL); | |
| InstallEventHandler (GetWindowEventTarget (mainWind), | |
| NewEventHandlerUPP (doKbdEvent), ARRAYLEN(kdEvent), | |
| (EventTypeSpec *) &kdEvent, NULL, NULL); | |
| /* create region to track cursor shape */ | |
| r.top = 0; r.left = 0; r.bottom = yp; r.right = xp; | |
| rgn = NewRgn (); | |
| RectRgn (rgn, &r); | |
| CloseRgn (rgn); | |
| CreateMouseTrackingRegion (mainWind, rgn, NULL, | |
| kMouseTrackingOptionsLocalClip, mouseID, NULL, NULL, &mouseRef); | |
| ShowWindow (mainWind); | |
| RGBForeColor (&blckColor); | |
| PaintRect (&r); | |
| RGBBackColor (&blckColor); | |
| return (1); | |
| } | |
| void ws_shutdown (void) | |
| { | |
| } | |
| void *ws_color_black (void) | |
| { | |
| return (&blckColor); | |
| } | |
| void *ws_color_white (void) | |
| { | |
| return (&whteColor); | |
| } | |
| void *ws_color_rgb ( int r, | |
| int g, | |
| int b ) | |
| { | |
| RGBColor *color; | |
| if ((color = malloc (sizeof (RGBColor))) != NULL) { | |
| color->red = r; | |
| color->green = g; | |
| color->blue = b; | |
| } | |
| return (color); | |
| } | |
| /* put a point on the screen */ | |
| void ws_display_point ( int x, | |
| int y, | |
| void *color ) | |
| { | |
| #if PIX_SIZE != 1 | |
| Rect r; | |
| #endif | |
| if (x > xpixels || y > ypixels) | |
| return; | |
| y = ypixels - y /* - 1 */; | |
| #if PIX_SIZE == 1 | |
| SetCPixel (x, y, (color == NULL) ? &blckColor : color); | |
| #else | |
| r.top = y * PIX_SIZE; | |
| r.left = x * PIX_SIZE; | |
| r.bottom = (y + 1) * PIX_SIZE; | |
| r.right = (x + 1) * PIX_SIZE; | |
| RGBForeColor ((color == NULL) ? &blckColor : color); | |
| PaintRect (&r); | |
| #endif | |
| } | |
| void ws_sync (void) | |
| { | |
| ; | |
| } | |
| /* | |
| * elapsed wall clock time since last call | |
| * +INF on first call | |
| */ | |
| struct elapsed_state { | |
| struct timeval tvs[2]; | |
| int new; | |
| }; | |
| static unsigned long | |
| elapsed(struct elapsed_state *ep) | |
| { | |
| unsigned long val; | |
| gettimeofday(&ep->tvs[ep->new], NULL); | |
| if (ep->tvs[!ep->new].tv_sec == 0) | |
| val = ~0L; | |
| else | |
| val = ((ep->tvs[ep->new].tv_sec - ep->tvs[!ep->new].tv_sec) * 1000000 + | |
| (ep->tvs[ep->new].tv_usec - ep->tvs[!ep->new].tv_usec)); | |
| ep->new = !ep->new; | |
| return val; | |
| } | |
| /* called periodically */ | |
| int ws_poll ( int *valp, | |
| int maxusec ) | |
| { | |
| static struct elapsed_state es; /* static to avoid clearing! */ | |
| elapsed(&es); /* start clock */ | |
| do { | |
| unsigned long e; | |
| MyEventWait (maxusec * kEventDurationMicrosecond); | |
| e = elapsed(&es); | |
| maxusec -= e; | |
| } while (maxusec > 10000); /* 10ms */ | |
| return (1); | |
| } | |
| void ws_beep (void) | |
| { | |
| SysBeep (3); | |
| } | |
| /* public version, used by delay code */ | |
| unsigned long os_elapsed (void) | |
| { | |
| static struct elapsed_state es; | |
| return (elapsed (&es)); | |
| } |