diff --git a/Common/Gmsh.cpp b/Common/Gmsh.cpp
index 2a45410d01699cc15bae70382d210c7b000ba0c4..5cb965da04d09523364fbfd896bff229c4c23b76 100644
--- a/Common/Gmsh.cpp
+++ b/Common/Gmsh.cpp
@@ -63,16 +63,32 @@ int GmshSetMessageHandler(GmshMessage *callback)
 
 int GmshSetOption(std::string category, std::string name, std::string value, int index)
 {
-  if(StringOption(GMSH_SET, category.c_str(), index, name.c_str(), value))
-    return 1;
-  return 0;
+  return StringOption(GMSH_SET, category.c_str(), index, name.c_str(), value);
 }
 
 int GmshSetOption(std::string category, std::string name, double value, int index)
 {
-  if(NumberOption(GMSH_SET, category.c_str(), index, name.c_str(), value))
-    return 1;
-  return 0;
+  return NumberOption(GMSH_SET, category.c_str(), index, name.c_str(), value);
+}
+
+int GmshSetOption(std::string category, std::string name, unsigned int value, int index)
+{
+  return ColorOption(GMSH_SET, category.c_str(), index, name.c_str(), value);
+}
+
+int GmshGetOption(std::string category, std::string name, std::string &value, int index)
+{
+  return StringOption(GMSH_GET, category.c_str(), index, name.c_str(), value);
+}
+
+int GmshGetOption(std::string category, std::string name, double &value, int index)
+{
+  return NumberOption(GMSH_GET, category.c_str(), index, name.c_str(), value);
+}
+
+int GmshGetOption(std::string category, std::string name, unsigned int &value, int index)
+{
+  return ColorOption(GMSH_GET, category.c_str(), index, name.c_str(), value);
 }
 
 int GmshMergeFile(std::string fileName)
diff --git a/Common/Gmsh.h b/Common/Gmsh.h
index 3d943950acdc0b4bc0c5c9312ed39de39ce061df..9578b3aeb23a5e2bfe37542141ab5e4bc3fcb2d1 100644
--- a/Common/Gmsh.h
+++ b/Common/Gmsh.h
@@ -13,6 +13,10 @@ int GmshInitialize(int argc=0, char **argv=0);
 int GmshSetMessageHandler(GmshMessage *callback);
 int GmshSetOption(std::string category, std::string name, std::string value, int index=0);
 int GmshSetOption(std::string category, std::string name, double value, int index=0);
+int GmshSetOption(std::string category, std::string name, unsigned int value, int index=0);
+int GmshGetOption(std::string category, std::string name, std::string &value, int index=0);
+int GmshGetOption(std::string category, std::string name, double &value, int index=0);
+int GmshGetOption(std::string category, std::string name, unsigned int &value, int index=0);
 int GmshMergeFile(std::string fileName);
 int GmshFinalize();
 int GmshBatch();
diff --git a/Fltk/openglWindow.cpp b/Fltk/openglWindow.cpp
index 7524c183dd73a9ee9eea2c41d3054037a7fd5b7e..d6920fb0ce844a497d0456e2fd6f52fb8d114e70 100644
--- a/Fltk/openglWindow.cpp
+++ b/Fltk/openglWindow.cpp
@@ -19,34 +19,6 @@
 #include "VertexArray.h"
 #include "Context.h"
 
