mac-rom/Toolbox/TextServicesMgr/TSMExtension.a
Elliot Nunn 5b0f0cc134 Bring in CubeE sources
Resource forks are included only for .rsrc files. These are DeRezzed into their data fork. 'ckid' resources, from the Projector VCS, are not included.

The Tools directory, containing mostly junk, is also excluded.
2017-12-26 10:02:57 +08:00

1686 lines
60 KiB
Plaintext

;______________________________________________________________________________
;
; File: TSMExtension.a
;
; Contains: Text Services Manager trap dispatcher.
;
; Written by: Kenny SC. Tung
;
; Copyright: © 1991-1992 by Apple Computer, Inc., all rights reserved.
;
; Change History (most recent first):
;
; <SM5> 8/26/92 kc Fix compiler warning.
; <SM4> 7/7/92 CSS Update from Reality:
; <49> 7/3/92 KST <JH>: Correct a type error: kIMJustSetCursorBit should really be
; kSWMJustSetCursorBit.
; <48> 6/26/92 KST #1031142 <JH>: When the application claims not TSM aware any
; more, we need to clear all UseInputWindow flags so it will not
; be reused when another TSM aware app is launched.
; <47> 6/26/92 KST #1033450,1033456,1031316 <JH>: When XCLOSETSMAWAREAPPLICATION()
; is called, we better inform Process Manager about it.
; <46> 6/22/92 KST #1033280,1033495 <JH>: When part code <= inSysWindow, return not
; over a floating window. (I used to only check inDesk).
; <45> 6/19/92 KST #1032492 <JH>: When TSM tries to open the resource file using
; the refcon in the floating window, need to verify its
; windowkind.
; <44> 6/17/92 KST #1030843 <JH>: If we click in a popup menu inside of a floating
; window, HMGetBalloon needs to return true so that balloon will
; be removed. Also changed the function name from
; utaIsApplicationTSMAware to utaIsAppTSMAwareAndNotUsingIW to be
; more precise and descriptive.
; <43> 6/14/92 KST Changed utaRemoveDocumentID to return the number of TSM
; documents remained open by the application.
; <SM3> 6/11/92 CSS Roll-in Reality Changes. I don't know where Fred left off so here
; are all the comments:
; <42> 6/10/92 YK Oops, donÕt do last minutes change.
; <41> 6/10/92 YK #1031298 <JH>: Add OldJapaneseInputMethodExists. It returns
; True if the specified old-input method exists.
; <40> 6/10/92 KST #1031142,1030881 <JH>: Since we removed the docID param from
; TSMEvent, UseInputWindow has been broken because keydown event
; is routed to SWM recursively. Fix it with a TSM global keeping
; track of which doc is using the input window. And added a new
; private call for SWM -- TSMEventFromSWM. The TSM boot code has
; been modified so that it can handle multiple TSMinit files.
; (Global will not be re-allocated).
; <39> 6/4/92 JH #1031574 <KST>: _HMGetBalloonPatch leaves bits behind when a
; help window is drawn over the menubar. Checking to see if we are
; over the menubar or over a systemwindow before we return false.
; <38> 6/2/92 KST <JH>, Should not check for inContent in HMGetBalloon.
; <37> 6/2/92 KST <JH>,The previous change has a minor mistake in HMGetBalloon
; patch.
; <36> 6/2/92 JH #1028635,1030481,1030631,1030634,1030647 <KST>: Added SystemMenu
; patch to support system menus for input methods.
; <35> 5/20/92 KST #1030447 <JH>: Fixed a bug. UseInputWindow did not work if we
; want to have global effect for the application.
; <34> 5/14/92 KST #1025797,<JH>: Added one new message selector 'kMsgHelpHELPMgr'
; to InformTSM. This call is used by __HMScanHWinResource in
; BalloonPACK.a. Also patched __HMGetBalloonPatch so that Help
; balloon will not flash in the Finder.
; <33> 5/4/92 KST #1025252,<JH>: Patched _PaintBehind so that floating windows
; will be updated correctly when the whole screen is redrawn.
; <32> 5/2/92 YK Flush the parameter on the stack before return to a caller.
; <31> 5/1/92 KST #1027482,<JH>: If input method changed cursor in a floating
; layer, then don't let other application to change the cursor
; again.
; <30> 5/1/92 KST #1028301,<JH>: SetTSMDialogState, RestoreTSMDialogState,
; TSMChangeCursor, TSMRestoreCursor calls are no longer needed and
; should be removed from the source code.
; <29> 4/9/92 KST JH,modifying InitTSMApplication to support the fact that SWM is
; no longer an application but a driver. Adding 2 new messages in
; InformTSM. Will remove SetDialogState in the next release.
; <28> 3/27/92 KST Documentation changes.
; <27> 3/23/92 KST Changes due to the code review.
; <26> 3/12/92 KST Added a new call "utaGetTSMAwareDocTable".
; <25> 3/6/92 KST Removed debugger code. Will grow internal table when overflow.
; <24> 3/4/92 KST Get trap address of SetCursor at INIT time.
; <23> 3/3/92 KST Added 2 new calls: "TSMChangeCursor", and "TSMRestoreCursor".
; <22> 3/2/92 KST Added a private TSM call "NewTSMDocument4SWM".
; <21> 2/28/92 KST Added 2 new calls "SetTSMDialogState", and
; "RestoreTSMDialogState".
; <20> 2/27/92 KST In utKillTSMAwareApplication, if the app is not TSM aware, we'll
; send an AE to SWM ask it to close its input window. If it is TSM
; aware, we'll set tsmKillApplicationP flag to true.
; <19> 2/11/92 DCL Changed the name of TSMEqu.[aph] to TextServices.[aph] for
; better read-ability.
; <18> 2/10/92 KST InformTSM's msgChangeToOldJIM now takes a parameter -- FEPID.
; <SM2> 4/22/92 FM Bring up to date with RealityÉ
; <17> 2/1/92 KST We don't have a global flag in TSM globals to indicate using
; bottom-line window.
; <16> 1/31/92 YK Added FindServiceWindow.
; <15> 1/29/92 KST Removed "xIsApplicationTSMAware" call. Also inform Process
; Manager whether it should start sending events to SWM when SWM
; informTSM with its PSN.
; <14> 1/16/92 KST Add a new message to InformTSM: kMsgChangeToOldJIM.
; <13> 1/11/92 KST TSM globals are initially cleared.
; <12> 1/10/92 KST Inform Process Manager if the application is TSM aware.
; <11> 1/9/92 KST Changed SetDefaultInputMethod selector back to 13 so that we can
; build TSM INIT with d13.
; <10> 1/8/92 KST Removed CleanUpTSMAwareApp routine. CleanUpTSMApp is now a
; message to InformTSM.
; <9> 1/4/92 KST Add a new routine "CloseTextService". Also "OpenTextService" now
; returns component instance to the caller.
; <8> 12/31/91 KST Added "CleanUpTSMAwareApplication" and "InformTSM" new calls.
; Check saved resource for "Use Input Window" global flag at boot
; time.
; <7> 12/20/91 KST Making progress toward Alpha. Changed "inline" to "TSM", and
; added new calls.
; <6> 12/10/91 KST Adding a new "InlineAwareRegister" call.
; <5> 12/10/91 KST Disable the Gestalt call for now.
; <4> 12/10/91 KST Added boot time initialization code, and to use "TSMPrivate.a".
; <3> 11/26/91 KST Low level TSM routines are now dispatched directly to the
; Component Manager.
; <2> 11/23/91 KST Check in the first time for Cube-E.
;
;
;______________________________________________________________________________
;______________________________________________________________________________
;
; File: "TSMDispatch.a"
;
; Written by Kenny SC. Tung
;
; Modification History:
; 21Nov91 KSCT New today.
;______________________________________________________________________________
PRINT OFF
LOAD 'StandardEqu.d'
INCLUDE 'Processes.a'
INCLUDE 'MFPrivate.a'
INCLUDE 'LinkedPatchMacros.a'
INCLUDE 'GestaltEqu.a'
INCLUDE 'LayerEqu.a'
INCLUDE 'TextServices.a'
INCLUDE 'TSMPrivate.a'
INCLUDE 'Balloons.a'
INCLUDE 'BalloonsPriv.a'
INCLUDE 'ScriptPriv.a'
PRINT ON
CASE OBJ
IF &type('TSMDebug') = 'UNDEFINED' THEN
TSMDebug EQU 0
ENDIF
IF &type('BuildTSMInit') = 'UNDEFINED' THEN
BuildTSMInit EQU 0 ; this is only defined when building INIT
ENDIF
;______________________________________________________________________________
; Input: D0.W low byte = trap index,
; high byte = # of parameters in words.
; Note:
;______________________________________________________________________________
TSMDISPATCH Proc export ; dispatch code
MOVEQ #0,D1
MOVE.W D0,D1 ; D1 = trap index
TST.W D1 ; Check the trap dispatch
BLT.S @1 ; Negative traps are trouble
CMP.W #kMaxTSMSelector,D1 ; Compare against our known limits
BLS.S @2 ; Continue if all seems well
@1 MOVEQ #0,D1
MOVE.W D0,D1
LSR.W #8,D1 ; D1 = # of parameters in words
LSL.W #1,D1 ; convert to bytes
MOVEQ #ParamErr,D0 ; Indicate parameter error
MOVEA.L (SP)+,A0 ; get return address
LEA (A7,D1),SP ; pop param
MOVE.W D0,(SP) ; function result
JMP (A0) ; Terminate this call
@2 ;; D1 = trap index.
EXT.W D1 ;
ASL.W #1,D1 ; each entry is 4 bytes
MOVE.W TSMTrapTable(D1.W),d0 ; get the address of the entry point
JMP TSMTrapTable(D0.W) ;jump to it
MACRO
JT &entry
IMPORT &entry
DC.W &entry - TSMTrapTable
ENDM
TSMTrapTable
JT XNEWTSMDOCUMENT ; 0 initialize TSM aware document
JT XDELETETSMDOCUMENT ; 1
JT XACTIVATETSMDOCUMENT ; 2
JT XDEACTIVATETSMDOCUMENT ; 3
JT XTSMEVENT ; 4
JT XTSMMENUSELECT ; 5
JT XSETTSMCURSOR ; 6
JT XFIXTSMDOCUMENT ; 7
JT XGETSERVICELIST ; 8
JT XOPENTEXTSERVICE ; 9
JT XCLOSETEXTSERVICE ; 10 <04Jan91 #9>
JT XSENDAETOCLIENT ; 11
JT XSETDEFAULTINPUTMETHOD ; 12
JT XGETDEFAULTINPUTMETHOD ; 13 (D)
JT XSETTEXTSERVICELANGUAGE ; 14 (E)
JT XGETTEXTSERVICELANGUAGE ; 15
JT XUSEINPUTWINDOW ; 16
JT XNEWSERVICEWINDOW ; 17
JT XCLOSESERVICEWINDOW ; 18
JT XGETFRONTSERVICEWINDOW ; 19
JT XINITTSMAWAREAPPLICATION ; 20
JT XCLOSETSMAWAREAPPLICATION ; 21
JT XINFORMTSM ; 22
JT XFINDSERVICEWINDOW ; 23
JT XNEWTSMDOCUMENT4SWM ; 24 <02Mar92 #22>
JT XTSMEVENTFROMSWM ; 25 <03Jun92 #39>
ENDP
; __________________________________________________________________________
; Function: xInitTSMAwareApplication()
; Application registers itself as TSM aware.
; Input: none.
; Output: D0.W = error code (memFullErr, tsmNotAnAppErr, tsmAlreadyRegisteredErr)
; Register usage: Use D0,D1,A0,A1
;
; Side Effect: If application registers itself the first time, a table to
; record open document IDs is allocated if it is not allocated.
; ___________________________________________________________________________
XINITTSMAWAREAPPLICATION PROC EXPORT
Import utaTSMAwareApplicationP
Export xInitTSMAwareDriver
WITH PSNRecord
SUBA.W #10, sp ; allocate storage for PSN (8 bytes) and result
PEA 2(sp) ; push address of PSN storage
_GetSystemClientProcess ; get PSN with which to associate the file
TST.W (sp)+ ; on error, PSN == kNoProcess
BNE.S noProcess
xInitTSMAwareDriver
;; Verify if we have registered this app already ...
MOVE.L highLongOfPSN(SP),D0 ; get high half of PSN
MOVE.L lowLongOfPSN(SP),D1 ; get low half of PSN
BSR utaTSMAwareApplicationP ; is it already registered?
BNE.S registered ; yes, punt =>
;; PSN on top of stack. Locate a free entry and store.
BSR getFreePSNEntry ; get a free entry in A1
BNE.S cleanSPExit ; punt on error (D0 set)
;; Record this application in the PSN table (A1) ...
IF TSMDebug THEN ; debug begin
CMP.W #kPSNTableSignature,psnTableSignature(A1) ; valid table?
BEQ.S TableOK ; yes
_debugger
TableOK
ENDIF ; end
MOVE.L (sp)+,psnHighID(A1) ; pop and save high half of PSN
MOVE.L (sp)+,psnLowID(A1) ; pop and save low half of PSN
CLR.W psnDoWeReallyUseIW(A1) ; don't use float input window
MOVEA.L psnDocsTablePtr(A1),A0 ; get the addr
MOVE.L A0,D0 ; is there a table?
BNE.S hasTable ; if yes, recycle it (clear counter)
MOVE.L #kDocTableDefSize,D0 ; doc ID table size
_NewPtr ,sys ,clear ; from system heap
BEQ.S newTable ; OK ->
MOVE.W #memFullErr,D0 ; set error code
BRA.S cleanSPExit ; no memory, sorry
newTable
MOVE.W #kDefTableEntryN,docTableEntryN(A0) ; total entry number of the table
MOVE.L A0,psnDocsTablePtr(A1) ; save the table in PSN record
hasTable
CLR.W docIDCount(A0) ; clear counter
;; Inform Process Manager that this application is TSM aware ...
LEA psnHighID(A1),A0 ; PSN addr
CLR.W -(SP) ; room for result
MOVE.L A0,-(SP) ; PSN
MOVE.W #$FFFF,-(SP) ; flag = true
_InlineAware
ADDA.W #2,SP ; ignore error
MOVEQ #0,D0 ; return no error
ret
MOVE.W D0,4(SP) ; return error in Pascal style
RTS
noProcess
MOVE.W #tsmNotAnAppErr,D0
cleanSPExit
LEA 8(SP),SP ; reset sp (for PSN record)
BRA.S ret
registered
MOVE.W #tsmAlreadyRegisteredErr,D0
BRA.S cleanSPExit
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Function: getFreePSNEntry
; Internal routine called by xInitTSMAwareApplication only.
; Output: A1.L = pointer to PSN record if D0 = 0,
; D0.W = noErr if found one free slot
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
getFreePSNEntry ; private routine
MOVEA.L ExpandMem,A0
MOVEA.L ExpandMemRec.emTSMGlobals(A0),A0 ; get TSM global in A0
MOVEA.L TSMVarsRec.tsmIAPSNTablePtr(A0),A0 ; get PSN table
MOVE.W iaAppCount(A0),D0 ; D0.W = total apps registered
MOVE.W iaTotalPSNEntryN(A0),D1 ; D1.W = total entries
CMP.W D1,D0 ; any free slot?
BHS.S @full ; no
@again
LEA iaPSNStart(A0),A1 ; A1 = first PSN record
@tryNext
TST.L psnHighID(A1) ; is this free?
BNE.S @4 ; No
TST.L psnLowID(A1) ; is this free?
BEQ.S @foundOne ; yes, both slots are zero
@4
ADDA.W #kPSNEntrySize,A1 ; points to the next one
BRA.S @tryNext
@foundOne ADD.W #1,iaAppCount(A0) ; bump app counter
MOVEQ #0,D0 ; no error
RTS
@full ;; all full, need to grow the array
;; PSN table is full, (too many TSM aware application? Good !!!), need to grow the table ...
MOVEA.L A0,A1 ; A1 = old PSN table
ADDQ #kDefTableEntryN,D1 ; increment total entry
MOVE.L D1,D0
LSL.L #kLog2PSNEntrySize,D0 ; total bytes
ADD.L #iaPSNStart,D0 ; plus header = new size to allocate
_NewPtr ,sys ,clear ; allocate a larger table from system heap
BNE.S @noMem ; no memory, we are in trouble
;; A0 = new PSN table, A1 = old PSN table, D1 = new total entry.
MOVE.W iaTotalPSNEntryN(A1),D0 ; D0.W = original total entries
LSL.L #kLog2PSNEntrySize,D0 ; convert to bytes
ADD.L #iaPSNStart,D0 ; plus header = old size to copy
EXG A1,A0 ; A0 is the source
_BlockMove ; copy A0 => A1
;; A0 is the old table, we can release it now ...
_DisposePtr ; free mem
MOVEA.L ExpandMem,A0 ; we come here when buffer is full
MOVEA.L ExpandMemRec.emTSMGlobals(A0),A0 ; get TSM global in A0
MOVE.L A1,TSMVarsRec.tsmIAPSNTablePtr(A0) ; save new table in TSM global
MOVE.W D1,iaTotalPSNEntryN(A1) ; update (NEW) total entries
EXG A1,A0 ; A0 is now the new PSN table
BRA.S @again ; try again
@noMem
MOVE.W #memFullErr,D0 ; return error
RTS
ENDWITH
ENDP ; xInitTSMAwareApplication END
; _________________________________________________________________________
; Function: OSErr utaRecordDocumentID(aHandle, &PSNRecord)
; Internal C routine --
; Record the document ID in PSN table for the application.
; Each application keeps track of all open document IDs.
; Called by 'xNewTSMDocument'.
; Output: noErr = no error
; Register usage: Use D0,D1,A0,A1
;
; Side effect:
; Grow the document table if it is full.
; _________________________________________________________________________
utaRecordDocumentID PROC EXPORT
IMPORT utaTSMAwareApplicationP
WITH PSNRecord
; 0(SP) -> return addr
docIDParam equ 4 ; 4(SP) -> aHandle = valid document ID
psnParam equ 8 ; 8(SP) -> ptr(PSNRecord)
MOVEA.L psnParam(SP),A0 ; A0 = ptr(PSNRecord)
MOVE.L highLongOfPSN(A0),D0 ; get high half of PSN
MOVE.L lowLongOfPSN(A0),D1 ; get low half of PSN
BSR utaTSMAwareApplicationP ; is it already registered?
BEQ.S @notAwareReturn ; no, it is not TSM aware? !!
@1
;; It is registered, A1 = ptr(PSNRecord) ...
MOVE.L psnDocsTablePtr(A1),D0 ; D0 = ptr(doc ID table)
BEQ.S @notAwareReturn ; if no table
MOVEA.L D0,A0
MOVE.W docIDCount(A0),D0 ; D0.W = total ID recorded
MOVE.W docTableEntryN(A0),D1 ; D1.W = total entries
CMP.W D1,D0 ; any free slot?
BHS.S @full ; no
LEA docIDStart(A0),A1 ; A1 = first ID
@loop
TST.L (A1)+ ; is this slot free?
BNE.S @loop ; no
MOVE.L docIDParam(SP),-(A1) ; save the ID in the free slot
ADD.W #1,docIDCount(A0) ; increment count
MOVEQ #0,D0 ; OK
@Exit
RTS
@notAwareReturn
MOVE.W #tsmNeverRegisteredErr,D0 ; return error
BRA.S @Exit
@full ; all full, need to grow the array
;; document table is full, need to grow the table ...
ADDQ #kDefTableEntryN,D1 ; increment total entry
MOVE.L D1,D0
LSL.L #kLog2DocEntrySize,D0 ; entry * 4
ADD.L #docIDStart,D0 ; plus header
_NewPtr ,sys ,clear ; allocate a larger table from system heap
BNE.S @noMem ; no memory, it's OK
;; A0 = new doc table, A1 = ptr(PSNRecord), D0.L = new table size, D1 = new total entry.
MOVE.L A2,-(SP) ; free A2
MOVEA.L A1,A2 ; A2 = ptr(PSNRecord)
MOVE.L psnDocsTablePtr(A2),A1 ; A1 = ptr(old table)
MOVE.L A0,psnDocsTablePtr(A2) ; save the new table
;; A0 = new doc table, A1 = old doc table,
MOVE.W docTableEntryN(A1),D0 ; D0.W = original total entries
LSL.L #kLog2DocEntrySize,D0 ; entry * 4
ADD.L #docIDStart,D0 ; plus header
EXG A1,A0 ; A0 is the source
_BlockMove ; copy A0 => A1
;; A0 is the old table, we can release it now ...
_DisposePtr ; free mem
MOVE.W D1,docTableEntryN(A1) ; update (NEW) total entries
MOVEA.L A2,A1 ; A1 = ptr(PSNRecord)
MOVEA.L (SP)+,A2 ; restore A2
BRA.S @1 ; try again
@noMem
MOVE.W #memFullErr,D0 ; return error
RTS
ENDWITH
ENDP ; utaRecordDocumentID END
; _________________________________________________________________________
; Function: OSErr utaRemoveDocumentID(handle, countPtr, psnRecordPtr);
; Internal routine -- Remove the document ID in process's doc ID table.
; Called by 'xDeleteTSMDocument' only.
; The caller of this routine should close all open text services!
; Input: Handle is a valid document ID
; Output: count = number of TSM documents remained
; psnRecordPtr = psn Record Ptr (meaningful only if count = 0)
; Register usage: Use D0,D1,A0,A1
; C calling convention .....
; _________________________________________________________________________
; 0(SP) -> return addr
; 4(SP) -> handle (ID)
; 8(SP) -> ptr(short) ; count
;12(SP) -> ptr(psn record) ; meaningful only if count = 0 !!!!!!!!!!!!!
utaRemoveDocumentID PROC EXPORT
IMPORT utaTSMAwareApplicationP
WITH PSNRecord, TSMDocumentRecord
MOVEA.L 4(SP),A0 ; A0 = handle
MOVEA.L (A0),A0 ; A0 = doc ID pointer
MOVE.L iDocPSNID1(A0),D0 ; get high half of PSN
MOVE.L iDocPSNID2(A0),D1 ; get low half of PSN
BSR utaTSMAwareApplicationP ; is it already registered?
BEQ.S @err ; no, it is not TSM aware? !!
;; It is registered, A1 = ptr(PSNRecord) ...
MOVE.L psnDocsTablePtr(A1),D0 ; D0 = ptr(doc ID table)
BEQ.S @err ; if no table
MOVEA.L D0,A0 ; A0 = ptr(doc ID table)
MOVE.W docIDCount(A0),D0 ; D0.W = total ID recorded
BEQ.S @stackOK ; br if empty (A1 = ptr(PSNRecord))
MOVE.L A1,-(SP) ; save ptr
MOVE.W docTableEntryN(A0),D0 ; D0.W = total entry
LEA docIDStart(A0),A1 ; A1 = first ID
MOVE.L 8(SP),D1 ; D1 = document ID to delete
@loop
TST.W D0 ; more to search?
BLE.S @notFound ; no (should never happen)
SUBQ #1,D0 ; one less to search
CMP.L (A1)+,D1 ; is this the one?
BNE.S @loop ; no
CLR.L -(A1) ; found, clear it
SUB.W #1,docIDCount(A0) ; decrement count
MOVEA.L (SP)+,A1 ; A1 = ptr(PSNRecord)
@stackOK
MOVE.W docIDCount(A0),D0 ; D0.W = total ID recorded
MOVEA.L 8(SP),A0 ; A0 = ptr to short
MOVE.W D0,(A0) ; return count remaining
MOVEA.L 12(SP),A0 ; A0 = ptr to psn record
MOVE.L A1,(A0) ; return psn record ptr
MOVEQ #0,D0 ; perfect
RTS
@notFound
ADDQ.W #4,SP ; pop ptr
@err
MOVE.W #tsmNeverRegisteredErr,D0 ; not TSM aware
RTS
ENDWITH
ENDP ; utaRemoveDocumentID END
; _____________________________________________________________________________________
; Function: OSErr utaUpdateAppFlagInPSNTable(&PSNRecord, useFloatWindowP);
; Internal routine -- update the 'psnAppUseInputWindowP' flag in the PSN table.
; Called by 'xActivateTSMDocument', and 'xUseInputWindow'.
; Input: Handle is a valid document ID
; Output: none
; Register usage: Use D0,D1,D2,A0,A1
; Modification history:
; 20May92 KST A boolean passed in by C compiler is 4 bytes !! When xUseInputWindow
; calls this routine and pass us the Boolean flag, I used MOVE.B to get
; the flag, which got garbage from the stack. <#35>
; _____________________________________________________________________________________
utaUpdateAppFlagInPSNTable PROC EXPORT
IMPORT utaTSMAwareApplicationP
WITH PSNRecord
; 0(SP) -> return addr
psnParam equ 4 ; 4(SP) -> ptr(PSNRecord)
useFWParam equ 8 ; 8(SP) -> useFloatWindow flag
MOVEA.L psnParam(SP),A0 ; A0 = ptr(PSNRecord)
MOVE.L highLongOfPSN(A0),D0 ; get high half of PSN
MOVE.L lowLongOfPSN(A0),D1 ; get low half of PSN
BSR utaTSMAwareApplicationP ; is it already registered?
BEQ.S @neverRegister ; no, it is not TSM aware? !!
;; It is registered, A1 = ptr(PSNRecord) ...
MOVE.L useFWParam(SP),D2 ; get flag with .L <#35>
MOVE.B D2,psnAppUseInputWindowP(A1); change the APP. flag in PSN record
MOVE.W #$FFFF,D0 ; true (inline aware)
TST.W psnDoWeReallyUseIW(A1) ; is the document using input window?
BEQ.S @3 ; no (inline aware)
MOVEQ #0,D0 ; D0 = false (not inline aware)
@3
;; Inform Process Manager that this application is TSM aware or not...
MOVEA.L psnParam(SP),A0 ; A0 = ptr(PSNRecord)
CLR.W -(SP) ; room for result
MOVE.L A0,-(SP) ; PSN
MOVE.B D0,-(SP) ; Boolean flag
_InlineAware
ADDA.W #2,SP
MOVEQ #0,D0 ; no error
@5
RTS
@neverRegister
MOVE.W #tsmNeverRegisteredErr,D0 ; not TSM aware
BRA.S @5
ENDWITH
ENDP ; utaUpdateAppFlagInPSNTable END
; _________________________________________________________________________
; Function: void utaUpdateDocFlagInPSNTable(idocID);
; Internal routine -- update the 'psnDocUseInputWindowP' flag in the PSN table.
; Called by 'xActivateTSMDocument', and 'xUseInputWindow'.
; Input: Handle is a valid document ID
; Output: none
; Register usage: Use D0,D1,D2,A0,A1
; _________________________________________________________________________
; 0(SP) -> return addr
; 4(SP) -> handle (ID)
utaUpdateDocFlagInPSNTable PROC EXPORT
IMPORT utaTSMAwareApplicationP
WITH PSNRecord, TSMDocumentRecord
MOVEA.L 4(SP),A0 ; A0 = handle
MOVEA.L (A0),A0 ; A0 = doc ID pointer
MOVE.L iDocPSNID1(A0),D0 ; get high half of PSN
MOVE.L iDocPSNID2(A0),D1 ; get low half of PSN
MOVE.B iDocUseInputWindowP(A0),D2 ; get flag when we dereferenced the handle
BSR utaTSMAwareApplicationP ; is it already registered ? (D2 preserved)
BEQ.S @8 ; no, it is not TSM aware? !!
;; It is registered, A1 = ptr(PSNRecord), D2.B = flag ...
MOVE.B D2,psnDocUseInputWindowP(A1); change the doc falg in PSN record
MOVE.W #$FFFF,D0 ; true (inline aware)
TST.W psnDoWeReallyUseIW(A1) ; is the document using input window?
BEQ.S @3 ; no (inline aware)
MOVEQ #0,D0 ; D0 = false (not inline aware)
@3
;; Inform Process Manager that this application is TSM aware or not...
LEA psnHighID(A1),A0 ; PSN addr
CLR.W -(SP) ; room for result
MOVE.L A0,-(SP) ; PSN
MOVE.B D0,-(SP) ; Boolean flag
_InlineAware
ADDA.W #2,SP
MOVEQ #0,D0 ; no error
@8 RTS
ENDWITH
ENDP ; utaUpdateDocFlagInPSNTable END
; _________________________________________________________________________
; Function: utaTSMAwareApplicationP
; Internal routine -- Verify if the application is TSM aware.
; Input: D0.L = high half of PSN. (I don't believe we've designed PSN as 8 bytes !!!)
; D1.L = low half of PSN
; Output: D0.W = true (non-zero) if the app is TSM aware, A1 = ptr(PSNRecord)
; D0.W = false (zero) if the app is not TSM aware.
; and condition code set.
; Register usage: Use D0,D1,A0,A1. D2 must be preserved.
;
; Side Effect: If D0 = true, return pointer to my internal PSN record in A1
; _________________________________________________________________________
utaTSMAwareApplicationP PROC EXPORT
WITH PSNRecord
MOVE.L D3,-(SP) ; free D3
;; make sure PSN is not 0 ...
MOVE.L D0,D3
OR.L D1,D3 ; valid PSN
BEQ.S @tsmAwareExit ; no, both id are 0
MOVEA.L ExpandMem,A0
MOVEA.L ExpandMemRec.emTSMGlobals(A0),A0 ; get TSM global in A0
MOVEA.L TSMVarsRec.tsmIAPSNTablePtr(A0),A0 ; get PSN table
MOVEQ #0,D3
MOVE.W iaAppCount(A0),D3 ; D3.W = total apps registered
BEQ.S @notFound ; none
MOVE.W iaTotalPSNEntryN(A0),D3 ; D3.L = total entries
BEQ.S @notFound ; should not happen, just in case
LEA iaPSNStart(A0),A1 ; A1 = first PSN record
SUBQ #1,D3
@loop
CMP.L psnHighID(A1),D0 ; same id?
BNE.S @5 ; no
CMP.L psnLowID(A1),D1 ; same id?
BEQ.S @found ; yes
@5
ADDA.W #kPSNEntrySize,A1 ; points to the next one
DBRA D3,@loop ; no array overflow check
@notFound
MOVEQ #0,D0 ; not TSM aware
@tsmAwareExit
MOVE.L (SP)+,D3 ; restore D3
TST.W D0 ; set CCR
RTS
@found
MOVEQ #1,D0 ; TSM aware
IF TSMDebug THEN
CMP.W #kPSNTableSignature,psnTableSignature(A1) ; valid table?
BEQ.S @20 ; yes
_debugger
@20
ENDIF
BRA.S @tsmAwareExit
ENDWITH
ENDP ; utaTSMAwareApplicationP
; _____________________________________________________________________________________________
; Function: xCloseTSMAwareApplication()
; Application deregisters itself when quit.
; Input: ProcessSerialNumberPtr.
; Output: D0.W = error code (memFullErr, tsmNotAnAppErr, openDocumentsErr)
; Register usage: Use D0,D1,A0,A1
;
; ¥¥ Note: xCloseTSMAwareApplication can't close the application if there is any document open.
; utKillTSMAwareApplication will close the document and then close the application.
;
; ¥¥ utCloseAppCommon code is shared by InformTSM's @KillTSMApp.
; Do not change the calling convention without changing @KillTSMApp !!
; _____________________________________________________________________________________________
XCLOSETSMAWAREAPPLICATION PROC EXPORT
IMPORT utaTSMAwareApplicationP, utDeleteCleanUpTSMDocument
EXPORT utCloseAppCommon
WITH PSNRecord
;; Verify if we have registered this application ...
SUBA.W #10,SP ; allocate storage for PSN (8 bytes) and result
PEA 2(SP) ; push address of PSN storage
_GetSystemClientProcess ; get PSN with which to associate the file
MOVE.W (SP)+,D0 ; on error, PSN == kNoProcess
BNE.W closeRet ; punt
MOVEQ #0,D2 ; clear flag (no force close)
utCloseAppCommon ; shared by utKillTSMAwareApplication
;; If you change the stack frame for this code, be sure to change utKillTSMAwareApplication
;; If D2 <> 0, then force to close all documents and exit. (called from InformTSM).
;; If D2 == 0 and there is open document, then return error.
;; Verify if we have registered this app already ...
MOVE.L 0(SP),D0 ; get high half of PSN
MOVE.L 4(SP),D1 ; get low half of PSN
BSR utaTSMAwareApplicationP ; is it already registered?
BEQ.S @notTSMaware ; no, it is not TSM aware
;; It is registered, A1 = ptr(PSNRecord) ...
MOVE.L psnDocsTablePtr(A1),D0 ; get document ID table
BEQ.S @docsClosed ; stop if nil
MOVEA.L D0,A0 ; A0 = document ID table
MOVE.W docIDCount(A0),D0 ; any open document?
BEQ.S @docsClosed ; no, OK =>
TST.W D2 ; is this a force close?
BEQ.S docsOpenErr ; no, can't continue
;; This is a force close but there is open document, so let's close the documents for the app.
;; D2 is free register now ...
MOVE.L A1,-(SP) ; save PSNRecord pointer
MOVEQ #0,D0 ; clear 32 bits
MOVE.W docTableEntryN(A0),D0 ; total number of entry
SUBQ #1,D0 ; for DBRAing
LEA docIDStart(A0),A0 ; A0 = points to the first ID
@loop ;; need to preserve A0/D0
MOVE.L (A0)+,D1 ; D1 = doc ID
BEQ.S @1 ; empty
CLR.L -4(A0) ; clear the table entry too
MOVEM.L D0/A0,-(SP) ; save D0/A0 across the call
MOVE.L D1,-(SP) ; push parameter -> ID
JSR utDeleteCleanUpTSMDocument ; delete and clean up the document <#47>
ADDA.W #4,SP ; pop param
MOVEM.L (SP)+,D0/A0 ; restore D0/A0
@1 DBRA D0,@loop
MOVEA.L (SP)+,A1 ; restore PSNRecord pointer
MOVEA.L psnDocsTablePtr(A1),A0 ; A0 = document ID table
;; the document ID table is not released, we just clear the counter for re-use
MOVE.W #0,docIDCount(A0) ; clear counter, all closed
@docsClosed
CLR.L psnHighID(A1) ; mark this PSN slot to be free
CLR.L psnLowID(A1)
CLR.L psnAppUseInputWindowP(A1) ; clear UseInputWindow flags so it will not be reused <#48>
MOVEA.L ExpandMem,A0
MOVEA.L ExpandMemRec.emTSMGlobals(A0),A0 ; get TSM global in A0
MOVEA.L TSMVarsRec.tsmIAPSNTablePtr(A0),A0 ; get PSN table
SUB.W #1,iaAppCount(A0) ; decrease app counter
;; now, inform Process Manager that this process is not TSM aware any more ....
CLR.W -(SP) ; room for result
PEA 2(SP) ; PSN
CLR.W -(SP) ; flag = flase
_InlineAware ; not aware
ADDA.W #2,SP ; ignore error
MOVEQ #0,D0 ; return no error
BRA.S closeRet
@notTSMaware
MOVE.W #tsmNeverRegisteredErr,D0 ; return error
BRA.S closeRet
docsOpenErr ; can't close because there is open documents
MOVE.W #tsmDocumentOpenErr,D0 ; return error
closeRet
LEA 8(SP),SP ; restore sp
MOVE.W D0,4(SP) ; return error in Pascal style
RTS
ENDWITH
ENDP ; XCLOSETSMAWAREAPPLICATION END
; _______________________________________________________________________________
; Function: pascal OSErr utaGetTSMAwareDocTable(ProcessSerialNumberPtr, docTablePtr)
; Verify if the application is TSM aware.
; If the USEINPUTWINDOW flag is set, we treat the app as non-TSM aware!
; If the app is TSM aware, then return its document table pointer in docTablePtr.
; If error, then docTablePtr has undefined value.
; Input: ProcessSerialNumberPtr.
; docTablePtr = pointer to docTable.
; Output: D0.W = error code (memFullErr, temNeverRegisteredErr, tsmUseInputWindowErr),
; D0.W = noErr if it is TSM aware.
; Register usage: Use D0,D1,A0,A1
; _______________________________________________________________________________
UTAGETTSMAWAREDOCTABLE PROC EXPORT
Import UTAISAPPTSMAWAREANDNOTUSINGIW
WITH PSNRecord
MOVEA.L 8(SP),A1 ; get ProcessSerialNumberPtr
CLR.W -(SP)
MOVE.L A1,-(SP) ; push ProcessSerialNumberPtr
JSR UTAISAPPTSMAWAREANDNOTUSINGIW ; get doc table ptr
MOVE.W (SP)+,D0 ; is it TSM aware or use input window?
BNE.S @5 ; no
MOVEA.L 4(SP),A0 ; get pointer to docTable
MOVE.L psnDocsTablePtr(A1),(A0) ; return docTable
@5
MOVEA.L (SP)+,A0 ; get return address
LEA 8(SP),SP ; restore sp
MOVE.W D0,(SP) ; return error in Pascal style
JMP (A0)
ENDWITH
ENDP
; _______________________________________________________________________________
; Function: utaGetTSMAppRecordPtr(ProcessSerialNumber *PSNRecord, TSMAppsRecord **appRecordPtr);
; Verify if the application is TSM aware.
; If the USEINPUTWINDOW flag is set, we treat the app as non-TSM aware!
; If the app is TSM aware, then return its document table pointer in docTablePtr.
; If error, then docTablePtr has undefined value.
; Input: ProcessSerialNumberPtr.
; docTablePtr = pointer to docTable.
; Output: D0.W = error code (memFullErr, temNeverRegisteredErr, tsmUseInputWindowErr),
; D0.W = noErr if it is TSM aware.
; Register usage: Use D0,D1,A0,A1
; _______________________________________________________________________________
UTAGETTSMAPPRECORDPTR PROC EXPORT
Import utaTSMAwareApplicationP
WITH PSNRecord
MOVEA.L 8(SP),A1 ; get ProcessSerialNumberPtr
MOVE.L highLongOfPSN(A1),D0 ; get high half of PSN
MOVE.L lowLongOfPSN(A1),D1 ; get low half of PSN
BSR utaTSMAwareApplicationP ; is it already registered?
BEQ.S @5 ; no, it is not TSM aware
MOVEA.L 4(SP),A0 ; get pointer to psn record
MOVE.L A1,(A0) ; return record
MOVEQ #0,D0 ; return noErr
@return
MOVEA.L (SP)+,A0 ; get return address
LEA 8(SP),SP ; restore sp
MOVE.W D0,(SP) ; return error in Pascal style
JMP (A0)
@5
MOVE.W #tsmNeverRegisteredErr,D0 ; return error
BRA.S @return
ENDWITH
ENDP
; _______________________________________________________________________________
; Function: pascal OSErr utaGetAppsUseInputWindowFlag(ProcessSerialNumberPtr, booleanPtr)
; Verify if the application is TSM aware.
; If the USEINPUTWINDOW flag is set, we treat the app as non-TSM aware!
; Input: ProcessSerialNumberPtr.
; Output: D0.W = error code (memFullErr, temNeverRegisteredErr, tsmUseInputWindowErr),
; D0.W = noErr if it is TSM aware and not using input window.
; A1.L = ptr(PSNRecord table entry)
; Register usage: Use D0,D1,A0,A1
; _______________________________________________________________________________
UTAGETAPPSUSEINPUTWINDOWFLAG PROC EXPORT
Import utaTSMAwareApplicationP
retaddr equ 0
booleanPtr equ 4
psnPtr equ 8
MOVEA.L psnPtr(SP),A1 ; get ProcessSerialNumberPtr
MOVE.L highLongOfPSN(A1),D0 ; get high half of PSN
MOVE.L lowLongOfPSN(A1),D1 ; get low half of PSN
BSR utaTSMAwareApplicationP ; is it already registered?
BEQ.S @5 ; no, it is not TSM aware
MOVE.B PSNRecord.psnAppUseInputWindowP(A1),D1; get the byte
@3
MOVEQ #0,D0 ; return noErr
MOVEA.L (SP)+,A0 ; get return address
MOVEA.L (SP)+,A1 ; get boolean address
MOVE.B D1,(A1) ; return flag
MOVE.L A0,(SP) ; remove parameter
MOVE.W D0,4(SP) ; return error in Pascal style
RTS
@5
MOVE.W #tsmNeverRegisteredErr,D0 ; return error
BRA.S @3
ENDP
; _______________________________________________________________________________
; Function: pascal OSErr utaIsAppTSMAwareAndNotUsingIW(ProcessSerialNumberPtr)
; Verify if the application is TSM aware and use input window or not.
; If the USEINPUTWINDOW flag is set, we treat the app as non-TSM aware!
; Input: ProcessSerialNumberPtr.
; Output: D0.W = error code (memFullErr, temNeverRegisteredErr, tsmUseInputWindowErr),
; D0.W = tsmUseInputWindowErr means the app is TSM aware !!!!
; D0.W = noErr if it is TSM aware and not using input window.
; A1.L = ptr(PSNRecord table entry)
; Register usage: Use D0,D1,A0,A1
; _______________________________________________________________________________
UTAISAPPTSMAWAREANDNOTUSINGIW PROC EXPORT
Import utaTSMAwareApplicationP
;; Verify if we have registered this application ...
MOVEA.L 4(SP),A1 ; get ProcessSerialNumberPtr
MOVE.L highLongOfPSN(A1),D0 ; get high half of PSN
MOVE.L lowLongOfPSN(A1),D1 ; get low half of PSN
BSR utaTSMAwareApplicationP ; is it already registered?
BEQ.S @5 ; no, it is not TSM aware
;; It is registered, A1 = ptr(PSNRecord)
TST.W psnDoWeReallyUseIW(A1) ; is the document using input window?
BNE.S @7 ; yes, if any of the 2 flags is set, return error
MOVEQ #noErr,D0 ; no error
@3
MOVEA.L (SP)+,A0 ; get return address
MOVE.L A0,(SP) ; remove parameter
MOVE.W D0,4(SP) ; return error in Pascal style
RTS
@5
MOVE.W #tsmNeverRegisteredErr,D0 ; return error
BRA.S @3
@7
MOVE.W #tsmUseInputWindowErr,D0 ; return error
BRA.S @3
ENDP ; xIsApplicationTSMAware END
; _______________________________________________________________________________
; Function: pascal OSErr xInformTSM(msgNumber, msgParamPtr)
; Inform TSM with some messages
; Input:
; Output: noErr if all OK
; Register usage: Use D0,D1,D2,A0,A1
; Stack frame:
; SP => 00(SP).L -> return addr
; 04(SP).L -> msgParamPtr
; 08(SP).W -> msgSelector
; 10(SP).W -> msgResult
; _______________________________________________________________________________
XINFORMTSM PROC EXPORT
Import utCloseAppCommon, utChangeToOldJIM, utInformPMgr, utSuspendResumeApp
msgParamPtr equ 4
msgSelector equ 8
msgResult equ 10
MOVE.W msgSelector(SP),D0 ; get selector
BEQ @noopExit ; no op
MOVEA.L msgParamPtr(SP),A1 ; get param ptr(script/id) <06Feb92 #18>
CMP.W #kMsgBkgAppsPSN,D0 ; is SWM passing me the PSN?
BEQ.S @getSWMsPSN ; yes
CMP.W #kMsgKillTSMApp,D0 ; kill the application?
BEQ.S @KillTSMApp ; yes
CMP.W #kMsgSuspendApp,D0 ; suspend the non-TSM aware application?
BEQ.S @SuspendApp ; yes
CMP.W #kMsgResumeApp,D0 ; resume the non-TSM aware application?
BEQ.S @ResumeApp ; yes
CMP.W #kMsgHelpHELPMgr,D0 ; kMsgHelpHELPMgr?
BEQ.W @tsmHelpMgrPatch ; yes
CMP.W #kMsgChangeToOldJIM,D0 ; change to old JIM
BNE.W @bad ; no
; _______________________________________________________________
; Function: void utChangeToOldJIM()
; User wants to switch to old input method (for Japanese script only)
; Input: none
; A1 = param record pointer
; Output: noErr if all OK
; tsmTSNotOpenErr = JIM is not open.
; _______________________________________________________________
MOVE.L A1,-(SP) ; pass the parameter <06Feb92 #18>
JSR utChangeToOldJIM ; for Japanese script only
TST.L (SP)+ ; pop param <06Feb92 #18>
BRA.S @noopExit ; and exit
; _______________________________________________________________
; Function: void SuspendApp()
; User wants to switch to old input method (for Japanese script only)
; Input: none
; A1 = param record pointer
; Output: noErr if all OK
; tsmTSNotOpenErr = JIM is not open.
; _______________________________________________________________
@SuspendApp
MOVE.L #kTSMSuspend,-(SP) ; pass the parameter
@SuspendResume
JSR utSuspendResumeApp ; suspend/resume
TST.L (SP)+ ; pop param
BRA.S @noopExit ; and exit
@ResumeApp
MOVE.L #kTSMResume,-(SP) ; pass the parameter
BRA.S @SuspendResume
; _______________________________________________________________
; Function: utKillTSMAwareApplication(ProcessSerialNumberPtr)
; Called from Patches:MiscPatches.a
; Input: ProcessSerialNumberPtr.
; A1 = param record pointer
; Output: noErr if all OK
;
; Modification history:
; 25Feb92 KST If the app is not TSM aware, we'll send an AE to SWM
; ask it to close its input window.
; 27Feb92 KST Set tsmKillApplicationP flag to signal we're killing the
; TSM aware application, and the menu is already killed !!
; 27Mar92 KST If the app is not TSM aware, we'll not be called.
; _______________________________________________________________
@KillTSMApp
;; When 'utCloseAppCommon' is called, it expects D2 is used as a flag,
;; and the stack frame looks like this:
;
; SP --> highLongOfPSN (long)
; lowLongOfPSN (long)
; return address (long)
; (high addr) result (word)
;
; ¥¥ Do not change this without changing XCLOSETSMAWAREAPPLICATION !!
MOVEA.L ExpandMem,A0
MOVEA.L ExpandMemRec.emTSMGlobals(A0),A0; get TSM global in A0
ST.B TSMVarsRec.tsmKillApplicationP(A0) ; set flag <#20>
MOVEQ #1,D2 ; set flag, force close the app
SUBA.W #2,SP ; room for result
PEA @return2Here ; return address
MOVE.L lowLongOfPSN(A1),D1 ; get low half of PSN
MOVE.L D1,-(SP) ; push low PSN
MOVE.L highLongOfPSN(A1),D1 ; get high half of PSN
MOVE.L D1,-(SP) ; push hign PSN
JMP utCloseAppCommon ; use common code, D2 is the flag
@return2Here
ADDA.W #2,SP ; ignore error
MOVEA.L ExpandMem,A0
MOVEA.L ExpandMemRec.emTSMGlobals(A0),A0; get TSM global in A0
CLR.B TSMVarsRec.tsmKillApplicationP(A0) ; clear flag <#20>
MOVEQ #0,D0 ; always success
BRA.S @noopExit ; and exit
; _______________________________________________________________
; Function: getSWMsPSN(SWM's ProcessSerialNumberPtr)
; Input: ProcessSerialNumberPtr.
; A1 = param record pointer
; Output: noErr if all OK
; _______________________________________________________________
@getSWMsPSN
Import xInitTSMAwareDriver
MOVEA.L ExpandMem,A0
MOVEA.L ExpandMemRec.emTSMGlobals(A0),A0; get TSM global in A0
MOVE.L highLongOfPSN(A1),D1 ; get high ID
MOVE.L D1,TSMVarsRec.tsmSWMHighPSN(A0) ; save in TSM global
MOVE.L lowLongOfPSN(A1),D1 ; get low ID
MOVE.L D1,TSMVarsRec.tsmSWMLowPSN(A0) ; save in TSM global
JSR utInformPMgr ; set up flag
MOVEA.L msgParamPtr(SP),A0 ; get param ptr which points at the PSN
MOVEA.L (SP),A1 ; get return addr
SUBQ #2,SP ; get 2 more bytes on the
MOVE.L highLongOfPSN(A0),highLongOfPSN(SP)
MOVE.L lowLongOfPSN(A0),lowLongOfPSN(SP)
MOVE.L A1,8(SP) ; move the return address
JMP xInitTSMAwareDriver ; return through InitTSMAware
@noopExit ; exit point shared by all InformTSM subfunctions
MOVEA.L (SP),A1 ; get return addr
LEA 10(SP),SP ; pop off params
MOVE.W D0,(SP) ; result
JMP (A1) ; return to caller
MOVEQ #0,D0 ; always success
BRA.S @noopExit ; and exit
@bad ; bad selector
MOVE.W #paramErr,D0 ; return error
BRA.S @noopExit
; _______________________________________________________________
; Function: tsmHelpMgrPatch
; Input:
; A1 = param record pointer
; Output: 1. return noErr if the mouse is over a floating window and,
; 2. also return that windowptr in tsmHelpWindowPtr, and
; 3. if the mouse is over content region, we'll try to open the
; resource file and return the refnum in tsmHelpRefnum.
; (If the window is a system floating window and refcon <> nil).
; Side effect:
; If we return noErr, then tsmHelpWindowPtr must contains a floating window,
; because Help Manager will later swap the layer to floating layer.
;
; (6) parameter for kMsgHelpHELPMgr -- record of 10 bytes:
; tsmHelpRefnum EQU 0 ; > 0 if we opened IM's resource file
; tsmHelpWindowPtr EQU 2 ; nil if no floating window
; tsmHelpSavedLayer EQU 6 ; temp. storage for Help Manager to swap the layer
; tsmHelpRecSize EQU tsmHelpSavedLayer+4
; _______________________________________________________________
@tsmHelpMgrPatch
MOVEM.L A2/A3,-(SP) ; save A2/A3
CLR.W tsmHelpRefnum(A1) ; clear Refnum
CLR.L tsmHelpWindowPtr(A1) ; clear WindowPtr
MOVEA.L A1,A2 ; A2 = param ptr
SUBQ #2,-(SP) ; room for result
MOVE.L Mouse,-(SP) ; pass the global mouse on stack
PEA tsmHelpWindowPtr(A2) ; pass WindowPtr
_FindServiceWindow
MOVE.W (SP)+,D0 ; over our window?
BEQ.S @helpErrReturn ; no
CMP.W #inSysWindow,D0 ; in system item, menubar <#46>
BLE.S @helpErrReturn ; exit if yes, not over a floater <#46>
CMP.W #inContent,D0 ; in content?
BNE.S @windowHasNoInstance ; no, just swap the layer
MOVEA.L tsmHelpWindowPtr(A2),A3 ; save the window ptr in A3
;; OK, the mouse is over a floating window so open the resource file so that
;; Help Manager can dig out the Balloon resource ...
;; But first, let's check if the window is a system floating window and refcon <> nil. <#45>
;; from here on, we return noErr to indicate the mouse is over a floater ...
CMP.W #systemFloatKind,WindowRecord.windowKind(A3) ; is this floater belonging to a text service <#45>
BNE.S @windowHasNoInstance ; if not, don't try to open its resource file <#45>
MOVE.L WindowRecord.refcon(A3),D0 ; is there an Instance?
BEQ.S @windowHasNoInstance ; if not, then don't try to open anything
SUBQ #2,-(SP) ; room for result
MOVE.L D0,-(SP) ; the Component instance
;; need special case for SWM
_OpenComponentResFile
MOVE.W (SP)+,D0 ; is it open?
BLE.S @helpErrReturn ; no
MOVE.W D0,tsmHelpRefnum(A2) ; return the RefNum
@windowHasNoInstance
MOVEQ #0,D0 ; OK
BRA.S @helpPopStack
@helpErrReturn
CLR.W tsmHelpRefnum(A2) ; clear Refnum
CLR.L tsmHelpWindowPtr(A2) ; clear WindowPtr
MOVE.W #paramErr,D0 ; return error
@helpPopStack
MOVEM.L (SP)+,A2/A3 ; restore A2/A3
BRA.S @noopExit
ENDP ; XINFORMTSM END
; END InformTSM
;; Begin patches ...
IF not BuildTSMInit THEN
; _______________________________________________________________________________
; SetCursor Patch
;
; Applications such as Finder periodically set the cursor. This is a problem
; if IM changes the cursor over floating window. The cursor will now flash
; because 2 parties compete changing the cursor. This patch will temporarily
; disable the SetCursor call if IM or SWM changed the cursor.
; _______________________________________________________________________________
__SetCursorPatch PatchProc _SetCursor,(Plus,SE,II,Portable,IIci)
move.l ExpandMem,a0 ; good old ExpandMem again
move.l ExpandMemRec.emTSMGlobals(a0),a0 ; our global ptr into a0
btst #kIMJustSetCursorBit,TSMVarsRec.tsmPatchFlags(a0) ; should we let SetCursor calls through?
bne.s @JustRTS ; flag is on nobody can set the cursor until it clears
;; kSWMJustSetCursorBit is set in SWM driver ....
btst #kSWMJustSetCursorBit,TSMVarsRec.tsmPatchFlags(a0) ; should we let SetCursor calls through?
bne.s @JustRTS ; flag is on nobody can set the cursor until it clears
jmpOld ; flag is clear go ahead and set the cursor
nop ; <sm5>
@JustRTS
move.l (sp)+,a0 ; pop return address <32>
addq #4,sp ; flush the parameter on the stack <32>
jmp (a0) ; return to the caller. <32>
ENDPROC
; _______________________________________________________________________________
; PaintBehind Patch
; AfterDark redraws the screen with FrontWindow(), and grayrgn. This however,
; does not draw the floating windows. This patch will paint from IM layer if
; theWindow = frontwindow, and theRegion = GrayRgn.
; _______________________________________________________________________________
__PaintBehindPatch PatchProc _PaintBehind,(Plus,SE,II,Portable,IIci)
theRetAddr EQU 0 ; satck frame for this call
theRegion EQU 4
theWindow EQU 8
SUBA.W #4,SP
_FrontWindow
MOVE.L (SP)+,D0
CMP.L theWindow(SP),D0 ; draw from the front window?
BNE.S @NeverMind ; no
MOVEA.L GrayRgn,A0 ; get the GRAY region handle
MOVEA.L (A0),A0 ; dereference it
LEA rgnBBox+bottom(A0),A0 ; A0 points to bottom
MOVEA.L theRegion(SP),A1 ; get the region
MOVEA.L (A1),A1 ; dereference it
LEA rgnBBox+top(A1),A1 ; A1 points to top
;; Note: Pyro always pass the region with -1, -1, bottom+1, right+1,
;; and this is why I don't branch with BNE or BEQ ...
TST.W (A1)+ ; top should be 0
BGT.S @NeverMind ; if > 0, then don't do anything special
TST.W (A1)+ ; left should be 0
BGT.S @NeverMind ; if > 0, then don't do anything special
;; A1 points to bottom of rect
MOVE.W (A1)+,D0
CMP.W (A0)+,D0 ; paint the whole desktop?
BLT.S @NeverMind ; no
MOVE.W (A1),D0
CMP.W (A0),D0 ; paint the whole desktop?
BLT.S @NeverMind ; no
;; Here, we assume the guy is trying to paint the whole screen, let's paint the floating windows too.
;; Dean said: "Just paint from input method's floating layer". -- (04May92)
;; I tried paint from the root layer, Balloon window's contents doesn't get redraw anyway.
SUBA.W #6,SP
PEA 2(SP)
_GetFrontServiceWindow
MOVE.W (SP)+,D0 ; any error?
BNE.S @NeverMind ; br if error
MOVE.L (SP)+,D0 ; get the front floating window
BEQ.S @NeverMind ; br if no floating window
MOVE.L D0,theWindow(SP) ; paint from the root
@NeverMind
jmpOld ; flag is clear go ahead and set the cursor
ENDPROC
__SystemMenuPatch PatchProc _SystemMenu,(Plus,SE,II,Portable,IIci)
import CHANGEMENURESULTFORINPUTMETHOD
move.l 4(sp),d0 ;get menuresult
swap d0 ;make the high word low
cmp.w #-kTSMSystemMenuID,d0 ;is this us?
bne.s @NotTSMMenu ;
swap d0 ;put the high word back
move.l d0,-(sp) ;move it onto the stack
pea (sp) ;push the address
jsr CHANGEMENURESULTFORINPUTMETHOD ;and send it to the input method
addq #4,sp ;get rid of space for menuresult
rts ;return to caller
@NotTSMMenu
jmpOld ;not ours so forget about it
ENDPROC
; ____________________________________________________________________________________
; __HMGetBalloonPatch Patch
; Again, applications such as Finder periodically redraw the Help balloon. This is
; a problem if there is a help balloon over the floating window. The balloon window
; will flash because app tries to remove the Balloon and paint one of its own.
; Trashes D0/A0/A1 -- these are free registers, right?
; ____________________________________________________________________________________
__HMGetBalloonPatch PatchProc _Pack14,(Plus,SE,II,Portable,IIci)
cmp.w #kHMGetBalloons,d0 ; is this IsBalloon?
beq.s @DoGetBalloonPatch ; yes so do it
nop ; <sm5>
jmpOld ; it wasn't kHMIsBalloon so call the real Pack14
@DoGetBalloonPatch
subq #2,sp ; room on the stack
jsrOld ; and jump to the old one
move.b (sp)+,d0 ; get resut
move.b d0,4(sp) ; and put in on the stack
beq.s @returnOldResult ; no balloon, so return the result to original caller
;
; OK so a ballon is up see if the last window we helped was a floating window
; we do that by getting the parent of the last window helped
; and seeing if that parent equals the IMlayer. This patch is for Finder because
; Finder does not know/care the floating window and draw its own Balloon.
;
; Now check if we are clicked inside of a floating window ... <#44>
SUBQ #6,SP ; room for result
MOVE.L Mouse,-(SP) ; pass the global mouse on stack
PEA 6(SP) ; pass WindowPtr
_FindServiceWindow
MOVE.W (SP)+,D0 ; over our window?
ADDQ.W #4,SP ; restore the stack
BEQ.S @returnOldResult ; no
CMP.W #inSysWindow,D0 ; in system item, menubar? <#39>
BLE.S @returnOldResult ; exit if yes, return the original result <#39>
MOVEA.L ExpandMem,A1 ; A1 = ExpandMem <#44>
MOVE.L ExpandMemRec.emTSMGlobals(A1),D0 ; get TSM global <#44>
BEQ.S @noTSM ; br if no TSM <#44>
MOVEA.L D0,A0 ; A0 = TSM global <#44>
;; If we are inside of PopUpMenuSelect, then say the balloon is on so that a previous balloon will be removed correctly.
BTST #kInTSMPopUpMenuSelectCall,TSMVarsRec.tsmPatchFlags(A0) ; are we in PopUpMenuSelect? <#44>
BNE.S @returnOldResult ; flag is on so return the original result <#44>
@noTSM
;; If we are inside of MenuSelect, then say the balloon is on so that a previous balloon will be removed correctly.
;; Note Help Manager already patched out __MenuSelect and set a flag in emHelpGlobals, so we'll just use that one !!
MOVE.L ExpandMemRec.emHelpGlobals(A1),A0 ; A0 = HelpMgr global ptr <#47>
TST.B hmgInMenuSelectFlag(A0) ; are we in MenuSelect? <#47>
BNE.S @returnOldResult ; yes so return the original result <#47>
;; end change of #44, #47
MOVE.B #0,4(sp) ; pretend no help windows are up by slamming the result to 0
@returnOldResult
RTS ; and return
ENDPROC
; ____________________________________________________________________________________
; __PopUpMenuSelect Patch <#44>
; If there is a popup menu in the floating window and with HelpMgr on, need to
; return the original result from HMGetBalloon so that balloon will be removed.
; ____________________________________________________________________________________
__PopUpMenuSelect PatchProc _PopUpMenuSelect,(Plus,SE,II,Portable,IIci)
retAddr EQU 8 ; saved 2 registers
MOVEM.L A0-A1,-(SP) ; free A0/A1
MOVEA.L ExpandMem,A1
MOVE.L ExpandMemRec.emTSMGlobals(A1),D1 ; get TSM global
BEQ.S @noEntry ; br if no TSM
MOVEA.L D1,A1 ; A1 = TSM global
BSET #kInTSMPopUpMenuSelectCall,TSMVarsRec.tsmPatchFlags(A1) ; say we're in PopupMenuSelect
MOVE.L retAddr(SP),D1 ; return address
MOVE.L D1,TSMVarsRec.tsmPopUpReturnAddr(A1) ; save the return address
LEA @return2Here,A0 ; return to here
MOVE.L A0,retAddr(SP)
;; OK, now to prevent from text services to receive an update event from SWM driver,
;; we need to tell SWM not to route events to TSM/text services ...
MOVE.W TSMVarsRec.tsmSWMDrvrRefNum(A1),D1 ; get refnum
BEQ.S @noEntry ; br if no SWM
NOT.W D1 ; unit entry := -1 * (refNum + 1)
cmp.w UnitNtryCnt,D1 ; is there an entry of this number?
bhs.s @noEntry ; no, so return NIL
LSL.W #2,D1 ; index := entry * 4
MOVE.L UTableBase,A1 ; unit I/O table [pointer]
MOVEA.L 0(A1,D1.W),A1 ; return DCtlHandle
MOVEA.L (A1),A1 ; dereference the handle
MOVEA.L dCtlStorage(A1),A1 ; get storage handle
MOVEA.L (A1),A1 ; dereference the handle
ST swmdrvrRecordMenuIsDown(A1) ; set the byte to true
@noEntry
MOVEM.L (SP)+,A0-A1 ; restore A0/A1
jmpOld ; and jump to the old one
@return2Here
MOVEA.L ExpandMem,A1
MOVE.L ExpandMemRec.emTSMGlobals(A1),A1 ; get TSM global
BCLR #kInTSMPopUpMenuSelectCall,TSMVarsRec.tsmPatchFlags(A1) ; we're not in PopupMenuSelect
MOVE.L TSMVarsRec.tsmPopUpReturnAddr(A1),D1 ; get the return address
MOVE.L D1,-(SP) ; return to caller
MOVE.W TSMVarsRec.tsmSWMDrvrRefNum(A1),D1 ; get refnum
BEQ.S @exit ; br if no SWM
NOT.W D1 ; unit entry := -1 * (refNum + 1)
cmp.w UnitNtryCnt,d1 ; is there an entry of this number?
bhs.s @exit ; no, so return NIL
LSL.W #2,D1 ; index := entry * 4
MOVE.L UTableBase,A1 ; unit I/O table [pointer]
MOVEA.L 0(A1,D1.W),A1 ; return DCtlHandle
MOVEA.L (A1),A1 ; dereference the handle
MOVEA.L dCtlStorage(A1),A1 ; get storage handle
MOVEA.L (A1),A1 ; dereference the handle
CLR.B swmdrvrRecordMenuIsDown(A1) ; clear the byte
@exit
RTS
ENDPROC
ENDIF ; end if building INIT
; _______________________________________________________________________________
; pascal short Gestalt(OSType selector, long responsePtr)
; Define a new Gestalt call to return TSM's version.
; _______________________________________________________________________________
TSMGestalt PROC EXPORT
MOVE.L 4(A7),A0 ; Return result to caller (responsePtr)
MOVE.L #TSMVersion,(A0) ; get version number
MOVE.L (SP)+,A0 ; Get return address
ADDQ #8,A7 ; Nuke some parameters
CLR.W (A7) ; no error
JMP (A0) ; return
ENDPROC
;============================================================================================
;
; InstallProc for the Text Services Manager -- allocate memory for globals.
;
;============================================================================================
TSMGRINSTALL proc export
WITH PSNRecord
MOVEA.L ExpandMem,A1
MOVE.L ExpandMemRec.emTSMGlobals(A1),D0 ; get TSM global
MOVEA.L D0,A1 ; clear A1 flag
BEQ.S @noGlobal ; not initialized
MOVE.W TSMVarsRec.tsmRecSize(A1),D0 ; record size
CMP.W #TSMVarsRec.TSMVarsRecSize,D0 ; are they the same size?
BEQ.W @return ; yes, reuse it
@noGlobal
;; allocate TSM global, and save it in ExpandMem ...
;; A1 <> nil if we have allocated the globals already.
;; all fields are initially cleared (0 or flase) !
MOVE.L #TSMVarsRec.TSMVarsRecSize,D0
_NewPtr ,Sys ,Clear ; allocate global from system heap
BNE.W @cantboot ; fatal error
;; A0 = new record, A1 = old record, copy A1 => A0,
MOVE.L A1,D0 ; do we have an old one?
BEQ.S @noOldRecord ; no
MOVEQ #0,D0
MOVE.W TSMVarsRec.tsmRecSize(A1),D0 ; old record size
EXG A0,A1 ; A0 = old record
_BlockMove ; A0 => A1 (preserved)
_DisposePtr ; free the old one
MOVEA.L ExpandMem,A0
MOVE.W #TSMVarsRec.TSMVarsRecSize,TSMVarsRec.tsmRecSize(A1) ; new record size
MOVE.L A1,ExpandMemRec.emTSMGlobals(A0) ; save the new TSM global in ExpandMem
BRA.S @return ; OK
@noOldRecord
MOVE.W #TSMVarsRec.TSMVarsRecSize,TSMVarsRec.tsmRecSize(A0)
MOVE.B #0, TSMVarsRec.tsmMajorVersion(A0) ; 0.1
MOVE.B #kTSMVersion, TSMVarsRec.tsmMinorVersion(A0) ; not released yet
MOVE.W #kUnknownScript,TSMVarsRec.tsmCurrentSLRec.fScript(A0) ; current script = unknown
MOVE.W #kUnknownLanguage,TSMVarsRec.tsmCurrentSLRec.fLanguage(A0) ; current language = unknown
MOVE.L #$4B534354,TSMVarsRec.tsmDebugSignature(A0)
MOVEA.L ExpandMem,A1
MOVE.L A0,ExpandMemRec.emTSMGlobals(A1) ; save TSM global in ExpandMem
MOVE.L A0,A1 ; save global in A1
;; allocate TSM aware PSN table, and save it in TSM global ...
MOVE.L #kPSNTableDefSize,D0 ; allocate TSM aware PSN table
_NewPtr ,Sys ,Clear ; from system heap
BNE.S @cantboot2 ; fatal error
MOVE.L A0,TSMVarsRec.tsmIAPSNTablePtr(A1) ; save the table addr in global too
MOVE.W #kDefTableEntryN,D0
MOVE.W D0,iaTotalPSNEntryN(A0) ; total entry number of the table
; LEA iaPSNStart(A0),A0 ; A0 points to the start of the array
; SUBQ.W #1,D0 ; for dbra
@loop1
; MOVE.W #kPSNTableSignature,psnTableSignature(A0) ; valid table signature
; ADDA.W #kPSNEntrySize,A0 ; next record
; DBRA D0,@loop1
; can't update default IM in TSM globals because we can't save the component, just description. too bad.
MOVE.L #gestaltTSMgrVersion,D0 ; selector to d0
import TSMGestalt
lea TSMGestalt,A0 ; get our function pointer into A0
_NewGestalt ; install it
MOVEQ #0,D0 ; all done
@return
RTS
@cantboot2
MOVE.L A1,A0
_DisposePtr ; free global
MOVEA.L ExpandMem,A0
CLR.L ExpandMemRec.emTSMGlobals(A0) ; clear TSM global
@cantboot
MOVEQ #dsMemFullErr,D0 ; no mem error
_SysError
BRA.S @return
ENDWITH
ENDPROC ; TSMgrInstall END
;============================================================================================
;
; old input method support.
;
;============================================================================================
; _______________________________________________________________________________
; pascal Boolean OldJapaneseInputMethodExists( short fepID);
;
; return true if the old Input Method which has the given id is installed.
; _______________________________________________________________________________
ojimRecord RECORD {a6link},decr
boolResult ds.w 1 ; activate result.
fepID ds.w 1 ; interface routine ID number.
return ds.l 1 ; return address.
a6link ds.l 1 ; old a6 register.
ojimRecord equ * ; size of local variables.
ENDR
OLDJAPANESEINPUTMETHODEXISTS PROC EXPORT
WITH ojimRecord,intfRecord,ScriptSystemGlobals,SMgrRecord
link a6,#ojimRecord
clr.w boolResult(a6) ; assume not found.
GetSmgrCore a0 ; load script manager core.
move.l smgrEntry+(smJapanese*4)(a0),d0 ; load doubleTalkRecord for Japanese.
beq.s @exit ; not installed. (something wrong)
move.l d0,a0
move.l intfArray(a0),d0 ; get the array handle.
ble.s @exit ; nil or negative -> something wrong.
move.l d0,a1 ; Load table handle.
move.l (a1),a1 ; Load table pointer.
move.l (a1)+,d0 ; Load table length.
move.w fepID(a6),d1 ; Load search id number.
bra.s @1 ; enter loop at bottom
@0
move.l (a1)+,a0 ; load table entry.
cmp.w (a0),d1 ; same id number?
beq.s @foundID ; yes -> we found it!
@1 dbra d0,@0 ; do the next entry.
bra.s @exit
@foundID
move.w #$0100,boolResult(a6) ; return (Pascal) true.
@exit
unlk a6
move.l (sp)+,a0 ; pop the return address.
addq #2,sp ; pop the Integer arguments.
jmp (a0) ; return to the caller.
ENDWITH
ENDPROC
END