144 lines
5.7 KiB
Python
144 lines
5.7 KiB
Python
# ----------------------------------------------------------------------------
|
|
# pyglet
|
|
# Copyright (c) 2006-2008 Alex Holkner
|
|
# All rights reserved.
|
|
#
|
|
# Redistribution and use in source and binary forms, with or without
|
|
# modification, are permitted provided that the following conditions
|
|
# are met:
|
|
#
|
|
# * Redistributions of source code must retain the above copyright
|
|
# notice, this list of conditions and the following disclaimer.
|
|
# * Redistributions in binary form must reproduce the above copyright
|
|
# notice, this list of conditions and the following disclaimer in
|
|
# the documentation and/or other materials provided with the
|
|
# distribution.
|
|
# * Neither the name of pyglet nor the names of its
|
|
# contributors may be used to endorse or promote products
|
|
# derived from this software without specific prior written
|
|
# permission.
|
|
#
|
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
|
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
|
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
|
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
# POSSIBILITY OF SUCH DAMAGE.
|
|
# ----------------------------------------------------------------------------
|
|
|
|
'''
|
|
'''
|
|
|
|
__docformat__ = 'restructuredtext'
|
|
__version__ = '$Id: $'
|
|
|
|
import ctypes
|
|
|
|
from pyglet.app import windows, BaseEventLoop
|
|
from pyglet.window.carbon import carbon, types, constants, _oscheck
|
|
|
|
EventLoopTimerProc = ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.c_void_p)
|
|
kEventDurationForever = ctypes.c_double(constants.kEventDurationForever)
|
|
|
|
class CarbonEventLoop(BaseEventLoop):
|
|
def run(self):
|
|
self._setup()
|
|
|
|
e = ctypes.c_void_p()
|
|
event_dispatcher = carbon.GetEventDispatcherTarget()
|
|
self._event_loop = event_loop = carbon.GetMainEventLoop()
|
|
event_queue = carbon.GetMainEventQueue()
|
|
self._timer = timer = ctypes.c_void_p()
|
|
idle_event_proc = EventLoopTimerProc(self._timer_proc)
|
|
carbon.InstallEventLoopTimer(event_loop,
|
|
ctypes.c_double(0.1), #?
|
|
kEventDurationForever,
|
|
idle_event_proc,
|
|
None,
|
|
ctypes.byref(timer))
|
|
|
|
self._force_idle = False
|
|
self._allow_polling = True
|
|
|
|
self.dispatch_event('on_enter')
|
|
|
|
while not self.has_exit:
|
|
if self._force_idle:
|
|
duration = 0
|
|
else:
|
|
duration = kEventDurationForever
|
|
if carbon.ReceiveNextEvent(0, None, duration,
|
|
True, ctypes.byref(e)) == 0:
|
|
carbon.SendEventToEventTarget(e, event_dispatcher)
|
|
carbon.ReleaseEvent(e)
|
|
|
|
# Manual idle event
|
|
if carbon.GetNumEventsInQueue(event_queue) == 0 or self._force_idle:
|
|
self._force_idle = False
|
|
self._timer_proc(timer, None, False)
|
|
|
|
carbon.RemoveEventLoopTimer(self._timer)
|
|
self.dispatch_event('on_exit')
|
|
|
|
def _stop_polling(self):
|
|
carbon.SetEventLoopTimerNextFireTime(self._timer, ctypes.c_double(0.0))
|
|
|
|
def _enter_blocking(self):
|
|
carbon.SetEventLoopTimerNextFireTime(self._timer, ctypes.c_double(0.0))
|
|
self._allow_polling = False
|
|
|
|
def _exit_blocking(self):
|
|
self._allow_polling = True
|
|
|
|
def _timer_proc(self, timer, data, in_events=True):
|
|
allow_polling = True
|
|
|
|
for window in windows:
|
|
# Check for live resizing
|
|
if window._resizing is not None:
|
|
allow_polling = False
|
|
old_width, old_height = window._resizing
|
|
rect = types.Rect()
|
|
carbon.GetWindowBounds(window._window,
|
|
constants.kWindowContentRgn,
|
|
ctypes.byref(rect))
|
|
width = rect.right - rect.left
|
|
height = rect.bottom - rect.top
|
|
if width != old_width or height != old_height:
|
|
window._resizing = width, height
|
|
window.switch_to()
|
|
window.dispatch_event('on_resize', width, height)
|
|
|
|
# Check for live dragging
|
|
if window._dragging:
|
|
allow_polling = False
|
|
|
|
# Check for deferred recreate
|
|
if window._recreate_deferred:
|
|
if in_events:
|
|
# Break out of ReceiveNextEvent so it can be processed
|
|
# in next iteration.
|
|
carbon.QuitEventLoop(self._event_loop)
|
|
self._force_idle = True
|
|
else:
|
|
# Do it now.
|
|
window._recreate_immediate()
|
|
|
|
sleep_time = self.idle()
|
|
|
|
if sleep_time is None:
|
|
sleep_time = constants.kEventDurationForever
|
|
elif sleep_time < 0.01 and allow_polling and self._allow_polling:
|
|
# Switch event loop to polling.
|
|
if in_events:
|
|
carbon.QuitEventLoop(self._event_loop)
|
|
self._force_idle = True
|
|
sleep_time = constants.kEventDurationForever
|
|
carbon.SetEventLoopTimerNextFireTime(timer, ctypes.c_double(sleep_time))
|
|
|