• XC_arrow - обычный курсор в форме стрелки, отображаемый сервером.
• XC_pencil - курсор в форме карандаша.
• XC_watch - песочные часы.
Создать курсор с использованием этих идентификаторов несложно. Из файла /usr/include/X11/cursorfont.h узнаем номера необходимых идентификаторов и опеределяем их:
const
XC_watch=150;
var
(* эта переменная содержит дескриптор создаваемого курсора *)
watch_cursor: TCursor;
(* создаем курсор "песочные часы" *)
watch_cursor:= XCreateFontCursor(display, XC_watch);
Другой метод создания курсора - использование пары пиксельных карт глубиной 1. Одна пиксельная карта определяет форму курсора, а другая работает как маска, определяющая, какие пиксели курсора действительно будут нарисованы. Остальная часть пикселей будет прозрачной. Создание такого курсора осуществляется с помощью функции XCreatePixmapCursor(). В качестве примера создадим курсор, используя битовое изображение "icon.bmp". Будем предполагать, что оно уже загружено в память и преобразовано в пиксельную карту, дескриптор которой сохранен в переменной bitmap. Мы хотим, что оно было полностью прозрачным. Это означает, что только черные фрагменты нарисуются, а белые будут прозрачными. Чтобы достигнуть такого эффекта, будем использовать иконку и как пиксельную карту курсора, и как маску пиксельной карты.
var
(* эта переменная содержит дескриптор создаваемого курсора *)
icon_cursor: TCursor;
(* вначале необходимо определить основной и фоновый цвета курсора *)
cursor_fg, cursor_bg: TXColor;
screen_colormap: TColormap;
rc: TStatus;
(* получаем доступ к палитре экрана по умолчанию *)
screen_colormap:= XDefaultColormap(display, XDefaultScreen(display));
(* выделяем черный и белый цвета *)
rc:= XAllocNamedColor(display, screen_colormap, 'black', @cursor_fg, @cursor_fg);
if (rc = 0) then begin
writeln('XAllocNamedColor - невозможно распределить цвет "black"');
halt(1);
end;
rc:= XAllocNamedColor(display, screen_colormap, 'white', @cursor_bg, @cursor_bg);
if (rc = 0) then begin
writeln('XAllocNamedColor - невозможно распределить цвет "white"');
halt(1);
end;
(* Наконец, создаем курсор. Горячую точку устанавливаем ближе к верхнему левому углу курсора - позиции (x=5, y=4). *)
icon_cursor:= XCreatePixmapCursor(display, bitmap, bitmap, @cursor_fg, @cursor_bg, 5, 4);
Когда мы определяем курсор, необходимо определить, какой пиксель курсора является указателем, доставляемым пользователю в различные события от мыши. Обычно, мы выберем позицию курсора, которая визуально выглядит похожей на "горячую точку". Например, на курсоре в виде стрелки конец стрелки будет определен как горячая точка.
Когда курсор больше не нужен, его необходимо освободить, используя функцию XFreeCursor():
XFreeCursor(display, icon_cursor);
После того, как курсор создан, необходимо сообщить X серверу об окне, к которому он должен быть подключен. Это делается с помощью XDefineCursor(), и заставляет сервер X менять указатель мыши на форму этого курсора всякий раз, когда указатель мыши перемещается внутри этого окно. Мы можем отключить этот курсор от нашего окна с помощью функции Xlib XUndefineCursor(), которая заставит отображаться встроенный курсор.
(* прикрепить курсор к окну *)
XDefineCursor(display, win, icon_cursor);
(* отключить курсор от окна *)
XUndefineCursor(display, win);
1.2.7 Лабораторная работа #2 "Текст и графика"
1. Напишите программу, выводящую текстовое сообщение в произвольную позицию (в пределах окна) произвольным цветом. Цвет и координаты должны меняться при изменении размеров окна.
2. Составьте программу, принимающую со стандартного ввода маску шрифта, выводимую строку, координаты х, у и отображающую окно с текстом согласно введенной информации.
3. Нарисуйте в окне график функции sin(x) на отрезке [-?;?]. Оси подпишите курсивом, метки по осям - обычным шрифтом, начало координат (0) выделите жирным шрифтом.
4. Нарисуйте в окне 100 окружностей. Цвет, координаты центра и радиус выбирать случайным образом.
5. Используя StructureNotifyMask и русский шрифт, модифицируйте программу из первого задания лабораторной работы #1 таким образом, чтобы сообщение всегда отображалось в центре окна.
6. Составьте программу, выводящую в окно все символы стандартного курсорного шрифта.
1.3 Работа с внешними устройствами
Как и большинство интерактивных программ, задачи, выполняющиеся в X Window, активно используют для ввода информации клавиатуру компьютера. Когда пользователь нажимает или отпускает клавишу, сервер получает соответствующий сигнал, который преобразуется в событие и отправляется в очередь программы, имеющей фокус ввода (input focus).
Поясним, что такое фокус ввода. Дело в том, что клавиатура у машины одна, и она разделяется всеми выполняющимися одновременно программами. Но в каждый момент времени поступающий от устройства сигнал доступен лишь одной из них, как правило, той, которой принадлежит активное окно. В этом случае говорят, что программа и ее окно имеют фокус ввода. Последний может переходить от окна к окну и от программы к программе.
Когда окно получает фокус, соответствующей программе посылается событие FocusIn, при потере - приходит событие FocusOut.
Когда пользователь нажимает клавишу клавиатуры, программа получает событие KeyPress. Сервер также может послать событие KeyRelease, когда клавиша отпускается, но это справедливо не для всех типов компьютеров.
Оба этих события сопровождаются структурой типа TXKeyEvent. Ее поле keycode содержит код нажатой клавиши, а поле state - состояние клавиш-модификаторов и кнопок мыши. Модификаторами называются такие клавиши, как Shift, Ctrl, Caps Lock. Кроме этого, X предусматривает наличие дополнительных модификаторов, которые обозначаются Mod1,…, Mod5. Каждой нажатой клавише-модификатору и кнопке мыши соответствует флаг в поле state.
Коды, передаваемые через поле keycode структуры TXKeyEvent, однозначно идентифицируют клавиши. Их конкретные значения зависят от типа машины и клавиатуры. Эти коды мы будем называть физическими. Чтобы обеспечить переносимость программ, сервер устанавливает соответствие между физическими кодами клавиш, которые могут меняться от компьютера к компьютеру, и целочисленными константами - логическими кодами (символами). Они имеют предопределенные значения, которые приведены в файле /usr/include/X11/keysymdef.h и начинаются с префикса "XK_". Так, букве "a" соответствует символ XK_a, клавише ‹Return› (‹Enter›) - символ XK_Return и т.д.
Для разных алфавитов X поддерживает разные множества логических кодов. Возможные типы алфавитов перечисляются в файле /usr/include/X11/keysym.h.
Одному коду клавиши может соответствовать несколько символов в зависимости от состояния клавиш-модификаторов. Функция
function XKeycodeToKeysym(prDisplay: PDisplay; nKeycode: TKeyCode; nIndex: longint): TKeySym; cdecl; external;
позволяет по коду nKeyCode получить соответствующий ему символ с номером nIndex. Если nIndex равен 0, то полученный символ соответствует просто нажатой клавише. Если nIndex равен 1, то возвращается символ, соответствующий ситуации, когда клавиша нажата одновременно с Shift.
Функция XKeysymToKeycode() осуществляет обратное преобразование.
Программа может получить карту соответствия кодов и символов, обратившись к процедуре XGetKeyboardMapping().
Изменяется соответствие физических и логических кодов процедурой XChangeKeyboardMapping(). Следующая последовательность операторов ставит клавише ‹F2› в соответствие символ XK_F3.
…
var
nF2Sym, nF3Sym: TKeysym;
nF2Keycode: TKeyCode;
prDisplay: PDisplay;
…
nF2Sym:= XStringToKeysym ('F2');
nF3Sym:= XStringToKeysym ('F3');
nF2Keycode:= XKeysymToKeycode (prDisplay, nF2Sym);
XChangeKeyboardMapping (prDisplay, nF2Keycode, 1, @nF3Sym, 1);
…
Здесь использована процедура XStringToKeysym(), которая по строке "str" возвращает соответствующий символ XK_str.
Когда соответствие кодов меняется, всем работающим в настоящее время клиентам посылается событие MappingNotify.
Клавиши-модификаторы также имеют логические коды. Клавишам Shift сопоставлены символы XK_Shift_L и XK_Shift_R; Caps Lock соответствует XK_CapsLock; Control - XK_Control_L; Mod1 - XK_Meta_L и XK_Meta_R. Символы остальных модификаторов (Mod2 - Mod5) не определены. X содержит набор специальных процедур, которые позволяют получить и установить соответствие код-символ для модификаторов. Эти функции следующие: XGetModifierMapping(), XInsertModifiermapEntry(), XDeleteModifiermapEntry(), XSetModifierMapping().