Move ALL Windows to Primary Screen

Use Case

  • Use anytime you want to quickly move all of your windows to the primary (internal) screen, like during an emergency power down.

UPDATED: 2021-02-24 11:31 GMT-6

Change Log

Ver 2.1 Changes 2021-02-24

  • Fix error caused by a change in the macOS
    • Error: Can’t get origin of {{0.0, 0.0}, {3440.0, 1415.0}}.

VER 2.0 Changes

  • Script now searches for ALL Apps and ALL Windows, whether they are background or not, visible or not.
  • Added optional display of list of all windows that were found (enable the last Action).

Example of All Window list

Shows window coordinates BEFORE any were moved.


~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

MACRO:   Move ALL Windows to Primary Screen

-~~~ VER: 2.1    2021-02-24 ~~~
Requires: KM 8.2.4+   macOS 10.11 (El Capitan)+
(Macro was written & tested using KM 9.0+ on macOS 10.14.5 (Mojave))

DOWNLOAD Macro File:

Move ALL Windows to Primary Screen.kmmacros
Note: This Macro was uploaded in a DISABLED state. You must enable before it can be triggered.


ReleaseNotes

Author.@JMichaelTX

PURPOSE:

  • Move ALL Windows to Primary (Internal) Screen

HOW TO USE:

  1. Trigger this macro
    .
  • All Windows NOT on the Primary Screen will be moved to the Primary Screen
  • The Top, Left Position will be offset (see below) to stagger the windows
  • The Window Height will be adjusted so that the Window Bottom is NOT below the Screen Bottom.
  • A Notification (from the Script) will be made when the script/macro completes.

NOTE: To see list of all windows, with coordinates before the move, ENABLE the last Display Text Action.

MACRO SETUP

  • There are no Actions designed for changes by end user.
  • However, you may adjust these Properties in the Script
    --- OFFSETS Used When Moving Windows ---
    property ptyOffsetX : 20
    property ptyOffsetY : 40
  • You may also ENABLE the last Action, Display Text, to see a list of all Windows before the move.
    • You are responsible for running the Macro, not me. :wink:
      .
  • Assign a Trigger to this maro. I prefer to put it in a Group with a Palette, and assign "M" as the trigger.
  • Move this macro to a Macro Group that is only Active when you need this Macro. This is probably a Global Group, in this case.
  • ENABLE this Macro.

TAGS: @Screen @Display @Window @Move @AS

USE AT YOUR OWN RISK

  • While I have given this limited testing, and to the best of my knowledge will do no harm, I cannot guarantee it.
  • If you have any doubts or questions:
    • Ask first
    • Turn on the KM Debugger from the KM Status Menu, and step through the macro, making sure you understand what it is doing with each Action.


AppleScript to Move All Windows

property ptyScriptName : "Move Windows to Main Screen"
property ptyScriptVer : "2.1" --  CHG formulas for extracting screen coordinates
property ptyScriptDate : "2021-02-24" # Search for ALL Apps
property ptyScriptAuthor : "JMichaelTX"

property LF : linefeed
(*
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

REQUIRED:
  1.  macOS El Capitan 10.11.6+
      (may work on Yosemite 10.10.5, but no guarantees)
      
Local:  /Users/Shared/Dropbox/SW/DEV/KM/Scripts/Move Windows to Main Screen V2.1.scpt
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  
*)

use AppleScript version "2.4"
use framework "Foundation"
use framework "AppKit"
use scripting additions

--- OFFSETS Used When Moving Windows ---
property ptyOffsetX : 20
property ptyOffsetY : 40

set scriptResults to "TBD"

