Invert display and lockscreen control dependencies

This commit is contained in:
Kristóf Tóth 2020-08-20 16:57:57 +02:00
parent e6458aba0b
commit ebbd1974df
7 changed files with 59 additions and 17 deletions

View File

@ -1,9 +1,6 @@
package afterlock package afterlock
import( import(
"after-lock/evdev"
"after-lock/lockscreen"
"after-lock/display"
"after-lock/atomicflag" "after-lock/atomicflag"
"time" "time"
"sync" "sync"
@ -11,6 +8,22 @@ import(
) )
// Display controls and monitors the physical display
type Display interface {
Suspend() error
IsOn() (bool, error)
}
// Lockscreen can determine whether the screensaver is active or not
type Lockscreen interface {
IsActive() (bool, error)
}
// KeypressDetector can wait for keypresses
type KeypressDetector interface {
BlockUntilKeypress(string) error
}
// AfterLock suspends the display when the lockscreen is active // AfterLock suspends the display when the lockscreen is active
type AfterLock struct { type AfterLock struct {
InitialDelay uint InitialDelay uint
@ -19,6 +32,9 @@ type AfterLock struct {
wg sync.WaitGroup wg sync.WaitGroup
stopFlag *atomicflag.AtomicFlag stopFlag *atomicflag.AtomicFlag
keypressFlag *atomicflag.AtomicFlag keypressFlag *atomicflag.AtomicFlag
Display Display
LockScreen Lockscreen
KeypressDetector KeypressDetector
} }
// New constructs a new AfterLock instance // New constructs a new AfterLock instance
@ -30,11 +46,12 @@ func New(keyboardDeviceNode string) *AfterLock {
} }
} }
// Start starts monitoring the lockscreen/keyboard status to determine // Start starts monitoring the lockscreen/keyboard to determine
// when to suspend the display. // when to suspend the display.
// Exits after the computer is unlocked // Exits after the computer is unlocked
// Requires InitialDelay, LoopDelay, Display and LockScreen to be set
func (af *AfterLock) Start() { func (af *AfterLock) Start() {
af.checkDelaysConfigured() af.checkStructConfigured()
af.wg.Add(1) af.wg.Add(1)
go af.detectKeypresses() go af.detectKeypresses()
@ -43,18 +60,27 @@ func (af *AfterLock) Start() {
af.hybernateDisplayLoop() af.hybernateDisplayLoop()
} }
func (af *AfterLock) checkDelaysConfigured() { func (af *AfterLock) checkStructConfigured() {
if af.InitialDelay == 0 { if af.InitialDelay == 0 {
panic(errors.New("InitialDelay not configured")) panic(errors.New("InitialDelay not configured"))
} }
if af.LoopDelay == 0 { if af.LoopDelay == 0 {
panic(errors.New("LoopDelay not configured")) panic(errors.New("LoopDelay not configured"))
} }
if af.Display == nil {
panic(errors.New("Display not configured"))
}
if af.LockScreen == nil {
panic(errors.New("LockScreen not configured"))
}
if af.KeypressDetector == nil {
panic(errors.New("KeypressDetector not configured"))
}
} }
func (af *AfterLock) detectKeypresses() { func (af *AfterLock) detectKeypresses() {
for { for {
err := evdev.BlockUntilKeypress(af.keyboardDeviceNode) err := af.KeypressDetector.BlockUntilKeypress(af.keyboardDeviceNode)
if err != nil { if err != nil {
panic(err) panic(err)
} }
@ -68,7 +94,7 @@ func (af *AfterLock) detectKeypresses() {
func (af *AfterLock) hybernateDisplayLoop() { func (af *AfterLock) hybernateDisplayLoop() {
for { for {
screenLocked, err := lockscreen.IsActive() screenLocked, err := af.LockScreen.IsActive()
if err != nil { if err != nil {
panic(err) panic(err)
} }
@ -78,12 +104,12 @@ func (af *AfterLock) hybernateDisplayLoop() {
return return
} }
displayOn, err := display.IsOn() displayOn, err := af.Display.IsOn()
if err != nil { if err != nil {
panic(err) panic(err)
} }
if displayOn { if displayOn {
err := display.Suspend() err := af.Display.Suspend()
if err != nil { if err != nil {
panic(err) panic(err)
} }

View File

@ -2,10 +2,13 @@ package main
import ( import (
"after-lock/afterlock" "after-lock/afterlock"
"after-lock/display"
"after-lock/keypressdetector"
"after-lock/lockfile" "after-lock/lockfile"
"after-lock/lockscreen"
"fmt" "fmt"
"runtime/debug"
"os" "os"
"runtime/debug"
) )
const ( const (
@ -26,6 +29,9 @@ func main() {
al := afterlock.New(keyboardDeviceNode) al := afterlock.New(keyboardDeviceNode)
al.InitialDelay = initialDelay al.InitialDelay = initialDelay
al.LoopDelay = loopDelay al.LoopDelay = loopDelay
al.Display = display.Xset{}
al.LockScreen = lockscreen.XDG{}
al.KeypressDetector = keypressdetector.Evdev{}
al.Start() al.Start()
} }

View File

@ -7,8 +7,11 @@ import (
) )
// Suspend the display using xset // Xset monitors/controls the display using xset
func Suspend() error { type Xset struct {}
// Suspend the display
func (Xset) Suspend() error {
cmd := exec.Command("xset", cmd := exec.Command("xset",
"dpms", "dpms",
"force", "force",
@ -18,7 +21,7 @@ func Suspend() error {
} }
// IsOn determines if the display is on // IsOn determines if the display is on
func IsOn() (bool, error) { func (Xset) IsOn() (bool, error) {
cmd := exec.Command("xset", "q") cmd := exec.Command("xset", "q")
outputBytes, err := cmd.CombinedOutput() outputBytes, err := cmd.CombinedOutput()
if err != nil { if err != nil {

View File

@ -1,4 +1,4 @@
package evdev package keypressdetector
// #cgo CFLAGS: -g -Wall // #cgo CFLAGS: -g -Wall
// #include "evdev.h" // #include "evdev.h"
@ -11,7 +11,11 @@ import (
) )
func BlockUntilKeypress(devicePath string) error { // Evdev can detect keypresses on /dev/input devices
type Evdev struct {}
// BlockUntilKeypress waits until a key is pressed on the specified device
func (Evdev) BlockUntilKeypress(devicePath string) error {
path := C.CString(devicePath) path := C.CString(devicePath)
defer C.free(unsafe.Pointer(path)) defer C.free(unsafe.Pointer(path))

View File

@ -6,8 +6,11 @@ import (
) )
// XDG uses qdbus to monitor the freedesktop screensaver status
type XDG struct {}
// IsActive checks whether the screen is locked (checks if the screensaver is active) // IsActive checks whether the screen is locked (checks if the screensaver is active)
func IsActive() (bool, error) { func (XDG) IsActive() (bool, error) {
cmd := exec.Command("qdbus", cmd := exec.Command("qdbus",
"org.kde.screensaver", "org.kde.screensaver",
"/ScreenSaver", "/ScreenSaver",