VirtualBox

source: vbox/trunk/src/VBox/Debugger/VBoxDbgConsole.cpp@ 57388

Last change on this file since 57388 was 57358, checked in by vboxsync, 9 years ago

*: scm cleanup run.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 23.1 KB
Line 
1/* $Id: VBoxDbgConsole.cpp 57358 2015-08-14 15:16:38Z vboxsync $ */
2/** @file
3 * VBox Debugger GUI - Console.
4 */
5
6/*
7 * Copyright (C) 2006-2015 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#define LOG_GROUP LOG_GROUP_DBGG
23#include "VBoxDbgConsole.h"
24
25#include <QLabel>
26#include <QApplication>
27#include <QFont>
28#include <QLineEdit>
29#include <QHBoxLayout>
30#include <QAction>
31#include <QContextMenuEvent>
32#include <QMenu>
33
34#include <VBox/dbg.h>
35#include <VBox/vmm/cfgm.h>
36#include <VBox/err.h>
37
38#include <iprt/thread.h>
39#include <iprt/tcp.h>
40#include <VBox/log.h>
41#include <iprt/assert.h>
42#include <iprt/asm.h>
43#include <iprt/alloc.h>
44#include <iprt/string.h>
45
46
47
48
49/*
50 *
51 * V B o x D b g C o n s o l e O u t p u t
52 * V B o x D b g C o n s o l e O u t p u t
53 * V B o x D b g C o n s o l e O u t p u t
54 *
55 *
56 */
57
58
59VBoxDbgConsoleOutput::VBoxDbgConsoleOutput(QWidget *pParent/* = NULL*/, const char *pszName/* = NULL*/)
60 : QTextEdit(pParent), m_uCurLine(0), m_uCurPos(0), m_hGUIThread(RTThreadNativeSelf())
61{
62 setReadOnly(true);
63 setUndoRedoEnabled(false);
64 setOverwriteMode(false);
65 setPlainText("");
66 setTextInteractionFlags(Qt::TextBrowserInteraction);
67 setAutoFormatting(QTextEdit::AutoAll);
68 setTabChangesFocus(true);
69 setAcceptRichText(false);
70
71 /*
72 * Font.
73 * Create actions for font menu items.
74 */
75 m_pCourierFontAction = new QAction(tr("Courier"), this);
76 m_pCourierFontAction->setCheckable(true);
77 m_pCourierFontAction->setShortcut(Qt::ControlModifier + Qt::Key_D);
78 connect(m_pCourierFontAction, SIGNAL(triggered()), this, SLOT(setFontCourier()));
79
80 m_pMonospaceFontAction = new QAction(tr("Monospace"), this);
81 m_pMonospaceFontAction->setCheckable(true);
82 m_pMonospaceFontAction->setShortcut(Qt::ControlModifier + Qt::Key_M);
83 connect(m_pMonospaceFontAction, SIGNAL(triggered()), this, SLOT(setFontMonospace()));
84
85 /* Create action group for grouping of exclusive font menu items. */
86 QActionGroup *pActionFontGroup = new QActionGroup(this);
87 pActionFontGroup->addAction(m_pCourierFontAction);
88 pActionFontGroup->addAction(m_pMonospaceFontAction);
89 pActionFontGroup->setExclusive(true);
90
91 /*
92 * Color scheme.
93 * Create actions for color-scheme menu items.
94 */
95 m_pGreenOnBlackAction = new QAction(tr("Green On Black"), this);
96 m_pGreenOnBlackAction->setCheckable(true);
97 m_pGreenOnBlackAction->setShortcut(Qt::ControlModifier + Qt::Key_1);
98 connect(m_pGreenOnBlackAction, SIGNAL(triggered()), this, SLOT(setColorGreenOnBlack()));
99
100 m_pBlackOnWhiteAction = new QAction(tr("Black On White"), this);
101 m_pBlackOnWhiteAction->setCheckable(true);
102 m_pBlackOnWhiteAction->setShortcut(Qt::ControlModifier + Qt::Key_2);
103 connect(m_pBlackOnWhiteAction, SIGNAL(triggered()), this, SLOT(setColorBlackOnWhite()));
104
105 /* Create action group for grouping of exclusive color-scheme menu items. */
106 QActionGroup *pActionColorGroup = new QActionGroup(this);
107 pActionColorGroup->addAction(m_pGreenOnBlackAction);
108 pActionColorGroup->addAction(m_pBlackOnWhiteAction);
109 pActionColorGroup->setExclusive(true);
110
111 /*
112 * Set the defaults (which syncs with the menu item checked state).
113 */
114 setFontCourier();
115 setColorGreenOnBlack();
116
117 NOREF(pszName);
118}
119
120
121VBoxDbgConsoleOutput::~VBoxDbgConsoleOutput()
122{
123 Assert(m_hGUIThread == RTThreadNativeSelf());
124}
125
126
127void
128VBoxDbgConsoleOutput::contextMenuEvent(QContextMenuEvent *pEvent)
129{
130 /*
131 * Create the context menu and add the menu items.
132 */
133 QMenu *pMenu = createStandardContextMenu();
134 QMenu *pColorMenu = pMenu->addMenu(tr("Co&lor Scheme"));
135 pColorMenu->addAction(m_pGreenOnBlackAction);
136 pColorMenu->addAction(m_pBlackOnWhiteAction);
137
138 QMenu *pFontMenu = pMenu->addMenu(tr("&Font Family"));
139 pFontMenu->addAction(m_pCourierFontAction);
140 pFontMenu->addAction(m_pMonospaceFontAction);
141
142 pMenu->exec(pEvent->globalPos());
143 delete pMenu;
144}
145
146
147void
148VBoxDbgConsoleOutput::setColorGreenOnBlack()
149{
150 setStyleSheet("QTextEdit { background-color: black; color: rgb(0, 224, 0) }");
151 m_enmColorScheme = kGreenOnBlack;
152
153 /* This is used both as a trigger as well as called independently from code.
154 When used as a trigger, the checked is done automatically by Qt. */
155 if (!m_pGreenOnBlackAction->isChecked())
156 m_pGreenOnBlackAction->setChecked(true);
157}
158
159
160void
161VBoxDbgConsoleOutput::setColorBlackOnWhite()
162{
163 setStyleSheet("QTextEdit { background-color: white; color: black }");
164 m_enmColorScheme = kBlackOnWhite;
165
166 if (!m_pBlackOnWhiteAction->isChecked())
167 m_pBlackOnWhiteAction->setChecked(true);
168}
169
170
171void
172VBoxDbgConsoleOutput::setFontCourier()
173{
174#ifdef Q_WS_MAC
175 QFont Font("Monaco", 10, QFont::Normal, FALSE);
176 Font.setStyleStrategy(QFont::NoAntialias);
177#else
178 QFont Font = font();
179 Font.setStyleHint(QFont::TypeWriter);
180 Font.setFamily("Courier [Monotype]");
181#endif
182 setFont(Font);
183
184 if (!m_pCourierFontAction->isChecked())
185 m_pCourierFontAction->setChecked(true);
186}
187
188
189void
190VBoxDbgConsoleOutput::setFontMonospace()
191{
192 QFont Font = font();
193 Font.setStyleHint(QFont::TypeWriter);
194 Font.setStyleStrategy(QFont::PreferAntialias);
195 Font.setFamily("Monospace [Monotype]");
196 setFont(Font);
197
198 if (!m_pMonospaceFontAction->isChecked())
199 m_pMonospaceFontAction->setChecked(true);
200}
201
202
203void
204VBoxDbgConsoleOutput::appendText(const QString &rStr, bool fClearSelection)
205{
206 Assert(m_hGUIThread == RTThreadNativeSelf());
207
208 if (rStr.isEmpty() || rStr.isNull() || !rStr.length())
209 return;
210
211 /*
212 * Insert all in one go and make sure it's visible.
213 *
214 * We need to move the cursor and unselect any selected text before
215 * inserting anything, otherwise, text will disappear.
216 */
217 QTextCursor Cursor = textCursor();
218 if (!fClearSelection && Cursor.hasSelection())
219 {
220 QTextCursor SavedCursor = Cursor;
221 Cursor.clearSelection();
222 Cursor.movePosition(QTextCursor::End);
223
224 Cursor.insertText(rStr);
225
226 setTextCursor(SavedCursor);
227 }
228 else
229 {
230 if (Cursor.hasSelection())
231 Cursor.clearSelection();
232 if (!Cursor.atEnd())
233 Cursor.movePosition(QTextCursor::End);
234
235 Cursor.insertText(rStr);
236
237 setTextCursor(Cursor);
238 ensureCursorVisible();
239 }
240}
241
242
243
244
245/*
246 *
247 * V B o x D b g C o n s o l e I n p u t
248 * V B o x D b g C o n s o l e I n p u t
249 * V B o x D b g C o n s o l e I n p u t
250 *
251 *
252 */
253
254
255VBoxDbgConsoleInput::VBoxDbgConsoleInput(QWidget *pParent/* = NULL*/, const char *pszName/* = NULL*/)
256 : QComboBox(pParent), m_hGUIThread(RTThreadNativeSelf())
257{
258 addItem(""); /* invariant: empty command line is the last item */
259
260 setEditable(true);
261 setInsertPolicy(NoInsert);
262 setAutoCompletion(false);
263 setMaxCount(50);
264 const QLineEdit *pEdit = lineEdit();
265 if (pEdit)
266 connect(pEdit, SIGNAL(returnPressed()), this, SLOT(returnPressed()));
267
268 NOREF(pszName);
269}
270
271
272VBoxDbgConsoleInput::~VBoxDbgConsoleInput()
273{
274 Assert(m_hGUIThread == RTThreadNativeSelf());
275}
276
277
278void
279VBoxDbgConsoleInput::setLineEdit(QLineEdit *pEdit)
280{
281 Assert(m_hGUIThread == RTThreadNativeSelf());
282 QComboBox::setLineEdit(pEdit);
283 if (lineEdit() == pEdit && pEdit)
284 connect(pEdit, SIGNAL(returnPressed()), this, SLOT(returnPressed()));
285}
286
287
288void
289VBoxDbgConsoleInput::returnPressed()
290{
291 Assert(m_hGUIThread == RTThreadNativeSelf());
292
293 QString strCommand = currentText();
294 /* TODO: trim whitespace? */
295 if (strCommand.isEmpty())
296 return;
297
298 /* deal with the current command. */
299 emit commandSubmitted(strCommand);
300
301
302 /*
303 * Add current command to history.
304 */
305 bool fNeedsAppending = true;
306
307 /* invariant: empty line at the end */
308 int iLastItem = count() - 1;
309 Assert(itemText(iLastItem).isEmpty());
310
311 /* have previous command? check duplicate. */
312 if (iLastItem > 0)
313 {
314 const QString strPrevCommand(itemText(iLastItem - 1));
315 if (strCommand == strPrevCommand)
316 fNeedsAppending = false;
317 }
318
319 if (fNeedsAppending)
320 {
321 /* history full? drop the oldest command. */
322 if (count() == maxCount())
323 {
324 removeItem(0);
325 --iLastItem;
326 }
327
328 /* insert before the empty line. */
329 insertItem(iLastItem, strCommand);
330 }
331
332 /* invariant: empty line at the end */
333 int iNewLastItem = count() - 1;
334 Assert(itemText(iNewLastItem).isEmpty());
335
336 /* select empty line to present "new" command line to the user */
337 setCurrentIndex(iNewLastItem);
338}
339
340
341
342
343
344
345/*
346 *
347 * V B o x D b g C o n s o l e
348 * V B o x D b g C o n s o l e
349 * V B o x D b g C o n s o l e
350 *
351 *
352 */
353
354
355VBoxDbgConsole::VBoxDbgConsole(VBoxDbgGui *a_pDbgGui, QWidget *a_pParent/* = NULL*/)
356 : VBoxDbgBaseWindow(a_pDbgGui, a_pParent), m_pOutput(NULL), m_pInput(NULL), m_fInputRestoreFocus(false),
357 m_pszInputBuf(NULL), m_cbInputBuf(0), m_cbInputBufAlloc(0),
358 m_pszOutputBuf(NULL), m_cbOutputBuf(0), m_cbOutputBufAlloc(0),
359 m_pTimer(NULL), m_fUpdatePending(false), m_Thread(NIL_RTTHREAD), m_EventSem(NIL_RTSEMEVENT),
360 m_fTerminate(false), m_fThreadTerminated(false)
361{
362 setWindowTitle("VBoxDbg - Console");
363
364 /*
365 * Create the output text box.
366 */
367 m_pOutput = new VBoxDbgConsoleOutput(this);
368
369 /* try figure a suitable size */
370 QLabel *pLabel = new QLabel( "11111111111111111111111111111111111111111111111111111111111111111111111111111112222222222", this);
371 pLabel->setFont(m_pOutput->font());
372 QSize Size = pLabel->sizeHint();
373 delete pLabel;
374 Size.setWidth((int)(Size.width() * 1.10));
375 Size.setHeight(Size.width() / 2);
376 resize(Size);
377
378 /*
379 * Create the input combo box (with a label).
380 */
381 QHBoxLayout *pLayout = new QHBoxLayout();
382 //pLayout->setSizeConstraint(QLayout::SetMaximumSize);
383
384 pLabel = new QLabel(" Command ");
385 pLayout->addWidget(pLabel);
386 pLabel->setMaximumSize(pLabel->sizeHint());
387 pLabel->setAlignment(Qt::AlignCenter);
388
389 m_pInput = new VBoxDbgConsoleInput(NULL);
390 pLayout->addWidget(m_pInput);
391 m_pInput->setDuplicatesEnabled(false);
392 connect(m_pInput, SIGNAL(commandSubmitted(const QString &)), this, SLOT(commandSubmitted(const QString &)));
393
394# if 0//def Q_WS_MAC
395 pLabel = new QLabel(" ");
396 pLayout->addWidget(pLabel);
397 pLabel->setMaximumSize(20, m_pInput->sizeHint().height() + 6);
398 pLabel->setMinimumSize(20, m_pInput->sizeHint().height() + 6);
399# endif
400
401 QWidget *pHBox = new QWidget(this);
402 pHBox->setLayout(pLayout);
403
404 m_pInput->setEnabled(false); /* (we'll get a ready notification) */
405
406
407 /*
408 * Vertical layout box on the whole widget.
409 */
410 QVBoxLayout *pVLayout = new QVBoxLayout();
411 pVLayout->setContentsMargins(0, 0, 0, 0);
412 pVLayout->setSpacing(5);
413 pVLayout->addWidget(m_pOutput);
414 pVLayout->addWidget(pHBox);
415 setLayout(pVLayout);
416
417 /*
418 * The tab order is from input to output, not the other way around as it is by default.
419 */
420 setTabOrder(m_pInput, m_pOutput);
421 m_fInputRestoreFocus = true; /* hack */
422
423 /*
424 * Setup the timer.
425 */
426 m_pTimer = new QTimer(this);
427 connect(m_pTimer, SIGNAL(timeout()), SLOT(updateOutput()));
428
429 /*
430 * Init the backend structure.
431 */
432 m_Back.Core.pfnInput = backInput;
433 m_Back.Core.pfnRead = backRead;
434 m_Back.Core.pfnWrite = backWrite;
435 m_Back.Core.pfnSetReady = backSetReady;
436 m_Back.pSelf = this;
437
438 /*
439 * Create the critical section, the event semaphore and the debug console thread.
440 */
441 int rc = RTCritSectInit(&m_Lock);
442 AssertRC(rc);
443
444 rc = RTSemEventCreate(&m_EventSem);
445 AssertRC(rc);
446
447 rc = RTThreadCreate(&m_Thread, backThread, this, 0, RTTHREADTYPE_DEBUGGER, RTTHREADFLAGS_WAITABLE, "VBoxDbgC");
448 AssertRC(rc);
449 if (RT_FAILURE(rc))
450 m_Thread = NIL_RTTHREAD;
451
452 /*
453 * Shortcuts.
454 */
455 m_pFocusToInput = new QAction("", this);
456 m_pFocusToInput->setShortcut(QKeySequence("Ctrl+L"));
457 addAction(m_pFocusToInput);
458 connect(m_pFocusToInput, SIGNAL(triggered(bool)), this, SLOT(actFocusToInput()));
459
460 m_pFocusToOutput = new QAction("", this);
461 m_pFocusToOutput->setShortcut(QKeySequence("Ctrl+O"));
462 addAction(m_pFocusToOutput);
463 connect(m_pFocusToOutput, SIGNAL(triggered(bool)), this, SLOT(actFocusToOutput()));
464
465 addAction(m_pOutput->m_pBlackOnWhiteAction);
466 addAction(m_pOutput->m_pGreenOnBlackAction);
467 addAction(m_pOutput->m_pCourierFontAction);
468 addAction(m_pOutput->m_pMonospaceFontAction);
469}
470
471
472VBoxDbgConsole::~VBoxDbgConsole()
473{
474 Assert(isGUIThread());
475
476 /*
477 * Wait for the thread.
478 */
479 ASMAtomicWriteBool(&m_fTerminate, true);
480 RTSemEventSignal(m_EventSem);
481 if (m_Thread != NIL_RTTHREAD)
482 {
483 int rc = RTThreadWait(m_Thread, 15000, NULL);
484 AssertRC(rc);
485 m_Thread = NIL_RTTHREAD;
486 }
487
488 /*
489 * Free resources.
490 */
491 delete m_pTimer;
492 m_pTimer = NULL;
493 RTCritSectDelete(&m_Lock);
494 RTSemEventDestroy(m_EventSem);
495 m_EventSem = 0;
496 m_pOutput = NULL;
497 m_pInput = NULL;
498 if (m_pszInputBuf)
499 {
500 RTMemFree(m_pszInputBuf);
501 m_pszInputBuf = NULL;
502 }
503 m_cbInputBuf = 0;
504 m_cbInputBufAlloc = 0;
505
506 delete m_pFocusToInput;
507 m_pFocusToInput = NULL;
508 delete m_pFocusToOutput;
509 m_pFocusToOutput = NULL;
510}
511
512
513void
514VBoxDbgConsole::commandSubmitted(const QString &rCommand)
515{
516 Assert(isGUIThread());
517
518 lock();
519 RTSemEventSignal(m_EventSem);
520
521 QByteArray Utf8Array = rCommand.toUtf8();
522 const char *psz = Utf8Array.constData();
523 size_t cb = strlen(psz);
524
525 /*
526 * Make sure we've got space for the input.
527 */
528 if (cb + m_cbInputBuf >= m_cbInputBufAlloc)
529 {
530 size_t cbNew = RT_ALIGN_Z(cb + m_cbInputBufAlloc + 1, 128);
531 void *pv = RTMemRealloc(m_pszInputBuf, cbNew);
532 if (!pv)
533 {
534 unlock();
535 return;
536 }
537 m_pszInputBuf = (char *)pv;
538 m_cbInputBufAlloc = cbNew;
539 }
540
541 /*
542 * Add the input and output it.
543 */
544 memcpy(m_pszInputBuf + m_cbInputBuf, psz, cb);
545 m_cbInputBuf += cb;
546 m_pszInputBuf[m_cbInputBuf++] = '\n';
547
548 m_pOutput->appendText(rCommand + "\n", true /*fClearSelection*/);
549 m_pOutput->ensureCursorVisible();
550
551 m_fInputRestoreFocus = m_pInput->hasFocus(); /* dirty focus hack */
552 m_pInput->setEnabled(false);
553
554 Log(("VBoxDbgConsole::commandSubmitted: %s (input-enabled=%RTbool)\n", psz, m_pInput->isEnabled()));
555 unlock();
556}
557
558
559void
560VBoxDbgConsole::updateOutput()
561{
562 Assert(isGUIThread());
563
564 lock();
565 m_fUpdatePending = false;
566 if (m_cbOutputBuf)
567 {
568 m_pOutput->appendText(QString::fromUtf8((const char *)m_pszOutputBuf, (int)m_cbOutputBuf), false /*fClearSelection*/);
569 m_cbOutputBuf = 0;
570 }
571 unlock();
572}
573
574
575/**
576 * Lock the object.
577 */
578void
579VBoxDbgConsole::lock()
580{
581 RTCritSectEnter(&m_Lock);
582}
583
584
585/**
586 * Unlocks the object.
587 */
588void
589VBoxDbgConsole::unlock()
590{
591 RTCritSectLeave(&m_Lock);
592}
593
594
595
596/**
597 * Checks if there is input.
598 *
599 * @returns true if there is input ready.
600 * @returns false if there not input ready.
601 * @param pBack Pointer to VBoxDbgConsole::m_Back.
602 * @param cMillies Number of milliseconds to wait on input data.
603 */
604/*static*/ DECLCALLBACK(bool)
605VBoxDbgConsole::backInput(PDBGCBACK pBack, uint32_t cMillies)
606{
607 VBoxDbgConsole *pThis = VBOXDBGCONSOLE_FROM_DBGCBACK(pBack);
608 pThis->lock();
609
610 bool fRc = true;
611 if (!pThis->m_cbInputBuf)
612 {
613 /*
614 * Wait outside the lock for the requested time, then check again.
615 */
616 pThis->unlock();
617 RTSemEventWait(pThis->m_EventSem, cMillies);
618 pThis->lock();
619 fRc = pThis->m_cbInputBuf
620 || ASMAtomicUoReadBool(&pThis->m_fTerminate);
621 }
622
623 pThis->unlock();
624 return fRc;
625}
626
627
628/**
629 * Read input.
630 *
631 * @returns VBox status code.
632 * @param pBack Pointer to VBoxDbgConsole::m_Back.
633 * @param pvBuf Where to put the bytes we read.
634 * @param cbBuf Maximum nymber of bytes to read.
635 * @param pcbRead Where to store the number of bytes actually read.
636 * If NULL the entire buffer must be filled for a
637 * successful return.
638 */
639/*static*/ DECLCALLBACK(int)
640VBoxDbgConsole::backRead(PDBGCBACK pBack, void *pvBuf, size_t cbBuf, size_t *pcbRead)
641{
642 VBoxDbgConsole *pThis = VBOXDBGCONSOLE_FROM_DBGCBACK(pBack);
643 Assert(pcbRead); /** @todo implement this bit */
644 if (pcbRead)
645 *pcbRead = 0;
646
647 pThis->lock();
648 int rc = VINF_SUCCESS;
649 if (!ASMAtomicUoReadBool(&pThis->m_fTerminate))
650 {
651 if (pThis->m_cbInputBuf)
652 {
653 const char *psz = pThis->m_pszInputBuf;
654 size_t cbRead = RT_MIN(pThis->m_cbInputBuf, cbBuf);
655 memcpy(pvBuf, psz, cbRead);
656 psz += cbRead;
657 pThis->m_cbInputBuf -= cbRead;
658 if (*psz)
659 memmove(pThis->m_pszInputBuf, psz, pThis->m_cbInputBuf);
660 pThis->m_pszInputBuf[pThis->m_cbInputBuf] = '\0';
661 *pcbRead = cbRead;
662 }
663 }
664 else
665 rc = VERR_GENERAL_FAILURE;
666 pThis->unlock();
667 return rc;
668}
669
670
671/**
672 * Write (output).
673 *
674 * @returns VBox status code.
675 * @param pBack Pointer to VBoxDbgConsole::m_Back.
676 * @param pvBuf What to write.
677 * @param cbBuf Number of bytes to write.
678 * @param pcbWritten Where to store the number of bytes actually written.
679 * If NULL the entire buffer must be successfully written.
680 */
681/*static*/ DECLCALLBACK(int)
682VBoxDbgConsole::backWrite(PDBGCBACK pBack, const void *pvBuf, size_t cbBuf, size_t *pcbWritten)
683{
684 VBoxDbgConsole *pThis = VBOXDBGCONSOLE_FROM_DBGCBACK(pBack);
685 int rc = VINF_SUCCESS;
686
687 pThis->lock();
688 if (cbBuf + pThis->m_cbOutputBuf >= pThis->m_cbOutputBufAlloc)
689 {
690 size_t cbNew = RT_ALIGN_Z(cbBuf + pThis->m_cbOutputBufAlloc + 1, 1024);
691 void *pv = RTMemRealloc(pThis->m_pszOutputBuf, cbNew);
692 if (!pv)
693 {
694 pThis->unlock();
695 if (pcbWritten)
696 *pcbWritten = 0;
697 return VERR_NO_MEMORY;
698 }
699 pThis->m_pszOutputBuf = (char *)pv;
700 pThis->m_cbOutputBufAlloc = cbNew;
701 }
702
703 /*
704 * Add the output.
705 */
706 memcpy(pThis->m_pszOutputBuf + pThis->m_cbOutputBuf, pvBuf, cbBuf);
707 pThis->m_cbOutputBuf += cbBuf;
708 pThis->m_pszOutputBuf[pThis->m_cbOutputBuf] = '\0';
709 if (pcbWritten)
710 *pcbWritten = cbBuf;
711
712 if (ASMAtomicUoReadBool(&pThis->m_fTerminate))
713 rc = VERR_GENERAL_FAILURE;
714
715 /*
716 * Tell the GUI thread to draw this text.
717 * We cannot do it from here without frequent crashes.
718 */
719 if (!pThis->m_fUpdatePending)
720 QApplication::postEvent(pThis, new VBoxDbgConsoleEvent(VBoxDbgConsoleEvent::kUpdate));
721
722 pThis->unlock();
723
724 return rc;
725}
726
727
728/*static*/ DECLCALLBACK(void)
729VBoxDbgConsole::backSetReady(PDBGCBACK pBack, bool fReady)
730{
731 VBoxDbgConsole *pThis = VBOXDBGCONSOLE_FROM_DBGCBACK(pBack);
732 if (fReady)
733 QApplication::postEvent(pThis, new VBoxDbgConsoleEvent(VBoxDbgConsoleEvent::kInputEnable));
734}
735
736
737/**
738 * The Debugger Console Thread
739 *
740 * @returns VBox status code (ignored).
741 * @param Thread The thread handle.
742 * @param pvUser Pointer to the VBoxDbgConsole object.s
743 */
744/*static*/ DECLCALLBACK(int)
745VBoxDbgConsole::backThread(RTTHREAD Thread, void *pvUser)
746{
747 VBoxDbgConsole *pThis = (VBoxDbgConsole *)pvUser;
748 LogFlow(("backThread: Thread=%p pvUser=%p\n", (void *)Thread, pvUser));
749
750 NOREF(Thread);
751
752 /*
753 * Create and execute the console.
754 */
755 int rc = pThis->dbgcCreate(&pThis->m_Back.Core, 0);
756
757 ASMAtomicUoWriteBool(&pThis->m_fThreadTerminated, true);
758 if (!ASMAtomicUoReadBool(&pThis->m_fTerminate))
759 QApplication::postEvent(pThis, new VBoxDbgConsoleEvent(rc == VINF_SUCCESS
760 ? VBoxDbgConsoleEvent::kTerminatedUser
761 : VBoxDbgConsoleEvent::kTerminatedOther));
762 LogFlow(("backThread: returns %Rrc (m_fTerminate=%RTbool)\n", rc, ASMAtomicUoReadBool(&pThis->m_fTerminate)));
763 return rc;
764}
765
766
767bool
768VBoxDbgConsole::event(QEvent *pGenEvent)
769{
770 Assert(isGUIThread());
771 if (pGenEvent->type() == (QEvent::Type)VBoxDbgConsoleEvent::kEventNumber)
772 {
773 VBoxDbgConsoleEvent *pEvent = (VBoxDbgConsoleEvent *)pGenEvent;
774
775 switch (pEvent->command())
776 {
777 /* make update pending. */
778 case VBoxDbgConsoleEvent::kUpdate:
779 lock();
780 if (!m_fUpdatePending)
781 {
782 m_fUpdatePending = true;
783 m_pTimer->setSingleShot(true);
784 m_pTimer->start(10);
785 }
786 unlock();
787 break;
788
789 /* Re-enable the input field and restore focus. */
790 case VBoxDbgConsoleEvent::kInputEnable:
791 Log(("VBoxDbgConsole: kInputEnable (input-enabled=%RTbool)\n", m_pInput->isEnabled()));
792 m_pInput->setEnabled(true);
793 if ( m_fInputRestoreFocus
794 && !m_pInput->hasFocus())
795 m_pInput->setFocus(); /* this is a hack. */
796 m_fInputRestoreFocus = false;
797 break;
798
799 /* The thread terminated by user command (exit, quit, bye). */
800 case VBoxDbgConsoleEvent::kTerminatedUser:
801 Log(("VBoxDbgConsole: kTerminatedUser (input-enabled=%RTbool)\n", m_pInput->isEnabled()));
802 m_pInput->setEnabled(false);
803 close();
804 break;
805
806 /* The thread terminated for some unknown reason., disable input */
807 case VBoxDbgConsoleEvent::kTerminatedOther:
808 Log(("VBoxDbgConsole: kTerminatedOther (input-enabled=%RTbool)\n", m_pInput->isEnabled()));
809 m_pInput->setEnabled(false);
810 break;
811
812 /* paranoia */
813 default:
814 AssertMsgFailed(("command=%d\n", pEvent->command()));
815 break;
816 }
817 return true;
818 }
819
820 return VBoxDbgBaseWindow::event(pGenEvent);
821}
822
823
824void
825VBoxDbgConsole::closeEvent(QCloseEvent *a_pCloseEvt)
826{
827 if (m_fThreadTerminated)
828 {
829 a_pCloseEvt->accept();
830 delete this;
831 }
832}
833
834
835void
836VBoxDbgConsole::actFocusToInput()
837{
838 if (!m_pInput->hasFocus())
839 m_pInput->setFocus(Qt::ShortcutFocusReason);
840}
841
842
843void
844VBoxDbgConsole::actFocusToOutput()
845{
846 if (!m_pOutput->hasFocus())
847 m_pOutput->setFocus(Qt::ShortcutFocusReason);
848}
849
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette