diff --git a/Common/Context.h b/Common/Context.h
index 2290a45fad8da9f7ec6db1a14a8cab8949880f6a..ed2f660b181f1966054c52cb575cf9ddb4715d4c 100644
--- a/Common/Context.h
+++ b/Common/Context.h
@@ -93,10 +93,8 @@ class CTX {
   std::string watchFilePattern;
   // show tootips in the GUI?
   int tooltips;
-  // scroll automatically to last message in the message window?
-  int msgAutoScroll;
   // position and size of various windows in the GUI
-  int menuPosition[2], glPosition[2], glSize[2], msgPosition[2], msgSize[2];
+  int menuPosition[2], glPosition[2], glSize[2], msgSize;
   int optPosition[2], visPosition[2], clipPosition[2], manipPosition[2];
   int statPosition[2], ctxPosition[2], solverPosition[2];
   int pluginPosition[2], pluginSize[2], fieldPosition[2], fieldSize[2];
diff --git a/Common/DefaultOptions.h b/Common/DefaultOptions.h
index 6181ff13887cb9a0b94b9ffec4aaf8884e1d4bc8..f7d827326d62028a508fc8bb3253f735ae0e5a11 100644
--- a/Common/DefaultOptions.h
+++ b/Common/DefaultOptions.h
@@ -724,18 +724,8 @@ StringXNumber GeneralOptions_Number[] = {
     "Horizontal position (in pixels) of the upper left corner of the menu window" }, 
   { F|S, "MenuPositionY" , opt_general_menu_position1 , 50. ,
     "Vertical position (in pixels) of the upper left corner of the menu window" }, 
-  { F|O, "MessageAutoScroll" , opt_general_message_auto_scroll , 1. , 
-    "Automatically scroll message window" }, 
-  { F|S, "MessagePositionX" , opt_general_message_position0 , 650. , 
-    "Horizontal position (in pixels) of the upper left corner of the message "
-    "window" }, 
-  { F|S, "MessagePositionY" , opt_general_message_position1 , 490. , 
-    "Vertical position (in pixels) of the upper left corner of the message "
-    "window" }, 
-  { F|S, "MessageHeight" , opt_general_message_size1 , 300. , 
-    "Height (in pixels) of the message window" }, 
-  { F|S, "MessageWidth" , opt_general_message_size0 , 400. , 
-    "Width (in pixels) of the message window" }, 
+  { F|S, "MessageHeight" , opt_general_message_size , 300. , 
+    "Height (in pixels) of the message console" }, 
   { F,   "MinX" , opt_general_xmin , 0. , 
     "Minimum model coordinate along the X-axis (read-only)" }, 
   { F,   "MinY" , opt_general_ymin , 0. , 
diff --git a/Common/GmshMessage.cpp b/Common/GmshMessage.cpp
index f5f303a7063839ef61ce70df9898b3ce0b847890..50feee990c26d4492db8998948fd9c44475ef30c 100644
--- a/Common/GmshMessage.cpp
+++ b/Common/GmshMessage.cpp
@@ -30,7 +30,6 @@
 #if defined(HAVE_FLTK)
 #include <FL/fl_ask.H>
 #include "FlGui.h"
-#include "messageWindow.h"
 #include "extraDialogs.h"
 #endif
 
@@ -160,9 +159,9 @@ void Msg::Fatal(const char *fmt, ...)
   if(FlGui::available()){
     FlGui::instance()->check();
     std::string tmp = std::string("@C1@.") + "Fatal   : " + str;
-    FlGui::instance()->messages->add(tmp.c_str());
-    FlGui::instance()->messages->show();
-    FlGui::instance()->messages->save
+    FlGui::instance()->addMessage(tmp.c_str());
+    FlGui::instance()->showMessages();
+    FlGui::instance()->saveMessages
       ((CTX::instance()->homeDir + CTX::instance()->errorFileName).c_str());
     fl_alert("A fatal error has occurred which will force Gmsh to abort.\n"
              "The error messages have been saved in the following file:\n\n%s",
@@ -201,8 +200,8 @@ void Msg::Error(const char *fmt, ...)
   if(FlGui::available()){
     FlGui::instance()->check();
     std::string tmp = std::string("@C1@.") + "Error   : " + str;
-    FlGui::instance()->messages->add(tmp.c_str());
-    FlGui::instance()->messages->show();
+    FlGui::instance()->addMessage(tmp.c_str());
+    FlGui::instance()->showMessages();
   }
 #endif
 
@@ -234,7 +233,7 @@ void Msg::Warning(const char *fmt, ...)
   if(FlGui::available()){
     FlGui::instance()->check();
     std::string tmp = std::string("@C1@.") + "Warning : " + str;
-    FlGui::instance()->messages->add(tmp.c_str());
+    FlGui::instance()->addMessage(tmp.c_str());
   }
 #endif
 
@@ -261,7 +260,7 @@ void Msg::Info(const char *fmt, ...)
   if(FlGui::available()){
     FlGui::instance()->check();
     std::string tmp = std::string("Info    : ") + str;
-    FlGui::instance()->messages->add(tmp.c_str());
+    FlGui::instance()->addMessage(tmp.c_str());
   }
 #endif
 
@@ -305,9 +304,9 @@ void Msg::Direct(int level, const char *fmt, ...)
       tmp = std::string("@C1@.") + str;
     else
       tmp = std::string("@C4@.") + str;
-    FlGui::instance()->messages->add(tmp.c_str());
+    FlGui::instance()->addMessage(tmp.c_str());
     if(level == 1)
-      FlGui::instance()->messages->show();
+      FlGui::instance()->showMessages();
   }
 #endif
 
@@ -338,7 +337,7 @@ void Msg::StatusBar(int num, bool log, const char *fmt, ...)
       FlGui::instance()->setStatus(str, num - 1);
     if(log){
       std::string tmp = std::string("Info    : ") + str;
-      FlGui::instance()->messages->add(tmp.c_str());
+      FlGui::instance()->addMessage(tmp.c_str());
     }
   }
 #endif
@@ -365,7 +364,7 @@ void Msg::Debug(const char *fmt, ...)
 #if defined(HAVE_FLTK)
   if(FlGui::available()){
     std::string tmp = std::string("Debug   : ") + str;
-    FlGui::instance()->messages->add(tmp.c_str());
+    FlGui::instance()->addMessage(tmp.c_str());
   }
 #endif
 
@@ -468,14 +467,14 @@ void Msg::PrintErrorCounter(const char *title)
 #if defined(HAVE_FLTK)
   if(FlGui::available()){
     std::string red("@C1@.");
-    FlGui::instance()->messages->add((red + prefix + line).c_str());
-    FlGui::instance()->messages->add((red + prefix + title).c_str());
-    FlGui::instance()->messages->add((red + prefix + warn).c_str());
-    FlGui::instance()->messages->add((red + prefix + err).c_str());
-    FlGui::instance()->messages->add((red + prefix + help).c_str());
-    FlGui::instance()->messages->add((red + prefix + line).c_str());
+    FlGui::instance()->addMessage((red + prefix + line).c_str());
+    FlGui::instance()->addMessage((red + prefix + title).c_str());
+    FlGui::instance()->addMessage((red + prefix + warn).c_str());
+    FlGui::instance()->addMessage((red + prefix + err).c_str());
+    FlGui::instance()->addMessage((red + prefix + help).c_str());
+    FlGui::instance()->addMessage((red + prefix + line).c_str());
     if(_errorCount){
-      FlGui::instance()->messages->show();
+      FlGui::instance()->showMessages();
       fl_beep();
     }
   }
diff --git a/Common/Options.cpp b/Common/Options.cpp
index a19976e71c9319d06b73485d415f6714d369dd78..f3f2ade0dbaf667cb9944cef1297b9d166d2fc06 100644
--- a/Common/Options.cpp
+++ b/Common/Options.cpp
@@ -46,7 +46,6 @@
 #include "optionWindow.h"
 #include "solverWindow.h"
 #include "manipWindow.h"
-#include "messageWindow.h"
 #include "contextWindow.h"
 #include "clippingWindow.h"
 #endif
@@ -2470,8 +2469,10 @@ double opt_general_graphics_position1(OPT_ARGS_NUM)
 
 double opt_general_graphics_size0(OPT_ARGS_NUM)
 {
-  if(action & GMSH_SET)
+  if(action & GMSH_SET){
     CTX::instance()->glSize[0] = (int)val;
+    if(CTX::instance()->glSize[0] <= 0) CTX::instance()->glSize[0] = 800;
+  }
 #if defined(HAVE_FLTK)
   if(FlGui::available()){
     if(action & GMSH_SET){
@@ -2489,8 +2490,10 @@ double opt_general_graphics_size0(OPT_ARGS_NUM)
 
 double opt_general_graphics_size1(OPT_ARGS_NUM)
 {
-  if(action & GMSH_SET)
+  if(action & GMSH_SET){
     CTX::instance()->glSize[1] = (int)val;
+    if(CTX::instance()->glSize[1] <= 0) CTX::instance()->glSize[1] = 600;
+  }
 #if defined(HAVE_FLTK)
   if(FlGui::available()){
     if(action & GMSH_SET){
@@ -2569,43 +2572,13 @@ double opt_general_system_menu_bar(OPT_ARGS_NUM)
   return CTX::instance()->systemMenuBar;
 }
 
-double opt_general_message_position0(OPT_ARGS_NUM)
-{
-  if(action & GMSH_SET)
-    CTX::instance()->msgPosition[0] = (int)val;
-  return CTX::instance()->msgPosition[0];
-}
-
-double opt_general_message_position1(OPT_ARGS_NUM)
-{
-  if(action & GMSH_SET)
-    CTX::instance()->msgPosition[1] = (int)val;
-  return CTX::instance()->msgPosition[1];
-}
-
-double opt_general_message_size0(OPT_ARGS_NUM)
+double opt_general_message_size(OPT_ARGS_NUM)
 {
-  if(action & GMSH_SET)
-    CTX::instance()->msgSize[0] = (int)val;
-  return CTX::instance()->msgSize[0];
-}
-
-double opt_general_message_size1(OPT_ARGS_NUM)
-{
-  if(action & GMSH_SET)
-    CTX::instance()->msgSize[1] = (int)val;
-  return CTX::instance()->msgSize[1];
-}
-
-double opt_general_message_auto_scroll(OPT_ARGS_NUM)
-{
-  if(action & GMSH_SET)
-    CTX::instance()->msgAutoScroll = (int)val;
-#if defined(HAVE_FLTK)
-  if(FlGui::available() && (action & GMSH_GUI))
-    FlGui::instance()->messages->butt->value(CTX::instance()->msgAutoScroll);
-#endif
-  return CTX::instance()->msgAutoScroll;
+  if(action & GMSH_SET){
+    CTX::instance()->msgSize = (int)val;
+    if(CTX::instance()->msgSize < 0) CTX::instance()->msgSize = 0;
+  }
+  return CTX::instance()->msgSize;
 }
 
 double opt_general_option_position0(OPT_ARGS_NUM)
diff --git a/Common/Options.h b/Common/Options.h
index d29b4addd026a155ddeab2bbd3e60181f68e2157..e80389fc05941916221ab22b6c6c259ddfff014b 100644
--- a/Common/Options.h
+++ b/Common/Options.h
@@ -252,11 +252,7 @@ double opt_general_polygon_offset_units(OPT_ARGS_NUM);
 double opt_general_menu_position0(OPT_ARGS_NUM);
 double opt_general_menu_position1(OPT_ARGS_NUM);
 double opt_general_system_menu_bar(OPT_ARGS_NUM);
-double opt_general_message_position0(OPT_ARGS_NUM);
-double opt_general_message_position1(OPT_ARGS_NUM);
-double opt_general_message_size0(OPT_ARGS_NUM);
-double opt_general_message_size1(OPT_ARGS_NUM);
-double opt_general_message_auto_scroll(OPT_ARGS_NUM);
+double opt_general_message_size(OPT_ARGS_NUM);
 double opt_general_option_position0(OPT_ARGS_NUM);
 double opt_general_option_position1(OPT_ARGS_NUM);
 double opt_general_plugin_position0(OPT_ARGS_NUM);
diff --git a/Fltk/CMakeLists.txt b/Fltk/CMakeLists.txt
index 3b6cbe786844d8037853e99603c2f3418f945e18..cbf7407a8fcd40cb22514ccd865970b5f5143c40 100644
--- a/Fltk/CMakeLists.txt
+++ b/Fltk/CMakeLists.txt
@@ -15,7 +15,6 @@ set(SRC
     statisticsWindow.cpp
     visibilityWindow.cpp
     clippingWindow.cpp
-    messageWindow.cpp
     manipWindow.cpp
     contextWindow.cpp
     solverWindow.cpp
diff --git a/Fltk/FlGui.cpp b/Fltk/FlGui.cpp
index 23892ba73935d19e2bef5d7533f4fa92ba28809f..e7f6737a487992097994229a69b03768e70cba3b 100644
--- a/Fltk/FlGui.cpp
+++ b/Fltk/FlGui.cpp
@@ -21,7 +21,6 @@
 #include "statisticsWindow.h"
 #include "visibilityWindow.h"
 #include "clippingWindow.h"
-#include "messageWindow.h"
 #include "manipWindow.h"
 #include "contextWindow.h"
 #include "solverWindow.h"
@@ -268,7 +267,6 @@ FlGui::FlGui(int argc, char **argv)
   stats = new statisticsWindow(CTX::instance()->deltaFontSize);
   visibility = new visibilityWindow(CTX::instance()->deltaFontSize);
   clipping = new clippingWindow(CTX::instance()->deltaFontSize);
-  messages = new messageWindow(CTX::instance()->deltaFontSize);
   manip = new manipWindow(CTX::instance()->deltaFontSize);
   geoContext = new geometryContextWindow(CTX::instance()->deltaFontSize);
   meshContext = new meshContextWindow(CTX::instance()->deltaFontSize);
@@ -785,11 +783,9 @@ void FlGui::storeCurrentWindowsInfo()
   CTX::instance()->glPosition[0] = graph[0]->win->x();
   CTX::instance()->glPosition[1] = graph[0]->win->y();
   CTX::instance()->glSize[0] = graph[0]->win->w();
-  CTX::instance()->glSize[1] = (graph[0]->win->h() - graph[0]->bottom->h());
-  CTX::instance()->msgPosition[0] = messages->win->x();
-  CTX::instance()->msgPosition[1] = messages->win->y();
-  CTX::instance()->msgSize[0] = messages->win->w();
-  CTX::instance()->msgSize[1] = messages->win->h();
+  CTX::instance()->glSize[1] = (graph[0]->win->h() - graph[0]->bottom->h() -
+                                graph[0]->browser->h());
+  CTX::instance()->msgSize = graph[0]->browser->h();
   CTX::instance()->optPosition[0] = options->win->x();
   CTX::instance()->optPosition[1] = options->win->y();
   CTX::instance()->pluginPosition[0] = plugins->win->x();
@@ -852,8 +848,6 @@ void window_cb(Fl_Widget *w, void *data)
       FlGui::instance()->manip->win->iconize();
     if(FlGui::instance()->stats->win->shown())
       FlGui::instance()->stats->win->iconize();
-    if(FlGui::instance()->messages->win->shown())
-      FlGui::instance()->messages->win->iconize();
     if(FlGui::instance()->menu->win->shown())
       FlGui::instance()->menu->win->iconize();
   }
@@ -901,9 +895,23 @@ void window_cb(Fl_Widget *w, void *data)
       FlGui::instance()->manip->win->show();
     if(FlGui::instance()->stats->win->shown())
       FlGui::instance()->stats->win->show();
-    if(FlGui::instance()->messages->win->shown())
-      FlGui::instance()->messages->win->show();
     FlGui::instance()->menu->win->show();
   }
 }
 
+void FlGui::addMessage(const char *msg)
+{
+  for(unsigned int i = 0; i < FlGui::instance()->graph.size(); i++)
+    FlGui::instance()->graph[i]->addMessage(msg);
+}
+
+void FlGui::showMessages()
+{
+  for(unsigned int i = 0; i < FlGui::instance()->graph.size(); i++)
+    FlGui::instance()->graph[i]->showMessages();
+}
+
+void FlGui::saveMessages(const char *fileName)
+{
+  FlGui::instance()->graph[0]->saveMessages(fileName);
+}
diff --git a/Fltk/FlGui.h b/Fltk/FlGui.h
index bc3b6563544a50be7bf2ae7bb8f08dd0775bad00..8a6f5a22ae008477bd12f014ae9d7f484afe5a10 100644
--- a/Fltk/FlGui.h
+++ b/Fltk/FlGui.h
@@ -28,7 +28,6 @@ class pluginWindow;
 class statisticsWindow;
 class visibilityWindow;
 class clippingWindow;
-class messageWindow;
 class manipWindow;
 class geometryContextWindow;
 class meshContextWindow;
@@ -59,7 +58,6 @@ class FlGui{
   statisticsWindow *stats;
   visibilityWindow *visibility;
   clippingWindow *clipping;
-  messageWindow *messages;
   manipWindow *manip;
   geometryContextWindow *geoContext;
   meshContextWindow *meshContext;
@@ -106,6 +104,12 @@ class FlGui{
   void setStatus(const char *msg, int num);
   // create the window for physical context dependant definitions
   void callForSolverPlugin(int dim);
+  // add line in message console(s)
+  void addMessage(const char *msg);
+  // show the message console
+  void showMessages();
+  // add line in message console(s)
+  void saveMessages(const char *fileName);
 };
 
 void redraw_cb(Fl_Widget *w, void *data);
diff --git a/Fltk/graphicWindow.cpp b/Fltk/graphicWindow.cpp
index 5406800492121c05522aea2888beb0a139e8efc6..b0696523ae08b87fa95561798317f1dd4c5b9f34 100644
--- a/Fltk/graphicWindow.cpp
+++ b/Fltk/graphicWindow.cpp
@@ -11,9 +11,9 @@
 #include "paletteWindow.h"
 #include "mainWindow.h"
 #include "menuWindow.h"
-#include "messageWindow.h"
 #include "manipWindow.h"
 #include "extraDialogs.h"
+#include "fileDialogs.h"
 #include "PView.h"
 #include "PViewData.h"
 #include "OS.h"
@@ -231,7 +231,7 @@ void status_options_cb(Fl_Widget *w, void *data)
   }
   else if(!strcmp(str, "?")){ // display options
     PrintOptions(0, GMSH_FULLRC, 0, 1, NULL);
-    FlGui::instance()->messages->show();
+    FlGui::instance()->showMessages();
   }
   else if(!strcmp(str, "p")){ // toggle projection mode
     if(!Fl::event_state(FL_SHIFT)){
@@ -417,6 +417,32 @@ static void remove_graphic_window_cb(Fl_Widget *w, void *data)
   }
 }
 
+void message_cb(Fl_Widget *w, void *data)
+{
+  if(FlGui::instance()->graph[0]->browser->h())
+    FlGui::instance()->graph[0]->hideMessages();
+  else 
+    FlGui::instance()->graph[0]->showMessages();
+  FlGui::check();
+}
+
+static void message_event_cb(Fl_Widget *w, void *data)
+{
+  graphicWindow *g = (graphicWindow*)data;
+
+  if(Fl::event_button() == 3 || Fl::event_state(FL_CTRL)){
+    int a = Msg::GetAnswer("Save or clear messages?", 0, 
+                           "Cancel", "Save", "Clear");
+    if(a == 1){
+      if(fileChooser(FILE_CHOOSER_CREATE, "Save", ""))
+        g->saveMessages(fileChooserGetName(1).c_str());
+    }
+    else if(a == 2) g->clearMessages();
+  }
+  else
+    g->copySelectedMessagesToClipboard();
+}
+
 // This dummy box class permits to define a box widget that will not
 // eat the FL_ENTER/FL_LEAVE events (the new Box widget in fltk > 1.1
 // does that, so that gl->handle() was not called when the mouse
@@ -447,8 +473,15 @@ graphicWindow::graphicWindow(bool main, int numTiles)
   int sh = 2 * FL_NORMAL_SIZE - 4; // status bar height
   int sw = FL_NORMAL_SIZE + 3; // status button width
   int width = CTX::instance()->glSize[0];
+  int mheight = CTX::instance()->msgSize;
   int glheight = CTX::instance()->glSize[1];
-  int height = glheight + sh;
+  int height = glheight + mheight + sh;
+
+  // no tile should be zero during tile creation
+  if(CTX::instance()->msgSize <= 0 || CTX::instance()->msgSize >= glheight){
+    mheight = 10;
+    glheight = CTX::instance()->glSize[1] - 10;
+  }
   
   // the graphic window should be a "normal" window (neither modal nor
   // non-modal)
@@ -462,69 +495,69 @@ graphicWindow::graphicWindow(bool main, int numTiles)
   }
 
   // bottom button bar
-  bottom = new Fl_Box(0, glheight, width, sh);
+  bottom = new Fl_Box(0, glheight + mheight, width, sh);
   bottom->box(FL_FLAT_BOX);
   
   int x = 2;
   int sht = sh - 4; // leave a 2 pixel border at the bottom
   
-  butt[5] = new Fl_Button(x, glheight + 2, sw, sht, "@-1gmsh_models");
+  butt[5] = new Fl_Button(x, glheight + mheight + 2, sw, sht, "@-1gmsh_models");
   butt[5]->callback(status_options_cb, (void *)"model");
   butt[5]->tooltip("Select active model");
   x += sw;
-  butt[0] = new Fl_Button(x, glheight + 2, sw, sht, "X");
+  butt[0] = new Fl_Button(x, glheight + mheight + 2, sw, sht, "X");
   butt[0]->callback(status_xyz1p_cb, (void *)"x");
   butt[0]->tooltip("Set +X or -X view (Alt+x or Alt+Shift+x)");
   x += sw;  
-  butt[1] = new Fl_Button(x, glheight + 2, sw, sht, "Y");
+  butt[1] = new Fl_Button(x, glheight + mheight + 2, sw, sht, "Y");
   butt[1]->callback(status_xyz1p_cb, (void *)"y");
   butt[1]->tooltip("Set +Y or -Y view (Alt+y or Alt+Shift+y)");
   x += sw;  
-  butt[2] = new Fl_Button(x, glheight + 2, sw, sht, "Z");
+  butt[2] = new Fl_Button(x, glheight + mheight + 2, sw, sht, "Z");
   butt[2]->callback(status_xyz1p_cb, (void *)"z");
   butt[2]->tooltip("Set +Z or -Z view (Alt+z or Alt+Shift+z)");
   x += sw;  
-  butt[4] = new Fl_Button(x, glheight + 2, sw, sht, "@-1gmsh_rotate");
+  butt[4] = new Fl_Button(x, glheight + mheight + 2, sw, sht, "@-1gmsh_rotate");
   butt[4]->callback(status_xyz1p_cb, (void *)"r");
   butt[4]->tooltip("Rotate +90 or -90 (Shift) degrees, or sync rotations (Alt)");
   x += sw;  
-  butt[3] = new Fl_Button(x, glheight + 2, 2 * FL_NORMAL_SIZE, sht, "1:1");
+  butt[3] = new Fl_Button(x, glheight + mheight + 2, 2 * FL_NORMAL_SIZE, sht, "1:1");
   butt[3]->callback(status_xyz1p_cb, (void *)"1:1");
   butt[3]->tooltip("Set unit scale, sync scale between viewports (Alt), "
                    "or reset bounding box around visible entities (Shift)");
   x += 2 * FL_NORMAL_SIZE;  
-  butt[8] = new Fl_Button(x, glheight + 2, sw, sht, "@-1gmsh_ortho");
+  butt[8] = new Fl_Button(x, glheight + mheight + 2, sw, sht, "@-1gmsh_ortho");
   butt[8]->callback(status_options_cb, (void *)"p");
   butt[8]->tooltip("Toggle projection mode (Alt+o or Alt+Shift+o)");
   x += sw;  
-  butt[12] = new Fl_Button(x, glheight + 2, sw, sht, "M");
+  butt[12] = new Fl_Button(x, glheight + mheight + 2, sw, sht, "M");
   butt[12]->callback(status_options_cb, (void *)"M");
   butt[12]->tooltip("Toggle mesh visibility (Alt+m)");
   x += sw;  
-  butt[13] = new Fl_Button(x, glheight + 2, sw, sht, "@-1gmsh_clscale");
+  butt[13] = new Fl_Button(x, glheight + mheight + 2, sw, sht, "@-1gmsh_clscale");
   butt[13]->callback(status_options_cb, (void *)"clscale");
   butt[13]->tooltip("Change mesh element size factor");
   x += sw;  
-  butt[9] = new Fl_Button(x, glheight + 2, sw, sht, "S");
+  butt[9] = new Fl_Button(x, glheight + mheight + 2, sw, sht, "S");
   butt[9]->callback(status_options_cb, (void *)"S");
   butt[9]->tooltip("Toggle mouse selection ON/OFF (Escape)");
   x += sw;  
-  butt[6] = new Fl_Button(x, glheight + 2, sw, sht, "@-1gmsh_rewind");
+  butt[6] = new Fl_Button(x, glheight + mheight + 2, sw, sht, "@-1gmsh_rewind");
   butt[6]->callback(status_rewind_cb);
   butt[6]->tooltip("Rewind animation");
   butt[6]->deactivate();
   x += sw;  
-  butt[10] = new Fl_Button(x, glheight + 2, sw, sht, "@-1gmsh_back");
+  butt[10] = new Fl_Button(x, glheight + mheight + 2, sw, sht, "@-1gmsh_back");
   butt[10]->callback(status_stepbackward_cb);
   butt[10]->tooltip("Step backward");
   butt[10]->deactivate();
   x += sw;  
-  butt[7] = new Fl_Button(x, glheight + 2, sw, sht, "@-1gmsh_play");
+  butt[7] = new Fl_Button(x, glheight + mheight + 2, sw, sht, "@-1gmsh_play");
   butt[7]->callback(status_play_cb);
   butt[7]->tooltip("Play/pause animation");
   butt[7]->deactivate();
   x += sw;  
-  butt[11] = new Fl_Button(x, glheight + 2, sw, sht, "@-1gmsh_forward");
+  butt[11] = new Fl_Button(x, glheight + mheight + 2, sw, sht, "@-1gmsh_forward");
   butt[11]->callback(status_stepforward_cb);
   butt[11]->tooltip("Step forward");
   butt[11]->deactivate();
@@ -540,8 +573,8 @@ graphicWindow::graphicWindow(bool main, int numTiles)
   int wleft = (width - x) / 3 - 1;
   int wright = (width - x) - (width - x) / 3 - 1;
   
-  label[0] = new Fl_Box(x, glheight + 2, wleft, sht);
-  label[1] = new Fl_Box(x + (width - x) / 3, glheight + 2, wright, sht);
+  label[0] = new Fl_Box(x, glheight + mheight + 2, wleft, sht);
+  label[1] = new Fl_Box(x + (width - x) / 3, glheight + mheight + 2, wright, sht);
   for(int i = 0; i < 2; i++) {
     label[i]->box(FL_THIN_DOWN_BOX);
     label[i]->align(FL_ALIGN_LEFT | FL_ALIGN_INSIDE | FL_ALIGN_CLIP);
@@ -557,7 +590,7 @@ graphicWindow::graphicWindow(bool main, int numTiles)
   win->size_range(minWidth, minHeight);
 
   // tiled opengl windows
-  tile = new Fl_Tile(0, 0, width, glheight);
+  tile = new Fl_Tile(0, 0, width, glheight + mheight);
 
   int w2 = width / 2, h2 = glheight / 2;
   if(numTiles == 2){
@@ -597,8 +630,20 @@ graphicWindow::graphicWindow(bool main, int numTiles)
   }
   for(unsigned int i = 0; i < gl.size(); i++) gl[i]->mode(mode);
 
+  browser = new Fl_Browser(0, glheight, width, mheight);
+  browser->box(FL_THIN_DOWN_BOX);
+  browser->textfont(FL_COURIER);
+  browser->textsize(FL_NORMAL_SIZE - 1);
+  browser->type(FL_MULTI_BROWSER);
+  browser->callback(message_event_cb, this);
+  browser->has_scrollbar(Fl_Browser_::VERTICAL);
+
   tile->end();
 
+  // resize the tile to match the prescribed sizes
+  tile->position(0, glheight, 0, CTX::instance()->glSize[1]);
+  _savedMessageHeight = CTX::instance()->msgSize;
+
   win->position(CTX::instance()->glPosition[0], CTX::instance()->glPosition[1]);
   win->end();
 }
@@ -626,9 +671,12 @@ void graphicWindow::split(openglWindow *g, char how)
     // let's be brutal :-)
     int mode = g->mode();
     openglWindow::setLastHandled(0);
-    tile->clear(); // this really deletes the child opengl windows
+    for(unsigned int i = 0; i < gl.size(); i++){
+      tile->remove(gl[i]);
+      delete gl[i];
+    }
     gl.clear();
-    openglWindow *g2 = new openglWindow(0, 0, tile->w(), tile->h());
+    openglWindow *g2 = new openglWindow(0, 0, tile->w(), tile->h() - browser->h());
     g2->end();
     g2->mode(mode);
     gl.push_back(g2);
@@ -636,6 +684,8 @@ void graphicWindow::split(openglWindow *g, char how)
     g2->show();
   }
   else{
+    // make sure browser is not zero-size when adding children
+    if(browser->h() == 0) resizeMessages(1);
     int x1 = g->x();
     int y1 = g->y();
     int w1 = (how == 'h') ? g->w() / 2 : g->w();
@@ -698,3 +748,81 @@ void graphicWindow::checkAnimButtons()
     butt[11]->deactivate();
   }
 }
+
+void graphicWindow::resizeMessages(int dh)
+{
+  for(unsigned int i = 0; i < gl.size(); i++){
+    if(gl[i]->y() + gl[i]->h() == browser->y())
+      gl[i]->resize(gl[i]->x(), gl[i]->y(), gl[i]->w(), gl[i]->h() - dh);
+  }
+  browser->resize(browser->x(), browser->y() - dh, browser->w(), browser->h() + dh);
+  browser->redraw();
+}
+
+void graphicWindow::showMessages()
+{
+  int height = _savedMessageHeight;
+  if(height < 10) height = 100;
+  int maxh = win->h() - bottom->h();
+  if(height > maxh) height = maxh / 2;
+  resizeMessages(height - browser->h());
+  if(browser->h())
+    browser->bottomline(browser->size());
+}
+
+void graphicWindow::hideMessages()
+{
+  _savedMessageHeight = browser->h();
+  resizeMessages(-browser->h());
+}
+
+void graphicWindow::addMessage(const char *msg)
+{
+  browser->add(msg, 0);
+  if(win->shown() && browser->h() >= 10)
+    browser->bottomline(browser->size());
+}
+
+void graphicWindow::clearMessages()
+{
+  browser->clear();
+}
+
+void graphicWindow::saveMessages(const char *filename)
+{
+  FILE *fp = fopen(filename, "w");
+
+  if(!fp) {
+    Msg::Error("Unable to open file '%s'", filename);
+    return;
+  }
+
+  Msg::StatusBar(2, true, "Writing '%s'...", filename);
+  for(int i = 1; i <= browser->size(); i++) {
+    const char *c = browser->text(i);
+    if(c[0] == '@')
+      fprintf(fp, "%s\n", &c[5]);
+    else
+      fprintf(fp, "%s\n", c);
+  }
+  Msg::StatusBar(2, true, "Done writing '%s'", filename);
+  fclose(fp);
+}
+
+void graphicWindow::copySelectedMessagesToClipboard()
+{
+  std::string buff;
+  for(int i = 1; i <= browser->size(); i++) {
+    if(browser->selected(i)) {
+      const char *c = browser->text(i);
+      if(strlen(c) > 5 && c[0] == '@')
+        buff += std::string(&c[5]);
+      else
+        buff += std::string(c);
+      buff += "\n";
+    }
+  }
+  // bof bof bof
+  Fl::copy(buff.c_str(), buff.size(), 0);
+  Fl::copy(buff.c_str(), buff.size(), 1);
+}
diff --git a/Fltk/graphicWindow.h b/Fltk/graphicWindow.h
index 74ba102ec2a2f6990d441eb5348fd34b0deb8e0d..865043487b74054d8ad9a63167fd5fbb572f9f0b 100644
--- a/Fltk/graphicWindow.h
+++ b/Fltk/graphicWindow.h
@@ -19,6 +19,7 @@
 class graphicWindow{
  private:
   std::string _title;
+  int _savedMessageHeight;
  public:
   Fl_Window *win;
   Fl_Tile *tile;
@@ -35,13 +36,18 @@ class graphicWindow{
   void split(openglWindow *g, char how);
   void setAnimButtons(int mode);
   void checkAnimButtons();
-  void showMessages(int numLines);
+  void showMessages();
+  void hideMessages();
+  void resizeMessages(int dh);
   void addMessage(const char *msg);
+  void clearMessages();
   void saveMessages(const char *filename);
+  void copySelectedMessagesToClipboard();
 };
 
 void status_xyz1p_cb(Fl_Widget *w, void *data);
 void status_options_cb(Fl_Widget *w, void *data);
 void status_play_manual(int time, int incr);
+void message_cb(Fl_Widget *w, void *data);
 
 #endif
diff --git a/Fltk/menuWindow.cpp b/Fltk/menuWindow.cpp
index 8678b78674541600397edf701c132be8e46e9fbd..63080c901df0a34c069569025623cf7d52a33a9c 100644
--- a/Fltk/menuWindow.cpp
+++ b/Fltk/menuWindow.cpp
@@ -21,7 +21,6 @@
 #include "graphicWindow.h"
 #include "optionWindow.h"
 #include "statisticsWindow.h"
-#include "messageWindow.h"
 #include "contextWindow.h"
 #include "visibilityWindow.h"
 #include "clippingWindow.h"
@@ -587,7 +586,7 @@ static void help_short_cb(Fl_Widget *w, void *data)
   Msg::Direct("  Alt+Shift+y   Set -Y view"); 
   Msg::Direct("  Alt+Shift+z   Set -Z view"); 
   Msg::Direct(" ");
-  FlGui::instance()->messages->show();
+  FlGui::instance()->showMessages();
 }
 
 #undef CC
@@ -617,14 +616,14 @@ static void help_mouse_cb(Fl_Widget *w, void *data)
   Msg::Direct("  For a 1 button mouse, Middle button = Shift+Left button, "
               "Right button = Alt+Left button");
   Msg::Direct(" ");
-  FlGui::instance()->messages->show();
+  FlGui::instance()->showMessages();
 }
 
 static void help_command_line_cb(Fl_Widget *w, void *data)
 {
   Msg::Direct(" ");
   PrintUsage("gmsh");
-  FlGui::instance()->messages->show();
+  FlGui::instance()->showMessages();
 }
 
 static void help_online_cb(Fl_Widget *w, void *data)
@@ -1800,7 +1799,7 @@ static void mesh_inspect_cb(Fl_Widget *w, void *data)
         Msg::Direct("  Disto: %g", ele->distoShapeMeasure());
         CTX::instance()->mesh.changed = ENT_ALL;
         drawContext::global()->draw();
-        FlGui::instance()->messages->show();
+        FlGui::instance()->showMessages();
       }
     }
     if(ib == 'q') {
diff --git a/Fltk/messageWindow.cpp b/Fltk/messageWindow.cpp
deleted file mode 100644
index baab79180f16d9f5aed02a5a563fd6709caf6175..0000000000000000000000000000000000000000
--- a/Fltk/messageWindow.cpp
+++ /dev/null
@@ -1,148 +0,0 @@
-// Gmsh - Copyright (C) 1997-2011 C. Geuzaine, J.-F. Remacle
-//
-// See the LICENSE.txt file for license information. Please report all
-// bugs and problems to <gmsh@geuz.org>.
-
-#include <stdio.h>
-#include <string.h>
-#include <FL/Fl_Box.H>
-#include <FL/Fl_Return_Button.H>
-#include <FL/fl_ask.H>
-#include "FlGui.h"
-#include "messageWindow.h"
-#include "paletteWindow.h"
-#include "fileDialogs.h"
-#include "GmshMessage.h"
-#include "OS.h"
-#include "Context.h"
-
-void message_cb(Fl_Widget *w, void *data)
-{
-  FlGui::instance()->messages->show();
-}
-
-static void message_auto_scroll_cb(Fl_Widget *w, void *data)
-{
-  CTX::instance()->msgAutoScroll = FlGui::instance()->messages->butt->value();
-}
-
-static void message_copy_cb(Fl_Widget *w, void *data)
-{
-  std::string buff;
-  for(int i = 1; i <= FlGui::instance()->messages->browser->size(); i++) {
-    if(FlGui::instance()->messages->browser->selected(i)) {
-      const char *c = FlGui::instance()->messages->browser->text(i);
-      if(strlen(c) > 5 && c[0] == '@')
-        buff += std::string(&c[5]);
-      else
-        buff += std::string(c);
-      buff += "\n";
-    }
-  }
-  // bof bof bof
-  Fl::copy(buff.c_str(), buff.size(), 0);
-  Fl::copy(buff.c_str(), buff.size(), 1);
-}
-
-static void message_clear_cb(Fl_Widget *w, void *data)
-{
-  FlGui::instance()->messages->browser->clear();
-}
-
-static void message_save_cb(Fl_Widget *w, void *data)
-{
- test:
-  if(fileChooser(FILE_CHOOSER_CREATE, "Save", "*")) {
-    std::string name = fileChooserGetName(1);
-    if(CTX::instance()->confirmOverwrite) {
-      if(!StatFile(name))
-        if(!fl_choice("File '%s' already exists.\n\nDo you want to replace it?", 
-                      "Cancel", "Replace", NULL, name.c_str()))
-          goto test;
-    }
-    FlGui::instance()->messages->save(name.c_str());
-  }
-}
-
-messageWindow::messageWindow(int deltaFontSize)
-{
-  FL_NORMAL_SIZE -= deltaFontSize;
-
-  int width = CTX::instance()->msgSize[0];
-  int height = CTX::instance()->msgSize[1];
-
-  win = new paletteWindow
-    (width, height, CTX::instance()->nonModalWindows ? true : false, "Message Console");
-  win->box(GMSH_WINDOW_BOX);
-
-  browser = new Fl_Browser(0, 0, width, height - 2 * WB - BH);
-  browser->box(FL_FLAT_BOX);
-  browser->textfont(FL_COURIER);
-  browser->textsize(FL_NORMAL_SIZE - 1);
-  browser->type(FL_MULTI_BROWSER);
-  browser->callback(message_copy_cb);
-
-  {
-    butt = new Fl_Check_Button
-      (width - 3 * BB - 3 * WB, height - BH - WB, BB, BH, "Auto scroll");
-    butt->type(FL_TOGGLE_BUTTON);
-    butt->callback(message_auto_scroll_cb);
-  }
-  {
-    Fl_Return_Button *o = new Fl_Return_Button
-      (width - 2 * BB - 2 * WB, height - BH - WB, BB, BH, "Clear");
-    o->callback(message_clear_cb);
-  }
-  {
-    Fl_Button *o = new Fl_Button
-      (width - BB - WB, height - BH - WB, BB, BH, "Save");
-    o->callback(message_save_cb);
-  }
-
-  win->resizable(new Fl_Box(1, 1, 4, 4));
-  win->size_range(3 * BB + 4 * WB, 100);
-
-  win->position(CTX::instance()->msgPosition[0], CTX::instance()->msgPosition[1]);
-  win->end();
-
-  FL_NORMAL_SIZE += deltaFontSize;
-}
-
-void messageWindow::add(const char *msg)
-{
-  browser->add(msg, 0);
-  if(win->shown() && CTX::instance()->msgAutoScroll)
-    browser->bottomline(browser->size());
-}
-
-void messageWindow::save(const char *filename)
-{
-  FILE *fp = fopen(filename, "w");
-
-  if(!fp) {
-    Msg::Error("Unable to open file '%s'", filename);
-    return;
-  }
-
-  Msg::StatusBar(2, true, "Writing '%s'...", filename);
-  for(int i = 1; i <= browser->size(); i++) {
-    const char *c = browser->text(i);
-    if(c[0] == '@')
-      fprintf(fp, "%s\n", &c[5]);
-    else
-      fprintf(fp, "%s\n", c);
-  }
-  Msg::StatusBar(2, true, "Done writing '%s'", filename);
-  fclose(fp);
-}
-
-void messageWindow::show(bool redrawOnly)
-{
-  if(CTX::instance()->msgAutoScroll)
-    browser->bottomline(browser->size());
-
-  if(win->shown() && redrawOnly)
-    win->redraw();
-  else
-    win->show();
-}
diff --git a/Fltk/messageWindow.h b/Fltk/messageWindow.h
deleted file mode 100644
index 1b20311efb77aa4cea4ea0dd0aa935d62b40ed11..0000000000000000000000000000000000000000
--- a/Fltk/messageWindow.h
+++ /dev/null
@@ -1,27 +0,0 @@
-// Gmsh - Copyright (C) 1997-2011 C. Geuzaine, J.-F. Remacle
-//
-// See the LICENSE.txt file for license information. Please report all
-// bugs and problems to <gmsh@geuz.org>.
-
-#ifndef _MESSAGE_WINDOW_H_
-#define _MESSAGE_WINDOW_H_
-
-#include <FL/Fl_Window.H>
-#include <FL/Fl_Browser.H>
-#include <FL/Fl_Check_Button.H>
-
-class messageWindow{
- public:
-  Fl_Window *win;
-  Fl_Browser *browser;
-  Fl_Check_Button *butt;
- public:
-  messageWindow(int deltaFontSize);
-  void show(bool redrawOnly=false);
-  void add(const char *msg);
-  void save(const char *filename);
-};
-
-void message_cb(Fl_Widget *w, void *data);
-
-#endif
diff --git a/Fltk/openglWindow.cpp b/Fltk/openglWindow.cpp
index 6b0f0a7030b05dc997c71cebcb5306af84ab8e09..6814e4b242ea272a82276dd88b2dae5d8a3cb83b 100644
--- a/Fltk/openglWindow.cpp
+++ b/Fltk/openglWindow.cpp
@@ -83,8 +83,9 @@ void openglWindow::_drawScreenMessage()
 
 void openglWindow::_drawBorder()
 {
-  // draw thin border if the parent group has several children
-  if(parent()->children() > 1){
+  // draw thin border if the parent group has more than 2 children (it
+  // has at least 2: the message console and one opengl window)
+  if(parent()->children() > 2){
     unsigned char r, g, b;
     Fl::get_color(color(), r, g, b);
     /* would need to redraw all gl's when _lastHandled is changed
diff --git a/Fltk/solverWindow.cpp b/Fltk/solverWindow.cpp
index 2ef8edd82f36af50b3fe28b44237d69f2b5fed49..4d34215d18e6802fb558cb8e4923cff3973b7c56 100644
--- a/Fltk/solverWindow.cpp
+++ b/Fltk/solverWindow.cpp
@@ -20,7 +20,6 @@
 #include "menuWindow.h"
 #include "solverWindow.h"
 #include "paletteWindow.h"
-#include "messageWindow.h"
 #include "fileDialogs.h"
 #include "StringUtils.h"
 #include "Options.h"
@@ -395,7 +394,7 @@ static void solver_command_cb(Fl_Widget *w, void *data)
   int idx = ((int *)data)[1];
 
   if(ConnectionManager::get(num)->popupMessages)
-    FlGui::instance()->messages->show(true);
+    FlGui::instance()->showMessages();
 
   int optionIndex = 0;
   for(int i = 0; i < idx; i++)