;__________________________________________________________________________________________________ ; File: PaletteMgr.a ; ; Contains: The Palette Manager ; ; Written by: Art Cabral and David Van Brink and lots of others ; ; Copyright: © 1987-1993 by Apple Computer, Inc., all rights reserved. ; ; Change History (most recent first): ; ; 10/28/93 SAH Rolled out change SM9 because it brought out bugs in the font ; manager. Rolled out change 14 because it caused the bug that ; caused change SM9. Both of these are correct changes, we just ; need to take them out until FlushFonts really flushes ALL the ; fonts (for all processes)... ; 10-19-93 jmp Removed the ctSeed whacking (Kon explained the error of my ; ways). WeÕll have to come up with some other method to fix ; dimming. ; 9/20/93 SAH Fixed a bug in ActivatePalette where it would always mark black ; or white tolerant entries as handled. It really needed to make ; sure they weren't explicit as well. ; 9/13/93 SAM Added a "code" to PMExit to call _TrashProcess (HeapUtilities). ; 08-03-93 jmp Changed the SetDepth code so that the MenuBar gets redrawn first ; after a depth switch. This is the way the pre-System7 Monitors ; 'cdev' did things. And it looks much nicer. ; 1/13/93 kc Export ReleaseList so that we can vectorize it. ; 12/11/92 HI Changes the HasLayers conditional to 1 from 0. SuperMario ROM ; has LayerMgr. Wrong conditional produced the wrong code in ; SetDepth which ends up calling PaintOne/PaintBehind sequence ; instead of RedrawAll. This fixes the problem of balloon help ; update problem when changing bit depths within Monitors CP. ; (Hoon Im) ; 5/21/92 kc Change the name of Allocate to PMAllocate to avoid name conflict ; with the glue. ; 5/4/92 FM fix typo ; 5/4/92 FM Roll in changes from PatchIICiRom.a file that were "lost" in the ; review processÉSave and restore window list in PMgrExit. Also ; zero out d3/d4 in resize palette so that the high word won ; <45> 7/10/91 JSM Remove obsolete SysVers conditional and obsolete ExitToShell ; patch. ; ; <44> 2/26/91 DFH csd,WS#910226a: Fixed bug in ptchPMgrExit where it assumed that ; graphics has been initialized. Bug introduced by change <43>. ; <43> 1/18/91 dvb Don't restore color environment if it hasn't been changed. ; <42> 1/3/91 VL (ngk) Replaced undefined HasLayerMgr conditional with HasLayers. ; (HasLayerMgr is actually set for system build. However, since ; this file is included by files like PatchIIROM.a which may not ; be used for system build, the conditional never gets set.) Also ; used new LayerMgr call RedrawAll to refresh screen in SetDepth. ; <41> 12/14/90 SMC Changed DisposeAppPalettes to use ApplZone->bklim to determine ; if palette is in the application heap. With DFH. ; <40> 12/14/90 jmp SetDepth had a problem where the port was NOT being preserved, ; so we (jmp & smc) moved the port preserving code to come just ; before the InitGDevice call. Also, for Layer Manager support, ; we changed the PaintOne/PaintOne sequence to be a ; PaintOne/PaintBehind sequence per dba & vl. ; <39> 10/30/90 DC ngk - Add a check for the basic four-bit grayscale clut in ; CheckColors ; <38> 10/24/90 DC VL - Fix CheckColors to use bit 2 of the value field as an ; inhibit bit instead of an enable bit ; <37> 10/12/90 jmp I put SetDepth back the way it was; it still doesnÕt work right, ; but I donÕt have time to mess with it now. Will look into it ; later. Basic problem: thePort is trashed. Bumped version back to ; 2.0.2. ; <36> 10/10/90 jmp Changed SetDepth call to match Monitors; also, updated ; PMgrVersion to 2.0.3 so Monitors could tell when to use SetDepth ; or not. ; <35> 9/23/90 DC csd Fix bug in GetGray when input GDevice is NULL ; <34> 9/17/90 BG Removed <21>. 040s are now behaving more reliably. ; <33> 9/15/90 DC added GetGray and put some quick elimination tests into ; CheckColors ; <32> 8/22/90 DC Added inhibit bit to CheckColors and check for individual max ; tolerance ; <31> 8/20/90 dvb Remove DrawGrayishString ; <30> 8/17/90 gbm The name of grayishTextCopy has changed to grayishTextOr ; <29> 8/7/90 gbm moving SysColors into InitPalettes will get rid of some ; assembler warnings ; <28> 8/3/90 dvb Make setdepth redraw _all_ layers. ; <27> 7/20/90 gbm Warning hunt. ; <26> 7/19/90 DVB Fix stack error in DrawGrayishString ; <24> 7/17/90 DVB Use GetFontInfo instead of FMSwapFont ; <23> 7/14/90 DVB Add "DrawGrayishString" ; <22> 6/28/90 DVB Fix CheckColors ; <21> 6/28/90 BG Added EclipseNOPs to fix temporary flakey 040 problems. ; <20> 6/27/90 DVB Add "CheckColors" dispatch ; <19> 6/19/90 DVB Do Gestalt checking for process mgr, implement pmWhite and ; pmBlack ; <18> 6/15/90 DVB Make ciPrivate always a word, to free up an entry word. ; Get/SetPaletteUpdates. Don't fix color environment on background ; quit. ; <17> 5/17/90 KON Sizes are a word, rather than a long when comparing palette ; sizes in resize palette. ; <16> 3/30/90 DVB Bump PaletteVersion ; <15> 3/29/90 DVB Make "WhatPal" nice, and available to layer mgr. ; <14> 3/2/90 DVB Fix explicit+tolerant+inhibit. ; <13> 2/23/90 DVB Don't clear windowlist in PMgrExit. ; <12> 2/21/90 JS SetDepth also takes a mode... ; <11> 2/15/90 DVB Change SetDepth's return to an OSErr ; <10> 2/14/90 DVB Correct SetDepth's trashage of registers ; <9> 2/5/90 DVB Back-roll the 605 InitGDevice to the BBS master, here. ; <8> 1/29/90 DVB Unhilite menu during "SetDepth" call, add rounded corners on ; setdepth ; <7> 1/18/90 DVB Undo last changes ; <6> 1/18/90 DVB Make work with cleaned-up PaletteEqu.a ; <5> 1/17/90 DVB Add PMgr version call, fix unreserveDevices ; <4> 1/12/90 DVB Remove automatic tailpatch to ExitToShell, added SetDepth and ; HasDepth calls. ; <3> 1/2/90 DVB Remove a reference to SysVers, in favor of ForROM ; <1.9> 7/14/89 BAL FOR Aurora: Changed some left shifts to some adds as per gary ; <¥2.0> 7/14/89 BAL For Aurora: Final CQD ; <1.8> 7/13/89 BAL Really, dvb, 1.8, fixed SetPal(-1,nil,x). ; <1.7> 7/8/89 BAL Modified PMgrDispatch to skip args of yet-uninvented calls. ; <1.6> 6/28/89 BAL really dvb - ciRGB is valid except for animated entries, where ; <¥1.5> 6/10/89 CEL Moved Private.a QuickDraw Equates into proper QuickDraw private ; file (colorequ.a), got rid of QuickDraw nFiles dependencies and ; fixed up necessary filesÉ ; <¥1.4> 5/29/89 BAL Blasting in 32-Bit QuickDraw version 1.0 Final ; 3/30/87 JTC Daisy chain the IAZInit routine properly. ; 3/27/87 EHB window manager calls added ; 3/27/87 AWC interface changed to support window manager ; 2/2/87 AWC new this date ; ; To Do: Make tolerant entries go faster by replacing color2index call with linear search! ; On activatepalette, activate every window from back to front, for total satisfaction! ; Don't forget about InitApp and CleanupApp ; Let DeltaRGB be (R+G+B)/3 or >>2 ; Get an invalmenubar! ; PMDithered ; Question: should we call "CheckForProcessMgr" for a ROM version? ; ( instead of calling Gestalt ) ; !! Roll in change 14 to the PatchciROM.a file...it was a single BMI.s ; near the top of Correlate. ; ;__________________________________________________________________________________________________ XPalettes PROC EXPORT ; dummy procedure; return to globals AWC.PB457 ENDPROC ; AWC.PB457 IF (&TYPE('ROMPaletteMgr') = 'UNDEFINED') THEN IF ForROM THEN ; <1.7> ROMPaletteMgr EQU 1 ; <1.7> ELSE ; <1.7> ROMPaletteMgr EQU 0 ENDIF ; <1.7> ENDIF IF NOT (ForROM) THEN JacksonPollack EQU 0 PatchGetCTable EQU 1 PatchInitGDevice EQU 1 HasLayers EQU 1 ELSE ; ForRom HasLayers EQU 1 ; ROM now has the LayerMgr. ENDIF ; Not ForRom INCLUDE 'Processes.a' INCLUDE 'GestaltEqu.a' INCLUDE 'LayerEqu.a' AppPalette Equ $DCC ; low memory global for layer palette AWC.PB457 UpdateMask Equ $E000 ; bits used to record update flags in pmPrivate AWC.PB457 AllUpdates Equ $C000 ; combination of CForeBit and CBackBIt AWC.PB457 plttUpdates Equ $0002 ; value passed to SetPalette [short] AWC.PB457 ;ctTolBit EQU 5 ; bit in value field saying "I've been yanked" ;ctTolVal EQU $2000 ;ctScatterBit EQU 4 ; bit in value field saying "scatter me" ;ctMatchBit EQU 3 ; bit in value field saying "been checked" ;ctScatterVal EQU $1000 ; word-write equivalent of ctScatterBit ;ctReserveBit EQU 6 ;ctReserveVal EQU $4000 PMgrVersNum EQU $0203 ; Version number (VVss: version subversion) ;----------------------------------------------------------- ; Let's talk about PMgrVersNum -- ; ; The first version with the PMgrVersion call was $0201. This was released ; as 6.0.5. ; ; Version $0202 adds: ; Dispatch #5: WhatPal ; GetPaletteUpdates, SetPaletteUpdates, pmWhite, pmBlack, CheckColors ;----------------------------------------------------------- ; Here is what is left of the Patch Collator stuff. The Palette Manager routines have never ; been patches to the ROM - they were never in the original ROM, so there was nothing to ; patch. This is all there is. The window manager patches are shown below and are marked ; near the routine with another patch signal. To find one, double click on the Patch Name ; and search for that (Command-H under MPW 2.0). ; ; File Date Patch# PMgr Routines Trap# ;AppleSystemPatch PaletteMgr.a 10Mar87 #PB103 (InitPalettes) $AA90 ;AppleSystemPatch PaletteMgr.a 10Mar87 #PB103 (NewPalette) $AA91 ;AppleSystemPatch PaletteMgr.a 10Mar87 #PB103 (GetNewPalette) $AA92 ;AppleSystemPatch PaletteMgr.a 10Mar87 #PB103 (DisposePalette) $AA93 ;AppleSystemPatch PaletteMgr.a 10Mar87 #PB103 (ActivatePalette) $AA94 ;AppleSystemPatch PaletteMgr.a 10Mar87 #PB103 (SetPalette) $AA95 ;AppleSystemPatch PaletteMgr.a 10Mar87 #PB103 (GetPalette) $AA96 ;AppleSystemPatch PaletteMgr.a 10Mar87 #PB103 (PmForeColor) $AA97 ;AppleSystemPatch PaletteMgr.a 10Mar87 #PB103 (PmBackColor) $AA98 ;AppleSystemPatch PaletteMgr.a 10Mar87 #PB103 (AnimateEntry) $AA99 ;AppleSystemPatch PaletteMgr.a 10Mar87 #PB103 (AnimatePalette) $AA9A ;AppleSystemPatch PaletteMgr.a 10Mar87 #PB103 (GetEntryColor) $AA9B ;AppleSystemPatch PaletteMgr.a 10Mar87 #PB103 (SetEntryColor) $AA9C ;AppleSystemPatch PaletteMgr.a 10Mar87 #PB103 (GetEntryUsage) $AA9D ;AppleSystemPatch PaletteMgr.a 10Mar87 #PB103 (SetEntryUsage) $AA9E ;AppleSystemPatch PaletteMgr.a 10Mar87 #PB103 (CTab2Palette) $AA9F ;AppleSystemPatch PaletteMgr.a 10Mar87 #PB103 (Palette2CTab) $AAA0 ;AppleSystemPatch PaletteMgr.a 22Jul87 #PB222 (CopyPalette) $AAA1 ; ; Fix File Date Patch# Fixed Routines Patch Routine Name ;AppleSystemPatch PaletteMgr.a 10Mar87 #PB103 (RGBForeColor) (RGBForeColor) ;AppleSystemPatch PaletteMgr.a 10Mar87 #PB103 (RGBBackColor) (RGBBackColor) ;AppleSystemPatch PaletteMgr.a 10Mar87 #PB506 (InitMenus) (myInitMenus) ;AppleSystemPatch PaletteMgr.a 10Mar87 #PB103 (NewCWindow) (myNewCWindow) ;AppleSystemPatch PaletteMgr.a 10Mar87 #PB103 (NewWindow) (myNewWindow) ;AppleSystemPatch PaletteMgr.a 10Mar87 #PB103 (HiliteWindow) (myHiliteWindow) ;AppleSystemPatch PaletteMgr.a 10Mar87 #PB103 (MoveWindow) (myMoveWindow) ;AppleSystemPatch PaletteMgr.a 10Mar87 #PB103 (SizeWindow) (mySizeWindow) ;AppleSystemPatch PaletteMgr.a 10Mar87 #PB103 (CloseWindow) (myClose) ;AppleSystemPatch PaletteMgr.a 10Mar87 #PB103 (ShowHide) (myShowHide) ;AppleSystemPatch PaletteMgr.a 10Mar87 #PB103 (MyExit) (myExit) ; ; Another routine which must be included for proper Palette Manager operation is ; GetNewCWindow which is patched in PatchIIROM.a FlushPalettes PROC EXPORT ; THIEVED FROM THE MEMORY MGR ;----------------------------------------------------------------------- ; Call DisposePalette for all palettes in the app heap. ; ; Registers: D0-D2/A0-A1 ; Called by vIAZInit. ;---------------------------------------------------------------------- IMPORT AppZoneAddr MOVEM.L A2-A3/D3,-(SP) ; save work registers MOVE.L PMgrHandle,A2 ; get paletteMgr handle CMP.L MinusOne,A2 ; is it there? BEQ.S @DONE ; => no, just return MOVE.L (A2),A1 ; point to data structure MOVE.L PListHandle(A1),A0 ; get handle to palette list _HLock ; and lock it down MOVE.L (A0),A3 ; point to palette list Move APalettes(A1),D3 ; get number of active handles Beq.s @NoPals ; no friends => go home Add FreeSpaces(A1),D3 ; calculate total number of entries BRA.S @FindEnd ; => check for no entries @FindLoop Move.L PaletteRef(A3),D1 ; get first entry BEQ.S @FindNext ; => no palette in entry MOVE.L D1,D0 ; and get for routine JSR AppZoneAddr ; in application area (or zero)? BNE.S @FindNext ; => not in app heap MOVE.L D1,-(SP) ; push palette handle DC.W $AA93 ; _DisposePalette ; and dispose it in place @FindNext AddQ #PLstEntrySz,A3 ; bump to the next entry @FindEnd DBra D3,@FindLoop ; repeat for all spaces @NoPals MOVE.L (A2),A1 ; point to palette stuff MOVE.L PListHandle(A1),A0 ; get handle to palette list _HUnlock ; and unlock it @DONE MOVEM.L (SP)+,A2-A3/D3 ; restore work registers RTS ;--------------------------------------------------- ; ; PROCEDURE ActivatePalette(dstWindow: WindowPtr); INLINE $AA94; ; ; ActivatePalette does what is documented in IM5. UpdatePalette is an internal ; routine that is passed a Palette handle, instead of a window. PROC EXPORT ActivatePalette,UpdatePalette IMPORT CalcDevs,ScatterDevices,SetDev,UnreserveDevices,UpdateDevices ParamSize equ 4 ; total bytes of params dstWindow equ ParamSize+8-4 ; source Palette handle ; The ActivatePalette stack frame is defined at the global level so it can be accessed ; by each of the routines subsidiary to ActivatePalette and thereby avoid gross parameter ; passing. All such subsidiary routines will link with A4 and not A6 thus keeping ; ActivatePalette's stack frame intact. D3 is used to hold any error condition. ; It is moved to D0 before we quit. UpdatePalette LINK A6,#spVarSize MOVEM.L D3-D4/A2-A4,-(SP) MOVEQ #1,D3 CLR.L WindowCopy(A6) ; No top window MOVE.L PMgrHandle,A2 MOVE.L dstWindow(A6),A3 ; In this case, really, a PaletteHandle BRA.S FoundPltt ; Jump into middle of ActivatePalette ActivatePalette Link A6,#spVarSize ; build stack frame MoveM.L D3-D4/A2-A4,-(SP) ; save registers MoveQ #1,D3 ; set error flag in case we branch Move.L PMgrHandle,A2 ; get global handle CmpA.L #PMgrNil,A2 ; is it nil? Beq GoHome ; it has to be initialized Move.L (A2),A0 ; dereference PMgrHandle AWC.PB500 Move nDevs(A0),D0 ; are there any clut devices? AWC.PB500 Beq GoHome ; no => punt AWC.PB500 Move.L dstWindow(A6),A3 ; get the window pointer CmpA.L #Nil,A3 ; is it real? Beq GoHome ; no => go home Move.L A3,WindowCopy(A6) ; save a copy for those who need it Tst PortBits+RowBytes(A3) ; is it a new port? Bpl.S TrySystem ; no => try for a system palette Move.L GrafVars(A3),A0 ; get the GrafVars handle Move.L (A0),A0 ; dereference it Move.L PmFgColor(A0),A3 ; save the palette handle in GrafVars CmpA.L #Nil,A3 ; is it nil? Bne.S FoundPltt ; no => we've found it TrySystem Move.L AppPalette,A3 ; get the layer's palette, if any AWC.PB457 Move.L A3,D0 ; CmpA.L #Nil,A0; is AppPalette nil? AWC.PB457 Bne.S FoundPltt ; no => use AppPalette AWC.PB457 Move.L (A2),A0 ; dereference PMgrHandle Move.L SysPalette(A0),A3 ; get the system palette, if any Move.L A3,D0 ; CmpA.L #Nil,A3; is SysPalette nil? AWC.PB457 Beq GoHome ; yes => we can't do it ; past this point we will have locked PMgrHandle and PaletteH. We also save theGDevice ; and clear the InfoHandle variable. FoundPltt Move.L A2,A0 ; copy PMgrHandle _HLock ; lock it down Move.L A3,A0 ; copy PaletteH MOVE.L A3,PaletteH(A6) ; and save a handle, too _HLock ; lock it down as well Move.L (A2),A4 ; dereference PMgrHandle Move.L A4,PMgrPtr(A6) ; save a copy of the pointer Move.L PListHandle(A4),A0 ; get PListHandle _HLock ; lock it down Move.L (A0),PListPtr(A6) ; save pointer to palette list Move nDevs(A4),Devices(A6) ; save number of devices in our list Lea DevHandles(A4),A0 ; point A4 at first device handle Move.L A0,PDevPtr(A6) ; save pointer to start of device list Move.L theGDevice,SaveGDev(A6) ; save theGDevice handle Clr.L InfoHandle(A6) ; mark it as unallocated Move.L (A3),A4 ; dereference PaletteH Move.L A4,PalettePtr(A6) ; save it for posterior Move pmEntries(A4),D4 ; fetch number of entries Move D4,myEntries(A6) ; save it for posterity Clr MAnimators(A6) ; MAnimators := 0 Clr MTolerators(A6) ; MTolerators := 0 ; Check to see on which devices the window is now rendered Jsr CalcDevs ; determine the new and frontmost device sets CLR -(SP) ; No SetEntries JSR ScatterDevices ; Scatter anyone who needs it Tst.L FrontSet(A6) ; is this window frontmost on any device? Beq NoFunStuff ; no => skip our wonderful rendering code ; Count the number of animating and tolerant colors. Mark explicit, dithered, and ; courteous colors as "handled" so we won't bother with them in SetDev et al. Lea pmInfo(A4),A4 ; point us at the first ColorInfo MOVE myEntries(A6),D4 ; set up loopy variable Bra.S ExamEnd ; jump into DBra loop ExamLoop Move ciUsage(A4),D1 ; copy ciUsage field of current entry BTst #AnimatedBit,D1 ; pmAnimated? Beq.S CheckTolrnt ; no => check for other kinds of usage AddQ #1,MAnimators(A6) ; bump number of animating colors Bra.S NextColor ; continue ; If a tolerant color is all black or white and not explicit, it's already in the palette, so ; we don't need to add it. We do this by only checking for black or white entries when the entry ; is not explicit. The code later will catch entries that are trying to set the first or last ; colors in the device color table. CheckTolrnt BTST #TolerantBit,D1 BEQ.S HandleColor if 0 then ; ; I believe this code to be right, however it causes black to be stuck in the palette in many ; cases where it never used to. The net result is that synthetic font caches are built with ; black being odd indices (not ff) and never being flushed once the palette is thrown away. ; We need to figure out how to flush the font caches for real for all processes and then we ; can bring this code back in. BTST #ExplicitBit,D1 ; is it explicit? BNE.S AlwaysAdd ; yes, so we must add it endif MOVE.L ciRGB+red(A4),D0 ; D0: Rhi.Rlo.Ghi.Glo MOVE.B ciRGB+blue(A4),D0 ; D0: Rhi.Rlo.Ghi.Bhi TST.L D0 ; Is it all zero's? BEQ.S HandleColor ; Yes => it's Black, its handled. ADDQ.L #1,D0 ; =FFFFFF? It's White, its handled BEQ.S HandleColor ; AlwaysAdd AddQ #1,MTolerators(A6) ; yes => bump number of tolerant colors Bra.S NextColor ; continue HandleColor BSet #HandledBit,ciUsage(A4) ; mark explicit and normal colors as handled NextColor Add #ciSize,A4 ; bump address to next ColorInfo ExamEnd DBra D4,ExamLoop ; loop for all pmEntries ; See if we have any animating or tolerant entries. If not, we can skip most of this Move MAnimators(A6),D0 ; do we have any animating AWC PB223 Or MTolerators(A6),D0 ; or tolerant entries? AWC PB223 Beq NoFunStuff ; no => just clean up the world AWC.PB508 ; Allocate a scratch buffer Move.L #InfoHandSz,D0 ; size of our scratch area AWC _NewHandle ,CLEAR ; allocate a scratch area Bne UnlockEm ; we couldn't get it - D3 still says "error" AWC.PB508 Move.L A0,InfoHandle(A6) ; save it _HLock ; lock it Move.L (A0),A0 ; dereference it Move.L A0,InfoPtr(A6) ; save dereferenced ptr ; Call SetDev to render or record the Palette on each device, as appropriate. MoveQ #0,D4 ; clear device counter DeviceLoop Move.L FrontSet(A6),D0 ; grab the front device set AWC PB223 BTst D4,D0 ; frontmost on this clut device? AWC PB223 Beq.S NoDevError ; no => jump across SetDev AWC PB223 Move MAnimators(A6),Animators(A6) ; copy MAnimators Move MTolerators(A6),Tolerators(A6) ; copy MTolerators Move D4,CurDevice(A6) ; copy it for SetDev Jsr SetDev ; render palette; did we get an error? Beq.S NoDevError ; did we find an error? AddQ #1,D3 ; bump our error count NoDevError AddQ #1,D4 ; we've examined another device Cmp Devices(A6),D4 ; have we done them all Bmi.S DeviceLoop ; no => do another Move.L SaveGDev(A6),theGDevice ; restore theGDevice handle AWC.PB508 NoFunStuff Move.L PMgrPtr(A6),A0 ; get the PMgrHandle pointer AWC PB223 Move.L PListHandle(A0),A0 ; get the PListHandle Move.L (A0),A0 ; dereference it Move.L PalettePtr(A6),A1 ; get the Palette Move pmPrivate(A1),D0 ; get the entry number And #PIdMask,D0 ; clear the flag bits Move Reserves(A0,D0.W*8),D0 ; does this palette have anything reserved? Beq.S NoneRsrvd ; no => forget about clearing AWC PB223 ; Clear any unused devices and update device bitmap Move.L PMgrPtr(A6),A0 ; get the PMgrHandle pointer AWC PB223 Move.L pmDevices(A1),D0 ; get former device set Move.L DeviceSet(A6),D1 ; get new device set Not.L D1 ; complement the current set And.L D1,D0 ; remove any current bits Beq.S NoneRsrvd ; if none needing unreserving, quit JSR UnreserveDevices ; Pass: A0->Pmgr data, A1->palette, D0 = devmask NoneRsrvd CLR -(SP) ; No Setentries JSR ScatterDevices ; Scatter those devices that unreserving affected JSR UpdateDevices Move.L DeviceSet(A6),pmDevices(A1) ; copy the new device set SubQ #1,D3 ; if now 0 then we got through with no errors UnlockEm Move.L PMgrPtr(A6),A0 ; get the master pointer Move.L PListHandle(A0),A0 ; get this handle _HUnlock ; unlock it Move.L A2,A0 ; copy PMgrHandle _HUnLock ; clear the dirty bit and restore the user's ciUsage fields Move.L PalettePtr(A6),A0 ; get Palette pointer BClr #DirtyBit,pmPrivate(A0) ; clear the dirty bit Move pmEntries(A0),D0 ; fetch number of entries Lea pmInfo(A0),A0 ; point us at the first ColorInfo Bra.S UnsetEnd ; jump into DBra loop UnsetLoop Move ciUsage(A0),D1 ; copy ciUsage field of current entry And #ClearBits,D1 ; clear all but the user's flags Move D1,ciUsage(A0) ; restore it AddA.L #ciSize,A0 ; bump A4 to the next color info UnsetEnd DBra D0,UnsetLoop ; loop for all pmEntries ColorInfo's Move.L A3,A0 ; copy PaletteHandle to A0 _HUnlock ; unlock it Move.L InfoHandle(A6),A0 ; get scratch handle CmpA.L #Nil,A0 ; was it allocated Beq.S NoError ; no => don't dispose it _DisposHandle ; get rid of it NoError MoveQ #0,D3 ; clear error flag GoHome Move.L D3,D0 ; copy error flag MoveM.L (SP)+,D3-D4/A2-A4 ; restore registers Unlk A6 ; clear stack frame Rtd #ParamSize ; strip parameters and go home ;--------------------------------------------------- ; ; PROCEDURE Allocate; LOCAL; ; PMAllocate PROC EXPORT IMPORT ClaimIndex,FindLink,Pillage,GimmeIndex ; We have one or more animating entries. For each entry in myPalette, look to see if it is ; animating. If so, look to see if it exists on this device. If not, look to see if we can ; allocate it on this device. MoveM.L D3/D4/A2-A3,-(SP) ; save registers TST Animators(A6) ; Have anything to animate? BEQ GoHome Move.L PalettePtr(A6),A3 ; get palette pointer MoveQ #0,D4 ; D4 is the entry number CLR.L D2 ; Clear upper bits of D2, for BF ops CLR.L D3 ; Clear upper bits of D3, for BF ops LEA pmInfo(A3),A2 ; bump A2 to the first ColorInfo Bra.S AnimateEnd ; jump into loop AnimateLoop Move ciFlags(A2),D0 ; examine "handled" Bmi.S NextAnimate ; it was explicit or courteous; ignore it BTst #AnimatedBit,D0 ; are we animating? Beq.S NextAnimate ; no => ignore it BTST #ExplicitBit,ciFlags+1(A2) ; is it animated+explicit? BEQ.S notExplicit ; no, just normal animated... doit. MOVE D4,D3 ; Move it here, for setting within clutrange AND BlackIndex(A6),D3 ; Roll over into range BEQ.S NextAnimate ; Got zero = "white"? So sorry, sir. CMP BlackIndex(A6),D3 ; are we trying to get "black"? BEQ.S NextAnimate ; No way, Mr. BFTST availBits(A6){D3:1} ; This index already explicitly animated? BNE.S NextAnimate ; Yes! Don't take it a second time. BFSET availBits(A6){D3:1} ; Mark this explicit entry as used. Clr -(SP) ; clear index result Move ciPrivate(A2),-(SP) ; push animation link info (first word only) Jsr FindLink ; FindLink(Device,myPalette^^.pmInfo[i].ciPrivate) Move (SP)+,D2 ; pop the index result Bne.S HadIndex ; true => it's still there - mark it as "handled" MOVE D3,-(SP) ; we want this index Jsr Pillage ; steal this index MOVE D3,D2 ; D2 = index we want (the same for explicit) BRA.S GotIndex ; And finish with this entry notExplicit Clr -(SP) ; clear index result Move ciPrivate(A2),-(SP) ; push animation link info (first word only) Jsr FindLink ; FindLink(Device,myPalette^^.pmInfo[i].ciPrivate) Move (SP)+,D2 ; pop the index result Bne.S HadIndex ; true => it's still there - mark it as "handled" SUBQ #2,SP ; Space for result BSR GimmeIndex ; Get the next available index MOVE (SP)+,D2 ; Did we get a color? Put index in D2 BEQ.S NextAnimate ; No=>but keep looping, for Explicits. GotIndex MOVE D2,-(SP) ; Push index we want JSR Pillage ; Knock off anyone else on it. MOVE D4,D0 ; Set D0 = entry we're stealing for MOVE.L A2,A0 ; setup for claim BSR ClaimIndex HadIndex BSet #HandledBit,ciFlags(A2) ; set "handled" bit NextAnimate AddA.L #ciSize,A2 ; bump us to the next ColorInfo AddQ #1,D4 ; bump entry number AnimateEnd CMP pmEntries(A3),D4 ; At end of entries yet? BLT AnimateLoop ; loop for all pmEntries GoHome MoveM.L (SP)+,D3/D4/A2-A3 ; restore registers Rts ; strip parameters and go home ;--------------------------------------------------- ; ; PROCEDURE CheckAllDeviceCluts; ; ; Set scatterbits for all indices in all devices which ; don't match the correct default clut. CheckAllDeviceCluts PROC EXPORT IMPORT CheckDeviceColors MOVEM.L A0-A3/D3-D4,-(SP) ; save 'em. MOVE.L PMgrHandle,A2 MOVE.L A2,A0 ; PMgrHandle _HLock ; Lock it down MOVE.L (A2),A3 ; Redereference MOVE nDevs(A3),D3 ; number of devices, for looping SUBQ #1,D3 ; less one for DBRAing CLR.L D4 ; D4 = device update mask gLoop SUB #2,SP ; space for boolean result MOVE.L DevHandles+DevHandle(A3,D3*8),-(SP) ; push gDevice handle JSR CheckDeviceColors ; check the device TST (SP)+ ; Was the device up to date? BEQ.S gLoopEnd ; Yes=>try next device BSET D3,D4 ; No=>mark update bit gLoopEnd DBRA D3,gLoop ; loop for all devices OR.L D4,scatterDevs(A3) ; mark devices for scattering MOVE.L A2,A0 ; PMgrHandle _HUnlock MOVEM.L (SP)+,A0-A3/D3-D4 ; save 'em. RTS ;--------------------------------------------------- ; ; FUNCTION CheckForProcessMgr:Boolean; ; ; Determine if the process mgr is present using Gestalt. ; (we assume that gestaltLaunchControl iff processMgr is here) ; Affect only A0/D0, since Gestalt is an OS trap. ; return Z-flag Clear if the process mgr is here (BNE ProcMgrTrue) CheckForProcessMgr PROC EXPORT MOVE.L ExpandMem,A0 TST $128(A0) RTS ;--------------------------------------------------- ; ; PROCEDURE PMgrExit; AAA2/12; ; ; Someone should call here when an application quits. Please. ; PMgrExit PROC EXPORT IMPORT ScatterDevices,UpdateDevices,DisposeAppPalettes IMPORT CheckForJuggler,CheckForProcessMgr PXVars RECORD {A6Link},DECREMENT result DS.B 0 ;Result: nothing return DS.B 4 A6Link DS.B 4 ; old contents of A6 frontPSN DS.B 8 ; a 64-bit process serial number myPSN DS.B 8 ; likewise inFront DS.B 2 ; a boolean IF (forRom OR theFuture) THEN wList DS.B 4 ; saved window list ENDIF linkSize DS.B 0 ; linky number ENDR WITH PXVars LINK A6,#linkSize movem.l a0-a2/d0-d2,-(sp) ; Those pesky c routines sub.l a0,a0 ; Pass the current process (0) moveq #12,d0 ; _TrashProcess ;_FigmentDispatch ; let everyone know this stuff is gone dc.w $A0A4 movem.l (sp)+,a0-a2/d0-d2 ; Restore em IF (forRom OR theFuture) THEN MOVE.l WindowList,wList(A6) ; FM save the current window list ENDIF TST.B QDExist ; if InitGraf has not been called yetÉ BNE.S @doNothing ; (a5) not valid and there is nothing to do CMP.L #PMgrNil,PMgrHandle ; If the palette manager doesnt exist... BEQ.S @doNothing CLR.L AppPalette JSR DisposeAppPalettes MOVE.L (A5),A0 BTST #3,QDSpare0(A0) ; Any change to color env? BEQ.S @doNothing BSR.S CheckForProcessMgr BEQ.S @front ; if no process mgr, assume we're in front MOVE #$0100,inFront(A6) ; default inFront to true SUBQ #2,SP ; space for result PEA frontPSN(A6) _GetFrontProcess TST (SP)+ ; problem getting front psn? BNE.S @front ; YES => just zap the cluts CLR.L myPSN(A6) MOVE.L #kCurrentProcess,myPSN+4(A6) SUBQ #2,SP ; space for OSErr result PEA frontPSN(A6) PEA myPSN(A6) PEA inFront(A6) _SameProcess ; are we the front process? ADDQ #2,SP ; OSErr leaves inFront true from above TST.B inFront(A6) BEQ.S @doNothing @front JSR CheckAllDeviceCluts ; A pretty simple patch, really. CLR -(SP) ; No Setentries on Scatter JSR ScatterDevices BSR CheckForJuggler ; Is Jugglertm active? BNE.S @doNothing ; No=>WMgr is void, next line dangerous JSR UpdateDevices MOVE.L mainDevice,theGDevice @doNothing IF (forRom OR theFuture) THEN MOVE.l wList(A6),WindowList ; FM restore the current window list ENDIF UNLK A6 RTS ;--------------------------------------------------- ; ; FUNCTION CheckForJuggler:Boolean; ; ; Set D0 to FFFFFFFF if Juggler is absent, and 00000000 if present. Affect ; No other registers. CheckForJuggler PROC EXPORT MOVE.L A0,-(SP) ; stow it. Move #JugglerTrap,D0 ; #$A88F AWC PB224 _GetTrapAddress ; find out what the trap is Move.L A0,-(SP) ; save it Move #UnimplementedTrap,D0 ; #$A89F _GetTrapAddress ; where do unimplemented traps go CmpA.L (SP)+,A0 ; are we Jugglerªing?4 SEQ D0 ; D0 = 00 is juggling, FF if not EXTB.L D0 ; Make it fully big. MOVEA.L (SP)+,A0 ; It don't hit the CCR. RTS ;--------------------------------------------------- ; ; PROCEDURE RecordPalette(myPalette: PaletteHandle); LOCAL; ; ; Copies myPalette into the PListHandle and records (in the pmPrivate field) where ; it lies in that list. If there are no free spaces in the PListHandle then that ; handle is resized. If it can't be resized, RecordPalette returns an error in D0. ; Otherwise a new handle is allocated for myPalette's pmSeeds field. If one can't ; be allocated, RecordPalette returns an error. It will also return an error if the ; PMgrHandle is nil. If RecordPalette returns an error, it first disposes of ; myPalette so the caller doesn't have to worry about watching the error code. RecordPalette PROC EXPORT ParamSize equ 4 ; total bytes of params myPalette equ ParamSize+8-4 ; source Palette handle VarSize equ 0 Link A6,#VarSize ; build stack frame MoveM.L D3/A2-A4,-(SP) ; save registers Move.L myPalette(A6),A4 ; get my palette first in case we branch to Error Move.L PMgrHandle,A2 ; get the PMgrHandle CmpA.L #PMgrNil,A2 ; has it been initialized? Beq Error ; no => handle the error (.S won't reach) Move.L (A2),A0 ; dereference the PMgrHandle Move.L PListHandle(A0),A3 ; get the handle to the list of palettes MoveQ #0,D0 ; clear high word Move SeedHSize(A0),D0 ; get length of seeds handles _NewHandle ,CLEAR ; allocate it; did we succeed? Bne Error ; no => handle the error (.S won't reach) Move.L (A4),A1 ; dereference myPalette Move.L A0,pmSeeds(A1) ; store the seeds handle in it Move.L (A2),A1 ; redereference the PMgrHandle Move FreeSpaces(A1),D0 ; get number of free slots; are any left? Bne.S FindOne ; yes => don't resize it; search for a free one MoveQ #0,D3 ; clear high word Move APalettes(A1),D3 ; get current size Move.L D3,D0 ; copy it Add #ListSpace,D0 ; bump it to add more room Bmi.S Error ; return an error if it wraps Lsl.L #3,D0 ; multiply by 8 Move.L A3,A0 ; copy PListHandle to A0 _SetHandleSize ; resize it Bne.S Error ; we couldn't do it ; Now we have to clear all of the new entries we just created. Move.L A3,A0 ; get PListHandle Move.L (A0),A0 ; redereference this Lea (A0,D3.W*8),A0 ; point us at the block to clear Move.L #ListSpace,D0 ; get how many entries to clear Bra.S ClearEnd ; jump into loop ClearLoop Clr.L (A0)+ ; clear the Palette field Clr.L (A0)+ ; clear the animation field ClearEnd DBra D0,ClearLoop ; loop for ListSpace entries AddQ #1,D3 ; D3 is palette's position in PListHandle Move.L (A3),A0 ; dereference PListHandle Lea (A0,D3.W*8),A0 ; point A0 at the current position Move.L (A2),A1 ; redereference the PMgrHandle Move #ListSpace-1,FreeSpaces(A1) ; number of spaces we've added AWC.PB378 Bra.S Cleanup ; share common code ; We have a free one somewhere in the list. Search forwards until we find one we can use. ; A1 is still pointing at the dereferenced PMgrHandle. FindOne Move APalettes(A1),D0 ; get number of active handles Add FreeSpaces(A1),D0 ; calculate total number of entries MoveQ #0,D3 ; initialize our counter Move.L (A3),A0 ; dereference PListHandle Bra.S FindEnd ; jump into loop FindLoop Move.L PaletteRef(A0),D1 ; get first entry Beq.S FoundIt ; we've got one AddQ #PLstEntrySz,A0 ; bump to the next entry AddQ #1,D3 ; bump our counter FindEnd DBra D0,FindLoop ; repeat for all spaces Bra.S Error ; this should not happen ; when we reach this section of common code, A1 = PMgrHandle^, D3 is the position of ; the palette, and A0 points to PListHandle^^[D3] FoundIt SubQ #1,FreeSpaces(A1) ; decrement the number free Cleanup AddQ #1,APalettes(A1) ; bump the number used Move.L A4,PaletteRef(A0) ; record the palette handle in PListHandle Clr.L Reserves(A0) ; clear the number of entries it reserves Move.L (A4),A0 ; dereference the Palette Move pmPrivate(A0),D0 ; grab the current update values AWC.PB457 And #UpdateMask,D0 ; clear away all but the update bits AWC.PB457 Or D0,D3 ; OR palette number with the update bits AWC.PB457 Move D3,pmPrivate(A0) ; this is the number of the palette MoveQ #0,D0 ; no error Bra.S GoHome ; we're done-oh! Error Move.L A4,A0 ; get Palette handle _DisposHandle ; get rid of it MoveQ #1,D0 ; set an error GoHome Tst.L D0 ; set condition codes for return MoveM.L (SP)+,D3/A2-A4 ; restore registers Unlk A6 ; clear stack frame Rtd #ParamSize ; strip parameters and go home ;--------------------------------------------------- ; ; FUNCTION NewPalette(entries: INTEGER; srcColors: CTabHandle; srcUsage,srcTolerance: ; INTEGER) : PaletteHandle; INLINE $AA91; ; ; Allocate a new palette and fill it with information from myColors. Set the usage ; field of each ciInfo to myUsage and set the tolerance to myTolerance. If myColors ; is nil we initialize all the colors to black. NewPalette FUNC EXPORT ParamSize equ 10 ; total bytes of params Palette equ ParamSize+12-4 ; function result entries equ Palette-2 ; number of entries in Palette srcColors equ entries-4 ; Color table handle srcUsage equ srcColors-2 ; default usage for each color in Palette srcTolerance equ srcUsage-2 ; default tolerance for each color in Palette VarSize equ 0 Link A6,#VarSize ; build stack frame MoveM.L D3/A2,-(SP) ; save registers Clr.L Palette(A6) ; set the result to nil Move entries(A6),D3 ; fetch number of entries MoveQ #0,D0 ; clear it out Move D3,D0 ; copy it for a calculation AddQ #1,D0 ; add one for the header Lsl.L #4,D0 ; multiply by 16 _NewHandle ,CLEAR ; get the handle; did we get an error? Bne.S GoHome ; yes => we're done for Move.L A0,A2 ; no => save the handle Move.L A2,-(SP) ; push handle Jsr RecordPalette ; allocates a seed's handle and records palette Bne.S GoHome ; it disposed the palette handle if it failed ; A2 contains the handle to the new Palette. Return the handle, then start by dereferencing it. ; For now we'll just clear everything. Note that we're making use of the fact that ; the size of the header is the same as an entry itself, so we can fall straight ; into the DBra and expect it to clear Entries+1 records! Also, zero the window field ; so we know that this palette is floating Move.L A2,Palette(A6) ; return the result Move.L (A2),A0 ; dereference Palette handle Move D3,pmEntries(A0) ; copy pmEntries Clr.L pmWindow(A0) ; zero the window field Move D3,D0 ; get entries into D0 Move srcUsage(A6),D1 ; copy usage to D1 Swap D1 ; put usage into high word Move srcTolerance(A6),D1 ; put tolerance into low word Lea pmInfo+ciUsage(A0),A0 ; point A0 at first ColorInfo Bra.S EntryEnd ; jump into the loop EntryLoop Move.L D1,(A0) ; set ciUsage (high word) and ciTolerance (low word) AddA #ciSize,A0 ; bump A0 to the next ciUsage field EntryEnd Dbra D0,EntryLoop ; loop for all entries Move.L srcColors(A6),A1 ; get ctabhandle CmpA.L #Nil,A1 ; is it nil? Beq.S NoCTab ; yes => skip the copy Move.L (A1),A1 ; dereference the source color table Move ctSize(A1),D0 ; get last color table entry AddQ #1,D0 ; make it number of entries; is it >= 1? Ble.S NoCTab ; no => we're done Move.L (A2),A0 ; redereference PaletteHandle AddA.L #pmInfo+ciRGB+red,A0 ; bump A0 to pmInfo.ciRGB.red AddA.L #ctTable+rgb+red,A1 ; bump A1 to ctTable.red ; put min(ctSize+1,pmEntries) into D0 Cmp D0,D3 ; compare color table size to palette size Bge.S UseAsIs ; if D0 is less than D3, we'll use it as is Move D3,D0 ; copy the lower value into D0 UseAsIs MoveQ #0,D1 ; D1 points at this entry Bra.S CopyEnd ; jump into loop CopyLoop Move.L red(A1),red(A0) ; copy red and green MOVE.B red(A1),red+1(A0) ; and into lo byte of red, MOVE.B green(A1),green+1(A0) ; and into lo byte of green, Move blue(A1),blue(A0) ; copy blue MOVE.B blue(A1),blue+1(A0) ; and into lo byte of blue. AddQ.L #ColorSpecSize,A1 ; bump A1 to next ColorSpec AddA.L #ciSize,A0 ; bump A0 to next ColorInfo CopyEnd Dbra D0,CopyLoop ; loop until the copy is complete NoCTab MoveQ #0,D0 ; no error GoHome MoveM.L (SP)+,D3/A2 ; restore registers Unlk A6 ; clear stack frame Rtd #ParamSize ; strip parameters and go home ;--------------------------------------------------- ; ; FUNCTION GetNewPalette(paletteID: INTEGER) : PaletteHandle; INLINE $AA92; ; ; GetNewPalette gets a resource of type 'pltt' with the specified ID and clears ; all the private fields. It then returns the data structure as a PaletteHandle. ; GetNewPalette FUNC EXPORT ParamSize equ 2 ; total bytes of params Palette equ ParamSize+12-4 ; function result paletteID equ Palette-2 ; number of entries in Palette VarSize equ 0 Link A6,#VarSize ; build stack frame Move.L A2,-(SP) ; save registers Clr.L Palette(A6) ; set result to Nil ; Load the data and detach it from resource manager Clr.L -(SP) ; make space for result Move.L #'pltt',-(SP) ; push resource type Move paletteID(A6),-(SP) ; push resource ID _GetResource ; get the resource Move.L (SP)+,D1 ; get handle off the stack Beq.S GoHome ; if nil we go home Move.L D1,A2 ; copy it to A2 Move.L D1,-(SP) ; push it back on the stack _DetachResource ; disconnect from resource manager Move.L A2,A0 ; copy it for the HNoPurge AWC.PB480 _HNoPurge ; we can't handle purged palettes AWC.PB480 Tst D0 ; did it return an error? AWC.PB480 Bne.S GoHome ; yes => go home AWC.PB480 Move.L (A2),A0 ; dereference palette AWC.PB457 Move #AllUpdates,D1 ; set D1 to the default AWC.PB457 Move plttUpdates(A0),D0 ; get update bits AWC.PB457 Bpl.S NoResUpdate ; the user didn't specify any AWC.PB457 ADD D0,D0 ; put the bits in the correct place AWC.PB457 Move D0,D1 ; put the result into D1 AWC.PB457 NoResUpdate Move D1,pmPrivate(A0) ; put them in the correct place AWC.PB457 Move.L A2,-(SP) ; push the handle Jsr RecordPalette ; allocates a seeds handle and records palette Bne.S GoHome ; it disposed the palette handle if it failed Move.L A2,Palette(A6) ; save Palette in result space ; clear the window field and also the private fields Move.L (A2),A2 ; dereference it ; Clr.L pmWindow(A2) ; set window field; this palette floats Clr.L pmDevices(A2) ; clear device bitmap GoHome Move.L (SP)+,A2 ; restore registers Unlk A6 ; clear stack frame Rtd #ParamSize ; strip parameters and go home ;--------------------------------------------------- ; ; PROCEDURE ClaimIndex; LOCAL; ; ; Assume that index D2 on CurDevice(A6) is unowned (it was free or has been pillaged). ; Now, we will claim it for palette entry D0 of PalettePtr(A6). We will link it thru ; the Linktabs, mark the Reserve bit in the color table, and zap the seed so that ; no tolerant entries later take it. ; ; In: D0 = Palette entry number ; D2 = device index number ; A0 -> colorinfo field within palette ClaimIndex PROC EXPORT MOVE.L DevCTab(A6),A1 MOVE.L (A1),A1 ; A1 -> color table SUBQ #4,SP _GetCTSeed ; (changes no registers) MOVE.L (SP)+,ctSeed(A1) ; alter the seed (we've changed something, eh?) BSet #HandledBit,ciFlags(A0) ; mark this entry as handled Move.L ciRGB+red(A0),ctTable+RGB+red(A1,D2.W*8) ; update red and green Move ciRGB+blue(A0),ctTable+RGB+blue(A1,D2.W*8) ; update blue AddQ #1,Updates(A6) ; we've changed something BSet #ctReserveBit,ctTable+value(A1,D2.W*8) ; reserve it Move.L DevLinks(A6),A1 ; point A1 at LinkTab And #$7FFF,D0 ; ensure that the top bit is off Or #$6000,D0 ; set the top bits to 011 Move D0,BackLink(A1,D2.W*4) ; set backward link to entry | $6000 ; Calculate a link to this new guy in D0. This will go in ciPrivate and, if we already ; had a link, into the BackLink of the old guy. Move CurDevice(A6),D0 ; get current device again Lsl #8,D0 ; shift device into upper byte Or D2,D0 ; OR in the device number BSet #15,D0 ; set the three highest bits to 100 ; Copy the old link then set the new one. Then look to see if the old link was real. ; If so, we have some work to do. If not, initialize the link by setting the forelink ; to the palette number. The back link has already been set to the entry number. Move ciPrivate(A0),D1 ; copy the old link Move D0,ciPrivate(A0) ; point ciPrivate at the new guy Tst D1 ; did we have any old links? Bne.S OldLinks ; yes => relink it Move.L PalettePtr(A6),A0 ; get pointer to palette Move pmPrivate(A0),D0 ; grab number of this palette And #PIdMask,D0 ; clear the flag bits Or #$6000,D0 ; to make it non-zero, set the top bits to 011 Move D0,ForeLink(A1,D2.W*4) ; set forward link to palette | $6000 Bra.S FixRefCount ; fix up the palette OldLinks Move D1,ForeLink(A1,D2.W*4) ; point Dev[FoundIndex] at old ciPrivate BfExtU D1{24:8},D2 ; grab index number (0..255) BfExtU D1{19:5},D1 ; grab device number (0..31) Lsl #8,D1 ; calculate offset to link table/4 Add D2,D1 ; offset to entry/4 Move.L PMgrPtr(A6),A1 ; get base pointer AddA.L #LinkTabs,A1 ; bump it to the LinkTabs Move D0,BackLink(A1,D1.L*4) ; set the backward link FixRefCount Move.L PListPtr(A6),A0 ; get PListPtr Move.L PalettePtr(A6),A1 ; get palette Move pmPrivate(A1),D0 ; get palette number And #PIdMask,D0 ; clear the flag bits AddQ #1,Reserves(A0,D0.W*8) ; bump number of reserves ADDQ #1,updates(A6) ; we've made a change RTS ;--------------------------------------------------- ; ; PROCEDURE ClearPalette(cPalette: PaletteHandle); LOCAL; ; ; Release all animated entries owned by cPalette. ; ClearPalette PROC EXPORT IMPORT ClearStrand ParamSize equ 4 ; total bytes of params cPalette equ ParamSize+8-4 ; source Palette handle VarSize equ 0 Link A6,#VarSize ; build stack frame MoveM.L D2-D4/A2-A4,-(SP) ; save registers Move.L PMgrHandle,A3 ; get palette manager handle CmpA.L #PMgrNil,A3 ; are we initialized? Beq.S GoHome ; no => quit AWC.PB377 Move.L (A3),A3 ; dereference it Move.L cPalette(A6),A1 ; get palette handle AWC.PB457 Move.L (A1),A2 ; dereference it AWC.PB457 ; Examine and remember the number of reserves this palette still has. Clear the number. Move pmPrivate(A2),D0 ; get the number of this palette And #PIdMask,D0 ; clear away update bits Move.L PListHandle(A3),A0 ; get the palette list handle Move.L (A0),A0 ; dereference it CmpA.L PaletteRef(A0,D0.W*8),A1 ; is this the correct handle? AWC.PB462 Bne.S BadPalette ; no => don't dispose anything AWC.PB462 Move Reserves(A0,D0.W*8),D3 ; remember how many animating entries it has Clr.L Reserves(A0,D0.W*8) ; clear the count ; Now clear each of the seeds this palette knows about, so that we'll update if we ; become active again. Clr.L pmDevices(A2) ; clear devices field Move.L pmSeeds(A2),A0 ; get seeds handle Move.L (A0),A0 ; dereference it Move SeedHSize(A3),D0 ; get size of handle Lsr #2,D0 ; divide by 4 Bra.S SeedEnd ; start clear loop SeedLoop Clr.L (A0)+ ; clear the remembered seed SeedEnd DBra D0,SeedLoop ; do it again ; Now check to see if we have any animating entries which we can dispose Tst D3 ; were there any animating entries? Beq.S GoHome ; no => quit ; run through every color to make sure it is not reserving any entries on any device ; by examining what the PaletteManager has to say about this palette as well as what ; each entry's ciPrivate field has to say about the subject. Leave pmPrivate field ; (which tells PMgr which palette we ought to be) alone. Move pmEntries(A2),D0 ; get number of entries AddA.L #pmInfo,A2 ; bump A2 to the first ColorInfo Lea DevHandles(A3),A4 ; point A4 at PMgrDevices AddA.L #LinkTabs,A3 ; point A3 to LinkTabs Bra.S EntryEnd ; jump into loop EntryLoop Move ciPrivate(A2),D3 ; get the current link information Bpl.S NextEntry ; if positive it's not a link Jsr ClearStrand ; If it's a link, wipe out it and its successors. OR.L D4,scatterDevs-LinkTabs(A3) ; A tricky offset; set bits to scatter devices NextEntry Clr ciFlags(A2) ; shut down any crap Clr ciPrivate(A2) ; clear it AddA.L #ciSize,A2 ; bump A2 to the next ColorInfo EntryEnd DBra D0,EntryLoop ; loop for all pmEntries GoHome MoveQ #0,D0 ; clear error condition BadPalette MoveM.L (SP)+,D2-D4/A2-A4 ; restore registers AWC.PB457 Unlk A6 ; clear stack frame Rtd #ParamSize ; strip parameters and go home ;--------------------------------------------------- ; ; PROCEDURE ClearStrand(Linkhead); LOCAL; ; ; Clear all device indexes which start on the given strand, taken from ; a ciPrivate field. Mark bit 4 of the value field of indices which must ; be returned to the environment. ; Enter with D3 = the linkhead, A3 = Linktab base, A4 = gDevice list base ; return with D4 = bitmask of those devices needing scattering ; We'll stomp on A0,D1,D2,D3,D4 ; (this code was moved out of ClearPalette so others could call it ) ClearStrand PROC EXPORT CLR.L D4 ; no devices need scattering yet. LinkLoop BfExtU D3{19:5},D1 ; grab device number (0..31) BfExtU D3{24:8},D2 ; grab index number (0..255) Move.L DevHandle(A4,D1.W*8),A0 ; get the device handle Move.L (A0),A0 ; dereference it Move.L gdPMap(A0),A0 ; get handle to pixmap Move.L (A0),A0 ; dereference pixmap Move.L pmTable(A0),A0 ; get handle to CTab Move.L (A0),A0 ; dereference CTab Cmp ctSize(A0),D2 ; is index number <= entries - 1? Bhi.S IgnoreIt ; no => don't unreserve it MOVE #ctScatterVal,ctTable+value(A0,D2.W*8) ; unreserve it, mark scatterbit BSET D1,D4 ; mark device for scattering IgnoreIt Lsl #8,D1 ; calculate offset to link table/4 Add D2,D1 ; offset to entry/4 Lea (A3,D1.L*4),A0 ; point A0 at next forward link Move ForeLink(A0),D3 ; get next link Clr.L ForeLink(A0) ; clear it for the next guy LinkEnd Tst D3 ; is there another link to examine? Bmi.S LinkLoop ; yes => go unlink it GoHome Rts ;--------------------------------------------------- ; ; PROCEDURE ErasePalette(ePalette: PaletteHandle); LOCAL; ; ErasePalette PROC EXPORT ParamSize equ 4 ; total bytes of params ePalette equ ParamSize+8-4 ; PaletteHandle to dispose VarSize equ 0 Link A6,#VarSize ; build stack frame MoveM.L A2-A3,-(SP) ; save registers Move.L ePalette(A6),A3 ; get the handle Move.L (A3),A2 ; dereference it Move.L pmSeeds(A2),A0 ; get the seeds handle while we have it CmpA #Nil,A0 ; is it nil? Beq.S DontDispose ; yes => punt _DisposHandle ; it's gone DontDispose Move.L WindowList,A0 ; get the window list for this layer AWC.PB506 Bra.S ListLoop ; continue AWC.PB439 CheckWindow Tst PortBits+Rowbytes(A0) ; by chance is it an old window? AWC.PB439 Bpl.S IgnoreWind ; yes => ignore it AWC.PB439 Move.L GrafVars(A0),A1 ; get GrafVars handle AWC.PB439 Move.L (A1),A1 ; dereference it AWC.PB439 Move.L PmFgColor(A1),D0 ; get the palette AWC.PB439 Cmp.L ePalette(A6),D0 ; is it correct? AWC.PB439 Bne.S IgnoreWind ; no => don't clear it AWC.PB439 Clr.L PmFgColor(A1) ; mark the window as Paletteless AWC.PB439 IgnoreWind Move.L nextWindow(A0),A0 ; grab the next window AWC.PB439 ListLoop Move.L A0,D0 ; CmpA.L #Nil,A0; another window? AWC.PB439 Bne.S CheckWindow ; yes => keep looking AWC.PB439 CmpA.L AppPalette,A3 ; are we disposing AppPalette? AWC.PB508 Bne.S NotAppPltt ; no => whew! AWC.PB508 Clr.L AppPalette ; okay, we won't try to find it anymore AWC.PB508 NotAppPltt Move pmPrivate(A2),D0 ; grab the last field we need from A2 AWC.PB439 And #PIdMask,D0 ; clear away flag bits Move.L PMgrHandle,A2 ; get the main handle CmpA.L #PMgrNil,A2 ; is it nil? Beq.S GoHome ; yes => don't try to find it Move.L (A2),A2 ; dereference it Move APalettes(A2),D1 ; start with number of active palettes Add FreeSpaces(A2),D1 ; add free spaces to get length of list Cmp D1,D0 ; are we within the correct range? Bpl.S GoHome ; no => punt Move.L PListHandle(A2),A1 ; get handle to list of palettes Move.L (A1),A1 ; dereference it CmpA.L (A1,D0.W*8),A3 ; get this handle; do they match? Bne.S GoHome ; no => in the future we may scan for it; for now, punt Clr.L (A1,D0.W*8) ; it's no longer referenced AddQ #1,FreeSpaces(A2) ; add 1 to free spaces SubQ #1,APalettes(A2) ; subtract 1 from total palettes GoHome MoveM.L (SP)+,A2-A3 ; restore registers Unlk A6 ; clear stack frame Rtd #ParamSize ; strip parameters and go home ;--------------------------------------------------- ; ; PROCEDURE Correlate; LOCAL; ; ; Make sure we have sufficient colors for all Tolerant entries. ; We use the bit table (availbits) to make sure that we don't ; yank the same entry twice, or steal an animated explicit. Correlate PROC EXPORT IMPORT Pillage,DeltaRGB,GimmeIndex MOVEM.L D3-D7/A2-A3,-(SP) TST Tolerators(A6) ; Anything intolerant? BEQ Leave ; No. Bail. ; ; First, we'll snag any explicit tolerant entries. ; MOVEQ #0,D4 ; entry number we're examining MOVE.L PalettePtr(A6),A2 ; A2->our palette LEA pmInfo(A2),A2 ; A2->first colorInfo MOVE.L DevCTab(A6),A3 ; A3 = device colortable handle MOVE.L A3,A0 ; A0 gets handle _HLock ; Lock it down MOVE.L (A3),A3 ; A3-> device colortable CLR.L D3 ; Clear the upper bits, for BF ops ExplLoop MOVE ciUsage(A2),D7 ; D7 = usage of this entry if 0 then ; ; I'm taking this code out for now. It causes us to not add entries that we used to add. This code ; is not installed for IIci ROMs. It only began being installed for SuperMario. By taking it out we ; bring the palette manager back to the Quadra Rom but bring back a bug with tolerant+explicit+ ; inhibited... BMI.S ExplLoopEnd ; Already handled? endif BTST #TolerantBit,D7 ; A Tolerator? BEQ.S ExplLoopEnd ; No, try next BTST #ExplicitBit,D7 ; Explicit Tolerator? BEQ.S ExplLoopEnd ; No, try next MOVE D4,D3 ; D3 = palette entry AND BlackIndex(A6),D3 ; D3 = explicit-ized clut index BEQ.S ExplLoopEnd ; Don't take index zero! it's white, you know. CMP BlackIndex(A6),D3 ; Are trying to snag black? BEQ.S ExplLoopEnd ; No! No! No! BFTST availBits(A6){D3:1} ; Already taken (by exp-anim, or earlier exp-tol)? BNE.S ExplLoopEnd BFSET availBits(A6){D3:1} ; No! Mark it as taken! MOVE D3,-(SP) ; This is the index we want to steal JSR Pillage ; Make sure noone else is settin on it SUBQ #2,SP ; Space for colordelta result PEA ciRGB(A2) ; Push palette's desired color PEA ctTable+rgb(A3,D3*8) ; Push current device's color bsr.l DeltaRGB ; How far apart are we? MOVE (SP)+,D1 CMP ciTolerance(A2),D1 ; are we within tolerance? BLS.S @GoodColor ; Yes=>don't change its RGB LEA ctTable(A3,D3*8),A0 ; A0->colorspec we're doing MOVE.L ciRGB+red(A2),rgb+red(A0) ; copy palette's red,green into device MOVE ciRGB+blue(A2),rgb+blue(A0) ; copy palette's blue into device BSET #ctTolBit,value(A0) ; Set the tolerator bit for index SUB #4,SP ; space for result _GetCTSeed ; put new seed MOVE.L (SP)+,ctSeed(A3) ; into table ADDQ #1,updates(A6) ; We've made a device change @GoodColor BSET #HandledBit,ciFlags(A2) ; Mark entry as handled ExplLoopEnd ADD #ciSize,A2 ; Bump A2 to next colorInfo in our palette ADDQ #1,D4 ; D4 is next entry number CMP myEntries(A6),D4 ; Up to, and not including, number of entries BLT.S ExplLoop ExplDone ;Now, we'll snag any regular tolerant entries. MOVE.L PalettePtr(A6),A2 ; A2->our palette LEA pmInfo(A2),A2 ; A2->first colorInfo ;Walk thru each palette entry and make sure there's an index within tolerance. CLR.L D7 ; Clear upper bits of D7, for BF ops CLR.L D4 ; D4 = palette entry number, and flags in high bits MOVE BlackIndex(A6),D5 ; when looking for indices, start at D5 and work down. SnagLoop TST ciFlags(A2) ; has this entry been handled? BMI SnagLoopEnd ; yah. BTST #TolerantBit,ciUsage+1(A2) ; Is it a tolerator? BEQ SnagLoopEnd ; nah. MOVE ciTolerance(A2),D6 ; get tolerance, for later CMPI #33,Tolerators(A6) ; If a smallish number of tolerators, BLT.S CheckColor ; Take slow C2I case. BTST #31,D4 ; Until one entry missed, take slow C2I case. BEQ.S CheckColor CMP #$400,D6 ; if tol<$400, just find one (instead of lots of color-to-indexes with new itables) BLS.S GrabIndex ; Go grab it. CheckColor SUBQ #4,SP ; space for Color2Index result PEA ciRGB(A2) ; push pointer to rgb _Color2Index MOVE.L (SP)+,D7 ; D7 = closest match SUBQ #2,SP ; DeltaRGB result PEA ciRGB(A2) ; Push palette's rgb PEA ctTable+rgb(A3,D7*8) ; Push closest-match rgb bsr.l DeltaRGB CMP (SP)+,D6 ; Compare delta to ciTolerance BHS.S SnagIt ; Low enough, just mark it handled and go on to take index. BFTST availBits(A6){D7:1} ; Out of range, but is it owned? BEQ.S YankIt ; If not, we'll take that entry. ;We must find an index to yank to our color. GrabIndex SUBQ #2,SP BSR GimmeIndex ; Get the next available index MOVE (SP)+,D7 ; D7 = next so-called available index BEQ.S GoHome ; Zero means we're out of entries BFTST availBits(A6){D7:1} ; Have we already matched to it? BNE.S GrabIndex ; If so, we can't just use it. PillIt MOVE D7,-(SP) ; Pillage this entry JSR Pillage YankIt LEA ctTable(A3,D7*8),A0 ; A0->colorSpec we're grabbing MOVE.L ciRGB+red(A2),rgb+red(A0) ; Yank our index's red,green MOVE ciRGB+blue(A2),rgb+blue(A0) ; Yank our index's blue BSET #ctTolBit,value(A0) ; Mark it as tolerance-yanked SUB #4,SP ; space for result _GetCTSeed ; put new seed MOVE.L (SP)+,ctseed(A3) ; into table ADDQ #1,updates(A6) ; We've made changes BSET #31,D4 ; We've made changes anyway, we can snag quickly. SnagIt BFSET availBits(A6){D7:1} ; Mark this index as taken SnagLoopEnd ADD #ciSize,A2 ; Bump A2 to next colorinfo ADDQ #1,D4 ; Advance D4 to next entry CMP myEntries(A6),D4 ; Done yet? BNE SnagLoop GoHome MOVE.L DevCTab(A6),A0 ; Get handle _HUnlock ; Release it Leave MOVEM.L (SP)+,D3-D7/A2-A3 RTS ;--------------------------------------------------- ; ; PROCEDURE DisposeAppPalettes(); ; ; Look through the palette list and dispose of any in the current App heap. DisposeAppPalettes PROC EXPORT MOVEM.L A0-A3/D0-D3,-(SP) ; save all registers MOVE.L PMgrHandle,A2 ; get paletteMgr handle CMP.L MinusOne,A2 ; is it there? BEQ GoHome ; => no, just return MOVE.L (A2),A1 ; point to data structure MOVE.L PListHandle(A1),A0 ; get handle to palette list _HLock ; and lock it down MOVE.L (A0),A3 ; point to palette list Move APalettes(A1),D3 ; get number of active handles Beq.s NoPals ; no friends => go home Add FreeSpaces(A1),D3 ; calculate total number of entries ;<13> Clr.L WindowList ; clear the list of windows for FrontWindow AWC.PB506 BRA.S FindEnd ; => check for no entries FindLoop Move.L PaletteRef(A3),D1 ; get first entry BEQ.S FindNext ; => no palette in entry MOVE.L ApplZone,A0 ; get application heap zone <41> CMP.L A0,D1 ; Are we before the heap zone? <41> BLO.S FindNext ; Yes => not in app heap CMP.L bklim(A0),D1 ; Are we past the heap zone <41> BHS.S FindNext ; => not in app heap MOVE.L D1,-(SP) ; push palette handle _DisposePalette ; and dispose it in place FindNext AddQ #PLstEntrySz,A3 ; bump to the next entry FindEnd DBra D3,FindLoop ; repeat for all spaces NoPals MOVE.L (A2),A1 ; point to palette stuff MOVE.L PListHandle(A1),A0 ; get handle to palette list _HUnlock ; and unlock it GoHome Clr.L AppPalette ; set us up for the next guy AWC.PB508 MOVEM.L (SP)+,A0-A3/D0-D3 RTS ;--------------------------------------------------- ; ; PROCEDURE DevSetEntries(aGDev:GDeviceHandle); ; ; Pass a gDev handle in A0. A SetEntries is made with the device's own color table. ; The device's seed isn't changed, though. DevSetEntries PROC EXPORT MOVE.L A2,-(SP) ; save one register MOVE.L TheGDevice,-(SP) ; save current gDev MOVE.L (A0),A2 ; A2->gDev MOVE.L gdPMap(A2),A2 ; A2 = pixmapH MOVE.L (A2),A2 ; A2->pixmap MOVE.L pmTable(A2),A2 ; A2 = cTabH MOVE.L (A2),A2 ; A2->colortable MOVE.L ctSeed(A2),-(SP) ; save seed til after SetEntries MOVE.L A0,TheGDevice ; set to our important one Clr -(SP) ; push starting count of 0 for SetEntries Move ctSize(A2),-(SP) ; push number of entries-1 Pea ctTable(A2) ; push address of the first ColorSpec _SetEntries ; do it MOVE.L (SP)+,ctSeed(A2) ; restore seed MOVE.L (SP)+,TheGDevice ; restore gDev MOVE.L (SP)+,A2 ; restore register RTS ;--------------------------------------------------- ; ; PROCEDURE DisposePalette(srcPalette: PaletteHandle); INLINE $AA93; ; DisposePalette PROC EXPORT ParamSize equ 4 ; total bytes of params srcPalette equ ParamSize+8-4 ; PaletteHandle to dispose VarSize equ 0 Link A6,#VarSize ; build stack frame Move.L A2,-(SP) ; save registers Move.L srcPalette(A6),A2 ; get the handle CmpA.L #Nil,A2 ; is it nil? Beq.S GoHome ; yes => go home Move.L A2,-(SP) ; push handle Jsr ClearPalette ; release any animating entries Bne.S GoHome ; if nonzero the palette was bad AWC.PB457 Move.L A2,-(SP) ; push it again Jsr ErasePalette ; erase palette from PMgrHandle and its window Move.L A2,A0 ; fetch palette handle into A0 _DisposHandle GoHome MOVE.L (SP)+,A2 ; restore register Unlk A6 ; clear stack frame Rtd #ParamSize ; strip parameters and go home ;--------------------------------------------------- ; ; FUNCTION GetClut(aGDev:gDeviceHandle):handle; Local; ; ; return a handle of an appropriate default clut for the device passed. ; This'll be unlocked, purgeable. PROC EXPORT GetClut GCVars RECORD {A6Link},DECREMENT result DS.B 4 ;Result: Handle to clut aGDev DS.B 4 ;Input: device handle return DS.B 4 A6Link DS.B 4 ;old contents of A6 oldZone DS.B 4 ;zone, upon entering typeNumber DS.B 2 linkSize DS.B 0 ;linky number ENDR whichClut DC.B 0,1,2,3,4,0,0,5,6 ; Which cluthandle to use ; depth 1 2 2 4 4 8 8 ; color? x n y n y n y clutIDs DC.B $01,$22,$42,$24,$44,$28,$08 WITH GCVars GetClut LINK A6,#linkSize MOVEM.L A0-A1/D0-D3,-(SP) _GetZone ; Save old heap zone, MOVE.L A0,oldZone(A6) ; To restore upon exit. MOVE.L SysZone,A0 _SetZone ; But we'll use the system heap. MOVE.L aGDev(A6),A0 MOVE.L (A0),A0 MOVE.L gdPMap(A0),A1 MOVE.L (A1),A1 MOVE pmPixelSize(A1),D0 CMPI #1,D0 ; one bit? BEQ.S @bw ; can only be black&white BTST #0,gdFlags+1(A0) ;A color device? BEQ.S @bw ; no? pixelSize is good enough ADDQ #1,D0 @bw LEA whichClut-1,A1 ; A1->which cluthandle to use MOVE.B (A1,D0.W),D0 ; Get byte sized offset, D0 hibits clr MOVE D0,typeNumber(A6) ; save number 0-6 for clut type MOVE.L PMgrHandle,A0 ; A0 = the big handle MOVE.L (A0),A0 ; A0->PMgr MOVE.L sevenCluts(A0,D0*4),A0 ; A0 = old Handle for this spot MOVE.L A0,D1 ; Is it NIL? BEQ.S @getCTab ; Yes, we'll have to get one MOVE.L (A0),D1 ; Is it Purged? BEQ.S @tossAndGet ; Yes => lose old handle, get new one MOVE.L A0,result(A6) ; No => we had the last one we made BRA.S @nilResult ; we'll return it. @tossAndGet _DisposHandle MOVE typeNumber(A6),D0 @getCTab LEA clutIDs,A0 ; A0->table of clut resource ID's CLR.L D3 ; Zap upper bytes MOVE.B (A0,D0.W),D3 ; Get byte-sized morsel into D0, high bits clear SUBQ #4,SP ; Room for result MOVE D3,-(SP) ; Push resource ID _GetCTable MOVE.L (SP)+,A0 ; Handle in A0 MOVE.L A0,result(A6) ; Get that result into our result BEQ.S @nilResult ; Problem? MOVE.L (A0),A1 ; A1->our new clut CMP.L ctSeed(A1),D3 ; Does the seed match the ID? BNE.S @purgeIt ; No=>can't be a ROM resource SUBQ #4,SP MOVE.L #'clut',-(SP) MOVE D3,-(SP) MOVE.L A0,D3 ; We'll keep old one in D3 a moment MOVE #$FFFF,RomMapInsert _Get1Resource ; Get only a ROMish version of clut-D3 MOVE.L (SP)+,D2 ; Get anything? BEQ.S @useOld ; No=>go deal with old one MOVE.L D2,result(A6) ; Yes=>save this one, MOVE.L D3,A0 ; lose the old one _DisposHandle BRA.S @gotIt @useOld MOVE.L D3,A0 @purgeIt _HPurge ; No, so mark it purgeable @gotIt MOVE.L PMgrHandle,A0 ; And save the handle. MOVE.L (A0),A0 ; A0->PMgrData MOVE typeNumber(A6),D0 ; D0 = selection, 0-5 MOVE.L result(A6),sevenCluts(A0,D0*4) ; And save the handle. @nilResult MOVE.L oldZone(A6),A0 ; Now, restore previous zone. _SetZone @goHome MOVEM.L (SP)+,A0-A1/D0-D3 UNLK A6 RTD #result-return-4 ;--------------------------------------------------- ; ; PROCEDURE InitPalettes; INLINE $AA90; ; PROC IMPORT RecordPalette,CHECKALLDEVICECLUTS IMPORT SCATTERDEVICES,UpdateDevices EXPORT InitPalettes EXPORT SysColors,SysColorEnd SysColorCount EQU 2 SysColors DC.W $0000,$0003,$0000,$000F ; seed [long], transIndex [word], ctSize [word] DC.W $0000,$FFFF,$FFFF,$FFFF ; white DC.W $0001,$0000,$0000,$0000 ; black SysColorEnd EQU * VarSize equ 0 InitPalettes Link A6,#VarSize ; build stack frame MoveM.L D3-D4/A2-A4,-(SP) ; save registers ; Start by running down the device list, finding all active CLUT devices. Count how many ; there are and record them in PListHandle. Move.L PMgrHandle,D0 ; get the Palette Manager handle Cmp.L #PMgrNil,D0 ; is it nil? Bne ChkAppPltt ; we're initializaed - check for AppPalette AWC.PB520 ; To start things up, allocate enough room for static Palette Manager data and 32 device table ; slots. Note that the current implementation of Color Quickdraw (not the architecture) sets ; a limit on the color index model of 256 entries. THIS NUMBER IS ASSUMED BY THE CODE BELOW, ; but the structure will allow modification once 'clut's bigger than 256 entries are allowed. ; This code also assumes that the cards have the potential of being 256 entry cards even if ; set at a lower resolution, so it always allocates 256 entries in each device map (integer sized). ; Note - the total space allocated for pm device table space is presumed (below) to ; be long word aligned. See the loop below at Clearing. Move.L #PMgrDataSz,D4 ; set D4 to the required size AWC.PB500 Move.L D4,D0 ; copy size to D0 _NewHandle ,SYS,CLEAR ; allocate our data area in the system heap Bne GoHome ; we got an error, so we quit Move.L A0,A3 ; copy to A3 for later use Move.L A0,PMgrHandle ; and remember it in low memory MoveQ #0,D3 ; zero our device count Move.L (A3),A4 ; dereference PMgrHandle CLR.L scatterDevs(A4) ; no devices needing scatter, to start CLR.L updateDevs(A4) ; no devices needing scatter, to start AddA #DevHandles,A4 ; point A4 at our local device list Clr.L -(SP) ; push room for device handle AWC.PB500 _GetDeviceList ; get the start of the device list AWC.PB500 Move.L (SP)+,A2 ; put the device list in A2 AWC.PB500 Bra.S DeviceEnd ; jump to the end of the loop AWC.PB500 DeviceLoop Move.L (A2),A0 ; dereference device handle Move gdFlags(A0),D0 ; get flags; is it an active device? ; Bpl.S NextDevice ; no => examine next device ;Yes, we do. BTst #ScreenDevice,D0 ; is it a screen device? Beq.S NextDevice ; no => examine next device AWC.PB377 ; three lines commented out: we list non-cluts in case they become clut. dvb1 ; Move gdType(A0),D0 ; get the type of the device AWC.PB377 ; Cmp #ClutType,D0 ; is it a Clut device? ; Bne.S NextDevice ; no => we only track Clut devices AddQ #1,D3 ; yes => bump our device count by 1 Move.L A2,DevHandle(A4) ; copy device handle AWC.PB500 Clr.L DevFrontMost(A4) ; clear device FrontMost field AddQ #DevInfoSz,A4 ; bump A4 to the next device slot Add.L #256*PmDevSz,D4 ; each device table is 1024 bytes (for now) Cmp #DevLimit,D3 ; are we at the limit the PMgr can handle? AWC.PB500 Bpl.S EnoughDevs ; if so, we'll ignore any remaining devices NextDevice Move.L gdNextGD(A0),A2 ; grab next device AWC.PB500 DeviceEnd Move.L A2,D0 ; CmpA #Nil,A2; is it nil? AWC.PB500 Bne.S DeviceLoop ; no => let's do it again EnoughDevs Move.L (A3),A4 ; redereference PMgrHandle Move D3,nDevs(A4) ; save length of device list Move D3,D0 ; make a copy of D3 Bne.S SeedSizeOk ; make sure we have a minimum size seed AWC.PB500 AddQ #1,D0 ; a kludge, but it's easier this way AWC.PB500 SeedSizeOk Lsl #2,D0 ; multiply by 4 AWC.PB500 Move D0,SeedHSize(A4) ; save size of SeedHSize handle Clr APalettes(A4) ; no animating palettes yet Move #ListSpace,FreeSpaces(A4) ; 16 free slots; we'll add more if needed Move.L D4,D0 ; D4 is the required size of PMgrHandle Move.L A3,A0 ; put handle in A0 for the call _SetHandleSize ; and expand the handle up Bne.S ResizeFails ; it went badly Move.L #ListSpace,D0 ; start with initial space for handles Lsl #3,D0 ; multiply by 8 _NewHandle SYS,CLEAR ; allocate and clear the handle Beq.S ClearAll ; if it works, continue Move.L A3,A0 ; prepare to dispose the handle _DisposHandle ; get rid of it ResizeFails Move.L #PMgrNil,PMgrHandle ; it didn't work - zero the handle Bra GoHome ; head home with error in D0 AWC.PB508 ClearAll Move.L (A3),A4 ; redereference PMgrHandle Move.L A0,PListHandle(A4) ; save the list of handles Move.L A3,A0 ; put PMgrHandle into A0 _HLock ; lock it down MOVE.L (A3),A4 ; redereference LEA sevenCluts(A4),A0 ; A0->list of depth-cluts MOVEQ #6,D0 ; A loop counter @sclclr CLR.L (A0)+ ; Clear one handle DBRA D0,@sclclr Move D3,D0 ; get the number of devices Lsl #8,D0 ; multiply by 1024/4 (1024 per device/4 per CLR.L) Lea PMgrDataSz(A4),A0 ; calculate start of device links Bra.S ClearEnd ; jump into loop ClearLoop Clr.L (A0)+ ; clear a long word - see! long word aligned ClearEnd DBra D0,ClearLoop ; repeat for all long words Move.L theZone,-(SP) ; save the current zone Move.L SysZone,theZone ; set the system zone Clr.L -(SP) ; clear some space for a handle Clr -(SP) ; push PaletteId = 0 _GetNewPalette ; try to get the system palette Move.L (SP)+,SysPalette(A4) ; save it; was it nil? Bne.S NoError ; no => we're done Lea SysColors,A0 ; get a pointer to our default table Move.L #SysColorEnd-SysColors,D0 ; get size _PtrToHand ; make a handle out of it Move.L A0,D3 ; save it Clr.L -(SP) ; space for result Move #SysColorCount,-(SP) ; push the number of entries Move.L A0,-(SP) ; push our handle Move #pmCourteous,-(SP) ; all courteous entries Move #$0000,-(SP) ; reasonably tolerant entries, too _NewPalette ; let's call ourselves to get a new palette Move.L (SP)+,SysPalette(A4) ; save the palette; we sure hope we got one Move.L D3,A0 ; put handle back in A0 _DisposHandle ; snuff it NoError Move.L SysPalette(A4),A0 ; get the palette for a moment CmpA.L #Nil,A0 ; is there one? Beq.S Cleanup ; no => cleanup Move.L (A0),A0 ; dereference SysPalette BSet #CForeBit,pmPrivate(A0) ; set the system update bits BSet #CBackBit,PmPrivate(A0) Cleanup Move.L (SP)+,theZone ; restore the current zone Move.L A3,A0 ; get PMgrHandle _HUnlock ; unlock it JSR CheckAllDeviceCluts ; Let PMgr slam the device cluts MOVE #$1,-(SP) ; Set the palette with new colors JSR ScatterDevices ; Redistribute them clut indices Clr.L AppPalette ; clear the applications's palette AWC.PB457 Bra.S LookForIt ; jump ahead AWC.PB520 ; Notice that we rely upon AppPalette being initialized (or -1) every time we arrive here. If ; it is non-zero, we assume this is an extra call to InitPalettes so we just leave. ChkAppPltt Move.L AppPalette,D0 ; fetch AppPalette; is it nil? AWC.PB520 Beq.S LookForIt ; yes => look for a palette resource 0 AWC.PB508 AddQ.L #1,D0 ; bump it by 1; was it $FFFFFFFF? AWC.PB508 Bne ChkAppPEnd ; no => must be good; next thing AWC.PB520 CLR.L AppPalette ; clear the AppPalette AWC.PB508 LookForIt Tst CurApRefNum ; are we using the system resource file? AWC.PB469 Beq.S ChkAppPEnd ; yes => forget installing an AppPalette AWC.PB520 Clr -(SP) ; function result AWC.PB457 _CurResFile ; get the current resfile AWC.PB457 Move (SP)+,D3 ; put it in D3 AWC.PB457 Cmp CurApRefNum,D3 ; need we change it? AWC.PB457 Beq.S ResFileOkay ; no => we've already got it AWC.PB457 Move CurApRefNum,-(SP) ; push the refnum back AWC.PB457 _UseResFile ; use this resfile AWC.PB457 Clr -(SP) ; result word AWC.PB506 _ResError ; see if this worked AWC.PB506 Move (SP)+,D0 ; get the result AWC.PB506 Bne.S ChkAppPEnd ; quit if we didn't get it AWC.PB520 ResFileOkay Clr.L -(SP) ; function result AWC.PB457 Move.L #'pltt',-(SP) ; push the resource type AWC.PB457 Clr -(SP) ; id 0 AWC.PB457 _Get1Resource ; fetch an application palette, if any AWC.PB457 Move.L (SP)+,A2 ; get handle off the stack AWC.PB457 Move.L A2,D0 ; CmpA.L #Nil,A2; did we get a resource? AWC.PB457 Beq.S Cleanup2 ; if nil we go home AWC.PB457 Move.L A2,-(SP) ; push it for the DetachResource AWC.PB457 _DetachResource ; disconnect from resource manager AWC.PB457 Move.L (A2),A0 ; dereference palette AWC.PB457 Move #AllUpdates,D1 ; set D1 to the default AWC.PB457 Move plttUpdates(A0),D0 ; get update bits AWC.PB457 Bpl.S NoResUpdate ; the user didn't specify any AWC.PB457 ADD D0,D0 ; put the bits in the correct place AWC.PB457 Move D0,D1 ; put the result into D1 AWC.PB457 NoResUpdate Move D1,pmPrivate(A0) ; put them in the correct place AWC.PB457 Move.L A2,-(SP) ; push palette for the RecordPalette AWC.PB457 Jsr RecordPalette ; allocates seeds handle, records palette AWC.PB457 Bne.S Cleanup2 ; it disposed palette if failed AWC.PB457 Move.L A2,AppPalette ; copy it to AppPalette AWC.PB457 Move.L (A2),A0 ; dereference AppPalette AWC.PB457 BSet #DisposeBit,pmPrivate(A0) ; set for automatic disposal AWC.PB457 Clr.L pmDevices(A0) ; clear device bitmap AWC.PB457 Cleanup2 Cmp CurApRefNum,D3 ; did we change the current resfile? AWC.PB457 Beq.S ChkAppPEnd ; no => don't put it back AWC.PB457 Move D3,-(SP) ; push the old current resfile AWC.PB457 _UseResFile ; and restore the old one AWC.PB457 ChkAppPEnd CheckExit JSR UpdateDevices GoHome MoveM.L (SP)+,D3-D4/A2-A4 ; restore registers Unlk A6 ; clear stack frame Rts ; go home ;--------------------------------------------------- ; ; FUNCTION CheckDeviceColors(aGDev:gdHandle):Boolean; LOCAL; ; ; Looks at a (hopefully clut) device, and compare its clut to the ; default clut for that device. If even one entry which is not owned for animation ; is out of place, the whole clut is marked for scattering. Return TRUE if ; the device is now marked for scattering. CheckDeviceColors PROC EXPORT CDCVars RECORD {A6Link},DECREMENT result DS.B 2 ;Result: boolean aGDev DS.B 4 ;Input: device handle return DS.B 4 A6Link DS.B 4 ;old contents of A6 linkSize DS.B 0 ;linky number ENDR WITH CDCVars LINK A6,#linkSize MOVEM.L A0-A3/D0-D2,-(SP) CLR D2 ; D2 = on-the-fly bool result. MOVE.L aGDev(A6),A2 MOVE.L (A2),A3 ; A3->gDevice TST gdType(A3) ; a clut device? BNE.S GoHome ; No=> go home w/false MOVE $14(A3),D0 AND #$8010,D0 BEQ.S GoHome ; No=> ditto SUBQ #4,SP ; space for result MOVE.L A2,-(SP) ; push gDevice handle JSR GetClut ; get the appropriate default clut MOVE.L (SP)+,A0 ; A0 = handle to default clut, keep handle on stk MOVE.L (A0),A0 ; A0->default clut LEA ctTable+rgb(A0),A0 ; bump to first colorSpec's rgb fiel MOVE.L gdPMap(A3),A1 ; A1 = device's pixmap MOVE.L (A1),A1 ; A1->device's pixmap MOVE.L pmTable(A1),A1 ; A1 = device's clut MOVE.L (A1),A1 ; A1->device's clut MOVE ctSize(A1),D0 ; D0 = size of clut - 1 LEA ctTable(A1),A1 ; bump A1 to first colorSpec iLoop BTST #reserveBit,value(A1) ; is this entry reserved? BNE.S iLoopEnd ; yes, skip it BSET #ctMatchBit,value(A1) ; mark entry as looked at MOVE.L red(A0),D1 ; get default red,green CMP.L rgb+red(A1),D1 ; do red and green match default? BNE.S fixIt ; No, scatter all the indices MOVE blue(A0),D1 ; Get default blue CMP rgb+blue(A1),D1 ; match device blue? BEQ.S iLoopEnd ; No, scatter... fixIt BSET #ctScatterBit,value(A1) ; Mark index for scattering MOVEQ #-1,D2 ; Set D2 result to true iLoopEnd ADDA #8,A0 ; Bump A0 to next colorSpec ADDA #8,A1 ; Bump A1 to next colorSpec DBRA D0,iLoop ; loop for all indices GoHome MOVE D2,result(A6) ; Set result. MOVEM.L (SP)+,A0-A3/D0-D2 UNLK A6 RTD #result-return-4 ;--------------------------------------------------- ; ; FUNCTION FindLink(LinkInfo:integer):integer; LOCAL; ; ; FindLink searches the device links until it encounters a device that matches Device or ; until it reaches the end of the list. It returns the index if it finds one. It ; returns 0 (which is an illegal index since it matches white) if it can't find one. FindLink PROC EXPORT ParamSize equ 2 ; total bytes of params theIndex equ ParamSize+10-2 ; index result LinkInfo equ theIndex-2 ; this palette's key to previously reserved entries VarSize equ 0 Link A4,#VarSize ; build stack frame Move.L D3,-(SP) ; save a register ; We will use D3 as a watchdog counter. We set it to the maximum number of devices that we ; might have to search so that if things go very wrong we stand a chance of finding out about it. Clr theIndex(A4) ; set result to "illegal" Move LinkInfo(A4),D0 ; get link data BfExtU D0{16:3},D1 ; grab top 3 bits Cmp #4,D1 ; are they set correctly Bne.S GoHome ; no => the LinkInfo is invalid Move Devices(A6),D3 ; get number of devices Move.L PMgrPtr(A6),A0 ; PMgrHandle^ AddA.L #LinkTabs,A0 ; calculate start of LinkTabs Bra.S IndexEnd ; start watchdog loop IndexLoop BfExtU D0{19:5},D1 ; grab device number (0..31) BfExtU D0{24:8},D2 ; grab index number (0..255) Cmp CurDevice(A6),D1 ; is it this device? Beq.S FoundIt ; yes => we've got it Lsl #8,D1 ; calculate offset to link table/4 Add D2,D1 ; offset to entry/4 Move (A0,D1.L*4),D0 ; get next link; is the top bit set? Bpl.S GoHome ; no => stop because we ran out of tries IndexEnd DBra D3,IndexLoop ; examine another index until our watchdog runs out ; Our watchdog counter ran out, so something is terribly wrong. We'll be polite about it and ; say we were just unable to find it. Bra.S GoHome ; We found the index. Set true and return the appropriate index to theIndex(A4) FoundIt And #$00FF,D2 ; clear everything except the index Move D2,theIndex(A4) ; set the result GoHome Move.L (SP)+,D3 ; restore registers Unlk A4 ; clear stack frame Rtd #ParamSize ; strip parameters and go home ;--------------------------------------------------- ; ; PROCEDURE AnalyzeDev; LOCAL; ; ; Build, into the InfoPtr, a sequence of entries to steal. The priorities are ; as follows: Any explicit entries are available for explicating. Any free ; entries are first available. Any yanked-tolerant entries are available next. ; Any animated entries owned by other palettes are available last. ; One more thing: the secondary sorting on 1,2,4-bit devices is by index, and on ; 8-bit devices is by nibble-swapped index. Thus, and this is especially ; important on gray-scale cluts, the indices ; will be stolen in a somewhat spread-out manner. AnalyzeDev PROC EXPORT MOVEM.L A2-A3/D3-D5,-(SP) LEA availBits(A6),A2 ; A2->availBits. Permanently. MOVE.L DevCTab(A6),A3 ; A3 = handle to current dev's clut MOVE.L (A3),A3 ; A3 -> current dev's clut. Permanently. CLR.L D3 ; Clear upper bits of D3, for BF op MOVE BlackIndex(A6),D3 ; D3 = highest index. Permanently. CLR D4 ; D4 = number of indices put into list. BSR ClearAvailBits ; Start the bits az nilz. ; ; First, find and unavailable-ize any ; eplicit entries from our palette. ; MOVE.L PalettePtr(A6),A0 ; A0->our palette CLR.L D0 ; D0 = each entry number, starting zero CLR.L D2 ; Clear upper bits of D2, for BF ops LEA pmInfo(A0),A1 BRA.S @expEnd @expLoop MOVE ciFlags(A1),D1 ; D1 = usage for the entry BMI.S @expNext ; Handled-bit->set! BTST #explicitBit,D1 ; An explicit entry? BEQ.S @expNext MOVE D0,D2 ; Copy entry number. AND D3,D2 ; And it down into clut's range BFSET (A2){D2:1} ; Set the used bit in our array o' bits @expNext ADDA #ciSize,A1 ; Bump A1 to next colorinfo ADDQ #1,D0 ; Bump D0 to match it's index @expEnd CMP pmEntries(A0),D0 ; Done last one yet? BLO.S @expLoop ; No, do more. ; ; Add any fully open indices to our list. ; MOVE.L InfoPtr(A6),A1 ; A1->our list o' entries. MOVE D3,D0 ; D0 will do our walking CLR.L D1 ; Clear upper bits of D1, for BF ops @openLoop MOVE D0,D1 ; D1=our possibly scrambled index BTST #4,D3 ; 8-bit device? BEQ.S @openNot8 ; No, don't spread entries ROR.B #4,D1 ; Yes => swap hi,lo nibbles @openNot8 BFTST (A2){D1:1} ; This entry already taken? BNE.S @openNext ; Yes => try next MOVE ctTable+value(A3,D1*8),D2 ; Get the status of index D1 AND #ctReserveVal+ctTolVal,D2 ; Mask out the bits we need to check BNE.S @openNext ; Either bit set is a problem, cant use it BFSET (A2){D1:1} ; Mark it as taken MOVE D1,(A1,D4*2) ; Put index into list. ADDQ #1,D4 ; One more in list. @openNext DBRA D0,@openLoop ; Keep checking, right down to zero. ; ; Add any non-reserved (inanimate) indices to our list. ; MOVE D3,D0 ; D0 will do our walking @inAniLoop MOVE D0,D1 ; D1=our possibly scrambled index BTST #4,D3 ; 8-bit device? BEQ.S @inAniNot8 ; No, don't spread entries ROR.B #4,D1 ; Yes => swap hi,lo nibbles @inAniNot8 BFTST (A2){D1:1} ; This entry already taken? BNE.S @inAniNext ; Yes => try next BTST #ctReserveBit,ctTable+value(A3,D1*8) ; This index anim? BNE.S @inAniNext ; Yes: not for us. BFSET (A2){D1:1} ; Mark it as taken MOVE D1,(A1,D4*2) ; Put index into list. ADDQ #1,D4 ; One more in list. @inAniNext DBRA D0,@inAniLoop ; Keep checking, right down to zero. ; ; Add any reserved indices which aren't ours to our list. ; This is called Seriously Pillaging. ; MOVE pmPrivate(A0),D5 ; D5 = palette number plus some bits AND #pIDMask,D5 ; D5 = palette number. Move.L PMgrPtr(A6),A0 ; A0 = base pointer AddA.L #LinkTabs,A0 ; A0->dem linky tings MOVE D3,D0 ; D0 will do our walking @pillLoop MOVE D0,D1 ; D1=our possibly scrambled index BTST #4,D3 ; 8-bit device? BEQ.S @pillNot8 ; No, don't spread entries ROR.B #4,D1 ; Yes => swap hi,lo nibbles @pillNot8 BFTST (A2){D1:1} ; This entry already taken? BNE.S @pillNext ; Yes => try next ; No=> walk the linktabs, see if it's ours MOVE CurDevice(A6),D2 ; D2 = device number we're checking LSL #8,D2 ; Device number in upper bits MOVE.B D1,D2 ; Index in lower byte @findOwner AND #$1FFF,D2 ; Clear key bits MOVE.W foreLink(A0,D2*4),D2 ; Get the forelink BEQ.S @pillNext BMI.S @findOwner AND #$1FFF,D2 ; Okay, clear the key bits CMP D2,D5 ; Is this index owned by this palette BEQ.S @pillNext ; Yes: not for us. BFSET (A2){D1:1} ; Mark it as taken MOVE D1,(A1,D4*2) ; Put index into list. ADDQ #1,D4 ; One more in list. @pillNext DBRA D0,@pillLoop ; Keep checking, right down to zero. MOVE D4,Pillages(A6) ; This is how many we've got Clr Histogram(A6) ; This is how many we've used BSR.S ClearAvailBits ; Clear the bits array to nothing again. MOVEM.L (SP)+,A2-A3/D3-D5 RTS ClearAvailBits MOVEQ #7,D0 @a CLR.L availBits(A6,D0*4) DBRA D0,@a BFSET availBits(A6){0:1} ; set the bit for white BFSET availBits(A6){D3:1} ; set the bit for black RTS ;--------------------------------------------------- ; ; PROCEDURE Pillage(myChoice); LOCAL; ; ; Just clear the links for index myChoice on CurDevice(A6) ; No registers altered. Pillage PROC EXPORT PilVars RECORD {A4Link},DECREMENT result DS.B 0 ;result: none myChoice DS.B 2 ;input: index to pillage return DS.B 4 A4Link DS.B 4 ;old contents of A4 linkSize DS.B 0 ;linky number ENDR WITH PilVars LINK A4,#linkSize MoveM.L D0/D3/D4,-(SP) ; save registers MOVE myChoice(A4),D3 ; does the caller want a specific index? MOVE CurDevice(A6),D4 LSL #8,D4 ; shift device into upper bits MOVE.B D3,D4 ; put index into low bits MOVE D4,-(SP) _ZapLinks ; unlink index D3 of CurDevice(A6) MOVE.L DevCTab(A6),A0 ; A0 = current device's clut MOVE.L (A0),A0 ; A0->clut CLR ctTable+value(A0,D3*8) ; Unmark the clut index entirely GoHome MoveM.L (SP)+,D0/D3/D4 ; restore registers Unlk A4 ; clear stack frame Rtd #result-return-4 ; strip parameters and go home ;--------------------------------------------------- ; ; FUNCTION GimmeIndex:INTEGER; LOCAL; ; ; Judging from the infohandle, get the next available index. Return ; zero if there's none left. We assume the ActivatePalette stack frame. ; We'll make use of registers D0,D1, and A0. ; GimmeIndex PROC EXPORT CLR D1 ; our result MOVE Histogram(A6),D0 ; D0 = next item from infoptr to steal CMP Pillages(A6),D0 ; Taken as many as we can? BEQ.S @goHome ; Return nil. MOVE.L infoPtr(A6),A0 ; A0->list of indices to take MOVE (A0,D0*2),D1 ; D1 = next one off list ADDQ #1,Histogram(A6) ; Bump to next guy @goHome MOVE D1,4(SP) ; return index RTS ;--------------------------------------------------- ; ; PROCEDURE MarkDevUBit; LOCAL; ; ; Set bit CurDevice in updateDevs. MarkDevUBit PROC Move CurDevice(A6),D0 ; get current device MOVE.L PMgrPtr(A6),A0 ; A1->PMgr data MOVE.L updateDevs(A0),D1 ; tricky offset, get device update mask BSET D0,D1 ; set the device's bit for updating MOVE.L D1,updateDevs(A0) ; put back mask RTS IF NOT ROMPaletteMgr THEN ;--------------------------------------------------- ; ; FUNCTION DeltaRGB(RGB1,RGB2:RGBColor):integer; LOCAL; ; ; A cool routine which preserves all registers DeltaRGB FUNC EXPORT ParamSize equ 8 ; total bytes of params Delta equ ParamSIze+10-2 ; integer result RGB1 equ Delta-4 ; palette entry pointer RGB2 equ RGB1-4 ; color table entry pointer VarSize equ 0 ; size of variables Link A6,#VarSize ; build stack frame MOVEM.L A0-A1/D0-D1,-(SP) Move.L RGB1(A6),A0 ; get first RGBColor Move.L RGB2(A6),A1 ; get second RGBColor Move (A1)+,D0 ; grab index red Sub (A0)+,D0 ; subtract entry red Bhs.S NotNeg1 ; take abs(Index.Red-ColorInfo.Red) Neg D0 ; negate it NotNeg1 Move (A1)+,D1 ; grab index green Sub (A0)+,D1 ; subtract entry green Bhs.S NotNeg2 ; take abs(Index.Green-ColorInfo.Green) Neg D1 ; negate it NotNeg2 Cmp D0,D1 ; leave greater unsigned value in D0 Blo.S DontSwitch1 ; D1 < D0 => D0 is already greater Move D1,D0 ; green value is greater DontSwitch1 Move (A1),D1 ; grab index blue Sub (A0),D1 ; subtract entry blue Bhs.S NotNeg3 ; take abs(Index.Blue-ColorInfo.Blue) Neg D1 ; negate it NotNeg3 Cmp D0,D1 ; leave greater unsigned value in D0 Blo.S FixResult ; D1 < D0 => D0 is already greater Move D1,D0 ; blue value is greater FixResult Move D0,Delta(A6) ; set result MOVEM.L (SP)+,A0-A1/D0-D1 Unlk A6 ; clear stack frame Rtd #ParamSize ; strip parameters and go home ENDF ENDIF ;--------------------------------------------------- ; ; PROCEDURE RedrawDesktop; LOCAL; ; ; Ignoring things like "DeskHook"... Just paint the rectangle pointed to by A2 on the desktop. ; We'll use A3 in the process. RedrawDesktop PROC EXPORT SUBQ #4,SP ; space for new region _NewRgn MOVE.L (SP),A3 ; A3 = new region, leave stack copy MOVE.L A2,-(SP) ; Push device rectangle _RectRgn ; Make that rectangular region CLR.L -(SP) ; NIL = desktop area MOVE.L A3,-(SP) ; Push the device region _PaintOne ; Update desktop within device bounds MOVE.L A3,-(SP) ; Get rid of our temp region _DisposRgn RTS ;--------------------------------------------------- ; ; PROCEDURE DirtySeeds(dstPalette: PaletteHandle); LOCAL; ; DirtySeeds PROC EXPORT ParamSize equ 4 ; total bytes of params dstPalette equ ParamSize+8-4 ; destination Palette handle VarSize equ 0 ; size of variables Link A6,#VarSize ; build stack frame AWC.PB508 Move.L PMgrHandle,A0 ; get the PMgrHandle (we assume its safe) AWC.PB508 Move.L (A0),A0 ; dereference it AWC.PB508 Move SeedHSize(A0),D0 ; get the seed handle size AWC.PB508 Lsr #2,D0 ; divide it by 4 to get number of longs AWC.PB508 SubQ #1,D0 ; decrement it for the DBra loop AWC.PB508 Move.L DstPalette(A6),A0 ; get the palette AWC.PB508 Move.L (A0),A0 ; dereference it AWC.PB508 BSet #DirtyBit,pmPrivate(A0) ; set the dirty bit AWC.PB508 Move.L pmSeeds(A0),A0 ; get the seeds handle AWC.PB508 Move.L (A0),A0 ; dereference it AWC.PB508 ClearLoop Clr.L (A0)+ ; clear a seed AWC.PB508 DBra D0,ClearLoop ; continue AWC.PB508 GoHome Unlk A6 ; clear stack frame AWC.PB508 Rtd #ParamSize ; strip parameters and go home AWC.PB508 ;--------------------------------------------------- ; ; PROCEDURE SetPalette(dstWindow: WindowPtr; srcPalette: PaletteHandle; CUpdates: BOOLEAN); ; INLINE $AA95; ; ; Passing -1 for the window sets the App Palette to the palette specified. SetPalette PROC EXPORT ParamSize equ 10 ; total bytes of params dstWindow equ ParamSize+8-4 ; source Palette handle srcPalette equ dstWindow-4 ; new window, if any CUpdates equ srcPalette-2 ; whether we want background color updates VarSize equ 0 ; size of variables Link A6,#VarSize ; build stack frame MOVE.L D3,-(SP) Move.L PMgrHandle,A1 ; we have to be initialized CmpA.L #PMgrNil,A1 ; is it initialized? Beq GoHome ; no => punt Move.L dstWindow(A6),A0 ; get the window pointer CmpA.L #-1,A0 ; does the caller want to set AppPalette? Bne.S NotSystem ; no => go look for the window Move.L AppPalette,D0 ; get the application palette; is it nil? AWC.PB457 Beq.S NoAppPltt ; yes => don't dispose it AWC.PB457 Move.L D0,A0 ; put it in an address register AWC.PB457 Move.L (A0),A0 ; dereference it AWC.PB457 BTst #DisposeBit,pmPrivate(A0) ; should we clobber it? AWC.PB457 Beq.S NoAppPltt ; no => the caller deals with it AWC.PB457 Move.L D0,-(SP) ; push the palette AWC.PB457 _DisposePalette ; can you say "bye bye"? AWC.PB457 NoAppPltt Move.L SrcPalette(A6),A0 ; get the palette parameter AWC.PB457 Move.L A0,AppPalette ; set the layer palette; is it nil? AWC.PB457 Beq.S AppNil ; no => activate the layer palette AWC.PB457 MOVE.L (A0),A0 ; A0->Palette BSet #CBackBit,PmPrivate(A0) ; set background update bit AWC PB223 BSet #CForeBit,PmPrivate(A0) ; set foreground update bit AWC PB223 Move.L SrcPalette(A6),A0 ; get the palette parameter AWC.PB457 BRA.S AppNotNil AppNil Move.L (A1),A0 ; dereference PMgrHandle Move.L SysPalette(A0),A0 ; get the system palette AWC.PB457 Move.L A0,D0 ; CmpA.L #Nil,A0; is it nil? AWC.PB457 Beq GoHome ; yes => shouldn't happen, but quit anyway AWC.PB457 AppNotNil Move.L A0,-(SP) ; push the palette pointer AWC.PB508 Bsr DirtySeeds ; clear the device seeds so we'll update AWC.PB508 Clr.L -(SP) ; push function result AWC.PB439 _FrontWindow ; push the front window AWC.PB439 Bra.S DontClear ; activate it AWC PB223 NotSystem Tst PortBits+RowBytes(A0) ; is it a new port? Bpl.S GoHome ; if not, we're out of here Move.L srcPalette(A6),D0 ; get the palette handle Move.L GrafVars(A0),A1 ; get handle to GrafVars Move.L (A1),A1 ; dereference GrafVars Move.L PmFgColor(A1),D3 ; save whatever's there currently Move.L D0,PmFgColor(A1) ; store the palette in GrafVars.PmFgColor; is it nil? Beq.S BitsOkay ; yes => that's okay, but we won't dereference it Move.L D0,A1 ; put the Palette handle into A1 Move.L (A1),A1 ; dereference it ; Move.L A0,pmWindow(A1) ; store the window in the palette AWC.PB439 BClr #CBackBit,PmPrivate(A1) ; clear background update bit AWC PB223 BSet #CForeBit,PmPrivate(A1) ; set foreground update bit AWC PB223 Tst.B CUpdates(A6) ; does she want background updates? AWC PB223 Beq.S BitsOkay ; 0 => default case, CUpdates = false AWC PB223 Bpl.S AllowBacks ; 1 => CUpdates = true AWC PB223 BTst #NForeBit,CUpdates(A6) ; does he want foreground updates? AWC PB223 Bne.S YesFores ; yes => leave it as is AWC PB223 BClr #CForeBit,PmPrivate(A1) ; turn foreground updates off AWC PB223 YesFores BTst #NBackBit,CUpdates(A6) ; does she want background updates? AWC PB223 Beq.S BitsOkay ; no => skip it AWC PB223 AllowBacks BSet #CBackBit,PmPrivate(A1) ; set the foreground update bit AWC PB223 BitsOkay Cmp.L D0,D3 ; are they identical? AWC PB223 Beq.S GoHome ; don't bother activating anything Move.L A0,-(SP) ; push the window pointer for the activate palette Tst.L D3 ; is this nil? Beq.S DontClear ; don't clear it MOVE.L D3,-(SP) JSR UpdatePalette ; Get rid of reserved entries, if necessary Move.L D3,A0 ; copy it to an address register AWC.PB457 Move.L (A0),A0 ; dereference it AWC.PB457 BTst #DisposeBit,pmPrivate(A0) ; should we dispose it? AWC.PB457 Beq.S DontClear ; no => leave it alone AWC.PB457 Move.L D3,-(SP) ; push the old handle _DisposePalette ; can you say "bye bye"? I knew you could AWC.PB457 DontClear _ActivatePalette ; set the palette if it happens to be FrontWIndow GoHome MOVE.L (SP)+,D3 Unlk A6 ; clear stack frame Rtd #ParamSize ; strip parameters and go home ;--------------------------------------------------- ; ; FUNCTION GetPalette(srcWindow: WindowPtr) : PaletteHandle; INLINE $AA96; ; GetPalette PROC EXPORT ParamSize equ 4 ; total bytes of params GetResult equ ParamSize+12-4 ; result palette handle srcWindow equ GetResult-4 ; source window to help find the palette VarSize equ 0 ; size of variables Link A6,#VarSize ; build stack frame Clr.L GetResult(A6) ; clear the result handle Move.L PMgrHandle,A1 ; we have to be initialized CmpA.L #PMgrNil,A1 ; is it initialized? Beq.S GoHome ; no => punt Move.L srcWindow(A6),A0 ; get the window pointer CmpA.L #Nil,A0 ; is it real? Beq.S GoHome ; no => punt CmpA.L #-1,A0 ; do they want the system palette? Bne.S NotSystem ; no, not the system Move.L AppPalette,GetResult(A6) ; grab AppPalette; is it nil? AWC.PB457 Bne.S GoHome ; no => we're done AWC.PB457 Move.L (A1),A1 ; dereference PMgrHandle AWC.PB457 Move.L SysPalette(A1),A0 ; get SysPalette AWC.PB457 Move.L A0,D0 ; CmpA.L #Nil,A0; is it nil? AWC.PB457 Beq.S GoHome ; yes => how did this happen? oh well, quit AWC.PB457 _HandToHand ; make a copy of it AWC.PB457 Tst D0 ; did the call succeed? AWC.PB457 Bne.S GoHome ; no => go home with result nil AWC.PB457 Move.L A0,AppPalette ; now we'll use the copy AWC.PB457 Move.L A0,GetResult(A6) ; give them the copy's handle AWC.PB457 Move.L A0,-(SP) ; push the handle for RecordPalette AWC.PB457 Move.L (A0),A0 ; dereference it AWC.PB457 Clr.L pmSeeds(A0) ; kill the copy of the seeds handle AWC.PB457 BClr #DisposeBit,pmPrivate(A0) ; caller must now dispose it AWC.PB457 Jsr RecordPalette ; insert it into our list of known things AWC.PB457 Beq.S GoHome ; scurry out of here AWC.PB457 Clr.L AppPalette ; sorry, it failed AWC.PB457 Clr.L GetResult(A6) ; so clear the result, too AWC.PB457 Bra.S GoHome ; continue AWC.PB457 NotSystem Tst PortBits+RowBytes(A0) ; is it a new port? Bpl.S GoHome ; if not, we're out of here Move.L GrafVars(A0),A0 ; get handle to GrafVars Move.L (A0),A0 ; dereference GrafVars Move.L PmFgColor(A0),A0 ; get the palette AWC.PB457 Move.L A0,GetResult(A6) ; give it to the caller; is it nil? AWC.PB457 Beq.S GoHome ; yes => don't bother with the dispose flag AWC.PB457 Move.L (A0),A0 ; dereference it AWC.PB457 BClr #DisposeBit,PmPrivate(A0) ; turn off the auto dispose AWC.PB457 GoHome Unlk A6 ; clear stack frame Rtd #ParamSize ; strip parameters and go home ;--------------------------------------------------- ; ; PROCEDURE FindIndex; IMMEDIATE; ; ; On entry: ; A2 - Palette pointer ; A3 - ColorInfo ; ; On exit: ; D0 - index of animating entry; 0 if not found (0 is illegal for animation) FindIndex PROC EXPORT MoveM.L D3/D4,-(SP) ; save registers Move ciPrivate(A3),D0 ; get link info BfExtU D0{16:3},D1 ; grab top 3 bits Cmp #4,D1 ; are they set correctly Bne.S BadIndex ; no => the LinkInfo is invalid Move.L PMgrHandle,A0 ; get main handle CmpA.L #PMgrNil,A0 ; is it nil? Beq.S BadIndex ; yes => punt Move.L (A0),A0 ; dereference the palette manager Move nDevs(A0),D3 ; get number of devices to search in D3 Beq.S BadIndex ; no devices => can't animate AWC.PB500 Lea DevHandles(A0),A1 ; point A1 at the device info stuff Bra.S DevEnd ; jump into loop DevLoop Move.L DevHandle(A1,D3.W*8),D4 ; get device handle Cmp.L theGDevice,D4 ; is this it? Beq.S FoundDevice ; yes => continue DevEnd DBra D3,DevLoop ; no => look at another device Bra.S BadIndex ; we fell through - punt FoundDevice Move nDevs(A0),D4 ; get number of devices, this time as a watchdog AddA.L #LinkTabs,A0 ; bump A0 to the base of LinkTabs Bra.S IndexEnd ; start watchdog loop IndexLoop BfExtU D0{19:5},D1 ; grab device number (0..31) BfExtU D0{24:8},D2 ; grab index number (0..255) Cmp D3,D1 ; is it this device? Beq.S FoundIndex ; yes => we've got it Lsl #8,D1 ; calculate offset to link table/4 Add D2,D1 ; offset to entry/4 Move ForeLink(A0,D1.L*4),D0 ; get next link; is the top bit set? Bpl.S BadIndex ; no => stop because we ran out of tries IndexEnd DBra D4,IndexLoop ; examine another index until our watchdog runs out BadIndex Bra.S SetBadIndex ; set index to "illegal" AWC.PB377 ; We found the index. Ensure that we don't exceed the bit depth, set "true" by returning ; a value <> 0. FoundIndex And #$00FF,D2 ; clear everything except the index Move D2,D0 ; set the result AWC.PB377 Move.L theGDevice,A0 ; get theGDevice AWC.PB377 Move.L (A0),A0 ; dereference it AWC.PB377 Move.L gdPMap(A0),A0 ; get handle to pixmap AWC.PB377 Move.L (A0),A0 ; dereference pixmap AWC.PB377 Move.L pmTable(A0),A0 ; get handle to CTab AWC.PB377 Move.L (A0),A0 ; dereference color table AWC.PB377 Cmp ctSize(A0),D0 ; compare link to maximum index AWC.PB377 Blt.S GoHome ; if D0-ctSize <= 0 then cool AWC.PB480 SetBadIndex MoveQ #0,D0 ; set index to "illegal" white AWC.PB377 GoHome MoveM.L (SP)+,D3/D4 ; restore registers Rts ; go home ;--------------------------------------------------- ; ; FUNCTION Entry2Index(srcEntry: INTEGER):LONGINT; AAA2/0 ; ; Return long index of specified entry of thePort's palette, on theGDevice. ; If none, return black, and return a QDErr. ; Mostly, rely on Color2Index to do the picking for us. We'll override its ; choice for an animated or explicit entry on an appropriate device. Entry2Index PROC EXPORT EIVars RECORD {A6Link},DECREMENT result DS.B 4 ;Result: Longword index srcEntry DS.B 2 ;Input: entry in palette of current port return DS.B 4 A6Link DS.B 4 ; old contents of A6 srcPalette DS.B 4 ; The palette we're working on. linkSize DS.B 0 ; linky number ENDR WITH EIVars LINK A6,#linkSize MoveM.L A2-A3,-(SP) ; save registers MOVE #1,QDErr ; Default: error CLR.L result(A6) ; Default: white. Or maybe black. Move.L PMgrHandle,D0 ; get the main handle, are we initialized? Beq GoHome ; no => punt AWC.PB377 Move.L GrafGlobals(A5),A0 ; get the QuickDraw globals pointer Move.L ThePort(A0),A0 ; point at the port Tst PortBits+Rowbytes(A0) ; is it a new port? Bpl GoHome ; no => punt AWC.PB377 Move.L GrafVars(A0),A0 ; get the data handle Move.L (A0),A0 ; dereference it Move.L PmFgColor(A0),A2 ; get the palette handle (finally) Move.L A2,D0 ; CmpA.L #Nil,A2; is there a palette? AWC.PB508 Bne.S FoundAPltt ; yes => we're cool so far AWC.PB508 Move.L AppPalette,A2 ; grab the AppPalette for use AWC.PB508 Move.L A2,D0 ; CmpA.L #Nil,A2; is there an AppPalette AWC.PB508 Beq GoHome ; no => punt AWC.PB508 FoundAPltt Move.L A2,srcPalette(A6) ; save it so we can unlock it AWC.PB520 Move.L A2,A0 ; put the handle into A0 AWC.PB520 _HLock ; lock it down AWC.PB520 Move.L (A2),A2 ; dereference myPalette AWC.PB508 MoveQ #0,D0 ; clear the high word Move srcEntry(A6),D0 ; capture the index Cmp pmEntries(A2),D0 ; D0 - pmEntries; is myEntry out of range? Bhs UnlockPltt ; yes, so we quit AWC.PB520 Asl.L #4,D0 ; multiply by record size of 16 Lea pmInfo(A2,D0.L),A3 ; set A3 to entry's ColorInfo CLR.L -(SP) ; Make room for result Pea ciRGB(A3) ; push address of ciRGB field BTST #animatedBit,ciUsage+1(A3) ; an animated entry? BEQ.S @notAn ; No=>plain color2Index ADDQ.L #1,(SP) ; Yes => use RGB from lo-bytes of ciRGB @notAn _Color2Index ; Get that index MOVE.L (SP)+,result(A6) ; Use that, if nothing else goes well. CLR QDErr ; Well, we got something. Move.L theGDevice,A0 ; get theGDevice Move.L (A0),A0 ; dereference it MOVE.L gdPMap(A0),A1 ; A1 = Pixmap H MOVE.L (A1),A1 ; A1 -> pixmap CMPI #2,pixelSize(A1) ; 1 or two bits deep? BGT.S @b ; No=>don't check pmWhite/Black MOVE ciUsage(A3),D1 ; D1 = usage BTST #whiteBit,D1 ; go White on 1-2 bits? BEQ.S @notWhite ; No=>try black CLR D0 ; Yes=>result color is white. BRA.S ShoveIndex @notWhite BTST #blackBit,D1 ; go Black on 1-2 bits? BEQ.S @a ; No=>check for animated/explicit stuff MOVEQ #-1,D0 ; Yes=>Set all the bits for the index BRA.S inRange ; and trim it to max allowed. @b MOVE gdType(A0),D1 ; get the type BEQ.s @a ; is it a clut device? SUBQ #1,D1 ; fixed type? BNE.S UnlockPltt ; no => we're almost done @a MOVE $14(A3),D0 AND #$8010,D0 BEQ.S UnlockPltt Move ciUsage(A3),D1 ; get flags MoveQ #0,D0 ; clear high word Move srcEntry(A6),D0 ; set D0 in case it is an explicit index BTst #AnimatedBit,D1 ; no => test animation bit Beq.S checkExplct ; if not, maybe explicit AWC.PB520 Jsr FindIndex ; uses our registers - put reserved index in D0 Tst D0 ; was the result "white"? Beq.S UnlockPltt ; yes => give up Bra.S ShoveIndex ; share common code checkExplct BTST #ExplicitBit,D1 ; BEQ.S UnlockPltt ; BTST #TolerantBit,D1 ; If we're explicit+tolerant, go with Color2Index. BNE.S UnlockPltt ; After all, ActivatePalÉ tried to get it for us. inRange Move.L gdPMap(A0),A0 ; get handle to pixmap Move.L (A0),A0 ; dereference pixmap Move.L pmTable(A0),A0 ; get handle to CTab Move.L (A0),A0 ; dereference color table And ctSize(A0),D0 ; and D0 with maximum index ShoveIndex Move.L D0,result(A6) ; jam the index AWC.PB377 UnlockPltt Move.L SrcPalette(A6),A0 ; get whichever palette we used AWC.PB520 _HUnlock ; unlock it AWC.PB520 GoHome MoveM.L (SP)+,A2-A3 ; restore register Unlk A6 ; clear stack frame Rtd #result-return-4 ; strip parameters and go home ;--------------------------------------------------- ; ; PROCEDURE Index2Entries(srcIndex: LONGINT; results:HANDLE):LONGINT; ; ; resize the handle, and return it filled with a list of INTEGERs. The first ; integer is the count, and the rest are the entries in the current port's ; palette that would match to the specified index. Index2Entries PROC EXPORT IEVars RECORD {A6Link},DECREMENT result DS.B 0 ;Result: none srcIndex DS.B 2 ;Input: entry in palette of current port results DS.B 4 ;Input: any old handle return DS.B 4 A6Link DS.B 4 ; old contents of A6 linkSize DS.B 0 ; linky number ENDR WITH IEVars LINK A6,#linkSize MOVEM.L D3-D7/A2,-(SP) Move.L GrafGlobals(A5),A0 ; get the QuickDraw globals pointer Move.L ThePort(A0),D0 ; point at the port BEQ.S @goHome ; No port set? SUBQ #4,SP MOVE.L D0,-(SP) _GetPalette ; Get the current palette MOVE.L (SP)+,D0 ; Get something? BEQ.S @goHome MOVE.L D0,A0 MOVE.L (A0),A0 MOVE pmEntries(A0),D4 ; D4 = number of entries in palette MOVE.L results(A6),D0 ; Get handle to return stuff in BEQ.S @goHome ; A problem, to be sure. MOVEA.L D0,A0 _HGetState MOVE.B D0,D3 ; D3 = previous state of their handle _HNoPurge _HUnlock MOVE D4,D0 ; D0 = number of entries in palette ADD D0,D0 ; D0 = twice number of palette entries ADDQ #2,D0 EXT.L D0 ; D0 = the biggest handle we'd need _SetHandleSize ; Now, A0 is the right sized handle _HLock MOVE.L (A0),A2 ; A2-> where everything will go. CLR.L D5 ; D5 = number of entries we've found MOVE.L srcIndex(A6),D6 ; D6 = index we're looking for BRA.S @scanEnd @scanLoop SUBQ #4,SP ; Space for long result index MOVE D4,-(SP) _Entry2Index CMP.L (SP)+,D6 ; Does this entry match our index? BNE.S @scanEnd ADDQ #1,D5 ; Found one more... MOVE D4,(A2,D5*2) ; Put the entry into the list o' entries @scanEnd DBRA D4,@scanLoop MOVE.L results(A6),A0 MOVE.L D5,D0 ADD.L D0,D0 ADDQ.L #2,D0 _SetHandleSize MOVE.B D3,D0 _HSetState @goHome MOVEM.L (SP)+,D3-D6/A2 UNLK A6 RTD #result-return-4 ;--------------------------------------------------- ; ; PROCEDURE PmForeColor(srcEntry: INTEGER); INLINE $AA97; ; PmForeColor PROC EXPORT EXPORT PmBackColor PCVars RECORD {A6Link},DECREMENT result DS.B 0 ;Result: none srcEntry DS.B 2 ;Input: entry in palette of current port return DS.B 4 A6Link DS.B 4 ; old contents of A6 callType DS.B 2 ; Fore- or Back- call linkSize DS.B 0 ; linky number ENDR WITH PCVars ;PmForeColor MoveQ #1,D0 ; we're coming from PmForeColor Bra.S PmSetColor ; share code PmBackColor MoveQ #0,D0 ; we're coming from PmBackColor PmSetColor Link A6,#linkSize ; build stack frame Move D0,callType(A6) ; save the type of call CLR.L -(SP) ; Room for result MOVE srcEntry(A6),-(SP) ; Push the entry input _Entry2Index ; Find a good index for it MOVE.L (SP)+,D0 ; Get index (if any) into D0 TST QDErr ; Found one? BNE.S GoHome ; No, skip it. Move.L GrafGlobals(A5),A0 ; get the QuickDraw globals pointer Move.L ThePort(A0),A0 ; point at the port MOVE.L GrafVars(A0),A1 ; A1 = Grafvars handle MOVE.L (A1),A1 ; A1->Grafvars MOVE.L D0,-(SP) ; Push index for Index2Color Tst callType(A6) ; foreground? AWC.PB377 Beq.S SetBackgrnd ; no => set background AWC.PB377 Move.L D0,FgColor(A0) ; jam the index Move srcEntry(A6),PmFgIndex(A1) ; save the entry number BSet #PmFgBit,PmFlags+1(A1) ; tell the world that we set the FgColor PEA rgbFgColor(A0) ; Push address of color result o' Index2Color Bra.S ToColor ; continue AWC.PB377 SetBackgrnd Move.L D0,BkColor(A0) ; jam the index AWC.PB377 Move srcEntry(A6),PmBkIndex(A1) ; save the entry number BSet #PmBkBit,PmFlags+1(A1) ; tell the world that we set the BkColor PEA rgbBkColor(A0) ; Push address of color result o' Index2Color ToColor _Index2Color ; Give port rgb color from index result GoHome Unlk A6 ; clear stack frame Rtd #result-return-4 ; strip parameters and go home ;--------------------------------------------------- ; ; PROCEDURE AnimateEntry(dstWindow: WindowPtr; dstEntry: INTEGER; srcRGB: RGBColor); INLINE $AA99; ; AnimateEntry PROC EXPORT ParamSize equ 10 ; total bytes of params dstWindow equ ParamSize+8-4 ; target window dstEntry equ dstWindow-2 ; palette entry to animate srcRGB equ dstEntry-4 ; new color to use SaveGDevice equ -4 ; room for saving theGDevice Mc equ SaveGDevice-6 ; RGBColor OldSeed equ Mc-4 ; old color table seed VarSize equ OldSeed ; size of the variables Link A6,#VarSize ; build stack frame MoveM.L D3-D5/A2-A4,-(SP) ; save registers Move.L PMgrHandle,A3 ; get the main handle CmpA.L #PMgrNil,A3 ; are we initialized? Beq GoHome ; no => punt AWC.PB377 Move.L dstWindow(A6),A0 ; get the target window CmpA.L #Nil,A0 ; is it nil? Beq GoHome ; yes => we're done AWC.PB377 Tst PortBits+Rowbytes(A0) ; is it a new port? Bpl GoHome ; no => punt AWC.PB377 Move.L GrafVars(A0),A0 ; get the data handle Move.L (A0),A0 ; dereference it Move.L PmFgColor(A0),A2 ; get the palette handle (finally) Move.L A2,D0 ; CmpA.L #Nil,A2; is there a palette? AWC.PB508 Bne.S FoundAPltt ; yes => use it AWC.PB508 Move.L AppPalette,A2 ; look for an AppPalette AWC.PB508 Move.L A2,D0 ; CmpA.L #Nil,A2; is there an AppPalette? AWC.PB508 Beq GoHome ; no => punt AWC.PB377 FoundAPltt Move.L (A2),A0 ; dereference the palette AWC.PB508 Move pmEntries(A0),D0 ; get the number of entries MoveQ #0,D1 ; clear high word Move dstEntry(A6),D1 ; get the index Cmp D0,D1 ; is the index in range? Bhs GoHome ; no => we're done AWC.PB377 Lsl #4,D1 ; multiply by ciSize Lea pmInfo(A0,D1.L),A2 ; point A2 at the entry ; BTst #ExplicitBit,ciUsage+1(A2) ; is it explicit? ; Bne GoHome ; yes => by definition not animating BTst #AnimatedBit,ciUsage+1(A2) ; is it animating? Beq GoHome ; no => quit ; Copy the colors to the palette before we check to see if we have links or not so that it ; will get copied even if we have no 'clut' devices Move.L srcRGB(A6),A0 ; get pointer to his RGB AWC.PB500 Move.L red(A0),D0 ; copy red and green AWC.PB500 Move.L D0,mc+red(A6) ; save red and green on the stack AWC.PB500 ROR.L #8,D0 ; Get at upper bytes of colors MOVE.b d0,ciRGB+green(A2) ; Only store high byte (lo is SetColor SWAP D0 ; get at red byte MOVE.B D0,ciRGB+red(A2) ; Only store high byte (lo is SetColor Move blue(A0),D0 ; copy blue AWC.PB500 Move D0,mc+blue(A6) ; save blue on the stack AWC.PB500 ROR #8,D0 ; get at significant byte of blue MOVE.B D0,ciRGB+blue(A2) ; Only store high byte (lo is SetColor Move ciPrivate(A2),D3 ; get the ForeLink field BfExtu D3{16:3},D1 ; get the key bits Cmp #4,D1 ; were they 100? Bne GoHome ; no => not a valid ForeLink; go home ; Now, finally, we have something to do. Let's follow those links and see where they take us Move.L A3,A0 ; copy PMgrHandle _HLock ; lock it down Move.L theGDevice,SaveGDevice(A6) ; save it ; Register usage: ; ; D0 : holds ForeLink temporarily ; D3 : holds device number ; D4 : holds index number ; D5 : watchdog loop counter ; ; A2 : base address of LinkTabs ; A3 : PMgrHandle (locked) ; A4 : base address of DevHandles Move.L (A3),A2 ; dereference PMgrHandle Move nDevs(A2),D5 ; maximum number of devices (watchdog counter) Lea DevHandles(A2),A4 ; point A4 at the device list AddA.L #LinkTabs,A2 ; point A2 at start of LinkTabs Move D3,D0 ; copy ForeLink into D0 Bra.S DevEnd ; jump into the loop DevLoop BfExtU D0{19:5},D3 ; grab device number (0..31) BfExtU D0{24:8},D4 ; grab index number (0..255) Move.L DevHandle(A4,D3.W*8),A0 ; get the device handle Move.L A0,theGDevice ; now we're on that device Move.L (A0),A0 ; dereference it Clr gdId(A0) ; no client id's, please Move.L gdPMap(A0),A0 ; get handle to pixmap Move.L (A0),A0 ; dereference pixmap Move.L pmTable(A0),A0 ; get handle to CTab Move.L (A0),A0 ; dereference CTab Move ctSize(A0),D0 ; grab number of entries - 1 Cmp D4,D0 ; compare our index to the max index Ble.S NextDevice ; out of range => look at next device AWC.PB480 Move.L ctSeed(A0),OldSeed(A6) ; save the seed so we can restore it Move.L mc+red(A6),ctTable+RGB+red(A0,D4.W*8) Move mc+blue(A6),ctTable+RGB+blue(A0,D4.W*8) ; Now perform a sequential _SetEntries using the device's color table as the source MOVE D4,-(SP) ; push D4 = Index for SetEntries CLR -(SP) ; push number of entries-1 = 1 Pea ctTable(A0,D4*8) ; push address of the first ColorSpec _SetEntries ; do it Move.L theGDevice,A0 ; get the device again Move.L (A0),A0 ; dereference it Move.L gdPMap(A0),A0 ; get handle to pixmap Move.L (A0),A0 ; dereference pixmap Move.L pmTable(A0),A0 ; get handle to CTab Move.L (A0),A0 ; dereference CTab Move.L OldSeed(A6),ctSeed(A0) ; we didn't really want it to change NextDevice Lsl #8,D3 ; calculate offset to link table/4 Add D4,D3 ; offset to entry/4 Move ForeLink(A2,D3.L*4),D0 ; get next link; is the top bit set? AWC.PB500 DevEnd DBpl D5,DevLoop ; keep going until D0 is positive or D5 runs out Move.L SaveGDevice(A6),theGDevice ; restore theGDevice Move.L A3,A0 ; copy PMgrHandle _HUnlock ; unlock it GoHome MoveQ #0,D0 ; no error AWC.PB377 MoveM.L (SP)+,D3-D5/A2-A4 ; restore registers Unlk A6 ; clear stack frame Rtd #ParamSize ; strip parameters and go home ;--------------------------------------------------- ; ; PROCEDURE AnimatePalette(dstWindow:WindowPtr; srcCTab: CTabHandle; srcIndex, ; dstEntry,dstLength: INTEGER; INLINE $AA9A; ; AnimatePalette PROC EXPORT ParamSize equ 14 ; total bytes of params dstWindow equ ParamSize+8-4 ; window to animate srcCTab equ dstWindow-4 ; new source colors srcIndex equ srcCTab-2 ; first source entry to use dstEntry equ srcIndex-2 ; first destination entry to set dstLength equ dstEntry-2 ; how many to set SaveGDevice equ -4 ; room for saving theGDevice SaveSeed equ SaveGDevice-4 ; old color table seed NumDev equ SaveSeed-2 ; copy of nDevs DevCTabH equ NumDev-DevLimit*4 ; enough room for a CTabHandle per device VarSize equ DevCTabH ; size of the variables Link A6,#VarSize ; build stack frame MoveM.L D3-D6/A2-A4,-(SP) ; save registers Move.L PMgrHandle,A4 ; get the main handle CmpA.L #PMgrNil,A4 ; are we initialized? Beq GoHome ; no => punt AWC.PB377 Move.L dstWindow(A6),A0 ; get the target window CmpA.L #Nil,A0 ; is it nil? Beq GoHome ; yes => we're done AWC.PB377 Tst PortBits+Rowbytes(A0) ; is it a new port? Bpl GoHome ; no => punt AWC.PB377 Move.L GrafVars(A0),A0 ; get the data handle Move.L (A0),A0 ; dereference it Move.L PmFgColor(A0),A2 ; get the palette handle (finally) Move.L A2,D0 ; CmpA.L #Nil,A2; is there a palette? AWC.PB508 Bne.S FoundAPltt ; yes => use it AWC.PB508 Move.L AppPalette,A2 ; look for an AppPalette AWC.PB508 Move.L A2,D0 ; CmpA.L #Nil,A2; is there an AppPalette? AWC.PB508 Beq GoHome ; no => punt AWC.PB508 FoundAPltt Move.L srcCTab(A6),A3 ; get source color table AWC.PB508 Move.L A3,D0 ; CmpA.L #Nil,A3; is it nil? AWC.PB508 Beq GoHome ; yes => again punt AWC.PB377 Move.L (A2),A2 ; dereference the palette Move pmEntries(A2),D0 ; get the number of entries; are there any? Beq GoHome ; no => still punt AWC.PB377 MoveQ #0,D3 ; clear high word (so we can Lsl.L later) Move dstEntry(A6),D3 ; get the starting index Cmp D0,D3 ; is the start after the end? Bhs GoHome ; yes => keep punting Move.L (A3),A3 ; dereference the color table Move srcIndex(A6),D4 ; get the starting index Cmp ctSize(A3),D4 ; is the starting index within range? Bhi GoHome ; no => once more, punt ; We have something worth copying! Now we can determine the length of the copy and ; place it in D5. Sub D3,D0 ; calculate maximum length of a palette copy Move D0,D5 ; save it in D5 Move ctSize(A3),D0 ; fetch the length of the color table AddQ #1,D0 ; add 1 to make it 1-based Sub D4,D0 ; calculate maximum length of a CTab copy Cmp D0,D5 ; is D5 too big? Bls.S NotTooBig ; no => don't replace it Move D0,D5 ; copy smaller value to D5 NotTooBig Cmp dstLength(A6),D5 ; is D5 bigger than the request? Bls.S StillOkay ; no => leave it alone Move dstLength(A6),D5 ; copy smaller value to D5 StillOkay Move.L (A4),A1 ; dereference the palette manager handle Move nDevs(A1),D0 ; put number of devices into D0 Move D0,NumDev(A6) ; remember number of devices Lea DevHandles(A1),A4 ; point A4 at the clut device list AWC Lea DevCTabH(A6),A0 ; point A0 at our temporary table AWC Bra.S ClearEnd ; jump into loop ClearLoop Clr.L (A0)+ ; clear room for a handle AWC ClearEnd DBra D0,ClearLoop ; continue for nDevs devices AWC AddA.L #LinkTabs,A1 ; bump A1 to the link tables Lsl.L #4,D3 ; multiply D3 by ciSize Lea pmInfo(A2,D3.L),A2 ; bump A2 to first ColorInfo Lea ctTable(A3,D4.W*8),A3 ; bump A3 to first ColorSpec Bra EntryEnd ; jump into loop EntryLoop BTst #AnimatedBit,ciUsage+1(A2) ; is it animating? Beq NextEntry ; no => continue MOVE.b RGB+red(A3),ciRGB+red(A2) ; red hi into our hibyte MOVE.b RGB+green(A3),ciRGB+green(A2) ; green hi into our hibyte MOVE.b RGB+blue(A3),ciRGB+blue(A2) ; blue hi into our hibyte Move ciPrivate(A2),D0 ; get the ForeLink field BfExtu D0{16:3},D1 ; get the key bits Cmp #4,D1 ; were they 100? Bne.S NextEntry ; no => not a valid ForeLink; go home Move NumDev(A6),D6 ; get maximum number of devices to examine SubQ #1,D6 ; decrement by 1 so we may fall through ; We fall through because the usual trick of branching to the end won't work when the ; end is a DBpl, not a DBf (DBra). DevLoop BfExtU D0{19:5},D3 ; grab device number (0..31) BfExtU D0{24:8},D4 ; grab index number (0..255) Lea DevCTabH(A6),A0 ; point A0 at temporary table Move.L (A0,D3.W*4),A0 ; get CTabHandle CmpA.L #Nil,A0 ; have we seen this device yet? Bne.S SeenDevice ; yes => skip setup Move.L DevHandle(A4,D3.W*8),A0 ; get the device handle Move.L (A0),A0 ; dereference it Clr gdId(A0) ; no client id's, please Move.L gdPMap(A0),A0 ; get handle to pixmap Move.L (A0),A0 ; dereference pixmap Move.L pmTable(A0),D0 ; get handle to CTab Lea DevCTabH(A6),A0 ; point A0 at temporary table Move.L D0,(A0,D3.W*4) ; save it for later Move.L D0,A0 ; copy CTabHandle back into A0 AWC PB223 SeenDevice Move.L (A0),A0 ; dereference CTab Move ctSize(A0),D0 ; grab number of entries - 1 Cmp D4,D0 ; compare our index to the max index Ble.S NextDevice ; out of range => look at next device AWC.PB480 Move.W ciRGB+red(A2),ctTable+RGB+red(A0,D4.W*8) ; Move.W ciRGB+green(A2),ctTable+RGB+green(A0,D4.W*8) ; Move.W ciRGB+blue(A2),ctTable+RGB+blue(A0,D4.W*8) ; NextDevice Lsl #8,D3 ; calculate offset to link table/4 Add D4,D3 ; offset to entry/4 Move ForeLink(A1,D3.L*4),D0 ; get next link; is the top bit set? DevEnd DBpl D6,DevLoop ; keep going until D0 is positive or D5 runs out NextEntry AddA.L #ciSize,A2 ; bump A2 to next ColorInfo AddA.L #ColorSpecSize,A3 ; bump A3 to next ColorSpec EntryEnd DBra D5,EntryLoop ; continue for all animating entries Move.L theGDevice,SaveGDevice(A6) ; save the old GDevice Move NumDev(A6),D6 ; get number of devices to examine Lea DevCTabH(A6),A2 ; point A2 at our temporary table Bra.S SetEnd ; jump into loop SetLoop Move.L (A2)+,A3 ; get next CTabHandle CmpA.L #Nil,A3 ; did we initialize it? Beq.S NextSet ; no => continue Move.L DevHandle(A4),theGDevice ; put us on that device Move.L (A3),A0 ; dereference it Move.L ctSeed(A0),SaveSeed(A6) ; save the current seed Clr -(SP) ; push starting count of 0 for SetEntries Move ctSize(A0),-(SP) ; push number of entries-1 Pea ctTable(A0) ; push address of the first ColorSpec _SetEntries ; do it Move.L (A3),A0 ; dereference CTab again Move.L SaveSeed(A6),ctSeed(A0) ; put the old seed back into place NextSet AddQ.L #DevInfoSz,A4 ; bump A4 to the next device SetEnd DBra D6,SetLoop ; loop for all devices Move.L SaveGDevice(A6),theGDevice ; restore the old GDevice GoHome MoveQ #0,D0 ; clear error condition AWC.PB377 MoveM.L (SP)+,D3-D6/A2-A4 ; rsstore registers Unlk A6 ; clear stack frame Rtd #ParamSize ; strip parameters and go home ;--------------------------------------------------- ; ; PROCEDURE GetEntryColor(srcPalette: PaletteHandle; srcEntry: INTEGER; VAR dstRGB: RGBColor); ; INLINE $AA9B; ; GetEntryColor PROC EXPORT ParamSize equ 10 ; total bytes of params srcPalette equ ParamSize+8-4 ; source Palette handle srcEntry equ srcPalette-2 ; entry to get dstRGB equ srcEntry-4 ; where to put color VarSize equ 0 Link A6,#VarSize ; build stack frame Move.L srcPalette(A6),A0 ; get palette CmpA.L #Nil,A0 ; is it nil? Beq.S GoHome ; yes => punt AWC.PB377 Move.L (A0),A0 ; dereference it Move pmEntries(A0),D0 ; get the number of entries MoveQ #0,D1 ; clear high word Move srcEntry(A6),D1 ; get the index Cmp D0,D1 ; is the index in range? Bhs.S GoHome ; no => we're done AWC.PB377 Lsl.L #4,D1 ; multiply by number of records Lea pmInfo(A0,D1.L),A0 ; point A0 at the correct ColorInfo Move.L dstRGB(A6),A1 ; get the destination Move.L ciRGB+red(A0),red(A1) ; copy red and green Move ciRGB+blue(A0),blue(A1) ; copy blue GoHome MoveQ #0,D0 ; clear error condition Unlk A6 ; clear stack frame Rtd #ParamSize ; strip parameters and go home ;--------------------------------------------------- ; ; PROCEDURE ScatterDevices(SetEm:Boolean); Local; ; ; Here is the long awaited ScatterDevices, which gives animated entries back to ; the world in a socially acceptable manner. The default clut for the device ; is used to fill in those entries of the device's clut marked with bit 4, ; the ctScatterBit. Then, the bits for those devices with new colors is set in ; the updateDevs bitmask of PMgrHandle. ; We restore all registers. ScatterDevices PROC EXPORT SDVars RECORD {A6Link},DECREMENT result DS.B 0 ;Result: none SetEm DS.B 2 ;Input: boolean, to set the entries really return DS.B 4 A6Link DS.B 4 ;old contents of A6 linkSize DS.B 0 ;linky number ENDR WITH SDVars LINK A6,#linkSize MOVEM.L A0/A2-A4/D1-D5,-(SP) ; Save some regs MOVE.L PMgrHandle,A0 MOVE.L (A0),A0 ; A0 -> PMgr data MOVE.L scatterDevs(A0),D4 ; D4 = bitmask of devices needing scattering BEQ GoHome ; What? No scattering? CLR.L scatterDevs(A0) ; We'll scatter these OR.L D4,updateDevs(A0) ; So mark them for updating MOVE nDevs(A0),D3 ; D3 = number of devices to check SUBQ #1,D3 ; less one (we've got _one_ device, right?) LEA DevHandles(A0),A2 ; A2 -> list of devices ScatterLoop BTST D3,D4 ; Do this device? BEQ ScatterEnd ; No=> skip some stuff SUBQ #4,SP ; space for result MOVE.L DevHandle(A2,D3*8),A3 ; A3 = device handle MOVE.L A3,-(SP) ; push device handle JSR GetClut ; get us a handle MOVE.L (SP)+,A4 ; Keep copy on stack MOVE.L (A4),A4 ; A4-> system color table for that depth MOVE.L ctSeed(A4),D2 ; D2 = system seed for that depth LEA ctTable+rgb(A4),A4 ; A4-> rgb of first color entry MOVE.L (A3),A3 ; A3->gDevice MOVE.L gdPMap(A3),A3 ; A3 = pixmaphandle MOVE.L (A3),A3 ; A3->pixmap MOVE.L pmTable(A3),A3 ; A3 = our color table H MOVE.L (A3),A3 ; A3-> our color table MOVE ctSize(A3),D1 LEA ctTable(A3),A0 ; A0->value of colorspec 0 CLR D5 ; No elements scattered EntryLoop BTST #ctMatchBit,value(A0) ; Is this entry looked at? BEQ.S CheckScat ; No=>check next one ADDQ #1,D5 ; Count number of unreserved entries CheckScat BTST #ctScatterBit,value(A0) ; Is the scatterbit on? BEQ.S EntryEnd ; No=>check next one CLR value(A0) ; Mark it as unreserved, scattered, etc. MOVE.L red(A4),rgb+red(A0) ; Move red and green component from system clut MOVE blue(A4),rgb+blue(A0) ; Move blue from system clut EntryEnd ADDQ #8,A0 ; Bump A0 to next color entry ADDQ #8,A4 ; Bump A4 to next color entry DBRA D1,EntryLoop MOVE.L DevHandle(A2,D3*8),A4 ; A4 = device handle CMP ctSize(A3),D5 ; Is every entry in place as in default? BLE.S NewSeed ; No=>give cTab a new seed MOVE.L D2,ctSeed(A3) ; Yes=>we get system seed here MOVE.L (A4),A0 ; A0->gDevice MOVE.L gdITable(A0),A0 ; A0 = Inverse table handle MOVE.L (A0),A0 ; A0-> ITable CLR.L (A0) ; Change ITab seed instead! BRA.S MaybeSet NewSeed SUBQ #4,SP ; Space for result _GetCTSeed ; Get us a new seed MOVE.L (SP)+,ctSeed(A3) ; And give it a new seed. MaybeSet TST SetEm(A6) ; So, do we actually update the device? BEQ.S ScatterEnd ; No=>do next device MOVE.L A4,A0 ; Put gDev handle in A0 JSR DevSetEntries ; And put entries into HW clut, w/o changing seed. ScatterEnd DBRA D3,ScatterLoop GoHome MOVEM.L (SP)+,A0/A2-A4/D1-D5 UNLK A6 RTD #result-return-4 ;--------------------------------------------------- ; ; PROCEDURE SetDev; LOCAL; ; ; Renders or allocates myPalette as appropriate for the given device. If myPalette ; is polite it accumulates reference counts. If it is intolerant it assigns indexes ; according to closest match and makes these colors available in the color table. If ; it is adamant (animated) it chooses indexes according to lowest reference counts ; and reserves the entries on the device (setting the reserve bit). ; ; This function uses the stack frame built upon A6 and builds its own stack frame on A4. PROC EXPORT SetDev OldPort equ -8 ; a place to stuff the port while we InvalRect SysUpdates equ OldPort-2 ; flag that tells whether the system wants updates OldUpdates equ SysUpdates-2 ; flag => 1 if Old Quickdraw colors got changed AWC VarSize equ OldUpdates ; number of bytes of variables AWC PB223 DepthBits DC.B 8,9,10,11,0,0,12,13 ; Inhibit bits for different depths/grays ; (depth) 2 2 4 4 8 8 ; (color?) n y n y n y SetDev Link A4,#VarSize ; build stack frame MoveM.L D3-D5/A2-A3,-(SP) ; save registers ; Grab the device handle and shove it into theGDevice Move CurDevice(A6),D3 ; get device offset Move.L PDevPtr(A6),A0 ; get pointer to internal list of devices Move.L (A0,D3.W*8),A0 ; get the device handle Move.L A0,theGDevice ; set theGDevice ; Removed code that calculated device info - see CalcDevs below AWC PB223 Move.L (A0),A0 ; dereference it TST gdType(A0) ; is it CLUT type (zero)? dvb1 BNE GoHome ; No => do nothing MOVE $14(A0),D0 AND #$8010,D0 BEQ GoHome ; No=>go home Move.L gdPMap(A0),A0 ; get handle to pixmap Move.L (A0),A0 ; dereference pixmap Move.L pmTable(A0),A0 ; get handle to CTab Move.L A0,DevCTab(A6) ; save color table handle, too Move.L (A0),A0 ; dereference CTab Move ctSize(A0),D0 ; grab number of entries - 1 Move D0,BlackIndex(A6) ; save it AddQ #1,D0 ; bump it to number of entries Move D0,DevIndexes(A6) ; save the number of indexes, too ; Compare the palette's seed for this device to the ctSeed belonging to the ; device. If they match, no environment or palette change has occurred. The routines ; which modify palettes make sure that the appropriate seed fields get changed. If ; the user modifies the palette herself, she must take responsibility for changing ; the seeds accordingly. Move.L ctSeed(A0),D0 ; read the current device seed Move.L PalettePtr(A6),A0 ; get the Palette pointer BTst #DirtyBit,pmPrivate(A0) ; does it need an update anyway? Bne.S DirtyBird ; yes => activate it anyway Move.L pmSeeds(A0),A0 ; get the handle to the seeds Move.L (A0),A0 ; dereference it Cmp.L (A0,D3.W*4),D0 ; does the Palette's seed match the device's? Beq GoHome ; yes => skip this whole mess ; Set up some useful pointers DirtyBird Move.L PDevPtr(A6),A0 ; get pointer to internal list of devices Lea (A0,D3.W*8),A0 ; point A0 at the device entry Move.L PMgrPtr(A6),A0 ; copy base pointer AddA.L #LinkTabs,A0 ; add offset to first link table Move D3,D0 ; get the device number (0..31) Lsl #8,D0 ; multiply by link table size (max 31*1024) Lea (A0,D0.W*4),A0 ; point A0 at link table Move.L A0,DevLinks(A6) ; save pointer to device links table ; Set Updates to 0 so we'll know if a SetEntries is necessary. Make a copy ; of ciUsage flags in ciFlags. Clr Updates(A6) ; clear number of updates to CTab we've done MOVE.L TheGDevice,A0 ; A0 = Current device handle MOVE.L (A0),A0 ; A0->Current device MOVE gdFlags(A0),D3 ; D3 = gDev's flags AND #1,D3 ; D3 = 0:b/w or 1:color MOVE.L gdPMap(A0),A0 ; A0 = current device pixmap MOVE.L (A0),A0 ; A0->current device pixmap ADD pmPixelSize(A0),D3 ; D3 = pixeldepth, +1 if color LEA depthBits-2,A0 MOVE.B (A0,D3.W),D3 ; D3 = bit of ciUsage to test for inhibit on this gDev Move myEntries(A6),D0 ; get myPalette^^.pmEntries Move.L PalettePtr(A6),A0 ; get the pointer to the palette Lea pmInfo(A0),A0 ; bump it to the first ColorInfo Bra.S InitEnd ; jump into the fray InitLoop Move ciUsage(A0),D1 ; D1 = usage flags, plus global HandledBit BTST D3,D1 ; Inhibit on this device? BEQ.S @noInhib BSET #handledBit,D1 ; Yes, just mark as "handled" @noInhib MOVE D1,ciFlags(A0) ; copy ciUsage to ciFlags AddA.L #ciSize,A0 ; bump A0 to the next ColorInfo InitEnd DBra D0,InitLoop ; loop for pmEntries JSR AnalyzeDev ; Make list of device indices to grab Jsr PMAllocate ; Get animated entries Jsr Correlate ; Get tolerant entries ; Now we are ready to set some colors (for real, man!). We have been changing colors ; in the device's color table all along. Now we just need to promulgate them through ; to the device with a sequential SetEntries call, but only if Updates is greater than ; zero. In order to make the call we have to unprotect each color and set it's client ; id to "none". Then we do the SetEntries call, after which we restore the protection ; and client id (255) of all colors. Next we copy the seed from the device color table ; to the palette so we'll know we've been here. Finally we generate update events for ; all windows of palettes which have been rendered on this device, including of course ; the current palette. CheckUpdate TST Updates(A6) BEQ.S FixSeeds JSR MarkDevUBit FixSeeds Move.L DevCTab(A6),A0 ; get color table Move.L (A0),A0 ; dereference it Move.L ctSeed(A0),D0 ; read the current device seed Move.L PalettePtr(A6),A0 ; get the Palette pointer Move.L pmSeeds(A0),A1 ; get the handle to the seeds Move.L (A1),A1 ; dereference it Move CurDevice(A6),D3 ; get device number back Move.L D0,(A1,D3.W*4) ; update the Palette's seed GoHome MoveQ #0,D0 ; clear error condition AWC.PB377 MoveM.L (SP)+,D3-D5/A2-A3 ; restore registers Unlk A4 ; clear stack frame Rts ; strip parameters and go home ;--------------------------------------------------- ; ; PROCEDURE SetEntryColor(dstPalette: PaletteHandle; dstEntry: INTEGER; srcRGB: RGBColor); ; INLINE $AA9C; ; SetEntryColor PROC EXPORT ParamSize equ 10 ; total bytes of params dstPalette equ ParamSize+8-4 ; source Palette handle dstEntry equ dstPalette-2 ; entry to set srcRGB equ dstEntry-4 ; new color VarSize equ 0 Link A6,#VarSize ; build stack frame Move.L dstPalette(A6),A0 ; get palette CmpA.L #Nil,A0 ; is it nil? Beq.S GoHome ; yes => punt AWC.PB377 Move.L (A0),A0 ; dereference it Move pmEntries(A0),D0 ; get the number of entries MoveQ #0,D1 ; clear high word Move dstEntry(A6),D1 ; get the index Cmp D0,D1 ; is the index in range? Bhs.S GoHome ; no => we're done AWC.PB377 Lsl.L #4,D1 ; multiply by number of records Lea pmInfo(A0,D1.L),A0 ; point A0 at the correct ColorInfo Move.L srcRGB(A6),A1 ; A1->source Move.L red(A1),ciRGB+red(A0) ; copy red and green, Move blue(A1),ciRGB+blue(A0) ; copy blue BTST #animatedBit,ciUsage+1(A0) ; Is it animated? BEQ.S @notAni ; No=> don't replicate bytes LEA ciRGB(A0),A0 ; (A nop, I think) MOVE.B (A0)+,(A0)+ ; we replicate the high bytes MOVE.B (A0)+,(A0)+ ; of each component into the low bytes MOVE.B (A0)+,(A0)+ @notAni Move.L dstPalette(A6),-(SP) ; push the palette handle AWC.PB508 Bsr DirtySeeds ; clear the device seeds AWC.PB508 GoHome MoveQ #0,D0 ; clear error condition AWC.PB377 Unlk A6 ; clear stack frame Rtd #ParamSize ; strip parameters and go home ;--------------------------------------------------- ; ; PROCEDURE GetEntryUsage(srcPalette: PaletteHandle; srcEntry: INTEGER; VAR dstUsage, ; dstTolerance: INTEGER); INLINE $AA9D; ; GetEntryUsage PROC EXPORT ParamSize equ 14 ; total bytes of params srcPalette equ ParamSize+8-4 ; source Palette handle srcEntry equ srcPalette-2 ; entry number dstUsage equ srcEntry-4 ; where to put usage dstTolerance equ dstUsage-4 ; where to put tolerance VarSize equ 0 Link A6,#VarSize ; build stack frame Move.L srcPalette(A6),A0 ; get palette CmpA.L #Nil,A0 ; is it nil? Beq.S GoHome ; yes => punt AWC.PB377 Move.L (A0),A0 ; dereference it Move pmEntries(A0),D0 ; get the number of entries MoveQ #0,D1 ; clear high word Move srcEntry(A6),D1 ; get the index Cmp D0,D1 ; is the index in range? Bhs.S GoHome ; no => we're done AWC.PB377 Lsl.L #4,D1 ; multiply by number of records Lea pmInfo(A0,D1.L),A0 ; point A0 at the correct ColorInfo Move.L dstUsage(A6),A1 ; get the destination Move ciUsage(A0),(A1) ; copy usage Move.L dstTolerance(A6),A1 ; get the second destination Move ciTolerance(A0),(A1) ; copy tolerance GoHome MoveQ #0,D0 ; clear error condition AWC.PB377 Unlk A6 ; clear stack frame Rtd #ParamSize ; strip parameters and go home ;--------------------------------------------------- ; ; PROCEDURE SetEntryUsage(dstPalette: PaletteHandle; dstEntry,srcUsage,srcTolerance: INTEGER); ; INLINE $AA9E; ; SetEntryUsage PROC EXPORT IMPORT ClearStrand ParamSize equ 10 ; total bytes of params dstPalette equ ParamSize+8-4 ; source Palette handle dstEntry equ dstPalette-2 ; entry number srcUsage equ dstEntry-2 ; new usage srcTolerance equ srcUsage-2 ; new tolerance VarSize equ 0 Link A6,#VarSize ; build stack frame MOVEM.L A2-A4/D3-D4,-(SP) ; save regs Move.L dstPalette(A6),A0 ; get palette CmpA.L #Nil,A0 ; is it nil? Beq.S GoHome ; yes => punt AWC.PB377 Move.L (A0),A0 ; dereference it Move pmEntries(A0),D0 ; get the number of entries MoveQ #0,D1 ; clear high word Move dstEntry(A6),D1 ; get the index Cmp D0,D1 ; is the index in range? Bhs.S GoHome ; no => we're done AWC.PB377 Lsl.L #4,D1 ; multiply by number of records Lea pmInfo(A0,D1.L),A2 ; point A2 at the correct ColorInfo MOVE ciUsage(A2),D0 ; D0 = old usage BTST #AnimatedBit,D0 ; Was it animated before? BEQ.S NoScat ; If not, we've nothing to release MOVE srcUsage(A6),D3 EOR D3,D0 ; And, which bits changed AND #$3F0C,D0 ; Animated, explicit, OR inhibits? BEQ.S noScat ; None? No change to fix MOVE ciPrivate(A2),D3 ; Yes, were any indexes actually reserved? BPL.S NoScat ; No => still no entries to release MOVE.L PMgrHandle,A0 ; A0 = pmgr handle MOVE.L (A0),A0 ; A0 ->pmgr data LEA LinkTabs(A0),A3 ; A3 -> LinkTabs LEA DevHandles(A0),A4 ; A4 -> Device handles CLR.L D4 ; No devices affected... yet JSR ClearStrand ; clear linktab/ctTable entries MOVE.L PMgrHandle,A0 ; A0 = pmgr handle MOVE.L (A0),A0 ; A0 ->pmgr data OR.L D4,scatterDevs(A0) ; Mark some devices for scattering CLR ciPrivate(A2) ; We no longer own those indices. NoScat MOVE srcUsage(A6),D0 ; Get new usage in D0 BTST #AnimatedBit,D0 ; Will it be now animated? (rgrdlss prior state) BEQ.S @NoDup ; No => don't dupe high/low bytes LEA ciRGB(A2),A0 ; A0->rgb color MOVE.B (A0)+,(A0)+ ; Dupe red into low byte MOVE.B (A0)+,(A0)+ ; Dupe green into low byte MOVE.B (A0)+,(A0)+ ; Dupe blue into low byte @NoDup Move D0,ciUsage(A2) ; copy usage Move srcTolerance(A6),ciTolerance(A2) ; copy tolerance Move.L dstPalette(A6),-(SP) ; push the palette handle AWC.PB508 Bsr DirtySeeds ; clear the device seeds AWC.PB508 GoHome MoveQ #0,D0 ; clear error condition AWC.PB377 MOVEM.L (SP)+,A2-A4/D3-D4 ; restore regs Unlk A6 ; clear stack frame Rtd #ParamSize ; strip parameters and go home ;--------------------------------------------------- ; ; PROCEDURE CTab2Palette(srcCTab: CTabHandle; dstPalette: PaletteHandle; myUsage, ; myTolerance: INTEGER); INLINE $AA9F; ; CTab2Palette PROC EXPORT ParamSize equ 12 ; total bytes of params srcCTab equ ParamSize+8-4 ; source ColorTable handle dstPalette equ srcCTab-4 ; destination Palette handle srcUsage equ dstPalette-2 ; default usage value srcTolerance equ srcUsage-2 ; default usage tolerance VarSize equ 0 Link A6,#VarSize ; build stack frame MoveM.L D3/A2-A3,-(SP) ; save registers Move.L dstPalette(A6),A2 ; get palette CmpA.L #Nil,A2 ; is it nil? Beq GoHome ; can't deal with nil here either AWC.PB377 Move.L dstPalette(A6),-(SP) ; push Palette Jsr ClearPalette ; clear animating entries and seed handle Bne.S GoHome ; if not zero it was a bad palette AWC.PB457 Move.L srcCTab(A6),A3 ; get color table CmpA #Nil,A3 ; is it nil? Beq.S GoHome ; can't deal with a nil handle AWC.PB377 Move.L (A3),A1 ; dereference it MoveQ #0,D3 ; clear high word of D3 Move ctSize(A1),D3 ; get size-1 of CTab AddQ #1,D3 ; D3 is number of entries in palette Move.L A2,A0 ; copy myPalette handle Move.L D3,D0 ; copy size AddQ #1,D0 ; include palette header Asl #4,D0 ; multiply by 16 bytes per entry | header _SetHandleSize ; do it Bne.S GoHome ; and quit if we couldn't do it AWC.PB377 Move.L A2,-(SP) ; push the palette handle AWC.PB508 Bsr DirtySeeds ; clear the device seeds AWC.PB508 Move.L (A2),A0 ; dereference our handle Move D3,pmEntries(A0) ; copy size AddA.L #pmInfo,A0 ; bump us to the first ColorInfo Move.L (A3),A1 ; dereference source handle again AddQ.L #ctTable,A1 ; bump A1 to the first ColorSpec Move srcUsage(A6),D1 ; grab myUsage from parameters Swap D1 ; put it in high word Move srcTolerance(A6),D1 ; grab myTolerance into low word Bra.S CopyEnd ; jump into DBra loop CopyLoop Move.L RGB+red(A1),ciRGB+red(A0) ; copy red and green Move RGB+blue(A1),ciRGB+blue(A0) ; copy blue BTST #animatedBit+16,D1 ; animated entry? BEQ.S @notAni ; No=>don't mangle hi/lo bytes MOVE.B RGB+red(A1),ciRGB+red+1(A0) ; copy red into lo byte MOVE.B RGB+green(A1),ciRGB+green+1(A0) ; copy green into lo byte MOVE.B RGB+blue(A1),ciRGB+blue+1(A0) ; copy blue into lo byte @notAni Move.L D1,ciUsage(A0) ; copy myUsage and myTolerance Clr ciFlags(A0) ; clear private flags Clr ciPrivate(A0) ; clear private links AddA.L #ciSize,A0 ; bump A0 to next ColorInfo AddQ.L #ColorSpecSize,A1 ; bump A1 to next ColorSpec CopyEnd DBra D3,CopyLoop ; decrement and branch until copy is done GoHome MoveQ #0,D0 ; clear error AWC.PB377 MoveM.L (SP)+,D3/A2-A3 ; restore registers Unlk A6 ; clear stack frame Rtd #ParamSize ; strip parameters and go home ;--------------------------------------------------- ; ; PROCEDURE Palette2CTab(srcPalette: PaletteHandle; dstCTab: CTabHandle); INLINE $AAA0; ; Palette2CTab PROC EXPORT ParamSize equ 8 ; total bytes of params srcPalette equ ParamSize+8-4 ; source Palette handle dstCTab equ srcPalette-4 ; destination CTabHandle VarSize equ 0 Link A6,#VarSize ; build stack frame MoveM.L D3/A2-A3,-(SP) ; save registers ; first grab MyPalette and myCTab and compare them to nil Move.L srcPalette(A6),A2 ; get source into A2 CmpA #Nil,A2 ; is it nil? Beq.S GoHome ; punt if no palette AWC.PB377 Move.L dstCTab(A6),A3 ; get destination into A3 CmpA #Nil,A3 ; is it nil? Beq.S GoHome ; punt if no ctab AWC.PB377 ; leave size in D0; dereference both handles and capture pmEntries Move.L (A2),A0 ; dereference myPalette MoveQ #0,D3 ; clear high word Move pmEntries(A0),D3 ; get number of palette entries Move.L D3,D0 ; copy length AddQ.L #1,D0 ; add 1 for the header Lsl.L #3,D0 ; multiply by size of ColorSpec Move.L A3,A0 ; put handle in A0 _SetHandleSize ; resize it Bne.S GoHome ; <> 0 => couldn't handle it AWC.PB377 Move.L (A2),A0 ; redereference myPalette Move.L (A3),A1 ; dereference CTab Move D3,D0 ; copy size to a temp SubQ #1,D0 ; ctSize is really last entry ; CHECK - what should we do with the seed? Get name of call from Ernie, again. Clr.L ctSeed(A1) ; clear seed Move D0,ctSize(A1) ; set size Clr TransIndex(A1) ; this is not a device ColorTable (clear hi bit) AddQ #ctTable,A1 ; bump color table to start AddA #pmInfo,A0 ; bump palette to start MoveQ #0,D1 ; clear index for pixel value Bra.S CopyEnd ; jump to start of copy CopyLoop Move D1,value(A1) ; set pixel value Move.L ciRGB(A0),RGB(A1) ; copy red and green Move ciRGB+blue(A0),RGB+blue(A1) ; copy blue AddA.L #ciSize,A0 ; bump A0 to next ColorInfo AddQ.L #ColorSpecSize,A1 ; bump A1 to next ColorSpec AddQ #1,D1 ; bump pixel value CopyEnd DBra D3,CopyLoop ; loop for all entries GoHome MoveQ #0,D0 ; clear error condition MoveM.L (SP)+,D3/A2-A3 ; restore registers Unlk A6 ; clear stack frame Rtd #ParamSize ; strip parameters and go home ;--------------------------------------------------- ; ; PROCEDURE ClearOne(eInfo:CiInfo; BasePtr:Ptr); LOCAL; ; ClearOne PROC EXPORT ParamSize equ 4 ; total bytes of params eInfo equ ParamSize+8-4 ; entry to clear BasePtr equ eInfo-4 ; pointer to PMgrHandle^^ VarSize equ 0 Link A6,#VarSize ; build stack frame Move.L A2,-(SP) ; save a register Move.L eInfo(A6),A0 ; get the ColorInfo address Move ciPrivate(A0),D0 ; get the current link information Clr ciFlags(A0) ; shut down any crap Clr ciPrivate(A0) ; clear it Move.L BasePtr(A6),A1 ; set up DevListPtr Lea DevHandles(A1),A2 ; A2 points at DevHandles AddA.L #LinkTabs,A1 ; A1 points at LinkTabs NextLink BfExtU D0{19:5},D1 ; grab device number (0..31) BfExtU D0{24:8},D2 ; grab index number (0..255) Move.L (A2,D1.W*8),A0 ; get the device handle Move.L (A0),A0 ; dereference it Move.L gdPMap(A0),A0 ; get handle to pixmap Move.L (A0),A0 ; dereference pixmap Move.L pmTable(A0),A0 ; get handle to CTab Move.L (A0),A0 ; dereference CTab Cmp ctSize(A0),D2 ; is index number <= entries - 1? Bhi.S IgnoreIt ; no => don't unreserve it Clr ctTable+value(A0,D2.W*8) ; unreserve it IgnoreIt Lsl #8,D1 ; calculate offset to link table/4 Add D2,D1 ; offset to entry/4 Lea (A1,D1.L*4),A0 ; point A0 at next forward link Move ForeLink(A0),D0 ; get next link Clr.L ForeLink(A0) ; clear it for the next guy Tst D0 ; is there another link to examine? Bmi.S NextLink ; yes => go unlink it Move.L (SP)+,A2 ; restore A2 Unlk A6 ; clean up our mess Rtd #ParamSize ; go home ;--------------------------------------------------- ; ; PROCEDURE CopyPalette(srcPalette,dstPalette: PaletteHandle; srcEntry,dstEntry,dstLength: ; INTEGER); INLINE $AAA1; ; CopyPalette PROC EXPORT ParamSize equ 14 ; total bytes of params srcPalette equ ParamSize+8-4 ; source Palette handle dstPalette equ srcPalette-4 ; destination palette handle srcEntry equ dstPalette-2 ; source starting entry dstEntry equ srcEntry-2 ; destination starting entry dstLength equ dstEntry-2 ; length of the copy TrimLen equ -2 VarSize equ TrimLen Link A6,#VarSize ; build stack frame MoveM.L D3-D4/A2-A4,-(SP) ; save registers Move.L PMgrHandle,A4 ; get the main handle CmpA.L #PMgrNil,A4 ; are we initialized? Beq GoHome ; no => punt AWC.PB377 Move.L dstPalette(A6),A2 ; get destination palette CmpA.L #Nil,A2 ; is it nil? Beq GoHome ; can't deal with nil here either AWC.PB377 Move.L srcPalette(A6),A3 ; get source palette CmpA.L #Nil,A3 ; is it nil? Beq GoHome ; can't deal with a nil handle AWC.PB377 CmpA.L A2,A3 ; does source = destination? Beq GoHome ; we can't handle this yet AWC.PB377 MoveQ #0,D0 ; clear D0 Move dstLength(A6),D0 ; get the length of the copy Ble GoHome ; we can quit if it's too small Move.L D0,D3 ; copy the length Add SrcEntry(A6),D0 ; D0 is the required length of the source Move.L (A3),A1 ; dereference source palette Move pmEntries(A1),D1 ; get size of source palette Sub D0,D1 ; D1, if negative, is how much we must trim D3 Bpl.S DontTrimSrc ; no => don't trim it Add D1,D3 ; trim back the length of the copy AWC.PB530 DontTrimSrc Move.L (A2),A0 ; dereference the destination Move pmEntries(A0),D4 ; get the length Move DstEntry(A6),D0 ; calculate the potential new pmEntries Add D3,D0 ; by adding the trimmed length Cmp D4,D0 ; need we add handle room? Ble.S BigEnough ; no => skip _SetHandleSize AWC.PB530 Move D0,D4 ; save new length Move.L A2,A0 ; copy DstPalette AddQ #1,D0 ; include palette header Asl #4,D0 ; multiply by 16 bytes per entry | header _SetHandleSize ; do it Bne GoHome ; and quit if we couldn't do it AWC.PB377 Move.L (A2),A0 ; dereference the destination handle Move D4,D2 ; make a copy of the new length MoveQ #0,D1 ; clear the high word Move PmEntries(A0),D1 ; this is where to start clearing Sub D1,D2 ; this is now many to clear Move D4,pmEntries(A0) ; save size Lea PmInfo(A0),A1 ; point us at the start of the table Asl #4,D1 ; this is the offset to the start of the clear AddA.L D1,A1 ; bump A1 to the start of the clear Bra.S ClearEnd ; jump to the DBra ; The main reason for clearing is so we can correctly detect and clear entries that are ; going to be clobbered. ClearLoop Clr.L (A1)+ ; clear 16 bytes Clr.L (A1)+ Clr.L (A1)+ Clr.L (A1)+ ClearEnd DBra D2,ClearLoop BigEnough CmpA.L A2,A3 ; does SrcPalette = DstPalette? Beq.S GoHome ; yes => can't handle this AWC.PB377 Move.L A3,-(SP) ; push the palette handle AWC.PB508 Bsr DirtySeeds ; clear the device seeds AWC.PB508 Move.L (A3),A1 ; dereference source palette MoveQ #0,D0 ; clear the high word Move DstEntry(A6),D0 ; get the first destination Asl.L #4,D0 ; multiply by 16 Move.L (A2),A0 ; dereference destination palette again AWC.PB508 Lea PmInfo(A0,D0),A0 ; point A0 at the first destination MoveQ #0,D1 ; clear the high word Move SrcEntry(A6),D0 ; get the first source Asl.L #4,D0 ; point A0 at the first destination Lea PmInfo(A1,D0),A1 ; point A1 at the first source Bra.S CopyEnd ; jump into the loop CopyLoop Move ciPrivate(A0),D0 ; get the link info Beq.S NoLinks ; no => it doesn't need clearing MoveM.L A0-A1,-(SP) ; save registers Move.L A0,-(SP) ; ciInfo to clear Move.L (A4),-(SP) ; dereference PMgrHandle and push it Jsr ClearOne ; clear the links MoveM.L (SP)+,A0-A1 ; restore interesting registers NoLinks Move.L ciRGB(A1),ciRGB(A0) ; copy first two words Move.L ciRGB+Blue(A1),ciRGB+blue(A0) ; copy blue and usage Move ciTolerance(A1),ciTolerance(A0) ; copy tolerance Clr ciFlags(A0) ; clear the flags field Clr ciPrivate(A0) ; clear the links field AddA.L #CiSize,A0 ; bump both pointers AddA.L #CiSize,A1 CopyEnd DBra D3,CopyLoop ; loop for (trimmed) length entries GoHome MoveQ #0,D0 ; clear error code AWC.PB377 MoveM.L (SP)+,D3-D4/A2-A4 ; restore registers Unlk A6 ; clear stack frame Rtd #ParamSize ; strip parameters and go home ;--------------------------------------------------- ; ; PROCEDURE UpdateDevice(DeviceNumber:INTEGER); Local; ; ; This here routine will do a setentries of deviceNumber on it's own color table. ; Also, it forces a redraw of that screen, including the menu bar. ; (This code was moved out of the tail of SetDev, so that ScatterDev could use it.) ; ; UpdateDevice PROC EXPORT UDVars RECORD {A6Link},DECREMENT result DS.B 0 ;Result length: none deviceNum DS.B 2 ;Input: device number return DS.B 4 A6Link DS.B 4 ;old contents of A6 oldPort DS.B 4 ;pointer to old port resultRect DS.B 8 ;a temp rectangle sysUpdates DS.B 2 ;a temp boolean linkSize DS.B 0 ;linky number ENDR WITH UDVars LINK A6,#linkSize MOVEM.L A0-A3/D0-D3,-(SP) SUBQ #4,SP _FrontWindow MOVE.L (SP)+,D3 ; D3 = topmost window. Permanently. Pea oldPort(A6) ; where to put current GrafPtr _GetPort ; get it MOVE.L PMgrHandle,A1 ; A1 = handle to palette data MOVE.L (A1),A1 ; A1->palette data MOVE deviceNum(A6),D0 ; D0 = device number to update MOVE.L devHandles+devHandle(A1,D0.W*8),A2 ; A2 = handle to device to update MOVE.L A2,A0 ; Put in A0, for devsetent JSR DevSetEntries Move.L (A2),A0 ; dereference it Lea gdRect(A0),A2 ; get address of device rect into A2 Move gdFlags(A0),D0 ; get flags BTst #MainScreen,D0 ; is it the main screen? Beq.S NoMenuFix ; no => don't update the menu Move.L MenuList,D0 ; get the MenuList handle; is it nil? AWC.PB508 Beq.S NoMenuFix ; yes => don't redraw the menu bar AWC.PB508 Move.L D0,A0 ; get ready to dereference it AWC.PB508 Tst.L (A0) ; has it been purged? AWC.PB508 Beq.S NoMenuFix ; yes => don't redraw the menu bar AWC.PB508 _DrawMenuBar ; redraw the menu bar AWC.PB508 NoMenuFix MoveQ #0,D0 ; we want no updates if no SysPalette AWC PB223 Move.L AppPalette,A0 ; fetch the application's palette, if any AWC.PB457 Move.L A0,D1 ; CmpA.L #Nil,A0; is it nil? AWC.PB457 Bne.S UseAppPltt ; no => use the application's palette AWC.PB457 MOVE.L PMgrHandle,A0 MOVE.L (A0),A0 ; A0 -> our data Move.L SysPalette(A0),A0 ; fetch the system palette Move.L A0,D1 ; CmpA.L #Nil,A0; is it nil? AWC.PB457 Beq.S NoSysP ; yes => we update UseAppPltt Move.L (A0),A0 ; dereference AppPalette or SysPalette AWC.PB457 Move pmPrivate(A0),D0 ; get update information AWC PB224 And #$C000,D0 ; and it with the proper flags AWC PB224 NoSysP Move D0,sysUpdates(A6) ; set update information AWC PB224 JSR CheckForJuggler ; ÀAre we Juggling? Bne.S NotJuggling ; no => handle updates the old way AWC PB224 Move.L A2,-(SP) ; push device rect on the stack AWC PB224 Move deviceNum(A6),-(SP) ; push PaletteMgr device number AWC PB224 Move sysUpdates(A6),-(SP) ; push default updates for old ports AWC PB224 Move #ColorInvalRect,-(SP) ; push the selector for _ColorInvalRect AWC PB224 _Juggler ; call Erich's disgusting C code AWC PB224 bra EndJuggling ; skip over the regular update code AWC PB224 NotJuggling Move.L WindowList,A3 ; get start of window list AWC PB224 CMPA #-1,A3 ; Window list there? BEQ WLDone ; No, fini. BRA EndWind ; Skip to end, for NIL check WindowLoop Move sysUpdates(A6),D1 ; reset the default update value AWC.PB480 Move #CBackBit,D0 ; grab a constant AWC PB224 CmpA.L D3,A3 ; is it the "fore" window? Bne.S NotCurrent ; no => check for background updates Move #CForeBit,D0 ; grab a different constant AWC PB223 NotCurrent Tst.B wVisible(A3) ; is this window visible? Beq NextWind ; no => do the next window Tst PortBits+RowBytes(A3) ; is it a color window? Bpl.S UseDefault ; no => handle an old style window AWC.PB480 Move.L GrafVars(A3),A0 ; get the extended variables handle Move.L (A0),A0 ; dereference it Move.L PmFgColor(A0),A0 ; get the window's palette, if any CmpA.L #Nil,A0 ; is it nil? Beq.S UseDefault ; yes => default to the system value AWC.PB480 Move.L (A0),A0 ; dereference the palette Move pmPrivate(A0),D1 ; fetch the palette's update values AWC.PB480 UseDefault BTst D0,D1 ; does the caller want this update? AWC.PB480 Beq.S NextWind ; no => do the next window ; We now must check to see if the window we're examining intersects the device ; we're working upon. We'll GlobalToLocal the device rect and simultaneously ; intersect it with the window's portRect. If we detect an intersection then ; we'll have calculated the rectangle we'll need for the InvalRect. First we ; point A0 at the Bounds rect for the port so we can put DevRect in local space. Lea PortBits(A3),A0 ; point A0 at potential bitmap AWC.PB480 Tst RowBytes(A0) ; bitmap or pixmap? AWC.PB480 Bpl.S GotBitmap ; no high bit in Rowbytes => bitmap AWC.PB480 Move.L BaseAddr(A0),A0 ; get Port's Pixmap handle AWC.PB480 Move.L (A0),A0 ; get Pixmap pointer AWC.PB480 GotBitmap Lea Bounds(A0),A0 ; advance A0 to Bounds rect AWC.PB480 Move Top(A2),D0 ; get device top AWC.PB480 Add Top(A0),D0 ; subtract bounds top AWC.PB480 Cmp PortRect+Bottom(A3),D0 ; is Dest.Top >= Port.Bottom? AWC.PB480 Bge.S NextWind ; yes => no intersection AWC.PB480 Move D0,resultRect+Top(A6) ; save it AWC.PB480 Move Left(A2),D0 ; get device left AWC.PB480 Add Left(A0),D0 ; subtract bounds left AWC.PB480 Cmp PortRect+Right(A3),D0 ; is Dest.Left >= Port.Right? AWC.PB480 Bge.S NextWind ; yes => no intersection AWC.PB480 Move D0,resultRect+Left(A6) ; save left AWC.PB480 Move Bottom(A2),D0 ; get bottom AWC.PB480 Add Top(A0),D0 ; subtract bounds top AWC.PB480 Cmp PortRect+Top(A3),D0 ; is Dest.Bottom <= Port.Top? AWC.PB480 Ble.S NextWind ; yes => no intersection AWC.PB480 Move D0,resultRect+Bottom(A6) ; save bottom AWC.PB480 Move Right(A2),D0 ; get right AWC.PB480 Add Left(A0),D0 ; subtract bounds left AWC.PB480 Cmp PortRect+Left(A3),D0 ; is Dest.Right <= Port.Left? AWC.PB480 Ble.S NextWind ; yes => no intersection AWC.PB480 Move D0,resultRect+Right(A6) ; save right AWC.PB480 Move.L A3,-(SP) ; push this window's pointer AWC.PB480 _SetPort ; make it the current port AWC.PB480 Pea resultRect(A6) ; move device rect (local) onto the stack AWC.PB480 _InvalRect ; invalidate it AWC.PB480 NextWind Move.L NextWindow(A3),A3 ; grab the next window in the list EndWind CmpA.L #Nil,A3 ; is it nil? Bne WindowLoop ; no => continue Bsr RedrawDesktop ; redraw the desktop (uses A3) AWC.PB508 WLDone EndJuggling Move.L oldPort(A6),-(SP) ; push old port _SetPort ; restore old port GoHome MoveQ #0,D0 ; clear error condition AWC.PB377 MoveM.L (SP)+,A0-A3/D0-D3 ; restore registers UNLK A6 RTD #result-return-4 ; bye. ;--------------------------------------------------- ; ; PROCEDURE UpdateDevices(); LOCAL; ; ; Update all devices with bits in updateDevs. UpdateDevices PROC EXPORT MOVEM.L A0/D0-D1,-(SP) CMPI.L #-1,WindowList ; Have Windows happened? BEQ.S GoHome ; No=>skip this stuff CMPI.L #-1,CurApName ; Is CurApName FFFFFFFF? BEQ.S GoHome ; If so, we can't help yet. MOVE.L PMgrHandle,A0 MOVE.L (A0),A0 ; A0->PMgr data MOVE nDevs(A0),D0 ; D0 = number of devices SUBQ #1,D0 ; less one for DBRAing MOVE.L updateDevs(A0),D1 ; D1 = mask of devices to update BEQ.S GoHome ; None. Bye. CLR.L updateDevs(A0) ; Say they've been updated. UpLoop BTST D0,D1 ; Update this one? BEQ.S UpLoopEnd ; Nah. MOVE D0,-(SP) ; Yah. Push device number (stack down 2) JSR UpdateDevice UpLoopEnd DBRA D0,UpLoop GoHome MOVEM.L (SP)+,A0/D0-D1 ; fix regs RTS ;--------------------------------------------------- ; ; FUNCTION WhatPal(aWindow:WindowPtr):PaletteHandle; LOCAL; AAA2/5 ; ; Given window in A2, return its palette, or appPalette, or even sysPalette WhatPal PROC EXPORT MOVE.L 4(SP),A0 ; A0 = aWindow TST portBits+rowBytes(A0) ; An old port? BPL.S @default ; Yes => go use sys- or app-palette MOVE.L GrafVars(A0),A0 MOVE.L (A0),A0 ; A0->aux data MOVE.L PmFgColor(A0),D0 ; D0 = specified Palette BNE.S @goHome ; Nil? No => we got a palette @default MOVE.L AppPalette,D0 ; Try the AppPalette BNE.S @goHome ; Yes, got an AppP MOVE.L PMgrHandle,A0 MOVE.L (A0),A0 MOVE.L SysPalette(A0),D0 ; D0 = System Palette @goHome MOVE.L D0,8(SP) RTD #4 ;--------------------------------------------------- ; ; PROCEDURE CalcDevs; LOCAL; ; ; Set DeviceSet(A6) and FrontSet(A6) to the bit-set of the ; devices that PaletteH(A6) affects. ; CalcDevs PROC EXPORT MOVEM.L D3-D7/A2-A3,-(SP) ; Restore registers SUBQ #8,SP ; Make space for a temp rect MOVE.L WindowList,A2 ; A2 = Windowlist walker MoveQ #0,D3 ; clear device set MoveQ #0,D4 ; clear front set CLR.L -(SP) ; Space for result _FrontWindow MOVE.L (SP)+,D6 ; Keep the frontwindow in here. BRA @wLoopEnd ; Branch to end of window walking @wLoop TST.B wVisible(A2) ; A visible window? ; BEQ @wLoopNext ; No. Ignore it. :inv'ble w'dws can have colors SUBQ #4,SP MOVE.L A2,-(SP) _WhatPal MOVE.L (SP)+,A0 CMPA.L PaletteH(A6),A0 ; Same one we're activating? BNE @wLoopNext ; No, don't check it. LEA portBits(A2),A0 ; A0->bitmap TST rowBytes(A0) ; Old port? BPL @oldPort ; Yes=>skip pm dereference MOVE.L baseAddr(A0),A0 ; A0 = pixmap handle MOVE.L (A0),A0 ; A0->pixmap @oldPort MOVE.L bounds(A0),D0 ; D0 = top, left of bounds rect MOVE.L portRect(A2),D1 ; D1 = top, left of port rect SUB D0,D1 ; D1Lo = global left SWAP D0 SWAP D1 SUB D0,D1 ; D1Lo = global top SWAP D0 SWAP D1 MOVE.L D1,WindowRect(A6) ; WindowRect topLeft in global MOVE.L portRect+botRight(A2),D1 ; D1 = bottom, right of port rect SUB D0,D1 ; D1Lo = global right SWAP D0 SWAP D1 SUB D0,D1 ; D1Lo = global bottom SWAP D1 MOVE.L D1,botRight+WindowRect(A6) ; WindowRect botRight in global MOVE.L PMgrPtr(A6),A0 ; A0->Pmgr data MOVE nDevs(A0),D5 ; D5 = device number SUBQ #1,D5 LEA DevHandles(A0),A3 ; A3->List of devices @dLoop MOVE.L DevHandle(A3,D5*8),A0 ; A0 = this device handle MOVE.L (A0),A0 ; A0->this device CLR -(SP) ; Space for result PEA gdRect(A0) ; Push device rect PEA WindowRect(A6) ; Push window rect PEA 10(SP) ; Push throwaway result rect _SectRect TST (SP)+ ; Any intersection? BEQ.S @dLoopEnd ; No=>advance to next gDevice BSET D5,D3 ; Set this bit of deviceSet TST.B wHilited(A2) ; Is this window hilited? BEQ.S @notFront ; If not, can't be frontish CMP.L A2,D6 ; Is this window the FrontWindow? BNE.S @wasntFront ; No => go here MOVE.L A2,DevFrontMost(A3,D5*8) ; Yes => save it. BRA.S @wasFront @wasntFront CMPA.L DevFrontMost(A3,D5*8),A2 ; was it previously frontmost? BNE.S @notFront ; No, not front at all. @wasFront BSET D5,D4 ; Set this bit of FrontSet @notFront @dLoopEnd DBRA D5,@dLoop ; Try next device @wLoopNext MOVE.L NextWindow(A2),A2 ; Get next window @wLoopEnd MOVE.L A2,D0 ; NIL window? BNE @wLoop ; No=>Loop! MOVE.L D3,DeviceSet(A6) ; Save device set MOVE.L D4,FrontSet(A6) ; Save frontmost set ADDQ.L #8,SP ; Lose temp rectangle MOVEM.L (SP)+,D3-D7/A2-A3 ; Restore registers RTS ;--------------------------------------------------- ; ; PROCEDURE UnhookDevice(whichDevice:deviceHandle); ; ; InitGDevice ought to call this routine. When a device is initialized, release any animated ; entries, and give it our idea of an appropriate clut. UnhookDevice PROC EXPORT ParamSize equ 4 ; total bytes of params whichDevice equ ParamSize+8-4 ; device we're unlinking Link A6,#spVarSize ; build stack frame MOVEM.L D2-D4/A2,-(SP) Move.L PMgrHandle,A0 ; get global handle CmpA.L #PMgrNil,A0 ; is it nil? Beq.S GoHome ; skip it Move.L (A0),A0 ; dereference PMgrHandle Move nDevs(A0),D3 ; are there any devices? LEA DevHandles(A0),A1 ; A1 = start of list of devices, D4=count MOVE.L whichDevice(A6),D1 ; D1 = device handle to fix release links of SUBQ #1,D3 ; for DBRA (nDevs says we've got some devs) FindDevLoop CMP.L DevHandle(A1,D3.W*8),D1 ; Is this the device? BEQ.S FoundDevice DBRA D3,FindDevLoop BRA.S GoHome ; It's not a device we know about. FoundDevice LSL.W #8,D3 ; Shift device number into high bits MOVE.L D1,A2 ; A2 = device we're zapping MOVE.L (A2),A2 ; dereference device MOVE.L gdPMap(A2),A2 ; A2 = PixMapHandle MOVE.L (A2),A2 ; dereference pmhandle MOVE.L pmTable(A2),A2 ; A2 = cluthandle MOVE.L (A2),A2 ; dereference that, too MOVE #255,D4 ; We'll just unlink all 256 entries of the linktab. ZapLoop MOVE.B D4,D3 MOVE.W D3,-(SP) ; Push combinded index and device _ZapLinks ; Unlink device/index combo ZapLoopEnd DBRA D4,ZapLoop SUB #2,SP ; Space for result MOVE.L D1,-(SP) ; Push device handle JSR CheckDeviceColors ; Look for the right colors TST (SP)+ ; Anything reallocated? BEQ.S GoHome ; No=>nothing CLR.L D0 LSR.W #8,D3 ; Get back device number BSET D3,D0 ; D0 = 1 bit set in the device's position OR.L D0,scatterDevs(A0) ; Tell ourselves to deal with that device. MOVE #1,-(SP) JSR ScatterDevices ; And scatter entries. ;!!! MOVE D3,-(SP) ; Push device number ;!!! JSR UpdateDevice ; Update this device. GoHome MOVEM.L (SP)+,D2-D4/A2 UNLK A6 RTD #paramSize ; Bus on out of here. ;--------------------------------------------------- ; ; PROCEDURE UnreserveDevices(PMgrPtr,PalettePtr,Devmask); ; ; Call me to unreserve entries when a palette has moved from one place to another. ; We have ActivatePalettes A6 frame, also, on entry, we have ; A0->Pmgr data, A1->palette, D0 = devmask ; UnreserveDevices PROC EXPORT MOVEM.L A2-A4/D1-D4,-(SP) LEA LinkTabs(A0),A2 ; A2 -> linktabs MOVE pmEntries(A1),D1 ; D1 = loop variable LEA pmInfo(A1),A3 ; A3 = walking ColorInfo pointer CLR.L D4 ; D4 = device mask for later scattering BRA.S entryEnd entryLoop MOVE ciPrivate(A3),D2 ; D2 = LinkTab entry (if any) BPL.S nextEntry ; If positive, it owns no entries. devLoop BFEXTU D2{19:5},D3 ; D3 = device number BTST D3,D0 ; A device we should 'clear'? BEQ.S nextDev ; No, keep walking BSET D3,D4 ; Mark device for scattering MOVE.L D0,-(SP) ; preserve D0 MOVE D2,-(SP) ; Push Device/Index _ZapLinks ; Unlink it MOVE.L (SP)+,D0 ; restore D0 MOVE.L DevHandles+DevHandle(A0,D3*8),A4 ; A4 = device handle BFEXTU D2{24:8},D3 ; D3 = index Move.L (A4),A4 ; dereference it Move.L gdPMap(A4),A4 ; get handle to pixmap Move.L (A4),A4 ; dereference pixmap Move.L pmTable(A4),A4 ; get handle to CTab Move.L (A4),A4 ; dereference CTab Cmp ctSize(A4),D3 ; is index number <= entries - 1? Bhi.S nextDev ; no => don't unreserve it MOVE #ctScatterVal,ctTable+value(A4,D3.W*8) ; unreserve it, mark scatterbit nextDev AND #$1FFF,D2 ; Mask off the key bits MOVE ForeLink(A2,D2.W*4),D2 ; Get next link item BMI.S devLoop ; End of list, eh? nextEntry ADDA #ciSize,A3 entryEnd DBRA D1,entryLoop OR.L D4,scatterDevs(A0) MOVEM.L (SP)+,A2-A4/D1-D4 RTS ;--------------------------------------------------- ; ; PROCEDURE ZapLinks(myIndex:integer); LOCAL; AAA2/4 ; ; If index myIndex (combined device and index) is linked by someone, break the link ; and mark it free. Decrement the "reserves" count of the palette who ; owns the index. Pass myIndex with device in high bits, index in low bits. ; (This code was moved out of Pillage ) ; (See how we courteously restore ALL registers) ZapLinks PROC EXPORT ZLVars RECORD {A6Link},DECREMENT result DS.B 0 ;Result length: none myIndex DS.B 2 ;Input: device number and index to unlink return DS.B 4 A6Link DS.B 4 ;old contents of A6 linkSize DS.B 0 ;linky number ENDR WITH ZLVars LINK A6,#linkSize MOVEM.L A0-A2/D0-D4,-(SP) MOVE.L PMgrHandle,A1 MOVE.L (A1),A1 ; A1->PMgrData LEA LinkTabs(A1),A0 ; A0->Link Tables MOVE.L PListHandle(A1),A2 ; A2 = palette list handle MOVE.L (A2),A2 ; A2 -> palette info list MOVE myIndex(A6),D0 ; D0 = tricky link AND #$1FFF,D0 ; clear key bits MOVE D0,D1 LSR #8,D1 ; D1 = device number MOVE.L DevHandles(A1,D1*8),A1 ; A1 = device handle MOVE.L (A1),A1 ; A1->device MOVE.L gdPMap(A1),A1 ; A1 = pixmap handle MOVE.L (A1),A1 ; A1->pixmap MOVE.L pmTable(A1),D1 ; D0 = color table for this device BEQ.S @a ; Skip this if none MOVE.L D1,A1 ; A1 = color table handle MOVE.L (A1),A1 ; A1 -> color table CLR D1 MOVE.B D0,D1 ; We need to clear the upper bits CMP ctSize(A1),D1 ; Index in range? BHI.S @a ; No=>skip this BCLR #ctReserveBit,ctTable+value(A1,D1*8) ; unreserve! @a Move ForeLink(A0,D0.W*4),D3 ; get forward links BEQ GoHome ; Hey! this link was unowned anyhow! Move BackLink(A0,D0.W*4),D4 ; get backward links Clr.L (A0,D0.W*4) ; clear the links away Tst D3 ; examine forward link Bmi.S MultiLinks1 ; if < 0 we have more than one assigned Tst D4 ; examine backward link Bmi.S MultiLinks2 ; if < 0 we have more than one assigned ; This was a quickie. D3 contains the palette number, D4 the entry number. All we ; need do is tell the palette it no longer has it. And #$1FFF,D3 ; clear key bits SubQ #1,Reserves(A2,D3*8) ; it has one less entry reserved Move.L PaletteRef(A2,D3*8),A0 ; get the palette Move.L (A0),A0 ; dereference it And.L #$00001FFF,D4 ; clear high word and key bits Lsl.L #4,D4 ; make it an offset to the ColorInfo Clr pmInfo+ciPrivate(A0,D4.L) ; clear the link Bra GoHome ; we did it! ; The forward link goes somewhere. See if the backward one does too. If so, ; jump to BothLinks. MultiLinks1 Tst D4 ; examine backward link Bmi.S BothLinks ; both of them go somewhere ; The forward link goes somewhere, but the backward one does not. We must remember ; the first forward link so we can copy it into the palette, then we advance ; forward by one, copy the palette entry into that, and continue searching until we find ; out what palette this is. Move D3,D0 ; remember the forward link BfExtU D3{19:5},D1 ; grab device number (0..31) BfExtU D3{24:8},D2 ; grab index number (0..255) Lsl #8,D1 ; calculate offset to link table/4 Add D2,D1 ; offset to entry/4 Lea (A0,D1.L*4),A1 ; point A1 at next forward link Move D4,BackLink(A1) ; copy the back link Move ForeLink(A1),D3 ; get next link Bpl.S GotPalette1 ; if > 0, we've found the palette MultiFLoop BfExtU D3{19:5},D1 ; grab device number (0..31) BfExtU D3{24:8},D2 ; grab index number (0..255) Lsl #8,D1 ; calculate offset to link table/4 Add D2,D1 ; offset to entry/4 Move ForeLink(A0,D1.L*4),D3 ; get next link; is it positive? Bmi.S MultiFLoop ; no => continue GotPalette1 And #$1FFF,D3 ; clear key bits SubQ #1,Reserves(A2,D3*8) ; it has one less entry reserved Move.L PaletteRef(A2,D3*8),A0 ; get the palette Move.L (A0),A0 ; dereference it And.L #$00001FFF,D4 ; clear high word of entry Lsl.L #4,D4 ; make it an offset to the ColorInfo Move D0,pmInfo+ciPrivate(A0,D4.L) ; set a new link Bra.S GoHome ; we did it! ; The backward link goes somewhere, but the forward one does not. We must advance ; backward by one, copy the palette id into it, and continue searching until we find out ; what palette this is. MultiLinks2 BfExtU D4{19:5},D1 ; grab device number (0..31) BfExtU D4{24:8},D2 ; grab index number (0..255) Lsl #8,D1 ; calculate offset to link table/4 Add D2,D1 ; offset to entry/4 Lea (A0,D1.L*4),A1 ; point A1 at next backward link Move D3,ForeLink(A1) ; copy the forward link Move BackLink(A1),D4 ; get next link Bpl.S GotPalette2 ; if > 0, we've found the palette MultiBLoop BfExtU D4{19:5},D1 ; grab device number (0..31) BfExtU D4{24:8},D2 ; grab index number (0..255) Lsl #8,D1 ; calculate offset to link table/4 Add D2,D1 ; offset to entry/4 Move BackLink(A0,D1.L*4),D4 ; get next link; is it positive? Bmi.S MultiBLoop ; no => continue Bra.S GotPalette2 ; share common code ; We're in the middle of the list somewhere. We'll step one backward and copy ; the forelink from the current entry, then we'll step one foreward and copy ; the backlink from the current entry. Then we'll keep going forward until we ; find the palette. All we need do is decrement its reference count, so we don't ; need the entry number. BothLinks BfExtU D4{19:5},D1 ; grab device number (0..31) BfExtU D4{24:8},D2 ; grab index number (0..255) Lsl #8,D1 ; calculate offset to link table/4 Add D2,D1 ; offset to entry/4 Lea (A0,D1.L*4),A1 ; point A1 at next backward link Move D3,ForeLink(A1) ; copy the forward link BfExtU D3{19:5},D1 ; grab device number (0..31) BfExtU D3{24:8},D2 ; grab index number (0..255) Lsl #8,D1 ; calculate offset to link table/4 Add D2,D1 ; offset to entry/4 Lea (A0,D1.L*4),A1 ; point A1 at next foreward link Move D4,BackLink(A1) ; copy the backward link Move ForeLink(A1),D3 ; get next foreward link Bpl.S GotPalette2 ; if > 0, we've found the palette BothLoop BfExtU D3{19:5},D1 ; grab device number (0..31) BfExtU D3{24:8},D2 ; grab index number (0..255) Lsl #8,D1 ; calculate offset to link table/4 Add D2,D1 ; offset to entry/4 Move ForeLink(A0,D1.L*4),D3 ; grab next forward link Bmi.S BothLoop ; if < 0, we keep looking GotPalette2 And #$1FFF,D3 ; clear away key bits SubQ #1,Reserves(A2,D3*8) ; it has one less entry reserved GoHome MOVEM.L (SP)+,A0-A2/D0-D4 UNLK A6 RTD #result-return-4 ; go home ;--------------------------------------------------- ; ; PROCEDURE ResizePalette(srcPalette:PaletteHandle; dstSize:INTEGER); AAA2/3; ; ; Set the number of entries in the palette, and properly dispose of some ; of them if the palette is shrinking. ResizePalette PROC EXPORT RPVars RECORD {A6Link},DECREMENT result DS.B 0 ; Result: none srcPal DS.B 4 ; input: palette handle dstSize DS.B 2 ; input: new size for palette return DS.B 4 A6Link DS.B 4 ; old contents of A6 linkSize DS.B 0 ;linky number ENDR WITH RPVars LINK A6,#linkSize MOVEM.L A2/D3-D4,-(SP) ; save 'em. IF (forRom OR theFuture) THEN ; clear out d3,d4 for later use moveq #0,d3 ; FM This ensures that the high move.l d3,d4 ; FM word is zeroed out before the compare ENDIF MOVE.L srcPal(A6),A0 ; A0 = palette we're resizing MOVE.L A0,D0 ADDQ.L #1,D0 ; Was it Ptr(-1)? The App Palette? BNE.S @foundPal ; No=>it's a real one MOVE.L AppPalette,A0 ; Get the 'app palette' @foundPal MOVE.L (A0),A2 ; A2->the palette MOVE dstSize(A6),D3 ; D3 = new size for palette MOVE pmEntries(A2),D4 ; D4 = old size of palette CMP D4,D3 ; Compare new size to old size BEQ.S @goHome ; The same, do nothing BHI.S @sizeIt ; It's bigger, resize and fix new entries _HLock ; If we're shrinking, we have to lose entries MOVE.L (A0),A2 ; A2->locked palette MOVE D4,D0 ; D0 = old size of palette LSL #4,D0 ; Multiply by size of colorInfos LEA pmInfo(A2,D0.W),A2 ; A2->just past last colorInfo @loseLoop SUBA #ciSize,A2 ; Bump A2 down to next colorInfo SUBQ #1,D4 ; Bump D4 down to next entry number MOVE ciUsage(A2),D0 ; D0 = usage for this entry ANDI #pmTolerant+pmAnimated,D0 ; Anything we care about? BEQ.S @loseEnd ; No, continue MOVE.L srcPal(A6),-(SP) ; Yes => set usage to courteous, before death MOVE D4,-(SP) ; Push entry number CLR.L -(SP) ; 0 usage, 0 tolerance (its the law) _SetEntryUsage @loseEnd CMP D4,D3 BNE.S @loseLoop ; Work right down to new size MOVE.L srcPal(A6),A0 ; Get handle back _HUnlock @sizeIt MOVE D3,D0 ; D0 = new number of entries EXT.L D0 ; long, for resize LSL.L #4,D0 ; times size of colorInfos ADD.L #pmInfo,D0 ; Plus size of header _SetHandleSize BNE.S @goHome ; Failed, go home. MOVE.L (A0),A2 ; A2->palette MOVE D3,pmEntries(A2) ; Set new palette size CMP.w D3,D4 ; Was old size smaller? BHS.S @goHome ; old size (D4) was bigger, or the same SUB.L D4,D3 ; D3 = difference in sizes LSL #4,D4 ; Get D4 to size*colorInfo size LEA pmInfo(A2,D4),A0 ; A0->first newly added entry LSL #2,D3 ; D3 = difference in sizes in longwords SUBQ #1,D3 ; Less one, for DBRA @clrLoop CLR.L (A0)+ ; Clear a long DBRA D3,@clrLoop ; Keep on clearing @goHome MOVEM.L (SP)+,A2/D3-D4 UNLK A6 RTD #result-return-4 ;--------------------------------------------------- ; ; PROCEDURE RestoreDeviceClut(aGDev:gDevice); AAA2/2; ; ; Set the specified device back to its default clut, based on depth ; and color/gray. If direct, ignore it. Actually, "UnhookDevice" ; does all the real work here, we just provide a loop to do it ; to all the devices if NIL is passed. ; RestoreDeviceClut PROC EXPORT TST.L 4(SP) ; Was NIL passed? BNE UnhookDevice ; Yes => just pass on to Unhookdevice MOVE.L A3,-(SP) ; Save a walking register MOVE.L deviceList,D0 ; Get head of devicelist BRA.S @devLoopEnd ; Go to end of list @devLoop MOVE.L D0,A3 MOVE.L A3,-(SP) ; Push device handle BSR UnhookDevice MOVE.L (A3),A3 ; Dereference gDev handle MOVE.L gdNextGD(A3),D0 ; Get next gdev handle @devLoopEnd BNE.S @devLoop ; NIL? MOVE.L (SP)+,A3 ; Yeah, fix register. RTD #4 ; We're out, lose input handle. ;--------------------------------------------------- ; ; PROCEDURE NewHiliteColor; AAA2/11; ; ; Call here when the hilite-color has been changed. Screens will be appropriately ; zapped. NewHiliteColor PROC EXPORT MOVE.L PMgrHandle,D1 ; PMgr active? BEQ.S cancel MOVE.L D1,A1 MOVE.L (A1),A1 ; A1->PMgr MOVE.L sevenCluts+8(A1),D0 ; Have we a two-bit hilite clut? BEQ.S noTwoBit ; Nah, we're fine CLR.L sevenCluts+8(A1) ; Okay, it's nil. MOVE.L D0,A0 ; Yes=>toss it, we'll rebuild. _DisposHandle noTwoBit MOVE.L D1,A1 ; A1 = PMgr Handle MOVE.L (A1),A1 ; A1->PMgr MOVE.L sevenCluts+16(A1),D0 ; Have we a four-bit hilite clut? BEQ.S noFourBit ; Nah, we're fine CLR.L sevenCluts+16(A1) ; Okay, it's nil. MOVE.L D0,A0 ; Yes=>toss it, we'll rebuild. _DisposHandle noFourBit JSR CheckAllDeviceCluts ; make sure everyone has new HiliteColor CLR -(SP) ; No setentries on scatter JSR ScatterDevices ; put some colors out there JSR UpdateDevices ; Send those InvalRects arounds. cancel RTS ; bye. ;--------------------------------------------------- ; ; PROCEDURE SaveFore(VAR x:ColorSpec); AAA2/13; ; PROCEDURE SaveBack(VAR x:ColorSpec); AAA2/14; ; ; Return a colorspec with the following coding: ; value = 0 - rgb is an rgb color ; value = 1 - rgb.red is the previous palette entry number ; SaveFore PROC EXPORT EXPORT SaveBack MOVEQ #0,D0 ; Tell ourselves it's a Fore BRA.S save SaveBack MOVEQ #1,D0 ; Tell ourselves it's a Back save MOVE.L 4(SP),A1 ; A1->colorSpec to return data in Move.L GrafGlobals(A5),A0 ; get the QuickDraw globals pointer Move.L ThePort(A0),A0 ; point at the port Tst PortBits+Rowbytes(A0) ; is it a new port? Bpl.S @saveRGB ; no => punt MOVE.L GrafVars(A0),D1 ; Get aux handle BEQ.S @SaveRGB ; Not there? puntit MOVE.L D1,A0 ; MOVE.L (A0),A0 ; A0->aux data BTST D0,pmFlags+1(A0) ; Test the appropriate bit fore PM BEQ.S @SaveRGB ; Okay, it wasn't a PmXxxxColor MOVE #1,value(A1) ; value=1: a PM save TST D0 ; Fore or back call BEQ.S @pmFore MOVE pmBkIndex(A0),rgb+red(A1) ; Save back entry number BRA.S @goHome @pmFore MOVE pmFgIndex(A0),rgb+red(A1) ; Save fore entry number @goHome RTD #4 @SaveRGB CLR value(A1) ; value=0: an RGB save PEA rgb(A1) ; Push pointer to rgb TST D0 ; Fore or back? BEQ.S @rgbFore _GetBackColor BRA.S @goHome @rgbFore _GetForeColor BRA.S @goHome ;--------------------------------------------------- ; ; PROCEDURE RestoreFore(VAR x:ColorSpec); AAA2/15; ; PROCEDURE RestoreBack(VAR x:ColorSpec); AAA2/16; ; ; Set the fore/back color from a colorspec ; with the following coding: ; value = 0 - rgb is an rgb color ; value = 1 - rgb.red is the previous palette entry number ; RestoreFore PROC Export EXPORT RestoreBack MOVE.L 4(SP),A1 ; A1->Spec to restore TST (A1)+ ; RGB or PM color? BNE.S forePM ; PM => do that PEA (A1) ; RGB => do that _RGBForeColor goHome RTD #4 forePM MOVE (A1),-(SP) _PMForeColor BRA.S goHome RestoreBack MOVE.L 4(SP),A1 ; A1->Spec to restore TST (A1)+ ; RGB or PM color? BNE.S backPM ; PM => do that PEA (A1) ; RGB => do that _RGBBackColor BRA.S goHome backPM MOVE (A1),-(SP) _PMBackColor BRA.S goHome ;--------------------------------------------------- ; ; PROCEDURE ReleaseList(selection:ReqListRec); AAA2/18; ; ; Have the palette manager release any entries in the ReqListRec. ; This is a pointer to a list of device indices in the same format ; as is passed to RestoreEntries. RestoreEntries should call this ; routine when passed NIL for the color table. ; ; Preserves standard toolbox regs: D3-D7/A2-A4 ; ReleaseList PROC EXPORT TST.L PMgrHandle BEQ.S @Nothing ; No PMgr, do nothing. MOVEM.L D3/D4/A2,-(SP) ; save regs, stack down 12 MOVE.L 16(SP),A2 ; A2->list of entries MOVE.L PMgrHandle,A0 MOVE.L (A0),A0 MOVE nDevs(A0),D0 ; D0 = number PMgr known devs LEA DevHandles(A0),A0 ; A0->list of PMgr known devs CLR D3 MOVE.L theGDevice,D1 @findDev CMP.L DevHandle(A0,D3*8),D1 ; Is it this device? BEQ.S @foundDev ; Yes => go zap some links. ADDQ #1,D3 CMP D0,D3 BLO @findDev BRA.S @GoHome ; Ran out of devices @foundDev LSL #8,D3 ; Get device in higher bits MOVE (A2)+,D4 ; D4=number of indices to clear @zapLoop MOVE (A2)+,D0 MOVE.B D0,D3 MOVE D3,-(SP) ; Push device/index combo _ZapLinks DBRA D4,@zapLoop @goHome MOVEM.L (SP)+,D3/D4/A2 @Nothing RTD #4 ;--------------------------------------------------- ; ;FUNCTION FindModeID(gd:GDHandle; depth: INTEGER):INTEGER; ; ; return the mode number (128-133 or so) for ; the requested depth on device "gd," ; or zero if no such mode available. ; (internal routine for SetDepth and HasDepth ; FindModeID FUNC Export RTS ;--------------------------------------------------- ; ;FUNCTION SetDepth(gd:GDHandle; depth: INTEGER; whichFlags:SHORT; flags:SHORT):OSErr; AAA2/19 ; ; SetDepth FUNC EXPORT whichMask EQU $00FF ; only allow user to change low byte of gdFlags SDVars RECORD {A6Link},DECREMENT result DS.B 2 ; boolean result gd DS.B 4 ; input: GDevice to set depth DS.B 2 ; input: depth to set to whichFlags DS.B 2 ; which GDFlags to affect flags DS.B 2 ; input: various flags return DS.B 4 ; return address on stack A6Link DS.B 4 ; link r DS.B 4 ; regionhandle oldPort DS.B 4 ; previous port myRect DS.B 8 ; rectangle for little black corners moreStuff DS.B 10 ; not sure what for? linkSize DS.B 0 ; size of record ENDR WITH SDVars LINK A6,#linkSize MOVEM.L A2-A3/D3-D5,-(SP) ; <6> MOVE #paramErr,result(A6) ; default to failure! MOVE.B #1,myRect+6(A6) MOVEQ #0,D0 MOVE depth(A6),D0 MOVE.L D0,r(A6) CLR -(SP) MOVE.L gd(A6),-(SP) CLR.L -(SP) MOVE.L r(A6),-(SP) PEA oldPort(A6) CLR.L -(SP) PEA myRect+7(A6) MOVE #$C12,D0 ; _DMRemoveDisplay DC.W $ABEB TST (SP)+ BNE.S @goHome MOVE.L oldPort(A6),D0 BTST.L #1,D0 BNE.S @goHome MOVE.L gd(A6),A1 MOVE.L (A1),A1 MOVE whichFlags(A6),D0 ; D0 = mask of flags to change ANDI #whichMask,D0 ; D0 = only the ones we let them change MOVE D0,D1 ; D1 = mask of flags to change AND flags(A6),D1 ; D1 = only the flags to change NOT D0 ; D0 = mask of flags to keep AND gdFlags(A1),D0 ; D0 = all the unchanged gdFlags OR D1,D0 ; D0 = new gdFlags word MOVE D0,gdFlags(A1) ; Put back into gDevice CLR -(SP) MOVE.L gd(A6),-(SP) CLR.L -(SP) PEA r(A6) CLR.L -(SP) CLR.L -(SP) MOVE #$A11,D0 ; _DMEnableDisplay DC.W $ABEB MOVE (SP)+,result(A6) @goHome MOVEM.L (SP)+,A2-A3/D3-D5 UNLK A6 RTD #result-return-4 ;--------------------------------------------------- ; ;FUNCTION HasDepth(gd:GDHandle; depth: INTEGER; whichFlags:SHORT; flags:SHORT):BOOLEAN; ; ; HasDepth FUNC EXPORT whichMask EQU $FFFE ; the lowest bit is settable, else fail SDVars RECORD {A6Link},DECREMENT result DS.B 2 ; 18 $12 boolean result gd DS.B 4 ; 14 $E input: GDevice to set depth DS.B 2 ; 12 $C input: depth to set to whichFlags DS.B 2 ; 10 $A which GDFlags to affect flags DS.B 2 ; 8 $8 input: various flags return DS.B 4 ; 4 $4 return address on stack A6Link DS.B 4 ; link myDepth DS.B 4 moreStuff DS.B 24 linkSize DS.B 0 ; size of record ENDR WITH SDVars LINK A6,#linkSize CLR result(A6) ; default to failure! MOVE whichFlags(A6),D0 ; D0 = mask of flags to change AND flags(A6),D0 ; D0 = new flags to set AND #whichMask,D0 ; D0 = all the bits we can't change BNE @goHome ; User tried to set bits we don't yet do! MOVEQ #0,D0 MOVE depth(A6),D0 MOVE.L D0,myDepth(A6) CLR moreStuff+0(A6) CLR.L moreStuff+2(A6) CLR moreStuff+6(A6) CLR.L moreStuff+8(A6) CLR.L moreStuff+12(A6) CLR -(SP) MOVE.L gd(A6), -(SP) PEA moreStuff(A6) MOVE.L myDepth(A6), -(SP) PEA -$C(A6) CLR.L -(SP) MOVE #$AF3,D0 ; unknown _DisplayDispatch selector DC.W $ABEB TST (SP)+ BNE.B @goHome MOVEQ.L #$7F, D0 MOVEQ.L #0, D1 MOVE depth(A6), D1 CMP.L D1, D0 BLT.B @whaaa MOVE $C(A6), D0 CMP -$C(A6), D0 BNE.B @goHome @whaaa MOVE -$1C(A6), $12(A6) @goHome UNLK A6 RTD #result-return-4 ;--------------------------------------------------- ; ;FUNCTION PMgrVersion:INTEGER; AAA2/21; ; ; PMgrVersion FUNC EXPORT MOVE #PMgrVersNum,4(SP) ; stash it above the return address CLR D0 ; no error RTS ;--------------------------------------------------- ; ;PROCEDURE SetPaletteUpdates(PaletteHandle, Integer); AAA2/22; ; ; Set the type of color updates that this palette will receive, ; from the xxxPaletteUpdates constants. ; ; (We don't check for nil being passed; it must be a real palette). SetPaletteUpdates PROC EXPORT SPUVars RECORD {A6Link},DECREMENT result DS.B 0 ; no result srcPalette DS.B 4 ; input: Palette to set updateMode DS.B 2 ; input: new update level return DS.B 4 ; return address on stack A6Link DS.B 4 ; link linkSize DS.B 0 ; size of record ENDR WITH SPUVars LINK A6,#linkSize MOVE.L srcPalette(A6),A0 MOVE.L (A0),A0 ; A0->palette MOVE updateMode(A6),D0 LSL #8,D0 ; Move those two bits high LSL #6,D0 ; Move those two bits high AND #$C000,D0 MOVE pmPrivate(A0),D1 AND #$3FFF,D1 OR D0,D1 MOVE D1,pmPrivate(A0) UNLK A6 CLR.L D0 ; No error RTD #result-return-4 ;--------------------------------------------------- ; ;FUNCTION GetPaletteUpdates(PaletteHandle, Integer):INTEGER; AAA2/23; ; ; inverse of SetPaletteUpdates ; GetPaletteUpdates PROC EXPORT GPUVars RECORD {A6Link},DECREMENT result DS.B 2 ; result: update level srcPalette DS.B 4 ; input: Palette to look at return DS.B 4 ; return address on stack A6Link DS.B 4 ; link linkSize DS.B 0 ; size of record ENDR WITH GPUVars LINK A6,#linkSize MOVE.L srcPalette(A6),A0 MOVE.L (A0),A0 MOVE pmPrivate(A0),D0 LSR #8,D0 LSR #6,D0 MOVE D0,result(A6) UNLK A6 CLR.L D0 RTD #result-return-4 ;--------------------------------------------------- ; ; FUNCTION GetGray(device: GDHandle, backGround: RGBColor; ; VAR foreGround: RGBColor): BOOLEAN; AAA2/25; ; GetGray PROC EXPORT GGVars RECORD {A6Link},DECREMENT result DS.B 2 ; result: BOOLEAN device DS.B 4 ; device to check bGround DS.B 4 ; input: backGound Color fGround DS.B 4 ; variable parameter foreGround Color return DS.B 4 ; return address on stack A6Link DS.B 4 ; link oldGD DS.B 4 ; GDevice before we started realFore DS.B 6 ; actual RGBValue of foreGround realBack DS.B 6 ; actual RGBValue of backGround calcAvg DS.B 6 ; calculated average realAvg DS.B 6 ; real average linkSize DS.B 0 ; size of record ENDR WITH GGVars LINK A6,#linkSize MOVE.L A2, -(SP) CLR.B result(A6) ; Assume false MOVE.L TheGDevice, oldGD(A6) TST.L device(A6) BEQ.S @theDeviceSet MOVE.L device(A6), TheGDevice @theDeviceSet SUBQ #4, SP MOVE.L bGround(A6), -(SP) _Color2Index PEA realBack(A6) _Index2Color SUBQ #4, SP MOVE.L fGround(A6), -(SP) _Color2Index PEA realFore(A6) _Index2Color LEA realFore(A6), A0 LEA realBack(A6), A1 LEA calcAvg(A6), A2 MOVEQ #2, D1 @addLoop MOVE.W (A0)+, D0 ADD.W (A1)+, D0 ROXR #1, D0 BMI.S @lighterThanHalf ADDQ #2, D0 @lighterThanHalf MOVE.W D0, (A2)+ DBRA D1, @addLoop SUBQ #4, SP PEA calcAvg(A6) _Color2Index PEA realAvg(A6) _Index2Color MOVE.L oldGD(A6), TheGDevice SUBQ #2,SP PEA realFore(A6) PEA realAvg(A6) JSR DeltaRGB SUBQ #2,SP PEA realBack(A6) PEA realAvg(A6) JSR DeltaRGB SUBQ #2,SP PEA calcAvg(A6) PEA realAvg(A6) JSR DeltaRGB MOVE (SP)+,D0 ; D0 = delta to self MOVE (SP)+,D1 ; D1 = delta to back MOVE (SP)+,D2 ; D2 = delta to fore LSR #1,D1 ; bias to prefer pattern LSR #1,D2 ; unless there's a good match CMP D1,D0 ; Are we closer to back? BHS.S @twoColor ; yes => dither CMP D2,D0 ; Are we closer to fore? BHS.S @twoColor ; yes => dither MOVE.B #1, result(A6) ; return true MOVE.L fGround(A6), A0 LEA realAvg(A6), A1 MOVE.L (A1)+, (A0)+ MOVE.W (A1)+, (A0)+ @twoColor MOVE.L (SP)+, A2 UNLK A6 CLR.L D0 RTD #result-return-4 ENDPROC ;--------------------------------------------------- ; ; FUNCTION CheckColors(device:GDHandle,colors:CTabHandle; ; maxTolerance,maxAveTolerance:INTEGER):BOOLEAN; AAA2/24; ; ; See if the list of color specified can be displayed nicely on ; theGDevice. CheckColors PROC EXPORT CCVars RECORD {A6Link},DECREMENT result DS.B 2 ; result: BOOLEAN device DS.B 4 ; device to check colors DS.B 4 ; input: color list to check maxTol DS.B 2 ; maximum tolerance for each color maxAveTol DS.B 2 ; maximum average tolerance return DS.B 4 ; return address on stack A6Link DS.B 4 ; link oldGD DS.B 4 ; GDevice before we started ;colorCount DS.B 2 ; ctSize+1 aColor DS.B 6 ; scratch rgb bColor DS.B 6 ; another scratch rgb hState DS.B 2 ; handle state of clut linkSize DS.B 0 ; size of record ENDR WITH CCVars LINK A6,#linkSize MOVEM.L A2-A3/D3-D7,-(SP) MOVE.L TheGDevice,oldGD(A6) MOVE.L device(A6),D0 ; did the user specify a GDevice? BEQ.S @noDevice MOVE.L D0,TheGDevice @noDevice MOVE.B #1,result(A6) ; Assume True MOVEA.L TheGDevice, A0 ; get a handle to TheGDevice MOVEA.L (A0), A0 ; dereference the Handle CMPI.W #$2, gdType(A0) ; check if the device is direct (16 or 32 bits) BEQ.S @exit MOVEA.L gdPMap(A0), A0 ; Get the PixMapHandle MOVEA.L (A0), A0 ; Get the PixMapPtr MOVEA.L pmTable(A0), A0 ; Get the PixMap CTabHandle MOVEA.L (A0), A0 ; Get the CTabPtr MOVE.L ctSeed(A0), D0 ; Get the Seed MOVEQ #(8+32), D1 ; check for 8-bit grey-scale CMP.L D0, D1 BEQ.S @exit MOVE.L colors(A6), A0 ; Get the input color table handle MOVE.L (A0), A0 ; dereference MOVE.L ctSeed(A0), D1 ; get the Seed CMP.L D0, D1 ; check if seeds are identical BEQ.S @exit MOVEQ #(4+32), D1 ; check for 4-bit gray-scale destination CMP.L D0, D1 BEQ.S @exit ; MOVE.W ctSize(A0), D1 ; our device clut is four-bit gray-scale and we're checking that the source clut is four-bits or less ; CMPI.W #15, D1 ; BLS.S @exit ;@doneChecking CLR result(A6) ; default to "false" = failure CLR.L D7 ; D7 = total color deltas MOVE.L colors(A6), A0 _HGetState ; A0 already contains the handle to the ColorTable MOVE D0,hState(A6) ; D6 = previous colors memstate _HLock MOVE.L (A0),A2 ; A2->color table to check MOVE ctSize(A2),D3 ; D3 = last color in table BEQ.S @goHome MOVEQ #0, D5 ; initialized number of colors checked ; MOVE D3,D0 ; ADDQ #1,D0 ; MOVE D0,colorCount(A6) ; save count of colors ; MOVEQ #-1, D6 ; set D6 to impossible value for index check. ADDQ #8,A2 ; A2->1st color in table @loop MOVEQ #4, D0 ; set bit 2 in D0 AND.W (A2), D0 ; test inhibit bit in value field of colorSpec BNE.S @next ; skip this color if the bit is set ADDQ.L #1, D5; ; increment number of colors checked BSR.S @color2color ; Get D5=index, D0=delta, D7 = ·deltas ; CMP.L D6,D5 ; Does it match the last one? ; BEQ.S @gohome ; Yes=>unacceptable CMP maxTol(A6),D0 ; Are we within maximum tolerance? BHI.S @goHome ; No=>fail ; MOVE.L D5,D6 ; get last index here @next ADDQ #8,A2 ; Bump to next color DBRA D3,@loop ; loop through all colors TST D5 BEQ.S @goHome DIVU D5,D7 ; compute average tolerance ; DIVU colorCount(A6),D7 ; compute average tolerance CMP maxAveTol(A6),D7 ; in range? BHI.S @goHome ; No=>don't set result true MOVE.B #1,result(A6) ; We made it through all the colors @gohome MOVE.L colors(A6),A0 MOVE hState(A6),D0 ; old handle state _HSetState @exit MOVE.L oldGD(A6),TheGDevice ; restore gdevice MOVEM.L (SP)+,A2-A3/D3-D7 UNLK A6 CLR.L D0 RTD #result-return-4 @color2color ;convert rgb A2+2 to index in D5, and back to color, delta in D0 SUBQ #4,SP ; space for result PEA 2(A2) _Color2Index ; MOVE.L (SP),D5 ; get color's index in D5 PEA aColor(A6) ; place to get actual color _Index2Color SUBQ #2,SP PEA aColor(A6) PEA 2(A2) JSR DeltaRGB CLR.L D0 MOVE (SP)+,D0 ; Get delta into D0 ADD.L D0,D7 ; Sum the delta into D7 RTS ;--------------------------------------------------- ; ; PROCEDURE PMgrDispatch(selector:INTEGER); AAA2; ; ; Here, we divvy up our last trap amongst a whole bunch of functions, using D0 ; as a selector. All registers preserved during dispatch except D0. PROC EXPORT PMgrDispatch procTable switch00 DC Entry2Index-procTable ; public choices switch01 DC Index2Entries-procTable switch02 DC RestoreDeviceClut-procTable switch03 DC ResizePalette-procTable switch04 DC ZapLinks-procTable switch05 DC WhatPal-procTable switch06 DC PMgrFinalError-procTable switch07 DC PMgrFinalError-procTable switch08 DC PMgrFinalError-procTable switch09 DC PMgrFinalError-procTable switch10 DC DeltaRGB-procTable ; secret choices switch11 DC NewHiliteColor-procTable switch12 DC PMgrExit-procTable switch13 DC SaveFore-procTable switch14 DC SaveBack-procTable switch15 DC RestoreFore-procTable switch16 DC RestoreBack-procTable switch17 DC PMgrFinalError-procTable switch18 DC ReleaseList-procTable switch19 DC SetDepth-procTable switch20 DC HasDepth-procTable switch21 DC PMgrVersion-procTable switch22 DC SetPaletteUpdates-procTable switch23 DC GetPaletteUpdates-procTable switch24 DC CheckColors-procTable switch25 DC GetGray-procTable switchMax EQU (*-procTable)/2 ; Say, don't forget that each pmgr dispatch must set D0 to zero on return! PMgrDispatch CMP.B #switchMax,D0 ; Is this (yet) a real function? BHS.S PMgrFinalError ; No! Bye! MOVE.L A0,-(SP) ; preserve A0 LEA procTable,A0 ; A0->list of proc pointers AND #$00FF,D0 ; Only use low byte for offset MOVE (A0,D0*2),D0 ; Get offset to the one we want ADDA D0,A0 ; Add offset MOVE.L A0,-(SP) ; Push target as return address MOVE.L 4(SP),A0 ; Restore A0 RTD #4 ; Go there. Straight. PMgrFinalError LSR #8,D0 ; Get to high byte of D0: arg count MOVE.L (SP)+,A0 ; Pop return address ADD D0,SP ; Remove those args MOVEQ #-1,D0 ; Error condition JMP (A0) ; bye. ENDPROC ;--------------------------------------------------- ; Thus ends the PaletteManager - ah, a sad thing it is, to be done. But WAIT! There's ; MORE! Let's patch RGBFORECOLOR and RGBBACKCOLOR just for grins! Yeah! IF NOT ROMPaletteMgr THEN ; no patches for the ROM version RWH.C864 IF NOT JacksonPollack THEN ; (skip RGBFore/Back, since JP knows it) ;--------------------------------------------------- ; ; procedure RGBForeColor (Color : RGBColor); ; ; This routine takes an RGB triple and sets the current Graf- or CGrafPort ; fields so that drawing will take place with the best match of the ; requested color, using the current GDevice's color matching rules. The ; appropriate fields are set depending on portType ; ; AppleSystemPatch PaletteMgr.a 10Mar87 #PB103 (RGBForeColor) (RGBForeColor) RGBForeColor PROC EXPORT EXPORT RGBBackColor,RGB2OLD StdDevCall Equ $1D2A0 ; RGBForeColor; RGBBackColor is $4081D2B0 StdDevMask Equ $FFFFFFEF ; the calls are different only at bit 4! MOVEQ #FGCOLOR,D0 ; get offset to index field MOVEQ #RGBFgColor,D1 ; get offset to RGB field SHARE MOVE.L 4(SP),A1 ; point at the RGB color MOVE.L GRAFGLOBALS(A5),A0 ; get the QuickDraw globals pointer MOVE.L THEPORT(A0),A0 ; point at the port PEA 0(A0,D0) ; save pointer to the index field TST PORTBITS+ROWBYTES(A0) ; is it a new port? BMI.S NEWPORT ; => yes, set RGB components JSR RGB2OLD ; else convert RGB to old color BRA DONE ; => ; To keep the stack correct we will momentarily preempt A1. We can restore it in a bit. ; Also, since we no longer need the offset to the index field NewPort Move.L GrafVars(A0),A1 ; get the GrafVars handle CmpA.L #Nil,A1 ; is it nil? Beq.S PuntPmCalls ; yes => punt and do the normal call Move.L (A1),A1 ; dereference it into A1 Move.L 4(SP),D2 ; get the return address Sub.l ROMBase, D2 ; Make it offset within ROM, And.L #StdDevMask,D2 ; and it with the std mask Cmp.L #StdDevCall,D2 ; is it from StdDevLoop? Bne.S NormalCall ; no => make the normal call Tst.L PmFgColor(A1) ; is there a palette? EHB.PBnnn Bne.S FoundAPltt ; yes => we can do it AWC.PB508 Tst.L AppPalette ; is there an AppPalette? AWC.PB508 Beq.S NormalCall ; => no, do normal call EHB.PBnnn FoundAPltt Move PmFlags(A1),D2 ; get the Palette Manager flags AWC.PB508 Cmp #FgColor,D0 ; was it forecolor? Bne.S GetBack ; no => get back color flag BTst #PmFgBit,D2 ; did PmForeColor set up this port? Beq.S PuntPmCalls ; no => continue normally AddQ #4,SP ; we won't need the pointer to the index Move pmFgIndex(A1),-(SP) ; push the entry number _PmForeColor ; set the port using PmForeColor Bra.S GoHome ; all finished GetBack BTst #PmBkBit,D2 ; did PmBackColor set up this port? Beq.S PuntPmCalls ; no => continue normally AddQ #4,SP ; we won't need the pointer to the index Move pmBkIndex(A1),-(SP) ; push the entry number _PmBackColor ; set the port using PmBackColor Bra.S GoHome ; all through NormalCall Move PmFlags(A1),D2 ; get flags Cmp #FgColor,D0 ; is this a foreground call? Bne.S NotFgCall ; no => clear PmBkBit BClr #PmFgBit,D2 ; clear the foreground flag bit Bra.S CommonFlags ; reunite it NotFgCall BClr #PmBkBit,D2 ; clear the background flag bit CommonFlags Move D2,PmFlags(A1) ; save the flags to GrafVars PuntPmCalls Move.L 8(SP),A1 ; restore the pointer to the RGBColor ; Here is the normal RGBForeColor code code MOVE.L red(A1),red(A0,D1) ; copy red and green components to the port MOVE.W blue(A1),blue(A0,D1) ; and blue too ; make an rgbColor on the stack MOVE.L green(A1),-(SP) ; copy green and blue MOVE.W red(A1),-(SP) ; copy red SUBQ #4,SP ; make room for function return PEA 4(SP) ; push pointer to rgb _Color2Index ; convert it to an index MOVE.L (SP)+,D0 ; get the index result ADDQ #6,SP ; get rid of the rgbColor Done MOVE.L (SP)+,A0 ; get pointer to index field MOVE.L D0,(A0) ; and set the index field GoHome Rtd #4 ; all done RGB2OLD ;----------------------------------------------- ; ; UTILITY TO CONVERT AN RGB (POINTED TO BY A1) VALUE ; TO AN OLD STYLE COLOR VALUE. RETURNS VALUE IN D0. CLOBBERS A0,D1 ; ; USES HIGH BIT OF EACH COMPONENT TO SELECT RGB OFF (0) OR ON (1) MOVEQ #0,D1 ; clear out D1 MOVE (A1)+,D1 ; get red ADD.L D1,D1 ; get high bit MOVE (A1)+,D1 ; get green ADD.L D1,D1 ; get high bit MOVE (A1)+,D1 ; get blue ADD.L D1,D1 ; get high bit SWAP D1 ; get RGB index noBlue LEA MapTbl,A0 ; get translate table MOVEQ #0,D0 ; clear out high word MOVE 0(A0,D1*2),D0 ; convert to planar value RTS ; => all done ; TABLE TO MAP FROM 3 BIT RGB TO OLD-STYLE COLOR INDICES MapTBL DC.W blackColor ; RBG = 0,0,0 -> black DC.W blueColor ; RBG = 0,0,1 -> blue DC.W greenColor ; RBG = 0,1,0 -> green DC.W cyanColor ; RBG = 0,1,1 -> cyan DC.W redColor ; RBG = 1,0,0 -> red DC.W magentaColor ; RBG = 1,0,1 -> magenta DC.W yellowColor ; RBG = 1,1,0 -> yellow DC.W whiteColor ; RBG = 1,1,1 -> white ;--------------------------------------------------- ; ; procedure RGBBackColor (Color : RGBColor); ; ; This routine takes an RGB triple and sets the current Graf- or CGrafPort ; fields so that drawing will take place with the best match of the ; requested color, using the current GDevice's color matching rules. The ; appropriate fields are set depending on portType. ; ; AppleSystemPatch PaletteMgr.a 10Mar87 #PB103 (RGBBackColor) (RGBBackColor) RGBBackColor MOVEQ #BKCOLOR,D0 ; get offset to the index field MOVEQ #RGBBkColor,D1 ; get offset to RGB field BRA SHARE ; => and use common code ENDIF ;(Jackson Pollack) IF PatchGetCTable THEN ;(This GetCTable was copied out of ColorMgr.a, and is used for patching ; when we install the new palette manager without 32-bit quickdraw.) ;--------------------------------------------------- ; ; FUNCTION myGetCTable(ID:INTEGER):Handle; ; ; Get a 'clut' resource of the specified ID, as a non-resource ; handle. Unless, of course, the number is 32+[1,2,4,8] in which ; case we return a gray scale of that size. Or if the number is ; 64+[1,2,4,8] we'll return a clut with a hilite modification. ; ; Passing 64 plus other than 1, 2, 4, or 8 will yield strange results. ; ; stack like this: (SP) return.L, 4(SP) depth.W, 6(SP) result handle.L ; ; for whole routine PROC EXPORT MyGetCTable GrayMuls DC.W $FFFF,$5555,$0000,$1111,$0000,$0000,$0000,$0101 ; ; gray multiplier 1-bit 2-bit 4-bit 8-bit doGrayClut AND #$F,D0 ; Mask the graybit MOVE D0,4(SP) ; Put it in the passed param CLR.L D1 ADDQ #3,D0 ; + 3 becomes * 8 on next line, for c-Spec size BSET D0,D1 ; 2 to the nth ADDQ.L #8,D1 ; Add size of ctab header MOVE.L D1,D0 ; Here, for newhandle _NewHandle ; Get a brand new colortable BEQ.S @gotGrayH ; Did we? CLR.L 6(SP) ; No=>return nil RTD #2 @gotGrayH MOVE 4(SP),D0 ; Get depth again LEA GrayMuls-2,A1 ; A1->our gray multiplier table <2.1> MOVE.w (A1,D0*2),D1 ; D1.w = color step for this bit depth move.w d1,d2 ; copy into d2 swap d2 ; set up high word move.w d1,d2 ; replicate throughout long MOVE.L (A0),A1 ; A1->our brand new ctable clut move.w #$8000,transIndex(A1) ; mark as device clut CLR D1 ; From bit depth, BSET D0,D1 ; Generate number of entries SUBQ #1,D1 ; Minus one, for ctSize silliness MOVE D1,ctSize(A1) ; Set size of colortable CMPI #3,D0 ; Size 1 or 2 bits? BLT.S @graySeed ; Yes => don't call it GrayScale by seed ADD #32,D0 ; Constant +32 for GrayScale seeds @graySeed MOVE.L D0,ctSeed(A1) ; Jam seed LEA ctTable(A1),A1 ; A1->first colorSpec MOVEQ #-1,D0 ; Lowest index is white MOVEQ #0,D1 ; D1 will be .value fields @grayLoop MOVE D1,(A1)+ ; put pixel value in .value field ADDQ #1,D1 ; MOVE.L D0,(A1)+ ; Stash red and green MOVE D0,(A1)+ ; Stash blue, A1->next cSpec SUB.L D2,D0 ; Bump D0 to next reasonable value BCC.S @grayLoop ; Until we go under zero, beyond black BRA GoHome doHiliteClut AND #$F,D0 ; Mask the hilitebit MOVE D0,-(SP) ; Push it for the Resource read BSR ReadIt ; Okay, read it. MOVE.L A0,D0 ; A good thing? BEQ GoHome ; No=>go home (with NIL from A0) MOVE.L (A0),A1 ; A1->color table SUBQ #4,SP ; Space for new seed _GetCTSeed ; Get that new seed MOVE.L (SP)+,ctSeed(A1) ; Put seed into synthetic table MOVE 4(SP),D0 ; D0 = clutID again BTST #1,D0 ; Two bit mode? BEQ.S checkFour ; No=>check other stuff ; If the hilite color is a gray then CLUT is OK <2.2> LEA HiliteRGB,A1 ; Point at hilite color <2.2> MOVE.B red(A1),D1 ; Get red msb <2.2> CMP.B green(A1),D1 ; green same as red? <2.2> BNE.S @notGray ; no, go use it. <2.2> CMP.B blue(A1),D1 ; blue same as red and green? <2.2> BEQ GoHome ; yes, leave clut alone. <2.2> @notGray MOVE.L (A0),A1 ; A1->color table <2.2> LEA ctTable+8+rgb(A1),A1 ; Bump A1 to 2nd entry.rgb.red MOVE.L #$7FFF7FFF,(A1)+ ; Put 50% gray into red,green MOVE #$7FFF,(A1)+ ; and blue ADDQ #2,A1 ; Bump past .value field in third entry MOVE.L HiliteRGB,(A1)+ ; Put hilite color into red,green MOVE HiliteRGB+blue,(A1) ; and blue. BRA GoHome checkFour BTST #2,D0 ; Four bit mode? BEQ GoHome ; No => must be 1 or 8-bit, so we're done. MOVE #14,D2 ; DBRA counter, skipping white MOVE.L #$0001FFFF,D1 ; Lo word = error distance, Hi word = best index @B4loop SUBQ #2,SP ; space for result PEA HiliteRGB ; push system hilite color PEA ctTable+rgb(A1,D2*8) ; push color we're checking JSR DeltaRGB MOVE (SP)+,D0 CMP D0,D1 BLS.S @B4loopEnd MOVE D0,D1 ; Get new smallest delta SWAP D1 ; D1 = Get index number in low word MOVE D2,D1 ; Get new closest index SWAP D1 ; D1 = Put delta back to low word @B4loopEnd SUBQ #1,D2 BNE.S @B4loop ; Loop on down, but skip zero CMPI #$3000,D1 ; Are we pretty darned tolerant? BLS.S GoHome ; Yes=> we're fine, go home SWAP D1 LEA ctTable+rgb+red(A1,D1*8),A1 ; A1->RGB to tweak @realClose MOVE.L HiliteRGB+red,D0 ; D0 = hilite r,g SWAP D0 ; D0.W = red ADD red(A1),D0 ; D0.W = hilite red+old red ROXR #1,D0 ; Average MOVE D0,red(A1) ; write red SWAP D0 ADD green(A1),D0 ; D0.W = hilite green+old green ROXR #1,D0 ; Average MOVE D0,green(A1) ; write green MOVE HiliteRGB+blue,D0 ; D0.W = hilite blue ADD blue(A1),D0 ROXR #1,D0 ; Average MOVE D0,blue(A1) ; write blue SUBQ #2,SP ; space for result PEA HiliteRGB ; Have we really got the hilite PEA (A1) ; color within a reasonable range? JSR DeltaRGB ; Let's see. CMPI #$3000,(SP)+ ; 3000 is good enough to look decent. BHI.S @realClose ; But, its not there yet, so avg again. BRA.S GoHome myGetCTable MOVE 4(SP),-(SP) ; First, try to read a resource BSR.S ReadIt ; (do that) MOVE.L A0,D0 ; Get anything? BEQ.S notRes ; No=>try other means GoHome MOVE.L A0,6(SP) ; Yes=>stash it RTD2 RTD #2 ; roger and out. notRes MOVE 4(SP),D0 ; Get requested ID CMPI #72,D0 ; 72 is the highest we can noodle BHI.S RTD2 MOVE.L #$00000116,D1 ; Bits 1, 2, 4, and 8 are set BTST D0,D1 ; Are low 5 bits in [1,2,4,8]? BEQ.S RTD2 BTST #5,D0 BNE.S doGrayClut ; 32+[1,2,4,8] BTST #6,D0 BNE.S doHiliteClut ; 64+[1,2,4,8] BRA.S RTD2 readIt SUBQ #4,A7 ; space for result MOVE.L #'clut',-(SP) ; resource type MOVE 12(SP),-(SP) ; push ID number _GetResource ; Get it. MOVE.L (A7)+,D0 ; D0 = resource handle. BEQ.S @tryROM ; (OR NOT!) maybe the ROM has it. MOVE.L D0,-(SP) ; Push to save it, a moment. MOVE.L D0,-(SP) ; Push to detach it _DetachResource ; It's no longer a resource MOVE.L (SP)+,A0 ; We'll return it in A0. _HNoPurge ; make this non-purgeable (if it was) <16May89> DAF MOVE.L (A0),A1 ; But first, SUBQ #4,SP ; Number one, _GetCTSeed ; Since we don't know where its been MOVE.L (SP)+,(A1) ; A Fresh seed. BRA.S @doneRead ; return, sans ID @tryROM MOVE #-1,RomMapInsert ; This time, try 'da ROM SUBQ #4,SP ; result MOVE.L #'clut',-(SP) ; resource type MOVE 12(SP),-(SP) ; resource ID _GetResource ; Get it. MOVE.L (A7)+,D0 BEQ.S @readFail ; It wasn't there! Not at all! MOVE.L D0,A0 ; Put here for hand to hand _HandToHand ; Make a normal handle from ROM resource BEQ.S @doneRead ; Made it? If so, return, sans ID @readFail SUBA.L A0,A0 ; A miserable failure. @doneRead RTD #2 ; Lose ID, and go home. ENDIF IF PatchInitGDevice THEN ;========================================================================================= ;========================================================================================= ; ; Patch to InitGDevice. Add support for GDevices with baseAddrs that change across ; depths (Trident card) in a MultiFinder friendly way. ; ;========================================================================================= ;========================================================================================= myInitGDevice PROC EXPORT iiROMGetDevPixMap EQU $18FC0 WITH VDPageInfo ;<1.1> ;------------------------------------------------------------- ; ; PROCEDURE InitGDevice (refNum: INTEGER; mode: LONGINT; GDH: GDHandle); ; ; Initialize the specified device to the specified mode. The GDevice ; data is placed into the provided handle. ; ; If mode = -1 then the driver is not called. It is assumed that the pixmap ; has been set up before InitGDevice is called. ; ; CAUTION: this routine is used during ROM boot; various Macintosh functions ; may not yet be available! ; IGDVars RECORD {A6Link},DECREMENT result DS.B 0 ; no result REFNUM DS.B 2 MODE DS.B 4 ; LONG, mode for video card GDH DS.B 4 ; LONG, handle to devPort return DS.B 4 ; the return address A6Link DS.B 4 ; our link IOPBlk DS.B IOVQElSize ; [64] parameter blk for I/O calls VidParms DS.B 12 ; [12] size of mode params GDHState DS.B 2 ; [word] lock state of GDH GDPState DS.B 2 ; [word] lock state of GDP SaveDevice DS.B 4 ; [long] saved device handle oldBaseAddr DS.B 4 ; old base address, for later comparison oldPort DS.B 4 ; thePort, before we got here oldColor DS.B 8 ; a colorSpec used to reinstantiate fg/bk VARSIZE DS.B 0 ; size of locals ENDR WITH IGDVars LINK A6,#VARSIZE ; allocate stack frame MOVEM.L D3/A2-A4,-(SP) ; save off work registers MOVE.L GDH(A6),A0 ; get the gDevice handle _HGetState ; get the current lock state MOVE D0,GDHState(A6) ; save the state _HLOCK ; and lock down the gDevice MOVE.L (A0),A2 ; get pointer to gDevice record MOVE.L GDPMap(A2),A0 ; get handle to pixMap MOVE.L (A0),A1 ; A1->pixmap MOVE.L baseAddr(A1),oldBaseAddr(A6) ; save the base address, for later portfixing _HGetState ; get the current lock state of the pixmap MOVE D0,GDPState(A6) ; save the state _HLOCK ; lock it down MOVE.L (A0),A3 ; keep pointer in A3 MOVE.L theGDevice,SaveDevice(A6) ; save theGDevice TST.B QDExist ; qd around? BNE.S @noShield ; no, don't shield cursor BTST #screenDevice,gdFlags(A2) ; is it screen (check hi byte with #>8) BEQ.S @noShield PEA gdRect(A2) CLR.L -(SP) ; in global cošrds _ShieldCursor @noShield ; initialize the GDevice's mode and refnum MOVE REFNUM(A6),GDRefNum(A2) ; set up RefNum MOVE.L MODE(A6),D0 ; get the mode CMP.L MinusOne,D0 ; is the mode -1? BEQ ModeOK ; if so, then don't call the driver ; set up the driver parameter block in case we need to use it LEA IOPBlk(A6),A0 ; point to parameter block CLR.L ioCompletion(A0) ; no completion routine CLR.W ioVRefNum(A0) ; no volRefNum MOVE RefNum(A6),ioRefNum(A0) ; set device's refnum LEA VidParms(A6),A1 ; point to params for GetMode MOVE.L A1,csParam(A0) ; point to param list CMP.L GDMode(A2),D0 ; has the mode changed? BEQ GrayOrColor ; => no, so don't set depth MOVE.L D0,GDMode(A2) ; set up mode ; setup the gDevice fields for the new screen depth CLR GDCCDepth(A2) ; invalidate cursor depth MOVEM.L A0/A1,-(SP) ; save these regs MOVE REFNUM(A6),-(SP) ; push refnum MOVE.L MODE(A6),-(SP) ; push mode MOVE.L GDPMap(A2),-(SP) ; pixMap handle PEA GDType(A2) ; point to device type jsrROM iiROMGetDevPixMap ; read in pixMap from device MOVEM.L (SP)+,A0/A1 ; restore them ; first, set the mode (A0 points to IOPB, A1 to control parameter block) MOVE #2,csCode(A0) ; csc_GetMode MOVE.L mode(A6),D0 ; get the mode MOVE D0,csMode(A1) ; set desired mode CLR csPage(A1) ; set page 1 CLR.L csData(A1) ; no additional data _Control ,IMMED ; SetMode(Mode,Page,Data); ; then gray the screen MOVE #5,csCode(A0) ; csc_GrayPage _Control ,IMMED ; paint current page gray ; set the device to color or monochrome, according to GDFlags GrayOrColor MOVE GDFlags(A2),D0 ; get flags word NOT D0 ; flip all bits AND #1,D0 ; clear all but low bit MOVE.B D0,csMode(A1) ; csMode = color/gray scale MOVE #6,csCode(A0) ; csc_SetGray _Control ,IMMED ; set color or monochrome ; if the device has a color table, set the device's color table CMP #ClutType,GDType(A2) ; is there a lookup table? BNE.S NoTbl ; =>no, don't set one MOVE.L pmTable(A3),A0 ; get handle to color table _HLock ; lock down the color table ;+++ LEA VidParms(A6),A1 ; point to params for SetEntries MOVE.L (A0),A0 ; get ctabPtr CLR.W csStart(A1) ; start at zero, use sequence mode MOVE.W ctSize(A0),csCount(A1) ; for the length of the table LEA ctTable(A0),A0 ; get pointer to colorspecs MOVE.L A0,csTable(A1) ; color table pointer is first param LEA IOPBlk(A6),A0 ; point to parameter block MOVE.W #3,csCode(A0) ; csc_SetEntries MOVE.L A1,csParam(A0) ; move addr of parms into block _Control ,IMMED ; SetEntries(ColorTable); MOVE.L pmTable(A3),A0 ; get handle to color table _HUnlock ; unlock the color table NoTbl ; if CLUT or fixed color table, build inverse table CMP #DirectType,GDType(A2) ; should there be an inverse table? BEQ.S ModeOK ; =>no inverse table MOVE.L pmTable(A3),-(SP) ; push color table handle MOVE.L GDITable(A2),-(SP) ; push inverse table handle MOVEQ #4,D0 ; make 4-4-4 inverse tables MOVE D0,GDResPref(A2) ; save in GDevice MOVE D0,-(SP) ; and push res _MakeITable ; and generate table ; If this device has not been initialized from the system file, then copy the ; bounds from the pixMap to the GDRect. Otherwise copy the GDRect to the Bounds. ModeOK LEA BOUNDS(A3),A0 ; point to pixmap.bounds LEA GDRECT(A2),A1 ; point to device's global rect MOVE GDFlags(A2),D0 ; get the flags word BTST #RAMInit,D0 ; initialized from RAM? BEQ.S BndsOK ; => no, copy pixMap.bounds to GDRect EXG A0,A1 ; else copy GDRect to pixMap.bounds BndsOK MOVE.L (A0)+,(A1)+ ; copy topLeft MOVE.L (A0)+,(A1)+ ; copy botRight ; ; if we're about the main device, then fix all those ; potentially errant ports. ; TST.B QDExist ; (Unless QuickDraw don't exist) BNE @noQD MOVE.L portList,D1 ; or if portlist = 0 or -1 BEQ @noQD ADDQ.L #1,D1 BEQ @noQD BTST #mainScreen,D0 ; is it the main scrn? (flags already in D0) BEQ @notMain PEA oldPort(A6) ; Save the current port _GetPort MOVE.L mainDevice,theGDevice ; and set to the screen MOVE.L PortList,A4 ; A4 = handle to list of ALL ports MOVE.L (A4),A4 ; A4->list of all ports MOVE (A4),D3 ; D3 = number of ports that exist BRA @portWalkEnd @portWalkLoop MOVE.L PortList,A4 MOVE.L (A4),A4 MOVE.L 2(A4,D3.W*4),A4 ; A4 = this port MOVE.L A4,-(SP) ; Set to each port in the port list _SetPort MOVE.L oldBaseAddr(A6),D1 ; D1 = the scrnbase of ports to change BTST #7,portVersion(A4) ; high bit set? BEQ.S @oldPort MOVE.L portPixMap(A4),A4 ; A4 = handle to the port's pixmap MOVE.L (A4),A4 ; A4->port's pixmap CMP.L baseAddr(A4),D1 ; same as the screen's? BNE.S @portWalkEnd ; no, skip this port MOVE.L baseAddr(A3),baseAddr(A4) ; replace a bunch of fields MOVE rowBytes(A3),rowBytes(A4) MOVE.L pixelType(A3),pixelType(A4) ; (gets pixelSize, too) MOVE.L cmpCount(A3),cmpCount(A4) ; (gets cmpSize, too) MOVE.L planeBytes(A3),planeBytes(A4) PEA oldColor(A6) ; placeholder for reinstantiating colors MOVE.L (SP),-(SP) MOVE.L (SP),-(SP) MOVE.L (SP),-(SP) _SaveFore ; Save and restore the foreground color _RestoreFore ; (Allowing for pmFore) _SaveBack ; And the same for the background _RestoreBack BRA.S @portWalkEnd @oldPort CMP.L portBits+baseAddr(A4),D1 ; same base on old port? BNE.S @portWalkEnd MOVE.L baseAddr(A3),portBits+baseAddr(A4) MOVE rowBytes(A3),D1 AND #nurbMask,D1 ; handle NURBs here MOVE D1,portBits+rowBytes(A4) @portWalkEnd DBRA D3,@portWalkLoop MOVE.L oldPort(A6),-(SP) ; restore the pre-existing port _SetPort MOVE.L oldBaseAddr(A6),D1 CMP.L scrnBase,D1 ; fix scrnBase too, if neede BNE.S @notMain MOVE.L baseAddr(A3),scrnBase @notMain _AllocCursor _ShowCursor @noQD ; ; notify the Palette Manager that the mode has changed ; ; <2.6> moved after GDRect has been adjusted <2.6> CMP.L #-1,PMgrHandle ; has the Palette Mgr been initialized? BEQ.S @noPMgr ; nope, so skip this MOVE.L GDH(A6),-(SP) ; push the device handle _RestoreDeviceClut ; call the Palette Manager Unhook device vector @noPMgr MOVE.L SaveDevice(A6),theGDevice ; restore theGDevice MOVE.L GDPMap(A2),A0 ; get pixMap handle MOVE GDPState(A6),D0 ; get the lock state _HSetState ; restore prior state MOVE.L GDH(A6),A0 ; get the gDevice handle MOVE GDHState(A6),D0 ; get the lock state _HSetState ; restore prior state MOVEM.L (SP)+,D3/A2-A4 ; restore work registers UNLINK result-return-4,'INITGDEV' ENDPROC ENDIF ;--------------------------------------------------- ; ; procedure myInitMenus; ; ; This code patches InitMenus. It would be better to call InitPalettes from InitWindows ; but MultiFinder has that patched out and we would again have to duplicate our efforts. ; ; AppleSystemPatch PaletteMgr.a 10Mar87 #PB103 (InitMenus) (myInitMenus) myInitMenus PROC EXPORT ROMInitMenus Equ $109EE ; AWC.PB506 JsrRom ROMInitMenus ; call InitMenus AWC.PB506 _InitPalettes ; set up the AppPalette AWC.PB520 Rts ; go home AWC.PB520 ;--------------------------------------------------- ; ; procedure myNewCWindow() ; ; Initialize the palette manager fields of the new window. ; ; AppleSystemPatch PaletteMgr.a 10Mar87 #PB103 (NewCWindow) (myNewCWindow) myNewCWindow PROC EXPORT ROMNewCWindow EQU $0F9F6 ; normal NewCWindow routine ; shuffle parameters so it will return to us MOVE.L SP,A0 ; get src for params MOVE.L SP,A1 ; get dst for params MOVE.L (A0)+,D1 ; save RTS MOVEQ #7,D0 ; move 8 longs @NxtLong MOVE.L (A0)+,(A1)+ ; move a long DBRA D0,@NxtLong ; repeat for all longs MOVE.L D1,30(SP) ; stuff original RTS JSRROM ROMNewCWindow ; call NewCWindow ; always set the default palette to 0 MOVE.L (SP),A1 ; get the window MOVE.L GrafVars(A1),A0 ; get handle to vars MOVE.L (A0),A0 ; point to vars CLR.L PMFgColor(A0) ; and clear palette MOVE.L (SP)+,A1 ; get window pointer MOVE.L (SP),A0 ; get return address MOVE.L A1,(SP) ; stuff wPtr JMP (A0) ; and return ;--------------------------------------------------- ; ; procedure myNewWindow(); ; ; When NewWindow is called, do an ActivatePalette in case there's a default palette. ; ; AppleSystemPatch PaletteMgr.a 10Mar87 #PB103 (NewWindow) (myNewWindow) myNewWindow PROC EXPORT ROMNewWindow EQU $0FA08 ; normal NewWindow routine ; shuffle parameters so it will return to us MOVE.L SP,A0 ; get src for params MOVE.L SP,A1 ; get dst for params MOVE.L (A0)+,D1 ; save RTS MOVEQ #7,D0 ; move 8 longs @NxtLong MOVE.L (A0)+,(A1)+ ; move a long DBRA D0,@NxtLong ; repeat for all longs MOVE.L D1,30(SP) ; stuff original RTS JSRROM ROMNewWindow ; call NewWindow MOVE.L (SP),-(SP) ; push the window _ActivatePalette ; and activate the system palette @DONE MOVE.L (SP)+,A1 ; get window pointer MOVE.L (SP),A0 ; get return address MOVE.L A1,(SP) ; stuff wPtr JMP (A0) ; and return ;--------------------------------------------------- ; ; procedure HiliteWindow(); ; ; Patch HiliteWindow to call ActivatePalette if called from SelectWindow ; AND if it is not called from MoveWindow! ; ; AppleSystemPatch PaletteMgr.a 10Mar87 #PB103 (HiliteWindow) (myHiliteWindow) myHiliteWindow PROC EXPORT FromSelect EQU $1016A ; RTS if called from select FromMove EQU $10396 ; RTS if selected from Move ROMHilite EQU $0FFCE ; real HiliteWindow CMPRA FromSelect,(SP) ; from selectWindow? BNE.S @JustHilite ; => no, just hilite CMPRA FromMove,$38(SP) ; from Move? BEQ.S @JustHilite ; => yes, just hilite TST.B 4(SP) ; hiliting? BEQ.S @JustHilite ; => no, just (un)hilite LEA 6(SP),A0 ; point to window MOVE.L (A0),-(SP) ; push window MOVE -(A0),-(SP) ; push boolean JSRROM ROMHilite ; call hilite in ROM MOVE.L 6(SP),-(SP) ; push window pointer _ActivatePalette ; and activate its palette RTD #6 ; strip 6 bytes params and return @JustHilite JMPROM ROMHilite ; and complete the call ;--------------------------------------------------- ; ; procedure MyMoveWindow ; ; Patch MoveWindow to call ActivatePalette ; ; AppleSystemPatch PaletteMgr.a 10Mar87 #PB103 (MoveWindow) (myMoveWindow) MyMoveWindow PROC EXPORT ROMMove EQU $0FD9C ; real MoveWindow LEA 10(SP),A0 ; point to window MOVE.L (A0),-(SP) ; push window MOVE.L -(A0),-(SP) ; push dst location MOVE -(A0),-(SP) ; push frontflag JSRROM ROMMove ; call movewindow MOVE.L 10(SP),-(SP) ; push window _ActivatePalette ; and activate its palette RTD #10 ; strip 10 bytes and return ;--------------------------------------------------- ; ; procedure MySizeWindow ; ; Patch SizeWindow to call MySetPalette ; ; AppleSystemPatch PaletteMgr.a 10Mar87 #PB103 (SizeWindow) (mySizeWindow) MySizeWindow PROC EXPORT ROMSize EQU $1000E ; real SizeWindow LEA 10(SP),A0 ; point to window MOVE.L (A0),-(SP) ; push window MOVE.L -(A0),-(SP) ; push dst location MOVE -(A0),-(SP) ; push frontflag JSRROM ROMSize ; call SizeWindow MOVE.L 10(SP),-(SP) ; push window _ActivatePalette ; and activate its palette RTD #10 ; strip 10 bytes and return ;--------------------------------------------------- ; ; procedure MyClose ; ; Patch CloseWindow to call DisposPalette. In the initial system disk release, this ; patch mistakenly operated on DisposeWindow instead of CloseWindow. ; ; AppleSystemPatch PaletteMgr.a 10Mar87 #PB103 (CloseWindow) (myClose) MyClose PROC EXPORT ROMClose EQU $0FB6E ; real CloseWindow MOVE.L 4(SP),A0 ; get the window TST PORTBITS+ROWBYTES(A0) ; is it new? BPL.S @NotNew ; => no MOVE.L GrafVars(A0),A0 ; get grafVar handle MOVE.L (A0),A0 ; point at grafVars MOVE.L PmFgColor(A0),D0 ; is there a palette BEQ.S @NotNew ; => no Move.L D0,A0 ; let's use an address register AWC.PB457 Move.L (A0),A0 ; dereference it AWC.PB457 BTst #DisposeBit,pmPrivate(A0) ; should we dispose of it? AWC.PB457 Beq.S @NotNew ; no => the user has to dispose of it AWC.PB457 MOVE.L D0,-(SP) ; else push palette _DisposePalette ; and dump it @NotNew JMPROM ROMClose ; and dispose the window ;--------------------------------------------------- ; ; procedure MyShowHide(WindowPtr; BOOLEAN); ; ; Patch MyShowHide to call ActivatePalette. If it is being called to show a hidden window, ; then do the ActivatePalette. ; ; AppleSystemPatch PaletteMgr.a 10Mar87 #PB103 (ShowHide) (myShowHide) MyShowHide PROC EXPORT ROMShow EQU $0F742 ; real ShowHide LEA 6(SP),A0 ; point to window MOVE.L (A0),-(SP) ; push window MOVE -(A0),-(SP) ; push boolean JSRROM ROMShow ; call showhide MOVE.L A1,-(SP) ; save A1 for ShowHide! MOVE.L 10(SP),-(SP) ; push window _ActivatePalette ; and activate its palette MOVE.L (SP)+,A1 ; restore A1 for ShawHide RTD #6 ; strip 10 bytes and return ;--------------------------------------------------- ; ; procedure MyExit; ; ; Patch MyExit to call DisposePalette for all palettes in the app heap. In addition, jam ; theGDevice and srcDevice with MainDevice. As if that weren't enough, make sure that ; cursor interrupts are enabled. ; ; This patch is not installed by A/UX or under MultiFinder. ; ; AppleSystemPatch PaletteMgr.a 10Mar87 #PB103 (MyExit) (myExit) MyExit PROC EXPORT EXPORT myExitExit ; address of JMP target to daisy chain ROMIAZInit EQU $4080DEF8 ; jump back into ROM ROMAppZoneAddr EQU $4080D434 ; a useful routine MOVEM.L A0-A6/D0-D4,-(SP) ; save all registers _PMgrExit MOVE.L MainDevice,A0 ; get the main device MOVE.L A0,SrcDevice ; set the src device MOVE.L A0,theGDevice ; and the current device MOVE #$2000,SR ; make sure interrupts enabled MOVEM.L (SP)+,A0-A6/D0-D4 ; restore all registers JMP $4080000A ; jump to next code in chain myExitExit EQU *-4 ; address of JMP target ENDIF ; Okay, that's it. We're out of here!