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.