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

53

Y at - il une événement qui est déclenché lorsque je branche ou sur 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. Voici une discussion similaire qui a déjà deux ans.

Je ne souhaite pas utiliser l'interrogation, mais j'ai besoin d'une configuration définissant automatiquement les paramètres d'affichage en fonction du type d'affichage connecté.

janoliver
la source
4
Cela peut être fait avec udev. Quelle est la version de votre noyau? Utilisez-vous KMS (paramètre de mode noyau)?
Andy
Merci d'avoir répondu. Je ne suis pas sûr à propos de KMS, mais comme je l'ai dit dans la question, udev n'envoie aucun événement. ( Moniteur udevadm - la propriété ne réagit pas du tout)
janoliver
@Andy: la dernière fois que cela est arrivé , il semblait que la plupart des systèmes nécessitaient une interrogation. Si vous avez trouvé un moyen de déclencher un événement udev, pouvez-vous répondre à cette question?
Gilles 'SO- arrête d'être méchant'
1
Je l'ai enfin lancé en chargeant i915 en tant que module de noyau.
janoliver
3
Vous pouvez utiliser xrandr ou disper pour détecter si un moniteur externe a été branché. Github.com/wertarbyte/autorandr peut vous montrer comment les utiliser. Mais xrandr / disper pourrait ne pas prendre en charge votre carte vidéo.
number5

Réponses:

