1

I have created an automator quick action that runs the following apple script

tell application "System Events"
    set frontApp to name of first application process whose frontmost is true --retrieves name of open application
end tell

tell application frontApp
    repeat while window 2 exists
        close window 2
    end repeat
end tell

It works; however, it takes a while to run if I have a lot of windows open.

Is there a way to close all windows simultaneously except for the frontmost one?

I typed in tell application "Finder" to close every window from 2 to 5 After I compiled it, it automatically changed to tell application "Finder" to close ( windows 2 thru 5 ). However, I get the error message error "Finder got an error: Can’t get windows 2 thru 3." number -1728 from windows 2 thru 3. So, then, it accepts the structure of the command, but I'm still missing something.

Edit: I tried the following script

tell application "Finder"
    close (every window where index is greater than 1)
end tell

However, I get the error "Finder got an error: Handler can’t handle objects of this class." number -10010

Why does this not work?

1
  • @user3439894 Sorry, I entered the code in wrong. I have now changed tell application "Finder" to tell application frontApp. This code is meant to be run as an Automator service. It has to first retrieve the name of the frontmost application because it needs to be able to run for any application. Commented Dec 4, 2019 at 23:23

3 Answers 3

1

Please try this. It might run faster. (edited my original answer with new code).

tell application "Finder"

    set theWindows to {}
    set theCount to (count of windows)
    if theCount is greater than 1 then
        repeat with i from 2 to theCount
            set theWindow to window i
            copy theWindow to end of theWindows
        end repeat
        close theWindows
    end if
end tell
14
  • It works, although it is just as slow as the original version. I'm still looking for a faster method. Commented Dec 4, 2019 at 22:47
  • @PeterSchorn I edited my answer with new code. Please try that. Commented Dec 5, 2019 at 0:02
  • 2
    It worked. You're a god damn genius. Commented Dec 5, 2019 at 0:12
  • Oh, wait. I spoke too soon. This only works with Finder. If I try it with another application, I get [Application] got an error: Can’t make {window id 39921, window id 39922} into type specifier. I think the problem is that the script is referring to the windows by their ID, rather than by their index. Commented Dec 5, 2019 at 0:27
  • 1
    Your code does EXACTLY what I want—except it only worked with the Finder application. Have you tried it with other applications to see if you get the same error I mentioned in a comment above? By the way, I really appreciate all the effort you're putting into this. Commented Dec 5, 2019 at 6:14
5

If you're running it as an Automator quick action, then you can close all windows except the frontmost window of the frontmost application by using the code below inside a Run AppleScript action (you can delete any sample code that appears, including on run {input, parameters}...end run:

tell application id "com.apple.SystemEvents" to tell the first process ¬
    whose frontmost = true to tell a reference to windows 2 thru -1 to ¬
    if exists then tell the value of attribute "AXCloseButton" to click
10
  • 1
    This should be the accepted answer. Commented Dec 6, 2019 at 18:36
  • All solutions which use one tell to System Events to get the name of the frontmost app and then another tell to the frontmost application by explicit name as determined have a big downside since the increased automation security introduced in macOS Catalina: For each app where you trigger your quick action you must give permission that app X can control System Events: Privacy > Automation > App XXX [√] System Events, App YYY [√] System Events, etc… Sadly the seemingly intuitive tell frontmost application inside an AppleScript inside a Quick Action is not supported. Any solutions?
    – porg
    Commented Apr 24, 2022 at 15:41
  • @porg That's why one shouldn't use System Events to get the frontmost application if all you need is the frontmost application. It's used here because System Events would be needed for any AppleScript solution to work on applications that aren't scriptable. If one knows in advance that the application is scriptable, then do this: tell the app named (path to frontmost application) to tell ref windows 2 thru -1 to if exists then close
    – CJK
    Commented Apr 30, 2022 at 3:41
  • @CJK thx for the explanation! My AppleScript throws a dialog to resize the frontmost window in the frontmost app with set the bounds of the front window to {x1, y1, x1 + xInputEvaluated, y1 + yInpEvaluated}. Apps which fail with Can’t get bounds of window 1 (cross-platform apps like LossLessCut, Visual Studio Code, qView) or even more rudimentary with Can’t get window 1. (e.g. ImageOptim) fail anyhow, regardless whether telling them directly or via System Events. Changed my Quick Action AppleScript accordingly. Removed apps' permissions to control System Events at Privacy > Automation.
    – porg
    Commented May 2, 2022 at 9:28
  • @porg I'll clarify what I wrote in my previous comment, as it seems you're working off half the information. Applications are either AppleScriptable (aka. "scriptable"), or they aren't. An app that is scriptable can be controlled natively with AppleScript, which for what we're talking about, means window 1 will be a defined object, and it will have a property called bounds allowing changing of window size/position. For all other apps, window is not defined, hence bounds will also not be defined. Cont'd...
    – CJK
    Commented May 8, 2022 at 8:20
0

I don't expect this to work for every app but it should for any scriptable app. NB Some apps have invisible windows (e.g. omnioutliner has various 'license' windows) so I've added a filtre to only include 'visible' windows. Perhaps that will cause the script to break on some apps. I've tested it on the Finder and OO.

tell application "System Events"
    set frontApp to name of first application process whose frontmost is true
end tell

tell application frontApp
    
    set ab to windows whose visible is true
    set bc to rest of ab
    
    try
        close bc
    on error
        repeat with y in bc
            close y
        end repeat
    end try
    
end tell

In general, the frontmost window has an index of 1. So this script makes a list of visible windows and then uses the 'rest' command to make a second list of every item after the first from list 1 (i.e. not window 1).

Awkwardly, different applications implement 'close' differently. With the Finder you can close a list of windows, with OO you cannot — it generates a -1700 error. So the last part of the script tries to close the list of windows and if that generates an error, it cycles through the list, closing each window sequentially.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .