Руководство по ОС Excelsior - Части 9-11

Скачать PDF


Содержание Части 1-5 Части 7-8 Части 9-11

Часть 9. Диск в файловой системе

Предисловие соавтора

Появлению описания диска мы обязаны А.Хапугину (Hady). Он является автором утилит проверки и починки файловой системы fschk и fsdb, и это описание адресует в помощь пользователям этих утилит.

Соавтор

Администратору системы часто приходится иметь дело с магнитными дисками: форматировать, инициализировать, копировать и, что самое страшное, редактировать низкоуровневыми средствами. Для этого необходимо иметь представление об устройстве носителя в ОС Excelsior.


Ну и ну, сколько же можно поворачивать?! Никакая это не дорожка, а просто юла какая-то...

Л.Кэрролл. Алиса в Зазеркалье

Диск представляет собой пакет, содержащий несколько рабочих поверхностей (возможно, одну). Рабочая поверхность аппаратно разбита на дорожки, каждая из которых содержит несколько секторов.

 
            |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~|
            |                   поверхность i               |
            |===============================================|
    |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~|    |
    |                    поверхность 1                 |----|
    |==================================================|    |
|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~|   |----|
|                    поверхность 0                 |---|    |
|===========||=====================================|   |----|
| дорожка 0 || сектор 0 | сектор1 | ... | сектор k |---|    |
|-----------||-------------------------------------|   |____|
| дорожка 1 || сектор 0 | сектор1 | ... | сектор k |---|
|-----------||-------------------------------------|   |
|           ||     .     .     .                   |___|
|-----------||-------------------------------------|
| дорожка j || сектор 0 | сектор1 | ... | сектор k |
|___________||_____________________________________|

Адресация на диске, как правило, реализована аппаратно, зависит от контроллера диска и его драйвера.

Описанную структуру принято называть физической структурой диска. Информация о физической структуре диска поставляется ОС драйвером и используется только для оптимизации операций чтения/записи.

Файловая система организует другое разбиение диска, которое мы будем называть логической структурой.

9.1. Блок

Логической единицей адресации диска в ОС Excelsior является БЛОК. Размер блока на всех дисках равен 4К (4096) байт. Блоки нумеруются с 0, количество блоков определяется емкостью носителя.

|~~~~~~~~|~~~~~~~~|~~~~~~~~|~~~~~~~~~~~~~|~~~~~~~~|
| блок 0 | блок 1 | блок 2 |  . . . . .  | блок N |
|________|________|________|_____________|________|

Номер блока на диске называется далее ФИЗИЧЕСКИМ НОМЕРОМ (ФН).

Блок с ФН 0 зарезервирован для программы начальной загрузки; он не может быть использован для хранения файлов.

Блок с ФН 1 называется СУПЕРБЛОКОМ и используется исключительно системой (см 9.2).

Блоки с ФН от 2 до некоторого номера SYS, зависящего от размера диска, используются исключительно системой и содержат в себе ДЕСКРИПТОРЫ ФАЙЛОВ (или ИНОДЫ, см. 9.3).

Остальные блоки используются для хранения ФАЙЛОВ (см. 9.5).

9.2. Суперблок

В суперблоке содержится следующая информация:

  • символьное имя носителя;
  • количество файлов на носителе;
  • количество блоков на носителе;
  • карта файлов;
  • карта блоков.

9.2.1. Метка носителя

Метка носителя - это строка в кодировке КОИ-8 длиной до 16 символов. Терминатором строки считается символ с кодировкой 0c. Метка не может содержать символы "/", "[", "]", ":".

9.2.2. Количество файлов

Количество файлов - 32-разрядное целое число, равное максимально возможному количеству файлов на диске (количеству дескрипторов файлов на диске).

9.2.3. Количество блоков

Количество блоков - 32-разрядное целое число, равное общему количеству блоков на диске, вычисленному при инициализации диска.

9.2.4. Карта файлов

Карта файлов - массив битов. Биты в карте нумеруются от 0 до N-1, где N - количество файлов на диске. Бит с номером J соответствует иноду с номером J. Если бит с номером J выставлен в "1", то инод с номером J считается свободным, в противном случае - занятым.

9.2.5. Карта блоков

Карта блоков - массив битов. Биты в карте нумеруются от 0 до N-1, где N - количество блоков на диске. Бит с номером J соответствует блоку с номером J. Если бит с номером J выставлен в "1", то блок с номером J считается свободным, в противном случае - занятым.

9.3. Область дескрипторов файлов

ОБЛАСТЬ ДЕСКРИПТОРОВ ФАЙЛОВ представляет собой одномерный массив 64-х байтовых записей с информацией о файле – инодов (см. 9.4).

Иноды нумеруются от 0 до N-1, где N - количество файлов на диске. Каждый инод либо является описанием файла, либо не занят системой.

Номер инода, описывающего файл, называется НОМЕРОМ ФАЙЛА и является внутрисистемным индикантом данного файла, так как его достаточно для организации доступа к файлу.

Инод с номером 0 на всех носителях используется для КОРНЕВОЙ ДИРЕКТОРИИ.

Инод с номером 1 зарезервирован для организации загрузки системы с данного диска.

Инод с номером 2 зарезервирован для закрытия дефектных блоков диска.

9.4. Дескриптор файла

Дескриптор файла - инод (от англ. "index node") – это специальная запись размером 64 байта, содержащая информацию ОС о файле. В ней находится:

  • таблица соответствия логических номеров (ЛН) (см. 9.4) блоков физическим номерам (ФН),
  • время создания файла,
  • время последней записи в файл,
  • информация о правах доступа пользователей к файлу,
  • размер файла в байтах,
  • количество ссылок на файл,
  • специальные признаки файла.

9.4.1. Таблица соответствия номеров блоков

ТАБЛИЦА СООТВЕТСТВИЯ ЛН и ФН - REF (от англ. "REFerence" - ссылка) представляет собой массив из 8 целых чисел. Каждый элемент этого массива может ссылаться на какой-нибудь блок диска или быть незанятым. В первом случае элемент содержит ФН блока, на который он ссылается, во втором – отрицательное число.

Диск              ||        ||        ||        ||
|~~~~~~~~|~~~~~~~~||~~~~~~~~||~~~~~~~~||~~~~~~~~||~~~~~~~
| блок 0 | блок 1 || блок X || блок Y || блок Z || . . .
|________|________||________||________||________||_______
                  ||     |  ||     |  ||     |  ||
      --------------------         |         |
      |       ----------------------         |
      |       |       ------------------------
      |       |       |
|~~~~~*~|~~~~~*~|~~~~~*~|~~~~~~|~~~~~~|~~~~~~|~~~~~~|~~~~~~|
|   X   |   Y   |   Z   |  -1  |  -1  |  -1  |  -1  |  -1  |
|_______|_______|_______|______|______|______|______|______|
  REF0     REF1    REF2   REF3   REF4   REF5   REF6   REF7

Для файлов, содержащих не более 8 блоков, элемент таблицы с номером, равным ЛН, ссылается на соответствующий ему блок. Если файл содержит более 8 блоков (32Кбайт), то элементы данного массива ссылаются не на блоки с информацией файла, а на так называемые ИНДЕКСНЫЕ блоки - блоки, содержащие ФН блоков файла. В этом случае блок с информацией файла находится по следующей схеме:

  REF0   REF1       || REF X || REF7
|~~~~~~|~~~~~~|~~~~~||~~~~~~~||~~~~~~|
| .... | .... | ... ||   Y   || .... |
|______|______|_____||____*__||______|
                    ||    |  ||
                          |
     ----------------------
     |
Блок Y                  ||                   ||
 |~~~~|~~~~|~~~~|~~~~~~~||~~~~~|~~~~~~~|~~~~~||~~~~~|~~~~|~~~~|
 |    |    |    |  ...  ||     | xxx * |     || ... |    |    |
 |____|____|____|_______||_____|_____|_|_____||_____|____|____|
    0    1    2         || Z-1    Z  |   Z+1 ||      1022 1023
                                     |
                         -------------
Диск              ||     |    ||
|~~~~~~~~|~~~~~~~~||~~~~~~~~~~||~~~~~~~
| блок 0 | блок 1 || блок xxx || . . .
|________|________||__________||_______
                  ||          ||

где X=(ЛН DIV 1024); Z=(ЛН MOD 1024); xxx - ФН блока, соответствующего ЛН.

Физический блок, на который есть ссылка из REF или индексного блока файла, должен быть помечен как занятый в карте блоков (см. 9.2.5).

Значение номера блока, большее максимального номера на диске, считается некорректным и должно быть заменено на "-1".

9.4.2. Время создания файла

Время создания файла - 32-разрядное целое число, равное времени создания файла, записанному в стандарте ОС Excelsior.

9.4.3. Время модификации файла

Время модификации файла - 32-разрядное целое число, равное времени последней записи в данный файл, записанному в стандарте ОС Excelsior.

9.4.4. Информация о правах доступа

Информация о правах доступа пользователей к файлу содержится в 4 байтах.

9.4.5. Размер файла

Размер файла - 32-разрядное целое число, в котором содержится размер файла в байтах (EOF - от End Of File). При этом система полагает, что файл содержит байты с номерами [0..EOF-1].

9.4.6. Количество ссылок на файл

Количество ссылок на файл (links) - 32-разрядное целое число, обозначающее количество ссылок на данный файл из директорий (см. 9.6.1.2). Если это число равно 0, то данный инод считается свободным и должен быть помечен в карте файлов как свободный. Если это поле больше нуля, то данный инод считается занятым и должен быть помечен в карте файлов как занятый. Значение, меньшее 0 или большее максимального номера файла считается некорректным и должно быть заменено на 0.

9.4.7. Специальные признаки

Специальные признаки файла - массив битов. В настоящей реализации используются следующие признаки:

  • длинный файл;
  • директория;
  • псевдофайл;

а) признак длинного файла (long) выставляется в том случае, если файл содержит более 8 блоков. В этом случае массив REF файла содержит номера не блоков с информацией, а индексных блоков (см. 9.4.1).

б) признак директории (dir) выставляется, если дескриптор описывает файл специального вида - директорию (см. 9.6).

в) признак псевдофайла (escape) обозначает, что данный дескриптор не является описанием файла. В байтах такого дескриптора, предназначенных для REF, содержится логическое имя драйвера некоторого устройства в стандарте ОС Excelsior.

9.5. Файл

Файл с точки зрения ОС представляет собой одномерный массив байтов, пронумерованых от 0 до EOF-1 (см. 9.4.4). Данный массив разбивается на блоки, которые также нумеруются с 0. Номер блока в файле называется ЛОГИЧЕСКИМ НОМЕРОМ блока.

|~~~~~~~~|~~~~~~~~|~~~~~~~~|~~~~~~~~~~~~~|~~~~~~~~|
| блок 0 | блок 1 | блок 2 |  . . . . .  | блок M |
|________|________|________|_____________|________|

9.6. Директория

ДИРЕКТОРИЯ - файл специального вида, доступный для чтения и записи как обычный файл, используемый ОС для организации файлового дерева. Директория представдяет собой одномерный массив УЗЛОВ - 64-байтовых записей (см. 9.6.1). Узлы в директории нумеруются от 0 до N-1, где N - текущее число узлов в директории. Размер директории должен быть не меньше 1 узла. При этом поле EOF инода, соответствующего данной директории, должно быть равно 64*N.

КОРНЕВОЙ директорией диска называется директория с номером инода 0. Узлы с номером 0 всех директорий диска, отличных от корневой, должны иметь имя "..", признаки {dir, hidden} (см. 9.6.1.3) и ссылаться (см. 9.6.1.2) на директорию, к которой данная директория привязана (см. 9.6.1.2).

9.6.1. Узел директории

Узел директории содержит следующую информацию:

  • имя узла;
  • номер файла, на который узел ссылается;
  • специальные признаки.

Узел либо ссылается на файл, либо является незанятым. Незанятым считается узел, который либо имеет пустое имя, либо специальный признак "отвязанный файл".

9.6.1.1. Имя узла

Имя узла - массив из 32 байт, в котором содержится имя в кодировке КОИ-8. Имя может быть пустым только для свободного узла. Терминатором имени считается либо конец массива либо символ 0c. Имя не может содержать символы " ", "/", "[", "]".

