##// END OF EJS Templates
Add GLUT input hook
Thomas Kluyver -
Show More
@@ -0,0 +1,141 b''
1 """GLUT Input hook for interactive use with prompt_toolkit
2 """
3 from __future__ import print_function
4
5
6 # GLUT is quite an old library and it is difficult to ensure proper
7 # integration within IPython since original GLUT does not allow to handle
8 # events one by one. Instead, it requires for the mainloop to be entered
9 # and never returned (there is not even a function to exit he
10 # mainloop). Fortunately, there are alternatives such as freeglut
11 # (available for linux and windows) and the OSX implementation gives
12 # access to a glutCheckLoop() function that blocks itself until a new
13 # event is received. This means we have to setup the idle callback to
14 # ensure we got at least one event that will unblock the function.
15 #
16 # Furthermore, it is not possible to install these handlers without a window
17 # being first created. We choose to make this window invisible. This means that
18 # display mode options are set at this level and user won't be able to change
19 # them later without modifying the code. This should probably be made available
20 # via IPython options system.
21
22 import sys
23 import time
24 import signal
25 import OpenGL.GLUT as glut
26 import OpenGL.platform as platform
27 from timeit import default_timer as clock
28
29 # Frame per second : 60
30 # Should probably be an IPython option
31 glut_fps = 60
32
33 # Display mode : double buffeed + rgba + depth
34 # Should probably be an IPython option
35 glut_display_mode = (glut.GLUT_DOUBLE |
36 glut.GLUT_RGBA |
37 glut.GLUT_DEPTH)
38
39 glutMainLoopEvent = None
40 if sys.platform == 'darwin':
41 try:
42 glutCheckLoop = platform.createBaseFunction(
43 'glutCheckLoop', dll=platform.GLUT, resultType=None,
44 argTypes=[],
45 doc='glutCheckLoop( ) -> None',
46 argNames=(),
47 )
48 except AttributeError:
49 raise RuntimeError(
50 '''Your glut implementation does not allow interactive sessions'''
51 '''Consider installing freeglut.''')
52 glutMainLoopEvent = glutCheckLoop
53 elif glut.HAVE_FREEGLUT:
54 glutMainLoopEvent = glut.glutMainLoopEvent
55 else:
56 raise RuntimeError(
57 '''Your glut implementation does not allow interactive sessions. '''
58 '''Consider installing freeglut.''')
59
60
61 def glut_display():
62 # Dummy display function
63 pass
64
65 def glut_idle():
66 # Dummy idle function
67 pass
68
69 def glut_close():
70 # Close function only hides the current window
71 glut.glutHideWindow()
72 glutMainLoopEvent()
73
74 def glut_int_handler(signum, frame):
75 # Catch sigint and print the defaultipyt message
76 signal.signal(signal.SIGINT, signal.default_int_handler)
77 print('\nKeyboardInterrupt')
78 # Need to reprint the prompt at this stage
79
80 # Initialisation code
81 glut.glutInit( sys.argv )
82 glut.glutInitDisplayMode( glut_display_mode )
83 # This is specific to freeglut
84 if bool(glut.glutSetOption):
85 glut.glutSetOption( glut.GLUT_ACTION_ON_WINDOW_CLOSE,
86 glut.GLUT_ACTION_GLUTMAINLOOP_RETURNS )
87 glut.glutCreateWindow( b'ipython' )
88 glut.glutReshapeWindow( 1, 1 )
89 glut.glutHideWindow( )
90 glut.glutWMCloseFunc( glut_close )
91 glut.glutDisplayFunc( glut_display )
92 glut.glutIdleFunc( glut_idle )
93
94
95 def inputhook(context):
96 """Run the pyglet event loop by processing pending events only.
97
98 This keeps processing pending events until stdin is ready. After
99 processing all pending events, a call to time.sleep is inserted. This is
100 needed, otherwise, CPU usage is at 100%. This sleep time should be tuned
101 though for best performance.
102 """
103 # We need to protect against a user pressing Control-C when IPython is
104 # idle and this is running. We trap KeyboardInterrupt and pass.
105
106 signal.signal(signal.SIGINT, glut_int_handler)
107
108 try:
109 t = clock()
110
111 # Make sure the default window is set after a window has been closed
112 if glut.glutGetWindow() == 0:
113 glut.glutSetWindow( 1 )
114 glutMainLoopEvent()
115 return 0
116
117 while not context.input_is_ready():
118 glutMainLoopEvent()
119 # We need to sleep at this point to keep the idle CPU load
120 # low. However, if sleep to long, GUI response is poor. As
121 # a compromise, we watch how often GUI events are being processed
122 # and switch between a short and long sleep time. Here are some
123 # stats useful in helping to tune this.
124 # time CPU load
125 # 0.001 13%
126 # 0.005 3%
127 # 0.01 1.5%
128 # 0.05 0.5%
129 used_time = clock() - t
130 if used_time > 10.0:
131 # print 'Sleep for 1 s' # dbg
132 time.sleep(1.0)
133 elif used_time > 0.1:
134 # Few GUI events coming in, so we can sleep longer
135 # print 'Sleep for 0.05 s' # dbg
136 time.sleep(0.05)
137 else:
138 # Many GUI events coming in, so sleep only very little
139 time.sleep(0.001)
140 except KeyboardInterrupt:
141 pass
@@ -38,7 +38,7 b' if glut.glutGetWindow() > 0:'
38 else:
38 else:
39 interactive = False
39 interactive = False
40
40
41 glut.glutCreateWindow('gui-glut')
41 glut.glutCreateWindow(b'gui-glut')
42 glut.glutDisplayFunc(display)
42 glut.glutDisplayFunc(display)
43 glut.glutReshapeFunc(resize)
43 glut.glutReshapeFunc(resize)
44 # This is necessary on osx to be able to close the window
44 # This is necessary on osx to be able to close the window
General Comments 0
You need to be logged in to leave comments. Login now