home *** CD-ROM | disk | FTP | other *** search
/ Nebula 1 (1993) / nebula.bin / SourceCode / MiniExamples / PerformanceTuning / Winfo / WinInfo.m < prev    next >
Encoding:
Text File  |  1991-10-18  |  14.1 KB  |  609 lines

  1. /*
  2.  * Winfo
  3.  * by Paul S. Kleppner
  4.  *
  5.  * This program may be freely distributed, but not sold.
  6.  * It is provided without warranty of any kind, expressed or
  7.  * implied, as to its fitness for any particular use.
  8.  */
  9.  
  10. /*
  11.  * WinInfo class.  This is the controlling object of the
  12.  * application -- it manages the report panel, and does
  13.  * all the work.
  14.  */
  15.  
  16. #import "WinInfo.h"
  17. #import <appkit/Application.h>
  18. #import <appkit/View.h>
  19. #import <appkit/Window.h>
  20. #import <appkit/Panel.h>
  21. #import <appkit/Control.h>
  22. #import <appkit/Font.h>
  23. #include <dpsclient/wraps.h>
  24. #include "wwrap.h"
  25. #include <stdlib.h>
  26. #import <appkit/timer.h>
  27. #import <appkit/Matrix.h>
  28.  
  29. #import "WView.h"
  30. #import "WinApp.h"
  31.  
  32.  
  33. @implementation WinInfo
  34.  
  35. + new
  36. {
  37.   self = [super new];
  38.   windowList = NULL;
  39.   wpList = NULL;
  40.   onScreenList = NULL;
  41.   displayWin = nil;
  42.   activeFlag = NO;
  43.  
  44.   myFont = [Font newFont:"Helvetica" size:10.0 style:0
  45.           matrix:NX_IDENTITYMATRIX];
  46.   if( [myFont screenFont] )
  47.     myFont = [myFont screenFont];
  48.  
  49.   [NXApp setDelegate:self];
  50.  
  51.   outlineMode = YES;
  52.   offScreenMode = NO;
  53.  
  54.   return self;
  55. }
  56.  
  57. // target of the start/stop button.
  58. - startStop:sender
  59. {
  60.   activeFlag = !activeFlag;
  61.  
  62.   if( activeFlag ) 
  63.     [self start:sender];
  64.   else
  65.     [self stop:sender];
  66.  
  67.   [timeDelay setEnabled:!activeFlag];
  68.  
  69.   return self;
  70. }
  71.  
  72. // Start things going.  Messaged when the user
  73. // has presed the "start" button.
  74. // sender is the start/stop button.
  75. - start:sender
  76. {
  77.   id vw;
  78.   NXRect r;
  79.   struct winfo *wp;
  80.   int i;
  81.  
  82.   int secs, osecs;
  83.   NXTrackingTimer myTimer;
  84.  
  85.   selectedContext = -1;
  86.  
  87.   // Delay, if user requested
  88.   osecs = secs = [timeDelay intValue];
  89.  
  90.   if( secs > 0 ){
  91.     NXBeginTimer(&myTimer, 0.0, 1.0);
  92.     for( ; secs > 0; --secs ){
  93.       [NXApp getNextEvent:NX_TIMERMASK];
  94.       [timeDelay setIntValue:secs-1];
  95.       NXPing();
  96.     }
  97.     NXEndTimer(&myTimer);
  98.   }
  99.  
  100.   [self getHighlightValues:highlightOpt];
  101.   [self clearReport];
  102.  
  103.   // Get information on all windows on the system.
  104.   [self buildWindowList];
  105.  
  106.   // And get numbers of on-screen windows.
  107.   [self buildOnScreenList];
  108.  
  109.   // Look through the on-screen list, and set the winfo struct
  110.   // to record that each of these windows is on screen.
  111.   for( i = 0; i < numOnScreen; ++i ){
  112.     wp = [self findWinfoByNumber:onScreenList[i]];
  113.     if( wp != NULL )
  114.       wp->origOnScreen = wp->onScreenNow = YES;
  115.   }
  116.  
  117.   // Set up displayWin.  This is a window the size of the full screen,
  118.   // into which we draw the outlines or contents of all other windows.
  119.   // displayWin gets set in front of all other windows on the system
  120.   // (except the Winfo report panel), and hides them all.
  121.   // displayWin is a panel, so that we can avoid making it key
  122.   [NXApp getScreenSize:&r.size];
  123.   displayWin = [Panel newContent:&r style:NX_PLAINSTYLE backing:NX_BUFFERED
  124.         buttonMask:0 defer:NO];
  125.   [displayWin setBecomeKeyOnlyIfNeeded:YES];        // it will never be key
  126.   vw = [WView newForClient:self];
  127.   
  128.   [displayWin setContentView:vw];
  129.  
  130.   // Put the report panel at the top-most level
  131.   [sender lockFocus];
  132.   mySetCurrentWindowLevel(NX_MAINMENULEVEL+2);
  133.   [[sender window] orderFront:self];
  134.   [sender unlockFocus];
  135.  
  136.   // Fill in display window with images of all other windows
  137.   [self showAllWindows];
  138.  
  139.   // Put the display window one level beneath the report panel
  140.   // (but in front of everybody else)
  141.   [vw lockFocus];
  142.   mySetCurrentWindowLevel(NX_MAINMENULEVEL+1);
  143.   [vw unlockFocus];
  144.  
  145.   [displayWin orderFront:self];
  146.  
  147.   [timeDelay setIntValue:osecs];
  148.  
  149.   // If there was a timer, we may not be active at this point;
  150.   // so activate us.
  151.   [NXApp activateSelf:YES];
  152.  
  153.   NXPing();
  154.  
  155.   return self;
  156. }
  157.  
  158. // Called when the stop button is pressed.  sender is that button.
  159. // Free up data structures, and the displayWin window.
  160.  
  161. - stop:sender
  162. {
  163.   [self clearOffScreen];
  164.  
  165.   if( windowList != NULL )
  166.     free(windowList);
  167.   if( wpList != NULL )
  168.     free(wpList);
  169.   [displayWin free];
  170.   windowList = NULL;
  171.   wpList = NULL;
  172.   displayWin = nil;
  173.  
  174.   [[sender window] orderFront:self];
  175.   mySetCurrentWindowLevel(NX_NORMALLEVEL);
  176.  
  177.   return self;
  178. }
  179.  
  180. // Mouse down proxy.  Called by the WView when a mouse down occurs
  181. // on the full-screen display window.  WView masks all other
  182. // windows (except the Winfo report panel), so it receives all mouse hits.
  183. // We figure out what window was at that point, and bring that window
  184. // to front (or send it to back if a command-click).  Then we
  185. // update the report panel appropriately.
  186. - mouseDownProxy:(NXEvent *)event
  187. {
  188.   struct winfo *wp;
  189.  
  190.   // Get the winfo for the window at the mouse-hit.
  191.   wp = [self mapPointToWindow:&event->location];
  192.  
  193.   if( wp != NULL ){
  194.     if( event->flags & NX_COMMANDMASK ){
  195.       // command-click: send to back
  196.       myOrderWindow(NX_BELOW, 0, wp->num);
  197.     } else {
  198.       // regular click: send to front and select
  199.       if( offScreenMode ){
  200.         // If the selected context changes, clear old context's off-
  201.         // screen windows, and show new ones
  202.         if( wp->context != selectedContext ){
  203.           [self moveOnScreen:NO forContext:selectedContext];
  204.           [self moveOnScreen:YES forContext:wp->context];
  205.         }
  206.       }
  207.       selectedContext = wp->context;
  208.       myOrderWindow(NX_ABOVE, 0, wp->num);
  209.       // Update report info for windows
  210.       [self showReportFor:wp];
  211.     }
  212.  
  213.     // Redisplay image of all windows, to reflect new order
  214.     [self showAllWindows];
  215.   }
  216.   return self;
  217. }
  218.  
  219.  
  220. // showAllWindows.  This contructs an image of all windows
  221. // on the displayWin which hides them all.  If outlineMode is set,
  222. // then we just draw outlines; otherwise, we fill in the images.
  223. - showAllWindows
  224. {
  225.   struct winfo *wp;
  226.   NXRect r;
  227.   int i;
  228.  
  229.   [[displayWin contentView] lockFocus];
  230.   [myFont set];
  231.  
  232.   [[displayWin contentView] getBounds:&r];
  233.  
  234.   if( outlineMode ){
  235.     // clear background to dark gray
  236.     PSsetgray(NX_DKGRAY);
  237.     NXRectFill(&r);
  238.  
  239.     [self buildOnScreenList];
  240.     for( i = numOnScreen-1; i >= 0; --i ){
  241.       if( wp = [self findWinfoByNumber:onScreenList[i]] ){
  242.         if( !wp->isMe )
  243.           [self showOutlineWindow:wp markBorder:
  244.            (wp->context == selectedContext)];
  245.       }
  246.     }
  247.   } else {
  248.     fillBelowWin([self trueWinNumberFor:reportPanel],
  249.                  [self trueWinNumberFor:displayWin]);
  250.   }
  251.  
  252.   [[displayWin contentView] unlockFocus];
  253.  
  254.   [displayWin flushWindow];
  255.   NXPing();
  256.  
  257.   return self;
  258. }
  259.  
  260. // Draw the outline for the given window.  If markBorder is
  261. // YES, then draw the border with a heavy black line.
  262. - showOutlineWindow:(struct winfo *)wp markBorder:(BOOL)mark
  263. {
  264.   BOOL highlight;
  265.   char cbuf[128];
  266.   
  267.   PSsetgray(NX_BLACK);
  268.  
  269.   highlight = NO;
  270.  
  271.   if( highlightAlpha && wp->hasAlpha )
  272.     highlight = YES;
  273.  
  274.   if( highlightColor && wp->colors > 1 )
  275.     highlight = YES;
  276.  
  277.   // Don't highlight depth for color windows, unless highlightColor is set
  278.   if( highlightDepth && wp->depth > 2 && (highlightColor || wp->colors == 1) )
  279.     highlight = YES;
  280.  
  281.   PSsetgray(highlight ? (NX_LTGRAY+NX_WHITE)/2 : NX_WHITE );
  282.   NXRectFill(&wp->place);
  283.     
  284.   PSsetgray(NX_BLACK);
  285.   NXFrameRectWithWidth(&wp->place, mark ? 4.0 : 1.0);
  286.  
  287.   PSmoveto(wp->place.origin.x + 4, 
  288.            wp->place.origin.y + wp->place.size.height - 12);
  289.   sprintf(cbuf, "%.1fkb", ((float) [self sizeBackingStore:wp]) / 1024);
  290.   PSshow(cbuf);
  291.   
  292.   return self;
  293. }
  294.  
  295. // Given a point, find the winfo struct for the top-most window at
  296. // that point.  Returns NULL if not found.
  297. - (struct winfo *) mapPointToWindow:(NXPoint *)p
  298. {
  299.   int wnum;
  300.   float wx, wy;
  301.   int found;
  302.  
  303.   myFindWindow(p->x, p->y, NX_BELOW, [self trueWinNumberFor:displayWin],
  304.                &wx, &wy, &wnum, &found);
  305.   if( found )
  306.     return [self findWinfoByNumber:wnum];
  307.   else
  308.     return NULL;
  309. }
  310.  
  311. // Target of the highlight check boxes.  If we are active, then
  312. // redisplay the windows so that the new highlight options area active.
  313. - changeHighlight:sender
  314. {
  315.   if( activeFlag ){
  316.     [self getHighlightValues:sender];
  317.     [self showAllWindows];
  318.   }
  319.   return self;
  320. }
  321.  
  322. // Get the user's highlight choices by interrogating the highlight 
  323. // boxes.  sender is a matrix of check boxes
  324. - getHighlightValues:sender
  325. {
  326.   highlightAlpha = ([[sender findCellWithTag:0] intValue] > 0 );
  327.   highlightColor = ([[sender findCellWithTag:1] intValue] > 0 );
  328.   highlightDepth = ([[sender findCellWithTag:2] intValue] > 0 );
  329.   return self;
  330. }
  331.  
  332. // Clear the report panel
  333. - clearReport
  334. {
  335.   [repBox setTitle:"No Window Selected"];
  336.   [repBox display];
  337.  
  338.   [repContext setStringValue:""];
  339.   [repSize setStringValue:""];
  340.   [repAlpha setStringValue:""];
  341.   [repDepth setStringValue:""];
  342.   [repColors setStringValue:""];
  343.   [repBackingStore setStringValue:""];
  344.   [repOnScreen setStringValue:""];
  345.   [repOffScreen setStringValue:""];
  346.   [repTotalScreen setStringValue:""];
  347.   [repTotalBackingStore setStringValue:""];
  348.  
  349.   return self;
  350. }
  351.  
  352. // Display in the report panel a report for the 
  353. // window with the given winfo struct.
  354. - showReportFor:(struct winfo *)wp
  355. {
  356.   NXRect *rp;
  357.   char cbuf[128];
  358.   int i, tback, non, noff;
  359.   struct winfo *wp2;
  360.   
  361.   rp = &wp->place;
  362.  
  363.   // Set the selected report box title to specify this window's number
  364.   sprintf(cbuf, "Window #%d", wp->num);
  365.   [repBox setTitle:cbuf];
  366.   [repBox display];
  367.  
  368.   // Show context
  369.   sprintf(cbuf, "0x%x", wp->context);    
  370.   [repContext setStringValue:cbuf];
  371.  
  372.   // Show size
  373.   sprintf(cbuf, "%.0f x %.0f", rp->size.width, rp->size.height);
  374.   [repSize setStringValue:cbuf];
  375.  
  376.   // Show alpha
  377.   if( wp->hasAlpha )
  378.     [repAlpha setStringValue:"Yes"];
  379.   else
  380.     [repAlpha setStringValue:"No"];
  381.  
  382.   // Show depth and colors
  383.   [repDepth setIntValue:wp->depth];
  384.   [repColors setIntValue:wp->colors];
  385.  
  386.   // Show backing store
  387.   [repBackingStore setIntValue:[self sizeBackingStore:wp]];
  388.  
  389.  
  390.   // For all windows in same context, count number
  391.   // on and off-screen, and total their backing store
  392.  
  393.   non = noff = 0;
  394.   tback = 0;
  395.  
  396.   for( i = 0; i < numWins; ++i ){
  397.     wp2 = wpList + i;
  398.     if( wp2->context == wp->context ){
  399.       if( wp2->origOnScreen )
  400.         ++non;
  401.       else
  402.         ++noff;
  403.       tback += [self sizeBackingStore:wp2];
  404.     }
  405.   }
  406.  
  407.   // Report on totals for windows in same context
  408.   [repOnScreen setIntValue:non];
  409.   [repOffScreen setIntValue:noff];
  410.   [repTotalScreen setIntValue:(non+noff)];
  411.   [repTotalBackingStore setIntValue:tback];
  412.   
  413.   return self;
  414. }
  415.  
  416. // Calculate the backing store used for the given window.
  417. // The calculation is based on: window size; number of colors;
  418. // depth of each color; and alpha.  It does not include
  419. // any other overhead or rounding within the window server.
  420. - (int) sizeBackingStore:(struct winfo *)wp
  421. {
  422.   NXRect *rp;
  423.   int depth;
  424.  
  425.   depth = wp->depth * wp->colors;
  426.   rp = &wp->place;
  427.  
  428.   // If alpha is set, then we guess the number of alpha bits based on
  429.   // the depth.  (There are two bits alpha for a depth of two, 4 bits
  430.   // for a depth of 12, and 8 bits for a depth of 24.)
  431.   if( wp->hasAlpha ){
  432.     if( depth == 2 )
  433.       depth = 4;
  434.     else
  435.       depth *= (4/3);
  436.   }
  437.  
  438.   return (int) ((rp->size.width * rp->size.height * depth)/8);
  439. }
  440.  
  441. // The appkit assigns logical window number to each window, apparantly
  442. // for its convenience.  This function returns the "true" window
  443. // number assigned by the window server, given an Appkig window number.
  444. - (int) trueWinNumberFor:win
  445. {
  446.   int n;
  447.   id vw;
  448.  
  449.   vw = [win contentView];
  450.   [vw lockFocus];
  451.   PScurrentwindow(&n);
  452.   [vw unlockFocus];
  453.   return n;
  454. }
  455.  
  456. // Target of the "display window contents" check box.
  457. // If set, we display the full window contents; if not, we
  458. // show only outlines.
  459. - showOutlines:sender
  460. {
  461.   outlineMode = ([sender intValue] == 0);
  462.  
  463.   if( activeFlag )
  464.     [self showAllWindows];
  465.  
  466.   return self;
  467. }
  468.  
  469.  
  470. // Target of the "show off-screen windows" check box.
  471. // If set, we show all off-screen windows; else we show
  472. // only on-screen windows.
  473. - showOffScreen:sender
  474. {
  475.   offScreenMode = ([sender intValue] == 1 );
  476.  
  477.   if( activeFlag ){
  478.     [self moveOnScreen:offScreenMode forContext:selectedContext];
  479.  
  480.     [self showAllWindows];
  481.   }
  482.  
  483.   return self;
  484. }
  485.  
  486. - clearOffScreen
  487. {
  488.   [self moveOnScreen:NO forContext:selectedContext];
  489.   [self showAllWindows];
  490.  
  491.   [showOffScreenButton setEnabled:YES];
  492.   return self;
  493. }
  494.  
  495. // how == YES to move off-screen windows on, else moves them back off
  496. // context is what context's windows to change
  497. - moveOnScreen:(BOOL)how forContext:(int)context
  498. {
  499.   int i;
  500.   struct winfo *wp;
  501.  
  502.   for( i = 0; i < numWins; ++i ){
  503.     wp = wpList + i;
  504.  
  505.     if( (wp->context == context) && !wp->origOnScreen ){
  506.       if( how ){
  507.         if( !wp->onScreenNow ){
  508.           myOrderWindow(NX_ABOVE, 0, wp->num);
  509.           wp->onScreenNow = YES;
  510.         }
  511.       } else {
  512.         if( wp->onScreenNow ){
  513.           myOrderWindow(NX_OUT, 0, wp->num);
  514.           wp->onScreenNow = NO;
  515.         }
  516.       }
  517.     }
  518.   }
  519.   return self;
  520. }
  521.  
  522. - appWillTerminate:sender
  523. {
  524.   if( wpList != NULL )
  525.     [self clearOffScreen];
  526.  
  527.   return self;
  528. }
  529.  
  530. // Given a DPS window number, return the winfo struct that
  531. // describes that window.  We just do a linear scan; this is fine
  532. // given the relatively small number of windows we expect.
  533. - (struct winfo *) findWinfoByNumber:(int)wnum
  534. {
  535.   struct winfo *wp;
  536.   int i;
  537.  
  538.   wp = wpList;
  539.   for( wp = wpList, i = numWins; i > 0; --i, ++wp )
  540.     if( wp->num == wnum )
  541.       return wp;
  542.   return NULL;
  543. }
  544.  
  545. // Build the complete window list.  This will calculate numWins,
  546. // create wpList, and fill in a wpList with info on all existing windows.
  547. - buildWindowList
  548. {
  549.   int i;
  550.   int alpha, depth;
  551.   struct winfo *wp;
  552.   int myContext;
  553.  
  554.  
  555.   myContext = [NXApp contextNumber];
  556.  
  557.   // Get an array of DPS window numbers
  558.   PScountwindowlist(0, &numWins);
  559.   windowList = malloc(sizeof(int) * numWins);
  560.   PSwindowlist(0, numWins, windowList);
  561.  
  562.   wpList = malloc(sizeof(struct winfo) * numWins);
  563.  
  564.   --numWins;                    // skip back-most window
  565.  
  566.   // For each window, get info for winfo struct describing window
  567.   for( i = 0; i < numWins; ++i ){
  568.     wp = wpList + i;
  569.     wp->num = windowList[i];
  570.     myCurrentWindowBounds(windowList[i],
  571.                           &wp->place.origin.x, &wp->place.origin.y,
  572.                           &wp->place.size.width, &wp->place.size.height);
  573.     myCurrentWindowAlpha(windowList[i], &alpha);
  574.     wp->hasAlpha = (alpha != 2);
  575.  
  576.     myCurrentWindowDepth(windowList[i], &depth);
  577.     wp->colors = NXNumberOfColorComponents(NXColorSpaceFromDepth(depth));
  578.     wp->depth = NXBPSFromDepth(depth);
  579.  
  580.     myCurrentOwner(windowList[i], &wp->context);
  581.     myCurrentWindowLevel(windowList[i], &wp->level);
  582.     
  583.     if( wp->context == myContext )
  584.       wp->isMe = YES;
  585.     else
  586.       wp->isMe = NO;
  587.  
  588.     wp->origOnScreen = wp->onScreenNow = NO;
  589.   }
  590.  
  591.   return self;
  592. }
  593.  
  594. // Build the on-screen list of windows.
  595. - buildOnScreenList
  596. {
  597.   // Find the on-screen windows
  598.   // with their order.
  599.   PScountscreenlist(0, &numOnScreen);
  600.   if( onScreenList )
  601.     free(onScreenList);
  602.   onScreenList = malloc(sizeof(int) * numOnScreen);
  603.   PSscreenlist(0, numOnScreen, onScreenList);
  604.  
  605.   return self;
  606. }
  607.  
  608. @end
  609.