123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140 |
- """GLUT Input hook for interactive use with prompt_toolkit
- """
- # 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 the idle callback to
- # ensure we got at least one event that will unblock the function.
- #
- # Furthermore, it is not possible to install these handlers without a window
- # being first created. We choose to make this window invisible. 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 sys
- import time
- import signal
- import OpenGL.GLUT as glut
- import OpenGL.platform as platform
- from timeit import default_timer as clock
- # 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)
- glutMainLoopEvent = None
- if sys.platform == 'darwin':
- try:
- glutCheckLoop = platform.createBaseFunction(
- 'glutCheckLoop', dll=platform.GLUT, resultType=None,
- argTypes=[],
- doc='glutCheckLoop( ) -> None',
- argNames=(),
- )
- except AttributeError as e:
- raise RuntimeError(
- '''Your glut implementation does not allow interactive sessions. '''
- '''Consider installing freeglut.''') from e
- glutMainLoopEvent = glutCheckLoop
- elif glut.HAVE_FREEGLUT:
- glutMainLoopEvent = glut.glutMainLoopEvent
- else:
- raise RuntimeError(
- '''Your glut implementation does not allow interactive sessions. '''
- '''Consider installing freeglut.''')
- def glut_display():
- # Dummy display function
- pass
- def glut_idle():
- # Dummy idle function
- pass
- def glut_close():
- # Close function only hides the current window
- glut.glutHideWindow()
- glutMainLoopEvent()
- def glut_int_handler(signum, frame):
- # Catch sigint and print the defaultipyt message
- signal.signal(signal.SIGINT, signal.default_int_handler)
- print('\nKeyboardInterrupt')
- # Need to reprint the prompt at this stage
- # Initialisation code
- glut.glutInit( sys.argv )
- glut.glutInitDisplayMode( glut_display_mode )
- # This is specific to freeglut
- if bool(glut.glutSetOption):
- glut.glutSetOption( glut.GLUT_ACTION_ON_WINDOW_CLOSE,
- glut.GLUT_ACTION_GLUTMAINLOOP_RETURNS )
- glut.glutCreateWindow( b'ipython' )
- glut.glutReshapeWindow( 1, 1 )
- glut.glutHideWindow( )
- glut.glutWMCloseFunc( glut_close )
- glut.glutDisplayFunc( glut_display )
- glut.glutIdleFunc( glut_idle )
- def inputhook(context):
- """Run the pyglet event loop by processing pending events only.
- This keeps processing pending events until stdin is ready. After
- processing all pending events, a call to time.sleep is inserted. This is
- needed, otherwise, CPU usage is at 100%. This sleep time should be tuned
- though for best performance.
- """
- # We need to protect against a user pressing Control-C when IPython is
- # idle and this is running. We trap KeyboardInterrupt and pass.
- signal.signal(signal.SIGINT, glut_int_handler)
- try:
- t = clock()
- # Make sure the default window is set after a window has been closed
- if glut.glutGetWindow() == 0:
- glut.glutSetWindow( 1 )
- glutMainLoopEvent()
- return 0
- while not context.input_is_ready():
- glutMainLoopEvent()
- # We need to sleep at this point to keep the idle CPU load
- # low. However, if sleep to long, GUI response is poor. As
- # a compromise, we watch how often GUI events are being processed
- # and switch between a short and long sleep time. Here are some
- # stats useful in helping to tune this.
- # time CPU load
- # 0.001 13%
- # 0.005 3%
- # 0.01 1.5%
- # 0.05 0.5%
- used_time = clock() - t
- if used_time > 10.0:
- # print('Sleep for 1 s') # dbg
- time.sleep(1.0)
- elif used_time > 0.1:
- # Few GUI events coming in, so we can sleep longer
- # print('Sleep for 0.05 s') # dbg
- time.sleep(0.05)
- else:
- # Many GUI events coming in, so sleep only very little
- time.sleep(0.001)
- except KeyboardInterrupt:
- pass
|