Show More
@@ -0,0 +1,15 | |||
|
1 | """GUI support for the IPython ZeroMQ kernel. | |
|
2 | ||
|
3 | This package contains the various toolkit-dependent utilities we use to enable | |
|
4 | coordination between the IPython kernel and the event loops of the various GUI | |
|
5 | toolkits. | |
|
6 | """ | |
|
7 | ||
|
8 | #----------------------------------------------------------------------------- | |
|
9 | # Copyright (C) 2010 The IPython Development Team. | |
|
10 | # | |
|
11 | # Distributed under the terms of the BSD License. | |
|
12 | # | |
|
13 | # The full license is in the file COPYING.txt, distributed as part of this | |
|
14 | # software. | |
|
15 | #----------------------------------------------------------------------------- |
@@ -0,0 +1,86 | |||
|
1 | """GUI support for the IPython ZeroMQ kernel - GTK toolkit support. | |
|
2 | """ | |
|
3 | #----------------------------------------------------------------------------- | |
|
4 | # Copyright (C) 2010 The IPython Development Team | |
|
5 | # | |
|
6 | # Distributed under the terms of the BSD License. The full license is in | |
|
7 | # the file COPYING.txt, distributed as part of this software. | |
|
8 | #----------------------------------------------------------------------------- | |
|
9 | ||
|
10 | #----------------------------------------------------------------------------- | |
|
11 | # Imports | |
|
12 | #----------------------------------------------------------------------------- | |
|
13 | # stdlib | |
|
14 | import sys | |
|
15 | ||
|
16 | # Third-party | |
|
17 | import gobject | |
|
18 | import gtk | |
|
19 | ||
|
20 | #----------------------------------------------------------------------------- | |
|
21 | # Classes and functions | |
|
22 | #----------------------------------------------------------------------------- | |
|
23 | ||
|
24 | class GTKEmbed(object): | |
|
25 | """A class to embed a kernel into the GTK main event loop. | |
|
26 | """ | |
|
27 | def __init__(self, kernel): | |
|
28 | self.kernel = kernel | |
|
29 | # These two will later store the real gtk functions when we hijack them | |
|
30 | self.gtk_main = None | |
|
31 | self.gtk_main_quit = None | |
|
32 | ||
|
33 | def start(self): | |
|
34 | """Starts the GTK main event loop and sets our kernel startup routine. | |
|
35 | """ | |
|
36 | # Register our function to initiate the kernel and start gtk | |
|
37 | gobject.idle_add(self._wire_kernel) | |
|
38 | gtk.main() | |
|
39 | ||
|
40 | def _wire_kernel(self): | |
|
41 | """Initializes the kernel inside GTK. | |
|
42 | ||
|
43 | This is meant to run only once at startup, so it does its job and | |
|
44 | returns False to ensure it doesn't get run again by GTK. | |
|
45 | """ | |
|
46 | self.gtk_main, self.gtk_main_quit = self._hijack_gtk() | |
|
47 | gobject.timeout_add(int(1000*self.kernel._poll_interval), | |
|
48 | self.iterate_kernel) | |
|
49 | return False | |
|
50 | ||
|
51 | def iterate_kernel(self): | |
|
52 | """Run one iteration of the kernel and return True. | |
|
53 | ||
|
54 | GTK timer functions must return True to be called again, so we make the | |
|
55 | call to :meth:`do_one_iteration` and then return True for GTK. | |
|
56 | """ | |
|
57 | self.kernel.do_one_iteration() | |
|
58 | return True | |
|
59 | ||
|
60 | def stop(self): | |
|
61 | # FIXME: this one isn't getting called because we have no reliable | |
|
62 | # kernel shutdown. We need to fix that: once the kernel has a | |
|
63 | # shutdown mechanism, it can call this. | |
|
64 | self.gtk_main_quit() | |
|
65 | sys.exit() | |
|
66 | ||
|
67 | def _hijack_gtk(self): | |
|
68 | """Hijack a few key functions in GTK for IPython integration. | |
|
69 | ||
|
70 | Modifies pyGTK's main and main_quit with a dummy so user code does not | |
|
71 | block IPython. This allows us to use %run to run arbitrary pygtk | |
|
72 | scripts from a long-lived IPython session, and when they attempt to | |
|
73 | start or stop | |
|
74 | ||
|
75 | Returns | |
|
76 | ------- | |
|
77 | The original functions that have been hijacked: | |
|
78 | - gtk.main | |
|
79 | - gtk.main_quit | |
|
80 | """ | |
|
81 | def dummy(*args, **kw): | |
|
82 | pass | |
|
83 | # save and trap main and main_quit from gtk | |
|
84 | orig_main, gtk.main = gtk.main, dummy | |
|
85 | orig_main_quit, gtk.main_quit = gtk.main_quit, dummy | |
|
86 | return orig_main, orig_main_quit |
@@ -88,6 +88,8 class Kernel(Configurable): | |||
|
88 | 88 | self.handlers[msg_type] = getattr(self, msg_type) |
|
89 | 89 | |
|
90 | 90 | def do_one_iteration(self): |
|
91 | """Do one iteration of the kernel's evaluation loop. | |
|
92 | """ | |
|
91 | 93 | try: |
|
92 | 94 | ident = self.reply_socket.recv(zmq.NOBLOCK) |
|
93 | 95 | except zmq.ZMQError, e: |
@@ -373,7 +375,8 class WxKernel(Kernel): | |||
|
373 | 375 | import wx |
|
374 | 376 | from IPython.lib.guisupport import start_event_loop_wx |
|
375 | 377 | doi = self.do_one_iteration |
|
376 | _poll_interval = self._poll_interval | |
|
378 | # Wx uses milliseconds | |
|
379 | poll_interval = int(1000*self._poll_interval) | |
|
377 | 380 | |
|
378 | 381 | # We have to put the wx.Timer in a wx.Frame for it to fire properly. |
|
379 | 382 | # We make the Frame hidden when we create it in the main app below. |
@@ -382,9 +385,10 class WxKernel(Kernel): | |||
|
382 | 385 | wx.Frame.__init__(self, None, -1) |
|
383 | 386 | self.timer = wx.Timer(self) |
|
384 | 387 | # Units for the timer are in milliseconds |
|
385 |
self.timer.Start( |
|
|
388 | self.timer.Start(poll_interval) | |
|
386 | 389 | self.Bind(wx.EVT_TIMER, self.on_timer) |
|
387 | 390 | self.func = func |
|
391 | ||
|
388 | 392 | def on_timer(self, event): |
|
389 | 393 | self.func() |
|
390 | 394 | |
@@ -410,17 +414,19 class TkKernel(Kernel): | |||
|
410 | 414 | |
|
411 | 415 | import Tkinter |
|
412 | 416 | doi = self.do_one_iteration |
|
413 | ||
|
417 | # Tk uses milliseconds | |
|
418 | poll_interval = int(1000*self._poll_interval) | |
|
414 | 419 | # For Tkinter, we create a Tk object and call its withdraw method. |
|
415 | 420 | class Timer(object): |
|
416 | 421 | def __init__(self, func): |
|
417 | 422 | self.app = Tkinter.Tk() |
|
418 | 423 | self.app.withdraw() |
|
419 | 424 | self.func = func |
|
425 | ||
|
420 | 426 | def on_timer(self): |
|
421 | 427 | self.func() |
|
422 | # Units for the timer are in milliseconds | |
|
423 | self.app.after(1000*self._poll_interval, self.on_timer) | |
|
428 | self.app.after(poll_interval, self.on_timer) | |
|
429 | ||
|
424 | 430 | def start(self): |
|
425 | 431 | self.on_timer() # Call it once to get things going. |
|
426 | 432 | self.app.mainloop() |
@@ -428,13 +434,25 class TkKernel(Kernel): | |||
|
428 | 434 | self.timer = Timer(doi) |
|
429 | 435 | self.timer.start() |
|
430 | 436 | |
|
437 | ||
|
438 | class GTKKernel(Kernel): | |
|
439 | """A Kernel subclass with GTK support.""" | |
|
440 | ||
|
441 | def start(self): | |
|
442 | """Start the kernel, coordinating with the GTK event loop""" | |
|
443 | from .gui.gtkembed import GTKEmbed | |
|
444 | ||
|
445 | gtk_kernel = GTKEmbed(self) | |
|
446 | gtk_kernel.start() | |
|
447 | ||
|
448 | ||
|
431 | 449 | #----------------------------------------------------------------------------- |
|
432 | 450 | # Kernel main and launch functions |
|
433 | 451 | #----------------------------------------------------------------------------- |
|
434 | 452 | |
|
435 | 453 | def launch_kernel(xrep_port=0, pub_port=0, req_port=0, hb_port=0, |
|
436 | 454 | independent=False, pylab=False): |
|
437 |
""" |
|
|
455 | """Launches a localhost kernel, binding to the specified ports. | |
|
438 | 456 | |
|
439 | 457 | Parameters |
|
440 | 458 | ---------- |
@@ -490,19 +508,20 given, the GUI backend is matplotlib's, otherwise use one of: \ | |||
|
490 | 508 | |
|
491 | 509 | kernel_class = Kernel |
|
492 | 510 | |
|
493 |
|
|
|
511 | kernel_classes = { | |
|
494 | 512 | 'qt' : QtKernel, |
|
495 |
'qt4' |
|
|
513 | 'qt4': QtKernel, | |
|
496 | 514 | 'payload-svg': Kernel, |
|
497 | 515 | 'wx' : WxKernel, |
|
498 | 'tk' : TkKernel | |
|
516 | 'tk' : TkKernel, | |
|
517 | 'gtk': GTKKernel, | |
|
499 | 518 | } |
|
500 | 519 | if namespace.pylab: |
|
501 | 520 | if namespace.pylab == 'auto': |
|
502 | 521 | gui, backend = pylabtools.find_gui_and_backend() |
|
503 | 522 | else: |
|
504 | 523 | gui, backend = pylabtools.find_gui_and_backend(namespace.pylab) |
|
505 |
kernel_class = |
|
|
524 | kernel_class = kernel_classes.get(gui) | |
|
506 | 525 | if kernel_class is None: |
|
507 | 526 | raise ValueError('GUI is not supported: %r' % gui) |
|
508 | 527 | pylabtools.activate_matplotlib(backend) |
General Comments 0
You need to be logged in to leave comments.
Login now