Как я могу определить, когда монитор подключен или отключен?

53

Есть ли какое-либо событие, которое запускается, когда я подключаю или отключаю внешний монитор к DisplayPort моего ноутбука? ACPID и UDEV вообще не реагируют.

Я использую встроенную графику на чипе Intel. Вот похожая дискуссия, которой уже пару лет.

Я не хочу использовать опрос, но мне нужно иметь некоторую конфигурацию, которая автоматически устанавливает параметры дисплея в зависимости от того, подключен ли дисплей.

janoliver
источник
4
Это можно сделать с помощью Udev. Какая у вас версия ядра? Используете ли вы KMS (настройки режима ядра)?
Энди
Спасибо за ответ. Я не уверен насчет KMS, но, как я уже сказал в этом вопросе, udev не отправляет никаких событий. ( udevadm monitor --property вообще не реагирует)
janoliver
@ Энди: в последний раз, когда это происходило , казалось, что большинство систем требует опроса. Если вы нашли способ вызвать событие udev, можете ли вы ответить на этот вопрос?
Жиль "ТАК - перестань быть злым"
1
Я наконец запустил загрузку i915 в качестве модуля ядра.
Январь
3
Вы можете использовать xrandr или disper, чтобы определить, подключен ли внешний монитор. Github.com/wertarbyte/autorandr может показать вам, как их использовать. Но xrandr / disper может не поддерживать вашу видеокарту.
number5

Ответы:

13

ПРИМЕЧАНИЕ. Тестирование проводилось на ноутбуке с графической картой с управлением i915.


Фон

ПРИМЕЧАНИЕ. Когда подключен новый экран, на хост не отправляется событие, оно остается верным даже после моего последнего редактирования. Таким образом, единственный способ - использовать опрос. Пытаясь сделать их максимально эффективными ...

РЕДАКТИРОВАТЬ № 3

Наконец, есть одно лучшее решение (через ACPI):

Там еще нет события, но ACPI кажется более эффективным, чем xrandrзапросить. (Примечание: для этого требуются загруженные модули ядра ACPI, но не требуются права root).

Мое окончательное решение (с использованием bash):

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

Теперь тест:

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

Он подключен, так что теперь я отключаю его:

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

Примечание: ${1:+*-1+1} разрешить логическое рассуждение: Если что - то присутствует , ответ будет перевернутой: ( crtState >> 4 ) * -1 + 1.

и последний сценарий:

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

ПРЕДУПРЕЖДЕНИЯ: легче xrandr, но не менее важно, с задержкой менее 0,02 секунды, скрипт Bash перейдет на вершину процесса пожирателей ресурсов ( top)!

Пока это стоит ~ 0,001 сек:

$ time read -a </proc/stat crtStat

Это требует ~ 0,030 сек:

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

Это большое! Таким образом, в зависимости от того, что вам нужно, delayможет быть разумно установлено между 0.5и 2.

РЕДАКТИРОВАТЬ № 2

Я наконец-то нашел что-то, используя это:

Важный отказ от ответственности: игра с /procи /sysзаписи может сломать вашу систему !!! Так что не пытайтесь сделать следующее на производственных системах.

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

... после некоторой очистки от нежелательных записей:

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

Я был в состоянии прочитать это:

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

Когда я подключаю, отключаю и снова подключаю кабель монитора.

Оригинальный ответ

Когда запрашивается конфигурация (запущена system/preferences/monitorили xrandr), графические карты выполняют тип сканирования , поэтому при запуске xrandr -qвыдается информация, но вы должны опросить статус.

Я просмотрел все журналы (ядро, демон, X и т. Д.), Просматривая /proc& /sys, и, похоже, ничего не существует, чтобы удовлетворить ваш запрос.

Я тоже попробовал это:

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

После всего этого, если вы запускаете, System/Preferences/Monitorкогда новый экран не был подключен или отключен, инструмент будет отображаться просто (обычно). Но если вы ранее подключали или отключали экран, иногда вы запускаете этот инструмент и увидите, что ваш рабочий стол выполняет сброс или обновление (то же самое, если вы запускаете xrandr).

Похоже, это подтверждает, что этот инструмент запрашивает xrandr(или работает аналогичным образом), периодически опрашивая состояние, начиная с момента его запуска.

Вы можете попробовать себя:

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

Это покажет, сколько экранов (дисплеев) подключено, за 10 секунд.

Пока это работает, подключите и / или отключите ваш экран / монитор и посмотрите, что происходит. Таким образом, вы можете создать небольшую тестовую функцию Bash:

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

который будет использоваться как в:

$ if isVgaConnected; then echo yes; fi

Но будьте осторожны, xrandrзанимает от 0,140 до 0,200 с, пока на вилках не происходит никаких изменений, и до 0,700 с, когда что-то было подключено или отключено непосредственно перед этим ( ПРИМЕЧАНИЕ. Похоже, что это не пожиратель ресурсов).

РЕДАКТИРОВАТЬ # 1