Не допускается наличие нескольких узлов с одним именем.

9.6.1.2. Номер файла

Номер файла - целое число. Если данное поле содержит номер файла и узел не является свободным, будем говорить, что узел (и директория вместе с ним) ССЫЛАЕТСЯ на этот файл, а файл, в свою очередь, ПРИВЯЗАН к этой директории под именем данного узла. Значение поля "номер файла", выходящее за диапазон [0..MAX_FILE-1], где MAX_FILE - число файлов на носителе, считается некорректным.

В одной директории может содержаться несколько узлов с разными именами, ссылающихся на один файл.

9.6.1.3. Специальные признаки файла

Специальные признаки файла - это массив битов. В настоящей реализации используются следующие признаки:

  • отвязанный файл ("del", от англ. deleted)
  • файл            ("file")
  • директория      ("dir")
  • скрытый файл    ("hidden")
  • псевдофайл      ("escape")

Признаки "del" и "hidden" не зависят от состояния остальных признаков. Признак "escape" отменяет действие признаков "file" и "dir". Признак "dir" отменяет действие признака "file". Системой поддерживается отсутствие признаков, действие которых отменено другим признаком.

а) признак "отвязанный файл" выставляется, если данный узел ранее ссылался на файл, но эта ссылка была удалена. В этом случае остальные признаки сохраняются неизменными до следующего использования узла.

б) признак "файл" выставляется, если узел в настоящий момент ссылается на обычный файл (не являющийся директорией).

в) признак "директория" выставляется, если данный узел ссылается на директорию. В этом случае синонимичный признак должен быть выставлен в иноде, на который ссылается данный узел.

г) признак "скрытый файл"" выставляется для использования в системных утилитах визуализации директорий. Он обозначает, что при запуске без специальных указаний данный узел визуализировать не нужно.

д) признак "псевдофайл" дублирует в узле синонимичный признак инода, на который ссылается данный узел (см 9.4.7,б).



Часть 10. Драйверы устройств

Предисловие соавтора

Содержимое этой части - результат бесед с Д.Кузнецовым (Leo).

Соавтор


ОС Excelsior - развиваемая и легко настраиваемая система. Универсальность программного обеспечения достигается независимостью от типов устройств, входящих в конфигурацию системы. Настройка на конкретную конфигурацию производится с помощью драйверов. Это терминальные драйверы и драйверымагнитных носителей, драйверы печатающих устройств и т.д.. При необходимости новые драйверы могут быть дописаны.

10.1. Поддержка драйверов в системе

Поддержка драйверов в ОС Excelsior осуществляется на уровне ядра системы.

Кроме того, существует библиотека defReqest, которая тоже используется при написании драйверов.

10.2. Типы драйверов

В ОС известны драйверы трех типов:

  1. дисковые;
  2. сериальные;
  3. специальные.

Дисковые драйверы обеспечивают работу с дисками: выполняют массовые операции над секторами фиксированного размера (до 4Гб).

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

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

10.3. Структура драйвера

Очередь запросов

10.3.1. Представление системе

Для того, чтобы с устройством можно было работать, драйвер должен представиться системе.

Прежде всего, в нем должно содержаться самоназвание - слово из семи произвольных символов, за исключением пробелов, "/", "\", ":".

Кроме того, он должен содержать две процедуры: def_drv, представляющую драйвер, и rem_drv, удаляющую драйвер.

Замечание.  Процедура rem_drv в принципе не обязательна, поскольку это действие обеспечивается и самой системой.

Процедура def_drv имеет следующие параметры: имя драйвера, номер подустройства (направления), имя владельца (по сути, драйвера, с которым необходимо синхронизоваться, например, самого себя или пусто), тип устройства, процедуру обработки запроса do_io.

10.3.2. Запрос

Стандарт запроса определен в библиотечном модуле defRequest. Для непосредственного ознакомления эта библиотека с подробным комментарием приводится в приложении к этому разделу. В терминах Модулы-2 запрос - это запись со следующими полями:

REQUEST = RECORD

            op : INTEGER;

            drn: INTEGER;

            ofs: INTEGER;

            buf: sys.ADDRESS;

            pos: INTEGER;

            len: INTEGER;

            res: INTEGER;

          END;

Поле op определяет характер операции над устройством (чтение, запись и т.п.).

Поле drn содержит номер подустройства (направления).

Поле res обрабатывается средствами библиотеки defErrors для получения информации об ошибках при выполнении операции.

Поля ofs, buf, pos, len ориентированы на дисковые и сериальные драйверы и имеют следующий смысл:

поле для дисковых драйверов для сериальных драйверов
len число секторов число байт
pos игнорируется номер байта
buf с какого адреса начинать операцию адрес, с которого читать или по которому писать
ofs с какого сектора начинать операцию игнорируется

10.3.3. Процедура обработки запроса

Каждый драйвер реализует процедуру обработки запросa do_io. Этой процедуре в качестве параметра передается запрос:

PROCEDURE do_io(VAR REQUEST);

Процедура может выглядеть приблизительно так:

PROCEDURE doio(VAR r: REQUEST);

BEGIN

  CASE r.op OF

    |READ : r.res:=my_read(r.drn,r.ofs,r.len...)

    |WRITE:

  END;

END doio;

10.4. Приложение: библиотека defRequest

DEFINITION MODULE defRequest; (* Ned 19-Sep-89. (c) KRONOS *)


(* Определяет стандарт запроса к драйверу. *)


IMPORT sys: SYSTEM;


CONST (* dmode *)

  ready = {0};

  floppy = {1};

  wint = {2};

  fmtsec = {3};

  fmttrk = {4};

  fmtunit = {5};

  wpro = {6};


(*sync = { 8};*)


CONST (* smode *)

  raw = { 0};

  parNO = { 1};

  parODD = { 2};

  parEVEN = { 3};

  stops0 = { 4};

  stops1 = { 5};

  stops1_5 = { 6};

  stops2 = { 7};

  sync = { 8};


TYPE

  TRANSLATE = POINTER TO ARRAY CHAR OF CHAR;


--------------------- Стандарт запроса -----------------------

                     ------------------


REQUEST = RECORD (* 28 bytes *)

            op : INTEGER; -- код операции

            drn: INTEGER; -- номер подустройства

            res: INTEGER; -- результат

            CASE :INTEGER OF

            |0: ofs : INTEGER; -- адрес на устройстве

                buf : sys.ADDRESS; -- адрес буфера в памяти

                pos : INTEGER; -- смещение в буфере

                len : INTEGER; -- длина


            |1: (* только для операций GET_SPEC, SET_SPEC*)

                dmode : BITSET;

                dsecs : INTEGER; (* размер устройства в *)

                                 (* секторах *)

                ssc : INTEGER; (* код размера сектора *)

                secsize: INTEGER; (* длина сектора 2**ssc*)

                cyls : INTEGER; (* число треков *)

                heads : INTEGER; (* число головок *)

                minsec : INTEGER; (* min номер сектора *)

                maxsec : INTEGER; (* max номер сектора *)

                ressec : INTEGER; (* число резервных сек.*)

                precomp: INTEGER; (* прекомпенсация *)

                rate : INTEGER; (* шаг головки *)


            |2: (* только для операций GET_SPEC, SET_SPEC*)

                smode : BITSET;

                baud : INTEGER; (* baud rate code *)

                xon : CHAR; (* XON/XOFF *)

                xoff : CHAR; (* протокол *)

                limxon : INTEGER; (* send xon limit *)

                limxoff: INTEGER; (* send xoff limit *)

                trtin : TRANSLATE;

                trtout : TRANSLATE;

            END

          END;


------------ Перечень операций над устройствами --------------

             ----------------------------------


