; ; File: StandardFilePACK.a ; ; Contains: The Standard File package, PACK 3 ; ; Written by: Steve Capps, Eric Ringewald, Ernst Beernink, John Meier, Nick Kledzik ; ; Copyright: © 1984-1992 by Apple Computer, Inc. All rights reserved. ; ; Change History (most recent first): ; ; 11/6/92 SWC Changed PackMacs.a->Packages.a. ; 10/14/92 CSS Change some branch short instructions to branches. Also, ; check for .NewAge driver and display the proper icon if ; present. ; <11> 8/25/92 DTY Always use the popup CDEF. Get rid of usePopUpCDEF conditional. ; <10> 7/5/92 csd #1034877 : Reversed some of change <9> because the code to ; rebuild the popup menu gets called multiple times. If it doesnÕt ; _DeleteMenu the old menu, then it stays in the list and ; _InsertMenu fails. The first time _DeleteMenu is called, itÕs ; being called for the CDEFÕs menu which has already been removed ; from MenuList. This is okay, though; _DeleteMenu will do ; nothing. ; <9> 7/5/92 gbm #1034877,: Standard file was relying on some behavior of ; the pop-up CDEF, which has changed for Cube-E, so we must alter ; the handling of the pop-up menu. (We need to delete it from ; memory and the menu list when weÕre through with it, because the ; CDEF no longer does that for us. ; <8> 5/26/92 FM Change the invisible check to special case remote volumes to ; never be invisible. That way if someone mounts a High Sierra or ; ISO format CD as an AppleShare volume it will show up in ; Standard File. (This is getting sickÉ) ; <7> 5/12/92 DTY #1028452: Make sure a volume is on line before seeing if itÕs ; invisible or not. ; <6> 4/28/92 DTY Get rid of hasBalloonHelp conditional. ; <5> 4/21/92 FM Fix invisible check. I was using the wrong offset in the ; GetCatInfo reply. < duuhhhhÉ> ; <4> 4/3/92 gbm Change smKeyDisabState to a kinder, gentler spelling. ; (smKeyDisableState) ; <3> 4/3/92 DTY #1019375,: Check to see if the keyboard was already locked ; on entry to Standard File. If it was, donÕt lock it or unlock ; it. ; <2> 4/2/92 FM #1022940,: #1022940 Make Standard file respect invisible ; volumes. Unfortunately High Sierra and ISO drivers that are ; currently shipping set the invisible bit by mistake. Therefore ; we have to special case them IF their FSTs are version 2.0.3 (We ; can check this by looking at the gestalt selector'hscd'. Also ; fixed #1011684 allowing recognition of user filters that change ; -1 (start hook) to an item in subdialogs ; <1> 10/1/91 JSM first checked in ; <0> 10/1/91 JSM Created from StandardFile3.PACK.a. ; ; Modification history from StandardFile3.PACK.a below: ; ; <68> 4/8/91 ngk KSM,#f2-ngk-001: remove dereferenced unlocked handle across ; DisposeMenu ; <67> 4/8/91 ngk KSM,#BS-047: fix wrong initial volume name when at desktop and ; curDirStore specifies non-boot volume. ; <66> 3/30/91 ngk DTY,#f1-ngk-002: FIx bug in which app's modalFilter proc was ; called twice with each key event. ; <65> 3/30/91 ngk DTY,#85960: don't intially activate TEbox if it is hidden ; (HideDItem). Fixes decompress dialog in AppleLink. ; <64> 3/29/91 ngk JDR,#f1-ngk-001: fix double paste in putfile for MPW and ; Hypercard ; <63> 3/25/91 ngk RLC,#b6-ngk-006: fix checking one too many file types ; <62> 3/20/91 ngk doh,#b6-ngk-004: fix abort register trashing bug ; <61> 3/18/91 ngk RLC, #85049: fix Cmd-N crash if no new folder button ; <60> 3/14/91 ngk kip,#b6-ngk-001: fix bug where pop up sometimes failed to change ; the folder. ; <59> 3/6/91 ngk RLC,#84250: fixed wrong balloon when upgrading old dialogs. ; <58> 2/26/91 ngk VL,#82594: Fix for Word 4.0, the open button was blank. ; <57> 2/21/91 ngk JDR, Fix bug introduced by fix 55.4,#82679. ; <56> 2/19/91 ngk KSM,#SLB102: now lock PACK3 before doing anything that could ; move memory. KSM,#BS-036: fix enabling of eject button after ; creating a new folder. KSM,#BS-040: check for Cmd-uppercase-V as ; well as Cmd-lowercase-v. ; <55> 2/11/91 ngk JDR,#82022: clr.w -(sp) instead of subq #2,sp before calling ; App's dialogfilter to fix bug in FileMaker. JDR,#79895: Force ; _PenNormal before drawing file list outline to fix bug in ; FileMaker. JDR,#82542: Fix out of bounds possibility in ; QuickSort. JDR,#82679: Volume name not updating on disk-insert ; and when following an alias to another volume. JDR,#82680: Fix ; saving at desktop for QuickMail. JDR,#82198: Fix disk insert ; check for UltraPaint by not relying on null events to check for ; insert event. JDR,#82541: Fix bug where InvalRect called before ; port set. ; <54> 1/26/91 PKE JSM,#79771: Ignore script codes in HFS info if the bit that ; enables scripted HFS items is off (as it is in System 7). Deals ; with problems caused by Finder setting these script codes to the ; wrong value. The real bug fix is in Finder. ; <53> 1/24/91 ngk VL, #77818: Fixed quicksort bug. ; <52> 1/17/91 ngk fix for right-left script systems in putFile TE item. ; <51> 1/14/91 ngk fix bug when filename field is full, now allow typing over ; selection to work. ; <50> 1/14/91 ngk Fix bug if starting at desktop, lDisplyedVolRef not set ; up. Do better preflighting by preloading and marking nonpurgable ; all needed resources. Fix bug where you could put into ; putfile filename box. When at desktop and nothing is selected, ; fix reply record to have vRefNum/dirID of last volume shown. ; <49> 1/9/91 ngk Fix bug in which save button had inconsistent hilight ; state if back window had update pending. Fix selectAndReveal to ; no longer scroll list so much that some blank spaced showed. Add ; support for custom SF2 dialogs to have help items. Fix clicking ; on volume when file list not active to draw list. Add support ; for page up/down keys. Optimized sorting in US case by checking ; if list is sorted before doing QuickSort. Changed drawing order ; to not clear list until new list is ready. Fix memory leak of ; items handle and dirID array. ; <48> 1/4/91 ngk Fix bug that prevented you from opening an alias to a file. ; <47> 12/14/90 ngk Fix bug in which aliases to applications were always showing up. ; <46> 12/14/90 ngk Try to use PopUpMenu CDEF. Fixed too many files bug - it ; now just displays as many as will fit (~600 but depends on name ; lengths). Fixed a bug for ResEdit - if app maps alias open to 1 ; then return with alias in reply, not target. When at desktop and ; a MFS disk is choosen, now dim new folder button. Rework initial ; drawing so old and new calls get activate, update, then list ; built. Fix bug with initial active item not getting set up, if ; non-standard. Use bitsaving balloon for popupmenu. Don't warn on ; lock files for old calls. Don't warn about locked stationery. ; FIx saving to desktop bug, it sometimes choose wrong volume if ; desktop button was used. Fix Eject and Cmd-Right/LeftArrow to ; update volume icon. Use Record defintion for accessing PoupCDEF ; internal data. ; <45> 11/28/90 ngk Fixed Pagemaker 4.0 bug - in their DITL, item one is a pict item ; intead of a button. Changed old calls to SF to draw in the old ; order so that apps that depend on activate as the first event ; are happy. Fixed sfHookChangeSelect in CustomPutFile to not show ; selection unless file list is active. If a file is not really an ; alias file, then return with it, instead of error alert. Force ; alias flag of folders to false. Fix type select to center select ; item in list, if the list had to be scrolled. Removed flicker of ; selected item if it is reselected. If app maps -1 hook to ; sfHookGotoDesktop then first volume on desktop is now selected. ; <44> 11/20/90 DC Fixed names of ID's of system icons ; <43> 10/30/90 ngk StandardGetFile was ignoring numTypes. In AddFolderContenst fix ; bug when numTypes is 0. Fix bug for apps that do folder ; selection and don't map to open instead of cancel. Disable Cmd ; right,left arrow when only 1 disk. Don't give tab key to old ; filter procs, MacWriteII tries to use it. Set low mem SFSaveDisk ; and CurDirStore when at desktop to reflect the desktop folder ; for the selected item. When in volume select compatability mode, ; do not map cmd-D. Fix GotoDesktop to not select first item in ; list, unless list is active. Fix set up of new folder button to ; dim if folder does not have search privileges. If app maps -1 to ; something, don't build list twice. Fix bug where filter proc was ; ignoring activate events. When at desktop and a disk is ejected, ; don't goto next drive. Use teSysJust to decide which side icons ; go on. Add flag after pack version that forces icons to be on ; left. Use new stationery icon. Fix bug in sorting use ; IUGetScriptItl instead of GetResource. Add SetUpDialogFlags to ; set up dialog flags for new std filter proc. ; <42> 9/27/90 ngk Pre-flighting Pack6 before calling _TypeSelectClear. Fill in ; reply record after click selecting a new item. ; <41> 9/17/90 ngk Disable new folder button on MFS disks. ; <40> 9/16/90 ngk Fixed bug that stopped type select from working in put file if ; TE item is disabled. ; <39> 8/31/90 ngk Restore check for command period and ESC, since ; standardFilterProc no longer does it for me. Restore lock state ; of PACK 0 and 6. Use resource based way to map file types to ; icons, now that special folders have seperate types. Use string ; resource to get command keys so that it is now localizable. ; <38> 8/21/90 ngk Don't allow word wrap and do allow horizontal scrolling in ; putfile TE. ; Beep if user tries to type more than 31 chars into filename TE. ; When pasting into filename TE, map and ':' to '-' and truncate ; to 31 chars. Add warning on opening locked files. Check for ; stationery and lockness (Nessie) after resolving aliases. ; Fixed bug in sorting, if list contained mixed scripts. ; Fixed bug where stationery warning dialog contained garbage. ; Fixed bug where if CurDirStore is set to trash, the system hangs. ; <37> 8/11/90 ngk Lots of bugs fixed: Auto-key tabbing in getfile selected a file. ; Finder flags not set to target when returning after resolving an ; alias. Selecting an alias to a volume, (incorrectly) set ; isFolder flag. sfHookOpenAlias on an alias file did not work. ; New folder at desktop put on wrong disk. Alias to volume on ; desktop did not resolve. In old reply records, wrong dirID was ; put in fType when selecting a volume. Set dir flag of alias file ; cat info when filtering thru CustomGetFile. Two files are ; selected, if app puts up its own window over sf. Now remember ; the folder in use for each volume. Stop using colorized icons in ; non-color grafports. ; <36> 8/7/90 PKE (first item is per NGK) Fix bug disposing of color table handle ; that doesnÕt exist. (Now PKE changes) If setting of script tags ; is disabled, then lock keyboards when in Standard File, and - if ; sfPut - return smSystemScript as ScriptCode in reply record, and ; set Finder script tag byte to unused (=0) when creating folders. ; <35> 8/6/90 ngk Run folders through an apps filter in CustomGetFile when ; numTypes = -1. ; <34> 8/5/90 ngk When at desktop, update volume icon/name to reflect current ; selection. Preflight Pack-0 and Pack-6. Fixes so that during ; hook calls while at desktop, reply record has correct dirIDs. ; packed together fields in FileEntry. Fix filter to do nothing on ; subdialogs. Call activate proc even on known items. Save port ; around GetNextEvent. Use GetLabels call to get icon colors. ; <33> 7/26/90 ngk Fix use of editOpen to editField. Allow app to map -1 to ; sfHookGotoDesktop. Fix auto-key in list to not put chars into ; text field. Fix dialog hook to not be called on subdialogs for ; old routines. ; <32> 7/24/90 gbm Knock of a few assembler warnings ; <31> 7/19/90 EMT Layers.a -> LayerEqu.a ; <30> 7/15/90 ngk Now use ResolveAliasFile routine. Goto-Alias-Target when target ; is at the desktop level now works. Make aliases to folders and ; volumes show up in old filtered getfile and look like a folder ; for CustomGetFile. ; <29> 7/6/90 RLC Fix special case balloons to clear flag if mouse isn't in one of ; the special areas. ; <28> 7/3/90 ngk un-comment-out call to StdFilter. ; <27> 7/2/90 ngk Change _DisposDialog to _CloseDialog. Map 'drop' to 'APPL' for ; file filtering. ; <26> 7/2/90 ngk Use PictButton CDEF for NewFolderButton. Rework event loop for ; sub dialogs. Cached control handle for all buttons. Call dialog ; hook and filter for sub dialogs, too. Dim "Create" button in New ; folder dialog, if no name is entered. Changed Alerts to Dialogs. ; Use new server icon for file servers. Copy Finder color table ; into listRec.usrHandle for coloring of icons. Fix bug with ; activate lists and procs. Fix Cmd-DownArrow bug on aliases. ; Change gotoAliasTarget to option-open. Fix bug with volume ; sorting/selection. Use StdFilterProc to reduce code size. ; <25> 6/14/90 ngk Fix bug with SF2Compatibility. ; <24> 6/7/90 ngk Add compatability mode for volume selecting. Fix bug with ; locking ioNamePtr. ; <23> 6/6/90 ngk Use script manager alias style info. Always make sure handle ; that ioNamePtr points into for fileFilter is locked down. Moved ; stackframe definition into this file. ; <22> 6/1/90 ngk Add error message for new folder when name already exists. Fix ; bug in pop up going to desktop of locked volume. Added support ; for new edition file types. Now properly set sfIsVolume. Range ; check some strings better. ; <21> 5/23/90 ngk Conditionally use popup CDEF. Handle userCanceledErr in ; ResolveAlias. In PutFile, no longer select first item by ; default. Add Cmd-D to mean Desktop. Make sure apps get initial ; update event filter call. Fix redrawing of open outline. Removed ; patch to GetResource('SICN',x) by changing MDEF. Dialog storage ; now allocated in locals, so wRefCon not needed. For SF2 ; compatability, move volume item right so doesn't hit halo. ; <20> 5/2/90 ngk Moved type select code into Pack6. ; <19> 4/30/90 ngk Factored out type select code. Changed allocation of local ; variables from the stack to a heap block - machines with only 8K ; of stack were running low, and QuickDraw was having problems. ; Deselected any items in list if user drags out of list. Disable ; open/save button if nothing is seleced and remove outline. Fix ; disk-insert and folder change via popup to select first item in ; target folder. Deselect list item if list is deactivated. Add ; Outline to default button in new folder sub-dialog. Make sure ; that NewFolder dialog is always on screen. Add standard keyboard ; equivalents for NewFolderDialog (Cmd-Period, ESC, , ) ; <18> 4/19/90 ngk Fix bug in initial file to select. Changed CompStyledString to ; test for case insensitive equality. Changed TypeSelect to handle ; case insensitive exact match. ; <17> 4/18/90 ngk hilite open button in converted dialogs ; <16> 4/10/90 ngk Added new folder button to PutFile. The button is actually a ; user item that simulates a button. Added concept of virtual and ; real items, to allow items id's to be moved around. Calls 5-8 ; now require a different, simpler DITL. Command-arrow keys force ; the file list to be active. ; <15> 3/27/90 ngk Changed way file list is built to be faster - less memory calls ; and less sorting needed. Changed desktop level to have volumes ; at top of list, then desktop files, then grayed trash. Changed ; type select algorithm to not require sorted file entries. ; Changed initial drawing so that initial dialog is drawn before ; the file is being built. ; <14> 3/22/90 ngk Fixed test of stationery bit. ; <12+> 3/19/90 JRM warn when opening stationery from non stationery-aware apps ; <12> 3/19/90 ngk Now no longer possible to sneak into trash. Fixed bug in which ; opening files sometimes failed. ; <11> 3/17/90 ngk Fixed two bugs that showed up in applelink download of disk ; files. 1) UpdateEvents were sent incorrectly to modalFilters, ; 2) The prompt string past into putfile was being ignored. Now ; center window, if where = <-1,-1>. Now do sanity check that ; dialog if dialog is not fully visible, then autocenter it. ; <10> 3/13/90 ngk Check that volume supports AccessCntrl before using ioACuser ; field. Fixed bug where no access privs alert was blank. Fixed ; bug where modalFilterProc was not being used in SFPxFile. ; <9> 3/10/90 csd Changed three more word references to the byte-sized style field ; to byte moves. ; <8> 3/9/90 ngk Fix 68000 bug clr.w on an odd address in initialize of ; IDirName.style Fix bug where alias to app shows up with folder ; icon. ; <7> 3/9/90 ngk Updated to changes in StandardFile.a. Fixed another bug with ; QuickMail enclosures, they thought getCancel was 2 instead of 3. ; <6> 3/5/90 ngk Only call hookLastCall on new routines, 'cause it breaks ; QuickMail enclosure retrieval. Made keyboard equivalent for ; cancel flash the cancel button. ; <5> 3/5/90 PKE Added smTruncEnd as truncWhere parameter for TruncString call, ; since TruncString interface now matches former NTruncString ; interface. ; <4> 2/28/90 ngk Fix bug where hitting return key causes crash, 'cause a6 not set ; up. ; <3> 2/25/90 ngk Fixed bug in new calls, forgot to set reply.good. Use ; kWhereToEmptyTrashFolderType instead of kTrashFolderType. Fixed ; PopUpMenu item to only be redrawn on update events for it. ; Changed LDEF interface. Changed new reply record to return ; script and finder flags. Rearranged parameters on new calls to ; make simple calls simpler. ; <2> 2/18/90 ngk Always gray out trash when at desktop. Use special $1A menu item ; for better looking pop up menu. Changed CompStyledString to use ; _IUScriptOrder and _IUMagPString. Cleaned up UserItem draw ; procedure. Moved drawing of folder pop-up, file list halo, and ; open button outline to dialog filter. ; <1> 2/17/90 ngk Split 7.0 and 6.0 into separate files. System 7.0 has ; StandardFile3.Å and system 6.0 has StandardFile2.Å ; Split out PackMacs.a into StandardFile.a and added real record ; templates and symbolic constants for dummy hook calls. ; Massive de-spaghetti-zation (restructuring) of code. ; Transmorgified most code fragments into real procedures ; ending with rts and then MacsBug symbols. Split out incestuous ; LDEF into real stand-alone, separately-compiled LDEF. ; Fixed up button setting code. Defined and used more dummy ; hook items. ; ; split into StandardFile3.PACK.a and StandardFile2.a ; ; <8> 2/2/90 ngk Backspace and clear keys now flush type-ahead. Double clicking ; on ejected disks no longer crashes. Aliases now have their ; filenames written to the reply record before being resolved (for ; MPW set directory). ; <7> 1/25/90 JSM There is no Script Manager call to determine if truncation is ; needed, OK to use StringWidth. Remove unneeded TruncChar DC.W. ; <6> 1/22/90 JRM special case Letter folders so they get their own icon ; <5> 1/10/90 JSM Condense text, use _TruncString for long names. Based on an ; idea by Frank "Wanted His Name Here" Stanbach. ; <4> 1/6/90 JSM Change type of folder aliases in conjunction with Finder. ; <3> 1/6/90 ngk Fixed bug if NIL active list pointer was passed in. Fixed ; tabbing to file name TE in put file to select all. ; <2> 12/19/89 RC Fix odd addressing problem in lOpenState flag from TST.W to ; TST.B. ; <3.8> 12/11/89 BBM made the entry point ŌStandardFileÕ a ŌMAINÕ entry for 6.0.x ; systems ; <3.7> 12/7/89 dba improve type-select by using event.when instead of TickCount; ; fix bug that ignored all type-select characters when command key ; is not down; make Cmd-Left work; fix auto-scrolling and unify ; SingleSelect and SelectAndReveal; use new _LSetHilite to save ; code; get rid of bug where part of activate outline gets drawn ; in the GetFile case; activate earlier when clicking on the list ; <3.6> 11/30/89 RLC Added an 'include StandardFileHelp.a' and BSR ShowSFBalloons ; call. ; <3.5> 11/29/89 ngk Changed the border around the selected list to be 1-pix white ; then 2-pix black Fixed the activation of the TE item in Put file ; so you no longer get weird xor selection effects. Fixed a case ; where the Save/Open toggle is displayed wrong Now use edition ; mini-icon for edition files ; <3.4> 11/29/89 JRM Add reveal to command-open of aliases, open documents from trash ; or desktop ; <3.3> 11/20/89 ngk Fixed bug where you could not select the file if only one in ; folder. ; <3.2> 11/15/89 ngk Fixed missing semi-colon ; <3.1> 11/14/89 ngk Fixed type-select when key-repeat is turned off. Changed ; FileEntry to be a real record. ; <3.0> 11/14/89 JRM Use bootVol for desktop, trash, enumerate trash, open ; trash/desktop items still doesn't work ; <2.9> 11/14/89 JRM Fix eject of selected disk on desktop, stack off by 2 in ; GetFilenameScript ; <2.8> 11/7/89 csd With dba: change IDs of SICNs so they stay in the Standard File ; range ; <2.7> 10/31/89 JRM Add command-open of an alias which open the aliasÕs parent ; folder ; <2.6> 10/31/89 JRM Fix type-select by using new UpperStr ; <2.5> 10/30/89 JRM Use script byte for sorting, drawing Call RelString for sorting ; Fixed bugs opening alias documents and folders Draw aliases ; using italic, removed alias icon Use generic PACK3 icons when ; drawing and in popup ; <2.4> 10/13/89 ngk Now include 'Aliases.a' ; <2.3> 10/11/89 ngk Fixed bug with maxIndex that cause corrupted heap. Fixed ; trunction of foldername in popup with new PopUpSymbol. Fixed ; open/save toggle when nothing is selected. Fixed arrow keys to ; switch drives only with cmdkey down. ; <2.2> 10/4/89 ngk nothing ; <2.1> 10/4/89 ngk Added fancy autoscrolling so selection is always in view. ; Command-shift-uparrow now is same as desktop button. Put ; PopUpMenuSymbol on right side of directory menu. Changed height ; of directory menu back smaller. Command-UpArrow to desktop now ; selects right volume. ; <2.0> 10/1/89 ngk Removed outline from textbox when it is active item. Removed ; outline from getfile list if it is only active item. Fixed bug ; where you could double click on dimmed item. ; <1.9> 9/18/89 ngk Fixed bug of tst.w instead of tst.b ; <1.8> 9/13/89 ngk Added new selectors 5-8. Added concept of current keyboard ; target (called active DITL item), allows keyboard navigation in ; PutFile. Tabbing now moves between possible active items. Change ; open/save button to always be open when a folder is selected. ; Right arrow now moves between volumes. Command up arrow now ; selects the folder that came from. Added callBackPtr to ; selectors 7 & 8, allows them to be Pascal local procedures. ; Selectors 7 & 8's dialog filter is now called before mapping ; instead of after. ; <1.7> 8/29/89 JRM always tst.b lAtDesktop instead of tst.w ; <1.6> 8/29/89 JRM fixed all tst.w to tst.b for lNewReply ; <1.5> 8/28/89 SES removed references to nFiles. ; <1.4> 8/11/89 JRM add back in 604 conditionals that Darin said I could take out ; <1.3> 8/8/89 JRM use alias manager, folder manager ; <1.2> 6/8/89 JRM conditionals for 604 and bigbang ; <1.1> 6/5/89 JRM big bang standard file ; 4/21/89 JRM remove checks for ROM85 and FSFCBLen draw mark for aliases stub ; out code for opening aliases desktop is root of standard file ; drive button ==> desktop button add disks, trash, desktop items ; to desktop changed alerts to use string list (smaller) use list ; manager to save code use popup menu manager to save code ; <1.0> 11/16/88 CCH Added to EASE. ; 3/4/88 JRM quick fix so superdrive gets floppy icon ; 12/21/87 JRM check if sfSaveDisk or CurDirStore have been changed ; <6> 7/23/85 ELR Removed RESOURCE name for space considerations. ; 7/23/85 ELR Translated back to Workshop format again. 1 Aug 1985 ELR A ; TAB character is now a Drive Button. ; 7/18/85 ELR Moved lomem storage for current folder into Pat's 'RegSave' ; area. Removed reliance on 'folder depth' being saved. Only uses ; that space if TFS is around. ; 7/17/85 ELR Fix bug in path menu for more than six levels deep. ; 7/16/85 ELR Added check of Dialog origin. For dialogs from system file, ; checked for odd dialog size to verify that this is really the ; new dialog. ; 7/11/85 ELR Replaced vestigal (SetIText of item 10) to the string passed in ; "Prompt" on getfiles. Fixed Instant Pascal "X" bug. ; 7/10/85 ELR Added check in Modal Dialog filter to make sure Default Item is ; enabled if CR/Enter is hit. Should fix Microsoft bug. ; 7/2/85 ELR A Bunch of new stuff. Menu Selection of tree traversal. Saving ; last folder in low mem. Volume name is no longer hot. ; 5/1/85 ELR New Today. Cloned from the all new SF1, by Capps. ; ; ; The all new Standard File 2. ; ; 3 September 1985 ; ; Written by Erich Ringewald. ; ; (C) Copyright Apple Computer Inc. 1984,1985 ; ; ; 1 May 1985 ELR New Today. Cloned from the all new SF1, ; by Capps. ; 2 July 1985 ELR A Bunch of new stuff. Menu Selection of ; tree traversal. Saving last folder in low mem. ; Volume name is no longer hot. ; 10 July 1985 ELR Added check in Modal Dialog filter to make sure ; Default Item is enabled if CR/Enter is hit. Should ; fix Microsoft bug. ; 11 July 1985 ELR Replaced vestigal (SetIText of item 10) to the ; string passed in "Prompt" on getfiles. Fixed ; Instant Pascal "X" bug. ; 16 July 1985 ELR Added check of Dialog origin. For dialogs from ; system file, checked for odd dialog size to ; verify that this is really the new dialog. ; 17 July 1985 ELR Fix bug in path menu for more than six levels deep. ; 18 July 1985 ELR Moved lomem storage for current folder into Pat's ; 'RegSave' area. Removed reliance on 'folder depth' ; being saved. Only uses that space if TFS is around. ; Version ; 6 23 July 1985 ELR Removed RESOURCE name for space considerations. ; 23 July 1985 ELR Translated back to Workshop format again. ; 1 Aug 1985 ELR A TAB character is now a Drive Button. ; ; 7 15 Aug 1985 EHB Converted to use List Mini-ger ; Erase names and mini-icons if no disk inserted ; 19 Aug 1985 ELR On key events in putfile, ignore them. Fixes putfile scroll bug. ; 26 Aug 1985 ELR Only equate TAB with DRIVE if the button is lit. Fixes bugs with ; pressing the TAB key for DRIVE button functions. ; 28 Aug 1985 ELR Properly check if we are spitting out the boot disk, so that ; the formatter and other goodies are always around for the fun. ; Added conditional assembly flag PFFiles. If TRUE, Standard File ; will display files in the putfile mode. ; 3 Sep 1985 ELR Added conditional mode for TruncStr. Can put elipses in middle ; of string. ; 4 Sep 1985 EHB Deselect selection when drag to side of list. ; 5 Sep 1985 EHB Added dynamic sizing of pop-down menu. ; Added auto-scrolling of pop-down menu. ; Fixed position problem of pop-down menu. ; Used DrawName code for drawing from defProc. ; Added application mini-icon; tweaked other icons. ; 9 Sep 1985 EHB Reinstated Eject Notify to properly handle cmd-ejects. ; Fixed double-click and drag to different cell bug in SFList. ; 10 Sep 1985 EHB Fixed LDEF128 bug that put ellipses in file names. ; Made the cmd-eject stuff really work. ; If there are files in a list, select the first one. ; 8 13 Sep 1985 EHB Fixed update problem with volume and directory names. ; Eliminated double update on level switch. ; Fixed "New Button" problem (distinguish between open, double-click ; and other item coerced into Open). ; Don't select first item on putFile. ; Touched up icons and icon alignment a la Capps suggestions. ; Made PutFile list 2 cells higher so Jazz wouldn't break (looks better too). ; Rearranged PutFile Item list for same reason... ; 17 Sep 1985 EHB Make sure to set lDirName if no TFS ; 25 Sep 1985 EHB Fixed SFSaveFile logic so it's compatible. ; 04 Oct 1985 EHB Made pulldown menu's shadow smaller ; 9 06 Nov 1985 EHB Added event coersion after _ModalDialog and before call to ; user's filter proc. Double clicks -> open/save button, and ; open/save of folder not returned as button items. ; 07 Nov 1985 EHB Moved mini-icons out of resources into code. This avoids loading ; and purging and missing SICN problems. ; 07 Nov 1985 EHB rearranged ListClick for better drag selection ; 12 Nov 1985 EHB set feFile.dimmed boolean TRUE if non-folder in putFile, else FALSE ; 10 13-26 Nov 1985 EHB New button drawing; New button hiliting; fixed dlgFilter for tabbing ; to switch drives; exit treeMenu if button released before file list built; ; fixed for other DLOG's in system file; move DLOG up if too low; made things ; work pretty well with variable-sized system fonts. ; 27 Nov 1985 EHB Leave save button dimmed if disk is locked *** Is this OK??? ; Made getFile list 16 pixels wider so same size as before ; 2 Dec 1985 EHB A folder open is passed through the dlgHook as "fake" item 103 (gOpenDir). ; Removed obsolete bitmap disposal code in Adios. ; 5 Dec 1985 EHB Fixed key scrolling bug introduced by fake item 103 ; In treeMenu, do getVolInfo if no TFS ; Cmd-eject wasn't loading in pack2 etc. Fixed, cleaned up... ; Setup LTicks from event record in DlgFilter ; Call ListClick with LTicks from event record ; 9 Dec 1985 EHB Added code to handle up and down arrows. ; 12 Dec 1985 EHB Added command up/down arrows to traverse the path. ; 16 Dec 1985 EHB Fixed double click in folder in PutFile bug. ; 16 Dec 1985 EHB In FillReplyRecord, Put DirID into rType if a folder is selected. ; Call FillReplyRecord immediately before calling dialog hook. ; v12 17 Dec 1985 EHB Preserve lock state across calls to SF ; Fix update problem with tab-click in dirRect. ; ;-------------------- System File 3.0 --------------------------- ; ; v13 30 Jan 1986 EHB Fix another update problem with tab-click in dirRect. ; If sfSaveDisk not on-line, don't use it as default! ; 18 Feb 1986 EHB Resize list for funny sized fonts... ; Inval editText field when editText box moved. ; v14 Added TruncChar to header. If 0, no elipses. ; 26 Feb 1986 EHB Fixed hangup on App1Event (cleaned up DlfgFilter). ; 27 Feb 1986 EHB Restore passThrough of clicks in file list ; ;---------------------------------------------------------------- ; ?? Aug 1986 DLD Fixed bug which was ignoring folders with privileges ; 03 Sep 1986 JRM access privilege changes ; getfile - not (search or read) grays folder icon ; putfile - not (search or write) grays folder icon ; alert prevents open dir of above ;v15 no write grays save button ;---------------------------------------------------------------- ; 01 Oct 1986 JRM Fixed bug which was leaving garbage on long folder/volume names ; 01 Oct 1986 JRM Fixed bug which required an itemhit to recognize disk inserts ;v16 ;---------------------------------------------------------------- ; 12 Nov 1986 JRM changes to access privilege changes ; getfile - not (search or read) grays folder icon ; putfile - not search or not read/write grays folder icon ; alert prevents open dir of above ;v17 no read or no write grays save button ;---------------------------------------------------------------- ;v18 03 Dec 1986 JRM don't use MPW fInvisible equate because they changed it ;---------------------------------------------------------------- ;v19 12 Jan 1987 JRM don't trash $00000000 in stdExit if ListHandle is nil ; 12 Jan 1987 JRM fixed bug where a x didn't work because typeahead wasn't cleared ;---------------------------------------------------------------- ;v20 26 Jan 1987 JRM use HGetState, HSetState except on old ROMs to keep UNIX people happy ; 17 Feb 1987 JRM exit file list loop only on fnfErr (someone else may have added files) ; 24 Feb 1987 JRM map command-. to cancel ; 24 Feb 1987 JRM (#6646) put up system error alert on OpenWD error ;---------------------------------------------------------------- ;v21 02 Mar 1987 JRM more HGetState, HSetState, use _TickCount ;---------------------------------------------------------------- ;v22 05 Mar 1987 JRM (#SD-KL029, #vr 073) fixed bugs with eject of unformatted disks ; 05 Mar 1987 JRM changes to invert by swapping foreground/background colors ;---------------------------------------------------------------- ;v23 07 Jul 1987 JRM always set lPriv for MFS disks to all privileges ;---------------------------------------------------------------- ;v24 <21dec87> JRM check if sfSaveDisk or CurDirStore have been changed ;(S347) when we get a gRedo command and if so, move to that ; new disk/directory. ;---------------------------------------------------------------- ;v25 <04mar88> JRM quick fix so superdrive gets floppy icon ;(S420) ;---------------------------------------------------------------- ;v26 <21apr89> JRM remove checks for ROM85 and FSFCBLen ; draw mark for aliases ; stub out code for opening aliases ; desktop is root of standard file ; drive button ==> desktop button ; add disks, trash, desktop items to desktop ; changed alerts to use string list (smaller) ; use list manager to save code ; use popup menu manager to save code ;(S???) ;---------------------------------------------------------------- ; todo***: ; call disk driver for icon (new call that allows multiple sizes) ; show no write, no read, no search icons for current folder ; get two lomem locations ; one is a handle to the most recently used directories ; auto-sync list when changes occur (most important for desktop and appleshare folders) ; Rewrite the code that displays the volume icon and name. It might ; be smaller to use a menu and DrawItem. The code is currenly way ; too large because it used to be used by pop up and LDEF, too. ; The code for enabling/disabling the new folder button while at ; the desktop is wrong. The new folder button is enable on locked ; volumes and volumens where the user does not have permissions ; to create folders. ;------------------------------------------------------------------------ ; ; Notes on starting the dialog. ; ; This is the chronological order of the call backs an app will ; get. This example use StandardGetFile with all call backs ; used. All simpler calls just skip some, but order is the same. ; ; HookProc(-1) ; chance for app to do any initialization ; DialogFilter(Deactivate) ; only if app has an active window when calling sf ; DialogFilter(Activate) ; activate event for sf main dialog ; ActivateProc(initialItem) ; tells app which item is initially the keyboard target ; DialogFilter(Update) ; update event for sf main dialog ; UserItemDrawProc(all) ; only if app has installed useritem (installed during hook -1) ; FileFilter(initial list) ; getfile only, called repeatedly to build list of files to display ; ; PRINT PUSH,OFF LOAD 'StandardEqu.d' INCLUDE 'Packages.a' MACRO _LSetHilite ; secret List Manager interface _PackCall #-4,_Pack0 ENDM ; secret PopUp CDEF internal structure (### should be in a private interface file someplace) CDEFpopUpData RECORD 0 theMenu DS.L 1 ; MenuHandle theMenuID DS.W 1 ; ID popupResult DS.L 1 ; for MacApp & hierarchial popups (hiword == menuId) myCtlRect DS.W 4 ; Rect, area where the control is drawn ; more fields ENDR INCLUDE 'Folders.a' ; for folder manager INCLUDE 'Aliases.a' ; for alias resolving INCLUDE 'LayerEqu.a' ; for window positioning INCLUDE 'IntlUtilsPriv.a' ; for type select stuff INCLUDE 'CTBUtilities.a' ; for pop up menu INCLUDE 'Icons.a' ; for GetLabel INCLUDE 'IconUtilsPriv.a' ; for generic icon ID's INCLUDE 'Balloons.a' ; for help manager routines INCLUDE 'BalloonsPriv.a' ; To get private _HMCountDITLHelpItems routine INCLUDE 'FinderPriv.a' ; for rAliasTypeMapTable INCLUDE 'DialogsPriv.a' ; for SetDefaultItem, etc INCLUDE 'StandardFile.a' ; for standard file definitions INCLUDE 'StandardFilePriv.a' ; my own equates IF &TYPE('hasDebugSymbols') = 'UNDEFINED' THEN hasDebugSymbols EQU 0 ENDIF MACRO DebuggerSymbol &name IF hasDebugSymbols THEN STRING ASIS DC.B $80 + &LEN(&name)+3, 'sf_', '&name' DC.W $0000 ENDIF ENDM PRINT POP ;___________________________________________________________________ ; ; standard types. ;___________________________________________________________________ Point RECORD 0 ; Point = RECORD CASE INTEGER OF v DS.W 1 ; 1: (v: INTEGER; h DS.W 1 ; h: INTEGER); ORG v vh DS.W h ; 2: (vh: ARRAY[1..2] OF INTEGER) ENDR ; END; Rect RECORD 0 ; Rect = RECORD CASE INTEGER OF top DS.W 1 ; 1: (top: INTEGER; left DS.W 1 ; left: INTEGER; bottom DS.W 1 ; bottom: INTEGER; right DS.W 1 ; right: INTEGER); ORG top ; topLeft DS Point ; 2: (topLeft: Point; botRight DS Point ; 3: (botRight: Point) ENDR ; END; BitMap RECORD 0 ; BitMap = RECORD baseAddr DS.L 1 ; baseAddr: QDPtr; rowBytes DS.W 1 ; rowBytes: INTEGER; bounds DS Rect ; bounds: Rect ENDR ; END; FontInfo RECORD 0 ; FontInfo = RECORD ascent DS.W 1 ; ascent: INTEGER; descent DS.W 1 ; descent: INTEGER; widMax DS.W 1 ; widMax: INTEGER; leading DS.W 1 ; leading: INTEGER; ENDR ; END; EventRecord RECORD 0 ; EventRecord = RECORD what DS.W 1 ; what: INTEGER; message DS.L 1 ; message: LONGINT; when DS.L 1 ; when: LONGINT; where DS Point ; where: Point; modifiers DS.W 1 ; modifiers: INTEGER ENDR ; END; VolumeParms RECORD 0 ; VolumeParms = RECORD vMVersion DS.W 1 ; vMVersion: INTEGER; vMAttrib DS.L 1 ; vMAttrib: LONGINT; vMLocalHand DS.L 1 ; vMLocalHand: LONGINT; vMServerAdr DS.L 1 ; vMServerAdr: LONGINT; size EQU * ; END; ENDR ; ;------------------------------------------------------ ; ; parameter and local variable stack structures ; Parameters5to8 RECORD {A6Link},DECR GetParamSize EQU *-8 ; bytes of prameters to remove on return fileFilter DS.L 1 ; ptr to function to weed out more files numTypes DS.W 1 ; number of file types in typeList typeList DS.L 1 ; ptr to file type list ORG fileFilter+2 PutParamSize EQU *-8 ; bytes of prameters to remove on return prompt DS.L 1 ; prompt defaultName DS.L 1 ; default name in put file reply DS.L 1 ; pointer to reply record dlgID DS.W 1 ; DLOG ID to use where DS.W 2 ; where the window goes dlgHook DS.L 1 ; dlogHook ptr filterProc DS.L 1 ; modal dialog filter or NIL activeList DS.L 1 ; ptr to list of possible active items activateProc DS.L 1 ; proc to handle activating items callBackPtr DS.L 1 ; pass back parameter or NIL return DS.L 1 A6Link DS.L 1 ENDR Parameters1to4 RECORD {A6Link},DECR GetParamSize EQU *-8 ; bytes of prameters to remove on return GetWhere DS.W 2 ; where the window goes GetPrompt DS.L 1 ; prompt fileFilter DS.L 1 ; ptr to function to weed out more files numTypes DS.W 1 ; number of file types in typeList typeList DS.L 1 ; ptr to file type list ORG GetPrompt+2 PutParamSize EQU *-8 ; bytes of prameters to remove on return PutWhere DS.W 2 ; where the window goes PutPrompt DS.L 1 ; prompt defaultName DS.L 1 ; default name in put file dlgHook DS.L 1 ; dlogHook ptr reply DS.L 1 ; pointer to reply record dlgID DS.W 1 ; DLOG ID to use filterProc DS.L 1 ; modal dialog filter or NIL activeList DS.L 1 ; ptr to list of possible active items activateProc DS.L 1 ; proc to handle activating items callBackPtr DS.L 1 ; pass back parameter or NIL return DS.L 1 A6Link DS.L 1 ENDR kMaxVolumes EQU 20 kPreFlightMax EQU 10 ; don't change this wihtout consulting NumPreFlightResources PerVolumeInfo RECORD 0 desktopDir DS.L 1 ; dirID of desktop folder lastDir DS.L 1 ; dirID of place to return to on this volume size EQU * ENDR SFFrame RECORD 0 lTheDialogRec DS.B DWindLen ; window record for main dialog lSubDialogRec DS.B DWindLen ; window record for any of the subdialogs lA6Link DS.L 1 ; save off A6 from link ; unified parameters lParamSize DS.W 1 ; bytes of prameters to remove on return lWhere DS.W 2 ; where the window goes lPrompt DS.L 1 ; prompt lDefaultName DS.L 1 ; default file name lFileFilter DS.L 1 ; ptr to function to weed out more files lNumTypes DS.W 1 ; number of file types in lTypeList lTypeList DS.L 1 ; ptr to file type list lDlgHook DS.L 1 ; dlogHook ptr lReply DS.L 1 ; pointer to reply record lDlgID DS.W 1 ; DLOG ID to use lFilterProc DS.L 1 ; modal dialog filter or NIL lActiveList DS.L 1 ; ptr to list of possible active items lActivateProc DS.L 1 ; proc to handle activating items lCallBackPtr DS.L 1 ; pass back parameter or NIL ; local variables lIOCmd DS.B ioHVQElSize ; space for any IO commands lHit DS.W 1 ; item hit for dialog select lItem DS.L 1 ; item handle from GetIItem lBox DS Rect ; box for GetIItem lKind DS.W 1 ; kind for GetIItem lString DS.B 256 ; string temp lPoint DS Point ; mouse point lSavePort DS.L 1 ; the port saved lSaveEject DS.L 1 ; the ejecthook saved lSaveDisk DS.W 1 ; the saveDisk saved lPack3State DS.W 1 ; the lock state of the pack lPack0State DS.W 1 ; saved state of list pack - not used lPack6State DS.W 1 ; saved state of international utils pack - not used lDirName DS StyledString ; current directory name lVolName DS StyledString ; current drive name lVolIcon DS.W 1 ; mini-icon number for volume lDisplyedVolRef DS.W 1 ; vRefNum of currently displayed volume lVolRefNum DS.W 1 ; current volume refnum, calculated from drive number lDriveNo DS.W 1 ; new drive number lCurDir DS.L 1 ; new current directory lNoEjects DS.W 1 ; ST if non-ejectable media lVnFiles DS.W 1 ; # files on volume lSigWord DS.W 1 ; sigword of current volume lVolParms DS VolumeParms ; of current volume lInset DS.W 1 ; Inset (pix) of folder center lTop DS.W 1 ; Top of list lNRect DS Rect ; name list rect lVolRect DS Rect ; rect for volume name lPopUpControl DS.L 1 ; control handle for pop up CDEF lPopUpMaxRect DS Rect ; max width rect for pop up lPopUpDirIDs DS.L 1 ; handle of array of dirIDs in pop up list lPopUpDirCount DS.W 1 ; number of dirIDs in lPopUpDirIDs array lFontInfoRec DS FontInfo lHeight DS.W 1 ; ascent + descent + leading lAlias DS FSSpec ; used when resolving alias lOldDITL DS.B 1 ; true if old item list lLocked DS.B 1 ; true if disk locked lPriv DS.W 1 ; access privileges <11Sep86 jrm> lDidEject DS.B 1 ; set TRUE if eject was done lDidPack2 DS.B 1 ; ST if pack2 loaded lScrollPurg DS.W 1 ; saved state of scroll bar lLastSel DS.L 1 ; previous selected cell lTypeSelect DS TypeSelectRecord ; buffer for type selecting lSelector DS.W 1 ; selector number of SF call (1-8) lDoingGetFile DS.B 1 ; Boolean, TRUE for get, FALSE for put lUseOutlineOpen DS.B 1 ; Boolean, if true draw bold ring around open/save button lNewReply DS.B 1 ; Boolean, Reply record is of new form lUseCallBack DS.B 1 ; Boolean, use callBackPtr lBalloonUp DS.B 1 ; <2.6 RLC 11/30/89> Help Mgr global use lAtDesktop DS.B 1 ; 0=>normal, -1=>inTrash, 1=>atDeskTop lStackFrameSize DS.W 1 ; amount of stack space to clean remove lFileListHandle DS.L 1 ; List Manager Handle for files lMainOpen DS.L 1 ; cache of control handle for open button in main dialog lMainCancel DS.L 1 ; cache of control handle for cancel button in main dialog lMainEject DS.L 1 ; cache of control handle for eject button in main dialog lMainDesktop DS.L 1 ; cache of control handle for desktop button in main dialog lMainNewFolder DS.L 1 ; cache of control handle for new folder button in main dialog lNFCreate DS.L 1 ; cache of control handle for create button in new folder dialog lEvent DS EventRecord ; an event record for disk insert events lMeta DS.W 1 ; word for event managerÕs modifiers lTicks DS.L 1 ; long for event manager ticks lMouseWhere DS Point ; Point for moused down in pop up <60> lTrashDir DS.L 1 ; dirID of trash for volume lDeskDir DS.L 1 ; dirID of desktop for volume lActiveDITLitem DS.W 1 ; dialog item that responds to typing lOpenRect DS Rect ; cache of boundry of open button lOpenState DS.B 1 ; 0 for open shown, 1 for alt open shown lOpenAltExists DS.B 1 ; 0 for no alt name, 1 for is alt name lOpenName DS.B 32 ; title of open button when non-file selected lOpenAltName DS.B 32 ; title of open button when file selected lSystemScript DS.W 1 ; cached system script lSystemFont DS.W 1 ; cached system scriptÕs font lSystemFontSize DS.W 1 ; cached system scriptÕs font size lBootVol DS.W 1 ; vrefnum of startup disk lBootDrive DS.W 1 ; drive of startup disk lTempDrive DS.W 1 ; temp drive (used during enumerate) lMapFromVItems DS.L 1 ; pointer to table mapping virtual items to DITL items lMapToVItems DS.L 1 ; pointer to table mapping DITL items to virtual items lNewFolderErr DS.W 1 ; OSErr encountered by new folder create lKnownRealItems DS.B 1 ; length of table mapping DITL items to virtual items lQuitFlag DS.B 1 ; false until user hits open/cancel lNewDialog DS.B 1 ; true iff using new dialog layout (i.e. newFolder button) lVolumeSelect DS.B 1 ; true iff in volume select compatibility mode lTemp DS.W 1 ; used for scratch lIconColors DS.B (6*7) ; SizeOf(RGBColor)*7 label colors, color #0 is no color, 3-bits lVolumes DS.B (kMaxVolumes*PerVolumeInfo.size) lAliasTypeMapH DS.L 1 ; handle to table mapping alias file types to icon resource IDs lFileTypeMapH DS.L 1 ; handle to table mapping file types to icon resource IDs lCmdKeyOpen DS.B 1 ; command key equivalent for open button lCmdKeyOptOpen DS.B 1 ; command key equivalent for option-open button lCmdKeyDesktop DS.B 1 ; command key equivalent for desktop button lCmdKeyNewFldr DS.B 1 ; command key equivalent for new folder button lFilterFolders DS.B 1 ; In CustomGetFile folders are run through the app's filter lSubDlgDone DS.B 1 ; dismisser button used in modal sub-dialog lListIsActive DS.B 1 ; whether sf thinks file list is the active item lATEIsActive DS.B 1 ; whether sf thinks a te field is the active item lDontDrawList DS.B 1 ; flag to turn off file list drawing 'til after selection lPopUpLooksGood DS.B 1 ; flag to not redraw popup after rebuilding its list lInitialMapped DS.W 1 ; what the app mapped -1 hook to lHelpTemplate DS.W 1 ; hdlg ID to call HMScanTemplate with, or zero lActiveListBuf DS.W 6 ; for implict active list made for old calls that have added TE items lCacheScrCode DS.W 1 ; script code of itl2 we have cached lCacheScrHandle DS.L 1 ; itl2 handle we have cached lTryShortSort DS.B 1 ; in US systems, file order is ususually display order, so may not need to sort lPreFlightCount DS.B 1 ; number of resources loaded successfully lPreFlightState DS.B kPreFlightMax ; IAlwaysShowLocalCD DS.B 1 ; Boolean that is set when we need to special case High Sierra and ISO CD's <2> FM IKeyboardState ds.l 1 ; <3> Current state of keyboard. ALIGN SFFrameSize EQU * ; size of link ENDR ;------------------------------------------------------ ; ; special key code and characters ; chCR EQU $0D ; carriage return chEnter EQU $03 ; Enter key (take default action) chTab EQU $09 chLeftArrow EQU $1C chRightArrow EQU $1D chUpArrow EQU $1E chDownArrow EQU $1F chPeriod EQU $2E ; a period! chEscape EQU $1B chClear EQU $1B ; clear key on keypad happens to have same char code as ESC chDelete EQU $08 ; aka backspace kcEscape EQU $35 ; for escape we need a key code to be unambiguous chPageUp EQU $0B chPageDown EQU $0C chEnd EQU $04 chHome EQU $01 StandardFile MAIN EXPORT ;----------------------------------------------------------- ; ; Pack3 - Standard File. Provides a standardized get/put file ; dialog for use by applications. ; ; #1 = putFile, #2 = GetFile ; #3 = Personal Dlg putFile, #4 = Personal Dlg getFile, ; #5 = improved PutFile, #6 = improved GetFile ; #6 = customizable improved PutFile, #7 = customizable improved GetFile ; bra.s SkipHeader ; bra around std header DC.W 0 ; flags DC.L ('PACK') DC.W 3 ; pack id DC.W 28 ; version >= 8 = TFS Release! ; version >= 9 does events right ; version >= 14 supports truncChar ; <21dec87> version >= 24 supports changing sfSaveDisk ; <21dec87> and CurDirStore from dialogHook ; version >= 26 supports calls 5 to 8 forceIconsOnLeft DC.W 0 ; if non-zero, ignore teSysJust and force icon on left pf2ActiveList DC.W $02,putName,putNmList ; activatable items in putfile gf2ActiveList DC.W $01,getNmList ; activatable items in getfile pf3ActiveList DC.W $02,sfItemFileNameTextEdit,sfItemFileListUser ; activatable items in putfile gf3ActiveList DC.W $01,sfItemFileListUser ; activatable items in getfile VirtualToSF2Put DC.B 0,1,2,0,4,5,6,8,0,0,7,3,0 ; mapping of virtual items to sf2Put SF2PutToVirtual DC.B 0,1,2,11,4,5,6,10,7 ; mapping of sf2Put items to sf3 VirtualToSF2Get DC.B 0,1,3,0,4,5,6,7,0,0,0,0,0 ; mapping of virtual items to sf2Get SF2GetToVirtual DC.B 0,1,2,2,4,5,6,7 ; mapping of sf2Get items to sf3 emptystring DC.B 1,' ' ; needed for building the pop up menu ALIGN SkipHeader move.l (SP)+,A0 ; get rts move.w (SP)+,D0 ; get flavor cmp.w #1,d0 beq.s @SFPutFileEntry ; selector = 1 cmp.w #2,d0 beq.s @SFGetFileEntry ; selector = 2 cmp.w #3,d0 beq.s @SFPPutFileEntry ; selector = 3 cmp.w #4,d0 beq.s @SFPGetFileEntry ; selector = 4 cmp.w #5,d0 beq.s @StandardPutFileEntry ; selector = 5 cmp.w #6,d0 beq.s @StandardGetFileEntry ; selector = 6 cmp.w #7,d0 beq.s @CustomPutFileEntry ; selector = 7 cmp.w #8,d0 beq.s @CustomGetFileEntry ; selector = 8 MOVEQ #dsNoPk3,D0 ; passed bad parameter _SysError ; and donÕt come back ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @SFPutFileEntry move.w #putDlgID,-(SP) ; add parameter of DLOG ID clr.l -(SP) ; add parameter of filter proc bra.s @defaultActives @SFGetFileEntry move.w #getDlgID,-(SP) ; add parameter of DLOG ID clr.l -(SP) ; add parameter of filter proc bra.s @defaultActives @SFPPutFileEntry bra.s @defaultActives @SFPGetFileEntry bra.s @defaultActives @StandardPutFileEntry move.w #rStandardFilePutID,-(SP) ; add parameter of DLOG ID bra.s @defaultProcs @StandardGetFileEntry move.w #rStandardFileGetID,-(SP) ; add parameter of DLOG ID bra.s @defaultProcs @CustomPutFileEntry bra.s Main @CustomGetFileEntry bra.s Main @defaultProcs move.l #-1,-(SP) ; add parameter of where clr.l -(SP) ; add parameter of dialog hook clr.l -(SP) ; add parameter of filter proc @defaultActives clr.l -(SP) ; add parameter of active list clr.l -(SP) ; add parameter of activateProc clr.l -(SP) ; add parameter of callBackPtr ; bra.s Main ;------------------------------------------------------------- ; ; Main ; ; main loop for all standard file routines. ; ; Entry: ; A0 is return address ; D0.W is selector ; Main WITH SFFrame move.l A0,-(SP) ; put return address back on stack link A6,#0 ; allocate std. frame movem.l D2-D7/A2-A4,-(SP) ; save regs bsr Initialize lea lTheDialogRec(a6),a3 ; use main dialog storage move.w lDlgID(a6),d0 ; use the perscribed dialog ID move.l #sfMainDialogRefCon,d3 ; mark the wRefCon as such bsr StartDialog ; get dialog, do -1 hook, show window bsr StartEventHandling ; handle initial activate and update events bsr BuildInitialList ; build initial list of files mainLoop bsr ShowSFBalloons ; <3.6 RLC 11/30/89> bsr FillReplyRecord ; be nice to dialog hooks bsr SetUpButtons ; enable and disable appropriate buttons bsr CheckDrives ; handle any inserts or ejects bsr GetNextItemHit ; get hit bsr DoAppsHook ; let app process hit bsr DoMyHook ; let me process hit tst.b lQuitFlag(a6) beq.s mainLoop lea lTheDialogRec(a6),a3 ; use main dialog storage bsr EndDialog abortExit bsr Finalize ; returns parameters to remove in d0 mainExit movem.l (SP)+,D2-D7/A2-A4 ; restore those regs unlk A6 move.l (SP)+,A0 ; get rts add.w D0,SP jmp (A0) DebuggerSymbol Main PreFlightResources DC.W ('PA'),('CK'),0 ; list mgr DC.W ('PA'),('CK'),6 ; international utils DC.W ('CD'),('EF'),0 ; button CDEF DC.W ('CD'),('EF'),1 ; scrollbar CDEF DC.W ('CD'),('EF'),61 ; Pict button CDEF DC.W ('CD'),('EF'),63 ; PopUp CDEF DC.W ('fm'),('ap'),rAliasTypeMapTable ; mapping of alias to icons DC.W ('fm'),('ap'),rGenericFileTypeMapTableID ; mapping of files to icons DC.W ('LD'),('EF'),-4000 ; StandardFile LDEF DC.W ('WD'),('EF'),0 ; Dialog WDEF NumPreFlightResources EQU (*-PreFlightResources)/6 IF kPreFlightMax < NumPreFlightResources THEN WRITELN 'kPreFlightMax is less than NumPreFlightResources' ENDIF ; should error exit here ;------------------------------------------------------------- ; ; Initialize ; ; Initializes everything needed. ; ; assumes D0.W has selector and stack frame is set up ; Initialize move.w d0,d3 ; save selector ; lock and save current lock state <56, #SLB102> move.l AppPacks+stdFile*4,a0; <56, #SLB102> _HGetState ; get lock state <56, #SLB102> move.b d0,d4 ; save lock state <56, #SLB102> _HLock ; lock ourselves down <56, #SLB102> ; use a heap block for locals, cause it might use to much stack on a 68000 machine move.l #SFFrameSize,d0 _NewPtr clear ; if this fails, abort tst.w d0 ; d0 has MemErr beq.s @allocOK move.l AppPacks+stdFile*4,a0; <56, #SLB102> move.b d4,d0 ; get saved lock state <56, #SLB102> _HSetState ; restore lock state <56, #SLB102> addq #4,sp ; remove return address ; mark reply record as "canceled" move.l Parameters1to4.reply(a6),a0 ; assume old call <62, b6-ngk-004> cmp.w #4,d3 ; test which selector <62, b6-ngk-004> bls.s @grr ; if new call, assumption was wrong <62, b6-ngk-004> move.l Parameters5to8.reply(a6),a0 ; new call <62, b6-ngk-004> @grr clr.w StandardFileReply.sfGood(a0); note: works for both new and old reply records <62, b6-ngk-004> bra.s mainExit ; quit @allocOK move.l a6,a4 ; a4 has real stack frame for parameters move.l a0,a6 ; a6 has the frame for locals move.l a4,lA6Link(a6) move.b d4,lPack3State(a6) ; and save lock state in locals <56, #SLB102> ; If setting of script tags is disabled, then lock keyboards so we can <36> ; only type in system script or Roman. subq #4,sp ; space for GetEnvirons return move.w #smGenFlags,-(sp) ; push GetEnvirons verb _GetEnvirons move.l (sp)+,d0 btst.l #smfNameTagEnab,d0 ; can we set script tags? bne.s @doneKeybdLock ; if so, skip keyboard lock subq #4,sp move.w #smKeyDisableState,-(sp) ; <33> See if keyboard is already locked _GetEnvirons move.l (sp)+,IKeyboardState(a6) ; <33> Save it tst.l IKeyboardState(a6) ; <33> If itÕs already locked, donÕt bother locking it again. bnz.s @doneKeybdLock ; <33> move.w #smKeyDisableKybds,-(sp) ; disable keybds not in sys or Roman script _KeyScript @doneKeybdLock ; <2> FM ; Check for version 2.03 of the FSTs that handle CD's <2> FM ; They accidentally set the invisible bit <2> FM move.b #0,IAlwaysShowLocalCD(a6) ; clear the special case flag. move.l #kHighSierraCDFST,d0 ; check for 'hscd' <2> FM _Gestalt ; get the response <2> FM tst.w d0 ; if err no special case <2> FM beq.s @noSpecialCaseCD ; <2> FM move.b #1,IAlwaysShowLocalCD(a6) ; else set the special case flag. @noSpecialCaseCD ; record the configuration move.w d3,lSelector(a6) ; save the selector @4 cmp.w #4,d3 shi.b lNewReply(a6) ; get whether it is new call shi.b lUseOutlineOpen(a6) ; as well as calls 1 & 2 cmp.w #2,d3 bgt.s @0 st lUseOutlineOpen(a6) ; as well as calls 1 & 2 @0 cmp.w #6,d3 shi.b lUseCallBack(a6) ; only use callbackPtr on routine 7 & 8 btst #0,d3 ; is this a putfile or getfile ? seq lDoingGetFile(a6) beq @getFileSetUp ; set up for all put files @putFileSetUp tst.b lNewReply(a6) bne.s @newPutSetUp ; set up for old put files only move.w #Parameters1to4.PutParamSize,lStackFrameSize(a6) move.l Parameters1to4.PutWhere(a4),lWhere(a6) move.l Parameters1to4.PutPrompt(a4),lPrompt(a6) move.l Parameters1to4.defaultName(a4),lDefaultName(a6) move.w #rStandardFileOldPutID,lHelpTemplate(a6) ; old put does not have a help item lea VirtualToSF2Put,a0 move.l a0,lMapFromVItems(a6) lea SF2PutToVirtual,a0 move.l a0,lMapToVItems(a6) move.b #8,lKnownRealItems(a6) lea pf2ActiveList,a0 move.l a0,lActiveList(a6) bra @oldSetUp @newPutSetUp ; set up for new put files only move.w #Parameters5to8.PutParamSize,lStackFrameSize(a6) move.l Parameters5to8.prompt(a4),lPrompt(a6) move.l Parameters5to8.defaultName(a4),lDefaultName(a6) move.w Parameters5to8.dlgID(a4),d0 ; a zero for dialogID means use default bne.s @newPutIDOK move.w #sfPutDialogID,d0 @newPutIDOK move.w d0,lDlgID(a6) move.b #11,lKnownRealItems(a6) move.l Parameters5to8.activeList(a4),lActiveList(a6) bne @newSetUp lea pf3ActiveList,a0 move.l a0,lActiveList(a6) bra @newSetUp @getFileSetUp ; set up for all get files tst.b lNewReply(a6) bne.s @newGetSetUp ; set up for old get files only move.w #Parameters1to4.GetParamSize,lStackFrameSize(a6) move.l Parameters1to4.GetWhere(a4),lWhere(a6) move.l Parameters1to4.GetPrompt(a4),lPrompt(a6) move.l Parameters1to4.fileFilter(a4),lFileFilter(a6) move.w Parameters1to4.numTypes(a4),lNumTypes(a6) move.l Parameters1to4.typeList(a4),lTypeList(a6) move.w #rStandardFileOldGetID,lHelpTemplate(a6) ; old get does not have a help item lea VirtualToSF2Get,a0 move.l a0,lMapFromVItems(a6) lea SF2GetToVirtual,a0 move.l a0,lMapToVItems(a6) move.b #7,lKnownRealItems(a6) lea gf2ActiveList,a0 move.l a0,lActiveList(a6) bra.s @oldSetUp @newGetSetUp ; set up for new get files only move.w #Parameters5to8.GetParamSize,lStackFrameSize(a6) clr.l lPrompt(a6) move.l Parameters5to8.fileFilter(a4),lFileFilter(a6) move.w Parameters5to8.numTypes(a4),d1 move.w d1,lNumTypes(a6) move.w lSelector(a6),d0 cmp.w #8,d0 ; only CustomGetFile can filter folders bne.s @getTypes tst.l lFileFilter(a6) sne lFilterFolders(a6) ; need a fileFIlter cmp.w #-1,d1 seq d0 ; and numTypes = -1 and.b d0,lFilterFolders(a6) ; to filter folders @getTypes move.l Parameters5to8.typeList(a4),lTypeList(a6) move.w Parameters5to8.dlgID(a4),d0 ; a zero for dialogID means use default bne.s @newGetIDOK move.w #sfGetDialogID,d0 @newGetIDOK move.w d0,lDlgID(a6) move.b #9,lKnownRealItems(a6) move.l Parameters5to8.activeList(a4),lActiveList(a6) bne.s @newSetUp lea gf3ActiveList,a0 move.l a0,lActiveList(a6) ; bra.s @newSetUp @newSetUp ; set up for all new routines move.l Parameters5to8.reply(a4),lReply(a6) move.l Parameters5to8.where(a4),lWhere(a6) move.l Parameters5to8.dlgHook(a4),lDlgHook(a6) move.l Parameters5to8.filterProc(a4),lFilterProc(a6) st lNewDialog(a6) bra.s @allSetUp @oldSetUp ; set up for all old routines move.l Parameters1to4.dlgHook(a4),lDlgHook(a6) move.l Parameters1to4.reply(a4),lReply(a6) move.w Parameters1to4.dlgID(a4),lDlgID(a6) move.l Parameters1to4.filterProc(a4),lFilterProc(a6) clr.b lNewDialog(a6) ; now check if no customization has been done. If so switch to new dialog tst.l lFilterProc(a6) bne.s @allSetUp ; can't change if there is a filter proc tst.l lDlgHook(a6) bne.s @allSetUp ; can't change if there is a dialog hook tst.b lDoingGetFile(a6) bne.s @testGetFile cmp.w #rStandardFileOldPutID,lDlgID(a6) bne.s @allSetUp ; can't change if there is a custom dialog ; looks like we get to pull a fast one and upgrade this to use new dialog st lNewDialog(a6) ; say we are using new dialog move.w #rStandardFilePutID,lDlgID(a6) ; switch ID move.b #11,lKnownRealItems(a6) ; now have 11 items lea pf3ActiveList,a0 move.l a0,lActiveList(a6) ; active list is different shi.b lUseOutlineOpen(a6) ; force outlining of open button bra.s @allSetUpUseTemplate ; going to use new dialog, so don't need to call scanTemplate <59,#84250> @testGetFile cmp.w #rStandardFileOldGetID,lDlgID(a6) bne.s @allSetUp ; can't change if there is a custom dialog ; looks like we get to pull a fast one and upgrade this to use new dialog st lNewDialog(a6) ; say we are using new dialog move.w #rStandardFileGetID,lDlgID(a6) ; switch ID move.b #9,lKnownRealItems(a6) ; now have 11 items lea gf3ActiveList,a0 move.l a0,lActiveList(a6) ; active list is different shi.b lUseOutlineOpen(a6) ; force outlining of open button @allSetUpUseTemplate clr.w lHelpTemplate(a6) ; going to use new dialog, so don't need to call scanTemplate <59,#84250> ; bra.s @allSetUp @allSetUp ; set up for all routines move.l Parameters1to4.activateProc(a4),lActivateProc(a6) move.l Parameters1to4.callBackPtr(a4),lCallBackPtr(a6) ; <56, #SLB102> moved locking of PACK3 from here to beginning of Initialize ; save the current grafport PEA lSavePort(A6) _GetPort ; save off current eject hook MOVE.L EjectNotify,lSaveEject(A6) ; save eject hook LEA ejectHit,A1 MOVE.L A1,EjectNotify ; record ours ; mark canceled flag in reply record, in case loading of resources fails <62, b6-ngk-004> move.l lReply(A6),a0 ; A0 = reply record <62, b6-ngk-004> clr.w StandardFileReply.sfGood(a0) ; note: works for both new and old reply records <62, b6-ngk-004> ; load in all required resources lea PreFlightResources,a2 ; a2 is table of resource types and IDs to load lea lPreFlightState(a6),a4 ; a4 is array of Hstates to save for each resource moveq #0,d3 @nextRes subq #4,sp ; loop through table move.l (a2)+,-(sp) move.w (a2)+,-(sp) _GetResource move.l (sp)+,d0 ;;<62> beq abortExit bne.s @gotRes ; <62, b6-ngk-004> addq #4,sp ; remove return address <62, b6-ngk-004> bra abortExit ; jump out and cleanup <62, b6-ngk-004> @gotRes move.l d0,a0 _HGetState move.b d0,(a4)+ _HNoPurge addq #1,d3 move.b d3,lPreFlightCount(a6) ; after each success, mark it cmp.b #NumPreFlightResources,d3 ; do each resource in table blt.s @nextRes ; get handles to icon mapping resource subq #4,sp move.l #'fmap',-(sp) move.w #rAliasTypeMapTable,-(sp) _GetResource move.l (sp)+,lAliasTypeMapH(a6) subq #4,sp move.l #'fmap',-(sp) move.w #rGenericFileTypeMapTableID,-(sp) _GetResource move.l (sp)+,lFileTypeMapH(a6) ; set up A4 to point to reply record MOVE.L lReply(A6),A4 ; A4 = reply record TST.B lNewReply(a6) BNE.S @2 ; only clear version field on old calls CLR.W SFReply.version(A4) ; version always zero @2 ; mark the reply.good false, in case an error causes us to abort clr.w StandardFileReply.sfGood(a4) ; note: works for both new and old reply records ; some defaults clr.b lQuitFlag(a6) moveq #1,d0 move.w d0,lLastSel(A6) ; no previous selection moveq #fsRtDirID, d0 move.l d0,lCurDir(a6) ; start at the root pea lTypeSelect(a6) _TypeSelectClear ; clear type select buffer ; see if we should try short circuiting the quicksort by checking if list is already sorted subq #4,sp ; space for GetEnvirons return move.w #smRegionCode,-(sp) ; push GetEnvirons verb _GetEnvirons move.l (sp)+,d0 cmp.w #verUS,d0 ; ### we need to decide if verBritian, verCanada, etc should be checked seq lTryShortSort(a6) move.w #-666,lCacheScrCode(a6) ; use an obviously bad script code to note cache is empty ; save off low mem cur disk global MOVE.W sfSaveDisk,lSaveDisk(A6) ; save next disk CLR.W sfSaveDisk ; don't want to eject ??? ; Get the volume of the startup disk MOVE BootDrive, D1 ; get startup WD LEA lIOCmd(A6),A0 ; do some I/O MOVE D1,ioVRefNum(A0) ; ask for info about startup WD CLR.L ioFilename(A0) ; no name CLR ioWDIndex(A0) ; no index _GetWDInfo BMI.S @setBootVol ; if fails then assume it was a vRefNum MOVE ioWDVRefNum(A0),D1 ; get volume of startup disk @setBootVol MOVE D1,lBootVol(A6) ; save away real startup vrefnum ;LEA lIOCmd(A6),A0 ; do some I/O CLR.W ioVolIndex(a0) MOVE.W lBootVol(A6),ioDrvNum(A0) ; lookup by vrefnum CLR.L ioVNPtr(A0) ; who cares about names _HGetVInfo ; get info about this drive MOVE.W ioVDrvInfo(A0),lBootDrive(A6); get drive of boot volume ; set up volume bsr FindDisk ; go setup the first disk bsr SniffDisk ; look at disk and folder ; make sure we are showing an arrow cursor bsr SetCursorToArrow ; preprocess DITL tst.b lNewDialog(a6) beq.s @doneMunge tst.b lDoingGetFile(a6) bne.s @doneMunge ; only call this on sf3Put dialog layout bsr.s MungeDITL ; change NewFolder user item into a rez-control @doneMunge rts DebuggerSymbol Initialize ;------------------------------------------------------------- ; munges a DITL before GetNewDialog gets a hold of it. ; Converts NewFolderUseItem into a ResControl item. ; ; trashes scratch registers ; MungeDITL ; get DLOG to get DITL ID subq #4,sp move.l #'DLOG',-(sp) move.w lDlgID(a6),-(sp) _GetResource move.l (sp)+,a0 move.l (a0),a0 ; get DITL and munge it subq #4,sp move.l #'DITL',-(sp) move.w 18(a0),-(sp) ; offset in DLOG to DITL ID _GetResource move.l (sp)+,a0 move.l a0,a1 ; save for future use moveq #sfItemNewFolderUser-2,d1 ; funky set up for FindItem2 bsr FindItem2 ; a0 now points to start of newfolder item lea 12(a0),a0 ; fix up a0 to point to item type of new folder item move.b (a0),d0 ; see if new folder item is a user item and.b #$7F,d0 ; ignore enable bit bne.s @exit ; if not user item then don't convert moveq #ctrlItem+resCtrl,d0 move.b d0,(a0)+ ; convert item to a rez-control move.b #2,(a0)+ ; rez-control has 2 bytes of parameters ; now munge in the resource ID parameter the rez-controls have subq #4,sp ; result move.l a1,-(sp) ; h move.l (a1),a1 sub.l a1,a0 ; calc offset a0 is into handle move.l a0,-(sp) ; offset moveq #0,d0 move.l d0,-(sp) ; ptr1 move.l d0,-(sp) ; len1 move.w #rNewFolderControlID,lTemp(a6) pea lTemp(a6) ; ptr2 moveq #2,d0 move.l d0,-(sp) ; len2 = SizeOf(word) _Munger addq #4,sp ; ignore result @exit rts DebuggerSymbol MungeDITL ;---------------------------------------------------------- ; Finalize ; ; undoes all initialization, and cleans up real tidy. ; Finalize ; clean up ghost volumes BSR CleanVols ; unmount those guys ; dispose of handle of dirIDs used by popup move.l lPopUpDirIDs(a6),a0 _DisposHandle ; get rid of the menu we stuck in the menu list (if itÕs still there) <9> ; NOTE: This code is totally dependent on the current behavior of the pop-up CDEF. The latest <9> ; (as this code is written) version of the pop-up does NOT arbitrarily remove and dispose itÕs <9> ; menu handle when the control is destroyed. Since the CDEF no longer cleans up after us, <9> ; we must delete the menu ourselves. Actually, IÕm being a LITTLE paranoid here and not trying <9> ; to delete the menu if I canÕt find it in the list (even though I KNOW it will be there...) <9> clr.l -(sp) ; make room for handle <9> move.w #sfPopUpMenuID, -(sp) ; give it our special id <9> _GetMHandle ; and ask for the handle <9> move.l (sp)+, d0 ; clean stack and test return value <9> beq.s @noMenuToKill ; NIL means no menu by this id is in the list<9> move.l d0, -(sp) ; push for dispose the menu <9> move.w #sfPopUpMenuID, -(sp) ; remove popup from menu list <9> _DeleteMenu ; <9> _DisposMenu ; d0 was pushed before delete <9> @noMenuToKill ; <9> ; restore graf port MOVE.L lSavePort(A6),-(SP) ; save the port _SetPort ; restore old eject hook proc MOVE.L lSaveEject(A6),ejectNotify ; restore the old notify rtn ; if we loaded stuff 'cause system disk was ejected, then make it purgable TST.B lDidPack2(A6) ; did we call pack2? BEQ.S @0 ; not free if no eject _DIUnLoad @0 ; restore purge state of all required resources ; could make this loop faster by checking for purge bit before GetResource lea PreFlightResources,a2 ; a2 is table of resource types and IDs to load lea lPreFlightState(a6),a4 ; a4 is array of Hstates to restore for each resource move.b lPreFlightCount(a6),d3 @nextRes subq.b #1,d3 blt.s @restoredState subq #4,sp move.l (a2)+,-(sp) move.w (a2)+,-(sp) _GetResource move.l (sp)+,a0 move.b (a4)+,d0 btst #purge,d0 ; was purgable bit set before? beq.s @nextRes _HPurge ; if so mark it purgable again bra.s @nextRes @restoredState ; restore lock state of PACK3 move.l AppPacks+stdFile*4,a0 move.b lPack3State(a6),D0 ; get saved lock state _HSetState ; restore lock state ; Re-enable keybds for all enabled scripts in case we disabled some of them. <36> tst.l IKeyboardState(a6) ; <33> But if it was locked when we came in, donÕt unlock it. bnz.s @keyboardWasLockedOnEntry ; <33> move.w #smKeyEnableKybds,-(sp) _KeyScript @keyBoardWasLockedOnEntry ; free up space for locals and restore a6 to stack frame move.w lStackFrameSize(a6),d3 ; get parameters to remove move.l lA6Link(a6),a4 move.l a6,a0 _DisposPtr move.l a4,a6 move.w d3,d0 ; return parameters to remove in d0 rts DebuggerSymbol Finalize ;------------------------------------------------------------- ; ; An error in a getfile attempt. ; SystemErrAlert MOVE #sfErrSystemError,D1 ; tell user that something isn't right BSR ErrorAlert ; show the alert. RTS DebuggerSymbol SystemErrAlert ;-------------------------------------------------------------------- ; ; RealToVirtualItem ; ; in: D0.W - real DITL item number ; out: D0.W - virtual item number ; Z - set if no translation possible, d0 left unchanged ; trashes A0 ; RealToVirtualItem tst.b lNewDialog(a6) ; new calls need no translation bne.s @done cmp.w #255,d0 ; only translate 0-255 bhi.s @noTrans move.l lMapToVItems(a6),a0 ; get translation table cmp.b lKnownRealItems(a6),d0 bls.s @doTrans ; if in range, do translation @noTrans cmp.b d0,d0 ; set Z flag bra.s @done @doTrans move.b (a0,d0.w),d0 ; translate via lookup table @done rts DebuggerSymbol RealToVirtualItem ;-------------------------------------------------------------------- ; ; VirtualToRealItem ; ; in: D0.W - virtual item number ; out: D0.W - real DITL item number ; Z - set if no translation possible, d0 left unchanged ; ; trashes A0 ; VirtualToRealItem tst.b lNewDialog(a6) ; new calls need no translation bne.s @done move.l lMapFromVItems(a6),a0 ; get translation table move.b (a0,d0.w),d0 @done rts DebuggerSymbol VirtualToRealItem ;-------------------------------------------------------------------- ; ; MainDialogHook ; ; in: lHit(a6) contains item hit ; a3 = dialog ptr ; MainDialogHook move.w lHit(a6),d0 cmp.w #sfHookFirstCall,d0 beq caseFirstHook ; sfHookFirstCall pseudo-item cmp.w #sfHookLastCall,d0 beq caseLastHook ; sfHookLastCall pseudo-item bsr.s RealToVirtualItem subq #1,d0 beq caseOpen ; itemOpenButton subq #1,d0 beq caseCancel ; itemCancelButton subq #2,d0 beq caseOpenParent ; itemVolumeUser subq #1,d0 beq caseEject ; itemEjectButton subq #1,d0 beq caseNextDrive ; itemDesktopButton, but means next drive for compatability subq #6,d0 beq caseNewFolder ; itemNewFolderUser blt.s @doneProcess SUB #89,D0 ; (101) rebuild file list BLT.S @doneProcess BEQ caseRebuildFileList SUBQ #1,D0 ; (102) pop up a path list BEQ casePopUpPathMenu SUBQ #1,D0 ; (103) open a folder BEQ caseOpenSelectedFolder SUBQ #1,D0 ; (104) open an alias folder BEQ caseOpenAlias SUBQ #1,D0 ; (105) open the desktop BEQ caseGotoDesktop SUBQ #1,D0 ; (106) open the parent of an alias BEQ caseGotoAliasTarget SUBQ #1,D0 ; (107) open parent of current selection BEQ caseOpenParent SUBQ #1,D0 ; (108) command right arrow BEQ caseNextDrive SUBQ #1,D0 ; (109) command left arrow BEQ casePrevDrive SUBQ #1,D0 ; (110) hookChangeSelection BEQ caseChangeSelection SUB #sfHookSetActiveOffset-110,D0 BLT.S @doneProcess CMP.W #50,D0 ; (200-250) set active item BLT caseSetActiveItem SUB #sfHookCharOffset-sfHookSetActiveOffset,D0 ; ($1000+) ?/character typed BGT caseKeyDown @doneProcess RTS DebuggerSymbol MainDialogHook ;------------------------------------------------------------- ; ; dialog is created but not shown, so do fixes ; caseFirstHook ; cache away some font info pea lFontInfoRec(a6) ; get the font info record _GetFontInfo ; get the info move.w lFontInfoRec.ascent(a6),d0 add.w lFontInfoRec.descent(a6),d0 add.w lFontInfoRec.leading(a6),d0 move.w d0,lHeight(a6) ; cache away the system script moveq #smSysScript,d0 bsr GetScript move.w D0,lSystemScript(A6) ; save system script (low word) in globals MOVE.W SysFontFam,lSystemFont(A6) ; save system font in globals CLR.W lSystemFontSize(A6) ; use default size CLR.B lDirName.style(A6) ; the current directory is always unstyled ; cache of control handles for all buttons moveq #sfItemOpenButton,d0 lea lMainOpen(a6),a0 bsr CacheButtonControl move.l lBox.topLeft(a6),lOpenRect.topLeft(a6) ; save off button rect move.l lBox.botRight(a6),lOpenRect.botRight(a6) cmp.w #ctrlItem+btnCtrl,lKind(A6) ; this is a hack for PageMaker 4.0 beq.s @mainDone ; they change item 1 to a PICT item, instead of a button clr.l lMainOpen(a6) ; I will mark this by a NIL controlhandle @mainDone moveq #sfItemCancelButton,d0 lea lMainCancel(a6),a0 bsr CacheButtonControl moveq #sfItemEjectButton,d0 lea lMainEject(a6),a0 bsr CacheButtonControl moveq #sfItemDesktopButton,d0 lea lMainDesktop(a6),a0 bsr CacheButtonControl clr.l lMainNewFolder(a6) ; assume there is no new folder button ; see if the open name in the DITL is different than normal open ; if it is we will use the DITL open name when a file is selected ; and "open" when a folder or volume is selected. LEA lOpenName(A6), A1 MOVEQ #sfOpenName, D1 BSR GetLocalString ; will return open string in lOpenName(A6) move.l lMainOpen(A6),d0 ; get open control handle beq.s @noOpenBut ; if it is NIL, then skip checking name move.l d0,-(SP) ; pass in control handle PEA lOpenAltName(A6) ; will return control title in lOpenAltName(A6) _GetCTitle moveq #0,d0 moveq #0,d1 tst.b lOpenAltName(A6) ; for Word 4.0, if DITL has no title <58, #82594> beq.s @noOpenBut ; for open button, don't use alt. <58, #82594> lea lOpenName(A6),a0 move.b (a0)+,D0 ; A0 is first char of string1 lea lOpenAltName(A6),a1 move.b (a1)+,D1 ; A1 is first char of string2 subq #2,sp ; room for result move.l a0,-(sp) move.l a1,-(sp) move.w d0,-(sp) move.w d1,-(sp) _IUMagIDString move.w (sp)+,d0 ; get result in d0 @noOpenBut move.b d0,lOpenAltExists(a6) ; D0 is 0 if equal, 1 if not equal move.b d0,lOpenState(a6) ; remember we are now showing the altName ; set up command key equivalents from string resource lea lString(A6), A1 moveq #sfCommandKeys, D1 bsr GetLocalString ; will return cmd keys string in lString(A6) lea lString+1(A6), a0 lea lCmdKeyOpen(a6),a1 ; first command key in table moveq #4,d0 ; number of command keyes in table _BlockMove ; copy command keys into respective slots ; set appropriate default active item ; putFile has fileName TE active ; getFile has file list active move.l lActiveList(a6),a0 move.w 2(a0),lActiveDITLitem(a6) ; get first item in list of activateable moveq #sfItemFileListUser,d0 bsr VirtualToRealItem cmp.w lActiveDITLitem(a6),d0 seq lListIsActive(a6) ; if it is file list, then remember ; set up user item for volume icon/name moveq #sfItemVolumeUser,d0 bsr VirtualToRealItem move.w d0,d3 bsr SetUserDraw ; install user draw proc ; set up user item for list of files moveq #sfItemFileListUser,d0 bsr VirtualToRealItem move.w d0,D3 ; user field ID for file box bsr SetUserDraw ; install user draw proc ; this is here so lBox points to ; file list for SetUp List ; set up flags in dialog record. This is done before app gets first hook, ; in case app wants to change default item by changing aDefItem. moveq #sfItemCancelButton,D0 ; get cancel button item bsr VirtualToRealItem move.w d0,d1 ; d1 = cancel button number moveq #sfItemOpenButton,D0 ; get Open button item bsr VirtualToRealItem ; d0 = default button number move.b lNewDialog(a6),d2 ; d2 = whether to track cursor bsr SetUpDialogFlags tst.b lDoingGetFile(a6) ; special casing bne.s @getFileMisc ; go to getfile ; NIL or zero length string prompt parameter => use string in DITL MOVE.L lPrompt(A6),D0 BEQ.S @useDITL ; use DITL prompt if NIL MOVE.L D0,A2 ; point to prompt moveq #sfItemPromptStaticText,d0 bsr VirtualToRealItem TST.B (A2) ; use DITL prompt if zero lenght string BEQ.S @useDITL BSR SetItsText @useDITL ; set TextEdit to initially be the filename passed in moveq #sfItemFileNameTextEdit,d0 bsr VirtualToRealItem MOVE.L lDefaultName(A6),A2 ; point to file name BSR SetItsText ; then select all of it move.l A3,-(SP) ; pass the windowPtr moveq #sfItemFileNameTextEdit,d0 bsr VirtualToRealItem move.w d0,-(sp) clr.w -(SP) ; select all move.w #300,-(SP) _SelIText ; set selection ; then enable autoscrolling of it st -(sp) ; fAuto: BOOLEAN move.l teHandle(a3),-(sp) ; hTE: TEHandle _TEAutoView ; if there is a new folder button, then cache it off tst.b lNewDialog(a6) beq.s @continueSetUp moveq #sfItemNewFolderUser,d0 lea lMainNewFolder(a6),a0 bsr.s CacheButtonControl ; bra.s @continueSetUp ; skip around getfile specials @getFileMisc @continueSetUp ; rearange MFS dialogs to work tst.b lNewReply(a6) bne.s @goodDITL bsr SF1Compatability ; only call this on routines 1-4 @goodDITL bsr GetFileListBoundary bsr FixBoxes bsr SetUpList bsr FixBoxes ; Now position the window MOVEQ #-1,D0 CMP.L lWhere(A6),D0 ; is where = <-1,-1> ? BNE.S @moveWindow MOVE.L A3,-(SP) ; pass the window MOVE.B #lcMainScreen,-(SP) ; over main monitor MOVE.B #hcCenter,-(SP) ; center horizontally MOVE.B #vcAlertCenter,-(SP); center vertically like an alert _AutoPositionWindow BRA.S @windowMoved @moveWindow MOVE.L A3,-(SP) ; pass the window MOVE.L lWhere(A6),-(SP) ; where it goes ST -(SP) ; and select it _MoveWindow @windowMoved rts DebuggerSymbol caseFirstHook ; ; in d0 = virtual item code ; a0 = address to store control handle CacheButtonControl move.l a0,-(sp) bsr VirtualToRealItem bsr GetIt move.l (sp)+,a0 move.l lItem(a6),(a0) rts ; This is called after app get first hook call. ; It gives me a change to fix up after tweaking which app may have done. ; MainHookAfterFirstHook move.w lHit(a6),lInitialMapped(a6) ; save what app returned bsr PositionSanityCheck ; make sure dialog is on screen tst.b lNewDialog(a6) ; only do this for original four calls bne.s @doneCompat ; that have not been upgraded to new dialogs bsr SF2Compatability ; tweak HFS dialogs to work @doneCompat bsr FixBoxes ; update boxs now that we know where the window is bsr GetFileListBoundary ; set up lNRect with file list boundary tst.b lNewDialog(a6) bne.s @boxFromDITL @makeBox lea lPopUpMaxRect(a6),a0 move.w lNRect+Left(a6),Left(a0) ; Left of popup is same as left of file list move.w lNRect+Right(a6),Right(a0) ; Right of popup is same as right of file list move.w lNRect+top(a6),d1 subq.w #4,d1 ; need some padding move.w d1,bottom(a0) ; bottom of popup is 3 pixels on top of file list sub.w lHeight(a6),d1 ; system script height subq.w #3,d1 ; more padding move.w d1,top(a0) ; top of popup is script height + pad of 7 pixels for box bra.s @haveMaxRect @boxFromDITL moveq #sfItemPopUpMenuUser,d0 bsr GetIt ; get bounding box move.l lBox(a6),lPopUpMaxRect(a6) move.l lBox+4(a6),lPopUpMaxRect+4(a6) move.w lNRect+top(a6),d0 ; now check that it is at least 4 pixels above file list sub.w lPopUpMaxRect+bottom(a6),d0 bmi.s @haveMaxRect ; if not above list, do nothing sub.w #4,d0 bge.s @haveMaxRect ; if already 4 pixels above, do nothing add.w d0,lPopUpMaxRect.top(a6) ; move control up to leave 4 pixels space add.w d0,lPopUpMaxRect.bottom(a6) @haveMaxRect subq #4,sp ; :ControlHandle; move.l a3,-(sp) ; theWindow: WindowPtr pea lPopUpMaxRect(a6) ; boundsRect: Rect clr.l -(sp) ; title: Str255 no title sf -(sp) ; visible: BOOLEAN invisible til we build list move.w #popupTitleCenterJust,-(sp) ; value: INTEGER centered, no styling move.w #sfPopUpMenuID,-(sp) ; min: INTEGER menu ID for popup clr.w -(sp) ; max: INTEGER title width move.w #popupMenuCDEFproc,-(sp) ; procID: INTEGER no variant clr.l -(sp) ; refCon: LONGINT no refCon _NewControl move.l (sp)+,lPopUpControl(a6) ; save control handle rts DebuggerSymbol MainHookAfterFirstHook ;------------------------------------------------------------------------------------- ; ; This gets the event off to a good start. We want the activate then update. ; If we let the dialog mgr do this, we might get key or mouse downs before the ; update. ; StartEventHandling ; keep calling GetNextEvent 'til we get the activate event for the main dialog @getAgain subq #2,sp ; room for Boolean result move.w #256,-(sp) ; only want activate events pea lEvent(a6) ; VAR eventRecord _GetNextEvent tst.b (sp)+ beq.s @getAgain ; if no event, try again cmp.w #activateEvt,lEvent.what(a6) bne.s @getAgain ; if not activate event, try again ; process the activate event by calling my dialog filter (which completely overrides dialog mgr) bsr.s HandleEvent ; handle activate event (this is called for both deact and act) cmp.l lEvent.message(a6),a3 bne.s @getAgain ; if not for main sf dialog, try agin btst #0,lEvent.modifiers+1(a6) beq.s @getAgain ; if not activating, try again (is this necessary?) ; fake an update event and handle it in my dialog filter move.w #updatEvt,lEvent.what(a6) move.l a3,lEvent.message(a6) bsr.s HandleEvent rts DebuggerSymbol StartEventHandling ;--------------------------------- ; send event to TheDialogFilter ; HandleEvent subq #2,sp ; room for boolean result move.l a3,-(sp) ; dialog pea lEvent(a6) ; VAR event record pea lHit(a6) ; VAR itemHit bsr TheDialogFilter addq #2,sp ; ignore result rts DebuggerSymbol HandleEvent ;-------------------------------------------------- ; ; This is called after initial activate and update event ; BuildInitialList tst.b lNewDialog(a6) beq.s @normalList ; old calls to sf don't get fancy -1 mapping ; if app mapped -1 to 110 then auto-select first file move.w lInitialMapped(a6),d0 cmp.w #sfHookChangeSelection,d0 ; if app returned sfHookChangeSelection bne.s @chkDesktop st d0 ; force rebuild bsr caseChangeSelection ; then rebuild list before showing dialog bra.s @done ; if app mapped -1 to 103 then goto to desktop @chkDesktop cmp.w #sfHookGotoDesktop,d0 bne.s @normalList bsr caseGotoDesktop2 ; switch to desktop and redraw bra.s @done ; otherwise select first file in list if file list is initial active item @normalList bsr ReListDisk ; enumerate folder, build file list, and draw it tst.b lListIsActive(a6) ; see if file list is keyboard target beq.s @done ; if not, don't select first tst.b lAtDesktop(a6) ; if at desktop <67, #BS-047> ble.s @first ; <67, #BS-047> move.w lBootVol(a6),lVolRefNum(A6) ; switch to boot volume <67, #BS-047> bsr SelectBootVolume ; select boot volume <67, #BS-047> bra.s @done @first move.w #chDownArrow,D0 ; else get first non-dimmed by simulating a down arrow bsr ArrowKey ; make sure volume icon is up to date @done move.w lVolRefNum(A6),d0 ; set up volume icon to current disk <55.7, #82680> bsr SetVolumeIcon ; <55.7, #82680> rts DebuggerSymbol BuildInitialList ;------------------------------------------------------------- ; release list manager stuff ; caseLastHook move.l lFileListHandle(a6),a1 ; get file list handle move.l a1,-(sp) ; dispose file list handle _LDispose rts DebuggerSymbol caseLastHook ;------------------------------------------------------------- ; ; User hit cancel, escape, or command-period ; caseCancel st lQuitFlag(a6) ; want to fall out of event loop rts DebuggerSymbol caseCancel ;------------------------------------------------------------- ; ; User hit open/save, return, enter, or doubled-clicked on item in list ; caseOpen move.l lCurDir(A6), d7 ; default directory move.w lVolRefNum(a6),d6 ; default vrefnum tst.b lDoingGetFile(a6) bne GetFileEnd PutFileEnd tst.b lAtDesktop(a6) ; at desktop we have many possible place to save ble.s @haveDir move.w lDisplyedVolRef(a6),d6 ; get the volume to save on move.w d6,d0 ; get desktop for this vRefNum bsr GetVolumeInfoPtr ; a0 (out) pointer to info move.l PerVolumeInfo.desktopDir(a0),d7 ; desktop dirID @haveDir ; get info on name choosen to see if it already exists bsr GetReplysFilenametoA0 ; get name in filename box move.l a0,a1 LEA lIOCmd(A6), A0 ; Point to IO command block MOVE.W d6,ioVRefNum(A0) ; use volume from globals MOVE.L A1,ioFileName(A0) ; Set pointer to volume name CLR.W ioFileType(A0) ; no variations, please CLR.W ioFDirIndex(A0) ; And use given name. move.l d7,ioDirID(a0) ; use current directory _GetCatInfo BEQ.S @chkOver ; if no error, may overwrite? CMP.W #fnfErr,D0 ; not found BEQ FinishReplyRecord ; doesn't exist, plow ahead ; CMP #-5000,D0 ; access denied ; BEQ.S goodPut ; write only folders will always give this ; we're not supporting write only folders yet CMP.W #NSVErr,D0 ; see if bad volume BNE SystemErrAlert MOVE.W #sfErrBadFilename,D1; tell user the name or volume was bad bra ErrorAlert ; ask the user if the existing file should be overwritten @chkOver btst #ioDirFlg,ioFLAttrib(a0) ; is it a folder? beq.s @chkReplaceExisting ; if not go on move #sfErrSaveOnFolder,D1 ; warn user that that is a folder bsr ErrorAlert @exit bra ExitCaseOpen @chkReplaceExisting move.l lIOCmd+ioFileName(A6),a1 ; pass the file name move.w #rSFReplaceExistingDialogID,d4 ; d4 is dialog to use move.l #sfReplaceDialogRefCon,d3 ; d3 is dialog refcon bsr ErrorAlert2 ; raise a file alert subq #1,D0 ; look at result bne.s @exit ; only 1 is "yes", all others mean cancel tst.b lNewReply(A6) ; can caller handle replace flag? beq.s @1 ; br around if not addq.b #1,StandardFileReply.sfReplacing(A4) ; yes, it is a replace @1 bra FinishReplyRecord GetFileEnd bsr FillReplyRecord ; fill the return record bsr GetSel ; get selection into A0 bmi FinishReplyRecord ; should never happen, (means nothing is selected) ; but if it does then fill out vol/dir only btst #isAliasBit,FileEntry.feFndrFlags(a0) ; if this is an alias, then app did some slimy ; hook stuff to get this to happen bne FinishReplyRecord ; if so, return with alias (not target) in reply btst #ioDirFlg,FileEntry.feFlAttr(a0) ; if this is a directory, then app did some slimy ; hook stuff to get this to happen bne DoneGood ; if so, just return with current reply record move.l FileEntry.feParID(A0),d7 ; remember dirID move.w FileEntry.feVRefNum(A0),d6 ; remember vRefNum ; On opens, check if it is stationery and warn if this is a ; non stationery-aware application. move.w FileEntry.feFndrFlags(A0),d5 swap d5 ; put finder flags in high word move.b FileEntry.feFLAttr(A0),d5 ; and file attributes in low word StatAndLockCheck ; needed flags are in d5 btst #isStationeryBit+16,d5 ; is this stationery? (testing high word) beq.s @CheckLock ; br if not, no need for warning subq #4, sp ; reserve space for handle move.l #'SIZE', -(sp) ; look for app's size resource move #-1, -(sp) _GetResource ; ### maybe we should call process manager to get this move.l (sp)+, d0 ; got the size? beq.s @doneStatWarning ; br if no size, always do warning move.l d0, a0 move.l (a0), a0 ; deref size resource btst #isStatAwareBit, 1(a0) ; is app stationery aware? bne.s @doneStatWarning ; br if so, doesn't need a warning @warning bsr GetReplysFilenametoA0 move.l a0,a1 ; a1 is for paramtext move.w #rSFStationeryWrnDialogID,d4 ; d4 is dialog to use move.l #sfStatWarnDialogRefCon,d3 ; d3 is dialog refcon bsr ErrorAlert2 ; raise a file alert subq #1,D0 ; look at result bne.s ExitCaseOpen ; ­1 -> it was cancelled @doneStatWarning @CheckLock tst.b lNewReply(a6) ; don't give lock warning to old calls beq.s @noLockWarning btst #isLockedFile,d5 ; is the file locked beq.s @noLockWarning ; br if not, no need for warning btst #isStationeryBit+16,d5 ; is this locked stationery? (testing high word) bne.s @noLockWarning ; if so, no need for warning bsr GetReplysFilenametoA0 move.l a0,a1 ; a1 is for paramtext move.w #rSFLockedWrnDialogID,d4 ; d4 is dialog to use move.l #sfLockWarnDialogRefCon,d3 ; d3 is dialog refcon bsr ErrorAlert2 ; raise a file alert subq #1,D0 ; look at result bne.s ExitCaseOpen ; ­1 -> it was cancelled @noLockWarning FinishReplyRecord ; Fill out the dirID/vrefnum or WDRefnum part of the reply record tst.b lNewReply(A6) ; can caller handle dirIDs? beq.s @makeWD ; br if not, make a WD move.l d7, StandardFileReply.sfFile+FSSpec.parID(A4) ; return back chosen directory move.w d6,StandardFileReply.sfFile+FSSpec.vRefNum(A4) ; return real vrefnum bra.s DoneGood @makeWD cmp.w #sigWord,lSigWord(a6) ; is this an MFS disk? (lSigWord set up by SetVolumeIcon) beq.s @returnVolume ; br if so, don't make WD on MFS Volumes lea lIOCmd(a6),a0 ; get our IO Block back move.w d6,ioVRefNum(a0) ; make a WD for this volume clr.l ioFileName(a0) move.l d7,ioDirID(a0) ; with this dirID move.l #'ERIK',ioWDProcID(a0) ; historical reasons _OpenWD bmi SystemErrAlert ; too many WDs open (*** separate alert?) 24feb87 move.w ioVRefNum(a0),d6 ; returns working directory refnum in ioVRefNum @returnVolume move d6,SFReply.vRefNum(a4) DoneGood addq.b #1,SFReply.good(A4) ; true, a good name (this works for both reply records) st lQuitFlag(a6) ; want to fall out of event loop ExitCaseOpen rts DebuggerSymbol caseOpen ;------------------------------------------------------------- ; ; User hit NewFolder Button ; caseNewFolder tst.b lNewDialog(a6) ; on do this is there is a new folder button beq.s @exit tst.b lDoingGetFile(a6) bne.s @exit ; only do this if button is enabled move.w #sfItemNewFolderUser,d0 bsr VirtualToRealItem bsr CanDo ; is the new folder control active ? bmi.s @exit ; exit if it is dimmed ; center over new folder button moveq #sfItemNewFolderUser,d0 bsr VirtualToRealItem bsr GetIt lea lBox(a6),a0 move.w Rect.bottom(a0),d0 add.w Rect.top(a0),d0 lsr.w #1,d0 ; center.v = (top+bottom)/2 swap d0 move.w Rect.right(a0),d0 add.w Rect.left(a0),d0 lsr.w #1,d0 ; center.h = (left+right)/2 move.l d0,lPoint(a6) pea lPoint(a6) _LocalToGlobal ; lPoint now contains center of button in global coordinates ; get dialog for new folder name move.w #rSFNewFolderDialogID,d0 ; id for dialog move.l #sfNewFolderDialogRefCon,d3 ; refcon for new folder dialog bsr DoSubDialog ; return button hit in d0 cmp.w #1,d0 bne.s @exit ; if not action button, then skip out move.w lNewFolderErr(a6),d0 ; see if there was an error during folder create bne.s @handleErr bsr NewDir ; if not switch to new folder bra.s @exit @handleErr moveq #sfFolderNameExists,d1 ; special case error of name already exists cmp.w #dupFNerr,d0 beq.s @doError moveq #sfErrSystemError,d1 ; otherwise, use generic error message @doError bsr ErrorAlert @exit rts DebuggerSymbol caseNewFolder ;------------------------------------------------------------- ; ; NewFolderDialogHook move.w lHit(a6),d0 cmp.w #sfHookFirstCall,d0 bne.s @tryNull ; set up dialog flags moveq #1,d0 ; d0 = default button number moveq #2,d1 ; d1 = cancel button number st d2 ; d2 = track cursor bsr SetUpDialogFlags ; center over new folder button ; lPoint contains center of button in global coordinates move.w portRect+Rect.bottom(a3),d0 add.w portRect+Rect.top(a3),d0 lsr.w #1,d0 ; center.v = (top+bottom)/2 swap d0 move.w portRect+Rect.right(a3),d0 add.w portRect+Rect.left(a3),d0 lsr.w #1,d0 ; center.h = (top+bottom)/2 sub.l d0,lPoint(a6) ; lPoint now contains where to move window to move.l a3,-(sp) move.l lPoint(a6),-(sp) clr.w -(sp) ; don't bring to front _MoveWindow bsr MyCheckWindow bne.s @windowOK ; uh, oh. centering over newfolder button will put it off screen ; so center over main dialog, which we know is on screen. move.l a3,-(sp) ; whichWindow: WindowPtr move.b #lcParentWindow,-(sp) ; where: LocationControlValues move.b #hcCenter,-(sp) ; horizontalControl: HorizontalControlValues move.b #vcDocumentCenter,-(sp) ; verticalControl: VerticalControlValues _AutoPositionWindow @windowOK ; remember control handle of create button moveq #1,d0 ; create button is item 1 bsr GetIt move.l lItem(a6),lNFCreate(a6) ; select all of text by default move.l a3,-(SP) ; pass the windowPtr move.w #3,-(sp) ; TE is item 3 clr.w -(SP) ; select all move.w #300,-(SP) _SelIText ; set selection bra @exit @tryNull cmp.w #sfHookNullEvent,d0 bne.s @tryCancel ; if TE has 0 chars in it then dim "Create" button moveq #3,d0 ; TE is item 3 bsr GetIt move.l lItem(a6),a0 _GetHandleSize ; get length of text typed moveq #0,d1 tst.w d0 ; >0 length -> $0000 sle d1 ; 0 length -> $00ff move.l lNFCreate(a6),-(sp) move.w d1,-(sp) _HiliteControl ; properly enable button bra @exit @tryCancel cmp.w #2,d0 ; if cancel then dismiss dialog beq @dismisser cmp.w #1,d0 ; if not "New" button then go on bne @exit ; get text out of TE box moveq #3,d0 ; TE is item 3 bsr GetIt move.l lItem(A6),-(sp) pea lString(a6) _GetIText ; get current keyboard script bsr GetKeyScript move.w d0,lItem(a6) ; get script out of low word ; create a folder lea lIOCmd(a6),a0 lea lString(a6),a1 move.b (a1),d0 ; truncate entered string to 31 chars cmp.b #31,d0 bls.s @nameOK moveq #31,d0 move.b d0,(a1) @nameOK move.l a1,ioNamePtr(a0) move.w lVolRefNum(a6),ioVRefNum(a0) move.l lCurDir(a6),ioDirID(a0) tst.b lAtDesktop(a6) ; if we are not at desktop then vol/dir is OK ble.s @dirOK move.w lDisplyedVolRef(a6),d0 ; d0 (in) vrefnum of disk move.w d0,lIOCmd+ioVRefNum(a6) ; better vRefNum bsr GetVolumeInfoPtr ; a0 (out) pointer to info move.l PerVolumeInfo.desktopDir(a0),lIOCmd+ioDirID(a6) ; better dirID lea lIOCmd(a6),a0 ; restore trashed a0 @dirOK _DirCreate move.w d0,lNewFolderErr(a6) bne.s @dismisser ; set script byte in finder info moveq #-1,d0 move.w d0,ioFDirIndex(a0) ; get info by dirID _GetCatInfo bmi.s @goto ; skip script set if error move.w lItem(a6),d0 bmi.s @goto ; skip script set if smSystemScript <36> bset #7,d0 ; high bit means use script move.b d0,ioFlxFndrInfo+sfFndrScript(a0) ; set the folder's script byte _SetCatInfo ; now go into new folder and rebuild list @goto move.l ioDirID(a0),lCurDir(a6) move.w ioVRefNum(a0),d0 ; need Drive number, but <56, #BS-036> bsr VRefNumToDriveNo ; have a vRefNum ,so convert <56, #BS-036> move.w d1,lDriveNo(A6) ; <56, #BS-036> @dismisser st lSubDlgDone(a6) @exit rts DebuggerSymbol NewFolderDialogHook ;------------------------------------------------------------- ; ; User typed command-up-arrow, back up in the directory ; caseOpenParent tst.b lAtDesktop(a6) ; at desktop already? bgt.s @exit ; br if so, exit early lea lIOCmd(a6),a0 ; get our param block move #-1,ioFDirIndex(a0) ; lookup by dirID mode move.l lCurDir(A6),ioDirID(a0) ; lookup current folder clr.l ioFileName(a0) ; no names _GetCatInfo bmi.s @exit move.l ioDrDirID(a0),-(sp) ; remember dir where we were (so we can select it) move.w ioVRefNum(a0),-(sp) ; remember vol where we were move.l ioDrParID(a0), d1 ; get the parent directory move.l d1,lCurDir(a6) ; make parent the current dir moveq #fsRtParID, d0 ; = 1 cmp.l d0, d1 ; at root of root? bne.s @select ; br if not, leave dir alone bsr GotoDesktop ; change to special desktop @select st lDontDrawList(a6) ; turn off drawing to reduce flick, cause about to change selection bsr NewDir ; rebuild list at new location move.w (sp)+,d4 ; retrieve previous volume move.l (sp)+,d2 ; retrieve previous dir ; now find the folder we were in in this list and select it moveq #-1,d3 ; start at start @nextcell addq.l #1,d3 move.l d3,d0 swap D0 ; need D0 high word be index, low word be zero bsr GetCellPtr ; D0=cell in ==> A0=dataPtr out bpl.s @next ; minus -> out of cells sf lDontDrawList(a6) ; turn drawing back on bsr DrawFileList ; could not find parent, won't call SelectAndReveal so need to draw bra.s @exit @next moveq #fsRtDirID,d0 ; = 2 cmp.l d0,d2 ; were we at root before? bne.s @notRoot moveq #fsRtParID,d0 ; = 1 cmp.l FileEntry.feParID(a0),d0 ; then we need to find a volume to select beq.s @dirOK ; (feTypeOrDirID contains desktop folder ID) bra.s @nextcell @notRoot cmp.l FileEntry.feTypeOrDirID(a0),d2 ; is this the right folder? bne.s @nextcell @dirOK cmp.w FileEntry.feVRefNum(a0),d4 ; is this the right drive? bne.s @nextcell st d2 ; try to center parent in file list bsr SelectAndReveal ; now select that folder, will turn drawing back on @exit rts DebuggerSymbol caseOpenParent ;---------------------------------------------------------------- ; ; When the user hits the eject button, we eject the disk, erase ; any current file list, and then fall into the code to skip to ; the next disk. ; caseEject bsr SmartEjectDisk ; eject either the selected disk, or the current disk bne SystemErrAlert ; any problem doing so? Eject2 tst.b lAtDesktop(a6) ; are we are desktop? ble.s @nextDisk ; if not goto next disk (cause this one is history) bra caseGotoDesktop2 @nextDisk bsr NextDisk ; go figure out next disk, sets lDriveNo(a6) bsr.s GotoVolumesPreferedFolder ; find the folder to goto for the new volume @done rts DebuggerSymbol caseEject ;------------------------------------------------------------------- ; changes to prefered folder for lDriveNo(A6) ; GotoVolumesPreferedFolder move.w lDriveNo(A6),d0 ; get the new drive number bsr GetVinfo ; if we have a preferred folder then goto it move.w ioVRefNum(a0),d0 move.w d0,d1 ; save vRefnum, cause GetVolumeInfoPtr trashes a0 & d0 bsr GetVolumeInfoPtr move.l PerVolumeInfo.lastDir(a0),d0 beq.s @doit ; if no preference, defaults to root move.l d0,lCurDir(a6) @doit move.w d1,d0 bsr SetVolumeIcon bsr SuckDisk ; and rebuild the file list rts DebuggerSymbol GotoVolumesPreferedFolder ;------------------------------------------------------------------- ; saves prefered folder associated with lVolRefNum(a6) ; SaveVolumesPreferedFolder tst.b lAtDesktop(a6) ; if we are at desktop bgt.s @done ; don't save current location ; save off folder at in current volume move.w lVolRefNum(a6),d0 bsr GetVolumeInfoPtr ; return info for the volume by a0 move.l lCurDir(a6),PerVolumeInfo.lastDir(a0) @done rts DebuggerSymbol SaveVolumesPreferedFolder ;------------------------------------------------------------------- ; ; caseNextDrive - When the user hits the right arrow, this hops to the next disk. ; caseNextDrive bsr CountDIPs cmp.w #1,d3 ; want to do nothing if only one disk beq.s @done bsr.s SaveVolumesPreferedFolder ; save off folder at in current volume bsr NextDisk ; go figure out next disk, sets lDriveNo(a6) bsr GotoVolumesPreferedFolder ; find the folder to goto for the new volume @done rts DebuggerSymbol caseNextDrive ;------------------------------------------------------------------- ; ; casePrevDrive - When the user hits the left arrow, this hops to the previous disk. ; casePrevDrive bsr CountDIPs cmp.w #1,d3 ; want to do nothing if only one disk beq.s @done bsr.s SaveVolumesPreferedFolder ; save off folder at in current volume bsr PrevDisk ; go figure out prev disk, sets lDriveNo(a6) bsr GotoVolumesPreferedFolder ; find the folder to goto for the new volume @done rts DebuggerSymbol casePrevDrive ;---------------------------------------------------------------- ; ; The application, on its dlg hook, can request a "rebuilding" of ; the file list based on new selection criteria. This is handled here. ; caseRebuildFileList bsr DumpList ; get rid of old list move.w lVolRefNum(A6), d0 ; <21dec87> get volume being displayed neg.w d0 ; <21dec87> turn into a drive number cmp.w sfSaveDisk, d0 ; <21dec87> has app requested a change? bne.s @changeDir ; <21dec87> br if so, switch to that volume move.l lCurDir(A6), d0 ; <21dec87> get dir being displayed cmp.l CurDirStore, d0 ; <21dec87> has app requested a change? bne.s @changeDir ; <21dec87> br if so, switch to that dir bsr ReListDisk ; set up new list rts ; get on with the show @changeDir move.w sfSaveDisk,lSaveDisk(A6) ; <21dec87> pass default volume to FindDisk bsr FindDisk ; <21dec87> go figure out saveDisk and CurDir bsr SuckDisk rts DebuggerSymbol caseRebuildFileList ;---------------------------------------------------------------- ; ; The application, on its dlg hook, can request a change of selected item. ; This can also cause the file list to be rebuilt if the volume or folder changed ; ; in: d0 ==0 ->smart rebuild, only rebuild list if it will be different ; <>0 ->force rebuild, even if folder is same ; caseChangeSelection tst.b lNewReply(a6) ; this only works with the new reply record beq.s @exit move.w d0,d1 ; remember if d0 was non-zero move.w StandardFileReply.sfFile+FSSpec.vRefNum(a4),d0 move.l StandardFileReply.sfFile+FSSpec.parID(a4),d7 tst.w d1 bne.s @redoList ; if d0 was non-zero then force rebuild cmp.w lVolRefNum(A6),d0 bne.s @redoList cmp.l lCurDir(A6),d7 beq.s @changeSelection @redoList bsr GoFindDisk ; d7=dirID, d0=vRefNum bsr SuckDisk @changeSelection lea StandardFileReply.sfFile+FSSpec.name(A4), A0 ; get address of default name move.b (a0),d0 ; was a name supplied? beq.s @exit ; br if not, skip default select cmp.b #31,d0 ; sanity check the name bgt.s @exit move.w StandardFileReply.sfScript(A4),D0 ; get script bsr RevealByName @exit rts DebuggerSymbol caseChangeSelection ;--------------------------------------------------------------- ; User moused down in the pop up menu rect. casePopUpPathMenu ; tst.b lAtDesktop(a6) ; don't do pup up when already at top ; bgt.s @done subq #2,sp ; :INTEGER move.l lPopUpControl(a6),-(sp) ; theControl: ControlHandle move.l lMouseWhere(a6),-(sp) ; startPt: Point, use position saved in TheDialogFilter <60> ;<60> subq #4,sp ;<60> move.l sp,-(sp) ;<60> _GetMouse ; startPt: Point moveq #-1,d0 move.l d0,-(sp) ; actionProc: ProcPtr _TrackControl tst.w (sp)+ beq.s @done bsr PopUpNewItem @done rts DebuggerSymbol casePopUpPathMenu ;-------------------------------------------------- ; user wants to open a folder ; caseOpenSelectedFolder pea lTypeSelect(a6) _TypeSelectClear ; clear type select buffer bsr GetSel ; get selection in A0 bmi.s @done ; can do anything without selection btst #ioDirFlg,FileEntry.feFlAttr(a0) ; a directory? beq.s @done ; br if not, do nothing ; don't allow opendir if missing access privileges move.b FileEntry.feFLPriv(a0),d0 ; get access privileges tst.b lDoingGetFile(a6) ; bne.s @getFile ; branch if getfile btst #bNoSearch, d0 ; do open if has search beq.s @doOpen ; br if has search and.b #mNoRead+mNoWrite,d0 ; also open if R and W beq.s @doOpen ; br if R and W @openErr move #sfErrNoPrivileges,D1 ; not enough access privileges bsr ErrorAlert ; explain to user bra.s @done @getFile and.b #mNoSearch+mNoRead,d0 ; getfile folder needs R or S cmp.b #mNoSearch+mNoRead,d0 ; missing both? beq.s @openErr ; no, branch to normal open dir @doOpen move.l FileEntry.feTypeOrDirID(a0),d1 ; get dirID to go into moveq #fsRtParID,d0 cmp.l FileEntry.feParID(a0),d0 ; check if this is really a volume's desktop folder bne.s @storeDir moveq #fsRtDirID,d1 ; if so, switch to open root folder @storeDir move.l d1,lCurDir(a6) move.w FileEntry.feDrive(a0),lDriveNo(a6) bsr NewDirSelectFirstIfGetFile ; enumerate new directory @done rts DebuggerSymbol caseOpenSelectedFolder ;------------------------------------------------------------- ; OpenAliasCommon ; in: current selection is alias ; ; out: lAlias(a6) = target FSSpec ; D0 = result OSErr ; d1 = dialog err to use if error ; OpenAliasCommon ; set up FSSpec of alias file bsr GetSel ; get selection in A0 move.w FileEntry.feVRefNum(a0),lAlias.vRefNum(A6) move.l FileEntry.feParID(a0),lAlias.parID(A6) lea FileEntry.feFile.text(A0), A0 lea lAlias.name(A6), A1 moveq #32, D0 _BlockMove ; call _ResolveAliasFile subq #2,sp ; room for result pea lAlias(a6) ; theSpec: FSSpec st -(sp) ; resolveAliasChains: Boolean pea lTemp(a6) ; VAR targetIsFolder: Boolean pea lTemp(a6) ; VAR wasAliased: Boolean _ResolveAliasFile move.w (sp)+,d0 move.w #sfErrBadAlias,D1 ; assume it was a bad alias tst.w D0 ; did resolve alias fail? bne.s @done ; if so, just return that error movem.l d2-d3,-(sp) ; be safe and save registers move.w lAlias.vRefNum(A6),d2 move.l lAlias.parID(A6),d3 bsr TrashCheck ; returns with Z flag set, if in trash (saves all registers) movem.l (sp)+,d2-d3 ; restore d2,d3 bne.s @done ; if not in trash, return noErr moveq #-1,d0 ; return an error code to force alert move.w #sfErrTrashAlias,D1 ; else suggest alias in trash alert @done rts DebuggerSymbol OpenAliasCommon ;------------------------------------------------------- ; ; user wants to warp via folder/volume alias to new location ; caseOpenAlias pea lTypeSelect(a6) _TypeSelectClear ; clear type select buffer bsr.s OpenAliasCommon cmp.w #userCanceledErr,d0 ; if user cancel mount then just go on beq @done cmp.w #resNotFound,d0 ; resNotFound => file was really not a alias file beq caseOpen ; so goto to normal open case tst.w d0 bne ErrorAlert ; any other error, tell user lea lIOCmd(a6),a0 ; get our param block clr.w ioFDirIndex(a0) ; lookup by name mode move.l lAlias.parID(A6),ioDirID(a0); lookup new folder move.w lAlias.vRefNum(A6),ioVRefnum(a0); alias vrefnum lea lAlias.name(A6),a1 ; get alias name move.l a1,ioFileName(a0) ; use alias name move.w #sfErrBadAlias,D1 ; assume it is a bad alias _GetCatInfo ; get dirID of aliased directory bne ErrorAlert ; br on error, tell user btst #ioDirFlg,ioFlAttrib(a0) ; alias to folder or file? bne.s @doFolder ; this is an alias to a file, ; so we need to fill out the reply record and return @doFile move.w lAlias.vRefNum(A6), d6 ; set these and then rejoin code move.l lAlias.parID(A6), d7 ; that handle's WDrefNums and such nonsense bsr GetReplysFilenametoA0 ; get ptr into reply record move.l a0, a1 ; and copy into result name lea lAlias.name(A6), A0 ; copy from alias name MOVEQ #32, D0 ; size is fileName max _BlockMove ; fill out filename field of reply record ; fill out file type lea lIOCmd(a6),a0 move.l ioFlUsrWds+fdType(A0),d0 ; get file type (this is usually the same as alias type) cmp.l #kApplicationAliasType,d0 ; except for aliases to applications bne.s @setType move.l #'APPL',d0 ; if the type was 'adrp' then change it to 'APPL' @setType move.l d0,StandardFileReply.sfType(A4) ; note: this works for both kinds of reply records tst.b lNewReply(a6) beq.s @joinRest ; fill out more stuff in new reply record move.w ioFlUsrWds+fdFlags(a0),StandardFileReply.sfFlags(A4) ; stuff in finder flags bsr GetFilenameFont ; returns script code in d0 move.w d0,StandardFileReply.sfScript(A4) ; stuff in script code clr.b StandardFileReply.sfIsFolder(A4) ; stuff in is not a folder clr.b StandardFileReply.sfIsVolume(A4) ; stuff in is not a volume @joinRest ; now we jump back into code the concludes sf. It expects: ; d5 = flags ; d6 = vRefNum ; d7 = dirID move.w ioFlUsrWds+fdFlags(a0),d5 swap d5 ; put finder flags in high word move.b ioFlAttrib(a0),d5 ; and file attributes in low word bra StatAndLockCheck @doFolder LEA lIOCmd(a6),a0 ; get our param block MOVE.L ioDirID(A0), D7 ; pass new directory MOVE.W ioVRefnum(A0), D0 ; get vrefnum bsr SetVolumeIcon ; update volume icon/name <55.4, #82679> move.w lIOCmd+ioVRefNum(A6),d0 ; get vRefNum of new disk <57> bsr GoFindDisk ; requires volume to find in d0.w bsr SuckDisk @done rts DebuggerSymbol caseOpenAlias ;------------------------------------------------------------- ; ; user hit command-shift-uparrow or desktop button ; caseGotoDesktop bsr SaveVolumesPreferedFolder ; remember this location caseGotoDesktop2 bsr GotoDesktop ; set up to goto boot volume's desktop folder bsr NewDir ; build and display desktop list SelectBootVolume ; make sure volume icon shows boot disk move.w lBootVol(a6),d0 bsr SetVolumeIcon ; find boot volume in list (volumes are always first, so find first matching vRefNum) moveq #-1,d3 ; start at start @nextcell addq.l #1,d3 move.l d3,d0 swap d0 ; need D0 high word be index, low word be zero bsr GetCellPtr ; D0=cell in ==> A0=dataPtr out bmi.s @done ; minus -> out of cells, should never happen move.w lBootVol(a6),d0 ; usually -1 cmp.w FileEntry.feVRefNum(a0),d0 ; is this the boot volume? bne.s @nextcell ; if not try next moveq #0,d0 ; if we want to select item $1234 in list (zero base) move.w d3,d0 ; swap d0 ; then save off $12340000 (row 1234, column 0 ) move.l d0,lLastSel(a6) ; save off default item to select tst.b lListIsActive(a6) beq.s @done ; if file list inactive, don't select st d2 ; try to center selection in file list bsr SelectAndReveal ; now select that volume @done rts DebuggerSymbol caseGotoDesktop ;------------------------------------------------------------- ; ; user did Command-Open of an alias ; caseGotoAliasTarget bsr OpenAliasCommon cmp.w #userCanceledErr,d0 ; if user cancel mount then just go on beq.s @done tst.w d0 bne ErrorAlert ; br if so, tell user st lDontDrawList(a6) ; turn off drawing until we find target move.l lAlias.parID(A6),D7 ; lookup parent of file moveq #1,d0 cmp.l d0,d7 ; if parentID = 1 then need to goto desktop bne.s @notVolume bsr GotoDesktop bsr NewDir bra.s @selectIt @notVolume move.w lAlias.vRefNum(A6), D0 ; file's vrefnum bsr GoFindDisk ; lookup up the disk bsr NewDir ; and switch filelist to it bne SystemErrAlert @selectIt lea lAlias.name(A6), a0 ; get alias name move.w lSystemScript(a6),d0 ; get alias script ### really should get script of file bsr RevealByName ; and select it in list, will turn drawing back on move.w lAlias.vRefNum(A6), D0 ; get vrefnum <55.4, #82679> bsr SetVolumeIcon ; update volume icon/name <55.4, #82679> @done rts DebuggerSymbol caseGotoAliasTarget ;---------------------------------------------------------------- ; ; new dummy hits that force new active item. ; caseSetActiveItem bsr SetActiveNow rts DebuggerSymbol caseSetActiveItem ;---------------------------------------------------------------- ; ; When the user types a character, we must scroll the list display ; to that position. Call ArrowKey to handle arrow keys. ; --> D0 character typed ; caseKeyDown move.w D0,D6 ; save the char <9Dec85> bsr ArrowKey ; handle arrow key <9Dec85> bne.s @done ; => handled arrow key <9Dec85> ; build an event record lea lEvent(a6),a0 move.w #keyDwnEvt,EventRecord.what(a0) ; what = keyDown move.l lTicks(a6),EventRecord.when(a0) ; when = saved by filter moveq #0,d0 move.w d0,EventRecord.modifiers(a0) ; modifiers = 0 move.b d6,d0 move.l d0,EventRecord.message(a0) ; message = key pressed (keyCode missing) ; call TypeSelectNewKey subq #2,sp ; room for boolean result move.l a0,-(sp) ; event record pea lTypeSelect(a6) ; tsr _TypeSelectNewKey tst.b (sp)+ beq.s @done bsr SelectTyped @done rts DebuggerSymbol caseKeyDown ;------------------------------------------------------------- ; ; GetKeyScript - d0 out: keyboard script ; GetScript - d0 in: GetEnvirons code, out: d0 result ; GetKeyScript ; If setting of script tags is disabled, always return keybd script = smSystemScript <36> subq #4,sp ; space for GetEnvirons return move.w #smGenFlags,-(sp) ; push GetEnvirons verb _GetEnvirons move.l (sp)+,d0 btst.l #smfNameTagEnab,d0 ; can we set script tags? bne.s @getRealKeyScript ; if so, get real keybd script move.l #smSystemScript,d0 rts @getRealKeyScript moveq #smKeyScript,d0 GetScript subq #4,sp ; space for long move.w d0,-(sp) ; ask for current keyboard script _GetEnvirons ; from script manager move.l (sp)+,d0 ; get long result, script in low word rts DebuggerSymbol GetKeyScript ;------------------------------------------------------------- ; CheckDrives ; handle any ejects ; CheckDrives move.w sfSaveDisk,d0 ; was a disk ejected? bpl.s @2 ; yes if negative driveNo in d0 bsr.s cmdEject ; if yes then remove it from list @2 rts DebuggerSymbol CheckDrives ;---------------------------------------------------------------- ; ; When the user hits cmd-shift 1 or 2, we first turn the drive number ; into a refNum so that EjectDisk can compare it to the Boot volume. ; Next we call EjectDisk to eject the specified disk. This destroys a ; bunch of our state, but not LDriveNo. If we ejected the current drive ; call NextDisk to get the next one; otherwise, call SniffDisk to set up the ; state. CmdEject neg.w d0 ; make d0 a real drive number MOVE.L VCBQHdr+QHead,A1 ; Point to the VCB queue <5Dec85> @0 CMP.W VCBDrvNum(A1),D0 ; is it the right drive #? <5Dec85> BEQ.S @1 ; if so, skip out <5Dec85> MOVE.L QLink(A1),A1 ; Get the link to the next vol <5Dec85> MOVE.L A1,D1 ; is it NIL? <5Dec85> BNE.S @0 ; if not, go back. <5Dec85> BRA.S @2 ; if we fall out, just exit <5Dec85> @1 move.w VCBVRefNum(A1),lVolRefNum(A6) ; set up volume to eject bsr EjectDisk ; eject it tst.b lAtDesktop(a6) ; if at desktop, need to rebuild list <2Feb90> bgt caseGotoDesktop ; this time, without the ejected volume <2Feb90> @2 move.w sfSaveDisk,d0 ; get disk we ejected neg.w d0 ; make it a real drive number clr.w sfSaveDisk ; flag eject done cmp.w lDriveNo(A6),d0 ; did we just eject it? beq Eject2 ; => yes, now find a new disk etc... bsr SniffDisk ; else reset all our info <5Dec85> rts DebuggerSymbol CmdEject ;---------------------------------------------------------------- ; ; ; SetActiveNow ; ; d0 = dialog item to make active ; a6 = main stack frame ; a3 = dialog ptr SetActiveNow cmp.w lActiveDITLitem(a6),d0 ; is selected already active? beq.s @done ; if so skip the change ; deactive current move.l a3,-(sp) ; dialog ptr move.w lActiveDITLitem(a6),-(sp) ; which item clr.w -(sp) ; deactivate move.w d0,lActiveDITLitem(a6) ; remember the new active one bsr CallActivate ; active the next move.l a3,-(sp) ; dialog ptr move.w lActiveDITLitem(a6),-(sp) ; which item st -(sp) ; activate bsr CallActivate @done rts DebuggerSymbol SetActiveNow ;----------------------------------------------------------------- ; ; Setup the filelist to match the new disk ; SuckDisk bsr DumpList ; kill the current file list bsr.s SuckCommon ; rebuild the file list bne SystemErrAlert ; error? br if so and exit rts DebuggerSymbol SuckDisk ; ; just like NewDisk, but in PutFile warns if locked disk SuckCommon tst.b lDoingGetFile(a6) ; write lock is not a concern bne.s @okDisk ; for getfile bsr SniffDisk ; check out disk... bne.s @exit tst.b d7 ; see if locked bpl.s @okDisk move #sfErrDiskLocked,D1 ; warn user that the disk is locked bsr ErrorAlert move.w #sfHookNullEvent,lHit(a6) ; clr button hit, so dialog does not return @okDisk bsr NewDisk ; set up new disk @exit rts DebuggerSymbol SuckCommon ;------------------------------------------------------------- ; GetReplysFilenametoA0 lea SFReply.fName(a4),a0 ; assume old name tst.b lNewReply(a6) ; new call ? beq.s @exit ; br if not, use old name lea StandardFileReply.sfFile+FSSpec.name(a4),a0 ; use new name @exit rts DebuggerSymbol GetReplysFilenametoA0 ;---------------------------------------------------------------- ; ; GetNextItemHit ; GetNextItemHit sf lDontDrawList(a6) ; this should be false, but error handling could have messed up PEA TheDialogFilter ; filter proc PEA lHit(A6) ; pass the item var _ModalDialog ; be modal cmp.l #sfMainDialogRefCon,wRefCon(a3) ; only pre-process the hits in the main dialog bne.s @doReturn_1 ; Remap the returned item so that the hook gets a different view of reality. ; Double clicks become presses of the Open/Save button, and Open/Save of a ; folder is returned as a separate item. moveq #sfItemDesktopButton,d0 bsr VirtualToRealItem cmp.w lHit(A6),d0 bne.s @notDrive tst.b lVolumeSelect(a6) ; in compatibility mode, we don't map to hookGotoDesktop bne.s @doReturn_1 move.w #sfHookGotoDesktop,lHit(A6) ; coerce old Drive button into Desktop button @doReturn_1 bra @doReturn ; and return back our special command @notDrive moveq #sfItemFileListUser,d0 bsr VirtualToRealItem cmp.w lHit(A6),d0 ; was hit in the File list? bne.s @chkOpen ; if so do mousedown in list moveq #-1,d1 ; erase what was selected last, so it won't flash move.l d1,lLastSel(a6) bsr SetActiveNow ; make the list item active now subq #2, sp ; boolean result for ListClick clr.l -(sp) ; space for a point move.l sp,-(sp) ; point at it _GetMouse ; where art thou fairest mouse? move lMeta(a6),-(sp) ; event modifiers saved from DlgFltr move.l lFileListHandle(a6),-(sp) _LClick bsr FillReplyRecord ; _LClick could have changed selection, so update reply record <42> ngk 27Sept90 move.b (sp)+,d2 ; get double click result bsr GetSel ; get selection into A0 bmi.s @nullItem ; => no selection tst.b d2 bne.s @doubleClk ; => no dublclik, pass file list item through to user tst.b lAtDesktop(a6) ; if we are at desktop ble.s @1 move.w FileEntry.feVRefNum(a0),d0 ; then update volume icon bsr SetVolumeIcon @1 bra.s @doReturn_1 @doubleClk tst.b FileEntry.feFile.dimmed(a0) ; is it dimmed? bne.s @nullItem ; canÕt double click on a dimmed selection moveq #sfItemOpenButton,d0 ; coerce item into open button bsr VirtualToRealItem move.w d0,lHit(A6) ; coerce original item into open button bra.s @gotOpen ; => coerce to open directory, if necessary <16Dec85> ; if open or save (or double click) on a folder, don't return button item @chkOpen moveq #sfItemOpenButton,d0 ; coerce item into open button bsr VirtualToRealItem cmp.w lHit(a6),d0 bne.s @chkNull tst.b lDoingGetFile(a6) ; is this getFile, bne.s @gotOpen ; if so go on with open tst.b lOpenState(a6) ; does button say save bne.s @doReturn ; if so, don't change it to hookOpenFolder @gotOpen bsr GetSel ; get selection into A0 bmi.s @doReturn ; => no selection, exit btst #isAliasBit,FileEntry.feFndrFlags(a0) ; is it an alias? beq.s @openNonAlias ; br if so @openAlias move.w #sfHookOpenAlias, lHit(a6) ; assume opening alias normally btst #optionKey,lMeta(A6) ; was option key pressed? beq.s @doReturn ; br if so, return open alias move.w #sfHookGotoAliasTarget,lHit(A6) ; return open of alias's parent bra.s @doReturn @nullItem move.w #sfHookNullEvent,lHit(a6) bra.s @doReturn @openNonAlias btst #ioDirFlg,FileEntry.feFlAttr(a0) ; a directory? beq.s @doReturn ; br if not, return regular open move.w #sfHookOpenFolder,lHit(A6) ; coerce item to open directory bra.s @doReturn @chkNull tst.b lNewReply(a6) ; some apps (UltraPaint 1.0) eat null events <55.6, #82198> beq.s @doCheck ; need to check disk inserts for them too. <55.6, #82198> ; on new calls, if disk was inserted then map null event to a change selection ; so don't check for disk insert unless we have a null event we can map cmp.w #sfHookNullEvent,lHit(a6) bne.s @doReturn ; during null events @doCheck bsr.s CheckForDiskInsert ; check for disk inserts @doReturn rts DebuggerSymbol GetNextItemHit ;---------------------------------------------------------------- ; ; CheckForDiskInsert ; ; Checks for disk insert event (ModalDialog masks these out) ; If mount failed, tries format dialog ; If mounted OK, then switches display to that disk ; CheckForDiskInsert SUBQ #2,SP ; get the disk inserted event MOVE #$0080,-(SP) ; both inserted and app1evts PEA lEvent(A6) _GetNextEvent move.l a3,-(sp) ; GetNextEvent may change port so reset it _SetPort TST.B (SP)+ ; did we get the disk inserted BEQ.S @done ; See if the mount suceeded TST.W lEvent.message(A6) ; did it succeed? BEQ.S @showThisDisk ; br if not, try formatting it ; if not then do DIBadMount ST lDidPack2(A6) ; record that pack2's been here BSR SetCursorToArrow ; cursor to arrow SUBQ #2,SP ; room for result MOVE.L lWhere(A6),-(SP) ; pass where to put it MOVE.L lEvent.message(A6),-(SP) ; pass the message _DIBadMount TST (SP)+ ; 0 - success set cc's BNE.S @done @showThisDisk ; save off folder at in current volume move.w lVolRefNum(a6),d0 bsr GetVolumeInfoPtr ; return info for the volume by a0 move.l lCurDir(a6),PerVolumeInfo.lastDir(a0) ; get info for new disk move.w lEvent.message+2(A6),d0 bsr.s GetVinfo ; if we have a preferred folder then goto it move.w lIOCmd+ioVRefNum(A6),d0 ; get vRefNum of new disk <55.4, #82679> bsr SetVolumeIcon ; update displayed volume icon and name <55.4, #82679> move.w lIOCmd+ioVRefNum(A6),d0 ; <55.4, #82679> bsr GetVolumeInfoPtr move.l PerVolumeInfo.lastDir(a0),d1 bne.s @gotDir moveq #fsRtDirID,d1 ; if no preference, defaults to root @gotDir tst.b lNewReply(a6) beq.s @oldWay ; the new way is to map null event into a sfHookChangeSelection to the root of the new disk ; this gives apps a chance to stop the disk change (nice for volume select) @newWay move.w lIOCmd+ioVRefNum(a6),StandardFileReply.sfFile+FSSpec.vRefNum(a4) ; set vRefnum of reply move.l d1,StandardFileReply.sfFile+FSSpec.parID(a4) ; set parID of reply clr.b StandardFileReply.sfFile+FSSpec.name(a4) ; select nothing move.w #sfHookChangeSelection,lHit(a6) bra.s @done @oldWay move.w lEvent.message+2(A6),lDriveNo(A6) ; set up driveNum for SuckDisk move.l d1,lCurDir(a6) ; set up dir for SuckDisk bsr SuckDisk ; switch to it @done rts DebuggerSymbol CheckForDiskInsert ;--------------------------------------------------------------------- ; ; A Common get volume info call. ; ; in d0 = driveNo ; GetVinfo lea lIOCmd(A6),A0 ; do some I/O clr.w ioVolIndex(a0) move.w d0,ioDrvNum(A0) ; lookup by drive number clr.l ioVNPtr(A0) _HGetVInfo ; get info about this drive rts DebuggerSymbol GetVinfo ;--------------------------------------------------------------------- ; ; The common eject code. First check to see if the disk to be removed ; is Boot disk. If so, we'd better load up the bare necessities... ; SmartEjectDisk TST.B lAtDesktop(A6) ; at the desktop? BLE.S EjectDisk ; br if not, use current disk bsr GetSel ; get selection in A0 move.w FileEntry.feVRefNum(A0), D7 ; eject selected disk bra.s EjectCommon EjectDisk MOVE.W lVolRefNum(A6), D7 ; eject current disk EjectCommon TST.B lDidEject(A6) ; was eject already called? BNE.S @doEject ; yes, just eject the disk CMP.W lBootVol(A6),D7 ; is this the startup disk? BNE.S @doEject ; br if not, skip preloading ST lDidEject(A6) ; record eject for freeAlert ST lDidPack2(A6) ; record that pack2's been here _DILoad ; Tell the formatter to nest down @doEject CLR.B lVolName+StyledString.text(A6) ; no volume name LEA lIOCmd(A6),A0 ; do some I/O CLR.L ioVNPtr(A0) ; and set it up MOVE D7,ioVRefNum(A0) ; eject the only drive _Eject RTS ; return with error ; The following is a bunch of incestuous code for munging about in the VCB queue. ;---------------------------------------------- GoFindDisk NEG.W D0 ; make it a drive num MOVE.W D0,lSaveDisk(A6) ; pass new disk to FindDisk BSR.S FindD7Disk ; setup lDriveNo amd lCurDir RTS DebuggerSymbol GoFindDisk ; FindDisk takes the drive number in lSaveDisk(A6) and dirID in CurDirStore and ; sets up D1 & lDriveNo(A6) to be the drive number and D7 & lCurDir(a6) do ; be the dirID, after some sanity checks. FindDisk MOVE.L CurDirStore,D7 ; get the DIR ID FindD7Disk MOVE.W lSaveDisk(A6),D2 ; get negated refnum BMI findError ; skip if uninitialized NEG.W D2 ; flip it to get volrefnum (HACK) ; see if the specified volume is both in the drive queue and on-line MOVE.L vcbQHdr+QHead,A1 ; first VCB start over @fdLoop CMP.W vcbVRefNum(A1),D2 ; get this refnum BEQ.S @found ; => found the default refnum <30Jan86> MOVE.L QLink(A1),A1 ; point to next VCB MOVE.L A1,D0 ; are we done?? BNE.S @fdLoop ; if not try again BRA.W findError ; => didn't find the refnum <30Jan86> @found MOVE.W vcbDRefNum(A1),D1 ; is the volume on line? <30Jan86> BPL.W findError ; => no, go find one <30Jan86> lea lIOCmd(a6),a0 ; point at io block move #-1,ioFDirIndex(a0) ; special getinfo clr.l ioFileName(a0) ; no names move d2,ioVRefNum(a0) ; look at given volume move.l d7,ioDirID(a0) ; at the given folder _GetCatInfo beq.s @dirOK ; br if dir ok, exit moveq #fsRtDirID,d7 ; use root if folder doesn't exist @dirOK moveq #0,d3 ; flag that we are going forward in the list bra.s tryDrive ; => try this drive ; This routine cycles through the VCB queue and finds the "next" disk that isn't ; the current refnum. It makes that local set to the new one. ; Also, this is two routines in one. We use D3 as a flag and do either ; ŅnextÓ disk, or ŅpreviousÓ disk. PrevDisk moveq #-1,d3 ; flag that we are going backward bra.s JoinNextDisk NextDisk moveq #0,d3 ; flag that we are going forward JoinNextDisk ; first skip to the current vRefNum we know of; it might not exist moveq #fsRtDirID,d7 ; to the root MOVE.L vcbQHdr+QHead,A1 ; first VCB start over MOVE.W lVolRefNum(A6),D2 ; get current refnum BEQ.W findError @cdLoop CMP.W vcbVRefNum(A1),D2 ; get this refnum BEQ.S inSearch ; start with next one MOVE.L QLink(A1),D0 BEQ.S findError MOVE.L D0,A1 ; point to next VCB BRA.S @cdLoop ; will this ever end?? ; now search for a non zero drive tryDrive ; <2> FM MOVE.W vcbDrvNum(A1),D1 ; get drive # BNE.S @found MOVE.W vcbDRefNum(A1),D1 ; see if hiding.. BPL.S inSearch NEG.W D1 ; drive really is there @found BSR VolumeIsInvisible ; If the drive is invisible, <2> <7> TST.W D0 ; donÕt show it in the list. <2> <7> BNE.S inSearch ; <2> <7> tst.w d3 ; are we looking for the previous? bz.s foundDrive ; no, go report that we found the next move.w d1,d3 ; keep track of the last one we found inSearch MOVE.L QLink(A1),D0 ; point to next VCB BNE.S @ndLoop ; if at end, start over MOVE.L vcbQHdr+QHead,D0 ; first VCB start over @ndLoop MOVE.L D0,A1 ; get vcb ptr CMP.W vcbVRefNum(A1),D2 ; see if repeated BNE.S tryDrive tst.w d3 ; we looped once all the way around bgt.s foundPrevious ; if +, we were looking for previous and found something move.w d2,d1 ; stay with the same disk as before bra.s foundDrive foundPrevious move.w d3,d1 ; the last drive we stashed is it! bra.s foundDrive findError MOVE.L lDeskDir(A6),D7 ; default is desktop dir. MOVE.W lBootDrive(A6),D1 ; on startup volume foundDrive MOVE.W D1,lDriveNo(A6) ; save for new disk MOVE.L D7,lCurDir(a6) RTS DebuggerSymbol FindDisk ;------------------------------------------------------------------ <2> FM ; <2> FM ; This routine checks if a volume is invisible because <2> FM ; we don't want to show invisible volumes. <2> FM ; (20/20 is a little strange sometimes) <2> FM ; <2> FM ; in: A1.w = VCB ptr <2> FM ; out: d0.w = true - volume is invisible; false - visible <2> FM ; trashes: a0,d0 <2> FM ; <2> FM ; If this disk is invisible then we want to skip it, because <2> FM ; we don't display invisible disks. A disk is invisible if the <2> FM ; invisible bit is set on its root folder. <2> FM ; ; We special case High Sierra and ISO CD Roms to always be visible because they ; accidentally have that bit set. We also special case remote volumes ; because they could be CD roms mounted remotely. At this point it ; seems like we should be special casing 20/20 hidden volumes because ; it would be easierÉ oh well. VolumeIsInvisible movem.l a0-a1/d1,-(sp) ; Is this a remote volume? (We always show remote volumesÉ) move.w vcbDRefNum(a1),d0 ; get driver RefNum addq #1,d0 neg.w d0 ; massage index lsl.w #2,d0 move.l uTableBase,a0 move.l (a0,d0.w),a0 ; index into table move.l (a0),a0 ; dereference handle btst #6,dCtlFlags+1(a0) ; see if it is in RAM move.l dCtlDriver(a0),a0 ; get driver start pointer beq.s @havePtr ; check result of tst.w move.l (a0),a0 ; RAM drivers need an extra dereference @havePtr lea drvrName+2(a0),a0 ; skip length byte and initial period cmp.l #'AFPT',(a0) ; .AFPTranslator means fileserver beq.s @skipInvisibleCheck ; Don't ever hide remote volumesÉ ; else are we looking at a local cd that we need to special case? tst.b SFFrame.IAlwaysShowLocalCD(A6) ; do we special case CD's? <2> FM beq.s @noSpecialCaseCD ; noÉ go check for invis. <2> FM cmp.w #$4147,vcbFSID(A1) ; Is this a ISO volume? <2> FM beq.s @skipInvisibleCheck ; yesÉ skip check <2> FM cmp.w #$4242,vcbFSID(A1) ; well, is it High Sierra? <2> FM beq.s @skipInvisibleCheck ; yesÉ skip check <2> FM @noSpecialCaseCD ; <2> FM lea lIOCmd(A6),A0 ; do some I/O move.w vcbVRefNum(A1),d0 ; get volume refnum É <2> FM move.w d0,ioVRefNum(a0) ; <2> FM move #-1,ioFDirIndex(a0) ; special case entry count <2> FM move.l #fsRtDirID,ioDirID(a0) ; Get the root info <2> FM clr.l ioFileName(a0) ; no name of directory. <2> FM _GetCatInfo ; get the info <2> FM bne.s @skipInvisibleCheck ; if err then I'm confusedÉ <2> FM btst #isInvisible,ioFlUsrWds+fdFlags(a0) ;is this volume invisible? <3> FM beq.s @skipInvisibleCheck ; yes so skip <2> FM moveq #1,d0 ; yes it was invisible! <2> FM bra.s @exit ; <2> FM @skipInvisibleCheck ; <2> FM moveq #0,d0 ; <2> FM @exit movem.l (sp)+,a0-a1/d1 rts ; <2> FM ;------------------------------------------------------------------ ; ; This routine converts a vRefNum to its Drive Number ; ; in: d0.w = vRefNum ; out: d1.w = Drive Number (or 0, if no such vRefNum) ; trashes: a0 ; VRefNumToDriveNo ; <56, #BS-036> move.l vcbQHdr+QHead,d1 ; first VCB <56, #BS-036> @vcbLoop beq.s @done ; exit at end of list <56, #BS-036> move.l d1,a0 ; <56, #BS-036> cmp.w vcbVRefNum(a0),d0 ; found volume? <56, #BS-036> beq.s @getDrive ; if so, get drive no. <56, #BS-036> move.l qLink(a0),d1 ; point to next VCB <56, #BS-036> bra.s @vcbLoop ; <56, #BS-036> @getDrive move.w vcbDrvNum(a0),d1 ; get drive # <56, #BS-036> @done rts ; <56, #BS-036> DebuggerSymbol VRefNumToDriveNo ;------------------------------------------------------------------ ; ; This routine counts the number of disks in place and returns the number in D3.W ; CountDIPs MOVEQ #0,D3 ; zero drive counter MOVE.L vcbQHdr+QHead,D0 ; first VCB @vcbLoop BEQ.S @done ; exit at finish MOVE.L D0,A1 MOVE vcbDrvNum(A1),D0 ; get drive # BNE.S @1 ; if <> then count it MOVE vcbDRefNum(A1),D1 ; see if hiding.. BPL.S @0 ; not hiding, ignore it @1 ADDQ #1,D3 ; increment # drives w/DIP @0 MOVE.L QLink(A1),D0 ; point to next VCB BRA.S @vcbLoop @done RTS DebuggerSymbol CountDIPs ;------------------------------------------------------------------ ; ; This routine cycles through the VCB queue and unmounts any disks ; who are clean and offline ; CleanVols LEA lIOCmd(A6),A0 ; get iocmd ready CLR.L ioVNPtr(A0) ; not by name MOVE.L vcbQHdr+QHead,A1 ; first VCB start over @0 TST vcbDrvNum(A1) ; is it offline BNE.S @1 ; if not go to next TST vcbDRefNum(A1) ; see if hiding.. BMI.S @1 ; it's really online TST.B qType+1(A1) ; files ever opened? BMI.S @1 MOVE.W vcbVRefNum(A1),ioVRefNum(A0) ; in case we do something _UnmountVol @1 MOVE.L QLink(A1),A1 ; point to next VCB MOVE.L A1,D0 ; any more? BNE.S @0 ; if at end, start over RTS DebuggerSymbol CleanVols ;-------------------------------------------------------------------- ; ; This gets called when a new disk is inserted. RelistDisk called when disk ; names should be recalc'ed. ; NewDisk tst.w lDriveNo(A6) ; is there a disk??? bne.s NewDirSelectFirst ; => yes bsr EraseFileList ; else erase file list bsr InvalVol ; inval names for redraw bsr InvalPopUp ; inval names for redraw move.l lFileListHandle(a6),-(sp) ; get the list handle _LSetHilite ; and unhilite the scroller moveq #0,d0 rts DebuggerSymbol NewDisk NewDirSelectFirstIfListActive tst.b lListIsActive(a6) ; if list active bne.s NewDirSelectFirst ; then select first ;bra.s NewDir ; else select nothing NewDir bsr DumpList ; clear displayed list bsr.s SniffDisk ; get ready for next dir/disk beq.s ReListDisk ; no error rts DebuggerSymbol NewDir NewDirSelectFirstIfGetFile tst.b lDoingGetFile(a6) ; switch directory, but only select first beq.s NewDir ; if doing getfile NewDirSelectFirst bsr.s NewDir bne.s @1 move.w #chDownArrow,D0 ; get first non-dimmed by simulating a down arrow bsr ArrowKey moveq #0,d0 ; clear condition codes @1 rts DebuggerSymbol NewDirSelectFirst ; recalculate the position of the dirRect in case we get a mouseDown in the dirRect before ; the update to redraw (and hence recalculate) the new dirRect has come through. ReListDisk BSR ReBuildMenu BSR DrawPopUpMenu ; draw pop up showing new folder we are in BSR AddFileListItems ; go set up the file list BSR EraseFileList ; erase current list BSR DrawFileList ; then draw new BSR SetCursorToArrow ; arrow again moveq #0,d0 rts DebuggerSymbol ReListDisk ;------------------------------------------------------------------ ; ; This looks at the disk from lDriveNo(A6) and gets its refnum into ; lVolRefNum(A6) exits with A0 pointing to VolInfo ; SniffDisk MOVE lDriveNo(A6), D0 ; is there a disk? BEQ @exit ; br if not, exit ; Get lots of interesting info about this drive CLR.B lAtDesktop(A6) ; assume we're not at the desktop LEA lIOCmd(A6),A0 ; do some I/O CLR.W ioVolIndex(a0) MOVE lDriveNo(A6),ioDrvNum(A0) ; lookup by drive number LEA lVolName+StyledString.text(A6),A1 ; point to volume name MOVE.L A1,ioVNPtr(A0) ; and set it up _HGetVInfo ; get info about this drive BNE @exit move.w ioVSigWord(a0),lSigWord(a6) ; save sigword move.w ioVAtrb(a0),d7 ; save the lock state tst.b d7 ; save lock state in lLocked(a6) <27-Nov-85> smi lLocked(a6) ; true = locked <27-Nov-85> move.w ioVRefNum(a0),d0 ; pass vRefNum bsr getVolIcon ; set up the icon move.w d0,lVolIcon(a6) ; save icon away for this disk LEA lIOCmd(A6),A0 ; do some I/O MOVE.W ioVRefNum(A0),D0 ; get volume refnum MOVE.W D0,lVolRefNum(A6) ; save default volume refnum MOVE.W D0,sfSaveDisk ; fix it up NEG.W sfSaveDisk ; really fix it up MOVE.W lDriveNo(A6),D1 ; get target drive # BSR NotEjectable ; not ejectable? MOVE.B D0,lNoEjects(A6) ; record if it can't be ejected ; get volume paramters LEA lIOCmd(A6),A0 ; do some I/O CLR.L ioNamePtr(A0) ; don't care about name MOVE.W lVolRefNum(A6),ioVRefNum(A0) ; lookup by vRefNum LEA lVolParms(A6),A1 MOVE.L A1,ioBuffer(A0) ; volParms to be filled MOVEQ #VolumeParms.size,D0 MOVE.L D0,ioReqCount(A0) ; size of volParms _GetVolParms ; get parameters about this volume BNE @exit ; get dirIDs of special folders for this volume MOVE.W lVolRefNum(A6), D0 ; look on current disk MOVE.L #kWhereToEmptyTrashFolderType,D1 ; get special trash folder BSR FindFolder MOVE.L D0,lTrashDir(A6) ; save away trash dirID MOVE.W lVolRefNum(A6), D0 ; look on current disk MOVE.L #kDesktopFolderType,D1 ; get special desktop folder BSR FindFolder MOVE.L D0,lDeskDir(A6) ; save away current desktop dirID ; Check to see if the new dir requested is actually trash or desktop folder LEA lDirName.text(A6), A1 ; get handy directory name MOVE.L lCurDir(A6),D0 ; get new directory CMP.L lTrashDir(A6),D0 ; dirID same as trash? BNE.S @checkDesk ; br if not @gotoRoot moveq #fsRtDirID,d0 move.l d0,lCurDir(a6) move.l d0,CurDirStore bra SniffDisk ; try again, "from the top" @checkDesk CMP.L lDeskDir(A6), D0 ; dirID same as desktop? BNE.S @checkDir ; br if not MOVE.B #1,lAtDesktop(A6) ; mark that we're at desktop MOVEQ #sfDesktopName,D1 ; name of desktop BSR GetLocalString ; set current dirName to desktop MOVE.W lSystemFont(A6),lDirName.font(A6) ; desktop/trash are always in system font MOVE.L lCurDir(A6), CurDirStore ; store dirID away in lomem ST lNoEjects(A6) ; can't eject desktop CLR lVnFiles(A6) ; don't know how many files there are CLR lPriv(A6) ; all privileges ;<55.5><55.7, #82680> don't update volume icon here because, this is called by Initialize before ;<55.5><55.7, #82680> dialog (port) is created and desktop dirIDs are computed. ;<55.5><55.7, #82680> move.w lVolRefNum(A6),d0 ; set up volume icon to current disk ;<55.5><55.7, #82680> bsr SetVolumeIcon ; bra.s @okExit ; Get info about a particular folder on this disk (and fall back to root on error) @checkDir move.l lCurDir(a6), d1 ; get directory @checkD1Dir lea lIOCmd(A6),A0 ; do some I/O move #-1,ioFDirIndex(a0) ; special case entry count move.l d1,ioDirID(a0) lea lDirName.text(A6),a1 move.l a1,ioFileName(a0) ; get name of directory. _GetCatInfo beq.s @cont @tryRoot moveq #fsRtDirID,d1 cmp.l lCurDir(a6), d1 ; at the root? beq.s @exit bra.s @checkD1Dir ; br if not, try root @cont move ioDrNmFls(a0),lVnFiles(a6) ; save # files clr.b lPriv(a6) ; assume all privleges move.l lVolParms.vMAttrib(a6),D0 ; get volumes parms btst #bAccessCntl,D0 ; does it support access control? beq.s @havePrivs ; if not, don't get permissions byte move.b ioACUser(a0),lPriv(a6) ; stuff in the permissions @havePrivs tst.b lLocked(a6) ; is disk also locked? beq.s @setDir bset #bNoWrite,lPriv(A6) ; if locked, flip on noWrite perm bit @setDir move.l d1,CurDirStore move.l d1,lCurDir(a6) ; see if folder is buried in the trash @trashCheck move.l ioDrParID(a0),d1 cmp.l lTrashDir(A6),d1 ; is parent folder the trash folder? beq @gotoRoot ; if so, goto to root level move #-1,ioFDirIndex(a0) ; look up by dirID only move.l d1,ioDrDirID(a0) clr.l ioFileName(a0) _GetCatInfo beq.s @trashCheck @okExit moveq #0, d0 ; exit with no error @exit rts DebuggerSymbol SniffDisk ;---------------------------------------------- ; in: d3.L = dirID ; d2.w = vRefNum ; ; out: Z flag set if in trash TrashCheck movem.l d0-d3/a0,-(sp) move.w d2,d0 move.l #kWhereToEmptyTrashFolderType, D1; get special trash folder bsr.s FindFolder bne.s @doCheck ; if no trash folder, then can't be in trash moveq #1,d0 bra.s @done ; return with Z flag clear @doCheck move.l d0,d1 ; save dirID of trash in d1 lea lIOCmd(A6),a0 ; do some I/O @checkNext move.l d3,ioDrDirID(a0) ; start at given folder cmp.l d3,d1 ; is it the trash? beq.s @done ; if so, we are in the trash move #-1,ioFDirIndex(a0) ; look up by dirID only clr.l ioFileName(a0) _GetCatInfo move.l ioDrParID(a0),d3 ; move up to parent folder tst.w d0 beq.s @checkNext @done movem.l (sp)+,d0-d3/a0 rts DebuggerSymbol TrashCheck ;-------------------------------------------------------- ; FindFolder - find the dirid of a special folder ; d0 (in) vrefnum of disk ; d1 (in) which special folder ; d0 (out) dirid of folder, or 0 if there was an error FindFolder SUBQ #2, SP ; error result MOVE D0, -(SP) ; look on this disk MOVE.L D1, -(SP) ; look for this folder ST -(SP) ; create folder if it doesn't exist PEA lKind(A6) ; unused destination vrefnum CLR.L lItem(A6) ; assume error getting dirID PEA lItem(A6) ; dirID result _FindFolder ADDQ #2, SP ; ignore error MOVE.L lItem(A6), D0 ; return dirID (0 if an error occurred) RTS DebuggerSymbol FindFolder GotoDesktop MOVE.L #kDesktopFolderType, D1; get special desktop folder BRA.S GotoCommon GotoTrash MOVE.L #kWhereToEmptyTrashFolderType, D1; get special trash folder GotoCommon MOVE lBootVol(A6), D0 ; look on startup disk BSR.S FindFolder MOVE.L D0, lCurDir(A6) ; change to this directory MOVE lBootDrive(A6), lDriveNo(A6) ; change to startup disk RTS DebuggerSymbol GotoDesktop ;-------------------------------------------------------------------- ; ; d1 (in) drive number ; d0 (out) ST if not ejectable ; ; trash a0 NotEjectable move.l a0,-(sp) MOVE.L DrvQHdr+QHead, A0 ; Point to the drive queue @nextDrive CMP.W DQDrive(A0), D1 ; is it the right drive #? BEQ.S @foundDrive ; if so, skip out MOVE.L QLink(A0), A0 ; Get the link to the next vol MOVE.L A0, D0 ; is it NIL? BNE.S @nextDrive ; br if not, try next drive BRA.S @exit @foundDrive CMP.B #8,-3(A0) ; ejectable value?? I.M. IV-181 SGE D0 ; ST if not ejectable @exit move.l (sp)+,a0 RTS DebuggerSymbol NotEjectable ;-------------------------------------------------------------------- ; SetCursorToArrow MOVE.L (A5),A0 ; hack entry point for set cursor PEA arrow(A0) _SetCursor RTS DebuggerSymbol SetCursorToArrow ;-------------------------------------------------------------------- ; ; Called TheDialogFilter(dialog,event,VAR item): BOOLEAN ; This is the filter proc for Modal dialog. It first does the normal ; force to adefitem. Then it tries to return a bogus button ; for null events(100). And...for key events, it returns yet another bogus ; button (1000+char) for key scrolling. ; Finally it calls the caller's filter proc before returning. FilterFrame RECORD {A4Link},DECR result DS.W 1 ; returned BOOLEAN paramSize EQU *-8 ; prameters to remove on return theDialog DS.L 1 ; DialogPtr theEvent DS.L 1 ; VAR EventRecord itemHit DS.L 1 ; VAR INTEGER ReturnAddr DS.L 1 A4Link DS.L 1 ; locals go here localWhere DS Point whichWindow DS.L 1 mouseState DS.W 1 calledFilter DS.W 1 ; whether apps dialog filter has been called for this event <66, #f1-ngk-002> ALIGN frameSize EQU * ; size of link ENDR TheDialogFilter link A4,#FilterFrame.frameSize movem.l D3/D4/A2/A3/A6,-(SP) ; save work regs clr.w FilterFrame.result(A4) ; assume failure return clr.w FilterFrame.calledFilter(A4) ; initialize <66, #f1-ngk-002> move.l FilterFrame.theEvent(A4),A2 ; A2 = pointer to the event move.l FilterFrame.theDialog(A4),A3 ; A3 = Dialog pointer ; ### This should do the same thing as the ROM code ClaimEvent. ; For update and Activate events, A3 should come from the event ; record, instead of the parameters. lea -lTheDialogRec(A3),A6 ; assume main dialog cmp.l #sfMainDialogRefCon,wRefCon(a3) ; back solve for A6 beq.s @haveA6 lea -lSubDialogRec(A3),A6 ; in sub dialog, so A6 is different @haveA6 ; call apps dialog filter tst.b lNewReply(a6) beq.s @callStdFilter ; in BigBang we call app's DlgFilter first, not last bsr CallUserDlgFilter bne @done ; if returned true, then no need to do my filter @callStdFilter ; call standard dialog filter bsr CallStdDlgFilter or.b d0,FilterFrame.result(A4) ; return with z-flag set if someone handled event bne @done ; if returned true, then no need to do my filter ; case off of event.what field move.w EventRecord.what(A2),d0 beq @ReturnNullEvent ; handle null event for all dialogs cmp.w #activateEvt,d0 beq @filterActivateEvent ; handle activate event for all dialogs ; don't do anymore filtering on subdialogs cmp.l #sfMainDialogRefCon,wRefCon(a3) beq.s @mainCase cmp.l #sfNewFolderDialogRefCon,wRefCon(a3) bne.s @NoFiltering_2 ; filter key-downs and auto-keys for new folder dialog @newFolderCase subq.w #3,d0 beq @filterAutoKey ; key down subq.w #2,d0 beq @filterAutoKey ; auto-key, both needed to limit TE to 31 chars subq.w #1,d0 beq @filterUpdateEvent bra.s @NoFiltering_2 ; filter lots of stuff for main dialog @mainCase subq #1,d0 beq.s @filterMouseDown subq.w #2,d0 beq @filterKeyDown subq.w #2,d0 beq @filterAutoKey subq.w #1,d0 beq @filterUpdateEvent @NoFiltering_2 bra @NoFilter_1 ; ; filtering of mouse down events ; @filterMouseDown subq.w #2,sp ; room for integer return value move.l EventRecord.where(a2),-(sp) pea FilterFrame.whichWindow(a4) ; space for windowptr _FindWindow move.w (sp)+,d0 ; result code cmp.l FilterFrame.whichWindow(a4),a3 ; in my window? bne.s @NoFiltering_2 cmp.w #inContent,d0 ; inside ? bne.s @NoFiltering_2 move.l EventRecord.where(a2),FilterFrame.localWhere(a4) pea FilterFrame.localWhere(a4) _GlobalToLocal ; convert to local coordinates ; see if moused in my dummy popUpMenu item move.l FilterFrame.localWhere(a4),lMouseWhere(a6) ; save off last mouse down position <60> subq.w #2,sp ; room for Boolean return value move.l FilterFrame.localWhere(a4),-(sp) ; ### seems like I should be able to use MaxRect and CDEF should do nothing if outside current size move.l lPopUpControl(a6),a0 ; get popup control move.l (a0),a0 move.l contrlData(a0),a0 ; get control data handle move.l (a0),a0 pea CDEFpopUpData.myCtlRect(a0) ; current size rect is 6 bytes into control data _PtInRect moveq #sfHookFolderPopUp,d0 tst.b (sp)+ ; in pop up menu ? bne @ChangeHitTo ; yes => map to hookFolderPopUp pseduo item ; see if it is a hit in an activatable item @checkActive subq.w #2,sp ; room for integer return value move.l FilterFrame.theDialog(a4),-(sp) move.l FilterFrame.localWhere(a4),-(sp) _FindDItem move.w (sp)+,d1 bmi.s @checkVersion ; if returns -1 then no item found addq #1,d1 ; FindDItem returns item number minus one move.l lActiveList(a6),a0 move.w (a0),d0 ; list length in D0 cmp.w #1,d0 ; is there only one activatable item? beq.s @NoFilter_1 ; if so, do nothing cmp.w lActiveDITLitem(a6),d1 ; is item already active? beq.s @NoFilter_1 ; if so, do nothing ; need to find if item hit is an activatable item @findNext2 addq #2,a0 ; walk list subq.w #1,d0 bmi.s @NoFilter_1 ; item hit not in list cmp.w (a0),d1 bne.s @findNext2 ; activate the moused-on item move.w d1,d0 ; item to enable in d0 bsr SetActiveNow ; a3 already set up @NoFilter_1 bra @NoFiltering ; go on as if no filtering happened @versionData dc.l $03444549 @checkVersion tst.b lDoingGetfile(a6) bne.s @NoFilter_1 tst.l FilterFrame.localWhere(a4) bne.s @NoFilter_1 btst #cmdKey,EventRecord.modifiers(a2) beq.s @NoFilter_1 move.l a4,-(sp) ; get current text and selection range moveq #sfItemFileNameTextEdit,d0 bsr VIrtualToRealItem move.w d0,d3 ; d3 is now real item number bsr GetIt move.l lItem(a6),a4 ; a4 is now item handle move.l teHandle(a3),a0 move.l (a0),a0 move.l teSelStart(a0),d4 swap d4 ; d4 is now old selection range move.l a4,-(sp) pea lString(A6) _GetIText ; change to new text and no selection range move.l a4,-(sp) pea @versionData _SetIText move.l a3,-(sp) move.w d3,-(sp) clr.l -(sp) _SelIText @versionWait subq #2,sp _StillDown tst.b (sp)+ bne.s @versionWait ; restore old string and selection move.l a4,-(sp) pea lString(A6) _SetIText move.l a3,-(sp) move.w d3,-(sp) move.l d4,-(sp) _SelIText move.l (sp)+,a4 bra @NoFiltering ; ; filtering of key down events ; @filterKeyDown move.w EventRecord.modifiers(A2),d1 ; save the modifiers moveq #0,D2 ; clear out character move.b EventRecord.message+3(A2),D2 ; get character into D2 ; check for default item keyboard equivalent ; cmp.b #chEnter,D2 ; is it Enter key? ; beq @DefaultItem ; cmp.b #chCR,D2 ; is it Return key? ; beq @DefaultItem ; check for command keys btst #cmdKey, d1 ; is command key down beq @notCmdKey ; br if not ; now check for Cmd-O moveq #sfItemOpenButton,d0 bsr VirtualToRealItem cmp.b lCmdKeyOpen(a6),d2 ; was it an Oh beq @ReturnButton ; yes, lets goÉ cmp.b lCmdKeyOptOpen(a6),d2 ; was it an option-Oh beq @ReturnButton ; yes, lets goÉ ; now check for Cmd-D tst.b lVolumeSelect(a6) ; don't do cmd-D when in volumeselect mode (button is drive) bne.s @checkArrows moveq #sfItemDesktopButton,d0 bsr VirtualToRealItem cmp.b lCmdKeyDesktop(a6),d2 ; was it an Dee beq @ReturnButton ; yes, lets goÉ ; check for Cmd-N, only in putFile tst.b lDoingGetFile(a6) bne.s @checkArrows moveq #sfItemNewFolderUser,d0 tst.b lNewDialog(a6) ; <61 #85049> beq.s @checkArrows ; <61 #85049> ;<61 #85049>bsr VirtualToRealItem cmp.b lCmdKeyNewFldr(a6),d2 ; was it an ehNa beq @ReturnButton ; yes, lets goÉ ; now check for command arrow keys @checkArrows cmp.b #chDownArrow,d2 ; was it down arrow? bne.s @chkRightArrow ; no, try next bsr GetSel ; get selection in A0 bmi.s @NoFIltering_ ; can do anything without selection btst #ioDirFlg,FileEntry.feFlAttr(a0) ; a folder or alias to a folder? beq.s @NoFIltering_ ; if not, do nothing move.w #sfHookOpenFolder,d0 btst #isAliasBit,FileEntry.feFndrFlags(a0) ; is it a real folder (not an alias)? beq.s @ActivateList ; if so, change it to sfHookOpenFolder move.w #sfHookGotoAliasTarget,d0 btst #optionKey,EventRecord.modifiers(a2); is option key down? bne.s @ActivateList ; if so, change to sfHookGotoAliasTarget move.w #sfHookOpenAlias,d0 ; else change to sfHookOpenAlias bra.s @ActivateList @chkRightArrow move.w #sfHookGotoNextDrive,d0 cmp.b #chRightArrow,d2 ; was it right arrow? beq.s @ActivateList ; yes, lets goÉ move.w #sfHookGotoPrevDrive,d0 cmp.b #chLeftArrow,d2 ; was it left arrow? beq.s @ActivateList ; yes, lets goÉ cmp.b #chUpArrow,d2 ; was it up arrow? bne.s @notCmdKey ; no, try other keys move.w #sfHookGotoParent,d0 ; assume shift not down btst #shiftKey, d1 ; is shift key down beq.s @ActivateList ; no, lets goÉ move.w #sfItemDesktopButton,d0 bsr VirtualToRealItem ; command-shift-upArrow means goto desktop bsr CanDo ; is the desktop control active bmi @ReturnNullEvent ; exit if it is dimmed bsr FlashItem ; flash item to give feedback ; a command arrow key was used. make sure file list is now target @ActivateList move.w d0,-(sp) ; save off moveq #sfItemFileListUser,d0 bsr VirtualToRealItem cmp.w lActiveDITLitem(a6),d0 ; is list already active ? beq.s @listNowActive bsr SetActiveNow @listNowActive move.w (sp)+,d0 ; restore bra @ChangeHitTo @NoFiltering_ bra @NoFiltering @notCmdKey ; Tab -> need to switch to next possible active item cmp.b #chTab,D2 ; is it a TAB? bne.s @notTab move.w lActiveDITLitem(a6),d1 move.l lActiveList(a6),a0 cmp.w #1,(a0) ; is there only one activatable item? beq.s @hideEvent ; so do nothing ; need to find next activatable item move.w (a0),d0 ; list length in D0 move.w lActiveDITLitem(a6),d1 ; current item in D1 @findnext addq #2,a0 ; walk list subq.w #1,d0 bmi.s @wrap ; if can't find current, then just use first cmp.w (a0),d1 bne.s @findnext tst.w d0 ; is this last item bne.s @haveNext @wrap move.l lActiveList(a6),a0 ; if so wrap around @haveNext move.w 2(a0),d0 ; get next item into d0 ; activate next item bsr SetActiveNow ; d0 and a3 already set up @hideEvent clr.w EventRecord.what(A2) ; make sure apps filter does not see tab key bra @ReturnNullEvent ; map TAB to a null event @notTab ; fall into same code as @filterAutoKey ; ; filtering of auto repeat key down events and common keys for new folder sub dialog ; @filterAutoKey ; for compatibility, old calls to sf get a chance to see keydown event ; new calls, already got a chance at beginning of TheDialogFilter tst.b lNewReply(a6) bne.s @doneUserKey ; for compatibility, old apps need filter to get key events bsr CallUserDlgFilter bne @done ; if returned true, then app handle event ; jump to done and avoid repeat call to CallUserDlgFilter move.w EventRecord.what(A2),d0 ; check if app changed event.what <64, #f1-ngk-001> cmp.w #keyDwnEvt,d0 ; still key down? <64, #f1-ngk-001> beq.s @doneUserKey ; <64, #f1-ngk-001> cmp.w #AutoKeyEvt,d0 ; or autokey? <64, #f1-ngk-001> bne @done ; if not, app changed, so not key <64, #f1-ngk-001> @doneUserKey move.w EventRecord.modifiers(A2),d1 ; save the modifiers moveq #0,D2 ; clear out character move.b EventRecord.message+3(A2),D2 ; get character into D2 ; check for ESC key, which means hit the Cancel button ; moveq #2,d0 ; cancel is always button 2 ; cmp.b #chEscape,d2 ; was it an escape? ; bne.s @1 ; cmp.b #kcEscape,EventRecord.message+2(a2) ; need the key code to tell escape from clear ; beq @ReturnButton ; yes, lets goÉ ;@1 ; auto-key tab does nothing cmp.b #chTab,D2 ; is it a TAB? beq @ReturnNullEvent ; if so, eat the key btst #cmdKey,d1 ; is command key pressed? beq.s @TEchk ; if not, then key could be for TE ; now check for Cmd-period, which means hit the Cancel button ; moveq #2,d0 ; cancel is always button 2 ; cmp.b lCmdKeyCancel(a6),d2 ; was it a period? ; beq @ReturnButton ; yes, lets goÉ ; check for Cmd-V in putfile for filename, or in newfolder for folder name @PasteChk tst.b lDoingGetFile(a6) bne @NoFiltering cmp.b #'V',d2 ; was it a V? (generated by menu) <56, #BS-040> beq.s @haveCmdV ; <56, #BS-040> cmp.b #'v',d2 ; was it a v? (generated by keyboard) ### not localizable bne @NoFiltering @haveCmdV cmp.l #sfNewFolderDialogRefCon,wRefCon(a3) beq.s @doPaste cmp.l #sfMainDialogRefCon,wRefCon(a3) bne @NoFiltering moveq #sfItemFileNameTextEdit,d0 bsr VirtualToRealItem subq #1,d0 cmp.w editField(a3),d0 ; is this the fileName TE item? bne @NoFiltering ; if not, let dialog manager handle it @doPaste bsr PasteFileName ; if so, do my special paste bra @ReturnNullEvent ; now check and see if TextEdit deserves the key ; note that the auto-key events rejoin the keyDown events here, since arrow keys repeat @TEchk tst.b lListIsActive(a6) ; if list active bne.s @notForTE ; move.l teHandle(a3),a0 ; get TE record for this dialog ; cmp.l #0,a0 ; beq.s @notForTE ; no TE, so don't give it to Dialog manager move.w editField(a3),d3 addq.w #1,d3 ; see if any TE items are active (-1 => no active field) ; beq.s @notForTE ; if not, then don't give it to Dialog manager ; move.l (a0),a0 ; tst.b teActive(a0) ; is TE item active? ; beq.s @notForTE ; if not, then don't give it to Dialog manager cmp.l #sfMainDialogRefCon,wRefCon(a3) bne.s @isFileName ; if not main, must be new folder subdialog moveq #sfItemFileNameTextEdit,d0 bsr VirtualToRealItem cmp.w d3,d0 ; is it filename TE item? bne.s @NotMyKey ; if not, must be an app te item @isFileName cmp.b #chCR,D2 ; is it a CR? beq.s @ReturnNullEvent_1 ; if so, eat CR cmp.b #chEnter,D2 ; is it an Enter? beq.s @ReturnNullEvent_1 ; if so, eat Enter cmp.b #':',D2 ; is it a colon? beq.s @ReturnNullEvent_1 ; if so, eat colon move.l teHandle(a3),a0 ; get TE record for this dialog move.l (a0),a0 move.w teLength(a0),d0 cmp.w #31,d0 ; is filename already full? blt.s @NoFiltering_3 ; if not, let Dialog manager handle it cmp.b #chLeftArrow,D2 ; is it a left arrow? beq.s @NoFiltering_3 ; if so, let Dialog manager handle it cmp.b #chRightArrow,D2 ; is it a right arrow? beq.s @NoFiltering_3 ; if so, let Dialog manager handle it cmp.b #chDelete,D2 ; is it the delete? beq.s @NoFiltering_3 ; if so, let Dialog manager handle it move.w teSelEnd(a0),d0 sub.w teSelStart(A0),d0 ; get size of selection bgt.s @NoFiltering_3 ; if 1 or more chars, allow typing to overwrite move.w #1,-(sp) _SysBeep ; eat char, don't let it get put into filename @ReturnNullEvent_1 bra @ReturnNullEvent @NotMyKey tst.b lATEIsActive(a6) beq.s @ReturnNullEvent_1 @NoFiltering_3 bra @NoFiltering ; the key was not for TE, if it is not a cmd-key, then map it to 1000+char only @notForTE btst #cmdKey,d1 ; is command key pressed? bne.s @NoFiltering_1 ; if so, then don't map it move.w D2, D0 add.w #sfHookCharOffset,D0 ; Return as itemHit = $1000+character bra @ChangeHitTo ; ; filtering of update events ; @filterUpdateEvent ; is this the main sf dialog? move.l a3,-(sp) ; save a3 lea lTheDialogRec(a6),a3 ; in here a3=main dialog cmp.l EventRecord.message(A2),a3 ; is update for main dialog? bne.s @doneUpdate ; switch to port update event is for subq #4,sp pea (sp) _GetPort ; save port for later restore move.l a3,-(sp) _SetPort ; switch to main dialog port to draw stuff ; if update event for me, be paranoid and draw all ; non-userItem things ; force drawing of active item halo move.b lListIsActive(a6),d0 bsr DrawFileListHalo ; be sure to draw extra box around the active control ; for compatibility, old calls to sf get a chance to see update event ; new calls, already got a change at beginning of TheDialogFilter tst.b lNewReply(a6) bne.s @doneUserUpt ; in BigBang we call app's DlgFilter first, not last bsr CallUserDlgFilter bne.s @doneDrawing ; if returned true, then app did update @doneUserUpt ; now do what dialog mgr would do and move.l a3,-(sp) _BeginUpdate move.l a3,-(sp) _DrawDialog ; draw dialog items move.l a3,-(sp) _EndUpdate ; tell dialog mgr to not handle this update event move.l FilterFrame.itemHit(A4),A0 ; return null pseudo-item move.w #sfHookNullEvent,(A0) move.b #1,FilterFrame.result(A4) @doneDrawing _SetPort ; restore port @doneUpdate move.l (sp)+,a3 ; restore a3 bra @checkUpdateFlood @NoFiltering_1 bra.s @NoFiltering ; ; filtering of activate events ; @filterActivateEvent move.l EventRecord.message(A2),a0 ; be sure it is activate for main dialog cmp.l #sfMainDialogRefCon,wRefCon(a0) bne.s @NoFiltering_1 move.l a3,-(sp) ; save current a3 subq #4,sp pea (sp) _GetPort ; save port on stack lea lTheDialogRec(a6),a3 ; switch to main dialog move.l a3,-(sp) _SetPort ; and port move.w EventRecord.modifiers(A2),d0 btst #activeFlag,d0 ; is it an activate or deactivate sne d0 ; make d0 a boolean move.b d0,-(sp) ; save d0 move.l a3,-(sp) move.w lActiveDITLitem(a6),-(sp) move.b d0,-(sp) ; activate or deactivate bsr CallActivate ; make sure item is properly active move.b (sp)+,d0 ; restore d0 bne.s @ActivateEvent @DeactivateEvent ; this is now done by StdFilterProc ; move.l lMainOpen(a6),d0 ; beq.s @doCancel ; if no open button, don't try to dim ; move.l d0,a0 ; bsr.s @dimIt ; dim open button ;@doCancel move.l lMainCancel(a6),a0 ; bsr.s @dimIt ; dim cancel button move.l lMainEject(a6),a0 bsr.s @dimIt ; dim eject button move.l lMainDesktop(a6),a0 bsr.s @dimIt ; dim desktop button move.l lMainNewFolder(a6),d0 beq.s @doneActivate move.l d0,a0 ; if it exists, bsr.s @dimIt ; dim newfolder button bra.s @doneActivate @dimIt move.l a0,-(sp) ; pass the button move.w #255,-(sp) _HiliteControl rts @ActivateEvent ; cancel is not set up in main loop because it is always enabled ; this is now done by StdFilterProc ; move.l lMainCancel(a6),-(sp) ; pass the button ; move.w #0,-(sp) ; _HiliteControl @doneActivate _SetPort ; restore port move.l (sp)+,a3 ; restore a3 ;bra @ReturnNullEvent ; don't let dialog manager try to activeate TE item @ReturnNullEvent moveq #sfHookNullEvent,D0 ; return fake button bra.s @ChangeHitTo @DefaultItem move.w aDefItem(a3),D0 ; default item number from dialog record @ReturnButton bsr CanDo ; is the control active?? bmi.s @returnNullEvent ; exit if it is dimmed bsr FlashItem ; flash item to give feedback @ChangeHitTo move.l FilterFrame.itemHit(A4),A0 ; point to item result move.w D0,(A0) move.b #1,FilterFrame.result(A4) ; turn false into true @NoFiltering move.w EventRecord.modifiers(A2),lMeta(A6) ; save the modifiers move.l EventRecord.when(A2),lTicks(A6) ; and the ticks tst.b lNewReply(a6) bne.s @checkUpdateFlood ; in new calls we call user DlgFilter first, not last tst.w FilterFrame.calledFilter(A4); already called? (keydown events are handled earlier) <66, #f1-ngk-002> bne.s @checkUpdateFlood ; if so, don't call again <66, #f1-ngk-002> bsr.s CallUserDlgFilter @checkUpdateFlood ; if an update event is pending for a behind window and no one ; handles it then, ModalDialog won't return. So at the last moment ; we check for update events that no one has handled and map them ; to hookNullEvents tst.b FilterFrame.result(A4) ; has event been handled? bne.s @done ; if so, we're done cmp.w #updatEvt,EventRecord.what(a2) ; is it an update event? bne.s @done ; if not, we're done cmp.l EventRecord.message(A2),a3 ; is it update for another? beq.s @done ; if so, map to hookNullEvent move.w #nullEvt,EventRecord.what(a2) ; but first, give StdFilter proc bsr.s CallStdDlgFilter ; a chance to do null event processing bra.s @ReturnNullEvent @done movem.l (SP)+,D3/D4/A2/A3/A6 ; restore work registers unlk A4 move.l (SP)+,A0 ; get rts add.w #FilterFrame.paramSize,SP jmp (A0) DebuggerSymbol TheDialogFilter ;------------------------------- ; ; called by TheDialogFilter ; ; a3 = dialog ; a2 = eventrecord ; CallStdDlgFilter subq.l #6,sp ; Make a proc ptr var and result pea 2(sp) ; Push the proc addr _GetStdFilterProc ; Get the standard filter proc address (macro) tst.w (sp)+ ; Everything OK beq.s @gotIt ; branch if have proc addq #4,sp ; remove space for proc ptr moveq #0,d0 ; return with z-flag set bra.s @done @gotIt move.l (sp)+,a0 ; Get the filter proc address subq #2,sp ; BOOLEAN move.l a3,-(sp) ; theDialog: DialogPtr move.l a2,-(sp) ; VAR theEvent: EventRecord move.l FilterFrame.itemHit(a4),-(sp) ; VAR itemHit: INTEGER jsr (a0) move.b (sp)+,d0 @done rts DebuggerSymbol CallStdDlgFilter ;------------------------------- ; ; called by TheDialogFilter, assumes A6 and A4 are setup ; CallUserDlgFilter st FilterFrame.calledFilter(A4) ; mark that have called filter <66, #f1-ngk-002> move.l lFilterProc(A6),D0 ; is there a dialog filter beq.s @noFilter lea lTheDialogRec(a6),a0 cmp.l a0,a3 beq.s @doFilter ; if this is a sub dialog tst.b lNewReply(a6) ; and not a new reply then done beq.s @noFilter @doFilter MOVE.L D0,A0 ; point to proc clr.w -(sp) ; make room for returned boolean <55.1, #82022> MOVE.L A3,-(SP) ; pass dialog MOVE.L A2,-(SP) ; pass the event MOVE.L FilterFrame.itemHit(A4),-(SP) ; point to item result TST.B lUseCallBack(A6) ; does routine want callback? BEQ.S @noCallBackPtr MOVE.L lCallBackPtr(A6),-(SP) @noCallBackPtr JSR (A0) ; call the hook MOVE.B (SP)+,D0 ; OR in their result OR.B D0,FilterFrame.result(A4) @noFilter RTS DebuggerSymbol CallUserDlgFilter ;-------------------------------------------------------------------- ; ; Does a paste in which and ':' are changed to '-' ; PasteFileName subq #4,sp move.l TEScrpHandle,-(sp) ; hDext: Handle move.l #'TEXT',-(sp) ; theType: ResType pea lPoint(a6) ; VAR offset {not used} _GetScrap move.l (sp)+,d0 ; if < 0 then error bpl.s @haveText clr.w TEScrpLength ; so mark nothing is TE scrap bra.s @done ; and do nothing @haveText move.w d0,TEScrpLength ; success, update TE scrap length ; now remove and ':' from TE scrap ; note that this way is OK, because second byte of ; a double byte char is never < $40 (which includes CR and ':') move.l TEScrpHandle,a0 move.l (a0),a0 ; walk through scrap @nextChar cmp.b #chCR,(a0) ; if beq.s @change cmp.b #':',(a0) ; or if ':' bne.s @loop @change move.b #'-',(a0) ; then change to '-' @loop addq #1,a0 subq #1,d0 ; until no more scrap bgt.s @nextChar ; next paste in processed stuff move.l teHandle(a3),-(sp) _TEPaste ; lastly, truncate to 31 chars move.l teHandle(a3),a1 move.l (a1),a1 move.w teLength(a1),d0 cmp.w #31,d0 ; is currently text length <= 31 ? ble.s @done ; if so then done move.l teTextH(a1),a0 ; else trucate whole TE to its first 31 chars moveq #31,d0 move.w d0,teLength(a1) _SetHandleSize ; a0 = handle, d0 = new size move.l teHandle(a3),-(sp) ; recalc TE stuff _TECalText @done rts DebuggerSymbol PasteFileName ;----------------- ; In: d0.w ; returns with N flag set it control is dimmed ; CanDo move.w d0,-(sp) ; save control # bsr.s GetIt ; item passed in d0 move.l lItem(a6),a0 ; get control handle move.l (a0),a0 ; control pointer move.w (sp)+,d0 ; restore control # tst.b ContrlHilite(a0) ; is control dimmed? @done rts DebuggerSymbol CanDo ;-------------------------------------------------------------------- ; ; GetIt ; Gets the item given in D0. Puts result in std frame GetIt MOVE.L A3,-(SP) ; pass the window MOVE D0,-(SP) ; user field ID PEA lKind(A6) PEA lItem(A6) PEA lBox(A6) _GetDItem ; get current settings RTS DebuggerSymbol GetIt ;-------------------------------------------------------------------- ; ; SetIt ; Sets the item given in D0. From results in std frame SetIt move.l A3,-(SP) ; pass the window move.w D0,-(SP) ; user field ID move.w lKind(A6),-(sp) move.l lItem(A6),-(sp) PEA lBox(A6) _SetDItem ; get current settings RTS DebuggerSymbol SetIt ;-------------------------------------------------------------------- ; flash button, item number in D0 ; FlashItem move.w d0, -(SP) ; save item number bsr.s GetIt ; get item handle move.l lItem(A6), -(SP) ; hilite the control move.w #1, -(SP) _HiliteControl move.w #8, A0 ; let the user see the hilite _Delay move.l lItem(A6), -(SP) ; restore control to normal clr.w -(SP) _HiliteControl @done move.w (SP)+, D0 ; restore item number rts DebuggerSymbol FlashItem ;-------------------------------------------------------------------- ; ; draws or undraws the extra border around the file list ; in: a3 -> dialog ptr ; a6 -> main stack frame ; d0 -> draw black if not zero ; penPat is white or black, as needed ; DrawFileListHalo move.l lActiveList(a6),a0 cmp.w #1,(a0) ; how many activatable items are there? ble.s @exit ; if one or less then no border move.b d0,-(sp) _PenNormal tst.b (sp)+ ; was d0 true ? bne.s @1 ; if so draw dark border move.w #notPatCopy,-(sp) ; else, switch to draw in white _PenMode @1 move.l lNRect.topLeft(a6),lBox.topLeft(a6) ; copy lNRect into temp rect move.l lNRect.botRight(a6),lBox.botRight(a6) pea lBox(a6) move.l #$fffdfffd,-(sp) ; outset box by three _InsetRect move.l #$00020002,-(SP) _PenSize pea lBox(a6) _FrameRect ; frame it _PenNormal ; don't mess up anyone else @exit rts DebuggerSymbol DrawFileListHalo bEditText equ 4 ;-------------------------------------------------------------------- ; ; PROCEDURE CallActivate(theDialog: DialogPtr; itemNo: INTEGER; activating: BOOLEAN); ; ; if the item is not one of the standard ones, calls user's proc ; to tell it it is activating or deactivating ; in: a3 -> dialog ptr ; a6 -> main stack frame ; 4(sp) -> boolean, activting or not ; 6(sp) -> word, which item ; 8(sp) -> long, dialog ptr (same as a3) CallActivate move.w 6(sp),d0 ; see if item is a text edit bsr GetIt move.w lKind(A6),d0 btst #bEditText,d0 ; is this a TE item? <40 ngk 16sept90 > beq @checkFileList ; if so I can de/activate it for app move.w lBox+left(a6),d0 ; is the TE item hidden (HideDItem) ? <65, #85960> cmp.w #$2000,D0 ; unsigned compare, < $2000 means not hidden <65, #85960> bgt @TEdone ; if hidden, don't try to activate (fixes AppleLink 6.0) <65, #85960> tst.b 4(sp) sne lATEIsActive(a6) ; remember that a TE item is active (or not) bne.s @TEActivate @TEDeActivate ; deactive the TE item move.l teHandle(a3),-(sp) ; if deactivating then _TEDeactivate ; deactivate the TE ; mark the dialog as not having active TE field move.w #-1,editField(a3) bra @checkFileList ; CSS @TEActivate ; switch to new item's text handle move.l teHandle(a3),a0 move.l (a0),a1 move.l lItem(a6),teTextH(a1) ; switch TE's rects to new items's rect lea teDestRect(a1),A0 move.l lBox(A6),(A0)+ ; set dest rect move.l lBox+4(A6),(A0)+ tst.w TeSysJust bmi.s @normBox ; don't make box wider in right-left scripts add.w #100,teDestRect+Rect.right(a1) ; make dest rect wider to allow scrolling @normBox move.l lBox(A6),(A0)+ ; set view rect move.l lBox+4(A6),(A0)+ st teClikLoc(A1) ; remove double click possibility ; select all and TEActivate it, unless mouse is down (user is dragging) clr.l -(sp) ; select from 0 move.w teLength(a1),d0 ext.l d0 ; d0 = length move.l d0,-(sp) subq #2,sp _Button tst.b (sp)+ beq.s @setIt clr.l (sp) ; don't select, 'cause it would make a flicker @setIt move.l teHandle(a3),-(sp) ; this TE _TESetSelect move.l teHandle(a3),-(sp) _TECalText ; recalc stuff move.l teHandle(a3),-(sp) _TEActivate ; active the TE item ; mark dialog with which field is active move.w 6(sp),d0 subq.w #1,d0 move.w d0,editField(a3) ; if this is putfile filename, then set mode tst.b lDoingGetFile(a6) ; is it put file? bne.s @TEdone moveq #sfItemFileNameTextEdit,d0 bsr VirtualToRealItem cmp.w 6(sp),d0 ; is it filename TE item? bne.s @TEdone move.l teHandle(a3),a0 move.l (a0),a0 moveq #-1,d0 move.w d0,teCROnly(a0) ; set TERec so that no implicit word wrap @TEdone bra.s @doneMyStuff @checkFileList ; see if the item being activated/deactivated is a list then do halo moveq #sfItemFileListUser,d0 bsr VirtualToRealItem cmp.w 6(sp),d0 bne.s @doneMyStuff move.b 4(sp),d0 ; be paranoid (possible to miss activate events) cmp.b lListIsActive(a6),d0 ; if I think it is already in this activate state beq.s @doneMyStuff ; then do nothing move.b d0,lListIsActive(a6) ; now remember new state ; draw the right halo bsr DrawFileListHalo ; state to draw in d0 ; select-deselect the selected item tst.b 4(sp) beq.s @deActList ; we are now activating the list, if there was an item selected, reselect it move.l lLastSel(a6),d0 bmi.s @doneMyStuff st -(sp) bra.s @setSelect ; now know we are deactiving, so see if there is a selected item @deActList bsr GetSel move.l d0,lLastSel(a6) bmi.s @doneMyStuff ; is a selected item, so save it off and deselect it clr.b -(sp) ; set selected false @setSelect move.l d0,-(sp) ; push the cell to deselect move.l lFileListHandle(a6),-(sp) _LSetSelect ; deselect the chosen cell @doneMyStuff ; jump to apps proc to tell it what is happening move.l lActivateProc(a6),A0 ; get ActivateProc Ptr in A0 move.l a0,d0 beq.s @noActvProc ; if NIL then donÕt call move.l (sp),-(sp) ; move return address down to make room move.l lCallBackPtr(a6),4(SP) ; for the extra parameter jmp (a0) ; note: does not return here @noActvProc move.l (SP)+,(SP) ; remove parameters move.l (SP)+,(SP) rts DebuggerSymbol CallActivate ;-------------------------------------------------------------------- ; ; This is the start of a hack to support apps (like quickmail enclosures) ; dialog that disable the filename field. If we could notice that, then ; we could change the active field to be the file list ; ;SyncActiveItem ; move.l teHandle(a3),a0 ; get TE record for this dialog ; cmp.l #0,a0 ; beq.s @notTE ; no TE, so don't give it to Dialog manager ; move.w editField(a3),d3 ; addq.w #1,d3 ; see if any TE items are active (-1 => no active field) ; beq.s @notTE ; if not, then don't give it to Dialog manager ; move.l (a0),a0 ; tst.b teActive(a0) ; is TE item active? ; beq.s @notTE ; if not, then don't give it to Dialog manager ;### ;@notTE ; ; rts ; DebuggerSymbol SyncActiveItem ;-------------------------------------------------------------------- ; ; Given an item in D3, this assumes its a user item and sets the draw proc to ; our common drawproc SetUserDraw MOVE D3,D0 ; user field ID for disk name BSR GetIt ; get current settings MOVE.L A3,-(SP) ; pass the window MOVE D3,-(SP) ; button ID MOVE lKind(A6),-(SP) PEA UserDraw ; install the draw proc PEA lBox(A6) _SetDItem RTS DebuggerSymbol SetUserDraw ;-------------------------------------------------------------------- ; ; Given a item # in D0 and a string in A2 this sets its text SetItsText BSR GetIt ; get current settings MOVE.L lItem(A6),-(SP) ; set the prompt MOVE.L A2,-(SP) _SetIText RTS DebuggerSymbol SetItsText ;-------------------------------------------------------------------- ; ; TruncString( VAR theStyle: Style; indent: INTEGER; VAR str: STR255; r: Rect ); ; 18 16 12 8 ; This truncates the string to fit in the given rectangle, condensing ; the text and appending ellipses if needed. TruncString LINK A6,#0 ; set up the std world MOVEM.L D2-D7/A2-A4,-(SP) ; save those regs ; calculate the width of the rectangle MOVE.L 8(A6),A0 ; get the rectangle MOVE.L (A0)+,D0 ; get the topleft MOVE.L (A0)+,D3 ; get the botright SUB.W D0,D3 ; find extent SUB.W 16(A6),D3 ; slop for indent ; calculate the width of the text to avoid unecessary calls to _TruncString MOVE.L 12(A6),A3 ; get the string pointer SUBQ #2,SP ; get the width MOVE.L A3,-(SP) _StringWidth CMP.W (SP)+,D3 ; see if it fits first time BGT.S @exit ; escape if so ; text doesn't fit, so let's try using condensed mode MOVE.L 18(A6),A0 ; get current style BSET #condenseBit,1(A0) ; add condensed to current style MOVE.W (A0),-(SP) ; and set it _TextFace ; let _TruncString truncate the string if needed SUBQ #2,SP ; returns whether string truncated MOVE.W D3,-(SP) ; width MOVE.L 12(A6),-(SP) ; theString MOVE.W #smTruncEnd,-(SP) ; truncate at end <5> _TruncString ADDQ #2,SP ; ignore result @exit MOVEM.L (SP)+,D2-D7/A2-A4 ; restore those regs UNLK A6 MOVE.L (SP)+,A0 ; get rts ADD #14,SP JMP (A0) DebuggerSymbol TruncString ;-------------------------------------------------------------------- ; ; UserDraw handles the draw requests for the user fields in the dialog box ; The global storage pointer is in the refcon of the window ; PROCEDURE UserDraw(wind: WindowPtr; item: Integer); udregs EQU 44+4 ; 11 regs + RTS udItem EQU udRegs ; item passed udWind EQU udItem+2 ; window passed UserDraw MOVEM.L D2-D7/A2-A6,-(SP) ; save magic regs(44 bytes) MOVE.W udItem(SP),D7 ; save the item number MOVE.L udWind(SP),A3 ; get the window lea -lTheDialogRec(A3),A6 ; get the stdFile stack moveq #sfItemVolumeUser,d0 bsr VirtualToRealItem cmp.w d0,d7 ; is it volume title? bne.s @notVol bsr.s DrawVolume bra.s @exit @notVol moveq #sfItemFileListUser,d0 bsr VirtualToRealItem cmp.w d0,d7 ; is it file list? bne.s @notFileList bsr DrawFileList bra.s @exit @notFileList cmp.w #getGrayBar,d7 ; is it getGrayBar? bne.s @exit bsr.s DrawGrayBar @exit MOVEM.L (SP)+,D2-D7/A2-A6 ; save magic regs(44 bytes) MOVE.L (SP)+,A0 ; get rts ADDQ.L #6,SP JMP (A0) DebuggerSymbol UserDraw ;------------------------------------------ ; Draw Volume Icon and Name ; ; DrawVolume move.l a3,-(sp) ; erase what's currently there lea lVolRect(a6),a2 move.l a2,-(sp) _EraseRect ; draw the icon and name for the current volume lea lVolName(a6),a3 move.w lVolIcon(a6),d7 ; disk icon selector moveq #0,d3 ; pass in indent bsr DrawName ; draw volume icon and name in a2 rect move.l (sp)+,a3 rts DebuggerSymbol DrawVolume ;------------------------------------------ ; Draw gray dividing line in get file ; ; DrawGrayBar moveq #getGrayBar,D0 ; user field ID bsr GetIt ; get current settings pea lBox(a6) _PenNormal _FrameRect ; frame the box rts DebuggerSymbol DrawGrayBar ;---------------------------------------------------------- ; Draw PopUpMenu with icon, current folder, and drop shadow ; ; assumes a3 = dialogPtr ; a6 = main stack frame ; DrawPopUpMenu tst.b lPopUpLooksGood(a6) ; when user goes up in pop up, the CDEF has already drawn it correctly bne.s @looksGood ; lPopUpLooksGood is used to flag that state. ; with the popup CDEF we need to force the control to redraw ; but then we don't want the later redraw on update, so remove ; the controls bounds from the update rgn move.l lPopUpControl(a6),-(sp) _Draw1Control move.l lPopUpControl(a6),a0 move.l (a0),a0 pea contrlRect(a0) _ValidRect @looksGood sf lPopUpLooksGood(a6) rts DebuggerSymbol DrawPopUpMenu ;----------------------------------- ; GetInset centers specified string in specified rect. ; ; Entry: A0 = rect ; A1 = string ; D3 = inset from frame ; Exit: D4 = inset from edge of rect ; ; It centers the string in the rect, leaving room for an icon on the left, getInset move Right(a0),d4 ; New routine as of <17Dec85> sub Left(a0),d4 sub #iconWidth+iconPad,d4 ; width of icon+white space sub d3,d4 ; + indent sub d3,d4 ; twice for centering subq.l #2,sp move.l a1,-(sp) ; string pointer _StringWidth sub (sp)+,d4 bge.s @1 ; will fit clr d4 ; won't, don't center @1 lsr #1,d4 ; div 2 rts DebuggerSymbol getInset ;----------------------------------------------------- ; ; Draw name centers the name and draws it with the appropriate ; mini icon, passed in d7. ; The indent is in d3 ; The centering inset is returned in d4. ; DrawInPlace should be called with d4 set up and the list handle in A0. DrawName move.l a2,a0 ; pass bounds rect lea StyledString.text(a3),a1 ; pass string ptr <17Dec85> bsr.s getInset ; get inset into D4 <17Dec85> move.w lFontInfoRec.ascent(a6),d5 ; get ascent swap d5 move.w lHeight(A6),d5 ; get height move.l lFileListHandle(a6),a0 ; list handle for plotmini DrawInPlace ; A0 = listHandle, A2 = Rect, A3 = StyledString ; D3 = indent, D4 = position, D5 = ascent, ; D7 = icon sub.w #70,sp ; string buffer and point move.l sp,a1 move.l (a2),(a1) add.w d4,Left(a1) ; position it add.w d3,Left(a1) ; add indent move.l (a1),d1 ; pass topLeft in d1 move.w d5,d0 ; get vertical offset sub.w #16,d0 ; get difference from standard bmi.s @1 ; => ignore neg asr.w #1,d0 ; split the difference swap d1 ; get top add.w d0,d1 ; add in difference swap d1 ; and make it a topLeft @1 move.l a0, -(sp) ; save a0/d1 across plotmini move.l d1, -(sp) move.l 4(sp), a0 move.l (sp), d1 move.w d7,d0 ; icon selector bsr PlotMini ; list handle in a0 addq #8, sp ; strip saved a0/d1 move.l (sp)+,d0 ; get start point add.w #iconwidth+iconpad,d0 ; pad to left move.l d0,-(sp) ; save for stuffing tempRect move.l d0,-(sp) ; push for moveto swap d5 ; get ascent add.w d5,(sp) ; add ascent to vertical _MoveTo ; position the pen lea TempRect,a0 ; build rect for truncating string move.l (sp)+,(a0) move.l 4(a2),4(a0) ; make a copy of the string so we don't destroy it move.l sp,a1 ; destination string lea styledString.text(a3), a0 ; get ptr to source string moveq #0,d0 ; get a long count move.b (a0),d0 ; get the count addq.b #1,d0 ; add in the length byte _BlockMove ; get name to be trunc'd move StyledString.font(a3), d0 ; get font cmp.w lSystemFont(a3), d0 ; same as port's font? beq.s @systemFont ; br if so, skip set move d0, -(sp) _TextFont ; set string for font bra.s @fontSet ; *** why is this set every time we draw a string?! ; make sure we have system face and size @systemFont clr.w -(sp) _TextFont clr.w -(sp) _TextSize @fontSet move.b StyledString.style(a3), d0 ; style normal? beq.s @faceSet ; br if so, style already set move.b d0, -(sp) ; set string's style _TextFace @faceSet move.b StyledString.style(a3),-(sp) ; make a copy of the current style move.l sp,-(sp) ; pea pointer to current style move.w #2,-(sp) ; 2 pixel indent pea 8(sp) ; pea lXName pea TempRect bsr TruncString pea 2(sp) ; pea lXName _DrawString move.w (sp)+, d0 ; was face different? beq.s @faceRestored ; br if not clr.w -(SP) ; restore face to normal _TextFace @faceRestored add.w #66,sp ; strip string buffer move StyledString.font(a3), d0 ; get font cmp.w lSystemFont(a3), d0 ; was it same as system font? beq.s @fontRestored ; br if so, don't need restore clr.w -(sp) ; restore font to normal _TextFont @fontRestored rts DebuggerSymbol DrawName ;--------------------------------------------------- ; ; Plot one of the mini icons. d0 = offset frrom genericIconBase ; d1 = topleft for icon ; a0 = list handle ; Trashes: a0,a1,d0,d1 PlotMini lea IconBitMap,a1 ; use lowmem for bitmap move #2,BitMap.rowBytes(a1) ; QD Rowbytes for 16x16 clr.l BitMap.bounds.topLeft(a1) ; boundsrect 0,0,16,16 move.l #$00100010,BitMap.bounds.botRight(a1) ; subq #4, sp ; space for handle move.l #'SICN', -(sp) ; get a small icon move d0, -(sp) ; pass SICN id _GetResource move.l (sp)+, d0 ; got an icon? beq.s @exit ; br if not, exit move.l d0, a0 move.l (a0),BitMap.baseAddr(a1) ; replace in bitmap move.l a1,-(sp) ; src bitmap move.l GrafGlobals(a5),a0 ; get qd globals move.l ThePort(a0),a0 ; point at the current port pea portBits(a0) ; pass window bitmap as dest bitmap pea BitMap.bounds.topLeft(a1) ; use bounds as src rect lea Scratch20,a0 move.l a0,-(sp) ; save the address move.l d1,(a0)+ ; point to topleft move -4(a0),(a0) ; copy top add #16,(a0)+ ; bottom = top+size move -4(a0),(a0) ; copy left add #16,(a0) ; right = left+size move #srcCopy,-(sp) ; copy mode clr.l -(sp) ; NIL MaskRgn _CopyBits ; finally @exit rts DebuggerSymbol PlotMini ;------------------------------------------------------------- ; ; AllOthersDialogHook move.w lHit(a6),d0 cmp.w #sfHookFirstCall,d0 bne.s @notFirstCall ; so center over main dialog, which we know is on screen. move.l a3,-(sp) ; whichWindow: WindowPtr move.b #lcParentWindow,-(sp) ; where: LocationControlValues move.b #hcCenter,-(sp) ; horizontalControl: HorizontalControlValues move.b #vcDocumentCenter,-(sp) ; verticalControl: VerticalControlValues _AutoPositionWindow ; change default button on replace and stationery dialog to second button moveq #1,d0 ; assume default is button 1 cmp.l #sfReplaceDialogRefCon,wRefCon(a3) beq.s @default2 cmp.l #sfStatWarnDialogRefCon,wRefCon(a3) bne.s @haveDefault @default2 moveq #2,d0 @haveDefault ; change cancel button on general error dialog to first button moveq #2,d1 ; assume cancel is button 2 cmp.l #sfErrorDialogRefCon,wRefCon(a3); this dialog has no button #2 bne.s @haveCancel moveq #1,d1 @haveCancel st d2 ; d2 = track cursor bsr SetUpDialogFlags ; requires d0,d1,d2 and a3 @notFirstCall cmp.w #1,d0 beq.s @dismisser cmp.w #2,d0 bne.s @exit @dismisser st lSubDlgDone(a6) @exit rts DebuggerSymbol AllOthersDialogHook ;-------------------------------------------------------------------- ; ; Get STR# D1 into A1 ; GetLocalString CLR.B (A1) ; assume failure SUBQ #4, SP ; Save space for handle MOVE.L #'STR#', -(SP) ; Push STR# MOVE.W #rStandardFileStringsID, -(SP) ; Push ID _GetResource ; Get the string list MOVE.L (SP)+, D0 ; and copy to A0 BEQ.S @exit MOVE.L D0, A0 MOVE.L (A0), A0 ; Dereference stringlist. MOVE.W (A0)+, D0 ; Get count MOVEQ #0, D0 ; zero high order @nextString SUBQ #1, D1 ; Decrement index BEQ.S @gotString ; if zero, have right string MOVE.B (A0)+, D0 ; Get string length ADD.W D0, A0 ; Skip over BRA.S @nextString ; and loop back @gotString MOVEQ #1, D0 ; include length byte ADD.B (A0), D0 ; Get string length _BlockMove ; Copy the string @exit RTS DebuggerSymbol GetLocalString ;-------------------------------------------------------------------- ; ErrorAlert(errorStringIndex) ; This routine raises an alert AFTER moving it to center ; D1 (in) string index ; D0 (out) alert result ; ; ErrorAlert2(namePtr) ; Raise the replace alert using the filename passed in in A1 ; A1 (in) ptr to string for citation ^0 ; D4 (in) dialog ID ; d3 (in) dialog refcon ; D0 (out) alert result ; ErrorAlert move.w #rSFOKDialogID,d4 move.l #sfErrorDialogRefCon,d3 lea lString(A6),a1 bsr.s GetLocalString ErrorAlert2 move.l a1,-(SP) clr.l -(SP) clr.l -(SP) clr.l -(SP) _ParamText move.w d4,d0 ; d0 = dialog ID bsr.s DoSubDialog rts DebuggerSymbol ErrorAlert ;--------------------------------------------- ; d0 = dialog res ID ; d3 = refcon ; DoSubDialog clr.b lSubDlgDone(a6) lea lSubDialogRec(a6),a3 ; a3 = dialog storage bsr.s StartDialog ; d3 = refcon ; loop until lSubDlgDone is true @next tst.b lSubDlgDone(a6) bne.s @done bsr GetNextItemHit ; get hit bsr DoAppsHook ; let app process hit bsr DoMyHook ; let me process hit bra.s @next @done ; take down dialog move.w lHit(a6),-(sp) ; save hit that cause dismiss around EndDialog bsr.s EndDialog move.w (sp)+, lHit(a6) lea lTheDialogRec(a6),a3 ; restore main dialog move.l a3,-(sp) _SetPort move.w lHit(a6),d0 rts DebuggerSymbol DoSubDialog ;-------------------------------------------- ; StartDialog ; in: a3 = dialog storage ; d0.w = dialog ID ; d3.l = refcon StartDialog ; load the dialog subq #4,SP ; room for window move.w d0,-(sp) ; id for dialog move.l a3,-(sp) ; use my window stroage moveq #-1,D0 ; get -1 move.l D0,-(SP) ; behind = -1 _GetNewDialog ; allocate a new dialog tst.l (sp)+ bne.s @gotDialog addq #4,sp ; pop return address bra abortExit ; jump to abort code, note: this is only helpful on main dialog @gotDialog move.l d3,wRefCon(a3) ; mark which dialog this is move.l a3,-(sp) ; make it current grafport _SetPort ; do first hook move.w #sfHookFirstCall,lHit(a6) bsr.s DoMyHook ; let me process hit first !!!!! bsr DoAppsHook ; let app process hit cmp.l #sfMainDialogRefCon,wRefCon(a3) ; the main dialog need some beq.s @specialMainExit ; special casing (MainHookAfterFirstHook) cmp.w #sfHookFirstCall,lHit(a6) ; Check if the users filter changed item <2> FM beq.s @showWindow ; hit. If they did they must want to surpress the dialog <2> FM bsr DoMyHook ; Run through DoMyhook again so we can surpress the dialog <2> FM tst.b lSubDlgDone(a6) ; did they repress the dialog?? <2> bne.s @exitNoShowWindow ; out of sight out of mindÉ <2> bra.s @showWindow @specialMainExit bsr MainHookAfterFirstHook ; show dialog @showWindow move.l A3,-(sp) _ShowWindow ; show it @exitNoShowWindow rts DebuggerSymbol StartDialog ;-------------------------------------------- ; EndDialog ; ; in: a3 = dialog storage ; EndDialog ; hide window move.l a3,-(sp) _HideWindow ; last hook move.w #sfHookLastCall,lHit(a6) tst.b lNewReply(a6) ; don't call last hook on calls 1-4 beq.s @doMyHook bsr.s DoAppsHook ; let app process hit @doMyHook bsr.s DoMyHook ; let me process hit first ; dispose dialog move.l a3,-(sp) _CloseDialog ; take down the dialog move.l items(a3),a0 ; dispose of the item list _DisposeHandle rts DebuggerSymbol EndDialog ;-------------------------------------------------------------------- ; ; DoMyHook move.l wRefCon(a3),d1 lea MainDialogHook,a0 ; use MainDialogHook for main dialog cmp.l #sfMainDialogRefCon,d1 beq.s @doit lea NewFolderDialogHook,a0 ; use NewFolderDialogHook for new folder dialog cmp.l #sfNewFolderDialogRefCon,d1 beq.s @doit lea AllOthersDialogHook,a0 ; otherwise use AllOthersDialogHook @doit jsr (a0) rts DebuggerSymbol DoMyHook ;-------------------------------------------------------------------- ; ; ; DoAppsHook move.l lDlgHook(a6),d0 ; get the hook beq.s @doneHook ; if none, then we're done lea lTheDialogRec(a6),a0 cmp.l a0,a3 beq.s @dialogOK ; if this is a sub dialog tst.b lNewReply(a6) ; and not a new reply then done beq.s @doneHook @dialogOK subq #2,sp ; room for result move.w lHit(a6),-(SP) ; pass the item hit move.l A3,-(SP) ; pass the dialog tst.b lUseCallBack(a6) ; does routine want callback? beq.s @noCallBackPtr move.l lCallBackPtr(a6),-(sp) @noCallBackPtr move.l D0,A0 jsr (A0) ; call the hook move.w (SP)+,lHit(a6) ; get result item @doneHook rts DebuggerSymbol DoAppsHook ;--------------------------------------------------------- ; ; in: d0.w = default button number ; d1.w = cancel button number ; d2.b = whether to track cursor (boolean) ; a3.l = dialog ptr SetUpDialogFlags move.b d2,-(sp) ; save for future use move.w d1,-(sp) ; save for future use ; system handles default button tst.l lMainOpen(a6) ; hack for PageMaker beq.s @doneMain subq #2,sp ; room for OSErr result move.l a3,-(sp) ; dialogPtr move.w d0,-(sp) ; default item _SetDialogDefaultItem addq #2,sp ; ignore result code @doneMain ; system handles cancel button move.w (sp)+,d1 ; retreive cancel button number subq #2,sp ; room for OSErr result move.l a3,-(sp) ; dialogPtr move.w d1,-(sp) ; cancel item number _SetDialogCancelItem addq #2,sp ; ignore result code ; system (in new dialog) the cursor move.b (sp)+,d2 ; retreive saved d2 subq #2,sp ; room for OSErr result move.l a3,-(sp) ; dialogPtr move.b d2,-(sp) ; whether to track _SetDialogTracksCursor addq #2,sp ; ignore result code rts DebuggerSymbol SetUpDialogFlags ;-------------------------------------------------------------------- ; ; PROCEDURE AddFileListItems; ; ; Entry ; A6 = stdfile frame ; disk = lVolRefNum(A6) ; ; Builds up the file list which consists of the header followed ; by a concatenation of file entries. ; (header)(file entry 1)...(file entry n) ; ; Register usage ; D6 offset of next record ; D5 current dirID ; D4 current file index ; D3 used by ForDiskDo ; A4 list cell data handle ; A3 list handle ; A2 used by ForDiskDo as vcb ptr AddFileListItems MOVEM.L D2-D6/A2-A4,-(SP) MOVEQ #1, D0 MOVE.L D0,lLastSel(A6) ; no previous selection CMP.W #40,lVnFiles(A6) ; a lot of files? BLS.S @skipWatch ; br if not, skip watch SUBQ #4,SP ; get the hour glass MOVE #4,-(SP) _GetCursor MOVE.L (SP)+,A0 MOVE.L (A0),-(SP) _SetCursor @skipWatch MOVE.L lFileListHandle(A6),A3 ; A3 = handle to list rec MOVE.L (A3),A4 ; get pointer to data record MOVE.L cells(A4),A4 ; A4 = handle to cell data MOVE.L A3,A0 ; set to starting size MOVE.L #sizeList+64,D0 ; start with room for 30 files _SetHandleSize MOVE.L A4,A0 ; set to starting size MOVE.L #1023,D0 ; start with a good size chunk ~30 files ; note, we grow it by 1024 each time, use 1023 now so we max at $7fff _SetHandleSize MOVEQ #0,D6 ; D6 = offset into data handle TST.B lAtDesktop(A6) ; at trash? BLE @notDesktop ; br if regular folder ; fall through to desktop case ; Add an entry for each disk which is mounted LEA AddDiskItem, A0 BSR ForDiskDo ; Sort the volume names at top of list moveq #0,d0 ; sort from start move.l (A3),A0 move.w dataBounds+Rect.bottom(A0),d1 ; number of volumes move.w d1,-(sp) ; save off for next sort subq.w #1,d1 ; sort is zero based bsr SortSome ; Add entries for desktop folder of each disk which is mounted MOVE.L #kDesktopFolderType,D5 ; add contents of desktop for all disks LEA AddSpecialFolder,A0 BSR ForDiskDo ; Sort the desktop files move.w (sp)+,d0 ; sort from start of desktop files move.l (A3),A0 move.w dataBounds+Rect.bottom(A0),d1 ; get number of files subq.w #1,d1 ; sort is zero based bsr SortSome ; Always add the trash to the desktop MOVE.L (A4),A1 ; dereference the list LEA (A1,D6.W),A1 WITH FileEntry MOVEQ #fsRtDirID,D0 MOVE.L D0,feTypeOrDirID(A1) ; stuff in 2 for dirID of trash MOVE.L D0,feParID(A1) ; stuff in 2 for parID of trash MOVE.W lBootVol(a6),feVRefNum(A1) ; trash's volume is startup MOVE.W lBootDrive(A6),feDrive(A1) ; trash's drive is startup CLR.B feFLAttr(A1) ; BSET #ioDirFlg,feFLAttr(A1) ; set isFolder attribute MOVE.B #mNoEject+bOpenable+bNoWrite+bNoRead+bNoSearch,feFLPriv(A1) ; give it no permissions MOVE.W #trashIconResource,feIcon(A1) ; set trash icon bsr GetIconSide ; gets iconLeft and Just into d0.w move.w d0,FileEntry.feIconLeft(A1) ;ST feIconLeft(A1) ; icon on left ;MOVE.B #teJustLeft,feJust(A1) ; left justify text CLR.W feIconColor(A1) ; trash is always black MOVE.W lSystemScript(A6),feFile.script(A1) ; trash uses system script MOVE.W lSystemFont(A6),feFile.font(A1) ; trash uses system font MOVE.W lSystemFontSize(A6),feFile.size(A1) ; trash uses system size ST feFile.dimmed(A1) ; trash is always dimmed CLR.B feFile.style(A1) ; normal style ENDWITH lea FileEntry.feFile.text(A1),A1 moveq #sfTrashName, D1 bsr GetLocalString ; load trash name into a1 bsr AddNewRecord bra.s @doneBuilding @notDesktop move.l lCurDir(a6), D5 ; add contents of current directory move lDriveNo(a6),lTempDrive(a6) ; setup drive for enumerate bsr AddFolderContents moveq #0,d0 ; sort from start move.l (A3),A0 move.w dataBounds+Rect.bottom(A0),d1 ; get number of files beq.s @doneBuilding ; don't sort if no files subq.w #1,d1 ; sort is zero based bsr.s SortSome @doneBuilding move.l (A3),A0 move.w dataBounds+Rect.bottom(A0),d3 ; get # files move.w d3,d0 bsr SetBounds ; calc new visible files move.w d3,d0 ; get # files beq.s @setMaxIndex subq.w #1,D0 ; zero based add.w D0,D0 ; *2 @setMaxIndex move.w D0,maxIndex(A0) ; set number of entries movem.l (SP)+,D2-D6/A2-A4 rts DebuggerSymbol AddFileListItems ;--------------------------------------------------- ; in: d0.w,d1.w = sort range ; a3 = list handle ; a4 = list cells data ; ; trashes: all data registers and A0,A1 ; SortSome movem.l a2-a4,-(sp) add.w d0,d0 ; sorting indexes which are two bytes wide move.w d0,-(sp) ; sort from add.w d1,d1 ; sorting indexes which are two bytes wide move.w d1,-(sp) ; sort to move.l a4,a0 _HLock ; lock cells data move.l (a4),a2 ; get ptr to cell data into a2 move.l a3,a0 _HLock ; lock list record move.l (a3),a0 lea cellArray(a0),a4 ; get ptr to offsets into a4 bsr OptQuickSort movem.l (sp)+,a2-a4 move.l a3,a0 _HUnLock ; unlock list record move.l a4,a0 _HUnLock ; unlock cells data rts DebuggerSymbol SortSome ;--------------------------------------------------- ; ; in: D1.L = file type ; out: D0.W = resource ID of icon to use ; D2.B = file is alias to container FileTypeToIconResourceID move.l a0,-(sp) move.l lAliasTypeMapH(a6),a0 ; try alias table st d2 ; asssume is alias to container bsr.s FileTypeLookUp ; returns with Z not set if it found match bne.s @done sf d2 move.l lFileTypeMapH(a6),a0 ; try generic stuff table bsr.s FileTypeLookUp ; returns with Z not set if it found match bne.s @done move.w #genericDocumentIconResource,d0 ; not in any table so default to document icon @done move.l (sp)+,a0 rts DebuggerSymbol FileTypeToIconResourceID ;--------------------------------------------------- ; ; in: D1.L = file type ; A0 = handle to mapping table ; out: D0.W = resource ID of icon to use ; trashed: A0 ; FileTypeLookUp move.l (a0),a0 ; dereference handle @next move.l (a0)+,d0 beq.s @done ; zero signals end of table, return with Z set cmp.l d0,d1 beq.s @found addq #4,a0 ; skip past wrong resource ID bra.s @next @found move.l (a0)+,d0 ; return correct resource ID, with Z not set swap d0 ; want high word @done rts DebuggerSymbol FileTypeLookUp ;--------------------------------------------------- ; AddFolderContents ; add the contents of the folder to the file list ; ; D6 offset of next record ; D5 current dirID ; D4 current file index ; D3 ForDiskDo ProcPtr ; A4 list cell data handle ; A3 list handle ; A2 ForDiskDo vcb ptr ; ; lIOCmd(a6).ioVRefNum needs to be set up ; ; trashes A0, A1, D0, D1 AddFolderContents moveq #1, d4 ; index beginning at first file @nextFile move.l a4,a0 ; lock down cell data cause ioNamePtr points into it _HLock lea lIOCmd(a6),a0 ; point to I/O command move.w d4,ioFDirIndex(a0) ; And use the given index. move.l (a4),a1 ; dereference the list lea FileEntry.feFile.text(A1,D6.W),A1 ; Point to name entry move.l a1,ioFileName(a0) move.l d5,ioDirID(a0) _GetCatInfo ; another file? bmi @exit ; br if not, we're done with this folder addq.w #1,d4 ; and bump index to get next file move.l ioDirID(a0), d0 ; get dirID of the folder cmp.l lTrashDir(a6), d0 ; is this the trash folder? beq.s @nextFile ; br if so, don't show it cmp.l lDeskDir(a6), d0 ; is this the desk folder? beq.s @nextFile ; br if so, don't show it move.l (a4),a1 ; dereference the list lea (a1,d6.w), a1 ; point at record in a1 clr.b FileEntry.feFile.dimmed(a1) ; default all entries to not dim move.w lTempDrive(a6),FileEntry.feDrive(a1) ; stuff in drive number move.w ioVRefNum(a0),FileEntry.feVRefNum(a1) ; stuff in vRefNum move.b ioFlAttrib(a0),FileEntry.feFLAttr(a1) ; stuff in the attribute clr.b FileEntry.feFLPriv(A1) ; assume can't get permissions move.w ioFlUsrWds+fdFlags(a0),FileEntry.feFndrFlags(a1) ; stuff in finder flags ; set up icon color for the file/folder bsr GetColorFromCatInfo move.w d0,FileEntry.feIconColor(a1) btst #ioDirFlg,ioFlAttrib(a0) ; is it a folder? bne.s @isFolder ; br if so, go do folder stuff @isFile move.l ioFlParID(a0),FileEntry.feParID(a1) ; stuff dirID move.l ioFlUsrWds+fdType(A0),d1 move.l d1,FileEntry.feTypeOrDirID(a1) ; stuff file type ; get icon for this file bsr FileTypeToIconResourceID ; d1 in, d0 out cmp.w #trashIconResource,d0 seq.b FileEntry.feFile.dimmed(a1) ; dim out aliases to trash cmp.w #genericDocumentIconResource,d0 ; is the a document? bne.s @doneStatChk btst #isStationeryBit,FileEntry.feFndrFlags(a1) ; and is stationery bit set? beq.s @doneStatChk move.w #genericStationeryIconResource,d0 ; if so, use stationery icon @doneStatChk tst.b d2 ; is this alias? beq @setIcon cmp.l #kApplicationAliasType,d1 ; 'adrp', if not an alias to an application beq.s @setIcon cmp.l #kContainerAliasType,d1 ; 'drop', if not an old alias to an application (or unknown container) beq.s @setIcon ; must be an alias to a folder/volume bset #ioDirFlg,FileEntry.feFLAttr(a1) ; pretend this is a folder bset #ioDirFlg,ioFlAttrib(a0) ; pretend this is a folder bra.s @setIcon ; folders may look different if lacking privileges @isFolder bclr #isAliasBit,FileEntry.feFndrFlags(a1) ; force alias flag of folders to false move.l ioDirID(a0),FileEntry.feTypeOrDirID(a1) ; stuff dirID of this folder move.l ioDrParID(a0),FileEntry.feParID(a1) ; stuff in the dirID of this folder's parent move.l lVolParms.vMAttrib(a6),D1 ; get volumes parms btst #bAccessCntl,D1 ; does it support access control? beq.s @getFolderIcon ; if not, don't get permissions byte move.b ioACUser(a0),FileEntry.feFLPriv(A1) ; stuff in the permissions tst.b lLocked(a6) ; is disk also locked? beq.s @getFolderIcon bset #bNoWrite,FileEntry.feFLPriv(A1) ; is locked, flip on noWrite perm bit ; set up mini-icon for folder @getFolderIcon move.w #genericLetterIconResource, d0 btst #isLetter,FileEntry.feFndrFlags(a1) ; is it letter? bne.s @setIcon ; br if so, got icon move.w #genericFolderIconResource,d0 ; assume it is a public folder move.b FileEntry.feFLPriv(A1),d1 ; get access privileges tst.b lDoingGetFile(a6) ; bne.s @getFile ; branch if getfile btst #bNoSearch, d1 ; normal folder if has search beq.s @setIcon ; br if has search and.b #mNoRead+mNoWrite,d1 ; also normal if R and W beq.s @setIcon ; br if R and W bra.s @grayFolder ; else, can't open this @getFile and.b #mNoSearch+mNoRead,d1 ; getfile folder needs R or S cmp.b #mNoSearch+mNoRead,d1 ; missing both? bne.s @setIcon ; no, branch to normal open dir @grayFolder move.w #privateFolderIconResource,d0 ; use different folder bset #bOpenable,FileEntry.feFLPriv(a1) ; mark unopenable @setIcon move.w d0,FileEntry.feIcon(a1) ; save mini-icon id tst.b lNoEjects(a6) beq.s @ejectIsSet bset #bNoEject,FileEntry.feFLPriv(A1) ; set this file can be eject if its volume can @ejectIsSet bsr GetIconSide ; gets iconLeft and Just into d0.w move.w d0,FileEntry.feIconLeft(A1) ;st FileEntry.feIconLeft(A1) ; icon on left ;move.b #teJustLeft,FileEntry.feJust(A1) ; left justify text btst #ioDirFlg,ioFlAttrib(a0) ; never dimmed for folders bne.s @doneDim tst.b lDoingGetFile(a6) ; dimmed files in putfile files bne.s @doneDim st FileEntry.feFile.dimmed(a1) @doneDim ; Set the font for the file's name from Finder Info bsr GetFilenameFont ; get filename's font move.w d0,FileEntry.feFile.script(a1) ; stuff script into record move.w d1,FileEntry.feFile.font(a1) ; stuff font into record move.w lSystemFontSize(A6),FileEntry.feFile.size(a1) ; stuff system size moveq #0, d0 ; assume no styling btst #isAliasBit,FileEntry.feFndrFlags(a1) ; see if it is an alias beq.s @setStyle ; get style to draw alias in from script manager subq #4, sp ; longint result move.w FileEntry.feFile.script(a1),-(sp) ; pass script move.w #smScriptAliasStyle,-(sp) ; get alias styling for this script _GetScript move.l (sp)+, d1 ; returns a long move.b d1,d0 ; put style byte in d0 lea lIOCmd(a6),a0 ; a0 could have been trashed by GetScript move.l (a4),a1 ; a1 could have been trashed by GetScript lea (a1,d6.w), a1 ; point at record in a1 @setStyle move.b d0,FileEntry.feFile.style(a1); stuff style into record btst #isInvisible,FileEntry.feFndrFlags(a1) ; is it invisible? beq.s @visible ; br if not, keep checking tst.b lDoingGetFile(a6) ; is this putfile? beq.s @goNextFile ; br if so, never show invisibles tst.w lNumTypes(A6) ; accepting everything? bge.s @goNextFile ; br if not, don't show invisibles @visible tst.b lDoingGetFile(a6) ; is this putfile? beq.s @addRecord ; br if so, always match (but dimmed) btst #ioDirFlg,ioFlAttrib(a0) ; is it a folder? bne.s @matched ; br if so, always add to list ; for get file, check list of file types and possible filter proc move.l ioFlUsrWds(A0),D0 ; get this file's type move.l lTypeList(A6),A1 ; get type list move.w lNumTypes(A6),D1 ; get # types in list bmi.s @matched ; skip if promiscuous match (-1 => match all) @nextType cmp.l (A1)+,D0 ; see if matches beq.s @matched ; it does, go on... subq #1,D1 ; try next type bne.s @nextType ; until exhausted the list of types <63 #b6-ngk-006> ;<63> bpl.s @nextType @goNextFile bra @nextFile ; no match in whole list @matched btst #ioDirFlg,ioFlAttrib(a0) ; is it a folder? beq.s @filter ; br if not, add to list tst.b lFilterFolders(a6) ; for custom get file, we call filter on folders beq.s @addRecord @filter bsr.s CallAppsFileFilter bne.s @goNextFile ; if returned true then don't add this record ; Passed through the filter, extend for the next entry @addRecord bsr AddNewRecord bpl.s @goNextFile ; and try the next file @exit rts DebuggerSymbol AddFolderContents ;------------------------------------ ; ; CallAppsFileFilter tst.l lFileFilter(A6) ; see if filter there beq.s @exit ; if not, then return as if filter returned false subq #2,SP ; room for boolean pea lIOCmd(A6) ; pass info tst.b lUseCallBack(a6) beq.s @noCallBackPtr move.l lCallBackPtr(a6),-(sp) @noCallBackPtr move.l lFileFilter(a6),A0 jsr (A0) ; call the file filter move.b (SP)+,d0 ; skip this file if true @exit rts DebuggerSymbol CallAppsFileFilter ;------------------------------------ ; ; in: a0 = catinforec ; out: d0 = color index GetColorFromCatInfo moveq #0,d0 move.b ioFlUsrWds+fdFlags+1(a0),d0 ; get Finder flags, color is bits 1-3 asr.w #1,d0 ; color bits are in bits 0-2 and.w #$07,d0 ; color offset rts DebuggerSymbol GetColorFromCatInfo ;------------------------------------ ; ; out: d0.w.low = text justification ; d0.w.high = icon on left boolean ; GetIconSide move.b forceIconsOnLeft,d0 ; check if PACK has been localized bne.s @default ; if not used default tst.w teSysJust ; if so, check sysJust beq.s @default ; if left-to-right, use default move.w #$00FF,d0 ; else icon on right, right justified bra.s @done @default move.w #$FF00,d0 ; default: icon on left, left justified @done rts ;----------------------------------------------------------------- ; GetFilenameFont - lookup the filename's font given a param block ; a0 (in) getcatinfo param block ; d1 (out) font id ; d0 (out) script id ; trashes d2, preserves a1 (added this comment, but no change in reg use <54>) GetFilenameFont movem.l a0-a1, -(sp) ; save regs; leaves a0 on top of stack ; If use of script tags is disabled, always set filename script = SystemScript <54> subq #4,sp ; space for GetEnvirons return <54> move.w #smGenFlags,-(sp) ; push GetEnvirons verb <54> _GetEnvirons ; <54> move.l (sp)+,d0 ; get Script Mgr flags <54> btst.l #smfNameTagEnab,d0 ; are script tags in use? <54> beq.s @setSysScript ; if not, assume system script <54> move.l (sp),a0 ; restore from stack <54> moveq #0, d0 ; clear out script move.b ioFlxFndrInfo+sfFndrScript(a0), d0 ; get the filename's script word bclr #7, d0 ; is script byte valid? bne.s @gotScript ; br if so, got script @setSysScript ; <54> move.w lSystemScript(a6), d0 ; default to system script @gotScript move d0, -(sp) ; save script so we can return it move lSystemFont(a6), d1 ; assume it is the system font cmp.w lSystemScript(a6), d0 ; same script as system? beq.s @exit ; br if so, got font subq #4, sp ; longint result move d0, -(sp) ; pass script move #smScriptSysFond, -(sp) ; get system font for this script _GetScript move.l (sp)+, d1 ; return font id @exit move (sp)+, d0 ; return script id movem.l (sp)+, a0-a1 ; restore regs rts DebuggerSymbol GetFilenameFont ;----------------------------------------------------------------- ; ForDiskDo - iterator to call a procedure for all online disks ; ; Register usage ; ; in: A0 = procedure to do for each disk ; ; trashes d3,a2 ; ForDiskDo MOVEM.L A1/D0,-(sp) ; save so we can use in invisible check <2> FM MOVE.L vcbQHdr+QHead,A2 ; first VCB start over <2> FM MOVE.L A0, D3 ; save procPtr @NextDisk MOVE.L A2, D0 BEQ.S @exit TST.W vcbDrvNum(A2) ; is it offline BNE.S @online ; br if not, use disk TST.W vcbDRefNum(A2) ; is it really online BPL.S @skipDisk ; br if now, skip this disk @online MOVE.L A2,A1 ; <2> <7> BSR VolumeIsInvisible ; <2> <7> See if this volume is invisible TST.W D0 ; <2> <7> If it is, donÕt call the procedure BNE.S @skipDisk ; <2> <7> for it MOVE vcbDrvNum(A2),lTempDrive(A6); setup drive for enumerate move.l a2,-(sp) MOVE.L D3, A0 ; get the proc ptr JSR (A0) ; and call the interator function move.l (sp)+,a2 BMI.S @exit @skipDisk MOVE.L QLink(A2), A2 ; get next disk BRA.S @NextDisk @exit MOVEM.L (sp)+,A1/D0 ; restore <2> FM rts DebuggerSymbol ForDiskDo ;----------------------------------------------------------------- ; AddSpecialFolder ; ; adds contents of trash or desktop folder to current list ; ; in: D5 = folder type ; A2 = VCB pointer ; ; D6 offset of next record ; ; A4 list data ptr ; A3 list handle ; ; trashes a0, AddSpecialFolder MOVE.W vcbVRefNum(A2), D0 LEA lIOCmd(a6),A0 ; point to I/O command MOVE.W D0,ioVRefNum(A0) ; remember we're listing this volume MOVE.L D5,-(SP) ; save folder type MOVE.L D5, D1 ; pass type in D1 BSR FindFolder ; lookup special folder in D0 MOVE.L D0, D5 ; got the folder? BEQ.S @exit ; br if not, skip enumeration move.w lTempDrive(A6),d1 ; get target drive # bsr NotEjectable ; not ejectable? move.b D0,lNoEjects(A6) ; record if it can't be ejected bsr AddFolderContents ; add contents of this special folder to list @exit MOVE.L (SP)+, D5 ; restore folder type moveq #0,d0 ; return no error rts DebuggerSymbol AddSpecialFolder ; AddDiskItem - Add a disk into the list ; ; Register usage ; D6 offset of next record ; D5 current dirID ; D4 current file index ; D3 ForDiskDo ProcPtr ; A4 list data ptr ; A3 alternate RTS stack ; A2 ForDiskDo vcb ptr ; trashes A1, D0, D1, A0, D2 AddDiskItem LEA lIOCmd(A6),A0 ; point to I/O command MOVE vcbVRefNum(A2),ioVRefNum(A0) ; lookup this volume MOVE #-1, ioFDirIndex(A0) ;lookup by dirID MOVEQ #fsRtDirID, D0 MOVE.L D0,ioDirID(A0) ; get root of volume MOVE.L (A4), A1 LEA FileEntry.feFile.text(A1,D6.W), A1 MOVE.L A1,ioFileName(A0) ; fill in name while we're at it _GetCatInfo ; find about this volume BMI @exit ; exit if volume gone already MOVE.L (A4),A1 ; dereference the list LEA (A1,D6.W), A1 move.w vcbVRefNum(a2),d0 ; d0 (in) vrefnum of disk move.l #kDesktopFolderType,d1 ; d1 (in) which special folder movem.l a0-a2,-(sp) bsr FindFolder ; d0 (out) dirID of folder, or 0 if there was an error move.l d0,d1 ; save in d1 move.w vcbVRefNum(a2),d0 ; d0 (in) vrefnum of disk bsr GetVolumeInfoPtr ; a0 (out) pointer to info tst.l d1 bne.s @gotDesk moveq #fsRtDirID,d1 ; if no desktop folder, use root = 2 @gotDesk move.l d1,PerVolumeInfo.desktopDir(a0) ; save off desktop dirID for this volume movem.l (sp)+,a0-a2 WITH FileEntry MOVE.L D1,feTypeOrDirID(A1) ; stuff in the dirID of desktop of volume MOVEQ #fsRtParID, D0 ; = 1 MOVE.L D0,feParID(A1) ; stuff in the dirID of the parent of root MOVE.W vcbDrvNum(A2),feDrive(A1) ; save drive number MOVE.W vcbVRefNum(a2),FileEntry.feVRefNum(a1) ; stuff in vRefNum MOVE.B ioFlAttrib(a0),feFLAttr(A1) ; stuff in the attribute CLR.B feFLPriv(A1) ; assume can't get permissions MOVE.W vcbDrvNum(A2), D1 ; get drive number BSR NotEjectable ; returns with d0=0 if ejectable TST.B d0 BEQ.S @1 BSET #bNoEject,FileEntry.feFLPriv(a1) ; remember if ejectable @1 MOVE.W ioFlUsrWds+fdFlags(a0),feFndrFlags(A1) ; stuff in finder flags MOVE.W ioVRefNum(a0),d0 ; pass vRefNum to GetVolIcon BSR GetVolIcon ; icon depends on volume type MOVE.W D0,feIcon(A1) ; stuff icon BSR GetColorFromCatInfo MOVE.W d0,feIconColor(A1) ; save icon color bsr GetIconSide ; gets iconLeft and Just into d0.w move.w d0,FileEntry.feIconLeft(A1) ;ST feIconLeft(A1) ; icon on left ;MOVE.B #teJustLeft,feJust(A1) ; left justify text BSR GetFilenameFont ; lookup filename's font MOVE.W D0,feFile.script(A1) ; save name's script MOVE.W D1,feFile.font(A1) ; save name's font MOVE.W lSystemFontSize(A6),feFile.size(A1) ; volumes use system size CLR.B feFile.dimmed(A1) ; volumes are never dimmed CLR.B feFile.style(A1) ; normal style ENDWITH BSR.S AddNewRecord ; add the new record onto list and indices @exit rts DebuggerSymbol AddDiskItem ;----------------------------------------------------------------- ; ; Extend the data and indices handle and update the offset to the current record ; ; Register usage ; A3 list record handle ; A4 list cell handle ; D6 offset into cell data of current record ; trashes: D0, D1, A0 AddNewRecord ; stuff index into index array moveq #0,d1 move.l (a3),a0 move.w dataBounds+Rect.bottom(a0),d1 ; current items in list ;subq #1,d1 add.l d1,d1 ; each is two bytes move.l A3,A0 ; get the list record size _GetHandleSize sub.l #sizeList,D0 ; get indices size cmp.l d0,d1 blt.s @stuffIndex add.l #sizeList+64,d0 ; grow index by 32 entries _SetHandleSize ; make more room bne.s @errExit @stuffIndex move.l (a3),a0 move.w d6,cellArray(a0,d1.w) ; insert new index addq.w #1,dataBounds+Rect.bottom(a0) ; advance offset (d6) into cell data moveq #FileEntry.feFile.text+1+2, D1 ; static size + length byte + round up move.l (A4), A0 ; deref data handle add.b FileEntry.feFile.text(A0,D6.w),D1; add in name length bclr #0, D1 ; evenize add.w d1,d6 ; size of current record into D1 ; make sure is room for next record move.l A4,A0 ; get the list cell data size _GetHandleSize move.l d0,d1 sub.l d6,d1 ; compute room left in cell data cmp.l #FileEntry.size,d1 ; is there room for next record? bge.s @okExit ; if so, go on move.l d0,d1 _HUnLock ; it might have been locked move.w #1024,d0 add.l d1,d0 ; do long add for SetHandleSize tst.w d0 ; test as if word, high bit of index is flag for selection bmi.s @errExit ; so can only go up to $7FFF _SetHandleSize ; add 1K chunk beq.s @okExit @errExit moveq #-1, D0 @okExit rts DebuggerSymbol AddNewRecord ;-------------------------------------------------------------------- ; ; QuickSort( l, r: INTEGER ); ; ; ; ; A4 dereferenced offsets array into FileEntry list ; A2 dereferenced FileEntry list ; ; trashes all data regs and A0-A1 except D6 and D7 ; LeftIndex Equ 6+4 RightIndex Equ 4+4 QuickSort move.w D6,-(SP) ; save reg, only word, to save recursed stack space move.w D7,-(SP) ; save reg move.w LeftIndex(SP),D6 ; D6 is left pointer move.w RightIndex(SP),D7 ; D7 is right pointer move.w d7,d5 sub.w d6,d5 ble.s @done ; nothing to sort cmp.w #2,d5 bne.s @normalCase ; special case only two items in list to sort move.w 0(A4,D6.W),D3 ; get index of left lea FileEntry.feFile(A2,D3.W),A0 ; point to left string move.w 0(A4,D7.W),D4 ; get index of right lea FileEntry.feFile(A2,D4.W),A1 ; point to right string bsr CompStyledString ; cc's set CMP left,right blt.s @done ; if already sorted then done move.w D4,(A4,D6.W) ; else swap entries move.w D3,(A4,D7.W) bra.s @done @normalCase ; do normal QuickSort bsr.s Partition ; takes d6,d7 returns d5 ; sort left partition (l, i-1) move.w d5,-(sp) ; save d5 move.w d6,-(sp) subq.w #2,d5 move.w d5,-(sp) bsr.s QuickSort move.w (sp)+,d5 ; restore d5 ; sort right partition (i+1, r) addq.w #2,d5 move.w d5,-(sp) move.w d7,-(sp) bsr.s QuickSort @done move.w (SP)+,D7 ; restore reg move.w (SP)+,D6 ; restore reg move.l (SP)+,(SP) ; pop parameters rts DebuggerSymbol QuickSort ; ; ; This partition uses the middle element as the pivot point. ; This could be improved by spending some cycles to find a ; better pivot, such as "median of three" ; Partition movem.l D6-D7,-(SP) ; save regs ; c := (r+l)/2 move.w d7,d5 add.w d6,d5 lsr.w #1,d5 and.w #$FFFE,d5 ; pick midpoint as pivot ; exchange A[c] <-> A[r] move.w 0(A4,D5.W),D3 ; move pivot to end move.w (A4,D7.W),(A4,D5.W) ; so we can use traditionaly QS move.w D3,(A4,D7.W) ; x := A[r] lea FileEntry.feFile(A2,D3.W),A0 ; point to pivot entry ; i := l - 1; subq.w #2,d6 ; repeat ; repeat i:= i+1 until A[j] ³ x @nextLeft addq.w #2,d6 move.w 0(A4,D6.W),D3 ; get testee offset = left lea FileEntry.feFile(A2,D3.W),A1 ; point to testee name bsr.s CompStyledString ; cc's set CMP testee,pivot bgt.s @nextLeft ; continue if still less than or equal to pivot ; repeat j:= j-1 until A[j] ² x @nextRight subq.w #2,d7 ble.s @exitRepeat ; bounds check on j <55.3, #82542> move.w 0(A4,D7.W),D3 ; get testee offset = left lea FileEntry.feFile(A2,D3.W),A1 ; point to testee name bsr.s CompStyledString ; cc's set CMP testee,pivot blt.s @nextRight ; continue if still greater than pivot ; if i ³ j then leave cmp.w d6,d7 ble.s @exitRepeat ; exchange A[i] <-> A[j] move.w 0(A4,D6.W),D3 ; do swap of indices move.w (A4,D7.W),(A4,D6.W) move.w D3,(A4,D7.W) ; until false bra.s @nextLeft @exitRepeat ; return i move.w d6,d5 movem.l (SP)+,D6-D7 ; restore regs ; exchange A[r] <-> A[i] move.w 0(A4,D5.W),D3 ; this swap pivot value into partition split move.w (A4,D7.W),(A4,D5.W) ; it partitions the range into 3 parts move.w D3,(A4,D7.W) ; (l,i-1),(i,i),(i+1,r) rts DebuggerSymbol Partition ;-------------------------------------------------------------------- ; ; CompStyledString ; ; input: A0 - Styled string, ; A1 - Styled string, ; ouptut: flags set as if CMP (A1),(A0) ; ; trashes d0 ; CompStyledString ; first check if two strings are even in the same script cmp.l a0,a1 ; optimize when strings are obviously the same beq.s @done movem.l a0-a1,-(sp) ; save off a0, a1 move.w StyledString.script(a0),d0 ; get first script id cmp.w StyledString.script(a1),d0 ; compare script numbers first beq.s @testString ; same script so compare the text ; they are not in same script, so just use script order subq #2,sp ; room for result move.w d0,-(sp) move.w StyledString.script(a1),-(sp) _IUScriptOrder ; get order for scripts tst.w (sp)+ ; set CC's and we are done bra.s @restore ; check if strings are byte for byte the same @testString lea StyledString.text(a0),a0 ; aPtr lea StyledString.text(a1),a1 ; bPtr move.b (a0),d0 ; length @nextByte cmp.b (a0)+,(a1)+ dbne d0,@nextByte beq.s @restore ; strings are exactly the same bytes, so done movem.l (sp),a0-a1 ; retrieve a0,a1 from stack ; since they are not exactly the same, MagPString can return an ordering @inequal subq #2,sp ; room for result pea StyledString.text+1(a0) ; aPtr pea StyledString.text+1(a1) ; bPtr moveq #0,d0 move.b StyledString.text(a0),d0 move.w d0,-(sp) ; aLen move.b StyledString.text(a1),d0 move.w d0,-(sp) ; bLen move.w StyledString.script(a0),d0 ; for what script do we want itl2? cmp.w lCacheScrCode(a6),d0 ; have we already cached that? beq.s @gotItl move.w d0,lCacheScrCode(a6) ; change cache to this script subq #4,sp move.w #2,-(sp) ; specify type of 'itlx' resource move.w d0,-(sp) ; specify the script code move.w #-1,-(sp) ; specify system, not app, sorting _IUGetScriptItl ; get itl2 handle into cache move.l (sp)+,lCacheScrHandle(a6) @gotItl move.l lCacheScrHandle(a6),-(sp) ; itl2 handle _IUMagPString ; sorting comparison tst.w (sp)+ ; set CC's and we are done @restore movem.l (sp)+,a0-a1 ; restore a0, a1 @done rts DebuggerSymbol CompStyledString ;-------------------------------------------------------------------- ; OptQuickSort(l, r: INTEGER); ; ; Walks list and checks if list is already sorted ; before calling QuickSort ; ; trashes all data regs and A0-A1 except D6 and D7 ; OptQuickSort tst.b lTryShortSort(a6) ; should we check if already sorted before calling QS? beq.s @doQS ; if not, just QuickSort it movem.l D6-D7,-(SP) ; save regs move.w 6+8(SP),D6 ; D6 is left pointer move.w 4+8(SP),D7 ; D7 is right pointer @next cmp.w d7,d6 bhs.s @sorted move.w 0(A4,D6.W),D3 ; get index of left lea FileEntry.feFile(A2,D3.W),A0 ; point to left string addq.w #2,d6 move.w 0(A4,D6.W),D4 ; get index of right lea FileEntry.feFile(A2,D4.W),A1 ; point to right string bsr CompStyledString ; cc's set CMP left,right ble.s @next movem.l (SP)+,D6-D7 ; restore regs @doQS bra QuickSort @sorted movem.l (SP)+,D6-D7 ; restore regs move.l (SP)+,(SP) ; pop parameters @done rts DebuggerSymbol OptQuickSort ;-------------------------------------------------------------------- ; ; PROCEDURE RevealByName; ; A0 name of item to be selected and scrolled to ; D0 script of name RevealByName cmp.w #smSystemScript,d0 bne.s @realScript move.w lSystemScript(a6),d0 @realScript move.w D0, lTypeSelect.tsrScript(A6) ; uses script lea lTypeSelect.tsrKeyStrokes(A6),A1; point to the typeahead buffer moveq #1, D0 ; string size is 1 for length byte add.b (A0),D0 ; plus length of string _BlockMove ; copy default name into typeahead buffer SelectTyped move.l lFileListHandle(a6),a0 move.l (a0),a0 move.w dataBounds+Rect.bottom(a0),d0 sub.w dataBounds+Rect.top(a0),d0 beq.s @done subq #2,sp ; result pea lTypeSelect(a6) ; tsr move.w d0,-(sp) ; listSize move.w #tsNormalSelectMode,-(sp) ; selectMode pea MyGetStringProc ; getStringProc move.l lFileListHandle(a6),-(sp) ; yourDataPtr is listrec handle _TypeSelectFindItem move.w (sp)+,d3 subq #1,d3 ; convert to zero based st d2 ; OK to center name in file list bsr.s SelectAndReveal ; select cell in d3 @done rts DebuggerSymbol RevealByName ;-------------------------------------------------------------------- ; ; FUNCTION MyGetStringProc(item: INTEGER; ; VAR itemsScript: ScriptCode; ; VAR itemsStringPtr: StringPtr; ; yourDataPtr: Ptr): BOOLEAN; ; MyGetStringProc ; get list handle move.l 4(sp),a0 ; 4 = yourDataPtr is listrec handle move.l (a0),a0 ; get offset of 'item' in cells handle move.w 16(sp),d0 ; 16 = item subq.w #1,d0 ; convert first from 1 add.w dataBounds+Rect.top(a0),d0 ; to top add.w d0,d0 ; each index is two bytes wide move.w cellArray(a0,d0.w),d0 ; get offset into cell data and.w #$7FFF,d0 ; strip off selected bit ; get address of 'item' FileEntry move.l cells(a0),a0 move.l (a0),a0 lea (a0,d0.w),a1 ; retrieve itemsScript move.l 12(sp),a0 ; 12 = itemsScript move.w FileEntry.feFile.script(a1),(a0) ; retrieve itemsStringPtr move.l 8(sp),a0 ; 8 = itemsStringPtr clr.l (a0) ; return NIL by default tst.b FileEntry.feFile.dimmed(a1) ; is it dimmed bne.s @1 ; if so return NIL lea FileEntry.feFile.text(a1),a1 move.l a1,(a0) ; else return pointer @1 move.l (sp)+,a0 ; return add #14,sp move.b #1,(sp) ; always return true jmp (a0) DebuggerSymbol MyGetStringProc ;-------------------------------------------------------------------- ; ; SelectAndReveal - select a new cell and scroll it into view ; in: d3.w cell index ; d2.b boolean, OK to center selection if scrolling is needed. ; ; trashed: d0,d1,d2,d3,a0,a1,a2 SelectAndReveal move.w d4,-(sp) ; save d4 move.b d2,d4 ; d4 now contains center boolean tst.b lListIsActive(a6) ; is the list the active item? bne.s @canShow ; if not, just remember the index for when list becomes active moveq #0,d0 ; if we want to select item $1234 in list (zero base) move.w d3,d0 ; swap d0 ; then save off $12340000 (row 1234, column 0 ) move.l d0,lLastSel(a6) ; bra @doneScroll @canShow move.l lFileListHandle(a6),a2 ; a2 = list handle bsr GetSel ; get selected cell into d0 bmi.s @noDeselect ; nothing currently selected, so nothing to deselect swap d0 ; get row number in low word cmp.w d3,d0 ; are we trying to change to the current selection? beq.s @doneSelect ; if so, don't deselect and select, to avoid a flash swap d0 ; restore d0 sf -(sp) ; un selected cell move.l d0,-(sp) ; push the cell to deselect move.l a2,-(sp) _LSetSelect ; select the chosen cell @noDeselect move.w d3,d0 ; get cell number swap d0 ; put it up in vertical clr.w d0 ; horizontal is always 0 move.l d0,lLastSel(a6) ; remember last selected cell st -(sp) ; selected cell move.l d0,-(sp) ; push the cell to select move.l a2,-(sp) _LSetSelect ; select the chosen cell @doneSelect move.l (a2),a1 ; list ptr move.w visible+top(a1),d1 ; the top visible move.w visible+bottom(a1),d2 ; below the bottom visible move.w d3,d0 ; check and see how far we should scroll sub.w d1,d0 ; do we need to scroll down (above the top)? blt.s @scroll ; => not visible, scroll move.w d3,d0 ; check and see how far we should scroll addq.w #1,d0 ; remember, we probably scroll one less than you think sub.w d2,d0 ; do we need to scroll up (below the bottom)? ble.s @doneScroll ; => visible, no need to scroll @scroll ; now we have decided that we need to scroll, we must decide whether ; to scroll the minimum necessary distance or whether to attempt to center ; the selection in the visible area by checking the parameter on the stack tst.b d4 ; can we center? beq.s @doScroll ; if not, then just scroll minimal amout move.w d3,d0 ; check and see how far we should scroll add.w d2,d1 ; find the center cell by averaging top and bottom subq.w #1,d1 ; round so more items in list are below than above asr.w #1,d1 ; we now have the center of the visible cells sub.w d1,d0 ; calculate the amount to scroll add.w d0,d2 ; do a bounds check to see if we will scroll too far sub.w dataBounds+bottom(a1),d2; will new bottom be out of bounds? and how much ble.s @doScroll ; if in bounds, go on sub.w d2,d0 ; don't scroll so much, to stay in bounds @doScroll tst.b lDontDrawList(a6) beq.s @scrollit ; display is blank, LScroll would only draw some cells, instead change visible rect add.w d0,visible+top(a1) ; change visible rect add.w d0,visible+bottom(a1) bra.s @doneScroll ; then draw whole list at once @scrollit clr.w -(sp) ; no horizontal scrolling move.w d0,-(sp) ; scroll this far vertically move.l a2,-(sp) ; list handle _LScroll @doneScroll tst.b lDontDrawList(a6) beq.s @checkVolume ; display is blank, need to draw whole list sf lDontDrawList(a6) ; turn drawing back on bsr.s DrawFileList ; draw whole list @checkVolume ; now see if we are at desktop and need to change volume icon tst.b lAtDesktop(a6) ble.s @done ; only do check if at desktop bsr GetSel bmi.s @done ; safety check ; we need to switch "current volume" move.w FileEntry.feVRefNum(a0),d0 bsr SetVolumeIcon @done move.w (sp)+,d4 rts DebuggerSymbol SelectAndReveal ;-------------------------------------------------------------------- ; ; PROCEDURE EraseFileList; ; EraseFileList moveq #sfItemFileListUser,d0 bsr VirtualToRealItem bsr GetIt ; get list box into lBox(A6) move.l lFileListHandle(a6),a0 ; get the list handle move.l (a0),a0 ; get pointer pea rView(a0) ; push the viewrect _EraseRect ; erase old list rts DebuggerSymbol EraseFileList ;-------------------------------------------------------------------- ; ; PROCEDURE DrawFileList; ; ; Draws the file list. ; DrawFileList _PenNormal ; want pen that is 1,1 <55.2, #79895> pea lNRect(a6) _FrameRect tst.b lDontDrawList(a6) bne.s @done move.l visRgn(a3), -(sp) ; pass visible region move.l lFileListHandle(a6),-(sp) ; point at the list _LUpdate ; validate the list and scrollbars since we've just drawn 'em move.l lFileListHandle(a6),a0 ; get the list handle move.l (a0),a0 ; get pointer pea rView(a0) ; push the viewrect _ValidRect ; get rid of list update from treemenu @done rts DebuggerSymbol DrawFileList ;-------------------------------------------------------------------- ; ; This gets called through the eject notify hook ; Notify( drive, caller: INTEGER ): BOOLEAN; ; ejectHit MOVE.L (SP)+,A1 MOVE (SP)+,D0 ; see who called MOVE (SP)+,D1 ; get drive ST (SP) ; return true (don't ever eject disk) SUBQ #1,D0 BNE.S @0 ; => disk switch called us MOVE.W D1,sfSaveDisk ; save disk to eject NEG.W sfSaveDisk ; make negative (is normally positive) SF (SP) ; return false @0 JMP (A1) ; adios DebuggerSymbol ejectHit ;------------------------------------------------------------ ; ; SetUpButtons ; ; Sets the state of all buttons ; SetUpButtons bsr.s SetUpDeskTopButton bsr.s SetUpEjectButton bsr SetUpNewFolderButton bsr SetUpOpenButton @done rts DebuggerSymbol SetUpButtons ;------------------------------------------------------------ ; ; SetUpDeskTopButton ; ; disable desktop button if at desktop ; SetUpDeskTopButton tst.b lAtDesktop(A6) ; at the desktop? sgt D3 ; set if so, dim it move.l lMainDesktop(a6),a0 bsr DimButton ; set dim state rts DebuggerSymbol SetUpDeskTopButton ;------------------------------------------------------------ ; ; SetUpEjectButton ; ; enable eject if current disk ejectable ; or desktop chosen and ejectable disk selected ; SetUpEjectButton TST.B lAtDesktop(A6) ; at the desktop? BLE.S @notDesk ; br if not ST D3 ; assume dimmed BSR GetSel ; get selection in A0 BMI.S @dimEject ; br if no selection btst #bNoEject,FileEntry.feFLPriv(a0) sne d3 BRA.S @dimEject @notDesk BSR CountDIPs ; find # disks TST.W D3 SEQ D3 OR.B lNoEjects(A6),D3 ; if media says no, don't allow @dimEject move.l lMainEject(a6),a0 bsr DimButton rts DebuggerSymbol SetUpEjectButton ;------------------------------------------------------------ ; ; SetUpNewFolderButton ; ; disable desktop button if at desktop ; SetUpNewFolderButton tst.b lDoingGetFile(a6) bne.s @done move.b lPriv(A6),d0 ; get privs and.b #mNoSearch+mNoWrite,d0 ; need write and search sne d3 ; d3 = FF iff do not have (write and search) cmp.w #sigWord,lSigWord(a6) ; is this an MFS disk? <41 ngk 17Sept90> bne.s @1 ; <41 ngk 17Sept90> st d3 ; if so, disable new folder button <41 ngk 17Sept90> @1 move.l lMainNewFolder(a6),d0 ; see if there is a new folder button beq.s @done move.l d0,a0 bsr DimButton ; dim/enable based on d3 @done rts DebuggerSymbol SetUpNewFolderButton ;------------------------------------------------------------------------------ ; ; SetUpOpenButton ; ; The following table tries to organize the possible states of the system ; and how to set up the open button ; ; ; ; Put/Get ActiveItem Select CurPriv SelPriv TEempty DiskIn Title Enabled ; ------- ---------- ------ ------- ------- ------- ------ |---- ------- ; ; Get FileList file xxx n.a. n.a. yes |alt yes ; Get FileList volume n.a. xxx n.a. yes |open yes ; Get FileList folder n.a. rd/src n.a. yes |open yes ; Get FileList folder n.a. ~rd~src n.a. yes |open no ; Get FileList none n.a. n.a. n.a. yes |alt no ; Get FileList dimmed n.a. n.a. n.a. yes |alt no ; ; Put FileList vl/fldr n.a. wr/src n.a. yes |open yes ; Put FileList vl/fldr n.a. ~wr~src n.a. yes |open no ; Put FileList file n.a. n.a. n.a. yes |??? ??? ; Put FileList none wr/src n.a. no yes |alt yes ; Put FileList none wr/src n.a. yes yes |alt no ; Put FileList none ~wr~src n.a. n.a. yes |alt no ; Put FileList dimmed wr/src n.a. no yes |alt yes ; Put FileList dimmed wr/src n.a. yes yes |alt no ; Put FileList dimmed ~wr~src n.a. n.a. yes |alt no ; Put TE name n.a. wr/src n.a. no yes |alt yes ; Put TE name n.a. wr/src n.a. yes yes |alt no ; ; ; This boils down to the following equations: ; ; title is open := (FileList is target) ; & (volume or folder is selected) ; & (selection is not dimmed) ; ; button is enabled := (title = open) & ; ( (selection has search priv) ; & ( (putFile & (selection has write priv)) ; | (getFile & (selection has read priv)) ) ) | ; ( (title = alt) & ; ( (getFile & (is selection) & (is not dimmed) ) ; | (putFile & (~TEempty) & (cur priv has write and search) )) ) ; SetUpOpenButton ; first figure out whether the open button should say "open" or "save" bsr GetSel ; get file entry into A0 move.l a0,a2 ; save in a2 for later use bmi.s @notOpen ; branch if no selection tst.b lListIsActive(a6) ; is File List the active item? beq.s @notOpen ; branch if not ; moveq #sfItemFileListUser,d0 ; bsr VirtualToRealItem ; cmp.w lActiveDITLitem(a6),d0 ; is File List the active item? ; bne.s @notOpen ; branch if not btst #ioDirFlg,FileEntry.feFlAttr(a2) ; is it a folder or volume? beq.s @notOpen ; branch if not tst.b FileEntry.feFile.dimmed(a2) ; is it dimmed? bne.s @notOpen ; branch if not @isOpen tst.b lOpenState(a6) beq.s @doneTitle ; button already correct lea lOpenName(a6),a0 clr.b lOpenState(a6) moveq #2,d0 ; control max for open button for balloon help bra.s @changeTitle @notOpen tst.b lOpenState(a6) bne.s @doneTitle ; button already correct lea lOpenAltName(a6),a0 st lOpenState(a6) moveq #1,d0 ; control max for alt-open button for balloon help @changeTitle tst.b lOpenAltExists(a6) ; is there really an alternate name? beq.s @doneTitle move.l lMainOpen(a6),a1 ; lMainOpen can not be NIL if lOpenAltExists is true move.l a1,-(sp) ; the open button control move.l (a1),a1 move.w d0,contrlMax(a1) ; change control max value move.l a0,-(sp) ; string to set title to _SetCTitle pea lOpenRect(a6) ; SetCTitle has side effect of inval'ing control rect _ValidRect ; so undo that side effect @doneTitle ; now figure out whether to dim or enable the open button tst.b lOpenState(a6) bne.s @altShown @openShown move.l a2,a0 ; at this point we know there is a selection btst #bOpenable,FileEntry.feFLPriv(a0) ; can selection be opened? bne.s @disable ; branch if not bra.s @enable @altShown tst.b lDoingGetFile(a6) ; getFile always has altopen enabled bne.s @altGet ; branch if it is ; test if TE is empty tst.b lNewReply(a6) ; new call ? beq.s @2 ; branch around if not tst.b StandardFileReply.sfFile+FSSpec.name(a4) ; test length of typed name beq.s @disable bra.s @3 @2 tst.b SFReply.fName(a4) ; test length of typed name beq.s @disable ; test privledges in current folder @3 move.b lPriv(A6),d0 ; get privs btst #bNoWrite,d0 ; need read and write to save bne.s @disable btst #bNoRead,d0 bne.s @disable bra.s @enable @altGet moveq #-1,d0 cmp.l d0,a2 ; see if there is a selection beq.s @disable ; dim alt if no selection tst.b FileEntry.feFile.dimmed(a2) ; see if selection is dimmed bne.s @disable ; dim alt if selection is dimmed @enable moveq #0,d3 bra.s @setOpen @disable moveq #-1,d3 @setOpen move.l lMainOpen(a6),d0 beq.s @doneSetUp ; if control handle is NIL, then don't try to dim move.l d0,a0 bsr.s DimButton ; set highlight state @doneSetUp rts DebuggerSymbol SetUpOpenButton ;------------------------------------------------------------ ; a0 = handle to button control record ; if D3 is 0 then enable button in D0 ; if D3 is FF then disable button in D0 ; DimButton move.l a0,-(sp) ; pass the button move.w d3,-(sp) clr.b (sp) ; clear high part _HiliteControl @done rts DebuggerSymbol DimButton ;------------------------------------------------------------------- ; ; FillReplyRecord. Fill the return record. ; ; original reply records: ; getFile ; If no selections fName = 0 and fType = 0. ; If a file is selected, fName <> 0, and contains the file name. ; If a folder is selected, fName = 0 and fType <> 0, and contains the DirID. ; putFIle ; fName = whatever is in TE box ; ; new reply records: ; getFile: ; If no selection, sfFile.fileName = 0 and sfType = 0. ; If a file is selected, sfFile is correct FileSpec, sfType is file type ; If a folder or volume is selected, sfFile is correct FileSpec ; putFile: ; sfFile.vRefnum, sfFile+FSSpec.parID is current volume/folder in view ; sfFile.fileName = whatever is in TE box ; sfType = 0 ; ; in: a4 = reply record ; trashes: d0,d1,d2,a0,a1 ; FillReplyRecord tst.b lNewReply(a6) ; new call ? beq @oldReply ; branch around if not @newRply moveq #0,d0 move.w d0,StandardFileReply.sfGood(a4) ; clear good and replacing move.b d0,StandardFileReply.sfFile+FSSpec.name(a4) ; remains 0 if no file selected move.l d0,StandardFileReply.sfType(a4) ; default to 0 move.w d0,StandardFileReply.sfFlags(a4) ; zero out flags move.b d0,StandardFileReply.sfIsFolder(a4) ; assume not a folder move.b d0,StandardFileReply.sfIsVolume(a4) ; assume not a volume move.l d0,StandardFileReply.sfReserved1(a4) ; always 0 move.w d0,StandardFileReply.sfReserved2(a4) ; always 0 move.w lVolRefNum(a6),StandardFileReply.sfFile+FSSpec.vRefNum(a4) ; default vRefNum move.l lCurDir(a6),StandardFileReply.sfFile+FSSpec.parID(a4) ; default parID tst.b lAtDesktop(a6) ; if at desktop, lCurDir is not a reliable default ble.s @notDesk move.w lDisplyedVolRef(a6),d0 ; get the volume to save on move.w d0,StandardFileReply.sfFile+FSSpec.vRefNum(a4) ; get desktop for this vRefNum bsr GetVolumeInfoPtr ; a0 (out) pointer to info move.l PerVolumeInfo.desktopDir(a0),StandardFileReply.sfFile+FSSpec.parID(a4) ; desktop dirID @notDesk bsr GetSel ; get selection into A0 bmi.s @noSelection ; if none then done move.w FileEntry.feVRefNum(a0),StandardFileReply.sfFile+FSSpec.vRefNum(a4) ; better vRefNum move.l FileEntry.feParID(a0),StandardFileReply.sfFile+FSSpec.parID(a4) ; better parID @noSelection tst.b lDoingGetFile(a6) beq.s @putFill @getFill move.l a0,d0 ; if a0=-1 then no selection bmi @done tst.b FileEntry.feFile.dimmed(a0) ; don't fill out rest if item is dimmed (trash) bne @done move.w FileEntry.feFile.script(a0),StandardFileReply.sfScript(a4) ; get script move.w FileEntry.feFndrFlags(a0),StandardFileReply.sfFlags(a4) ; get flags btst #isAliasBit,FileEntry.feFndrFlags(a0) ; is it an alias? bne.s @isFile ; then it must be a file (even though folder bit may be set) btst #ioDirFlg,FileEntry.feFlAttr(a0) ; is it a folder? beq.s @isFile @isFolder moveq #fsRtParID,d1 ; = 1 cmp.l FileEntry.feParID(a0),d1 ; is it a volume? sne StandardFileReply.sfIsFolder(a4) ; seq StandardFileReply.sfIsVolume(a4) ; bra.s @getFillName @isFile move.l FileEntry.feTypeOrDirID(a0),StandardFileReply.sfType(A4) ; get file type @getFillName lea FileEntry.feFile.text(a0),a0 ; a0 is source for blockmove lea StandardFileReply.sfFile+FSSpec.name(a4),a1 ; a1 is destination for blockmove bra @fillName @putFill tst.b lAtDesktop(a6) ; if we are not at desktop then vol/dir is OK ble.s @dirOK move.w lDisplyedVolRef(a6),d0 ; d0 (in) vrefnum of disk move.w d0,StandardFileReply.sfFile+FSSpec.vRefNum(a4) ; better vRefNum bsr GetVolumeInfoPtr ; a0 (out) pointer to info move.l PerVolumeInfo.desktopDir(a0),StandardFileReply.sfFile+FSSpec.parID(a4) ; better dirID @dirOK bsr GetKeyScript move.w d0,StandardFileReply.sfScript(a4) ; get script out of low word ; ### is this right? can keyboard script change after typing but before save hit? moveq #sfItemFileNameTextEdit,d0 ; get the edit text item bsr VirtualToRealItem bsr GetIt move.l lItem(a6),-(sp) ; push item handle pea lString(a6) ; place to put name _GetIText lea lString(a6),a0 ; a0 is source for blockmove lea StandardFileReply.sfFile+FSSpec.name(a4),a1 ; a1 is destination for blockmove bra.s @fillName @oldReply clr.w SFReply.good(a4) ; clear good and replacing clr.b SFReply.fName(a4) ; remains 0 if no file selected clr.l SFReply.fType(a4) ; remains 0 if no selection tst.b lDoingGetFile(a6) beq.s @oldPutFill @oldGetFill bsr GetSel ; get selection into A0 bmi.s @done ; if none then done move.w FileEntry.feVRefNum(a0),SFReply.vRefNum(a4) ; return volume (new for 7.0) move.l FileEntry.feTypeOrDirID(a0),SFReply.fType(A4) ; return type or DirID btst #isAliasBit,FileEntry.feFndrFlags(a0) ; is it an alias? bne.s @oldName ; => yes, so just get name btst #ioDirFlg,FileEntry.feFlAttr(a0) ; is it a folder? beq.s @oldName ; => no, so fill in file name moveq #fsRtParID,d0 ; = 1 cmp.l FileEntry.feParID(a0),d0 ; is it a volume? bne.s @done ; if not, we're done moveq #fsRtDirID,d0 ; = 2 move.l d0,SFReply.fType(A4) ; it is a volume use 2, instead of desktop folder bra.s @done @oldName lea FileEntry.feFile.text(a0),a0 ; point to name lea SFReply.fName(a4),a1 ; a1 is destination for blockmove bra.s @fillName @oldPutFill moveq #sfItemFileNameTextEdit,d0 ; get the edit text item bsr VirtualToRealItem bsr GetIt move.l lItem(a6),-(sp) ; push item handle pea lString(a6) ; place to put name _GetIText lea lString(a6),a0 ; a0 is source for blockmove lea SFReply.fName(a4),a1; a1 is destination for blockmove @fillName moveq #31,d1 ; be conservative with make filename length moveq #0,d0 move.b (a0),d0 ; get string length cmp.l d1,d0 ; less than max? ble.s @3 move.b d1,d0 ; no, trim to 31 move.b d0,(a0) ; stuff length @3 addq.b #1,d0 ; allow for length byte itself _BlockMove ; fill filename of reply @done rts DebuggerSymbol FillReplyRecord ;------------------------------------------------------------------- ; ; Set up the list. lBox(a6) is the bounding rect for the list. ; SetUpList sub.l #16,sp ; a temporary rectangle lea lNRect(a6),a0 move.l (a0),(sp) move.l 4(a0),4(sp) ; copy the original file rect sub.w #15,6(sp) ; lose 15 pixels for scroll bar move.l sp,-(sp) ; point at temprect move.l OneOne,-(sp) ; shrink 1, 1 for listmgr _InsetRect lea 8(sp), a0 clr.l (a0)+ clr.l (a0)+ move.l sp,a0 ; a0 points at temprect for lmgr subq.l #4,sp ; space for list handle move.l a0,-(sp) ; pass at rView addq #8, a0 move.l a0, -(sp) ; pass data bounds clr.l -(sp) ; empty size move.w #-4000,-(sp) ; use default proc move.l a3,-(sp) ; pass window pointer to ernie st -(sp) ; draw it sf -(sp) ; no grow sf -(sp) ; no horizontal scroll st -(sp) ; has vertscroll _LNew move.l (sp)+, a1 ; get ListHandle move.l a1, lFileListHandle(a6) ; save away ListHandle move.l (a1), a1 lea ClickHack, a0 move.l a0, lClikLoop(a1) ; set up our custom click proc move.b #$FC,selFlags(a1) ; want single selection, but OK to select "empty" cells ; This is because our "lengths" are bogus, so "empty" is bogus add.l #16,sp ; throw away rest of temprect ; initialize the indent to be h=iconPad,v=Font ascent move.w lFontInfoRec.ascent(a6),indent+Point.v(a1) move.w #iconPad-1,indent+Point.h(a1) ; if on a color machine with color graph port ; then put a ptr to an array of RGBColor's in usrHandle btst #6,ROM85 ; do we have Color QD? bne.s @doneColor move.w portVersion(A3),d0 and.w #$C000,d0 ; are we using a color grafport? beq.s @doneColor moveq #1,d3 lea lIconColors(a6),a2 @nextColor subq #2,sp ; : OSErr move.w d3,-(sp) ; labelNumber: INTEGER move.l a2,-(sp) ; VAR labelColor: RGBColor clr.l -(sp) ; VAR Str255: labelString _GetLabel tst.w (sp)+ bne.s @doneColor addq #6,a2 ; SizeOf(RGBRec) addq #1,d3 cmp.w #7,d3 ; only do colors 1 thru 7 ble.s @nextColor move.l lFileListHandle(a6),a0 move.l (a0), a0 lea lIconColors(a6),a1 move.l a1,userHandle(a0) ; save ptr to color table in userHandle for LDEF to get to bsr DumpList ; initialize bounds and visible @doneColor rts DebuggerSymbol SetUpList ;----------------------------------------------------------------------- ; The hack allows user to deselect by dragging out of list ; ClickHack movem.l a6/a3,-(sp) move.l GrafGlobals(A5),A0 move.l thePort(A0),A0 ; get our stack frame lea -lTheDialogRec(a0),a6 bsr.s GetSel ; get selection in A0, cell in d0 move.l d0,lLastSel(a6) bmi.s @exit ; can do anything without selection move.l lFileListHandle(a6), A3 ; get the list handle move.l (A3), A3 move.l mouseLoc(a3),lPoint(a6) subq #2,sp ; room for boolean result move.l lPoint(a6),-(sp) pea lNRect(a6) _PtInRect ; is cursor still in file list box? tst.b (sp)+ bne.s @exit ; cursor moved out of list rect move.w visible+Rect.top(a3),d0 cmp.w dataBounds+Rect.top(a3),d0 beq.s @doneAutoscroll move.w visible+Rect.bottom(a3),d0 cmp.w dataBounds+Rect.bottom(a3),d0 bne.s @exit @doneAutoscroll ; cursor is out of list rec and done autoscrolling, so deselect clr.w -(SP) ; deselect move.l lLastSel(a6),-(SP) ; pass the last selected cell move.l lFileListHandle(a6), -(sp) ; pass the list _LSetSelect moveq #-1,d0 move.l d0,lLastSel(a6) ; remember nothing is selected @exit movem.l (sp)+,a6/a3 MOVEQ #1, D0 ; never abort the click RTS DebuggerSymbol ClickHack ;------------------------------------------------------ ; note: GetCellPtr and GetSel must be kept in sync ; ; GetCellPtr - get a pointer to the cell data ; ; d0 -> cell ; a0 <- ptr to cell data ; GetCellPtr movem.l a3/a4,-(sp) move.l d0,-(sp) ; fill tempcell with data move.l lFileListHandle(a6),a4 ; pass list handle in a4 move.l sp,a3 ; pass ptr to cell in a3 bra.s GetData ;------------------------------------------------------ ; GetSel -- get the current selection ; ; CCs - set minus if no selection ; a0 - points at selected item ; d0 - cell for selected item GetSel movem.l a3/a4,-(sp) move.l lFileListHandle(a6),a4 ; get list handle clr.l -(sp) ; fill tempcell with data move.l sp,a3 ; and save ptr to cell subq #2, sp ; boolean result st -(sp) ; find first selected cell move.l a3,-(sp) ; VAR cell move.l a4,-(sp) ; list handle _LGetSelect tst.b (sp)+ ; did we find somethings selected? beq.s GSErrExit ; br if not, exit ; get a pointer to the cell data given a pointer to a cell in a3 GetData subq.l #4,sp ; 2 VAR INTs move.l sp,-(sp) ; point at INT1 move.l (sp),-(sp) addq.l #2,(sp) ; point at INT2 move.l (a3),-(sp) ; the cell from above move.l a4,-(sp) ; list handle _LFind move.l (sp)+,d0 ; hi offset, lo length, kill 2 VARINTs bmi.s GSErrExit ; skip out if couldn't find selected cell swap d0 ; get offset for cell move.l (a4),a0 ; list ptr deref move.l Cells(a0),a0 ; cell handle move.l (a0),a0 ; point at cellblock add.w d0,a0 ; a0 points to data of cell move.l (a3), d0 ; return cell found bra.s GSExit GSErrExit moveq #-1,d0 ; return failure with CCs set MINUS move.l d0,a0 GSExit addq.l #4,sp ; remove cell from stack movem.l (sp)+,a3/a4 ; restore regs rts DebuggerSymbol GetCellPtr ;------------------------------------------------------------- ; ; FixBoxes. ; A3 must contain window ptr for call to GetIt. ; The VolRect is the rect that contains the volume name ; The DirRect is the rect that contains the directory name and that gets ; mouse clicks for the pulldown menu. ; The ButRect contains the button frame and shadow for draw, inval, and erase FixBoxes moveq #0,d0 ; default indent = 0 FixEdges move.w d0,-(sp) ; save indent moveq #sfItemVolumeUser,d0; get the volume name/icon useritem bsr VirtualToRealItem bsr GetIt ; set up this item move.w (sp)+,d0 ; get indent move.l lBox+topLeft(a6),lVolRect+topLeft(a6) move.l lBox+botRight(a6),lVolRect+botRight(a6) ; copy the item's rect rts DebuggerSymbol FixBoxes ;--------------------------------- ; ; Inval volume icon and name. ; InvalVol pea lVolRect(a6) _InvalRect rts DebuggerSymbol InvalVol ;--------------------------------- ; ; Inval pop up menu area ; InvalPopUp pea lPopUpMaxRect(a6) _InvalRect rts DebuggerSymbol InvalPopUp ;--------------------------------- ; ; This is called after hookFirstCall but before the window is shown. ; SF2Compatability clr.b lVolumeSelect(a6) tst.b lDoingGetFile(a6) beq.s @setDrive ; set up user item for gray line between buttons moveq #getGrayBar,D3 ; user field ID for grey line bsr SetUserDraw ; install user draw proc ; ? this must be here for historical reasons ? moveq #10,d0 ; set up the "ignored" prompt move.l lPrompt(a6),a2 ; pointer to string bsr SetItsText ; see if file list is off screen, in which case we go into volume select compatibility mode moveq #getNmList,d3 bsr FindItem ; get file list boundary into -8(a0) subq #2,sp ; room for result move.l 4+Rect.topLeft(a0),-(sp) ; push top left of file list rect pea portRect(a3) ; push boundary of dialog _PtInRect tst.b (sp)+ bne.s @setDrive ; if it is inside dialog then go on normally st lVolumeSelect(a6) ; we are in that mode bra @done ; Change drive button title to "desktop" @setDrive MOVEQ #putDrive,D0 ; get drive button item BSR GetIt LEA lString(A6), A1 MOVEQ #sfDesktopName, D1 BSR GetLocalString MOVE.L lItem(A6),-(SP) ; get the control PEA lString(A6) _SetCTitle ; make sure filelist and volume user items are enabled moveq #putVolume,d3 bsr EnblItem ; enable volume Item addq #4,Rect.left-8(a0) ; shrink the volume rect a bit to it does not overlap the file list halo moveq #sfItemFileListUser,d0 bsr VIrtualToRealItem move.w d0,d3 bsr EnblItem ; enable file list ; some apps have customized SF2 dialogs with added TE items. We need to ; add these to the standard list of activatble items, or they would be ; unacessable. move.l lActiveList(a6),a0 ; copy standard list to buffer that can be append to lea lActiveListBuf(a6),a1 move.l (a0)+,(a1) ; copy 6 bytes (getfile only needs 4, but whose counting) move.w (a0)+,4(a1) move.l a1,lActiveList(a6) ; switch pointer to point to buffer move.b lKnownRealItems(a6),d3 ; start at end of standard items move.l items(a3),a0 ; item list handle move.l (a0),a0 ; ptr move.w (a0),d2 ; get number of items-1 addq.w #1,d2 ; get number of items @nextItem addq.w #1,d3 ; go to next item cmp.w d3,d2 ; are we at end of items? blt.s @doneExtraTEs bsr FindItem ; in:d3, out: a0 btst #bEditText,12(a0) ; see if it is a TE item beq.s @nextItem ; loop addq.w #1,(a1) ; now have one more item move.w (a1),d0 ; get how many count add.w d0,d0 ; each element is a word (2 bytes) move.w d3,(a1,d0.w) ; go to end and add this new one bra.s @nextItem ; loop @doneExtraTEs ; check if SF2 custom dialog has a help item in it. If so, force scan ; this way an app can continue to use SF2 and get help in 7.0 and run in 6.0 subq #2,sp ; room for integer result move.l a3,-(sp) ; dialog ptr _HMCountDITLHelpItems tst.w (sp)+ ; get how many help items are in ble.s @doneHelpCheck ; if error of no help items, go on clr.w lHelpTemplate(a6) ; mark that have no template to force scan @doneHelpCheck @done rts DebuggerSymbol SF2Compatability ;---------------------------------------------------------- ; ; The dialog hack. This routine shuffles around items in the ; dialog, and the dialog itself, to make this StdFile behave ; nicely when being called by guys thinking they are calling ; the old StdFile. ; SF1Compatability ; get list box boundary into lNRect(A6) bsr GetFileListBoundary ; get change in size into d4, and default rect into temprect moveq #0,d4 clr.l tempRect ; temprect topleft = 0,0 move.l #$0088015C,tempRect+4 ; temprect botRight = 136,348 (old getFile) move.w lHeight(a6),d4 ; get height of button add.w #6,d4 ; 3 for shadow, frame; 3 for spacing tst.b lDoingGetFile(a6) bne.s @ItemHack ; is get file... add #88,d4 ; add room for file list (putfile) move.l #$00680130,tempRect+4 ; temprect botright = 104,304 (old putFile) ; adjust the item list if necessary. Item list needs to be moved down if ; width of item 8 <> 1 (for putfile) or width of item 8 <> 16 (for getfile). @ItemHack moveq #1,d5 ; get width of gray line for putfile tst.b lDoingGetFile(a6) ; is putfile? beq.s @0 ; => yes moveq #16,d5 ; else get width of scrollbar @0 moveq #8,d3 ; go get item 8 for width check bsr FindItem ; get item into A0 move.w ItmRect+right(a0),d0 ; get the right sub.w ItmRect+left(a0),d0 ; sub the left moveq #0,d3 ; set default for PlaceIt cmp.w d5,d0 ; is it an old ditl?? seq lOldDITL(a6) ; set flag for below beq.s @1 ; => yes, go adjust things move.w lHeight(a6),d4 ; else check for bigger font sub.w #16,d4 ; what we expected? (get size difference in d4) beq @doneMoving ; => yes, no need to move items around @1 move.w lNRect+top(a6),d6 ; this is the top of file rect move.l Items(a3),a0 ; handle to item list move.l (a0),a0 ; deref move.w (a0),d5 ; # items -1 moveq #1,d3 ; start with item 1 @2 bsr FindItem ; get pointer to item tst.b lDoingGetFile(a6) ; context check? beq.s @3 ; => it's putfile cmp.w ItmRect+bottom(a0),d6 ; see if he's above me bge.s @4 ; skip move if he's above me @3 add d4,ItmRect+top(a0) ; add to top add d4,ItmRect+bottom(a0) ; to offset the item btst #2,ItmType(a0) ; is this a control? beq.s @4 ; nope... move.l ItmHndl(a0),-(sp) ; save the control handle move.l ItmRect+topleft(a0),-(sp) ; move to new location _MoveControl ; Move it @4 addq #1,d3 ; next item dbra d5,@2 ; shuffle them all ; tweak the list's rectangle. If an old dialog, make the list 16 pixels wider ; (because scrollbar internal to list now). moveq #sfItemFileListUser,d0 bsr VirtualToRealItem move.w d0,d3 bsr FindItem ; get the item addq #ItmRect,a0 ; point to the rect for below move.w lHeight(a6),d1 ; get height of cell for below tst.b lOldDITL(a6) ; new item list? beq.s @6 ; => yes, just adjust for fontsize tst.b lDoingGetFile(a6) ; is putfile? beq.s @5 ; => yes, don't need to grow list add.w #16,right(a0) ; add 16 to the fileListItem.right bra.s @6 ; => and resize the list, DLOG ; putFile: jam standard list at $18,$F,$6A,$E7 ; the cell height is in d1. The standard cell height is d1-16, so make top,bottom 16 less in constants @5 move.l #$0008000F,top(a0) ; top - 16, left add.w d1,top(a0) ; bump top for button move.l #$005A00E7,bottom(a0) ; bottom - 16, right add.w d1,bottom(a0) ; bump bottom for button ; if the cells won't fit evenly into list, shrink the list @6 move.w bottom(a0),d0 ; get bottom sub.w top(a0),d0 ; get height subq #2,d0 ; skip top, bottom lines divu d1,d0 ; divide by cell height swap d0 ; get remainder sub.w d0,bottom(a0) ; shrink to next cell boundary tst.b lOldDITL(a6) ; new item list? beq.s @BumpDLOG ; => yes, just make DLOG bigger ; now we must resize the DLOG. If it is in app, or if in sys with new ; DLOG ID, use DLOG from DWindow. Else use the DLOG rect already in tempRect. subq.l #6,sp ; make room for handle and resFile move.l #'DLOG',-(sp) ; push the type move.w lDlgID(a6),d3 ; get the dialog ID move.w d3,-(sp) ; push the dialog ID _GetResource ; get res handle onto stack _HomeResFile ; where does it live? move.w (sp)+,d0 ; get it bne.s @BumpDLOG ; => not from sys file cmp.w #putDlgID,d3 ; was it std putFile? beq.s @BDLOG ; => yes, it's ok cmp.w #getDlgID,d3 ; was it std getfile? beq.s @BDLOG ; => yes, it's ok @BumpDLOG move.l DWindow+PortRect+4(a3),TempRect+4 ; else use DLOG size @BDLOG move.l d4,d3 ; make a copy for dialog rect delta ; Now temprect contains a rect that the caller thought he was putting ; up. This rect will be grown by d3, and the box needs to be re-centered ; on the screen after this operation. move.l d3,d5 swap d5 add.l TempRect+4,d5 move.l a3,-(sp) ; first grow the window move.l d5,-(sp) ; by this amount st -(sp) ; updating necessary _SizeWindow ; invalidate current edit field cause it was moved move.w #-1,DWindow+editField(A3) ; get list box boundary into lNRect(A6) again, incase it moved. bsr.s GetFileListBoundary @doneMoving rts DebuggerSymbol SF1Compatability GetFileListBoundary moveq #sfItemFileListUser,d0 bsr VirtualToRealItem bsr GetIt lea lBox(a6),a0 ; point to box move.l (a0)+,lNRect+topLeft(a6) ; stuff away the rectangle move.l (a0)+,lNRect+botRight(a6) ; of the file list rts DebuggerSymbol GetFileListBoundary ; If we branched here from above, then there was a new DITL. We must assume that ; there is also a new DLOG. Users who specify new DITLs (as opposed to the system's ; new DITL) must also supply a new DLOG. At this point, the window will have that size. ; ; check is window (a3) is entirely on screen ; returns with CC set ; MyCheckWindow subq #2,sp ; room for boolean result move.l a3,-(sp) ; whichWindow = theDialog move.b #ccFrame,-(sp) ; checkControl = ccFrame st -(sp) ; entirelyOnScreen = TRUE _CheckWindow tst.b (sp)+ ; is dialog entirely on screen? rts DebuggerSymbol MyCheckWindow ; ; make sure the dialog is entirely on screen ; PositionSanityCheck bsr.s MyCheckWindow bne.s @done ; if so, then we are done move.l A3,-(SP) ; pass the window move.b #lcMainScreen,-(SP) ; over main monitor move.b #hcCenter,-(SP) ; center horizontally move.b #vcAlertCenter,-(SP); center vertically like an alert _AutoPositionWindow @done rts DebuggerSymbol PositionSanityCheck ;------------------------------------------------------------------- ; ; Enable an item. Assumes a3 -> dialog record. d3 contains item # ; to enable. returns ptr to item in a0. ; ; FindItem2 assumes a0 is handle to items, d1 contains item# - 2 EnblItem bsr.s FindItem add.w #12,a0 ; right to the type bclr #7,(a0) ; enable the item rts DebuggerSymbol EnblItem FindItem move d3,d1 subq.w #2,d1 ; minor adjustment move.l items(a3),a0 ; item list handle FindItem2 move.l (a0),a0 ; ptr addq.l #2,a0 ; skip item count moveq #0,d0 tst.w d1 bmi.s @1 @0 add.w #13,a0 ; skip handle(4), rect(8), type(1) move.b (a0)+,d0 ; get length of data addq.b #1,d0 bclr #0,d0 ; round up length add.w d0,a0 ; skip data dbra d1,@0 @1 rts DebuggerSymbol FindItem ;-------------------------------------------------------------------- ; ; in: d0.w = vRefNum ; ; trashes d0-d2,a0-a1 ; SetVolumeIcon ; get volume name lea lIOCmd(A6),A0 ; do some I/O clr.w ioVolIndex(a0) ; lookup by vRefNum move.w D0,ioVRefNum(A0) ; look on item's drive pea lVolName+StyledString.text(A6) ; point to volume name move.l (sp)+,ioVNPtr(A0) ; and set it up _HGetVInfo ; get info about this drive bne.s @exit ; see if it has changed move.w ioVRefNum(a0),d0 ; pass vRefNum cmp.w lDisplyedVolRef(a6),d0 beq.s @exit move.w d0,lDisplyedVolRef(a6) move.w ioVSigWord(a0),lSigWord(a6) ; update signature so we can tell we're on an MFS disk ; get volume icon bsr.s getVolIcon ; set up the icon move.w d0,lVolIcon(a6) ; save icon away for this disk ; set low mem globals to reflect new directory move.w lDisplyedVolRef(a6),d0 move.w d0,SFSaveDisk ; update low-mem volume neg.w SFSaveDisk ; want drive number, not vrefnum tst.b lAtDesktop(a6) ; special case when at desktop, since there <55.5> ble.s @inval ; are merged folders for each volume <55.5> bsr.s GetVolumeInfoPtr ; a0 (out) pointer to info move.l PerVolumeInfo.desktopDir(a0),d0 beq.s @inval ; just in case dirID not known yet <55.5> move.l d0,CurDirStore ; update low-mem dirID <55.5> ; inval display @inval bsr InvalVol @exit rts DebuggerSymbol SetVolumeIcon ;-------------------------------------------------------------------- ; in: d0.w = vRefNum ; out: a0 = ^VolumeInfo, trashed d0 ; GetVolumeInfoPtr neg.w d0 ; -1 -> 1 subq #1,d0 ; zero based asl.w #3,d0 ; * SizeOf(PerVolumeInfo) lea lVolumes(a6),a0 lea (a0,d0.w),a0 rts DebuggerSymbol GetVolumeInfoPtr ;-------------------------------------------------------------------- ; in: d0.w = vRefNum ; out: d0.w = iconID ; GetVolIcon move.l a0,-(sp) ; don't trash a0 move.l VCBQHdr+2,a0 ; walk vcb queue @nextVcb cmp.w vcbVRefNum(a0),d0 beq.s @gotVCB ; get driver refnum move.l qLink(a0),d1 move.l d1,a0 bne.s @nextVcb bra.s @default ; should never get here @gotVCB move.w vcbDRefNum(a0),d0 ; get driver RefNum addq #1,d0 neg.w d0 ; massage index lsl.w #2,d0 move.l uTableBase,a0 move.l (a0,d0.w),a0 ; index into table move.l (a0),a0 ; dereference handle btst #6,dCtlFlags+1(a0) ; see if it is in RAM move.l dCtlDriver(a0),a0 ; get driver start pointer beq.s @havePtr ; check result of tst.w move.l (a0),a0 ; RAM drivers need an extra dereference @havePtr lea drvrName+2(a0),a0 ; skip length byte and initial period move.w #floppyIconResource,d0 cmp.l #'Sony',(a0) ; .Sony means use floppy icon beq.s @done cmp.l #'NewA',(a0) ; .NewAge means use floppy icon CSS beq.s @done move.w #genericFileServerIconResource,d0 cmp.l #'AFPT',(a0) ; .AFPTranslator means use fileserver icon beq.s @done @default move.w #genericHardDiskIconResource,d0 ; else use Hard disk icon @done move.l (sp)+,a0 rts DebuggerSymbol GetVolIcon ;--------------------------------------------------------------- ; ; GetPopupIcon ; in: d1 = dirID of folder ; out: d0 = icon ID to use GetPopupIcon move.w #desktopIconResource, d0 ; assume it is the desktop icon cmp.l lDeskDir(a6),d1 ; is this the desktop? beq.s @exit ; br if so, got icon move.w #trashIconResource, d0 ; assume it is the trash icon cmp.l lTrashDir(a6),d1 ; is this the trash? beq.s @exit ; br if so, got icon move.w lVolIcon(a6),d0 ; use disk's icon cmp.l #2,d1 ; is this root level? beq.s @exit ; br if so, got icon ; otherwise it must be a folder move.w #openFolderIconResource,d0; anything else is an open folde @exit rts DebuggerSymbol GetPopupIcon ; ; ReBuildMenu movem.l a2-a4,-(sp) ; save some regs ; a2 hold handle to array of dirIDs ; a3 holds pointer to IO param block ; a4 hold menu handle ; d5 is item index ; d6 is dirID moveq #0, d6 ; assume no movement subq #4, sp move #sfPopUpMenuID, -(sp) pea emptyString _NewMenu move.l (sp)+, d0 beq @noMenuExit move.l d0, a4 ; keep menu in a4 moveq #0, d0 _NewHandle bmi @noMenuExit moveq #1,d5 ; keep menu item in d5 move.l lCurDir(a6),d6 ; keep current directory in d6 move.l a0, a2 ; keep dirID handle in a2 lea lIOCmd(a6), a3 ; keep param block in a3 move.w lVolRefNum(a6),ioVRefnum(a3) ; setup volume in param block lea lString(a6),a1 ; setup name in param block move.l a1,ioFileName(a3) @nextDirectory moveq #1, d0 cmp.l d0, d6 ; at root of root? bne.s @dirOK @atDesktop move.l lDeskDir(a6), d6 ; root of root is desktop @dirOK cmp.l lDeskDir(a6), d6 ; is this the desktop? bne.s @notDesktop ; br if not, check trash moveq #sfDesktopName, D1 ; get desktop's name bra.s @fillName ; fill item using name @notDesktop cmp.l lTrashDir(a6), d6 ; is this the trash? bne.s @notTrash ; br if not, it's a folder moveq #sfTrashName, D1 ; get trash's name @fillName lea lString(a6),a1 ; handy place to put name bsr GetLocalString ; load string resource bra.s @fillEntry ; fill entry using this name @notTrash move.l d6,ioDirID(a3) ; for this directory move #-1,ioFDirIndex(a3) ; lookup by dirID move.l a3, a0 _GetCatInfo bne.s @noDrawExit ; skip out on file system error jrm 01oct86 @fillEntry move d5, d0 asl #2, d0 move.l a2, a0 _SetHandleSize bmi.s @noDrawExit move.l (a2), a0 move d5, d0 asl #2, d0 move.l d6, -4(a0, d0.w) ; save away dirid for this item move.l a4, -(sp) pea emptyString _AppendMenu ; add a menu item @setMenuItem move.l a4, -(sp) move d5, -(sp) pea lString(a6) _SetItem move.l d6, d1 bsr GetPopupIcon @gotIcon move.l a4, -(sp) move d5, -(sp) sub.w #genericIconBase,d0 ; start SF icons at 0 instead of genericIconBase move.w d0,-(sp) _SetItmIcon move.l a4, -(sp) move d5, -(sp) move #$1A, -(sp) ; magic value for small icons _SetItemCmd cmp.l lDeskDir(a6),d6 ; is this the desktop? beq.s @disposeExit ; br if so, we're done addq #1, d5 ; add 1 to number of names cmp.l lTrashDir(a6),d6 ; is this the trash? beq @atDesktop ; br if so, next is desktop move.l ioDrParID(a3),d6 ; next is parent folder bra @nextDirectory @noDrawExit ; ### I really don't know if inval is appropriate here bsr InvalPopUp ; need to redraw PopUpMenuSymbol (this error handling needs to be looked at) moveq #0, d6 ; no movement @disposeExit ; swap in the new array of dirIDs move.l lPopUpDirIDs(a6),d0 beq.s @storeNewDirs move.l d0,a0 _DisposHandle @storeNewDirs move.l a2,lPopUpDirIDs(a6) move.w d5,lPopUpDirCount(a6) ; swap the new menu into the menuHandle move.l lPopUpControl(a6),a0 move.l (a0),a0 move.w #1,contrlValue(a0) ; we always want the top item "selected" st contrlVis(a0) ; force it visible (it was initially hidden) move.l contrlData(a0),a0 ; <10> The following code was removed for change <9>, but shouldnÕt have been. Since this code path is taken ; <10> every time the path popup changes, it needs to delete the old version of the menu from MenuList before ; <10> inserting the updated version. Otherwise, the _InsertMenu fails. ; <10> ; <10) So, this is exactly the same as the pre-<9> code. The first time this code is run, the popup CDEF will ; <10> already have called _DeleteMenu, removing its menu from the MenuList. Our _DeleteMenu is harmless and ; <10> does nothing in that case. However, since we, and not the CDEF, are now inserting the menu, the CDEF will ; <10> assume we own it and will never _DeleteMenu or _DisposMenu it. Because of this, we _DeleteMenu and _DisposMenu ; <10> every subsequent time through this code and once when weÕre all done (see change <9>). move.l a0,d5 ; save data handle <10> <68, #f2-ngk-001> move.l (a0),a0 ; <10> move.l CDEFpopUpData.theMenu(a0),d0 ; menuHandle is first long in control data <10> beq.s @storeNewMenu ; <10> move.l d0, -(sp) ; push for dispose the menu <10> move.w #sfPopUpMenuID, -(sp) ; remove popup from menu list <10> _DeleteMenu ; <10> harmless if not in the menu list _DisposMenu ; d0 was pushed before delete <10> @storeNewMenu ; <10> move.l d5,a0 ; retrieve data handle <10> move.l (a0),a0 ; dereference <68, #f2-ngk-001> move.l a4,CDEFpopUpData.theMenu(a0) ; menuHandle is first long in control data move.l a4, -(sp) move #-1, -(sp) ; add a popup menu _InsertMenu @noMenuExit movem.l (sp)+, a2-a4 ; restore regs rts DebuggerSymbol ReBuildMenu ;--------------------------------------------------------------- ; PopUpNewItem move.l lPopUpControl(a6),a0 move.l (a0),a0 move.w contrlValue(a0),d0 ; get newly selected item # in pop up cmp.w lPopUpDirCount(a6),d0 ; are we going to desktop? beq.s @desktop subq #1,d0 ; list is zero-based, menu is one-based move.l lPopUpDirIDs(a6),a0 move.l (a0),a0 asl.w #2,d0 ; array of longs move.l (a0,d0.w),d0 ; get dirID of newly selected item bne.s @haveDir ; if zero then a volume with no desktop folder @desktop tst.b lAtDesktop(a6) ; are we already at desktop? bgt.s @done bra caseGotoDesktop2 ; do same as pressing Desktop button @haveDir cmp.l lCurDir(a6), d0 ; did the user change directories? beq.s @done ; if not, don't recalc move.l d0, lCurDir(a6) ; stuff new directory st lPopUpLooksGood(a6) bsr NewDirSelectFirstIfGetFile ; build and draw a new dir @done rts DebuggerSymbol PopUpNewItem ;------------------------------------------------------------------- ; ; DumpList empties our current list. ; DumpList move.l lFileListHandle(a6),D0 beq.s @done ; do nothing if no file list move.l d0,A0 ; file list handle move.l (A0),A0 ; data record pointer lea databounds(A0),A1 ; say there's no data clr.l (A1)+ ; topLeft = 0 clr.w (A1)+ ; bottom = 0 move.w #1,(A1) ; right = 1 lea visible(A0),A1 ; say there's no visible clr.l (a1)+ ; clr.l (a1)+ ; the size of the data and array are reset by setHandleSize to new size @done rts DebuggerSymbol DumpList ;------------ ; SetBounds -- use rView to determine the list's data and visible bounds. ; set visible top,left,bottom,right to 0,0,x,1 ; x := (rview.bottom-rview.top)/cellsize.v ; Entry: D0 = # of cells in list ; A0 = pointer to data record ; Trashes: A1,D0,D1 SetBounds LEA dataBounds(A0),A1 ; get bounds pointer CLR.L (A1)+ ; top = left = 0 MOVE.W D0,(A1)+ ; bottom = # of cells MOVE.W #1,(A1)+ ; bounds.right = 1 LEA visible(A0),A1 ; get visible pointer CLR.L (A1)+ ; set vis top,left = 0 MOVE.W cellsize+v(A0),D1 ; get cellsize MOVEQ #0,D0 ; division needs a long ADD.W rView+bottom(A0),D0 ; add bottom SUB.W rView+top(A0),D0 ; subtract top ADD.W D1,D0 ; add cellsize.v SUBQ #1,D0 ; and subtract 1 DIVU D1,D0 ; divide by cellsize.v MOVE.W D0,(A1)+ ; and update visible bottom MOVE.W #1,(A1) ; vis.right = 1 ; set control max of scroll bar, don't use SetCtlMax because it will change display ; thumb. We will let LUpdate do that. This way scrollbar jumps once to new location move.w dataBounds+bottom(A0),d0 sub.w visible+bottom(A0),d0 move.l vScroll(a0),a1 move.l (a1),a1 move.w d0,contrlMax(a1) clr.w contrlValue(a1) RTS DebuggerSymbol SetBounds ;------------------------------------------------------------------------------- ; in: D0.W = key out: D0.W = BOOLEAN ; ; Given a keyCode, it handles arrow keys and returns true if it was one. ; Uses up and down arrow to move selection. If it is not visible, scroll to it. ; If there is no selection, get one (up arrow = bottom; dn arrow = top) and ; make it visible. Dimmed items are skipped over. If there are no selections, ; nothing happens. If there is only one selectable item, it remains selected. ; ;------------------------------------------------------------------------------- ArrowKey MOVEM.L A4/D3-D5,-(SP) ; save regs MOVE.L lFileListHandle(A6), A4 ; A4 = list handle ; handle arrow keys MOVEQ #-1,D4 ; D4 = up direction offset CMP.B #chUpArrow,D0 ; is it up arrow? BEQ.S @gotArrow ; br if so, handle up arrow MOVEQ #1,D4 ; D4 = down direction offset CMP.B #chDownArrow,D0 ; is it down arrow? BEQ.S @gotArrow ; br if so, handle down CMP.B #chRightArrow,D0 ; is it right arrow? BEQ.S @arrowExit ; br if so, eat key CMP.B #chLeftArrow,D0 ; is it left arrow? BEQ.S @arrowExit ; br if so, eat key ; handle paging keys move.l lFileListHandle(a6),a1 move.l (a1),a0 move.w visible+top(a0),d3 sub.w visible+bottom(a0),d3 ; calculate the size of a page cmp.b #chPageUp,d0 beq.s @scrollList neg.w d3 ; page down by negative of pugUp value cmp.b #chPageDown,d0 beq.s @scrollList move.w #-2000,d3 ; scroll a very large amout to goto top cmp.b #chHome,d0 beq.s @scrollList neg.w d3 ; negate Home to goto end cmp.b #chEnd,d0 bne.s @noArrowExit @scrollList clr.w -(sp) ; col move.w d3,-(sp) ; row move.l a1,-(sp) ; list record _LScroll bra.s @arrowExit @gotArrow MOVE.L (A4), A0 MOVE.W dataBounds+bottom(A0),D5; D5 = bounds.bottom SUBQ #1,D5 ; D5 = last cell number BSR GetSel ; get current selection BMI.S @noSelection ; br if no selection MOVE.L D0, D3 ; D3 = save current cell SWAP D3 ; get column in low word BRA.S @NextCell ; if no selections, move selection to top for down arrow, end for up arrow. If top/bottom ; not selected, search starting at end. @NoSelection MOVEQ #0,D3 ; assume go to top of list TST.W D4 ; go to top of list? BPL.S @DoSelect ; br if so, select top MOVE.W D5,D3 ; else select bottom BRA.S @DoSelect ; Scan the list, selecting the first non-dimmed cell in the right direction @NextCell ADD.W D4,D3 ; at top? BMI.S @arrowExit ; br is so, exit CMP.W D3,D5 ; at bottom? BLT.S @arrowExit ; br if so, exit @DoSelect MOVE.L D3, D0 SWAP D0 BSR GetCellPtr TST.B FileEntry.feFile.dimmed(A0) ; is it dimmed? BNE.S @NextCell ; br if so, try next cell sf d2 ; don't center selection with scrolling, just scroll by one BSR SelectAndReveal ; select the cell in D3 @arrowExit pea lTypeSelect(a6) _TypeSelectClear ; clear type select buffer MOVEQ #1, D0 BRA.S @exit @noArrowExit MOVEQ #0, D0 @exit MOVEM.L (SP)+,A4/D3-D5 ; restore regs RTS DebuggerSymbol ArrowKey ;-------------------------------------------------------------- ; PROCEDURE ShowSFBalloons; {Shows balloons that are specified by 'PACK' resources} ; ; Enter: A2 = pointer to any event (including NULL) ; A3 = Dialog ptr ; A6 = main stack frame ; ; ; local variables off of A4 sdrHelpMsg EQU -hmmHMSize sdrHotRect EQU sdrHelpMsg-8 sdrTip EQU sdrHotRect-4 sdrMouse EQU sdrTip-4 sdrSize EQU sdrMouse ; ; ShowSFBalloons LINK A4,#sdrSize ; make a stack frame MOVEM.L D0-D2/A0-A3,-(SP) ; save regs just in case some body cares SUBQ #2,SP _HMGetBalloons ; we're safe as this is 7.0 only TST.B (SP)+ BEQ.S @exitSFBalloons ; ok, help wasn't on so let's exit PEA sdrMouse(A4) ; a place to put the mouse point _GetMouse ; go and get it move.l lPopUpControl(a6),a0 ; get popup control move.l (a0),a0 move.l contrlData(a0),a0 ; get control data handle move.l (a0),a0 lea CDEFpopUpData.myCtlRect(a0),a2 ; current size rect is 6 bytes into control data SUBQ.L #2,SP ; room for boolean MOVE.L sdrMouse(A4),-(SP) ; push that mouse point pea (a2) ; current size of menu _PtInRect TST.B (SP)+ ; was the mouse in dir Rect? BEQ.S @WasntDirRect ; go now and check the Save button MOVE.W #hsiPopUpMenu,D0 ; get the directory popup message move.l a2,a0 BSR.S ShowSpecialBalloon ; go and show the balloon BRA.S @exitSFBalloons ; time to exit @WasntDirRect move.w lHelpTemplate(a6),d0 ; new calls, and old ones with help items don't need scan beq.s @exitClearly SUBQ #2,SP MOVE.W D0,-(SP) ; push the resource id of the dialog MOVE.W #-1,-(SP) ; don't look in another resource ref num ; 'cuz we want resources to come from here (i.e. System) MOVE.L #'hdlg',-(SP) ; scan our 'hdlg' resource for msgs _HMScanTemplateItems TST (SP)+ ; use result as flag ; BEQ.S ; *** someday @exitClearly CLR.B lBalloonUp(A6) ; so we get our special case balloons @exitSFBalloons MOVEM.L (SP)+,D0-D2/A0-A3 ; go restore the regs UNLK A4 @dontCallHelp RTS ; return to the bulk DebuggerSymbol ShowSFBalloons ; ; ShowSpecialBalloon - ; ; Enter: A0 = -> to Hot Rect ; A4 = local stack frame ; A6 = standard file stack frame ; D0 = message number index (in STR#, res ID = rStandardFileHelpStringsID) ; ; ShowSpecialBalloon CMP.B lBalloonUp(A6),D0 BEQ.S @exitsdr MOVE.B D0,lBalloonUp(A6) ; set our global saying we ; showed the help balloon ; A0 -> Hot Rect MOVE.L topLeft(A0),sdrHotRect+topLeft(A4) ; copy the Hot Rect MOVE.L botRight(A0),sdrHotRect+botRight(A4) LEA sdrHelpMsg(A4),A0 MOVE #khmmStringRes,hmmHelpType(A0) ; we want to show a 'STR#' resource MOVE #rStandardFileHelpStringsID,hmmHelpMessage(A0) ; of this res ID MOVE D0,hmmHelpMessage+2(A0) ; and this index MOVE.L sdrHotRect+botRight(A4),D0 ; make the tip the bottom right for now MOVE.L D0,sdrTip(A4) SUBQ.W #5,V+sdrTip(A4) SUBQ.W #8,H+sdrTip(A4) ; move it up and left a bit PEA sdrTip(A4) ; convert tip to global _LocalToGlobal PEA sdrHotRect+topLeft(A4) ; and the altrect to left _LocalToGlobal PEA sdrHotRect+botRight(A4) ; and the altrect bottom right _LocalToGlobal SUBQ #2,SP ; room for pack call result PEA sdrHelpMsg(A4) ; push the help message MOVE.L sdrTip(A4),-(SP) ; push the tip PEA sdrHotRect(A4) ; push the altRect (also the hot rect) CLR.L -(SP) ; no tipProc CLR.L -(SP) ; 0 for proc and variant IDs MOVE.W #kHMSaveBitsWindow,-(SP) ; save bits behind, AND generate update event _HMShowBalloon ; call the package MOVE (SP)+,D0 ; did we get a noErr result? BEQ.S @exitsdr ; yes, just exit @sdrUnsuccess CLR.B lBalloonUp(A6) ; no, so clear the flag @exitsdr RTS DebuggerSymbol ShowSpecialBalloon ENDWITH END ; of file