diff --git a/CMakeLists.txt b/CMakeLists.txt
index 1f4de457533d4f326b0b64da822ae4b06d67d7c6..6e6658a67578747c45d2baded065b17de8c1437f 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -456,6 +456,12 @@ if(HAVE_FLTK OR HAVE_QT OR ENABLE_GRAPHICS)
     set_config_option(HAVE_MPEG_ENCODE "Mpeg")
   endif(ENABLE_MPEG_ENCODE)
 
+  if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/contrib/3M)
+    add_subdirectory(contrib/3M)
+    include_directories(contrib/3M)
+    set_config_option(HAVE_3M "3M")
+  endif(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/contrib/3M)
+
   if(ENABLE_OSMESA)
     find_library(OSMESA_LIB OSMesa)
     if(OSMESA_LIB)
diff --git a/Common/CommandLine.cpp b/Common/CommandLine.cpp
index 6f2d7e86094ee1ff25ebc20c59cf81797da11fe7..29c042d85bbaab493933c8b8c86c8e15a32537be 100644
--- a/Common/CommandLine.cpp
+++ b/Common/CommandLine.cpp
@@ -580,8 +580,8 @@ void GetOptions(int argc, char *argv[])
             CTX::instance()->mesh.algo3d = ALGO_3D_FRONTAL_DEL;
           else if(!strncmp(argv[i], "delhex3d", 8))
             CTX::instance()->mesh.algo3d = ALGO_3D_FRONTAL_HEX;
-		  else if(!strncmp(argv[i], "rtree3d", 9))
-			CTX::instance()->mesh.algo3d = ALGO_3D_RTREE;
+          else if(!strncmp(argv[i], "rtree3d", 9))
+            CTX::instance()->mesh.algo3d = ALGO_3D_RTREE;
           else
             Msg::Fatal("Unknown mesh algorithm");
           i++;
diff --git a/Common/GmshConfig.h.in b/Common/GmshConfig.h.in
index a9329d30ba713c02f1215a740cdecfbdf8f3a1ea..0248ac92b9a182d15808489e028feb02bb2a1873 100644
--- a/Common/GmshConfig.h.in
+++ b/Common/GmshConfig.h.in
@@ -6,6 +6,7 @@
 #ifndef _GMSH_CONFIG_H_
 #define _GMSH_CONFIG_H_
 
+#cmakedefine HAVE_3M
 #cmakedefine HAVE_64BIT_SIZE_T
 #cmakedefine HAVE_ACIS
 #cmakedefine HAVE_ANN
diff --git a/Common/Options.cpp b/Common/Options.cpp
index f4c3dce18f0c9094ddb84a8f7b65a0410db2a0c9..75be46b1c23083af9226786a256a9edc303f7014 100644
--- a/Common/Options.cpp
+++ b/Common/Options.cpp
@@ -5046,9 +5046,9 @@ double opt_mesh_algo3d(OPT_ARGS_NUM)
     case ALGO_3D_FRONTAL:
       FlGui::instance()->options->mesh.choice[3]->value(1);
       break;
-	case ALGO_3D_RTREE:
-	  FlGui::instance()->options->mesh.choice[3]->value(5);
-	  break;
+    case ALGO_3D_RTREE:
+      FlGui::instance()->options->mesh.choice[3]->value(5);
+      break;
     case ALGO_3D_DELAUNAY:
     default:
       FlGui::instance()->options->mesh.choice[3]->value(0);
diff --git a/Fltk/FlGui.cpp b/Fltk/FlGui.cpp
index 1c410b80dc72710a58ce172a57acf6a955242cc8..e90d1e803dd7b290bd5954145175fc47f2582c91 100644
--- a/Fltk/FlGui.cpp
+++ b/Fltk/FlGui.cpp
@@ -890,15 +890,22 @@ void window_cb(Fl_Widget *w, void *data)
       oldy = FlGui::instance()->graph[0]->win->y();
       oldw = FlGui::instance()->graph[0]->win->w();
       oldh = FlGui::instance()->graph[0]->win->h();
+//#define FS
+#ifndef FS
       FlGui::instance()->graph[0]->win->resize(Fl::x(), Fl::y(), Fl::w(), Fl::h());
       FlGui::instance()->graph[0]->hideMessages();
       FlGui::check();
-      //FlGui::instance()->graph[0]->win->fullscreen();
+#else
+      FlGui::instance()->graph[0]->win->fullscreen();
+#endif
       zoom = 0;
     }
     else{
+#ifndef FS
       FlGui::instance()->graph[0]->win->resize(oldx, oldy, oldw, oldh);
-      //FlGui::instance()->graph[0]->win->fullscreen_off(oldx, oldy, oldw, oldh);
+#else
+      FlGui::instance()->graph[0]->win->fullscreen_off();
+#endif
       zoom = 1;
     }
     FlGui::instance()->menu->win->show();
