##// END OF EJS Templates
Backport PR #2294: inputhook_qt4: Use QEventLoop instead of starting up the QCoreApplication...
Backport PR #2294: inputhook_qt4: Use QEventLoop instead of starting up the QCoreApplication I referenced this branch in #2080 and was letting it sit for a little while, but I have decided to make it a full pull request to get some additional visibility. Essentially our Qt event loop mechanism repeatedly starts and quits a `QCoreApplication` object. Unfortunately the `QCoreApplication::quit` slot has a lot of unintended side effects (like emitting an `aboutToQuit` signal which closes all open file dialogs). For our input hook, we _might_ be able to get by with just using a `QEventLoop` whose quit slot is much simpler and less destructive. For a little bit of background on why one might want to just use `QEventLoop::exec`, let's examine what `QCoreApplication::exec` does: ```c++ int QCoreApplication::exec() { if (!QCoreApplicationPrivate::checkInstance("exec")) return -1; // ... [some assertions] threadData->quitNow = false; QEventLoop eventLoop; self->d_func()->in_exec = true; self->d_func()->aboutToQuitEmitted = false; int returnCode = eventLoop.exec(); threadData->quitNow = false; if (self) { self->d_func()->in_exec = false; if (!self->d_func()->aboutToQuitEmitted) emit self->aboutToQuit(); self->d_func()->aboutToQuitEmitted = true; sendPostedEvents(0, QEvent::DeferredDelete); } return returnCode; } ``` As far as I can tell, it's a small wrapper around `QEventLoop::exec` which also: * Sets some variables regarding the current status * Emits an `aboutToQuit` signal right before the function returns (which is the root cause of @denisri's problem in #2080). Historically, our Qt event loop is a python implementation of the (win 32) input hook supplied with the PyQt4 source (see qtcore_input_hook` in `python-qt4/sip/QtCore/qcoreapplication.sip`), which more or less dates to a [mailing list post](http://www.riverbankcomputing.com/pipermail/pyqt/2007-July/016512.html) from July 2007.

File last commit:

r5807:3ba61c59
r9834:71196839
Show More
asyncfrontendbase.py
82 lines | 2.7 KiB | text/x-python | PythonLexer
Gael Varoquaux
Split the frontend base class in different files and add a base class...
r1355 """
Base front end class for all async frontends.
"""
__docformat__ = "restructuredtext en"
Fernando Perez
Fixes so the test suite runs when Twisted is not available....
r2133 # Tell nose to skip this module
__test__ = {}
Gael Varoquaux
Split the frontend base class in different files and add a base class...
r1355 #-------------------------------------------------------------------------------
Matthias BUSSONNIER
update copyright to 2011/20xx-2011...
r5390 # Copyright (C) 2008-2011 The IPython Development Team
Gael Varoquaux
Split the frontend base class in different files and add a base class...
r1355 #
# Distributed under the terms of the BSD License. The full license is in
# the file COPYING, distributed as part of this software.
#-------------------------------------------------------------------------------
#-------------------------------------------------------------------------------
# Imports
#-------------------------------------------------------------------------------
Fernando Perez
Fixes so the test suite runs when Twisted is not available....
r2133 # Third-party
from twisted.python.failure import Failure
from zope.interface import implements, classProvides
# From IPython
from IPython.frontend.frontendbase import (FrontEndBase, IFrontEnd,
IFrontEndFactory)
Gael Varoquaux
Split the frontend base class in different files and add a base class...
r1355 from IPython.kernel.core.history import FrontEndHistory
Brian Granger
Fixed another bug related to missing dependencies in tests.
r1558 from IPython.kernel.engineservice import IEngineCore
Gael Varoquaux
Split the frontend base class in different files and add a base class...
r1355
Thomas Spura
Delete all references to old IPython.external.guid...
r5807 import uuid
Fernando Perez
Fixes so the test suite runs when Twisted is not available....
r2133 #-----------------------------------------------------------------------------
# Classes and functions
#-----------------------------------------------------------------------------
Gael Varoquaux
Split the frontend base class in different files and add a base class...
r1355
class AsyncFrontEndBase(FrontEndBase):
"""
Overrides FrontEndBase to wrap execute in a deferred result.
All callbacks are made as callbacks on the deferred result.
"""
Bernardo B. Marques
remove all trailling spaces
r4872
Gael Varoquaux
Split the frontend base class in different files and add a base class...
r1355 implements(IFrontEnd)
classProvides(IFrontEndFactory)
Bernardo B. Marques
remove all trailling spaces
r4872
Gael Varoquaux
Split the frontend base class in different files and add a base class...
r1355 def __init__(self, engine=None, history=None):
assert(engine==None or IEngineCore.providedBy(engine))
self.engine = IEngineCore(engine)
if history is None:
self.history = FrontEndHistory(input_cache=[''])
else:
self.history = history
Bernardo B. Marques
remove all trailling spaces
r4872
Gael Varoquaux
Split the frontend base class in different files and add a base class...
r1355 def execute(self, block, blockID=None):
"""Execute the block and return the deferred result.
Bernardo B. Marques
remove all trailling spaces
r4872
Gael Varoquaux
Split the frontend base class in different files and add a base class...
r1355 Parameters:
block : {str, AST}
blockID : any
Bernardo B. Marques
remove all trailling spaces
r4872 Caller may provide an ID to identify this block.
Gael Varoquaux
Split the frontend base class in different files and add a base class...
r1355 result['blockID'] := blockID
Bernardo B. Marques
remove all trailling spaces
r4872
Gael Varoquaux
Split the frontend base class in different files and add a base class...
r1355 Result:
Deferred result of self.interpreter.execute
"""
Bernardo B. Marques
remove all trailling spaces
r4872
Gael Varoquaux
Split the frontend base class in different files and add a base class...
r1355 if(not self.is_complete(block)):
return Failure(Exception("Block is not compilable"))
Bernardo B. Marques
remove all trailling spaces
r4872
Gael Varoquaux
Split the frontend base class in different files and add a base class...
r1355 if(blockID == None):
Thomas Spura
Delete all references to old IPython.external.guid...
r5807 blockID = uuid.uuid4()
Bernardo B. Marques
remove all trailling spaces
r4872
Gael Varoquaux
Split the frontend base class in different files and add a base class...
r1355 d = self.engine.execute(block)
d.addCallback(self._add_history, block=block)
d.addCallbacks(self._add_block_id_for_result,
errback=self._add_block_id_for_failure,
callbackArgs=(blockID,),
errbackArgs=(blockID,))
d.addBoth(self.update_cell_prompt, blockID=blockID)
Bernardo B. Marques
remove all trailling spaces
r4872 d.addCallbacks(self.render_result,
Gael Varoquaux
Split the frontend base class in different files and add a base class...
r1355 errback=self.render_error)
Bernardo B. Marques
remove all trailling spaces
r4872
Gael Varoquaux
Split the frontend base class in different files and add a base class...
r1355 return d