Turn hiding of Dock on or off by hammerspoon #3560
-
Hi everyone, I want to use hammerspoon to turn the hiding of Dock on or off in my script. I found maybe I could use Here's something I got:
And Good Night! |
Beta Was this translation helpful? Give feedback.
Replies: 4 comments 1 reply
-
Now I find I can use hs.execute("defaults write com.apple.dock autohide -bool yes/no; killall Dock") to turn on or off. But I don't think it is elegant. So I still want to open this discussion, for how to do this work by hammerspoon-self. |
Beta Was this translation helpful? Give feedback.
-
For items with popup menus, the menu items don't "exist", and thus don't have AXUIElement's we can access, unless the menu is showing (unlike the application menus, whose AXUIElement's always exist all the time). So, we have to take a few extra steps: toggleDockHiding = function()
local axuielement = require("hs.axuielement")
local timer = require("hs.timer")
local minFloat = require("hs.math").minFloat
local dockElement = axuielement.applicationElement("com.apple.dock")
local separator = nil
-- the first child of the dock item is a list of the icons on display
for _, child in ipairs(dockElement[1]) do
if child.AXSubrole == "AXSeparatorDockItem" then
separator = child
break
end
end
if separator then
separator:doAXShowMenu()
-- the children of the first child of `separator` will be the menu items, but it may take
-- time to populate the list, so put the rest in a timer to give the application loop time to
-- progress
local menuTimer
menuTimer = timer.doAfter(minFloat, function()
menuTimer = nil -- make upvalue so not collected prematurely
for _, menuitem in ipairs(separator[1]) do
if menuitem.AXTitle:match("^Turn Hiding O") then
menuitem:doAXPress()
return
end
end
-- if we're still here, then didn't find menu item
separator:doAXShowMenu() -- closes menu
end)
end
end |
Beta Was this translation helpful? Give feedback.
-
Be warned that killing the Dock like that may cause all your minimized windows to un-minimize themselves. (And possibly other side effects. The 'Dock' process is in charge of a surprising amount of non-Dock features, including Exposé/Spaces/Mission Control/whatever the current macOS is calling it.) Another option that doesn't require killing the Dock or popping up menus is to use AppleScript: -- Normally you can just use the builtin applescript function:
local applescript = hs.osascript.applescript
-- But as described in #1980, that function currently has a memory leak.
-- You might be better off running the AppleScript in a separate process like this instead:
local gsub = string.gsub
local function shellArg(x)
return [[']] .. gsub(x, [[']], [['\'']]) .. [[']]
end
local function applescript(x)
hs.execute('osascript -e '..shellArg(x))
end
-----------------------------------------------------------
local setDockAutohideScript = [[
tell application "System Events"
tell dock preferences
set autohide to %s
end tell
end tell
]]
local function setDockAutohide(autohide)
applescript(setDockAutohideScript:format(autohide and 'true' or 'false'))
end
local function toggleDockAutohide()
applescript(setDockAutohideScript:format('not autohide'))
end
setDockAutohide(true) Also, by default, there is a builtin keyboard shortcut to toggle Dock hiding: ⌘ Command-⌥ Option-D. (You can change it or turn it off by going to System Preferences → Keyboard → Shortcuts → Launchpad & Dock.) So if all you need is to be able to toggle Dock hiding from the keyboard, you can just use that. Or you can send that keyboard shortcut from Hammerspoon to toggle the Dock: hs.eventtap.keyStroke({'command', 'option'}, 'd') |
Beta Was this translation helpful? Give feedback.
-
To complement @Rhys-T amazing answer, here is the full script to monitor if external display is connected and toggle dock autohide accordingly: -- Normally you can just use the builtin applescript function:
local applescript = hs.osascript.applescript
-- But as described in #1980, that function currently has a memory leak.
-- You might be better off running the AppleScript in a separate process like this instead:
local gsub = string.gsub
local function shellArg(x)
return [[']] .. gsub(x, [[']], [['\'']]) .. [[']]
end
local function applescript(x)
hs.execute('osascript -e '..shellArg(x))
end
-----------------------------------------------------------
local setDockAutohideScript = [[
tell application "System Events"
tell dock preferences
set autohide to %s
end tell
end tell
]]
local function setDockAutohide(autohide)
applescript(setDockAutohideScript:format(autohide and 'true' or 'false'))
end
local function toggleDockAutohide()
applescript(setDockAutohideScript:format('not autohide'))
end
-----------------------------------------------------------
function isExternalMonitorConnected()
local screens = hs.screen.allScreens()
local builtinScreen = hs.screen.primaryScreen() -- Usually the built-in screen is the primary one
for _, screen in ipairs(screens) do
if screen:id() ~= builtinScreen:id() then
return true
end
end
return false
end
local wasExternalConnected = isExternalMonitorConnected()
function monitorWatcherCallback()
local isExternalConnected = isExternalMonitorConnected()
if isExternalConnected and not wasExternalConnected then
print("👍 External monitor connected")
setDockAutohide(false)
elseif not isExternalConnected and wasExternalConnected then
print("👎 External monitor disconnected")
setDockAutohide(true)
end
wasExternalConnected = isExternalConnected
end
local screenWatcher = hs.screen.watcher.new(monitorWatcherCallback)
screenWatcher:start() |
Beta Was this translation helpful? Give feedback.
For items with popup menus, the menu items don't "exist", and thus don't have AXUIElement's we can access, unless the menu is showing (unlike the application menus, whose AXUIElement's always exist all the time). So, we have to take a few extra steps: