/* * RegionDisplay.h * * definition of RegionDisplay class for regview * * Copyright 1994, Silicon Graphics, Inc. * All Rights Reserved. * * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.; * the contents of this file may not be disclosed to third parties, copied or * duplicated in any form, in whole or in part, without the prior written * permission of Silicon Graphics, Inc. * * RESTRICTED RIGHTS LEGEND: * Use, duplication or disclosure by the Government is subject to restrictions * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data * and Computer Software clause at DFARS 252.227-7013, and/or in similar or * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished - * rights reserved under the Copyright Laws of the United States. */ #ident "$Revision: 1.5 $" #define XK_MISCELLANY #include #include #include #include #include #include #include #include #include "util.h" #include "RegionDisplay.h" /* * Access for Legend class */ static RegionDisplay *theRegionDisplay; class DispInfo { public: void *vaddr; GC gc; }; /* * Name of callback list that we call when the user selects a page * with the mouse or arrow keys. */ const char RegionDisplay::pageSelectCB[] = "pageSelectCB"; XtResource RegionDisplay::resources[] = { { "invalidColor", "InvalidColor", XmRPixel, sizeof (unsigned long), XtOffset(RegionDisplay *, invalidColor), XmRString, "#608189" }, { "residentColor", "ResidentColor", XmRPixel, sizeof (unsigned long), XtOffset(RegionDisplay *, residentColor), XmRString, "#8e388e" }, { "pagedOutColor", "PagedOutColor", XmRPixel, sizeof (unsigned long), XtOffset(RegionDisplay *, pagedOutColor), XmRString, "#7171c6" }, { "zappedColor", "ZappedColor", XmRPixel, sizeof (unsigned long), XtOffset(RegionDisplay *, zappedColor), XmRString, "#c67171" }, { "lineColor", "LineColor", XmRPixel, sizeof (unsigned long), XtOffset(RegionDisplay *, lineColor), XmRString, "black" }, { "lineWidth", "LineWidth", XmRInt, sizeof (int), XtOffset(RegionDisplay *, lineWidth), XmRString, "1" }, { XmNfontList, XmCFontList, XmRFontList, sizeof (XmFontList), XtOffset(RegionDisplay *, fontList), XmRString, "-*-courier-medium-r-*-*-12-*" }, { "textMargin", "TextMargin", XmRDimension, sizeof (Dimension), XtOffset(RegionDisplay *, textMargin), XmRString, "5" }, }; /* * RegionDisplay::RegionDisplay(const char *name, * Widget parent) : VkComponent(name) * * Description: * RegionDisplay constructor * * Parameters: * name ViewKit name of object to create * parent parent Widget */ RegionDisplay::RegionDisplay(const char *name, Widget parent) : VkComponent(name) { theRegionDisplay = this; reset(); hasFocus = False; int n; Arg wargs[10]; n = 0; XtSetArg(wargs[n], XmNscrollingPolicy, XmAPPLICATION_DEFINED); n++; _baseWidget = XmCreateScrolledWindow(parent, "regionDisplay", wargs, n); installDestroyHandler(); getResources(resources, XtNumber(resources)); n = 0; XtSetArg(wargs[n], XmNorientation, XmVERTICAL); n++; scrollBar = XmCreateScrollBar(_baseWidget, "scrollBar", wargs, n); XtManageChild(scrollBar); XtAddCallback(scrollBar, XmNvalueChangedCallback, scrollCB, this); XtAddCallback(scrollBar, XmNdragCallback, scrollCB, this); drawArea = XmCreateDrawingArea(_baseWidget, "drawArea", NULL, 0); XtManageChild(drawArea); XtAddEventHandler(drawArea, FocusChangeMask, False, focusHandler, this); XmScrolledWindowSetAreas(_baseWidget, NULL, scrollBar, drawArea); } /* * RegionDisplay destructor */ RegionDisplay::~RegionDisplay() { } /* * void RegionDisplay::zoomIn() * * Description: * Increase magnification by one step */ void RegionDisplay::zoomIn() { zoomFactor++; setScrollBar(); draw(); } /* * void RegionDisplay::zoomOut() * * Description: * Decrease magnification by one step */ void RegionDisplay::zoomOut() { if (zoomFactor > 1) { zoomFactor--; setScrollBar(); draw(); } } /* * void RegionDisplay::afterRealizeHook() * * Description: * Do initialization stuff that needs to take place after the * window gets mapped. */ void RegionDisplay::afterRealizeHook() { drawWin = XtWindow(drawArea); display = XtDisplay(drawArea); XtAddCallback(drawArea, XmNexposeCallback, exposeCB, this); XtAddCallback(drawArea, XmNinputCallback, inputCB, this); XtAddCallback(drawArea, XmNresizeCallback, resizeCB, this); XGCValues gcv; gcv.foreground = invalidColor; invalidGC = XCreateGC(display, drawWin, GCForeground, &gcv); gcv.foreground = residentColor; residentGC = XCreateGC(display, drawWin, GCForeground, &gcv); gcv.foreground = pagedOutColor; pagedOutGC = XCreateGC(display, drawWin, GCForeground, &gcv); gcv.foreground = zappedColor; zappedGC = XCreateGC(display, drawWin, GCForeground, &gcv); XmFontContext context; if (!XmFontListInitFontContext(&context, fontList)) { (void)fprintf(stderr, "Couldn't get a font!\n"); exit(1); } XFontStruct *font; XmStringCharSet charset; XmFontListGetNextFont(context, &charset, &font); XmFontListFreeFontContext(context); gcv.font = font->fid; textHeight = font->ascent + font->descent; textWidth = XTextWidth(font, "00000000", 8) + textMargin * 2; int depth, n; n = 0; Arg wargs[10]; XtSetArg(wargs[n], XmNdepth, &depth); n++; XtGetValues(drawArea, wargs, n); gcv.foreground = lineColor; gcv.line_width = lineWidth; lineGC = XtGetGC(drawArea, GCForeground | GCFont | GCLineWidth, &gcv); Pixel backgroundColor; n = 0; XtSetArg(wargs[n], XmNbackground, &backgroundColor); n++; XtGetValues(drawArea, wargs, n); gcv.foreground = backgroundColor; backgroundGC = XCreateGC(display, drawWin, GCForeground, &gcv); setScrollBar(); resize(); } /* * DispInfo *RegionDisplay::makeDispInfo(prpgd_sgi_t *pageData, * void *baseAddr, int pageSize) * * Description: * Turn a prpgd_sti_t array into an array of DispInfo objects. * Each object has the stuff we need to draw the bar and label * for the page. * * Parameters: * pageData page descriptors * baseAddr base address of the region * pageSize how big each page is * * Returns: * An array of corresponding DispInfo objects. */ DispInfo *RegionDisplay::makeDispInfo(prpgd_sgi_t *pageData, void *baseAddr, int pageSize) { DispInfo *di = new DispInfo[pageData->pr_pglen]; for (int i = 0; i < pageData->pr_pglen; i++) { switch (RegionInfo::getPageState(pageData->pr_data + i)) { case RegionInfo::kResident: di[i].gc = residentGC; break; case RegionInfo::kZapped: di[i].gc = zappedGC; break; case RegionInfo::kPagedOut: di[i].gc = pagedOutGC; case RegionInfo::kInvalid: default: di[i].gc = invalidGC; break; } di[i].vaddr = (void *)((char *)baseAddr + i * pageSize); } return di; } /* * Boolean DispInfoEqual(DispInfo *d1, DispInfo *d2, int n) * * Description: * Compare to DispInfo arrays. * * Parameters: * d1 One DispInfo array * d2 Another DispInfo array * n number of elements to compare * * Returns: * TRUE if they're the same, FALSE otherwise */ Boolean DispInfoEqual(DispInfo *d1, DispInfo *d2, int n) { while (n--) { if (d1->vaddr != d2->vaddr || d1->gc != d2->gc) { return False; } d1++; d2++; } return True; } /* * void RegionDisplay::reset() * * Description: * Initialize some variables to flush our data structures. */ void RegionDisplay::reset() { selectedPage = -1; scrollFactor = 0; zoomFactor = 1; if (disp) { delete [] disp; disp = NULL; } nPages = 0; } /* * void RegionDisplay::newRegion() * * Description: * Reinitialize variables to setup for a new region. */ void RegionDisplay::newRegion() { reset(); setScrollBar(); draw(); } /* * void RegionDisplay::update(RegionInfo *info) * * Description: * Update the display to reflect any changes in the region being * monitored. * * Parameters: * info */ void RegionDisplay::update(RegionInfo *info) { prpgd_sgi_t *pageData = info->getPageData(); prmap_sgi_t *map = info->getMap(); DispInfo *di = makeDispInfo(pageData, map->pr_vaddr, info->getPageSize()); /* * Don't do anything if the new stuff is the same as the old. */ if (disp && nPages == pageData->pr_pglen && DispInfoEqual(di, disp, nPages)) { delete [] di; return; } if (disp) { delete [] disp; } disp = di; nPages = (int)pageData->pr_pglen; setScrollBar(); draw(); } /* * void RegionDisplay::draw() * * Description: * Draw a bar for each page in the region, and label each bar if * the labels wil fit vertically. */ void RegionDisplay::draw() { if (!disp) { return; } XRectangle clip; clip.x = 0; clip.y = 0; clip.width = drawWidth; clip.height = drawHeight; XSetClipRectangles(display, invalidGC, 0, 0, &clip, 1, Unsorted); XSetClipRectangles(display, residentGC, 0, 0, &clip, 1, Unsorted); XSetClipRectangles(display, pagedOutGC, 0, 0, &clip, 1, Unsorted); XSetClipRectangles(display, backgroundGC, 0, 0, &clip, 1, Unsorted); Dimension width = drawWidth - textWidth; Dimension x = textWidth; float height = (float)(drawHeight * zoomFactor) / (float)nPages; Boolean doOutlines = height > 2 * lineWidth; if (!doOutlines) { XDrawRectangle(display, drawWin, lineGC, x, 0, width, drawHeight); } /* * Draw a border if we have the focus, so keyboard traversal looks * nice. If we've drawn the border, clip the rest of our output * so that we don't erase it (this avoids yucky flashing). */ if (hasFocus) { XDrawRectangle(display, drawWin, lineGC, 0, 0, drawWidth - 1, drawHeight - 1); clip.x = 1; clip.y = 1; clip.width = drawWidth - 2; clip.height = drawHeight - 2; XSetClipRectangles(display, invalidGC, 0, 0, &clip, 1, Unsorted); XSetClipRectangles(display, residentGC, 0, 0, &clip, 1, Unsorted); XSetClipRectangles(display, pagedOutGC, 0, 0, &clip, 1, Unsorted); XSetClipRectangles(display, backgroundGC, 0, 0, &clip, 1, Unsorted); } Boolean doLabels = height >= textHeight; /* * Don't render the ones that the user won't see. */ int i = (int)(scrollFactor / height); while (i < nPages) { int y = i * height - scrollFactor; /* * Quit when we get to the bottom of the window */ if (y > drawHeight) { break; } int ypixels = (i + 1) * height - y - scrollFactor; if (doLabels) { char buf[20]; (void)sprintf(buf, "%08x", disp[i].vaddr); XFillRectangle(display, drawWin, backgroundGC, 0, y, textWidth, ypixels); XDrawString(display, drawWin, lineGC, textMargin, y + textHeight, buf, strlen(buf)); } else { XFillRectangle(display, drawWin, backgroundGC, 0, (int)y, textWidth, ypixels); } XFillRectangle(display, drawWin, disp[i].gc, x + 1, y, width - 2, ypixels); if (doOutlines) { XDrawRectangle(display, drawWin, lineGC, x, y, width, ypixels); } /* * Draw an extra rectangle around the selected page. */ if (i == selectedPage) { if (ypixels > lineWidth * 2) { XDrawRectangle(display, drawWin, lineGC, x + lineWidth, y + lineWidth, width - 2 * lineWidth, ypixels - 2 * lineWidth); } else { XDrawLine(display, drawWin, lineGC, x, y, x + width, y); } } y += ypixels; i++; } } /* * void RegionDisplay::handleInput(XEvent *event) * * Description: * Deal with mouse button presses, mouse dragging, and the up and * down arrow keys. * * Parameters: * event an X event */ void RegionDisplay::handleInput(XEvent *event) { if (!disp || !event) { return; } Boolean selected = False; float height = (float)(drawHeight * zoomFactor) / (float)nPages; int page; switch (event->type) { case ButtonPress: XtAddEventHandler(drawArea, PointerMotionMask, False, motionHandler, this); break; case MotionNotify: page = (int)((scrollFactor + event->xmotion.y) / height); selected = True; break; case ButtonRelease: XtRemoveEventHandler(drawArea, PointerMotionMask, False, motionHandler, this); page = (int)((scrollFactor + event->xbutton.y) / height); selected = True; break; case KeyPress: switch (XLookupKeysym(&event->xkey, 0)) { case XK_Up: if (selectedPage > 0) { page = selectedPage - 1; selected = True; } break; case XK_Down: if (selectedPage < nPages - 1) { page = selectedPage + 1; selected = True; } break; } break; } if (selected) { if (page < 0) { page = 0; } else if (page >= nPages) { page = nPages - 1; } if (page != selectedPage) { selectedPage = page; /* * Check to see if we need to scroll in order to keep the * selected page visible. */ if (height * page < scrollFactor) { scrollFactor = (int)(height * page); setScrollBar(); } else if (page > 0 && height * (page + 1) > drawHeight + scrollFactor) { scrollFactor = (int)(height * (page + 1) - drawHeight); setScrollBar(); } draw(); callCallbacks(pageSelectCB, disp[page].vaddr); } } } /* * void RegionDisplay::resize() * * Description: * Determine our new size and render ourselves appropriately. */ void RegionDisplay::resize() { int n = 0; Arg wargs[10]; XtSetArg(wargs[n], XmNwidth, &drawWidth); n++; XtSetArg(wargs[n], XmNheight, &drawHeight); n++; XtGetValues(drawArea, wargs, n); draw(); } /* * void RegionDisplay::setScrollBar() * * Description: * Make the scroll bar attributes reflect our internal data * structures appropriately. */ void RegionDisplay::setScrollBar() { int n; Arg wargs[10]; if (nPages == 0) { n = 0; XtSetArg(wargs[n], XmNminimum, 0); n++; XtSetArg(wargs[n], XmNmaximum, 1); n++; XtSetArg(wargs[n], XmNsliderSize, 1); n++; XtSetArg(wargs[n], XmNvalue, 0); n++; XtSetValues(scrollBar, wargs, n); } else { n = 0; XtSetArg(wargs[n], XmNsliderSize, drawHeight); n++; XtSetArg(wargs[n], XmNpageIncrement, drawHeight); n++; XtSetArg(wargs[n], XmNincrement, (drawHeight * zoomFactor) > nPages ? (drawHeight * zoomFactor) / nPages : 1); n++; XtSetArg(wargs[n], XmNminimum, 0); n++; XtSetArg(wargs[n], XmNmaximum, drawHeight * zoomFactor); n++; if (scrollFactor > drawHeight * (zoomFactor - 1)) { scrollFactor = drawHeight * (zoomFactor - 1); } XtSetArg(wargs[n], XmNvalue, scrollFactor); n++; XtSetValues(scrollBar, wargs, n); } } /* * void RegionDisplay::scroll(XmScrollBarCallbackStruct *cb) * * Description: * The value of our scroll bar changed. Update scrollFactor * accordingly. * * Parameters: * cb */ void RegionDisplay::scroll(XmScrollBarCallbackStruct *cb) { scrollFactor = cb->value; draw(); } /* * Xt callback to call our draw function */ void RegionDisplay::exposeCB(Widget, XtPointer client, XtPointer) { ((RegionDisplay *)client)->draw(); } /* * Xt callback to call our input function */ void RegionDisplay::inputCB(Widget, XtPointer client, XtPointer cb) { ((RegionDisplay *)client)->handleInput(((XmDrawingAreaCallbackStruct *)cb)->event); } /* * Xt callback to call our resize function */ void RegionDisplay::resizeCB(Widget, XtPointer client, XtPointer) { ((RegionDisplay *)client)->resize(); } /* * Xt callback to call our scroll function */ void RegionDisplay::scrollCB(Widget, XtPointer client, XtPointer cb) { ((RegionDisplay *)client)->scroll((XmScrollBarCallbackStruct *)cb); } /* * Event handler for pointer motion events. This gets added only when * we're dragging, and removed when we stop dragging. */ void RegionDisplay::motionHandler(Widget, XtPointer client, XEvent *event, Boolean *) { ((RegionDisplay *)client)->handleInput(event); } /* * Event handler for FocusIn/FocusOut events. We draw ourselves * slightly differently if we have the focus. */ void RegionDisplay::focusHandler(Widget, XtPointer client, XEvent *event, Boolean *) { RegionDisplay *regDisp = (RegionDisplay *)client; if (event->type == FocusIn) { regDisp->hasFocus = True; regDisp->draw(); } else if (event->type == FocusOut) { regDisp->hasFocus = False; regDisp->draw(); } } XtResource Legend::resources[] = { { "invalidString", "InvalidString", XmRString, sizeof (char *), XtOffset(Legend *, invalidString), XmRString, "Invalid (%d K)" }, { "residentString", "ResidentString", XmRString, sizeof (char *), XtOffset(Legend *, residentString), XmRString, "Resident (%d K)" }, { "pagedOutString", "PagedOutString", XmRString, sizeof (char *), XtOffset(Legend *, pagedOutString), XmRString, "Paged Out (%d K)" }, { "zappedString", "PagedOutString", XmRString, sizeof (char *), XtOffset(Legend *, zappedString), XmRString, "Zapped (%d K)" }, }; /* * Legend::Legend(const char *name, Widget parent) : VkComponent(name) * * Description: * Legend constructor. * * Parameters: * name ViewKit name of object * parent parent Widget */ Legend::Legend(const char *name, Widget parent) : VkComponent(name) { assert(theRegionDisplay); _baseWidget = XmCreateForm(parent, "legend", NULL, 0); installDestroyHandler(); getResources(resources, XtNumber(resources)); lastInvalidSize = (unsigned long)-1; lastResidentSize = (unsigned long)-1; lastPagedOutSize = (unsigned long)-1; lastZappedSize = (unsigned long)-1; invalid = createDraw(_baseWidget, "invalid", theRegionDisplay->invalidColor, NULL); invalidLabel = createLabel(_baseWidget, "invalidLabel", invalid, NULL); resident = createDraw(_baseWidget, "resident", theRegionDisplay->residentColor, invalid); residentLabel = createLabel(_baseWidget, "residentLabel", resident, invalid); Widget pagedOut = createDraw(_baseWidget, "pagedOut", theRegionDisplay->pagedOutColor, resident); pagedOutLabel = createLabel(_baseWidget, "pagedOutLabel", pagedOut, resident); Widget zapped = createDraw(_baseWidget, "zapped", theRegionDisplay->zappedColor, pagedOut); zappedLabel = createLabel(_baseWidget, "zappedLabel", zapped, pagedOut); } /* * Legend destructor. */ Legend::~Legend() { } /* * void Legend::setLabels(unsigned long invalidSize, * unsigned long residentSize, * unsigned long pagedOutSize, * unsigned long zappedSize) * * Description: * Set the label strings in the legend to reflect sizes of * current region. * * Parameters: * invalidSize * residentSize * pagedOutSize * zappedSize */ void Legend::setLabels(unsigned long invalidSize, unsigned long residentSize, unsigned long pagedOutSize, unsigned long zappedSize) { char buf[200]; if (invalidSize != lastInvalidSize) { (void)sprintf(buf, invalidString, invalidSize); SetLabel(invalidLabel, buf); lastInvalidSize = invalidSize; } if (residentSize != lastResidentSize) { (void)sprintf(buf, residentString, residentSize); SetLabel(residentLabel, buf); lastResidentSize = residentSize; } if (pagedOutSize != lastPagedOutSize) { (void)sprintf(buf, pagedOutString, pagedOutSize); SetLabel(pagedOutLabel, buf); lastPagedOutSize = pagedOutSize; } if (zappedSize != lastZappedSize) { (void)sprintf(buf, zappedString, zappedSize); SetLabel(zappedLabel, buf); lastZappedSize = zappedSize; } } /* * Widget Legend::createDraw(Widget parent, char *name, * unsigned long background, Widget topWidget) * * Description: * Create an XmDrawingArea widget to use as a part of a legend * for the RegionDisplay component. * * Parameters: * parent parent widget * name name of widget * background background color * topWidget top attachment * * Returns: * A drawing area widget */ Widget Legend::createDraw(Widget parent, char *name, unsigned long background, Widget topWidget) { int n; Arg wargs[5]; n = 0; if (topWidget) { XtSetArg(wargs[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(wargs[n], XmNtopWidget, topWidget); n++; } XtSetArg(wargs[n], XmNbackground, background); n++; Widget draw = XmCreateDrawingArea(parent, name, wargs, n); XtManageChild(draw); XtAddCallback(draw, XmNexposeCallback, exposeCB, this); return draw; } /* * Widget Legend::createLabel(Widget parent, char *name, Widget leftWidget, * Widget topWidget) * * Description: * Create a label widget to use as part of a legend for the * RegionDisplay component. * * Parameters: * parent parent widget * name name of widget * leftWidget left attachment * topWidget top attachment * * Returns: * the label widget */ Widget Legend::createLabel(Widget parent, char *name, Widget leftWidget, Widget topWidget) { int n; Arg wargs[5]; n = 0; if (leftWidget) { XtSetArg(wargs[n], XmNleftAttachment, XmATTACH_WIDGET); n++; XtSetArg(wargs[n], XmNleftWidget, leftWidget); n++; } if (topWidget) { XtSetArg(wargs[n], XmNtopAttachment, XmATTACH_WIDGET); n++; XtSetArg(wargs[n], XmNtopWidget, topWidget); n++; } Widget label = XmCreateLabel(parent, name, wargs, n); XtManageChild(label); return label; } /* * void Legend::drawLegend(Widget draw) * * Description: * draw the border around the color in one of the drawing areas * that comprise the legend. * * Parameters: * draw drawing area widget */ void Legend::drawLegend(Widget draw) { if (!theRegionDisplay) { return; } int n; Arg wargs[2]; Dimension width, height; n = 0; XtSetArg(wargs[n], XmNwidth, &width); n++; XtSetArg(wargs[n], XmNheight, &height); n++; XtGetValues(draw, wargs, n); XDrawRectangle(XtDisplay(draw), XtWindow(draw), theRegionDisplay->lineGC, 0, 0, width - 1, height - 1); } /* * Xt callback for expose event for drawing area that's part of the * legend. */ void Legend::exposeCB(Widget w, XtPointer client, XtPointer) { ((Legend *)client)->drawLegend(w); }