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.
have you see SizeUp http://www.irradiatedsoftware.com/
I hadn’t, but to be honest most of the features other than centering don’t really appeal to me. This script works well enough for that.
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.)
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.
Well, that did the trick!
Gotta love AppleScript syntax
Thank you for bothering to help. My life is in order again!
Hey there,
good post, extremely useful!
Also check out this page for handy scripts http://www.giacomoballi.com/scripts.html
By the way, Tim, i was just about to point that out…
Good job guys!
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?
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.
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.
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 tryAgain, 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 tryThe 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!
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!
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.
Good tip, Andrew. Thanks!
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 tryI’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
I posted yet another version at the apple.stackexchange thread.