Bagaimana saya bisa mendeteksi ketika monitor dicolokkan atau dicabut?

53

Apakah ada setiap peristiwa yang dipicu ketika saya pasang atau keluar monitor eksternal ke dalam DisplayPort dari laptop saya? ACPID dan UDEV tidak bereaksi sama sekali.

Saya menggunakan grafis onboard pada chip intel. Ini diskusi serupa yang sudah berumur beberapa tahun.

Saya tidak ingin menggunakan polling tetapi saya perlu memiliki beberapa konfigurasi yang mengatur pengaturan tampilan secara otomatis tergantung pada apakah layar terhubung.

janoliver
sumber
4
Itu bisa dilakukan dengan udev. Apa versi kernel Anda? Apakah Anda menggunakan KMS (pengaturan mode kernel)?
Andy
Terima kasih atas jawabannya. Saya tidak yakin tentang KMS, tetapi seperti yang saya katakan di pertanyaan, udev tidak mengirim acara apa pun. ( Monitor udevadm --property tidak bereaksi sama sekali)
janoliver
@Andy: terakhir kali ini muncul , sepertinya sebagian besar sistem membutuhkan polling. Jika Anda menemukan cara untuk memicu acara udev, dapatkah Anda menjawab pertanyaan itu?
Gilles 'SANGAT berhenti menjadi jahat'
1
Saya akhirnya menjalankannya memuat i915 sebagai modul kernel.
janoliver
3
Anda dapat menggunakan xrandr atau disper untuk mendeteksi apakah monitor eksternal telah dipasang. Github.com/wertarbyte/autorandr dapat menunjukkan kepada Anda cara menggunakannya. Tetapi xrandr / disper mungkin tidak mendukung kartu video Anda.
number5

Jawaban:

13

CATATAN: Ini diuji pada laptop dengan kartu grafis yang digerakkan i915.


Latar Belakang

CATATAN: Ketika layar baru dicolokkan, tidak ada acara dikirim ke tuan rumah, ini tetap benar bahkan setelah edit terakhir saya. Jadi satu-satunya cara adalah menggunakan polling. Mencoba menjadikannya seefisien mungkin ...

EDIT # 3

Akhirnya ada satu solusi yang lebih baik (melalui ACPI):

Masih belum ada acara, tetapi ACPI tampaknya lebih efisien daripada xrandrbertanya. (Catatan: Ini membutuhkan modul kernel ACPI yang dimuat, tetapi tidak memerlukan hak akses root).

Solusi terakhir saya (menggunakan bash):

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

Sekarang ujian:

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

Itu sudah terhubung, jadi sekarang saya mencabutnya:

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

CATATAN: ${1:+*-1+1} mengizinkan boolean argumen: Jika ada sesuatu yang hadir , jawabannya akan terbalik: ( crtState >> 4 ) * -1 + 1.

dan skrip terakhir:

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

PERINGATAN: lebih ringan dari xrandr, tetapi tidak penting dengan penundaan lebih kecil dari 0,02 detik, skrip Bash akan pergi ke bagian atas proses pemakan sumber daya ( top)!

Sementara ini biaya ~ 0,001 detik:

$ time read -a </proc/stat crtStat

Ini membutuhkan ~ 0,030 detik:

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

Ini besar! Jadi tergantung pada apa yang Anda butuhkan, delaybisa diatur antara 0.5dan 2.

EDIT # 2

Saya akhirnya menemukan sesuatu, menggunakan ini:

Penafian penting: Bermain dengan /procdan /sysentri dapat merusak sistem Anda !!! Jadi jangan coba yang berikut ini pada sistem produksi.

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

... setelah beberapa pembersihan entri yang tidak diinginkan:

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

Saya sudah bisa membaca ini:

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

Saat saya mencolokkan, cabut, dan pasang kembali kabel monitor.

Jawaban Asli

Ketika konfigurasi diminta (berjalan system/preferences/monitoratau xrandr), kartu grafis melakukan jenis pemindaian , jadi menjalankan xrandr -qmemberi Anda info, tetapi Anda harus polling status.

Saya telah memindai semua log, (kernel, daemon, X, dan sebagainya) mencari melalui /proc& /sys, dan tampaknya tidak ada yang memenuhi permintaan Anda.

Saya sudah mencoba ini juga:

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

Setelah semua itu, jika Anda menjalankan System/Preferences/Monitorsementara tidak ada layar baru yang baru saja dicolokkan, atau dicabut, alat akan muncul secara sederhana (normal). Tetapi jika Anda sudah memasang atau mencabut layar sebelumnya, kadang-kadang Anda akan menjalankan alat ini dan Anda akan melihat desktop Anda membuat jenis reset atau refresh (sama jika Anda menjalankan xrandr).

Ini sepertinya mengkonfirmasi bahwa alat ini meminta xrandr(atau bekerja dengan cara yang sama) dengan memungut status secara berkala, mulai saat dijalankan.

Anda bisa mencoba sendiri:

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

Ini akan menampilkan berapa banyak layar (display) yang terhubung, selama 10 detik.

Saat ini berjalan, pasang dan / atau cabut layar / monitor Anda dan lihat apa yang terjadi. Jadi Anda bisa membuat fungsi tes Bash kecil:

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

yang bisa digunakan seperti pada:

$ if isVgaConnected; then echo yes; fi

Tapi hati-hati, xrandrbutuh sekitar 0,140 detik hingga 0,200 detik sementara tidak ada perubahan yang terjadi pada colokan dan hingga 0,700 detik setiap kali sesuatu dicolokkan atau dicabut tepat sebelumnya ( CATATAN: Tampaknya bukan menjadi pemakan sumber daya).

