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

From: Michael Albinus <[email-masked]>
Date: Thu, 06 Feb 2025 12:56:41 +0100

Eli Zaretskii <[email-masked]> writes:

Hi Eli,

>>                                  why would those not be ale to run the
>> hook?  If it's because it's in a separate UI thread, they can push to
>> `pending_funcalls`, or in the worst case they can add an event into the
>> event queue and then use `special-event-map` to run an ad-hoc function
>> which runs the hook.
>>
>> Of course, we could similarly make the D-bus code manually do
>> (lookup-key special-event-map [sleep-event])
>
> Thanks, so which of these solutions would you recommend as the
> cleanest and the most convenient/extensible one?
>
> Michael, do you have any opinions or comments about these
> possibilities, from the D-Bus support POV?

I'm against to touch the D-Bus code because of this. Unneeded
dependency.

I've assembled a POC patch (appended), which adds the sleep-event
special event to special-event-map, and which adds a new function
insert-special-event, all on C level. With this, I'm able to eval in the
*scratch* buffer

--8<---------------cut here---------------start------------->8---
(defun sleep-handle-event (event)
  (declare (completion ignore))
  (interactive "e")
  (message "Event arrived: %S" event))

(insert-special-event '(sleep-event t))
--8<---------------cut here---------------end--------------->8---

insert-special-event is not restricted to the sleep-event event, but
shall support all special events, finally.

Comments?

Best regards, Michael.

diff --git a/src/keyboard.c b/src/keyboard.c
index 2d8c45c05ee..e6539582eea 100644
--- a/src/keyboard.c
+++ b/src/keyboard.c
@@ -4273,6 +4273,7 @@ kbd_buffer_get_event (KBOARD **kbp,
       case CONFIG_CHANGED_EVENT:
       case FOCUS_OUT_EVENT:
       case SELECT_WINDOW_EVENT:
+      case SLEEP_EVENT:
         {
           obj = make_lispy_event (&event->ie);
           kbd_fetch_ptr = next_kbd_event (event);
@@ -7110,6 +7111,9 @@ make_lispy_event (struct input_event *event)
 #endif
 #endif /* USE_FILE_NOTIFY */

+    case SLEEP_EVENT:
+      return Fcons (Qsleep_event, event->arg);
+
     case CONFIG_CHANGED_EVENT:
 	return list3 (Qconfig_changed_event,
 		      event->arg, event->frame_or_window);
@@ -11631,6 +11635,36 @@ DEFUN ("input-pending-p", Finput_pending_p, Sinput_pending_p, 0, 1, 0,
 	  ? Qt : Qnil);
 }

+DEFUN ("insert-special-event", Finsert_special_event, Sinsert_special_event,
+       1, 1, 0,
+       doc: /* Insert a special EVENT into the input queue.  */)
+  (Lisp_Object event)
+{
+  /* Check, that it is a special event.  */
+  CHECK_CONS (event);
+  if (NILP (access_keymap
+	    (get_keymap (Vspecial_event_map, 0, 1), event, 0, 0, 1)))
+    signal_error ("Invalid event kind", XCAR (event));
+
+  /* Construct an input event.  */
+  struct input_event ie;
+  EVENT_INIT (ie);
+  ie.kind =
+    /* TODO: Add the other special event kinds.  */
+    (EQ (XCAR (event), Qsleep_event) ? SLEEP_EVENT
+#ifdef HAVE_DBUS
+     : EQ (XCAR (event), Qdbus_event) ? DBUS_EVENT
+#endif
+     : NO_EVENT);
+  ie.frame_or_window = Qnil;
+  ie.arg = CDR (event);
+
+  /* Store it into the input event queue.  */
+  kbd_buffer_store_event (&ie);
+
+  return (Qnil);
+}
+
 /* Reallocate recent_keys copying the recorded keystrokes
    in the right order.  */
 static void
@@ -12803,6 +12837,7 @@ init_while_no_input_ignore_events (void)
 #ifdef THREADS_ENABLED
   events = Fcons (Qthread_event, events);
 #endif
+  events = Fcons (Qsleep_event, events);

   return events;
 }
@@ -12826,6 +12861,7 @@ is_ignored_event (union buffered_input_event *event)
 #ifdef HAVE_DBUS
     case DBUS_EVENT: ignore_event = Qdbus_event; break;
 #endif
+    case SLEEP_EVENT: ignore_event = Qsleep_event; break;
     default: ignore_event = Qnil; break;
     }

@@ -12931,6 +12967,7 @@ syms_of_keyboard (void)
 #endif /* USE_FILE_NOTIFY */

   DEFSYM (Qtouch_end, "touch-end");
+  DEFSYM (Qsleep_event, "sleep-event");

   /* Menu and tool bar item parts.  */
   DEFSYM (QCenable, ":enable");
@@ -13144,6 +13181,7 @@ syms_of_keyboard (void)
   defsubr (&Srecursive_edit);
   defsubr (&Sinternal_track_mouse);
   defsubr (&Sinput_pending_p);
+  defsubr (&Sinsert_special_event);
   defsubr (&Slossage_size);
   defsubr (&Srecent_keys);
   defsubr (&Sthis_command_keys);
@@ -14017,6 +14055,8 @@ keys_of_keyboard (void)
 			    "handle-focus-out");
   initial_define_lispy_key (Vspecial_event_map, "move-frame",
 			    "handle-move-frame");
+  initial_define_lispy_key (Vspecial_event_map, "sleep-event",
+			    "sleep-handle-event");
 }

 /* Mark the pointers in the kboard objects.
diff --git a/src/termhooks.h b/src/termhooks.h
index 0795148f1af..a77ca25e159 100644
--- a/src/termhooks.h
+++ b/src/termhooks.h
@@ -291,6 +291,9 @@ #define EMACS_TERMHOOKS_H
   , FILE_NOTIFY_EVENT
 #endif

+  /* Sleep/wake event.  */
+  , SLEEP_EVENT
+
   /* Pre-edit text was changed. */
   , PREEDIT_TEXT_EVENT