diff --git a/src/apps/debugger/user_interface/gui/team_window/ConsoleOutputView.cpp b/src/apps/debugger/user_interface/gui/team_window/ConsoleOutputView.cpp index cc5876fa24..3272d6e1c8 100644 --- a/src/apps/debugger/user_interface/gui/team_window/ConsoleOutputView.cpp +++ b/src/apps/debugger/user_interface/gui/team_window/ConsoleOutputView.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2013, Rene Gollent, rene@gollent.com. + * Copyright 2013-2014, Rene Gollent, rene@gollent.com. * Distributed under the terms of the MIT License. */ @@ -15,9 +15,31 @@ #include #include +#include + enum { - MSG_CLEAR_OUTPUT = 'clou' + MSG_CLEAR_OUTPUT = 'clou', + MSG_POST_OUTPUT = 'poou' +}; + + +static const bigtime_t kOutputWaitInterval = 10000; + + +// #pragma mark - ConsoleOutputView::OutputInfo + + +struct ConsoleOutputView::OutputInfo { + int32 fd; + BString text; + + OutputInfo(int32 fd, const BString& text) + : + fd(fd), + text(text) + { + } }; @@ -30,7 +52,10 @@ ConsoleOutputView::ConsoleOutputView() fStdoutEnabled(NULL), fStderrEnabled(NULL), fConsoleOutput(NULL), - fClearButton(NULL) + fClearButton(NULL), + fPendingOutput(NULL), + fWorkToDoSem(-1), + fOutputWorker(-1) { SetName("ConsoleOutput"); } @@ -38,6 +63,13 @@ ConsoleOutputView::ConsoleOutputView() ConsoleOutputView::~ConsoleOutputView() { + if (fWorkToDoSem > 0) + delete_sem(fWorkToDoSem); + + if (fOutputWorker > 0) + wait_for_thread(fOutputWorker, NULL); + + delete fPendingOutput; } @@ -65,27 +97,14 @@ ConsoleOutputView::ConsoleOutputReceived(int32 fd, const BString& output) else if (fd == 2 && fStderrEnabled->Value() != B_CONTROL_ON) return; - text_run_array run; - run.count = 1; - run.runs[0].font = be_fixed_font; - run.runs[0].offset = 0; - run.runs[0].color.red = fd == 1 ? 0 : 192; - run.runs[0].color.green = 0; - run.runs[0].color.blue = 0; - run.runs[0].color.alpha = 255; + OutputInfo* info = new(std::nothrow) OutputInfo(fd, output); + if (info == NULL) + return; - bool autoScroll = false; - BScrollBar* scroller = fConsoleOutput->ScrollBar(B_VERTICAL); - float min, max; - scroller->GetRange(&min, &max); - if (min == max || scroller->Value() == max) - autoScroll = true; - - fConsoleOutput->Insert(fConsoleOutput->TextLength(), output.String(), - output.Length(), &run); - if (autoScroll) { - scroller->GetRange(&min, &max); - fConsoleOutput->ScrollTo(0.0, max); + ObjectDeleter infoDeleter(info); + if (fPendingOutput->AddItem(info)) { + infoDeleter.Detach(); + release_sem(fWorkToDoSem); } } @@ -97,8 +116,18 @@ ConsoleOutputView::MessageReceived(BMessage* message) case MSG_CLEAR_OUTPUT: { fConsoleOutput->SetText(""); + fPendingOutput->MakeEmpty(); break; } + case MSG_POST_OUTPUT: + { + OutputInfo* info = fPendingOutput->RemoveItemAt(0); + if (info == NULL) + break; + + ObjectDeleter infoDeleter(info); + _HandleConsoleOutput(info); + } default: BGroupView::MessageReceived(message); break; @@ -145,6 +174,18 @@ ConsoleOutputView::SaveSettings(BMessage& settings) void ConsoleOutputView::_Init() { + fPendingOutput = new OutputInfoList(10, true); + + fWorkToDoSem = create_sem(0, "output_work_available"); + if (fWorkToDoSem < 0) + throw std::bad_alloc(); + + fOutputWorker = spawn_thread(_OutputWorker, "output worker", B_LOW_PRIORITY, this); + if (fOutputWorker < 0) + throw std::bad_alloc(); + + resume_thread(fOutputWorker); + BScrollView* consoleScrollView; BLayoutBuilder::Group<>(this, B_HORIZONTAL, 0.0f) @@ -166,3 +207,56 @@ ConsoleOutputView::_Init() fConsoleOutput->SetStylable(true); fConsoleOutput->SetDoesUndo(false); } + + +int32 +ConsoleOutputView::_OutputWorker(void* arg) +{ + ConsoleOutputView* view = (ConsoleOutputView*)arg; + + for (;;) { + status_t error = acquire_sem(view->fWorkToDoSem); + if (error == B_INTERRUPTED) + continue; + else if (error != B_OK) + break; + + BMessenger(view).SendMessage(MSG_POST_OUTPUT); + snooze(kOutputWaitInterval); + } + + return B_OK; +} + + +void +ConsoleOutputView::_HandleConsoleOutput(OutputInfo* info) +{ + if (info->fd == 1 && fStdoutEnabled->Value() != B_CONTROL_ON) + return; + else if (info->fd == 2 && fStderrEnabled->Value() != B_CONTROL_ON) + return; + + text_run_array run; + run.count = 1; + run.runs[0].font = be_fixed_font; + run.runs[0].offset = 0; + run.runs[0].color.red = info->fd == 1 ? 0 : 192; + run.runs[0].color.green = 0; + run.runs[0].color.blue = 0; + run.runs[0].color.alpha = 255; + + bool autoScroll = false; + BScrollBar* scroller = fConsoleOutput->ScrollBar(B_VERTICAL); + float min, max; + scroller->GetRange(&min, &max); + if (min == max || scroller->Value() == max) + autoScroll = true; + + fConsoleOutput->Insert(fConsoleOutput->TextLength(), info->text, + info->text.Length(), &run); + if (autoScroll) { + scroller->GetRange(&min, &max); + fConsoleOutput->ScrollTo(0.0, max); + } +} diff --git a/src/apps/debugger/user_interface/gui/team_window/ConsoleOutputView.h b/src/apps/debugger/user_interface/gui/team_window/ConsoleOutputView.h index 5413323c66..b1cbd43ef9 100644 --- a/src/apps/debugger/user_interface/gui/team_window/ConsoleOutputView.h +++ b/src/apps/debugger/user_interface/gui/team_window/ConsoleOutputView.h @@ -1,5 +1,5 @@ /* - * Copyright 2013, Rene Gollent, rene@gollent.com. + * Copyright 2013-2014, Rene Gollent, rene@gollent.com. * Distributed under the terms of the MIT License. */ #ifndef CONSOLE_OUTPUT_VIEW_H_ @@ -7,6 +7,7 @@ #include +#include class BButton; @@ -31,14 +32,23 @@ public: void LoadSettings(const BMessage& settings); status_t SaveSettings(BMessage& settings); +private: + struct OutputInfo; + typedef BObjectList OutputInfoList; + private: void _Init(); + static int32 _OutputWorker(void* arg); + void _HandleConsoleOutput(OutputInfo* info); private: BCheckBox* fStdoutEnabled; BCheckBox* fStderrEnabled; BTextView* fConsoleOutput; BButton* fClearButton; + OutputInfoList* fPendingOutput; + sem_id fWorkToDoSem; + thread_id fOutputWorker; };