Index: /trunk/MagicSoft/Mars/Changelog
===================================================================
--- /trunk/MagicSoft/Mars/Changelog	(revision 2476)
+++ /trunk/MagicSoft/Mars/Changelog	(revision 2477)
@@ -3,8 +3,8 @@
   2003/11/05: Wolfgang Wittek
 
-   * macros/CT1Analysis.C, macros/ONOFFCT1Analysis.C
+   * macros/CT1Analysis.C, macros/ONOFFCT1Analysis.C:
      - current versions of the macros for the analysis of CT1 data
  
-   * manalysis/MMarquardt.[h,cc]
+   * manalysis/MMarquardt.[h,cc]:
      - very pleliminary version of a class performing a minimization 
        using the Marquardt method
@@ -14,5 +14,5 @@
        to the shower image using the maximum likelihood method 
 
-   * mimage/M2dimFunction.[h,cc]
+   * mimage/M2dimFunction.[h,cc]:
      - very pleliminary version of a container which contains the
        parameters of the 2-dim function describing the shower image
@@ -58,4 +58,22 @@
      - removed some obsolete IsUsed(idx) checks when filling the histogram
      - ExecuteEvent now plots in the same canvas all the time
+
+   * mmain/MStatusDisplay.[h,cc]:
+     - added new data member fUserFrame
+     - added new member function AddUserFrame
+     - made call to ProcessEvent() and similar thread safe by
+       checking whether we run in the main thread or not.
+     - Set the progress bar range to (0,1)
+     - Added member function to set progress bar position
+     - updated comments
+     - added some workarounds for root bugs in TCanvas (sometimes
+       they call gPad->cd() indirectly when gPad==NULL)
+     - Fixed thread safety of UpdateTab()
+     - Fixed some crashes in case fTab==NULL
+     - Tried to make HandleConfigureNotify more flexible to allow
+       the new fUserFrame to work correctly - needs still some
+       investigations
+     - made fList a protected data member 
+     - added new member function Update()
 
 
Index: /trunk/MagicSoft/Mars/mmain/MStatusDisplay.cc
===================================================================
--- /trunk/MagicSoft/Mars/mmain/MStatusDisplay.cc	(revision 2476)
+++ /trunk/MagicSoft/Mars/mmain/MStatusDisplay.cc	(revision 2477)
@@ -72,9 +72,11 @@
 #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 <TRint.h>                // gApplication, TRint::Class()
+#include <TMethodCall.h>          // TMethodCall
+
+//#include <TRint.h>                // gApplication, TRint::Class()
 #include <TInterpreter.h>         // gInterpreter
 
@@ -282,4 +284,18 @@
 // --------------------------------------------------------------------------
 //
+// 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
 //
@@ -376,6 +392,9 @@
 
         // make it visible
-        // FIXME: This is a workaround, because TApplication::Run is not thread safe against ProcessEvents
-        if (gApplication->InheritsFrom(TRint::Class()))
+        // 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);
     }
@@ -425,5 +444,6 @@
 // --------------------------------------------------------------------------
 //
-// Add the progress bar to the GUI
+// Add the progress bar to the GUI. The Progress Bar range is set to
+// (0,1) as default.
 //
 void MStatusDisplay::AddProgressBar()
@@ -433,4 +453,5 @@
 
     fBar=new TGHProgressBar(this);
+    fBar->SetRange(0, 1);
     fBar->ShowPosition();
     AddFrame(fBar, laybar);
@@ -440,4 +461,14 @@
 // --------------------------------------------------------------------------
 //
+// 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
 //
@@ -446,4 +477,6 @@
     fStatusBar = new TGStatusBar(this, 1, 1);
 
+    //
+    // Divide it like the 'Golden Cut' (goldener Schnitt)
     //
     //     1-a     a
@@ -474,6 +507,10 @@
         return;
     fStatusBar->SetText(txt, 0);
-    // FIXME: This is a workaround, because TApplication::Run is not thread safe against ProcessEvents
-    if (gApplication->InheritsFrom(TRint::Class()))
+
+    // 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);
 }
@@ -488,6 +525,10 @@
         return;
     fStatusBar->SetText(txt, 1);
-    // FIXME: This is a workaround, because TApplication::Run is not thread safe against ProcessEvents
-    if (gApplication->InheritsFrom(TRint::Class()))
+
+    // 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);
 }
