gtkembed.py
86 lines
| 3.1 KiB
| text/x-python
|
PythonLexer
Fernando Perez
|
r2949 | """GUI support for the IPython ZeroMQ kernel - GTK toolkit support. | ||
""" | ||||
#----------------------------------------------------------------------------- | ||||
Matthias BUSSONNIER
|
r5390 | # Copyright (C) 2010-2011 The IPython Development Team | ||
Fernando Perez
|
r2949 | # | ||
# Distributed under the terms of the BSD License. The full license is in | ||||
# the file COPYING.txt, distributed as part of this software. | ||||
#----------------------------------------------------------------------------- | ||||
#----------------------------------------------------------------------------- | ||||
# Imports | ||||
#----------------------------------------------------------------------------- | ||||
# stdlib | ||||
import sys | ||||
# Third-party | ||||
import gobject | ||||
import gtk | ||||
#----------------------------------------------------------------------------- | ||||
# Classes and functions | ||||
#----------------------------------------------------------------------------- | ||||
class GTKEmbed(object): | ||||
"""A class to embed a kernel into the GTK main event loop. | ||||
""" | ||||
def __init__(self, kernel): | ||||
self.kernel = kernel | ||||
# These two will later store the real gtk functions when we hijack them | ||||
self.gtk_main = None | ||||
self.gtk_main_quit = None | ||||
def start(self): | ||||
"""Starts the GTK main event loop and sets our kernel startup routine. | ||||
""" | ||||
# Register our function to initiate the kernel and start gtk | ||||
gobject.idle_add(self._wire_kernel) | ||||
gtk.main() | ||||
def _wire_kernel(self): | ||||
"""Initializes the kernel inside GTK. | ||||
This is meant to run only once at startup, so it does its job and | ||||
returns False to ensure it doesn't get run again by GTK. | ||||
""" | ||||
self.gtk_main, self.gtk_main_quit = self._hijack_gtk() | ||||
gobject.timeout_add(int(1000*self.kernel._poll_interval), | ||||
self.iterate_kernel) | ||||
return False | ||||
def iterate_kernel(self): | ||||
"""Run one iteration of the kernel and return True. | ||||
GTK timer functions must return True to be called again, so we make the | ||||
call to :meth:`do_one_iteration` and then return True for GTK. | ||||
""" | ||||
self.kernel.do_one_iteration() | ||||
return True | ||||
def stop(self): | ||||
# FIXME: this one isn't getting called because we have no reliable | ||||
# kernel shutdown. We need to fix that: once the kernel has a | ||||
# shutdown mechanism, it can call this. | ||||
self.gtk_main_quit() | ||||
sys.exit() | ||||
def _hijack_gtk(self): | ||||
"""Hijack a few key functions in GTK for IPython integration. | ||||
Modifies pyGTK's main and main_quit with a dummy so user code does not | ||||
block IPython. This allows us to use %run to run arbitrary pygtk | ||||
scripts from a long-lived IPython session, and when they attempt to | ||||
start or stop | ||||
Returns | ||||
------- | ||||
The original functions that have been hijacked: | ||||
- gtk.main | ||||
- gtk.main_quit | ||||
""" | ||||
def dummy(*args, **kw): | ||||
pass | ||||
# save and trap main and main_quit from gtk | ||||
orig_main, gtk.main = gtk.main, dummy | ||||
orig_main_quit, gtk.main_quit = gtk.main_quit, dummy | ||||
return orig_main, orig_main_quit | ||||