ControlPlane and Automating window context repositioning

Posted on Monday, August 11, 2014


I decided to speed up a repetitive task I have been doing lately…. Moving windows around and repositioning them.

In my current job I have a nice adequate apple macbook pro attacked to a 27" thunderbolt screen.  I appreciate the extra space but it comes at a cost, whenever I run to a meeting with my laptop or take my laptop home all my application windows get repositioned.   Then when I plug back into the big monitor or reboot my machine I have to move all my windows to the positions I prefer.

Well this particular problem can be fixed with a few Applescript scripts.  And to make it even awesomer you can add ControlPlane http://www.controlplaneapp.com/ [1] to the equation

Here is what I did to save my sanity.   It’s a long read but worth it…





First things first


The first thing you need to do is give the terminal some special permissions (to allow it to manipulate windows via a script… there is some security risk in this if someone is able to get into your command line… but really if someone is in your command line they can do a lot of damage anyway)




Click on the apple icon in the upper right and select "System Preferences"




Open "Security & Privacy"







Click on Accessibility, unlock it by clicking the lock and entering your password.  Then checkbox "Terminal" 

Now Terminal has more permissions to have its scripts effect other programs.


Close the window.





Terminal


First I am going to tackle moving and resizing the terminal.

From the command line create and edit moveWindowTerminal.scpt


> vi moveWindowTerminal.scpt




tell application "Terminal"
  tell window 1
    set position to {3390, -2000}
    set size to {850, 1414}
  end tell
end tell


This will set the width of my first Terminal Window to "850" and its Height to "1414"  which is the max height it can be on a 27" monitor that has a resolution of 2560x1440  (you need to account for the top bar)

My laptop sits to the left of my monitor so to get it all the way over to the right side of the 27" I have to use 3390 pixels.   Also it may seem funny that the other number is -2000…. Well I found out that since I do line up my screens so that technically my laptop is lower than my monitor (see image)




The position can get a little confused as it crossed the screen boundaries.  One way I solved this was to just use a large negative number which forces it up against the bottom of the menu bar.

Ok now to run this code from the command line.



> osascript moveWindowTerminal.scpt



That worked!




The terminal ends up roughly here on the 27" screen.






Moving Intellij


Moving my Intellij Windows was a little more of a chore, but I did get it working.

From the command line create and edit moveWindowIntellij.scpt


> vi moveWindowIntellij.scpt




tell application "System Events"
  tell process "idea"
    repeat with x from 1 to (count windows)
      set position of window x to {1680, -2000}
      set size of window x to {1710, 1414}
    end repeat
  end tell
  try
    set ideaPIDs to every process whose name contains "idea"
    set ideaPID to item 1 of ideaPIDs
    set frontmost of ideaPID to true
  end try
end tell


This will move every Intellij Window and resize it.  After it resizes them all it will bring the application to the front. 

Now to run this code from the command line.



> osascript moveWindowIntellij.scpt



If you look at the code you will see that you can't talk directly to Intellij.  It is not applescript aware.  But we can tweak a few things, like the windows, by using the "System Events" application.





Intellij now takes up this portion of my 27" monitor.





Skype

I am running Skype in fullscreen mode because I can take advantage of spaces… I really do like spaces. They really help my workflow.  Unfortunately I have spent the last several years developing on a windows machine and I missed a lot of the UI goodness of OS X.  But now I am developing again on a Mac, so I get my spaces back… enough of the nostalgia.

At any rate I want to make my Skype full screen via a script.

From the command line create and edit moveWindowSkype.scpt


> vi moveWindowSkype.scpt




tell application "Skype"
  set isfullscreen to false
  tell application "System Events" to tell process "Skype"
    set isfullscreen to value of attribute "AXFullScreen" of window 1
  end tell

  if not isfullscreen then
    activate
    tell application "System Events" to keystroke "f" using { command down, control down }
  end if
end tell



Ok now to run this code from the command line.



> osascript moveWindowSkype.scpt


It goes fullscreen just fine, and it occupies its own "Space" .
I would also like it to move itself to the first space, but I have not figured out how to do that yet.
If you have a solution please send it my way!


