如何在多显示器设置中使用 xset 待机显示器?

Rav*_*ina 12 xrandr display xorg multiple-monitors xset

当有两个或多个监视器一起工作时,有没有办法通过发出如下命令将其中一个置于待机/挂起状态:xset dpms force suspend?或为此目的设置时间,例如:xset dpms 100 0 0哪些单独在这些显示器上工作?

我有两台相互配合的显示器,eDP1(我的笔记本电脑)和 VGA1(外接显示器)。

如果我不直接与他们交互,我希望他们每个人都分别进入挂起/待机模式,假设我正在 VGA1 上看电影,而 eDP1 一个半小时没有做任何事情。

我对使用不感兴趣,xrandor --off --output eDP1因为它的速度不够快。

我希望我的显示器准备好工作,只需简单的鼠标移动,我就可以在它们之间快速切换。

  • 运行:Ubuntu 18.04
  • 窗口管理器:OpenBox

Ser*_*nyy 9

使用 xset(实际上是 X11)无法控制单个显示器

正如标题所暗示的,它是不可能的原因,如何 xset将它使用X11的功能是建立和所致。如果我们查看源代码,xset调用DPMSForceLevel(dpy,DPMSModeSuspend)第 557 行),显示变量dpy来自XOpenDisplay()函数(第 203 行),根据定义

服务器及其屏幕和输入设备称为显示器。

换句话说,xset将设置全局应用于整个显示器,而不是单个屏幕。有必要更改xset源代码才能使其正常工作。DPMS 扩展本身似乎大多只调用整个显示,而不是单个屏幕,因此甚至无法使用 X11 库编写自定义代码。

通过/sys子系统手动控制该设置似乎也不起作用

$ sudo bash -c 'echo Off > /sys/class/drm/card0-VGA-1/dpms'
[sudo] password for admin: 
bash: /sys/class/drm/card0-VGA-1/dpms: Permission denied
Run Code Online (Sandbox Code Playgroud)

当发生键或鼠标事件时,屏幕也会脱离 DPMS 模式,因此考虑到您可能想要移动鼠标或使用键盘,这些操作中的任何一个都会导致显示器离开 DPMS 模式。

替代解决方法

最佳替代方案(实际上是实际工作的解决方案)是xrandr- 它可用于控制单个“输出”。特别是,

xrandr --output VGA-1 -off
Run Code Online (Sandbox Code Playgroud)

将关闭该输出。是的,您已经提到您不想使用此解决方案,因为它不够快,但到目前为止,它是最好的解决方案。它有几个优点:

  • 不受按键和鼠标事件的影响
  • 独立控制输出不同 xset

xrandr --output VGA-1 --brightness 0.1将上色以这样一种方式的屏幕,它出现了,即使--brightness是一个软件解决方案,所以显示是不实际的硬件级调光,也不是关上的硬件水平。但是,它可以使屏幕消隐,并且还可以抵抗键/鼠标事件。

我查看了 Mate 和 Budgie 屏幕保护程序的源代码,它们都是 GNOME 屏幕保护程序的分支,但是在任何一种情况下,它们似乎都是一个软件解决方案,因为源代码中没有提到 DPMS。


Jac*_*ijm 5

临时评论

  1. 应 OP 的要求,我制作了下面的脚本通过xrandr. 在更长的测试中,这很糟糕。并不是关闭失败,而是在重新激活屏幕时,屏幕布局完全混乱。我很乐意发布它以查看它是否适用于您的情况,但我的建议是不要使用它。
    在脚本中,我返回将亮度设置为零。
  2. 有一些关于我们应该通过鼠标位置还是通过活动窗口的位置来定义活动监视器讨论。如果不存在窗口,后者将不起作用。我们可能根本没有窗口(除了桌面本身),在这种情况下,选择黑屏的窗口将是随机的(如果我们不包括例外,则中断)。IMO 唯一有意义的选项 - 并且在所有情况下都以可预测的方式工作 - 是通过鼠标位置定义活动屏幕。此外,这也是窗口管理器决定新窗口出现的位置的方式。

那么我在这个版本中改变了什么?
默认情况下,空闲时间现在由键盘和鼠标活动定义。唤醒也是由任何一个完成的。


自动使非活动屏幕变暗

正如我的回答者所说,分别从 cli 关闭屏幕充其量是一个挑战,我也没有找到选项。

我找到的是一种在 x 时间后自动调所有屏幕的方法,除了鼠标所在的屏幕。

开始了

#!/usr/bin/env python3
import subprocess
import gi
gi.require_version("Gdk", "3.0")
from gi.repository import Gdk
import time
import sys


def get_idle():
    try:
        return int(subprocess.check_output("xprintidle")) / 1000
    except subprocess.CalledProcessError:
        return 0


def get_monitors():
    screen = Gdk.Screen.get_default()
    n_mons = display.get_n_monitors()
    mons = [screen.get_monitor_plug_name(i) for i in range(n_mons)]
    return mons


def set_mon_dimmed(mon, dim):
    print(mon, dim)
    val = "0.0" if dim else "1"
    try:
        subprocess.Popen(["xrandr", "--output", mon, "--brightness", val])
    except subprocess.CalledProcessError:
        print("oops")


def mousepos():
    # find out mouse location
    return Gdk.get_default_root_window().get_pointer()[1:3]


def get_currmonitor_atpos(x, y, display=None):
    """
    fetch the current monitor (obj) at position. display is optional to save
    fuel if it is already fetched elsewhere
    """
    if not display:
        display = Gdk.Display.get_default()
    return display.get_monitor_at_point(x, y)


display = Gdk.Display.get_default()
wait = int(sys.argv[1])
elapsed = 0
# set intervals to check
res = 2
monitors = [m for m in get_monitors()]
for m in monitors:
    set_mon_dimmed(m, False)

