Como posso detectar quando um monitor está conectado ou desconectado?

53

Existe algum evento acionado quando conecto ou retiro um monitor externo na DisplayPort do meu laptop? ACPID e UDEV não reagem de maneira alguma.

Estou usando gráficos integrados em um chip intel. Aqui está uma discussão semelhante, que já tem alguns anos.

Não quero usar o polling, mas preciso ter algumas configurações que definam as configurações do monitor automaticamente, dependendo de o monitor estar conectado.

janoliver
fonte
4
Isso pode ser feito com o udev. Qual é a sua versão do kernel? Você está usando o KMS (configuração do modo kernel)?
Andy
Obrigado pela resposta. Não tenho certeza sobre o KMS, mas, como disse na pergunta, o udev não envia nenhum evento. ( udevadm monitor --property não reage de todo)
janoliver 25/05
@ Andy: a última vez que isso surgiu , parecia que a maioria dos sistemas exigia pesquisas. Se você encontrou uma maneira de acionar um evento udev, poderia responder a essa pergunta?
Gilles 'SO- stop be evil'
11
Finalmente consegui rodar o carregamento do i915 como módulo do kernel.
Janoliver 29/05
3
Você pode usar o xrandr ou o disper para detectar se o monitor externo foi conectado. Github.com/wertarbyte/autorandr pode mostrar como usá-los. Mas xrandr / disper pode não ser compatível com sua placa de vídeo.
Number5

Respostas:

13

NOTA: Isso foi testado em um laptop com uma placa gráfica i915.


fundo

NOTA: Quando uma nova tela é conectada, nenhum evento é enviado ao host, isso permanece verdadeiro mesmo após a minha última edição. Portanto, a única maneira é usar a pesquisa. Tentando torná-los o mais eficiente possível ...

EDIT # 3

Finalmente, há uma solução melhor (por meio da ACPI):

Ainda não há evento, mas a ACPI parece mais eficiente do xrandrque perguntar. (Nota: isso requer módulos do kernel ACPI carregados, mas não requer privilégios de root).

Minha solução final (usando o bash):

isVgaConnected() {
    local crtState
    read -a < /proc/acpi/video/VID/CRT0/state crtState
    test $(( ( ${crtState[1]} >>4 ) ${1:+*-1+1} )) -ne 0
}

Agora um teste:

$ if isVgaConnected; then echo yes; else echo no; fi 
yes

Está conectado, então agora eu desconecto:

$ if isVgaConnected; then echo yes; else echo no; fi 
no

NOTA: ${1:+*-1+1} permitir um boolean argumento: Se algo está presente , a resposta seria invertido: ( crtState >> 4 ) * -1 + 1.

e o script final:

#!/bin/bash

export crtProcEntry=/proc/acpi/video/VID/CRT0/state

isVgaConnected() {
    local crtState
    read -a < $crtProcEntry crtState
    test $(( ( ${crtState[1]} >>4 ) ${1:+*-1+1} )) -ne 0
}

delay=.1
unset switch
isVgaConnected || switch=not
while :;do
    while isVgaConnected $switch;do
        sleep $delay
      done
    if [ "$switch" ];then
        unset switch
        echo VGA IS connected
        # doing something while VGA is connected
      else
        switch=not
        echo VGA is NOT connected.
        # doing something else, maybe.
      fi
  done

Avisos: mais leve que xrandr, mas não sem importância, com um atraso menor que 0,02 segundos, o script Bash irá para o topo do processo de obtenção de recursos ( top)!

Enquanto isso custa ~ 0,001 seg:

$ time read -a </proc/stat crtStat

Isso requer ~ 0,030 seg:

$ read -a < /proc/acpi/video/VID/CRT0/state crtState

Isso é grande! Portanto, dependendo do que você precisa, delaypode ser razoavelmente definido entre 0.5e 2.

EDIT # 2

Finalmente encontrei algo usando este:

Isenção de responsabilidade importante: Brincar com /proce /sysentradas pode danificar seu sistema !!! Portanto, não tente o seguinte em sistemas de produção.

mapfile watchFileList < <(
    find /sys /proc -type f 2>/dev/null |
    grep -i acpi\\\|i91 
)

