Home Link

Hello, my name is Brett Terpstra, and it’s nice to meet you. Elegant solutions to complex problems. Curious?

Quick tip: AppleScript application toggle

Quick tip: AppleScript application toggle Tagged:
Jan 22, 2011 (393 days ago)

Tophat and wand

From my hat full of stupid Mac tricks:

I use a lesser-known (and very old) program called Spark for defining most of the keyboard shortcuts on my system. I have a shortcut for every one of my most regularly-used applications, plus shortcuts for various AppleScripts, shell scripts, system functions, etc. I know there are more recent applications which do the same thing, but I’ve had everything set up in Spark for ages and it still works a treat. Seriously, if you want an application launcher, it’s worth checking out (and free). However, you can use this tip in any app which lets you assign a hotkey to an AppleScript (FastScripts, BetterTouchTool).

So, anyway, I’ve grown to like applications which have a system-wide hotkey that toggles them between foreground and hidden. It makes a lot of sense for certain applications which you check and then move on from. Sparrow, Twitter, etc. I wanted that functionality in more apps, so I run this as the AppleScript in Spark, replacing the app name with whatever I want to toggle.

set appName to "Mail"
 
set appID to bundle identifier of (info for (path to application appName))
tell application "System Events"
	if not (exists process appName) then
		tell application appID to activate
	else
		if frontmost of process appName then
			set visible of process appName to false
		else
			set frontmost of process appName to true
		end if
	end if
end tell

Sorry about the do shell script for launching the app. I’m really lazy about replacing more than one instance of a variable, and “tell application appName” doesn’t work, even with various “using terms from” attempts. Know how to fix that? Let me know. Thanks to D Curtis and Zettt in the comments, I’ve put together a more elegant script. It does the same thing without shelling out, and the syntax is cleaned up. Thanks guys!

One more update: after some testing, it looks like D Curtis’ first script below is much faster for some reason (I’m assuming that getting the “bundle identifier of (info for (path to application appName))” takes some extra resources). I recommend going with this one instead, but I’m leaving both up for reference:

set appName to "Mail"
set startIt to false
tell application "System Events"
	if not (exists process appName) then
		set startIt to true
	else if frontmost of process appName then
		set visible of process appName to false
	else
		set frontmost of process appName to true
	end if
end tell
if startIt then
	tell application appName to activate
end if

9 Responses to “Quick tip: AppleScript application toggle”

  1. D Curtis says:

    This is a very weird bug. Seems like it just doesn’t want to work inside the System Events tell. If you do the following it works. It’s kinda ugly but I think it’s because if you do a tell inside another tell then the second goes through the first. So in the original you’re telling System Events to tell Mail to activate.

    set appName to "Mail"
    set startIt to false
    tell application "System Events"
      if not (exists process appName) then
        set startIt to true
      else if frontmost of process appName then
        set visible of process appName to false
      else
        set frontmost of process appName to true
      end if
    end tell
    if startIt then
      tell application appName to activate
    end if
    

    But what’s even more weird is that this works,

    set appName to "Mail"
    set startIt to false
    tell application "System Events"
        if not (exists process appName) then
            tell application "Mail" to activate
        else if frontmost of process appName then
            set visible of process appName to false
        else
            set frontmost of process appName to true
        end if
    end tell
    if startIt then
        tell application appName to activate
    end if
    

    but this does not work as you probably already know,

    set appName to "Mail"
    
    tell application "System Events"
      if not (exists process appName) then
        tell application appName to activate
      else if frontmost of process appName then
        set visible of process appName to false
      else
        set frontmost of process appName to true
      end if
    end tell
    

    Also you can use exists instead of name of every process ...

  2. Zettt says:

    Interesting problem. The solution is a bit awkward, but I got it working. (Launch By Creator or Identifier )

    set appName to bundle identifier of (info for (path to application "Mail"))
    
  3. Zettt says:

    Final solution. Don’t know whether this is better than other solutions. I guess it is one way to do it …

    set appName to "Safari"
    set alreadyLaunched to false
    
    tell application "System Events"
        if not (exists process appName) then
            set alreadyLaunched to false
        else
            set alreadyLaunched to true
        end if
        set frontmostApp to name of the first process whose frontmost is true
    end tell
    
    if alreadyLaunched is false then
        tell application appName to launch
    else if alreadyLaunched is true then
        if frontmostApp is equal to appName then
            tell application "System Events" to set visible of process appName to false
        else
            tell application appName to activate
        end if
    end if
    
    • D Curtis says:

      @Zett activate will bring the app to the front whether it is open or not. So really, all you need to do is check if the app you’re looking for is frontmost. If it is, you hide it. If it isn’t, you activate it. Ideally this should work but I don’t care enough anymore to test it.

      set appName to "Mail"
      set needsActivation to false
      tell application "System Events"
        if frontmost of process appName then
          set visible of process appName to false
        else
          set needsActivation to true
        end if
      end tell
      
      if needsActivation then
        tell application appName to activate
      end if
      
  4. Seriously Brett, this is all kinds of awesome. This is like the umpteenth time I’ve wished for a feature of some kind, only to have it solved by what is for you, merely a “quick tip”.

  5. It would be fantastic to be able to set global hotkeys to jump to specific tabs in Chrome. My first 3 tabs in Chrome are Personal Gmail, Work Gmail, and FogBugz. I’d love the ability to jump directly to one of those three using a keyboard shortcut.

    It seems to me that it should be possible to modify the application toggle script to add a “command-1″ sent to the app once it displays. That would solve the problem for me. It seems trivially easy, but my experience is that things that seem like easy changes rarely are.

    I’m trying to use variations of:

    tell application "System Events" to keystroke "1" using command down
    

    in various spots in the script, but in testing it doesn’t ever seem to respond by switching the active tab.

    Any chance someone reading this would be able to help me with how to do this?

  6. […] started with two snippets of AppleScript, one for toggling the visibility of an app, and one for answering Skype with a hotkey. The code on these pages isn’t mine, though […]

  7. Ric Zito says:

    Hi there,

    I’m coming to this thread very late, but I find it interesting because I too use Spark as my go-to hotkey app, and have done for years. It still works great, even on Lion. I just thought you might like to know that Spark has built in “Hide foreground” and “Hide others” actions : no need for Applescript or anything similar. It’s global (if you want it to be) so it works in ANY app, and plus, it’s much faster than Applescript.

    In Spark’s main window, just dbl-click “Application” in the sidebar, and in the slide-dwon sheet that appears, drop down the Action menu. There you’ll find the commands. I’ve set cmd-H and cmd-opt-H as my hotkeys. It works an absolute treat.

    cheers, Ric

  8. Ric Zito says:

    Sorry — I meant ctrl-H and ctrl-opt-H…

Thanks for reading!

Entries (RSS) and Comments (RSS), or Subscribe by Email