diff --git a/Common/Gmsh.cpp b/Common/Gmsh.cpp
index 098b16b274c07c5e92713b42062e4683e2339426..6ff89e50e2b76cd63c7517c2d90517d98c74cf74 100644
--- a/Common/Gmsh.cpp
+++ b/Common/Gmsh.cpp
@@ -201,6 +201,11 @@ int GmshBatch()
     CreateOutputFile(name, CTX::instance()->mesh.fileFormat);
   }
 
+#if defined(HAVE_FLTK) // FIXME this actually does not require the GUI
+  // launch solver (if requested)
+  solver_batch_cb(0, (void*)CTX::instance()->launchSolverAtStartup);
+#endif
+
   time_t now;
   time(&now);
   std::string currtime = ctime(&now);
diff --git a/Fltk/onelabGroup.cpp b/Fltk/onelabGroup.cpp
index 28f32cf06fc719a04ea3e51233325dbb07202590..d2255466890f6cc246c09ce983f50e8cbcf63c09 100644
--- a/Fltk/onelabGroup.cpp
+++ b/Fltk/onelabGroup.cpp
@@ -81,7 +81,7 @@ class onelabGmshServer : public GmshServer{
           onelab_cb(0, (void*)"refresh");
         }
         // wait at most waitint seconds and respond to FLTK events
-        FlGui::instance()->wait(waitint);
+        if(FlGui::available()) FlGui::instance()->wait(waitint);
       }
       else if(ret > 0){
         return 0; // data is there!
@@ -193,8 +193,9 @@ bool onelab::localNetworkClient::run()
         else if(type == "number"){
           onelab::number p; p.fromChar(message); set(p);
           if(p.getName() == getName() + "/Progress")
-            FlGui::instance()->setProgress(p.getLabel().c_str(), p.getValue(),
-                                           p.getMin(), p.getMax());
+            if(FlGui::available())
+              FlGui::instance()->setProgress(p.getLabel().c_str(), p.getValue(),
+                                             p.getMin(), p.getMax());
         }
         else if(type == "string"){
           onelab::string p; p.fromChar(message); set(p);
@@ -302,7 +303,7 @@ bool onelab::localNetworkClient::run()
         MergePostProcessingFile(message, CTX::instance()->solver.autoShowLastStep,
                                 CTX::instance()->solver.autoHideNewViews, true);
         drawContext::global()->draw();
-        if(n != PView::list.size()){
+        if(FlGui::available() && n != PView::list.size()){
           FlGui::instance()->rebuildTree();
           FlGui::instance()->openModule("Post-processing");
         }
@@ -320,7 +321,8 @@ bool onelab::localNetworkClient::run()
       {
         int n = PView::list.size();
         PView::fillVertexArray(this, length, &message[0], swap);
-        FlGui::instance()->updateViews(n != (int)PView::list.size());
+        if(FlGui::available())
+          FlGui::instance()->updateViews(n != (int)PView::list.size());
         drawContext::global()->draw();
       }
       break;
@@ -363,7 +365,7 @@ static void initializeLoops()
   onelabUtils::initializeLoop("2");
   onelabUtils::initializeLoop("3");
 
-  if(onelab::server::instance()->getChanged())
+  if(FlGui::available() && onelab::server::instance()->getChanged())
     FlGui::instance()->rebuildTree();
 }
 
@@ -374,7 +376,7 @@ static bool incrementLoops()
   else if(onelabUtils::incrementLoop("2")) ret = true;
   else if(onelabUtils::incrementLoop("1")) ret = true;
 
-  if(onelab::server::instance()->getChanged())
+  if(FlGui::available() && onelab::server::instance()->getChanged())
     FlGui::instance()->rebuildTree();
 
   return ret;
@@ -1568,6 +1570,59 @@ void solver_cb(Fl_Widget *w, void *data)
   CTX::instance()->launchSolverAtStartup = -1;
 }
 
+void solver_batch_cb(Fl_Widget *w, void *data)
+{
+  int num = (intptr_t)data;
+  if(num < 0) return;
+  std::string name = opt_solver_name(num, GMSH_GET, "");
+  std::string exe = opt_solver_executable(num, GMSH_GET, "");
+  std::string host = opt_solver_remote_login(num, GMSH_GET, "");
+  if(exe.empty()){
+    Msg::Error("Solver executable name not provided");
+    return;
+  }
+
+  // create client
+  onelab::localNetworkClient *c = new onelab::localNetworkClient(name, exe, host);
+  c->setIndex(num);
+  onelab::string o(c->getName() + "/Action");
+
+  // initialize
+  onelabUtils::runGmshClient("initalize", CTX::instance()->solver.autoMesh);
+  o.setValue("initialize");
+  onelab::server::instance()->set(o);
+  c->run();
+
+  // load db
+  if(CTX::instance()->solver.autoSaveDatabase){
+    std::string db = SplitFileName(GModel::current()->getFileName())[0] + "onelab.db";
+    if(!StatFile(db)) loadDb(db);
+  }
+
+  // check
+  onelabUtils::runGmshClient("check", CTX::instance()->solver.autoMesh);
+  o.setValue("check");
+  onelab::server::instance()->set(o);
+  c->run();
+
+  // compute
+  initializeLoops();
+  do{
+    onelabUtils::runGmshClient("compute", CTX::instance()->solver.autoMesh);
+    onelabUtils::guessModelName(c);
+    o.setValue("compute");
+    onelab::server::instance()->set(o);
+    c->run();
+  } while(incrementLoops());
+
+  if(CTX::instance()->solver.autoSaveDatabase ||
+     CTX::instance()->solver.autoArchiveOutputFiles){
+    std::string db = SplitFileName(GModel::current()->getFileName())[0] + "onelab.db";
+    if(CTX::instance()->solver.autoArchiveOutputFiles) archiveOutputFiles(db);
+    if(CTX::instance()->solver.autoSaveDatabase) saveDb(db);
+  }
+}
+
 void flgui_wait_cb(double time)
 {
   FlGui::instance()->wait(time);
diff --git a/Fltk/onelabGroup.h b/Fltk/onelabGroup.h
index 1871036579a961e32044ba2fa458fa562a8c91ec..401beec1a580ba6a0d9a81c26329e987b7e6e0d8 100644
--- a/Fltk/onelabGroup.h
+++ b/Fltk/onelabGroup.h
@@ -83,6 +83,7 @@ class onelabGroup : public Fl_Group{
 
 void onelab_cb(Fl_Widget *w, void *data);
 void solver_cb(Fl_Widget *w, void *data);
+void solver_batch_cb(Fl_Widget *w, void *data);
 int metamodel_cb(const std::string &name, const std::string &action="");
 
 #endif