@@ -166,9 +166,10 @@ function windowfilter._showCandidates()
166166 local t = {}
167167 for _ ,app in ipairs (running ) do
168168 local appname = app :name ()
169+ local pid = app :pid ()
169170 if appname and windowfilter .isGuiApp (appname ) and # app :allWindows ()== 0
170171 and not windowfilter .ignoreInDefaultFilter [appname ] and app :kind ()>= 0
171- and (not apps [appname ] or not next (apps [appname ].windows )) then
172+ and (not apps [pid ] or not next (apps [pid ].windows )) then
172173 t [# t + 1 ]= appname
173174 end
174175 end
@@ -277,17 +278,17 @@ function WF:isWindowAllowed(theWindow)
277278 -- which allegedly is a window, but without id
278279 if not id then return end
279280 if activeInstances [self ] then return self .windows [id ] and true or false end
280- local appname ,win = theWindow :application ():name ()
281- if apps [appname ] then
282- for wid ,w in pairs (apps [appname ].windows ) do
281+ local pid ,win = theWindow :application ():pid ()
282+ if apps [pid ] then
283+ for wid ,w in pairs (apps [pid ].windows ) do
283284 if wid == id then win = w break end
284285 end
285286 end
286287 if not win then
287288 -- hs.assert(not global.watcher,'window not being tracked')
288289 self .log .d (' window is not being tracked' )
289290 win = Window .new (theWindow ,id ) -- fixme
290- win .app = {} win .app .name = appname
291+ win .app = {} win .app .name = theWindow : application (): name ()
291292 if self .trackSpacesFilters then
292293 win .isInCurrentSpace = false
293294 if not win .isVisible then win .isInCurrentSpace = true
@@ -1205,7 +1206,7 @@ function App:getFocused()
12051206 if not self .windows [fwid ] then
12061207 -- windows on a different space aren't picked up by :allWindows() at first refresh
12071208 log .df (' %s (%d) was not registered' ,self .name ,fwid )
1208- appWindowEvent (fw ,uiwatcher .windowCreated ,nil ,self .name )
1209+ appWindowEvent (fw ,uiwatcher .windowCreated ,nil ,self .pid )
12091210 end
12101211 if not self .windows [fwid ] then
12111212 log .wf (' %s (%d) is STILL not registered' ,self .name ,fwid )
@@ -1215,13 +1216,13 @@ function App:getFocused()
12151216 end
12161217end
12171218
1218- function App .new (app ,appname ,watcher )
1219- local o = setmetatable ({app = app ,name = appname ,watcher = watcher ,windows = {}},{__index = App })
1219+ function App .new (app ,appname ,pid , watcher )
1220+ local o = setmetatable ({app = app ,name = appname ,pid = pid , watcher = watcher ,windows = {}},{__index = App })
12201221 if app :isHidden () then o .isHidden = true end
12211222 -- TODO if a way is found to fecth *all* windows across spaces, add it here
12221223 -- and remove .switchedToSpace, .forceRefreshOnSpaceChange
12231224 log .f (' new app %s registered' ,appname )
1224- apps [appname ] = o
1225+ apps [pid ] = o
12251226 o :getAppWindows ()
12261227end
12271228
@@ -1261,7 +1262,7 @@ function App:getCurrentSpaceAppWindows(inserted)
12611262 for _ ,win in ipairs (allWindows ) do
12621263 local id = win :id ()
12631264 if id then
1264- if not self .windows [id ] then appWindowEvent (win ,uiwatcher .windowCreated ,nil ,self .name ) end
1265+ if not self .windows [id ] then appWindowEvent (win ,uiwatcher .windowCreated ,nil ,self .pid ) end
12651266 gone [id ]= nil
12661267 arrived [id ]= self .windows [id ]
12671268 end
@@ -1310,7 +1311,7 @@ function App:focusChanged(id,win)
13101311 else
13111312 if not self .windows [id ] then
13121313 log .df (' %s (%d) is not registered yet' ,self .name ,id )
1313- appWindowEvent (win ,uiwatcher .windowCreated ,nil ,self .name )
1314+ appWindowEvent (win ,uiwatcher .windowCreated ,nil ,self .pid )
13141315 end
13151316 if self == active then
13161317 if not self .windows [id ] then log .wf (' cannot process focus changed for app %s - %s (%d) not registered' ,self .name ,win :role (),id )
@@ -1344,11 +1345,12 @@ function App:destroyed()
13441345 for _ ,win in pairs (self .windows ) do
13451346 win :destroyed ()
13461347 end
1347- apps [self .name ]= nil
1348+ apps [self .pid ]= nil
13481349end
13491350
1350- local function windowEvent (event ,appname ,id )
1351- local app = apps [appname ]
1351+ local function windowEvent (event ,pid ,id )
1352+ local app = apps [pid ]
1353+ local appname = app .name
13521354 log .vf (' %s (%s) <= %s (window event)' ,appname ,id or ' ?' ,event )
13531355 if not id then return log .df (' %s: %s cannot be processed' ,appname ,event ) end
13541356 if not app then return log .df (' app %s is not registered!' ,appname ) end
@@ -1371,8 +1373,9 @@ end
13711373local RETRY_DELAY ,MAX_RETRIES = 0.2 ,5
13721374local windowWatcherDelayed = {}
13731375
1374- appWindowEvent = function (win ,event ,_ ,appname ,retry )
1376+ appWindowEvent = function (win ,event ,_ ,pid ,retry )
13751377 if not win :isWindow () then return end
1378+ local appname = application .applicationForPID (pid ):name ()
13761379 local role = win .subrole and win :subrole ()
13771380 if appname == ' Hammerspoon' and (not role or role == ' AXUnknown' ) then return end
13781381 local id = win .id and win :id ()
@@ -1382,34 +1385,35 @@ appWindowEvent=function(win,event,_,appname,retry)
13821385 retry = (retry or 0 )+ 1
13831386 if not id then
13841387 if retry > MAX_RETRIES then log .wf (' %s: %s has no id' ,appname ,role or (win .role and win :role ()) or ' window' )
1385- else windowWatcherDelayed [win ]= timer .doAfter (retry * RETRY_DELAY ,function ()appWindowEvent (win ,event ,_ ,appname ,retry )end ) end
1388+ else windowWatcherDelayed [win ]= timer .doAfter (retry * RETRY_DELAY ,function ()appWindowEvent (win ,event ,_ ,pid ,retry )end ) end
13861389 return
13871390 end
1388- if apps [appname ].windows [id ] then return log .df (' %s (%d) already registered' ,appname ,id ) end
1391+ if apps [pid ].windows [id ] then return log .df (' %s (%d) already registered' ,appname ,id ) end
13891392 local watcher = win :newWatcher (function (_ ,watcherEvent )
1390- windowEvent (watcherEvent ,appname ,id )
1391- end , appname )
1393+ windowEvent (watcherEvent ,pid ,id )
1394+ end )
13921395-- pretty sure this is a NOP now since pid capture is no longer delayed
13931396-- if not watcher:pid() then
13941397-- log.wf('%s: %s has no watcher pid',appname,role or (win.role and win:role()))
13951398-- if retry>MAX_RETRIES then log.df('%s: %s has no watcher pid',appname,win.subrole and win:subrole() or (win.role and win:role()) or 'window')
13961399-- else
1397- -- windowWatcherDelayed[win]=timer.doAfter(retry*RETRY_DELAY,function()appWindowEvent(win,event,_,appname ,retry)end) end
1400+ -- windowWatcherDelayed[win]=timer.doAfter(retry*RETRY_DELAY,function()appWindowEvent(win,event,_,pid ,retry)end) end
13981401-- return
13991402-- end
1400- Window .created (win ,id ,apps [appname ],watcher )
1403+ Window .created (win ,id ,apps [pid ],watcher )
14011404 watcher :start ({uiwatcher .elementDestroyed ,uiwatcher .windowMoved ,uiwatcher .windowResized
14021405 ,uiwatcher .windowMinimized ,uiwatcher .windowUnminimized ,uiwatcher .titleChanged })
14031406 elseif event == uiwatcher .focusedWindowChanged then
1404- local app = apps [appname ]
1407+ local app = apps [pid ]
14051408 if not app then return log .df (' app %s is not registered!' ,appname ) end
14061409 app :focusChanged (id ,win )
14071410 end
14081411end
14091412
14101413local function startAppWatcher (app ,appname ,retry ,nologging ,force )
14111414 if not app or not appname then log .e (' called startAppWatcher with no app' ) return end
1412- if apps [appname ] then return not nologging and log .df (' app %s already registered' ,appname ) end
1415+ local pid = app :pid ()
1416+ if apps [pid ] then return not nologging and log .df (' app %s already registered' ,appname ) end
14131417 if app :kind ()< 0 or not windowfilter .isGuiApp (appname ) then log .df (' app %s has no GUI' ,appname ) return end
14141418 if not fnutils .contains (axuielement .applicationElement (app ):attributeNames () or {}, " AXFocusedWindow" ) then
14151419 log .df (' app %s has no AXFocusedWindow element' ,appname )
@@ -1418,14 +1422,14 @@ local function startAppWatcher(app,appname,retry,nologging,force)
14181422 retry = (retry or 0 )+ 1
14191423
14201424 if app :focusedWindow () or force then
1421- pendingApps [appname ]= nil -- done
1422- local watcher = app :newWatcher (appWindowEvent ,appname )
1425+ pendingApps [pid ]= nil -- done
1426+ local watcher = app :newWatcher (appWindowEvent ,pid )
14231427 watcher :start ({uiwatcher .windowCreated ,uiwatcher .focusedWindowChanged })
1424- App .new (app ,appname ,watcher )
1428+ App .new (app ,appname ,pid , watcher )
14251429 else
14261430 -- apps that start with an open window will often fail to be detected by the watcher if we
14271431 -- start it too early, so we try `app:focusedWindow()` MAX_RETRIES times before giving up
1428- pendingApps [appname ] = timer .doAfter (retry * RETRY_DELAY ,function ()
1432+ pendingApps [pid ] = timer .doAfter (retry * RETRY_DELAY ,function ()
14291433 startAppWatcher (app ,appname ,retry ,nologging , retry > MAX_RETRIES )
14301434 end )
14311435 end
@@ -1438,7 +1442,8 @@ local function appEvent(appname,event,app)
14381442 if not appname then return end
14391443 if event == appwatcher .launched then return startAppWatcher (app ,appname )
14401444 elseif event == appwatcher .launching then return end
1441- local appo = apps [appname ]
1445+ local pid = app :pid ()
1446+ local appo = apps [pid ]
14421447 if event == appwatcher .activated then
14431448 if appo then return appo :activated ()
14441449 else return startAppWatcher (app ,appname ,0 ,true ) end
@@ -1452,7 +1457,7 @@ local function appEvent(appname,event,app)
14521457 timer.doAfter(0.1*retry,function()appEvent(appname,event,app,retry)end)
14531458 return
14541459 --]]
1455- elseif event == appwatcher .terminated then pendingApps [appname ]= nil end
1460+ elseif event == appwatcher .terminated then pendingApps [pid ]= nil end
14561461 if not appo then return log .df (' app %s is not registered!' ,appname ) end
14571462 if event == appwatcher .terminated then return appo :destroyed ()
14581463 elseif event == appwatcher .deactivated then return appo :deactivated ()
0 commit comments