Delete every finder window, but the two frontmost, in current space

Hello! :slight_smile:

This is not an optimized version, nor a totally correct one, as I think my assumption about the windows being retrieved in random order, or not by index to be wrong. I’ll come back with a slightly faster solution.
Edit: Not faster, but more robust, as it now considers info-windows, but not the preferences window, I have no clue whether that is necessary or not.

Edit

I’m coming back to this one later if nobody beats me to it. I will bail out if there is any folder prefernces windows open, leave clippings windows be, and the same goes for finders preference’s window.

Having said that:

This is a script to be run to keep order on your own desktop, I haven’t used clippings windows in a long time, but those must be considered.

But for the other settings windows; info windows, preferences windows for folders, and finders preverences window, I tend to close those, as soon as I am finished with them.

But usage patterns may vary.

The main objective with this script anyway, was to show a technique to deal with windows just in your own space.
That system events are smart enough to only return the windows from the current space of an an application process or process whose visible is true.

Edit II
The code below works because I have configured Finder to show the posix paths in the title bar I think

You have to enter this in your terminal window, it should work for Leopard and later, but I used to have it this way
in Tiger as well.

defaults write com.apple.finder _FXShowPosixPathInTitle -bool YES killall Finder
You can read more about that here:http://hints.macworld.com/article.php?story=20071101210524604

Enjoy


” © Mcusr and Put in Public Domain.
” If use, or you derive the principles from this code, and posts elsewhere, or uses it in something you 
” get paid or kudos for, then you agree to refer to this post by using the code found here, or the 
” underlying principles! :)

set {ix, forSave} to {2, 2}
set {spaceWins, spaceWNames} to {{}, {}}
-- we fetch references to its finder windows in THIS SPACE
-- This is apliccable to other applicatons
-- How to get the positon, may vary, but the logic, or lack of, stands!
tell application "System Events" to tell process "Finder"
    
    set wc to (get count its every window)
    repeat with i from 1 to wc
        copy (a reference to its window i) to end of spaceWins
        copy (get name of its window i) to end of spaceWNames
    end repeat
end tell

set spaceCT to (get count spaceWins)
if spaceCT < forSave then error "not enough Finder windows in this space"

-- Considers info windows.
-- The trick about info windows is that they contains "info" in their name
-- ugly .. I know, but I can't get the class out of system events.
-- if those windows are laying inside the range, then the index has to be 
-- skewed backwards, as the info windows are not considered.
-- I don't dare closing them, after having closed finder windows,
-- which is the job I am to do.
-- Finder windows must necessarily by laying after any info windows
-- in the z-layering, with higher indicies.
-- Skews the index, ensuring enough Finder windows will be saved.

set toSkew to 0
set tix to 1
repeat with awnName in spaceWNames
    if tix < (ix + toSkew) then
        if contents of awnName contains "-info" then
            set toSkew to toSkew + 1
        else
            set tix to tix + 1
        end if
    else
        exit repeat
    end if
end repeat

-- Having found the skew factor, we add it to the 
-- index of the layered windows.
set ix to ix + toSkew


-- Finds every window we want to keep, they may be in
-- every SPACE
set keepers to {}
tell application "Finder"
    set keepers to (get its every Finder window whose index < (ix + 1)) as list
    set keepCt to (get count keepers)
    if keepCt < forSave then error "not enough Finder windows in this space"
    -- We prune out the windows from the list we obtained by 
    -- System Events, as we are to spare those.
    set toDel to spaceCT
    repeat with i from 1 to spaceCT
        copy position of (contents of item i of spaceWins) to sPos
        
        repeat with j from 1 to keepCt
            
            copy position of (contents of item j of keepers) to kPos
            
            if item 1 of sPos is equal to item 1 of kPos and (((item 2 of sPos) + 22) is equal to item 2 of kPos) 
then

                        ” We identify the windows by their position, as many Finderwindows can have the same name
                       ” And we haven't got an Id of it, so this is the way. If  the windows are positioned in EXACTLY
                       ” same place on another space, then this goes wrong, but the probabilty for that is hopefully
                       ” low, - or this script isn't for you! :)

                set item j of spaceWins to missing value
                set toDel to toDel - 1
                exit repeat
            end if
            
        end repeat
    end repeat
    
    -- Purges the Finderwindows we want to get rid of.
    set i to 0
    repeat with awinInSpace in spaceWins
        set i to i + 1
        if contents of awinInSpace is not missing value then
            
            repeat with aFwin in (get every Finder window)
                
                if name of contents of aFwin is contents of item i of spaceWNames and index of contents of aFwin > ix then
                    set amatch to Finder window id (id of contents of aFwin)
                    close amatch
                    set toDel to toDel - 1
                    exit repeat
                end if
                if toDel is 0 then exit repeat
            end repeat
        end if
    end repeat
    -- if there were other windows like info windows, then they would be spared
end tell



Hello!

This is a working script based on the skeleton above to prune finder windows apart from the number of frontmost that you want to keep, in the Space you are in.

You choose, if you want to collapse, or close.

It does consider the preferences window, and the info-window, clippings windows, and keeps them “out of the loop”, that is, they are not being closed.

I hope you like it! :slight_smile:

Edit:

I have added error messages that shows up, and the opportunity to prune every Finderwindow away by doing so when “0” is the number of windows to keep. I put that in here, and I have no intention to have a separate script for pruning them all, but feel free, should the dialog annoy you!


property scriptTitle : "Close Every Finder Window In This Space But..."
-- © Mcusr and Put in Public Domain.
-- If use, or you derive the principles from this code, and posts elsewhere, or uses it in something you 
-- get paid or kudos for, then you agree to refer to this post by using the code found here, or the 
-- underlying principles! :)
on run
	try
		set infoIconFile to a reference to file ((path to library folder from system domain as text) & "CoreServices:CoreTypes.bundle:Contents:Resources:AlertNoteIcon.icns")
	on error
		set infoIconFile to 3
	end try
	
	try
		set warningIconFile to a reference to file ((path to library folder from system domain as text) & "CoreServices:CoreTypes.bundle:Contents:Resources:AlertCautionIcon.icns")
	on error
		set stopIconFile to 3
	end try
	
	try
		set stopIconFile to a reference to file ((path to library folder from system domain as text) & "CoreServices:CoreTypes.bundle:Contents:Resources:AlertStopIcon.icns")
	on error
		set stopIconFile to 3
	end try
	
	
	
	set theNumberToKeep to 0
	set theResultisOk to promptForANumber(a reference to theNumberToKeep, "Enter The Number of Finder Windows You Wish To Keep!", infoIconFile)
	if theResultisOk then
		if theNumberToKeep is 0 then
			set theVerification to my buttonDialog({aMessageAsText:"Are you sure you want to prune all the windows in this space?", aTitleAsText:my scriptTitle, waitingForSeconds:3000, btnsAsList:{"No", "Yes"}, indexOfbtnCancelInList:1, idxOfbtnDefaultInList:2, iconFileOrNull:warningIconFile, bundeIdOfFrontApp:"com.apple.finder"})
			-- We never receive a "No"!
			set thePruneOperation to my buttonDialog({aMessageAsText:"Choose the Way to Prune!", aTitleAsText:my scriptTitle, waitingForSeconds:3000, btnsAsList:{"Cancel", "Collapse", "Close"}, indexOfbtnCancelInList:1, idxOfbtnDefaultInList:3, iconFileOrNull:infoIconFile, bundeIdOfFrontApp:"com.apple.finder"})
			pruneEverFinderWindowsInThisSpace of me by thePruneOperation
		else
			
			set thePruneOperation to my buttonDialog({aMessageAsText:"Choose the Way to Prune!", aTitleAsText:my scriptTitle, waitingForSeconds:3000, btnsAsList:{"Cancel", "Collapse", "Close"}, indexOfbtnCancelInList:1, idxOfbtnDefaultInList:3, iconFileOrNull:infoIconFile, bundeIdOfFrontApp:"com.apple.finder"})
			
			pruneAllFinderWindowsInThisSpaceBut of me apart from theNumberToKeep by thePruneOperation
		end if
	end if
	my abortNicely({bundleIdFrontApp:"com.apple.finder"}) -- Returns Nothing	
end run

on buttonDialog(R) -- Returns Button, or dies
	-- Is used for getting replies! You hit the answers which is one of two .. or three, one cancels. (cancel button 0?)
	-- R : {aMessageAsText:theMessage,aTitleAsText:thetitle,waitingForSeconds:lenToTimeout,btnsAsList:theButtons,indexOfbtnCancelInList:btnIdxCancel,idxOfbtnDefaultInList:btnIdxDefault,iconFileOrNull:rscFile,bundeIdOfFrontApp:frontappId}
	local res, failed
	set failed to false
	tell application "SystemUIServer"
		activate
		try
			set res to button returned of (display dialog (aMessageAsText of R) with title (aTitleAsText of R) ¬
				giving up after (waitingForSeconds of R) buttons (btnsAsList of R) cancel button (indexOfbtnCancelInList of R) default button (idxOfbtnDefaultInList of R) with icon (iconFileOrNull of R))
			if res = "" then error number 3000
			return res
		on error e number n
			if n is -128 then
				
				set failed to true
			else if n is 3000 then
				set failed to true
			end if
		end try
	end tell
	if failed is true then
		my abortNicely({bundleIdFrontApp:(bundeIdOfFrontApp of R)}) -- Returns Nothing
	else
		return res
	end if
end buttonDialog


to displayErrorMessageAndDie(theMessage, anIcon)
	tell application "SystemUIServer"
		activate
		try
			display dialog theMessage with title my scriptTitle giving up after 300 buttons {"Ok"} default button 1 with icon anIcon
		end try
	end tell
	my abortNicely({bundleIdFrontApp:"com.apple.finder"})
	
end displayErrorMessageAndDie



on abortNicely(R) -- Returns Nothing
	-- R : {bundleIdFrontApp:frontappId}
	tell application "System Events" to tell application process id (bundleIdFrontApp of R)
		key down control
		key code 118
		key up control
	end tell
	error number -128
end abortNicely



to promptForANumber(refToAnumber, theMessage, anIcon) -- returns false for success 
	local theFail, theRetVal
	set theFail to false
	tell application "SystemUIServer"
		activate
		repeat
			try
				set theRetVal to (display dialog theMessage default answer "2" with title my scriptTitle giving up after 300 buttons {"Cancel", "Ok"} cancel button 1 default button 2 with icon anIcon)
				
				if gave up of theRetVal is true then
					set failed to true
				else
					try
						set contents of refToAnumber to text returned of theRetVal as number
						exit repeat
					end try
				end if
			on error e number n
				set theFail to true
				exit repeat
			end try
		end repeat
	end tell
	return not theFail
end promptForANumber


