1
# ----------------------------------------------------------------------------
3
# Copyright (c) 2006-2008 Alex Holkner
6
# Redistribution and use in source and binary forms, with or without
7
# modification, are permitted provided that the following conditions
10
# * Redistributions of source code must retain the above copyright
11
# notice, this list of conditions and the following disclaimer.
12
# * Redistributions in binary form must reproduce the above copyright
13
# notice, this list of conditions and the following disclaimer in
14
# the documentation and/or other materials provided with the
16
# * Neither the name of pyglet nor the names of its
17
# contributors may be used to endorse or promote products
18
# derived from this software without specific prior written
21
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32
# POSSIBILITY OF SUCH DAMAGE.
33
# ----------------------------------------------------------------------------
35
'''Application-wide functionality.
37
Most applications need only call `run` after creating one or more windows
38
to begin processing events. For example, a simple application consisting of
41
from pyglet import app
42
from pyglet import window
47
To handle events on the main event loop, instantiate it manually. The
48
following example exists the application as soon as any window is closed (the
49
default policy is to wait until all windows are closed)::
51
event_loop = app.EventLoop()
54
def on_window_close(window):
60
__docformat__ = 'restructuredtext'
61
__version__ = '$Id: __init__.py 2049 2008-05-02 01:50:36Z Alex.Holkner $'
66
from pyglet import clock
67
from pyglet import event
69
_is_epydoc = hasattr(sys, 'is_epydoc') and sys.is_epydoc
71
class WeakSet(object):
72
'''Set of objects, referenced weakly.
74
Adding an object to this set does not prevent it from being garbage
75
collected. Upon being garbage collected, the object is automatically
79
self._dict = weakref.WeakKeyDictionary()
82
self._dict[value] = True
84
def remove(self, value):
88
for key in self._dict.keys():
91
def __contains__(self, other):
92
return other in self._dict
95
return len(self._dict)
97
#: Set of all open displays. Instances of `Display` are automatically added
98
#: to this set upon construction. The set uses weak references, so displays
99
#: are removed from the set when they are no longer referenced.
104
#: Set of all open windows (including invisible windows). Instances of
105
#: `Window` are automatically added to this set upon construction. The set
106
#: uses weak references, so windows are removed from the set when they are no
107
#: longer referenced or are closed explicitly.
113
class BaseEventLoop(event.EventDispatcher):
114
'''The main run loop of the application.
116
Calling `run` begins the application event loop, which processes
117
operating system events, calls `pyglet.clock.tick` to call scheduled
118
functions and calls `pyglet.window.Window.on_draw` and
119
`pyglet.window.Window.flip` to update window contents.
121
Applications can subclass `EventLoop` and override certain methods
122
to integrate another framework's run loop, or to customise processing
123
in some other way. You should not in general override `run`, as
124
this method contains platform-specific code that ensures the application
125
remains responsive to the user while keeping CPU usage to a minimum.
128
#: Flag indicating if the event loop will exit in the next iteration.
133
'''Begin processing events, scheduled functions and window updates.
135
This method returns when `has_exit` is set to True.
137
Developers are discouraged from overriding this method, as the
138
implementation is platform-specific.
140
raise NotImplementedError('abstract')
146
# Disable event queuing for dispatch_events
147
from pyglet.window import Window
148
Window._enable_event_queue = False
150
# Dispatch pending events
151
for window in windows:
153
window.dispatch_pending_events()
155
def _idle_chance(self):
156
'''If timeout has expired, manually force an idle loop.
158
Called by window that have blocked the event loop (e.g. during
163
'''Called during each iteration of the event loop.
165
The method is called immediately after any window events (i.e., after
166
any user input). The method can return a duration after which
167
the idle method will be called again. The method may be called
168
earlier if the user creates more input events. The method
169
can return `None` to only wait for user events.
171
For example, return ``1.0`` to have the idle method called every
172
second, or immediately after any user events.
174
The default implementation dispatches the
175
`pyglet.window.Window.on_draw` event for all windows and uses
176
`pyglet.clock.tick` and `pyglet.clock.get_sleep_time` on the default
177
clock to determine the return value.
179
This method should be overridden by advanced users only. To have
180
code execute at regular intervals, use the
181
`pyglet.clock.schedule` methods.
184
:return: The number of seconds before the idle method should
185
be called again, or `None` to block for user input.
187
dt = clock.tick(True)
190
for window in windows:
193
window.dispatch_event('on_draw')
197
return clock.get_sleep_time(True)
200
'''Safely exit the event loop at the end of the current iteration.
202
This method is convenience for setting `has_exit` to ``True``.
206
def on_window_close(self, window):
207
'''Default window close handler.'''
212
def on_window_close(window):
213
'''A window was closed.
215
This event is dispatched when a window is closed. It is not
216
dispatched if the window's close button was pressed but the
217
window did not close.
219
The default handler calls `exit` if no more windows are open. You
220
can override this handler to base your application exit on some
227
'''The event loop is about to begin.
229
This is dispatched when the event loop is prepared to enter
230
the main run loop, and represents the last chance for an
231
application to initialise itself.
237
'''The event loop is about to exit.
239
After dispatching this event, the `run` method returns (the
240
application may not actually exit if you have more code
241
following the `run` invocation).
246
BaseEventLoop.register_event_type('on_window_close')
247
BaseEventLoop.register_event_type('on_enter')
248
BaseEventLoop.register_event_type('on_exit')
250
#: The global event loop. Set to the correct instance when an `EventLoop` is
253
#: :type: `EventLoop`
257
'''Begin processing events, scheduled functions and window updates.
259
This is a convenience function, equivalent to::
267
'''Exit the application event loop.
269
Causes the application event loop to finish, if an event loop is currently
270
running. The application may not necessarily exit (for example, there may
271
be additional code following the `run` invocation).
273
This is a convenience function, equivalent to::
282
EventLoop = BaseEventLoop
283
EventLoop.__name__ = 'EventLoop'
286
# Permit cyclic import.
288
pyglet.app = sys.modules[__name__]
290
if sys.platform == 'darwin':
291
from pyglet.app.carbon import CarbonEventLoop as EventLoop
292
elif sys.platform in ('win32', 'cygwin'):
293
from pyglet.app.win32 import Win32EventLoop as EventLoop
295
from pyglet.app.xlib import XlibEventLoop as EventLoop