¿Cómo puedo detectar cuando un monitor está enchufado o desenchufado?

53

¿Hay algún evento que se active cuando conecto o desconecto un monitor externo en el DisplayPort de mi computadora portátil? ACPID y UDEV no reaccionan en absoluto.

Estoy usando gráficos integrados en un chip Intel. Aquí hay una discusión similar que ya tiene un par de años.

No quiero usar el sondeo, pero necesito tener alguna configuración que establezca la configuración de la pantalla automáticamente, dependiendo de si la pantalla está conectada.

janoliver
fuente
44
Se puede hacer con udev. ¿Cuál es tu versión de kernel? ¿Estás usando KMS (configuración del modo kernel)?
Andy
Gracias por la respuesta. No estoy seguro acerca de KMS, pero como dije en la pregunta, udev no envía ningún evento. ( monitor udevadm : la propiedad no reacciona en absoluto)
enero
@Andy: la última vez que esto ocurrió , parecía que la mayoría de los sistemas requerían sondeo. Si ha encontrado una manera de desencadenar un evento udev, ¿podría responder esa pregunta?
Gilles 'SO- deja de ser malvado'
1
Finalmente lo ejecuté cargando i915 como módulo de kernel.
enero
3
Puede usar xrandr o disper para detectar si se ha conectado un monitor externo. Github.com/wertarbyte/autorandr puede mostrarle cómo usarlos. Pero xrandr / disper podría no ser compatible con su tarjeta de video.
número5

Respuestas:

13

NOTA: Esto se probó en una computadora portátil con una tarjeta gráfica impulsada por i915.


Antecedentes

NOTA: Cuando se conecta una nueva pantalla, no se envía ningún evento al host, esto se mantuvo incluso después de mi última edición. Entonces, la única forma es usar encuestas. Tratando de hacerlos lo más eficientes posible ...

EDITAR # 3

Finalmente hay una mejor solución (a través de ACPI):

Todavía no hay ningún evento, pero ACPI parece más eficiente que xrandrpreguntar. (Nota: Esto requiere que se carguen los módulos del núcleo ACPI, pero no requiere privilegios de root).

Mi solución final (usando bash):

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

Ahora una prueba:

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

Está enchufado, así que ahora lo desconecto:

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

NOTA: ${1:+*-1+1} permite que un booleano argumento: si algo está presente , se invierte la respuesta: ( crtState >> 4 ) * -1 + 1.

y el guión 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

ADVERTENCIAS: más ligero xrandr, pero no sin importancia con un retraso menor a 0.02 segundos, ¡el script Bash irá a la parte superior del proceso de comedores de recursos ( top)!

Si bien esto cuesta ~ 0.001 segundos:

$ time read -a </proc/stat crtStat

Esto requiere ~ 0.030 segundos:

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

¡Esto es grande! Entonces, dependiendo de lo que necesite, delaypodría establecerse razonablemente entre 0.5y 2.

EDITAR # 2

Finalmente encontré algo, usando esto:

Descargo de responsabilidad importante: ¡ Jugar con /procy /sysentradas podría dañar su sistema! Así que no intentes lo siguiente en sistemas de producción.

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

... después de una limpieza de entradas no deseadas:

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

He podido leer esto:

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

Cuando conecto, desconecto y vuelvo a enchufar el cable del monitor.

Respuesta original

Cuando se consulta la configuración (en ejecución system/preferences/monitoro xrandr), las tarjetas gráficas realizan un tipo de exploración , por lo que la ejecución le xrandr -qbrinda la información, pero debe sondear el estado.

He escaneado todos los registros (kernel, daemon, X, etc.) buscando en /proc& /sys, y claramente parece que no existe nada que satisfaga su solicitud.

También he intentado esto:

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

Después de todo eso, si ejecuta System/Preferences/Monitormientras no se ha enchufado una nueva pantalla, ni se ha desenchufado, la herramienta aparecerá simplemente (normalmente). Pero si ha conectado o desconectado una pantalla anteriormente, a veces ejecutará esta herramienta y verá que su escritorio realiza un tipo de reinicio o actualización (lo mismo si ejecuta xrandr).

Esto parece confirmar que esta herramienta solicita xrandr(o funciona de la misma manera) al sondear el estado periódicamente, comenzando en el momento en que se ejecuta.

Podrías probarlo tú mismo:

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

Esto mostrará cuántas pantallas (pantallas) están conectadas, durante 10 segundos.

Mientras esto se ejecuta, conecte y / o desconecte su pantalla / monitor y vea lo que sucede. Para que pueda crear una pequeña función de prueba de Bash:

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

que sería utilizable como en:

$ if isVgaConnected; then echo yes; fi

Pero tenga cuidado, xrandrtoma alrededor de 0.140 segundos a 0.200 segundos mientras no se produce ningún cambio en los enchufes y hasta 0.700 segundos cada vez que algo se conectó o desconectó justo antes ( NOTA: Parece que no consume recursos).

