As of 2020, the gbulb library appears to be unmaintained. Anyone wishing to integrate asyncio and GTK should only consider the second part of the answer (showing asyncio running in a dedicated thread) or take a look at asyncio-glib
, which integrates asyncio and GTK using an approach more minimalistic and robust than that taken by gbulb.
Original answer follows below.
The gbulb
library is designed to provide a connector between the asyncio event loop as specified by PEP 3156 and the GLib main loop implementation. However, the current master of gbulb
is broken for asyncio as shipped with Python 3.4. To fix this, you can check out this fork instead of the master. (The problem was later fixed upstream.)
With a working gbulb, it is trivial to modify your example to both accept incoming connections and run GTK:
#!/usr/bin/python3
import gi
gi.require_version("Gtk", "3.0")
import asyncio, gbulb
from gi.repository import Gtk
asyncio.set_event_loop_policy(gbulb.GLibEventLoopPolicy())
@asyncio.coroutine
def client_connected_handler(client_reader, client_writer):
print("Connection received!")
client_writer.write(b'Hello')
while True:
data = yield from client_reader.read(8192)
if not data:
break
if 'EXIT' in data.decode():
print("Closing server")
break
print(data)
client_writer.write(data)
print('Server is closed')
loop = asyncio.get_event_loop()
loop.run_until_complete(
asyncio.start_server(client_connected_handler, 'localhost', 2222))
w = Gtk.Window()
w.add(Gtk.Label('hey!'))
w.connect('destroy', Gtk.main_quit)
w.show_all()
loop.run_forever()
Another possibility is to run the asyncio event loop in a different thread:
#!/usr/bin/python3
import asyncio, threading
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk
async def client_connected_handler(client_reader, client_writer):
# ... unchanged ...
def run_asyncio():
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
loop.run_until_complete(
asyncio.start_server(client_connected_handler, 'localhost', 2222))
loop.run_forever()
threading.Thread(target=run_asyncio).start()
w = Gtk.Window()
w.add(Gtk.Label('hey!'))
w.connect('destroy', Gtk.main_quit)
w.show_all()
Gtk.main()
This has the advantage of not requiring gbulb
at all (it is not clear how well gbulb
has been tested in production). One does need to be careful, however, to use thread-safe functions to communicate between the GUI (main) thread and the asyncio thread. This means using loop.call_soon_threadsafe
or asyncio.run_coroutine_threadsafe
to submit things to asyncio from GTK, and GLib.idle_add
to submit things to GTK from asyncio.