brobocop brobocop - 1 month ago 12
Linux Question

SDL_PollEvent causes screen to wake up after xset dpms force off

I have a program that turns the screen on and off with

xset dpms force on/off
and also calls
SDL_PollEvent(&e)
in a loop. After turning the display off with
xset
, any call to
SDL_PollEvent
causes the screen to wake up, even without any input. I can comment out the
SDL_PollEvent
call and it doesn't happen. Is there something I need to do with an event or something to prevent the screen from turning on? Updated with minimal code to reproduce the problem:

#include <GL/glew.h>
#include <SDL2/SDL.h>
#include <atomic>
#include <iostream>
#include <thread>
using namespace std;
atomic<bool> SCREEN_ON(true);
atomic<bool> RUNNING(true);
atomic<bool> SERVER_CONNECTED(false);

std::string exec(const char *cmd) {
char buffer[128];
std::string result = "";
std::shared_ptr<FILE> pipe(popen(cmd, "r"), pclose);
if (!pipe)
throw std::runtime_error("popen() failed!");
while (!feof(pipe.get())) {
if (fgets(buffer, 128, pipe.get()) != NULL)
result += buffer;
}
return result;
}
double get_time() {
static const Uint64 freq = SDL_GetPerformanceFrequency();
static const Uint64 begin_time = SDL_GetPerformanceCounter();
Uint64 current = SDL_GetPerformanceCounter();
Uint64 elapsed = current - begin_time;
return (double)elapsed / (double)freq;
}

void handle_input() {
SDL_Event e;
while (SDL_PollEvent(&e)){}
}

void monitor_thread() {
while (RUNNING) {
double time = get_time();
if (time < 15)
SERVER_CONNECTED = false;
else if (time < 35)
SERVER_CONNECTED = true;
else
SERVER_CONNECTED = false;

cout << "server status: " << SERVER_CONNECTED << endl;
cout << "screen_on status: " << SCREEN_ON << endl;

handle_input();
SDL_Delay(1000);

if (SCREEN_ON && (!SERVER_CONNECTED)) {
cout << "TURNING SCREEN OFF\n";
SCREEN_ON = false;
exec("sleep 1 && xset -display :0.0 dpms force off");
}
if ((!SCREEN_ON) && SERVER_CONNECTED) {
cout << "TURNING SCREEN ON\n";
SCREEN_ON = true;
exec("sleep 1 && xset -display :0.0 dpms force on");
}
}
}

int main(int argc, char *argv[]) {
Uint32 initflags = SDL_INIT_TIMER | SDL_INIT_VIDEO;
SDL_Init(initflags);
Uint32 window_flags =
SDL_WINDOW_FULLSCREEN | SDL_WINDOW_OPENGL | SDL_WINDOW_INPUT_GRABBED;
SDL_Window *window =
SDL_CreateWindow("title", 25, 25, 800, 600, window_flags);
SDL_SetRelativeMouseMode(SDL_TRUE);
SDL_EnableScreenSaver();
SDL_GLContext gl_context = SDL_GL_CreateContext(window);
glewInit();
thread update_thread(monitor_thread);
glClearColor(1, 1, 0, 0);
glClear(GL_COLOR_BUFFER_BIT);
while (RUNNING) {
if (!SCREEN_ON) {
cout << "zzz...\n";
SDL_Delay(2000);
continue;
}
glClear(GL_COLOR_BUFFER_BIT);
SDL_Delay(16);
SDL_GL_SwapWindow(window);
}
return 0;
}


The screen will turn itself back on very shortly after
exec("sleep 1 && xset -display :0.0 dpms force off");
, before the next call to turn it back on.


Nevermind, SDL_PollEvent can only be called in the main thread.

Answer

Call SDL_EnableScreenSaver().

More info:

Why does SDL disable my screensaver by default?

Many applications using SDL are games or screensavers or media players where the user is either watching something for an extended period of time or using joystick input which generally does not prevent the screensaver from kicking on.

You can disable this behavior by setting the environment variable: SDL_VIDEO_ALLOW_SCREENSAVER=1 This can be set globally for the user or on a per-application basis in code.

In SDL 2.0.2 this can also be changed by setting the hint SDL_HINT_VIDEO_ALLOW_SCREENSAVER.

Additionally, SDL 2.0 provides the function SDL_EnableScreenSaver().

Comments