Hi, this is Gary with MacMost.com. On this episode I'm going to show you how to write
a script in Automator so that you can snap windows to positions on your screen.
MacMost is brought to you thanks to a great group of supporters. Join us and get exclusive
content at MacMost.com/patreon.
So I know there are third party tools that allow you to snap windows to different parts
of your screen. You can do the same thing at Automator and with a little scripting you
can make it quite advanced. So let's start off here in Automator. I'm going to create
a new document and I'm going to make it a Quick Action. Now the only thing I'm going
to add to it is the ability to write a JavaScript script. So I'm going to use Run JavaScript
and drag that over into here. Everything we're going to do is going to be in here. I'm going
to expand this space a bit. We're going to put all our of code in here. The Workflow
is not going to receive any input. We're not going to have any selected text or anything
like that and it's going to work in any application.
Now to get started I'm going to get the current app. So the one that's currently running because
that's the one we're going to change the position of the window for. So we're going to put two
lines here. App = Application.currentApplication();
app.includesStandardAdditions = true; This is typical in starting a JavaScript or
JXAscript in Automator. Now we want to set the position for the front-most window for
this app. So to do that it's pretty simple. I'm going to do app.windows[0] for the first
window and I'm going to set the bounds equal to a boundary object which has four properties
{x: so we'll say x is 0 for the upper left hand corner with y:0 as well. We'll do width
and we'll set it to something like 300 pixels and height we'll set that to say 500 pixels.
All this will do then is set the boundary for the current window to zero zero to 300,
500. We can get rid of the return input there. We don't need that. We can just try this script
out by hitting the Run button. Since the front-most window is Automator itself it should effect
Automator. You can see, sure enough, it set it there.
Now what's interesting here is you can just change these numbers to whatever you want
and you can be done. You can create a variety of different Automator scripts that can set
things to the top left corner, the top right corner, the left third, the right two-thirds.
Whatever you need. But let's get a little more complex and make a script that's a little
more versatile. So I'm going to put a little window that pops up and asks you where you
want the window position. So I'm going to do a variable called areaChoices and I'm going
to set it equal to a list of choices. We'll make those our three choices for now.
Now I'm going to get the user choice using app.chooseFromList. You have to use a reference
to an app in order to bring up chooseFromList. So we'll set the first parameter to be areaChoices.
Then we'll do some more options here. We'll do withPrompt, Where? and we'll close that
off. Comment this line out now so it doesn't actually do anything. I'll hit Run and you
can see it comes up with this list here and I can select one and hit OK or I can double
click one and the result is put into Area. So what I can do here is say if (area = "Left
Third") and we need to do double equals there to test. Then we can do something like this
and else if (area =="Right Two-Thirds") then we can do the same thing.
So I'm going to copy and paste but we'll change the numbers. So we'll have it start at 300
pixels and be say 600 pixels wide. So now it will choose between these two. So if I
run this now, if I do left third, it's going to do that. If I run it again and I choose
right two thirds you can see it puts it there. It's not putting it exactly at ⅓ or exactly
the right ⅔ because all I'm doing is just guessing using these numbers. So let's stop
guessing and actually get the real values.
So here's the code I'm going to use to get the pixel dimensions of the screen. It's going
to work regardless of how many displays I've got. So let's walk through it. The first line
is going to run a Shell Script. The shell script is going to do this special assistant
profiler here to actually get the text about all of our displays and graphics card. It's
the same thing that you will see if you go to About This Mac and then go to System Information
and then look at your display information. The text it's going to return is going to
be this text. I'm actually going to show it to you. I'm going to paste in this return
here so I'll run this. I'm going to have to just choose one here, it doesn't matter which
one. We'll see every line here. You could see what it looks like. It does look like
what you get in About This Mac.
So what we want to do then is we want to put that into display info. Split it every time
we see the text UI Looks Like. So let's look at that again here. We can see here the text
UI Looks Like appears three times. One for each screen. It kind of kicks off the information
we want about the screen. The resolution is great but if we have the resolution set to
be something different, which I do on my retina display, then it's not going to match. UI
Looks Like is the same as the resolution here for the first and for the second. But for
the third screen you can see the resolution is much higher and I have set the UI Looks
Like to be smaller. So that's the real resolution of the screen is 1280 by 720 and it's what
we want to use in our script to figure out what is half or one third of the width of
the screen.
So every time it sees this it is going to divide this up into a different item in the
array using Split and the split command is basically going to make sure that there's
one element that's before the first display. The second element is going to be the first
display. The third element is going to be the second display and the fourth element
is going to be the third display. We get all the text from UI Looks Like right after that
all the way down. Now notice here it says Main Display Yes. It only says that on the
third display. That's key. That allows to identify the third display as the main display.
So after we work with all of that we're going to loop through those four items. We're going
to look for the text Main Display. If it's greater than negative 1 it means that it exists
in this item. It's only going to be there for the last item. In that case it's going
to run this. It's going to split all that text up with spaces. After UI Looks Like we
get 1280 space X space 720. So that first item represented by zero is the width. The
third item represented by 2 is the height. The X would be the 1 in-between that. So it's
0, 1, 2. 1280 720 put into display width, display height. Great we're done!
So we Break. What we should have here is a correct displayWidth and a displayHeight.
We'll test it. So I will put that in a Return. I will Run. It doesn't matter which one we
pick. You can see here the return value is 1280, 720. Hooray! We've figured out the display
width and the display height. Now we can use that down here. So we can say, okay x and
y upper left hand corner. But the width, let's set that to displayWidth divided by three.
Or better yet multiplied by .333. The height we'll set that to displayHeight. So full height.
That'll be the left third. Then we'll go and we'll say the right two-thirds we'll start
that at displayWidth x .333. So one third over and then we will go displayWidth x .6667
two thirds of the width. The height we'll do displayHeight.
So now when we run this we go and say left third gives us the left third. We run it again
two thirds give us the right two thirds. So that's exactly what we want. So far so good.
We're going to run into a problem when we try to run this as a script on anything but
Automator. We are going to need another way to tell what app is actually the front most
app. When we run this as a service it's going to still think that the Automator process
is the frontmost app.
So we'll keep this here but we'll add some more lines. This is what this looks like here.
We're going to get front app name by going to Application("System Events") looking at
the processes there. Then we will use the process is .whose {frontmost: is true. It's
a little weird syntax here but it actually gives us the name of the frontmost process.
We actually have to look at the first element in the array that's returned to get the name
of it. So the value then should be returned. Let's try it out. Ah, Automator. That's good.
So it's working. The front app is then going to be Application front app name. You would
think that you'd be able to take this off and get the front app right there in that
line. But it doesn't work.
So now we have the front app. Great. So instead of setting the app, the main app, the one
that's running which would be the Automator process, we're going to set the front app
here. It should work the same in Automator. Great, it does. Now let's save this script.
Save. We're going to call it Window Position. It saves it as a quick action. So now it should
appear if we go to anything, the application you're running, and there's under Services,
Window Position. So let's try it out in another app, like say Safari. So here we are in Safari.
Go to Safari. Go to Services and Window Position. It's going to give us that little dialogue
there. I'll say left third and there it goes. It sets it to the left third. The great thing
is I can open up another window here in Safari and now this is the frontmost window. So when
I go Service, Window Position I can say right two thirds and it locks this window to the
right two thirds of the screen.
So next I can go in System Preferences and I can do Keyboard, Shortcuts, App shortcuts
and I can add one. I'll say All Applications, Window Position, and I'll make the keyboard
shortcut something like Shift F1. There you go. So now I can go into Safari here. Let's
move this window around. If I look under Services I can see Window Position is Shift F1. So
I don't have to choose that anymore. I can just do Shift F1. It'll pop up and I can set
the position of the window. Now what you're going to get every time you use the script
is you're going to get a little dialogue that asks for permission. I had already run the
script for Safari so you didn't see it. But let's try it on Maps here. Go to Services.
Here I can just use Shift F1 and it's going to say Maps wants to access System Events.
All of that. So you say okay. Now I can use the script. That's the basics.
You also want to add another else statement for the top left corner. So in that case you
want to have say half the displayWidth and half the displayHeight. Note that display
Height does not take into account the Menu Bar height at the top so you may want to subtract
some or work with that just to get things exactly as you want. Of course if you do have
multiple screens and you want to set things to be in different areas of different screens
you can work with negative values or values that are greater than the displayHeight or
displayWidth to position it on the different screens where you want it.