Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 1 addition & 8 deletions examples/demo.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,13 @@
* Can be closed with Escape or by pressing the window close button.
* In both cases, it should print "Close detected" exactly once.
* Hit "f" to spend 2 seconds doing direct draws.
* Hit "s" to async-sleep the scheduling loop for 2 seconds. Resizing
and closing the window still work.

"""

import time

from rendercanvas.auto import RenderCanvas, loop
from rendercanvas.utils.cube import setup_drawing_sync
from rendercanvas.utils.asyncs import sleep
import rendercanvas


Expand All @@ -41,7 +38,7 @@


@canvas.add_event_handler("*")
async def process_event(event):
def process_event(event):
global cursor_index

if event["event_type"] not in ["pointer_move", "before_draw", "animate"]:
Expand All @@ -59,10 +56,6 @@ async def process_event(event):
i += 1
canvas.force_draw()
print(f"Drew {i} frames in 2s.")
elif event["key"] == "s":
print("Async sleep ... zzzz")
await sleep(2)
print("waking up")
elif event["key"] == "c":
# Swap cursor
shapes = list(rendercanvas.CursorShape)
Expand Down
21 changes: 10 additions & 11 deletions rendercanvas/_events.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,6 @@ def add_handler(self, *args, order: float = 0) -> Callable:

Arguments:
callback (callable, optional): The event handler. Must accept a single event argument.
Can be a plain function or a coroutine function.
If you use async callbacks, see :ref:`async` for the limitations.
*types (list of EventType): A list of event types.
order (float): Set callback priority order. Callbacks with lower priorities
are called first. Default is 0. When an event is emitted, callbacks with
Expand Down Expand Up @@ -113,6 +111,10 @@ def decorator(_callback: Callable):
return decorator(callback)

def _add_handler(self, callback, order, *types):
if iscoroutinefunction(callback):
raise TypeError(
"Coroutines cannot be callbacks (anymore). Instead, you can use a regular callback that calls `loop.add_task(coro)`."
)
if self._closed:
return
self.remove_handler(callback, *types)
Expand Down Expand Up @@ -166,7 +168,7 @@ def submit(self, event):

self._pending_events.append(event)

async def flush(self):
def flush(self):
"""Dispatch all pending events.

This should generally be left to the scheduler.
Expand All @@ -176,9 +178,9 @@ async def flush(self):
event = self._pending_events.popleft()
except IndexError:
break
await self.emit(event)
self.emit(event)

async def emit(self, event):
def emit(self, event):
"""Directly emit the given event.

In most cases events should be submitted, so that they are flushed
Expand All @@ -192,15 +194,12 @@ async def emit(self, event):
if event.get("stop_propagation", False):
break
with log_exception(f"Error during handling {event_type} event"):
if iscoroutinefunction(callback):
await callback(event)
else:
callback(event)
callback(event)
# Close?
if event_type == "close":
self._release()

async def close(self):
def close(self):
"""Close the event handler.

Drops all pending events, send the close event, and disables the emitter.
Expand All @@ -209,4 +208,4 @@ async def close(self):
if not self._closed:
self._pending_events.clear()
self.submit({"event_type": "close"})
await self.flush()
self.flush()
2 changes: 1 addition & 1 deletion rendercanvas/_loop.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ async def _loop_task(self):
closed_canvas_ids = set(event_emitters) - set(new_event_emitters)
for canvas_id in closed_canvas_ids:
events = event_emitters[canvas_id]
await events.close()
events.close()

# Keep canvases alive
for canvas in canvases:
Expand Down
4 changes: 2 additions & 2 deletions rendercanvas/_scheduler.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ async def __scheduler_task(self):
# Process events, handlers may request a draw
if (canvas := self.get_canvas()) is None:
break
await canvas._process_events()
canvas._process_events()
del canvas

# Determine what to do next ...
Expand Down Expand Up @@ -176,7 +176,7 @@ async def __scheduler_task(self):
if not do_draw:
continue

await self._events.emit({"event_type": "before_draw"})
self._events.emit({"event_type": "before_draw"})

# Ask the canvas to draw
if (canvas := self.get_canvas()) is None:
Expand Down
6 changes: 3 additions & 3 deletions rendercanvas/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -308,8 +308,8 @@ def submit_event(self, event: dict) -> None:

# %% Scheduling and drawing

async def _process_events(self):
"""Process events and animations (async).
def _process_events(self):
"""Process events and animations.

Called from the scheduler.
"""
Expand All @@ -323,7 +323,7 @@ async def _process_events(self):

# Flush our events, so downstream code can update stuff.
# Maybe that downstream code request a new draw.
await self._events.flush()
self._events.flush()

# TODO: implement later (this is a start but is not tested)
# Schedule animation events until the lag is gone
Expand Down
4 changes: 2 additions & 2 deletions rendercanvas/stub.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,8 @@ class StubRenderCanvas(BaseRenderCanvas):
def _final_canvas_init(self):
return super()._final_canvas_init()

async def _process_events(self):
return await super()._process_events()
def _process_events(self):
return super()._process_events()

def _draw_frame_and_present(self):
return super()._draw_frame_and_present()
Expand Down
10 changes: 1 addition & 9 deletions tests/test_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -198,15 +198,7 @@ def handler(event):
c.submit_event({"event_type": "key_down", "value": 1})
c.submit_event({"event_type": "key_down", "value": 2})

def sync_flush(events):
coro = events.flush()
while True:
try:
coro.send(None)
except StopIteration:
break

sync_flush(c._events)
c._events.flush()
assert events == [1, 2]


Expand Down
Loading