##// END OF EJS Templates
Merge branch 'glut-rebased' of git://github.com/fperez/ipython into glut...
Nicolas Rougier -
r4818:89161a5b merge
parent child Browse files
Show More
@@ -0,0 +1,46 b''
1 #!/usr/bin/env python
2 """Simple GLUT example to manually test event loop integration.
3
4 This is meant to run tests manually in ipython as:
5
6 In [5]: %gui glut
7
8 In [6]: %run gui-glut.py
9
10 In [7]: gl.glClearColor(1,1,1,1)
11 """
12
13 #!/usr/bin/env python
14 import sys
15 import OpenGL.GL as gl
16 import OpenGL.GLUT as glut
17
18 def display():
19 gl.glClear (gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT)
20 glut.glutSwapBuffers()
21
22 def resize(width,height):
23 gl.glViewport(0, 0, width, height+4)
24 gl.glMatrixMode(gl.GL_PROJECTION)
25 gl.glLoadIdentity()
26 gl.glOrtho(0, width, 0, height+4, -1, 1)
27 gl.glMatrixMode(gl.GL_MODELVIEW)
28
29
30 if glut.glutGetWindow() > 0:
31 interactive = True
32 glut.glutInit(sys.argv)
33 glut.glutInitDisplayMode(glut.GLUT_DOUBLE |
34 glut.GLUT_RGBA |
35 glut.GLUT_DEPTH)
36 glut.glutShowWindow()
37 else:
38 glut.glutCreateWindow('gui-glut')
39 interactive = False
40
41 glut.glutDisplayFunc(display)
42 glut.glutReshapeFunc(resize)
43 gl.glClearColor(0,0,0,1)
44
45 if not interactive:
46 glut.glutMainLoop()
@@ -1,393 +1,393 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # encoding: utf-8
2 # encoding: utf-8
3 """
3 """
4 The :class:`~IPython.core.application.Application` object for the command
4 The :class:`~IPython.core.application.Application` object for the command
5 line :command:`ipython` program.
5 line :command:`ipython` program.
6
6
7 Authors
7 Authors
8 -------
8 -------
9
9
10 * Brian Granger
10 * Brian Granger
11 * Fernando Perez
11 * Fernando Perez
12 * Min Ragan-Kelley
12 * Min Ragan-Kelley
13 """
13 """
14
14
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16 # Copyright (C) 2008-2010 The IPython Development Team
16 # Copyright (C) 2008-2010 The IPython Development Team
17 #
17 #
18 # Distributed under the terms of the BSD License. The full license is in
18 # Distributed under the terms of the BSD License. The full license is in
19 # the file COPYING, distributed as part of this software.
19 # the file COPYING, distributed as part of this software.
20 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
21
21
22 #-----------------------------------------------------------------------------
22 #-----------------------------------------------------------------------------
23 # Imports
23 # Imports
24 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
25
25
26 from __future__ import absolute_import
26 from __future__ import absolute_import
27
27
28 import logging
28 import logging
29 import os
29 import os
30 import sys
30 import sys
31
31
32 from IPython.config.loader import (
32 from IPython.config.loader import (
33 Config, PyFileConfigLoader
33 Config, PyFileConfigLoader
34 )
34 )
35 from IPython.config.application import boolean_flag
35 from IPython.config.application import boolean_flag
36 from IPython.core import release
36 from IPython.core import release
37 from IPython.core import usage
37 from IPython.core import usage
38 from IPython.core.crashhandler import CrashHandler
38 from IPython.core.crashhandler import CrashHandler
39 from IPython.core.formatters import PlainTextFormatter
39 from IPython.core.formatters import PlainTextFormatter
40 from IPython.core.application import (
40 from IPython.core.application import (
41 ProfileDir, BaseIPythonApplication, base_flags, base_aliases
41 ProfileDir, BaseIPythonApplication, base_flags, base_aliases
42 )
42 )
43 from IPython.core.shellapp import (
43 from IPython.core.shellapp import (
44 InteractiveShellApp, shell_flags, shell_aliases
44 InteractiveShellApp, shell_flags, shell_aliases
45 )
45 )
46 from IPython.frontend.terminal.interactiveshell import TerminalInteractiveShell
46 from IPython.frontend.terminal.interactiveshell import TerminalInteractiveShell
47 from IPython.lib import inputhook
47 from IPython.lib import inputhook
48 from IPython.utils import warn
48 from IPython.utils import warn
49 from IPython.utils.path import get_ipython_dir, check_for_old_config
49 from IPython.utils.path import get_ipython_dir, check_for_old_config
50 from IPython.utils.traitlets import (
50 from IPython.utils.traitlets import (
51 Bool, List, Dict, CaselessStrEnum
51 Bool, List, Dict, CaselessStrEnum
52 )
52 )
53
53
54 #-----------------------------------------------------------------------------
54 #-----------------------------------------------------------------------------
55 # Globals, utilities and helpers
55 # Globals, utilities and helpers
56 #-----------------------------------------------------------------------------
56 #-----------------------------------------------------------------------------
57
57
58 #: The default config file name for this application.
58 #: The default config file name for this application.
59 default_config_file_name = u'ipython_config.py'
59 default_config_file_name = u'ipython_config.py'
60
60
61 _examples = """
61 _examples = """
62 ipython --pylab # start in pylab mode
62 ipython --pylab # start in pylab mode
63 ipython --pylab=qt # start in pylab mode with the qt4 backend
63 ipython --pylab=qt # start in pylab mode with the qt4 backend
64 ipython --log-level=DEBUG # set logging to DEBUG
64 ipython --log-level=DEBUG # set logging to DEBUG
65 ipython --profile=foo # start with profile foo
65 ipython --profile=foo # start with profile foo
66
66
67 ipython qtconsole # start the qtconsole GUI application
67 ipython qtconsole # start the qtconsole GUI application
68 ipython qtconsole -h # show the help string for the qtconsole subcmd
68 ipython qtconsole -h # show the help string for the qtconsole subcmd
69
69
70 ipython profile create foo # create profile foo w/ default config files
70 ipython profile create foo # create profile foo w/ default config files
71 ipython profile -h # show the help string for the profile subcmd
71 ipython profile -h # show the help string for the profile subcmd
72 """
72 """
73
73
74 #-----------------------------------------------------------------------------
74 #-----------------------------------------------------------------------------
75 # Crash handler for this application
75 # Crash handler for this application
76 #-----------------------------------------------------------------------------
76 #-----------------------------------------------------------------------------
77
77
78 class IPAppCrashHandler(CrashHandler):
78 class IPAppCrashHandler(CrashHandler):
79 """sys.excepthook for IPython itself, leaves a detailed report on disk."""
79 """sys.excepthook for IPython itself, leaves a detailed report on disk."""
80
80
81 def __init__(self, app):
81 def __init__(self, app):
82 contact_name = release.authors['Fernando'][0]
82 contact_name = release.authors['Fernando'][0]
83 contact_email = release.authors['Fernando'][1]
83 contact_email = release.authors['Fernando'][1]
84 bug_tracker = 'http://github.com/ipython/ipython/issues'
84 bug_tracker = 'http://github.com/ipython/ipython/issues'
85 super(IPAppCrashHandler,self).__init__(
85 super(IPAppCrashHandler,self).__init__(
86 app, contact_name, contact_email, bug_tracker
86 app, contact_name, contact_email, bug_tracker
87 )
87 )
88
88
89 def make_report(self,traceback):
89 def make_report(self,traceback):
90 """Return a string containing a crash report."""
90 """Return a string containing a crash report."""
91
91
92 sec_sep = self.section_sep
92 sec_sep = self.section_sep
93 # Start with parent report
93 # Start with parent report
94 report = [super(IPAppCrashHandler, self).make_report(traceback)]
94 report = [super(IPAppCrashHandler, self).make_report(traceback)]
95 # Add interactive-specific info we may have
95 # Add interactive-specific info we may have
96 rpt_add = report.append
96 rpt_add = report.append
97 try:
97 try:
98 rpt_add(sec_sep+"History of session input:")
98 rpt_add(sec_sep+"History of session input:")
99 for line in self.app.shell.user_ns['_ih']:
99 for line in self.app.shell.user_ns['_ih']:
100 rpt_add(line)
100 rpt_add(line)
101 rpt_add('\n*** Last line of input (may not be in above history):\n')
101 rpt_add('\n*** Last line of input (may not be in above history):\n')
102 rpt_add(self.app.shell._last_input_line+'\n')
102 rpt_add(self.app.shell._last_input_line+'\n')
103 except:
103 except:
104 pass
104 pass
105
105
106 return ''.join(report)
106 return ''.join(report)
107
107
108 #-----------------------------------------------------------------------------
108 #-----------------------------------------------------------------------------
109 # Aliases and Flags
109 # Aliases and Flags
110 #-----------------------------------------------------------------------------
110 #-----------------------------------------------------------------------------
111 flags = dict(base_flags)
111 flags = dict(base_flags)
112 flags.update(shell_flags)
112 flags.update(shell_flags)
113 addflag = lambda *args: flags.update(boolean_flag(*args))
113 addflag = lambda *args: flags.update(boolean_flag(*args))
114 addflag('autoedit-syntax', 'TerminalInteractiveShell.autoedit_syntax',
114 addflag('autoedit-syntax', 'TerminalInteractiveShell.autoedit_syntax',
115 'Turn on auto editing of files with syntax errors.',
115 'Turn on auto editing of files with syntax errors.',
116 'Turn off auto editing of files with syntax errors.'
116 'Turn off auto editing of files with syntax errors.'
117 )
117 )
118 addflag('banner', 'TerminalIPythonApp.display_banner',
118 addflag('banner', 'TerminalIPythonApp.display_banner',
119 "Display a banner upon starting IPython.",
119 "Display a banner upon starting IPython.",
120 "Don't display a banner upon starting IPython."
120 "Don't display a banner upon starting IPython."
121 )
121 )
122 addflag('confirm-exit', 'TerminalInteractiveShell.confirm_exit',
122 addflag('confirm-exit', 'TerminalInteractiveShell.confirm_exit',
123 """Set to confirm when you try to exit IPython with an EOF (Control-D
123 """Set to confirm when you try to exit IPython with an EOF (Control-D
124 in Unix, Control-Z/Enter in Windows). By typing 'exit' or 'quit',
124 in Unix, Control-Z/Enter in Windows). By typing 'exit' or 'quit',
125 you can force a direct exit without any confirmation.""",
125 you can force a direct exit without any confirmation.""",
126 "Don't prompt the user when exiting."
126 "Don't prompt the user when exiting."
127 )
127 )
128 addflag('term-title', 'TerminalInteractiveShell.term_title',
128 addflag('term-title', 'TerminalInteractiveShell.term_title',
129 "Enable auto setting the terminal title.",
129 "Enable auto setting the terminal title.",
130 "Disable auto setting the terminal title."
130 "Disable auto setting the terminal title."
131 )
131 )
132 classic_config = Config()
132 classic_config = Config()
133 classic_config.InteractiveShell.cache_size = 0
133 classic_config.InteractiveShell.cache_size = 0
134 classic_config.PlainTextFormatter.pprint = False
134 classic_config.PlainTextFormatter.pprint = False
135 classic_config.InteractiveShell.prompt_in1 = '>>> '
135 classic_config.InteractiveShell.prompt_in1 = '>>> '
136 classic_config.InteractiveShell.prompt_in2 = '... '
136 classic_config.InteractiveShell.prompt_in2 = '... '
137 classic_config.InteractiveShell.prompt_out = ''
137 classic_config.InteractiveShell.prompt_out = ''
138 classic_config.InteractiveShell.separate_in = ''
138 classic_config.InteractiveShell.separate_in = ''
139 classic_config.InteractiveShell.separate_out = ''
139 classic_config.InteractiveShell.separate_out = ''
140 classic_config.InteractiveShell.separate_out2 = ''
140 classic_config.InteractiveShell.separate_out2 = ''
141 classic_config.InteractiveShell.colors = 'NoColor'
141 classic_config.InteractiveShell.colors = 'NoColor'
142 classic_config.InteractiveShell.xmode = 'Plain'
142 classic_config.InteractiveShell.xmode = 'Plain'
143
143
144 flags['classic']=(
144 flags['classic']=(
145 classic_config,
145 classic_config,
146 "Gives IPython a similar feel to the classic Python prompt."
146 "Gives IPython a similar feel to the classic Python prompt."
147 )
147 )
148 # # log doesn't make so much sense this way anymore
148 # # log doesn't make so much sense this way anymore
149 # paa('--log','-l',
149 # paa('--log','-l',
150 # action='store_true', dest='InteractiveShell.logstart',
150 # action='store_true', dest='InteractiveShell.logstart',
151 # help="Start logging to the default log file (./ipython_log.py).")
151 # help="Start logging to the default log file (./ipython_log.py).")
152 #
152 #
153 # # quick is harder to implement
153 # # quick is harder to implement
154 flags['quick']=(
154 flags['quick']=(
155 {'TerminalIPythonApp' : {'quick' : True}},
155 {'TerminalIPythonApp' : {'quick' : True}},
156 "Enable quick startup with no config files."
156 "Enable quick startup with no config files."
157 )
157 )
158
158
159 flags['i'] = (
159 flags['i'] = (
160 {'TerminalIPythonApp' : {'force_interact' : True}},
160 {'TerminalIPythonApp' : {'force_interact' : True}},
161 """If running code from the command line, become interactive afterwards.
161 """If running code from the command line, become interactive afterwards.
162 Note: can also be given simply as '-i.'"""
162 Note: can also be given simply as '-i.'"""
163 )
163 )
164 flags['pylab'] = (
164 flags['pylab'] = (
165 {'TerminalIPythonApp' : {'pylab' : 'auto'}},
165 {'TerminalIPythonApp' : {'pylab' : 'auto'}},
166 """Pre-load matplotlib and numpy for interactive use with
166 """Pre-load matplotlib and numpy for interactive use with
167 the default matplotlib backend."""
167 the default matplotlib backend."""
168 )
168 )
169
169
170 aliases = dict(base_aliases)
170 aliases = dict(base_aliases)
171 aliases.update(shell_aliases)
171 aliases.update(shell_aliases)
172
172
173 # it's possible we don't want short aliases for *all* of these:
173 # it's possible we don't want short aliases for *all* of these:
174 aliases.update(dict(
174 aliases.update(dict(
175 gui='TerminalIPythonApp.gui',
175 gui='TerminalIPythonApp.gui',
176 pylab='TerminalIPythonApp.pylab',
176 pylab='TerminalIPythonApp.pylab',
177 ))
177 ))
178
178
179 #-----------------------------------------------------------------------------
179 #-----------------------------------------------------------------------------
180 # Main classes and functions
180 # Main classes and functions
181 #-----------------------------------------------------------------------------
181 #-----------------------------------------------------------------------------
182
182
183 class TerminalIPythonApp(BaseIPythonApplication, InteractiveShellApp):
183 class TerminalIPythonApp(BaseIPythonApplication, InteractiveShellApp):
184 name = u'ipython'
184 name = u'ipython'
185 description = usage.cl_usage
185 description = usage.cl_usage
186 default_config_file_name = default_config_file_name
186 default_config_file_name = default_config_file_name
187 crash_handler_class = IPAppCrashHandler
187 crash_handler_class = IPAppCrashHandler
188 examples = _examples
188 examples = _examples
189
189
190 flags = Dict(flags)
190 flags = Dict(flags)
191 aliases = Dict(aliases)
191 aliases = Dict(aliases)
192 classes = List()
192 classes = List()
193 def _classes_default(self):
193 def _classes_default(self):
194 """This has to be in a method, for TerminalIPythonApp to be available."""
194 """This has to be in a method, for TerminalIPythonApp to be available."""
195 return [
195 return [
196 InteractiveShellApp, # ShellApp comes before TerminalApp, because
196 InteractiveShellApp, # ShellApp comes before TerminalApp, because
197 self.__class__, # it will also affect subclasses (e.g. QtConsole)
197 self.__class__, # it will also affect subclasses (e.g. QtConsole)
198 TerminalInteractiveShell,
198 TerminalInteractiveShell,
199 ProfileDir,
199 ProfileDir,
200 PlainTextFormatter,
200 PlainTextFormatter,
201 ]
201 ]
202
202
203 subcommands = Dict(dict(
203 subcommands = Dict(dict(
204 qtconsole=('IPython.frontend.qt.console.qtconsoleapp.IPythonQtConsoleApp',
204 qtconsole=('IPython.frontend.qt.console.qtconsoleapp.IPythonQtConsoleApp',
205 """Launch the IPython Qt Console."""
205 """Launch the IPython Qt Console."""
206 ),
206 ),
207 notebook=('IPython.frontend.html.notebook.notebookapp.IPythonNotebookApp',
207 notebook=('IPython.frontend.html.notebook.notebookapp.IPythonNotebookApp',
208 """Launch the IPython HTML Notebook Server"""
208 """Launch the IPython HTML Notebook Server"""
209 ),
209 ),
210 profile = ("IPython.core.profileapp.ProfileApp",
210 profile = ("IPython.core.profileapp.ProfileApp",
211 "Create and manage IPython profiles."
211 "Create and manage IPython profiles."
212 ),
212 ),
213 kernel = ("IPython.zmq.ipkernel.IPKernelApp",
213 kernel = ("IPython.zmq.ipkernel.IPKernelApp",
214 "Start a kernel without an attached frontend."
214 "Start a kernel without an attached frontend."
215 ),
215 ),
216 ))
216 ))
217
217
218 # *do* autocreate requested profile, but don't create the config file.
218 # *do* autocreate requested profile, but don't create the config file.
219 auto_create=Bool(True)
219 auto_create=Bool(True)
220 # configurables
220 # configurables
221 ignore_old_config=Bool(False, config=True,
221 ignore_old_config=Bool(False, config=True,
222 help="Suppress warning messages about legacy config files"
222 help="Suppress warning messages about legacy config files"
223 )
223 )
224 quick = Bool(False, config=True,
224 quick = Bool(False, config=True,
225 help="""Start IPython quickly by skipping the loading of config files."""
225 help="""Start IPython quickly by skipping the loading of config files."""
226 )
226 )
227 def _quick_changed(self, name, old, new):
227 def _quick_changed(self, name, old, new):
228 if new:
228 if new:
229 self.load_config_file = lambda *a, **kw: None
229 self.load_config_file = lambda *a, **kw: None
230 self.ignore_old_config=True
230 self.ignore_old_config=True
231
231
232 gui = CaselessStrEnum(('qt','wx','gtk', 'pyglet'), config=True,
232 gui = CaselessStrEnum(('qt', 'wx', 'gtk', 'glut', 'pyglet'), config=True,
233 help="Enable GUI event loop integration ('qt', 'wx', 'gtk', 'pyglet')."
233 help="Enable GUI event loop integration ('qt', 'wx', 'gtk', 'glut', 'pyglet')."
234 )
234 )
235 pylab = CaselessStrEnum(['tk', 'qt', 'wx', 'gtk', 'osx', 'auto'],
235 pylab = CaselessStrEnum(['tk', 'qt', 'wx', 'gtk', 'osx', 'auto'],
236 config=True,
236 config=True,
237 help="""Pre-load matplotlib and numpy for interactive use,
237 help="""Pre-load matplotlib and numpy for interactive use,
238 selecting a particular matplotlib backend and loop integration.
238 selecting a particular matplotlib backend and loop integration.
239 """
239 """
240 )
240 )
241 display_banner = Bool(True, config=True,
241 display_banner = Bool(True, config=True,
242 help="Whether to display a banner upon starting IPython."
242 help="Whether to display a banner upon starting IPython."
243 )
243 )
244
244
245 # if there is code of files to run from the cmd line, don't interact
245 # if there is code of files to run from the cmd line, don't interact
246 # unless the --i flag (App.force_interact) is true.
246 # unless the --i flag (App.force_interact) is true.
247 force_interact = Bool(False, config=True,
247 force_interact = Bool(False, config=True,
248 help="""If a command or file is given via the command-line,
248 help="""If a command or file is given via the command-line,
249 e.g. 'ipython foo.py"""
249 e.g. 'ipython foo.py"""
250 )
250 )
251 def _force_interact_changed(self, name, old, new):
251 def _force_interact_changed(self, name, old, new):
252 if new:
252 if new:
253 self.interact = True
253 self.interact = True
254
254
255 def _file_to_run_changed(self, name, old, new):
255 def _file_to_run_changed(self, name, old, new):
256 if new and not self.force_interact:
256 if new and not self.force_interact:
257 self.interact = False
257 self.interact = False
258 _code_to_run_changed = _file_to_run_changed
258 _code_to_run_changed = _file_to_run_changed
259
259
260 # internal, not-configurable
260 # internal, not-configurable
261 interact=Bool(True)
261 interact=Bool(True)
262
262
263
263
264 def parse_command_line(self, argv=None):
264 def parse_command_line(self, argv=None):
265 """override to allow old '-pylab' flag with deprecation warning"""
265 """override to allow old '-pylab' flag with deprecation warning"""
266
266
267 argv = sys.argv[1:] if argv is None else argv
267 argv = sys.argv[1:] if argv is None else argv
268
268
269 if '-pylab' in argv:
269 if '-pylab' in argv:
270 # deprecated `-pylab` given,
270 # deprecated `-pylab` given,
271 # warn and transform into current syntax
271 # warn and transform into current syntax
272 argv = argv[:] # copy, don't clobber
272 argv = argv[:] # copy, don't clobber
273 idx = argv.index('-pylab')
273 idx = argv.index('-pylab')
274 warn.warn("`-pylab` flag has been deprecated.\n"
274 warn.warn("`-pylab` flag has been deprecated.\n"
275 " Use `--pylab` instead, or `--pylab=foo` to specify a backend.")
275 " Use `--pylab` instead, or `--pylab=foo` to specify a backend.")
276 sub = '--pylab'
276 sub = '--pylab'
277 if len(argv) > idx+1:
277 if len(argv) > idx+1:
278 # check for gui arg, as in '-pylab qt'
278 # check for gui arg, as in '-pylab qt'
279 gui = argv[idx+1]
279 gui = argv[idx+1]
280 if gui in ('wx', 'qt', 'qt4', 'gtk', 'auto'):
280 if gui in ('wx', 'qt', 'qt4', 'gtk', 'auto'):
281 sub = '--pylab='+gui
281 sub = '--pylab='+gui
282 argv.pop(idx+1)
282 argv.pop(idx+1)
283 argv[idx] = sub
283 argv[idx] = sub
284
284
285 return super(TerminalIPythonApp, self).parse_command_line(argv)
285 return super(TerminalIPythonApp, self).parse_command_line(argv)
286
286
287 def initialize(self, argv=None):
287 def initialize(self, argv=None):
288 """Do actions after construct, but before starting the app."""
288 """Do actions after construct, but before starting the app."""
289 super(TerminalIPythonApp, self).initialize(argv)
289 super(TerminalIPythonApp, self).initialize(argv)
290 if self.subapp is not None:
290 if self.subapp is not None:
291 # don't bother initializing further, starting subapp
291 # don't bother initializing further, starting subapp
292 return
292 return
293 if not self.ignore_old_config:
293 if not self.ignore_old_config:
294 check_for_old_config(self.ipython_dir)
294 check_for_old_config(self.ipython_dir)
295 # print self.extra_args
295 # print self.extra_args
296 if self.extra_args:
296 if self.extra_args:
297 self.file_to_run = self.extra_args[0]
297 self.file_to_run = self.extra_args[0]
298 # create the shell
298 # create the shell
299 self.init_shell()
299 self.init_shell()
300 # and draw the banner
300 # and draw the banner
301 self.init_banner()
301 self.init_banner()
302 # Now a variety of things that happen after the banner is printed.
302 # Now a variety of things that happen after the banner is printed.
303 self.init_gui_pylab()
303 self.init_gui_pylab()
304 self.init_extensions()
304 self.init_extensions()
305 self.init_code()
305 self.init_code()
306
306
307 def init_shell(self):
307 def init_shell(self):
308 """initialize the InteractiveShell instance"""
308 """initialize the InteractiveShell instance"""
309 # I am a little hesitant to put these into InteractiveShell itself.
309 # I am a little hesitant to put these into InteractiveShell itself.
310 # But that might be the place for them
310 # But that might be the place for them
311 sys.path.insert(0, '')
311 sys.path.insert(0, '')
312
312
313 # Create an InteractiveShell instance.
313 # Create an InteractiveShell instance.
314 # shell.display_banner should always be False for the terminal
314 # shell.display_banner should always be False for the terminal
315 # based app, because we call shell.show_banner() by hand below
315 # based app, because we call shell.show_banner() by hand below
316 # so the banner shows *before* all extension loading stuff.
316 # so the banner shows *before* all extension loading stuff.
317 self.shell = TerminalInteractiveShell.instance(config=self.config,
317 self.shell = TerminalInteractiveShell.instance(config=self.config,
318 display_banner=False, profile_dir=self.profile_dir,
318 display_banner=False, profile_dir=self.profile_dir,
319 ipython_dir=self.ipython_dir)
319 ipython_dir=self.ipython_dir)
320
320
321 def init_banner(self):
321 def init_banner(self):
322 """optionally display the banner"""
322 """optionally display the banner"""
323 if self.display_banner and self.interact:
323 if self.display_banner and self.interact:
324 self.shell.show_banner()
324 self.shell.show_banner()
325 # Make sure there is a space below the banner.
325 # Make sure there is a space below the banner.
326 if self.log_level <= logging.INFO: print
326 if self.log_level <= logging.INFO: print
327
327
328
328
329 def init_gui_pylab(self):
329 def init_gui_pylab(self):
330 """Enable GUI event loop integration, taking pylab into account."""
330 """Enable GUI event loop integration, taking pylab into account."""
331 gui = self.gui
331 gui = self.gui
332
332
333 # Using `pylab` will also require gui activation, though which toolkit
333 # Using `pylab` will also require gui activation, though which toolkit
334 # to use may be chosen automatically based on mpl configuration.
334 # to use may be chosen automatically based on mpl configuration.
335 if self.pylab:
335 if self.pylab:
336 activate = self.shell.enable_pylab
336 activate = self.shell.enable_pylab
337 if self.pylab == 'auto':
337 if self.pylab == 'auto':
338 gui = None
338 gui = None
339 else:
339 else:
340 gui = self.pylab
340 gui = self.pylab
341 else:
341 else:
342 # Enable only GUI integration, no pylab
342 # Enable only GUI integration, no pylab
343 activate = inputhook.enable_gui
343 activate = inputhook.enable_gui
344
344
345 if gui or self.pylab:
345 if gui or self.pylab:
346 try:
346 try:
347 self.log.info("Enabling GUI event loop integration, "
347 self.log.info("Enabling GUI event loop integration, "
348 "toolkit=%s, pylab=%s" % (gui, self.pylab) )
348 "toolkit=%s, pylab=%s" % (gui, self.pylab) )
349 if self.pylab:
349 if self.pylab:
350 activate(gui, import_all=self.pylab_import_all)
350 activate(gui, import_all=self.pylab_import_all)
351 else:
351 else:
352 activate(gui)
352 activate(gui)
353 except:
353 except:
354 self.log.warn("Error in enabling GUI event loop integration:")
354 self.log.warn("Error in enabling GUI event loop integration:")
355 self.shell.showtraceback()
355 self.shell.showtraceback()
356
356
357 def start(self):
357 def start(self):
358 if self.subapp is not None:
358 if self.subapp is not None:
359 return self.subapp.start()
359 return self.subapp.start()
360 # perform any prexec steps:
360 # perform any prexec steps:
361 if self.interact:
361 if self.interact:
362 self.log.debug("Starting IPython's mainloop...")
362 self.log.debug("Starting IPython's mainloop...")
363 self.shell.mainloop()
363 self.shell.mainloop()
364 else:
364 else:
365 self.log.debug("IPython not interactive...")
365 self.log.debug("IPython not interactive...")
366
366
367
367
368 def load_default_config(ipython_dir=None):
368 def load_default_config(ipython_dir=None):
369 """Load the default config file from the default ipython_dir.
369 """Load the default config file from the default ipython_dir.
370
370
371 This is useful for embedded shells.
371 This is useful for embedded shells.
372 """
372 """
373 if ipython_dir is None:
373 if ipython_dir is None:
374 ipython_dir = get_ipython_dir()
374 ipython_dir = get_ipython_dir()
375 profile_dir = os.path.join(ipython_dir, 'profile_default')
375 profile_dir = os.path.join(ipython_dir, 'profile_default')
376 cl = PyFileConfigLoader(default_config_file_name, profile_dir)
376 cl = PyFileConfigLoader(default_config_file_name, profile_dir)
377 try:
377 try:
378 config = cl.load_config()
378 config = cl.load_config()
379 except IOError:
379 except IOError:
380 # no config found
380 # no config found
381 config = Config()
381 config = Config()
382 return config
382 return config
383
383
384
384
385 def launch_new_instance():
385 def launch_new_instance():
386 """Create and run a full blown IPython instance"""
386 """Create and run a full blown IPython instance"""
387 app = TerminalIPythonApp.instance()
387 app = TerminalIPythonApp.instance()
388 app.initialize()
388 app.initialize()
389 app.start()
389 app.start()
390
390
391
391
392 if __name__ == '__main__':
392 if __name__ == '__main__':
393 launch_new_instance()
393 launch_new_instance()
@@ -1,29 +1,30 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """
2 """
3 Extra capabilities for IPython
3 Extra capabilities for IPython
4 """
4 """
5
5
6 #-----------------------------------------------------------------------------
6 #-----------------------------------------------------------------------------
7 # Copyright (C) 2008-2009 The IPython Development Team
7 # Copyright (C) 2008-2009 The IPython Development Team
8 #
8 #
9 # Distributed under the terms of the BSD License. The full license is in
9 # Distributed under the terms of the BSD License. The full license is in
10 # the file COPYING, distributed as part of this software.
10 # the file COPYING, distributed as part of this software.
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Imports
14 # Imports
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16
16
17 from IPython.lib.inputhook import (
17 from IPython.lib.inputhook import (
18 enable_wx, disable_wx,
18 enable_wx, disable_wx,
19 enable_gtk, disable_gtk,
19 enable_gtk, disable_gtk,
20 enable_qt4, disable_qt4,
20 enable_qt4, disable_qt4,
21 enable_tk, disable_tk,
21 enable_tk, disable_tk,
22 enable_glut, disable_glut,
22 enable_pyglet, disable_pyglet,
23 enable_pyglet, disable_pyglet,
23 set_inputhook, clear_inputhook,
24 set_inputhook, clear_inputhook,
24 current_gui
25 current_gui
25 )
26 )
26
27
27 #-----------------------------------------------------------------------------
28 #-----------------------------------------------------------------------------
28 # Code
29 # Code
29 #-----------------------------------------------------------------------------
30 #-----------------------------------------------------------------------------
@@ -1,382 +1,585 b''
1 # coding: utf-8
1 # coding: utf-8
2 """
2 """
3 Inputhook management for GUI event loop integration.
3 Inputhook management for GUI event loop integration.
4 """
4 """
5
5
6 #-----------------------------------------------------------------------------
6 #-----------------------------------------------------------------------------
7 # Copyright (C) 2008-2009 The IPython Development Team
7 # Copyright (C) 2008-2009 The IPython Development Team
8 #
8 #
9 # Distributed under the terms of the BSD License. The full license is in
9 # Distributed under the terms of the BSD License. The full license is in
10 # the file COPYING, distributed as part of this software.
10 # the file COPYING, distributed as part of this software.
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Imports
14 # Imports
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16
16
17 import ctypes
17 import ctypes
18 import sys
18 import sys
19 import warnings
19 import warnings
20
20
21 #-----------------------------------------------------------------------------
21 #-----------------------------------------------------------------------------
22 # Constants
22 # Constants
23 #-----------------------------------------------------------------------------
23 #-----------------------------------------------------------------------------
24
24
25 # Constants for identifying the GUI toolkits.
25 # Constants for identifying the GUI toolkits.
26 GUI_WX = 'wx'
26 GUI_WX = 'wx'
27 GUI_QT = 'qt'
27 GUI_QT = 'qt'
28 GUI_QT4 = 'qt4'
28 GUI_QT4 = 'qt4'
29 GUI_GTK = 'gtk'
29 GUI_GTK = 'gtk'
30 GUI_TK = 'tk'
30 GUI_TK = 'tk'
31 GUI_OSX = 'osx'
31 GUI_OSX = 'osx'
32 GUI_GLUT = 'glut'
32 GUI_PYGLET = 'pyglet'
33 GUI_PYGLET = 'pyglet'
33
34
34 #-----------------------------------------------------------------------------
35 #-----------------------------------------------------------------------------
35 # Utility classes
36 # Utility classes
36 #-----------------------------------------------------------------------------
37 #-----------------------------------------------------------------------------
37
38
38
39
39 #-----------------------------------------------------------------------------
40 #-----------------------------------------------------------------------------
40 # Main InputHookManager class
41 # Main InputHookManager class
41 #-----------------------------------------------------------------------------
42 #-----------------------------------------------------------------------------
42
43
43
44
44 class InputHookManager(object):
45 class InputHookManager(object):
45 """Manage PyOS_InputHook for different GUI toolkits.
46 """Manage PyOS_InputHook for different GUI toolkits.
46
47
47 This class installs various hooks under ``PyOSInputHook`` to handle
48 This class installs various hooks under ``PyOSInputHook`` to handle
48 GUI event loop integration.
49 GUI event loop integration.
49 """
50 """
50
51
51 def __init__(self):
52 def __init__(self):
52 self.PYFUNC = ctypes.PYFUNCTYPE(ctypes.c_int)
53 self.PYFUNC = ctypes.PYFUNCTYPE(ctypes.c_int)
53 self._apps = {}
54 self._apps = {}
54 self._reset()
55 self._reset()
55
56
56 def _reset(self):
57 def _reset(self):
57 self._callback_pyfunctype = None
58 self._callback_pyfunctype = None
58 self._callback = None
59 self._callback = None
59 self._installed = False
60 self._installed = False
60 self._current_gui = None
61 self._current_gui = None
61
62
62 def get_pyos_inputhook(self):
63 def get_pyos_inputhook(self):
63 """Return the current PyOS_InputHook as a ctypes.c_void_p."""
64 """Return the current PyOS_InputHook as a ctypes.c_void_p."""
64 return ctypes.c_void_p.in_dll(ctypes.pythonapi,"PyOS_InputHook")
65 return ctypes.c_void_p.in_dll(ctypes.pythonapi,"PyOS_InputHook")
65
66
66 def get_pyos_inputhook_as_func(self):
67 def get_pyos_inputhook_as_func(self):
67 """Return the current PyOS_InputHook as a ctypes.PYFUNCYPE."""
68 """Return the current PyOS_InputHook as a ctypes.PYFUNCYPE."""
68 return self.PYFUNC.in_dll(ctypes.pythonapi,"PyOS_InputHook")
69 return self.PYFUNC.in_dll(ctypes.pythonapi,"PyOS_InputHook")
69
70
70 def set_inputhook(self, callback):
71 def set_inputhook(self, callback):
71 """Set PyOS_InputHook to callback and return the previous one."""
72 """Set PyOS_InputHook to callback and return the previous one."""
72 self._callback = callback
73 self._callback = callback
73 self._callback_pyfunctype = self.PYFUNC(callback)
74 self._callback_pyfunctype = self.PYFUNC(callback)
74 pyos_inputhook_ptr = self.get_pyos_inputhook()
75 pyos_inputhook_ptr = self.get_pyos_inputhook()
75 original = self.get_pyos_inputhook_as_func()
76 original = self.get_pyos_inputhook_as_func()
76 pyos_inputhook_ptr.value = \
77 pyos_inputhook_ptr.value = \
77 ctypes.cast(self._callback_pyfunctype, ctypes.c_void_p).value
78 ctypes.cast(self._callback_pyfunctype, ctypes.c_void_p).value
78 self._installed = True
79 self._installed = True
79 return original
80 return original
80
81
81 def clear_inputhook(self, app=None):
82 def clear_inputhook(self, app=None):
82 """Set PyOS_InputHook to NULL and return the previous one.
83 """Set PyOS_InputHook to NULL and return the previous one.
83
84
84 Parameters
85 Parameters
85 ----------
86 ----------
86 app : optional, ignored
87 app : optional, ignored
87 This parameter is allowed only so that clear_inputhook() can be
88 This parameter is allowed only so that clear_inputhook() can be
88 called with a similar interface as all the ``enable_*`` methods. But
89 called with a similar interface as all the ``enable_*`` methods. But
89 the actual value of the parameter is ignored. This uniform interface
90 the actual value of the parameter is ignored. This uniform interface
90 makes it easier to have user-level entry points in the main IPython
91 makes it easier to have user-level entry points in the main IPython
91 app like :meth:`enable_gui`."""
92 app like :meth:`enable_gui`."""
92 pyos_inputhook_ptr = self.get_pyos_inputhook()
93 pyos_inputhook_ptr = self.get_pyos_inputhook()
93 original = self.get_pyos_inputhook_as_func()
94 original = self.get_pyos_inputhook_as_func()
94 pyos_inputhook_ptr.value = ctypes.c_void_p(None).value
95 pyos_inputhook_ptr.value = ctypes.c_void_p(None).value
95 self._reset()
96 self._reset()
96 return original
97 return original
97
98
98 def clear_app_refs(self, gui=None):
99 def clear_app_refs(self, gui=None):
99 """Clear IPython's internal reference to an application instance.
100 """Clear IPython's internal reference to an application instance.
100
101
101 Whenever we create an app for a user on qt4 or wx, we hold a
102 Whenever we create an app for a user on qt4 or wx, we hold a
102 reference to the app. This is needed because in some cases bad things
103 reference to the app. This is needed because in some cases bad things
103 can happen if a user doesn't hold a reference themselves. This
104 can happen if a user doesn't hold a reference themselves. This
104 method is provided to clear the references we are holding.
105 method is provided to clear the references we are holding.
105
106
106 Parameters
107 Parameters
107 ----------
108 ----------
108 gui : None or str
109 gui : None or str
109 If None, clear all app references. If ('wx', 'qt4') clear
110 If None, clear all app references. If ('wx', 'qt4') clear
110 the app for that toolkit. References are not held for gtk or tk
111 the app for that toolkit. References are not held for gtk or tk
111 as those toolkits don't have the notion of an app.
112 as those toolkits don't have the notion of an app.
112 """
113 """
113 if gui is None:
114 if gui is None:
114 self._apps = {}
115 self._apps = {}
115 elif self._apps.has_key(gui):
116 elif self._apps.has_key(gui):
116 del self._apps[gui]
117 del self._apps[gui]
117
118
118 def enable_wx(self, app=None):
119 def enable_wx(self, app=None):
119 """Enable event loop integration with wxPython.
120 """Enable event loop integration with wxPython.
120
121
121 Parameters
122 Parameters
122 ----------
123 ----------
123 app : WX Application, optional.
124 app : WX Application, optional.
124 Running application to use. If not given, we probe WX for an
125 Running application to use. If not given, we probe WX for an
125 existing application object, and create a new one if none is found.
126 existing application object, and create a new one if none is found.
126
127
127 Notes
128 Notes
128 -----
129 -----
129 This methods sets the ``PyOS_InputHook`` for wxPython, which allows
130 This methods sets the ``PyOS_InputHook`` for wxPython, which allows
130 the wxPython to integrate with terminal based applications like
131 the wxPython to integrate with terminal based applications like
131 IPython.
132 IPython.
132
133
133 If ``app`` is not given we probe for an existing one, and return it if
134 If ``app`` is not given we probe for an existing one, and return it if
134 found. If no existing app is found, we create an :class:`wx.App` as
135 found. If no existing app is found, we create an :class:`wx.App` as
135 follows::
136 follows::
136
137
137 import wx
138 import wx
138 app = wx.App(redirect=False, clearSigInt=False)
139 app = wx.App(redirect=False, clearSigInt=False)
139 """
140 """
140 from IPython.lib.inputhookwx import inputhook_wx
141 from IPython.lib.inputhookwx import inputhook_wx
141 self.set_inputhook(inputhook_wx)
142 self.set_inputhook(inputhook_wx)
142 self._current_gui = GUI_WX
143 self._current_gui = GUI_WX
143 import wx
144 import wx
144 if app is None:
145 if app is None:
145 app = wx.GetApp()
146 app = wx.GetApp()
146 if app is None:
147 if app is None:
147 app = wx.App(redirect=False, clearSigInt=False)
148 app = wx.App(redirect=False, clearSigInt=False)
148 app._in_event_loop = True
149 app._in_event_loop = True
149 self._apps[GUI_WX] = app
150 self._apps[GUI_WX] = app
150 return app
151 return app
151
152
152 def disable_wx(self):
153 def disable_wx(self):
153 """Disable event loop integration with wxPython.
154 """Disable event loop integration with wxPython.
154
155
155 This merely sets PyOS_InputHook to NULL.
156 This merely sets PyOS_InputHook to NULL.
156 """
157 """
157 if self._apps.has_key(GUI_WX):
158 if self._apps.has_key(GUI_WX):
158 self._apps[GUI_WX]._in_event_loop = False
159 self._apps[GUI_WX]._in_event_loop = False
159 self.clear_inputhook()
160 self.clear_inputhook()
160
161
161 def enable_qt4(self, app=None):
162 def enable_qt4(self, app=None):
162 """Enable event loop integration with PyQt4.
163 """Enable event loop integration with PyQt4.
163
164
164 Parameters
165 Parameters
165 ----------
166 ----------
166 app : Qt Application, optional.
167 app : Qt Application, optional.
167 Running application to use. If not given, we probe Qt for an
168 Running application to use. If not given, we probe Qt for an
168 existing application object, and create a new one if none is found.
169 existing application object, and create a new one if none is found.
169
170
170 Notes
171 Notes
171 -----
172 -----
172 This methods sets the PyOS_InputHook for PyQt4, which allows
173 This methods sets the PyOS_InputHook for PyQt4, which allows
173 the PyQt4 to integrate with terminal based applications like
174 the PyQt4 to integrate with terminal based applications like
174 IPython.
175 IPython.
175
176
176 If ``app`` is not given we probe for an existing one, and return it if
177 If ``app`` is not given we probe for an existing one, and return it if
177 found. If no existing app is found, we create an :class:`QApplication`
178 found. If no existing app is found, we create an :class:`QApplication`
178 as follows::
179 as follows::
179
180
180 from PyQt4 import QtCore
181 from PyQt4 import QtCore
181 app = QtGui.QApplication(sys.argv)
182 app = QtGui.QApplication(sys.argv)
182 """
183 """
183 from IPython.external.qt_for_kernel import QtCore, QtGui
184 from IPython.external.qt_for_kernel import QtCore, QtGui
184
185
185 if 'pyreadline' in sys.modules:
186 if 'pyreadline' in sys.modules:
186 # see IPython GitHub Issue #281 for more info on this issue
187 # see IPython GitHub Issue #281 for more info on this issue
187 # Similar intermittent behavior has been reported on OSX,
188 # Similar intermittent behavior has been reported on OSX,
188 # but not consistently reproducible
189 # but not consistently reproducible
189 warnings.warn("""PyReadline's inputhook can conflict with Qt, causing delays
190 warnings.warn("""PyReadline's inputhook can conflict with Qt, causing delays
190 in interactive input. If you do see this issue, we recommend using another GUI
191 in interactive input. If you do see this issue, we recommend using another GUI
191 toolkit if you can, or disable readline with the configuration option
192 toolkit if you can, or disable readline with the configuration option
192 'TerminalInteractiveShell.readline_use=False', specified in a config file or
193 'TerminalInteractiveShell.readline_use=False', specified in a config file or
193 at the command-line""",
194 at the command-line""",
194 RuntimeWarning)
195 RuntimeWarning)
195
196
196 # PyQt4 has had this since 4.3.1. In version 4.2, PyOS_InputHook
197 # PyQt4 has had this since 4.3.1. In version 4.2, PyOS_InputHook
197 # was set when QtCore was imported, but if it ever got removed,
198 # was set when QtCore was imported, but if it ever got removed,
198 # you couldn't reset it. For earlier versions we can
199 # you couldn't reset it. For earlier versions we can
199 # probably implement a ctypes version.
200 # probably implement a ctypes version.
200 try:
201 try:
201 QtCore.pyqtRestoreInputHook()
202 QtCore.pyqtRestoreInputHook()
202 except AttributeError:
203 except AttributeError:
203 pass
204 pass
204
205
205 self._current_gui = GUI_QT4
206 self._current_gui = GUI_QT4
206 if app is None:
207 if app is None:
207 app = QtCore.QCoreApplication.instance()
208 app = QtCore.QCoreApplication.instance()
208 if app is None:
209 if app is None:
209 app = QtGui.QApplication([" "])
210 app = QtGui.QApplication([" "])
210 app._in_event_loop = True
211 app._in_event_loop = True
211 self._apps[GUI_QT4] = app
212 self._apps[GUI_QT4] = app
212 return app
213 return app
213
214
214 def disable_qt4(self):
215 def disable_qt4(self):
215 """Disable event loop integration with PyQt4.
216 """Disable event loop integration with PyQt4.
216
217
217 This merely sets PyOS_InputHook to NULL.
218 This merely sets PyOS_InputHook to NULL.
218 """
219 """
219 if self._apps.has_key(GUI_QT4):
220 if self._apps.has_key(GUI_QT4):
220 self._apps[GUI_QT4]._in_event_loop = False
221 self._apps[GUI_QT4]._in_event_loop = False
221 self.clear_inputhook()
222 self.clear_inputhook()
222
223
223 def enable_gtk(self, app=None):
224 def enable_gtk(self, app=None):
224 """Enable event loop integration with PyGTK.
225 """Enable event loop integration with PyGTK.
225
226
226 Parameters
227 Parameters
227 ----------
228 ----------
228 app : ignored
229 app : ignored
229 Ignored, it's only a placeholder to keep the call signature of all
230 Ignored, it's only a placeholder to keep the call signature of all
230 gui activation methods consistent, which simplifies the logic of
231 gui activation methods consistent, which simplifies the logic of
231 supporting magics.
232 supporting magics.
232
233
233 Notes
234 Notes
234 -----
235 -----
235 This methods sets the PyOS_InputHook for PyGTK, which allows
236 This methods sets the PyOS_InputHook for PyGTK, which allows
236 the PyGTK to integrate with terminal based applications like
237 the PyGTK to integrate with terminal based applications like
237 IPython.
238 IPython.
238 """
239 """
239 import gtk
240 import gtk
240 try:
241 try:
241 gtk.set_interactive(True)
242 gtk.set_interactive(True)
242 self._current_gui = GUI_GTK
243 self._current_gui = GUI_GTK
243 except AttributeError:
244 except AttributeError:
244 # For older versions of gtk, use our own ctypes version
245 # For older versions of gtk, use our own ctypes version
245 from IPython.lib.inputhookgtk import inputhook_gtk
246 from IPython.lib.inputhookgtk import inputhook_gtk
246 self.set_inputhook(inputhook_gtk)
247 self.set_inputhook(inputhook_gtk)
247 self._current_gui = GUI_GTK
248 self._current_gui = GUI_GTK
248
249
249 def disable_gtk(self):
250 def disable_gtk(self):
250 """Disable event loop integration with PyGTK.
251 """Disable event loop integration with PyGTK.
251
252
252 This merely sets PyOS_InputHook to NULL.
253 This merely sets PyOS_InputHook to NULL.
253 """
254 """
254 self.clear_inputhook()
255 self.clear_inputhook()
255
256
256 def enable_tk(self, app=None):
257 def enable_tk(self, app=None):
257 """Enable event loop integration with Tk.
258 """Enable event loop integration with Tk.
258
259
259 Parameters
260 Parameters
260 ----------
261 ----------
261 app : toplevel :class:`Tkinter.Tk` widget, optional.
262 app : toplevel :class:`Tkinter.Tk` widget, optional.
262 Running toplevel widget to use. If not given, we probe Tk for an
263 Running toplevel widget to use. If not given, we probe Tk for an
263 existing one, and create a new one if none is found.
264 existing one, and create a new one if none is found.
264
265
265 Notes
266 Notes
266 -----
267 -----
267 If you have already created a :class:`Tkinter.Tk` object, the only
268 If you have already created a :class:`Tkinter.Tk` object, the only
268 thing done by this method is to register with the
269 thing done by this method is to register with the
269 :class:`InputHookManager`, since creating that object automatically
270 :class:`InputHookManager`, since creating that object automatically
270 sets ``PyOS_InputHook``.
271 sets ``PyOS_InputHook``.
271 """
272 """
272 self._current_gui = GUI_TK
273 self._current_gui = GUI_TK
273 if app is None:
274 if app is None:
274 import Tkinter
275 import Tkinter
275 app = Tkinter.Tk()
276 app = Tkinter.Tk()
276 app.withdraw()
277 app.withdraw()
277 self._apps[GUI_TK] = app
278 self._apps[GUI_TK] = app
278 return app
279 return app
279
280
280 def disable_tk(self):
281 def disable_tk(self):
281 """Disable event loop integration with Tkinter.
282 """Disable event loop integration with Tkinter.
282
283
283 This merely sets PyOS_InputHook to NULL.
284 This merely sets PyOS_InputHook to NULL.
284 """
285 """
285 self.clear_inputhook()
286 self.clear_inputhook()
286
287
288 def enable_glut(self, app=None):
289 """Enable event loop integration with GLUT.
287
290
291 Parameters
292 ----------
293 app : ignored
294 Ignored, it's only a placeholder to keep the call signature of all
295 gui activation methods consistent, which simplifies the logic of
296 supporting magics.
297
298 Notes
299 -----
300
301 This methods sets the PyOS_InputHook for GLUT, which allows the GLUT to
302 integrate with terminal based applications like IPython. Due to GLUT
303 limitations, it is currently not possible to start the event loop
304 without first creating a window. You should thus not create another
305 window but use instead the created one. See 'gui-glut.py' in the
306 docs/examples/lib directory.
307
308 The default screen mode is set to:
309
310 glut.GLUT_DOUBLE | glut.GLUT_RGBA | glut.GLUT_DEPTH
311
312 Script integration
313 ------------------
314
315 if glut.glutGetWindow() > 0:
316 interactive = True
317 glut.glutShowWindow()
318 else:
319 interactive = False
320 glut.glutInit(sys.argv)
321 glut.glutInitDisplayMode( glut.GLUT_DOUBLE |
322 glut.GLUT_RGBA |
323 glut.GLUT_DEPTH )
324 ...
325 if not interactive:
326 glut.glutMainLoop()
327 """
328 # GLUT is quite an old library and it is difficult to ensure proper
329 # integration within IPython since original GLUT does not allow to handle
330 # events one by one. Instead, it requires for the mainloop to be entered
331 # and never returned (there is not even a function to exit he
332 # mainloop). Fortunately, there are alternatives such as freeglut
333 # (available for linux and windows) and the OSX implementation gives
334 # access to a glutCheckLoop() function that blocks itself until a new
335 # event is received. This means we have to setup a default timer to
336 # ensure we got at least one event that will unblock the function. We set
337 # a default timer of 60fps.
338 #
339 # Furthermore, it is not possible to install these handlers without a
340 # window being first created. We choose to make this window invisible and
341 # the user is supposed to make it visible when needed (see gui-glut.py in
342 # the docs/examples/lib directory). This means that display mode options
343 # are set at this level and user won't be able to change them later
344 # without modifying the code. This should probably be made available via
345 # IPython options system.
346
347 import OpenGL
348 OpenGL.ERROR_CHECKING = False
349 import OpenGL.GLUT as glut
350 import OpenGL.platform as platform
351 import time
352
353
354 # Frame per second : 60
355 # Should probably be an IPython option
356 glut_fps = 60
357
358
359 # Display mode : double buffeed + rgba + depth
360 # Should probably be an IPython option
361 glut_display_mode = (glut.GLUT_DOUBLE |
362 glut.GLUT_RGBA |
363 glut.GLUT_DEPTH)
364
365 glut_interrupted = False
366
367 def display():
368 ''' Dummy display function '''
369 pass
370
371 def timer(fps):
372 # We should normally set the active window to 1 and post a
373 # redisplay for each window. The problem is that we do not know
374 # how much active windows we have and there is no function in glut
375 # to get that number.
376 # glut.glutSetWindow(1)
377 glut.glutTimerFunc( int(1000.0/fps), timer, fps)
378 glut.glutPostRedisplay()
379
380 def close():
381 glut.glutHideWindow()
382
383 glutMainLoopEvent = None
384 if sys.platform == 'darwin':
385 try:
386 glutCheckLoop = platform.createBaseFunction(
387 'glutCheckLoop', dll=platform.GLUT, resultType=None,
388 argTypes=[],
389 doc='glutCheckLoop( ) -> None',
390 argNames=(),
391 )
392 except AttributeError:
393 raise RuntimeError(
394 '''Your glut implementation does not allow interactive sessions'''
395 '''Consider installing freeglut.''')
396 glutMainLoopEvent = glutCheckLoop
397 elif glut.HAVE_FREEGLUT:
398 glutMainLoopEvent = glut.glutMainLoopEvent
399 else:
400 raise RuntimeError(
401 '''Your glut implementation does not allow interactive sessions. '''
402 '''Consider installing freeglut.''')
403
404 def inputhook_glut():
405 """ Process pending GLUT events only. """
406
407 # We need to protect against a user pressing Control-C when IPython
408 # is idle and this is running. We should trap KeyboardInterrupt and
409 # pass but it does not seem to work with glutMainLoopEvent.
410 # Instead, we setup a signal handler on SIGINT and returns after
411 # having restored the default python SIGINT handler.
412 import signal
413 def handler(signum, frame):
414 signal.signal(signal.SIGINT, signal.default_int_handler)
415 print '\nKeyboardInterrupt'
416 # Need to reprint the prompt at this stage
417
418 signal.signal(signal.SIGINT, handler)
419
420 try:
421 glutMainLoopEvent()
422 except KeyboardInterrupt: # this catch doesn't work for some reasons...
423 pass
424
425 return 0
426
427 if not self._apps.has_key(GUI_GLUT):
428 glut.glutInit(sys.argv)
429 # Display mode should be also an Ipython option since user won't be able
430 # to change it later
431 glut.glutInitDisplayMode(glut_display_mode)
432 glut.glutCreateWindow(sys.argv[0])
433 glut.glutHideWindow()
434 glut.glutWMCloseFunc(close)
435 glut.glutDisplayFunc(display)
436 glut.glutTimerFunc( int(1000.0/glut_fps), timer, glut_fps)
437 else:
438 glut.glutWMCloseFunc(close)
439 glut.glutDisplayFunc(display)
440 glut.glutTimerFunc( int(1000.0/glut_fps), timer, glut_fps)
441
442 self.set_inputhook(inputhook_glut)
443 self._current_gui = GUI_GLUT
444 self._apps[GUI_GLUT] = True
445
446 def disable_glut(self):
447 """Disable event loop integration with glut.
448
449 This sets PyOS_InputHook to NULL and set the display function to a
450 dummy one and set the timer to a dummy timer that will be triggered
451 very far in the future.
452 """
453 import signal
454 import OpenGL
455 OpenGL.ERROR_CHECKING = False
456 import OpenGL.GLUT as glut
457 import OpenGL.platform as platform
458
459 def timer_none(fps):
460 ''' Dummy timer function '''
461 pass
462
463 glutMainLoopEvent = None
464 if sys.platform == 'darwin':
465 try:
466 glutCheckLoop = platform.createBaseFunction(
467 'glutCheckLoop', dll=platform.GLUT, resultType=None,
468 argTypes=[],
469 doc='glutCheckLoop( ) -> None',
470 argNames=(),
471 )
472 except AttributeError:
473 raise RuntimeError(
474 '''Your glut implementation does not allow interactive sessions'''
475 '''Consider installing freeglut.''')
476 glutMainLoopEvent = glutCheckLoop
477 elif glut.HAVE_FREEGLUT:
478 glutMainLoopEvent = glut.glutMainLoopEvent
479 else:
480 raise RuntimeError(
481 '''Your glut implementation does not allow interactive sessions. '''
482 '''Consider installing freeglut.''')
483
484 glut.glutHideWindow() # This is an event to be processed below
485 glutMainLoopEvent()
486 #glut.glutTimerFunc( sys.maxint-1, timer_none, 0)
487 self.clear_inputhook()
488 #signal.signal(signal.SIGINT, signal.default_int_handler)
288
489
289 def enable_pyglet(self, app=None):
490 def enable_pyglet(self, app=None):
290 """Enable event loop integration with pyglet.
491 """Enable event loop integration with pyglet.
291
492
292 Parameters
493 Parameters
293 ----------
494 ----------
294 app : ignored
495 app : ignored
295 Ignored, it's only a placeholder to keep the call signature of all
496 Ignored, it's only a placeholder to keep the call signature of all
296 gui activation methods consistent, which simplifies the logic of
497 gui activation methods consistent, which simplifies the logic of
297 supporting magics.
498 supporting magics.
298
499
299 Notes
500 Notes
300 -----
501 -----
301 This methods sets the ``PyOS_InputHook`` for pyglet, which allows
502 This methods sets the ``PyOS_InputHook`` for pyglet, which allows
302 pyglet to integrate with terminal based applications like
503 pyglet to integrate with terminal based applications like
303 IPython.
504 IPython.
304
505
305 """
506 """
306 import pyglet
507 import pyglet
307 from IPython.lib.inputhookpyglet import inputhook_pyglet
508 from IPython.lib.inputhookpyglet import inputhook_pyglet
308 self.set_inputhook(inputhook_pyglet)
509 self.set_inputhook(inputhook_pyglet)
309 self._current_gui = GUI_PYGLET
510 self._current_gui = GUI_PYGLET
310 return app
511 return app
311
512
312 def disable_pyglet(self):
513 def disable_pyglet(self):
313 """Disable event loop integration with pyglet.
514 """Disable event loop integration with pyglet.
314
515
315 This merely sets PyOS_InputHook to NULL.
516 This merely sets PyOS_InputHook to NULL.
316 """
517 """
317 self.clear_inputhook()
518 self.clear_inputhook()
318
519
319
320 def current_gui(self):
520 def current_gui(self):
321 """Return a string indicating the currently active GUI or None."""
521 """Return a string indicating the currently active GUI or None."""
322 return self._current_gui
522 return self._current_gui
323
523
324 inputhook_manager = InputHookManager()
524 inputhook_manager = InputHookManager()
325
525
326 enable_wx = inputhook_manager.enable_wx
526 enable_wx = inputhook_manager.enable_wx
327 disable_wx = inputhook_manager.disable_wx
527 disable_wx = inputhook_manager.disable_wx
328 enable_qt4 = inputhook_manager.enable_qt4
528 enable_qt4 = inputhook_manager.enable_qt4
329 disable_qt4 = inputhook_manager.disable_qt4
529 disable_qt4 = inputhook_manager.disable_qt4
330 enable_gtk = inputhook_manager.enable_gtk
530 enable_gtk = inputhook_manager.enable_gtk
331 disable_gtk = inputhook_manager.disable_gtk
531 disable_gtk = inputhook_manager.disable_gtk
332 enable_tk = inputhook_manager.enable_tk
532 enable_tk = inputhook_manager.enable_tk
333 disable_tk = inputhook_manager.disable_tk
533 disable_tk = inputhook_manager.disable_tk
534 enable_glut = inputhook_manager.enable_glut
535 disable_glut = inputhook_manager.disable_glut
334 enable_pyglet = inputhook_manager.enable_pyglet
536 enable_pyglet = inputhook_manager.enable_pyglet
335 disable_pyglet = inputhook_manager.disable_pyglet
537 disable_pyglet = inputhook_manager.disable_pyglet
336 clear_inputhook = inputhook_manager.clear_inputhook
538 clear_inputhook = inputhook_manager.clear_inputhook
337 set_inputhook = inputhook_manager.set_inputhook
539 set_inputhook = inputhook_manager.set_inputhook
338 current_gui = inputhook_manager.current_gui
540 current_gui = inputhook_manager.current_gui
339 clear_app_refs = inputhook_manager.clear_app_refs
541 clear_app_refs = inputhook_manager.clear_app_refs
340
542
341
543
342 # Convenience function to switch amongst them
544 # Convenience function to switch amongst them
343 def enable_gui(gui=None, app=None):
545 def enable_gui(gui=None, app=None):
344 """Switch amongst GUI input hooks by name.
546 """Switch amongst GUI input hooks by name.
345
547
346 This is just a utility wrapper around the methods of the InputHookManager
548 This is just a utility wrapper around the methods of the InputHookManager
347 object.
549 object.
348
550
349 Parameters
551 Parameters
350 ----------
552 ----------
351 gui : optional, string or None
553 gui : optional, string or None
352 If None, clears input hook, otherwise it must be one of the recognized
554 If None, clears input hook, otherwise it must be one of the recognized
353 GUI names (see ``GUI_*`` constants in module).
555 GUI names (see ``GUI_*`` constants in module).
354
556
355 app : optional, existing application object.
557 app : optional, existing application object.
356 For toolkits that have the concept of a global app, you can supply an
558 For toolkits that have the concept of a global app, you can supply an
357 existing one. If not given, the toolkit will be probed for one, and if
559 existing one. If not given, the toolkit will be probed for one, and if
358 none is found, a new one will be created. Note that GTK does not have
560 none is found, a new one will be created. Note that GTK does not have
359 this concept, and passing an app if `gui`=="GTK" will raise an error.
561 this concept, and passing an app if `gui`=="GTK" will raise an error.
360
562
361 Returns
563 Returns
362 -------
564 -------
363 The output of the underlying gui switch routine, typically the actual
565 The output of the underlying gui switch routine, typically the actual
364 PyOS_InputHook wrapper object or the GUI toolkit app created, if there was
566 PyOS_InputHook wrapper object or the GUI toolkit app created, if there was
365 one.
567 one.
366 """
568 """
367 guis = {None: clear_inputhook,
569 guis = {None: clear_inputhook,
368 GUI_OSX: lambda app=False: None,
570 GUI_OSX: lambda app=False: None,
369 GUI_TK: enable_tk,
571 GUI_TK: enable_tk,
370 GUI_GTK: enable_gtk,
572 GUI_GTK: enable_gtk,
371 GUI_WX: enable_wx,
573 GUI_WX: enable_wx,
372 GUI_QT: enable_qt4, # qt3 not supported
574 GUI_QT: enable_qt4, # qt3 not supported
373 GUI_QT4: enable_qt4,
575 GUI_QT4: enable_qt4,
576 GUI_GLUT: enable_glut,
374 GUI_PYGLET: enable_pyglet,
577 GUI_PYGLET: enable_pyglet,
375 }
578 }
376 try:
579 try:
377 gui_hook = guis[gui]
580 gui_hook = guis[gui]
378 except KeyError:
581 except KeyError:
379 e = "Invalid GUI request %r, valid ones are:%s" % (gui, guis.keys())
582 e = "Invalid GUI request %r, valid ones are:%s" % (gui, guis.keys())
380 raise ValueError(e)
583 raise ValueError(e)
381 return gui_hook(app)
584 return gui_hook(app)
382
585
General Comments 0
You need to be logged in to leave comments. Login now