From a5df54bb353db1acfb8fad87281d68012c2976a4 Mon Sep 17 00:00:00 2001
From: Christophe Geuzaine <cgeuzaine@ulg.ac.be>
Date: Thu, 3 Jan 2002 10:25:07 +0000
Subject: [PATCH] New client/server model

---
 Common/DefaultOptions.h | 271 +++++++++++++++++++++++++++++-
 Common/GetOptions.cpp   |  15 +-
 Common/Options.cpp      | 362 ++++++++++++++++++++++++++++++++++++++--
 Common/Options.h        | 153 ++++++++++++++++-
 Fltk/Callbacks.cpp      | 173 ++++++++++---------
 Fltk/Callbacks.h        |  18 +-
 Fltk/GUI.cpp            | 214 ++++++++++++++----------
 Fltk/GUI.h              |  19 ++-
 Fltk/GmshServer.cpp     | 127 ++++++++++++++
 Fltk/GmshServer.h       |   8 +
 Fltk/Makefile           |   9 +-
 Fltk/Socket.cpp         | 215 ------------------------
 Fltk/Socket.h           |  17 --
 Fltk/Solvers.cpp        | 130 ++++++++-------
 Fltk/Solvers.h          |  29 ++--
 Makefile                |   6 +-
 Mesh/3D_Mesh.cpp        |  10 +-
 doc/FAQ                 |  20 ++-
 doc/VERSIONS            |   6 +-
 doc/gmsh.1              |   5 +-
 utils/GmshClient.c      |  80 +++++++++
 utils/GmshClient.h      |  22 +++
 utils/Makefile          |   8 +-
 utils/mysolver.c        | 173 +++++++++++++++++++
 utils/mysolver.opt      |  28 ++++
 25 files changed, 1580 insertions(+), 538 deletions(-)
 create mode 100644 Fltk/GmshServer.cpp
 create mode 100644 Fltk/GmshServer.h
 delete mode 100644 Fltk/Socket.cpp
 delete mode 100644 Fltk/Socket.h
 create mode 100644 utils/GmshClient.c
 create mode 100644 utils/GmshClient.h
 create mode 100644 utils/mysolver.c
 create mode 100644 utils/mysolver.opt