diff --git a/Fltk/menuWindow.cpp b/Fltk/menuWindow.cpp
index 44a6238a0ee0437a9761111bfb3fc7f3d765a3d1..21609da8ef517f6cf3bdadbb1f2465006a2b4403 100644
--- a/Fltk/menuWindow.cpp
+++ b/Fltk/menuWindow.cpp
@@ -57,6 +57,9 @@ typedef unsigned long intptr_t;
 #if defined(HAVE_ONELAB)
 #include "onelab.h"
 #endif
+#if defined(HAVE_3M)
+#include "3M.h"
+#endif
 
 static void file_new_cb(Fl_Widget *w, void *data)
 {
@@ -2370,6 +2373,9 @@ static Fl_Menu_Item bar_table[] = {
     {"&Manipulator",     FL_CTRL+FL_SHIFT+'m', (Fl_Callback *)manip_cb, 0},
 #if defined(HAVE_ONELAB)
     {"&OneLab",          0, (Fl_Callback *)solver_cb, (void*)(-1), FL_MENU_DIVIDER},
+#endif
+#if defined(HAVE_3M)
+    {"&3M",              0, (Fl_Callback *)window3M_cb, 0, FL_MENU_DIVIDER},
 #endif
     {"S&tatistics",      FL_CTRL+'i', (Fl_Callback *)statistics_cb, 0},
     {"M&essage Console", FL_CTRL+'l', (Fl_Callback *)message_cb, 0},
@@ -2435,6 +2441,9 @@ static Fl_Menu_Item sysbar_table[] = {
     {"Manipulator",     FL_META+FL_SHIFT+'m', (Fl_Callback *)manip_cb, 0},
 #if defined(HAVE_ONELAB)
     {"OneLab",          0, (Fl_Callback *)solver_cb, (void*)(-1), FL_MENU_DIVIDER},
+#endif
+#if defined(HAVE_3M)
+    {"3M",              0, (Fl_Callback *)window3M_cb, 0, FL_MENU_DIVIDER},
 #endif
     {"Statistics",      FL_META+'i', (Fl_Callback *)statistics_cb, 0},
     {"Message Console", FL_META+'l', (Fl_Callback *)message_cb, 0},
diff --git a/Fltk/optionWindow.cpp b/Fltk/optionWindow.cpp
index 56cddad00b682dc28e8b1a058bbeaff94a9207fb..00d73f39297b3f7bdd14242041f6909dcc74becd 100644
--- a/Fltk/optionWindow.cpp
+++ b/Fltk/optionWindow.cpp
@@ -517,7 +517,7 @@ static void mesh_options_ok_cb(Fl_Widget *w, void *data)
                   (o->mesh.choice[3]->value() == 2) ? ALGO_3D_FRONTAL_DEL :
                   (o->mesh.choice[3]->value() == 3) ? ALGO_3D_FRONTAL_HEX :
                   (o->mesh.choice[3]->value() == 4) ? ALGO_3D_MMG3D :
-				  (o->mesh.choice[3]->value() == 5) ? ALGO_3D_RTREE :
+                  (o->mesh.choice[3]->value() == 5) ? ALGO_3D_RTREE :
                   ALGO_3D_FRONTAL);
   opt_mesh_algo_recombine(0, GMSH_SET, o->mesh.choice[1]->value());
   opt_mesh_recombine_all(0, GMSH_SET, o->mesh.butt[21]->value());
diff --git a/Mesh/Generator.cpp b/Mesh/Generator.cpp
index 660087edb6e9b7c036ab649081d3361e56061bc1..62087e6044324f5bbf42e5fed9c0d4a5ac7a191c 100644
--- a/Mesh/Generator.cpp
+++ b/Mesh/Generator.cpp
@@ -557,16 +557,16 @@ static void Mesh3D(GModel *m)
   FindConnectedRegions(delaunay, connected);
   for(unsigned int i = 0; i < connected.size(); i++){
     MeshDelaunayVolume(connected[i]);
-	if(CTX::instance()->mesh.algo3d==ALGO_3D_RTREE){
-	  Filler f;
-	  f.treat_region(connected[i][0]);
-	}
+    if(CTX::instance()->mesh.algo3d == ALGO_3D_RTREE){
+      Filler f;
+      f.treat_region(connected[i][0]);
+    }
   }
 
   double t2 = Cpu();
   CTX::instance()->meshTimer[2] = t2 - t1;
   Msg::StatusBar(2, true, "Done meshing 3D (%g s)", CTX::instance()->meshTimer[2]);
-  
+
 }
 
 void OptimizeMeshNetgen(GModel *m)