summaryrefslogtreecommitdiffstats
path: root/src/screensaver.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/screensaver.cpp')
-rw-r--r--src/screensaver.cpp217
1 files changed, 217 insertions, 0 deletions
diff --git a/src/screensaver.cpp b/src/screensaver.cpp
new file mode 100644
index 0000000..75e6ba5
--- /dev/null
+++ b/src/screensaver.cpp
@@ -0,0 +1,217 @@
+#include "screensaver.h"
+
+#include <QX11Info>
+#include <QStringList>
+#include <QProcess>
+#include <X11/Xlib.h>
+#include <X11/Xatom.h>
+
+#ifdef X11_Xscreensaver_FOUND
+#include <X11/extensions/scrnsaver.h>
+#include <X11/Xutil.h>
+#endif
+#ifdef X11_dpms_FOUND
+#include <X11/extensions/dpms.h>
+#endif
+
+namespace {
+
+Display *display = nullptr;
+bool extensionSupported = false;
+bool dpmsSupported = false;
+Atom XA_SCREENSAVER_VERSION, XA_SCREENSAVER_STATUS, XA_LOCK;
+XErrorHandler old_handler = nullptr;
+Bool got_badwindow = False;
+
+bool init()
+{
+ if (display != nullptr) {
+ return true;
+ }
+ display = QX11Info::display();
+ if (display == nullptr) {
+ return false;
+ }
+#ifdef X11_Xscreensaver_FOUND
+ int dummy;
+ extensionSupported = (XScreenSaverQueryExtension(display, &dummy, &dummy) == True);
+ if (extensionSupported) {
+ XA_SCREENSAVER_STATUS = XInternAtom( display, "_SCREENSAVER_STATUS", False );
+ XA_SCREENSAVER_VERSION = XInternAtom( display, "_SCREENSAVER_VERSION",False );
+ XA_LOCK = XInternAtom( display, "LOCK", False );
+ }
+#endif
+#ifdef X11_dpms_FOUND
+ dpmsSupported = (DPMSCapable(display) == True);
+#endif
+ return true;
+}
+
+static int BadWindow_ehandler( Display *dpy, XErrorEvent *error )
+{
+ if( error->error_code == BadWindow ) {
+ got_badwindow = True;
+ return 0;
+ } else {
+ if( !old_handler ) {
+ abort();
+ }
+ return ( *old_handler )( dpy, error );
+ }
+}
+
+#ifdef X11_Xscreensaver_FOUND
+static Window find_screensaver_window( Display *dpy, char **version )
+{
+ unsigned int i;
+ Window root = RootWindowOfScreen( DefaultScreenOfDisplay( dpy ) );
+ Window root2, parent, *kids;
+ unsigned int nkids;
+
+ if( version ) {
+ *version = 0;
+ }
+
+ if( ! XQueryTree( dpy, root, &root2, &parent, &kids, &nkids ) ) {
+ abort();
+ }
+ if( root != root2 ) {
+ abort();
+ }
+ if( parent ) {
+ abort();
+ }
+ if( !( kids && nkids ) ) {
+ return 0;
+ }
+ for( i = 0; i < nkids; i++ ) {
+ Atom type;
+ int format;
+ unsigned long nitems, bytesafter;
+ unsigned char *v;
+ int status;
+
+ /* We're walking the list of root-level windows and trying to find
+ the one that has a particular property on it. We need to trap
+ BadWindows errors while doing this, because it's possible that
+ some random window might get deleted in the meantime. (That
+ window won't have been the one we're looking for.)
+ */
+ XSync( dpy, False );
+ if( old_handler ) {
+ abort();
+ }
+ got_badwindow = False;
+ old_handler = XSetErrorHandler( BadWindow_ehandler );
+ status = XGetWindowProperty( dpy, kids[i],
+ XA_SCREENSAVER_VERSION,
+ 0, 200, False, XA_STRING,
+ &type, &format, &nitems, &bytesafter,
+ &v );
+ XSync( dpy, False );
+ XSetErrorHandler( old_handler );
+ old_handler = nullptr;
+
+ if( got_badwindow ) {
+ status = BadWindow;
+ got_badwindow = False;
+ }
+
+ if( status == Success && type != None ) {
+ Window ret = kids[i];
+ if( version ) {
+ *version = ( char* )v;
+ }
+ XFree( kids );
+ return ret;
+ }
+ }
+
+ if( kids ) {
+ XFree( kids );
+ }
+ return 0;
+}
+#endif
+
+}
+
+/*
+ * Main attraction
+ */
+
+namespace ScreenSaver {
+
+void allowSaverAndStandby(bool allow)
+{
+ if (!init())
+ return;
+#ifdef X11_Xscreensaver_FOUND
+ if (extensionSupported) {
+ XScreenSaverSuspend(display, allow ? False : True);
+ return;
+ }
+#endif
+ // TODO: Maybe try some fallback, call xset, or trigger some event periodically
+}
+
+void forceScreenOn()
+{
+ if (!init())
+ return;
+#ifdef X11_dpms_FOUND
+ CARD16 power_level;
+ BOOL state;
+ if (DPMSInfo(display, &power_level, &state) && state) {
+ DPMSForceLevel(display, DPMSModeOn);
+ return;
+ }
+#endif
+}
+
+bool isLocked()
+{
+#ifdef X11_Xscreensaver_FOUND
+ if (!init())
+ return false;
+ char *v = nullptr;
+ Window window = find_screensaver_window( display, &v );
+ if( !window )
+ return false;
+ if( !v || !*v )
+ return false;
+ XClassHint hint;
+ memset( &hint, 0, sizeof( hint ) );
+ XGetClassHint( display, window, &hint );
+ if( !hint.res_class )
+ return false;
+
+ Atom type;
+ int format;
+ unsigned long nitems, bytesafter;
+ Atom *data = nullptr;
+ if( XGetWindowProperty( display,
+ RootWindow( display, 0 ),
+ XA_SCREENSAVER_STATUS,
+ 0, 999, False, XA_INTEGER,
+ &type, &format, &nitems, &bytesafter,
+ reinterpret_cast<unsigned char**>(&data) )
+ != Success
+ || !type
+ || data == nullptr )
+ return false;
+ if( type != XA_INTEGER || nitems < 3 ) {
+ if( data ) {
+ free( data );
+ }
+ return false;
+ }
+
+ Atom blanked = ( Atom ) data[0];
+ if( blanked == XA_LOCK )
+ return true; // Yay
+#endif
+ return false;
+}
+
+}