-void mousePosition::set(drawContext *ctx)
-{
-  for(int i = 0; i < 3; i++){
-    s[i] = ctx->s[i];
-    t[i] = ctx->t[i];
-  }
-
-  win[0] = (double)Fl::event_x();
-  win[1] = (double)Fl::event_y();
-  win[2] = 0.;
-
-  wnr[0] = 
-    (ctx->vxmin + win[0] / (double)ctx->viewport[2] * (ctx->vxmax - ctx->vxmin)) 
-    / ctx->s[0] - ctx->t[0] + ctx->t_init[0] / ctx->s[0];
-  wnr[1] = 
-    (ctx->vymax - win[1] / (double)ctx->viewport[3] * (ctx->vymax - ctx->vymin))
-    / ctx->s[1] - ctx->t[1] + ctx->t_init[1] / ctx->s[1];
-  wnr[2] = 0.;
-}
-
-void mousePosition::recenter(drawContext *ctx)
-{
-  // compute the equivalent translation to apply *after* the scaling
-  // so that the scaling is done around the point which was clicked:
-  ctx->t[0] = t[0] * (s[0] / ctx->s[0]) - wnr[0] * (1. - (s[0] / ctx->s[0]));
-  ctx->t[1] = t[1] * (s[1] / ctx->s[1]) - wnr[1] * (1. - (s[1] / ctx->s[1]));
-}
-  
 static void lassoZoom(drawContext *ctx, mousePosition &click1, mousePosition &click2)
 {
   if(click1.win[0] == click2.win[0] || click1.win[1] == click2.win[1])
@@ -235,12 +207,6 @@ void openglWindow::_setLastHandled(openglWindow* w)
 
 int openglWindow::handle(int event)
 {
-  // The event model in FLTK is pretty different from other toolkits:
-  // the events are passed to the widget handle of the widget that has
-  // the focus. If this handle returns 1, then the event is considered
-  // as treated, and is suppressed. If the handle returns 0, the event
-  // is passed to the parent.
-
   switch (event) {
 
   case FL_FOCUS: // accept the focus when I'm asked if I want it
@@ -257,7 +223,7 @@ int openglWindow::handle(int event)
   case FL_PUSH:
     _setLastHandled(this);
     take_focus(); // force keyboard focus when we click in the window
-    _curr.set(_ctx);
+    _curr.set(_ctx, Fl::event_x(), Fl::event_y());
     if(Fl::event_button() == 1 && 
        !Fl::event_state(FL_SHIFT) && !Fl::event_state(FL_ALT)) {
       if(!lassoMode && Fl::event_state(FL_CTRL)) {
@@ -333,20 +299,20 @@ int openglWindow::handle(int event)
         lassoMode = false;
       }
     }
-    _click.set(_ctx);
-    _prev.set(_ctx);
+    _click.set(_ctx, Fl::event_x(), Fl::event_y());
+    _prev.set(_ctx, Fl::event_x(), Fl::event_y());
     GUI::instance()->manip->update();
     return 1;
 
   case FL_RELEASE:
-    _curr.set(_ctx);
+    _curr.set(_ctx, Fl::event_x(), Fl::event_y());
     CTX::instance()->drawRotationCenter = 0;
     if(!lassoMode) {
       CTX::instance()->mesh.draw = 1;
       CTX::instance()->post.draw = 1;
       redraw();
     }
-    _prev.set(_ctx);
+    _prev.set(_ctx, Fl::event_x(), Fl::event_y());
     return 1;
 
   case FL_MOUSEWHEEL:
@@ -363,7 +329,7 @@ int openglWindow::handle(int event)
     return 1;
 
   case FL_DRAG:
-    _curr.set(_ctx);
+    _curr.set(_ctx, Fl::event_x(), Fl::event_y());
     {
       double dx = _curr.win[0] - _prev.win[0];
       double dy = _curr.win[1] - _prev.win[1];
@@ -416,12 +382,12 @@ int openglWindow::handle(int event)
         redraw();
       }
     }
-    _prev.set(_ctx);
+    _prev.set(_ctx, Fl::event_x(), Fl::event_y());
     GUI::instance()->manip->update();
     return 1;
 
   case FL_MOVE:
-    _curr.set(_ctx);
+    _curr.set(_ctx, Fl::event_x(), Fl::event_y());
     if(lassoMode){
       redraw();
     }
@@ -483,7 +449,7 @@ int openglWindow::handle(int event)
                        me ? me->getInfoString().c_str() : "");
       }
     }
-    _prev.set(_ctx);
+    _prev.set(_ctx, Fl::event_x(), Fl::event_y());
     return 1;
 
   default:
diff --git a/Fltk/openglWindow.h b/Fltk/openglWindow.h
index 63da66ae5ad8ae6746a735b386b1d7a1b314c633..d9d02ee9ed57eed51491528e893fce99c6186a27 100644
--- a/Fltk/openglWindow.h
+++ b/Fltk/openglWindow.h
@@ -18,30 +18,6 @@ class GFace;
 class GRegion;
 class MElement;
 
