phoenix icon indicating copy to clipboard operation
phoenix copied to clipboard

3 Monitor setup - Move window to specific monitor

Open ABC-LG opened this issue 3 years ago • 8 comments

  • Version: 3.0.0 (127)
  • macOS: 12.5.1

I have a setup with 3 monitors and want to be able to move a window to a specific screen using a key combination.

I know how to move my window to the next screen and how to fetch the UUID identifier for all screens, but I have no clue on how to achieve this.

Send window to the next screen:

Key.on('n', ['ctrl', 'shift'], () => {
    const window = Window.focused();
    const nextScreenFrame = frameOfNextScreen(window);
    if (!window || !nextScreenFrame) {
        return;
    }
    if (windowFitsInFrame(window, nextScreenFrame)) {

        centerWindowInFrame(window, nextScreenFrame);
    } else {
        maximizeWindowInFrame(window, nextScreenFrame);
    }
});

function frameOfNextScreen(window) {
    if (!window || !window.screen().next()) {
        return;
    }
    return window.screen().next().flippedVisibleFrame();
}

Thanks in advance for any help.

ABC-LG avatar Sep 09 '22 13:09 ABC-LG

Hey! Perhaps use Screen.all() and find the screen instance you are interested on with the UUID from the provided array? The UUIDs stay constant, so you can define them static based on your display setup.

kasper avatar Sep 09 '22 17:09 kasper

Something like this could also work:

const orderedScreens = Screen.all().sort((a, b) => a.frame().x - b.frame().x);

It should give you your screens in horizontal order so you can place windows via moveToScreen(orderedScreens[1]).

mafredri avatar Sep 10 '22 11:09 mafredri

Hi there, I am also struggling with this same issue. Is moveToScreen() a function defined somewhere? I don't see it when searching the repo.

thetomcraig avatar Oct 11 '22 02:10 thetomcraig

@thetomcraig Hi, there is no moveToScreen(…) function in the core API. You need to use the setFrame(…) or setTopLeft(…) to move a window to a specific screen by using the screen’s coordinates. Hope that helps! https://kasper.github.io/phoenix/api/window

kasper avatar Oct 11 '22 17:10 kasper

Okay this makes sense, the missing piece though is getting those coordinates for a desired screen based on it's UUID. I don't see a way to do this with the Screen API, afaik.

The method I can think of now would be to do a loop that calls .next() repeatedly on an iterator until it finds the one with the identifier property matching the desired screen's UUID, then get's it's frame, then sets that frame for the current window. Something like this pseudo code:

  const desiredUUID = '37D8832A-2D66-02CA-B9F7-8F30A301B230'

  const window = Window.focused ();
  const oldScreen = window.screen();

  let desiredScreen = undefined;
  let screenIterator = oldScreen.next();
  while(!oldScreen.isEqual(newScreen)) {
    if (screenIterator.identifier() === desiredUUID) {
       desiredScreen = screenIterator;
       break;
    }
    screenIterator = screenIterator.next();
  }

if (desiredScreen !== undefined) {
  const ratio = frameRatio(
     oldScreen.flippedVisibleFrame(), 
     desiredScreen.flippedVisibleFrame(),
  )
  window.setFrame(ratio(window.frame()));
}

I think this should work but it seems pretty inefficient. Am I missing something here?

thetomcraig avatar Oct 13 '22 17:10 thetomcraig

@thetomcraig How about something like this?

const foundScreen = Screen.all().find(screen => screen.identifier() === desiredUUID);

kasper avatar Oct 14 '22 05:10 kasper

YES this is perfect! (As you can tell I'm not a js developer, lol). I was able to achieve what I wanted with this, it may prove useful to others:

const windowIds = [
                    "37D8832A-2D66-02CA-B9F7-8F30A301B230",
                    "95458444-A649-45C1-94AA-7D8880A7144F",
                    "AA4129F8-E94C-455C-A2CE-F3C7DF605E8E",
                    "B2085621-B801-4448-8FB9-30E7D08C1419",
                    "3913815D-56F0-4FE7-90F7-6CB91892A81D"
                   ];

function frameRatio(a, b){
  const widthRatio = b.width / a.width;
  const heightRatio = b.height / a.height;

  return ({width, height, x, y}) => {
    width = Math.round(width * widthRatio);
    height = Math.round(height * heightRatio);
    x = Math.round(b.x + (x - a.x) * widthRatio);
    y = Math.round(b.y + (y - a.y) * heightRatio);

    return {width, height, x, y};
  };
};

function moveToDisplayWithUUID(uuid) {
  const window = Window.focused ();
  if ( !window ) return;

  const oldScreen = window.screen(); 

  const newScreen = Screen.all().find(screen => screen.identifier() === uuid)

  if(oldScreen.isEqual(newScreen) || newScreen === undefined) {
     return; 
  }

  const ratio = frameRatio(
     oldScreen.flippedVisibleFrame(), 
     newScreen.flippedVisibleFrame(),
  )

  window.setFrame(ratio(window.frame()));
}

setKeyHandler ('1', HYPER, () => {
  moveToDisplayWithUUID(windowIds[0])
});
...
other functions here for other indices

Thanks @kasper this is great.

thetomcraig avatar Oct 17 '22 02:10 thetomcraig

@thetomcraig Awesome! 😁

kasper avatar Oct 17 '22 05:10 kasper