Centering Windows in Mac OS X with AppleScript

I can be a little OCD with the windows on my screen. I tend to line them up at the edges or try to center them in the display. Maybe it’s a bad habit, but it’s one I’m probably not going to shake any time soon, so the least I can do is try to avoid wasting too much time on it.

I found an AppleScript on GitHub for centering the frontmost window. It didn’t do quite what I wanted, so here’s my slightly-modified version, which will center the window in your screen horizontally without changing the vertical position or size.

tell application "Finder"
	set screenSize to bounds of window of desktop
	set screenWidth to item 3 of screenSize
end tell

tell application "System Events"
	set myFrontMost to name of first item of ¬
		(processes whose frontmost is true)
end tell

try
	tell application myFrontMost
		set windowSize to bounds of window 1
		set windowXl to item 1 of windowSize
		set windowYt to item 2 of windowSize
		set windowXr to item 3 of windowSize
		set windowYb to item 4 of windowSize
		
		set windowWidth to windowXr - windowXl
		
		set bounds of window 1 to {¬
			(screenWidth - windowWidth) / 2.0, ¬
			windowYt, ¬
			(screenWidth + windowWidth) / 2.0, ¬
			windowYb}
	end tell
end try

Paste this into Script Editor or download the script file. Put the file in ~/Library/Scripts. Make sure you’ve got the Script menu turned on in the AppleScript Utility application. It will show up in there, and should work in most Mac applications.

I have found a couple of limitations. It doesn’t seem to work at all with Firefox, which doesn’t have very complete AppleScript support. It’s likely that there are other applications out there with missing or incomplete AppleScript support that this won’t work for either. The second problem is that there’s a bug in the Terminal application that moves the window upwards, even though the script is written in a way that’s supposed to preserve the vertical position. It would be possible to work around this, but I decided that it didn’t bother me enough to clutter up the code. If you want a workaround, post a comment and I’ll give it a shot.

The original script doesn’t specify a license, so I hope it’s OK to modify and share it. I figure that, since it’s published on GitHub, and the author releases a lot of open source code under very liberal licenses, that he’s probably not intending to keep very tight control over it. My changes are offered to the public domain.

I’m just as obsessive with making sure objects are lined up straight on my (real life) desk top. Sadly, AppleScript can’t help me there.

Update, 15-Nov-2010: This continues to be a fairly popular post, which a lot of people seem to come across through search engines. See the comments below for tips about ensuring that the window size doesn’t change, and for centering vertically as well. I’ve also noticed that this fails on multi-display setups, centering between the two screens instead of on the current screen. I’ll try to come up with a fix for that.

