From 4a35b97d8a6662dd8593a6f4c003af53f27ebc8f Mon Sep 17 00:00:00 2001
From: Christophe Geuzaine <cgeuzaine@ulg.ac.be>
Date: Sat, 1 Oct 2011 15:35:51 +0000
Subject: [PATCH] move onelab inside gmsh to make it easy to build a demo gui

---
 Common/GmshSocket.h    |   6 +
 Common/onelab.h        | 547 +++++++++++++++++++++++++++++++++++++++++
 Fltk/CMakeLists.txt    |   1 +
 Fltk/FlGui.cpp         |   6 +
 Fltk/FlGui.h           |   2 +
 Fltk/graphicWindow.cpp |   3 +
 Fltk/onelabWindow.cpp  | 195 +++++++++++++++
 Fltk/onelabWindow.h    |  27 ++
 8 files changed, 787 insertions(+)
 create mode 100644 Common/onelab.h
 create mode 100644 Fltk/onelabWindow.cpp
 create mode 100644 Fltk/onelabWindow.h

diff --git a/Common/GmshSocket.h b/Common/GmshSocket.h
index 6d46f035a8..9210aec96d 100644
--- a/Common/GmshSocket.h
+++ b/Common/GmshSocket.h
@@ -70,6 +70,7 @@ class GmshSocket{
     GMSH_MERGE_FILE   = 20,
     GMSH_PARSE_STRING = 21,
     GMSH_VERTEX_ARRAY = 22,
+    GMSH_ONELAB_PARAM = 23,
     GMSH_SPEED_TEST   = 30,
     GMSH_OPTION_1     = 100,
     GMSH_OPTION_2     = 101,
@@ -204,6 +205,11 @@ class GmshSocket{
     }
     return 0;
   }