… looking at this code I need to fix something.  This will go full screen on the screen skype currently is.  I want to move it to my laptop monitor first then resize it.

The following code seemed to fixed that.


tell application "Skype"
  set isfullscreen to false
  tell application "System Events" to tell process "Skype"
    set isfullscreen to value of attribute "AXFullScreen" of window 1
  end tell
  tell application "System Events"
    tell process "Skype"
      repeat with x from 1 to (count windows)
        set position of window x to {0, 0}
      end repeat
    end tell
  end tell
  if not isfullscreen then
    activate
    tell application "System Events" to keystroke "f" using { command down, control down }
  end if
end tell


I found an example how to do the fullscreen at https://gist.github.com/dsummersl/4175461 [4]




Wrap it all in a simple bash script

I don't know about you but I just like s simple bash script to run all three at once.  Here is my simple bash script.


> vi moveAllWindows.sh


Here is the code


#!/bin/bash

echo 'Moving all Windows to make use of the big 27" screen!'


osascript moveWindowSkype.scpt
osascript moveWindowTerminal.scpt
osascript moveWindowIntellij.scpt


Then remember to make it executable, then run it.


> chmod u+x moveAllWindows.sh
>  ./moveAllWindows.sh


And voila all my windows are moved into the correct position.




Extra Goodness


I used a script from this forum http://forums.macrumors.com/showthread.php?t=711954 [3]  See Kainjow.
That will list all processes running on your system (their names you must use in your applescript)

Here is the code that was posted 


tell application "System Events"
     repeat with p in every process
         if background only of p is false then
             display dialog name of p as string
         end if
     end repeat
 end tell






What about automating it?


Wouldn't it be nice to have this script run when I plug the monitor in?

Looking around a little I found an open source program called ControlPlane http://www.controlplaneapp.com/ [1]

After downloading and starting this program click on the plane icon in the menu bar.








First things first,  Checkbox the "Start ControlPlane at login.


I found this great site that will walk you through how to use ControlPlane.

Here is how I set mine up to change when the monitor was plugged in.




Click on the Contexts menu then click the + button



Give the Context a name and click OK.




Click on the Evidence Sources tab and make sure "Attached Monitor" is check boxed






Click on Rules tab and click the + Button



Click "Add Attached Monitor Rule"



Cool, it sees my cinema display and fills out all the data just fine!

Oh and it chose the context I created earlier …. Cool!

Click OK





Select Actions tab and press +




Select System Actions and then "Run Shell Script"




Find your script and click Open



Select the context, on arrival and give it a delay of 2 seconds.  (not sure if I need to but its probably a good idea)

Unplugging the monitor and plugging it in again did nothing… sigh… OK what is the problem?


 Looking at the menu it looks like I can force the script to run by forcing the context.



That gave me this error.

 Doing a quick no brainer test of the script  ran just fine


>  ./moveAllWindows.sh





I found the log its under the Advanced tab, scroll down and you can see I got a non-zero status error.



I figured it out I need to put in absolute paths in my script.



#!/bin/bash

echo 'Moving all Windows to make use of the big 27" screen!'

osascript /Users/patman/moveWindowSkype.scpt
osascript /Users/patman/moveWindowTerminal.scpt
osascript /Users/patman/moveWindowIntellij.scpt


This almost worked



This dialog popped up.


I need to Open my system Preferences and give Control Plane some additional permission.



From Security & Privacy select Accessibility and checkbox "Control Plane" To give it permission to move windows around.


Now forcing the script works, but plugging the monitor in and out does not.



Turns out the confidence switch was too high.  It was at 75% I had to lower it to 70% to match the  Rule level




Finally its working like I want.

This is a pretty cool tool I can imagine a few more fun things to do with this tool!

I removed the 2 second delay and it still works just fine.   It does take 2-4 seconds after the screen is attached and working to recognize it and run the script, but that is acceptable for my needs.



References

       Visited 7/2014
[2]  AppleScript - System Events Error : Access for assistive devices is disabled (NSAddict)
       Visited 7/2014
[3]  Applescript - list of running apps?
       Visited 7/2014
       Visited 7/2014
[5]  ControlPlane: Automation Cockpit For Your Mac
       Visited 7/2014