diff --git a/Common/CommandLine.cpp b/Common/CommandLine.cpp
index 68fdd374905861c08b315c399e22a70c7838125d..aa5c05b6dae31e05b5bd6c800c249ae22152c587 100644
--- a/Common/CommandLine.cpp
+++ b/Common/CommandLine.cpp
@@ -231,6 +231,13 @@ void GetOptions(int argc, char *argv[])
         CTX::instance()->noPopup = 1;
         i++;
       }
+      else if(!strcmp(argv[i] + 1, "watch")) {
+        i++;
+        if(argv[i])
+          CTX::instance()->watchFilePattern = argv[i++];
+        else
+          Msg::Fatal("Missing string");
+      }
       else if(!strcmp(argv[i] + 1, "string")) {
         i++;
         if(argv[i])
diff --git a/Common/Context.h b/Common/Context.h
index 85d3d73a783a8659e947f6a68a7015198a758c96..6064141bc71884519a9d83f23a239a9665797c4e 100644
--- a/Common/Context.h
+++ b/Common/Context.h
@@ -82,6 +82,8 @@ class CTX {
   int numWindows, numTiles;
   // text editor and web browser command (with included '%s')
   std::string editor, webBrowser;
+  // pattern of files to watch out for
+  std::string watchFilePattern;
   // show tootips in the GUI?
   int tooltips;
   // scroll automatically to last message in the message window?
diff --git a/Common/DefaultOptions.h b/Common/DefaultOptions.h
index b711a6320592a295442d2b0453b15bebfa36c622..522136ea014128154a2b8a04d91cf730cc7879c5 100644
--- a/Common/DefaultOptions.h
+++ b/Common/DefaultOptions.h
@@ -97,6 +97,9 @@ StringXString GeneralOptions_String[] = {
 #endif
     "System command to launch a web browser" },
 
+  { F|S, "WatchFilePattern", opt_general_watch_file_pattern , "" ,
+    "Pattern of files to watch out for (to load automatically)"},
+
   { 0, 0 , 0 , "" , 0 }
 } ;
 
diff --git a/Common/Options.cpp b/Common/Options.cpp
index d3b313aad06829b3fcb72a2a1f77fe036e9d9ab4..16b5729e4146b955a850db97b5b0c0697358dbf0 100644
--- a/Common/Options.cpp
+++ b/Common/Options.cpp
@@ -1046,6 +1046,13 @@ std::string opt_general_web_browser(OPT_ARGS_STR)
   return CTX::instance()->webBrowser;
 }
 
+std::string opt_general_watch_file_pattern(OPT_ARGS_STR)
+{
+  if(action & GMSH_SET)
+    CTX::instance()->watchFilePattern = val;
+  return CTX::instance()->watchFilePattern;
+}
+
 std::string opt_general_gui_theme(OPT_ARGS_STR)
 {
   if(action & GMSH_SET)
diff --git a/Common/Options.h b/Common/Options.h
index 5dc83d1049e5c401c05ed835447685cbb9df40a4..834d029a7a11b8e8d2f52f2a561ed17e019451e7 100644
--- a/Common/Options.h
+++ b/Common/Options.h
@@ -46,6 +46,7 @@ std::string opt_general_recent_file4(OPT_ARGS_STR);
 std::string opt_general_recent_file5(OPT_ARGS_STR);
 std::string opt_general_editor(OPT_ARGS_STR);
 std::string opt_general_web_browser(OPT_ARGS_STR);
+std::string opt_general_watch_file_pattern(OPT_ARGS_STR);
 std::string opt_general_gui_theme(OPT_ARGS_STR);
 std::string opt_general_graphics_font(OPT_ARGS_STR);
 std::string opt_solver_socket_name(OPT_ARGS_STR);
diff --git a/Fltk/FlGui.cpp b/Fltk/FlGui.cpp
index 9a509bf2fd8a6e73482a7a2d888f54b130349eeb..a350644cc362266cd18d8b0024becda5c282320d 100644
--- a/Fltk/FlGui.cpp
+++ b/Fltk/FlGui.cpp
@@ -340,6 +340,10 @@ int FlGui::testGlobalShortcuts(int event)
     mod_forward_cb(0, 0);
     status = 1;
   }
+  else if(Fl::test_shortcut('w')) {
+    file_watch_cb(0, 0);
+    status = 1;
+  }
   else if(Fl::test_shortcut('e')) {
     for(unsigned int i = 0; i < graph.size(); i++)
       for(unsigned int j = 0; j < graph[i]->gl.size(); j++)
diff --git a/Fltk/menuWindow.cpp b/Fltk/menuWindow.cpp
index 73b2afa38f3cecba8a5cb86df2fb177fc4030e0b..d2a503e81405d16c895da01423898953f3a64997 100644
--- a/Fltk/menuWindow.cpp
+++ b/Fltk/menuWindow.cpp
@@ -4,10 +4,12 @@
 // bugs and problems to <gmsh@geuz.org>.
 
 #include <string.h>
+#include <stdlib.h>
 #include <stdio.h>
 #include <time.h>
 #include <FL/Fl_Box.H>
 #include <FL/fl_ask.H>
+#include <FL/filename.H>
 #include "GmshConfig.h"
 #include "GmshMessage.h"
 #include "GmshSocket.h"
@@ -413,6 +415,40 @@ void file_quit_cb(Fl_Widget *w, void *data)
   Msg::Exit(0);
 }
 
