From f1c6102a981b8a41dafe586cfd08722fa046fe74 Mon Sep 17 00:00:00 2001
From: Christophe Geuzaine <cgeuzaine@ulg.ac.be>
Date: Thu, 1 Oct 2009 07:37:44 +0000
Subject: [PATCH] finished up first pass at remote view management:

* interactive stuff is now almost feature-complete (including
  multi-step, axes and adaptive refinement)

* plugins can now be executed on remote views

* renamed GmshRemote->ConnectionManager & GmshDaemon->GmshRemote
---
 Common/CMakeLists.txt        |   4 +-
 Common/ConnectionManager.cpp | 105 +++++++++++++++++++++
 Common/ConnectionManager.h   | 107 +++++++++++++++++++++
 Common/Gmsh.cpp              |   4 +-
 Common/GmshDaemon.cpp        | 111 ----------------------
 Common/GmshDaemon.h          |  14 ---
 Common/GmshRemote.cpp        | 178 ++++++++++++++++++-----------------
 Common/GmshRemote.h          |  97 +------------------
 Common/Main.cpp              |   1 +
 Common/Options.cpp           | 132 +++++++++++++-------------
 Common/VertexArray.cpp       |  17 +++-
 Common/VertexArray.h         |   4 +-
 Fltk/Main.cpp                |   4 +-
 Fltk/extraDialogs.cpp        |  38 +++++---
 Fltk/menuWindow.cpp          |  22 ++---
 Fltk/optionWindow.cpp        |   6 +-
 Fltk/pluginWindow.cpp        |   9 +-
 Fltk/solverWindow.cpp        |  56 +++++------
 Graphics/gl2ps.cpp           |  26 +----
 Graphics/gl2ps.h             |   6 +-
 Plugin/Plugin.cpp            |  33 +++++++
 Plugin/Plugin.h              |   2 +
 Post/PView.cpp               |   2 +-
 Post/PView.h                 |   5 +-
 Post/PViewData.h             |   2 +-
 Post/PViewDataRemote.h       |  53 ++++-------
 Post/PViewVertexArrays.cpp   |  43 +++++++--
 27 files changed, 566 insertions(+), 515 deletions(-)
 create mode 100644 Common/ConnectionManager.cpp
 create mode 100644 Common/ConnectionManager.h
 delete mode 100644 Common/GmshDaemon.cpp
 delete mode 100644 Common/GmshDaemon.h

