close 'duplicate' finder windows - just for fun

It is a bit exciting, isn’t it?

First of all, I reckon I have to code this as dirty as it need be. Should it prove to be faster to have 3-4 dangling lists, related to eachother by index, and removing items by 3-4 statements, without any handler calls, then so be it.

I’ll use this for figuring out if there are path names, or just the names in the title bars:


set pathinTitles to false
try
	set pathinTitles to do shell script "defaults read com.apple.finder _FXShowPosixPathInTitle" as boolean
end try

Then there is the classification of windows, I am not sure about mounted volumes, the Finder Preferences window, or if info windows of files and folders show up as windows, or if they indeed are panels.

What I am sure of, is that every window in a space, are layered before any windows in any other space, so this time, the sole call to system events will be:

tell application id "sevs" to tell application process "Finder" to set finderWinCountCurSpace to count its windows

What to do with the superfluos windows obtained by

tell application id "MACS"  to set allFinderWinCount to count its windows

Is something I haven’t dealt with yet. I’ll figure something out.

(I believe I go faster through the Launch Services database by using creator code, than anything else.)

I am also going to put in some comment this time, but just a few.

I am also going to time alternative solutions during the weekend with getMillisec so you have to be patient. :slight_smile:

Hello!

Joys script used 3, then 4 seconds, with the count dialog decoupled, mine did indeed use 5, then 5, Marks didn’t run for some reason. 20 duplicate windows, 19 were closed, with a total of 59 windows open when the scripts were run.

I’ll just say that I do things with the targets of the finder windows, in order to have something to unique to work from that works in every situation. And that the script should be fairly robust, and work from whatever app.

Working with the targets of windows, and coercing finder references into aliases, must necessarily be a bit more expensive, than dealing with just text, but that is the only way you can assure that you have unique windows when you have, as the windows won’t be unique when using “normal” window titles, and two subfolders are carrying the same name.

It considers Finder windows only, so I don’t deal with clippings windows, not knowing if it is possible to open duplicates of those anyway. But it do consider computer windows, and spotlight windows in current space.

Here it is, working so far, maybe I’ll try to optimize the loop further, and see if I can shave off more here. I doubt I can shave off more in the loops, but I’ll give it a try!

Edit

I am pondering adding the old part of my script as curtsey to those using posix paths in their window title, in the mean time, while I am pondering this, I have added a dialog, like a progress dialog, to show that something is indeed happening, leveraging on “ignoring application responses”, to show users (me), that something are progressing.

Edit+

Added three comments.