@@ -515,5 +556,5 @@
 //
 MStatusDisplay::MStatusDisplay(Long_t t)
-: TGMainFrame(gClient ? gClient->GetRoot() : NULL, 1, 1), fTimer(this, t, kTRUE), fStatus(kLoopNone), fLog(&gLog), fLogIdx(-1), fLogTimer(this, 250, kTRUE), fLogBox(NULL), fIsLocked(0)
+: 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)
 {
     //
@@ -544,5 +585,4 @@
     SetWMSizeHints(570, 480, 1280, 980, 1, 1);
     Move(rand()%100+50, rand()%100+50);
-    //Resize(740, 600);
     Resize(570, 480);
 
@@ -559,4 +599,5 @@
     {
         AddMenuBar();
+        AddUserFrame();
         AddTabs();
         AddProgressBar();
@@ -575,6 +616,9 @@
     MapWindow();
 
-    // FIXME: This is a workaround, because TApplication::Run is not thread safe against ProcessEvents
-    if (gApplication->InheritsFrom(TRint::Class()))
+    // 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();
 }
@@ -587,4 +631,8 @@
 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
@@ -714,21 +762,4 @@
 }
 
-/*
-class MCanvas : public TRootEmbeddedCanvas
-{
-public:
-    MCanvas(const char* name, const TGWindow* p, UInt_t w, UInt_t h, UInt_t o) :
-              TRootEmbeddedCanvas(name, p, w, h, o) {}
-              void Layout()
-              {
-                  cout << "EmbLayout: " << GetCanvas()->GetName() << endl;
-
-                  // Create layout for canvas. Depending on the size of the container
-                  // we need to add the scrollbars.
-                  TRootEmbeddedCanvas::Layout();
-              }
-};
-*/
-
 TGCompositeFrame *MStatusDisplay::AddRawTab(const char *name)
 {
@@ -742,6 +773,9 @@
 
     // display new tab in the main frame
-    // FIXME: This is a workaround, because TApplication::Run is not thread safe against ProcessEvents
-    if (gApplication->InheritsFrom(TRint::Class()))
+    // 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);
 
@@ -786,16 +820,14 @@
 
     // layout and map new tab
-//#if ROOT_VERSION_CODE < ROOT_VERSION(3,03,00)
-//    MapSubwindows();
-//    Layout();
-//#else
     Layout();
     MapSubwindows();
     Layout();
-//#endif
 
     // display new tab in the main frame
-    // FIXME: This is a workaround, because TApplication::Run is not thread safe against ProcessEvents
-    if (gApplication->InheritsFrom(TRint::Class()))
+    // 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);
 
@@ -807,9 +839,14 @@
 }
 
-
 // --------------------------------------------------------------------------
 //
 // Update a canvas in a tab, takes the corresponding TGCompositeFrame
-// as an argument
+// 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)
@@ -822,19 +859,48 @@
         return;
 
-    // Code taken from TCanvas::Update() and TCanvas::Paint()
-    // replaces PaintModified() by Paint()
+    //
+    // If we are in a multithreaded environment (gThreadXAR) we
+    // have to make sure, that thus function is called from
+    // the main thread.
+    //
+    // NOTE: Maybe there is still need to make sure, that only
+    //       one thread can update the canvas by calling UpdateTab
+    //       at the same time. Could be done by a TMutex.
+    //
     if (gThreadXAR)
     {
-        void *arr[2] = { NULL, c };
-        if (((*gThreadXAR)("CUPD", 2, arr, NULL)))
+        // 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;
     }
+
+#if ROOT_VERSION_CODE < ROOT_VERSION(3,10,01)
+    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,01)
+    if (padsav)
+        padsav->cd();
+    else
+        gPad=NULL;
+#endif
     //c->SetCursor(kCross);
 
@@ -924,6 +990,9 @@
 
     // display new tab in the main frame
-    // FIXME: This is a workaround, because TApplication::Run is not thread safe against ProcessEvents
-    if (gApplication->InheritsFrom(TRint::Class()))
+    // 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);
 
