home *** CD-ROM | disk | FTP | other *** search
- /*
- * Winfo
- * by Paul S. Kleppner
- * modified by Ali Ozer 12/92 for 3.0 and to use dumpwindow operator for info.
- *
- * This program may be freely distributed, but not sold.
- * It is provided without warranty of any kind, expressed or
- * implied, as to its fitness for any particular use.
- */
-
- /*
- * WinInfo class. This is the controlling object of the
- * application -- it manages the report panel, and does
- * all the work.
- */
-
- #import <appkit/appkit.h>
- #import "WinInfo.h"
- #include "wwrap.h"
- #include <stdlib.h>
-
- #import "WView.h"
- #import "WinApp.h"
-
- #define DISPLAYWINDOWSLEVEL NX_NORMALLEVEL
- #define REPORTPANELLEVEL 1000
-
- // Values for selected context...
- #define ALLCONTEXTS -2
- #define NOCONTEXT -1
-
- // Display modes
- #define CONTENTSMODE 1
- #define TRANSPARENTMODE 2
- #define OUTLINEMODE 3
-
- extern BOOL getWindowBytes (int windowNum, int *bytes, int *type);
-
- @implementation WinInfo
-
- + new
- {
- self = [super new];
- windowList = NULL;
- wpList = NULL;
- onScreenList = NULL;
- displayWin = nil;
- activeFlag = NO;
-
- myFont = [Font newFont:"Helvetica" size:10.0 style:0
- matrix:NX_IDENTITYMATRIX];
- if( [myFont screenFont] )
- myFont = [myFont screenFont];
-
- [NXApp setDelegate:self];
-
- displayMode = OUTLINEMODE;
- offScreenMode = NO;
- highlightAlpha = highlightDepth = YES;
- {
- const char *tmp = NXGetDefaultValue([NXApp appName],"ShowNonRetained");
- showNonretained = (tmp && tmp[0] == 'Y');
- }
- allContexts = NO;
-
- return self;
- }
-
- // target of the start/stop button.
- - startStop:sender
- {
- activeFlag = !activeFlag;
-
- if( activeFlag )
- [self start:sender];
- else
- [self stop:sender];
-
- [timeDelay setEnabled:!activeFlag];
-
- return self;
- }
-
- // Start things going. Messaged when the user
- // has presed the "start" button.
- // sender is the start/stop button.
- - start:sender
- {
- id vw;
- NXRect r;
- struct winfo *wp;
- int i;
-
- int secs, osecs;
- NXTrackingTimer myTimer;
-
- selectedContext = allContexts ? ALLCONTEXTS : NOCONTEXT;
-
- // Delay, if user requested
- osecs = secs = [timeDelay intValue];
-
- if( secs > 0 ){
- NXBeginTimer(&myTimer, 0.0, 1.0);
- for( ; secs > 0; --secs ){
- [NXApp getNextEvent:NX_TIMERMASK];
- [timeDelay setIntValue:secs-1];
- NXPing();
- }
- NXEndTimer(&myTimer);
- }
-
- [self clearReport];
-
- // Get information on all windows on the system.
- [self buildWindowList];
-
- // And get numbers of on-screen windows.
- [self buildOnScreenList];
-
- // Look through the on-screen list, and set the winfo struct
- // to record that each of these windows is on screen.
- for( i = 0; i < numOnScreen; ++i ){
- wp = [self findWinfoByNumber:onScreenList[i]];
- if( wp != NULL )
- wp->origOnScreen = wp->onScreenNow = YES;
- }
-
- // Set up displayWin. This is a window the size of the full screen,
- // into which we draw the outlines or contents of all other windows.
- // displayWin gets set in front of all other windows on the system
- // (except the Winfo report panel), and hides them all.
- // displayWin is a panel, so that we can avoid making it key
- [NXApp getScreenSize:&r.size];
-
- //Initialize the origin of the rectangle
- r.origin.x = r.origin.y = 0.0;
-
- displayWin = [Panel newContent:&r style:NX_PLAINSTYLE backing:NX_BUFFERED
- buttonMask:0 defer:NO];
- [displayWin setBecomeKeyOnlyIfNeeded:YES]; // it will never be key
- vw = [WView newForClient:self];
-
- [displayWin setContentView:vw];
-
- // Put the report panel at the top-most level
- [sender lockFocus];
- mySetCurrentWindowLevel(REPORTPANELLEVEL);
- [[sender window] orderFront:self];
- [sender unlockFocus];
-
- if (selectedContext != NOCONTEXT) {
- [self moveOnScreen:offScreenMode forContext:selectedContext];
- }
-
- // Fill in display window with images of all other windows
- [self showAllWindows];
-
- // Summarize info for all windows...
- [self showReportSummaryForAll];
-
- // Put the display window one level beneath the report panel
- // (but in front of everybody else)
- [vw lockFocus];
- mySetCurrentWindowLevel(REPORTPANELLEVEL-1);
- [vw unlockFocus];
-
- [displayWin orderFront:self];
-
- [timeDelay setIntValue:osecs];
-
- // If there was a timer, we may not be active at this point;
- // so activate us.
- [NXApp activateSelf:YES];
-
- NXPing();
-
- return self;
- }
-
- // Called when the stop button is pressed. sender is that button.
- // Free up data structures, and the displayWin window.
-
- - stop:sender
- {
- [self clearOffScreen];
-
- if( windowList != NULL )
- free(windowList);
- if( wpList != NULL )
- free(wpList);
- [displayWin free];
- windowList = NULL;
- wpList = NULL;
- displayWin = nil;
-
- [[sender window] orderFront:self];
- mySetCurrentWindowLevel(NX_NORMALLEVEL);
-
- return self;
- }
-
- // Mouse down proxy. Called by the WView when a mouse down occurs
- // on the full-screen display window. WView masks all other
- // windows (except the Winfo report panel), so it receives all mouse hits.
- // We figure out what window was at that point, and bring that window
- // to front (or send it to back if a command-click). Then we
- // update the report panel appropriately.
- - mouseDownProxy:(NXEvent *)event
- {
- struct winfo *wp;
-
- // Get the winfo for the window at the mouse-hit.
- wp = [self mapPointToWindow:&event->location];
-
- if( wp != NULL ){
- if( event->flags & NX_COMMANDMASK ){
- // command-click: send to back
- myOrderWindow(NX_BELOW, 0, wp->num);
- } else if( event->flags & NX_ALTERNATEMASK ){
- // alt-click: send to front
- myOrderWindow(NX_ABOVE, 0, wp->num);
- } else {
- // regular click: send to front
- if( offScreenMode && !allContexts && (wp->context != selectedContext )) {
- [self moveOnScreen:NO forContext:selectedContext];
- [self moveOnScreen:YES forContext:wp->context];
- selectedContext = wp->context;
- }
- myOrderWindow(NX_ABOVE, 0, wp->num);
- // Update report info for windows
- [self showReportFor:wp];
- }
-
- // Redisplay image of all windows, to reflect new order
- [self showAllWindows];
- }
- return self;
- }
-
-
- // showAllWindows. This contructs an image of all windows
- // on the displayWin which hides them all. If outlineMode is set,
- // then we just draw outlines; otherwise, we fill in the images.
- - showAllWindows
- {
- struct winfo *wp;
- NXRect r;
- int i;
-
- [[displayWin contentView] lockFocus];
- [myFont set];
-
- [[displayWin contentView] getBounds:&r];
-
- if( displayMode != CONTENTSMODE ){
- // clear background to dark gray
- PSsetgray(NX_DKGRAY);
- NXRectFill(&r);
-
- [self buildOnScreenList];
- for( i = numOnScreen-1; i >= 0; --i ){
- if( wp = [self findWinfoByNumber:onScreenList[i]] ){
- if( !wp->isMe )
- [self showOutlineWindow:wp];
- }
- }
- } else {
- fillBelowWin([self trueWinNumberFor:reportPanel],
- [self trueWinNumberFor:displayWin]);
- }
-
- [[displayWin contentView] unlockFocus];
-
- [displayWin flushWindow];
- NXPing();
-
- return self;
- }
-
- - setReportPanel:anObject
- {
- reportPanel = anObject;
- [reportPanel setFrameAutosaveName:"Report Panel"];
- return self;
- }
-
- - (void)getDepthName:(NXWindowDepth)depth into:(char *)buffer
- {
- switch (depth) {
- case NX_TwoBitGrayDepth: sprintf (buffer, "2 bit gray"); break;
- case NX_EightBitGrayDepth: sprintf (buffer, "8 bit gray"); break;
- case NX_TwelveBitRGBDepth: sprintf (buffer, "12 bit RGB"); break;
- case NX_TwentyFourBitRGBDepth: sprintf (buffer, "24 bit RGB"); break;
- default: sprintf (buffer, "%d spp, %d bps", NXNumberOfColorComponents(NXColorSpaceFromDepth(depth)), NXBPSFromDepth(depth)); break;
- }
- }
-
- - changeHighlightOptions:sender
- {
- highlightAlpha = [[sender findCellWithTag:0] state];
- highlightDepth = [[sender findCellWithTag:1] state];
- if( activeFlag ){
- [self showAllWindows];
- }
- return self;
- }
-
- - changeDisplayOptions:sender
- {
- displayMode = [sender selectedTag];
- if( activeFlag ){
- [self showAllWindows];
- }
- return self;
- }
-
- - changeOffScreenOptions:sender
- {
- switch ([sender selectedTag]) {
- case 1: offScreenMode = allContexts = NO; break;
- case 2: offScreenMode = YES; allContexts = NO; break;
- case 3: offScreenMode = allContexts = YES; break;
- }
- selectedContext = allContexts ? ALLCONTEXTS : (reportedWindow ? reportedWindow->context : NOCONTEXT);
- if( activeFlag ){
- [self moveOnScreen:offScreenMode forContext:selectedContext];
- [self showAllWindows];
- }
- return self;
- }
-
- // Draw the outline for the given window.
- //
- - showOutlineWindow:(struct winfo *)wp
- {
- char cbuf[128];
- float borderWidth = (wp == reportedWindow) ? 5.0 : ((reportedWindow && (wp->context == reportedWindow->context)) ? 3.0 : 1.0);
-
- PSsetgray(NX_BLACK);
-
- if (displayMode == OUTLINEMODE) {
- BOOL highlight =
- ((highlightAlpha && wp->hasAlpha ) ||
- (highlightDepth && (wp->depth != NX_TwoBitGrayDepth)));
- PSsetgray(highlight ? NX_LTGRAY : NX_WHITE );
- NXRectFill (&wp->place);
- } else {
- PSsetgray(NX_WHITE );
- PSsetalpha (0.16666667);
- PScompositerect(NX_X(&wp->place),NX_Y(&wp->place),NX_WIDTH(&wp->place),NX_HEIGHT(&wp->place),NX_SOVER);
- PSsetalpha (1.0);
- }
- PSsetgray(NX_BLACK);
- NXFrameRectWithWidth(&wp->place, borderWidth);
-
- PSmoveto(wp->place.origin.x + 5, wp->place.origin.y + wp->place.size.height - 13);
- sprintf(cbuf, "%d", wp->num);
- PSshow(cbuf);
-
- PSmoveto(wp->place.origin.x + 5, wp->place.origin.y + wp->place.size.height - 23);
- if (wp->bytes >= 0) sprintf(cbuf, "%.1fkb", ((float) wp->bytes) / 1024);
- else sprintf(cbuf, "?kb");
- PSshow(cbuf);
-
- return self;
- }
-
- // Given a point, find the winfo struct for the top-most window at
- // that point. Returns NULL if not found.
- - (struct winfo *) mapPointToWindow:(NXPoint *)p
- {
- int wnum;
- float wx, wy;
- int found;
-
- myFindWindow(p->x, p->y, NX_BELOW, [self trueWinNumberFor:displayWin],
- &wx, &wy, &wnum, &found);
- if( found )
- return [self findWinfoByNumber:wnum];
- else
- return NULL;
- }
-
- // Clear the report panel
- - clearReport
- {
- [repBox setTitle:"No Window Selected"];
- [repBox display];
-
- [repContext setStringValue:""];
- [repSize setStringValue:""];
- [repAlpha setStringValue:""];
- [repDepth setStringValue:""];
- [repDepthLimit setStringValue:""];
- [repBackingStore setStringValue:""];
- [repType setStringValue:""];
- [repTotal setStringValue:""];
- [repTotalBackingStore setStringValue:""];
- [repAllTotal setStringValue:""];
- [repAllTotalBackingStore setStringValue:""];
-
- reportedWindow = NULL;
-
- return self;
- }
-
- // Display in the report panel a report for the
- // window with the given winfo struct.
- - showReportFor:(struct winfo *)wp
- {
- NXRect *rp;
- char cbuf[128];
- int i, tback, non, noff;
- struct winfo *wp2;
-
- reportedWindow = wp;
-
- rp = &wp->place;
-
- // Set the selected report box title to specify this window's number
- sprintf(cbuf, "Window #%d", wp->num);
- [repBox setTitle:cbuf];
- [repBox display];
-
- // Show context
- sprintf(cbuf, "%u", (unsigned int)(wp->context));
- [repContext setStringValue:cbuf];
-
- // Show size
- sprintf(cbuf, "%.0f x %.0f", rp->size.width, rp->size.height);
- [repSize setStringValue:cbuf];
-
- // Show alpha
- if( wp->hasAlpha )
- [repAlpha setStringValue:"Yes"];
- else
- [repAlpha setStringValue:"No"];
-
- // Show depth and colors
- {
- char buffer[100];
- [self getDepthName:wp->depth into:buffer];
- [repDepth setStringValue:buffer];
- [self getDepthName:wp->depthLimit into:buffer];
- [repDepthLimit setStringValue:buffer];
- }
-
- // Show backing store
- if (wp->bytes >= 0) [repBackingStore setIntValue:wp->bytes];
- else [repBackingStore setStringValue:"Unknown"];
-
- switch (wp->type) {
- case NX_NONRETAINED: [repType setStringValue:"Nonretained"]; break;
- case NX_RETAINED: [repType setStringValue:"Retained"]; break;
- case NX_BUFFERED: [repType setStringValue:"Buffered"]; break;
- default: [repBackingStore setStringValue:"Unknown"]; break;
- }
-
- // For all windows in same context, count number
- // on and off-screen, and total their backing store
-
- non = noff = 0;
- tback = 0;
-
- for( i = 0; i < numWins; ++i ){
- wp2 = wpList + i;
- if( wp2->context == wp->context ){
- if (wp2->bytes >= 0) tback += wp2->bytes;
- if( wp2->origOnScreen )
- ++non;
- else
- ++noff;
- }
- }
-
- sprintf (cbuf, "%d windows (%d on, %d off)", non+noff, non, noff);
- [repTotal setStringValue:cbuf];
- [repTotalBackingStore setIntValue:tback];
-
- return self;
- }
-
- // The appkit assigns logical window number to each window, apparantly
- // for its convenience. This function returns the "true" window
- // number assigned by the window server, given an Appkig window number.
- - (int) trueWinNumberFor:win
- {
- int n;
- id vw;
-
- vw = [win contentView];
- [vw lockFocus];
- PScurrentwindow(&n);
- [vw unlockFocus];
- return n;
- }
-
- - clearOffScreen
- {
- [self moveOnScreen:NO forContext:selectedContext];
- [self showAllWindows];
- return self;
- }
-
- // how == YES to move off-screen windows on, else moves them back off
- // context is what context's windows to change
- - moveOnScreen:(BOOL)how forContext:(int)context
- {
- int i;
- struct winfo *wp;
-
- for( i = 0; i < numWins; ++i ){
- wp = wpList + i;
-
- if( !wp->origOnScreen ){
- BOOL show = ((wp->type != NX_NONRETAINED) || showNonretained) && ((context == wp->context) || (context == ALLCONTEXTS));
- if( how && show ){
- if( !wp->onScreenNow ){
- if (wp->level > DISPLAYWINDOWSLEVEL) {
- mySetCurrentWindowLevelOfWindow(wp->num, DISPLAYWINDOWSLEVEL);
- }
- myOrderWindow(NX_ABOVE, 0, wp->num);
- wp->onScreenNow = YES;
- }
- } else {
- if( wp->onScreenNow ){
- myOrderWindow(NX_OUT, 0, wp->num);
- if (wp->level > DISPLAYWINDOWSLEVEL) {
- mySetCurrentWindowLevelOfWindow(wp->num, wp->level);
- }
- wp->onScreenNow = NO;
- }
- }
- }
- }
- return self;
- }
-
- - appWillTerminate:sender
- {
- if( wpList != NULL )
- [self clearOffScreen];
-
- return self;
- }
-
- // Given a DPS window number, return the winfo struct that
- // describes that window. We just do a linear scan; this is fine
- // given the relatively small number of windows we expect.
- - (struct winfo *) findWinfoByNumber:(int)wnum
- {
- struct winfo *wp;
- int i;
-
- wp = wpList;
- for( wp = wpList, i = numWins; i > 0; --i, ++wp )
- if( wp->num == wnum )
- return wp;
- return NULL;
- }
-
- - (void)showReportSummaryForAll
- {
- struct winfo *wp2;
- char buf[100];
- int tback = 0, non = 0, noff= 0, i;
-
- for( i = 0; i < numWins; ++i ){
- wp2 = wpList + i;
- if (wp2->bytes >= 0) tback += wp2->bytes;
- if( wp2->origOnScreen )
- ++non;
- else
- ++noff;
- }
-
- sprintf (buf, "%d windows (%d on, %d off)", non+noff, non, noff);
- [repAllTotal setStringValue:buf];
- [repAllTotalBackingStore setIntValue:tback];
- }
-
- // Build the complete window list. This will calculate numWins,
- // create wpList, and fill in a wpList with info on all existing windows.
- - buildWindowList
- {
- int i;
- int alpha;
- struct winfo *wp;
- int myContext;
-
-
- myContext = [NXApp contextNumber];
-
- // Get an array of DPS window numbers
- PScountwindowlist(0, &numWins);
- windowList = malloc(sizeof(int) * numWins);
- PSwindowlist(0, numWins, windowList);
-
- wpList = malloc(sizeof(struct winfo) * numWins);
-
- --numWins; // skip back-most window
-
- // For each window, get info for winfo struct describing window
- for( i = 0; i < numWins; ++i ){
- wp = wpList + i;
- wp->num = windowList[i];
- myCurrentWindowBounds(windowList[i],
- &wp->place.origin.x, &wp->place.origin.y,
- &wp->place.size.width, &wp->place.size.height);
- myCurrentWindowAlpha(windowList[i], &alpha);
- wp->hasAlpha = (alpha != 2);
-
- myCurrentWindowDepth(windowList[i], &wp->depth);
- myCurrentWindowDepthLimit(windowList[i], &wp->depthLimit);
-
- if (!getWindowBytes (windowList[i], &wp->bytes, &wp->type)) {
- wp->bytes = wp->type = -1;
- }
-
- myCurrentOwner(windowList[i], &wp->context);
- myCurrentWindowLevel(windowList[i], &wp->level);
-
- if( wp->context == myContext )
- wp->isMe = YES;
- else
- wp->isMe = NO;
-
- wp->origOnScreen = wp->onScreenNow = NO;
- }
-
- return self;
- }
-
- // Build the on-screen list of windows.
- - buildOnScreenList
- {
- // Find the on-screen windows
- // with their order.
- PScountscreenlist(0, &numOnScreen);
- if( onScreenList )
- free(onScreenList);
- onScreenList = malloc(sizeof(int) * numOnScreen);
- PSscreenlist(0, numOnScreen, onScreenList);
-
- return self;
- }
-
- @end
-