/* * $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 * 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 #include #include #include #include "ws.h" #include "display.h" #include #include #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)); }