script pruneDupFWins
	-- © McUsr 2012 28.10.2012 completely rewritten to cope with all cases of window titles, and computer windows
	property parent : AppleScript
	property scriptTitle : "Close Duplicate Windows"
	property FinderIcon : a reference to file ((path to library folder from system domain as text) & "CoreServices:Finder.app:Contents:Resources:Finder.icns")
	
	# COLLECTING NECESSARY DATA
	# fastest way to make SystemEvents, get the window count for the windows appearing in the current space.
	local fwc, clcount, prevApp # Finder Window Count, close count
	
	
	set clount to 0
	try
		tell application id "sevs"
			set prevApp to (name of every process whose frontmost is true and visible is true) as text
			tell application process "Finder" to set fwc to count its windows
		end tell
		if fwc = 0 then return 0
	on error
		return 0 # Finder wasn't running!
	end try
	if fwc > 10 then
		ignoring application responses
			tell application id "com.apple.systemuiserver"
				activate
				try # 
					display dialog "Finding Duplicate Finder Windows in current space..." with title my scriptTitle buttons {"Ok"} default button 1 with icon my FinderIcon giving up after (fwc div 10)
				end try
			end tell
		end ignoring
	end if
	# script for enhancing speed, not needed really 
	script o
		property ides : {} # ides of wins
		property targs : {} # targets
		property tmpTargs : {} # third pair of  tmp lists !
		property tmpIdes : {}
	end script
	local startTargs, startIdes # firs pair of tmp lists for collecting
	# collecting targets and ids of Finders windows, as fast as possible.
	tell application id "MACS"
		set {startTargs, startIdes} to {target, id} of its every Finder window
	end tell
	
	# PREPROCESSING OF FINDER-DATA BEFORE WE CAN LOOK FOR DUPLICATES
	# we have to convert the Targets into text, The spotlight windows, just disappears in the process
	# as we get a runtime error, «class ccmp» is a way to say computer-object outside a finder tell block.
	local curtag, siftedTargs, siftedIdes # second pair of tmplists for sifting and preparing
	set {o's targs, o's ides, siftedTargs, siftedIdes} to {startTargs, startIdes, {}, {}}
	repeat with i from 1 to length of startTargs
		try
			set curTarg to item i of o's targs # curtag used for minimizing references
			set end of siftedTargs to curTarg as alias -- as text
			set end of siftedIdes to item i of o's ides
		on error
			try
				if class of curTarg = «class ccmp» then
					set end of siftedTargs to "Computer"
					set end of siftedIdes to item i of o's ides
				end if
			end try
		end try
	end repeat
	set {startTargs, startIdes} to {missing value, missing value}
	
	# Finding the last finder window in our space, we have grabbed THEM all. Finder windows in other spaces
	# has a higher index, than our last window number as obtained from system events.
	local fwcAdj # Finder window count . Adjusted 
	set {o's ides, fwcAdj} to {siftedIdes, length of siftedIdes}
	tell application id "MACS"
		repeat
			tell its Finder window id (item fwcAdj of o's ides) to if index of it > fwc then
				set fwcAdj to fwcAdj - 1
			else
				exit repeat
			end if
		end repeat
	end tell
	set fwc to fwcAdj
	# This count are the fwc first windows  in our list we must consider for pruning duplicates of  here.
	# SIFTING OUT ANY DUPLICATE FINDER WINDOWS
	set {o's ides, o's targs} to {items 1 thru fwc of siftedIdes, items 1 thru fwc of siftedTargs}
	
	local tids, searchlist, idx, idList # used for having a searchlist, and the index for found elements
	# idlist is the list of ids of finder windows we are going to close 
	set {tids, idList} to {AppleScript's text item delimiters, {}}
        # What happens here, is that we take each line of the list of finder windows, chops it off the list
        # and looks for duplicates, which corresponding id's are put onto the idlist for closure.
        # we just churn thru the whole list until all duplicates are removed as fast as possible.
        # if anybody has an idea of a faster way, I am all ears!
	repeat
		# this construct will fail when there are only one item left on the list.
		try
			set {searchItm, o's targs, o's ides} to {item 1 of o's targs, items 2 thru -1 of o's targs, items 2 thru -1 of o's ides}
			set searchlist to o's targs
			# an inlined handler indexofItem by Emmanuel Levy
			set AppleScript's text item delimiters to return
			set searchlist to return & searchlist & return
			set AppleScript's text item delimiters to ""
			try
				set idx to -1 + (count (paragraphs of (text 1 thru (offset of (return & searchItm & return) in searchlist) of searchlist)))
			on error
				set idx to 0
			end try
			
			repeat while idx > 0
				set end of idList to item idx of o's ides
				if idx = 1 then
					set {o's targs, o's ides} to {rest of o's targs, rest of o's ides}
				else if idx = length of o's targs then
					set {o's targs, o's ides} to {items 1 thru -2 of o's targs, items 1 thru -2 of o's ides}
				else
					set {o's targs, o's ides} to {items 1 thru (idx - 1) of o's targs & items (idx + 1) thru -1 of o's targs, items 1 thru (idx - 1) of o's ides & items (idx + 1) thru -1 of o's ides}
				end if
				set searchlist to o's targs
				# an inlined handler indexofItem by Emmanuel Levy
				set AppleScript's text item delimiters to return
				set searchlist to return & searchlist & return
				set AppleScript's text item delimiters to ""
				try
					set idx to -1 + (count (paragraphs of (text 1 thru (offset of (return & searchItm & return) in searchlist) of searchlist)))
				on error
					set idx to 0
				end try
			end repeat
			
		on error
			exit repeat
		end try
	end repeat
	
	set AppleScript's text item delimiters to tids
	# CLOSING ANY DUPLICATE FINDER WINDOWS
	set clcount to length of idList
	if clcount ≠ 0 then
		tell application id "MACS"
			repeat with wid in idList
				tell its Finder window id wid to close
			end repeat
		end tell
		if clcount = 1 then
			set msgText to "I closed 1 window!"
		else
			set msgText to "I closed " & clcount & " windows!"
		end if
	else
		set msgText to "Nothing to do!"
	end if
	tell application id "MACS"
		activate
		try # comment out the line below when testing for speed
			display dialog msgText with title my scriptTitle buttons {"Ok"} default button 1 with icon my FinderIcon giving up after 1.2
		end try
	end tell
	tell application prevApp to activate
end script
# set t1 to (current date)
tell pruneDupFWins to run
(*
set t2 to (current date) - t1
tell application "Finder"
	activate
	display dialog "message " & t2
end tell
*)

It is fun. :slight_smile:

I just realized I can make the script above run 2-3 seconds faster, by starting using names instead of targets. :smiley:

Sifting out all computer windows, while I sift out spotlight windows.

And only comparing targets, when I look for duplicates, and finds a matching name.

I’ll come back with this, with a merged edition, that handles both posix pathnames, and regular folder names as windows title. Just like the script above, but this time, I’ll minimize the usage of targets of windows.

Now it uses no more than 3 seconds for both cases, with dialogs, 39 unique windows, 20 duplicates, no more than 2 seconds when the dialogs are removed.

It handles all cases for window titles with and without posix paths in them, Spotlight windows, Computer Windows, and identical window titles, when posix paths are not used.

Should anybody find bugs or anything, please let me know! :slight_smile:


script pruneDupFWins
	-- © McUsr 2012 28.10.2012 completely rewritten to cope with all cases of window titles, and computer windows
	property parent : AppleScript
	property scriptTitle : "Close Duplicate Windows"
	property FinderIcon : a reference to file ((path to library folder from system domain as text) & "CoreServices:Finder.app:Contents:Resources:Finder.icns")
	
	# COLLECTING NECESSARY DATA
	# fastest way to make SystemEvents, get the window count for the windows appearing in the current space.
	local fwc, clcount, prevApp, pathInTitles # Finder Window Count, close count
	set pathInTitles to false
	try
		set pathInTitles to (do shell script "defaults read com.apple.finder _FXShowPosixPathInTitle") as number as  boolean
	end try
	try
		tell application id "sevs"
			if not (UI elements enabled) then set (UI elements enabled) to true (* to be sure than GUI scripting will be active Yvan Koenig*)
			set prevApp to (name of every process whose frontmost is true and visible is true) as text
			tell application process "Finder"
				if visible of it is false then set visible of it to true
				set fwc to count its windows
			end tell
		end tell
		if fwc = 0 then return 0
	on error
		return 0 # Finder wasn't running!
	end try
	if fwc > 20 then
		ignoring application responses
			tell application id "com.apple.systemuiserver"
				activate
				try # 
					display dialog "Finding Duplicate Finder Windows in current space..." with title my scriptTitle buttons {"Ok"} default button 1 with icon my FinderIcon giving up after ((fwc div 10) - 1)
				end try
			end tell
		end ignoring
	end if
	
	# COLLECTING THE FINDER WINDOWS
	
	
	script o # script for enhancing speed, not needed really 
		property ides : {} # ides of wins
		property targs : {} # targets
		property tmpTargs : {} # third pair of  tmp lists !
		property tmpIdes : {}
	end script
	
	
	local startTargs, startIdes # first pair of tmp lists for collecting
	
	tell application id "MACS" # collecting targets and ids of Finders windows, as fast as possible.
		set {startTargs, startIdes} to {name, id} of its every Finder window
	end tell
	
	# PREPROCESSING OF FINDER-DATA BEFORE WE CAN LOOK FOR DUPLICATES
	
	# Finding the last finder window in our space, we have grabbed THEM all. Possibly to many, if we have open
	# file info windows and such in this space. Finder windows in other spaces has a higher index, than our 
	# window count as obtained from System Events.
	
	local fwcAdj # Finder window count . Adjusted 
	set {o's ides, fwcAdj} to {items 1 thru fwc of startIdes, fwc}
	tell application id "MACS"
		repeat
			tell its Finder window id (item fwcAdj of o's ides) to if index of it > fwc then
				set fwcAdj to fwcAdj - 1
			else
				exit repeat
			end if
		end repeat
	end tell
	
	if fwcAdj = 0 then return 0
	
	set {o's targs, o's ides} to {items 1 thru fwcAdj of startTargs, items 1 thru fwcAdj of startIdes}
	
	if pathInTitles = true then
		# Sifting out any computer windows.
		# we have to convert the Targets into text, The spotlight windows, just disappears in the process
		# as we get a runtime error, «class ccmp» is a way to say computer-object outside a finder tell block.
		local curId, siftedTargs, siftedIdes, hadCompWin, curWinCount # second pair of tmplists for sifting and preparing
		
		set {siftedTargs, siftedIdes, hadCompWin, curWinCount} to {{}, {}, false, fwcAdj}
		repeat with i from 1 to fwcAdj
			
			if (item i of o's targs) = "" then
				set curWinCount to curWinCount - 1
				try
					set curId to item i of o's ides # curtag used for minimizing references
					tell application id "MACS"
						if class of (target of (its Finder window id curId)) = computer-object then
							if hadCompWin = true then
								close Finder window id curId
							else
								set hadCompWin to true
							end if
						end if
					end tell
				end try
			else
				set end of siftedTargs to item i of o's targs
				set end of siftedIdes to item i of o's ides
			end if
		end repeat
		set fwcAdj to curWinCount
		if fwcAdj = 0 then return 0 # if there is nothing left, we'll leave the party!
		set {o's ides, o's targs} to {siftedIdes, siftedTargs}
		#		set {startTargs, startIdes} to {missing value, missing value}
	end if
	# no point in the above if we are not showing posix paths in the titles, as then text will show up!
	
	local searchTarg, searchIde, tids, searchlist, idx, idList, hadToSkip, skipList
	# used for having a searchlist, and the index for found elements
	# idlist is the list of ids of finder windows we are going to close 
	set {tids, idList} to {AppleScript's text item delimiters, {}}
	repeat
		# this construct will fail when there are only one item left on the list.
		try
			# start by removing blockers that we put on if we have to skip 
			
			set {searchTarg, searchIde, o's targs, o's ides} to {item 1 of o's targs, item 1 of o's ides, items 2 thru -1 of o's targs, items 2 thru -1 of o's ides}
			set searchlist to o's targs
			# an inlined handler indexofItem by Emmanuel Levy
			set AppleScript's text item delimiters to return
			set searchlist to return & searchlist & return
			set AppleScript's text item delimiters to ""
			try
				set idx to -1 + (count (paragraphs of (text 1 thru (offset of (return & searchTarg & return) in searchlist) of searchlist)))
				set {hadToSkip, skipList} to {false, {}}
			on error
				set idx to 0
			end try
			
			repeat while idx > 0
				local dontSkipit
				set dontSkipit to true
				# todo: når vi ikke har posix pathnames, så sjekker vi targets her, om det er samme target.
				# hvis det ikke er det, så er index fortsatt ulik 0, så vi fortsetter å sammenligne...
				if pathInTitles = true then
					set end of idList to item idx of o's ides
				else
					try
						tell application id "MACS" to if (target of (Finder window id searchIde)) = (target of (Finder window id (item idx of o's ides))) then
							set end of idList to item idx of o's ides
						else
							set {dontSkipit, hadToSkip, end of skipList} to {false, true, idx}
						end if
					on error
						# spotlight windows 
						set {dontSkipit, hadToSkip, end of skipList} to {false, true, idx}
					end try
				end if
				if dontSkipit then
					if idx = 1 then
						set {o's targs, o's ides} to {rest of o's targs, rest of o's ides}
					else if idx = length of o's targs then
						set {o's targs, o's ides} to {items 1 thru -2 of o's targs, items 1 thru -2 of o's ides}
					else
						set {o's targs, o's ides} to {items 1 thru (idx - 1) of o's targs & items (idx + 1) thru -1 of o's targs, items 1 thru (idx - 1) of o's ides & items (idx + 1) thru -1 of o's ides}
					end if
				else
					# we must skip it, as the name isn't denoting the same folder, we should still continue searching for others though
					set item idx of o's targs to "_@_" & item idx of o's targs
				end if
				set searchlist to o's targs
				set AppleScript's text item delimiters to return
				set searchlist to return & searchlist & return
				set AppleScript's text item delimiters to ""
				try
					set idx to -1 + (count (paragraphs of (text 1 thru (offset of (return & searchTarg & return) in searchlist) of searchlist)))
				on error
					set idx to 0
				end try
				
				if idx = 0 and hadToSkip = true then # have to remove our trick before we commence 
					repeat with skippedWindow in skipList
						local okTarg
						set AppleScript's text item delimiters to "_@_"
						set okTarg to text items of item skippedWindow of o's targs
						set AppleScript's text item delimiters to ""
						set item skippedWindow of o's targs to okTarg as text
					end repeat
				end if
			end repeat
			
		on error
			exit repeat
		end try
	end repeat
	
	set AppleScript's text item delimiters to tids
	
	set clcount to length of idList
	if clcount ≠ 0 then
		tell application id "MACS"
			repeat with wid in idList
				tell its Finder window id wid to close
			end repeat
		end tell
		if clcount = 1 then
			set msgText to "I closed 1 window!"
		else
			set msgText to "I closed " & clcount & " windows!"
		end if
	else
		set msgText to "Nothing to do!"
	end if
	tell application id "MACS"
		activate
		try # comment out the line below when testing for speed
			display dialog msgText with title my scriptTitle buttons {"Ok"} default button 1 with icon my FinderIcon giving up after 1.2
		end try
	end tell
	tell application prevApp to activate
end script

tell pruneDupFWins to run

Hello!

I’ll just toss in this script to toggle posix paths in the title of Finder windows on and off

script FinderPosixPaths
	set pathInTitles to false
   try
       set pathInTitles to (do shell script "defaults read com.apple.finder _FXShowPosixPathInTitle") as number as boolean
   end try
	if not pathInTitles then
		do shell script "defaults write com.apple.finder _FXShowPosixPathInTitle -bool YES; killAll Finder"
	else
		do shell script "defaults write com.apple.finder _FXShowPosixPathInTitle -bool NO; killAll Finder"
	end if
end script
tell FinderPosixPaths to run

The last script I posted runs fine on 10.6 and 10.8 it has no problem running on a standard Mac setup. !

The one think I did notice. Was anytime I messed with this command. My finder search would play up after. This included the contextual menu “Show in Finder”. Not showing in finder And I could not type in Mission Control search field. Only a reboot would fix it. It may just be my system reacting this way ?.

Hello!

I am sorry to hear that the last one makes trouble for you, it runs fine for me under Mac OsX 106. The blog I found the foundation for it, also stated that it worked for Mac Os X 10.8 (Show Full Directory Path in Mac OS X Finder Window Title Bars)

As for your script, I ran it in the debugger, and it generates a run time error under 10.6 when posix path of finder windows titles are enabled, when it finds a spotlight window.

It maybe a 10.8+ thing. I have used the code before with now issue.

Have not tested the script with posix-names on 10.6. If I get a min I will.

Worked ok in 10.6 with posix-names. cannot test it in debugger as I do not have it.

By the way you may want to add a try-on error block for the do shell script code.

Like many of Apples prefs. The absence of a entry will be the same as an entry with 0,No,False.

This is the case with _FXShowPosixPathInTitle. It does not normally exist.

So your script will return an error of does not exist on Macs that have never run the defaults write com.apple.finder _FXShowPosixPathInTitle -bool YES code before.

Hello.

Now, that is entirely correct, that if a default value isn’t set, then the do shell script will fail with an error.

I forgot that in the script above, but not in the script that closes duplicate windows.

Consider it fixed in the post above containing the script

Well, it didn’t on my machine, you can just add a try block to avoid it. That is catching Spotlight windows, as their target will fail, the moment you check for a target, as the alias in targets of spotlight windows are invalid, when posix paths are shown in the finder window titles (phew). (The targets of them are specified as alias file “” )

Edit

During the evening, I’ll post an updated version of the Finder window title script right here. As it is it makes you loose any Spotlight windows you have, which may not be convenient, if your queries are complex.


script FinderPosixPaths
#  © McUsr 2012 and put in public domain! You are not allowed to post this elsewhere, nor in a publicly accessible repository
# please refer to it by this link: http://macscripter.net/edit.php?id=157144
	property ScriptTitle : "ToggleFinderPosixPaths"
	property FinderIcon : a reference to file ((path to library folder from system domain as text) & "CoreServices:Finder.app:Contents:Resources:Finder.icns")
	
	on run
		local pathInTitles, hasSpotlightWindows
		set pathInTitles to false
		try
			set pathInTitles to (do shell script "defaults read com.apple.finder _FXShowPosixPathInTitle") as number as boolean
		end try
		set hasSpotlightWindows to false
		# figuring out if we have any spotlight windows
		script o # script for enhancing speed, not needed really 
			property ides : {} # ides of wins
			property targs : {} # targets
		end script
		
		tell application id "MACS" # collecting targets and ids of Finders windows, as fast as possible.
			set {o's targs, o's ides} to {name, id} of its every Finder window
			repeat with i from 1 to length of o's ides
				try
					set a to target of (its Finder window id (item i of o's ides)) as text
					# Just generating a run time error if there isn't a spotlight window, to signal that we got.
					
				on error
					if class of (target of (its Finder window id (item i of o's ides))) = computer-object then
					else
						set hasSpotlightWindows to true
					end if
				end try
			end repeat
		end tell
		local theAnswer
		if hasSpotlightWindows = true then
			with timeout of 301 seconds
				tell application "SystemUIServer"
					activate
					try
						set theAnswer to button returned of (display dialog "You have finder Spotlight windows open. Do you want to loose them by restarting Finder?" with title my ScriptTitle buttons {"No", "Yes"} cancel button 1 default button 1 with icon my FinderIcon giving up after 300)
					on error
						set theAnswer to "No"
					end try
				end tell
			end timeout
		else
			set theAnswer to "Yes"
		end if
		if theAnswer = "Yes" then
			if not pathInTitles then
				do shell script "defaults write com.apple.finder _FXShowPosixPathInTitle -bool YES; killAll Finder"
			else
				do shell script "defaults write com.apple.finder _FXShowPosixPathInTitle -bool NO; killAll Finder"
			end if
		end if
	end run
end script
tell FinderPosixPaths to run

1 Like

All Done! :slight_smile:

Edit

Should computer-object be turned into (system-attribute -object), when you compile, then you’ll have to enter «class ccmp» before compiling/saving.

That holds for both of my scripts.

Added a check for and promptly setting of UI Scripting enabled in my script in post #44 as it needs it to operate.

That was the hopefully very finishing touch!

Cool script!!

Thanks!

-Tim

Thank you. :slight_smile:

Closes duplicate windows and skips Spotlight search windows.

This is about as terse as I can get it.


tell application "Finder"
	set AppleScript's text item delimiters to linefeed
	tell windows
		if (get collapsed) contains true then set collapsed to false
		set {winID, winTarg} to {id, paragraphs of (target as text)}
	end tell
	repeat with i from 1 to length of winTarg
		set _win to item 1 of winTarg
		set winTarg to rest of winTarg
		if (_win is in winTarg) and (_win ≠ "") then close window id (item i of winID)
	end repeat
end tell

1 Like

Hello.

Yes it is terse, and certainly look better than rather long and complex script I wrote, but my script is differnt in that it only deals with the windows in the current space, and that it does that as fast as possible.

Your script seems to be as fast as mine (if I remove the dialog code), or faster, but I have no time for timing, at the moment, fast enough will do.

But it is amazing, to see that you achieve what you do in so few lines. And maybe having windows unique in all spaces will do. I have not leveraged much upon the possibility of having the same window in several spaces.