cpu-disp.cc
//************************************************************************
// MODULE : CPU Scheduler display module *
// AUTHOR : Ron Chernich *
// PURPOSE: Perform all Graphic display actions (except clear screen) *
// associated with the CPU scheduler screen. *
// HISTORY: *
// 26-MAR-93 First (MSC/C++ 7.00) version *
// 29-APR-93 Bug animation routines added *
// 16-MAY-93 Snail Trail redraw made intelligent *
// 27-OCT-93 Smart Mouse pointer hiding added *
// 28-FEB-94 Label lost! - Cast GfxTextExtent to INT16 in DrawQueue *
// 25-AUG-94 All static funcs collected under a class umbrella *
//************************************************************************
#include "cpu-disp.hh"
#include "kernel.hh"
///////////////////////////////////////////////////////////////////////////
// On startup, ensure all path memory is "FALSE"
//
CpuAnim::CpuAnim (void)
{
for (int idx = 0; idx < 8; idx++)
bVis[idx] = FALSE;
}
///////////////////
// Bug Animator routine - passed a start and end point, animate a blot
// representing the current process between where it is now, and where
// it's headed. The animation paths support Deitel's model of a multi
// tasking OS, so "illogical" movements are ignored.
//
void CpuAnim::Anim (INT16 Start, INT16 Finish, BOOL bQuik)
{
point p1, p2;
switch (Start) {
case INPUT_Q:
p1.x = PT_INPUT_LX, p1.y = PT_INPUT_LY;
p2.x = PT_BUG_XMIN, p2.y = p1.y;
MoveBug(p1, p2, bQuik);
p1.x = p2.x, p1.y = PT_READY_LY;
MoveBug(p2, p1, bQuik);
p2.x = PT_READY_LX, p2.y = p1.y;
MoveBug(p1, p2, bQuik);
bVis[0] = TRUE;
break;
case SUSRDY_Q:
p1.x = PT_SUSRDY_LX, p1.y = PT_SUSRDY_LY;
p2.x = PT_BUG_XMIN, p2.y = p1.y;
MoveBug(p1, p2, bQuik);
p1.y = PT_READY_LY, p1.x = p2.x;
MoveBug(p2, p1, bQuik);
p2.x = PT_READY_LX, p2.y = p1.y;
MoveBug(p1, p2, bQuik);
bVis[5] = TRUE;
break;
case CPROC_BOX:
p1.x = PT_CPROC_X, p1.y = PT_CPROC_Y;
switch (Finish) {
case BLOKED_Q:
p2.x = p1.x, p2.y = PT_BLOKED_LY;
MoveBug(p1, p2, bQuik);
p1.x = PT_BLOKED_LX, p1.y = p2.y;
MoveBug(p2, p1, bQuik);
bVis[3] = TRUE;
break;
case READY_Q:
p2.x = p1.x, p2.y = PT_BUG_YMIN;
MoveBug(p1, p2, bQuik);
p1.x = PT_BUG_XMIN, p1.y = p2.y;
MoveBug(p2, p1, bQuik);
p2.x = p1.x, p2.y = PT_READY_LY;
MoveBug(p1, p2, bQuik);
p1.x = PT_READY_LX, p1.y = p2.y;
MoveBug(p2, p1, bQuik);
bVis[2] = TRUE;
break;
}
break;
case READY_Q:
switch (Finish) {
case CPROC_BOX:
p1.x = PT_READY_RX, p1.y = PT_READY_RY;
p2.x = PT_CPROC_X, p2.y = p1.y;
MoveBug(p1, p2, bQuik);
p1.x = PT_CPROC_X, p1.y = PT_CPROC_Y;
MoveBug(p2, p1, bQuik);
bVis[1] = TRUE;
break;
case SUSRDY_Q:
p1.x = PT_READY_LX, p1.y = PT_READY_LY;
p2.x = PT_BUG_XMIN, p2.y = p1.y;
MoveBug(p1, p2, bQuik);
p1.x = p2.x, p1.y = PT_SUSRDY_LY;
MoveBug(p2, p1, bQuik);
p2.x = PT_SUSRDY_LX, p2.y = p1.y;
MoveBug(p1, p2, bQuik);
bVis[5] = TRUE;
break;
}
break;
case BLOKED_Q:
p1.x = PT_BLOKED_RX, p1.y = PT_BLOKED_RY;
p2.x = PT_BUG_XMAX, p2.y = p1.y;
MoveBug(p1, p2, bQuik);
switch (Finish) {
case READY_Q:
p1.x = p2.x, p1.y = PT_BUG_YMIN;
MoveBug(p2, p1, bQuik);
p2.x = PT_BUG_XMIN, p2.y = p1.y;
MoveBug(p1, p2, bQuik);
p1.x = p2.x, p1.y = PT_READY_LY;
MoveBug(p2, p1, bQuik);
p2.x = PT_READY_LX, p2.y = p1.y;
MoveBug(p1, p2, bQuik);
bVis[4] = TRUE;
break;
case SUSBLK_Q:
p1.x = p2.x, p1.y = PT_SUSBLK_RY;
MoveBug(p2, p1, bQuik);
p2.x = PT_SUSBLK_RX, p2.y = p1.y;
MoveBug(p1, p2, bQuik);
bVis[6] = TRUE;
break;
}
break;
case SUSBLK_Q:
switch (Finish) {
case BLOKED_Q:
p1.x = PT_SUSBLK_RX, p1.y = PT_SUSBLK_RY;
p2.x = PT_BUG_XMAX, p2.y = p1.y;
MoveBug(p1, p2, bQuik);
p1.x = p2.x, p1.y = PT_BLOKED_RY;
MoveBug(p2, p1, bQuik);
p2.x = PT_BLOKED_RX, p2.y = p1.y;
MoveBug(p1, p2, bQuik);
bVis[6] = TRUE;
break;
case SUSRDY_Q:
p1.x = PT_SUSBLK_LX, p1.y = PT_SUSBLK_LY;
p2.x = PT_SUSRDY_RX, p2.y = PT_SUSRDY_RY;
MoveBug(p1, p2, bQuik);
bVis[7] = TRUE;
break;
}
break;
}
}
/////////////////
// Paint the Graphics for the CPU scheduler screen
//
void CpuAnim::Paint (void)
{
static char *szProcTxt[] =
{ "Process ID", "Parent ID", "Priority", "BP", "SP", "IP", "Quantum" };
DrawQueue(INPUT_QX, INPUT_QY, "Input Queue");
DrawQueue(READY_QX, READY_QY, "Ready Queue");
DrawQueue(BLOKED_QX, BLOKED_QY, "Blocked Queue");
DrawQueue(SUSRDY_QX, SUSRDY_QY, "Suspended-Ready Queue");
DrawQueue(SUSBLK_QX, SUSBLK_QY, "Suspended-Blocked Queue");
GfxRect(CPROC_X, CPROC_Y, CPROC_X2, CPROC_Y+CPROC_DY,
GFX_Fill, PROC_BG);
GfxRect(CPROC_X2, CPROC_Y, CPROC_X+CPROC_DX, CPROC_Y+CPROC_DY,
GFX_Fill, SLOT_BG);
GfxRect(CPROC_X, CPROC_Y, CPROC_X+CPROC_DX, CPROC_Y+CPROC_DY,
GFX_Frame, SLOT_TXT);
GfxTextColor(SLOT_TXT);
GfxMoveTo(CPROC_X2, CPROC_Y), GfxLineTo(CPROC_X2, CPROC_Y+CPROC_DY);
for (INT16 i = 0, y = CPROC_Y; i < CPROC_ITEM; i++, y += CPROC_DDY) {
GfxMoveTo(CPROC_X, y), GfxLineTo(CPROC_X+CPROC_DX, y);
GfxText(CPROC_X+4,
y+((SLOT_DY-GfxTextHeight()) >> 1), szProcTxt[i], GFX_Transparent);
}
if (bVis[0])
Anim(INPUT_Q, READY_Q, TRUE);
if (bVis[1])
Anim(READY_Q, CPROC_BOX, TRUE);
if (bVis[2])
Anim(CPROC_BOX, READY_Q, TRUE);
if (bVis[3])
Anim(CPROC_BOX, BLOKED_Q, TRUE);
if (bVis[4])
Anim(BLOKED_Q, READY_Q, TRUE);
if (bVis[5])
Anim(READY_Q, SUSRDY_Q, TRUE);
if (bVis[6])
Anim(BLOKED_Q, SUSBLK_Q, TRUE);
if (bVis[7])
Anim(SUSBLK_Q, SUSRDY_Q, TRUE);
}
/////////////////
// Draw (or erase) the process box variable data stuff..
//
void CpuAnim::PaintBox (PMSG_ANIP pPcb)
{
char st[32];
INT16 idx = 0;
INT16 y = CPROC_Y;
static UINT16 uLastPid = NO_PROC;
GfxTextColor(SLOT_TXT);
if (pPcb && (uLastPid == pPcb->uNr[0])) {
idx = 3;
y += (3 * CPROC_DDY);
}
Mickey.AutoPointer(CPROC_X2, CPROC_Y, CPROC_X+CPROC_DX, CPROC_Y+CPROC_DY);
while (idx < CPROC_ITEM) {
GfxSetClip(CPROC_X2+1, y+1, CPROC_X+CPROC_DX-1, y+SLOT_DY-1);
GfxRect(CPROC_X2+1, y+1, CPROC_X+CPROC_DX-1, y+SLOT_DY-1,
GFX_Fill, SLOT_BG);
if (idx < 2) {
if (pPcb)
sprintf(st, "P%d", pPcb->uNr[idx]);
else
strcpy(st, ((idx == 0) ? "" : ""));
}
if (pPcb && (idx >= 2))
switch (idx) {
case 2 : sprintf(st, "%d", pPcb->nPri); break;
case 3 : sprintf(st, "%d", pPcb->uNr[2]); break;
case 4 : sprintf(st, "%d:%04X", pPcb->uNr[4], pPcb->uNr[5]); break;
case 5 : sprintf(st, "%d:%s", pPcb->uNr[3], pPcb->szPCD); break;
case 6 : sprintf(st, "%d", (((INT16)pPcb->uNr[6]<0)?0:pPcb->uNr[6]));
}
GfxText(CPROC_X2+4, y+((SLOT_DY-GfxTextHeight()) >> 1),
st, GFX_Transparent);
GfxClrClip();
idx++;
y += CPROC_DDY;
}
Mickey.ShowPointer();
uLastPid = (pPcb) ? pPcb->uNr[0] : NO_PROC;
}
/////////////////////
// Animate the "Bug" between the passed points (which will always be in
// the same plane, x or y). If the Kwik Draw bool is true, don't animate,
// just do it as fast as possible (used after screen re-draw).
//
void CpuAnim::MoveBug (point Pts, point Ptf, BOOL bKwik)
{
Mickey.AutoPointer(MIN(Pts.x, Ptf.x)-BUG_RAD, MIN(Pts.y, Ptf.y)-BUG_RAD,
MAX(Pts.x, Ptf.x)+BUG_RAD, MAX(Pts.y, Ptf.y)+BUG_RAD);
if (bKwik) {
GfxCircle(Pts.x, Pts.y, BUG_RAD, GFX_Fill, BUG_TAIL);
GfxCircle(Ptf.x, Ptf.y, BUG_RAD, GFX_Fill, BUG_TAIL);
if (Pts.x == Ptf.x)
Pts.x -= BUG_RAD, Ptf.x += BUG_RAD;
else
Pts.y -= BUG_RAD, Ptf.y += BUG_RAD;
GfxRect(Pts.x, Pts.y, Ptf.x, Ptf.y, GFX_Fill, BUG_TAIL);
}
else
if (Pts.x == Ptf.x) {
INT16 inc = (Ptf.y > Pts.y) ? 1 : -1;
while (Pts.y != (Ptf.y + inc)) {
GfxCircle(Pts.x, Pts.y, BUG_RAD-2, GFX_Fill, BUG_BLOT);
GfxCircle(Pts.x, Pts.y, BUG_RAD, GFX_Frame, BUG_TAIL);
Pts.y += inc;
}
GfxCircle(Ptf.x, Ptf.y, BUG_RAD, GFX_Fill, BUG_TAIL);
}
else {
INT16 inc = (Ptf.x > Pts.x) ? 1 : -1;
while (Pts.x != (Ptf.x + inc)) {
GfxCircle(Pts.x, Pts.y, BUG_RAD-2, GFX_Fill, BUG_BLOT);
GfxCircle(Pts.x, Pts.y, BUG_RAD, GFX_Frame, BUG_TAIL);
Pts.x += inc;
}
GfxCircle(Ptf.x, Ptf.y, BUG_RAD, GFX_Fill, BUG_TAIL);
}
Mickey.ShowPointer();
}
////////////////////
// (Re)Draw a queue of slots for the process display at the passed Top Left.
//
void CpuAnim::DrawQueue (INT16 x, INT16 y, char *str)
{
INT16 i, dx, dy;
GfxRect(x, y, (x+(SLOT_DX * MAX_SLOTS)), (y+SLOT_DY), GFX_Fill, SLOT_BG);
for (i = 0, dx = 0; i < MAX_SLOTS; i++, dx += SLOT_DX)
GfxRect((x+dx), y, (x+dx+SLOT_DX), (y+SLOT_DY), GFX_Frame, SLOT_BDR);
dx = x + (((SLOT_DX * MAX_SLOTS) - (INT16)GfxTextExtent(str)) >> 1);
dy = y + SLOT_DY + (GfxTextHeight() >> TEXT_OFS);
GfxTextColor(SLOT_TXT);
GfxText(dx, dy, str, GFX_Transparent);
}
//////////////////
// Called each time all queues need displaying with arrays mapping
// queue slots to processes
//
void CpuAnim::PaintAllQ (MSG_ANIQ &qs)
{
GfxTextColor(PROC_TXT);
DispQ(qs.arr[0], INPUT_QX, INPUT_QY, SLOT_DX);
DispQ(qs.arr[1], READY_QX+((MAX_SLOTS-1)*SLOT_DX), READY_QY);
DispQ(qs.arr[2], BLOKED_QX+((MAX_SLOTS-1)*SLOT_DX), BLOKED_QY);
DispQ(qs.arr[3], SUSRDY_QX+((MAX_SLOTS-1)*SLOT_DX), SUSRDY_QY);
DispQ(qs.arr[4], SUSBLK_QX+((MAX_SLOTS-1)*SLOT_DX), SUSBLK_QY);
}
///////////////
// Repaint the processes in the passed Q using the (updated) array..
//
void CpuAnim::RefreshQ (UINT16 q, UINT16 *pNr)
{
INT16 x, y, dx = -SLOT_DX;
switch (q) {
case INPUT_Q:
x = INPUT_QX+1, y = INPUT_QY+1, dx = SLOT_DX;
break;
case READY_Q:
x = READY_QX+((MAX_SLOTS-1)*SLOT_DX)+1, y = READY_QY+1;
break;
case SUSRDY_Q:
x = SUSRDY_QX+((MAX_SLOTS-1)*SLOT_DX)+1, y = SUSRDY_QY+1;
break;
case SUSBLK_Q:
x = SUSBLK_QX+((MAX_SLOTS-1)*SLOT_DX)+1, y = SUSBLK_QY+1;
break;
case BLOKED_Q:
x = BLOKED_QX+((MAX_SLOTS-1)*SLOT_DX)+1, y = BLOKED_QY+1;
break;
}
INT16 xpos, ypos = y + ((SLOT_DY - GfxTextHeight()) >> 1) - 1;
GfxTextColor(PROC_TXT);
for (INT16 i = 0; i < MAX_PROC; i++, pNr++, x += dx) {
Mickey.AutoPointer(x, y, x+SLOT_DX, y+SLOT_DY);
GfxSetClip(x, y, x+SLOT_DX-2, y+SLOT_DY-2);
GfxRect(x, y, x+SLOT_DX-2, y+SLOT_DY-2, GFX_Fill, SLOT_BG);
if (*pNr != NO_PROC) {
char st[4];
sprintf(st, "P%d", *pNr);
xpos = x + ((SLOT_DX - GfxTextExtent(st)) >> 1);
GfxText(xpos, ypos, st, GFX_Transparent);
}
GfxClrClip();
Mickey.ShowPointer();
}
}
//////////////////
// Label a queue's slots with the processes occupying them
//
void CpuAnim::DispQ (UINT16 *pq, INT16 x, INT16 y, INT16 dx)
{
char sz[4];
INT16 xpos, ypos = y + ((SLOT_DY - GfxTextHeight()) >> 1);
Mickey.AutoPointer(x, y, x+SLOT_DX, y+SLOT_DY);
for (int i = 0; i < MAX_PROC; i++, pq++, x += dx) {
if (*pq == NO_PROC)
break;
sprintf(sz, "P%d", *pq);
xpos = x + ((SLOT_DX - GfxTextExtent(sz)) >> 1) + 1;
GfxText(xpos, ypos, sz, GFX_Transparent);
}
Mickey.ShowPointer();
}
///////////////////////////////// EOF //////////////////////////////////////