EDIT # 1

Untuk memastikan saya tidak mengajarkan sesuatu yang salah, saya telah mencari di Web dan dokumen, tetapi tidak menemukan apa pun tentang DBus dan Layar .

Akhirnya, saya telah menjalankan di dua jendela yang berbeda dbus-monitor --system(saya telah bermain dengan opsi juga) dan skrip kecil yang saya tulis:

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

... dan lagi terpasang, daripada mencabut monitor, berkali-kali. Jadi sekarang saya bisa mengatakan:

  • Dalam konfigurasi ini, menggunakan driver i915 , tidak ada cara lain selain berlari xrandr -quntuk mengetahui apakah monitor dicolokkan atau tidak.

Tetapi berhati-hatilah, karena tampaknya tidak ada cara lain. Misalnya, xrandrsepertinya membagikan informasi ini, sehingga desktop GNOME saya akan beralih ke xineramasecara otomatis ... ketika saya berlarixrandr .

Beberapa dokumen

F. Hauri
sumber
4

Baris berikut muncul di 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)

saat memasang monitor ke Konektor-VGA. Jadi mungkin ada cara untuk mencari tahu ini.

sebastianwagner
sumber
Dengan nVidia 9800 GT dan driver berpemilik, monitor udevadm tidak menunjukkan apa-apa saat saya menghubungkan monitor HDMI. Perangkat keras / driver apa yang Anda gunakan?
frankster
Sayangnya, itu tidak berfungsi andal bagi saya. Kadang-kadang saya mendapatkan pesan acara ini ketika saya mencolokkan monitor saya dan terkadang tidak.
Tobias
3

Bagi mereka yang, untuk alasan apa pun, tidak ingin mengambil rute hotplug, masih mungkin untuk tidak melakukan polling dalam skrip menggunakan inotifywait:

#! / bin / bash

SCREEN_LEFT = DP2
SCREEN_RIGHT = eDP1
START_DELAY = 5

renice +19 $$> / dev / null

tidur $ START_DELAY

OLD_DUAL = "dummy"

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

    if ["$ OLD_DUAL"! = "$ DUAL"]; kemudian
        jika ["$ DUAL" == "terhubung"]; kemudian
            gema 'Pengaturan monitor ganda'
            xrandr --output $ SCREEN_LEFT --auto --rotate normal --pos 0x0 --output $ SCREEN_RIGHT --auto --rotate normal - di bawah $ SCREEN_LEFT
        lain
            gema 'Pengaturan monitor tunggal'
            xrandr --auto
        fi

        OLD_DUAL = "$ DUAL"
    fi

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

Paling baik dipanggil dari .xsessionrc Anda, jangan lupa bagian akhirnya &. Polling dengan xrandr memberikan masalah kegunaan serius pada laptop baru saya (mouse akan berhenti secara berkala).

Balzola
sumber
Saya tidak akan berpikir bahwa Anda dapat menggunakan inotify /procdan hanya melakukan inotifywait -q -e close /sys/class/drm/card0-DP-2/status memang tidak berakhir setelah melepas DP-2 pada sistem saya
nhed
3

Saya terjebak menggunakan srandrd . Ini memonitor peristiwa X dan memicu skrip Anda ketika layar terhubung atau terputus.

scorpp
sumber
0

Jelas harus ada sesuatu! :) / sys filesystem memberitahu userspace perangkat keras apa yang tersedia, jadi alat userspace (seperti udev atau mdev) dapat secara dinamis mengisi direktori "/ dev" dengan node perangkat yang mewakili perangkat yang saat ini tersedia perangkat keras. Linux menyediakan dua antarmuka hotplug: / sbin / hotplug dan netlink.

Ada demo C kecil di file berikut. http://www.kernel.org/doc/pending/hotplug.txt

roncsak
sumber
0

Sebagian besar perangkat lunak sistem / aplikasi di Linux saat ini menggunakan beberapa teknik IPC untuk berkomunikasi satu sama lain. D-Bus sekarang sebagian besar digunakan dengan aplikasi GNOME, dan mungkin membantu.

Jurnal Linux:

D-BUS dapat memfasilitasi pengiriman acara, atau sinyal, melalui sistem, yang memungkinkan berbagai komponen dalam sistem untuk berkomunikasi dan pada akhirnya untuk mengintegrasikan dengan lebih baik. Misalnya, Bluetooth Dæmon dapat mengirim sinyal panggilan masuk yang dapat disadap pemutar musik Anda, mematikan volume sampai panggilan berakhir.

wiki:

D-Bus memasok daemon sistem (untuk acara seperti "perangkat keras baru ditambahkan" atau "antrian printer berubah") dan daemon sesi pengguna per login (untuk kebutuhan komunikasi antar-proses umum di antara aplikasi pengguna)

Bahkan ada perpustakaan Python untuk ini, dan ubuntu baru-baru ini menggunakan kemampuan ini yang disebut " zeitgeist ".

Amir Naghizadeh
sumber
-6

Secara grafis Anda dapat melihat apakah monitor dikenali Monitor, saya tahu Anda dapat menemukannya di Ubuntu, Fedora, dan lainnya di lokasi ini (atau yang serupa).

Sistem / Preferensi / Monitor

Dan Anda dapat menghidupkan / mematikan monitor yang Anda inginkan atau menggunakan keduanya secara bersamaan dengan duplikat gambar di monitor atau monitor independen

Bruce_Warrior
sumber
2
Dia meminta acara yang dipicu ketika monitor dicolokkan / dicabut
Michael Mrozek
Apakah kamu melihat di sini? stackoverflow.com/questions/5469828/...
Satish