/* | |
* $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)); | |
} |