This is ClockXDPS.c in view mode; [Download] [Up]
/*
* $RCSfile: ClockXDPS.c,v $
*
* Copyright (C) 1992 by Adobe Systems Incorporated.
* All rights reserved.
*
* Permission to use, copy, modify, and distribute this software and its
* documentation for any purpose and without fee is hereby granted,
* provided that the above copyright notices appear in all copies and that
* both those copyright notices and this permission notice appear in
* supporting documentation and that the name of Adobe Systems
* Incorporated not be used in advertising or publicity pertaining to
* distribution of the software without specific, written prior
* permission. If any portion of this software is changed, it cannot be
* marketed under Adobe's trademarks and/or copyrights unless Adobe, in
* its sole discretion, approves by a prior writing the quality of the
* resulting implementation.
*
* ADOBE MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF THE SOFTWARE FOR
* ANY PURPOSE. IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY.
* ADOBE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
* IMPLIED WARRANTIES OF MERCHANTABILITY FITNESS FOR A PARTICULAR PURPOSE AND
* NON-INFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL ADOBE BE LIABLE
* TO YOU OR ANY OTHER PARTY FOR ANY SPECIAL, INDIRECT, OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE, STRICT LIABILITY OR ANY OTHER ACTION ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ADOBE WILL NOT
* PROVIDE ANY TRAINING OR OTHER SUPPORT FOR THE SOFTWARE.
*
* PostScript, Display PostScript, and Adobe are trademarks of Adobe Systems
* Incorporated registered in the U.S.A. and other countries.
*
* Author: Adobe Systems Incorporated
*/
/***************************************************************
**
** INCLUDE FILES
**
***************************************************************/
#include "Clock.h"
#include "ClockWraps.h"
/***************************************************************
**
** DATA DECLARATIONS
**
***************************************************************/
/*
* Start time for measurement
*/
static struct timeval StartTime;
static void markTime(), returnTime();
/*
** These are the userpath operands and operators for the clock hands.
** They are sent and stored in the server.
*/
static float ptsHour[] = {
-4.5, 0, /* dps_moveto */
0, 100, /* dps_rlineto */
0, 100, 4.5, 180, 0, /* dps_arcn */
0, -100, /* dps_rlineto */
/* dps_closepath */
0, 0, /* dps_moveto */
0, 0, 10, 360, 0 /* dps_arcn */
/* dps_closepath */
};
static float bboxHour[] = {-10, -10, 10, 150};
static char opsHour[] = {
dps_moveto, dps_rlineto, dps_arcn, dps_rlineto,
dps_closepath, dps_moveto, dps_arcn, dps_closepath
};
static float ptsMin[] = {
-4.5, 0, /* dps_moveto */
0, 132, /* dps_rlineto */
0, 132, 4.5, 180, 0, /* dps_arcn */
0, -132, /* dps_rlineto */
/* dps_closepath */
0, 0, /* dps_moveto */
0, 0, 10, 360, 0 /* dps_arcn */
/* dps_closepath */
};
static float bboxMin[] = {-10, -10, 10, 145};
static char opsMin[] = {
dps_moveto, dps_rlineto, dps_arcn, dps_rlineto,
dps_closepath, dps_moveto, dps_arcn, dps_closepath
};
static float ptsSec[] = {
-1.5, 0, /* dps_moveto */
0, 145, /* dps_rlineto */
3, 0, /* dps_rlineto */
0, -145, /* dps_rlineto */
4, 0, /* dps_rlineto */
0, -20, /* dps_rlineto */
0, -20, 5.5, 360, 180, /* dps_arcn */
0, 20, /* dps_rlineto */
4, 0, /* dps_rlineto */
/* dps_closepath */
0, 0, /* dps_moveto */
0, 0, 10, 360, 0 /* dps_arcn */
/* dsp_closepath */
};
static float bboxSec[] = {-10, -30, 10, 170};
static char opsSec[] = {
dps_moveto, dps_rlineto, dps_rlineto,
dps_rlineto, dps_rlineto, dps_rlineto, dps_arcn,
dps_rlineto, dps_rlineto, dps_closepath, dps_moveto,
dps_arcn, dps_closepath
};
static float ptsAlarmTop[] = {
-1.0, 100, /* dps_moveto */
0, 5, /* dps_rlineto */
0, 105, 1.0, 180, 0, /* dps_arcn */
0, -5 /* dps_rlineto */
/* dps_closepath */
};
static float bboxAlarmTop[] = {-5, 70, 5, 120};
static char opsAlarmTop[] = {
dps_moveto, dps_rlineto,
dps_arcn, dps_rlineto, dps_closepath};
static float ptsAlarmBot[] = {
-1.0, 0, /* dps_moveto */
0, 100, /* dps_rlineto */
2.0, 0, /* dps_rlineto */
0, -100 /* dps_rlineto */
/* dps_closepath */
};
static float bboxAlarmBot[] = {-5, -2, 5, 120};
static char opsAlarmBot[] = {
dps_moveto, dps_rlineto,
dps_rlineto, dps_rlineto, dps_closepath
};
/*
** Graphics state user object identifiers
*/
static DPSGState
gstateWindow = 0,
gstateBuffer = 0,
gstateHour = 0,
gstateMin = 0,
gstateSec = 0,
gstateShad = 0;
/*
** Clock hands userpaths user object identifiers
*/
static int
upathHour = 0,
upathMin = 0,
upathSec = 0,
upathAlarmTop = 0,
upathAlarmBot = 0;
/*
** Angle in degrees of clock hands
*/
static float
angleHour,
angleMin,
angleSec,
angleAlarm = 0;
/*
** Variables for transformation between DPS/X and
** X Window System coordinates
*/
static float Ctm[6], Invctm[6]; /* transformation matrices */
static int XOffset, YOffset; /* coordinate system offsets */
/***************************************************************
**
** FUNCTION: drawUpathLines
**
** DESCRIPTION: Use PSDoUserPath to draw the ticks of the clock
** indicating hours or minutes.
**
** PARAMETERS: clr gray scale color value
** wid line width
** startlen starting length from circle center
** endlen ending length from circle center
** deg delta angle in degrees
**
** RETURN: None.
**
***************************************************************/
static void drawUpathLines (clr, wid, startlen, endlen, deg)
float clr, wid, startlen, endlen, deg;
{
int i , j;
float angle;
float bbox[4];
float pts[MAX_PTS];
char ops[MAX_OPS];
/*
** Initialize the loop control variables
*/
deg = ABS (deg * RADIAN);
i = 0; j = 0;
for (angle = 0; angle < 2 * M_PI; angle += deg)
{
/*
** Calculate the coordinate points for the start of the angled
** line using standard trigometric calculations. Place the
** DPS 'moveto' operator into the operator array.
*/
pts[i++] = (floor) (cos (angle) * startlen);
pts[i++] = (floor) (sin (angle) * startlen);
ops[j++] = dps_moveto;
/*
** Calculate the coordinate points for the end of the angled
** line using standard trigometric calculations. Place the
** DPS 'lineto' operator into the operator array.
*/
pts[i++] = (floor) (cos (angle) * endlen);
pts[i++] = (floor) (sin (angle) * endlen);
ops[j++] = dps_lineto;
}
/*
** Set the draw color and line width
*/
PSsetgray (clr);
PSsetlinewidth (wid);
/*
** Define the bounding box
*/
bbox[0] = -CLOCKSIZE;
bbox[1] = -CLOCKSIZE;
bbox[2] = CLOCKSIZE;
bbox[3] = CLOCKSIZE;
/*
** Stroke all the lines in the userpath
*/
PSDoUserPath ((DPSPointer) pts, i, dps_float, ops, j,
(DPSPointer) bbox, dps_ustroke);
} /* end drawUpathLines () */
/***************************************************************
**
** FUNCTION: drawFace
**
** DESCRIPTION: Draws the clock face background
**
** PARAMETERS: None.
**
** RETURN: None.
**
***************************************************************/
static void drawFace ()
{
float radius;
/* Clear the page; add a little bit of slop */
PSWErasePage (CLRPAGE, -CLOCKSIZE - 2, -CLOCKSIZE - 2,
2*CLOCKSIZE + 4, 2*CLOCKSIZE + 4);
radius = CLOCKSIZE * SIZEDASHES;
/*
** Draw the filled circle that makes up the clock face
*/
PSWDrawCircle (radius, CLRCIRC, True);
/*
** Set the line cap parameter to round cap
*/
PSsetlinecap (1);
/*
** Draw the minute and hour tick marks around the face
*/
drawUpathLines (CLRMIN, WIDMIN, radius * LENMIN, radius, DEGMIN);
drawUpathLines (CLRHOUR, WIDHOUR, radius * LENHOUR, radius, DEGHOUR);
}
/***************************************************************
**
** FUNCTION: defineUPaths
**
** DESCRIPTION: Define the userpaths of the hands as user objects.
**
** PARAMETERS: None.
**
** RETURN: None.
**
***************************************************************/
static void defineUPaths ()
{
/*
** Setup hour hand userpath object
*/
PSDoUserPath (ptsHour, XtNumber(ptsHour),
dps_float, opsHour, XtNumber(opsHour),
bboxHour, dps_send);
upathHour = PSDefineAsUserObj();
/*
** Setup minute hand userpath object
*/
PSDoUserPath (ptsMin, XtNumber(ptsMin),
dps_float, opsMin, XtNumber(opsMin),
bboxMin, dps_send);
upathMin = PSDefineAsUserObj();
/*
** Setup second hand userpath object
*/
PSDoUserPath (ptsSec, XtNumber(ptsSec),
dps_float, opsSec, XtNumber(opsSec),
bboxSec, dps_send);
upathSec = PSDefineAsUserObj();
/*
** Setup top of alarm hand userpath object
*/
PSDoUserPath (ptsAlarmTop, XtNumber(ptsAlarmTop),
dps_float, opsAlarmTop, XtNumber(opsAlarmTop),
bboxAlarmTop, dps_send);
upathAlarmTop = PSDefineAsUserObj();
/*
** Setup bottom of alarm hand userpath object
*/
PSDoUserPath (ptsAlarmBot, XtNumber(ptsAlarmBot),
dps_float, opsAlarmBot, XtNumber(opsAlarmBot),
bboxAlarmBot, dps_send);
upathAlarmBot = PSDefineAsUserObj();
} /* end defineUPaths () */
/***************************************************************
**
** FUNCTION: definegstate
**
** DESCRIPTION: Define a new graphics state with a coordinate
** system translation, and new color and line
** width. The graphics state will retain the
** current scaling from the current graphics state.
**
** PARAMETERS: gstate graphics state user object identifier
** offsetX coordinate translation X offset
** offsetY coordinate translation Y offset
** color drawing color
** linewidth stroking line width
**
** RETURN: gstate graphics state user object identifier
**
***************************************************************/
static DPSGState definegstate (gstate, offsetX, offsetY, color, linewidth)
int gstate;
float offsetX, offsetY, color, linewidth;
{
/*
** Save the graphics state to allow for definition of a new
** graphics state
*/
PSgsave ();
/*
** Set the coordinate system translation, color, and line width
*/
PSWSetGraphicsParams (offsetX, offsetY, color, linewidth);
/*
** If this is the first time, capture a new gstate. If not,
** update the old gstate to the new values
*/
if (gstate == 0) XDPSCaptureContextGState(AppData.dpsCtxt, &gstate);
else XDPSUpdateContextGState(AppData.dpsCtxt, gstate);
/*
** Restore the graphics state
*/
PSgrestore ();
/*
** Return the graphics state user object identifier
*/
return gstate;
} /* end definegstate () */
/***************************************************************
**
** FUNCTION: defineGStates
**
** DESCRIPTION: Redefine the gsates because the CTM has changed
** as the result of the resizing the draw area.
**
** PARAMETERS: None.
**
** RETURN: None.
**
***************************************************************/
static void defineGStates ()
{
/*
** Define the hour hand graphics state user object
*/
gstateHour = definegstate (gstateHour, 0.0, 0.0,
CLRHANDS - 0.2, LNWIDHANDS);
/*
** Define the minute hand graphics state user object
*/
gstateMin = definegstate (gstateMin, OFFSETHANDSX, OFFSETHANDSY,
CLRHANDS - 0.2, LNWIDHANDS);
/*
** Define the second hand graphics state user object
*/
gstateSec = definegstate (gstateSec, 2 * OFFSETHANDSX, 2 * OFFSETHANDSY,
CLRSECOND, LNWIDSECOND);
/*
** Define the second hand shadow graphics state user object
*/
gstateShad = definegstate (gstateShad, 2 * OFFSETHANDSX + OFFSETSHADX,
2 * OFFSETHANDSY + OFFSETSHADY,
CLRSHADOW, LNWIDSECOND);
} /* end defineGStates () */
/***************************************************************
**
** FUNCTION: setGStates
**
** DESCRIPTION: Update gstates to reflect turning graphics states
** on or off. If now on, define new gstates. If now
** off, free old gstates and set either the buffer or
** window gstate for future rendering
**
** PARAMETERS: None.
**
** RETURN: None.
**
***************************************************************/
void setGStates ()
{
if (AppData.graphicStates) defineGStates();
else {
XDPSFreeContextGState(AppData.dpsCtxt, gstateHour);
XDPSFreeContextGState(AppData.dpsCtxt, gstateMin);
XDPSFreeContextGState(AppData.dpsCtxt, gstateSec);
XDPSFreeContextGState(AppData.dpsCtxt, gstateShad);
gstateHour = gstateMin = gstateSec = gstateShad = 0;
if (AppData.doubleBuffering) {
XDPSSetContextGState(AppData.dpsCtxt, gstateBuffer);
} else XDPSSetContextGState(AppData.dpsCtxt, gstateWindow);
}
} /* end restoreInitialGState () */
/***************************************************************
**
** FUNCTION: drawClockHand
**
** DESCRIPTION: Draws the clock hands using the userpath either
** as stored in the server or by sending them each
** time. The decision is based on user selection in
** the control panel in the timing window.
**
** PARAMETERS: hand number representing the hand to draw
**
** RETURN: None.
**
***************************************************************/
static void drawClockHand (hand)
int hand;
{
/*
** If userpaths in server was selected, the requested hand
** is drawn using the stored userpath
*/
if (AppData.serverPaths)
{
switch (hand)
{
case ALARM:
PSsetgray (CLRALARMTOP);
PSWUpathFill (upathAlarmTop);
PSsetgray (CLRALARMBOT);
PSWUpathFill (upathAlarmBot);
break;
case HOUR:
PSWUpathStrokeFill (upathHour);
break;
case MINUTE:
PSWUpathStrokeFill (upathMin);
break;
case SHADOW:
PSWUpathFill (upathSec);
break;
case SECOND:
PSWUpathFill (upathSec);
PSWDrawCircle (10.0, CLRSECOND - 0.2, False);
break;
}
}
/*
** If userpaths in server was not selected, the requested hand
** is drawn by sending the userpath to the server with PSDoUserPath()
*/
else
{
switch (hand)
{
case ALARM:
PSsetgray (CLRALARMTOP);
PSDoUserPath (ptsAlarmTop, XtNumber(ptsAlarmTop),
dps_float, opsAlarmTop, XtNumber(opsAlarmTop),
bboxAlarmTop, dps_ufill);
PSsetgray (CLRALARMBOT);
PSDoUserPath (ptsAlarmBot, XtNumber(ptsAlarmBot),
dps_float, opsAlarmBot, XtNumber(opsAlarmBot),
bboxAlarmBot, dps_ufill);
break;
case HOUR:
PSDoUserPath (ptsHour, XtNumber(ptsHour),
dps_float, opsHour, XtNumber(opsHour),
bboxHour, dps_ustroke);
PSsetgray (CLRHANDS);
PSDoUserPath (ptsHour, XtNumber(ptsHour),
dps_float, opsHour, XtNumber(opsHour),
bboxHour, dps_ufill);
break;
case MINUTE:
PSDoUserPath (ptsMin, XtNumber(ptsMin),
dps_float, opsMin, XtNumber(opsMin),
bboxMin, dps_ustroke);
PSsetgray (CLRHANDS);
PSDoUserPath (ptsMin, XtNumber(ptsMin),
dps_float, opsMin, XtNumber(opsMin),
bboxMin, dps_ufill);
break;
case SHADOW:
PSDoUserPath (ptsSec, XtNumber(ptsSec),
dps_float, opsSec, XtNumber(opsSec),
bboxSec, dps_ufill);
break;
case SECOND:
PSDoUserPath (ptsSec, XtNumber(ptsSec),
dps_float, opsSec, XtNumber(opsSec),
bboxSec, dps_ufill);
PSWDrawCircle (10.0, CLRSECOND - 0.2, False);
break;
}
}
} /* end drawClockHand () */
/***************************************************************
**
** FUNCTION: drawHands
**
** DESCRIPTION: Sets up the graphics state and draws the clock
** hands. Draws either with or without the gstate
** saved in the server as a user object. Decision
** is based on user selection in the control panel
** in the timing window. A slight performance
** advantage is gained with gstates but they use
** up an appreciable amount of memory so they
** should be used judiciously.
**
** PARAMETERS: None.
**
** RETURN: None.
**
***************************************************************/
void drawHands ()
{
/*
** If the graphics state drawing was selected, install the graphics
** state user object for the appropriate hand and draw the hand
*/
if (AppData.graphicStates)
{
PSgsave();
/*
** Alarm hand
*/
PSWInstallGstate (gstateHour, angleAlarm);
drawClockHand (ALARM);
/*
** Hour hand
*/
PSWInstallGstate (gstateHour, angleHour);
drawClockHand (HOUR);
/*
** Minute hand
*/
PSWInstallGstate (gstateMin, angleMin);
drawClockHand (MINUTE);
/*
** Second hand shadow
*/
PSWInstallGstate (gstateShad, angleSec);
drawClockHand (SHADOW);
/*
** Second hand
*/
PSWInstallGstate (gstateSec, angleSec);
drawClockHand (SECOND);
PSgrestore();
}
/*
** If the graphics state drawing was not selected, for each hand:
** save the current graphics state, set the color and line width,
** translate the origin, rotate the context, draw the hand, and
** restore the original graphics state for the next hand
*/
else
{
/*
** Alarm hand
*/
PSWPushDrawingParams(0.0, 0.0, 0.0, 0.0, angleAlarm);
drawClockHand (ALARM);
PSgrestore();
/*
** Hour hand
*/
PSWPushDrawingParams(0.0, 0.0, CLRHANDS - 0.2,
LNWIDHANDS, angleHour);
drawClockHand (HOUR);
PSgrestore();
/*
** Minute hand
*/
PSWPushDrawingParams(OFFSETHANDSX, OFFSETHANDSY,
CLRHANDS - 0.2, LNWIDHANDS, angleMin);
drawClockHand (MINUTE);
PSgrestore();
/*
** Second hand shadow
*/
PSWPushDrawingParams(2*OFFSETHANDSX + OFFSETSHADX,
2*OFFSETHANDSY + OFFSETSHADY,
CLRSHADOW, LNWIDSECOND, angleSec);
drawClockHand (SHADOW);
PSgrestore();
/*
** Second hand
*/
PSWPushDrawingParams(2 * OFFSETHANDSX, 2 * OFFSETHANDSY,
CLRSECOND, LNWIDSECOND, angleSec);
drawClockHand (SECOND);
PSgrestore ();
}
} /* end drawHands */
/***************************************************************
**
** FUNCTION: convertTimeToHandAngles
**
** DESCRIPTION: Get the current system time and calculate the
** angles of the hands.
**
** PARAMETERS: timeOfDay current time
**
** RETURN: None.
**
***************************************************************/
static void convertTimeToHandAngles (timeOfDay)
struct timeval *timeOfDay;
{
struct tm *localTime;
/*
** Get the current system time and convert to local time
*/
localTime = localtime (&timeOfDay->tv_sec);
/*
** Calculate the angles of the hour, minute, and second hands
*/
angleHour = ((localTime->tm_hour % 12) + localTime->tm_min/60.0) *
DEGHOUR;
angleMin = (localTime->tm_min + localTime->tm_sec/60.0) * DEGMIN;
angleSec = localTime->tm_sec * DEGMIN;
/*
** Save the millisecond value for later timer scheduling
*/
AppData.milliSecs = timeOfDay->tv_usec / 1000;
} /* end convertTimeToHandAngles () */
/***************************************************************
**
** FUNCTION: drawClockTime
**
** DESCRIPTION: Invoked each time the clock is drawn. The clock
** face pixmap is copied into the clock image
** pixmap. The current system time is obtained to
** determine the angles of the hands. The hands
** are then drawn into the clock image pixmap. The
** draw area window is cleared which copies the
** newly drawn clock image pixmap into the window.
**
** PARAMETERS: None.
**
** RETURN: None.
**
***************************************************************/
void drawClockTime ()
{
long elapsedTime;
static int depth;
static GC gc = NULL;
Display *dpy = XtDisplay(AppData.widget);
Window win = XtWindow(AppData.widget);
int total, i;
/*
** Create a GC for copying, and find depth of drawing area
*/
if (gc == NULL) {
gc = XCreateGC(dpy, win, 0, NULL);
XtVaGetValues(AppData.widget, XtNdepth, &depth, NULL);
}
/*
** If double buffering, create pixmap.
** Install as current drawable and capture a gstate
** If currently using gstates for hands, redefine them
*/
if (AppData.doubleBuffering && AppData.clockPixmap == None) {
AppData.clockPixmap = XCreatePixmap (dpy, win, AppData.Xwidth,
AppData.Xheight, depth);
PSWSetDrawable(AppData.clockPixmap,
AppData.Xwidth/2, AppData.Xheight/2);
XDPSCaptureContextGState(AppData.dpsCtxt, &gstateBuffer);
if (AppData.graphicStates) defineGStates();
}
/*
** If using a pixmap background, create pixmap and draw face into
** it. The DPSWaitContext for timing, after the if statement,
** guarantees synchronization.
*/
if (AppData.pixmapBackground && AppData.facePixmap == None) {
AppData.facePixmap =
XCreatePixmap (dpy, win,
AppData.Xwidth, AppData.Xheight,
depth);
/* Temporarily render into pixmap */
PSgsave();
PSWSetDrawable(AppData.facePixmap,
AppData.Xwidth/2, AppData.Xheight/2);
drawFace ();
PSgrestore();
}
/*
** Start timing and convert time into angles
*/
DPSWaitContext (AppData.dpsCtxt);
markTime ();
convertTimeToHandAngles(&StartTime);
/*
** If double buffering, draw into clock pixmap. Either copy face
** pixmap or redraw the face, then draw the hands, then copy into window.
** Assume current context is set to render into the clock pixmap.
** Must call DPSWaitContext to ensure drawing is done before copying
*/
if (AppData.doubleBuffering) {
if (AppData.pixmapBackground) {
XCopyArea (dpy, AppData.facePixmap, AppData.clockPixmap,
gc, 0, 0, AppData.Xwidth, AppData.Xheight, 0, 0);
} else { /* Do not use a predrawn face pixmap */
drawFace ();
}
drawHands ();
DPSWaitContext (AppData.dpsCtxt);
XCopyArea (dpy, AppData.clockPixmap, win, gc,
0, 0, AppData.Xwidth, AppData.Xheight, 0, 0);
} else {
/*
** If no double buffering, draw directly into window
*/
if (AppData.pixmapBackground) {
XCopyArea (dpy, AppData.facePixmap, win, gc,
0, 0, AppData.Xwidth, AppData.Xheight, 0, 0);
} else {
drawFace ();
}
drawHands ();
}
/*
** Wait for completion, then get elapsed time
*/
DPSWaitContext (AppData.dpsCtxt);
returnTime (&elapsedTime);
/*
** Increment time counters and set elapsed time into the display window
** Keep the last 5 times in the lastTimes array, and use their average
** as the displayed time.
*/
for (i = 4; i > 0; i--) AppData.lastTimes[i] = AppData.lastTimes[i-1];
AppData.lastTimes[0] = elapsedTime;
if (AppData.numIterations < 5) AppData.numIterations++;
total = 0;
for (i = 0; i < AppData.numIterations; i++) total += AppData.lastTimes[i];
setTimingValue (total / AppData.numIterations);
/*
** Increment the millisecond value for later timer scheduling
*/
AppData.milliSecs += elapsedTime;
if (AppData.trace)
XmToggleButtonSetState (AppData.traceToggle, False, True);
}
/***************************************************************
**
** FUNCTION: isHit
**
** DESCRIPTION: Check for hit detection. No boundary check is
** made because the alarm hand can reside in pretty
** much the whole draw area.
**
** PARAMETERS: x, y X Window System coordinates of mouse
**
** RETURN: hit hit flag indicating mouse hit alarm hand
**
***************************************************************/
int isHit (x, y)
int x, y;
{
Bool hit;
float ptX, ptY;
int xoffset, yoffset;
float ctm[6], invctm[6];
/*
** Rotate coordinate system underneath the mouse point, and get
** new transformation matrices
*/
PSgsave();
PSrotate(angleAlarm);
PSWGetTransform(ctm, invctm, &xoffset, &yoffset);
/*
** Convert mouse point into user space
*/
x -= xoffset;
y -= yoffset;
ptX = invctm[A_COEFF] * x + invctm[C_COEFF] * y + invctm[TX_CONS];
ptY = invctm[B_COEFF] * x + invctm[D_COEFF] * y + invctm[TY_CONS];
/*
** See if the point hits either the alarm top or bottom
*/
hit = PSHitUserPath(ptX, ptY, HITSETTING,
ptsAlarmTop, XtNumber(ptsAlarmTop), dps_float,
opsAlarmTop, XtNumber(opsAlarmTop), bboxAlarmTop,
dps_inufill);
if (!hit) {
hit = PSHitUserPath(ptX, ptY, HITSETTING,
ptsAlarmBot, XtNumber(ptsAlarmBot), dps_float,
opsAlarmBot, XtNumber(opsAlarmBot), bboxAlarmBot,
dps_inufill);
}
PSgrestore();
/*
** Return the hit flag
*/
return hit;
} /* end isHit () */
/***************************************************************
**
** FUNCTION: checkAlarm
**
** DESCRIPTION: Check for alarm time to ring. If it has rung in
** in this interval, it must clear the interval or
** be manually moved before it can ring again.
**
** PARAMETERS: None.
**
** RETURN: ring flag indicating it is time to ring alarm
**
***************************************************************/
int checkAlarm ()
{
int ring = FALSE;
static int hasRung = FALSE;
static float lastHour = 0.0;
static float lastAlarm = 0.0;
/*
** Determine if hour hand is within the alarm hand interval
*/
if (angleHour <= angleAlarm - ALARM_INTERVAL &&
angleHour >= angleAlarm + ALARM_INTERVAL) {
if (! hasRung) {
/*
** Set the ring flag
*/
hasRung = TRUE;
ring = TRUE;
}
} else {
/*
** Clear the has rung flag
*/
hasRung = FALSE;
}
/*
** Return the ring flag
*/
return ring;
} /* end checkAlarm () */
/***************************************************************
**
** FUNCTION: setAlarm
**
** DESCRIPTION: Enter a modal loop to redraw the alarm hand per
** mouse drag event.
**
** PARAMETERS: None.
**
** RETURN: None.
**
***************************************************************/
void setAlarm ()
{
XEvent event;
int tracking = TRUE;
int x, y;
float ptX, ptY;
Display *dpy = XtDisplay(AppData.widget);
/*
** Wait for the first button motion or release event
*/
XMaskEvent (dpy, ButtonMotionMask | ButtonReleaseMask, &event);
/*
** Loop collecting button motion events until a button release event
*/
while (tracking) {
/*
** Consolidate events currently on the queue
*/
while (XCheckMaskEvent(dpy, ButtonMotionMask | ButtonReleaseMask,
&event)) {
if (event.type == ButtonRelease) {
tracking = FALSE;
break;
}
} /* end while loop */
/*
** Compute the x,y coordinates of the button release in DPS units
*/
x = event.xbutton.x - XOffset;
y = event.xbutton.y - YOffset;
ptX = Invctm[A_COEFF] * x + Invctm[C_COEFF] * y + Invctm[TX_CONS];
ptY = Invctm[B_COEFF] * x + Invctm[D_COEFF] * y + Invctm[TY_CONS];
/*
** Compute the new alarm hand angle (-360 to 0 degrees)
*/
angleAlarm = atan2 ((double) ptY, (double) ptX) / RADIAN - 90.0;
if (angleAlarm > 0) angleAlarm -= 360;
/*
** Draw the clock with the new alarm hand angle and current time
*/
drawClockTime ();
} /* end while loop */
} /* end setAlarm () */
/***************************************************************
**
** FUNCTION: initDPSContext
**
** DESCRIPTION: Post-Realization initialization of DPSContext and such.
**
** PARAMETERS: None.
**
** RETURN: None.
**
***************************************************************/
void initDPSContext ()
{
Dimension height, width;
Display *dpy = XtDisplay(AppData.widget);
XSetWindowAttributes attr;
/*
** Get height of drawing window
*/
XtVaGetValues (AppData.widget, XtNheight, &height, XtNwidth, &width, NULL);
/*
** Create the DPSContext in which rendering will occur
*/
AppData.dpsCtxt = XDPSGetSharedContext(dpy);
(void) XDPSSetEventDelivery(dpy, dps_event_pass_through);
if (AppData.dpsCtxt == NULL) {
printf("Couldn't create a Display PostScript context.\n");
exit(1);
}
if (XDPSSetContextDrawable(AppData.dpsCtxt, XtWindow(AppData.widget),
height) != dps_status_success)
{
printf ("Couldn't set Display PostScript context drawable.\n");
exit (1);
}
/*
** Set the default DPSContext
*/
DPSSetContext (AppData.dpsCtxt);
XDPSChainTextContext (AppData.dpsCtxt, AppData.trace);
/*
** Save the initial graphics state
*/
XDPSCaptureContextGState(AppData.dpsCtxt, &gstateWindow);
/*
** Define the initial Window geometry
*/
PSWGetTransform (Ctm, Invctm, &XOffset, &YOffset);
handleWindowResize(AppData.widget, width, height);
/*
** Keep DPS origin in center of window
*/
attr.bit_gravity = CenterGravity;
XChangeWindowAttributes(dpy, XtWindow(AppData.widget),
CWBitGravity, &attr);
/*
** Define the userpaths and gstates for the drawing of the hands
*/
defineUPaths ();
} /* end initDPSContext () */
/***************************************************************
**
** FUNCTION: markTime
**
** DESCRIPTION: Mark the start time for an operation.
**
** PARAMETERS: None.
**
** RETURN: None.
**
***************************************************************/
static void markTime ()
{
gettimeofday (&StartTime, (struct timezone *)NULL);
}
/***************************************************************
**
** FUNCTION: returnTime
**
** DESCRIPTION: Return the elapsed time since markTime was called
** in milliseconds
**
** PARAMETERS: elapsedTime returned time in milliseconds
**
** RETURN: None.
**
***************************************************************/
static void returnTime (elapsedTime)
long *elapsedTime;
{
struct timeval endTime;
gettimeofday (&endTime, (struct timezone *)NULL);
*elapsedTime = (endTime.tv_sec - StartTime.tv_sec) * 1000 +
(endTime.tv_usec - StartTime.tv_usec)/1000;
}
/***************************************************************
**
** FUNCTION: handleWindowResize
**
** DESCRIPTION: Rescales coordinate system to reflect new window size
**
** PARAMETERS: w Widget that was resized
** newWidth New widget width
** newHeight New widget height
**
** RETURN: None.
**
***************************************************************/
void handleWindowResize (w, newWidth, newHeight)
Widget w;
int newWidth, newHeight;
{
float newDPSHeight, newDPSWidth;
int x, y;
float xScale, yScale;
if (AppData.doubleBuffering) {
XDPSSetContextGState(AppData.dpsCtxt, gstateWindow);
}
PSWSetOffset(newWidth/2, newHeight/2);
/*
** Compute coordinate of upper right corner in user space
*/
x = newWidth - newWidth/2;
y = 0 - newHeight/2;
newDPSWidth = Invctm[A_COEFF] * x + Invctm[C_COEFF] * y + Invctm[TX_CONS];
newDPSHeight = Invctm[B_COEFF] * x + Invctm[D_COEFF] * y + Invctm[TY_CONS];
xScale = newDPSWidth / CLOCKSIZE;
yScale = newDPSHeight / CLOCKSIZE;
PSscale (xScale, yScale);
PSinitclip();
PSinitviewclip();
PSWGetTransform (Ctm, Invctm, &XOffset, &YOffset);
AppData.Xwidth = newWidth;
AppData.Xheight = newHeight;
if (AppData.clockPixmap) {
XFreePixmap (XtDisplay(w), AppData.clockPixmap);
XDPSFreeContextGState(AppData.dpsCtxt, gstateBuffer);
}
if (AppData.facePixmap) XFreePixmap (XtDisplay(w), AppData.facePixmap);
AppData.clockPixmap = AppData.facePixmap = None;
XDPSUpdateContextGState(AppData.dpsCtxt, gstateWindow);
if (AppData.graphicStates && !AppData.doubleBuffering) defineGStates();
} /* end resizeWindow () */
/***************************************************************
**
** FUNCTION: setBufferRendering
**
** DESCRIPTION: Enable or disable rendering to offscreen buffer
**
** PARAMETERS: None
**
** RETURN: None.
**
***************************************************************/
void setBufferRendering()
{
if (AppData.doubleBuffering) {
if (AppData.clockPixmap != None) {
XDPSSetContextGState(AppData.dpsCtxt, gstateBuffer);
}
} else XDPSSetContextGState(AppData.dpsCtxt, gstateWindow);
if (AppData.graphicStates) defineGStates();
}
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.