sys7.1-doc-wip/Toolbox/StandardFile/StandardFilePACK.a
2020-04-26 16:46:44 +08:00

8405 lines
288 KiB
Plaintext
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

;
; Hacks to match MacOS (most recent first):
;
; <Sys7.1> 8/3/92 Reverted <SM5>
; 9/2/94 SuperMario ROM source dump (header preserved below)
;
;
; 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):
;
; <SM6> 11/6/92 SWC Changed PackMacs.a->Packages.a.
; <SM5> 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 <gbm>: Reversed some of change <9> because the code to
; rebuild the popup menu gets called multiple times. If it doesnt
; _DeleteMenu the old menu, then it stays in the list and
; _InsertMenu fails. The first time _DeleteMenu is called, its
; being called for the CDEFs menu which has already been removed
; from MenuList. This is okay, though; _DeleteMenu will do
; nothing.
; <9> 7/5/92 gbm #1034877,<csd>: 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 were 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 its
; 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,<FM>: Check to see if the keyboard was already locked
; on entry to Standard File. If it was, dont lock it or unlock
; it.
; <2> 4/2/92 FM #1022940,<DTY>: #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 <KSM> fix for right-left script systems in putFile TE item.
; <51> 1/14/91 ngk <KSM> fix bug when filename field is full, now allow typing over
; selection to work.
; <50> 1/14/91 ngk <KSM> 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 <Enter> 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 <kip> 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 <KSM> Fix bug that prevented you from opening an alias to a file.
; <47> 12/14/90 ngk <pp> Fix bug in which aliases to applications were always showing up.
; <46> 12/14/90 ngk <KSM> 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 <KSM> 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 <CR> 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 doesnt 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, <CR>, <Enter>)
; <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 aliass 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
; <v26> 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.
; <v25> 3/4/88 JRM quick fix so superdrive gets floppy icon
; <v24> 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<ret> x<ret> 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 managers 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 scripts font
lSystemFontSize DS.W 1 ; cached system scripts 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 dont 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 its already locked, dont 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 its 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 its <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, Im being a LITTLE paranoid here and not trying <9>
; to delete the menu if I cant 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, dont 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 <JRM 09Sep86>
; BEQ.S goodPut ; write only folders will always give this <JRM 09Sep86>
; 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 <jrm 04Sep86>
move.b FileEntry.feFLPriv(a0),d0 ; get access privileges <jrm 04Sep86>
tst.b lDoingGetFile(a6) ; <jrm 04Sep86>
bne.s @getFile ; branch if getfile <jrm 04Sep86>
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 <jrm 04Sep86>
beq.s @doOpen ; br if R and W <jrm 04Sep86>
@openErr move #sfErrNoPrivileges,D1 ; not enough access privileges <jrm 04Sep86>
bsr ErrorAlert ; explain to user <jrm 04Sep86>
bra.s @done
@getFile
and.b #mNoSearch+mNoRead,d0 ; getfile folder needs R or S <jrm 04Sep86>
cmp.b #mNoSearch+mNoRead,d0 ; missing both? <jrm 04Sep86>
beq.s @openErr ; no, branch to normal open dir <jrm 04Sep86>
@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 ; cant 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 ; dont 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 <CR> <Enter> 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 <CR> 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 <CR> 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 <CR>
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.s @checkFileList ;<SM5> CSS <Sys7.1>
@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 <CR> 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 dont 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) ; <jrm 04Sep86>
bne.s @getFile ; branch if getfile <jrm 04Sep86>
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 <jrm 04Sep86>
beq.s @setIcon ; br if R and W <jrm 04Sep86>
bra.s @grayFolder ; else, can't open this
@getFile and.b #mNoSearch+mNoRead,d1 ; getfile folder needs R or S <jrm 04Sep86>
cmp.b #mNoSearch+mNoRead,d1 ; missing both? <jrm 04Sep86>
bne.s @setIcon ; no, branch to normal open dir <jrm 04Sep86>
@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, dont 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 <ngk 20Nov89>
; This is because our "lengths" are bogus, so "empty" is bogus <ngk 20Nov89>
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? <EHB 20-Oct-85>
beq.s @BDLOG ; => yes, it's ok <EHB 20-Oct-85>
cmp.w #getDlgID,d3 ; was it std getfile? <EHB 20-Oct-85>
beq.s @BDLOG ; => yes, it's ok <EHB 20-Oct-85>
@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
; ex<SM5> <Sys7.1> Don't treat 'NewA' same as 'Sony'
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 shouldnt 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 were 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