17 comments

  1. Stakker

    Very cool, cheers! (I share the same alignment “problem” :-)
    I use Spark to launch the script with a keyboard shortcut myself.

    However, the script can actually change the horizontal window size by one pixel.

    This is noticeable with Pages if you size the window so that it’s exactly the width of the page (horizontal scroll bar disappears but no background gray appears yet). The script can sometimes make the window 1 pixel wider or narrower depending on the width of the window. Perhaps something to do with odd/even numbers?

    Yes, one pixel. But we’re already in freaky obsession territory here! :-) (In pages the one pixel is very noticeable since it makes an ugly dark line appear into the margin, instead of smooth white.)

    • Tim Moore

      Good catch, Stakker,

      That’s because windows with an odd-numbered pixel-width can’t be perfectly centered on a screen with an even number of pixels. Fractional pixel values get rounded automatically.

      If you want more control over the rounding, you can change this part:

          set bounds of window 1 to {¬
              (screenWidth - windowWidth) / 2.0, ¬
              windowYt, ¬
              (screenWidth + windowWidth) / 2.0, ¬
              windowYb}
      

      to something like this:

          set bounds of window 1 to {¬
              round ((screenWidth - windowWidth) / 2) rounding as taught in school, ¬
              windowYt, ¬
              round ((screenWidth + windowWidth) / 2) rounding as taught in school, ¬
              windowYb}
      

      It’s kind of wordy, but it tells AppleScript to always round .5 up. Normally, it rounds .5 towards the nearest even number.

      You can see full documentation for the different rounding options in the AppleScript 2.1 Help: round document on Apple’s site.

  2. Russ

    I love this script, but I’m new to Macs, and a total noob with scripts, so bear with me…

    If you have, for example, two Word documents open, the script will only apply itself to the document that was initially opened. You can’t toggle between windows and apply the script to the second document.

    Is there anyway to jig this script so that it will work with multiple windows of the same application after having switched to the second or subsequent document/window?

    • Tim Moore

      Russ,

      Normally it should work with whatever window is frontmost, but I can’t guarantee it will work properly in every application, because it depends on their support for AppleScript. I unfortunately don’t have a copy of Microsoft Word to test with, but if anyone has a solution, please let me know and I’ll update the post.

  3. Andrew Goodrick-Werner

    Thank you, Tim, this script is incredibly useful for obsessive people like us.

    I’m wondering if it would be at all possible to center windows vertically as well? I don’t know AppleScript, and can’t seem to figure this out. Ideally, I’d like my Mail, iTunes, Finder windows, etc. to be centered vertically between the dock and menu bar.

    • Tim Moore

      Thanks!

      It should be possible to make it center vertically using basically the same approach.

      Try this:

      tell application "Finder"
      	set screenSize to bounds of window of desktop
      	set screenWidth to item 3 of screenSize
      	set screenHeight to item 4 of screenSize
      end tell
      
      tell application "System Events"
      	set myFrontMost to name of first item of ¬
      		(processes whose frontmost is true)
      end tell
      
      try
      	tell application myFrontMost
      		set windowSize to bounds of window 1
      		set windowXl to item 1 of windowSize
      		set windowYt to item 2 of windowSize
      		set windowXr to item 3 of windowSize
      		set windowYb to item 4 of windowSize
      		
      		set windowWidth to windowXr - windowXl
      		set windowHeight to windowYb - windowYt
      		
      		set bounds of window 1 to {¬
      			round ((screenWidth - windowWidth) / 2) rounding as taught in school, ¬
      			round ((screenHeight - windowHeight) / 2) rounding as taught in school, ¬
      			round ((screenWidth + windowWidth) / 2) rounding as taught in school, ¬
      			round ((screenHeight + windowHeight) / 2) rounding as taught in school}
      	end tell
      end try
      
      • Andrew Goodrick-Werner

        Again, thanks so much – I feel SO nice knowing that this is possible; I’ve never even seen AppleScript until today! I eventually figured out how your version worked, and came up with the following:

        tell application "Finder"
        	set screenSize to bounds of window of desktop
        	set screenWidth to item 3 of screenSize
        	set screenHeight to item 4 of screenSize
        end tell
        
        tell application "System Events" to tell process "Dock"
        	set dockSize to size in list 1
        	set dockHeight to item 2 of dockSize
        end tell
        
        tell application "System Events"
        	set screenHeight to (screenHeight - dockHeight)
        	set myFrontMost to name of first item of ¬
        		(processes whose frontmost is true)
        end tell
        
        try
        	tell application myFrontMost
        		set windowSize to bounds of window 1
        		set windowXl to item 1 of windowSize
        		set windowYt to item 2 of windowSize
        		set windowXr to item 3 of windowSize
        		set windowYb to item 4 of windowSize
        		
        		set windowWidth to windowXr - windowXl
        		set windowHeight to windowYb - windowYt
        		
        		set bounds of window 1 to {¬
        			round ((screenWidth - windowWidth) / 2) rounding as taught in school, ¬
        			round ((screenHeight - windowHeight) / 2) rounding as taught in school, ¬
        			round ((screenWidth + windowWidth) / 2) rounding as taught in school, ¬
        			round ((screenHeight + windowHeight) / 2) rounding as taught in school}
        	end tell
        end try
        

        The two problems with what I’ve got are that Assistive Devices have to be enabled in System Preferences, and it’ll only work with the Dock on the bottom, but I never move mine anyway.

        Cheers! :)

  4. Axel

    Just wanted to say that this was incredibly helpful, as I’m new to Macs and as obsessive-compulsive about placement as you are. Thanks!

  5. Andrew Goodrick-Werner

    Also, here’s a tip I’ve found to be extremely useful.

    You can make this AppleScript a Service that is accessible from any application’s menu in the Menu Bar. Open Automator, create a new Service — setting the options at the top to “no input” and “any application” — drag “Run AppleScript” into the workflow, and paste one of the scripts posted above into the text field. Save the Service, and run it from the Services menu in the Menu Bar.

    I prefer this method to having the Scripts menu always visible in my menu bar, since this is the only AppleScript I use regularly.

  6. Tim Moore

    I found a post on Stack Exchange that links to this post but asks about the issue with the Terminal. It’s just a bug in Terminal’s Apple Events support, but there is a workaround. Here it is:

    tell application "Finder"
    	set screenSize to bounds of window of desktop
    	set screenWidth to item 3 of screenSize
    	set screenHeight to item 4 of screenSize
    end tell
    
    tell application "System Events"
    	set myFrontMost to name of first item of ¬
    		(processes whose frontmost is true)
    end tell
    
    try
    	tell application myFrontMost
    		set windowSize to bounds of window 1
    		set windowXl to item 1 of windowSize
    		set windowYt to item 2 of windowSize
    		set windowXr to item 3 of windowSize
    		set windowYb to item 4 of windowSize
    		
    		set windowWidth to windowXr - windowXl
    		set windowHeight to windowYb - windowYt
    		
    		if myFrontMost is "Terminal" then
    			set bounds of window 1 to {¬
    				round ((screenWidth - windowWidth) / 2) rounding as taught in school, ¬
    				round ((screenHeight + windowHeight) / 2) rounding as taught in school, ¬
    				round ((screenWidth + windowWidth) / 2) rounding as taught in school, ¬
    				round ((screenHeight + windowHeight) / 2 + windowHeight) rounding as taught in school}
    		else
    			set bounds of window 1 to {¬
    				round ((screenWidth - windowWidth) / 2) rounding as taught in school, ¬
    				round ((screenHeight - windowHeight) / 2) rounding as taught in school, ¬
    				round ((screenWidth + windowWidth) / 2) rounding as taught in school, ¬
    				round ((screenHeight + windowHeight) / 2) rounding as taught in school}
    		end if
    		
    		set the result to bounds of window 1
    		
    	end tell
    end try
    
  7. Andrew Goodrick-Werner

    I’ve updated my version of the script to take into account dock position and menu bar height — I also made sure to include your Terminal workaround, Tim. Enjoy! :)

    tell application “Finder”
    set screenSize to bounds of window of desktop
    set screenWidth to item 3 of screenSize
    set screenHeight to item 4 of screenSize
    end tell

    tell application “System Events”
    tell dock preferences
    if screen edge is bottom then
    tell application “System Events” to tell process “Dock”
    set dockSize to size in list 1
    set dockHeight to item 2 of dockSize
    set screenHeight to (screenHeight – dockHeight)
    end tell
    else if screen edge is left then
    tell application “System Events” to tell process “Dock”
    set dockSize to size in list 1
    set dockHeight to item 1 of dockSize
    set screenWidth to (screenWidth + dockHeight)
    end tell
    else
    tell application “System Events” to tell process “Dock”
    set dockSize to size in list 1
    set dockHeight to item 1 of dockSize
    set screenWidth to (screenWidth – dockHeight)
    end tell
    end if
    end tell

    set screenHeight to (screenHeight + 22)
    set myFrontMost to name of first item of ¬
    (processes whose frontmost is true)
    end tell

    try
    tell application myFrontMost
    set windowSize to bounds of window 1
    set windowXl to item 1 of windowSize
    set windowYt to item 2 of windowSize
    set windowXr to item 3 of windowSize
    set windowYb to item 4 of windowSize

    set windowWidth to windowXr – windowXl
    set windowHeight to windowYb – windowYt

    if myFrontMost is “Terminal” then
    set bounds of window 1 to {¬
    round ((screenWidth – windowWidth) / 2) rounding as taught in school, ¬
    round ((screenHeight – windowHeight) / 2) rounding as taught in school, ¬
    round ((screenWidth + windowWidth) / 2) rounding as taught in school, ¬
    round ((screenHeight + windowHeight) / 2) rounding as taught in school}
    else
    set bounds of window 1 to {¬
    round ((screenWidth – windowWidth) / 2) rounding as taught in school, ¬
    round ((screenHeight – windowHeight) / 2) rounding as taught in school, ¬
    round ((screenWidth + windowWidth) / 2) rounding as taught in school, ¬
    round ((screenHeight + windowHeight) / 2) rounding as taught in school}
    end if

    set the result to bounds of window 1

    end tell
    end try

Post a comment

You may use the following HTML:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>