diff --git a/Common/CMakeLists.txt b/Common/CMakeLists.txt
index 553fca6464..b1db0dabb6 100644
--- a/Common/CMakeLists.txt
+++ b/Common/CMakeLists.txt
@@ -5,9 +5,8 @@
 
 set(SRC
   Gmsh.cpp
-    GmshMessage.cpp
     GmshRemote.cpp
-    GmshDaemon.cpp
+    GmshMessage.cpp
   Context.cpp
   Options.cpp
   CommandLine.cpp
@@ -22,6 +21,7 @@ set(SRC
   ListUtils.cpp
   TreeUtils.cpp avl.cpp
   MallocUtils.cpp
+  ConnectionManager.cpp
 )
 
 file(GLOB HDR RELATIVE ${CMAKE_SOURCE_DIR}/Common *.h) 
diff --git a/Common/ConnectionManager.cpp b/Common/ConnectionManager.cpp
new file mode 100644
index 0000000000..a66d7d4594
--- /dev/null
+++ b/Common/ConnectionManager.cpp
@@ -0,0 +1,105 @@
+// Gmsh - Copyright (C) 1997-2009 C. Geuzaine, J.-F. Remacle
+//
+// See the LICENSE.txt file for license information. Please report all
+// bugs and problems to <gmsh@geuz.org>.
+
+#include <sstream>
+#include "GmshConfig.h"
+#include "GmshMessage.h"
+#include "ConnectionManager.h"
+#include "StringUtils.h"
+#include "OS.h"
+#include "Context.h"
+
+std::map<int, ConnectionManager*> ConnectionManager::_all;
+
+ConnectionManager::ConnectionManager()
+  : clientServer(1), popupMessages(1), mergeViews(1), _pid(0), _server(0)
+{
+  // we need at least five for the solver menu
+  buttonName.resize(5);
+  buttonSwitch.resize(5);
+  optionName.resize(5);
+  optionValue.resize(5);
+}
+
+std::string ConnectionManager::getSocketName()
+{
+  std::string sockname;
+  if(!strstr(CTX::instance()->solver.socketName.c_str(), ":")){
+    // Unix socket
+    std::ostringstream tmp;
+    tmp << CTX::instance()->homeDir << CTX::instance()->solver.socketName;
+    sockname = FixWindowsPath(tmp.str());
+  }
+  else{
+    // TCP/IP socket
+    sockname = CTX::instance()->solver.socketName;
+    // if only the port is given, prepend the host name
+    if(sockname.size() && sockname[0] == ':')
+      sockname = GetHostName() + sockname;
+  }
+  return sockname;
+}
+
+void ConnectionManager::runToGetOptions()
+{
+  if(inputFileName.empty()) return;
+  
+  std::string inputArg = inputFileName.empty() ? "" : ReplacePercentS
+    (inputFileSwitch, std::string("\"") + FixWindowsPath(inputFileName) + "\"");
+  std::string optionArg = ReplacePercentS(optionSwitch, "");
+  run(inputArg + " " + optionArg);
+}
+
+void ConnectionManager::runCommand(int commandIndex, int optionIndex, int optionChoice)
+{
+  std::string inputArg = inputFileName.empty() ? "" : ReplacePercentS
+    (inputFileSwitch, std::string("\"") + FixWindowsPath(inputFileName) + "\"");
+
+  std::string meshArg = meshFileName.empty() ? "" : ReplacePercentS
+    (meshFileSwitch, std::string("\"") + FixWindowsPath(meshFileName) + "\"");
+
+  if(commandIndex < 0 || commandIndex >= (int)buttonSwitch.size()){
+    Msg::Error("Wrong command index");
+    return;
+  }
+
+  if(optionIndex < 0 || optionIndex >= (int)optionValue.size()){
+    Msg::Error("Wrong option index");
+    return;
+  }
+
+  std::string commandArg;
+  if(optionValue[optionIndex].size()){
+    if(optionChoice < 0 || optionChoice >= (int)optionValue[optionIndex].size()){
+      Msg::Error("Wrong option choice");
+      return;
+    }
+    commandArg = ReplacePercentS
+      (buttonSwitch[commandIndex], optionValue[optionIndex][optionChoice]);
+  }
+  else{ // no options
+    commandArg = buttonSwitch[commandIndex];
+  }
+
+  run(inputArg + " " + meshArg + " " + commandArg);
+}
+
+#if !defined(HAVE_FLTK)
+
+void ConnectionManager::run(std::string args)
+{
+  Msg::Error("Gmsh has to be compiled with FLTK support to run remote apps");
+}
+
+#endif
+
+void ConnectionManager::kill()
+{
+  if(_pid > 0) {
+    if(KillProcess(_pid))
+      Msg::Info("Killed %s pid %d", name.c_str(), _pid);
+  }
+  _pid = -1;
+}
diff --git a/Common/ConnectionManager.h b/Common/ConnectionManager.h
new file mode 100644
index 0000000000..0eded54417
--- /dev/null
+++ b/Common/ConnectionManager.h
@@ -0,0 +1,107 @@
+// Gmsh - Copyright (C) 1997-2009 C. Geuzaine, J.-F. Remacle
+//
+// See the LICENSE.txt file for license information. Please report all
+// bugs and problems to <gmsh@geuz.org>.
+
+#ifndef _CONNECTION_MANAGER_H_
+#define _CONNECTION_MANAGER_H_
+
+#include <string>
+#include <vector>
+#include <map>
+
+class GmshServer;
+
+class ConnectionManager {
+ public:
+  // the name of the remote program (e.g. "GetDP")
+  std::string name;
+  // the executable command (e.g. "/usr/bin/getdp.exe")
+  std::string executable;
+  // the name of the input file for the remote program (e.g. "")
+  std::string inputFileName;
+  // the command line switch to specify the input file (e.g. "%s")
+  std::string inputFileSwitch;
+  // the standard extension of input file names for the remote program
+  // (e.g. ".pro")
+  std::string inputFileExtension;
+  // the name of the mesh file used by the remote program (e.g. "")
+  std::string meshFileName;
+  // the command line switch used to specify the mesh file
+  // (e.g. "-mesh %s")
+  std::string meshFileSwitch;
+  // the command line switch used to specify the socket (e.g. "-socket
+  // %s")
+  std::string socketSwitch;
+  // the names of the action buttons in the GUI (e.g. "Pre", "Cal",
+  // "Post")
+  std::vector<std::string> buttonName;
+  // the command line switches associated with the buttons (e.g. "-pre
+  // %s", "-cal", "-pos %s"); each %s will consume one of the options,
+  // in the order the buttons are defined
+  std::vector<std::string> buttonSwitch;
+  // the name of the options that can be passed to the remote program
+  // (e.g. "Resolution", "PostOperation")
+  std::vector<std::string> optionName;
+  // the command line switch to get the available values for all the
+  // options
+  std::string optionSwitch;
+  // the possible values for each option (these are normally
+  // dynamically filled by calling the remote program with the
+  // optionSwitch command line arg)
+  std::vector<std::vector<std::string> > optionValue;
+  // a help string describing the remote program
+  std::string help;
+  // set to true if the remote program should communicate with Gmsh
+  // through a socket
+  bool clientServer;
+  // set to true if remote messages should pop up the message window
+  bool popupMessages;
+  // set to true if remotely generated post-processing files should be
+  // merged by Gmsh
+  bool mergeViews;
+ private:
+  // the process id number of the remote program while it is running,
+  // or -1 when stopped
+  int _pid;
+  // a pointer to the server when the remote program is running, or 0
+  // when stopped
+  GmshServer *_server;
+  // a static map of all available remote programs: ints 0, 1, ... 4
+  // are reserved for the main solver menu; int -1 is used when
+  // permanently listening for incoming connections
+  static std::map<int, ConnectionManager*> _all;
+ public:
+  ConnectionManager();
+  ~ConnectionManager(){}
+  // get the name of the socket
+  std::string getSocketName();
+  // get/set the pid
+  int getPid(){ return _pid; }
+  void setPid(int pid){ _pid = pid; }
+  // get/set the server
+  GmshServer *getServer(){ return _server; }
+  void setServer(GmshServer *server){ _server = server; }
+  // get the num-th remote program; if it does not exist, create it
+  static ConnectionManager *get(int num)
+  {
+    std::map<int, ConnectionManager*>::iterator it = _all.find(num);
+    if(it == _all.end()){
+      ConnectionManager *s = new ConnectionManager();
+      _all[num] = s;
+      return s;
+    }
+    return it->second;
+  }
+  // run the remote program to get its options
+  void runToGetOptions();
+  // run the commandIndex-th command (button), using the specified
+  // option
+  void runCommand(int commandIndex, int optionIndex, int optionChoice);
+  // run the remote program with the given arguments
+  void run(std::string args);
+  // kill the remote program
+  void kill();
+};
+
+#endif
diff --git a/Common/Gmsh.cpp b/Common/Gmsh.cpp
index 2c03d02748..c2ee693a21 100644
--- a/Common/Gmsh.cpp
+++ b/Common/Gmsh.cpp
@@ -7,6 +7,7 @@
 #include <time.h>
 #include "GmshConfig.h"
 #include "GmshDefines.h"
+#include "GmshRemote.h"
 #include "GModel.h"
 #include "GmshMessage.h"
 #include "OpenFile.h"
@@ -19,7 +20,6 @@
 #include "Context.h"
 #include "robustPredicates.h"
 #include "meshPartition.h"
-#include "GmshDaemon.h"
 
 #if !defined(HAVE_NO_POST)
 #include "PluginManager.h"
@@ -139,7 +139,7 @@ int GmshBatch()
 #endif
 
   if(CTX::instance()->batch == -3){
-    GmshDaemon(CTX::instance()->solver.socketName);
+    GmshRemote(CTX::instance()->solver.socketName);
   }
   else if(CTX::instance()->batch == -2){
     GModel::current()->checkMeshCoherence(CTX::instance()->geom.tolerance);
diff --git a/Common/GmshDaemon.cpp b/Common/GmshDaemon.cpp
deleted file mode 100644
index cc820418e2..0000000000
--- a/Common/GmshDaemon.cpp
+++ /dev/null
@@ -1,111 +0,0 @@
-// Gmsh - Copyright (C) 1997-2009 C. Geuzaine, J.-F. Remacle
-//
-// See the LICENSE.txt file for license information. Please report all
-// bugs and problems to <gmsh@geuz.org>.
-
-#include <sstream>
-#include "GmshMessage.h"
-#include "GmshSocket.h"
-#include "OpenFile.h"
-#include "OS.h"
-#include "PView.h"
-#include "PViewOptions.h"
-#include "PViewData.h"
-#include "VertexArray.h"
-#include "Context.h"
-
-static void computeAndSendVertexArrays(GmshClient &client)
-{
-  CTX::instance()->terminal = 1; // debug
-  client.Info("Sending vertex arrays");
-  for(unsigned int i = 0; i < PView::list.size(); i++){
-    PView *p = PView::list[i];
-    p->fillVertexArrays();
-    PViewData *data = p->getData();
-    VertexArray *va[4] = 
-      {p->va_points, p->va_lines, p->va_triangles, p->va_vectors};
-    for(int type = 0; type < 4; type++){
-      if(va[type]){
-        int len;
-        char *str = va[type]->toChar
-          (p->getNum(), type + 1, data->getMin(), data->getMax(),
-           data->getTime(0), data->getBoundingBox(), len);
-        client.SendMessage(GmshSocket::GMSH_VERTEX_ARRAY, len, str);
-        delete [] str;
-      }
-    }
-  }
-}
-
-int GmshDaemon(std::string socket)
-{
-  GmshClient client;
-
-  if(client.Connect(socket.c_str()) < 0){
-    Msg::Error("Unable to connect to server on %s", socket.c_str());
-    return 1;
-  }
-  client.Start();
-  client.Info("Remote Gmsh sucessfully started");
-
-  computeAndSendVertexArrays(client);
-
-  client.Info("Remote Gmsh is listening...");
-  while(1){
-    // stop if we have no communications for 60 seconds
-    int ret = client.Select(60, 0);
-    if(!ret){
-      client.Info("Timout: stopping remote Gmsh...");
-      break;
-    }
-    else if(ret < 0){
-      client.Error("Error on select: stopping remote Gmsh...");
-      break;
-    }
-
-    int type, length;
-    if(!client.ReceiveHeader(&type, &length)){
-      client.Error("Did not receive message header: stopping remote Gmsh...");
-      break;
-    }
-      
-    char *msg = new char[length + 1];
-    if(!client.ReceiveString(length, msg)){
-      client.Error("Did not receive message body: stopping remote Gmsh...");
-      delete [] msg;
-      break;
-    }
-
-    if(type == GmshSocket::GMSH_STOP){
-      client.Info("Stopping remote Gmsh...");
-      break;
-    }
-    else if(type == GmshSocket::GMSH_VERTEX_ARRAY){
-      ParseString(msg);
-      computeAndSendVertexArrays(client);
-    }
-    else if(type == GmshSocket::GMSH_MERGE_FILE){
-      MergeFile(msg);
-      computeAndSendVertexArrays(client);
-    }
-    else if(type == GmshSocket::GMSH_PARSE_STRING){
-      ParseString(msg);
-    }
-    else if(type == GmshSocket::GMSH_SPEED_TEST){
-      client.Info("Sending huge array");
-      std::string huge(500000000, 'a');
-      client.SpeedTest(huge.c_str());
-    }
-    else{
-      client.Error("Ignoring unknown message");
-    }
-    
-    delete [] msg;
-  }
-
-  client.Info("Remote Gmsh is stopped");
-  client.Stop();
-  client.Disconnect();
-
-  return 0;
-}
diff --git a/Common/GmshDaemon.h b/Common/GmshDaemon.h
deleted file mode 100644
index f51e11b3c8..0000000000
--- a/Common/GmshDaemon.h
+++ /dev/null
@@ -1,14 +0,0 @@
-// Gmsh - Copyright (C) 1997-2009 C. Geuzaine, J.-F. Remacle
-//
-// See the LICENSE.txt file for license information. Please report all
-// bugs and problems to <gmsh@geuz.org>.
-
-#ifndef _GMSH_DAEMON_H_
-#define _GMSH_DAEMON_H_
-
-#include <string>
-
-int GmshDaemon(std::string socket);
-
-#endif
-
diff --git a/Common/GmshRemote.cpp b/Common/GmshRemote.cpp
index bbdf5a9d9f..a0c072434f 100644
--- a/Common/GmshRemote.cpp
+++ b/Common/GmshRemote.cpp
@@ -1,105 +1,113 @@
-// Gmsh - Copyright (C) 1997-2009 C. Geuzaine, J.-F. Remacle
-//
-// See the LICENSE.txt file for license information. Please report all
-// bugs and problems to <gmsh@geuz.org>.
-
 #include <sstream>
-#include "GmshConfig.h"
 #include "GmshMessage.h"
-#include "GmshRemote.h"
-#include "StringUtils.h"
+#include "GmshSocket.h"
+#include "OpenFile.h"
 #include "OS.h"
+#include "PView.h"
+#include "PViewOptions.h"
+#include "PViewData.h"
+#include "VertexArray.h"
 #include "Context.h"
 
-std::map<int, GmshRemote*> GmshRemote::_all;
-
-GmshRemote::GmshRemote()
-  : clientServer(1), popupMessages(1), mergeViews(1), _pid(0), _server(0)
-{
-  // we need at least five for the solver menu
-  buttonName.resize(5);
-  buttonSwitch.resize(5);
-  optionName.resize(5);
-  optionValue.resize(5);
-}
-
-std::string GmshRemote::getSocketName()
+static void computeAndSendVertexArrays(GmshClient &client)
 {
-  std::string sockname;
-  if(!strstr(CTX::instance()->solver.socketName.c_str(), ":")){
-    // Unix socket
-    std::ostringstream tmp;
-    tmp << CTX::instance()->homeDir << CTX::instance()->solver.socketName;
-    sockname = FixWindowsPath(tmp.str());
-  }
-  else{
-    // TCP/IP socket
-    sockname = CTX::instance()->solver.socketName;
-    // if only the port is given, prepend the host name
-    if(sockname.size() && sockname[0] == ':')
-      sockname = GetHostName() + sockname;
+  CTX::instance()->terminal = 1; // debug
+  client.Info("Sending vertex arrays");
+  for(unsigned int i = 0; i < PView::list.size(); i++){
+    PView *p = PView::list[i];
+    p->fillVertexArrays();
+    PViewData *data = p->getData();
+    PViewOptions *opt = p->getOptions();
+    double min = data->getMin(), max = data->getMax();
+    if(opt->rangeType == PViewOptions::PerTimeStep){
+      min = data->getMin(opt->timeStep);
+      max = data->getMax(opt->timeStep);
+    }
+    VertexArray *va[4] = 
+      {p->va_points, p->va_lines, p->va_triangles, p->va_vectors};
+    for(int type = 0; type < 4; type++){
+      if(va[type]){
+        int len;
+        char *str = va[type]->toChar
+          (p->getNum(), data->getName(), type + 1, min, max, 
+           data->getNumTimeSteps(), data->getTime(opt->timeStep),
+           data->getBoundingBox(), len);
+        client.SendMessage(GmshSocket::GMSH_VERTEX_ARRAY, len, str);
+        delete [] str;
+      }
+    }
   }
-  return sockname;
 }
 
-void GmshRemote::runToGetOptions()
+int GmshRemote(std::string socket)
 {
-  if(inputFileName.empty()) return;
-  
-  std::string inputArg = inputFileName.empty() ? "" : ReplacePercentS
-    (inputFileSwitch, std::string("\"") + FixWindowsPath(inputFileName) + "\"");
-  std::string optionArg = ReplacePercentS(optionSwitch, "");
-  run(inputArg + " " + optionArg);
-}
-
-void GmshRemote::runCommand(int commandIndex, int optionIndex, int optionChoice)
-{
-  std::string inputArg = inputFileName.empty() ? "" : ReplacePercentS
-    (inputFileSwitch, std::string("\"") + FixWindowsPath(inputFileName) + "\"");
-
-  std::string meshArg = meshFileName.empty() ? "" : ReplacePercentS
-    (meshFileSwitch, std::string("\"") + FixWindowsPath(meshFileName) + "\"");
+  GmshClient client;
 
-  if(commandIndex < 0 || commandIndex >= (int)buttonSwitch.size()){
-    Msg::Error("Wrong command index");
-    return;
+  if(client.Connect(socket.c_str()) < 0){
+    Msg::Error("Unable to connect to server on %s", socket.c_str());
+    return 1;
   }
+  client.Start();
+  client.Info("Remote Gmsh sucessfully started");
 
-  if(optionIndex < 0 || optionIndex >= (int)optionValue.size()){
-    Msg::Error("Wrong option index");
-    return;
-  }
+  computeAndSendVertexArrays(client);
 
-  std::string commandArg;
-  if(optionValue[optionIndex].size()){
-    if(optionChoice < 0 || optionChoice >= (int)optionValue[optionIndex].size()){
-      Msg::Error("Wrong option choice");
-      return;
+  client.Info("Remote Gmsh is listening...");
+  while(1){
+    // stop if we have no communications for 60 seconds
+    int ret = client.Select(60, 0);
+    if(!ret){
+      client.Info("Timout: stopping remote Gmsh...");
+      break;
+    }
+    else if(ret < 0){
+      client.Error("Error on select: stopping remote Gmsh...");
+      break;
     }
-    commandArg = ReplacePercentS
-      (buttonSwitch[commandIndex], optionValue[optionIndex][optionChoice]);
-  }
-  else{ // no options
-    commandArg = buttonSwitch[commandIndex];
-  }
-
-  run(inputArg + " " + meshArg + " " + commandArg);
-}
 
-#if !defined(HAVE_FLTK)
+    int type, length;
+    if(!client.ReceiveHeader(&type, &length)){
+      client.Error("Did not receive message header: stopping remote Gmsh...");
+      break;
+    }
+      
+    char *msg = new char[length + 1];
+    if(!client.ReceiveString(length, msg)){
+      client.Error("Did not receive message body: stopping remote Gmsh...");
+      delete [] msg;
+      break;
+    }
 
-void GmshRemote::run(std::string args)
-{
-  Msg::Error("Gmsh has to be compiled with FLTK support to run remote apps");
-}
+    if(type == GmshSocket::GMSH_STOP){
+      client.Info("Stopping remote Gmsh...");
+      break;
+    }
+    else if(type == GmshSocket::GMSH_VERTEX_ARRAY){
+      ParseString(msg);
+      computeAndSendVertexArrays(client);
+    }
+    else if(type == GmshSocket::GMSH_MERGE_FILE){
+      MergeFile(msg);
+      computeAndSendVertexArrays(client);
+    }
+    else if(type == GmshSocket::GMSH_PARSE_STRING){
+      ParseString(msg);
+    }
+    else if(type == GmshSocket::GMSH_SPEED_TEST){
+      client.Info("Sending huge array");
+      std::string huge(500000000, 'a');
+      client.SpeedTest(huge.c_str());
+    }
+    else{
+      client.Error("Ignoring unknown message");
+    }
+    
+    delete [] msg;
+  }
 
-#endif
+  client.Info("Remote Gmsh is stopped");
+  client.Stop();
+  client.Disconnect();
 
-void GmshRemote::kill()
-{
-  if(_pid > 0) {
-    if(KillProcess(_pid))
-      Msg::Info("Killed %s pid %d", name.c_str(), _pid);
-  }
-  _pid = -1;
+  return 0;
 }
diff --git a/Common/GmshRemote.h b/Common/GmshRemote.h
index 17d2244836..6ea08a1b47 100644
--- a/Common/GmshRemote.h
+++ b/Common/GmshRemote.h
@@ -7,101 +7,8 @@
 #define _GMSH_REMOTE_H_
 
 #include <string>
-#include <vector>
-#include <map>
 
-class GmshServer;
-
-class GmshRemote {
- public:
-  // the name of the remote program (e.g. "GetDP")
-  std::string name;
-  // the executable command (e.g. "/usr/bin/getdp.exe")
-  std::string executable;
-  // the name of the input file for the remote program (e.g. "")
-  std::string inputFileName;
-  // the command line switch to specify the input file (e.g. "%s")
-  std::string inputFileSwitch;
-  // the standard extension of input file names for the remote program
-  // (e.g. ".pro")
-  std::string inputFileExtension;
-  // the name of the mesh file used by the remote program (e.g. "")
-  std::string meshFileName;
-  // the command line switch used to specify the mesh file
-  // (e.g. "-mesh %s")
-  std::string meshFileSwitch;
-  // the command line switch used to specify the socket (e.g. "-socket
-  // %s")
-  std::string socketSwitch;
-  // the names of the action buttons in the GUI (e.g. "Pre", "Cal",
-  // "Post")
-  std::vector<std::string> buttonName;
-  // the command line switches associated with the buttons (e.g. "-pre
-  // %s", "-cal", "-pos %s"); each %s will consume one of the options,
-  // in the order the buttons are defined
-  std::vector<std::string> buttonSwitch;
-  // the name of the options that can be passed to the remote program
-  // (e.g. "Resolution", "PostOperation")
-  std::vector<std::string> optionName;
-  // the command line switch to get the available values for all the
-  // options
-  std::string optionSwitch;
-  // the possible values for each option (these are normally
-  // dynamically filled by calling the remote program with the
-  // optionSwitch command line arg)
-  std::vector<std::vector<std::string> > optionValue;
-  // a help string describing the remote program
-  std::string help;
-  // set to true if the remote program should communicate with Gmsh
-  // through a socket
-  bool clientServer;
-  // set to true if remote messages should pop up the message window
-  bool popupMessages;
-  // set to true if remotely generated post-processing files should be
-  // merged by Gmsh
-  bool mergeViews;
- private:
-  // the process id number of the remote program while it is running,
-  // or -1 when stopped
-  int _pid;
-  // a pointer to the server when the remote program is running, or 0
-  // when stopped
-  GmshServer *_server;
-  // a static map of all available remote programs: ints 0, 1, ... 4
-  // are reserved for the main solver menu; int -1 is used when
-  // permanently listening for incoming connections
-  static std::map<int, GmshRemote*> _all;
- public:
-  GmshRemote();
-  ~GmshRemote(){}
-  // get the name of the socket
-  std::string getSocketName();
-  // get/set the pid
-  int getPid(){ return _pid; }
-  void setPid(int pid){ _pid = pid; }
-  // get/set the server
-  GmshServer *getServer(){ return _server; }
-  void setServer(GmshServer *server){ _server = server; }
-  // get the num-th remote program; if it does not exist, create it
-  static GmshRemote *get(int num)
-  {
-    std::map<int, GmshRemote*>::iterator it = _all.find(num);
-    if(it == _all.end()){
-      GmshRemote *s = new GmshRemote();
-      _all[num] = s;
-      return s;
-    }
-    return it->second;
-  }
-  // run the remote program to get its options
-  void runToGetOptions();
-  // run the commandIndex-th command (button), using the specified
-  // option
-  void runCommand(int commandIndex, int optionIndex, int optionChoice);
-  // run the remote program with the given arguments
-  void run(std::string args);
-  // kill the remote program
-  void kill();
-};
+int GmshRemote(std::string socket);
 
 #endif
+
diff --git a/Common/Main.cpp b/Common/Main.cpp
index adcde7a0b1..56fd743130 100644
--- a/Common/Main.cpp
+++ b/Common/Main.cpp
@@ -27,3 +27,4 @@ int main(int argc, char *argv[])
   Msg::Exit(0);
   return 1;
 }
+
diff --git a/Common/Options.cpp b/Common/Options.cpp
index 4c770457c2..727c99506a 100644
--- a/Common/Options.cpp
+++ b/Common/Options.cpp
@@ -8,7 +8,7 @@
 #include "GmshConfig.h"
 #include "GmshDefines.h"
 #include "GmshMessage.h"
-#include "GmshRemote.h"
+#include "ConnectionManager.h"
 #include "StringUtils.h"
 #include "GModel.h"
 #include "Generator.h"
@@ -1041,12 +1041,12 @@ std::string opt_solver_socket_name(OPT_ARGS_STR)
 std::string opt_solver_name(OPT_ARGS_STR)
 {
   if(action & GMSH_SET)
-    GmshRemote::get(num)->name = val;
+    ConnectionManager::get(num)->name = val;
 #if defined(HAVE_FLTK)
   if(FlGui::available() && (action & GMSH_GUI))
-    FlGui::instance()->solver[num]->win->label(GmshRemote::get(num)->name.c_str());
+    FlGui::instance()->solver[num]->win->label(ConnectionManager::get(num)->name.c_str());
 #endif
-  return GmshRemote::get(num)->name;
+  return ConnectionManager::get(num)->name;
 }
 
 std::string opt_solver_name0(OPT_ARGS_STR)
@@ -1077,13 +1077,13 @@ std::string opt_solver_name4(OPT_ARGS_STR)
 std::string opt_solver_executable(OPT_ARGS_STR)
 {
   if(action & GMSH_SET)
-    GmshRemote::get(num)->executable = val;
+    ConnectionManager::get(num)->executable = val;
 #if defined(HAVE_FLTK)
   if(FlGui::available() && (action & GMSH_GUI))
     FlGui::instance()->solver[num]->input[2]->value
-      (GmshRemote::get(num)->executable.c_str());
+      (ConnectionManager::get(num)->executable.c_str());
 #endif
-  return GmshRemote::get(num)->executable;
+  return ConnectionManager::get(num)->executable;
 }
 
 std::string opt_solver_executable0(OPT_ARGS_STR)
@@ -1114,8 +1114,8 @@ std::string opt_solver_executable4(OPT_ARGS_STR)
 std::string opt_solver_help(OPT_ARGS_STR)
 {
   if(action & GMSH_SET)
-    GmshRemote::get(num)->help = val;
-  return GmshRemote::get(num)->help;
+    ConnectionManager::get(num)->help = val;
+  return ConnectionManager::get(num)->help;
 }
 
 std::string opt_solver_help0(OPT_ARGS_STR)
@@ -1147,17 +1147,17 @@ std::string opt_solver_input_name(OPT_ARGS_STR)
 {
   if(action & GMSH_SET){
 #if !defined(HAVE_NO_PARSER)
-    GmshRemote::get(num)->inputFileName = FixRelativePath(gmsh_yyname, val);
+    ConnectionManager::get(num)->inputFileName = FixRelativePath(gmsh_yyname, val);
 #else
-    GmshRemote::get(num)->inputFileName = val;
+    ConnectionManager::get(num)->inputFileName = val;
 #endif
   }
 #if defined(HAVE_FLTK)
   if(FlGui::available() && (action & GMSH_GUI))
     FlGui::instance()->solver[num]->input[0]->value
-      (GmshRemote::get(num)->inputFileName.c_str());
+      (ConnectionManager::get(num)->inputFileName.c_str());
 #endif
-  return GmshRemote::get(num)->inputFileName;
+  return ConnectionManager::get(num)->inputFileName;
 }
 
 std::string opt_solver_input_name0(OPT_ARGS_STR)
@@ -1188,8 +1188,8 @@ std::string opt_solver_input_name4(OPT_ARGS_STR)
 std::string opt_solver_extension(OPT_ARGS_STR)
 {
   if(action & GMSH_SET)
-    GmshRemote::get(num)->inputFileExtension = val;
-  return GmshRemote::get(num)->inputFileExtension;
+    ConnectionManager::get(num)->inputFileExtension = val;
+  return ConnectionManager::get(num)->inputFileExtension;
 }
 
 std::string opt_solver_extension0(OPT_ARGS_STR)
@@ -1221,17 +1221,17 @@ std::string opt_solver_mesh_name(OPT_ARGS_STR)
 {
   if(action & GMSH_SET){
 #if !defined(HAVE_NO_PARSER)
-    GmshRemote::get(num)->meshFileName = FixRelativePath(gmsh_yyname, val);
+    ConnectionManager::get(num)->meshFileName = FixRelativePath(gmsh_yyname, val);
 #else
-    GmshRemote::get(num)->meshFileName = val;
+    ConnectionManager::get(num)->meshFileName = val;
 #endif
   }
 #if defined(HAVE_FLTK)
   if(FlGui::available() && (action & GMSH_GUI))
     FlGui::instance()->solver[num]->input[1]->value
-      (GmshRemote::get(num)->meshFileName.c_str());
+      (ConnectionManager::get(num)->meshFileName.c_str());
 #endif
-  return GmshRemote::get(num)->meshFileName;
+  return ConnectionManager::get(num)->meshFileName;
 }
 
 std::string opt_solver_mesh_name0(OPT_ARGS_STR)
@@ -1262,8 +1262,8 @@ std::string opt_solver_mesh_name4(OPT_ARGS_STR)
 std::string opt_solver_mesh_command(OPT_ARGS_STR)
 {
   if(action & GMSH_SET)
-    GmshRemote::get(num)->meshFileSwitch = val;
-  return GmshRemote::get(num)->meshFileSwitch;
+    ConnectionManager::get(num)->meshFileSwitch = val;
+  return ConnectionManager::get(num)->meshFileSwitch;
 }
 
 std::string opt_solver_mesh_command0(OPT_ARGS_STR)
@@ -1294,8 +1294,8 @@ std::string opt_solver_mesh_command4(OPT_ARGS_STR)
 std::string opt_solver_socket_command(OPT_ARGS_STR)
 {
   if(action & GMSH_SET)
-    GmshRemote::get(num)->socketSwitch = val;
-  return GmshRemote::get(num)->socketSwitch;
+    ConnectionManager::get(num)->socketSwitch = val;
+  return ConnectionManager::get(num)->socketSwitch;
 }
 
 std::string opt_solver_socket_command0(OPT_ARGS_STR)
@@ -1326,8 +1326,8 @@ std::string opt_solver_socket_command4(OPT_ARGS_STR)
 std::string opt_solver_name_command(OPT_ARGS_STR)
 {
   if(action & GMSH_SET)
-    GmshRemote::get(num)->inputFileSwitch = val;
-  return GmshRemote::get(num)->inputFileSwitch;
+    ConnectionManager::get(num)->inputFileSwitch = val;
+  return ConnectionManager::get(num)->inputFileSwitch;
 }
 
 std::string opt_solver_name_command0(OPT_ARGS_STR)
@@ -1358,8 +1358,8 @@ std::string opt_solver_name_command4(OPT_ARGS_STR)
 std::string opt_solver_option_command(OPT_ARGS_STR)
 {
   if(action & GMSH_SET)
-    GmshRemote::get(num)->optionSwitch = val;
-  return GmshRemote::get(num)->optionSwitch;
+    ConnectionManager::get(num)->optionSwitch = val;
+  return ConnectionManager::get(num)->optionSwitch;
 }
 
 std::string opt_solver_option_command0(OPT_ARGS_STR)
@@ -1390,8 +1390,8 @@ std::string opt_solver_option_command4(OPT_ARGS_STR)
 std::string opt_solver_first_option(OPT_ARGS_STR)
 {
   if(action & GMSH_SET)
-    GmshRemote::get(num)->optionName[0] = val;
-  return GmshRemote::get(num)->optionName[0];
+    ConnectionManager::get(num)->optionName[0] = val;
+  return ConnectionManager::get(num)->optionName[0];
 }
 
 std::string opt_solver_first_option0(OPT_ARGS_STR)
@@ -1422,8 +1422,8 @@ std::string opt_solver_first_option4(OPT_ARGS_STR)
 std::string opt_solver_second_option(OPT_ARGS_STR)
 {
   if(action & GMSH_SET)
-    GmshRemote::get(num)->optionName[1] = val;
-  return GmshRemote::get(num)->optionName[1];
+    ConnectionManager::get(num)->optionName[1] = val;
+  return ConnectionManager::get(num)->optionName[1];
 }
 
 std::string opt_solver_second_option0(OPT_ARGS_STR)
@@ -1454,8 +1454,8 @@ std::string opt_solver_second_option4(OPT_ARGS_STR)
 std::string opt_solver_third_option(OPT_ARGS_STR)
 {
   if(action & GMSH_SET)
-    GmshRemote::get(num)->optionName[2] = val;
-  return GmshRemote::get(num)->optionName[2];
+    ConnectionManager::get(num)->optionName[2] = val;
+  return ConnectionManager::get(num)->optionName[2];
 }
 
 std::string opt_solver_third_option0(OPT_ARGS_STR)
@@ -1486,8 +1486,8 @@ std::string opt_solver_third_option4(OPT_ARGS_STR)
 std::string opt_solver_fourth_option(OPT_ARGS_STR)
 {
   if(action & GMSH_SET)
-    GmshRemote::get(num)->optionName[3] = val;
-  return GmshRemote::get(num)->optionName[3];
+    ConnectionManager::get(num)->optionName[3] = val;
+  return ConnectionManager::get(num)->optionName[3];
 }
 
 std::string opt_solver_fourth_option0(OPT_ARGS_STR)
@@ -1518,8 +1518,8 @@ std::string opt_solver_fourth_option4(OPT_ARGS_STR)
 std::string opt_solver_fifth_option(OPT_ARGS_STR)
 {
   if(action & GMSH_SET)
-    GmshRemote::get(num)->optionName[4] = val;
-  return GmshRemote::get(num)->optionName[4];
+    ConnectionManager::get(num)->optionName[4] = val;
+  return ConnectionManager::get(num)->optionName[4];
 }
 
 std::string opt_solver_fifth_option0(OPT_ARGS_STR)
@@ -1550,8 +1550,8 @@ std::string opt_solver_fifth_option4(OPT_ARGS_STR)
 std::string opt_solver_first_button(OPT_ARGS_STR)
 {
   if(action & GMSH_SET)
-    GmshRemote::get(num)->buttonName[0] = val;
-  return GmshRemote::get(num)->buttonName[0];
+    ConnectionManager::get(num)->buttonName[0] = val;
+  return ConnectionManager::get(num)->buttonName[0];
 }
 
 std::string opt_solver_first_button0(OPT_ARGS_STR)
@@ -1582,8 +1582,8 @@ std::string opt_solver_first_button4(OPT_ARGS_STR)
 std::string opt_solver_first_button_command(OPT_ARGS_STR)
 {
   if(action & GMSH_SET)
-    GmshRemote::get(num)->buttonSwitch[0] = val;
-  return GmshRemote::get(num)->buttonSwitch[0];
+    ConnectionManager::get(num)->buttonSwitch[0] = val;
+  return ConnectionManager::get(num)->buttonSwitch[0];
 }
 
 std::string opt_solver_first_button_command0(OPT_ARGS_STR)
@@ -1614,8 +1614,8 @@ std::string opt_solver_first_button_command4(OPT_ARGS_STR)
 std::string opt_solver_second_button(OPT_ARGS_STR)
 {
   if(action & GMSH_SET)
-    GmshRemote::get(num)->buttonName[1] = val;
-  return GmshRemote::get(num)->buttonName[1];
+    ConnectionManager::get(num)->buttonName[1] = val;
+  return ConnectionManager::get(num)->buttonName[1];
 }
 
 std::string opt_solver_second_button0(OPT_ARGS_STR)
@@ -1646,8 +1646,8 @@ std::string opt_solver_second_button4(OPT_ARGS_STR)
 std::string opt_solver_second_button_command(OPT_ARGS_STR)
 {
   if(action & GMSH_SET)
-    GmshRemote::get(num)->buttonSwitch[1] = val;
-  return GmshRemote::get(num)->buttonSwitch[1];
+    ConnectionManager::get(num)->buttonSwitch[1] = val;
+  return ConnectionManager::get(num)->buttonSwitch[1];
 }
 
 std::string opt_solver_second_button_command0(OPT_ARGS_STR)
@@ -1678,8 +1678,8 @@ std::string opt_solver_second_button_command4(OPT_ARGS_STR)
 std::string opt_solver_third_button(OPT_ARGS_STR)
 {
   if(action & GMSH_SET)
-    GmshRemote::get(num)->buttonName[2] = val;
-  return GmshRemote::get(num)->buttonName[2];
+    ConnectionManager::get(num)->buttonName[2] = val;
+  return ConnectionManager::get(num)->buttonName[2];
 }
 
 std::string opt_solver_third_button0(OPT_ARGS_STR)
@@ -1710,8 +1710,8 @@ std::string opt_solver_third_button4(OPT_ARGS_STR)
 std::string opt_solver_third_button_command(OPT_ARGS_STR)
 {
   if(action & GMSH_SET)
-    GmshRemote::get(num)->buttonSwitch[2] = val;
-  return GmshRemote::get(num)->buttonSwitch[2];
+    ConnectionManager::get(num)->buttonSwitch[2] = val;
+  return ConnectionManager::get(num)->buttonSwitch[2];
 }
 
 std::string opt_solver_third_button_command0(OPT_ARGS_STR)
@@ -1742,8 +1742,8 @@ std::string opt_solver_third_button_command4(OPT_ARGS_STR)
 std::string opt_solver_fourth_button(OPT_ARGS_STR)
 {
   if(action & GMSH_SET)
-    GmshRemote::get(num)->buttonName[3] = val;
-  return GmshRemote::get(num)->buttonName[3];
+    ConnectionManager::get(num)->buttonName[3] = val;
+  return ConnectionManager::get(num)->buttonName[3];
 }
 
 std::string opt_solver_fourth_button0(OPT_ARGS_STR)
@@ -1774,8 +1774,8 @@ std::string opt_solver_fourth_button4(OPT_ARGS_STR)
 std::string opt_solver_fourth_button_command(OPT_ARGS_STR)
 {
   if(action & GMSH_SET)
-    GmshRemote::get(num)->buttonSwitch[3] = val;
-  return GmshRemote::get(num)->buttonSwitch[3];
+    ConnectionManager::get(num)->buttonSwitch[3] = val;
+  return ConnectionManager::get(num)->buttonSwitch[3];
 }
 
 std::string opt_solver_fourth_button_command0(OPT_ARGS_STR)
@@ -1806,8 +1806,8 @@ std::string opt_solver_fourth_button_command4(OPT_ARGS_STR)
 std::string opt_solver_fifth_button(OPT_ARGS_STR)
 {
   if(action & GMSH_SET)
-    GmshRemote::get(num)->buttonName[4] = val;
-  return GmshRemote::get(num)->buttonName[4];
+    ConnectionManager::get(num)->buttonName[4] = val;
+  return ConnectionManager::get(num)->buttonName[4];
 }
 
 std::string opt_solver_fifth_button0(OPT_ARGS_STR)
@@ -1838,8 +1838,8 @@ std::string opt_solver_fifth_button4(OPT_ARGS_STR)
 std::string opt_solver_fifth_button_command(OPT_ARGS_STR)
 {
   if(action & GMSH_SET)
-    GmshRemote::get(num)->buttonSwitch[4] = val;
-  return GmshRemote::get(num)->buttonSwitch[4];
+    ConnectionManager::get(num)->buttonSwitch[4] = val;
+  return ConnectionManager::get(num)->buttonSwitch[4];
 }
 
 std::string opt_solver_fifth_button_command0(OPT_ARGS_STR)
@@ -5921,16 +5921,16 @@ double opt_solver_plugins(OPT_ARGS_NUM)
 double opt_solver_client_server(OPT_ARGS_NUM)
 {
   if(action & GMSH_SET)
-    GmshRemote::get(num)->clientServer = (bool)val;
+    ConnectionManager::get(num)->clientServer = (bool)val;
 #if defined(HAVE_FLTK)
   if(FlGui::available() && (action & GMSH_GUI)){
-    if(GmshRemote::get(num)->clientServer)
+    if(ConnectionManager::get(num)->clientServer)
       ((Fl_Menu_Item*)FlGui::instance()->solver[num]->menu->menu())[0].set();
     else
       ((Fl_Menu_Item*)FlGui::instance()->solver[num]->menu->menu())[0].clear();
   }
 #endif
-  return GmshRemote::get(num)->clientServer ? 1 : 0;
+  return ConnectionManager::get(num)->clientServer ? 1 : 0;
 }
 
 double opt_solver_client_server0(OPT_ARGS_NUM)
@@ -5961,16 +5961,16 @@ double opt_solver_client_server4(OPT_ARGS_NUM)
 double opt_solver_popup_messages(OPT_ARGS_NUM)
 {
   if(action & GMSH_SET)
-    GmshRemote::get(num)->popupMessages = (bool)val;
+    ConnectionManager::get(num)->popupMessages = (bool)val;
 #if defined(HAVE_FLTK)
   if(FlGui::available() && (action & GMSH_GUI)){
-    if(GmshRemote::get(num)->popupMessages)
+    if(ConnectionManager::get(num)->popupMessages)
       ((Fl_Menu_Item*)FlGui::instance()->solver[num]->menu->menu())[1].set();
     else
       ((Fl_Menu_Item*)FlGui::instance()->solver[num]->menu->menu())[1].clear();
   }
 #endif
-  return GmshRemote::get(num)->popupMessages ? 1 : 0;
+  return ConnectionManager::get(num)->popupMessages ? 1 : 0;
 }
 
 double opt_solver_popup_messages0(OPT_ARGS_NUM)
@@ -6001,16 +6001,16 @@ double opt_solver_popup_messages4(OPT_ARGS_NUM)
 double opt_solver_merge_views(OPT_ARGS_NUM)
 {
   if(action & GMSH_SET)
-    GmshRemote::get(num)->mergeViews = (bool)val;
+    ConnectionManager::get(num)->mergeViews = (bool)val;
 #if defined(HAVE_FLTK)
   if(FlGui::available() && (action & GMSH_GUI)){
-    if(GmshRemote::get(num)->mergeViews)
+    if(ConnectionManager::get(num)->mergeViews)
       ((Fl_Menu_Item*)FlGui::instance()->solver[num]->menu->menu())[2].set();
     else
       ((Fl_Menu_Item*)FlGui::instance()->solver[num]->menu->menu())[2].clear();
   }
 #endif
-  return GmshRemote::get(num)->mergeViews ? 1 : 0;
+  return ConnectionManager::get(num)->mergeViews ? 1 : 0;
 }
 
 double opt_solver_merge_views0(OPT_ARGS_NUM)
diff --git a/Common/VertexArray.cpp b/Common/VertexArray.cpp
index d8ed66c622..da07a08824 100644
--- a/Common/VertexArray.cpp
+++ b/Common/VertexArray.cpp
@@ -217,22 +217,26 @@ int VertexArray::getMemoryUsage()
   return bytes / 1024 / 1024;
 }
 
-char *VertexArray::toChar(int num, int type, double min, double max, double time,
-                          SBoundingBox3d bbox, int &len)
+char *VertexArray::toChar(int num, std::string name, int type, double min, double max, 
+                          int numsteps, double time, SBoundingBox3d bbox, int &len)
 {
   int vn = _vertices.size(), nn = _normals.size(), cn = _colors.size();
   int vs = vn * sizeof(float), ns = nn * sizeof(char), cs = cn * sizeof(unsigned char);
   int is = sizeof(int), ds = sizeof(double);
+  int ss = name.size();
   double xmin = bbox.min().x(), ymin = bbox.min().y(), zmin = bbox.min().z();
   double xmax = bbox.max().x(), ymax = bbox.max().y(), zmax = bbox.max().z();
 
-  len = 5 * is + 9 * ds + vs + ns + cs;
+  len = ss + 7 * is + 9 * ds + vs + ns + cs;
   char *bytes = new char[len];
   int index = 0;
   memcpy(&bytes[index], &num, is); index += is;
+  memcpy(&bytes[index], &ss, is); index += is;
+  memcpy(&bytes[index], name.c_str(), ss); index += ss;
   memcpy(&bytes[index], &type, is); index += is;
   memcpy(&bytes[index], &min, ds); index += ds;
   memcpy(&bytes[index], &max, ds); index += ds;
+  memcpy(&bytes[index], &numsteps, is); index += is;
   memcpy(&bytes[index], &time, ds); index += ds;
   memcpy(&bytes[index], &xmin, ds); index += ds;
   memcpy(&bytes[index], &ymin, ds); index += ds;
@@ -258,9 +262,16 @@ void VertexArray::fromChar(const char *bytes)
   if(num > 65535)
     Msg::Error("Should swap data in vertex array stream");
 
+  int ss; memcpy(&ss, &bytes[index], is); index += is;
+  if(ss){
+    std::vector<char> name(ss); 
+    memcpy(&name[0], &bytes[index], ss); index += ss;
+  }
+
   int type; memcpy(&type, &bytes[index], is); index += is;
   double min; memcpy(&min, &bytes[index], ds); index += ds;
   double max; memcpy(&max, &bytes[index], ds); index += ds;
+  int numsteps; memcpy(&numsteps, &bytes[index], is); index += is;
   double time; memcpy(&time, &bytes[index], ds); index += ds;
   double xmin; memcpy(&xmin, &bytes[index], ds); index += ds;
   double ymin; memcpy(&ymin, &bytes[index], ds); index += ds;
diff --git a/Common/VertexArray.h b/Common/VertexArray.h
index 4e7bdc3b75..53916a84d7 100644
--- a/Common/VertexArray.h
+++ b/Common/VertexArray.h
@@ -164,8 +164,8 @@ class VertexArray{
   int getMemoryUsage();
   // serialize the vertex array into a string (for sending over the
   // network)
-  char *toChar(int num, int type, double min, double max, double time,
-               SBoundingBox3d bbox, int &len);
+  char *toChar(int num, std::string name, int type, double min, double max, 
+               int numsteps, double time, SBoundingBox3d bbox, int &len);
   void fromChar(const char *bytes);
 };
 
diff --git a/Fltk/Main.cpp b/Fltk/Main.cpp
index 2d41035c3a..f8fee40057 100644
--- a/Fltk/Main.cpp
+++ b/Fltk/Main.cpp
@@ -6,7 +6,7 @@
 #include <string>
 #include "Gmsh.h"
 #include "GmshMessage.h"
-#include "GmshRemote.h"
+#include "ConnectionManager.h"
 #include "FlGui.h"
 #include "menuWindow.h"
 #include "drawContext.h"
@@ -116,7 +116,7 @@ int main(int argc, char *argv[])
 
   // Listen to external solvers
   if(CTX::instance()->solver.listen)
-    GmshRemote::get(-1)->run("");
+    ConnectionManager::get(-1)->run("");
 
   // loop
   return FlGui::instance()->run();
diff --git a/Fltk/extraDialogs.cpp b/Fltk/extraDialogs.cpp
index acd6144b65..33caed8d96 100644
--- a/Fltk/extraDialogs.cpp
+++ b/Fltk/extraDialogs.cpp
@@ -225,27 +225,31 @@ class ConnectionBrowser : public Fl_Hold_Browser {
  public:
   ConnectionBrowser(int x, int y, int w, int h, const char *l=0)
     : Fl_Hold_Browser(x, y, w, h, l) {}
+};
+
+struct _connectionChooser{
+  Fl_Double_Window *window;
+  Fl_Input *input;
+  ConnectionBrowser *browser;
+  Fl_Return_Button *ok;
+  Fl_Button *cancel;
   void save(Fl_Preferences &prefs)
   {
     for(int i = 0; i < 100; i++){
       char name[256];
       sprintf(name, "connection%02d", i);
-      if(i < size())
-        prefs.set(name, text(i + 1));
+      if(i < browser->size())
+        prefs.set(name, browser->text(i + 1));
       else if(prefs.entryExists(name)) 
         prefs.deleteEntry(name);
     }
+    prefs.set("connectionPositionX", window->x());
+    prefs.set("connectionPositionY", window->y());
+    prefs.set("connectionWidth", window->w());
+    prefs.set("connectionHeight", window->h());
   }
 };
 
-struct _connectionChooser{
-  Fl_Double_Window *window;
-  Fl_Input *input;
-  ConnectionBrowser *browser;
-  Fl_Return_Button *ok;
-  Fl_Button *cancel;
-};
-
 static _connectionChooser *chooser = 0;
 
 static void select_cb(Fl_Widget* w, void *data)
@@ -256,12 +260,13 @@ static void select_cb(Fl_Widget* w, void *data)
 
 std::string connectionChooser()
 {
+  int x = 100, y = 100, h = 4 * WB + 10 * BH, w = 3 * BB + 2 * WB;
+
   if(!chooser){
     chooser = new _connectionChooser;
-    int h = 4 * WB + 12 * BH, w = 4 * BB + 2 * WB;
     chooser->window = new Fl_Double_Window(w, h);
     chooser->window->set_modal();
-    chooser->window->label("Start Remote Gmsh");
+    chooser->window->label("Remote Start");
     Fl_Box *b1 = new Fl_Box(WB, WB, w, BH, "Command:");
     b1->align(FL_ALIGN_INSIDE|FL_ALIGN_LEFT);
     chooser->input = new Fl_Input(WB, WB + BH, w - 2 * WB, BH);
@@ -280,6 +285,11 @@ std::string connectionChooser()
   }
 
   Fl_Preferences prefs(Fl_Preferences::USER, "fltk.org", "gmsh");
+  prefs.get("connectionPositionX", x, x);
+  prefs.get("connectionPositionY", y, y);
+  prefs.get("connectionWidth", w, w);
+  prefs.get("connectionHeight", h, h);
+  chooser->window->resize(x, y, w, h);
 
   int old = chooser->browser->value();
   chooser->browser->clear();
@@ -319,12 +329,12 @@ std::string connectionChooser()
           }
           chooser->browser->insert(1, chooser->input->value());
         }
-        chooser->browser->save(prefs);
+        chooser->save(prefs);
         chooser->window->hide();
         return chooser->input->value();
       }
       if (o == chooser->window || o == chooser->cancel){
-        chooser->browser->save(prefs);
+        chooser->save(prefs);
         chooser->window->hide();
         return "";
       }
diff --git a/Fltk/menuWindow.cpp b/Fltk/menuWindow.cpp
index 66ae243efe..90a11fc96d 100644
--- a/Fltk/menuWindow.cpp
+++ b/Fltk/menuWindow.cpp
@@ -10,8 +10,8 @@
 #include <FL/fl_ask.H>
 #include "GmshConfig.h"
 #include "GmshMessage.h"
-#include "GmshRemote.h"
 #include "GmshSocket.h"
+#include "ConnectionManager.h"
 #include "FlGui.h"
 #include "menuWindow.h"
 #include "mainWindow.h"
@@ -149,20 +149,20 @@ static void file_clear_cb(Fl_Widget *w, void *data)
 
 static void file_remote_cb(Fl_Widget *w, void *data)
 {
-  GmshServer *server = GmshRemote::get(99)->getServer();
+  GmshServer *server = ConnectionManager::get(99)->getServer();
 
   std::string str((const char*)data);
 
   if(str == "start"){
     if(server){
-      Msg::Error("A server is already running");
+      Msg::Error("Cannot start: server is already running");
       return;
     }
-    GmshRemote::get(99)->name = "Remote";
-    GmshRemote::get(99)->socketSwitch = "-socket %s";
-    GmshRemote::get(99)->executable = connectionChooser();
-    if(GmshRemote::get(99)->executable.size())
-      GmshRemote::get(99)->run("");
+    ConnectionManager::get(99)->name = "Remote";
+    ConnectionManager::get(99)->socketSwitch = "-socket %s";
+    ConnectionManager::get(99)->executable = connectionChooser();
+    if(ConnectionManager::get(99)->executable.size())
+      ConnectionManager::get(99)->run("");
   }
   else{
     if(!server){
@@ -173,7 +173,7 @@ static void file_remote_cb(Fl_Widget *w, void *data)
       server->SendString(GmshSocket::GMSH_STOP, "Disconnect!");
     }
     else if(str == "merge"){
-      const char *file = fl_input("File:", "~/data/res00.pos");
+      const char *file = fl_input("Merge", "/tmp/data.pos");
       if(file) server->SendString(GmshSocket::GMSH_MERGE_FILE, file);
     }
     else if(str == "clear"){
@@ -184,7 +184,7 @@ static void file_remote_cb(Fl_Widget *w, void *data)
       drawContext::global()->draw();
     }
     else if(str == "test"){
-      server->SendString(GmshSocket::GMSH_SPEED_TEST, "Test connection speed");
+      server->SendString(GmshSocket::GMSH_SPEED_TEST, "Speed test");
     }
   }
 }
@@ -2190,7 +2190,6 @@ static Fl_Menu_Item bar_table[] = {
       {"Start...",  0, (Fl_Callback *)file_remote_cb, (void*)"start"},
       {"Merge...",  0, (Fl_Callback *)file_remote_cb, (void*)"merge"},
       {"Clear",     0, (Fl_Callback *)file_remote_cb, (void*)"clear"},
-      {"Test Connection Speed", 0, (Fl_Callback *)file_remote_cb, (void*)"test"},
       {"Stop",      0, (Fl_Callback *)file_remote_cb, (void*)"stop"},
       {0},
     {"New Window", 0, (Fl_Callback *)file_window_cb, (void*)"new"},
@@ -2241,7 +2240,6 @@ static Fl_Menu_Item sysbar_table[] = {
       {"Start...",  0, (Fl_Callback *)file_remote_cb, (void*)"start"},
       {"Merge...",  0, (Fl_Callback *)file_remote_cb, (void*)"merge"},
       {"Clear",     0, (Fl_Callback *)file_remote_cb, (void*)"clear"},
-      {"Test Connection Speed", 0, (Fl_Callback *)file_remote_cb, (void*)"test"},
       {"Stop",      0, (Fl_Callback *)file_remote_cb, (void*)"stop"},
       {0},
     {"New Window", 0, (Fl_Callback *)file_window_cb, (void*)"new"},
diff --git a/Fltk/optionWindow.cpp b/Fltk/optionWindow.cpp
index c2c1519f13..967668323f 100644
--- a/Fltk/optionWindow.cpp
+++ b/Fltk/optionWindow.cpp
@@ -10,7 +10,7 @@
 #include "GmshConfig.h"
 #include "GmshDefines.h"
 #include "GmshMessage.h"
-#include "GmshRemote.h"
+#include "ConnectionManager.h"
 #include "FlGui.h"
 #include "optionWindow.h"
 #include "paletteWindow.h"
@@ -472,7 +472,7 @@ static void solver_options_ok_cb(Fl_Widget *w, void *data)
   int old_listen = (int)opt_solver_listen(0, GMSH_GET, o->solver.butt[0]->value());
   opt_solver_listen(0, GMSH_SET, o->solver.butt[0]->value());
   if(!old_listen && o->solver.butt[0]->value())
-    GmshRemote::get(-1)->run("");
+    ConnectionManager::get(-1)->run("");
 
   opt_solver_socket_name(0, GMSH_SET, o->solver.input[0]->value());
 
@@ -3260,7 +3260,7 @@ void optionWindow::updateViewGroup(int index)
   opt_view_timestep(index, GMSH_GUI, 0);
   opt_view_show_time(index, GMSH_GUI, 0);
 
-  if(data->getNumVectors() || data->getNumTensors())
+  if(data->getNumVectors() || data->getNumTensors() || data->isRemote())
     view.vector->activate();
   else
     view.vector->deactivate();
diff --git a/Fltk/pluginWindow.cpp b/Fltk/pluginWindow.cpp
index ddb50b8f1f..0c442cfc97 100644
--- a/Fltk/pluginWindow.cpp
+++ b/Fltk/pluginWindow.cpp
@@ -127,8 +127,13 @@ static void plugin_run_cb(Fl_Widget *w, void *data)
     if(FlGui::instance()->plugins->view_browser->selected(i)) {
       no_view_selected = false;
       try{
-        if(i - 1 >= 0 && i - 1 < (int)PView::list.size())
-          p->execute(PView::list[i - 1]);
+        if(i - 1 >= 0 && i - 1 < (int)PView::list.size()){
+          PView *view = PView::list[i - 1];
+          if(view->getData()->isRemote())
+            p->executeRemote(view);
+          else
+            p->execute(view);
+        }
         else
           p->execute(0);
       }
diff --git a/Fltk/solverWindow.cpp b/Fltk/solverWindow.cpp
index 3abdb95bd9..7a34eb2acc 100644
--- a/Fltk/solverWindow.cpp
+++ b/Fltk/solverWindow.cpp
@@ -9,8 +9,8 @@
 #include <FL/Fl_Return_Button.H>
 #include <FL/Fl_Browser.H>
 #include "GmshMessage.h"
-#include "GmshRemote.h"
 #include "GmshSocket.h"
+#include "ConnectionManager.h"
 #include "GModel.h"
 #include "PView.h"
 #include "OpenFile.h"
@@ -28,9 +28,9 @@
 
 class FlGmshServer : public GmshServer{
  private:
-  GmshRemote *_remote;
+  ConnectionManager *_remote;
  public:
-  FlGmshServer(GmshRemote *remote) : _remote(remote), GmshServer() {}
+  FlGmshServer(ConnectionManager *remote) : _remote(remote), GmshServer() {}
   ~FlGmshServer() {}
   int SystemCall(const char *str)
   { 
@@ -76,7 +76,7 @@ class FlGmshServer : public GmshServer{
   }
 };
 
-void GmshRemote::run(std::string args)
+void ConnectionManager::run(std::string args)
 {
  new_connection:
   
@@ -93,7 +93,7 @@ void GmshRemote::run(std::string args)
 
   // find associated solver window if there is one
   solverWindow *window = 0;
-  for(std::map<int, GmshRemote*>::iterator it = _all.begin(); 
+  for(std::map<int, ConnectionManager*>::iterator it = _all.begin(); 
       it != _all.end(); it++){
     if(this == it->second){
       if(it->first >= 0 && it->first < NB_SOLVER_MAX){
@@ -142,7 +142,7 @@ void GmshRemote::run(std::string args)
     return;
   }
 
-  Msg::Info("Running '%s'...", name.c_str());
+  Msg::StatusBar(2, true, "Running '%s'...", name.c_str());
 
   bool initOption[5] = {false, false, false, false, false};  
   while(1) {
@@ -226,9 +226,9 @@ void GmshRemote::run(std::string args)
       {
         int n = PView::list.size();
         PView::fillVertexArray(this, length, message);
-        drawContext::global()->draw();
         if(n != (int)PView::list.size())
           FlGui::instance()->updateViews();
+        drawContext::global()->draw();
       }
       break;
     default:
@@ -264,7 +264,7 @@ void GmshRemote::run(std::string args)
   server->Shutdown();
   delete server;
 
-  Msg::Info("...done running '%s'", name.c_str());
+  Msg::StatusBar(2, true, "Done running '%s'", name.c_str());
 
   if(prog.empty()){
     Msg::Info("Client disconnected: starting new connection");
@@ -282,10 +282,10 @@ void solver_cb(Fl_Widget *w, void *data)
   // from the current model name (only if this file actually exists)
   if(!strlen(FlGui::instance()->solver[num]->input[0]->value())){
     std::string inputFile = split[0] + split[1] + 
-      GmshRemote::get(num)->inputFileExtension;
+      ConnectionManager::get(num)->inputFileExtension;
     if(!StatFile(inputFile)){
       FlGui::instance()->solver[num]->input[0]->value(inputFile.c_str());
-      GmshRemote::get(num)->inputFileName = inputFile;
+      ConnectionManager::get(num)->inputFileName = inputFile;
     }
   }
 
@@ -294,7 +294,7 @@ void solver_cb(Fl_Widget *w, void *data)
   if(!strlen(FlGui::instance()->solver[num]->input[1]->value())){
     std::string meshFile = split[0] + split[1] + ".msh";
     FlGui::instance()->solver[num]->input[1]->value(meshFile.c_str());
-    GmshRemote::get(num)->meshFileName = meshFile;
+    ConnectionManager::get(num)->meshFileName = meshFile;
   }
 
   // show the window before calling Solver() to avoid race condition on
@@ -302,7 +302,7 @@ void solver_cb(Fl_Widget *w, void *data)
   // callbacks get messed up)
   FlGui::instance()->solver[num]->win->show();
 
-  GmshRemote::get(num)->runToGetOptions();
+  ConnectionManager::get(num)->runToGetOptions();
 }
 
 static void solver_ok_cb(Fl_Widget *w, void *data)
@@ -349,7 +349,7 @@ static void solver_choose_executable_cb(Fl_Widget *w, void *data)
 static void solver_file_open_cb(Fl_Widget *w, void *data)
 {
   int num = (int)(long)data;
-  std::string pattern = "*" + GmshRemote::get(num)->inputFileExtension;
+  std::string pattern = "*" + ConnectionManager::get(num)->inputFileExtension;
 
   if(fileChooser(0, 0, "Choose", pattern.c_str())) {
     FlGui::instance()->solver[num]->input[0]->value(fileChooserGetName(1).c_str());
@@ -391,38 +391,38 @@ static void solver_command_cb(Fl_Widget *w, void *data)
   int num = ((int *)data)[0];
   int idx = ((int *)data)[1];
 
-  if(GmshRemote::get(num)->popupMessages)
+  if(ConnectionManager::get(num)->popupMessages)
     FlGui::instance()->messages->show(true);
 
-  GmshRemote::get(num)->inputFileName =
+  ConnectionManager::get(num)->inputFileName =
     FlGui::instance()->solver[num]->input[0]->value();
 
-  GmshRemote::get(num)->meshFileName = 
+  ConnectionManager::get(num)->meshFileName = 
     FlGui::instance()->solver[num]->input[1]->value();
 
   int optionIndex = 0;
   for(int i = 0; i < idx; i++)
-    optionIndex += numPercentS(GmshRemote::get(num)->buttonSwitch[i]);
+    optionIndex += numPercentS(ConnectionManager::get(num)->buttonSwitch[i]);
 
   int optionChoice = 0;
   if(optionIndex >= 0 && optionIndex < FlGui::instance()->solver[num]->choice.size())
     optionChoice = FlGui::instance()->solver[num]->choice[optionIndex]->value();
-  GmshRemote::get(num)->runCommand(idx, optionIndex, optionChoice);
+  ConnectionManager::get(num)->runCommand(idx, optionIndex, optionChoice);
 }
 
 static void solver_kill_cb(Fl_Widget *w, void *data)
 {
   int num = (int)(long)data;
-  GmshRemote::get(num)->kill();
+  ConnectionManager::get(num)->kill();
 }
 
 solverWindow::solverWindow(int num, int deltaFontSize)
 {
   FL_NORMAL_SIZE -= deltaFontSize;
 
-  int numOptions = GmshRemote::get(num)->optionName.size();
-  for(unsigned int i = 0; i < GmshRemote::get(num)->optionName.size(); i++){
-    if(GmshRemote::get(num)->optionName[i].empty()){
+  int numOptions = ConnectionManager::get(num)->optionName.size();
+  for(unsigned int i = 0; i < ConnectionManager::get(num)->optionName.size(); i++){
+    if(ConnectionManager::get(num)->optionName[i].empty()){
       numOptions = i;
       break;
     }
@@ -485,21 +485,21 @@ solverWindow::solverWindow(int num, int deltaFontSize)
       for(int i = 0; i < numOptions; i++) {
         Fl_Choice *c = new Fl_Choice
           (2 * WB, 2 * WB + (4 + i) * BH, LL, BH, 
-           GmshRemote::get(num)->optionName[i].c_str());
+           ConnectionManager::get(num)->optionName[i].c_str());
         c->align(FL_ALIGN_RIGHT);
         choice.push_back(c);
       }
 
       static int arg[NB_SOLVER_MAX][5][2];
-      command.resize(GmshRemote::get(num)->buttonName.size());
+      command.resize(ConnectionManager::get(num)->buttonName.size());
       for(unsigned int i = 0; i < command.size(); i++) {
         arg[num][i][0] = num;
         arg[num][i][1] = i;
         command[i] = new Fl_Button
           ((2 + i) * WB + i * BBS, 3 * WB + (4 + numOptions) * BH,
-           BBS, BH, GmshRemote::get(num)->buttonName[i].c_str());
+           BBS, BH, ConnectionManager::get(num)->buttonName[i].c_str());
         command[i]->callback(solver_command_cb, (void *)arg[num][i]);
-        if(GmshRemote::get(num)->buttonName[i].empty())
+        if(ConnectionManager::get(num)->buttonName[i].empty())
           command[i]->hide();
       }
 
@@ -519,10 +519,10 @@ solverWindow::solverWindow(int num, int deltaFontSize)
         (2 * WB, 2 * WB + 1 * BH, width - 4 * WB, height - 4 * WB - BH);
       o->add(" ");
       add_multiline_in_browser
-        (o, "@c@b@.", GmshRemote::get(num)->name.c_str(), false);
+        (o, "@c@b@.", ConnectionManager::get(num)->name.c_str(), false);
       o->add(" ");
       add_multiline_in_browser
-        (o, "@c@. ", GmshRemote::get(num)->help.c_str(), false);
+        (o, "@c@. ", ConnectionManager::get(num)->help.c_str(), false);
 
       g->end();
     }
diff --git a/Graphics/gl2ps.cpp b/Graphics/gl2ps.cpp
index 120926f903..4772ea013e 100644
--- a/Graphics/gl2ps.cpp
+++ b/Graphics/gl2ps.cpp
@@ -27,31 +27,9 @@
  * library in the file named "COPYING.GL2PS"; if not, I will be glad
  * to provide one.
  *
- * Contributors:
- *   Michael Sweet <mike@easysw.com>
- *   Marc Ume <marc.ume@digitalgraphics.be>
- *   Jean-Francois Remacle <remacle@gce.ucl.ac.be>
- *   Bart Kaptein <B.L.Kaptein@lumc.nl>
- *   Quy Nguyen-Dai <quy@nguyendai.org>
- *   Sam Buss <sbuss@ucsd.edu>
- *   Shane Hill <Shane.Hill@dsto.defence.gov.au>
- *   Romain Boman <r_boman@yahoo.fr>
- *   Rouben Rostamian <rostamian@umbc.edu>
- *   Diego Santa Cruz <Diego.SantaCruz@epfl.ch>
- *   Shahzad Muzaffar <Shahzad.Muzaffar@cern.ch>
- *   Lassi Tuura <lassi.tuura@cern.ch>
- *   Guy Barrand <barrand@lal.in2p3.fr>
- *   Prabhu Ramachandran <prabhu@aero.iitm.ernet.in>
- *   Micha Bieber <bieber@traits.de>
- *   Olivier Couet <couet@mail.cern.ch>
- *   Shai Ayal <shaiay@gmail.com>
- *   Fabian Wenzel <wenzel@tu-harburg.de>
- *   Ian D. Gay <gay@sfu.ca>
- *   Cosmin Truta <cosmin@cs.toronto.edu>
- *   Baiju Devani <b.devani@gmail.com>
- *   Alexander Danilov <danilov@lanl.gov>
+ * For the latest info about gl2ps and a full list of contributors,
+ * see http://www.geuz.org/gl2ps/.
  *
- * For the latest info about gl2ps, see http://www.geuz.org/gl2ps/.
  * Please report all bugs and problems to <gl2ps@geuz.org>.
  */
 
diff --git a/Graphics/gl2ps.h b/Graphics/gl2ps.h
index c9803c15b9..29c82762a4 100644
--- a/Graphics/gl2ps.h
+++ b/Graphics/gl2ps.h
@@ -27,7 +27,9 @@
  * library in the file named "COPYING.GL2PS"; if not, I will be glad
  * to provide one.
  *
- * For the latest info about gl2ps, see http://www.geuz.org/gl2ps/.
+ * For the latest info about gl2ps and a full list of contributors,
+ * see http://www.geuz.org/gl2ps/.
+ *
  * Please report all bugs and problems to <gl2ps@geuz.org>.
  */
 
@@ -78,7 +80,7 @@
 
 #define GL2PS_MAJOR_VERSION 1
 #define GL2PS_MINOR_VERSION 3
-#define GL2PS_PATCH_VERSION 3
+#define GL2PS_PATCH_VERSION 4
 #define GL2PS_EXTRA_VERSION "-cvs"
 
 #define GL2PS_VERSION (GL2PS_MAJOR_VERSION + \
diff --git a/Plugin/Plugin.cpp b/Plugin/Plugin.cpp
index ebbaba6678..2af25732b4 100644
--- a/Plugin/Plugin.cpp
+++ b/Plugin/Plugin.cpp
@@ -3,6 +3,7 @@
 // See the LICENSE.txt file for license information. Please report all
 // bugs and problems to <gmsh@geuz.org>.
 
+#include <sstream>
 #include <stdio.h>
 #include <string.h>
 #include "GmshConfig.h"
@@ -38,6 +39,38 @@ void GMSH_Plugin::catchErrorMessage(char *errorMessage) const
   strcpy(errorMessage, str.c_str());
 }
 
+PView *GMSH_PostPlugin::executeRemote(PView *view)
+{
+  int j = -1, remoteIndex = -1;
+  for(unsigned int i = 0; i < PView::list.size(); i++){
+    if(PView::list[i]->getData()->isRemote()) j++;
+    if(PView::list[i]->getNum() == view->getNum()){
+      remoteIndex = j;
+      break;
+    }
+  }
+  if(remoteIndex < 0){
+    Msg::Error("Unable to determine index of remote view");
+    return view;
+  }
+  
+  for(int i = 0; i < getNbOptions(); i++)
+    if(getOption(i)->str == "iView") getOption(i)->def = remoteIndex;
+  
+  std::ostringstream sstream;
+  for(int i = 0; i < getNbOptionsStr(); i++)
+    sstream << "Plugin(" << getName() << ")." << getOptionStr(i)->str 
+            <<  "= \"" << getOptionStr(i)->def << "\";\n";
+  for(int i = 0; i < getNbOptions(); i++)
+    sstream << "Plugin(" << getName() << ")." << getOption(i)->str 
+            << "=" << getOption(i)->def << ";\n";
+  sstream << "Plugin(" << getName() << ").Run;\n";
+  
+  std::string options = sstream.str();
+  view->getData()->fillRemoteVertexArrays(options);
+  return view;
+}
+
 PView *GMSH_PostPlugin::getView(int index, PView *view)
 {
   if(index < 0)
diff --git a/Plugin/Plugin.h b/Plugin/Plugin.h
index d20167ef90..10c359a76b 100644
--- a/Plugin/Plugin.h
+++ b/Plugin/Plugin.h
@@ -83,6 +83,8 @@ class GMSH_PostPlugin : public GMSH_Plugin
   // view is simply modified, else, a new view is added in the view
   // list
   virtual PView *execute(PView *) = 0;
+  // excute on a remote dataset
+  virtual PView *executeRemote(PView *);
   // get the view given an index and a default value
   virtual PView *getView(int index, PView *view);
   // get the data in list format
diff --git a/Post/PView.cpp b/Post/PView.cpp
index a297a05f66..41c5dea242 100644
--- a/Post/PView.cpp
+++ b/Post/PView.cpp
@@ -180,7 +180,7 @@ void PView::setOptions(PViewOptions *val)
 
 PViewData *PView::getData(bool useAdaptiveIfAvailable)
 { 
-  if(useAdaptiveIfAvailable && _data->isAdaptive())
+  if(useAdaptiveIfAvailable && _data->isAdaptive() && !_data->isRemote())
     return _data->getAdaptiveData()->getData();
   else
     return _data;
diff --git a/Post/PView.h b/Post/PView.h
index 6efef65ab9..c577b4c0c9 100644
--- a/Post/PView.h
+++ b/Post/PView.h
@@ -17,7 +17,7 @@ class VertexArray;
 class smooth_normals;
 class GModel;
 class GMSH_PostPlugin;
-class GmshRemote;
+class ConnectionManager;
 
 // A post-processing view.
 class PView{
@@ -118,7 +118,8 @@ class PView{
   void fillVertexArrays();
 
   // fill a vertex array using a raw stream of bytes
-  static void fillVertexArray(GmshRemote *remote, int length, const char *data);
+  static void fillVertexArray(ConnectionManager *remote, int length, 
+                              const char *data);
 
   // smoothed normals
   smooth_normals *normals;
diff --git a/Post/PViewData.h b/Post/PViewData.h
index 5cdb13e9b0..70398f5dca 100644
--- a/Post/PViewData.h
+++ b/Post/PViewData.h
@@ -199,7 +199,7 @@ class PViewData {
   
   // ask to fill vertex arrays remotely
   virtual bool isRemote(){ return false; }
-  virtual int fillRemoteVertexArrays(){ return 0; }
+  virtual int fillRemoteVertexArrays(std::string &options){ return 0; }
 
   // I/O routines
   virtual bool writeSTL(std::string fileName);
diff --git a/Post/PViewDataRemote.h b/Post/PViewDataRemote.h
index 1a8c769e80..e4f888b4d2 100644
--- a/Post/PViewDataRemote.h
+++ b/Post/PViewDataRemote.h
@@ -9,57 +9,40 @@
 #include <vector>
 #include <string>
 #include "GmshMessage.h"
-#include "GmshRemote.h"
+#include "ConnectionManager.h"
 #include "GmshSocket.h"
 #include "PViewData.h"
 #include "SBoundingBox3d.h"
-#include "Options.h"
-#include "StringUtils.h"
-#include "Context.h"
 
 // The container for a remote dataset (does not contain any actual
-// data!)
+// data)
 class PViewDataRemote : public PViewData {
  private: 
-  int _numTimeSteps;
+  ConnectionManager *_remote;
   double _min, _max;
-  std::vector<double> _timeStepMin, _timeStepMax;
+  int _numTimeSteps;
+  double _time;
   SBoundingBox3d _bbox;
-  std::vector<double> _time;
-  GmshRemote *_remote;
  public:
-  PViewDataRemote(GmshRemote *remote, double min, double max, double time,
-                  SBoundingBox3d &bbox)
-    : _remote(remote), _numTimeSteps(1), _min(min), _max(max), _bbox(bbox)
-  {
-    _time.push_back(time);
-  }
+  PViewDataRemote(ConnectionManager *remote, double min, double max, int numsteps, 
+                  double time, SBoundingBox3d &bbox)
+    : _remote(remote), _min(min), _max(max), _numTimeSteps(numsteps), 
+      _time(time), _bbox(bbox) {}
   ~PViewDataRemote(){}
-  bool finalize(){ return false;}
+  bool finalize(){ return true; }
   int getNumTimeSteps(){ return _numTimeSteps; }
   double getMin(int step=-1){ return _min; }
   double getMax(int step=-1){ return _max; }
   SBoundingBox3d getBoundingBox(int step=-1){ return _bbox; }
-  double getTime(int step)
-  {
-    if(step >= 0 && step < (int)_time.size()) return _time[step];
-    return 0.; 
-  }
-  int getNumElements(int step=-1, int ent=-1)
-  { 
-    // hack so that it does not retrn 0
-    return -1; 
-  }  
+  double getTime(int step){ return _time; }
+  // need to return != 0 for "empty" tests
+  int getNumElements(int step=-1, int ent=-1){ return -1; }  
   void setMin(double min){ _min = min; }
-  void setMax(double max){ _min = max; }
+  void setMax(double max){ _max = max; }
   void setBoundingBox(SBoundingBox3d bbox){ _bbox = bbox; }
-  void setTime(int step, double time)
-  {
-    if(step >= (int)_time.size()) _time.resize(step + 1);
-    _time[step] = time;
-  }
+  void setTime(double time){ _time = time; }
   bool isRemote(){ return true; }
-  int fillRemoteVertexArrays()
+  int fillRemoteVertexArrays(std::string &options)
   {
     GmshServer *server = _remote->getServer();
     if(!server){
@@ -67,10 +50,6 @@ class PViewDataRemote : public PViewData {
       return 1;
     }
     setDirty(true);
-    std::string fileName = CTX::instance()->homeDir + CTX::instance()->tmpFileName;
-    // FIXME: until we rewrite the option code and allow nice serialization ;-)
-    PrintOptions(0, GMSH_FULLRC, 0, 0, fileName.c_str());
-    std::string options = ConvertFileToString(fileName);
     server->SendString(GmshSocket::GMSH_VERTEX_ARRAY, options.c_str());
     return 1;
   }
diff --git a/Post/PViewVertexArrays.cpp b/Post/PViewVertexArrays.cpp
index 112f6147b9..f621afc81a 100644
--- a/Post/PViewVertexArrays.cpp
+++ b/Post/PViewVertexArrays.cpp
@@ -6,7 +6,7 @@
 #include <string.h>
 #include "GmshMessage.h"
 #include "GmshDefines.h"
-#include "GmshRemote.h"
+#include "ConnectionManager.h"
 #include "Iso.h"
 #include "PView.h"
 #include "PViewOptions.h"
@@ -18,6 +18,8 @@
 #include "Context.h"
 #include "OpenFile.h"
 #include "mathEvaluator.h"
+#include "Options.h"
+#include "StringUtils.h"
 
 static void saturate(int nb, double val[PVIEW_NMAX][9], double vmin, double vmax, 
                      int i0=0, int i1=1, int i2=2, int i3=3, 
@@ -1070,7 +1072,14 @@ class initPView {
 
     p->deleteVertexArrays();
 
-    if(data->fillRemoteVertexArrays()) return;
+    if(data->isRemote()){
+      // FIXME: need to rewrite option code and add nice serialization
+      std::string fileName = CTX::instance()->homeDir + CTX::instance()->tmpFileName;
+      PrintOptions(0, GMSH_FULLRC, 0, 0, fileName.c_str());
+      std::string options = ConvertFileToString(fileName);
+      data->fillRemoteVertexArrays(options);
+      return;
+    }
 
     if(opt->useGenRaise) opt->createGeneralRaise();
 
@@ -1119,20 +1128,29 @@ void PView::fillVertexArrays()
   init(this);
 }
 
-void PView::fillVertexArray(GmshRemote *remote, int length, const char *bytes)
+void PView::fillVertexArray(ConnectionManager *remote, int length, const char *bytes)
 {
   int is = sizeof(int), ds = sizeof(double);
 
-  if(length < 2 * is + 9 * ds){
+  if(length < 4 * is + 9 * ds){
     Msg::Error("Too few bytes to create vertex array: %d", length);
     return;
   }
   
+  std::string name;
+
   int index = 0;
   int num; memcpy(&num, &bytes[index], is); index += is;
+  int ss; memcpy(&ss, &bytes[index], is); index += is;
+  if(ss){
+    std::vector<char> n(ss);
+    memcpy(&n[0], &bytes[index], ss); index += ss;
+    for(unsigned int i = 0; i < n.size(); i++) name += n[i];
+  }
   int type; memcpy(&type, &bytes[index], is); index += is;
   double min; memcpy(&min, &bytes[index], ds); index += ds;
   double max; memcpy(&max, &bytes[index], ds); index += ds;
+  int numsteps; memcpy(&numsteps, &bytes[index], is); index += is;
   double time; memcpy(&time, &bytes[index], ds); index += ds;
   double xmin; memcpy(&xmin, &bytes[index], ds); index += ds;
   double ymin; memcpy(&ymin, &bytes[index], ds); index += ds;
@@ -1143,15 +1161,26 @@ void PView::fillVertexArray(GmshRemote *remote, int length, const char *bytes)
   
   Msg::Debug("Filling vertex array (type %d) in view num %d", type, num);
 
+  SBoundingBox3d bbox(xmin, ymin, zmin, xmax, ymax, zmax);
+
   PView *p = PView::getViewByNum(num);
   if(!p){
     Msg::Info("View num %d does not exist: creating new view", num);
-    SBoundingBox3d bb(xmin, ymin, zmin, xmax, ymax, zmax);
-    PViewData *data = new PViewDataRemote(remote, min, max, time, bb);
-    data->setName("Remote");
+    PViewData *data = new PViewDataRemote(remote, min, max, numsteps, time, bbox);
+    data->setName(name + " (remote)");
     p = new PView(data, num);
     SetBoundingBox();
   }
+  else{
+    PViewDataRemote *data = dynamic_cast<PViewDataRemote*>(p->getData());
+    if(data){
+      data->setMin(min);
+      data->setMax(max);
+      data->setTime(time);
+    }
+  }
+
+  p->getOptions()->tmpBBox += bbox;
 
   switch(type){
   case 1:
-- 
GitLab