diff --git a/afterlock/afterlock.go b/afterlock/afterlock.go index 6ca3360..7b9fbbe 100644 --- a/afterlock/afterlock.go +++ b/afterlock/afterlock.go @@ -1,9 +1,6 @@ package afterlock import( - "after-lock/evdev" - "after-lock/lockscreen" - "after-lock/display" "after-lock/atomicflag" "time" "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 type AfterLock struct { InitialDelay uint @@ -19,6 +32,9 @@ type AfterLock struct { wg sync.WaitGroup stopFlag *atomicflag.AtomicFlag keypressFlag *atomicflag.AtomicFlag + Display Display + LockScreen Lockscreen + KeypressDetector KeypressDetector } // 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. // Exits after the computer is unlocked +// Requires InitialDelay, LoopDelay, Display and LockScreen to be set func (af *AfterLock) Start() { - af.checkDelaysConfigured() + af.checkStructConfigured() af.wg.Add(1) go af.detectKeypresses() @@ -43,18 +60,27 @@ func (af *AfterLock) Start() { af.hybernateDisplayLoop() } -func (af *AfterLock) checkDelaysConfigured() { +func (af *AfterLock) checkStructConfigured() { if af.InitialDelay == 0 { panic(errors.New("InitialDelay not configured")) } if af.LoopDelay == 0 { 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() { for { - err := evdev.BlockUntilKeypress(af.keyboardDeviceNode) + err := af.KeypressDetector.BlockUntilKeypress(af.keyboardDeviceNode) if err != nil { panic(err) } @@ -68,7 +94,7 @@ func (af *AfterLock) detectKeypresses() { func (af *AfterLock) hybernateDisplayLoop() { for { - screenLocked, err := lockscreen.IsActive() + screenLocked, err := af.LockScreen.IsActive() if err != nil { panic(err) } @@ -78,12 +104,12 @@ func (af *AfterLock) hybernateDisplayLoop() { return } - displayOn, err := display.IsOn() + displayOn, err := af.Display.IsOn() if err != nil { panic(err) } if displayOn { - err := display.Suspend() + err := af.Display.Suspend() if err != nil { panic(err) } diff --git a/cmd/after-lock/after-lock.go b/cmd/after-lock/after-lock.go index 317df44..8d518d5 100644 --- a/cmd/after-lock/after-lock.go +++ b/cmd/after-lock/after-lock.go @@ -2,10 +2,13 @@ package main import ( "after-lock/afterlock" + "after-lock/display" + "after-lock/keypressdetector" "after-lock/lockfile" + "after-lock/lockscreen" "fmt" - "runtime/debug" "os" + "runtime/debug" ) const ( @@ -26,6 +29,9 @@ func main() { al := afterlock.New(keyboardDeviceNode) al.InitialDelay = initialDelay al.LoopDelay = loopDelay + al.Display = display.Xset{} + al.LockScreen = lockscreen.XDG{} + al.KeypressDetector = keypressdetector.Evdev{} al.Start() } diff --git a/display/display.go b/display/display.go index c4c49f3..bc506fe 100644 --- a/display/display.go +++ b/display/display.go @@ -7,8 +7,11 @@ import ( ) -// Suspend the display using xset -func Suspend() error { +// Xset monitors/controls the display using xset +type Xset struct {} + +// Suspend the display +func (Xset) Suspend() error { cmd := exec.Command("xset", "dpms", "force", @@ -18,7 +21,7 @@ func Suspend() error { } // IsOn determines if the display is on -func IsOn() (bool, error) { +func (Xset) IsOn() (bool, error) { cmd := exec.Command("xset", "q") outputBytes, err := cmd.CombinedOutput() if err != nil { diff --git a/evdev/evdev.c b/keypressdetector/evdev.c similarity index 100% rename from evdev/evdev.c rename to keypressdetector/evdev.c diff --git a/evdev/evdev.go b/keypressdetector/evdev.go similarity index 54% rename from evdev/evdev.go rename to keypressdetector/evdev.go index 53126d1..56f94ef 100644 --- a/evdev/evdev.go +++ b/keypressdetector/evdev.go @@ -1,4 +1,4 @@ -package evdev +package keypressdetector // #cgo CFLAGS: -g -Wall // #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) defer C.free(unsafe.Pointer(path)) diff --git a/evdev/evdev.h b/keypressdetector/evdev.h similarity index 100% rename from evdev/evdev.h rename to keypressdetector/evdev.h diff --git a/lockscreen/lockscreen.go b/lockscreen/lockscreen.go index 53be539..018deab 100644 --- a/lockscreen/lockscreen.go +++ b/lockscreen/lockscreen.go @@ -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) -func IsActive() (bool, error) { +func (XDG) IsActive() (bool, error) { cmd := exec.Command("qdbus", "org.kde.screensaver", "/ScreenSaver",