Как вывести список всех окон из всех рабочих областей в Python на Mac?

Следующий код Python 2 выводит список всех окон в текущей рабочей области:

#!/usr/bin/python
import Quartz
for window in Quartz.CGWindowListCopyWindowInfo(Quartz.kCGWindowListOptionOnScreenOnly, Quartz.kCGNullWindowID):
    print("%s - %s" % (window['kCGWindowOwnerName'], window.get('kCGWindowName', u'Unknown').encode('ascii','ignore')))

Хотя он не печатает приложения, которые находятся в полноэкранном режиме (так как они находятся в другом рабочем пространстве).

Как мне изменить приведенный выше скрипт, чтобы вывести список всех окон со всех рабочих столов?


person kenorb    schedule 28.05.2017    source источник


Ответы (2)


Следующий скрипт должен возвращать информацию об окне на любом рабочем столе/рабочей области/дисплее, в полноэкранном режиме и подробную информацию (координаты, pid, заголовки и т. д.):

#!/usr/bin/python

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

def windowList(wl):
    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') # remove 'encode' for Python 3.x

wl1 = CGWindowListCopyWindowInfo(kCGWindowListExcludeDesktopElements, kCGNullWindowID)
print('Move target window (or ignore)\n')
time.sleep(5)

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

wl2 = CGWindowListCopyWindowInfo(kCGWindowListExcludeDesktopElements, kCGNullWindowID)

w = NSMutableSet.setWithArray_(wl1)
w.minusSet_(NSSet.setWithArray_(wl2))

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

windowList(wl)

print('\nDetailed window information: {0}\n'.format(w))
person l'L'l    schedule 28.05.2017

Ключ здесь в том, чтобы использовать правильный вариант для 1-го аргумента CGWindowListCopyWindowInfo. Таким образом, помимо использования свойства optionOnScreenOnly (в котором перечислены все окна, которые в настоящее время на экране), необходимо добавить свойство excludeDesktopElements.

excludeDesktopElements: исключить из списка все окна, являющиеся элементами рабочего стола. , включая фоновое изображение и значки рабочего стола.

E.g.

list = CGWindowListCopyWindowInfo(kCGWindowListExcludeDesktopElements | kCGWindowListOptionOnScreenOnly, kCGNullWindowID)

В качестве альтернативы для всех окон также можно использовать свойство kCGWindowListOptionAll.

kCGWindowListOptionAll: список всех окон, включая экранные и закадровые. При получении списка с помощью этой опции параметр relativeToWindow должен быть установлен на kCGNullWindowID.

Для других свойств проверьте CGWindow.h в CoreGraphics.


Таким образом, исходный код можно изменить на:

#!/usr/bin/python
# Prints list of all windows.
# See: https://stackoverflow.com/q/44232433/55075
import Quartz
for window in Quartz.CGWindowListCopyWindowInfo(Quartz.kCGWindowListOptionOnScreenOnly | Quartz.kCGWindowListExcludeDesktopElements, Quartz.kCGNullWindowID):
    print("%s - %s" % (window['kCGWindowOwnerName'], window.get('kCGWindowName', u'Unknown').encode('ascii','ignore')))
person kenorb    schedule 29.05.2017
comment
Разве это не должно быть побитовым или? - person ManuelSchneid3r; 31.01.2020