diff --git a/Common/DefaultOptions.h b/Common/DefaultOptions.h
index dddb4f2eb7..8325e35438 100644
--- a/Common/DefaultOptions.h
+++ b/Common/DefaultOptions.h
@@ -50,12 +50,239 @@ StringXString MeshOptions_String[] = {
 } ;
 
 StringXString SolverOptions_String[] = {
+  { F|O, "Name0" , opt_solver_name0 , "GetDP" ,
+    "Name of solver 0" },
+  { F|O, "Help0" , opt_solver_help0 , 
+    "A General environment for the treatment of\nDiscrete Problems\n\n"
+    "Copyright (c) 1997-2002\nPatrick Dular and Christophe Geuzaine\n\n"
+    "Visit http://www.geuz.org/getdp/ for more info",
+    "Help string for solver 0" },
+  { F|O, "Executable0" , opt_solver_executable0 , 
 #ifdef WIN32
-  { F|O, "GetDPCommand" , opt_solver_getdp_command , "./getdp.exe" , 
+    "./getdp.exe" , 
 #else
-  { F|O, "GetDPCommand" , opt_solver_getdp_command , "getdp" , 
+    "getdp" , 
 #endif
-    "System command to launch the GetDP solver (should _not_ contain the '&' character)" },
+    "System command to launch solver 0 (should _not_ contain the '&' character)" },
+  { F|O, "Extension0" , opt_solver_extension0 , ".pro" ,
+    "Default file name extension for solver 0" },
+  { F|O, "MeshName0" , opt_solver_mesh_name0 , "" ,
+    "Default mesh file name for solver 0" },
+  { F|O, "MeshCommand0" , opt_solver_mesh_command0 , "-msh %s" ,
+    "Command used to specify the mesh file for solver 0" },
+  { F|O, "OptionCommand0" , opt_solver_option_command0 , "" ,
+    "Command to get options from solver 0" },
+  { F|O, "FirstOption0" , opt_solver_first_option0 , "Resolution" ,
+    "Label of first option for solver 0" },
+  { F|O, "SecondOption0" , opt_solver_second_option0 , "PostOperation" ,
+    "Label of second option for solver 0" },
+  { F|O, "ThirdOption0" , opt_solver_third_option0 , "" ,
+    "Label of third option for solver 0" },
+  { F|O, "FourthOption0" , opt_solver_fourth_option0 , "" ,
+    "Label of fourth option for solver 0" },
+  { F|O, "FifthOption0" , opt_solver_fifth_option0 , "" ,
+    "Label of fifth option for solver 0" },
+  { F|O, "FirstButton0" , opt_solver_first_button0 , "Pre" ,
+    "Label of first button for solver 0" },
+  { F|O, "FirstButtonCommand0" , opt_solver_first_button_command0 , "-pre %s" ,
+    "Command associated with the first button for solver 0" },
+  { F|O, "SecondButton0" , opt_solver_second_button0 , "Cal" ,
+    "Label of second button for solver 0" },
+  { F|O, "SecondButtonCommand0" , opt_solver_second_button_command0 , "-cal" ,
+    "Command associated with the second button for solver 0" },
+  { F|O, "ThirdButton0" , opt_solver_third_button0 , "Pos" ,
+    "Label of third button for solver 0" },
+  { F|O, "ThirdButtonCommand0" , opt_solver_third_button_command0 , "-bin -pos %s" ,
+    "Command associated with the third button for solver 0" },
+  { F|O, "FourthButton0" , opt_solver_fourth_button0 , "" ,
+    "Label of fourth button for solver 0" },
+  { F|O, "FourthButtonCommand0" , opt_solver_fourth_button_command0 , "" ,
+    "Command associated with the fourth button for solver 0" },
+  { F|O, "FifthButton0" , opt_solver_fifth_button0 , "" ,
+    "Label of fifth button for solver 0" },
+  { F|O, "FifthButtonCommand0" , opt_solver_fifth_button_command0 , "" ,
+    "Command associated with the fifth button for solver 0" },
+
+  { F|O, "Name1" , opt_solver_name1 , "" ,
+    "Name of solver 1" },
+  { F|O, "Help1" , opt_solver_help1 , "" ,
+    "Help string for solver 1" },
+  { F|O, "Executable1" , opt_solver_executable1 , "" , 
+    "System command to launch solver 1 (should _not_ contain the '&' character)" },
+  { F|O, "Extension1" , opt_solver_extension1 , "" ,
+    "Default file name extension for solver 1" },
+  { F|O, "MeshName1" , opt_solver_mesh_name1 , "" ,
+    "Default mesh file name for solver 1" },
+  { F|O, "MeshCommand1" , opt_solver_mesh_command1 , "" ,
+    "Command used to specify the mesh file for solver 1" },
+  { F|O, "OptionCommand1" , opt_solver_option_command1 , "" ,
+    "Command to get options from solver 1" },
+  { F|O, "FirstOption1" , opt_solver_first_option1 , "" ,
+    "Label of first option for solver 1" },
+  { F|O, "SecondOption1" , opt_solver_second_option1 , "" ,
+    "Label of second option for solver 1" },
+  { F|O, "ThirdOption1" , opt_solver_third_option1 , "" ,
+    "Label of third option for solver 1" },
+  { F|O, "FourthOption1" , opt_solver_fourth_option1 , "" ,
+    "Label of fourth option for solver 1" },
+  { F|O, "FifthOption1" , opt_solver_fifth_option1 , "" ,
+    "Label of fifth option for solver 1" },
+  { F|O, "FirstButton1" , opt_solver_first_button1 , "" ,
+    "Label of first button for solver 1" },
+  { F|O, "FirstButtonCommand1" , opt_solver_first_button_command1 , "" ,
+    "Command associated with the first button for solver 1" },
+  { F|O, "SecondButton1" , opt_solver_second_button1 , "" ,
+    "Label of second button for solver 1" },
+  { F|O, "SecondButtonCommand1" , opt_solver_second_button_command1 , "" ,
+    "Command associated with the second button for solver 1" },
+  { F|O, "ThirdButton1" , opt_solver_third_button1 , "" ,
+    "Label of third button for solver 1" },
+  { F|O, "ThirdButtonCommand1" , opt_solver_third_button_command1 , "" ,
+    "Command associated with the third button for solver 1" },
+  { F|O, "FourthButton1" , opt_solver_fourth_button1 , "" ,
+    "Label of fourth button for solver 1" },
+  { F|O, "FourthButtonCommand1" , opt_solver_fourth_button_command1 , "" ,
+    "Command associated with the fourth button for solver 1" },
+  { F|O, "FifthButton1" , opt_solver_fifth_button1 , "" ,
+    "Label of fifth button for solver 1" },
+  { F|O, "FifthButtonCommand1" , opt_solver_fifth_button_command1 , "" ,
+    "Command associated with the fifth button for solver 1" },
+
+  { F|O, "Name2" , opt_solver_name2 , "" ,
+    "Name of solver 2" },
+  { F|O, "Help2" , opt_solver_help2 , "" ,
+    "Help string for solver 2" },
+  { F|O, "Executable2" , opt_solver_executable2 , "" , 
+    "System command to launch solver 2 (should _not_ contain the '&' character)" },
+  { F|O, "Extension2" , opt_solver_extension2 , "" ,
+    "Default file name extension for solver 2" },
+  { F|O, "MeshName2" , opt_solver_mesh_name2 , "" ,
+    "Default mesh file name for solver 2" },
+  { F|O, "MeshCommand2" , opt_solver_mesh_command2 , "" ,
+    "Command used to specify the mesh file for solver 2" },
+  { F|O, "OptionCommand2" , opt_solver_option_command2 , "" ,
+    "Command to get options from solver 2" },
+  { F|O, "FirstOption2" , opt_solver_first_option2 , "" ,
+    "Label of first option for solver 2" },
+  { F|O, "SecondOption2" , opt_solver_second_option2 , "" ,
+    "Label of second option for solver 2" },
+  { F|O, "ThirdOption2" , opt_solver_third_option2 , "" ,
+    "Label of third option for solver 2" },
+  { F|O, "FourthOption2" , opt_solver_fourth_option2 , "" ,
+    "Label of fourth option for solver 2" },
+  { F|O, "FifthOption2" , opt_solver_fifth_option2 , "" ,
+    "Label of fifth option for solver 2" },
+  { F|O, "FirstButton2" , opt_solver_first_button2 , "" ,
+    "Label of first button for solver 2" },
+  { F|O, "FirstButtonCommand2" , opt_solver_first_button_command2 , "" ,
+    "Command associated with the first button for solver 2" },
+  { F|O, "SecondButton2" , opt_solver_second_button2 , "" ,
+    "Label of second button for solver 2" },
+  { F|O, "SecondButtonCommand2" , opt_solver_second_button_command2 , "" ,
+    "Command associated with the second button for solver 2" },
+  { F|O, "ThirdButton2" , opt_solver_third_button2 , "" ,
+    "Label of third button for solver 2" },
+  { F|O, "ThirdButtonCommand2" , opt_solver_third_button_command2 , "" ,
+    "Command associated with the third button for solver 2" },
+  { F|O, "FourthButton2" , opt_solver_fourth_button2 , "" ,
+    "Label of fourth button for solver 2" },
+  { F|O, "FourthButtonCommand2" , opt_solver_fourth_button_command2 , "" ,
+    "Command associated with the fourth button for solver 2" },
+  { F|O, "FifthButton2" , opt_solver_fifth_button2 , "" ,
+    "Label of fifth button for solver 2" },
+  { F|O, "FifthButtonCommand2" , opt_solver_fifth_button_command2 , "" ,
+    "Command associated with the fifth button for solver 2" },
+
+  { F|O, "Name3" , opt_solver_name3 , "" ,
+    "Name of solver 3" },
+  { F|O, "Help3" , opt_solver_help3 , "" ,
+    "Help string for solver 3" },
+  { F|O, "Executable3" , opt_solver_executable3 , "" , 
+    "System command to launch solver 3 (should _not_ contain the '&' character)" },
+  { F|O, "Extension3" , opt_solver_extension3 , "" ,
+    "Default file name extension for solver 3" },
+  { F|O, "MeshName3" , opt_solver_mesh_name3 , "" ,
+    "Default mesh file name for solver 3" },
+  { F|O, "MeshCommand3" , opt_solver_mesh_command3 , "" ,
+    "Command used to specify the mesh file for solver 3" },
+  { F|O, "OptionCommand3" , opt_solver_option_command3 , "" ,
+    "Command to get options from solver 3" },
+  { F|O, "FirstOption3" , opt_solver_first_option3 , "" ,
+    "Label of first option for solver 3" },
+  { F|O, "SecondOption3" , opt_solver_second_option3 , "" ,
+    "Label of second option for solver 3" },
+  { F|O, "ThirdOption3" , opt_solver_third_option3 , "" ,
+    "Label of third option for solver 3" },
+  { F|O, "FourthOption3" , opt_solver_fourth_option3 , "" ,
+    "Label of fourth option for solver 3" },
+  { F|O, "FifthOption3" , opt_solver_fifth_option3 , "" ,
+    "Label of fifth option for solver 3" },
+  { F|O, "FirstButton3" , opt_solver_first_button3 , "" ,
+    "Label of first button for solver 3" },
+  { F|O, "FirstButtonCommand3" , opt_solver_first_button_command3 , "" ,
+    "Command associated with the first button for solver 3" },
+  { F|O, "SecondButton3" , opt_solver_second_button3 , "" ,
+    "Label of second button for solver 3" },
+  { F|O, "SecondButtonCommand3" , opt_solver_second_button_command3 , "" ,
+    "Command associated with the second button for solver 3" },
+  { F|O, "ThirdButton3" , opt_solver_third_button3 , "" ,
+    "Label of third button for solver 3" },
+  { F|O, "ThirdButtonCommand3" , opt_solver_third_button_command3 , "" ,
+    "Command associated with the third button for solver 3" },
+  { F|O, "FourthButton3" , opt_solver_fourth_button3 , "" ,
+    "Label of fourth button for solver 3" },
+  { F|O, "FourthButtonCommand3" , opt_solver_fourth_button_command3 , "" ,
+    "Command associated with the fourth button for solver 3" },
+  { F|O, "FifthButton3" , opt_solver_fifth_button3 , "" ,
+    "Label of fifth button for solver 3" },
+  { F|O, "FifthButtonCommand3" , opt_solver_fifth_button_command3 , "" ,
+    "Command associated with the fifth button for solver 3" },
+
+  { F|O, "Name4" , opt_solver_name4 , "" ,
+    "Name of solver 4" },
+  { F|O, "Help4" , opt_solver_help4 , "" ,
+    "Help string for solver 4" },
+  { F|O, "Executable4" , opt_solver_executable4 , "" , 
+    "System command to launch solver 4 (should _not_ contain the '&' character)" },
+  { F|O, "Extension4" , opt_solver_extension4 , "" ,
+    "Default file name extension for solver 4" },
+  { F|O, "MeshName4" , opt_solver_mesh_name4 , "" ,
+    "Default mesh file name for solver 4" },
+  { F|O, "MeshCommand4" , opt_solver_mesh_command4 , "" ,
+    "Command used to specify the mesh file for solver 4" },
+  { F|O, "OptionCommand4" , opt_solver_option_command4 , "" ,
+    "Command to get options from solver 4" },
+  { F|O, "FirstOption4" , opt_solver_first_option4 , "" ,
+    "Label of first option for solver 4" },
+  { F|O, "SecondOption4" , opt_solver_second_option4 , "" ,
+    "Label of second option for solver 4" },
+  { F|O, "ThirdOption4" , opt_solver_third_option4 , "" ,
+    "Label of third option for solver 4" },
+  { F|O, "FourthOption4" , opt_solver_fourth_option4 , "" ,
+    "Label of fourth option for solver 4" },
+  { F|O, "FifthOption4" , opt_solver_fifth_option4 , "" ,
+    "Label of fifth option for solver 4" },
+  { F|O, "FirstButton4" , opt_solver_first_button4 , "" ,
+    "Label of first button for solver 4" },
+  { F|O, "FirstButtonCommand4" , opt_solver_first_button_command4 , "" ,
+    "Command associated with the first button for solver 4" },
+  { F|O, "SecondButton4" , opt_solver_second_button4 , "" ,
+    "Label of second button for solver 4" },
+  { F|O, "SecondButtonCommand4" , opt_solver_second_button_command4 , "" ,
+    "Command associated with the second button for solver 4" },
+  { F|O, "ThirdButton4" , opt_solver_third_button4 , "" ,
+    "Label of third button for solver 4" },
+  { F|O, "ThirdButtonCommand4" , opt_solver_third_button_command4 , "" ,
+    "Command associated with the third button for solver 4" },
+  { F|O, "FourthButton4" , opt_solver_fourth_button4 , "" ,
+    "Label of fourth button for solver 4" },
+  { F|O, "FourthButtonCommand4" , opt_solver_fourth_button_command4 , "" ,
+    "Command associated with the fourth button for solver 4" },
+  { F|O, "FifthButton4" , opt_solver_fifth_button4 , "" ,
+    "Label of fifth button for solver 4" },
+  { F|O, "FifthButtonCommand4" , opt_solver_fifth_button_command4 , "" ,
+    "Command associated with the fifth button for solver 4" },
+
   { 0, NULL , NULL , NULL , NULL }
 } ;
 
@@ -493,10 +720,40 @@ StringXNumber MeshOptions_Number[] = {
 } ;
 
 StringXNumber SolverOptions_Number[] = {
-  { F|O, "GetDPMergeViews" , opt_solver_getdp_mergeviews , 1.0 , 
-    "Automatically merge any post-processing view created by GetDP" },
-  { F|O, "GetDPPopupMessages" , opt_solver_getdp_popupmessages , 1.0 ,
-    "Automatically display GetDP messages" },
+  { F|O, "ClientServer0" , opt_solver_client_server0 , 1.0 ,
+    "Connect solver 0 to the Gmsh server" },
+  { F|O, "MergeViews0" , opt_solver_merge_views0 , 1.0 , 
+    "Automatically merge any post-processing view created by solver 0" },
+  { F|O, "PopupMessages0" , opt_solver_popup_messages0 , 1.0 ,
+    "Automatically display messages produced by solver 0" },
+
+  { F|O, "ClientServer1" , opt_solver_client_server1 , 0.0 ,
+    "Connect solver 1 to the Gmsh server" },
+  { F|O, "MergeViews1" , opt_solver_merge_views1 , 1.0 , 
+    "Automatically merge any post-processing view created by solver 1" },
+  { F|O, "PopupMessages1" , opt_solver_popup_messages1 , 1.0 ,
+    "Automatically display messages produced by solver 1" },
+
+  { F|O, "ClientServer2" , opt_solver_client_server2 , 0.0 ,
+    "Connect solver 2 to the Gmsh server" },
+  { F|O, "MergeViews2" , opt_solver_merge_views2 , 1.0 , 
+    "Automatically merge any post-processing view created by solver 2" },
+  { F|O, "PopupMessages2" , opt_solver_popup_messages2 , 1.0 ,
+    "Automatically display messages produced by solver 2" },
+
+  { F|O, "ClientServer3" , opt_solver_client_server3 , 0.0 ,
+    "Connect solver 3 to the Gmsh server" },
+  { F|O, "MergeViews3" , opt_solver_merge_views3 , 1.0 , 
+    "Automatically merge any post-processing view created by solver 3" },
+  { F|O, "PopupMessages3" , opt_solver_popup_messages3 , 1.0 ,
+    "Automatically display messages produced by solver 3" },
+
+  { F|O, "ClientServer4" , opt_solver_client_server4 , 0.0 ,
+    "Connect solver 4 to the Gmsh server" },
+  { F|O, "MergeViews4" , opt_solver_merge_views4 , 1.0 , 
+    "Automatically merge any post-processing view created by solver 4" },
+  { F|O, "PopupMessages4" , opt_solver_popup_messages4 , 1.0 ,
+    "Automatically display messages produced by solver 4" },
 
   { 0, NULL , NULL , 0. , NULL }
 } ;
diff --git a/Common/GetOptions.cpp b/Common/GetOptions.cpp
index 4a239a8462..f2c56bf965 100644
--- a/Common/GetOptions.cpp
+++ b/Common/GetOptions.cpp
@@ -1,4 +1,4 @@
-// $Id: GetOptions.cpp,v 1.43 2001-12-06 10:10:42 geuzaine Exp $
+// $Id: GetOptions.cpp,v 1.44 2002-01-03 10:25:06 geuzaine Exp $
 
 #include <unistd.h>
 #include "Gmsh.h"
@@ -79,7 +79,8 @@ void Print_Usage(char *name){
   Msg(DIRECT, "                        post-processing mode (default: automatic)");
 #endif
   Msg(DIRECT, "  -v int                set verbosity level (default: 2)");
-  Msg(DIRECT, "  -opt \"string\"         parse string before project file");
+  Msg(DIRECT, "  -string \"string\"      parse string before project file");
+  Msg(DIRECT, "  -option file          parse option file before GUI creation");
   Msg(DIRECT, "  -version              show version number");
   Msg(DIRECT, "  -info                 show detailed version information");
   Msg(DIRECT, "  -help                 show this message");
@@ -106,7 +107,7 @@ void Get_Options (int argc, char *argv[], int *nbfiles) {
     
     if (argv[i][0] == '-') {
       
-      if(!strcmp(argv[i]+1, "opt")){
+      if(!strcmp(argv[i]+1, "string")){
 	i++;
         if(argv[i]!=NULL) TheOptString = argv[i++];
 	else{
@@ -156,6 +157,14 @@ void Get_Options (int argc, char *argv[], int *nbfiles) {
       else if(!strcmp(argv[i]+1, "histogram")){ 
         CTX.mesh.histogram = 1; i++;
       }
+      else if(!strcmp(argv[i]+1, "option")){ 
+        i++;
+        if(argv[i] != NULL) ParseFile(argv[i++],1);
+        else {    
+          fprintf(stderr, ERROR_STR "Missing file name\n");
+          exit(1);
+        }
+      }
       else if(!strcmp(argv[i]+1, "o")){ 
         i++;
         if(argv[i] != NULL) CTX.output_filename = argv[i++];
diff --git a/Common/Options.cpp b/Common/Options.cpp
index 5b6f4bad60..315fd761a2 100644
--- a/Common/Options.cpp
+++ b/Common/Options.cpp
@@ -1,4 +1,4 @@
-// $Id: Options.cpp,v 1.67 2001-12-16 05:16:37 remacle Exp $
+// $Id: Options.cpp,v 1.68 2002-01-03 10:25:06 geuzaine Exp $
 
 #include "Gmsh.h"
 #include "GmshUI.h"
@@ -511,16 +511,320 @@ char * opt_general_editor(OPT_ARGS_STR){
   return CTX.editor;
 }
 
-char * opt_solver_getdp_command(OPT_ARGS_STR){
+char * opt_solver_name(OPT_ARGS_STR){
 #ifdef _FLTK
-  if(action & GMSH_SET) strcpy(GetDP_Info.command, val);
+  if(action & GMSH_SET) strcpy(SINFO[num].name, val);
   if(WID && (action & GMSH_GUI))
-    WID->getdp_input[2]->value(GetDP_Info.command);
-  return GetDP_Info.command;
+    WID->solver[num].window->label(SINFO[num].name);
+  return SINFO[num].name;
 #else
-  return "getdp";
+  return "undefined";
 #endif
 }
+char * opt_solver_name0(OPT_ARGS_STR){ return opt_solver_name(0,action,val); }
+char * opt_solver_name1(OPT_ARGS_STR){ return opt_solver_name(1,action,val); }
+char * opt_solver_name2(OPT_ARGS_STR){ return opt_solver_name(2,action,val); }
+char * opt_solver_name3(OPT_ARGS_STR){ return opt_solver_name(3,action,val); }
+char * opt_solver_name4(OPT_ARGS_STR){ return opt_solver_name(4,action,val); }
+
+char * opt_solver_executable(OPT_ARGS_STR){
+#ifdef _FLTK
+  if(action & GMSH_SET) strcpy(SINFO[num].executable_name, val);
+  if(WID && (action & GMSH_GUI))
+    WID->solver[num].input[2]->value(SINFO[num].executable_name);
+  return SINFO[num].executable_name;
+#else
+  return "undefined";
+#endif
+}
+char * opt_solver_executable0(OPT_ARGS_STR){ return opt_solver_executable(0,action,val); }
+char * opt_solver_executable1(OPT_ARGS_STR){ return opt_solver_executable(1,action,val); }
+char * opt_solver_executable2(OPT_ARGS_STR){ return opt_solver_executable(2,action,val); }
+char * opt_solver_executable3(OPT_ARGS_STR){ return opt_solver_executable(3,action,val); }
+char * opt_solver_executable4(OPT_ARGS_STR){ return opt_solver_executable(4,action,val); }
+
+char * opt_solver_help(OPT_ARGS_STR){
+#ifdef _FLTK
+  if(action & GMSH_SET) SINFO[num].help = val;
+  return SINFO[num].help;
+#else
+  return "undefined";
+#endif
+}
+char * opt_solver_help0(OPT_ARGS_STR){ return opt_solver_help(0,action,val); }
+char * opt_solver_help1(OPT_ARGS_STR){ return opt_solver_help(1,action,val); }
+char * opt_solver_help2(OPT_ARGS_STR){ return opt_solver_help(2,action,val); }
+char * opt_solver_help3(OPT_ARGS_STR){ return opt_solver_help(3,action,val); }
+char * opt_solver_help4(OPT_ARGS_STR){ return opt_solver_help(4,action,val); }
+
+char * opt_solver_extension(OPT_ARGS_STR){
+#ifdef _FLTK
+  if(action & GMSH_SET) strcpy(SINFO[num].extension, val);
+  return SINFO[num].extension;
+#else
+  return "undefined";
+#endif
+}
+char * opt_solver_extension0(OPT_ARGS_STR){ return opt_solver_extension(0,action,val); }
+char * opt_solver_extension1(OPT_ARGS_STR){ return opt_solver_extension(1,action,val); }
+char * opt_solver_extension2(OPT_ARGS_STR){ return opt_solver_extension(2,action,val); }
+char * opt_solver_extension3(OPT_ARGS_STR){ return opt_solver_extension(3,action,val); }
+char * opt_solver_extension4(OPT_ARGS_STR){ return opt_solver_extension(4,action,val); }
+
+char * opt_solver_mesh_name(OPT_ARGS_STR){
+#ifdef _FLTK
+  if(action & GMSH_SET) strcpy(SINFO[num].mesh_name, val);
+  return SINFO[num].mesh_name;
+#else
+  return "undefined";
+#endif
+}
+char * opt_solver_mesh_name0(OPT_ARGS_STR){ return opt_solver_mesh_name(0,action,val); }
+char * opt_solver_mesh_name1(OPT_ARGS_STR){ return opt_solver_mesh_name(1,action,val); }
+char * opt_solver_mesh_name2(OPT_ARGS_STR){ return opt_solver_mesh_name(2,action,val); }
+char * opt_solver_mesh_name3(OPT_ARGS_STR){ return opt_solver_mesh_name(3,action,val); }
+char * opt_solver_mesh_name4(OPT_ARGS_STR){ return opt_solver_mesh_name(4,action,val); }
+
+char * opt_solver_mesh_command(OPT_ARGS_STR){
+#ifdef _FLTK
+  if(action & GMSH_SET) strcpy(SINFO[num].mesh_command, val);
+  if(WID && (action & GMSH_GUI))
+    WID->solver[num].input[1]->value(SINFO[num].mesh_name);
+  return SINFO[num].mesh_command;
+#else
+  return "undefined";
+#endif
+}
+char * opt_solver_mesh_command0(OPT_ARGS_STR){ return opt_solver_mesh_command(0,action,val); }
+char * opt_solver_mesh_command1(OPT_ARGS_STR){ return opt_solver_mesh_command(1,action,val); }
+char * opt_solver_mesh_command2(OPT_ARGS_STR){ return opt_solver_mesh_command(2,action,val); }
+char * opt_solver_mesh_command3(OPT_ARGS_STR){ return opt_solver_mesh_command(3,action,val); }
+char * opt_solver_mesh_command4(OPT_ARGS_STR){ return opt_solver_mesh_command(4,action,val); }
+
+char * opt_solver_option_command(OPT_ARGS_STR){
+#ifdef _FLTK
+  if(action & GMSH_SET) strcpy(SINFO[num].option_command, val);
+  return SINFO[num].option_command;
+#else
+  return "undefined";
+#endif
+}
+char * opt_solver_option_command0(OPT_ARGS_STR){ return opt_solver_option_command(0,action,val); }
+char * opt_solver_option_command1(OPT_ARGS_STR){ return opt_solver_option_command(1,action,val); }
+char * opt_solver_option_command2(OPT_ARGS_STR){ return opt_solver_option_command(2,action,val); }
+char * opt_solver_option_command3(OPT_ARGS_STR){ return opt_solver_option_command(3,action,val); }
+char * opt_solver_option_command4(OPT_ARGS_STR){ return opt_solver_option_command(4,action,val); }
+
+char * opt_solver_first_option(OPT_ARGS_STR){
+#ifdef _FLTK
+  if(action & GMSH_SET) strcpy(SINFO[num].option_name[0], val);
+  return SINFO[num].option_name[0];
+#else
+  return "undefined";
+#endif
+}
+char * opt_solver_first_option0(OPT_ARGS_STR){ return opt_solver_first_option(0,action,val); }
+char * opt_solver_first_option1(OPT_ARGS_STR){ return opt_solver_first_option(1,action,val); }
+char * opt_solver_first_option2(OPT_ARGS_STR){ return opt_solver_first_option(2,action,val); }
+char * opt_solver_first_option3(OPT_ARGS_STR){ return opt_solver_first_option(3,action,val); }
+char * opt_solver_first_option4(OPT_ARGS_STR){ return opt_solver_first_option(4,action,val); }
+
+char * opt_solver_second_option(OPT_ARGS_STR){
+#ifdef _FLTK
+  if(action & GMSH_SET) strcpy(SINFO[num].option_name[1], val);
+  return SINFO[num].option_name[1];
+#else
+  return "undefined";
+#endif
+}
+char * opt_solver_second_option0(OPT_ARGS_STR){ return opt_solver_second_option(0,action,val); }
+char * opt_solver_second_option1(OPT_ARGS_STR){ return opt_solver_second_option(1,action,val); }
+char * opt_solver_second_option2(OPT_ARGS_STR){ return opt_solver_second_option(2,action,val); }
+char * opt_solver_second_option3(OPT_ARGS_STR){ return opt_solver_second_option(3,action,val); }
+char * opt_solver_second_option4(OPT_ARGS_STR){ return opt_solver_second_option(4,action,val); }
+
+char * opt_solver_third_option(OPT_ARGS_STR){
+#ifdef _FLTK
+  if(action & GMSH_SET) strcpy(SINFO[num].option_name[2], val);
+  return SINFO[num].option_name[2];
+#else
+  return "undefined";
+#endif
+}
+char * opt_solver_third_option0(OPT_ARGS_STR){ return opt_solver_third_option(0,action,val); }
+char * opt_solver_third_option1(OPT_ARGS_STR){ return opt_solver_third_option(1,action,val); }
+char * opt_solver_third_option2(OPT_ARGS_STR){ return opt_solver_third_option(2,action,val); }
+char * opt_solver_third_option3(OPT_ARGS_STR){ return opt_solver_third_option(3,action,val); }
+char * opt_solver_third_option4(OPT_ARGS_STR){ return opt_solver_third_option(4,action,val); }
+
+char * opt_solver_fourth_option(OPT_ARGS_STR){
+#ifdef _FLTK
+  if(action & GMSH_SET) strcpy(SINFO[num].option_name[3], val);
+  return SINFO[num].option_name[3];
+#else
+  return "undefined";
+#endif
+}
+char * opt_solver_fourth_option0(OPT_ARGS_STR){ return opt_solver_fourth_option(0,action,val); }
+char * opt_solver_fourth_option1(OPT_ARGS_STR){ return opt_solver_fourth_option(1,action,val); }
+char * opt_solver_fourth_option2(OPT_ARGS_STR){ return opt_solver_fourth_option(2,action,val); }
+char * opt_solver_fourth_option3(OPT_ARGS_STR){ return opt_solver_fourth_option(3,action,val); }
+char * opt_solver_fourth_option4(OPT_ARGS_STR){ return opt_solver_fourth_option(4,action,val); }
+
+char * opt_solver_fifth_option(OPT_ARGS_STR){
+#ifdef _FLTK
+  if(action & GMSH_SET) strcpy(SINFO[num].option_name[4], val);
+  return SINFO[num].option_name[4];
+#else
+  return "undefined";
+#endif
+}
+char * opt_solver_fifth_option0(OPT_ARGS_STR){ return opt_solver_fifth_option(0,action,val); }
+char * opt_solver_fifth_option1(OPT_ARGS_STR){ return opt_solver_fifth_option(1,action,val); }
+char * opt_solver_fifth_option2(OPT_ARGS_STR){ return opt_solver_fifth_option(2,action,val); }
+char * opt_solver_fifth_option3(OPT_ARGS_STR){ return opt_solver_fifth_option(3,action,val); }
+char * opt_solver_fifth_option4(OPT_ARGS_STR){ return opt_solver_fifth_option(4,action,val); }
+
+char * opt_solver_first_button(OPT_ARGS_STR){
+#ifdef _FLTK
+  if(action & GMSH_SET) strcpy(SINFO[num].button_name[0], val);
+  return SINFO[num].button_name[0];
+#else
+  return "undefined";
+#endif
+}
+char * opt_solver_first_button0(OPT_ARGS_STR){ return opt_solver_first_button(0,action,val); }
+char * opt_solver_first_button1(OPT_ARGS_STR){ return opt_solver_first_button(1,action,val); }
+char * opt_solver_first_button2(OPT_ARGS_STR){ return opt_solver_first_button(2,action,val); }
+char * opt_solver_first_button3(OPT_ARGS_STR){ return opt_solver_first_button(3,action,val); }
+char * opt_solver_first_button4(OPT_ARGS_STR){ return opt_solver_first_button(4,action,val); }
+
+char * opt_solver_first_button_command(OPT_ARGS_STR){
+#ifdef _FLTK
+  if(action & GMSH_SET) strcpy(SINFO[num].button_command[0], val);
+  return SINFO[num].button_command[0];
+#else
+  return "undefined";
+#endif
+}
+char * opt_solver_first_button_command0(OPT_ARGS_STR){ return opt_solver_first_button_command(0,action,val); }
+char * opt_solver_first_button_command1(OPT_ARGS_STR){ return opt_solver_first_button_command(1,action,val); }
+char * opt_solver_first_button_command2(OPT_ARGS_STR){ return opt_solver_first_button_command(2,action,val); }
+char * opt_solver_first_button_command3(OPT_ARGS_STR){ return opt_solver_first_button_command(3,action,val); }
+char * opt_solver_first_button_command4(OPT_ARGS_STR){ return opt_solver_first_button_command(4,action,val); }
+
+char * opt_solver_second_button(OPT_ARGS_STR){
+#ifdef _FLTK
+  if(action & GMSH_SET) strcpy(SINFO[num].button_name[1], val);
+  return SINFO[num].button_name[1];
+#else
+  return "undefined";
+#endif
+}
+char * opt_solver_second_button0(OPT_ARGS_STR){ return opt_solver_second_button(0,action,val); }
+char * opt_solver_second_button1(OPT_ARGS_STR){ return opt_solver_second_button(1,action,val); }
+char * opt_solver_second_button2(OPT_ARGS_STR){ return opt_solver_second_button(2,action,val); }
+char * opt_solver_second_button3(OPT_ARGS_STR){ return opt_solver_second_button(3,action,val); }
+char * opt_solver_second_button4(OPT_ARGS_STR){ return opt_solver_second_button(4,action,val); }
+
+char * opt_solver_second_button_command(OPT_ARGS_STR){
+#ifdef _FLTK
+  if(action & GMSH_SET) strcpy(SINFO[num].button_command[1], val);
+  return SINFO[num].button_command[1];
+#else
+  return "undefined";
+#endif
+}
+char * opt_solver_second_button_command0(OPT_ARGS_STR){ return opt_solver_second_button_command(0,action,val); }
+char * opt_solver_second_button_command1(OPT_ARGS_STR){ return opt_solver_second_button_command(1,action,val); }
+char * opt_solver_second_button_command2(OPT_ARGS_STR){ return opt_solver_second_button_command(2,action,val); }
+char * opt_solver_second_button_command3(OPT_ARGS_STR){ return opt_solver_second_button_command(3,action,val); }
+char * opt_solver_second_button_command4(OPT_ARGS_STR){ return opt_solver_second_button_command(4,action,val); }
+
+char * opt_solver_third_button(OPT_ARGS_STR){
+#ifdef _FLTK
+  if(action & GMSH_SET) strcpy(SINFO[num].button_name[2], val);
+  return SINFO[num].button_name[2];
+#else
+  return "undefined";
+#endif
+}
+char * opt_solver_third_button0(OPT_ARGS_STR){ return opt_solver_third_button(0,action,val); }
+char * opt_solver_third_button1(OPT_ARGS_STR){ return opt_solver_third_button(1,action,val); }
+char * opt_solver_third_button2(OPT_ARGS_STR){ return opt_solver_third_button(2,action,val); }
+char * opt_solver_third_button3(OPT_ARGS_STR){ return opt_solver_third_button(3,action,val); }
+char * opt_solver_third_button4(OPT_ARGS_STR){ return opt_solver_third_button(4,action,val); }
+
+char * opt_solver_third_button_command(OPT_ARGS_STR){
+#ifdef _FLTK
+  if(action & GMSH_SET) strcpy(SINFO[num].button_command[2], val);
+  return SINFO[num].button_command[2];
+#else
+  return "undefined";
+#endif
+}
+char * opt_solver_third_button_command0(OPT_ARGS_STR){ return opt_solver_third_button_command(0,action,val); }
+char * opt_solver_third_button_command1(OPT_ARGS_STR){ return opt_solver_third_button_command(1,action,val); }
+char * opt_solver_third_button_command2(OPT_ARGS_STR){ return opt_solver_third_button_command(2,action,val); }
+char * opt_solver_third_button_command3(OPT_ARGS_STR){ return opt_solver_third_button_command(3,action,val); }
+char * opt_solver_third_button_command4(OPT_ARGS_STR){ return opt_solver_third_button_command(4,action,val); }
+
+char * opt_solver_fourth_button(OPT_ARGS_STR){
+#ifdef _FLTK
+  if(action & GMSH_SET) strcpy(SINFO[num].button_name[3], val);
+  return SINFO[num].button_name[3];
+#else
+  return "undefined";
+#endif
+}
+char * opt_solver_fourth_button0(OPT_ARGS_STR){ return opt_solver_fourth_button(0,action,val); }
+char * opt_solver_fourth_button1(OPT_ARGS_STR){ return opt_solver_fourth_button(1,action,val); }
+char * opt_solver_fourth_button2(OPT_ARGS_STR){ return opt_solver_fourth_button(2,action,val); }
+char * opt_solver_fourth_button3(OPT_ARGS_STR){ return opt_solver_fourth_button(3,action,val); }
+char * opt_solver_fourth_button4(OPT_ARGS_STR){ return opt_solver_fourth_button(4,action,val); }
+
+char * opt_solver_fourth_button_command(OPT_ARGS_STR){
+#ifdef _FLTK
+  if(action & GMSH_SET) strcpy(SINFO[num].button_command[3], val);
+  return SINFO[num].button_command[3];
+#else
+  return "undefined";
+#endif
+}
+char * opt_solver_fourth_button_command0(OPT_ARGS_STR){ return opt_solver_fourth_button_command(0,action,val); }
+char * opt_solver_fourth_button_command1(OPT_ARGS_STR){ return opt_solver_fourth_button_command(1,action,val); }
+char * opt_solver_fourth_button_command2(OPT_ARGS_STR){ return opt_solver_fourth_button_command(2,action,val); }
+char * opt_solver_fourth_button_command3(OPT_ARGS_STR){ return opt_solver_fourth_button_command(3,action,val); }
+char * opt_solver_fourth_button_command4(OPT_ARGS_STR){ return opt_solver_fourth_button_command(4,action,val); }
+
+char * opt_solver_fifth_button(OPT_ARGS_STR){
+#ifdef _FLTK
+  if(action & GMSH_SET) strcpy(SINFO[num].button_name[4], val);
+  return SINFO[num].button_name[4];
+#else
+  return "undefined";
+#endif
+}
+char * opt_solver_fifth_button0(OPT_ARGS_STR){ return opt_solver_fifth_button(0,action,val); }
+char * opt_solver_fifth_button1(OPT_ARGS_STR){ return opt_solver_fifth_button(1,action,val); }
+char * opt_solver_fifth_button2(OPT_ARGS_STR){ return opt_solver_fifth_button(2,action,val); }
+char * opt_solver_fifth_button3(OPT_ARGS_STR){ return opt_solver_fifth_button(3,action,val); }
+char * opt_solver_fifth_button4(OPT_ARGS_STR){ return opt_solver_fifth_button(4,action,val); }
+
+char * opt_solver_fifth_button_command(OPT_ARGS_STR){
+#ifdef _FLTK
+  if(action & GMSH_SET) strcpy(SINFO[num].button_command[4], val);
+  return SINFO[num].button_command[4];
+#else
+  return "undefined";
+#endif
+}
+char * opt_solver_fifth_button_command0(OPT_ARGS_STR){ return opt_solver_fifth_button_command(0,action,val); }
+char * opt_solver_fifth_button_command1(OPT_ARGS_STR){ return opt_solver_fifth_button_command(1,action,val); }
+char * opt_solver_fifth_button_command2(OPT_ARGS_STR){ return opt_solver_fifth_button_command(2,action,val); }
+char * opt_solver_fifth_button_command3(OPT_ARGS_STR){ return opt_solver_fifth_button_command(3,action,val); }
+char * opt_solver_fifth_button_command4(OPT_ARGS_STR){ return opt_solver_fifth_button_command(4,action,val); }
+
 
 char * opt_view_name(OPT_ARGS_STR){
   GET_VIEW(NULL) ;
@@ -1546,7 +1850,7 @@ double opt_mesh_constrained_bgmesh(OPT_ARGS_NUM){
 }
 double opt_mesh_degree(OPT_ARGS_NUM){
   if(action & GMSH_SET)
-    CTX.mesh.degree = (int)val; // INTERDIT POUR LE MOMENT !!!
+    CTX.mesh.degree = 1; //(int)val; // INTERDIT POUR LE MOMENT !!!
 #ifdef _FLTK
   if(WID && (action & GMSH_GUI))
     WID->mesh_butt[3]->value(CTX.mesh.degree==2);
@@ -1666,30 +1970,56 @@ double opt_mesh_cpu_time(OPT_ARGS_NUM){
 }
 
 
+double opt_solver_client_server(OPT_ARGS_NUM){
+#ifdef _FLTK
+  if(action & GMSH_SET)
+    SINFO[num].client_server = (int)val;
+  if(WID && (action & GMSH_GUI))
+    WID->solver[num].butt[2]->value(SINFO[num].client_server);
+  return SINFO[num].client_server;
+#else
+  return 0.;
+#endif
+}
+double opt_solver_client_server0(OPT_ARGS_NUM){ return opt_solver_client_server(0,action,val); }
+double opt_solver_client_server1(OPT_ARGS_NUM){ return opt_solver_client_server(1,action,val); }
+double opt_solver_client_server2(OPT_ARGS_NUM){ return opt_solver_client_server(2,action,val); }
+double opt_solver_client_server3(OPT_ARGS_NUM){ return opt_solver_client_server(3,action,val); }
+double opt_solver_client_server4(OPT_ARGS_NUM){ return opt_solver_client_server(4,action,val); }
 
-double opt_solver_getdp_popupmessages(OPT_ARGS_NUM){
+double opt_solver_popup_messages(OPT_ARGS_NUM){
 #ifdef _FLTK
   if(action & GMSH_SET)
-    GetDP_Info.popupmessages = (int)val;
+    SINFO[num].popup_messages = (int)val;
   if(WID && (action & GMSH_GUI))
-    WID->getdp_butt[0]->value(GetDP_Info.popupmessages);
-  return GetDP_Info.popupmessages;
+    WID->solver[num].butt[0]->value(SINFO[num].popup_messages);
+  return SINFO[num].popup_messages;
 #else
   return 1.;
 #endif
 }
-double opt_solver_getdp_mergeviews(OPT_ARGS_NUM){
+double opt_solver_popup_messages0(OPT_ARGS_NUM){ return opt_solver_popup_messages(0,action,val); }
+double opt_solver_popup_messages1(OPT_ARGS_NUM){ return opt_solver_popup_messages(1,action,val); }
+double opt_solver_popup_messages2(OPT_ARGS_NUM){ return opt_solver_popup_messages(2,action,val); }
+double opt_solver_popup_messages3(OPT_ARGS_NUM){ return opt_solver_popup_messages(3,action,val); }
+double opt_solver_popup_messages4(OPT_ARGS_NUM){ return opt_solver_popup_messages(4,action,val); }
+
+double opt_solver_merge_views(OPT_ARGS_NUM){
 #ifdef _FLTK
   if(action & GMSH_SET)
-    GetDP_Info.mergeviews = (int)val;
+    SINFO[num].merge_views = (int)val;
   if(WID && (action & GMSH_GUI))
-    WID->getdp_butt[1]->value(GetDP_Info.mergeviews);
-  return GetDP_Info.mergeviews;
+    WID->solver[num].butt[1]->value(SINFO[num].merge_views);
+  return SINFO[num].merge_views;
 #else
   return 1.;
 #endif
 }
-
+double opt_solver_merge_views0(OPT_ARGS_NUM){ return opt_solver_merge_views(0,action,val); }
+double opt_solver_merge_views1(OPT_ARGS_NUM){ return opt_solver_merge_views(1,action,val); }
+double opt_solver_merge_views2(OPT_ARGS_NUM){ return opt_solver_merge_views(2,action,val); }
+double opt_solver_merge_views3(OPT_ARGS_NUM){ return opt_solver_merge_views(3,action,val); }
+double opt_solver_merge_views4(OPT_ARGS_NUM){ return opt_solver_merge_views(4,action,val); }
 
 double opt_post_scales(OPT_ARGS_NUM){
   if(action & GMSH_SET) 
diff --git a/Common/Options.h b/Common/Options.h
index 072675d46e..f6854ebf9b 100644
--- a/Common/Options.h
+++ b/Common/Options.h
@@ -24,7 +24,138 @@ char * opt_general_error_filename(OPT_ARGS_STR);
 char * opt_general_session_filename(OPT_ARGS_STR);
 char * opt_general_options_filename(OPT_ARGS_STR);
 char * opt_general_editor(OPT_ARGS_STR);
-char * opt_solver_getdp_command(OPT_ARGS_STR);
+char * opt_solver_name(OPT_ARGS_STR);
+char * opt_solver_name0(OPT_ARGS_STR);
+char * opt_solver_name1(OPT_ARGS_STR);
+char * opt_solver_name2(OPT_ARGS_STR);
+char * opt_solver_name3(OPT_ARGS_STR);
+char * opt_solver_name4(OPT_ARGS_STR);
+char * opt_solver_executable(OPT_ARGS_STR);
+char * opt_solver_executable0(OPT_ARGS_STR);
+char * opt_solver_executable1(OPT_ARGS_STR);
+char * opt_solver_executable2(OPT_ARGS_STR);
+char * opt_solver_executable3(OPT_ARGS_STR);
+char * opt_solver_executable4(OPT_ARGS_STR);
+char * opt_solver_help(OPT_ARGS_STR);
+char * opt_solver_help0(OPT_ARGS_STR);
+char * opt_solver_help1(OPT_ARGS_STR);
+char * opt_solver_help2(OPT_ARGS_STR);
+char * opt_solver_help3(OPT_ARGS_STR);
+char * opt_solver_help4(OPT_ARGS_STR);
+char * opt_solver_extension(OPT_ARGS_STR);
+char * opt_solver_extension0(OPT_ARGS_STR);
+char * opt_solver_extension1(OPT_ARGS_STR);
+char * opt_solver_extension2(OPT_ARGS_STR);
+char * opt_solver_extension3(OPT_ARGS_STR);
+char * opt_solver_extension4(OPT_ARGS_STR);
+char * opt_solver_mesh_name(OPT_ARGS_STR);
+char * opt_solver_mesh_name0(OPT_ARGS_STR);
+char * opt_solver_mesh_name1(OPT_ARGS_STR);
+char * opt_solver_mesh_name2(OPT_ARGS_STR);
+char * opt_solver_mesh_name3(OPT_ARGS_STR);
+char * opt_solver_mesh_name4(OPT_ARGS_STR);
+char * opt_solver_mesh_command(OPT_ARGS_STR);
+char * opt_solver_mesh_command0(OPT_ARGS_STR);
+char * opt_solver_mesh_command1(OPT_ARGS_STR);
+char * opt_solver_mesh_command2(OPT_ARGS_STR);
+char * opt_solver_mesh_command3(OPT_ARGS_STR);
+char * opt_solver_mesh_command4(OPT_ARGS_STR);
+char * opt_solver_option_command(OPT_ARGS_STR);
+char * opt_solver_option_command0(OPT_ARGS_STR);
+char * opt_solver_option_command1(OPT_ARGS_STR);
+char * opt_solver_option_command2(OPT_ARGS_STR);
+char * opt_solver_option_command3(OPT_ARGS_STR);
+char * opt_solver_option_command4(OPT_ARGS_STR);
+char * opt_solver_first_option(OPT_ARGS_STR);
+char * opt_solver_first_option0(OPT_ARGS_STR);
+char * opt_solver_first_option1(OPT_ARGS_STR);
+char * opt_solver_first_option2(OPT_ARGS_STR);
+char * opt_solver_first_option3(OPT_ARGS_STR);
+char * opt_solver_first_option4(OPT_ARGS_STR);
+char * opt_solver_second_option(OPT_ARGS_STR);
+char * opt_solver_second_option0(OPT_ARGS_STR);
+char * opt_solver_second_option1(OPT_ARGS_STR);
+char * opt_solver_second_option2(OPT_ARGS_STR);
+char * opt_solver_second_option3(OPT_ARGS_STR);
+char * opt_solver_second_option4(OPT_ARGS_STR);
+char * opt_solver_third_option(OPT_ARGS_STR);
+char * opt_solver_third_option0(OPT_ARGS_STR);
+char * opt_solver_third_option1(OPT_ARGS_STR);
+char * opt_solver_third_option2(OPT_ARGS_STR);
+char * opt_solver_third_option3(OPT_ARGS_STR);
+char * opt_solver_third_option4(OPT_ARGS_STR);
+char * opt_solver_fourth_option(OPT_ARGS_STR);
+char * opt_solver_fourth_option0(OPT_ARGS_STR);
+char * opt_solver_fourth_option1(OPT_ARGS_STR);
+char * opt_solver_fourth_option2(OPT_ARGS_STR);
+char * opt_solver_fourth_option3(OPT_ARGS_STR);
+char * opt_solver_fourth_option4(OPT_ARGS_STR);
+char * opt_solver_fifth_option(OPT_ARGS_STR);
+char * opt_solver_fifth_option0(OPT_ARGS_STR);
+char * opt_solver_fifth_option1(OPT_ARGS_STR);
+char * opt_solver_fifth_option2(OPT_ARGS_STR);
+char * opt_solver_fifth_option3(OPT_ARGS_STR);
+char * opt_solver_fifth_option4(OPT_ARGS_STR);
+char * opt_solver_first_button(OPT_ARGS_STR);
+char * opt_solver_first_button0(OPT_ARGS_STR);
+char * opt_solver_first_button1(OPT_ARGS_STR);
+char * opt_solver_first_button2(OPT_ARGS_STR);
+char * opt_solver_first_button3(OPT_ARGS_STR);
+char * opt_solver_first_button4(OPT_ARGS_STR);
+char * opt_solver_first_button_command(OPT_ARGS_STR);
+char * opt_solver_first_button_command0(OPT_ARGS_STR);
+char * opt_solver_first_button_command1(OPT_ARGS_STR);
+char * opt_solver_first_button_command2(OPT_ARGS_STR);
+char * opt_solver_first_button_command3(OPT_ARGS_STR);
+char * opt_solver_first_button_command4(OPT_ARGS_STR);
+char * opt_solver_second_button(OPT_ARGS_STR);
+char * opt_solver_second_button0(OPT_ARGS_STR);
+char * opt_solver_second_button1(OPT_ARGS_STR);
+char * opt_solver_second_button2(OPT_ARGS_STR);
+char * opt_solver_second_button3(OPT_ARGS_STR);
+char * opt_solver_second_button4(OPT_ARGS_STR);
+char * opt_solver_second_button_command(OPT_ARGS_STR);
+char * opt_solver_second_button_command0(OPT_ARGS_STR);
+char * opt_solver_second_button_command1(OPT_ARGS_STR);
+char * opt_solver_second_button_command2(OPT_ARGS_STR);
+char * opt_solver_second_button_command3(OPT_ARGS_STR);
+char * opt_solver_second_button_command4(OPT_ARGS_STR);
+char * opt_solver_third_button(OPT_ARGS_STR);
+char * opt_solver_third_button0(OPT_ARGS_STR);
+char * opt_solver_third_button1(OPT_ARGS_STR);
+char * opt_solver_third_button2(OPT_ARGS_STR);
+char * opt_solver_third_button3(OPT_ARGS_STR);
+char * opt_solver_third_button4(OPT_ARGS_STR);
+char * opt_solver_third_button_command(OPT_ARGS_STR);
+char * opt_solver_third_button_command0(OPT_ARGS_STR);
+char * opt_solver_third_button_command1(OPT_ARGS_STR);
+char * opt_solver_third_button_command2(OPT_ARGS_STR);
+char * opt_solver_third_button_command3(OPT_ARGS_STR);
+char * opt_solver_third_button_command4(OPT_ARGS_STR);
+char * opt_solver_fourth_button(OPT_ARGS_STR);
+char * opt_solver_fourth_button0(OPT_ARGS_STR);
+char * opt_solver_fourth_button1(OPT_ARGS_STR);
+char * opt_solver_fourth_button2(OPT_ARGS_STR);
+char * opt_solver_fourth_button3(OPT_ARGS_STR);
+char * opt_solver_fourth_button4(OPT_ARGS_STR);
+char * opt_solver_fourth_button_command(OPT_ARGS_STR);
+char * opt_solver_fourth_button_command0(OPT_ARGS_STR);
+char * opt_solver_fourth_button_command1(OPT_ARGS_STR);
+char * opt_solver_fourth_button_command2(OPT_ARGS_STR);
+char * opt_solver_fourth_button_command3(OPT_ARGS_STR);
+char * opt_solver_fourth_button_command4(OPT_ARGS_STR);
+char * opt_solver_fifth_button(OPT_ARGS_STR);
+char * opt_solver_fifth_button0(OPT_ARGS_STR);
+char * opt_solver_fifth_button1(OPT_ARGS_STR);
+char * opt_solver_fifth_button2(OPT_ARGS_STR);
+char * opt_solver_fifth_button3(OPT_ARGS_STR);
+char * opt_solver_fifth_button4(OPT_ARGS_STR);
+char * opt_solver_fifth_button_command(OPT_ARGS_STR);
+char * opt_solver_fifth_button_command0(OPT_ARGS_STR);
+char * opt_solver_fifth_button_command1(OPT_ARGS_STR);
+char * opt_solver_fifth_button_command2(OPT_ARGS_STR);
+char * opt_solver_fifth_button_command3(OPT_ARGS_STR);
+char * opt_solver_fifth_button_command4(OPT_ARGS_STR);
 char * opt_view_name(OPT_ARGS_STR);
 char * opt_view_format(OPT_ARGS_STR);
 char * opt_view_filename(OPT_ARGS_STR);
@@ -207,8 +338,24 @@ double opt_mesh_nb_hexahedra(OPT_ARGS_NUM);
 double opt_mesh_nb_prisms(OPT_ARGS_NUM);
 double opt_mesh_nb_pyramids(OPT_ARGS_NUM);
 double opt_mesh_cpu_time(OPT_ARGS_NUM);
-double opt_solver_getdp_popupmessages(OPT_ARGS_NUM);
-double opt_solver_getdp_mergeviews(OPT_ARGS_NUM);
+double opt_solver_client_server(OPT_ARGS_NUM);
+double opt_solver_client_server0(OPT_ARGS_NUM);
+double opt_solver_client_server1(OPT_ARGS_NUM);
+double opt_solver_client_server2(OPT_ARGS_NUM);
+double opt_solver_client_server3(OPT_ARGS_NUM);
+double opt_solver_client_server4(OPT_ARGS_NUM);
+double opt_solver_popup_messages(OPT_ARGS_NUM);
+double opt_solver_popup_messages0(OPT_ARGS_NUM);
+double opt_solver_popup_messages1(OPT_ARGS_NUM);
+double opt_solver_popup_messages2(OPT_ARGS_NUM);
+double opt_solver_popup_messages3(OPT_ARGS_NUM);
+double opt_solver_popup_messages4(OPT_ARGS_NUM);
+double opt_solver_merge_views(OPT_ARGS_NUM);
+double opt_solver_merge_views0(OPT_ARGS_NUM);
+double opt_solver_merge_views1(OPT_ARGS_NUM);
+double opt_solver_merge_views2(OPT_ARGS_NUM);
+double opt_solver_merge_views3(OPT_ARGS_NUM);
+double opt_solver_merge_views4(OPT_ARGS_NUM);
 double opt_post_scales(OPT_ARGS_NUM);
 double opt_post_link(OPT_ARGS_NUM);
 double opt_post_smooth(OPT_ARGS_NUM);
diff --git a/Fltk/Callbacks.cpp b/Fltk/Callbacks.cpp
index 6a9a6c8115..d83419c224 100644
--- a/Fltk/Callbacks.cpp
+++ b/Fltk/Callbacks.cpp
@@ -1,4 +1,4 @@
-// $Id: Callbacks.cpp,v 1.100 2001-12-06 08:10:59 geuzaine Exp $
+// $Id: Callbacks.cpp,v 1.101 2002-01-03 10:25:06 geuzaine Exp $
 
 #include <sys/types.h>
 #include <signal.h>
@@ -1584,105 +1584,122 @@ void mesh_define_transfinite_volume_cb(CALLBACK_ARGS){
 
 #include "Solvers.h"
 
-void getdp_cb(CALLBACK_ARGS){
-  char file[256];
-  static int first=1;
-  if(first){
-    first = 0;
+void solver_cb(CALLBACK_ARGS){
+  char file[256], tmp[256];
+  static int first[5]={1,1,1,1,1};
+  int num = (int)data;
+
+  if(first[num]){
+    first[num] = 0;
     strcpy(file,CTX.base_filename);
-    strcat(file,".pro");
-    WID->getdp_input[0]->value(file);
+    strcat(file,SINFO[num].extension);
+    WID->solver[num].input[0]->value(file);
+  }
+  if(SINFO[num].nboptions){
+    sprintf(tmp, "%s %s", SINFO[num].option_command,
+	    (char*)WID->solver[num].input[0]->value());
+    Solver(num, tmp);
   }
-  GetDP((char*)WID->getdp_input[0]->value());
-  WID->create_getdp_window();
+  WID->create_solver_window(num);
 }
-void getdp_file_open_cb(CALLBACK_ARGS){
-  char *newfile;
-  newfile = fl_file_chooser("Open problem definition file", "*.[Pp][Rr][Oo]", NULL);
+void solver_file_open_cb(CALLBACK_ARGS){
+  char *newfile, tmp[256];
+  int num = (int)data;
+  sprintf(tmp, "*%s", SINFO[num].extension);
+  newfile = fl_file_chooser("Open problem definition file", tmp, NULL);
   if (newfile != NULL){
-    WID->getdp_input[0]->value(newfile);
-    GetDP(newfile);
+    WID->solver[num].input[0]->value(newfile);
+    if(SINFO[num].nboptions){
+      sprintf(tmp, "%s %s", SINFO[num].option_command, newfile);
+      Solver(num, tmp);
+    }
   }
 }
-void getdp_file_edit_cb(CALLBACK_ARGS){
+void solver_file_edit_cb(CALLBACK_ARGS){
   char cmd[1000];
-  sprintf(cmd, CTX.editor, WID->getdp_input[0]->value());
+  int num = (int)data;
+  sprintf(cmd, CTX.editor, WID->solver[num].input[0]->value());
   Msg(INFO, "Starting text editor '%s'", cmd);
   system(cmd);
 }
-void getdp_choose_mesh_cb(CALLBACK_ARGS){
+void solver_choose_mesh_cb(CALLBACK_ARGS){
   char *newfile;
+  int num = (int)data;
   newfile = fl_file_chooser("Open mesh file", "*.[Mm][Ss][Hh]", NULL);
-  if (newfile != NULL) WID->getdp_input[1]->value(newfile);
-}
-void getdp_pre_cb(CALLBACK_ARGS){
-  char arg[256];
-  if(GetDP_Info.popupmessages) WID->create_message_window();
-  if(strlen(WID->getdp_input[1]->value()))
-    sprintf(arg, "%s -msh %s -pre %s", 
-	    WID->getdp_input[0]->value(),
-	    WID->getdp_input[1]->value(),
-	    GetDP_Info.res[WID->getdp_choice[0]->value()]);
-  else
-    sprintf(arg, "%s -pre %s", 
-	    WID->getdp_input[0]->value(), 
-	    GetDP_Info.res[WID->getdp_choice[0]->value()]);
-
-  GetDP(arg);
-}
-void getdp_cal_cb(CALLBACK_ARGS){
-  char arg[256];
-  if(GetDP_Info.popupmessages) WID->create_message_window();
-  if(strlen(WID->getdp_input[1]->value()))
-    sprintf(arg, "%s -msh %s -cal", 
-	    WID->getdp_input[0]->value(),
-	    WID->getdp_input[1]->value());
-  else
-    sprintf(arg, "%s -cal", WID->getdp_input[0]->value());
-  GetDP(arg);
-}
-void getdp_post_cb(CALLBACK_ARGS){
-  char arg[256];
-  if(GetDP_Info.popupmessages) WID->create_message_window();
-  if(strlen(WID->getdp_input[1]->value()))
-    sprintf(arg, "%s -msh %s -bin -pos %s",
-	    WID->getdp_input[0]->value(),
-	    WID->getdp_input[1]->value(),
-	    GetDP_Info.postop[WID->getdp_choice[1]->value()]);
-  else
-    sprintf(arg, "%s -bin -pos %s",
-	    WID->getdp_input[0]->value(),
-	    GetDP_Info.postop[WID->getdp_choice[1]->value()]);
-  GetDP(arg);
-}
-void getdp_kill_cb(CALLBACK_ARGS){
-  if(GetDP_Info.pid > 0){
-    kill(GetDP_Info.pid, 9);
-    Msg(INFO, "Killed GetDP pid %d", GetDP_Info.pid);
-  }
-  GetDP_Info.pid = -1;
-}
-void getdp_choose_command_cb(CALLBACK_ARGS){
+  if (newfile != NULL) WID->solver[num].input[1]->value(newfile);
+}
+int nbs(char *str){
+  int i, nb=0;
+  for(i=0; i<(int)strlen(str)-1; i++){
+    if(str[i]=='%' && str[i+1]=='s'){
+      nb++; i++;
+    }
+  }
+  return nb;
+}
+void solver_command_cb(CALLBACK_ARGS){
+  char arg[512], mesh[256], command[256];
+  int num = ((int*)data)[0];
+  int idx = ((int*)data)[1];
+  int i, usedopts = 0;
+
+  if(SINFO[num].popup_messages) WID->create_message_window();
+
+  if(strlen(WID->solver[num].input[1]->value()))
+    sprintf(mesh, SINFO[num].mesh_command, WID->solver[num].input[1]->value());
+  else 
+    strcpy(mesh, "");
+
+  //printf("num%d idx%d %s -> %d\n", 
+  //	 num, idx, SINFO[num].button_command[idx], nbs(SINFO[num].button_command[idx]));
+
+  if(nbs(SINFO[num].button_command[idx])){
+    for(i=0; i<idx; i++) usedopts += nbs(SINFO[num].button_command[i]);
+    if(usedopts > SINFO[num].nboptions){
+      Msg(GERROR, "Missing options to execute command");
+      return;
+    }
+    sprintf(command, SINFO[num].button_command[idx], 
+	    SINFO[num].option[usedopts][WID->solver[num].choice[usedopts]->value()]);
+  }
+  else{
+    strcpy(command, SINFO[num].button_command[idx]);
+  }
+
+  sprintf(arg, "%s %s %s", WID->solver[num].input[0]->value(), mesh, command);
+
+  Solver(num, arg);
+}
+void solver_kill_cb(CALLBACK_ARGS){
+  int num = (int)data;
+  if(SINFO[num].pid > 0){
+    kill(SINFO[num].pid, 9);
+    Msg(INFO, "Killed %s pid %d", SINFO[num].name, SINFO[num].pid);
+  }
+  SINFO[num].pid = -1;
+}
+void solver_choose_executable_cb(CALLBACK_ARGS){
   char *newfile;
+  int num = (int)data;
 #if defined(WIN32)
   newfile = fl_file_chooser("Choose executable", "*.[Ee][Xx][Ee]", NULL);
 #else
   newfile = fl_file_chooser("Choose executable", "*", NULL);
 #endif
-  if (newfile != NULL) WID->getdp_input[2]->value(newfile);
+  if (newfile != NULL) WID->solver[num].input[2]->value(newfile);
 }
-void getdp_ok_cb(CALLBACK_ARGS){
-  opt_solver_getdp_popupmessages(0, GMSH_SET, WID->getdp_butt[0]->value());
-  opt_solver_getdp_mergeviews(0, GMSH_SET, WID->getdp_butt[1]->value());
-
+void solver_ok_cb(CALLBACK_ARGS){
+  int num = (int)data;
   int retry=0;
-  if(strcmp(opt_solver_getdp_command(0, GMSH_GET, NULL), 
-	    WID->getdp_input[2]->value())) retry=1;
-  opt_solver_getdp_command(0, GMSH_SET, (char*)WID->getdp_input[2]->value());
-  if(retry) getdp_cb(NULL,NULL);
+  opt_solver_popup_messages(num, GMSH_SET, WID->solver[num].butt[0]->value());
+  opt_solver_merge_views(num, GMSH_SET, WID->solver[num].butt[1]->value());
+  opt_solver_client_server(num, GMSH_SET, WID->solver[num].butt[2]->value());
+  if(strcmp(opt_solver_executable(num, GMSH_GET, NULL),
+	    WID->solver[num].input[2]->value())) retry=1;
+  opt_solver_executable(num, GMSH_SET, (char*)WID->solver[num].input[2]->value());
+  if(retry) solver_cb(NULL,data);
 }
 
-
 // Dynamic Post Menus
 
 void view_toggle_cb(CALLBACK_ARGS){
diff --git a/Fltk/Callbacks.h b/Fltk/Callbacks.h
index 211d409d03..ce82715571 100644
--- a/Fltk/Callbacks.h
+++ b/Fltk/Callbacks.h
@@ -204,16 +204,14 @@ void con_mesh_define_transfinite_volume_cb(CALLBACK_ARGS) ;
 
 // Dynamic Solver Menus
 
-void getdp_cb(CALLBACK_ARGS);
-void getdp_file_open_cb(CALLBACK_ARGS);
-void getdp_file_edit_cb(CALLBACK_ARGS);
-void getdp_choose_mesh_cb(CALLBACK_ARGS);
-void getdp_pre_cb(CALLBACK_ARGS);
-void getdp_cal_cb(CALLBACK_ARGS);
-void getdp_post_cb(CALLBACK_ARGS);
-void getdp_kill_cb(CALLBACK_ARGS);
-void getdp_choose_command_cb(CALLBACK_ARGS);
-void getdp_ok_cb(CALLBACK_ARGS);
+void solver_cb(CALLBACK_ARGS);
+void solver_file_open_cb(CALLBACK_ARGS);
+void solver_file_edit_cb(CALLBACK_ARGS);
+void solver_choose_mesh_cb(CALLBACK_ARGS);
+void solver_command_cb(CALLBACK_ARGS);
+void solver_kill_cb(CALLBACK_ARGS);
+void solver_choose_executable_cb(CALLBACK_ARGS);
+void solver_ok_cb(CALLBACK_ARGS);
 
 // Dynamic post menus
 
diff --git a/Fltk/GUI.cpp b/Fltk/GUI.cpp
index f64080efac..2e9951f4eb 100644
--- a/Fltk/GUI.cpp
+++ b/Fltk/GUI.cpp
@@ -1,4 +1,4 @@
-// $Id: GUI.cpp,v 1.141 2001-12-06 08:10:59 geuzaine Exp $
+// $Id: GUI.cpp,v 1.142 2002-01-03 10:25:06 geuzaine Exp $
 
 // To make the interface as visually consistent as possible, please:
 // - use the IW, BB, BH, BW and WB values
@@ -276,7 +276,11 @@ Context_Item menu_mesh[] =
 
 Context_Item menu_solver[] = 
 { { "2Solver", NULL } ,
-  { "GetDP", (Fl_Callback *)getdp_cb } ,
+  { "Solver 0", (Fl_Callback *)solver_cb , (void*)0} ,
+  { "Solver 1", (Fl_Callback *)solver_cb , (void*)1} ,
+  { "Solver 2", (Fl_Callback *)solver_cb , (void*)2} ,
+  { "Solver 3", (Fl_Callback *)solver_cb , (void*)3} ,
+  { "Solver 4", (Fl_Callback *)solver_cb , (void*)4} ,
   { NULL } };
 
 Context_Item menu_post[] = 
@@ -499,7 +503,8 @@ int GUI::global_shortcuts(int event){
 //***************************** The GUI constructor ************************************
 
 GUI::GUI(int argc, char **argv) {
-  
+  int i;
+
   m_window = NULL;
   g_window = NULL;
   gen_window = NULL;
@@ -514,7 +519,6 @@ GUI::GUI(int argc, char **argv) {
   view_window = NULL;
   context_geometry_window = NULL;
   context_mesh_window = NULL;
-  getdp_window = NULL;
 
   if(strlen(CTX.display)) Fl::display(CTX.display);
 
@@ -552,7 +556,11 @@ GUI::GUI(int argc, char **argv) {
   create_message_window();
   create_visibility_window();
   create_about_window();
-  create_getdp_window();
+
+  for(i=0; i<5; i++){
+    solver[i].window = NULL;
+    create_solver_window(i);
+  }
 
   // Draw the scene
   g_opengl_window->redraw();
@@ -768,12 +776,22 @@ void GUI::set_context(Context_Item *menu_asked, int flag){
     }
     break;
   default : // geometry, mesh, solver contexts
+    if(m_module_butt->value() == 2){ //solver
+      menu[1].label = opt_solver_name0(0,GMSH_GET,0);
+      menu[2].label = opt_solver_name1(0,GMSH_GET,0);
+      menu[3].label = opt_solver_name2(0,GMSH_GET,0);
+      menu[4].label = opt_solver_name3(0,GMSH_GET,0);
+      menu[5].label = opt_solver_name4(0,GMSH_GET,0);
+      for(i=0 ; i<5 ; i++){
+	if(!strlen(menu[i+1].label)) menu[i+1].label = NULL;
+      }
+    }
     for(i=0 ; i < NB_BUTT_MAX ; i++){
       m_toggle_butt[i]->hide();
       m_popup_butt[i]->hide();
       if(menu[i+1].label){
 	m_push_butt[i]->label(menu[i+1].label);
-	m_push_butt[i]->callback(menu[i+1].callback);
+	m_push_butt[i]->callback(menu[i+1].callback,menu[i+1].arg);
 	m_push_butt[i]->redraw();
 	m_push_butt[i]->show();
 	nb++;
@@ -1461,7 +1479,7 @@ void GUI::create_solver_options_window(){
 
   int width = 20*CTX.fontsize;
   int height = 5*WB+8*BH ;
-  
+
   solver_window = new Fl_Window(width,height);
   solver_window->box(WINDOW_BOX);
   solver_window->label("Solver options");
@@ -1470,10 +1488,20 @@ void GUI::create_solver_options_window(){
     { 
       Fl_Group* o = new Fl_Group(WB, WB+BH, width-2*WB, height-3*WB-2*BH, "Solvers");
       o->labelsize(CTX.fontsize);
+
       Fl_Box *text =  new Fl_Box(FL_NO_BOX, 2*WB, 3*WB+1*BH, width-4*WB, 2*BH,
-				 "There are no global solver options available yet");
+				 "There are no global solver options available yet.\n\n"
+				 "To define your own solver interface, edit the option file.");
       text->align(FL_ALIGN_LEFT|FL_ALIGN_TOP|FL_ALIGN_INSIDE|FL_ALIGN_WRAP);
       text->labelsize(CTX.fontsize);
+      /*
+	int BW = width-4*WB;
+	solver_butt[0] = new Fl_Check_Button(2*WB, 2*WB+1*BH, BW, BH, "Use Unix sockets");
+	solver_butt[0]->type(FL_TOGGLE_BUTTON);
+	solver_butt[0]->down_box(TOGGLE_BOX);
+	solver_butt[0]->labelsize(CTX.fontsize);
+	solver_butt[0]->selection_color(TOGGLE_COLOR);
+      */
       o->end();
     }
     o->end();
@@ -1766,7 +1794,7 @@ void GUI::set_statistics(){
 void GUI::add_multiline_in_browser(Fl_Browser *o, char* prefix, char *str){
   int start = 0, len;
   char *buff;
-  if(!strlen(str) || !strcmp(str, "\n")){
+  if(!str || !strlen(str) || !strcmp(str, "\n")){
     o->add("");
     return;
   }
@@ -1912,6 +1940,7 @@ void GUI::create_message_window(){
 }
 
 void GUI::add_message(char *msg){
+  for(int i=0 ; i<(int)strlen(msg) ; i++) if(msg[i]=='\n') msg[i] = ' ';
   msg_browser->add(msg,0);
   msg_browser->bottomline(msg_browser->size());
 }
@@ -2860,140 +2889,151 @@ void GUI::create_mesh_context_window(int num){
 }
 
 
-//************** Create the window for the getdp solver **************
+//************** Create the windows for the solvers **************
 
-void GUI::create_getdp_window(){
-  int i;
+#include "Solvers.h"
+
+void GUI::create_solver_window(int num){
+  int i, nbbutts=0, newrow=0;
   static Fl_Group *g[10];
 
   int LL = (int)(1.75*IW);
 
-  if(getdp_window){
-    getdp_window->show();
+  if(solver[num].window){
+    solver[num].window->show();
     return;
   }
-  
+
+  for(i=0; i<5; i++)
+    if(strlen(SINFO[num].option_name[i])) SINFO[num].nboptions = i+1;
+
+  for(i=0; i<5; i++)
+    if(strlen(SINFO[num].button_name[i])) nbbutts++ ;
+  if(nbbutts > 3) newrow = 1;
+
   int width = 5*BB+6*WB;
-  int height = 10*WB+ 8*BH  ;
+  int height = (8+SINFO[num].nboptions+newrow)*WB+ (6+SINFO[num].nboptions+newrow)*BH  ;
+  if(height < 7*WB+7*BH) height = 7*WB+7*BH; //minimum height required by Options tab
   
-  getdp_window = new Fl_Window(width,height);
-  getdp_window->box(WINDOW_BOX);
-  getdp_window->label("GetDP solver");
+  solver[num].window = new Fl_Window(width,height);
+  solver[num].window->box(WINDOW_BOX);
   { 
-    Fl_Tabs* o = new Fl_Tabs(WB, WB, width-2*WB, height-3*WB-1*BH);
+    Fl_Tabs* o = new Fl_Tabs(WB, WB, width-2*WB, height-(3+newrow)*WB-(1+newrow)*BH);
     { 
-      g[0] = new Fl_Group(WB, WB+BH, width-2*WB, height-3*WB-2*BH, "General");
+      g[0] = new Fl_Group(WB, WB+BH, width-2*WB, height-(3+newrow)*WB-(2+newrow)*BH, "General");
       g[0]->labelsize(CTX.fontsize);
       
-      getdp_input[0] = new Fl_Input(2*WB, 2*WB+1*BH, LL, BH, "Problem");
+      solver[num].input[0] = new Fl_Input(2*WB, 2*WB+1*BH, LL, BH, "Problem");
       Fl_Button *b1 = new Fl_Button(2*WB, 3*WB+2*BH, BB, BH, "Choose");
-      b1->callback(getdp_file_open_cb);
+      b1->callback(solver_file_open_cb, (void*)num);
       b1->labelsize(CTX.fontsize);
       Fl_Button *b2 = new Fl_Button(3*WB+BB, 3*WB+2*BH, BB, BH, "Edit");
-      b2->callback(getdp_file_edit_cb);
+      b2->callback(solver_file_edit_cb, (void*)num);
       b2->labelsize(CTX.fontsize);
-      
-      getdp_choice[0] = new Fl_Choice(2*WB, 4*WB+3*BH, LL, BH,"Resolution");
-      getdp_choice[1] = new Fl_Choice(2*WB, 5*WB+4*BH, LL, BH,"Post operation");
-      
-      getdp_input[1] = new Fl_Input(2*WB, 6*WB+5*BH, LL, BH, "Mesh");
-      Fl_Button *b3 = new Fl_Button(2*WB, 7*WB+6*BH, BB, BH, "Choose");
-      b3->callback(getdp_choose_mesh_cb);
+
+      solver[num].input[1] = new Fl_Input(2*WB, 4*WB+3*BH, LL, BH, "Mesh");
+      Fl_Button *b3 = new Fl_Button(2*WB, 5*WB+4*BH, BB, BH, "Choose");
+      b3->callback(solver_choose_mesh_cb, (void*)num);
       b3->labelsize(CTX.fontsize);
-      
+
       for(i=0 ; i<2 ; i++){
-	getdp_input[i]->labelsize(CTX.fontsize);
-	getdp_input[i]->textsize(CTX.fontsize);
-	getdp_input[i]->align(FL_ALIGN_RIGHT);
+	solver[num].input[i]->labelsize(CTX.fontsize);
+	solver[num].input[i]->textsize(CTX.fontsize);
+	solver[num].input[i]->align(FL_ALIGN_RIGHT);
       }
-      for(i=0 ; i<2 ; i++){
-	getdp_choice[i]->textsize(CTX.fontsize);
-	getdp_choice[i]->labelsize(CTX.fontsize);
-	getdp_choice[i]->align(FL_ALIGN_RIGHT);
+
+      for(i=0; i<SINFO[num].nboptions; i++){
+	solver[num].choice[i] = new Fl_Choice(2*WB, (6+i)*WB+(5+i)*BH, LL, BH,
+					      SINFO[num].option_name[i]);
+	solver[num].choice[i]->textsize(CTX.fontsize);
+	solver[num].choice[i]->labelsize(CTX.fontsize);
+	solver[num].choice[i]->align(FL_ALIGN_RIGHT);
       }
-      
+
       g[0]->end();
     }
     { 
-      g[1] = new Fl_Group(WB, WB+BH, width-2*WB, height-3*WB-2*BH, "Options");
+      g[1] = new Fl_Group(WB, WB+BH, width-2*WB, height-(3+newrow)*WB-(2+newrow)*BH, "Options");
       g[1]->labelsize(CTX.fontsize);
       
-      getdp_input[2] = new Fl_Input(2*WB, 2*WB+1*BH, LL, BH, "Command");
+      solver[num].input[2] = new Fl_Input(2*WB, 2*WB+1*BH, LL, BH, "Executable");
+      solver[num].input[2]->labelsize(CTX.fontsize);
+      solver[num].input[2]->textsize(CTX.fontsize);
+      solver[num].input[2]->align(FL_ALIGN_RIGHT);
       Fl_Button *b = new Fl_Button(2*WB, 3*WB+2*BH, BB, BH, "Choose");
-      b->callback(getdp_choose_command_cb);
+      b->callback(solver_choose_executable_cb, (void*)num);
       b->labelsize(CTX.fontsize);
       
-      getdp_butt[0] = new Fl_Check_Button(2*WB, 4*WB+3*BH, LL, BH, 
-					  "Automatic message display");
-      getdp_butt[1] = new Fl_Check_Button(2*WB, 4*WB+4*BH, LL, BH, 
-					  "Automatic view merge");
-      
-      getdp_input[2]->labelsize(CTX.fontsize);
-      getdp_input[2]->textsize(CTX.fontsize);
-      getdp_input[2]->align(FL_ALIGN_RIGHT);
-      for(i=0 ; i<2 ; i++){
-	getdp_butt[i]->type(FL_TOGGLE_BUTTON);
-	getdp_butt[i]->down_box(TOGGLE_BOX);
-	getdp_butt[i]->labelsize(CTX.fontsize);
-	getdp_butt[i]->selection_color(TOGGLE_COLOR);
+      solver[num].butt[2] = new Fl_Check_Button(2*WB, 4*WB+3*BH, LL, BH, 
+						"Client/server connection");
+      solver[num].butt[0] = new Fl_Check_Button(2*WB, 4*WB+4*BH, LL, BH, 
+						"Automatic message display");
+      solver[num].butt[1] = new Fl_Check_Button(2*WB, 4*WB+5*BH, LL, BH, 
+						"Automatic view merge");
+      for(i=0 ; i<3 ; i++){
+	solver[num].butt[i]->type(FL_TOGGLE_BUTTON);
+	solver[num].butt[i]->down_box(TOGGLE_BOX);
+	solver[num].butt[i]->labelsize(CTX.fontsize);
+	solver[num].butt[i]->selection_color(TOGGLE_COLOR);
       }
       
-      Fl_Return_Button* o = new Fl_Return_Button(width-BB-2*WB, 2*WB+7*BH, BB, BH, "OK");
+      Fl_Return_Button* o = new Fl_Return_Button(width-BB-2*WB, 
+						 height-(3+newrow)*WB-(2+newrow)*BH, BB, BH, "OK");
       o->labelsize(CTX.fontsize);
-      o->callback(getdp_ok_cb);
+      o->callback(solver_ok_cb, (void*)num);
       
       g[1]->end();
     }
     { 
-      g[2] = new Fl_Group(WB, WB+BH, width-2*WB, height-3*WB-2*BH, "About");
+      g[2] = new Fl_Group(WB, WB+BH, width-2*WB, height-(3+newrow)*WB-(2+newrow)*BH, "About");
       g[2]->labelsize(CTX.fontsize);
       
-      Fl_Browser *o = new Fl_Browser(2*WB, 2*WB+1*BH, width-4*WB, height-5*WB-2*BH);
-      o->add("");
-      o->add("@c@b@.GetDP");
-      o->add("@c@.A General environment for the treatment");
-      o->add("@c@.of Discrete Problems");
+      Fl_Browser *o = new Fl_Browser(2*WB, 2*WB+1*BH, width-4*WB,
+				     height-(5+newrow)*WB-(2+newrow)*BH);
+      o->textsize(CTX.fontsize);
       o->add("");
-      o->add("@c@.Experimental solver plugin for Gmsh");
+      add_multiline_in_browser(o, "@c@b@.", SINFO[num].name);
       o->add("");
-      o->add("@c@.Visit http://www.geuz.org/getdp/ for more info");
-      o->textsize(CTX.fontsize);
+      add_multiline_in_browser(o, "@c@. ", SINFO[num].help);
       
       g[2]->end();
     }
     o->end();
   }
-  
-  { 
-    Fl_Button* o = new Fl_Button(width-5*BB-5*WB, height-BH-WB, BB, BH, "Pre");
-    o->labelsize(CTX.fontsize);
-    o->callback(getdp_pre_cb);
-  }
-  { 
-    Fl_Button* o = new Fl_Button(width-4*BB-4*WB, height-BH-WB, BB, BH, "Cal");
-    o->labelsize(CTX.fontsize);
-    o->callback(getdp_cal_cb);
-  }
-  { 
-    Fl_Button* o = new Fl_Button(width-3*BB-3*WB, height-BH-WB, BB, BH, "Post");
-    o->labelsize(CTX.fontsize);
-    o->callback(getdp_post_cb);
+
+  static int arg[5][5][2];
+  int nb=0;
+  for(i=4; i>=0; i--){
+    if(strlen(SINFO[num].button_name[i])){
+      arg[num][i][0]=num;
+      arg[num][i][1]=i;
+      solver[num].command[nb] = new Fl_Button(width-(1+nb+2*!newrow)*BB-(1+nb+2*!newrow)*WB, 
+					      height-(1+newrow)*BH-(1+newrow)*WB, 
+					      BB, BH,
+					      SINFO[num].button_name[i]);
+      solver[num].command[nb]->callback(solver_command_cb,(void*)arg[num][i]);
+      solver[num].command[nb]->labelsize(CTX.fontsize);
+      nb++;
+    }
   }
+  
   { 
     Fl_Button* o = new Fl_Button(width-2*BB-2*WB, height-BH-WB, BB, BH, "Kill");
     o->labelsize(CTX.fontsize);
-    o->callback(getdp_kill_cb);
+    o->callback(solver_kill_cb, (void*)num);
   }
   { 
     Fl_Button* o = new Fl_Button(width-BB-WB, height-BH-WB, BB, BH, "Cancel");
     o->labelsize(CTX.fontsize);
-    o->callback(cancel_cb, (void*)getdp_window);
+    o->callback(cancel_cb, (void*)solver[num].window);
   }
   
   
   if(CTX.center_windows)
-    getdp_window->position(m_window->x()+m_window->w()/2-width/2,
-			   m_window->y()+9*BH-height/2);
-  getdp_window->end();
+    solver[num].window->position(m_window->x()+m_window->w()/2-width/2,
+				 m_window->y()+9*BH-height/2);
+  solver[num].window->end();
 }
 
+
+
diff --git a/Fltk/GUI.h b/Fltk/GUI.h
index 573ae7c235..07d2a1f782 100644
--- a/Fltk/GUI.h
+++ b/Fltk/GUI.h
@@ -36,6 +36,7 @@
 typedef struct{
   char *label;
   Fl_Callback* callback;
+  void *arg;
 } Context_Item;
 
 extern Context_Item menu_geometry[]; 
@@ -76,6 +77,17 @@ struct PluginDialogBox
   Fl_Value_Input *view_value[20];
 };
 
+// The dialog for solvers
+
+struct SolverDialogBox
+{
+  Fl_Window *window;
+  Fl_Input *input[50] ;
+  Fl_Choice *choice[10] ;
+  Fl_Check_Button *butt[10] ;
+  Fl_Button *command[10] ;
+};
+
 // The GUI class contains only the important widgets (which can be set/queried).
 
 class GUI{
@@ -173,10 +185,7 @@ public:
   Fl_Input         *context_mesh_input[20] ;
 
   // solver windows
-  Fl_Window        *getdp_window ;
-  Fl_Input         *getdp_input[50] ;
-  Fl_Choice        *getdp_choice[10] ;
-  Fl_Check_Button  *getdp_butt[10] ;
+  SolverDialogBox  solver[5] ;
 
   // the constructor
   GUI(int argc, char **argv);
@@ -197,7 +206,7 @@ public:
   void create_about_window();
   void create_geometry_context_window(int num);
   void create_mesh_context_window(int num);
-  void create_getdp_window();
+  void create_solver_window(int num);
 
   // general purpose interaction
   void run();
diff --git a/Fltk/GmshServer.cpp b/Fltk/GmshServer.cpp
new file mode 100644
index 0000000000..cf91c9e8c6
--- /dev/null
+++ b/Fltk/GmshServer.cpp
@@ -0,0 +1,127 @@
+/* $Id: GmshServer.cpp,v 1.1 2002-01-03 10:25:06 geuzaine Exp $ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef _AIX
+#include <strings.h>
+#endif
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/un.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+/* private functions */
+
+static int Socket_ReceiveData(int socket, void *buffer, int bytes){
+  int sofar, remaining, len;
+  char *buf;
+
+  buf = (char*)buffer;
+  sofar = 0;
+  remaining = bytes;
+  do {
+    len = read(socket, buf + sofar, remaining);
+    if (len<=0) return 0;
+    sofar += len;
+    remaining -= len;
+  } while (remaining>0);
+  return bytes;
+}
+
+static int Socket_UnlinkName(char *name){
+#ifdef _AIX
+   char name2[1000];
+   strcpy(name2,name);
+   name2[strlen(name2)-1] = '\0';
+   return unlink(name2);
+#else
+   return unlink(name);
+#endif
+}
+
+
+/* public interface */
+
+int Gmsh_StartClient(char *command, char *sockname){
+  int s, sock;
+#ifdef linux
+  socklen_t len ;
+#else
+  int len;
+#endif
+  struct sockaddr_un addr, from;
+  fd_set rfds;
+  struct timeval tv;
+  int retval;
+
+  /* no socket? launch the command! */
+  if(!sockname){
+    system(command);
+    return 1;
+  }
+
+  /* first delete the socket's name if it exists */
+  Socket_UnlinkName(sockname);
+  
+  /* make the socket */
+  s = socket(PF_UNIX, SOCK_STREAM, 0);
+  if (s<0) return -1; /* Error: Couldn't create socket */
+  
+  /* bind the socket to its name */
+  strcpy(addr.sun_path, sockname);
+  addr.sun_family = AF_UNIX;
+  if(bind(s, (struct sockaddr *)&addr, 
+	  strlen(addr.sun_path)+sizeof(addr.sun_family)) < 0)
+    return -2; /* Error: Couldn't bind socket to name */
+  
+  /* change permissions on the socket name in case it has to be rm'd later */
+  chmod(sockname, 0666);
+  
+  /* Start the external function via system() call */
+  system(command);
+  
+  /* wait for external function to connect */
+  if(listen(s, 20)) return -3; /* Error: Socket listen failed */
+  
+  /* Watch s to see when it has input. */
+  /* Wait up to 2 seconds */
+  tv.tv_sec = 2;
+  tv.tv_usec = 0;
+  FD_ZERO(&rfds);
+  FD_SET(s, &rfds);
+  retval = select(s+1, &rfds, NULL, NULL, &tv);
+  
+  if(!retval) return -4; /* Error: Socket listening timeout */
+  
+  len = sizeof(from);
+  if ((sock = accept(s, (struct sockaddr *)&from, &len)) < 0)
+    return -5; /* Error: Socket accept failed */
+  
+  close(s); /* don't need this socket anymore */
+  
+  return sock;
+}
+
+int Gmsh_ReceiveString(int socket, int *type, char str[]){
+   int len;
+
+   Socket_ReceiveData(socket, type, sizeof(int));
+   if (Socket_ReceiveData(socket, &len, sizeof(int))) {
+     if (Socket_ReceiveData(socket, str, len)==len) {
+       str[len] = '\0';
+       return 1;
+     }
+   }
+   return 0;
+}
+
+int Gmsh_StopClient(char *sockname, int sock){
+  if(Socket_UnlinkName(sockname)==-1)
+    return -1; /* Impossible to unlink the socket */
+  close(sock);
+  return 0;
+}
+
diff --git a/Fltk/GmshServer.h b/Fltk/GmshServer.h
new file mode 100644
index 0000000000..6714cca65c
--- /dev/null
+++ b/Fltk/GmshServer.h
@@ -0,0 +1,8 @@
+#ifndef _GMSH_SERVER_H_
+#define _GMSH_SERVER_H_
+
+int Gmsh_StartClient(char *command, char *sockname);
+int Gmsh_ReceiveString(int socket, int *type, char str[]);
+int Gmsh_StopClient(char *sockname, int socket);
+
+#endif
diff --git a/Fltk/Makefile b/Fltk/Makefile
index afbaccadf0..51c1aab05f 100644
--- a/Fltk/Makefile
+++ b/Fltk/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.30 2001-12-04 10:47:39 geuzaine Exp $
+# $Id: Makefile,v 1.31 2002-01-03 10:25:06 geuzaine Exp $
 #
 # Makefile for "libFltk.a"
 #
@@ -12,7 +12,7 @@ RANLIB   = ranlib
 
 LIB      = ../lib/libFltk.a
 INCLUDE  = -I../Common -I../DataStr -I../Graphics -I../Geo\
-           -I../Mesh -I../Parser -I../Fltk -I../Plugin
+           -I../Mesh -I../Parser -I../Fltk -I../Plugin -I../utils
 
 OPT_FLAGS     = -g -Wall
 OS_FLAGS      = -D_LITTLE_ENDIAN
@@ -33,7 +33,7 @@ SRC = Main.cpp \
       Opengl.cpp\
       Opengl_Window.cpp\
       Colorbar_Window.cpp\
-      Socket.cpp\
+      GmshServer.cpp\
       Solvers.cpp
 
 
@@ -120,10 +120,9 @@ Colorbar_Window.o: Colorbar_Window.cpp ../Common/Gmsh.h \
  ../DataStr/Tree.h ../DataStr/avl.h ../DataStr/Tools.h \
  ../Common/GmshUI.h ../Common/Numeric.h GUI.h Opengl_Window.h \
  Colorbar_Window.h ../Common/ColorTable.h ../Common/Context.h
-Socket.o: Socket.cpp ../Common/Message.h
 Solvers.o: Solvers.cpp ../Common/Gmsh.h ../Common/Message.h \
  ../DataStr/Malloc.h ../DataStr/List.h ../DataStr/Tree.h \
- ../DataStr/avl.h ../DataStr/Tools.h Socket.h ../Parser/OpenFile.h \
+ ../DataStr/avl.h ../DataStr/Tools.h ../Parser/OpenFile.h \
  Solvers.h ../Common/GmshUI.h GUI.h Opengl_Window.h Colorbar_Window.h \
  ../Common/ColorTable.h ../Mesh/Mesh.h ../Mesh/Vertex.h \
  ../Mesh/Simplex.h ../Mesh/Edge.h ../Geo/ExtrudeParams.h \
diff --git a/Fltk/Socket.cpp b/Fltk/Socket.cpp
deleted file mode 100644
index f82a5a4533..0000000000
--- a/Fltk/Socket.cpp
+++ /dev/null
@@ -1,215 +0,0 @@
-/* $Id: Socket.cpp,v 1.14 2001-11-05 08:37:43 geuzaine Exp $ */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#ifdef _AIX
-#include <strings.h>
-#endif
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/stat.h>
-#include <sys/un.h>
-#include <sys/time.h>
-#include <unistd.h>
-
-#include "Message.h"
-
-int Socket_ReceiveData(int socket, void *buffer, int bytes){
-  int sofar, remaining, len;
-  char *buf;
-  
-  buf = (char*)buffer;
-  sofar = 0;
-  remaining = bytes;
-  do {
-    len = read(socket, buf + sofar, remaining);
-    if (len<=0) return 0;
-    sofar += len;
-    remaining -= len;
-  } while (remaining>0);
-  return bytes;
-}
-
-void Socket_SendData(int socket, void *buffer, int bytes){
-  int sofar, remaining, len;
-  char *buf;
-  
-  buf = (char*)buffer;
-  sofar = 0;
-  remaining = bytes;
-  do {
-    len = write(socket, buf + sofar, remaining);
-    sofar += len;
-    remaining -= len;
-  } while (remaining>0);
-}
-
-int Socket_ReceiveInt(int socket, int *i){
-  return Socket_ReceiveData(socket, i, sizeof(int));
-}
-
-void Socket_SendInt(int socket, int i){
-  Socket_SendData(socket, &i, sizeof(int));
-}
-
-int Socket_ReceiveDouble(int socket, double *x){
-  return Socket_ReceiveData(socket, x, sizeof(double));
-}
-
-void Socket_SendDouble(int socket, double x){
-  Socket_SendData(socket, &x, sizeof(double));
-}
-
-int Socket_ReceiveString(int socket, char str[]){
-   int len;
-
-   if (Socket_ReceiveInt(socket, &len)) {
-     if (Socket_ReceiveData(socket, str, len)==len) {
-       str[len] = '\0';
-       return 1;
-     }
-   }
-   return 0;
-}
-
-void Socket_SendString(int socket, char str[]){
-  int len;
-  
-  len = strlen(str);
-  Socket_SendInt(socket, len);
-  Socket_SendData(socket, str, len);
-}
-
-int Socket_UnlinkName(char *name){
-#ifdef _AIX
-   char name2[1000];
-   strcpy(name2,name);
-   name2[strlen(name2)-1] = '\0';
-   return unlink(name2);
-#else
-   return unlink(name);
-#endif
-}
-
-int Socket_StartProgram(char *progname, char *sockname){
-  int s, sock;
-#ifdef linux
-  socklen_t len ;
-#else
-  int len;
-#endif
-  struct sockaddr_un addr, from;
-  char command[1000];
-  fd_set rfds;
-  struct timeval tv;
-  int retval;
-
-  /* first delete the socket's name if it exists */
-  Socket_UnlinkName(sockname);
-  
-  /* make the socket */
-  s = socket(PF_UNIX, SOCK_STREAM, 0);
-  if (s<0) {
-    Msg(GERROR, "Couldn't create socket");
-    return -1;
-  }
-  
-  /* bind the socket to its name */
-  strcpy(addr.sun_path, sockname);
-  addr.sun_family = AF_UNIX;
-  if(bind(s, (struct sockaddr *)&addr, strlen(addr.sun_path)+sizeof(addr.sun_family)) < 0) {
-    Msg(GERROR, "Couldn't bind socket to name '%s'", sockname);
-    return -1;
-  }
-  
-  /* change permissions on the socket name in case it has to be rm'd later */
-  chmod(sockname, 0666);
-  
-  /* Start the external function via system() call */
-  sprintf(command, "%s -socket %s &", progname, sockname);
-  system(command);
-  
-  /* wait for external function to connect */
-  if(listen(s, 20)) Msg(GERROR, "Socket listen failed");
-  
-  /* Watch s to see when it has input. */
-  /* Wait up to 2 seconds */
-  tv.tv_sec = 2;
-  tv.tv_usec = 0;
-  FD_ZERO(&rfds);
-  FD_SET(s, &rfds);
-  retval = select(s+1, &rfds, NULL, NULL, &tv);
-  
-  if(!retval){
-    Msg(GERROR, "Socket listening timeout");	
-    return -1;
-  }
-  
-  len = sizeof(from);
-  if ( (sock = accept(s, (struct sockaddr *)&from, &len)) < 0) {
-    Msg(GERROR, "Socket accept failed");	
-    return -1;
-  }
-  
-  close(s); /* don't need this socket anymore */
-  
-  return sock;
-}
-
-int Socket_StopProgram(char *progname, char *sockname, int sock){
-  if(Socket_UnlinkName(sockname)==-1)
-    Msg(WARNING, "Impossible to unlink the socket '%s'", sockname);
-  close(sock);
-  return 0;
-}
-
-long Socket_GetTime(){
-  struct timeval tp;
-  gettimeofday(&tp, (struct timezone *)0);
-  return (long)tp.tv_sec * 1000000 + (long)tp.tv_usec;
-}
-
-void Socket_Idle(double delay){
-  long t1 = Socket_GetTime();
-  while(1){
-    if(Socket_GetTime() - t1 > 1.e6*delay) break;
-  }
-}
-
-int Socket_Connect(char *sockname){
-  struct sockaddr_un addr;
-  int len, sock;
-  int tries;
-
-  /* slight delay to be sure that the socket is bound by the
-     server before we attempt to connect to it... */
-  Socket_Idle(0.1);
-
-  /* create socket */
-  sock = socket(PF_UNIX, SOCK_STREAM, 0);
-  if (sock<0){
-    Msg(GERROR, "Couldn't create socket");
-    return -1;
-  }
-
-  /* try to connect socket to given name */
-  strcpy(addr.sun_path, sockname);
-  addr.sun_family = AF_UNIX;
-  len = strlen(addr.sun_path)+sizeof(addr.sun_family);
-  for (tries=0;tries<5;tries++) {
-    if (connect(sock, (struct sockaddr *)&addr, len) < 0) {
-      Msg(WARNING, "Socket connect failed on '%s'", sockname);
-    }
-    else {
-      return sock;
-    }
-  }
-   
-  return -1;
-}
-
-
-void Socket_Close(int sock){
-  close(sock);
-}
diff --git a/Fltk/Socket.h b/Fltk/Socket.h
deleted file mode 100644
index a25f56bb97..0000000000
--- a/Fltk/Socket.h
+++ /dev/null
@@ -1,17 +0,0 @@
-#ifndef _SOCKET_H_
-#define _SOCKET_H_
-
-int  Socket_ReceiveData(int socket, void *buffer, int bytes);
-void Socket_SendData(int socket, void *buffer, int bytes);
-int  Socket_ReceiveInt(int socket, int *i);
-void Socket_SendInt(int socket, int i);
-int  Socket_ReceiveDouble(int socket, double *x);
-void Socket_SendDouble(int socket, double x);
-int  Socket_ReceiveString(int socket, char str[]);
-void Socket_SendString(int socket, char str[]);
-int  Socket_StartProgram(char *progname, char *sockname);
-int  Socket_StopProgram(char *progname, char *sockname, int sock);
-int  Socket_Connect(char *sockname);
-void Socket_Close(int sock);
-
-#endif
diff --git a/Fltk/Solvers.cpp b/Fltk/Solvers.cpp
index 0613e84e95..8899026fdc 100644
--- a/Fltk/Solvers.cpp
+++ b/Fltk/Solvers.cpp
@@ -1,6 +1,8 @@
-// $Id: Solvers.cpp,v 1.8 2001-10-29 08:52:19 geuzaine Exp $
+// $Id: Solvers.cpp,v 1.9 2002-01-03 10:25:06 geuzaine Exp $
 
 #include "Gmsh.h"
+#include "GmshClient.h"
+#include "GmshServer.h"
 
 #include <sys/types.h>
 #include <sys/socket.h>
@@ -8,7 +10,6 @@
 #include <sys/un.h>
 #include <unistd.h>
 
-#include "Socket.h"
 #include "OpenFile.h"
 #include "Solvers.h"
 #include "GmshUI.h"
@@ -20,55 +21,66 @@
 extern Context_T  CTX;
 extern GUI       *WID;
 
+SolverInfo SINFO[5] ;
+
+int Solver(int num, char *args){
+  int sock, type, stop=0, i, j, n;
+  char command[1000], socket_name[1000], str[1000];
+  
+  if(!SINFO[num].client_server){
+    sprintf(command, "%s %s &", SINFO[num].executable_name, args);
+    Gmsh_StartClient(command, NULL);
+    Msg(INFO, "%s start (%s)", SINFO[num].name, command);
+    return 1;
+  }
 
-// interface to GetDP
-
-_GetDP_Info GetDP_Info ;
-
-int GetDP(char *args){
-  int sock, type, i, n;
-  char progname[1000], sockname[1000], str[1000];
-
-  strcpy(sockname, CTX.home_dir);
-  strcat(sockname, ".gmshsock");
-
-  sprintf(progname, "%s %s", GetDP_Info.command, args);
-  sock = Socket_StartProgram(progname, sockname);
+  sprintf(socket_name, "%s.gmshsock-%d", CTX.home_dir, num);
+  sprintf(command, "%s %s -socket %s &", SINFO[num].executable_name, 
+	  args, socket_name);
+  sock = Gmsh_StartClient(command, socket_name);
   if(sock<0){
-    Msg(GERROR, "Could not execute '%s'", progname);
-    WID->getdp_choice[0]->clear();
-    WID->getdp_choice[1]->clear();
+    switch(sock){
+    case -1 : Msg(GERROR, "Couldn't create socket '%s'", socket_name); break;
+    case -2 : Msg(GERROR, "Couldn't bin socket to name '%s'", socket_name); break;
+    case -3 : Msg(GERROR, "Socket listen failed on '%s'", socket_name); break;
+    case -4 : Msg(GERROR, "Solver '%s' not responding on socket '%s'", 
+		  SINFO[num].name, socket_name); break;
+    case -5 : Msg(GERROR, "Socket accept failed on '%s'", socket_name); break;
+    }
+    for(i=0 ; i<SINFO[num].nboptions ; i++)
+      WID->solver[num].choice[i]->clear();
     return 0;
   }
 
-  Socket_ReceiveInt(sock, &GetDP_Info.pid);
-
-  Msg(INFO, "GetDP start (%s)", progname);
+  Msg(INFO, "%s start (%s)", SINFO[num].name, command);
 
-  GetDP_Info.nbres = 0;
-  GetDP_Info.nbpostop = 0;
+  for(i=0 ; i<SINFO[num].nboptions ; i++) SINFO[num].nbval[i] = 0;
+  SINFO[num].pid = 0;
 
   while(1){
-    if(GetDP_Info.pid < 0) break;
-
-    Socket_ReceiveInt(sock, &type);
-
-    if(type == GETDP_END) break;
-
-    Socket_ReceiveString(sock, str);
-
+    if(SINFO[num].pid < 0) break;
+    Gmsh_ReceiveString(sock, &type, str);
     switch(type){
-    case GETDP_PROGRESS :
-      Msg(STATUS3N, "GetDP %s", str);
-      break ;
-    case GETDP_RESOLUTION_NAME :
-      strcpy(GetDP_Info.res[GetDP_Info.nbres++],str);
+    case GMSH_CLIENT_START :
+      SINFO[num].pid = atoi(str);
+      break;
+    case GMSH_CLIENT_STOP :
+      SINFO[num].pid = -1;
+      stop = 1;
+      break;
+    case GMSH_CLIENT_PROGRESS :
+      Msg(STATUS3N, "%s %s", SINFO[num].name, str);
       break ;
-    case GETDP_POSTOPERATION_NAME :
-      strcpy(GetDP_Info.postop[GetDP_Info.nbpostop++],str);
+    case GMSH_CLIENT_OPTION_1 :
+    case GMSH_CLIENT_OPTION_2 :
+    case GMSH_CLIENT_OPTION_3 :
+    case GMSH_CLIENT_OPTION_4 :
+    case GMSH_CLIENT_OPTION_5 :
+      i = type-GMSH_CLIENT_OPTION;
+      strcpy(SINFO[num].option[i][SINFO[num].nbval[i]++],str);
       break ;
-    case GETDP_LOAD_VIEW :
-      if(GetDP_Info.mergeviews){
+    case GMSH_CLIENT_VIEW :
+      if(SINFO[num].merge_views){
 	n = List_Nbr(CTX.post.list);
 	MergeProblem(str);
 	Draw(); 
@@ -76,38 +88,34 @@ int GetDP(char *args){
 	  WID->set_context(menu_post, 0);
       }
       break ;
-    case GETDP_INFO :
-      Msg(DIRECT, "GetDP > %s", str);
+    case GMSH_CLIENT_INFO :
+    case GMSH_CLIENT_WARNING :
+    case GMSH_CLIENT_ERROR :
+      Msg(DIRECT, "%s : %s", SINFO[num].name, str);
       break;
     default :
-      Msg(WARNING, "Unknown type of message received from GetDP");
-      Msg(DIRECT, "GetDP > %s", str);
+      Msg(WARNING, "Unknown type of message received from %s", SINFO[num].name);
+      Msg(DIRECT, "%s : %s", SINFO[num].name, str);
       break ;
     }
-
+    if(stop) break;
   }
 
-  if(GetDP_Info.nbres){
-    WID->getdp_choice[0]->clear();
-    for(i=0;i<GetDP_Info.nbres;i++) 
-      WID->getdp_choice[0]->add(GetDP_Info.res[i]);
-    WID->getdp_choice[0]->value(0);
-  }
-
-  if(GetDP_Info.nbpostop){
-    WID->getdp_choice[1]->clear();
-    for(i=0;i<GetDP_Info.nbpostop;i++) 
-      WID->getdp_choice[1]->add(GetDP_Info.postop[i]);
-    WID->getdp_choice[1]->value(0);
+  for(i=0 ; i<SINFO[num].nboptions ; i++){
+    if(SINFO[num].nbval[i]){
+      WID->solver[num].choice[i]->clear();
+      for(j=0;j<SINFO[num].nbval[i];j++) 
+	WID->solver[num].choice[i]->add(SINFO[num].option[i][j]);
+      WID->solver[num].choice[i]->value(0);
+    }
   }
 
   Msg(STATUS3N, "Ready");
 
-  Socket_StopProgram(progname, sockname, sock);
-
-  GetDP_Info.pid = -1;
+  if(Gmsh_StopClient(socket_name, sock) < 0)
+    Msg(WARNING, "Impossible to unlink the socket '%s'", socket_name);
 
-  Msg(INFO, "GetDP stop (%s)", progname);
+  Msg(INFO, "%s stop (%s)", SINFO[num].name, command);
 
   return 1;
 }
diff --git a/Fltk/Solvers.h b/Fltk/Solvers.h
index 9cfdc646e9..88d3c3ca28 100644
--- a/Fltk/Solvers.h
+++ b/Fltk/Solvers.h
@@ -1,28 +1,21 @@
 #ifndef _SOLVERS_H_
 #define _SOLVERS_H_
 
-// Message protocol for GetDP
-
-#define GETDP_END                 -1
-#define GETDP_INFO                 1
-#define GETDP_PROGRESS             2
-#define GETDP_RESOLUTION_NAME      3
-#define GETDP_POSTOPERATION_NAME   4
-#define GETDP_LOAD_VIEW            5
-
 typedef struct{
-  char command[256];
-  int popupmessages, mergeviews;
+  char name[256], extension[32], executable_name[256];
+  char mesh_name[256], mesh_command[256];
+  char button_name[5][32], button_command[5][256];
+  char option_name[5][256], option_command[256];
+  char option[5][100][256];
+  int  nboptions, nbval[5];
+  char *help;
+  int client_server, popup_messages, merge_views;
   int pid;
-  int nbres, nbpostop;
-  char res[100][100];
-  char postop[100][100];
-} _GetDP_Info ;
-
-extern _GetDP_Info GetDP_Info ;
+} SolverInfo ;
 
-int GetDP(char *args);
+extern SolverInfo SINFO[5] ;
 
+int Solver(int num, char *args);
 
 #endif
 
diff --git a/Makefile b/Makefile
index 8e6e8aa3cb..b3eb063afa 100644
--- a/Makefile
+++ b/Makefile
@@ -1,8 +1,8 @@
-# $Id: Makefile,v 1.177 2001-12-06 08:10:59 geuzaine Exp $
+# $Id: Makefile,v 1.178 2002-01-03 10:25:06 geuzaine Exp $
 
 GMSH_MAJOR_VERSION = 1
-GMSH_MINOR_VERSION = 32
-GMSH_PATCH_VERSION = 1
+GMSH_MINOR_VERSION = 33
+GMSH_PATCH_VERSION = 0
 
 MAKE = make
 CXX = c++
diff --git a/Mesh/3D_Mesh.cpp b/Mesh/3D_Mesh.cpp
index 00441b6653..00f784c3d1 100644
--- a/Mesh/3D_Mesh.cpp
+++ b/Mesh/3D_Mesh.cpp
@@ -1,4 +1,4 @@
-// $Id: 3D_Mesh.cpp,v 1.34 2001-12-16 05:16:37 remacle Exp $
+// $Id: 3D_Mesh.cpp,v 1.35 2002-01-03 10:25:06 geuzaine Exp $
 
 /*
  
@@ -661,7 +661,7 @@ void Convex_Hull_Mesh (List_T * Points, Mesh * m){
   N = List_Nbr (Points);
   n = IMAX (N / 20, 1);
 
-  clock_t t1 = clock();
+  //clock_t t1 = clock();
 
   Box_6_Tetraedron (Points, m);
   List_Sort (Points, comparePosition);
@@ -741,10 +741,10 @@ void Convex_Hull_Mesh (List_T * Points, Mesh * m){
       }
     }
   }
-  clock_t t2 = clock();
+  //clock_t t2 = clock();
 
-  Msg(STATUS3,"Nb1 = %d Nb2 = %d Nb3 = %d N = %d t = %lf\n",Nb1,Nb2,Nb3
-      ,N,(double)(t2-t1)/CLOCKS_PER_SEC);
+  //Msg(STATUS3,"Nb1 = %d Nb2 = %d Nb3 = %d N = %d t = %lf",Nb1,Nb2,Nb3
+  //    ,N,(double)(t2-t1)/CLOCKS_PER_SEC);
 }
 
 void suppress_vertex (void *data, void *dum){
diff --git a/doc/FAQ b/doc/FAQ
index a2c60447bf..3bafdcd64a 100644
--- a/doc/FAQ
+++ b/doc/FAQ
@@ -1,4 +1,4 @@
-GMSH FREQUENTLY ASKED QUESTIONS ($Date: 2001-12-03 08:41:45 $)
+GMSH FREQUENTLY ASKED QUESTIONS ($Date: 2002-01-03 10:25:06 $)
 
 1. GENERAL
 ==========
@@ -139,7 +139,23 @@ hexahedra.
 6. SOLVER PROBLEMS
 ==================
 
-6.1) On Windows, Gmsh does not seem to find the solver
+6.1) How do I integrate my own solver with Gmsh?
+
+If you want to simply launch a program from withing Gmsh, just edit
+the options to define your solver commands (e.g. Solver.Name0,
+Solver.Executable0, etc.), and set the ClientServer option to zero
+(e.g. Solver.ClientServer0 = 0). 
+
+If you want your solver to interact with Gmsh (for error messages,
+option definitions, post-processing, etc.), you will need to link your
+solver with the 'GmshClient.c' file and add the appropriate function
+calls inside your program. You will of course also need to define your
+solver commands in an option file, but this time you should set the
+ClientServer variable to 1 (e.g. Solver.ClientServer = 1). A complete
+example on how to build a solver that interacts with Gmsh is available
+at http://www.geuz.org/gmsh/doc/mysolver.tgz.
+
+6.2) On Windows, Gmsh does not seem to find the solver
 executable. What's wrong?
 
 - the shell executable 'sh.exe' has to be in your path;
diff --git a/doc/VERSIONS b/doc/VERSIONS
index 2d33704550..a4f034b7a3 100644
--- a/doc/VERSIONS
+++ b/doc/VERSIONS
@@ -1,4 +1,8 @@
-$Date: 2001-12-04 09:31:27 $
+$Date: 2002-01-03 10:25:06 $
+
+New in 1.33: New parameterizable solver interface (allowing up to 5
+user-defined solvers); enhanced 2D aniso algorithm; 3D initial mesh
+speedup;
 
 New in 1.32: New visibility browser; better floating point exception
 checks; fixed infinite looping when merging meshes in project files;
diff --git a/doc/gmsh.1 b/doc/gmsh.1
index 7638504ec9..2c8d24818b 100644
--- a/doc/gmsh.1
+++ b/doc/gmsh.1
@@ -203,9 +203,12 @@ use perspective instead of orthographic projection.
 start in automatic, geometry, mesh, solver or post-processing mode
 (default: automatic).
 .TP 4
-.B \-opt string
+.B \-string string
 parse string before project file.
 .TP 4
+.B \-option file
+parse option file before GUI creation.
+.TP 4
 .B \-v int
 set verbosity level (default: 2).
 .TP 4
diff --git a/utils/GmshClient.c b/utils/GmshClient.c
new file mode 100644
index 0000000000..f06e8bfe8c
--- /dev/null
+++ b/utils/GmshClient.c
@@ -0,0 +1,80 @@
+/* $Id: GmshClient.c,v 1.1 2002-01-03 10:25:06 geuzaine Exp $ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef _AIX
+#include <strings.h>
+#endif
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/un.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+/* private functions */
+
+static void Socket_SendData(int socket, void *buffer, int bytes){
+  int sofar, remaining, len;
+  char *buf;
+  buf = (char*)buffer;
+  sofar = 0;
+  remaining = bytes;
+  do {
+    len = write(socket, buf + sofar, remaining);
+    sofar += len;
+    remaining -= len;
+  } while (remaining>0);
+}
+
+static long Socket_GetTime(){
+  struct timeval tp;
+  gettimeofday(&tp, (struct timezone *)0);
+  return (long)tp.tv_sec * 1000000 + (long)tp.tv_usec;
+}
+
+static void Socket_Idle(double delay){
+  long t1 = Socket_GetTime();
+  while(1){
+    if(Socket_GetTime() - t1 > 1.e6*delay) break;
+  }
+}
+
+/* public interface */
+
+int Gmsh_Connect(char *sockname){
+  struct sockaddr_un addr;
+  int len, sock;
+  int tries;
+
+  /* slight delay to be sure that the socket is bound by the
+     server before we attempt to connect to it... */
+  Socket_Idle(0.1);
+
+  /* create socket */
+  sock = socket(PF_UNIX, SOCK_STREAM, 0);
+  if (sock<0) return -1; /* Error: Couldn't create socket */
+
+  /* try to connect socket to given name */
+  strcpy(addr.sun_path, sockname);
+  addr.sun_family = AF_UNIX;
+  len = strlen(addr.sun_path)+sizeof(addr.sun_family);
+  for (tries=0;tries<5;tries++) {
+    if (connect(sock, (struct sockaddr *)&addr, len) >= 0) return sock;
+  }
+   
+  return -2; /* Error: Couldn't connect */
+}
+
+void Gmsh_SendString(int socket, int type, char str[]){
+  int len = strlen(str);
+  Socket_SendData(socket, &type, sizeof(int));
+  Socket_SendData(socket, &len, sizeof(int));
+  Socket_SendData(socket, str, len);
+}
+
+void Gmsh_Disconnect(int sock){
+  close(sock);
+}
+
diff --git a/utils/GmshClient.h b/utils/GmshClient.h
new file mode 100644
index 0000000000..d0730b7631
--- /dev/null
+++ b/utils/GmshClient.h
@@ -0,0 +1,22 @@
+#ifndef _GMSH_CLIENT_H_
+#define _GMSH_CLIENT_H_
+
+#define GMSH_CLIENT_START       1
+#define GMSH_CLIENT_STOP        2
+#define GMSH_CLIENT_INFO        10
+#define GMSH_CLIENT_WARNING     11
+#define GMSH_CLIENT_ERROR       12
+#define GMSH_CLIENT_PROGRESS    13
+#define GMSH_CLIENT_VIEW        20
+#define GMSH_CLIENT_OPTION      100
+#define GMSH_CLIENT_OPTION_1    (GMSH_CLIENT_OPTION+0)
+#define GMSH_CLIENT_OPTION_2    (GMSH_CLIENT_OPTION+1)
+#define GMSH_CLIENT_OPTION_3    (GMSH_CLIENT_OPTION+2)
+#define GMSH_CLIENT_OPTION_4    (GMSH_CLIENT_OPTION+3)
+#define GMSH_CLIENT_OPTION_5    (GMSH_CLIENT_OPTION+4)
+
+int  Gmsh_Connect(char *sockname);
+void Gmsh_SendString(int socket, int type, char str[]);
+void Gmsh_Disconnect(int sock);
+
+#endif
diff --git a/utils/Makefile b/utils/Makefile
index fda4acbffb..5bd2143d85 100644
--- a/utils/Makefile
+++ b/utils/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.5 2001-08-20 08:25:24 geuzaine Exp $
+# $Id: Makefile,v 1.6 2002-01-03 10:25:06 geuzaine Exp $
 
 CXX        = c++
 OPT_FLAGS  = -g
@@ -10,6 +10,12 @@ dxf2geo: dxf2geo.c message.c
 	$(CXX) $(OPT_FLAGS) -o ../bin/dxf2geo -I../DataStr\
               dxf2geo.c message.c ../lib/libDataStr.a -lm
 
+mysolver: mysolver.c
+	$(CXX) $(OPT_FLAGS) -o mysolver.exe mysolver.c GmshClient.c
+
+mysolvertgz:
+	gtar zcvf mysolver.tgz mysolver.c mysolver.opt GmshClient.c GmshClient.h
+
 clean:
 	$(RM) $(RMFLAGS) *.o
 
diff --git a/utils/mysolver.c b/utils/mysolver.c
new file mode 100644
index 0000000000..c4fd035f98
--- /dev/null
+++ b/utils/mysolver.c
@@ -0,0 +1,173 @@
+/* $Id: mysolver.c,v 1.1 2002-01-03 10:25:06 geuzaine Exp $ */
+
+/* This file contains a dummy client solver for Gmsh. It does not
+   solve anything, but shows how to program your own solver to interact
+   with the Gmsh solver module.
+   
+   To compile this solver, type something like:
+
+   gcc -o mysolver.exe mysolver.c GmshClient.c
+   
+   To test this solver, copy the mysolver.opt file into your default
+   Gmsh option file, or lauch Gmsh with the command:
+   
+   gmsh -option mysolver.opt */
+
+/* We start by including some standard headers. Under Windows, you
+   will need to install the cygwin tools (http://www.cygwin.com) to
+   compile this example (as well as your own solver), since the Gmsh
+   solver interface uses Unix sockets. */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+/* Now we include the Gmsh client interface definitions. At the time
+   of this writing, the client interface contains only three
+   functions: Gmsh_Connect, Gmsh_SendString and Gmsh_Disconnect. This
+   example shows how to use these functions in order to program some
+   simple interactions between a solver and Gmsh. */
+
+#include "GmshClient.h"
+
+/* The following typedef defines the two actions of our dummy solver:
+   either output some valid option strings, or run a dummy computation
+   and output a post-processing map. */
+
+typedef enum{options,run} action;
+
+/* Let's now define some fake CPU intensive functions: */
+
+long worktime(){
+  struct timeval tp;
+  gettimeofday(&tp, (struct timezone *)0);
+  return (long)tp.tv_sec * 1000000 + (long)tp.tv_usec;
+}
+
+void work(){
+  long t1 = worktime();
+  while(1){
+    if(worktime() - t1 > 1.e5) break;
+  }
+}
+
+/* And here we go with the main routine of the solver: */
+
+int main(int argc, char *argv[]){
+  action what;
+  int i=0, s;
+  char *name=NULL, *option=NULL, *socket=NULL, tmp[256];
+  FILE *file;
+
+  /* 1. Loop through the command line arguments, remember the action
+     the solver has to perform (what) and store the socket name, the
+     option name and the problem name. */
+
+  while(i<argc) {
+    if(argv[i][0] == '-') {
+      if(!strcmp(argv[i]+1, "socket")){
+	i++;
+	if(argv[i]) socket = argv[i++];
+      }
+      else if(!strcmp(argv[i]+1, "options")){
+	i++;
+	what = options;
+      }
+      else if(!strcmp(argv[i]+1, "run")){
+	i++;
+	what = run;
+	if(argv[i]) option = argv[i++];
+      }
+    }
+    else
+      name = argv[i++];
+  }
+
+  /* 2. If the '-socket' option was not given, we cannot connect to Gmsh... */
+
+  if(!socket){
+    printf("No socket specified: running non-interactively...\n");
+    exit(1);
+  }
+
+  /* 3. Try to connect to the socket given by the '-socket' command
+     line option: */
+
+  s = Gmsh_Connect(socket) ;
+  switch(s){
+
+    /* 3.1. If the socket is <0, issue an error... */
+
+  case -1 :
+    printf("Couldn't create socket %s\n", socket);
+    break;
+  case -2 :
+    printf("Couldn't connect to socket %s\n", socket);
+    break;
+  default :
+    
+    /* 3.2. ...otherwise, send the GMSH_CLIENT_START command (together
+       with the process ID of the solver), check if a problem name was
+       specified, and decide what to do according to the 'what'
+       variable: */
+    
+    sprintf(tmp, "%d", getpid());
+    Gmsh_SendString(s, GMSH_CLIENT_START, tmp);
+    if(!name){
+      Gmsh_SendString(s, GMSH_CLIENT_ERROR, "Missing file name");
+      Gmsh_Disconnect(s);
+      exit(1);
+    }
+    switch(what){
+      
+      /* 3.2.1. If what==options, the solver sends the valid options
+         (here for the first option): */
+      
+    case options :
+      Gmsh_SendString(s, GMSH_CLIENT_OPTION_1, "Val1");
+      Gmsh_SendString(s, GMSH_CLIENT_OPTION_1, "Val2");
+      Gmsh_SendString(s, GMSH_CLIENT_OPTION_1, "Val3");
+      break;
+      
+      /* 3.2.2. If what==run, the solver runs the chosen option,
+         updates the progress message, issues some information data,
+         produces a post-processing map and asks to Gmsh to merge it: */
+
+    case run :
+      sprintf(tmp, "Running %s with option %s...", name, option);
+      Gmsh_SendString(s, GMSH_CLIENT_INFO, tmp);
+      for(i=0 ; i<100 ; i++){
+	sprintf(tmp, "%d %% complete", i);
+	Gmsh_SendString(s, GMSH_CLIENT_PROGRESS, tmp);
+	work();
+      }
+      sprintf(tmp, "Done with %s!", name);
+      Gmsh_SendString(s, GMSH_CLIENT_INFO, tmp); 
+      file = fopen ("mysolver.pos", "wb");
+      if (!file){
+	Gmsh_SendString(s, GMSH_CLIENT_ERROR, "Unable to open output file");
+      }
+      else{
+	fprintf(file, "View \"%s\"{\n", option);
+	fprintf(file, "ST(0,0,0,1,0,0,0,1,0){0,1,2};\n");
+	fprintf(file, "};\n");
+	fclose(file);
+	Gmsh_SendString(s, GMSH_CLIENT_VIEW, "mysolver.pos");
+      }
+      break;
+    }
+    
+    /* 3.3. We can now disconnect the solver from Gmsh: */
+
+    Gmsh_SendString(s, GMSH_CLIENT_STOP, "Goodbye!");
+    Gmsh_Disconnect(s);
+    break;
+  }
+
+
+  /* 4. That's it! */
+
+}
diff --git a/utils/mysolver.opt b/utils/mysolver.opt
new file mode 100644
index 0000000000..87ba8a6e3f
--- /dev/null
+++ b/utils/mysolver.opt
@@ -0,0 +1,28 @@
+// These are the options for the dummy solver client. The following
+// set of options define 'My Solver' as the second Gmsh solver.
+Solver.Name1 = "My Solver";
+Solver.Help1 = "A simple example of the client/server 
+solver implementation in Gmsh...";
+Solver.Executable1 = "./mysolver.exe";
+Solver.Extension1 = "";
+Solver.MeshName1 = "";
+Solver.MeshCommand1 = "";
+Solver.OptionCommand1 = "-options";
+Solver.FirstOption1 = "Option";
+Solver.SecondOption1 = "";
+Solver.ThirdOption1 = "";
+Solver.FourthOption1 = "";
+Solver.FifthOption1 = "";
+Solver.FirstButton1 = "Run";
+Solver.FirstButtonCommand1 = "-run %s";
+Solver.SecondButton1 = "";
+Solver.SecondButtonCommand1 = "";
+Solver.ThirdButton1 = "";
+Solver.ThirdButtonCommand1 = "";
+Solver.FourthButton1 = "";
+Solver.FourthButtonCommand1 = "";
+Solver.FifthButton1 = "";
+Solver.FifthButtonCommand1 = "";
+Solver.ClientServer1 = 1;
+Solver.MergeViews1 = 1;
+Solver.PopupMessages1 = 1;
-- 
GitLab