diff options
Diffstat (limited to 'src/screensaver.cpp')
-rw-r--r-- | src/screensaver.cpp | 217 |
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; +} + +} |