Введение

Ядровой протокол X Window System является базовым протоколом X Window System – сетевой оконной системы для растровых дисплеев, используемой для создания графических пользовательских интерфейсов в Unix, Unix-подобных и других операционных системах. X Window System основана на клиент-серверной модели: один сервер управляет аппаратным обеспечением ввода-вывода, таким как экран, клавиатура и мышь; все прикладные программы выступают в роли клиентов, взаимодействуя с пользователем и друг с другом через сервер. Это взаимодействие регулируется ядровым протоколом X Window System. Существуют и другие протоколы, связанные с X Window System, построенные либо на основе ядрового протокола X Window System, либо являющиеся отдельными протоколами. В ядровом протоколе X Window System по сети асинхронно передаются только четыре типа пакетов: запросы, ответы, события и ошибки. Запросы отправляются клиентом серверу для выполнения определенной операции (например, создания нового окна) и получения от него данных. Ответы отправляются сервером для предоставления этих данных. События отправляются сервером для уведомления клиентов об активности пользователя или других интересующих их событиях. Ошибки – это пакеты, отправляемые сервером для уведомления клиента об ошибках, возникших при обработке его запросов. Запросы могут генерировать ответы, события и ошибки; помимо этого, протокол не предписывает определенного порядка отправки пакетов по сети. Существуют расширения ядрового протокола, каждое из которых имеет собственные запросы, ответы, события и ошибки. X была разработана в MIT в 1984 году (ее текущая версия X11 появилась в сентябре 1987 года). Ее создатели, Боб Шейфлер и Джим Геттис, изначально определили основной принцип протокола как "создание механизма, а не политики". В результате, ядровой протокол не определяет взаимодействие между клиентами и между клиентом и пользователем. Эти взаимодействия регулируются отдельными спецификациями, такими как ICCCM и спецификации freedesktop.org, и обычно автоматически обеспечиваются с помощью заданного набора виджетов.

Окна

То, что обычно называется окном в большинстве графических пользовательских интерфейсов, называется окном верхнего уровня в системе X Window System. Термин «окно» также используется для обозначения окон, находящихся внутри другого окна, то есть дочерних окон родительского окна. Графические элементы, такие как кнопки, меню, значки и т. д., могут быть реализованы с помощью дочерних окон. Клиент может запросить создание окна, точнее, создание дочернего окна существующего окна. В результате окна, созданные клиентами, располагаются в виде дерева (иерархии). Корень этого дерева — корневое окно, которое является специальным окном, создаваемым автоматически сервером при запуске. Все остальные окна являются прямыми или косвенными дочерними окнами корневого окна. Окна верхнего уровня являются прямыми дочерними окнами корневого окна. Визуально корневое окно имеет размер виртуального рабочего стола и находится позади всех остальных окон. Содержимое окна не всегда гарантированно сохраняется со временем. В частности, содержимое окна может быть уничтожено при перемещении окна, изменении его размера, перекрытии другими окнами и, в целом, при его полном или частичном скрытии. В частности, содержимое теряется, если X-сервер не поддерживает резервную копию содержимого окна. Клиент может запросить поддержание резервной копии для окна, но сервер не обязан это делать. Поэтому клиенты не могут предполагать, что резервная копия поддерживается. Если видимая часть окна имеет неопределенное содержимое, клиенту отправляется событие, уведомляющее о необходимости перерисовать содержимое окна. Каждое окно имеет связанный набор атрибутов, таких как геометрия окна (размер и положение), фоновое изображение, запрошена ли для него резервная копия и т. д. Протокол включает запросы для проверки и изменения атрибутов окна клиентом. Окна могут быть InputOutput (ввод-вывод) или InputOnly (только ввод). Окна InputOutput могут отображаться на экране и используются для рисования. Окна InputOnly никогда не отображаются на экране и используются только для приема ввода. Декоративная рамка и панель заголовка (возможно, включая кнопки), которые обычно видны вокруг окон, создаются менеджером окон, а не клиентом, создающим окно. Менеджер окон также обрабатывает ввод, связанный с этими элементами, например, изменение размера окна при нажатии и перетаскивании рамки окна пользователем. Клиенты обычно работают в созданном ими окне, не учитывая изменения, вносимые менеджером окон. Изменением, которое необходимо учитывать, является то, что менеджеры окон, перенаправляющие родительские элементы (reparenting window managers), которыми являются почти все современные менеджеры окон, изменяют родительское окно окон верхнего уровня на окно, отличное от корневого. С точки зрения основного протокола, менеджер окон является клиентом, ничем не отличающимся от других приложений. Информацию об окне можно получить, запустив программу xwininfo. Передав ей аргумент командной строки `tree`, эта программа отображает дерево дочерних окон данного окна, а также их идентификаторы и данные о геометрии.

