14

While having two or more monitor working together, Is there any way to put a single one of them on standby/suspend by issuing a command like: xset dpms force suspend? or having a time set for that purpose like: xset dpms 100 0 0 which works on these monitors separately?

I've got two monitor working along each other, eDP1 (My Laptop) and VGA1 (An External monitor).

I want each of them to go into suspend/standby mode separately if I'm not directly interacting with them, suppose I'm watching a movie on VGA1, and for an hour and half eDP1 is on doing nothing.

I'm not interested in using xrandor --off --output eDP1 because it's not fast enough to work with.

I want my monitor to be ready to work, with a simple mouse movement so I'm able to switch between them fast.

  • Running: Ubuntu 18.04
  • Window Manager: OpenBox
14
  • Is it for energy reasons, or would a visual solution do? Mar 28, 2019 at 11:38
  • @Ravexina Question, how far does your eDP1 backlight go ? Does it turn off brightness all the way ? If yes, could you please test the two commands I had in askubuntu.com/a/814043/295286 answer ? Thank you in advance for the response Mar 28, 2019 at 21:58
  • 1
    @Ravexina done, seems to work flawlessly, but will keep it running for a day, will post it late tonight. It will keep record on activity per screen, but never dim/switch off screen wher the mouse currently is, right? Mar 29, 2019 at 7:59
  • 1
    OK, well I'll probably try to implement Window tracking on the weekend then. Sadly I don't have that much time to deal with these things right now. Mar 29, 2019 at 12:01
  • 1
    @Ravexina, thanks. I will probably post another (vala) version soon, triggered by either active window or (if there is no valid window) by mouse action. Also will see if we can do something with backlight, which will probably also save some energy. The time during bonus simply is too short, but the question is intersting enough to play a little further. To be continued. Thanks once again. Mar 31, 2019 at 14:51

5 Answers 5

10

Controlling individual monitors is not possible with xset ( and X11 actually)

As the title suggests, it is not possible for reasons of how xset is built and due to the X11 functions it uses. If we look at the source code, xset calls DPMSForceLevel(dpy,DPMSModeSuspend) (line 557), and the display variable dpy comes from XOpenDisplay() function ( line 203 ), and that is by definition:

A server, together with its screens and input devices, is called a display.

In other words, xset applies settings globally to the whole display, not individual Screens. It'd be necessary to change xset source code in order for that to work. DPMS extensions themselves mostly seem to only call whole display, not individual screens, so it is not possible to even write custom code with X11 library.

Manually controlling that setting via /sys subsystem also doesn't appear to be working

$ 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

Screens also are taken out of DPMS mode when key or mouse events occur, so considering that you may want to move your mouse or use keyboard, either of those actions would cause the monitor to leave DPMS mode.

Alternative workarounds

Best alternative (and actually physically working solution) is xrandr - it could be used to control the individual "outputs". In particular,

xrandr --output VGA-1 -off

will set that output off. Yes, you've mentioned that you don't want to use this solution since it is not fast enough, however so far it is the best one available. It has couple of advantages:

  • immune to key and mouse events
  • independently controls outpus unlike xset

The xrandr --output VGA-1 --brightness 0.1 will colorize the screen in such way that it appears off, even though --brightness is a software solution, so the display is not actually dimmed at hardware level, nor it is off on hardware level. However, it does the job of blanking a screen and is also resistant to key/mouse events.

I've looked source code of Mate and Budgie screensavers, which are both forks of GNOME screensaver, however in either case they seem to be a software solution, since there's no mention of DPMS in the source code.

7
  • I like the alternatives... +1
    – Fabby
    Mar 26, 2019 at 22:47
  • 1
    @Fabby Thanks :) So far that's the best alternatives available Mar 26, 2019 at 23:04
  • I think the Window Managers are doing some tricks and might provide some hooks. There is a stack exchange site called "Software Design" and it might be a good place to float the idea that when a major window (like a web browser but not Conky or top bar displaying time) has no pixel changes over say 10 minutes the whole monitor (just a single one) starts to dim over 30 seconds until it's completely black. Then navigating the mouse over that monitor (I typically use 3 monitors) restores brightness gradually over a 1 to 5 second period. Mar 31, 2019 at 20:26
  • @WinEunuuchs2Unix I have an idea and there are a few things to watch for, but it's tricky, and yes depends on window manager in question. Problem is the DPMS. It's either dim everything or nothing with DPMS. Best we can do is xrandr --off for now Mar 31, 2019 at 20:39
  • My DPMS knowledge is limited. I think it's a save electricity thing for standy/sleep. There is also HDMI-CEC which might give same results but that is even more of a black hole of magic to me. I don't know if xrandr -off even turns off the monitor. It might be the same as brightness set to zero? Which is another issue I have a program running 24/7 which sets brightness and gamma individually for 3 monitors which even Windows can't do. Not sure if night light, red shift or flux do it. Anyway those programs might get messed up by xrandr off. Sorry for hijacking your answer with speculating:) Mar 31, 2019 at 21:09
5
+100