-class mousePosition {
- public:
-  double win[3]; // window coordinates
-  double wnr[3]; // world coordinates BEFORE rotation
-  double s[3]; // scaling state when the event was recorded
-  double t[3]; // translation state when the event was recorded
-  mousePosition()
-  {
-    for(int i = 0; i < 3; i++)
-      win[i] = wnr[i] = s[i] = t[i] = 0.;
-  }
-  mousePosition(const mousePosition &instance)
-  {
-    for(int i = 0; i < 3; i++){
-      win[i] = instance.win[i];
-      wnr[i] = instance.wnr[i];
-      s[i] = instance.s[i];
-      t[i] = instance.t[i];
-    }
-  }
-  void set(drawContext *ctx);
-  void recenter(drawContext *ctx);
-};
-
 class openglWindow : public Fl_Gl_Window {
  private:
   static openglWindow *_lastHandled;
diff --git a/Graphics/drawContext.h b/Graphics/drawContext.h
index 1fae498a7436210a3cb1509239ee9339c93fac10..42da54c3a6af9fdb51874721c3a791cfb9e87947 100644
--- a/Graphics/drawContext.h
+++ b/Graphics/drawContext.h
@@ -178,4 +178,51 @@ class drawContext {
                               int shade=0);
 };
 
+class mousePosition {
+ public:
+  double win[3]; // window coordinates
+  double wnr[3]; // world coordinates BEFORE rotation
+  double s[3]; // scaling state when the event was recorded
+  double t[3]; // translation state when the event was recorded
+  mousePosition()
+  {
+    for(int i = 0; i < 3; i++)
+      win[i] = wnr[i] = s[i] = t[i] = 0.;
+  }
+  mousePosition(const mousePosition &instance)
+  {
+    for(int i = 0; i < 3; i++){
+      win[i] = instance.win[i];
+      wnr[i] = instance.wnr[i];
+      s[i] = instance.s[i];
+      t[i] = instance.t[i];
+    }
+  }
+  void set(drawContext *ctx, int x, int y)
+  {
+    for(int i = 0; i < 3; i++){
+      s[i] = ctx->s[i];
+      t[i] = ctx->t[i];
+    }
+    win[0] = (double)x;
+    win[1] = (double)y;
+    win[2] = 0.;
+
+    wnr[0] = 
+      (ctx->vxmin + win[0] / (double)ctx->viewport[2] * (ctx->vxmax - ctx->vxmin)) 
+      / ctx->s[0] - ctx->t[0] + ctx->t_init[0] / ctx->s[0];
+    wnr[1] = 
+      (ctx->vymax - win[1] / (double)ctx->viewport[3] * (ctx->vymax - ctx->vymin))
+      / ctx->s[1] - ctx->t[1] + ctx->t_init[1] / ctx->s[1];
+    wnr[2] = 0.;
+  }
+  void recenter(drawContext *ctx)
+  {
+    // compute the equivalent translation to apply *after* the scaling
+    // so that the scaling is done around the point which was clicked:
+    ctx->t[0] = t[0] * (s[0] / ctx->s[0]) - wnr[0] * (1. - (s[0] / ctx->s[0]));
+    ctx->t[1] = t[1] * (s[1] / ctx->s[1]) - wnr[1] * (1. - (s[1] / ctx->s[1]));
+  }
+};
+
 #endif
diff --git a/doc/texinfo/gmsh.texi b/doc/texinfo/gmsh.texi
index 7d44796ad7307843af123e692a10abf92863c2d9..d7602aa93f60f1e73c0e430856bc7467ed912b6c 100644
--- a/doc/texinfo/gmsh.texi
+++ b/doc/texinfo/gmsh.texi
@@ -581,8 +581,8 @@ with your own code), you will need to learn the internal Gmsh
 Application Programming Interface (API). No complete documentation of
 this API is available yet; a good starting point is @ref{Programming
 notes}, which gives a short introduction to Gmsh's internal source code
-structure. Then have a look e.g. at @file{utils/misc/driver.cpp} in the
-source code.
+structure. Then have a look e.g. at the examples in the
+@file{utils/api_demos/} directory in the source code.
 
 @c -------------------------------------------------------------------------
 @c Syntactic rules used in the manual
diff --git a/utils/api_demos/Makefile b/utils/api_demos/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..2c341fa5334f32be04de5ae504595a1d84a03cb7
--- /dev/null
+++ b/utils/api_demos/Makefile
@@ -0,0 +1,22 @@
+#
+# how to build a standalone 64 bit gmsh lib on OSX:
+# 
+#   export CC="gcc -m64"
+#   export CXX="g++ -m64"
+#   ./configure --disable-gui --disable-netgen --disable-fm --disable-kbipack\
+#               --disable-occ --enable-graphics --disable-med --disable-chaco\
+#               --disable-metis --prefix=~/src/gmsh/utils/api_demos
+#   make install-lib
+# 
+
+mainAntTweakBar: mainAntTweakBar.cpp
+	g++ -m64 -o mainAntTweakBar -Iinclude mainAntTweakBar.cpp -Llib\
+          -lGmsh -lAntTweakBar\
+          -framework OpenGL -framework GLUT -framework Cocoa -framework ApplicationServices\
+          -llapack -lblas -lz -lm
+
+mainGlut: mainGlut.cpp
+	g++ -m64 -o mainGlut -Iinclude mainGlut.cpp -Llib -lGmsh\
+          -framework OpenGL -framework GLUT -framework Cocoa -framework ApplicationServices\
+          -llapack -lblas -lz -lm
+
diff --git a/utils/api_demos/mainAntTweakBar.cpp b/utils/api_demos/mainAntTweakBar.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..52a49700540a11dbc37c79a361c1a75205124444
--- /dev/null
+++ b/utils/api_demos/mainAntTweakBar.cpp
@@ -0,0 +1,268 @@
+//
+// A simple example on how to build a GUI frontend to Gmsh using GLUT
+// and libAntTweakBar
+//
+
+#if defined(__APPLE__)
+#  include <GLUT/glut.h>
+#else
+#  include <GL/glut.h>
+#endif
+#include <AntTweakBar.h>
+#include <gmsh/Gmsh.h>
+#include <gmsh/GModel.h>
+#include <gmsh/MElement.h>
+#include <gmsh/drawContext.h>
+
+drawContext *ctx = 0;
+
+// Gmsh redefinitions (reimplement stuff in Fltk/Draw.h)
+void Draw(){ ctx->draw3d(); ctx->draw2d(); }
+void DrawCurrentOpenglWindow(bool make_current){}
+void DrawPlugin(void (*draw)(void *context)){}
+int GetFontIndex(const char *fontname){ return 0; }
+int GetFontEnum(int index){ return 0; }
+const char *GetFontName(int index){ return "Helvetica"; }
+int GetFontAlign(const char *alignstr){ return 0; }
+int GetFontSize(){ return 18; }
+void SetFont(int fontid, int fontsize){}
+double GetStringWidth(const char *str)
+{ return glutBitmapLength(GLUT_BITMAP_HELVETICA_18, (const unsigned char*)str); }
+int GetStringHeight(){ return 18; }
+int GetStringDescent(){ return 6; }
+void DrawString(const char *str)
+{ for (int i = 0; i < strlen(str); i++) 
+    glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18, str[i]); }
+
+// GLUT callbacks
+void display()
+{
+  glViewport(ctx->viewport[0], ctx->viewport[1],
+             ctx->viewport[2], ctx->viewport[3]);
+  glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
+  Draw();
+  TwDraw();
+  glutSwapBuffers(); 
+  glutPostRedisplay();
+}
+
+void reshape(int w, int h)
+{
+  ctx->viewport[2] = w;
+  ctx->viewport[3] = h;
+  TwWindowSize(w, h);
+}
+
+void keyboard(unsigned char key, int x, int y)
+{
+  static bool fullScreen = false;
+  static int oldw = 10, oldh = 10;
+  if(TwEventKeyboardGLUT(key, x, y)) return;
+  switch(key){
+  case '1': GModel::current()->mesh(1); break;
+  case '2': GModel::current()->mesh(2); break;
+  case '3': GModel::current()->mesh(3); break;
+  case 'f': 
+    if(fullScreen){ glutReshapeWindow(oldw, oldh); }
+    else{ oldw = ctx->viewport[2]; oldh = ctx->viewport[3]; glutFullScreen(); }
+    fullScreen = !fullScreen;
+  }
+  glutPostRedisplay();
+}
+
+static int xprev = 0, yprev = 0, specialkey = 0;
+
+void mouseMotion(int x, int y)
+{
+  if(TwEventMouseMotionGLUT(x, y)) return;
+  int w = ctx->viewport[2]; 
+  int h = ctx->viewport[3];
+  if(specialkey == GLUT_ACTIVE_SHIFT){
+    double dx = x - xprev;
+    double dy = y - yprev;
+    if(fabs(dy) > fabs(dx)) {
+      double fact = (4. * fabs(dy) + h) / (double)h;
+      ctx->s[0] *= ((dy > 0) ? fact : 1. / fact);
+      ctx->s[1] = ctx->s[0];
+      ctx->s[2] = ctx->s[0];
+    }
+  }
+  else{
+    ctx->addQuaternion((2. * xprev - w) / w, (h - 2. * yprev) / h,
+                       (2. * x - w) / w, (h - 2. * y) / h);
+  }
+  xprev = x;
+  yprev = y;
+  glutPostRedisplay();
+}
+
+void mouseButton(int button, int state, int x, int y)
+{
+  if(TwEventMouseButtonGLUT(button, state, x, y)) return;
+  specialkey = glutGetModifiers();
+  xprev = x;
+  yprev = y;
+}
+
+// AntTweakBar callbacks
+void TW_CALL SetLightDirCB(const void *value, void *clientData)
+{
+  const double *dir = (const double *)(value);
+  GmshSetOption("General", "Light0X", -dir[0]);
+  GmshSetOption("General", "Light0Y", -dir[1]);
+  GmshSetOption("General", "Light0Z", -dir[2]);
+}
+
+void TW_CALL GetLightDirCB(void *value, void *clientData)
+{
+  double *dir = (double*)(value);
+  GmshGetOption("General", "Light0X", dir[0]);
+  GmshGetOption("General", "Light0Y", dir[1]);
+  GmshGetOption("General", "Light0Z", dir[2]);
+  dir[0] *= -1; dir[1] *= -1; dir[2] *= -1;
+}
+
+void TW_CALL SetInt32CB(const void *value, void *clientData)
+{
+  int b = *(const int*)(value);
+  std::string s((const char *)clientData);
+  int idot = s.find_first_of('.');
+  GmshSetOption(s.substr(0, idot), s.substr(idot + 1), (double)b);
+}
+
+void TW_CALL GetInt32CB(void *value, void *clientData)
+{
+  std::string s((const char *)clientData);
+  int idot = s.find_first_of('.');
+  double tmp;
+  GmshGetOption(s.substr(0, idot), s.substr(idot + 1), tmp);
+  *(int*)(value) = (int)tmp;
+}
+
+void TW_CALL SetDoubleCB(const void *value, void *clientData)
+{
+  double b = *(const double*)(value);
+  std::string s((const char *)clientData);
+  int idot = s.find_first_of('.');
+  GmshSetOption(s.substr(0, idot), s.substr(idot + 1), b);
+}
+
+void TW_CALL GetDoubleCB(void *value, void *clientData)
+{
+  std::string s((const char *)clientData);
+  int idot = s.find_first_of('.');
+  GmshGetOption(s.substr(0, idot), s.substr(idot + 1), *(double*)(value));
+}
+
+void TW_CALL SetColorCB(const void *value, void *clientData)
+{
+  unsigned int b = *(const unsigned int*)(value);
+  std::string s((const char *)clientData);
+  int idot = s.find_first_of('.');
+  GmshSetOption(s.substr(0, idot), s.substr(idot + 1), b);
+}
+
+void TW_CALL GetColorCB(void *value, void *clientData)
+{
+  std::string s((const char *)clientData);
+  int idot = s.find_first_of('.');
+  GmshGetOption(s.substr(0, idot), s.substr(idot + 1), *(unsigned int*)(value));
+}
+
+void TW_CALL MenuCB(void *clientData)
+{
+  printf("menu '%s'\n", (const char*)clientData);
+}
+
+int main(int argc, char **argv)
+{
+  GmshInitialize(argc, argv);
+  GmshSetOption("General", "Terminal", 1.);
+  GmshSetOption("View", "IntervalsType", 1.);
+  GmshSetOption("View", "AdaptVisualizationGrid", 1.);
+  GmshSetOption("View", "TargetError", 0.00001);
+  GmshSetOption("View", "MaxRecursionLevel", 3.); 
+
+  for(int i = 1; i < argc; i++) GmshMergeFile(argv[i]);
+
+  ctx = new drawContext();
+
+  if(!TwInit(TW_OPENGL, NULL)){
+    printf("AntTweakBar initialization failed: %s\n", TwGetLastError());
+    return 1;
+  }
+
+  glutInit(&argc, argv);
+  glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
+  glutInitWindowSize(ctx->viewport[2], ctx->viewport[3]);
+  glutInitWindowPosition(100, 100);
+  glutCreateWindow("Gmsh Viewer");
+  glutDisplayFunc(display);
+  glutReshapeFunc(reshape);
+  glutMouseFunc(mouseButton);
+  glutMotionFunc(mouseMotion);
+  glutPassiveMotionFunc((GLUTmousemotionfun)TwEventMouseMotionGLUT);
+  glutKeyboardFunc(keyboard);
+  glutSpecialFunc((GLUTspecialfun)TwEventSpecialGLUT);
+  TwGLUTModifiersFunc(glutGetModifiers);
+
+  TwBar *bar = TwNewBar("Options");
+  TwDefine(" Options size='200 400' "); // color='0 0 0' alpha=128");
+  {
+    TwEnumVal axesEV[6] = { {0, "None"}, {1, "Simple axes"}, {2, "Box"}, 
+                            {3, "Full grid"}, {4, "Open grid"}, {5, "Ruler"} };
+    TwType axesType = TwDefineEnum("AxesType", axesEV, 6);
+    TwAddVarCB(bar, "Axes", axesType, SetInt32CB, GetInt32CB, (void*)"General.Axes", 
+               " group='General' help='Change axes.' ");
+    TwAddVarCB(bar, "LightDir", TW_TYPE_DIR3D, SetLightDirCB, GetLightDirCB, 0,
+               " group='General' label='Light direction' close help='Change light direction.' ");
+    {
+      TwAddVarCB(bar, "Background", TW_TYPE_COLOR32, SetColorCB, GetColorCB, (void*)"General.Background",
+                 " group='GeneralColor' label='Background color' ");
+      TwAddVarCB(bar, "BackgroundGradient", TW_TYPE_COLOR32, SetColorCB, GetColorCB, (void*)"General.BackgroundGradient",
+                 " group='GeneralColor' label='Background gradient color' ");
+      TwDefine(" Options/GeneralColor  label='Colors' close group='General' ");
+    }
+    TwDefine(" Options/General close ");
+  }
+  {
+    TwAddVarCB(bar, "Points", TW_TYPE_BOOL32, SetInt32CB, GetInt32CB, (void*)"Geometry.Points",
+               " group='Geometry' help='Draw points.' ");
+    TwAddVarCB(bar, "Lines", TW_TYPE_BOOL32, SetInt32CB, GetInt32CB, (void*)"Geometry.Lines",
+               " group='Geometry' help='Draw lines.' ");
+    TwAddVarCB(bar, "Surfaces", TW_TYPE_BOOL32, SetInt32CB, GetInt32CB, (void*)"Geometry.Surfaces",
+               " group='Geometry' help='Draw surfaces.' ");
+    TwAddVarCB(bar, "Volumes", TW_TYPE_BOOL32, SetInt32CB, GetInt32CB, (void*)"Geometry.Volumes",
+               " group='Geometry' help='Draw volumes.' ");
+  }
+  {
+    TwAddVarCB(bar, "Vertices", TW_TYPE_BOOL32, SetInt32CB, GetInt32CB, (void*)"Mesh.Points",
+               " group='Mesh' help='Draw mesh vertices.' ");
+    TwAddVarCB(bar, "MeshLines", TW_TYPE_BOOL32, SetInt32CB, GetInt32CB, (void*)"Mesh.Lines",
+               " group='Mesh' label='Lines' help='Draw line mesh.' ");
+    TwAddVarCB(bar, "SurfaceEdges", TW_TYPE_BOOL32, SetInt32CB, GetInt32CB, (void*)"Mesh.SurfaceEdges",
+               " group='Mesh' label='Surface edges' help='Draw surface mesh edges.' ");
+    TwAddVarCB(bar, "SurfaceFaces", TW_TYPE_BOOL32, SetInt32CB, GetInt32CB, (void*)"Mesh.SurfaceFaces",
+               " group='Mesh' label='Surface faces' help='Draw surface mesh faces.' ");
+    TwAddVarCB(bar, "VolumeEdges", TW_TYPE_BOOL32, SetInt32CB, GetInt32CB, (void*)"Mesh.VolumeEdges",
+               " group='Mesh' label='Volume edges' help='Draw volume mesh edges.' ");
+    TwAddVarCB(bar, "VolumeFaces", TW_TYPE_BOOL32, SetInt32CB, GetInt32CB, (void*)"Mesh.VolumeFaces",
+               " group='Mesh' label='Volume faces' help='Draw volume mesh faces.' ");
+    TwAddVarCB(bar, "Explode", TW_TYPE_DOUBLE, SetDoubleCB, GetDoubleCB, (void*)"Mesh.Explode",
+               " group='Mesh' label='Explode factor' min=0 max=1 step=0.01 help='Explode mesh.' ");
+    TwAddVarCB(bar, "SizeFactor", TW_TYPE_DOUBLE, SetDoubleCB, GetDoubleCB, (void*)"Mesh.CharacteristicLengthFactor",
+               " group='Mesh' label='Element size factor' min=0.01 max=100 step=0.01 ");
+  }
+
+  TwBar *menubar = TwNewBar("Menu");
+  TwDefine(" Menu size='200 400' position='500 30' iconified='true' ");
+  TwAddButton(menubar, "Elementary entities", MenuCB, (void*)"Elementary", 0);
+  TwAddButton(menubar, "Physical groups", MenuCB, (void*)"Physical", 0);
+  TwAddButton(menubar, "Edit", MenuCB, (void*)"Edit", 0);
+  TwAddButton(menubar, "Reload", MenuCB, (void*)"Reload", 0);
+
+  glutMainLoop();
+
+  GmshFinalize();
+  return 0;
+}
diff --git a/utils/api_demos/mainGlut.cpp b/utils/api_demos/mainGlut.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..370232840a4c81c1a81508fbf832e4e8a85baee3
--- /dev/null
+++ b/utils/api_demos/mainGlut.cpp
@@ -0,0 +1,124 @@
+//
+// A simple example on how to build a GUI frontend to Gmsh using GLUT
+//
+
+#if defined(__APPLE__)
+#  include <GLUT/glut.h>
+#else
+#  include <GL/glut.h>
+#endif
+#include <Gmsh/Gmsh.h>
+#include <gmsh/GModel.h>
+#include <gmsh/MElement.h>
+#include <Gmsh/drawContext.h>
+
+drawContext *ctx = 0;
+
+// reimplement functions in Fltk/Draw.h
+void Draw(){ ctx->draw3d(); ctx->draw2d(); }
+void DrawCurrentOpenglWindow(bool make_current){}
+void DrawPlugin(void (*draw)(void *context)){}
+int GetFontIndex(const char *fontname){ return 0; }
+int GetFontEnum(int index){ return 0; }
+const char *GetFontName(int index){ return "Helvetica"; }
+int GetFontAlign(const char *alignstr){ return 0; }
+int GetFontSize(){ return 18; }
+void SetFont(int fontid, int fontsize){}
+double GetStringWidth(const char *str)
+{ 
+  return glutBitmapLength(GLUT_BITMAP_HELVETICA_18, (const unsigned char*)str);
+}
+int GetStringHeight(){ return 18; }
+int GetStringDescent(){ return 6; }
+void DrawString(const char *str)
+{
+  for (int i = 0; i < strlen(str); i++)
+    glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18, str[i]);
+}
+
+void display()
+{
+  glViewport(ctx->viewport[0], ctx->viewport[1],
+             ctx->viewport[2], ctx->viewport[3]);
+  glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
+  Draw();
+  glutSwapBuffers(); 
+}
+
+void reshape(int w, int h)
+{
+  ctx->viewport[2] = w;
+  ctx->viewport[3] = h;
+  display();
+}
+
+void keyboard(unsigned char key, int x, int y)
+{
+  switch(key){
+  case '1': GModel::current()->mesh(1); break;
+  case '2': GModel::current()->mesh(2); break;
+  case '3': GModel::current()->mesh(3); break;
+  }
+  display();
+}
+
+static int xprev = 0, yprev = 0, specialkey = 0;
+
+void motion(int x, int y)
+{
+  int w = ctx->viewport[2]; 
+  int h = ctx->viewport[3];
+  if(specialkey == GLUT_ACTIVE_SHIFT){
+    double dx = x - xprev;
+    double dy = y - yprev;
+    if(fabs(dy) > fabs(dx)) {
+      double fact = (4. * fabs(dy) + h) / (double)h;
+      ctx->s[0] *= ((dy > 0) ? fact : 1. / fact);
+      ctx->s[1] = ctx->s[0];
+      ctx->s[2] = ctx->s[0];
+    }
+  }
+  else{
+    ctx->addQuaternion((2. * xprev - w) / w, (h - 2. * yprev) / h,
+                       (2. * x - w) / w, (h - 2. * y) / h);
+  }
+  xprev = x;
+  yprev = y;
+  display();
+}
+
+void mouse(int button, int state, int x, int y)
+{
+  specialkey = glutGetModifiers();
+  xprev = x;
+  yprev = y;
+}
+
+int main(int argc, char **argv)
+{
+  GmshInitialize(argc, argv);
+  GmshSetOption("General", "Terminal", 1);
+  GmshSetOption("View", "IntervalsType", 1);
+  GmshSetOption("View", "AdaptVisualizationGrid", 1);
+  GmshSetOption("View", "TargetError", 0.00001);
+  GmshSetOption("View", "MaxRecursionLevel", 3.); 
+
+  for(int i = 1; i < argc; i++) GmshMergeFile(argv[i]);
+
+  ctx = new drawContext();
+
+  glutInit(&argc, argv);
+  glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
+  glutInitWindowSize(ctx->viewport[2], ctx->viewport[3]);
+  glutInitWindowPosition(100, 100);
+  glutCreateWindow("GLUT Gmsh Viewer");
+  glutDisplayFunc(display);
+  glutReshapeFunc(reshape);
+  glutKeyboardFunc(keyboard);
+  glutMotionFunc(motion);
+  glutMouseFunc(mouse);
+  glutMainLoop();
+
+  GmshFinalize();
+  return 0;
+}
diff --git a/utils/misc/celldriver.cpp b/utils/api_demos/mainHomology.cpp
old mode 100755
new mode 100644
similarity index 100%
rename from utils/misc/celldriver.cpp
rename to utils/api_demos/mainHomology.cpp
diff --git a/utils/misc/laplace.cpp b/utils/api_demos/mainLaplace.cpp
similarity index 100%
rename from utils/misc/laplace.cpp
rename to utils/api_demos/mainLaplace.cpp
diff --git a/utils/misc/driverOCC.cpp b/utils/api_demos/mainOcc.cpp
similarity index 100%
rename from utils/misc/driverOCC.cpp
rename to utils/api_demos/mainOcc.cpp
diff --git a/utils/api_demos/mainPost.cpp b/utils/api_demos/mainPost.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..1f6ba0fbaa289a5840c100d948b332695d77656c
--- /dev/null
+++ b/utils/api_demos/mainPost.cpp
@@ -0,0 +1,48 @@
+// configure, compile and install Gmsh as a library with
+//
+//   ./configure --disable-gui
+//   make install-lib
+//
+// Then compile this driver with "g++ driver.cpp -lGmsh -llapack -lblas"
+
+#include <stdio.h>
+#include <gmsh/Gmsh.h>
+#include <gmsh/GModel.h>
+#include <gmsh/MElement.h>
+
+    std::vector<GEntity*> entities;
+    GModel::current()->getEntities(entities);
+    std::map<int, std::vector<double> > d;
+    for(unsigned int i = 0; i < entities.size(); i++){
+      for(unsigned int j = 0; j < entities[i]->getNumMeshElements(); j++){
+        MElement *e = entities[i]->getMeshElement(j);
+        d[e->getNum()].push_back(e->gammaShapeMeasure());
+      }
+    }
+    new PView(name, "ElementData", GModel::current(), d);
+    PluginManager::instance()->setPluginOption("CutPlane", "A", 1.); 
+    PluginManager::instance()->setPluginOption("CutPlane", "B", 0.); 
+    PluginManager::instance()->setPluginOption("CutPlane", "C", 0.); 
+    PluginManager::instance()->setPluginOption("CutPlane", "D", -0.05); 
+    PluginManager::instance()->setPluginOption("CutPlane", "iView", 0.); 
+    PluginManager::instance()->action("CutPlane", "Run", 0);
+
+int main(int argc, char **argv)
+{
+  GmshInitialize(argc, argv);
+  GmshSetOption("Mesh", "Algorithm", 5);
+  GModel *m = new GModel();
+  m->readGEO("../../tutorial/t5.geo");
+  m->mesh(3);
+  for(GModel::riter it = m->firstRegion(); it != m->lastRegion(); ++it){
+    GRegion *r = *it;
+    printf("volume %d contains %d elements:\n", r->tag(), r->getNumMeshElements());
+    for(unsigned int i = 0; i < r->getNumMeshElements(); i++)
+      printf(" %d", r->getMeshElement(i)->getNum());
+    printf("\n");
+  }
+  m->writeMSH("test.msh");
+  m->writeUNV("test.unv");
+  delete m;
+  GmshFinalize();
+}
diff --git a/utils/misc/driver.cpp b/utils/api_demos/mainSimple.cpp
similarity index 100%
rename from utils/misc/driver.cpp
rename to utils/api_demos/mainSimple.cpp