Como identificar qual processo está executando qual janela no Mac OS X?

28

Gostaria de saber se é possível identificar qual processo é responsável pela criação / gerenciamento de uma janela no Mac OS X.

Por exemplo, quando várias instâncias de um aplicativo são iniciadas, como posso obter o ID do processo (PID) correspondente a uma janela específica? Ou, se houver uma janela de diálogo modal sem título, como posso obter o PID do proprietário?

Eu sei que no Windows é possível usar a ferramenta Sysinternals Suite , que fornece uma maneira de procurar uma biblioteca que está sendo executada com alguns dados.

Estou procurando por um mecanismo semelhante ao que aparece neste post do blog .

Nesse caso, usando o Sysinternals Suite (e o Process Explorer), eles descobriram qual DLL / programa estava usando a webcam pesquisando uma DLL ou substring (nesse caso, usando o nome físico do dispositivo).

Existe algum mecanismo ou programa ou você tem alguma idéia de como procurar algo semelhante para o Mac OS X? Como posso identificar qual processo lançou uma janela?

I.Cougil
fonte
“… Qual processo está mostrando qual janela…” Isso é confuso quando comparado com o exemplo do Windows de “… qual DLL / programa estava usando a webcam procurando uma DLL ou substring”. Você pode editar sua pergunta para esclarecer.
precisa saber é o seguinte
1
Alguns processos estão sendo executados sem janelas e talvez até sem um terminal de controle.
Basile Starynkevitch

Respostas:

22

Eu usei o script Python . Não é infalível, mas funciona muito bem para mim.

Não vou repassar o script completo sem permissão, mas aqui está um resumo: ele usa CGWindowListCopyWindowInfo, que é importado de Quartz, para coletar informações da janela do sistema, depois pede ao usuário para mover a janela desejada, depois coleta as informações da janela novamente e mostra informações para os que mudaram. As informações despejadas incluem o ID do processo, como kCGWindowOwnerPID.

Aqui está o código:

#!/usr/bin/env python

import time
from Quartz import CGWindowListCopyWindowInfo, kCGWindowListExcludeDesktopElements, kCGNullWindowID
from Foundation import NSSet, NSMutableSet

wl1 = CGWindowListCopyWindowInfo(kCGWindowListExcludeDesktopElements, kCGNullWindowID)
print 'Move target window'
time.sleep(5)
wl2 = CGWindowListCopyWindowInfo(kCGWindowListExcludeDesktopElements, kCGNullWindowID)

w = NSMutableSet.setWithArray_(wl1)
w.minusSet_(NSSet.setWithArray_(wl2))
print '\nList of windows that moved:'
print w
print '\n'

O script imprime informações para a janela que mudou de posição dentro de um intervalo de 5 segundos. Portanto, a saída é assim:

List of windows that moved:
{(
        {
        kCGWindowAlpha = 1;
        kCGWindowBounds =         {
            Height = 217;
            Width = 420;
            X = 828;
            Y = 213;
        };
        kCGWindowIsOnscreen = 1;
        kCGWindowLayer = 8;
        kCGWindowMemoryUsage = 406420;
        kCGWindowName = "";
        kCGWindowNumber = 77;
        kCGWindowOwnerName = UserNotificationCenter;
        kCGWindowOwnerPID = 481;
        kCGWindowSharingState = 1;
        kCGWindowStoreType = 2;
    }
)}
ecoar
fonte
Bem, não é exatamente o que eu estava procurando, mas é um bom ponto de partida. Obrigado @echo on!
I.Cougil 13/07/2015
@echo on - Não sei como aplicar o que esse site mostra, você poderia elaborar?
C_K
Parece que o link para o script python está morto. Acredito que encontrei o mesmo post em um novo blog aqui: cadebaba.blogspot.com/2014/04/…
Mark Ebbert 4/17/17
Este é um roteiro incrível. Isso ajudou a encontrar um software desagradável que não consegui identificar.
Samvel Avanesov
LEGAIS!! Essa é realmente a maneira correta e correta de identificar e remover malware que abre janelas de alerta. Muito melhor do que instalar e executar um programa antivírus que, quem sabe, pode ser um malware.
Jerry Krinock
15

Eu fiz uma ferramenta chamada lswin

$ python lswin.py

    PID WinID  x,y,w,h                  [Title] SubTitle
------- -----  ---------------------    -------------------------------------------
    169  1956 {0,-38,1280,25        }   [Window Server] Backstop Menubar
    169  1955 {0,-60,1280,22        }   [Window Server] Menubar
    169   396 {0,-38,1280,25        }   [Window Server] Backstop Menubar
    169   395 {0,-60,1280,22        }   [Window Server] Menubar
    169     6 {0,0,0,0              }   [Window Server] Cursor
    169     4 {0,22,1280,25         }   [Window Server] Backstop Menubar
    169     3 {0,0,1280,22          }   [Window Server] Menubar
    169     2 {0,0,1280,800         }   [Window Server] Desktop
    262   404 {0,-38,1280,38        }   [Google Chrome] 
    262   393 {0,0,1280,800         }   [Google Chrome] 
    262   380 {100,100,1,1          }   [Google Chrome] Focus Proxy
    ... ...

Então você pode usar grep para encontrar o pid da sua janela.

Aqui está o código fonte do script:

#!/usr/bin/env python

import Quartz