Temporary comment

  1. On request of OP, I made the script below switch the screen off by means of xrandr. On a longer test, this worked out pretty badly. Not so much the switching off failed, but at reactivating the screen, screen layout was totally messed up. I'd be happy to post it to see if it works in your case however, but my advice is not to use it.
    In the script, I went back to setting brightness to zero instead.
  2. There was some discussion on wether we should define the active monitor by mouse location, or by location of the active window. The latter will not work if no window exists. We might not have a window at all (apart from the desktop itself) in which case the choice of window to black out would be random (or break if we won't include the exception). IMO the only option that makes sense -and would work in a predictable way in all cases- is to define the active screen by mouse position. Furthermore, that is also how the window manager decides where new windows should appear.

Then what did I change in this version?
The idle time is now defined by both keyboard- and mouse activity by default. Waking up is also done by either one.


Automatically dim inactive screen

As said by my fellow answerers, switching screens off from cli separately is a challenge at best, and I didn't find an option either.

What I did find is a way to automatically dim all screens, except the one where the mouse is, after x time.

Here we go

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

How to set up

Set up is straightforward:

  1. Make sure you have both python3-gi and xprintidle installed

    sudo apt install python3-gi xprintidle
    
  2. Copy the script above into an empty file, save it as dim_inactive, and make it executable

  3. Run it by the command:

    /path/to/dim_inactive <idle_time_in_seconds>
    

    an example:

    /path/to/dim_inactive 120
    

    will dim all screens where the mouse is not after two minutes

Additional information / explanation

  • The script lists all screens on startup
  • It keeps record if idle time per monitor (possibly more than 2). If a monitor isn't accessed for x seconds, it is blacked out, apart from the monitor where the mouse is.
  • According to a good (but bad) tradition, Gnome keeps breaking stuff and keeps changing API's. As a result, running this script on 19.04 and above, You'll get a few deprecated warnings. At the same time, it doesn't break on PEP8. Will nevertheless update to the latest API's.
7
  • Very nice, almost tempted to write something like that as well. But I guess that's the repeated theme here - so far there's nothing better than dimming the other display via software solutions, nothing hardware-ish Mar 28, 2019 at 21:51
  • @SergiyKolodyazhnyy Nah, only backlight would add something, but that's it as far as I can see now. Think something should be possible, but will probably have a cold start, just like xrandr --off I guess. Mar 28, 2019 at 21:54
  • @JacobVlijm Yeah, xrandr --off is what I'd prefer in this case. Especially since VGA backlight cannot be software-controlled. Mar 28, 2019 at 22:00
  • 1
    Thank you for all your efforts, But I'm getting the weirdest behaviors... For example: It dim the monitors but does not reset the brightness back to 1 at any circumstances. When I'm interacting with external display using keyboard and while mouse is in the main display, the external one goes black after idle time. When I don't have any interact with main display but mouse is there it does nothing there and when I move the mouse to other display main one imminently goes black.
    – Ravexina
    Mar 30, 2019 at 9:13
  • @Ravex (1) are your monitors mirrored? If not, you might have stopped the script with second screen balnked. Fixed that now. (2) Why active screen is defined my mousepos is explained in [2] of the temporary comment (3) Should also be fixed with the changes in (1) (same cause) Huh, no, need to reset idle time, will do that later today. Mar 30, 2019 at 9:50
4

For years I had my laptop setup such that when lid is closed laptop would suspend and external monitors would go blank.

For your reason of wanting to watch a video for 90 minutes on external monitor and have laptop screen go blank I changed lid close option to "Do Nothing":

  • Advantage: When I close Laptop lid all Laptop windows go below full screen video.
  • Advantage: When I open Laptop lid windows are restored and are no longer below full screen video.
  • Disadvantage: I have to make video non-full screen to access top bar menu to select suspend from gear menu.
  • Advantage: When system is suspended by menu on external monitor, opening laptop lid still resumes system.

I'm not using DPMS for external monitors but you could check your settings with xset q command:

$ 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

Notice these lines:

Screen Saver:
  prefer blanking:  yes
  • You would likely want prefer blanking: no

Also notice these lines:

DPMS (Energy Star):
  Standby: 0    Suspend: 0    Off: 0
  DPMS is Disabled
  • You would likely want DPMS is enabled to set monitor to Standby when desired.

Hopefully other users have used these options and post a detailed answer for you.

0
3

How about simply closing the laptop?

Why?

These two monitors are one display area so turning one off will create a number of issues like screen redrawing, applications moving to the main monitor, ...

(I went down that road a few years ago and the only reliable way I found of doing what you want to do is to push the button on the external monitor or close the laptop)

Just ensure you set these power settings with 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'
1
  • Actually, this is a nice solution. Hardware, plus this can be scripted. However, OP is using Openbox, which suggests gsettings might not take effect. For good alternative, you may want to include unix.stackexchange.com/a/52645/85039 Mar 27, 2019 at 0:32
0

If the monitor has ddc that can work - it's relatively slow, too, but about the only way to reduce power in a ccfl backlit monitor without xrandr. Unfortunately only half of my monitors implement it.

$ ddccontrol dev:/dev/i2c-4
...
        > Power control
                > id=dpms, name=DPMS Control, address=0xd6, delay=-1ms, type=2
                  Possible values:
                        > id=on - name=On, value=1
                        > id=standby - name=Standby, value=4
...

You can easily connect i2c buses to outputs looking at the /sys/class/drm/card* directories Sergiy mentioned above (i. e. their i2c* subdirs).

So, "ddccontrol dev:/dev/i2c-4 -r 0xd6 -w 4" sets it to Standby, "ddccontrol dev:/dev/i2c-4 -r 0xd6 -w 1" sets it to On again.

I have cronjobs set up including getIdle from https://github.com/IonicaBizau/screensaver/blob/master/getIdle.c which gives the X idle time in ms.

You should probably add your user to the i2c group or otherwise enable access to the ddc buses.

One other quirk: while the ddc control is labeled "Power", at least with my monitor I can't use it to determine the actual power status - if I turn the monitor off manually, it still says "On" and I can't turn it on via i2c.

0

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .