Is there a method that allows moving a window to another screen? I know how to use .windowMove to move and resize windows, and how to access sizes and coordinates on different screen indexes, but not move from one screen index to another.
Thanks!
- Kitch Membery @Kitch2020-08-10 08:45:15.362Z
Hi Dustin!
Try adjusting the "screenIndex" on this one mate!
const appWindow = sf.ui.app('com.apple.TextEdit').mainWindow; const screenIndex = 1; function centerWindow(window) { var screenFrame = sf.ui.screens.allScreens[screenIndex].visibleFrame; var windowFrame = window.frame; window.windowMove({ position: { x: screenFrame.x + (screenFrame.w / 2) - (windowFrame.w / 2), y: screenFrame.y + (screenFrame.h / 2) - (windowFrame.h / 2), }, }); } centerWindow(appWindow);
Hope that helps :-)
Kitch Membery @Kitch2020-08-10 08:47:00.116Z
This will move the front-most Text Edit window to your second screen. But you knew that :-)
Kitch Membery @Kitch2020-08-10 09:44:39.667Z
There is also a SoundFlow action that does this in the Macro Editor its called "Move Window to Screen". Simply change the delta value.
sf.window.moveToScreen({delta:1});
- In reply toKitch⬆:
Dustin Harris @Dustin_Harris
Ahh I had removed the screen frame.x/y, which is likely where the screen index info is contained :)
(Was doing “x: screenFrame.w/2 - windowFrame.w/2”)
- In reply toKitch⬆:
Dustin Harris @Dustin_Harris
Kitch you perennial legend. Works as advertised. screenFrame.x/.y were the critical components I thought I could live without.
Simple example: gets the foremost finder window and moves it top-left of the screen of my choice.
sf.ui.screens.invalidate(); //make SoundFlow check up on your screens and screen properties sf.ui.finder.windows.first.elementRaise(); //bring the active finder window to the front let window = sf.ui.finder.windows.first; //make it a variable because typing long things suck var bottomScreen = sf.ui.screens.allScreens[0].visibleFrame; var topScreen = sf.ui.screens.allScreens[1].visibleFrame; window.windowMove({position: {x: topScreen.x, y: topScreen.y,}}) // top left of my top screen, change to bottomScreen.x/.y for bottom.
Kitch Membery @Kitch2020-08-10 23:57:58.372Z
Dustin!!!
I've never been called a perennial legend before (Why, thank you!).
And yes... "typing long things sucks"
SUCCESS!!
- AIn reply toDustin_Harris⬆:Andrew Sherman @Andrew_Sherman
Greetings... I'm getting errors when I try running either of these scripts, visibleFrame seems to be the culprit. Any ideas?
TypeError: Cannot read property 'visibleFrame' of undefined
Dustin Harris @Dustin_Harris
Heyya Andrew! Do you mind posting your code? (if you don't know this already, you can quote your code but typing 3 back-ticks (key above the tab key on most mac keyboards)) then pasting your code, then ending with 3 more back ticks.
Cheers!
- AAndrew Sherman @Andrew_Sherman
Thanks Dustin, it the same as your script - I copied and tried it but it's not running.,
sf.ui.screens.invalidate(); //make SoundFlow check up on your screens and screen properties sf.ui.finder.windows.first.elementRaise(); //bring the active finder window to the front let window = sf.ui.finder.windows.first; //make it a variable because typing long things suck var bottomScreen = sf.ui.screens.allScreens[0].visibleFrame; var topScreen = sf.ui.screens.allScreens[1].visibleFrame; window.windowMove({position: {x: topScreen.x, y: topScreen.y,}}) // top left of my top screen, change to bottomScreen.x/.y for bottom.
Dustin Harris @Dustin_Harris
off the top of my head you'll get an error in
var topScreen = sf.ui.screens.allScreens[1].visibleFrame;
if you only have one screen... is that the case?- AAndrew Sherman @Andrew_Sherman
Yes, I'm running one screen at the moment; had 2 screens for many years but I'm going with one these days! I'm mainly trying to move windows to specific positions on the screen, but I'm trying to do percentages as opposed to fixed sizes (eg send window to top left quarter).
Dustin Harris @Dustin_Harris
try it like this:
sf.ui.screens.invalidate(); //make SoundFlow check up on your screens and screen properties sf.ui.finder.windows.first.elementRaise(); //bring the active finder window to the front let window = sf.ui.finder.windows.first; //make it a variable because typing long things suck let mainScreen = sf.ui.screens.allScreens[0].visibleFrame; window.windowMove({position: {x: mainScreen.x, y: mainScreen.y,}}) // top left of my top screen, change to bottomScreen.x/.y for bottom.
- AAndrew Sherman @Andrew_Sherman
Amazing, thank you Dustin! So is allScreens[0] the first screen (only screen in my case)?
How do I get the window to go to one of the other quarters of the screen, eg bottom right?
Dustin Harris @Dustin_Harris
ok! so... yes.. allScreens[0] is the 'first screen', computers index things starting at 0. visible frame is is the resolution of your screen, minus the menu bar. I've made a little script that is kind of like a tutorial, check it out, hopefully it's as self explanatory as I think it is :)
sf.ui.screens.invalidate(); //make SoundFlow check up on your screens and screen properties let finderWindow = sf.ui.finder.windows.first; //this just shortens the name so I don't have to type "sf.ui.finder.windows.first each time" if (finderWindow.exists) {// check if there is a finder window open for us to play with sf.ui.finder.menuClick({ menuPath: ['File', 'New Finder Window'] }) //if not, open one finderWindow.elementWaitFor(); //and wait for it to appear, beacause macOS takes a second to do it. } finderWindow.elementRaise(); //bring the active finder window to the front of other apps. let mainScreen = sf.ui.screens.allScreens[0].visibleFrame //define visible screen properties as 'mainScreen' //mainScreen.w is the same as sf.ui.screens.allScreens[0].invalidate().visibleFrame.w alert(`The usable width of your main screen is: ${mainScreen.w} pixels`) //mainScreen.h is the same as sf.ui.screens.allScreens[0].invalidate().visibleFrame.w alert(`The usable heigh of your main screen is: ${mainScreen.h} pixels`) alert(`The Finder Window is ${finderWindow.frame.w} pixels wide`); alert(`The Finder Windows is ${finderWindow.frame.h} pixes tall`); alert(`The Finder window is at the screen coordinates of: ${finderWindow.frame.x}, ${finderWindow.frame.y}`); alert(`The next command will make the finder window half the screen height, and half the screen width`) finderWindow.windowMove({ size: { x: mainScreen.w / 2, y: mainScreen.h / 2, } }); alert(`the next command will make the finder window move to the top left of the screen`) finderWindow.windowMove({ position: { x: 0, y: 0, } }) alert(`the next command will make the finder window move to the bottom right of the screen`) finderWindow.windowMove({ position: { x: mainScreen.w - finderWindow.frame.w, y: mainScreen.h - finderWindow.frame.h, } }) alert(`the next command will make the finder window move to the centre of the screen`) finderWindow.windowMove({ position: { x: (mainScreen.w / 2) - (finderWindow.frame.w / 2) , y: (mainScreen.h / 2) - (finderWindow.frame.h / 2), } })
- AAndrew Sherman @Andrew_Sherman
Dustin, I'm voting that you join the perennial legends club...
Dustin Harris @Dustin_Harris
Hahaha! Not so fast, I just discovered a pretty important typo:
if (finderWindow.exists) {
Should be:
if (!finderWindow.exists) {
Note the “!”, it makes the condition you’ve stated the opposite. ,
!finderWindow.exists
is ‘finderWindow does NOT exist’
- In reply toDustin_Harris⬆:AAndrew Sherman @Andrew_Sherman
That's a great format for a tutorial
- In reply toDustin_Harris⬆:AAndrew Sherman @Andrew_Sherman
Hi Dustin,
The command to send the window to the bottom right places it at the bottom right of the screen, but it's not quite at the bottom, it's a little too high (by the same amount as the height of the menu bar). Do we need to factor that in? I'm on a single monitor with menu bar present on main screen.
Dustin Harris @Dustin_Harris
that's interesting. It works for me... are you hiding or showing your dock? (mine is hidden)... also I might have to invalidate the window somewhere to refresh the cache in case the window gets resized before being moved. I'll look into it :)
-D
EDIT! I TAKE IT BACK. Mine also does not go to the bottom of the screen...
- In reply toAndrew_Sherman⬆:
Dustin Harris @Dustin_Harris
using
.frame
instead of.visibleFrame
fixes it for me:add this line to your script:
let entireMainScreen = sf.ui.screens.allScreens[0].frame;
and then use this to move to the bottom right instead:
finderWindow.windowMove({ position: { x: entireMainScreen.w - finderWindow.frame.w, y: entireMainScreen.h - finderWindow.frame.h, } })
:)
- AAndrew Sherman @Andrew_Sherman
Great Dustin, that works nicely. Thank you so much for your help on this. I'm using similar code to try to manipulate the windows to half screen (and will get to thirds at some point), but I can't get it to work reliably like the quarter screens that we have going now.
If you randomly make a few new finder windows and then resize them, and then try to run it again, sometimes it doesn't re-size it properly.
Here's the versions of the script I'm working with. You'll see I'm using a variable for the app; ultimately I want to use this on various apps, not just Finder. I'm also setting it up so that it can become a template.
// Soundflow checks number of screens, and screen sizes sf.ui.screens.invalidate(); // Use 0 for main screen, 1 for second screen etc var screenNumber = 0; // I want to replace this with something that recognises the active foreground application, and gets the name/id of the app so that we can manipulate the windows var app = sf.ui.finder; let appWindow = app.windows.first; // Check if there is a window open if (appWindow.exists) { app.menuClick({ menuPath: ['File', 'New Finder Window'] }); appWindow.elementWaitFor(); } // Bring the active window to the front of other apps appWindow.elementRaise(); // Define visible screen properties as 'mainScreen' (excluding menu bar) let mainScreen = sf.ui.screens.allScreens[screenNumber].visibleFrame; // Whole screen size including menu bar let entireMainScreen = sf.ui.screens.allScreens[screenNumber].frame; // Notes: // mainScreen.w is the same as sf.ui.screens.allScreens[screenNumber].invalidate().visibleFrame.w // The usable width of your main screen is: ${mainScreen.w} pixels // mainScreen.h is the same as sf.ui.screens.allScreens[screenNumber].invalidate().visibleFrame.w // The usable heigh of your main screen is: ${mainScreen.h} pixels // The app window is ${appWindow.frame.w} pixels wide // The app window is ${appWindow.frame.h} pixes tall // The window is at the screen coordinates of: ${appWindow.frame.x}, ${appWindow.frame.y} // -------------------------------------------- // Quarter-size windows: // First re-size, then move // Resize window, make window half the screen height, and half the screen width // appWindow.windowMove({ size: { x: mainScreen.w / 2, y: mainScreen.h / 2, } }); // Move to top left // appWindow.windowMove({ position: { x: 0, y: 0, } }); // Move to bottom left // appWindow.windowMove({ position: { x: 0, y: entireMainScreen.h - appWindow.frame.h, } }); // Move to top right // appWindow.windowMove({ position: { x: entireMainScreen.w - appWindow.frame.w, y: 0, } }); // Move to bottom right // appWindow.windowMove({ position: { x: entireMainScreen.w - appWindow.frame.w, y: entireMainScreen.h - appWindow.frame.h, } }); // -------------------------------------------- // Half-size windows: // First re-size, then move // Make window full screen height, and half the screen width appWindow.windowMove({ size: { x: entireMainScreen.w / 2, y: entireMainScreen.h, } }); // Right - not working reliably yet appWindow.windowMove({ position: { x: entireMainScreen.w - appWindow.frame.w, y: 0, } }); // -------------------------------------------- // Make the window move to the centre of the screen // appWindow.windowMove({ position: { x: (mainScreen.w / 2) - (appWindow.frame.w / 2) , y: (mainScreen.h / 2) - (appWindow.frame.h / 2), } });
Dustin Harris @Dustin_Harris
So yeah, part of the simplification of the tutorial was to get the 'first' finder window, and that can be tricky with multiple windows, especially if you reorder them, resize them, etc and don't inform Sound Flow about what you've done. (side note: the invalidate() method helps mitigate this by essentially telling sound flow to 'forget what you think you know about x property, and go get the values as they are right now,
sf.ui.finder.window.invalidate().first
will tell Sound Flow to double check what it thinks it know about the first finder window. This info is 'cached' and .invalidate() 'invalidates the cache' forcing a fresh retrieve. This isn't our best approach here. Our best approach is to be more specific about WHAT windows we want to address:take this window:
it's my only finder window open at the moment, so I CAN address it as:
sf.ui.finder.windows.first
//the 'first' windowbut the more definitive way of addressing this window is:
sf.ui.finder.windows.whoseTitle.is("Dustin’s iMac").first
//the window titled 'Dustin's iMac'to resize the edit window in pro tools you would address:
sf.ui.proTools.mainWindow
so as I'm sure you're starting to see, different programs have different window type and names and accessing them in the most precise way can be a bit of a fact-finding mission, there are tools and tips on how to do this though! Maybe @Kitch has a video link handy to look at UI elements?Keep asking questions here though, and we'll try our best to help when you get stuck on something.
If it's helpful, here's a script I use all the time to resize my pro tools screen from full screen to half screen (super useful when I need to read documents or emails that reference things in my pro tools session):
//This script toggles the ProTools edit window from being fullscreen to half-width sf.ui.screens.invalidate(); var screenIndex = 0; var screenFrame = sf.ui.screens.allScreens[screenIndex].visibleFrame; sf.ui.proTools.appActivateMainWindow(); var editWindow = sf.ui.proTools.mainWindow; editWindow.windowMove({position: {x: 0, y: 0,}}) if (editWindow.frame.w +100 < screenFrame.w) { // to account for rounding errors in division editWindow.windowMove({size: {x: screenFrame.w, y: screenFrame.h}}); } else { editWindow.windowMove({size: {x: screenFrame.w / 2, y: screenFrame.h}}); }
- AAndrew Sherman @Andrew_Sherman
Thank you Dustin, appreciate it