четверг, 29 ноября 2012 г.

Закрашивание полей в linux консоли - баг или фича?

Пока разбирался с Powerline в linux консоли, обнаружил весьма интересный и поучительный баг. Поучительный - потому что пришлось просмотреть исходный код сразу четырех компонентов - плагина Powerline, vim, эмулятора видеотерминала и framebuffer драйвера в ядре linux. Баг проявляется при переключении между виртуальными консолями (в т.ч. графической) и заключается в закрашивании одного из полей монитора каким-либо цветом. На этой картинке цветная полоса находится внизу. Как это воспроизвести: запустите vim в консоли, но таким образом, чтобы сразу появлялась цветная статусная строка, для этого в $HOME/.vimrc должна присутствовать строка
set laststatus=2
Затем сразу же переключитесь в другую консоль и обратно - вы получите полосу, закрашенную цветом статусной строки в одном из полей консоли. Если теперь вы закроете vim и снова переключитесь в другую консоль и обратно, то цветная полоса уйдет.

Сначала я подумал, что во всем виноваты Powerline или vim, но потом до меня дошло, что user space программа не может быть виновна в закрашивании области, которая ей даже не доступна! Значит проблема в ядре, в частности в эмуляторе видеотерминала или драйвере фреймбуфера. В подтверждение этому - следующий эксперимент.

Запустите в консоли любую псевдографическую программу, например в своей системе я нашел программу system-config-firewall-tui. Программа переведет консоль в псевдографический режим с синим полем и тремя кнопками (одна из них - Отмена, так что ничего страшного после ее запуска не не произойдет). Внимательно посмотрите на края монитора. Теперь переключитесь в другую консоль и обратно. Количество синего увеличилось, не так ли? Закройте программу и нажмите несколько раз Enter чтобы добавить черного цвета снизу. Видите точно такую же полосу, как в vim, только синего цвета? Еще одно переключение туда-обратно сотрет ее.

Изучение кода ядра вскрыло проблему. Оказывается, при переключении консоли в функции fbcon_switch() (см. drivers/video/console/fbcon.c) вызывается функция fbcon_clear_margins(), которая вызывает метод ops->clear_margins(), который, в свою очередь, закрашивает поля (margins, но как правило, это одно поле) цветом vc->vc_video_erase_char (см. функцию ud_clear_margins() в drivers/video/console/fbcon_ud.c и подобные им в других подобных файлах, которые в свою очередь вызывают функцию attr_col_ec() из drivers/video/console/fbcon.h). Проблема в том, что цвет  vc->vc_video_erase_char в псевдографике может зависеть от погоды и расположения звезд.

Зачем это сделано? Как я понял, некоторые режимы фреймбуфера могут использовать поля монитора, и при переключении в другую консоль эти поля нужно очищать, чтобы не наблюдать все время, например, кусок застывшего видео сбоку или снизу. Как очищать, каким цветом? В интернете я нашел патч, написанный еще в 2003 году, в котором предлагалось закрашивать поля черным цветом (см. здесь и здесь), однако, как я понял из дискуссии, использовать черный цвет не всегда правильно, поскольку графические дисплеи могут быть разные. Таким образом, закрашивание цветом erase char - это меньшее из зол.

Комментариев нет:

Отправить комментарий