Skip to content

Commit 9841abe

Browse files
committed
Add posibility to revert changes if something went wrong
1 parent 9e25de8 commit 9841abe

1 file changed

Lines changed: 53 additions & 0 deletions

File tree

main.py

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
# constants
2222
TIME_STEP = 5 # seconds
2323
CONFIG_RELOAD_EVERY = 6 # iterations -> ~30 s
24+
REVERT_TIMEOUT = 15 # seconds before auto-reverting a display change
2425

2526
PROJECT_NAME = "SRR"
2627
PROJECT_EXECUTABLE = PROJECT_NAME + ".exe"
@@ -165,6 +166,40 @@ def _state_label(state: Optional[bool]) -> str:
165166
return "AC (performance)" if state else "Battery (powersave)"
166167

167168

169+
def _snapshot_current_settings(
170+
display_map: Dict[str, bytes],
171+
config: Dict[str, Tuple[ScreenSettings, ScreenSettings]],
172+
) -> Dict[str, ScreenSettings]:
173+
snapshot: Dict[str, ScreenSettings] = {}
174+
for monitor_id in config:
175+
adapter = display_map.get(monitor_id)
176+
if adapter is None:
177+
continue
178+
try:
179+
w, h, f = reschanger.get_display_settings(
180+
adapter, reschanger.ENUM_CURRENT_SETTINGS
181+
)
182+
snapshot[monitor_id] = ScreenSettings(w, h, f)
183+
except Exception as e:
184+
logging.warning(f"snapshot failed for {monitor_id!r}: {e}")
185+
return snapshot
186+
187+
188+
async def _revert_after_timeout(
189+
prev: Dict[str, ScreenSettings],
190+
display_map: Dict[str, bytes],
191+
) -> None:
192+
await asyncio.sleep(REVERT_TIMEOUT)
193+
logging.warning("revert timer fired — restoring previous display settings")
194+
for monitor_id, ss in prev.items():
195+
adapter = display_map.get(monitor_id)
196+
if adapter is None:
197+
continue
198+
await change_screen_settings(ss, adapter)
199+
if _tray is not None:
200+
_tray.notify("Display settings reverted — screen may have gone dark.")
201+
202+
168203
async def srr_loop() -> None:
169204
assert _shutdown_event is not None
170205
assert _reload_event is not None
@@ -176,6 +211,7 @@ async def srr_loop() -> None:
176211
if _tray is not None:
177212
_tray.set_state_text(_state_label(last_state))
178213
counter = 0
214+
pending_revert: Optional[asyncio.Task] = None
179215

180216
while not _shutdown_event.is_set():
181217
try:
@@ -184,12 +220,21 @@ async def srr_loop() -> None:
184220
except asyncio.TimeoutError:
185221
pass
186222

223+
# One full TIME_STEP passed without issues — confirm the previous switch
224+
if pending_revert is not None and not pending_revert.done():
225+
pending_revert.cancel()
226+
pending_revert = None
227+
187228
if _reload_event.is_set():
188229
_reload_event.clear()
189230
current_config = await load_config(force=True)
190231
display_map = build_display_map()
191232
if current_config is not None:
233+
prev = _snapshot_current_settings(display_map, current_config)
192234
await switch_rate(cur_power_state(), current_config, display_map)
235+
pending_revert = asyncio.create_task(
236+
_revert_after_timeout(prev, display_map)
237+
)
193238

194239
if _tray is not None and _tray.paused:
195240
continue
@@ -204,11 +249,19 @@ async def srr_loop() -> None:
204249
current_config = new_config
205250
if _tray is not None:
206251
_tray.notify("Config reloaded.")
252+
prev = _snapshot_current_settings(display_map, current_config)
207253
await switch_rate(current_state, current_config, display_map)
254+
pending_revert = asyncio.create_task(
255+
_revert_after_timeout(prev, display_map)
256+
)
208257
counter += 1
209258

210259
if current_state != last_state and current_config is not None:
260+
prev = _snapshot_current_settings(display_map, current_config)
211261
await switch_rate(current_state, current_config, display_map)
262+
pending_revert = asyncio.create_task(
263+
_revert_after_timeout(prev, display_map)
264+
)
212265
if _tray is not None:
213266
_tray.set_state_text(_state_label(current_state))
214267

0 commit comments

Comments
 (0)