try
  --~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  set frontApp to path to frontmost application as text -- use for dialogs
  
  --- GET COORDINATES OF PRIMARY VISIBLE SCREEN ---
  -- (all windows to the right, or to the left, of this will be moved)
  
  set primaryScreenVisibleFrame to current application's NSScreen's screens()'s firstObject()'s visibleFrame()
  
  set primaryScreenLeft to (item 1 of item 1 of primaryScreenVisibleFrame)
  set primaryScreenRight to (primaryScreenLeft) + (item 1 of item 2 of primaryScreenVisibleFrame)
  set primaryScreenTop to (item 2 of item 1 of primaryScreenVisibleFrame)
  set primaryScreenBottom to (primaryScreenTop) + (item 2 of item 2 of primaryScreenVisibleFrame)
  
  
  (*
--- ALTERNATE METHOD Using KM ---
tell application "Keyboard Maestro Engine"
  set AppleScript's text item delimiters to ","
  set primaryScreenVisibleFrame to text items of (process tokens "%ScreenVisible%Main%")
  set primaryScreenRight to item 3 of mainScreenFrame
end tell
*)
  
  --- GET ALL VISIBLE APPS ---
  
  tell application "System Events"
    set appNameList to (name of every application process)
  end tell
  
  --log " App List: " & (appNameList as text)
  
  set iWin to 0
  
  --- LOOP THROUGH EACH APP  ---
  
  set logStr to "Left, Top, Width, Height  ┃   App  ┃   WinRole  ┃   Win Title" & LF & LF
  
  display notification "START Search for Windows"
  
  repeat with oAppName in appNameList
    set appName to contents of oAppName
    
    -----------------------------------------------------
    tell application "System Events" to tell application process appName
      -----------------------------------------------------
      set winCount to count of windows
      
      --display notification " App: " & appName & "   # of Windows: " & winCount
      
      repeat with iW from 1 to winCount
        
        set oWin to window iW
        
        tell oWin
          set winTitle to title
          set {winLeft, winTop} to position
          set {winWidth, winHeight} to size
          
          set winBottom to winTop + winHeight
          
          if (((winLeft > primaryScreenRight) or ¬
            (winLeft < primaryScreenLeft))) then
            
            set logStr to logStr & my logWin({position & size & space & appName & space & role & space & title}, " ⬅︎⬅︎ ") & LF
            
            --- MOVE WINDOW ---
            
            set iWin to iWin + 1
            
            --- ADD OFFSETS to POSITION ---
            set newXPos to primaryScreenLeft + (ptyOffsetX * iWin)
            set newYPos to primaryScreenTop + (ptyOffsetY * iWin)
            set position of oWin to {newXPos, newYPos}
            
            --- MAKE SURE WIN BOTTOM DOES NOT EXCEED SCREEN BOTTOM ---
            set newBottom to newYPos + winHeight
            if (newBottom > primaryScreenBottom) then set newBottom to primaryScreenBottom
            set newHeight to newBottom - newYPos
            
            set size of oWin to {winWidth, newHeight}
          else
            set logStr to logStr & my logWin({position & size & space & appName & space & role & space & title}, " ") & LF
            
          end if
          
        end tell
        
        
      end repeat -- on each window
      
    end tell -- "System Events" --> appName
    
  end repeat -- oAppName in appNameList
  
  
  if (iWin > 0) then
    set msgStr to (iWin as text) & " Window(s) MOVED"
  else
    set msgStr to "NO Windows Were Found to Move."
  end if
  
  set msgTitleStr to ptyScriptName
  display notification msgStr with title msgTitleStr sound name "Tink.aiff"
  
  set scriptResults to "OK" & LF & msgStr & LF & LF & logStr
  
  --~~~~~~~~~~~~~ END TRY ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  
on error errMsg number errNum
  
  if errNum = -128 then ## User Canceled
    set errMsg to "[USER_CANCELED]"
  end if
  
  set scriptResults to "[ERROR]" & return & errMsg & return & return ¬
    & "SCRIPT: " & ptyScriptName & "   Ver: " & ptyScriptVer & return ¬
    & "Error Number: " & errNum
end try
--~~~~~~~~~~~~~~~~END ON ERROR ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

--- RETURN THE RESULTS TO THE KM EXECUTE SCRIPT ACTION ---
return scriptResults

--~~~~~~~~~~~~~~~ END OF MAIN SCRIPT ~~~~~~~~~~~~~~~~~~~

on logWin(pListOfProp, pPrefixStr)
  local logWinStr
  
  set astid to AppleScript's text item delimiters
  
  set AppleScript's text item delimiters to ", "
  set logWinStr to pPrefixStr & (pListOfProp as text)
  set AppleScript's text item delimiters to astid
  
  set logWinStr to my changeString(",  ,", "  ┃  ", logWinStr)
  
  return logWinStr
  
end logWin

on changeString(pSearchForStr, pReplaceWithStr, pSourceStr)
  local item_list, changedStr, astid
  
  set astid to AppleScript's text item delimiters
  
  set AppleScript's text item delimiters to the pSearchForStr
  set the item_list to every text item of pSourceStr
  set AppleScript's text item delimiters to the pReplaceWithStr
  set changedStr to the item_list as string
  set AppleScript's text item delimiters to astid
  
  return changedStr
end changeString