Skip to content

Commit

Permalink
Do not mess with DPMS/blanking
Browse files Browse the repository at this point in the history
This is the job of the DPMS setting. We only stop children when Xss
blanks the screen or when DPMS blanks the screen. The last part is a
bit inefficient as there is no event associated.
  • Loading branch information
vincentbernat committed Dec 26, 2021
1 parent a1478bc commit 591b2a7
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 138 deletions.
9 changes: 0 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -234,15 +234,6 @@ Options to XSecureLock can be passed by environment variables:
the screen saver.
* `XSECURELOCK_AUTH_WARNING_COLOR`: specifies the X11 color (see manpage of
XParseColor) for the warning text of the auth dialog.
* `XSECURELOCK_BLANK_TIMEOUT`: specifies the time (in seconds) before telling
X11 to fully blank the screen; a negative value disables X11 blanking. The
time is measured since the closing of the auth window or xsecurelock
startup. Setting this to 0 is rather nonsensical, as key-release events
(e.g. from the keystroke to launch xsecurelock or from pressing escape to
close the auth dialog) always wake up the screen.
* `XSECURELOCK_BLANK_DPMS_STATE`: specifies which DPMS state to put the screen
in when blanking (one of standby, suspend, off and on, where "on" means to
not invoke DPMS at all).
* `XSECURELOCK_BURNIN_MITIGATION`: specifies the number of pixels the prompt
of `auth_x11` may be moved at startup to mitigate possible burn-in
effects due to the auth dialog being displayed all the time (e.g. when
Expand Down
158 changes: 29 additions & 129 deletions main.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ limitations under the License.
#endif
#ifdef HAVE_XCOMPOSITE_EXT
#include <X11/extensions/Xcomposite.h> // for XCompositeGetOverlayWindow

#include "incompatible_compositor.xbm" // for incompatible_compositor_bits
#endif
#ifdef HAVE_XSCREENSAVER_EXT
Expand Down Expand Up @@ -75,7 +74,7 @@ limitations under the License.
*
* This defines the minimum frequency to call WatchChildren().
*/
#define WATCH_CHILDREN_HZ 10
#define WATCH_CHILDREN_HZ 1

/*! \brief Try to reinstate grabs in regular intervals.
*
Expand Down Expand Up @@ -143,115 +142,12 @@ int have_switch_user_command = 0;
int force_grab = 0;
//! If set, print window info about any "conflicting" windows to stderr.
int debug_window_info = 0;
//! If nonnegative, the time in seconds till we blank the screen explicitly.
int blank_timeout = -1;
//! The DPMS state to switch the screen to when blanking.
const char *blank_dpms_state = "off";
//! Whether to reset the saver module when auth closes.
int saver_reset_on_auth_close = 0;

//! The PID of a currently running notify command, or 0 if none is running.
pid_t notify_command_pid = 0;

//! The time when we will blank the screen.
struct timeval time_to_blank;

//! Whether the screen is currently blanked by us.
int blanked = 0;

#ifdef HAVE_DPMS_EXT
//! Whether DPMS needs to be disabled when unblanking. Set when blanking.
int must_disable_dpms = 0;
#endif

void ResetBlankScreenTimer(void) {
if (blank_timeout < 0) {
return;
}
gettimeofday(&time_to_blank, NULL);
time_to_blank.tv_sec += blank_timeout;
}

void InitBlankScreen(void) {
if (blank_timeout < 0) {
return;
}
blanked = 0;
ResetBlankScreenTimer();
}

void MaybeBlankScreen(Display *display) {
if (blank_timeout < 0 || blanked) {
return;
}
struct timeval now;
gettimeofday(&now, NULL);
if (now.tv_sec < time_to_blank.tv_sec ||
(now.tv_sec == time_to_blank.tv_sec &&
now.tv_usec < time_to_blank.tv_usec)) {
return;
}
// Blank timer expired - blank the screen.
blanked = 1;
XForceScreenSaver(display, ScreenSaverActive);
if (!strcmp(blank_dpms_state, "on")) {
// Just X11 blanking.
goto done;
}
#ifdef HAVE_DPMS_EXT
// If we get here, we want to do DPMS blanking.
int dummy;
if (!DPMSQueryExtension(display, &dummy, &dummy)) {
Log("DPMS is unavailable and XSECURELOCK_BLANK_DPMS_STATE not on");
goto done;
}
CARD16 state;
BOOL onoff;
DPMSInfo(display, &state, &onoff);
if (!onoff) {
// DPMS not active by user - so we gotta force it.
must_disable_dpms = 1;
DPMSEnable(display);
}
if (!strcmp(blank_dpms_state, "standby")) {
DPMSForceLevel(display, DPMSModeStandby);
} else if (!strcmp(blank_dpms_state, "suspend")) {
DPMSForceLevel(display, DPMSModeSuspend);
} else if (!strcmp(blank_dpms_state, "off")) {
DPMSForceLevel(display, DPMSModeOff);
} else {
Log("XSECURELOCK_BLANK_DPMS_STATE not in standby/suspend/off/on");
}
#else
Log("DPMS is not compiled in and XSECURELOCK_BLANK_DPMS_STATE not on");
#endif
done:
// Flush the output buffer so we turn off the display now and not a few ms
// later.
XFlush(display);
}

void ScreenNoLongerBlanked(Display *display) {
#ifdef HAVE_DPMS_EXT
if (must_disable_dpms) {
DPMSDisable(display);
must_disable_dpms = 0;
// Flush the output buffer so we turn on the display now and not a
// few ms later. Makes our and X11's idle timer more consistent.
XFlush(display);
}
#endif
blanked = 0;
}

void UnblankScreen(Display *display) {
if (blanked) {
XForceScreenSaver(display, ScreenSaverReset);
ScreenNoLongerBlanked(display);
}
ResetBlankScreenTimer();
}

static void HandleSIGTERM(int signo) {
KillAllSaverChildrenSigHandler(signo); // Dirty, but quick.
KillAuthChildSigHandler(signo); // More dirty.
Expand Down Expand Up @@ -319,18 +215,34 @@ int WatchChildren(Display *dpy, Window auth_win, Window saver_win,
WatchSaverChild(dpy, saver_win, 0, saver_executable,
state != WATCH_CHILDREN_SAVER_DISABLED);

if (auth_running) {
// While auth is running, we never blank.
UnblankScreen(dpy);
} else {
// If no auth is running, permit blanking as per timer.
MaybeBlankScreen(dpy);
}

// Do not terminate the screen lock.
return 0;
}

/*! \brief Check if screen is blanked by DPMS.
*
* \return If true, the screen is blanked by DPMS.
*/
int IsBlankedByDPMS(Display *dpy) {
#if HAVE_DPMS_EXT
static Bool DPMSExtensionAvailable = -1;
if (DPMSExtensionAvailable == -1) {
int dummy;
DPMSExtensionAvailable = (DPMSQueryExtension(dpy, &dummy, &dummy) != 0);
}
if (!DPMSExtensionAvailable) {
return 0;
}
/* There is no DPMSSelectInput, so we need to poll */
CARD16 dpms_state;
BOOL dpms_enabled;
if (DPMSInfo(dpy, &dpms_state, &dpms_enabled)) {
return (dpms_enabled && dpms_state != DPMSModeOn);
}
#endif
return 0;
}

/*! \brief Wake up the screen saver in response to a keyboard or mouse event.
*
* \return If true, authentication was successful, and the program should exit.
Expand Down Expand Up @@ -425,8 +337,6 @@ void LoadDefaults() {
*GetStringSetting("XSECURELOCK_SWITCH_USER_COMMAND", "");
force_grab = GetIntSetting("XSECURELOCK_FORCE_GRAB", 0);
debug_window_info = GetIntSetting("XSECURELOCK_DEBUG_WINDOW_INFO", 0);
blank_timeout = GetIntSetting("XSECURELOCK_BLANK_TIMEOUT", 600);
blank_dpms_state = GetStringSetting("XSECURELOCK_BLANK_DPMS_STATE", "off");
saver_reset_on_auth_close =
GetIntSetting("XSECURELOCK_SAVER_RESET_ON_AUTH_CLOSE", 0);
}
Expand Down Expand Up @@ -1091,13 +1001,12 @@ int main(int argc, char **argv) {
// Need to flush the display so savers sure can access the window.
XFlush(display);

// Figure out the initial Xss saver state. This gets updated by event.
enum WatchChildrenState xss_requested_saver_state = WATCH_CHILDREN_NORMAL;
#ifdef HAVE_XSCREENSAVER_EXT
if (scrnsaver_event_base != 0) {
XScreenSaverInfo *info = XScreenSaverAllocInfo();
XScreenSaverQueryInfo(display, root_window, info);
if (info->state == ScreenSaverOn) {
if (info->state == ScreenSaverOn && info->kind == ScreenSaverBlanked) {
xss_requested_saver_state = WATCH_CHILDREN_SAVER_DISABLED;
}
XFree(info);
Expand All @@ -1112,8 +1021,6 @@ int main(int argc, char **argv) {
xss_sleep_lock_fd = -1;
}

InitBlankScreen();

int background_window_mapped = 0, background_window_visible = 0,
auth_window_mapped = 0, saver_window_mapped = 0,
need_to_reinstate_grabs = 0, xss_lock_notified = 0;
Expand All @@ -1129,8 +1036,8 @@ int main(int argc, char **argv) {
select(x11_fd + 1, &in_fds, 0, 0, &tv);

// Make sure to shut down the saver when blanked. Saves power.
enum WatchChildrenState requested_saver_state =
blanked ? WATCH_CHILDREN_SAVER_DISABLED : xss_requested_saver_state;
enum WatchChildrenState requested_saver_state = IsBlankedByDPMS(display) ?
WATCH_CHILDREN_SAVER_DISABLED : xss_requested_saver_state;

// Now check status of our children.
if (WatchChildren(display, auth_window, saver_window, requested_saver_state,
Expand Down Expand Up @@ -1270,14 +1177,12 @@ int main(int argc, char **argv) {
case MotionNotify:
case ButtonPress:
// Mouse events launch the auth child.
ScreenNoLongerBlanked(display);
if (WakeUp(display, auth_window, saver_window, NULL)) {
goto done;
}
break;
case KeyPress: {
// Keyboard events launch the auth child.
ScreenNoLongerBlanked(display);
Status status = XLookupNone;
int have_key = 1;
int do_wake_up = 1;
Expand Down Expand Up @@ -1375,9 +1280,6 @@ int main(int argc, char **argv) {
} break;
case KeyRelease:
case ButtonRelease:
// Known to wake up screen blanking.
ScreenNoLongerBlanked(display);
break;
case MappingNotify:
case EnterNotify:
case LeaveNotify:
Expand Down Expand Up @@ -1493,7 +1395,7 @@ int main(int argc, char **argv) {
priv.ev.type == scrnsaver_event_base + ScreenSaverNotify) {
XScreenSaverNotifyEvent *xss_ev =
(XScreenSaverNotifyEvent *)&priv.ev;
if (xss_ev->state == ScreenSaverOn) {
if (xss_ev->state == ScreenSaverOn && xss_ev->kind == ScreenSaverBlanked) {
xss_requested_saver_state = WATCH_CHILDREN_SAVER_DISABLED;
} else {
xss_requested_saver_state = WATCH_CHILDREN_NORMAL;
Expand All @@ -1513,8 +1415,6 @@ int main(int argc, char **argv) {
}

done:
// Make sure no DPMS changes persist.
UnblankScreen(display);

if (previous_focused_window != None) {
XSetErrorHandler(SilentlyIgnoreErrorsHandler);
Expand Down

0 comments on commit 591b2a7

Please sign in to comment.