/* class comment */!!

inherit(TextWindow, #StatusWindow, #(eventDescSet /* descriptor of events */
windowOnTop
   /* state of sys menu selection; 0=off, 1=on */
inFocus /* true if window has focus */
apFocus /* true if application has focus */
showCounters), 2, nil)!!

setClassVars(StatusWindow, #(timerOn
traceCount
hMenu
locRect
paintStruct
caption
traceText
emulText
breakText
tracing
emuState
tmHeight

tmWidth))!!

now(class(StatusWindow))!!

/* 6/23/1992 9:13 */
Def openWithPosAndState(self pos showState | statTemp posMinimize cOld)
{
  statTemp := newStyle(self, nil, nil, "stuff", nil, nil,
                       WS_CAPTION bitOr WS_MINIMIZEBOX bitOr
                       WS_OVERLAPPED bitOr WS_SYSMENU);

  initStatus(statTemp);
  shouldHideWindow(statTemp);
  
  /* restore position if passed in or retrieved from ini file */
  if pos
    /* use position only if it is the proper proportion */
    cOld := cRect(statTemp);
    if ((width(pos) = width(cOld)) cand (height(pos) = height(cOld)))
      setCRect(statTemp, pos);
      moveWindow(statTemp);
    endif;
  endif;
  
  show(statTemp, showState);
  
  ^statTemp;
}
!!

/* Return the name of this class's MS-Windows window class
  either for registration or new window creation. */
Def wndClass(self)
{ ^"StatusWindow";
}!!

/* Return the name of this class's Windows window icon
  either for registration or new window creation. */
Def wndIcon(self)
{ ^"Status";
}!!

now(StatusWindow)!!

/* 7/2/1993 9:16 PUBLIC */
Def losingApFocus(self)
{
  apFocus := nil;
  shouldHideWindow(self);
}
!!

/* 7/2/1993 9:16 PUBLIC */
Def gotApFocus(self)
{
  apFocus := 0;
  shouldHideWindow(self);
}
!!

/* 10/20/1993 8:58 */
Def losingFocus(self, hWndNew)
{
  inFocus := nil;
  shouldHideWindow(self);
  losingFocus(self:ancestor, hWndNew);
}!!

/* 10/20/1993 8:58 */
Def gotFocus(self, hWndPrev)
{
  inFocus := 0;
  shouldHideWindow(self);
  ^gotFocus(self:ancestor, hWndPrev);
}!!

/* 9/10/1992 9:39 */
Def makeWindowStayOnTop(self)
{
  /* make the window stay topmost; -1 makes the window stay topmost */
  /* 0x13 -> SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE */
  Call SetWindowPos(getHWnd(self), -1, 0, 0, 0, 0, 0x13);
}!!

/* 9/10/1992 9:39 */
Def makeWindowNormal(self)
{
  /* make the window behave like any other normal window */
  /* 0x13 -> SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE */
  Call SetWindowPos(getHWnd(self), 1, 0, 0, 0, 0, 0x13);
}!!

/* Change the status window from being always topmost/normal, otherwise
   pass the system message through to the default window proc. */
