Add Event Watchers and Filters
Adds pygame.event.add_event_watcher, pygame.event.remove_event_watcher, pygame.event.add_event_filter, and pygame.event.remove_event_filter as loose wrappers around the corresponding SDL functions as a potential new way to handle events.
This has two primary rationales. Firstly, to allow using an event handler paradigm if desired while having no impact on the standard event loop structure. As this PR does nothing without explicitly opting into it opens up more options while not having any impact on other methods of handling events.
Secondarily, event watchers can be used as an effective solution for the quirk of the Windows version of SDL of the main thread freezing while the OS is sending resize or window movement events. This allows for more advanced users who may be impacted by the issue to resolve it without having to mess with the windows APIs directly. An example of the issue from upstream pygame can be found here.
A simple example that will print out all events that are added to the queue could be done like this:
@pygame.event.add_event_watcher
def event_logger(ev):
print(ev)
and an example of a filter that will block only left click events:
@pygame.event.add_event_filter
def left_click_filter(ev):
if ev.type == pygame.MOUSEBUTTONDOWN and ev.button == BUTTON_LEFT:
return True # Returns true to filter out the event
return False
I have also created a more complex demo implementation showcasing the event watchers as well as demonstrating both the windows issue and an example solution for the issue here.
Summary by CodeRabbit
-
New Features
- Added event watcher API to register callbacks that receive converted events in real time.
- Added event filter API to register filters that can block or allow events before delivery (thread-safe, short-circuiting).
-
Documentation
- Added reference docs describing watcher/filter signatures, behavior, threading notes, return semantics, and error handling.
-
Tests
- Added unit tests covering add/remove semantics, multiple watchers, filter behavior, and error cases.
[!WARNING]
Rate limit exceeded
@SuperRedingBros has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 24 minutes and 34 seconds before requesting another review.
⌛ How to resolve this issue?
After the wait time has elapsed, a review can be triggered using the
@coderabbitai reviewcommand as a PR comment. Alternatively, push new commits to this PR.We recommend that you space out your commits to avoid hitting the rate limit.
🚦 How do rate limits work?
CodeRabbit enforces hourly rate limits for each developer per organization.
Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.
Please see our FAQ for further information.
📥 Commits
Reviewing files that changed from the base of the PR and between c3282b131580ffcfe566c338b409090fda95dda9 and 1df883eeec383c0a2f7d74b07a7484582298e325.
📒 Files selected for processing (3)
buildconfig/stubs/pygame/event.pyi(2 hunks)src_c/event.c(7 hunks)test/event_test.py(1 hunks)
📝 Walkthrough
Walkthrough
Adds four new event APIs (add/remove event watcher and filter): type stubs, docs, C implementation with internal state and synchronization, watcher wrapper and proxy event constructor, and unit tests covering add/remove semantics and runtime behavior.
Changes
| Cohort / File(s) | Summary |
|---|---|
Type stubs buildconfig/stubs/pygame/event.pyi |
Added generic declarations for add_event_watcher, remove_event_watcher, add_event_filter, and remove_event_filter with positional-only parameter signatures and appropriate return types. |
Documentation docs/reST/ref/event.rst |
Added documentation blocks for the four new APIs describing signatures, behavior, threading notes, return values, and error handling. |
C documentation macros src_c/doc/event_doc.h |
Added macros: DOC_EVENT_ADDEVENTWATCHER, DOC_EVENT_REMOVEEVENTWATCHER, DOC_EVENT_ADDEVENTFILTER, DOC_EVENT_REMOVEEVENTFILTER. |
Core implementation src_c/event.c |
Implemented watcher/filter mechanisms, new Python-exposed methods (add_event_watcher, remove_event_watcher, add_event_filter, remove_event_filter), internal userFilters state, mutex-protected operations, pg_watcher_wrapper, pg_eventNew_no_free_proxy, and integrated filter short-circuiting into event processing. |
Tests test/event_test.py |
Added tests: test_add_event_watcher, test_remove_event_watcher, test_add_event_filter, test_remove_event_filter verifying add/remove semantics and runtime behavior. |
Sequence Diagram(s)
sequenceDiagram
autonumber
participant App as Application
participant Pygame as Pygame Event System
participant Filters as User Filters
participant Watchers as User Watchers
rect rgb(230,240,255)
note over App,Pygame: Register handlers
App->>Pygame: add_event_filter(filter_fn)
Pygame->>Filters: store filter_fn (thread-safe)
App->>Pygame: add_event_watcher(watcher_fn)
Pygame->>Watchers: store watcher_fn (thread-safe)
end
rect rgb(220,255,220)
note over App,Pygame: Event dispatch
App->>Pygame: post_event(event)
Pygame->>Pygame: check enabled
alt enabled
loop filters
Pygame->>Filters: filter_fn(event)
alt filter returns true
Pygame->>Pygame: drop event (stop)
else
Pygame->>Pygame: continue
end
end
loop watchers
Pygame->>Watchers: watcher_fn(converted Event)
end
Pygame->>Pygame: deliver event to normal handlers
end
end
rect rgb(255,235,220)
note over App,Pygame: Unregister handlers
App->>Pygame: remove_event_filter(filter_fn)
Pygame->>Filters: remove filter_fn (thread-safe)
App->>Pygame: remove_event_watcher(watcher_fn)
Pygame->>Watchers: remove watcher_fn (thread-safe)
end
Estimated code review effort
🎯 4 (Complex) | ⏱️ ~45 minutes
- Inspect thread-safety and locking around
userFiltersand watcher storage. - Verify reference counting and lifetime for
pg_eventNew_no_free_proxyand the event wrapper. - Confirm filter short-circuiting integrates correctly with existing enabled-check and delivery paths.
- Check module init/teardown for allocation and cleanup of new state.
Poem
🐰 I nibble at events both near and far,
I watch the hops and filter each tiny star,
Callbacks sit lightly, mutexes guard the gate,
Four new friends join the eventful state,
Hooray — the stream now dances, neat and straight.
Pre-merge checks and finishing touches
✅ Passed checks (2 passed)
| Check name | Status | Explanation |
|---|---|---|
| Description Check | ✅ Passed | Check skipped - CodeRabbit’s high-level summary is enabled. |
| Title check | ✅ Passed | The title 'Add Event Watchers and Filters' directly and clearly summarizes the main change—introducing four new event watcher and filter functions to the pygame.event module. |
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.
Comment @coderabbitai help to get the list of available commands and usage tips.
- Ideally it would have been better if you opened a new issue to discuss the API before implementing it.
Fair enough, I'll try to keep that in mind for the future. Should I make a new issue to discuss this there?
- SDL3, which is what we are porting pygame-ce to, has the new main callbacks API. Ideally, any new API we add must follow SDL3 style/behaviour even if implemented in the current SDL2 codebase.
I do remember reading that somewhere, would you suggest making the event watchers behave more like SDL_AppEvent?
- For this PR, I am not opposed to adding event callbacks but I believe there should be only one thing added, and that should be equivalent to SDL3's
SDL_AppEvent. Adding both watchers and filters is exposing too much details to the users and is potentially more confusing IMHO.
Also pretty fair, I mostly just added the filters because I considered them an adjacent feature that I figured I would add while I was adding the event watchers. If you think that they are making things more confusing I have no problem with removing them.
would you suggest making the event watchers behave more like SDL_AppEvent?
yes that is what I would personally prefer.
Should I make a new issue to discuss this there?
That would be appreciated, I would also like to hear other contributors opinions on this API.