From eec103d5e2cce551426eb48942714988d335d8bb Mon Sep 17 00:00:00 2001 From: Michael Mogenson Date: Mon, 20 May 2024 09:47:17 -0400 Subject: [PATCH] Hacky work around for private move window to space function 1. Switch to the desired space 2. Wait for new space to become visible on screen 3. Move window to new space 4. Wait for window to register as part of new space 5. Tile spaces --- init.lua | 80 ++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 69 insertions(+), 11 deletions(-) diff --git a/init.lua b/init.lua index 5353394..bc9a144 100644 --- a/init.lua +++ b/init.lua @@ -42,6 +42,7 @@ local WindowFilter = hs.window.filter local leftClick = hs.eventtap.leftClick local partial = hs.fnutils.partial local rectMidPoint = hs.geometry.rectMidPoint +local operatingSystemVersion = hs.host.operatingSystemVersion local PaperWM = {} PaperWM.__index = PaperWM @@ -389,10 +390,12 @@ function PaperWM:tileSpace(space) -- if focused window is in space, tile from that local focused_window = Window.focusedWindow() - local anchor_window = (focused_window and - (Spaces.windowSpaces(focused_window)[1] == space)) and - focused_window or - getFirstVisibleWindow(window_list[space], screen) + local anchor_window = nil + if focused_window and Spaces.windowSpaces(focused_window)[1] == space then + anchor_window = focused_window + else + anchor_window = getFirstVisibleWindow(window_list[space], screen) + end if not anchor_window then self.logger.e("no anchor window in space") @@ -577,6 +580,7 @@ function PaperWM:removeWindow(remove_window, skip_new_window_focus) end -- remove watcher + ui_watchers[remove_window:id()]:stop() ui_watchers[remove_window:id()] = nil -- update index table @@ -1059,6 +1063,13 @@ function PaperWM:moveWindowToSpace(index, window) return end + + local screen = Screen(Spaces.spaceDisplay(new_space)) + if not screen then + self.logger.d("no screen for space") + return + end + -- cache a copy of focused_window, don't switch focus when removing window local old_space = self:removeWindow(focused_window, true) if not old_space then @@ -1066,13 +1077,60 @@ function PaperWM:moveWindowToSpace(index, window) return end - Spaces.moveWindowToSpace(focused_window, new_space) - self:addWindow(focused_window) - self:tileSpace(old_space) - self:tileSpace(new_space) - Spaces.gotoSpace(new_space) - - focusSpace(new_space, focused_window) + -- Hopefully this ugly hack isn't around for long + -- https://github.com/Hammerspoon/hammerspoon/issues/3636 + local version = operatingSystemVersion() + if version.major * 100 + version.minor >= 1405 then + local do_window_move = coroutine.wrap(function() + repeat + coroutine.yield(false) -- not done + until Spaces.activeSpaceOnScreen(screen:id()) == new_space + + local window_frame = focused_window:frame() + local screen_frame = getCanvas(screen) + + -- center window and fit to new screen + window_frame.w = math.min(window_frame.w, screen_frame.w) + window_frame.h = math.min(window_frame.h, screen_frame.h) + window_frame.x = screen_frame.x + (screen_frame.w // 2) - + (window_frame.w // 2) + window_frame.y = screen_frame.y + (screen_frame.h // 2) - + (window_frame.h // 2) + + focused_window:setFrame(window_frame) + + repeat + coroutine.yield(false) -- not done + until Spaces.windowSpaces(focused_window)[1] == new_space + + -- add window and tile + self:addWindow(focused_window) + focused_window:focus() + self:tileSpace(old_space) + self:tileSpace(new_space) + return true -- done + end) + + -- switch spaces, wait for space to be ready, move window, wait for window to be ready + Spaces.gotoSpace(new_space) + local start_time = Timer.secondsSinceEpoch() + Timer.doUntil(do_window_move, function(timer) + if Timer.secondsSinceEpoch() - start_time > 5 then + self.logger.ef("moveWindowToSpace() timeout! new space %d curr space %d window space %d", new_space, + Spaces.activeSpaceOnScreen(screen:id()), Spaces.windowSpaces(focused_window)[1]) + timer:stop() + end + end, + Window.animationDuration) + else -- MacOS < 14.5 + Spaces.moveWindowToSpace(focused_window, new_space) + self:addWindow(focused_window) + self:tileSpace(old_space) + self:tileSpace(new_space) + Spaces.gotoSpace(new_space) + + focusSpace(new_space, focused_window) + end end ---move and resize a window to the coordinates specified by the frame