Commits

aholkner  committed 38b6018

  • Participants
  • Parent commits 26b6668
  • Branches ctypes-soc

Comments (0)

Files changed (4)

+Pygame-ctypes 0.07
+------------------
+ - SDL_INIT_NOPARACHUTE init flag passed
+ - Many functions now silently downcast floats to ints (yuk)
+ - Added pygame_icon.bmp, missing from previous distribution
+
+SDL-ctypes 0.07
+---------------
+ - SDL_Surface free'd when pygame.Surface deleted
+ - Null callbacks permitted
+ - Extra refs for all callbacks kept to prevent unexpected segfaults when
+   anonymous functions are collected.
+ - None allowed as shape argument to array methods, rather than segfaulting
+
 Pygame-ctypes 0.06
 ------------------
  - Initial release (version numbering coincides with SDL-ctypes release).

File SDL/events.py

     arg_types=[_SDL_EventFilter],
     return_type=None)
 
+_eventfilter_ref = None     # keep global to avoid GC of anon func
+
 def SDL_SetEventFilter(filter):
     '''Set up a filter to process all events before they change internal
     state and are posted to the internal event queue.
             instance must not be modified.
 
     '''
+    global _eventfilter_ref
     if filter:
         def f(e):
             return filter(e.contents.specialize())
-        _SDL_SetEventFilter(_SDL_EventFilter(f))
+        _eventfilter_ref = _SDL_EventFilter(f)
     else:
-        _SDL_SetEventFilter(_SDL_EventFilter())
+        _eventfilter_ref = _SDL_EventFilter()
+    _SDL_SetEventFilter(_eventfilter_ref)
 
 SDL_GetEventFilter = SDL.dll.function('SDL_GetEventFilter',
     '''Return the current event filter.

File SDL/mixer.py

     arg_types=[_Mix_FilterFunc, c_void_p],
     return_type=None)
 
+_mix_postmix_ref = None
+
 def Mix_SetPostMix(mix_func, udata):
     '''Set a function that is called after all mixing is performed.
 
             call.
 
     '''
-    _Mix_SetPostMix(_make_filter(mix_func, udata), None)
+    global _mix_postmix_ref
+    _mix_postmix_ref = _make_filter(mix_func, udata)
+    _Mix_SetPostMix(_mix_postmix_ref, None)
 
 _Mix_HookMusic = _dll.private_function('Mix_HookMusic',
     arg_types=[_Mix_FilterFunc, c_void_p],
     return_type=None)
 
+_hookmusic_ref = None
+
 def Mix_HookMusic(mix_func, udata):
     '''Add your own music player or additional mixer function.
 
             call.
 
     '''
-    _Mix_HookMusic(_make_filter(mix_func, udata), None)
+    global _hookmusic_ref
+    _hookmusic_ref = _make_filter(mix_func, udata)
+    _Mix_HookMusic(_hookmusic_ref, None)
 
 _Mix_HookMusicFinishedFunc = CFUNCTYPE(None)
 
     arg_types=[_Mix_ChannelFinishedFunc],
     return_type=None)
 
+# Keep the ctypes func around
+_channelfinished_ref = None
+
 def Mix_ChannelFinished(channel_finished):
     '''Add your own callback when a channel has finished playing.
 
             and returns None.  Pass None here to disable the callback.
 
     '''
+    global _channelfinished_ref
     if channel_finished:
-        _Mix_ChannelFinished(_Mix_ChannelFinishedFunc(channel_finished))
+        _channelfinished_ref = _Mix_ChannelFinishedFunc(channel_finished)
     else:
-        _Mix_ChannelFinished(_Mix_ChannelFinishedFunc())
+        _channelfinished_ref = _Mix_ChannelFinishedFunc()
+    _Mix_ChannelFinished(cfunc)
 
 _Mix_EffectFunc = CFUNCTYPE(None, c_int, POINTER(c_ubyte), c_int, c_void_p)
 def _make_Mix_EffectFunc(func, udata):
     return_type=c_int,
     error_return=0)
 
+_effect_func_refs = []
+
 def Mix_RegisterEffect(chan, f, d, arg):
     '''Register a special effect function.
 
             User data passed to both callbacks.
 
     '''
-    if f:
-        f = _make_MixEffectFunc(f, arg)
-    if d:
-        d = _make_MixEffectDoneFunc(d, arg)
+    f = _make_MixEffectFunc(f, arg)
+    d = _make_MixEffectDoneFunc(d, arg)
+    _effect_func_refs.append(f)
+    _effect_func_refs.append(d) 
+    # TODO: override EffectDone callback to remove refs and prevent
+    # memory leak.  Be careful with MIX_CHANNEL_POST
     _Mix_RegisterEffect(chan, f, d, arg)
             
 # Mix_UnregisterEffect cannot be implemented

File SDL/timer.py

     arg_types=[c_uint, _SDL_TimerCallback],
     return_type=c_int)
 
+_timercallback_ref = None   # Keep global to avoid possible GC
+
 def SDL_SetTimer(interval, callback):
     '''Set a callback to run after the specified number of milliseconds has
     elapsed.
 
     # Note SDL_SetTimer actually returns 1 on success, not 0 as documented
     # in SDL_timer.h.
+    global _timercallback_ref
     if callback:
-        result = _SDL_SetTimer(interval, _SDL_TimerCallback(callback))
+        _timercallback_ref = _SDL_TimerCallback(callback)
     else:
-        result = _SDL_SetTimer(interval, _SDL_TimerCallback())
-    if result == -1:
+        _timercallback_ref = _SDL_TimerCallback()
+    
+    # XXX if this fails the global ref is incorrect and old one will
+    # possibly be collected early.
+    if _SDL_SetTimer(interval, _timercallback_ref) == -1:
         raise SDL.error.SDL_Exception, SDL.error.SDL_GetError()
 
 
     arg_types=[c_uint, _SDL_NewTimerCallback, c_void_p],
     return_type=c_void_p)
 
+_timer_refs = {}        # Keep global to manage GC
+
 def SDL_AddTimer(interval, callback, param):
     '''Add a new timer to the pool of timers already running.
 
     :rtype: int
     :return: the timer ID
     '''
-
     def _callback(interval, _ignored_param):
         return callback(interval, param)
     
-    result = _SDL_AddTimer(interval, _SDL_NewTimerCallback(_callback), None)
+    func = _SDL_NewTimerCallback(_callback)
+    result = _SDL_AddTimer(interval, func, None)
     if not result:
         raise SDL.error.SDL_Exception, SDL.error.SDL_GetError()
+    _timer_refs[result] = func
     return result
 
-SDL_RemoveTimer = SDL.dll.function('SDL_RemoveTimer',
+_SDL_RemoveTimer = SDL.dll.private_function('SDL_RemoveTimer',
+    args=['t'],
+    arg_types=[c_void_p],
+    return_type=c_int,
+    error_return=0)
+
+def SDL_RemoveTimer(t):
     '''Remove one of the multiple timers knowing its ID.
 
     :Parameters:
         `t` : int
             The timer ID, as returned by `SDL_AddTimer`.
 
-    ''',
-    args=['t'],
-    arg_types=[c_void_p],
-    return_type=c_int,
-    error_return=0)
+    '''
+    global _timer_refs
+    _SDL_RemoveTimer(t)
+    del _timer_refs[t]
 
-