From 5897f45db7bbcd79601c2b2a1c6464f3a5691cf3 Mon Sep 17 00:00:00 2001
From: Christophe Geuzaine <cgeuzaine@ulg.ac.be>
Date: Mon, 1 Dec 2008 23:25:28 +0000
Subject: [PATCH] Third phase of code refactoring: move callbacks where they
 belong & drastically reduce namespace pollution.

There's no new functionality for now: PLEASE TEST THAT EVERYTHING
WORKS AS IT USED TO BEFORE.
---
 Common/Makefile               |    2 +-
 Common/Options.cpp            |   27 +-
 Common/StringUtils.cpp        |   28 +
 Common/StringUtils.h          |    1 +
 Fltk/Callbacks.cpp            | 4728 ---------------------------------
 Fltk/Callbacks.h              |  258 --
 Fltk/GUI.cpp                  |   94 +-
 Fltk/GUI.h                    |    5 +
 Fltk/Makefile                 |  211 +-
 Fltk/aboutWindow.cpp          |   20 +-
 Fltk/classificationEditor.cpp |  551 ++--
 Fltk/classificationEditor.h   |   10 +-
 Fltk/clippingWindow.cpp       |  133 +-
 Fltk/clippingWindow.h         |    2 +
 Fltk/contextWindow.cpp        |   36 +-
 Fltk/extraDialogs.cpp         |    8 +-
 Fltk/fieldWindow.cpp          |  120 +-
 Fltk/fieldWindow.h            |    2 +
 Fltk/fileDialogs.cpp          |  159 +-
 Fltk/graphicWindow.cpp        |  175 +-
 Fltk/graphicWindow.h          |    3 +
 Fltk/manipWindow.cpp          |   26 +-
 Fltk/manipWindow.h            |    2 +
 Fltk/menuWindow.cpp           | 2120 ++++++++++++++-
 Fltk/menuWindow.h             |   12 +
 Fltk/messageWindow.cpp        |   60 +-
 Fltk/messageWindow.h          |    2 +
 Fltk/optionWindow.cpp         | 1254 ++++++++-
 Fltk/optionWindow.h           |   10 +
 Fltk/pluginWindow.cpp         |  148 +-
 Fltk/pluginWindow.h           |    2 +
 Fltk/projectionEditor.cpp     | 1030 +++----
 Fltk/projectionEditor.h       |   23 +-
 Fltk/solverWindow.cpp         |  173 +-
 Fltk/solverWindow.h           |    2 +
 Fltk/statisticsWindow.cpp     |   63 +-
 Fltk/statisticsWindow.h       |    2 +
 Fltk/visibilityWindow.cpp     |  391 ++-
 Fltk/visibilityWindow.h       |    2 +
 doc/texinfo/gmsh.texi         |    6 +-
 40 files changed, 5851 insertions(+), 6050 deletions(-)
 delete mode 100644 Fltk/Callbacks.cpp
 delete mode 100644 Fltk/Callbacks.h

diff --git a/Common/Makefile b/Common/Makefile
index cfe0ca46aa..fc4082844c 100644
--- a/Common/Makefile
+++ b/Common/Makefile
@@ -167,7 +167,7 @@ SmoothData${OBJEXT}: SmoothData.cpp SmoothData.h ../Numeric/Numeric.h \
   ../Numeric/NumericEmbedded.h
 Octree${OBJEXT}: Octree.cpp Octree.h OctreeInternals.h
 OctreeInternals${OBJEXT}: OctreeInternals.cpp GmshMessage.h OctreeInternals.h
-StringUtils${OBJEXT}: StringUtils.cpp StringUtils.h
+StringUtils${OBJEXT}: StringUtils.cpp StringUtils.h GmshMessage.h
 ListUtils${OBJEXT}: ListUtils.cpp MallocUtils.h ListUtils.h TreeUtils.h avl.h \
   GmshMessage.h
 TreeUtils${OBJEXT}: TreeUtils.cpp MallocUtils.h TreeUtils.h avl.h ListUtils.h
diff --git a/Common/Options.cpp b/Common/Options.cpp
index f126f5b3f8..c732125712 100644
--- a/Common/Options.cpp
+++ b/Common/Options.cpp
@@ -37,7 +37,6 @@
 #include "messageWindow.h"
 #include "contextWindow.h"
 #include "clippingWindow.h"
-extern void activate_cb(Fl_Widget* w, void* data);
 #endif
 
 // the single static option context
@@ -3156,7 +3155,7 @@ double opt_general_fast_redraw(OPT_ARGS_NUM)
 #if defined(HAVE_FLTK)
   if(GUI::available() && (action & GMSH_GUI)){
     GUI::instance()->options->general.butt[2]->value(CTX.fast_redraw);
-    activate_cb(NULL, (void*)"fast_redraw");
+    GUI::instance()->options->activate("fast_redraw");
   }
 #endif
   return CTX.fast_redraw;
@@ -3220,7 +3219,7 @@ double opt_general_axes(OPT_ARGS_NUM)
 #if defined(HAVE_FLTK)
   if(GUI::available() && (action & GMSH_GUI)){
     GUI::instance()->options->general.choice[4]->value(CTX.axes);
-    activate_cb(NULL, (void*)"general_axes");
+    GUI::instance()->options->activate("general_axes");
   }
 #endif
   return CTX.axes;
@@ -3245,7 +3244,7 @@ double opt_general_axes_auto_position(OPT_ARGS_NUM)
 #if defined(HAVE_FLTK)
   if(GUI::available() && (action & GMSH_GUI)){
     GUI::instance()->options->general.butt[0]->value(CTX.axes_auto_position);
-    activate_cb(NULL, (void*)"general_axes_auto");
+    GUI::instance()->options->activate("general_axes_auto");
   }
 #endif
   return CTX.axes_auto_position;
@@ -3357,7 +3356,7 @@ double opt_general_small_axes(OPT_ARGS_NUM)
 #if defined(HAVE_FLTK)
   if(GUI::available() && (action & GMSH_GUI)){
     GUI::instance()->options->general.butt[1]->value(CTX.small_axes);
-    activate_cb(NULL, (void*)"general_small_axes");
+    GUI::instance()->options->activate("general_small_axes");
   }
 #endif
   return CTX.small_axes;
@@ -3568,7 +3567,7 @@ double opt_general_rotation_center_cg(OPT_ARGS_NUM)
 #if defined(HAVE_FLTK)
   if(GUI::available() && (action & GMSH_GUI)){
     GUI::instance()->options->general.butt[15]->value(CTX.rotation_center_cg);
-    activate_cb(NULL, (void*)"rotation_center");
+    GUI::instance()->options->activate("rotation_center");
   }
 #endif
   return CTX.rotation_center_cg;
@@ -3863,7 +3862,7 @@ double opt_general_clip_whole_elements(OPT_ARGS_NUM)
 #if defined(HAVE_FLTK)
   if(GUI::available() && (action & GMSH_GUI)){
     GUI::instance()->clipping->butt[0]->value(CTX.clip_whole_elements);
-    activate_cb(NULL, (void*)"clip_whole_elements");
+    GUI::instance()->options->activate("clip_whole_elements");
   }
 #endif
   return CTX.clip_whole_elements;
@@ -5097,7 +5096,7 @@ double opt_mesh_light(OPT_ARGS_NUM)
 #if defined(HAVE_FLTK)
   if(GUI::available() && (action & GMSH_GUI)){
     GUI::instance()->options->mesh.butt[17]->value(CTX.mesh.light);
-    activate_cb(NULL, (void*)"mesh_light");
+    GUI::instance()->options->activate("mesh_light");
   }
 #endif
   return CTX.mesh.light;
@@ -6675,7 +6674,7 @@ double opt_view_auto_position(OPT_ARGS_NUM)
 #if defined(HAVE_FLTK)
   if(_gui_action_valid(action, num)) {
     GUI::instance()->options->view.butt[7]->value(opt->AutoPosition);
-    activate_cb(NULL, (void*)"view_axes_auto_2d");
+    GUI::instance()->options->activate("view_axes_auto_2d");
   }
 #endif
   return opt->AutoPosition;
@@ -6764,7 +6763,7 @@ double opt_view_axes(OPT_ARGS_NUM)
 #if defined(HAVE_FLTK)
   if(_gui_action_valid(action, num)) {
     GUI::instance()->options->view.choice[8]->value(opt->Axes);
-    activate_cb(NULL, (void*)"view_axes");
+    GUI::instance()->options->activate("view_axes");
   }
 #endif
   return opt->Axes;
@@ -6800,7 +6799,7 @@ double opt_view_axes_auto_position(OPT_ARGS_NUM)
 #if defined(HAVE_FLTK)
   if(_gui_action_valid(action, num)) {
     GUI::instance()->options->view.butt[25]->value(opt->AxesAutoPosition);
-    activate_cb(NULL, (void*)"view_axes_auto_3d");
+    GUI::instance()->options->activate("view_axes_auto_3d");
   }
 #endif
   return opt->AxesAutoPosition;
@@ -7021,7 +7020,7 @@ double opt_view_light(OPT_ARGS_NUM)
 #if defined(HAVE_FLTK)
   if(_gui_action_valid(action, num)){
     GUI::instance()->options->view.butt[11]->value(opt->Light);
-    activate_cb(NULL, (void*)"view_light");
+    GUI::instance()->options->activate("view_light");
   }
 #endif
   return opt->Light;
@@ -7465,7 +7464,7 @@ double opt_view_range_type(OPT_ARGS_NUM)
 #if defined(HAVE_FLTK)
   if(_gui_action_valid(action, num)){
     GUI::instance()->options->view.choice[7]->value(opt->RangeType - 1);
-    activate_cb(NULL, (void*)"custom_range");
+    GUI::instance()->options->activate("custom_range");
   }
 #endif
   return opt->RangeType;
@@ -7889,7 +7888,7 @@ double opt_view_use_gen_raise(OPT_ARGS_NUM)
 #if defined(HAVE_FLTK)
   if(_gui_action_valid(action, num)){
     GUI::instance()->options->view.butt[6]->value(opt->UseGenRaise);
-    activate_cb(NULL, (void*)"general_transform");
+    GUI::instance()->options->activate("general_transform");
   }
 #endif
   return opt->UseGenRaise;
diff --git a/Common/StringUtils.cpp b/Common/StringUtils.cpp
index eb11528d6e..eaa3769be7 100644
--- a/Common/StringUtils.cpp
+++ b/Common/StringUtils.cpp
@@ -8,6 +8,7 @@
 #endif
 
 #include "StringUtils.h"
+#include "GmshMessage.h"
 
 void SwapBytes(char *array, int size, int n)
 {
@@ -101,3 +102,30 @@ std::vector<std::string> SplitWhiteSpace(std::string in, unsigned int len)
   }
   return out;
 }
+
+void ReplaceMultiFormat(const char *in, const char *val, char *out)
+{
+  unsigned int i = 0, j = 0;
+
+  out[0] = '\0';
+  while(i < strlen(in)){
+    if(in[i] == '%' && i != strlen(in) - 1){
+      if(in[i + 1] == 's'){
+        strcat(out, val);
+        i += 2;
+        j += strlen(val);
+      }
+      else{
+        Msg::Warning("Skipping unknown format '%%%c' in '%s'", in[i + 1], in);
+        i += 2;
+      }
+    }
+    else{
+      out[j] = in[i];
+      out[j + 1] = '\0';
+      i++;
+      j++;
+    }
+  }
+  out[j] = '\0';
+}
diff --git a/Common/StringUtils.h b/Common/StringUtils.h
index 3883bbafec..e09f15553a 100644
--- a/Common/StringUtils.h
+++ b/Common/StringUtils.h
@@ -16,5 +16,6 @@ std::string SanitizeTeXString(const char *in, int equation);
 std::string FixWindowsPath(const char *in);
 void SplitFileName(const char *name, char *no_ext, char *ext, char *base);
 std::vector<std::string> SplitWhiteSpace(std::string in, unsigned int len);
+void ReplaceMultiFormat(const char *in, const char *val, char *out);
 
 #endif
diff --git a/Fltk/Callbacks.cpp b/Fltk/Callbacks.cpp
deleted file mode 100644
index b9a6249f3c..0000000000
--- a/Fltk/Callbacks.cpp
+++ /dev/null
@@ -1,4728 +0,0 @@
-// Gmsh - Copyright (C) 1997-2008 C. Geuzaine, J.-F. Remacle
-//
-// See the LICENSE.txt file for license information. Please report all
-// bugs and problems to <gmsh@geuz.org>.
-
-#include <string.h>
-#include <signal.h>
-#include <time.h>
-#include <map>
-#include <string>
-#include <sstream>
-#include <FL/fl_ask.H>
-#include <FL/Fl_Color_Chooser.H>
-#include "GUI.h"
-#include "menuWindow.h"
-#include "graphicWindow.h"
-#include "optionWindow.h"
-#include "visibilityWindow.h"
-#include "clippingWindow.h"
-#include "statisticsWindow.h"
-#include "solverWindow.h"
-#include "manipWindow.h"
-#include "messageWindow.h"
-#include "fieldWindow.h"
-#include "pluginWindow.h"
-#include "contextWindow.h"
-#include "aboutWindow.h"
-#include "partitionDialog.h"
-#include "extraDialogs.h"
-#include "fileDialogs.h"
-#include "GmshMessage.h"
-#include "MallocUtils.h"
-#include "ListUtils.h"
-#include "StringUtils.h"
-#include "GModel.h"
-#include "MElement.h"
-#include "GeoStringInterface.h"
-#include "findLinks.h"
-#include "Generator.h"
-#include "HighOrder.h"
-#include "Draw.h"
-#include "SelectBuffer.h"
-#include "PView.h"
-#include "PViewOptions.h"
-#include "PViewData.h"
-#include "CreateFile.h"
-#include "OpenFile.h"
-#include "CommandLine.h"
-#include "Context.h"
-#include "Options.h"
-#include "Callbacks.h"
-#include "Plugin.h"
-#include "PluginManager.h"
-#include "Visibility.h"
-#include "Numeric.h"
-#include "Solvers.h"
-#include "OS.h"
-#include "Field.h"
-#include "BackgroundMesh.h"
-
-extern Context_T CTX;
-
-// Helper routines
-
-int SelectContour(int type, int num, List_T * List)
-{
-  int k = 0, ip;
-
-  switch (type) {
-  case ENT_LINE:
-    k = allEdgesLinked(num, List);
-    for(int i = 0; i < List_Nbr(List); i++) {
-      List_Read(List, i, &ip);
-      HighlightEntityNum(0, abs(ip), 0, 0);
-    }
-    break;
-  case ENT_SURFACE:
-    k = allFacesLinked(num, List);
-    for(int i = 0; i < List_Nbr(List); i++) {
-      List_Read(List, i, &ip);
-      HighlightEntityNum(0, 0, abs(ip), 0);
-    }
-    break;
-  }
-
-  Draw();
-  return k;
-}
-
-
-// Common callbacks 
-
-void cancel_cb(CALLBACK_ARGS)
-{
-  if(data)
-    ((Fl_Window *) data)->hide();
-}
-
-void color_cb(CALLBACK_ARGS)
-{
-  unsigned int (*fct) (int, int, unsigned int);
-  fct = (unsigned int (*)(int, int, unsigned int))data;
-  uchar r = CTX.UNPACK_RED(fct(0, GMSH_GET, 0));
-  uchar g = CTX.UNPACK_GREEN(fct(0, GMSH_GET, 0));
-  uchar b = CTX.UNPACK_BLUE(fct(0, GMSH_GET, 0));
-  if(fl_color_chooser("Color Chooser", r, g, b))
-    fct(0, GMSH_SET | GMSH_GUI, CTX.PACK_COLOR(r, g, b, 255));
-  Draw();
-}
-
-void view_color_cb(CALLBACK_ARGS)
-{
-  unsigned int (*fct) (int, int, unsigned int);
-  fct = (unsigned int (*)(int, int, unsigned int))data;
-  uchar r = CTX.UNPACK_RED(fct(GUI::instance()->options->view.index, GMSH_GET, 0));
-  uchar g = CTX.UNPACK_GREEN(fct(GUI::instance()->options->view.index, GMSH_GET, 0));
-  uchar b = CTX.UNPACK_BLUE(fct(GUI::instance()->options->view.index, GMSH_GET, 0));
-  if(fl_color_chooser("Color Chooser", r, g, b))
-    fct(GUI::instance()->options->view.index, GMSH_SET | GMSH_GUI, CTX.PACK_COLOR(r, g, b, 255));
-  Draw();
-}
-
-void redraw_cb(CALLBACK_ARGS)
-{
-  Draw();
-}
-
-void window_cb(CALLBACK_ARGS)
-{
-  static int oldx = 0, oldy = 0, oldw = 0, oldh = 0, zoom = 1;
-  const char *str = (const char*)data;
-
-  if(!strcmp(str, "minimize")){
-    GUI::instance()->graph[0]->win->iconize();
-    if(GUI::instance()->options->win->shown()) GUI::instance()->options->win->iconize();
-    if(GUI::instance()->plugins->win->shown()) GUI::instance()->plugins->win->iconize();
-    if(GUI::instance()->fields->win->shown()) GUI::instance()->fields->win->iconize();
-    if(GUI::instance()->visibility->win->shown()) GUI::instance()->visibility->win->iconize();
-    if(GUI::instance()->clipping->win->shown()) GUI::instance()->clipping->win->iconize();
-    if(GUI::instance()->manip->win->shown()) GUI::instance()->manip->win->iconize();
-    if(GUI::instance()->stats->win->shown()) GUI::instance()->stats->win->iconize();
-    if(GUI::instance()->messages->win->shown()) GUI::instance()->messages->win->iconize();
-    GUI::instance()->menu->win->iconize();
-  }
-  else if(!strcmp(str, "zoom")){
-    if(zoom){
-      oldx = GUI::instance()->graph[0]->win->x();
-      oldy = GUI::instance()->graph[0]->win->y();
-      oldw = GUI::instance()->graph[0]->win->w();
-      oldh = GUI::instance()->graph[0]->win->h();
-      GUI::instance()->graph[0]->win->resize(Fl::x(), Fl::y(), Fl::w(), Fl::h());
-      zoom = 0;
-    }
-    else{
-      GUI::instance()->graph[0]->win->resize(oldx, oldy, oldw, oldh);
-      zoom = 1;
-    }
-    GUI::instance()->graph[0]->win->show();
-    GUI::instance()->menu->win->show();
-  }
-  else if(!strcmp(str, "front")){
-    // the order is important!
-    GUI::instance()->graph[0]->win->show();
-    if(GUI::instance()->options->win->shown()) GUI::instance()->options->win->show();
-    if(GUI::instance()->plugins->win->shown()) GUI::instance()->plugins->win->show();
-    if(GUI::instance()->fields->win->shown()) GUI::instance()->fields->win->show();
-    if(GUI::instance()->geoContext->win->shown()) GUI::instance()->geoContext->win->show();
-    if(GUI::instance()->meshContext->win->shown()) GUI::instance()->meshContext->win->show();
-    for(unsigned int i = 0; i < GUI::instance()->solver.size(); i++) {
-      if(GUI::instance()->solver[i]->win->shown()) GUI::instance()->solver[i]->win->show();
-    }
-    if(GUI::instance()->visibility->win->shown()) GUI::instance()->visibility->win->show();
-    if(GUI::instance()->clipping->win->shown()) GUI::instance()->clipping->win->show();
-    if(GUI::instance()->manip->win->shown()) GUI::instance()->manip->win->show();
-    if(GUI::instance()->stats->win->shown()) GUI::instance()->stats->win->show();
-    if(GUI::instance()->messages->win->shown()) GUI::instance()->messages->win->show();
-    GUI::instance()->menu->win->show();
-  }
-}
-
-void activate_cb(CALLBACK_ARGS)
-{
-  // this is a central callback to activate/deactivate parts of the
-  // GUI depending on the user's choices (or the option settings)
-
-  if(!data) return;
-
-  optionWindow *o = GUI::instance()->options;
-
-  const char *str = (const char*)data;
-
-  if(!strcmp(str, "fast_redraw")){
-    if(o->general.butt[2]->value())
-      GUI::instance()->options->redraw->show();
-    else
-      GUI::instance()->options->redraw->hide();
-  }
-  else if(!strcmp(str, "rotation_center")){
-    if(o->general.butt[15]->value()) {
-      o->general.push[0]->deactivate();
-      o->general.value[8]->deactivate();
-      o->general.value[9]->deactivate();
-      o->general.value[10]->deactivate();
-    }
-    else {
-      o->general.push[0]->activate();
-      o->general.value[8]->activate();
-      o->general.value[9]->activate();
-      o->general.value[10]->activate();
-    }
-  }
-  else if(!strcmp(str, "general_axes")){
-    if(o->general.choice[4]->value()){
-      o->general.value[17]->activate();
-      o->general.value[18]->activate();
-      o->general.value[19]->activate();
-      o->general.input[3]->activate();
-      o->general.input[4]->activate();
-      o->general.input[5]->activate();
-      o->general.input[6]->activate();
-      o->general.input[7]->activate();
-      o->general.input[8]->activate();
-    }
-    else{
-      o->general.value[17]->deactivate();
-      o->general.value[18]->deactivate();
-      o->general.value[19]->deactivate();
-      o->general.input[3]->deactivate();
-      o->general.input[4]->deactivate();
-      o->general.input[5]->deactivate();
-      o->general.input[6]->deactivate();
-      o->general.input[7]->deactivate();
-      o->general.input[8]->deactivate();
-    }
-  }
-  else if(!strcmp(str, "general_axes_auto")){
-    if(o->general.butt[0]->value()){
-      o->general.value[20]->deactivate();
-      o->general.value[21]->deactivate();
-      o->general.value[22]->deactivate();
-      o->general.value[23]->deactivate();
-      o->general.value[24]->deactivate();
-      o->general.value[25]->deactivate();
-    }
-    else{
-      o->general.value[20]->activate();
-      o->general.value[21]->activate();
-      o->general.value[22]->activate();
-      o->general.value[23]->activate();
-      o->general.value[24]->activate();
-      o->general.value[25]->activate();
-    }
-  }
-  else if(!strcmp(str, "general_small_axes")){
-    if(o->general.butt[1]->value()){
-      o->general.value[26]->activate();
-      o->general.value[27]->activate();
-    }
-    else{
-      o->general.value[26]->deactivate();
-      o->general.value[27]->deactivate();
-    }
-  }
-  else if(!strcmp(str, "custom_range")){
-    if(o->view.choice[7]->value() == 1){
-      o->view.value[31]->activate();
-      o->view.value[32]->activate();
-      o->view.push[1]->activate();
-      o->view.push[2]->activate();
-    }
-    else {
-      o->view.value[31]->deactivate();
-      o->view.value[32]->deactivate();
-      o->view.push[1]->deactivate();
-      o->view.push[2]->deactivate();
-    }
-  }
-  else if(!strcmp(str, "general_transform")){
-    if(o->view.butt[6]->value()){
-      o->view.choice[11]->activate();
-      o->view.value[2]->activate();
-      o->view.input[4]->activate();
-      o->view.input[5]->activate();
-      o->view.input[6]->activate();
-    }
-    else{
-      o->view.choice[11]->deactivate();
-      o->view.value[2]->deactivate();
-      o->view.input[4]->deactivate();
-      o->view.input[5]->deactivate();
-      o->view.input[6]->deactivate();
-    }
-  }
-  else if(!strcmp(str, "mesh_light")){
-    if(o->mesh.butt[17]->value()){
-      o->mesh.butt[18]->activate();
-      o->mesh.butt[19]->activate();
-      o->mesh.butt[20]->activate();
-      o->mesh.butt[0]->activate();
-      o->mesh.value[18]->activate();
-    }
-    else{
-      o->mesh.butt[18]->deactivate();
-      o->mesh.butt[19]->deactivate();
-      o->mesh.butt[20]->deactivate();
-      o->mesh.butt[0]->deactivate();
-      o->mesh.value[18]->deactivate();
-    }
-  }
-  else if(!strcmp(str, "view_light")){
-    if(o->view.butt[11]->value()){
-      o->view.butt[8]->activate();
-      o->view.butt[9]->activate();
-      o->view.butt[12]->activate();
-      o->view.value[10]->activate();
-    }
-    else{
-      o->view.butt[8]->deactivate();
-      o->view.butt[9]->deactivate();
-      o->view.butt[12]->deactivate();
-      o->view.value[10]->deactivate();
-    }
-  }
-  else if(!strcmp(str, "view_axes")){
-    if(o->view.choice[8]->value()){
-      o->view.value[3]->activate();
-      o->view.value[4]->activate();
-      o->view.value[5]->activate();
-      o->view.input[7]->activate();
-      o->view.input[8]->activate();
-      o->view.input[9]->activate();
-      o->view.input[10]->activate();
-      o->view.input[11]->activate();
-      o->view.input[12]->activate();
-    }
-    else{
-      o->view.value[3]->deactivate();
-      o->view.value[4]->deactivate();
-      o->view.value[5]->deactivate();
-      o->view.input[7]->deactivate();
-      o->view.input[8]->deactivate();
-      o->view.input[9]->deactivate();
-      o->view.input[10]->deactivate();
-      o->view.input[11]->deactivate();
-      o->view.input[12]->deactivate();
-    }
-  }
-  else if(!strcmp(str, "view_axes_auto_3d")){
-    if(o->view.butt[25]->value()){
-      o->view.value[13]->deactivate();
-      o->view.value[14]->deactivate();
-      o->view.value[15]->deactivate();
-      o->view.value[16]->deactivate();
-      o->view.value[17]->deactivate();
-      o->view.value[18]->deactivate();
-    }
-    else{
-      o->view.value[13]->activate();
-      o->view.value[14]->activate();
-      o->view.value[15]->activate();
-      o->view.value[16]->activate();
-      o->view.value[17]->activate();
-      o->view.value[18]->activate();
-    }
-  }
-  else if(!strcmp(str, "view_axes_auto_2d")){
-    if(o->view.butt[7]->value()){
-      o->view.value[20]->deactivate();
-      o->view.value[21]->deactivate();
-      o->view.value[22]->deactivate();
-      o->view.value[23]->deactivate();
-    }
-    else{
-      o->view.value[20]->activate();
-      o->view.value[21]->activate();
-      o->view.value[22]->activate();
-      o->view.value[23]->activate();
-    }
-  }
-}
-
-// Graphical window 
-
-void status_xyz1p_cb(CALLBACK_ARGS)
-{
-  const char *str = (const char*)data;
-
-  drawContext *ctx = GUI::instance()->graph[0]->gl->getDrawContext();
-
-  if(!strcmp(str, "r")){ // rotate 90 degress around axis perp to the screen
-    double axis[3] = {0., 0., 1.};
-    if(!Fl::event_state(FL_SHIFT))
-      ctx->addQuaternionFromAxisAndAngle(axis, -90.);
-    else
-      ctx->addQuaternionFromAxisAndAngle(axis, 90.);
-    Draw();
-  }
-  else if(!strcmp(str, "x")){ // X pointing out or into the screen
-    if(!Fl::event_state(FL_SHIFT)){
-      ctx->r[0] = -90.;
-      ctx->r[1] = 0.;
-      ctx->r[2] = -90.;
-    }
-    else{
-      ctx->r[0] = -90.;
-      ctx->r[1] = 0.;
-      ctx->r[2] = 90.;
-    }
-    ctx->setQuaternionFromEulerAngles();
-    Draw();
-  }
-  else if(!strcmp(str, "y")){ // Y pointing out or into the screen
-    if(!Fl::event_state(FL_SHIFT)){
-      ctx->r[0] = -90.;
-      ctx->r[1] = 0.;
-      ctx->r[2] = 180.;
-    }
-    else{
-      ctx->r[0] = -90.;
-      ctx->r[1] = 0.;
-      ctx->r[2] = 0.;
-    }
-    ctx->setQuaternionFromEulerAngles();
-    Draw();
-  }
-  else if(!strcmp(str, "z")){ // Z pointing out or into the screen
-    if(!Fl::event_state(FL_SHIFT)){
-      ctx->r[0] = 0.;
-      ctx->r[1] = 0.;
-      ctx->r[2] = 0.;
-    }
-    else{
-      ctx->r[0] = 0.;
-      ctx->r[1] = 180.;
-      ctx->r[2] = 0.;
-    }
-    ctx->setQuaternionFromEulerAngles();
-    Draw();
-  }
-  else if(!strcmp(str, "1:1")){ // reset translation and scaling
-    ctx->t[0] = ctx->t[1] = ctx->t[2] = 0.;
-    ctx->s[0] = ctx->s[1] = ctx->s[2] = 1.;
-    Draw();
-  }
-  else if(!strcmp(str, "reset")){ // reset everything
-    ctx->t[0] = ctx->t[1] = ctx->t[2] = 0.;
-    ctx->s[0] = ctx->s[1] = ctx->s[2] = 1.;
-    ctx->r[0] = 0.;
-    ctx->r[1] = 0.;
-    ctx->r[2] = 0.;
-    ctx->setQuaternionFromEulerAngles();
-    Draw();
-  }
-  else if(!strcmp(str, "p")){ // toggle projection mode
-    if(!Fl::event_state(FL_SHIFT)){
-      opt_general_orthographic(0, GMSH_SET | GMSH_GUI, 
-                               !opt_general_orthographic(0, GMSH_GET, 0));
-    }
-    else{
-      perspective_editor();
-    }
-    Draw();
-  }
-  else if(!strcmp(str, "model")){ // toggle projection mode
-    model_chooser();
-  }
-  else if(!strcmp(str, "?")){ // display options
-    Print_Options(0, GMSH_FULLRC, 0, 1, NULL);
-    GUI::instance()->messages->show();
-  }
-  else if(!strcmp(str, "S")){ // mouse selection
-    if(CTX.mouse_selection){
-      opt_general_mouse_selection(0, GMSH_SET | GMSH_GUI, 0);
-      GUI::instance()->graph[0]->gl->cursor(FL_CURSOR_DEFAULT, FL_BLACK, FL_WHITE);
-    }
-    else
-      opt_general_mouse_selection(0, GMSH_SET | GMSH_GUI, 1);
-  }
-  GUI::instance()->manip->update();
-}
-
-static int stop_anim, view_in_cycle = -1;
-
-void ManualPlay(int time, int step)
-{
-  // avoid firing ManualPlay recursively (can happen e.g when keeping
-  // the finger down on the arrow key: if the system generates too
-  // many events, we can overflow the stack--that happened on my
-  // powerbook with the new, optimzed FLTK event handler)
-  static bool busy = false;
-  if(busy) return;
-  busy = true;
-  if(time) {
-    for(unsigned int i = 0; i < PView::list.size(); i++)
-      if(opt_view_visible(i, GMSH_GET, 0))
-        opt_view_timestep(i, GMSH_SET | GMSH_GUI,
-                          opt_view_timestep(i, GMSH_GET, 0) + step);
-  }
-  else { // hide all views except view_in_cycle
-    if(step > 0) {
-      if((view_in_cycle += step) >= (int)PView::list.size())
-        view_in_cycle = 0;
-      for(int i = 0; i < (int)PView::list.size(); i += step)
-        opt_view_visible(i, GMSH_SET | GMSH_GUI, (i == view_in_cycle));
-    }
-    else {
-      if((view_in_cycle += step) < 0)
-        view_in_cycle = PView::list.size() - 1;
-      for(int i = PView::list.size() - 1; i >= 0; i += step)
-        opt_view_visible(i, GMSH_SET | GMSH_GUI, (i == view_in_cycle));
-    }
-  }
-  Draw();
-  busy = false;
-}
-
-void status_play_cb(CALLBACK_ARGS)
-{
-  static double anim_time;
-  GUI::instance()->graph[0]->setAnimButtons(0);
-  stop_anim = 0;
-  anim_time = GetTimeInSeconds();
-  while(1) {
-    if(stop_anim)
-      break;
-    if(GetTimeInSeconds() - anim_time > CTX.post.anim_delay) {
-      anim_time = GetTimeInSeconds();
-      ManualPlay(!CTX.post.anim_cycle, 1);
-    }
-    GUI::instance()->check();
-  }
-}
-
-void status_pause_cb(CALLBACK_ARGS)
-{
-  stop_anim = 1;
-  GUI::instance()->graph[0]->setAnimButtons(1);
-}
-
-void status_rewind_cb(CALLBACK_ARGS)
-{
-  if(!CTX.post.anim_cycle) {
-    for(unsigned int i = 0; i < PView::list.size(); i++)
-      opt_view_timestep(i, GMSH_SET | GMSH_GUI, 0);
-  }
-  else {
-    view_in_cycle = 0;
-    for(unsigned int i = 0; i < PView::list.size(); i++)
-      opt_view_visible(i, GMSH_SET | GMSH_GUI, !i);
-  }
-  Draw();
-}
-
-void status_stepbackward_cb(CALLBACK_ARGS)
-{
-  ManualPlay(!CTX.post.anim_cycle, -1);
-}
-
-void status_stepforward_cb(CALLBACK_ARGS)
-{
-  ManualPlay(!CTX.post.anim_cycle, 1);
-}
-
-// File Menu
-
-void file_new_cb(CALLBACK_ARGS)
-{
- test:
-  if(file_chooser(0, 1, "New", "*")) {
-    std::string name = file_chooser_get_name(1);
-    if(!StatFile(name.c_str())){
-      if(fl_choice("File '%s' already exists.\n\nDo you want to erase it?",
-                   "Cancel", "Erase", NULL, name.c_str()))
-        UnlinkFile(name.c_str());
-      else
-        goto test;
-    }
-    FILE *fp = fopen(name.c_str(), "w");
-    if(!fp){
-      Msg::Error("Unable to open file '%s'", name.c_str());
-      return;
-    }
-    time_t now;
-    time(&now);
-    fprintf(fp, "// Gmsh project created on %s", ctime(&now));
-    fclose(fp);
-    OpenProject(name.c_str());
-    Draw();
-  }
-}
-
-#if defined(HAVE_NATIVE_FILE_CHOOSER)
-#  define TT "\t"
-#  define NN "\n"
-#else
-#  define TT " ("
-#  define NN ")\t"
-#endif
-
-static const char *input_formats =
-  "All files" TT "*" NN
-  "Gmsh geometry" TT "*.geo" NN
-  "Gmsh mesh" TT "*.msh" NN
-  "Gmsh post-processing view" TT "*.pos" NN
-#if defined(HAVE_OCC)
-  "STEP model" TT "*.{stp,step}" NN
-  "IGES model" TT "*.{igs,iges}" NN
-  "BRep model" TT "*.brep" NN
-#endif
-  "I-deas universal mesh" TT "*.unv" NN
-  "Diffpack 3D mesh" TT "*.diff" NN
-  "VTK mesh" TT "*.vtk" NN
-#if defined(HAVE_MED)
-  "MED file" TT "*.{med,mmed,rmed}" NN
-#endif
-  "Medit mesh" TT "*.mesh" NN
-  "Nastran bulk data file" TT "*.{bdf,nas}" NN
-  "Plot3D structured mesh" TT "*.p3d" NN
-  "STL surface mesh" TT "*.stl" NN
-  "VRML surface mesh" TT "*.{wrl,vrml}" NN
-#if defined(HAVE_LIBJPEG)
-  "JPEG" TT "*.{jpg,jpeg}" NN
-#endif
-#if defined(HAVE_LIBPNG)
-  "PNG" TT "*.png" NN
-#endif
-  "BMP" TT "*.bmp" NN
-  "PPM" TT "*.ppm" NN
-  "PGM" TT "*.pgm" NN
-  "PBM" TT "*.pbm" NN
-  "PNM" TT "*.pnm" NN;
-
-#undef TT
-#undef NN
-
-
-void file_open_cb(CALLBACK_ARGS)
-{
-  int n = PView::list.size();
-  if(file_chooser(0, 0, "Open", input_formats)) {
-    OpenProject(file_chooser_get_name(1).c_str());
-    Draw();
-  }
-  if(n != (int)PView::list.size())
-    GUI::instance()->menu->setContext(menu_post, 0);
-}
-
-void file_merge_cb(CALLBACK_ARGS)
-{
-  int n = PView::list.size();
-  int f = file_chooser(1, 0, "Merge", input_formats);
-  if(f) {
-    for(int i = 1; i <= f; i++)
-      MergeFile(file_chooser_get_name(i).c_str());
-    Draw();
-  }
-  if(n != (int)PView::list.size())
-    GUI::instance()->menu->setContext(menu_post, 0);
-}
-
-int _save_msh(const char *name){ return msh_dialog(name); }
-int _save_pos(const char *name){ return pos_dialog(name); }
-int _save_options(const char *name){ return options_dialog(name); }
-int _save_geo(const char *name){ return geo_dialog(name); }
-int _save_cgns(const char *name){ return cgns_write_dialog(name); }
-int _save_unv(const char *name){ return unv_dialog(name); }
-int _save_vtk(const char *name){ return generic_mesh_dialog(name, "VTK Options", FORMAT_VTK, true); }
-int _save_diff(const char *name){ return generic_mesh_dialog(name, "Diffpack Options", FORMAT_DIFF, true); }
-int _save_med(const char *name){ return generic_mesh_dialog(name, "MED Options", FORMAT_MED, false); }
-int _save_mesh(const char *name){ return generic_mesh_dialog(name, "MESH Options", FORMAT_MESH, false); }
-int _save_bdf(const char *name){ return bdf_dialog(name); }
-int _save_p3d(const char *name){ return generic_mesh_dialog(name, "P3D Options", FORMAT_P3D, false); }
-int _save_stl(const char *name){ return generic_mesh_dialog(name, "STL Options", FORMAT_STL, true); }
-int _save_vrml(const char *name){ return generic_mesh_dialog(name, "VRML Options", FORMAT_VRML, false); }
-int _save_eps(const char *name){ return gl2ps_dialog(name, "EPS Options", FORMAT_EPS); }
-int _save_gif(const char *name){ return gif_dialog(name); }
-int _save_jpeg(const char *name){ return jpeg_dialog(name); }
-int _save_tex(const char *name){ return latex_dialog(name); }
-int _save_pdf(const char *name){ return gl2ps_dialog(name, "PDF Options", FORMAT_PDF); }
-int _save_png(const char *name){ return generic_bitmap_dialog(name, "PNG Options", FORMAT_PNG); }
-int _save_ps(const char *name){ return gl2ps_dialog(name, "PS Options", FORMAT_PS); }
-int _save_ppm(const char *name){ return generic_bitmap_dialog(name, "PPM Options", FORMAT_PPM); }
-int _save_svg(const char *name){ return gl2ps_dialog(name, "SVG Options", FORMAT_SVG); }
-int _save_yuv(const char *name){ return generic_bitmap_dialog(name, "YUV Options", FORMAT_YUV); }
-
-int _save_auto(const char *name)
-{
-  switch(GuessFileFormatFromFileName(name)){
-  case FORMAT_MSH  : return _save_msh(name);
-  case FORMAT_POS  : return _save_pos(name);
-  case FORMAT_OPT  : return _save_options(name);
-  case FORMAT_GEO  : return _save_geo(name);
-  case FORMAT_CGNS : return _save_cgns(name);
-  case FORMAT_UNV  : return _save_unv(name);
-  case FORMAT_VTK  : return _save_vtk(name);
-  case FORMAT_MED  : return _save_med(name);
-  case FORMAT_MESH : return _save_mesh(name);
-  case FORMAT_BDF  : return _save_bdf(name);
-  case FORMAT_DIFF : return _save_diff(name);
-  case FORMAT_P3D  : return _save_p3d(name);
-  case FORMAT_STL  : return _save_stl(name);
-  case FORMAT_VRML : return _save_vrml(name);
-  case FORMAT_EPS  : return _save_eps(name);
-  case FORMAT_GIF  : return _save_gif(name);
-  case FORMAT_JPEG : return _save_jpeg(name);
-  case FORMAT_TEX  : return _save_tex(name);
-  case FORMAT_PDF  : return _save_pdf(name);
-  case FORMAT_PNG  : return _save_png(name);
-  case FORMAT_PS   : return _save_ps(name);
-  case FORMAT_PPM  : return _save_ppm(name);
-  case FORMAT_SVG  : return _save_svg(name);
-  case FORMAT_YUV  : return _save_yuv(name);
-  default :
-    CreateOutputFile(name, FORMAT_AUTO); 
-    return 1;
-  }
-}
-
-typedef struct{
-  const char *pat;
-  int (*func) (const char *name);
-} patXfunc;
-
-void file_save_as_cb(CALLBACK_ARGS)
-{
-#if defined(HAVE_NATIVE_FILE_CHOOSER)
-#  define TT "\t"
-#  define NN "\n"
-#else
-#  define TT " ("
-#  define NN ")\t"
-#endif
-
-  static patXfunc formats[] = {
-    {"Guess from extension" TT "*.*", _save_auto},
-    {"Gmsh mesh" TT "*.msh", _save_msh},
-    {"Gmsh mesh statistics" TT "*.pos", _save_pos},
-    {"Gmsh options" TT "*.opt", _save_options},
-    {"Gmsh unrolled geometry" TT "*.geo", _save_geo},
-#if defined(HAVE_LIBCGNS)
-    {"CGNS" TT "*.cgns", _save_cgns},
-#endif
-    {"I-deas universal mesh" TT "*.unv", _save_unv},
-    {"Diffpack 3D mesh" TT "*.diff", _save_diff},
-    {"VTK mesh" TT "*.vtk", _save_vtk},
-#if defined(HAVE_MED)
-    {"MED file" TT "*.med", _save_med},
-#endif
-    {"Medit mesh" TT "*.mesh", _save_mesh},
-    {"Nastran bulk data file" TT "*.bdf", _save_bdf},
-    {"Plot3D structured mesh" TT "*.p3d", _save_p3d},
-    {"STL surface mesh" TT "*.stl", _save_stl},
-    {"VRML surface mesh" TT "*.wrl", _save_vrml},
-    {"Encapsulated PostScript" TT "*.eps", _save_eps},
-    {"GIF" TT "*.gif", _save_gif},
-#if defined(HAVE_LIBJPEG)
-    {"JPEG" TT "*.jpg", _save_jpeg},
-#endif
-    {"LaTeX" TT "*.tex", _save_tex},
-    {"PDF" TT "*.pdf", _save_pdf},
-#if defined(HAVE_LIBPNG)
-    {"PNG" TT "*.png", _save_png},
-#endif
-    {"PostScript" TT "*.ps", _save_ps},
-    {"PPM" TT "*.ppm", _save_ppm},
-    {"SVG" TT "*.svg", _save_svg},
-    {"YUV" TT "*.yuv", _save_yuv},
-  };
-
-  int nbformats = sizeof(formats) / sizeof(formats[0]);
-  static char *pat = NULL;
-  if(!pat) {
-    pat = (char *)Malloc(nbformats * 256 * sizeof(char));
-    strcpy(pat, formats[0].pat);
-    for(int i = 1; i < nbformats; i++) {
-      strcat(pat, NN);
-      strcat(pat, formats[i].pat);
-    }
-  }
-
-#undef TT
-#undef NN
-
- test:
-  if(file_chooser(0, 1, "Save As", pat)) {
-    std::string name = file_chooser_get_name(1);
-    if(CTX.confirm_overwrite) {
-      if(!StatFile(name.c_str()))
-        if(!fl_choice("File '%s' already exists.\n\nDo you want to replace it?", 
-                      "Cancel", "Replace", NULL, name.c_str()))
-          goto test;
-    }
-    int i = file_chooser_get_filter();
-    if(i >= 0 && i < nbformats){
-      if(!formats[i].func(name.c_str())) goto test;
-    }
-    else{ // handle any additional automatic fltk filter
-      if(!_save_auto(name.c_str())) goto test;
-    }
-  }
-}
-
-void file_rename_cb(CALLBACK_ARGS)
-{
- test:
-  if(file_chooser(0, 1, "Rename", "*", CTX.filename)) {
-    std::string name = file_chooser_get_name(1);
-    if(CTX.confirm_overwrite) {
-      if(!StatFile(name.c_str()))
-        if(!fl_choice("File '%s' already exists.\n\nDo you want to replace it?", 
-                      "Cancel", "Replace", NULL, name.c_str()))
-          goto test;
-    }
-    rename(CTX.filename, name.c_str());
-    OpenProject(name.c_str());
-    Draw();
-  }
-}
-
-void file_quit_cb(CALLBACK_ARGS)
-{
-  Msg::Exit(0);
-}
-
-// Option Menu
-
-void options_cb(CALLBACK_ARGS)
-{
-  GUI::instance()->options->win->show();
-}
-
-void options_browser_cb(CALLBACK_ARGS)
-{
-  GUI::instance()->options->showGroup(GUI::instance()->options->browser->value());
-}
-
-void options_save_cb(CALLBACK_ARGS)
-{
-  Msg::StatusBar(2, true, "Writing '%s'", CTX.options_filename_fullpath);
-  Print_Options(0, GMSH_OPTIONSRC, 1, 1, CTX.options_filename_fullpath);
-  Msg::StatusBar(2, true, "Wrote '%s'", CTX.options_filename_fullpath);
-}
-
-void options_restore_defaults_cb(CALLBACK_ARGS)
-{
-  // not sure if we have to remove the file...
-  UnlinkFile(CTX.session_filename_fullpath);
-  UnlinkFile(CTX.options_filename_fullpath);
-  ReInit_Options(0);
-  Init_Options_GUI(0);
-  if(GUI::instance()->menu->module->value() == 3) // hack to refresh the buttons
-    GUI::instance()->menu->setContext(menu_post, 0);
-  Draw();
-}
-
-// General options
-
-void general_options_cb(CALLBACK_ARGS)
-{
-  GUI::instance()->options->showGroup(1);
-}
-
-void general_options_color_scheme_cb(CALLBACK_ARGS)
-{
-  opt_general_color_scheme(0, GMSH_SET, GUI::instance()->options->general.choice[3]->value());
-  Draw();
-}
-
-void general_options_rotation_center_select_cb(CALLBACK_ARGS)
-{
-  std::vector<GVertex*> vertices;
-  std::vector<GEdge*> edges;
-  std::vector<GFace*> faces;
-  std::vector<GRegion*> regions;
-  std::vector<MElement*> elements;
-
-  Msg::StatusBar(3, false, "Select entity\n[Press 'q' to abort]");
-  char ib = SelectEntity(ENT_ALL, vertices, edges, faces, regions, elements);
-  if(ib == 'l') {
-    SPoint3 pc(0., 0., 0.);
-    if(vertices.size())
-      pc.setPosition(vertices[0]->x(), vertices[0]->y(), vertices[0]->z());
-    else if(edges.size())
-      pc = edges[0]->bounds().center();
-    else if(faces.size())
-      pc = faces[0]->bounds().center();
-    else if(regions.size())
-      pc = regions[0]->bounds().center();
-    else if(elements.size())
-      pc = elements[0]->barycenter();
-    opt_general_rotation_center_cg(0, GMSH_SET, GUI::instance()->options->general.butt[15]->value());
-    opt_general_rotation_center0(0, GMSH_SET|GMSH_GUI, pc.x());
-    opt_general_rotation_center1(0, GMSH_SET|GMSH_GUI, pc.y());
-    opt_general_rotation_center2(0, GMSH_SET|GMSH_GUI, pc.z());
-  }
-  ZeroHighlight();
-  Draw();
-  Msg::StatusBar(3, false, "");
-}
-
-void general_options_ok_cb(CALLBACK_ARGS)
-{
-  activate_cb(NULL, data);
-
-  optionWindow *o = GUI::instance()->options;
-
-  static double lc = 0.;
-  if(lc != CTX.lc){
-    lc = CTX.lc;
-    for(int i = 2; i < 5; i++){
-      o->general.value[i]->minimum(-5 * CTX.lc);
-      o->general.value[i]->maximum(5 * CTX.lc);
-    }
-  }
-  if(data){
-    const char *name = (const char*)data;
-    if(!strcmp(name, "rotation_center_coord")){
-      CTX.draw_rotation_center = 1;
-    }
-    else if(!strcmp(name, "light_value")){
-      double x, y, z;
-      x = o->general.value[2]->value();
-      y = o->general.value[3]->value();
-      z = o->general.value[4]->value();
-      o->general.sphere->setValue(x, y, z);    
-    }
-    else if(!strcmp(name, "light_sphere")){
-      double x, y, z;
-      o->general.sphere->getValue(x, y, z);
-      o->general.value[2]->value(x);
-      o->general.value[3]->value(y);
-      o->general.value[4]->value(z);
-    }
-  }
-
-  opt_general_axes_auto_position(0, GMSH_SET, o->general.butt[0]->value());
-  opt_general_small_axes(0, GMSH_SET, o->general.butt[1]->value());
-  opt_general_fast_redraw(0, GMSH_SET, o->general.butt[2]->value());
-  opt_general_mouse_hover_meshes(0, GMSH_SET, o->general.butt[11]->value());
-  if(opt_general_double_buffer(0, GMSH_GET, 0) != o->general.butt[3]->value())
-    opt_general_double_buffer(0, GMSH_SET, o->general.butt[3]->value());
-  if(opt_general_antialiasing(0, GMSH_GET, 0) != o->general.butt[12]->value())
-    opt_general_antialiasing(0, GMSH_SET, o->general.butt[12]->value());
-  opt_general_trackball(0, GMSH_SET, o->general.butt[5]->value());
-  opt_general_terminal(0, GMSH_SET, o->general.butt[7]->value());
-  double sessionrc = opt_general_session_save(0, GMSH_GET, 0);
-  opt_general_session_save(0, GMSH_SET, o->general.butt[8]->value());
-  if(sessionrc && !opt_general_session_save(0, GMSH_GET, 0))
-    Print_Options(0, GMSH_SESSIONRC, 1, 1, CTX.session_filename_fullpath);
-  opt_general_options_save(0, GMSH_SET, o->general.butt[9]->value());
-  opt_general_expert_mode(0, GMSH_SET, o->general.butt[10]->value());
-  opt_general_tooltips(0, GMSH_SET, o->general.butt[13]->value());
-  opt_general_confirm_overwrite(0, GMSH_SET, o->general.butt[14]->value());
-  opt_general_rotation_center_cg(0, GMSH_SET, o->general.butt[15]->value());
-  opt_general_draw_bounding_box(0, GMSH_SET, o->general.butt[6]->value());
-  opt_general_polygon_offset_always(0, GMSH_SET, o->general.butt[4]->value());
-  opt_general_axes_mikado(0, GMSH_SET, o->general.butt[16]->value());
-
-  opt_general_shine_exponent(0, GMSH_SET, o->general.value[0]->value());  
-  opt_general_shine(0, GMSH_SET, o->general.value[1]->value());
-  opt_general_light00(0, GMSH_SET, o->general.value[2]->value());
-  opt_general_light01(0, GMSH_SET, o->general.value[3]->value());
-  opt_general_light02(0, GMSH_SET, o->general.value[4]->value());
-  opt_general_light03(0, GMSH_SET, o->general.value[13]->value());
-  opt_general_verbosity(0, GMSH_SET, o->general.value[5]->value());
-  opt_general_point_size(0, GMSH_SET, o->general.value[6]->value());
-  opt_general_line_width(0, GMSH_SET, o->general.value[7]->value());
-  opt_general_rotation_center0(0, GMSH_SET, o->general.value[8]->value());
-  opt_general_rotation_center1(0, GMSH_SET, o->general.value[9]->value());
-  opt_general_rotation_center2(0, GMSH_SET, o->general.value[10]->value());
-  opt_general_quadric_subdivisions(0, GMSH_SET, o->general.value[11]->value());
-  opt_general_graphics_fontsize(0, GMSH_SET, o->general.value[12]->value());
-  opt_general_clip_factor(0, GMSH_SET, o->general.value[14]->value());
-  opt_general_polygon_offset_factor(0, GMSH_SET, o->general.value[15]->value());
-  opt_general_polygon_offset_units(0, GMSH_SET, o->general.value[16]->value());
-  opt_general_axes_tics0(0, GMSH_SET, o->general.value[17]->value());
-  opt_general_axes_tics1(0, GMSH_SET, o->general.value[18]->value());
-  opt_general_axes_tics2(0, GMSH_SET, o->general.value[19]->value());
-  opt_general_axes_xmin(0, GMSH_SET, o->general.value[20]->value());
-  opt_general_axes_ymin(0, GMSH_SET, o->general.value[21]->value());
-  opt_general_axes_zmin(0, GMSH_SET, o->general.value[22]->value());
-  opt_general_axes_xmax(0, GMSH_SET, o->general.value[23]->value());
-  opt_general_axes_ymax(0, GMSH_SET, o->general.value[24]->value());
-  opt_general_axes_zmax(0, GMSH_SET, o->general.value[25]->value());
-  opt_general_small_axes_position0(0, GMSH_SET, o->general.value[26]->value());
-  opt_general_small_axes_position1(0, GMSH_SET, o->general.value[27]->value());
-
-  opt_general_default_filename(0, GMSH_SET, o->general.input[0]->value());
-  opt_general_editor(0, GMSH_SET, o->general.input[1]->value());
-  opt_general_web_browser(0, GMSH_SET, o->general.input[2]->value());
-  opt_general_axes_format0(0, GMSH_SET, o->general.input[3]->value());
-  opt_general_axes_format1(0, GMSH_SET, o->general.input[4]->value());
-  opt_general_axes_format2(0, GMSH_SET, o->general.input[5]->value());
-  opt_general_axes_label0(0, GMSH_SET, o->general.input[6]->value());
-  opt_general_axes_label1(0, GMSH_SET, o->general.input[7]->value());
-  opt_general_axes_label2(0, GMSH_SET, o->general.input[8]->value());
-
-  opt_general_vector_type(0, GMSH_SET, o->general.choice[0]->value() + 1);
-  opt_general_graphics_font(0, GMSH_SET, o->general.choice[1]->text());
-  opt_general_orthographic(0, GMSH_SET, !o->general.choice[2]->value());
-  opt_general_axes(0, GMSH_SET, o->general.choice[4]->value());
-  opt_general_background_gradient(0, GMSH_SET, o->general.choice[5]->value());
-
-  if(CTX.fast_redraw)
-    CTX.post.draw = CTX.mesh.draw = 0;
-  Draw();
-  CTX.post.draw = CTX.mesh.draw = 1;
-  CTX.draw_rotation_center = 0;
-}
-
-void general_arrow_param_cb(CALLBACK_ARGS)
-{
-  double a = opt_general_arrow_head_radius(0, GMSH_GET, 0);
-  double b = opt_general_arrow_stem_length(0, GMSH_GET, 0);
-  double c = opt_general_arrow_stem_radius(0, GMSH_GET, 0);
-  while(arrow_editor("Arrow Editor", a, b, c)){
-    opt_general_arrow_head_radius(0, GMSH_SET, a);
-    opt_general_arrow_stem_length(0, GMSH_SET, b);
-    opt_general_arrow_stem_radius(0, GMSH_SET, c);
-    Draw();
-  }
-}
-
-// Geometry options
-
-void geometry_options_cb(CALLBACK_ARGS)
-{
-  GUI::instance()->options->showGroup(2);
-}
-
-void geometry_options_ok_cb(CALLBACK_ARGS)
-{
-  activate_cb(NULL, data);
-
-  optionWindow *o = GUI::instance()->options;
-
-  opt_geometry_points(0, GMSH_SET, o->geo.butt[0]->value());
-  opt_geometry_lines(0, GMSH_SET, o->geo.butt[1]->value());
-  opt_geometry_surfaces(0, GMSH_SET, o->geo.butt[2]->value());
-  opt_geometry_volumes(0, GMSH_SET, o->geo.butt[3]->value());
-  opt_geometry_points_num(0, GMSH_SET, o->geo.butt[4]->value());
-  opt_geometry_lines_num(0, GMSH_SET, o->geo.butt[5]->value());
-  opt_geometry_surfaces_num(0, GMSH_SET, o->geo.butt[6]->value());
-  opt_geometry_volumes_num(0, GMSH_SET, o->geo.butt[7]->value());
-  opt_geometry_auto_coherence(0, GMSH_SET, o->geo.butt[8]->value());
-  opt_geometry_light(0, GMSH_SET, o->geo.butt[9]->value());
-  opt_geometry_highlight_orphans(0, GMSH_SET, o->geo.butt[10]->value());
-  opt_geometry_occ_fix_small_edges(0, GMSH_SET, o->geo.butt[11]->value());
-  opt_geometry_occ_fix_small_faces(0, GMSH_SET, o->geo.butt[12]->value());
-  opt_geometry_occ_sew_faces(0, GMSH_SET, o->geo.butt[13]->value());
-  opt_geometry_light_two_side(0, GMSH_SET, o->geo.butt[14]->value());
-
-  opt_geometry_normals(0, GMSH_SET, o->geo.value[0]->value());
-  opt_geometry_tangents(0, GMSH_SET, o->geo.value[1]->value());
-  opt_geometry_tolerance(0, GMSH_SET, o->geo.value[2]->value());
-  opt_geometry_point_size(0, GMSH_SET, o->geo.value[3]->value());
-  opt_geometry_line_width(0, GMSH_SET, o->geo.value[4]->value());
-  opt_geometry_point_sel_size(0, GMSH_SET, o->geo.value[5]->value());
-  opt_geometry_line_sel_width(0, GMSH_SET, o->geo.value[6]->value());
-
-  opt_geometry_point_type(0, GMSH_SET, o->geo.choice[0]->value());
-  opt_geometry_line_type(0, GMSH_SET, o->geo.choice[1]->value());
-  opt_geometry_surface_type(0, GMSH_SET, o->geo.choice[2]->value());
-
-  if(CTX.fast_redraw)
-    CTX.post.draw = CTX.mesh.draw = 0;
-  Draw();
-  CTX.post.draw = CTX.mesh.draw = 1;
-}
-
-// Mesh options
-
-void mesh_options_cb(CALLBACK_ARGS)
-{
-  GUI::instance()->options->showGroup(3);
-}
-
-void mesh_options_ok_cb(CALLBACK_ARGS)
-{
-  activate_cb(NULL, data);
-
-  optionWindow *o = GUI::instance()->options;
-
-  opt_mesh_reverse_all_normals(0, GMSH_SET, o->mesh.butt[0]->value());
-  opt_mesh_lc_from_curvature(0, GMSH_SET, o->mesh.butt[1]->value());
-  opt_mesh_lc_from_points(0, GMSH_SET, o->mesh.butt[5]->value());
-  opt_mesh_lc_extend_from_boundary(0, GMSH_SET, o->mesh.butt[16]->value());
-  opt_mesh_optimize(0, GMSH_SET, o->mesh.butt[2]->value());
-  opt_mesh_optimize_netgen(0, GMSH_SET, o->mesh.butt[24]->value());
-  opt_mesh_order(0, GMSH_SET, o->mesh.value[3]->value());
-  opt_mesh_smooth_internal_edges(0, GMSH_SET, o->mesh.butt[3]->value());
-  opt_mesh_second_order_incomplete(0, GMSH_SET, o->mesh.butt[4]->value());
-  opt_mesh_c1(0, GMSH_SET, o->mesh.butt[21]->value());
-  opt_mesh_points(0, GMSH_SET, o->mesh.butt[6]->value());
-  opt_mesh_lines(0, GMSH_SET, o->mesh.butt[7]->value());
-  opt_mesh_triangles(0, GMSH_SET, o->mesh.menu->menu()[0].value() ? 1 : 0);
-  opt_mesh_quadrangles(0, GMSH_SET, o->mesh.menu->menu()[1].value() ? 1 : 0);
-  opt_mesh_tetrahedra(0, GMSH_SET, o->mesh.menu->menu()[2].value() ? 1 : 0);
-  opt_mesh_hexahedra(0, GMSH_SET, o->mesh.menu->menu()[3].value() ? 1 : 0);
-  opt_mesh_prisms(0, GMSH_SET, o->mesh.menu->menu()[4].value() ? 1 : 0);
-  opt_mesh_pyramids(0, GMSH_SET, o->mesh.menu->menu()[5].value() ? 1 : 0);
-  opt_mesh_surfaces_edges(0, GMSH_SET, o->mesh.butt[8]->value());
-  opt_mesh_surfaces_faces(0, GMSH_SET, o->mesh.butt[9]->value());
-  opt_mesh_volumes_edges(0, GMSH_SET, o->mesh.butt[10]->value());
-  opt_mesh_volumes_faces(0, GMSH_SET, o->mesh.butt[11]->value());
-  opt_mesh_points_num(0, GMSH_SET, o->mesh.butt[12]->value());
-  opt_mesh_lines_num(0, GMSH_SET, o->mesh.butt[13]->value());
-  opt_mesh_surfaces_num(0, GMSH_SET, o->mesh.butt[14]->value());
-  opt_mesh_volumes_num(0, GMSH_SET, o->mesh.butt[15]->value());
-  opt_mesh_light(0, GMSH_SET, o->mesh.butt[17]->value());
-  opt_mesh_light_two_side(0, GMSH_SET, o->mesh.butt[18]->value());
-  opt_mesh_smooth_normals(0, GMSH_SET, o->mesh.butt[19]->value());
-  opt_mesh_light_lines(0, GMSH_SET, o->mesh.butt[20]->value());
-  opt_mesh_nb_smoothing(0, GMSH_SET, o->mesh.value[0]->value());
-  opt_mesh_lc_factor(0, GMSH_SET, o->mesh.value[2]->value());
-  opt_mesh_lc_min(0, GMSH_SET, o->mesh.value[25]->value());
-  opt_mesh_lc_max(0, GMSH_SET, o->mesh.value[26]->value());
-  opt_mesh_quality_inf(0, GMSH_SET, o->mesh.value[4]->value());
-  opt_mesh_quality_sup(0, GMSH_SET, o->mesh.value[5]->value());
-  opt_mesh_radius_inf(0, GMSH_SET, o->mesh.value[6]->value());
-  opt_mesh_radius_sup(0, GMSH_SET, o->mesh.value[7]->value());
-  opt_mesh_normals(0, GMSH_SET, o->mesh.value[8]->value());
-  opt_mesh_explode(0, GMSH_SET, o->mesh.value[9]->value());
-  opt_mesh_tangents(0, GMSH_SET, o->mesh.value[13]->value());
-  opt_mesh_point_size(0, GMSH_SET, o->mesh.value[10]->value());
-  opt_mesh_line_width(0, GMSH_SET, o->mesh.value[11]->value());
-  opt_mesh_label_frequency(0, GMSH_SET, o->mesh.value[12]->value());
-  opt_mesh_angle_smooth_normals(0, GMSH_SET, o->mesh.value[18]->value());
-
-  opt_mesh_point_type(0, GMSH_SET, o->mesh.choice[0]->value());
-  opt_mesh_algo2d(0, GMSH_SET,
-                  (o->mesh.choice[2]->value() == 0) ? ALGO_2D_FRONTAL : 
-                  (o->mesh.choice[2]->value() == 1) ? ALGO_2D_DELAUNAY :
-                  ALGO_2D_MESHADAPT_DELAUNAY);
-  opt_mesh_algo3d(0, GMSH_SET,
-                  (o->mesh.choice[3]->value() == 0) ? ALGO_3D_TETGEN_DELAUNAY : 
-                  ALGO_3D_NETGEN);
-  opt_mesh_recombine_algo(0, GMSH_SET,
-                  (o->mesh.choice[5]->value() == 0) ? 1 : 2);
-  opt_mesh_color_carousel(0, GMSH_SET, o->mesh.choice[4]->value());
-  opt_mesh_quality_type(0, GMSH_SET, o->mesh.choice[6]->value());
-  opt_mesh_label_type(0, GMSH_SET, o->mesh.choice[7]->value());
-
-  if(CTX.fast_redraw)
-    CTX.post.draw = CTX.mesh.draw = 0;
-  Draw();
-  CTX.post.draw = CTX.mesh.draw = 1;
-}
-
-// Solver options
-
-void solver_options_cb(CALLBACK_ARGS)
-{
-  GUI::instance()->options->showGroup(4);
-}
-
-void solver_options_ok_cb(CALLBACK_ARGS)
-{
-  activate_cb(NULL, data);
-
-  optionWindow *o = GUI::instance()->options;
-
-  int old_listen = (int)opt_solver_listen(0, GMSH_GET, o->solver.butt[0]->value());
-  opt_solver_listen(0, GMSH_SET, o->solver.butt[0]->value());
-  if(!old_listen && o->solver.butt[0]->value())
-    Solver(-1, NULL);
-
-  opt_solver_max_delay(0, GMSH_SET, o->solver.value[0]->value());
-
-  opt_solver_socket_name(0, GMSH_SET, o->solver.input[0]->value());
-
-  if(CTX.fast_redraw)
-    CTX.post.draw = CTX.mesh.draw = 0;
-  Draw();
-  CTX.post.draw = CTX.mesh.draw = 1;
-}
-
-// Post options
-
-void post_options_cb(CALLBACK_ARGS)
-{
-  GUI::instance()->options->showGroup(5);
-}
-
-void post_options_ok_cb(CALLBACK_ARGS)
-{
-  activate_cb(NULL, data);
-
-  optionWindow *o = GUI::instance()->options;
-
-  opt_post_anim_cycle(0, GMSH_SET, o->post.butt[0]->value());
-  opt_post_combine_remove_orig(0, GMSH_SET, o->post.butt[1]->value());
-  opt_post_horizontal_scales(0, GMSH_SET, o->post.butt[2]->value());
-
-  opt_post_anim_delay(0, GMSH_SET, o->post.value[0]->value());
-
-  opt_post_link(0, GMSH_SET, o->post.choice[0]->value());
-
-  if(CTX.fast_redraw)
-    CTX.post.draw = CTX.mesh.draw = 0;
-  Draw();
-  CTX.post.draw = CTX.mesh.draw = 1;
-}
-
-// View options
-
-void view_options_cb(CALLBACK_ARGS)
-{
-  GUI::instance()->options->showGroup((int)(long)data + 6);
-}
-
-void view_options_timestep_cb(CALLBACK_ARGS)
-{
-  int links = (int)opt_post_link(0, GMSH_GET, 0);
-  for(int i = 0; i < (int)PView::list.size(); i++) {
-    if((links == 2 || links == 4) ||
-       ((links == 1 || links == 3) && opt_view_visible(i, GMSH_GET, 0)) ||
-       (links == 0 && i == GUI::instance()->options->view.index)) {
-      opt_view_timestep(i, GMSH_SET, ((Fl_Value_Input *) w)->value());
-    }
-  }
-  Draw();
-}
-
-void view_options_timestep_decr_cb(CALLBACK_ARGS)
-{
-  int links = (int)opt_post_link(0, GMSH_GET, 0);
-  for(int i = 0; i < (int)PView::list.size(); i++) {
-    if((links == 2 || links == 4) ||
-       ((links == 1 || links == 3) && opt_view_visible(i, GMSH_GET, 0)) ||
-       (links == 0 && i == GUI::instance()->options->view.index)) {
-      opt_view_timestep(i, GMSH_SET | GMSH_GUI,
-                        opt_view_timestep(i, GMSH_GET, 0) - 1);
-    }
-  }
-  Draw();
-}
-
-void view_options_timestep_incr_cb(CALLBACK_ARGS)
-{
-  int links = (int)opt_post_link(0, GMSH_GET, 0);
-  for(int i = 0; i < (int)PView::list.size(); i++) {
-    if((links == 2 || links == 4) ||
-       ((links == 1 || links == 3) && opt_view_visible(i, GMSH_GET, 0)) ||
-       (links == 0 && i == GUI::instance()->options->view.index)) {
-      opt_view_timestep(i, GMSH_SET | GMSH_GUI,
-                        opt_view_timestep(i, GMSH_GET, 0) + 1);
-    }
-  }
-  Draw();
-}
-
-void view_arrow_param_cb(CALLBACK_ARGS)
-{
-  double a = opt_view_arrow_head_radius(GUI::instance()->options->view.index, GMSH_GET, 0);
-  double b = opt_view_arrow_stem_length(GUI::instance()->options->view.index, GMSH_GET, 0);
-  double c = opt_view_arrow_stem_radius(GUI::instance()->options->view.index, GMSH_GET, 0);
-  while(arrow_editor("Arrow Editor", a, b, c)){
-    opt_view_arrow_head_radius(GUI::instance()->options->view.index, GMSH_SET, a);
-    opt_view_arrow_stem_length(GUI::instance()->options->view.index, GMSH_SET, b);
-    opt_view_arrow_stem_radius(GUI::instance()->options->view.index, GMSH_SET, c);
-    Draw();
-  }
-}
-
-void view_options_ok_cb(CALLBACK_ARGS)
-{
-  int current = GUI::instance()->options->view.index;
-
-  if(current < 0)
-    return;
-
-  activate_cb(NULL, data);
-
-  optionWindow *o = GUI::instance()->options;
-
-  if(data){
-    const char *str = (const char*)data;
-    if(!strcmp(str, "range_min")){
-      o->view.value[31]->value(opt_view_min(o->view.index, GMSH_GET, 0));
-    }
-    else if(!strcmp(str, "range_max")){
-      o->view.value[32]->value(opt_view_max(o->view.index, GMSH_GET, 0));
-    }
-  }
-  
-  int force = 0, links = (int)opt_post_link(0, GMSH_GET, 0);
-
-  // get the old values for the current view
-
-  double scale_type = opt_view_scale_type(current, GMSH_GET, 0);
-  double intervals_type = opt_view_intervals_type(current, GMSH_GET, 0);
-  double point_type = opt_view_point_type(current, GMSH_GET, 0);
-  double line_type = opt_view_line_type(current, GMSH_GET, 0);
-  double vector_type = opt_view_vector_type(current, GMSH_GET, 0);
-  double glyph_location = opt_view_glyph_location(current, GMSH_GET, 0);
-  double tensor_type = opt_view_tensor_type(current, GMSH_GET, 0);
-  double range_type = opt_view_range_type(current, GMSH_GET, 0);
-  double axes = opt_view_axes(current, GMSH_GET, 0);
-  double mikado = opt_view_axes_mikado(current, GMSH_GET, 0);
-  double boundary = opt_view_boundary(current, GMSH_GET, 0);
-  double external_view = opt_view_external_view(current, GMSH_GET, 0);
-  double gen_raise_view = opt_view_gen_raise_view(current, GMSH_GET, 0);
-  double show_time = opt_view_show_time(current, GMSH_GET, 0);
-
-  double type = opt_view_type(current, GMSH_GET, 0);
-  double saturate_values = opt_view_saturate_values(current, GMSH_GET, 0);
-  double max_recursion_level = opt_view_max_recursion_level(current, GMSH_GET, 0);
-  double target_error = opt_view_target_error(current, GMSH_GET, 0);
-  double show_element = opt_view_show_element(current, GMSH_GET, 0);
-  double draw_skin_only = opt_view_draw_skin_only(current, GMSH_GET, 0);
-  double show_scale = opt_view_show_scale(current, GMSH_GET, 0);
-  double auto_position = opt_view_auto_position(current, GMSH_GET, 0);
-  double axes_auto_position = opt_view_axes_auto_position(current, GMSH_GET, 0);
-  double draw_strings = opt_view_draw_strings(current, GMSH_GET, 0);
-  double light = opt_view_light(current, GMSH_GET, 0);
-  double light_two_side = opt_view_light_two_side(current, GMSH_GET, 0);
-  double light_lines = opt_view_light_lines(current, GMSH_GET, 0);
-  double smooth_normals = opt_view_smooth_normals(current, GMSH_GET, 0);
-  double draw_points = opt_view_draw_points(current, GMSH_GET, 0);
-  double draw_lines = opt_view_draw_lines(current, GMSH_GET, 0);
-  double draw_triangles = opt_view_draw_triangles(current, GMSH_GET, 0);
-  double draw_quadrangles = opt_view_draw_quadrangles(current, GMSH_GET, 0);
-  double draw_tetrahedra = opt_view_draw_tetrahedra(current, GMSH_GET, 0);
-  double draw_hexahedra = opt_view_draw_hexahedra(current, GMSH_GET, 0);
-  double draw_prisms = opt_view_draw_prisms(current, GMSH_GET, 0);
-  double draw_pyramids = opt_view_draw_pyramids(current, GMSH_GET, 0);
-  double draw_scalars = opt_view_draw_scalars(current, GMSH_GET, 0);
-  double draw_vectors = opt_view_draw_vectors(current, GMSH_GET, 0);
-  double draw_tensors = opt_view_draw_tensors(current, GMSH_GET, 0);
-  double use_gen_raise = opt_view_use_gen_raise(current, GMSH_GET, 0);
-  double fake_transparency = opt_view_fake_transparency(current, GMSH_GET, 0);
-  double use_stipple = opt_view_use_stipple(current, GMSH_GET, 0);
-  double center_glyphs = opt_view_center_glyphs(current, GMSH_GET, 0);
-
-  double normals = opt_view_normals(current, GMSH_GET, 0);
-  double tangents = opt_view_tangents(current, GMSH_GET, 0);
-  double custom_min = opt_view_custom_min(current, GMSH_GET, 0);
-  double custom_max = opt_view_custom_max(current, GMSH_GET, 0);
-  double nb_iso = opt_view_nb_iso(current, GMSH_GET, 0);
-  double offset0 = opt_view_offset0(current, GMSH_GET, 0);
-  double offset1 = opt_view_offset1(current, GMSH_GET, 0);
-  double offset2 = opt_view_offset2(current, GMSH_GET, 0);
-  double transform00 = opt_view_transform00(current, GMSH_GET, 0);
-  double transform01 = opt_view_transform01(current, GMSH_GET, 0);
-  double transform02 = opt_view_transform02(current, GMSH_GET, 0);
-  double transform10 = opt_view_transform10(current, GMSH_GET, 0);
-  double transform11 = opt_view_transform11(current, GMSH_GET, 0);
-  double transform12 = opt_view_transform12(current, GMSH_GET, 0);
-  double transform20 = opt_view_transform20(current, GMSH_GET, 0);
-  double transform21 = opt_view_transform21(current, GMSH_GET, 0);
-  double transform22 = opt_view_transform22(current, GMSH_GET, 0);
-  double raise0 = opt_view_raise0(current, GMSH_GET, 0);
-  double raise1 = opt_view_raise1(current, GMSH_GET, 0);
-  double raise2 = opt_view_raise2(current, GMSH_GET, 0);
-  double normal_raise = opt_view_normal_raise(current, GMSH_GET, 0);
-  double timestep = opt_view_timestep(current, GMSH_GET, 0);
-  double arrow_size = opt_view_arrow_size(current, GMSH_GET, 0);
-  double arrow_size_proportional = opt_view_arrow_size_proportional(current, GMSH_GET, 0);
-  double displacement_factor = opt_view_displacement_factor(current, GMSH_GET, 0);
-  double point_size = opt_view_point_size(current, GMSH_GET, 0);
-  double line_width = opt_view_line_width(current, GMSH_GET, 0);
-  double explode = opt_view_explode(current, GMSH_GET, 0);
-  double angle_smooth_normals = opt_view_angle_smooth_normals(current, GMSH_GET, 0);
-  double position0 = opt_view_position0(current, GMSH_GET, 0);
-  double position1 = opt_view_position1(current, GMSH_GET, 0);
-  double size0 = opt_view_size0(current, GMSH_GET, 0);
-  double size1 = opt_view_size1(current, GMSH_GET, 0);
-  double axes_tics0 = opt_view_axes_tics0(current, GMSH_GET, 0);
-  double axes_tics1 = opt_view_axes_tics1(current, GMSH_GET, 0);
-  double axes_tics2 = opt_view_axes_tics2(current, GMSH_GET, 0);
-  double axes_xmin = opt_view_axes_xmin(current, GMSH_GET, 0);
-  double axes_ymin = opt_view_axes_ymin(current, GMSH_GET, 0);
-  double axes_zmin = opt_view_axes_zmin(current, GMSH_GET, 0);
-  double axes_xmax = opt_view_axes_xmax(current, GMSH_GET, 0);
-  double axes_ymax = opt_view_axes_ymax(current, GMSH_GET, 0);
-  double axes_zmax = opt_view_axes_zmax(current, GMSH_GET, 0);
-  double gen_raise_factor = opt_view_gen_raise_factor(current, GMSH_GET, 0);
-
-  char name[256]; strcpy(name, opt_view_name(current, GMSH_GET, NULL));
-  char format[256]; strcpy(format, opt_view_format(current, GMSH_GET, NULL));
-  char axes_label0[256]; strcpy(axes_label0, opt_view_axes_label0(current, GMSH_GET, NULL));
-  char axes_label1[256]; strcpy(axes_label1, opt_view_axes_label1(current, GMSH_GET, NULL));
-  char axes_label2[256]; strcpy(axes_label2, opt_view_axes_label2(current, GMSH_GET, NULL));
-  char axes_format0[256]; strcpy(axes_format0, opt_view_axes_format0(current, GMSH_GET, NULL));
-  char axes_format1[256]; strcpy(axes_format1, opt_view_axes_format1(current, GMSH_GET, NULL));
-  char axes_format2[256]; strcpy(axes_format2, opt_view_axes_format2(current, GMSH_GET, NULL));
-  char gen_raise0[256]; strcpy(gen_raise0, opt_view_gen_raise0(current, GMSH_GET, NULL));
-  char gen_raise1[256]; strcpy(gen_raise1, opt_view_gen_raise1(current, GMSH_GET, NULL));
-  char gen_raise2[256]; strcpy(gen_raise2, opt_view_gen_raise2(current, GMSH_GET, NULL));
-
-  // modify only the views that need to be updated
-  for(int i = 0; i < (int)PView::list.size(); i++) {
-    if((links == 2 || links == 4) ||
-       ((links == 1 || links == 3) && opt_view_visible(i, GMSH_GET, 0)) ||
-       (links == 0 && i == current)) {
-
-      if(links == 3 || links == 4)
-        force = 1;
-
-      double val;
-
-      // view_choice
-
-      val = o->view.choice[1]->value() + 1;
-      if(force || (val != scale_type))
-        opt_view_scale_type(i, GMSH_SET, val);
-
-      val = o->view.choice[0]->value() + 1;
-      if(force || (val != intervals_type))
-        opt_view_intervals_type(i, GMSH_SET, val);
-      
-      val = o->view.choice[5]->value();
-      if(force || (val != point_type))
-        opt_view_point_type(i, GMSH_SET, val);
-      
-      val = o->view.choice[6]->value();
-      if(force || (val != line_type))
-        opt_view_line_type(i, GMSH_SET, val);
-
-      val = o->view.choice[2]->value() + 1;
-      if(force || (val != vector_type))
-        opt_view_vector_type(i, GMSH_SET, val);
-
-      val = o->view.choice[3]->value() + 1;
-      if(force || (val != glyph_location))
-        opt_view_glyph_location(i, GMSH_SET, val);
-
-      val = o->view.choice[4]->value() + 1;
-      if(force || (val != tensor_type))
-        opt_view_tensor_type(i, GMSH_SET, val);
-      
-      val = o->view.choice[7]->value() + 1;
-      if(force || (val != range_type))
-        opt_view_range_type(i, GMSH_SET, val);
-
-      val = o->view.choice[8]->value();
-      if(force || (val != axes))
-        opt_view_axes(i, GMSH_SET, val);
-
-      val = o->view.choice[9]->value();
-      if(force || (val != boundary))
-        opt_view_boundary(i, GMSH_SET, val);
-
-      val = o->view.choice[10]->value() - 1;
-      if(force || (val != external_view))
-        opt_view_external_view(i, GMSH_SET, val);
-
-      val = o->view.choice[11]->value() - 1;
-      if(force || (val != gen_raise_view))
-        opt_view_gen_raise_view(i, GMSH_SET, val);
-
-      val = o->view.choice[12]->value();
-      if(force || (val != show_time))
-        opt_view_show_time(i, GMSH_SET, val);
-      
-      val = o->view.choice[13]->value() + 1;
-      if(force || (val != type))
-        opt_view_type(i, GMSH_SET, val);
-
-      // view_butts
-
-      val = o->view.butt[0]->value();
-      if(force || (val != arrow_size_proportional))
-        opt_view_arrow_size_proportional(i, GMSH_SET, val);
-
-      val = o->view.butt[38]->value();
-      if(force || (val != saturate_values))
-        opt_view_saturate_values(i, GMSH_SET, val);
-
-      val = o->view.butt[10]->value();
-      if(force || (val != show_element))
-        opt_view_show_element(i, GMSH_SET, val);
-
-      val = o->view.butt[2]->value();
-      if(force || (val != draw_skin_only))
-        opt_view_draw_skin_only(i, GMSH_SET, val);
-
-      val = o->view.butt[4]->value();
-      if(force || (val != show_scale))
-        opt_view_show_scale(i, GMSH_SET, val);
-
-      val = o->view.butt[3]->value();
-      if(force || (val != mikado))
-        opt_view_axes_mikado(i, GMSH_SET, val);
-
-      val = o->view.butt[7]->value();
-      if(force || (val != auto_position))
-        opt_view_auto_position(i, GMSH_SET, val);
-
-      val = o->view.butt[25]->value();
-      if(force || (val != axes_auto_position))
-        opt_view_axes_auto_position(i, GMSH_SET, val);
-
-      val = o->view.butt[5]->value();
-      if(force || (val != draw_strings))
-        opt_view_draw_strings(i, GMSH_SET, val);
-
-      val = o->view.butt[11]->value();
-      if(force || (val != light))
-        opt_view_light(i, GMSH_SET, val);
-
-      val = o->view.butt[8]->value();
-      if(force || (val != light_lines))
-        opt_view_light_lines(i, GMSH_SET, val);
-
-      val = o->view.butt[9]->value();
-      if(force || (val != light_two_side))
-        opt_view_light_two_side(i, GMSH_SET, val);
-
-      val = o->view.butt[12]->value();
-      if(force || (val != smooth_normals))
-        opt_view_smooth_normals(i, GMSH_SET, val);
-
-      val = o->view.menu[0]->menu()[0].value() ? 1 : 0;
-      if(force || (val != draw_scalars))
-        opt_view_draw_scalars(i, GMSH_SET, val);
-
-      val = o->view.menu[0]->menu()[1].value() ? 1 : 0;
-      if(force || (val != draw_vectors))
-        opt_view_draw_vectors(i, GMSH_SET, val);
-
-      val = o->view.menu[0]->menu()[2].value() ? 1 : 0;
-      if(force || (val != draw_tensors))
-        opt_view_draw_tensors(i, GMSH_SET, val);
-
-      val = o->view.menu[1]->menu()[0].value() ? 1 : 0;
-      if(force || (val != draw_points))
-        opt_view_draw_points(i, GMSH_SET, val);
-
-      val = o->view.menu[1]->menu()[1].value() ? 1 : 0;
-      if(force || (val != draw_lines))
-        opt_view_draw_lines(i, GMSH_SET, val);
-
-      val = o->view.menu[1]->menu()[2].value() ? 1 : 0;
-      if(force || (val != draw_triangles))
-        opt_view_draw_triangles(i, GMSH_SET, val);
-
-      val = o->view.menu[1]->menu()[3].value() ? 1 : 0;
-      if(force || (val != draw_quadrangles))
-        opt_view_draw_quadrangles(i, GMSH_SET, val);
-
-      val = o->view.menu[1]->menu()[4].value() ? 1 : 0;
-      if(force || (val != draw_tetrahedra))
-        opt_view_draw_tetrahedra(i, GMSH_SET, val);
-
-      val = o->view.menu[1]->menu()[5].value() ? 1 : 0;
-      if(force || (val != draw_hexahedra))
-        opt_view_draw_hexahedra(i, GMSH_SET, val);
-
-      val = o->view.menu[1]->menu()[6].value() ? 1 : 0;
-      if(force || (val != draw_prisms))
-        opt_view_draw_prisms(i, GMSH_SET, val);
-
-      val = o->view.menu[1]->menu()[7].value() ? 1 : 0;
-      if(force || (val != draw_pyramids))
-        opt_view_draw_pyramids(i, GMSH_SET, val);
-
-      val = o->view.butt[6]->value();
-      if(force || (val != use_gen_raise))
-        opt_view_use_gen_raise(i, GMSH_SET, val);
-
-      val = o->view.butt[24]->value();
-      if(force || (val != fake_transparency))
-        opt_view_fake_transparency(i, GMSH_SET, val);
-
-      val = o->view.butt[26]->value();
-      if(force || (val != use_stipple))
-        opt_view_use_stipple(i, GMSH_SET, val);
-
-      val = o->view.butt[1]->value();
-      if(force || (val != center_glyphs))
-        opt_view_center_glyphs(i, GMSH_SET, val);
-
-      // view_values
-      
-      val = o->view.value[0]->value();
-      if(force || (val != normals))
-        opt_view_normals(i, GMSH_SET, val);
-
-      val = o->view.value[1]->value();
-      if(force || (val != tangents))
-        opt_view_tangents(i, GMSH_SET, val);
-
-      val = o->view.value[31]->value();
-      if(force || (val != custom_min))
-        opt_view_custom_min(i, GMSH_SET, val);
-
-      val = o->view.value[32]->value();
-      if(force || (val != custom_max))
-        opt_view_custom_max(i, GMSH_SET, val);
-
-      val = o->view.value[33]->value();
-      if(force || (val != max_recursion_level))
-        opt_view_max_recursion_level(i, GMSH_SET, val);
-
-      val = o->view.value[34]->value();
-      if(force || (val != target_error))
-        opt_view_target_error(i, GMSH_SET, val);
-
-      val = o->view.value[30]->value();
-      if(force || (val != nb_iso))
-        opt_view_nb_iso(i, GMSH_SET, val);
-
-      val = o->view.value[40]->value();
-      if(force || (val != offset0))
-        opt_view_offset0(i, GMSH_SET, val);
-
-      val = o->view.value[41]->value();
-      if(force || (val != offset1))
-        opt_view_offset1(i, GMSH_SET, val);
-
-      val = o->view.value[42]->value();
-      if(force || (val != offset2))
-        opt_view_offset2(i, GMSH_SET, val);
-
-      val = o->view.value[51]->value();
-      if(force || (val != transform00))
-        opt_view_transform00(i, GMSH_SET, val);
-
-      val = o->view.value[52]->value();
-      if(force || (val != transform01))
-        opt_view_transform01(i, GMSH_SET, val);
-
-      val = o->view.value[53]->value();
-      if(force || (val != transform02))
-        opt_view_transform02(i, GMSH_SET, val);
-
-      val = o->view.value[54]->value();
-      if(force || (val != transform10))
-        opt_view_transform10(i, GMSH_SET, val);
-
-      val = o->view.value[55]->value();
-      if(force || (val != transform11))
-        opt_view_transform11(i, GMSH_SET, val);
-
-      val = o->view.value[56]->value();
-      if(force || (val != transform12))
-        opt_view_transform12(i, GMSH_SET, val);
-
-      val = o->view.value[57]->value();
-      if(force || (val != transform20))
-        opt_view_transform20(i, GMSH_SET, val);
-
-      val = o->view.value[58]->value();
-      if(force || (val != transform21))
-        opt_view_transform21(i, GMSH_SET, val);
-
-      val = o->view.value[59]->value();
-      if(force || (val != transform22))
-        opt_view_transform22(i, GMSH_SET, val);
-
-      val = o->view.value[43]->value();
-      if(force || (val != raise0))
-        opt_view_raise0(i, GMSH_SET, val);
-
-      val = o->view.value[44]->value();
-      if(force || (val != raise1))
-        opt_view_raise1(i, GMSH_SET, val);
-
-      val = o->view.value[45]->value();
-      if(force || (val != raise2))
-        opt_view_raise2(i, GMSH_SET, val);
-
-      val = o->view.value[46]->value();
-      if(force || (val != normal_raise))
-        opt_view_normal_raise(i, GMSH_SET, val);
-
-      val = o->view.value[50]->value();
-      if(force || (val != timestep))
-        opt_view_timestep(i, GMSH_SET, val);
-
-      val = o->view.value[60]->value();
-      if(force || (val != arrow_size))
-        opt_view_arrow_size(i, GMSH_SET, val);
-
-      val = o->view.value[63]->value();
-      if(force || (val != displacement_factor))
-        opt_view_displacement_factor(i, GMSH_SET, val);
-
-      val = o->view.value[61]->value();
-      if(force || (val != point_size))
-        opt_view_point_size(i, GMSH_SET, val);
-
-      val = o->view.value[62]->value();
-      if(force || (val != line_width))
-        opt_view_line_width(i, GMSH_SET, val);
-
-      val = o->view.value[12]->value();
-      if(force || (val != explode))
-        opt_view_explode(i, GMSH_SET, val);
-
-      val = o->view.value[10]->value();
-      if(force || (val != angle_smooth_normals))
-        opt_view_angle_smooth_normals(i, GMSH_SET, val);
-
-      val = o->view.value[20]->value();
-      if(force || (val != position0))
-        opt_view_position0(i, GMSH_SET, val);
-
-      val = o->view.value[21]->value();
-      if(force || (val != position1))
-        opt_view_position1(i, GMSH_SET, val);
-
-      val = o->view.value[22]->value();
-      if(force || (val != size0))
-        opt_view_size0(i, GMSH_SET, val);
-      
-      val = o->view.value[23]->value();
-      if(force || (val != size1))
-        opt_view_size1(i, GMSH_SET, val);
-
-      val = o->view.value[13]->value();
-      if(force || (val != axes_xmin))
-        opt_view_axes_xmin(i, GMSH_SET, val);
-
-      val = o->view.value[14]->value();
-      if(force || (val != axes_ymin))
-        opt_view_axes_ymin(i, GMSH_SET, val);
-
-      val = o->view.value[15]->value();
-      if(force || (val != axes_zmin))
-        opt_view_axes_zmin(i, GMSH_SET, val);
-
-      val = o->view.value[16]->value();
-      if(force || (val != axes_xmax))
-        opt_view_axes_xmax(i, GMSH_SET, val);
-
-      val = o->view.value[17]->value();
-      if(force || (val != axes_ymax))
-        opt_view_axes_ymax(i, GMSH_SET, val);
-
-      val = o->view.value[18]->value();
-      if(force || (val != axes_zmax))
-        opt_view_axes_zmax(i, GMSH_SET, val);
-
-      val = o->view.value[2]->value();
-      if(force || (val != gen_raise_factor))
-        opt_view_gen_raise_factor(i, GMSH_SET, val);
-
-      val = o->view.value[3]->value();
-      if(force || (val != axes_tics0))
-        opt_view_axes_tics0(i, GMSH_SET, val);
-
-      val = o->view.value[4]->value();
-      if(force || (val != axes_tics1))
-        opt_view_axes_tics1(i, GMSH_SET, val);
-
-      val = o->view.value[5]->value();
-      if(force || (val != axes_tics2))
-        opt_view_axes_tics2(i, GMSH_SET, val);
-
-      // view_inputs
-
-      const char *str;
-
-      str = o->view.input[0]->value();
-      if(force || strcmp(str, name))
-        opt_view_name(i, GMSH_SET, str);
-
-      str = o->view.input[1]->value();
-      if(force || strcmp(str, format))
-        opt_view_format(i, GMSH_SET, str);
-
-      str = o->view.input[10]->value();
-      if(force || strcmp(str, axes_label0))
-        opt_view_axes_label0(i, GMSH_SET, str);
-
-      str = o->view.input[11]->value();
-      if(force || strcmp(str, axes_label1))
-        opt_view_axes_label1(i, GMSH_SET, str);
-
-      str = o->view.input[12]->value();
-      if(force || strcmp(str, axes_label2))
-        opt_view_axes_label2(i, GMSH_SET, str);
-
-      str = o->view.input[7]->value();
-      if(force || strcmp(str, axes_format0))
-        opt_view_axes_format0(i, GMSH_SET, str);
-
-      str = o->view.input[8]->value();
-      if(force || strcmp(str, axes_format1))
-        opt_view_axes_format1(i, GMSH_SET, str);
-
-      str = o->view.input[9]->value();
-      if(force || strcmp(str, axes_format2))
-        opt_view_axes_format2(i, GMSH_SET, str);
-
-      str = o->view.input[4]->value();
-      if(force || strcmp(str, gen_raise0))
-        opt_view_gen_raise0(i, GMSH_SET, str);
-
-      str = o->view.input[5]->value();
-      if(force || strcmp(str, gen_raise1))
-        opt_view_gen_raise1(i, GMSH_SET, str);
-
-      str = o->view.input[6]->value();
-      if(force || strcmp(str, gen_raise2))
-        opt_view_gen_raise2(i, GMSH_SET, str);
-
-      // colors (since the color buttons modify the values directly
-      // through callbacks, we can use the opt_XXX routines directly)
-      if(force || (i != current)){
-        opt_view_color_points(i, GMSH_SET, opt_view_color_points(current, GMSH_GET, 0));
-        opt_view_color_lines(i, GMSH_SET, opt_view_color_lines(current, GMSH_GET, 0));
-        opt_view_color_triangles(i, GMSH_SET, opt_view_color_triangles(current, GMSH_GET, 0));
-        opt_view_color_quadrangles(i, GMSH_SET, opt_view_color_quadrangles(current, GMSH_GET, 0));
-        opt_view_color_tetrahedra(i, GMSH_SET, opt_view_color_tetrahedra(current, GMSH_GET, 0));
-        opt_view_color_hexahedra(i, GMSH_SET, opt_view_color_hexahedra(current, GMSH_GET, 0));
-        opt_view_color_prisms(i, GMSH_SET, opt_view_color_prisms(current, GMSH_GET, 0));
-        opt_view_color_pyramids(i, GMSH_SET, opt_view_color_pyramids(current, GMSH_GET, 0));
-        opt_view_color_tangents(i, GMSH_SET, opt_view_color_tangents(current, GMSH_GET, 0));
-        opt_view_color_normals(i, GMSH_SET, opt_view_color_normals(current, GMSH_GET, 0));
-        opt_view_color_text2d(i, GMSH_SET, opt_view_color_text2d(current, GMSH_GET, 0));
-        opt_view_color_text3d(i, GMSH_SET, opt_view_color_text3d(current, GMSH_GET, 0));
-        opt_view_color_axes(i, GMSH_SET, opt_view_color_axes(current, GMSH_GET, 0));
-      }
-
-      // colorbar window
-
-      if(force || (i != current)) {
-        ColorTable_Copy(&PView::list[current]->getOptions()->CT);
-        ColorTable_Paste(&PView::list[i]->getOptions()->CT);
-        PView::list[i]->setChanged(true);
-      }
-    }
-  }
-
-  if(CTX.fast_redraw)
-    CTX.post.draw = CTX.mesh.draw = 0;
-  Draw();
-  CTX.post.draw = CTX.mesh.draw = 1;
-}
-
-// Statistics Menu
-
-void statistics_cb(CALLBACK_ARGS)
-{
-  GUI::instance()->stats->show();
-}
-
-void statistics_update_cb(CALLBACK_ARGS)
-{
-  GUI::instance()->stats->compute(true);
-}
-
-void statistics_histogram_cb(CALLBACK_ARGS)
-{
-  std::string name((const char*)data);
-
-  std::vector<double> x, y;
-
-  if(name == "Gamma2D"){
-    for(int i = 0; i < 100; i++) y.push_back(GUI::instance()->stats->quality[0][i]);
-    new PView("Gamma", "# Elements", x, y);
-  }
-  else if(name == "Eta2D"){
-    for(int i = 0; i < 100; i++) y.push_back(GUI::instance()->stats->quality[1][i]);
-    new PView("Eta", "# Elements", x, y);
-  }
-  else if(name == "Rho2D"){
-    for(int i = 0; i < 100; i++) y.push_back(GUI::instance()->stats->quality[2][i]);
-    new PView("Rho", "# Elements", x, y);
-  }
-  else if(name == "Disto2D"){
-    for(int i = 0; i < 100; i++) y.push_back(GUI::instance()->stats->quality[3][i]);
-    new PView("Disto", "# Elements", x, y);
-  }
-  else{
-    std::vector<GEntity*> entities;
-    GModel::current()->getEntities(entities);
-    std::map<int, std::vector<double> > d;
-    for(unsigned int i = 0; i < entities.size(); i++){
-      if(entities[i]->dim() < 2) continue;
-      for(unsigned int j = 0; j < entities[i]->getNumMeshElements(); j++){
-        MElement *e = entities[i]->getMeshElement(j);
-        if(name == "Gamma3D")
-          d[e->getNum()].push_back(e->gammaShapeMeasure());
-        else if(name == "Eta3D")
-          d[e->getNum()].push_back(e->etaShapeMeasure());
-        else if(name == "Rho3D")
-          d[e->getNum()].push_back(e->rhoShapeMeasure());
-        else
-          d[e->getNum()].push_back(e->distoShapeMeasure());
-      }
-    }
-    name.resize(name.size() - 2);
-    new PView(name, "ElementData", GModel::current(), d);
-  }
-
-  GUI::instance()->updateViews();
-  Draw();
-}
-
-// Messages Menu
-
-void message_cb(CALLBACK_ARGS)
-{
-  GUI::instance()->messages->show();
-}
-
-void message_auto_scroll_cb(CALLBACK_ARGS)
-{
-  CTX.msg_auto_scroll = GUI::instance()->messages->butt->value();
-}
-
-void message_copy_cb(CALLBACK_ARGS)
-{
-#define BUFFL 50000
-  static char buff[BUFFL];
-  strcpy(buff, "");
-  for(int i = 1; i <= GUI::instance()->messages->browser->size(); i++) {
-    if(GUI::instance()->messages->browser->selected(i)) {
-      const char *c = GUI::instance()->messages->browser->text(i);
-      if(strlen(buff) + strlen(c) > BUFFL - 2) {
-        Msg::Error("Text selection too large to copy");
-        break;
-      }
-      if(c[0] == '@')
-        strcat(buff, &c[5]);
-      else
-        strcat(buff, c);
-      strcat(buff, "\n");
-    }
-  }
-  // bof bof bof
-  Fl::copy(buff, strlen(buff), 0);
-  Fl::copy(buff, strlen(buff), 1);
-}
-
-void message_clear_cb(CALLBACK_ARGS)
-{
-  GUI::instance()->messages->browser->clear();
-}
-
-void message_save_cb(CALLBACK_ARGS)
-{
- test:
-  if(file_chooser(0, 1, "Save", "*")) {
-    std::string name = file_chooser_get_name(1);
-    if(CTX.confirm_overwrite) {
-      if(!StatFile(name.c_str()))
-        if(!fl_choice("File '%s' already exists.\n\nDo you want to replace it?", 
-                      "Cancel", "Replace", NULL, name.c_str()))
-          goto test;
-    }
-    GUI::instance()->messages->save(name.c_str());
-  }
-}
-
-// Visibility Menu
-
-void visibility_cb(CALLBACK_ARGS)
-{
-  // get the visibility info from the model, and update the browser accordingly
-
-  const char *str = (const char*)data;
-  if(str && !strcmp(str, "redraw_only"))
-    GUI::instance()->visibility->show(true);
-  else
-    GUI::instance()->visibility->show(false);
-
-  GUI::instance()->visibility->browser->clear();
-
-  int type = GUI::instance()->visibility->type->value();
-
-  VisibilityManager::instance()->update(type);
-  for(int i = 0; i < VisibilityManager::instance()->getNumEntities(); i++){
-    GUI::instance()->visibility->browser->add(VisibilityManager::instance()->getBrowserLine(i).c_str());
-    if(VisibilityManager::instance()->getVisibility(i))
-      GUI::instance()->visibility->browser->select(i + 1);
-  }
-
-  // activate the delete button for physicals only!
-  if(type == 1)
-    GUI::instance()->visibility->push[0]->activate();
-  else
-    GUI::instance()->visibility->push[0]->deactivate();
-
-  // disable numeric and interactive selection for partitions
-  if(type == 2){
-    GUI::instance()->visibility->group[1]->deactivate();
-    GUI::instance()->visibility->group[2]->deactivate();
-  }
-  else{
-    GUI::instance()->visibility->group[1]->activate();
-    GUI::instance()->visibility->group[2]->activate();
-  }
-}
-
-void visibility_ok_cb(CALLBACK_ARGS)
-{
-  // if the browser is not empty, get the selections made in the
-  // browser and apply them into the model
-  if(VisibilityManager::instance()->getNumEntities()){
-    CTX.mesh.changed |= (ENT_LINE | ENT_SURFACE | ENT_VOLUME);
-    bool recursive = GUI::instance()->visibility->butt[0]->value() ? true : false;
-    int type = GUI::instance()->visibility->type->value();
-    VisibilityManager::instance()->setAllInvisible(type);
-    for(int i = 0; i < VisibilityManager::instance()->getNumEntities(); i++)
-      if(GUI::instance()->visibility->browser->selected(i + 1))
-        VisibilityManager::instance()->setVisibility(i, 1, recursive);
-    // then refresh the browser to account for recursive selections
-    for(int i = 0; i < VisibilityManager::instance()->getNumEntities(); i++)
-      if(VisibilityManager::instance()->getVisibility(i))
-        GUI::instance()->visibility->browser->select(i + 1);
-    Draw();
-  }
-}
-
-void visibility_save_cb(CALLBACK_ARGS)
-{
-  std::string str = VisibilityManager::instance()->getStringForGEO();
-  add_infile(str.c_str(), CTX.filename);
-}
-
-void visibility_delete_cb(CALLBACK_ARGS)
-{
-  int type = GUI::instance()->visibility->type->value();
-  if(type != 1) return; // delete only available for physicals
-
-  bool all = true;
-  for(int i = 0; i < VisibilityManager::instance()->getNumEntities(); i++){
-    if(!GUI::instance()->visibility->browser->selected(i + 1)){
-      all = false;
-      break;
-    }
-  }
-  if(all){
-    GModel::current()->deletePhysicalGroups();
-  }
-  else{
-    for(int i = 0; i < VisibilityManager::instance()->getNumEntities(); i++){
-      if(GUI::instance()->visibility->browser->selected(i + 1)){
-        Vis *v = VisibilityManager::instance()->getEntity(i);
-        GModel::current()->deletePhysicalGroup(v->getDim(), v->getTag());
-      }
-    }
-  }
-
-  visibility_cb(NULL, (void*)"redraw_only");
-}
-
-void visibility_sort_cb(CALLBACK_ARGS)
-{
-  const char *str = (const char*)data;
-  int val;
-  if(!strcmp(str, "type"))
-    val = 1;
-  else if(!strcmp(str, "number"))
-    val = 2;
-  else if(!strcmp(str, "name"))
-    val = 3;
-  else if(!strcmp(str, "-"))
-    val = -1;
-  else if(!strcmp(str, "+"))
-    val = -2;
-  else
-    val = 0;
-
-  if(val == 0) { // select or deselect everything
-    int selectall = 0;
-    for(int i = 0; i < GUI::instance()->visibility->browser->size(); i++)
-      if(!GUI::instance()->visibility->browser->selected(i + 1)) {
-        selectall = 1;
-        break;
-      }
-    if(selectall)
-      for(int i = 0; i < GUI::instance()->visibility->browser->size(); i++)
-        GUI::instance()->visibility->browser->select(i + 1);
-    else
-      GUI::instance()->visibility->browser->deselect();
-  }
-  else if(val == -1){ // invert the selection
-    int *state = new int[GUI::instance()->visibility->browser->size()];
-    for(int i = 0; i < GUI::instance()->visibility->browser->size(); i++)
-      state[i] = GUI::instance()->visibility->browser->selected(i + 1);
-    GUI::instance()->visibility->browser->deselect();
-    for(int i = 0; i < GUI::instance()->visibility->browser->size(); i++)
-      if(!state[i]) GUI::instance()->visibility->browser->select(i + 1);
-    delete [] state;
-  }
-  else if(val == -2){ // create new parameter name for selection
-    for(int i = 0; i < GUI::instance()->visibility->browser->size(); i++){
-      if(GUI::instance()->visibility->browser->selected(i + 1)){
-        static char tmpstr[256];
-        sprintf(tmpstr, "%d", VisibilityManager::instance()->getTag(i));
-        GUI::instance()->geoContext->input[1]->value(tmpstr);
-        break;
-      }
-    }
-    GUI::instance()->geoContext->input[0]->value("NewName");
-    GUI::instance()->geoContext->show(0);
-  }
-  else { // set new sorting mode
-    VisibilityManager::instance()->setSortMode(val);
-    visibility_cb(NULL, (void*)"redraw_only");
-  }
-}
-
-void visibility_number_cb(CALLBACK_ARGS)
-{
-  CTX.mesh.changed |= (ENT_LINE | ENT_SURFACE | ENT_VOLUME);
-
-  // type = 0 for elementary, 1 for physical and 2 for partitions
-  int type = GUI::instance()->visibility->type->value();
-  if(type != 0 && type != 1) return;
-
-  // what = 0 for nodes, 1 for elements, 2 for points, 3 for lines, 4
-  // for surfaces, 5 for volumes, 6 for physical points, 7 for
-  // physical lines, 8 for physical surfaces and 9 for physical
-  // volumes
-  int what = (int)(long)data;
-  char val;
-  if(what >= 100){ // show
-    val = 1;
-    what -= 100;
-  }
-  else{ // hide
-    val = 0;
-  }
-  const char *str = GUI::instance()->visibility->input[what]->value();
-  if(type == 1 && what >= 2 && what <= 5) what += 4;
-
-  int num = (!strcmp(str, "all") || !strcmp(str, "*")) ? -1 : atoi(str);
-  bool recursive = GUI::instance()->visibility->butt[0]->value() ? true : false;
-  
-  VisibilityManager::instance()->setVisibilityByNumber(what, num, val, recursive);
-
-  int pos = GUI::instance()->visibility->browser->position();
-  visibility_cb(NULL, (void*)"redraw_only");
-  GUI::instance()->visibility->browser->position(pos);
-  Draw();
-}
-
-static void _apply_visibility(char mode,
-                              std::vector<GVertex*> &vertices,
-                              std::vector<GEdge*> &edges,
-                              std::vector<GFace*> &faces,
-                              std::vector<GRegion*> &regions,
-                              std::vector<MElement*> &elements)
-{
-  // type = 0 for elementary, 1 for physical and 2 for partitions
-  int type = GUI::instance()->visibility->type->value();
-  if(type != 0 && type != 1) return;
-  bool recursive = GUI::instance()->visibility->butt[0]->value() ? true : false;
-
-  if(mode == 1){ // when showing a single entity, first hide everything
-    if(CTX.pick_elements)
-      VisibilityManager::instance()->setVisibilityByNumber(1, -1, 0, false);
-    else
-      for(int i = 2; i <= 5; i++)
-        VisibilityManager::instance()->setVisibilityByNumber(i, -1, 0, false);
-  }
-
-  if(mode == 2) mode = 1;
-  
-  if(CTX.pick_elements){
-    for(unsigned int i = 0; i < elements.size(); i++)
-      elements[i]->setVisibility(mode);
-  }
-  else{
-    for(unsigned int i = 0; i < vertices.size(); i++){
-      if(type == 0)
-        vertices[i]->setVisibility(mode, recursive);
-      else
-        for(unsigned int j = 0; j < vertices[i]->physicals.size(); j++)
-          VisibilityManager::instance()->setVisibilityByNumber
-            (6, vertices[i]->physicals[j], mode, recursive);
-    }
-    for(unsigned int i = 0; i < edges.size(); i++){
-      if(type == 0)
-        edges[i]->setVisibility(mode, recursive);
-      else
-        for(unsigned int j = 0; j < edges[i]->physicals.size(); j++)
-          VisibilityManager::instance()->setVisibilityByNumber
-            (7, edges[i]->physicals[j], mode, recursive);
-    }
-    for(unsigned int i = 0; i < faces.size(); i++){
-      if(type == 0)
-        faces[i]->setVisibility(mode, recursive);
-      else
-        for(unsigned int j = 0; j < faces[i]->physicals.size(); j++)
-          VisibilityManager::instance()->setVisibilityByNumber
-            (8, faces[i]->physicals[j], mode, recursive);
-    }
-    for(unsigned int i = 0; i < regions.size(); i++){
-      if(type == 0)
-        regions[i]->setVisibility(mode, recursive);
-      else
-        for(unsigned int j = 0; j < regions[i]->physicals.size(); j++)
-          VisibilityManager::instance()->setVisibilityByNumber
-            (9, regions[i]->physicals[j], mode, recursive);
-    }
-  }
-  int pos = GUI::instance()->visibility->browser->position();
-  visibility_cb(NULL, (void*)"redraw_only");
-  GUI::instance()->visibility->browser->position(pos);
-}
-
-void visibility_interactive_cb(CALLBACK_ARGS)
-{
-  const char *str = (const char*)data;
-  const char *help;
-  int what;
-  char mode;
-
-  if(!strcmp(str, "hide_elements")){
-    CTX.pick_elements = 1;
-    what = ENT_ALL;
-    mode = 0;
-    help = "elements to hide";
-  }
-  else if(!strcmp(str, "hide_points")){
-    CTX.pick_elements = 0;
-    what = ENT_POINT;
-    mode = 0;
-    help = "points to hide";
-    opt_geometry_points(0, GMSH_SET | GMSH_GUI, 1);
-  }
-  else if(!strcmp(str, "hide_lines")){
-    CTX.pick_elements = 0;
-    what = ENT_LINE;
-    mode = 0;
-    help = "lines to hide";
-    opt_geometry_lines(0, GMSH_SET | GMSH_GUI, 1);
-  }
-  else if(!strcmp(str, "hide_surfaces")){
-    CTX.pick_elements = 0;
-    what = ENT_SURFACE;
-    mode = 0;
-    help = "surfaces to hide";
-    if(GModel::current()->getMeshStatus() < 2)
-      opt_geometry_surfaces(0, GMSH_SET | GMSH_GUI, 1);
-  }
-  else if(!strcmp(str, "hide_volumes")){
-    CTX.pick_elements = 0;
-    what = ENT_VOLUME;
-    mode = 0;
-    help = "volumes to hide";
-    if(GModel::current()->getMeshStatus() < 3)
-      opt_geometry_volumes(0, GMSH_SET | GMSH_GUI, 1);
-  }
-  else if(!strcmp(str, "show_elements")){
-    CTX.pick_elements = 1;
-    what = ENT_ALL;
-    mode = 1;
-    help = "elements to show";
-  }
-  else if(!strcmp(str, "show_points")){
-    CTX.pick_elements = 0;
-    what = ENT_POINT;
-    mode = 1;
-    help = "points to show";
-    opt_geometry_points(0, GMSH_SET | GMSH_GUI, 1);
-  }
-  else if(!strcmp(str, "show_lines")){
-    CTX.pick_elements = 0;
-    what = ENT_LINE;
-    mode = 1;
-    help = "lines to show";
-    opt_geometry_lines(0, GMSH_SET | GMSH_GUI, 1);
-  }
-  else if(!strcmp(str, "show_surfaces")){
-    CTX.pick_elements = 0;
-    what = ENT_SURFACE;
-    mode = 1;
-    help = "surfaces to show";
-    if(GModel::current()->getMeshStatus() < 2)
-      opt_geometry_surfaces(0, GMSH_SET | GMSH_GUI, 1);
-  }
-  else if(!strcmp(str, "show_volumes")){
-    CTX.pick_elements = 0;
-    what = ENT_VOLUME;
-    mode = 1;
-    help = "volumes to show";
-    if(GModel::current()->getMeshStatus() < 3)
-      opt_geometry_volumes(0, GMSH_SET | GMSH_GUI, 1);
-  }
-  else if(!strcmp(str, "show_all")){
-    for(int i = 1; i <= 5; i++) // elements, points, lines, surfaces, volumes
-      VisibilityManager::instance()->setVisibilityByNumber(i, -1, 1, false);
-    CTX.mesh.changed = ENT_ALL;
-    Draw();  
-    return;
-  }
-  else
-    return;
-
-  std::vector<GVertex*> vertices, vertices_old;
-  std::vector<GEdge*> edges, edges_old;
-  std::vector<GFace*> faces, faces_old;
-  std::vector<GRegion*> regions, regions_old;
-  std::vector<MElement*> elements, elements_old;
-
-  while(1) {
-    if(what == ENT_ALL) 
-      CTX.mesh.changed = ENT_ALL;
-    Draw();
-    Msg::StatusBar(3, false, "Select %s\n[Press %s'q' to abort]", 
-        help, mode ? "" : "'u' to undo or ");
-
-    char ib = SelectEntity(what, vertices, edges, faces, regions, elements);
-    if(ib == 'l') {
-      _apply_visibility(mode, vertices, edges, faces, regions, elements);
-      // store for possible undo later
-      vertices_old = vertices;
-      edges_old = edges;
-      faces_old = faces;
-      regions_old = regions;
-      elements_old = elements;
-    }
-    if(ib == 'u' && !mode){ // undo only in hide mode
-      _apply_visibility(2, vertices_old, edges_old, faces_old, 
-                        regions_old, elements_old);
-    }
-    if(ib == 'q'){
-      break;
-    }
-  }
-
-  CTX.mesh.changed = ENT_ALL;
-  CTX.pick_elements = 0;
-  Draw();  
-  Msg::StatusBar(3, false, "");
-}
-
-// Clipping planes menu
-
-void clip_cb(CALLBACK_ARGS)
-{
-  GUI::instance()->clipping->show();
-}
-
-void clip_num_cb(CALLBACK_ARGS)
-{
-  GUI::instance()->clipping->resetBrowser();
-}
-
-void clip_update_cb(CALLBACK_ARGS)
-{
-  if(GUI::instance()->clipping->group[0]->visible()){ // clipping planes
-    int idx = GUI::instance()->clipping->choice->value();
-    CTX.geom.clip &= ~(1 << idx);
-    CTX.mesh.clip &= ~(1 << idx);
-    for(unsigned int i = 0; i < PView::list.size(); i++)
-      PView::list[i]->getOptions()->Clip &= ~(1 << idx);
-    for(int i = 0; i < GUI::instance()->clipping->browser->size(); i++){
-      if(GUI::instance()->clipping->browser->selected(i + 1)){
-        if(i == 0)
-          CTX.geom.clip |= (1 << idx);
-        else if(i == 1)
-          CTX.mesh.clip |= (1 << idx);
-        else if(i - 2 < PView::list.size())
-          PView::list[i - 2]->getOptions()->Clip |= (1 << idx);
-      }
-    }
-    for(int i = 0; i < 4; i++)
-      CTX.clip_plane[idx][i] = GUI::instance()->clipping->value[i]->value();
-  }
-  else{ // clipping box
-    CTX.geom.clip = 0;
-    CTX.mesh.clip = 0;
-    for(unsigned int i = 0; i < PView::list.size(); i++)
-      PView::list[i]->getOptions()->Clip = 0;
-    for(int i = 0; i < GUI::instance()->clipping->browser->size(); i++){
-      if(GUI::instance()->clipping->browser->selected(i + 1)){
-        for(int idx = 0; idx < 6; idx++){
-          if(i == 0)
-            CTX.geom.clip |= (1 << idx);
-          else if(i == 1)
-            CTX.mesh.clip |= (1 << idx);
-          else if(i - 2 < PView::list.size())
-            PView::list[i - 2]->getOptions()->Clip |= (1 << idx);
-        }
-      }
-    }
-    double c[3] = {GUI::instance()->clipping->value[4]->value(),
-                   GUI::instance()->clipping->value[5]->value(),
-                   GUI::instance()->clipping->value[6]->value()};
-    double d[3] = {GUI::instance()->clipping->value[7]->value(),
-                   GUI::instance()->clipping->value[8]->value(),
-                   GUI::instance()->clipping->value[9]->value()};
-    // left
-    CTX.clip_plane[0][0] = 1.;  CTX.clip_plane[0][1] = 0.;  CTX.clip_plane[0][2] = 0.;
-    CTX.clip_plane[0][3] = -(c[0] - d[0] / 2.);
-    // right
-    CTX.clip_plane[1][0] = -1.; CTX.clip_plane[1][1] = 0.; CTX.clip_plane[1][2] = 0.;
-    CTX.clip_plane[1][3] = (c[0] + d[0] / 2.);
-    // top
-    CTX.clip_plane[2][0] = 0.; CTX.clip_plane[2][1] = 1.; CTX.clip_plane[2][2] = 0.;
-    CTX.clip_plane[2][3] = -(c[1] - d[1] / 2.);
-    // bottom
-    CTX.clip_plane[3][0] = 0.; CTX.clip_plane[3][1] = -1.; CTX.clip_plane[3][2] = 0.;
-    CTX.clip_plane[3][3] = (c[1] + d[1] / 2.);
-    // near
-    CTX.clip_plane[4][0] = 0.; CTX.clip_plane[4][1] = 0.; CTX.clip_plane[4][2] = 1.;
-    CTX.clip_plane[4][3] = -(c[2] - d[2] / 2.);
-    // far
-    CTX.clip_plane[5][0] = 0.; CTX.clip_plane[5][1] = 0.; CTX.clip_plane[5][2] = -1.;
-    CTX.clip_plane[5][3] = (c[2] + d[2] / 2.);
-  }
-
-  if(CTX.clip_whole_elements || 
-     CTX.clip_whole_elements != GUI::instance()->clipping->butt[0]->value()){
-    for(int clip = 0; clip < 6; clip++){
-      if(CTX.mesh.clip)
-	CTX.mesh.changed |= (ENT_LINE | ENT_SURFACE | ENT_VOLUME);
-      for(unsigned int index = 0; index < PView::list.size(); index++)
-	if(PView::list[index]->getOptions()->Clip)
-	  PView::list[index]->setChanged(true);
-    }
-  }
-  
-  CTX.clip_whole_elements = GUI::instance()->clipping->butt[0]->value();
-  CTX.clip_only_draw_intersecting_volume = GUI::instance()->clipping->butt[1]->value();
-  CTX.clip_only_volume = GUI::instance()->clipping->butt[2]->value();
-  
-  int old = CTX.draw_bbox;
-  CTX.draw_bbox = 1;
-  if(CTX.fast_redraw)
-    CTX.post.draw = CTX.mesh.draw = 0;
-  Draw();
-  CTX.draw_bbox = old;
-  CTX.post.draw = CTX.mesh.draw = 1;
-}
-
-void clip_invert_cb(CALLBACK_ARGS)
-{
-  for(int i = 0; i < 4; i++)
-    GUI::instance()->clipping->value[i]->value(-GUI::instance()->clipping->value[i]->value());
-  clip_update_cb(NULL, NULL);
-}
-
-void clip_reset_cb(CALLBACK_ARGS)
-{
-  CTX.geom.clip = 0;
-  CTX.mesh.clip = 0;
-  for(unsigned int index = 0; index < PView::list.size(); index++)
-    PView::list[index]->getOptions()->Clip = 0;
-
-  for(int i = 0; i < 6; i++){
-    CTX.clip_plane[i][0] = 1.;
-    for(int j = 1; j < 4; j++)
-      CTX.clip_plane[i][j] = 0.;
-  }
-
-  if(CTX.clip_whole_elements){
-    CTX.mesh.changed |= (ENT_LINE | ENT_SURFACE | ENT_VOLUME);
-    for(unsigned int index = 0; index < PView::list.size(); index++)
-      PView::list[index]->setChanged(true);
-  }
-
-  GUI::instance()->clipping->resetBrowser();
-  Draw();
-}
-
-// Manipulator menu
-
-void manip_cb(CALLBACK_ARGS)
-{
-  GUI::instance()->manip->show();
-}
-
-void manip_update_cb(CALLBACK_ARGS)
-{
-  drawContext *ctx = GUI::instance()->graph[0]->gl->getDrawContext();
-  ctx->r[0] = GUI::instance()->manip->value[0]->value();
-  ctx->r[1] = GUI::instance()->manip->value[1]->value();
-  ctx->r[2] = GUI::instance()->manip->value[2]->value();
-  ctx->t[0] = GUI::instance()->manip->value[3]->value();
-  ctx->t[1] = GUI::instance()->manip->value[4]->value();
-  ctx->t[2] = GUI::instance()->manip->value[5]->value();
-  ctx->s[0] = GUI::instance()->manip->value[6]->value();
-  ctx->s[1] = GUI::instance()->manip->value[7]->value();
-  ctx->s[2] = GUI::instance()->manip->value[8]->value();
-  ctx->setQuaternionFromEulerAngles();
-  Draw();
-}
-
-// Help Menu (if you change the following, please also change the
-// texinfo documentation in doc/texinfo/shortcuts.texi)
-
-#if defined(__APPLE__)
-#  define CC(str) "Cmd+" str " "
-#else
-#  define CC(str) "Ctrl+" str
-#endif
-
-void help_short_cb(CALLBACK_ARGS)
-{
-  Msg::Direct(" ");
-  Msg::Direct("Keyboard shortcuts:");
-  Msg::Direct(" ");
-  Msg::Direct("  Left arrow    Go to previous time step"); 
-  Msg::Direct("  Right arrow   Go to next time step"); 
-  Msg::Direct("  Up arrow      Make previous view visible"); 
-  Msg::Direct("  Down arrow    Make next view visible"); 
-  Msg::Direct(" ");
-  Msg::Direct("  <             Go back to previous context");
-  Msg::Direct("  >             Go forward to next context");
-  Msg::Direct("  0             Reload project file");
-  Msg::Direct("  1 or F1       Mesh lines");
-  Msg::Direct("  2 or F2       Mesh surfaces");
-  Msg::Direct("  3 or F3       Mesh volumes");
-  Msg::Direct("  Escape        Cancel lasso zoom/selection, toggle mouse selection ON/OFF");
-  Msg::Direct(" ");
-  Msg::Direct("  g             Go to geometry module");
-  Msg::Direct("  m             Go to mesh module");
-  Msg::Direct("  p             Go to post-processing module");
-  Msg::Direct("  s             Go to solver module");
-  Msg::Direct(" ");
-  Msg::Direct("  Shift+a       Bring all windows to front");
-  Msg::Direct("  Shift+g       Show geometry options");
-  Msg::Direct("  Shift+m       Show mesh options");
-  Msg::Direct("  Shift+o       Show general options"); 
-  Msg::Direct("  Shift+p       Show post-processing options");
-  Msg::Direct("  Shift+s       Show solver options"); 
-  Msg::Direct("  Shift+u       Show post-processing view plugins");
-  Msg::Direct("  Shift+w       Show post-processing view options");
-  Msg::Direct("  Shift+Escape  Enable full mouse selection");
-  Msg::Direct(" ");
-  Msg::Direct("  " CC("i") "        Show statistics window"); 
-  Msg::Direct("  " CC("l") "        Show message console");
-#if defined(__APPLE__)
-  Msg::Direct("  " CC("m") "        Minimize window"); 
-#endif
-  Msg::Direct("  " CC("n") "        Create new project file"); 
-  Msg::Direct("  " CC("o") "        Open project file"); 
-  Msg::Direct("  " CC("q") "        Quit");
-  Msg::Direct("  " CC("r") "        Rename project file");
-  Msg::Direct("  " CC("s") "        Save file as");
-  Msg::Direct(" ");
-  Msg::Direct("  Shift+" CC("c") "  Show clipping plane window");
-  Msg::Direct("  Shift+" CC("m") "  Show manipulator window"); 
-  Msg::Direct("  Shift+" CC("n") "  Show option window"); 
-  Msg::Direct("  Shift+" CC("o") "  Merge file(s)"); 
-  Msg::Direct("  Shift+" CC("s") "  Save mesh in default format");
-  Msg::Direct("  Shift+" CC("u") "  Show plugin window");
-  Msg::Direct("  Shift+" CC("v") "  Show visibility window");
-  Msg::Direct(" ");
-  Msg::Direct("  Alt+a         Loop through axes modes"); 
-  Msg::Direct("  Alt+b         Hide/show bounding boxes");
-  Msg::Direct("  Alt+c         Loop through predefined color schemes");
-  Msg::Direct("  Alt+e         Hide/Show element outlines for visible post-processing views");
-  Msg::Direct("  Alt+f         Change redraw mode (fast/full)"); 
-  Msg::Direct("  Alt+h         Hide/show all post-processing views"); 
-  Msg::Direct("  Alt+i         Hide/show all post-processing view scales");
-  Msg::Direct("  Alt+l         Hide/show geometry lines");
-  Msg::Direct("  Alt+m         Toggle visibility of all mesh entities");
-  Msg::Direct("  Alt+n         Hide/show all post-processing view annotations");
-  Msg::Direct("  Alt+o         Change projection mode (orthographic/perspective)");
-  Msg::Direct("  Alt+p         Hide/show geometry points");
-  Msg::Direct("  Alt+r         Loop through range modes for visible post-processing views"); 
-  Msg::Direct("  Alt+s         Hide/show geometry surfaces");
-  Msg::Direct("  Alt+t         Loop through interval modes for visible post-processing views"); 
-  Msg::Direct("  Alt+v         Hide/show geometry volumes");
-  Msg::Direct("  Alt+w         Enable/disable all lighting");
-  Msg::Direct("  Alt+x         Set X view"); 
-  Msg::Direct("  Alt+y         Set Y view"); 
-  Msg::Direct("  Alt+z         Set Z view"); 
-  Msg::Direct(" ");
-  Msg::Direct("  Alt+Shift+a   Hide/show small axes"); 
-  Msg::Direct("  Alt+Shift+b   Hide/show mesh volume faces");
-  Msg::Direct("  Alt+Shift+d   Hide/show mesh surface faces");
-  Msg::Direct("  Alt+Shift+l   Hide/show mesh lines");
-  Msg::Direct("  Alt+Shift+o   Adjust projection parameters");
-  Msg::Direct("  Alt+Shift+p   Hide/show mesh points");
-  Msg::Direct("  Alt+Shift+s   Hide/show mesh surface edges");
-  Msg::Direct("  Alt+Shift+v   Hide/show mesh volume edges");
-  Msg::Direct("  Alt+Shift+w   Reverse all mesh normals");
-  Msg::Direct("  Alt+Shift+x   Set -X view"); 
-  Msg::Direct("  Alt+Shift+y   Set -Y view"); 
-  Msg::Direct("  Alt+Shift+z   Set -Z view"); 
-  Msg::Direct(" ");
-  GUI::instance()->messages->show();
-}
-
-void help_mouse_cb(CALLBACK_ARGS)
-{
-  Msg::Direct(" ");
-  Msg::Direct("Mouse actions:");
-  Msg::Direct(" ");
-  Msg::Direct("  Move                - Highlight the entity under the mouse pointer");
-  Msg::Direct("                        and display its properties in the status bar");
-  Msg::Direct("                      - Resize a lasso zoom or a lasso (un)selection");
-  Msg::Direct("  Left button         - Rotate");
-  Msg::Direct("                      - Select an entity");
-  Msg::Direct("                      - Accept a lasso zoom or a lasso selection"); 
-  Msg::Direct("  Ctrl+Left button    Start a lasso zoom or a lasso (un)selection"); 
-  Msg::Direct("  Middle button       - Zoom");
-  Msg::Direct("                      - Unselect an entity");
-  Msg::Direct("                      - Accept a lasso zoom or a lasso unselection");
-  Msg::Direct("  Ctrl+Middle button  Orthogonalize display"); 
-  Msg::Direct("  Right button        - Pan");
-  Msg::Direct("                      - Cancel a lasso zoom or a lasso (un)selection");
-  Msg::Direct("                      - Pop-up menu on post-processing view button");
-  Msg::Direct("  Ctrl+Right button   Reset to default viewpoint");   
-  Msg::Direct(" ");   
-  Msg::Direct("  For a 2 button mouse, Middle button = Shift+Left button");
-  Msg::Direct("  For a 1 button mouse, Middle button = Shift+Left button, Right button = Alt+Left button");
-  Msg::Direct(" ");
-  GUI::instance()->messages->show();
-}
-
-void help_command_line_cb(CALLBACK_ARGS)
-{
-  Msg::Direct(" ");
-  Print_Usage("gmsh");
-  GUI::instance()->messages->show();
-}
-
-void _replace_multi_format(const char *in, const char *val, char *out)
-{
-  unsigned int i = 0, j = 0;
-
-  out[0] = '\0';
-  while(i < strlen(in)){
-    if(in[i] == '%' && i != strlen(in) - 1){
-      if(in[i + 1] == 's'){
-        strcat(out, val);
-        i += 2;
-        j += strlen(val);
-      }
-      else{
-        Msg::Warning("Skipping unknown format '%%%c' in '%s'", in[i + 1], in);
-        i += 2;
-      }
-    }
-    else{
-      out[j] = in[i];
-      out[j + 1] = '\0';
-      i++;
-      j++;
-    }
-  }
-  out[j] = '\0';
-}
-
-void help_online_cb(CALLBACK_ARGS)
-{
-  std::string prog = FixWindowsPath(CTX.web_browser);
-  char cmd[1024];
-  _replace_multi_format(prog.c_str(), "http://geuz.org/gmsh/doc/texinfo/", cmd);
-  SystemCall(cmd);
-}
-
-void help_license_cb(CALLBACK_ARGS)
-{
-  std::string prog = FixWindowsPath(CTX.web_browser);
-  char cmd[1024];
-  _replace_multi_format(prog.c_str(), "http://geuz.org/gmsh/doc/LICENSE.txt", cmd);
-  SystemCall(cmd);
-}
-
-void help_credits_cb(CALLBACK_ARGS)
-{
-  std::string prog = FixWindowsPath(CTX.web_browser);
-  char cmd[1024];
-  _replace_multi_format(prog.c_str(), "http://geuz.org/gmsh/doc/CREDITS.txt", cmd);
-  SystemCall(cmd);
-}
-
-void help_about_cb(CALLBACK_ARGS)
-{
-  GUI::instance()->about->win->show();
-}
-
-// Module Menu
-
-void mod_geometry_cb(CALLBACK_ARGS)
-{
-  GUI::instance()->menu->setContext(menu_geometry, 0);
-}
-
-void mod_mesh_cb(CALLBACK_ARGS)
-{
-  GUI::instance()->menu->setContext(menu_mesh, 0);
-}
-
-void mod_solver_cb(CALLBACK_ARGS)
-{
-  GUI::instance()->menu->setContext(menu_solver, 0);
-}
-
-void mod_post_cb(CALLBACK_ARGS)
-{
-  GUI::instance()->menu->setContext(menu_post, 0);
-}
-
-void mod_back_cb(CALLBACK_ARGS)
-{
-  GUI::instance()->menu->setContext(NULL, -1);
-}
-
-void mod_forward_cb(CALLBACK_ARGS)
-{
-  GUI::instance()->menu->setContext(NULL, 1);
-}
-
-// Dynamic Geomtry Menus
-
-void geometry_elementary_cb(CALLBACK_ARGS)
-{
-  GUI::instance()->menu->setContext(menu_geometry_elementary, 0);
-}
-
-void geometry_physical_cb(CALLBACK_ARGS)
-{
-  GUI::instance()->menu->setContext(menu_geometry_physical, 0);
-}
-
-void geometry_edit_cb(CALLBACK_ARGS)
-{
-  std::string prog = FixWindowsPath(CTX.editor);
-  std::string file = FixWindowsPath(CTX.filename);
-  char cmd[1024];
-  _replace_multi_format(prog.c_str(), file.c_str(), cmd);
-  SystemCall(cmd);
-}
-
-void geometry_reload_cb(CALLBACK_ARGS)
-{
-  OpenProject(CTX.filename);
-  Draw();
-}
-
-void geometry_elementary_add_cb(CALLBACK_ARGS)
-{
-  GUI::instance()->menu->setContext(menu_geometry_elementary_add, 0);
-}
-
-static void _add_new_point()
-{
-  opt_geometry_points(0, GMSH_SET | GMSH_GUI, 1);
-  Draw();
-
-  GUI::instance()->geoContext->show(1);
-
-  while(1) {
-    GUI::instance()->graph[0]->gl->addPointMode = true;
-    Msg::StatusBar(3, false, "Move mouse and/or enter coordinates\n"
-        "[Press 'Shift' to hold position, 'e' to add point or 'q' to abort]");
-    std::vector<GVertex*> vertices;
-    std::vector<GEdge*> edges;
-    std::vector<GFace*> faces;
-    std::vector<GRegion*> regions;
-    std::vector<MElement*> elements;
-    char ib = SelectEntity(ENT_NONE, vertices, edges, faces, regions, elements);
-    if(ib == 'e'){
-      add_point(CTX.filename,
-                GUI::instance()->geoContext->input[2]->value(),
-                GUI::instance()->geoContext->input[3]->value(),
-                GUI::instance()->geoContext->input[4]->value(),
-                GUI::instance()->geoContext->input[5]->value());
-      GUI::instance()->resetVisibility();
-      Draw();
-    }
-    if(ib == 'q'){
-      GUI::instance()->graph[0]->gl->addPointMode = false;
-      break;
-    }
-  }
-
-  Msg::StatusBar(3, false, "");
-}
-
-static void _add_new_multiline(std::string type)
-{
-  std::vector<GVertex*> vertices;
-  std::vector<GEdge*> edges;
-  std::vector<GFace*> faces;
-  std::vector<GRegion*> regions;
-  std::vector<MElement*> elements;
-  std::vector<int> p;
-
-  opt_geometry_points(0, GMSH_SET | GMSH_GUI, 1);
-  opt_geometry_lines(0, GMSH_SET | GMSH_GUI, 1);
-  Draw();
-
-  while(1) {
-    if(p.empty())
-      Msg::StatusBar(3, false, "Select control points\n"
-          "[Press 'e' to end selection or 'q' to abort]");
-    else
-      Msg::StatusBar(3, false, "Select control points\n"
-          "[Press 'e' to end selection, 'u' to undo last selection or 'q' to abort]");
-    char ib = SelectEntity(ENT_POINT, vertices, edges, faces, regions, elements);
-    if(ib == 'l') {
-      for(unsigned int i = 0; i < vertices.size(); i++){
-        HighlightEntity(vertices[i]);
-        p.push_back(vertices[i]->tag());
-      }
-      Draw();
-    }
-    if(ib == 'r') {
-      Msg::Warning("Entity de-selection not supported yet during multi-line creation");
-    }
-    if(ib == 'e') {
-      if(p.size() >= 2)
-	add_multline(type, p, CTX.filename);
-      GUI::instance()->resetVisibility();
-      ZeroHighlight();
-      Draw();
-      p.clear();
-    }
-    if(ib == 'u') {
-      if(p.size()){
-        ZeroHighlightEntityNum(p.back(), 0, 0, 0);
-        Draw();
-        p.pop_back();
-      }
-    }
-    if(ib == 'q') {
-      ZeroHighlight();
-      Draw();
-      break;
-    }
-  }
-
-  Msg::StatusBar(3, false, "");
-}
-
-static void _add_new_line()
-{
-  std::vector<GVertex*> vertices;
-  std::vector<GEdge*> edges;
-  std::vector<GFace*> faces;
-  std::vector<GRegion*> regions;
-  std::vector<MElement*> elements;
-  std::vector<int> p;
-
-  opt_geometry_points(0, GMSH_SET | GMSH_GUI, 1);
-  opt_geometry_lines(0, GMSH_SET | GMSH_GUI, 1);
-  Draw();
-
-  while(1) {
-    if(p.empty())
-      Msg::StatusBar(3, false, "Select start point\n"
-          "[Press 'q' to abort]");
-    if(p.size() == 1)
-      Msg::StatusBar(3, false, "Select end point\n"
-          "[Press 'u' to undo last selection or 'q' to abort]");
-    char ib = SelectEntity(ENT_POINT, vertices, edges, faces, regions, elements);
-    if(ib == 'l') {
-      HighlightEntity(vertices[0]);
-      Draw();
-      p.push_back(vertices[0]->tag());
-    }
-    if(ib == 'r') {
-      Msg::Warning("Entity de-selection not supported yet during line creation");
-    }
-    if(ib == 'u') {
-      if(p.size()){
-        ZeroHighlightEntityNum(p.back(), 0, 0, 0);
-        Draw();
-        p.pop_back();
-      }
-    }
-    if(ib == 'q') {
-      ZeroHighlight();
-      Draw();
-      break;
-    }
-    if(p.size() == 2) {
-      add_multline("Line", p, CTX.filename);
-      GUI::instance()->resetVisibility();
-      ZeroHighlight();
-      Draw();
-      p.clear();
-    }
-  }
-
-  Msg::StatusBar(3, false, "");
-}
-
-static void _add_new_circle()
-{
-  std::vector<GVertex*> vertices;
-  std::vector<GEdge*> edges;
-  std::vector<GFace*> faces;
-  std::vector<GRegion*> regions;
-  std::vector<MElement*> elements;
-  std::vector<int> p;
-
-  opt_geometry_points(0, GMSH_SET | GMSH_GUI, 1);
-  opt_geometry_lines(0, GMSH_SET | GMSH_GUI, 1);
-  Draw();
-
-  while(1) {
-    if(p.empty())
-      Msg::StatusBar(3, false, "Select start point\n"
-          "[Press 'q' to abort]");
-    if(p.size() == 1)
-      Msg::StatusBar(3, false, "Select center point\n"
-          "[Press 'u' to undo last selection or 'q' to abort]");
-    if(p.size() == 2)
-      Msg::StatusBar(3, false, "Select end point\n"
-          "[Press 'u' to undo last selection or 'q' to abort]");
-    char ib = SelectEntity(ENT_POINT, vertices, edges, faces, regions, elements);
-    if(ib == 'l') {
-      HighlightEntity(vertices[0]);
-      Draw();
-      p.push_back(vertices[0]->tag());
-    }
-    if(ib == 'r') {
-      Msg::Warning("Entity de-selection not supported yet during circle creation");
-    }
-    if(ib == 'u') {
-      if(p.size()){
-        ZeroHighlightEntityNum(p.back(), 0, 0, 0);
-        Draw();
-        p.pop_back();
-      }
-    }
-    if(ib == 'q') {
-      ZeroHighlight();
-      Draw();
-      break;
-    }
-    if(p.size() == 3) {
-      add_circ(p[0], p[1], p[2], CTX.filename); // begin, center, end
-      GUI::instance()->resetVisibility();
-      ZeroHighlight();
-      Draw();
-      p.clear();
-    }
-  }
-
-  Msg::StatusBar(3, false, "");
-}
-
-static void _add_new_ellipse()
-{
-  std::vector<GVertex*> vertices;
-  std::vector<GEdge*> edges;
-  std::vector<GFace*> faces;
-  std::vector<GRegion*> regions;
-  std::vector<MElement*> elements;
-  std::vector<int> p;
-
-  opt_geometry_points(0, GMSH_SET | GMSH_GUI, 1);
-  opt_geometry_lines(0, GMSH_SET | GMSH_GUI, 1);
-  Draw();
-
-  while(1) {
-    if(p.empty())
-      Msg::StatusBar(3, false, "Select start point\n"
-          "[Press 'q' to abort]");
-    if(p.size() == 1)
-      Msg::StatusBar(3, false, "Select center point\n"
-          "[Press 'u' to undo last selection or 'q' to abort]");
-    if(p.size() == 2)
-      Msg::StatusBar(3, false, "Select major axis point\n"
-          "[Press 'u' to undo last selection or 'q' to abort]");
-    if(p.size() == 3)
-      Msg::StatusBar(3, false, "Select end point\n"
-          "[Press 'u' to undo last selection or 'q' to abort]");
-    char ib = SelectEntity(ENT_POINT, vertices, edges, faces, regions, elements);
-    if(ib == 'l') {
-      HighlightEntity(vertices[0]);
-      Draw();
-      p.push_back(vertices[0]->tag());
-    }
-    if(ib == 'r') {
-      Msg::Warning("Entity de-selection not supported yet during ellipse creation");
-    }
-    if(ib == 'u') {
-      if(p.size()){
-        ZeroHighlightEntityNum(p.back(), 0, 0, 0);
-        Draw();
-        p.pop_back();
-      }
-    }
-    if(ib == 'q') {
-      ZeroHighlight();
-      Draw();
-      break;
-    }
-    if(p.size() == 4) {
-      add_ell(p[0], p[1], p[2], p[3], CTX.filename);
-      GUI::instance()->resetVisibility();
-      ZeroHighlight();
-      Draw();
-      p.clear();
-    }
-  }
-
-  Msg::StatusBar(3, false, "");
-}
-
-static void _add_new_surface_volume(int mode)
-{
-  std::vector<GVertex*> vertices;
-  std::vector<GEdge*> edges;
-  std::vector<GFace*> faces;
-  std::vector<GRegion*> regions;
-  std::vector<MElement*> elements;
-  int type, num;
-
-  List_T *List1 = List_Create(10, 10, sizeof(int));
-  List_T *List2 = List_Create(10, 10, sizeof(int));
-
-  if(mode == 2) {
-    type = ENT_SURFACE;
-    opt_geometry_surfaces(0, GMSH_SET | GMSH_GUI, 1);
-    opt_geometry_volumes(0, GMSH_SET | GMSH_GUI, 1);
-  }
-  else {
-    type = ENT_LINE;
-    opt_geometry_lines(0, GMSH_SET | GMSH_GUI, 1);
-    opt_geometry_surfaces(0, GMSH_SET | GMSH_GUI, 1);
-  }
-  Draw();
-
-  while(1) {
-    List_Reset(List1);
-    List_Reset(List2);
-
-    while(1) {
-      if(type == ENT_LINE){
-        if(!List_Nbr(List1))
-          Msg::StatusBar(3, false, "Select surface boundary\n"
-              "[Press 'q' to abort]");
-        else
-          Msg::StatusBar(3, false, "Select surface boundary\n"
-              "[Press 'u' to undo last selection or 'q' to abort]");
-      }
-      else{
-        if(!List_Nbr(List1))
-          Msg::StatusBar(3, false, "Select volume boundary\n"
-              "[Press 'q' to abort]");
-        else
-          Msg::StatusBar(3, false, "Select volume boundary\n"
-              "[Press 'u' to undo last selection or 'q' to abort]");
-      }
-
-      char ib = SelectEntity(type, vertices, edges, faces, regions, elements);
-      if(ib == 'q') {
-        ZeroHighlight();
-        Draw();
-        goto stopall;
-      }
-      if(ib == 'u') {
-        if(List_Nbr(List1) > 0){
-          List_Read(List1, List_Nbr(List1)-1, &num);
-          ZeroHighlightEntityNum(0,
-                                 (type == ENT_LINE) ? abs(num) : 0, 
-                                 (type != ENT_LINE) ? abs(num) : 0,
-                                 0);
-          List_Pop(List1);
-          Draw();
-        }
-      }
-      if(ib == 'r') {
-        Msg::Warning("Entity de-selection not supported yet during surface/volume creation");
-      }
-      if(ib == 'l') {
-        int num = (type == ENT_LINE) ? edges[0]->tag() : faces[0]->tag();
-        if(SelectContour(type, num, List1)) {
-          if(type == ENT_LINE)
-            add_lineloop(List1, CTX.filename, &num);
-          else
-            add_surfloop(List1, CTX.filename, &num);
-          List_Reset(List1);
-          List_Add(List2, &num);
-          while(1) {
-            if(!List_Nbr(List1))
-              Msg::StatusBar(3, false, "Select hole boundaries (if none, press 'e')\n"
-                  "[Press 'e' to end selection or 'q' to abort]");
-            else
-              Msg::StatusBar(3, false, "Select hole boundaries\n"
-                  "[Press 'e' to end selection, 'u' to undo last selection or 'q' to abort]");
-            ib = SelectEntity(type, vertices, edges, faces, regions, elements);
-            if(ib == 'q') {
-              ZeroHighlight();
-              Draw();
-              goto stopall;
-            }
-            if(ib == 'e') {
-              ZeroHighlight();
-              Draw();
-              List_Reset(List1);
-              break;
-            }
-            if(ib == 'u') {
-              if(List_Nbr(List1) > 0){
-                List_Read(List1, List_Nbr(List1)-1, &num);
-                ZeroHighlightEntityNum(0,
-                                       (type == ENT_LINE) ? abs(num) : 0, 
-                                       (type != ENT_LINE) ? abs(num) : 0,
-                                       0);
-                List_Pop(List1);
-                Draw();
-              }
-            }
-            if(ib == 'l') {
-              num = (type == ENT_LINE) ? edges[0]->tag() : faces[0]->tag();
-              if(SelectContour(type, num, List1)) {
-                if(type == ENT_LINE)
-                  add_lineloop(List1, CTX.filename, &num);
-                else
-                  add_surfloop(List1, CTX.filename, &num);
-                List_Reset(List1);
-                List_Add(List2, &num);
-              }
-            }
-            if(ib == 'r') {
-              Msg::Warning("Entity de-selection not supported yet during surface/volume creation");
-            }
-          }
-          if(List_Nbr(List2)) {
-            switch (mode) {
-            case 0: add_surf("Plane Surface", List2, CTX.filename); break;
-            case 1: add_surf("Ruled Surface", List2, CTX.filename); break;
-            case 2: add_vol(List2, CTX.filename); break;
-            }
-            GUI::instance()->resetVisibility();
-            ZeroHighlight();
-            Draw();
-            break;
-          }
-        } // if SelectContour
-      }
-    }
-  }
-
-stopall:;
-  List_Delete(List1);
-  List_Delete(List2);
-
-  Msg::StatusBar(3, false, "");
-}
-
-void geometry_elementary_add_new_cb(CALLBACK_ARGS)
-{
-  if(!data){
-    GUI::instance()->menu->setContext(menu_geometry_elementary_add_new, 0);
-    return;
-  }
-
-  std::string str((const char*)data);
-  if(str == "Parameter")
-    GUI::instance()->geoContext->show(0);
-  else if(str == "Point")
-    _add_new_point();
-  else if(str == "Line")
-    _add_new_line();
-  else if(str == "Spline")
-    _add_new_multiline(str);
-  else if(str == "BSpline")
-    _add_new_multiline(str);
-  else if(str == "Circle")
-    _add_new_circle();
-  else if(str == "Ellipse")
-    _add_new_ellipse();
-  else if(str == "Plane Surface")
-    _add_new_surface_volume(0);
-  else if(str == "Ruled Surface")
-    _add_new_surface_volume(1);
-  else if(str == "Volume")
-    _add_new_surface_volume(2);
-  else
-    Msg::Error("Unknown entity to create: %s", str.c_str());
-}
-
-static void _split_selection()
-{
-  opt_geometry_lines(0, GMSH_SET | GMSH_GUI, 1);
-  Draw();
-  Msg::StatusBar(3, false, "Select a line to split\n"
-          "[Press 'q' to abort]");
-  std::vector<GVertex*> vertices;
-  std::vector<GEdge*> edges;
-  std::vector<GFace*> faces;
-  std::vector<GRegion*> regions;
-  std::vector<MElement*> elements;
-  GEdge* edge_to_split = NULL;
-  while(1){
-    char ib = SelectEntity(2, vertices, edges, faces, regions, elements);
-    if(ib == 'q')
-      break;
-    if(!edges.empty()){
-      edge_to_split = edges[0];
-      HighlightEntity(edges[0]);
-      break;
-    }
-  }
-  Msg::StatusBar(3, false, "");
-  if(edges.empty())
-    return;
-  List_T *List1 = List_Create(5, 5, sizeof(int));
-  Msg::StatusBar(3, false, "Select break points\n"
-                 "[Press 'e' to end selection or 'q' to abort]");
-  opt_geometry_points(0, GMSH_SET | GMSH_GUI, 1);
-  Draw();
-  while(1){
-    char ib = SelectEntity(1, vertices, edges, faces, regions, elements);
-    if(ib == 'q')
-      break;
-    if(ib == 'e'){
-      split_edge(edge_to_split->tag(), List1, CTX.filename);
-      break;
-    }
-    if(!vertices.empty()){
-      for(unsigned int i = 0; i < vertices.size(); i++){
-        int tag = vertices[i]->tag();
-        int index = List_ISearchSeq(List1, &tag, fcmp_int); 
-        if(index < 0) List_Add(List1, &tag);
-        HighlightEntity(vertices[i]);
-      }
-    }
-  }
-  Msg::StatusBar(3, false, "");
-  GUI::instance()->resetVisibility();
-  ZeroHighlight();
-  Draw();
-}
-
-static void _action_point_line_surface_volume(int action, int mode, const char *what)
-{
-  std::vector<GVertex*> vertices;
-  std::vector<GEdge*> edges;
-  std::vector<GFace*> faces;
-  std::vector<GRegion*> regions;
-  std::vector<MElement*> elements;
-  int type;
-  const char *str;
-
-  if(!strcmp(what, "Point")) {
-    type = ENT_POINT;
-    str = "points";
-    opt_geometry_points(0, GMSH_SET | GMSH_GUI, 1);
-  }
-  else if(!strcmp(what, "Line")) {
-    type = ENT_LINE;
-    str = "lines";
-    opt_geometry_lines(0, GMSH_SET | GMSH_GUI, 1);
-  }
-  else if(!strcmp(what, "Surface")) {
-    type = ENT_SURFACE;
-    str = "surfaces";
-    opt_geometry_surfaces(0, GMSH_SET | GMSH_GUI, 1);
-  }
-  else if(!strcmp(what, "Volume")) {
-    type = ENT_VOLUME;
-    str = "volumes";
-    opt_geometry_volumes(0, GMSH_SET | GMSH_GUI, 1);
-  }
-  else{
-    Msg::Error("Unknown entity to select");
-    return;
-  }
-
-  if(action == 8){
-    GUI::instance()->meshContext->show(0);
-  }
-
-  Draw();
-    
-  List_T *List1 = List_Create(5, 5, sizeof(int));
-  while(1) {
-    if(!List_Nbr(List1))
-      Msg::StatusBar(3, false, "Select %s\n"
-          "[Press 'e' to end selection or 'q' to abort]", str);
-    else
-      Msg::StatusBar(3, false, "Select %s\n"
-          "[Press 'e' to end selection, 'u' to undo last selection or 'q' to abort]", str);
-
-    char ib = SelectEntity(type, vertices, edges, faces, regions, elements);
-    if(ib == 'l') {
-      // we don't use List_Insert in order to keep the original
-      // ordering (this is slower, but this way undo works as
-      // expected)
-      int tag;
-      switch (type) {
-      case ENT_POINT: 
-        for(unsigned int i = 0; i < vertices.size(); i++){
-          HighlightEntity(vertices[i]);
-          tag = vertices[i]->tag();
-          if(List_ISearchSeq(List1, &tag, fcmp_int) < 0)
-            List_Add(List1, &tag);
-        }
-        break;
-      case ENT_LINE:
-        for(unsigned int i = 0; i < edges.size(); i++){
-          HighlightEntity(edges[i]);
-          tag = edges[i]->tag();
-          if(List_ISearchSeq(List1, &tag, fcmp_int) < 0)
-            List_Add(List1, &tag);
-        }
-        break;
-      case ENT_SURFACE:
-        for(unsigned int i = 0; i < faces.size(); i++){
-          HighlightEntity(faces[i]);
-          tag = faces[i]->tag();
-          if(List_ISearchSeq(List1, &tag, fcmp_int) < 0)
-            List_Add(List1, &tag);
-        }
-        break;
-      case ENT_VOLUME:
-        for(unsigned int i = 0; i < regions.size(); i++){
-          HighlightEntity(regions[i]);
-          tag = regions[i]->tag();
-          if(List_ISearchSeq(List1, &tag, fcmp_int) < 0)
-            List_Add(List1, &tag);
-        }
-        break;
-      }
-      Draw();
-    }
-    if(ib == 'r') {
-      // we don't use List_Suppress in order to keep the original
-      // ordering (this is slower, but this way undo works as
-      // expected)
-      int index, tag;
-      switch (type) {
-      case ENT_POINT:
-        for(unsigned int i = 0; i < vertices.size(); i++){
-          tag = vertices[i]->tag();
-          index = List_ISearchSeq(List1, &tag, fcmp_int); 
-          if(index >= 0) List_PSuppress(List1, index);
-          ZeroHighlightEntityNum(tag, 0, 0, 0);
-        }
-        break;
-      case ENT_LINE:
-        for(unsigned int i = 0; i < edges.size(); i++){
-          tag = edges[i]->tag();
-          index = List_ISearchSeq(List1, &tag, fcmp_int); 
-          if(index >= 0) List_PSuppress(List1, index);
-          ZeroHighlightEntityNum(0, tag, 0, 0);
-        }
-        break;
-      case ENT_SURFACE:
-        for(unsigned int i = 0; i < faces.size(); i++){
-          tag = faces[i]->tag();
-          index = List_ISearchSeq(List1, &tag, fcmp_int); 
-          if(index >= 0) List_PSuppress(List1, index);
-          ZeroHighlightEntityNum(0, 0, tag, 0);
-        }
-        break;
-      case ENT_VOLUME:
-        for(unsigned int i = 0; i < regions.size(); i++){
-          tag = regions[i]->tag();
-          index = List_ISearchSeq(List1, &tag, fcmp_int); 
-          if(index >= 0) List_PSuppress(List1, index);
-          ZeroHighlightEntityNum(0, 0, 0, tag);
-        }
-        break;
-      }
-      Draw();
-    }
-    if(ib == 'u') {
-      if(List_Nbr(List1)) {
-        int num;
-        List_Read(List1, List_Nbr(List1) - 1, &num);
-        ZeroHighlightEntityNum((type == ENT_POINT) ? num : 0,
-                               (type == ENT_LINE) ? num : 0,
-                               (type == ENT_SURFACE) ? num : 0,
-                               (type == ENT_VOLUME) ? num : 0);
-        Draw();
-        List_Pop(List1);
-      }
-    }
-    if(ib == 'i') {
-      Msg::Error("Inverting selection!");
-    }
-    if(ib == 'e') {
-      if(List_Nbr(List1)){
-        switch (action) {
-        case 0:
-          translate(mode, List1, CTX.filename, what,
-                    GUI::instance()->geoContext->input[6]->value(),
-                    GUI::instance()->geoContext->input[7]->value(),
-                    GUI::instance()->geoContext->input[8]->value());
-          break;
-        case 1:
-          rotate(mode, List1, CTX.filename, what,
-                 GUI::instance()->geoContext->input[12]->value(),
-                 GUI::instance()->geoContext->input[13]->value(),
-                 GUI::instance()->geoContext->input[14]->value(),
-                 GUI::instance()->geoContext->input[9]->value(),
-                 GUI::instance()->geoContext->input[10]->value(),
-                 GUI::instance()->geoContext->input[11]->value(),
-                 GUI::instance()->geoContext->input[15]->value());
-          break;
-        case 2:
-          dilate(mode, List1, CTX.filename, what,
-                 GUI::instance()->geoContext->input[16]->value(),
-                 GUI::instance()->geoContext->input[17]->value(),
-                 GUI::instance()->geoContext->input[18]->value(),
-                 GUI::instance()->geoContext->input[19]->value());
-          break;
-        case 3:
-          symmetry(mode, List1, CTX.filename, what,
-                   GUI::instance()->geoContext->input[20]->value(),
-                   GUI::instance()->geoContext->input[21]->value(),
-                   GUI::instance()->geoContext->input[22]->value(),
-                   GUI::instance()->geoContext->input[23]->value());
-          break;
-        case 4:
-          extrude(List1, CTX.filename, what,
-                  GUI::instance()->geoContext->input[6]->value(),
-                  GUI::instance()->geoContext->input[7]->value(),
-                  GUI::instance()->geoContext->input[8]->value());
-          break;
-        case 5:
-          protude(List1, CTX.filename, what,
-                  GUI::instance()->geoContext->input[12]->value(),
-                  GUI::instance()->geoContext->input[13]->value(),
-                  GUI::instance()->geoContext->input[14]->value(),
-                  GUI::instance()->geoContext->input[9]->value(),
-                  GUI::instance()->geoContext->input[10]->value(),
-                  GUI::instance()->geoContext->input[11]->value(),
-                  GUI::instance()->geoContext->input[15]->value());
-          break;
-        case 6:
-          delet(List1, CTX.filename, what);
-          break;
-        case 7:
-          add_physical(what, List1, CTX.filename);
-          break;
-        case 8:
-          add_charlength(List1, CTX.filename, GUI::instance()->meshContext->input[0]->value());
-          break;
-        case 9:
-          add_recosurf(List1, CTX.filename);
-          break;
-
-        default:
-          Msg::Error("Unknown action on selected entities");
-          break;
-        }
-        List_Reset(List1);
-        GUI::instance()->resetVisibility();
-        ZeroHighlight();
-        if(action <= 6) SetBoundingBox();
-        Draw();
-      }
-    }
-    if(ib == 'q') {
-      ZeroHighlight();
-      Draw();
-      break;
-    }
-  }
-  List_Delete(List1);
-
-  Msg::StatusBar(3, false, "");
-}
-  
-void geometry_elementary_add_translate_cb(CALLBACK_ARGS)
-{
-  if(!data){
-    GUI::instance()->menu->setContext(menu_geometry_elementary_add_translate, 0);
-    return;
-  }
-  GUI::instance()->geoContext->show(2);
-  _action_point_line_surface_volume(0, 1, (const char*)data);
-}
-
-void geometry_elementary_add_rotate_cb(CALLBACK_ARGS)
-{
-  if(!data){
-    GUI::instance()->menu->setContext(menu_geometry_elementary_add_rotate, 0);
-    return;
-  }
-  GUI::instance()->geoContext->show(3);
-  _action_point_line_surface_volume(1, 1, (const char*)data);
-}
-
-void geometry_elementary_add_scale_cb(CALLBACK_ARGS)
-{
-  if(!data){
-    GUI::instance()->menu->setContext(menu_geometry_elementary_add_scale, 0);
-    return;
-  }
-  GUI::instance()->geoContext->show(4);
-  _action_point_line_surface_volume(2, 1, (const char*)data);
-}
-
-void geometry_elementary_add_symmetry_cb(CALLBACK_ARGS)
-{
-  if(!data){
-    GUI::instance()->menu->setContext(menu_geometry_elementary_add_symmetry, 0);
-    return;
-  }
-  GUI::instance()->geoContext->show(5);
-  _action_point_line_surface_volume(3, 1, (const char*)data);
-}
-
-void geometry_elementary_translate_cb(CALLBACK_ARGS)
-{
-  if(!data){
-    GUI::instance()->menu->setContext(menu_geometry_elementary_translate, 0);
-    return;
-  }
-  GUI::instance()->geoContext->show(2);
-  _action_point_line_surface_volume(0, 0, (const char*)data);
-}
-
-void geometry_elementary_rotate_cb(CALLBACK_ARGS)
-{
-  if(!data){
-    GUI::instance()->menu->setContext(menu_geometry_elementary_rotate, 0);
-    return;
-  }
-  GUI::instance()->geoContext->show(3);
-  _action_point_line_surface_volume(1, 0, (const char*)data);
-}
-
-void geometry_elementary_scale_cb(CALLBACK_ARGS)
-{
-  if(!data){
-    GUI::instance()->menu->setContext(menu_geometry_elementary_scale, 0);
-    return;
-  }
-  GUI::instance()->geoContext->show(4);
-  _action_point_line_surface_volume(2, 0, (const char*)data);
-}
-
-void geometry_elementary_symmetry_cb(CALLBACK_ARGS)
-{
-  if(!data){
-    GUI::instance()->menu->setContext(menu_geometry_elementary_symmetry, 0);
-    return;
-  }
-  GUI::instance()->geoContext->show(5);
-  _action_point_line_surface_volume(3, 0, (const char*)data);
-}
-
-void geometry_elementary_extrude_cb(CALLBACK_ARGS)
-{
-  GUI::instance()->menu->setContext(menu_geometry_elementary_extrude, 0);
-}
-
-void geometry_elementary_extrude_translate_cb(CALLBACK_ARGS)
-{
-  if(!data){
-    GUI::instance()->menu->setContext(menu_geometry_elementary_extrude_translate, 0);
-    return;
-  }
-  GUI::instance()->geoContext->show(2);
-  _action_point_line_surface_volume(4, 0, (const char*)data);
-}
-
-void geometry_elementary_extrude_rotate_cb(CALLBACK_ARGS)
-{
-  if(!data){
-    GUI::instance()->menu->setContext(menu_geometry_elementary_extrude_rotate, 0);
-    return;
-  }
-  GUI::instance()->geoContext->show(3);
-  _action_point_line_surface_volume(5, 0, (const char*)data);
-}
-
-void geometry_elementary_delete_cb(CALLBACK_ARGS)
-{
-  if(!data){
-    GUI::instance()->menu->setContext(menu_geometry_elementary_delete, 0);
-    return;
-  }
-  _action_point_line_surface_volume(6, 0, (const char*)data);
-}
-
-void geometry_elementary_split_cb(CALLBACK_ARGS)
-{
-  if(!data){
-    GUI::instance()->menu->setContext(menu_geometry_elementary_split, 0);
-    return;
-  }
-  _split_selection();
-}
-
-void geometry_elementary_coherence_cb(CALLBACK_ARGS)
-{
-  coherence(CTX.filename);
-}
-
-void geometry_physical_add_cb(CALLBACK_ARGS)
-{
-  if(!data){
-    GUI::instance()->menu->setContext(menu_geometry_physical_add, 0);
-    return;
-  }
-  std::string str((const char*)data);
-  if(str == "Point")
-    GUI::instance()->callForSolverPlugin(0);
-  else if(str == "Line")
-    GUI::instance()->callForSolverPlugin(1);
-
-  _action_point_line_surface_volume(7, 0, str.c_str());
-}
-
-// Dynamic Mesh Menus
-
-void mesh_save_cb(CALLBACK_ARGS)
-{
-  char name[256];
-  if(CTX.output_filename)
-    strcpy(name, CTX.output_filename);
-  else
-    GetDefaultFileName(CTX.mesh.format, name);
-  if(CTX.confirm_overwrite) {
-    if(!StatFile(name))
-      if(!fl_choice("File '%s' already exists.\n\nDo you want to replace it?",
-                    "Cancel", "Replace", NULL, name))
-        return;
-  }
-  CreateOutputFile(name, CTX.mesh.format);
-}
-
-void mesh_define_cb(CALLBACK_ARGS)
-{
-  GUI::instance()->menu->setContext(menu_mesh_define, 0);
-}
-
-void mesh_1d_cb(CALLBACK_ARGS)
-{
-  GModel::current()->mesh(1);
-  Draw();
-  Msg::StatusBar(2, false, " ");
-}
-
-void mesh_2d_cb(CALLBACK_ARGS)
-{
-  GModel::current()->mesh(2);
-  Draw();
-  Msg::StatusBar(2, false, " ");
-}
-
-void mesh_3d_cb(CALLBACK_ARGS)
-{
-  GModel::current()->mesh(3);
-  Draw();
-  Msg::StatusBar(2, false, " ");
-}
-
-void mesh_delete_cb(CALLBACK_ARGS)
-{
-  GUI::instance()->menu->setContext(menu_mesh_delete, 0);
-}
-
-void mesh_delete_parts_cb(CALLBACK_ARGS)
-{
-  const char *str = (const char*)data;
-  int what;
-
-  if(!strcmp(str, "elements")){
-    CTX.pick_elements = 1;
-    what = ENT_ALL;
-  }
-  else if(!strcmp(str, "lines")){
-    CTX.pick_elements = 0;
-    what = ENT_LINE;
-  }
-  else if(!strcmp(str, "surfaces")){
-    CTX.pick_elements = 0;
-    what = ENT_SURFACE;
-  }
-  else if(!strcmp(str, "volumes")){
-    CTX.pick_elements = 0;
-    what = ENT_VOLUME;
-  }
-  else
-    return;
-
-  std::vector<GVertex*> vertices;
-  std::vector<GEdge*> edges;
-  std::vector<GFace*> faces;
-  std::vector<GRegion*> regions;
-  std::vector<MElement*> elements;
-
-  std::vector<MElement*> ele;
-  std::vector<GEntity*> ent;
-
-  while(1) {
-    CTX.mesh.changed = ENT_ALL;
-    Draw();
-
-    if(ele.size() || ent.size())
-      Msg::StatusBar(3, false, "Select %s\n"
-          "[Press 'e' to end selection, 'u' to undo last selection or 'q' to abort]", str);
-    else
-      Msg::StatusBar(3, false, "Select %s\n"
-          "[Press 'e' to end selection or 'q' to abort]", str);
-
-    char ib = SelectEntity(what, vertices, edges, faces, regions, elements);
-    if(ib == 'l') {
-      if(CTX.pick_elements){
-        for(unsigned int i = 0; i < elements.size(); i++){
-          if(elements[i]->getVisibility() != 2){
-            elements[i]->setVisibility(2); ele.push_back(elements[i]);
-          }
-        }
-      }
-      else{
-        for(unsigned int i = 0; i < edges.size(); i++){
-          if(edges[i]->getSelection() != 1){
-            edges[i]->setSelection(1); ent.push_back(edges[i]);
-          }
-        }
-        for(unsigned int i = 0; i < faces.size(); i++){
-          if(faces[i]->getSelection() != 1){
-            faces[i]->setSelection(1); ent.push_back(faces[i]);
-          }
-        }
-        for(unsigned int i = 0; i < regions.size(); i++){
-          if(regions[i]->getSelection() != 1){
-            regions[i]->setSelection(1); ent.push_back(regions[i]);
-          }
-        }
-      }
-    }
-    if(ib == 'r') {
-      if(CTX.pick_elements){
-        for(unsigned int i = 0; i < elements.size(); i++)
-          elements[i]->setVisibility(1);
-      }
-      else{
-        for(unsigned int i = 0; i < edges.size(); i++)
-          edges[i]->setSelection(0);
-        for(unsigned int i = 0; i < faces.size(); i++)
-          faces[i]->setSelection(0);
-        for(unsigned int i = 0; i < regions.size(); i++)
-          regions[i]->setSelection(0);
-      }
-    }
-    if(ib == 'u') {
-      if(CTX.pick_elements){
-        if(ele.size()){
-          ele[ele.size() - 1]->setVisibility(1);
-          ele.pop_back();
-        }
-      }
-      else{
-        if(ent.size()){
-          ent[ent.size() - 1]->setSelection(0);
-          ent.pop_back();
-        }
-      }
-    }
-    if(ib == 'e') {
-      if(CTX.pick_elements){
-        for(unsigned int i = 0; i < ele.size(); i++)
-          if(ele[i]->getVisibility() == 2) ele[i]->setVisibility(0);
-      }
-      else{
-        for(unsigned int i = 0; i < ent.size(); i++)
-          if(ent[i]->getSelection() == 1) ent[i]->setVisibility(0);
-      }
-      GModel::current()->removeInvisibleElements();
-      ele.clear();
-      ent.clear();
-    }
-    if(ib == 'q') {
-      ZeroHighlight();
-      break;
-    }
-  }
-
-  CTX.mesh.changed = ENT_ALL;
-  CTX.pick_elements = 0;
-  Draw();  
-  Msg::StatusBar(3, false, "");
-}
-
-void mesh_update_edges_cb(CALLBACK_ARGS)
-{
-  Msg::Error("Update edges not implemented yet");
-}
-
-void mesh_remesh_cb(CALLBACK_ARGS)
-{
-  Msg::Error("Remesh not implemented yet");
-}
-
-void mesh_inspect_cb(CALLBACK_ARGS)
-{
-  std::vector<GVertex*> vertices;
-  std::vector<GEdge*> edges;
-  std::vector<GFace*> faces;
-  std::vector<GRegion*> regions;
-  std::vector<MElement*> elements;
-
-  CTX.pick_elements = 1;
-  CTX.mesh.changed = ENT_ALL;
-  Draw();
-
-  while(1) {
-    Msg::StatusBar(3, false, "Select element\n[Press 'q' to abort]");
-    char ib = SelectEntity(ENT_ALL, vertices, edges, faces, regions, elements);
-    if(ib == 'l') {
-      if(elements.size()){
-        ZeroHighlight();
-        elements[0]->setVisibility(2);
-        Msg::Direct("Element %d:", elements[0]->getNum());
-	int type = elements[0]->getTypeForMSH();
-	const char *name;
-	MElement::getInfoMSH(type, &name);
-        Msg::Direct("  Type: %d ('%s')", type, name); 
-        Msg::Direct("  Dimension: %d", elements[0]->getDim());
-        Msg::Direct("  Order: %d", elements[0]->getPolynomialOrder()); 
-        Msg::Direct("  Partition: %d", elements[0]->getPartition()); 
-        char tmp1[32], tmp2[512];
-        sprintf(tmp2, "  Vertices:");
-        for(int i = 0; i < elements[0]->getNumVertices(); i++){
-          sprintf(tmp1, " %d", elements[0]->getVertex(i)->getNum());
-          strcat(tmp2, tmp1);
-        }
-        Msg::Direct(tmp2);
-        SPoint3 pt = elements[0]->barycenter();
-        Msg::Direct("  Barycenter: (%g,%g,%g)", pt[0], pt[1], pt[2]);
-        Msg::Direct("  Rho: %g", elements[0]->rhoShapeMeasure());
-        Msg::Direct("  Gamma: %g", elements[0]->gammaShapeMeasure());
-        Msg::Direct("  Eta: %g", elements[0]->etaShapeMeasure());
-        Msg::Direct("  Disto: %g", elements[0]->distoShapeMeasure());
-        CTX.mesh.changed = ENT_ALL;
-        Draw();
-        GUI::instance()->messages->show();
-      }
-    }
-    if(ib == 'q') {
-      ZeroHighlight();
-      break;
-    }
-  }
-
-  CTX.pick_elements = 0;
-  CTX.mesh.changed = ENT_ALL;
-  Draw();
-  Msg::StatusBar(3, false, "");
-}
-
-void mesh_degree_cb(CALLBACK_ARGS)
-{
-  if((long)data == 2)
-    SetOrderN(GModel::current(), 2, CTX.mesh.second_order_linear, 
-              CTX.mesh.second_order_incomplete);
-  else
-    SetOrder1(GModel::current());
-  CTX.mesh.changed |= (ENT_LINE | ENT_SURFACE | ENT_VOLUME);
-  Draw();
-  Msg::StatusBar(2, false, " ");
-}
-
-void mesh_optimize_cb(CALLBACK_ARGS)
-{
-  if(CTX.threads_lock) {
-    Msg::Info("I'm busy! Ask me that later...");
-    return;
-  }
-  CTX.threads_lock = 1;
-  OptimizeMesh(GModel::current());
-  CTX.threads_lock = 0;
-  CTX.mesh.changed |= (ENT_LINE | ENT_SURFACE | ENT_VOLUME);
-  Draw();
-  Msg::StatusBar(2, false, " ");
-}
-
-void mesh_refine_cb(CALLBACK_ARGS)
-{
-  RefineMesh(GModel::current(), CTX.mesh.second_order_linear);
-  CTX.mesh.changed |= (ENT_LINE | ENT_SURFACE | ENT_VOLUME);
-  Draw();
-  Msg::StatusBar(2, false, " ");
-}
-
-void mesh_optimize_netgen_cb(CALLBACK_ARGS)
-{
-  if(CTX.threads_lock) {
-    Msg::Info("I'm busy! Ask me that later...");
-    return;
-  }
-  CTX.threads_lock = 1;
-  OptimizeMeshNetgen(GModel::current());
-  CTX.threads_lock = 0;
-  CTX.mesh.changed |= (ENT_LINE | ENT_SURFACE | ENT_VOLUME);
-  Draw();
-  Msg::StatusBar(2, false, " ");
-}
-
-void mesh_partition_cb(CALLBACK_ARGS)
-{
-  partition_dialog();
-}
-
-void mesh_define_length_cb(CALLBACK_ARGS)
-{
-  _action_point_line_surface_volume(8, 0, "Point");
-}
-
-void mesh_define_recombine_cb(CALLBACK_ARGS)
-{
-  _action_point_line_surface_volume(9, 0, "Surface");
-}
-
-void mesh_define_transfinite_cb(CALLBACK_ARGS)
-{
-  GUI::instance()->menu->setContext(menu_mesh_define_transfinite, 0);
-}
-
-static void _add_transfinite(int dim)
-{
-  std::vector<GVertex*> vertices;
-  std::vector<GEdge*> edges;
-  std::vector<GFace*> faces;
-  std::vector<GRegion*> regions;
-  std::vector<MElement*> elements;
-  std::vector<int> p;
-  char ib;
-
-  opt_geometry_points(0, GMSH_SET | GMSH_GUI, 1);
-  switch (dim) {
-  case 1: opt_geometry_lines(0, GMSH_SET | GMSH_GUI, 1); break;
-  case 2: opt_geometry_surfaces(0, GMSH_SET | GMSH_GUI, 1); break;
-  case 3: opt_geometry_volumes(0, GMSH_SET | GMSH_GUI, 1); break;
-  }
-  Draw();
-
-  while(1) {
-    switch (dim) {
-    case 1:
-      if(p.empty())
-        Msg::StatusBar(3, false, "Select lines\n"
-            "[Press 'e' to end selection or 'q' to abort]");
-      else
-        Msg::StatusBar(3, false, "Select lines\n"
-            "[Press 'e' to end selection, 'u' to undo last selection or 'q' to abort]");
-      ib = SelectEntity(ENT_LINE, vertices, edges, faces, regions, elements);
-      break;
-    case 2:
-      Msg::StatusBar(3, false, "Select surface\n[Press 'q' to abort]");
-      ib = SelectEntity(ENT_SURFACE, vertices, edges, faces, regions, elements);
-      break;
-    case 3:
-      Msg::StatusBar(3, false, "Select volume\n[Press 'q' to abort]");
-      ib = SelectEntity(ENT_VOLUME, vertices, edges, faces, regions, elements);
-      break;
-    default:
-      ib = 'l';
-      break;
-    }
-
-    if(ib == 'e') {
-      if(dim == 1) {
-        if(p.size())
-          add_trsfline(p, CTX.filename,
-                       GUI::instance()->meshContext->choice[0]->text(),
-                       GUI::instance()->meshContext->input[2]->value(),
-                       GUI::instance()->meshContext->input[1]->value());
-      }
-      ZeroHighlight();
-      Draw();
-      p.clear();
-    }
-    if(ib == 'u') {
-      if(dim == 1) {
-        if(p.size()){
-          ZeroHighlightEntityNum(0, p.back(), 0, 0);
-          Draw();
-          p.pop_back();
-        }
-      }
-    }
-    if(ib == 'q') {
-      ZeroHighlight();
-      Draw();
-      break;
-    }
-    if(ib == 'r') {
-      Msg::Warning("Entity de-selection not supported yet during transfinite definition");
-    }
-    if(ib == 'l') {
-      switch (dim) {
-      case 1:
-        for(unsigned int i = 0; i < edges.size(); i++){
-          HighlightEntity(edges[i]);
-          p.push_back(edges[i]->tag());
-        }
-        Draw();
-        break;
-      case 2:
-      case 3:
-        if(dim == 2){
-          HighlightEntity(faces[0]);
-          Draw();
-          p.push_back(faces[0]->tag());
-        }
-        else{
-          HighlightEntity(regions[0]);
-          Draw();
-          p.push_back(regions[0]->tag());
-        }
-        while(1) {
-          if(p.size() == 1)
-            Msg::StatusBar(3, false, "Select (ordered) boundary points\n"
-                "[Press 'e' to end selection or 'q' to abort]");
-          else
-            Msg::StatusBar(3, false, "Select (ordered) boundary points\n"
-                "[Press 'e' to end selection, 'u' to undo last selection or 'q' to abort]");
-          ib = SelectEntity(ENT_POINT, vertices, edges, faces, regions, elements);
-          if(ib == 'l') {
-            HighlightEntity(vertices[0]);
-            Draw();
-            p.push_back(vertices[0]->tag());
-          }
-          if(ib == 'u') {
-            if(p.size() > 1){
-              ZeroHighlightEntityNum(p.back(), 0, 0, 0);
-              Draw();
-              p.pop_back();
-            }
-          }
-          if(ib == 'r') {
-            Msg::Warning("Entity de-selection not supported yet during transfinite definition");
-          }
-          if(ib == 'e') {
-            switch (dim) {
-            case 2:
-              if(p.size() == 0 + 1 || p.size() == 3 + 1 || p.size() == 4 + 1)
-                add_trsfsurf(p, CTX.filename,
-                             GUI::instance()->meshContext->choice[1]->text());
-              else
-                Msg::Error("Wrong number of points for transfinite surface");
-              break;
-            case 3:
-              if(p.size() == 6 + 1 || p.size() == 8 + 1)
-                add_trsfvol(p, CTX.filename);
-              else
-                Msg::Error("Wrong number of points for transfinite volume");
-              break;
-            }
-            ZeroHighlight();
-            Draw();
-            p.clear();
-            break;
-          }
-          if(ib == 'q') {
-            ZeroHighlight();
-            Draw();
-            goto stopall;
-          }
-        }
-        break;
-      }
-    }
-  }
-
-stopall:
-  Msg::StatusBar(3, false, "");
-}
-
-void mesh_define_transfinite_line_cb(CALLBACK_ARGS)
-{
-  GUI::instance()->meshContext->show(1);
-  _add_transfinite(1);
-}
-
-void mesh_define_transfinite_surface_cb(CALLBACK_ARGS)
-{
-  GUI::instance()->meshContext->show(2);
-  _add_transfinite(2);
-}
-
-void mesh_define_transfinite_volume_cb(CALLBACK_ARGS)
-{
-  _add_transfinite(3);
-}
-
-// Dynamic Solver Menus
-
-void solver_cb(CALLBACK_ARGS)
-{
-  static int init = 0, first[MAX_NUM_SOLVERS];
-  int num = (int)(long)data;
-
-  if(!init) {
-    for(int i = 0; i < MAX_NUM_SOLVERS; i++)
-      first[i] = 1;
-    init = 1;
-  }
-
-  if(first[num]) {
-    char file[256];
-    first[num] = 0;
-    strcpy(file, CTX.no_ext_filename);
-    strcat(file, SINFO[num].extension);
-    GUI::instance()->solver[num]->input[0]->value(file);
-  }
-  if(SINFO[num].nboptions) {
-    std::string file = FixWindowsPath(GUI::instance()->solver[num]->input[0]->value());
-    char tmp[256], tmp2[256];
-    sprintf(tmp, "\"%s\"", file.c_str());
-    sprintf(tmp2, SINFO[num].name_command, tmp);
-    sprintf(tmp, "%s %s", SINFO[num].option_command, tmp2);
-    Solver(num, tmp);
-  }
-  GUI::instance()->solver[num]->win->show();
-}
-
-void solver_file_open_cb(CALLBACK_ARGS)
-{
-  char tmp[256], tmp2[256];
-  int num = (int)(long)data;
-  sprintf(tmp, "*%s", SINFO[num].extension);
-
-  // We allow to create the .pro file... Or should we add a "New file"
-  // button?
-  if(file_chooser(0, 0, "Choose", tmp)) {
-    GUI::instance()->solver[num]->input[0]->value(file_chooser_get_name(1).c_str());
-    if(SINFO[num].nboptions) {
-      std::string file = FixWindowsPath(file_chooser_get_name(1).c_str());
-      sprintf(tmp, "\"%s\"", file.c_str());
-      sprintf(tmp2, SINFO[num].name_command, tmp);
-      sprintf(tmp, "%s %s", SINFO[num].option_command, tmp2);
-      Solver(num, tmp);
-    }
-  }
-}
-
-void solver_file_edit_cb(CALLBACK_ARGS)
-{
-  int num = (int)(long)data;
-  std::string prog = FixWindowsPath(CTX.editor);
-  std::string file = FixWindowsPath(GUI::instance()->solver[num]->input[0]->value());
-  char cmd[1024];
-  _replace_multi_format(prog.c_str(), file.c_str(), cmd);
-  SystemCall(cmd);
-}
-
-void solver_choose_mesh_cb(CALLBACK_ARGS)
-{
-  int num = (int)(long)data;
-  if(file_chooser(0, 0, "Choose", "*"))
-    GUI::instance()->solver[num]->input[1]->value(file_chooser_get_name(1).c_str());
-}
-
-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 tmp[256], mesh[256], arg[512], command[256];
-  int num = ((int *)data)[0];
-  int idx = ((int *)data)[1];
-  int i, usedopts = 0;
-
-  if(SINFO[num].popup_messages)
-    GUI::instance()->messages->show(true);
-
-  if(strlen(GUI::instance()->solver[num]->input[1]->value())) {
-    std::string m = FixWindowsPath(GUI::instance()->solver[num]->input[1]->value());
-    sprintf(tmp, "\"%s\"", m.c_str());
-    sprintf(mesh, SINFO[num].mesh_command, tmp);
-  }
-  else {
-    strcpy(mesh, "");
-  }
-
-  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::Error("Missing options to execute command");
-      return;
-    }
-    sprintf(command, SINFO[num].button_command[idx],
-            SINFO[num].option[usedopts][GUI::instance()->solver[num]->choice[usedopts]->value()]);
-  }
-  else {
-    strcpy(command, SINFO[num].button_command[idx]);
-  }
-
-  std::string c = FixWindowsPath(GUI::instance()->solver[num]->input[0]->value());
-  sprintf(arg, "\"%s\"", c.c_str());
-  sprintf(tmp, SINFO[num].name_command, arg);
-  sprintf(arg, "%s %s %s", tmp, mesh, command);
-  Solver(num, arg);
-}
-
-void solver_kill_cb(CALLBACK_ARGS)
-{
-  int num = (int)(long)data;
-  if(SINFO[num].pid > 0) {
-    if(KillProcess(SINFO[num].pid))
-      Msg::Info("Killed %s pid %d", SINFO[num].name, SINFO[num].pid);
-  }
-  SINFO[num].pid = -1;
-}
-
-void solver_choose_executable_cb(CALLBACK_ARGS)
-{
-  int num = (int)(long)data;
-  if(file_chooser(0, 0, "Choose",
-#if defined(WIN32)
-                  "*.exe"
-#else
-                  "*"
-#endif
-                  )){
-    GUI::instance()->solver[num]->input[2]->value(file_chooser_get_name(1).c_str());
-    solver_ok_cb(w, data);
-  }
-}
-
-void solver_ok_cb(CALLBACK_ARGS)
-{
-  int retry = 0, num = (int)(long)data;
-  opt_solver_popup_messages(num, GMSH_SET, GUI::instance()->solver[num]->butt[0]->value());
-  opt_solver_merge_views(num, GMSH_SET, GUI::instance()->solver[num]->butt[1]->value());
-  opt_solver_client_server(num, GMSH_SET, GUI::instance()->solver[num]->butt[2]->value());
-  if(strcmp(opt_solver_executable(num, GMSH_GET, NULL), GUI::instance()->solver[num]->input[2]->value()))
-    retry = 1;
-  opt_solver_executable(num, GMSH_SET, GUI::instance()->solver[num]->input[2]->value());
-  if(retry)
-    solver_cb(NULL, data);
-}
-
-// Dynamic Post Menus
-
-void view_toggle_cb(CALLBACK_ARGS)
-{
-  int num = (int)(long)data;
-  opt_view_visible(num, GMSH_SET,
-                   GUI::instance()->menu->toggle[num]->value());
-  Draw();
-}
-
-static void _view_reload(int index)
-{
-  if(index >= 0 && index < (int)PView::list.size()){
-    PView *p = PView::list[index];
-
-    if(StatFile(p->getData()->getFileName().c_str())){
-      Msg::Error("File '%s' does not exist", p->getData()->getFileName().c_str());
-      return;
-    }
-
-    int n = PView::list.size();
-
-    // FIXME: use fileIndex
-    MergeFile(p->getData()->getFileName().c_str());
-
-    if((int)PView::list.size() > n){ // we loaded a new view
-      // delete old data and replace with new
-      delete p->getData();
-      p->setData(PView::list.back()->getData());
-      PView::list.back()->setData(0);
-      // delete new view
-      delete PView::list.back();
-      // in case the reloaded view has a different number of time steps
-      if(p->getOptions()->TimeStep > p->getData()->getNumTimeSteps() - 1)
-        p->getOptions()->TimeStep = 0;
-      p->setChanged(true);
-      GUI::instance()->updateViews();
-    }
-  }
-}
-
-void view_reload_cb(CALLBACK_ARGS)
-{
-  _view_reload((int)(long)data);
-  Draw();
-}
-
-void view_reload_all_cb(CALLBACK_ARGS)
-{
-  for(unsigned int i = 0; i < PView::list.size(); i++)
-    _view_reload(i);
-  Draw();
-}
-
-void view_reload_visible_cb(CALLBACK_ARGS)
-{
-  for(unsigned int i = 0; i < PView::list.size(); i++)
-    if(opt_view_visible(i, GMSH_GET, 0))
-      _view_reload(i);
-  Draw();
-}
-
-void view_remove_other_cb(CALLBACK_ARGS)
-{
-  if(PView::list.empty()) return;
-  for(int i = PView::list.size() - 1; i >= 0; i--)
-    if(i != (long)data) delete PView::list[i];
-  GUI::instance()->updateViews();
-  Draw();
-}
-
-void view_remove_all_cb(CALLBACK_ARGS)
-{
-  if(PView::list.empty()) return;
-  while(PView::list.size()) delete PView::list[0];
-  GUI::instance()->updateViews();
-  Draw();
-}
-
-void view_remove_visible_cb(CALLBACK_ARGS)
-{
-  if(PView::list.empty()) return;
-  for(int i = PView::list.size() - 1; i >= 0; i--)
-    if(opt_view_visible(i, GMSH_GET, 0)) delete PView::list[i];
-  GUI::instance()->updateViews();
-  Draw();
-}
-
-void view_remove_invisible_cb(CALLBACK_ARGS)
-{
-  if(PView::list.empty()) return;
-  for(int i = PView::list.size() - 1; i >= 0; i--)
-    if(!opt_view_visible(i, GMSH_GET, 0)) delete PView::list[i];
-  GUI::instance()->updateViews();
-  Draw();
-}
-
-void view_remove_empty_cb(CALLBACK_ARGS)
-{
-  if(PView::list.empty()) return;
-  for(int i = PView::list.size() - 1; i >= 0; i--)
-    if(PView::list[i]->getData()->empty()) delete PView::list[i];
-  GUI::instance()->updateViews();
-  Draw();
-}
-
-void view_remove_cb(CALLBACK_ARGS)
-{
-  delete PView::list[(int)(long)data];
-  GUI::instance()->updateViews();
-  Draw();
-}
-
-static void _view_save_as(int index, const char *title, int format)
-{
-  PView *view = PView::list[index];
-  
- test:
-  if(file_chooser(0, 1, title, "*", view->getData()->getFileName().c_str())){
-    std::string name = file_chooser_get_name(1);
-    if(CTX.confirm_overwrite) {
-      if(!StatFile(name.c_str()))
-        if(!fl_choice("File '%s' already exists.\n\nDo you want to replace it?",
-                      "Cancel", "Replace", NULL, name.c_str()))
-          goto test;
-    }
-    view->write(name.c_str(), format);
-  }
-}
-
-void view_save_ascii_cb(CALLBACK_ARGS)
-{
-  _view_save_as((int)(long)data, "Save As ASCII View", 0);
-}
-
-void view_save_binary_cb(CALLBACK_ARGS)
-{
-  _view_save_as((int)(long)data, "Save As Binary View", 1);
-}
-
-void view_save_parsed_cb(CALLBACK_ARGS)
-{
-  _view_save_as((int)(long)data, "Save As Parsed View", 2);
-}
-
-void view_save_stl_cb(CALLBACK_ARGS)
-{
-  _view_save_as((int)(long)data, "Save As STL Triangulation", 3);
-}
-
-void view_save_txt_cb(CALLBACK_ARGS)
-{
-  _view_save_as((int)(long)data, "Save As Raw Text", 4);
-}
-
-void view_save_msh_cb(CALLBACK_ARGS)
-{
-  _view_save_as((int)(long)data, "Save As Gmsh Mesh", 5);
-}
-
-void view_save_med_cb(CALLBACK_ARGS)
-{
-  _view_save_as((int)(long)data, "Save As MED file", 6);
-}
-
-void view_alias_cb(CALLBACK_ARGS)
-{
-  new PView(PView::list[(int)(long)data], false);
-  GUI::instance()->updateViews();
-  Draw();
-}
-
-void view_alias_with_options_cb(CALLBACK_ARGS)
-{
-  new PView(PView::list[(int)(long)data], true);
-  GUI::instance()->updateViews();
-  Draw();
-}
-
-void view_combine_space_all_cb(CALLBACK_ARGS)
-{
-  PView::combine(false, 1, CTX.post.combine_remove_orig);
-  GUI::instance()->updateViews();
-  Draw();
-}
-
-void view_combine_space_visible_cb(CALLBACK_ARGS)
-{
-  PView::combine(false, 0, CTX.post.combine_remove_orig);
-  GUI::instance()->updateViews();
-  Draw();
-}
-
-void view_combine_space_by_name_cb(CALLBACK_ARGS)
-{
-  PView::combine(false, 2, CTX.post.combine_remove_orig);
-  GUI::instance()->updateViews();
-  Draw();
-}
-
-void view_combine_time_all_cb(CALLBACK_ARGS)
-{
-  PView::combine(true, 1, CTX.post.combine_remove_orig);
-  GUI::instance()->updateViews();
-  Draw();
-}
-
-void view_combine_time_visible_cb(CALLBACK_ARGS)
-{
-  PView::combine(true, 0, CTX.post.combine_remove_orig);
-  GUI::instance()->updateViews();
-  Draw();
-}
-
-void view_combine_time_by_name_cb(CALLBACK_ARGS)
-{
-  PView::combine(true, 2, CTX.post.combine_remove_orig);
-  GUI::instance()->updateViews();
-  Draw();
-}
-
-void view_all_visible_cb(CALLBACK_ARGS)
-{
-  for(unsigned int i = 0; i < PView::list.size(); i++)
-    opt_view_visible(i, GMSH_SET | GMSH_GUI, 
-                     (long)data < 0 ? !opt_view_visible(i, GMSH_GET, 0) :
-                     (long)data > 0 ? 1 : 0);
-  Draw();
-}
-
-void view_applybgmesh_cb(CALLBACK_ARGS)
-{
-  int index =  (int)(long)data;
-  if(index >= 0 && index < (int)PView::list.size()){
-    GModel::current()->getFields()->set_background_mesh(index);
-  }
-}
-
-void view_plugin_cb(CALLBACK_ARGS)
-{
-  GUI::instance()->plugins->show((int)(long)data);
-}
-
-void view_field_cb(CALLBACK_ARGS)
-{
-  GUI::instance()->fields->win->show();
-  GUI::instance()->fields->editField(NULL);
-}
-
-void view_field_delete_cb(CALLBACK_ARGS)
-{
-  Field *f = (Field*)GUI::instance()->fields->editor_group->user_data();
-  delete_field(f->id, CTX.filename);
-  GUI::instance()->fields->editField(NULL);
-}
-
-void view_field_new_cb(CALLBACK_ARGS)
-{
-  Fl_Menu_Button* mb = ((Fl_Menu_Button*)w);
-  FieldManager *fields = GModel::current()->getFields();
-  int id = fields->new_id();
-  add_field(id, mb->text(), CTX.filename);
-  GUI::instance()->fields->editField((*fields)[id]);
-}
-
-void view_field_apply_cb(CALLBACK_ARGS)
-{
-  GUI::instance()->fields->saveFieldOptions();
-}
-
-void view_field_revert_cb(CALLBACK_ARGS)
-{
-  GUI::instance()->fields->loadFieldOptions();
-}
-
-void view_field_browser_cb(CALLBACK_ARGS)
-{
-  int selected = GUI::instance()->fields->browser->value();
-  if(!selected){
-    GUI::instance()->fields->editField(NULL);
-  }
-  Field *f = (Field*)GUI::instance()->fields->browser->data(selected);
-  GUI::instance()->fields->editField(f);
-}
-
-void view_field_put_on_view_cb(CALLBACK_ARGS)
-{
-  Fl_Menu_Button* mb = ((Fl_Menu_Button*)w);
-  Field *field = (Field*)GUI::instance()->fields->editor_group->user_data();
-  int iView;
-  if(sscanf(mb->text(), "View [%i]", &iView)){
-    if(iView < (int)PView::list.size()){
-      field->put_on_view(PView::list[iView]);
-    }
-  }
-  else{
-    field->put_on_new_view();
-    GUI::instance()->updateViews();
-  }
-  Draw();
-}
-
-void view_field_select_file_cb(CALLBACK_ARGS)
-{
-  Fl_Input *input = (Fl_Input*)data;
-  int ret = file_chooser(0, 0, "File selection", "", input->value());
-  if(ret){
-    input->value(file_chooser_get_name(0).c_str());
-    input->set_changed();
-  }
-}
-
-void view_field_select_node_cb(CALLBACK_ARGS)
-{
-  const char *mode = "select";
-  const char *help = "vertices";
-  CTX.pick_elements = 1;
-  Draw();  
-  std::vector<GVertex*> vertices, vertices_old;
-  std::vector<GEdge*> edges, edges_old;
-  std::vector<GFace*> faces, faces_old;
-  std::vector<GRegion*> regions, regions_old;
-  std::vector<MElement*> elements, elements_old;
-  opt_geometry_points(0, GMSH_SET | GMSH_GUI, 1);
-  while(1) {
-    Msg::StatusBar(3, false, "Select %s\n[Press %s'q' to abort]", 
-        help, mode ? "" : "'u' to undo or ");
-    
-    char ib = SelectEntity(ENT_POINT, vertices, edges, faces, regions, elements);
-    printf("char = %c\n", ib);
-    if(ib == 'q'){
-      for(std::vector<GVertex*>::iterator it = vertices.begin(); it != vertices.end(); it++){
-	printf("%p\n", *it);
-      }
-      break;
-    }
-  }
-  CTX.mesh.changed = ENT_ALL;
-  CTX.pick_elements = 0;
-  Msg::StatusBar(3, false, "");
-  Draw();  
-}
-
-void view_plugin_input_value_cb(CALLBACK_ARGS)
-{
-  double (*f)(int, int, double) = (double (*)(int, int, double)) data;
-  Fl_Value_Input *input = (Fl_Value_Input*) w;
-  f(-1, 0, input->value());
-}
-
-void view_plugin_input_cb(CALLBACK_ARGS)
-{
-  const char* (*f)(int, int, const char*) = (const char* (*)(int, int, const char*)) data;
-  Fl_Input *input = (Fl_Input*) w;
-  f(-1, 0, input->value());
-}
-
-void view_plugin_browser_cb(CALLBACK_ARGS)
-{
-  // get selected plugin
-  GMSH_Plugin *p = 0;
-  for(int i = 1; i <= GUI::instance()->plugins->browser->size(); i++) {
-    if(GUI::instance()->plugins->browser->selected(i)) {
-      p = (GMSH_Plugin*)GUI::instance()->plugins->browser->data(i);
-      break;
-    }
-  }
-  if(!p) return;
-
-  // get first first selected view
-  int iView = -1;
-  for(int i = 1; i <= GUI::instance()->plugins->view_browser->size(); i++) {
-    if(GUI::instance()->plugins->view_browser->selected(i)) {
-      iView = i - 1;
-      break;
-    }
-  }
-
-  // set the Fl_Value_Input callbacks and configure the input value
-  // fields (we get step, min and max by calling the option function
-  // with action==1, 2 and 3, respectively)
-  int n = p->getNbOptions();
-  if(n > MAX_PLUGIN_OPTIONS) n = MAX_PLUGIN_OPTIONS;
-  for(int i = 0; i < n; i++) {
-    StringXNumber *sxn = p->getOption(i);
-    if(sxn->function){
-      p->dialogBox->value[i]->callback(view_plugin_input_value_cb, (void*)sxn->function);
-      if(iView >= 0){
-        p->dialogBox->value[i]->step(sxn->function(iView, 1, 0.));
-        p->dialogBox->value[i]->minimum(sxn->function(iView, 2, 0.));
-        p->dialogBox->value[i]->maximum(sxn->function(iView, 3, 0.));
-      }
-    }
-  }
-
-  // set the Fl_Input callbacks
-  int m = p->getNbOptionsStr();
-  if(m > MAX_PLUGIN_OPTIONS) m = MAX_PLUGIN_OPTIONS;
-  for(int i = 0; i < m; i++) {
-    StringXString *sxs = p->getOptionStr(i);
-    if(sxs->function){
-      p->dialogBox->input[i]->callback(view_plugin_input_cb, (void*)sxs->function);
-    }
-  }
-
-  // hide all plugin groups except the selected one
-  for(int i = 1; i <= GUI::instance()->plugins->browser->size(); i++)
-    ((GMSH_Plugin*)GUI::instance()->plugins->browser->data(i))->dialogBox->group->hide();
-  p->dialogBox->group->show();
-}
-
-void view_plugin_run_cb(CALLBACK_ARGS)
-{
-  // get selected plugin
-  GMSH_Post_Plugin *p = 0;
-  for(int i = 1; i <= GUI::instance()->plugins->browser->size(); i++) {
-    if(GUI::instance()->plugins->browser->selected(i)) {
-      p = (GMSH_Post_Plugin*)GUI::instance()->plugins->browser->data(i);
-      break;
-    }
-  }
-  if(!p) return;
-
-  if(p->dialogBox) { // get the values from the GUI
-    int m = p->getNbOptionsStr();
-    int n = p->getNbOptions();
-    if(m > MAX_PLUGIN_OPTIONS) m = MAX_PLUGIN_OPTIONS;
-    if(n > MAX_PLUGIN_OPTIONS) n = MAX_PLUGIN_OPTIONS;
-    for(int i = 0; i < m; i++) {
-      StringXString *sxs = p->getOptionStr(i);
-      sxs->def = p->dialogBox->input[i]->value();
-    }
-    for(int i = 0; i < n; i++) {
-      StringXNumber *sxn = p->getOption(i);
-      sxn->def = p->dialogBox->value[i]->value();
-    }
-  }
-
-  // run on all selected views
-  bool no_view_selected = true;
-  for(int i = 1; i <= GUI::instance()->plugins->view_browser->size(); i++) {
-    if(GUI::instance()->plugins->view_browser->selected(i)) {
-      no_view_selected = false;
-      try{
-        if(i - 1 >= 0 && i - 1 < (int)PView::list.size())
-          p->execute(PView::list[i - 1]);
-        else
-          p->execute(0);
-      }
-      catch(GMSH_Plugin * err) {
-        char tmp[256];
-        p->catchErrorMessage(tmp);
-        Msg::Warning("%s", tmp);
-      }
-    }
-  }
-  if(no_view_selected){
-    p->execute(0);
-  }
-
-  GUI::instance()->updateViews();
-  CTX.post.plugin_draw_function = NULL;
-  Draw();
-}
-
-void view_plugin_cancel_cb(CALLBACK_ARGS)
-{
-  GUI::instance()->plugins->win->hide();
-  CTX.post.plugin_draw_function = NULL;
-  Draw();
-}
-
-// Contextual windows for geometry
-
-void con_geometry_define_parameter_cb(CALLBACK_ARGS)
-{
-  add_param(GUI::instance()->geoContext->input[0]->value(),
-            GUI::instance()->geoContext->input[1]->value(), CTX.filename);
-  GUI::instance()->resetVisibility();
-}
-
-void con_geometry_define_point_cb(CALLBACK_ARGS)
-{
-  add_point(CTX.filename,
-            GUI::instance()->geoContext->input[2]->value(),
-            GUI::instance()->geoContext->input[3]->value(),
-            GUI::instance()->geoContext->input[4]->value(),
-            GUI::instance()->geoContext->input[5]->value());
-  GUI::instance()->resetVisibility();
-  ZeroHighlight();
-  SetBoundingBox();
-  Draw();
-}
-
-void con_geometry_snap_cb(CALLBACK_ARGS)
-{
-  CTX.geom.snap[0] = GUI::instance()->geoContext->value[0]->value();
-  CTX.geom.snap[1] = GUI::instance()->geoContext->value[1]->value();
-  CTX.geom.snap[2] = GUI::instance()->geoContext->value[2]->value();
-}
diff --git a/Fltk/Callbacks.h b/Fltk/Callbacks.h
deleted file mode 100644
index 4dcd312614..0000000000
--- a/Fltk/Callbacks.h
+++ /dev/null
@@ -1,258 +0,0 @@
-// Gmsh - Copyright (C) 1997-2008 C. Geuzaine, J.-F. Remacle
-//
-// See the LICENSE.txt file for license information. Please report all
-// bugs and problems to <gmsh@geuz.org>.
-
-#ifndef _CALLBACKS_H_
-#define _CALLBACKS_H_
-
-#include <FL/Fl_Widget.H>
-
-#define CALLBACK_ARGS   Fl_Widget* w, void* data
-
-void ManualPlay(int time, int step);
-
-// Common callbacks
-
-void cancel_cb(CALLBACK_ARGS);
-void color_cb(CALLBACK_ARGS);
-void view_color_cb(CALLBACK_ARGS);
-void redraw_cb(CALLBACK_ARGS);
-void window_cb(CALLBACK_ARGS);
-void activate_cb(CALLBACK_ARGS);
-
-// Graphical window
-
-void status_xyz1p_cb(CALLBACK_ARGS);
-void status_play_cb(CALLBACK_ARGS);
-void status_pause_cb(CALLBACK_ARGS);
-void status_rewind_cb(CALLBACK_ARGS);
-void status_stepbackward_cb(CALLBACK_ARGS);
-void status_stepforward_cb(CALLBACK_ARGS);
-
-// File Menu
-
-void file_new_cb(CALLBACK_ARGS);
-void file_open_cb(CALLBACK_ARGS);
-void file_merge_cb(CALLBACK_ARGS);
-void file_rename_cb(CALLBACK_ARGS);
-void file_save_as_cb(CALLBACK_ARGS);
-void file_save_as_auto_cb(CALLBACK_ARGS);
-void file_save_as_geo_cb(CALLBACK_ARGS);
-void file_save_as_geo_options_cb(CALLBACK_ARGS);
-void file_save_as_msh_cb(CALLBACK_ARGS);
-void file_save_as_msh_all_cb(CALLBACK_ARGS);
-void file_save_as_unv_cb(CALLBACK_ARGS);
-void file_save_as_gref_cb(CALLBACK_ARGS);
-void file_save_as_vrml_cb(CALLBACK_ARGS);
-void file_save_as_ps_simple_cb(CALLBACK_ARGS);
-void file_save_as_ps_accurate_cb(CALLBACK_ARGS);
-void file_save_as_epstex_simple_cb(CALLBACK_ARGS);
-void file_save_as_epstex_accurate_cb(CALLBACK_ARGS);
-void file_save_as_jpegtex_cb(CALLBACK_ARGS);
-void file_save_as_pngtex_cb(CALLBACK_ARGS);
-void file_save_as_tex_cb(CALLBACK_ARGS);
-void file_save_as_jpeg_cb(CALLBACK_ARGS);
-void file_save_as_png_cb(CALLBACK_ARGS);
-void file_save_as_gif_cb(CALLBACK_ARGS);
-void file_save_as_gif_dithered_cb(CALLBACK_ARGS);
-void file_save_as_gif_transparent_cb(CALLBACK_ARGS);
-void file_save_as_ppm_cb(CALLBACK_ARGS);
-void file_save_as_yuv_cb(CALLBACK_ARGS);
-void file_quit_cb(CALLBACK_ARGS);
-
-// Option Menu
-
-void options_cb(CALLBACK_ARGS);
-void options_browser_cb(CALLBACK_ARGS);
-void options_save_cb(CALLBACK_ARGS);
-void options_restore_defaults_cb(CALLBACK_ARGS);
-
-void general_options_cb(CALLBACK_ARGS);
-void general_options_ok_cb(CALLBACK_ARGS);
-void general_options_color_scheme_cb(CALLBACK_ARGS);
-void general_options_rotation_center_select_cb(CALLBACK_ARGS);
-void general_arrow_param_cb(CALLBACK_ARGS);
-
-void geometry_options_cb(CALLBACK_ARGS);
-void geometry_options_ok_cb(CALLBACK_ARGS);
-
-void mesh_options_cb(CALLBACK_ARGS);
-void mesh_options_ok_cb(CALLBACK_ARGS);
-
-void solver_options_cb(CALLBACK_ARGS);
-void solver_options_ok_cb(CALLBACK_ARGS);
-
-void post_options_cb(CALLBACK_ARGS);
-void post_options_ok_cb(CALLBACK_ARGS);
-
-void view_options_cb(CALLBACK_ARGS);
-void view_options_ok_cb(CALLBACK_ARGS);
-void view_options_timestep_cb(CALLBACK_ARGS);
-void view_options_timestep_decr_cb(CALLBACK_ARGS);
-void view_options_timestep_incr_cb(CALLBACK_ARGS);
-void view_arrow_param_cb(CALLBACK_ARGS);
-void view_toggle_cb(CALLBACK_ARGS);
-void view_reload_cb(CALLBACK_ARGS);
-void view_reload_all_cb(CALLBACK_ARGS);
-void view_reload_visible_cb(CALLBACK_ARGS);
-void view_remove_cb(CALLBACK_ARGS);
-void view_remove_other_cb(CALLBACK_ARGS);
-void view_remove_all_cb(CALLBACK_ARGS);
-void view_remove_visible_cb(CALLBACK_ARGS);
-void view_remove_invisible_cb(CALLBACK_ARGS);
-void view_remove_empty_cb(CALLBACK_ARGS);
-void view_save_ascii_cb(CALLBACK_ARGS);
-void view_save_binary_cb(CALLBACK_ARGS);
-void view_save_parsed_cb(CALLBACK_ARGS);
-void view_save_stl_cb(CALLBACK_ARGS);
-void view_save_txt_cb(CALLBACK_ARGS);
-void view_save_msh_cb(CALLBACK_ARGS);
-void view_save_med_cb(CALLBACK_ARGS);
-void view_alias_cb(CALLBACK_ARGS);
-void view_alias_with_options_cb(CALLBACK_ARGS);
-void view_combine_space_all_cb(CALLBACK_ARGS);
-void view_combine_space_visible_cb(CALLBACK_ARGS);
-void view_combine_space_by_name_cb(CALLBACK_ARGS);
-void view_combine_time_all_cb(CALLBACK_ARGS);
-void view_combine_time_visible_cb(CALLBACK_ARGS);
-void view_combine_time_by_name_cb(CALLBACK_ARGS);
-void view_all_visible_cb(CALLBACK_ARGS);
-void view_applybgmesh_cb(CALLBACK_ARGS);
-void view_field_cb(CALLBACK_ARGS);
-void view_field_new_cb(CALLBACK_ARGS);
-void view_field_apply_cb(CALLBACK_ARGS);
-void view_field_revert_cb(CALLBACK_ARGS);
-void view_field_browser_cb(CALLBACK_ARGS);
-void view_field_delete_cb(CALLBACK_ARGS);
-void view_field_select_file_cb(CALLBACK_ARGS);
-void view_field_put_on_view_cb(CALLBACK_ARGS);
-void view_field_select_node_cb(CALLBACK_ARGS);
-void view_plugin_cb(CALLBACK_ARGS);
-void view_plugin_browser_cb(CALLBACK_ARGS);
-void view_plugin_run_cb(CALLBACK_ARGS);
-void view_plugin_cancel_cb(CALLBACK_ARGS);
-
-// Statistics Menu
-
-void statistics_cb(CALLBACK_ARGS);
-void statistics_update_cb(CALLBACK_ARGS);
-void statistics_histogram_cb(CALLBACK_ARGS);
-
-// Message Menu
-
-void message_cb(CALLBACK_ARGS);
-void message_auto_scroll_cb(CALLBACK_ARGS);
-void message_copy_cb(CALLBACK_ARGS);
-void message_clear_cb(CALLBACK_ARGS);
-void message_save_cb(CALLBACK_ARGS);
-
-// Visibility Menu
-
-void visibility_cb(CALLBACK_ARGS);
-void visibility_sort_cb(CALLBACK_ARGS);
-void visibility_number_cb(CALLBACK_ARGS);
-void visibility_interactive_cb(CALLBACK_ARGS);
-void visibility_ok_cb(CALLBACK_ARGS);
-void visibility_save_cb(CALLBACK_ARGS);
-void visibility_delete_cb(CALLBACK_ARGS);
-
-// Clipping planes Menu
-
-void clip_cb(CALLBACK_ARGS);
-void clip_update_cb(CALLBACK_ARGS);
-void clip_invert_cb(CALLBACK_ARGS);
-void clip_num_cb(CALLBACK_ARGS);
-void clip_reset_cb(CALLBACK_ARGS);
-
-// Manipulator Menu
-
-void manip_cb(CALLBACK_ARGS);
-void manip_update_cb(CALLBACK_ARGS);
-
-// Help Menu
-
-void help_short_cb(CALLBACK_ARGS);
-void help_mouse_cb(CALLBACK_ARGS);
-void help_command_line_cb(CALLBACK_ARGS);
-void help_online_cb(CALLBACK_ARGS);
-void help_license_cb(CALLBACK_ARGS);
-void help_credits_cb(CALLBACK_ARGS);
-void help_about_cb(CALLBACK_ARGS);
-
-// Module Menu
-
-void mod_geometry_cb(CALLBACK_ARGS);
-void mod_mesh_cb(CALLBACK_ARGS);
-void mod_solver_cb(CALLBACK_ARGS);
-void mod_post_cb(CALLBACK_ARGS);
-void mod_back_cb(CALLBACK_ARGS);
-void mod_forward_cb(CALLBACK_ARGS);
-
-// Dynamic Geometry Menus
-
-void geometry_elementary_cb(CALLBACK_ARGS);
-void   geometry_elementary_add_cb(CALLBACK_ARGS);
-void     geometry_elementary_add_new_cb(CALLBACK_ARGS);
-void     geometry_elementary_add_translate_cb(CALLBACK_ARGS);
-void     geometry_elementary_add_rotate_cb(CALLBACK_ARGS);
-void     geometry_elementary_add_scale_cb(CALLBACK_ARGS);
-void     geometry_elementary_add_symmetry_cb(CALLBACK_ARGS);
-void   geometry_elementary_delete_cb(CALLBACK_ARGS);
-void geometry_elementary_split_cb(CALLBACK_ARGS);
-void   geometry_elementary_translate_cb(CALLBACK_ARGS);
-void   geometry_elementary_rotate_cb(CALLBACK_ARGS);
-void   geometry_elementary_scale_cb(CALLBACK_ARGS);
-void   geometry_elementary_symmetry_cb(CALLBACK_ARGS);
-void   geometry_elementary_extrude_cb(CALLBACK_ARGS);
-void     geometry_elementary_extrude_translate_cb(CALLBACK_ARGS);
-void     geometry_elementary_extrude_rotate_cb(CALLBACK_ARGS);
-void   geometry_elementary_coherence_cb(CALLBACK_ARGS);
-void geometry_physical_cb(CALLBACK_ARGS);
-void   geometry_physical_add_cb(CALLBACK_ARGS);
-void geometry_edit_cb(CALLBACK_ARGS);
-void geometry_reload_cb(CALLBACK_ARGS); 
-
-void con_geometry_define_parameter_cb(CALLBACK_ARGS);
-void con_geometry_define_point_cb(CALLBACK_ARGS);
-void con_geometry_snap_cb(CALLBACK_ARGS);
-
-// Dynamic Mesh Menus
-
-void mesh_save_cb(CALLBACK_ARGS);
-void mesh_define_cb(CALLBACK_ARGS);
-void mesh_1d_cb(CALLBACK_ARGS);
-void mesh_2d_cb(CALLBACK_ARGS); 
-void mesh_3d_cb(CALLBACK_ARGS); 
-void mesh_delete_cb(CALLBACK_ARGS);
-void mesh_delete_parts_cb(CALLBACK_ARGS);
-void mesh_inspect_cb(CALLBACK_ARGS);
-void mesh_remesh_cb(CALLBACK_ARGS); 
-void mesh_update_edges_cb(CALLBACK_ARGS); 
-void mesh_parameterize_cb(CALLBACK_ARGS);
-void mesh_degree_cb(CALLBACK_ARGS); 
-void mesh_refine_cb(CALLBACK_ARGS);
-void mesh_optimize_cb(CALLBACK_ARGS); 
-void mesh_optimize_netgen_cb(CALLBACK_ARGS); 
-void mesh_partition_cb(CALLBACK_ARGS);
-void mesh_classify_cb(CALLBACK_ARGS); 
-void mesh_define_length_cb (CALLBACK_ARGS);
-void mesh_define_recombine_cb (CALLBACK_ARGS);
-void mesh_define_transfinite_cb (CALLBACK_ARGS); 
-void mesh_define_transfinite_line_cb(CALLBACK_ARGS);
-void mesh_define_transfinite_surface_cb(CALLBACK_ARGS);
-void mesh_define_transfinite_volume_cb(CALLBACK_ARGS); 
-
-// Dynamic Solver Menus
-
-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);
-
-#endif
-
diff --git a/Fltk/GUI.cpp b/Fltk/GUI.cpp
index cf329f4093..f016763178 100644
--- a/Fltk/GUI.cpp
+++ b/Fltk/GUI.cpp
@@ -25,6 +25,7 @@
 #include "colorbarWindow.h"
 #include "popupButton.h"
 #include "fileDialogs.h"
+#include "Draw.h"
 #include "GmshDefines.h"
 #include "GmshMessage.h"
 #include "GModel.h"
@@ -33,7 +34,6 @@
 #include "Field.h"
 #include "Plugin.h"
 #include "PluginManager.h"
-#include "Callbacks.h"
 #include "OpenFile.h"
 #include "Options.h"
 #include "Context.h"
@@ -474,9 +474,7 @@ int GUI::testGlobalShortcuts(int event)
   }
   
   if(status == 2){
-    graph[0]->gl->make_current();
-    graph[0]->gl->redraw();
-    check();
+    Draw();
     return 1;
   }
   else if(status == 1)
@@ -488,19 +486,19 @@ int GUI::testGlobalShortcuts(int event)
 int GUI::testArrowShortcuts()
 {
   if(Fl::test_shortcut(FL_Left)) {
-    ManualPlay(1, -1);
+    status_play_manual(1, -1);
     return 1;
   }
   else if(Fl::test_shortcut(FL_Right)) {
-    ManualPlay(1, 1);
+    status_play_manual(1, 1);
     return 1;
   }
   else if(Fl::test_shortcut(FL_Up)) {
-    ManualPlay(0, -1);
+    status_play_manual(0, -1);
     return 1;
   }
   else if(Fl::test_shortcut(FL_Down)) {
-    ManualPlay(0, 1);
+    status_play_manual(0, 1);
     return 1;
   }
   return 0;
@@ -561,9 +559,7 @@ void GUI::setStatus(const char *msg, int num)
     else
       onscreen_buffer[1][0] = '\0';
     onscreen_buffer[0][i-1] = '\0';
-    graph[0]->gl->make_current();
-    graph[0]->gl->redraw();
-    check();
+    Draw();
   }
 }
 
@@ -609,6 +605,82 @@ void GUI::callForSolverPlugin(int dim)
   if(sp) sp->popupPropertiesForPhysicalEntity(dim);
 }
 
+// Callbacks
+
+void hide_cb(Fl_Widget *w, void *data)
+{
+  if(data) ((Fl_Widget *)data)->hide();
+}
+
+void redraw_cb(Fl_Widget *w, void *data)
+{
+  Draw();
+}
+
+void window_cb(Fl_Widget *w, void *data)
+{
+  static int oldx = 0, oldy = 0, oldw = 0, oldh = 0, zoom = 1;
+  const char *str = (const char*)data;
+
+  if(!strcmp(str, "minimize")){
+    GUI::instance()->graph[0]->win->iconize();
+    GUI::instance()->options->win->iconize();
+    GUI::instance()->plugins->win->iconize();
+    GUI::instance()->fields->win->iconize();
+    GUI::instance()->visibility->win->iconize();
+    GUI::instance()->clipping->win->iconize();
+    GUI::instance()->manip->win->iconize();
+    GUI::instance()->stats->win->iconize();
+    GUI::instance()->messages->win->iconize();
+    GUI::instance()->menu->win->iconize();
+  }
+  else if(!strcmp(str, "zoom")){
+    if(zoom){
+      oldx = GUI::instance()->graph[0]->win->x();
+      oldy = GUI::instance()->graph[0]->win->y();
+      oldw = GUI::instance()->graph[0]->win->w();
+      oldh = GUI::instance()->graph[0]->win->h();
+      GUI::instance()->graph[0]->win->resize(Fl::x(), Fl::y(), Fl::w(), Fl::h());
+      zoom = 0;
+    }
+    else{
+      GUI::instance()->graph[0]->win->resize(oldx, oldy, oldw, oldh);
+      zoom = 1;
+    }
+    GUI::instance()->graph[0]->win->show();
+    GUI::instance()->menu->win->show();
+  }
+  else if(!strcmp(str, "front")){
+    // the order is important!
+    GUI::instance()->graph[0]->win->show();
+    if(GUI::instance()->options->win->shown()) 
+      GUI::instance()->options->win->show();
+    if(GUI::instance()->plugins->win->shown())
+      GUI::instance()->plugins->win->show();
+    if(GUI::instance()->fields->win->shown())
+      GUI::instance()->fields->win->show();
+    if(GUI::instance()->geoContext->win->shown())
+      GUI::instance()->geoContext->win->show();
+    if(GUI::instance()->meshContext->win->shown())
+      GUI::instance()->meshContext->win->show();
+    for(unsigned int i = 0; i < GUI::instance()->solver.size(); i++) {
+      if(GUI::instance()->solver[i]->win->shown())
+        GUI::instance()->solver[i]->win->show();
+    }
+    if(GUI::instance()->visibility->win->shown())
+      GUI::instance()->visibility->win->show();
+    if(GUI::instance()->clipping->win->shown())
+      GUI::instance()->clipping->win->show();
+    if(GUI::instance()->manip->win->shown())
+      GUI::instance()->manip->win->show();
+    if(GUI::instance()->stats->win->shown())
+      GUI::instance()->stats->win->show();
+    if(GUI::instance()->messages->win->shown())
+      GUI::instance()->messages->win->show();
+    GUI::instance()->menu->win->show();
+  }
+}
+
 // Utility routines
 
 int GetFontIndex(const char *fontname)
diff --git a/Fltk/GUI.h b/Fltk/GUI.h
index 7cb7958dd7..5e67852a33 100644
--- a/Fltk/GUI.h
+++ b/Fltk/GUI.h
@@ -95,6 +95,11 @@ class GUI{
   void callForSolverPlugin(int dim);
 };
 
+// callbacks
+void hide_cb(Fl_Widget *w, void *data);
+void redraw_cb(Fl_Widget *w, void *data);
+void window_cb(Fl_Widget *w, void *data);
+
 // utility functions
 int GetFontIndex(const char *fontname);
 int GetFontEnum(int index);
diff --git a/Fltk/Makefile b/Fltk/Makefile
index 1d8dc146d2..a0bb89684d 100644
--- a/Fltk/Makefile
+++ b/Fltk/Makefile
@@ -36,7 +36,6 @@ SRC = Main.cpp \
         projectionEditor.cpp\
         classificationEditor.cpp\
         partitionDialog.cpp\
-      Callbacks.cpp\
       Draw.cpp\
       Solvers.cpp
 
@@ -89,7 +88,7 @@ GUI${OBJEXT}: GUI.cpp GUI.h graphicWindow.h openglWindow.h \
   colorbarWindow.h ../Post/ColorTable.h fieldWindow.h pluginWindow.h \
   statisticsWindow.h visibilityWindow.h clippingWindow.h messageWindow.h \
   manipWindow.h contextWindow.h solverWindow.h aboutWindow.h \
-  fileDialogs.h ../Common/GmshDefines.h ../Common/GmshMessage.h \
+  fileDialogs.h Draw.h ../Common/GmshDefines.h ../Common/GmshMessage.h \
   ../Geo/GModel.h ../Geo/GVertex.h ../Geo/GEntity.h ../Geo/Range.h \
   ../Geo/SPoint3.h ../Geo/SBoundingBox3d.h ../Geo/GPoint.h \
   ../Geo/SPoint2.h ../Geo/GEdge.h ../Geo/GEntity.h ../Geo/GVertex.h \
@@ -100,11 +99,13 @@ GUI${OBJEXT}: GUI.cpp GUI.h graphicWindow.h openglWindow.h \
   ../Geo/SBoundingBox3d.h ../Post/PView.h Solvers.h ../Mesh/Field.h \
   ../Plugin/Plugin.h ../Common/Options.h ../Post/PViewDataList.h \
   ../Post/PViewData.h ../Common/ListUtils.h ../Numeric/GmshMatrix.h \
-  ../Plugin/PluginManager.h Callbacks.h ../Common/OpenFile.h \
-  ../Common/Context.h ../Geo/CGNSOptions.h ../Mesh/PartitionOptions.h
-graphicWindow${OBJEXT}: graphicWindow.cpp graphicWindow.h openglWindow.h \
+  ../Plugin/PluginManager.h ../Common/OpenFile.h ../Common/Context.h \
+  ../Geo/CGNSOptions.h ../Mesh/PartitionOptions.h
+graphicWindow${OBJEXT}: graphicWindow.cpp GUI.h graphicWindow.h openglWindow.h \
   ../Graphics/drawContext.h ../Geo/SBoundingBox3d.h ../Geo/SPoint3.h \
-  shortcutWindow.h ../Post/PView.h ../Post/PViewData.h Callbacks.h \
+  shortcutWindow.h menuWindow.h popupButton.h messageWindow.h \
+  manipWindow.h extraDialogs.h Draw.h ../Post/PView.h ../Post/PViewData.h \
+  ../Common/OS.h ../Common/Options.h ../Post/ColorTable.h \
   ../Common/Context.h ../Geo/CGNSOptions.h ../Mesh/PartitionOptions.h
 openglWindow${OBJEXT}: openglWindow.cpp openglWindow.h ../Graphics/drawContext.h \
   ../Geo/SBoundingBox3d.h ../Geo/SPoint3.h graphicWindow.h manipWindow.h \
@@ -122,42 +123,80 @@ openglWindow${OBJEXT}: openglWindow.cpp openglWindow.h ../Graphics/drawContext.h
   ../Geo/MEdge.h ../Geo/MVertex.h ../Geo/SVector3.h ../Geo/MFace.h \
   ../Geo/MVertex.h ../Geo/SVector3.h ../Numeric/FunctionSpace.h \
   ../Numeric/GmshMatrix.h
-menuWindow${OBJEXT}: menuWindow.cpp GUI.h menuWindow.h popupButton.h \
-  shortcutWindow.h Callbacks.h ../Common/Options.h ../Post/ColorTable.h \
-  Solvers.h ../Common/GmshMessage.h ../Post/PView.h ../Geo/SPoint3.h \
-  ../Post/PViewData.h ../Geo/SBoundingBox3d.h ../Geo/SPoint3.h \
-  ../Post/PViewOptions.h ../Post/ColorTable.h ../Common/Context.h \
-  ../Geo/CGNSOptions.h ../Mesh/PartitionOptions.h
+menuWindow${OBJEXT}: menuWindow.cpp GUI.h Draw.h menuWindow.h popupButton.h \
+  shortcutWindow.h graphicWindow.h openglWindow.h \
+  ../Graphics/drawContext.h ../Geo/SBoundingBox3d.h ../Geo/SPoint3.h \
+  optionWindow.h spherePositionWidget.h colorbarWindow.h \
+  ../Post/ColorTable.h statisticsWindow.h messageWindow.h contextWindow.h \
+  visibilityWindow.h clippingWindow.h manipWindow.h fieldWindow.h \
+  pluginWindow.h solverWindow.h aboutWindow.h fileDialogs.h \
+  partitionDialog.h projectionEditor.h ../Geo/fourierProjectionFace.h \
+  ../Geo/GModel.h ../Geo/GVertex.h ../Geo/GEntity.h ../Geo/Range.h \
+  ../Geo/SPoint3.h ../Geo/SBoundingBox3d.h ../Geo/GPoint.h \
+  ../Geo/SPoint2.h ../Geo/GEdge.h ../Geo/GEntity.h ../Geo/GVertex.h \
+  ../Geo/SVector3.h ../Geo/SPoint3.h ../Geo/SPoint3.h ../Geo/SPoint2.h \
+  ../Geo/GFace.h ../Geo/GEntity.h ../Geo/GPoint.h ../Geo/GEdgeLoop.h \
+  ../Geo/GEdge.h ../Geo/SPoint2.h ../Geo/SVector3.h ../Geo/Pair.h \
+  ../Geo/GRegion.h ../Geo/GEntity.h ../Geo/SPoint3.h \
+  ../Geo/SBoundingBox3d.h ../Geo/Range.h classificationEditor.h \
+  ../Geo/MElement.h ../Common/GmshDefines.h ../Geo/MVertex.h \
+  ../Geo/SPoint2.h ../Geo/SPoint3.h ../Geo/MEdge.h ../Geo/MVertex.h \
+  ../Geo/SVector3.h ../Geo/MFace.h ../Geo/MVertex.h ../Geo/SVector3.h \
+  ../Common/GmshMessage.h ../Numeric/FunctionSpace.h \
+  ../Numeric/GmshMatrix.h ../Common/Options.h Solvers.h \
+  ../Common/CommandLine.h ../Mesh/Generator.h ../Mesh/HighOrder.h \
+  ../Post/PView.h ../Post/PViewData.h ../Post/PViewOptions.h \
+  ../Post/ColorTable.h ../Mesh/Field.h ../Common/OS.h \
+  ../Common/StringUtils.h ../Graphics/SelectBuffer.h \
+  ../Graphics/drawContext.h ../Common/OpenFile.h ../Common/CreateFile.h \
+  ../Geo/findLinks.h ../Common/ListUtils.h ../Geo/GeoStringInterface.h \
+  ../Common/Context.h ../Geo/CGNSOptions.h ../Mesh/PartitionOptions.h
 optionWindow${OBJEXT}: optionWindow.cpp GUI.h optionWindow.h \
   spherePositionWidget.h colorbarWindow.h ../Post/ColorTable.h \
-  shortcutWindow.h ../Common/GmshMessage.h ../Common/Options.h \
-  Callbacks.h ../Post/PView.h ../Geo/SPoint3.h ../Post/PViewData.h \
-  ../Geo/SBoundingBox3d.h ../Geo/SPoint3.h ../Post/PViewOptions.h \
-  ../Post/ColorTable.h ../Common/Context.h ../Geo/CGNSOptions.h \
+  shortcutWindow.h menuWindow.h popupButton.h extraDialogs.h Draw.h \
+  ../Graphics/SelectBuffer.h ../Graphics/drawContext.h \
+  ../Geo/SBoundingBox3d.h ../Geo/SPoint3.h ../Geo/GVertex.h \
+  ../Geo/GEntity.h ../Geo/Range.h ../Geo/SPoint3.h \
+  ../Geo/SBoundingBox3d.h ../Geo/GPoint.h ../Geo/SPoint2.h ../Geo/GEdge.h \
+  ../Geo/GEntity.h ../Geo/GVertex.h ../Geo/SVector3.h ../Geo/SPoint3.h \
+  ../Geo/SPoint3.h ../Geo/SPoint2.h ../Geo/GFace.h ../Geo/GEntity.h \
+  ../Geo/GPoint.h ../Geo/GEdgeLoop.h ../Geo/GEdge.h ../Geo/SPoint2.h \
+  ../Geo/SVector3.h ../Geo/Pair.h ../Geo/GRegion.h ../Geo/GEntity.h \
+  ../Common/GmshDefines.h ../Common/GmshMessage.h ../Common/Options.h \
+  Solvers.h ../Geo/GModel.h ../Geo/GVertex.h ../Geo/GEdge.h \
+  ../Geo/GFace.h ../Geo/GRegion.h ../Geo/SPoint3.h \
+  ../Geo/SBoundingBox3d.h ../Geo/MElement.h ../Geo/MVertex.h \
+  ../Geo/SPoint2.h ../Geo/SPoint3.h ../Geo/MEdge.h ../Geo/MVertex.h \
+  ../Geo/SVector3.h ../Geo/MFace.h ../Geo/MVertex.h ../Geo/SVector3.h \
+  ../Numeric/FunctionSpace.h ../Numeric/GmshMatrix.h ../Post/PView.h \
+  ../Post/PViewData.h ../Post/PViewOptions.h ../Post/ColorTable.h \
+  ../Common/OS.h ../Common/Context.h ../Geo/CGNSOptions.h \
   ../Mesh/PartitionOptions.h
 colorbarWindow${OBJEXT}: colorbarWindow.cpp colorbarWindow.h \
   ../Post/ColorTable.h GUI.h ../Common/Context.h ../Geo/CGNSOptions.h \
   ../Mesh/PartitionOptions.h
-fieldWindow${OBJEXT}: fieldWindow.cpp GUI.h fieldWindow.h shortcutWindow.h \
-  ../Geo/GModel.h ../Geo/GVertex.h ../Geo/GEntity.h ../Geo/Range.h \
-  ../Geo/SPoint3.h ../Geo/SBoundingBox3d.h ../Geo/SPoint3.h \
-  ../Geo/GPoint.h ../Geo/SPoint2.h ../Geo/GEdge.h ../Geo/GEntity.h \
-  ../Geo/GVertex.h ../Geo/SVector3.h ../Geo/SPoint3.h ../Geo/SPoint3.h \
-  ../Geo/SPoint2.h ../Geo/GFace.h ../Geo/GEntity.h ../Geo/GPoint.h \
-  ../Geo/GEdgeLoop.h ../Geo/GEdge.h ../Geo/SPoint2.h ../Geo/SVector3.h \
-  ../Geo/Pair.h ../Geo/GRegion.h ../Geo/GEntity.h ../Geo/SPoint3.h \
-  ../Geo/SBoundingBox3d.h ../Post/PView.h Callbacks.h \
-  ../Common/GmshMessage.h ../Mesh/Field.h ../Geo/GeoStringInterface.h \
-  ../Common/ListUtils.h ../Common/Context.h ../Geo/CGNSOptions.h \
-  ../Mesh/PartitionOptions.h
-pluginWindow${OBJEXT}: pluginWindow.cpp GUI.h pluginWindow.h shortcutWindow.h \
-  ../Post/PView.h ../Geo/SPoint3.h ../Plugin/PluginManager.h \
-  ../Plugin/Plugin.h ../Common/Options.h ../Post/ColorTable.h \
-  ../Common/GmshMessage.h ../Post/PViewDataList.h ../Post/PViewData.h \
-  ../Geo/SBoundingBox3d.h ../Geo/SPoint3.h ../Common/ListUtils.h \
-  ../Numeric/GmshMatrix.h Callbacks.h ../Common/Context.h \
+fieldWindow${OBJEXT}: fieldWindow.cpp GUI.h Draw.h fieldWindow.h \
+  shortcutWindow.h fileDialogs.h ../Common/GmshDefines.h ../Geo/GModel.h \
+  ../Geo/GVertex.h ../Geo/GEntity.h ../Geo/Range.h ../Geo/SPoint3.h \
+  ../Geo/SBoundingBox3d.h ../Geo/SPoint3.h ../Geo/GPoint.h \
+  ../Geo/SPoint2.h ../Geo/GEdge.h ../Geo/GEntity.h ../Geo/GVertex.h \
+  ../Geo/SVector3.h ../Geo/SPoint3.h ../Geo/SPoint3.h ../Geo/SPoint2.h \
+  ../Geo/GFace.h ../Geo/GEntity.h ../Geo/GPoint.h ../Geo/GEdgeLoop.h \
+  ../Geo/GEdge.h ../Geo/SPoint2.h ../Geo/SVector3.h ../Geo/Pair.h \
+  ../Geo/GRegion.h ../Geo/GEntity.h ../Geo/SPoint3.h \
+  ../Geo/SBoundingBox3d.h ../Post/PView.h ../Common/GmshMessage.h \
+  ../Mesh/Field.h ../Geo/GeoStringInterface.h ../Common/ListUtils.h \
+  ../Graphics/SelectBuffer.h ../Graphics/drawContext.h \
+  ../Common/Options.h ../Post/ColorTable.h ../Common/Context.h \
   ../Geo/CGNSOptions.h ../Mesh/PartitionOptions.h
-statisticsWindow${OBJEXT}: statisticsWindow.cpp GUI.h statisticsWindow.h \
+pluginWindow${OBJEXT}: pluginWindow.cpp GUI.h Draw.h pluginWindow.h \
+  shortcutWindow.h ../Post/PView.h ../Geo/SPoint3.h \
+  ../Plugin/PluginManager.h ../Plugin/Plugin.h ../Common/Options.h \
+  ../Post/ColorTable.h ../Common/GmshMessage.h ../Post/PViewDataList.h \
+  ../Post/PViewData.h ../Geo/SBoundingBox3d.h ../Geo/SPoint3.h \
+  ../Common/ListUtils.h ../Numeric/GmshMatrix.h ../Common/Context.h \
+  ../Geo/CGNSOptions.h ../Mesh/PartitionOptions.h
+statisticsWindow${OBJEXT}: statisticsWindow.cpp GUI.h Draw.h statisticsWindow.h \
   shortcutWindow.h ../Geo/GModel.h ../Geo/GVertex.h ../Geo/GEntity.h \
   ../Geo/Range.h ../Geo/SPoint3.h ../Geo/SBoundingBox3d.h \
   ../Geo/SPoint3.h ../Geo/GPoint.h ../Geo/SPoint2.h ../Geo/GEdge.h \
@@ -165,31 +204,64 @@ statisticsWindow${OBJEXT}: statisticsWindow.cpp GUI.h statisticsWindow.h \
   ../Geo/SPoint3.h ../Geo/SPoint2.h ../Geo/GFace.h ../Geo/GEntity.h \
   ../Geo/GPoint.h ../Geo/GEdgeLoop.h ../Geo/GEdge.h ../Geo/SPoint2.h \
   ../Geo/SVector3.h ../Geo/Pair.h ../Geo/GRegion.h ../Geo/GEntity.h \
-  ../Geo/SPoint3.h ../Geo/SBoundingBox3d.h ../Post/PView.h Callbacks.h \
-  ../Mesh/Generator.h ../Common/Context.h ../Geo/CGNSOptions.h \
-  ../Mesh/PartitionOptions.h
-visibilityWindow${OBJEXT}: visibilityWindow.cpp GUI.h visibilityWindow.h \
-  shortcutWindow.h Callbacks.h ../Common/Context.h ../Geo/CGNSOptions.h \
-  ../Mesh/PartitionOptions.h
-clippingWindow${OBJEXT}: clippingWindow.cpp GUI.h clippingWindow.h \
-  shortcutWindow.h ../Post/PView.h ../Geo/SPoint3.h \
-  ../Post/PViewOptions.h ../Post/ColorTable.h ../Geo/SBoundingBox3d.h \
-  ../Geo/SPoint3.h Callbacks.h ../Common/Context.h ../Geo/CGNSOptions.h \
+  ../Geo/SPoint3.h ../Geo/SBoundingBox3d.h ../Geo/MElement.h \
+  ../Common/GmshDefines.h ../Geo/MVertex.h ../Geo/SPoint2.h \
+  ../Geo/SPoint3.h ../Geo/MEdge.h ../Geo/MVertex.h ../Geo/SVector3.h \
+  ../Geo/MFace.h ../Geo/MVertex.h ../Geo/SVector3.h \
+  ../Common/GmshMessage.h ../Numeric/FunctionSpace.h \
+  ../Numeric/GmshMatrix.h ../Post/PView.h ../Mesh/Generator.h \
+  ../Common/Context.h ../Geo/CGNSOptions.h ../Mesh/PartitionOptions.h
+visibilityWindow${OBJEXT}: visibilityWindow.cpp GUI.h Draw.h visibilityWindow.h \
+  shortcutWindow.h contextWindow.h ../Common/GmshDefines.h \
+  ../Common/GmshMessage.h ../Geo/GModel.h ../Geo/GVertex.h \
+  ../Geo/GEntity.h ../Geo/Range.h ../Geo/SPoint3.h \
+  ../Geo/SBoundingBox3d.h ../Geo/SPoint3.h ../Geo/GPoint.h \
+  ../Geo/SPoint2.h ../Geo/GEdge.h ../Geo/GEntity.h ../Geo/GVertex.h \
+  ../Geo/SVector3.h ../Geo/SPoint3.h ../Geo/SPoint3.h ../Geo/SPoint2.h \
+  ../Geo/GFace.h ../Geo/GEntity.h ../Geo/GPoint.h ../Geo/GEdgeLoop.h \
+  ../Geo/GEdge.h ../Geo/SPoint2.h ../Geo/SVector3.h ../Geo/Pair.h \
+  ../Geo/GRegion.h ../Geo/GEntity.h ../Geo/SPoint3.h \
+  ../Geo/SBoundingBox3d.h ../Geo/MElement.h ../Geo/MVertex.h \
+  ../Geo/SPoint2.h ../Geo/SPoint3.h ../Geo/MEdge.h ../Geo/MVertex.h \
+  ../Geo/SVector3.h ../Geo/MFace.h ../Geo/MVertex.h ../Geo/SVector3.h \
+  ../Numeric/FunctionSpace.h ../Numeric/GmshMatrix.h \
+  ../Common/Visibility.h ../Common/GmshDefines.h \
+  ../Graphics/SelectBuffer.h ../Graphics/drawContext.h \
+  ../Geo/GeoStringInterface.h ../Common/ListUtils.h ../Common/Options.h \
+  ../Post/ColorTable.h ../Common/Context.h ../Geo/CGNSOptions.h \
   ../Mesh/PartitionOptions.h
+clippingWindow${OBJEXT}: clippingWindow.cpp GUI.h Draw.h clippingWindow.h \
+  shortcutWindow.h ../Common/GmshDefines.h ../Post/PView.h \
+  ../Geo/SPoint3.h ../Post/PViewOptions.h ../Post/ColorTable.h \
+  ../Geo/SBoundingBox3d.h ../Geo/SPoint3.h ../Common/Context.h \
+  ../Geo/CGNSOptions.h ../Mesh/PartitionOptions.h
 messageWindow${OBJEXT}: messageWindow.cpp GUI.h messageWindow.h shortcutWindow.h \
-  Callbacks.h ../Common/GmshMessage.h ../Common/Context.h \
+  fileDialogs.h ../Common/GmshMessage.h ../Common/OS.h \
+  ../Common/Context.h ../Geo/CGNSOptions.h ../Mesh/PartitionOptions.h
+manipWindow${OBJEXT}: manipWindow.cpp GUI.h Draw.h manipWindow.h \
+  shortcutWindow.h graphicWindow.h openglWindow.h \
+  ../Graphics/drawContext.h ../Geo/SBoundingBox3d.h ../Geo/SPoint3.h \
+  ../Common/Options.h ../Post/ColorTable.h ../Common/Context.h \
   ../Geo/CGNSOptions.h ../Mesh/PartitionOptions.h
-manipWindow${OBJEXT}: manipWindow.cpp GUI.h manipWindow.h shortcutWindow.h \
-  Callbacks.h ../Common/Options.h ../Post/ColorTable.h \
+contextWindow${OBJEXT}: contextWindow.cpp GUI.h Draw.h contextWindow.h \
+  shortcutWindow.h ../Geo/GeoStringInterface.h ../Common/ListUtils.h \
+  ../Common/OpenFile.h ../Graphics/SelectBuffer.h \
+  ../Graphics/drawContext.h ../Geo/SBoundingBox3d.h ../Geo/SPoint3.h \
+  ../Geo/GVertex.h ../Geo/GEntity.h ../Geo/Range.h ../Geo/SPoint3.h \
+  ../Geo/SBoundingBox3d.h ../Geo/GPoint.h ../Geo/SPoint2.h ../Geo/GEdge.h \
+  ../Geo/GEntity.h ../Geo/GVertex.h ../Geo/SVector3.h ../Geo/SPoint3.h \
+  ../Geo/SPoint3.h ../Geo/SPoint2.h ../Geo/GFace.h ../Geo/GEntity.h \
+  ../Geo/GPoint.h ../Geo/GEdgeLoop.h ../Geo/GEdge.h ../Geo/SPoint2.h \
+  ../Geo/SVector3.h ../Geo/Pair.h ../Geo/GRegion.h ../Geo/GEntity.h \
   ../Common/Context.h ../Geo/CGNSOptions.h ../Mesh/PartitionOptions.h
-contextWindow${OBJEXT}: contextWindow.cpp GUI.h contextWindow.h shortcutWindow.h \
-  Callbacks.h ../Common/Context.h ../Geo/CGNSOptions.h \
-  ../Mesh/PartitionOptions.h
 solverWindow${OBJEXT}: solverWindow.cpp GUI.h solverWindow.h shortcutWindow.h \
-  Solvers.h Callbacks.h ../Common/Context.h ../Geo/CGNSOptions.h \
-  ../Mesh/PartitionOptions.h
+  optionWindow.h spherePositionWidget.h colorbarWindow.h \
+  ../Post/ColorTable.h messageWindow.h fileDialogs.h \
+  ../Common/GmshMessage.h Solvers.h ../Common/StringUtils.h \
+  ../Common/Options.h ../Common/OS.h ../Common/Context.h \
+  ../Geo/CGNSOptions.h ../Mesh/PartitionOptions.h
 aboutWindow${OBJEXT}: aboutWindow.cpp GUI.h aboutWindow.h shortcutWindow.h \
-  ../Common/CommandLine.h ../Common/StringUtils.h Callbacks.h \
+  ../Common/CommandLine.h ../Common/StringUtils.h ../Common/OS.h \
   ../Common/Context.h ../Geo/CGNSOptions.h ../Mesh/PartitionOptions.h
 fileDialogs${OBJEXT}: fileDialogs.cpp GUI.h shortcutWindow.h \
   ../Common/GmshDefines.h ../Common/CreateFile.h ../Common/Options.h \
@@ -270,37 +342,6 @@ partitionDialog${OBJEXT}: partitionDialog.cpp GUI.h shortcutWindow.h \
   ../Geo/SBoundingBox3d.h Draw.h ../Common/Options.h ../Post/ColorTable.h \
   ../Mesh/Partition.h ../Common/Context.h ../Geo/CGNSOptions.h \
   ../Mesh/PartitionOptions.h
-Callbacks${OBJEXT}: Callbacks.cpp GUI.h menuWindow.h popupButton.h \
-  graphicWindow.h openglWindow.h ../Graphics/drawContext.h \
-  ../Geo/SBoundingBox3d.h ../Geo/SPoint3.h optionWindow.h \
-  spherePositionWidget.h colorbarWindow.h ../Post/ColorTable.h \
-  visibilityWindow.h clippingWindow.h statisticsWindow.h solverWindow.h \
-  manipWindow.h messageWindow.h fieldWindow.h pluginWindow.h \
-  contextWindow.h aboutWindow.h partitionDialog.h extraDialogs.h \
-  fileDialogs.h ../Common/GmshMessage.h ../Common/MallocUtils.h \
-  ../Common/ListUtils.h ../Common/StringUtils.h ../Geo/GModel.h \
-  ../Geo/GVertex.h ../Geo/GEntity.h ../Geo/Range.h ../Geo/SPoint3.h \
-  ../Geo/SBoundingBox3d.h ../Geo/GPoint.h ../Geo/SPoint2.h ../Geo/GEdge.h \
-  ../Geo/GEntity.h ../Geo/GVertex.h ../Geo/SVector3.h ../Geo/SPoint3.h \
-  ../Geo/SPoint3.h ../Geo/SPoint2.h ../Geo/GFace.h ../Geo/GEntity.h \
-  ../Geo/GPoint.h ../Geo/GEdgeLoop.h ../Geo/GEdge.h ../Geo/SPoint2.h \
-  ../Geo/SVector3.h ../Geo/Pair.h ../Geo/GRegion.h ../Geo/GEntity.h \
-  ../Geo/SPoint3.h ../Geo/SBoundingBox3d.h ../Geo/MElement.h \
-  ../Common/GmshDefines.h ../Geo/MVertex.h ../Geo/SPoint2.h \
-  ../Geo/SPoint3.h ../Geo/MEdge.h ../Geo/MVertex.h ../Geo/SVector3.h \
-  ../Geo/MFace.h ../Geo/MVertex.h ../Geo/SVector3.h \
-  ../Numeric/FunctionSpace.h ../Numeric/GmshMatrix.h \
-  ../Geo/GeoStringInterface.h ../Geo/findLinks.h ../Mesh/Generator.h \
-  ../Mesh/HighOrder.h Draw.h ../Graphics/SelectBuffer.h \
-  ../Graphics/drawContext.h ../Post/PView.h ../Post/PViewOptions.h \
-  ../Post/ColorTable.h ../Post/PViewData.h ../Common/CreateFile.h \
-  ../Common/OpenFile.h ../Common/CommandLine.h ../Common/Context.h \
-  ../Geo/CGNSOptions.h ../Mesh/PartitionOptions.h ../Common/Options.h \
-  Callbacks.h ../Plugin/Plugin.h ../Post/PViewDataList.h \
-  ../Post/PViewData.h ../Plugin/PluginManager.h ../Common/Visibility.h \
-  ../Common/GmshDefines.h ../Numeric/Numeric.h \
-  ../Numeric/NumericEmbedded.h Solvers.h ../Common/OS.h ../Mesh/Field.h \
-  ../Mesh/BackgroundMesh.h
 Draw${OBJEXT}: Draw.cpp GUI.h graphicWindow.h openglWindow.h \
   ../Graphics/drawContext.h ../Geo/SBoundingBox3d.h ../Geo/SPoint3.h \
   ../Common/GmshDefines.h Draw.h ../Common/StringUtils.h \
diff --git a/Fltk/aboutWindow.cpp b/Fltk/aboutWindow.cpp
index db95e0a991..7a568280c8 100644
--- a/Fltk/aboutWindow.cpp
+++ b/Fltk/aboutWindow.cpp
@@ -11,11 +11,27 @@
 #include "shortcutWindow.h"
 #include "CommandLine.h"
 #include "StringUtils.h"
-#include "Callbacks.h"
+#include "OS.h"
 #include "Context.h"
 
 extern Context_T CTX;
 
+static void help_license_cb(Fl_Widget *w, void *data)
+{
+  std::string prog = FixWindowsPath(CTX.web_browser);
+  char cmd[1024];
+  ReplaceMultiFormat(prog.c_str(), "http://geuz.org/gmsh/doc/LICENSE.txt", cmd);
+  SystemCall(cmd);
+}
+
+static void help_credits_cb(Fl_Widget *w, void *data)
+{
+  std::string prog = FixWindowsPath(CTX.web_browser);
+  char cmd[1024];
+  ReplaceMultiFormat(prog.c_str(), "http://geuz.org/gmsh/doc/CREDITS.txt", cmd);
+  SystemCall(cmd);
+}
+
 aboutWindow::aboutWindow(int fontsize)
   : _fontsize(fontsize)
 {
@@ -71,7 +87,7 @@ aboutWindow::aboutWindow(int fontsize)
     o->add(" ");
     o->add("@c@.Visit http://www.geuz.org/gmsh/ for more information");
     o->add(" ");
-    o->callback(cancel_cb, (void *)win);
+    o->callback(hide_cb, (void *)win);
   }
 
   {
diff --git a/Fltk/classificationEditor.cpp b/Fltk/classificationEditor.cpp
index 92bfa09f48..1b84e89bbd 100644
--- a/Fltk/classificationEditor.cpp
+++ b/Fltk/classificationEditor.cpp
@@ -20,10 +20,7 @@
 
 extern Context_T CTX;
 
-void buildListOfEdgeAngle(e2t_cont adj,std::vector<edge_angle> &edges_detected,
-                          std::vector<edge_angle> &edges_lonly);
-
-void NoElementsSelectedMode (classificationEditor *e)
+static void NoElementsSelectedMode (classificationEditor *e)
 {
   e->_buttons[CLASSBUTTON_DEL]->deactivate();
   e->_buttons[CLASSBUTTON_ADD]->deactivate();
@@ -36,7 +33,7 @@ void NoElementsSelectedMode (classificationEditor *e)
   e->_togbuttons[CLASSTOGBUTTON_HIDE]->activate(); 
 }
 
-void ElementsSelectedMode(classificationEditor *e)
+static void ElementsSelectedMode(classificationEditor *e)
 {
   e->_buttons[CLASSBUTTON_DEL]->activate();
   e->_buttons[CLASSBUTTON_ADD]->activate();
@@ -49,7 +46,179 @@ void ElementsSelectedMode(classificationEditor *e)
   e->_togbuttons[CLASSTOGBUTTON_HIDE]->deactivate(); 
 }
 
-int maxEdgeNum()
+static void class_selectgface_cb(Fl_Widget *w, void *data)
+{
+  classificationEditor *e = (classificationEditor*)data;
+  std::vector<GVertex*> vertices;
+  std::vector<GEdge*> edges;
+  std::vector<GFace*> faces;
+  std::vector<GFace*> temp;
+  std::vector<GRegion*> regions;
+  std::vector<MElement*> elements;
+
+  opt_geometry_surfaces(0, GMSH_SET | GMSH_GUI, 1);
+
+  while(1) {
+    CTX.mesh.changed = ENT_ALL;
+    Draw();
+
+    Msg::StatusBar(3, false, "Select Model Face\n"
+        "[Press 'e' to end selection or 'q' to abort]");
+    
+    char ib = SelectEntity(ENT_SURFACE, vertices, edges, faces, regions, elements);
+    if(ib == 'l') {
+      for(unsigned int i = 0; i < faces.size(); i++){
+        HighlightEntity(faces[i]);      
+        temp.push_back(faces[i]);
+      }
+    }
+    // ok store the list of gfaces !
+    if(ib == 'e') {
+      ZeroHighlight();
+      for(unsigned int i = 0; i < temp.size(); i++){
+        e->_faces.insert (temp[i]);
+      }
+      break;
+    }
+    // do nothing
+    if(ib == 'q') {
+      ZeroHighlight();
+      break;
+    }
+  } 
+  CTX.mesh.changed = ENT_ALL;
+  Draw();  
+  Msg::StatusBar(3, false, "");
+}
+
+static void class_deleteedge_cb(Fl_Widget *w, void *data)
+{
+  classificationEditor *e = (classificationEditor*)data;
+  std::vector<GVertex*> vertices;
+  std::vector<GEdge*> edges;
+  std::vector<GFace*> faces;
+  std::vector<GRegion*> regions;
+  std::vector<MElement*> elements;
+  std::vector<MLine*> ele;
+  
+  CTX.pick_elements = 1;
+  
+  while(1) {
+    CTX.mesh.changed = ENT_ALL;
+    Draw();
+
+    Msg::StatusBar(3, false, "Select Elements\n"
+        "[Press 'e' to end selection or 'q' to abort]");
+    
+    char ib = SelectEntity(ENT_ALL, vertices, edges, faces, regions, elements);
+    if(ib == 'l') {
+      if(CTX.pick_elements){
+        for(unsigned int i = 0; i < elements.size(); i++){
+          if(elements[i]->getNumEdges() == 1 && elements[i]->getVisibility() != 2){
+            elements[i]->setVisibility(2); ele.push_back((MLine*)elements[i]);
+          }
+        }
+      }
+    }
+    if(ib == 'r') {
+      for(unsigned int i = 0; i < elements.size(); i++)
+        elements[i]->setVisibility(1);
+    }
+    // ok, we compute edges !
+    if(ib == 'e') {
+      ZeroHighlight();      
+      break;
+    }
+    // do nothing
+    if(ib == 'q') {
+      ZeroHighlight();
+      ele.clear();
+      break;
+    }
+  }
+
+  std::sort (ele.begin(),ele.end());
+  //  look in all temporary edges if a deleted one is present and delete it !
+  std::vector<MLine*> temp = e->temporary->lines;
+  e->temporary->lines.clear();
+       
+  for(unsigned int i=0;i<temp.size();i++)
+    {      
+      std::vector<MLine*>::iterator it = std::find (ele.begin(),ele.end(),temp[i]);
+      if (it != ele.end())
+        {
+          delete temp[i];
+        }
+      else e->temporary->lines.push_back(temp[i]);
+    }
+  
+  CTX.mesh.changed = ENT_ALL;
+  CTX.pick_elements = 0;
+  Draw();  
+  Msg::StatusBar(3, false, "");
+}
+
+static void class_save_cb(Fl_Widget *w, void *data)
+{
+  classificationEditor *e = (classificationEditor*)data;
+
+  e->saved->lines.insert(e->saved->lines.end(), e->temporary->lines.begin(),
+                         e->temporary->lines.end());
+  e->temporary->lines.clear();
+  e->_elements.clear();
+  e->edges_detected.clear();
+
+  CTX.mesh.changed = ENT_ALL;
+  CTX.pick_elements = 0;
+  NoElementsSelectedMode (e);
+  Draw();  
+  Msg::StatusBar(3, false, "");
+}
+
+static void class_clear_cb(Fl_Widget *w, void *data)
+{
+  classificationEditor *e = (classificationEditor*)data;
+
+  for(unsigned int i = 0; i < e->temporary->lines.size(); i++){      
+    delete e->temporary->lines[i];
+  }
+  e->temporary->lines.clear();
+
+  CTX.mesh.changed = ENT_ALL;
+  CTX.pick_elements = 0;
+  NoElementsSelectedMode (e);
+  Draw();  
+  Msg::StatusBar(3, false, "");
+}
+
+static void class_ok_cb(Fl_Widget *w, void *data)
+{
+  classificationEditor *e = (classificationEditor*)data;
+  e->edge_detec->deactivate();
+  e->edge_detec->hide();
+  e->face_color->activate();
+  e->face_color->show();
+  class_save_cb(w,data);
+  opt_mesh_lines(0, GMSH_SET | GMSH_GUI, e->op[0]);
+  opt_mesh_surfaces_edges(0, GMSH_SET | GMSH_GUI, e->op[1]);
+  opt_mesh_surfaces_faces(0, GMSH_SET | GMSH_GUI, e->op[2]);
+  opt_mesh_line_width(0, GMSH_SET | GMSH_GUI, e->op[3]);
+
+  Msg::StatusBar(3, false, "");
+}
+
+static void class_okcolor_cb(Fl_Widget *w, void *data)
+{
+  classificationEditor *e = (classificationEditor*)data;
+  e->edge_detec->deactivate();
+  e->edge_detec->show();
+  e->face_color->deactivate();
+  e->face_color->hide();
+  //  class_save_cb(w,data);
+  Msg::StatusBar(3, false, "");
+}
+
+static int maxEdgeNum()
 {
   GModel::eiter it =  GModel::current()->firstEdge();
   GModel::eiter ite = GModel::current()->lastEdge();
@@ -62,7 +231,7 @@ int maxEdgeNum()
   return MAXX;
 }
 
-int maxFaceNum()
+static int maxFaceNum()
 {
   GModel::fiter it =  GModel::current()->firstFace();
   GModel::fiter ite = GModel::current()->lastFace();
@@ -84,9 +253,9 @@ struct compareMLinePtr
   }
 };
 
-void recurClassify(MTri3 *t, GFace *gf,
-                   std::map<MLine*, GEdge*, compareMLinePtr> &lines,
-                   std::map<MTriangle*, GFace*> &reverse)
+static void recurClassify(MTri3 *t, GFace *gf,
+                          std::map<MLine*, GEdge*, compareMLinePtr> &lines,
+                          std::map<MTriangle*, GFace*> &reverse)
 {
   if (!t->isDeleted()){
     gf->triangles.push_back(t->tri());
@@ -105,8 +274,8 @@ void recurClassify(MTri3 *t, GFace *gf,
   }
 }
 
-GEdge *getNewModelEdge(GFace *gf1, GFace *gf2, 
-                       std::map<std::pair<int, int>, GEdge* > &newEdges)
+static GEdge *getNewModelEdge(GFace *gf1, GFace *gf2, 
+                              std::map<std::pair<int, int>, GEdge* > &newEdges)
 {
   int t1 = gf1 ? gf1->tag() : -1;
   int t2 = gf2 ? gf2->tag() : -1;
@@ -127,11 +296,11 @@ GEdge *getNewModelEdge(GFace *gf1, GFace *gf2,
     return it->second;  
 }
 
-void recurClassifyEdges(MTri3 *t , 
-                        std::map<MTriangle*, GFace*> &reverse,
-                        std::map<MLine*, GEdge*, compareMLinePtr> &lines,
-                        std::set<MLine*> &touched,
-                        std::map<std::pair<int, int>, GEdge*> &newEdges)
+static void recurClassifyEdges(MTri3 *t , 
+                               std::map<MTriangle*, GFace*> &reverse,
+                               std::map<MLine*, GEdge*, compareMLinePtr> &lines,
+                               std::set<MLine*> &touched,
+                               std::map<std::pair<int, int>, GEdge*> &newEdges)
 {
   if (!t->isDeleted()){
     t->setDeleted(true);
@@ -157,7 +326,7 @@ void recurClassifyEdges(MTri3 *t ,
   }
 }
 
-void class_color_cb(Fl_Widget* w, void* data)
+static void class_color_cb(Fl_Widget* w, void* data)
 {
   classificationEditor *e = (classificationEditor*)data;
   std::map<MLine*, GEdge*, compareMLinePtr> lines;
@@ -224,7 +393,7 @@ void class_color_cb(Fl_Widget* w, void* data)
   Msg::StatusBar(3, false, "");
 }
 
-void updateedges_cb(Fl_Widget* w, void* data)
+static void updateedges_cb(Fl_Widget* w, void* data)
 {
   classificationEditor *e = (classificationEditor*)data;
  
@@ -254,6 +423,88 @@ void updateedges_cb(Fl_Widget* w, void* data)
   Draw();   
 }
 
+static void class_hide_cb(Fl_Widget *w, void *data)
+{
+  CTX.hide_unselected = !CTX.hide_unselected;
+  CTX.mesh.changed = ENT_ALL;
+  Draw();
+}
+
+static void buildListOfEdgeAngle(e2t_cont adj, std::vector<edge_angle> &edges_detected,
+                                 std::vector<edge_angle> &edges_lonly)
+{
+  e2t_cont::iterator it = adj.begin();
+  for( ; it != adj.end(); ++it){
+    if(it->second.second)
+      edges_detected.push_back(edge_angle(it->first.getVertex(0), 
+                                          it->first.getVertex(1), 
+                                          it->second.first, it->second.second));
+    else 
+      edges_lonly.push_back(edge_angle(it->first.getVertex(0),
+                                       it->first.getVertex(1), 
+                                       it->second.first, it->second.second));
+  }
+  std::sort(edges_detected.begin(), edges_detected.end());
+}
+
+static void class_select_cb(Fl_Widget *w, void *data)
+{
+  classificationEditor *e = (classificationEditor*)data;
+  std::vector<GVertex*> vertices;
+  std::vector<GEdge*> edges;
+  std::vector<GFace*> faces;
+  std::vector<GRegion*> regions;
+  std::vector<MElement*> elements;
+  std::vector<MTriangle*> &ele(e->getElements());
+
+  CTX.pick_elements = 1;
+
+  while(1) {
+    CTX.mesh.changed = ENT_ALL;
+    Draw();
+
+    Msg::StatusBar(3, false, "Select Elements\n"
+        "[Press 'e' to end selection or 'q' to abort]");
+    
+    char ib = SelectEntity(ENT_ALL, vertices, edges, faces, regions, elements);
+    if(ib == 'l') {
+      if(CTX.pick_elements){
+        for(unsigned int i = 0; i < elements.size(); i++){
+          if(elements[i]->getNumEdges() == 3 && elements[i]->getVisibility() != 2){
+            elements[i]->setVisibility(2); ele.push_back((MTriangle*)elements[i]);
+          }
+        }
+      }
+    }
+    if(ib == 'r') {
+      for(unsigned int i = 0; i < elements.size(); i++)
+        elements[i]->setVisibility(1);
+    }
+    // ok, we compute edges !
+    if(ib == 'e') {
+      ZeroHighlight();
+      e2t_cont adj;
+      buildEdgeToTriangle (ele , adj );      
+      buildListOfEdgeAngle ( adj,e->edges_detected,e->edges_lonly);
+      ElementsSelectedMode (e);
+      break;
+    }
+    // do nothing
+    if(ib == 'q') {
+      ZeroHighlight();
+      ele.clear();
+      break;
+    }
+  }
+  
+  updateedges_cb(0, data);
+
+  CTX.mesh.changed = ENT_ALL;
+  CTX.pick_elements = 0;
+  Draw();  
+  Msg::StatusBar(3, false, "");
+}
+
 edge_angle::edge_angle(MVertex *_v1, MVertex *_v2, MElement *t1, MElement *t2)
   : v1(_v1), v2(_v2)
 {
@@ -284,30 +535,13 @@ edge_angle::edge_angle(MVertex *_v1, MVertex *_v2, MElement *t1, MElement *t2)
     }
     norme(c1);
     norme(c2);
-    prodve(c1,c2,c3);
-    double cosa ; prosca(c1,c2,&cosa);
-    double sina = norme (c3);
-    angle = atan2(sina,cosa);
+    prodve(c1, c2, c3);
+    double cosa; prosca(c1, c2, &cosa);
+    double sina = norme(c3);
+    angle = atan2(sina, cosa);
   }
 }
 
-void buildListOfEdgeAngle(e2t_cont adj, std::vector<edge_angle> &edges_detected,
-                          std::vector<edge_angle> &edges_lonly)
-{
-  e2t_cont::iterator it = adj.begin();
-  for( ; it != adj.end(); ++it){
-    if(it->second.second)
-      edges_detected.push_back(edge_angle(it->first.getVertex(0), 
-                                          it->first.getVertex(1), 
-                                          it->second.first, it->second.second));
-    else 
-      edges_lonly.push_back(edge_angle(it->first.getVertex(0),
-                                       it->first.getVertex(1), 
-                                       it->second.first, it->second.second));
-  }
-  std::sort(edges_detected.begin(), edges_detected.end());
-}
-
 classificationEditor::classificationEditor()
 {
   op[0] = opt_mesh_lines(0, GMSH_GET, 0.);
@@ -413,243 +647,6 @@ classificationEditor::classificationEditor()
   _window->size_range(width, (int)(0.85 * height));    
 }
 
-void class_hide_cb(Fl_Widget *w, void *data)
-{
-  CTX.hide_unselected = !CTX.hide_unselected;
-  CTX.mesh.changed = ENT_ALL;
-  Draw();
-}
-
-void class_select_cb(Fl_Widget *w, void *data)
-{
-  classificationEditor *e = (classificationEditor*)data;
-  std::vector<GVertex*> vertices;
-  std::vector<GEdge*> edges;
-  std::vector<GFace*> faces;
-  std::vector<GRegion*> regions;
-  std::vector<MElement*> elements;
-  std::vector<MTriangle*> &ele(e->getElements());
-
-  CTX.pick_elements = 1;
-
-  while(1) {
-    CTX.mesh.changed = ENT_ALL;
-    Draw();
-
-    Msg::StatusBar(3, false, "Select Elements\n"
-        "[Press 'e' to end selection or 'q' to abort]");
-    
-    char ib = SelectEntity(ENT_ALL, vertices, edges, faces, regions, elements);
-    if(ib == 'l') {
-      if(CTX.pick_elements){
-        for(unsigned int i = 0; i < elements.size(); i++){
-          if(elements[i]->getNumEdges() == 3 && elements[i]->getVisibility() != 2){
-            elements[i]->setVisibility(2); ele.push_back((MTriangle*)elements[i]);
-          }
-        }
-      }
-    }
-    if(ib == 'r') {
-      for(unsigned int i = 0; i < elements.size(); i++)
-        elements[i]->setVisibility(1);
-    }
-    // ok, we compute edges !
-    if(ib == 'e') {
-      ZeroHighlight();
-      e2t_cont adj;
-      buildEdgeToTriangle (ele , adj );      
-      buildListOfEdgeAngle ( adj,e->edges_detected,e->edges_lonly);
-      ElementsSelectedMode (e);
-      break;
-    }
-    // do nothing
-    if(ib == 'q') {
-      ZeroHighlight();
-      ele.clear();
-      break;
-    }
-  }
-  
-  updateedges_cb(0, data);
-
-  CTX.mesh.changed = ENT_ALL;
-  CTX.pick_elements = 0;
-  Draw();  
-  Msg::StatusBar(3, false, "");
-}
-
-void class_selectgface_cb(Fl_Widget *w, void *data)
-{
-  classificationEditor *e = (classificationEditor*)data;
-  std::vector<GVertex*> vertices;
-  std::vector<GEdge*> edges;
-  std::vector<GFace*> faces;
-  std::vector<GFace*> temp;
-  std::vector<GRegion*> regions;
-  std::vector<MElement*> elements;
-
-  opt_geometry_surfaces(0, GMSH_SET | GMSH_GUI, 1);
-
-  while(1) {
-    CTX.mesh.changed = ENT_ALL;
-    Draw();
-
-    Msg::StatusBar(3, false, "Select Model Face\n"
-        "[Press 'e' to end selection or 'q' to abort]");
-    
-    char ib = SelectEntity(ENT_SURFACE, vertices, edges, faces, regions, elements);
-    if(ib == 'l') {
-      for(unsigned int i = 0; i < faces.size(); i++){
-        HighlightEntity(faces[i]);      
-        temp.push_back(faces[i]);
-      }
-    }
-    // ok store the list of gfaces !
-    if(ib == 'e') {
-      ZeroHighlight();
-      for(unsigned int i = 0; i < temp.size(); i++){
-        e->_faces.insert (temp[i]);
-      }
-      break;
-    }
-    // do nothing
-    if(ib == 'q') {
-      ZeroHighlight();
-      break;
-    }
-  } 
-  CTX.mesh.changed = ENT_ALL;
-  Draw();  
-  Msg::StatusBar(3, false, "");
-}
-
-void class_deleteedge_cb(Fl_Widget *w, void *data)
-{
-  classificationEditor *e = (classificationEditor*)data;
-  std::vector<GVertex*> vertices;
-  std::vector<GEdge*> edges;
-  std::vector<GFace*> faces;
-  std::vector<GRegion*> regions;
-  std::vector<MElement*> elements;
-  std::vector<MLine*> ele;
-  
-  CTX.pick_elements = 1;
-  
-  while(1) {
-    CTX.mesh.changed = ENT_ALL;
-    Draw();
-
-    Msg::StatusBar(3, false, "Select Elements\n"
-        "[Press 'e' to end selection or 'q' to abort]");
-    
-    char ib = SelectEntity(ENT_ALL, vertices, edges, faces, regions, elements);
-    if(ib == 'l') {
-      if(CTX.pick_elements){
-        for(unsigned int i = 0; i < elements.size(); i++){
-          if(elements[i]->getNumEdges() == 1 && elements[i]->getVisibility() != 2){
-            elements[i]->setVisibility(2); ele.push_back((MLine*)elements[i]);
-          }
-        }
-      }
-    }
-    if(ib == 'r') {
-      for(unsigned int i = 0; i < elements.size(); i++)
-        elements[i]->setVisibility(1);
-    }
-    // ok, we compute edges !
-    if(ib == 'e') {
-      ZeroHighlight();      
-      break;
-    }
-    // do nothing
-    if(ib == 'q') {
-      ZeroHighlight();
-      ele.clear();
-      break;
-    }
-  }
-
-  std::sort (ele.begin(),ele.end());
-  //  look in all temporary edges if a deleted one is present and delete it !
-  std::vector<MLine*> temp = e->temporary->lines;
-  e->temporary->lines.clear();
-       
-  for(unsigned int i=0;i<temp.size();i++)
-    {      
-      std::vector<MLine*>::iterator it = std::find (ele.begin(),ele.end(),temp[i]);
-      if (it != ele.end())
-        {
-          delete temp[i];
-        }
-      else e->temporary->lines.push_back(temp[i]);
-    }
-  
-  CTX.mesh.changed = ENT_ALL;
-  CTX.pick_elements = 0;
-  Draw();  
-  Msg::StatusBar(3, false, "");
-}
-
-void class_save_cb(Fl_Widget *w, void *data)
-{
-  classificationEditor *e = (classificationEditor*)data;
-
-  e->saved->lines.insert(e->saved->lines.end(), e->temporary->lines.begin(),
-                         e->temporary->lines.end());
-  e->temporary->lines.clear();
-  e->_elements.clear();
-  e->edges_detected.clear();
-
-  CTX.mesh.changed = ENT_ALL;
-  CTX.pick_elements = 0;
-  NoElementsSelectedMode (e);
-  Draw();  
-  Msg::StatusBar(3, false, "");
-}
-
-void class_clear_cb(Fl_Widget *w, void *data)
-{
-  classificationEditor *e = (classificationEditor*)data;
-
-  for(unsigned int i = 0; i < e->temporary->lines.size(); i++){      
-    delete e->temporary->lines[i];
-  }
-  e->temporary->lines.clear();
-
-  CTX.mesh.changed = ENT_ALL;
-  CTX.pick_elements = 0;
-  NoElementsSelectedMode (e);
-  Draw();  
-  Msg::StatusBar(3, false, "");
-}
-
-void class_ok_cb(Fl_Widget *w, void *data)
-{
-  classificationEditor *e = (classificationEditor*)data;
-  e->edge_detec->deactivate();
-  e->edge_detec->hide();
-  e->face_color->activate();
-  e->face_color->show();
-  class_save_cb(w,data);
-  opt_mesh_lines(0, GMSH_SET | GMSH_GUI, e->op[0]);
-  opt_mesh_surfaces_edges(0, GMSH_SET | GMSH_GUI, e->op[1]);
-  opt_mesh_surfaces_faces(0, GMSH_SET | GMSH_GUI, e->op[2]);
-  opt_mesh_line_width(0, GMSH_SET | GMSH_GUI, e->op[3]);
-
-  Msg::StatusBar(3, false, "");
-}
-
-void class_okcolor_cb(Fl_Widget *w, void *data)
-{
-  classificationEditor *e = (classificationEditor*)data;
-  e->edge_detec->deactivate();
-  e->edge_detec->show();
-  e->face_color->deactivate();
-  e->face_color->hide();
-  //  class_save_cb(w,data);
-  Msg::StatusBar(3, false, "");
-}
-
 void mesh_classify_cb(Fl_Widget* w, void* data)
 {
   // create the (static) editor
diff --git a/Fltk/classificationEditor.h b/Fltk/classificationEditor.h
index 86b3daeb33..29443dd961 100644
--- a/Fltk/classificationEditor.h
+++ b/Fltk/classificationEditor.h
@@ -57,14 +57,6 @@ class classificationEditor {
   Fl_Group *edge_detec, *face_color, *reverse_eng;
 };
 
-void class_select_cb(Fl_Widget *w, void *data);
-void class_hide_cb(Fl_Widget *w, void *data);
-void class_selectgface_cb(Fl_Widget *w, void *data);
-void class_save_cb(Fl_Widget *w, void *data);
-void class_clear_cb(Fl_Widget *w, void *data);
-void class_deleteedge_cb(Fl_Widget *w, void *data);
-void class_color_cb(Fl_Widget *w, void *data);
-void class_ok_cb(Fl_Widget *w, void *data);
-void class_okcolor_cb(Fl_Widget *w, void *data);
+void mesh_classify_cb(Fl_Widget* w, void* data);
 
 #endif
diff --git a/Fltk/clippingWindow.cpp b/Fltk/clippingWindow.cpp
index 85f795f853..ecfa93dc2c 100644
--- a/Fltk/clippingWindow.cpp
+++ b/Fltk/clippingWindow.cpp
@@ -6,15 +6,144 @@
 #include <FL/Fl_Tabs.H>
 #include <FL/Fl_Return_Button.H>
 #include "GUI.h"
+#include "Draw.h"
 #include "clippingWindow.h"
 #include "shortcutWindow.h"
+#include "GmshDefines.h"
 #include "PView.h"
 #include "PViewOptions.h"
-#include "Callbacks.h"
 #include "Context.h"
 
 extern Context_T CTX;
 
+void clip_cb(Fl_Widget *w, void *data)
+{
+  GUI::instance()->clipping->show();
+}
+
+static void clip_num_cb(Fl_Widget *w, void *data)
+{
+  GUI::instance()->clipping->resetBrowser();
+}
+
+static void clip_update_cb(Fl_Widget *w, void *data)
+{
+  if(GUI::instance()->clipping->group[0]->visible()){ // clipping planes
+    int idx = GUI::instance()->clipping->choice->value();
+    CTX.geom.clip &= ~(1 << idx);
+    CTX.mesh.clip &= ~(1 << idx);
+    for(unsigned int i = 0; i < PView::list.size(); i++)
+      PView::list[i]->getOptions()->Clip &= ~(1 << idx);
+    for(int i = 0; i < GUI::instance()->clipping->browser->size(); i++){
+      if(GUI::instance()->clipping->browser->selected(i + 1)){
+        if(i == 0)
+          CTX.geom.clip |= (1 << idx);
+        else if(i == 1)
+          CTX.mesh.clip |= (1 << idx);
+        else if(i - 2 < PView::list.size())
+          PView::list[i - 2]->getOptions()->Clip |= (1 << idx);
+      }
+    }
+    for(int i = 0; i < 4; i++)
+      CTX.clip_plane[idx][i] = GUI::instance()->clipping->value[i]->value();
+  }
+  else{ // clipping box
+    CTX.geom.clip = 0;
+    CTX.mesh.clip = 0;
+    for(unsigned int i = 0; i < PView::list.size(); i++)
+      PView::list[i]->getOptions()->Clip = 0;
+    for(int i = 0; i < GUI::instance()->clipping->browser->size(); i++){
+      if(GUI::instance()->clipping->browser->selected(i + 1)){
+        for(int idx = 0; idx < 6; idx++){
+          if(i == 0)
+            CTX.geom.clip |= (1 << idx);
+          else if(i == 1)
+            CTX.mesh.clip |= (1 << idx);
+          else if(i - 2 < PView::list.size())
+            PView::list[i - 2]->getOptions()->Clip |= (1 << idx);
+        }
+      }
+    }
+    double c[3] = {GUI::instance()->clipping->value[4]->value(),
+                   GUI::instance()->clipping->value[5]->value(),
+                   GUI::instance()->clipping->value[6]->value()};
+    double d[3] = {GUI::instance()->clipping->value[7]->value(),
+                   GUI::instance()->clipping->value[8]->value(),
+                   GUI::instance()->clipping->value[9]->value()};
+    // left
+    CTX.clip_plane[0][0] = 1.;  CTX.clip_plane[0][1] = 0.;  CTX.clip_plane[0][2] = 0.;
+    CTX.clip_plane[0][3] = -(c[0] - d[0] / 2.);
+    // right
+    CTX.clip_plane[1][0] = -1.; CTX.clip_plane[1][1] = 0.; CTX.clip_plane[1][2] = 0.;
+    CTX.clip_plane[1][3] = (c[0] + d[0] / 2.);
+    // top
+    CTX.clip_plane[2][0] = 0.; CTX.clip_plane[2][1] = 1.; CTX.clip_plane[2][2] = 0.;
+    CTX.clip_plane[2][3] = -(c[1] - d[1] / 2.);
+    // bottom
+    CTX.clip_plane[3][0] = 0.; CTX.clip_plane[3][1] = -1.; CTX.clip_plane[3][2] = 0.;
+    CTX.clip_plane[3][3] = (c[1] + d[1] / 2.);
+    // near
+    CTX.clip_plane[4][0] = 0.; CTX.clip_plane[4][1] = 0.; CTX.clip_plane[4][2] = 1.;
+    CTX.clip_plane[4][3] = -(c[2] - d[2] / 2.);
+    // far
+    CTX.clip_plane[5][0] = 0.; CTX.clip_plane[5][1] = 0.; CTX.clip_plane[5][2] = -1.;
+    CTX.clip_plane[5][3] = (c[2] + d[2] / 2.);
+  }
+
+  if(CTX.clip_whole_elements || 
+     CTX.clip_whole_elements != GUI::instance()->clipping->butt[0]->value()){
+    for(int clip = 0; clip < 6; clip++){
+      if(CTX.mesh.clip)
+	CTX.mesh.changed |= (ENT_LINE | ENT_SURFACE | ENT_VOLUME);
+      for(unsigned int index = 0; index < PView::list.size(); index++)
+	if(PView::list[index]->getOptions()->Clip)
+	  PView::list[index]->setChanged(true);
+    }
+  }
+  
+  CTX.clip_whole_elements = GUI::instance()->clipping->butt[0]->value();
+  CTX.clip_only_draw_intersecting_volume = GUI::instance()->clipping->butt[1]->value();
+  CTX.clip_only_volume = GUI::instance()->clipping->butt[2]->value();
+  
+  int old = CTX.draw_bbox;
+  CTX.draw_bbox = 1;
+  if(CTX.fast_redraw)
+    CTX.post.draw = CTX.mesh.draw = 0;
+  Draw();
+  CTX.draw_bbox = old;
+  CTX.post.draw = CTX.mesh.draw = 1;
+}
+
+static void clip_invert_cb(Fl_Widget *w, void *data)
+{
+  for(int i = 0; i < 4; i++)
+    GUI::instance()->clipping->value[i]->value(-GUI::instance()->clipping->value[i]->value());
+  clip_update_cb(NULL, NULL);
+}
+
+static void clip_reset_cb(Fl_Widget *w, void *data)
+{
+  CTX.geom.clip = 0;
+  CTX.mesh.clip = 0;
+  for(unsigned int index = 0; index < PView::list.size(); index++)
+    PView::list[index]->getOptions()->Clip = 0;
+
+  for(int i = 0; i < 6; i++){
+    CTX.clip_plane[i][0] = 1.;
+    for(int j = 1; j < 4; j++)
+      CTX.clip_plane[i][j] = 0.;
+  }
+
+  if(CTX.clip_whole_elements){
+    CTX.mesh.changed |= (ENT_LINE | ENT_SURFACE | ENT_VOLUME);
+    for(unsigned int index = 0; index < PView::list.size(); index++)
+      PView::list[index]->setChanged(true);
+  }
+
+  GUI::instance()->clipping->resetBrowser();
+  Draw();
+}
+
 clippingWindow::clippingWindow(int fontsize) 
   : _fontsize(fontsize)
 {
@@ -119,7 +248,7 @@ clippingWindow::clippingWindow(int fontsize)
   {
     Fl_Button *o = new Fl_Button
       (width - BB - WB, height - BH - WB, BB, BH, "Cancel");
-    o->callback(cancel_cb, (void *)win);
+    o->callback(hide_cb, (void *)win);
   }
 
   win->position(CTX.clip_position[0], CTX.clip_position[1]);
diff --git a/Fltk/clippingWindow.h b/Fltk/clippingWindow.h
index de6678b19d..1b1c6bba51 100644
--- a/Fltk/clippingWindow.h
+++ b/Fltk/clippingWindow.h
@@ -29,4 +29,6 @@ class clippingWindow{
   void show();
 };
 
+void clip_cb(Fl_Widget *w, void *data);
+
 #endif
diff --git a/Fltk/contextWindow.cpp b/Fltk/contextWindow.cpp
index a84ff337fa..dece09ba31 100644
--- a/Fltk/contextWindow.cpp
+++ b/Fltk/contextWindow.cpp
@@ -6,13 +6,43 @@
 #include <FL/Fl_Tabs.H>
 #include <FL/Fl_Return_Button.H>
 #include "GUI.h"
+#include "Draw.h"
 #include "contextWindow.h"
 #include "shortcutWindow.h"
-#include "Callbacks.h"
+#include "GeoStringInterface.h"
+#include "OpenFile.h"
+#include "SelectBuffer.h"
 #include "Context.h"
 
 extern Context_T CTX;
 
+static void con_geometry_define_parameter_cb(Fl_Widget *w, void *data)
+{
+  add_param(GUI::instance()->geoContext->input[0]->value(),
+            GUI::instance()->geoContext->input[1]->value(), CTX.filename);
+  GUI::instance()->resetVisibility();
+}
+
+static void con_geometry_define_point_cb(Fl_Widget *w, void *data)
+{
+  add_point(CTX.filename,
+            GUI::instance()->geoContext->input[2]->value(),
+            GUI::instance()->geoContext->input[3]->value(),
+            GUI::instance()->geoContext->input[4]->value(),
+            GUI::instance()->geoContext->input[5]->value());
+  GUI::instance()->resetVisibility();
+  ZeroHighlight();
+  SetBoundingBox();
+  Draw();
+}
+
+static void con_geometry_snap_cb(Fl_Widget *w, void *data)
+{
+  CTX.geom.snap[0] = GUI::instance()->geoContext->value[0]->value();
+  CTX.geom.snap[1] = GUI::instance()->geoContext->value[1]->value();
+  CTX.geom.snap[2] = GUI::instance()->geoContext->value[2]->value();
+}
+
 geometryContextWindow::geometryContextWindow(int fontsize)
   : _fontsize(fontsize)
 {
@@ -161,7 +191,7 @@ geometryContextWindow::geometryContextWindow(int fontsize)
   {
     Fl_Button *o = new Fl_Button
       (width - BB - WB, height - BH - WB, BB, BH, "Cancel");
-    o->callback(cancel_cb, (void *)win);
+    o->callback(hide_cb, (void *)win);
   }
 
   win->position(CTX.ctx_position[0], CTX.ctx_position[1]);
@@ -243,7 +273,7 @@ meshContextWindow::meshContextWindow(int fontsize)
   {
     Fl_Button *o = new Fl_Button
       (width - BB - WB, height - BH - WB, BB, BH, "Cancel");
-    o->callback(cancel_cb, (void *)win);
+    o->callback(hide_cb, (void *)win);
   }
 
   win->position(CTX.ctx_position[0], CTX.ctx_position[1]);
diff --git a/Fltk/extraDialogs.cpp b/Fltk/extraDialogs.cpp
index ac9186aa28..475f761c34 100644
--- a/Fltk/extraDialogs.cpp
+++ b/Fltk/extraDialogs.cpp
@@ -141,7 +141,7 @@ int perspective_editor()
 
 // Model chooser
 
-static void model_switch(Fl_Widget* w, void *data)
+static void model_switch_cb(Fl_Widget* w, void *data)
 {
   Fl_Select_Browser *b = (Fl_Select_Browser *)w;
   if(b->value()) GModel::current(b->value() - 1);
@@ -151,7 +151,7 @@ static void model_switch(Fl_Widget* w, void *data)
   Draw();
 }
 
-static void model_draw_all(Fl_Widget* w, void *data)
+static void model_draw_all_cb(Fl_Widget* w, void *data)
 {
   Fl_Check_Button *b = (Fl_Check_Button*)w;
   opt_general_draw_all_models(0, GMSH_SET | GMSH_GUI, (int)b->value());
@@ -178,10 +178,10 @@ int model_chooser()
     Fl_Box *l = new Fl_Box(0, 0, WW, BH, "Choose current model:");
     l->align(FL_ALIGN_LEFT | FL_ALIGN_INSIDE | FL_ALIGN_CLIP);
     menu->browser = new Fl_Hold_Browser(0, BH, WW, 4 * BH);
-    menu->browser->callback(model_switch);
+    menu->browser->callback(model_switch_cb);
     menu->browser->when(FL_WHEN_RELEASE_ALWAYS);
     menu->butt = new Fl_Check_Button(0, 5 * BH, WW, BH, "Draw all models");
-    menu->butt->callback(model_draw_all);
+    menu->butt->callback(model_draw_all_cb);
     menu->window->end();
   }
 
diff --git a/Fltk/fieldWindow.cpp b/Fltk/fieldWindow.cpp
index e4095aad98..f9472332f5 100644
--- a/Fltk/fieldWindow.cpp
+++ b/Fltk/fieldWindow.cpp
@@ -9,18 +9,122 @@
 #include <FL/Fl_Return_Button.H>
 #include <FL/Fl_Value_Input.H>
 #include "GUI.h"
+#include "Draw.h"
 #include "fieldWindow.h"
 #include "shortcutWindow.h"
+#include "fileDialogs.h"
+#include "GmshDefines.h"
 #include "GModel.h"
 #include "PView.h"
-#include "Callbacks.h"
 #include "GmshMessage.h"
 #include "Field.h"
 #include "GeoStringInterface.h"
+#include "SelectBuffer.h"
+#include "Options.h"
 #include "Context.h"
 
 extern Context_T CTX;
 
+void field_cb(Fl_Widget *w, void *data)
+{
+  GUI::instance()->fields->win->show();
+  GUI::instance()->fields->editField(NULL);
+}
+
+static void field_delete_cb(Fl_Widget *w, void *data)
+{
+  Field *f = (Field*)GUI::instance()->fields->editor_group->user_data();
+  delete_field(f->id, CTX.filename);
+  GUI::instance()->fields->editField(NULL);
+}
+
+static void field_new_cb(Fl_Widget *w, void *data)
+{
+  Fl_Menu_Button* mb = ((Fl_Menu_Button*)w);
+  FieldManager *fields = GModel::current()->getFields();
+  int id = fields->new_id();
+  add_field(id, mb->text(), CTX.filename);
+  GUI::instance()->fields->editField((*fields)[id]);
+}
+
+static void field_apply_cb(Fl_Widget *w, void *data)
+{
+  GUI::instance()->fields->saveFieldOptions();
+}
+
+static void field_revert_cb(Fl_Widget *w, void *data)
+{
+  GUI::instance()->fields->loadFieldOptions();
+}
+
+static void field_browser_cb(Fl_Widget *w, void *data)
+{
+  int selected = GUI::instance()->fields->browser->value();
+  if(!selected){
+    GUI::instance()->fields->editField(NULL);
+  }
+  Field *f = (Field*)GUI::instance()->fields->browser->data(selected);
+  GUI::instance()->fields->editField(f);
+}
+
+static void field_put_on_view_cb(Fl_Widget *w, void *data)
+{
+  Fl_Menu_Button* mb = ((Fl_Menu_Button*)w);
+  Field *field = (Field*)GUI::instance()->fields->editor_group->user_data();
+  int iView;
+  if(sscanf(mb->text(), "View [%i]", &iView)){
+    if(iView < (int)PView::list.size()){
+      field->put_on_view(PView::list[iView]);
+    }
+  }
+  else{
+    field->put_on_new_view();
+    GUI::instance()->updateViews();
+  }
+  Draw();
+}
+
+static void field_select_file_cb(Fl_Widget *w, void *data)
+{
+  Fl_Input *input = (Fl_Input*)data;
+  int ret = file_chooser(0, 0, "File selection", "", input->value());
+  if(ret){
+    input->value(file_chooser_get_name(0).c_str());
+    input->set_changed();
+  }
+}
+
+static void field_select_node_cb(Fl_Widget *w, void *data)
+{
+  const char *mode = "select";
+  const char *help = "vertices";
+  CTX.pick_elements = 1;
+  Draw();  
+  std::vector<GVertex*> vertices, vertices_old;
+  std::vector<GEdge*> edges, edges_old;
+  std::vector<GFace*> faces, faces_old;
+  std::vector<GRegion*> regions, regions_old;
+  std::vector<MElement*> elements, elements_old;
+  opt_geometry_points(0, GMSH_SET | GMSH_GUI, 1);
+  while(1) {
+    Msg::StatusBar(3, false, "Select %s\n[Press %s'q' to abort]", 
+        help, mode ? "" : "'u' to undo or ");
+    
+    char ib = SelectEntity(ENT_POINT, vertices, edges, faces, regions, elements);
+    printf("char = %c\n", ib);
+    if(ib == 'q'){
+      for(std::vector<GVertex*>::iterator it = vertices.begin(); it != vertices.end(); it++){
+	printf("%p\n", *it);
+      }
+      break;
+    }
+  }
+  CTX.mesh.changed = ENT_ALL;
+  CTX.pick_elements = 0;
+  Msg::StatusBar(3, false, "");
+  Draw();  
+}
+
 fieldWindow::fieldWindow(int fontsize) : _fontsize(fontsize)
 {
   int width0 = 34 * _fontsize + WB;
@@ -39,19 +143,19 @@ fieldWindow::fieldWindow(int fontsize) : _fontsize(fontsize)
   std::map<std::string, FieldFactory*>::iterator it;
   for(it = fields.map_type_name.begin(); it != fields.map_type_name.end(); it++)
     new_btn->add(it->first.c_str());
-  new_btn->callback(view_field_new_cb);
+  new_btn->callback(field_new_cb);
 
   y += BH;
   browser = new Fl_Hold_Browser(x, y + WB, w, h - 2 * WB);
-  browser->callback(view_field_browser_cb);
+  browser->callback(field_browser_cb);
 
   y += h; 
   delete_btn = new Fl_Button(x, y, w, BH, "Delete");
-  delete_btn->callback(view_field_delete_cb, this);
+  delete_btn->callback(field_delete_cb, this);
 
   y += BH;
   put_on_view_btn = new Fl_Menu_Button(x, y, w, BH, "Put on view");
-  put_on_view_btn->callback(view_field_put_on_view_cb, this);
+  put_on_view_btn->callback(field_put_on_view_cb, this);
 
   x += w + WB;
   y = WB;
@@ -78,11 +182,11 @@ fieldWindow::fieldWindow(int fontsize) : _fontsize(fontsize)
   
   Fl_Button *apply_btn = new Fl_Return_Button
     (x + w - BB, y + h - BH - WB, BB, BH, "Apply");
-  apply_btn->callback(view_field_apply_cb, this);
+  apply_btn->callback(field_apply_cb, this);
   
   Fl_Button *revert_btn = new Fl_Button
     (x + w - 2 * BB - WB, y + h - BH - WB, BB, BH, "Revert");
-  revert_btn->callback(view_field_revert_cb, this);
+  revert_btn->callback(field_revert_cb, this);
   
   background_btn = new Fl_Check_Button
     (x, y + h - BH - WB, (int)(1.5 * BB), BH, "Background mesh size");
@@ -286,7 +390,7 @@ void fieldWindow::editField(Field *f)
       {
         Fl_Button *b = new Fl_Button(x, yy, BH, BH, "S");
         input = new Fl_Input(x + WB + BH, yy, IW - WB - BH, BH, it->first.c_str());
-        b->callback(view_field_select_file_cb, input);
+        b->callback(field_select_file_cb, input);
       }
       break;
     case FIELD_OPTION_STRING:
diff --git a/Fltk/fieldWindow.h b/Fltk/fieldWindow.h
index 349007d8eb..97e69bc2b4 100644
--- a/Fltk/fieldWindow.h
+++ b/Fltk/fieldWindow.h
@@ -44,4 +44,6 @@ class fieldWindow{
   void editField(Field *f);
 };
 
+void field_cb(Fl_Widget *w, void *data);
+
 #endif
diff --git a/Fltk/fileDialogs.cpp b/Fltk/fileDialogs.cpp
index e23fdc805c..1ab0198643 100644
--- a/Fltk/fileDialogs.cpp
+++ b/Fltk/fileDialogs.cpp
@@ -952,79 +952,9 @@ int generic_mesh_dialog(const char *name, const char *title, int format,
 
 #if defined(HAVE_LIBCGNS)
 
-// Forward declarations of some callbacks
-void cgnsw_gc_location_cb(Fl_Widget *widget, void *data);
-void cgnsw_write_dummy_bc_cb(Fl_Widget *widget, void *data);
-void cgnsw_bc_location_cb(Fl_Widget *widget, void *data);
-void cgnsw_write_normals_cb(Fl_Widget *widget, void *data);
-void cgnsw_normal_source_cb(Fl_Widget *widget, void *data);
+struct CGNSWriteDialog;
 
-// Pointers to required widgets
-struct CGNSWriteDialog
-{
-  Fl_Window *window;
-  Fl_Choice *choiceZoneDef;
-  Fl_Input *inputBaseName;
-  Fl_Input *inputZoneName;
-  Fl_Input *inputInterfaceName;
-  Fl_Input *inputPatchName;
-  Fl_Round_Button *roundButton0GCatVertex;
-  Fl_Round_Button *roundButton1GCatFace;
-  Fl_Check_Button *checkButtonWriteBC;
-  Fl_Round_Button *roundButton0BCatVertex;
-  Fl_Round_Button *roundButton1BCatFace;
-  Fl_Check_Button *checkButtonWriteNormals;
-  Fl_Round_Button *roundButton0NormalGeo;
-  Fl_Round_Button *roundButton1NormalElem;
-  Fl_Choice *choiceVecDim;
-  Fl_Check_Button *checkButtonUnknownUserDef;
-  const char *filename;
-  int status;
-  void write_all_options()
-  {
-    opt_mesh_zone_definition(0, GMSH_SET | GMSH_GUI, choiceZoneDef->value());
-    CTX.mesh.cgns_options.baseName = inputBaseName->value();
-    CTX.mesh.cgns_options.zoneName = inputZoneName->value();
-    CTX.mesh.cgns_options.interfaceName = inputInterfaceName->value();
-    CTX.mesh.cgns_options.patchName = inputPatchName->value();
-    CTX.mesh.cgns_options.gridConnectivityLocation =
-      roundButton1GCatFace->value();
-    CTX.mesh.cgns_options.writeBC = checkButtonWriteBC->value();
-    CTX.mesh.cgns_options.bocoLocation = roundButton1BCatFace->value();
-    CTX.mesh.cgns_options.normalSource = (checkButtonWriteNormals->value()) ?
-       roundButton1NormalElem->value() + 1 : 0;
-    CTX.mesh.cgns_options.vectorDim = choiceVecDim->value() + 2;
-    CTX.mesh.cgns_options.writeUserDef = checkButtonUnknownUserDef->value();
-  }
-  void read_all_options()
-  {
-    choiceZoneDef->value(CTX.mesh.zone_definition);
-    inputBaseName->value(CTX.mesh.cgns_options.baseName.c_str());
-    inputZoneName->value(CTX.mesh.cgns_options.zoneName.c_str());
-    inputInterfaceName->value(CTX.mesh.cgns_options.interfaceName.c_str());
-    inputPatchName->value(CTX.mesh.cgns_options.patchName.c_str());
-    checkButtonWriteBC->value(CTX.mesh.cgns_options.writeBC);
-    checkButtonWriteNormals->value(CTX.mesh.cgns_options.normalSource);
-    choiceVecDim->value(CTX.mesh.cgns_options.vectorDim - 2);
-    checkButtonUnknownUserDef->value(CTX.mesh.cgns_options.writeUserDef);
-
-    // Call all callbacks to ensure consistent options
-    cgnsw_gc_location_cb
-      ((CTX.mesh.cgns_options.gridConnectivityLocation) ?
-       roundButton1GCatFace : roundButton0GCatVertex, this);
-    // The order of the next 4 is important
-    cgnsw_normal_source_cb
-      ((CTX.mesh.cgns_options.normalSource == 2) ?
-       roundButton1NormalElem : roundButton0NormalGeo, this);
-    cgnsw_write_normals_cb(checkButtonWriteNormals, this);
-    cgnsw_bc_location_cb
-      ((CTX.mesh.cgns_options.bocoLocation) ?
-       roundButton1BCatFace : roundButton0BCatVertex, this);
-    cgnsw_write_dummy_bc_cb(checkButtonWriteBC, this);
-  }
-};
-
-void cgnsw_gc_location_cb(Fl_Widget *widget, void *data)
+static void cgnsw_gc_location_cb(Fl_Widget *widget, void *data)
 {
   CGNSWriteDialog *dlg = static_cast<CGNSWriteDialog*>(data);
   if(widget == dlg->roundButton0GCatVertex) {
@@ -1037,12 +967,12 @@ void cgnsw_gc_location_cb(Fl_Widget *widget, void *data)
   }
 }
 
-void cgnsw_write_dummy_bc_cb(Fl_Widget *widget, void *data)
+static void cgnsw_write_dummy_bc_cb(Fl_Widget *widget, void *data)
 {
   CGNSWriteDialog *dlg = static_cast<CGNSWriteDialog*>(data);
   if(dlg->checkButtonWriteBC->value()) {
     dlg->roundButton0BCatVertex->activate();
-//     dlg->roundButton1BCatFace->activate();  //**Tmp
+    // dlg->roundButton1BCatFace->activate();  //**Tmp
     dlg->checkButtonWriteNormals->activate();
     if(dlg->checkButtonWriteNormals->value()) {
       if(dlg->roundButton0BCatVertex->value())
@@ -1059,7 +989,7 @@ void cgnsw_write_dummy_bc_cb(Fl_Widget *widget, void *data)
   } 
 }
 
-void cgnsw_bc_location_cb(Fl_Widget *widget, void *data)
+static void cgnsw_bc_location_cb(Fl_Widget *widget, void *data)
 {
   CGNSWriteDialog *dlg = static_cast<CGNSWriteDialog*>(data);
   if(widget == dlg->roundButton0BCatVertex) {
@@ -1077,7 +1007,7 @@ void cgnsw_bc_location_cb(Fl_Widget *widget, void *data)
   }
 }
 
-void cgnsw_write_normals_cb(Fl_Widget *widget, void *data)
+static void cgnsw_write_normals_cb(Fl_Widget *widget, void *data)
 {
   CGNSWriteDialog *dlg = static_cast<CGNSWriteDialog*>(data);
   if(dlg->checkButtonWriteNormals->value()) {
@@ -1091,7 +1021,7 @@ void cgnsw_write_normals_cb(Fl_Widget *widget, void *data)
   } 
 }
 
-void cgnsw_normal_source_cb(Fl_Widget *widget, void *data)
+static void cgnsw_normal_source_cb(Fl_Widget *widget, void *data)
 {
   CGNSWriteDialog *dlg = static_cast<CGNSWriteDialog*>(data);
   if(widget == dlg->roundButton0NormalGeo) {
@@ -1104,14 +1034,14 @@ void cgnsw_normal_source_cb(Fl_Widget *widget, void *data)
   }
 }
 
-void cgnsw_defaults_cb(Fl_Widget *widget, void *data)
+static void cgnsw_defaults_cb(Fl_Widget *widget, void *data)
 {
   CGNSWriteDialog *dlg = static_cast<CGNSWriteDialog*>(data);
   CTX.mesh.cgns_options.setDefaults();
   dlg->read_all_options();
 }
 
-void cgnsw_write_cb(Fl_Widget *widget, void *data)
+static void cgnsw_write_cb(Fl_Widget *widget, void *data)
 {
   CGNSWriteDialog *dlg = static_cast<CGNSWriteDialog*>(data);
 
@@ -1124,13 +1054,78 @@ void cgnsw_write_cb(Fl_Widget *widget, void *data)
   dlg->status = 1;
 }
 
-void cgnsw_cancel_cb(Fl_Widget *widget, void *data)
+static void cgnsw_cancel_cb(Fl_Widget *widget, void *data)
 {
   CGNSWriteDialog *dlg = static_cast<CGNSWriteDialog*>(data);
   dlg->window->hide();
   dlg->status = 0;
 }
 
+// Pointers to required widgets
+struct CGNSWriteDialog
+{
+  Fl_Window *window;
+  Fl_Choice *choiceZoneDef;
+  Fl_Input *inputBaseName;
+  Fl_Input *inputZoneName;
+  Fl_Input *inputInterfaceName;
+  Fl_Input *inputPatchName;
+  Fl_Round_Button *roundButton0GCatVertex;
+  Fl_Round_Button *roundButton1GCatFace;
+  Fl_Check_Button *checkButtonWriteBC;
+  Fl_Round_Button *roundButton0BCatVertex;
+  Fl_Round_Button *roundButton1BCatFace;
+  Fl_Check_Button *checkButtonWriteNormals;
+  Fl_Round_Button *roundButton0NormalGeo;
+  Fl_Round_Button *roundButton1NormalElem;
+  Fl_Choice *choiceVecDim;
+  Fl_Check_Button *checkButtonUnknownUserDef;
+  const char *filename;
+  int status;
+  void write_all_options()
+  {
+    opt_mesh_zone_definition(0, GMSH_SET | GMSH_GUI, choiceZoneDef->value());
+    CTX.mesh.cgns_options.baseName = inputBaseName->value();
+    CTX.mesh.cgns_options.zoneName = inputZoneName->value();
+    CTX.mesh.cgns_options.interfaceName = inputInterfaceName->value();
+    CTX.mesh.cgns_options.patchName = inputPatchName->value();
+    CTX.mesh.cgns_options.gridConnectivityLocation =
+      roundButton1GCatFace->value();
+    CTX.mesh.cgns_options.writeBC = checkButtonWriteBC->value();
+    CTX.mesh.cgns_options.bocoLocation = roundButton1BCatFace->value();
+    CTX.mesh.cgns_options.normalSource = (checkButtonWriteNormals->value()) ?
+       roundButton1NormalElem->value() + 1 : 0;
+    CTX.mesh.cgns_options.vectorDim = choiceVecDim->value() + 2;
+    CTX.mesh.cgns_options.writeUserDef = checkButtonUnknownUserDef->value();
+  }
+  void read_all_options()
+  {
+    choiceZoneDef->value(CTX.mesh.zone_definition);
+    inputBaseName->value(CTX.mesh.cgns_options.baseName.c_str());
+    inputZoneName->value(CTX.mesh.cgns_options.zoneName.c_str());
+    inputInterfaceName->value(CTX.mesh.cgns_options.interfaceName.c_str());
+    inputPatchName->value(CTX.mesh.cgns_options.patchName.c_str());
+    checkButtonWriteBC->value(CTX.mesh.cgns_options.writeBC);
+    checkButtonWriteNormals->value(CTX.mesh.cgns_options.normalSource);
+    choiceVecDim->value(CTX.mesh.cgns_options.vectorDim - 2);
+    checkButtonUnknownUserDef->value(CTX.mesh.cgns_options.writeUserDef);
+
+    // Call all callbacks to ensure consistent options
+    cgnsw_gc_location_cb
+      ((CTX.mesh.cgns_options.gridConnectivityLocation) ?
+       roundButton1GCatFace : roundButton0GCatVertex, this);
+    // The order of the next 4 is important
+    cgnsw_normal_source_cb
+      ((CTX.mesh.cgns_options.normalSource == 2) ?
+       roundButton1NormalElem : roundButton0NormalGeo, this);
+    cgnsw_write_normals_cb(checkButtonWriteNormals, this);
+    cgnsw_bc_location_cb
+      ((CTX.mesh.cgns_options.bocoLocation) ?
+       roundButton1BCatFace : roundButton0BCatVertex, this);
+    cgnsw_write_dummy_bc_cb(checkButtonWriteBC, this);
+  }
+};
+
 int cgns_write_dialog(const char *filename)
 {
   static CGNSWriteDialog dlg;
@@ -1197,7 +1192,7 @@ int cgns_write_dialog(const char *filename)
   dlg.inputPatchName->align(FL_ALIGN_RIGHT);
   y += BH + WB;
 
-//--Left column
+  //--Left column
 
   int yl = y;
   {
@@ -1245,7 +1240,7 @@ int cgns_write_dialog(const char *filename)
     yl += BH + WB;
   }
 
-//--Right column
+  //--Right column
 
   int yr = y;
 
diff --git a/Fltk/graphicWindow.cpp b/Fltk/graphicWindow.cpp
index ee56a7cfef..686669215b 100644
--- a/Fltk/graphicWindow.cpp
+++ b/Fltk/graphicWindow.cpp
@@ -4,11 +4,18 @@
 // bugs and problems to <gmsh@geuz.org>.
 
 #include <FL/fl_draw.H>
+#include "GUI.h"
 #include "graphicWindow.h"
 #include "shortcutWindow.h"
+#include "menuWindow.h"
+#include "messageWindow.h"
+#include "manipWindow.h"
+#include "extraDialogs.h"
+#include "Draw.h"
 #include "PView.h"
 #include "PViewData.h"
-#include "Callbacks.h"
+#include "OS.h"
+#include "Options.h"
 #include "Context.h"
 
 extern Context_T CTX;
@@ -93,6 +100,172 @@ static void gmsh_models(Fl_Color c)
 #undef bl
 #undef el
 
+void status_xyz1p_cb(Fl_Widget *w, void *data)
+{
+  const char *str = (const char*)data;
+
+  drawContext *ctx = GUI::instance()->graph[0]->gl->getDrawContext();
+
+  if(!strcmp(str, "r")){ // rotate 90 degress around axis perp to the screen
+    double axis[3] = {0., 0., 1.};
+    if(!Fl::event_state(FL_SHIFT))
+      ctx->addQuaternionFromAxisAndAngle(axis, -90.);
+    else
+      ctx->addQuaternionFromAxisAndAngle(axis, 90.);
+    Draw();
+  }
+  else if(!strcmp(str, "x")){ // X pointing out or into the screen
+    if(!Fl::event_state(FL_SHIFT)){
+      ctx->r[0] = -90.; ctx->r[1] = 0.; ctx->r[2] = -90.;
+    }
+    else{
+      ctx->r[0] = -90.; ctx->r[1] = 0.; ctx->r[2] = 90.;
+    }
+    ctx->setQuaternionFromEulerAngles();
+    Draw();
+  }
+  else if(!strcmp(str, "y")){ // Y pointing out or into the screen
+    if(!Fl::event_state(FL_SHIFT)){
+      ctx->r[0] = -90.; ctx->r[1] = 0.; ctx->r[2] = 180.;
+    }
+    else{
+      ctx->r[0] = -90.; ctx->r[1] = 0.; ctx->r[2] = 0.;
+    }
+    ctx->setQuaternionFromEulerAngles();
+    Draw();
+  }
+  else if(!strcmp(str, "z")){ // Z pointing out or into the screen
+    if(!Fl::event_state(FL_SHIFT)){
+      ctx->r[0] = 0.; ctx->r[1] = 0.; ctx->r[2] = 0.;
+    }
+    else{
+      ctx->r[0] = 0.; ctx->r[1] = 180.; ctx->r[2] = 0.;
+    }
+    ctx->setQuaternionFromEulerAngles();
+    Draw();
+  }
+  else if(!strcmp(str, "1:1")){ // reset translation and scaling
+    ctx->t[0] = ctx->t[1] = ctx->t[2] = 0.;
+    ctx->s[0] = ctx->s[1] = ctx->s[2] = 1.;
+    Draw();
+  }
+  else if(!strcmp(str, "reset")){ // reset everything
+    ctx->t[0] = ctx->t[1] = ctx->t[2] = 0.;
+    ctx->s[0] = ctx->s[1] = ctx->s[2] = 1.;
+    ctx->r[0] = ctx->r[1] = ctx->r[2] = 0.;
+    ctx->setQuaternionFromEulerAngles();
+    Draw();
+  }
+  else if(!strcmp(str, "p")){ // toggle projection mode
+    if(!Fl::event_state(FL_SHIFT)){
+      opt_general_orthographic(0, GMSH_SET | GMSH_GUI, 
+                               !opt_general_orthographic(0, GMSH_GET, 0));
+    }
+    else{
+      perspective_editor();
+    }
+    Draw();
+  }
+  else if(!strcmp(str, "model")){ // toggle projection mode
+    model_chooser();
+  }
+  else if(!strcmp(str, "?")){ // display options
+    Print_Options(0, GMSH_FULLRC, 0, 1, NULL);
+    GUI::instance()->messages->show();
+  }
+  else if(!strcmp(str, "S")){ // mouse selection
+    if(CTX.mouse_selection){
+      opt_general_mouse_selection(0, GMSH_SET | GMSH_GUI, 0);
+      GUI::instance()->graph[0]->gl->cursor(FL_CURSOR_DEFAULT, FL_BLACK, FL_WHITE);
+    }
+    else
+      opt_general_mouse_selection(0, GMSH_SET | GMSH_GUI, 1);
+  }
+  GUI::instance()->manip->update();
+}
+
+static int stop_anim, view_in_cycle = -1;
+
+void status_play_manual(int time, int step)
+{
+  // avoid firing this routine recursively (can happen e.g when
+  // keeping the finger down on the arrow key: if the system generates
+  // too many events, we can overflow the stack--that happened on my
+  // powerbook with the new, optimzed FLTK event handler)
+  static bool busy = false;
+  if(busy) return;
+  busy = true;
+  if(time) {
+    for(unsigned int i = 0; i < PView::list.size(); i++)
+      if(opt_view_visible(i, GMSH_GET, 0))
+        opt_view_timestep(i, GMSH_SET | GMSH_GUI,
+                          opt_view_timestep(i, GMSH_GET, 0) + step);
+  }
+  else { // hide all views except view_in_cycle
+    if(step > 0) {
+      if((view_in_cycle += step) >= (int)PView::list.size())
+        view_in_cycle = 0;
+      for(int i = 0; i < (int)PView::list.size(); i += step)
+        opt_view_visible(i, GMSH_SET | GMSH_GUI, (i == view_in_cycle));
+    }
+    else {
+      if((view_in_cycle += step) < 0)
+        view_in_cycle = PView::list.size() - 1;
+      for(int i = PView::list.size() - 1; i >= 0; i += step)
+        opt_view_visible(i, GMSH_SET | GMSH_GUI, (i == view_in_cycle));
+    }
+  }
+  Draw();
+  busy = false;
+}
+
+static void status_play_cb(Fl_Widget *w, void *data)
+{
+  static double anim_time;
+  GUI::instance()->graph[0]->setAnimButtons(0);
+  stop_anim = 0;
+  anim_time = GetTimeInSeconds();
+  while(1) {
+    if(stop_anim)
+      break;
+    if(GetTimeInSeconds() - anim_time > CTX.post.anim_delay) {
+      anim_time = GetTimeInSeconds();
+      status_play_manual(!CTX.post.anim_cycle, 1);
+    }
+    GUI::instance()->check();
+  }
+}
+
+static void status_pause_cb(Fl_Widget *w, void *data)
+{
+  stop_anim = 1;
+  GUI::instance()->graph[0]->setAnimButtons(1);
+}
+
+static void status_rewind_cb(Fl_Widget *w, void *data)
+{
+  if(!CTX.post.anim_cycle) {
+    for(unsigned int i = 0; i < PView::list.size(); i++)
+      opt_view_timestep(i, GMSH_SET | GMSH_GUI, 0);
+  }
+  else {
+    view_in_cycle = 0;
+    for(unsigned int i = 0; i < PView::list.size(); i++)
+      opt_view_visible(i, GMSH_SET | GMSH_GUI, !i);
+  }
+  Draw();
+}
+
+static void status_stepbackward_cb(Fl_Widget *w, void *data)
+{
+  status_play_manual(!CTX.post.anim_cycle, -1);
+}
+
+static void status_stepforward_cb(Fl_Widget *w, void *data)
+{
+  status_play_manual(!CTX.post.anim_cycle, 1);
+}
+
 graphicWindow::graphicWindow(int fontsize)
 {
   static bool first = true;
diff --git a/Fltk/graphicWindow.h b/Fltk/graphicWindow.h
index 0610cfa0f7..266412126e 100644
--- a/Fltk/graphicWindow.h
+++ b/Fltk/graphicWindow.h
@@ -23,4 +23,7 @@ class graphicWindow{
   void checkAnimButtons();
 };
 
+void status_xyz1p_cb(Fl_Widget *w, void *data);
+void status_play_manual(int time, int step);
+
 #endif
diff --git a/Fltk/manipWindow.cpp b/Fltk/manipWindow.cpp
index c83feddb27..2155d54da4 100644
--- a/Fltk/manipWindow.cpp
+++ b/Fltk/manipWindow.cpp
@@ -6,14 +6,36 @@
 #include <FL/Fl_Box.H>
 #include <FL/Fl_Return_Button.H>
 #include "GUI.h"
+#include "Draw.h"
 #include "manipWindow.h"
 #include "shortcutWindow.h"
-#include "Callbacks.h"
+#include "graphicWindow.h"
 #include "Options.h"
 #include "Context.h"
 
 extern Context_T CTX;
 
+void manip_cb(Fl_Widget *w, void *data)
+{
+  GUI::instance()->manip->show();
+}
+
+static void manip_update_cb(Fl_Widget *w, void *data)
+{
+  drawContext *ctx = GUI::instance()->graph[0]->gl->getDrawContext();
+  ctx->r[0] = GUI::instance()->manip->value[0]->value();
+  ctx->r[1] = GUI::instance()->manip->value[1]->value();
+  ctx->r[2] = GUI::instance()->manip->value[2]->value();
+  ctx->t[0] = GUI::instance()->manip->value[3]->value();
+  ctx->t[1] = GUI::instance()->manip->value[4]->value();
+  ctx->t[2] = GUI::instance()->manip->value[5]->value();
+  ctx->s[0] = GUI::instance()->manip->value[6]->value();
+  ctx->s[1] = GUI::instance()->manip->value[7]->value();
+  ctx->s[2] = GUI::instance()->manip->value[8]->value();
+  ctx->setQuaternionFromEulerAngles();
+  Draw();
+}
+
 manipWindow::manipWindow(int fontsize)
   : _fontsize(fontsize)
 {
@@ -69,7 +91,7 @@ manipWindow::manipWindow(int fontsize)
   {
     Fl_Button *o = new Fl_Button
       (width - BB - WB, height - BH - WB, BB, BH, "Cancel");
-    o->callback(cancel_cb, (void *)win);
+    o->callback(hide_cb, (void *)win);
   }
 
   win->position(CTX.manip_position[0], CTX.manip_position[1]);
diff --git a/Fltk/manipWindow.h b/Fltk/manipWindow.h
index 043923bae7..0ddfb7d59c 100644
--- a/Fltk/manipWindow.h
+++ b/Fltk/manipWindow.h
@@ -21,4 +21,6 @@ class manipWindow{
   void show();
 };
 
+void manip_cb(Fl_Widget *w, void *data);
+
 #endif
diff --git a/Fltk/menuWindow.cpp b/Fltk/menuWindow.cpp
index 2e9bf4f05a..13b59f15cd 100644
--- a/Fltk/menuWindow.cpp
+++ b/Fltk/menuWindow.cpp
@@ -4,21 +4,2131 @@
 // bugs and problems to <gmsh@geuz.org>.
 
 #include <string.h>
+#include <stdio.h>
+#include <time.h>
 #include <FL/Fl_Box.H>
+#include <FL/fl_ask.H>
 #include "GUI.h"
+#include "Draw.h"
 #include "menuWindow.h"
 #include "shortcutWindow.h"
-#include "Callbacks.h"
+#include "graphicWindow.h"
+#include "optionWindow.h"
+#include "statisticsWindow.h"
+#include "messageWindow.h"
+#include "contextWindow.h"
+#include "visibilityWindow.h"
+#include "clippingWindow.h"
+#include "manipWindow.h"
+#include "fieldWindow.h"
+#include "pluginWindow.h"
+#include "solverWindow.h"
+#include "aboutWindow.h"
+#include "fileDialogs.h"
+#include "partitionDialog.h"
+#include "projectionEditor.h"
+#include "classificationEditor.h"
 #include "Options.h"
 #include "Solvers.h"
 #include "GmshMessage.h"
+#include "CommandLine.h"
+#include "Generator.h"
+#include "HighOrder.h"
+#include "GModel.h"
 #include "PView.h"
 #include "PViewData.h"
 #include "PViewOptions.h"
+#include "Field.h"
+#include "OS.h"
+#include "StringUtils.h"
+#include "SelectBuffer.h"
+#include "OpenFile.h"
+#include "CreateFile.h"
+#include "findLinks.h"
+#include "GeoStringInterface.h"
+#include "Options.h"
 #include "Context.h"
 
 extern Context_T CTX;
 
+static void file_new_cb(Fl_Widget *w, void *data)
+{
+ test:
+  if(file_chooser(0, 1, "New", "*")) {
+    std::string name = file_chooser_get_name(1);
+    if(!StatFile(name.c_str())){
+      if(fl_choice("File '%s' already exists.\n\nDo you want to erase it?",
+                   "Cancel", "Erase", NULL, name.c_str()))
+        UnlinkFile(name.c_str());
+      else
+        goto test;
+    }
+    FILE *fp = fopen(name.c_str(), "w");
+    if(!fp){
+      Msg::Error("Unable to open file '%s'", name.c_str());
+      return;
+    }
+    time_t now;
+    time(&now);
+    fprintf(fp, "// Gmsh project created on %s", ctime(&now));
+    fclose(fp);
+    OpenProject(name.c_str());
+    Draw();
+  }
+}
+
+#if defined(HAVE_NATIVE_FILE_CHOOSER)
+#  define TT "\t"
+#  define NN "\n"
+#else
+#  define TT " ("
+#  define NN ")\t"
+#endif
+
+static const char *input_formats =
+  "All files" TT "*" NN
+  "Gmsh geometry" TT "*.geo" NN
+  "Gmsh mesh" TT "*.msh" NN
+  "Gmsh post-processing view" TT "*.pos" NN
+#if defined(HAVE_OCC)
+  "STEP model" TT "*.{stp,step}" NN
+  "IGES model" TT "*.{igs,iges}" NN
+  "BRep model" TT "*.brep" NN
+#endif
+  "I-deas universal mesh" TT "*.unv" NN
+  "Diffpack 3D mesh" TT "*.diff" NN
+  "VTK mesh" TT "*.vtk" NN
+#if defined(HAVE_MED)
+  "MED file" TT "*.{med,mmed,rmed}" NN
+#endif
+  "Medit mesh" TT "*.mesh" NN
+  "Nastran bulk data file" TT "*.{bdf,nas}" NN
+  "Plot3D structured mesh" TT "*.p3d" NN
+  "STL surface mesh" TT "*.stl" NN
+  "VRML surface mesh" TT "*.{wrl,vrml}" NN
+#if defined(HAVE_LIBJPEG)
+  "JPEG" TT "*.{jpg,jpeg}" NN
+#endif
+#if defined(HAVE_LIBPNG)
+  "PNG" TT "*.png" NN
+#endif
+  "BMP" TT "*.bmp" NN
+  "PPM" TT "*.ppm" NN
+  "PGM" TT "*.pgm" NN
+  "PBM" TT "*.pbm" NN
+  "PNM" TT "*.pnm" NN;
+
+#undef TT
+#undef NN
+
+static void file_open_cb(Fl_Widget *w, void *data)
+{
+  int n = PView::list.size();
+  if(file_chooser(0, 0, "Open", input_formats)) {
+    OpenProject(file_chooser_get_name(1).c_str());
+    Draw();
+  }
+  if(n != (int)PView::list.size())
+    GUI::instance()->menu->setContext(menu_post, 0);
+}
+
+static void file_merge_cb(Fl_Widget *w, void *data)
+{
+  int n = PView::list.size();
+  int f = file_chooser(1, 0, "Merge", input_formats);
+  if(f) {
+    for(int i = 1; i <= f; i++)
+      MergeFile(file_chooser_get_name(i).c_str());
+    Draw();
+  }
+  if(n != (int)PView::list.size())
+    GUI::instance()->menu->setContext(menu_post, 0);
+}
+
+static int _save_msh(const char *name){ return msh_dialog(name); }
+static int _save_pos(const char *name){ return pos_dialog(name); }
+static int _save_options(const char *name){ return options_dialog(name); }
+static int _save_geo(const char *name){ return geo_dialog(name); }
+static int _save_cgns(const char *name){ return cgns_write_dialog(name); }
+static int _save_unv(const char *name){ return unv_dialog(name); }
+static int _save_vtk(const char *name){ return generic_mesh_dialog
+    (name, "VTK Options", FORMAT_VTK, true); }
+static int _save_diff(const char *name){ return generic_mesh_dialog
+    (name, "Diffpack Options", FORMAT_DIFF, true); }
+static int _save_med(const char *name){ return generic_mesh_dialog
+    (name, "MED Options", FORMAT_MED, false); }
+static int _save_mesh(const char *name){ return generic_mesh_dialog
+    (name, "MESH Options", FORMAT_MESH, false); }
+static int _save_bdf(const char *name){ return bdf_dialog(name); }
+static int _save_p3d(const char *name){ return generic_mesh_dialog
+    (name, "P3D Options", FORMAT_P3D, false); }
+static int _save_stl(const char *name){ return generic_mesh_dialog
+    (name, "STL Options", FORMAT_STL, true); }
+static int _save_vrml(const char *name){ return generic_mesh_dialog
+    (name, "VRML Options", FORMAT_VRML, false); }
+static int _save_eps(const char *name){ return gl2ps_dialog
+    (name, "EPS Options", FORMAT_EPS); }
+static int _save_gif(const char *name){ return gif_dialog(name); }
+static int _save_jpeg(const char *name){ return jpeg_dialog(name); }
+static int _save_tex(const char *name){ return latex_dialog(name); }
+static int _save_pdf(const char *name){ return gl2ps_dialog
+    (name, "PDF Options", FORMAT_PDF); }
+static int _save_png(const char *name){ return generic_bitmap_dialog
+    (name, "PNG Options", FORMAT_PNG); }
+static int _save_ps(const char *name){ return gl2ps_dialog
+    (name, "PS Options", FORMAT_PS); }
+static int _save_ppm(const char *name){ return generic_bitmap_dialog
+    (name, "PPM Options", FORMAT_PPM); }
+static int _save_svg(const char *name){ return gl2ps_dialog
+    (name, "SVG Options", FORMAT_SVG); }
+static int _save_yuv(const char *name){ return generic_bitmap_dialog
+    (name, "YUV Options", FORMAT_YUV); }
+
+static int _save_auto(const char *name)
+{
+  switch(GuessFileFormatFromFileName(name)){
+  case FORMAT_MSH  : return _save_msh(name);
+  case FORMAT_POS  : return _save_pos(name);
+  case FORMAT_OPT  : return _save_options(name);
+  case FORMAT_GEO  : return _save_geo(name);
+  case FORMAT_CGNS : return _save_cgns(name);
+  case FORMAT_UNV  : return _save_unv(name);
+  case FORMAT_VTK  : return _save_vtk(name);
+  case FORMAT_MED  : return _save_med(name);
+  case FORMAT_MESH : return _save_mesh(name);
+  case FORMAT_BDF  : return _save_bdf(name);
+  case FORMAT_DIFF : return _save_diff(name);
+  case FORMAT_P3D  : return _save_p3d(name);
+  case FORMAT_STL  : return _save_stl(name);
+  case FORMAT_VRML : return _save_vrml(name);
+  case FORMAT_EPS  : return _save_eps(name);
+  case FORMAT_GIF  : return _save_gif(name);
+  case FORMAT_JPEG : return _save_jpeg(name);
+  case FORMAT_TEX  : return _save_tex(name);
+  case FORMAT_PDF  : return _save_pdf(name);
+  case FORMAT_PNG  : return _save_png(name);
+  case FORMAT_PS   : return _save_ps(name);
+  case FORMAT_PPM  : return _save_ppm(name);
+  case FORMAT_SVG  : return _save_svg(name);
+  case FORMAT_YUV  : return _save_yuv(name);
+  default :
+    CreateOutputFile(name, FORMAT_AUTO); 
+    return 1;
+  }
+}
+
+typedef struct{
+  const char *pat;
+  int (*func) (const char *name);
+} patXfunc;
+
+static void file_save_as_cb(Fl_Widget *w, void *data)
+{
+#if defined(HAVE_NATIVE_FILE_CHOOSER)
+#  define TT "\t"
+#  define NN "\n"
+#else
+#  define TT " ("
+#  define NN ")\t"
+#endif
+  static patXfunc formats[] = {
+    {"Guess from extension" TT "*.*", _save_auto},
+    {"Gmsh mesh" TT "*.msh", _save_msh},
+    {"Gmsh mesh statistics" TT "*.pos", _save_pos},
+    {"Gmsh options" TT "*.opt", _save_options},
+    {"Gmsh unrolled geometry" TT "*.geo", _save_geo},
+#if defined(HAVE_LIBCGNS)
+    {"CGNS" TT "*.cgns", _save_cgns},
+#endif
+    {"I-deas universal mesh" TT "*.unv", _save_unv},
+    {"Diffpack 3D mesh" TT "*.diff", _save_diff},
+    {"VTK mesh" TT "*.vtk", _save_vtk},
+#if defined(HAVE_MED)
+    {"MED file" TT "*.med", _save_med},
+#endif
+    {"Medit mesh" TT "*.mesh", _save_mesh},
+    {"Nastran bulk data file" TT "*.bdf", _save_bdf},
+    {"Plot3D structured mesh" TT "*.p3d", _save_p3d},
+    {"STL surface mesh" TT "*.stl", _save_stl},
+    {"VRML surface mesh" TT "*.wrl", _save_vrml},
+    {"Encapsulated PostScript" TT "*.eps", _save_eps},
+    {"GIF" TT "*.gif", _save_gif},
+#if defined(HAVE_LIBJPEG)
+    {"JPEG" TT "*.jpg", _save_jpeg},
+#endif
+    {"LaTeX" TT "*.tex", _save_tex},
+    {"PDF" TT "*.pdf", _save_pdf},
+#if defined(HAVE_LIBPNG)
+    {"PNG" TT "*.png", _save_png},
+#endif
+    {"PostScript" TT "*.ps", _save_ps},
+    {"PPM" TT "*.ppm", _save_ppm},
+    {"SVG" TT "*.svg", _save_svg},
+    {"YUV" TT "*.yuv", _save_yuv},
+  };
+  int nbformats = sizeof(formats) / sizeof(formats[0]);
+  static char *pat = 0;
+  if(!pat) {
+    pat = new char[nbformats * 256];
+    strcpy(pat, formats[0].pat);
+    for(int i = 1; i < nbformats; i++) {
+      strcat(pat, NN);
+      strcat(pat, formats[i].pat);
+    }
+  }
+#undef TT
+#undef NN
+
+ test:
+  if(file_chooser(0, 1, "Save As", pat)) {
+    std::string name = file_chooser_get_name(1);
+    if(CTX.confirm_overwrite) {
+      if(!StatFile(name.c_str()))
+        if(!fl_choice("File '%s' already exists.\n\nDo you want to replace it?", 
+                      "Cancel", "Replace", NULL, name.c_str()))
+          goto test;
+    }
+    int i = file_chooser_get_filter();
+    if(i >= 0 && i < nbformats){
+      if(!formats[i].func(name.c_str())) goto test;
+    }
+    else{ // handle any additional automatic fltk filter
+      if(!_save_auto(name.c_str())) goto test;
+    }
+  }
+}
+
+static void file_rename_cb(Fl_Widget *w, void *data)
+{
+ test:
+  if(file_chooser(0, 1, "Rename", "*", CTX.filename)) {
+    std::string name = file_chooser_get_name(1);
+    if(CTX.confirm_overwrite) {
+      if(!StatFile(name.c_str()))
+        if(!fl_choice("File '%s' already exists.\n\nDo you want to replace it?", 
+                      "Cancel", "Replace", NULL, name.c_str()))
+          goto test;
+    }
+    rename(CTX.filename, name.c_str());
+    OpenProject(name.c_str());
+    Draw();
+  }
+}
+
+void file_quit_cb(Fl_Widget *w, void *data)
+{
+  Msg::Exit(0);
+}
+
+#if defined(__APPLE__)
+#  define CC(str) "Cmd+" str " "
+#else
+#  define CC(str) "Ctrl+" str
+#endif
+
+static void help_short_cb(Fl_Widget *w, void *data)
+{
+  Msg::Direct(" ");
+  Msg::Direct("Keyboard shortcuts:");
+  Msg::Direct(" ");
+  Msg::Direct("  Left arrow    Go to previous time step"); 
+  Msg::Direct("  Right arrow   Go to next time step"); 
+  Msg::Direct("  Up arrow      Make previous view visible"); 
+  Msg::Direct("  Down arrow    Make next view visible"); 
+  Msg::Direct(" ");
+  Msg::Direct("  <             Go back to previous context");
+  Msg::Direct("  >             Go forward to next context");
+  Msg::Direct("  0             Reload project file");
+  Msg::Direct("  1 or F1       Mesh lines");
+  Msg::Direct("  2 or F2       Mesh surfaces");
+  Msg::Direct("  3 or F3       Mesh volumes");
+  Msg::Direct("  Escape        Cancel lasso zoom/selection, toggle mouse selection ON/OFF");
+  Msg::Direct(" ");
+  Msg::Direct("  g             Go to geometry module");
+  Msg::Direct("  m             Go to mesh module");
+  Msg::Direct("  p             Go to post-processing module");
+  Msg::Direct("  s             Go to solver module");
+  Msg::Direct(" ");
+  Msg::Direct("  Shift+a       Bring all windows to front");
+  Msg::Direct("  Shift+g       Show geometry options");
+  Msg::Direct("  Shift+m       Show mesh options");
+  Msg::Direct("  Shift+o       Show general options"); 
+  Msg::Direct("  Shift+p       Show post-processing options");
+  Msg::Direct("  Shift+s       Show solver options"); 
+  Msg::Direct("  Shift+u       Show post-processing view plugins");
+  Msg::Direct("  Shift+w       Show post-processing view options");
+  Msg::Direct("  Shift+Escape  Enable full mouse selection");
+  Msg::Direct(" ");
+  Msg::Direct("  " CC("i") "        Show statistics window"); 
+  Msg::Direct("  " CC("l") "        Show message console");
+#if defined(__APPLE__)
+  Msg::Direct("  " CC("m") "        Minimize window"); 
+#endif
+  Msg::Direct("  " CC("n") "        Create new project file"); 
+  Msg::Direct("  " CC("o") "        Open project file"); 
+  Msg::Direct("  " CC("q") "        Quit");
+  Msg::Direct("  " CC("r") "        Rename project file");
+  Msg::Direct("  " CC("s") "        Save file as");
+  Msg::Direct(" ");
+  Msg::Direct("  Shift+" CC("c") "  Show clipping plane window");
+  Msg::Direct("  Shift+" CC("m") "  Show manipulator window"); 
+  Msg::Direct("  Shift+" CC("n") "  Show option window"); 
+  Msg::Direct("  Shift+" CC("o") "  Merge file(s)"); 
+  Msg::Direct("  Shift+" CC("s") "  Save mesh in default format");
+  Msg::Direct("  Shift+" CC("u") "  Show plugin window");
+  Msg::Direct("  Shift+" CC("v") "  Show visibility window");
+  Msg::Direct(" ");
+  Msg::Direct("  Alt+a         Loop through axes modes"); 
+  Msg::Direct("  Alt+b         Hide/show bounding boxes");
+  Msg::Direct("  Alt+c         Loop through predefined color schemes");
+  Msg::Direct("  Alt+e         Hide/Show element outlines for visible post-pro views");
+  Msg::Direct("  Alt+f         Change redraw mode (fast/full)"); 
+  Msg::Direct("  Alt+h         Hide/show all post-processing views"); 
+  Msg::Direct("  Alt+i         Hide/show all post-processing view scales");
+  Msg::Direct("  Alt+l         Hide/show geometry lines");
+  Msg::Direct("  Alt+m         Toggle visibility of all mesh entities");
+  Msg::Direct("  Alt+n         Hide/show all post-processing view annotations");
+  Msg::Direct("  Alt+o         Change projection mode (orthographic/perspective)");
+  Msg::Direct("  Alt+p         Hide/show geometry points");
+  Msg::Direct("  Alt+r         Loop through range modes for visible post-pro views"); 
+  Msg::Direct("  Alt+s         Hide/show geometry surfaces");
+  Msg::Direct("  Alt+t         Loop through interval modes for visible post-pro views"); 
+  Msg::Direct("  Alt+v         Hide/show geometry volumes");
+  Msg::Direct("  Alt+w         Enable/disable all lighting");
+  Msg::Direct("  Alt+x         Set X view"); 
+  Msg::Direct("  Alt+y         Set Y view"); 
+  Msg::Direct("  Alt+z         Set Z view"); 
+  Msg::Direct(" ");
+  Msg::Direct("  Alt+Shift+a   Hide/show small axes"); 
+  Msg::Direct("  Alt+Shift+b   Hide/show mesh volume faces");
+  Msg::Direct("  Alt+Shift+d   Hide/show mesh surface faces");
+  Msg::Direct("  Alt+Shift+l   Hide/show mesh lines");
+  Msg::Direct("  Alt+Shift+o   Adjust projection parameters");
+  Msg::Direct("  Alt+Shift+p   Hide/show mesh points");
+  Msg::Direct("  Alt+Shift+s   Hide/show mesh surface edges");
+  Msg::Direct("  Alt+Shift+v   Hide/show mesh volume edges");
+  Msg::Direct("  Alt+Shift+w   Reverse all mesh normals");
+  Msg::Direct("  Alt+Shift+x   Set -X view"); 
+  Msg::Direct("  Alt+Shift+y   Set -Y view"); 
+  Msg::Direct("  Alt+Shift+z   Set -Z view"); 
+  Msg::Direct(" ");
+  GUI::instance()->messages->show();
+}
+
+static void help_mouse_cb(Fl_Widget *w, void *data)
+{
+  Msg::Direct(" ");
+  Msg::Direct("Mouse actions:");
+  Msg::Direct(" ");
+  Msg::Direct("  Move                - Highlight the entity under the mouse pointer");
+  Msg::Direct("                        and display its properties in the status bar");
+  Msg::Direct("                      - Resize a lasso zoom or a lasso (un)selection");
+  Msg::Direct("  Left button         - Rotate");
+  Msg::Direct("                      - Select an entity");
+  Msg::Direct("                      - Accept a lasso zoom or a lasso selection"); 
+  Msg::Direct("  Ctrl+Left button    Start a lasso zoom or a lasso (un)selection"); 
+  Msg::Direct("  Middle button       - Zoom");
+  Msg::Direct("                      - Unselect an entity");
+  Msg::Direct("                      - Accept a lasso zoom or a lasso unselection");
+  Msg::Direct("  Ctrl+Middle button  Orthogonalize display"); 
+  Msg::Direct("  Right button        - Pan");
+  Msg::Direct("                      - Cancel a lasso zoom or a lasso (un)selection");
+  Msg::Direct("                      - Pop-up menu on post-processing view button");
+  Msg::Direct("  Ctrl+Right button   Reset to default viewpoint");   
+  Msg::Direct(" ");   
+  Msg::Direct("  For a 2 button mouse, Middle button = Shift+Left button");
+  Msg::Direct("  For a 1 button mouse, Middle button = Shift+Left button, "
+              "Right button = Alt+Left button");
+  Msg::Direct(" ");
+  GUI::instance()->messages->show();
+}
+
+static void help_command_line_cb(Fl_Widget *w, void *data)
+{
+  Msg::Direct(" ");
+  Print_Usage("gmsh");
+  GUI::instance()->messages->show();
+}
+
+static void help_online_cb(Fl_Widget *w, void *data)
+{
+  std::string prog = FixWindowsPath(CTX.web_browser);
+  char cmd[1024];
+  ReplaceMultiFormat(prog.c_str(), "http://geuz.org/gmsh/doc/texinfo/", cmd);
+  SystemCall(cmd);
+}
+
+static void help_about_cb(Fl_Widget *w, void *data)
+{
+  GUI::instance()->about->win->show();
+}
+
+void mod_geometry_cb(Fl_Widget *w, void *data)
+{
+  GUI::instance()->menu->setContext(menu_geometry, 0);
+}
+
+void mod_mesh_cb(Fl_Widget *w, void *data)
+{
+  GUI::instance()->menu->setContext(menu_mesh, 0);
+}
+
+void mod_solver_cb(Fl_Widget *w, void *data)
+{
+  GUI::instance()->menu->setContext(menu_solver, 0);
+}
+
+void mod_post_cb(Fl_Widget *w, void *data)
+{
+  GUI::instance()->menu->setContext(menu_post, 0);
+}
+
+void mod_back_cb(Fl_Widget *w, void *data)
+{
+  GUI::instance()->menu->setContext(NULL, -1);
+}
+
+void mod_forward_cb(Fl_Widget *w, void *data)
+{
+  GUI::instance()->menu->setContext(NULL, 1);
+}
+
+static void geometry_elementary_cb(Fl_Widget *w, void *data)
+{
+  GUI::instance()->menu->setContext(menu_geometry_elementary, 0);
+}
+
+static void geometry_physical_cb(Fl_Widget *w, void *data)
+{
+  GUI::instance()->menu->setContext(menu_geometry_physical, 0);
+}
+
+static void geometry_edit_cb(Fl_Widget *w, void *data)
+{
+  std::string prog = FixWindowsPath(CTX.editor);
+  std::string file = FixWindowsPath(CTX.filename);
+  char cmd[1024];
+  ReplaceMultiFormat(prog.c_str(), file.c_str(), cmd);
+  SystemCall(cmd);
+}
+
+void geometry_reload_cb(Fl_Widget *w, void *data)
+{
+  OpenProject(CTX.filename);
+  Draw();
+}
+
+static void geometry_elementary_add_cb(Fl_Widget *w, void *data)
+{
+  GUI::instance()->menu->setContext(menu_geometry_elementary_add, 0);
+}
+
+static void add_new_point()
+{
+  opt_geometry_points(0, GMSH_SET | GMSH_GUI, 1);
+  Draw();
+
+  GUI::instance()->geoContext->show(1);
+
+  while(1) {
+    GUI::instance()->graph[0]->gl->addPointMode = true;
+    Msg::StatusBar(3, false, "Move mouse and/or enter coordinates\n"
+        "[Press 'Shift' to hold position, 'e' to add point or 'q' to abort]");
+    std::vector<GVertex*> vertices;
+    std::vector<GEdge*> edges;
+    std::vector<GFace*> faces;
+    std::vector<GRegion*> regions;
+    std::vector<MElement*> elements;
+    char ib = SelectEntity(ENT_NONE, vertices, edges, faces, regions, elements);
+    if(ib == 'e'){
+      add_point(CTX.filename,
+                GUI::instance()->geoContext->input[2]->value(),
+                GUI::instance()->geoContext->input[3]->value(),
+                GUI::instance()->geoContext->input[4]->value(),
+                GUI::instance()->geoContext->input[5]->value());
+      GUI::instance()->resetVisibility();
+      Draw();
+    }
+    if(ib == 'q'){
+      GUI::instance()->graph[0]->gl->addPointMode = false;
+      break;
+    }
+  }
+
+  Msg::StatusBar(3, false, "");
+}
+
+static void add_new_multiline(std::string type)
+{
+  std::vector<GVertex*> vertices;
+  std::vector<GEdge*> edges;
+  std::vector<GFace*> faces;
+  std::vector<GRegion*> regions;
+  std::vector<MElement*> elements;
+  std::vector<int> p;
+
+  opt_geometry_points(0, GMSH_SET | GMSH_GUI, 1);
+  opt_geometry_lines(0, GMSH_SET | GMSH_GUI, 1);
+  Draw();
+
+  while(1) {
+    if(p.empty())
+      Msg::StatusBar(3, false, "Select control points\n"
+          "[Press 'e' to end selection or 'q' to abort]");
+    else
+      Msg::StatusBar(3, false, "Select control points\n"
+          "[Press 'e' to end selection, 'u' to undo last selection or 'q' to abort]");
+    char ib = SelectEntity(ENT_POINT, vertices, edges, faces, regions, elements);
+    if(ib == 'l') {
+      for(unsigned int i = 0; i < vertices.size(); i++){
+        HighlightEntity(vertices[i]);
+        p.push_back(vertices[i]->tag());
+      }
+      Draw();
+    }
+    if(ib == 'r') {
+      Msg::Warning("Entity de-selection not supported yet during multi-line creation");
+    }
+    if(ib == 'e') {
+      if(p.size() >= 2)
+	add_multline(type, p, CTX.filename);
+      GUI::instance()->resetVisibility();
+      ZeroHighlight();
+      Draw();
+      p.clear();
+    }
+    if(ib == 'u') {
+      if(p.size()){
+        ZeroHighlightEntityNum(p.back(), 0, 0, 0);
+        Draw();
+        p.pop_back();
+      }
+    }
+    if(ib == 'q') {
+      ZeroHighlight();
+      Draw();
+      break;
+    }
+  }
+
+  Msg::StatusBar(3, false, "");
+}
+
+static void add_new_line()
+{
+  std::vector<GVertex*> vertices;
+  std::vector<GEdge*> edges;
+  std::vector<GFace*> faces;
+  std::vector<GRegion*> regions;
+  std::vector<MElement*> elements;
+  std::vector<int> p;
+
+  opt_geometry_points(0, GMSH_SET | GMSH_GUI, 1);
+  opt_geometry_lines(0, GMSH_SET | GMSH_GUI, 1);
+  Draw();
+
+  while(1) {
+    if(p.empty())
+      Msg::StatusBar(3, false, "Select start point\n"
+          "[Press 'q' to abort]");
+    if(p.size() == 1)
+      Msg::StatusBar(3, false, "Select end point\n"
+          "[Press 'u' to undo last selection or 'q' to abort]");
+    char ib = SelectEntity(ENT_POINT, vertices, edges, faces, regions, elements);
+    if(ib == 'l') {
+      HighlightEntity(vertices[0]);
+      Draw();
+      p.push_back(vertices[0]->tag());
+    }
+    if(ib == 'r') {
+      Msg::Warning("Entity de-selection not supported yet during line creation");
+    }
+    if(ib == 'u') {
+      if(p.size()){
+        ZeroHighlightEntityNum(p.back(), 0, 0, 0);
+        Draw();
+        p.pop_back();
+      }
+    }
+    if(ib == 'q') {
+      ZeroHighlight();
+      Draw();
+      break;
+    }
+    if(p.size() == 2) {
+      add_multline("Line", p, CTX.filename);
+      GUI::instance()->resetVisibility();
+      ZeroHighlight();
+      Draw();
+      p.clear();
+    }
+  }
+
+  Msg::StatusBar(3, false, "");
+}
+
+static void add_new_circle()
+{
+  std::vector<GVertex*> vertices;
+  std::vector<GEdge*> edges;
+  std::vector<GFace*> faces;
+  std::vector<GRegion*> regions;
+  std::vector<MElement*> elements;
+  std::vector<int> p;
+
+  opt_geometry_points(0, GMSH_SET | GMSH_GUI, 1);
+  opt_geometry_lines(0, GMSH_SET | GMSH_GUI, 1);
+  Draw();
+
+  while(1) {
+    if(p.empty())
+      Msg::StatusBar(3, false, "Select start point\n"
+          "[Press 'q' to abort]");
+    if(p.size() == 1)
+      Msg::StatusBar(3, false, "Select center point\n"
+          "[Press 'u' to undo last selection or 'q' to abort]");
+    if(p.size() == 2)
+      Msg::StatusBar(3, false, "Select end point\n"
+          "[Press 'u' to undo last selection or 'q' to abort]");
+    char ib = SelectEntity(ENT_POINT, vertices, edges, faces, regions, elements);
+    if(ib == 'l') {
+      HighlightEntity(vertices[0]);
+      Draw();
+      p.push_back(vertices[0]->tag());
+    }
+    if(ib == 'r') {
+      Msg::Warning("Entity de-selection not supported yet during circle creation");
+    }
+    if(ib == 'u') {
+      if(p.size()){
+        ZeroHighlightEntityNum(p.back(), 0, 0, 0);
+        Draw();
+        p.pop_back();
+      }
+    }
+    if(ib == 'q') {
+      ZeroHighlight();
+      Draw();
+      break;
+    }
+    if(p.size() == 3) {
+      add_circ(p[0], p[1], p[2], CTX.filename); // begin, center, end
+      GUI::instance()->resetVisibility();
+      ZeroHighlight();
+      Draw();
+      p.clear();
+    }
+  }
+
+  Msg::StatusBar(3, false, "");
+}
+
+static void add_new_ellipse()
+{
+  std::vector<GVertex*> vertices;
+  std::vector<GEdge*> edges;
+  std::vector<GFace*> faces;
+  std::vector<GRegion*> regions;
+  std::vector<MElement*> elements;
+  std::vector<int> p;
+
+  opt_geometry_points(0, GMSH_SET | GMSH_GUI, 1);
+  opt_geometry_lines(0, GMSH_SET | GMSH_GUI, 1);
+  Draw();
+
+  while(1) {
+    if(p.empty())
+      Msg::StatusBar(3, false, "Select start point\n"
+          "[Press 'q' to abort]");
+    if(p.size() == 1)
+      Msg::StatusBar(3, false, "Select center point\n"
+          "[Press 'u' to undo last selection or 'q' to abort]");
+    if(p.size() == 2)
+      Msg::StatusBar(3, false, "Select major axis point\n"
+          "[Press 'u' to undo last selection or 'q' to abort]");
+    if(p.size() == 3)
+      Msg::StatusBar(3, false, "Select end point\n"
+          "[Press 'u' to undo last selection or 'q' to abort]");
+    char ib = SelectEntity(ENT_POINT, vertices, edges, faces, regions, elements);
+    if(ib == 'l') {
+      HighlightEntity(vertices[0]);
+      Draw();
+      p.push_back(vertices[0]->tag());
+    }
+    if(ib == 'r') {
+      Msg::Warning("Entity de-selection not supported yet during ellipse creation");
+    }
+    if(ib == 'u') {
+      if(p.size()){
+        ZeroHighlightEntityNum(p.back(), 0, 0, 0);
+        Draw();
+        p.pop_back();
+      }
+    }
+    if(ib == 'q') {
+      ZeroHighlight();
+      Draw();
+      break;
+    }
+    if(p.size() == 4) {
+      add_ell(p[0], p[1], p[2], p[3], CTX.filename);
+      GUI::instance()->resetVisibility();
+      ZeroHighlight();
+      Draw();
+      p.clear();
+    }
+  }
+
+  Msg::StatusBar(3, false, "");
+}
+
+static int select_contour(int type, int num, List_T * List)
+{
+  int k = 0, ip;
+
+  switch (type) {
+  case ENT_LINE:
+    k = allEdgesLinked(num, List);
+    for(int i = 0; i < List_Nbr(List); i++) {
+      List_Read(List, i, &ip);
+      HighlightEntityNum(0, abs(ip), 0, 0);
+    }
+    break;
+  case ENT_SURFACE:
+    k = allFacesLinked(num, List);
+    for(int i = 0; i < List_Nbr(List); i++) {
+      List_Read(List, i, &ip);
+      HighlightEntityNum(0, 0, abs(ip), 0);
+    }
+    break;
+  }
+
+  Draw();
+  return k;
+}
+
+static void add_new_surface_volume(int mode)
+{
+  std::vector<GVertex*> vertices;
+  std::vector<GEdge*> edges;
+  std::vector<GFace*> faces;
+  std::vector<GRegion*> regions;
+  std::vector<MElement*> elements;
+  int type, num;
+
+  List_T *List1 = List_Create(10, 10, sizeof(int));
+  List_T *List2 = List_Create(10, 10, sizeof(int));
+
+  if(mode == 2) {
+    type = ENT_SURFACE;
+    opt_geometry_surfaces(0, GMSH_SET | GMSH_GUI, 1);
+    opt_geometry_volumes(0, GMSH_SET | GMSH_GUI, 1);
+  }
+  else {
+    type = ENT_LINE;
+    opt_geometry_lines(0, GMSH_SET | GMSH_GUI, 1);
+    opt_geometry_surfaces(0, GMSH_SET | GMSH_GUI, 1);
+  }
+  Draw();
+
+  while(1) {
+    List_Reset(List1);
+    List_Reset(List2);
+
+    while(1) {
+      if(type == ENT_LINE){
+        if(!List_Nbr(List1))
+          Msg::StatusBar(3, false, "Select surface boundary\n"
+              "[Press 'q' to abort]");
+        else
+          Msg::StatusBar(3, false, "Select surface boundary\n"
+              "[Press 'u' to undo last selection or 'q' to abort]");
+      }
+      else{
+        if(!List_Nbr(List1))
+          Msg::StatusBar(3, false, "Select volume boundary\n"
+              "[Press 'q' to abort]");
+        else
+          Msg::StatusBar(3, false, "Select volume boundary\n"
+              "[Press 'u' to undo last selection or 'q' to abort]");
+      }
+
+      char ib = SelectEntity(type, vertices, edges, faces, regions, elements);
+      if(ib == 'q') {
+        ZeroHighlight();
+        Draw();
+        goto stopall;
+      }
+      if(ib == 'u') {
+        if(List_Nbr(List1) > 0){
+          List_Read(List1, List_Nbr(List1)-1, &num);
+          ZeroHighlightEntityNum(0,
+                                 (type == ENT_LINE) ? abs(num) : 0, 
+                                 (type != ENT_LINE) ? abs(num) : 0,
+                                 0);
+          List_Pop(List1);
+          Draw();
+        }
+      }
+      if(ib == 'r') {
+        Msg::Warning("Entity de-selection not supported yet during "
+                     "surface/volume creation");
+      }
+      if(ib == 'l') {
+        int num = (type == ENT_LINE) ? edges[0]->tag() : faces[0]->tag();
+        if(select_contour(type, num, List1)) {
+          if(type == ENT_LINE)
+            add_lineloop(List1, CTX.filename, &num);
+          else
+            add_surfloop(List1, CTX.filename, &num);
+          List_Reset(List1);
+          List_Add(List2, &num);
+          while(1) {
+            if(!List_Nbr(List1))
+              Msg::StatusBar
+                (3, false, "Select hole boundaries (if none, press 'e')\n"
+                 "[Press 'e' to end selection or 'q' to abort]");
+            else
+              Msg::StatusBar
+                (3, false, "Select hole boundaries\n"
+                 "[Press 'e' to end selection, 'u' to undo last selection "
+                 "or 'q' to abort]");
+            ib = SelectEntity(type, vertices, edges, faces, regions, elements);
+            if(ib == 'q') {
+              ZeroHighlight();
+              Draw();
+              goto stopall;
+            }
+            if(ib == 'e') {
+              ZeroHighlight();
+              Draw();
+              List_Reset(List1);
+              break;
+            }
+            if(ib == 'u') {
+              if(List_Nbr(List1) > 0){
+                List_Read(List1, List_Nbr(List1)-1, &num);
+                ZeroHighlightEntityNum(0,
+                                       (type == ENT_LINE) ? abs(num) : 0, 
+                                       (type != ENT_LINE) ? abs(num) : 0,
+                                       0);
+                List_Pop(List1);
+                Draw();
+              }
+            }
+            if(ib == 'l') {
+              num = (type == ENT_LINE) ? edges[0]->tag() : faces[0]->tag();
+              if(select_contour(type, num, List1)) {
+                if(type == ENT_LINE)
+                  add_lineloop(List1, CTX.filename, &num);
+                else
+                  add_surfloop(List1, CTX.filename, &num);
+                List_Reset(List1);
+                List_Add(List2, &num);
+              }
+            }
+            if(ib == 'r') {
+              Msg::Warning("Entity de-selection not supported yet during "
+                           "surface/volume creation");
+            }
+          }
+          if(List_Nbr(List2)) {
+            switch (mode) {
+            case 0: add_surf("Plane Surface", List2, CTX.filename); break;
+            case 1: add_surf("Ruled Surface", List2, CTX.filename); break;
+            case 2: add_vol(List2, CTX.filename); break;
+            }
+            GUI::instance()->resetVisibility();
+            ZeroHighlight();
+            Draw();
+            break;
+          }
+        } // if select_contour
+      }
+    }
+  }
+
+ stopall:
+  List_Delete(List1);
+  List_Delete(List2);
+
+  Msg::StatusBar(3, false, "");
+}
+
+static void geometry_elementary_add_new_cb(Fl_Widget *w, void *data)
+{
+  if(!data){
+    GUI::instance()->menu->setContext(menu_geometry_elementary_add_new, 0);
+    return;
+  }
+
+  std::string str((const char*)data);
+  if(str == "Parameter")
+    GUI::instance()->geoContext->show(0);
+  else if(str == "Point")
+    add_new_point();
+  else if(str == "Line")
+    add_new_line();
+  else if(str == "Spline")
+    add_new_multiline(str);
+  else if(str == "BSpline")
+    add_new_multiline(str);
+  else if(str == "Circle")
+    add_new_circle();
+  else if(str == "Ellipse")
+    add_new_ellipse();
+  else if(str == "Plane Surface")
+    add_new_surface_volume(0);
+  else if(str == "Ruled Surface")
+    add_new_surface_volume(1);
+  else if(str == "Volume")
+    add_new_surface_volume(2);
+  else
+    Msg::Error("Unknown entity to create: %s", str.c_str());
+}
+
+static void split_selection()
+{
+  opt_geometry_lines(0, GMSH_SET | GMSH_GUI, 1);
+  Draw();
+  Msg::StatusBar(3, false, "Select a line to split\n"
+          "[Press 'q' to abort]");
+  std::vector<GVertex*> vertices;
+  std::vector<GEdge*> edges;
+  std::vector<GFace*> faces;
+  std::vector<GRegion*> regions;
+  std::vector<MElement*> elements;
+  GEdge* edge_to_split = NULL;
+  while(1){
+    char ib = SelectEntity(2, vertices, edges, faces, regions, elements);
+    if(ib == 'q')
+      break;
+    if(!edges.empty()){
+      edge_to_split = edges[0];
+      HighlightEntity(edges[0]);
+      break;
+    }
+  }
+  Msg::StatusBar(3, false, "");
+  if(edges.empty())
+    return;
+  List_T *List1 = List_Create(5, 5, sizeof(int));
+  Msg::StatusBar(3, false, "Select break points\n"
+                 "[Press 'e' to end selection or 'q' to abort]");
+  opt_geometry_points(0, GMSH_SET | GMSH_GUI, 1);
+  Draw();
+  while(1){
+    char ib = SelectEntity(1, vertices, edges, faces, regions, elements);
+    if(ib == 'q')
+      break;
+    if(ib == 'e'){
+      split_edge(edge_to_split->tag(), List1, CTX.filename);
+      break;
+    }
+    if(!vertices.empty()){
+      for(unsigned int i = 0; i < vertices.size(); i++){
+        int tag = vertices[i]->tag();
+        int index = List_ISearchSeq(List1, &tag, fcmp_int); 
+        if(index < 0) List_Add(List1, &tag);
+        HighlightEntity(vertices[i]);
+      }
+    }
+  }
+  Msg::StatusBar(3, false, "");
+  GUI::instance()->resetVisibility();
+  ZeroHighlight();
+  Draw();
+}
+
+static void action_point_line_surface_volume(int action, int mode, const char *what)
+{
+  std::vector<GVertex*> vertices;
+  std::vector<GEdge*> edges;
+  std::vector<GFace*> faces;
+  std::vector<GRegion*> regions;
+  std::vector<MElement*> elements;
+  int type;
+  const char *str;
+
+  if(!strcmp(what, "Point")) {
+    type = ENT_POINT;
+    str = "points";
+    opt_geometry_points(0, GMSH_SET | GMSH_GUI, 1);
+  }
+  else if(!strcmp(what, "Line")) {
+    type = ENT_LINE;
+    str = "lines";
+    opt_geometry_lines(0, GMSH_SET | GMSH_GUI, 1);
+  }
+  else if(!strcmp(what, "Surface")) {
+    type = ENT_SURFACE;
+    str = "surfaces";
+    opt_geometry_surfaces(0, GMSH_SET | GMSH_GUI, 1);
+  }
+  else if(!strcmp(what, "Volume")) {
+    type = ENT_VOLUME;
+    str = "volumes";
+    opt_geometry_volumes(0, GMSH_SET | GMSH_GUI, 1);
+  }
+  else{
+    Msg::Error("Unknown entity to select");
+    return;
+  }
+
+  if(action == 8){
+    GUI::instance()->meshContext->show(0);
+  }
+
+  Draw();
+    
+  List_T *List1 = List_Create(5, 5, sizeof(int));
+  while(1) {
+    if(!List_Nbr(List1))
+      Msg::StatusBar(3, false, "Select %s\n"
+          "[Press 'e' to end selection or 'q' to abort]", str);
+    else
+      Msg::StatusBar(3, false, "Select %s\n"
+          "[Press 'e' to end selection, 'u' to undo last selection or 'q' to abort]", str);
+
+    char ib = SelectEntity(type, vertices, edges, faces, regions, elements);
+    if(ib == 'l') {
+      // we don't use List_Insert in order to keep the original
+      // ordering (this is slower, but this way undo works as
+      // expected)
+      int tag;
+      switch (type) {
+      case ENT_POINT: 
+        for(unsigned int i = 0; i < vertices.size(); i++){
+          HighlightEntity(vertices[i]);
+          tag = vertices[i]->tag();
+          if(List_ISearchSeq(List1, &tag, fcmp_int) < 0)
+            List_Add(List1, &tag);
+        }
+        break;
+      case ENT_LINE:
+        for(unsigned int i = 0; i < edges.size(); i++){
+          HighlightEntity(edges[i]);
+          tag = edges[i]->tag();
+          if(List_ISearchSeq(List1, &tag, fcmp_int) < 0)
+            List_Add(List1, &tag);
+        }
+        break;
+      case ENT_SURFACE:
+        for(unsigned int i = 0; i < faces.size(); i++){
+          HighlightEntity(faces[i]);
+          tag = faces[i]->tag();
+          if(List_ISearchSeq(List1, &tag, fcmp_int) < 0)
+            List_Add(List1, &tag);
+        }
+        break;
+      case ENT_VOLUME:
+        for(unsigned int i = 0; i < regions.size(); i++){
+          HighlightEntity(regions[i]);
+          tag = regions[i]->tag();
+          if(List_ISearchSeq(List1, &tag, fcmp_int) < 0)
+            List_Add(List1, &tag);
+        }
+        break;
+      }
+      Draw();
+    }
+    if(ib == 'r') {
+      // we don't use List_Suppress in order to keep the original
+      // ordering (this is slower, but this way undo works as
+      // expected)
+      int index, tag;
+      switch (type) {
+      case ENT_POINT:
+        for(unsigned int i = 0; i < vertices.size(); i++){
+          tag = vertices[i]->tag();
+          index = List_ISearchSeq(List1, &tag, fcmp_int); 
+          if(index >= 0) List_PSuppress(List1, index);
+          ZeroHighlightEntityNum(tag, 0, 0, 0);
+        }
+        break;
+      case ENT_LINE:
+        for(unsigned int i = 0; i < edges.size(); i++){
+          tag = edges[i]->tag();
+          index = List_ISearchSeq(List1, &tag, fcmp_int); 
+          if(index >= 0) List_PSuppress(List1, index);
+          ZeroHighlightEntityNum(0, tag, 0, 0);
+        }
+        break;
+      case ENT_SURFACE:
+        for(unsigned int i = 0; i < faces.size(); i++){
+          tag = faces[i]->tag();
+          index = List_ISearchSeq(List1, &tag, fcmp_int); 
+          if(index >= 0) List_PSuppress(List1, index);
+          ZeroHighlightEntityNum(0, 0, tag, 0);
+        }
+        break;
+      case ENT_VOLUME:
+        for(unsigned int i = 0; i < regions.size(); i++){
+          tag = regions[i]->tag();
+          index = List_ISearchSeq(List1, &tag, fcmp_int); 
+          if(index >= 0) List_PSuppress(List1, index);
+          ZeroHighlightEntityNum(0, 0, 0, tag);
+        }
+        break;
+      }
+      Draw();
+    }
+    if(ib == 'u') {
+      if(List_Nbr(List1)) {
+        int num;
+        List_Read(List1, List_Nbr(List1) - 1, &num);
+        ZeroHighlightEntityNum((type == ENT_POINT) ? num : 0,
+                               (type == ENT_LINE) ? num : 0,
+                               (type == ENT_SURFACE) ? num : 0,
+                               (type == ENT_VOLUME) ? num : 0);
+        Draw();
+        List_Pop(List1);
+      }
+    }
+    if(ib == 'i') {
+      Msg::Error("Inverting selection!");
+    }
+    if(ib == 'e') {
+      if(List_Nbr(List1)){
+        switch (action) {
+        case 0:
+          translate(mode, List1, CTX.filename, what,
+                    GUI::instance()->geoContext->input[6]->value(),
+                    GUI::instance()->geoContext->input[7]->value(),
+                    GUI::instance()->geoContext->input[8]->value());
+          break;
+        case 1:
+          rotate(mode, List1, CTX.filename, what,
+                 GUI::instance()->geoContext->input[12]->value(),
+                 GUI::instance()->geoContext->input[13]->value(),
+                 GUI::instance()->geoContext->input[14]->value(),
+                 GUI::instance()->geoContext->input[9]->value(),
+                 GUI::instance()->geoContext->input[10]->value(),
+                 GUI::instance()->geoContext->input[11]->value(),
+                 GUI::instance()->geoContext->input[15]->value());
+          break;
+        case 2:
+          dilate(mode, List1, CTX.filename, what,
+                 GUI::instance()->geoContext->input[16]->value(),
+                 GUI::instance()->geoContext->input[17]->value(),
+                 GUI::instance()->geoContext->input[18]->value(),
+                 GUI::instance()->geoContext->input[19]->value());
+          break;
+        case 3:
+          symmetry(mode, List1, CTX.filename, what,
+                   GUI::instance()->geoContext->input[20]->value(),
+                   GUI::instance()->geoContext->input[21]->value(),
+                   GUI::instance()->geoContext->input[22]->value(),
+                   GUI::instance()->geoContext->input[23]->value());
+          break;
+        case 4:
+          extrude(List1, CTX.filename, what,
+                  GUI::instance()->geoContext->input[6]->value(),
+                  GUI::instance()->geoContext->input[7]->value(),
+                  GUI::instance()->geoContext->input[8]->value());
+          break;
+        case 5:
+          protude(List1, CTX.filename, what,
+                  GUI::instance()->geoContext->input[12]->value(),
+                  GUI::instance()->geoContext->input[13]->value(),
+                  GUI::instance()->geoContext->input[14]->value(),
+                  GUI::instance()->geoContext->input[9]->value(),
+                  GUI::instance()->geoContext->input[10]->value(),
+                  GUI::instance()->geoContext->input[11]->value(),
+                  GUI::instance()->geoContext->input[15]->value());
+          break;
+        case 6:
+          delet(List1, CTX.filename, what);
+          break;
+        case 7:
+          add_physical(what, List1, CTX.filename);
+          break;
+        case 8:
+          add_charlength(List1, CTX.filename, GUI::instance()->meshContext->input[0]->value());
+          break;
+        case 9:
+          add_recosurf(List1, CTX.filename);
+          break;
+
+        default:
+          Msg::Error("Unknown action on selected entities");
+          break;
+        }
+        List_Reset(List1);
+        GUI::instance()->resetVisibility();
+        ZeroHighlight();
+        if(action <= 6) SetBoundingBox();
+        Draw();
+      }
+    }
+    if(ib == 'q') {
+      ZeroHighlight();
+      Draw();
+      break;
+    }
+  }
+  List_Delete(List1);
+
+  Msg::StatusBar(3, false, "");
+}
+  
+static void geometry_elementary_add_translate_cb(Fl_Widget *w, void *data)
+{
+  if(!data){
+    GUI::instance()->menu->setContext(menu_geometry_elementary_add_translate, 0);
+    return;
+  }
+  GUI::instance()->geoContext->show(2);
+  action_point_line_surface_volume(0, 1, (const char*)data);
+}
+
+static void geometry_elementary_add_rotate_cb(Fl_Widget *w, void *data)
+{
+  if(!data){
+    GUI::instance()->menu->setContext(menu_geometry_elementary_add_rotate, 0);
+    return;
+  }
+  GUI::instance()->geoContext->show(3);
+  action_point_line_surface_volume(1, 1, (const char*)data);
+}
+
+static void geometry_elementary_add_scale_cb(Fl_Widget *w, void *data)
+{
+  if(!data){
+    GUI::instance()->menu->setContext(menu_geometry_elementary_add_scale, 0);
+    return;
+  }
+  GUI::instance()->geoContext->show(4);
+  action_point_line_surface_volume(2, 1, (const char*)data);
+}
+
+static void geometry_elementary_add_symmetry_cb(Fl_Widget *w, void *data)
+{
+  if(!data){
+    GUI::instance()->menu->setContext(menu_geometry_elementary_add_symmetry, 0);
+    return;
+  }
+  GUI::instance()->geoContext->show(5);
+  action_point_line_surface_volume(3, 1, (const char*)data);
+}
+
+static void geometry_elementary_translate_cb(Fl_Widget *w, void *data)
+{
+  if(!data){
+    GUI::instance()->menu->setContext(menu_geometry_elementary_translate, 0);
+    return;
+  }
+  GUI::instance()->geoContext->show(2);
+  action_point_line_surface_volume(0, 0, (const char*)data);
+}
+
+static void geometry_elementary_rotate_cb(Fl_Widget *w, void *data)
+{
+  if(!data){
+    GUI::instance()->menu->setContext(menu_geometry_elementary_rotate, 0);
+    return;
+  }
+  GUI::instance()->geoContext->show(3);
+  action_point_line_surface_volume(1, 0, (const char*)data);
+}
+
+static void geometry_elementary_scale_cb(Fl_Widget *w, void *data)
+{
+  if(!data){
+    GUI::instance()->menu->setContext(menu_geometry_elementary_scale, 0);
+    return;
+  }
+  GUI::instance()->geoContext->show(4);
+  action_point_line_surface_volume(2, 0, (const char*)data);
+}
+
+static void geometry_elementary_symmetry_cb(Fl_Widget *w, void *data)
+{
+  if(!data){
+    GUI::instance()->menu->setContext(menu_geometry_elementary_symmetry, 0);
+    return;
+  }
+  GUI::instance()->geoContext->show(5);
+  action_point_line_surface_volume(3, 0, (const char*)data);
+}
+
+static void geometry_elementary_extrude_cb(Fl_Widget *w, void *data)
+{
+  GUI::instance()->menu->setContext(menu_geometry_elementary_extrude, 0);
+}
+
+static void geometry_elementary_extrude_translate_cb(Fl_Widget *w, void *data)
+{
+  if(!data){
+    GUI::instance()->menu->setContext(menu_geometry_elementary_extrude_translate, 0);
+    return;
+  }
+  GUI::instance()->geoContext->show(2);
+  action_point_line_surface_volume(4, 0, (const char*)data);
+}
+
+static void geometry_elementary_extrude_rotate_cb(Fl_Widget *w, void *data)
+{
+  if(!data){
+    GUI::instance()->menu->setContext(menu_geometry_elementary_extrude_rotate, 0);
+    return;
+  }
+  GUI::instance()->geoContext->show(3);
+  action_point_line_surface_volume(5, 0, (const char*)data);
+}
+
+static void geometry_elementary_delete_cb(Fl_Widget *w, void *data)
+{
+  if(!data){
+    GUI::instance()->menu->setContext(menu_geometry_elementary_delete, 0);
+    return;
+  }
+  action_point_line_surface_volume(6, 0, (const char*)data);
+}
+
+static void geometry_elementary_split_cb(Fl_Widget *w, void *data)
+{
+  if(!data){
+    GUI::instance()->menu->setContext(menu_geometry_elementary_split, 0);
+    return;
+  }
+  split_selection();
+}
+
+static void geometry_elementary_coherence_cb(Fl_Widget *w, void *data)
+{
+  coherence(CTX.filename);
+}
+
+static void geometry_physical_add_cb(Fl_Widget *w, void *data)
+{
+  if(!data){
+    GUI::instance()->menu->setContext(menu_geometry_physical_add, 0);
+    return;
+  }
+  std::string str((const char*)data);
+  if(str == "Point")
+    GUI::instance()->callForSolverPlugin(0);
+  else if(str == "Line")
+    GUI::instance()->callForSolverPlugin(1);
+
+  action_point_line_surface_volume(7, 0, str.c_str());
+}
+
+static void mesh_save_cb(Fl_Widget *w, void *data)
+{
+  char name[256];
+  if(CTX.output_filename)
+    strcpy(name, CTX.output_filename);
+  else
+    GetDefaultFileName(CTX.mesh.format, name);
+  if(CTX.confirm_overwrite) {
+    if(!StatFile(name))
+      if(!fl_choice("File '%s' already exists.\n\nDo you want to replace it?",
+                    "Cancel", "Replace", NULL, name))
+        return;
+  }
+  CreateOutputFile(name, CTX.mesh.format);
+}
+
+static void mesh_define_cb(Fl_Widget *w, void *data)
+{
+  GUI::instance()->menu->setContext(menu_mesh_define, 0);
+}
+
+void mesh_1d_cb(Fl_Widget *w, void *data)
+{
+  GModel::current()->mesh(1);
+  Draw();
+  Msg::StatusBar(2, false, " ");
+}
+
+void mesh_2d_cb(Fl_Widget *w, void *data)
+{
+  GModel::current()->mesh(2);
+  Draw();
+  Msg::StatusBar(2, false, " ");
+}
+
+void mesh_3d_cb(Fl_Widget *w, void *data)
+{
+  GModel::current()->mesh(3);
+  Draw();
+  Msg::StatusBar(2, false, " ");
+}
+
+static void mesh_delete_cb(Fl_Widget *w, void *data)
+{
+  GUI::instance()->menu->setContext(menu_mesh_delete, 0);
+}
+
+static void mesh_delete_parts_cb(Fl_Widget *w, void *data)
+{
+  const char *str = (const char*)data;
+  int what;
+
+  if(!strcmp(str, "elements")){
+    CTX.pick_elements = 1;
+    what = ENT_ALL;
+  }
+  else if(!strcmp(str, "lines")){
+    CTX.pick_elements = 0;
+    what = ENT_LINE;
+  }
+  else if(!strcmp(str, "surfaces")){
+    CTX.pick_elements = 0;
+    what = ENT_SURFACE;
+  }
+  else if(!strcmp(str, "volumes")){
+    CTX.pick_elements = 0;
+    what = ENT_VOLUME;
+  }
+  else
+    return;
+
+  std::vector<GVertex*> vertices;
+  std::vector<GEdge*> edges;
+  std::vector<GFace*> faces;
+  std::vector<GRegion*> regions;
+  std::vector<MElement*> elements;
+
+  std::vector<MElement*> ele;
+  std::vector<GEntity*> ent;
+
+  while(1) {
+    CTX.mesh.changed = ENT_ALL;
+    Draw();
+
+    if(ele.size() || ent.size())
+      Msg::StatusBar(3, false, "Select %s\n"
+                     "[Press 'e' to end selection, 'u' to undo last selection or "
+                     "'q' to abort]", str);
+    else
+      Msg::StatusBar(3, false, "Select %s\n"
+          "[Press 'e' to end selection or 'q' to abort]", str);
+
+    char ib = SelectEntity(what, vertices, edges, faces, regions, elements);
+    if(ib == 'l') {
+      if(CTX.pick_elements){
+        for(unsigned int i = 0; i < elements.size(); i++){
+          if(elements[i]->getVisibility() != 2){
+            elements[i]->setVisibility(2); ele.push_back(elements[i]);
+          }
+        }
+      }
+      else{
+        for(unsigned int i = 0; i < edges.size(); i++){
+          if(edges[i]->getSelection() != 1){
+            edges[i]->setSelection(1); ent.push_back(edges[i]);
+          }
+        }
+        for(unsigned int i = 0; i < faces.size(); i++){
+          if(faces[i]->getSelection() != 1){
+            faces[i]->setSelection(1); ent.push_back(faces[i]);
+          }
+        }
+        for(unsigned int i = 0; i < regions.size(); i++){
+          if(regions[i]->getSelection() != 1){
+            regions[i]->setSelection(1); ent.push_back(regions[i]);
+          }
+        }
+      }
+    }
+    if(ib == 'r') {
+      if(CTX.pick_elements){
+        for(unsigned int i = 0; i < elements.size(); i++)
+          elements[i]->setVisibility(1);
+      }
+      else{
+        for(unsigned int i = 0; i < edges.size(); i++)
+          edges[i]->setSelection(0);
+        for(unsigned int i = 0; i < faces.size(); i++)
+          faces[i]->setSelection(0);
+        for(unsigned int i = 0; i < regions.size(); i++)
+          regions[i]->setSelection(0);
+      }
+    }
+    if(ib == 'u') {
+      if(CTX.pick_elements){
+        if(ele.size()){
+          ele[ele.size() - 1]->setVisibility(1);
+          ele.pop_back();
+        }
+      }
+      else{
+        if(ent.size()){
+          ent[ent.size() - 1]->setSelection(0);
+          ent.pop_back();
+        }
+      }
+    }
+    if(ib == 'e') {
+      if(CTX.pick_elements){
+        for(unsigned int i = 0; i < ele.size(); i++)
+          if(ele[i]->getVisibility() == 2) ele[i]->setVisibility(0);
+      }
+      else{
+        for(unsigned int i = 0; i < ent.size(); i++)
+          if(ent[i]->getSelection() == 1) ent[i]->setVisibility(0);
+      }
+      GModel::current()->removeInvisibleElements();
+      ele.clear();
+      ent.clear();
+    }
+    if(ib == 'q') {
+      ZeroHighlight();
+      break;
+    }
+  }
+
+  CTX.mesh.changed = ENT_ALL;
+  CTX.pick_elements = 0;
+  Draw();  
+  Msg::StatusBar(3, false, "");
+}
+
+static void mesh_update_edges_cb(Fl_Widget *w, void *data)
+{
+  Msg::Error("Update edges not implemented yet");
+}
+
+static void mesh_remesh_cb(Fl_Widget *w, void *data)
+{
+  Msg::Error("Remesh not implemented yet");
+}
+
+static void mesh_inspect_cb(Fl_Widget *w, void *data)
+{
+  std::vector<GVertex*> vertices;
+  std::vector<GEdge*> edges;
+  std::vector<GFace*> faces;
+  std::vector<GRegion*> regions;
+  std::vector<MElement*> elements;
+
+  CTX.pick_elements = 1;
+  CTX.mesh.changed = ENT_ALL;
+  Draw();
+
+  while(1) {
+    Msg::StatusBar(3, false, "Select element\n[Press 'q' to abort]");
+    char ib = SelectEntity(ENT_ALL, vertices, edges, faces, regions, elements);
+    if(ib == 'l') {
+      if(elements.size()){
+        ZeroHighlight();
+        elements[0]->setVisibility(2);
+        Msg::Direct("Element %d:", elements[0]->getNum());
+	int type = elements[0]->getTypeForMSH();
+	const char *name;
+	MElement::getInfoMSH(type, &name);
+        Msg::Direct("  Type: %d ('%s')", type, name); 
+        Msg::Direct("  Dimension: %d", elements[0]->getDim());
+        Msg::Direct("  Order: %d", elements[0]->getPolynomialOrder()); 
+        Msg::Direct("  Partition: %d", elements[0]->getPartition()); 
+        char tmp1[32], tmp2[512];
+        sprintf(tmp2, "  Vertices:");
+        for(int i = 0; i < elements[0]->getNumVertices(); i++){
+          sprintf(tmp1, " %d", elements[0]->getVertex(i)->getNum());
+          strcat(tmp2, tmp1);
+        }
+        Msg::Direct(tmp2);
+        SPoint3 pt = elements[0]->barycenter();
+        Msg::Direct("  Barycenter: (%g,%g,%g)", pt[0], pt[1], pt[2]);
+        Msg::Direct("  Rho: %g", elements[0]->rhoShapeMeasure());
+        Msg::Direct("  Gamma: %g", elements[0]->gammaShapeMeasure());
+        Msg::Direct("  Eta: %g", elements[0]->etaShapeMeasure());
+        Msg::Direct("  Disto: %g", elements[0]->distoShapeMeasure());
+        CTX.mesh.changed = ENT_ALL;
+        Draw();
+        GUI::instance()->messages->show();
+      }
+    }
+    if(ib == 'q') {
+      ZeroHighlight();
+      break;
+    }
+  }
+
+  CTX.pick_elements = 0;
+  CTX.mesh.changed = ENT_ALL;
+  Draw();
+  Msg::StatusBar(3, false, "");
+}
+
+static void mesh_degree_cb(Fl_Widget *w, void *data)
+{
+  if((long)data == 2)
+    SetOrderN(GModel::current(), 2, CTX.mesh.second_order_linear, 
+              CTX.mesh.second_order_incomplete);
+  else
+    SetOrder1(GModel::current());
+  CTX.mesh.changed |= (ENT_LINE | ENT_SURFACE | ENT_VOLUME);
+  Draw();
+  Msg::StatusBar(2, false, " ");
+}
+
+static void mesh_optimize_cb(Fl_Widget *w, void *data)
+{
+  if(CTX.threads_lock) {
+    Msg::Info("I'm busy! Ask me that later...");
+    return;
+  }
+  CTX.threads_lock = 1;
+  OptimizeMesh(GModel::current());
+  CTX.threads_lock = 0;
+  CTX.mesh.changed |= (ENT_LINE | ENT_SURFACE | ENT_VOLUME);
+  Draw();
+  Msg::StatusBar(2, false, " ");
+}
+
+static void mesh_refine_cb(Fl_Widget *w, void *data)
+{
+  RefineMesh(GModel::current(), CTX.mesh.second_order_linear);
+  CTX.mesh.changed |= (ENT_LINE | ENT_SURFACE | ENT_VOLUME);
+  Draw();
+  Msg::StatusBar(2, false, " ");
+}
+
+static void mesh_optimize_netgen_cb(Fl_Widget *w, void *data)
+{
+  if(CTX.threads_lock) {
+    Msg::Info("I'm busy! Ask me that later...");
+    return;
+  }
+  CTX.threads_lock = 1;
+  OptimizeMeshNetgen(GModel::current());
+  CTX.threads_lock = 0;
+  CTX.mesh.changed |= (ENT_LINE | ENT_SURFACE | ENT_VOLUME);
+  Draw();
+  Msg::StatusBar(2, false, " ");
+}
+
+static void mesh_partition_cb(Fl_Widget *w, void *data)
+{
+  partition_dialog();
+}
+
+static void mesh_define_length_cb(Fl_Widget *w, void *data)
+{
+  action_point_line_surface_volume(8, 0, "Point");
+}
+
+static void mesh_define_recombine_cb(Fl_Widget *w, void *data)
+{
+  action_point_line_surface_volume(9, 0, "Surface");
+}
+
+static void mesh_define_transfinite_cb(Fl_Widget *w, void *data)
+{
+  GUI::instance()->menu->setContext(menu_mesh_define_transfinite, 0);
+}
+
+static void add_transfinite(int dim)
+{
+  std::vector<GVertex*> vertices;
+  std::vector<GEdge*> edges;
+  std::vector<GFace*> faces;
+  std::vector<GRegion*> regions;
+  std::vector<MElement*> elements;
+  std::vector<int> p;
+  char ib;
+
+  opt_geometry_points(0, GMSH_SET | GMSH_GUI, 1);
+  switch (dim) {
+  case 1: opt_geometry_lines(0, GMSH_SET | GMSH_GUI, 1); break;
+  case 2: opt_geometry_surfaces(0, GMSH_SET | GMSH_GUI, 1); break;
+  case 3: opt_geometry_volumes(0, GMSH_SET | GMSH_GUI, 1); break;
+  }
+  Draw();
+
+  while(1) {
+    switch (dim) {
+    case 1:
+      if(p.empty())
+        Msg::StatusBar(3, false, "Select lines\n"
+            "[Press 'e' to end selection or 'q' to abort]");
+      else
+        Msg::StatusBar(3, false, "Select lines\n"
+            "[Press 'e' to end selection, 'u' to undo last selection or 'q' to abort]");
+      ib = SelectEntity(ENT_LINE, vertices, edges, faces, regions, elements);
+      break;
+    case 2:
+      Msg::StatusBar(3, false, "Select surface\n[Press 'q' to abort]");
+      ib = SelectEntity(ENT_SURFACE, vertices, edges, faces, regions, elements);
+      break;
+    case 3:
+      Msg::StatusBar(3, false, "Select volume\n[Press 'q' to abort]");
+      ib = SelectEntity(ENT_VOLUME, vertices, edges, faces, regions, elements);
+      break;
+    default:
+      ib = 'l';
+      break;
+    }
+
+    if(ib == 'e') {
+      if(dim == 1) {
+        if(p.size())
+          add_trsfline(p, CTX.filename,
+                       GUI::instance()->meshContext->choice[0]->text(),
+                       GUI::instance()->meshContext->input[2]->value(),
+                       GUI::instance()->meshContext->input[1]->value());
+      }
+      ZeroHighlight();
+      Draw();
+      p.clear();
+    }
+    if(ib == 'u') {
+      if(dim == 1) {
+        if(p.size()){
+          ZeroHighlightEntityNum(0, p.back(), 0, 0);
+          Draw();
+          p.pop_back();
+        }
+      }
+    }
+    if(ib == 'q') {
+      ZeroHighlight();
+      Draw();
+      break;
+    }
+    if(ib == 'r') {
+      Msg::Warning("Entity de-selection not supported yet during "
+                   "transfinite definition");
+    }
+    if(ib == 'l') {
+      switch (dim) {
+      case 1:
+        for(unsigned int i = 0; i < edges.size(); i++){
+          HighlightEntity(edges[i]);
+          p.push_back(edges[i]->tag());
+        }
+        Draw();
+        break;
+      case 2:
+      case 3:
+        if(dim == 2){
+          HighlightEntity(faces[0]);
+          Draw();
+          p.push_back(faces[0]->tag());
+        }
+        else{
+          HighlightEntity(regions[0]);
+          Draw();
+          p.push_back(regions[0]->tag());
+        }
+        while(1) {
+          if(p.size() == 1)
+            Msg::StatusBar(3, false, "Select (ordered) boundary points\n"
+                           "[Press 'e' to end selection or 'q' to abort]");
+          else
+            Msg::StatusBar(3, false, "Select (ordered) boundary points\n"
+                           "[Press 'e' to end selection, 'u' to undo last selection "
+                           "or 'q' to abort]");
+          ib = SelectEntity(ENT_POINT, vertices, edges, faces, regions, elements);
+          if(ib == 'l') {
+            HighlightEntity(vertices[0]);
+            Draw();
+            p.push_back(vertices[0]->tag());
+          }
+          if(ib == 'u') {
+            if(p.size() > 1){
+              ZeroHighlightEntityNum(p.back(), 0, 0, 0);
+              Draw();
+              p.pop_back();
+            }
+          }
+          if(ib == 'r') {
+            Msg::Warning("Entity de-selection not supported yet during "
+                         "transfinite definition");
+          }
+          if(ib == 'e') {
+            switch (dim) {
+            case 2:
+              if(p.size() == 0 + 1 || p.size() == 3 + 1 || p.size() == 4 + 1)
+                add_trsfsurf(p, CTX.filename,
+                             GUI::instance()->meshContext->choice[1]->text());
+              else
+                Msg::Error("Wrong number of points for transfinite surface");
+              break;
+            case 3:
+              if(p.size() == 6 + 1 || p.size() == 8 + 1)
+                add_trsfvol(p, CTX.filename);
+              else
+                Msg::Error("Wrong number of points for transfinite volume");
+              break;
+            }
+            ZeroHighlight();
+            Draw();
+            p.clear();
+            break;
+          }
+          if(ib == 'q') {
+            ZeroHighlight();
+            Draw();
+            goto stopall;
+          }
+        }
+        break;
+      }
+    }
+  }
+
+ stopall:
+  Msg::StatusBar(3, false, "");
+}
+
+static void mesh_define_transfinite_line_cb(Fl_Widget *w, void *data)
+{
+  GUI::instance()->meshContext->show(1);
+  add_transfinite(1);
+}
+
+static void mesh_define_transfinite_surface_cb(Fl_Widget *w, void *data)
+{
+  GUI::instance()->meshContext->show(2);
+  add_transfinite(2);
+}
+
+static void mesh_define_transfinite_volume_cb(Fl_Widget *w, void *data)
+{
+  add_transfinite(3);
+}
+
+static void view_toggle_cb(Fl_Widget *w, void *data)
+{
+  int num = (int)(long)data;
+  opt_view_visible(num, GMSH_SET,
+                   GUI::instance()->menu->toggle[num]->value());
+  Draw();
+}
+
+static void view_reload(int index)
+{
+  if(index >= 0 && index < (int)PView::list.size()){
+    PView *p = PView::list[index];
+
+    if(StatFile(p->getData()->getFileName().c_str())){
+      Msg::Error("File '%s' does not exist", p->getData()->getFileName().c_str());
+      return;
+    }
+
+    int n = PView::list.size();
+
+    // FIXME: use fileIndex
+    MergeFile(p->getData()->getFileName().c_str());
+
+    if((int)PView::list.size() > n){ // we loaded a new view
+      // delete old data and replace with new
+      delete p->getData();
+      p->setData(PView::list.back()->getData());
+      PView::list.back()->setData(0);
+      // delete new view
+      delete PView::list.back();
+      // in case the reloaded view has a different number of time steps
+      if(p->getOptions()->TimeStep > p->getData()->getNumTimeSteps() - 1)
+        p->getOptions()->TimeStep = 0;
+      p->setChanged(true);
+      GUI::instance()->updateViews();
+    }
+  }
+}
+
+static void view_reload_cb(Fl_Widget *w, void *data)
+{
+  view_reload((int)(long)data);
+  Draw();
+}
+
+static void view_reload_all_cb(Fl_Widget *w, void *data)
+{
+  for(unsigned int i = 0; i < PView::list.size(); i++)
+    view_reload(i);
+  Draw();
+}
+
+static void view_reload_visible_cb(Fl_Widget *w, void *data)
+{
+  for(unsigned int i = 0; i < PView::list.size(); i++)
+    if(opt_view_visible(i, GMSH_GET, 0))
+      view_reload(i);
+  Draw();
+}
+
+static void view_remove_other_cb(Fl_Widget *w, void *data)
+{
+  if(PView::list.empty()) return;
+  for(int i = PView::list.size() - 1; i >= 0; i--)
+    if(i != (long)data) delete PView::list[i];
+  GUI::instance()->updateViews();
+  Draw();
+}
+
+static void view_remove_all_cb(Fl_Widget *w, void *data)
+{
+  if(PView::list.empty()) return;
+  while(PView::list.size()) delete PView::list[0];
+  GUI::instance()->updateViews();
+  Draw();
+}
+
+static void view_remove_visible_cb(Fl_Widget *w, void *data)
+{
+  if(PView::list.empty()) return;
+  for(int i = PView::list.size() - 1; i >= 0; i--)
+    if(opt_view_visible(i, GMSH_GET, 0)) delete PView::list[i];
+  GUI::instance()->updateViews();
+  Draw();
+}
+
+static void view_remove_invisible_cb(Fl_Widget *w, void *data)
+{
+  if(PView::list.empty()) return;
+  for(int i = PView::list.size() - 1; i >= 0; i--)
+    if(!opt_view_visible(i, GMSH_GET, 0)) delete PView::list[i];
+  GUI::instance()->updateViews();
+  Draw();
+}
+
+static void view_remove_empty_cb(Fl_Widget *w, void *data)
+{
+  if(PView::list.empty()) return;
+  for(int i = PView::list.size() - 1; i >= 0; i--)
+    if(PView::list[i]->getData()->empty()) delete PView::list[i];
+  GUI::instance()->updateViews();
+  Draw();
+}
+
+static void view_remove_cb(Fl_Widget *w, void *data)
+{
+  delete PView::list[(int)(long)data];
+  GUI::instance()->updateViews();
+  Draw();
+}
+
+static void view_save_as(int index, const char *title, int format)
+{
+  PView *view = PView::list[index];
+  
+ test:
+  if(file_chooser(0, 1, title, "*", view->getData()->getFileName().c_str())){
+    std::string name = file_chooser_get_name(1);
+    if(CTX.confirm_overwrite) {
+      if(!StatFile(name.c_str()))
+        if(!fl_choice("File '%s' already exists.\n\nDo you want to replace it?",
+                      "Cancel", "Replace", NULL, name.c_str()))
+          goto test;
+    }
+    view->write(name.c_str(), format);
+  }
+}
+
+static void view_save_ascii_cb(Fl_Widget *w, void *data)
+{
+  view_save_as((int)(long)data, "Save As ASCII View", 0);
+}
+
+static void view_save_binary_cb(Fl_Widget *w, void *data)
+{
+  view_save_as((int)(long)data, "Save As Binary View", 1);
+}
+
+static void view_save_parsed_cb(Fl_Widget *w, void *data)
+{
+  view_save_as((int)(long)data, "Save As Parsed View", 2);
+}
+
+static void view_save_stl_cb(Fl_Widget *w, void *data)
+{
+  view_save_as((int)(long)data, "Save As STL Triangulation", 3);
+}
+
+static void view_save_txt_cb(Fl_Widget *w, void *data)
+{
+  view_save_as((int)(long)data, "Save As Raw Text", 4);
+}
+
+static void view_save_msh_cb(Fl_Widget *w, void *data)
+{
+  view_save_as((int)(long)data, "Save As Gmsh Mesh", 5);
+}
+
+static void view_save_med_cb(Fl_Widget *w, void *data)
+{
+  view_save_as((int)(long)data, "Save As MED file", 6);
+}
+
+static void view_alias_cb(Fl_Widget *w, void *data)
+{
+  new PView(PView::list[(int)(long)data], false);
+  GUI::instance()->updateViews();
+  Draw();
+}
+
+static void view_alias_with_options_cb(Fl_Widget *w, void *data)
+{
+  new PView(PView::list[(int)(long)data], true);
+  GUI::instance()->updateViews();
+  Draw();
+}
+
+static void view_combine_space_all_cb(Fl_Widget *w, void *data)
+{
+  PView::combine(false, 1, CTX.post.combine_remove_orig);
+  GUI::instance()->updateViews();
+  Draw();
+}
+
+static void view_combine_space_visible_cb(Fl_Widget *w, void *data)
+{
+  PView::combine(false, 0, CTX.post.combine_remove_orig);
+  GUI::instance()->updateViews();
+  Draw();
+}
+
+static void view_combine_space_by_name_cb(Fl_Widget *w, void *data)
+{
+  PView::combine(false, 2, CTX.post.combine_remove_orig);
+  GUI::instance()->updateViews();
+  Draw();
+}
+
+static void view_combine_time_all_cb(Fl_Widget *w, void *data)
+{
+  PView::combine(true, 1, CTX.post.combine_remove_orig);
+  GUI::instance()->updateViews();
+  Draw();
+}
+
+static void view_combine_time_visible_cb(Fl_Widget *w, void *data)
+{
+  PView::combine(true, 0, CTX.post.combine_remove_orig);
+  GUI::instance()->updateViews();
+  Draw();
+}
+
+static void view_combine_time_by_name_cb(Fl_Widget *w, void *data)
+{
+  PView::combine(true, 2, CTX.post.combine_remove_orig);
+  GUI::instance()->updateViews();
+  Draw();
+}
+
+static void view_all_visible_cb(Fl_Widget *w, void *data)
+{
+  for(unsigned int i = 0; i < PView::list.size(); i++)
+    opt_view_visible(i, GMSH_SET | GMSH_GUI, 
+                     (long)data < 0 ? !opt_view_visible(i, GMSH_GET, 0) :
+                     (long)data > 0 ? 1 : 0);
+  Draw();
+}
+
+static void view_applybgmesh_cb(Fl_Widget *w, void *data)
+{
+  int index =  (int)(long)data;
+  if(index >= 0 && index < (int)PView::list.size()){
+    GModel::current()->getFields()->set_background_mesh(index);
+  }
+}
+
 // The static menus (we cannot use the 'g', 'm' 's' and 'p' mnemonics
 // since they are already defined as global shortcuts)
 static Fl_Menu_Item bar_table[] = {
@@ -33,7 +2143,7 @@ static Fl_Menu_Item bar_table[] = {
     {0},
   {"&Tools", 0, 0, 0, FL_SUBMENU},
     {"&Options...",      FL_CTRL+FL_SHIFT+'n', (Fl_Callback *)options_cb, 0},
-    {"Pl&ugins...",      FL_CTRL+FL_SHIFT+'u', (Fl_Callback *)view_plugin_cb, (void*)(-1)},
+    {"Pl&ugins...",      FL_CTRL+FL_SHIFT+'u', (Fl_Callback *)plugin_cb, (void*)(-1)},
     {"&Visibility",      FL_CTRL+FL_SHIFT+'v', (Fl_Callback *)visibility_cb, 0},
     {"&Clipping",        FL_CTRL+FL_SHIFT+'c', (Fl_Callback *)clip_cb, 0},
     {"&Manipulator",     FL_CTRL+FL_SHIFT+'m', (Fl_Callback *)manip_cb, 0, FL_MENU_DIVIDER},
@@ -72,7 +2182,7 @@ static Fl_Menu_Item sysbar_table[] = {
     {0},
   {"Tools", 0, 0, 0, FL_SUBMENU},
     {"Options...",      FL_META+FL_SHIFT+'n', (Fl_Callback *)options_cb, 0},
-    {"Plugins...",      FL_META+FL_SHIFT+'u', (Fl_Callback *)view_plugin_cb, (void*)(-1)},
+    {"Plugins...",      FL_META+FL_SHIFT+'u', (Fl_Callback *)plugin_cb, (void*)(-1)},
     {"Visibility",      FL_META+FL_SHIFT+'v', (Fl_Callback *)visibility_cb, 0},
     {"Clipping",        FL_META+FL_SHIFT+'c', (Fl_Callback *)clip_cb, 0},
     {"Manipulator",     FL_META+FL_SHIFT+'m', (Fl_Callback *)manip_cb, 0, FL_MENU_DIVIDER},
@@ -288,7 +2398,7 @@ contextItem menu_mesh[] = {
 };  
   contextItem menu_mesh_define[] = {
     {"1Mesh>Define", NULL} ,
-    {"Fields",      (Fl_Callback *)view_field_cb},
+    {"Fields",      (Fl_Callback *)field_cb},
     {"Characteristic length", (Fl_Callback *)mesh_define_length_cb  } ,
     {"Recombine",   (Fl_Callback *)mesh_define_recombine_cb  } ,
     {"Transfinite", (Fl_Callback *)mesh_define_transfinite_cb  } , 
@@ -601,7 +2711,7 @@ void menuWindow::setContext(contextItem *menu_asked, int flag)
         p[j]->add("Options...", 'o', 
                   (Fl_Callback *) view_options_cb, (void *)nb, 0);
         p[j]->add("Plugins...", 'p', 
-                  (Fl_Callback *) view_plugin_cb, (void *)nb, 0);
+                  (Fl_Callback *) plugin_cb, (void *)nb, 0);
       }
 
       toggle.push_back(b1);
diff --git a/Fltk/menuWindow.h b/Fltk/menuWindow.h
index 1953ea97a1..304e2277a0 100644
--- a/Fltk/menuWindow.h
+++ b/Fltk/menuWindow.h
@@ -76,4 +76,16 @@ class menuWindow{
   void setContext(contextItem *menu_asked, int flag);
 };
 
+void file_quit_cb(Fl_Widget *w, void *data);
+void mod_geometry_cb(Fl_Widget *w, void *data);
+void mod_mesh_cb(Fl_Widget *w, void *data);
+void mod_solver_cb(Fl_Widget *w, void *data);
+void mod_post_cb(Fl_Widget *w, void *data);
+void mod_back_cb(Fl_Widget *w, void *data);
+void mod_forward_cb(Fl_Widget *w, void *data);
+void geometry_reload_cb(Fl_Widget *w, void *data);
+void mesh_1d_cb(Fl_Widget *w, void *data);
+void mesh_2d_cb(Fl_Widget *w, void *data);
+void mesh_3d_cb(Fl_Widget *w, void *data);
+
 #endif
diff --git a/Fltk/messageWindow.cpp b/Fltk/messageWindow.cpp
index 5c01de08a1..7c387e064a 100644
--- a/Fltk/messageWindow.cpp
+++ b/Fltk/messageWindow.cpp
@@ -5,15 +5,71 @@
 
 #include <FL/Fl_Box.H>
 #include <FL/Fl_Return_Button.H>
+#include <FL/fl_ask.H>
 #include "GUI.h"
 #include "messageWindow.h"
 #include "shortcutWindow.h"
-#include "Callbacks.h"
+#include "fileDialogs.h"
 #include "GmshMessage.h"
+#include "OS.h"
 #include "Context.h"
 
 extern Context_T CTX;
 
+void message_cb(Fl_Widget *w, void *data)
+{
+  GUI::instance()->messages->show();
+}
+
+static void message_auto_scroll_cb(Fl_Widget *w, void *data)
+{
+  CTX.msg_auto_scroll = GUI::instance()->messages->butt->value();
+}
+
+static void message_copy_cb(Fl_Widget *w, void *data)
+{
+#define BUFFL 50000
+  static char buff[BUFFL];
+  strcpy(buff, "");
+  for(int i = 1; i <= GUI::instance()->messages->browser->size(); i++) {
+    if(GUI::instance()->messages->browser->selected(i)) {
+      const char *c = GUI::instance()->messages->browser->text(i);
+      if(strlen(buff) + strlen(c) > BUFFL - 2) {
+        Msg::Error("Text selection too large to copy");
+        break;
+      }
+      if(c[0] == '@')
+        strcat(buff, &c[5]);
+      else
+        strcat(buff, c);
+      strcat(buff, "\n");
+    }
+  }
+  // bof bof bof
+  Fl::copy(buff, strlen(buff), 0);
+  Fl::copy(buff, strlen(buff), 1);
+}
+
+static void message_clear_cb(Fl_Widget *w, void *data)
+{
+  GUI::instance()->messages->browser->clear();
+}
+
+static void message_save_cb(Fl_Widget *w, void *data)
+{
+ test:
+  if(file_chooser(0, 1, "Save", "*")) {
+    std::string name = file_chooser_get_name(1);
+    if(CTX.confirm_overwrite) {
+      if(!StatFile(name.c_str()))
+        if(!fl_choice("File '%s' already exists.\n\nDo you want to replace it?", 
+                      "Cancel", "Replace", NULL, name.c_str()))
+          goto test;
+    }
+    GUI::instance()->messages->save(name.c_str());
+  }
+}
+
 messageWindow::messageWindow(int fontsize)
   : _fontsize(fontsize)
 {
@@ -50,7 +106,7 @@ messageWindow::messageWindow(int fontsize)
   {
     Fl_Button *o = new Fl_Button
       (width - BB - WB, height - BH - WB, BB, BH, "Cancel");
-    o->callback(cancel_cb, (void *)win);
+    o->callback(hide_cb, (void *)win);
   }
 
   win->resizable(new Fl_Box(1, 1, 4, 4));
diff --git a/Fltk/messageWindow.h b/Fltk/messageWindow.h
index 2d1b2140e4..1cf53836fa 100644
--- a/Fltk/messageWindow.h
+++ b/Fltk/messageWindow.h
@@ -24,4 +24,6 @@ class messageWindow{
   void save(const char *filename);
 };
 
+void message_cb(Fl_Widget *w, void *data);
+
 #endif
diff --git a/Fltk/optionWindow.cpp b/Fltk/optionWindow.cpp
index 114adb6671..fd3b470223 100644
--- a/Fltk/optionWindow.cpp
+++ b/Fltk/optionWindow.cpp
@@ -7,15 +7,24 @@
 #include <FL/Fl_Tabs.H>
 #include <FL/Fl_Box.H>
 #include <FL/Fl_Scroll.H>
+#include <FL/Fl_Color_Chooser.H>
 #include "GUI.h"
 #include "optionWindow.h"
 #include "shortcutWindow.h"
+#include "menuWindow.h"
+#include "extraDialogs.h"
+#include "Draw.h"
+#include "SelectBuffer.h"
+#include "GmshDefines.h"
 #include "GmshMessage.h"
 #include "Options.h"
-#include "Callbacks.h"
+#include "Solvers.h"
+#include "GModel.h"
+#include "MElement.h"
 #include "PView.h"
 #include "PViewData.h"
 #include "PViewOptions.h"
+#include "OS.h"
 #include "Context.h"
 
 extern Context_T CTX;
@@ -90,6 +99,1051 @@ Fl_Menu_Item menu_font_names[] = {
   {0}
 };
 
+static void color_cb(Fl_Widget *w, void *data)
+{
+  unsigned int (*fct) (int, int, unsigned int);
+  fct = (unsigned int (*)(int, int, unsigned int))data;
+  uchar r = CTX.UNPACK_RED(fct(0, GMSH_GET, 0));
+  uchar g = CTX.UNPACK_GREEN(fct(0, GMSH_GET, 0));
+  uchar b = CTX.UNPACK_BLUE(fct(0, GMSH_GET, 0));
+  if(fl_color_chooser("Color Chooser", r, g, b))
+    fct(0, GMSH_SET | GMSH_GUI, CTX.PACK_COLOR(r, g, b, 255));
+  Draw();
+}
+
+static void view_color_cb(Fl_Widget *w, void *data)
+{
+  unsigned int (*fct) (int, int, unsigned int);
+  fct = (unsigned int (*)(int, int, unsigned int))data;
+  uchar r = CTX.UNPACK_RED(fct(GUI::instance()->options->view.index, GMSH_GET, 0));
+  uchar g = CTX.UNPACK_GREEN(fct(GUI::instance()->options->view.index, GMSH_GET, 0));
+  uchar b = CTX.UNPACK_BLUE(fct(GUI::instance()->options->view.index, GMSH_GET, 0));
+  if(fl_color_chooser("Color Chooser", r, g, b))
+    fct(GUI::instance()->options->view.index, 
+        GMSH_SET | GMSH_GUI, CTX.PACK_COLOR(r, g, b, 255));
+  Draw();
+}
+
+void options_cb(Fl_Widget *w, void *data)
+{
+  GUI::instance()->options->win->show();
+}
+
+static void options_browser_cb(Fl_Widget *w, void *data)
+{
+  GUI::instance()->options->showGroup(GUI::instance()->options->browser->value());
+}
+
+void options_save_cb(Fl_Widget *w, void *data)
+{
+  Msg::StatusBar(2, true, "Writing '%s'", CTX.options_filename_fullpath);
+  Print_Options(0, GMSH_OPTIONSRC, 1, 1, CTX.options_filename_fullpath);
+  Msg::StatusBar(2, true, "Wrote '%s'", CTX.options_filename_fullpath);
+}
+
+static void options_restore_defaults_cb(Fl_Widget *w, void *data)
+{
+  // not sure if we have to remove the file...
+  UnlinkFile(CTX.session_filename_fullpath);
+  UnlinkFile(CTX.options_filename_fullpath);
+  ReInit_Options(0);
+  Init_Options_GUI(0);
+  if(GUI::instance()->menu->module->value() == 3) // hack to refresh the buttons
+    GUI::instance()->menu->setContext(menu_post, 0);
+  Draw();
+}
+
+void general_options_cb(Fl_Widget *w, void *data)
+{
+  GUI::instance()->options->showGroup(1);
+}
+
+static void general_options_color_scheme_cb(Fl_Widget *w, void *data)
+{
+  opt_general_color_scheme
+    (0, GMSH_SET, GUI::instance()->options->general.choice[3]->value());
+  Draw();
+}
+
+static void general_options_rotation_center_select_cb(Fl_Widget *w, void *data)
+{
+  std::vector<GVertex*> vertices;
+  std::vector<GEdge*> edges;
+  std::vector<GFace*> faces;
+  std::vector<GRegion*> regions;
+  std::vector<MElement*> elements;
+
+  Msg::StatusBar(3, false, "Select entity\n[Press 'q' to abort]");
+  char ib = SelectEntity(ENT_ALL, vertices, edges, faces, regions, elements);
+  if(ib == 'l') {
+    SPoint3 pc(0., 0., 0.);
+    if(vertices.size())
+      pc.setPosition(vertices[0]->x(), vertices[0]->y(), vertices[0]->z());
+    else if(edges.size())
+      pc = edges[0]->bounds().center();
+    else if(faces.size())
+      pc = faces[0]->bounds().center();
+    else if(regions.size())
+      pc = regions[0]->bounds().center();
+    else if(elements.size())
+      pc = elements[0]->barycenter();
+    opt_general_rotation_center_cg
+      (0, GMSH_SET, GUI::instance()->options->general.butt[15]->value());
+    opt_general_rotation_center0(0, GMSH_SET|GMSH_GUI, pc.x());
+    opt_general_rotation_center1(0, GMSH_SET|GMSH_GUI, pc.y());
+    opt_general_rotation_center2(0, GMSH_SET|GMSH_GUI, pc.z());
+  }
+  ZeroHighlight();
+  Draw();
+  Msg::StatusBar(3, false, "");
+}
+
+static void general_options_ok_cb(Fl_Widget *w, void *data)
+{
+  optionWindow *o = GUI::instance()->options;
+  o->activate((const char*)data);
+
+  static double lc = 0.;
+  if(lc != CTX.lc){
+    lc = CTX.lc;
+    for(int i = 2; i < 5; i++){
+      o->general.value[i]->minimum(-5 * CTX.lc);
+      o->general.value[i]->maximum(5 * CTX.lc);
+    }
+  }
+  if(data){
+    const char *name = (const char*)data;
+    if(!strcmp(name, "rotation_center_coord")){
+      CTX.draw_rotation_center = 1;
+    }
+    else if(!strcmp(name, "light_value")){
+      double x, y, z;
+      x = o->general.value[2]->value();
+      y = o->general.value[3]->value();
+      z = o->general.value[4]->value();
+      o->general.sphere->setValue(x, y, z);    
+    }
+    else if(!strcmp(name, "light_sphere")){
+      double x, y, z;
+      o->general.sphere->getValue(x, y, z);
+      o->general.value[2]->value(x);
+      o->general.value[3]->value(y);
+      o->general.value[4]->value(z);
+    }
+  }
+
+  opt_general_axes_auto_position(0, GMSH_SET, o->general.butt[0]->value());
+  opt_general_small_axes(0, GMSH_SET, o->general.butt[1]->value());
+  opt_general_fast_redraw(0, GMSH_SET, o->general.butt[2]->value());
+  opt_general_mouse_hover_meshes(0, GMSH_SET, o->general.butt[11]->value());
+  if(opt_general_double_buffer(0, GMSH_GET, 0) != o->general.butt[3]->value())
+    opt_general_double_buffer(0, GMSH_SET, o->general.butt[3]->value());
+  if(opt_general_antialiasing(0, GMSH_GET, 0) != o->general.butt[12]->value())
+    opt_general_antialiasing(0, GMSH_SET, o->general.butt[12]->value());
+  opt_general_trackball(0, GMSH_SET, o->general.butt[5]->value());
+  opt_general_terminal(0, GMSH_SET, o->general.butt[7]->value());
+  double sessionrc = opt_general_session_save(0, GMSH_GET, 0);
+  opt_general_session_save(0, GMSH_SET, o->general.butt[8]->value());
+  if(sessionrc && !opt_general_session_save(0, GMSH_GET, 0))
+    Print_Options(0, GMSH_SESSIONRC, 1, 1, CTX.session_filename_fullpath);
+  opt_general_options_save(0, GMSH_SET, o->general.butt[9]->value());
+  opt_general_expert_mode(0, GMSH_SET, o->general.butt[10]->value());
+  opt_general_tooltips(0, GMSH_SET, o->general.butt[13]->value());
+  opt_general_confirm_overwrite(0, GMSH_SET, o->general.butt[14]->value());
+  opt_general_rotation_center_cg(0, GMSH_SET, o->general.butt[15]->value());
+  opt_general_draw_bounding_box(0, GMSH_SET, o->general.butt[6]->value());
+  opt_general_polygon_offset_always(0, GMSH_SET, o->general.butt[4]->value());
+  opt_general_axes_mikado(0, GMSH_SET, o->general.butt[16]->value());
+
+  opt_general_shine_exponent(0, GMSH_SET, o->general.value[0]->value());  
+  opt_general_shine(0, GMSH_SET, o->general.value[1]->value());
+  opt_general_light00(0, GMSH_SET, o->general.value[2]->value());
+  opt_general_light01(0, GMSH_SET, o->general.value[3]->value());
+  opt_general_light02(0, GMSH_SET, o->general.value[4]->value());
+  opt_general_light03(0, GMSH_SET, o->general.value[13]->value());
+  opt_general_verbosity(0, GMSH_SET, o->general.value[5]->value());
+  opt_general_point_size(0, GMSH_SET, o->general.value[6]->value());
+  opt_general_line_width(0, GMSH_SET, o->general.value[7]->value());
+  opt_general_rotation_center0(0, GMSH_SET, o->general.value[8]->value());
+  opt_general_rotation_center1(0, GMSH_SET, o->general.value[9]->value());
+  opt_general_rotation_center2(0, GMSH_SET, o->general.value[10]->value());
+  opt_general_quadric_subdivisions(0, GMSH_SET, o->general.value[11]->value());
+  opt_general_graphics_fontsize(0, GMSH_SET, o->general.value[12]->value());
+  opt_general_clip_factor(0, GMSH_SET, o->general.value[14]->value());
+  opt_general_polygon_offset_factor(0, GMSH_SET, o->general.value[15]->value());
+  opt_general_polygon_offset_units(0, GMSH_SET, o->general.value[16]->value());
+  opt_general_axes_tics0(0, GMSH_SET, o->general.value[17]->value());
+  opt_general_axes_tics1(0, GMSH_SET, o->general.value[18]->value());
+  opt_general_axes_tics2(0, GMSH_SET, o->general.value[19]->value());
+  opt_general_axes_xmin(0, GMSH_SET, o->general.value[20]->value());
+  opt_general_axes_ymin(0, GMSH_SET, o->general.value[21]->value());
+  opt_general_axes_zmin(0, GMSH_SET, o->general.value[22]->value());
+  opt_general_axes_xmax(0, GMSH_SET, o->general.value[23]->value());
+  opt_general_axes_ymax(0, GMSH_SET, o->general.value[24]->value());
+  opt_general_axes_zmax(0, GMSH_SET, o->general.value[25]->value());
+  opt_general_small_axes_position0(0, GMSH_SET, o->general.value[26]->value());
+  opt_general_small_axes_position1(0, GMSH_SET, o->general.value[27]->value());
+
+  opt_general_default_filename(0, GMSH_SET, o->general.input[0]->value());
+  opt_general_editor(0, GMSH_SET, o->general.input[1]->value());
+  opt_general_web_browser(0, GMSH_SET, o->general.input[2]->value());
+  opt_general_axes_format0(0, GMSH_SET, o->general.input[3]->value());
+  opt_general_axes_format1(0, GMSH_SET, o->general.input[4]->value());
+  opt_general_axes_format2(0, GMSH_SET, o->general.input[5]->value());
+  opt_general_axes_label0(0, GMSH_SET, o->general.input[6]->value());
+  opt_general_axes_label1(0, GMSH_SET, o->general.input[7]->value());
+  opt_general_axes_label2(0, GMSH_SET, o->general.input[8]->value());
+
+  opt_general_vector_type(0, GMSH_SET, o->general.choice[0]->value() + 1);
+  opt_general_graphics_font(0, GMSH_SET, o->general.choice[1]->text());
+  opt_general_orthographic(0, GMSH_SET, !o->general.choice[2]->value());
+  opt_general_axes(0, GMSH_SET, o->general.choice[4]->value());
+  opt_general_background_gradient(0, GMSH_SET, o->general.choice[5]->value());
+
+  if(CTX.fast_redraw)
+    CTX.post.draw = CTX.mesh.draw = 0;
+  Draw();
+  CTX.post.draw = CTX.mesh.draw = 1;
+  CTX.draw_rotation_center = 0;
+}
+
+static void general_arrow_param_cb(Fl_Widget *w, void *data)
+{
+  double a = opt_general_arrow_head_radius(0, GMSH_GET, 0);
+  double b = opt_general_arrow_stem_length(0, GMSH_GET, 0);
+  double c = opt_general_arrow_stem_radius(0, GMSH_GET, 0);
+  while(arrow_editor("Arrow Editor", a, b, c)){
+    opt_general_arrow_head_radius(0, GMSH_SET, a);
+    opt_general_arrow_stem_length(0, GMSH_SET, b);
+    opt_general_arrow_stem_radius(0, GMSH_SET, c);
+    Draw();
+  }
+}
+
+void geometry_options_cb(Fl_Widget *w, void *data)
+{
+  GUI::instance()->options->showGroup(2);
+}
+
+static void geometry_options_ok_cb(Fl_Widget *w, void *data)
+{
+  optionWindow *o = GUI::instance()->options;
+  o->activate((const char*)data);
+
+  opt_geometry_points(0, GMSH_SET, o->geo.butt[0]->value());
+  opt_geometry_lines(0, GMSH_SET, o->geo.butt[1]->value());
+  opt_geometry_surfaces(0, GMSH_SET, o->geo.butt[2]->value());
+  opt_geometry_volumes(0, GMSH_SET, o->geo.butt[3]->value());
+  opt_geometry_points_num(0, GMSH_SET, o->geo.butt[4]->value());
+  opt_geometry_lines_num(0, GMSH_SET, o->geo.butt[5]->value());
+  opt_geometry_surfaces_num(0, GMSH_SET, o->geo.butt[6]->value());
+  opt_geometry_volumes_num(0, GMSH_SET, o->geo.butt[7]->value());
+  opt_geometry_auto_coherence(0, GMSH_SET, o->geo.butt[8]->value());
+  opt_geometry_light(0, GMSH_SET, o->geo.butt[9]->value());
+  opt_geometry_highlight_orphans(0, GMSH_SET, o->geo.butt[10]->value());
+  opt_geometry_occ_fix_small_edges(0, GMSH_SET, o->geo.butt[11]->value());
+  opt_geometry_occ_fix_small_faces(0, GMSH_SET, o->geo.butt[12]->value());
+  opt_geometry_occ_sew_faces(0, GMSH_SET, o->geo.butt[13]->value());
+  opt_geometry_light_two_side(0, GMSH_SET, o->geo.butt[14]->value());
+
+  opt_geometry_normals(0, GMSH_SET, o->geo.value[0]->value());
+  opt_geometry_tangents(0, GMSH_SET, o->geo.value[1]->value());
+  opt_geometry_tolerance(0, GMSH_SET, o->geo.value[2]->value());
+  opt_geometry_point_size(0, GMSH_SET, o->geo.value[3]->value());
+  opt_geometry_line_width(0, GMSH_SET, o->geo.value[4]->value());
+  opt_geometry_point_sel_size(0, GMSH_SET, o->geo.value[5]->value());
+  opt_geometry_line_sel_width(0, GMSH_SET, o->geo.value[6]->value());
+
+  opt_geometry_point_type(0, GMSH_SET, o->geo.choice[0]->value());
+  opt_geometry_line_type(0, GMSH_SET, o->geo.choice[1]->value());
+  opt_geometry_surface_type(0, GMSH_SET, o->geo.choice[2]->value());
+
+  if(CTX.fast_redraw)
+    CTX.post.draw = CTX.mesh.draw = 0;
+  Draw();
+  CTX.post.draw = CTX.mesh.draw = 1;
+}
+
+void mesh_options_cb(Fl_Widget *w, void *data)
+{
+  GUI::instance()->options->showGroup(3);
+}
+
+static void mesh_options_ok_cb(Fl_Widget *w, void *data)
+{
+  optionWindow *o = GUI::instance()->options;
+  o->activate((const char*)data);
+
+  opt_mesh_reverse_all_normals(0, GMSH_SET, o->mesh.butt[0]->value());
+  opt_mesh_lc_from_curvature(0, GMSH_SET, o->mesh.butt[1]->value());
+  opt_mesh_lc_from_points(0, GMSH_SET, o->mesh.butt[5]->value());
+  opt_mesh_lc_extend_from_boundary(0, GMSH_SET, o->mesh.butt[16]->value());
+  opt_mesh_optimize(0, GMSH_SET, o->mesh.butt[2]->value());
+  opt_mesh_optimize_netgen(0, GMSH_SET, o->mesh.butt[24]->value());
+  opt_mesh_order(0, GMSH_SET, o->mesh.value[3]->value());
+  opt_mesh_smooth_internal_edges(0, GMSH_SET, o->mesh.butt[3]->value());
+  opt_mesh_second_order_incomplete(0, GMSH_SET, o->mesh.butt[4]->value());
+  opt_mesh_c1(0, GMSH_SET, o->mesh.butt[21]->value());
+  opt_mesh_points(0, GMSH_SET, o->mesh.butt[6]->value());
+  opt_mesh_lines(0, GMSH_SET, o->mesh.butt[7]->value());
+  opt_mesh_triangles(0, GMSH_SET, o->mesh.menu->menu()[0].value() ? 1 : 0);
+  opt_mesh_quadrangles(0, GMSH_SET, o->mesh.menu->menu()[1].value() ? 1 : 0);
+  opt_mesh_tetrahedra(0, GMSH_SET, o->mesh.menu->menu()[2].value() ? 1 : 0);
+  opt_mesh_hexahedra(0, GMSH_SET, o->mesh.menu->menu()[3].value() ? 1 : 0);
+  opt_mesh_prisms(0, GMSH_SET, o->mesh.menu->menu()[4].value() ? 1 : 0);
+  opt_mesh_pyramids(0, GMSH_SET, o->mesh.menu->menu()[5].value() ? 1 : 0);
+  opt_mesh_surfaces_edges(0, GMSH_SET, o->mesh.butt[8]->value());
+  opt_mesh_surfaces_faces(0, GMSH_SET, o->mesh.butt[9]->value());
+  opt_mesh_volumes_edges(0, GMSH_SET, o->mesh.butt[10]->value());
+  opt_mesh_volumes_faces(0, GMSH_SET, o->mesh.butt[11]->value());
+  opt_mesh_points_num(0, GMSH_SET, o->mesh.butt[12]->value());
+  opt_mesh_lines_num(0, GMSH_SET, o->mesh.butt[13]->value());
+  opt_mesh_surfaces_num(0, GMSH_SET, o->mesh.butt[14]->value());
+  opt_mesh_volumes_num(0, GMSH_SET, o->mesh.butt[15]->value());
+  opt_mesh_light(0, GMSH_SET, o->mesh.butt[17]->value());
+  opt_mesh_light_two_side(0, GMSH_SET, o->mesh.butt[18]->value());
+  opt_mesh_smooth_normals(0, GMSH_SET, o->mesh.butt[19]->value());
+  opt_mesh_light_lines(0, GMSH_SET, o->mesh.butt[20]->value());
+  opt_mesh_nb_smoothing(0, GMSH_SET, o->mesh.value[0]->value());
+  opt_mesh_lc_factor(0, GMSH_SET, o->mesh.value[2]->value());
+  opt_mesh_lc_min(0, GMSH_SET, o->mesh.value[25]->value());
+  opt_mesh_lc_max(0, GMSH_SET, o->mesh.value[26]->value());
+  opt_mesh_quality_inf(0, GMSH_SET, o->mesh.value[4]->value());
+  opt_mesh_quality_sup(0, GMSH_SET, o->mesh.value[5]->value());
+  opt_mesh_radius_inf(0, GMSH_SET, o->mesh.value[6]->value());
+  opt_mesh_radius_sup(0, GMSH_SET, o->mesh.value[7]->value());
+  opt_mesh_normals(0, GMSH_SET, o->mesh.value[8]->value());
+  opt_mesh_explode(0, GMSH_SET, o->mesh.value[9]->value());
+  opt_mesh_tangents(0, GMSH_SET, o->mesh.value[13]->value());
+  opt_mesh_point_size(0, GMSH_SET, o->mesh.value[10]->value());
+  opt_mesh_line_width(0, GMSH_SET, o->mesh.value[11]->value());
+  opt_mesh_label_frequency(0, GMSH_SET, o->mesh.value[12]->value());
+  opt_mesh_angle_smooth_normals(0, GMSH_SET, o->mesh.value[18]->value());
+
+  opt_mesh_point_type(0, GMSH_SET, o->mesh.choice[0]->value());
+  opt_mesh_algo2d(0, GMSH_SET,
+                  (o->mesh.choice[2]->value() == 0) ? ALGO_2D_FRONTAL : 
+                  (o->mesh.choice[2]->value() == 1) ? ALGO_2D_DELAUNAY :
+                  ALGO_2D_MESHADAPT_DELAUNAY);
+  opt_mesh_algo3d(0, GMSH_SET,
+                  (o->mesh.choice[3]->value() == 0) ? ALGO_3D_TETGEN_DELAUNAY : 
+                  ALGO_3D_NETGEN);
+  opt_mesh_recombine_algo(0, GMSH_SET,
+                  (o->mesh.choice[5]->value() == 0) ? 1 : 2);
+  opt_mesh_color_carousel(0, GMSH_SET, o->mesh.choice[4]->value());
+  opt_mesh_quality_type(0, GMSH_SET, o->mesh.choice[6]->value());
+  opt_mesh_label_type(0, GMSH_SET, o->mesh.choice[7]->value());
+
+  if(CTX.fast_redraw)
+    CTX.post.draw = CTX.mesh.draw = 0;
+  Draw();
+  CTX.post.draw = CTX.mesh.draw = 1;
+}
+
+void solver_options_cb(Fl_Widget *w, void *data)
+{
+  GUI::instance()->options->showGroup(4);
+}
+
+static void solver_options_ok_cb(Fl_Widget *w, void *data)
+{
+  optionWindow *o = GUI::instance()->options;
+  o->activate((const char*)data);
+
+  int old_listen = (int)opt_solver_listen(0, GMSH_GET, o->solver.butt[0]->value());
+  opt_solver_listen(0, GMSH_SET, o->solver.butt[0]->value());
+  if(!old_listen && o->solver.butt[0]->value())
+    Solver(-1, NULL);
+
+  opt_solver_max_delay(0, GMSH_SET, o->solver.value[0]->value());
+
+  opt_solver_socket_name(0, GMSH_SET, o->solver.input[0]->value());
+
+  if(CTX.fast_redraw)
+    CTX.post.draw = CTX.mesh.draw = 0;
+  Draw();
+  CTX.post.draw = CTX.mesh.draw = 1;
+}
+
+void post_options_cb(Fl_Widget *w, void *data)
+{
+  GUI::instance()->options->showGroup(5);
+}
+
+static void post_options_ok_cb(Fl_Widget *w, void *data)
+{
+  optionWindow *o = GUI::instance()->options;
+  o->activate((const char*)data);
+
+  opt_post_anim_cycle(0, GMSH_SET, o->post.butt[0]->value());
+  opt_post_combine_remove_orig(0, GMSH_SET, o->post.butt[1]->value());
+  opt_post_horizontal_scales(0, GMSH_SET, o->post.butt[2]->value());
+
+  opt_post_anim_delay(0, GMSH_SET, o->post.value[0]->value());
+
+  opt_post_link(0, GMSH_SET, o->post.choice[0]->value());
+
+  if(CTX.fast_redraw)
+    CTX.post.draw = CTX.mesh.draw = 0;
+  Draw();
+  CTX.post.draw = CTX.mesh.draw = 1;
+}
+
+void view_options_cb(Fl_Widget *w, void *data)
+{
+  GUI::instance()->options->showGroup((int)(long)data + 6);
+}
+
+static void view_options_timestep_cb(Fl_Widget *w, void *data)
+{
+  int links = (int)opt_post_link(0, GMSH_GET, 0);
+  for(int i = 0; i < (int)PView::list.size(); i++) {
+    if((links == 2 || links == 4) ||
+       ((links == 1 || links == 3) && opt_view_visible(i, GMSH_GET, 0)) ||
+       (links == 0 && i == GUI::instance()->options->view.index)) {
+      opt_view_timestep(i, GMSH_SET, ((Fl_Value_Input *) w)->value());
+    }
+  }
+  Draw();
+}
+
+static void view_options_timestep_decr_cb(Fl_Widget *w, void *data)
+{
+  int links = (int)opt_post_link(0, GMSH_GET, 0);
+  for(int i = 0; i < (int)PView::list.size(); i++) {
+    if((links == 2 || links == 4) ||
+       ((links == 1 || links == 3) && opt_view_visible(i, GMSH_GET, 0)) ||
+       (links == 0 && i == GUI::instance()->options->view.index)) {
+      opt_view_timestep(i, GMSH_SET | GMSH_GUI,
+                        opt_view_timestep(i, GMSH_GET, 0) - 1);
+    }
+  }
+  Draw();
+}
+
+static void view_options_timestep_incr_cb(Fl_Widget *w, void *data)
+{
+  int links = (int)opt_post_link(0, GMSH_GET, 0);
+  for(int i = 0; i < (int)PView::list.size(); i++) {
+    if((links == 2 || links == 4) ||
+       ((links == 1 || links == 3) && opt_view_visible(i, GMSH_GET, 0)) ||
+       (links == 0 && i == GUI::instance()->options->view.index)) {
+      opt_view_timestep(i, GMSH_SET | GMSH_GUI,
+                        opt_view_timestep(i, GMSH_GET, 0) + 1);
+    }
+  }
+  Draw();
+}
+
+static void view_arrow_param_cb(Fl_Widget *w, void *data)
+{
+  double a = opt_view_arrow_head_radius
+    (GUI::instance()->options->view.index, GMSH_GET, 0);
+  double b = opt_view_arrow_stem_length
+    (GUI::instance()->options->view.index, GMSH_GET, 0);
+  double c = opt_view_arrow_stem_radius
+    (GUI::instance()->options->view.index, GMSH_GET, 0);
+  while(arrow_editor("Arrow Editor", a, b, c)){
+    opt_view_arrow_head_radius
+      (GUI::instance()->options->view.index, GMSH_SET, a);
+    opt_view_arrow_stem_length
+      (GUI::instance()->options->view.index, GMSH_SET, b);
+    opt_view_arrow_stem_radius
+      (GUI::instance()->options->view.index, GMSH_SET, c);
+    Draw();
+  }
+}
+
+static void view_options_ok_cb(Fl_Widget *w, void *data)
+{
+  int current = GUI::instance()->options->view.index;
+
+  if(current < 0) return;
+
+  optionWindow *o = GUI::instance()->options;
+  o->activate((const char*)data);
+
+  if(data){
+    const char *str = (const char*)data;
+    if(!strcmp(str, "range_min")){
+      o->view.value[31]->value(opt_view_min(o->view.index, GMSH_GET, 0));
+    }
+    else if(!strcmp(str, "range_max")){
+      o->view.value[32]->value(opt_view_max(o->view.index, GMSH_GET, 0));
+    }
+  }
+  
+  int force = 0, links = (int)opt_post_link(0, GMSH_GET, 0);
+
+  // get the old values for the current view
+  double scale_type = opt_view_scale_type(current, GMSH_GET, 0);
+  double intervals_type = opt_view_intervals_type(current, GMSH_GET, 0);
+  double point_type = opt_view_point_type(current, GMSH_GET, 0);
+  double line_type = opt_view_line_type(current, GMSH_GET, 0);
+  double vector_type = opt_view_vector_type(current, GMSH_GET, 0);
+  double glyph_location = opt_view_glyph_location(current, GMSH_GET, 0);
+  double tensor_type = opt_view_tensor_type(current, GMSH_GET, 0);
+  double range_type = opt_view_range_type(current, GMSH_GET, 0);
+  double axes = opt_view_axes(current, GMSH_GET, 0);
+  double mikado = opt_view_axes_mikado(current, GMSH_GET, 0);
+  double boundary = opt_view_boundary(current, GMSH_GET, 0);
+  double external_view = opt_view_external_view(current, GMSH_GET, 0);
+  double gen_raise_view = opt_view_gen_raise_view(current, GMSH_GET, 0);
+  double show_time = opt_view_show_time(current, GMSH_GET, 0);
+
+  double type = opt_view_type(current, GMSH_GET, 0);
+  double saturate_values = opt_view_saturate_values(current, GMSH_GET, 0);
+  double max_recursion_level = opt_view_max_recursion_level(current, GMSH_GET, 0);
+  double target_error = opt_view_target_error(current, GMSH_GET, 0);
+  double show_element = opt_view_show_element(current, GMSH_GET, 0);
+  double draw_skin_only = opt_view_draw_skin_only(current, GMSH_GET, 0);
+  double show_scale = opt_view_show_scale(current, GMSH_GET, 0);
+  double auto_position = opt_view_auto_position(current, GMSH_GET, 0);
+  double axes_auto_position = opt_view_axes_auto_position(current, GMSH_GET, 0);
+  double draw_strings = opt_view_draw_strings(current, GMSH_GET, 0);
+  double light = opt_view_light(current, GMSH_GET, 0);
+  double light_two_side = opt_view_light_two_side(current, GMSH_GET, 0);
+  double light_lines = opt_view_light_lines(current, GMSH_GET, 0);
+  double smooth_normals = opt_view_smooth_normals(current, GMSH_GET, 0);
+  double draw_points = opt_view_draw_points(current, GMSH_GET, 0);
+  double draw_lines = opt_view_draw_lines(current, GMSH_GET, 0);
+  double draw_triangles = opt_view_draw_triangles(current, GMSH_GET, 0);
+  double draw_quadrangles = opt_view_draw_quadrangles(current, GMSH_GET, 0);
+  double draw_tetrahedra = opt_view_draw_tetrahedra(current, GMSH_GET, 0);
+  double draw_hexahedra = opt_view_draw_hexahedra(current, GMSH_GET, 0);
+  double draw_prisms = opt_view_draw_prisms(current, GMSH_GET, 0);
+  double draw_pyramids = opt_view_draw_pyramids(current, GMSH_GET, 0);
+  double draw_scalars = opt_view_draw_scalars(current, GMSH_GET, 0);
+  double draw_vectors = opt_view_draw_vectors(current, GMSH_GET, 0);
+  double draw_tensors = opt_view_draw_tensors(current, GMSH_GET, 0);
+  double use_gen_raise = opt_view_use_gen_raise(current, GMSH_GET, 0);
+  double fake_transparency = opt_view_fake_transparency(current, GMSH_GET, 0);
+  double use_stipple = opt_view_use_stipple(current, GMSH_GET, 0);
+  double center_glyphs = opt_view_center_glyphs(current, GMSH_GET, 0);
+
+  double normals = opt_view_normals(current, GMSH_GET, 0);
+  double tangents = opt_view_tangents(current, GMSH_GET, 0);
+  double custom_min = opt_view_custom_min(current, GMSH_GET, 0);
+  double custom_max = opt_view_custom_max(current, GMSH_GET, 0);
+  double nb_iso = opt_view_nb_iso(current, GMSH_GET, 0);
+  double offset0 = opt_view_offset0(current, GMSH_GET, 0);
+  double offset1 = opt_view_offset1(current, GMSH_GET, 0);
+  double offset2 = opt_view_offset2(current, GMSH_GET, 0);
+  double transform00 = opt_view_transform00(current, GMSH_GET, 0);
+  double transform01 = opt_view_transform01(current, GMSH_GET, 0);
+  double transform02 = opt_view_transform02(current, GMSH_GET, 0);
+  double transform10 = opt_view_transform10(current, GMSH_GET, 0);
+  double transform11 = opt_view_transform11(current, GMSH_GET, 0);
+  double transform12 = opt_view_transform12(current, GMSH_GET, 0);
+  double transform20 = opt_view_transform20(current, GMSH_GET, 0);
+  double transform21 = opt_view_transform21(current, GMSH_GET, 0);
+  double transform22 = opt_view_transform22(current, GMSH_GET, 0);
+  double raise0 = opt_view_raise0(current, GMSH_GET, 0);
+  double raise1 = opt_view_raise1(current, GMSH_GET, 0);
+  double raise2 = opt_view_raise2(current, GMSH_GET, 0);
+  double normal_raise = opt_view_normal_raise(current, GMSH_GET, 0);
+  double timestep = opt_view_timestep(current, GMSH_GET, 0);
+  double arrow_size = opt_view_arrow_size(current, GMSH_GET, 0);
+  double arrow_size_proportional = opt_view_arrow_size_proportional(current, GMSH_GET, 0);
+  double displacement_factor = opt_view_displacement_factor(current, GMSH_GET, 0);
+  double point_size = opt_view_point_size(current, GMSH_GET, 0);
+  double line_width = opt_view_line_width(current, GMSH_GET, 0);
+  double explode = opt_view_explode(current, GMSH_GET, 0);
+  double angle_smooth_normals = opt_view_angle_smooth_normals(current, GMSH_GET, 0);
+  double position0 = opt_view_position0(current, GMSH_GET, 0);
+  double position1 = opt_view_position1(current, GMSH_GET, 0);
+  double size0 = opt_view_size0(current, GMSH_GET, 0);
+  double size1 = opt_view_size1(current, GMSH_GET, 0);
+  double axes_tics0 = opt_view_axes_tics0(current, GMSH_GET, 0);
+  double axes_tics1 = opt_view_axes_tics1(current, GMSH_GET, 0);
+  double axes_tics2 = opt_view_axes_tics2(current, GMSH_GET, 0);
+  double axes_xmin = opt_view_axes_xmin(current, GMSH_GET, 0);
+  double axes_ymin = opt_view_axes_ymin(current, GMSH_GET, 0);
+  double axes_zmin = opt_view_axes_zmin(current, GMSH_GET, 0);
+  double axes_xmax = opt_view_axes_xmax(current, GMSH_GET, 0);
+  double axes_ymax = opt_view_axes_ymax(current, GMSH_GET, 0);
+  double axes_zmax = opt_view_axes_zmax(current, GMSH_GET, 0);
+  double gen_raise_factor = opt_view_gen_raise_factor(current, GMSH_GET, 0);
+
+  char name[256]; 
+  strcpy(name, opt_view_name(current, GMSH_GET, NULL));
+  char format[256];
+  strcpy(format, opt_view_format(current, GMSH_GET, NULL));
+  char axes_label0[256];
+  strcpy(axes_label0, opt_view_axes_label0(current, GMSH_GET, NULL));
+  char axes_label1[256];
+  strcpy(axes_label1, opt_view_axes_label1(current, GMSH_GET, NULL));
+  char axes_label2[256];
+  strcpy(axes_label2, opt_view_axes_label2(current, GMSH_GET, NULL));
+  char axes_format0[256];
+  strcpy(axes_format0, opt_view_axes_format0(current, GMSH_GET, NULL));
+  char axes_format1[256];
+  strcpy(axes_format1, opt_view_axes_format1(current, GMSH_GET, NULL));
+  char axes_format2[256];
+  strcpy(axes_format2, opt_view_axes_format2(current, GMSH_GET, NULL));
+  char gen_raise0[256];
+  strcpy(gen_raise0, opt_view_gen_raise0(current, GMSH_GET, NULL));
+  char gen_raise1[256];
+  strcpy(gen_raise1, opt_view_gen_raise1(current, GMSH_GET, NULL));
+  char gen_raise2[256];
+  strcpy(gen_raise2, opt_view_gen_raise2(current, GMSH_GET, NULL));
+
+  // modify only the views that need to be updated
+  for(int i = 0; i < (int)PView::list.size(); i++) {
+    if((links == 2 || links == 4) ||
+       ((links == 1 || links == 3) && opt_view_visible(i, GMSH_GET, 0)) ||
+       (links == 0 && i == current)) {
+
+      if(links == 3 || links == 4)
+        force = 1;
+
+      double val;
+
+      // view_choice
+
+      val = o->view.choice[1]->value() + 1;
+      if(force || (val != scale_type))
+        opt_view_scale_type(i, GMSH_SET, val);
+
+      val = o->view.choice[0]->value() + 1;
+      if(force || (val != intervals_type))
+        opt_view_intervals_type(i, GMSH_SET, val);
+      
+      val = o->view.choice[5]->value();
+      if(force || (val != point_type))
+        opt_view_point_type(i, GMSH_SET, val);
+      
+      val = o->view.choice[6]->value();
+      if(force || (val != line_type))
+        opt_view_line_type(i, GMSH_SET, val);
+
+      val = o->view.choice[2]->value() + 1;
+      if(force || (val != vector_type))
+        opt_view_vector_type(i, GMSH_SET, val);
+
+      val = o->view.choice[3]->value() + 1;
+      if(force || (val != glyph_location))
+        opt_view_glyph_location(i, GMSH_SET, val);
+
+      val = o->view.choice[4]->value() + 1;
+      if(force || (val != tensor_type))
+        opt_view_tensor_type(i, GMSH_SET, val);
+      
+      val = o->view.choice[7]->value() + 1;
+      if(force || (val != range_type))
+        opt_view_range_type(i, GMSH_SET, val);
+
+      val = o->view.choice[8]->value();
+      if(force || (val != axes))
+        opt_view_axes(i, GMSH_SET, val);
+
+      val = o->view.choice[9]->value();
+      if(force || (val != boundary))
+        opt_view_boundary(i, GMSH_SET, val);
+
+      val = o->view.choice[10]->value() - 1;
+      if(force || (val != external_view))
+        opt_view_external_view(i, GMSH_SET, val);
+
+      val = o->view.choice[11]->value() - 1;
+      if(force || (val != gen_raise_view))
+        opt_view_gen_raise_view(i, GMSH_SET, val);
+
+      val = o->view.choice[12]->value();
+      if(force || (val != show_time))
+        opt_view_show_time(i, GMSH_SET, val);
+      
+      val = o->view.choice[13]->value() + 1;
+      if(force || (val != type))
+        opt_view_type(i, GMSH_SET, val);
+
+      // view_butts
+
+      val = o->view.butt[0]->value();
+      if(force || (val != arrow_size_proportional))
+        opt_view_arrow_size_proportional(i, GMSH_SET, val);
+
+      val = o->view.butt[38]->value();
+      if(force || (val != saturate_values))
+        opt_view_saturate_values(i, GMSH_SET, val);
+
+      val = o->view.butt[10]->value();
+      if(force || (val != show_element))
+        opt_view_show_element(i, GMSH_SET, val);
+
+      val = o->view.butt[2]->value();
+      if(force || (val != draw_skin_only))
+        opt_view_draw_skin_only(i, GMSH_SET, val);
+
+      val = o->view.butt[4]->value();
+      if(force || (val != show_scale))
+        opt_view_show_scale(i, GMSH_SET, val);
+
+      val = o->view.butt[3]->value();
+      if(force || (val != mikado))
+        opt_view_axes_mikado(i, GMSH_SET, val);
+
+      val = o->view.butt[7]->value();
+      if(force || (val != auto_position))
+        opt_view_auto_position(i, GMSH_SET, val);
+
+      val = o->view.butt[25]->value();
+      if(force || (val != axes_auto_position))
+        opt_view_axes_auto_position(i, GMSH_SET, val);
+
+      val = o->view.butt[5]->value();
+      if(force || (val != draw_strings))
+        opt_view_draw_strings(i, GMSH_SET, val);
+
+      val = o->view.butt[11]->value();
+      if(force || (val != light))
+        opt_view_light(i, GMSH_SET, val);
+
+      val = o->view.butt[8]->value();
+      if(force || (val != light_lines))
+        opt_view_light_lines(i, GMSH_SET, val);
+
+      val = o->view.butt[9]->value();
+      if(force || (val != light_two_side))
+        opt_view_light_two_side(i, GMSH_SET, val);
+
+      val = o->view.butt[12]->value();
+      if(force || (val != smooth_normals))
+        opt_view_smooth_normals(i, GMSH_SET, val);
+
+      val = o->view.menu[0]->menu()[0].value() ? 1 : 0;
+      if(force || (val != draw_scalars))
+        opt_view_draw_scalars(i, GMSH_SET, val);
+
+      val = o->view.menu[0]->menu()[1].value() ? 1 : 0;
+      if(force || (val != draw_vectors))
+        opt_view_draw_vectors(i, GMSH_SET, val);
+
+      val = o->view.menu[0]->menu()[2].value() ? 1 : 0;
+      if(force || (val != draw_tensors))
+        opt_view_draw_tensors(i, GMSH_SET, val);
+
+      val = o->view.menu[1]->menu()[0].value() ? 1 : 0;
+      if(force || (val != draw_points))
+        opt_view_draw_points(i, GMSH_SET, val);
+
+      val = o->view.menu[1]->menu()[1].value() ? 1 : 0;
+      if(force || (val != draw_lines))
+        opt_view_draw_lines(i, GMSH_SET, val);
+
+      val = o->view.menu[1]->menu()[2].value() ? 1 : 0;
+      if(force || (val != draw_triangles))
+        opt_view_draw_triangles(i, GMSH_SET, val);
+
+      val = o->view.menu[1]->menu()[3].value() ? 1 : 0;
+      if(force || (val != draw_quadrangles))
+        opt_view_draw_quadrangles(i, GMSH_SET, val);
+
+      val = o->view.menu[1]->menu()[4].value() ? 1 : 0;
+      if(force || (val != draw_tetrahedra))
+        opt_view_draw_tetrahedra(i, GMSH_SET, val);
+
+      val = o->view.menu[1]->menu()[5].value() ? 1 : 0;
+      if(force || (val != draw_hexahedra))
+        opt_view_draw_hexahedra(i, GMSH_SET, val);
+
+      val = o->view.menu[1]->menu()[6].value() ? 1 : 0;
+      if(force || (val != draw_prisms))
+        opt_view_draw_prisms(i, GMSH_SET, val);
+
+      val = o->view.menu[1]->menu()[7].value() ? 1 : 0;
+      if(force || (val != draw_pyramids))
+        opt_view_draw_pyramids(i, GMSH_SET, val);
+
+      val = o->view.butt[6]->value();
+      if(force || (val != use_gen_raise))
+        opt_view_use_gen_raise(i, GMSH_SET, val);
+
+      val = o->view.butt[24]->value();
+      if(force || (val != fake_transparency))
+        opt_view_fake_transparency(i, GMSH_SET, val);
+
+      val = o->view.butt[26]->value();
+      if(force || (val != use_stipple))
+        opt_view_use_stipple(i, GMSH_SET, val);
+
+      val = o->view.butt[1]->value();
+      if(force || (val != center_glyphs))
+        opt_view_center_glyphs(i, GMSH_SET, val);
+
+      // view_values
+      
+      val = o->view.value[0]->value();
+      if(force || (val != normals))
+        opt_view_normals(i, GMSH_SET, val);
+
+      val = o->view.value[1]->value();
+      if(force || (val != tangents))
+        opt_view_tangents(i, GMSH_SET, val);
+
+      val = o->view.value[31]->value();
+      if(force || (val != custom_min))
+        opt_view_custom_min(i, GMSH_SET, val);
+
+      val = o->view.value[32]->value();
+      if(force || (val != custom_max))
+        opt_view_custom_max(i, GMSH_SET, val);
+
+      val = o->view.value[33]->value();
+      if(force || (val != max_recursion_level))
+        opt_view_max_recursion_level(i, GMSH_SET, val);
+
+      val = o->view.value[34]->value();
+      if(force || (val != target_error))
+        opt_view_target_error(i, GMSH_SET, val);
+
+      val = o->view.value[30]->value();
+      if(force || (val != nb_iso))
+        opt_view_nb_iso(i, GMSH_SET, val);
+
+      val = o->view.value[40]->value();
+      if(force || (val != offset0))
+        opt_view_offset0(i, GMSH_SET, val);
+
+      val = o->view.value[41]->value();
+      if(force || (val != offset1))
+        opt_view_offset1(i, GMSH_SET, val);
+
+      val = o->view.value[42]->value();
+      if(force || (val != offset2))
+        opt_view_offset2(i, GMSH_SET, val);
+
+      val = o->view.value[51]->value();
+      if(force || (val != transform00))
+        opt_view_transform00(i, GMSH_SET, val);
+
+      val = o->view.value[52]->value();
+      if(force || (val != transform01))
+        opt_view_transform01(i, GMSH_SET, val);
+
+      val = o->view.value[53]->value();
+      if(force || (val != transform02))
+        opt_view_transform02(i, GMSH_SET, val);
+
+      val = o->view.value[54]->value();
+      if(force || (val != transform10))
+        opt_view_transform10(i, GMSH_SET, val);
+
+      val = o->view.value[55]->value();
+      if(force || (val != transform11))
+        opt_view_transform11(i, GMSH_SET, val);
+
+      val = o->view.value[56]->value();
+      if(force || (val != transform12))
+        opt_view_transform12(i, GMSH_SET, val);
+
+      val = o->view.value[57]->value();
+      if(force || (val != transform20))
+        opt_view_transform20(i, GMSH_SET, val);
+
+      val = o->view.value[58]->value();
+      if(force || (val != transform21))
+        opt_view_transform21(i, GMSH_SET, val);
+
+      val = o->view.value[59]->value();
+      if(force || (val != transform22))
+        opt_view_transform22(i, GMSH_SET, val);
+
+      val = o->view.value[43]->value();
+      if(force || (val != raise0))
+        opt_view_raise0(i, GMSH_SET, val);
+
+      val = o->view.value[44]->value();
+      if(force || (val != raise1))
+        opt_view_raise1(i, GMSH_SET, val);
+
+      val = o->view.value[45]->value();
+      if(force || (val != raise2))
+        opt_view_raise2(i, GMSH_SET, val);
+
+      val = o->view.value[46]->value();
+      if(force || (val != normal_raise))
+        opt_view_normal_raise(i, GMSH_SET, val);
+
+      val = o->view.value[50]->value();
+      if(force || (val != timestep))
+        opt_view_timestep(i, GMSH_SET, val);
+
+      val = o->view.value[60]->value();
+      if(force || (val != arrow_size))
+        opt_view_arrow_size(i, GMSH_SET, val);
+
+      val = o->view.value[63]->value();
+      if(force || (val != displacement_factor))
+        opt_view_displacement_factor(i, GMSH_SET, val);
+
+      val = o->view.value[61]->value();
+      if(force || (val != point_size))
+        opt_view_point_size(i, GMSH_SET, val);
+
+      val = o->view.value[62]->value();
+      if(force || (val != line_width))
+        opt_view_line_width(i, GMSH_SET, val);
+
+      val = o->view.value[12]->value();
+      if(force || (val != explode))
+        opt_view_explode(i, GMSH_SET, val);
+
+      val = o->view.value[10]->value();
+      if(force || (val != angle_smooth_normals))
+        opt_view_angle_smooth_normals(i, GMSH_SET, val);
+
+      val = o->view.value[20]->value();
+      if(force || (val != position0))
+        opt_view_position0(i, GMSH_SET, val);
+
+      val = o->view.value[21]->value();
+      if(force || (val != position1))
+        opt_view_position1(i, GMSH_SET, val);
+
+      val = o->view.value[22]->value();
+      if(force || (val != size0))
+        opt_view_size0(i, GMSH_SET, val);
+      
+      val = o->view.value[23]->value();
+      if(force || (val != size1))
+        opt_view_size1(i, GMSH_SET, val);
+
+      val = o->view.value[13]->value();
+      if(force || (val != axes_xmin))
+        opt_view_axes_xmin(i, GMSH_SET, val);
+
+      val = o->view.value[14]->value();
+      if(force || (val != axes_ymin))
+        opt_view_axes_ymin(i, GMSH_SET, val);
+
+      val = o->view.value[15]->value();
+      if(force || (val != axes_zmin))
+        opt_view_axes_zmin(i, GMSH_SET, val);
+
+      val = o->view.value[16]->value();
+      if(force || (val != axes_xmax))
+        opt_view_axes_xmax(i, GMSH_SET, val);
+
+      val = o->view.value[17]->value();
+      if(force || (val != axes_ymax))
+        opt_view_axes_ymax(i, GMSH_SET, val);
+
+      val = o->view.value[18]->value();
+      if(force || (val != axes_zmax))
+        opt_view_axes_zmax(i, GMSH_SET, val);
+
+      val = o->view.value[2]->value();
+      if(force || (val != gen_raise_factor))
+        opt_view_gen_raise_factor(i, GMSH_SET, val);
+
+      val = o->view.value[3]->value();
+      if(force || (val != axes_tics0))
+        opt_view_axes_tics0(i, GMSH_SET, val);
+
+      val = o->view.value[4]->value();
+      if(force || (val != axes_tics1))
+        opt_view_axes_tics1(i, GMSH_SET, val);
+
+      val = o->view.value[5]->value();
+      if(force || (val != axes_tics2))
+        opt_view_axes_tics2(i, GMSH_SET, val);
+
+      // view_inputs
+
+      const char *str;
+
+      str = o->view.input[0]->value();
+      if(force || strcmp(str, name))
+        opt_view_name(i, GMSH_SET, str);
+
+      str = o->view.input[1]->value();
+      if(force || strcmp(str, format))
+        opt_view_format(i, GMSH_SET, str);
+
+      str = o->view.input[10]->value();
+      if(force || strcmp(str, axes_label0))
+        opt_view_axes_label0(i, GMSH_SET, str);
+
+      str = o->view.input[11]->value();
+      if(force || strcmp(str, axes_label1))
+        opt_view_axes_label1(i, GMSH_SET, str);
+
+      str = o->view.input[12]->value();
+      if(force || strcmp(str, axes_label2))
+        opt_view_axes_label2(i, GMSH_SET, str);
+
+      str = o->view.input[7]->value();
+      if(force || strcmp(str, axes_format0))
+        opt_view_axes_format0(i, GMSH_SET, str);
+
+      str = o->view.input[8]->value();
+      if(force || strcmp(str, axes_format1))
+        opt_view_axes_format1(i, GMSH_SET, str);
+
+      str = o->view.input[9]->value();
+      if(force || strcmp(str, axes_format2))
+        opt_view_axes_format2(i, GMSH_SET, str);
+
+      str = o->view.input[4]->value();
+      if(force || strcmp(str, gen_raise0))
+        opt_view_gen_raise0(i, GMSH_SET, str);
+
+      str = o->view.input[5]->value();
+      if(force || strcmp(str, gen_raise1))
+        opt_view_gen_raise1(i, GMSH_SET, str);
+
+      str = o->view.input[6]->value();
+      if(force || strcmp(str, gen_raise2))
+        opt_view_gen_raise2(i, GMSH_SET, str);
+
+      // colors (since the color buttons modify the values directly
+      // through callbacks, we can use the opt_XXX routines directly)
+      if(force || (i != current)){
+        opt_view_color_points
+          (i, GMSH_SET, opt_view_color_points(current, GMSH_GET, 0));
+        opt_view_color_lines
+          (i, GMSH_SET, opt_view_color_lines(current, GMSH_GET, 0));
+        opt_view_color_triangles
+          (i, GMSH_SET, opt_view_color_triangles(current, GMSH_GET, 0));
+        opt_view_color_quadrangles
+          (i, GMSH_SET, opt_view_color_quadrangles(current, GMSH_GET, 0));
+        opt_view_color_tetrahedra
+          (i, GMSH_SET, opt_view_color_tetrahedra(current, GMSH_GET, 0));
+        opt_view_color_hexahedra
+          (i, GMSH_SET, opt_view_color_hexahedra(current, GMSH_GET, 0));
+        opt_view_color_prisms
+          (i, GMSH_SET, opt_view_color_prisms(current, GMSH_GET, 0));
+        opt_view_color_pyramids
+          (i, GMSH_SET, opt_view_color_pyramids(current, GMSH_GET, 0));
+        opt_view_color_tangents
+          (i, GMSH_SET, opt_view_color_tangents(current, GMSH_GET, 0));
+        opt_view_color_normals
+          (i, GMSH_SET, opt_view_color_normals(current, GMSH_GET, 0));
+        opt_view_color_text2d
+          (i, GMSH_SET, opt_view_color_text2d(current, GMSH_GET, 0));
+        opt_view_color_text3d
+          (i, GMSH_SET, opt_view_color_text3d(current, GMSH_GET, 0));
+        opt_view_color_axes
+          (i, GMSH_SET, opt_view_color_axes(current, GMSH_GET, 0));
+      }
+
+      // colorbar window
+
+      if(force || (i != current)) {
+        ColorTable_Copy(&PView::list[current]->getOptions()->CT);
+        ColorTable_Paste(&PView::list[i]->getOptions()->CT);
+        PView::list[i]->setChanged(true);
+      }
+    }
+  }
+
+  if(CTX.fast_redraw)
+    CTX.post.draw = CTX.mesh.draw = 0;
+  Draw();
+  CTX.post.draw = CTX.mesh.draw = 1;
+}
+
 optionWindow::optionWindow(int fontsize) : _fontsize(fontsize)
 {
   int width = 34 * _fontsize + WB;
@@ -104,7 +1158,7 @@ optionWindow::optionWindow(int fontsize) : _fontsize(fontsize)
   {
     Fl_Button *o = new Fl_Button
       (width - BB - WB, height - BH - WB, BB, BH, "Cancel");
-    o->callback(cancel_cb, (void *)win);
+    o->callback(hide_cb, (void *)win);
   }
   {
     Fl_Button *o = new Fl_Button
@@ -2221,3 +3275,199 @@ void optionWindow::updateViewGroup(int index)
   view.colorbar->update(data->getName().c_str(), data->getMin(), 
                         data->getMax(), &opt->CT, &v->getChanged());
 }
+
+void optionWindow::activate(const char *what)
+{
+  if(!what) return;
+
+  // activate/deactivate parts of the option window depending on the
+  // user's choices (or the option settings)
+  if(!strcmp(what, "fast_redraw")){
+    if(general.butt[2]->value())
+      redraw->show();
+    else
+      redraw->hide();
+  }
+  else if(!strcmp(what, "rotation_center")){
+    if(general.butt[15]->value()) {
+      general.push[0]->deactivate();
+      general.value[8]->deactivate();
+      general.value[9]->deactivate();
+      general.value[10]->deactivate();
+    }
+    else {
+      general.push[0]->activate();
+      general.value[8]->activate();
+      general.value[9]->activate();
+      general.value[10]->activate();
+    }
+  }
+  else if(!strcmp(what, "general_axes")){
+    if(general.choice[4]->value()){
+      general.value[17]->activate();
+      general.value[18]->activate();
+      general.value[19]->activate();
+      general.input[3]->activate();
+      general.input[4]->activate();
+      general.input[5]->activate();
+      general.input[6]->activate();
+      general.input[7]->activate();
+      general.input[8]->activate();
+    }
+    else{
+      general.value[17]->deactivate();
+      general.value[18]->deactivate();
+      general.value[19]->deactivate();
+      general.input[3]->deactivate();
+      general.input[4]->deactivate();
+      general.input[5]->deactivate();
+      general.input[6]->deactivate();
+      general.input[7]->deactivate();
+      general.input[8]->deactivate();
+    }
+  }
+  else if(!strcmp(what, "general_axes_auto")){
+    if(general.butt[0]->value()){
+      general.value[20]->deactivate();
+      general.value[21]->deactivate();
+      general.value[22]->deactivate();
+      general.value[23]->deactivate();
+      general.value[24]->deactivate();
+      general.value[25]->deactivate();
+    }
+    else{
+      general.value[20]->activate();
+      general.value[21]->activate();
+      general.value[22]->activate();
+      general.value[23]->activate();
+      general.value[24]->activate();
+      general.value[25]->activate();
+    }
+  }
+  else if(!strcmp(what, "general_small_axes")){
+    if(general.butt[1]->value()){
+      general.value[26]->activate();
+      general.value[27]->activate();
+    }
+    else{
+      general.value[26]->deactivate();
+      general.value[27]->deactivate();
+    }
+  }
+  else if(!strcmp(what, "custom_range")){
+    if(view.choice[7]->value() == 1){
+      view.value[31]->activate();
+      view.value[32]->activate();
+      view.push[1]->activate();
+      view.push[2]->activate();
+    }
+    else {
+      view.value[31]->deactivate();
+      view.value[32]->deactivate();
+      view.push[1]->deactivate();
+      view.push[2]->deactivate();
+    }
+  }
+  else if(!strcmp(what, "general_transform")){
+    if(view.butt[6]->value()){
+      view.choice[11]->activate();
+      view.value[2]->activate();
+      view.input[4]->activate();
+      view.input[5]->activate();
+      view.input[6]->activate();
+    }
+    else{
+      view.choice[11]->deactivate();
+      view.value[2]->deactivate();
+      view.input[4]->deactivate();
+      view.input[5]->deactivate();
+      view.input[6]->deactivate();
+    }
+  }
+  else if(!strcmp(what, "mesh_light")){
+    if(mesh.butt[17]->value()){
+      mesh.butt[18]->activate();
+      mesh.butt[19]->activate();
+      mesh.butt[20]->activate();
+      mesh.butt[0]->activate();
+      mesh.value[18]->activate();
+    }
+    else{
+      mesh.butt[18]->deactivate();
+      mesh.butt[19]->deactivate();
+      mesh.butt[20]->deactivate();
+      mesh.butt[0]->deactivate();
+      mesh.value[18]->deactivate();
+    }
+  }
+  else if(!strcmp(what, "view_light")){
+    if(view.butt[11]->value()){
+      view.butt[8]->activate();
+      view.butt[9]->activate();
+      view.butt[12]->activate();
+      view.value[10]->activate();
+    }
+    else{
+      view.butt[8]->deactivate();
+      view.butt[9]->deactivate();
+      view.butt[12]->deactivate();
+      view.value[10]->deactivate();
+    }
+  }
+  else if(!strcmp(what, "view_axes")){
+    if(view.choice[8]->value()){
+      view.value[3]->activate();
+      view.value[4]->activate();
+      view.value[5]->activate();
+      view.input[7]->activate();
+      view.input[8]->activate();
+      view.input[9]->activate();
+      view.input[10]->activate();
+      view.input[11]->activate();
+      view.input[12]->activate();
+    }
+    else{
+      view.value[3]->deactivate();
+      view.value[4]->deactivate();
+      view.value[5]->deactivate();
+      view.input[7]->deactivate();
+      view.input[8]->deactivate();
+      view.input[9]->deactivate();
+      view.input[10]->deactivate();
+      view.input[11]->deactivate();
+      view.input[12]->deactivate();
+    }
+  }
+  else if(!strcmp(what, "view_axes_auto_3d")){
+    if(view.butt[25]->value()){
+      view.value[13]->deactivate();
+      view.value[14]->deactivate();
+      view.value[15]->deactivate();
+      view.value[16]->deactivate();
+      view.value[17]->deactivate();
+      view.value[18]->deactivate();
+    }
+    else{
+      view.value[13]->activate();
+      view.value[14]->activate();
+      view.value[15]->activate();
+      view.value[16]->activate();
+      view.value[17]->activate();
+      view.value[18]->activate();
+    }
+  }
+  else if(!strcmp(what, "view_axes_auto_2d")){
+    if(view.butt[7]->value()){
+      view.value[20]->deactivate();
+      view.value[21]->deactivate();
+      view.value[22]->deactivate();
+      view.value[23]->deactivate();
+    }
+    else{
+      view.value[20]->activate();
+      view.value[21]->activate();
+      view.value[22]->activate();
+      view.value[23]->activate();
+    }
+  }
+}
diff --git a/Fltk/optionWindow.h b/Fltk/optionWindow.h
index b103a78b90..e182003554 100644
--- a/Fltk/optionWindow.h
+++ b/Fltk/optionWindow.h
@@ -90,6 +90,16 @@ class optionWindow{
   void resetBrowser();
   void resetExternalViewList();
   void updateViewGroup(int index);
+  void activate(const char *what);
 };
 
+void options_cb(Fl_Widget *w, void *data);
+void options_save_cb(Fl_Widget *w, void *data);
+void general_options_cb(Fl_Widget *w, void *data);
+void geometry_options_cb(Fl_Widget *w, void *data);
+void mesh_options_cb(Fl_Widget *w, void *data);
+void solver_options_cb(Fl_Widget *w, void *data);
+void post_options_cb(Fl_Widget *w, void *data);
+void view_options_cb(Fl_Widget *w, void *data);
+
 #endif
diff --git a/Fltk/pluginWindow.cpp b/Fltk/pluginWindow.cpp
index 6aac712470..b66a65ed2c 100644
--- a/Fltk/pluginWindow.cpp
+++ b/Fltk/pluginWindow.cpp
@@ -8,16 +8,150 @@
 #include <FL/Fl_Tabs.H>
 #include <FL/Fl_Scroll.H>
 #include "GUI.h"
+#include "Draw.h"
 #include "pluginWindow.h"
 #include "shortcutWindow.h"
 #include "PView.h"
 #include "PluginManager.h"
 #include "Plugin.h"
-#include "Callbacks.h"
 #include "Context.h"
 
 extern Context_T CTX;
 
+void plugin_cb(Fl_Widget *w, void *data)
+{
+  GUI::instance()->plugins->show((int)(long)data);
+}
+
+static void plugin_input_value_cb(Fl_Widget *w, void *data)
+{
+  double (*f)(int, int, double) = (double (*)(int, int, double)) data;
+  Fl_Value_Input *input = (Fl_Value_Input*) w;
+  f(-1, 0, input->value());
+}
+
+static void plugin_input_cb(Fl_Widget *w, void *data)
+{
+  const char* (*f)(int, int, const char*) = (const char* (*)(int, int, const char*)) data;
+  Fl_Input *input = (Fl_Input*) w;
+  f(-1, 0, input->value());
+}
+
+static void plugin_browser_cb(Fl_Widget *w, void *data)
+{
+  // get selected plugin
+  GMSH_Plugin *p = 0;
+  for(int i = 1; i <= GUI::instance()->plugins->browser->size(); i++) {
+    if(GUI::instance()->plugins->browser->selected(i)) {
+      p = (GMSH_Plugin*)GUI::instance()->plugins->browser->data(i);
+      break;
+    }
+  }
+  if(!p) return;
+
+  // get first first selected view
+  int iView = -1;
+  for(int i = 1; i <= GUI::instance()->plugins->view_browser->size(); i++) {
+    if(GUI::instance()->plugins->view_browser->selected(i)) {
+      iView = i - 1;
+      break;
+    }
+  }
+
+  // set the Fl_Value_Input callbacks and configure the input value
+  // fields (we get step, min and max by calling the option function
+  // with action==1, 2 and 3, respectively)
+  int n = p->getNbOptions();
+  if(n > MAX_PLUGIN_OPTIONS) n = MAX_PLUGIN_OPTIONS;
+  for(int i = 0; i < n; i++) {
+    StringXNumber *sxn = p->getOption(i);
+    if(sxn->function){
+      p->dialogBox->value[i]->callback(plugin_input_value_cb, (void*)sxn->function);
+      if(iView >= 0){
+        p->dialogBox->value[i]->step(sxn->function(iView, 1, 0.));
+        p->dialogBox->value[i]->minimum(sxn->function(iView, 2, 0.));
+        p->dialogBox->value[i]->maximum(sxn->function(iView, 3, 0.));
+      }
+    }
+  }
+
+  // set the Fl_Input callbacks
+  int m = p->getNbOptionsStr();
+  if(m > MAX_PLUGIN_OPTIONS) m = MAX_PLUGIN_OPTIONS;
+  for(int i = 0; i < m; i++) {
+    StringXString *sxs = p->getOptionStr(i);
+    if(sxs->function){
+      p->dialogBox->input[i]->callback(plugin_input_cb, (void*)sxs->function);
+    }
+  }
+
+  // hide all plugin groups except the selected one
+  for(int i = 1; i <= GUI::instance()->plugins->browser->size(); i++)
+    ((GMSH_Plugin*)GUI::instance()->plugins->browser->data(i))->dialogBox->group->hide();
+  p->dialogBox->group->show();
+}
+
+static void plugin_run_cb(Fl_Widget *w, void *data)
+{
+  // get selected plugin
+  GMSH_Post_Plugin *p = 0;
+  for(int i = 1; i <= GUI::instance()->plugins->browser->size(); i++) {
+    if(GUI::instance()->plugins->browser->selected(i)) {
+      p = (GMSH_Post_Plugin*)GUI::instance()->plugins->browser->data(i);
+      break;
+    }
+  }
+  if(!p) return;
+
+  if(p->dialogBox) { // get the values from the GUI
+    int m = p->getNbOptionsStr();
+    int n = p->getNbOptions();
+    if(m > MAX_PLUGIN_OPTIONS) m = MAX_PLUGIN_OPTIONS;
+    if(n > MAX_PLUGIN_OPTIONS) n = MAX_PLUGIN_OPTIONS;
+    for(int i = 0; i < m; i++) {
+      StringXString *sxs = p->getOptionStr(i);
+      sxs->def = p->dialogBox->input[i]->value();
+    }
+    for(int i = 0; i < n; i++) {
+      StringXNumber *sxn = p->getOption(i);
+      sxn->def = p->dialogBox->value[i]->value();
+    }
+  }
+
+  // run on all selected views
+  bool no_view_selected = true;
+  for(int i = 1; i <= GUI::instance()->plugins->view_browser->size(); i++) {
+    if(GUI::instance()->plugins->view_browser->selected(i)) {
+      no_view_selected = false;
+      try{
+        if(i - 1 >= 0 && i - 1 < (int)PView::list.size())
+          p->execute(PView::list[i - 1]);
+        else
+          p->execute(0);
+      }
+      catch(GMSH_Plugin * err) {
+        char tmp[256];
+        p->catchErrorMessage(tmp);
+        Msg::Warning("%s", tmp);
+      }
+    }
+  }
+  if(no_view_selected){
+    p->execute(0);
+  }
+
+  GUI::instance()->updateViews();
+  CTX.post.plugin_draw_function = NULL;
+  Draw();
+}
+
+static void plugin_cancel_cb(Fl_Widget *w, void *data)
+{
+  GUI::instance()->plugins->win->hide();
+  CTX.post.plugin_draw_function = NULL;
+  Draw();
+}
+
 pluginWindow::pluginWindow(int fontsize) : _fontsize(fontsize)
 {
   int width0 = 34 * _fontsize + WB;
@@ -32,21 +166,21 @@ pluginWindow::pluginWindow(int fontsize) : _fontsize(fontsize)
   {
     Fl_Button *o = new Fl_Button
       (width - BB - WB, height - BH - WB, BB, BH, "Cancel");
-    o->callback(view_plugin_cancel_cb);
+    o->callback(plugin_cancel_cb);
   }
   {
     run = new Fl_Return_Button
       (width - 2 * BB - 2 * WB, height - BH - WB, BB, BH, "Run");
-    run->callback(view_plugin_run_cb);
+    run->callback(plugin_run_cb);
   }
   
   int L1 = (int)(0.3 * width), L2 = (int)(0.6 * L1);
   browser = new Fl_Hold_Browser(WB, WB, L1, height - 3 * WB - BH);
-  browser->callback(view_plugin_browser_cb);
+  browser->callback(plugin_browser_cb);
 
   view_browser = new Fl_Multi_Browser(WB + L1, WB, L2, height - 3 * WB - BH);
   view_browser->has_scrollbar(Fl_Browser_::VERTICAL);
-  view_browser->callback(view_plugin_browser_cb);
+  view_browser->callback(plugin_browser_cb);
 
   for(GMSH_PluginManager::iter it = GMSH_PluginManager::instance()->begin();
       it != GMSH_PluginManager::instance()->end(); ++it) {
@@ -79,7 +213,7 @@ void pluginWindow::show(int viewIndex)
   if(viewIndex >= 0 && viewIndex < (int)PView::list.size()){
     view_browser->deselect();
     view_browser->select(viewIndex + 1);
-    view_plugin_browser_cb(NULL, NULL);
+    plugin_browser_cb(NULL, NULL);
   }
   win->show();
 }
@@ -183,5 +317,5 @@ void pluginWindow::resetViewBrowser()
     view_browser->deactivate();
   }
 
-  view_plugin_browser_cb(NULL, NULL);
+  plugin_browser_cb(NULL, NULL);
 }
diff --git a/Fltk/pluginWindow.h b/Fltk/pluginWindow.h
index 697a4eae10..3f06646628 100644
--- a/Fltk/pluginWindow.h
+++ b/Fltk/pluginWindow.h
@@ -38,4 +38,6 @@ class pluginWindow{
   void resetViewBrowser();
 };
 
+void plugin_cb(Fl_Widget *w, void *data);
+
 #endif
diff --git a/Fltk/projectionEditor.cpp b/Fltk/projectionEditor.cpp
index 55f1ea5c10..5067b8e204 100644
--- a/Fltk/projectionEditor.cpp
+++ b/Fltk/projectionEditor.cpp
@@ -62,439 +62,128 @@ static fourierProjectionFace *createProjectionFaceFromName(const char *name)
   return f;
 }
 
-uvPlot::uvPlot(int x, int y, int w, int h, const char *l)
-  : Fl_Window(x, y, w, h, l), _dmin(0.), _dmax(0.)
-{
-  ColorTable_InitParam(2, &_colorTable);
-  ColorTable_Recompute(&_colorTable);
-}
-
-void uvPlot::set(std::vector<double> &u, std::vector<double> &v, 
-                 std::vector<double> &dist, std::vector<std::complex<double> > &f)
-{ 
-  _u = u; 
-  _v = v;
-  _dist = dist;
-  _f = f;
-  if(dist.empty()){
-    _dmin = _dmax = 0.;
-  }
-  else{
-    _dmin = _dmax = dist[0];
-    for(unsigned int i = 1; i < dist.size(); i++){
-      _dmin = std::min(_dmin, dist[i]);
-      _dmax = std::max(_dmax, dist[i]);
-    }
+static void project_point(FM::ProjectionSurface *ps, double x, double y, double z,
+                          std::vector<double> &u, std::vector<double> &v, 
+                          std::vector<double> &dist,
+                          std::vector<std::complex<double> > &f)
+{                  
+  double uu, vv, p[3], n[3];
+  ps->OrthoProjectionOnSurface(x, y, z, uu, vv);
+  if(uu >= 0. && uu <= 1. && vv >= 0. && vv <= 1.){
+    ps->F(uu, vv, p[0], p[1], p[2]);
+    ps->GetUnitNormal(uu, vv, n[0], n[1], n[2]);
+    double dx = x - p[0], dy = y - p[1], dz = z - p[2];
+    u.push_back(uu);
+    v.push_back(vv);
+    dist.push_back(sqrt(dx * dx + dy * dy + dz * dz));
+    f.push_back(dx * n[0] + dy * n[1] + dz * n[2]);
   }
-  redraw();
 }
 
-void uvPlot::color(double d)
+static void getTangents(const SVector3 n, SVector3 &t1, SVector3 &t2, const double angle)
 {
-  int index;
-  if(_dmin == _dmax)
-    index = _colorTable.size / 2;
+  SVector3 ex(0., 0., 0.);
+  if(n[0] == 0.)
+    ex[0] = 1.;
+  else if(n[1] == 0.)
+    ex[1] = 1.;
   else
-    index = (int)((d - _dmin) * (_colorTable.size - 1) / (_dmax - _dmin));
-  unsigned int color = _colorTable.table[index];
-  int r = CTX.UNPACK_RED(color);
-  int g = CTX.UNPACK_GREEN(color);
-  int b = CTX.UNPACK_BLUE(color);
-  fl_color(r, g, b);
+    ex[2] = 1.;
+  SVector3 a = crossprod(n, ex);
+  a.normalize();
+  SVector3 b = crossprod(n, a);
+  b.normalize();
+  double x = n[0], y = n[1], z = n[2];
+  double c = cos(angle * M_PI / 180.), s = sin(angle * M_PI / 180.);
+  double rot[3][3] = 
+    {{x * x * (1-c) + c    , x * y * (1-c) - z * s, x * z * (1-c) + y * s},
+     {y * x * (1-c) + z * s, y * y * (1-c) + c    , y * z * (1-c) - x * s},
+     {x * z * (1-c) - y * s, y * z * (1-c) + x * s, z * z * (1-c) + c    }};
+  for(int i = 0; i < 3; i++){
+    t1[i] = t2[i] = 0.;
+    for(int j = 0; j < 3; j++){
+      t1[i] += rot[i][j] * a[j];
+      t2[i] += rot[i][j] * b[j];
+    }
+  }
 }
 
-void uvPlot::draw()
+static void update_cb(Fl_Widget *w, void *data)
 {
-  // draw background
-  fl_color(FL_WHITE);
-  fl_rectf(0, 0, w(), h());
+  projectionEditor *e = (projectionEditor*)data;
 
-  // draw points in u,v space, colored by their distance to the
-  // projection surface
-  int pw = w();
-  int ph = h() - (2 * GetFontSize() + 5);
-  for(unsigned int i = 0; i < _u.size(); i++){
-    int x = (int)(_u[i] * pw);
-    int y = (int)(_v[i] * ph);
-    color(_dist[i]);
-    fl_rect(x, y, 3, 3);
-  }
+  // get all parameters from GUI and modify projection surface accordingly
 
-  // draw color bar
-  for(int i = 0; i < w(); i++){
-    int index = (int)(i * (_colorTable.size - 1) / w());
-    unsigned int color = _colorTable.table[index];
-    int r = CTX.UNPACK_RED(color);
-    int g = CTX.UNPACK_GREEN(color);
-    int b = CTX.UNPACK_BLUE(color);
-    fl_color(r, g, b);
-    fl_line(i, ph, i, ph + 10);
+  projection *p = e->getCurrentProjection();
+  if(p){
+    FM::ProjectionSurface *ps = (FM::ProjectionSurface*)p->face->getNativePtr();
+    ps->SetOrigin(p->parameters[0]->value(),
+                  p->parameters[1]->value(),
+                  p->parameters[2]->value());
+    SVector3 n(p->parameters[3]->value(),
+               p->parameters[4]->value(),
+               p->parameters[5]->value());
+    if(!n.normalize()) n[2] = 1.;
+    SVector3 t1, t2;
+    getTangents(n, t1, t2, p->parameters[6]->value());
+    ps->SetE0(n[0], n[1], n[2]);
+    ps->SetE1(t1[0], t1[1], t1[2]);
+    ps->SetE2(t2[0], t2[1], t2[2]);
+    ps->SetScale(p->parameters[7]->value(),
+                 p->parameters[8]->value(),
+                 p->parameters[9]->value());
+    for (int i = 0; i < ps->GetNumParameters(); i++)
+      ps->SetParameter(i, p->parameters[i + 10]->value());
+
+    p->face->buildSTLTriangulation();
+
+    // project selected points and elements and update u,v display
+    std::vector<double> u, v, dist;
+    std::vector<std::complex<double> > f;
+    std::vector<GEntity*> &ent(e->getEntities());
+    for(unsigned int i = 0; i < ent.size(); i++){
+      if(ent[i]->getSelection()){
+        GVertex *gv = dynamic_cast<GVertex*>(ent[i]);
+        if(!gv)
+          Msg::Error("Problem in point selection processing");
+        else
+          project_point(ps, gv->x(), gv->y(), gv->z(), u, v, dist, f);
+      }
+    }
+    std::vector<MElement*> &ele(e->getElements());
+    std::set<MVertex*> verts;
+    for(unsigned int i = 0; i < ele.size(); i++)
+      if(ele[i]->getVisibility() == 2)
+        for(int j = 0; j < ele[i]->getNumVertices(); j++)
+          verts.insert(ele[i]->getVertex(j));
+    for(std::set<MVertex*>::iterator it = verts.begin(); it != verts.end(); it++)
+      project_point(ps, (*it)->x(), (*it)->y(), (*it)->z(), u, v, dist, f);
+    e->uv()->set(u, v, dist, f);
   }
 
-  // draw labels
-  fl_color(FL_BLACK);
-  fl_font(FL_HELVETICA, GetFontSize());
-  static char min[256], max[256], pts[256];
-  sprintf(min, "%g", _dmin);
-  sprintf(max, "%g", _dmax);
-  sprintf(pts, "[%d pts]", (int)_u.size());
-  fl_draw(min, 5, h() - 5);
-  fl_draw(pts, pw / 2 - (int)fl_width(pts) / 2, h() - 5);
-  fl_draw(max, pw - (int)fl_width(max) - 5, h() - 5);
+  Draw();
 }
 
-projection::projection(fourierProjectionFace *f, int x, int y, int w, int h, 
-                       int bb, int bh, projectionEditor *e) 
-  : face(f)
+static void browse_cb(Fl_Widget *w, void *data)
 {
-  group = new Fl_Scroll(x, y, w, h);
-  SBoundingBox3d bounds = GModel::current()->bounds();
-  FM::ProjectionSurface *ps = (FM::ProjectionSurface*)f->getNativePtr();
-  
-  Fl_Toggle_Button *b = new Fl_Toggle_Button(x, y, bb, bh, "Set position");
-  b->callback(set_position_cb, e);
-  
-  { // origin is stored in parameters[0,1,2]
-    SPoint3 pc = bounds.center();
-    for(int i = 0; i < 3; i++){
-      Fl_Value_Input *v = new Fl_Value_Input(x, y + (1 + i) * bh, bb, bh);
-      parameters.push_back(v);
-      v->maximum(bounds.max()[i] + 10. * CTX.lc);
-      v->minimum(bounds.min()[i] - 10. * CTX.lc);
-      v->step(CTX.lc / 100.);
-      v->value(pc[i]);
-      v->label((i == 0) ? "X" : (i == 1) ? "Y" : "Z");
-    }
-    ps->SetOrigin(pc[0], pc[1], pc[2]);
-    Fl_Repeat_Button *bm[3], *bp[3];
-    for(int i = 0; i < 3; i++){
-      new Fl_Box(x + w - bb / 3 - bb / 6, y + (1 + i) * bh, bb / 8, bh, 
-                 (i == 0) ? "E0" : (i == 1) ? "E1" : "E2");
-      bp[i] = new Fl_Repeat_Button(x + w - bb / 3, y + (1 + i) * bh, 
-                                   bb / 8, bh / 2, "+");
-      bm[i] = new Fl_Repeat_Button(x + w - bb / 3, y + (1 + i) * bh + bh / 2,
-                                   bb / 8, bh / 2, "-");
-    }
-    bp[0]->callback(translate_p0_cb, e);
-    bp[1]->callback(translate_p1_cb, e);
-    bp[2]->callback(translate_p2_cb, e);
-    bm[0]->callback(translate_m0_cb, e);
-    bm[1]->callback(translate_m1_cb, e);
-    bm[2]->callback(translate_m2_cb, e);
-  }
-  { // normal is stored in parameters[3,4,5]
-    Fl_Value_Input *v1 = new Fl_Value_Input(x, y + 4 * bh, bb / 3, bh);
-    parameters.push_back(v1);
-    v1->maximum(1.); v1->minimum(-1.); v1->step(0.01); v1->value(0.);
-    Fl_Value_Input *v2 = new Fl_Value_Input(x + bb / 3, y + 4 * bh, bb / 3, bh);
-    parameters.push_back(v2);
-    v2->maximum(1.); v2->minimum(-1.); v2->step(0.01); v2->value(0.);
-    Fl_Value_Input *v3 = new Fl_Value_Input(x + 2 * bb / 3, y + 4 * bh, bb - 2 * bb / 3, bh);
-    parameters.push_back(v3);
-    v3->maximum(1.); v3->minimum(-1.); v3->step(0.01); v3->value(1.);
-    v3->label("Normal");
-    Fl_Button *b = new Fl_Button(x + w - bb / 3, y + 4 * bh + bh / 4, bb / 8, bh / 2, "-");
-    b->callback(invert_normal_cb, e);
-    b->tooltip("Invert normal");
-  }
-  { // rotation is stored in parameters[6]
-    Fl_Value_Input *v = new Fl_Value_Input(x, y + 5 * bh, bb, bh, "Rotation");
-    v->maximum(-180.);
-    v->minimum(180.);
-    v->step(0.1);
-    v->value(0.);
-    parameters.push_back(v);
-  }
-  { // scale is stored in parameters[7,8,9]
-    for(int i = 0; i < 3; i++){
-      Fl_Value_Input *v = new Fl_Value_Input(x, y + (6 + i) * bh, bb, bh);
-      parameters.push_back(v);
-      v->maximum(CTX.lc * 10.);
-      v->minimum(CTX.lc / 100.);
-      v->step(CTX.lc / 100.);
-      v->value(CTX.lc / 10.);
-      v->label((i == 0) ? "Scale0" : (i == 1) ? "Scale1" : "Scale2");
-    }
-  }
+  projectionEditor *e = (projectionEditor*)data;
 
-  // other parameters are stored in parameters[10,...]
-  for(int i = 0; i < ps->GetNumParameters(); i++){
-    Fl_Value_Input *v = new Fl_Value_Input(x, y + (9 + i) * bh, bb, bh);
-    v->maximum(10. * CTX.lc);
-    v->minimum(-10. * CTX.lc);
-    v->step(CTX.lc / 100.);
-    v->label(strdup(ps->GetLabel(i).c_str()));
-    v->value(ps->GetParameter(i));
-    parameters.push_back(v);
+  std::vector<projection*> &projections(e->getProjections());
+  for(unsigned int i = 0; i < projections.size(); i++){
+    projections[i]->face->setVisibility(false);
+    projections[i]->group->hide();
   }
-
-  for(unsigned int i = 0; i < parameters.size(); i++){
-    parameters[i]->align(FL_ALIGN_RIGHT);
-    parameters[i]->callback(update_cb, e);
+  
+  projection *p = e->getCurrentProjection();
+  if(p){
+    p->face->setVisibility(true);
+    p->group->show();
   }
 
-  group->end();
-  group->hide();
+  update_cb(0, data);
 }
 
-projectionEditor::projectionEditor() 
-{
-  GModel *m = GModel::current();
-
-  // construct FM_Internals 
-  m->readFourier();
-  printf("readerSize = %d\n",m->getFMInternals()->getSize());
-  printf("currentSize = %d\n",m->getFMInternals()->current()->GetNumGroups());
-
-  // construct GUI in terms of standard sizes
-  int _fontsize = GetFontSize();
-  const int width = (int)(3.75 * BB), height = 25 * BH;
-  
-  // create all widgets (we construct this once, we never deallocate!)
-  _window = new dialogWindow(width, height, CTX.non_modal_windows, "Reparameterize");
-  
-  new Fl_Box(WB, WB + BH / 2, BB / 2, BH, "Select:");
-  
-  Fl_Group *o = new Fl_Group(WB, WB, 2 * BB, 3 * BH);
-  _select[0] = new Fl_Round_Button(2 * WB + BB / 2, WB, BB, BH, "Points");
-  _select[1] = new Fl_Round_Button(2 * WB + BB / 2, WB + BH, BB, BH, "Elements");
-  if(m->getNumMeshElements())
-    _select[1]->value(1);
-  else
-    _select[0]->value(1);
-  for(int i = 0; i < 2; i++){
-    _select[i]->callback(select_cb, this);
-    _select[i]->type(FL_RADIO_BUTTON);
-  }
-  o->end();
-
-  {  
-    Fl_Toggle_Button *b1 = new Fl_Toggle_Button
-      (width - WB - 3 * BB / 2, WB, 3 * BB / 2, BH, "Hide unselected");
-    b1->callback(hide_cb);
-    Fl_Button *b2 = new Fl_Button
-      (width - WB - 3 * BB / 2, WB + BH, 3 * BB / 2, BH, "Save selection");
-    b2->callback(save_selection_cb, this);
-  }
-
-  const int brw = (int)(1.3 * BB);
-
-  _browser = new Fl_Hold_Browser(WB, 2 * WB + 2 * BH, brw, 6 * BH);
-  _browser->callback(browse_cb, this);
-
-  _paramWin[0] = 2 * WB + brw;
-  _paramWin[1] = 2 * WB + 2 * BH;
-  _paramWin[2] = width - 3 * WB - brw;
-  _paramWin[3] = 7 * BH;
-  _paramWin[4] = (int)(1.25 * BB);
-  _paramWin[5] = BH;
-
-  {
-    Fl_Button *b1 = new Fl_Button(WB, 2 * WB + 8 * BH, brw / 2, BH, "Load");
-    b1->callback(load_projection_cb, this);
-    Fl_Button *b2 = new Fl_Button(WB + brw / 2, 2 * WB + 8 * BH, brw / 2, BH, "Save");
-    b2->callback(save_projection_cb, this);
-  }
-
-  int hard = 8;
-  int uvw = width - 2 * WB - 2 * hard - 3 * WB;
-  int uvh = height - 8 * WB - 15 * BH - 2 * hard;
-
-  _hardEdges[0] = new Fl_Toggle_Button(WB, 3 * WB + 9 * BH + hard, 
-                                       hard, uvh);
-  _hardEdges[1] = new Fl_Toggle_Button(width - 4 * WB - hard, 3 * WB + 9 * BH + hard,
-                                       hard, uvh);
-  _hardEdges[2] = new Fl_Toggle_Button(WB + hard, 3 * WB + 9 * BH, 
-                                       uvw, hard);
-  _hardEdges[3] = new Fl_Toggle_Button(WB + hard, height - 5 * WB - 6 * BH - hard, 
-                                       uvw, hard);
-  for(int i = 0; i < 4; i++)
-    _hardEdges[i]->tooltip("Push to mark edge as `hard'");
-
-  _uvPlot = new uvPlot(WB + hard, 3 * WB + 9 * BH + hard, uvw, uvh);
-  _uvPlot->end();
-
-  _slider = new Fl_Slider(width - 3 * WB, 3 * WB + 9 * BH + hard, 2 * WB, uvh);
-  _slider->minimum(1.);
-  _slider->maximum(0.);
-  _slider->value(1.);
-  _slider->callback(filter_cb, this);
-  _slider->tooltip("Filter selection by distance to projection surface");
-
-  _orientation = new Fl_Toggle_Button(width - 3 * WB, height - 5 * WB - 6 * BH - hard, 
-                                      2 * WB, hard);
-  _orientation->callback(filter_cb, this);
-  _orientation->tooltip("Filter elements using orientation");
-
-  new Fl_Box(WB, height - 4 * WB - 6 * BH, BB, BH, "Patch Type:");
-  Fl_Group *oo = new Fl_Group( WB, height - 4 * WB - 6 * BH, 3 * BB, BH);
-  _pselect[0] = new Fl_Round_Button(2 * WB + BB, height - 4 * WB - 6 * BH,
-                                   BB, BH, "Continuation");
-  _pselect[1] = new Fl_Round_Button(3 * WB + 2 * BB, height - 4 * WB - 
-                                   6 * BH, BB, BH, "Windowing");
-
-  for(int i = 0; i < 2; i++)
-    _pselect[i]->type(FL_RADIO_BUTTON);
-
-  _pselect[0]->value(1);
-
-  oo->end();
-
-  _modes[0] = new Fl_Value_Input(WB, height - 4 * WB - 5 * BH, BB  / 2, BH);
-  _modes[0]->tooltip("Number of Fourier modes along u");
-  _modes[1] = new Fl_Value_Input(WB + BB / 2, height - 4 * WB - 5 * BH, BB  / 2, BH, 
-                                 "Fourier modes");
-  _modes[1]->tooltip("Number of Fourier modes along v");
-  _modes[2] = new Fl_Value_Input(WB, height - 4 * WB - 4 * BH, BB  / 2, BH);
-  _modes[2]->tooltip("Number of Chebyshev modes along u");
-  _modes[3] = new Fl_Value_Input(WB + BB / 2, height - 4 * WB - 4 * BH, BB  / 2, BH, 
-                                 "Chebyshev modes");
-  _modes[3]->tooltip("Number of Chebyshev modes along v");
-  for(int i = 0; i < 4; i++){
-    _modes[i]->value(8);
-    _modes[i]->maximum(128);
-    _modes[i]->minimum(1);
-    _modes[i]->step(1);
-    _modes[i]->align(FL_ALIGN_RIGHT);
-  }    
-
-  {
-    Fl_Button *b = new Fl_Button(width - WB - BB, height - 4 * WB - 5 * BH, 
-                                  BB, 2 * BH, "Generate\nPatch");
-    b->callback(compute_cb, this);
-  }
-
-  {
-    int bb = (int)(0.37 * BB);
-    new Fl_Box(WB, height - 3 * WB - 3 * BH, BB / 2, BH, "Delete:");
-    Fl_Button *b1 = new Fl_Button(WB + BB / 2, height - 3 * WB - 3 * BH, 
-                                  bb, BH, "last");
-    b1->callback(action_cb, (void*)"delete_last");
-    Fl_Button *b2 = new Fl_Button(WB + BB / 2 + bb, height - 3 * WB - 3 * BH,
-                                  bb, BH, "all");
-    b2->callback(action_cb, (void*)"delete_all");
-    Fl_Button *b3 = new Fl_Button(WB + BB / 2 + 2 * bb, height - 3 * WB - 3 * BH,
-                                  bb, BH, "sel.");
-    b3->callback(action_cb, (void*)"delete_select");
-  }
-
-  {
-    int bb = (int)(0.37 * BB);
-    int s = width - WB - BB / 2 - 3 * bb;
-    new Fl_Box(s, height - 3 * WB - 3 * BH, BB / 2, BH, "Save:");
-    Fl_Button *b1 = new Fl_Button(s + BB / 2, height - 3 * WB - 3 * BH,
-                                  bb, BH, "last");
-    b1->callback(action_cb, (void*)"save_last");
-    Fl_Button *b2 = new Fl_Button(s + BB / 2 + bb, height - 3 * WB - 3 * BH,
-                                  bb, BH, "all");
-    b2->callback(action_cb, (void*)"save_all");
-    Fl_Button *b3 = new Fl_Button(s + BB / 2 + 2 * bb, height - 3 * WB - 3 * BH,
-                                  bb, BH, "sel.");
-    b3->callback(action_cb, (void*)"save_select");
-  }
-
-  {
-    Fl_Button *b1 = new Fl_Button(WB, height - 2 * WB - 2 * BH, BB, BH, 
-                                  "Blend");
-    b1->callback(blend_cb, this);
-    
-    Fl_Button *b2 = new Fl_Button(2 * WB + BB, height - 2 * WB - 2 * BH, BB, 
-                                  BH, "Intersect");
-  }
-
-  Fl_Button *b = new Fl_Button(width - WB - BB, height - WB - BH, BB, BH, "Cancel");
-  b->callback(close_cb, _window);
-  
-  _window->end();
-  _window->hotspot(_window);
-  _window->resizable(_uvPlot);
-  _window->size_range(width, (int)(0.85 * height));
-
-  // create
-}
-
-void projectionEditor::load(fourierProjectionFace *face, std::string tag)
-{
-  FM::ProjectionSurface *ps = (FM::ProjectionSurface*)face->getNativePtr();
-  _browser->add(tag.size() ? tag.c_str() : ps->GetName().c_str());
-  projection *p =  new projection(face, _paramWin[0], _paramWin[1], _paramWin[2],
-                                  _paramWin[3], _paramWin[4], _paramWin[5], this);
-  _projections.push_back(p);
-  _window->add(p->group);
-}
-
-void projectionEditor::show()
-{ 
-  _window->show(); 
-  select_cb(0, this); 
-}
-
-int projectionEditor::getSelectionMode() 
-{ 
-  if(_select[0]->value())
-    return ENT_POINT;
-  else
-    return ENT_ALL;
-}
-
-int projectionEditor::getPatchType()
-{
-  if (_pselect[0]->value())
-    return 0;
-  else
-    return 1;
-}
-
-projection *projectionEditor::getCurrentProjection()
-{
-  for(int i = 1; i <= _browser->size(); i++)
-    if(_browser->selected(i)) return _projections[i - 1];
-  return 0;
-}
-
-projection *projectionEditor::getLastProjection()
-{
-  return _projections[_projections.size() - 1];
-}
-
-void browse_cb(Fl_Widget *w, void *data)
-{
-  projectionEditor *e = (projectionEditor*)data;
-
-  std::vector<projection*> &projections(e->getProjections());
-  for(unsigned int i = 0; i < projections.size(); i++){
-    projections[i]->face->setVisibility(false);
-    projections[i]->group->hide();
-  }
-  
-  projection *p = e->getCurrentProjection();
-  if(p){
-    p->face->setVisibility(true);
-    p->group->show();
-  }
-
-  update_cb(0, data);
-}
-
-void project_point(FM::ProjectionSurface *ps, double x, double y, double z,
-                   std::vector<double> &u, std::vector<double> &v, 
-                   std::vector<double> &dist,
-                   std::vector<std::complex<double> > &f)
-{                  
-  double uu, vv, p[3], n[3];
-  ps->OrthoProjectionOnSurface(x, y, z, uu, vv);
-  if(uu >= 0. && uu <= 1. && vv >= 0. && vv <= 1.){
-    ps->F(uu, vv, p[0], p[1], p[2]);
-    ps->GetUnitNormal(uu, vv, n[0], n[1], n[2]);
-    double dx = x - p[0], dy = y - p[1], dz = z - p[2];
-    u.push_back(uu);
-    v.push_back(vv);
-    dist.push_back(sqrt(dx * dx + dy * dy + dz * dz));
-    f.push_back(dx * n[0] + dy * n[1] + dz * n[2]);
-  }
-}
-
-void invert_normal_cb(Fl_Widget *w, void *data)
+static void invert_normal_cb(Fl_Widget *w, void *data)
 {
   projectionEditor *e = (projectionEditor*)data;
   projection *p = e->getCurrentProjection();
@@ -506,7 +195,7 @@ void invert_normal_cb(Fl_Widget *w, void *data)
   }
 }
 
-void translate(void *data, int axis, bool plus)
+static void translate(void *data, int axis, bool plus)
 {
   projectionEditor *e = (projectionEditor*)data;
   projection *p = e->getCurrentProjection();
@@ -533,14 +222,14 @@ void translate(void *data, int axis, bool plus)
   }
 }
 
-void translate_p0_cb(Fl_Widget *w, void *data){ translate(data, 0, true); }
-void translate_p1_cb(Fl_Widget *w, void *data){ translate(data, 1, true); }
-void translate_p2_cb(Fl_Widget *w, void *data){ translate(data, 2, true); }
-void translate_m0_cb(Fl_Widget *w, void *data){ translate(data, 0, false); }
-void translate_m1_cb(Fl_Widget *w, void *data){ translate(data, 1, false); }
-void translate_m2_cb(Fl_Widget *w, void *data){ translate(data, 2, false); }
+static void translate_p0_cb(Fl_Widget *w, void *data){ translate(data, 0, true); }
+static void translate_p1_cb(Fl_Widget *w, void *data){ translate(data, 1, true); }
+static void translate_p2_cb(Fl_Widget *w, void *data){ translate(data, 2, true); }
+static void translate_m0_cb(Fl_Widget *w, void *data){ translate(data, 0, false); }
+static void translate_m1_cb(Fl_Widget *w, void *data){ translate(data, 1, false); }
+static void translate_m2_cb(Fl_Widget *w, void *data){ translate(data, 2, false); }
 
-void set_position_cb(Fl_Widget *w, void *data)
+static void set_position_cb(Fl_Widget *w, void *data)
 {
   projectionEditor *e = (projectionEditor*)data;
   projection *p = e->getCurrentProjection();
@@ -576,91 +265,7 @@ void set_position_cb(Fl_Widget *w, void *data)
   }
 }
 
-void getTangents(const SVector3 n, SVector3 &t1, SVector3 &t2, const double angle)
-{
-  SVector3 ex(0., 0., 0.);
-  if(n[0] == 0.)
-    ex[0] = 1.;
-  else if(n[1] == 0.)
-    ex[1] = 1.;
-  else
-    ex[2] = 1.;
-  SVector3 a = crossprod(n, ex);
-  a.normalize();
-  SVector3 b = crossprod(n, a);
-  b.normalize();
-  double x = n[0], y = n[1], z = n[2];
-  double c = cos(angle * M_PI / 180.), s = sin(angle * M_PI / 180.);
-  double rot[3][3] = 
-    {{x * x * (1-c) + c    , x * y * (1-c) - z * s, x * z * (1-c) + y * s},
-     {y * x * (1-c) + z * s, y * y * (1-c) + c    , y * z * (1-c) - x * s},
-     {x * z * (1-c) - y * s, y * z * (1-c) + x * s, z * z * (1-c) + c    }};
-  for(int i = 0; i < 3; i++){
-    t1[i] = t2[i] = 0.;
-    for(int j = 0; j < 3; j++){
-      t1[i] += rot[i][j] * a[j];
-      t2[i] += rot[i][j] * b[j];
-    }
-  }
-}
-
-void update_cb(Fl_Widget *w, void *data)
-{
-  projectionEditor *e = (projectionEditor*)data;
-
-  // get all parameters from GUI and modify projection surface accordingly
-
-  projection *p = e->getCurrentProjection();
-  if(p){
-    FM::ProjectionSurface *ps = (FM::ProjectionSurface*)p->face->getNativePtr();
-    ps->SetOrigin(p->parameters[0]->value(),
-                  p->parameters[1]->value(),
-                  p->parameters[2]->value());
-    SVector3 n(p->parameters[3]->value(),
-               p->parameters[4]->value(),
-               p->parameters[5]->value());
-    if(!n.normalize()) n[2] = 1.;
-    SVector3 t1, t2;
-    getTangents(n, t1, t2, p->parameters[6]->value());
-    ps->SetE0(n[0], n[1], n[2]);
-    ps->SetE1(t1[0], t1[1], t1[2]);
-    ps->SetE2(t2[0], t2[1], t2[2]);
-    ps->SetScale(p->parameters[7]->value(),
-                 p->parameters[8]->value(),
-                 p->parameters[9]->value());
-    for (int i = 0; i < ps->GetNumParameters(); i++)
-      ps->SetParameter(i, p->parameters[i + 10]->value());
-
-    p->face->buildSTLTriangulation();
-
-    // project selected points and elements and update u,v display
-    std::vector<double> u, v, dist;
-    std::vector<std::complex<double> > f;
-    std::vector<GEntity*> &ent(e->getEntities());
-    for(unsigned int i = 0; i < ent.size(); i++){
-      if(ent[i]->getSelection()){
-        GVertex *gv = dynamic_cast<GVertex*>(ent[i]);
-        if(!gv)
-          Msg::Error("Problem in point selection processing");
-        else
-          project_point(ps, gv->x(), gv->y(), gv->z(), u, v, dist, f);
-      }
-    }
-    std::vector<MElement*> &ele(e->getElements());
-    std::set<MVertex*> verts;
-    for(unsigned int i = 0; i < ele.size(); i++)
-      if(ele[i]->getVisibility() == 2)
-        for(int j = 0; j < ele[i]->getNumVertices(); j++)
-          verts.insert(ele[i]->getVertex(j));
-    for(std::set<MVertex*>::iterator it = verts.begin(); it != verts.end(); it++)
-      project_point(ps, (*it)->x(), (*it)->y(), (*it)->z(), u, v, dist, f);
-    e->uv()->set(u, v, dist, f);
-  }
-
-  Draw();
-}
-
-void select_cb(Fl_Widget *w, void *data)
+static void select_cb(Fl_Widget *w, void *data)
 {
   projectionEditor *e = (projectionEditor*)data;
 
@@ -760,7 +365,7 @@ void select_cb(Fl_Widget *w, void *data)
   Msg::StatusBar(3, false, "");
 }
 
-void filter_cb(Fl_Widget *w, void *data)
+static void filter_cb(Fl_Widget *w, void *data)
 {
   projectionEditor *e = (projectionEditor*)data;
   projection *p = e->getCurrentProjection();
@@ -811,19 +416,19 @@ void filter_cb(Fl_Widget *w, void *data)
   update_cb(0, data);
 }
 
-void close_cb(Fl_Widget *w, void *data)
+static void close_cb(Fl_Widget *w, void *data)
 {
   if(data) ((Fl_Window *) data)->hide();
 }
 
-void hide_cb(Fl_Widget *w, void *data)
+static void proj_hide_cb(Fl_Widget *w, void *data)
 {
   CTX.hide_unselected = !CTX.hide_unselected;
   CTX.mesh.changed = ENT_ALL;
   Draw();
 }
 
-void save_selection_cb(Fl_Widget *w, void *data)
+static void save_selection_cb(Fl_Widget *w, void *data)
 {
   projectionEditor *e = (projectionEditor*)data;
   if(file_chooser(0, 1, "Save Selection", "*.{geo,msh}")){
@@ -863,7 +468,7 @@ void save_selection_cb(Fl_Widget *w, void *data)
   }
 }
 
-void load_projection_cb(Fl_Widget *w, void *data)
+static void load_projection_cb(Fl_Widget *w, void *data)
 {
   projectionEditor *e = (projectionEditor*)data;
   if(file_chooser(0, 0, "Load Projection", "*.pro")){
@@ -904,7 +509,7 @@ void load_projection_cb(Fl_Widget *w, void *data)
   }
 }
 
-void save_projection_cb(Fl_Widget *w, void *data)
+static void save_projection_cb(Fl_Widget *w, void *data)
 {
   projectionEditor *e = (projectionEditor*)data;
   projection *p = e->getCurrentProjection();
@@ -927,7 +532,7 @@ void save_projection_cb(Fl_Widget *w, void *data)
   }
 }
 
-void compute_cb(Fl_Widget *w, void *data)
+static void compute_cb(Fl_Widget *w, void *data)
 {
   GModel* m = GModel::current();
 
@@ -1026,7 +631,7 @@ void compute_cb(Fl_Widget *w, void *data)
   Draw();
 }
 
-void delete_fourier(GFace *gf)
+static void delete_fourier(GFace *gf)
 {
   if(gf->getNativeType() != GEntity::FourierModel) return;
 
@@ -1044,7 +649,7 @@ void delete_fourier(GFace *gf)
   m->remove(gf);
 }
 
-void blend_cb(Fl_Widget *w, void *data)
+static void blend_cb(Fl_Widget *w, void *data)
 {
   GModel *m = GModel::current();
 
@@ -1065,7 +670,7 @@ void blend_cb(Fl_Widget *w, void *data)
   }
 }
 
-void action_cb(Fl_Widget *w, void *data)
+static void action_cb(Fl_Widget *w, void *data)
 {
   std::string what((char*)data);
   std::vector<GFace*> faces;
@@ -1119,6 +724,401 @@ void action_cb(Fl_Widget *w, void *data)
   Draw();
 }
 
+uvPlot::uvPlot(int x, int y, int w, int h, const char *l)
+  : Fl_Window(x, y, w, h, l), _dmin(0.), _dmax(0.)
+{
+  ColorTable_InitParam(2, &_colorTable);
+  ColorTable_Recompute(&_colorTable);
+}
+
+void uvPlot::set(std::vector<double> &u, std::vector<double> &v, 
+                 std::vector<double> &dist, std::vector<std::complex<double> > &f)
+{ 
+  _u = u; 
+  _v = v;
+  _dist = dist;
+  _f = f;
+  if(dist.empty()){
+    _dmin = _dmax = 0.;
+  }
+  else{
+    _dmin = _dmax = dist[0];
+    for(unsigned int i = 1; i < dist.size(); i++){
+      _dmin = std::min(_dmin, dist[i]);
+      _dmax = std::max(_dmax, dist[i]);
+    }
+  }
+  redraw();
+}
+
+void uvPlot::color(double d)
+{
+  int index;
+  if(_dmin == _dmax)
+    index = _colorTable.size / 2;
+  else
+    index = (int)((d - _dmin) * (_colorTable.size - 1) / (_dmax - _dmin));
+  unsigned int color = _colorTable.table[index];
+  int r = CTX.UNPACK_RED(color);
+  int g = CTX.UNPACK_GREEN(color);
+  int b = CTX.UNPACK_BLUE(color);
+  fl_color(r, g, b);
+}
+
+void uvPlot::draw()
+{
+  // draw background
+  fl_color(FL_WHITE);
+  fl_rectf(0, 0, w(), h());
+
+  // draw points in u,v space, colored by their distance to the
+  // projection surface
+  int pw = w();
+  int ph = h() - (2 * GetFontSize() + 5);
+  for(unsigned int i = 0; i < _u.size(); i++){
+    int x = (int)(_u[i] * pw);
+    int y = (int)(_v[i] * ph);
+    color(_dist[i]);
+    fl_rect(x, y, 3, 3);
+  }
+
+  // draw color bar
+  for(int i = 0; i < w(); i++){
+    int index = (int)(i * (_colorTable.size - 1) / w());
+    unsigned int color = _colorTable.table[index];
+    int r = CTX.UNPACK_RED(color);
+    int g = CTX.UNPACK_GREEN(color);
+    int b = CTX.UNPACK_BLUE(color);
+    fl_color(r, g, b);
+    fl_line(i, ph, i, ph + 10);
+  }
+
+  // draw labels
+  fl_color(FL_BLACK);
+  fl_font(FL_HELVETICA, GetFontSize());
+  static char min[256], max[256], pts[256];
+  sprintf(min, "%g", _dmin);
+  sprintf(max, "%g", _dmax);
+  sprintf(pts, "[%d pts]", (int)_u.size());
+  fl_draw(min, 5, h() - 5);
+  fl_draw(pts, pw / 2 - (int)fl_width(pts) / 2, h() - 5);
+  fl_draw(max, pw - (int)fl_width(max) - 5, h() - 5);
+}
+
+projection::projection(fourierProjectionFace *f, int x, int y, int w, int h, 
+                       int bb, int bh, projectionEditor *e) 
+  : face(f)
+{
+  group = new Fl_Scroll(x, y, w, h);
+  SBoundingBox3d bounds = GModel::current()->bounds();
+  FM::ProjectionSurface *ps = (FM::ProjectionSurface*)f->getNativePtr();
+  
+  Fl_Toggle_Button *b = new Fl_Toggle_Button(x, y, bb, bh, "Set position");
+  b->callback(set_position_cb, e);
+  
+  { // origin is stored in parameters[0,1,2]
+    SPoint3 pc = bounds.center();
+    for(int i = 0; i < 3; i++){
+      Fl_Value_Input *v = new Fl_Value_Input(x, y + (1 + i) * bh, bb, bh);
+      parameters.push_back(v);
+      v->maximum(bounds.max()[i] + 10. * CTX.lc);
+      v->minimum(bounds.min()[i] - 10. * CTX.lc);
+      v->step(CTX.lc / 100.);
+      v->value(pc[i]);
+      v->label((i == 0) ? "X" : (i == 1) ? "Y" : "Z");
+    }
+    ps->SetOrigin(pc[0], pc[1], pc[2]);
+    Fl_Repeat_Button *bm[3], *bp[3];
+    for(int i = 0; i < 3; i++){
+      new Fl_Box(x + w - bb / 3 - bb / 6, y + (1 + i) * bh, bb / 8, bh, 
+                 (i == 0) ? "E0" : (i == 1) ? "E1" : "E2");
+      bp[i] = new Fl_Repeat_Button(x + w - bb / 3, y + (1 + i) * bh, 
+                                   bb / 8, bh / 2, "+");
+      bm[i] = new Fl_Repeat_Button(x + w - bb / 3, y + (1 + i) * bh + bh / 2,
+                                   bb / 8, bh / 2, "-");
+    }
+    bp[0]->callback(translate_p0_cb, e);
+    bp[1]->callback(translate_p1_cb, e);
+    bp[2]->callback(translate_p2_cb, e);
+    bm[0]->callback(translate_m0_cb, e);
+    bm[1]->callback(translate_m1_cb, e);
+    bm[2]->callback(translate_m2_cb, e);
+  }
+  { // normal is stored in parameters[3,4,5]
+    Fl_Value_Input *v1 = new Fl_Value_Input(x, y + 4 * bh, bb / 3, bh);
+    parameters.push_back(v1);
+    v1->maximum(1.); v1->minimum(-1.); v1->step(0.01); v1->value(0.);
+    Fl_Value_Input *v2 = new Fl_Value_Input(x + bb / 3, y + 4 * bh, bb / 3, bh);
+    parameters.push_back(v2);
+    v2->maximum(1.); v2->minimum(-1.); v2->step(0.01); v2->value(0.);
+    Fl_Value_Input *v3 = new Fl_Value_Input(x + 2 * bb / 3, y + 4 * bh, bb - 2 * bb / 3, bh);
+    parameters.push_back(v3);
+    v3->maximum(1.); v3->minimum(-1.); v3->step(0.01); v3->value(1.);
+    v3->label("Normal");
+    Fl_Button *b = new Fl_Button(x + w - bb / 3, y + 4 * bh + bh / 4, bb / 8, bh / 2, "-");
+    b->callback(invert_normal_cb, e);
+    b->tooltip("Invert normal");
+  }
+  { // rotation is stored in parameters[6]
+    Fl_Value_Input *v = new Fl_Value_Input(x, y + 5 * bh, bb, bh, "Rotation");
+    v->maximum(-180.);
+    v->minimum(180.);
+    v->step(0.1);
+    v->value(0.);
+    parameters.push_back(v);
+  }
+  { // scale is stored in parameters[7,8,9]
+    for(int i = 0; i < 3; i++){
+      Fl_Value_Input *v = new Fl_Value_Input(x, y + (6 + i) * bh, bb, bh);
+      parameters.push_back(v);
+      v->maximum(CTX.lc * 10.);
+      v->minimum(CTX.lc / 100.);
+      v->step(CTX.lc / 100.);
+      v->value(CTX.lc / 10.);
+      v->label((i == 0) ? "Scale0" : (i == 1) ? "Scale1" : "Scale2");
+    }
+  }
+
+  // other parameters are stored in parameters[10,...]
+  for(int i = 0; i < ps->GetNumParameters(); i++){
+    Fl_Value_Input *v = new Fl_Value_Input(x, y + (9 + i) * bh, bb, bh);
+    v->maximum(10. * CTX.lc);
+    v->minimum(-10. * CTX.lc);
+    v->step(CTX.lc / 100.);
+    v->label(strdup(ps->GetLabel(i).c_str()));
+    v->value(ps->GetParameter(i));
+    parameters.push_back(v);
+  }
+
+  for(unsigned int i = 0; i < parameters.size(); i++){
+    parameters[i]->align(FL_ALIGN_RIGHT);
+    parameters[i]->callback(update_cb, e);
+  }
+
+  group->end();
+  group->hide();
+}
+
+projectionEditor::projectionEditor() 
+{
+  GModel *m = GModel::current();
+
+  // construct FM_Internals 
+  m->readFourier();
+  printf("readerSize = %d\n",m->getFMInternals()->getSize());
+  printf("currentSize = %d\n",m->getFMInternals()->current()->GetNumGroups());
+
+  // construct GUI in terms of standard sizes
+  int _fontsize = GetFontSize();
+  const int width = (int)(3.75 * BB), height = 25 * BH;
+  
+  // create all widgets (we construct this once, we never deallocate!)
+  _window = new dialogWindow(width, height, CTX.non_modal_windows, "Reparameterize");
+  
+  new Fl_Box(WB, WB + BH / 2, BB / 2, BH, "Select:");
+  
+  Fl_Group *o = new Fl_Group(WB, WB, 2 * BB, 3 * BH);
+  _select[0] = new Fl_Round_Button(2 * WB + BB / 2, WB, BB, BH, "Points");
+  _select[1] = new Fl_Round_Button(2 * WB + BB / 2, WB + BH, BB, BH, "Elements");
+  if(m->getNumMeshElements())
+    _select[1]->value(1);
+  else
+    _select[0]->value(1);
+  for(int i = 0; i < 2; i++){
+    _select[i]->callback(select_cb, this);
+    _select[i]->type(FL_RADIO_BUTTON);
+  }
+  o->end();
+
+  {  
+    Fl_Toggle_Button *b1 = new Fl_Toggle_Button
+      (width - WB - 3 * BB / 2, WB, 3 * BB / 2, BH, "Hide unselected");
+    b1->callback(proj_hide_cb);
+    Fl_Button *b2 = new Fl_Button
+      (width - WB - 3 * BB / 2, WB + BH, 3 * BB / 2, BH, "Save selection");
+    b2->callback(save_selection_cb, this);
+  }
+
+  const int brw = (int)(1.3 * BB);
+
+  _browser = new Fl_Hold_Browser(WB, 2 * WB + 2 * BH, brw, 6 * BH);
+  _browser->callback(browse_cb, this);
+
+  _paramWin[0] = 2 * WB + brw;
+  _paramWin[1] = 2 * WB + 2 * BH;
+  _paramWin[2] = width - 3 * WB - brw;
+  _paramWin[3] = 7 * BH;
+  _paramWin[4] = (int)(1.25 * BB);
+  _paramWin[5] = BH;
+
+  {
+    Fl_Button *b1 = new Fl_Button(WB, 2 * WB + 8 * BH, brw / 2, BH, "Load");
+    b1->callback(load_projection_cb, this);
+    Fl_Button *b2 = new Fl_Button(WB + brw / 2, 2 * WB + 8 * BH, brw / 2, BH, "Save");
+    b2->callback(save_projection_cb, this);
+  }
+
+  int hard = 8;
+  int uvw = width - 2 * WB - 2 * hard - 3 * WB;
+  int uvh = height - 8 * WB - 15 * BH - 2 * hard;
+
+  _hardEdges[0] = new Fl_Toggle_Button(WB, 3 * WB + 9 * BH + hard, 
+                                       hard, uvh);
+  _hardEdges[1] = new Fl_Toggle_Button(width - 4 * WB - hard, 3 * WB + 9 * BH + hard,
+                                       hard, uvh);
+  _hardEdges[2] = new Fl_Toggle_Button(WB + hard, 3 * WB + 9 * BH, 
+                                       uvw, hard);
+  _hardEdges[3] = new Fl_Toggle_Button(WB + hard, height - 5 * WB - 6 * BH - hard, 
+                                       uvw, hard);
+  for(int i = 0; i < 4; i++)
+    _hardEdges[i]->tooltip("Push to mark edge as `hard'");
+
+  _uvPlot = new uvPlot(WB + hard, 3 * WB + 9 * BH + hard, uvw, uvh);
+  _uvPlot->end();
+
+  _slider = new Fl_Slider(width - 3 * WB, 3 * WB + 9 * BH + hard, 2 * WB, uvh);
+  _slider->minimum(1.);
+  _slider->maximum(0.);
+  _slider->value(1.);
+  _slider->callback(filter_cb, this);
+  _slider->tooltip("Filter selection by distance to projection surface");
+
+  _orientation = new Fl_Toggle_Button(width - 3 * WB, height - 5 * WB - 6 * BH - hard, 
+                                      2 * WB, hard);
+  _orientation->callback(filter_cb, this);
+  _orientation->tooltip("Filter elements using orientation");
+
+  new Fl_Box(WB, height - 4 * WB - 6 * BH, BB, BH, "Patch Type:");
+  Fl_Group *oo = new Fl_Group( WB, height - 4 * WB - 6 * BH, 3 * BB, BH);
+  _pselect[0] = new Fl_Round_Button(2 * WB + BB, height - 4 * WB - 6 * BH,
+                                   BB, BH, "Continuation");
+  _pselect[1] = new Fl_Round_Button(3 * WB + 2 * BB, height - 4 * WB - 
+                                   6 * BH, BB, BH, "Windowing");
+
+  for(int i = 0; i < 2; i++)
+    _pselect[i]->type(FL_RADIO_BUTTON);
+
+  _pselect[0]->value(1);
+
+  oo->end();
+
+  _modes[0] = new Fl_Value_Input(WB, height - 4 * WB - 5 * BH, BB  / 2, BH);
+  _modes[0]->tooltip("Number of Fourier modes along u");
+  _modes[1] = new Fl_Value_Input(WB + BB / 2, height - 4 * WB - 5 * BH, BB  / 2, BH, 
+                                 "Fourier modes");
+  _modes[1]->tooltip("Number of Fourier modes along v");
+  _modes[2] = new Fl_Value_Input(WB, height - 4 * WB - 4 * BH, BB  / 2, BH);
+  _modes[2]->tooltip("Number of Chebyshev modes along u");
+  _modes[3] = new Fl_Value_Input(WB + BB / 2, height - 4 * WB - 4 * BH, BB  / 2, BH, 
+                                 "Chebyshev modes");
+  _modes[3]->tooltip("Number of Chebyshev modes along v");
+  for(int i = 0; i < 4; i++){
+    _modes[i]->value(8);
+    _modes[i]->maximum(128);
+    _modes[i]->minimum(1);
+    _modes[i]->step(1);
+    _modes[i]->align(FL_ALIGN_RIGHT);
+  }    
+
+  {
+    Fl_Button *b = new Fl_Button(width - WB - BB, height - 4 * WB - 5 * BH, 
+                                  BB, 2 * BH, "Generate\nPatch");
+    b->callback(compute_cb, this);
+  }
+
+  {
+    int bb = (int)(0.37 * BB);
+    new Fl_Box(WB, height - 3 * WB - 3 * BH, BB / 2, BH, "Delete:");
+    Fl_Button *b1 = new Fl_Button(WB + BB / 2, height - 3 * WB - 3 * BH, 
+                                  bb, BH, "last");
+    b1->callback(action_cb, (void*)"delete_last");
+    Fl_Button *b2 = new Fl_Button(WB + BB / 2 + bb, height - 3 * WB - 3 * BH,
+                                  bb, BH, "all");
+    b2->callback(action_cb, (void*)"delete_all");
+    Fl_Button *b3 = new Fl_Button(WB + BB / 2 + 2 * bb, height - 3 * WB - 3 * BH,
+                                  bb, BH, "sel.");
+    b3->callback(action_cb, (void*)"delete_select");
+  }
+
+  {
+    int bb = (int)(0.37 * BB);
+    int s = width - WB - BB / 2 - 3 * bb;
+    new Fl_Box(s, height - 3 * WB - 3 * BH, BB / 2, BH, "Save:");
+    Fl_Button *b1 = new Fl_Button(s + BB / 2, height - 3 * WB - 3 * BH,
+                                  bb, BH, "last");
+    b1->callback(action_cb, (void*)"save_last");
+    Fl_Button *b2 = new Fl_Button(s + BB / 2 + bb, height - 3 * WB - 3 * BH,
+                                  bb, BH, "all");
+    b2->callback(action_cb, (void*)"save_all");
+    Fl_Button *b3 = new Fl_Button(s + BB / 2 + 2 * bb, height - 3 * WB - 3 * BH,
+                                  bb, BH, "sel.");
+    b3->callback(action_cb, (void*)"save_select");
+  }
+
+  {
+    Fl_Button *b1 = new Fl_Button(WB, height - 2 * WB - 2 * BH, BB, BH, 
+                                  "Blend");
+    b1->callback(blend_cb, this);
+    
+    Fl_Button *b2 = new Fl_Button(2 * WB + BB, height - 2 * WB - 2 * BH, BB, 
+                                  BH, "Intersect");
+  }
+
+  Fl_Button *b = new Fl_Button(width - WB - BB, height - WB - BH, BB, BH, "Cancel");
+  b->callback(close_cb, _window);
+  
+  _window->end();
+  _window->hotspot(_window);
+  _window->resizable(_uvPlot);
+  _window->size_range(width, (int)(0.85 * height));
+
+  // create
+}
+
+void projectionEditor::load(fourierProjectionFace *face, std::string tag)
+{
+  FM::ProjectionSurface *ps = (FM::ProjectionSurface*)face->getNativePtr();
+  _browser->add(tag.size() ? tag.c_str() : ps->GetName().c_str());
+  projection *p =  new projection(face, _paramWin[0], _paramWin[1], _paramWin[2],
+                                  _paramWin[3], _paramWin[4], _paramWin[5], this);
+  _projections.push_back(p);
+  _window->add(p->group);
+}
+
+void projectionEditor::show()
+{ 
+  _window->show(); 
+  select_cb(0, this); 
+}
+
+int projectionEditor::getSelectionMode() 
+{ 
+  if(_select[0]->value())
+    return ENT_POINT;
+  else
+    return ENT_ALL;
+}
+
+int projectionEditor::getPatchType()
+{
+  if (_pselect[0]->value())
+    return 0;
+  else
+    return 1;
+}
+
+projection *projectionEditor::getCurrentProjection()
+{
+  for(int i = 1; i <= _browser->size(); i++)
+    if(_browser->selected(i)) return _projections[i - 1];
+  return 0;
+}
+
+projection *projectionEditor::getLastProjection()
+{
+  return _projections[_projections.size() - 1];
+}
+
 void mesh_parameterize_cb(Fl_Widget* w, void* data)
 {
   // display geometry surfaces
diff --git a/Fltk/projectionEditor.h b/Fltk/projectionEditor.h
index 95392bd2c3..8dffb1cc9f 100644
--- a/Fltk/projectionEditor.h
+++ b/Fltk/projectionEditor.h
@@ -81,27 +81,8 @@ class projectionEditor {
   double getThreshold(){ return _slider->value(); }
 };
 
-void select_cb(Fl_Widget *w, void *data);
-void filter_cb(Fl_Widget *w, void *data);
-void browse_cb(Fl_Widget *w, void *data);
-void set_position_cb(Fl_Widget *w, void *data);
-void invert_normal_cb(Fl_Widget *w, void *data);
-void translate_p0_cb(Fl_Widget *w, void *data);
-void translate_p1_cb(Fl_Widget *w, void *data);
-void translate_p2_cb(Fl_Widget *w, void *data);
-void translate_m0_cb(Fl_Widget *w, void *data);
-void translate_m1_cb(Fl_Widget *w, void *data);
-void translate_m2_cb(Fl_Widget *w, void *data);
-void update_cb(Fl_Widget *w, void *data);
-void close_cb(Fl_Widget *w, void *data);
-void hide_cb(Fl_Widget *w, void *data);
-void save_selection_cb(Fl_Widget *w, void *data);
-void load_projection_cb(Fl_Widget *w, void *data);
-void save_projection_cb(Fl_Widget *w, void *data);
-void blend_cb(Fl_Widget *w, void *data);
-void compute_cb(Fl_Widget *w, void *data);
-void action_cb(Fl_Widget *w, void *data);
-
 #endif
 
+void mesh_parameterize_cb(Fl_Widget* w, void* data);
+
 #endif
diff --git a/Fltk/solverWindow.cpp b/Fltk/solverWindow.cpp
index 644de28021..72b16444bb 100644
--- a/Fltk/solverWindow.cpp
+++ b/Fltk/solverWindow.cpp
@@ -3,6 +3,7 @@
 // See the LICENSE.txt file for license information. Please report all
 // bugs and problems to <gmsh@geuz.org>.
 
+#include <string.h>
 #include <FL/Fl_Tabs.H>
 #include <FL/Fl_Box.H>
 #include <FL/Fl_Return_Button.H>
@@ -10,12 +11,180 @@
 #include "GUI.h"
 #include "solverWindow.h"
 #include "shortcutWindow.h"
+#include "optionWindow.h"
+#include "messageWindow.h"
+#include "fileDialogs.h"
+#include "GmshMessage.h"
 #include "Solvers.h"
-#include "Callbacks.h"
+#include "StringUtils.h"
+#include "Options.h"
+#include "OS.h"
 #include "Context.h"
 
 extern Context_T CTX;
 
+void solver_cb(Fl_Widget *w, void *data)
+{
+  static int init = 0, first[MAX_NUM_SOLVERS];
+  int num = (int)(long)data;
+
+  if(!init) {
+    for(int i = 0; i < MAX_NUM_SOLVERS; i++)
+      first[i] = 1;
+    init = 1;
+  }
+
+  if(first[num]) {
+    char file[256];
+    first[num] = 0;
+    strcpy(file, CTX.no_ext_filename);
+    strcat(file, SINFO[num].extension);
+    GUI::instance()->solver[num]->input[0]->value(file);
+  }
+  if(SINFO[num].nboptions) {
+    std::string file = FixWindowsPath
+      (GUI::instance()->solver[num]->input[0]->value());
+    char tmp[256], tmp2[256];
+    sprintf(tmp, "\"%s\"", file.c_str());
+    sprintf(tmp2, SINFO[num].name_command, tmp);
+    sprintf(tmp, "%s %s", SINFO[num].option_command, tmp2);
+    Solver(num, tmp);
+  }
+  GUI::instance()->solver[num]->win->show();
+}
+
+static void solver_file_open_cb(Fl_Widget *w, void *data)
+{
+  char tmp[256], tmp2[256];
+  int num = (int)(long)data;
+  sprintf(tmp, "*%s", SINFO[num].extension);
+
+  // We allow to create the .pro file... Or should we add a "New file"
+  // button?
+  if(file_chooser(0, 0, "Choose", tmp)) {
+    GUI::instance()->solver[num]->input[0]->value(file_chooser_get_name(1).c_str());
+    if(SINFO[num].nboptions) {
+      std::string file = FixWindowsPath(file_chooser_get_name(1).c_str());
+      sprintf(tmp, "\"%s\"", file.c_str());
+      sprintf(tmp2, SINFO[num].name_command, tmp);
+      sprintf(tmp, "%s %s", SINFO[num].option_command, tmp2);
+      Solver(num, tmp);
+    }
+  }
+}
+
+static void solver_file_edit_cb(Fl_Widget *w, void *data)
+{
+  int num = (int)(long)data;
+  std::string prog = FixWindowsPath(CTX.editor);
+  std::string file = FixWindowsPath(GUI::instance()->solver[num]->input[0]->value());
+  char cmd[1024];
+  ReplaceMultiFormat(prog.c_str(), file.c_str(), cmd);
+  SystemCall(cmd);
+}
+
+static void solver_choose_mesh_cb(Fl_Widget *w, void *data)
+{
+  int num = (int)(long)data;
+  if(file_chooser(0, 0, "Choose", "*"))
+    GUI::instance()->solver[num]->input[1]->value(file_chooser_get_name(1).c_str());
+}
+
+static 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;
+}
+
+static void solver_command_cb(Fl_Widget *w, void *data)
+{
+  char tmp[256], mesh[256], arg[512], command[256];
+  int num = ((int *)data)[0];
+  int idx = ((int *)data)[1];
+  int i, usedopts = 0;
+
+  if(SINFO[num].popup_messages)
+    GUI::instance()->messages->show(true);
+
+  if(strlen(GUI::instance()->solver[num]->input[1]->value())) {
+    std::string m = FixWindowsPath(GUI::instance()->solver[num]->input[1]->value());
+    sprintf(tmp, "\"%s\"", m.c_str());
+    sprintf(mesh, SINFO[num].mesh_command, tmp);
+  }
+  else {
+    strcpy(mesh, "");
+  }
+
+  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::Error("Missing options to execute command");
+      return;
+    }
+    sprintf(command, SINFO[num].button_command[idx], SINFO[num].option
+            [usedopts][GUI::instance()->solver[num]->choice[usedopts]->value()]);
+  }
+  else {
+    strcpy(command, SINFO[num].button_command[idx]);
+  }
+
+  std::string c = FixWindowsPath(GUI::instance()->solver[num]->input[0]->value());
+  sprintf(arg, "\"%s\"", c.c_str());
+  sprintf(tmp, SINFO[num].name_command, arg);
+  sprintf(arg, "%s %s %s", tmp, mesh, command);
+  Solver(num, arg);
+}
+
+static void solver_kill_cb(Fl_Widget *w, void *data)
+{
+  int num = (int)(long)data;
+  if(SINFO[num].pid > 0) {
+    if(KillProcess(SINFO[num].pid))
+      Msg::Info("Killed %s pid %d", SINFO[num].name, SINFO[num].pid);
+  }
+  SINFO[num].pid = -1;
+}
+
+static void solver_ok_cb(Fl_Widget *w, void *data)
+{
+  int retry = 0, num = (int)(long)data;
+  opt_solver_popup_messages
+    (num, GMSH_SET, GUI::instance()->solver[num]->butt[0]->value());
+  opt_solver_merge_views
+    (num, GMSH_SET, GUI::instance()->solver[num]->butt[1]->value());
+  opt_solver_client_server
+    (num, GMSH_SET, GUI::instance()->solver[num]->butt[2]->value());
+  if(strcmp(opt_solver_executable(num, GMSH_GET, NULL), 
+            GUI::instance()->solver[num]->input[2]->value()))
+    retry = 1;
+  opt_solver_executable
+    (num, GMSH_SET, GUI::instance()->solver[num]->input[2]->value());
+  if(retry)
+    solver_cb(NULL, data);
+}
+
+static void solver_choose_executable_cb(Fl_Widget *w, void *data)
+{
+  int num = (int)(long)data;
+  if(file_chooser(0, 0, "Choose",
+#if defined(WIN32)
+                  "*.exe"
+#else
+                  "*"
+#endif
+                  )){
+    GUI::instance()->solver[num]->input[2]->value(file_chooser_get_name(1).c_str());
+    solver_ok_cb(w, data);
+  }
+}
+
 solverWindow::solverWindow(int solverIndex, int fontsize)
   : _fontsize(fontsize)
 {
@@ -125,7 +294,7 @@ solverWindow::solverWindow(int solverIndex, int fontsize)
     b1->callback(solver_kill_cb, (void *)solverIndex);
     Fl_Button *b2 = new Fl_Button
       (width - BB - WB, height - BH - WB, BB, BH, "Cancel");
-    b2->callback(cancel_cb, (void*)win);
+    b2->callback(hide_cb, (void*)win);
   }
 
   win->position(CTX.solver_position[0], CTX.solver_position[1]);
diff --git a/Fltk/solverWindow.h b/Fltk/solverWindow.h
index ebc5fbfd9d..940a0fbacc 100644
--- a/Fltk/solverWindow.h
+++ b/Fltk/solverWindow.h
@@ -25,4 +25,6 @@ class solverWindow{
   solverWindow(int solverIndex, int fontsize);
 };
 
+void solver_cb(Fl_Widget *w, void *data);
+
 #endif
diff --git a/Fltk/statisticsWindow.cpp b/Fltk/statisticsWindow.cpp
index 074af9e76d..c3385d91f9 100644
--- a/Fltk/statisticsWindow.cpp
+++ b/Fltk/statisticsWindow.cpp
@@ -7,16 +7,75 @@
 #include <FL/Fl_Box.H>
 #include <FL/Fl_Return_Button.H>
 #include "GUI.h"
+#include "Draw.h"
 #include "statisticsWindow.h"
 #include "shortcutWindow.h"
 #include "GModel.h"
+#include "MElement.h"
 #include "PView.h"
-#include "Callbacks.h"
 #include "Generator.h"
 #include "Context.h"
 
 extern Context_T CTX;
 
+void statistics_cb(Fl_Widget *w, void *data)
+{
+  GUI::instance()->stats->show();
+}
+
+static void statistics_update_cb(Fl_Widget *w, void *data)
+{
+  GUI::instance()->stats->compute(true);
+}
+
+static void statistics_histogram_cb(Fl_Widget *w, void *data)
+{
+  std::string name((const char*)data);
+
+  std::vector<double> x, y;
+
+  if(name == "Gamma2D"){
+    for(int i = 0; i < 100; i++) y.push_back(GUI::instance()->stats->quality[0][i]);
+    new PView("Gamma", "# Elements", x, y);
+  }
+  else if(name == "Eta2D"){
+    for(int i = 0; i < 100; i++) y.push_back(GUI::instance()->stats->quality[1][i]);
+    new PView("Eta", "# Elements", x, y);
+  }
+  else if(name == "Rho2D"){
+    for(int i = 0; i < 100; i++) y.push_back(GUI::instance()->stats->quality[2][i]);
+    new PView("Rho", "# Elements", x, y);
+  }
+  else if(name == "Disto2D"){
+    for(int i = 0; i < 100; i++) y.push_back(GUI::instance()->stats->quality[3][i]);
+    new PView("Disto", "# Elements", x, y);
+  }
+  else{
+    std::vector<GEntity*> entities;
+    GModel::current()->getEntities(entities);
+    std::map<int, std::vector<double> > d;
+    for(unsigned int i = 0; i < entities.size(); i++){
+      if(entities[i]->dim() < 2) continue;
+      for(unsigned int j = 0; j < entities[i]->getNumMeshElements(); j++){
+        MElement *e = entities[i]->getMeshElement(j);
+        if(name == "Gamma3D")
+          d[e->getNum()].push_back(e->gammaShapeMeasure());
+        else if(name == "Eta3D")
+          d[e->getNum()].push_back(e->etaShapeMeasure());
+        else if(name == "Rho3D")
+          d[e->getNum()].push_back(e->rhoShapeMeasure());
+        else
+          d[e->getNum()].push_back(e->distoShapeMeasure());
+      }
+    }
+    name.resize(name.size() - 2);
+    new PView(name, "ElementData", GModel::current(), d);
+  }
+
+  GUI::instance()->updateViews();
+  Draw();
+}
+
 statisticsWindow::statisticsWindow(int fontsize)
   : _fontsize(fontsize)
 {
@@ -114,7 +173,7 @@ statisticsWindow::statisticsWindow(int fontsize)
   }
   {
     Fl_Button *o = new Fl_Button(width - BB - WB, height - BH - WB, BB, BH, "Cancel");
-    o->callback(cancel_cb, (void *)win);
+    o->callback(hide_cb, (void *)win);
   }
   
   win->position(CTX.stat_position[0], CTX.stat_position[1]);
diff --git a/Fltk/statisticsWindow.h b/Fltk/statisticsWindow.h
index 304a38783c..680623bd7b 100644
--- a/Fltk/statisticsWindow.h
+++ b/Fltk/statisticsWindow.h
@@ -26,4 +26,6 @@ class statisticsWindow{
   void show();
 };
 
+void statistics_cb(Fl_Widget *w, void *data);
+
 #endif
diff --git a/Fltk/visibilityWindow.cpp b/Fltk/visibilityWindow.cpp
index 9733b5e7f5..74e52858c6 100644
--- a/Fltk/visibilityWindow.cpp
+++ b/Fltk/visibilityWindow.cpp
@@ -7,13 +7,400 @@
 #include <FL/Fl_Box.H>
 #include <FL/Fl_Return_Button.H>
 #include "GUI.h"
+#include "Draw.h"
 #include "visibilityWindow.h"
 #include "shortcutWindow.h"
-#include "Callbacks.h"
+#include "contextWindow.h"
+#include "GmshDefines.h"
+#include "GmshMessage.h"
+#include "GModel.h"'
+#include "MElement.h"
+#include "Visibility.h"
+#include "SelectBuffer.h"
+#include "GeoStringInterface.h"
+#include "Options.h"
 #include "Context.h"
 
 extern Context_T CTX;
 
+// Visibility Menu
+
+void visibility_cb(Fl_Widget *w, void *data)
+{
+  // get the visibility info from the model, and update the browser
+  // accordingly
+  const char *str = (const char*)data;
+  if(str && !strcmp(str, "redraw_only"))
+    GUI::instance()->visibility->show(true);
+  else
+    GUI::instance()->visibility->show(false);
+
+  GUI::instance()->visibility->browser->clear();
+
+  int type = GUI::instance()->visibility->type->value();
+
+  VisibilityManager::instance()->update(type);
+  for(int i = 0; i < VisibilityManager::instance()->getNumEntities(); i++){
+    GUI::instance()->visibility->browser->add
+      (VisibilityManager::instance()->getBrowserLine(i).c_str());
+    if(VisibilityManager::instance()->getVisibility(i))
+      GUI::instance()->visibility->browser->select(i + 1);
+  }
+  
+  // activate the delete button for physicals only!
+  if(type == 1)
+    GUI::instance()->visibility->push[0]->activate();
+  else
+    GUI::instance()->visibility->push[0]->deactivate();
+
+  // disable numeric and interactive selection for partitions
+  if(type == 2){
+    GUI::instance()->visibility->group[1]->deactivate();
+    GUI::instance()->visibility->group[2]->deactivate();
+  }
+  else{
+    GUI::instance()->visibility->group[1]->activate();
+    GUI::instance()->visibility->group[2]->activate();
+  }
+}
+
+static void visibility_ok_cb(Fl_Widget *w, void *data)
+{
+  // if the browser is not empty, get the selections made in the
+  // browser and apply them into the model
+  if(VisibilityManager::instance()->getNumEntities()){
+    CTX.mesh.changed |= (ENT_LINE | ENT_SURFACE | ENT_VOLUME);
+    bool recursive = GUI::instance()->visibility->butt[0]->value() ? true : false;
+    int type = GUI::instance()->visibility->type->value();
+    VisibilityManager::instance()->setAllInvisible(type);
+    for(int i = 0; i < VisibilityManager::instance()->getNumEntities(); i++)
+      if(GUI::instance()->visibility->browser->selected(i + 1))
+        VisibilityManager::instance()->setVisibility(i, 1, recursive);
+    // then refresh the browser to account for recursive selections
+    for(int i = 0; i < VisibilityManager::instance()->getNumEntities(); i++)
+      if(VisibilityManager::instance()->getVisibility(i))
+        GUI::instance()->visibility->browser->select(i + 1);
+    Draw();
+  }
+}
+
+static void visibility_save_cb(Fl_Widget *w, void *data)
+{
+  std::string str = VisibilityManager::instance()->getStringForGEO();
+  add_infile(str.c_str(), CTX.filename);
+}
+
+static void visibility_delete_cb(Fl_Widget *w, void *data)
+{
+  int type = GUI::instance()->visibility->type->value();
+  if(type != 1) return; // delete only available for physicals
+
+  bool all = true;
+  for(int i = 0; i < VisibilityManager::instance()->getNumEntities(); i++){
+    if(!GUI::instance()->visibility->browser->selected(i + 1)){
+      all = false;
+      break;
+    }
+  }
+  if(all){
+    GModel::current()->deletePhysicalGroups();
+  }
+  else{
+    for(int i = 0; i < VisibilityManager::instance()->getNumEntities(); i++){
+      if(GUI::instance()->visibility->browser->selected(i + 1)){
+        Vis *v = VisibilityManager::instance()->getEntity(i);
+        GModel::current()->deletePhysicalGroup(v->getDim(), v->getTag());
+      }
+    }
+  }
+
+  visibility_cb(NULL, (void*)"redraw_only");
+}
+
+static void visibility_sort_cb(Fl_Widget *w, void *data)
+{
+  const char *str = (const char*)data;
+  int val;
+  if(!strcmp(str, "type"))
+    val = 1;
+  else if(!strcmp(str, "number"))
+    val = 2;
+  else if(!strcmp(str, "name"))
+    val = 3;
+  else if(!strcmp(str, "-"))
+    val = -1;
+  else if(!strcmp(str, "+"))
+    val = -2;
+  else
+    val = 0;
+
+  if(val == 0) { // select or deselect everything
+    int selectall = 0;
+    for(int i = 0; i < GUI::instance()->visibility->browser->size(); i++)
+      if(!GUI::instance()->visibility->browser->selected(i + 1)) {
+        selectall = 1;
+        break;
+      }
+    if(selectall)
+      for(int i = 0; i < GUI::instance()->visibility->browser->size(); i++)
+        GUI::instance()->visibility->browser->select(i + 1);
+    else
+      GUI::instance()->visibility->browser->deselect();
+  }
+  else if(val == -1){ // invert the selection
+    int *state = new int[GUI::instance()->visibility->browser->size()];
+    for(int i = 0; i < GUI::instance()->visibility->browser->size(); i++)
+      state[i] = GUI::instance()->visibility->browser->selected(i + 1);
+    GUI::instance()->visibility->browser->deselect();
+    for(int i = 0; i < GUI::instance()->visibility->browser->size(); i++)
+      if(!state[i]) GUI::instance()->visibility->browser->select(i + 1);
+    delete [] state;
+  }
+  else if(val == -2){ // create new parameter name for selection
+    for(int i = 0; i < GUI::instance()->visibility->browser->size(); i++){
+      if(GUI::instance()->visibility->browser->selected(i + 1)){
+        static char tmpstr[256];
+        sprintf(tmpstr, "%d", VisibilityManager::instance()->getTag(i));
+        GUI::instance()->geoContext->input[1]->value(tmpstr);
+        break;
+      }
+    }
+    GUI::instance()->geoContext->input[0]->value("NewName");
+    GUI::instance()->geoContext->show(0);
+  }
+  else { // set new sorting mode
+    VisibilityManager::instance()->setSortMode(val);
+    visibility_cb(NULL, (void*)"redraw_only");
+  }
+}
+
+static void visibility_number_cb(Fl_Widget *w, void *data)
+{
+  CTX.mesh.changed |= (ENT_LINE | ENT_SURFACE | ENT_VOLUME);
+
+  // type = 0 for elementary, 1 for physical and 2 for partitions
+  int type = GUI::instance()->visibility->type->value();
+  if(type != 0 && type != 1) return;
+
+  // what = 0 for nodes, 1 for elements, 2 for points, 3 for lines, 4
+  // for surfaces, 5 for volumes, 6 for physical points, 7 for
+  // physical lines, 8 for physical surfaces and 9 for physical
+  // volumes
+  int what = (int)(long)data;
+  char val;
+  if(what >= 100){ // show
+    val = 1;
+    what -= 100;
+  }
+  else{ // hide
+    val = 0;
+  }
+  const char *str = GUI::instance()->visibility->input[what]->value();
+  if(type == 1 && what >= 2 && what <= 5) what += 4;
+
+  int num = (!strcmp(str, "all") || !strcmp(str, "*")) ? -1 : atoi(str);
+  bool recursive = GUI::instance()->visibility->butt[0]->value() ? true : false;
+  
+  VisibilityManager::instance()->setVisibilityByNumber(what, num, val, recursive);
+
+  int pos = GUI::instance()->visibility->browser->position();
+  visibility_cb(NULL, (void*)"redraw_only");
+  GUI::instance()->visibility->browser->position(pos);
+  Draw();
+}
+
+static void _apply_visibility(char mode,
+                              std::vector<GVertex*> &vertices,
+                              std::vector<GEdge*> &edges,
+                              std::vector<GFace*> &faces,
+                              std::vector<GRegion*> &regions,
+                              std::vector<MElement*> &elements)
+{
+  // type = 0 for elementary, 1 for physical and 2 for partitions
+  int type = GUI::instance()->visibility->type->value();
+  if(type != 0 && type != 1) return;
+  bool recursive = GUI::instance()->visibility->butt[0]->value() ? true : false;
+
+  if(mode == 1){ // when showing a single entity, first hide everything
+    if(CTX.pick_elements)
+      VisibilityManager::instance()->setVisibilityByNumber(1, -1, 0, false);
+    else
+      for(int i = 2; i <= 5; i++)
+        VisibilityManager::instance()->setVisibilityByNumber(i, -1, 0, false);
+  }
+
+  if(mode == 2) mode = 1;
+  
+  if(CTX.pick_elements){
+    for(unsigned int i = 0; i < elements.size(); i++)
+      elements[i]->setVisibility(mode);
+  }
+  else{
+    for(unsigned int i = 0; i < vertices.size(); i++){
+      if(type == 0)
+        vertices[i]->setVisibility(mode, recursive);
+      else
+        for(unsigned int j = 0; j < vertices[i]->physicals.size(); j++)
+          VisibilityManager::instance()->setVisibilityByNumber
+            (6, vertices[i]->physicals[j], mode, recursive);
+    }
+    for(unsigned int i = 0; i < edges.size(); i++){
+      if(type == 0)
+        edges[i]->setVisibility(mode, recursive);
+      else
+        for(unsigned int j = 0; j < edges[i]->physicals.size(); j++)
+          VisibilityManager::instance()->setVisibilityByNumber
+            (7, edges[i]->physicals[j], mode, recursive);
+    }
+    for(unsigned int i = 0; i < faces.size(); i++){
+      if(type == 0)
+        faces[i]->setVisibility(mode, recursive);
+      else
+        for(unsigned int j = 0; j < faces[i]->physicals.size(); j++)
+          VisibilityManager::instance()->setVisibilityByNumber
+            (8, faces[i]->physicals[j], mode, recursive);
+    }
+    for(unsigned int i = 0; i < regions.size(); i++){
+      if(type == 0)
+        regions[i]->setVisibility(mode, recursive);
+      else
+        for(unsigned int j = 0; j < regions[i]->physicals.size(); j++)
+          VisibilityManager::instance()->setVisibilityByNumber
+            (9, regions[i]->physicals[j], mode, recursive);
+    }
+  }
+  int pos = GUI::instance()->visibility->browser->position();
+  visibility_cb(NULL, (void*)"redraw_only");
+  GUI::instance()->visibility->browser->position(pos);
+}
+
+static void visibility_interactive_cb(Fl_Widget *w, void *data)
+{
+  const char *str = (const char*)data;
+  const char *help;
+  int what;
+  char mode;
+
+  if(!strcmp(str, "hide_elements")){
+    CTX.pick_elements = 1;
+    what = ENT_ALL;
+    mode = 0;
+    help = "elements to hide";
+  }
+  else if(!strcmp(str, "hide_points")){
+    CTX.pick_elements = 0;
+    what = ENT_POINT;
+    mode = 0;
+    help = "points to hide";
+    opt_geometry_points(0, GMSH_SET | GMSH_GUI, 1);
+  }
+  else if(!strcmp(str, "hide_lines")){
+    CTX.pick_elements = 0;
+    what = ENT_LINE;
+    mode = 0;
+    help = "lines to hide";
+    opt_geometry_lines(0, GMSH_SET | GMSH_GUI, 1);
+  }
+  else if(!strcmp(str, "hide_surfaces")){
+    CTX.pick_elements = 0;
+    what = ENT_SURFACE;
+    mode = 0;
+    help = "surfaces to hide";
+    if(GModel::current()->getMeshStatus() < 2)
+      opt_geometry_surfaces(0, GMSH_SET | GMSH_GUI, 1);
+  }
+  else if(!strcmp(str, "hide_volumes")){
+    CTX.pick_elements = 0;
+    what = ENT_VOLUME;
+    mode = 0;
+    help = "volumes to hide";
+    if(GModel::current()->getMeshStatus() < 3)
+      opt_geometry_volumes(0, GMSH_SET | GMSH_GUI, 1);
+  }
+  else if(!strcmp(str, "show_elements")){
+    CTX.pick_elements = 1;
+    what = ENT_ALL;
+    mode = 1;
+    help = "elements to show";
+  }
+  else if(!strcmp(str, "show_points")){
+    CTX.pick_elements = 0;
+    what = ENT_POINT;
+    mode = 1;
+    help = "points to show";
+    opt_geometry_points(0, GMSH_SET | GMSH_GUI, 1);
+  }
+  else if(!strcmp(str, "show_lines")){
+    CTX.pick_elements = 0;
+    what = ENT_LINE;
+    mode = 1;
+    help = "lines to show";
+    opt_geometry_lines(0, GMSH_SET | GMSH_GUI, 1);
+  }
+  else if(!strcmp(str, "show_surfaces")){
+    CTX.pick_elements = 0;
+    what = ENT_SURFACE;
+    mode = 1;
+    help = "surfaces to show";
+    if(GModel::current()->getMeshStatus() < 2)
+      opt_geometry_surfaces(0, GMSH_SET | GMSH_GUI, 1);
+  }
+  else if(!strcmp(str, "show_volumes")){
+    CTX.pick_elements = 0;
+    what = ENT_VOLUME;
+    mode = 1;
+    help = "volumes to show";
+    if(GModel::current()->getMeshStatus() < 3)
+      opt_geometry_volumes(0, GMSH_SET | GMSH_GUI, 1);
+  }
+  else if(!strcmp(str, "show_all")){
+    for(int i = 1; i <= 5; i++) // elements, points, lines, surfaces, volumes
+      VisibilityManager::instance()->setVisibilityByNumber(i, -1, 1, false);
+    CTX.mesh.changed = ENT_ALL;
+    Draw();  
+    return;
+  }
+  else
+    return;
+
+  std::vector<GVertex*> vertices, vertices_old;
+  std::vector<GEdge*> edges, edges_old;
+  std::vector<GFace*> faces, faces_old;
+  std::vector<GRegion*> regions, regions_old;
+  std::vector<MElement*> elements, elements_old;
+
+  while(1) {
+    if(what == ENT_ALL) 
+      CTX.mesh.changed = ENT_ALL;
+    Draw();
+    Msg::StatusBar(3, false, "Select %s\n[Press %s'q' to abort]", 
+                   help, mode ? "" : "'u' to undo or ");
+
+    char ib = SelectEntity(what, vertices, edges, faces, regions, elements);
+    if(ib == 'l') {
+      _apply_visibility(mode, vertices, edges, faces, regions, elements);
+      // store for possible undo later
+      vertices_old = vertices;
+      edges_old = edges;
+      faces_old = faces;
+      regions_old = regions;
+      elements_old = elements;
+    }
+    if(ib == 'u' && !mode){ // undo only in hide mode
+      _apply_visibility(2, vertices_old, edges_old, faces_old, 
+                        regions_old, elements_old);
+    }
+    if(ib == 'q'){
+      break;
+    }
+  }
+
+  CTX.mesh.changed = ENT_ALL;
+  CTX.pick_elements = 0;
+  Draw();  
+  Msg::StatusBar(3, false, "");
+}
+
 // derive our own browser, that reacts differently to the Enter key
 class visBrowser : public Fl_Browser{
   int handle(int event)
@@ -222,7 +609,7 @@ visibilityWindow::visibilityWindow(int fontsize)
 
     Fl_Button *o2 = new Fl_Button
       (width - BB - WB, height - BH - WB, BB, BH, "Cancel");
-    o2->callback(cancel_cb, (void *)win);
+    o2->callback(hide_cb, (void *)win);
   }
 
   win->position(CTX.vis_position[0], CTX.vis_position[1]);
diff --git a/Fltk/visibilityWindow.h b/Fltk/visibilityWindow.h
index cc78e570a0..d9af15ca22 100644
--- a/Fltk/visibilityWindow.h
+++ b/Fltk/visibilityWindow.h
@@ -30,4 +30,6 @@ class visibilityWindow{
   void show(bool redrawOnly);
 };
 
+void visibility_cb(Fl_Widget *w, void *data);
+
 #endif
diff --git a/doc/texinfo/gmsh.texi b/doc/texinfo/gmsh.texi
index 46479213dc..a05a9ae89e 100644
--- a/doc/texinfo/gmsh.texi
+++ b/doc/texinfo/gmsh.texi
@@ -3994,11 +3994,7 @@ default value for this option;
 create the handling routine @code{opt_XXX} in @file{Common/Options.cpp} (and
 add the prototype in @file{Common/Options.h});
 @item
-optional: create the associated widget in @file{Fltk/GUI.cpp};
-@item
-optional: if no special callback is to be associated with the widget, add the
-handling routine @code{opt_XXX} to the OK callback for the corresponding
-option panel (in @file{Fltk/Callbacks.cpp}).
+optional: create the associated widget in @file{Fltk/optionWindow.cpp};
 @end enumerate
 
 @c todo:
-- 
GitLab