Revisit of EventLoop; Proposed re-use of Client source-code
Revisit of EventLoop
6/6/2008 Notes
from Clint: "For the re-use of client source... what if we just move most of it into pqComponents? just leave the main() in Applications/Client ? I think that's similar to the main() of pvserver, pvdataserver and pvrenderserver are created."
from Utkarsh: "I just have one minor thing to highlight: currently pqMain creates the pqOptions instance. Is that acceptable? It means that you'll be stuck with only those command line arguments that ParaView client provides. Since one can provide their own process module GUI helper implementation, it can be possible to process some new command line options in there."
Proposed re-use of Client source-code
This page is a follow up to the Event Loop and "Reverse" plugin ideas described in http://www.paraview.org/ParaView3/index.php/OverView_Plugins, and proposes to re-use the source in ParaView3/Applications/Client.
EventLoop
Dimensionality Vis
Our situation: a customer at Sandia who does optimization and dimensionality reduction, wants to launch ParaView from his vis application, called raptor. One application area of this work is to try to better understand why nature folds protein molecules in particular ways.
Raptor is C++, uses Qt, with some VTK displayed in a QVTKWidget. Most of the time the VTK visualization is not very heavy; we mainly use it for some selection tasks. Periodically we want to run ParaView and load data when the visualization does get more complex. The datasets we generate are not real big, so we have not been using client-server mode. We do still want to be able to use the various VTK filters and the existing client-side GUI of ParaView.
Our proposal is to modify the way ParaView runs in pqMain and pqProcessModuleGUIHelp, to support eventloop-controlling applications such as raptor.
Here’s an itemized list of desirements for raptor, in the context of ParaView:
- Create VTK objects in memory in raptor and have ParaView read and display them;
- i.e. run ParaView in-process, and control the Qt Event loop by calling QcoreApplication::exec();
- show or hide the ParaView main GUI from raptor;
- Want existing ParaView client GUI;
- Benefit from updates to ParaView client GUI source code;
- Not visualizing large datasets at this time, i.e. do not need parallel client-server;
- If possible, re-use code in: ParaView3/Applications/Client.
This list simply states that we want raptor to take advantage of ParaView’s visualization abilities, and tightly integrate the applications so that they behave as one and the same. We want raptor to gracefully bring ParaView into and out of context.
Experiments in controlling the event loop
To satisfy the requirements of running in-process, being the invoker of ::exec(), and show/hide the GUI, these two classes were modified:
ParaView3/Qt/Core/ pqProcessModuleGUIHelper pqMain
The changes made were to add preRun(), Run(), and postRun(), and preAppExec(), appExec(), and postAppExec() methods to pqMain and pqProcessModuleGUIHelper, respectively, so that all the code before and after QcoreApplication::exec() could be called, and then exec() overridden by the non-paraview application by overriding pqProcessModuleGUIHelper::appExec().
The interface changes for pqProcessModuleGUIHelper and pqMain:
pqProcessModuleGUIHelper
. . . /// preAppExec does everything up to appExec() virtual int preAppExec(int argc, char** argv, int numServerProcs, int myId); /// appExec executes the QApplication::exec virtual int appExec(); /// postAppExec does everything after the appExec virtual int postAppExec(); . . .
pqMain
. . . public: /// Call pqMain::preRun() in your client's main(), returning the result static int preRun(QApplication& app, pqProcessModuleGUIHelper* helper, pqOptions * & options); /// Call pqMain::Run() in your client's main(), returning the result. /// this overloaded method is intended to be run stand-alone, i.e. without running /// preRun(...) nor postRun(...) static int Run(QApplication& app, pqProcessModuleGUIHelper* helper); /// Call pqMain::Run() in your client's main(), returning the result. This overload of Run is intended /// to be run after preRun(...) static int Run(pqOptions * options); /// call pqMain::postRun() for cleanup - this calls Delete() on pvmain, options, and helper members static void postRun(); . . .
Re-use of Client source
Experiments in GUI Re-use
To satisfy the requirements of re-using the ParaView Client GUI, these classes were modified,
ParaView3/Applications/Client/ ProcessModuleGUIHelper
and a new library was added called pqClientLib that encapsulates most of the functionality from ParaView3/Applications/Client, and a new project called paraview_client was created for the main() and to inherit and specialize some code from ProcessModuleGUIHelper. In theory paraview_client could replace the existing paraview (ParaView3/Applications/Client) project.
I know there have been some discussions regarding the minimally sufficient code to write for a paraview application. My argument to encapsulate the client into a library, with perhaps some mechanism to override certain behaviour (e.g. Tim Shead cited “Quit” from the main menu, which would imply some way to override pqApplicationCore::quit()), is that myself, or anybody else with my requirements, really does not want to be forced to understand what to keep or throw away in ParaView3/Applications/Client/MainWindow.[h|cxx]. Also, if other ParaView developers (e.g. Clint, Utkarsh, Mark, etc.) make important changes to the client I would want to automatically get the new functionality without having to discover it by looking at differences between my version of MainWindow and the one checked into ParaView.
Using the changes described above to pqProcessModuleGUIHelper and pqMain, the main for paraview now looks like this:
int main(int argc, char* argv[]) { QApplication app(argc, argv); #ifdef Q_WS_X11 // Using motif style gives us test failures (and its ugly). // Using cleanlooks style gives us errors when using valgrind (Trolltech's bug #179200) // let's just use plastique for now QApplication::setStyle(new QPlastiqueStyle); #endif pqComponentsInit(); QDir dir(QApplication::applicationDirPath()); dir.cdUp(); dir.cd("Plugins"); QApplication::setLibraryPaths(QStringList(dir.absolutePath())); my_ProcessModuleGUIHelper * mypmgh = my_ProcessModuleGUIHelper::New(); pqOptions * options; int status = pqMain::preRun(app, mypmgh, options); if (! status) { status = pqMain::Run(options); if (! status) { status = app.exec(); } else { return status; } } else { return status; } status = mypmgh->postAppExec(); if (! status) { pqMain::postRun(); } return status; }
Note: The current main.cxx in ParaView3/Applications/Client should continue to compile as is.
Ken had concerns about modifications that I’ve described would impact other applications, like DobranoViz, OverView, or others. I don’t think these clients would be affected very much by this effort, but other people besides me probably know better. -Jon