x11: actually disable screensaver

We already use 2 screensaver APIs when attempting to disable the
screensaver: XResetScreenSaver() (from xlib) and XScreenSaverSuspend
(from the X11 Screen Saver extension). None of these actually work.

On modern desktop Linux, we are expected to make dbus calls using some
freedesktop-defined protocol (and possibly we'd have to fallback to a
Gnome specific one). At least xscreensaver doesn't respect the "old"
APIs either.

Solve this by running the xdg-screensaver script. It's a terrible, ugly
piece of shit (just read the script if you disagree), but at least it
appears to work everywhere. It's also simpler than involving various
dbus client libraries.

I hope this can replace the --heartbeat-cmd option, and maybe we could
remove our own DPMS/XSS code too.
This commit is contained in:
wm4 2015-04-15 22:39:01 +02:00
parent e6d7e55012
commit dd12040ebe
2 changed files with 61 additions and 12 deletions

View File

@ -38,6 +38,10 @@
#include "vo.h"
#include "win_state.h"
#include "osdep/timer.h"
#include "osdep/subprocess.h"
// Specifically for mp_cancel
#include "stream/stream.h"
#include <X11/Xmd.h>
#include <X11/Xlib.h>
@ -470,6 +474,30 @@ static void vo_x11_get_bounding_monitors(struct vo_x11_state *x11, long b[4])
#endif
}
static void *screensaver_thread(void *arg)
{
struct vo_x11_state *x11 = arg;
for (;;) {
sem_wait(&x11->screensaver_sem);
// don't queue multiple wakeups
while (!sem_trywait(&x11->screensaver_sem)) {}
if (mp_cancel_test(x11->screensaver_terminate))
break;
char *args[] = {"xdg-screensaver", "reset", NULL};
if (mp_subprocess(args, x11->screensaver_terminate, NULL, NULL,
NULL, &(char*){0}))
{
MP_WARN(x11, "Disabling screensaver failed.\n");
break;
}
}
return NULL;
}
int vo_x11_init(struct vo *vo)
{
struct mp_vo_opts *opts = vo->opts;
@ -487,6 +515,14 @@ int vo_x11_init(struct vo *vo)
};
vo->x11 = x11;
x11->screensaver_terminate = mp_cancel_new(x11);
sem_init(&x11->screensaver_sem, 0, 0);
if (pthread_create(&x11->screensaver_thread, NULL, screensaver_thread, x11)) {
x11->screensaver_terminate = NULL;
sem_destroy(&x11->screensaver_sem);
goto error;
}
x11_error_output = x11->log;
XSetErrorHandler(x11_errorhandler);
@ -498,13 +534,7 @@ int vo_x11_init(struct vo *vo)
if (!x11->display) {
MP_MSG(x11, vo->probing ? MSGL_V : MSGL_ERR,
"couldn't open the X11 display (%s)!\n", dispName);
x11_error_output = NULL;
XSetErrorHandler(NULL);
talloc_free(x11);
vo->x11 = NULL;
return 0;
goto error;
}
x11->screen = DefaultScreen(x11->display); // screen ID
x11->rootwin = RootWindow(x11->display, x11->screen); // root window ID
@ -543,6 +573,10 @@ int vo_x11_init(struct vo *vo)
vo_x11_update_geometry(vo);
return 1;
error:
vo_x11_uninit(vo);
return 0;
}
static const struct mp_keymap keymap[] = {
@ -691,9 +725,18 @@ void vo_x11_uninit(struct vo *vo)
MP_VERBOSE(x11, "uninit ...\n");
if (x11->xim)
XCloseIM(x11->xim);
x11_error_output = NULL;
XSetErrorHandler(NULL);
XCloseDisplay(x11->display);
if (x11->display) {
x11_error_output = NULL;
XSetErrorHandler(NULL);
XCloseDisplay(x11->display);
}
if (x11->screensaver_terminate) {
mp_cancel_trigger(x11->screensaver_terminate);
sem_post(&x11->screensaver_sem);
pthread_join(x11->screensaver_thread, NULL);
sem_destroy(&x11->screensaver_sem);
}
talloc_free(x11);
vo->x11 = NULL;
@ -1766,7 +1809,7 @@ static void xscreensaver_heartbeat(struct vo_x11_state *x11)
(time - x11->screensaver_time_last) >= 10)
{
x11->screensaver_time_last = time;
sem_post(&x11->screensaver_sem);
XResetScreenSaver(x11->display);
}
}
@ -1790,7 +1833,7 @@ static int xss_suspend(Display *mDisplay, Bool suspend)
static void set_screensaver(struct vo_x11_state *x11, bool enabled)
{
Display *mDisplay = x11->display;
if (x11->screensaver_enabled == enabled)
if (!mDisplay || x11->screensaver_enabled == enabled)
return;
MP_VERBOSE(x11, "%s screensaver.\n", enabled ? "Enabling" : "Disabling");
x11->screensaver_enabled = enabled;

View File

@ -20,9 +20,12 @@
#include <stdint.h>
#include <stdbool.h>
#include <pthread.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include "osdep/semaphore.h"
#include "common/common.h"
struct vo;
@ -57,6 +60,9 @@ struct vo_x11_state {
bool screensaver_enabled;
bool dpms_touched;
double screensaver_time_last;
pthread_t screensaver_thread;
sem_t screensaver_sem;
struct mp_cancel *screensaver_terminate;
XIM xim;
XIC xic;