+  int ReceiveMessage(int len, void *buffer)
+  {
+    if(_ReceiveData(buffer, len) == len) return 1;
+    return 0;
+  }
   // str should be allocated with size (len+1)
   int ReceiveString(int len, char *str)
   {
diff --git a/Common/onelab.h b/Common/onelab.h
new file mode 100644
index 0000000000..431f6fb47c
--- /dev/null
+++ b/Common/onelab.h
@@ -0,0 +1,547 @@
+// ONELAB - Copyright (C) 2011 ULg-UCL
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use, copy,
+// modify, merge, publish, distribute, and/or sell copies of the
+// Software, and to permit persons to whom the Software is furnished
+// to do so, provided that the above copyright notice(s) and this
+// permission notice appear in all copies of the Software and that
+// both the above copyright notice(s) and this permission notice
+// appear in supporting documentation.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE
+// COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR
+// ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY
+// DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+// WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+// ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+// OF THIS SOFTWARE.
+
+#ifndef _ONELAB_H_
+#define _ONELAB_H_
+
+#include <string>
+#include <vector>
+#include <set>
+#include <map>
+#include <iostream>
+#include <sstream>
+#include "GmshSocket.h";
+
+namespace onelab{
+
+  typedef enum { NUMBER = 1, STRING = 2, REGION = 3, FUNCTION = 4 } parameterType;
+
+  // The base parameter class.
+  class parameter{
+  private:
+    // the name of the parameter, including its "path" in the
+    // parameter hierarchy. The path separator '/' can be followed by
+    // a number to force ordering (hence a parameter name cannot start
+    // with a number).
+    std::string _name;
+    // optional help strings
+    std::string _shortHelp, _help;
+    // client code(s) for which this parameter makes sense
+    std::set<std::string> _clients;
+  public:
+    parameter(const std::string &name, const std::string &shortHelp="", 
+              const std::string &help="")
+      : _name(name), _shortHelp(shortHelp), _help(help){}
+    void setShortHelp(std::string &shortHelp){ _shortHelp = shortHelp; }
+    void setHelp(std::string &help){ _help = help; }
+    void setClients(std::set<std::string> &clients){ _clients = clients; }
+    void addClient(std::string &client){ _clients.insert(client); }
+    void addClients(std::set<std::string> &clients)
+    { 
+      _clients.insert(clients.begin(), clients.end()); 
+    }
+    virtual parameterType getType() const = 0;
+    std::string getTypeAsString()
+    {
+      std::ostringstream sstream;
+      sstream << getType();
+      return sstream.str();
+    }
+    const std::string &getName() const { return _name; }
+    const std::string &getShortHelp() const { return _shortHelp; }
+    const std::string &getHelp() const { return _help; }
+    const std::set<std::string> &getClients() const { return _clients; }
+    char charSep(){ return '\0'; }
+    std::string sanitize(const std::string &in)
+    {
+      std::string out(in);
+      for(unsigned int i = 0; i < in.size(); i++)
+        if(out[i] == charSep()) out[i] = ' ';
+      return out;
+    }
+    virtual std::string toChar() = 0;
+    virtual void fromChar(const std::string &c){}
+  };
+  
+  class parameterLessThan{
+  public:
+    bool operator()(const parameter *p1, const parameter *p2) const
+    {
+      return p1->getName() < p2->getName();
+    }
+  };
+
+  // The number class. Numbers are stored internally as double
+  // precision real numbers. Currently all more complicated types
+  // (complex numbers, vectors, etc.) are supposed to be encapsulated
+  // in functions. We will probably add more base types in the future
+  // to make the interface nicer.
+  class number : public parameter{
+  private:
+    double _value;
+    double _defaultValue, _min, _max, _step;
+    std::vector<double> _choices;
+  public:
+    number(const std::string &name) 
+      : parameter(name), _value(0.), _defaultValue(0.), 
+        _min(1.), _max(0.), _step(0.)
+    {
+    }
+    number(const std::string &name, double defaultValue,
+           const std::string &shortHelp="", const std::string &help="") 
+      : parameter(name, shortHelp, help), _value(defaultValue), 
+        _defaultValue(defaultValue), _min(1.), _max(0.), _step(0.)
+    {
+    }
+    void setValue(double value){ _value = value; }
+    void setMin(double min){ _min = min; }
+    void setMax(double max){ _min = max; }
+    void setStep(double step){ _step = step; }
+    void setChoices(std::vector<double> &choices){ _choices = choices; }
+    parameterType getType() const { return NUMBER; }
+    double getValue() const { return _value; }
+    double getDefaultValue() const { return _defaultValue; }
+    std::string toChar()
+    {
+      std::ostringstream sstream;
+      sstream << getType() << charSep() << sanitize(getName()) << charSep() 
+              << sanitize(getShortHelp()) << charSep() 
+              << sanitize(getHelp()) << charSep() << _value << charSep()
+              << _defaultValue << charSep()
+              << _min << charSep() << _max << charSep() << _step << charSep()
+              << _choices.size() << charSep();
+      for(unsigned int i = 0; i < _choices.size(); i++)
+        sstream << _choices[i] << charSep();
+      sstream << getClients().size() << charSep();
+      for(std::set<std::string>::iterator it = getClients().begin();
+          it != getClients().end(); it++)
+        sstream << *it << charSep();
+      return sstream.str();
+    }
+  };
+
+  // The string class.
+  class string : public parameter{
+  private:
+    std::string _value;
+    std::string _defaultValue;
+    std::vector<std::string> _choices;
+  public:
+    string(const std::string &name) 
+      : parameter(name), _value(""), _defaultValue("")
+    {
+    }
+    string(const std::string &name, const std::string &defaultValue, 
+           const std::string &shortHelp="", const std::string &help="") 
+      : parameter(name, shortHelp, help), _value(defaultValue), 
+        _defaultValue(defaultValue)
+    {
+    }
+    void setValue(const std::string &value){ _value = value; }
+    void setChoices(std::vector<std::string> &choices){ _choices = choices; }
+    parameterType getType() const { return STRING; }
+    const std::string &getValue() const { return _value; }
+    const std::string &getDefaultValue() const { return _defaultValue; }
+    std::string toChar()
+    {
+      std::ostringstream sstream;
+      sstream << getType() << charSep() << sanitize(getName()) << charSep() 
+              << sanitize(getShortHelp()) << charSep() 
+              << sanitize(getHelp()) << charSep() << sanitize(_value) << charSep()
+              << sanitize(_defaultValue) << charSep()
+              << _choices.size() << charSep();
+      for(unsigned int i = 0; i < _choices.size(); i++)
+        sstream << sanitize(_choices[i]) << charSep();
+      sstream << getClients().size() << charSep();
+      for(std::set<std::string>::iterator it = getClients().begin();
+          it != getClients().end(); it++)
+        sstream << *it << charSep();
+      return sstream.str();
+    }
+  };
+
+  // The region class. A region can be any kind of geometrical entity.
+  class region : public parameter{
+  private:
+    std::string _value, _defaultValue;
+    std::vector<std::string> _choices;
+  public:
+    region(const std::string &name) 
+      : parameter(name), _value(""), _defaultValue("")
+    {
+    }
+    region(const std::string &name, const std::string &defaultValue,
+           const std::string &shortHelp="", const std::string &help="") 
+      : parameter(name, shortHelp, help), _value(defaultValue), 
+        _defaultValue(defaultValue)
+    {
+    }
+    parameterType getType() const { return REGION; }
+    const std::string &getValue() const { return _value; }
+    const std::string &getDefaultValue() const { return _defaultValue; }
+    std::string toChar()
+    {
+      std::ostringstream sstream;
+      sstream << getType() << charSep() << sanitize(getName()) << charSep() 
+              << sanitize(getShortHelp()) << charSep() << sanitize(getHelp()) 
+              << charSep() << _value << charSep() << _defaultValue << charSep()
+              << _choices.size() << charSep();
+      for(unsigned int i = 0; i < _choices.size(); i++)
+        sstream << _choices[i] << charSep();
+      sstream << getClients().size() << charSep();
+      for(std::set<std::string>::iterator it = getClients().begin();
+          it != getClients().end(); it++)
+        sstream << *it << charSep();
+      return sstream.str();
+    }
+  };
+
+  // The (possibly piece-wise defined on regions) function
+  // class. Currently functions are entirely client-dependent: they
+  // are just represented internally as strings. Again, we might want
+  // to specialize in the future to make the interface more refined.
+  class function : public parameter{
+  private:
+    std::string _value, _defaultValue;
+    std::map<std::string, std::string> _pieceWiseValues;
+    std::vector<std::string> _choices;
+  public:
+    function(const std::string &name) 
+      : parameter(name), _value(""), _defaultValue("")
+    {
+    }
+    function(const std::string &name, const std::string &defaultValue,
+             const std::string &shortHelp="", const std::string &help="") 
+      : parameter(name, shortHelp, help), _value(defaultValue), 
+        _defaultValue(defaultValue)
+    {
+    }
+    void setValue(const std::string &value, const std::string &region="")
+    {
+      if(region.empty())
+        _value = value;
+      else
+        _pieceWiseValues[region] = value;
+    }
+    parameterType getType() const { return FUNCTION; }
+    const std::string getValue(const std::string &region="") const
+    {
+      if(region.size()){
+        std::map<std::string, std::string>::const_iterator it =
+          _pieceWiseValues.find(region);
+        if(it != _pieceWiseValues.end()) return it->second;
+        return "";
+      }
+      else return _value; 
+    }
+    const std::map<std::string, std::string> &getPieceWiseValues() const 
+    {
+      return _pieceWiseValues; 
+    }
+    const std::string &getDefaultValue() const { return _defaultValue; }
+    std::string toChar()
+    {
+      std::ostringstream sstream;
+      sstream << getType() << charSep() << sanitize(getName()) << charSep() 
+              << sanitize(getShortHelp()) << charSep() 
+              << sanitize(getHelp()) << charSep() << sanitize(_value) << charSep()
+              << sanitize(_defaultValue) << charSep()
+              << _pieceWiseValues.size() << charSep();
+        for(std::map<std::string, std::string>::const_iterator it =
+              _pieceWiseValues.begin(); it != _pieceWiseValues.end(); it++)
+          sstream << sanitize(it->first) << charSep() 
+                  << sanitize(it->second) << charSep();
+      sstream << _choices.size() << charSep();
+      for(unsigned int i = 0; i < _choices.size(); i++)
+        sstream << sanitize(_choices[i]) << charSep();
+      sstream << getClients().size() << charSep();
+      for(std::set<std::string>::iterator it = getClients().begin();
+          it != getClients().end(); it++)
+        sstream << *it << charSep();
+      return sstream.str();
+    }
+  };
+
+  // The parameter space, i.e., the set of parameters stored and
+  // handled by the onelab server.
+  class parameterSpace{
+  private:
+    std::set<number*, parameterLessThan> _numbers;
+    std::set<string*, parameterLessThan> _strings;
+    std::set<region*, parameterLessThan> _regions;
+    std::set<function*, parameterLessThan> _functions;
+    // set a parameter in the parameter space; if it already exists,
+    // use the new value but make sure to add new clients if necessary
+    template <class T> bool _set(T &p, std::set<T*, parameterLessThan> &parameters)
+    {
+      std::set<std::string> clients;
+      typename std::set<T*, parameterLessThan>::iterator it = parameters.find(&p);
+      if(it != parameters.end()){
+        parameters.erase(it);
+        T* oldp = *it;
+        clients = oldp->getClients();
+        delete oldp;
+      }
+      T* newp = new T(p);
+      newp->addClients(clients);
+      parameters.insert(newp);
+      return true;
+    }
+    // get the parameter matching the given name, or all the
+    // parameters in the category if no name is given
+    template <class T> bool _get(std::vector<T> &p, const std::string &name,
+                                 std::set<T*, parameterLessThan> &parameters)
+    {
+      if(name.empty()){
+        for(typename std::set<T*, parameterLessThan>::iterator it = parameters.begin();
+            it != parameters.end(); it++)
+          p.push_back(**it);
+      }
+      else{
+        T tmp(name);
+        typename std::set<T*, parameterLessThan>::iterator it = parameters.find(&tmp);
+        if(it != parameters.end())
+          p.push_back(**it);
+      }
+      return true;
+    }
+  public:
+    parameterSpace(){}
+    ~parameterSpace()
+    {
+      for(std::set<number*, parameterLessThan>::iterator it = _numbers.begin();
+          it != _numbers.end(); it++)
+        delete *it;
+      for(std::set<string*, parameterLessThan>::iterator it = _strings.begin();
+          it != _strings.end(); it++)
+        delete *it;
+      for(std::set<region*, parameterLessThan>::iterator it = _regions.begin();
+          it != _regions.end(); it++)
+        delete *it;
+      for(std::set<function*, parameterLessThan>::iterator it = _functions.begin();
+          it != _functions.end(); it++)
+        delete *it;
+    }
+    bool set(number &p){ return _set(p, _numbers); }
+    bool set(string &p){ return _set(p, _strings); }
+    bool set(region &p){ return _set(p, _regions); }
+    bool set(function &p){ return _set(p, _functions); }
+    bool get(std::vector<number> &p, const std::string &name="")
+    {
+      return _get(p, name, _numbers); 
+    }
+    bool get(std::vector<string> &p, const std::string &name="")
+    {
+      return _get(p, name, _strings); 
+    }
+    bool get(std::vector<region> &p, const std::string &name="")
+    {
+      return _get(p, name, _regions); 
+    }
+    bool get(std::vector<function> &p, const std::string &name="")
+    {
+      return _get(p, name, _functions);
+    }
+  };
+
+  // The onelab client: a class that communicates with the onelab
+  // server. Each client should be derived from this one.
+  class client{
+  protected:
+    // the name of the client
+    std::string _name;
+  public:
+    client(const std::string &name) : _name(name){}
+    virtual ~client(){}
+    std::string getName(){ return _name; }
+    virtual bool run(const std::string &what) = 0;
+    virtual bool kill() = 0;
+  };
+
+  // The onelab server: a singleton that stores the parameter space
+  // and interacts with onelab clients.
+  class server{
+  private:
+    // the unique server
+    static server *_server;
+    // the address of the server
+    std::string _address;
+    // the connected clients, indexed by name
+    std::map<std::string, client*> _clients;
+    // the parameter space
+    parameterSpace _parameterSpace;
+  public:
+    server(const std::string &address="") : _address(address) {}
+    ~server(){}
+    static server *instance(const std::string &address="")
+    {
+      if(!_server) _server = new server(address);
+      return _server;
+    }
+    template <class T> bool set(T &p)
+    {
+      // this needs to be locked to avoid race conditions when several
+      // clients try to set a parameter at the same time
+      return _parameterSpace.set(p); 
+    }
+    template <class T> bool get(std::vector<T> &p, const std::string &name="")
+    {
+      return _parameterSpace.get(p, name); 
+    }
+    bool registerClient(client *c)
+    {
+      if(_clients.count(c->getName())) return false;
+      _clients[c->getName()] = c;
+      return true;
+    }
+    typedef std::map<std::string, client*>::iterator citer;
+    citer firstClient(){ return _clients.begin(); }
+    citer lastClient(){ return _clients.end(); }
+    citer findClient(const std::string &name){ return _clients.find(name); }
+    int getNumClients(){ return _clients.size(); }
+  };
+    
+  class localClient : public client{
+  protected:
+    // the pointer to the server
+    server *_server;
+  public:
+    localClient(const std::string &name) : client(name)
+    {
+      _server = server::instance();
+      _server->registerClient(this);
+    }
+    virtual ~localClient(){}
+    template <class T> bool set(T &parameter)
+    {
+      parameter.addClient(_name);
+      _server->set(parameter);
+      return true;
+    }
+    template <class T> bool get(std::vector<T> &parameters,
+                                const std::string &name="")
+    {
+      _server->get(parameters, name);
+      return true;
+    }
+    virtual bool run(const std::string &what){ return false; }
+    virtual bool kill(){ return false; }
+  };
+
+  class localNetworkClient : public localClient{
+  private:
+    // command line to launch the remote network client
+    std::string _commandLine;
+    // pid of the remote network client
+    int _pid;
+  public:
+    localNetworkClient(const std::string &name, const std::string &commandLine)
+      : localClient(name), _commandLine(commandLine){}
+    virtual ~localNetworkClient(){}
+    int getPid(){ return _pid; }
+    void setPid(int pid){ _pid = pid; }
+    virtual bool run(const std::string &what);
+    virtual bool kill();
+  };
+
+  class remoteNetworkClient : public client{
+  private:
+    std::string _serverAddress;
+    // underlying GmshClient
+    GmshClient *_gmshClient;
+  public:
+    remoteNetworkClient(const std::string &name, const std::string &serverAddress)
+      : client(name), _serverAddress(serverAddress)
+    {
+      _gmshClient = new GmshClient();
+      if(_gmshClient->Connect(_serverAddress.c_str()) < 0){
+        delete _gmshClient;
+        _gmshClient = 0;
+      }
+      else{
+        _gmshClient->Start();
+      }
+    }
+    virtual ~remoteNetworkClient()
+    {
+      if(_gmshClient){
+        _gmshClient->Stop();
+        _gmshClient->Disconnect();
+        delete _gmshClient;
+        _gmshClient = 0;
+      }
+    }
+    template <class T> bool set(T &parameter)
+    {
+      if(!_gmshClient) return false;
+      parameter.addClient(_name);
+      std::string msg = parameter.toChar();
+      _gmshClient->SendMessage(GmshSocket::GMSH_ONELAB_PARAM, msg.size(), &msg[0]);
+      return true;
+    }
+    template <class T> bool get(std::vector<T> &parameters, 
+                                const std::string &name="")
+    {
+      if(!_gmshClient) return false;
+      T parameter(name);
+      parameter.addClient(_name);
+      std::string msg = parameter.toChar();
+      _gmshClient->SendMessage(GmshSocket::GMSH_ONELAB_PARAM, msg.size(), &msg[0]);
+      while(1){
+        // stop if we have no communications for 30 seconds
+        int ret = _gmshClient->Select(30, 0);
+        if(!ret){
+          _gmshClient->Info("Timout: aborting remote get");
+          return false;
+        }
+        else if(ret < 0){
+          _gmshClient->Error("Error on select: aborting remote get");
+          return false;
+        }
+        int type, length, swap;
+        if(!_gmshClient->ReceiveHeader(&type, &length, &swap)){
+          _gmshClient->Error("Did not receive message header: aborting remote get");
+          return false;
+        }
+        std::string msg(length);
+        if(!_gmshClient->ReceiveMessage(length, &msg[0])){
+          _gmshClient->Error("Did not receive message body: aborting remote get");
+          return false;
+        }
+        if(type == GmshSocket::GMSH_ONELAB_PARAM){
+          printf("Remote: got %s!\n", msg.c_str());
+          return true;
+        }
+        else{
+          _gmshClient->Error("Unknown message type: aborting remote get");
+          return false;
+        }
+      }
+      return true;
+    }
+  };
+
+}
+
+#endif
diff --git a/Fltk/CMakeLists.txt b/Fltk/CMakeLists.txt
index cbf7407a8f..81c7b0743c 100644
--- a/Fltk/CMakeLists.txt
+++ b/Fltk/CMakeLists.txt
@@ -24,6 +24,7 @@ set(SRC
     projectionEditor.cpp
     classificationEditor.cpp
     partitionDialog.cpp
+    onelabWindow.cpp
 )
 
 file(GLOB HDR RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.h) 
diff --git a/Fltk/FlGui.cpp b/Fltk/FlGui.cpp
index 47f7956326..607205240d 100644
--- a/Fltk/FlGui.cpp
+++ b/Fltk/FlGui.cpp
@@ -24,6 +24,7 @@
 #include "manipWindow.h"
 #include "contextWindow.h"
 #include "solverWindow.h"
+#include "onelabWindow.h"
 #include "aboutWindow.h"
 #include "colorbarWindow.h"
 #include "fileDialogs.h"
@@ -271,6 +272,7 @@ FlGui::FlGui(int argc, char **argv)
   geoContext = new geometryContextWindow(CTX::instance()->deltaFontSize);
   meshContext = new meshContextWindow(CTX::instance()->deltaFontSize);
   about = new aboutWindow();
+  onelab = new onelabWindow();
   for(int i = 0; i < NB_SOLVER_MAX; i++)
     solver.push_back(new solverWindow(i, CTX::instance()->deltaFontSize));
 
@@ -648,6 +650,10 @@ int FlGui::testGlobalShortcuts(int event)
     show = !show;
     status = 2;
   }
+  else if(Fl::test_shortcut('@')) {
+    onelab_cb(0, (void*)"laucnhed_from_shortcut");
+    status = 1;
+  }
   else if(testArrowShortcuts()) {
     status = 1;
   }
diff --git a/Fltk/FlGui.h b/Fltk/FlGui.h
index 8a6f5a22ae..6bdc204365 100644
--- a/Fltk/FlGui.h
+++ b/Fltk/FlGui.h
@@ -33,6 +33,7 @@ class geometryContextWindow;
 class meshContextWindow;
 class aboutWindow;
 class solverWindow;
+class onelabWindow;
 
 class GVertex;
 class GEdge;
@@ -62,6 +63,7 @@ class FlGui{
   geometryContextWindow *geoContext;
   meshContextWindow *meshContext;
   aboutWindow *about;
+  onelabWindow *onelab;
   std::vector<solverWindow*> solver;
  public:
   FlGui(int argc, char **argv);
diff --git a/Fltk/graphicWindow.cpp b/Fltk/graphicWindow.cpp
index 5b5050c9ff..48ced566eb 100644
--- a/Fltk/graphicWindow.cpp
+++ b/Fltk/graphicWindow.cpp
@@ -479,6 +479,9 @@ graphicWindow::graphicWindow(bool main, int numTiles)
   int glheight = CTX::instance()->glSize[1];
   int height = glheight + mheight + sh;
 
+  // FIXME: make sure height < screen_height
+
+
   // no tile should be zero during tile creation
   if(CTX::instance()->msgSize <= 0 || CTX::instance()->msgSize >= glheight){
     mheight = 10;
diff --git a/Fltk/onelabWindow.cpp b/Fltk/onelabWindow.cpp
new file mode 100644
index 0000000000..7aa28c2860
--- /dev/null
+++ b/Fltk/onelabWindow.cpp
@@ -0,0 +1,195 @@
+// Gmsh - Copyright (C) 1997-2011 C. Geuzaine, J.-F. Remacle
+//
+// See the LICENSE.txt file for license information. Please report all
+// bugs and problems to <gmsh@geuz.org>.
+
+#include "onelab.h"
+#include "GmshMessage.h"
+#include "Context.h"
+#include "OS.h"
+#include "FlGui.h"
+#include "paletteWindow.h"
+#include "onelabWindow.h"
+
+// This file contains the Gmsh/FLTK specific parts of the ONELAB
+// interface. You'll need to reimplement this if you plan to build
+// a different ONELAB server.
+
+onelab::server *onelab::server::_server = 0;
+
+class onelabGmshServer : public GmshServer{
+ private:
+  onelab::localNetworkClient *_client;
+ public:
+  onelabGmshServer(onelab::localNetworkClient *client) : GmshServer(), _client(client) {}
+  ~onelabGmshServer() {}
+  int SystemCall(const char *str)
+  { 
+    return ::SystemCall(str); 
+  }
+  int NonBlockingWait(int socket, double waitint, double timeout)
+  { 
+    double start = GetTimeInSeconds();
+    while(1){
+      if(timeout > 0 && GetTimeInSeconds() - start > timeout)
+        return 2; // timout
+
+      if(_client->getPid() < 0)
+        return 1; // process has been killed
+
+      // check if there is data (call select with a zero timeout to
+      // return immediately, i.e., do polling)
+      int ret = Select(0, 0, socket);
+
+      if(ret == 0){ 
+        // nothing available: wait at most waitint seconds, and in the
+        // meantime respond to FLTK events
+        FlGui::instance()->wait(waitint);
+      }
+      else if(ret > 0){ 
+        return 0; // data is there!
+      }
+      else{ 
+        // an error happened
+        _client->setPid(-1);
+        return 1;
+      }
+    }
+  }
+};
+
+bool onelab::localNetworkClient::run(const std::string &what)
+{
+  _pid = 0;
+  onelabGmshServer *server = new onelabGmshServer(this);
+ 
+  std::string sockname = "localhost:1631";
+  std::string command = "getdp -onelab -socket localhost:1631 test.pro &";
+
+  int sock;
+  try{
+    sock = server->Start(command.c_str(), sockname.c_str(), 30);
+  }
+  catch(const char *err){
+    Msg::Error("%s (on socket '%s')", err, sockname.c_str());
+    sock = -1;
+  }
+  
+  if(sock < 0){
+    server->Shutdown();
+    delete server;
+    return false;
+  }
+
+  Msg::StatusBar(2, true, "Running '%s'...", _name.c_str());
+
+  while(1) {
+
+    if(_pid < 0) break;
+    
+    int stop = server->NonBlockingWait(sock, 0.1, 0.);
+    if(stop || _pid < 0) break;
+    
+    int type, length, swap;
+    if(!server->ReceiveHeader(&type, &length, &swap)){
+      Msg::Error("Did not receive message header: stopping server");
+      break;
+    }
+
+    double timer = GetTimeInSeconds();
+    
+    char *message = new char[length + 1];
+    if(!server->ReceiveString(length, message)){
+      Msg::Error("Did not receive message body: stopping server");
+      delete [] message;
+      break;
+    }
+
+    switch (type) {
+    case GmshSocket::GMSH_START:
+      _pid = atoi(message);
+      break;
+    case GmshSocket::GMSH_STOP:
+      _pid = -1;
+      break;
+    case GmshSocket::GMSH_ONELAB_PARAM:
+      printf("server: got onelab param!\n");
+      break;
+    case GmshSocket::GMSH_PROGRESS:
+      Msg::StatusBar(2, false, "%s %s", _name.c_str(), message);
+      break;
+    case GmshSocket::GMSH_INFO:
+      Msg::Direct("%-8.8s: %s", _name.c_str(), message);
+      break;
+    case GmshSocket::GMSH_WARNING:
+      Msg::Direct(2, "%-8.8s: %s", _name.c_str(), message);
+      break;
+    case GmshSocket::GMSH_ERROR:
+      Msg::Direct(1, "%-8.8s: %s", _name.c_str(), message);
+      break;
+    default:
+      Msg::Warning("Received unknown message type (%d)", type);
+      break;
+    }
+
+    delete [] message;
+    FlGui::instance()->check();
+  }
+
+  server->Shutdown();
+  delete server;
+
+  Msg::StatusBar(2, true, "Done running '%s'", _name.c_str());
+
+  return false;
+}
+
+bool onelab::localNetworkClient::kill()
+{
+  if(_pid > 0) {
+    if(KillProcess(_pid)){
+      Msg::Info("Killed '%s' (pid %d)", _name.c_str(), _pid);
+      _pid = -1;
+      return true; 
+    }
+  }
+  _pid = -1;
+  return false;
+}
+
+void onelab_cb(Fl_Widget *w, void *data)
+{
+  printf("onelab has %d clients\n", onelab::server::instance()->getNumClients());
+  for(onelab::server::citer it = onelab::server::instance()->firstClient();
+      it != onelab::server::instance()->lastClient(); it++){
+    onelab::client *c = it->second;
+    printf("client name = %s\n", c->getName().c_str());
+  }
+  FlGui::instance()->onelab->show();
+}
+
+onelabWindow::onelabWindow(int deltaFontSize)
+{
+  FL_NORMAL_SIZE -= deltaFontSize;
+
+  int width = 32 * FL_NORMAL_SIZE;
+  int height = 10 * BH + 3 * WB;
+  
+  _win = new paletteWindow
+    (width, height, CTX::instance()->nonModalWindows ? true : false, "ONELAB");
+  _win->box(GMSH_WINDOW_BOX);
+  {
+    _tree = new Fl_Tree(WB, WB, width - 2 * WB, height - 3 * WB - BH);
+  }
+  
+  _run = new Fl_Button(width - WB - BB, height - WB - BH, BB, BH, "Compute");
+
+  _win->position
+    (CTX::instance()->solverPosition[0], CTX::instance()->solverPosition[1]);
+  _win->end();
+
+  FL_NORMAL_SIZE += deltaFontSize;
+
+  onelab::server::instance()->registerClient(new onelab::localNetworkClient
+                                             ("getdp", "/Users/geuzaine/src/getdp/bin/getdp"));
+}
diff --git a/Fltk/onelabWindow.h b/Fltk/onelabWindow.h
new file mode 100644
index 0000000000..c723229c02
--- /dev/null
+++ b/Fltk/onelabWindow.h
@@ -0,0 +1,27 @@
+// Gmsh - Copyright (C) 1997-2011 C. Geuzaine, J.-F. Remacle
+//
+// See the LICENSE.txt file for license information. Please report all
+// bugs and problems to <gmsh@geuz.org>.
+
+#ifndef _ONELAB_WINDOW_H_
+#define _ONELAB_WINDOW_H_
+
+#include <vector>
+#include <FL/Fl_Window.H>
+#include <FL/Fl_Tree.H>
+#include <FL/Fl_Button.H>
+#include "onelab.h"
+
+class onelabWindow{
+ private:
+  Fl_Window *_win;
+  Fl_Tree *_tree;
+  Fl_Button *_run;
+ public:
+  onelabWindow(int deltaFontSize=0);
+  void show(){ _win->show(); }
+};
+
+void onelab_cb(Fl_Widget *w, void *data);
+
+#endif
-- 
GitLab