These two versions should take into account windows from all applications and not consider those that are minimized. Thank you Nigel Garvey, DJ Bazzie Wazzie, and Shane Stanley for a great resource!
DJ Bazzie Wazzie’s modified script:
set ymin to 22 --height of system menu, retina or not it is always 22 pixels
set xmin to 0 ----you could subtract height of dock from ymax if it is permanent visible
tell application "Finder"
tell bounds of window of the desktop as list to set {xmax, ymax} to {item 3, item 4}
end tell
set windowRects to {} --the array where are used rectangles are in (windows)
set columnOffsets to {xmin, xmax} --already add the boundaries in it
set rowOffsets to {ymin, ymax} -- already add the boundaries in it
-- adayzdone
set myWindows to {}
tell application "System Events"
set theWindows to (every window of (every process whose visible is true) whose value of its attribute "AXMinimized" is false)
repeat with aWindow in theWindows
if contents of aWindow ≠{} then set myWindows to myWindows & contents of aWindow
end repeat
end tell
--fill the windowRects array with the rectangles of the windows. Also fill in the grid lines
tell application "System Events"
repeat with theWindow in myWindows
set s to theWindow's size
set l to theWindow's position
tell (item 1 of l)
if it is not in columnOffsets and it > xmin and it < xmax then set end of columnOffsets to it
end tell
tell (item 1 of l) + (item 1 of s)
if it is not in columnOffsets and it > xmin and it < xmax then set end of columnOffsets to it
end tell
tell (item 2 of l)
if it is not in rowOffsets and it > ymin and it < ymax then set end of rowOffsets to it
end tell
tell (item 2 of l) + (item 2 of s)
if it is not in rowOffsets and it > ymin and it < ymax then set end of rowOffsets to it
end tell
set end of windowRects to my newRect(item 1 of l, item 2 of l, (item 1 of s) + (item 1 of l), (item 2 of s) + (item 2 of l))
end repeat
end tell
--sort the grid lines from low to high. This needed to build up a grid where the index actually matches the rectangles
set rowOffsets to bubblesort(rowOffsets)
set columnOffsets to bubblesort(columnOffsets)
--now build the grid with the rectangles
set b to item 1 of rowOffsets
set gridView to {}
repeat with h from 1 to (count rowOffsets) - 1
set thisRow to {}
set a to item 1 of columnOffsets
set y to item (h + 1) of rowOffsets
repeat with v from 1 to (count columnOffsets) - 1
set x to item (v + 1) of columnOffsets
set theRect to newRect(a, b, x, y)
repeat with usedRect in windowRects
--check if this rectangles is in a used spot or not.
if theRect's location's xpos ≥ usedRect's location's xpos then
if theRect's location's ypos ≥ usedRect's location's ypos then
if theRect's endpoint's xpos ≤ usedRect's endpoint's xpos then
if theRect's endpoint's ypos ≤ usedRect's endpoint's ypos then
set theRect's inUse to true
end if
end if
end if
end if
end repeat
set end of thisRow to theRect
set a to x
end repeat
set b to y
set end of gridView to thisRow
end repeat
--now we have a grid we can start looking for the biggest rectangle the brute force way
set bigRect to newRect(0, 0, 0, 0)
repeat with a from 1 to count gridView
repeat with b from 1 to count item 1 of gridView
set currentRect to newRect(0, 0, 0, 0)
set maxWidth to (count item 1 of gridView) - b + 2
set location of currentRect to location of item b of item a of gridView
set endpoint of currentRect to endpoint of item b of item a of gridView
repeat with x from a to count gridView
repeat with y from b to count item 1 of gridView
log bigRect
if inUse of item y of item x of gridView or y = maxWidth then
set maxWidth to y
exit repeat
end if
set currentRect's endpoint to endpoint of item y of item x of gridView
if getSizeFromRect(currentRect) > getSizeFromRect(bigRect) then copy currentRect to bigRect
end repeat
end repeat
end repeat
end repeat
--just for the show create the a new window in the biggest largest available rectangle on you screen.
tell bigRect to set {a, b, x, y} to {it's location's xpos, it's location's ypos, it's endpoint's xpos, it's endpoint's ypos}
tell application "AppleScript Editor"
set theDoc to make new document
tell theDoc's window to set it's bounds to {a, b, x, y}
end tell
--return the biggest avilable rectangle.
return bigRect
on newPoint(x, y)
return {xpos:x, ypos:y}
end newPoint
on newRect(x, y, h, w)
return {location:newPoint(x, y), endpoint:newPoint(h, w), inUse:false}
end newRect
on getSizeFromRect(rect)
tell rect
return ((it's endpoint's xpos) - (it's location's xpos)) * ((it's endpoint's ypos) - (it's location's ypos))
end tell
end getSizeFromRect
on bubblesort(theList)
script o
property lst : theList
end script
repeat with i from (count theList) to 2 by -1
set a to beginning of o's lst
repeat with j from 2 to i
set b to item j of o's lst
if (a > b) then
set item (j - 1) of o's lst to b
set item j of o's lst to a
else
set a to b
end if
end repeat
end repeat
return o's lst
end bubblesort
Shane Stanley’s modified script:
set xMin to 200 -- ignore if width is below this
set yMin to 200 -- ignore if height is below this
-- get screen size (ignore secondary screens)
tell application id "au.com.myriad-com.ASObjC-Runner" -- ASObjC Runner.app
set {theWidth, theHeight} to usable dimensions of screen 1
set {x1, y1} to usable offset of screen 1
end tell
set usableBounds to {x1, y1, x1 + theWidth, y1 + theHeight}
set availableRects to {usableBounds}
-- adayzdone
set myWindows to {}
tell application "System Events"
set theWindows to (every window of (every process whose visible is true) whose value of its attribute "AXMinimized" is false)
repeat with aWindow in theWindows
if contents of aWindow ≠{} then set myWindows to myWindows & contents of aWindow
end repeat
end tell
set existingWindows to {}
tell application "System Events"
repeat with theWindow in myWindows
set {theWidth, theHeight} to theWindow's size
set {x1, y1} to theWindow's position
set end of existingWindows to {x1, y1, x1 + theWidth, y1 + theHeight}
end repeat
end tell
repeat with i from 1 to count of existingWindows
set newList to {}
repeat with j from 1 to count of availableRects
set m to item j of availableRects
set n to item i of existingWindows
set newList to newList & subtractArea_from_(n, m)
end repeat
copy checkSize(xMin, yMin, newList) to availableRects -- remove any that are too small
end repeat
set theBounds to findBiggest(availableRects)
if theBounds = missing value then
display dialog "Not enough room left."
else
tell application "AppleScript Editor"
set theDoc to make new document
tell theDoc's window to set it's bounds to theBounds
end tell
end if
on subtractArea_from_({xMinus1, yMinus1, xMinus2, yMinus2}, {x1, y1, x2, y2})
if xMinus1 > x2 or xMinus2 < x1 or yMinus1 > y2 or yMinus2 < y1 then
-- rects don't intersect, so return full area in list
return {{x1, y1, x2, y2}}
end if
set theResult to {}
if xMinus1 > x1 and xMinus1 < x2 then
set end of theResult to {x1, y1, xMinus1, y2}
end if
if xMinus2 < x2 and xMinus2 > x1 then
set end of theResult to {xMinus2, y1, x2, y2}
end if
if yMinus1 > y1 and yMinus1 < y2 then
set end of theResult to {x1, y1, x2, yMinus1}
end if
if yMinus2 < y2 and yMinus2 > y1 then
set end of theResult to {x1, yMinus2, x2, y2}
end if
return theResult
end subtractArea_from_
on checkSize(xMin, yMin, newList) -- remove any rects that are too small
set newerList to {}
repeat with i from 1 to count of newList
set oneValue to item i of newList
if (item 3 of oneValue) - (item 1 of oneValue) > xMin and (item 4 of oneValue) - (item 2 of oneValue) > yMin then
set end of newerList to oneValue
end if
end repeat
return newerList
end checkSize
on findBiggest(newList)
local oneValue, theArea, maxArea, maxValue
set maxArea to 0
set maxValue to missing value
repeat with i from 1 to count of newList
set oneValue to item i of newList
set theArea to ((item 3 of oneValue) - (item 1 of oneValue)) * ((item 4 of oneValue) - (item 2 of oneValue))
if theArea > maxArea then
set maxArea to theArea
set maxValue to oneValue
end if
end repeat
return maxValue
end findBiggest