Получение активного приложения в OS X 10.7 с использованием демона python - PullRequest
3 голосов
/ 01 марта 2012

Я пытаюсь построить демон в python и хочу получить имя текущего активного приложения.

Для демона я использую этот хороший код, отсканированный от Сандера Марешала

Следующая строка отлично работает в OS X 10.7, когда я НЕ запускаю приложение как демон, хотя в документации сказано, что «activeApplication ()» устарела в 10.6 +

activeAppName = str(NSWorkspace.sharedWorkspace().activeApplication()['NSApplicationName'])

Но как только я запускаю приложение как демон, приложение вылетает.

Однако, демон не падает, когда я делаю только

workspace = str(NSWorkspace.sharedWorkspace())

, который возвращает:

<NSWorkspace: 0x7ffe7cc013c0>

Итак, мои вопросы:

  1. Почему он падает только как демон?
  2. Как получить активное приложение через python на OS X 10.7 (которая также работает с демоном ;-))?

Я не понимаю сообщение об ошибке, но, возможно, один из вас понимает:

Process:         Python [7920]
Path:            /System/Library/Frameworks/Python.framework/Versions/2.7/Resources/Python.app/Contents/MacOS/Python
Identifier:      Python
Version:         ??? (???)
Code Type:       X86-64 (Native)
Parent Process:  ??? [1]

Date/Time:       2012-02-29 23:35:25.202 +0100
OS Version:      Mac OS X 10.7.3 (11D50b)
Report Version:  9

Interval Since Last Report:          818421 sec
Crashes Since Last Report:           21
Per-App Crashes Since Last Report:   15
Anonymous UUID:                      05B412BD-4629-472B-964D-BE4A88B06DD1

Crashed Thread:  0  Dispatch queue: com.apple.main-thread

Exception Type:  EXC_BAD_ACCESS (SIGSEGV)
Exception Codes: KERN_INVALID_ADDRESS at 0x0000000000000108

VM Regions Near 0x108:
--> 
    __TEXT                 0000000102e90000-0000000102e91000 [    4K] r-x/rwx SM=COW  /System/Library/Frameworks/Python.framework/Versions/2.7/Resources/Python.app/Contents/MacOS/Python

Application Specific Information:
*** single-threaded process forked ***
objc[7918]: garbage collection is OFF

Thread 0 Crashed:: Dispatch queue: com.apple.main-thread
0   libdispatch.dylib               0x00007fff8ceb7ce9 _dispatch_wakeup + 108
1   libdispatch.dylib               0x00007fff8ceba876 _dispatch_resume_slow + 20
2   com.apple.CoreServices.CarbonCore   0x00007fff8d34f919 _ZL22connectToCoreServicesDv + 269
3   com.apple.CoreServices.CarbonCore   0x00007fff8d34f7d5 _ZL9getStatusv + 24
4   com.apple.CoreServices.CarbonCore   0x00007fff8d34f74f scCreateSystemServiceVersion + 50
5   com.apple.LaunchServices        0x00007fff90b5ace1 _ZL45SetupCoreApplicationServicesCommunicationPortv + 147
6   com.apple.LaunchServices        0x00007fff90b5b37a getProcessDispatchTable() + 19
7   com.apple.LaunchServices        0x00007fff90b56de0 LSClientSideSharedMemory::GetClientSideSharedMemory(LSSessionID, bool) + 158
8   com.apple.LaunchServices        0x00007fff90b6b152 _LSCopyFrontApplication + 42
9   com.apple.AppKit                0x00007fff899adc5d -[NSWorkspace activeApplication] + 26
10  libffi.dylib                    0x00007fff91df2e7c ffi_call_unix64 + 76
11  libffi.dylib                    0x00007fff91df3ae9 ffi_call + 728
12  _objc.so                        0x00000001031c7d60 PyObjCFFI_Caller + 2272
13  _objc.so                        0x00000001031dd169 0x1031ae000 + 192873
14  org.python.python               0x0000000102ea0d32 PyObject_Call + 97
15  org.python.python               0x0000000102f20f63 PyEval_EvalFrameEx + 14353
16  org.python.python               0x0000000102f23df7 0x102e99000 + 568823
17  org.python.python               0x0000000102f20e0a PyEval_EvalFrameEx + 14008
18  org.python.python               0x0000000102f23df7 0x102e99000 + 568823
19  org.python.python               0x0000000102f20e0a PyEval_EvalFrameEx + 14008
20  org.python.python               0x0000000102f23cd8 PyEval_EvalCodeEx + 1996
21  org.python.python               0x0000000102f23d4d PyEval_EvalCode + 54
22  org.python.python               0x0000000102f3b08f 0x102e99000 + 663695
23  org.python.python               0x0000000102f3b14f PyRun_FileExFlags + 157
24  org.python.python               0x0000000102f3c2a2 PyRun_SimpleFileExFlags + 392
25  org.python.python               0x0000000102f4c2af Py_Main + 2715
26  org.python.python               0x0000000102e90e88 0x102e90000 + 3720

