Moving all windows of visible apps from display 1 to 3

I have two HDTV being used as displays 1 and 3 of my iMac, that is display 2.

Every time the Mac sleeps, since High Sierra, contents of monitor 1 and 3 get switched, what annoys the hell out of me.

I am trying to create a script to move every visible window on monitor 1 to 3 and vice-versa.

Monitor 1 and 3 are HDTV, so I don’t need to worry with the offsetY of the windows. My iMac has a screen width of 2560.

What I need is:

  1. gather a list of all windows
  2. check to see if their offsetX is less than 1920 (window is on display1) or between 4480 and 6400 (window is on display 3), then add 4480 to the windows on display 1 and subtract the same value from windows on display 3 to move them to display 1.

This is what I have so far.

tell application "System Events"
	set listOfProcesses to (name of every process where background only is false)
	
	repeat with aProcess in listOfProcesses
		tell aProcess
		    set numWindows to count of window
			repeat with i from 1 to numWindows
				set aWindow to window i
				set {x, y, w, h} to bounds of aWindow
		    end repeat
		end tell
		
		
	end repeat
end tell

I am stuck here

set {x, y, w, h} to bounds of aWindow

with the error message “can’t get bounds of F”

???

Hi.

The cause of the immediate error is that the outer repeat is cycling through the names of each process, as fetched in the second line, so the inner one is cycling through the characters of those names.

Even when that’s corrected on my Mojave machine, processes don’t understand the ‘count’ command, so that has to be moved outside the ‘tell aProcess’ statement (and ‘of window’ corrected to ‘windows’).

Even then I’m still getting errors, but I don’t know offhand if it’s because some process windows are invisible or because some don’t have bounds for some other reason.

I think I am almost there.

Here is the current script:

set monitorWidth1 to 1920
set monitorWidth2 to 2560
set monitorWidth3 to 1920

set offsetWindow to monitorWidth1 + monitorWidth2

tell application "System Events"
	set listOfProcesses to (name of every process where background only is false)
end tell

repeat with aProcess in listOfProcesses
	
	tell application aProcess
		
		copy (name of every window) to janelas -- Obtain list of window names of current process.
		
		repeat with j from 1 to (count janelas) -- Cycle though list of window names, ...
			
			set {x, y, w, h} to bounds of window j
			
			if x < 1920 then
				set newX to x + (offsetWindow)
			else if x > (offset) then
				set newX to x - (offsetWindow)
			end if
			
			set bounds of window j to {newX, y, w, h}
			
		end repeat
		
	end tell
end repeat

the script runs and the windows are moved to the twilight zone and disappear from all monitors.

what is wrong?

macos_boy. I don’t have multiple monitors to test your script, but I was curious as to your use of the offset command in the following code:

if x < 1920 then
               set newX to x + (offsetWindow)
           else if x > (offset) then
               set newX to x - (offsetWindow)
           end if

Normally offset is used to find the position of one string inside another. Perhaps this was meant to be offsetWindow?

Also, not every app is scriptable and may not respond to the bounds property. If that becomes an issue, you may want to consider using System Events instead. Since you are only changing the x position of the app, you could use the position property. The following is untested code just to demonstrate:

tell application "System Events" to tell process appName
	set position of window j to {newX, y}
end tell

The following is tested and works with an app that’s not scriptable:

tell application "System Events" to tell process "FSNotes"
	set position of window 1 to {50, 50}
end tell

Brilliant, it is working now.

offsetWindow is just a variable I was using to find how much I would have to shift the window but I then realized that my iMac being in the middle, it is equivalent to coordinates 0 to 2560 in X. The monitor to the left would be negative coordinates and the one in the right will start at 2560.

I was expecting coordinate x = 0 to be the left edge of the left monitor, but it isn’t. It is the left edge of the middle monitor.

Thanks.