Index: trunk/MagicSoft/Mars/mbase/BaseLinkDef.h
===================================================================
--- trunk/MagicSoft/Mars/mbase/BaseLinkDef.h	(revision 2492)
+++ trunk/MagicSoft/Mars/mbase/BaseLinkDef.h	(revision 2493)
@@ -29,4 +29,5 @@
 
 #pragma link C++ class MEvtLoop+;
+#pragma link C++ class MStatusDisplay+;
 
 #pragma link C++ class MInputStreamID+;
Index: trunk/MagicSoft/Mars/mbase/MStatusDisplay.cc
===================================================================
--- trunk/MagicSoft/Mars/mbase/MStatusDisplay.cc	(revision 2493)
+++ trunk/MagicSoft/Mars/mbase/MStatusDisplay.cc	(revision 2493)
@@ -0,0 +1,2216 @@
+/* ======================================================================== *\
+!
+! *
+! * This file is part of MARS, the MAGIC Analysis and Reconstruction
+! * Software. It is distributed to you in the hope that it can be a useful
+! * and timesaving tool in analysing Data of imaging Cerenkov telescopes.
+! * It is distributed WITHOUT ANY WARRANTY.
+! *
+! * Permission to use, copy, modify and distribute this software and its
+! * documentation for any purpose is hereby granted without fee,
+! * provided that the above copyright notice appear in all copies and
+! * that both that copyright notice and this permission notice appear
+! * in supporting documentation. It is provided "as is" without express
+! * or implied warranty.
+! *
+!
+!
+!   Author(s): Thomas Bretz, 4/2003 <mailto:tbretz@astro-uni-wuerzburg.de>
+!
+!   Copyright: MAGIC Software Development, 2003
+!
+!
+\* ======================================================================== */
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// MStatusDisplay
+//
+// This status display can be used (and is used) to display results in
+// a tabbed window. The window can be written to and read from a root file
+// (see Read and Write) or printed as a postscript file (see SaveAsPS).
+//
+// To write gif files of C-Macros use SaveAsGif() or SaveAsC().
+// Direct printing to the default printer (via lpr) can be done by
+// PrintToLpr().
+//
+// It has also to half status lines which can be used to display the status
+// or something going on. Together with the status lines it has a progress
+// bar which can display the progress of a job or loop.
+// Access the progress bar by GetProgressBar()
+//
+// To add a new tab and get a pointer to the newly created TCanvas
+// use AddTab.
+//
+// If you have a MStatusDisplay and you are not sure whether it was
+// destroyed by the user meanwhile use:
+//   gROOT->GetListOfSpecials()->FindObject(pointer);
+// Each MStatusDisplay is added to list list by its constructor and
+// removed from the list by the destructor.
+//
+// You can redirect an output to a MLog-logstream by calling SetLogStream().
+// To disable redirction call SetLogStream(NULL)
+//
+// Because updates to the tabs are only done/displayed if a tab is active
+// using the gui doesn't make things slower (<1%) if the first (legend
+// tab) is displayed. This gives you the possibility to look into
+// the current progress of a loop without loosing more time than the
+// single update of the tab.
+//
+/////////////////////////////////////////////////////////////////////////////
+#include "MStatusDisplay.h"
+
+#include <fstream>                // fstream
+
+#include <TLine.h>                // TLine
+#include <TText.h>                // TText
+#include <TFile.h>                // gFile
+#include <TFrame.h>               // TFrame
+#include <TStyle.h>               // gStyle
+#include <TCanvas.h>              // TCanvas
+#include <TSystem.h>              // gSystem
+#include <TDatime.h>              // TDatime
+#include <TRandom.h>              // TRandom
+#include <TThread.h>              // TThread::Self()
+#include <TBrowser.h>             // TBrowser
+#include <TObjArray.h>            // TObjArray
+#include <TPostScript.h>          // TPostScript
+#include <TMethodCall.h>          // TMethodCall
+
+//#include <TRint.h>                // gApplication, TRint::Class()
+#include <TInterpreter.h>         // gInterpreter
+
+#include <TGTab.h>                // TGTab
+#include <TGLabel.h>              // TGLabel
+#include <TG3DLine.h>             // TGHorizontal3DLine
+#include <TGButton.h>             // TGPictureButton
+#include <TGTextView.h>           // TGTextView
+#include <TGStatusBar.h>          // TGStatusBar
+#include <TGProgressBar.h>        // TGHProgressBar
+
+#include <TRootEmbeddedCanvas.h>  // TRootEmbeddedCanvas
+
+#include "MLog.h"                 // MLog
+#include "MLogManip.h"            // inf, warn, err
+
+#include "MGList.h"               // MGList
+#include "MGMenu.h"               // MGMenu, TGMenu
+#include "MSearch.h"              // MSearch
+#include "MParContainer.h"        // MParContainer::GetDescriptor
+
+#undef DEBUG
+//#define DEBUG
+
+ClassImp(MStatusDisplay);
+
+using namespace std;
+
+// ------------ Workaround for a non working TGTextView::Search -------------
+#if ROOT_VERSION_CODE < ROOT_VERSION(3,02,05)
+class MGTextView : public TGTextView
+{
+public:
+    MGTextView(const TGWindow *parent, UInt_t w, UInt_t h, Int_t id = -1,
+               UInt_t sboptions = 0, ULong_t back = GetWhitePixel()) :
+    TGTextView(parent, w, h, id, sboptions, back) {}
+    MGTextView(const TGWindow *parent, UInt_t w, UInt_t h, TGText *text,
+               Int_t id = -1, UInt_t sboptions = 0, ULong_t back = GetWhitePixel()) :
+    TGTextView(parent, w, h, text, id, sboptions, back) {}
+    MGTextView(const TGWindow *parent, UInt_t w, UInt_t h, const char *string,
+               Int_t id = -1, UInt_t sboptions = 0, ULong_t back = GetWhitePixel()) :
+    TGTextView(parent, w, h, string, id, sboptions, back) {}
+
+    void Mark(Long_t xPos, Long_t yPos) { TGTextView::Mark(xPos, yPos); }
+    void UnMark()                       { TGTextView::UnMark(); }
+
+    Bool_t Search(const char *string, Bool_t direction, Bool_t caseSensitive)
+    {
+        // Taken from TGTextView::Search and modified.
+
+        TGLongPosition pos, pos2;
+        pos2.fX = pos2.fY = 0;
+        if (fIsMarked) {
+            if (!direction)
+            {
+                pos2.fX = fMarkedStart.fX;
+                pos2.fY = fMarkedStart.fY;
+            }
+            else
+            {
+                pos2.fX = fMarkedEnd.fX + 1;
+                pos2.fY = fMarkedEnd.fY;
+            }
+        }
+        if (!fText->Search(&pos, pos2, string, direction, caseSensitive))
+            return kFALSE;
+        UnMark();
+        fIsMarked = kTRUE;
+        fMarkedStart.fY = fMarkedEnd.fY = pos.fY;
+        fMarkedStart.fX = pos.fX;
+        fMarkedEnd.fX = fMarkedStart.fX + strlen(string);
+        pos.fY = ToObjYCoord(fVisible.fY);
+        if ((fMarkedStart.fY < pos.fY) ||
+            (ToScrYCoord(fMarkedStart.fY) >= (Int_t)fCanvas->GetHeight()))
+            pos.fY = fMarkedStart.fY;
+        pos.fX = ToObjXCoord(fVisible.fX, pos.fY);
+        if ((fMarkedStart.fX < pos.fX) ||
+            (ToScrXCoord(fMarkedStart.fX, pos.fY) >= (Int_t)fCanvas->GetWidth()))
+            pos.fX = fMarkedStart.fX;
+
+        SetVsbPosition((ToScrYCoord(pos.fY) + fVisible.fY)/fScrollVal.fY);
+        SetHsbPosition((ToScrXCoord(pos.fX, pos.fY) + fVisible.fX)/fScrollVal.fX);
+        DrawRegion(0, (Int_t)ToScrYCoord(fMarkedStart.fY), fCanvas->GetWidth(),
+                   UInt_t(ToScrYCoord(fMarkedEnd.fY+1) - ToScrYCoord(fMarkedEnd.fY)));
+
+        return kTRUE;
+    }
+};
+#else
+#define MGTextView TGTextView
+#endif
+// --------------------------------------------------------------------------
+
+// --------------------------------------------------------------------------
+//
+// Add menu bar to the GUI
+//
+void MStatusDisplay::AddMenuBar()
+{
+    //
+    // File Menu
+    //
+    MGPopupMenu *filemenu = new MGPopupMenu(gClient->GetRoot());
+    // filemenu->AddEntry("Save &As...", kFileSaveAs);
+    filemenu->AddEntry("New Can&vas",   kFileCanvas);
+    filemenu->AddEntry("New &Browser",  kFileBrowser);
+    filemenu->AddSeparator();
+    filemenu->AddEntry("Save As status.&ps",   kFileSaveAsPS);
+    filemenu->AddEntry("Save As status.&gif",  kFileSaveAsGIF);
+    filemenu->AddEntry("Save As status.&C",    kFileSaveAsC);
+    filemenu->AddEntry("Save As status.&root", kFileSaveAsRoot);
+    filemenu->AddSeparator();
+    filemenu->AddEntry("Re&set",               kFileReset);
+    filemenu->AddSeparator();
+    filemenu->AddEntry("Print with &lpr",      kFilePrint);
+    //filemenu->AddEntry("Set printer &name",    kFilePrinterName);
+    filemenu->AddSeparator();
+    filemenu->AddEntry("C&lose", kFileClose);
+    filemenu->AddEntry("E&xit", kFileExit);
+    filemenu->Associate(this);
+
+    //
+    // Tab Menu
+    //
+    MGPopupMenu *tabmenu = new MGPopupMenu(gClient->GetRoot());
+    // tabmenu->AddEntry("Save &As...", kFileSaveAs);
+    tabmenu->AddEntry("Next [&+]",           kTabNext);
+    tabmenu->AddEntry("Previous [&-]",       kTabPrevious);
+    tabmenu->AddSeparator();
+    tabmenu->AddEntry("Save As tab-i.&ps",   kTabSaveAsPS);
+    tabmenu->AddEntry("Save As tab-i.&gif",  kTabSaveAsGIF);
+    tabmenu->AddEntry("Save As tab-i.&C",    kTabSaveAsC);
+    tabmenu->AddEntry("Save As tab-i.&root", kTabSaveAsRoot);
+    tabmenu->AddSeparator();
+    tabmenu->AddEntry("Re&move",             kTabRemove);
+    tabmenu->AddSeparator();
+    tabmenu->AddEntry("Print with &lpr",     kFilePrint);
+    tabmenu->Associate(this);
+
+    //
+    // Loop Menu
+    //
+    MGPopupMenu *loopmenu = new MGPopupMenu(gClient->GetRoot());
+    loopmenu->AddEntry("&Stop", kLoopStop);
+    loopmenu->Associate(this);
+
+    //
+    // Loop Menu
+    //
+    MGPopupMenu *sizemenu = new MGPopupMenu(gClient->GetRoot());
+    sizemenu->AddEntry("Fit to 640x&480",   kSize640);
+    sizemenu->AddEntry("Fit to 800x&600",   kSize800);
+    sizemenu->AddEntry("Fit to 960x7&20",   kSize960);
+    sizemenu->AddEntry("Fit to 1024x&768",  kSize1024);
+    sizemenu->AddEntry("Fit to 1280x&1024", kSize1280);
+    sizemenu->Associate(this);
+
+    //
+    // Log Menu
+    //
+    MGPopupMenu *logmenu = new MGPopupMenu(gClient->GetRoot());
+    logmenu->AddEntry("&Copy Selected", kLogCopy);
+    logmenu->AddEntry("Cl&ear all",     kLogClear);
+    logmenu->AddSeparator();
+    logmenu->AddEntry("Select &All",    kLogSelect);
+    logmenu->AddSeparator();
+    logmenu->AddEntry("&Find...",       kLogFind);
+    logmenu->AddSeparator();
+    logmenu->AddEntry("&Save",          kLogSave);
+    logmenu->AddEntry("Save &append",   kLogAppend);
+    logmenu->Associate(this);
+
+    //
+    // Menu Bar
+    //
+    TGLayoutHints *layitem = new TGLayoutHints(kLHintsNormal, 0, 4, 0, 0);
+    fList->Add(layitem);
+
+    MGMenuBar *menubar = new MGMenuBar(this, 1, 1, kHorizontalFrame);
+    menubar->AddPopup("&File", filemenu, layitem);
+    menubar->AddPopup("Lo&g",  logmenu,  layitem);
+    menubar->AddPopup("&Size", sizemenu, layitem);
+    menubar->AddPopup("&Tab",  tabmenu,  layitem);
+    menubar->AddPopup("&Loop", loopmenu, layitem);
+    menubar->BindKeys(this);
+    AddFrame(menubar);
+
+    //
+    // Line below menu bar
+    //
+    TGLayoutHints *laylinesep  = new TGLayoutHints(kLHintsTop|kLHintsExpandX);
+    fList->Add(laylinesep);
+
+    TGHorizontal3DLine *linesep = new TGHorizontal3DLine(this);
+    AddFrame(linesep, laylinesep);
+
+    //
+    // Add everything to autodel list
+    //
+    fList->Add(filemenu);
+    fList->Add(loopmenu);
+    fList->Add(sizemenu);
+    fList->Add(menubar);
+    fList->Add(tabmenu);
+    fList->Add(logmenu);
+    fList->Add(linesep);
+}
+
+// --------------------------------------------------------------------------
+//
+// Adds an empty TGCompositeFrame which might be filled by the user
+//
+void MStatusDisplay::AddUserFrame()
+{
+    TGLayoutHints *lay=new TGLayoutHints(kLHintsExpandX);
+    fList->Add(lay);
+
+    fUserFrame = new TGCompositeFrame(this, 1, 1);
+    AddFrame(fUserFrame, lay);
+    fList->Add(fUserFrame);
+}
+
+// --------------------------------------------------------------------------
+//
+// Add the title tab
+//
+void MStatusDisplay::AddMarsTab()
+{
+    // Create Tab1
+    TGCompositeFrame *f = fTab->AddTab("-=MARS=-");
+
+    // Add MARS version
+    TGLabel *l = new TGLabel(f, Form("Official Release: V%s", MARSVER));
+    fList->Add(l);
+
+    TGLayoutHints *layb = new TGLayoutHints(kLHintsCenterX|kLHintsTop, 10, 10, 5, 5);
+    fList->Add(layb);
+    f->AddFrame(l, layb);
+
+    // Add root version
+    l = new TGLabel(f, Form("Using ROOT v%s", ROOTVER));
+    fList->Add(l);
+
+    TGLayoutHints *lay = new TGLayoutHints(kLHintsCenterX|kLHintsTop);
+    fList->Add(lay);
+    f->AddFrame(l, lay);
+
+    // Add Mars logo picture
+    const TGPicture *pic2 = fList->GetPicture("marslogo.xpm");
+    if (pic2)
+    {
+        TGPictureButton *mars  = new TGPictureButton(f, pic2, kPicMars);
+        fList->Add(mars);
+        mars->Associate(this);
+
+        TGLayoutHints *lay2 = new TGLayoutHints(kLHintsCenterX|kLHintsCenterY, 10, 10, 5, 5);
+        fList->Add(lay2);
+        f->AddFrame(mars, lay2);
+    }
+
+    // Add date and time
+    TDatime d;
+    l = new TGLabel(f, d.AsString());
+    fList->Add(l);
+    f->AddFrame(l, lay);
+
+    // Add copyright notice
+    l = new TGLabel(f, "(c) MAGIC Software Development, 2000-2003");
+    fList->Add(l);
+    f->AddFrame(l, layb);
+
+    TGLayoutHints *layc = new TGLayoutHints(kLHintsCenterX|kLHintsTop, 10, 10, 0, 5);
+    fList->Add(layc);
+
+    l = new TGLabel(f, "<< Thomas Bretz >>");
+    fList->Add(l);
+    f->AddFrame(l, layc);
+}
+
+// --------------------------------------------------------------------------
+//
+// Adds the logbook tab to the GUI if it was not added previously.
+//
+// The logbook is updated four times a second only if the tab is visible.
+//
+// You can redirect an output to a MLog-logstream by calling SetLogStream().
+// To disable redirction call SetLogStream(NULL)
+//
+// if enable==kFALSE the stdout is disabled/enabled. Otherwise stdout
+// is ignored.
+//
+void MStatusDisplay::SetLogStream(MLog *log, Bool_t enable)
+{
+    if (gROOT->IsBatch())
+        return;
+
+    if (log && fLogBox==NULL)
+    {
+        fLogIdx = fTab->GetNumberOfTabs();
+
+        // Create Tab1
+        TGCompositeFrame *f = fTab->AddTab("-Logbook-");
+
+        // Create Text View
+        fLogBox = new MGTextView(f, 1, 1); // , -1, 0, TGFrame::GetDefaultFrameBackground());
+        if (fFont)
+            fLogBox->SetFont(fFont);
+        //fLogBox->Associate(this);
+
+        // Add List box to the tab
+        TGLayoutHints *lay = new TGLayoutHints(kLHintsNormal|kLHintsExpandX|kLHintsExpandY,2,2,2,2);
+        f->AddFrame(fLogBox, lay);
+
+        // layout and map tab
+        Layout();
+        MapSubwindows();
+
+        // make it visible
+        // FIXME: This is a workaround, because TApplication::Run is not
+        //        thread safe against ProcessEvents. We assume, that if
+        //        we are not in the Main-Thread ProcessEvents() is
+        //        called by the TApplication Event Loop...
+        if (!TThread::Self()/*gApplication->InheritsFrom(TRint::Class())*/)
+            gClient->ProcessEventsFor(fTab);
+    }
+
+    if (log)
+    {
+        fLog = log;
+
+        log->SetOutputGui(fLogBox, kTRUE);
+        log->EnableOutputDevice(MLog::eGui);
+        if (!enable)
+            log->DisableOutputDevice(MLog::eStdout);
+
+        fLogTimer.Start();
+    }
+    else
+    {
+        fLogTimer.Stop();
+
+        fLog->DisableOutputDevice(MLog::eGui);
+        fLog->SetOutputGui(NULL);
+        if (!enable)
+            fLog->EnableOutputDevice(MLog::eStdout);
+
+        fLog = &gLog;
+    }
+}
+
+// --------------------------------------------------------------------------
+//
+// Add the Tabs and the predifined Tabs to the GUI
+//
+void MStatusDisplay::AddTabs()
+{
+    fTab = new TGTab(this, 300, 300);
+
+    AddMarsTab();
+
+    // Add fTab to Frame
+    TGLayoutHints *laytabs = new TGLayoutHints(kLHintsNormal|kLHintsExpandX|kLHintsExpandY, 5, 5, 5);
+    AddFrame(fTab, laytabs);
+
+    fList->Add(fTab);
+    fList->Add(laytabs);
+}
+
+// --------------------------------------------------------------------------
+//
+// Add the progress bar to the GUI. The Progress Bar range is set to
+// (0,1) as default.
+//
+void MStatusDisplay::AddProgressBar()
+{
+    TGLayoutHints *laybar=new TGLayoutHints(kLHintsExpandX, 5, 5, 5, 5);
+    fList->Add(laybar);
+
+    fBar=new TGHProgressBar(this);
+    fBar->SetRange(0, 1);
+    fBar->ShowPosition();
+    AddFrame(fBar, laybar);
+    fList->Add(fBar);
+}
+
+// --------------------------------------------------------------------------
+//
+// Set the progress bar position between 0 and 1. The Progress bar range
+// is assumed to be (0,1)
+//
+void MStatusDisplay::SetProgressBarPosition(Float_t p)
+{
+    fBar->SetPosition(p);
+}
+
+// --------------------------------------------------------------------------
+//
+// Adds the status bar to the GUI
+//
+void MStatusDisplay::AddStatusBar()
+{
+    fStatusBar = new TGStatusBar(this, 1, 1);
+
+    //
+    // Divide it like the 'Golden Cut' (goldener Schnitt)
+    //
+    //     1-a     a
+    // 1: ------|----
+    //
+    // a/(1-a) = (1-a)/1
+    // a^2+a-1 = 0
+    //       a = (-1+-sqrt(1+4))/2 = sqrt(5)/2-1/2 = 0.618
+    //
+    Int_t p[2] = {38, 62};
+
+    fStatusBar->SetParts(p, 2);
+
+    TGLayoutHints *layb = new TGLayoutHints(kLHintsNormal|kLHintsExpandX, 5, 4, 0, 3);
+    AddFrame(fStatusBar, layb);
+
+    fList->Add(fStatusBar);
+    fList->Add(layb);
+}
+
+// --------------------------------------------------------------------------
+//
+// Change the text in the status line 1
+//
+void MStatusDisplay::SetStatusLine1(const char *txt)
+{
+    if (gROOT->IsBatch())
+        return;
+    fStatusBar->SetText(txt, 0);
+
+    // FIXME: This is a workaround, because TApplication::Run is not
+    //        thread safe against ProcessEvents. We assume, that if
+    //        we are not in the Main-Thread ProcessEvents() is
+    //        called by the TApplication Event Loop...
+    if (!TThread::Self()/*gApplication->InheritsFrom(TRint::Class())*/)
+        gClient->ProcessEventsFor(fStatusBar);
+}
+
+// --------------------------------------------------------------------------
+//
+// Change the text in the status line 2
+//
+void MStatusDisplay::SetStatusLine2(const char *txt)
+{
+    if (gROOT->IsBatch())
+        return;
+    fStatusBar->SetText(txt, 1);
+
+    // FIXME: This is a workaround, because TApplication::Run is not
+    //        thread safe against ProcessEvents. We assume, that if
+    //        we are not in the Main-Thread ProcessEvents() is
+    //        called by the TApplication Event Loop...
+    if (!TThread::Self()/*gApplication->InheritsFrom(TRint::Class())*/)
+        gClient->ProcessEventsFor(fStatusBar);
+}
+
+// --------------------------------------------------------------------------
+//
+// Display information about the name of a container
+//
+void MStatusDisplay::SetStatusLine2(const MParContainer &cont)
+{
+    SetStatusLine2(Form("%s: %s", cont.GetDescriptor(), cont.GetTitle()));
+}
+
+// --------------------------------------------------------------------------
+//
+// Default constructor. Opens a window with a progress bar. Get a pointer
+// to the bar by calling GetBar. This pointer can be used for the
+// eventloop.
+//
+// Be carefull: killing or closing the window while the progress meter
+//   is still in use may cause segmentation faults. Please kill the window
+//   always by deleting the corresponding object.
+//
+// Update time default: 10s
+//
+MStatusDisplay::MStatusDisplay(Long_t t)
+: TGMainFrame(gClient ? gClient->GetRoot() : NULL, 1, 1), fTab(NULL), fTimer(this, t, kTRUE), fStatus(kLoopNone), fLog(&gLog), fLogIdx(-1), fLogTimer(this, 250, kTRUE), fLogBox(NULL), fIsLocked(0)
+{
+    //
+    // This is a possibility for the user to check whether this
+    // object has already been deleted. It will be removed
+    // from the list in the destructor.
+    //
+    gROOT->GetListOfSpecials()->Add(this);
+
+    fFont = gVirtualX->LoadQueryFont("7x13bold");
+    fMutex = new TMutex;
+
+    //
+    // In case we are in batch mode use a list of canvases
+    // instead of the Root Embedded Canvases in the TGTab
+    //
+    fBatch = new TList;
+    fBatch->SetOwner();
+
+    //
+    // Create a list handling GUI widgets
+    //
+    fList = new MGList;
+    fList->SetOwner();
+
+    //
+    // set the smallest and biggest size of the Main frame
+    // and move it to its appearance position
+    SetWMSizeHints(570, 480, 1280, 980, 1, 1);
+    Move(rand()%100+50, rand()%100+50);
+    Resize(570, 480);
+
+    //
+    // Create the layout hint for the root embedded canavses
+    //
+    fLayCanvas = new TGLayoutHints(kLHintsExpandX|kLHintsExpandY);
+    fList->Add(fLayCanvas);
+
+    //
+    // Add Widgets (from top to bottom)
+    //
+    if (gClient) // BATCH MODE
+    {
+        AddMenuBar();
+        AddUserFrame();
+        AddTabs();
+        AddProgressBar();
+        AddStatusBar();
+    }
+
+    //
+    // Now do an automatic layout of the widgets and display the window
+    //
+    Layout();
+    MapSubwindows();
+
+    SetWindowName("Status Display");
+    SetIconName("Status Display");
+
+    MapWindow();
+
+    // FIXME: This is a workaround, because TApplication::Run is not
+    //        thread safe against ProcessEvents. We assume, that if
+    //        we are not in the Main-Thread ProcessEvents() is
+    //        called by the TApplication Event Loop...
+    if (!TThread::Self()/*gApplication->InheritsFrom(TRint::Class())*/)
+        gSystem->ProcessEvents();
+}
+
+// --------------------------------------------------------------------------
+//
+// Destruct the window with all its tiles. Also the Progress Bar object
+// is deleted.
+//
+MStatusDisplay::~MStatusDisplay()
+{
+#if ROOT_VERSION_CODE < ROOT_VERSION(3,10,01)
+    fTab = NULL; // See HandleEvent
+#endif
+
+    //
+    // Delete object from global object table so it cannot
+    // be deleted by chance a second time
+    //
+    gInterpreter->DeleteGlobal(this);
+
+    //
+    // This is a possibility for the user to check whether this
+    // object has already been deleted. It has been added
+    // to the list in the constructor.
+    //
+    gROOT->GetListOfSpecials()->Remove(this);
+
+    SetLogStream(NULL);
+
+    //
+    // Delete the list of objects corresponding to this object
+    //
+    delete fList;
+
+    //
+    // Delete the list list of canvases used in batch mode
+    // instead of the Root Embedded Canvases in the TGTab
+    //
+    delete fBatch;
+
+    //
+    // Delete the font used for the logging window
+    //
+    if (fFont)
+        gVirtualX->DeleteFont(fFont);
+
+    //
+    // Delete mutex
+    //
+    delete fMutex;
+}
+
+// --------------------------------------------------------------------------
+//
+// Takes a TGCompositeFrame as argument. Searches for the first
+// TRootEmbeddedCanvas which is contained by it and returns a pointer
+// to the corresponding TCanvas. If it isn't found NULL is returned.
+//
+TRootEmbeddedCanvas *MStatusDisplay::GetEmbeddedCanvas(TGCompositeFrame *cf) const
+{
+    TIter Next(cf->GetList());
+
+    TGFrameElement *f;
+    while ((f=(TGFrameElement*)Next()))
+        if (f->fFrame->InheritsFrom(TRootEmbeddedCanvas::Class()))
+            return (TRootEmbeddedCanvas*)f->fFrame;
+
+    return NULL;
+}
+
+// --------------------------------------------------------------------------
+//
+// Takes a TGCompositeFrame as argument. Searches for the first
+// TRootEmbeddedCanvas which is contained by it and returns a pointer
+// to the corresponding TCanvas. If it isn't found NULL is returned.
+//
+TCanvas *MStatusDisplay::GetCanvas(TGCompositeFrame *cf) const
+{
+    TRootEmbeddedCanvas *ec = GetEmbeddedCanvas(cf);
+    return ec ? ec->GetCanvas() : NULL;
+}
+
+// --------------------------------------------------------------------------
+//
+// Returns GetCanvas of the i-th Tab.
+//
+TCanvas *MStatusDisplay::GetCanvas(int i) const
+{
+    if (gROOT->IsBatch())
+        return (TCanvas*)fBatch->At(i-1);
+
+    if (i<0 || i>=fTab->GetNumberOfTabs())
+    {
+        *fLog << warn << "MStatusDisplay::GetCanvas: Out of range." << endl;
+        return NULL;
+    }
+
+    return GetCanvas(fTab->GetTabContainer(i));
+}
+
+// --------------------------------------------------------------------------
+//
+// Searches for a TRootEmbeddedCanvas in the TGCompositeFramme of the
+// Tab with the name 'name'. Returns the corresponding TCanvas or
+// NULL if something isn't found.
+//
+TCanvas *MStatusDisplay::GetCanvas(const TString &name) const
+{
+    TGFrameElement *f;
+    TIter Next(fTab->GetList());
+    while ((f=(TGFrameElement*)Next()))
+    {
+        TObject *frame = f->fFrame;
+        if (!frame->InheritsFrom(TGTabElement::Class()))
+            continue;
+
+        TGTabElement *tab = (TGTabElement*)frame;
+        if (tab->GetString()==name)
+            break;
+    }
+
+    // Search for the next TGCompositeFrame in the list
+    while ((f=(TGFrameElement*)Next()))
+    {
+        TObject *frame = f->fFrame;
+        if (frame->InheritsFrom(TGCompositeFrame::Class()))
+            return GetCanvas((TGCompositeFrame*)frame);
+    }
+
+    return NULL;
+}
+
+// --------------------------------------------------------------------------
+//
+// Calls TCanvas::cd(), for the canvas returned by GetCanvas.
+//
+Bool_t MStatusDisplay::CdCanvas(const TString &name)
+{
+    TCanvas *c = GetCanvas(name);
+    if (!c)
+        return kFALSE;
+
+    c->cd();
+    return kTRUE;
+}
+
+TGCompositeFrame *MStatusDisplay::AddRawTab(const char *name)
+{
+    // Add new tab
+    TGCompositeFrame *f = fTab->AddTab(name);
+
+    // layout and map new tab
+    Layout();
+    MapSubwindows();
+    Layout();
+
+    // display new tab in the main frame
+    // FIXME: This is a workaround, because TApplication::Run is not
+    //        thread safe against ProcessEvents. We assume, that if
+    //        we are not in the Main-Thread ProcessEvents() is
+    //        called by the TApplication Event Loop...
+    if (!TThread::Self()/*gApplication->InheritsFrom(TRint::Class())*/)
+        gClient->ProcessEventsFor(fTab);
+
+    *fLog << inf << "Adding Raw Tab '" << name << "' (" << f->GetWidth() << "x";
+    *fLog << f->GetHeight() << ")" << endl;
+
+    // return pointer to new canvas
+    return f;
+}
+
+// --------------------------------------------------------------------------
+//
+// Adds a new tab with the name 'name'. Adds a TRootEmbeddedCanvas to the
+// tab and returns a reference to the corresponding TCanvas.
+//
+TCanvas &MStatusDisplay::AddTab(const char *name)
+{
+    if (gROOT->IsBatch())
+    {
+        TCanvas *c = new TCanvas(name, name);
+        fBatch->Add(c);
+        return *c;
+    }
+
+    // Add new tab
+    TGCompositeFrame *f = fTab->AddTab(name);
+
+    // create root embedded canvas and add it to the tab
+    TRootEmbeddedCanvas *ec = new TRootEmbeddedCanvas(name, f, f->GetWidth(), f->GetHeight(), 0);
+    f->AddFrame(ec, fLayCanvas);
+    fList->Add(ec);
+
+    // set background and border mode of the canvas
+    TCanvas &c = *ec->GetCanvas();
+
+    c.SetFillColor(16/*165*//*17*//*203*/);
+    c.SetBorderMode(0);
+
+    // If kNoContextMenu set set kNoContextMenu of the canvas
+    if (TestBit(kNoContextMenu))
+        c.SetBit(kNoContextMenu);
+
+    // layout and map new tab
+    Layout();          // seems to layout the TGCompositeFrame
+    MapSubwindows();   // maps the TGCompositeFrame
+    Layout();          // layout the embedded canvas in the frame
+
+    // display new tab in the main frame
+    // FIXME: This is a workaround, because TApplication::Run is not
+    //        thread safe against ProcessEvents. We assume, that if
+    //        we are not in the Main-Thread ProcessEvents() is
+    //        called by the TApplication Event Loop...
+    if (!TThread::Self()/*gApplication->InheritsFrom(TRint::Class())*/)
+        gClient->ProcessEventsFor(fTab);
+
+    *fLog << inf << "Adding Tab '" << name << "' (" << f->GetWidth() << "x";
+    *fLog << f->GetHeight() << ", TCanvas=" << &c << ")" << endl;
+
+    // return pointer to new canvas
+    return c;
+}
+
+// --------------------------------------------------------------------------
+//
+// Update a canvas in a tab, takes the corresponding TGCompositeFrame
+// as an argument. This is necessary, because not all functions
+// changing the contents of a canvas or pad can call SetModified()
+// for the corresponding tab. If this is not called correctly the
+// tab won't be updated calling TCanvas::Update(). So we simply
+// redraw it by our own (instead we could recursively call
+// TPad::Modified() for everything contained by the TCanvas and
+// call TCanvas::Update() afterwards)
+//
+void MStatusDisplay::UpdateTab(TGCompositeFrame *f)
+{
+    if (!f)
+        return;
+
+    TCanvas *c=GetCanvas(f);
+    if (!c)
+        return;
+
+    //
+    // If we are in a multithreaded environment (gThreadXAR) we
+    // have to make sure, that thus function is called from
+    // the main thread.
+    //
+    if (gThreadXAR)
+    {
+        // Tell the X-Requester how to call this method
+        TString str = Form("%d", (ULong_t)f);
+
+        TMethodCall call(IsA(), "UpdateTab", "NULL");
+        void *arr[4] = { NULL, &call, this, (void*)(const char*)str };
+
+        // If this is not the main thread return
+        if (((*gThreadXAR)("METH", 4, arr, NULL)))
+            return;
+    }
+
+    //
+    // Secure calls to update the tabs against itself, at least
+    // c->Paint() or c->Flush() may crash X (bad drawable).
+    // This makes sure, that a X call is not interuppted by
+    // another X-call which was started from an gui interrrupt
+    // in the same thread
+    //
+    if (fMutex->TryLock()==13)
+        return;
+
+#if ROOT_VERSION_CODE < ROOT_VERSION(3,10,02)
+    TPad *padsav = (TPad*)gPad;
+    if (!gPad)
+        c->cd();
+#endif
+
+    if (!c->IsBatch())
+        c->FeedbackMode(kFALSE);  // Goto double buffer mode
+
+    //
+    // Doing this ourself gives us the possibility to repaint
+    // the canvas in any case (Paint() instead of PaintModified())
+    //
+    c->Paint();                   // Repaint all pads
+    c->Flush();                   // Copy all pad pixmaps to the screen
+
+#if ROOT_VERSION_CODE < ROOT_VERSION(3,10,02)
+    if (padsav)
+        padsav->cd();
+    else
+        gPad=NULL;
+#endif
+
+    //c->SetCursor(kCross);
+
+    // Old version
+    //c->Modified();
+    //c->Update();
+    //c->Paint();
+
+    fMutex->UnLock();
+}
+
+// --------------------------------------------------------------------------
+//
+// Saves the given canvas (pad) or all pads (num<0) as a temporary
+// postscript file and prints it using 'lpr'. If a printer name is set
+// via SetPrinter 'lpr -Pname' is used.
+//
+Int_t MStatusDisplay::PrintToLpr(Int_t num)
+{
+    TString name = "mars";
+
+    for (int i=0; i<6; i++)
+        name += (char)(gRandom->Uniform(25)+65);
+
+    name += ".ps";
+
+    const Int_t pages = SaveAsPS(num, name);
+
+    SetStatusLine1("Printing...");
+    SetStatusLine2("");
+
+    if (!pages)
+    {
+        *fLog << warn << "MStatusDisplay::PrintToLpr: Sorry, couldn't save file as temporary postscript!" << endl;
+        SetStatusLine2("Failed!");
+        return 0;
+    }
+
+    TString cmd="lpr ";
+    if (!fPrinter.IsNull())
+    {
+        cmd += "-P";
+        cmd += fPrinter;
+        cmd += " ";
+    }
+    cmd += name;
+
+    gSystem->Exec(cmd);
+    gSystem->Unlink(name);
+
+    SetStatusLine2(Form("Done (%dpages)", pages));
+
+    return pages;
+}
+
+// --------------------------------------------------------------------------
+//
+// Remove tab no i if this tab contains a TRootEmbeddedCanvas
+//
+void MStatusDisplay::RemoveTab(int i)
+{
+    TGCompositeFrame *f = fTab->GetTabContainer(i);
+    if (!f)
+        return;
+
+    TRootEmbeddedCanvas *ec = GetEmbeddedCanvas(f);
+    if (!ec)
+        return;
+
+    TCanvas *c = ec->GetCanvas();
+    if (!c)
+        return;
+
+    const TString name(c->GetName());
+
+    f->RemoveFrame(ec);
+    delete fList->Remove(ec);
+
+    fTab->RemoveTab(i);
+    fTab->SetTab(0);
+
+    // Looks strange...
+    // const Int_t n = fTab->GetNumberOfTabs();
+    // fTab->SetTab(i<=n-1 ? i : i-1);
+
+    // layout and map new tab
+    Layout();          // seems to layout the TGCompositeFrame
+    MapSubwindows();   // maps the TGCompositeFrame
+    Layout();          // layout the embedded canvas in the frame
+
+    // display new tab in the main frame
+    // FIXME: This is a workaround, because TApplication::Run is not
+    //        thread safe against ProcessEvents. We assume, that if
+    //        we are not in the Main-Thread ProcessEvents() is
+    //        called by the TApplication Event Loop...
+    if (!TThread::Self()/*gApplication->InheritsFrom(TRint::Class())*/)
+        gClient->ProcessEventsFor(fTab);
+
+    *fLog << inf << "Removed Tab #" << i << " '" << name << "'" << endl;
+}
+
+// --------------------------------------------------------------------------
+//
+// Use this to check whether the MStatusDisplay still contains the
+// TCanvas c. It could be removed meanwhile by menu usage.
+//
+Bool_t MStatusDisplay::HasCanvas(const TCanvas *c) const
+{
+    if (!c)
+        return kFALSE;
+
+    if (gROOT->IsBatch())
+        return (Bool_t)fBatch->FindObject(c);
+
+    for (int i=1; i<fTab->GetNumberOfTabs(); i++)
+        if (c==GetCanvas(i))
+            return kTRUE;
+    return kFALSE;
+}
+
+/*
+    if (...)
+       fMenu->AddPopup("&CaOs", fCaOs, NULL);
+    else
+       fMenu->RemovePopup("CaOs");
+    fMenu->Resize(fMenu->GetDefaultSize());
+    MapSubwindows();
+    MapWindow();
+ */
+
+// --------------------------------------------------------------------------
+//
+// Process the kC_COMMAND, kCM_MENU  messages
+//
+Bool_t MStatusDisplay::ProcessMessageCommandMenu(Long_t id)
+{
+    switch (id)
+    {
+    case kLoopStop:
+    case kFileClose:
+    case kFileExit:
+        if (id==kFileExit || id==kFileClose)
+            CloseWindow();
+        fStatus = (Status_t)id;
+        return kTRUE;
+
+    case kFileCanvas:
+        new TCanvas;
+        return kTRUE;
+
+    case kFileBrowser:
+        new TBrowser;
+        return kTRUE;
+
+    case kFileReset:
+        for (int i=fTab->GetNumberOfTabs()-1; i>0; i--)
+            RemoveTab(i);
+        return kTRUE;
+        /*
+    case kFileSave:
+        cout << "Save..." << endl;
+        return kTRUE;
+
+    case kFileSaveAs:
+        cout << "SaveAs..." << endl;
+        return kTRUE;
+*/
+    case kFileSaveAsPS:
+        SaveAsPS();
+        return kTRUE;
+
+    case kFileSaveAsGIF:
+        SaveAsGIF();
+        return kTRUE;
+
+    case kFileSaveAsC:
+        SaveAsC();
+        return kTRUE;
+
+    case kFileSaveAsRoot:
+        SaveAsRoot();
+        return kTRUE;
+
+    case kFilePrint:
+        PrintToLpr();
+        return kTRUE;
+
+    case kTabSaveAsPS:
+        SaveAsPS(fTab->GetCurrent());
+        return kTRUE;
+
+    case kTabSaveAsGIF:
+        SaveAsGIF(fTab->GetCurrent());
+        return kTRUE;
+
+    case kTabSaveAsC:
+        SaveAsC(fTab->GetCurrent());
+        return kTRUE;
+
+    case kTabSaveAsRoot:
+        SaveAsRoot(fTab->GetCurrent());
+        return kTRUE;
+
+    case kTabPrint:
+        PrintToLpr(fTab->GetCurrent());
+        return kTRUE;
+
+    case kTabNext:
+        fTab->SetTab(fTab->GetCurrent()+1);
+        return kTRUE;
+
+    case kTabPrevious:
+        fTab->SetTab(fTab->GetCurrent()-1);
+        return kTRUE;
+
+    case kTabRemove:
+        RemoveTab(fTab->GetCurrent());
+        return kTRUE;
+
+    case kSize640:
+        Resize(570, 480);
+        return kTRUE;
+    case kSize800:
+        Resize(740, 600);
+        return kTRUE;
+    case kSize960:
+        Resize(880, 700);
+        return kTRUE;
+    case kSize1024:
+        Resize(980, 768);
+        return kTRUE;
+    case kSize1280:
+        Resize(1280, 980);
+        return kTRUE;
+
+    case kLogClear:
+        fLogBox->Clear();
+        return kTRUE;
+    case kLogCopy:
+        fLogBox->Copy();
+        return kTRUE;
+    case kLogSelect:
+        fLogBox->SelectAll();
+        return kTRUE;
+    case kLogFind:
+        new MSearch(this);
+        return kTRUE;
+    case kLogSave:
+        SetStatusLine1("Saving log...");
+        SetStatusLine2("");
+        *fLog << inf << "Saving log... " << flush;
+        if (fLogBox->GetText()->Save("statusdisplay.log"))
+        {
+            *fLog << "done." << endl;
+            SetStatusLine2("done.");
+        }
+        else
+        {
+            *fLog << "failed!" << endl;
+            SetStatusLine2("Failed!");
+        }
+        return kTRUE;
+
+    case kLogAppend:
+        SetStatusLine1("Appending logg...");
+        SetStatusLine2("");
+        *fLog << inf << "Appending log... " << flush;
+        if (fLogBox->GetText()->Append("statusdisplay.log"))
+        {
+            *fLog << "done." << endl;
+            SetStatusLine2("done.");
+        }
+        else
+        {
+            *fLog << "failed!" << endl;
+            SetStatusLine2("Failed!");
+        }
+        return kTRUE;
+#ifdef DEBUG
+    default:
+        cout << "Command-Menu #" << id << endl;
+#endif
+    }
+    return kTRUE;
+
+}
+
+// --------------------------------------------------------------------------
+//
+// Process the kC_COMMAND messages
+//
+Bool_t MStatusDisplay::ProcessMessageCommand(Long_t submsg, Long_t mp1, Long_t mp2)
+{
+    switch (submsg)
+    {
+    case kCM_MENU:
+        return ProcessMessageCommandMenu(mp1); // mp2=userdata
+    case kCM_TAB:
+        /*
+         for (int i=0; i<fTab->GetNumberOfTabs(); i++)
+         fTab->GetTabContainer(i)->UnmapWindow();
+         */
+        UpdateTab(fTab->GetTabContainer(mp1));
+        //fTab->GetTabContainer(mp1)->MapWindow();
+
+        /*
+        if (mp1>0)
+            fMenu->AddPopup("&CaOs", fCaOs, NULL);
+        else
+            fMenu->RemovePopup("CaOs");
+        fMenu->Resize(fMenu->GetDefaultSize());
+        MapSubwindows();
+        MapWindow();
+        */
+        return kTRUE;
+#ifdef DEBUG
+    case kCM_MENUSELECT:
+        cout << "Command-Menuselect #" << mp1 << " (UserData=" << (void*)mp2 << ")" << endl;
+        return kTRUE;
+
+    case kCM_BUTTON:
+        cout << "Command-Button." << endl;
+        return kTRUE;
+
+    case kCM_CHECKBUTTON:
+        cout << "Command-CheckButton." << endl;
+        return kTRUE;
+
+    case kCM_RADIOBUTTON:
+        cout << "Command-RadioButton." << endl;
+        return kTRUE;
+
+    case kCM_LISTBOX:
+        cout << "Command-Listbox #" << mp1 << " (LineId #" << mp2 << ")" << endl;
+        return kTRUE;
+
+    case kCM_COMBOBOX:
+        cout << "Command-ComboBox." << endl;
+        return kTRUE;
+    default:
+        cout << "Command: " << "Submsg:" << submsg << " Mp1=" << mp1 << " Mp2=" << mp2 << endl;
+#endif
+    }
+    return kTRUE;
+}
+
+// --------------------------------------------------------------------------
+//
+// Process the kC_TEXTVIEW messages
+//
+Bool_t MStatusDisplay::ProcessMessageTextview(Long_t submsg, Long_t mp1, Long_t mp2)
+{
+    // kC_TEXTVIEW, kTXT_ISMARKED, widget id, [true|false]                  //
+    // kC_TEXTVIEW, kTXT_DATACHANGE, widget id, 0                           //
+    // kC_TEXTVIEW, kTXT_CLICK2, widget id, position (y << 16) | x)         //
+    // kC_TEXTVIEW, kTXT_CLICK3, widget id, position (y << 16) | x)         //
+    // kC_TEXTVIEW, kTXT_F3, widget id, true                                //
+    // kC_TEXTVIEW, kTXT_OPEN, widget id, 0                                 //
+    // kC_TEXTVIEW, kTXT_CLOSE, widget id, 0                                //
+    // kC_TEXTVIEW, kTXT_SAVE, widget id, 0                                 //
+#ifdef DEBUG
+    switch (submsg)
+    {
+    case kTXT_ISMARKED:
+        cout << "Textview-IsMarked #" << mp1 << " " << (mp2?"yes":"no") << endl;
+        return kTRUE;
+
+    case kTXT_DATACHANGE:
+        cout << "Textview-DataChange #" << mp1 << endl;
+        return kTRUE;
+
+    case kTXT_CLICK2:
+        cout << "Textview-Click2 #" << mp1 << " x=" << (mp2&0xffff) << " y= " << (mp2>>16) << endl;
+        return kTRUE;
+
+    case kTXT_CLICK3:
+        cout << "Textview-Click3 #" << mp1 << " x=" << (mp2&0xffff) << " y= " << (mp2>>16) << endl;
+        return kTRUE;
+
+    case kTXT_F3:
+        cout << "Textview-F3 #" << mp1 << endl;
+        return kTRUE;
+
+    case kTXT_OPEN:
+        cout << "Textview-Open #" << mp1 << endl;
+        return kTRUE;
+
+    case kTXT_CLOSE:
+        cout << "Textview-Close #" << mp1 << endl;
+        return kTRUE;
+
+    case kTXT_SAVE:
+        cout << "Textview-Save #" << mp1 << endl;
+        return kTRUE;
+
+    default:
+        cout << "Textview: " << "Submsg:" << submsg << " Mp1=" << mp1 << " Mp2=" << mp2 << endl;
+    }
+#endif
+    return kTRUE;
+}
+
+// --------------------------------------------------------------------------
+//
+// Process the kC_USER messages
+//
+Bool_t MStatusDisplay::ProcessMessageUser(Long_t submsg, Long_t mp1, Long_t mp2)
+{
+    // kS_START, case sensitive | backward<<1, char *txt
+    switch (submsg)
+    {
+    case kS_START:
+        fLogBox->Search((char*)mp2, !(mp1&2>>1), mp1&1);
+        return kTRUE;
+#ifdef DEBUG
+    default:
+        cout << "User: " << "Submsg:" << submsg << " Mp1=" << mp1 << " Mp2=" << mp2 << endl;
+#endif
+    }
+    return kTRUE;
+}
+
+// --------------------------------------------------------------------------
+//
+// Process the messages from the GUI
+//
+Bool_t MStatusDisplay::ProcessMessage(Long_t msg, Long_t mp1, Long_t mp2)
+{
+    // Can be found in WidgetMessageTypes.h
+    cout << "Msg: " << GET_MSG(msg) << " Submsg:" << GET_SUBMSG(msg);
+    cout << " Mp1=" << mp1 << " Mp2=" << mp2 << endl;
+    switch (GET_MSG(msg))
+    {
+    case kC_COMMAND:
+        return ProcessMessageCommand(GET_SUBMSG(msg), mp1, mp2);
+
+    case kC_TEXTVIEW:
+        return ProcessMessageTextview(GET_SUBMSG(msg), mp1, mp2);
+
+    case kC_USER:
+        return ProcessMessageUser(GET_SUBMSG(msg), mp1, mp2);
+    }
+#ifdef DEBUG
+    cout << "Msg: " << GET_MSG(msg) << " Submsg:" << GET_SUBMSG(msg);
+    cout << " Mp1=" << mp1 << " Mp2=" << mp2 << endl;
+#endif
+    return kTRUE;
+}
+
+void MStatusDisplay::CloseWindow()
+{
+    // Got close message for this MainFrame. Calls parent CloseWindow()
+    // (which destroys the window) and terminate the application.
+    // The close message is generated by the window manager when its close
+    // window menu item is selected.
+
+    // CloseWindow must be overwritten because otherwise CloseWindow
+    // and the destructor are calling DestroyWindow which seems to be
+    // in conflict with the TRootEmbeddedCanvas.
+
+    // FIXME: Make sure that the Status Display is deleted from every
+    //        where (eg Eventloop) first!
+
+    gLog << dbg << "MStatusDisplay is on heap: " << (int)IsOnHeap() << endl;
+
+    if (fIsLocked<=0 && IsOnHeap())
+        delete this;
+    fStatus = kFileExit;
+}
+
+// --------------------------------------------------------------------------
+//
+// Calls SetBit(kNoContextMenu) for all TCanvas objects found in the
+// Tabs.
+//
+void MStatusDisplay::SetNoContextMenu(Bool_t flag)
+{
+    if (fIsLocked>1 || gROOT->IsBatch())
+        return;
+
+    flag ? SetBit(kNoContextMenu) : ResetBit(kNoContextMenu);
+
+    for (int i=1; i<fTab->GetNumberOfTabs(); i++)
+    {
+        TCanvas *c = GetCanvas(i);
+        if (c)
+            flag ? c->SetBit(kNoContextMenu) : c->ResetBit(kNoContextMenu);
+    }
+}
+
+// --------------------------------------------------------------------------
+//
+// Updates the canvas (if existing) in the currenly displayed Tab.
+// The update intervall is controlled by StartUpdate and StopUpdate
+//
+Bool_t MStatusDisplay::HandleTimer(TTimer *timer)
+{
+    if (gROOT->IsBatch())
+        return kTRUE;
+
+    const Int_t c = fTab->GetCurrent();
+
+    // Skip Legend Tab
+    if (c==0)
+        return kTRUE;
+
+    // Update a canvas tab (if visible)
+    if (timer==&fTimer && c!=fLogIdx)
+    {
+        UpdateTab(fTab->GetCurrentContainer());
+        return kTRUE;
+    }
+
+    // update the logbook tab (if visible)
+    if (timer==&fLogTimer && c==fLogIdx)
+    {
+        fLog->UpdateGui();
+
+        /*
+        if (!fLogBox->TestBit(kHasChanged))
+            return kTRUE;
+
+            fLogBox->ResetBit(kHasChanged);
+            */
+        return kTRUE;
+    }
+
+    return kTRUE;
+}
+
+// --------------------------------------------------------------------------
+//
+// Draws a clone of a canvas into a new canvas. Taken from TCanvas.
+//
+void MStatusDisplay::DrawClonePad(TCanvas &newc, const TCanvas &oldc) const
+{
+    //copy pad attributes
+    newc.Range(oldc.GetX1(),oldc.GetY1(),oldc.GetX2(),oldc.GetY2());
+    newc.SetTickx(oldc.GetTickx());
+    newc.SetTicky(oldc.GetTicky());
+    newc.SetGridx(oldc.GetGridx());
+    newc.SetGridy(oldc.GetGridy());
+    newc.SetLogx(oldc.GetLogx());
+    newc.SetLogy(oldc.GetLogy());
+    newc.SetLogz(oldc.GetLogz());
+    newc.SetBorderSize(oldc.GetBorderSize());
+    newc.SetBorderMode(oldc.GetBorderMode());
+    ((TAttLine&)oldc).Copy((TAttLine&)newc);
+    ((TAttFill&)oldc).Copy((TAttFill&)newc);
+    ((TAttPad&)oldc).Copy((TAttPad&)newc);
+
+    //copy primitives
+    TObject *obj;
+    TIter next(oldc.GetListOfPrimitives());
+    while ((obj=next())) {
+        gROOT->SetSelectedPad(&newc);
+        newc.GetListOfPrimitives()->Add(obj->Clone(),obj->GetDrawOption());
+    }
+    newc.Modified();
+    newc.Update();
+}
+
+// --------------------------------------------------------------------------
+//
+// Reads the contents of a saved MStatusDisplay from a file.
+//
+Int_t MStatusDisplay::Read(const char *name)
+{
+    if (!gFile)
+    {
+        *fLog << warn << "MStatusDisplay::Read: No file found. Please create a TFile first." << endl;
+        return 0;
+    }
+
+    if (!gFile->IsOpen())
+    {
+        *fLog << warn << "MStatusDisplay::Read: File not open. Please open the TFile first." << endl;
+        return 0;
+    }
+
+    TObjArray list;
+
+    const Int_t n = list.Read(name);
+    if (n==0)
+    {
+        *fLog << warn << "MStatusDisplay::Read: No objects read." << endl;
+        return 0;
+    }
+
+    TIter Next(&list);
+    TCanvas *c;
+    while ((c=(TCanvas*)Next()))
+        DrawClonePad(AddTab(c->GetName()), *c);
+
+    *fLog << inf << "MStatusDisplay: Key " << name << " with " << n << " keys read from file." << endl;
+
+    return n;
+}
+
+// --------------------------------------------------------------------------
+//
+// Writes the contents of a MStatusDisplay to a file.
+//
+Int_t MStatusDisplay::Write(Int_t num, const char *name, Int_t option, Int_t bufsize)
+{
+    if (!gFile)
+    {
+        *fLog << warn << "MStatusDisplay::Write: No file found. Please create a TFile first." << endl;
+        return 0;
+    }
+
+    if (!gFile->IsOpen())
+    {
+        *fLog << warn << "MStatusDisplay::Write: File not open. Please open the TFile first." << endl;
+        return 0;
+    }
+
+    if (!gFile->IsWritable())
+    {
+        *fLog << warn << "MStatusDisplay::Write: File not writable." << endl;
+        return 0;
+    }
+
+    if (num==0)
+    {
+        *fLog << warn << "MStatusDisplay::Write: Tab doesn't contain an embedded Canvas... skipped." << endl;
+        return 0;
+    }
+
+    if (!gROOT->IsBatch() && num>=fTab->GetNumberOfTabs())
+    {
+        *fLog << warn << "MStatusDisplay::Write: Tab doesn't exist... skipped." << endl;
+        return 0;
+    }
+    if (gROOT->IsBatch() && num>fBatch->GetSize())
+    {
+        *fLog << warn << "MStatusDisplay::Write: Tab doesn't exist... skipped." << endl;
+        return 0;
+    }
+
+    TObjArray list;
+
+    const Int_t max  = gROOT->IsBatch() ? fBatch->GetSize()+1 : fTab->GetNumberOfTabs();
+    const Int_t from = num<0 ?   1 : num;
+    const Int_t to   = num<0 ? max : num+1;
+
+    TCanvas *c;
+    for (int i=from; i<to; i++)
+        if ((c = GetCanvas(i)))
+            list.Add(c);
+
+    const Int_t n = list.Write(name, kSingleKey);
+
+    *fLog << inf << "MStatusDisplay: " << n << " keys written to file as key " << name << "." << endl;
+
+    return n;
+}
+
+// --------------------------------------------------------------------------
+//
+// Use this to start the synchronous (GUI eventloop driven) tab update.
+// Can also be used to change the update intervall. If millisec<0
+// the intervall given in SetUpdateTime is used. If the intervall in
+// SetUpdateTime is <0 nothing is done. (Call SetUpdateTime(-1) to
+// disable the automatic update in a MEventloop.
+//
+void MStatusDisplay::StartUpdate(Int_t millisec)
+{
+    if (fIsLocked>1)
+        return;
+
+    if (fTimer.GetTime()<TTime(0))
+        return;
+    fTimer.Start(millisec);
+}
+
+// --------------------------------------------------------------------------
+//
+// Stops the automatic GUI update
+//
+void MStatusDisplay::StopUpdate()
+{
+    if (fIsLocked>1)
+        return;
+
+    fTimer.Stop();
+}
+
+// --------------------------------------------------------------------------
+//
+// Set the update interval for the GUI update, see StartUpdate.
+//
+void MStatusDisplay::SetUpdateTime(Long_t t)
+{
+    fTimer.SetTime(t);
+}
+
+// --------------------------------------------------------------------------
+//
+// Set the background color in a canvas
+//
+void MStatusDisplay::CanvasSetFillColor(TPad &p, Int_t col) const
+{
+    TObject *obj;
+
+    // See also TPad::UseCurrentStyle
+    TIter Next(p.GetListOfPrimitives());
+    while ((obj=Next()))
+    {
+        if (obj->InheritsFrom(TPad::Class()))
+            CanvasSetFillColor(*(TPad*)obj, col);
+        if (obj->InheritsFrom(TFrame::Class()))
+            ((TFrame*)obj)->SetFillColor(col);
+    }
+
+    p.SetFillColor(col);
+}
+
+void MStatusDisplay::AddExtension(TString &name, const TString &ext, Int_t num) const
+{
+    if (name.IsNull())
+    {
+        name = "status";
+        if (num>0)
+        {
+            name += "-";
+            name += num;
+        }
+    }
+
+    if (name.EndsWith("."+ext))
+        return;
+
+    name += ".";
+    name += ext;
+}
+
+Bool_t MStatusDisplay::CheckTabForCanvas(int num) const
+{
+    if (gROOT->IsBatch())
+        return num>0 && num<=fBatch->GetSize() || num<0;
+
+    if (num>=fTab->GetNumberOfTabs())
+    {
+        *fLog << warn << "Tab #" << num << " doesn't exist..." << endl;
+        return kFALSE;
+    }
+    if (num==0)
+    {
+        *fLog << warn << "Tab #" << num << " doesn't contain an embedded canvas..." << endl;
+        return kFALSE;
+    }
+    if (fTab->GetNumberOfTabs()<2 || !gPad)
+    {
+        *fLog << warn << "Sorry, you must have at least one existing canvas (gPad!=NULL)" << endl;
+        return kFALSE;
+    }
+    return kTRUE;
+}
+
+// --------------------------------------------------------------------------
+//
+// Insert the following two lines into the postscript header:
+//
+//   %%DocumentPaperSizes: a4
+//   %%Orientation: Landscape
+//
+void MStatusDisplay::UpdatePSHeader(const TString &name) const
+{
+    const TString newstr("%%DocumentPaperSizes: a4\n%%Orientation: Landscape\n");
+    const Int_t   l = newstr.Length();
+
+    Long_t t[4]; // { id, size, flags, modtime }
+    gSystem->GetPathInfo(name, t, t+1, t+2, t+3);
+
+    char *c[2] = { new char[l], new char[l] };
+
+    fstream f(name, ios::in|ios::out);
+
+    TString str;
+    f >> str >> c[0][0];     // Read "%!PS-Adobe-2.0\n" (Mini Header)
+    f.read(c[0], l);
+    f.seekp(-l, ios::cur);
+    f.write(newstr, l);
+
+    int i=0;
+    while (1)
+    {
+        f.read(c[(i+1)%2], l);
+        f.seekp(-l, ios::cur);
+
+        if (f)
+        {
+            f.write(c[i%2],l);
+            i++;
+            i%=2;
+            continue;
+        }
+
+        const Int_t ssz   = str.Length()+1;        // Length of Mini-Header
+        const Int_t block = t[1]-ssz;              // Length of block to be shifted
+        const Int_t size  = block%l;               // Reminder
+        const Int_t pos   = (block/l)*l + ssz + 1; // Position to start writing
+
+        f.clear();
+        f.seekp(pos);
+        f.write(c[i%2], l);
+        f.write(c[(i+1)%2], size);
+        break;
+    }
+
+    delete c[1];
+    delete c[0];
+}
+
+// --------------------------------------------------------------------------
+//
+// In case of num<0 all tabs are written into the PS file. If num>0
+// the canvas in the corresponding tab is written to the file.
+// Name is the name of the file (with or without extension).
+//
+// Returns the number of pages written.
+//
+// To write all tabs you can also use SaveAsPS(name)
+//
+Int_t MStatusDisplay::SaveAsPS(Int_t num, TString name)
+{
+    SetStatusLine1("Writing Postscript file...");
+    SetStatusLine2("");
+
+    if (!CheckTabForCanvas(num))
+    {
+        SetStatusLine2("Failed!");
+        return 0;
+    }
+
+    AddExtension(name, "ps", num);
+
+    if (num<0)
+        *fLog << inf << "Open ps-File: " << name << endl;
+
+    TPad       *padsav = (TPad*)gPad;
+    TVirtualPS *psave  = gVirtualPS;
+
+    TDatime d;
+
+    TPostScript ps(name, 112);
+    ps.SetBit(TPad::kPrintingPS);
+    ps.PrintFast(13, "/nan {1} def ");
+
+    gVirtualPS = &ps;
+
+    //
+    // Create a list to delete the canvas clones
+    //
+    TList l;
+    l.SetOwner();
+
+    //
+    // Create some GUI elements for a page legend
+    //
+    TLine line;
+
+    int page = 1;
+
+    //
+    // Maintain tab numbers
+    //
+    const Int_t max  = gROOT->IsBatch() ? fBatch->GetSize()+1 : fTab->GetNumberOfTabs();
+    const Int_t from = num<0 ?   1 : num;
+    const Int_t to   = num<0 ? max : num+1;
+
+    for (int i=from; i<to; i++)
+    {
+        TCanvas *c;
+        if (!(c = GetCanvas(i)))
+        {
+            if (num<0)
+                *fLog << inf << " - ";
+            *fLog << "Tab #" << i << " doesn't contain an embedded Canvas... skipped." << endl;
+            continue;
+        }
+
+        SetStatusLine2(Form("Tab #%d", i));
+
+        //
+        // Init page and page size, make sure, that the canvas in the file
+        // has the same Aspect Ratio than on the screen.
+        //
+        ps.NewPage();
+
+        //
+        // 26 is used here to scale the canvas into a height of 26,
+        // such that the page title can be set above the canvas...
+        //
+        Float_t psw = 26; //29.7; // A4 - width
+        Float_t psh = 21.0; // A4 - height
+
+        const Float_t cw = c->GetWw();
+        const Float_t ch = c->GetWh();
+
+        if (psw/psh>cw/ch)
+            psw = cw/ch*psh;
+        else
+            psh = ch/cw*psw;
+
+        ps.Range(psw, psh); // A4
+
+        //
+        // Clone canvas and change background color and schedule for
+        // deletion
+        //
+        TCanvas *n = (TCanvas*)c->Clone();
+        CanvasSetFillColor(*n, kWhite);
+        l.Add(n);
+        //
+        // Paint canvas into root file
+        //
+        if (num<0)
+            *fLog << inf << " - ";
+        *fLog << inf << "Writing Tab #" << i << ": " << c->GetName() << " (" << c << ") ";
+        if (num>0)
+            *fLog << "to " << name;
+        *fLog << "..." << flush;
+
+        n->SetBatch(kTRUE);
+        n->Paint();
+
+        //
+        // Use the canvas as coordinate system for the overlaying text
+        //
+        gPad = n;
+
+        //
+        // Print overlaying text (NDC = %)
+        //
+        ps.SetTextColor(kBlack);
+        ps.SetTextSize(0.015);
+        ps.SetTextFont(22);
+        ps.SetTextAlign(11); // left top
+        ps.TextNDC(0, 1.02, TString("  ")+n->GetName());
+        ps.SetTextAlign(21); // cent top
+        ps.TextNDC(0.5, 1.02, TString("MARS - Magic Analysis and Reconstruction Software - ")+d.AsString());
+        ps.SetTextAlign(31); // right top
+        ps.TextNDC(1, 1.02, Form("Page No.%i (%i)  ", page++, i));
+        line.PaintLineNDC(0, 1.015, 1, 1.015);
+
+        //
+        // Finish drawing page
+        //
+        n->SetBatch(kFALSE);
+        if (num<0)
+            *fLog << "done." << endl;
+    }
+
+    gPad = NULL; // Important!
+    l.Delete();
+
+    ps.Close();
+    UpdatePSHeader(name);
+
+    gVirtualPS = psave;
+    if (padsav)
+        padsav->cd();
+
+    *fLog << inf << "done." << endl;
+
+    SetStatusLine2(Form("Done (%dpages)", page-1));
+
+    return page-1;
+}
+
+Bool_t MStatusDisplay::SaveAsGIF(Int_t num, TString name)
+{
+    if (gROOT->IsBatch())
+    {
+        *fLog << warn << "Sorry, writing gif-files is not available in batch mode." << endl;
+        return 0;
+    }
+    SetStatusLine1("Writing GIF file...");
+    SetStatusLine2("");
+
+    if (!CheckTabForCanvas(num))
+    {
+        SetStatusLine2("Failed!");
+        return 0;
+    }
+
+    AddExtension(name, "gif", num);
+
+    if (num<0)
+        *fLog << inf << "Writing gif-Files..." << endl;
+
+    TPad *padsav = (TPad*)gPad;
+
+    int page = 1;
+
+    //
+    // Maintain tab numbers
+    //
+    const Int_t from = num<0 ? 1 : num;
+    const Int_t to   = num<0 ? fTab->GetNumberOfTabs() : num+1;
+
+    for (int i=from; i<to; i++)
+    {
+        TCanvas *c;
+        if (!(c = GetCanvas(i)))
+        {
+            if (num<0)
+                *fLog << inf << " - ";
+            *fLog << "Tab #" << i << " doesn't contain an embedded Canvas... skipped." << endl;
+            continue;
+        }
+
+        SetStatusLine2(Form("Tab #%d", i));
+
+        //
+        // Clone canvas and change background color and schedule for
+        // deletion
+        //
+        //TCanvas *n = (TCanvas*)c->Clone();
+        //CanvasSetFillColor(*n, kWhite);
+
+        //
+        // Paint canvas into root file
+        //
+        TString writename = name;
+        if (num<0)
+        {
+            TString numname = "-";
+            numname += i;
+            writename.Insert(name.Last('.'), numname);
+        }
+        if (num<0)
+            *fLog << inf << " - ";
+        *fLog << inf << "Writing Tab #" << i << " to " << writename << ": " << c->GetName() << " (" << c << ") ";
+        if (num>0)
+            *fLog << "to " << name;
+        *fLog << "..." << flush;
+
+        c->Draw();
+        c->SaveAs(writename);
+        /*
+         n->Draw();
+         n->SaveAs(writename);
+         delete n;
+         */
+
+        if (num<0)
+            *fLog << "done." << endl;
+    }
+
+    padsav->cd();
+
+    *fLog << inf << "done." << endl;
+
+    SetStatusLine2("Done.");
+
+    return page-1;
+}
+
+Bool_t MStatusDisplay::SaveAsC(Int_t num, TString name)
+{
+    SetStatusLine1("Writing C++ file...");
+    SetStatusLine2("");
+
+    if (!CheckTabForCanvas(num))
+    {
+        SetStatusLine2("Failed!");
+        return 0;
+    }
+
+    AddExtension(name, "C", num);
+
+    if (num<0)
+        *fLog << inf << "Writing C-Files..." << endl;
+
+    TPad *padsav = (TPad*)gPad;
+
+    int page = 1;
+
+    //
+    // Maintain tab numbers
+    //
+    const Int_t from = num<0 ? 1 : num;
+    const Int_t to   = num<0 ? fTab->GetNumberOfTabs() : num+1;
+
+    for (int i=from; i<to; i++)
+    {
+        TCanvas *c;
+        if (!(c = GetCanvas(i)))
+        {
+            if (num<0)
+                *fLog << inf << " - ";
+            *fLog << "Tab #" << i << " doesn't contain an embedded Canvas... skipped." << endl;
+            continue;
+        }
+
+        SetStatusLine2(Form("Tab #%d", i));
+
+        //
+        // Clone canvas and change background color and schedule for
+        // deletion
+        //
+        TCanvas *n = (TCanvas*)c->Clone();
+        CanvasSetFillColor(*n, kWhite);
+
+        //
+        // Paint canvas into root file
+        //
+        TString writename = name;
+        if (num<0)
+        {
+            TString numname = "-";
+            numname += i;
+            writename.Insert(name.Last('.'), numname);
+        }
+        if (num<0)
+            *fLog << inf << " - ";
+        *fLog << inf << "Writing Tab #" << i << " to " << writename << ": " << c->GetName() << " (" << n << ") ";
+        if (num>0)
+            *fLog << "to " << name;
+        *fLog << "..." << flush;
+
+        n->SaveSource(writename, "");
+        delete n;
+
+        if (num<0)
+            *fLog << "done." << endl;
+    }
+
+    padsav->cd();
+
+    *fLog << inf << "done." << endl;
+
+    SetStatusLine2("Done.");
+
+    return page-1;
+}
+
+// --------------------------------------------------------------------------
+//
+// In case of num<0 all tabs are written into the PS file. If num>0
+// the canvas in the corresponding tab is written to the file.
+// Name is the name of the file (with or without extension).
+//
+// Returns the number of keys written.
+//
+// To write all tabs you can also use SaveAsPS(name)
+//
+Int_t MStatusDisplay::SaveAsRoot(Int_t num, TString name)
+{
+    SetStatusLine1("Writing root file...");
+    SetStatusLine2("");
+
+    if (!CheckTabForCanvas(num))
+    {
+        SetStatusLine2("Failed!");
+        return 0;
+    }
+
+    AddExtension(name, "root", num);
+
+    TFile *fsave = gFile;
+    TFile file(name, "RECREATE", "MARS - Status Window Contents", 9);
+    const Int_t keys = Write(num);
+    gFile = fsave;
+
+    SetStatusLine2("Done.");
+
+    return keys;
+}
+
+Bool_t MStatusDisplay::HandleConfigureNotify(Event_t *evt)
+{
+    //
+    // The initialization of the GUI is not yet enough finished...
+    //
+    if (!fTab)
+        return kTRUE;
+
+    UInt_t w = evt->fWidth;
+    UInt_t h = evt->fHeight;
+
+    /*
+     cout << "Old: " << GetWidth() << " " << GetHeight() << " " << GetBorderWidth() << endl;
+     cout << "New: " << w << " " << h << " ";
+     cout << "New: " << GetDefaultWidth() << " " << GetDefaultHeight() << " " << endl;
+     */
+
+    //Bool_t wchanged = w!=GetWidth();
+    Bool_t hchanged = h!=GetHeight();
+    /*
+    if (!wchanged && !hchanged)
+    {
+        Layout();
+        // FIXME: Make sure that this doesn't result in endless loops.
+        // return kTRUE;
+    }
+    */
+
+    if (GetWidth()==1 && GetHeight()==1)
+        return kTRUE;
+
+    // calculate the constant part of the window
+    const UInt_t cw = GetWidth() -fTab->GetWidth();
+    const UInt_t ch = GetHeight()-fTab->GetHeight();
+
+    // calculate new size of frame (canvas @ 1:sqrt(2))
+    if (hchanged)
+        w = (UInt_t)((h-ch)*sqrt(2.)+.5)+cw;
+    else
+        h = (UInt_t)((w-cw)/sqrt(2.)+.5)+ch;
+
+    // resize frame
+    Resize(w, h);
+
+    return kTRUE;
+}
+
+Bool_t MStatusDisplay::HandleEvent(Event_t *event)
+{
+    Bool_t rc = TGMainFrame::HandleEvent(event);
+
+    //
+    // This fixes a bug in older root versions which makes
+    // TCanvas crash if gPad==NULL. So we make sure, that
+    // gPad!=NULL -- be carfull, this may have other side
+    // effects.
+    //
+#if ROOT_VERSION_CODE < ROOT_VERSION(3,10,01)
+    if (!gPad && fTab)
+        for (int i=0; i<fTab->GetNumberOfTabs(); i++)
+        {
+            TCanvas *c = GetCanvas(i);
+            if (c)
+            {
+                c->cd();
+                gLog << dbg << "MStatusDisplay::HandleEvent - Workaround: gPad=" << gPad << "." << endl;
+                break;
+            }
+        }
+#endif
+
+    return rc;
+}
+
+/*
+ // --------------------------------------------------------------------------
+//
+//  Opens a save as dialog, and tries to store the canvas
+//  in the given output format
+//
+void MGEvtDisplay::SaveAsDialog() const
+{
+    static const char *gSaveAsTypes[] =
+    {
+        "PostScript",   "*.ps",
+        "Encapsulated PostScript", "*.eps",
+        "Gif files",    "*.gif",
+        "Macro files",  "*.C",
+        "ROOT files",   "*.root",
+        "All files",    "*",
+        NULL,           NULL
+    };
+
+    static TString dir(".");
+
+    TGFileInfo fi; // fFileName and fIniDir deleted in ~TGFileInfo
+
+    fi.fFileTypes = (const char**)gSaveAsTypes;
+    fi.fIniDir    = StrDup(dir);
+
+    new TGFileDialog(fClient->GetRoot(), this, kFDSave, &fi);
+
+    if (!fi.fFilename)
+        return;
+
+    dir = fi.fIniDir;
+
+    if (strstr(fi.fFilename, ".root") ||
+        strstr(fi.fFilename, ".ps")   ||
+        strstr(fi.fFilename, ".eps")  ||
+        strstr(fi.fFilename, ".gif"))
+    {
+        fCanvas->SaveAs(fi.fFilename);
+        return;
+    }
+    if (strstr(fi.fFilename, ".C"))
+    {
+        fCanvas->SaveSource(fi.fFilename);
+        return;
+    }
+    Warning("SaveAsDialog", "Unknown Extension: %s", fi.fFilename);
+}
+*/
Index: trunk/MagicSoft/Mars/mbase/MStatusDisplay.h
===================================================================
--- trunk/MagicSoft/Mars/mbase/MStatusDisplay.h	(revision 2493)
+++ trunk/MagicSoft/Mars/mbase/MStatusDisplay.h	(revision 2493)
@@ -0,0 +1,180 @@
+#ifndef MARS_MStatusDisplay
+#define MARS_MStatusDisplay
+
+#ifndef MARS_MAGIC
+#include "MAGIC.h"
+#endif
+
+#ifndef ROOT_TGFrame
+#include <TGFrame.h>
+#endif
+
+#ifndef ROOT_TTimer
+#include <TTimer.h>
+#endif
+
+class MLog;
+class MGList;
+class MParContainer;
+
+class TPad;
+class TTimer;
+class TMutex;
+class TCanvas;
+
+class TGTab;
+class TGTextView;
+class TGStatusBar;
+class TGProgressBar;
+class TGHProgressBar;
+class TGCompositeFrame;
+class TRootEmbeddedCanvas;
+
+class MStatusDisplay : public TGMainFrame
+{
+public:
+    typedef enum {
+        // kFile
+        kFileBrowser, kFileCanvas, kFileSave, kFileSaveAs, kFileSaveAsPS,
+        kFileSaveAsRoot, kFileSaveAsGIF, kFileSaveAsC, kFilePrint,
+        kFilePrinterName, kFileClose, kFileExit, kFileReset,
+        // kLoop
+        kLoopNone, kLoopStop,
+        // kTab
+        kTabSave, kTabSaveAs, kTabSaveAsPS, kTabSaveAsRoot, kTabSaveAsGIF,
+        kTabSaveAsC, kTabPrint, kTabNext, kTabPrevious, kTabRemove,
+        // kSize
+        kSize640, kSize800, kSize960, kSize1024, kSize1280,
+        // kLog
+        kLogCopy, kLogClear, kLogSelect, kLogFind, kLogSave, kLogAppend,
+        // kPic
+        kPicMagic, kPicMars,
+        // kPic
+        kSearch
+    } Status_t;
+
+protected:
+    MGList           *fList;
+    TGCompositeFrame *fUserFrame;
+
+    Bool_t ProcessMessage(Long_t msg, Long_t mp1, Long_t mp2);
+
+private:
+    TGHProgressBar   *fBar;
+    TGTab            *fTab;
+    TGLayoutHints    *fLayCanvas;
+
+    TTimer  fTimer;
+    TMutex *fMutex;
+
+    TGStatusBar *fStatusBar;
+
+    Status_t fStatus;
+
+    TString fPrinter;
+
+    MLog *fLog;
+    Int_t fLogIdx;
+    TTimer fLogTimer;
+    TGTextView *fLogBox;
+
+    FontStruct_t fFont;
+
+    UInt_t fIsLocked;
+
+    TList *fBatch;          //!
+
+    void AddMenuBar();
+    void AddUserFrame();
+    void AddTabs();
+    void AddProgressBar();
+    void AddStatusBar();
+    void AddMarsTab();
+    void AddLogTab();
+
+    TCanvas *GetCanvas(TGCompositeFrame *f) const;
+
+    Bool_t ProcessMessageCommandMenu(Long_t mp1);
+    Bool_t ProcessMessageCommand(Long_t submsg, Long_t mp1, Long_t mp2);
+    Bool_t ProcessMessageTextview(Long_t submsg, Long_t mp1, Long_t mp2);
+    Bool_t ProcessMessageUser(Long_t submsg, Long_t mp1, Long_t mp2);
+    void   CloseWindow();
+    Bool_t HandleConfigureNotify(Event_t *);
+    Bool_t HandleEvent(Event_t *event);
+
+    Bool_t HandleTimer(TTimer *timer=NULL);
+    void UpdateTab(TGCompositeFrame *f);
+
+    void DrawClonePad(TCanvas &newc, const TCanvas &oldc) const;
+    void CanvasSetFillColor(TPad &c, Int_t col) const;
+
+    void AddExtension(TString &name, const TString &ext, Int_t num) const;
+
+    void UpdatePSHeader(const TString &name) const;
+
+    void RemoveTab(int i);
+
+    TRootEmbeddedCanvas *GetEmbeddedCanvas(TGCompositeFrame *cf) const;
+
+public:
+     MStatusDisplay(Long_t t=1000);
+     virtual ~MStatusDisplay();
+
+     void SetLogStream(MLog *log, Bool_t enable=kFALSE);
+
+     void StartUpdate(Int_t millisec=-1);
+     void StopUpdate();
+     void SetUpdateTime(Long_t t);
+
+     void SetProgressBarPosition(Float_t p);
+     TGProgressBar *GetBar() const { return (TGProgressBar*)fBar; }
+
+     void SetStatusLine1(const char *txt);
+     void SetStatusLine2(const char *txt);
+     void SetStatusLine2(const MParContainer &cont);
+
+     void SetPrinter(const TString &lpr) { fPrinter = lpr; }
+
+     TCanvas &AddTab(const char *name);
+     TGCompositeFrame *AddRawTab(const char *name);
+
+     Bool_t   HasCanvas(const TCanvas *c) const;
+     TCanvas *GetCanvas(int i) const;
+     TCanvas *GetCanvas(const TString &name) const;
+
+     Int_t Read(const char *name="MStatusDisplay");
+     Int_t Write(const char *name="MStatusDisplay", Int_t option=0, Int_t bufsize=0)
+     {
+         return Write(-1, name, option, bufsize);
+     }
+     Int_t Write(Int_t num, const char *name="MStatusDisplay", Int_t option=0, Int_t bufsize=0);
+
+     Bool_t CdCanvas(const TString &name);
+     void   Update() { HandleTimer(&fTimer); HandleTimer(&fLogTimer); }
+
+     void SetNoContextMenu(Bool_t flag=kTRUE);
+
+     Int_t  SaveAsPS(TString name="") { return SaveAsPS(-1, name); }
+     Bool_t SaveAsGIF(TString name="") { return SaveAsGIF(-1, name); }
+     Bool_t SaveAsC(TString name="") { return SaveAsC(-1, name); }
+     Int_t  SaveAsRoot(TString name="") { return SaveAsRoot(-1, name); }
+     Int_t  PrintToLpr() { return PrintToLpr(-1); }
+
+     Int_t  SaveAsPS(Int_t num, TString name="");
+     Bool_t SaveAsGIF(Int_t num, TString name="");
+     Bool_t SaveAsC(Int_t num, TString name="");
+     Int_t  SaveAsRoot(Int_t num, TString name="");
+     Int_t  PrintToLpr(Int_t num);
+
+     Status_t CheckStatus() const { return fStatus; }
+     void ClearStatus() { fStatus = kLoopNone; }
+
+     void Lock() { fIsLocked++; }
+     void UnLock() { if (fIsLocked>0) fIsLocked--; }
+
+     Bool_t CheckTabForCanvas(int num) const;
+
+     ClassDef(MStatusDisplay, 0)   // Window for a status display
+};
+
+#endif
Index: trunk/MagicSoft/Mars/mbase/Makefile
===================================================================
--- trunk/MagicSoft/Mars/mbase/Makefile	(revision 2492)
+++ trunk/MagicSoft/Mars/mbase/Makefile	(revision 2493)
@@ -43,4 +43,5 @@
            MFilter.cc \
            MEvtLoop.cc \
+           MStatusDisplay.cc \
            MIter.cc \
            MReadSocket.cc \
