From 17d0d1318ac26cf0a2b5b554af718688047d7f5b 2014-07-26 15:47:16 From: John Stowers Date: 2014-07-26 15:47:16 Subject: [PATCH] add gtk3 support to ipython kernel --- diff --git a/IPython/kernel/zmq/eventloops.py b/IPython/kernel/zmq/eventloops.py index 3e195a3..9609ca3 100644 --- a/IPython/kernel/zmq/eventloops.py +++ b/IPython/kernel/zmq/eventloops.py @@ -154,6 +154,14 @@ def loop_gtk(kernel): gtk_kernel.start() +def loop_gtk3(kernel): + """Start the kernel, coordinating with the GTK event loop""" + from .gui.gtk3embed import GTKEmbed + + gtk_kernel = GTKEmbed(kernel) + gtk_kernel.start() + + def loop_cocoa(kernel): """Start the kernel, coordinating with the Cocoa CFRunLoop event loop via the matplotlib MacOSX backend. @@ -233,6 +241,7 @@ loop_map = { 'wx' : loop_wx, 'tk' : loop_tk, 'gtk': loop_gtk, + 'gtk3': loop_gtk3, None : None, } diff --git a/IPython/kernel/zmq/gui/gtk3embed.py b/IPython/kernel/zmq/gui/gtk3embed.py new file mode 100644 index 0000000..8488550 --- /dev/null +++ b/IPython/kernel/zmq/gui/gtk3embed.py @@ -0,0 +1,85 @@ +"""GUI support for the IPython ZeroMQ kernel - GTK toolkit support. +""" +#----------------------------------------------------------------------------- +# Copyright (C) 2010-2011 The IPython Development Team +# +# 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 +from gi.repository import GObject, 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