From 05df632bd828d7cac1b4c2ca134e94fbdfabc1ab Mon Sep 17 00:00:00 2001 From: Nicolas Guillaumin Date: Thu, 8 Sep 2016 15:18:37 -0700 Subject: [PATCH] WIP: Fixes #2026 Screensaver suspend on Linux via Dbus One some systems (tested with Gnome 3 on Arch Linux) the current method of using `xdg-screensaver` to suspend the screensaver does not work. Instead, using DBus to issue an `Inhibit` request is recommended. The request returns a cookie that needs to be re-used to un-inhibit the screensaver later. Additionally if the DBus connection is closed the current inhibition is discarded. Thus, the DBus connection needs to stay connected for the duration of the screenshot inhibition. The code is heavily inspired from the [SDL 2.x code](http://hg.libsdl.org/SDL/file/default/src/core/linux/SDL_dbus.c#l172). I didn't call the SDL 2 code though since this it to fix the issue with the GL driver, and I assume one would want to have screensaver inhibited even when SDL 2 is not available (but GL is). I've set "WIP" because: * I haven't done C in a long time so my code is probably not great * There's a dependency on DBus which I don't know is acceptable or not * I've put my code where I could to check it works, but `x11_common` may not be the best place * The code need and "init" and "deinit" kind of method as it needs to initialise the DBus connection, and on deinit close it properly. I've used `x11_connect` and `x11_window_destroy` but they don't sound like the best choices. * I'm a bit unclear as to what happens when "suspend screensaver" is ticked on/off in the menu. This doesn't seem to call `x11_suspend_screensaver` everytime, so I'm not sure if there's a hook somewhere (as disabling screensaver suspend in the menu should cause a DBus unhinibit request to be sent). * Should I just call the SDL 2.x code (meaning that the GL driver would depend on SDL 2.x at runtime)? So, first of all are you ok with the approach, and if yes I'd gladly get feedback about the code, how to architecture it and the best place to put it. Thanks! --- Makefile.common | 5 ++ gfx/common/x11_common.c | 117 ++++++++++++++++++++++++++++++++++++++++ gfx/common/x11_common.h | 4 ++ qb/config.libs.sh | 1 + 4 files changed, 127 insertions(+) diff --git a/Makefile.common b/Makefile.common index d091566bfe..9034725f8d 100644 --- a/Makefile.common +++ b/Makefile.common @@ -612,6 +612,11 @@ ifeq ($(HAVE_XKBCOMMON), 1) LIBS += $(XKBCOMMON_LIBS) endif +ifeq ($(HAVE_DBUS), 1) + LIBS += $(DBUS_LIBS) + CFLAGS += $(DBUS_CFLAGS) +endif + ifeq ($(HAVE_UDEV), 1) DEFINES += $(UDEV_CFLAGS) LIBS += $(UDEV_LIBS) diff --git a/gfx/common/x11_common.c b/gfx/common/x11_common.c index 7f1058b785..32ba700aef 100644 --- a/gfx/common/x11_common.c +++ b/gfx/common/x11_common.c @@ -34,6 +34,12 @@ #include "../../verbosity.h" #include "../../runloop.h" +#ifdef HAVE_DBUS +#include +static DBusConnection* dbus_connection; +static unsigned int dbus_screensaver_cookie = 0; +#endif + Colormap g_x11_cmap; Window g_x11_win; Display *g_x11_dpy; @@ -146,6 +152,75 @@ void x11_set_window_attr(Display *dpy, Window win) } void x11_suspend_screensaver(Window wnd, bool enable) +{ + x11_suspend_screensaver_xdg_screensaver(wnd, enable); +#ifdef HAVE_DBUS + x11_suspend_screensaver_dbus(enable); +#endif +} + +#ifdef HAVE_DBUS +void x11_suspend_screensaver_dbus(bool enable) +{ + const char *app = "RetroArch"; + const char *reason = "Playing a game"; + DBusMessage *msg, *reply; + + if (!enable) + return; + + if (dbus_screensaver_cookie > 0) + return; // Already suspended + + if (dbus_connection == NULL) + return; // DBus connection was not obtained + + + msg = dbus_message_new_method_call("org.freedesktop.ScreenSaver", + "/org/freedesktop/ScreenSaver", + "org.freedesktop.ScreenSaver", + "Inhibit"); + + if (msg != NULL) + { + dbus_message_append_args(msg, + DBUS_TYPE_STRING, &app, + DBUS_TYPE_STRING, &reason, + DBUS_TYPE_INVALID); + } + + if (msg != NULL) + { + reply = dbus_connection_send_with_reply_and_block(dbus_connection, msg, 300, NULL); + if (reply != NULL) { + if (!dbus_message_get_args(reply, NULL, + DBUS_TYPE_UINT32, &dbus_screensaver_cookie, + DBUS_TYPE_INVALID)) + { + dbus_screensaver_cookie = 0; + } + + dbus_message_unref(reply); + } + + dbus_message_unref(msg); + } + + if (dbus_screensaver_cookie == 0) + { + RARCH_ERR("[DBus]: Failed to suspend screensaver via DBus.\n"); + } + else + { + RARCH_LOG("[DBus]: Suspended screensaver.\n"); + } + + return; + +} +#endif + +void x11_suspend_screensaver_xdg_screensaver(Window wnd, bool enable) { int ret; char cmd[64] = {0}; @@ -533,6 +608,22 @@ bool x11_connect(void) return false; } +#ifdef HAVE_DBUS + DBusError err; + int ret; + dbus_error_init(&err); + + dbus_connection = dbus_bus_get_private(DBUS_BUS_SESSION, &err); + if (dbus_error_is_set(&err)) { + RARCH_ERR("[DBus]: Failed to get DBus connection. Screensaver will not be suspended.\n"); + dbus_error_free(&err); + } + if (dbus_connection != NULL) { + dbus_connection_set_exit_on_disconnect(dbus_connection, true); + } +#endif + + return true; } @@ -573,6 +664,32 @@ void x11_window_destroy(bool fullscreen) if (!fullscreen) XDestroyWindow(g_x11_dpy, g_x11_win); g_x11_win = None; + +#ifdef HAVE_DBUS + if (dbus_connection != NULL) + { + + DBusMessage *msg = dbus_message_new_method_call("org.freedesktop.ScreenSaver", + "/org/freedesktop/ScreenSaver", + "org.freedesktop.ScreenSaver", + "UnInhibit"); + dbus_message_append_args (msg, + DBUS_TYPE_UINT32, &dbus_screensaver_cookie, + DBUS_TYPE_INVALID); + if (msg != NULL) { + if (dbus_connection_send(dbus_connection, msg, NULL)) { + dbus_connection_flush(dbus_connection); + } + dbus_message_unref(msg); + } + + dbus_screensaver_cookie = 0; + + dbus_connection_close(dbus_connection); + dbus_connection_unref(dbus_connection); + dbus_shutdown(); + } +#endif } void x11_colormap_destroy(void) diff --git a/gfx/common/x11_common.h b/gfx/common/x11_common.h index 0bfea3202f..7c5d359443 100644 --- a/gfx/common/x11_common.h +++ b/gfx/common/x11_common.h @@ -44,6 +44,10 @@ void x11_save_last_used_monitor(Window win); void x11_show_mouse(Display *dpy, Window win, bool state); void x11_windowed_fullscreen(Display *dpy, Window win); void x11_suspend_screensaver(Window win, bool enable); +void x11_suspend_screensaver_xdg_screensaver(Window win, bool enable); +#ifdef HAVE_DBUS +void x11_suspend_screensaver_dbus(bool enable); +#endif bool x11_enter_fullscreen(Display *dpy, unsigned width, unsigned height, XF86VidModeModeInfo *desktop_mode); diff --git a/qb/config.libs.sh b/qb/config.libs.sh index d6a4f1a6e2..8a7b2fec22 100644 --- a/qb/config.libs.sh +++ b/qb/config.libs.sh @@ -382,6 +382,7 @@ check_pkgconf XCB xcb check_pkgconf WAYLAND wayland-egl check_pkgconf XKBCOMMON xkbcommon 0.3.2 +check_pkgconf DBUS dbus-1 check_pkgconf XEXT xext check_pkgconf XF86VM xxf86vm check_pkgconf XINERAMA xinerama