Hi,
maybe its of interest and help for someone. I wrote it in less than a bunch of minutes, more for fun.
tell application "Finder"
set wins_nm to name of windows
set wins_id to windows
set sort_abc to my tagSort(wins_nm)
set close_w to {}
repeat with a from 1 to count wins_nm
try
set {after_f, c_nm} to {item (a + 1) of sort_abc, item a of sort_abc}
if after_f is c_nm then copy after_f to end of close_w
on error
exit repeat
end try
end repeat
set uniq_ls to {}
repeat with a in wins_id
set get_nm to name of a
if get_nm is in close_w and get_nm is not in uniq_ls then
copy get_nm to end of uniq_ls
close a
end if
end repeat
end tell
to tagSort(L) -- a general purpose simple sort; not enough tags to get fancy.
considering case
set sl to {}
set IL to {}
repeat (count L) times
set the low_item to ""
repeat with i from 1 to (count L)
if i is not in the IL then
set this_item to item i of L as text
if the low_item is "" then
set the low_item to this_item
set the low_item_index to i
else if this_item comes before the low_item then
set the low_item to this_item
set the low_item_index to i
end if
end if
end repeat
set the end of sl to the low_item
set the end of the IL to the low_item_index
end repeat
end considering
return sl
end tagSort
I remember last time when you said that everyone uses its own coding style. Or something close to this meaning.
Thats in substance the interesting factor looking at other scripters!
But sorry if I can’t follow you in the example you posted- and i’ll explain:
which is technically interesting but too time- consuming for such a little task when it comes the opportunity to close duplicate windows only.
I reworked my snippet and got a shorter code than before, considering spotlight searches too. I’m still unsure what you meant with “.considering spaces”. Duplicates are duplicates and as such they should be removed in all spaces, following the idea for which I conceived such a script. I don’t think that there are such many differences to simply close windows on OS 10.6.x or 10.8.x.
tell application "Finder"
set {wins_nm, wins_id} to {name, id} of windows
set {uniq_ls, nm_ls, cc} to {{}, {}, count wins_nm}
#controlling names is super-fast
repeat with a from 1 to cc
if item a of wins_nm is not in nm_ls then
copy item a of wins_nm to end of nm_ls
copy item a of wins_id to end of uniq_ls
end if
end repeat
#nothing found :)
if uniq_ls is {} then return
#close windows except spotlight searches
set ls to {}
repeat with a in wins_id
if a is not in uniq_ls and target of window id a is not "" then close window id a
end repeat
end tell
It only removes from the current space, since I believe it only should remove things you have control over. Say if you have split a project over several spaces. There may be a duplicate Finder window there that makes sense.
I understand what you mean, But at times with high intensity, I may end up with around 30 windows, and then the script pays off when removing duplicate windows, as it may take a conceived long time to do so without any form of optimization.
Hi,
i understand what you mean too. Being not a big fan of Spaces, but having nevertheless lots of windows on screen some times, i prefer to organize myself using the Dock and Applescripts.
My intention wasn’t to degrade your efforts of who is able to resolve the same problem with less code.
It also keeps the windows in the correct layering, deleting the oldest of the same windows.
Well, you have made me think, I know I can optimize it some further, as the date is not to be reused, so maybe I’ll have a another go, just for the hell of it.
I read McUsr’s hint on macosxhint last month and I came to similar conclusions as Joy did.
So I posted my version in the comments there. I also posted it here (updated from the one in the comment on macosxhints) with a fuller explanation of what I thought. And the pit falls of just using the windows Name.
set keepWindowList to {}
set closeWindowCount to 0
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")
(* icon to use with end dialogue *)
tell application "Finder"
set theWindowList to every Finder window (* get the list of finder windows*)
repeat with i from 1 to number of items in theWindowList (* iterate through each winodow *)
set this_item to item i of theWindowList (* get a winodow in the list*)
set windowID to id of this_item (* get the windows unique id*)
set windowTarget to target of this_item (* get the windows target*)
set windowName to name of this_item (* get the windows name *)
if target of this_item is computer container then (* Check if window is a computer container *)
if windowName is in keepWindowList then (* Check if the window name is in the keepWindowList *)
set closeWindowCount to closeWindowCount + 1 (* add 1 to the closeWindowCount if the window name is in the list *)
close this_item (* close the Window *)
else
copy windowName to end of keepWindowList (* The Window name was not in the list so add it to the list*)
end if
else if windowName contains "Searching " then (* The Window was not a computer container so check if its a Search window*)
if windowName is in keepWindowList then (* Check if the window name is in the keepWindowList *)
set closeWindowCount to closeWindowCount + 1 (* add 1 to the closeWindowCount if the window name is in the list *)
close this_item (* close the Window *)
else
copy windowName to end of keepWindowList (* The Window name was not in the list so add it to the list*)
end if
else (* The Window was not a computer container or a Search window so it should be a normal finder window*)
set windowNTargets to POSIX path of (windowTarget as alias) (*Convert the target to an alias path from a file system item reference and then get its Posix path*)
if windowNTargets is in keepWindowList then (* Check if the window Target is in the keepWindowList *)
set closeWindowCount to closeWindowCount + 1 (* add 1 to the closeWindowCount if the window Target is in the list *)
close this_item (* close the Window *)
else
copy windowNTargets to end of keepWindowList (* The Window target was not in the list so add it to the list*)
end if
end if
end repeat
end tell
There are something that has been overlooked by me in this, I should have stated, and put with the hack for showing full pathnames of the windows. As that is my reality, and then the problem with identical filenames works.
The reason for the complexity, is to just deliver the names in the current space. At least under some configurations, Finder will deliver all the windows for all spaces, whereas System Events only gives the windows for the current space.
Given the reality above, with pathnames as windows name, at least parts of the complexity can be justified. But it is still possible to optimize it further. Your approach on the other hand will as far as I can see close windows in all spaces, which was what I wanted to avoid in the first place.
Hi MacUsr, mark hunte,
i never thought that somebody would take this topic so seriously.
Nice, so noting becomes trivial in scripting. In the meantime i modified my script, after reading the blog post of mark and following the suggestions of MacUsr. Now the script closes finder windows in the current space only, considering locations and excluding spotlight search windows
#consider finder windows in current space only
tell application "System Events" to set spaces_win to name of windows of process "Finder"
tell application "Finder"
#sort unique paths and get duplicate locations, exclude spotlight searches
set {id_ls, pt_ls} to {{}, {}}
repeat with a in spaces_win
set {the_id, the_pt} to {id, target} of window a
set the_pt to (the_pt as text)
if the_pt is not in pt_ls then
copy the_pt to end of pt_ls
else
if the_pt is not "" then copy the_id to end of id_ls
end if
end repeat
if id_ls is {} then return
#finally, close finder windows
repeat with b in id_ls
close window id b
end repeat
end tell
I’m sure both scripts could be joined up with a dialog to ask if to close in a single space or all.
the simplest way is to put both scripts in a handler each. And then use…
display dialog "Close Duplicates in." buttons {"Current Space only", "All Spaces", "Cancel"} default button 3
set the button_pressed to the button returned of the result
if the button_pressed is "Current Space only" then
my joyScript()
else if the button_pressed is "All Spaces" then
my markScript()
end if
I wanted to time your script against mine, but for some odd reason the line with id, target fails.
@ Mark. I hope you update your blog, given the information above. And your script fails to, I get the message: “Can’t make «class alia» “” of application “Finder” into type alias.”
It is the line:
set windowNTargets to POSIX path of (windowTarget as alias) (*Convert the target to an alias path from a file system item reference and then get its Posix path*)
That fails for some odd reason. I think the reason to be, but aren’t sure it is because I have bundles open.
(On my machine, my script uses around 2 seconds to close 18 duplicate windows.)
Hi,
i wrote a final version.
This one should definitively work:
-added a dialog as mark hunte’s suggested.
-ignore spotlight windows, *Clipping- windows
-consider locations
-consider spaces
tell application "Finder" to set finder_icon to path to resource "Finder.icns"
try
set button_pressed to button returned of (display dialog "Close window Duplicates in." buttons {"Current Space only", "All Spaces", "Cancel"} default button 3 with icon finder_icon)
on error number the err
if err is -128 then return
end try
if button_pressed is "Current Space only" then
tell application "System Events" to set spaces_win to name of windows of process "Finder"
else
set spaces_win to 0
end if
tell application "Finder"
set { pt_ls, open_wins} to { {}, windows}
repeat with a in open_wins
if name of a does not end with "Clipping" then
set {the_id, the_pt} to {id, target} of a
set the_pt to (the_pt as text)
if the_pt is not in pt_ls then
copy the_pt to end of pt_ls
else
if spaces_win is 0 then
if the_pt is not "" then close a
else
if name of a is in spaces_win and the_pt is not "" then close a
end if
end if
end if
end repeat
end tell
i’m sorry, but the script compiles well and runs smootly on my machine. I’ll encourage you to debug the conflicting line as it is necessary for the continuation of the script.
try to split the finder window values in two lines:
set the_id to id of a
set the_pt to target of a as text
instead of
set {the_id, the_pt} to {id, target} of a
set the_pt to (the_pt as text)
Does it work well on your machine when you have open Finder windows into applications and bundles?
It is no big deal really, I just wanted to time them, out of curiousity. It is just that I have such windows open all the time.
Edit: Are you using 10.8? Because it doesn’t work for me with 10.6, with regular finder windows, containing regular folders, when I run from within Script Debugger 4.5.7.
Hi mark,
i did my best to help us all, first. The question is more, if the script working for you ?
The script i wrote considers and plays with window names simply.
tell application "System Events" to set spaces_win to name of windows of process "Finder"
Given the script i wrote, everybody should be able to adjust the variables and lines he/she dislikes. Other solutions aren’t that far, i think.
Since your script doesn’t do what mine does, I wonder if you can adjust your blog-post a tad.
You should also speed-test it. If I have say 30 windows open, and then opens 20 windows that are alike, my script closes the duplicate windows in 2 secs, on my machine.