26 июля 2007

Screen DPI in Vista

В Windows есть замечательная возможность - можно вручную указать DPI экрана. Приложения автоматически будут учитывать этот параметр, если используют "правильный" mapping mode, или учитывают этот параметр вручную через вызов GetDeviceCaps(ScreenDC, LOGPIXELSX / LOGPIXELSY) для режима MM_TEXT.

Видимо далеко не все разработчики учитывали DPI в режиме MM_TEXT (а этот режим используется по умолчанию), поэтому в Висте появился новый режим работы при увеличенном DPI (старый назвали XP style DPI scaling):



В этом режиме (когда указанная галочка снята) Виста полагает, что если приложение явно не сообщило, что оно умеет работать с разными dpi, то значит оно масштабировать нифига не умеет. И Виста будет делать это масштабирование насильно.

В моем текущем проекте весь GUI самописный и в нем с самого начала заложена поддержка различных dpi, т.к. значительная часть пользователей сидит на "крупных шрифтах" (они же 120dpi). Поэтому мне стало очень интересно, как будет выглядеть наше приложение в этом новом режиме. Так как никаких вызовов SetProcessDPIAware() и пометок в манифесте по поводу dpiAware нет, то Виста должна принять нас за лохов и применить добавочное масштабирование, что в сумме с заложенной в нашем GUI логикой в итоге должно дать двойное масштабирование. Однако этого не произошло - все выглядит как в XP. Довольно странно...

Полезная статья на эту тему: DPI-aware applications in Windows Vista. В частности, там указывается, что при собственноручной отрисовке иконок можно выбрать наиболее подходящий размер иконки из доступных:
// images available in sizes 16x16, 20x20, and 24x24
int nToolbarImageSize = (16*fScale+0.5f) >= 24 ? 24 : ((16*fScale+0.5f) >= 20 ? 20 : 16);
Идея очень правильная, так как при точном масштабировании иконки получаются довольно кривыми, поэтому достаточно выбрать наиболее близкую по размеру и отрисовать ее 1:1. Однако, не стоит это делать приведенным выше методом, гораздо разумнее положить все доступные размеры в контейнер и воспользоваться алгоритмом std::lower_bound.

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

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