Assembla home | Assembla project page
 

Writing qt applications with gobject.MainLoop?

GStreamer-0.10 uses asynchronous calls to control its pipelines, and these calls have async replies. You can get these replies by either polling the pipeline's bus, or by running a gobject.MainLoop?. Problems arise when you are writing a qt application that has its own main loop, and your application doesn't necessarily have multi-threaded requirements (besides those already implemented by gstreamer). The following class will run the gobject.MainLoop? whenever the QApplication is idle by using QTimer.start(0), and gobject.MainLoop?.MainContext?.pending/iteration.

The exception in the constructor protects the singleton-nature of gobject.MainLoop? for this application. Now you can just make your async calls from within the main qt thread. Fire away!

import sys
import time
import gobject
from PyQt4.QtCore import QObject, QTimer, SIGNAL, QThread, QEventLoop
from PyQt4.QtGui import QApplication


gobject.threads_init()

class GObjectLoop:
    """ Manages a gobject.MainLoop. """

    _instance = None

    def __init__(self):
        if not QGObjectLoop._instance is None:
            raise RuntimeError('there can only be one QGObjectLoop')
        else:
            QGObjectLoop._instance = self
        self.gmainloop = gobject.MainLoop()
        # this is horribly inefficient!
        self.gcontext = self.gmainloop.get_context()
        self.idletimer = QTimer(QApplication.instance())
        QObject.connect(self.idletimer, SIGNAL('timeout()'),
                        self.on_idle)
        self.idletimer.start(0)

    def __del__(self):
        self.gmainloop.quit()

    def on_idle(self):
        while self.gcontext.pending():
            self.gcontext.iteration()

# this prevents a seg fault, not sure why.
import atexit
def _atexit():
    GObjectLoop._instance = None
atexit.register(_atexit)

The only problem with this is that it is terribly (horribly) inefficient. In fact, your main thread is likely to hog all remaining CPU cycles! This is because qt will check the gobject main loop whenever it is idle, which is the same as saying your machine will run on_idle whenever it is idle. I ran into some threading problems with trying to run the qt and gobject loops in seperate threads, and decided that this was much easier. Good luck!