Def WM_SYSCOMMAND(self, wP, lP | hMenu)
{
  if wP == 500
    /* do the topmost window handling */
    hMenu := Call GetSystemMenu(hWnd, 0);
    if (windowOnTop = 1)
      Call CheckMenuItem(hMenu,500, MF_UNCHECKED);
      windowOnTop := 0;
      saveProfileEntry(TheProfileInfoObj, "StatusInfo", "Topmost", "0");
    else 
      Call CheckMenuItem(hMenu,500, MF_CHECKED);
      windowOnTop := 1;
      saveProfileEntry(TheProfileInfoObj, "StatusInfo", "Topmost", "1");
    endif;
    shouldHideWindow(self);
  endif;
  if wP == 501
    /* do the topmost window handling */
    hMenu := Call GetSystemMenu(hWnd, 0);
    if (showCounters = 1)
      Call CheckMenuItem(hMenu,501, MF_UNCHECKED);
      showCounters := 0;
    else 
      Call CheckMenuItem(hMenu,501, MF_CHECKED);
      showCounters := 1;
    endif;
    getTraceStatus(self);
    setWindowText(self);
    invalidate(self);
    shouldHideWindow(self);
  endif;
  ^asInt(execWindowProc(self, #WM_SYSCOMMAND, wP, lP));
}!!
!!

/* Add "Always on Top" to system menu. */
Def addAlwaysOnTop(self | hMenu)
{ hMenu := Call GetSystemMenu(hWnd, 0);
  Call AppendMenu(hMenu, MF_SEPARATOR, 0, 0);
  Call AppendMenu(hMenu, 0, 500, asciiz("&Always On Top"));
  Call AppendMenu(hMenu, 0, 501, asciiz("&Show Counters")); 
}
!!
!!

/* PRIVATE -- calc new window size based on #regs displayed */
Def newWinSize(self | wRect cRect width height bwRect)
{ 
  bwRect := windowRect( TheToolBarPresenter );
  wRect := windowRect( self ) ;
  cRect := clientRect( self ) ;
  width  := ((tmWidth) * 38) ;  /* 38 characters wide */
  height := (tmHeight) + 2 + (height(wRect) - height(cRect)) ;

  if ( (left(bwRect) + width) > x(screenSize()) ) then
    setLeft ( wRect, x(screenSize()) - width);
  else
    setLeft ( wRect, left(bwRect) );
  endif;
  if ( (bottom(bwRect)) > (y(screenSize())/2) ) then
    setTop( wRect, top(bwRect) - height - 2);
  else
    setTop ( wRect, bottom(bwRect)+ (tmHeight) );
  endif;
  setRight(  wRect, left(wRect)+width  ) ;
  setBottom( wRect, top(wRect)+height ) ; 
  setCRect( self, wRect ) ;
  moveWindow( self ) ;
  /* N.B.: no repaint */
}
!!

/* 9/10/1992 9:39
   Display the window as topmost or not according to this table:
   
   PowerViews application active?
   | Status window in focus?
   | | Always on top selected?
   | | | Result (on top of other windows?)
   0 0 0 0
   0 0 1 0
   0 1 0 X (transition state; can't have focus without PV ap active)
   0 1 1 X (ditto)
   1 0 0 0
   1 0 1 1
   1 1 0 1
   1 1 1 1
   */
Def shouldHideWindow(self)
{
  if apFocus
    if inFocus cor (windowOnTop = 1)
      makeWindowStayOnTop(self);
    else
      makeWindowNormal(self);
    endif;
  else
    /* ap not in focus */
    if not(inFocus)
      makeWindowNormal(self);
    endif;
  endif;
}
!!

/* Create a window in MS-Windows according to
  parameters specified in the arguments.  The style
  argument determines new window style. */
Def create(self, par, wName, rect, style | wndCls, parHWnd)
{ parHWnd :=
  if parent := par
  then handle(par)
  else 0
  endif;
  wndCls := wndClass(class(self));
  if Call GetClassInfo(HInstance, asciiz(wndCls),
    new(Struct, 26)) = 0
  then register(class(self));
  endif;
  caption := wName;
  wStyle := style;
  setCurWindow(System, self);
  hWnd :=
  if rect
  then Call CreateWindowEx( 0x00000008L
    /* WS_EX_TOPMOST */,asciiz(wndCls), asciiz(caption), style,
    left(rect), top(rect), width(rect), height(rect),
    parHWnd, hMenu cor 0, HInstance, 0L);
  else Call CreateWindowEx( 0x00000008L
    /* WS_EX_TOPMOST */,asciiz(wndCls), asciiz(caption), style,
    0x80 * 0x100, 0, 0x80 * 0x100, 0,
    parHWnd, hMenu cor 0, HInstance, 0L);
  endif;
  if hWnd = 0
  then alert(System, self, #windCreateError);
  endif;
  add(Windows, self);
  if not(parent)
  then add(OpenWindows, self);
  endif;
}!!

/* 8/18/1992 14:43 */
Def getBreakText(self | breakCause)
{ 
  breakCause := getBkptCause(HLBreakLibClass$Inst);

  select
    case breakCause = HLB_BECAUSE_NONE
    is 
      breakText := "Break Cause: None";
    endCase
    case breakCause = HLB_BECAUSE_RESET
    is  
      breakText := "Break Cause: Reset";
    endCase
    case breakCause = HLB_BECAUSE_HALT
    is  
      breakText := "Break Cause: User Halted";
    endCase
    case breakCause = HLB_BECAUSE_BUSBRK
    is  
      breakText := "Break Cause: Trigger Breakpoint";
    endCase
    case breakCause = HLB_BECAUSE_STEP
    is  
      breakText := "Break Cause: Step";
    endCase
    case breakCause = HLB_BECAUSE_BKPT
    is  
      breakText := "Break Cause: Execution Breakpoint";
    endCase
    case breakCause = HLB_BECAUSE_OVERLAY_ACCESS
    is  
      breakText := "Break Cause: Overlay Access Violation";
    endCase
    case breakCause = HLB_BECAUSE_DBL_BUS_FAULT
    is  
      breakText := "Break Cause: Double Bus Fault";
    endCase
    case breakCause = HLB_BECAUSE_EXTERNAL
    is  
      breakText := "Break Cause: External Break Request";
    endCase
    case breakCause = HLB_BECAUSE_STEP_FAIL
    is  
      breakText := "Break Cause: Single Step Failure";
    endCase
  endSelect;
  cls(self);
  drawString(self,breakText);
  invalidate(self);
}
!!

/* PRIVATE -- @@ should get font from fontInfo @@ */
Def initTextMetrics(self | hDC, tm, origFont, fontInfo)
{ tm := new(Struct, 32);
  fontInfo := Call GetStockObject(SYSTEM_FIXED_FONT) ;
  hDC := getContext( self ) ;
  origFont := Call SelectObject( hDC, fontInfo ) ;
  Call GetTextMetrics( hDC, tm ) ;
  tmWidth  := asInt(wordAt(tm, 10));
  tmHeight := asInt(wordAt(tm, 8)) + asInt(wordAt(tm, 0));
  if origFont
    Call SelectObject( hDC, origFont ) ;
  endif;
  releaseContext( self, hDC ) ;
}!!

!!

/* If self is the application's main window, then
  check if ready to shut down application. Otherwise,
  ensure that window is ready to be closed. */
Def close(self)
{ 
   if shouldClose(self)
      then
        Call UnregisterClass(asciiz(wndClass(class(self))),HInstance);
        closeEvents(EvNoteLibClass$Inst, eventDescSet);
        destroy(self);
   endif;
   TheStatusPresenter := nil ;
}!!

/* 6/24/1992 9:20 */
Def getEmulStatus(self)
{ 
  /* find out the current state of the CPU */  
  emuState := prim_getEmulationStatus(requireWithPath(HLBrkRootLib,"bkroot.dll"));
}
!!

/* 6/24/1992 9:16 */
Def getEmulText(self)
{ 
  ^emulText;
}
!!

/* 6/24/1992 9:20 */
Def getStatus(self)
{ 
  getTraceStatus(self);
  getEmulStatus(self);  
  setEmulText(self);
}
!!

/* 6/24/1992 9:20 - PRIVATE */
Def getTraceStatus(self | trcBufNum systemType counter cnt0Ref cnt1Ref)
{ 
  systemType := getSystemType(ProcLibClass$Inst);
  if TraceLibClass$Inst cand
      (systemType = PROC_POWERPACK) cor (systemType = PROC_MICEPACK)
    tracing := prim_trcTracingGet(TraceLibClass$Inst)[1];
    if (showCounters = 1)
       cnt0Ref := new(Struct, 2);
       cnt1Ref := new(Struct, 2);
       trcGetCounters(TraceLibClass$Inst, cnt0Ref, cnt1Ref);
       counter := " cnt0:" + asString(longAt(cnt0Ref,0)) +
                  ",cnt1:" + asString(longAt(cnt1Ref,0));
    else
       counter := "";
    endif;
    if tracing == 1 then 
       if (systemType = PROC_POWERPACK)
          trcBufNum := prim_trcCollectingBufferGet(TraceLibClass$Inst)[1];
          setTraceText(self,"Tracing: " + asString(trcBufNum) + counter);
       else
          setTraceText(self,"Tracing " + counter);
       endif;
    else
      setTraceText(self,"Not Tracing." + counter);
    endif;
  else
    /* make sure the status window is not always in the foreground */
    tracing := 0;
    setTraceText(self,"");
  endif;
}
!!

/* 6/24/1992 9:16 */
Def getTraceText(self)
{ 
  ^traceText;
}
!!

/* PRIVATE -- register for event notification */
Def initEventNotifier(self)
{
  requireWithPath( EvNoteLib, "event.dll" ) ;
  eventDescSet := registerEvents(EvNoteLibClass$Inst, hWnd, tuple(
  EVENT_BKPT_HALTED,
  EVENT_HL_BKPTEXEC_EMUL_STARTED,
  EVENT_HL_BKPTEXEC_EMUL_STEPPING,
  EVENT_HL_BKPTEXEC_EMUL_STEPPING+1,
  EVENT_TRACE_CLEAR_TRACE,
  EVENT_TRACE_NEW_SUB_BUFFER,
  EVENT_TRACE_TRACING_OFF, 
  EVENT_TRACE_TRACING_ON)); 
}
!!

/* 6/22/1992 13:16 */

/* Initialize the status popup display */
Def initStatus(self)
{ 
  timerOn := 1;
  traceCount := 0;
  
  initTextMetrics(self);
  initEventNotifier(self);
  initStatusWindow(self);
  
}
!!

/* 6/22/1992 13:37 */
Def initStatusWindow(self | tmpRect sysMenu)
{ 
  addAlwaysOnTop(self);
  sysMenu := Call GetSystemMenu(hWnd, 0);
  windowOnTop  := getIniValueNum(TheProfileInfoObj, "StatusInfo", "Topmost");
  if not(windowOnTop)
    windowOnTop := 0;
  endif;
  showCounters := 0;
  if (windowOnTop = 1)
    Call CheckMenuItem(sysMenu,500, MF_CHECKED);
  else
    Call CheckMenuItem(sysMenu,500, MF_UNCHECKED);
  endif;
  
  /* fill in the emul. text and trace text instance vars */
  getStatus(self);
  
  if (emuState = HLB_EMU_HALTED) then
    setEmulText(self);
    getBreakText(self);
  else
    cls(self);
  endif;

  /* update the windows title bar */
  setWindowText(self);

  registerF1Help(CLIULibraryClass$Inst, HI_ENTRY_STATUS,
    hWnd, HELP_ENTRY_STATUS);
  
  newWinSize(self);
}
!!

/* 6/24/1992 9:13 */
Def setEmulText(self)
{ 
  select 
  case emuState == HLB_EMU_HALTED
    is emulText := "Halted.  "
  endCase
  case emuState == HLB_EMU_HUNG
    is emulText := "Hung.  "
  endCase
  case emuState == HLB_EMU_RUNNING
    is emulText := "Running.  "
  endCase
  case emuState == HLB_EMU_STEPPING
    is emulText := "Stepping.  "
  endCase
  endSelect;

}!!

/* 6/24/1992 9:13 */
Def setTraceText(self,newText)
{ 
  traceText := newText;
}
!!

/* 6/24/1992 9:46 */
Def setWindowText(self)
{ 
  setText(self, getEmulText(self) + getTraceText(self));
}
!!

/* Return true if ok for window to close.  The default
  response is true.  Descendant classes can redefine
  this method if they need to check with user before
  closing window. */
Def shouldClose(self)
{
}!!

/* WINDOWS -- sent by event manager (evNoteLib) */
Def WM_EVENT(self, wP, lP)
{ 
  if (lP = EVENT_BKPT_HALTED) then
    getBreakText(self);
    getStatus(self);
  endif;
  
  if (lP = EVENT_HL_BKPTEXEC_EMUL_STARTED) cor 
     (lP = EVENT_HL_BKPTEXEC_EMUL_STEPPING) then
    cls(self);
    getStatus(self);
  endif;

  if (lP = EVENT_TRACE_NEW_SUB_BUFFER) cor
     (lP = EVENT_TRACE_TRACING_ON) cor
     (lP = EVENT_TRACE_TRACING_OFF) cor
     (lP = EVENT_TRACE_CLEAR_TRACE) then
    getTraceStatus(self);
  endif;

  if (lP = (EVENT_HL_BKPTEXEC_EMUL_STEPPING+1)) then
    cls(self);
    emulText := "Pending.";
    getTraceStatus(self);
  endif;

  setWindowText(self);
  invalidate(self);
  ^0
}
!!