13

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 modification. Donc, le seul moyen est d'utiliser polling. 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 xrandrde s'enquérir. (Nota: Cela nécessite des modules de 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

C'est branché, alors maintenant je le débranche:

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

REMARQUE: ${1:+*-1+1} permettre un booléen argument: Si quelque chose est présent , serait inversée réponse: ( 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 non sans importance, avec un délai inférieur à 0,02 seconde, le script Bash ira au sommet du processus des utilisateurs de ressources ( top)!

Bien que cela coûte ~ 0.001 seconde:

$ time read -a </proc/stat crtStat

Cela nécessite ~ 0.030 seconde:

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

C'est grand! Donc, en fonction de vos besoins, vous delaypouvez choisir entre 0.5et 2.

EDIT # 2

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

Avertissement important: Jouer avec /procet les /sysentrées peuvent casser votre système !!! Alors n'essayez 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 non désirées:

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.

Réponse originale

Lorsque la configuration est demandée (en cours d'exécution system/preferences/monitorou xrandr), les cartes graphiques effectuent un type d' analyse . Par conséquent, l'exécution xrandr -qvous donne les informations, mais vous devez interroger l'état.

J'ai parcouru tous les journaux (noyau, démon, X, etc.) en cherchant dans /proc& /sys, et rien ne semble exister qui puisse satisfaire votre requête.

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 courez System/Preferences/Monitoralors qu’aucun nouvel écran n’a été branché, ni débranché, l’outil apparaîtra simplement (normalement). Mais si vous avez déjà branché ou débranché un écran, vous exécuterez parfois cet outil et votre bureau affichera un type de réinitialisation ou d' actualisation (identique si vous exécutez xrandr).

Cela semble confirmer que cet outil demande xrandr(ou fonctionne de la même manière) en interrogeant périodiquement l’état de l’état, à partir du moment où il est exécuté.

Vous pouvez essayer vous-même:

$ 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 combien d'écrans (écrans) sont 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, cela xrandrprend environ 0.140 sec à 0.200 sec quand aucun changement ne se produit sur les fiches et jusqu’à 0.700 secondes chaque fois que quelque chose était branché ou débranché juste avant ( NOTE: cela ne semble pas être un mangeur de ressources).

EDIT # 1

Pour m'assurer que je n'enseigne pas quelque chose d'incorrect, j'ai effectué des recherches sur le Web et dans la documentation, mais je n'ai rien trouvé sur DBus et Screens .

Enfin, j’ai couru 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, à l' aide du pilote i915 , il n'y a pas d'autre moyen que de lancer l'exécution xrandr -qpour savoir si un moniteur est branché ou non.

Mais soyez prudent, car il ne semble pas y avoir d'autres moyens. Par exemple, xrandrsemble partager cette information, mon bureau GNOME passerait xineramaautomatiquement à ... quand je courraisxrandr .

Quelques docs

F. Hauri
la source
4

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. Donc, il pourrait y avoir un moyen de comprendre cela.

sebastianwagner
la source
Avec un nVidia 9800 GT et des pilotes propriétaires, le moniteur udevadm n’affiche rien lorsque je connecte un moniteur HDMI. Quel matériel / pilotes utilisez-vous?
frankster
Dommage, cela ne fonctionne pas fiable pour moi. Parfois, je reçois ces messages d'événement lorsque je connecte mon moniteur et parfois pas.
Tobias
3

Pour ceux qui, pour une raison quelconque, ne veulent pas prendre la route hotplug, il est toujours possible de ne pas interroger dans un script à l'aide de inotifywait:

#! / bin / bash

SCREEN_LEFT = DP2
SCREEN_RIGHT = eDP1
START_DELAY = 5

renice +19 $$> / dev / null

dormir $ START_DELAY

OLD_DUAL = "dummy"

tandis que [1]; faire
    DUAL = $ (cat / sys / class / drm / card0-DP-2 / status)

    if ["$ OLD_DUAL"! = "$ DUAL"]; ensuite
        if ["$ DUAL" == "connecté"]; ensuite
            echo 'Configuration double moniteur'
            xrandr --output $ SCREEN_LEFT --auto --rotate normal --pos 0x0 --output $ SCREEN_RIGHT --auto --rotate normal - ci-dessous $ SCREEN_LEFT
        autre
            echo 'Configuration d'un seul moniteur'
            xrandr --auto
        Fi

        OLD_DUAL = "$ DUAL"
    Fi

    inotifywait -q -e ferme / sys / classe / drm / card0-DP-2 / statut> / dev / null
terminé

Il est préférable de l'invoquer à partir de votre fichier .xsessionrc, sans oublier la fin &. Les sondages avec xrandr ont posé de sérieux problèmes d’utilisabilité sur mon tout nouvel ordinateur portable (la souris ralentissait périodiquement).

Balzola
la source
Je n'aurais pas pensé que vous pouviez utiliser inotify sur /proc, mais le inotifywait -q -e close /sys/class/drm/card0-DP-2/status fait de ne pas mettre fin à cette opération ne
consistait
3

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

scorpp
la source
0

Évidemment il devrait y avoir quelque chose! :) / sys filesystem indique à l’espace utilisateur quel matériel est disponible, ainsi ses outils (tels que udev ou mdev) peuvent remplir dynamiquement un répertoire "/ dev" avec des nœuds de périphérique représentant le matériel actuellement disponible. Linux fournit 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

Roncsak
la source
0

Aujourd'hui, 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 aider.

Journal Linux:

D-BUS peut faciliter l'envoi d'événements ou de signaux à travers le système, permettant ainsi à différents composants du système de communiquer et 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 volume 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 ajouté" ou "file d'impression modifiée") et un démon de session par utilisateur (pour les besoins généraux de communication inter-processus entre les applications utilisateur).

Il existe même une bibliothèque Python pour cela, et Ubuntu a récemment utilisé cette capacité appelée " Zeitgeist ".

Amir Naghizadeh
la source
-6

Graphiquement, vous pouvez voir si le moniteur est reconnu avec Monitor, je sais que vous pouvez le trouver sur Ubuntu, Fedora et d’autres dans cet emplacement (ou un emplacement similaire).

Système / Préférences / Moniteur

Et vous pouvez activer / désactiver le moniteur de votre choix ou utiliser les deux en même temps avec une image dupliquée sur un moniteur ou des moniteurs indépendants

Bruce_Warrior
la source
2
Il a demandé un événement qui se déclenche lorsqu'un moniteur est branché / débranché
Michael Mrozek
Avez-vous regardé ici? stackoverflow.com/questions/5469828/…
Satish le