在系统设置事件中运行显示相关命令

在系统设置事件中运行显示相关命令

我正在开发一个 systemd/udev 设置,我想在上游共享它,但是我无法让它以非 hacky 的方式工作。本质上,我将此脚本作为 systemd 服务的执行程序:

      ICON="somepath/dslr-camera-white.png"

      function on-display() {
          local sdisplay=$(echo $XDG_SESSION_TYPE)
          if [ "$sdisplay" == "wayland" ]; then
          local display=":$(echo $WAYLAND_DISPLAY)"
          else
          local display=":$(ls /tmp/.X11-unix/* | sed 's#/tmp/.X11-unix/X##' | head -n 1)"
          fi
          
          local user=$(who | grep '('$display')' | awk '{print $1}' | head -n 1)

          local uid=$(id -u $user)

          sudo -u $user DISPLAY=$display DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/$uid/bus "$@"
      }

      cleanup() {
          on-display notify-send -i $ICON "Disconnected" "The DSLR Camera has been turned off." --app-name="DSLR Webcam"
          trap - SIGTERM && kill -- -$$
      }

      trap cleanup SIGINT SIGTERM EXIT

      on-display notify-send -i $ICON "Connected" "The DSLR Camera has been turned on and it is ready to use." --app-name="DSLR Webcam"
      on-display yad --window-icon=$ICON --image=$ICON --no-buttons --title="DSLR Webcam" --notification --listen &

      output=$(v4l2-ctl --list-devices)
      line=$(echo "$output" | grep "Virtual Camera")
      vdevice=$(echo "$output" | sed -n "/$line/{n;s/^\t\+//p;}")
      gphoto2 --stdout --capture-movie | ffmpeg -i - -vcodec rawvideo -pix_fmt yuv420p -threads 0 -f v4l2 $vdevice

该服务的要点是当插入特定的 gphoto2 支持的相机时由 udev 规则启动,因此我有这些 udev 规则:

ACTION=="add", ATTR{idVendor}=="04a9", ATTR{idProduct}=="3218", RUN+="systemctl start dslr-webcam.service"
ACTION=="remove", ATTR{idVendor}=="04a9", ATTR{idProduct}=="3218", RUN+="systemctl stop dslr-webcam.service"

到目前为止,“好吧”,因为我已经阅读了使用RUNsystemd 服务的替代方案,但无论如何......这里的问题具体是对yad.

yad是一个允许您从 CLI 显示对话框的程序,我利用它来制作系统图标,因为我希望在相机处于活动状态时显示一个系统图标。

问题

与 不同notify-send,它可能在一些常见的套接字上工作,yad需要适当的XAUTHORITY设置才能工作,否则你会得到cannot open display: :0。在我的例子中,hacky 解决方案是简单地将其设置为正确的 Xauthority,因为我使用的是 SDDM(显示管理器),它驻留在目录中/tmp,因此我可以将其添加到脚本中:

XAUTHORITY=$(ls /tmp/xauth*)

然后它就起作用了……但这很糟糕,它做了很多假设,事实上整个on-display函数似乎也是一个坏主意。如果我把它带到不同的系统,它可能不会工作,因为适当的 Xauthority 可能在无数的地方,而且我什至还没有尝试过 Wayland(我将把它留到以后)。

关于什么xauth

我以为我可以以某种方式用来xauth检索正确的 Xauthority,但情况似乎并非如此...这个脚本是一个系统服务,所以我xauth info返回Authority file: /root/.xauthWV7OfU,并以正确的用户身份运行它sudo -u $user xauth info给我Authority file: /home/myuser/.Xauthority,但这些都不起作用当给予yad.正确的XAUTHORITY是由显示管理器设置的,所以我想我只能从它的子进程中获取它。

我也尝试过这个给出的所有方法回答,但第一个不起作用,因为XAUTHORITY实际上不在系统环境中,而第二个(除了提到的陷阱之外)不起作用,它说 xauth 文件位于/run/sddm/xauth_KvyuHd,但尝试使用它并不不起作用,所以它与 xauth 文件不同/tmp/xauth_FzoQqz

来自与上一个问题相同的问题,方法似乎有效,但我不知道它的便携性如何。而且看起来仍然很老套。


作为用户服务运行

也许这是最有前途的一个,因为该脚本中没有任何内容阻止它作为用户运行(它也摆脱了on-display),我确实尝试了这种方法,而如果相机已插入并且我运行systemctl --user start dslr-webcam.service它就会工作正如预期的那样(包括yad),现在我对规则有疑问udev。我搜索了很多地方,包括这里,但我找不到如何从udev规则运行 systemd 用户服务,对我来说这也没有任何意义,如何udev知道要使用哪个用户?

答案1

您不直接从 udev 规则运行用户服务;相反,你应该让 udev 告诉 systemd 该设备需要特定的用户服务跑步。

TAG+="systemd", ENV{SYSTEMD_USER_WANTS}="dslr-webcam.service"这样:

ACTION=="add", ATTR{idVendor}=="04a9", ATTR{idProduct}=="3218". TAG+="systemd", ENV{SYSTEMD_USER_WANTS}="dslr-webcam.service"
ACTION=="remove", ATTR{idVendor}=="04a9", ATTR{idProduct}=="3218", TAG+="systemd", ENV{SYSTEMD_USER_WANTS}="dslr-webcam.service"

由于您dslr-webcam.service需要 GUI 访问,因此它应该将自己声明为BindsTo=graphical-session.targetAfter=graphical-session.target。当以这种方式声明时,服务应该自动获取正确的 DISPLAY 和 XAUTHORITY 变量。

顺便说一下,感谢您分享您的想法;它给了我灵感去建立一些非常相似的东西......

相关内容