web-dev-qa-db-fra.com

Comment puis-je détecter lorsqu'un moniteur est branché ou débranché?

Y a-t-il un événement qui se déclenche lorsque je branche ou déconnecte un moniteur externe dans le DisplayPort de mon ordinateur portable? ACPID et UDEV ne réagissent pas du tout.

J'utilise des graphiques intégrés sur une puce Intel. Ici est une discussion similaire qui a déjà quelques années.

Je ne veux pas utiliser l'interrogation, mais je dois avoir une configuration qui définit automatiquement les paramètres d'affichage selon que l'écran est connecté.

54
janoliver

REMARQUE: Ceci a été testé sur un ordinateur portable avec une carte graphique pilotée par i915.


Contexte

REMARQUE: Lorsqu'un nouvel écran est branché, aucun événement n'est envoyé à l'hôte, cela est resté vrai même après ma dernière édition. La seule façon est donc d'utiliser le sondage. Essayer de les rendre aussi efficaces que possible ...

EDIT # 3

Enfin, il existe une meilleure solution (via ACPI):

Il n'y a toujours pas d'événement, mais ACPI semble plus efficace que xrandr pour s'enquérir. (Nota: ceci nécessite des modules du noyau ACPI chargés, mais ne nécessite pas de privilèges root).

Ma solution finale (en utilisant bash):

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

Maintenant un test:

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

Il est branché, alors maintenant je le débranche:

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

REMARQUE: ${1:+*-1+1} autorise un argument booléen: Si quelque chose est présent, la réponse serait inversée: ( crtState >> 4 ) * -1 + 1.

et le 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

AVERTISSEMENTS: plus léger que xrandr, mais pas sans importance avec un retard inférieur à 0,02 secondes, le script Bash ira en haut du processus des mangeurs de ressources (top)!

Alors que cela coûte ~ 0,001 s:

$ time read -a </proc/stat crtStat

Cela nécessite ~ 0,030 sec:

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

C'est grand! Ainsi, selon ce dont vous avez besoin, delay peut être raisonnablement défini entre 0.5 et 2.

EDIT # 2

J'ai enfin trouvé quelque chose, en utilisant ceci:

Avertissement important: Jouer avec /proc et /sys les entrées pourraient briser votre système !!! N'essayez donc pas ce qui suit sur les systèmes de production.

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

... après un nettoyage des entrées indésirables:

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

J'ai pu lire ceci:

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

Lorsque je branche, débranche et rebranche le câble du moniteur.

Lorsque la configuration est demandée (exécution de system/preferences/monitor ou xrandr), les cartes graphiques font un type de - scan, donc exécutant xrandr -q vous donne les informations, mais vous devez interroger le statut.

J'ai analysé tous les journaux (noyau, démon, X et ainsi de suite) en cherchant dans /proc & /sys, et rien ne semble clairement exister qui réponde à votre demande.

J'ai aussi essayé ça:

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

Après tout cela, si vous exécutez System/Preferences/Monitor alors qu'aucun nouvel écran n'a été branché ou débranché, l'outil apparaît simplement (normalement). Mais si vous avez déjà branché ou débranché un écran auparavant, vous exécuterez parfois cet outil et vous verrez votre bureau faire un type de reset ou refresh (idem si vous exécutez xrandr).

Cela semble confirmer que cet outil demande xrandr (ou fonctionne de la même manière) en interrogeant l'état périodiquement, en commençant au moment de son exécution.

Vous pouvez vous essayer:

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

Cela affichera le nombre d'écrans (écrans) connectés, pendant 10 secondes.

Pendant que cela fonctionne, branchez et/ou débranchez votre écran/moniteur et regardez ce qui se passe. Vous pouvez donc créer une petite fonction de test Bash:

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

qui serait utilisable comme dans:

$ if isVgaConnected; then echo yes; fi

Mais attention, xrandr prend environ 0,140 sec à 0,200 sec alors qu'aucun changement ne se produit sur les fiches et jusqu'à 0,700 seconde chaque fois que quelque chose a été branché ou débranché juste avant ( REMARQUE: Il semble que ce ne soit pas une ressource mangeur).

EDIT # 1

Pour m'assurer que je n'enseigne pas quelque chose de incorrect, j'ai cherché sur le Web et dans la documentation, mais je n'ai rien trouvé sur DBus et écrans.

