simh-testsetgenerator/display/carbon.c
Mark Pizzolato b804964514 PDP11, PDP1, TX-0: Added SDL based graphics support using sim_video.
Both VT11 and VS60 properly autoconfigure on the PDP11.
PDP11 now runs Lunar Lander on all SDL supported platforms.
Reworked refresh logic to not require internal delays in the display library
2016-01-29 10:16:30 -08:00

333 lines
10 KiB
C

/*
* $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 "xy.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 ( 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));
}