/** * Gets the timeouts. The values are in unit of seconds. * @param standby Amount of time of inactivity before standby mode will be invoked. * @param suspend Amount of time of inactivity before the screen is placed into suspend mode. * @param off Amount of time of inactivity before the monitor is shut off. * @ingroup Ecore_X_DPMS_Group */ EAPI void ecore_x_dpms_timeouts_get(unsigned int *standby, unsigned int *suspend, unsigned int *off) { #ifdef ECORE_XDPMS LOGFN(__FILE__, __LINE__, __FUNCTION__); DPMSGetTimeouts(_ecore_x_disp, (unsigned short *)standby, (unsigned short *)suspend, (unsigned short *)off); #endif /* ifdef ECORE_XDPMS */ }
/** * Sets the off timeout (in unit of seconds). * @param new_timeout Amount of time of inactivity before the monitor is shut off. * @ingroup Ecore_X_DPMS_Group */ EAPI void ecore_x_dpms_timeout_off_set(unsigned int new_timeout) { #ifdef ECORE_XDPMS unsigned short standby, suspend, off; LOGFN(__FILE__, __LINE__, __FUNCTION__); DPMSGetTimeouts(_ecore_x_disp, &standby, &suspend, &off); DPMSSetTimeouts(_ecore_x_disp, standby, suspend, new_timeout); #endif /* ifdef ECORE_XDPMS */ }
/** * Returns the amount of time of inactivity before the third and final * level of power saving is invoked. * @return The off timeout value. * @ingroup Ecore_X_DPMS_Group */ EAPI unsigned int ecore_x_dpms_timeout_off_get(void) { #ifdef ECORE_XDPMS unsigned short standby, suspend, off; LOGFN(__FILE__, __LINE__, __FUNCTION__); DPMSGetTimeouts(_ecore_x_disp, &standby, &suspend, &off); return off; #else /* ifdef ECORE_XDPMS */ return 0; #endif /* ifdef ECORE_XDPMS */ }
/*! * This function works around an XServer idleTime bug in the * XScreenSaverExtension if dpms is running. In this case the current * dpms-state time is always subtracted from the current idletime. * This means: XScreenSaverInfo->idle is not the time since the last * user activity, as descriped in the header file of the extension. * This result in SUSE bug # and sf.net bug #. The bug in the XServer itself * is reported at https://bugs.freedesktop.org/buglist.cgi?quicksearch=6439. * * Workaround: Check if if XServer is in a dpms state, check the * current timeout for this state and add this value to * the current idle time and return. * * \param _idleTime an unsigned long value with the current idletime from * XScreenSaverInfo->idle * \return an unsigned long with the corrected idletime */ static unsigned long workaroundX11(Display *dpy, unsigned long _idle) { int dummy; CARD16 standby, suspend, off; CARD16 state; BOOL onoff; if(DPMSQueryExtension(dpy, &dummy, &dummy)) { if(DPMSCapable(dpy)) { DPMSGetTimeouts(dpy, &standby, &suspend, &off); DPMSInfo(dpy, &state, &onoff); if(onoff) { switch(state) { case DPMSModeStandby: // this check is a little bit paranoid, but just to be sure if(_idle < (unsigned) (standby * 1000)) { _idle += (standby * 1000); } break; case DPMSModeSuspend: if(_idle < (unsigned) ((suspend + standby) * 1000)) { _idle += ((suspend + standby) * 1000); } break; case DPMSModeOff: if(_idle < (unsigned) ((off + suspend + standby) * 1000)) { _idle += ((off + suspend + standby) * 1000); } break; case DPMSModeOn: break; default: break; } } } } return _idle; }
/*! * This function works around an XServer idleTime bug in the * XScreenSaverExtension if dpms is running. In this case the current * dpms-state time is always subtracted from the current idletime. * This means: XScreenSaverInfo->idle is not the time since the last * user activity, as descriped in the header file of the extension. * This result in SUSE bug # and sf.net bug #. The bug in the XServer itself * is reported at https://bugs.freedesktop.org/buglist.cgi?quicksearch=6439. * * Workaround: Check if if XServer is in a dpms state, check the * current timeout for this state and add this value to * the current idle time and return. * * \param _idleTime a unsigned long value with the current idletime from * XScreenSaverInfo->idle * \return a unsigned long with the corrected idletime */ unsigned long workaroundCreepyXServer(Display *dpy, unsigned long _idleTime ){ int dummy; CARD16 standby, suspend, off; CARD16 state; BOOL onoff; if (DPMSQueryExtension(dpy, &dummy, &dummy)) { if (DPMSCapable(dpy)) { DPMSGetTimeouts(dpy, &standby, &suspend, &off); DPMSInfo(dpy, &state, &onoff); if (onoff) { switch (state) { case DPMSModeStandby: /* this check is a littlebit paranoid, but be sure */ if (_idleTime < (unsigned) (standby * 1000)) _idleTime += (standby * 1000); break; case DPMSModeSuspend: if (_idleTime < (unsigned) ((suspend + standby) * 1000)) _idleTime += ((suspend + standby) * 1000); break; case DPMSModeOff: if (_idleTime < (unsigned) ((off + suspend + standby) * 1000)) _idleTime += ((off + suspend + standby) * 1000); break; case DPMSModeOn: default: break; } } } } XCloseDisplay(dpy); return _idleTime; }
uint32_t get_idle_milliseconds(Display *d) { XScreenSaverInfo *ssi; int evbase, errbase; if (!XScreenSaverQueryExtension(d, &evbase, &errbase)) { fprintf(stderr, "screen saver extension not supported\n"); return 1; } ssi = XScreenSaverAllocInfo(); if (ssi == NULL) { fprintf(stderr, "couldn't allocate screen saver info\n"); return 1; } if (!XScreenSaverQueryInfo(d, DefaultRootWindow(d), ssi)) { fprintf(stderr, "couldn't query screen saver info\n"); return 1; } uint32_t idle = (uint32_t) ssi->idle; XFree(ssi); // ugh. ssi->idle is wrong if DPMS is enabled, we have // to compensate. if (DPMSQueryExtension(d, &evbase, &errbase)) { if (DPMSCapable(d)) { CARD16 standby, suspend, off, state; BOOL onoff; DPMSGetTimeouts(d, &standby, &suspend, &off); DPMSInfo(d, &state, &onoff); if (onoff) { uint32_t offset = 0; switch (state) { case DPMSModeStandby: offset = (uint32_t) (standby * 1000); break; case DPMSModeSuspend: offset = (uint32_t) ((suspend + standby) * 1000); break; case DPMSModeOff: offset = (uint32_t) ((off + suspend + standby) * 1000); break; default: /*nothing*/; } if (offset != 0 && idle < offset) idle += offset; } } } return idle; }
int main(int argc, char** argv) { int verbose = 0, bg = 0; int i, ev, er; char *lock_cmd = "xlock"; char *flag_file = NULL; char estr[100], cmd[500]; struct stat sbuf; CARD16 power; CARD16 desired = DPMSModeOff; BOOL state; /* setup the lock command. it may be reset by -lock below. */ if (getenv("XLOCK_CMD")) { lock_cmd = (char *) getenv("XLOCK_CMD"); } /* process cmd line: */ for (i=1; i<argc; i++) { if (!strcmp(argv[i], "-display")) { sprintf(estr, "DISPLAY=%s", argv[++i]); putenv(strdup(estr)); } else if (!strcmp(argv[i], "-auth")) { sprintf(estr, "XAUTHORITY=%s", argv[++i]); putenv(strdup(estr)); } else if (!strcmp(argv[i], "-lock")) { lock_cmd = argv[++i]; } else if (!strcmp(argv[i], "-f")) { flag_file = argv[++i]; unlink(flag_file); } else if (!strcmp(argv[i], "-grab")) { grab = 1; } else if (!strcmp(argv[i], "-bg")) { bg = 1; } else if (!strcmp(argv[i], "-v")) { verbose = 1; } else if (!strcmp(argv[i], "-standby")) { desired = DPMSModeStandby; } else if (!strcmp(argv[i], "-suspend")) { desired = DPMSModeSuspend; } else if (!strcmp(argv[i], "-off")) { desired = DPMSModeOff; } } /* we want it to go into background to avoid blocking, so add '&'. */ strcpy(cmd, lock_cmd); strcat(cmd, " &"); lock_cmd = cmd; /* close any file descriptors we may have inherited (e.g. port 5900) */ for (i=3; i<=100; i++) { close(i); } /* open DISPLAY */ dpy = XOpenDisplay(NULL); if (! dpy) { fprintf(stderr, "XOpenDisplay failed.\n"); exit(1); } /* check for DPMS extension */ if (! DPMSQueryExtension(dpy, &ev, &er)) { fprintf(stderr, "DPMSQueryExtension failed.\n"); exit(1); } if (! DPMSCapable(dpy)) { fprintf(stderr, "DPMSCapable failed.\n"); exit(1); } /* make sure DPMS is enabled */ if (! DPMSEnable(dpy)) { fprintf(stderr, "DPMSEnable failed.\n"); exit(1); } /* retrieve the timeouts for later resetting */ if (! DPMSGetTimeouts(dpy, &standby, &suspend, &off)) { fprintf(stderr, "DPMSGetTimeouts failed.\n"); exit(1); } if (! standby || ! suspend || ! off) { /* if none, set to some reasonable values */ standby = 900; suspend = 1200; off = 1800; } if (verbose) { fprintf(stderr, "DPMS timeouts: %d %d %d\n", standby, suspend, off); } /* now set them to very small values */ if (desired == DPMSModeOff) { if (! DPMSSetTimeouts(dpy, 1, 1, 1)) { fprintf(stderr, "DPMSSetTimeouts failed.\n"); exit(1); } } else if (desired == DPMSModeSuspend) { if (! DPMSSetTimeouts(dpy, 1, 1, 0)) { fprintf(stderr, "DPMSSetTimeouts failed.\n"); exit(1); } } else if (desired == DPMSModeStandby) { if (! DPMSSetTimeouts(dpy, 1, 0, 0)) { fprintf(stderr, "DPMSSetTimeouts failed.\n"); exit(1); } } XFlush(dpy); /* set handlers for clean up in case we terminate via signal */ signal(SIGHUP, reset); signal(SIGINT, reset); signal(SIGQUIT, reset); signal(SIGABRT, reset); signal(SIGTERM, reset); /* force state into DPMS Off (lowest power) mode */ if (! DPMSForceLevel(dpy, desired)) { fprintf(stderr, "DPMSForceLevel failed.\n"); exit(1); } XFlush(dpy); /* read state */ msleep(500); if (! DPMSInfo(dpy, &power, &state)) { fprintf(stderr, "DPMSInfo failed.\n"); exit(1); } fprintf(stderr, "power: %d state: %d\n", power, state); /* grab display if desired. NOT WORKING */ if (grab) { if (verbose) { fprintf(stderr, "calling XGrabServer()\n"); } XGrabServer(dpy); } /* go into background if desired. */ if (bg) { pid_t p; if ((p = fork()) != 0) { if (p < 0) { fprintf(stderr, "problem forking.\n"); exit(1); } else { /* XXX no fd closing */ exit(0); } } } /* main loop: */ while (1) { /* reassert DPMSModeOff (desired) */ if (verbose) fprintf(stderr, "reasserting desired DPMSMode\n"); DPMSForceLevel(dpy, desired); XFlush(dpy); /* wait a bit */ msleep(200); /* check for flag file appearence */ if (flag_file && stat(flag_file, &sbuf) == 0) { if (verbose) { fprintf(stderr, "flag found: %s\n", flag_file); } unlink(flag_file); reset(0); exit(0); } /* check state and power level */ if (! DPMSInfo(dpy, &power, &state)) { fprintf(stderr, "DPMSInfo failed.\n"); reset(0); exit(1); } if (verbose) { fprintf(stderr, "power: %d state: %d\n", power, state); } if (!state || power != desired) { /* Someone (or maybe a cat) is evidently watching... */ fprintf(stderr, "DPMS CHANGE: power: %d state: %d\n", power, state); break; } } reset(0); fprintf(stderr, "locking screen with command: \"%s\"\n", lock_cmd); system(lock_cmd); exit(0); }