Sunday, June 13, 2021

#1 2021-05-16 08:34:47 pm

peavine
Member
From:: Prescott, Arizona
Registered: 2018-09-04
Posts: 910

App Tiling Script

The following script tiles visible apps running on a computer. To test this script, open it in Script Editor, open an additional app, and run the script. A few comments:

* The script has two limitations. First, it does not work as expected when the dock is side-aligned. Second, a fair number of apps have minimum heights that cannot be changed and may not tile correctly. This is most often an issue when three apps are tiled vertically on a screen with a vertical resolution of 1080 pixels or less.

* The script tiles up to six apps. If one or no apps are open or if more than six apps are open, the script quits without taking any action.

* If an app has two or more open windows, the additional open windows are positioned and resized behind the first window.

* I haven't tested this script on a computer with multiple monitors.

Applescript:

-- Revised 2021.05.22

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

on main()
   set windowBuffer to 10 -- this can be changed but a small value is recommended
   set {activeApp, openApps} to getAppData()
   set windowData to getWindowData(openApps, windowBuffer)
   tileApps(activeApp, openApps, windowData)
end main

on getAppData()
   set activeApp to current application's NSWorkspace's sharedWorkspace()'s frontmostApplication()
   set activeApp to activeApp's processIdentifier() as integer
   set openApps to current application's NSWorkspace's sharedWorkspace()'s runningApplications()
   set thePredicate to current application's NSPredicate's predicateWithFormat:"activationPolicy = 0"
   set openApps to ((openApps's filteredArrayUsingPredicate:thePredicate)'s valueForKey:"processIdentifier") as list
   set appCount to (count openApps)
   
   tell application "Finder"
       if (exists window 1) then
           if appCount < 2 or appCount > 6 then error number -128
       else
           if appCount < 3 or appCount > 7 then error number -128
           if activeApp = item 1 of openApps then set activeApp to item -1 of openApps
           set openApps to rest of openApps
       end if
   end tell
   
   return {activeApp, openApps}
end getAppData

on getWindowData(openApps, windowBuffer)
   set menuHeight to 24 -- normally this should not be changed
   set appCount to (count openApps)
   
   set screenBounds to item 2 of (current application's NSScreen's mainScreen()'s visibleFrame())
   set screenWidth to item 1 of screenBounds as integer
   set screenHeight to item 2 of screenBounds as integer
   
   set windowWidth to ((screenWidth - (windowBuffer * 3)) div 2)
   set windowFullHeight to (screenHeight - (windowBuffer * 2))
   set windowHalfHeight to ((screenHeight - (windowBuffer * 3)) div 2)
   set windowThirdHeight to ((screenHeight - (windowBuffer * 4)) div 3)
   
   set x1 to windowBuffer
   set x2 to (x1 + windowWidth + windowBuffer)
   set y1 to (menuHeight + windowBuffer)
   set y2 to (y1 + windowHalfHeight + windowBuffer)
   set y3 to (y1 + windowThirdHeight + windowBuffer)
   set y4 to (y3 + windowThirdHeight + windowBuffer)
   
   if appCount = 2 then
       set windowData to {{{x1, y1}, {windowWidth, windowFullHeight}}, {{x2, y1}, {windowWidth, windowFullHeight}}}
   else if appCount = 3 then
       set windowData to {{{x1, y1}, {windowWidth, windowFullHeight}}, {{x2, y1}, {windowWidth, windowHalfHeight}}, {{x2, y2}, {windowWidth, windowHalfHeight}}}
   else if appCount = 4 then
       set windowData to {{{x1, y1}, {windowWidth, windowHalfHeight}}, {{x1, y2}, {windowWidth, windowHalfHeight}}, {{x2, y1}, {windowWidth, windowHalfHeight}}, {{x2, y2}, {windowWidth, windowHalfHeight}}}
   else if appCount = 5 then
       set windowData to {{{x1, y1}, {windowWidth, windowHalfHeight}}, {{x1, y2}, {windowWidth, windowHalfHeight}}, {{x2, y1}, {windowWidth, windowThirdHeight}}, {{x2, y3}, {windowWidth, windowThirdHeight}}, {{x2, y4}, {windowWidth, windowThirdHeight}}}
   else if appCount = 6 then
       set windowData to {{{x1, y1}, {windowWidth, windowThirdHeight}}, {{x1, y3}, {windowWidth, windowThirdHeight}}, {{x1, y4}, {windowWidth, windowThirdHeight}}, {{x2, y1}, {windowWidth, windowThirdHeight}}, {{x2, y3}, {windowWidth, windowThirdHeight}}, {{x2, y4}, {windowWidth, windowThirdHeight}}}
   end if
   
   return windowData
end getWindowData

on tileApps(activeApp, openApps, windowData)
   tell application "System Events"
       tell (first process whose unix id is activeApp) to tell every window
           set position to item 1 of item 1 of windowData
           set size to item 2 of item 1 of windowData
       end tell
       
       set windowData to rest of windowData
       repeat with anID in openApps
           if contents of anID = activeApp then
               set contents of anID to missing value
               exit repeat
           end if
       end repeat
       set openApps to integers of openApps
       
       repeat with i from 1 to (count openApps)
           tell (first process whose unix id is (item i of openApps)) to tell every window
               set position to item 1 of item i of windowData
               set size to item 2 of item i of windowData
           end tell
       end repeat
   end tell
end tileApps

main()

Last edited by peavine (2021-05-22 08:51:49 am)


2018 Mac mini - macOS Catalina

Offline

 

#2 2021-05-17 10:17:59 am

peavine
Member
From:: Prescott, Arizona
Registered: 2018-09-04
Posts: 910

Re: App Tiling Script

The following is a companion script of sorts, and its purpose is to tile windows of the active app. To test this script, open it in Script Editor, open an additional Script Editor window, and run the script. This script does not raise a window of the active app if located behind another app--enable the repeat loop near the botton of the script if this is an issue.

Applescript:

-- Revised 2021.05.19

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

on main()
   set windowBuffer to 5 -- this can be changed but a small value is recommended
   set {activeApp, windowCount} to getAppData()
   set windowData to getWindowData(windowBuffer, windowCount)
   tileWindows(windowData, windowCount)
end main

on getAppData()
   set activeApp to current application's NSWorkspace's sharedWorkspace()'s frontmostApplication()
   set activeApp to activeApp's localizedName() as text
   
   if activeApp = "Script Editor" then -- corrects for a Script Editor bug
       tell application activeApp to set windowCount to (count documents)
   else
       try
           tell application activeApp to set windowCount to (count windows)
       on error
           display alert "Window Tile" message activeApp & " is not scriptable" as critical
           error number -128
       end try
   end if
   
   if windowCount < 2 or windowCount > 6 then error number -128
   return {activeApp, windowCount}
end getAppData

on getWindowData(windowBuffer, windowCount)
   set menuHeight to 24 -- normally this should not be changed
   
   set screenBounds to item 2 of (current application's NSScreen's mainScreen()'s visibleFrame())
   set screenWidth to item 1 of screenBounds as integer
   set screenHeight to item 2 of screenBounds as integer
   
   set windowWidth to ((screenWidth - (windowBuffer * 3)) div 2)
   set windowFullHeight to (screenHeight - (windowBuffer * 2))
   set windowHalfHeight to ((screenHeight - (windowBuffer * 3)) div 2)
   set windowThirdHeight to ((screenHeight - (windowBuffer * 4)) div 3)
   
   set x1 to windowBuffer
   set x2 to (x1 + windowWidth + windowBuffer)
   set y1 to (menuHeight + windowBuffer)
   set y2 to (y1 + windowHalfHeight + windowBuffer)
   set y3 to (y1 + windowThirdHeight + windowBuffer)
   set y4 to (y3 + windowThirdHeight + windowBuffer)
   
   if windowCount = 2 then
       set windowData to {{{x1, y1}, {windowWidth, windowFullHeight}}, {{x2, y1}, {windowWidth, windowFullHeight}}}
   else if windowCount = 3 then
       set windowData to {{{x1, y1}, {windowWidth, windowFullHeight}}, {{x2, y1}, {windowWidth, windowHalfHeight}}, {{x2, y2}, {windowWidth, windowHalfHeight}}}
   else if windowCount = 4 then
       set windowData to {{{x1, y1}, {windowWidth, windowHalfHeight}}, {{x1, y2}, {windowWidth, windowHalfHeight}}, {{x2, y1}, {windowWidth, windowHalfHeight}}, {{x2, y2}, {windowWidth, windowHalfHeight}}}
   else if windowCount = 5 then
       set windowData to {{{x1, y1}, {windowWidth, windowHalfHeight}}, {{x1, y2}, {windowWidth, windowHalfHeight}}, {{x2, y1}, {windowWidth, windowThirdHeight}}, {{x2, y3}, {windowWidth, windowThirdHeight}}, {{x2, y4}, {windowWidth, windowThirdHeight}}}
   else if windowCount = 6 then
       set windowData to {{{x1, y1}, {windowWidth, windowThirdHeight}}, {{x1, y3}, {windowWidth, windowThirdHeight}}, {{x1, y4}, {windowWidth, windowThirdHeight}}, {{x2, y1}, {windowWidth, windowThirdHeight}}, {{x2, y3}, {windowWidth, windowThirdHeight}}, {{x2, y4}, {windowWidth, windowThirdHeight}}}
       return windowData
   end if
end getWindowData

on tileWindows(windowData, windowCount)
   set activeProcess to current application's NSWorkspace's sharedWorkspace()'s frontmostApplication()
   set activeProcess to activeProcess's processIdentifier() as integer
   
   tell application "System Events" to tell (first process whose unix id is activeProcess)
       -- enable this repeat loop to raise all tiled windows above other apps
       -- repeat windowCount times
       -- tell window windowCount to perform action "AXRaise"
       -- end repeat
       repeat with i from 1 to windowCount
           tell window i
               set position to item 1 of item i of windowData
               set size to item 2 of item i of windowData
           end tell
       end repeat
   end tell
end tileWindows

main()

Last edited by peavine (2021-05-22 07:49:58 am)


2018 Mac mini - macOS Catalina

Offline

 

Board footer

Powered by FluxBB

RSS (new topics) RSS (active topics)