If someone builds without dbus, say on macOS, does this approach work without dbus? On Wed, Feb 5, 2025 at 8:44 PM Andrew Cohen wrote: > >>>>> "SM" == Stefan Monnier writes: > > >>> Maybe a hook is not such a bad idea after all. > >> But then how would platforms where these events come from the > >> window-system call that hook? > > SM> I don't understand the question: why would those not be ale to > SM> run the hook? If it's because it's in a separate UI thread, > SM> they can push to `pending_funcalls`, or in the worst case they > SM> can add an event into the event queue and then use > SM> `special-event-map` to run an ad-hoc function which runs the > SM> hook. > > I remain open to other ideas, but it seems to me that the most > straightforward is to allow systems to add a sleep-event into the event > queue. My original code installed a callback function to run the hooks > when a state change is detected. So this same function can be installed > into special-event-map and the behavior on all systems is the same. > > I've modified the code a bit---I've made the handler function > configurable with a defcustom and set it by default to the function that > just runs the hooks. But the same handler will be used on both > sleep-events and dbus detection. The only difference is that if the > system supports dbus, dbus detection of state changes will be used, > while in other cases sleep-events will trigger the handler. > > ;;; sleep.el --- run hooks on device sleep and wake -*- lexical-binding:t > -*- > > ;; Copyright (C) 2025 Free Software Foundation, Inc. > > ;; Author: Andrew Cohen <> > ;; Maintainer: emacs-devel@gnu.org > ;; Keywords: > > ;; This file is part of GNU Emacs. > > ;; GNU Emacs is free software: you can redistribute it and/or modify > ;; it under the terms of the GNU General Public License as published by > ;; the Free Software Foundation, either version 3 of the License, or > ;; (at your option) any later version. > > ;; GNU Emacs is distributed in the hope that it will be useful, > ;; but WITHOUT ANY WARRANTY; without even the implied warranty of > ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > ;; GNU General Public License for more details. > > ;; You should have received a copy of the GNU General Public License > ;; along with GNU Emacs. If not, see . > > ;;; Commentary: > > ;;; This global minor mode enables evaluating code when the device > ;;; running Emacs enters or leaves the sleep state. The hooks > ;;; `sleep-sleep-hook' and `sleep-wake-hook' are run when the system > ;;; detects that it is going to sleep or waking up. Currently only a > ;;; D-Bus interface to detect sleep state change is implemented. > > ;;; Code: > > (require 'dbus) > > (defgroup sleep nil > "Run hooks on device entering/leaving the sleep state." > :group 'hardware) > > (defcustom sleep-handler-function 'handle-sleep-event > "Function called on device sleep state change. > The function takes a single boolean argument (t for sleep and nil for > wake). The default function just runs the sleep and wake hooks." > :group 'sleep > :type 'function) > > (defcustom sleep-sleep-hook nil > "Hook to run on device entering sleep." > :group 'sleep > :type 'hook) > > (defcustom sleep-wake-hook nil > "Hook to run on device leaving sleep." > :group 'sleep > :type 'hook) > > (defvar sleep-dbus-registration-object nil > "Object returned from `dbus-register-signal'. > This is recorded so that the signal may be unregistered.") > > (defun sleep-dbus-detection (mode) > "Enable D-Bus detection of device sleep/wake state change. > When enabled run `sleep-handler-function' when a state change is > detected. Disable detection if MODE is nil." > (if mode > (unless sleep-dbus-registration-object > (setq sleep-dbus-registration-object > (dbus-register-signal :system > "org.freedesktop.login1" > "/org/freedesktop/login1" > "org.freedesktop.login1.Manager" > "PrepareForSleep" > sleep-handler-function))) > (condition-case nil > (progn > (ignore-error (dbus-error wrong-type-argument) > (dbus-unregister-object > sleep-dbus-registration-object)) > (setq sleep-dbus-registration-object nil)) > (wrong-type-argument nil)))) > > (defun handle-sleep-event (sleep-wake) > "Handler to execute sleep and wake functions. > SLEEP-WAKE is t on sleeping and nil on waking." > (ignore-errors > (if sleep-wake > (run-hooks 'sleep-sleep-hook) > (run-hooks 'sleep-wake-hook)))) > > ;;;###autoload > (define-minor-mode sleep-wake-mode > "Toggle sleep/wake detection. > > With `sleep-wake-mode' enabled, the hooks `sleep-sleep-hook' and > `sleep-wake-hook' will be executed when the device enters or leaves the > sleep state. This is currently only available on systems that support > D-Bus detection of sleep state changes." > :global t > :group 'sleep > (cond > ((and (featurep 'dbusbind) > (member "org.freedesktop.login1" > (dbus-list-activatable-names :system))) > (sleep-dbus-detection sleep-wake-mode)) > (t > (if sleep-wake-mode > (define-key special-event-map [sleep-event] sleep-handler-function) > (define-key special-event-map [sleep-event] 'ignore))))) > > (provide 'sleep) > ;;; sleep.el ends here > > > -- > Andrew Cohen >