These changes facilitate more robust parameter type checking and helps to identify unexpected coding errors. Most simulators can now also be compiled with a C++ compiler without warnings. Additionally, these changes have also been configured to facilitate easier backporting of simulator and device simulation modules to run under the simh v3.9+ SCP framework.
333 lines
10 KiB
C
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 "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));
|
|
}
|