Subject: Re: bug#63620: 30.0.50; [Feature Request] run hooks on sleep/wake

From: Andrew Cohen <[email-masked]>
Date: Tue, 04 Feb 2025 11:19:55 +0800

I have not had much time for Emacs outside of my regular activities, but
I made the changes you suggested and have been using the package for the
past year. Unless I hear objections, I'll push the package to master
sometime soon.

Best,
Andy

ea288bd05e7d11740f5d580771ed7ca5ad496b15
Author:     Andrew G Cohen <[email-masked]>
AuthorDate: Thu Mar 21 11:06:36 2024 +0800
Commit:     Andrew G Cohen <[email-masked]>
CommitDate: Tue Feb 4 11:14:26 2025 +0800

Parent:     c54d8d4cbe0 New functions to suspend and resume gnus demon
Merged:     master
Contained:  feature/igc
Follows:    emacs-29.1.90 (176369)

New sleep-wake-mode to run hooks on sleep state change

* lisp/sleep.el: New global minor mode. When enabled, the hooks
sleep-wake-hook and sleep-sleep-hook are run on the corresponding sleep
state change.

2 files changed, 112 insertions(+)
etc/NEWS      |   6 ++++
lisp/sleep.el | 106 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

modified   etc/NEWS
@@ -1015,6 +1015,12 @@ destination window is chosen using 'display-buffer-alist'.  Example:
 
 * New Modes and Packages in Emacs 31.1
 
+** New global minor mode 'sleep-wake'.
+With this minor mode enabled, the hooks 'sleep-sleep-hook' and
+'sleep-wake-hook' are run when the device running Emacs enters or leaves
+the sleep state. Currently only D-Bus detection of device sleep state
+changes is available.
+
 
 * Incompatible Lisp Changes in Emacs 31.1
 
new file   lisp/sleep.el
@@ -0,0 +1,106 @@
+;;; sleep.el --- run hooks on device sleep and wake  -*- lexical-binding:t -*-
+
+;; Copyright (C) 2025 Free Software Foundation, Inc.
+
+;; Author: Andrew Cohen <>
+;; Maintainer: [email-masked]
+;; 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 <https://www.gnu.org/licenses/>.
+
+;;; 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-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-registration-object nil
+  "Object returned from `dbus-register-signal'.
+This is recorded so that the signal may be unregistered.")
+
+
+(defun sleep-dbus-enable ()
+  "Enable D-Bus detection of device sleep/wake state change.
+Run `sleep-sleep-hook' and `sleep-wake-hook' as appropriate."
+  (unless sleep-registration-object
+    (setq sleep-registration-object
+          (dbus-register-signal :system
+                                "org.freedesktop.login1"
+                                "/org/freedesktop/login1"
+                                "org.freedesktop.login1.Manager"
+                                "PrepareForSleep"
+                                #'sleep-handler))))
+
+(defun sleep-dbus-disable ()
+  "Disable D-Bus detection of device sleep/wake state change."
+  (condition-case nil
+      (progn
+        (ignore-error (dbus-error wrong-type-argument)
+          (dbus-unregister-object
+           sleep-registration-object))
+        (setq sleep-registration-object nil))
+    (wrong-type-argument nil)))
+
+(defun sleep-handler (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)))
+    (if sleep-wake-mode
+        (sleep-dbus-enable)
+      (sleep-dbus-disable)))
+   (t
+    (message "No sleep/wake detection method found."))))
+
+(provide 'sleep)
+;;; sleep.el ends here

-- 
Andrew Cohen