This is WinInfo.m in view mode; [Download] [Up]
/*
* Winfo
* by Paul S. Kleppner
*
* 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 "WinInfo.h"
#import <appkit/Application.h>
#import <appkit/View.h>
#import <appkit/Window.h>
#import <appkit/Panel.h>
#import <appkit/Control.h>
#import <appkit/Font.h>
#include <dpsclient/wraps.h>
#include "wwrap.h"
#include <stdlib.h>
#import <appkit/timer.h>
#import <appkit/Matrix.h>
#import "WView.h"
#import "WinApp.h"
@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];
outlineMode = YES;
offScreenMode = 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 = -1;
// 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 getHighlightValues:highlightOpt];
[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];
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(NX_MAINMENULEVEL+2);
[[sender window] orderFront:self];
[sender unlockFocus];
// Fill in display window with images of all other windows
[self showAllWindows];
// Put the display window one level beneath the report panel
// (but in front of everybody else)
[vw lockFocus];
mySetCurrentWindowLevel(NX_MAINMENULEVEL+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 {
// regular click: send to front and select
if( offScreenMode ){
// If the selected context changes, clear old context's off-
// screen windows, and show new ones
if( 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( outlineMode ){
// 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 markBorder:
(wp->context == selectedContext)];
}
}
} else {
fillBelowWin([self trueWinNumberFor:reportPanel],
[self trueWinNumberFor:displayWin]);
}
[[displayWin contentView] unlockFocus];
[displayWin flushWindow];
NXPing();
return self;
}
// Draw the outline for the given window. If markBorder is
// YES, then draw the border with a heavy black line.
- showOutlineWindow:(struct winfo *)wp markBorder:(BOOL)mark
{
BOOL highlight;
char cbuf[128];
PSsetgray(NX_BLACK);
highlight = NO;
if( highlightAlpha && wp->hasAlpha )
highlight = YES;
if( highlightColor && wp->colors > 1 )
highlight = YES;
// Don't highlight depth for color windows, unless highlightColor is set
if( highlightDepth && wp->depth > 2 && (highlightColor || wp->colors == 1) )
highlight = YES;
PSsetgray(highlight ? (NX_LTGRAY+NX_WHITE)/2 : NX_WHITE );
NXRectFill(&wp->place);
PSsetgray(NX_BLACK);
NXFrameRectWithWidth(&wp->place, mark ? 4.0 : 1.0);
PSmoveto(wp->place.origin.x + 4,
wp->place.origin.y + wp->place.size.height - 12);
sprintf(cbuf, "%.1fkb", ((float) [self sizeBackingStore:wp]) / 1024);
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;
}
// Target of the highlight check boxes. If we are active, then
// redisplay the windows so that the new highlight options area active.
- changeHighlight:sender
{
if( activeFlag ){
[self getHighlightValues:sender];
[self showAllWindows];
}
return self;
}
// Get the user's highlight choices by interrogating the highlight
// boxes. sender is a matrix of check boxes
- getHighlightValues:sender
{
highlightAlpha = ([[sender findCellWithTag:0] intValue] > 0 );
highlightColor = ([[sender findCellWithTag:1] intValue] > 0 );
highlightDepth = ([[sender findCellWithTag:2] intValue] > 0 );
return self;
}
// Clear the report panel
- clearReport
{
[repBox setTitle:"No Window Selected"];
[repBox display];
[repContext setStringValue:""];
[repSize setStringValue:""];
[repAlpha setStringValue:""];
[repDepth setStringValue:""];
[repColors setStringValue:""];
[repBackingStore setStringValue:""];
[repOnScreen setStringValue:""];
[repOffScreen setStringValue:""];
[repTotalScreen setStringValue:""];
[repTotalBackingStore setStringValue:""];
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;
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, "0x%x", 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
[repDepth setIntValue:wp->depth];
[repColors setIntValue:wp->colors];
// Show backing store
[repBackingStore setIntValue:[self sizeBackingStore:wp]];
// 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->origOnScreen )
++non;
else
++noff;
tback += [self sizeBackingStore:wp2];
}
}
// Report on totals for windows in same context
[repOnScreen setIntValue:non];
[repOffScreen setIntValue:noff];
[repTotalScreen setIntValue:(non+noff)];
[repTotalBackingStore setIntValue:tback];
return self;
}
// Calculate the backing store used for the given window.
// The calculation is based on: window size; number of colors;
// depth of each color; and alpha. It does not include
// any other overhead or rounding within the window server.
- (int) sizeBackingStore:(struct winfo *)wp
{
NXRect *rp;
int depth;
depth = wp->depth * wp->colors;
rp = &wp->place;
// If alpha is set, then we guess the number of alpha bits based on
// the depth. (There are two bits alpha for a depth of two, 4 bits
// for a depth of 12, and 8 bits for a depth of 24.)
if( wp->hasAlpha ){
if( depth == 2 )
depth = 4;
else
depth *= (4/3);
}
return (int) ((rp->size.width * rp->size.height * depth)/8);
}
// 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;
}
// Target of the "display window contents" check box.
// If set, we display the full window contents; if not, we
// show only outlines.
- showOutlines:sender
{
outlineMode = ([sender intValue] == 0);
if( activeFlag )
[self showAllWindows];
return self;
}
// Target of the "show off-screen windows" check box.
// If set, we show all off-screen windows; else we show
// only on-screen windows.
- showOffScreen:sender
{
offScreenMode = ([sender intValue] == 1 );
if( activeFlag ){
[self moveOnScreen:offScreenMode forContext:selectedContext];
[self showAllWindows];
}
return self;
}
- clearOffScreen
{
[self moveOnScreen:NO forContext:selectedContext];
[self showAllWindows];
[showOffScreenButton setEnabled:YES];
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->context == context) && !wp->origOnScreen ){
if( how ){
if( !wp->onScreenNow ){
myOrderWindow(NX_ABOVE, 0, wp->num);
wp->onScreenNow = YES;
}
} else {
if( wp->onScreenNow ){
myOrderWindow(NX_OUT, 0, wp->num);
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;
}
// 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, depth;
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], &depth);
wp->colors = NXNumberOfColorComponents(NXColorSpaceFromDepth(depth));
wp->depth = NXBPSFromDepth(depth);
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
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.