Mac OS X Window Server против X11: безумная задача
Предназначен для всех, кто любит низкоуровневый Windows Server (CoreGraphicsPrivate.h и т. Д.), X11 на Mac, SIMBL и другие сумасшедшие вещи:)
На Mac есть простое эмулированное приложение X11 (например, xterm, xeyes и т. Д.) С одним окном. Во время работы X11 каким-то образом создает собственное окно Quartz для представления этого эмулированного приложения, и это окно доступно через Quartz Window Services, так что я могу получить его CSWindowID, заголовок, положение, размер и PID владельца (PID X11.app). Но он не поддерживает API-интерфейс Accessibility, поэтому его невозможно контролировать (за исключением, может быть, частных функций Core Graphich из того же процесса).
Теперь вот задача:
Мне нужно разместить дополнительный NSView (или просто нарисовать что-то) на таком окне. Я имею в виду родное окно Quartz, которое появилось в результате эмуляции приложения X11. Я знаю, что для управления окнами на Mac я должен быть в том же процессе, то есть X11.app.
Я написал плагин SIMBL, который внедряется в процесс X11.app.
Там я могу позвонить [NSApp windows], но все время получаю ровно 2 NSWindows, которые не имеют ничего общего с окнами реальных приложений. Они даже не видны на экране.
Тем не менее, когда я вызываю NSWindowList(), я получаю все, что мне нужно (идентификаторы окон для окон X11) и даже больше (идентификаторы окон из других приложений).
Когда у меня есть CSWindowID для окон, эмулируемых X11, я вызываю [NSApp windowWithWindowNumber: ] (Какао) и HIWindowFromCGWindowID() (Carbon), но они оба возвращают ноль! Из того же самого процесса!
Кстати, все эти действия прекрасно работают, когда я вмешиваюсь в процесс Safari и другие...
Итак, вопросы:
Как X11 создал такие окна, которые недоступны в том же процессе?
Как я могу получить указатели на окна X11 (NSWindow *, CGContextRef или, по крайней мере, на что угодно...) и разместить на них мою графику (я даже не говорю о NSViews)?
Заранее большое спасибо!
2 ответа
Все исходники X11.app и другие материалы (Xquartz) доступны на официальном сайте Apple (текущая версия 2.3.5 (сервер 85.2)). Ядро создания окон лежит в подкаталоге xpr.
Для работы с окнами Xquartz использует библиотеку Xplugin (/usr/lib/libXplugin.dylib). Его заголовок /usr/include/Xplugin.h определяет функции, такие как xp_create_surface() и другие, которые создают окна с использованием закрытого API-интерфейса CoreGraphics, например CGSNewWindowWithOpaqueShape(). Недокументированные CoreGraphicsPrivate.h или CSGPrivate.h, результат обратного инжиниринга, можно найти через Интернет. Xplugin запоминает идентификаторы таких окон Quartz в своем собственном хэше и возвращает для них непрозрачное целое число (т.е. xp_resource_id). Затем Xquartz связывает определенный XID с этим xp_resource_id и возвращает его клиенту.
Xplugin является закрытым исходным кодом и не имеет API для возврата нативного Quartz, который можно нарисовать с помощью xp_resource_id или XID.
Чтобы нарисовать окно, которое было создано с помощью частного API CoreGraphics, вы должны использовать эти частные API. Есть функция с именем CGWindowContextCreate(), которая возвращает CGContextRef для определенного собственного окна по его идентификатору Quartz. Можно нарисовать на окне, используя этот контекст. Но чтобы получить реальный контекст вместо NULL, вы должны быть в процессе, который создал окно.
Насколько я понимаю, X11 использует свой собственный сервер Windows и общий стек. Вот почему он может запускать приложения X11 без специальных портов.
Он имеет только тот уровень ответов, который имитирует уровень окон Какао, так что он может взаимодействовать с общим интерфейсом. Это не замаскированный стек Какао, а стек Х11, внешне замаскированный под Какао. Таким образом, он отвечает только на подмножество сообщений, связанных с Какао.
Я думаю, чтобы сделать что-то серьезное в X11, вы должны использовать X11 API с самого начала. Другими словами, пишите так, как будто он не предназначен для работы поверх Mac OS.