to pruneAllFinderWindowsInThisSpaceBut apart from theCount by operation
	
	set {ix, forSave} to {2, 2}
	set {spaceWins, spaceWNames} to {{}, {}}
	-- we fetch references to its finder windows in THIS SPACE
	-- This is apliccable to other applicatons
	-- How to get the positon, may vary, but the logic, or lack of, stands!
	tell application "System Events" to tell process "Finder"
		
		set wc to (get count its every window)
		repeat with i from 1 to wc
			copy (a reference to its window i) to end of spaceWins
			copy (get name of its window i) to end of spaceWNames
		end repeat
	end tell
	
	set spaceCT to (get count spaceWins)
	if spaceCT < forSave then my displayErrorMessageAndDie("Not enough Finder windows in this space.", my stopIconFile)
	
	-- Actually I bail out if the main preferences window is open.
	-- Folder preferences windows, are out of the loop, when using system events.
	-- And it does us no good, to look for them globally. (by finder).
	set foundIt to false
	repeat with awnName in spaceWNames
		tell application "Finder"
			try
				set wn to its preferences window awnName
				set foundIt to true
				exit repeat
			end try
		end tell
	end repeat
	
	if foundIt is true then
		my displayErrorMessageAndDie("The Finder preferences window is open.", my stopIconFile)
	end if
	
	-- clippings windows; are there any clippings windows in this space ??
	-- In that case; we'll skew the ones we are to save backwards, leaving 
	-- the clippings windows be! (The purpose is dubious, as it seems like
	-- the clippings window are getting a higher index autmatically, but 
	-- I'll leave it here for safe measure.
	
	set toSkew to 0
	set tix to 1
	repeat with awnName in spaceWNames
		if tix < (ix + toSkew) then
			tell application "Finder"
				try
					set wn to its clipping window awnName
					set toSkew to toSkew + 1
				on error
					set tix to tix + 1
				end try
			end tell
		else
			exit repeat
		end if
	end repeat
	-- Having found the skew factor, we add it to the 
	-- index of the layered windows.
	set ix to ix + toSkew
	
	
	-- Considers info windows.
	-- The trick about info windows is that they contains "info" in their name
	-- ugly .. I know, but I can't get the class out of system events.
	-- if those windows are laying inside the range, then the index has to be 
	-- skewed backwards, as the info windows are not considered.
	-- I don't dare closing them, after having closed finder windows,
	-- which is the job I am to do.
	-- Finder windows must necessarily by laying after any info windows
	-- in the z-layering, with higher indicies.
	-- Skews the index, ensuring enough Finder windows will be saved.
	
	set toSkew to 0
	set tix to 1
	repeat with awnName in spaceWNames
		if tix < (ix + toSkew) then
			if contents of awnName contains "-info" then
				set toSkew to toSkew + 1
			else
				set tix to tix + 1
			end if
		else
			exit repeat
		end if
	end repeat
	
	-- Having found the skew factor, we add it to the 
	-- index of the layered windows.
	set ix to ix + toSkew
	
	-- Finds every window we want to keep, they may be in
	-- every SPACE
	set keepers to {}
	tell application "Finder"
		set keepers to (get its every Finder window whose index < (ix + 1)) as list
		set keepCt to (get count keepers)
		if keepCt < forSave then error "not enough Finder windows in this space"
		-- We prune out the windows from the list we obtained by 
		-- System Events, as we are to spare those.
		set toDel to spaceCT
		repeat with i from 1 to spaceCT
			copy position of (contents of item i of spaceWins) to sPos
			
			repeat with j from 1 to keepCt
				
				copy position of (contents of item j of keepers) to kPos
				
				if item 1 of sPos is equal to item 1 of kPos and (((item 2 of sPos) + 22) is equal to item 2 of kPos) then
					set item j of spaceWins to missing value
					set toDel to toDel - 1
					exit repeat
				end if
				
			end repeat
		end repeat
		
		-- Purges the Finderwindows we want to get rid of.
		set i to 0
		repeat with awinInSpace in spaceWins
			set i to i + 1
			if contents of awinInSpace is not missing value then
				
				repeat with aFwin in (get every Finder window)
					
					if name of contents of aFwin is contents of item i of spaceWNames and index of contents of aFwin > ix then
						set amatch to Finder window id (id of contents of aFwin)
						try
							if operation is "close" then
								close amatch
							else if operation is "collapse" then
								set collapsed of amatch to true
							else
								my displayErrorMessageAndDie("Wrong operation in pruneAllFinderWindowsInThisSpaceBut.", my stopIconFile)
							end if
						end try
						set toDel to toDel - 1
						exit repeat
					end if
					if toDel is 0 then exit repeat
				end repeat
			end if
		end repeat
		-- if there were other windows like info windows, then they would be spared
	end tell
end pruneAllFinderWindowsInThisSpaceBut

to pruneEverFinderWindowsInThisSpace by operation
	set spaceWNames to {}
	-- we fetch references to its finder windows in THIS SPACE
	-- This is apliccable to other applicatons
	-- How to get the positon, may vary, but the logic, or lack of, stands!
	tell application "System Events" to tell process "Finder"
		
		set wc to (get count its every window)
		repeat with i from 1 to wc
			copy (get name of its window i) to end of spaceWNames
		end repeat
	end tell
	
	set spaceCT to (get count spaceWNames)
	
	-- Actually I bail out if the main preferences window is open.
	-- Folder preferences windows, are out of the loop, when using system events.
	-- And it does us no good, to look for them globally. (by finder).
	set foundIt to false
	repeat with awnName in spaceWNames
		tell application "Finder"
			try
				set wn to its preferences window awnName
				set foundIt to true
				exit repeat
			end try
		end tell
	end repeat
	
	if foundIt is true then
		my displayErrorMessageAndDie("The Finder preferences window is open.", my stopIconFile)
	end if
	
	tell application "Finder"
		repeat with i from 1 to (get count spaceWNames)
			
			repeat with aFwin in (get every Finder window)
				
				if name of contents of aFwin is contents of item i of spaceWNames then
					set amatch to Finder window id (id of contents of aFwin)
					try
						if operation is "close" then
							close amatch
						else if operation is "collapse" then
							set collapsed of amatch to true
						else
							my displayErrorMessageAndDie("Wrong operation in pruneEverFinderWindowsInThisSpace.", my stopIconFile)
						end if
					end try
					exit repeat
				end if
			end repeat
		end repeat
		-- if there were other windows like info windows, then they would be spared
	end tell
end pruneEverFinderWindowsInThisSpace



Enjoy!