0

I am trying to block the function XNextEvent from returning when DPMS is actively blanking the screen, so that I do not receive keyboard or mouse inputs while my screen is black.

I want to block the function from returning entirely, because I have already tried to query DPMS for its state once the function returns, but it seems that the DPMS system is somehow processing all of my inputs before X receives them, because every query within XNextEvent is telling me that DPMS is no longer blanking:

while (running && !XNextEvent(dpy, &ev))
{
    if (!DPMSInfo(dpy, &pwr, &state))
    {
        fprintf(stderr, "%s: DPMSInfo failed!\n", argv[0]);
        running = 0;
    }
    else if (!state || pwr == DPMSModeOn)
    {
        // sans a critical error, this will ALWAYS return true
        // regardless of the current state of the screen
        if (ev.type == KeyPress)
        {
            // now I am handling keyboard input
            // while the screen is still potentially blank
        }
    }

}

Is there some underlying feature of DPMS or X that will block all inputs while blanked, and require at least one input to awaken the display before continuing to listen to them?

agregate
  • 163
  • 6
  • X server receives events from libinput and sends it to your application, not vice versa. You can disable input device before enabling DPMS, e.g. win `xinput` command. – dimich Sep 27 '22 at 04:10
  • @dimich Yes, there is the function `XIChangeProperty` for that, but then I need to be able to hook into DPMS to detect when it is disabled again. How would I do this? – agregate Sep 27 '22 at 04:53
  • I researched xorg sources some time ago and haven't found API for detecting DPMS state change. But in my case it wasn't necessary. In your case, if you want to catch DPMS event by inactivity timeout, i guess monitor state polling would be a solution. But maybe someone can give better advice. – dimich Sep 27 '22 at 05:00
  • @dimich I might look into that. Thank you. – agregate Sep 27 '22 at 05:04
  • 1
    @dimich Turns out DPMS is caught by `XNextEvent` with the `XScreenSaver` extension. See my answer below. – agregate Sep 27 '22 at 06:21

1 Answers1

1

I've found a way to make use of the XScreenSaver extension by reading the code for the xssstart program:

if (!XScreenSaverQueryExtension(dpy, &evbase, &errbase))
    die("failed to query XScreenSaver extension!\n");

XScreenSaverSelectInput(dpy, DefaultRootWindow(dpy), ScreenSaverNotifyMask);

int ready = 1;

while (running && !XNextEvent(dpy, &ev))
{
    if (((XScreenSaverNotifyEvent *) &ev)->state == ScreenSaverOn)
    {
        ready = 0; // DPMS is now blanking
        XUngrabKeyboard(dpy, CurrentTime);
    }
    else if (((XScreenSaverNotifyEvent *) &ev)->state == ScreenSaverOff)
    {
        ready = 1; // DPMS is no longer blanking
        XGrabKeyboard(dpy, win, True, GrabModeAsync, GrabModeAsync, CurrentTime);
    }
    if (ready && ev.type == KeyPress)
    {
        // now I am only handling keyboard input when not blanked
    }
}

Note that the major drawback of this solution is that when the keyboard is relinquished, the keyboard input will be fed into any other random application in the background (in the case of a screen locker such as slock). This is ultimately the subject of another question though. I might be able to focus on a fake window and purge the input there...

agregate
  • 163
  • 6