ISSN 0236-235X (P)
ISSN 2311-2735 (E)

Journal influence

Higher Attestation Commission (VAK) - К1 quartile
Russian Science Citation Index (RSCI)

Bookmark

Next issue

2
Publication date:
16 June 2024

The article was published in issue no. № 3, 2007
Abstract:
Аннотация:
Author: () -
Ключевое слово:
Page views: 11825
Print version
Full issue in PDF (2.31Mb)

Font size:       Font:

В статье "В поисках серебряной пули" Фредерик П. Брукс сравнивает проекты по созданию программного обеспечения с оборотнями из сказок, внушающими особый ужас: притворяясь чем-то знакомым и обыденным, они способны внезапно обращаться в чудовищ, пожирающих бюджет, время и другие ресурсы, а получающаяся в результате реализации проекта система обладает невероятным количеством изъянов (http://www.apl.jhu.edu/Classes/635431/ felikson/Publications/No_Silver_Bullet_Brooks.html). Убить оборотня можно, как известно, только волшебной серебряной пулей, однако ее поиски до сих пор не увенчались успехом. По мнению Брукса, все дело в том, что наиболее трудная и значительная по объему работа в программировании заключается в составлении спецификаций, разработке и проверке программы как концептуальной конструкции, но работа эта остается, как правило, невыполненной. "Мы, конечно же, делаем синтаксические ошибки, но они – ничто по сравнению с ошибками концептуальными", – замечает Брукс. Исправление концептуальных ошибок означает, как правило, полную переработку системы, поэтому о них предпочитают умалчивать, когда речь идет о системе давно эксплуатируемой.

В интерактивной системе имеется два действующих лица: программа (программы), исполняющаяся на ЭВМ, и человек (оператор), наблюдающий результаты работы программы на экране и влияющий на ход ее исполнения посредством устройств ввода (обычно это клавиатура и указывающее устройство типа "мышь"). Как результаты работы программы (например, "на экране высвечено окно"), так и последствия действий оператора (например, "нажата клавиша") можно охарактеризовать одним и тем же словом СОБЫТИЕ.

Слово "событие", как и многие другие термины, имеет двоякий смысл: первый – общепринятый, "житейский", и второй – специальный, который должен согласовываться с первым.

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

Что считать событием в интерактивной системе, решают ее разработчики. Обсудим решения, принятые разработчиками системы X Window.

Система состоит из двух основных компонентов: дисплейного сервера (или просто сервера) и библиотек функций, предназначенных для создания прикладных графических программ, называемых клиентскими. Эти библиотеки называют также "клиентскими", или "клиентскими библиотеками X Window", чтобы отличать их от других библиотек языка программирования Си. Базовая клиентская библиотека называется Xlib, ни одна клиентская программа не может обойтись без обращения к функциям этой библиотеки, непосредственного или косвенного (через функции других клиентских библиотек, более высокого уровня).

Сервер и клиентские программы могут исполняться либо на одном и том же процессоре – и тогда они запускаются как отдельные процессы UNIX, – либо на разных процессорах, входящих в некоторую сеть ("сетевая прозрачность").

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

Вывод данных осуществляется в определенное окно. Каждой клиентской программой на экране может быть создано произвольное количество окон. Среди окон существует иерархия в виде дерева: каждое окно создается в некотором другом окне, называемом родительским. Существует одно окно, прародитель всех остальных. Это окно считается созданным по умолчанию, заполняет целиком весь экран и называется корневым. Окна можно создавать и уничтожать, высвечивать на экране и гасить, изменять их размеры и перемещать, а также изменять порядок наложения.

События в X Window

При работе интерактивной графической системы X Window могут наступать определенные события.

Одни события (например, KeyPress – "нажата клавиша") наступают в результате действий пользователя (оператора), другие (например, MapNotify – "на экране высвечено окно") – вследствие вызова определенных функций библиотеки Xlib. Некоторые события могут наступать как в результате действий оператора, так и вследствие вызова определенных функций. К таким событиям относятся EnterNotify ("кусор введен в окно") и LeaveNotify ("курсор выведен из окна"), наступающие при пересечении курсором границ окна (курсор перемещается в результате либо действий оператора, либо отработки функции XWarpPointer).

События и моменты их наступления фиксируются сервером. Момент наступления события фиксируется с точностью до одной миллисекунды. Зафиксировав событие, сервер направляет (или не направляет) клиентским программам извещения о событии, в которых указывается тип события и дополнительные сведения, зависящие от типа события. Например, для события KeyPress указывается код нажатой клавиши. Условия отправки извещения и его состав зависят от типа события, однако имеются некоторые сведения, обязательно включаемые в любое извещение. Заметим, что момент наступления события должен был бы включаться в извещение о любом событии, однако в системе X Window это не так: отметка времени о событиях большинства типов в извещение не включается, и в этом состоит первая концептуальная недоработка – часто бывает важно знать, в какой последовательности наступали события, например, при отдадке и для диагностики.

Любое событие, кроме событий типа Mapping­Notify ("изменена раскладка клавиатуры или кнопок указывающего устройства"), связано с определенным окном, называемым окном события. С событиями некоторых типов может быть связано не одно, а несколько окон. Например, с событием DestroyNotify ("окно уничтожено") связаны два окна – само уничтоженное окно и его родительское. В таких случаях формируется несколько извещений, по одному на каждое затрагиваемое окно (в извещение можно включить только один идентификатор окна).

Каждая клиентская программа может заказать отправку ей извещений о событиях большинства типов, установив соответствующий бит в особой маске событий. Для каждого окна и каждой клиентской программы существует отдельная маска событий, автоматически формируемая при создании окна или установлении соединения между сервером и клиентской программой. Установка бита маски событий во многих случаях является единственным условием отправки извещения клиентской программе.

Окна в X Window бывают двух классов – обыкновенные (Input/Output) и прозрачные (InputOnly). Вывод данных возможен только в обыкновенные окна. Прозрачные окна, в отличие от обыкновенных, всегда невидимы, они не имеют ни фона, ни рамки, однако могут накрывать другие окна и быть накрыты ими (полностью или частично). Наличие прозрачного окна на экране можно визуально определить по изменению вида курсора, если прозрачному окну сопоставлен отдельный курсор (с каждым окном в X Window может быть связан собственный курсор, хотя обычно вид курсора наследуется от родительского окна). С прозрачным окном, как и с обыкновенным, могут быть связаны события, но не всех типов. Например, событие KeyPress может быть связано с прозрачным окном, а событие NoExpose ("операция копирования успешно завершена") – нет, поскольку операция копирования для прозрачных окон невозможна. В X Window события типа Visibility Notify ("изменилась видимость окна") не могут быть связаны с прозрачными окнами, и это – еще один пример концептуальной недоработки: хотя сквозь прозрачное окно просвечивает содержимое других, накрываемых им окон, прозрачное окно занимает вполне определенное положение в стеке окон своего поколения, и изменение этого положения можно определить визуально.

Захват и освобождение клавиатуры

Любая клиентская программа может заказать отправку ей извещений о событиях типа KeyPress, и тогда она сможет прочитывать вводимый с клавиатуры текст независимо от того, какой программе он должен быть адресован. Для того чтобы обеспечить какую-то защиту от несанкционированного доступа, введена возможность так называемого "захвата" клавиатуры. Любая клиентская программа может захватить клавиатуру, и тогда извещения о клавиатурных событиях (KeyPress и KeyRelease – "клавиша клавиатуры отпущена») будут отправляться только одной клиентской программе, той, которая выполнила захват, независимо от того, какие еще программы их заказали. После освобождения клавиатуры извещения вновь направляются всем программам, их заказавшим. Захват может быть безусловным и по условию. Безусловный захват наступает вследствие вызова в клиентской программе функции XGrabKeyboard. Освобождается клавиатура в этом случае вследствие вызова в той же клиентской программе функции XUngrabKeyboard. Это – захват по инициативе программы. Захват по условию (или захват по инициативе оператора) наступает после нажатия на определенную клавишу, код которой был указан среди аргументов функции заявки на захват XGrabKey. Клавиатура освобождается в этом случае после того, как указанная клавиша будет отпущена. Например, программа может указать в заявке на захват код клавиши SHIFT, и после нажатия на эту клавишу клавиатура окажется захваченной, и извещения о нажатии на любые другие клавиши (при нажатой клавише SHIFT) будут направляться только одной клиентской программе. Эту возможность можно использовать, например, для ввода пароля.

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

При нажатии на клавишу может наступить сразу два события: KeyPress и захват клавиатуры. Возникает естественный вопрос, какое из них наступает раньше (дело в том, что после захвата клавиатуры извещения направляются только одной клиентской программе, и вопрос можно переформулировать следующим образом: если в заявке на захват в качестве условия захвата было указано нажатие, например, на клавишу SHIFT, то будет ли направлено извещение о событии KeyPress при нажатии на эту клавишу всем клиентским программам, заказавшим извещения, или только одной?) В англоязычной документации не только не существует ответа, этот вопрос невозможно даже сформулировать, пользуясь принятой терминологией. В руководстве программиста дается разъяснение термина event (обычно переводимого как "событие"), из которого становится ясно, что он означает извещение о событии, а вот для слова событие англоязычного термина в X Window нет (см.: The Definition Guides to the X Window System. Vol. 1. Xlib Programming Manual. O'Reilly & Associates, 1995). В этом заключается серьезный концептуальный просчет, который служит причиной путаницы и недоразумений, поскольку трудно говорить о механизме событий, избегая слово "событие". Смысловые проблемы возникают также при обсуждении вопросов, связанных с захватом и освобождением указывающего устройства.

Событие KeymapNotify. При пересечении курсором границы окна наступает событие Enter­Notify, и сервер формирует соответствующее извещение. Клиентским программам, принимающим такие извещения, бывает важно знать, какие клавиши клавиатуры и кнопки указывающего устройства были нажаты в момент пересечения курсором границы окна. Эти сведения естественно было бы включить в извещение о событии EnterNotify, однако в X Window вместо этого формируется извещение о вымышленном событии KeymapNotify, в которое и помещаются указанные сведения.

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

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

Возможность имитации событий чрезвычайно полезна (например, для макетирования и отладки), однако реализация этого механизма в X Window имеет следующий недостаток. Обычно при имитировании стремятся сделать так, чтобы имитированный объект отличался от настоящего как можно меньше. При имитации событий в X Window это может оказаться трудным делом. Проблема в том, что события X Window происходят в некотором контексте: создано какое-то количество окон, имеющих определенные размеры и положение, некоторые из окон высвечены, имеется определенный порядок их наложения и т.д. Серверу текущий контекст всегда известен, а вот клиентская программа может его лишь опрашивать, но к моменту получения затребованных сведений они могут оказаться устаревшими (напомним, что сервер и клиентские программы могут исполняться на разных процессорах сети). Кроме того, такой элемент контекста, как захваченность устройства, клиентской программе недоступен по замыслу.Заметим, что само название функции – XSend­Event, используемой для имитации событий, говорит о том, что эта функция была задумана для другой цели, а именно как средство инициации события ClientMessage ("события в клиентской программе").

Для расширения возможностей системы по координации действий клиентских программ предусмотрено событие типа ClientMessage, которое можно охарактеризовать словами "в клиентской программе что-то произошло". Это событие уникально тем, что свидетельствует о чем-то, произошедшем в клиентской программе. Сервер в данном случае не фиксирует события (например, не сопоставляет ему отметки времени), а играет роль посредника, отправляющего извещения о нем другим клиентским программам, но состав извещения полностью формируется клиентской программой. В извещении об этом событии передается 20 байтов, ответственность за правильную интерпретацию которых несет прикладной программист. Концептуальная недоработка заключается в том, что особой функции, вызов которой порождал бы событие ClientMessage, в X Window не предусмотрено, это событие наступает в результате вызова функции-имитатора событий XSendEvent.

Обмен данными между клиентскими программами. Одна из типичных задач интерактивной графики – копирование данных, отображенных в окне. Копирование может осуществляться в пределах одного и того же окна или из одного окна в другое, причем данные в этих окнах могут отображаться разными клиентскими программами. Будем считать, что выполняется копирование текста из окна одного текстового редактора в окно другого. Для решения подобных задач в X Window предусмотрены события SelectionRequest («выдан запрос на копирование выделенных данных»), SelectionNotify («выделенные данные скопированы») и SelectionClear («отмена выделения данных, подлежащих копированию»). При копировании фрагмента текста события могут развиваться по следующему сценарию.

1.   Манипулируя клавиатурой и/или мышью, оператор выделяет фрагмент текста, подлежащий копированию. Информировать систему о желании скопировать выделенный текст он может, например, одновременным нажатием клавиш CNTRL и C.

2.   Зафиксировав событие KeyPress, сервер направляет извещения тем клиентским программам, которые заказали его для окна отправки (среди этих программ должна быть, очевидно, программа-отправитель, то есть первый текстовый редактор).

3.   Программа-отправитель, получив извещение о событии KeyPress и выяснив, что нажаты клавиши CNTRL и C, вызывает функцию XSetSelectionOwner.

4.   Сервер интерпретирует запрос XSetSelection­Owner как сигнал о том, что имеются данные, подлежащие копированию, и запоминает этот факт. Примечание. Запрос XSetSelectionOwner может оказаться повторным. Это может произойти в том случае, если оператор передумал и решил копировать другой фрагмент текста, возможно, даже в другом окне и относящемся к другой клиентской программе, то есть выделил другой фрагмент и снова нажал на клавиши CNTRL и C. Этот второй запрос сервер интерпретирует как сигнал о том, что имеются другой подлежащий копированию фрагмент, а копирование первого нужно отменить. Отмена копирования фиксируется как событие SelectionClear.

5.   Оператор переводит курсор в другое окно, а информировать систему о своем желании скопировать в него выделенный фрагмент он может, например, одновременным нажатием клавиш CNTRL и V.

6.   Зафиксировав событие KeyPress, сервер направляет извещения тем клиентским программам, которые заказали его для окна приема (среди этих программ должна быть, очевидно, программа получатель, то есть второй текстовый редактор).

7.   Программа-получатель, получив извещение о событии KeyPress и выяснив, что нажаты клавиши CNTRL и V, вызывает особую функцию XConvert­Selection.

8.   Сервер интерпретирует вызов XConvert­Selection как запрос на копирование данных, то есть наступление события SelectionRequest, и направляет извещение о нем программе-отправителю (то есть первому редактору).

9.   По событию SelectionRequest программа-отправитель выполняет копирование данных, после чего вызывает функцию XSendEvent, указав в качестве аргумента тип события SelectionNotify.

10. Сервер интерпретирует вызов XSendEvent как сигнал о завершении пересылки данных, то есть о наступлении события SelectionNotify, и направляет извещение о нем программе-отправителю.

Концептуальная погрешность заключается в том, что событие SelectionNotify, свидетельствующее о завершении копирования данных, может наступить только в результате вызова функции-имитатора XSendEvent, а не специально предназначенной для этого функции (по аналогии с XSetSelection-Owner и XConvertSelection). Эта погрешность наглядно демонстрируется таблицей, в которой приведены типы событий, соответствующие им типы структур данных, передаваемых в составе извещения, и функции, вызов которых порождает эти события.

Таблица

Событие

Извещение (тип структры)

Функция

SelectionClear

XSelectionClearEvent

XSetSelectionOwer

SelectionRequest

XSelectionRequestEvent

XConvertSelection

SelectionNotify

XSelectionEvent

XSendEvent

ClientMessage

XClientMessageEvent

XSendEvent

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


Permanent link:
http://swsys.ru/index.php?page=article&id=328&lang=en
Print version
Full issue in PDF (2.31Mb)
The article was published in issue no. № 3, 2007

Perhaps, you might be interested in the following articles of similar topics: