From cf4c3264e4c0328ed7baa3f60f48c64d2dc3c361 2011-09-14 06:01:19 From: Nicolas Rougier Date: 2011-09-14 06:01:19 Subject: [PATCH] Tried to fix the CTRL-C problem (https://github.com/ipython/ipython/pull/742) and take other comments/typos into account --- diff --git a/IPython/lib/inputhook.py b/IPython/lib/inputhook.py index c5aa1cf..ed6f71c 100755 --- a/IPython/lib/inputhook.py +++ b/IPython/lib/inputhook.py @@ -285,15 +285,8 @@ class InputHookManager(object): """ self.clear_inputhook() - -<<<<<<< HEAD - - def enable_pyglet(self, app=None): - """Enable event loop integration with pyglet. -======= def enable_glut(self, app=None): """Enable event loop integration with GLUT. ->>>>>>> Added code for the GLUT interactive session Parameters ---------- @@ -304,46 +297,17 @@ class InputHookManager(object): Notes ----- -<<<<<<< HEAD - This methods sets the ``PyOS_InputHook`` for pyglet, which allows - pyglet to integrate with terminal based applications like - IPython. - - """ - import pyglet - from IPython.lib.inputhookpyglet import inputhook_pyglet - self.set_inputhook(inputhook_pyglet) - self._current_gui = GUI_PYGLET - return app - - def disable_pyglet(self): - """Disable event loop integration with pyglet. - This merely sets PyOS_InputHook to NULL. - """ -======= - This methods sets the PyOS_InputHook for GLUT, which allows - the GLUT to integrate with terminal based applications like - IPython. + This methods sets the PyOS_InputHook for GLUT, which allows the GLUT to + integrate with terminal based applications like IPython. Due to GLUT + limitations, it is currently not possible to start the event loop + without first creating a window. You should thus not create another + window but use instead the created one. See 'gui-glut.py' in the + docs/examples/lib directory. + + The default screen mode is set to: - GLUT is quite an old library and it is difficult to ensure proper - integration within IPython since original GLUT does not allow to handle - events one by one. Instead, it requires for the mainloop to be entered - and never returned (there is not even a function to exit he - mainloop). Fortunately, there are alternatives such as freeglut - (available for linux and windows) and the OSX implementation gives - access to a glutCheckLoop() function that blocks itself until a new - event is received. This means we have to setup a default timer to - ensure we got at least one event that will unblock the function. We set - a default timer of 60fps. - - Furthermore, it is not possible to install these handlers without a - window being first created. We choose to make this window invisible and - the user is supposed to make it visible when needed (see gui-glut.py in - the docs/examples/lib directory). This means that display mode options - are set at this level and user won't be able to change them later - without modifying the code. This should probably be made available via - IPython options system. + glut.GLUT_DOUBLE | glut.GLUT_RGBA | glut.GLUT_DEPTH Script integration ------------------ @@ -361,12 +325,44 @@ class InputHookManager(object): if not interactive: glut.glutMainLoop() """ + # GLUT is quite an old library and it is difficult to ensure proper + # integration within IPython since original GLUT does not allow to handle + # events one by one. Instead, it requires for the mainloop to be entered + # and never returned (there is not even a function to exit he + # mainloop). Fortunately, there are alternatives such as freeglut + # (available for linux and windows) and the OSX implementation gives + # access to a glutCheckLoop() function that blocks itself until a new + # event is received. This means we have to setup a default timer to + # ensure we got at least one event that will unblock the function. We set + # a default timer of 60fps. + # + # Furthermore, it is not possible to install these handlers without a + # window being first created. We choose to make this window invisible and + # the user is supposed to make it visible when needed (see gui-glut.py in + # the docs/examples/lib directory). This means that display mode options + # are set at this level and user won't be able to change them later + # without modifying the code. This should probably be made available via + # IPython options system. + + import OpenGL + OpenGL.ERROR_CHECKING = False import OpenGL.GLUT as glut import OpenGL.platform as platform + import time - def timer_none(fps): - ''' Dummy timer function ''' - pass + + # Frame per second : 60 + # Should probably be an IPython option + glut_fps = 60 + + + # Display mode : double buffeed + rgba + depth + # Should probably be an IPython option + glut_display_mode = (glut.GLUT_DOUBLE | + glut.GLUT_RGBA | + glut.GLUT_DEPTH) + + glut_interrupted = False def display(): ''' Dummy display function ''' @@ -381,13 +377,16 @@ class InputHookManager(object): glut.glutTimerFunc( int(1000.0/fps), timer, fps) glut.glutPostRedisplay() + def close(): + glut.glutHideWindow() + glutMainLoopEvent = None if sys.platform == 'darwin': try: - glutCheckLoop = platform.createBaseFunction( - 'glutCheckLoop', dll=platform.GLUT, resultType=None, + glutCheckLoop = platform.createBaseFunction( + 'glutCheckLoop', dll=platform.GLUT, resultType=None, argTypes=[], - doc='glutCheckLoop( ) -> None', + doc='glutCheckLoop( ) -> None', argNames=(), ) except AttributeError: @@ -403,50 +402,120 @@ class InputHookManager(object): '''Consider installing freeglut.''') def inputhook_glut(): - """ Process pending GLUT events only. """ - # We need to protect against a user pressing Control-C when IPython is - # idle and this is running. We trap KeyboardInterrupt and pass. + """ Process pending GLUT events only. """ + + # We need to protect against a user pressing Control-C when IPython + # is idle and this is running. We should trap KeyboardInterrupt and + # pass but it does not seem to work with glutMainLoopEvent. + # Instead, we setup a signal handler on SIGINT and returns after + # having restored the default python SIGINT handler. + import signal + def handler(signum, frame): + signal.signal(signal.SIGINT, signal.default_int_handler) + print '\nKeyboardInterrupt' + # Need to reprint the prompt at this stage + + signal.signal(signal.SIGINT, handler) + try: glutMainLoopEvent() - except KeyboardInterrupt: + except KeyboardInterrupt: # this catch doesn't work for some reasons... pass - return 0 - # Frame per second : 60 - # Should be probably an IPython option - fps = 60 + return 0 + if not self._apps.has_key(GUI_GLUT): glut.glutInit(sys.argv) - - # Display mode shoudl be also an Ipython option since user won't be able + # Display mode should be also an Ipython option since user won't be able # to change it later - glut.glutInitDisplayMode(glut.GLUT_DOUBLE | glut.GLUT_RGBA | glut.GLUT_DEPTH) + glut.glutInitDisplayMode(glut_display_mode) glut.glutCreateWindow(sys.argv[0]) - # glut.glutReshapeWindow(1,1) glut.glutHideWindow() + glut.glutWMCloseFunc(close) glut.glutDisplayFunc(display) - glut.glutTimerFunc( int(1000.0/fps), timer, fps) + glut.glutTimerFunc( int(1000.0/glut_fps), timer, glut_fps) else: + glut.glutWMCloseFunc(close) glut.glutDisplayFunc(display) - glut.glutTimerFunc( int(1000.0/fps), timer, fps) + glut.glutTimerFunc( int(1000.0/glut_fps), timer, glut_fps) self.set_inputhook(inputhook_glut) self._current_gui = GUI_GLUT self._apps[GUI_GLUT] = True - def disable_glut(self): """Disable event loop integration with glut. - + This sets PyOS_InputHook to NULL and set the display function to a dummy one and set the timer to a dummy timer that will be triggered very far in the future. """ - glut.HideWindow() - glut.glutTimerFunc( sys.maxint-1, null_timer_none, 0) ->>>>>>> Added code for the GLUT interactive session + import signal + import OpenGL + OpenGL.ERROR_CHECKING = False + import OpenGL.GLUT as glut + import OpenGL.platform as platform + + def timer_none(fps): + ''' Dummy timer function ''' + pass + + glutMainLoopEvent = None + if sys.platform == 'darwin': + try: + glutCheckLoop = platform.createBaseFunction( + 'glutCheckLoop', dll=platform.GLUT, resultType=None, + argTypes=[], + doc='glutCheckLoop( ) -> None', + argNames=(), + ) + except AttributeError: + raise RuntimeError( + '''Your glut implementation does not allow interactive sessions''' + '''Consider installing freeglut.''') + glutMainLoopEvent = glutCheckLoop + elif glut.HAVE_FREEGLUT: + glutMainLoopEvent = glut.glutMainLoopEvent + else: + raise RuntimeError( + '''Your glut implementation does not allow interactive sessions. ''' + '''Consider installing freeglut.''') + + glut.glutHideWindow() # This is an event to be processed below + glutMainLoopEvent() + #glut.glutTimerFunc( sys.maxint-1, timer_none, 0) self.clear_inputhook() + #signal.signal(signal.SIGINT, signal.default_int_handler) + + def enable_pyglet(self, app=None): + """Enable event loop integration with pyglet. + + Parameters + ---------- + app : ignored + Ignored, it's only a placeholder to keep the call signature of all + gui activation methods consistent, which simplifies the logic of + supporting magics. + Notes + ----- + This methods sets the ``PyOS_InputHook`` for pyglet, which allows + pyglet to integrate with terminal based applications like + IPython. + + """ + import pyglet + from IPython.lib.inputhookpyglet import inputhook_pyglet + self.set_inputhook(inputhook_pyglet) + self._current_gui = GUI_PYGLET + return app + + def disable_pyglet(self): + """Disable event loop integration with pyglet. + + This merely sets PyOS_InputHook to NULL. + """ + self.clear_inputhook() def current_gui(self): """Return a string indicating the currently active GUI or None.""" @@ -462,13 +531,10 @@ enable_gtk = inputhook_manager.enable_gtk disable_gtk = inputhook_manager.disable_gtk enable_tk = inputhook_manager.enable_tk disable_tk = inputhook_manager.disable_tk -<<<<<<< HEAD -enable_pyglet = inputhook_manager.enable_pyglet -disable_pyglet = inputhook_manager.disable_pyglet -======= enable_glut = inputhook_manager.enable_glut disable_glut = inputhook_manager.disable_glut ->>>>>>> Added code for the GLUT interactive session +enable_pyglet = inputhook_manager.enable_pyglet +disable_pyglet = inputhook_manager.disable_pyglet clear_inputhook = inputhook_manager.clear_inputhook set_inputhook = inputhook_manager.set_inputhook current_gui = inputhook_manager.current_gui @@ -507,12 +573,9 @@ def enable_gui(gui=None, app=None): GUI_WX: enable_wx, GUI_QT: enable_qt4, # qt3 not supported GUI_QT4: enable_qt4, -<<<<<<< HEAD + GUI_GLUT: enable_glut, GUI_PYGLET: enable_pyglet, } -======= - GUI_GLUT: enable_glut} ->>>>>>> Added code for the GLUT interactive session try: gui_hook = guis[gui] except KeyError: