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/Xrandr.h>
#include "osdep/atomic.h"
#include "config.h"
#include "misc/bstr.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_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 vo_x11_selectinput_witherr(struct vo *vo, Display *display,
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)
{
struct vo_x11_state *x11 = arg;
bool suspend = false;
bool run = true;
for (;;) {
sem_wait(&x11->screensaver_sem);
// don't queue multiple wakeups
while (!sem_trywait(&x11->screensaver_sem)) {}
while (run) {
pthread_mutex_lock(&x11->screensaver_thread_lock);
bool suspend_new = suspend;
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))
break;
if (!run) {
suspend_new = false; // make sure to resume on exit
if (suspend == suspend_new)
break;
}
char *args[] = {"xdg-screensaver", "reset", NULL};
int status = mp_subprocess(args, NULL, NULL, mp_devnull, mp_devnull, &(char*){0});
char *args[] = {"xdg-screensaver", suspend_new ? "suspend" : "resume",
mp_tprintf(32, "%lx", x11->screensaver_thread_window),
NULL};
int status = mp_subprocess(args, NULL, NULL, mp_devnull, mp_devnull,
&(char*){0});
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);
break;
}
suspend = suspend_new;
}
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)
{
struct mp_vo_opts *opts = vo->opts;
@ -544,12 +581,8 @@ int vo_x11_init(struct vo *vo)
};
vo->x11 = x11;
sem_init(&x11->screensaver_sem, 0, 0);
if (pthread_create(&x11->screensaver_thread, NULL, screensaver_thread, x11)) {
sem_destroy(&x11->screensaver_sem);
goto error;
}
x11->screensaver_thread_running = true;
pthread_mutex_init(&x11->screensaver_thread_lock, NULL);
pthread_cond_init(&x11->screensaver_thread_wakeup, NULL);
x11_error_output = x11->log;
XSetErrorHandler(x11_errorhandler);
@ -773,12 +806,16 @@ void vo_x11_uninit(struct vo *vo)
}
if (x11->screensaver_thread_running) {
atomic_store(&x11->screensaver_terminate, true);
sem_post(&x11->screensaver_sem);
pthread_mutex_lock(&x11->screensaver_thread_lock);
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);
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) {
close(x11->wakeup_pipe[0]);
close(x11->wakeup_pipe[1]);
@ -1041,8 +1078,6 @@ void vo_x11_check_events(struct vo *vo)
Display *display = vo->x11->display;
XEvent Event;
xscreensaver_heartbeat(vo->x11);
while (XPending(display)) {
XNextEvent(display, &Event);
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_xembed_update(x11, 0);
screensaver_thread_update(x11);
}
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]);
}
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)
{
Display *mDisplay = x11->display;
@ -1917,6 +1942,7 @@ static void set_screensaver(struct vo_x11_state *x11, bool enabled)
return;
MP_VERBOSE(x11, "%s screensaver.\n", enabled ? "Enabling" : "Disabling");
x11->screensaver_enabled = enabled;
screensaver_thread_update(x11);
int nothing;
if (DPMSQueryExtension(mDisplay, &nothing, &nothing)) {
BOOL onoff = 0;

View File

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