This script tiles all open windows of the application that has the focus. Note should be made that:
-
The application that has the focus must be scriptable.
-
The script may not work properly if tested in a script editor.
-
The user can modify the tiling pattern by editing the windowSetting list. For example, the list for 3 windows can be {1, 1, 1} or {1, 2} or {2, 1} or {3}.
-
Script Editor contains a bug which may cause this script to tile windows in an unexpected fashion.
-
The calculations made in setting windowBounds are based, in part, on those posted by One208 in the thread linked at the bottom of this post.
-- Revised 2022.02.14
use framework "AppKit"
use framework "Foundation"
use scripting additions
on main()
set {activeApp, windowCount} to getAppData()
set windowBounds to getWindowData(windowCount)
tileWindows(activeApp, windowBounds, windowCount)
end main
on getAppData()
set activeApp to current application's NSWorkspace's sharedWorkspace()'s frontmostApplication()'s localizedName as text
try
tell application activeApp to set windowCount to (count windows)
on error
errorAlert(activeApp & " may not be scriptable")
end try
if windowCount < 2 or windowCount > 9 then errorAlert(activeApp & " appears to have less than 2 or more than 9 open windows")
return {activeApp, windowCount}
end getAppData
on getWindowData(windowCount)
set wB to 5 -- window buffer
set windowSetting to {{1, 1}, {1, 2}, {2, 2}, {2, 3}, {3, 3}, {2, 2, 3}, {2, 3, 3}, {3, 3, 3}}
set windowSetting to item (windowCount - 1) of windowSetting
set columnCount to (count windowSetting)
set {x1, y1, x2, y2} to getDisplayBounds() -- usable display bounds
set wFH to ((y2 - y1) - (wB * 2)) div 1 -- window heights
set wHH to ((y2 - y1) - (wB * 3)) div 2
set wTH to ((y2 - y1) - (wB * 4)) div 3
if columnCount = 2 then -- window widths
set wW to ((x2 - x1) - (wB * 3)) div 2
else
set wW to ((x2 - x1) - (wB * 4)) div 3
end if
set windowBounds to {}
repeat with i from 1 to columnCount -- loop through columns
repeat with j from 1 to item i of windowSetting -- loop through windows in a column
if item i of windowSetting = 1 then
set end of windowBounds to {(x1 + (i * wB) + ((i - 1) * (wW))), (y1 + (j * wB) + ((j - 1) * wFH)), (x1 + (i * wB) + (i * wW)), (y1 + (j * wB) + (j * wFH))}
else if item i of windowSetting = 2 then
set end of windowBounds to {(x1 + (i * wB) + ((i - 1) * (wW))), (y1 + (j * wB) + ((j - 1) * wHH)), (x1 + (i * wB) + (i * wW)), (y1 + (j * wB) + (j * wHH))}
else
set end of windowBounds to {(x1 + (i * wB) + ((i - 1) * (wW))), (y1 + (j * wB) + ((j - 1) * wTH)), (x1 + (i * wB) + (i * wW)), (y1 + (j * wB) + (j * wTH))}
end if
end repeat
end repeat
return windowBounds
end getWindowData
on tileWindows(activeApp, windowBounds, windowCount)
tell application activeApp
repeat with i from windowCount to 1 by -1
set bounds of window i to (item i of windowBounds)
end repeat
end tell
tell application "System Events" to tell process activeApp -- app and process names must be same
click menu item "Bring All to Front" of menu "Window" of menu bar 1
end tell
end tileWindows
on getDisplayBounds()
set theScreen to current application's NSScreen's mainScreen()
set {{aF, bF}, {cF, dF}} to theScreen's frame()
set {{aV, bV}, {cV, dV}} to theScreen's visibleFrame()
return {aV as integer, (dF - bV - dV) as integer, (aV + cV) as integer, (dF - bV) as integer}
end getDisplayBounds
on errorAlert(dialogMessage)
display alert "An error has occurred" message dialogMessage as critical
error number -128
end errorAlert
main()
The post mentioned above is at: