How to move an application between monitors in Hammerspoon?
Asked Answered
T

5

11

At work I have a 3 monitor setup. I would like to move the current application to a second or a third monitor with a key binding. How to do that?

Tracery answered 11/1, 2019 at 17:27 Comment(0)
W
16

The screen library helps finding the right "display". allScreens lists the displays in the same order as they are defined by the system. The hs.window:moveToScreen function moves to a given screen, where it's possible to set the UUID.

The following code works for me. Hitting CTRL+ALT+CMD+ 3 moves the currently focused window to display 3, same as if you would choose "Display 3" in the Dock's Option menu.

function moveWindowToDisplay(d)
  return function()
    local displays = hs.screen.allScreens()
    local win = hs.window.focusedWindow()
    win:moveToScreen(displays[d], false, true)
  end
end

hs.hotkey.bind({"ctrl", "alt", "cmd"}, "1", moveWindowToDisplay(1))
hs.hotkey.bind({"ctrl", "alt", "cmd"}, "2", moveWindowToDisplay(2))
hs.hotkey.bind({"ctrl", "alt", "cmd"}, "3", moveWindowToDisplay(3))
Wendell answered 15/10, 2019 at 15:39 Comment(1)
This is good but you need to know here which screen if first, second etc...Hawks
I
25

I use the following script to cycle the focused window through the screens.

-- bind hotkey
hs.hotkey.bind({'alt', 'ctrl', 'cmd'}, 'n', function()
  -- get the focused window
  local win = hs.window.focusedWindow()
  -- get the screen where the focused window is displayed, a.k.a. current screen
  local screen = win:screen()
  -- compute the unitRect of the focused window relative to the current screen
  -- and move the window to the next screen setting the same unitRect 
  win:move(win:frame():toUnitRect(screen:frame()), screen:next(), true, 0)
end)
Inanity answered 1/11, 2019 at 15:54 Comment(0)
W
16

The screen library helps finding the right "display". allScreens lists the displays in the same order as they are defined by the system. The hs.window:moveToScreen function moves to a given screen, where it's possible to set the UUID.

The following code works for me. Hitting CTRL+ALT+CMD+ 3 moves the currently focused window to display 3, same as if you would choose "Display 3" in the Dock's Option menu.

function moveWindowToDisplay(d)
  return function()
    local displays = hs.screen.allScreens()
    local win = hs.window.focusedWindow()
    win:moveToScreen(displays[d], false, true)
  end
end

hs.hotkey.bind({"ctrl", "alt", "cmd"}, "1", moveWindowToDisplay(1))
hs.hotkey.bind({"ctrl", "alt", "cmd"}, "2", moveWindowToDisplay(2))
hs.hotkey.bind({"ctrl", "alt", "cmd"}, "3", moveWindowToDisplay(3))
Wendell answered 15/10, 2019 at 15:39 Comment(1)
This is good but you need to know here which screen if first, second etc...Hawks
D
5

Not exactly the answer to OP but leaving this here for others who also want to cycle through monitors and maximize on each screen:

local app = hs.window.focusedWindow()
app:moveToScreen(app:screen():next())
app:maximize()

You can put this in a function and bind it to Ctrl + Alt + n like so:

function moveToNextScreen()
  local app = hs.window.focusedWindow()
  app:moveToScreen(app:screen():next())
  app:maximize()
end

hs.hotkey.bind({"ctrl", "alt"}, "n", moveToNextScreen)
Durman answered 5/11, 2020 at 10:12 Comment(0)
S
3

I've answered this in Reddit post here, but in case anyone comes across this question here's the answer:

The Hammerspoon API doesn't provide an explicit function for doing this, so you gotta roll out with a custom implementation to achieve this:

-- Get the focused window, its window frame dimensions, its screen frame dimensions,
-- and the next screen's frame dimensions.
local focusedWindow = hs.window.focusedWindow()
local focusedScreenFrame = focusedWindow:screen():frame()
local nextScreenFrame = focusedWindow:screen():next():frame()
local windowFrame = focusedWindow:frame()

-- Calculate the coordinates of the window frame in the next screen and retain aspect ratio
windowFrame.x = ((((windowFrame.x - focusedScreenFrame.x) / focusedScreenFrame.w) * nextScreenFrame.w) + nextScreenFrame.x)
windowFrame.y = ((((windowFrame.y - focusedScreenFrame.y) / focusedScreenFrame.h) * nextScreenFrame.h) + nextScreenFrame.y)
windowFrame.h = ((windowFrame.h / focusedScreenFrame.h) * nextScreenFrame.h)
windowFrame.w = ((windowFrame.w / focusedScreenFrame.w) * nextScreenFrame.w)

-- Set the focused window's new frame dimensions
focusedWindow:setFrame(windowFrame)

Wrapping the snippet above in a function and binding it to a hotkey should cycle the currently focused application across your different monitors.

Stipendiary answered 20/4, 2019 at 22:31 Comment(0)
U
1

Another way to move the window around is to use the directional move functions, e.g. win:moveOneScreenEast() and the like (there's one function for each direction). I find it useful to bind arrow keys to effect mnemonic keyboard shortcuts.

hs.hotkey.bind({'alt', 'ctrl', 'cmd'}, 'Right', function()
  local win = hs.window.focusedWindow()
  win:moveOneScreenEast(false, true, 0.5)
end)
hs.hotkey.bind({'alt', 'ctrl', 'cmd'}, 'Left', function()
  local win = hs.window.focusedWindow()
  win:moveOneScreenWest(false, true, 0.5)
end)

Reference: http://hammerspoon.org/docs/hs.window.html#moveOneScreenEast

Ulmaceous answered 22/4, 2023 at 21:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.