mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-10-16 16:24:00 -04:00
lock: take the lock back when the shell restarts into a locked session (#3685)
* lock: take the lock back when the shell restarts into a locked session Check the state once when the module completes, on locked or lockedHint, and handle it the way onSessionLocked does, including the wait while the session is inactive. After a logind Unlock that the shell ignored for a lock it started, only lockedHint still says locked; and the module loads asynchronously, so the state can arrive before its Connections exist. * loginctl: read LockedHint from logind on unlock logind's Unlock signal does not clear LockedHint, only the locker does. Forcing it false told a shell restarted in that window that the session was no longer locked.
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package loginctl
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/AvengeMedia/dankgo/dbusutil"
|
||||
@@ -29,9 +30,10 @@ func (m *Manager) handleDBusSignal(sig *dbus.Signal) {
|
||||
}
|
||||
|
||||
case dbusSessionInterface + ".Unlock":
|
||||
lockedHint := m.sessionLockedHint()
|
||||
m.stateMutex.Lock()
|
||||
m.state.Locked = false
|
||||
m.state.LockedHint = false
|
||||
m.state.LockedHint = lockedHint
|
||||
m.stateMutex.Unlock()
|
||||
m.notifySubscribers()
|
||||
m.prelockedReady.Store(false)
|
||||
@@ -109,6 +111,19 @@ func (m *Manager) handleDBusSignal(sig *dbus.Signal) {
|
||||
}
|
||||
}
|
||||
|
||||
// logind's Unlock does not clear LockedHint, the locker does. Report logind's
|
||||
// value so a shell restarted while still locked can take the lock back.
|
||||
func (m *Manager) sessionLockedHint() bool {
|
||||
if m.sessionObj == nil {
|
||||
return false
|
||||
}
|
||||
props, err := m.getSessionProperties(context.Background())
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return dbusutil.GetOr(props, "LockedHint", false)
|
||||
}
|
||||
|
||||
func (m *Manager) handlePropertiesChanged(sig *dbus.Signal) {
|
||||
if len(sig.Body) < 2 {
|
||||
return
|
||||
|
||||
@@ -6,8 +6,10 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
mockdbus "github.com/AvengeMedia/DankMaterialShell/core/internal/mocks/github.com/godbus/dbus/v5"
|
||||
"github.com/godbus/dbus/v5"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
@@ -34,25 +36,41 @@ func TestManager_HandleDBusSignal_Lock(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestManager_HandleDBusSignal_Unlock(t *testing.T) {
|
||||
manager := &Manager{
|
||||
state: &SessionState{
|
||||
Locked: true,
|
||||
LockedHint: true,
|
||||
},
|
||||
stateMutex: sync.RWMutex{},
|
||||
dirty: make(chan struct{}, 1),
|
||||
tests := []struct {
|
||||
name string
|
||||
lockedHint bool
|
||||
}{
|
||||
{name: "logind cleared LockedHint", lockedHint: false},
|
||||
{name: "logind still reports LockedHint", lockedHint: true},
|
||||
}
|
||||
|
||||
sig := &dbus.Signal{
|
||||
Name: "org.freedesktop.login1.Session.Unlock",
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
sessionObj := mockdbus.NewMockBusObject(t)
|
||||
sessionObj.EXPECT().CallWithContext(mock.Anything, "org.freedesktop.DBus.Properties.GetAll", dbus.Flags(0), "org.freedesktop.login1.Session").Return(&dbus.Call{
|
||||
Body: []any{map[string]dbus.Variant{"LockedHint": dbus.MakeVariant(tt.lockedHint)}},
|
||||
})
|
||||
|
||||
manager := &Manager{
|
||||
state: &SessionState{
|
||||
Locked: true,
|
||||
LockedHint: true,
|
||||
},
|
||||
stateMutex: sync.RWMutex{},
|
||||
dirty: make(chan struct{}, 1),
|
||||
sessionObj: sessionObj,
|
||||
}
|
||||
|
||||
manager.handleDBusSignal(&dbus.Signal{
|
||||
Name: "org.freedesktop.login1.Session.Unlock",
|
||||
})
|
||||
|
||||
manager.stateMutex.RLock()
|
||||
defer manager.stateMutex.RUnlock()
|
||||
assert.False(t, manager.state.Locked)
|
||||
assert.Equal(t, tt.lockedHint, manager.state.LockedHint)
|
||||
})
|
||||
}
|
||||
|
||||
manager.handleDBusSignal(sig)
|
||||
|
||||
manager.stateMutex.RLock()
|
||||
defer manager.stateMutex.RUnlock()
|
||||
assert.False(t, manager.state.Locked)
|
||||
assert.False(t, manager.state.LockedHint)
|
||||
}
|
||||
|
||||
func TestManager_HandleDBusSignal_PrepareForSleep(t *testing.T) {
|
||||
|
||||
@@ -79,8 +79,15 @@ Scope {
|
||||
Component.onCompleted: {
|
||||
IdleService.lockComponent = this;
|
||||
IdleService.isSessionLockSecure = sessionLock.secure;
|
||||
if (SettingsData.lockAtStartup && !freshGreeterLogin())
|
||||
if (SettingsData.lockAtStartup && !freshGreeterLogin()) {
|
||||
lock();
|
||||
return;
|
||||
}
|
||||
// A shell restarted into a locked session: after a logind Unlock
|
||||
// ignored for a lock it started, only lockedHint still says locked,
|
||||
// and the state can arrive before this module's Connections exist.
|
||||
if (SessionService.locked || SessionService.lockedHint)
|
||||
followLoginctlLock();
|
||||
}
|
||||
|
||||
function notifyLockedHint(locked: bool) {
|
||||
@@ -116,6 +123,21 @@ Scope {
|
||||
return true;
|
||||
}
|
||||
|
||||
function followLoginctlLock() {
|
||||
if (shouldLock || pendingLock)
|
||||
return;
|
||||
if (handleLoginctlCustomLock())
|
||||
return;
|
||||
if (!SessionService.active && SessionService.loginctlAvailable && SettingsData.loginctlLockIntegration) {
|
||||
pendingLock = true;
|
||||
lockInitiatedLocally = false;
|
||||
return;
|
||||
}
|
||||
lockInitiatedLocally = false;
|
||||
lockPowerOffArmed = powerOffOnLock;
|
||||
shouldLock = true;
|
||||
}
|
||||
|
||||
function resetLockRetry() {
|
||||
lockRetryAttempts = 0;
|
||||
lockRetryPending = false;
|
||||
@@ -193,18 +215,7 @@ Scope {
|
||||
target: SessionService
|
||||
|
||||
function onSessionLocked() {
|
||||
if (shouldLock || pendingLock)
|
||||
return;
|
||||
if (handleLoginctlCustomLock())
|
||||
return;
|
||||
if (!SessionService.active && SessionService.loginctlAvailable && SettingsData.loginctlLockIntegration) {
|
||||
pendingLock = true;
|
||||
lockInitiatedLocally = false;
|
||||
return;
|
||||
}
|
||||
lockInitiatedLocally = false;
|
||||
lockPowerOffArmed = powerOffOnLock;
|
||||
shouldLock = true;
|
||||
root.followLoginctlLock();
|
||||
}
|
||||
|
||||
function onSessionUnlocked() {
|
||||
|
||||
Reference in New Issue
Block a user