From f7aacbc4a9b8162230a7deff89c730e060dcaa44 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Tue, 18 Aug 2026 10:07:56 +0000 Subject: [PATCH] refactor(event): let modules translate their own platform events MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The SDL pump did the translation itself, so it had to know about keyboard, joystick, touch, window, graphics, audio and ui: eight upward dependencies from one of the engine's lowest modules, and the source of every remaining dependency cycle. Each module now registers an IPlatformEventSink for the events it owns and the pump only dispatches. Key and text events move to keyboard/sdl, joystick and game-controller events (including the hotplug device table) to joystick/sdl, finger events to touch/sdl, resize and the mobile background/foreground surface watch to window/sdl, the ImGui observer to ui, and Audio::pump to an end-of-pump hook in audio. The pump keeps only quit and window-close, which are about the event loop rather than any one module. Sinks run in priority order -- observer, then surface, then input -- so ImGui still sees events first and the window is resized before anything reads its size. The mobile surface teardown keeps using SDL_AddEventWatch rather than the poll path, since by the time SDL_PollEvent returns the native surface is gone; the watch is now installed by the window module on its first pump. Also removes exceptionIfInRenderPass, whose body has been commented out since it was written and whose only remaining effect was a graphics include. The engine dependency graph now has zero cycles, down from 26, and the back-edge whitelist is down to 2 (window -> graphics, window -> image). Layering is also right way up: event sits at L0 with the input modules above it at L1/L2. Verified: unit tests for event/input/ui/audio/thread pass, and the example smoke suite gives the same 19 pass / 9 fail as the pre-change baseline (those 9 fail on main too, from script API drift in the examples themselves). Co-authored-by: 西风逍遥游 --- scripts/module_depgraph.py | 21 +- src/modules/audio/EventSink.cpp | 31 +++ src/modules/event/PlatformEventSink.h | 59 ++++++ src/modules/event/sdl/Event.cpp | 282 ++----------------------- src/modules/event/sdl/Event.h | 2 +- src/modules/joystick/sdl/EventSink.cpp | 111 ++++++++++ src/modules/keyboard/sdl/EventSink.cpp | 67 ++++++ src/modules/touch/sdl/EventSink.cpp | 73 +++++++ src/modules/ui/EventSink.cpp | 36 ++++ src/modules/window/sdl/EventSink.cpp | 108 ++++++++++ 10 files changed, 511 insertions(+), 279 deletions(-) create mode 100644 src/modules/audio/EventSink.cpp create mode 100644 src/modules/event/PlatformEventSink.h create mode 100644 src/modules/joystick/sdl/EventSink.cpp create mode 100644 src/modules/keyboard/sdl/EventSink.cpp create mode 100644 src/modules/touch/sdl/EventSink.cpp create mode 100644 src/modules/ui/EventSink.cpp create mode 100644 src/modules/window/sdl/EventSink.cpp diff --git a/scripts/module_depgraph.py b/scripts/module_depgraph.py index f9c562ec..61df0d7d 100755 --- a/scripts/module_depgraph.py +++ b/scripts/module_depgraph.py @@ -25,25 +25,14 @@ MODULES_DIR = os.path.join(REPO, "src", "modules") INCLUDE_RE = re.compile(r'^\s*#\s*include\s*[<"]([^">]+)[">]', re.M) SOURCE_EXT = (".cpp", ".cc", ".h", ".hpp") -# Upward edges that break the layering. Each entry is a known debt item to be -# removed by the capability-registry work; the --check mode fails on anything -# outside this list so no new back-edge slips in. +# Upward edges that break the layering. Each entry is a known debt item; --check +# fails on anything outside this list so no new back-edge slips in, and reports +# entries that are no longer needed so the list shrinks as debt is paid off. KNOWN_BACK_EDGES = { - # event/sdl/Event.cpp: the SDL pump pushes into its consumers instead of - # letting them subscribe. - ("event", "audio"), - ("event", "filesystem"), - ("event", "graphics"), - ("event", "joystick"), - ("event", "keyboard"), - ("event", "touch"), - ("event", "ui"), - ("event", "window"), - # window/Window.cpp, window/sdl/Window.cpp + # window/Window.cpp, window/sdl/Window.cpp: the window owns the Graphics + # pointer and decodes its own icon image. ("window", "graphics"), ("window", "image"), - # ui/EditorHost.cpp: the headless editor host pumps events itself. - ("ui", "event"), } diff --git a/src/modules/audio/EventSink.cpp b/src/modules/audio/EventSink.cpp new file mode 100644 index 00000000..00d1ebb2 --- /dev/null +++ b/src/modules/audio/EventSink.cpp @@ -0,0 +1,31 @@ +// Drives streaming-source refills once per event pump. +// +// Audio::pump has nothing to do with platform events, but it does need a +// per-frame tick and the event pump was the only one available -- so the event +// module called into audio. Hanging it off the sink's end-of-pump hook keeps +// the timing identical without the dependency. + +#include "audio/Audio.h" +#include "common/Capability.h" +#include "common/Module.h" +#include "event/PlatformEventSink.h" + +namespace eve::audio { +namespace { + +class AudioPumpSink : public eve::event::IPlatformEventSink { +public: + void onPumpFinished() override { + if (auto *audio = eve::ModuleManager::getInstance