Script to position and resize the frontmost app

This script sets the position and size of the frontmost app to specified values. The user can add or remove apps by editing the appData record, and apps not included in this record are set to the “Default” values. The format of each item in the appData record is:

|App Name|:{x position, y position, window width, window height}

The script will optionally reposition the cursor to a location within the frontmost app. To enable this feature, add the app’s name to the cursorApps list.

As currently written, the script only works on the frontmost window of an app. If the user prefers that the script work on every window, remove line 1 below and replace it with line 2.

tell application "System Events" to tell process (activeApp as text) to tell window 1
tell application "System Events" to tell process (activeApp as text) to tell every window

This script works on the premise that the name of an app and its process name are the same. I have only encountered one instance where this was not the case, and, if encountered, this is easily fixed within the script on a case-by-case basis.

To test this script, open it in Script Editor or Script Debugger and run.

use framework "AppKit"
use framework "CoreGraphics"
use framework "Foundation"

on main()
	set appData to {|Default|:{510, 33, 900, 750}, |Finder|:{375, 33, 1170, 700}, |Mail|:{380, 33, 1160, 987}, |Preview|:{468, 33, 984, 1037}, |Safari|:{160, 23, 1600, 1057}, |Script Debugger|:{480, 23, 960, 1057}, |Script Editor|:{480, 23, 960, 1057}} -- do not delete Default entry
	set appData to current application's NSDictionary's dictionaryWithDictionary:appData
	
	set cursorApps to {"Finder", "Safari", "Script Debugger"} -- reposition cursor in these apps
	set cursorApps to current application's NSArray's arrayWithArray:cursorApps
	set cursorPosition to {30, 30} -- cursor position relative to upper-left corner of app
	
	set activeApp to current application's NSWorkspace's sharedWorkspace()'s frontmostApplication()'s localizedName()
	set windowData to (appData's valueForKey:activeApp) as list
	if windowData = {missing value} then set windowData to (appData's valueForKey:"Default") as list
	set moveCursor to cursorApps's containsObject:activeApp
	
	try
		tell application "System Events" to tell process (activeApp as text) to tell window 1
			set position to {item 1, item 2} of windowData
			set size to {item 3, item 4} of windowData
		end tell
	on error
		error number -128
	end try
	
	if moveCursor = true then -- thanks Mark FX
		set cursorPoint to current application's NSMakePoint((item 1 of windowData) + (item 1 of cursorPosition), (item 2 of windowData) + (item 2 of cursorPosition))
		current application's CGWarpMouseCursorPosition(cursorPoint)
	end if
end main

main()

The operation of this script is similar to that above, differing in that it resizes all active apps, does not reposition the cursor, has a do-not-resize list, and makes hidden apps visible.

use framework "AppKit"
use framework "Foundation"
use scripting additions

on main()
	set appData to {|Default|:{510, 33, 900, 750}, |Finder|:{375, 33, 1170, 700}, |Mail|:{380, 33, 1160, 987}, |Preview|:{468, 33, 984, 1037}, |Safari|:{160, 23, 1600, 1057}, |Script Debugger|:{480, 23, 960, 1057}, |Script Editor|:{480, 23, 960, 1057}} -- do not delete Default entry
	set appData to current application's NSDictionary's dictionaryWithDictionary:appData
	set doNotResize to {}
	
	set openApps to current application's NSWorkspace's sharedWorkspace()'s runningApplications()
	set thePredicates to current application's NSPredicate's predicateWithFormat:"activationPolicy == 0 AND NOT localizedName IN %@" argumentArray:{doNotResize}
	set openApps to (openApps's filteredArrayUsingPredicate:thePredicates)'s valueForKey:"localizedName"
	
	repeat with anApp in openApps
		set windowData to (appData's valueForKey:anApp) as list
		if windowData = {missing value} then set windowData to (appData's valueForKey:"Default") as list
		try
			tell application "System Events" to tell process (anApp as text)
				if (visible = false) then set visible to true
				tell every window
					set position to {item 1, item 2} of windowData
					set size to {item 3, item 4} of windowData
				end tell
			end tell
		end try
	end repeat
end main

main()

The following is a minor rewrite of the script in post 1. The cursorApps list can be left blank, but all apps in this list have to be in the appData list.

use framework "AppKit"
use framework "Foundation"
use scripting additions

on main()
	set appData to {|Default|:{510, 35, 900, 750}, |Finder|:{375, 35, 1170, 700}, |Mail|:{380, 35, 1160, 985}, |Preview|:{468, 35, 984, 1035}, |Safari|:{160, 25, 1600, 1055}}
	set appData to current application's NSDictionary's dictionaryWithDictionary:appData
	
	set activeApp to current application's NSWorkspace's sharedWorkspace()'s frontmostApplication()
	set activeAppName to activeApp's localizedName()
	set activeAppID to activeApp's processIdentifier()
	
	set windowData to (appData's valueForKey:activeAppName)
	if windowData is (missing value) then set windowData to (appData's valueForKey:"Default")
	set {x, y, w, h} to (windowData as list)
	
	set cursorApps to {"Finder", "Safari"}
	set cursorApps to current application's NSArray's arrayWithArray:cursorApps
	set moveCursor to cursorApps's containsObject:activeAppName
	
	try
		tell application "System Events" to tell (first process whose unix id is activeAppID) to tell every window
			set position to {x, y}
			set size to {w, h}
		end tell
	on error
		display alert "An error occurred while repositioning or resizing the app " & quote & (activeAppName as text) & quote message "This typically occurrs when the appData list contains a value that cannot be processed" as critical
		error number -128
	end try
	
	if moveCursor as boolean is true then -- thanks Mark FX
		set cursorPoint to current application's NSMakePoint(x + (w div 2), y + (h div 2))
		current application's CGWarpMouseCursorPosition(cursorPoint)
	end if
end main

main()

The following is a helper script that copies to the clipboard data for insertion in the appData list.

tell application "System Events"
	set processName to name of first process whose frontmost is true
	tell process processName
		set {{x, y}, {w, h}} to {position, size} of window 1
	end tell
end tell

set the clipboard to "|" & processName & "|:{" & x & ", " & y & ", " & w & ", " & h & "}"

display alert "The data for " & quote & processName & quote & " was placed on the clipboard" message "X Coordinate: " & x & linefeed & "Y Coordinate: " & y & linefeed & "Window Width: " & w & linefeed & "Window Height: " & h as informational

I tested these scripts on Monterey and ran them with FastScripts, the Script Editor script menu, and saved as an app with an icon in the Dock.