monrecord = {}
for m in monitors:
    monrecord[m] = {"idle": 0, "dimmed": False}

display = Gdk.Display.get_default()
idle1 = 0


while True:
    time.sleep(res)
    curr_mousepos = mousepos()
    activemon = get_currmonitor_atpos(
        curr_mousepos[0], curr_mousepos[1]
    ).get_model()
    idle2 = get_idle()
    if idle2 < idle1:
        monrecord[activemon]["idle"] = 0
        if monrecord[activemon]["dimmed"]:
            set_mon_dimmed(activemon, False)
            monrecord[activemon]["dimmed"] = False

    for m in monrecord.keys():
        curr_idle = monrecord[m]["idle"]
        print(m, curr_idle)
        if all([
            curr_idle > wait,
            monrecord[m]["dimmed"] is not True,
            m != activemon
        ]):
            set_mon_dimmed(m, True)
            monrecord[m]["dimmed"] = True         
        else:
            if m != activemon:
                monrecord[m]["idle"] = curr_idle + res

    idle1 = idle2
Run Code Online (Sandbox Code Playgroud)

如何设置

设置很简单:

  1. 请确保您有两个python3-gixprintidle安装

    sudo apt install python3-gi xprintidle
    
    Run Code Online (Sandbox Code Playgroud)
  2. 将上面的脚本复制到一个空文件中,另存为dim_inactive,并使其可执行

  3. 通过以下命令运行它:

    /path/to/dim_inactive <idle_time_in_seconds>
    
    Run Code Online (Sandbox Code Playgroud)

    一个例子:

    /path/to/dim_inactive 120
    
    Run Code Online (Sandbox Code Playgroud)

    将在两分钟后使鼠标不在的所有屏幕变暗

附加信息/说明

  • 该脚本在启动时列出所有屏幕
  • 它会记录每个监视器的空闲时间(可能超过 2 个)。如果显示器在 x 秒内没有被访问,它就会被黑掉,除了鼠标所在的显示器
  • 根据一个好的(但坏的)传统,Gnome 不断地破坏东西并不断改变 API。因此,在 19.04 及更高版本上运行此脚本,您将收到一些已弃用的警告。同时,它不会在 PEP8 上中断。尽管如此,仍会更新到最新的 API。


Win*_*nix 4

多年来,我对笔记本电脑的设置是这样的:当盖子关闭时,笔记本电脑将暂停,外部显示器将变为空白。

由于您想要在外部显示器上观看 90 分钟的视频并且让笔记本电脑屏幕变黑,我将盖子关闭选项更改为“不执行任何操作”:

  • 优点:当我合上笔记本电脑盖子时,所有笔记本电脑窗口都位于全屏视频下方。
  • 优点:当我打开笔记本电脑盖时,窗口会恢复并且不再位于全屏视频下方。
  • 缺点:我必须使视频非全屏才能访问顶部栏菜单才能从齿轮菜单中选择暂停。
  • 优点:当系统通过外部显示器上的菜单暂停时,打开笔记本电脑盖仍然可以恢复系统。

我没有将 DPMS 用于外部显示器,但您可以使用xset q命令检查您的设置:

$ xset q
Keyboard Control:
  auto repeat:  on    key click percent:  0    LED mask:  00000002
  XKB indicators:
    00: Caps Lock:   off    01: Num Lock:    on     02: Scroll Lock: off
    03: Compose:     off    04: Kana:        off    05: Sleep:       off
    06: Suspend:     off    07: Mute:        off    08: Misc:        off
    09: Mail:        off    10: Charging:    off    11: Shift Lock:  off
    12: Group 2:     off    13: Mouse Keys:  off
  auto repeat delay:  500    repeat rate:  33
  auto repeating keys:  00ffffffdffffbbf
                        fadfffefffedffff
                        9fffffffffffffff
                        fff7ffffffffffff
  bell percent:  50    bell pitch:  400    bell duration:  100
Pointer Control:
  acceleration:  5/1    threshold:  5
Screen Saver:
  prefer blanking:  yes    allow exposures:  yes
  timeout:  0    cycle:  0
Colors:
  default colormap:  0xb3    BlackPixel:  0x0    WhitePixel:  0xffffff
Font Path:
  /usr/share/fonts/X11/misc,/usr/share/fonts/X11/Type1,built-ins
DPMS (Energy Star):
  Standby: 0    Suspend: 0    Off: 0
  DPMS is Disabled
Run Code Online (Sandbox Code Playgroud)

注意这些行:

Screen Saver:
  prefer blanking:  yes
Run Code Online (Sandbox Code Playgroud)
  • 你可能想要prefer blanking: no

另请注意这些行:

DPMS (Energy Star):
  Standby: 0    Suspend: 0    Off: 0
  DPMS is Disabled
Run Code Online (Sandbox Code Playgroud)
  • 您可能希望在需要时DPMS is enabled将监视器设置为Standby

希望其他用户已经使用过这些选项并为您发布详细的答案。


Fab*_*bby 3

简单地关闭笔记本电脑怎么样?

为什么?

这两台显示器是一个显示区域,因此关闭其中一台会产生许多问题,例如屏幕重绘、应用程序移至主显示器......

(几年前我就走上了这条路,我发现做你想做的事情的唯一可靠的方法是按下外部显示器上的按钮或关闭笔记本电脑)

只需确保您使用以下命令设置这些电源设置gsettings set

org.gnome.settings-daemon.plugins.power lid-close-suspend-with-external-monitor false
org.gnome.settings-daemon.plugins.power lid-close-ac-action 'nothing'
org.gnome.settings-daemon.plugins.power lid-close-battery-action 'nothing'
Run Code Online (Sandbox Code Playgroud)