Systemicus чаcть 2: GUI



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


    Общие итоги


    Как и обещал в прошлой теме нашел тонкое место (точнее места) в производительности — ими оказались планировщик (циклический) и ошибка двойной перерисовки всех окон.
    Анти-итогом стала проблема размера исполняемого файла оболочки (explorer.exe). Я надеялся вместить весь код оболочки в одну секцию PE (4096 байт), но пока этого не получилось. Секция кода на данный момент составляет 4800 байт (сам файлик весит почти 10 Кб :-( ). Возможно, в будущем удастся немного сократить размер, но т.к. в оболочке многое еще нужно будет добавить, то размер explorer.exe может достигнуть даже 16 килобайт.

    Принцип работы


    Сразу отмечу, что скупой платит дважды. Из-за моего желания сэкономить лишних килобайт оперативной памяти, я изначально отклонил путь создания байтовой маски экрана (где каждому пикселю соответствует байт с номером окна [окон предусмотрено до 256]). И проблема не только в экономии памяти, но и в экономии ресурсов процессора, ведь в отсутствии данной технологии нету необходимости перед выводом каждого пикселя экрана проверять его принадлежность к определенному окну. Но… когда дело дошло до клиппинга (т.е. отрисовки только части окна, которое лежит под другим окном) я понял, как глубоко ошибся. Благо было бы, если рисуемое окно лежит только под одним окошком — там клиппинг можно вычислить — всего-то прямоугольная область. А что делать, если рисуемое окно перекрывают самым непотребным образом сразу несколько других окон и рисуемая область оказывается весьма причудливой формы?
    В общем, вернулся назад и ввел байтовую маску экрана. Расход памяти увеличился, зато уменьшилось количество кода (вычислять стало легче, хотя это не значит, что повысилась скорость).

    Итак, всё просто до безобразия. Есть байтовая маска экрана, где каждому пикселю присваивается нулевое значение либо иное, если точка принадлежит окну. Есть структура окон, она у меня такого вида:

    WNDLIST_ITEM:
       .handle      dd 0   ; +00
       .x           dd 0   ; +04
       .y           dd 0   ; +08
       .width       dd 0   ; +12
       .height      dd 0   ; +16
       .flags       dd 0   ; +20
       .rsrc        dd 0   ; +24
       .parent      dd 0   ; +28
       .wbmp        dd 0   ; +32
       .caption     dd 0   ; +36
       ; if DESKTOP: db Leftbuttonstate  ; +36
       ;             db RightButtonState ; +37
       ;             dw reserved         ; +38
       .clickx      dw 0   ; +40
       .clicky      dw 0   ; +42
       .winstyle    dd 0
                    db 16 dup 0   
    

    Значения parent и winstyle оказались неиспользуемыми и потому зарезервированными (как и 16 байт после). Имея эти данные мы можем построить окно в скрытом буфере wbmp (технология двойной буферизации). В целях экономии памяти в буфере всё рисуется 8-битным цветом (пока используется только 16), т.е. 1 байт на точку, а при выводе на экран этот цвет преобразуется в 24/32-разрядный при помощи таблицы сопоставления значений цветов.

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

    Теперь об элементах окна. Для всех элементов всех окон существует всего одна общая глобальная таблица элементов, каждый элемент которой содержит ссылку на окно (1 байт, т.к. окон всего 256 максимум), позиция относительно окна и размеры элемента (по 2 байта), байт состояния и 2 двойных слова — ссылка (на текст, например для кнопок или другая инофрмация для других элементов) и extras (иконка для кнопки или другие данные в зависимости от типа элемента). Байт состояния: младшие 4 бита указывают на тип элемента (кнопка, чекбокс, текстовое поле и т.п.), старшие на его состояние (активен ли, hover).

    Главный процесс explorer'а получает событие от драйвера мышки. Что происходит: по координатам указателя ищется окно. Окну передается параметры указателя, а именно нажата ли клавиша, если нажата, то это нажатие или отпускание клавиши. При нажатии вначале активизируем окно, т.е. делаем его активным и перерисовываем на переднем плане. Далее по глобальной таблице элементов ищем все элементы, принадлежащие окну, а среди них — подпадающие под координаты мышки. Если нашли, то в соответствии с параметрами указателя мышки обрабатываем (рисуем, перерисовываем и т.п.).
    Если же указатель находится вне окон, то это событие также обрабатывается. В данном случае, если нажат клавиша на рабочем столе, а меню Пуск открыто — то нужно его закрыть. В дальнейшем эти события нужны будут для создания ярлыков и других функций рабочего стола.

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

    План на ближайшее будущее


    В текущей реализации осталось много проблем, в частности, иногда появляются ошибки при отрисовке курсора мышки после клика по рабочему столу — копия курсора остается на столе)) Есть и некоторые другие проблемы, впрочем небольшие.
    Из важного — полноценный элемент textarea с прокруткой текста, взаимосвязь радиокнопок одного имени (т.е. включение только одной кнопки в один момент времени для группы radiobuttons). Это из сложностей. Интересной, но не очень трудной задачей остается привязка приложений к их окнам, т.к. сейчас это всё тестовые окна, выводимые самой оболочкой.

    Есть идея реализации терминала созданием окна и копированием в него содержимого из адреса 0xB8000 (естественно, превращая каждый символ в площадь пикселей 8*16).

    А далее — портирование пары-тройки приложений, в первую очередь fasmw, какой-нибудь маленькой игрушки и, наверное, калькулятора. После чего отпишусь уважаемому хабрасообществу.

    И напоследок небольшое видео. Нету, видео не выложу, т.к. CamStudio очень затормаживает Qemu. Выкладываю образ для запуска Qemu. Выбирайте Partition 2, режим любой, но а 640*480 есть небольшая проблема с фоном) И не ругайте, это АЛЬФА… много багов. Ругать будете за бета-версию :-) Также, прошу прощения за стиль и ошибки (если есть), уже глубокая ночь…

    Ссылка на файл: http://nebka.ru/files/647-0.02_qemu.7z

    Similar posts

    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More
    Ads

    Comments 20

      +1
      Не думали участвовать со своими наработками в конкурсе Intel Make It Wearable?
        +3
        да куда мне))) засмеют ведь)
        +17
        На Windows 7 (64битной) архив не запустился, жаловался на отсутствие kqemu. Решил очень лениво — просто скачал другую версию qemu и распаковал поверх в папку «qemu».

        Сделал небольшое видео за автора, в 800x600 (т.к. в 640x480 автор говорил, что есть проблема с фоном). Для записи использовал давно и честно купленный Bandicam (не реклама, просто удобная штука), при записи в MPEG1 с максимальным качеством просадки производительности на моей машинке нет. Плата за скорость и удобство — небольшая нечёткость картинки, на которое накладываются ограничения по формату ютуба…

          +1
          спасибо огромное!)
            +3
            Начиная с 38 секунды (примерно) после клика на заголовок можно увидеть неперерисованную область серого цвета, что за эффект?

            И как человек, который испытал многие трудности разработки GUI фреймворка с нуля, хочу спросить автора о тех непростых вещах, которыми столкнулся, вот некоторые из них:
            — Модальные окна (+ дефолтные кнопки и реакция на клавиатуру)
            — Всплывающие меню
            — Диспетчеризация событий в тот момент, когда показаны модальные или всплывающие окна (WS_POPUP, я думаю Вы поймете, о чем речь, если во многом копируете Windows)

            Планируете реализовывать?

              +2
              область — это из той же области, что и остатки курсора на раб. столе — всё это возникло после того, как переписал часть кода (в статье про переход на байтовую карту) и что-то задел где-то, пока не выловил что именно((

              всплывающие меню — однозначно буду делать, в одну из первых очередей (только в отличии от меню пуск, постараюсь сделать меню элементом, а не отдельным псевдоокном… хотя это естественно, так и должно быть))) просто мысли вслух).
              про п.1 и п.3 — пока нет, сначала доделаю всё остальное по GUI, потом будут и модальные окна, т.к. думаю это не первоочередная задача…

              вообще, хотелось бы такую GUI как у SolOS… драйверов там нету — чистый VESA, а скорость работы поражает… притом даже полупрозрачность окон есть… из самописных осей (включая коллективную MenuetOS) это самая быстрая GUI из тех, что я видел…
            +6
            поможет кому-нибудь в разработке своей GUI
            надеялся вместить весь код оболочки в одну секцию PE (4096 байт)
            ._.
              –5
              Учитывая количество процессорных архитектур в наше время объясните, пожалуйста, зачем затевать разработку на ассемблере, заранее обрекая проект на непереносимость? Или я что-то пропустил с тех пор, как всерьез ассемблером интересовался (т.е. за пару десятков лет)?
                +8
                Мне кажется этот проект для саморазвития.
                  +2
                  это точно)
                  0
                  всегда пугали этим, но Intel уже начала поход даже на мобильные архитектуры. единственно — это отличие от x64, но на нее портировать с x86 не особо сложно… да в принципе x64 это только надстройка над 86-й, так что и портировать не надо.
                  0
                  Во всём этом смущает завязка на PE. Если делаете своё, делайте на чём-то свободном. Например, на горизонте wayland. Или, даже, начхав на wayland, свой собственный метод отрисовки, наподобие framebuffer.
                    0
                    так отрисовка и так своя, а код можно запихнуть хоть в ELF при желании, просто мне удобнее работать с PE-EXE…
                      +1
                      Тем паче должно быть интересно поиграться с fb. Эта штука встроена в ядро линукса и даже содержит очень артефактный и примитивный window manager, точнее, деление экрана на области вывода.

                      Если к этому написать очень маленькое и лёгкое графическое окружение, то у него может даже оказаться осмысленная область применения.
                        +1
                        Во, только подумал о том, что сейчас и наступает тот момент, когда нужно принять архитектурное решение. Я бы разделил GUI на аналог GDI, работающий с областями экрана, не зная об их содержимом, и графическую библиотеку, занимающуюся отрисовкой и обеспечением логики оконных элементов GUI.
                      +1
                      PE — это формат объектных файлов. От него не зависит абсолютно ничего, кроме загрузчика.
                        +1
                        … И библиотек, с которыми линкуется, не?
                          +2
                          Да, но эти библиотеки на PE не завязаны никаким местом. Если скомпилировать в PE — будет PE. Скомпилировать ELF — будет ELF. Скомпилировать в IBM Object deck — будет стопка перфокарт (шутка, x86-64 не поддерживается, но вообще это самый удобный из известных мне форматов).
                      +1
                      У вас сервер не отдает MIME. И еще: не надо вкладывать в каждый архив QEMU для Windows. Все-таки есть и другие ОС. Лучше давайте ссылку на сборки — кому надо, тот скачает.
                        0
                        Почему-то мышка не выходит из левого нижнего квадрата. По-моему, границы экрана обрабатываются некорректно.

                        Only users with full accounts can post comments. Log in, please.