VBoxDbgConsole.cpp revision eb64ee0abd56a8f7d9b102e00294404f96398a82
/* $Id$ */
/** @file
* VBox Debugger GUI - Console.
*/
/*
* Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*/
/*******************************************************************************
* Header Files *
*******************************************************************************/
#define LOG_GROUP LOG_GROUP_DBGG
#include "VBoxDbgConsole.h"
#include <QLabel>
#include <QApplication>
#include <QFont>
#include <QLineEdit>
#include <QHBoxLayout>
#include <QAction>
#include <QContextMenuEvent>
#include <QMenu>
/*
*
* V B o x D b g C o n s o l e O u t p u t
* V B o x D b g C o n s o l e O u t p u t
* V B o x D b g C o n s o l e O u t p u t
*
*
*/
VBoxDbgConsoleOutput::VBoxDbgConsoleOutput(QWidget *pParent/* = NULL*/, const char *pszName/* = NULL*/)
{
setReadOnly(true);
setUndoRedoEnabled(false);
setOverwriteMode(false);
setPlainText("");
setTabChangesFocus(true);
setAcceptRichText(false);
/*
* Font.
* Create actions for font menu items.
*/
m_pCourierFontAction->setCheckable(true);
m_pMonospaceFontAction->setCheckable(true);
/* Create action group for grouping of exclusive font menu items. */
pActionFontGroup->setExclusive(true);
/*
* Color scheme.
* Create actions for color-scheme menu items.
*/
m_pGreenOnBlackAction->setCheckable(true);
m_pBlackOnWhiteAction->setCheckable(true);
/* Create action group for grouping of exclusive color-scheme menu items. */
pActionColorGroup->setExclusive(true);
/*
* Set the defaults (which syncs with the menu item checked state).
*/
}
{
}
void
{
/*
* Create the context menu and add the menu items.
*/
delete pMenu;
}
void
{
setStyleSheet("QTextEdit { background-color: black; color: rgb(0, 224, 0) }");
/* This is used both as a trigger as well as called independently from code.
When used as a trigger, the checked is done automatically by Qt. */
if (!m_pGreenOnBlackAction->isChecked())
m_pGreenOnBlackAction->setChecked(true);
}
void
{
setStyleSheet("QTextEdit { background-color: white; color: black }");
if (!m_pBlackOnWhiteAction->isChecked())
m_pBlackOnWhiteAction->setChecked(true);
}
void
{
#ifdef Q_WS_MAC
#else
#endif
if (!m_pCourierFontAction->isChecked())
m_pCourierFontAction->setChecked(true);
}
void
{
if (!m_pMonospaceFontAction->isChecked())
m_pMonospaceFontAction->setChecked(true);
}
void
{
return;
/*
* Insert all in one go and make sure it's visible.
*
* We need to move the cursor and unselect any selected text before
* inserting anything, otherwise, text will disappear.
*/
{
}
else
{
if (Cursor.hasSelection())
}
}
/*
*
* V B o x D b g C o n s o l e I n p u t
* V B o x D b g C o n s o l e I n p u t
* V B o x D b g C o n s o l e I n p u t
*
*
*/
VBoxDbgConsoleInput::VBoxDbgConsoleInput(QWidget *pParent/* = NULL*/, const char *pszName/* = NULL*/)
{
setEditable(true);
setAutoCompletion(false);
setMaxCount(50);
if (pEdit)
}
{
}
void
{
}
void
{
/* TODO: trim whitespace? */
if (strCommand.isEmpty())
return;
/* deal with the current command. */
/*
* Add current command to history.
*/
bool fNeedsAppending = true;
/* invariant: empty line at the end */
/* have previous command? check duplicate. */
if (iLastItem > 0)
{
if (strCommand == strPrevCommand)
fNeedsAppending = false;
}
if (fNeedsAppending)
{
/* history full? drop the oldest command. */
{
removeItem(0);
--iLastItem;
}
/* insert before the empty line. */
}
/* invariant: empty line at the end */
/* select empty line to present "new" command line to the user */
}
/*
*
* V B o x D b g C o n s o l e
* V B o x D b g C o n s o l e
* V B o x D b g C o n s o l e
*
*
*/
: VBoxDbgBaseWindow(a_pDbgGui, a_pParent), m_pOutput(NULL), m_pInput(NULL), m_fInputRestoreFocus(false),
m_fTerminate(false), m_fThreadTerminated(false)
{
setWindowTitle("VBoxDbg - Console");
/*
* Create the output text box.
*/
m_pOutput = new VBoxDbgConsoleOutput(this);
/* try figure a suitable size */
QLabel *pLabel = new QLabel( "11111111111111111111111111111111111111111111111111111111111111111111111111111112222222222", this);
delete pLabel;
/*
* Create the input combo box (with a label).
*/
//pLayout->setSizeConstraint(QLayout::SetMaximumSize);
m_pInput->setDuplicatesEnabled(false);
connect(m_pInput, SIGNAL(commandSubmitted(const QString &)), this, SLOT(commandSubmitted(const QString &)));
# if 0//def Q_WS_MAC
# endif
/*
* Vertical layout box on the whole widget.
*/
pVLayout->setContentsMargins(0, 0, 0, 0);
/*
* The tab order is from input to output, not the other way around as it is by default.
*/
m_fInputRestoreFocus = true; /* hack */
/*
* Setup the timer.
*/
/*
* Init the backend structure.
*/
/*
* Create the critical section, the event semaphore and the debug console thread.
*/
rc = RTThreadCreate(&m_Thread, backThread, this, 0, RTTHREADTYPE_DEBUGGER, RTTHREADFLAGS_WAITABLE, "VBoxDbgC");
if (RT_FAILURE(rc))
/*
* Shortcuts.
*/
}
{
Assert(isGUIThread());
/*
* Wait for the thread.
*/
ASMAtomicWriteBool(&m_fTerminate, true);
if (m_Thread != NIL_RTTHREAD)
{
}
/*
* Free resources.
*/
delete m_pTimer;
m_EventSem = 0;
if (m_pszInputBuf)
{
}
m_cbInputBuf = 0;
m_cbInputBufAlloc = 0;
delete m_pFocusToInput;
delete m_pFocusToOutput;
}
void
{
Assert(isGUIThread());
lock();
/*
* Make sure we've got space for the input.
*/
{
if (!pv)
{
unlock();
return;
}
m_pszInputBuf = (char *)pv;
}
/*
* Add the input and output it.
*/
m_cbInputBuf += cb;
m_pInput->setEnabled(false);
Log(("VBoxDbgConsole::commandSubmitted: %s (input-enabled=%RTbool)\n", psz, m_pInput->isEnabled()));
unlock();
}
void
{
Assert(isGUIThread());
lock();
m_fUpdatePending = false;
if (m_cbOutputBuf)
{
m_pOutput->appendText(QString::fromUtf8((const char *)m_pszOutputBuf, (int)m_cbOutputBuf), false /*fClearSelection*/);
m_cbOutputBuf = 0;
}
unlock();
}
/**
* Lock the object.
*/
void
{
}
/**
* Unlocks the object.
*/
void
{
}
/**
* Checks if there is input.
*
* @returns true if there is input ready.
* @returns false if there not input ready.
* @param pBack Pointer to VBoxDbgConsole::m_Back.
* @param cMillies Number of milliseconds to wait on input data.
*/
/*static*/ DECLCALLBACK(bool)
{
bool fRc = true;
if (!pThis->m_cbInputBuf)
{
/*
* Wait outside the lock for the requested time, then check again.
*/
}
return fRc;
}
/**
* Read input.
*
* @returns VBox status code.
* @param pBack Pointer to VBoxDbgConsole::m_Back.
* @param pvBuf Where to put the bytes we read.
* @param cbBuf Maximum nymber of bytes to read.
* @param pcbRead Where to store the number of bytes actually read.
* If NULL the entire buffer must be filled for a
* successful return.
*/
/*static*/ DECLCALLBACK(int)
{
if (pcbRead)
*pcbRead = 0;
int rc = VINF_SUCCESS;
{
if (pThis->m_cbInputBuf)
{
if (*psz)
}
}
else
return rc;
}
/**
* Write (output).
*
* @returns VBox status code.
* @param pBack Pointer to VBoxDbgConsole::m_Back.
* @param pvBuf What to write.
* @param cbBuf Number of bytes to write.
* @param pcbWritten Where to store the number of bytes actually written.
* If NULL the entire buffer must be successfully written.
*/
/*static*/ DECLCALLBACK(int)
{
int rc = VINF_SUCCESS;
{
if (!pv)
{
if (pcbWritten)
*pcbWritten = 0;
return VERR_NO_MEMORY;
}
}
/*
* Add the output.
*/
if (pcbWritten)
*pcbWritten = cbBuf;
/*
* Tell the GUI thread to draw this text.
* We cannot do it from here without frequent crashes.
*/
if (!pThis->m_fUpdatePending)
return rc;
}
/*static*/ DECLCALLBACK(void)
{
if (fReady)
}
/**
* The Debugger Console Thread
*
* @returns VBox status code (ignored).
* @param Thread The thread handle.
* @param pvUser Pointer to the VBoxDbgConsole object.s
*/
/*static*/ DECLCALLBACK(int)
{
/*
* Create and execute the console.
*/
LogFlow(("backThread: returns %Rrc (m_fTerminate=%RTbool)\n", rc, ASMAtomicUoReadBool(&pThis->m_fTerminate)));
return rc;
}
bool
{
Assert(isGUIThread());
{
{
/* make update pending. */
case VBoxDbgConsoleEvent::kUpdate:
lock();
if (!m_fUpdatePending)
{
m_fUpdatePending = true;
m_pTimer->setSingleShot(true);
}
unlock();
break;
/* Re-enable the input field and restore focus. */
case VBoxDbgConsoleEvent::kInputEnable:
m_pInput->setEnabled(true);
if ( m_fInputRestoreFocus
m_fInputRestoreFocus = false;
break;
/* The thread terminated by user command (exit, quit, bye). */
m_pInput->setEnabled(false);
close();
break;
/* The thread terminated for some unknown reason., disable input */
m_pInput->setEnabled(false);
break;
/* paranoia */
default:
break;
}
return true;
}
}
void
{
if (m_fThreadTerminated)
{
a_pCloseEvt->accept();
delete this;
}
}
void
{
}
void
{
}