Pular para o conteúdo

Configuração de Escala de DPI no WSL em Monitor com Densidade de Pixels Alta

O driver de vídeo no WSL (17/08/2024) não está enviando as informações do tamanho real do monitor para o Xrandr.

Isso é um problema para qualquer aplicação que possua uma GUI.

Você pode conferir uma ferramenta que fiz usando o conteúdo desse post no github: https://github.com/A-Ribeiro/wsl-hidpi-suggestion .

Contexto

Por esses dias estava programando uma ferramenta que utiliza o Xrandr para fazer uma query do tamanho do display para renderizar os componentes gráficos com a resolução correta.

O código nativo no windows e no linux funcionam corretamente.

No WSL tem essa questão.

Parece que o driver de vídeo no WSL não transfere a informação correta do tamanho dos monitores do sistema para as aplicações.

Por isso criei esses scripts que configuram a escala de DPI nas variáveis de ambiente do WSL no '~/.bashrc'.

Configuração

1) Entre no wsl e crie um arquivo com o nome '~/powershell_get_dim.ps1' e preencha com o conteúdo abaixo:

Add-Type @"
using System;
using System.Runtime.InteropServices;
public class DCOps {
    [DllImport("user32.dll")] public static extern IntPtr GetDC(IntPtr hwnd);
    [DllImport("user32.dll")] public static extern int ReleaseDC(IntPtr hwnd, IntPtr hdc);
    [DllImport("gdi32.dll")] public static extern int GetDeviceCaps(IntPtr hdc, int nIndex);

    public static int HORZSIZE = 4;
    public static int VERTSIZE = 6;
    public static int DESKTOPVERTRES = 117;
    public static int DESKTOPHORZRES = 118;
}
"@

$hdc = [DCOps]::GetDC([IntPtr]::Zero)

if ($hdc -eq [IntPtr]::Zero){
    echo "1,1,1,1"
    exit
}

$w=[DCOps]::GetDeviceCaps($hdc, [DCOps]::DESKTOPHORZRES)
$h=[DCOps]::GetDeviceCaps($hdc, [DCOps]::DESKTOPVERTRES)

$wm=[DCOps]::GetDeviceCaps($hdc, [DCOps]::HORZSIZE)
$hm=[DCOps]::GetDeviceCaps($hdc, [DCOps]::VERTSIZE)

$rc=[DCOps]::ReleaseDC([IntPtr]::Zero, $hdc)

echo "$w,$h,$wm,$hm"

Esse script pega o monitor padrão do windows e retorna a resolução atual em pixels e em milímetros.

2) Agora crie um arquivo '~/_new_set_dpi_scale_from_win32.sh' com o conteúdo abaixo:

#!/bin/sh

f_dpi_scale() {

    local dpi_scale powershell_script MainDisplayInfo dpi_100_percent

    # the notation ${<item1>:-<item2>}
    #    is similar to <item1> or <item2>, if <item1> is not defined
    dpi_scale="${GDK_DPI_SCALE:-${QT_SCALE_FACTOR:-${GTK_SCALE:-${GDK_SCALE:-}}}}"

    if [[ -z "${dpi_scale:-}" ]] ; then
        powershell_script=`cat ~/powershell_get_dim.ps1`
        MainDisplayInfo=$("/mnt/c/Windows/System32/WindowsPowerShell/v1.0/powershell.exe" "$powershell_script")
        # set -f # avoid globbing (expansion of *).
        # array=(${MainDisplayInfo//,/ })
        # array=(`echo $MainDisplayInfo | sed 's/,/\n/g'`)
        array=(`echo $MainDisplayInfo | tr ',' '\n'`)
        w=${array[0]} # width in px
        h=${array[1]} # height in px
        wm=${array[2]} # width in mm
        hm=${array[3]} # height in mm

        dpi_100_percent=$(bc <<<"scale=6; $w / ($wm / 25.4)")
        dpi_scale=$(bc <<<"scale=6; ($w * 25.4) / ($wm * 96) ")

        export GDK_SCALE=${GDK_SCALE:-$dpi_scale}
        export GDK_DPI_SCALE=${GDK_DPI_SCALE:-$dpi_scale}
        export GTK_SCALE=${GTK_SCALE:-$dpi_scale}

        # https://doc.qt.io/qt-5/highdpi.html
        # export QT_AUTO_SCREEN_SCALE_FACTOR=${QT_AUTO_SCREEN_SCALE_FACTOR:-1}
        # export QT_ENABLE_HIGHDPI_SCALING=${QT_ENABLE_HIGHDPI_SCALING:-1}
        export QT_SCALE_FACTOR=${QT_SCALE_FACTOR:-$dpi_scale}

        echo "DPI scale info:"
        echo " - Main size"
        echo "     (px): ${w}x${h}"
        echo "     (mm): ${wm}x${hm}"
        echo "     (DPI-100%): ${dpi_100_percent} DPI"
        echo " - Scale set to: $dpi_scale"

    fi
}

# if dir runtime-dir exists, then ...
[ -d /mnt/wslg/runtime-dir ] && f_dpi_scale

Esse script basicamente executa nosso script em powershell e no final configura as variáveis no sistema: GDK_SCALE, GDK_DPI_SCALE, GTK_SCALE e QT_SCALE_FACTOR.

3) Por fim, abra o seu arquivo '~/.bashrc' e acrescente a seguinte linha de código:

# ...

. ~/_new_set_dpi_scale_from_win32.sh

Pronto

Agora é só entrar no WSL e testar as aplicações de GUI.

Obs.: Essa configuração só tem efeito nas aplicações que utilizam alguma dessas variáveis de ambiente que acabamos de configurar.

Espero que tenham gostado do conteúdo.

abraços,

Alessandro Ribeiro

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *