Come posso rilevare quando un monitor è collegato o scollegato?


53

C'è qualche evento che viene attivato quando collego o esco da un monitor esterno nel DisplayPort del mio laptop? ACPID e UDEV non reagiscono affatto.

Sto usando la grafica integrata su un chip Intel. Ecco una discussione simile che ha già un paio d'anni.

Non voglio usare il polling ma devo avere una configurazione che imposta automaticamente le impostazioni del display a seconda che il display sia collegato.


4
Può essere fatto con udev. Qual è la tua versione del kernel? Stai usando KMS (impostazione della modalità kernel)?
Andy,

Grazie per la risposta. Non sono sicuro di KMS, ma come ho detto nella domanda, udev non invia alcun evento. ( udevadm monitor - la proprietà non reagisce affatto)
janoliver

@Andy: l'ultima volta che è venuto fuori , sembrava che la maggior parte dei sistemi richiedesse il polling. Se hai trovato il modo di attivare un evento udev, potresti rispondere a questa domanda?
Gilles 'SO- smetti di essere malvagio'

1
Finalmente ho funzionato caricando i915 come modulo del kernel.
Janoliver,

3
Puoi usare xrandr o disper per rilevare se è stato collegato un monitor esterno. Github.com/wertarbyte/autorandr può mostrarti come usarli. Ma xrandr / disper potrebbe non supportare la tua scheda video.
numero

Risposte:


13

NOTA: questo è stato testato su un laptop con una scheda grafica guidata i915.


sfondo

NOTA: quando viene collegata una nuova schermata, nessun evento viene inviato all'host, questo è rimasto vero anche dopo la mia ultima modifica. Quindi l'unico modo è usare il polling. Cercando di renderli il più efficienti possibile ...

EDIT # 3

Finalmente c'è una soluzione migliore (tramite ACPI):

Non c'è ancora nessun evento, ma ACPI sembra più efficiente di xrandrindagare. (Nota: questo richiede moduli del kernel ACPI caricati, ma non richiede i privilegi di root).

La mia soluzione finale (usando bash):

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

Ora un test:

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

È collegato, quindi ora lo scollego:

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

NOTA: ${1:+*-1+1} permettere un booleano argomento: se qualcosa è presente , risposta sarebbe essere invertito: ( crtState >> 4 ) * -1 + 1.

e la sceneggiatura finale:

#!/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

AVVERTENZE: più leggero di xrandr, ma non irrilevante con un ritardo inferiore a 0,02 secondi, lo script Bash andrà in cima al processo dei mangiatori di risorse ( top)!

Mentre questo costa ~ 0,001 secondi:

$ time read -a </proc/stat crtStat

Ciò richiede ~ 0,030 sec:

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

Questo è grande! Quindi, a seconda di ciò di cui hai bisogno, delaypotrebbe essere ragionevolmente impostato tra 0.5e 2.

EDIT # 2

Ho finalmente trovato qualcosa, usando questo:

Importante dichiarazione di non responsabilità: giocare con /proce le /sysvoci potrebbero danneggiare il sistema !!! Quindi non provare quanto segue sui sistemi di produzione.

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

... dopo alcune pulizie di ingressi indesiderati:

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

Sono stato in grado di leggere questo:

/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 collego, scollego e ricollego il cavo del monitor.

Risposta originale

Quando viene richiesta la configurazione (in esecuzione system/preferences/monitoro xrandr), le schede grafiche eseguono un tipo di scansione , pertanto l'esecuzione xrandr -qfornisce le informazioni, ma è necessario eseguire il polling dello stato.

Ho scansionato tutti i log (kernel, demone, X e così via) cercando in /proc& /sys, e chiaramente non sembra esistere nulla che soddisfi la tua richiesta.

Ho provato anche questo:

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

Dopotutto, se esegui System/Preferences/Monitormentre non è stato appena collegato o scollegato alcun nuovo schermo, lo strumento apparirà semplicemente (normalmente). Ma se hai già collegato o scollegato uno schermo, a volte eseguirai questo strumento e vedrai il tuo desktop fare un tipo di ripristino o aggiornamento (lo stesso se esegui xrandr).

Ciò sembra confermare che questo strumento richiede xrandr(o funziona allo stesso modo) eseguendo periodicamente il polling dello stato, a partire dal momento in cui viene eseguito.

Potresti provare te stesso:

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

Questo mostrerà quante schermate (display) sono collegate, per 10 secondi.

Mentre questo funziona, collega e / o scollega lo schermo / monitor e guarda cosa succede. Quindi potresti creare una piccola funzione di Bash test:

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

che sarebbe utilizzabile come in:

$ if isVgaConnected; then echo yes; fi

Ma fai attenzione, xrandrimpiega circa 0,140 secondi a 0,200 secondi mentre non si verificano cambiamenti sulle spine e fino a 0,700 secondi ogni volta che qualcosa è stato collegato o scollegato poco prima ( NOTA: sembra non essere un mangiatore di risorse).

