# Copyright 2023 (c) Anna Schumaker. """Functions for configuring a callback at a specific time.""" import datetime import math from gi.repository import GLib _GSOURCE_MAPPING = dict() _NEXT_ALARM_ID = 1 def _calc_seconds(time: datetime.time) -> int: """Calculate the number of seconds until the given time.""" now = datetime.datetime.now() then = datetime.datetime.combine(now.date(), time) if now >= then: then += datetime.timedelta(days=1) return math.ceil((then - now).total_seconds()) def __set_alarm(time: datetime.time, func: callable, alarm_id: int) -> None: gsrcid = GLib.timeout_add_seconds(_calc_seconds(time), _do_alarm, time, func, alarm_id) _GSOURCE_MAPPING[alarm_id] = gsrcid return alarm_id def _do_alarm(time: datetime.time, func: callable, alarm_id: int) -> bool: """Run an alarm callback.""" func() __set_alarm(time, func, alarm_id) return GLib.SOURCE_REMOVE def set_alarm(time: datetime.time, func: callable) -> int: """Register a callback to be called at a specific time.""" global _NEXT_ALARM_ID res = __set_alarm(time, func, _NEXT_ALARM_ID) _NEXT_ALARM_ID += 1 return res def cancel_alarm(alarm_id: int) -> None: """Cancel an alarm.""" GLib.source_remove(_GSOURCE_MAPPING[alarm_id]) del _GSOURCE_MAPPING[alarm_id]