x11: use xdg-screensaver suspend/resume

If it doesn't work this time, I'll remove all X11 screensaver code.

Fixes #4763.
This commit is contained in:
wm4 2017-08-15 20:32:44 +02:00
parent 34ab0386cb
commit 6694048272
2 changed files with 64 additions and 39 deletions

View File

@ -37,6 +37,8 @@
#include <X11/extensions/Xinerama.h> #include <X11/extensions/Xinerama.h>
#include <X11/extensions/Xrandr.h> #include <X11/extensions/Xrandr.h>
#include "osdep/atomic.h"
#include "config.h" #include "config.h"
#include "misc/bstr.h" #include "misc/bstr.h"
#include "options/options.h" #include "options/options.h"
@ -135,7 +137,6 @@ static atomic_int x11_error_silence;
static void vo_x11_update_geometry(struct vo *vo); static void vo_x11_update_geometry(struct vo *vo);
static void vo_x11_fullscreen(struct vo *vo); static void vo_x11_fullscreen(struct vo *vo);
static void xscreensaver_heartbeat(struct vo_x11_state *x11);
static void set_screensaver(struct vo_x11_state *x11, bool enabled); static void set_screensaver(struct vo_x11_state *x11, bool enabled);
static void vo_x11_selectinput_witherr(struct vo *vo, Display *display, static void vo_x11_selectinput_witherr(struct vo *vo, Display *display,
Window w, long event_mask); Window w, long event_mask);
@ -503,27 +504,63 @@ static void vo_x11_get_bounding_monitors(struct vo_x11_state *x11, long b[4])
static void *screensaver_thread(void *arg) static void *screensaver_thread(void *arg)
{ {
struct vo_x11_state *x11 = arg; struct vo_x11_state *x11 = arg;
bool suspend = false;
bool run = true;
for (;;) { while (run) {
sem_wait(&x11->screensaver_sem); pthread_mutex_lock(&x11->screensaver_thread_lock);
// don't queue multiple wakeups bool suspend_new = suspend;
while (!sem_trywait(&x11->screensaver_sem)) {} for (;;) {
run = x11->screensaver_thread_running;
suspend_new = x11->screensaver_thread_suspend;
if (!run || suspend != suspend_new)
break;
pthread_cond_wait(&x11->screensaver_thread_wakeup,
&x11->screensaver_thread_lock);
}
pthread_mutex_unlock(&x11->screensaver_thread_lock);
if (atomic_load(&x11->screensaver_terminate)) if (!run) {
break; suspend_new = false; // make sure to resume on exit
if (suspend == suspend_new)
break;
}
char *args[] = {"xdg-screensaver", "reset", NULL}; char *args[] = {"xdg-screensaver", suspend_new ? "suspend" : "resume",
int status = mp_subprocess(args, NULL, NULL, mp_devnull, mp_devnull, &(char*){0}); mp_tprintf(32, "%lx", x11->screensaver_thread_window),
NULL};
int status = mp_subprocess(args, NULL, NULL, mp_devnull, mp_devnull,
&(char*){0});
if (status) { if (status) {
MP_VERBOSE(x11, "Disabling screensaver failed (%d). Make sure the " MP_VERBOSE(x11, "Updating screensaver failed (%d). Make sure the "
"xdg-screensaver script is installed.\n", status); "xdg-screensaver script is installed.\n", status);
break; break;
} }
suspend = suspend_new;
} }
return NULL; return NULL;
} }
static void screensaver_thread_update(struct vo_x11_state *x11)
{
if (!x11->screensaver_thread_running && x11->window) {
x11->screensaver_thread_window = x11->window;
x11->screensaver_thread_running = true;
if (pthread_create(&x11->screensaver_thread, NULL, screensaver_thread, x11))
x11->screensaver_thread_running = false;
}
if (!x11->screensaver_thread_running)
return;
pthread_mutex_lock(&x11->screensaver_thread_lock);
x11->screensaver_thread_suspend = !x11->screensaver_enabled;
pthread_cond_signal(&x11->screensaver_thread_wakeup);
pthread_mutex_unlock(&x11->screensaver_thread_lock);
}
int vo_x11_init(struct vo *vo) int vo_x11_init(struct vo *vo)
{ {
struct mp_vo_opts *opts = vo->opts; struct mp_vo_opts *opts = vo->opts;
@ -544,12 +581,8 @@ int vo_x11_init(struct vo *vo)
}; };
vo->x11 = x11; vo->x11 = x11;
sem_init(&x11->screensaver_sem, 0, 0); pthread_mutex_init(&x11->screensaver_thread_lock, NULL);
if (pthread_create(&x11->screensaver_thread, NULL, screensaver_thread, x11)) { pthread_cond_init(&x11->screensaver_thread_wakeup, NULL);
sem_destroy(&x11->screensaver_sem);
goto error;
}
x11->screensaver_thread_running = true;
x11_error_output = x11->log; x11_error_output = x11->log;
XSetErrorHandler(x11_errorhandler); XSetErrorHandler(x11_errorhandler);
@ -773,12 +806,16 @@ void vo_x11_uninit(struct vo *vo)
} }
if (x11->screensaver_thread_running) { if (x11->screensaver_thread_running) {
atomic_store(&x11->screensaver_terminate, true); pthread_mutex_lock(&x11->screensaver_thread_lock);
sem_post(&x11->screensaver_sem); x11->screensaver_thread_running = false;
pthread_cond_signal(&x11->screensaver_thread_wakeup);
pthread_mutex_unlock(&x11->screensaver_thread_lock);
pthread_join(x11->screensaver_thread, NULL); pthread_join(x11->screensaver_thread, NULL);
sem_destroy(&x11->screensaver_sem);
} }
pthread_mutex_destroy(&x11->screensaver_thread_lock);
pthread_cond_destroy(&x11->screensaver_thread_wakeup);
if (x11->wakeup_pipe[0] >= 0) { if (x11->wakeup_pipe[0] >= 0) {
close(x11->wakeup_pipe[0]); close(x11->wakeup_pipe[0]);
close(x11->wakeup_pipe[1]); close(x11->wakeup_pipe[1]);
@ -1041,8 +1078,6 @@ void vo_x11_check_events(struct vo *vo)
Display *display = vo->x11->display; Display *display = vo->x11->display;
XEvent Event; XEvent Event;
xscreensaver_heartbeat(vo->x11);
while (XPending(display)) { while (XPending(display)) {
XNextEvent(display, &Event); XNextEvent(display, &Event);
MP_TRACE(x11, "XEvent: %d\n", Event.type); MP_TRACE(x11, "XEvent: %d\n", Event.type);
@ -1424,6 +1459,8 @@ static void vo_x11_create_window(struct vo *vo, XVisualInfo *vis,
vo_x11_set_property_utf8(vo, XA(x11, _GTK_THEME_VARIANT), "dark"); vo_x11_set_property_utf8(vo, XA(x11, _GTK_THEME_VARIANT), "dark");
} }
vo_x11_xembed_update(x11, 0); vo_x11_xembed_update(x11, 0);
screensaver_thread_update(x11);
} }
static void vo_x11_map_window(struct vo *vo, struct mp_rect rc) static void vo_x11_map_window(struct vo *vo, struct mp_rect rc)
@ -1898,18 +1935,6 @@ void vo_x11_wait_events(struct vo *vo, int64_t until_time_us)
mp_flush_wakeup_pipe(x11->wakeup_pipe[0]); mp_flush_wakeup_pipe(x11->wakeup_pipe[0]);
} }
static void xscreensaver_heartbeat(struct vo_x11_state *x11)
{
double time = mp_time_sec();
if (x11->display && !x11->screensaver_enabled &&
(time - x11->screensaver_time_last) >= 10)
{
x11->screensaver_time_last = time;
sem_post(&x11->screensaver_sem);
}
}
static void set_screensaver(struct vo_x11_state *x11, bool enabled) static void set_screensaver(struct vo_x11_state *x11, bool enabled)
{ {
Display *mDisplay = x11->display; Display *mDisplay = x11->display;
@ -1917,6 +1942,7 @@ static void set_screensaver(struct vo_x11_state *x11, bool enabled)
return; return;
MP_VERBOSE(x11, "%s screensaver.\n", enabled ? "Enabling" : "Disabling"); MP_VERBOSE(x11, "%s screensaver.\n", enabled ? "Enabling" : "Disabling");
x11->screensaver_enabled = enabled; x11->screensaver_enabled = enabled;
screensaver_thread_update(x11);
int nothing; int nothing;
if (DPMSQueryExtension(mDisplay, &nothing, &nothing)) { if (DPMSQueryExtension(mDisplay, &nothing, &nothing)) {
BOOL onoff = 0; BOOL onoff = 0;

View File

@ -24,9 +24,6 @@
#include <X11/Xlib.h> #include <X11/Xlib.h>
#include <X11/Xutil.h> #include <X11/Xutil.h>
#include "osdep/atomic.h"
#include "osdep/semaphore.h"
#include "common/common.h" #include "common/common.h"
struct vo; struct vo;
@ -66,11 +63,13 @@ struct vo_x11_state {
bool screensaver_enabled; bool screensaver_enabled;
bool dpms_touched; bool dpms_touched;
double screensaver_time_last;
long screensaver_thread_window;
pthread_t screensaver_thread; pthread_t screensaver_thread;
pthread_mutex_t screensaver_thread_lock;
pthread_cond_t screensaver_thread_wakeup;
bool screensaver_thread_running; bool screensaver_thread_running;
sem_t screensaver_sem; bool screensaver_thread_suspend;
atomic_bool screensaver_terminate;
XIM xim; XIM xim;
XIC xic; XIC xic;