Introduction

Dear reader, I’m about to inform you my upgraded setup how I manage my windows after making this post Managing window positions with apple script and alfred workflows.

As I had several apps managed on the previous setup, I wanted a bit more flexibility with it. My setups differ sometimes from eachother. Mainly I have a PLP setup, sometimes I work from just my macbook (Optionally with my iPad as second screen).

So I had a few reqruirements:

  • Easy to add new apps to the setup
  • Easy to support multiple layouts
  • Abillity to reapply the position to a single app

Setup

Knowing the position

To know the position (bounds or pos & size) I have a script that will place the location of requested app in the clipboard. It is constructed as followed:

For scriptfilter with keyword ws pos I use the following script.

tell application "System Events" to set theNames to name of processes whose background only is false
set appNameList to {}

set ignoreList to {"app_mode_loader"}

repeat with appName in theNames
	if appName is not in ignoreList then
		set end of appNameList to appName
	end if
end repeat

-- Construct JSON output
set jsonArray to "{ \"items\": ["
repeat with i from 1 to count of appNameList
	set appName to item i of appNameList
	set jsonArray to jsonArray & "{\"title\": \"" & appName & "\", \"subtitle\": \"Get the bounds / pos & size of" & appName & "\", \"arg\": \"" & appName & "\"}"
	if i is not equal to (count of appNameList) then
		set jsonArray to jsonArray & ","
	end if
end repeat
set jsonArray to jsonArray & "]}"

return jsonArray

This allows me to easily select the apps I want to get either the bounds or pos / size from. But not all apps are always shown, such as Browser Apps. So I also have a keyword trigger on ws pos that requires an argument.

The script that grabs the actual position of the requested app:

use framework "Foundation"
use scripting additions

on run argv
	set theQuery to item 1 of argv

	try
		tell application theQuery
			set appBounds to get the bounds of the front window
			set resultString to "set appBounds to {" & (item 1 of appBounds) & ", " & (item 2 of appBounds) & ", " & (item 3 of appBounds) & ", " & (item 4 of appBounds) & "}"
		end tell
	on error errorMessage number errorNumber
		tell application "System Events" to tell application process theQuery
			set appPos to get position of window 1
			set appSize to get size of window 1
			set posString to "set appPos to {" & (item 1 of appPos) & ", " & (item 2 of appPos) & "}"
			set sizeString to "set appSize to {" & (item 1 of appSize) & ", " & (item 2 of appSize) & "}"
			set resultString to posString & "\n" & sizeString
		end tell
	end try

	return resultString
end run

The above script will output the required variables and values for the requested app. Which in turn can be copy & pasted into the script to position said app.

output:

# Bounds
set appBounds to {1088, 406, 2719, 1461}

# Pos & Size
set appPos to {-2160, 1436}
set appSize to {2160, 1420}

And the output should be passed to a transform to trim the whitespaces and afterwards to Copy to Clipboard.

Placing apps

To place apps at the wanted location we just need to call either one of the below script. If the app supports bounds, you’ll know this via the contents in the clipboard provided by ws pos ...

set appBounds to {3218, -38, 5351, 1284}

tell application "System Events"
	try
		set bounds of the front window of application "Safari" to appBounds
	end try
end tell

Otherwise for size & pos:

set appPos to {-2160, -959}
set appSize to {2160, 963}

tell application "System Events"
	try
		tell process "Discord"
			set position of window 1 to appPos
			set size of window 1 to appSize
		end tell
	end try
end tell

The above scripts are used in the larger workflow to position each invividual app.

Alfred Workflows

ws pos

S c r i w K w p s e s t y p w p f o o o i s r s l d t e r A p p R l u e n S c r i p t t r i m w h i t e s p a c e C P o l p a y y t s o o u c n l d i p b o a r d

ws place

This is the main workflow, which to me is maintainable. I can update the List Filter to add or remove workspace layouts. And / or remove single apps placement scripts.

With the Keyword: ws place ... I can select a singular app to be repositioned according to the provided details. Which are also corolated to the if/else blocks presented with a1-a10 below.

And with the List Filter: ws place It’ll present to me a list of configured layouts. Which is attached to a junction which will invoke all attached scripts.

In my workflow, I include a junction after each set of app layouts that points to a Play sound action. This is helpful as it plays a sound when the task is complete, similar to the ws pos mentioned earlier.

L i w s s t p f l i a l c t e e r p i M l p a p a c d B o o k C C o o n n n n e e c c t t e e d K w d e s t y t o w p o o l J r a J d c e a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a 1 2 3 4 5 6 7 8 9 1 1 2 3 4 5 6 7 8 9 1 1 2 3 4 5 6 7 8 9 1 0 0 0 J J J S S S S S S S S S S S S S S S S S S S S S S S S S S S S S S c a c a c a c a c a c a c a c a c a c a c a c a c a c a c a c a c a c a c a c a c a c a c a c a c a c a c a c a c a c a r p r p r p r p r p r p r p r p r p r p r p r p r p r p r p r p r p r p r p r p r p r p r p r p r p r p r p r p r p r p i p i p i p i p i p i p i p i p i p i p i p i p i p i p i p i p i p i p i p i p i p i p i p i p i p i p i p i p i p i p p 1 p 2 p 3 p 4 p 5 p 6 p 7 p 8 p 9 p 1 p 1 p 2 p 3 p 4 p 5 p 6 p 7 p 8 p 9 p 1 p 1 p 2 p 3 p 4 p 5 p 6 p 7 p 8 p 9 p 1 t t t t t t t t t t 0 t t t t t t t t t t 0 t t t t t t t t t t 0

Note: The line between ipad and the junction block on the same plane to the right are connected.