Show More
@@ -170,10 +170,13 b' class TerminalInteractiveShell(InteractiveShell):' | |||
|
170 | 170 | help="Enable auto setting the terminal title." |
|
171 | 171 | ) |
|
172 | 172 | |
|
173 | def __init__(self, config=None, ipython_dir=None, profile_dir=None, user_ns=None, | |
|
174 | user_module=None, custom_exceptions=((),None), | |
|
175 | usage=None, banner1=None, banner2=None, | |
|
176 | display_banner=None): | |
|
173 | # In the terminal, GUI control is done via PyOS_InputHook | |
|
174 | from IPython.lib.inputhook import enable_gui | |
|
175 | enable_gui = staticmethod(enable_gui) | |
|
176 | ||
|
177 | def __init__(self, config=None, ipython_dir=None, profile_dir=None, | |
|
178 | user_ns=None, user_module=None, custom_exceptions=((),None), | |
|
179 | usage=None, banner1=None, banner2=None, display_banner=None): | |
|
177 | 180 | |
|
178 | 181 | super(TerminalInteractiveShell, self).__init__( |
|
179 | 182 | config=config, profile_dir=profile_dir, user_ns=user_ns, |
@@ -516,14 +519,6 b' class TerminalInteractiveShell(InteractiveShell):' | |||
|
516 | 519 | return True |
|
517 | 520 | |
|
518 | 521 | #------------------------------------------------------------------------- |
|
519 | # Things related to GUI support and pylab | |
|
520 | #------------------------------------------------------------------------- | |
|
521 | ||
|
522 | def enable_gui(self, gui=None): | |
|
523 | from IPython.lib.inputhook import enable_gui | |
|
524 | enable_gui(gui) | |
|
525 | ||
|
526 | #------------------------------------------------------------------------- | |
|
527 | 522 | # Things related to exiting |
|
528 | 523 | #------------------------------------------------------------------------- |
|
529 | 524 |
@@ -510,190 +510,6 b' class Kernel(Configurable):' | |||
|
510 | 510 | # before Python truly shuts down. |
|
511 | 511 | time.sleep(0.01) |
|
512 | 512 | |
|
513 | ||
|
514 | #------------------------------------------------------------------------------ | |
|
515 | # Eventloops for integrating the Kernel into different GUIs | |
|
516 | #------------------------------------------------------------------------------ | |
|
517 | ||
|
518 | ||
|
519 | def loop_qt4(kernel): | |
|
520 | """Start a kernel with PyQt4 event loop integration.""" | |
|
521 | ||
|
522 | from IPython.external.qt_for_kernel import QtCore | |
|
523 | from IPython.lib.guisupport import get_app_qt4, start_event_loop_qt4 | |
|
524 | ||
|
525 | kernel.app = get_app_qt4([" "]) | |
|
526 | kernel.app.setQuitOnLastWindowClosed(False) | |
|
527 | kernel.timer = QtCore.QTimer() | |
|
528 | kernel.timer.timeout.connect(kernel.do_one_iteration) | |
|
529 | # Units for the timer are in milliseconds | |
|
530 | kernel.timer.start(1000*kernel._poll_interval) | |
|
531 | start_event_loop_qt4(kernel.app) | |
|
532 | ||
|
533 | ||
|
534 | def loop_wx(kernel): | |
|
535 | """Start a kernel with wx event loop support.""" | |
|
536 | ||
|
537 | import wx | |
|
538 | from IPython.lib.guisupport import start_event_loop_wx | |
|
539 | ||
|
540 | doi = kernel.do_one_iteration | |
|
541 | # Wx uses milliseconds | |
|
542 | poll_interval = int(1000*kernel._poll_interval) | |
|
543 | ||
|
544 | # We have to put the wx.Timer in a wx.Frame for it to fire properly. | |
|
545 | # We make the Frame hidden when we create it in the main app below. | |
|
546 | class TimerFrame(wx.Frame): | |
|
547 | def __init__(self, func): | |
|
548 | wx.Frame.__init__(self, None, -1) | |
|
549 | self.timer = wx.Timer(self) | |
|
550 | # Units for the timer are in milliseconds | |
|
551 | self.timer.Start(poll_interval) | |
|
552 | self.Bind(wx.EVT_TIMER, self.on_timer) | |
|
553 | self.func = func | |
|
554 | ||
|
555 | def on_timer(self, event): | |
|
556 | self.func() | |
|
557 | ||
|
558 | # We need a custom wx.App to create our Frame subclass that has the | |
|
559 | # wx.Timer to drive the ZMQ event loop. | |
|
560 | class IPWxApp(wx.App): | |
|
561 | def OnInit(self): | |
|
562 | self.frame = TimerFrame(doi) | |
|
563 | self.frame.Show(False) | |
|
564 | return True | |
|
565 | ||
|
566 | # The redirect=False here makes sure that wx doesn't replace | |
|
567 | # sys.stdout/stderr with its own classes. | |
|
568 | kernel.app = IPWxApp(redirect=False) | |
|
569 | start_event_loop_wx(kernel.app) | |
|
570 | ||
|
571 | ||
|
572 | def loop_tk(kernel): | |
|
573 | """Start a kernel with the Tk event loop.""" | |
|
574 | ||
|
575 | import Tkinter | |
|
576 | doi = kernel.do_one_iteration | |
|
577 | # Tk uses milliseconds | |
|
578 | poll_interval = int(1000*kernel._poll_interval) | |
|
579 | # For Tkinter, we create a Tk object and call its withdraw method. | |
|
580 | class Timer(object): | |
|
581 | def __init__(self, func): | |
|
582 | self.app = Tkinter.Tk() | |
|
583 | self.app.withdraw() | |
|
584 | self.func = func | |
|
585 | ||
|
586 | def on_timer(self): | |
|
587 | self.func() | |
|
588 | self.app.after(poll_interval, self.on_timer) | |
|
589 | ||
|
590 | def start(self): | |
|
591 | self.on_timer() # Call it once to get things going. | |
|
592 | self.app.mainloop() | |
|
593 | ||
|
594 | kernel.timer = Timer(doi) | |
|
595 | kernel.timer.start() | |
|
596 | ||
|
597 | ||
|
598 | def loop_gtk(kernel): | |
|
599 | """Start the kernel, coordinating with the GTK event loop""" | |
|
600 | from .gui.gtkembed import GTKEmbed | |
|
601 | ||
|
602 | gtk_kernel = GTKEmbed(kernel) | |
|
603 | gtk_kernel.start() | |
|
604 | ||
|
605 | ||
|
606 | def loop_cocoa(kernel): | |
|
607 | """Start the kernel, coordinating with the Cocoa CFRunLoop event loop | |
|
608 | via the matplotlib MacOSX backend. | |
|
609 | """ | |
|
610 | import matplotlib | |
|
611 | if matplotlib.__version__ < '1.1.0': | |
|
612 | kernel.log.warn( | |
|
613 | "MacOSX backend in matplotlib %s doesn't have a Timer, " | |
|
614 | "falling back on Tk for CFRunLoop integration. Note that " | |
|
615 | "even this won't work if Tk is linked against X11 instead of " | |
|
616 | "Cocoa (e.g. EPD). To use the MacOSX backend in the kernel, " | |
|
617 | "you must use matplotlib >= 1.1.0, or a native libtk." | |
|
618 | ) | |
|
619 | return loop_tk(kernel) | |
|
620 | ||
|
621 | from matplotlib.backends.backend_macosx import TimerMac, show | |
|
622 | ||
|
623 | # scale interval for sec->ms | |
|
624 | poll_interval = int(1000*kernel._poll_interval) | |
|
625 | ||
|
626 | real_excepthook = sys.excepthook | |
|
627 | def handle_int(etype, value, tb): | |
|
628 | """don't let KeyboardInterrupts look like crashes""" | |
|
629 | if etype is KeyboardInterrupt: | |
|
630 | io.raw_print("KeyboardInterrupt caught in CFRunLoop") | |
|
631 | else: | |
|
632 | real_excepthook(etype, value, tb) | |
|
633 | ||
|
634 | # add doi() as a Timer to the CFRunLoop | |
|
635 | def doi(): | |
|
636 | # restore excepthook during IPython code | |
|
637 | sys.excepthook = real_excepthook | |
|
638 | kernel.do_one_iteration() | |
|
639 | # and back: | |
|
640 | sys.excepthook = handle_int | |
|
641 | ||
|
642 | t = TimerMac(poll_interval) | |
|
643 | t.add_callback(doi) | |
|
644 | t.start() | |
|
645 | ||
|
646 | # but still need a Poller for when there are no active windows, | |
|
647 | # during which time mainloop() returns immediately | |
|
648 | poller = zmq.Poller() | |
|
649 | poller.register(kernel.shell_socket, zmq.POLLIN) | |
|
650 | ||
|
651 | while True: | |
|
652 | try: | |
|
653 | # double nested try/except, to properly catch KeyboardInterrupt | |
|
654 | # due to pyzmq Issue #130 | |
|
655 | try: | |
|
656 | # don't let interrupts during mainloop invoke crash_handler: | |
|
657 | sys.excepthook = handle_int | |
|
658 | show.mainloop() | |
|
659 | sys.excepthook = real_excepthook | |
|
660 | # use poller if mainloop returned (no windows) | |
|
661 | # scale by extra factor of 10, since it's a real poll | |
|
662 | poller.poll(10*poll_interval) | |
|
663 | kernel.do_one_iteration() | |
|
664 | except: | |
|
665 | raise | |
|
666 | except KeyboardInterrupt: | |
|
667 | # Ctrl-C shouldn't crash the kernel | |
|
668 | io.raw_print("KeyboardInterrupt caught in kernel") | |
|
669 | finally: | |
|
670 | # ensure excepthook is restored | |
|
671 | sys.excepthook = real_excepthook | |
|
672 | ||
|
673 | # mapping of keys to loop functions | |
|
674 | loop_map = { | |
|
675 | 'qt' : loop_qt4, | |
|
676 | 'qt4': loop_qt4, | |
|
677 | 'inline': None, | |
|
678 | 'osx': loop_cocoa, | |
|
679 | 'wx' : loop_wx, | |
|
680 | 'tk' : loop_tk, | |
|
681 | 'gtk': loop_gtk, | |
|
682 | None : None, | |
|
683 | } | |
|
684 | ||
|
685 | def enable_gui(gui, kernel=None): | |
|
686 | """Enable integration with a given GUI""" | |
|
687 | if kernel is None: | |
|
688 | kernel = IPKernelApp.instance().kernel | |
|
689 | if gui not in loop_map: | |
|
690 | raise ValueError("GUI %r not supported" % gui) | |
|
691 | loop = loop_map[gui] | |
|
692 | if kernel.eventloop is not None and kernel.eventloop is not loop: | |
|
693 | raise RuntimeError("Cannot activate multiple GUI eventloops") | |
|
694 | kernel.eventloop = loop | |
|
695 | ||
|
696 | ||
|
697 | 513 | #----------------------------------------------------------------------------- |
|
698 | 514 | # Aliases and Flags for the IPKernelApp |
|
699 | 515 | #----------------------------------------------------------------------------- |
@@ -109,6 +109,11 b' class ZMQInteractiveShell(InteractiveShell):' | |||
|
109 | 109 | |
|
110 | 110 | keepkernel_on_exit = None |
|
111 | 111 | |
|
112 | # Over ZeroMQ, GUI control isn't done with PyOS_InputHook as there is no | |
|
113 | # interactive input being read; we provide event loop support in ipkernel | |
|
114 | from .eventloops import enable_gui | |
|
115 | enable_gui = staticmethod(enable_gui) | |
|
116 | ||
|
112 | 117 | def init_environment(self): |
|
113 | 118 | """Configure the user's environment. |
|
114 | 119 | |
@@ -390,10 +395,6 b' class ZMQInteractiveShell(InteractiveShell):' | |||
|
390 | 395 | } |
|
391 | 396 | self.payload_manager.write_payload(payload) |
|
392 | 397 | |
|
393 | def enable_gui(self, gui=None): | |
|
394 | from IPython.zmq.ipkernel import enable_gui | |
|
395 | enable_gui(gui) | |
|
396 | ||
|
397 | 398 | # A few magics that are adapted to the specifics of using pexpect and a |
|
398 | 399 | # remote terminal |
|
399 | 400 |
General Comments 0
You need to be logged in to leave comments.
Login now