#wl = Quartz.CGWindowListCopyWindowInfo( Quartz.kCGWindowListOptionOnScreenOnly | Quartz.kCGWindowListExcludeDesktopElements, Quartz.kCGNullWindowID)
wl = Quartz.CGWindowListCopyWindowInfo( Quartz.kCGWindowListOptionAll, Quartz.kCGNullWindowID)

wl = sorted(wl, key=lambda k: k.valueForKey_('kCGWindowOwnerPID'))

#print wl

print 'PID'.rjust(7) + ' ' + 'WinID'.rjust(5) + '  ' + 'x,y,w,h'.ljust(21) + ' ' + '\t[Title] SubTitle'
print '-'.rjust(7,'-') + ' ' + '-'.rjust(5,'-') + '  ' + '-'.ljust(21,'-') + ' ' + '\t-------------------------------------------'

for v in wl:
    print ( \
        str(v.valueForKey_('kCGWindowOwnerPID') or '?').rjust(7) + \
        ' ' + str(v.valueForKey_('kCGWindowNumber') or '?').rjust(5) + \
        ' {' + ('' if v.valueForKey_('kCGWindowBounds') is None else \
            ( \
                str(int(v.valueForKey_('kCGWindowBounds').valueForKey_('X')))     + ',' + \
                str(int(v.valueForKey_('kCGWindowBounds').valueForKey_('Y')))     + ',' + \
                str(int(v.valueForKey_('kCGWindowBounds').valueForKey_('Width'))) + ',' + \
                str(int(v.valueForKey_('kCGWindowBounds').valueForKey_('Height'))) \
            ) \
            ).ljust(21) + \
        '}' + \
        '\t[' + ((v.valueForKey_('kCGWindowOwnerName') or '') + ']') + \
        ('' if v.valueForKey_('kCGWindowName') is None else (' ' + v.valueForKey_('kCGWindowName') or '')) \
    ).encode('utf8')
osexp2003
fonte
Funciona perfeitamente. Obrigado por compartilhar @ osexp2003!
Hay
10

@kenorb Combinei suas 2 versões do script, basicamente ele funciona como o primeiro, mostrando diferença, mas a formatação é a partir do segundo. Além disso, se a janela não estiver na tela - ela não está sendo impressa, caso contrário, gera muito lixo

import Quartz
import time
from Foundation import NSSet, NSMutableSet
def transformWindowData(data):
    list1 = []
    for v in data:
        if not v.valueForKey_('kCGWindowIsOnscreen'):
            continue


        row = ( \
            str(v.valueForKey_('kCGWindowOwnerPID') or '?').rjust(7) + \
            ' ' + str(v.valueForKey_('kCGWindowNumber') or '?').rjust(5) + \
            ' {' + ('' if v.valueForKey_('kCGWindowBounds') is None else \
                ( \
                    str(int(v.valueForKey_('kCGWindowBounds').valueForKey_('X')))     + ',' + \
                    str(int(v.valueForKey_('kCGWindowBounds').valueForKey_('Y')))     + ',' + \
                    str(int(v.valueForKey_('kCGWindowBounds').valueForKey_('Width'))) + ',' + \
                    str(int(v.valueForKey_('kCGWindowBounds').valueForKey_('Height'))) \
                ) \
                ).ljust(21) + \
            '}' + \
            '\t[' + ((v.valueForKey_('kCGWindowOwnerName') or '') + ']') + \
            ('' if v.valueForKey_('kCGWindowName') is None else (' ' + v.valueForKey_('kCGWindowName') or '')) \
        ).encode('utf8')
        list1.append(row)

    return list1;

def printBeautifully(dataSet):
    print 'PID'.rjust(7) + ' ' + 'WinID'.rjust(5) + '  ' + 'x,y,w,h'.ljust(21) + ' ' + '\t[Title] SubTitle'
    print '-'.rjust(7,'-') + ' ' + '-'.rjust(5,'-') + '  ' + '-'.ljust(21,'-') + ' ' + '\t-------------------------------------------'

    # print textList1
    for v in dataSet:
        print v;

#grab initial set
wl = Quartz.CGWindowListCopyWindowInfo( Quartz.kCGWindowListOptionAll, Quartz.kCGNullWindowID)
wl = sorted(wl, key=lambda k: k.valueForKey_('kCGWindowOwnerPID'))

#convert into readable format
textList1 = transformWindowData(wl);

#print everything we have on the screen
print 'all windows:'
printBeautifully(textList1)

print 'Move target window'
time.sleep(5)

#grab window data the second time
wl2 = Quartz.CGWindowListCopyWindowInfo(Quartz.kCGWindowListOptionAll, Quartz.kCGNullWindowID)
textList2 = transformWindowData(wl2)

#check the difference
w = NSMutableSet.setWithArray_(textList1)
w.minusSet_(NSSet.setWithArray_(textList2))

#print the difference
printBeautifully(w)
Ruzard
fonte
Fantástico. Um passo mais perto do xkill for Mac!
Michael Fox
2
Com um pouco depip install pyobjc-framework-Quartz
CupawnTae
Observe que o script não funciona 100% com configurações para vários monitores. Se você executar isso em um terminal em uma tela e depois mover a janela para outra tela, verá muitas janelas listadas no diff. Todos eles parecem janelas e ícones do sistema na barra de menus, etc. É melhor mover o terminal e a janela misteriosa para a mesma tela antes de executar.
DaveBurns 24/01