Skip to content

Instantly share code, notes, and snippets.

@tmandry
Created December 21, 2014 08:30
Show Gist options
  • Save tmandry/a5b1ab6d6ea012c1e8c5 to your computer and use it in GitHub Desktop.
Save tmandry/a5b1ab6d6ea012c1e8c5 to your computer and use it in GitHub Desktop.
Track all window open, close, move, and resize events using Hammerspoon
local events = hs.uielement.watcher
watchers = {}
function init()
appsWatcher = hs.application.watcher.new(handleGlobalAppEvent)
appsWatcher:start()
-- Watch any apps that already exist
local apps = hs.application.runningApplications()
for i = 1, #apps do
if apps[i]:title() ~= "Hammerspoon" then
watchApp(apps[i], true)
end
end
end
function handleGlobalAppEvent(name, event, app)
if event == hs.application.watcher.launched then
watchApp(app)
elseif event == hs.application.watcher.terminated then
-- Clean up
local appWatcher = watchers[app:pid()]
if appWatcher then
appWatcher.watcher:stop()
for id, watcher in pairs(appWatcher.windows) do
watcher:stop()
end
watchers[app:pid()] = nil
end
end
end
function watchApp(app, initializing)
if watchers[app:pid()] then return end
local watcher = app:newWatcher(handleAppEvent)
watchers[app:pid()] = {watcher = watcher, windows = {}}
watcher:start({events.windowCreated, events.focusedWindowChanged})
-- Watch any windows that already exist
for i, window in pairs(app:allWindows()) do
watchWindow(window, initializing)
end
end
function handleAppEvent(element, event)
if event == events.windowCreated then
watchWindow(element)
elseif event == events.focusedWindowChanged then
-- Handle window change
end
end
function watchWindow(win, initializing)
local appWindows = watchers[win:application():pid()].windows
if win:isStandard() and not appWindows[win:id()] then
local watcher = win:newWatcher(handleWindowEvent, {pid=win:pid(), id=win:id()})
appWindows[win:id()] = watcher
watcher:start({events.elementDestroyed, events.windowResized, events.windowMoved})
if not initializing then
hs.alert.show('window created: '..win:id()..' with title: '..win:title())
end
end
end
function handleWindowEvent(win, event, watcher, info)
if event == events.elementDestroyed then
watcher:stop()
watchers[info.pid].windows[info.id] = nil
else
-- Handle other events...
end
hs.alert.show('window event '..event..' on '..info.id)
end
init()
@tmandry
Copy link
Author

tmandry commented Dec 21, 2014

Depends on Hammerspoon/hammerspoon#162 and Hammerspoon/hammerspoon#161

The bookkeeping is almost all for the purpose of not leaking resources when apps or windows are closed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment