Anatomy of ParaView
-------------------

In order to use SMTK within ParaView, it is important to understand
some of ParaView's design.
A core premise of ParaView is that the user interface will frequently
be a separate process from rendering and I/O tasks, as these must be
run in a distributed-memory parallel environment.
Thus, ParaView has a client process and 1 or more server processes.
Even when running in serial (i.e., non-parallel) mode, ParaView makes a
distinction between tasks run on the client and the server(s).

ParaView's design has the client create and manage objects on the server.
Nearly all objects on the server are subclasses of vtkObject and thus can
be managed using wrappings created by VTK (similar to Python wrappers).
These wrappers are called client-server wrappers and allow ParaView to
serialize, deserialize, and remotely invoke methods on server-side objects.

Nearly all objects on the server have a matching instance on each server process.
For example, if the client creates a file-reader and an actor to display data from the file,
it will instruct each server to create a reader and an actor; and have each server attach the
reader and actor — even though some of the servers' readers may not have data for that
actor to display because the data is unevenly distributed.

This pattern simplifies the work the client must do,
however it also means that server-side objects should rarely (if ever)

#. send signals to the client or
#. perform blocking operations based on their local data;

the reason for
this is that,

#. if every server process sent a signal when an action was performed, a large
   number of servers would quickly overwhelm the client and
#. since each server process holds a different portion of the data,
   not every server process would block at the same time which can lead to deadlocks
   and race conditions.

So, although there are infrequent exceptions,
be aware that ParaView takes great care to initiate all actions on the client,
even when it seems that the server should do so.

Integration with SMTK
---------------------

In ParaView, there are 3 types of objects that SMTK frequently interacts with:

* Subclasses of vtkObject which live on each server process and are "wrapped"
  by C++ code that allows remote invocation of their methods across the
  client-server (CS) connection each server maintains with either the rank-0
  server or the client.
  Several SMTK classes have instances owned by a "wrapper" class that inherits
  from vtkObject to make this communication possible.
* Subclasses of vtkSMProxy, which live on the client process.
  Subclasses specific to SMTK are only required when the client needs to expose
  methods to manage SMTK data on the server that cannot be handled by
  ParaView's client-server wrapping. For example, methods that take non-primitive
  objects, such as pointers to SMTK classes as input, since these methods
  cannot be CS-wrapped.
* Subclasses of pqProxy, which live on the client process and reference
  an instance of vtkSMKProxy (or its subclasses).
  Subclasses specific to SMTK exist to expose Qt signals and slots related to
  SMTK. If Qt is not required, then you should subclass vtkSMProxy instead.

Inside the ``smtk/extension/paraview`` directory, the top-level of directories
hold code placed in VTK modules (thus they have a ``vtk.module`` file).
In directories with VTK modules, some subdirectories hold ParaView plugins
(thus they have ``paraview.plugin`` files).
VTK modules are libraries that export symbols; other libraries may depend on
them and import their symbols.
ParaView plugins may be *implemented* as libraries, but they do not expose
symbols and on some platforms cannot be linked to.
Therefore, whatever classes might be reused or referenced by other plugins
should be placed in a VTK module; the ParaView plugins exist only to expose
functionality from VTK modules in ParaView.
