SDL_PollEvent导致xset dpms强制关闭后屏幕唤醒

SDL_PollEvent causes screen to wake up after xset dpms force off

本文关键字:屏幕 唤醒 PollEvent 导致 xset dpms SDL      更新时间:2023-10-16

我有一个程序,可以用xset dpms force on/off打开和关闭屏幕,并在循环中调用SDL_PollEvent(&e)。在用xset关闭显示后,任何对SDL_PollEvent的调用都会导致屏幕唤醒,即使没有任何输入。我可以注释出SDL_PollEvent调用,它不会发生。我是否需要做一些事情来处理事件或阻止屏幕打开?用最少的代码更新以重现问题:

#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 OFFn";
            SCREEN_ON = false;
            exec("sleep 1 && xset -display :0.0 dpms force off");
        }
        if ((!SCREEN_ON) && SERVER_CONNECTED) {
            cout << "TURNING SCREEN ONn";
            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;
}

exec("sleep 1 && xset -display :0.0 dpms force off");之后不久,在下一次调用将其重新打开之前,屏幕将自行打开。

别介意,SDL_PollEvent只能在主线程中调用。

呼叫SDL_EnableScreenSaver()

更多信息:

为什么SDL默认禁用我的屏保?

许多使用SDL的应用程序是游戏、屏保或媒体播放器用户要么长时间观看某样东西,要么长时间观看某样东西时间或使用摇杆输入,一般不防止屏保启动

您可以通过设置环境变量来禁用此行为:SDL_VIDEO_ALLOW_SCREENSAVER=1可以为用户或全局设置

在SDL 2.0.2中,这也可以通过设置提示来更改SDL_HINT_VIDEO_ALLOW_SCREENSAVER .

另外,SDL 2.0提供了SDL_EnableScreenSaver()函数。