139 const char *kRecEventNames[] = {
164 const char *kCmdEventTree =
"CmdEvents";
165 const char *kGuiEventTree =
"GuiEvents";
166 const char *kWindowsTree =
"WindowsTree";
167 const char *kExtraEventTree =
"ExtraEvents";
168 const char *kBranchName =
"MainBranch";
180 class TGCursorWindow :
public TGFrame {
183 Pixmap_t fPic, fMask;
187 virtual ~TGCursorWindow();
190 static TGCursorWindow *gCursorWin = 0;
191 static Int_t gDecorWidth = 0;
192 static Int_t gDecorHeight = 0;
197 TGCursorWindow::TGCursorWindow() :
198 TGFrame(gClient->GetDefaultRoot(), 32, 32, kTempFrame)
200 SetWindowAttributes_t wattr;
201 const TGPicture *pbg = fClient->GetPicture(
"recursor.png");
202 fPic = pbg->GetPicture();
203 fMask = pbg->GetMask();
205 gVirtualX->ShapeCombineMask(fId, 0, 0, fMask);
206 SetBackgroundPixmap(fPic);
208 wattr.fMask = kWAOverrideRedirect | kWASaveUnder;
209 wattr.fSaveUnder = kTRUE;
210 wattr.fOverrideRedirect = kTRUE;
212 gVirtualX->ChangeWindowAttributes(fId, &wattr);
218 TGCursorWindow::~TGCursorWindow()
225 TRecorder::TRecorder()
228 fRecorderState =
new TRecorderInactive();
236 TRecorder::TRecorder(
const char *filename, Option_t *option)
240 fRecorderState =
new TRecorderInactive();
241 if ((opt ==
"NEW") || (opt ==
"RECREATE"))
242 Start(filename, option);
250 TRecorder::~TRecorder()
252 delete fRecorderState;
259 void TRecorder::Browse(TBrowser *)
267 void TRecorder::Start(
const char *filename, Option_t *option, Window_t *w,
270 fRecorderState->Start(
this, filename, option, w, winCount);
276 void TRecorder::Stop(Bool_t guiCommand)
278 fRecorderState->Stop(
this, guiCommand);
284 Bool_t TRecorder::Replay(
const char *filename, Bool_t showMouseCursor,
285 TRecorder::EReplayModes mode)
287 return fRecorderState->Replay(
this, filename, showMouseCursor, mode);
293 void TRecorder::Pause()
295 fRecorderState->Pause(
this);
301 void TRecorder::Resume()
303 fRecorderState->Resume(
this);
309 void TRecorder::ReplayStop()
311 fRecorderState->ReplayStop(
this);
317 void TRecorder::ListCmd(
const char *filename)
319 fRecorderState->ListCmd(filename);
325 void TRecorder::ListGui(
const char *filename)
327 fRecorderState->ListGui(filename);
334 void TRecorder::ChangeState(TRecorderState *newstate, Bool_t delPreviousState)
336 if (delPreviousState)
337 delete fRecorderState;
339 fRecorderState = newstate;
345 TRecorder::ERecorderState TRecorder::GetState()
const
347 return fRecorderState->GetState();
354 void TRecorder::PrevCanvases(
const char *filename, Option_t *option)
356 fRecorderState->PrevCanvases(filename,option);
362 ClassImp(TRecorderReplaying);
368 TRecorderReplaying::TRecorderReplaying(
const char *filename)
373 fEventReplayed = kTRUE;
375 fExtraTreeCounter = 0;
376 fFilterStatusBar = kFALSE;
382 fShowMouseCursor = kTRUE;
383 fWaitingForWindow = kFALSE;
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);
395 gCursorWin =
new TGCursorWindow();
402 TRecorderReplaying::~TRecorderReplaying()
404 fTimer->Disconnect(fTimer,
"Timeout()",
this,
"ReplayRealtime()");
408 gClient->Disconnect(gClient,
"RegisteredWindow(Window_t)",
this,
409 "RegisterWindow(Window_t)");
422 gCursorWin->DeleteWindow();
434 Bool_t TRecorderReplaying::Initialize(TRecorder *r, Bool_t showMouseCursor,
435 TRecorder::EReplayModes)
440 fExtraTreeCounter = 0;
444 fFilterStatusBar = kFALSE;
446 fWaitingForWindow = kFALSE;
451 fShowMouseCursor = showMouseCursor;
453 if (!fFile || fFile->IsZombie() || !fFile->IsOpen())
456 fCmdTree = (TTree*) fFile->Get(kCmdEventTree);
457 fWinTree = (TTree*) fFile->Get(kWindowsTree);
458 fGuiTree = (TTree*) fFile->Get(kGuiEventTree);
459 fExtraTree = (TTree*) fFile->Get(kExtraEventTree);
461 if (!fCmdTree || !fWinTree || ! fGuiTree || ! fExtraTree) {
462 Error(
"TRecorderReplaying::Initialize",
463 "The ROOT file is not valid event logfile.");
468 fCmdTree->SetBranchAddress(kBranchName, &fCmdEvent);
469 fWinTree->SetBranchAddress(kBranchName, &fWin);
470 fGuiTree->SetBranchAddress(kBranchName, &fGuiEvent);
471 fExtraTree->SetBranchAddress(kBranchName, &fExtraEvent);
474 Error(
"TRecorderReplaying::Initialize",
475 "The ROOT file is not valid event logfile");
480 if (!PrepareNextEvent()) {
481 Info(
"TRecorderReplaying::Initialize",
482 "Log file empty. No event to replay.");
487 fWinTreeEntries = fWinTree->GetEntries();
491 gClient->Connect(
"RegisteredWindow(Window_t)",
"TRecorderReplaying",
492 this,
"RegisterWindow(Window_t)");
494 Info(
"TRecorderReplaying::Initialize",
"Replaying of file %s started",
497 TFile *f = TFile::Open(fFile->GetName());
498 if (f && !f->IsZombie()) {
499 TIter nextkey(f->GetListOfKeys());
502 while ((key = (TKey*)nextkey())) {
503 fFilterStatusBar = kTRUE;
504 obj = key->ReadObj();
505 if (!obj->InheritsFrom(
"TCanvas"))
507 fCanv = (TCanvas*) obj;
511 TIter nextc(gROOT->GetListOfCanvases());
512 while ((canvas = (TCanvas*)nextc())) {
513 canvas->SetWindowSize(canvas->GetWindowWidth(),
514 canvas->GetWindowHeight());
516 fFilterStatusBar = kFALSE;
522 fTimer->Connect(
"Timeout()",
"TRecorderReplaying",
this,
"ReplayRealtime()");
539 void TRecorderReplaying::RegisterWindow(Window_t w)
541 if (fFilterStatusBar) {
542 TGWindow *win = gClient->GetWindowById(w);
544 if (win->GetParent()->InheritsFrom(
"TGStatusBar")) {
545 fFilterStatusBar = kFALSE;
552 if (fWinTreeEntries > fRegWinCounter) {
553 fWinTree->GetEntry(fRegWinCounter);
558 Error(
"TRecorderReplaying::RegisterWindow",
559 "More windows registered than expected");
564 if ((gDebug > 0) && (fWaitingForWindow)) {
565 std::ios::fmtflags f = std::cout.flags();
566 std::cout <<
" Window registered: new ID: " << std::hex << w <<
567 " previous ID: " << fWin << std::dec << std::endl;
568 std::cout.flags( f );
578 TRecWinPair *ids =
new TRecWinPair(fWin, w);
580 fWindowList->Add(ids);
584 if (fWaitingForWindow && fGuiEvent->fWindow == fWin) {
587 std::ios::fmtflags f = std::cout.flags();
588 std::cout <<
" Window " << std::hex << fGuiEvent->fWindow <<
589 " registered." << std::dec << std::endl;
590 std::cout.flags( f );
593 fNextEvent = fGuiEvent;
595 fWaitingForWindow = kFALSE;
607 Bool_t TRecorderReplaying::RemapWindowReferences()
613 TListIter it(fWindowList);
615 Bool_t found = kFALSE;
618 while ((ids = (TRecWinPair*)it.Next())) {
620 if (!found && fGuiEvent->fWindow == 0) {
621 fGuiEvent->fWindow = gVirtualX->GetDefaultRootWindow();
624 else if (!found && ids->fKey == fGuiEvent->fWindow) {
625 fGuiEvent->fWindow = ids->fValue;
628 for (Int_t i = 0; i < 5; ++i) {
629 if ((Long_t) ids->fKey == fGuiEvent->fUser[i])
630 fGuiEvent->fUser[i] = ids->fValue;
632 if (fGuiEvent->fMasked && ids->fKey == fGuiEvent->fMasked) {
633 fGuiEvent->fMasked = ids->fValue;
637 if (!found && fGuiEvent->fWindow == 0) {
638 fGuiEvent->fWindow = gVirtualX->GetDefaultRootWindow();
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;
652 TRecorderInactive::DumpRootEvent(fGuiEvent,0);
654 std::cout.flags(org_flags);
659 fWaitingForWindow = kTRUE;
667 Bool_t TRecorderReplaying::FilterEvent(TRecGuiEvent *e)
680 if (e->fType == kClientMessage) {
681 if ((e->fFormat == 32) && (e->fHandle != TRecGuiEvent::kROOT_MESSAGE)
682 && ((Atom_t)e->fUser[0] == TRecGuiEvent::kWM_DELETE_WINDOW))
690 if (e->fType == kConfigureNotify && e->fUser[4] == TRecGuiEvent::kCNFilter) {
694 if (e->fType == kOtherEvent) {
695 if (e->fFormat >= kGKeyPress && e->fFormat < kOtherEvent)
722 Bool_t TRecorderReplaying::PrepareNextEvent()
730 if (fCmdTree->GetEntries() > fCmdTreeCounter)
731 fCmdTree->GetEntry(fCmdTreeCounter);
734 if (fExtraTree->GetEntries() > fExtraTreeCounter)
735 fExtraTree->GetEntry(fExtraTreeCounter);
739 while (fGuiTree->GetEntries() > fGuiTreeCounter) {
740 fGuiTree->GetEntry(fGuiTreeCounter);
741 if (!fGuiEvent || !FilterEvent(fGuiEvent))
747 if (fCmdEvent && fGuiEvent && fExtraEvent) {
750 if ((fCmdEvent->GetTime() <= fGuiEvent->GetTime()) &&
751 (fCmdEvent->GetTime() <= fExtraEvent->GetTime()))
752 fNextEvent = fCmdEvent;
754 if (fGuiEvent->GetTime() <= fExtraEvent->GetTime())
755 fNextEvent = fGuiEvent;
757 fNextEvent = fExtraEvent;
760 else if (fCmdEvent && fGuiEvent) {
763 if (fCmdEvent->GetTime() <= fGuiEvent->GetTime())
764 fNextEvent = fCmdEvent;
766 fNextEvent = fGuiEvent;
768 else if (fCmdEvent && fExtraEvent ) {
771 if (fCmdEvent->GetTime() <= fExtraEvent->GetTime())
772 fNextEvent = fCmdEvent;
774 fNextEvent = fExtraEvent;
776 else if (fGuiEvent && fExtraEvent) {
779 if (fExtraEvent->GetTime() <= fGuiEvent->GetTime())
780 fNextEvent = fExtraEvent;
782 fNextEvent = fGuiEvent;
786 else if (!fCmdEvent && !fGuiEvent && !fExtraEvent)
790 fNextEvent = fGuiEvent;
793 fNextEvent = fCmdEvent;
795 fNextEvent = fExtraEvent;
802 if (fNextEvent == fCmdEvent)
806 if (fNextEvent == fExtraEvent)
810 if (fNextEvent == fGuiEvent) {
812 if (RemapWindowReferences())
827 Bool_t TRecorderReplaying::CanOverlap()
830 Error(
"TRecorderReplaying::CanOverlap()",
"fGuiEvent = 0");
835 if (fNextEvent->GetType() != TRecEvent::kGuiEvent)
840 std::cout <<
"Event overlapping " <<
841 kRecEventNames[((TRecGuiEvent*)fNextEvent)->fType] << std::endl;
842 TRecorderInactive::DumpRootEvent(((TRecGuiEvent*)fNextEvent), 0);
846 TRecGuiEvent *e = (TRecGuiEvent*) fNextEvent;
849 if (e->fType == kButtonPress || e->fType == kButtonRelease ||
850 e->fType == kMotionNotify)
871 void TRecorderReplaying::ReplayRealtime()
876 if ((gROOT->GetEditorMode() == kText) ||
877 (gROOT->GetEditorMode() == kPaveLabel)){
878 gROOT->SetEditorMode();
883 if (gVirtualX->EventsPending()) {
884 gSystem->ProcessEvents();
890 if (!fEventReplayed && !CanOverlap())
900 fPreviousEventTime = fNextEvent->GetTime();
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);
909 if ((keysym & ~0x20) == kKey_S) {
912 ev->ReplayEvent(fShowMouseCursor);
919 fNextEvent->ReplayEvent(fShowMouseCursor);
926 if (!PrepareNextEvent()) {
930 Info(
"TRecorderReplaying::ReplayRealtime",
"Replaying finished");
931 fRecorder->ChangeState(
new TRecorderInactive());
941 fTimer->Start(Long_t(fNextEvent->GetTime() - fPreviousEventTime));
948 void TRecorderReplaying::Pause(TRecorder *r)
951 r->ChangeState(
new TRecorderPaused(
this), kFALSE);
952 Info(
"TRecorderReplaying::Pause",
"Replaying paused.");
958 void TRecorderReplaying::ReplayStop(TRecorder *r)
960 Info(
"TRecorderReplaying::ReplayStop",
"Replaying cancelled");
961 r->ChangeState(
new TRecorderInactive());
967 void TRecorderReplaying::Continue()
970 fTimer->Start(Long_t(fNextEvent->GetTime() - fPreviousEventTime));
976 ClassImp(TRecorderInactive);
981 void TRecorderInactive::Start(TRecorder *r,
const char *filename,
982 Option_t *option, Window_t *w, Int_t winCount)
990 TRecorderRecording *rec =
new TRecorderRecording(r, filename, option, w, winCount);
991 if (rec->StartRecording()) {
993 r->fFilename = gSystem->BaseName(filename);
1004 Bool_t TRecorderInactive::Replay(TRecorder *r,
const char *filename,
1005 Bool_t showMouseCursor,
1006 TRecorder::EReplayModes mode)
1012 TRecorderReplaying *replay =
new TRecorderReplaying(filename);
1014 if (replay->Initialize(r, showMouseCursor, mode)) {
1015 r->ChangeState(replay);
1016 r->fFilename = gSystem->BaseName(filename);
1028 void TRecorderInactive::ListCmd(
const char *filename)
1036 TFile *file = TFile::Open(filename);
1038 if (file->IsZombie() || !file->IsOpen()) {
1042 TTree *t1 = (TTree*)file->Get(kCmdEventTree);
1045 Error(
"TRecorderInactive::List",
1046 "The ROOT file is not valid event logfile.");
1051 TRecCmdEvent *fCmdEvent =
new TRecCmdEvent();
1052 t1->SetBranchAddress(kBranchName, &fCmdEvent);
1054 Int_t entries = t1->GetEntries();
1055 for (Int_t i = 0; i < entries; ++i) {
1057 std::cout <<
"[" << i <<
"] " <<
"fTime=" <<
1058 (ULong64_t) fCmdEvent->GetTime() <<
" fText=" <<
1059 fCmdEvent->GetText() << std::endl;
1061 std::cout << std::endl;
1070 void TRecorderInactive::ListGui(
const char *filename)
1079 TFile *file = TFile::Open(filename);
1081 if (file->IsZombie() || !file->IsOpen()) {
1085 TTree *t1 = (TTree*)file->Get(kGuiEventTree);
1088 Error(
"TRecorderInactive::ListGui",
1089 "The ROOT file is not valid event logfile.");
1094 TRecGuiEvent *guiEvent =
new TRecGuiEvent();
1095 t1->SetBranchAddress(kBranchName, &guiEvent);
1097 Int_t entries = t1->GetEntries();
1099 for (Int_t i = 0; i < entries ; ++i) {
1101 DumpRootEvent(guiEvent, i);
1112 void TRecorderInactive::DumpRootEvent(TRecGuiEvent *e, Int_t n)
1114 std::ios::fmtflags f = std::cout.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)
1133 for (Int_t i=0; i<5; ++i)
1134 if (DisplayValid(e->fUser[i]) != -1)
1135 std::cout <<
"[" << i <<
"]=" << DisplayValid(e->fUser[i]);
1138 std::cout <<
" | fM:" << std::hex << e->fMasked;
1140 std::cout << std::endl;
1141 std::cout.flags( f );
1147 void TRecorderInactive::PrevCanvases(
const char *filename, Option_t *option)
1149 fCollect = gROOT->GetListOfCanvases();
1150 TFile *f = TFile::Open(filename, option);
1151 if (f && !f->IsZombie()) {
1161 ClassImp(TRecorderPaused);
1166 TRecorderPaused::TRecorderPaused(TRecorderReplaying *state)
1168 fReplayingState = state;
1174 void TRecorderPaused::Resume(TRecorder *r)
1176 fReplayingState->Continue();
1177 Info(
"TRecorderPaused::Resume",
"Replaying resumed");
1180 r->ChangeState(fReplayingState);
1186 void TRecorderPaused::ReplayStop(TRecorder *r)
1188 delete fReplayingState;
1190 Info(
"TRecorderReplaying::ReplayStop",
"Reaplying cancelled");
1191 r->ChangeState(
new TRecorderInactive());
1198 ClassImp(TRecorderRecording);
1204 TRecorderRecording::TRecorderRecording(TRecorder *r,
const char *filename,
1205 Option_t *option, Window_t *w,
1213 fFilteredIdsCount = winCount;
1214 fFilteredIds =
new Window_t[fFilteredIdsCount];
1215 for(Int_t i=0; i < fFilteredIdsCount; ++i)
1216 fFilteredIds[i] = w[i];
1219 fCmdEventPending = kFALSE;
1222 fFilterEventPave = kFALSE;
1228 fTimer =
new TTimer(25, kTRUE);
1230 fMouseTimer =
new TTimer(50, kTRUE);
1231 fMouseTimer->Connect(
"Timeout()",
"TRecorderRecording",
this,
1232 "RecordMousePosition()");
1235 fFile = TFile::Open(filename, option);
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");
1244 fCmdEvent =
new TRecCmdEvent();
1245 fGuiEvent =
new TRecGuiEvent();
1246 fExtraEvent =
new TRecExtraEvent();
1252 TRecorderRecording::~TRecorderRecording()
1254 delete[] fFilteredIds;
1269 Bool_t TRecorderRecording::StartRecording()
1271 if (!fFile || fFile->IsZombie() || !fFile->IsOpen())
1276 gApplication->Connect(
"LineProcessed(const char*)",
"TRecorderRecording",
1277 this,
"RecordCmdEvent(const char*)");
1281 gClient->Connect(
"RegisteredWindow(Window_t)",
"TRecorderRecording",
this,
1282 "RegisterWindow(Window_t)");
1287 gClient->Connect(
"ProcessedEvent(Event_t*, Window_t)",
"TRecorderRecording",
1288 this,
"RecordGuiEvent(Event_t*, Window_t)");
1292 TQObject::Connect(
"TGFrame",
"ProcessedConfigure(Event_t*)",
1293 "TRecorderRecording",
this,
"RecordGuiCNEvent(Event_t*)");
1297 TQObject::Connect(
"TPad",
"RecordPave(const TObject*)",
"TRecorderRecording",
1298 this,
"RecordPave(const TObject*)");
1301 TQObject::Connect(
"TPad",
"RecordLatex(const TObject*)",
1302 "TRecorderRecording",
this,
"RecordText(const TObject*)");
1306 TQObject::Connect(
"TPad",
"EventPave()",
"TRecorderRecording",
this,
1307 "FilterEventPave()");
1311 TQObject::Connect(
"TPad",
"StartEditing()",
"TRecorderRecording",
this,
1315 TQObject::Connect(
"TGuiBldDragManager",
"TimerEvent(Event_t*)",
1316 "TRecorderRecording",
this,
"RecordGuiBldEvent(Event_t*)");
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);
1325 Int_t numCanvases = gROOT->GetListOfCanvases()->LastIndex();
1327 if (numCanvases >= 0){
1329 TIter nextwindow (gClient->GetListOfWindows());
1333 while ((twin = (TGWindow*) nextwindow())) {
1334 twin2 = (Window_t) twin->GetId();
1335 if (IsFiltered(twin2)) {
1337 std::cout <<
"WindowID "<< twin2 <<
" filtered" << std::endl;
1340 else if (twin != gClient->GetRoot()) {
1341 RegisterWindow(twin2);
1352 fMouseTimer->Start(50);
1354 Info(
"TRecorderRecording::StartRecording",
"Recording started. Log file: %s",
1363 void TRecorderRecording::Stop(TRecorder *, Bool_t guiCommand)
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*)");
1384 if (fCmdEventPending && guiCommand)
1387 fRecorder->Write(
"recorder");
1392 fMouseTimer->TurnOff();
1394 Info(
"TRecorderRecording::Stop",
"Recording finished.");
1396 fRecorder->ChangeState(
new TRecorderInactive());
1403 void TRecorderRecording::RegisterWindow(Window_t w)
1406 fWin = (ULong64_t) w;
1416 void TRecorderRecording::RecordCmdEvent(
const char *line)
1419 if (fCmdEventPending)
1424 fCmdEvent->SetTime(fTimer->GetAbsTime());
1425 fCmdEvent->SetText((
char*)line);
1429 fCmdEventPending = kTRUE;
1444 void TRecorderRecording::RecordGuiEvent(Event_t *e, Window_t wid)
1448 if (fFilteredIdsCount && IsFiltered(e->fWindow))
1452 if (fFilterEventPave && (e->fCode == 1)) {
1453 fFilterEventPave = kFALSE;
1456 fFilterEventPave = kFALSE;
1460 if (e->fType == kSelectionClear || e->fType == kSelectionRequest ||
1461 e->fType == kSelectionNotify)
1468 fGuiEvent->SetTime(fTimer->GetAbsTime());
1478 void TRecorderRecording::RecordGuiBldEvent(Event_t *e)
1480 e->fFormat = e->fType;
1481 e->fType = kOtherEvent;
1487 fGuiEvent->SetTime(fTimer->GetAbsTime());
1496 void TRecorderRecording::RecordMousePosition()
1501 ev.fType = kMotionNotify;
1504 ev.fUser[0] = ev.fUser[1] = ev.fUser[2] = ev.fUser[3] = ev.fUser[4] = 0;
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;
1518 RecordGuiEvent(&ev, 0);
1519 fMouseTimer->Reset();
1527 void TRecorderRecording::RecordGuiCNEvent(Event_t *e)
1530 if (fFilteredIdsCount && IsFiltered(e->fWindow))
1535 SetTypeOfConfigureNotify(e);
1541 fGuiEvent->SetTime(fTimer->GetAbsTime());
1550 void TRecorderRecording::RecordPave(
const TObject *obj)
1552 Long64_t extratime = fBeginPave;
1553 Long64_t interval = (Long64_t)fTimer->GetAbsTime() - fBeginPave;
1554 TPaveLabel *pavel = (TPaveLabel *) obj;
1556 label = pavel->GetLabel();
1559 cad =
"TPaveLabel *p = new TPaveLabel(";
1560 cad += pavel->GetX1();
1562 cad += pavel->GetY1();
1564 cad += pavel->GetX2();
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]);
1576 cad +=
" p->SetTextFont(83); p->SetTextSizePixels(14); ";
1578 cad +=
" gPad->Modified(); gPad->Update();";
1579 extratime += interval;
1580 RecordExtraEvent(cad, extratime);
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);
1594 void TRecorderRecording::RecordText(
const TObject *obj)
1596 Long64_t extratime = fBeginPave;
1597 Long64_t interval = (Long64_t)fTimer->GetAbsTime() - fBeginPave;
1598 TLatex *texto = (TLatex *) obj;
1600 label = texto->GetTitle();
1603 cad =
"TLatex *l = new TLatex(";
1604 cad += texto->GetX();
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]);
1616 cad +=
" l->SetTextFont(83); l->SetTextSizePixels(14); ";
1618 cad +=
" gPad->Modified(); gPad->Update();";
1619 extratime += interval;
1620 RecordExtraEvent(cad, extratime);
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);
1636 void TRecorderRecording::FilterEventPave()
1638 fFilterEventPave = kTRUE;
1644 void TRecorderRecording::StartEditing()
1646 fBeginPave = fTimer->GetAbsTime();
1653 void TRecorderRecording::RecordExtraEvent(TString line, TTime extTime)
1655 fExtraEvent->SetTime(extTime);
1656 fExtraEvent->SetText(line);
1663 void TRecorderRecording::CopyEvent(Event_t *e, Window_t wid)
1665 fGuiEvent->fType = e->fType;
1666 fGuiEvent->fWindow = e->fWindow;
1667 fGuiEvent->fTime = e->fTime;
1669 fGuiEvent->fX = e->fX;
1670 fGuiEvent->fY = e->fY;
1671 fGuiEvent->fXRoot = e->fXRoot;
1672 fGuiEvent->fYRoot = e->fYRoot;
1674 fGuiEvent->fCode = e->fCode;
1675 fGuiEvent->fState = e->fState;
1677 fGuiEvent->fWidth = e->fWidth;
1678 fGuiEvent->fHeight = e->fHeight;
1680 fGuiEvent->fCount = e->fCount;
1681 fGuiEvent->fSendEvent = e->fSendEvent;
1682 fGuiEvent->fHandle = e->fHandle;
1683 fGuiEvent->fFormat = e->fFormat;
1685 if (fGuiEvent->fHandle == gROOT_MESSAGE)
1686 fGuiEvent->fHandle = TRecGuiEvent::kROOT_MESSAGE;
1688 for(Int_t i=0; i<5; ++i)
1689 fGuiEvent->fUser[i] = e->fUser[i];
1691 if (fGuiEvent->fUser[0] == (Int_t)gWM_DELETE_WINDOW)
1692 fGuiEvent->fUser[0] = TRecGuiEvent::kWM_DELETE_WINDOW;
1694 if (e->fType == kGKeyPress || e->fType == kKeyRelease) {
1697 gVirtualX->LookupString(e, tmp,
sizeof(tmp), keysym);
1698 fGuiEvent->fCode = keysym;
1701 fGuiEvent->fMasked = wid;
1707 Bool_t TRecorderRecording::IsFiltered(Window_t
id)
1709 for(Int_t i=0; i < fFilteredIdsCount; ++i)
1710 if (
id == fFilteredIds[i])
1725 void TRecorderRecording::SetTypeOfConfigureNotify(Event_t *e)
1730 if ((e->fX == 0 && e->fY == 0)) {
1731 e->fUser[4] = TRecGuiEvent::kCNFilter;
1738 e->fUser[4] = TRecGuiEvent::kCNMoveResize;
1742 TGWindow *w = gClient->GetWindowById(e->fWindow);
1744 TGFrame *t = (TGFrame *)w;
1748 if (t->GetWidth() == e->fWidth && t->GetHeight() == e->fHeight &&
1749 e->fX == t->GetX() && e->fY == t->GetY()) {
1750 e->fUser[4] = TRecGuiEvent::kCNFilter;
1754 if (t->GetWidth() == e->fWidth && t->GetHeight() == e->fHeight) {
1755 e->fUser[4] = TRecGuiEvent::kCNMove;
1759 e->fUser[4] = TRecGuiEvent::kCNResize;
1772 ClassImp(TGRecorder);
1777 TGRecorder::TGRecorder(
const TGWindow *p, UInt_t w, UInt_t h) :
1778 TGMainFrame(p ? p : gClient->GetRoot(), w, h)
1780 TGHorizontalFrame *hframe;
1781 TGVerticalFrame *vframe;
1782 SetCleanup(kDeepCleanup);
1783 fRecorder =
new TRecorder();
1784 fFilteredIds[0] = GetId();
1787 hframe =
new TGHorizontalFrame(
this, 200, 75, kChildFrame | kFixedHeight,
1789 fFilteredIds[1] = hframe->GetId();
1793 vframe =
new TGVerticalFrame(hframe, 200, 75, kChildFrame | kFixedHeight,
1795 fFilteredIds[2] = vframe->GetId();
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,
1802 fFilteredIds[3] = fStatusLabel->GetId();
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,
1809 fFilteredIds[4] = fTimeLabel->GetId();
1811 hframe->AddFrame(vframe,
new TGLayoutHints(kLHintsLeft | kLHintsExpandY));
1813 vframe =
new TGVerticalFrame(hframe, 200, 75, kChildFrame | kFixedHeight,
1815 fFilteredIds[5] = vframe->GetId();
1817 fStatus =
new TGLabel(vframe,
"Inactive");
1818 fStatus->SetTextColor(0x7cffff);
1819 fStatus->SetBackgroundColor((Pixel_t)0x000000);
1820 vframe->AddFrame(fStatus,
new TGLayoutHints(kLHintsLeft | kLHintsTop,
1822 fFilteredIds[6] = fStatus->GetId();
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,
1830 fFilteredIds[7] = fTimeDisplay->GetId();
1832 hframe->AddFrame(vframe,
new TGLayoutHints(kLHintsLeft | kLHintsExpandY,
1834 AddFrame(hframe,
new TGLayoutHints(kLHintsExpandX, 2, 2, 2, 2));
1837 hframe =
new TGHorizontalFrame(
this, 200, 200);
1838 fFilteredIds[8] = hframe->GetId();
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,
1846 fStartStop->Resize(40,40);
1847 fFilteredIds[9] = fStartStop->GetId();
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,
1855 fReplay->Resize(40,40);
1856 fFilteredIds[10] = fReplay->GetId();
1859 fCursorCheckBox =
new TGCheckButton(
this,
"Show mouse cursor");
1860 AddFrame(fCursorCheckBox,
new TGLayoutHints(kLHintsCenterX, 2, 2, 2, 2));
1861 fFilteredIds[11] = fCursorCheckBox->GetId();
1864 fTimer =
new TTimer(25);
1865 fTimer->Connect(
"Timeout()",
"TGRecorder",
this,
"Update()");
1867 AddFrame(hframe,
new TGLayoutHints(kLHintsCenterX, 2, 2, 2, 2));
1869 SetEditDisabled(kEditDisable | kEditDisableGrab);
1870 SetWindowName(
"ROOT Event Recorder");
1881 void TGRecorder::SetDefault()
1883 fTimeDisplay->SetText(
"00:00:00");
1885 fReplay->SetPicture(gClient->GetPicture(
"replay.png"));
1886 fReplay->SetEnabled(kTRUE);
1888 fCursorCheckBox->SetEnabled(kTRUE);
1889 fCursorCheckBox->SetOn(kTRUE);
1891 fStartStop->SetPicture(gClient->GetPicture(
"record.png"));
1892 fStartStop->SetEnabled(kTRUE);
1899 void TGRecorder::Update()
1905 time_t elapsed_time = (time_t)difftime( fElapsed, fStart );
1906 running = gmtime( &elapsed_time );
1908 switch(fRecorder->GetState()) {
1912 case TRecorder::kRecording:
1913 case TRecorder::kReplaying:
1917 if (fRecorder->GetState() == TRecorder::kReplaying)
1918 fStatus->SetText(
"Replaying");
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());
1926 if (gVirtualX->EventsPending()) {
1927 fStatus->SetText(
"Waiting...");
1928 fStatus->SetTextColor((Pixel_t)0xff0000);
1931 fStatus->SetTextColor((Pixel_t)0x7cffff);
1934 fTimeDisplay->Resize();
1944 case TRecorder::kInactive:
1945 fStatus->SetText(
"Inactive");
1946 fStatus->SetTextColor((Pixel_t)0x7cffff);
1961 void TGRecorder::StartStop()
1963 static const char *gFiletypes[] = {
1964 "All files",
"*",
"Text files",
"*.txt",
"ROOT files",
"*.root", 0, 0
1968 switch(fRecorder->GetState()) {
1971 case TRecorder::kInactive:
1973 fi.fFileTypes = gFiletypes;
1974 fi.fOverwrite = kFALSE;
1976 new TGFileDialog(gClient->GetDefaultRoot(),
1977 gClient->GetDefaultRoot(),
1980 if (fi.fFilename && strlen(fi.fFilename)) {
1982 if (!gROOT->GetListOfCanvases()->IsEmpty()) {
1983 fRecorder->PrevCanvases(fi.fFilename,
"RECREATE");
1984 fRecorder->Start(fi.fFilename,
"UPDATE", fFilteredIds,
1988 fRecorder->Start(fi.fFilename,
"RECREATE", fFilteredIds,
1991 fCursorCheckBox->SetDisabledAndSelected(kTRUE);
1992 fStartStop->SetPicture(gClient->GetPicture(
"stop.png"));
1993 fReplay->SetEnabled(kFALSE);
2000 case TRecorder::kRecording:
2001 fRecorder->Stop(kTRUE);
2005 case TRecorder::kReplaying:
2007 fStartStop->SetPicture(gClient->GetPicture(
"replay.png"));
2011 case TRecorder::kPaused:
2012 fRecorder->Resume();
2013 fStartStop->SetPicture(gClient->GetPicture(
"pause.png"));
2025 void TGRecorder::Replay()
2029 switch(fRecorder->GetState()) {
2032 case TRecorder::kInactive:
2034 new TGFileDialog(gClient->GetDefaultRoot(),
2035 gClient->GetDefaultRoot(),
2038 if (fi.fFilename && strlen(fi.fFilename)) {
2039 if (fRecorder->Replay(fi.fFilename, fCursorCheckBox->IsOn())) {
2044 fReplay->SetPicture(gClient->GetPicture(
"stop.png"));
2045 fStartStop->SetPicture(gClient->GetPicture(
"pause.png"));
2047 if (fCursorCheckBox->IsOn())
2048 fStartStop->SetEnabled(kFALSE);
2050 fCursorCheckBox->SetEnabled(kFALSE);
2056 case TRecorder::kReplaying:
2057 case TRecorder::kPaused:
2058 fRecorder->ReplayStop();
2070 TGRecorder::~TGRecorder()
2080 ClassImp(TRecCmdEvent);
2081 ClassImp(TRecGuiEvent);
2086 void TRecGuiEvent::ReplayEvent(Bool_t showMouseCursor)
2088 Int_t px, py, dx, dy;
2090 Event_t *e = CreateEvent(
this);
2094 if (e->fType == kSelectionClear || e->fType == kSelectionRequest ||
2095 e->fType == kSelectionNotify) {
2101 if (e->fType == kConfigureNotify) {
2102 TGWindow *w = gClient->GetWindowById(e->fWindow);
2111 WindowAttributes_t attr;
2112 if (e->fUser[4] == TRecGuiEvent::kCNMove) {
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);
2120 if (e->fUser[4] == TRecGuiEvent::kCNResize) {
2122 w->Resize(e->fWidth, e->fHeight);
2125 if (e->fUser[4] == TRecGuiEvent::kCNMoveResize) {
2127 w->MoveResize(e->fX, e->fY, e->fWidth, e->fHeight);
2131 Error(
"TRecGuiEvent::ReplayEvent",
2132 "kConfigureNotify: Unknown value: fUser[4] = %ld ",
2141 Error(
"TRecGuiEvent::ReplayEvent",
2142 "kConfigureNotify: Window does not exist anymore ");
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;
2158 if (showMouseCursor && e->fType == kMotionNotify) {
2159 if (gCursorWin && e->fWindow == gVirtualX->GetDefaultRootWindow()) {
2160 if (!gCursorWin->IsMapped()) {
2161 gCursorWin->MapRaised();
2163 if (gVirtualX->GetDrawMode() == TVirtualX::kCopy) {
2166 gCursorWin->RaiseWindow();
2168 gCursorWin->Move(e->fXRoot + gDecorWidth, e->fYRoot + gDecorHeight);
2176 if (e->fType == kOtherEvent && e->fFormat >= kGKeyPress &&
2177 e->fFormat < kOtherEvent) {
2178 e->fType = (EGEventType)e->fFormat;
2180 gDragManager->HandleTimerEvent(e, 0);
2186 gClient->HandleEvent(e);
2188 gClient->HandleMaskEvent(e, fMasked);
2196 Event_t *TRecGuiEvent::CreateEvent(TRecGuiEvent *ge)
2198 Event_t *e =
new Event_t();
2202 e->fType = ge->fType;
2203 e->fWindow = ge->fWindow;
2204 e->fTime = ge->fTime;
2208 e->fXRoot = ge->fXRoot;
2209 e->fYRoot = ge->fYRoot;
2211 e->fCode = ge->fCode;
2212 e->fState = ge->fState;
2214 e->fWidth = ge->fWidth;
2215 e->fHeight = ge->fHeight;
2217 e->fCount = ge->fCount;
2218 e->fSendEvent = ge->fSendEvent;
2220 e->fHandle = ge->fHandle;
2221 e->fFormat = ge->fFormat;
2223 if (e->fHandle == TRecGuiEvent::kROOT_MESSAGE)
2224 e->fHandle = gROOT_MESSAGE;
2226 for(Int_t i=0; i<5; ++i)
2227 e->fUser[i] = ge->fUser[i];
2229 if (e->fUser[0] == TRecGuiEvent::kWM_DELETE_WINDOW)
2230 e->fUser[0] = gWM_DELETE_WINDOW;
2232 if (ge->fType == kGKeyPress || ge->fType == kKeyRelease) {
2233 e->fCode = gVirtualX->KeysymToKeycode(ge->fCode);
2236 e->fUser[2] = e->fCode;
2243 ClassImp(TRecWinPair);