+void file_watch_cb(Fl_Widget *w, void *data)
+{
+  std::string pattern = FixRelativePath
+    (GModel::current()->getFileName(), CTX::instance()->watchFilePattern);
+  std::string directory = SplitFileName(pattern)[0];
+  if(directory.empty()) directory = "./";
+  
+  dirent **files = 0;
+  int num = fl_filename_list(directory.c_str(), &files, fl_numericsort);
+  if(num <= 0) return;
+  std::vector<std::string> matches;
+  for (int i = 0; i < num; i++) {
+    std::string name = directory + files[i]->d_name;
+    if(fl_filename_match(name.c_str(), pattern.c_str()))
+      matches.push_back(name);
+    free((void*)files[i]);
+  }
+  if(files) free((void*)files);
+
+  Msg::Info("%d files matching watch pattern '%s'", num, pattern.c_str());
+  
+  std::set<std::string> allFiles;
+  for(unsigned int i = 0; i < GModel::list.size(); i++)
+    allFiles.insert(GModel::list[i]->getFileName());
+  for(unsigned int i = 0; i < PView::list.size(); i++)
+    for(unsigned int j = 0; j < PView::list[i]->getData()->getNumTimeSteps(); j++)
+      allFiles.insert(PView::list[i]->getData()->getFileName(j));
+
+  for(unsigned int i = 0; i < matches.size(); i++)
+    if(allFiles.find(matches[i]) == allFiles.end())
+      MergeFile(matches[i]);
+  drawContext::global()->draw();
+}
+
 #if defined(__APPLE__)
 #  define CC(str) "Cmd+" str " "
 #else
diff --git a/Fltk/menuWindow.h b/Fltk/menuWindow.h
index 9f5f626bf12d4113cf76ecfc47a72d2fc3db97fa..14b6ab8277219c574109fa717cd47c8013208390 100644
--- a/Fltk/menuWindow.h
+++ b/Fltk/menuWindow.h
@@ -80,6 +80,7 @@ class menuWindow{
 };
 
 void file_quit_cb(Fl_Widget *w, void *data);
+void file_watch_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);
diff --git a/Post/PViewData.h b/Post/PViewData.h
index e1bc38187a57d42cdf6cf42c27fa8df257ec3c71..ab542330d5becb253f16eb9536746ace1498f6cb 100644
--- a/Post/PViewData.h
+++ b/Post/PViewData.h
@@ -51,8 +51,8 @@ class PViewData {
   virtual std::string getName(){ return _name; }
   virtual void setName(std::string val){ _name = val; }
 
-  // get/set filename
-  virtual std::string getFileName(){ return _fileName; }
+  // get/set (the main) filename containing the data
+  virtual std::string getFileName(int step=-1){ return _fileName; }
   virtual void setFileName(std::string val){ _fileName = val; }
 
   // get/set index of view data in file
diff --git a/Post/PViewDataGModel.cpp b/Post/PViewDataGModel.cpp
index d915edf87e218596d318393ebf1951da3e897367..e9cbbca9987a6634395bd162f1048e230e765284 100644
--- a/Post/PViewDataGModel.cpp
+++ b/Post/PViewDataGModel.cpp
@@ -112,6 +112,12 @@ MElement *PViewDataGModel::_getElement(int step, int ent, int ele)
   return curr;
 }
 
+std::string PViewDataGModel::getFileName(int step)
+{
+  if(step < 0 || step > _steps.size() - 1) return PViewData::getFileName();
+  return _steps[step]->getFileName();
+}
+
 int PViewDataGModel::getNumTimeSteps()
 {
   return _steps.size();
diff --git a/Post/PViewDataGModel.h b/Post/PViewDataGModel.h
index 50aed8fd9c05d041ffe23920e7ecbec50d8b28c4..293c79b344f20a465d456881dbec081cefe192fb 100644
--- a/Post/PViewDataGModel.h
+++ b/Post/PViewDataGModel.h
@@ -129,6 +129,7 @@ class PViewDataGModel : public PViewData {
   PViewDataGModel(DataType type=NodeData);
   ~PViewDataGModel();
   bool finalize();
+  std::string getFileName(int step=-1);
   int getNumTimeSteps();
   double getTime(int step);
   double getMin(int step=-1);