Enfin, j'ai exécuté dans deux fenêtres différentes dbus-monitor --system (J'ai aussi joué avec des options) et le petit script que j'ai écrit:

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

... et encore branché, que débranché le moniteur, plusieurs fois. Alors maintenant, je pourrais dire:

  • Dans cette configuration, en utilisant le pilote i915 , il n'y a pas d'autre moyen que d'exécuter xrandr -q pour savoir si un moniteur est branché ou non.

Mais soyez prudent, car il ne semble pas y avoir d'autres moyens. Par exemple, xrandr semble partager ces informations, donc mon bureau GNOME basculerait automatiquement vers xinerama ... lorsque j'exécutais xrandr.

Quelques documents

14
F. Hauri

Les lignes suivantes sont apparues dans 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)

lors de la connexion d'un moniteur au connecteur VGA. Il pourrait donc y avoir un moyen de comprendre cela.

4
sebastianwagner

Je suis resté à utiliser srandrd . Il surveille les événements X et déclenche votre script lorsqu'un affichage est connecté ou déconnecté.

3
scorpp

Pour ceux qui, pour une raison quelconque, ne veulent pas emprunter la route hotplug, il est toujours possible de ne pas interroger dans un script en utilisant inotifywait:

 #!/bin/bash 
 
 SCREEN_LEFT = DP2 
 SCREEN_RIGHT = eDP1 
 START_DELAY = 5 
 
 renice +19 $$>/dev/null 
 
 sleep $ START_DELAY 
 
 OLD_DUAL = "factice" 
 
 pendant que [ 1 ]; do 
 DUAL = $ (cat /sys/class/drm/card0-DP-2/status)[.____. diplomatique .____.] if ["$ OLD_DUAL"! = "$ DUAL"]; alors 
 si ["$ DUAL" == "connecté"]; puis 
 echo 'Configuration double moniteur' 
 xrandr --output $ SCREEN_LEFT --auto --rotate normal --pos 0x0 --output $ SCREEN_RIGHT --auto --rotate normal --below $ SCREEN_LEFT 
 Else 
 Echo 'Configuration moniteur unique' 
 Xrandr --auto 
 Fi 
 
 OLD_DUAL = "$ DUAL" 
 fi 
 
 inotifywait -q -e close/sys/class/drm/card0-DP-2/status>/dev/null 
 done 
 

Il est préférable de l'invoquer depuis votre .xsessionrc, sans oublier la fin &. L'interrogation avec xrandr a donné de sérieux problèmes d'utilisation sur mon tout nouvel ordinateur portable (la souris se bloquait périodiquement).

3
Balzola

Évidemment, il devrait y avoir quelque chose! :) Le système de fichiers/sys indique à l'espace utilisateur le matériel disponible, afin que les outils de l'espace utilisateur (tels que udev ou mdev) puissent remplir dynamiquement un répertoire "/ dev" avec des nœuds de périphérique représentant le matériel actuellement disponible. Linux propose deux interfaces hotplug:/sbin/hotplug et netlink.

Il y a une petite démo C dans le fichier suivant. http://www.kernel.org/doc/pending/hotplug.txt

0
roncsak

La plupart du temps, les logiciels système/applications sous Linux utilisaient certaines techniques ipc pour communiquer entre eux. D-Bus est maintenant principalement utilisé avec les applications GNOME et pourrait vous aider.

Linux Journal:

D-BUS peut faciliter l'envoi d'événements ou de signaux à travers le système, permettant aux différents composants du système de communiquer et, finalement, de mieux s'intégrer. Par exemple, un démon Bluetooth peut envoyer un signal d'appel entrant que votre lecteur de musique peut intercepter, en coupant le son jusqu'à la fin de l'appel.

wiki:

D-Bus fournit à la fois un démon système (pour les événements tels que "nouveau périphérique matériel ajouté" ou "file d'attente d'imprimante modifiée") et un démon par session de connexion par utilisateur (pour les besoins généraux de communication interprocessus entre les applications utilisateur)

Il existe même une bibliothèque Python pour cela, et ubuntu a récemment utilisé cette capacité qui appelait " zeitgeist ".

0
Amir Naghizadeh