aboutsummaryrefslogtreecommitdiff
path: root/subprojects/d2tk/pugl/doc/c/event-loop.rst
blob: 3b9915fdea0c42b751dc684852c104eaace6563a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
.. default-domain:: c
.. highlight:: c

######################
Driving the Event Loop
######################

Pugl does not contain any threads or other event loop "magic".
For flexibility, the event loop is driven explicitly by repeatedly calling :func:`puglUpdate`,
which processes events from the window system and dispatches them to views when necessary.

The exact use of :func:`puglUpdate` depends on the application.
Plugins should call it with a ``timeout`` of 0 in a callback driven by the host.
This avoids blocking the main loop,
since other plugins and the host itself need to run as well.

A program can use whatever timeout is appropriate:
event-driven applications may wait forever by using a ``timeout`` of -1,
while those that draw continuously may use a significant fraction of the frame period
(with enough time left over to render).

*********
Redrawing
*********

Occasional redrawing can be requested by calling :func:`puglPostRedisplay` or :func:`puglPostRedisplayRect`.
After these are called,
a :struct:`PuglEventExpose` will be dispatched on the next call to :func:`puglUpdate`.

For continuous redrawing,
call :func:`puglPostRedisplay` while handling a :struct:`PuglEventUpdate` event.
This event is sent just before views are redrawn,
so it can be used as a hook to expand the update region right before the view is exposed.
Anything else that needs to be done every frame can be handled similarly.

*****************
Event Dispatching
*****************

Ideally, pending events are dispatched during a call to :func:`puglUpdate`,
directly within the scope of that call.

Unfortunately, this is not universally true due to differences between platforms.

MacOS
=====

On MacOS, drawing is handled specially and not by the normal event queue mechanism.
This means that configure and expose events,
and possibly others,
may be dispatched to a view outside the scope of a :func:`puglUpdate` call.
In general, you can not rely on coherent event dispatching semantics on MacOS:
the operating system can call into application code at "random" times,
and these calls may result in Pugl events being dispatched.

An application that follows the Pugl guidelines should work fine,
but there is one significant inconsistency you may encounter on MacOS:
posting a redisplay will not wake up a blocked :func:`puglUpdate` call.

Windows
=======

On Windows, the application has relatively tight control over the event loop,
so events are typically dispatched explicitly by :func:`puglUpdate`.
Drawing is handled by events,
so posting a redisplay will wake up a blocked :func:`puglUpdate` call.

However, it is possible for the system to dispatch events at other times.
So,
it is possible for events to be dispatched outside the scope of a :func:`puglUpdate` call,
but this does not happen in normal circumstances and can largely be ignored.

X11
===

On X11, the application strictly controls event dispatching,
and there is no way for the system to call into application code at surprising times.
So, all events are dispatched in the scope of a :func:`puglUpdate` call.

*********************
Recursive Event Loops
*********************

On Windows and MacOS,
the event loop is stalled while the user is resizing the window or,
on Windows,
has displayed the window menu.
This means that :func:`puglUpdate` will block until the resize is finished,
or the menu is closed.

Pugl dispatches :struct:`PuglEventLoopEnter` and :struct:`PuglEventLoopLeave` events to notify the application of this situation.
If you want to continuously redraw during resizing on these platforms,
you can schedule a timer with :func:`puglStartTimer` when the recursive loop is entered,
and post redisplays when handling the :struct:`PuglEventTimer`.
Be sure to remove the timer with :func:`puglStopTimer` when the recursive loop is finished.

On X11, there are no recursive event loops,
and everything works as usual while the user is resizing the window.
There is nothing special about a "live resize" on X11,
and the above loop events will never be dispatched.