EDITAR # 1

Para asegurarme de que no estoy enseñando algo incorrecto, busqué en la Web y en los documentos, pero no encontré nada sobre DBus y pantallas .

Finalmente, corrí en dos ventanas diferentes dbus-monitor --system(también he estado jugando con opciones) y el pequeño script que escribí:

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

... y nuevamente enchufado, que desenchufó el monitor, muchas veces. Entonces ahora podría decir:

  • En esta configuración, usando el controlador i915 , no hay otra manera que ejecutar xrandr -qpara saber si un monitor está enchufado o no.

Pero tenga cuidado, porque no parece haber otras formas. Por ejemplo, xrandrparece compartir esta información, por lo que mi escritorio GNOME cambiará xineramaautomáticamente ... cuando ejecutéxrandr .

Algunos documentos

F. Hauri
fuente
4

Las siguientes líneas aparecieron en 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)

al conectar un monitor al conector VGA. Entonces, podría haber una manera de resolver esto.

sebastianwagner
fuente
Con un nVidia 9800 GT y controladores propietarios, el monitor udevadm no muestra nada cuando conecto un monitor HDMI. ¿Qué hardware / controladores estás usando?
frankster
Lamentablemente, eso no funciona confiable para mí. A veces recibo estos mensajes de eventos cuando conecto mi monitor y otras veces no.
Tobias
3

Para aquellos que, por cualquier razón, no quieren tomar la ruta de conexión en caliente, aún es posible no sondear dentro de un script usando inotifywait:

#! / bin / bash

SCREEN_LEFT = DP2
SCREEN_RIGHT = eDP1
START_DELAY = 5

renice +19 $$> / dev / null

dormir $ START_DELAY

OLD_DUAL = "ficticio"

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

    if ["$ OLD_DUAL"! = "$ DUAL"]; entonces
        si ["$ DUAL" == "conectado"]; entonces
            echo 'Configuración de monitor dual'
            xrandr --output $ SCREEN_LEFT --auto --rotate normal --pos 0x0 --output $ SCREEN_RIGHT --auto --rotate normal --abajo $ SCREEN_LEFT
        más
            echo 'Configuración de monitor único'
            xrandr --auto
        fi

        OLD_DUAL = "$ DUAL"
    fi

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

Es mejor invocarlo desde su .xsessionrc, sin olvidar el final &. Las encuestas con xrandr dieron serios problemas de uso en mi nueva computadora portátil (el mouse se detendría periódicamente).

Balzola
fuente
No hubiera pensado que puede usar inotify /procy simplemente hacerlo inotifywait -q -e close /sys/class/drm/card0-DP-2/status no terminó al desconectar DP-2 en mi sistema
nhed
3

Me quedé con el uso de srandrd . Monitorea los eventos X y activa su script cuando una pantalla se conecta o desconecta.

scorpp
fuente
0

¡Obviamente debería haber algo! :) / sys filesystem le dice al usuario espacio qué hardware está disponible, por lo que las herramientas de espacio de usuario (como udev o mdev) pueden llenar dinámicamente un directorio "/ dev" con nodos de dispositivos que representan el hardware actualmente disponible. Linux proporciona dos interfaces hotplug: / sbin / hotplug y netlink.

Hay una pequeña demostración de C en el siguiente archivo. http://www.kernel.org/doc/pending/hotplug.txt

roncsak
fuente
0

La mayoría del software de sistema / aplicación en Linux hoy en día utiliza algunas técnicas de IPC para comunicarse entre sí. D-Bus ahora se usa principalmente con aplicaciones GNOME, y podría ayudar.

Revista Linux:

D-BUS puede facilitar el envío de eventos o señales a través del sistema, permitiendo que diferentes componentes en el sistema se comuniquen y finalmente se integren mejor. Por ejemplo, un dispositivo Bluetooth puede enviar una señal de llamada entrante que su reproductor de música puede interceptar, silenciando el volumen hasta que finalice la llamada.

wiki:

D-Bus proporciona un demonio del sistema (para eventos como "nuevo dispositivo de hardware agregado" o "cambio de cola de impresora") y un demonio de sesión de inicio de sesión por usuario (para necesidades generales de comunicación entre procesos entre aplicaciones de usuario)

Incluso hay una biblioteca de Python para esto, y ubuntu recientemente usó esta habilidad que llamó " zeitgeist ".

Amir Naghizadeh
fuente
-6

Gráficamente puede ver si se reconoce el monitor Monitor, sé que puede encontrarlo en Ubuntu, Fedora y otros en esta ubicación (o similar).

Sistema / Preferencias / Monitor

Y puede encender / apagar cualquier monitor que desee o usar ambos al mismo tiempo con una imagen duplicada en ambos monitores o monitores independientes

Bruce_Warrior
fuente
2
Solicitó un evento que se activa cuando un monitor está enchufado / desenchufado
Michael Mrozek
¿Miraste aquí? stackoverflow.com/questions/5469828/…
Satish