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.