Debugger: Tweaks to ConsoleOutputView.
- When receiving console output, we now put it into a pending output list. An asynchronous worker thread then tells the view to add another line to the output view, with a 10 msec delay between lines. This ensures that if the debugged program has a large amount of console output, it doesn't result in the debugger UI going unresponsive due to handling the constant influx of text insertions in rapid succession.
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013, Rene Gollent, [email protected].
|
||||
* Copyright 2013-2014, Rene Gollent, [email protected].
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
@@ -15,9 +15,31 @@
|
||||
#include <String.h>
|
||||
#include <TextView.h>
|
||||
|
||||
#include <AutoDeleter.h>
|
||||
|
||||
|
||||
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<OutputInfo> 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<OutputInfo> 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013, Rene Gollent, [email protected].
|
||||
* Copyright 2013-2014, Rene Gollent, [email protected].
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef CONSOLE_OUTPUT_VIEW_H_
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
|
||||
#include <GroupView.h>
|
||||
#include <ObjectList.h>
|
||||
|
||||
|
||||
class BButton;
|
||||
@@ -31,14 +32,23 @@ public:
|
||||
void LoadSettings(const BMessage& settings);
|
||||
status_t SaveSettings(BMessage& settings);
|
||||
|
||||
private:
|
||||
struct OutputInfo;
|
||||
typedef BObjectList<OutputInfo> 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;
|
||||
};
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user