Skip to content

Instantly share code, notes, and snippets.

@tych0
Created December 20, 2025 18:37
Show Gist options
  • Select an option

  • Save tych0/b7263cb5d6c8e42cce902fb2132f3c89 to your computer and use it in GitHub Desktop.

Select an option

Save tych0/b7263cb5d6c8e42cce902fb2132f3c89 to your computer and use it in GitHub Desktop.
#!/usr/bin/env python3
"""
Monitor screensaver events using the MIT-SCREEN-SAVER extension.
Uses an event-driven approach with SelectInput to receive notifications.
"""
import xcffib
import xcffib.xproto
import xcffib.screensaver
import sys
import select
def monitor_screensaver_events():
"""
Monitor screensaver events using an event loop.
Receives NotifyEvents when the screensaver state changes.
"""
# Connect to X server
conn = xcffib.connect()
# Get the screensaver extension
screensaver = conn(xcffib.screensaver.key)
# Get the root window
setup = conn.get_setup()
screen = setup.roots[0]
root = screen.root
# Query screensaver version
version_reply = screensaver.QueryVersion(
xcffib.screensaver.MAJOR_VERSION,
xcffib.screensaver.MINOR_VERSION
).reply()
print(f"MIT-SCREEN-SAVER extension version: {version_reply.server_major_version}.{version_reply.server_minor_version}")
print("Registered for screensaver events. Waiting for idle/active state changes...\n")
# Register for screensaver events using SelectInput
# NotifyMask will send us events when the screensaver state changes
screensaver.SelectInput(
root,
xcffib.screensaver.Event.NotifyMask | xcffib.screensaver.Event.CycleMask,
)
conn.flush()
try:
# Event loop - wait for screensaver events
while True:
event = conn.wait_for_event()
if event is None:
print("Connection lost")
break
handle_screensaver_event(event)
except KeyboardInterrupt:
print("\n\nMonitoring stopped.")
finally:
conn.disconnect()
def handle_screensaver_event(event):
"""
Handle a screensaver NotifyEvent.
Args:
event: xcffib.screensaver.NotifyEvent
"""
# State can be: Off (0), On (1), Cycle (2), Disabled (3)
state_names = {
xcffib.screensaver.State.Off: "OFF",
xcffib.screensaver.State.On: "ON",
xcffib.screensaver.State.Cycle: "CYCLE",
xcffib.screensaver.State.Disabled: "DISABLED"
}
# Kind can be: Blanked (0), Internal (1), External (2)
kind_names = {
xcffib.screensaver.Kind.Blanked: "Blanked",
xcffib.screensaver.Kind.Internal: "Internal",
xcffib.screensaver.Kind.External: "External"
}
state = state_names.get(event.state, f"Unknown({event.state})")
kind = kind_names.get(event.kind, f"Unknown({event.kind})")
forced = "forced" if event.forced else "not forced"
print(f"Screensaver event: state={state}, kind={kind}, {forced}, time={event.time}")
if event.state == xcffib.screensaver.State.On:
print(" → User is now IDLE (screensaver activated)")
elif event.state == xcffib.screensaver.State.Off:
print(" → User is now ACTIVE (screensaver deactivated)")
elif event.state == xcffib.screensaver.State.Cycle:
print(" → Screensaver cycle event")
else:
print(f" → Screensaver {event} event")
if __name__ == "__main__":
monitor_screensaver_events()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment