diff --git a/Common/VertexArray.cpp b/Common/VertexArray.cpp
index bf906f66c3bb583964bc88e722b0a2aa9230964f..79338e74b27544dfcabc2b5e597baf84cc930b13 100644
--- a/Common/VertexArray.cpp
+++ b/Common/VertexArray.cpp
@@ -1,4 +1,4 @@
-// $Id: VertexArray.cpp,v 1.6 2005-05-21 04:55:59 geuzaine Exp $
+// $Id: VertexArray.cpp,v 1.7 2005-10-09 15:58:40 geuzaine Exp $
 //
 // Copyright (C) 1997-2005 C. Geuzaine, J.-F. Remacle
 //
@@ -81,6 +81,20 @@ void VertexArray::add(float x, float y, float z, unsigned int col)
   List_Add(colors, &a);
 }
 
+void VertexArray::global_change_color(unsigned int col)
+{
+  unsigned char r = UNPACK_RED(col);
+  unsigned char g = UNPACK_GREEN(col);
+  unsigned char b = UNPACK_BLUE(col);
+  unsigned char a = UNPACK_ALPHA(col);
+  for(int i = 0; i < List_Nbr(colors); i+= 4){
+    List_Write(colors, i, &r);
+    List_Write(colors, i, &g);
+    List_Write(colors, i, &b);
+    List_Write(colors, i, &a);
+  }
+}
+
 static double theeye[3];
 
 int compareTriEye(const void *a, const void *b)
diff --git a/Common/VertexArray.h b/Common/VertexArray.h
index 2d31f67ed3b4643caecbd96382c9bffd70f8e310..a77b7193b50fe37324c7b4c7bd159b5d66820160 100644
--- a/Common/VertexArray.h
+++ b/Common/VertexArray.h
@@ -32,6 +32,7 @@ class VertexArray{
 	   float n0, float n1, float n2, unsigned int col);
   void add(float x, float y, float z, unsigned int col);
   void sort(double eye[3]);
+  void global_change_color(unsigned int col);
 };
 
 #endif
diff --git a/Fltk/GUI.cpp b/Fltk/GUI.cpp
index c992ea5d7b0e24bcefaa49ed032ffe21607a4ba6..d7c948368c5bfe78ada9e6ea79c1c4e8f6027f78 100644
--- a/Fltk/GUI.cpp
+++ b/Fltk/GUI.cpp
@@ -1,4 +1,4 @@
-// $Id: GUI.cpp,v 1.457 2005-09-21 15:03:46 remacle Exp $
+// $Id: GUI.cpp,v 1.458 2005-10-09 15:58:40 geuzaine Exp $
 //
 // Copyright (C) 1997-2005 C. Geuzaine, J.-F. Remacle
 //
