##// END OF EJS Templates
Merge branch 'pyglet' by Nicolas Rougier, with minor fixes....
Fernando Perez -
r4805:7511bc62 merge
parent child Browse files
Show More
@@ -0,0 +1,115 b''
1 # encoding: utf-8
2 """
3 Enable pyglet to be used interacive by setting PyOS_InputHook.
4
5 Authors
6 -------
7
8 * Nicolas P. Rougier
9 * Fernando Perez
10 """
11
12 #-----------------------------------------------------------------------------
13 # Copyright (C) 2008-2009 The IPython Development Team
14 #
15 # Distributed under the terms of the BSD License. The full license is in
16 # the file COPYING, distributed as part of this software.
17 #-----------------------------------------------------------------------------
18
19 #-----------------------------------------------------------------------------
20 # Imports
21 #-----------------------------------------------------------------------------
22
23 import os
24 import signal
25 import sys
26 import time
27 from timeit import default_timer as clock
28 import pyglet
29
30 #-----------------------------------------------------------------------------
31 # Platform-dependent imports and functions
32 #-----------------------------------------------------------------------------
33
34 if os.name == 'posix':
35 import select
36
37 def stdin_ready():
38 infds, outfds, erfds = select.select([sys.stdin],[],[],0)
39 if infds:
40 return True
41 else:
42 return False
43
44 elif sys.platform == 'win32':
45 import msvcrt
46
47 def stdin_ready():
48 return msvcrt.kbhit()
49
50
51 # On linux only, window.flip() has a bug that causes an AttributeError on
52 # window close. For details, see:
53 # http://groups.google.com/group/pyglet-users/browse_thread/thread/47c1aab9aa4a3d23/c22f9e819826799e?#c22f9e819826799e
54
55 if sys.platform.startswith('linux'):
56 def flip(window):
57 try:
58 window.flip()
59 except AttributeError:
60 pass
61 else:
62 def flip(window):
63 window.flip()
64
65 #-----------------------------------------------------------------------------
66 # Code
67 #-----------------------------------------------------------------------------
68
69 def inputhook_pyglet():
70 """Run the pyglet event loop by processing pending events only.
71
72 This keeps processing pending events until stdin is ready. After
73 processing all pending events, a call to time.sleep is inserted. This is
74 needed, otherwise, CPU usage is at 100%. This sleep time should be tuned
75 though for best performance.
76 """
77 # We need to protect against a user pressing Control-C when IPython is
78 # idle and this is running. We trap KeyboardInterrupt and pass.
79 try:
80 t = clock()
81 while not stdin_ready():
82 pyglet.clock.tick()
83 for window in pyglet.app.windows:
84 window.switch_to()
85 window.dispatch_events()
86 window.dispatch_event('on_draw')
87 flip(window)
88
89 # We need to sleep at this point to keep the idle CPU load
90 # low. However, if sleep to long, GUI response is poor. As
91 # a compromise, we watch how often GUI events are being processed
92 # and switch between a short and long sleep time. Here are some
93 # stats useful in helping to tune this.
94 # time CPU load
95 # 0.001 13%
96 # 0.005 3%
97 # 0.01 1.5%
98 # 0.05 0.5%
99 used_time = clock() - t
100 if used_time > 5*60.0:
101 # print 'Sleep for 5 s' # dbg
102 time.sleep(5.0)
103 elif used_time > 10.0:
104 # print 'Sleep for 1 s' # dbg
105 time.sleep(1.0)
106 elif used_time > 0.1:
107 # Few GUI events coming in, so we can sleep longer
108 # print 'Sleep for 0.05 s' # dbg
109 time.sleep(0.05)
110 else:
111 # Many GUI events coming in, so sleep only very little
112 time.sleep(0.001)
113 except KeyboardInterrupt:
114 pass
115 return 0
@@ -0,0 +1,33 b''
1 #!/usr/bin/env python
2 """Simple pyglet example to manually test event loop integration.
3
4 This is meant to run tests manually in ipython as:
5
6 In [5]: %gui pyglet
7
8 In [6]: %run gui-pyglet.py
9 """
10
11 import pyglet
12
13
14 window = pyglet.window.Window()
15 label = pyglet.text.Label('Hello, world',
16 font_name='Times New Roman',
17 font_size=36,
18 x=window.width//2, y=window.height//2,
19 anchor_x='center', anchor_y='center')
20 @window.event
21 def on_close():
22 window.close()
23
24 @window.event
25 def on_draw():
26 window.clear()
27 label.draw()
28
29 try:
30 from IPython.lib.inputhook import enable_pyglet
31 enable_pyglet()
32 except ImportError:
33 pyglet.app.run()
@@ -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'), config=True,
232 gui = CaselessStrEnum(('qt','wx','gtk', 'pyglet'), config=True,
233 help="Enable GUI event loop integration ('qt', 'wx', 'gtk')."
233 help="Enable GUI event loop integration ('qt', 'wx', 'gtk', '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,28 +1,29 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_pyglet, disable_pyglet,
22 set_inputhook, clear_inputhook,
23 set_inputhook, clear_inputhook,
23 current_gui
24 current_gui
24 )
25 )
25
26
26 #-----------------------------------------------------------------------------
27 #-----------------------------------------------------------------------------
27 # Code
28 # Code
28 #-----------------------------------------------------------------------------
29 #-----------------------------------------------------------------------------
@@ -1,344 +1,382 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_PYGLET = 'pyglet'
32
33
33 #-----------------------------------------------------------------------------
34 #-----------------------------------------------------------------------------
34 # Utility classes
35 # Utility classes
35 #-----------------------------------------------------------------------------
36 #-----------------------------------------------------------------------------
36
37
37
38
38 #-----------------------------------------------------------------------------
39 #-----------------------------------------------------------------------------
39 # Main InputHookManager class
40 # Main InputHookManager class
40 #-----------------------------------------------------------------------------
41 #-----------------------------------------------------------------------------
41
42
42
43
43 class InputHookManager(object):
44 class InputHookManager(object):
44 """Manage PyOS_InputHook for different GUI toolkits.
45 """Manage PyOS_InputHook for different GUI toolkits.
45
46
46 This class installs various hooks under ``PyOSInputHook`` to handle
47 This class installs various hooks under ``PyOSInputHook`` to handle
47 GUI event loop integration.
48 GUI event loop integration.
48 """
49 """
49
50
50 def __init__(self):
51 def __init__(self):
51 self.PYFUNC = ctypes.PYFUNCTYPE(ctypes.c_int)
52 self.PYFUNC = ctypes.PYFUNCTYPE(ctypes.c_int)
52 self._apps = {}
53 self._apps = {}
53 self._reset()
54 self._reset()
54
55
55 def _reset(self):
56 def _reset(self):
56 self._callback_pyfunctype = None
57 self._callback_pyfunctype = None
57 self._callback = None
58 self._callback = None
58 self._installed = False
59 self._installed = False
59 self._current_gui = None
60 self._current_gui = None
60
61
61 def get_pyos_inputhook(self):
62 def get_pyos_inputhook(self):
62 """Return the current PyOS_InputHook as a ctypes.c_void_p."""
63 """Return the current PyOS_InputHook as a ctypes.c_void_p."""
63 return ctypes.c_void_p.in_dll(ctypes.pythonapi,"PyOS_InputHook")
64 return ctypes.c_void_p.in_dll(ctypes.pythonapi,"PyOS_InputHook")
64
65
65 def get_pyos_inputhook_as_func(self):
66 def get_pyos_inputhook_as_func(self):
66 """Return the current PyOS_InputHook as a ctypes.PYFUNCYPE."""
67 """Return the current PyOS_InputHook as a ctypes.PYFUNCYPE."""
67 return self.PYFUNC.in_dll(ctypes.pythonapi,"PyOS_InputHook")
68 return self.PYFUNC.in_dll(ctypes.pythonapi,"PyOS_InputHook")
68
69
69 def set_inputhook(self, callback):
70 def set_inputhook(self, callback):
70 """Set PyOS_InputHook to callback and return the previous one."""
71 """Set PyOS_InputHook to callback and return the previous one."""
71 self._callback = callback
72 self._callback = callback
72 self._callback_pyfunctype = self.PYFUNC(callback)
73 self._callback_pyfunctype = self.PYFUNC(callback)
73 pyos_inputhook_ptr = self.get_pyos_inputhook()
74 pyos_inputhook_ptr = self.get_pyos_inputhook()
74 original = self.get_pyos_inputhook_as_func()
75 original = self.get_pyos_inputhook_as_func()
75 pyos_inputhook_ptr.value = \
76 pyos_inputhook_ptr.value = \
76 ctypes.cast(self._callback_pyfunctype, ctypes.c_void_p).value
77 ctypes.cast(self._callback_pyfunctype, ctypes.c_void_p).value
77 self._installed = True
78 self._installed = True
78 return original
79 return original
79
80
80 def clear_inputhook(self, app=None):
81 def clear_inputhook(self, app=None):
81 """Set PyOS_InputHook to NULL and return the previous one.
82 """Set PyOS_InputHook to NULL and return the previous one.
82
83
83 Parameters
84 Parameters
84 ----------
85 ----------
85 app : optional, ignored
86 app : optional, ignored
86 This parameter is allowed only so that clear_inputhook() can be
87 This parameter is allowed only so that clear_inputhook() can be
87 called with a similar interface as all the ``enable_*`` methods. But
88 called with a similar interface as all the ``enable_*`` methods. But
88 the actual value of the parameter is ignored. This uniform interface
89 the actual value of the parameter is ignored. This uniform interface
89 makes it easier to have user-level entry points in the main IPython
90 makes it easier to have user-level entry points in the main IPython
90 app like :meth:`enable_gui`."""
91 app like :meth:`enable_gui`."""
91 pyos_inputhook_ptr = self.get_pyos_inputhook()
92 pyos_inputhook_ptr = self.get_pyos_inputhook()
92 original = self.get_pyos_inputhook_as_func()
93 original = self.get_pyos_inputhook_as_func()
93 pyos_inputhook_ptr.value = ctypes.c_void_p(None).value
94 pyos_inputhook_ptr.value = ctypes.c_void_p(None).value
94 self._reset()
95 self._reset()
95 return original
96 return original
96
97
97 def clear_app_refs(self, gui=None):
98 def clear_app_refs(self, gui=None):
98 """Clear IPython's internal reference to an application instance.
99 """Clear IPython's internal reference to an application instance.
99
100
100 Whenever we create an app for a user on qt4 or wx, we hold a
101 Whenever we create an app for a user on qt4 or wx, we hold a
101 reference to the app. This is needed because in some cases bad things
102 reference to the app. This is needed because in some cases bad things
102 can happen if a user doesn't hold a reference themselves. This
103 can happen if a user doesn't hold a reference themselves. This
103 method is provided to clear the references we are holding.
104 method is provided to clear the references we are holding.
104
105
105 Parameters
106 Parameters
106 ----------
107 ----------
107 gui : None or str
108 gui : None or str
108 If None, clear all app references. If ('wx', 'qt4') clear
109 If None, clear all app references. If ('wx', 'qt4') clear
109 the app for that toolkit. References are not held for gtk or tk
110 the app for that toolkit. References are not held for gtk or tk
110 as those toolkits don't have the notion of an app.
111 as those toolkits don't have the notion of an app.
111 """
112 """
112 if gui is None:
113 if gui is None:
113 self._apps = {}
114 self._apps = {}
114 elif self._apps.has_key(gui):
115 elif self._apps.has_key(gui):
115 del self._apps[gui]
116 del self._apps[gui]
116
117
117 def enable_wx(self, app=None):
118 def enable_wx(self, app=None):
118 """Enable event loop integration with wxPython.
119 """Enable event loop integration with wxPython.
119
120
120 Parameters
121 Parameters
121 ----------
122 ----------
122 app : WX Application, optional.
123 app : WX Application, optional.
123 Running application to use. If not given, we probe WX for an
124 Running application to use. If not given, we probe WX for an
124 existing application object, and create a new one if none is found.
125 existing application object, and create a new one if none is found.
125
126
126 Notes
127 Notes
127 -----
128 -----
128 This methods sets the ``PyOS_InputHook`` for wxPython, which allows
129 This methods sets the ``PyOS_InputHook`` for wxPython, which allows
129 the wxPython to integrate with terminal based applications like
130 the wxPython to integrate with terminal based applications like
130 IPython.
131 IPython.
131
132
132 If ``app`` is not given we probe for an existing one, and return it if
133 If ``app`` is not given we probe for an existing one, and return it if
133 found. If no existing app is found, we create an :class:`wx.App` as
134 found. If no existing app is found, we create an :class:`wx.App` as
134 follows::
135 follows::
135
136
136 import wx
137 import wx
137 app = wx.App(redirect=False, clearSigInt=False)
138 app = wx.App(redirect=False, clearSigInt=False)
138 """
139 """
139 from IPython.lib.inputhookwx import inputhook_wx
140 from IPython.lib.inputhookwx import inputhook_wx
140 self.set_inputhook(inputhook_wx)
141 self.set_inputhook(inputhook_wx)
141 self._current_gui = GUI_WX
142 self._current_gui = GUI_WX
142 import wx
143 import wx
143 if app is None:
144 if app is None:
144 app = wx.GetApp()
145 app = wx.GetApp()
145 if app is None:
146 if app is None:
146 app = wx.App(redirect=False, clearSigInt=False)
147 app = wx.App(redirect=False, clearSigInt=False)
147 app._in_event_loop = True
148 app._in_event_loop = True
148 self._apps[GUI_WX] = app
149 self._apps[GUI_WX] = app
149 return app
150 return app
150
151
151 def disable_wx(self):
152 def disable_wx(self):
152 """Disable event loop integration with wxPython.
153 """Disable event loop integration with wxPython.
153
154
154 This merely sets PyOS_InputHook to NULL.
155 This merely sets PyOS_InputHook to NULL.
155 """
156 """
156 if self._apps.has_key(GUI_WX):
157 if self._apps.has_key(GUI_WX):
157 self._apps[GUI_WX]._in_event_loop = False
158 self._apps[GUI_WX]._in_event_loop = False
158 self.clear_inputhook()
159 self.clear_inputhook()
159
160
160 def enable_qt4(self, app=None):
161 def enable_qt4(self, app=None):
161 """Enable event loop integration with PyQt4.
162 """Enable event loop integration with PyQt4.
162
163
163 Parameters
164 Parameters
164 ----------
165 ----------
165 app : Qt Application, optional.
166 app : Qt Application, optional.
166 Running application to use. If not given, we probe Qt for an
167 Running application to use. If not given, we probe Qt for an
167 existing application object, and create a new one if none is found.
168 existing application object, and create a new one if none is found.
168
169
169 Notes
170 Notes
170 -----
171 -----
171 This methods sets the PyOS_InputHook for PyQt4, which allows
172 This methods sets the PyOS_InputHook for PyQt4, which allows
172 the PyQt4 to integrate with terminal based applications like
173 the PyQt4 to integrate with terminal based applications like
173 IPython.
174 IPython.
174
175
175 If ``app`` is not given we probe for an existing one, and return it if
176 If ``app`` is not given we probe for an existing one, and return it if
176 found. If no existing app is found, we create an :class:`QApplication`
177 found. If no existing app is found, we create an :class:`QApplication`
177 as follows::
178 as follows::
178
179
179 from PyQt4 import QtCore
180 from PyQt4 import QtCore
180 app = QtGui.QApplication(sys.argv)
181 app = QtGui.QApplication(sys.argv)
181 """
182 """
182 from IPython.external.qt_for_kernel import QtCore, QtGui
183 from IPython.external.qt_for_kernel import QtCore, QtGui
183
184
184 if 'pyreadline' in sys.modules:
185 if 'pyreadline' in sys.modules:
185 # see IPython GitHub Issue #281 for more info on this issue
186 # see IPython GitHub Issue #281 for more info on this issue
186 # Similar intermittent behavior has been reported on OSX,
187 # Similar intermittent behavior has been reported on OSX,
187 # but not consistently reproducible
188 # but not consistently reproducible
188 warnings.warn("""PyReadline's inputhook can conflict with Qt, causing delays
189 warnings.warn("""PyReadline's inputhook can conflict with Qt, causing delays
189 in interactive input. If you do see this issue, we recommend using another GUI
190 in interactive input. If you do see this issue, we recommend using another GUI
190 toolkit if you can, or disable readline with the configuration option
191 toolkit if you can, or disable readline with the configuration option
191 'TerminalInteractiveShell.readline_use=False', specified in a config file or
192 'TerminalInteractiveShell.readline_use=False', specified in a config file or
192 at the command-line""",
193 at the command-line""",
193 RuntimeWarning)
194 RuntimeWarning)
194
195
195 # PyQt4 has had this since 4.3.1. In version 4.2, PyOS_InputHook
196 # PyQt4 has had this since 4.3.1. In version 4.2, PyOS_InputHook
196 # was set when QtCore was imported, but if it ever got removed,
197 # was set when QtCore was imported, but if it ever got removed,
197 # you couldn't reset it. For earlier versions we can
198 # you couldn't reset it. For earlier versions we can
198 # probably implement a ctypes version.
199 # probably implement a ctypes version.
199 try:
200 try:
200 QtCore.pyqtRestoreInputHook()
201 QtCore.pyqtRestoreInputHook()
201 except AttributeError:
202 except AttributeError:
202 pass
203 pass
203
204
204 self._current_gui = GUI_QT4
205 self._current_gui = GUI_QT4
205 if app is None:
206 if app is None:
206 app = QtCore.QCoreApplication.instance()
207 app = QtCore.QCoreApplication.instance()
207 if app is None:
208 if app is None:
208 app = QtGui.QApplication([" "])
209 app = QtGui.QApplication([" "])
209 app._in_event_loop = True
210 app._in_event_loop = True
210 self._apps[GUI_QT4] = app
211 self._apps[GUI_QT4] = app
211 return app
212 return app
212
213
213 def disable_qt4(self):
214 def disable_qt4(self):
214 """Disable event loop integration with PyQt4.
215 """Disable event loop integration with PyQt4.
215
216
216 This merely sets PyOS_InputHook to NULL.
217 This merely sets PyOS_InputHook to NULL.
217 """
218 """
218 if self._apps.has_key(GUI_QT4):
219 if self._apps.has_key(GUI_QT4):
219 self._apps[GUI_QT4]._in_event_loop = False
220 self._apps[GUI_QT4]._in_event_loop = False
220 self.clear_inputhook()
221 self.clear_inputhook()
221
222
222 def enable_gtk(self, app=None):
223 def enable_gtk(self, app=None):
223 """Enable event loop integration with PyGTK.
224 """Enable event loop integration with PyGTK.
224
225
225 Parameters
226 Parameters
226 ----------
227 ----------
227 app : ignored
228 app : ignored
228 Ignored, it's only a placeholder to keep the call signature of all
229 Ignored, it's only a placeholder to keep the call signature of all
229 gui activation methods consistent, which simplifies the logic of
230 gui activation methods consistent, which simplifies the logic of
230 supporting magics.
231 supporting magics.
231
232
232 Notes
233 Notes
233 -----
234 -----
234 This methods sets the PyOS_InputHook for PyGTK, which allows
235 This methods sets the PyOS_InputHook for PyGTK, which allows
235 the PyGTK to integrate with terminal based applications like
236 the PyGTK to integrate with terminal based applications like
236 IPython.
237 IPython.
237 """
238 """
238 import gtk
239 import gtk
239 try:
240 try:
240 gtk.set_interactive(True)
241 gtk.set_interactive(True)
241 self._current_gui = GUI_GTK
242 self._current_gui = GUI_GTK
242 except AttributeError:
243 except AttributeError:
243 # For older versions of gtk, use our own ctypes version
244 # For older versions of gtk, use our own ctypes version
244 from IPython.lib.inputhookgtk import inputhook_gtk
245 from IPython.lib.inputhookgtk import inputhook_gtk
245 self.set_inputhook(inputhook_gtk)
246 self.set_inputhook(inputhook_gtk)
246 self._current_gui = GUI_GTK
247 self._current_gui = GUI_GTK
247
248
248 def disable_gtk(self):
249 def disable_gtk(self):
249 """Disable event loop integration with PyGTK.
250 """Disable event loop integration with PyGTK.
250
251
251 This merely sets PyOS_InputHook to NULL.
252 This merely sets PyOS_InputHook to NULL.
252 """
253 """
253 self.clear_inputhook()
254 self.clear_inputhook()
254
255
255 def enable_tk(self, app=None):
256 def enable_tk(self, app=None):
256 """Enable event loop integration with Tk.
257 """Enable event loop integration with Tk.
257
258
258 Parameters
259 Parameters
259 ----------
260 ----------
260 app : toplevel :class:`Tkinter.Tk` widget, optional.
261 app : toplevel :class:`Tkinter.Tk` widget, optional.
261 Running toplevel widget to use. If not given, we probe Tk for an
262 Running toplevel widget to use. If not given, we probe Tk for an
262 existing one, and create a new one if none is found.
263 existing one, and create a new one if none is found.
263
264
264 Notes
265 Notes
265 -----
266 -----
266 If you have already created a :class:`Tkinter.Tk` object, the only
267 If you have already created a :class:`Tkinter.Tk` object, the only
267 thing done by this method is to register with the
268 thing done by this method is to register with the
268 :class:`InputHookManager`, since creating that object automatically
269 :class:`InputHookManager`, since creating that object automatically
269 sets ``PyOS_InputHook``.
270 sets ``PyOS_InputHook``.
270 """
271 """
271 self._current_gui = GUI_TK
272 self._current_gui = GUI_TK
272 if app is None:
273 if app is None:
273 import Tkinter
274 import Tkinter
274 app = Tkinter.Tk()
275 app = Tkinter.Tk()
275 app.withdraw()
276 app.withdraw()
276 self._apps[GUI_TK] = app
277 self._apps[GUI_TK] = app
277 return app
278 return app
278
279
279 def disable_tk(self):
280 def disable_tk(self):
280 """Disable event loop integration with Tkinter.
281 """Disable event loop integration with Tkinter.
281
282
282 This merely sets PyOS_InputHook to NULL.
283 This merely sets PyOS_InputHook to NULL.
283 """
284 """
284 self.clear_inputhook()
285 self.clear_inputhook()
285
286
287
288
289 def enable_pyglet(self, app=None):
290 """Enable event loop integration with pyglet.
291
292 Parameters
293 ----------
294 app : ignored
295 Ignored, it's only a placeholder to keep the call signature of all
296 gui activation methods consistent, which simplifies the logic of
297 supporting magics.
298
299 Notes
300 -----
301 This methods sets the ``PyOS_InputHook`` for pyglet, which allows
302 pyglet to integrate with terminal based applications like
303 IPython.
304
305 """
306 import pyglet
307 from IPython.lib.inputhookpyglet import inputhook_pyglet
308 self.set_inputhook(inputhook_pyglet)
309 self._current_gui = GUI_PYGLET
310 return app
311
312 def disable_pyglet(self):
313 """Disable event loop integration with pyglet.
314
315 This merely sets PyOS_InputHook to NULL.
316 """
317 self.clear_inputhook()
318
319
286 def current_gui(self):
320 def current_gui(self):
287 """Return a string indicating the currently active GUI or None."""
321 """Return a string indicating the currently active GUI or None."""
288 return self._current_gui
322 return self._current_gui
289
323
290 inputhook_manager = InputHookManager()
324 inputhook_manager = InputHookManager()
291
325
292 enable_wx = inputhook_manager.enable_wx
326 enable_wx = inputhook_manager.enable_wx
293 disable_wx = inputhook_manager.disable_wx
327 disable_wx = inputhook_manager.disable_wx
294 enable_qt4 = inputhook_manager.enable_qt4
328 enable_qt4 = inputhook_manager.enable_qt4
295 disable_qt4 = inputhook_manager.disable_qt4
329 disable_qt4 = inputhook_manager.disable_qt4
296 enable_gtk = inputhook_manager.enable_gtk
330 enable_gtk = inputhook_manager.enable_gtk
297 disable_gtk = inputhook_manager.disable_gtk
331 disable_gtk = inputhook_manager.disable_gtk
298 enable_tk = inputhook_manager.enable_tk
332 enable_tk = inputhook_manager.enable_tk
299 disable_tk = inputhook_manager.disable_tk
333 disable_tk = inputhook_manager.disable_tk
334 enable_pyglet = inputhook_manager.enable_pyglet
335 disable_pyglet = inputhook_manager.disable_pyglet
300 clear_inputhook = inputhook_manager.clear_inputhook
336 clear_inputhook = inputhook_manager.clear_inputhook
301 set_inputhook = inputhook_manager.set_inputhook
337 set_inputhook = inputhook_manager.set_inputhook
302 current_gui = inputhook_manager.current_gui
338 current_gui = inputhook_manager.current_gui
303 clear_app_refs = inputhook_manager.clear_app_refs
339 clear_app_refs = inputhook_manager.clear_app_refs
304
340
305
341
306 # Convenience function to switch amongst them
342 # Convenience function to switch amongst them
307 def enable_gui(gui=None, app=None):
343 def enable_gui(gui=None, app=None):
308 """Switch amongst GUI input hooks by name.
344 """Switch amongst GUI input hooks by name.
309
345
310 This is just a utility wrapper around the methods of the InputHookManager
346 This is just a utility wrapper around the methods of the InputHookManager
311 object.
347 object.
312
348
313 Parameters
349 Parameters
314 ----------
350 ----------
315 gui : optional, string or None
351 gui : optional, string or None
316 If None, clears input hook, otherwise it must be one of the recognized
352 If None, clears input hook, otherwise it must be one of the recognized
317 GUI names (see ``GUI_*`` constants in module).
353 GUI names (see ``GUI_*`` constants in module).
318
354
319 app : optional, existing application object.
355 app : optional, existing application object.
320 For toolkits that have the concept of a global app, you can supply an
356 For toolkits that have the concept of a global app, you can supply an
321 existing one. If not given, the toolkit will be probed for one, and if
357 existing one. If not given, the toolkit will be probed for one, and if
322 none is found, a new one will be created. Note that GTK does not have
358 none is found, a new one will be created. Note that GTK does not have
323 this concept, and passing an app if `gui`=="GTK" will raise an error.
359 this concept, and passing an app if `gui`=="GTK" will raise an error.
324
360
325 Returns
361 Returns
326 -------
362 -------
327 The output of the underlying gui switch routine, typically the actual
363 The output of the underlying gui switch routine, typically the actual
328 PyOS_InputHook wrapper object or the GUI toolkit app created, if there was
364 PyOS_InputHook wrapper object or the GUI toolkit app created, if there was
329 one.
365 one.
330 """
366 """
331 guis = {None: clear_inputhook,
367 guis = {None: clear_inputhook,
332 GUI_OSX: lambda app=False: None,
368 GUI_OSX: lambda app=False: None,
333 GUI_TK: enable_tk,
369 GUI_TK: enable_tk,
334 GUI_GTK: enable_gtk,
370 GUI_GTK: enable_gtk,
335 GUI_WX: enable_wx,
371 GUI_WX: enable_wx,
336 GUI_QT: enable_qt4, # qt3 not supported
372 GUI_QT: enable_qt4, # qt3 not supported
337 GUI_QT4: enable_qt4 }
373 GUI_QT4: enable_qt4,
374 GUI_PYGLET: enable_pyglet,
375 }
338 try:
376 try:
339 gui_hook = guis[gui]
377 gui_hook = guis[gui]
340 except KeyError:
378 except KeyError:
341 e = "Invalid GUI request %r, valid ones are:%s" % (gui, guis.keys())
379 e = "Invalid GUI request %r, valid ones are:%s" % (gui, guis.keys())
342 raise ValueError(e)
380 raise ValueError(e)
343 return gui_hook(app)
381 return gui_hook(app)
344
382
General Comments 0
You need to be logged in to leave comments. Login now