CONST (* L.S.B. (Low Significant Byte *)

  NOP = 0;

  LOCK = 1;       (* LOCK пока не используется *)

  UNLOCK = 2;     (* UNLOCK пока не используется *)


  READ = 3;       (* чтение данных с устройства *)

  WRITE = 4;      (* запись данных на устройство *)


  WAIT = 5;       (* ожидание данных *)

  READY = 6;      (* запрос о числе байтов в буфере ввода *)

  CONTROL = 7;    (* управляющая операция для клавиатур, *)

                  (* экранов и т.д. Старшие байты содержат *)

                  (* код операции *)


  GET_SPEC = 8;   (* запрос спецификации устройства *)

  SET_SPEC = 9;   (* определение спецификации устройства *)

  POWER_OFF = 10; (* завершение работы *)

  FORMAT = 11;    (* форматирование устройства *)

  SEEK = 12;      (* позиционирование *)

  MOUNT = 13;     (* монтирование носителя *)

  UNMOUNT = 14;   (* размонтирование носителя *)


(*************************************************************


------------------------ ПРИМЕЧАНИЕ ------------------------

                        ------------


Следующее описание определяет параметры каждой операции и поля, через которые эти параметры передаются. Все операции возвращают результат операции в поле res. Для всех операций поле drn содержит номер (под)устройства.


READ, WRITE (disk):

-----------------

        IN

            drn - номер (под)устройства

            buf - буфер ввода-вывода

            ofs - номер сектора на диске

            len - число секторов

        OUT

            res - результат операции


READ, WRITE (serial):

------------------------------

        IN

            drn - номер (под)устройства

            buf - буфер ввода-вывода

            pos - смещение в буфере

            len - число байтов

        OUT

            len - число непрочитанных байтов

            res - результат операции


WAIT (serial):

------------

        IN

            drn - номер (под)устройства

        OUT

            res - результат операции


READY (input serial):

--------------------

        IN

            drn - номер (под)устройства

        OUT

            len - число байтов в буфере ввода

            res - результат операции


CONTROL:

-------

        IN

            op  - старшие байты содержат код управляющей операциии

            drn - номер (под)устройства

        OUT

            res - результат операции


FORMAT:

------


Драйвер должен указать системе посредством операции GET_SPEC, какой тип форматирования он поддерживает:

  • fmtsec (посекторное);
  • fmttrk (потрековое);
  • fmtunit (всего устройства).

        OUT

            res - результат операции

            len - размер буфера (для fmttrk, см. далее)


Система вызывает драйвер с "ofs"=-1 "buf"=NIL перед форматированием.

Если драйверу требуется буфер, он должен возвратить "not_enough" в качестве результата и указать в "len" необходимый размер, после чего система отведет память под буфер и повторит операцию уже с "ofs"=-1, "buf"=выделенный_буфер, "len"=размер_буфера.

Если драйвер возвращает "ok" при ofs=-1, то буфер не отводится.


Для драйверов с форрматированием "fmtunit":


        IN drn - номер (под)устройства

            ofs = 0

Для драйверов с форрматированием "fmttrk":


        IN drn - номер (под)устройства

            buf - буфер ввода-вывода

            ofs - смещение на устройстве (в секторах)

            len - размер буфера (в байтах).


Драйверы с посекторным форматированием пока не поддерживаются в системе.


**************************************************************)

END defRequest.



Часть 11. Базовая поддержка графики

Предисловие соавтора

Содержимое этой части целиком лежит на совести А.Никитина (Nick), который является также автором большинства графических библиотек.


Глава 11.1. Общие сведения

11.1.1. Типы графических дисплеев

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

Как дисплеи на запоминаюших ЭЛТ, так и векторные дисплеи с произвольным сканированием являются устройствами рисования непрерывных отрезков, рисуемых из любой адресуемой точки в любую другую. Растровое устройство работает совершенно иначе. Его можно рассматривать как матрицу дискретных ячеек (точек), каждая из которых может быть подсвечена. Таким образом, растровый дисплей является "точечно-рисующим" устройством. Невозможно, за исключением специальных случаев, непосредственно нарисовать отрезок из одной адресуемой точки (пиксела) в матрице в другую адресуемую точку. Отрезок можно лишь аппроксимировать последовательностью точек, близко лежащих к реальной траектории отрезка.

11.1.2. Буфер кадра

Чаще всего в растровых графических устройствах используются различного рода буферы кадра, представляющие собой большой непрерывный участок оперативной памяти компьютера. Каждый пиксел растра кодируется как минимум одним битом памяти. Для квадратного растра размером 512x512x1 бит требуется 262144 бита памяти. Изображение в буфере кадра строится поточечно. Если точка растра кодируется одним битом памяти, имеющим только два состояния (двоичное 0 и 1), то можно получить только "черно-белое" изображение. Буфер кадра является цифровым устройством, тогда как электронно-лучевая трубка - аналоговое устройство, для работы которого требуется электрическое напряжение различных уровней. Поэтому при считывании информации из буфера кадра и ее выводе на графическое устройство с растровой ЭЛТ должно происходить преобразование из цифрового представления в аналоговый сигнал. Такое преобразование выполняет цифро-аналоговый преобразователь (ЦАП). Каждый пиксел буфера кадра, прежде чем он будет отображен на растровой ЭЛТ, должен быть считан и преобразован.

Интенсивность каждого пиксела на ЭЛТ управляется содержимым соответсвующих пикселов в буфере кадра. Двоичное число, полученное из буфера кадра, интерпретируется как уровень интенсивности между 0 и 2^N-1. С помощью ЦАП это число преобразуется в напряжение между 0 (темный экран) и 2^N-1 (максимальная интенсивность свечения). Очевидно, что всего можно получить 2^N уровней интенсивности, и расширение диапазона одновременно доступных цветов или полутонов серого может быть лишь получено путем увеличения разрядности слова, кодирующего состояние пиксела.

11.1.3 Таблица цветов (палитра)

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

Поскольку существует три основных цвета, линейная комбинация которых позволяет получить все остальные цвета, то можно реализовать простой "цветной" буфер кадра, разбив слово таблицы цветов на три равные части по M бит. Каждая из этих трех частей будет задавать интенсивность одного из основных цветов. Таким образом можно получить 2^N цветов из (2^M)^3, возможных, т.е. при M=4 (2^4)^3 = 4096 цветов, а при М=8 уже 16777216, что намного превосходит возможности глаза человека, различаюшего не более нескольких тысяч оттенков.



Глава 11.2. Битовые карты

Если разрядность слова, кодирующего состояние пиксела в буфере кадра растрового графического дисплея, равна 1, и эти пикселы расположены друг за другом в слове памяти процессора, то такого рода буфер кадра называют битовой плоскостью, или битовой картой (bitmap). Имея одну битовую плоскость, можно, очевидно, получить только "черно-белое" изображение. Для увеличения градаций "серой" шкалы или количества цветов нужно использовать несколько битовых плоскостей. При этом слово, кодирующее состояние пиксела на экране ЭЛТ, пакуется из соответствующих пикселов каждой из N используемых битовых плоскостей и интерпретируеся как уровень интенсивности между 0 и 2^N-1.

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

WPL (Words Per Line) = ( W + N-1 ) DIV N ,

где W - ширина битовой плоскости, N - ширина слова процессора в битах.



Глава 11.3. Библиотеки определения

Для поддержки стандартной работы с графическими дисплеями и решения задач машинной графики, и тем самым облегчения переноса больших графических програмных систем, в ОС Excelsior имеется набор библиотек нижнего уровня, состоящий из модулей: defScreen, Screen - подержка работы с графическими устройствами отображения, defBMG, BMG - представление битовых карт, рисование на них графических примитивов и текста, defFont, Fonts - описание и работа с различного рода шрифтами. Этот набор по мере развития операционной системы и прикладного програмного обеспечения будет расширяться.

11.3.1. Модуль defBMG

В модуле defBMG (текст прилагается, см.11.5.1) вводятся два базовых типа, определяющих стадартное для всех библиотек нижнего уровня описание битовых карт.

В записи BMD - дескриптора битовой карты - обзначены поля W и H, определяющие ее горизонтальный и вертикальный размеры соответственно, WPL - количество слов памяти для одной битовой строки, массив layers содержит в себе базовые адреса битовых слоев, PATTERN - шаблон для рисования линий. Поля W, H, WPL, BASE и PATTERN используются графическими командами процессора. Поле mask - шаблон имеющихся слоев в данной битовой карте (что очень удобно). Тип BITMAP удобен для низкоуровневых прикладных библиотек графики.

11.3.2. Модуль defScreen

В данном модуле (текст прилагается, см. 11.5.2) вводятся базовыe типы для описания характеристик графических дисплеев, их особенностей, а также задаются коды стандартных команд для программ-драйверов этих устройств.

11.3.2.1. Представление экранов, тип операции, маска записи

Определим буфер кадра как двумерный массив размером ScrWidth-x-ScrHeight n-разрядных слов, кодирующих цвет точек экрана.

Screen = ARRAY [0..ScrWidth-1][0..ScrHeight-1] OF ARRAY [0..n-1] OF BIT

Color(X,Y) -  некоторая функция, выдающая по координатам точки ее цвет
Mode       -  двуместная побитовая логическая функция между содержимым экрана и заданным цветом операции Color
Mask       -  маска записи.

Тогда операция постановки точки с координатами (X,Y) цвета Color и маской записи Mask определяется так:

Screen[X,Y]:=(Screen[X,Y]-mask) + (Screen[X,Y] Mode Color)*Mask .

Эта формула, записанная в нестрогом виде, несколько проясняет смысл введенных выше понятий.

11.3.2.2. Область отсечения (Clip Rectangle)

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

Теперь все координаты будем отсчитывать относительно точки (0,0) области отсечения, а постановку на экран точки с координатами, выходящими за пределы области отсечения, игнорировать.

11.3.2.3. Описание прямоугольного блока

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

TYPE BLOCK = RECORD x,y,w,h: INTEGER END;

где x,y - соответсвенно горизонтальная и вертикальная координаты нижнего левого угла прямоугольника, а w,h – его ширина и высота.

11.3.2.4 Инструмент (Tool)

Для работы с содержимым экрана необходимо уметь задать цвет, которым мы хотим рисовать, тип операции над содержимым экрана и заданным цветом, и очень удобно иметь маску записи (см 11.1.1). Помимо этого необходимо уметь просто и удобно задать координаты и размер доступной для изменений области экрана, т.е. определить "область отсечения" (см. 11.3.2.2).

Так как весь этот "инструментaрий" необходимо постоянно иметь под рукой, логично было бы собрать его в один "ящик":

TYPE TOOL = RECORD

              mode : INTEGER;

              mask : BITSET;

              color: BITSET;

              back : BITSET;

              clip : BLOCK;

              zX,zY: INTEGER;

            END;

Описание полей:

mask  -  маска записи (см. 11.3.2.1);
color -  "рабочий" цвет для рисования графических примитивов (линия, круг и т.д.), а также цвет рисования символов;
back  -  цвет фона, на котором рисуются символы (очень удобно иметь при выводе на экран различного рода текстов);
zX,zY -  центр относительных координат;
clip  -  описание прямоугольника, определяющего область отсечения (задается относительно zX и zY);
mode  -  тип операции (см 11.1.1), в данной версии может принимать следующие значения:

CONST

    rep = 0; (* destinator := sourse *)

    or  = 1; (* destinator := destinator OR sourse *)

    xor = 2; (* destinator := destinator XOR sourse *)

    bic = 3; (* destinator := destinator AND NOT sourse *)


      normal  = 0; (* зарезервировано *)

      reverse = 4; (* зарезервировано *)

11.3.2.5. Палитра (Palette)

Для удобного описания палитры (см. 11.1.3) введены два типа данных. COLOR - описывает соотношение интенсивностей основных цветов ( r - красный (rED), g - зеленый (gREEN), b - синий (bLUE)). PALETTE задает соответствие между кодом цвета, т.е. индексом в массиве, и соотношением основных цветов. Иными словами, определяет палитру цветов, одновременно доступных к изображению.

11.3.2.6 Описание Экрана

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

TYPE

  STATE  = POINTER TO STATUS;

  STATUS = RECORD

             type : INTEGER;

             kind : INTEGER;

             W,H  : INTEGER;

             bpp  : INTEGER;

             ldcx : INTEGER;

             ldcy : INTEGER;

             dx   : INTEGER;

             dy   : INTEGER;

             xpix : INTEGER;

             ypix : INTEGER;

             RGB  : INTEGER;

             pal  : PALETTE;

             ext  : INTEGER;

           END;

magic - волшебное слово, которое не следует изменять;
type - число, определяющее тип устройства, например:
type=0 => устройство IGD480;
bpp - число бит на точку;
ldcx,ldcy - текущее положение отображаемой области;
W и H - ширина и высота области в элементах изображения;
dx,dy - шаг изменения положения отображаемой области буфера кадра;
xpix,ypix - соотношение расстояний между элементами изображения по вертикали и горизонтали, соотвественно, на физическом экране;
pal - текущая палитра;
RGB - дипазон значений интенсивностей красного, синего и зеленого цветов;
desc - ссылка на дескриптор представления буфера кадра, например, указатель на переменную типа BMD;
kind - вид конкретной реализации буфера кадра, в данной версии модуля может принимать следующие значения:

bitmap = 444D4224h; (* $BMD *)

pelmap = 44504124h; (* $APD *)

other  = 48544F24h; (* $OTH *)

11.3.2.7. Управляющие коды для драйверов

Для стандартного общения с драйверами различных графических дисплеев в модуле описаны соответсвующие константы - управляющие коды:

CONTROL   = 01h; --

_init     = 02h; -- команда инициализации драйвера,

_set_ldcx = 03h; -- установка горизонтальной координаты положения отображаемой области буфера кадра,

_set_ldcy = 04h; -- установка вертикальной координаты положения отображаемой области буфера кадра,

_set_rgb  = 05h; -- запись нового содержимого палитры,

_get_rgb  = 06h; -- чтение текущего содержимого палитры.

Замечание.  Все графические библиотеки для растровых дисплеев с различного рода реализациями буфера кадра должны придерживаться изложенных здесь правил изменения содержимого буфера кадра в соответствии со значениями маски записи, устанавливаемого цвета и типа операции.

11.3.3. Модуль defFonts

В данном модуле (текст прилагается, см.11.5.3) вводятся базовыe типы для описания характеристик шрифтов и их особенностей.

Здесь шрифтом мы называем набор графических представлений символов, расположенных в порядке, определенном стандартом КОИ-8, для отображения текстов на графическом экране. Для представленных битовыми матрицами шрифтов размеры знако-места не должны превышать 128x128 точек.

11.3.3.1. Дескриптор шрифта

Объявленный в модуле тип FNTD (FoNT Descriptor) есть запись, в которой хранятся все основные характеристики шрифта.

TYPE

  FONT = POINTER TO FNTD;

  BTAB = ARRAY CHAR OF CHAR;

  ITAB = ARRAY CHAR OF INTEGER;

  BTPTR = POINTER TO BTAB;

  ITPTR = POINTER TO ITAB;


  FNTD = RECORD

           W,H  : INTEGER;

           BASE : SYSTEM.ADDRESS;

           rfe  : SYSTEM.WORD;

           magic: INTEGER;

           state: BITSET;

           size : INTEGER;

           bline: INTEGER;

           uline: INTEGER;

           space: INTEGER;

           fchar: CHAR;

           lchar: CHAR;

           propW: BTPTR; (* #NIL only of state*prop#{} *)

           propX: BTPTR; (* #NIL only of state*prop#{} *)

           cellW: BTPTR;

           cellH: BTPTR;

           cellY: BTPTR;

           cellX: BTPTR; (* allways zero now *)

           bases: ITPTR;

         END;

CONST

    prop   = {0};

    italic = {1};

    packed = {2};

Поля W и H определяют максимальный размер знако-места для данного шрифта, bline и uline - положение базовой линии и линии подчеркивания относительно нижнего края знако-места.


+-------------------------+-- H-1
| *************** !       |
|   ****       ** !       |
|   ****        * !       |
|   ****    *     !       |
|   *********     !       |
|   ****    *     !       |
|   ****          !       |
|   ****          !       |
|   ****          !       |
|   ****          !       |
|-********--------!-------|-- 4  базовая линия
|                 !       |
|=================!=======|== 2  линия подчеркивания
|                 !       |
+-----------------!-------+-- 0
|<---------- W ---------->|
|<--propW^['F']-->|

В массиве, на который указывает значение поля propW, хранятся смещения от начала знако-места заданного символа ch до позиции печати следующего в строке. Поля rfe1, rfe2 и rfe3 зарезервированы для расширений, возможных при дальнейшем развитии графической поддержки в системе. Объяснение семантики остальных полей дескриптора можно встретить далее по тексту.

11.3.3.2. DCH-шрифты

В системе команд процессора КРОНОС 2.6 есть команда отображения символа с шириной и высотой, не превышающими 32 на битовые карты. Подробное описание команды можно найти в документации по системе команд процессора. Специально для этой графической команды в дескриптор шрифта введено поле BASE - указатель на начало непрерывной области памяти, где хранятся образы символов. При этом они имеют одинаковый размер и расположены ровно друг за другом.

BASE -----> +--------+
            |   0c   |
            +--------+
            |   1c   |
            +--------+
            |   2c   |
                :
                :
            |  376c  |
            +--------+ <-- BASE + ORD(377c) * H
            |  377c  |
            +--------+

Однако расстояния между символами при печати могут отличаться от ширины знако-места, но превосходить их. На это указывает отсутсвие в слове состояния шрифта state признака constW.

О том что вы имеете дело с DCH-шрифтом, говорит наличие признака dchar в слове состояния, и для этих шрифтов значение поля size равно высоте шрифта, умноженной на количество хранимых символов шрифта.

11.3.3.3. PACKED-шрифты

Для удобства хранения шрифтов большого размера предусмотрена возможность компактизации их содержимого, например, за счет того, что символы могут иметь одинаковое начертание, или быть неотображаемыми, т.е. не иметь своего битового образа. Для выделения подобного рода шрифтов в слове состояния выставляется признак packed, а также соответсвующим образом расписываются следующие поля поля дескриптора шрифта: указатели на массивы ширины и высоты хранимых образов - cellW и cellH, а также смещения этих образов по вертикали относительно нижнего края полного знако-места - charY, массив указателей на области памяти, занимаемых образами символов - bases. И если указатель в этом массиве равен NIL, то символ не имеет своего образа, например, по причине того, что не является отображаемым.

В случае пропорционального ненаклоненного шрифта смещение от начала знако-места заданного символа ch до позиции печати следующего в слове, хранящееся в массиве propW^[ch], равнo ширинe его знако-места ORD(cellW^[ch]).

                 |<-------->|<-- cellW^[l']
                 |          |
|<--cellW^['F']->|          |<--cellW^['y']-->|
+----------------+----------+-----------------+
| ************** | ******   |                 |
|   ****      ** |   ****   |                 |
|   ****       * |   ****   |                 |
|   ****   *     |   ****   |                 |
|   ********     |   ****   | *******    **** |
|   ****   *     |   ****   |   ****      *   |
|   ****         |   ****   |    ****    *    |
|   ****         |   ****   |     ****  *     |
|   ****         |   ****   |      *****      |
|   ****         |   ****   |       ***       |
|-*********------|-********-+--------*--------+
|                |          |       *         |
|================|==========|======*==========|
|                |          |   *****         |
+----------------+----------+-----------------+
+----------------+----------+-----------------+-+
|<-propW^['F']-->|          |<-- prop['y']--->|
                 |          |
                 |<-------->|<---prop['l']

Из рисунка становится ясно, что это утверждение не верно для наклонных шрифтов, выделяемых признаком ital.

                   |<------->|<--cellW^[l']
                   |         |
|<---cellW^['F']--->|        |<--cellW^['y']->|
+-------------------+--------+----------------+
|     **************|  ******|                |
|       ****      **|    ****|                |
|       ****       *|    ****|                |
|      ****   *    ||   **** |                |
|      ********    ||   **** | *******    ****|
|     ****   *     ||  ****  |  ****      *   |
|     ****         ||  ****  |   ****    *    |
|    ****          || ****   |   ****  *      |
|    ****          || ****   |    *****       |
|   ****           ||****    |    ***         |
|-*********------|-********-|------*--------|-+
|                |  |       ||    *         | |
|================|==|=====****==*===========|=|
|                |  |     |****             | |
+----------------|--------|-|+--------------|-+
|<-propW^['F']-->|        | |<--propW^['y']-->|
                 |        | |
                 |<-------->|<-----propW^['l']
                       -->| |<-----propX^['l']

В случае более плотной упаковки графических образов символов хранится только минимальный прямоугольник, охватывающий область значащих пикселов (на рисунке это прямоугольник размером ORD(cellW^["'"]) на ORD(cellH^["'"]) точек). При этом необходимое для корректного отображения символа смещение нижнего левого угла этого прямоугольника относительно базовой линии хранится в массиве, на который указывает поле charY в дескрипторе шрифта, и в слове состояния отсутствует признак constH.

      |<-->|<---cellW^['l']
---+--|----|-----------------+
^  |  |    | !               |
|  |--+****+-+---------------+----
|  |  ****** !               |  |
|  |  |***** !               | cellH^["'"]
|  |  |  **  !               |  |
|  |--+-*----+---------------+----
H  |  |      !               |  |
|  |  |      !               |  |
|  |  |      !               | charY^["'"]
|  |  |      !               |  |
|  |  |      !               |  |
|  |--|------!---------------|------- базовая линия
|  |  |      !               |  |
V  |  |      !               |  V
---+--|------!---------------+----
   |  |<------- W ---------->|
-->|  |<-------cellX^["'"]
   |<------->!<---- propW^["'"]

11.3.3.4. Дополнения

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



Глава 11.4. Прикладные библиотеки

11.4.1 Модуль BMG (BitMap Graphics)

Mодуль BMG (текст прилагается, см.11.5.4) предназначен для поддержки графического вывода на битовые карты и содержит набор процедур нижнего уровня, представляющих собой достаточный базис для написания графических систем более высокого уровня.

Данная библиотека является "чистой" и пригодна для использования в многопроцессных системах.

11.4.1.1 Процедуры работы с блоками

Описанные ниже процедуры призваны оградить пользователя от лишних размышлений при копировании и других действиях с прямоугольными битовыми блоками.

PROCEDURE cross(VAR des: BLOCK; blk0,blk1: BLOCK);

Процедура cross вычисляет пересечение двух блоков blk0, blk1 и параметры результирующего прямоугольника пересечения заносит в дескриптор блока des. Если же пересечение пусто, то ширина и высота в des будут равны 0.

PROCEDURE bblt (des: BITMAP; dtool: TOOL; x,y: INTEGER;

                sou: BITMAP; stool: TOOL; block: BLOCK);

bblt (bIT bLOCK tRANSFER) - процедура пересылки битового блока-источника block из битовой карты sou в битовую карту des. При этом левый нижний угол блока попадает в точку с координатами x,y; блок в источнике sou клипируется в соответствии с stool, а в приемнике des в соответствии с dtool. Как и все графические операции, bblt выполняется с определенной модой опeрации, которая задается значением параметра dtool.mode.

11.4.1.2. Процедуры стирания и заполнения

PROCEDURE erase(bmd: BITMAP);

Процедура erase предназначена для полной очистки слоев в битовой карте.

PROCEDURE fill(bmd: BITMAP; tool: TOOL; block: BLOCK;

                 w: INTEGER; SEQ pattern: SYSTEM.WORD);

PROCEDURE pattern(bmd: BITMAP; tool: TOOL; block: BLOCK;

                    w: INTEGER; pattern: ARRAY OF SYSTEM.WORD);

Эти процедуры заполняют с помощью заданного инструмента прямоугольную область block битовым шаблоном шириной w и высотой, определяемой по правилу:

(Размер pattern в словах)    DIV (ширина w, в словах)

(  (HIGH(pattern)+1) DIV ((w+31) DIV 32)  )

11.4.1.3. Процедуры рисования графических примитивов

Во всех нижеописанных процедурах bmd - указатель на битовую карту, где будет изображаться заданный примитив, tool - инструмент рисования.

PROCEDURE dot(... x,y: INTEGER);

Постановка точки.


PROCEDURE line(... x0,y0,x1,y1: INTEGER);

Рисование отрезка прямой по координатам его концов.


PROCEDURE dline(... X0,Y0,X1,Y1: INTEGER; VAR r: SYSTEM.WORD);

Рисование отрезка штрих-пунктирной прямой по координатам его концов. Шаблон задается переменной r. При этом при последовательном рисовании двух линий, если начало второй лежит в конце первой, рисунок шаблона не нарушится, что обеспечивается возвращением соответствующего значения этой переменной.


PROCEDURE rect (... x0,y0,x1,y1: INTEGER);

PROCEDURE frame(... x0,y0,x1,y1: INTEGER);

Рисование прямоугольника и рамки по координатам их диагональных вершин.


PROCEDURE arc(... xc,yc,xa,ya,xb,yb,r: INTEGER);

Рисование дуги окружности с центром в точке (xc,yc) радиуса r, от луча [(xc,yc),(xa,ya)) к лучу [(xc,yc),(xb,yb)).


PROCEDURE arc3(... x0,y0,x1,y1,x2,y2: INTEGER);

Рисование дуги окружности от точки (x0,y0) через (x1,y1) до точки (x2,y2).


PROCEDURE circle(... xc,yc,rad: INTEGER);

PROCEDURE circlef(... xc,yc,rad: INTEGER);

Рисование окружности и круга: xc, yc - координаты центра, rad - радиус.


PROCEDURE ring(... xc,yc,r1,r2: INTEGER);

Рисование круглого кольца по координатам центра xc, yc, внутреннему и внешнему радиусам.


PROCEDURE ellipse0(... xc,yc,rx,ry: INTEGER);

PROCEDURE ellipse0f(... xc,yc,rx,ry: INTEGER);

Эллипс и закрашенный эллипс: xc, yc - координаты центра; rx, ry - величины полуосей, параллельных осям X и Y соответственно.


PROCEDURE polyline0(... SEQ xy: INTEGER);

PROCEDURE polyline1(... xy: ARRAY OF INTEGER);

Рисование ломаной линии, заданной набором точек. Первой в паре лежит координата по X, второй - координата по Y. Если в последовательности или массиве количество элементов нечетно, то последний элемент при рисовании не принимается во внимание.


PROCEDURE trif(... x0,y0,x1,y1,x2,y2: INTEGER);

Рисование закрашенного треугольника по координатам трех его вершин.


PROCEDURE grid(... block: BLOCK; xstep,ystep: INTEGER);

PROCEDURE scroll(... x,y: INTEGER);

Содержимое прямоугольной области tool.clip сдвигается по горизонтали на расстояние x, по вертикали - на y. Направление сдвига задается знаком x (положительный - влево) и y (положительный - вниз). Освободившееся при этом место заполняется в соответствии с инструментом tool.


PROCEDURE offset(bmd: BITMAP; x,y,layer: INTEGER; VAR adr: SYSTEM.ADDRESS; VAR bitoffset: INTEGER);

По координатам x и y и номеру слоя layer выдает адрес слова в памяти и битовое смещение в этом слове, соответствующее данной точке. Если указанный слой в bmd отсутствует, в adr возвращается NIL.


PROCEDURE write(... str: ARRAY OF CHAR; pos,len: INTEGER);

PROCEDURE xwrite(... str: ARRAY OF CHAR; pos,len: INTEGER): INTEGER;

Отображают из строки str с позиции pos len символов шрифтом fnt. Процедура xwrite возвращает горизонтальную координату точки, следующей непосредственно за последней точкой выведенной строки.


PROCEDURE print(... f: ARRAY OF CHAR; SEQ arg: SYSTEM.WORD);

PROCEDURE xprint(... f: ARRAY OF CHAR; SEQ arg: SYSTEM.WORD): INTEGER;

Печатают значения параметров arg в формате, заданном в строке f. Процедура xwrite возвращает горизонтальную координату точки, следующей непосредственно за последней точкой выведенной строки.


PROCEDURE writech(... x,y: INTEGER; fnt: FONT; ch: CHAR);

Отображает символ ch из шрифта fnt в позиции (x,y).


PROCEDURE lenght(fnt: FONT; fmt: ARRAY OF CHAR; SEQ arg: SYSTEM.WORD): INTEGER;

Подсчитывает ширину области в пикселах, которую займет строка, отображенная шрифтом fnt, при печати значений параметров arg в формате, заданном в строке fmt.


PROCEDURE width (fnt: FONT; fmt: ARRAY OF CHAR; SEQ arg: SYSTEM.WORD): INTEGER;

Подсчитывает ширину области в пикселах, которую займет строка, отображенная шрифтом fnt, при печати значений параметров arg в формате, заданном в строке fmt.


PROCEDURE margin (fnt: FONT; fmt: ARRAY OF CHAR; SEQ arg: SYSTEM.WORD): INTEGER;

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

11.4.2. Модуль Screen

Mодуль Screen (текст прилагается, см.11.5.5) предназначен для поддержки и стандартизации управления экранами.

11.4.2.1. Переменные "done", "error"

Значение переменной "done" говорит о том, была ли ошибка при исполнении операций с экраном, а "error" является индикантом последней произошедшей ошибки (см. описание модуля defErrors). Приведем в качестве примера способ выявления ошибки и один из многих способов реакции на него:

operation(...);

IF NOT done THEN Terminal.perror(error,"%%s"); HALT END

11.4.2.2 Процедуры управления

Модуль при инициализации открывает устройствo по его символическому имени взятому из параметра SCR окружения задачи; если это удалось, производится его захват, закрывается для других задач доступ к нему; дескриптор экрана помещается в переменную state модуля. По окончании задачи устройство освобождается. Если открыть устройство не удалось, переменные done и error примут соответствующие значения.

PROCEDURE set_ldcx(x: INTEGER);

PROCEDURE set_ldcy(y: INTEGER);

Данные процедуры производят установку (если устройство располагает такой возможностью) координат левого нижнего угла видимой области экрана (Left Down Corner of visible area) по горизонтали и вертикали соответственно.


PROCEDURE set_palette(p: PALETTE; from,len: INTEGER);

Записывает len цветов в аппаратную палитру устройства, заданного дескриптором scr, начиная с цвета с номером from по образцу, заданному в переменной "p".


PROCEDURE op(cmd: INTEGER; SEQ args: SYSTEM.WORD);

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



Глава 11.5. Тексты определяющих модулей библиотек

11.5.1. Текст библиотеки defBMG

DEFINITION MODULE defBMG; (* nick 01-Jun-90. (c) KRONOS *)


IMPORT SYSTEM;


TYPE


  BITMAP = POINTER TO BMD;


  BMD = RECORD

          W,H : INTEGER;

          WPL : INTEGER;

          BASE : SYSTEM.ADDRESS;

          PATTERN: BITSET;

          mask : BITSET;

          layers : ARRAY [0..7] OF SYSTEM.ADDRESS; -- base addrs of layers

        END;


END defBMG.



11.5.2. Текст библиотеки defScreen

DEFINITION MODULE defScreen; (* nick 04-Oct-90. (c) KRONOS *)


IMPORT SYSTEM;


TYPE


  COLOR = RECORD

            r: INTEGER; (* intensity of red beam *)

            g: INTEGER; (* intensity of green beam *)

            b: INTEGER; (* intensity of blue beam *)

          END;


  PALETTE = DYNARR OF COLOR;


CONST (* screen kind *)

  bitmap = 444D4224h; (* $BMD *)

  pelmap = 44504124h; (* $APD *)

  other = 48544F24h; (* $OTH *)


TYPE

  STATE = POINTER TO STATUS;

  STATUS = RECORD

             type : INTEGER; (* type of screen device *)

             kind : INTEGER; (* kind of implementation *)

             W,H  : INTEGER; (* width = W pixells, height = H pix *)

             bpp  : INTEGER; (* bIT pER pIXELL *)

             ldcx : INTEGER; (* curren left down corner X position *)

             ldcy : INTEGER; (* curren left down corner Y position *)

             dx   : INTEGER; (* step by horizontal shifter *)

             dy   : INTEGER; (* step by vertical shifter *)

             xpix : INTEGER; (* distance between pixells at X-axis *)

             ypix : INTEGER; (* distance between pixells at Y-axis *)

             RGB  : INTEGER; (* range of beam's intensity *)

             pal  : PALETTE; (* current palette *)

             ext  : INTEGER; (* some extra descriptor *)

           END;


  BLOCK = RECORD x,y,w,h: INTEGER END;

  TOOL = RECORD

           mode : INTEGER; (* operation mode *)

           mask : BITSET; (* write mask *)

           color: BITSET; (* color/foreground *)

           back : BITSET; (* for text background *)

           clip : BLOCK; (* clipping rectangle *)

           zX,zY: INTEGER; (* (0,0) abs coordinates *)

         END;


CONST (* operation modes *)

  rep = 0; or = 1; reverse = 4;

  xor = 2; bic = 3; normal = 0;


CONST (* Driver Control Codes *)

  CONTROL = 01h;

  _init = 02h;

  _set_ldcx = 03h;

  _set_ldcy = 04h;

  _set_rgb = 05h;

  _get_rgb = 06h;

  _refresh = 07h;

  _refreshw = 08h;


END defScreen.



11.5.3. Текст библиотеки defFont

DEFINITION MODULE defFont; (* nick 07-May-90. (c) KRONOS *)

                           (* Leo  28-Jan-91. (c) KRONOS *)


IMPORT SYSTEM;


TYPE

  FONT = POINTER TO FNTD;

  BTAB = ARRAY CHAR OF CHAR;

  ITAB = ARRAY CHAR OF INTEGER;

  BTPTR = POINTER TO BTAB;

  ITPTR = POINTER TO ITAB;


  FNTD = RECORD

           W,H  : INTEGER;

           BASE : SYSTEM.ADDRESS;

           rfe  : SYSTEM.WORD;

           magic: INTEGER;

           state: BITSET;

           size : INTEGER;

           bline: INTEGER;

           uline: INTEGER;

           space: INTEGER;

           fchar: CHAR;

           lchar: CHAR;

           propW: BTPTR; (* #NIL only of state*prop#{} *)

           propX: BTPTR; (* #NIL only of state*prop#{} *)

           cellW: BTPTR;

           cellH: BTPTR;

           cellY: BTPTR;

           cellX: BTPTR; (* allways zero now *)

           bases: ITPTR;

         END;

CONST

  prop = {0};

  italic = {1};

  packed = {2};


END defFont.



11.5.4. Текст библиотеки BMG

DEFINITION MODULE BMG; (* nick 02-Mar-90. (c) KRONOS *)


IMPORT SYSTEM, defScreen, defBMG, defFont;


TYPE

  TOOL = defScreen.TOOL; BMD = defBMG.BMD;

  BLOCK = defScreen.BLOCK; BITMAP = defBMG.BITMAP;


CONST

  rep = defScreen.rep; xor = defScreen.xor;

  or = defScreen.or; bic = defScreen.bic;


---------------------- BitBlock Procedures ---------------------

                      ---------------------


PROCEDURE cross(VAR des: BLOCK; blk0,blk1: BLOCK);


PROCEDURE bblt(des: BITMAP; dtool: TOOL;

               x,y: INTEGER;

               sou: BITMAP; stool: TOOL; block: BLOCK);


--------------- Graphic Primitive Procedures -----------------

              --------------------------------


PROCEDURE erase(bmd: BITMAP);


PROCEDURE fill (bmd: BITMAP; t: TOOL; block: BLOCK;

                  w: INTEGER; SEQ pattern: SYSTEM.WORD);


PROCEDURE pattern(bmd: BITMAP; t: TOOL; block: BLOCK;

                  w,h: INTEGER; pattern: ARRAY OF SYSTEM.WORD);


PROCEDURE grid(bmd: BITMAP; t: TOOL; block: BLOCK; xstep,ystep: INTEGER);


PROCEDURE dot  (bmd: BITMAP; t: TOOL; X,Y: INTEGER);


PROCEDURE line (bmd: BITMAP; t: TOOL; X0,Y0,X1,Y1: INTEGER);

PROCEDURE dline(bmd: BITMAP; t: TOOL; X0,Y0,X1,Y1: INTEGER;

                                        VAR r: SYSTEM.WORD);

PROCEDURE rect (bmd: BITMAP; t: TOOL; X0,Y0,X1,Y1: INTEGER);

PROCEDURE frame(bmd: BITMAP; t: TOOL; X0,Y0,X1,Y1: INTEGER);

PROCEDURE arc  (bmd: BITMAP; t: TOOL; X0,Y0,xa,ya,xb,yb,r: INTEGER);

PROCEDURE arc3 (bmd: BITMAP; t: TOOL; x0,y0,x1,y1,x2,y2: INTEGER);


PROCEDURE circle   (bmd: BITMAP; t: TOOL; X,Y,R: INTEGER);

PROCEDURE circlef  (bmd: BITMAP; t: TOOL; X,Y,R: INTEGER);

PROCEDURE ring     (bmd: BITMAP; t: TOOL; x0,y0,r1,r2: INTEGER);

PROCEDURE ellipse0 (bmd: BITMAP; t: TOOL; xc,yc,rx,ry: INTEGER);

PROCEDURE ellipse0f(bmd: BITMAP; t: TOOL; xc,yc,rx,ry: INTEGER);


PROCEDURE polyline0(bmd: BITMAP; t: TOOL; SEQ xy: INTEGER);

PROCEDURE polyline1(bmd: BITMAP; t: TOOL; xy: ARRAY OF INTEGER);


PROCEDURE trif(bmd: BITMAP; t: TOOL; x0,y0,x1,y1,x2,y2: INTEGER);


----------------------------------------------------------------


PROCEDURE scroll(bmd: BITMAP; tool: TOOL; x,y: INTEGER);


PROCEDURE offset(bmd: BITMAP; x,y,layer: INTEGER;

             VAR adr: SYSTEM.ADDRESS; VAR bitoffset: INTEGER);


----------------------------------------------------------------


PROCEDURE lenght(fnt: defFont.FONT; fmt: ARRAY OF CHAR;

                              SEQ arg: SYSTEM.WORD): INTEGER;


PROCEDURE width (fnt: defFont.FONT; fmt: ARRAY OF CHAR;

                              SEQ arg: SYSTEM.WORD): INTEGER;


PROCEDURE margin(fnt: defFont.FONT; fmt: ARRAY OF CHAR;

                              SEQ arg: SYSTEM.WORD): INTEGER;


PROCEDURE write(bmd: BITMAP; tool: TOOL; x,y: INTEGER; fnt: defFont.FONT;

                              str: ARRAY OF CHAR; pos,len: INTEGER);


PROCEDURE xwrite(bmd: BITMAP; tool: TOOL; x,y: INTEGER; fnt: defFont.FONT;

                              str: ARRAY OF CHAR; pos,len: INTEGER): INTEGER;


PROCEDURE print(bmd: BITMAP; tool: TOOL; x,y: INTEGER; fnt: defFont.FONT;

                              fmt: ARRAY OF CHAR; SEQ arg: SYSTEM.WORD);


PROCEDURE xprint(bmd: BITMAP; tool: TOOL; x,y: INTEGER; fnt: defFont.FONT;

                              fmt: ARRAY OF CHAR; SEQ arg: SYSTEM.WORD): INTEGER;


PROCEDURE writech(bmd: BITMAP; tool: TOOL; x,y: INTEGER;

                              fnt: defFont.FONT; ch: CHAR);


END BMG.



11.5.5. Текст библиотеки Screen

DEFINITION MODULE Screen; (* Leo & nick 26-Mar-90. (c) KRONOS *)


IMPORT SYSTEM;

IMPORT defScreen;


TYPE

  STATUS = defScreen.STATUS;

  STATE = defScreen.STATE;

  COLOR = defScreen.COLOR;

  PALETTE = defScreen.PALETTE;


VAL done: BOOLEAN;

  error: INTEGER;

  state: STATE;


PROCEDURE nop;

PROCEDURE set_ldcx(x: INTEGER);

PROCEDURE set_ldcy(y: INTEGER);

PROCEDURE set_palette(p: PALETTE; from,len: INTEGER);

PROCEDURE refresh (x,y,w,h: INTEGER);

PROCEDURE refreshw(x,y,w,h: INTEGER);


PROCEDURE op(cmd: INTEGER; SEQ args: SYSTEM.WORD);


CONST

  bitmap = defScreen.bitmap;

  pelmap = defScreen.pelmap;

  other = defScreen.other;


PROCEDURE loophole(kind: INTEGER; VAR ext: SYSTEM.WORD);


PROCEDURE attach(name: ARRAY OF CHAR);

(* attach screen other then $SCR *)


END Screen.



11.5.6. Текст библиотеки Fonts

DEFINITION MODULE Fonts; (* Leo 27-Jan-91. (c) KRONOS *)


IMPORT defFont;


TYPE

  FONT = defFont.FONT;


CONST

  prop =defFont.prop;

  packed=defFont.packed;

  italic=defFont.italic;


VAL font: FONT; (* default constant font always in memory *)

  done: BOOLEAN;

  error: INTEGER;


PROCEDURE new (VAR fnt: FONT; w,h: INTEGER; f,l: CHAR; state: BITSET);

PROCEDURE dispose(VAR fnt: FONT);


PROCEDURE read (VAR fnt: FONT; file_name: ARRAY OF CHAR);

PROCEDURE write( fnt: FONT; file_name: ARRAY OF CHAR);


PROCEDURE pack (fnt: FONT); (* pack unpacked font *)

PROCEDURE unpack(fnt: FONT); (* unpack font for "dch" ussing *)


PROCEDURE copy(des: FONT; to: CHAR; sou: FONT; from: CHAR);

(* des[to]:=sou[from] *)

(* des must be previously "new" with appropriate state,f,l,w,h *)


END Fonts.



Часть 12. Подсистема Windows

Предисловие соавтора

Эта часть будет настолько сильно изменяться, что можно рассматривать ее как проект (или сигнальный вариант) описания подсистемы окон. Необходимость в таком варианте возникла хотя бы потому, что читатель не имеет иной возможности ознакомиться с текстами библиотек и комментариями к ним.

Начало работе с окнами положил Д.Кузнецов (Leo), его перу принадлежат библиотеки pmPUP, pmWnd, pmWM. Продолжил тему А.Никитин (Nick), он соавтор библиотеки Wnd, являющейся естественным развитием библиотеки pmWnd. Предполагается, что в скором времени он завершит работу над presentation manager, базирующимся на библиотеке Wnd.



12.1. Текст библиотеки pmPUP

Это было самое начало работы с окнами. Здесь реализованы так называемые POPUP-окна (окна, образующие стек - в фиксированный момент времени доступно только верхнее окно для изменения информации в нем) и операции над ними, позволяющие использовать библиотеку для изготовления Presentation Manager. Рекомедуется использовать их, если требуется не очень большое количество окон и не требуется двигать их по экрану – это будет быстро.

DEFINITION MODULE pmPUP; (* Leo 18-Jan-91. (c) KRONOS *)


IMPORT SYSTEM; (* It might be a Presentation Manager *)

IMPORT defScreen;

IMPORT defFont;

IMPORT BIO;


TYPE POPUP;

     MENU;

     DEBUG;

     ROLLER;

     DIREX;

     TEXT = DYNARR OF STRING;


VAL

    done:  BOOLEAN;

    error: INTEGER;


    pnull: POPUP;

    mnull: MENU;

    rnull: ROLLER;

    dnull: DIREX;

    gnull: DEBUG;


    black: BITSET;  (* by default two last layers of display used *)

    shadow: BITSET; (* {2,3} for 4 plane display, for example *)

    normal: BITSET;

    bright: BITSET;


    ch:      CHAR;    (* last key read from keyboard by PM *)

    time:    INTEGER; (* timeout substract time of waiting *)

    mx,my:   INTEGER; (* mouse coordinates driven by PM *)

    timeout: INTEGER;


    font:  defFont.FONT;

    sfont: defFont.FONT; (* special signs font font^.H x font^.H *)


CONST (* for sfont: (sfont generated automaticaly) *)

  empty=0c; (* empty (black) char *)

  utria=1c; (* triangle directed to up *)

  dtria=2c; (* triangle directed to down *)

  ltria=3c; (* triangle directed to left *)

  rtria=4c; (* triangle directed to right *)


PROCEDURE setplanes(shadow,normal,bright: BITSET);

PROCEDURE setcolors;


PROCEDURE pushtimeout(milisec: INTEGER);

PROCEDURE poptimeout;


---------------------------- blocks ----------------------------

                            --------


PROCEDURE block(b: defScreen.BLOCK; fill,pressed: BOOLEAN);


PROCEDURE panel(b: defScreen.BLOCK; VAR inter: defScreen.BLOCK;

                      fill,pressed: BOOLEAN);


PROCEDURE switch(b: defScreen.BLOCK; pressed: BOOLEAN);


PROCEDURE button(b: defScreen.BLOCK; pressed: BOOLEAN);


PROCEDURE inblock(x,y: INTEGER; b: defScreen.BLOCK): BOOLEAN;


PROCEDURE inblocks(x,y: INTEGER; SEQ b: defScreen.BLOCK): INTEGER;


--------------------------- messages ---------------------------

                           ----------


PROCEDURE mwait(cpdkeys: BITSET; SEQ kbkeys: CHAR);

PROCEDURE wait (SEQ kbkeys: CHAR);


PROCEDURE message( xc,yc: INTEGER; f: ARRAY OF CHAR; SEQ a: SYSTEM.WORD);

PROCEDURE perror (er,xc,yc: INTEGER; f: ARRAY OF CHAR; SEQ a: SYSTEM.WORD);


---------------------------- popups ----------------------------

                            --------


PROCEDURE pnew (VAR pup: POPUP; x,y,w,h: INTEGER);

PROCEDURE pdispose(VAR pup: POPUP);


PROCEDURE popen (pup: POPUP);

PROCEDURE pclose(pup: POPUP);


PROCEDURE pclosed(pup: POPUP): BOOLEAN;


PROCEDURE pblock (pup: POPUP; VAR block: defScreen.BLOCK);


--------------------------- dialogbox --------------------------

                           -----------


PROCEDURE diabox(xc,yc,w: INTEGER;

                 VAR str: ARRAY OF CHAR;

               promptfmt: ARRAY OF CHAR; SEQ args: SYSTEM.WORD);


PROCEDURE confirm(xc,yc,w: INTEGER;

                  VAR str: ARRAY OF CHAR;

                promptfmt: ARRAY OF CHAR; SEQ args: SYSTEM.WORD);


----------------------------- debug ----------------------------

                             -------


PROCEDURE gnew (VAR debug: DEBUG; x,y,w,h: INTEGER);

PROCEDURE gdispose(VAR debug: DEBUG);


PROCEDURE gopen (debug: DEBUG);

PROCEDURE gclose(debug: DEBUG);


PROCEDURE gprint(debug: DEBUG; fmt: ARRAY OF CHAR; SEQ args: SYSTEM.WORD);


---------------------------- rollers ---------------------------

                            ---------


CONST

  xup = {0}; xlf = {2};

  xdw = {1}; xrg = {3};


PROCEDURE rnew (VAR rol: ROLLER; x,y,w,h: INTEGER; exit: BITSET;

                 titfmt: ARRAY OF CHAR; SEQ args: SYSTEM.WORD);


PROCEDURE rdispose(VAR rol: ROLLER);

(* roller always maked with title *)


PROCEDURE rsettext(rol: ROLLER; text: TEXT; top,line: INTEGER);

(* if line<0 or top<0 (or both) automaticaly setted by internal AI *)


PROCEDURE rsetstr (rol: ROLLER; alt: INTEGER;

                   fmt: ARRAY OF CHAR; SEQ arg: SYSTEM.WORD);


PROCEDURE rgettext(rol: ROLLER; VAR text: TEXT);


PROCEDURE ropen (rol: ROLLER);

PROCEDURE rclose(rol: ROLLER);


PROCEDURE rselect (rol: ROLLER);

PROCEDURE rselected(rol: ROLLER): BOOLEAN;


PROCEDURE rchoose(rol: ROLLER; alt: INTEGER);


PROCEDURE ralt (rol: ROLLER): INTEGER;


PROCEDURE rblocks(rol: ROLLER; VAR main,txt,tit,off,up,rl,dw: defScreen.BLOCK);


----------------------------- menus ----------------------------

                             -------


PROCEDURE mnew (VAR m: MENU; x,y,w,h: INTEGER; exit: BITSET;

               titfmt: ARRAY OF CHAR; SEQ arg: SYSTEM.WORD);

PROCEDURE mdispose(VAR m: MENU);


PROCEDURE mprint(m: MENU; alt: INTEGER;

               fmt: ARRAY OF CHAR; SEQ args: SYSTEM.WORD);


PROCEDURE mread(m: MENU; alt: INTEGER; VAR s: ARRAY OF CHAR);


PROCEDURE mhotkey(m: MENU; alt: INTEGER; hotkey: CHAR; capequ: BOOLEAN);


PROCEDURE mopen (m: MENU);

PROCEDURE mclose(m: MENU);


PROCEDURE mselect (m: MENU);

PROCEDURE mselected(m: MENU): BOOLEAN;


PROCEDURE mchoose(m: MENU; alt: INTEGER);


PROCEDURE malt(m: MENU): INTEGER;


PROCEDURE mblocks(m: MENU; VAR main,txt,tit,off: defScreen.BLOCK);


----------------------------- direx ----------------------------

                             -------


CONST (* items *)

  dirs     = {0};

  files    = {1};

  hidden   = {2};

  devices  = {3};

  all      = dirs + files + hidden + devices;

  standard = dirs + files;


PROCEDURE dnew (VAR drx: DIREX; x,y,w,h: INTEGER; exit: BITSET;

                 cdname: ARRAY OF CHAR;

                pattern: ARRAY OF CHAR;

                  items: BITSET);

PROCEDURE ddispose(VAR drx: DIREX);


PROCEDURE dopen (drx: DIREX);

PROCEDURE dclose(drx: DIREX);


PROCEDURE dchoose(drx: DIREX; filename: ARRAY OF CHAR);

PROCEDURE dselect(drx: DIREX);


PROCEDURE dselected(drx: DIREX): BOOLEAN;


PROCEDURE dfilename(drx: DIREX; VAR fname: ARRAY OF CHAR);

PROCEDURE dfullname(drx: DIREX; VAR fname: ARRAY OF CHAR);

PROCEDURE dopenfile(drx: DIREX; VAR f: BIO.FILE; biomode: ARRAY OF CHAR);

PROCEDURE dcd (drx: DIREX; VAR cd: BIO.FILE);


PROCEDURE dblocks(drx: DIREX; VAR main,txt,tit,off,up,rl,dw: defScreen.BLOCK);


----------------------------------------------------------------


PROCEDURE zoom;


END pmPUP.


----------------------------------------------------------------

NOTES:

  1. "*dispose" never change "done" & "error" by itself!
  2. "*blocks" defined only after first "*open" or "*select"
ch keeps value of last key readen from Keyboard by PM (000c if none)
mx,my keep values of x- & y-coordinates of mouse cursor driven by PM.
(any panel set cursor on it "off" block at open time)
time keeps the value of the time not spended for waiting. Application may use the value timeout-time to calcuate the time spended by human for last input.

PROCEDURE setplanes(black,shadow,normal,bright: BITSET);

PROCEDURE setcolors;

-------------------

By default PM used last (leftmost or higest) 2 planes on dispay. Application may orevride this by calling "setplanes".

PM not changed screen palette, till he is asked about it by calling "setcolors". The last one set 4 gradations of grey (if it possible) for current plane combination used for colors black, shadow, normal & bright.

PROCEDURE pushfont(font: defFont.FONT);

PROCEDURE popfont;

-----------------

Changes default font for printing text in PM.

Be carefull! Current "font" linked with any "new" popup, menu, roller, direx and will be used with it as long as this object exist.

Application may push and pop fonts freely, but it will not dispose appropriate font before all object referenced to it disposed!

PROCEDURE pushtimeout(milisec: INTEGER);

PROCEDURE poptimeout;

--------------------

Changes current timeout time (in miliseconds).

This timeout will be actual for all procedures waiting mouse or keyboard input (such as "wait", "message", "perror", "select" and so on) until next push or pop call will be executed.

To prevent timeout waiting execute call "pushtimeout(-1)" or "pushtimeout(MAX(INTEGER))" (realy it will be timeout for 24 days and nights).

Application may determine that "timeout" condition was occured by testing PM.time<=0!

PROCEDURE inblock (x,y: INTEGER; b: defScreen.BLOCK): BOOLEAN;

PROCEDURE inblocks(x,y: INTEGER; SEQ b: defScreen.BLOCK): INTEGER;

------------------

"inblock" returns TRUE when x,y IN block "b".
"inblocks" returns the number of the block in wich x,y points otherwise -1.

PROCEDURE mwait(cpdkeys: BITSET; SEQ kbkeys: CHAR);

PROCEDURE wait (SEQ kbkeys: CHAR);

---------------

"mwait" Waits for one of "kbkeys" pressed on keyboard or one of "cpdkeys" pressed on mouse or timeout occured
wait(....,0c) waits any key pressed on keyboard
wait(time,{}) waits for CR or ESC
wait(time,{1,2}) waits for buttons 1 or 2 on mouse
If cpdkeys={} "mwait" do not touch mouse at all.
"wait" is equal to mwait({0..CPD.state^.nokeys-1},kbkeys);
"done" always TRUE.

PROCEDURE message(xc,yc : INTEGER; f: ARRAY OF CHAR; SEQ a: SYSTEM.WORD);

PROCEDURE perror (xc,yc,er: INTEGER; f: ARRAY OF CHAR; SEQ a: SYSTEM.WORD);

-----------------

"message"

print message (format,args) in the appropriated box with center xc,yc on the screen and waits, driving the mouse cursor, until one of the next conditions will happen:

  • timeout occured (see timeout);
  • CR of ESC pressed on the Keyboard;
  • leftmost mouse key pressed when cursor in "off" button of message panel;
  • rightmost mouse key pressed (cursor anywhere);

"perror"

is equal to sequence of calls:

Lexicon.perror(bump,er,f,a);
message(t,xc,yc,"%s",bump).

Both procedures set "done"=FALSE only when it's impossible to open appropriate window or parameters is bad. "done"=TRUE at least human press ESC or timeout happens.

PROCEDURE pclosed(pup: POPUP): BOOLEAN;

-----------------

Window opened or closed?

returns TRUE of FALSE; never change "done", "error".
returns TRUE for bad POPUP object.

NEWS


   psave

   prestore


   direx: bright for directories.


   exit keys on CPD (diabox, message e.t.c)


   block for menu N'th alt



12.2. Текст библиотеки pmWnd

Библиотека реализует механизмы работы с топологией окон и базовый набор графических примитивов над ними.

DEFINITION MODULE pmWnd; (* Leo 09-Apr-91. (c) KRONOS *)


IMPORT SYSTEM, defScreen, defFont;


TYPE

  TOOL = defScreen.TOOL;

  BLOCK = defScreen.BLOCK;

  FONT = defFont.FONT;

  WINDOW = POINTER TO WNDESC;

  PAINT = PROCEDURE (WINDOW,INTEGER,INTEGER,INTEGER,INTEGER);

  WNDESC = RECORD

             x,y   : INTEGER;

             w,h   : INTEGER;

             mode  : BITSET;

             fore  : BITSET;

             back  : BITSET;

             mask  : BITSET;

             image : BOOLEAN;

             closed: BOOLEAN;

             board : PAINT;

             paint : PAINT;

             mgr   : SYSTEM.WORD;

             obj   : SYSTEM.WORD;

             desc  : SYSTEM.WORD;

             inner : TOOL;

             full  : TOOL;

           END;


VAL done:  BOOLEAN;

  error:   INTEGER;

  scrW:    INTEGER; (* phisical screen W *)

  scrH:    INTEGER; (* phisical screen H *)

  scrM:    BITSET;  (* phisical screen Mask *)

  top:     WINDOW;

  bottom:  WINDOW;

  desktop: WINDOW;

  kind:    INTEGER;


CONST

  bitmap = 0;

  pelmap = 1;

  gamma  = 2;

  ega    = 3;

  vga    = 4;


CONST (* window modes: *)

  scr    = {0};

  img    = {1};

  deep   = {2};

  normal = scr+img;


  (* tool modes: *)


  xor    = defScreen.xor;

  or     = defScreen.or ;

  bic    = defScreen.bic;

  rep    = defScreen.rep;


PROCEDURE new (VAR wnd: WINDOW);

PROCEDURE dispose(VAR wnd: WINDOW);


PROCEDURE open (wnd: WINDOW);

PROCEDURE close (wnd: WINDOW);


PROCEDURE move (wnd: WINDOW; x,y : INTEGER);

PROCEDURE resize(wnd: WINDOW; w,h : INTEGER);

PROCEDURE mask (wnd: WINDOW; fore,back: BITSET);


PROCEDURE inner (wnd: WINDOW; x,y,w,h: INTEGER);


PROCEDURE upperthen(wnd: WINDOW; und: WINDOW): BOOLEAN;

(* TRUE iff window "wnd" upper then "und". (Note: upperthen(w,w)=FALSE!) *)


PROCEDURE ontop (wnd: WINDOW);

PROCEDURE onbottom(wnd: WINDOW);


PROCEDURE putover (wnd: WINDOW; under: WINDOW);

PROCEDURE putunder(wnd: WINDOW; over : WINDOW);


PROCEDURE refreshbox (wnd: WINDOW; x,y,w,h: INTEGER);

PROCEDURE refreshboard(wnd: WINDOW; x,y,w,h: INTEGER);

PROCEDURE refresh (wnd: WINDOW);

PROCEDURE refreshall;


PROCEDURE savebox(wnd: WINDOW; x,y,w,h: INTEGER);


PROCEDURE locate(x,y: INTEGER): WINDOW;

PROCEDURE up (wnd: WINDOW ): WINDOW;

PROCEDURE dw (wnd: WINDOW ): WINDOW;


PROCEDURE image (wnd: WINDOW; on : BOOLEAN);

PROCEDURE painter(wnd: WINDOW; paint: PAINT);

PROCEDURE boarder(wnd: WINDOW; board: PAINT);


PROCEDURE object (wnd: WINDOW; obj : SYSTEM.WORD);

PROCEDURE manager(wnd: WINDOW; mgr : SYSTEM.WORD);


----------------------------------------------------------------


PROCEDURE mode(wnd: WINDOW; mode: BITSET);


----------------------------------------------------------------


PROCEDURE erase(wnd: WINDOW);

PROCEDURE fill (wnd: WINDOW; tool: TOOL; block: BLOCK;

                  w: INTEGER; SEQ p: SYSTEM.WORD);


PROCEDURE bblt(des: WINDOW; dtool: TOOL; x,y: INTEGER;

               sou: WINDOW; stool: TOOL; blk: BLOCK);


PROCEDURE pattern(wnd: WINDOW; t: TOOL; block: BLOCK;

                  w,h: INTEGER; p: ARRAY OF SYSTEM.WORD);


PROCEDURE grid (wnd: WINDOW; t: TOOL; block: BLOCK; xstep,ystep: INTEGER);


PROCEDURE dot (wnd: WINDOW; tool: TOOL; x, y : INTEGER);

PROCEDURE line (wnd: WINDOW; tool: TOOL; x0,y0,x1,y1: INTEGER);

PROCEDURE dline (wnd: WINDOW; tool: TOOL; x0,y0,x1,y1: INTEGER; VAR r: SYSTEM.WORD);

PROCEDURE hline (wnd: WINDOW; tool: TOOL; x0,y0,x1 : INTEGER);

PROCEDURE vline (wnd: WINDOW; tool: TOOL; x0,y0,y1 : INTEGER);

PROCEDURE rect (wnd: WINDOW; tool: TOOL; x0,y0,x1,y1: INTEGER);

PROCEDURE frame (wnd: WINDOW; tool: TOOL; x0,y0,x1,y1: INTEGER);

PROCEDURE scroll(wnd: WINDOW; tool: TOOL; x,y : INTEGER);


PROCEDURE trif (wnd: WINDOW; tool: TOOL; x0,y0,x1,y1,x2,y2: INTEGER);


PROCEDURE arc (wnd: WINDOW; tool: TOOL; xc,yc,xa,ya,xb,yb,r: INTEGER);

PROCEDURE arc3 (wnd: WINDOW; tool: TOOL; x0,y0,x1,y1,x2,y2: INTEGER);


PROCEDURE ring (wnd: WINDOW; tool: TOOL; xc,yc,r0,r1: INTEGER);

PROCEDURE circle (wnd: WINDOW; tool: TOOL; x,y,r: INTEGER);

PROCEDURE circlef(wnd: WINDOW; tool: TOOL; x,y,r: INTEGER);


PROCEDURE print (wnd: WINDOW; tool: TOOL; x,y: INTEGER;

                 fnt: defFont.FONT;

                 fmt: ARRAY OF CHAR; SEQ arg: SYSTEM.WORD);


PROCEDURE xprint(wnd: WINDOW; tool: TOOL; x,y: INTEGER;

                 fnt: defFont.FONT;

                 fmt: ARRAY OF CHAR; SEQ arg: SYSTEM.WORD): INTEGER;


PROCEDURE write (wnd: WINDOW; tool: TOOL; x,y: INTEGER;

                 fnt: defFont.FONT;

                 str: ARRAY OF CHAR; pos,len: INTEGER);


PROCEDURE xwrite(wnd: WINDOW; tool: TOOL; x,y: INTEGER;

                 fnt: defFont.FONT;

                 str: ARRAY OF CHAR; pos,len: INTEGER): INTEGER;


PROCEDURE writech(wnd: WINDOW; tool: TOOL; x,y: INTEGER;

                  fnt: defFont.FONT; ch: CHAR);


PROCEDURE lenght(fnt: defFont.FONT;

                 fmt: ARRAY OF CHAR; SEQ arg: SYSTEM.WORD): INTEGER;


PROCEDURE width (fnt: defFont.FONT;

                 fmt: ARRAY OF CHAR; SEQ arg: SYSTEM.WORD): INTEGER;


PROCEDURE margin(fnt: defFont.FONT;

                 fmt: ARRAY OF CHAR; SEQ arg: SYSTEM.WORD): INTEGER;


END pmWnd.



12.3. Текст библиотеки pmWM

В интерактивных графических системах возникает необходимость в непосредственном управлении топологией оконной структуры. Библиотека реализует возможности: передвижение окон, изменение их размеров, тасование окон, добавление пользователем новых операций над окнами и связанными с ними структурами данных.

DEFINITION MODULE pmWM; (* Leo 23-Apr-91. (c) KRONOS *)


IMPORT SYSTEM, pmWnd, defFont;


TYPE WINDOW = pmWnd.WINDOW;


VAL done:  BOOLEAN;

  error:   INTEGER;


  ssfont:  defFont.FONT; (* special signs font *)


  active:  WINDOW; (* last activated window *)

  abutton: INTEGER; (* last switched button no *)


  closed:  BOOLEAN; (* active window m.b. closed *)


  moved:   BOOLEAN; (* active window m.b. moved *)

  moveX:   INTEGER; (* new coordinates for *)

  moveY:   INTEGER; (* active window *)


  resized: BOOLEAN; (* active window m.b. resized *)

  resizeW: INTEGER; (* new sizes for *)

  resizeH: INTEGER; (* active window *)


VAR

  black:  BITSET;

  shadow: BITSET;

  normal: BITSET;

  bright: BITSET;


CONST (* ssfont chars *)

  ssempty   = 00c;

  ssmove    = 01c;

  ssresize  = 02c;

  ssclose   = 03c;

  ssontop   = 04c;

  ssonbot   = 05c;

  sszoomin  = 06c;

  sszoomout = 07c;

  ssleft    = 10c;

  ssright   = 11c;

  ssup      = 12c;

  ssdw      = 13c;

  sspan     = 14c;

  sseye     = 15c;

  sszoom    = 16c;

  ssgrid    = 17c;

  sscascade = 20c;

  ssfire    = 21c;

  ssicon    = 22c;

  sstool    = 23c;


PROCEDURE new (VAR w: WINDOW);

PROCEDURE dispose(VAR w: WINDOW);


PROCEDURE enable (w: WINDOW); (* enable/disable WM control for *)

PROCEDURE disable(w: WINDOW); (* move, resize, close (default enable) *)


PROCEDURE monitor;


CONST (* corners *)

  luc = 0; ruc = 2;

  ldc = 1; rdc = 3;


PROCEDURE button (w: WINDOW; no,corner,x,y,w,h: INTEGER); (* inner sizes *)

PROCEDURE pressed(w: WINDOW; button: INTEGER): BOOLEAN;

PROCEDURE toggle (w: WINDOW; button: INTEGER; pressed: BOOLEAN);


PROCEDURE buttoncolors(w: WINDOW; no: INTEGER; fore,pressed,back: BITSET);


PROCEDURE print (w: WINDOW; button: INTEGER; font: defFont.FONT;

                            format: ARRAY OF CHAR; SEQ args: SYSTEM.WORD);


END pmWM.



12.4. Текст библиотеки Wnd

DEFINITION MODULE Wnd; (* nick 14-Dec-91. (c) KRONOS *)

(* Реализует механизмы работы с топологией окон и базовый набор графических примитивов над ними.

   От pmWnd отличается тем, что понятие окна расширено (введено понятие "подокна"), что позволяет создавать древовидные оконно-подоконные структуры.

*)


IMPORT SYSTEM, defScreen, defFont, defBMG;


TYPE

  TOOL = defScreen.TOOL;

  BLOCK = defScreen.BLOCK;

  FONT = defFont.FONT;


  WINDOW = POINTER TO WNDESC;


  PAINT = PROCEDURE (WINDOW,INTEGER,INTEGER,INTEGER,INTEGER);


  RESIZE = PROCEDURE (WINDOW,INTEGER,INTEGER);


  WNDESC = RECORD (* READ ONLY! *)

             x,y    : INTEGER; (* relative "desk" *)

             w,h    : INTEGER; (* pixels *)

             sx,sy  : INTEGER; (* relative "desktop" *)

             mode   : BITSET; (* method of drawing *)

             fore   : BITSET;

             back   : BITSET;

             mask   : BITSET;

             image  : BOOLEAN; (* has image ? *)

             closed : BOOLEAN; (* is closed now? *)

             visible: BOOLEAN; (* is visible now? *)

             tool   : TOOL; (* default tool *)

             desk   : WINDOW; (* own desktop *)

             top    : WINDOW; (* upper subwindow *)

             bottom : WINDOW; (* downer subwindow *)


             resize : RESIZE; (* pre resize action *)

             corner : INTEGER; (* resize will move it *)

             minw   : INTEGER; (* min sizes of window *)

             minh   : INTEGER;

             maxw   : INTEGER; (* max sizes of window *)

             maxh   : INTEGER;

             refresh: PAINT;

           END;


CONST (* corners: *) ruc=0; rdc=1; ldc=2; luc=3; (* default "ruc" *)


VAL done: BOOLEAN;

  error: INTEGER;


  scrW:  INTEGER; (* phisical screen W *)

  scrH:  INTEGER; (* phisical screen H *)

  scrM:  BITSET; (* phisical screen Mask *)


desktop: WINDOW;

  B:     defBMG.BITMAP;


CONST (* window modes: *)

  scr    = {0}; (* drawing on screen in "fore" layers only *)

  img    = {1}; (* drawing in image in "fore" layers only *)

  deep   = {2}; (* drawing in image and on screen in all possible layers *)

  glass  = {3}; (* drawing over subwindows *)

  whole  = {4}; (* refresh whole window after resize *)

  normal = scr+img; (* default window "mode" after create *)


  (* tool modes: *)


  xor    = defScreen.xor;

  or     = defScreen.or ;

  bic    = defScreen.bic;

  rep    = defScreen.rep;


PROCEDURE create (VAR wnd: WINDOW; desk: WINDOW; x,y,w,h: INTEGER;

                fore,back: BITSET; refresh: PAINT);


PROCEDURE dispose(VAR wnd: WINDOW);


PROCEDURE image(wnd: WINDOW; x,y,w,h: INTEGER);

(* never be called. may by used only as "create" or "painter" parameter *)


PROCEDURE painter(wnd: WINDOW; refresh: PAINT);

(* set another refresh procedure for the window.

* if "refresh" will stay to "image" then new image created

*)


PROCEDURE open (wnd: WINDOW);

PROCEDURE close (wnd: WINDOW);


PROCEDURE move (wnd: WINDOW; x,y: INTEGER);


PROCEDURE resize(wnd: WINDOW; w,h: INTEGER);


PROCEDURE moveandresize(wnd: WINDOW; x,y,w,h: INTEGER);


PROCEDURE resizer(wnd: WINDOW; resize: RESIZE);

PROCEDURE minmax (wnd: WINDOW; minW,minH,maxW,maxH: INTEGER);


PROCEDURE corner (wnd: WINDOW; corner: INTEGER);

(* only "ruc", "rdc" are implemented yet *)


PROCEDURE upperthen(wnd: WINDOW; und: WINDOW): BOOLEAN;

(* TRUE iff window "wnd" upper then "und". (Note: upperthen(w,w)=FALSE!) *)


PROCEDURE ontop (wnd: WINDOW);

PROCEDURE onbottom(wnd: WINDOW);


PROCEDURE putover (wnd: WINDOW; under: WINDOW);

PROCEDURE putunder(wnd: WINDOW; over : WINDOW);


PROCEDURE pass(wnd: WINDOW; desk: WINDOW);


PROCEDURE refreshbox(wnd: WINDOW; x,y,w,h: INTEGER);

PROCEDURE refresh (wnd: WINDOW);

PROCEDURE refreshall(wnd: WINDOW);


PROCEDURE savebox(wnd: WINDOW; x,y,w,h: INTEGER);


PROCEDURE locate(x,y: INTEGER): WINDOW;

PROCEDURE up (wnd: WINDOW ): WINDOW;

PROCEDURE dw (wnd: WINDOW ): WINDOW;


PROCEDURE assign(wnd: WINDOW; name: ARRAY OF CHAR; obj: SYSTEM.WORD);

PROCEDURE object(wnd: WINDOW; name: ARRAY OF CHAR; VAR obj: SYSTEM.WORD);

PROCEDURE delete(wnd: WINDOW; name: ARRAY OF CHAR);


PROCEDURE iterobjects(wnd: WINDOW);

PROCEDURE nextobject (wnd: WINDOW; VAR name: ARRAY OF CHAR;

                                   VAR obj : SYSTEM.WORD): BOOLEAN;


----------------------------------------------------------------


PROCEDURE mode(wnd: WINDOW; mode: BITSET);


----------------------------------------------------------------


PROCEDURE erase(wnd: WINDOW);

PROCEDURE fill (wnd: WINDOW; tool: TOOL; block: BLOCK;

                  w: INTEGER; SEQ p: SYSTEM.WORD);


PROCEDURE bblt(des: WINDOW; dtool: TOOL; x,y: INTEGER;

               sou: WINDOW; stool: TOOL; blk: BLOCK);


PROCEDURE pattern(wnd: WINDOW; t: TOOL; block: BLOCK;

                  w,h: INTEGER; p: ARRAY OF SYSTEM.WORD);


PROCEDURE grid (wnd: WINDOW; t: TOOL; block: BLOCK; xstep,ystep: INTEGER);


PROCEDURE dot    (wnd: WINDOW; tool: TOOL; x, y : INTEGER);

PROCEDURE line   (wnd: WINDOW; tool: TOOL; x0,y0,x1,y1: INTEGER);

PROCEDURE dline  (wnd: WINDOW; tool: TOOL; x0,y0,x1,y1: INTEGER; VAR r: SYSTEM.WORD);

PROCEDURE hline  (wnd: WINDOW; tool: TOOL; x0,y0,x1 : INTEGER);

PROCEDURE vline  (wnd: WINDOW; tool: TOOL; x0,y0,y1 : INTEGER);

PROCEDURE rect   (wnd: WINDOW; tool: TOOL; x0,y0,x1,y1: INTEGER);

PROCEDURE frame  (wnd: WINDOW; tool: TOOL; x0,y0,x1,y1: INTEGER);

PROCEDURE scroll (wnd: WINDOW; tool: TOOL; x,y : INTEGER);


PROCEDURE trif   (wnd: WINDOW; tool: TOOL; x0,y0,x1,y1,x2,y2: INTEGER);


PROCEDURE arc    (wnd: WINDOW; tool: TOOL; xc,yc,xa,ya,xb,yb,r: INTEGER);

PROCEDURE arc3   (wnd: WINDOW; tool: TOOL; x0,y0,x1,y1,x2,y2: INTEGER);


PROCEDURE ring   (wnd: WINDOW; tool: TOOL; xc,yc,r0,r1: INTEGER);

PROCEDURE circle (wnd: WINDOW; tool: TOOL; x,y,r: INTEGER);

PROCEDURE circlef(wnd: WINDOW; tool: TOOL; x,y,r: INTEGER);


PROCEDURE print (wnd: WINDOW; tool: TOOL; x,y: INTEGER;

                 fnt: defFont.FONT;

                 fmt: ARRAY OF CHAR; SEQ arg: SYSTEM.WORD);


PROCEDURE xprint(wnd: WINDOW; tool: TOOL; x,y: INTEGER;

                 fnt: defFont.FONT;

                 fmt: ARRAY OF CHAR; SEQ arg: SYSTEM.WORD): INTEGER;


PROCEDURE write (wnd: WINDOW; tool: TOOL; x,y: INTEGER;

                 fnt: defFont.FONT;

                 str: ARRAY OF CHAR; pos,len: INTEGER);


PROCEDURE xwrite(wnd: WINDOW; tool: TOOL; x,y: INTEGER;

                 fnt: defFont.FONT;

                 str: ARRAY OF CHAR; pos,len: INTEGER): INTEGER;


PROCEDURE writech(wnd: WINDOW; tool: TOOL; x,y: INTEGER;

                  fnt: defFont.FONT; ch: CHAR);


PROCEDURE lenght(fnt: defFont.FONT;

                 fmt: ARRAY OF CHAR; SEQ arg: SYSTEM.WORD): INTEGER;


PROCEDURE width (fnt: defFont.FONT;

                 fmt: ARRAY OF CHAR; SEQ arg: SYSTEM.WORD): INTEGER;


PROCEDURE margin(fnt: defFont.FONT;

                 fmt: ARRAY OF CHAR; SEQ arg: SYSTEM.WORD): INTEGER;


END Wnd.


(*

PROCEDURE resize(wnd: WINDOW; w,h: INTEGER);

--------------------------------------------


wnd^.resize(wnd,w,h)


called (after possible image resize and) as resize

notification before redraw.

old coordinates and sizes are still in wnd^.(sx,sy,w,h).


There are two kinds of action that may be done by

wnd^.resize according to new window size


For windows with IMAGE:

    moves and resize subwindows if need it.


    (image already resized when wnd^.resize called)


    set wnd^.mode(img) and redraw all extended rectangle of

    window (if exist). They will be refreshed later

    automaticly.


    set wnd^.mode(normal) and redraw all retained rectangles of

    window if them exist and it's needed. Mode normal need to

    refresh this rectangles because automaticly refresh of

    retained rectangle will NOT be executed.


For windows WITHOUT image:

    moves and resize subwindows if need it.

    set wnd^.mode(normal) and redraw all retained rectangles of

    window if them exist and it's needed. Mode normal need to

    refresh this rectangles because automaticly refresh of

    retained rectangle will NOT be executed.


    be ready to redraw new parts of window when wnd^.refresh

    will be called.


(0,0) coordinates still linked to left down corner of the

window after resize.


when corner =

    ruc: resize chage sizes moving right upper corner


    rdc: resize chage sizes moving right down corner


and so on


PROCEDURE moveandresize(wnd: WINDOW; x,y,w,h: INTEGER);

-------------------------------------------------------


wnd^.resize(wnd,w,h)


called (after possible image resize and) as resize

notification before redraw.

old coordinates and sizes are still in wnd^.(sx,sy,w,h).


After moveandresize whole window will de redrown automaticly.


*)



Содержание Части 1-5 Части 7-8 Части 9-11

Скачать PDF