@@ -2005,20 +2074,29 @@
 Bool_t MStatusDisplay::HandleConfigureNotify(Event_t *evt)
 {
-    //cout << "----- Start -----" << endl;
+    //
+    // 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 << endl;
-
-    Bool_t wchanged = w!=GetWidth();
+    /*
+     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();
-        return kTRUE;
-    }
+        // FIXME: Make sure that this doesn't result in endless loops.
+        // return kTRUE;
+    }
+    */
 
     if (GetWidth()==1 && GetHeight()==1)
@@ -2029,5 +2107,5 @@
     const UInt_t ch = GetHeight()-fTab->GetHeight();
 
-    // canculate new size of frame (canvas @ 1:sqrt(2))
+    // calculate new size of frame (canvas @ 1:sqrt(2))
     if (hchanged)
         w = (UInt_t)((h-ch)*sqrt(2.)+.5)+cw;
@@ -2035,6 +2113,4 @@
         h = (UInt_t)((w-cw)/sqrt(2.)+.5)+ch;
 
-    //cout << "Res: " << w << " " << h << " " << evt->fX << " " << evt->fY << endl;
-
     // resize frame
     Resize(w, h);
@@ -2045,24 +2121,76 @@
 Bool_t MStatusDisplay::HandleEvent(Event_t *event)
 {
-    /*
-    if (event->fType!=9)
-    {
-        cout << "Event: " << event->fType << " ";
-        cout << event->fX << " " << event->fY << endl;
-    }
-    */
-    /*
-    switch (event->fType) {
-      case kConfigureNotify:
-         //while (gVirtualX->CheckEvent(fId, kConfigureNotify, *event))
-         //   ;
-         HandleConfigureNotify(event);
-         return kTRUE;
-    }
-    */
-    //   if (event->fType==kConfigureNotify && event->fX!=0 && event->fY!=0)
-    //        return kTRUE;
-
-    return TGMainFrame::HandleEvent(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/mmain/MStatusDisplay.h
===================================================================
--- /trunk/MagicSoft/Mars/mmain/MStatusDisplay.h	(revision 2476)
+++ /trunk/MagicSoft/Mars/mmain/MStatusDisplay.h	(revision 2477)
@@ -27,4 +27,5 @@
 class TGProgressBar;
 class TGHProgressBar;
+class TGCompositeFrame;
 class TRootEmbeddedCanvas;
 
@@ -33,5 +34,5 @@
 public:
     typedef enum {
-        // KFile
+        // kFile
         kFileBrowser, kFileCanvas, kFileSave, kFileSaveAs, kFileSaveAsPS,
         kFileSaveAsRoot, kFileSaveAsGIF, kFileSaveAsC, kFilePrint,
@@ -52,9 +53,14 @@
     } Status_t;
 
+protected:
+    MGList           *fList;
+    TGCompositeFrame *fUserFrame;
+
+    Bool_t ProcessMessage(Long_t msg, Long_t mp1, Long_t mp2);
+
 private:
-    MGList         *fList;
-    TGHProgressBar *fBar;
-    TGTab          *fTab;
-    TGLayoutHints  *fLayCanvas;
+    TGHProgressBar   *fBar;
+    TGTab            *fTab;
+    TGLayoutHints    *fLayCanvas;
 
     TTimer fTimer;
@@ -78,9 +84,10 @@
 
     void AddMenuBar();
+    void AddUserFrame();
+    void AddTabs();
     void AddProgressBar();
+    void AddStatusBar();
     void AddMarsTab();
     void AddLogTab();
-    void AddTabs();
-    void AddStatusBar();
 
     TCanvas *GetCanvas(TGCompositeFrame *f) const;
@@ -90,5 +97,4 @@
     Bool_t ProcessMessageTextview(Long_t submsg, Long_t mp1, Long_t mp2);
     Bool_t ProcessMessageUser(Long_t submsg, Long_t mp1, Long_t mp2);
-    Bool_t ProcessMessage(Long_t msg, Long_t mp1, Long_t mp2);
     void   CloseWindow();
     Bool_t HandleConfigureNotify(Event_t *);
@@ -119,4 +125,5 @@
      void SetUpdateTime(Long_t t);       
 
+     void SetProgressBarPosition(Float_t p);
      TGProgressBar *GetBar() const { return (TGProgressBar*)fBar; }
 
@@ -142,4 +149,5 @@
 
      Bool_t CdCanvas(const TString &name);
+     void   Update() { HandleTimer(&fTimer); HandleTimer(&fLogTimer); }
 
      void SetNoContextMenu(Bool_t flag=kTRUE);
