From dd12040ebe7c4006eab56c0d4a18d495274cf37d Mon Sep 17 00:00:00 2001 From: wm4 Date: Wed, 15 Apr 2015 22:39:01 +0200 Subject: 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. --- video/out/x11_common.c | 67 +++++++++++++++++++++++++++++++++++++++++--------- video/out/x11_common.h | 6 +++++ 2 files changed, 61 insertions(+), 12 deletions(-) diff --git a/video/out/x11_common.c b/video/out/x11_common.c index 392da3cee0..36a497055a 100644 --- a/video/out/x11_common.c +++ b/video/out/x11_common.c @@ -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 #include @@ -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; diff --git a/video/out/x11_common.h b/video/out/x11_common.h index f6d73dae00..eeff773bef 100644 --- a/video/out/x11_common.h +++ b/video/out/x11_common.h @@ -20,9 +20,12 @@ #include #include +#include #include #include +#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; -- cgit v1.2.3