EDIT # 1

Per essere sicuro di non insegnare qualcosa di errato, ho cercato nel Web e nei documenti, ma non ho trovato nulla su DBus e schermate .

Infine, ho corso in due finestre diverse dbus-monitor --system(ho anche giocato con le opzioni) e la piccola sceneggiatura che ho scritto:

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

... e ancora una volta collegato, che scollegato il monitor, molte volte. Quindi ora potrei dire:

  • In questa configurazione, utilizzando il driver i915 , non c'è altro modo che correre xrandr -qper sapere se un monitor è collegato o meno.

Ma fai attenzione, perché non sembrano esserci altri modi. Ad esempio, xrandrsembra condividere queste informazioni, quindi il mio desktop GNOME passerebbe xineramaautomaticamente ... quando ho eseguitoxrandr .

Alcuni documenti


4

Sono comparse le seguenti righe 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)

quando si collega un monitor al connettore VGA. Quindi potrebbe esserci un modo per capirlo.


Con un nVidia 9800 GT e driver proprietari, il monitor udevadm non mostra nulla quando collego un monitor HDMI. Quale hardware / driver stai usando?
Frank

Peccato, per me non funziona in modo affidabile. A volte ricevo questi messaggi di evento quando collego il mio monitor e talvolta no.
Tobias,

3

Per coloro che, per qualsiasi motivo, non vogliono seguire il percorso hotplug, è comunque possibile non eseguire il polling all'interno di uno script usando inotifywait:

#! / Bin / bash

SCREEN_LEFT = DP2
SCREEN_RIGHT = eDP1
START_DELAY = 5

renice +19 $$> / dev / null

dormire $ START_DELAY

OLD_DUAL = "fittizio"

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

    if ["$ OLD_DUAL"! = "$ DUAL"]; poi
        se ["$ DUAL" == "connesso"]; poi
            echo 'Configurazione doppio monitor'
            xrandr --output $ SCREEN_LEFT --auto --rotate normal --pos 0x0 --output $ SCREEN_RIGHT --auto --rotate normal --below $ SCREEN_LEFT
        altro
            echo 'Impostazione monitor singolo'
            xrandr --auto
        fi

        OLD_DUAL = "$ DUAL"
    fi

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

È meglio invocato dal tuo .xsessionrc, senza dimenticare il finale &. Il polling con xrandr ha causato seri problemi di usabilità sul mio laptop nuovo di zecca (il mouse si arrestava periodicamente).


Non avrei mai pensato di poter usare inotify su /proce semplicemente fare inotifywait -q -e close /sys/class/drm/card0-DP-2/status non è finito con la disconnessione di DP-2 sul mio sistema
nhed

3

Ho continuato a usare srandrd . Monitora gli eventi X e attiva lo script quando uno schermo viene collegato o disconnesso.


0

Ovviamente ci dovrebbe essere qualcosa! :) Il filesystem / sys dice a userspace quale hardware è disponibile, quindi gli strumenti di userspace (come udev o mdev) possono popolare dinamicamente una directory "/ dev" con nodi di dispositivo che rappresentano l'hardware attualmente disponibile. Linux fornisce due interfacce hotplug: / sbin / hotplug e netlink.

C'è una piccola demo C nel seguente file. http://www.kernel.org/doc/pending/hotplug.txt


0

Per lo più software di sistema / applicazione su Linux oggi hanno usato alcune tecniche ipc per comunicare tra loro. D-Bus è ora utilizzato principalmente con le applicazioni GNOME e potrebbe essere d'aiuto.

Linux Journal:

D-BUS può facilitare l'invio di eventi o segnali attraverso il sistema, consentendo a diversi componenti del sistema di comunicare e infine integrarsi meglio. Ad esempio, un demone Bluetooth può inviare un segnale di chiamata in arrivo che il lettore musicale può intercettare, disattivando il volume fino al termine della chiamata.

wiki:

D-Bus fornisce sia un demone di sistema (per eventi come "nuovo dispositivo hardware aggiunto" o "coda della stampante modificata") che un demone per sessione di accesso per utente (per esigenze di comunicazione tra processi generali tra le applicazioni utente)

C'è anche una libreria Python per questo, e Ubuntu ha recentemente usato questa abilità che ha chiamato " zeitgeist ".


-6

Graficamente puoi vedere se il monitor è riconosciuto Monitor, so che puoi trovarlo su Ubuntu, Fedora e altri in questa (o in una posizione simile).

System / Preferences / Monitor

E puoi accendere / spegnere qualsiasi monitor che desideri o utilizzare entrambi contemporaneamente con un'immagine duplicata su entrambi i monitor o monitor indipendenti


2
Ha chiesto un evento che si attiva quando un monitor viene collegato / scollegato
Michael Mrozek

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.