Logo ROOT   6.10/09
Reference Guide
TRecorder.cxx
Go to the documentation of this file.
1 // @(#)root/gui:$Id$
2 // Author: Katerina Opocenska 11/09/2008
3 
4 /*************************************************************************
5 * Copyright (C) 1995-2008, Rene Brun and Fons Rademakers. *
6 * All rights reserved. *
7 * *
8 * For the licensing terms see $ROOTSYS/LICENSE. *
9 * For the list of contributors see $ROOTSYS/README/CREDITS. *
10 *************************************************************************/
11 
12 //////////////////////////////////////////////////////////////////////////
13 // //
14 // ROOT EVENT RECORDING SYSTEM //
15 // ================================================================== //
16 // //
17 // TRecorder class provides interface for recording and replaying //
18 // events in ROOT. //
19 // Recorded events are: //
20 // - Commands typed by user in commandline ('new TCanvas') //
21 // - GUI events (mouse movement, button clicks, ...) //
22 // //
23 // All the recorded events from one session are stored in one TFile //
24 // and can be replayed again anytime. //
25 // //
26 // Recording //
27 // ================================================================== //
28 // //
29 // 1] To start recording //
30 // //
31 // TRecorder r(const char *filename, "NEW") //
32 // TRecorder r(const char *filename, "RECREATE") //
33 // //
34 // or: //
35 // //
36 // TRecorder *recorder = new TRecorder; //
37 // recorder->Start(const char *filename, ...) //
38 // //
39 // -filename Name of ROOT file in which to save //
40 // recorded events. //
41 // //
42 // 2] To stop recording //
43 // //
44 // recorder->Stop() //
45 // //
46 // //
47 // IMPORTANT: //
48 // State capturing is part of recording. It means that if you want to //
49 // record events for some object (window), creation of this object //
50 // must be also recorded. //
51 // //
52 // Example: //
53 // -------- //
54 // t = new TRecorder(); // Create a new recorder //
55 // t->Start("logfile.root"); // ! Start recording first //
56 // //
57 // c = new TCanvas(); // ! Then, create an object //
58 // c->Dump(); // Work with that object //
59 // //
60 // t->Stop(); // Stop recording //
61 // //
62 // It is strongly recommended to start recording with empty ROOT //
63 // environment, at least with no previously created ROOT GUI. //
64 // This ensures that only events for well known windows are stored. //
65 // Events for windows, which were not created during recording, //
66 // cannot be replayed. //
67 // //
68 // Replaying //
69 // =================================================================== //
70 // //
71 // 1] To start replaying //
72 // //
73 // TRecorder r(const char *filename) //
74 // TRecorder r(const char *filename, "READ") //
75 // //
76 // or: //
77 // //
78 // TRecorder *recorder = new TRecorder; //
79 // recorder->Replay(const char *filename, //
80 // Bool_t showMouseCursor = kTRUE); //
81 // //
82 // -filename A name of file with recorded events //
83 // previously created with TRecorder::Start //
84 // //
85 // -showMouseCursor If kTRUE, mouse cursor is replayed as well. //
86 // In that case it is not recommended to use mouse //
87 // during replaying. //
88 // //
89 // In general, it is not recommended to use mouse to change positions //
90 // and states of ROOT windows during replaying. //
91 // //
92 // IMPORTANT: //
93 // The state of ROOT environment before replaying of some events //
94 // must be exactly the same as before recording them. //
95 // Therefore it is strongly recommended to start both recording //
96 // and replaying with empty ROOT environment. //
97 // //
98 // 2] To pause replaying //
99 // //
100 // recorder->Pause() //
101 // //
102 // Replaying is stopped until recorder->Resume() is called. //
103 // //
104 // //
105 // 3] To resume paused replaying //
106 // //
107 // recorder->Resume() //
108 // //
109 // Resumes previously stopped replaying. //
110 // //
111 // //
112 // 4] To stop replaying before its end //
113 // //
114 // recorder->Stop() //
115 // //
116 //////////////////////////////////////////////////////////////////////////
117 
118 #include "TRecorder.h"
119 
120 #include "TROOT.h"
121 #include "TFile.h"
122 #include "TTimer.h"
123 #include "TTree.h"
124 #include "TSystem.h"
125 #include "TMutex.h"
126 #include "TGButton.h"
127 #include "TGFileDialog.h"
128 #include "TGLabel.h"
129 #include "TGWindow.h"
130 #include "Buttons.h"
131 #include "TKey.h"
132 #include "TPaveLabel.h"
133 #include "TLatex.h"
134 #include "TVirtualDragManager.h"
135 #include "TGPicture.h"
136 #include "KeySymbols.h"
137 
138 // Names of ROOT GUI events. Used for listing event logs.
139 const char *kRecEventNames[] = {
140  "KeyPress",
141  "KeyRelease",
142  "ButtonPress",
143  "ButtonRelease",
144  "MotionNotify",
145  "EnterNotify",
146  "LeaveNotify",
147  "FocusIn",
148  "FocusOut",
149  "Expose",
150  "ConfigureNotify",
151  "MapNotify",
152  "UnmapNotify",
153  "DestroyNotify",
154  "ClientMessage",
155  "SelectionClear",
156  "SelectionRequest",
157  "SelectionNotify",
158  "ColormapNotify",
159  "ButtonDoubleClick",
160  "OtherEvent"
161 };
162 
163 // Names of TTrees in the TFile with recorded events
164 const char *kCmdEventTree = "CmdEvents"; // Name of TTree with commandline events
165 const char *kGuiEventTree = "GuiEvents"; // Name of TTree with GUI events
166 const char *kWindowsTree = "WindowsTree"; // Name of TTree with window IDs
167 const char *kExtraEventTree = "ExtraEvents"; // Name of TTree with extra events (PaveLabels and Texts)
168 const char *kBranchName = "MainBranch"; // Name of the main branch in all TTress
169 
171 
172 
173 //_____________________________________________________________________________
174 //
175 // TGCursorWindow
176 //
177 // Window used as fake mouse cursor wile replaying events.
178 //_____________________________________________________________________________
179 
180 class TGCursorWindow : public TGFrame {
181 
182 protected:
183  Pixmap_t fPic, fMask; // Pixmaps used as Window shape
184 
185 public:
186  TGCursorWindow();
187  virtual ~TGCursorWindow();
188 };
189 
190 static TGCursorWindow *gCursorWin = 0;
191 static Int_t gDecorWidth = 0;
192 static Int_t gDecorHeight = 0;
193 
194 ////////////////////////////////////////////////////////////////////////////////
195 /// TGCursorWindow constructor.
196 
197 TGCursorWindow::TGCursorWindow() :
198  TGFrame(gClient->GetDefaultRoot(), 32, 32, kTempFrame)
199 {
200  SetWindowAttributes_t wattr;
201  const TGPicture *pbg = fClient->GetPicture("recursor.png");
202  fPic = pbg->GetPicture();
203  fMask = pbg->GetMask();
204 
205  gVirtualX->ShapeCombineMask(fId, 0, 0, fMask);
206  SetBackgroundPixmap(fPic);
207 
209  wattr.fSaveUnder = kTRUE;
210  wattr.fOverrideRedirect = kTRUE;
211 
212  gVirtualX->ChangeWindowAttributes(fId, &wattr);
213 }
214 
215 ////////////////////////////////////////////////////////////////////////////////
216 /// Destructor.
217 
218 TGCursorWindow::~TGCursorWindow()
219 {
220 }
221 
222 ////////////////////////////////////////////////////////////////////////////////
223 /// Creates initial INACTIVE state for the recorder
224 
226 {
227  fFilename = "";
229 }
230 
231 ////////////////////////////////////////////////////////////////////////////////
232 /// Creates a recorder with filename to replay or to record,
233 /// depending on option (NEW or RECREATE will start recording,
234 /// READ will start replaying)
235 
236 TRecorder::TRecorder(const char *filename, Option_t *option)
237 {
238  TString opt(option);
239  fFilename = "";
241  if ((opt == "NEW") || (opt == "RECREATE"))
242  Start(filename, option);
243  else
244  Replay(filename);
245 }
246 
247 ////////////////////////////////////////////////////////////////////////////////
248 /// Destructor.
249 
251 {
252  delete fRecorderState;
253 }
254 
255 ////////////////////////////////////////////////////////////////////////////////
256 /// Browse the recorder from a ROOT file. This allows to replay a
257 /// session from the browser.
258 
260 {
261  Replay(fFilename);
262 }
263 
264 ////////////////////////////////////////////////////////////////////////////////
265 /// Starts recording events
266 
267 void TRecorder::Start(const char *filename, Option_t *option, Window_t *w,
268  Int_t winCount)
269 {
270  fRecorderState->Start(this, filename, option, w, winCount);
271 }
272 
273 ////////////////////////////////////////////////////////////////////////////////
274 /// Stopps recording events
275 
276 void TRecorder::Stop(Bool_t guiCommand)
277 {
278  fRecorderState->Stop(this, guiCommand);
279 }
280 
281 ////////////////////////////////////////////////////////////////////////////////
282 /// Replays events from 'filename'
283 
284 Bool_t TRecorder::Replay(const char *filename, Bool_t showMouseCursor,
286 {
287  return fRecorderState->Replay(this, filename, showMouseCursor, mode);
288 }
289 
290 ////////////////////////////////////////////////////////////////////////////////
291 /// Pauses replaying
292 
294 {
295  fRecorderState->Pause(this);
296 }
297 
298 ////////////////////////////////////////////////////////////////////////////////
299 /// Resumes replaying
300 
302 {
303  fRecorderState->Resume(this);
304 }
305 
306 ////////////////////////////////////////////////////////////////////////////////
307 /// Cancells replaying
308 
310 {
311  fRecorderState->ReplayStop(this);
312 }
313 
314 ////////////////////////////////////////////////////////////////////////////////
315 /// Prints out recorded commandline events
316 
317 void TRecorder::ListCmd(const char *filename)
318 {
319  fRecorderState->ListCmd(filename);
320 }
321 
322 ////////////////////////////////////////////////////////////////////////////////
323 /// Prints out recorded GUI events
324 
325 void TRecorder::ListGui(const char *filename)
326 {
327  fRecorderState->ListGui(filename);
328 }
329 
330 ////////////////////////////////////////////////////////////////////////////////
331 /// Changes state from the current to the passed one (newstate)
332 /// Deletes the old state if delPreviousState = KTRUE
333 
334 void TRecorder::ChangeState(TRecorderState *newstate, Bool_t delPreviousState)
335 {
336  if (delPreviousState)
337  delete fRecorderState;
338 
339  fRecorderState = newstate;
340 }
341 
342 ////////////////////////////////////////////////////////////////////////////////
343 /// Get current state of recorder.
344 
346 {
347  return fRecorderState->GetState();
348 }
349 
350 
351 ////////////////////////////////////////////////////////////////////////////////
352 /// Save previous canvases in a .root file
353 
354 void TRecorder::PrevCanvases(const char *filename, Option_t *option)
355 {
356  fRecorderState->PrevCanvases(filename,option);
357 }
358 
359 //______________________________________________________________________________
360 // Represents state of TRecorder when replaying
361 
363 
364 ////////////////////////////////////////////////////////////////////////////////
365 /// Allocates all necessary data structures used for replaying
366 /// What is allocated here is deleted in destructor
367 
369 {
370  fCanv = 0;
371  fCmdTree = 0;
372  fCmdTreeCounter = 0;
373  fEventReplayed = kTRUE;
374  fExtraTree = 0;
375  fExtraTreeCounter = 0;
376  fFilterStatusBar = kFALSE;
377  fGuiTree = 0;
378  fGuiTreeCounter = 0;
379  fNextEvent = 0;
380  fRecorder = 0;
381  fRegWinCounter = 0;
382  fShowMouseCursor = kTRUE;
383  fWaitingForWindow = kFALSE;
384  fWin = 0;
385  fWinTree = 0;
386  fWinTreeEntries = 0;
387  fFile = TFile::Open(filename);
388  fCmdEvent = new TRecCmdEvent();
389  fGuiEvent = new TRecGuiEvent();
390  fExtraEvent = new TRecExtraEvent();
391  fWindowList = new TList();
392  fTimer = new TTimer();
393  fMutex = new TMutex(kFALSE);
394  if (!gCursorWin)
395  gCursorWin = new TGCursorWindow();
396 }
397 
398 ////////////////////////////////////////////////////////////////////////////////
399 /// Closes all signal-slot connections
400 /// Frees all memory allocated in contructor.
401 
403 {
404  fTimer->Disconnect(fTimer, "Timeout()", this, "ReplayRealtime()");
405  fTimer->TurnOff();
406  // delete fTimer;
407 
408  gClient->Disconnect(gClient, "RegisteredWindow(Window_t)", this,
409  "RegisterWindow(Window_t)");
410 
411  if (fFile) {
412  fFile->Close();
413  delete fFile;
414  }
415 
416  delete fWindowList;
417  delete fCmdEvent;
418  delete fGuiEvent;
419  delete fExtraEvent;
420  delete fMutex;
421  if (gCursorWin)
422  gCursorWin->DeleteWindow();
423  gCursorWin = 0;
424 }
425 
426 ////////////////////////////////////////////////////////////////////////////////
427 /// Initialization of data structures for replaying.
428 /// Start of replaying.
429 ///
430 /// Return value:
431 /// - kTRUE = everything is OK and replaying has begun
432 /// - kFALSE = non existing or invalid log file, replaying has not started
433 
436 {
437  fWin = 0;
438  fGuiTreeCounter = 0;
439  fCmdTreeCounter = 0;
440  fExtraTreeCounter = 0;
441  fRegWinCounter = 0;
442  fRecorder = 0;
443 
444  fFilterStatusBar = kFALSE;
445 
446  fWaitingForWindow = kFALSE;
447 
448  fEventReplayed = 1;
449 
450  fRecorder = r;
451  fShowMouseCursor = showMouseCursor;
452 
453  if (!fFile || fFile->IsZombie() || !fFile->IsOpen())
454  return kFALSE;
455 
456  fCmdTree = (TTree*) fFile->Get(kCmdEventTree);
457  fWinTree = (TTree*) fFile->Get(kWindowsTree);
458  fGuiTree = (TTree*) fFile->Get(kGuiEventTree);
459  fExtraTree = (TTree*) fFile->Get(kExtraEventTree);
460 
461  if (!fCmdTree || !fWinTree || ! fGuiTree || ! fExtraTree) {
462  Error("TRecorderReplaying::Initialize",
463  "The ROOT file is not valid event logfile.");
464  return kFALSE;
465  }
466 
467  try {
468  fCmdTree->SetBranchAddress(kBranchName, &fCmdEvent);
469  fWinTree->SetBranchAddress(kBranchName, &fWin);
470  fGuiTree->SetBranchAddress(kBranchName, &fGuiEvent);
471  fExtraTree->SetBranchAddress(kBranchName, &fExtraEvent);
472  }
473  catch(...) {
474  Error("TRecorderReplaying::Initialize",
475  "The ROOT file is not valid event logfile");
476  return kFALSE;
477  }
478 
479  // No event to replay in given ROOT file
480  if (!PrepareNextEvent()) {
481  Info("TRecorderReplaying::Initialize",
482  "Log file empty. No event to replay.");
483  return kFALSE;
484  }
485 
486  // Number of registered windows during recording
487  fWinTreeEntries = fWinTree->GetEntries();
488 
489  // When a window is registered during replaying,
490  // TRecorderReplaying::RegisterWindow(Window_t) is called
491  gClient->Connect("RegisteredWindow(Window_t)", "TRecorderReplaying",
492  this, "RegisterWindow(Window_t)");
493 
494  Info("TRecorderReplaying::Initialize", "Replaying of file %s started",
495  fFile->GetName());
496 
497  TFile *f = TFile::Open(fFile->GetName());
498  if (f && !f->IsZombie()) {
499  TIter nextkey(f->GetListOfKeys());
500  TKey *key;
501  TObject *obj;
502  while ((key = (TKey*)nextkey())) {
503  fFilterStatusBar = kTRUE;
504  obj = key->ReadObj();
505  if (!obj->InheritsFrom("TCanvas"))
506  continue;
507  fCanv = (TCanvas*) obj;
508  fCanv->Draw();
509  }
510  TCanvas *canvas;
511  TIter nextc(gROOT->GetListOfCanvases());
512  while ((canvas = (TCanvas*)nextc())) {
513  canvas->SetWindowSize(canvas->GetWindowWidth(),
514  canvas->GetWindowHeight());
515  }
516  fFilterStatusBar = kFALSE;
517  f->Close();
518  }
519 
520  gPad = 0;
521  // Starts replaying
522  fTimer->Connect("Timeout()","TRecorderReplaying",this,"ReplayRealtime()");
523  fTimer->Start(0);
524 
525  return kTRUE;
526 }
527 
528 ////////////////////////////////////////////////////////////////////////////////
529 /// Creates mapping for the newly registered window w and adds this
530 /// mapping to fWindowList
531 ///
532 /// Called by signal whenever a new window is registered during replaying.
533 ///
534 /// The new window ID is mapped to the old one with the same number in the
535 /// list of registered windows.
536 /// It means that 1st new window is mapped to the 1st original,
537 /// 2nd to the 2nd, Nth new to the Nth original.
538 
540 {
541  if (fFilterStatusBar) {
542  TGWindow *win = gClient->GetWindowById(w);
543  if (win) {
544  if (win->GetParent()->InheritsFrom("TGStatusBar")) {
545  fFilterStatusBar = kFALSE;
546  return;
547  }
548  }
549  }
550 
551  // Get original window ID that was registered as 'fRegWinCounter'th
552  if (fWinTreeEntries > fRegWinCounter) {
553  fWinTree->GetEntry(fRegWinCounter);
554  }
555  else {
556  // More windows registered when replaying then when recording.
557  // Cannot continue
558  Error("TRecorderReplaying::RegisterWindow",
559  "More windows registered than expected");
560  //ReplayStop(fRecorder);
561  return;
562  }
563 
564  if ((gDebug > 0) && (fWaitingForWindow)) {
565  std::ios::fmtflags f = std::cout.flags(); // store flags
566  std::cout << " Window registered: new ID: " << std::hex << w <<
567  " previous ID: " << fWin << std::dec << std::endl;
568  std::cout.flags( f ); // restore flags (reset std::hex)
569  }
570 
571  // Lock mutex for guarding access to fWindowList
572  fMutex->Lock();
573 
574  // Increases counter of registered windows
575  fRegWinCounter++;
576 
577  // Creates new mapping of original window (fWin) and a new one (w)
578  TRecWinPair *ids = new TRecWinPair(fWin, w);
579  // Saves the newly created mapping
580  fWindowList->Add(ids);
581 
582  // If we are waiting for this window to be registered
583  // (Replaying was stopped because of that)
584  if (fWaitingForWindow && fGuiEvent->fWindow == fWin) {
585 
586  if (gDebug > 0) {
587  std::ios::fmtflags f = std::cout.flags(); // store flags
588  std::cout << " Window " << std::hex << fGuiEvent->fWindow <<
589  " registered." << std::dec << std::endl;
590  std::cout.flags( f ); // restore flags (reset std::hex)
591  }
592 
593  fNextEvent = fGuiEvent;
594  // Sets that we do not wait for this window anymore
595  fWaitingForWindow = kFALSE;
596 
597  // Start replaying of events again
598  fTimer->Start(25);
599  }
600  fMutex->UnLock();
601 }
602 
603 ////////////////////////////////////////////////////////////////////////////////
604 /// All references to the old windows (IDs) in fNextEvent are replaced by
605 /// new ones according to the mappings in fWindowList
606 
608 {
609  // Lock mutex for guarding access to fWindowList
610  fMutex->Lock();
611 
612  TRecWinPair *ids;
613  TListIter it(fWindowList);
614 
615  Bool_t found = kFALSE;
616 
617  // Iterates through the whole list of mappings
618  while ((ids = (TRecWinPair*)it.Next())) {
619  // Window that the event belongs to
620  if (!found && fGuiEvent->fWindow == 0) {
621  fGuiEvent->fWindow = gVirtualX->GetDefaultRootWindow();
622  found = kTRUE;
623  }
624  else if (!found && ids->fKey == fGuiEvent->fWindow) {
625  fGuiEvent->fWindow = ids->fValue;
626  found = kTRUE;
627  }
628  for (Int_t i = 0; i < 5; ++i) {
629  if ((Long_t) ids->fKey == fGuiEvent->fUser[i])
630  fGuiEvent->fUser[i] = ids->fValue;
631  }
632  if (fGuiEvent->fMasked && ids->fKey == fGuiEvent->fMasked) {
633  fGuiEvent->fMasked = ids->fValue;
634  }
635  }
636 
637  if (!found && fGuiEvent->fWindow == 0) {
638  fGuiEvent->fWindow = gVirtualX->GetDefaultRootWindow();
639  found = kTRUE;
640  }
641  // Mapping for the event found
642  if (found) {
643  fMutex->UnLock();
644  return kTRUE;
645  }
646 
647  if (gDebug > 0) {
648  // save actual formatting flags
649  std::ios_base::fmtflags org_flags = std::cout.flags();
650  std::cout << "fGuiTreeCounter = " << std::dec << fGuiTreeCounter <<
651  " No mapping found for ID " << std::hex << fGuiEvent->fWindow << std::endl;
653  // restore original formatting flags
654  std::cout.flags(org_flags);
655  }
656 
657  // Stopps timer and waits for the appropriate window to be registered
658  fTimer->Stop();
659  fWaitingForWindow = kTRUE;
660 
661  fMutex->UnLock();
662  return kFALSE;
663 }
664 
665 ////////////////////////////////////////////////////////////////////////////////
666 
668 {
669  // Not all the recorded events are replayed.
670  // Some of them are generated automatically in ROOT
671  // as a consequence of other events.
672  //
673  // RETURN VALUE:
674  // - kTRUE = passed TRecGuiEvent *e should be filtered
675  // (should not be replayed)
676  // - kFALSE = passed TRecGuiEvent *e should not be filtered
677  // (should be replayed)
678 
679  // We do not replay any client messages except closing of windows
680  if (e->fType == kClientMessage) {
681  if ((e->fFormat == 32) && (e->fHandle != TRecGuiEvent::kROOT_MESSAGE)
683  return kFALSE;
684  else
685  return kTRUE;
686  }
687 
688  // See TRecorderRecording::SetTypeOfConfigureNotify to get know
689  // which kConfigureNotify events are filtered
690  if (e->fType == kConfigureNotify && e->fUser[4] == TRecGuiEvent::kCNFilter) {
691  return kTRUE;
692  }
693 
694  if (e->fType == kOtherEvent) {
695  if (e->fFormat >= kGKeyPress && e->fFormat < kOtherEvent)
696  return kFALSE;
697  return kTRUE;
698  }
699 
700  return kFALSE;
701 }
702 
703 ////////////////////////////////////////////////////////////////////////////////
704 /// Finds the next event in log file to replay and sets it to fNextEvent
705 ///
706 /// Reads both from CmdTree and GuiTree and chooses that event that becomes
707 /// earlier
708 /// - fCmdTreeCounter determines actual position in fCmdTree
709 /// - fGuiTreeCounter determines actual position in fCmdTree
710 ///
711 /// If GUI event should be replayed, we must first make sure that there is
712 /// appropriate mapping for this event
713 ///
714 /// RETURN VALUE:
715 /// kFALSE = there is no event to be replayed
716 /// kTRUE = there is still at least one event to be replayed. Cases:
717 /// - fNextEvent = 0 => We are waiting for the appropriate
718 /// window to be registered
719 /// - fNextEvent != 0 => fNextEvent can be replayed (windows are
720 /// ready)
721 
723 {
724  fCmdEvent = 0;
725  fGuiEvent = 0;
726  fExtraEvent = 0;
727  fNextEvent = 0;
728 
729  // Reads the next unreplayed commandline event to fCmdEvent
730  if (fCmdTree->GetEntries() > fCmdTreeCounter)
731  fCmdTree->GetEntry(fCmdTreeCounter);
732 
733  // Reads the next unreplayed extra event to fExtraEvent
734  if (fExtraTree->GetEntries() > fExtraTreeCounter)
735  fExtraTree->GetEntry(fExtraTreeCounter);
736 
737  // Reads the next unreplayed GUI event to fGuiEvent
738  // Skips GUI events that should not be replayed (FilterEvent call)
739  while (fGuiTree->GetEntries() > fGuiTreeCounter) {
740  fGuiTree->GetEntry(fGuiTreeCounter);
741  if (!fGuiEvent || !FilterEvent(fGuiEvent))
742  break;
743  fGuiTreeCounter++;
744  }
745 
746  // Chooses which one will be fNextEvent (the next event to be replayed)
747  if (fCmdEvent && fGuiEvent && fExtraEvent) {
748  // If there are all uf them, compares their times and chooses the
749  // earlier one
750  if ((fCmdEvent->GetTime() <= fGuiEvent->GetTime()) &&
751  (fCmdEvent->GetTime() <= fExtraEvent->GetTime()))
752  fNextEvent = fCmdEvent;
753  else {
754  if (fGuiEvent->GetTime() <= fExtraEvent->GetTime())
755  fNextEvent = fGuiEvent;
756  else
757  fNextEvent = fExtraEvent;
758  }
759  }
760  else if (fCmdEvent && fGuiEvent) {
761  // If there are both of them, compares their times and chooses the
762  // earlier one
763  if (fCmdEvent->GetTime() <= fGuiEvent->GetTime())
764  fNextEvent = fCmdEvent;
765  else
766  fNextEvent = fGuiEvent;
767  }
768  else if (fCmdEvent && fExtraEvent ) {
769  // If there are both of them, compares their times and chooses the
770  // earlier one
771  if (fCmdEvent->GetTime() <= fExtraEvent->GetTime())
772  fNextEvent = fCmdEvent;
773  else
774  fNextEvent = fExtraEvent;
775  }
776  else if (fGuiEvent && fExtraEvent) {
777  // If there are both of them, compares their times and chooses the
778  // earlier one
779  if (fExtraEvent->GetTime() <= fGuiEvent->GetTime())
780  fNextEvent = fExtraEvent;
781  else
782  fNextEvent = fGuiEvent;
783  }
784 
785  // Nor commandline neither event to replay
786  else if (!fCmdEvent && !fGuiEvent && !fExtraEvent)
787  fNextEvent = 0;
788  // Only GUI event to replay
789  else if (fGuiEvent)
790  fNextEvent = fGuiEvent;
791  // Only commandline event to replay
792  else if (fCmdEvent)
793  fNextEvent = fCmdEvent;
794  else
795  fNextEvent = fExtraEvent;
796 
797  // Nothing to replay
798  if (fNextEvent == 0)
799  return kFALSE;
800 
801  // Commandline event to replay
802  if (fNextEvent == fCmdEvent)
803  fCmdTreeCounter++;
804 
805  // Extra event to replay
806  if (fNextEvent == fExtraEvent)
807  fExtraTreeCounter++;
808 
809  // GUI event to replay
810  if (fNextEvent == fGuiEvent) {
811  // We have the new window to send this event to
812  if (RemapWindowReferences())
813  fGuiTreeCounter++;
814  // We do not have it yet (waiting for registraion)
815  else
816  fNextEvent = 0;
817  }
818  return kTRUE;
819 }
820 
821 ////////////////////////////////////////////////////////////////////////////////
822 /// ButtonPress and ButtonRelease must be sometimes replayed more times
823 /// Example: pressing of a button opens small window and user chooses
824 /// something from that window (color)
825 /// Window must be opened while user is choosing
826 
828 {
829  if (!fGuiEvent) {
830  Error("TRecorderReplaying::CanOverlap()", "fGuiEvent = 0");
831  return kFALSE;
832  }
833 
834  // only GUI events overlapping is allowed
835  if (fNextEvent->GetType() != TRecEvent::kGuiEvent)
836  return kFALSE;
837 
838 
839  if (gDebug > 0) {
840  std::cout << "Event overlapping " <<
841  kRecEventNames[((TRecGuiEvent*)fNextEvent)->fType] << std::endl;
843  }
844 
845  // GUI event
846  TRecGuiEvent *e = (TRecGuiEvent*) fNextEvent;
847 
848  // Overlapping allowed for ButtonPress, ButtonRelease and MotionNotify
849  if (e->fType == kButtonPress || e->fType == kButtonRelease ||
850  e->fType == kMotionNotify)
851  return kTRUE;
852 
853  return kFALSE;
854 }
855 
856 ////////////////////////////////////////////////////////////////////////////////
857 /// Replays the next event.
858 ///
859 /// It is called when fTimer times out.
860 /// Every time fTimer is set again to time equal to time difference between
861 /// current two events being replayed.
862 ///
863 /// It can happen that execution of an event lasts different time during the
864 /// recording and during the replaying.
865 /// If fTimer times out too early and the previous event has not been yet
866 /// replayed, it is usually postponed in order
867 /// to keep events execution in the right order.
868 /// The excpetions are determined by TRecorderReplaying::CanOverlap()
869 ///
870 
872 {
873  UInt_t keysym;
874  char str[2];
875 
876  if ((gROOT->GetEditorMode() == kText) ||
877  (gROOT->GetEditorMode() == kPaveLabel)){
878  gROOT->SetEditorMode();
879  }
880 
881  // If there are automatically generated ROOT events in the queue, they
882  // are let to be handled first
883  if (gVirtualX->EventsPending()) {
885  return;
886  }
887 
888  // Previous event has not been replayed yet and it is not allowed for
889  // this event to be replayed more times
890  if (!fEventReplayed && !CanOverlap())
891  return;
892 
893  // Event to replay prepared
894  if (fNextEvent) {
895  // Sets that fNextEvent has not been replayed yet
896  fEventReplayed = 0;
897 
898  // Remembers its execution time to compute time difference with
899  // the next event
900  fPreviousEventTime = fNextEvent->GetTime();
901 
902  // Special execution of events causing potential deadlocks
903  if (fNextEvent->GetType() == TRecEvent::kGuiEvent) {
904  TRecGuiEvent *ev = (TRecGuiEvent *)fNextEvent;
905  if (ev->fType == kGKeyPress && ev->fState & kKeyControlMask) {
906  Event_t *e = ev->CreateEvent(ev);
907  gVirtualX->LookupString(e, str, sizeof(str), keysym);
908  // catch the ctrl-s event
909  if ((keysym & ~0x20) == kKey_S) {
910  fEventReplayed = 1;
911  PrepareNextEvent();
912  ev->ReplayEvent(fShowMouseCursor);
913  return;
914  }
915  }
916  }
917 
918  // REPLAYS CURRENT EVENT
919  fNextEvent->ReplayEvent(fShowMouseCursor);
920 
921  // Sets that fNextEvent has been replayed
922  fEventReplayed = 1;
923  }
924 
925  // Prepares new event for replaying
926  if (!PrepareNextEvent()) {
927  // No more events to be replayed (replaying has finished).
928 
929  // Switches recorder back to INACTIVE state
930  Info("TRecorderReplaying::ReplayRealtime", "Replaying finished");
931  fRecorder->ChangeState(new TRecorderInactive());
932  return;
933  }
934  else {
935  // We have event to replay here.
936 
937  // It will be replayed with the same time difference to the previous
938  // one as when recording.
939  // After given time, timer will call this method again
940  if (fNextEvent)
941  fTimer->Start(Long_t(fNextEvent->GetTime() - fPreviousEventTime));
942  }
943 }
944 
945 ////////////////////////////////////////////////////////////////////////////////
946 /// Pauses replaying
947 
949 {
950  fTimer->Stop();
951  r->ChangeState(new TRecorderPaused(this), kFALSE);
952  Info("TRecorderReplaying::Pause", "Replaying paused.");
953 }
954 
955 ////////////////////////////////////////////////////////////////////////////////
956 /// Cancels replaying
957 
959 {
960  Info("TRecorderReplaying::ReplayStop", "Replaying cancelled");
961  r->ChangeState(new TRecorderInactive());
962 }
963 
964 ////////////////////////////////////////////////////////////////////////////////
965 /// Continues previously paused replaying
966 
968 {
969  if (fNextEvent)
970  fTimer->Start(Long_t(fNextEvent->GetTime() - fPreviousEventTime));
971 }
972 
973 //______________________________________________________________________________
974 // Represents state of TRecorder after its creation
975 
977 
978 ////////////////////////////////////////////////////////////////////////////////
979 /// Switches from INACTIVE state to RECORDING and starts recording
980 
981 void TRecorderInactive::Start(TRecorder *r, const char *filename,
982  Option_t *option, Window_t *w, Int_t winCount)
983 {
984  // const char *filename = name of ROOT file where to store recorded events
985  // Option_t *option = option for creation of ROOT file
986  // Window_t *w = list of IDs of recorder windows (if GUI for
987  // recorder is used) [0 by default]
988  // Int_t winCount = number of IDs it this list [0 by default]
989 
990  TRecorderRecording *rec = new TRecorderRecording(r, filename, option, w, winCount);
991  if (rec->StartRecording()) {
992  r->ChangeState(rec);
993  r->fFilename = gSystem->BaseName(filename);
994  }
995  else
996  delete rec;
997 }
998 
999 ////////////////////////////////////////////////////////////////////////////////
1000 /// Switches from INACTIVE state of recorder to REPLAYING
1001 /// Return kTRUE if replaying has started or kFALSE if it is not possible
1002 /// (bad file etc.)
1003 
1005  Bool_t showMouseCursor,
1007 {
1008  // const char *filename = name of ROOT file from where to replay recorded
1009  // events
1010  // TRecorder::EReplayModes mode = mode of replaying
1011 
1012  TRecorderReplaying *replay = new TRecorderReplaying(filename);
1013 
1014  if (replay->Initialize(r, showMouseCursor, mode)) {
1015  r->ChangeState(replay);
1016  r->fFilename = gSystem->BaseName(filename);
1017  return kTRUE;
1018  }
1019  else {
1020  delete replay;
1021  return kFALSE;
1022  }
1023 }
1024 
1025 ////////////////////////////////////////////////////////////////////////////////
1026 /// Prints out commandline events recorded in given file
1027 
1028 void TRecorderInactive::ListCmd(const char *filename)
1029 {
1030  /*
1031  if (!TClassTable::GetDict(" TRecCmdEvent")) {
1032  Error("TRecorderInactive::List", " TRecCmdEvent not in dictionary.");
1033  return;
1034  }*/
1035 
1036  TFile *file = TFile::Open(filename);
1037  if (!file) return;
1038  if (file->IsZombie() || !file->IsOpen()) {
1039  delete file;
1040  return;
1041  }
1042  TTree *t1 = (TTree*)file->Get(kCmdEventTree);
1043 
1044  if (!t1) {
1045  Error("TRecorderInactive::List",
1046  "The ROOT file is not valid event logfile.");
1047  delete file;
1048  return;
1049  }
1050 
1051  TRecCmdEvent *fCmdEvent = new TRecCmdEvent();
1052  t1->SetBranchAddress(kBranchName, &fCmdEvent);
1053 
1054  Int_t entries = t1->GetEntries();
1055  for (Int_t i = 0; i < entries; ++i) {
1056  t1->GetEntry(i);
1057  std::cout << "[" << i << "] " << "fTime=" <<
1058  (ULong64_t) fCmdEvent->GetTime() << " fText=" <<
1059  fCmdEvent->GetText() << std::endl;
1060  }
1061  std::cout << std::endl;
1062 
1063  delete fCmdEvent;
1064  delete file;
1065 }
1066 
1067 ////////////////////////////////////////////////////////////////////////////////
1068 /// Prints out GUI events recorded in given file
1069 
1070 void TRecorderInactive::ListGui(const char *filename)
1071 {
1072  /*
1073  if (!TClassTable::GetDict("TRecGuiEvent")) {
1074  Error("TRecorderInactive::ListGui",
1075  "TRecGuiEvent not in the dictionary.");
1076  return;
1077  }*/
1078 
1079  TFile *file = TFile::Open(filename);
1080  if (!file) return;
1081  if (file->IsZombie() || !file->IsOpen()) {
1082  delete file;
1083  return;
1084  }
1085  TTree *t1 = (TTree*)file->Get(kGuiEventTree);
1086 
1087  if (!t1) {
1088  Error("TRecorderInactive::ListGui",
1089  "The ROOT file is not valid event logfile.");
1090  delete file;
1091  return;
1092  }
1093 
1094  TRecGuiEvent *guiEvent = new TRecGuiEvent();
1095  t1->SetBranchAddress(kBranchName, &guiEvent);
1096 
1097  Int_t entries = t1->GetEntries();
1098 
1099  for (Int_t i = 0; i < entries ; ++i) {
1100  t1->GetEntry(i);
1101  DumpRootEvent(guiEvent, i);
1102  }
1103 
1104  delete file;
1105  delete guiEvent;
1106 }
1107 
1108 ////////////////////////////////////////////////////////////////////////////////
1109 /// Prints out attributes of one GUI event TRecGuiEvent *e
1110 /// Int_n n is number of event if called in cycle
1111 
1113 {
1114  std::ios::fmtflags f = std::cout.flags(); // store flags
1115  std::cout << "[" << n << "] " << std::dec << std::setw(10)
1116  << e->GetTime().AsString() << std::setw(15) << kRecEventNames[e->fType]
1117  << " fW:" << std::hex << e->fWindow
1118  << " t:" << std::dec << e->fTime
1119  << " x:" << DisplayValid(e->fX)
1120  << " y:" << DisplayValid(e->fY)
1121  << " fXR:" << DisplayValid(e->fXRoot)
1122  << " fYR:" << DisplayValid(e->fYRoot)
1123  << " c:" << DisplayValid(e->fCode)
1124  << " s:" << DisplayValid(e->fState)
1125  << " w:" << DisplayValid(e->fWidth)
1126  << " h:" << DisplayValid(e->fHeight)
1127  << " cnt:" << DisplayValid(e->fCount)
1128  << " se:" << e->fSendEvent
1129  << " h:" << e->fHandle
1130  << " fF:" << DisplayValid(e->fFormat)
1131  << " | ";
1132 
1133  for (Int_t i=0; i<5; ++i)
1134  if (DisplayValid(e->fUser[i]) != -1)
1135  std::cout << "[" << i << "]=" << DisplayValid(e->fUser[i]);
1136 
1137  if (e->fMasked)
1138  std::cout << " | fM:" << std::hex << e->fMasked;
1139 
1140  std::cout << std::endl;
1141  std::cout.flags( f ); // restore flags (reset std::hex)
1142 }
1143 
1144 ////////////////////////////////////////////////////////////////////////////////
1145 /// Save previous canvases in a .root file
1146 
1147 void TRecorderInactive::PrevCanvases(const char *filename, Option_t *option)
1148 {
1149  fCollect = gROOT->GetListOfCanvases();
1150  TFile *f = TFile::Open(filename, option);
1151  if (f && !f->IsZombie()) {
1152  fCollect->Write();
1153  f->Close();
1154  delete f;
1155  }
1156 }
1157 
1158 //______________________________________________________________________________
1159 // Represents state of TRecorder when paused
1160 
1162 
1163 ////////////////////////////////////////////////////////////////////////////////
1164 /// Rememeber the recorder state that is paused
1165 
1167 {
1168  fReplayingState = state;
1169 }
1170 
1171 ////////////////////////////////////////////////////////////////////////////////
1172 /// Continues replaying
1173 
1175 {
1176  fReplayingState->Continue();
1177  Info("TRecorderPaused::Resume", "Replaying resumed");
1178 
1179  // Switches back to the previous replaying state
1180  r->ChangeState(fReplayingState);
1181 }
1182 
1183 ////////////////////////////////////////////////////////////////////////////////
1184 /// Replaying is cancelled
1185 
1187 {
1188  delete fReplayingState;
1189 
1190  Info("TRecorderReplaying::ReplayStop", "Reaplying cancelled");
1191  r->ChangeState(new TRecorderInactive());
1192 }
1193 
1194 
1195 //______________________________________________________________________________
1196 // Represents state of TRecorder when recording events
1197 
1199 
1200 ////////////////////////////////////////////////////////////////////////////////
1201 /// Initializes TRecorderRecording for recording
1202 /// What is allocated here is deleted in destructor
1203 
1205  Option_t *option, Window_t *w,
1206  Int_t winCount)
1207 {
1208  fRecorder = r;
1209  fBeginPave = 0;
1210 
1211  // Remember window IDs of GUI recorder (appropriate events are
1212  // filtered = not recorded)
1213  fFilteredIdsCount = winCount;
1214  fFilteredIds = new Window_t[fFilteredIdsCount];
1215  for(Int_t i=0; i < fFilteredIdsCount; ++i)
1216  fFilteredIds[i] = w[i];
1217 
1218  // No unhandled commandline event in the beginning
1219  fCmdEventPending = kFALSE;
1220 
1221  // Filer pave events (mouse button move)
1222  fFilterEventPave = kFALSE;
1223 
1224  // No registered windows in the beginning
1225  fRegWinCounter = 0;
1226 
1227  // New timer for recording
1228  fTimer = new TTimer(25, kTRUE);
1229 
1230  fMouseTimer = new TTimer(50, kTRUE);
1231  fMouseTimer->Connect("Timeout()", "TRecorderRecording", this,
1232  "RecordMousePosition()");
1233 
1234  // File where store recorded events
1235  fFile = TFile::Open(filename, option);
1236 
1237  // TTrees with windows, commandline events and GUi events
1238  fWinTree = new TTree(kWindowsTree, "Windows");
1239  fCmdTree = new TTree(kCmdEventTree, "Commandline events");
1240  fGuiTree = new TTree(kGuiEventTree, "GUI events");
1241  fExtraTree = new TTree(kExtraEventTree, "Extra events");
1242 
1243  fWin = 0;
1244  fCmdEvent = new TRecCmdEvent();
1245  fGuiEvent = new TRecGuiEvent();
1246  fExtraEvent = new TRecExtraEvent();
1247 }
1248 
1249 ////////////////////////////////////////////////////////////////////////////////
1250 /// Freeing of allocated memory
1251 
1253 {
1254  delete[] fFilteredIds;
1255 
1256  if (fFile)
1257  delete fFile;
1258  delete fMouseTimer;
1259  delete fTimer;
1260  delete fCmdEvent;
1261  delete fGuiEvent;
1262  delete fExtraEvent;
1263 }
1264 
1265 ////////////////////////////////////////////////////////////////////////////////
1266 /// Connects appropriate signals and slots in order to gain all registered
1267 /// windows and processed events in ROOT and then starts recording
1268 
1270 {
1271  if (!fFile || fFile->IsZombie() || !fFile->IsOpen())
1272  return kFALSE;
1273 
1274  // When user types something in the commandline,
1275  // TRecorderRecording::RecordCmdEvent(const char *line) is called
1276  gApplication->Connect("LineProcessed(const char*)", "TRecorderRecording",
1277  this, "RecordCmdEvent(const char*)");
1278 
1279  // When a new window in ROOT is registered,
1280  // TRecorderRecording::RegisterWindow(Window_t) is called
1281  gClient->Connect("RegisteredWindow(Window_t)", "TRecorderRecording", this,
1282  "RegisterWindow(Window_t)");
1283 
1284  // When a GUI event (different from kConfigureNotify) is processed in
1285  // TGClient::HandleEvent or in TGClient::HandleMaskEvent,
1286  // TRecorderRecording::RecordGuiEvent(Event_t*, Window_t) is called
1287  gClient->Connect("ProcessedEvent(Event_t*, Window_t)", "TRecorderRecording",
1288  this, "RecordGuiEvent(Event_t*, Window_t)");
1289 
1290  // When a kConfigureNotify event is processed in TGFrame::HandleEvent,
1291  // TRecorderRecording::RecordGuiCNEvent(Event_t*) is called
1292  TQObject::Connect("TGFrame", "ProcessedConfigure(Event_t*)",
1293  "TRecorderRecording", this, "RecordGuiCNEvent(Event_t*)");
1294 
1295  // When a PaveLabel is created, TRecorderRecording::RecordPave(TObject*)
1296  // is called
1297  TQObject::Connect("TPad", "RecordPave(const TObject*)", "TRecorderRecording",
1298  this, "RecordPave(const TObject*)");
1299 
1300  // When a Text is created, TRecorderRecording::RecordText() is called
1301  TQObject::Connect("TPad", "RecordLatex(const TObject*)",
1302  "TRecorderRecording", this, "RecordText(const TObject*)");
1303 
1304  // When a PaveLabel is created, TRecorderRecording::FilterEventPave()
1305  // is called to filter mouse clicks events.
1306  TQObject::Connect("TPad", "EventPave()", "TRecorderRecording", this,
1307  "FilterEventPave()");
1308 
1309  // When starting editing a TLatex or a TPaveLabel, StartEditing()
1310  // is called to memorize edition starting time.
1311  TQObject::Connect("TPad", "StartEditing()", "TRecorderRecording", this,
1312  "StartEditing()");
1313 
1314  // Gui Builder specific events.
1315  TQObject::Connect("TGuiBldDragManager", "TimerEvent(Event_t*)",
1316  "TRecorderRecording", this, "RecordGuiBldEvent(Event_t*)");
1317 
1318  // Creates in TTrees appropriate branches to store registered windows,
1319  // commandline events and GUI events
1320  fWinTree->Branch(kBranchName, &fWin, "fWin/l");
1321  fCmdTree->Branch(kBranchName, " TRecCmdEvent", &fCmdEvent);
1322  fGuiTree->Branch(kBranchName, "TRecGuiEvent", &fGuiEvent);
1323  fExtraTree->Branch(kBranchName, "TRecExtraEvent", &fExtraEvent);
1324 
1325  Int_t numCanvases = gROOT->GetListOfCanvases()->LastIndex();
1326 
1327  if (numCanvases >= 0){
1328 
1329  TIter nextwindow (gClient->GetListOfWindows());
1330  TGWindow *twin;
1331  Window_t twin2;
1332  Int_t cnt = 0;
1333  while ((twin = (TGWindow*) nextwindow())) {
1334  twin2 = (Window_t) twin->GetId();
1335  if (IsFiltered(twin2)) {
1336  if (gDebug > 0) {
1337  std::cout << "WindowID "<< twin2 << " filtered" << std::endl;
1338  }
1339  }
1340  else if (twin != gClient->GetRoot()) {
1341  RegisterWindow(twin2);
1342  }
1343  cnt++;
1344  }
1345  //Info("TRecorderRecording::StartRecording", "Previous Canvases");
1346  }
1347 
1348  // Starts the timer for recording
1349  fTimer->TurnOn();
1350 
1351  // start mouse events recording timer
1352  fMouseTimer->Start(50);
1353 
1354  Info("TRecorderRecording::StartRecording", "Recording started. Log file: %s",
1355  fFile->GetName());
1356 
1357  return kTRUE;
1358 }
1359 
1360 ////////////////////////////////////////////////////////////////////////////////
1361 /// Disconnects all slots and stopps recording.
1362 
1364 {
1365  TQObject::Disconnect("TGuiBldDragManager", "TimerEvent(Event_t*)", this,
1366  "RecordGuiBldEvent(Event_t*)");
1367  TQObject::Disconnect("TGFrame", "ProcessedConfigure(Event_t*)", this,
1368  "RecordGuiCNEvent(Event_t*)");
1369  TQObject::Disconnect("TPad", "RecordPave(const TObject*)", this,
1370  "RecordPave(const TObject*)");
1371  TQObject::Disconnect("TPad", "RecordLatex(const TObject*)", this,
1372  "RecordText(const TObject*)");
1373  TQObject::Disconnect("TPad", "EventPave()", this, "FilterEventPave()");
1374  TQObject::Disconnect("TPad", "StartEditing()", this, "StartEditing()");
1375  gClient->Disconnect(gClient, "ProcessedEvent(Event_t*, Window_t)", this,
1376  "RecordGuiEvent(Event_t*, Window_t)");
1377  gClient->Disconnect(gClient, "RegisteredWindow(Window_t)", this,
1378  "RegisterWindow(Window_t)");
1379  gApplication->Disconnect(gApplication, "LineProcessed(const char*)", this,
1380  "RecordCmdEvent(const char*)");
1381 
1382  // Decides if to store the last event. It is stored if GUI recorder is used,
1383  // otherwise it is 'TEventRecorded::Stop' and should not be stored
1384  if (fCmdEventPending && guiCommand)
1385  fCmdTree->Fill();
1386 
1387  fRecorder->Write("recorder");
1388  fFile->Write();
1389  fFile->Close();
1390  fTimer->TurnOff();
1391 
1392  fMouseTimer->TurnOff();
1393 
1394  Info("TRecorderRecording::Stop", "Recording finished.");
1395 
1396  fRecorder->ChangeState(new TRecorderInactive());
1397 }
1398 
1399 ////////////////////////////////////////////////////////////////////////////////
1400 /// This method is called when RegisteredWindow(Window_t) is emitted from
1401 /// TGClient.
1402 
1404 {
1405  // Stores ID of the registered window in appropriate TTree
1406  fWin = (ULong64_t) w;
1407  fWinTree->Fill();
1408 }
1409 
1410 ////////////////////////////////////////////////////////////////////////////////
1411 /// Records commandline event (text and time) ans saves the previous
1412 /// commandline event
1413 /// This 1 event delay in saving ensures that the last commandline events
1414 /// 'TRecorder::Stop' will be not stored
1415 
1417 {
1418  // If there is some previously recorded event, saves it in TTree now
1419  if (fCmdEventPending)
1420  fCmdTree->Fill();
1421 
1422  // Fill information about this new commandline event: command text and
1423  // time of event execution
1424  fCmdEvent->SetTime(fTimer->GetAbsTime());
1425  fCmdEvent->SetText((char*)line);
1426 
1427  // This event will be stored next time (if it is not the last one
1428  // 'TRecorder::Stop')
1429  fCmdEventPending = kTRUE;
1430  return;
1431 }
1432 
1433 ////////////////////////////////////////////////////////////////////////////////
1434 /// Records GUI Event_t *e different from kConfigureNotify (they are
1435 /// recorded in TRecorderRecording::RecordGuiCNEvent)
1436 ///
1437 /// It is called via signal-slot when an event is processed in
1438 /// TGClient::HandleEvent(Event_t *event)
1439 /// or in TGClient::HandleMaskEvent(Event_t *event, Window_t wid)
1440 ///
1441 /// If signal is emitted from TGClient::HandleEvent(Event_t *event),
1442 /// then wid = 0
1443 
1445 {
1446  // If this event is caused by a recorder itself (GUI recorder),
1447  // it is not recorded
1448  if (fFilteredIdsCount && IsFiltered(e->fWindow))
1449  return;
1450 
1451  // Doesn't record the mouse clicks when a pavelabel is recorded
1452  if (fFilterEventPave && (e->fCode == 1)) {
1453  fFilterEventPave = kFALSE;
1454  return;
1455  }
1456  fFilterEventPave = kFALSE;
1457 
1458  // don't record any copy/paste event, as event->fUser[x] parameters
1459  // will be invalid when replaying on a different OS
1460  if (e->fType == kSelectionClear || e->fType == kSelectionRequest ||
1461  e->fType == kSelectionNotify)
1462  return;
1463 
1464  // Copies all items of e to fGuiEvent
1465  CopyEvent(e, wid);
1466 
1467  // Saves time of recording
1468  fGuiEvent->SetTime(fTimer->GetAbsTime());
1469 
1470  // Saves recorded event itself in TTree
1471  fGuiTree->Fill();
1472 }
1473 
1474 ////////////////////////////////////////////////////////////////////////////////
1475 /// Special case for the gui builder, having a timer handling some of the
1476 /// events.
1477 
1479 {
1480  e->fFormat = e->fType;
1481  e->fType = kOtherEvent;
1482 
1483  // Copies all items of e to fGuiEvent
1484  CopyEvent(e, 0);
1485 
1486  // Saves time of recording
1487  fGuiEvent->SetTime(fTimer->GetAbsTime());
1488 
1489  // Saves recorded event itself in TTree
1490  fGuiTree->Fill();
1491 }
1492 
1493 ////////////////////////////////////////////////////////////////////////////////
1494 /// Try to record all mouse moves...
1495 
1497 {
1498  Window_t dum;
1499  Event_t ev;
1500  ev.fCode = 0;
1501  ev.fType = kMotionNotify;
1502  ev.fState = 0;
1503  ev.fWindow = 0;
1504  ev.fUser[0] = ev.fUser[1] = ev.fUser[2] = ev.fUser[3] = ev.fUser[4] = 0;
1505  ev.fCount = 0;
1506  ev.fFormat = 0;
1507  ev.fHandle = 0;
1508  ev.fHeight = 0;
1509  ev.fSendEvent = 0;
1510  ev.fTime = 0;
1511  ev.fWidth = 0;
1512 
1513  gVirtualX->QueryPointer(gVirtualX->GetDefaultRootWindow(), dum, dum,
1514  ev.fXRoot, ev.fYRoot, ev.fX, ev.fY, ev.fState);
1515  ev.fXRoot -= gDecorWidth;
1516  ev.fYRoot -= gDecorHeight;
1517 
1518  RecordGuiEvent(&ev, 0);
1519  fMouseTimer->Reset();
1520 }
1521 
1522 ////////////////////////////////////////////////////////////////////////////////
1523 /// Records GUI Event_t *e of type kConfigureNotify.
1524 /// It is called via signal-slot when an kConfigureNotify event is processed
1525 /// in TGFrame::HandleEvent
1526 
1528 {
1529  // If this event is caused by a recorder itself, it is not recorded
1530  if (fFilteredIdsCount && IsFiltered(e->fWindow))
1531  return;
1532 
1533  // Sets fUser[4] value to one of EConfigureNotifyType
1534  // According to this value, event is or is not replayed in the future
1535  SetTypeOfConfigureNotify(e);
1536 
1537  // Copies all items of e to fGuiEvent
1538  CopyEvent(e, 0);
1539 
1540  // Saves time of recording
1541  fGuiEvent->SetTime(fTimer->GetAbsTime());
1542 
1543  // Saves recorded event itself in TTree
1544  fGuiTree->Fill();
1545 }
1546 
1547 ////////////////////////////////////////////////////////////////////////////////
1548 /// Records TPaveLabel object created in TCreatePrimitives::Pave()
1549 
1551 {
1552  Long64_t extratime = fBeginPave;
1553  Long64_t interval = (Long64_t)fTimer->GetAbsTime() - fBeginPave;
1554  TPaveLabel *pavel = (TPaveLabel *) obj;
1555  const char *label;
1556  label = pavel->GetLabel();
1557  TString aux = "";
1558  TString cad = "";
1559  cad = "TPaveLabel *p = new TPaveLabel(";
1560  cad += pavel->GetX1();
1561  cad += ",";
1562  cad += pavel->GetY1();
1563  cad += ",";
1564  cad += pavel->GetX2();
1565  cad += ",";
1566  cad += pavel->GetY2();
1567  cad += ",\"\"); p->Draw(); gPad->Modified(); gPad->Update();";
1568  Int_t i, len = (Int_t)strlen(label);
1569  interval /= (len + 2);
1570  RecordExtraEvent(cad, extratime);
1571  for (i=0; i < len; ++i) {
1572  cad = "p->SetLabel(\"";
1573  cad += (aux += label[i]);
1574  cad += "\"); ";
1575 #ifndef R__WIN32
1576  cad += " p->SetTextFont(83); p->SetTextSizePixels(14); ";
1577 #endif
1578  cad += " gPad->Modified(); gPad->Update();";
1579  extratime += interval;
1580  RecordExtraEvent(cad, extratime);
1581  }
1582  cad = "p->SetTextFont(";
1583  cad += pavel->GetTextFont();
1584  cad += "); p->SetTextSize(";
1585  cad += pavel->GetTextSize();
1586  cad += "); gPad->Modified(); gPad->Update();";
1587  extratime += interval;
1588  RecordExtraEvent(cad, extratime);
1589 }
1590 
1591 ////////////////////////////////////////////////////////////////////////////////
1592 /// Records TLatex object created in TCreatePrimitives::Text()
1593 
1595 {
1596  Long64_t extratime = fBeginPave;
1597  Long64_t interval = (Long64_t)fTimer->GetAbsTime() - fBeginPave;
1598  TLatex *texto = (TLatex *) obj;
1599  const char *label;
1600  label = texto->GetTitle();
1601  TString aux = "";
1602  TString cad = "";
1603  cad = "TLatex *l = new TLatex(";
1604  cad += texto->GetX();
1605  cad += ",";
1606  cad += texto->GetY();
1607  cad += ",\"\"); l->Draw(); gPad->Modified(); gPad->Update();";
1608  Int_t i, len = (Int_t)strlen(label);
1609  interval /= (len + 2);
1610  RecordExtraEvent(cad, extratime);
1611  for (i=0; i < len; ++i) {
1612  cad = "l->SetTitle(\"";
1613  cad += (aux += label[i]);
1614  cad += "\"); ";
1615 #ifndef R__WIN32
1616  cad += " l->SetTextFont(83); l->SetTextSizePixels(14); ";
1617 #endif
1618  cad += " gPad->Modified(); gPad->Update();";
1619  extratime += interval;
1620  RecordExtraEvent(cad, extratime);
1621  }
1622  cad = "l->SetTextFont(";
1623  cad += texto->GetTextFont();
1624  cad += "); l->SetTextSize(";
1625  cad += texto->GetTextSize();
1626  cad += "); gPad->Modified(); gPad->Update();";
1627  cad += " TVirtualPad *spad = gPad->GetCanvas()->GetSelectedPad();";
1628  cad += " gPad->GetCanvas()->Selected(spad, l, kButton1Down);";
1629  extratime += interval;
1630  RecordExtraEvent(cad, extratime);
1631 }
1632 
1633 ////////////////////////////////////////////////////////////////////////////////
1634 /// Change the state of the flag to kTRUE when you are recording a pavelabel.
1635 
1637 {
1638  fFilterEventPave = kTRUE;
1639 }
1640 
1641 ////////////////////////////////////////////////////////////////////////////////
1642 /// Memorize the starting time of editinga TLatex or a TPaveLabel
1643 
1645 {
1646  fBeginPave = fTimer->GetAbsTime();
1647 }
1648 
1649 ////////////////////////////////////////////////////////////////////////////////
1650 /// Records TLatex or TPaveLabel object created in TCreatePrimitives,
1651 /// ExtTime is needed for the correct replay of these events.
1652 
1654 {
1655  fExtraEvent->SetTime(extTime);
1656  fExtraEvent->SetText(line);
1657  fExtraTree->Fill();
1658 }
1659 
1660 ////////////////////////////////////////////////////////////////////////////////
1661 /// Copies all items of given event to fGuiEvent
1662 
1664 {
1665  fGuiEvent->fType = e->fType;
1666  fGuiEvent->fWindow = e->fWindow;
1667  fGuiEvent->fTime = e->fTime;
1668 
1669  fGuiEvent->fX = e->fX;
1670  fGuiEvent->fY = e->fY;
1671  fGuiEvent->fXRoot = e->fXRoot;
1672  fGuiEvent->fYRoot = e->fYRoot;
1673 
1674  fGuiEvent->fCode = e->fCode;
1675  fGuiEvent->fState = e->fState;
1676 
1677  fGuiEvent->fWidth = e->fWidth;
1678  fGuiEvent->fHeight = e->fHeight;
1679 
1680  fGuiEvent->fCount = e->fCount;
1681  fGuiEvent->fSendEvent = e->fSendEvent;
1682  fGuiEvent->fHandle = e->fHandle;
1683  fGuiEvent->fFormat = e->fFormat;
1684 
1685  if (fGuiEvent->fHandle == gROOT_MESSAGE)
1686  fGuiEvent->fHandle = TRecGuiEvent::kROOT_MESSAGE;
1687 
1688  for(Int_t i=0; i<5; ++i)
1689  fGuiEvent->fUser[i] = e->fUser[i];
1690 
1691  if (fGuiEvent->fUser[0] == (Int_t)gWM_DELETE_WINDOW)
1692  fGuiEvent->fUser[0] = TRecGuiEvent::kWM_DELETE_WINDOW;
1693 
1694  if (e->fType == kGKeyPress || e->fType == kKeyRelease) {
1695  char tmp[10] = {0};
1696  UInt_t keysym = 0;
1697  gVirtualX->LookupString(e, tmp, sizeof(tmp), keysym);
1698  fGuiEvent->fCode = keysym;
1699  }
1700 
1701  fGuiEvent->fMasked = wid;
1702 }
1703 
1704 ////////////////////////////////////////////////////////////////////////////////
1705 /// Returns kTRUE if passed id belongs to window IDs of recorder GUI itself
1706 
1708 {
1709  for(Int_t i=0; i < fFilteredIdsCount; ++i)
1710  if (id == fFilteredIds[i])
1711  return kTRUE;
1712 
1713  return kFALSE;
1714 }
1715 
1716 ////////////////////////////////////////////////////////////////////////////////
1717 /// Sets type of kConfigureNotify event to one of EConfigureNotify
1718 ///
1719 /// On Linux paremeters of GUI event kConfigureNotify are different
1720 /// than parameters of the same event executed on Windows.
1721 /// Therefore we need to distinguish [on Linux], if the event is movement
1722 /// or resize event.
1723 /// On Windows, we do not need to distinguish them.
1724 
1726 {
1727  // On both platforms, we mark the events matching the criteria
1728  // (automatically generated in ROOT) as events that should be filtered
1729  // when replaying (TRecGuiEvent::kCNFilter)
1730  if ((e->fX == 0 && e->fY == 0)) { // || e->fFormat == 32 ) {
1732  return;
1733  }
1734 
1735 #ifdef WIN32
1736 
1737  // No need to distinguish between move and resize on Windows
1739 
1740 #else
1741 
1742  TGWindow *w = gClient->GetWindowById(e->fWindow);
1743  if (w) {
1744  TGFrame *t = (TGFrame *)w;
1745 
1746  // If this event does not cause any change in position or size ->
1747  // automatically generated event
1748  if (t->GetWidth() == e->fWidth && t->GetHeight() == e->fHeight &&
1749  e->fX == t->GetX() && e->fY == t->GetY()) {
1751  }
1752  else {
1753  // Size of the window did not change -> move
1754  if (t->GetWidth() == e->fWidth && t->GetHeight() == e->fHeight) {
1755  e->fUser[4] = TRecGuiEvent::kCNMove;
1756  }
1757  // Size of the window changed -> resize
1758  else {
1760  }
1761  }
1762  }
1763 
1764 #endif
1765 }
1766 
1767 
1768 
1769 //______________________________________________________________________________
1770 // The GUI for the recorder
1771 
1773 
1774 ////////////////////////////////////////////////////////////////////////////////
1775 /// The GUI for the recorder
1776 
1778  TGMainFrame(p ? p : gClient->GetRoot(), w, h)
1779 {
1780  TGHorizontalFrame *hframe;
1781  TGVerticalFrame *vframe;
1782  SetCleanup(kDeepCleanup);
1783  fRecorder = new TRecorder();
1784  fFilteredIds[0] = GetId();
1785 
1786  // Create a horizontal frame widget with buttons
1787  hframe = new TGHorizontalFrame(this, 200, 75, kChildFrame | kFixedHeight,
1788  (Pixel_t)0x000000);
1789  fFilteredIds[1] = hframe->GetId();
1790 
1791  // LABEL WITH TIME
1792 
1793  vframe = new TGVerticalFrame(hframe, 200, 75, kChildFrame | kFixedHeight,
1794  (Pixel_t)0x000000);
1795  fFilteredIds[2] = vframe->GetId();
1796 
1797  TGLabel *fStatusLabel = new TGLabel(vframe, "Status:");
1798  fStatusLabel->SetTextColor(0x7cffff);
1799  fStatusLabel->SetBackgroundColor((Pixel_t)0x000000);
1800  vframe->AddFrame(fStatusLabel, new TGLayoutHints(kLHintsLeft | kLHintsTop,
1801  2, 2, 2, 2));
1802  fFilteredIds[3] = fStatusLabel->GetId();
1803 
1804  TGLabel *fTimeLabel = new TGLabel(vframe, "Time: ");
1805  fTimeLabel->SetTextColor(0x7cffff);
1806  fTimeLabel->SetBackgroundColor((Pixel_t)0x000000);
1807  vframe->AddFrame(fTimeLabel, new TGLayoutHints(kLHintsLeft | kLHintsTop,
1808  2, 2, 13, 2));
1809  fFilteredIds[4] = fTimeLabel->GetId();
1810 
1811  hframe->AddFrame(vframe, new TGLayoutHints(kLHintsLeft | kLHintsExpandY));
1812 
1813  vframe = new TGVerticalFrame(hframe, 200, 75, kChildFrame | kFixedHeight,
1814  (Pixel_t)0x000000);
1815  fFilteredIds[5] = vframe->GetId();
1816 
1817  fStatus = new TGLabel(vframe, "Inactive");
1818  fStatus->SetTextColor(0x7cffff);
1819  fStatus->SetBackgroundColor((Pixel_t)0x000000);
1820  vframe->AddFrame(fStatus, new TGLayoutHints(kLHintsLeft | kLHintsTop,
1821  2, 2, 2, 2));
1822  fFilteredIds[6] = fStatus->GetId();
1823 
1824  fTimeDisplay = new TGLabel(vframe, "00:00:00");
1825  fTimeDisplay->SetTextColor(0x7cffff);
1826  fTimeDisplay->SetTextFont("Helvetica -34", kFALSE);
1827  fTimeDisplay->SetBackgroundColor((Pixel_t)0x000000);
1828  vframe->AddFrame(fTimeDisplay, new TGLayoutHints(kLHintsLeft | kLHintsTop,
1829  2, 2, 2, 2));
1830  fFilteredIds[7] = fTimeDisplay->GetId();
1831 
1832  hframe->AddFrame(vframe, new TGLayoutHints(kLHintsLeft | kLHintsExpandY,
1833  10, 0, 0, 0));
1834  AddFrame(hframe, new TGLayoutHints(kLHintsExpandX, 2, 2, 2, 2));
1835 
1836  // Create a horizontal frame widget with buttons
1837  hframe = new TGHorizontalFrame(this, 200, 200);
1838  fFilteredIds[8] = hframe->GetId();
1839 
1840  // START-STOP button
1841  fStartStop = new TGPictureButton(hframe,gClient->GetPicture("record.png"));
1842  fStartStop->SetStyle(gClient->GetStyle());
1843  fStartStop->Connect("Clicked()","TGRecorder",this,"StartStop()");
1844  hframe->AddFrame(fStartStop, new TGLayoutHints(kLHintsLeft | kLHintsTop,
1845  2, 2, 2, 2));
1846  fStartStop->Resize(40,40);
1847  fFilteredIds[9] = fStartStop->GetId();
1848 
1849  // REPLAY button
1850  fReplay = new TGPictureButton(hframe,gClient->GetPicture("replay.png"));
1851  fReplay->SetStyle(gClient->GetStyle());
1852  fReplay->Connect("Clicked()","TGRecorder",this,"Replay()");
1853  hframe->AddFrame(fReplay, new TGLayoutHints(kLHintsLeft | kLHintsTop,
1854  2, 2, 2, 2));
1855  fReplay->Resize(40,40);
1856  fFilteredIds[10] = fReplay->GetId();
1857 
1858  // MOUSE CURSOR CHECKBOX
1859  fCursorCheckBox = new TGCheckButton(this,"Show mouse cursor");
1860  AddFrame(fCursorCheckBox, new TGLayoutHints(kLHintsCenterX, 2, 2, 2, 2));
1861  fFilteredIds[11] = fCursorCheckBox->GetId();
1862 
1863  // Timer
1864  fTimer = new TTimer(25);
1865  fTimer->Connect("Timeout()", "TGRecorder", this, "Update()");
1866 
1867  AddFrame(hframe, new TGLayoutHints(kLHintsCenterX, 2, 2, 2, 2));
1868 
1869  SetEditDisabled(kEditDisable | kEditDisableGrab);
1870  SetWindowName("ROOT Event Recorder");
1871  MapSubwindows();
1872  Layout();
1873  MapWindow();
1874 
1875  SetDefault();
1876 }
1877 
1878 ////////////////////////////////////////////////////////////////////////////////
1879 /// Sets GUI to the default inactive state
1880 
1882 {
1883  fTimeDisplay->SetText("00:00:00");
1884 
1885  fReplay->SetPicture(gClient->GetPicture("replay.png"));
1886  fReplay->SetEnabled(kTRUE);
1887 
1888  fCursorCheckBox->SetEnabled(kTRUE);
1889  fCursorCheckBox->SetOn(kTRUE);
1890 
1891  fStartStop->SetPicture(gClient->GetPicture("record.png"));
1892  fStartStop->SetEnabled(kTRUE);
1893 }
1894 
1895 ////////////////////////////////////////////////////////////////////////////////
1896 /// Called when fTimer timeouts (every 0.025 second)
1897 /// Updates GUI of recorder
1898 
1900 {
1901  struct tm *running;
1902  static int cnt = 0;
1903  TString stime;
1904  time( &fElapsed );
1905  time_t elapsed_time = (time_t)difftime( fElapsed, fStart );
1906  running = gmtime( &elapsed_time );
1907 
1908  switch(fRecorder->GetState()) {
1909 
1910  // When recording or replaying, updates timer
1911  // and displays new value of seconds counter
1912  case TRecorder::kRecording:
1913  case TRecorder::kReplaying:
1914 
1915  // Every whole second: updates timer and displays new value
1916  if (cnt >= 10) {
1917  if (fRecorder->GetState() == TRecorder::kReplaying)
1918  fStatus->SetText("Replaying");
1919  else
1920  fStatus->SetText("Recording");
1921  stime.Form("%02d:%02d:%02d", running->tm_hour,
1922  running->tm_min, running->tm_sec);
1923  fTimeDisplay->SetText(stime.Data());
1924 
1925  cnt = 0;
1926  if (gVirtualX->EventsPending()) {
1927  fStatus->SetText("Waiting...");
1928  fStatus->SetTextColor((Pixel_t)0xff0000);
1929  }
1930  else {
1931  fStatus->SetTextColor((Pixel_t)0x7cffff);
1932  }
1933  fStatus->Resize();
1934  fTimeDisplay->Resize();
1935  }
1936  else
1937  ++cnt;
1938 
1939  // Changes background color according to the queue of pending events
1940  fTimer->Reset();
1941  break;
1942 
1943  // End of replaying or recording. Sets recorder GUI to default state
1944  case TRecorder::kInactive:
1945  fStatus->SetText("Inactive");
1946  fStatus->SetTextColor((Pixel_t)0x7cffff);
1947  fStatus->Resize();
1948  fTimer->TurnOff();
1949  SetDefault();
1950  break;
1951 
1952  default:
1953  break;
1954  }
1955 }
1956 
1957 ////////////////////////////////////////////////////////////////////////////////
1958 /// Handles push of the fStartStop button
1959 /// according to the current recorder state
1960 
1962 {
1963  static const char *gFiletypes[] = {
1964  "All files", "*", "Text files", "*.txt", "ROOT files", "*.root", 0, 0
1965  };
1966  TGFileInfo fi;
1967 
1968  switch(fRecorder->GetState()) {
1969 
1970  // Starts recording
1971  case TRecorder::kInactive:
1972 
1973  fi.fFileTypes = gFiletypes;
1974  fi.fOverwrite = kFALSE;
1975 
1976  new TGFileDialog(gClient->GetDefaultRoot(),
1977  gClient->GetDefaultRoot(),
1978  kFDSave,&fi);
1979 
1980  if (fi.fFilename && strlen(fi.fFilename)) {
1981 
1982  if (!gROOT->GetListOfCanvases()->IsEmpty()) {
1983  fRecorder->PrevCanvases(fi.fFilename, "RECREATE");
1984  fRecorder->Start(fi.fFilename, "UPDATE", fFilteredIds,
1985  fgWidgetsCount);
1986  }
1987  else {
1988  fRecorder->Start(fi.fFilename, "RECREATE", fFilteredIds,
1989  fgWidgetsCount);
1990  }
1991  fCursorCheckBox->SetDisabledAndSelected(kTRUE);
1992  fStartStop->SetPicture(gClient->GetPicture("stop.png"));
1993  fReplay->SetEnabled(kFALSE);
1994  fTimer->TurnOn();
1995  time( &fStart );
1996  }
1997  break;
1998 
1999  // Stops recording
2000  case TRecorder::kRecording:
2001  fRecorder->Stop(kTRUE);
2002  break;
2003 
2004  // Pauses replaying
2005  case TRecorder::kReplaying:
2006  fRecorder->Pause();
2007  fStartStop->SetPicture(gClient->GetPicture("replay.png"));
2008  break;
2009 
2010  // Resumes replaying
2011  case TRecorder::kPaused:
2012  fRecorder->Resume();
2013  fStartStop->SetPicture(gClient->GetPicture("pause.png"));
2014  break;
2015 
2016  default:
2017  break;
2018  } // switch
2019 }
2020 
2021 ////////////////////////////////////////////////////////////////////////////////
2022 /// Handles push of fReplay button
2023 /// according to the current recorder state
2024 
2026 {
2027  TGFileInfo fi;
2028 
2029  switch(fRecorder->GetState()) {
2030 
2031  // Starts replaying
2032  case TRecorder::kInactive:
2033 
2034  new TGFileDialog(gClient->GetDefaultRoot(),
2035  gClient->GetDefaultRoot(),
2036  kFDOpen, &fi);
2037 
2038  if (fi.fFilename && strlen(fi.fFilename)) {
2039  if (fRecorder->Replay(fi.fFilename, fCursorCheckBox->IsOn())) {
2040 
2041  fTimer->TurnOn();
2042  time( &fStart );
2043 
2044  fReplay->SetPicture(gClient->GetPicture("stop.png"));
2045  fStartStop->SetPicture(gClient->GetPicture("pause.png"));
2046 
2047  if (fCursorCheckBox->IsOn())
2048  fStartStop->SetEnabled(kFALSE);
2049 
2050  fCursorCheckBox->SetEnabled(kFALSE);
2051  }
2052  }
2053  break;
2054 
2055  // Stops replaying
2056  case TRecorder::kReplaying:
2057  case TRecorder::kPaused:
2058  fRecorder->ReplayStop();
2059  break;
2060 
2061  default:
2062  break;
2063 
2064  } // switch
2065 }
2066 
2067 ////////////////////////////////////////////////////////////////////////////////
2068 /// Destructor. Cleanup the GUI.
2069 
2071 {
2072  fTimer->TurnOff();
2073  delete fTimer;
2074  Cleanup();
2075 }
2076 
2077 //______________________________________________________________________________
2078 // Helper class
2079 
2082 
2083 ////////////////////////////////////////////////////////////////////////////////
2084 /// Replays stored GUI event
2085 
2086 void TRecGuiEvent::ReplayEvent(Bool_t showMouseCursor)
2087 {
2088  Int_t px, py, dx, dy;
2089  Window_t wtarget;
2090  Event_t *e = CreateEvent(this);
2091 
2092  // don't try to replay any copy/paste event, as event->fUser[x]
2093  // parameters are invalid on different OSes
2094  if (e->fType == kSelectionClear || e->fType == kSelectionRequest ||
2095  e->fType == kSelectionNotify) {
2096  delete e;
2097  return;
2098  }
2099 
2100  // Replays movement/resize event
2101  if (e->fType == kConfigureNotify) {
2102  TGWindow *w = gClient->GetWindowById(e->fWindow);
2103 
2104  // Theoretically, w should always exist (we found the right mapping,
2105  // otherwise we would not get here).
2106  // Anyway, it can happen that it was destroyed by some earlier ROOT event
2107  // We give higher priority to automatically generated
2108  // ROOT events in TRecorderReplaying::ReplayRealtime.
2109 
2110  if (w) {
2111  WindowAttributes_t attr;
2112  if (e->fUser[4] == TRecGuiEvent::kCNMove) {
2113  // Linux: movement of the window
2114  // first get window attribute to compensate the border size
2115  gVirtualX->GetWindowAttributes(e->fWindow, attr);
2116  if ((e->fX - attr.fX > 0) && (e->fY - attr.fY > 0))
2117  w->Move(e->fX - attr.fX, e->fY - attr.fY);
2118  }
2119  else {
2120  if (e->fUser[4] == TRecGuiEvent::kCNResize) {
2121  // Linux: resize of the window
2122  w->Resize(e->fWidth, e->fHeight);
2123  }
2124  else {
2125  if (e->fUser[4] == TRecGuiEvent::kCNMoveResize) {
2126  // Windows: movement or resize of the window
2127  w->MoveResize(e->fX, e->fY, e->fWidth, e->fHeight);
2128  }
2129  else {
2130  if (gDebug > 0)
2131  Error("TRecGuiEvent::ReplayEvent",
2132  "kConfigureNotify: Unknown value: fUser[4] = %ld ",
2133  e->fUser[4]);
2134  }
2135  }
2136  }
2137  }
2138  else {
2139  // w = 0
2140  if (gDebug > 0)
2141  Error("TRecGuiEvent::ReplayEvent",
2142  "kConfigureNotify: Window does not exist anymore ");
2143  }
2144  delete e;
2145  return;
2146 
2147  } // kConfigureNotify
2148 
2149  if (showMouseCursor && e->fType == kButtonPress) {
2150  gVirtualX->TranslateCoordinates(e->fWindow, gVirtualX->GetDefaultRootWindow(),
2151  e->fX, e->fY, px, py, wtarget);
2152  dx = px - gCursorWin->GetX();
2153  dy = py - gCursorWin->GetY();
2154  if (TMath::Abs(dx) > 5) gDecorWidth += dx;
2155  if (TMath::Abs(dy) > 5) gDecorHeight += dy;
2156  }
2157  // Displays fake mouse cursor for MotionNotify event
2158  if (showMouseCursor && e->fType == kMotionNotify) {
2159  if (gCursorWin && e->fWindow == gVirtualX->GetDefaultRootWindow()) {
2160  if (!gCursorWin->IsMapped()) {
2161  gCursorWin->MapRaised();
2162  }
2163  if (gVirtualX->GetDrawMode() == TVirtualX::kCopy) {
2164 //#ifdef R__MACOSX
2165  // this may have side effects (e.g. stealing focus)
2166  gCursorWin->RaiseWindow();
2167 //#endif
2168  gCursorWin->Move(e->fXRoot + gDecorWidth, e->fYRoot + gDecorHeight);
2169  }
2170  }
2171  }
2172 
2173  // Lets all the other events to be handled the same way as when recording
2174  // first, special case for the gui builder, having a timer handling
2175  // some of the events
2176  if (e->fType == kOtherEvent && e->fFormat >= kGKeyPress &&
2177  e->fFormat < kOtherEvent) {
2178  e->fType = (EGEventType)e->fFormat;
2179  if (gDragManager)
2181  delete e;
2182  return;
2183  }
2184  else { // then the normal cases
2185  if (!fMasked)
2186  gClient->HandleEvent(e);
2187  else
2188  gClient->HandleMaskEvent(e, fMasked);
2189  }
2190  delete e;
2191 }
2192 
2193 ////////////////////////////////////////////////////////////////////////////////
2194 /// Converts TRecGuiEvent type to Event_t type
2195 
2197 {
2198  Event_t *e = new Event_t();
2199 
2200  // Copies all data items
2201 
2202  e->fType = ge->fType;
2203  e->fWindow = ge->fWindow;
2204  e->fTime = ge->fTime;
2205 
2206  e->fX = ge->fX;
2207  e->fY = ge->fY;
2208  e->fXRoot = ge->fXRoot;
2209  e->fYRoot = ge->fYRoot;
2210 
2211  e->fCode = ge->fCode;
2212  e->fState = ge->fState;
2213 
2214  e->fWidth = ge->fWidth;
2215  e->fHeight = ge->fHeight;
2216 
2217  e->fCount = ge->fCount;
2218  e->fSendEvent = ge->fSendEvent;
2219 
2220  e->fHandle = ge->fHandle;
2221  e->fFormat = ge->fFormat;
2222 
2224  e->fHandle = gROOT_MESSAGE;
2225 
2226  for(Int_t i=0; i<5; ++i)
2227  e->fUser[i] = ge->fUser[i];
2228 
2230  e->fUser[0] = gWM_DELETE_WINDOW;
2231 
2232  if (ge->fType == kGKeyPress || ge->fType == kKeyRelease) {
2233  e->fCode = gVirtualX->KeysymToKeycode(ge->fCode);
2234 #ifdef R__WIN32
2235  e->fUser[1] = 1;
2236  e->fUser[2] = e->fCode;
2237 #endif
2238  }
2239 
2240  return e;
2241 }
2242 
void RegisterWindow(Window_t w)
This method is called when RegisteredWindow(Window_t) is emitted from TGClient.
Definition: TRecorder.cxx:1403
virtual const char * BaseName(const char *pathname)
Base name of a file name. Base name of /user/root is root.
Definition: TSystem.cxx:931
void RecordCmdEvent(const char *line)
Records commandline event (text and time) ans saves the previous commandline event This 1 event delay...
Definition: TRecorder.cxx:1416
Bool_t fSendEvent
Definition: GuiTypes.h:183
Time_t fTime
Definition: TRecorder.h:289
Bool_t fSendEvent
Definition: TRecorder.h:299
Definition: TMutex.h:30
const char * kRecEventNames[]
Definition: TRecorder.cxx:139
Long_t fUser[5]
Definition: TRecorder.h:302
virtual Bool_t ProcessEvents()
Process pending events (GUI, timers, sockets).
Definition: TSystem.cxx:423
virtual void Info(const char *method, const char *msgfmt,...) const
Issue info message.
Definition: TObject.cxx:847
Window_t fValue
Definition: TRecorder.h:353
void CopyEvent(Event_t *e, Window_t wid)
Copies all items of given event to fGuiEvent.
Definition: TRecorder.cxx:1663
void RecordText(const TObject *obj)
Records TLatex object created in TCreatePrimitives::Text()
Definition: TRecorder.cxx:1594
void FilterEventPave()
Change the state of the flag to kTRUE when you are recording a pavelabel.
Definition: TRecorder.cxx:1636
void ListGui(const char *filename)
Prints out recorded GUI events.
Definition: TRecorder.cxx:325
long long Long64_t
Definition: RtypesCore.h:69
Double_t GetX2() const
Definition: TBox.h:53
TLine * line
Bool_t fOverwrite
Definition: TGFileDialog.h:65
const char Option_t
Definition: RtypesCore.h:62
virtual void SetTextColor(Pixel_t color, Bool_t global=kFALSE)
Changes text color.
Definition: TGLabel.cxx:359
Int_t GetY() const
Definition: TGFrame.h:279
Int_t fCount
Definition: GuiTypes.h:182
UInt_t GetHeight() const
Definition: TGFrame.h:272
TH1 * h
Definition: legend2.C:5
void RecordExtraEvent(TString line, TTime extTime)
Records TLatex or TPaveLabel object created in TCreatePrimitives, ExtTime is needed for the correct r...
Definition: TRecorder.cxx:1653
virtual void ListCmd(const char *)
Definition: TRecorder.h:531
const char * kCmdEventTree
Definition: TRecorder.cxx:164
EGEventType
Definition: GuiTypes.h:58
A ROOT file is a suite of consecutive data records (TKey instances) with a well defined format...
Definition: TFile.h:46
Int_t fCount
Definition: TRecorder.h:298
virtual TObject * Get(const char *namecycle)
Return pointer to object identified by namecycle.
virtual void Pause(TRecorder *)
Definition: TRecorder.h:527
#define gROOT
Definition: TROOT.h:375
Int_t fY
Definition: GuiTypes.h:177
virtual Int_t GetEntry(Long64_t entry=0, Int_t getall=0)
Read all branches of entry and return total number of bytes read.
Definition: TTree.cxx:5321
R__EXTERN Atom_t gWM_DELETE_WINDOW
Definition: TVirtualX.h:39
Basic string class.
Definition: TString.h:129
#define gClient
Definition: TGClient.h:166
int Int_t
Definition: RtypesCore.h:41
bool Bool_t
Definition: RtypesCore.h:59
Double_t GetY2() const
Definition: TBox.h:55
virtual void Draw(Option_t *option="")
Default Draw method for all objects.
Definition: TObject.cxx:202
virtual Bool_t Replay(TRecorder *, const char *, Bool_t, TRecorder::EReplayModes)
Definition: TRecorder.h:526
R__EXTERN TApplication * gApplication
Definition: TApplication.h:165
Bool_t FilterEvent(TRecGuiEvent *e)
Definition: TRecorder.cxx:667
Basic time type with millisecond precision.
Definition: TTime.h:27
UInt_t GetWidth() const
Definition: TGFrame.h:271
TObject * Next()
Return next object in the list. Returns 0 when no more objects in list.
Definition: TList.cxx:937
void Start(const char *filename, Option_t *option="RECREATE", Window_t *w=0, Int_t winCount=0)
Starts recording events.
Definition: TRecorder.cxx:267
Window_t fWindow
Definition: GuiTypes.h:175
TLatex * t1
Definition: textangle.C:20
void RecordPave(const TObject *obj)
Records TPaveLabel object created in TCreatePrimitives::Pave()
Definition: TRecorder.cxx:1550
Short_t Abs(Short_t d)
Definition: TMathBase.h:108
Handle_t GetId() const
Definition: TGObject.h:48
virtual void ReplayStop(TRecorder *)
Definition: TRecorder.h:529
R__EXTERN TVirtualDragManager * gDragManager
Int_t fYRoot
Definition: TRecorder.h:293
Iterator of linked list.
Definition: TList.h:183
Definition: Buttons.h:30
static TFile * Open(const char *name, Option_t *option="", const char *ftitle="", Int_t compress=1, Int_t netopt=0)
Create / open a file.
Definition: TFile.cxx:3909
virtual void ReplayStop(TRecorder *r)
Replaying is cancelled.
Definition: TRecorder.cxx:1186
UInt_t fHeight
Definition: TRecorder.h:297
virtual void Start(TRecorder *, const char *, Option_t *, Window_t *, Int_t)
Definition: TRecorder.h:524
Window_t fMasked
Definition: TRecorder.h:306
void Update()
Called when fTimer timeouts (every 0.025 second) Updates GUI of recorder.
Definition: TRecorder.cxx:1899
ULong_t Pixel_t
Definition: GuiTypes.h:39
virtual Int_t SetBranchAddress(const char *bname, void *add, TBranch **ptr=0)
Change branch address, dealing with clone trees properly.
Definition: TTree.cxx:7873
virtual Float_t GetTextSize() const
Return the text size.
Definition: TAttText.h:36
const char ** fFileTypes
Definition: TGFileDialog.h:63
TRecorder()
Creates initial INACTIVE state for the recorder.
Definition: TRecorder.cxx:225
UInt_t GetWindowHeight() const
Definition: TCanvas.h:168
Handle_t fHandle
Definition: GuiTypes.h:184
To draw Mathematical Formula.
Definition: TLatex.h:18
Handle_t Atom_t
Definition: GuiTypes.h:36
virtual void Stop(TRecorder *, Bool_t)
Definition: TRecorder.h:525
void RecordGuiCNEvent(Event_t *e)
Records GUI Event_t *e of type kConfigureNotify.
Definition: TRecorder.cxx:1527
Int_t fXRoot
Definition: GuiTypes.h:178
void RecordMousePosition()
Try to record all mouse moves...
Definition: TRecorder.cxx:1496
Handle_t fHandle
Definition: TRecorder.h:300
virtual void SetBackgroundColor(Pixel_t back)
Set background color (override from TGWindow base class).
Definition: TGFrame.cxx:294
virtual void ListGui(const char *filename)
Prints out GUI events recorded in given file.
Definition: TRecorder.cxx:1070
void Replay()
Handles push of fReplay button according to the current recorder state.
Definition: TRecorder.cxx:2025
Book space in a file, create I/O buffers, to fill them, (un)compress them.
Definition: TKey.h:24
Bool_t Initialize(TRecorder *r, Bool_t showMouseCursor, TRecorder::EReplayModes mode)
Initialization of data structures for replaying.
Definition: TRecorder.cxx:434
void ListCmd(const char *filename)
Prints out recorded commandline events.
Definition: TRecorder.cxx:317
Int_t fXRoot
Definition: TRecorder.h:292
TString fFilename
Definition: TRecorder.h:437
A doubly linked list.
Definition: TList.h:43
virtual ~TGRecorder()
Destructor. Cleanup the GUI.
Definition: TRecorder.cxx:2070
A Pave (see TPave) with a text centered in the Pave.
Definition: TPaveLabel.h:20
virtual void SetStyle(UInt_t newstyle)
Set the button style (modern or classic).
Definition: TGButton.cxx:221
Bool_t fOverrideRedirect
Definition: GuiTypes.h:106
Pixmap_t GetPicture() const
Definition: TGPicture.h:65
const char * GetLabel() const
Definition: TPaveLabel.h:35
Using a TBrowser one can browse all ROOT objects.
Definition: TBrowser.h:37
Bool_t Connect(const char *signal, const char *receiver_class, void *receiver, const char *slot)
Non-static method is used to connect from the signal of this object to the receiver slot...
Definition: TQObject.cxx:867
const char * kBranchName
Definition: TRecorder.cxx:168
Int_t GetX() const
Definition: TGFrame.h:278
friend class TRecorderReplaying
Definition: TRecorder.h:435
virtual void Resize(UInt_t w, UInt_t h)
Resize the window.
Definition: TGWindow.cxx:164
Double_t GetX() const
Definition: TText.h:51
virtual Bool_t Replay(TRecorder *r, const char *filename, Bool_t showMouseCursor, TRecorder::EReplayModes mode)
Switches from INACTIVE state of recorder to REPLAYING Return kTRUE if replaying has started or kFALSE...
Definition: TRecorder.cxx:1004
TRandom2 r(17)
virtual void Stop(TRecorder *r, Bool_t guiCommand)
Disconnects all slots and stopps recording.
Definition: TRecorder.cxx:1363
R__EXTERN TSystem * gSystem
Definition: TSystem.h:539
const Mask_t kWASaveUnder
Definition: GuiTypes.h:149
void Resume()
Resumes replaying.
Definition: TRecorder.cxx:301
Time_t fTime
Definition: GuiTypes.h:176
EGEventType fType
Definition: GuiTypes.h:174
void ChangeState(TRecorderState *newstate, Bool_t deletePreviousState=kTRUE)
Changes state from the current to the passed one (newstate) Deletes the old state if delPreviousState...
Definition: TRecorder.cxx:334
UInt_t fHeight
Definition: GuiTypes.h:181
Double_t GetY() const
Definition: TText.h:59
static const char * gFiletypes[]
Definition: TGTextEdit.cxx:48
virtual Font_t GetTextFont() const
Return the text font.
Definition: TAttText.h:35
void RegisterWindow(Window_t w)
Creates mapping for the newly registered window w and adds this mapping to fWindowList.
Definition: TRecorder.cxx:539
Window_t fKey
Definition: TRecorder.h:352
virtual Bool_t InheritsFrom(const char *classname) const
Returns kTRUE if object inherits from class "classname".
Definition: TObject.cxx:436
void Form(const char *fmt,...)
Formats a string using a printf style format descriptor.
Definition: TString.cxx:2332
void SetTypeOfConfigureNotify(Event_t *e)
Sets type of kConfigureNotify event to one of EConfigureNotify.
Definition: TRecorder.cxx:1725
unsigned int UInt_t
Definition: RtypesCore.h:42
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition: TObject.cxx:873
UInt_t fState
Definition: TRecorder.h:295
virtual void Continue()
Continues previously paused replaying.
Definition: TRecorder.cxx:967
static void DumpRootEvent(TRecGuiEvent *e, Int_t n)
Prints out attributes of one GUI event TRecGuiEvent *e Int_n n is number of event if called in cycle...
Definition: TRecorder.cxx:1112
void ReplayRealtime()
Replays the next event.
Definition: TRecorder.cxx:871
static Int_t gDecorWidth
Definition: TRecorder.cxx:191
Int_t fYRoot
Definition: GuiTypes.h:178
UInt_t fWidth
Definition: TRecorder.h:296
Handles synchronous and a-synchronous timer events.
Definition: TTimer.h:51
const char * AsString() const
Return the time as a string.
Definition: TTime.cxx:28
static Int_t gDecorHeight
Definition: TRecorder.cxx:192
const char * kGuiEventTree
Definition: TRecorder.cxx:165
#define gVirtualX
Definition: TVirtualX.h:350
const Bool_t kFALSE
Definition: RtypesCore.h:92
Bool_t PrepareNextEvent()
Finds the next event in log file to replay and sets it to fNextEvent.
Definition: TRecorder.cxx:722
virtual void Move(Int_t x, Int_t y)
Move the window.
Definition: TGWindow.cxx:156
const char * kExtraEventTree
Definition: TRecorder.cxx:167
long Long_t
Definition: RtypesCore.h:50
The Canvas class.
Definition: TCanvas.h:31
void PrevCanvases(const char *filename, Option_t *option)
Save previous canvases in a .root file.
Definition: TRecorder.cxx:1147
void RecordGuiEvent(Event_t *e, Window_t wid)
Records GUI Event_t *e different from kConfigureNotify (they are recorded in TRecorderRecording::Reco...
Definition: TRecorder.cxx:1444
void Replay()
Definition: TRecorder.h:475
virtual Bool_t IsOpen() const
Returns kTRUE in case file is open and kFALSE if file is not open.
Definition: TFile.cxx:1383
TRecorderState * fRecorderState
Definition: TRecorder.h:425
#define ClassImp(name)
Definition: Rtypes.h:336
double f(double x)
virtual void ReplayEvent(Bool_t showMouseCursor=kTRUE)
Replays stored GUI event.
Definition: TRecorder.cxx:2086
Bool_t IsZombie() const
Definition: TObject.h:122
Double_t GetX1() const
Definition: TBox.h:52
virtual void ListCmd(const char *filename)
Prints out commandline events recorded in given file.
Definition: TRecorder.cxx:1028
UInt_t GetWindowWidth() const
Definition: TCanvas.h:167
UInt_t fCode
Definition: GuiTypes.h:179
void StartStop()
Handles push of the fStartStop button according to the current recorder state.
Definition: TRecorder.cxx:1961
unsigned long long ULong64_t
Definition: RtypesCore.h:70
const Mask_t kWAOverrideRedirect
Definition: GuiTypes.h:148
UInt_t fCode
Definition: TRecorder.h:294
Int_t fFormat
Definition: TRecorder.h:301
char * fFilename
Definition: TGFileDialog.h:61
void RecordGuiBldEvent(Event_t *e)
Special case for the gui builder, having a timer handling some of the events.
Definition: TRecorder.cxx:1478
Bool_t Disconnect(const char *signal=0, void *receiver=0, const char *slot=0)
Disconnects signal of this object from slot of receiver.
Definition: TQObject.cxx:1025
you should not use this method at all Int_t Int_t Double_t Double_t Double_t e
Definition: TRolke.cxx:630
void ReplayStop()
Cancells replaying.
Definition: TRecorder.cxx:309
void SetWindowSize(UInt_t ww, UInt_t wh)
Definition: TCanvas.h:204
virtual void AddFrame(TGFrame *f, TGLayoutHints *l=0)
Add frame to the composite frame using the specified layout hints.
Definition: TGFrame.cxx:1099
void SetDefault()
Sets GUI to the default inactive state.
Definition: TRecorder.cxx:1881
const TGWindow * GetParent() const
Definition: TGWindow.h:81
void StartEditing()
Memorize the starting time of editinga TLatex or a TPaveLabel.
Definition: TRecorder.cxx:1644
Long_t fUser[5]
Definition: GuiTypes.h:186
virtual Long64_t GetEntries() const
Definition: TTree.h:381
virtual TRecorder::ERecorderState GetState() const
Get current state of recorder.
Definition: TRecorder.cxx:345
Mother of all ROOT objects.
Definition: TObject.h:37
virtual void MoveResize(Int_t x, Int_t y, UInt_t w, UInt_t h)
Move and resize the window.
Definition: TGWindow.cxx:172
UInt_t fWidth
Definition: GuiTypes.h:181
Bool_t StartRecording()
Connects appropriate signals and slots in order to gain all registered windows and processed events i...
Definition: TRecorder.cxx:1269
typedef void((*Func_t)())
Handle_t Window_t
Definition: GuiTypes.h:28
virtual void PrevCanvases(const char *, Option_t *)
Definition: TRecorder.h:534
Int_t fFormat
Definition: GuiTypes.h:185
void Stop(Bool_t guiCommand=kFALSE)
Stopps recording events.
Definition: TRecorder.cxx:276
RooCmdArg Layout(Double_t xmin, Double_t xmax=0.99, Double_t ymin=0.95)
friend class TRecorderRecording
Definition: TRecorder.h:434
virtual void ReplayStop(TRecorder *r)
Cancels replaying.
Definition: TRecorder.cxx:958
virtual void Resume(TRecorder *)
Definition: TRecorder.h:528
Bool_t IsFiltered(Window_t id)
Returns kTRUE if passed id belongs to window IDs of recorder GUI itself.
Definition: TRecorder.cxx:1707
virtual void Resume(TRecorder *r)
Continues replaying.
Definition: TRecorder.cxx:1174
Definition: file.py:1
static TGCursorWindow * gCursorWin
Definition: TRecorder.cxx:190
EGEventType fType
Definition: TRecorder.h:287
virtual Bool_t HandleTimerEvent(Event_t *, TTimer *)
static Event_t * CreateEvent(TRecGuiEvent *ge)
Converts TRecGuiEvent type to Event_t type.
Definition: TRecorder.cxx:2196
Handle_t Pixmap_t
Definition: GuiTypes.h:29
virtual ~TRecorderReplaying()
Closes all signal-slot connections Frees all memory allocated in contructor.
Definition: TRecorder.cxx:402
Pixmap_t GetMask() const
Definition: TGPicture.h:66
#define gPad
Definition: TVirtualPad.h:284
UInt_t fState
Definition: GuiTypes.h:180
void Pause()
Pauses replaying.
Definition: TRecorder.cxx:293
R__EXTERN Int_t gDebug
Definition: Rtypes.h:83
Double_t GetY1() const
Definition: TBox.h:54
const char * GetText() const
Definition: TRecorder.h:209
friend class TRecorderPaused
Definition: TRecorder.h:433
virtual ~TRecorder()
Destructor.
Definition: TRecorder.cxx:250
A TTree object has a header with a name and a title.
Definition: TTree.h:78
virtual void ListGui(const char *)
Definition: TRecorder.h:532
virtual TRecorder::ERecorderState GetState() const =0
virtual void Pause(TRecorder *r)
Pauses replaying.
Definition: TRecorder.cxx:948
const Mask_t kKeyControlMask
Definition: GuiTypes.h:196
virtual ~TRecorderRecording()
Freeing of allocated memory.
Definition: TRecorder.cxx:1252
virtual TTime GetTime() const
Definition: TRecorder.h:171
const Bool_t kTRUE
Definition: RtypesCore.h:91
const Int_t n
Definition: legend1.C:16
void PrevCanvases(const char *filename, Option_t *option)
Save previous canvases in a .root file.
Definition: TRecorder.cxx:354
Int_t fX
Definition: GuiTypes.h:177
void Browse(TBrowser *)
Browse the recorder from a ROOT file.
Definition: TRecorder.cxx:259
Window_t fWindow
Definition: TRecorder.h:288
const char * cnt
Definition: TXMLSetup.cxx:75
friend class TRecorderInactive
Definition: TRecorder.h:432
const char * kWindowsTree
Definition: TRecorder.cxx:166
R__EXTERN Atom_t gROOT_MESSAGE
Definition: TVirtualX.h:41
virtual const char * GetTitle() const
Returns title of object.
Definition: TNamed.h:48
Bool_t RemapWindowReferences()
All references to the old windows (IDs) in fNextEvent are replaced by new ones according to the mappi...
Definition: TRecorder.cxx:607
virtual void Close(Option_t *option="")
Close a file.
Definition: TFile.cxx:904
Bool_t CanOverlap()
ButtonPress and ButtonRelease must be sometimes replayed more times Example: pressing of a button ope...
Definition: TRecorder.cxx:827
const char * Data() const
Definition: TString.h:347