Карты и чертежи

Карта пикселей — это область памяти, которая может использоваться для рисования. В отличие от окон, карты пикселей не отображаются на экране автоматически. Однако содержимое карты пикселей (или её части) может быть перенесено в окно и наоборот, что позволяет использовать такие методы, как двойная буферизация. Большинство графических операций, которые можно выполнять на окнах, также можно выполнять на картах пикселей. Окна и карты пикселей совместно называются отрисовываемыми объектами (drawables), а их данные хранятся на сервере. Клиент, однако, может запросить передачу содержимого отрисовываемого объекта с сервера на клиент или наоборот.

Графические контексты и шрифты

Клиент может запросить ряд графических операций, таких как очистка области, копирование области в другую, рисование точек, линий, прямоугольников и текста. За исключением очистки, все операции могут быть выполнены на любом графическом объекте, будь то окно или растровое изображение. Большинство запросов на графические операции включают графический контекст – структуру, содержащую параметры этих операций. Графический контекст включает цвет переднего плана, цвет фона, шрифт текста и другие графические параметры. При запросе графической операции клиент предоставляет графический контекст. Не все параметры графического контекста влияют на операцию: например, шрифт не влияет на рисование линии. Основной протокол определяет использование шрифтов на стороне сервера. Такие шрифты хранятся в файлах, и сервер получает к ним доступ либо напрямую через локальную файловую систему, либо по сети из другой программы, называемой сервером шрифтов. Клиенты могут запросить список шрифтов, доступных на сервере, а также запросить загрузку (если шрифт еще не загружен) или выгрузку (если шрифт не используется другими клиентами) шрифта сервером. Клиент может запросить общую информацию о шрифте (например, высоту символов) и пространство, занимаемое конкретной строкой при рисовании с использованием определенного шрифта. Имена шрифтов являются произвольными строками на уровне основного протокола X Window. Соглашения об описании логических шрифтов X определяют, как шрифты должны именоваться в соответствии с их атрибутами. Эти соглашения также определяют значения дополнительных свойств, которые могут быть привязаны к шрифтам. Программа `xlsfonts` выводит список шрифтов, хранящихся на сервере. Программа `xfontsel` отображает символы шрифтов и позволяет пользователю выбрать имя шрифта для вставки в другое окно. Использование шрифтов на стороне сервера в настоящее время считается устаревшим в пользу шрифтов на стороне клиента. Такие шрифты отрисовываются клиентом, а не сервером, с использованием библиотек Xft или cairo и расширения XRender. Основной протокол не содержит спецификаций для шрифтов на стороне клиента.

События

События — это пакеты, отправляемые сервером клиенту, чтобы сообщить о наступлении события, которое может заинтересовать клиента. Например, событие отправляется при нажатии пользователем клавиши или кнопки мыши. События используются не только для обработки ввода: например, события отправляются для уведомления о создании новых дочерних окон данного окна. Каждое событие привязано к окну. Например, если пользователь щелкает мышью, когда указатель находится в окне, событие будет относиться к этому окну. Пакет события содержит идентификатор этого окна. Клиент может запросить у сервера отправку события другому клиенту; это используется для взаимодействия между клиентами. Такое событие, например, генерируется, когда клиент запрашивает текст, который в данный момент выделен: это событие отправляется клиенту, который в данный момент обрабатывает окно, содержащее выделенный текст. Событие Expose отправляется, когда область окна становится видимой после уничтожения её содержимого. Содержимое окна может быть уничтожено при определенных условиях, например, если окно перекрыто, а сервер не поддерживает буфер обмена. Сервер генерирует событие Expose, чтобы уведомить клиент о необходимости перерисовки части окна. Большинство типов событий отправляются только в том случае, если клиент предварительно выразил заинтересованность в них. Это связано с тем, что клиенты могут быть заинтересованы только в определенных типах событий. Например, клиент может быть заинтересован в событиях, связанных с клавиатурой, но не в событиях, связанных с мышью. Однако некоторые типы событий отправляются клиентам, даже если они не запрашивали их явно. Клиенты указывают, какие типы событий они хотят получать, устанавливая атрибут окна. Например, для перерисовки окна после уничтожения его содержимого клиент должен получать события Expose, которые сообщают ему о необходимости повторной отрисовки окна. Однако клиент будет получать события Expose только в том случае, если он предварительно заявил о своей заинтересованности в этих событиях, что делается путем соответствующей настройки атрибута маски событий окна. Разные клиенты могут запрашивать события для одного и того же окна. Они могут даже устанавливать разные маски событий для одного и того же окна. Например, один клиент может запрашивать только события клавиатуры для окна, а другой клиент — только события мыши для того же окна. Это возможно, потому что сервер для каждого окна поддерживает отдельную маску событий для каждого клиента. Однако существуют типы событий, которые может выбрать только один клиент для каждого окна в определенный момент времени. В частности, эти события сообщают о нажатиях кнопок мыши и некоторых изменениях, связанных с управлением окнами. Программа xev отображает события, относящиеся к окну. В частности, команда xev id WID запрашивает все возможные события, относящиеся к окну с идентификатором WID, и выводит их на экран.

Атомы

Атомы — это 32-битные целые числа, представляющие строки. Разработчики протокола ввели атомы, поскольку они позволяют представлять строки в сжатом и фиксированном размере: в то время как строка может быть произвольной длины, атом всегда является 32-битным целым числом. Преимущество краткости атомов было использовано путем обязательного их использования в тех типах пакетов, которые, вероятно, будут отправляться многократно с одними и теми же строками; это обеспечивает более эффективное использование сети. Фиксированный размер атомов был использован при определении фиксированного размера событий, а именно 32 байта: пакеты фиксированного размера могут содержать атомы, но не могут содержать длинные строки. Фактически, атомы — это идентификаторы строк, хранящихся на сервере. Они похожи на идентификаторы ресурсов (окон, пиктограмм и т. д.), но отличаются от них двумя аспектами. Во-первых, идентификаторы атомов выбираются сервером, а не клиентом. Иными словами, когда клиент запрашивает создание нового атома, он отправляет серверу только строку для хранения, а не ее идентификатор; этот идентификатор выбирается сервером и отправляется обратно клиенту в качестве ответа. Второе важное отличие между ресурсами и атомами заключается в том, что атомы не привязаны к клиентам. После создания атом сохраняется до тех пор, пока сервер не будет завершен или перезапущен (это не поведение ресурсов по умолчанию). Атомы являются идентификаторами и, следовательно, уникальны. Однако идентификатор атома и идентификатор ресурса могут совпадать. Строка, связанная с атомом, называется именем атома. Имя атома нельзя изменить после создания, и не может быть двух атомов с одинаковым именем. В результате имя атома обычно используется для обозначения атома: «атом ABCD» означает, точнее, «атом, связанная строка которого — ABCD» или «атом, имя которого — ABCD». Клиент может запросить создание нового атома и запросить идентификатор атома для заданной строки. Некоторые атомы предопределены (создаются сервером с заданным идентификатором и строкой). Атомы используются для множества целей, в основном связанных с обменом данными между различными клиентами, подключенными к одному и тому же серверу. В частности, они используются в связи со свойствами окон, которые описаны ниже. Список всех атомов, находящихся на сервере, можно вывести с помощью программы xlsatoms. В частности, эта программа выводит каждый атом (идентификатор, то есть число) вместе с его именем (связанной строкой).

Свойства

Каждое окно имеет предопределенный набор атрибутов и набор свойств, все они хранятся на сервере и доступны клиентам посредством соответствующих запросов. Атрибуты – это данные об окне, такие как его размер, положение, цвет фона и т. д. Свойства – это произвольные фрагменты данных, присоединенные к окну. В отличие от атрибутов, свойства не имеют значения на уровне основного протокола X Window. Клиент может хранить произвольные данные в свойстве окна. Свойство характеризуется именем, типом и значением. Свойства аналогичны переменным в императивных языках программирования, поскольку клиент может создать новое свойство с заданным именем и типом и сохранить в нем значение. Свойства привязаны к окнам: два свойства с одним и тем же именем могут существовать в двух разных окнах, при этом имея разные типы и значения. Имя, тип и значение свойства – это строки, точнее, атомы, то есть строки, хранящиеся на сервере и доступные клиентам через идентификаторы. Клиентское приложение может получить доступ к заданному свойству, используя идентификатор атома, содержащего имя свойства. Свойства в основном используются для межклиентского взаимодействия. Например, свойство WM_NAME (свойство, названное атомом, связанная строка которого – "WM_NAME") используется для хранения имени окон. Менеджеры окон обычно считывают это свойство, чтобы отображать имя окон в строке заголовка. Некоторые типы межклиентского взаимодействия используют свойства корневого окна. Например, согласно спецификации freedesktop window manager, менеджеры окон должны хранить идентификатор текущего активного окна в свойстве с именем NET_ACTIVE_WINDOW корневого окна. Ресурсы X, содержащие параметры программ, также хранятся в свойствах корневого окна; таким образом, все клиенты могут получить к ним доступ, даже если они запущены на разных компьютерах. Программа xprop выводит свойства заданного окна; xprop root выводит имя, тип и значение каждого свойства корневого окна.

Другое

Существуют и другие запросы и события в основном протоколе. Первый вид запросов связан с родительскими связями между окнами: клиент может запросить изменение родителя окна или запросить информацию о родительстве окон. Другие запросы относятся к механизму выбора, который, однако, в основном управляется другими протоколами. Другие запросы касаются фокуса ввода и формы курсора. Клиент также может запросить завершение работы владельца ресурса (окна, пиксельной карты и т.д.), что приводит к разрыву соединения сервером с этим клиентом. Наконец, клиент может отправить серверу запрос бездействия.

Расширения

Ядро протокола X Window было разработано с учетом возможности расширения. Основной протокол определяет механизм для запроса доступных расширений, а также формат запросов, событий и пакетов ошибок расширений. В частности, клиент может запросить список всех доступных расширений и данные, относящиеся к конкретному расширению. Пакеты расширений аналогичны пакетам основного протокола. Основной протокол определяет, что пакеты запросов, событий и ошибок содержат целое число, указывающее их тип (например, запрос на создание нового окна имеет номер 1). Определенный диапазон этих целых чисел зарезервирован для использования расширениями.

Разрешение

Когда клиент первоначально устанавливает соединение с сервером, сервер может ответить, приняв соединение, отклонив его или запросив аутентификацию. Запрос аутентификации содержит имя используемого метода аутентификации. Основной протокол не определяет процедуру аутентификации, которая зависит от типа используемой аутентификации, за исключением того, что она завершается отправкой сервером пакета подтверждения или отказа. В ходе обычной работы клиента и сервера единственные запросы, связанные с аутентификацией, относятся к методу доступа на основе хоста. В частности, клиент может запросить включение этого метода, а также чтение и изменение списка хостов (клиентов), которым разрешено подключаться. Типичные приложения не используют эти запросы; они используются программой xhost для предоставления пользователю или скрипту доступа к списку разрешенных хостов. Метод доступа на основе хоста считается небезопасным.

Неопределенные части

Основной протокол X Window System не регламентирует взаимодействие между клиентами и не определяет, как окна используются для создания визуальных элементов, типичных для графических пользовательских интерфейсов (кнопок, меню и т.п.). Элементы графического пользовательского интерфейса определяются клиентскими библиотеками, реализующими наборы виджетов. Взаимодействие между клиентами регулируется другими стандартами, такими как ICCCM и спецификации freedesktop. Взаимодействие между клиентами имеет отношение к механизмам выбора, буферам обмена и перетаскиванию, которые используются пользователем для передачи данных из одного окна в другое. Поскольку окнами могут управлять разные программы, необходим протокол для обмена этими данными. Взаимодействие между клиентами также важно для оконных менеджеров X, программ, которые управляют внешним видом окон и общим стилем графического пользовательского интерфейса.

Управление сеансом

Еще один вопрос, в котором межклиентное взаимодействие играет определенную роль, – это управление сеансами. То, как начинается пользовательский сеанс, является отдельной задачей, не входящей в основной протокол. Обычно это происходит автоматически благодаря диспетчеру отображения X. Однако пользователь также может запустить сеанс вручную, используя программы xinit или startx.