luahammerspoon

Hammerspoon Window management does not work as expected on secondary monitor


I'm new to Lua and hammerspoon and can not for the life of me figure out why the below code works fine on my primary screen, but the cycling though positions does not work on my secondary monitor. hitting the shortcut on windows on the secondary monitor enables the first position, but a second press does nothing.

Reading the docs, hs.screen.mainScreen() enable the current focused screen so it should work?

As an aside...the secondary monitor is actually physically the same monitor as the primary running PBP (otherwise graphics card can not handle the resolution)

I've only posted the code i think is relevant below:

local rightScreen = hs.screen.primaryScreen(0x600003f98880)
local leftScreen = rightScreen:toWest()

function bindKey(key, fn)
  hs.hotkey.bind({"cmd", "ctrl","alt"}, key, fn)
end

grid = {
  {key="q", units={positions.leftthird, positions.left50, positions.left66}},
  {key="w", units={positions.middlethird}},
  {key="e", units={positions.rightthird}},
  {key="r", units={positions.left50, positions.lower50Left50, positions.upper50Left50, positions.upper50, positions.lower50}}, -- virker IKKE på sekundære skærm
  {key="t", units={positions.right50, positions.lower50Right50, positions.upper50Right50, positions.upper50, positions.lower50}}, -- virker IKKE på sekundære skærm

}

hs.fnutils.each(grid, function(entry)
  bindKey(entry.key, function()
    local units = entry.units
    local screen = hs.screen.mainScreen()
    local window = hs.window.focusedWindow()
    local windowGeo = window:frame()

    local index = 0
    hs.fnutils.find(units, function(unit)
      index = index + 1

      local geo = hs.geometry.new(unit):fromUnitRect(screen:frame()):floor()
     return windowGeo:equals(geo)
    end)
    if index == #units then index = 0 end

    window:moveToUnit(units[index + 1])
  end)
end)

Solution

  • Best I can do is post my own code for a similar purpose that I wrote 3+ years ago and it's been working perfectly since then, on both internal and external monitors. As you can see I'm using win:setFrame instead of :moveToUnit. Sorry I can't help in debugging your problem but I've forgotten Lua and Hammerspoon already... Hope that helps

    function coords ()
      return hs.window.focusedWindow(), hs.window.focusedWindow():frame(),
             hs.window.focusedWindow():screen(), hs.window.focusedWindow():screen():frame()
    end
    
    
    hs.hotkey.bind({"cmd", "alt", "ctrl"}, "left", function()
    
      local win, wf, scr, sf = coords()
    
      if wf.x <= sf.x and wf.w <= math.floor(sf.w/3) then
        wf.x = sf.x
        wf.w = math.floor(sf.w/4)
      elseif wf.x <= sf.x and wf.w <= math.floor(sf.w/2) then
        wf.x = sf.x
        wf.w = math.floor(sf.w/3)
      else
        wf.x = sf.x
        wf.w = math.floor(sf.w/2)
      end
      wf.y=sf.y
      wf.h=sf.h
      win:setFrame(wf, 0)
    end)
    
    
    hs.hotkey.bind({"cmd", "alt", "ctrl"}, "right", function()
    
      local win, wf, scr, sf = coords()
    
      if wf.x >= math.floor(sf.x + sf.w/3) and wf.w <= math.floor(sf.w/3) then
        wf.w = sf.w/4
        wf.x = math.floor(sf.x + 3 * sf.w/4)
      elseif wf.x >= math.floor(sf.x + sf.w/2) and wf.w <= math.floor(sf.w/2) then
        wf.w = sf.w/3
        wf.x = math.floor(sf.x + 2 * sf.w/3)
      else
        wf.w = sf.w/2
        wf.x = math.floor(sf.x + sf.w/2)
      end
      wf.y=sf.y
      wf.h=sf.h
      win:setFrame(wf, 0)
    end)
    
    
    hs.hotkey.bind({"cmd", "alt", "ctrl"}, "up", function()
    
      local win, wf, scr, sf = coords()
    
      win:setFrame(sf, 0)
    end)
    
    hs.hotkey.bind({"cmd", "alt", "ctrl"}, "down", function()
    
      local win, wf, scr, sf = coords()
    
      if wf.x ~= math.floor(sf.x + sf.w/3) and wf.w ~= math.floor(sf.w/3) then
        wf.w = math.floor(sf.w/3)
        wf.x = math.floor(sf.x + sf.w/3)
      else
        wf.w = sf.w/2
        wf.x = math.floor(sf.x + sf.w/4)
      end
      wf.y=sf.y
      wf.h=sf.h
    
      win:setFrame(wf, 0)
    end)