Compare commits

...

3 Commits

Author SHA1 Message Date
francop 3c9c03b64b New files 2026-05-16 11:11:49 -04:00
francop 11ed9b80bc local SPEED_TO_DISABLE = 140.0 2026-05-16 11:10:43 -04:00
francop c3308429ff The Menu Render Guard implemetned to prevent IPC errors after sleep/wake 2026-05-16 11:10:16 -04:00
4 changed files with 85 additions and 62 deletions
+14
View File
@@ -34,6 +34,7 @@ obj.saveCountdown = obj.saveInterval
obj.isRescued = false
obj.isTransitioning = false
obj.isRestoring = false
obj.isMenuUpdating = false -- Safety guard to prevent concurrent IPC menu rendering loops
obj.wakeTimer = nil
obj.lastScreenCount = #hs.screen.allScreens()
obj.lastSavedTime = "Never"
@@ -231,6 +232,10 @@ end
local timerMenu = hs.menubar.new()
function updateMenu()
-- Safety Guard: Bail if update is already running from a previous thread block
if obj.isMenuUpdating then return end
obj.isMenuUpdating = true
if timerMenu then
local screens = hs.screen.allScreens()
timerMenu:setTitle(string.format("💠 %d:%02d", math.floor(obj.saveCountdown / 60), obj.saveCountdown % 60))
@@ -257,17 +262,25 @@ function updateMenu()
end
timerMenu:setMenu(menuTable)
end
obj.isMenuUpdating = false
end
obj.powerWatcher = hs.caffeinate.watcher.new(function(event)
if event == hs.caffeinate.watcher.systemWillSleep or event == hs.caffeinate.watcher.screensDidSleep or event == hs.caffeinate.watcher.screensDidLock then
log("POWER: Sleep event.")
obj.isTransitioning = true
-- Stop both timers entirely so they don't fire or stack requests while suspended
if obj.autoSaveTimer then obj.autoSaveTimer:stop() end
if obj.clockTimer then obj.clockTimer:stop() end
elseif event == hs.caffeinate.watcher.systemDidWake or event == hs.caffeinate.watcher.screensDidWake or event == hs.caffeinate.watcher.screensDidUnlock then
log("POWER: Wake event.")
obj.saveCountdown = obj.saveInterval
obj.isMenuUpdating = false -- Explicitly clean guard flag upon waking up
-- Safely start timers up only after wakeup initialization
if obj.autoSaveTimer then obj.autoSaveTimer:start() end
if obj.clockTimer then obj.clockTimer:start() end
if obj.wakeTimer then obj.wakeTimer:stop() end
local currentScreens = #hs.screen.allScreens()
@@ -285,6 +298,7 @@ obj.powerWatcher = hs.caffeinate.watcher.new(function(event)
obj.isTransitioning = false
obj.isRestoring = false
obj.lastScreenCount = currentScreens
updateMenu()
end
end
end):start()
@@ -0,0 +1,70 @@
{
"windows" : [
{
"x" : 0,
"winTitle" : "francop - Gitea: Git with a cup of tea - Google Chrome",
"y" : 30,
"appName" : "Google Chrome",
"h" : 957,
"w" : 1920,
"bundleID" : "com.google.Chrome"
},
{
"x" : 2883,
"winTitle" : "raycast-scripts — -zsh — 120×30",
"y" : 25,
"appName" : "Terminal",
"h" : 499,
"w" : 860,
"bundleID" : "com.apple.Terminal"
},
{
"x" : 2879,
"winTitle" : "francop — -zsh — 120×30",
"y" : 528,
"appName" : "Terminal",
"h" : 499,
"w" : 860,
"bundleID" : "com.apple.Terminal"
},
{
"x" : 2670,
"winTitle" : "lab-status.py — raycast-scripts — Untracked",
"y" : 366,
"appName" : "Code",
"h" : 714,
"w" : 1170,
"bundleID" : "com.microsoft.VSCode"
},
{
"x" : 0,
"winTitle" : "mouseJiggle.lua — .hammerspoon — Modified",
"y" : 30,
"appName" : "Code",
"h" : 956,
"w" : 1920,
"bundleID" : "com.microsoft.VSCode"
},
{
"x" : 1920,
"winTitle" : "AFFiNE",
"y" : 0,
"appName" : "AFFiNE",
"h" : 1080,
"w" : 960,
"bundleID" : "pro.affine.app"
},
{
"x" : 392,
"winTitle" : "Bluetooth",
"y" : 168,
"appName" : "System Settings",
"h" : 671,
"w" : 723,
"bundleID" : "com.apple.systempreferences"
}
],
"screenCount" : 3,
"saveTime" : "2026-05-16 04:21:57",
"mode" : "Docked"
}
-61
View File
@@ -1,61 +0,0 @@
{
"screenCount" : 3,
"windows" : [
{
"x" : -952,
"bundleID" : "com.apple.finder",
"y" : 159,
"appName" : "Finder",
"h" : 492,
"w" : 920,
"winTitle" : "raycast-scripts"
},
{
"x" : 2070,
"bundleID" : "com.raycast.macos",
"y" : 121,
"appName" : "Raycast",
"h" : 319,
"w" : 1000,
"winTitle" : "Settings"
},
{
"x" : 1986,
"bundleID" : "com.google.GeminiMacOS",
"y" : 110,
"appName" : "Gemini",
"h" : 536,
"w" : 1002,
"winTitle" : "Gemini — Hammerspoon Menu Bar Icon Troubleshooting"
},
{
"x" : 0,
"bundleID" : "com.google.Chrome",
"y" : 39,
"appName" : "Google Chrome",
"h" : 957,
"w" : 1920,
"winTitle" : "francop - Dashboard - Gitea: Git with a cup of tea - Google Chrome"
},
{
"x" : 2794,
"bundleID" : "com.apple.Terminal",
"y" : 131,
"appName" : "Terminal",
"h" : 499,
"w" : 860,
"winTitle" : "francop — -zsh — 120×30"
},
{
"x" : 0,
"bundleID" : "com.microsoft.VSCode",
"y" : 30,
"appName" : "Code",
"h" : 957,
"w" : 1920,
"winTitle" : "init.lua — .hammerspoon"
}
],
"saveTime" : "2026-05-15 22:26:48",
"mode" : "Docked"
}
+1 -1
View File
@@ -7,7 +7,7 @@ local LOCKOUT_DURATION = 3.0 -- Cooldown duration (seconds) before allowed to
-- Asymmetrical Thresholds
local SPEED_TO_ENABLE = 115.0 -- Slightly lower: easier to turn ON
local SPEED_TO_DISABLE = 150.0 -- Slightly higher: harder to accidentally turn OFF
local SPEED_TO_DISABLE = 140.0 -- Slightly higher: harder to accidentally turn OFF
-- Focusdim Global Hotkey Configuration from your settings
local FOCUS_DIM_MODS = { "ctrl", "alt", "shift", "cmd" }