Чтобы убедиться, что я не преподаю что-то неправильное, я искал в Интернете и документах, но не нашел ничего о DBus и экранах .

Наконец, я запустил два разных окна dbus-monitor --system(я тоже играл с опциями) и небольшой сценарий, который я написал:

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

... и снова подключил, чем отключил монитор, много раз. Так что теперь я могу сказать:

  • В этой конфигурации с использованием драйвера i915 нет другого способа, кроме xrandr -qкак узнать, подключен ли монитор или нет.

Но будьте осторожны, потому что, похоже, других путей нет. Например, xrandrкажется, что делится этой информацией, поэтому мой рабочий стол GNOME переключился бы xineramaавтоматически ... когда я запустилсяxrandr .

Некоторые документы

F. Hauri
источник
4

Следующие строки появились в 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)

при подключении монитора к VGA-разъему. Так что может быть способ выяснить это.

sebastianwagner
источник
При использовании nVidia 9800 GT и проприетарных драйверов монитор udevadm ничего не показывает при подключении монитора HDMI. Какое оборудование / драйверы вы используете?
Франк
К сожалению, это не работает надежно для меня. Иногда я получаю эти сообщения о событиях, когда я подключаю свой монитор, а иногда нет.
Тобиас
3

Для тех, кто по какой-либо причине не хочет идти по маршруту горячего подключения, все еще возможно не опрашивать в скрипте с использованием inotifywait:

#! / Bin / Баш

SCREEN_LEFT = DP2
SCREEN_RIGHT = eDP1
START_DELAY = 5

renice +19 $$> / dev / null

спать $ START_DELAY

OLD_DUAL = "фиктивный"

пока [1]; делать
    DUAL = $ (cat / sys / class / drm / card0-DP-2 / status)

    if ["$ OLD_DUAL"! = "$ DUAL"]; тогда
        if ["$ DUAL" == "connected"]; тогда
            echo 'Настройка двух мониторов'
            xrandr --output $ SCREEN_LEFT --auto - вращать в нормальном режиме --pos 0x0 --output $ SCREEN_RIGHT --auto - вращать в обычном режиме - ниже $ SCREEN_LEFT
        еще
            echo 'Настройка одного монитора'
            xrandr --auto
        фи

        OLD_DUAL = "$ DUAL"
    фи

    inotifywait -q -e close / sys / class / drm / card0-DP-2 / status> / dev / null
сделанный

Лучше всего вызывать его из .xsessionrc, не забывая окончание &. Опрос xrandr дал серьезные проблемы с юзабилити на моем новом ноутбуке (мышь периодически зависала).

Balzola
источник
Я бы не подумал, что вы можете использовать inotify, /procи только выполнение inotifywait -q -e close /sys/class/drm/card0-DP-2/status действительно не заканчивалось при отключении DP-2 в моей системе
nhed
3

Я придерживался использования srandrd . Он отслеживает события X и запускает ваш сценарий, когда дисплей подключается или отключается.

scorpp
источник
0

Очевидно, что-то должно быть! Файловая система :) / sys сообщает пользовательскому пространству, какое оборудование доступно, поэтому инструменты пользовательского пространства (такие как udev или mdev) могут динамически заполнять каталог «/ dev» узлами устройства, представляющими доступное в настоящее время оборудование. Linux предоставляет два интерфейса горячего подключения: / sbin / hotplug и netlink.

В следующем файле есть небольшая демонстрация C http://www.kernel.org/doc/pending/hotplug.txt

roncsak
источник
0

В основном системное / прикладное программное обеспечение в Linux сегодня использует некоторые методы ipc для связи друг с другом. D-Bus теперь в основном используется с приложениями GNOME и может помочь.

Linux Journal:

D-BUS может облегчать отправку событий или сигналов через систему, позволяя различным компонентам системы обмениваться данными и, в конечном итоге, лучше интегрироваться. Например, демон Bluetooth может отправлять сигнал входящего вызова, который может перехватить ваш музыкальный проигрыватель, приглушая громкость до завершения вызова.

вики:

D-Bus предоставляет как системный демон (для таких событий, как «добавлено новое аппаратное устройство» или «очередь принтера изменена»), так и демон для сеанса входа в систему для каждого пользователя (для общих потребностей межпроцессного взаимодействия между пользовательскими приложениями)

Для этого есть даже библиотека Python, и Ubuntu недавно использовала эту способность, которая называется « Zeitgeist ».

Амир Нагизаде
источник
-6

Графически вы можете увидеть, распознается ли монитор Monitor, я знаю, что вы можете найти это в Ubuntu, Fedora и других в этом (или подобном) месте.

System / Preferences / монитор

И вы можете включить / выключить любой монитор или использовать оба одновременно с дублированным изображением на обоих мониторах или независимых мониторах.

Bruce_Warrior
источник
2
Он попросил о событии, которое срабатывает, когда монитор подключен / отключен
Майкл Мрозек
Вы смотрели здесь? stackoverflow.com/questions/5469828/…
Satish