prompt=("/" "|" '\' '-');

l=0
while :; do
  mapfile watchStat < <(
    grep -H . ${watchFileList[@]} 2>/dev/null
  )

  for ((i=0;i<=${#watchStat[@]};i++)); do
    [ "${watchStat[i]}" == "${oldStat[i]}" ] || echo ${watchStat[i]}
  done

  oldStat=("${watchStat[@]}")
  sleep .5
  printf "\r%s\r" ${prompt[l++]}
  [ $l -eq 4 ]&&l=0
done

... após alguma limpeza de entradas indesejadas:

for ((i=0;i<=${#watchFileList[@]};i++)); do
  [[ "${watchFileList[$i]}" =~ /sys/firmware/acpi/interrupts/sci ]] &&
      unset watchFileList[$i] && echo $i
done

Eu pude ler isto:

/proc/acpi/video/VID/CRT0/state:state: 0x1d
/proc/acpi/video/VID/CRT0/state:state: 0x0d
/proc/acpi/video/VID/CRT0/state:state: 0x1d

Quando conecto, desconecto e conecto o cabo do monitor.

Resposta original

Quando a configuração é consultada (em execução system/preferences/monitorou xrandr), as placas gráficas fazem um tipo de verificação ; portanto, a execução xrandr -qfornece as informações, mas você precisa pesquisar o status.

Examinei todos os logs (kernel, daemon, X e assim por diante) pesquisando /proc& /sys, e claramente parece que não existe nada que satisfaça sua solicitação.

Eu tentei isso também:

export spc50="$(printf "%50s" "")"
watch -n1  '
    find /proc/acpi/video -type f |
        xargs grep -H . |
        sed "s/^\([^:]*):/\1'$spc50'}:/;
             s/^\(.\{50\}\) *:/\1 /"'

Depois de tudo isso, se você executar System/Preferences/Monitorenquanto nenhuma nova tela foi conectada ou desconectada, a ferramenta aparecerá simplesmente (normalmente). Mas se você conectou ou desconectou uma tela antes, às vezes você executa esta ferramenta e vê sua área de trabalho fazendo um tipo de redefinição ou atualização (o mesmo se você executar xrandr).

Isso parece confirmar que essa ferramenta solicita xrandr(ou funciona da mesma maneira) pesquisando o status periodicamente, começando no momento em que é executada.

Você pode tentar:

$ for ((i=10;i--;)); do xrandr -q | grep ' connected' | wc -l; sleep 1; done
1
1
1
2
2
2
1
1
1
1

Isso exibirá quantas telas (monitores) estão conectadas por 10 segundos.

Enquanto isso estiver funcionando, conecte e / ou desconecte sua tela / monitor e veja o que está acontecendo. Então você pode criar uma pequena função de teste do Bash:

isVgaConnected() {
    local xRandr=$(xrandr -q)
    [ "$xRandr" == "${xRandr#*VGA1 con}" ] || return 0
    return 1
}

que seria utilizável como em:

$ if isVgaConnected; then echo yes; fi

Mas tenha cuidado, xrandrleva de 0,140 a 0,200 s enquanto nenhuma alteração ocorre nos plugues e até 0,700 segundos sempre que algo foi conectado ou desconectado pouco antes ( NOTA: parece não ser um consumidor de recursos).

EDIT # 1

Para garantir que não estou ensinando algo incorreto, pesquisei na Web e nos documentos, mas não encontrei nada sobre DBus e telas .

Finalmente, corri em duas janelas diferentes dbus-monitor --system(também brinquei com opções) e o pequeno script que escrevi:

$ for ((i=1000;i--;)); do isVgaConnected && echo yes || echo no; sleep .5; done

... e novamente conectado, depois de desconectado o monitor, muitas vezes. Então agora eu poderia dizer:

  • Nesta configuração, usando o driver i915 , não há outra maneira senão executar xrandr -qpara saber se um monitor está conectado ou não.

Mas tenha cuidado, porque não parece haver outras maneiras. Por exemplo, xrandrparece compartilhar essas informações, então minha área de trabalho do GNOME mudaria para xineramaautomaticamente ... quando eu corriaxrandr .

Alguns documentos

F. Hauri
fonte
4

As seguintes linhas apareceram em udevadm monitor

KERNEL[46578.184280] change   /devices/pci0000:00/0000:00:02.0/drm/card0 (drm)
UDEV  [46578.195887] change   /devices/pci0000:00/0000:00:02.0/drm/card0 (drm)

ao conectar um monitor ao conector VGA. Portanto, pode haver uma maneira de descobrir isso.

sebastianwagner
fonte
Com uma nVidia 9800 GT e drivers proprietários, o monitor udevadm não mostra nada quando eu conecto um monitor HDMI. Que hardware / drivers você está usando?
frankster
Infelizmente, isso não funciona de maneira confiável para mim. Às vezes, recebo essas mensagens de evento quando conecto meu monitor e às vezes não.
Tobias
3

Para quem, por qualquer motivo, não quiser seguir a rota de hotplug, ainda é possível não pesquisar em um script usando o inotifywait:

#! / bin / bash

SCREEN_LEFT = DP2
SCREEN_RIGHT = eDP1
START_DELAY = 5

renice +19 $$> / dev / null

dormir $ START_DELAY

OLD_DUAL = "fictício"

enquanto [1]; Faz
    DUAL = $ (cat / sys / class / drm / card0-DP-2 / status)

    if ["$ OLD_DUAL"! = "$ DUAL"]; então
        se ["$ DUAL" == "conectado"]; então
            eco 'Configuração do monitor duplo'
            xrandr - saída $ SCREEN_LEFT - automático - rotação normal --pos 0x0 - saída $ SCREEN_RIGHT - automático - rotação normal - abaixo $ SCREEN_LEFT
        outro
            eco 'Configuração de monitor único'
            xrandr --auto
        fi

        OLD_DUAL = "$ DUAL"
    fi

    inotifywait -q -e close / sys / class / drm / card0-DP-2 / status> / dev / null
feito

É melhor invocado a partir do seu .xsessionrc, sem esquecer o final &. A pesquisa com o xrandr causou sérios problemas de usabilidade no meu novo laptop (o mouse parava periodicamente).

Balzola
fonte
Eu não teria pensado que você pode usar inotify on /proce apenas fazendo inotifywait -q -e close /sys/class/drm/card0-DP-2/status de fato não terminou após desconectar DP-2 no meu sistema
nhed
3

Eu continuei usando srandrd . Ele monitora X eventos e aciona seu script quando um monitor é conectado ou desconectado.

scorpp
fonte
0

Obviamente deve haver algo! :) / sys filesystem informa ao espaço de usuário que hardware está disponível, para que ferramentas do espaço de usuário (como udev ou mdev) possam preencher dinamicamente um diretório "/ dev" com nós de dispositivo que representam o hardware atualmente disponível. O Linux fornece duas interfaces de hotplug: / sbin / hotplug e netlink.

Há uma pequena demonstração C no arquivo a seguir. http://www.kernel.org/doc/pending/hotplug.txt

roncsak
fonte
0

Atualmente, o software de sistema / aplicativo no Linux atualmente utiliza algumas técnicas de ipc para comunicação entre si. O D-Bus agora é usado principalmente com aplicativos GNOME e pode ajudar.

Diário do Linux:

O D-BUS pode facilitar o envio de eventos ou sinais através do sistema, permitindo que diferentes componentes do sistema se comuniquem e, finalmente, se integrem melhor. Por exemplo, um daemon Bluetooth pode enviar um sinal de chamada que seu music player pode interceptar, silenciando o volume até o término da chamada.

wiki:

O D-Bus fornece um daemon do sistema (para eventos como "novo dispositivo de hardware adicionado" ou "fila da impressora alterada") e um daemon por sessão de login do usuário (para necessidades gerais de comunicação entre processos entre aplicativos do usuário)

Existe até uma biblioteca Python para isso, e o ubuntu recentemente usou essa habilidade chamada " zeitgeist ".

Amir Naghizadeh
fonte
-6

Graficamente, você pode ver se o monitor é reconhecido Monitor, eu sei que você pode encontrar isso no Ubuntu, Fedora e outros neste (ou em um local semelhante).

Sistema / Preferências / Monitor

E você pode ligar / desligar qualquer monitor que desejar ou usar ao mesmo tempo com imagem duplicada no monitor ou em monitores independentes

Bruce_Warrior
fonte
2
Ele pediu um evento que é acionado quando um monitor é conectado / desconectado
Michael Mrozek
Você olhou aqui? stackoverflow.com/questions/5469828/…
Satish