@@ -324,7 +324,7 @@ Context_Item menu_mesh[] = {
   { "1D",     (Fl_Callback *)mesh_1d_cb } ,
   { "2D",     (Fl_Callback *)mesh_2d_cb } , 
   { "3D",     (Fl_Callback *)mesh_3d_cb } , 
-  { "remesh", (Fl_Callback *)mesh_remesh } , 
+  { "Remesh", (Fl_Callback *)mesh_remesh } , 
   { "First order",  (Fl_Callback *)mesh_degree_cb, (void*)1 } , 
   { "Second order", (Fl_Callback *)mesh_degree_cb, (void*)2 } , 
 #if defined(HAVE_NETGEN)
@@ -832,6 +832,10 @@ GUI::GUI(int argc, char **argv)
   onscreen_buffer[0][0] = '\0';
   onscreen_buffer[1][0] = '\0';
 
+  // initialize selection bits
+  selection = ENT_NONE;
+  try_selection = quit_selection = end_selection = undo_selection = 0;
+
   // set X display
   if(strlen(CTX.display))
     Fl::display(CTX.display);
diff --git a/Fltk/Opengl.cpp b/Fltk/Opengl.cpp
index d665cf5a2de2e99c07bdd7cdc653f0ebd37f6029..188da306ce3e52b00d99a4490a25ae9ca688af37 100644
--- a/Fltk/Opengl.cpp
+++ b/Fltk/Opengl.cpp
@@ -1,4 +1,4 @@
-// $Id: Opengl.cpp,v 1.52 2005-04-19 01:09:33 geuzaine Exp $
+// $Id: Opengl.cpp,v 1.53 2005-10-09 15:58:41 geuzaine Exp $
 //
 // Copyright (C) 1997-2005 C. Geuzaine, J.-F. Remacle
 //
@@ -33,10 +33,6 @@ extern GUI *WID;
 extern Mesh M;
 extern Context_T CTX;
 
-void Process_SelectionBuffer(int x, int y, int *n, GLuint * ii, GLuint * jj);
-void Filter_SelectionBuffer(int n, GLuint * typ, GLuint * ient,
-                            Vertex ** thev, Curve ** thec, Surface ** thes,
-                            Mesh * m);
 // Draw specialization
 
 void InitOpengl(void)
@@ -208,8 +204,8 @@ int check_type(int type, Vertex * v, Curve * c, Surface * s)
 
 char SelectEntity(int type, Vertex ** v, Curve ** c, Surface ** s)
 {
-  int hits;
-  GLuint ii[SELECTION_BUFFER_SIZE], jj[SELECTION_BUFFER_SIZE];
+  int numhits;
+  hit hits[SELECTION_BUFFER_SIZE];
 
   WID->g_opengl_window->take_focus(); // force keyboard focus in GL window 
 
@@ -227,12 +223,12 @@ char SelectEntity(int type, Vertex ** v, Curve ** c, Surface ** s)
     WID->wait();
     if(WID->quit_selection) {
       WID->quit_selection = 0;
-      WID->selection = 0;
+      WID->selection = ENT_NONE;
       return 'q';
     }
     if(WID->end_selection) {
       WID->end_selection = 0;
-      WID->selection = 0;
+      WID->selection = ENT_NONE;
       return 'e';
     }
     if(WID->undo_selection) {
@@ -241,15 +237,14 @@ char SelectEntity(int type, Vertex ** v, Curve ** c, Surface ** s)
     }
     if(WID->try_selection) {
       WID->try_selection = 0;
-      if(type == ENT_NONE){ // just report the mouse click
+      if(WID->selection == ENT_NONE){ // just report the mouse click
 	return 'c';
       }
       else{
-	Process_SelectionBuffer(Fl::event_x(), Fl::event_y(), &hits, ii, jj);
-	Filter_SelectionBuffer(hits, ii, jj, v, c, s, &M);
-	if(check_type(type, *v, *c, *s)) {
+	Process_SelectionBuffer(Fl::event_x(), Fl::event_y(), &numhits, hits);
+	if(Filter_SelectionBuffer(WID->selection, numhits, hits, v, c, s, &M)){
 	  HighlightEntity(*v, *c, *s, 1);
-	  WID->selection = 0;
+	  WID->selection = ENT_NONE;
 	  return 'l';
 	}
       }
diff --git a/Fltk/Opengl_Window.cpp b/Fltk/Opengl_Window.cpp
index ffd4d90e755602955d0f70951d2946eafd42a660..d1adadcc4dd00058b7aa40593187d454ae253e62 100644
--- a/Fltk/Opengl_Window.cpp
+++ b/Fltk/Opengl_Window.cpp
@@ -1,4 +1,4 @@
-// $Id: Opengl_Window.cpp,v 1.48 2005-04-05 05:56:48 geuzaine Exp $
+// $Id: Opengl_Window.cpp,v 1.49 2005-10-09 15:58:41 geuzaine Exp $
 //
 // Copyright (C) 1997-2005 C. Geuzaine, J.-F. Remacle
 //
@@ -35,11 +35,7 @@ extern GUI *WID;
 extern Mesh M;
 extern Context_T CTX;
 
-void Process_SelectionBuffer(int x, int y, int *n, GLuint * ii, GLuint * jj);
-void Filter_SelectionBuffer(int n, GLuint * typ, GLuint * ient,
-                            Vertex ** thev, Curve ** thec, Surface ** thes,
-                            Mesh * m);
-int check_type(int type, Vertex * v, Curve * c, Surface * s);
+int check_type(int type, Vertex *v, Curve *c, Surface *s);
 
 void Opengl_Window::draw()
 {
@@ -140,7 +136,8 @@ void myZoom(GLdouble X1, GLdouble X2, GLdouble Y1, GLdouble Y2,
 
 int Opengl_Window::handle(int event)
 {
-  GLuint ii[SELECTION_BUFFER_SIZE], jj[SELECTION_BUFFER_SIZE];
+  int numhits;
+  hit hits[SELECTION_BUFFER_SIZE];
 
   switch (event) {
 
@@ -319,14 +316,14 @@ int Opengl_Window::handle(int event)
     }
     else {
       WID->make_opengl_current();
-      Process_SelectionBuffer(xpos, ypos, &hits, ii, jj);
+      Process_SelectionBuffer(xpos, ypos, &numhits, hits);
       ov = v;
       oc = c;
       os = s;
       v = NULL;
       c = NULL;
       s = NULL;
-      Filter_SelectionBuffer(hits, ii, jj, &v, &c, &s, &M);
+      Filter_SelectionBuffer(WID->selection, numhits, hits, &v, &c, &s, &M);
       if(ov != v || oc != c || os != s) {
         if(check_type(WID->selection, v, c, s))
           WID->g_window->cursor(FL_CURSOR_CROSS, FL_BLACK, FL_WHITE);
diff --git a/Graphics/Draw.cpp b/Graphics/Draw.cpp
index edc9329fff5d7a93d5ba16c5986356d3aaa64994..73628233e1991dfc5ba3253de0a5bacab9ec732b 100644
--- a/Graphics/Draw.cpp
+++ b/Graphics/Draw.cpp
@@ -1,4 +1,4 @@
-// $Id: Draw.cpp,v 1.77 2005-03-20 20:45:11 geuzaine Exp $
+// $Id: Draw.cpp,v 1.78 2005-10-09 15:58:41 geuzaine Exp $
 //
 // Copyright (C) 1997-2005 C. Geuzaine, J.-F. Remacle
 //
@@ -285,7 +285,7 @@ void InitPosition(void)
 
 // Entity selection
 
-void Process_SelectionBuffer(int x, int y, int *n, GLuint * ii, GLuint * jj)
+void Process_SelectionBuffer(int x, int y, int *n, hit *hits)
 {
   GLuint selectBuf[SELECTION_BUFFER_SIZE];
 
@@ -295,63 +295,90 @@ void Process_SelectionBuffer(int x, int y, int *n, GLuint * ii, GLuint * jj)
   CTX.render_mode = GMSH_SELECT;
 
   glInitNames();
-  glPushName(0);
+  glPushName(0); // init stack with 0 (=type=point). This will be
+		 // overwritten with the actual entity type everytime
+		 // an entity is drawn
 
   glPushMatrix();
   Orthogonalize(x, y);
   Draw_Mesh(&M);
   glPopMatrix();
 
-  GLint hits = glRenderMode(GL_RENDER);
+  GLint numhits = glRenderMode(GL_RENDER);
   CTX.render_mode = GMSH_RENDER;
 
-  if(hits < 0)
-    return;     // Selection Buffer Overflow
+  if(numhits < 0){
+    // selection buffer overflow
+    *n = 0;
+    return;
+  }
 
   GLint *ptr = (GLint *) selectBuf;
 
-  for(int i = 0; i < hits; i++) {
-    GLint names = *ptr;
+  for(int i = 0; i < numhits; i++) {
+    GLint names = *ptr; // number of names in the name stack (should
+			// always be 2 in Gmsh: the first is the type
+			// of the entity, the second the entity
+			// number)
     ptr++;
+    GLint mindepth = *ptr;
     ptr++;
+    GLint maxdepth = *ptr;
     ptr++;
+    hits[i].depth = (mindepth+maxdepth)/2;
     for(int j = 0; j < names; j++) {
       if(j == 0)
-        ii[i] = *ptr;
+        hits[i].type = *ptr; // type of entity (0, 1, 2 for point, line, surf)
       else if(j == 1)
-        jj[i] = *ptr;
+        hits[i].ient = *ptr; // num of entity
       ptr++;
     }
   }
-  *n = hits;
+  *n = numhits;
 }
 
-void Filter_SelectionBuffer(int n, GLuint * typ, GLuint * ient,
-                            Vertex ** thev, Curve ** thec, Surface ** thes,
-                            Mesh * m)
+int fcmp_hit_depth(const void *a, const void *b)
 {
-  GLuint typmin = 4;
+  return ((hit*)a)->depth - ((hit*)b)->depth;
+}
+
+int Filter_SelectionBuffer(int type, int n, hit *hits, 
+			   Vertex **thev, Curve **thec, Surface **thes, Mesh *m)
+{
+  // If type == ENT_NONE, return the closest entity of "lowest
+  // dimension" (point < line < surface < volume). Otherwise, return
+  // the closest entity of type "type"
+
+  unsigned int typmin = 4;
 
   for(int i = 0; i < n; i++) {
-    if(typ[i] < typmin)
-      typmin = typ[i];
+    if(hits[i].type < typmin)
+      typmin = hits[i].type;
   }
 
+  // sort hits to get closest entities first
+  qsort(hits, n, sizeof(hit), fcmp_hit_depth);
+
   for(int i = 0; i < n; i++) {
-    if(typ[i] == typmin) {
-      switch (typ[i]) {
+    if((type == ENT_NONE && hits[i].type == typmin) ||
+       (type == ENT_POINT && hits[i].type == 0) ||
+       (type == ENT_LINE && hits[i].type == 1) ||
+       (type == ENT_SURFACE && hits[i].type == 2)){
+      switch (hits[i].type) {
       case 0:
-	*thev = FindPoint(ient[i], m);
-        break;
+	*thev = FindPoint(hits[i].ient, m);
+        return 1;
       case 1:
-	*thec = FindCurve(ient[i], m);
-        break;
+	*thec = FindCurve(hits[i].ient, m);
+	return 1;
       case 2:
-	*thes = FindSurface(ient[i], m);
-        break;
+	*thes = FindSurface(hits[i].ient, m);
+	return 1;
       }
     }
   }
+  
+  return 0;
 }
 
 // Takes a cursor position in window coordinates and returns the line
diff --git a/Graphics/Draw.h b/Graphics/Draw.h
index b21a6f299225ce35f22fac0d5dfc2ca97765ad72..e0486f162ad6a7ed4e7a28eb996cfe455ab4fc61 100644
--- a/Graphics/Draw.h
+++ b/Graphics/Draw.h
@@ -38,6 +38,14 @@ void Orthogonalize(int x, int y);
 void ClearOpengl(void);
 void SetOpenglContext(void);
 
+typedef struct{
+  unsigned int type, ient, depth;
+} hit;
+
+void Process_SelectionBuffer(int x, int y, int *n, hit *hits);
+int Filter_SelectionBuffer(int type, int n, hit *hits, 
+			    Vertex **thev, Curve **thec, Surface **thes, Mesh *m);
+
 void unproject(double x, double y, double p[3], double d[3]);
 void Viewport2World(double win[3], double xyz[3]);
 void World2Viewport(double xyz[3], double win[3]);
diff --git a/Graphics/Geom.cpp b/Graphics/Geom.cpp
index 01762f9077a9fe5ddfb1abb25c3ad3ca1b5833f6..4e77769268905706b5e33aa7882444082a1d87ca 100644
--- a/Graphics/Geom.cpp
+++ b/Graphics/Geom.cpp
@@ -1,4 +1,4 @@
-// $Id: Geom.cpp,v 1.90 2005-09-07 14:36:45 remacle Exp $
+// $Id: Geom.cpp,v 1.91 2005-10-09 15:58:41 geuzaine Exp $
 //
 // Copyright (C) 1997-2005 C. Geuzaine, J.-F. Remacle
 //
@@ -683,7 +683,7 @@ void HighlightEntity(Vertex * v, Curve * c, Surface * s, int permanent)
   char Message[256], temp[256];
 
   if(permanent){
-    // we want to draw incrementally (in-between to "Draw()" calls):
+    // we want to draw incrementally (in-between to "Draw()" calls!):
     // we need to make sure that the opengl context is set correctly
     SetOpenglContext();
   }
@@ -702,6 +702,8 @@ void HighlightEntity(Vertex * v, Curve * c, Surface * s, int permanent)
     if(permanent){
       c->ipar[3] = 1;
       Draw_Curve(&c,NULL);
+      CTX.mesh.changed = 1; // a bit brutal, but the simplest solution
+      Draw_Mesh_Curve(&c,NULL);
     }
     else{
       if(c->beg && c->end)
@@ -714,6 +716,8 @@ void HighlightEntity(Vertex * v, Curve * c, Surface * s, int permanent)
     if(permanent){
       s->ipar[4] = 1;
       Draw_Surface(&s,NULL);
+      CTX.mesh.changed = 1; // a bit brutal, but the simplest solution
+      Draw_Mesh_Surface(&s,NULL);
     }
     else{
       int nbg = List_Nbr(s->Generatrices);
@@ -774,23 +778,28 @@ void HighlightEntityNum(int v, int c, int s, int permanent)
 
 void ZeroHighlightPoint(void *a, void *b)
 {
-  Vertex *v;
-  v = *(Vertex **) a;
+  Vertex *v = *(Vertex **) a;
   v->Frozen = 0;
 }
 
 void ZeroHighlightCurve(void *a, void *b)
 {
-  Curve *c;
-  c = *(Curve **) a;
+  Curve *c = *(Curve **) a;
   c->ipar[3] = 0;
+  // the curve colors might have changed (and in complicated ways,
+  // e.g., if we color by partition, so we cannot use the
+  // global_change_color trick)
+  CTX.mesh.changed = 1;
 }
 
 void ZeroHighlightSurface(void *a, void *b)
 {
-  Surface *s;
-  s = *(Surface **) a;
+  Surface *s = *(Surface **) a;
   s->ipar[4] = 0;
+  // the surface colors might have changed (and in complicated ways,
+  // e.g., if we color by partition, so we cannot use the
+  // global_change_color trick)
+  CTX.mesh.changed = 1;
 }
 
 void ZeroHighlight(Mesh * m)
diff --git a/Graphics/Mesh.cpp b/Graphics/Mesh.cpp
index 9d757042858d3a7a8ad514431c7c705b471723c5..f9b3035d1d75a0cc6a2f47fa921a9768526b707d 100644
--- a/Graphics/Mesh.cpp
+++ b/Graphics/Mesh.cpp
@@ -1,4 +1,4 @@
-// $Id: Mesh.cpp,v 1.137 2005-08-09 23:39:42 geuzaine Exp $
+// $Id: Mesh.cpp,v 1.138 2005-10-09 15:58:41 geuzaine Exp $
 //
 // Copyright (C) 1997-2005 C. Geuzaine, J.-F. Remacle
 //
@@ -162,11 +162,11 @@ void Draw_Mesh(Mesh * M)
       glDisable((GLenum)(GL_CLIP_PLANE0 + i));
   }
 
-  // if we're in selection mode, we're done
-
-  if(CTX.render_mode == GMSH_SELECT)
-    return;
-
+  // We used to be able to exit here when in SELECT mode. Since we
+  // also allow to select mesh entities now, we cannot anymore. Not
+  // sure what we should do eventually
+  //if(CTX.render_mode == GMSH_SELECT) return;
+  
   // draw the bounding box if we asked for it and we have a geometry
   // or a mesh, or if we are in fast redraw mode and there is no
   // geometry but there is a mesh
@@ -396,6 +396,11 @@ void Draw_Mesh_Surface(void *a, void *b)
   if(!(s->Visible & VIS_MESH))
     return;
 
+  if(CTX.render_mode == GMSH_SELECT) {
+    glLoadName(2);
+    glPushName(s->Num);
+  }
+
   if (CTX.mesh.surfaces_num) {
     int numLabels = Tree_Nbr(s->Simplexes) + Tree_Nbr(s->SimplexesBase) 
       + Tree_Nbr(s->Quadrangles);
@@ -467,6 +472,10 @@ void Draw_Mesh_Surface(void *a, void *b)
     Tree_Action(s->Quadrangles, Draw_Mesh_Quadrangle);
   }
 
+  if(CTX.render_mode == GMSH_SELECT) {
+    glPopName();
+  }
+
   theSurface = NULL;
 }
 
@@ -488,6 +497,11 @@ void Draw_Mesh_Curve(void *a, void *b)
   if(!(c->Visible & VIS_MESH))
     return;
 
+  if(CTX.render_mode == GMSH_SELECT) {
+    glLoadName(1);
+    glPushName(c->Num);
+  }
+
   if (CTX.mesh.lines_num) {
     int numLabels = Tree_Nbr(c->Simplexes) + Tree_Nbr(c->SimplexesBase);
     numLabelsDisplayed = 0;
@@ -526,6 +540,10 @@ void Draw_Mesh_Curve(void *a, void *b)
     Tree_Action(c->SimplexesBase, Draw_Mesh_Line);
   }
 
+  if(CTX.render_mode == GMSH_SELECT) {
+    glPopName();
+  }
+
   theCurve = NULL;
 }
 
@@ -626,7 +644,9 @@ void Draw_Mesh_Line(void *a, void *b)
   }
 
   unsigned int col;
-  if(theColor.type)
+  if(theCurve && theCurve->ipar[3])
+    col = CTX.color.geom.line_sel;
+  else if(theColor.type)
     col = theColor.mesh;
   else if(CTX.mesh.color_carousel == 1)
     col = CTX.color.mesh.carousel[abs(s->iEnt % 20)];
@@ -902,7 +922,9 @@ void Draw_Mesh_Triangle(void *a, void *b)
     return;
 
   unsigned int col;
-  if(theColor.type)
+  if(theSurface && theSurface->ipar[4])
+    col = CTX.color.geom.surface_sel;
+  else if(theColor.type)
     col = theColor.mesh;
   else if(CTX.mesh.color_carousel == 1)
     col = CTX.color.mesh.carousel[abs(s->iEnt % 20)];
@@ -1080,7 +1102,9 @@ void Draw_Mesh_Quadrangle(void *a, void *b)
     return;
 
   unsigned int col;
-  if(theColor.type)
+  if(theSurface && theSurface->ipar[4])
+    col = CTX.color.geom.surface_sel;
+  else if(theColor.type)
     col = theColor.mesh;
   else if(CTX.mesh.color_carousel == 1)
     col = CTX.color.mesh.carousel[abs(q->iEnt % 20)];
diff --git a/TODO b/TODO
index e0cc1601d4c23c1a370af4bf7d75cf7bdcbed7c6..5836d23c43408033310ecc1f1ec4851bbdf10fab 100644
--- a/TODO
+++ b/TODO
@@ -1,4 +1,17 @@
-$Id: TODO,v 1.100 2005-09-07 16:38:19 geuzaine Exp $
+$Id: TODO,v 1.101 2005-10-09 15:58:40 geuzaine Exp $
+
+********************************************************************
+
+Add a way to select multiple entities using a lasso + add a way to
+remove entities from a selection by clicking on them
+
+********************************************************************
+
+We should fine-grain CTX.mesh.changed so that we can keep track of
+changes surface by surface, volume by volume, etc. This would speed up
+mesh selection quite a bit on large models (since we would only have
+to regenerate the vertex array for the surface/volume that has
+changed, and not everything)
 
 ********************************************************************
 
diff --git a/doc/VERSIONS b/doc/VERSIONS
index a2ff80d1e18d4d25e617287fbc41eca78b82625f..4ebc1a96d60a724d00daa34127d81d24bc4ef7cf 100644
--- a/doc/VERSIONS
+++ b/doc/VERSIONS
@@ -1,4 +1,4 @@
-$Id: VERSIONS,v 1.341 2005-09-02 15:56:24 geuzaine Exp $
+$Id: VERSIONS,v 1.342 2005-10-09 15:58:41 geuzaine Exp $
 
 New since 1.60: added support for second order (curved) elements in
 post-processor; new version (1.4) of post-processing file formats; new
@@ -14,8 +14,8 @@ Windows/Cygwin; removed Discrete Line and Discrete Surface commands
 in .msh format); fixed coloring by mesh partition; new "mesh
 statistics" export format; new full-quad recombine option; new
 Plugin(ModulusPhase); experimental Tetgen integration; hexas and
-prisms are now always saved with positive volume; various small bug
-fixes and improvements.
+prisms are now always saved with positive volume; improved interactive
+entity selection; various small bug fixes and improvements.
 
 New in 1.60: added support for discrete curves; new Window menu on Mac
 OS X; generalized all octree-based plugins (CutGrid, StreamLines,