Ответы [ 2 ]

3 голосов
/ 01 марта 2012

Я провел несколько тестов с этим, и я думаю, что ваша проблема может заключаться в том, как вы демонизируете этот инструмент, а затем пытаетесь сделать вызов, для которого требуются службы Windows, которые могут быть недоступны. Эта ссылка здесь намекает на такую ​​ситуацию: http://grokbase.com/t/python/pythonmac-sig/08axst378p/appscript-and-launching-apps-from-background-only-python-processes

Я впервые проверил эту теорию, используя ваш скрипт демона, и сделал osascript вызов, чтобы найти активное приложение через AppleScript:

from subprocess import Popen, PIPE

cmd = """osascript \
    -e 'tell application "System Events"' \
    -e 'set app_name to name of the first process whose frontmost is true' \
    -e 'end tell' """
v = Popen(cmd, shell=True, stdout=PIPE).stdout.read()

Popen - это способ запуска системной команды в подпроцессе и возможность проверки его кода возврата или считывания его вывода (или отправки ввода) http://docs.python.org/library/subprocess.html.. Osascript - это инструмент командной строки для вызова сценариев Apple.

Для меня это работает, потому что он запускает новый подпроцесс, который, я думаю, имеет ли доступ к серверу окон?

Затем я создал plist launchd вместо того, чтобы использовать ваш скрипт демона. Это работает:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>com.company.test</string>
    <key>Nice</key>
    <integer>1</integer>
    <key>OnDemand</key>
    <false/>
    <key>Program</key>
    <string>/path/to/script.py</string>
</dict>
</plist>

Launchd - это менеджер процессов демона OSX, который, похоже, запускает программы таким образом, что они имеют полный доступ к серверу окон.

Для script.py у меня просто был цикл, запись имени файла переднего приложения в спящий режим.

Обновление

Поскольку вы упомянули, что ваш подход к pyobjc устарел, и вам, похоже, нравится подход appleScript, я подумал, что воспользуюсь питонским подходом, используя appscript - привязки python к сценарию apple

from appscript import app, its
activeApp = app('System Events').processes[its.frontmost == True].first()
print activeApp

#result
app(u'/System/Library/CoreServices/System Events.app').application_processes[u'Terminal']

activeApp - это объект, представляющий самое переднее приложение, о котором сообщает приложение System Events.

1 голос
/ 01 марта 2012

Сбой в конечном итоге происходит в libdispatch, и похоже, что он как-то связан с общей памятью;посмотрите вызов GetClientSideSharedMemory в стеке вызовов.Таким образом, похоже, что ваш демон-код работает вразрез с технологией grand central dispatch , встроенной в OS X.

Посмотрите на модуль python daemon .Это делает вещи (соответствуют PEP 3143 ), которые игнорирует фрагмент кода, который вы используете.

Поскольку OS X - это в основном UNIX с дополнительными функциями, возможно, вам потребуется добавить некоторые специфические для OS X шаги при попытке запустить программу в качестве демона.

Вы можетеизучите исходный код других демонов, которые работают под OS X, например, Postfix.

...