title: How can Twisted call Qt back?
body: <p>I am practicing PyQt+Twisted by writing a chat client. This requires getting the two event loops to play nice. I want to figure out how to do this without the Twisted QTReactor. The pattern I'm trying to achieve is</p>
  
  <ol>
  <li>Qt runs normally, Twisted runs in another thread (say a QThread).</li>
  <li>Qt functions/methods call Twisted functions with <code>callFromThread</code>.</li>
  <li>We hook up the deferreds given to us by Twisted so that they cause emission of Qt signals. In this way the Twisted thread can call back the Qt thread.</li>
  </ol>
  
  <p>I've actually gotten that part working. The heart of the solution is this function</p>
  
  <pre><code>def callFromMain(self, func, successSignal, *args):
      """Call an async I/O function with a Qt signal as it's callback
  
      func is the Twisted function you want to invoke. It probably returns a
      deferred. successSignal is the signal you want to emit once the asynchronous
      call finishes. This signal will be emitted with the result of func as an
      argument
      """
  
      def succeed(result):
          self.emit(successSignal, result)
  
      def wrapped():
          d = defer.maybeDeferred(func, *args)
          if successSignal is not None:
              d.addCallback(succeed)
  
      reactor.callFromThread(wrapped)
  </code></pre>
  
  <p>The problem is that I don't know what to do when I get "un-asked-for" data. For example, someone <em>else</em> might send out a chat message. I need to be able to detect the receipt of the data in the Twisted thread and somehow get that data into the Qt thread. This seems tricky because in this case I haven't provided the Twisted part of the program with a signal to use as a callback. How can I do that?</p>
  
  <p>Below please find complete example code to run my almost working chat client and server. To use these programs first copy the server and client as .py files and the ui specification as a .ui file. Run the server and then run the client. Once the client window is up, click the "connect" button. You should see a message on the server indicating a new connection. Then try typing into the line edit and clicking the "send" button. You'll see that the data makes it to the server and back, but that it doesn't show up in the client's QTextEdit box. This is because <strong>I can't figure out how to get the data from the ChatProtocol to the Qt part of the program.</strong> How can we do this?</p>
  
  <p><strong>SERVER (asyncore)</strong></p>
  
  <pre><code>import asyncore
  import socket
  import constants as C
  
  HOST = 'localhost'
  PORT = 12344
  
  class ChatServer(asyncore.dispatcher):
      """Receive and forward chat messages
  
      When a new connection is made we spawn a dispatcher for that
      connection.
      """
      ADDRESS_FAMILY = socket.AF_INET
      SOCKET_TYPE = socket.SOCK_STREAM
      def __init__(self, host, port):
          self.map = {}
          self.address = (host,port)
          self.clients = []
          asyncore.dispatcher.__init__(self, map=self.map)
  
      def serve(self):
          """Bind to socket and start asynchronous loop"""
          self.create_socket(self.ADDRESS_FAMILY, self.SOCKET_TYPE)
          self.bind(self.address)
          print("ChatServer bound to %s %s"%self.address)
          self.listen(1)
          asyncore.loop(map=self.map)
  
      def writable(self):
          return False
  
      def readable(self):
          return True
  
      def newMessage(self, data, fromWho):
          """Put data in all clients' buffers"""
          print("new data: %s"%data)
          for client in self.clients:
              client.buffer = client.buffer + data
  
      def handle_accept(self):
          """Deal with newly accepted connection"""
          (connSock, clientAddress) = self.accept()
          print("New connection accepted from %s %s"%clientAddress)
          self.clients.append(ChatHandler(connSock, self.map, self))
  
  class ChatHandler(asyncore.dispatcher):
      def __init__(self, sock, map, server):
          self.server = server
          self.buffer = ''
          asyncore.dispatcher.__init__(self, sock, map)
  
      def writable(self):
          return len(self.buffer) &gt; 0
  
      def readable(self):
          return True
  
      def handle_read(self):
          """Notify server of any new incoming data"""
          data = self.recv(4096)
          if data:
              self.server.newMessage(data, self)
  
      def handle_write(self):
          """send some amount of buffer"""
          sent = self.send(self.buffer)
          self.buffer = self.buffer[sent:]
  
  if __name__=='__main__':
      if HOST is None:
          HOST = raw_input('Host: ')
      if PORT is None:
          PORT = int(raw_input('Port: '))
      s = ChatServer(HOST, PORT)
      s.serve()
  </code></pre>
  
  <p><strong>CLIENT (PyQt + Twisted)</strong></p>
  
  <pre><code>import sys
  
  import PyQt4.QtGui as QtGui
  import PyQt4.QtCore as QtCore
  import PyQt4.uic as uic
  
  import twisted.internet.reactor as reactor
  import twisted.internet.defer as defer
  import twisted.internet.protocol as protocol
  
  class MainWindow(QtGui.QMainWindow):
      def __init__(self):
          QtGui.QMainWindow.__init__(self)
          self.ui = uic.loadUi('ui.ui')
          self.networkThread = NetworkThread()
          self.networkThread.start()
  
          self.ui.sendButton.clicked.connect(self.sendMessage)
          self.ui.connectButton.clicked.connect(self.getNetworkConnection)
          #Make connections from network thread signals to our slots
          self.connect(self.networkThread,
                       self.networkThread.sigConnected,
                       self.onConnected)
          self.connect(self.networkThread,
                       self.networkThread.sigNewData,
                       self.onNewData)
          self.ui.show()
  
      def getNetworkConnection(self):
          factory = protocol.ClientCreator(reactor, ChatProtocol)
          self.networkThread.callFromMain(factory.connectTCP,
                                          self.networkThread.sigConnected,
                                          'localhost', 12344)
  
      def onConnected(self, p):
          print("Got a protocol!")
          self.cxn = p
  
      def onNewData(self, data):
          self.ui.outputBox.append('\r\n'+data)
  
      def sendMessage(self):
          message = str(self.ui.inputBox.text())
          self.networkThread.callFromMain(self.cxn.send, None, message)
  
  class NetworkThread(QtCore.QThread):
      """Run the twisted reactor in its own thread"""
      def __init__(self):
          QtCore.QThread.__init__(self)
          self.sigConnected = QtCore.SIGNAL("sigConnected")
          self.sigNewData = QtCore.SIGNAL("sigNewData")
  
      def run(self):
          reactor.run(installSignalHandlers=0)
  
      def callFromMain(self, func, successSignal, *args):
          """Call an async I/O function with a Qt signal as it's callback"""
  
          def succeed(result):
              self.emit(successSignal, result)
  
          def wrapped():
              d = defer.maybeDeferred(func, *args)
              if successSignal is not None:
                  d.addCallback(succeed)
  
          reactor.callFromThread(wrapped)
  
  class ChatProtocol(protocol.Protocol):
      def dataReceived(self, data):
          print("Got data: %s"%data)
          print("...but I don't know how to pass it to Qt :(")
  
      def send(self, data):
          self.transport.write(data)
  
  class ChatFactory(protocol.ClientFactory):
      protocol = ChatProtocol
  
  if __name__ == '__main__':
      app = QtGui.QApplication(sys.argv)
      ex = MainWindow()
      sys.exit(app.exec_())
  </code></pre>
  
  <p><strong>UI file</strong></p>
  
  <pre><code>&lt;?xml version="1.0" encoding="UTF-8"?&gt;
  &lt;ui version="4.0"&gt;
   &lt;class&gt;MainWindow&lt;/class&gt;
   &lt;widget class="QMainWindow" name="MainWindow"&gt;
    &lt;property name="geometry"&gt;
     &lt;rect&gt;
      &lt;x&gt;0&lt;/x&gt;
      &lt;y&gt;0&lt;/y&gt;
      &lt;width&gt;800&lt;/width&gt;
      &lt;height&gt;600&lt;/height&gt;
     &lt;/rect&gt;
    &lt;/property&gt;
    &lt;property name="windowTitle"&gt;
     &lt;string&gt;MainWindow&lt;/string&gt;
    &lt;/property&gt;
    &lt;widget class="QWidget" name="centralwidget"&gt;
     &lt;layout class="QVBoxLayout" name="verticalLayout_2"&gt;
      &lt;item&gt;
       &lt;layout class="QVBoxLayout" name="verticalLayout"&gt;
        &lt;item&gt;
         &lt;widget class="QTextEdit" name="outputBox"/&gt;
        &lt;/item&gt;
        &lt;item&gt;
         &lt;widget class="QLineEdit" name="inputBox"/&gt;
        &lt;/item&gt;
        &lt;item&gt;
         &lt;layout class="QHBoxLayout" name="horizontalLayout"&gt;
          &lt;item&gt;
           &lt;widget class="QPushButton" name="sendButton"&gt;
            &lt;property name="text"&gt;
             &lt;string&gt;send&lt;/string&gt;
            &lt;/property&gt;
           &lt;/widget&gt;
          &lt;/item&gt;
          &lt;item&gt;
           &lt;spacer name="horizontalSpacer"&gt;
            &lt;property name="orientation"&gt;
             &lt;enum&gt;Qt::Horizontal&lt;/enum&gt;
            &lt;/property&gt;
            &lt;property name="sizeHint" stdset="0"&gt;
             &lt;size&gt;
              &lt;width&gt;40&lt;/width&gt;
              &lt;height&gt;20&lt;/height&gt;
             &lt;/size&gt;
            &lt;/property&gt;
           &lt;/spacer&gt;
          &lt;/item&gt;
          &lt;item&gt;
           &lt;widget class="QPushButton" name="connectButton"&gt;
            &lt;property name="text"&gt;
             &lt;string&gt;connect&lt;/string&gt;
            &lt;/property&gt;
           &lt;/widget&gt;
          &lt;/item&gt;
         &lt;/layout&gt;
        &lt;/item&gt;
       &lt;/layout&gt;
      &lt;/item&gt;
     &lt;/layout&gt;
    &lt;/widget&gt;
    &lt;widget class="QMenuBar" name="menubar"&gt;
     &lt;property name="geometry"&gt;
      &lt;rect&gt;
       &lt;x&gt;0&lt;/x&gt;
       &lt;y&gt;0&lt;/y&gt;
       &lt;width&gt;800&lt;/width&gt;
       &lt;height&gt;21&lt;/height&gt;
      &lt;/rect&gt;
     &lt;/property&gt;
    &lt;/widget&gt;
    &lt;widget class="QStatusBar" name="statusbar"/&gt;
   &lt;/widget&gt;
   &lt;resources/&gt;
   &lt;connections/&gt;
  &lt;/ui&gt;
  </code></pre>