// SPDX-FileCopyrightText: 2021 Ernie Pasveer <epasveer@att.net>
//
// SPDX-License-Identifier: GPL-3.0-or-later

#include "SeerGdbWidget.h"
#include "SeerLogWidget.h"
#include "SeerMemoryVisualizerWidget.h"
#include "SeerArrayVisualizerWidget.h"
#include "SeerMatrixVisualizerWidget.h"
#include "SeerStructVisualizerWidget.h"
#include "SeerVarVisualizerWidget.h"
#include "SeerImageVisualizerWidget.h"
#include "SeerGdbMonitorWidget.h"
#include "SeerHelpPageDialog.h"
#include "SeerUtl.h"
#include "QHContainerWidget.h"
#include <QtGui/QFont>
#include <QtGui/QGuiApplication>
#include <QtWidgets/QApplication>
#include <QtWidgets/QMessageBox>
#include <QtWidgets/QFileDialog>
#include <QtCore/QLoggingCategory>
#include <QtCore/QSettings>
#include <QtCore/QProcess>
#include <QtCore/QRegularExpression>
#include <QtCore/QDir>
#include <QtCore/QFile>
#include <QtCore/QFileInfo>
#include <QtCore/QFileInfoList>
#include <QtCore/QThread>
#include <QtCore/QDebug>
#include <QtGlobal>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <termios.h>
#include <sys/ioctl.h>
#include <signal.h>
#include <string.h>
#include <errno.h>

static QLoggingCategory LC("seer.gdbwidget");

SeerGdbWidget::SeerGdbWidget (QWidget* parent) : QWidget(parent) {

    _executableName                         = "";
    _executableArguments                    = "";
    _executableWorkingDirectory             = "";
    _executableBreakpointsFilename          = "";
    _executableBreakpointFunctionName       = "";
    _executableBreakpointFirstInstruction   = false;
    _executableConnectHostPort              = "";
    _executableRRTraceDirectory             = "";
    _executableCoreFilename                 = "";
    _executablePid                          = 0;

    _gdbMonitor                             = 0;
    _gdbProcess                             = 0;

#ifdef SEER_GDB_NAME
    _gdbProgram                             = STRINGIFY(SEER_GDB_NAME);
#else
    _gdbProgram                             = "/usr/bin/gdb";
#endif

#ifdef SEER_GDB_LAUNCHER
    _gdbLauncher                            = STRINGIFY(SEER_GDB_LAUNCHER);
#else
    _gdbLauncher                            = "";
#endif

    _gdbArguments                           = "--interpreter=mi";
    _gdbASyncMode                           = true;
    _gdbNonStopMode                         = false;
    _gdbServerDebug                         = false;
    _assemblyDisassemblyFlavor              = "att";
    _gdbHandleTerminatingException          = true;
    _gdbRandomizeStartAddress               = false;
    _gdbEnablePrettyPrinting                = true;
    _gdbRemoteTargetType                    = "extended-remote";
    _gdbRecordMode                          = "";
    _gdbRecordDirection                     = "";

    setIsQuitting(false);
    setNewExecutableFlag(true);

    setupUi(this);

    // Create the gdb process.
    _gdbProcess = new QProcess(this);

    // Create the gdb monitor.
    _gdbMonitor = new GdbMonitor(this);
    _gdbMonitor->setProcess(_gdbProcess);

    // Handle the app's 'quit' event, in case we want to do things before exiting.
    QObject::connect(QCoreApplication::instance(),                              &QCoreApplication::aboutToQuit,                                                             this,                                                           &SeerGdbWidget::handleAboutToQuit);

    // Connect things.
    QObject::connect(commandLogsWidget,                                         &SeerCommandLogsWidget::executeGdbCommand,                                                  this,                                                           &SeerGdbWidget::handleManualCommandExecute);

    QObject::connect(_gdbProcess,                                               &QProcess::readyReadStandardOutput,                                                         _gdbMonitor,                                                    &GdbMonitor::handleReadyReadStandardOutput);
    QObject::connect(_gdbProcess,                                               &QProcess::readyReadStandardError,                                                          _gdbMonitor,                                                    &GdbMonitor::handleReadyReadStandardError);
    QObject::connect(_gdbProcess,                                               static_cast<void (QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished),            this,                                                           &SeerGdbWidget::handleGdbProcessFinished); // ??? Do we care about the gdb process ending? For now, terminate Seer.
    QObject::connect(_gdbProcess,                                               static_cast<void (QProcess::*)(QProcess::ProcessError)>(&QProcess::errorOccurred),          this,                                                           &SeerGdbWidget::handleGdbProcessErrored);

    QObject::connect(_gdbMonitor,                                               &GdbMonitor::tildeTextOutput,                                                               commandLogsWidget->gdbOutputLog(),                              &SeerGdbLogWidget::handleText);
    QObject::connect(_gdbMonitor,                                               &GdbMonitor::ampersandTextOutput,                                                           commandLogsWidget->gdbOutputLog(),                              &SeerGdbLogWidget::handleText);
    QObject::connect(_gdbMonitor,                                               &GdbMonitor::atsignTextOutput,                                                              commandLogsWidget->gdbOutputLog(),                              &SeerGdbLogWidget::handleText);
    QObject::connect(_gdbMonitor,                                               &GdbMonitor::equalTextOutput,                                                               commandLogsWidget->seerOutputLog(),                             &SeerSeerLogWidget::handleText);
    QObject::connect(_gdbMonitor,                                               &GdbMonitor::caretTextOutput,                                                               commandLogsWidget->seerOutputLog(),                             &SeerSeerLogWidget::handleText);
    QObject::connect(_gdbMonitor,                                               &GdbMonitor::astrixTextOutput,                                                              commandLogsWidget->seerOutputLog(),                             &SeerSeerLogWidget::handleText);
    QObject::connect(_gdbMonitor,                                               &GdbMonitor::astrixTextOutput,                                                              editorManagerWidget,                                            &SeerEditorManagerWidget::handleText);
    QObject::connect(_gdbMonitor,                                               &GdbMonitor::caretTextOutput,                                                               editorManagerWidget,                                            &SeerEditorManagerWidget::handleText);
    QObject::connect(_gdbMonitor,                                               &GdbMonitor::caretTextOutput,                                                               sourceLibraryManagerWidget->sourceBrowserWidget(),              &SeerSourceBrowserWidget::handleText);
    QObject::connect(_gdbMonitor,                                               &GdbMonitor::caretTextOutput,                                                               sourceLibraryManagerWidget->functionBrowserWidget(),            &SeerFunctionBrowserWidget::handleText);
    QObject::connect(_gdbMonitor,                                               &GdbMonitor::caretTextOutput,                                                               sourceLibraryManagerWidget->typeBrowserWidget(),                &SeerTypeBrowserWidget::handleText);
    QObject::connect(_gdbMonitor,                                               &GdbMonitor::caretTextOutput,                                                               sourceLibraryManagerWidget->staticBrowserWidget(),              &SeerStaticBrowserWidget::handleText);
    QObject::connect(_gdbMonitor,                                               &GdbMonitor::caretTextOutput,                                                               sourceLibraryManagerWidget->libraryBrowserWidget(),             &SeerLibraryBrowserWidget::handleText);
    QObject::connect(_gdbMonitor,                                               &GdbMonitor::caretTextOutput,                                                               sourceLibraryManagerWidget->adaExceptionsBrowserWidget(),       &SeerAdaExceptionsBrowserWidget::handleText);
    QObject::connect(_gdbMonitor,                                               &GdbMonitor::caretTextOutput,                                                               sourceLibraryManagerWidget->skipBrowserWidget(),                &SeerSkipBrowserWidget::handleText);
    QObject::connect(_gdbMonitor,                                               &GdbMonitor::caretTextOutput,                                                               stackManagerWidget->stackFramesBrowserWidget(),                 &SeerStackFramesBrowserWidget::handleText);
    QObject::connect(_gdbMonitor,                                               &GdbMonitor::caretTextOutput,                                                               stackManagerWidget->stackLocalsBrowserWidget(),                 &SeerStackLocalsBrowserWidget::handleText);
    QObject::connect(_gdbMonitor,                                               &GdbMonitor::caretTextOutput,                                                               stackManagerWidget->stackArgumentsBrowserWidget(),              &SeerStackArgumentsBrowserWidget::handleText);
    QObject::connect(_gdbMonitor,                                               &GdbMonitor::caretTextOutput,                                                               stackManagerWidget->stackDumpBrowserWidget(),                   &SeerStackDumpBrowserWidget::handleText);
    QObject::connect(_gdbMonitor,                                               &GdbMonitor::caretTextOutput,                                                               stackManagerWidget,                                             &SeerStackManagerWidget::handleText);
    QObject::connect(_gdbMonitor,                                               &GdbMonitor::caretTextOutput,                                                               commandLogsWidget->breakpointsBrowser(),                        &SeerBreakpointsBrowserWidget::handleText);
    QObject::connect(_gdbMonitor,                                               &GdbMonitor::caretTextOutput,                                                               commandLogsWidget->watchpointsBrowser(),                        &SeerWatchpointsBrowserWidget::handleText);
    QObject::connect(_gdbMonitor,                                               &GdbMonitor::caretTextOutput,                                                               commandLogsWidget->catchpointsBrowser(),                        &SeerCatchpointsBrowserWidget::handleText);
    QObject::connect(_gdbMonitor,                                               &GdbMonitor::caretTextOutput,                                                               commandLogsWidget->printpointsBrowser(),                        &SeerPrintpointsBrowserWidget::handleText);
    QObject::connect(_gdbMonitor,                                               &GdbMonitor::caretTextOutput,                                                               commandLogsWidget->checkpointsBrowser(),                                      &SeerCheckpointsBrowserWidget::handleText);
    QObject::connect(_gdbMonitor,                                               &GdbMonitor::caretTextOutput,                                                               variableManagerWidget->variableTrackerBrowserWidget(),          &SeerVariableTrackerBrowserWidget::handleText);
    QObject::connect(_gdbMonitor,                                               &GdbMonitor::caretTextOutput,                                                               variableManagerWidget->variableLoggerBrowserWidget(),           &SeerVariableLoggerBrowserWidget::handleText);
    QObject::connect(_gdbMonitor,                                               &GdbMonitor::caretTextOutput,                                                               variableManagerWidget->registerValuesBrowserWidget(),           &SeerRegisterValuesBrowserWidget::handleText);
    QObject::connect(_gdbMonitor,                                               &GdbMonitor::caretTextOutput,                                                               variableManagerWidget->signalValuesBrowserWidget(),             &SeerSignalValuesBrowserWidget::handleText);
    QObject::connect(_gdbMonitor,                                               &GdbMonitor::astrixTextOutput,                                                              commandLogsWidget->watchpointsBrowser(),                        &SeerWatchpointsBrowserWidget::handleText);
    QObject::connect(_gdbMonitor,                                               &GdbMonitor::astrixTextOutput,                                                              this,                                                           &SeerGdbWidget::handleText);
    QObject::connect(_gdbMonitor,                                               &GdbMonitor::equalTextOutput,                                                               this,                                                           &SeerGdbWidget::handleText);
    QObject::connect(_gdbMonitor,                                               &GdbMonitor::tildeTextOutput,                                                               this,                                                           &SeerGdbWidget::handleText);

    QObject::connect(_gdbMonitor,                                               &GdbMonitor::caretTextOutput,                                                               threadManagerWidget->threadFramesBrowserWidget(),               &SeerThreadFramesBrowserWidget::handleText);
    QObject::connect(_gdbMonitor,                                               &GdbMonitor::equalTextOutput,                                                               threadManagerWidget->threadFramesBrowserWidget(),               &SeerThreadFramesBrowserWidget::handleText);
    QObject::connect(_gdbMonitor,                                               &GdbMonitor::astrixTextOutput,                                                              threadManagerWidget->threadFramesBrowserWidget(),               &SeerThreadFramesBrowserWidget::handleText);
    QObject::connect(_gdbMonitor,                                               &GdbMonitor::caretTextOutput,                                                               threadManagerWidget->threadIdsBrowserWidget(),                  &SeerThreadIdsBrowserWidget::handleText);
    QObject::connect(_gdbMonitor,                                               &GdbMonitor::caretTextOutput,                                                               threadManagerWidget->threadGroupsBrowserWidget(),               &SeerThreadGroupsBrowserWidget::handleText);
    QObject::connect(_gdbMonitor,                                               &GdbMonitor::equalTextOutput,                                                               threadManagerWidget->threadGroupsBrowserWidget(),               &SeerThreadGroupsBrowserWidget::handleText);
    QObject::connect(_gdbMonitor,                                               &GdbMonitor::caretTextOutput,                                                               threadManagerWidget->adaTasksBrowserWidget(),                   &SeerAdaTasksBrowserWidget::handleText);

    QObject::connect(editorManagerWidget,                                       &SeerEditorManagerWidget::refreshBreakpointsList,                                           this,                                                           &SeerGdbWidget::handleGdbGenericpointList);
    QObject::connect(editorManagerWidget,                                       &SeerEditorManagerWidget::refreshStackFrames,                                               this,                                                           &SeerGdbWidget::handleGdbStackListFrames);
    QObject::connect(editorManagerWidget,                                       &SeerEditorManagerWidget::insertBreakpoint,                                                 this,                                                           &SeerGdbWidget::handleGdbBreakpointInsert);
    QObject::connect(editorManagerWidget,                                       &SeerEditorManagerWidget::insertPrintpoint,                                                 this,                                                           &SeerGdbWidget::handleGdbPrintpointInsert);
    QObject::connect(editorManagerWidget,                                       &SeerEditorManagerWidget::deleteBreakpoints,                                                this,                                                           &SeerGdbWidget::handleGdbBreakpointDelete);
    QObject::connect(editorManagerWidget,                                       &SeerEditorManagerWidget::enableBreakpoints,                                                this,                                                           &SeerGdbWidget::handleGdbBreakpointEnable);
    QObject::connect(editorManagerWidget,                                       &SeerEditorManagerWidget::disableBreakpoints,                                               this,                                                           &SeerGdbWidget::handleGdbBreakpointDisable);
    QObject::connect(editorManagerWidget,                                       &SeerEditorManagerWidget::infoBreakpoint,                                                   this,                                                           &SeerGdbWidget::handleGdbBreakpointInfo);
    QObject::connect(editorManagerWidget,                                       &SeerEditorManagerWidget::runToLine,                                                        this,                                                           &SeerGdbWidget::handleGdbRunToLine);
    QObject::connect(editorManagerWidget,                                       &SeerEditorManagerWidget::runToAddress,                                                     this,                                                           &SeerGdbWidget::handleGdbRunToAddress);
    QObject::connect(editorManagerWidget,                                       &SeerEditorManagerWidget::addVariableLoggerExpression,                                      variableManagerWidget->variableLoggerBrowserWidget(),           &SeerVariableLoggerBrowserWidget::addVariableExpression);
    QObject::connect(editorManagerWidget,                                       &SeerEditorManagerWidget::addVariableTrackerExpression,                                     this,                                                           &SeerGdbWidget::handleGdbDataAddExpression);
    QObject::connect(editorManagerWidget,                                       &SeerEditorManagerWidget::refreshVariableTrackerValues,                                     this,                                                           &SeerGdbWidget::handleGdbDataListValues);
    QObject::connect(editorManagerWidget,                                       &SeerEditorManagerWidget::addMemoryVisualizer,                                              this,                                                           &SeerGdbWidget::handleGdbMemoryAddExpression);
    QObject::connect(editorManagerWidget,                                       &SeerEditorManagerWidget::addArrayVisualizer,                                               this,                                                           &SeerGdbWidget::handleGdbArrayAddExpression);
    QObject::connect(editorManagerWidget,                                       &SeerEditorManagerWidget::addMatrixVisualizer,                                              this,                                                           &SeerGdbWidget::handleGdbMatrixAddExpression);
    QObject::connect(editorManagerWidget,                                       &SeerEditorManagerWidget::addStructVisualizer,                                              this,                                                           &SeerGdbWidget::handleGdbVarAddExpression);
    QObject::connect(editorManagerWidget,                                       &SeerEditorManagerWidget::evaluateVariableExpression,                                       this,                                                           &SeerGdbWidget::handleGdbDataEvaluateExpression);
    QObject::connect(editorManagerWidget,                                       &SeerEditorManagerWidget::evaluateVariableExpression,                                       variableManagerWidget->variableLoggerBrowserWidget(),           &SeerVariableLoggerBrowserWidget::handleEvaluateVariableExpression);
    QObject::connect(editorManagerWidget,                                       &SeerEditorManagerWidget::requestAssembly,                                                  this,                                                           &SeerGdbWidget::handleGdbGetAssembly);
    QObject::connect(editorManagerWidget,                                       &SeerEditorManagerWidget::requestSourceAndAssembly,                                         this,                                                           &SeerGdbWidget::handleGdbGetSourceAndAssembly);

    QObject::connect(sourceLibraryManagerWidget->sourceBrowserWidget(),         &SeerSourceBrowserWidget::refreshSourceList,                                                this,                                                           &SeerGdbWidget::handleGdbExecutableSources);
    QObject::connect(sourceLibraryManagerWidget->sourceBrowserWidget(),         &SeerSourceBrowserWidget::selectedFile,                                                     editorManagerWidget,                                            &SeerEditorManagerWidget::handleOpenFile);
    QObject::connect(sourceLibraryManagerWidget->functionBrowserWidget(),       &SeerFunctionBrowserWidget::refreshFunctionList,                                            this,                                                           &SeerGdbWidget::handleGdbExecutableFunctions);
    QObject::connect(sourceLibraryManagerWidget->functionBrowserWidget(),       &SeerFunctionBrowserWidget::insertBreakpoint,                                               this,                                                           &SeerGdbWidget::handleGdbBreakpointInsert);
    QObject::connect(sourceLibraryManagerWidget->functionBrowserWidget(),       &SeerFunctionBrowserWidget::addSkip,                                                        this,                                                           &SeerGdbWidget::handleGdbSkipAdd);
    QObject::connect(sourceLibraryManagerWidget->functionBrowserWidget(),       &SeerFunctionBrowserWidget::selectedFile,                                                   editorManagerWidget,                                            &SeerEditorManagerWidget::handleOpenFile);
    QObject::connect(sourceLibraryManagerWidget->typeBrowserWidget(),           &SeerTypeBrowserWidget::refreshTypeList,                                                    this,                                                           &SeerGdbWidget::handleGdbExecutableTypes);
    QObject::connect(sourceLibraryManagerWidget->typeBrowserWidget(),           &SeerTypeBrowserWidget::selectedFile,                                                       editorManagerWidget,                                            &SeerEditorManagerWidget::handleOpenFile);
    QObject::connect(sourceLibraryManagerWidget->staticBrowserWidget(),         &SeerStaticBrowserWidget::refreshVariableList,                                              this,                                                           &SeerGdbWidget::handleGdbExecutableVariables);
    QObject::connect(sourceLibraryManagerWidget->staticBrowserWidget(),         &SeerStaticBrowserWidget::selectedFile,                                                     editorManagerWidget,                                            &SeerEditorManagerWidget::handleOpenFile);
    QObject::connect(sourceLibraryManagerWidget->libraryBrowserWidget(),        &SeerLibraryBrowserWidget::refreshLibraryList,                                              this,                                                           &SeerGdbWidget::handleGdbExecutableLibraries);
    QObject::connect(sourceLibraryManagerWidget->adaExceptionsBrowserWidget(),  &SeerAdaExceptionsBrowserWidget::refreshAdaExceptions,                                      this,                                                           &SeerGdbWidget::handleGdbAdaListExceptions);
    QObject::connect(sourceLibraryManagerWidget->adaExceptionsBrowserWidget(),  &SeerAdaExceptionsBrowserWidget::insertCatchpoint,                                          this,                                                           &SeerGdbWidget::handleGdbCatchpointInsert);
    QObject::connect(sourceLibraryManagerWidget->skipBrowserWidget(),           &SeerSkipBrowserWidget::refreshSkipList,                                                    this,                                                           &SeerGdbWidget::handleGdbSkipList);
    QObject::connect(sourceLibraryManagerWidget->skipBrowserWidget(),           &SeerSkipBrowserWidget::addSkip,                                                            this,                                                           &SeerGdbWidget::handleGdbSkipAdd);
    QObject::connect(sourceLibraryManagerWidget->skipBrowserWidget(),           &SeerSkipBrowserWidget::deleteSkips,                                                        this,                                                           &SeerGdbWidget::handleGdbSkipDelete);
    QObject::connect(sourceLibraryManagerWidget->skipBrowserWidget(),           &SeerSkipBrowserWidget::enableSkips,                                                        this,                                                           &SeerGdbWidget::handleGdbSkipEnable);
    QObject::connect(sourceLibraryManagerWidget->skipBrowserWidget(),           &SeerSkipBrowserWidget::disableSkips,                                                       this,                                                           &SeerGdbWidget::handleGdbSkipDisable);

    QObject::connect(stackManagerWidget->stackFramesBrowserWidget(),            &SeerStackFramesBrowserWidget::refreshStackFrames,                                          this,                                                           &SeerGdbWidget::handleGdbStackListFrames);
    QObject::connect(stackManagerWidget->stackFramesBrowserWidget(),            &SeerStackFramesBrowserWidget::selectedFrame,                                               this,                                                           &SeerGdbWidget::handleGdbStackSelectFrame);
    QObject::connect(stackManagerWidget->stackFramesBrowserWidget(),            &SeerStackFramesBrowserWidget::selectedFile,                                                editorManagerWidget,                                            &SeerEditorManagerWidget::handleOpenFile);
    QObject::connect(stackManagerWidget->stackFramesBrowserWidget(),            &SeerStackFramesBrowserWidget::selectedAddress,                                             editorManagerWidget,                                            &SeerEditorManagerWidget::handleOpenAddress);
    QObject::connect(stackManagerWidget->stackFramesBrowserWidget(),            &SeerStackFramesBrowserWidget::maybeSelectedAddress,                                        editorManagerWidget,                                            &SeerEditorManagerWidget::handleMaybeOpenAddress);
    QObject::connect(stackManagerWidget->stackArgumentsBrowserWidget(),         &SeerStackArgumentsBrowserWidget::refreshStackArguments,                                    this,                                                           &SeerGdbWidget::handleGdbStackListArguments);
    QObject::connect(stackManagerWidget->stackArgumentsBrowserWidget(),         &SeerStackArgumentsBrowserWidget::addVariableLoggerExpression,                              variableManagerWidget->variableLoggerBrowserWidget(),           &SeerVariableLoggerBrowserWidget::addVariableExpression);
    QObject::connect(stackManagerWidget->stackArgumentsBrowserWidget(),         &SeerStackArgumentsBrowserWidget::addVariableTrackerExpression,                             this,                                                           &SeerGdbWidget::handleGdbDataAddExpression);
    QObject::connect(stackManagerWidget->stackArgumentsBrowserWidget(),         &SeerStackArgumentsBrowserWidget::addMemoryVisualizer,                                      this,                                                           &SeerGdbWidget::handleGdbMemoryAddExpression);
    QObject::connect(stackManagerWidget->stackArgumentsBrowserWidget(),         &SeerStackArgumentsBrowserWidget::addArrayVisualizer,                                       this,                                                           &SeerGdbWidget::handleGdbArrayAddExpression);
    QObject::connect(stackManagerWidget->stackArgumentsBrowserWidget(),         &SeerStackArgumentsBrowserWidget::addMatrixVisualizer,                                      this,                                                           &SeerGdbWidget::handleGdbMatrixAddExpression);
    QObject::connect(stackManagerWidget->stackArgumentsBrowserWidget(),         &SeerStackArgumentsBrowserWidget::addStructVisualizer,                                      this,                                                           &SeerGdbWidget::handleGdbVarAddExpression);
    QObject::connect(stackManagerWidget->stackArgumentsBrowserWidget(),         &SeerStackArgumentsBrowserWidget::refreshVariableTrackerValues,                             this,                                                           &SeerGdbWidget::handleGdbDataListExpressions);
    QObject::connect(stackManagerWidget->stackLocalsBrowserWidget(),            &SeerStackLocalsBrowserWidget::refreshStackLocals,                                          this,                                                           &SeerGdbWidget::handleGdbStackListLocals);
    QObject::connect(stackManagerWidget->stackLocalsBrowserWidget(),            &SeerStackLocalsBrowserWidget::addVariableLoggerExpression,                                 variableManagerWidget->variableLoggerBrowserWidget(),           &SeerVariableLoggerBrowserWidget::addVariableExpression);
    QObject::connect(stackManagerWidget->stackLocalsBrowserWidget(),            &SeerStackLocalsBrowserWidget::addVariableTrackerExpression,                                this,                                                           &SeerGdbWidget::handleGdbDataAddExpression);
    QObject::connect(stackManagerWidget->stackLocalsBrowserWidget(),            &SeerStackLocalsBrowserWidget::addMemoryVisualizer,                                         this,                                                           &SeerGdbWidget::handleGdbMemoryAddExpression);
    QObject::connect(stackManagerWidget->stackLocalsBrowserWidget(),            &SeerStackLocalsBrowserWidget::addArrayVisualizer,                                          this,                                                           &SeerGdbWidget::handleGdbArrayAddExpression);
    QObject::connect(stackManagerWidget->stackLocalsBrowserWidget(),            &SeerStackLocalsBrowserWidget::addMatrixVisualizer,                                         this,                                                           &SeerGdbWidget::handleGdbMatrixAddExpression);
    QObject::connect(stackManagerWidget->stackLocalsBrowserWidget(),            &SeerStackLocalsBrowserWidget::addStructVisualizer,                                         this,                                                           &SeerGdbWidget::handleGdbVarAddExpression);
    QObject::connect(stackManagerWidget->stackLocalsBrowserWidget(),            &SeerStackLocalsBrowserWidget::refreshVariableTrackerValues,                                this,                                                           &SeerGdbWidget::handleGdbDataListExpressions);
    QObject::connect(stackManagerWidget->stackDumpBrowserWidget(),              &SeerStackDumpBrowserWidget::refreshStackPointer,                                           this,                                                           &SeerGdbWidget::handleGdbDataEvaluateExpression);
    QObject::connect(stackManagerWidget->stackDumpBrowserWidget(),              &SeerStackDumpBrowserWidget::refreshStackDump,                                              this,                                                           QOverload<int,QString,int,int>::of(&SeerGdbWidget::handleGdbMemoryEvaluateExpression));
    QObject::connect(stackManagerWidget->stackDumpBrowserWidget(),              &SeerStackDumpBrowserWidget::addMemoryVisualizer,                                           this,                                                           &SeerGdbWidget::handleGdbMemoryAddExpression);
    QObject::connect(stackManagerWidget,                                        &SeerStackManagerWidget::refreshThreadFrames,                                               this,                                                           &SeerGdbWidget::handleGdbThreadListFrames);

    QObject::connect(variableManagerWidget->variableTrackerBrowserWidget(),     &SeerVariableTrackerBrowserWidget::refreshVariableTrackerNames,                             this,                                                           &SeerGdbWidget::handleGdbDataListExpressions);
    QObject::connect(variableManagerWidget->variableTrackerBrowserWidget(),     &SeerVariableTrackerBrowserWidget::refreshVariableTrackerValues,                            this,                                                           &SeerGdbWidget::handleGdbDataListValues);
    QObject::connect(variableManagerWidget->variableTrackerBrowserWidget(),     &SeerVariableTrackerBrowserWidget::addVariableExpression,                                   this,                                                           &SeerGdbWidget::handleGdbDataAddExpression);
    QObject::connect(variableManagerWidget->variableTrackerBrowserWidget(),     &SeerVariableTrackerBrowserWidget::deleteVariableExpressions,                               this,                                                           &SeerGdbWidget::handleGdbDataDeleteExpressions);
    QObject::connect(variableManagerWidget->variableTrackerBrowserWidget(),     &SeerVariableTrackerBrowserWidget::addMemoryVisualizer,                                     this,                                                           &SeerGdbWidget::handleGdbMemoryAddExpression);
    QObject::connect(variableManagerWidget->variableTrackerBrowserWidget(),     &SeerVariableTrackerBrowserWidget::addArrayVisualizer,                                      this,                                                           &SeerGdbWidget::handleGdbArrayAddExpression);
    QObject::connect(variableManagerWidget->variableTrackerBrowserWidget(),     &SeerVariableTrackerBrowserWidget::addMatrixVisualizer,                                     this,                                                           &SeerGdbWidget::handleGdbMatrixAddExpression);
    QObject::connect(variableManagerWidget->variableTrackerBrowserWidget(),     &SeerVariableTrackerBrowserWidget::addStructVisualizer,                                     this,                                                           &SeerGdbWidget::handleGdbVarAddExpression);
    QObject::connect(variableManagerWidget->variableLoggerBrowserWidget(),      &SeerVariableLoggerBrowserWidget::evaluateVariableExpression,                               this,                                                           &SeerGdbWidget::handleGdbDataEvaluateExpression);
    QObject::connect(variableManagerWidget->variableLoggerBrowserWidget(),      &SeerVariableLoggerBrowserWidget::addMemoryVisualizer,                                      this,                                                           &SeerGdbWidget::handleGdbMemoryAddExpression);
    QObject::connect(variableManagerWidget->variableLoggerBrowserWidget(),      &SeerVariableLoggerBrowserWidget::addArrayVisualizer,                                       this,                                                           &SeerGdbWidget::handleGdbArrayAddExpression);
    QObject::connect(variableManagerWidget->variableLoggerBrowserWidget(),      &SeerVariableLoggerBrowserWidget::addMatrixVisualizer,                                      this,                                                           &SeerGdbWidget::handleGdbMatrixAddExpression);
    QObject::connect(variableManagerWidget->variableLoggerBrowserWidget(),      &SeerVariableLoggerBrowserWidget::addStructVisualizer,                                      this,                                                           &SeerGdbWidget::handleGdbVarAddExpression);
    QObject::connect(variableManagerWidget->registerValuesBrowserWidget(),      &SeerRegisterValuesBrowserWidget::refreshRegisterNames,                                     this,                                                           &SeerGdbWidget::handleGdbRegisterListNames);
    QObject::connect(variableManagerWidget->registerValuesBrowserWidget(),      &SeerRegisterValuesBrowserWidget::refreshRegisterValues,                                    this,                                                           &SeerGdbWidget::handleGdbRegisterListValues);
    QObject::connect(variableManagerWidget->registerValuesBrowserWidget(),      &SeerRegisterValuesBrowserWidget::setRegisterValue,                                         this,                                                           &SeerGdbWidget::handleGdbRegisterSetValue);
    QObject::connect(variableManagerWidget->signalValuesBrowserWidget(),        &SeerSignalValuesBrowserWidget::refreshSignalNames,                                         this,                                                           &SeerGdbWidget::handleGdbSignalListNames);
    QObject::connect(variableManagerWidget->signalValuesBrowserWidget(),        &SeerSignalValuesBrowserWidget::refreshSignalValues,                                        this,                                                           &SeerGdbWidget::handleGdbSignalListValues);
    QObject::connect(variableManagerWidget->signalValuesBrowserWidget(),        &SeerSignalValuesBrowserWidget::setSignalValue,                                             this,                                                           &SeerGdbWidget::handleGdbSignalSetValue);

    QObject::connect(threadManagerWidget->threadFramesBrowserWidget(),          &SeerThreadFramesBrowserWidget::refreshThreadIds,                                           this,                                                           &SeerGdbWidget::handleGdbThreadListIds);
    QObject::connect(threadManagerWidget->threadFramesBrowserWidget(),          &SeerThreadFramesBrowserWidget::refreshThreadFrames,                                        this,                                                           &SeerGdbWidget::handleGdbThreadListFrames);
    QObject::connect(threadManagerWidget->threadFramesBrowserWidget(),          &SeerThreadFramesBrowserWidget::selectedFile,                                               editorManagerWidget,                                            &SeerEditorManagerWidget::handleOpenFile);
    QObject::connect(threadManagerWidget->threadFramesBrowserWidget(),          &SeerThreadFramesBrowserWidget::selectedAddress,                                            editorManagerWidget,                                            &SeerEditorManagerWidget::handleOpenAddress);
    QObject::connect(threadManagerWidget->threadFramesBrowserWidget(),          &SeerThreadFramesBrowserWidget::maybeSelectedAddress,                                       editorManagerWidget,                                            &SeerEditorManagerWidget::handleMaybeOpenAddress);
    QObject::connect(threadManagerWidget->threadFramesBrowserWidget(),          &SeerThreadFramesBrowserWidget::selectedThread,                                             this,                                                           &SeerGdbWidget::handleGdbThreadSelectId);
    QObject::connect(threadManagerWidget->threadFramesBrowserWidget(),          &SeerThreadFramesBrowserWidget::nextThreadId,                                               this,                                                           &SeerGdbWidget::handleGdbNextThreadId);
    QObject::connect(threadManagerWidget->threadFramesBrowserWidget(),          &SeerThreadFramesBrowserWidget::stepThreadId,                                               this,                                                           &SeerGdbWidget::handleGdbStepThreadId);
    QObject::connect(threadManagerWidget->threadFramesBrowserWidget(),          &SeerThreadFramesBrowserWidget::finishThreadId,                                             this,                                                           &SeerGdbWidget::handleGdbFinishThreadId);
    QObject::connect(threadManagerWidget->threadFramesBrowserWidget(),          &SeerThreadFramesBrowserWidget::continueThreadId,                                           this,                                                           &SeerGdbWidget::handleGdbContinueThreadId);
    QObject::connect(threadManagerWidget->threadFramesBrowserWidget(),          &SeerThreadFramesBrowserWidget::interruptThreadId,                                          this,                                                           &SeerGdbWidget::handleGdbInterruptThreadId);

    QObject::connect(threadManagerWidget->threadIdsBrowserWidget(),             &SeerThreadIdsBrowserWidget::refreshThreadIds,                                              this,                                                           &SeerGdbWidget::handleGdbThreadListIds);
    QObject::connect(threadManagerWidget->threadIdsBrowserWidget(),             &SeerThreadIdsBrowserWidget::selectedThread,                                                this,                                                           &SeerGdbWidget::handleGdbThreadSelectId);
    QObject::connect(threadManagerWidget->threadIdsBrowserWidget(),             &SeerThreadIdsBrowserWidget::nextThreadId,                                                  this,                                                           &SeerGdbWidget::handleGdbNextThreadId);
    QObject::connect(threadManagerWidget->threadIdsBrowserWidget(),             &SeerThreadIdsBrowserWidget::stepThreadId,                                                  this,                                                           &SeerGdbWidget::handleGdbStepThreadId);
    QObject::connect(threadManagerWidget->threadIdsBrowserWidget(),             &SeerThreadIdsBrowserWidget::finishThreadId,                                                this,                                                           &SeerGdbWidget::handleGdbFinishThreadId);
    QObject::connect(threadManagerWidget->threadIdsBrowserWidget(),             &SeerThreadIdsBrowserWidget::continueThreadId,                                              this,                                                           &SeerGdbWidget::handleGdbContinueThreadId);
    QObject::connect(threadManagerWidget->threadIdsBrowserWidget(),             &SeerThreadIdsBrowserWidget::interruptThreadId,                                             this,                                                           &SeerGdbWidget::handleGdbInterruptThreadId);

    QObject::connect(threadManagerWidget->threadGroupsBrowserWidget(),          &SeerThreadGroupsBrowserWidget::refreshThreadGroups,                                        this,                                                           &SeerGdbWidget::handleGdbThreadListGroups);
    QObject::connect(threadManagerWidget->threadGroupsBrowserWidget(),          &SeerThreadGroupsBrowserWidget::runThreadGroup,                                             this,                                                           &SeerGdbWidget::handleGdbRunThreadGroup);
    QObject::connect(threadManagerWidget->threadGroupsBrowserWidget(),          &SeerThreadGroupsBrowserWidget::startThreadGroup,                                           this,                                                           &SeerGdbWidget::handleGdbStartThreadGroup);
    QObject::connect(threadManagerWidget->threadGroupsBrowserWidget(),          &SeerThreadGroupsBrowserWidget::continueThreadGroup,                                        this,                                                           &SeerGdbWidget::handleGdbContinueThreadGroup);
    QObject::connect(threadManagerWidget->threadGroupsBrowserWidget(),          &SeerThreadGroupsBrowserWidget::interruptThreadGroup,                                       this,                                                           &SeerGdbWidget::handleGdbInterruptThreadGroup);

    QObject::connect(threadManagerWidget->adaTasksBrowserWidget(),              &SeerAdaTasksBrowserWidget::refreshAdaTasks,                                                this,                                                           &SeerGdbWidget::handleGdbAdaListTasks);
    QObject::connect(threadManagerWidget->adaTasksBrowserWidget(),              &SeerAdaTasksBrowserWidget::selectedThread,                                                 this,                                                           &SeerGdbWidget::handleGdbThreadSelectId);

    QObject::connect(threadManagerWidget,                                       &SeerThreadManagerWidget::schedulerLockingModeChanged,                                      this,                                                           &SeerGdbWidget::handleGdbSchedulerLockingMode);
    QObject::connect(threadManagerWidget,                                       &SeerThreadManagerWidget::scheduleMultipleModeChanged,                                      this,                                                           &SeerGdbWidget::handleGdbScheduleMultipleMode);
    QObject::connect(threadManagerWidget,                                       &SeerThreadManagerWidget::forkFollowsModeChanged,                                           this,                                                           &SeerGdbWidget::handleGdbForkFollowMode);

    QObject::connect(commandLogsWidget->breakpointsBrowser(),                   &SeerBreakpointsBrowserWidget::refreshBreakpointsList,                                      this,                                                           &SeerGdbWidget::handleGdbGenericpointList);
    QObject::connect(commandLogsWidget->breakpointsBrowser(),                   &SeerBreakpointsBrowserWidget::deleteBreakpoints,                                           this,                                                           &SeerGdbWidget::handleGdbBreakpointDelete);
    QObject::connect(commandLogsWidget->breakpointsBrowser(),                   &SeerBreakpointsBrowserWidget::enableBreakpoints,                                           this,                                                           &SeerGdbWidget::handleGdbBreakpointEnable);
    QObject::connect(commandLogsWidget->breakpointsBrowser(),                   &SeerBreakpointsBrowserWidget::disableBreakpoints,                                          this,                                                           &SeerGdbWidget::handleGdbBreakpointDisable);
    QObject::connect(commandLogsWidget->breakpointsBrowser(),                   &SeerBreakpointsBrowserWidget::insertBreakpoint,                                            this,                                                           &SeerGdbWidget::handleGdbBreakpointInsert);
    QObject::connect(commandLogsWidget->breakpointsBrowser(),                   &SeerBreakpointsBrowserWidget::addBreakpointCondition,                                      this,                                                           &SeerGdbWidget::handleGdbBreakpointCondition);
    QObject::connect(commandLogsWidget->breakpointsBrowser(),                   &SeerBreakpointsBrowserWidget::addBreakpointIgnore,                                         this,                                                           &SeerGdbWidget::handleGdbBreakpointIgnore);
    QObject::connect(commandLogsWidget->breakpointsBrowser(),                   &SeerBreakpointsBrowserWidget::addBreakpointCommands,                                       this,                                                           &SeerGdbWidget::handleGdbBreakpointCommands);
    QObject::connect(commandLogsWidget->breakpointsBrowser(),                   &SeerBreakpointsBrowserWidget::selectedFile,                                                editorManagerWidget,                                            &SeerEditorManagerWidget::handleOpenFile);
    QObject::connect(commandLogsWidget->breakpointsBrowser(),                   &SeerBreakpointsBrowserWidget::selectedAddress,                                             editorManagerWidget,                                            &SeerEditorManagerWidget::handleOpenAddress);
    QObject::connect(commandLogsWidget->breakpointsBrowser(),                   &SeerBreakpointsBrowserWidget::maybeSelectedAddress,                                        editorManagerWidget,                                            &SeerEditorManagerWidget::handleMaybeOpenAddress);

    QObject::connect(commandLogsWidget->watchpointsBrowser(),                   &SeerWatchpointsBrowserWidget::refreshWatchpointsList,                                      this,                                                           &SeerGdbWidget::handleGdbGenericpointList);
    QObject::connect(commandLogsWidget->watchpointsBrowser(),                   &SeerWatchpointsBrowserWidget::deleteWatchpoints,                                           this,                                                           &SeerGdbWidget::handleGdbWatchpointDelete);
    QObject::connect(commandLogsWidget->watchpointsBrowser(),                   &SeerWatchpointsBrowserWidget::enableWatchpoints,                                           this,                                                           &SeerGdbWidget::handleGdbWatchpointEnable);
    QObject::connect(commandLogsWidget->watchpointsBrowser(),                   &SeerWatchpointsBrowserWidget::disableWatchpoints,                                          this,                                                           &SeerGdbWidget::handleGdbWatchpointDisable);
    QObject::connect(commandLogsWidget->watchpointsBrowser(),                   &SeerWatchpointsBrowserWidget::insertWatchpoint,                                            this,                                                           &SeerGdbWidget::handleGdbWatchpointInsert);
    QObject::connect(commandLogsWidget->watchpointsBrowser(),                   &SeerWatchpointsBrowserWidget::addBreakpointCondition,                                      this,                                                           &SeerGdbWidget::handleGdbBreakpointCondition);
    QObject::connect(commandLogsWidget->watchpointsBrowser(),                   &SeerWatchpointsBrowserWidget::addBreakpointIgnore,                                         this,                                                           &SeerGdbWidget::handleGdbBreakpointIgnore);
    QObject::connect(commandLogsWidget->watchpointsBrowser(),                   &SeerWatchpointsBrowserWidget::addBreakpointCommands,                                       this,                                                           &SeerGdbWidget::handleGdbBreakpointCommands);
    QObject::connect(commandLogsWidget->watchpointsBrowser(),                   &SeerWatchpointsBrowserWidget::selectedFile,                                                editorManagerWidget,                                            &SeerEditorManagerWidget::handleOpenFile);

    QObject::connect(commandLogsWidget->catchpointsBrowser(),                   &SeerCatchpointsBrowserWidget::refreshCatchpointsList,                                      this,                                                           &SeerGdbWidget::handleGdbGenericpointList);
    QObject::connect(commandLogsWidget->catchpointsBrowser(),                   &SeerCatchpointsBrowserWidget::deleteCatchpoints,                                           this,                                                           &SeerGdbWidget::handleGdbCatchpointDelete);
    QObject::connect(commandLogsWidget->catchpointsBrowser(),                   &SeerCatchpointsBrowserWidget::enableCatchpoints,                                           this,                                                           &SeerGdbWidget::handleGdbCatchpointEnable);
    QObject::connect(commandLogsWidget->catchpointsBrowser(),                   &SeerCatchpointsBrowserWidget::disableCatchpoints,                                          this,                                                           &SeerGdbWidget::handleGdbCatchpointDisable);
    QObject::connect(commandLogsWidget->catchpointsBrowser(),                   &SeerCatchpointsBrowserWidget::insertCatchpoint,                                            this,                                                           &SeerGdbWidget::handleGdbCatchpointInsert);
    QObject::connect(commandLogsWidget->catchpointsBrowser(),                   &SeerCatchpointsBrowserWidget::addBreakpointCondition,                                      this,                                                           &SeerGdbWidget::handleGdbBreakpointCondition);
    QObject::connect(commandLogsWidget->catchpointsBrowser(),                   &SeerCatchpointsBrowserWidget::addBreakpointIgnore,                                         this,                                                           &SeerGdbWidget::handleGdbBreakpointIgnore);
    QObject::connect(commandLogsWidget->catchpointsBrowser(),                   &SeerCatchpointsBrowserWidget::addBreakpointCommands,                                       this,                                                           &SeerGdbWidget::handleGdbBreakpointCommands);

    QObject::connect(commandLogsWidget->printpointsBrowser(),                   &SeerPrintpointsBrowserWidget::refreshPrintpointsList,                                      this,                                                           &SeerGdbWidget::handleGdbGenericpointList);
    QObject::connect(commandLogsWidget->printpointsBrowser(),                   &SeerPrintpointsBrowserWidget::deletePrintpoints,                                           this,                                                           &SeerGdbWidget::handleGdbPrintpointDelete);
    QObject::connect(commandLogsWidget->printpointsBrowser(),                   &SeerPrintpointsBrowserWidget::enablePrintpoints,                                           this,                                                           &SeerGdbWidget::handleGdbPrintpointEnable);
    QObject::connect(commandLogsWidget->printpointsBrowser(),                   &SeerPrintpointsBrowserWidget::disablePrintpoints,                                          this,                                                           &SeerGdbWidget::handleGdbPrintpointDisable);
    QObject::connect(commandLogsWidget->printpointsBrowser(),                   &SeerPrintpointsBrowserWidget::insertPrintpoint,                                            this,                                                           &SeerGdbWidget::handleGdbPrintpointInsert);
    QObject::connect(commandLogsWidget->printpointsBrowser(),                   &SeerPrintpointsBrowserWidget::addBreakpointCondition,                                      this,                                                           &SeerGdbWidget::handleGdbBreakpointCondition);
    QObject::connect(commandLogsWidget->printpointsBrowser(),                   &SeerPrintpointsBrowserWidget::addBreakpointIgnore,                                         this,                                                           &SeerGdbWidget::handleGdbBreakpointIgnore);
    QObject::connect(commandLogsWidget->printpointsBrowser(),                   &SeerPrintpointsBrowserWidget::addBreakpointCommand,                                        this,                                                           &SeerGdbWidget::handleGdbBreakpointCommand);

    QObject::connect(commandLogsWidget->checkpointsBrowser(),                   &SeerCheckpointsBrowserWidget::refreshCheckpointsList,                                      this,                                                           &SeerGdbWidget::handleGdbCheckpointList);
    QObject::connect(commandLogsWidget->checkpointsBrowser(),                   &SeerCheckpointsBrowserWidget::insertCheckpoint,                                            this,                                                           &SeerGdbWidget::handleGdbCheckpointInsert);
    QObject::connect(commandLogsWidget->checkpointsBrowser(),                   &SeerCheckpointsBrowserWidget::selectCheckpoint,                                            this,                                                           &SeerGdbWidget::handleGdbCheckpointSelect);
    QObject::connect(commandLogsWidget->checkpointsBrowser(),                   &SeerCheckpointsBrowserWidget::deleteCheckpoints,                                           this,                                                           &SeerGdbWidget::handleGdbCheckpointDelete);

    QObject::connect(this,                                                      &SeerGdbWidget::assemblyConfigChanged,                                                      editorManagerWidget,                                            &SeerEditorManagerWidget::handleAssemblyConfigChanged);

    QObject::connect(this,                                                      &SeerGdbWidget::stoppingPointReached,                                                       stackManagerWidget,                                             &SeerStackManagerWidget::handleStoppingPointReached);
    QObject::connect(this,                                                      &SeerGdbWidget::stoppingPointReached,                                                       stackManagerWidget->stackFramesBrowserWidget(),                 &SeerStackFramesBrowserWidget::handleStoppingPointReached);
    QObject::connect(this,                                                      &SeerGdbWidget::stoppingPointReached,                                                       stackManagerWidget->stackLocalsBrowserWidget(),                 &SeerStackLocalsBrowserWidget::handleStoppingPointReached);
    QObject::connect(this,                                                      &SeerGdbWidget::stoppingPointReached,                                                       stackManagerWidget->stackArgumentsBrowserWidget(),              &SeerStackArgumentsBrowserWidget::handleStoppingPointReached);
    QObject::connect(this,                                                      &SeerGdbWidget::stoppingPointReached,                                                       stackManagerWidget->stackDumpBrowserWidget(),                   &SeerStackDumpBrowserWidget::handleStoppingPointReached);
    QObject::connect(this,                                                      &SeerGdbWidget::stoppingPointReached,                                                       threadManagerWidget->threadFramesBrowserWidget(),               &SeerThreadFramesBrowserWidget::handleStoppingPointReached);
    QObject::connect(this,                                                      &SeerGdbWidget::stoppingPointReached,                                                       threadManagerWidget->threadIdsBrowserWidget(),                  &SeerThreadIdsBrowserWidget::handleStoppingPointReached);
    QObject::connect(this,                                                      &SeerGdbWidget::stoppingPointReached,                                                       threadManagerWidget->adaTasksBrowserWidget(),                   &SeerAdaTasksBrowserWidget::handleStoppingPointReached);
    QObject::connect(this,                                                      &SeerGdbWidget::stoppingPointReached,                                                       variableManagerWidget->variableTrackerBrowserWidget(),          &SeerVariableTrackerBrowserWidget::handleStoppingPointReached);
    QObject::connect(this,                                                      &SeerGdbWidget::stoppingPointReached,                                                       variableManagerWidget->registerValuesBrowserWidget(),           &SeerRegisterValuesBrowserWidget::handleStoppingPointReached);
    QObject::connect(this,                                                      &SeerGdbWidget::stoppingPointReached,                                                       variableManagerWidget->signalValuesBrowserWidget(),             &SeerSignalValuesBrowserWidget::handleStoppingPointReached);
    QObject::connect(this,                                                      &SeerGdbWidget::stoppingPointReached,                                                       commandLogsWidget->breakpointsBrowser(),                        &SeerBreakpointsBrowserWidget::handleStoppingPointReached);
    QObject::connect(this,                                                      &SeerGdbWidget::stoppingPointReached,                                                       commandLogsWidget->watchpointsBrowser(),                        &SeerWatchpointsBrowserWidget::handleStoppingPointReached);
    QObject::connect(this,                                                      &SeerGdbWidget::stoppingPointReached,                                                       commandLogsWidget->catchpointsBrowser(),                        &SeerCatchpointsBrowserWidget::handleStoppingPointReached);
    QObject::connect(this,                                                      &SeerGdbWidget::stoppingPointReached,                                                       commandLogsWidget->printpointsBrowser(),                        &SeerPrintpointsBrowserWidget::handleStoppingPointReached);
    QObject::connect(this,                                                      &SeerGdbWidget::stoppingPointReached,                                                       commandLogsWidget->checkpointsBrowser(),                        &SeerCheckpointsBrowserWidget::handleStoppingPointReached);

    QObject::connect(this,                                                      &SeerGdbWidget::sessionTerminated,                                                          editorManagerWidget,                                            &SeerEditorManagerWidget::handleSessionTerminated);
    QObject::connect(this,                                                      &SeerGdbWidget::sessionTerminated,                                                          sourceLibraryManagerWidget->sourceBrowserWidget(),              &SeerSourceBrowserWidget::handleSessionTerminated);
    QObject::connect(this,                                                      &SeerGdbWidget::sessionTerminated,                                                          sourceLibraryManagerWidget->functionBrowserWidget(),            &SeerFunctionBrowserWidget::handleSessionTerminated);
    QObject::connect(this,                                                      &SeerGdbWidget::sessionTerminated,                                                          sourceLibraryManagerWidget->functionBrowserWidget(),            &SeerFunctionBrowserWidget::handleSessionTerminated);
    QObject::connect(this,                                                      &SeerGdbWidget::sessionTerminated,                                                          sourceLibraryManagerWidget->staticBrowserWidget(),              &SeerStaticBrowserWidget::handleSessionTerminated);
    QObject::connect(this,                                                      &SeerGdbWidget::sessionTerminated,                                                          sourceLibraryManagerWidget->libraryBrowserWidget(),             &SeerLibraryBrowserWidget::handleSessionTerminated);
    QObject::connect(this,                                                      &SeerGdbWidget::sessionTerminated,                                                          sourceLibraryManagerWidget->adaExceptionsBrowserWidget(),       &SeerAdaExceptionsBrowserWidget::handleSessionTerminated);
    QObject::connect(this,                                                      &SeerGdbWidget::sessionTerminated,                                                          sourceLibraryManagerWidget->skipBrowserWidget(),                &SeerSkipBrowserWidget::handleSessionTerminated);
    QObject::connect(this,                                                      &SeerGdbWidget::sessionTerminated,                                                          variableManagerWidget->variableLoggerBrowserWidget(),           &SeerVariableLoggerBrowserWidget::handleSessionTerminated);
    QObject::connect(this,                                                      &SeerGdbWidget::sessionTerminated,                                                          variableManagerWidget->variableTrackerBrowserWidget(),          &SeerVariableTrackerBrowserWidget::handleSessionTerminated);
    QObject::connect(this,                                                      &SeerGdbWidget::sessionTerminated,                                                          variableManagerWidget->registerValuesBrowserWidget(),           &SeerRegisterValuesBrowserWidget::handleSessionTerminated);
    QObject::connect(this,                                                      &SeerGdbWidget::sessionTerminated,                                                          stackManagerWidget,                                             &SeerStackManagerWidget::handleSessionTerminated);
    QObject::connect(this,                                                      &SeerGdbWidget::sessionTerminated,                                                          stackManagerWidget->stackFramesBrowserWidget(),                 &SeerStackFramesBrowserWidget::handleSessionTerminated);
    QObject::connect(this,                                                      &SeerGdbWidget::sessionTerminated,                                                          stackManagerWidget->stackLocalsBrowserWidget(),                 &SeerStackLocalsBrowserWidget::handleSessionTerminated);
    QObject::connect(this,                                                      &SeerGdbWidget::sessionTerminated,                                                          stackManagerWidget->stackArgumentsBrowserWidget(),              &SeerStackArgumentsBrowserWidget::handleSessionTerminated);
    QObject::connect(this,                                                      &SeerGdbWidget::sessionTerminated,                                                          stackManagerWidget->stackDumpBrowserWidget(),                   &SeerStackDumpBrowserWidget::handleSessionTerminated);
    QObject::connect(this,                                                      &SeerGdbWidget::sessionTerminated,                                                          threadManagerWidget->threadFramesBrowserWidget(),               &SeerThreadFramesBrowserWidget::handleSessionTerminated);
    QObject::connect(this,                                                      &SeerGdbWidget::sessionTerminated,                                                          threadManagerWidget->threadIdsBrowserWidget(),                  &SeerThreadIdsBrowserWidget::handleSessionTerminated);
    QObject::connect(this,                                                      &SeerGdbWidget::sessionTerminated,                                                          threadManagerWidget->threadGroupsBrowserWidget(),               &SeerThreadGroupsBrowserWidget::handleSessionTerminated);
    QObject::connect(this,                                                      &SeerGdbWidget::sessionTerminated,                                                          threadManagerWidget->adaTasksBrowserWidget(),                   &SeerAdaTasksBrowserWidget::handleSessionTerminated);
    QObject::connect(this,                                                      &SeerGdbWidget::sessionTerminated,                                                          commandLogsWidget->breakpointsBrowser(),                        &SeerBreakpointsBrowserWidget::handleSessionTerminated);
    QObject::connect(this,                                                      &SeerGdbWidget::sessionTerminated,                                                          commandLogsWidget->watchpointsBrowser(),                        &SeerWatchpointsBrowserWidget::handleSessionTerminated);
    QObject::connect(this,                                                      &SeerGdbWidget::sessionTerminated,                                                          commandLogsWidget->catchpointsBrowser(),                        &SeerCatchpointsBrowserWidget::handleSessionTerminated);
    QObject::connect(this,                                                      &SeerGdbWidget::sessionTerminated,                                                          commandLogsWidget->printpointsBrowser(),                        &SeerPrintpointsBrowserWidget::handleSessionTerminated);
    QObject::connect(this,                                                      &SeerGdbWidget::sessionTerminated,                                                          commandLogsWidget->checkpointsBrowser(),                        &SeerCheckpointsBrowserWidget::handleSessionTerminated);

    QObject::connect(leftCenterRightSplitter,                                   &QSplitter::splitterMoved,                                                                  this,                                                           &SeerGdbWidget::handleSplitterMoved);
    QObject::connect(sourceLibraryVariableManagerSplitter,                      &QSplitter::splitterMoved,                                                                  this,                                                           &SeerGdbWidget::handleSplitterMoved);
    QObject::connect(sourceCommandLogsSplitter,                                 &QSplitter::splitterMoved,                                                                  this,                                                           &SeerGdbWidget::handleSplitterMoved);
    QObject::connect(stackThreadManagerSplitter,                                &QSplitter::splitterMoved,                                                                  this,                                                           &SeerGdbWidget::handleSplitterMoved);
    QObject::connect(commandLogsWidget->gdbOutputLog(),                         &SeerGdbLogWidget::refreshBreakpointsList,                                                  this,                                                           &SeerGdbWidget::handleGdbGenericpointList);
    QObject::connect(editorManagerWidget,                                       &SeerEditorManagerWidget::refreshFunctionList,                                              this,                                                           &SeerGdbWidget::handleGdbExecutableFunctions);
    QObject::connect(editorManagerWidget,                                       &SeerEditorManagerWidget::refreshVariableList,                                              this,                                                           &SeerGdbWidget::handleGdbExecutableVariables);
    QObject::connect(editorManagerWidget,                                       &SeerEditorManagerWidget::refreshTypeList,                                                  this,                                                           &SeerGdbWidget::handleGdbExecutableTypes);

#if SEER_GDB_LOGOUT == 1
    // Direct all GdbWidget and GdbMonitor log to GDB Log, for debugging
    QObject::connect(this,                                                      &SeerGdbWidget::gdbCommandLogout,                                                           commandLogsWidget->gdbOutputLog(),                              &SeerGdbLogWidget::handleText);
    QObject::connect(_gdbMonitor,                                               &GdbMonitor::allTextOutput,                                                                 commandLogsWidget->gdbOutputLog(),                              &SeerGdbLogWidget::handleText);
#endif

    QObject::connect(this,                                                      &SeerGdbWidget::stateChanged,                                                               editorManagerWidget,                                            &SeerEditorManagerWidget::handleGdbStateChanged);

    // Restore window settings.
    readSettings();
}

SeerGdbWidget::~SeerGdbWidget () {

    commandLogsWidget->deleteConsole();

    if (_gdbMonitor) {
        delete _gdbMonitor;
    }

    if (_gdbProcess) {
        _gdbProcess->kill();
        _gdbProcess->waitForFinished();
        delete _gdbProcess;
    }
}

GdbMonitor* SeerGdbWidget::gdbMonitor () {
    return _gdbMonitor;
}

QProcess* SeerGdbWidget::gdbProcess () {
    return _gdbProcess;
}

void SeerGdbWidget::setExecutableName (const QString& executableName) {

    _executableName = executableName;

    setNewExecutableFlag(true);
}

const QString& SeerGdbWidget::executableName () const {
    return _executableName;
}

void SeerGdbWidget::setExecutableSymbolName (const QString& executableSymbolName) {

    _executableSymbolName = executableSymbolName;

    setNewExecutableFlag(true);
}

const QString& SeerGdbWidget::executableSymbolName () const {
    return _executableSymbolName;
}

void SeerGdbWidget::setNewExecutableFlag (bool flag) {

    _newExecutableFlag = flag;
}

bool SeerGdbWidget::newExecutableFlag () const {
    return _newExecutableFlag;
}

void SeerGdbWidget::setExecutableArguments (const QString& executableArguments) {

    _executableArguments = executableArguments;
}

const QString& SeerGdbWidget::executableArguments () const {
    return _executableArguments;
}

void SeerGdbWidget::setExecutableWorkingDirectory (const QString& executableWorkingDirectory) {

    _executableWorkingDirectory = executableWorkingDirectory;
}

const QString& SeerGdbWidget::executableWorkingDirectory () const {
    return _executableWorkingDirectory;
}

void SeerGdbWidget::setExecutableBreakpointsFilename (const QString& breakpointsFilename) {
    _executableBreakpointsFilename = breakpointsFilename;
}

const QString& SeerGdbWidget::executableBreakpointsFilename () const {
    return _executableBreakpointsFilename;
}

void SeerGdbWidget::setExecutableBreakpointFunctionName (const QString& nameoraddress) {
    _executableBreakpointFunctionName = nameoraddress;
}

const QString& SeerGdbWidget::executableBreakpointFunctionName () const {
    return _executableBreakpointFunctionName;
}

void SeerGdbWidget::setExecutableBreakpointSourceName (const QString& sourceFilenameAndLineno) {
    _executableBreakpointSourceName = sourceFilenameAndLineno;
}

const QString& SeerGdbWidget::executableBreakpointSourceName () const {
    return _executableBreakpointSourceName;
}

void SeerGdbWidget::setExecutableBreakpointFirstInstruction (bool flag) {
    _executableBreakpointFirstInstruction = flag;
}

bool SeerGdbWidget::executableBreakpointFirstInstruction () const {
    return _executableBreakpointFirstInstruction;
}

void SeerGdbWidget::setExecutablePid (int pid) {
    _executablePid = pid;
}

int SeerGdbWidget::executablePid () const {
    return _executablePid;
}

void SeerGdbWidget::setExecutableConnectHostPort (const QString& connectHostPort) {
    _executableConnectHostPort = connectHostPort;
}

const QString& SeerGdbWidget::executableConnectHostPort () const {
    return _executableConnectHostPort;
}

void SeerGdbWidget::setExecutableRRTraceDirectory (const QString& rrTraceDirectory) {
    _executableRRTraceDirectory = rrTraceDirectory;
}

const QString& SeerGdbWidget::executableRRTraceDirectory () const {
    return _executableRRTraceDirectory;
}

void SeerGdbWidget::setExecutableCoreFilename (const QString& coreFilename) {
    _executableCoreFilename = coreFilename;
}

const QString& SeerGdbWidget::executableCoreFilename () const {
    return _executableCoreFilename;
}

void SeerGdbWidget::setExecutablePreGdbCommands (const QStringList& preGdbCommands) {
    _executablePreGdbCommands = preGdbCommands;
}

const QStringList& SeerGdbWidget::executablePreGdbCommands () const {
    return _executablePreGdbCommands;
}

void SeerGdbWidget::setExecutablePostGdbCommands (const QStringList& postGdbCommands) {
    _executablePostGdbCommands = postGdbCommands;
}

const QStringList& SeerGdbWidget::executablePostGdbCommands () const {
    return _executablePostGdbCommands;
}

void SeerGdbWidget::setExecutableLaunchMode (const QString& launchMode) {
    _executableLaunchMode = launchMode;
}

const QString& SeerGdbWidget::executableLaunchMode () const {
    return _executableLaunchMode;
}

const QString& SeerGdbWidget::executableBreakMode () const {
    return _executableBreakMode;
}

void SeerGdbWidget::saveLaunchMode() {
    _executableLaunchModeBackup = _executableLaunchMode;
    _executableBreakModeBackup  = _executableBreakMode;
}

void SeerGdbWidget::restoreLaunchMode() {
    _executableLaunchMode = _executableLaunchModeBackup;
    _executableBreakMode  = _executableBreakModeBackup;
}

bool SeerGdbWidget::hasBackupLaunchMode () const {
    if (_executableLaunchModeBackup == "") {
        return false;
    }

    return true;
}

void SeerGdbWidget::clearBackupLaunchMode () {
    _executableLaunchModeBackup = "";
    _executableBreakModeBackup  = "";
}

const QString& SeerGdbWidget::backupLaunchMode () const {
    return _executableLaunchModeBackup;
}

void SeerGdbWidget::setGdbProgram (const QString& program) {

    _gdbProgram = program;
}

QString SeerGdbWidget::gdbProgram () const {

    return _gdbProgram;
}

void SeerGdbWidget::setGdbLauncher (const QString& launchProgram) {

    _gdbLauncher = launchProgram;
}

QString SeerGdbWidget::gdbLauncher () const {

    return _gdbLauncher;
}

void SeerGdbWidget::setGdbArguments (const QString& arguments) {

    _gdbArguments = arguments;
}

QString SeerGdbWidget::gdbArguments () const {

    return _gdbArguments;
}

void SeerGdbWidget::setGdbProgramOverride (const QString& program) {

    _gdbProgramOverride = program;
}

QString SeerGdbWidget::gdbProgramOverride () const {

    return _gdbProgramOverride;
}

void SeerGdbWidget::setGdbArgumentsOverride (const QString& arguments) {

    _gdbArgumentsOverride = arguments;
}

QString SeerGdbWidget::gdbArgumentsOverride () const {

    return _gdbArgumentsOverride;
}

void SeerGdbWidget::setRRProgram (const QString& program) {

    _gdbRRProgram = program;
}

QString SeerGdbWidget::rrProgram () const {

    return _gdbRRProgram;
}

void SeerGdbWidget::setRRArguments (const QString& arguments) {

    _gdbRRArguments = arguments;
}

QString SeerGdbWidget::rrArguments () const {

    return _gdbRRArguments;
}

void SeerGdbWidget::setRRGdbArguments (const QString& arguments) {

    _gdbRRGdbArguments = arguments;
}

QString SeerGdbWidget::rrGdbArguments () const {

    return _gdbRRGdbArguments;
}

void SeerGdbWidget::setGdbAsyncMode (bool flag) {

    _gdbASyncMode = flag;
}

bool SeerGdbWidget::gdbAsyncMode () const {

    return _gdbASyncMode;
}

void SeerGdbWidget::setGdbNonStopMode (bool flag) {

    _gdbNonStopMode = flag;
}

bool SeerGdbWidget::gdbNonStopMode () const {

    return _gdbNonStopMode;
}

void SeerGdbWidget::setGdbServerDebug (bool flag) {

    _gdbServerDebug = flag;
}

bool SeerGdbWidget::gdbServerDebug () const {

    return _gdbServerDebug;
}

void SeerGdbWidget::setGdbHandleTerminatingException (bool flag) {

    _gdbHandleTerminatingException = flag;
}

bool SeerGdbWidget::gdbHandleTerminatingException () const {

    return _gdbHandleTerminatingException;
}

void SeerGdbWidget::setGdbRandomizeStartAddress (bool flag) {

    _gdbRandomizeStartAddress = flag;
}

bool SeerGdbWidget::gdbRandomizeStartAddress () const {

    return _gdbRandomizeStartAddress;
}

void SeerGdbWidget::setGdbEnablePrettyPrinting (bool flag) {

    _gdbEnablePrettyPrinting = flag;
}

bool SeerGdbWidget::gdbEnablePrettyPrinting () const {

    return _gdbEnablePrettyPrinting;
}

void SeerGdbWidget::setGdbRemoteTargetType (const QString& type) {

    _gdbRemoteTargetType = type;
}

QString SeerGdbWidget::gdbRemoteTargetType () const {

    return _gdbRemoteTargetType;
}

void SeerGdbWidget::setGdbArchitectureType (const QString& type) {

    _gdbArchitectureType = type;
}

QString SeerGdbWidget::gdbArchitectureType () const {

    return _gdbArchitectureType;
}

void SeerGdbWidget::setGdbRecordMode(const QString& mode) {

    if (mode == "auto") {
        if (gdbProgram().contains("udb")) {
            _gdbRecordMode = "udb";
        }else{
            _gdbRecordMode = "";
        }
    }else{
        _gdbRecordMode = mode;
    }

    if (_gdbRecordMode != "rr" && _gdbRecordMode != "udb" && _gdbRecordMode != "") {
        handleGdbCommand("record " + _gdbRecordMode);
    }

    emit recordSettingsChanged();
}

QString SeerGdbWidget::gdbRecordMode () const {

    return _gdbRecordMode;
}

void SeerGdbWidget::setGdbRecordDirection (const QString& direction) {

    _gdbRecordDirection = direction;

    emit recordSettingsChanged();
}

QString SeerGdbWidget::gdbRecordDirection () const {

    return _gdbRecordDirection;
}

SeerEditorManagerWidget* SeerGdbWidget::editorManager () {

    return editorManagerWidget;
}

const SeerEditorManagerWidget* SeerGdbWidget::editorManager () const {

    return editorManagerWidget;
}

void SeerGdbWidget::addMessage (const QString& message, QMessageBox::Icon messageType) {

    commandLogsWidget->messagesBrowser()->addMessage(message, messageType);
}

void SeerGdbWidget::handleText (const QString& text) {

    if (text.startsWith("*running,thread-id=\"all\"")) {

    // Probably a better way to handle all these types of stops.
    }else if (text.startsWith("*stopped")) {

        emit stoppingPointReached();

    }else if (text.startsWith("=breakpoint-created,")) {

        handleGdbGenericpointList();

    }else if (text.startsWith("=thread-group-started,")) {
        // =thread-group-started,id="i1",pid="30916"

        QString pid_text = Seer::parseFirst(text, "pid=", '"', '"', false);

        //qDebug() << "Inferior pid = " << pid_text;

        setExecutablePid(pid_text.toLong());

    }else if (text.startsWith("=thread-group-exited,")) {

        handleGdbTerminateExecutable(false);

    // Scan the output for magic text to refresh the Signal tab.
    }else if (text.startsWith("~\"@refresh-signal-values\"")) {

        handleGdbSignalListValues("all");

    }else{
        // All other text is ignored by this widget.
    }
}

void SeerGdbWidget::handleManualCommandExecute (QString command) {

    // Do nothing if it is blank.
    if (command == "") {
        return;
    }

    // Execute it.
    handleGdbCommand(command);
}

void SeerGdbWidget::handleGdbCommand (const QString& command, bool ignoreErrors) {

    qCDebug(LC) << "Command=" << command;

    if (_gdbProcess->state() == QProcess::NotRunning) {
        if (ignoreErrors == false) {
            QMessageBox::warning(this, "Seer",
                                 QString("The executable has not been started yet or has already exited.\n\n") +
                                 "(" + command + ")",
                                 QMessageBox::Ok);
        }
        return;
    }

    QString str = command + "\n";    // Ensure there's a trailing RETURN.

    QByteArray bytes = str.toUtf8(); // 8-bit Unicode Transformation Format

#if SEER_GDB_LOGOUT == 1
    // Broadcast this log. For debugging
    emit gdbCommandLogout("From Widget:" + str);
#endif

    _gdbProcess->write(bytes);       // Send the data into the stdin stream of the bash child process
}

void SeerGdbWidget::handleGdbCommands (const QStringList& commands) {

    // This may not be as good as using "source file.gdb" because it doesn't
    // stop on errors.
    //
    // Leaving it here, though.

    for (auto command : commands) {
        handleGdbCommand(command, true);
    }
}

void SeerGdbWidget::handleGdbMonitorCommand (int id, const QString& command) {
    handleGdbCommand(QString::number(id)+"-monitor-exec " + command);
}

void SeerGdbWidget::handleGdbExit () {

    handleGdbCommand("-gdb-exit");
}

void SeerGdbWidget::handleGdbRunExecutable (const QString& breakMode, bool loadSessionBreakpoints) {

    qCDebug(LC) << "Starting 'gdb run/start':" << breakMode;

    QApplication::setOverrideCursor(Qt::BusyCursor);

    while (1) {
        // Has a executable name been provided?
        if (executableName() == "") {

            QMessageBox::warning(this, "Seer",
                    QString("The executable name has not been provided.\n\nUse File->Debug..."),
                    QMessageBox::Ok);
            break;
        }

        _executableBreakMode = breakMode;

        // Always say a new executable.
        // This causes a new gdb each time. The same console, though.
        setNewExecutableFlag(true);

        // Delete the old gdb if there is a new executable.
        if (newExecutableFlag() == true) {
            killGdb();
        }

        // If gdb isn't running, start it.
        if (isGdbRuning() == false) {

            // Connect the terminal to the console.
            console()->resetTerminal();
            console()->connectTerminal();

            // Start gdb.
            bool f = startGdb();
            if (f == false) {
                QMessageBox::critical(this, tr("Error"), tr("Can't start gdb."));
                break;
            }

            if (gdbAsyncMode()) {
                handleGdbCommand("-gdb-set mi-async on"); // Turn on async mode so the 'interrupt' can happen.
            }

            if (gdbNonStopMode()) {
                handleGdbCommand("-gdb-set pagination off");
                handleGdbCommand("-gdb-set non-stop on");
            }else{
                handleGdbCommand("-gdb-set non-stop off");
            }

            handleGdbLoadMICommands();
            handleGdbSourceScripts();
            handleGdbLoadSkips();
        }

        // Set the program's tty device for stdin and stdout.
        handleGdbTerminalDeviceName();

        setExecutableLaunchMode("run");
        saveLaunchMode();
        setGdbRecordMode("auto");
        setExecutablePid(0);

        // Load the executable, if needed.
        if (newExecutableFlag() == true) {
            handleGdbSetArchitectureType();
            handleGdbExecutablePreCommands();       // Run any 'pre' commands before program is loaded.
            handleGdbExecutableName();              // Load the program into the gdb process.
            handleGdbExecutableSources();           // Load the program source files.
            handleGdbExecutableLoadBreakpoints();   // Set the program's breakpoints (if any) before running.

            if (loadSessionBreakpoints) {
                handleGdbSessionLoadBreakpoints();
            }

            setNewExecutableFlag(false);
        }

        // Set or reset some things.
        handleGdbExecutableWorkingDirectory();  // Set the program's working directory before running.
        handleGdbAssemblyDisassemblyFlavor();   // Set the disassembly flavor to use.
        handleGdbAssemblySymbolDemangling();    // Set the symbol demangling.

        editorManager()->maybeShowAssembly();

        if (gdbHandleTerminatingException()) {
            handleGdbCommand("-gdb-set unwind-on-terminating-exception on"); // Turn on terminating exceptions when gdb calls the program's functions.
        }else{
            handleGdbCommand("-gdb-set unwind-on-terminating-exception off");
        }

        if (gdbRandomizeStartAddress()) {
            handleGdbCommand("-gdb-set disable-randomization off"); // Turn on randomization of starting address for process.
        }

        if (gdbEnablePrettyPrinting()) {
            handleGdbCommand("-enable-pretty-printing"); // Turn on pretty-printing. Can not be turned off.
        }

        // Set the program's arguments before running.
        handleGdbExecutableArguments();

        // Set a breakpoint for start up if "infunction".
        if (_executableBreakMode == "infunction" && executableBreakpointFunctionName() != "") {

            if (executableBreakpointFunctionName().contains(QRegularExpression("^0[xX][0-9a-fA-F]+"))) {
                handleGdbBreakpointInsert("*" + executableBreakpointFunctionName());
            }else{
                handleGdbBreakpointInsert("-f --function " + executableBreakpointFunctionName());
            }
        }

        // Set breakpoints for start up if "insource".
        if (_executableBreakMode == "insource" && executableBreakpointSourceName() != "") {
            handleGdbBreakpointsInsert(executableBreakpointSourceName());
        }

        // Elaborate gdb variable output
        handleGdbCommand("set print repeats unlimited");

        // Run any 'post' commands after program is loaded.
        handleGdbExecutablePostCommands();

        // Run the executable.
        if (_executableBreakMode == "inmain") {
            handleGdbCommand("-exec-run --all --start"); // Stop in main.
        }else if (_executableBreakMode == "firstinstruction") {
            handleGdbCommand("-exec-starti"); // Stop at first instruction.
        }else{
            handleGdbCommand("-exec-run --all"); // Do not stop in main. But honor other breakpoints that may have been previously set.
        }

        // Set window titles with name of program.
        emit changeWindowTitle(QString("%1 (pid=%2)").arg(executableName()).arg(QGuiApplication::applicationPid()));

        // Notify the state of the GdbWidget has changed.
        emit stateChanged();

        break;
    }

    QApplication::restoreOverrideCursor();

    qCDebug(LC) << "Finishing 'gdb run/start'.";
}

void SeerGdbWidget::handleGdbAttachExecutable (bool loadSessionBreakpoints) {

    qCDebug(LC) << "Starting 'gdb attach'.";

    QApplication::setOverrideCursor(Qt::BusyCursor);

    while (1) {

        // Has a executable name been provided?
        if (executableName() == "") {

            QMessageBox::warning(this, "Seer",
                    QString("The executable name has not been provided.\n\nUse File->Debug..."),
                    QMessageBox::Ok);
            break;
        }

        _executableBreakMode = "";

        // Always say a new executable.
        // This causes a new gdb each time. The same console, though.
        setNewExecutableFlag(true);

        // Delete the old gdb if there is a new executable.
        if (newExecutableFlag() == true) {
            killGdb();
        }

        // If gdb isn't running, start it.
        // No need to connect to the console in this mode.
        if (isGdbRuning() == false) {

            // Connect the terminal to the console.
            console()->resetTerminal();
            console()->connectTerminal();

            // Start gdb.
            bool f = startGdb();
            if (f == false) {
                QMessageBox::critical(this, tr("Error"), tr("Can't start gdb."));
                break;
            }

            if (gdbAsyncMode()) {
                handleGdbCommand("-gdb-set mi-async on"); // Turn on async mode so the 'interrupt' can happen.
            }

            handleGdbLoadMICommands();
            handleGdbSourceScripts();
            handleGdbLoadSkips();
        }

        // Set the program's tty device for stdin and stdout.
        // Not really needed for 'attach' mode, but do it anyway.
        handleGdbTerminalDeviceName();

        // No console for 'attach' mode but make sure it's reattached.
        setExecutableLaunchMode("attach");
        saveLaunchMode();
        setGdbRecordMode("auto");
        commandLogsWidget->reattachConsole();

        // Load the executable, if needed.
        if (newExecutableFlag() == true) {
            handleGdbSetArchitectureType();
            handleGdbExecutablePreCommands();       // Run any 'pre' commands before program is loaded.
            handleGdbExecutableName();              // Load the program into the gdb process.
            handleGdbExecutableSources();           // Load the program source files.
            handleGdbExecutableLoadBreakpoints();   // Set the program's breakpoints (if any) before running.

            if (loadSessionBreakpoints) {
                handleGdbSessionLoadBreakpoints();
            }

            setNewExecutableFlag(false);
        }

        // Set or reset some things.
        handleGdbExecutableWorkingDirectory();  // Set the program's working directory before running.
        handleGdbAssemblyDisassemblyFlavor();   // Set the disassembly flavor to use.
        handleGdbAssemblySymbolDemangling();    // Set the symbol demangling.

        editorManager()->maybeShowAssembly();

        if (gdbHandleTerminatingException()) {
            handleGdbCommand("-gdb-set unwind-on-terminating-exception on"); // Turn on terminating exceptions when gdb calls the program's functions.
        }else{
            handleGdbCommand("-gdb-set unwind-on-terminating-exception off");
        }

        // Attach to the executable's pid.
        handleGdbCommand(QString("-target-attach %1").arg(executablePid()));

        // Set breakpoints for start up if "insource".
        if (executableBreakpointSourceName() != "") {
            handleGdbBreakpointsInsert(executableBreakpointSourceName());
        }

        // Elaborate gdb variable output
        handleGdbCommand("set print repeats unlimited");

        // Run any 'post' commands after program is loaded.
        handleGdbExecutablePostCommands();

        // Set window titles with name of program.
        emit changeWindowTitle(QString("%1 (pid=%2)").arg(executableName()).arg(QGuiApplication::applicationPid()));

        // Notify the state of the GdbWidget has changed.
        emit stateChanged();

        break;
    }

    QApplication::restoreOverrideCursor();

    qCDebug(LC) << "Finishing 'gdb attach'.";
}

void SeerGdbWidget::handleGdbConnectExecutable (bool loadSessionBreakpoints) {

    qCDebug(LC) << "Starting 'gdb connect'.";

    QApplication::setOverrideCursor(Qt::BusyCursor);

    while (1) {

        _executableBreakMode = "";

        // Always say a new executable.
        // This causes a new gdb each time. The same console, though.
        setNewExecutableFlag(true);

        // Disconnect from the terminal and delete the old gdb if there is a new executable.
        if (newExecutableFlag() == true) {
            killGdb();
        }

        // If gdb isn't running, start it.
        if (isGdbRuning() == false) {

            // Connect the terminal to the console.
            console()->resetTerminal();
            console()->connectTerminal();

            // Start gdb.
            bool f = startGdb();
            if (f == false) {
                QMessageBox::critical(this, tr("Error"), tr("Can't start gdb."));
                break;
            }

            handleGdbLoadMICommands();
            handleGdbSourceScripts();
            handleGdbLoadSkips();
        }

        // Set the program's tty device for stdin and stdout.
        // Not really needed for 'connect' mode, but do it anyway.
        handleGdbTerminalDeviceName();

        // No console for 'connect' mode but make sure it's reattached.
        setExecutableLaunchMode("connect");
        saveLaunchMode();
        setGdbRecordMode("auto");
        setExecutablePid(0);
        commandLogsWidget->reattachConsole();

        // Load any 'pre' commands.
        if (newExecutableFlag() == true) {
            if (gdbServerDebug()) {
                handleGdbCommand("-gdb-set debug remote 1"); // Turn on gdbserver debug
            }else{
                handleGdbCommand("-gdb-set debug remote 0");
            }
            handleGdbExecutablePreCommands(); // Run any 'pre' commands before program is loaded.
        }

        // Connect to the remote gdbserver using the proper remote type.
        handleGdbCommand(QString("-target-select %1 %2").arg(gdbRemoteTargetType()).arg(executableConnectHostPort()));

        // Load the executable, if needed.
        if (newExecutableFlag() == true) {
            handleGdbSetArchitectureType();
            handleGdbExecutableName();              // Load the program into the gdb process.
            handleGdbExecutableSources();           // Load the program source files.
            handleGdbExecutableLoadBreakpoints();   // Set the program's breakpoints (if any) before running.

            if (loadSessionBreakpoints) {
                handleGdbSessionLoadBreakpoints();
            }

            setNewExecutableFlag(false);
        }

        // Set or reset some things.
        handleGdbExecutableWorkingDirectory();  // Set the program's working directory before running.
        handleGdbAssemblyDisassemblyFlavor();   // Set the disassembly flavor to use.
        handleGdbAssemblySymbolDemangling();    // Set the symbol demangling.

        editorManager()->maybeShowAssembly();

        if (gdbHandleTerminatingException()) {
            handleGdbCommand("-gdb-set unwind-on-terminating-exception on"); // Turn on terminating exceptions when gdb calls the program's functions.
        }else{
            handleGdbCommand("-gdb-set unwind-on-terminating-exception off");
        }

        // Set breakpoints for start up if "insource".
        if (executableBreakpointSourceName() != "") {
            handleGdbBreakpointsInsert(executableBreakpointSourceName());
        }

        // Elaborate gdb variable output
        handleGdbCommand("set print repeats unlimited");

        // Run any 'post' commands after program is loaded.
        handleGdbExecutablePostCommands();

        // Set window titles with name of program.
        emit changeWindowTitle(QString("%1 (pid=%2)").arg(executableConnectHostPort()).arg(QGuiApplication::applicationPid()));

        // Notify the state of the GdbWidget has changed.
        emit stateChanged();

        break;
    }

    QApplication::restoreOverrideCursor();

    qCDebug(LC) << "Finishing 'gdb connect'.";
}

void SeerGdbWidget::handleGdbRRExecutable (bool loadSessionBreakpoints) {

    qCDebug(LC) << "Starting 'gdb direct rr'.";

    QApplication::setOverrideCursor(Qt::BusyCursor);

    while (1) {

        // Has a executable name been provided?
        if (executableName() != "") {
            QMessageBox::warning(this, "Seer",
                    QString("The executable name can't be provided for 'rr' mode."),
                    QMessageBox::Ok);
            break;
        }

        _executableBreakMode = "";

        // Always say a new executable.
        // This causes a new gdb each time. The same console, though.
        setNewExecutableFlag(true);

        // Disconnect from the console and delete the old gdb, then reconnect.
        if (newExecutableFlag() == true) {
            killGdb();
        }

        // If gdb isn't running, start it.
        if (isGdbRuning() == false) {

            // Connect the terminal to the console.
            console()->resetTerminal();
            console()->connectTerminal();

            // Start gdb.
            bool f = startGdbRR();
            if (f == false) {
                QMessageBox::critical(this, tr("Error"), tr("Can't start gdb."));
                break;
            }

            handleGdbLoadMICommands();
            handleGdbSourceScripts();
            handleGdbLoadSkips();
        }

        // Set the program's tty device for stdin and stdout.
        handleGdbTerminalDeviceName();

        // Set the launch mode.
        setExecutableLaunchMode("rr");
        saveLaunchMode();
        setGdbRecordMode("rr");
        setGdbRecordDirection("");
        setExecutablePid(0);

        // Load the executable, if needed.
        // For RR, this will start it.
        if (newExecutableFlag() == true) {
            handleGdbSetArchitectureType();
            handleGdbExecutablePreCommands();       // Run any 'pre' commands before program is loaded.
            handleGdbExecutableName();              // Load the program into the gdb process.
            handleGdbExecutableSources();           // Load the program source files.
            handleGdbExecutableLoadBreakpoints();   // Set the program's breakpoints (if any) before running.

            if (loadSessionBreakpoints) {
                handleGdbSessionLoadBreakpoints();
            }

            setNewExecutableFlag(false);
        }

        // Set or reset some things.
        handleGdbExecutableWorkingDirectory();  // Set the program's working directory before running.
        handleGdbAssemblyDisassemblyFlavor();   // Set the disassembly flavor to use.
        handleGdbAssemblySymbolDemangling();    // Set the symbol demangling.

        editorManager()->maybeShowAssembly();

        if (gdbHandleTerminatingException()) {
            handleGdbCommand("-gdb-set unwind-on-terminating-exception on"); // Turn on terminating exceptions when gdb calls the program's functions.
        }else{
            handleGdbCommand("-gdb-set unwind-on-terminating-exception off");
        }

        if (gdbEnablePrettyPrinting()) {
            handleGdbCommand("-enable-pretty-printing"); // Turn on pretty-printing. Can not be turned off.
        }

        // Set breakpoints for start up if "insource".
        if (executableBreakpointSourceName() != "") {
            handleGdbBreakpointsInsert(executableBreakpointSourceName());
        }

        // Elaborate gdb variable output
        handleGdbCommand("set print repeats unlimited");

        // Run any 'post' commands after program is loaded.
        handleGdbExecutablePostCommands();

        // Set window titles with name of program.
        emit changeWindowTitle(QString("%1 (pid=%2)").arg(executableRRTraceDirectory()).arg(QGuiApplication::applicationPid()));

        // Notify the state of the GdbWidget has changed.
        emit stateChanged();

        break;
    }

    QApplication::restoreOverrideCursor();

    qCDebug(LC) << "Finishing 'gdb rr'.";
}

void SeerGdbWidget::handleGdbCoreFileExecutable () {

    qCDebug(LC) << "Starting 'gdb corefile'.";

    QApplication::setOverrideCursor(Qt::BusyCursor);

    while (1) {

        // Has a executable name been provided?
        if (executableName() == "") {

            QMessageBox::warning(this, "Seer",
                    QString("The executable name has not been provided.\n\nUse File->Debug..."),
                    QMessageBox::Ok);
            break;
        }

        _executableBreakMode = "";

        // Always say a new executable.
        // This causes a new gdb each time. The same console, though.
        setNewExecutableFlag(true);

        // Disconnect from the console and delete the old gdb. No need to reconnect.
        if (newExecutableFlag() == true) {
            killGdb();
        }

        // If gdb isn't running, start it.
        // No need to connect to the console in this mode.
        if (isGdbRuning() == false) {

            // Connect the terminal to the console.
            console()->resetTerminal();
            console()->connectTerminal();

            // Start gdb.
            bool f = startGdb();
            if (f == false) {
                QMessageBox::critical(this, tr("Error"), tr("Can't start gdb."));
                break;
            }

            if (gdbAsyncMode()) {
                handleGdbCommand("-gdb-set mi-async on"); // Turn on async mode so the 'interrupt' can happen.
            }

            handleGdbLoadMICommands();
            handleGdbSourceScripts();
            handleGdbLoadSkips();
        }

        // Set the program's tty device for stdin and stdout.
        // Not really needed for 'core' mode, but do it anyway.
        handleGdbTerminalDeviceName();

        // No console for 'core' mode but make sure it's reattached.
        setExecutableLaunchMode("corefile");
        saveLaunchMode();
        setGdbRecordMode("auto");
        setExecutablePid(0);
        commandLogsWidget->reattachConsole();

        if (newExecutableFlag() == true) {
            handleGdbSetArchitectureType();
            handleGdbExecutablePreCommands();       // Run any 'pre' commands before program is loaded.
            handleGdbExecutableName();              // Load the program into the gdb process.
            handleGdbExecutableSources();           // Load the program source files.
            handleGdbAssemblyDisassemblyFlavor();   // Set the disassembly flavor to use.
            handleGdbAssemblySymbolDemangling();    // Set the symbol demangling.

            editorManager()->maybeShowAssembly();
        }

        setNewExecutableFlag(false);

        // Load the executable's core file.
        handleGdbCommand(QString("-target-select core %1").arg(executableCoreFilename()));

        // Elaborate gdb variable output
        handleGdbCommand("set print repeats unlimited");

        // Run any 'post' commands after program is loaded.
        handleGdbExecutablePostCommands();

        // This is needed for 'core' mode to refresh the stack frame, for some reason.
        handleGdbStackListFrames();

        // Set window titles with name of program.
        emit changeWindowTitle(QString("%1 (pid=%2)").arg(executableName()).arg(QGuiApplication::applicationPid()));

        // Notify the state of the GdbWidget has changed.
        emit stateChanged();

        break;
    }

    QApplication::restoreOverrideCursor();

    qCDebug(LC) << "Finishing 'gdb corefile'.";
}

void SeerGdbWidget::handleGdbTerminateExecutable (bool confirm) {

    while (1) {

        // Do you really want to restart?
        if (isGdbRuning() == true) {

            if (confirm) {
                int result = QMessageBox::warning(this, "Seer",
                        QString("Terminate current session?"),
                        QMessageBox::Ok|QMessageBox::Cancel, QMessageBox::Cancel);

                if (result == QMessageBox::Cancel) {
                    break;
                }
            }

            handleGdbCommand(QString("save breakpoints /tmp/breakpoints.seer.%1").arg(QCoreApplication::applicationPid()), true);
            delay(2);

            // Give the gdb and 'exit' command.
            // This should handle detaching from an attached pid.
            handleGdbCommand("-exec-kill", true);

            // Kill the gdb.
            killGdb();

            // Print a message.
            addMessage("Program terminated.", QMessageBox::Warning);

            // Alert listeners the session has been terminated.
            emit sessionTerminated();

            // Notify the state of the GdbWidget has changed.
            emit stateChanged();
        }

        break;
    }
}

void SeerGdbWidget::handleGdbShutdown () {

    // Remove session breakpoint file, if any.
    QFile::remove(QString("/tmp/breakpoints.seer.%1").arg(QCoreApplication::applicationPid()));

    // Do nothing if there's not gdb running.
    if (isGdbRuning() == false) {
        return;
    }

    // We are in no mode now.
    setExecutableLaunchMode("");
    setGdbRecordMode("");

    // Give the gdb and 'exit' command.
    // This should handle detaching from an attached pid.
    handleGdbExit();

    // Kill the gdb.
    killGdb();
}

void SeerGdbWidget::handleGdbRunToLine (QString fullname, int lineno) {

    if (executableLaunchMode() == "") {
        return;
    }

    QString command = "-exec-until " + fullname + ":" + QString::number(lineno);

    handleGdbCommand(command);
}

void SeerGdbWidget::handleGdbRunToAddress (QString address) {

    if (executableLaunchMode() == "") {
        return;
    }

    QString command = "-exec-until *" +address;

    handleGdbCommand(command);
}

void SeerGdbWidget::handleGdbNext () {

    if (executableLaunchMode() == "") {
        return;
    }

    handleGdbCommand(QString("-exec-next %1").arg(gdbRecordDirection()));
}

void SeerGdbWidget::handleGdbNexti () {

    if (executableLaunchMode() == "") {
        return;
    }

    handleGdbCommand(QString("-exec-next-instruction %1").arg(gdbRecordDirection()));
}

void SeerGdbWidget::handleGdbStep () {

    if (executableLaunchMode() == "") {
        return;
    }

    handleGdbCommand(QString("-exec-step %1").arg(gdbRecordDirection()));
}

void SeerGdbWidget::handleGdbStepi () {

    if (executableLaunchMode() == "") {
        return;
    }

    handleGdbCommand(QString("-exec-step-instruction %1").arg(gdbRecordDirection()));
}

void SeerGdbWidget::handleGdbFinish () {

    if (executableLaunchMode() == "") {
        return;
    }

    handleGdbCommand(QString("-exec-finish %1").arg(gdbRecordDirection()));
}

void SeerGdbWidget::handleGdbContinue () {

    if (executableLaunchMode() == "") {
        return;
    }

    handleGdbCommand(QString("-exec-continue %1").arg(gdbRecordDirection()));
}

void SeerGdbWidget::handleGdbReverseNext () {

    if (executableLaunchMode() == "") {
        return;
    }

    handleGdbCommand("-exec-next --reverse");
}

void SeerGdbWidget::handleGdbReverseNexti () {

    if (executableLaunchMode() == "") {
        return;
    }

    handleGdbCommand("-exec-next-instruction --reverse");
}

void SeerGdbWidget::handleGdbReverseStep () {

    if (executableLaunchMode() == "") {
        return;
    }

    handleGdbCommand("-exec-step --reverse");
}

void SeerGdbWidget::handleGdbReverseStepi () {

    if (executableLaunchMode() == "") {
        return;
    }

    handleGdbCommand("-exec-step-instruction --reverse");
}

void SeerGdbWidget::handleGdbReverseFinish () {

    if (executableLaunchMode() == "") {
        return;
    }

    handleGdbCommand("-exec-finish --reverse");
}

void SeerGdbWidget::handleGdbReverseContinue () {

    if (executableLaunchMode() == "") {
        return;
    }

    handleGdbCommand("-exec-continue --reverse");
}

void SeerGdbWidget::handleGdbRecordStart () {

    if (executableLaunchMode() == "") {
        return;
    }

    if (executableLaunchMode() == "rr" || executableLaunchMode() == "udb") {
        QMessageBox::warning(this, "Seer", QString("Record 'Start' not available in RR or UDB mode."), QMessageBox::Ok);
        return;
    }

    setGdbRecordMode("full");
    setGdbRecordDirection("");
}

void SeerGdbWidget::handleGdbRecordStop () {

    if (executableLaunchMode() == "") {
        return;
    }

    if (executableLaunchMode() == "rr" || executableLaunchMode() == "udb") {
        QMessageBox::warning(this, "Seer", QString("Record 'Stop' not available in RR or UDB mode."), QMessageBox::Ok);
        return;
    }

    setGdbRecordMode("stop");
    setGdbRecordDirection("");
}

void SeerGdbWidget::handleGdbRecordForward () {

    setGdbRecordDirection("");
}

void SeerGdbWidget::handleGdbRecordReverse () {

    setGdbRecordDirection("--reverse");
}

void SeerGdbWidget::handleGdbRecordStartStopToggle () {

    if (gdbRecordMode() == "stop" || gdbRecordMode() == "") {

        setGdbRecordMode("full");
        setGdbRecordDirection("");

    }else if (gdbRecordMode() == "full") {

        setGdbRecordMode("stop");
        setGdbRecordDirection("");

    }else if (gdbRecordMode() == "rr") {

        // Don't do anthing.

    }else if (gdbRecordMode() == "udb") {

        // Don't do anthing.

    }else{

        setGdbRecordMode("stop");
        setGdbRecordDirection("");
    }
}

void SeerGdbWidget::handleGdbRecordDirectionToggle () {

    if (gdbRecordDirection() == "") {
        setGdbRecordDirection("--reverse");
    }else if (gdbRecordDirection() == "--reverse") {
        setGdbRecordDirection("");
    }else{
        setGdbRecordDirection("");
    }
}

void SeerGdbWidget::handleGdbInterrupt () {

    sendGdbInterrupt(-1);
}

void SeerGdbWidget::handleGdbInterruptSIGINT () {

    sendGdbInterrupt(SIGINT);
}

void SeerGdbWidget::handleGdbInterruptSIGKILL () {

    sendGdbInterrupt(SIGKILL);
}

void SeerGdbWidget::handleGdbInterruptSIGFPE () {

    sendGdbInterrupt(SIGFPE);
}

void SeerGdbWidget::handleGdbInterruptSIGSEGV () {

    sendGdbInterrupt(SIGSEGV);
}

void SeerGdbWidget::handleGdbInterruptSIGUSR1 () {

    sendGdbInterrupt(SIGUSR1);
}

void SeerGdbWidget::handleGdbInterruptSIGUSR2 () {

    sendGdbInterrupt(SIGUSR2);
}

void SeerGdbWidget::handleGdbRunThreadGroup (QString threadGroup) {

    if (executableLaunchMode() == "") {
        return;
    }

    if (threadGroup == "") {
        return;
    }

    handleGdbCommand(QString("-exec-run --thread-group %1").arg(threadGroup));
}

void SeerGdbWidget::handleGdbStartThreadGroup (QString threadGroup) {

    if (executableLaunchMode() == "") {
        return;
    }

    if (threadGroup == "") {
        return;
    }

    handleGdbCommand(QString("-exec-run --thread-group %1 --start").arg(threadGroup));
}

void SeerGdbWidget::handleGdbContinueThreadGroup (QString threadGroup) {

    if (executableLaunchMode() == "") {
        return;
    }

    if (threadGroup == "") {
        return;
    }

    handleGdbCommand(QString("-exec-continue %1 --thread-group %2").arg(gdbRecordDirection()).arg(threadGroup));
}

void SeerGdbWidget::handleGdbInterruptThreadGroup (QString threadGroup) {

    if (executableLaunchMode() == "") {
        return;
    }

    if (threadGroup == "") {
        return;
    }

    handleGdbCommand(QString("-exec-interrupt --thread-group %1").arg(threadGroup));
}

void SeerGdbWidget::handleGdbNextThreadId (int threadid) {

    if (executableLaunchMode() == "") {
        return;
    }

    handleGdbCommand(QString("-exec-next --thread %1 %2").arg(threadid).arg(gdbRecordDirection()));
}

void SeerGdbWidget::handleGdbStepThreadId (int threadid) {

    if (executableLaunchMode() == "") {
        return;
    }

    handleGdbCommand(QString("-exec-step %1 --thread %2").arg(gdbRecordDirection()).arg(threadid));
}

void SeerGdbWidget::handleGdbFinishThreadId (int threadid) {

    if (executableLaunchMode() == "") {
        return;
    }

    handleGdbCommand(QString("-exec-finish %1 --thread %2").arg(gdbRecordDirection()).arg(threadid));
}

void SeerGdbWidget::handleGdbContinueThreadId (int threadid) {

    if (executableLaunchMode() == "") {
        return;
    }

    handleGdbCommand(QString("-exec-continue %1 --thread %2").arg(gdbRecordDirection()).arg(threadid));
}

void SeerGdbWidget::handleGdbInterruptThreadId (int threadid) {

    if (executableLaunchMode() == "") {
        return;
    }

    handleGdbCommand(QString("-exec-interrupt --thread %1").arg(threadid));
}

void SeerGdbWidget::handleGdbExecutableSources () {

    if (executableLaunchMode() == "") {
        return;
    }

    handleGdbCommand("-file-list-exec-source-files");
}

void SeerGdbWidget::handleGdbExecutableFunctions (int id, const QString& functionRegex) {

    if (executableLaunchMode() == "") {
        return;
    }

    if (id <= 0) {
        return;
    }

    if (functionRegex == "") {
        return;
    }

    QApplication::setOverrideCursor(Qt::BusyCursor);
    handleGdbCommand(QString("%1-symbol-info-functions --include-nondebug --name %2").arg(id).arg(functionRegex));
    QApplication::restoreOverrideCursor();
}

void SeerGdbWidget::handleGdbExecutableTypes (int id, const QString& typeRegex) {

    if (executableLaunchMode() == "") {
        return;
    }

    if (id <= 0) {
        return;
    }

    if (typeRegex == "") {
        return;
    }

    //qDebug() << id << typeRegex;

    handleGdbCommand(QString("%1-symbol-info-types --name %2").arg(id).arg(typeRegex));
}

void SeerGdbWidget::handleGdbExecutableVariables (int id, const QString& variableNameRegex, const QString& variableTypeRegex) {

    if (executableLaunchMode() == "") {
        return;
    }

    if (id <= 0) {
        return;
    }

    if (variableNameRegex == "" && variableTypeRegex == "") {
        return;
    }

    QString command = QString("%1-symbol-info-variables").arg(id);

    if (variableNameRegex != "") {
        command += QString(" --name %1").arg(variableNameRegex);
    }

    if (variableTypeRegex != "") {
        command += QString(" --type %1").arg(variableTypeRegex);
    }

    handleGdbCommand(command);
}

void SeerGdbWidget::handleGdbExecutableLibraries () {

    if (executableLaunchMode() == "") {
        return;
    }

    handleGdbCommand("-file-list-shared-libraries");
}

void SeerGdbWidget::handleGdbExecutableName () {

    if (executableLaunchMode() == "") {
        return;
    }

    //qDebug() << executableName();
    //qDebug() << executableSymbolName();

    // executableName() is expected to be non-blank.

    // An executable and no symbol file? Symbols are expected in the executable.
    if (executableName() != "" && executableSymbolName() == "") {

        handleGdbCommand(QString("-file-exec-and-symbols \"") + executableName() + "\"");

    // An executable and a symbol file?  Open the executable and symbol files separately.
    }else if (executableName() != "" && executableSymbolName() != "") {

        handleGdbCommand(QString("-file-exec-file \"")   + executableName() + "\"");
        handleGdbCommand(QString("-file-symbol-file \"") + executableSymbolName() + "\"");

    // No executable and a symbol file?  Open the symbol files only.
    }else if (executableName() == "" && executableSymbolName() != "") {

        handleGdbCommand(QString("-file-symbol-file \"") + executableSymbolName() + "\"");
    }
}

void SeerGdbWidget::handleGdbExecutableArguments () {

    if (executableLaunchMode() == "") {
        return;
    }

    handleGdbCommand(QString("-exec-arguments ") + executableArguments());
}

void SeerGdbWidget::handleGdbExecutableWorkingDirectory () {

    if (executableLaunchMode() == "") {
        return;
    }

    if (executableWorkingDirectory() != "") {
        handleGdbCommand(QString("-environment-cd \"") + executableWorkingDirectory() + "\"");
    }
}

void SeerGdbWidget::handleGdbExecutableLoadBreakpoints () {

    if (executableBreakpointsFilename() == "") {
        return;
    }

    handleGdbCommand("source -v " + executableBreakpointsFilename());
    handleGdbGenericpointList();
}

void SeerGdbWidget::handleGdbExecutablePreCommands () {

    for (const auto& i : _executablePreGdbCommands) {
        handleGdbCommand(i);
    }
}

void SeerGdbWidget::handleGdbExecutablePostCommands () {

    for (const auto& i : _executablePostGdbCommands) {
        handleGdbCommand(i);
    }
}

void SeerGdbWidget::handleGdbSessionLoadBreakpoints () {

    QString filename = QString("/tmp/breakpoints.seer.%1").arg(QCoreApplication::applicationPid());

    if (QFile::exists(filename) == false) {
        return;
    }

    handleGdbCommand(QString("source -v %1").arg(filename));
    handleGdbGenericpointList();
}

void SeerGdbWidget::handleGdbSessionSaveBreakpoints () {

    handleGdbCommand(QString("source -v /tmp/breakpoints.seer.%1").arg(QCoreApplication::applicationPid()));
}

void SeerGdbWidget::handleGdbTerminalDeviceName () {

    if (commandLogsWidget->console()->terminalDeviceName() != "") {

        handleGdbCommand(QString("-inferior-tty-set ") + commandLogsWidget->console()->terminalDeviceName());

    }else{
        qWarning() << "Can't set TTY name because the name is blank.";
    }
}

void SeerGdbWidget::handleGdbStackListFrames () {

    if (executableLaunchMode() == "") {
        return;
    }

    handleGdbCommand("-stack-list-frames");
}

void SeerGdbWidget::handleGdbStackSelectFrame (int frameno) {

    if (executableLaunchMode() == "") {
        return;
    }

    // This is not supported anymore with gdbmi.
    // handleGdbCommand(QString("-stack-select-frame %1").arg(frameno));

    // So resort to calling the non-gdbmi version.
    handleGdbCommand(QString("frame %1").arg(frameno));

    emit stoppingPointReached();
}

void SeerGdbWidget::handleGdbStackListLocals () {

    if (executableLaunchMode() == "") {
        return;
    }

    handleGdbCommand("-stack-list-variables --all-values");
}

void SeerGdbWidget::handleGdbStackListArguments () {

    if (executableLaunchMode() == "") {
        return;
    }

    handleGdbCommand("-stack-list-arguments --all-values");
}

void SeerGdbWidget::handleGdbGenericpointList () {

    if (executableLaunchMode() == "") {
        return;
    }

    handleGdbCommand("-break-list");
}

void SeerGdbWidget::handleGdbBreakpointDelete (QString breakpoints) {

    if (executableLaunchMode() == "") {
        return;
    }

    handleGdbCommand("-break-delete " + breakpoints);
    handleGdbGenericpointList();
}

void SeerGdbWidget::handleGdbBreakpointEnable (QString breakpoints) {

    if (executableLaunchMode() == "") {
        return;
    }

    handleGdbCommand("-break-enable " + breakpoints);
    handleGdbGenericpointList();
}

void SeerGdbWidget::handleGdbBreakpointDisable (QString breakpoints) {

    if (executableLaunchMode() == "") {
        return;
    }

    handleGdbCommand("-break-disable " + breakpoints);
    handleGdbGenericpointList();
}

void SeerGdbWidget::handleGdbBreakpointInfo (int breakpointid, QString breakpoint) {

    if (executableLaunchMode() == "") {
        return;
    }

    QString str = QString("%1-break-info %2").arg(breakpointid).arg(breakpoint);

    handleGdbCommand(str);
}

void SeerGdbWidget::handleGdbBreakpointsInsert (QString breakpoints) {

    if (executableLaunchMode() == "") {
        return;
    }

    QStringList breakpointlist = breakpoints.split(',');

    for (const QString& breakpoint : breakpointlist) {
        handleGdbBreakpointInsert(breakpoint);
    }

    handleGdbGenericpointList();
}

void SeerGdbWidget::handleGdbBreakpointInsert (QString breakpoint) {

    if (executableLaunchMode() == "") {
        return;
    }

    handleGdbCommand("-break-insert " + breakpoint);
    handleGdbGenericpointList();
}

void SeerGdbWidget::handleGdbBreakpointCondition (QString breakpoint, QString condition) {

    if (executableLaunchMode() == "") {
        return;
    }

    QString str = condition.replace('"', "\\\""); // Quote " characters.

    handleGdbCommand("-break-condition " + breakpoint + " \"" + condition + "\"");
    handleGdbGenericpointList();
}

void SeerGdbWidget::handleGdbBreakpointIgnore (QString breakpoint, QString count) {

    if (executableLaunchMode() == "") {
        return;
    }

    handleGdbCommand("-break-after " + breakpoint + " " + count);
    handleGdbGenericpointList();
}

void SeerGdbWidget::handleGdbBreakpointCommand (QString breakpoint, QString command) {

    if (executableLaunchMode() == "") {
        return;
    }

    handleGdbCommand("-break-commands " + breakpoint + " \"" + command + "\"");
    handleGdbGenericpointList();
}

void SeerGdbWidget::handleGdbBreakpointCommands (QString breakpoint, QStringList commands) {

    if (executableLaunchMode() == "") {
        return;
    }

    QString commandstext;

    for (int i=0; i<commands.count(); i++) {
        if (commands[i].trimmed().isEmpty()) {
            continue;
        }

        commandstext += QString(" \"") + commands[i] + "\"";
    }

    handleGdbCommand("-break-commands " + breakpoint + commandstext);
    handleGdbGenericpointList();
}

void SeerGdbWidget::handleGdbBreakpointReload (QStringList breakpointsText) {

      for (int i=0; i<breakpointsText.size(); i++) {
           handleGdbBreakpointInsert(breakpointsText[i]);
      }
}

void SeerGdbWidget::handleGdbWatchpointReload (QStringList watchpointsText) {

      for (int i=0; i<watchpointsText.size(); i++) {
           handleGdbWatchpointInsert(watchpointsText[i]);
      }
}

void SeerGdbWidget::handleGdbCatchpointReload (QStringList catchpointsText) {

      for (int i=0; i<catchpointsText.size(); i++) {
           handleGdbCatchpointInsert(catchpointsText[i]);
      }
}

void SeerGdbWidget::handleGdbWatchpointDelete (QString watchpoints) {

    if (executableLaunchMode() == "") {
        return;
    }

    handleGdbCommand("-break-delete " + watchpoints);
    handleGdbGenericpointList();
}

void SeerGdbWidget::handleGdbWatchpointEnable (QString watchpoints) {

    if (executableLaunchMode() == "") {
        return;
    }

    handleGdbCommand("-break-enable " + watchpoints);
    handleGdbGenericpointList();
}

void SeerGdbWidget::handleGdbWatchpointDisable (QString watchpoints) {

    if (executableLaunchMode() == "") {
        return;
    }

    handleGdbCommand("-break-disable " + watchpoints);
    handleGdbGenericpointList();
}

void SeerGdbWidget::handleGdbWatchpointInsert (QString watchpoint) {

    if (executableLaunchMode() == "") {
        return;
    }

    handleGdbCommand("-break-watch " + watchpoint);
    handleGdbGenericpointList();
}

void SeerGdbWidget::handleGdbCatchpointDelete (QString catchpoints) {

    if (executableLaunchMode() == "") {
        return;
    }

    handleGdbCommand("-break-delete " + catchpoints);
    handleGdbGenericpointList();
}

void SeerGdbWidget::handleGdbCatchpointEnable (QString catchpoints) {

    if (executableLaunchMode() == "") {
        return;
    }

    handleGdbCommand("-break-enable " + catchpoints);
    handleGdbGenericpointList();
}

void SeerGdbWidget::handleGdbCatchpointDisable (QString catchpoints) {

    if (executableLaunchMode() == "") {
        return;
    }

    handleGdbCommand("-break-disable " + catchpoints);
    handleGdbGenericpointList();
}

void SeerGdbWidget::handleGdbCatchpointInsert (QString catchpoint) {

    if (executableLaunchMode() == "") {
        return;
    }

    handleGdbCommand("-catch-" + catchpoint); // A little bit different than break insert or watch insert.
    handleGdbGenericpointList();
}

void SeerGdbWidget::handleGdbPrintpointDelete (QString printpoints) {

    if (executableLaunchMode() == "") {
        return;
    }

    handleGdbCommand("-break-delete " + printpoints);
    handleGdbGenericpointList();
}

void SeerGdbWidget::handleGdbPrintpointEnable (QString printpoints) {

    if (executableLaunchMode() == "") {
        return;
    }

    handleGdbCommand("-break-enable " + printpoints);
    handleGdbGenericpointList();
}

void SeerGdbWidget::handleGdbPrintpointDisable (QString printpoints) {

    if (executableLaunchMode() == "") {
        return;
    }

    handleGdbCommand("-break-disable " + printpoints);
    handleGdbGenericpointList();
}

void SeerGdbWidget::handleGdbPrintpointInsert (QString type, QString function, QString channel, QString parameters) {

    if (executableLaunchMode() == "") {
        return;
    }

    handleGdbCommand("-gdb-set dprintf-style "    + type);
    handleGdbCommand("-gdb-set dprintf-function " + function);
    handleGdbCommand("-gdb-set dprintf-channel "  + channel);

    handleGdbCommand("-dprintf-insert " + parameters);
    handleGdbGenericpointList();
}


void SeerGdbWidget::handleGdbThreadListFrames () {

    if (executableLaunchMode() == "") {
        return;
    }

    handleGdbCommand("-thread-info");
}

void SeerGdbWidget::handleGdbThreadListIds () {

    if (executableLaunchMode() == "") {
        return;
    }

    handleGdbCommand("-thread-list-ids");
}

void SeerGdbWidget::handleGdbThreadListGroups () {

    if (executableLaunchMode() == "") {
        return;
    }

    handleGdbCommand("-list-thread-groups");
}

void SeerGdbWidget::handleGdbThreadSelectId (int threadid) {

    if (executableLaunchMode() == "") {
        return;
    }

    handleGdbCommand(QString("-thread-select %1").arg(threadid));

    emit stoppingPointReached();
}

void SeerGdbWidget::handleGdbAdaListTasks () {

    if (executableLaunchMode() == "") {
        return;
    }

    handleGdbCommand("-ada-task-info");
}

void SeerGdbWidget::handleGdbAdaListExceptions () {

    if (executableLaunchMode() == "") {
        return;
    }

    handleGdbCommand("-info-ada-exceptions");
}

void SeerGdbWidget::handleGdbSkipList () {

    // This option can work when GDB is running.

    handleGdbCommand("-skip-list");
}

void SeerGdbWidget::handleGdbSkipAdd (QString skipmode, QString skipparameters) {

    // This option can work when GDB is running.

    if (skipmode == "file") {
        handleGdbCommand("-skip-create-file " + skipparameters);
    }else if (skipmode == "gfile") {
        handleGdbCommand("-skip-create-gfile " + skipparameters);
    }else if (skipmode == "function") {
        handleGdbCommand("-skip-create-function " + skipparameters);
    }else if (skipmode == "rfunction") {
        handleGdbCommand("-skip-create-rfunction " + skipparameters);
    }else{
        return;
    }

    handleGdbSkipList();
}

void SeerGdbWidget::handleGdbSkipDelete (QString skipids) {

    if (executableLaunchMode() == "") {
        return;
    }

    handleGdbCommand("-skip-delete " + skipids);

    handleGdbSkipList();
}

void SeerGdbWidget::handleGdbSkipEnable (QString skipids) {

    if (executableLaunchMode() == "") {
        return;
    }

    handleGdbCommand("-skip-enable " + skipids);

    handleGdbSkipList();
}

void SeerGdbWidget::handleGdbSkipDisable (QString skipids) {

    if (executableLaunchMode() == "") {
        return;
    }

    handleGdbCommand("-skip-disable " + skipids);

    handleGdbSkipList();
}

void SeerGdbWidget::handleGdbCheckpointList () {

    if (executableLaunchMode() == "") {
        return;
    }

    handleGdbCommand("-checkpoint-list");
}

void SeerGdbWidget::handleGdbCheckpointInsert () {

    if (executableLaunchMode() == "") {
        return;
    }

    handleGdbCommand("-checkpoint-create");
    handleGdbCommand("-checkpoint-list");
}

void SeerGdbWidget::handleGdbCheckpointSelect (QString id) {

    if (executableLaunchMode() == "") {
        return;
    }

    handleGdbCommand("-checkpoint-select " + id);

    emit stoppingPointReached();
}

void SeerGdbWidget::handleGdbCheckpointDelete (QString ids) {

    if (executableLaunchMode() == "") {
        return;
    }

    QStringList list = ids.split(" ");

    for (auto id : list) {
        handleGdbCommand("-checkpoint-delete " + id);
    }

    handleGdbCommand("-checkpoint-list");
}

void SeerGdbWidget::handleGdbRegisterListNames () {

    if (executableLaunchMode() == "") {
        return;
    }

    handleGdbCommand("-data-list-register-names");
}

void SeerGdbWidget::handleGdbRegisterListValues (QString fmt) {

    if (executableLaunchMode() == "") {
        return;
    }

    if (fmt == "") {
        fmt = "N";
    }

    // XXX Not sure what --skip-unavailable does.
    // XXX Perhaps skips registers that can't get value for.
    // XXX handleGdbCommand("-data-list-register-values --skip-unavailable " + fmt);

    handleGdbCommand("-data-list-register-values " + fmt);
}

void SeerGdbWidget::handleGdbRegisterSetValue (QString fmt, QString name, QString value) {

    if (executableLaunchMode() == "") {
        return;
    }

    // Set the register value.
    handleGdbCommand("-gdb-set $" + name + "=" + value);

    // Refresh whoever is listening.
    handleGdbRegisterListValues(fmt);
}

void SeerGdbWidget::handleGdbSignalListNames () {

    if (executableLaunchMode() == "") {
        return;
    }

    handleGdbCommand("-signal-list-names");
}

void SeerGdbWidget::handleGdbSignalListValues (QString names) {

    if (executableLaunchMode() == "") {
        return;
    }

    handleGdbCommand("-signal-list-values " + names);
}

void SeerGdbWidget::handleGdbSignalSetValue (QString name, QString stop, QString print, QString pass) {

    if (executableLaunchMode() == "") {
        return;
    }

    // Set the signal value.
    handleGdbCommand("-signal-set-value " + name + " " + stop + " " + print + " " + pass);

    // Refresh whoever is listening.
    handleGdbSignalListValues("");
}

void SeerGdbWidget::handleGdbDataEvaluateExpression (int expressionid, QString expression) {

    if (executableLaunchMode() == "") {
        return;
    }

    // Check if there's a ObjectiveC pretext.
    QString token("(objc)");

    if (expression.startsWith(token)) {
        handleGdbCommand(QString::number(expressionid) + "-objc-evaluate-expression \"" + expression.mid(token.length()) + "\"");

    // Otherwise handle normally.
    }else{
        handleGdbCommand(QString::number(expressionid) + "-data-evaluate-expression \"" + expression + "\"");
    }
}

void SeerGdbWidget::handleGdbVarObjCreate (int expressionid, QString expression) {

    if (executableLaunchMode() == "") {
        return;
    }

    QString str = QString("%1-var-create seer%1 \"*\" \"%2\"").arg(expressionid).arg(expression);

    handleGdbCommand(str);
}

void SeerGdbWidget::handleGdbVarObjListChildren (int expressionid, QString objname) {

    if (executableLaunchMode() == "") {
        return;
    }

    QString str = QString("%1-var-list-children --all-values \"%2\"").arg(expressionid).arg(objname);

    handleGdbCommand(str);
}

void SeerGdbWidget::handleGdbVarObjUpdate (int expressionid, QString objname) {

    if (executableLaunchMode() == "") {
        return;
    }

    QString str = QString("%1-var-update --all-values \"%2\"").arg(expressionid).arg(objname);

    handleGdbCommand(str);
}

void SeerGdbWidget::handleGdbVarObjAssign (int expressionid, QString objname, QString value) {

    if (executableLaunchMode() == "") {
        return;
    }

    QString str = QString("%1-var-assign \"%2\" %3").arg(expressionid).arg(objname).arg(value);

    handleGdbCommand(str);
}

void SeerGdbWidget::handleGdbVarObjDelete (int expressionid, QString objname) {

    if (executableLaunchMode() == "") {
        return;
    }

    QString str = QString("%1-var-delete \"%2\"").arg(expressionid).arg(objname);

    handleGdbCommand(str);
}

void SeerGdbWidget::handleGdbVarObjAttributes (int objid, QString objname) {

    if (executableLaunchMode() == "") {
        return;
    }

    QString str = QString("%1-var-show-attributes \"%2\"").arg(objid).arg(objname);

    handleGdbCommand(str);
}

void SeerGdbWidget::handleGdbDataListValues () {

    if (executableLaunchMode() == "") {
        return;
    }

    for (int i=0; i<_dataExpressionId.size(); i++) {
        handleGdbDataEvaluateExpression(_dataExpressionId[i], _dataExpressionName[i]);
    }
}

void SeerGdbWidget::handleGdbDataListExpressions () {

    if (executableLaunchMode() == "") {
        return;
    }

    // ^done,DataExpressionTable={
    //     entry={id="2",expression="a"},
    //     entry={id="3",expression="i"}
    // }

    QString text;
    text += "^done,DataExpressionTable={";

    for (int i=0; i<_dataExpressionId.size(); i++) {
        if (i != 0) {
            text += ",";
        }
        text += "entry={id=\"" + QString::number(_dataExpressionId[i]) + "\",expression=\"" + _dataExpressionName[i] + "\"}";
    }

    text += "}";

    gdbMonitor()->handleTextOutput(text);
}

void SeerGdbWidget::handleGdbDataAddExpression (QString expression) {

    if (executableLaunchMode() == "") {
        return;
    }

    // Is this one already present?
    // ??? Emit an error?
    if (_dataExpressionName.indexOf(expression) >= 0) {
        return;
    }

    // Add it to our list of variables.
    _dataExpressionName.push_back(expression);
    _dataExpressionId.push_back(Seer::createID());

    // ^done,DataExpressionAdded={
    //     id="2",
    //     expression="a"
    // }

    QString text = QString("^done,DataExpressionAdded={id=\"%1\",expression=\"%2\"}").arg(_dataExpressionId.back()).arg(_dataExpressionName.back());

    //qDebug() << text;

    gdbMonitor()->handleTextOutput(text);
}

void SeerGdbWidget::handleGdbDataDeleteExpressions (QString expressionids) {

    if (executableLaunchMode() == "") {

        // Clear expression list.
        _dataExpressionId.clear();
        _dataExpressionName.clear();

        return;
    }

    // ^done,DataExpressionDeleted={
    //     entry={id="2", expression="a"},
    //     entry={id="3", expression="a"}
    // }

    QString text;
    text += "^done,DataExpressionDeleted={";

    if (expressionids == "*") {

        bool first = true;
        for (int i=0; i<_dataExpressionId.size(); i++) {

            if (first == false) {
                text += ",";
            }

            text += "entry={id=\"" + QString::number(_dataExpressionId[i]) + "\",expression=\"" + _dataExpressionName[i] + "\"}";
            first = false;
        }

        _dataExpressionId.clear();
        _dataExpressionName.clear();

    }else{

        QStringList ids = expressionids.split(' ', Qt::SkipEmptyParts);

        bool first = true;
        for (int i=0; i<ids.size(); i++) {

            if (ids[i] == "") {
                continue;
            }

            int index = _dataExpressionId.indexOf(ids[i].toInt());

            if (index < 0) {
                continue;
            }

            if (first == false) {
                text += ",";
            }

            text += "entry={id=\"" + QString::number(_dataExpressionId[index]) + "\",expression=\"" + _dataExpressionName[index] + "\"}";
            first = false;

            _dataExpressionId.remove(index);
            _dataExpressionName.remove(index);
        }
    }

    text += "}";

    gdbMonitor()->handleTextOutput(text);
}

void SeerGdbWidget::handleGdbMemoryAddExpression (QString expression) {

    if (executableLaunchMode() == "") {
        return;
    }

    SeerMemoryVisualizerWidget* w = new SeerMemoryVisualizerWidget(0);
    w->show();

    // Connect things.
    QObject::connect(_gdbMonitor,  &GdbMonitor::astrixTextOutput,                           w,    &SeerMemoryVisualizerWidget::handleText);
    QObject::connect(_gdbMonitor,  &GdbMonitor::caretTextOutput,                            w,    &SeerMemoryVisualizerWidget::handleText);
    QObject::connect(w,            &SeerMemoryVisualizerWidget::evaluateVariableExpression, this, &SeerGdbWidget::handleGdbDataEvaluateExpression);
    QObject::connect(w,            &SeerMemoryVisualizerWidget::evaluateMemoryExpression,   this, QOverload<int,QString,int>::of(&SeerGdbWidget::handleGdbMemoryEvaluateExpression));
    QObject::connect(w,            &SeerMemoryVisualizerWidget::evaluateAsmExpression,      this, &SeerGdbWidget::handleGdbAsmEvaluateExpression);

    // Tell the visualizer what variable to use.
    w->setVariableName(expression);
}

void SeerGdbWidget::handleGdbArrayAddExpression (QString expression) {

    if (executableLaunchMode() == "") {
        return;
    }

    SeerArrayVisualizerWidget* w = new SeerArrayVisualizerWidget(0);
    w->show();

    // Connect things.
    QObject::connect(_gdbMonitor,  &GdbMonitor::astrixTextOutput,                           w,    &SeerArrayVisualizerWidget::handleText);
    QObject::connect(_gdbMonitor,  &GdbMonitor::caretTextOutput,                            w,    &SeerArrayVisualizerWidget::handleText);
    QObject::connect(w,            &SeerArrayVisualizerWidget::evaluateVariableExpression,  this, &SeerGdbWidget::handleGdbDataEvaluateExpression);
    QObject::connect(w,            &SeerArrayVisualizerWidget::evaluateMemoryExpression,    this, &SeerGdbWidget::handleGdbArrayEvaluateExpression);

    // Tell the visualizer what variable to use.
    w->setAVariableName(expression);
}

void SeerGdbWidget::handleGdbMatrixAddExpression (QString expression) {

    if (executableLaunchMode() == "") {
        return;
    }

    SeerMatrixVisualizerWidget* w = new SeerMatrixVisualizerWidget(0);
    w->show();

    // Connect things.
    QObject::connect(_gdbMonitor,  &GdbMonitor::astrixTextOutput,                            w,    &SeerMatrixVisualizerWidget::handleText);
    QObject::connect(_gdbMonitor,  &GdbMonitor::caretTextOutput,                             w,    &SeerMatrixVisualizerWidget::handleText);
    QObject::connect(w,            &SeerMatrixVisualizerWidget::evaluateVariableExpression,  this, &SeerGdbWidget::handleGdbDataEvaluateExpression);
    QObject::connect(w,            &SeerMatrixVisualizerWidget::evaluateMemoryExpression,    this, &SeerGdbWidget::handleGdbArrayEvaluateExpression);

    // Tell the visualizer what variable to use.
    w->setVariableName(expression);
}

void SeerGdbWidget::handleGdbStructAddExpression (QString expression) {

    if (executableLaunchMode() == "") {
        return;
    }

    SeerStructVisualizerWidget* w = new SeerStructVisualizerWidget(0);
    w->show();

    // Connect things.
    QObject::connect(_gdbMonitor,  &GdbMonitor::astrixTextOutput,                            w,    &SeerStructVisualizerWidget::handleText);
    QObject::connect(_gdbMonitor,  &GdbMonitor::caretTextOutput,                             w,    &SeerStructVisualizerWidget::handleText);
    QObject::connect(w,            &SeerStructVisualizerWidget::evaluateVariableExpression,  this, &SeerGdbWidget::handleGdbDataEvaluateExpression);
    QObject::connect(w,            &SeerStructVisualizerWidget::addMemoryVisualizer,         this, &SeerGdbWidget::handleGdbMemoryAddExpression);
    QObject::connect(w,            &SeerStructVisualizerWidget::addArrayVisualizer,          this, &SeerGdbWidget::handleGdbArrayAddExpression);
    QObject::connect(w,            &SeerStructVisualizerWidget::addMatrixVisualizer,         this, &SeerGdbWidget::handleGdbMatrixAddExpression);
    QObject::connect(w,            &SeerStructVisualizerWidget::addStructVisualizer,         this, &SeerGdbWidget::handleGdbStructAddExpression);

    // Tell the visualizer what variable to use.
    w->setVariableName(expression);
}

void SeerGdbWidget::handleGdbVarAddExpression (QString expression) {

    if (executableLaunchMode() == "") {
        return;
    }

    SeerVarVisualizerWidget* w = new SeerVarVisualizerWidget(0);
    w->show();

    // Connect things.
    QObject::connect(_gdbMonitor,  &GdbMonitor::astrixTextOutput,                            w,    &SeerVarVisualizerWidget::handleText);
    QObject::connect(_gdbMonitor,  &GdbMonitor::caretTextOutput,                             w,    &SeerVarVisualizerWidget::handleText);
    QObject::connect(w,            &SeerVarVisualizerWidget::varObjCreate,                   this, &SeerGdbWidget::handleGdbVarObjCreate);
    QObject::connect(w,            &SeerVarVisualizerWidget::varObjListChildren,             this, &SeerGdbWidget::handleGdbVarObjListChildren);
    QObject::connect(w,            &SeerVarVisualizerWidget::varObjUpdate,                   this, &SeerGdbWidget::handleGdbVarObjUpdate);
    QObject::connect(w,            &SeerVarVisualizerWidget::varObjAssign,                   this, &SeerGdbWidget::handleGdbVarObjAssign);
    QObject::connect(w,            &SeerVarVisualizerWidget::varObjDelete,                   this, &SeerGdbWidget::handleGdbVarObjDelete);
    QObject::connect(w,            &SeerVarVisualizerWidget::varObjAttributes,               this, &SeerGdbWidget::handleGdbVarObjAttributes);
    QObject::connect(w,            &SeerVarVisualizerWidget::addMemoryVisualizer,            this, &SeerGdbWidget::handleGdbMemoryAddExpression);
    QObject::connect(w,            &SeerVarVisualizerWidget::addArrayVisualizer,             this, &SeerGdbWidget::handleGdbArrayAddExpression);
    QObject::connect(w,            &SeerVarVisualizerWidget::addMatrixVisualizer,            this, &SeerGdbWidget::handleGdbMatrixAddExpression);
    QObject::connect(w,            &SeerVarVisualizerWidget::addVarVisualizer,               this, &SeerGdbWidget::handleGdbVarAddExpression);

    // Tell the visualizer what variable to use.
    w->setVariableName(expression);
}

void SeerGdbWidget::handleGdbImageAddExpression (QString expression) {

    if (executableLaunchMode() == "") {
        return;
    }

    SeerImageVisualizerWidget* w = new SeerImageVisualizerWidget(0);
    w->show();

    // Connect things.
    QObject::connect(_gdbMonitor,  &GdbMonitor::astrixTextOutput,                           w,    &SeerImageVisualizerWidget::handleText);
    QObject::connect(_gdbMonitor,  &GdbMonitor::caretTextOutput,                            w,    &SeerImageVisualizerWidget::handleText);
    QObject::connect(w,            &SeerImageVisualizerWidget::evaluateVariableExpression,  this, &SeerGdbWidget::handleGdbDataEvaluateExpression);
    QObject::connect(w,            &SeerImageVisualizerWidget::evaluateMemoryExpression,    this, QOverload<int,QString,int>::of(&SeerGdbWidget::handleGdbMemoryEvaluateExpression));

    // Tell the visualizer what variable to use.
    w->setVariableName(expression);
}

void SeerGdbWidget::handleGdbMemoryEvaluateExpression (int expressionid, QString address, int count) {

    if (executableLaunchMode() == "") {
        return;
    }

    handleGdbCommand(QString::number(expressionid) + "-data-read-memory-bytes " + address + " " + QString::number(count));
}

void SeerGdbWidget::handleGdbMemoryEvaluateExpression (int expressionid, QString address, int offset, int count) {

    if (executableLaunchMode() == "") {
        return;
    }

    handleGdbCommand(QString::number(expressionid) + "-data-read-memory-bytes -o " + QString::number(offset) + " " + address + " " + QString::number(count));
}

void SeerGdbWidget::handleGdbAsmEvaluateExpression (int expressionid, QString address, int count, int mode) {

    // -data-disassemble -s $pc -e "$pc + 96" -- 2

    if (executableLaunchMode() == "") {
        return;
    }

    handleGdbCommand(QString("%1-data-disassemble -s \"%2 - %3\" -e \"%4 + %5\" -- %6").arg(expressionid).arg(address).arg(0).arg(address).arg(count).arg(mode));
}

void SeerGdbWidget::handleGdbArrayEvaluateExpression (int expressionid, QString address, int count) {

    if (executableLaunchMode() == "") {
        return;
    }

    handleGdbCommand(QString::number(expressionid) + "-data-read-memory-bytes " + address + " " + QString::number(count));
}

void SeerGdbWidget::handleGdbGetAssembly (QString address) {

    if (executableLaunchMode() == "") {
        return;
    }

    //qDebug() << "Getting assembly for address" << address << "for mode" << assemblyDisassemblyMode();

    QString command;

    if (assemblyDisassemblyMode() == "length") {
        command = QString("-data-disassemble -s \"%1\" -e \"%1 + %2\" -- 2").arg(address).arg(assemblyDisassemblyBytes());
    }else if (assemblyDisassemblyMode() == "function") {
        command = QString("-data-disassemble -a \"%1\" -- 2").arg(address);
    }else{
        command = QString("-data-disassemble -a \"%1\" -- 2").arg(address);
    }

    //qDebug() << command;

    handleGdbCommand(command);
}

void SeerGdbWidget::handleGdbGetSourceAndAssembly (QString address) {

    if (executableLaunchMode() == "") {
        return;
    }

    //qDebug() << "Getting source and assembly for address" << address << "for mode" << assemblyDisassemblyMode();

    QString command;

    if (assemblyDisassemblyMode() == "length") {
        command = QString("-data-disassemble -s \"%1\" -e \"%1 + %2\" -- 5").arg(address).arg(assemblyDisassemblyBytes());
    }else if (assemblyDisassemblyMode() == "function") {
        command = QString("-data-disassemble -a \"%1\" -- 5").arg(address);
    }else{
        command = QString("-data-disassemble -a \"%1\" -- 5").arg(address);
    }

    //qDebug() << command;

    handleGdbCommand(command);
}

void SeerGdbWidget::handleGdbMemoryVisualizer () {

    handleGdbMemoryAddExpression("");
}

void SeerGdbWidget::handleGdbArrayVisualizer () {

    handleGdbArrayAddExpression("");
}

void SeerGdbWidget::handleGdbMatrixVisualizer () {

    handleGdbMatrixAddExpression("");
}

void SeerGdbWidget::handleGdbStructVisualizer () {

    handleGdbStructAddExpression("");
}

void SeerGdbWidget::handleGdbVarVisualizer () {

    handleGdbVarAddExpression("");
}

void SeerGdbWidget::handleGdbImageVisualizer () {

    handleGdbImageAddExpression("");
}

void SeerGdbWidget::handleGdbMonitor () {

    if (executableLaunchMode() == "") {
        return;
    }

    SeerGdbMonitorWidget* w = new SeerGdbMonitorWidget(0);
    w->show();

    // Connect things.
    QObject::connect(_gdbMonitor,  &GdbMonitor::astrixTextOutput,                        w,      &SeerGdbMonitorWidget::handleText);
    QObject::connect(_gdbMonitor,  &GdbMonitor::caretTextOutput,                         w,      &SeerGdbMonitorWidget::handleText);
    QObject::connect(w,            &SeerGdbMonitorWidget::executeGdbMonitorCommand,      this,   &SeerGdbWidget::handleGdbMonitorCommand);
}

void SeerGdbWidget::handleSplitterMoved (int pos, int index) {

    Q_UNUSED(pos);
    Q_UNUSED(index);

    //qDebug() << "Splitter moved to " << pos << index;

    writeSettings();
}

void SeerGdbWidget::handleGdbAssemblyDisassemblyFlavor () {

    if (_assemblyDisassemblyFlavor != "") {
        handleGdbCommand(QString("-gdb-set disassembly-flavor ") + _assemblyDisassemblyFlavor);
    }
}

void SeerGdbWidget::handleGdbAssemblySymbolDemangling () {

    if (_assemblySymbolDemangling != "") {
        handleGdbCommand(QString("-gdb-set print asm-demangle ") + _assemblySymbolDemangling);
    }
}

void SeerGdbWidget::handleGdbProcessFinished (int exitCode, QProcess::ExitStatus exitStatus) {

    //qDebug() << "Gdb process finished. Exit code =" << exitCode << "Exit status =" << exitStatus;

    // Warn if gdb exits only if we are in some kind of run mode.
    if (executableLaunchMode() != "") {

        QMessageBox::warning(this, "Seer",
                QString("The GDB program exited unexpectedly.\n\n") +
                QString("Exit code=%1 Exit status=%2").arg(exitCode).arg(exitStatus) + "\n\n" +
                QString("'%1 %2'").arg(_gdbProcess->program()).arg(_gdbProcess->arguments().join(' ')) + "\n\n" +
                QString("Please restart Seer."),
                QMessageBox::Ok);
    }
}

void SeerGdbWidget::handleGdbProcessErrored (QProcess::ProcessError errorStatus) {

    //qDebug() << "Error launching gdb process. Error =" << errorStatus;

    if (errorStatus == QProcess::FailedToStart) {
        QMessageBox::warning(this, "Seer",
                                   QString("Unable to launch the GDB program.\n\n") +
                                   QString("'%1 %2'").arg(_gdbProcess->program()).arg(_gdbProcess->arguments().join(' ')) + "\n\n" +
                                   QString("Error status=%1").arg(errorStatus),
                                   QMessageBox::Ok);
    }
}

void SeerGdbWidget::handleAboutToQuit () {

    // Detect if we're exiting Seer.
    setIsQuitting(true);
}

void SeerGdbWidget::writeSettings () {

    //qDebug() << "Write Settings";

    QSettings settings;

    settings.beginGroup("mainwindowsplitters"); {
        settings.setValue("leftCenterRightSplitter",              leftCenterRightSplitter->saveState());
        settings.setValue("sourceCommandLogsSplitter",            sourceCommandLogsSplitter->saveState());
        settings.setValue("sourceLibraryVariableManagerSplitter", sourceLibraryVariableManagerSplitter->saveState());
        settings.setValue("stackThreadManagerSplitter",           stackThreadManagerSplitter->saveState());
    } settings.endGroup();

    settings.beginGroup("consolewindow"); {
        settings.setValue("mode", consoleMode());
        settings.setValue("scrolllines", consoleScrollLines());
    }settings.endGroup();

    settings.beginWriteArray("sourcealternatedirectories"); {
        QStringList directories = sourceAlternateDirectories();

        for (int i = 0; i < directories.size(); ++i) {
            settings.setArrayIndex(i);
            settings.setValue("directory", directories[i]);
        }
    } settings.endArray();

    settings.beginWriteArray("sourceignorefilepatters"); {
        QStringList patterns = sourceIgnoreFilePatterns();

        for (int i = 0; i < patterns.size(); ++i) {
            settings.setArrayIndex(i);
            settings.setValue("pattern", patterns[i]);
        }
    } settings.endArray();

    settings.beginWriteArray("sourcemiscfilepatterns"); {
        QStringList patterns = sourceMiscFilePatterns();

        for (int i = 0; i < patterns.size(); ++i) {
            settings.setArrayIndex(i);
            settings.setValue("pattern", patterns[i]);
        }
    } settings.endArray();

    settings.beginWriteArray("sourcesourcefilepatterns"); {
        QStringList patterns = sourceSourceFilePatterns();

        for (int i = 0; i < patterns.size(); ++i) {
            settings.setArrayIndex(i);
            settings.setValue("pattern", patterns[i]);
        }
    } settings.endArray();

    settings.beginWriteArray("sourceheaderfilepatterns"); {
        QStringList patterns = sourceHeaderFilePatterns();

        for (int i = 0; i < patterns.size(); ++i) {
            settings.setArrayIndex(i);
            settings.setValue("pattern", patterns[i]);
        }
    } settings.endArray();

    settings.beginGroup("assembly"); {
        settings.setValue("showassemblytabonstartupmode",    assemblyShowAssemblyTabOnStartupMode());
        settings.setValue("keepassemblytabontop",            assemblyKeepAssemblyTabOnTop());
        settings.setValue("assemblydisassemblyflavor",       assemblyDisassemblyFlavor());
        settings.setValue("assemblysymboldemagling",         assemblySymbolDemagling());
        settings.setValue("assemblyregisterformat",          assemblyRegisterFormat());
        settings.setValue("assemblyshowaddresscolumn",       assemblyShowAddressColumn());
        settings.setValue("assemblyshowoffsetcolumn",        assemblyShowOffsetColumn());
        settings.setValue("assemblyshowopcodecolumn",        assemblyShowOpcodeColumn());
        settings.setValue("assemblyshowsourcelines",         assemblyShowSourceLines());
        settings.setValue("assemblydisassemblymode",         assemblyDisassemblyMode());
        settings.setValue("assemblydisassemblybytes",        assemblyDisassemblyBytes());
    } settings.endGroup();
}

void SeerGdbWidget::readSettings () {

    QSettings settings;
    int       size;

    settings.beginGroup("mainwindowsplitters"); {
        leftCenterRightSplitter->restoreState(settings.value("leftCenterRightSplitter").toByteArray());
        sourceCommandLogsSplitter->restoreState(settings.value("sourceCommandLogsSplitter").toByteArray());
        sourceLibraryVariableManagerSplitter->restoreState(settings.value("sourceLibraryVariableManagerSplitter").toByteArray());
        stackThreadManagerSplitter->restoreState(settings.value("stackThreadManagerSplitter").toByteArray());
    } settings.endGroup();

    settings.beginGroup("consolewindow"); {
        setConsoleMode(settings.value("mode", "attached").toString());
        setConsoleScrollLines(settings.value("scrolllines", 1000).toInt());
    } settings.endGroup();

    size = settings.beginReadArray("sourcealternatedirectories"); {
        QStringList directories;

        for (int i = 0; i < size; ++i) {
            settings.setArrayIndex(i);

            directories << settings.value("directory").toString();
        }

        setSourceAlternateDirectories(directories);
    } settings.endArray();

    size = settings.beginReadArray("sourceignorefilepatters"); {
        QStringList patterns;

        for (int i = 0; i < size; ++i) {
            settings.setArrayIndex(i);

            patterns << settings.value("pattern").toString();
        }

        setSourceIgnoreFilePatterns(patterns);
    } settings.endArray();

    if (settings.childGroups().contains("sourcemiscfilepatterns")) {
        size = settings.beginReadArray("sourcemiscfilepatterns"); {
            QStringList patterns;

            for (int i = 0; i < size; ++i) {
                settings.setArrayIndex(i);

                patterns << settings.value("pattern").toString();
            }

            setSourceMiscFilePatterns(patterns);
        } settings.endArray();
    }

    if (settings.childGroups().contains("sourcesourcefilepatterns")) {
        size = settings.beginReadArray("sourcesourcefilepatterns"); {
            QStringList patterns;

            for (int i = 0; i < size; ++i) {
                settings.setArrayIndex(i);

                patterns << settings.value("pattern").toString();
            }

            setSourceSourceFilePatterns(patterns);
        } settings.endArray();
    }

    if (settings.childGroups().contains("sourceheaderfilepatterns")) {
        size = settings.beginReadArray("sourceheaderfilepatterns"); {
            QStringList patterns;

            for (int i = 0; i < size; ++i) {
                settings.setArrayIndex(i);

                patterns << settings.value("pattern").toString();
            }

            setSourceHeaderFilePatterns(patterns);
        } settings.endArray();
    }

    settings.beginGroup("assembly"); {
        setAssemblyShowAssemblyTabOnStartupMode( settings.value("showassemblytabonstartupmode",  "never").toString());
        setAssemblyKeepAssemblyTabOnTop(         settings.value("keepassemblytabontop",          true).toBool());
        setAssemblyDisassemblyFlavor(            settings.value("assemblydisassemblyflavor",     "att").toString());
        setAssemblySymbolDemagling(              settings.value("assemblysymboldemagling",       "on").toString());
        setAssemblyRegisterFormat(               settings.value("assemblyregisterformat",        "Natural").toString());
        setAssemblyShowAddressColumn(            settings.value("assemblyshowaddresscolumn",     true).toBool());
        setAssemblyShowOffsetColumn(             settings.value("assemblyshowoffsetcolumn",      false).toBool());
        setAssemblyShowOpcodeColumn(             settings.value("assemblyshowopcodecolumn",      false).toBool());
        setAssemblyShowSourceLines(              settings.value("assemblyshowsourcelines",       false).toBool());
        setAssemblyDisassemblyMode(              settings.value("assemblydisassemblymode",       "function").toString(),    settings.value("assemblydisassemblybytes", "256").toInt());
    } settings.endGroup();
}

bool SeerGdbWidget::isQuitting () const {
    return _isQuitting;
}

void SeerGdbWidget::setIsQuitting (bool f) {
    _isQuitting = f;
}

bool SeerGdbWidget::isGdbRuning () const {

    if (_gdbProcess->state() == QProcess::NotRunning) {
        return false;
    }

    return true;
}

bool SeerGdbWidget::startGdb () {

    // Don't do anything, if already running.
    if (isGdbRuning()) {
        qWarning() << "Already running";
        return false;
    }

    // Build the raw command to launch the gdb program.
    // Later the raw command will be broken into individual strings (via ' ')
    // that the QProcess object expects.
    QString rawcommand;

    // Is a 'launcher' being used? Like 'flatpak-spawn'.
    if (gdbLauncher() != "") {
        rawcommand += gdbLauncher() + " ";
    }

    // Set the gdb program name to use.
    if (gdbProgramOverride() != "") {
        rawcommand += gdbProgramOverride() + " ";
    }else{
        rawcommand += gdbProgram() + " ";
    }

    // Build the gdb argument list.
    if (gdbArgumentsOverride() != "") {
        rawcommand += gdbArgumentsOverride() + " ";
    }else{
        rawcommand += gdbArguments() + " ";
    }

    // Now expand any $VAR environment variables.
    bool ok;
    QString expandedcommand = Seer::expandEnv(rawcommand, &ok);

    //qDebug() << "Raw command     : " << rawcommand;
    //qDebug() << "Expanded command: " << expandedcommand;

    if (ok == false) {
        QMessageBox::critical(this, "Error", QString("Can't resolve all environment variables in command to launch gdb:\n'%1'").arg(rawcommand));
        return false;
    }

    // Split string into words, handling "double quoted" words.
    QStringList args = Seer::split(expandedcommand);

    // Extract the program name and create a list of arguments.
    QString program = args.front();
    args.pop_front();

    // Give the gdb process the program and the argument list.
    _gdbProcess->setProgram(program);
    _gdbProcess->setArguments(args);

    // We need to set the C language, otherwise the MI interface is translated and our message
    // filters will not work.
    QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
    env.insert("LANG", "C");
    _gdbProcess->setProcessEnvironment(env);

    // Start the gdb process.
    _gdbProcess->start();

    //qDebug() << _gdbProcess->state();

    return true;
}

bool SeerGdbWidget::startGdbRR () {

    // Don't do anything, if already running.
    if (isGdbRuning()) {
        qWarning() << "Already running";
        return false;
    }

    // Does the RR trace directory exist?
    if (QFile::exists(executableRRTraceDirectory()) == false) {
        QMessageBox::critical(this, "Seer",
                                    QString("The RR trace-directory '" + executableRRTraceDirectory() + "' doesn't exist."),
                                    QMessageBox::Ok);
        return false;
    }

    // Build the raw command to launch the RR program.
    // Later the raw command will be broken into individual strings (via ' ')
    // that the QProcess object expects.
    QString rawcommand;

    // Is a 'launcher' being used? Like 'flatpak-spawn'.
    if (gdbLauncher() != "") {
        rawcommand += gdbLauncher() + " ";
    }

    // Set the RR program name to use.
    rawcommand += rrProgram() + " ";
    rawcommand += rrArguments() + " --tty " + commandLogsWidget->console()->terminalDeviceName() + " " + executableRRTraceDirectory() + " ";

    // Set any extra gdb arguments that RR may want.
    if (rrGdbArguments() != "") {
        rawcommand += "-- " + rrGdbArguments() + " ";
    }

    // Now expand any $VAR environment variables.
    bool ok;
    QString expandedcommand = Seer::expandEnv(rawcommand, &ok);

    //qDebug() << "Raw command     : " << rawcommand;
    //qDebug() << "Expanded command: " << expandedcommand;

    if (ok == false) {
        QMessageBox::critical(this, "Error", QString("Can't resolve all environment variables in command to launch RR:\n'%1'").arg(rawcommand));
        return false;
    }

    // Split string into words, handling "double quoted" words.
    QStringList args = Seer::split(expandedcommand);

    // Extract the program name and create a list of arguments.
    QString program = args.front();
    args.pop_front();

    // Give the gdb process the program and the argument list.
    _gdbProcess->setProgram(program);
    _gdbProcess->setArguments(args);

    // We need to set the C language, otherwise the MI interface is translated and our message
    // filters will not work.
    QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
    env.insert("LANG", "C");
    _gdbProcess->setProcessEnvironment(env);

    // Start the gdb process.
    _gdbProcess->start();

    //qDebug() << _gdbProcess->state();

    return true;
}

void SeerGdbWidget::killGdb () {

    // Don't do anything, if isn't running.
    if (isGdbRuning() == false) {
        return;
    }

    // Clear the launch mode.
    setExecutableLaunchMode("");
    setGdbRecordMode("");

    // Kill the process.
    _gdbProcess->kill();

    // Wait for it to end.
    _gdbProcess->waitForFinished();

    // Sanity check.
    if (isGdbRuning()) {
        qWarning() << "Is running but shouldn't be.";
    }
}

SeerConsoleWidget* SeerGdbWidget::console () {

    return commandLogsWidget->console();
}

void SeerGdbWidget::setConsoleMode (const QString& mode) {

    commandLogsWidget->setConsoleMode(mode);
}

QString SeerGdbWidget::consoleMode () const {

    return commandLogsWidget->consoleMode();
}

void SeerGdbWidget::setConsoleScrollLines (int count) {

    commandLogsWidget->setConsoleScrollLines(count);
}

int SeerGdbWidget::consoleScrollLines () const {

    return commandLogsWidget->consoleScrollLines();
}

void SeerGdbWidget::setRememberManualCommandCount (int count) {

    commandLogsWidget->setRememberManualCommandCount(count);
}

int SeerGdbWidget::rememberManualCommandCount () const {

    return commandLogsWidget->rememberManualCommandCount();
}

void SeerGdbWidget::clearManualCommandHistory () {

    commandLogsWidget->clearManualCommandHistory();
}

const QStringList& SeerGdbWidget::sourceAlternateDirectories() const {

    return editorManager()->editorAlternateDirectories();
}

void SeerGdbWidget::setSourceAlternateDirectories (const QStringList& alternateDirectories) {

    editorManager()->setEditorAlternateDirectories(alternateDirectories);
}

void SeerGdbWidget::setSourceMiscFilePatterns (const QStringList& filePatterns) {

    sourceLibraryManagerWidget->sourceBrowserWidget()->setMiscFilePatterns(filePatterns);
}

const QStringList& SeerGdbWidget::sourceMiscFilePatterns () const {

    return sourceLibraryManagerWidget->sourceBrowserWidget()->miscFilePatterns();
}

void SeerGdbWidget::setSourceSourceFilePatterns (const QStringList& filePatterns) {

    sourceLibraryManagerWidget->sourceBrowserWidget()->setSourceFilePatterns(filePatterns);
}

const QStringList& SeerGdbWidget::sourceSourceFilePatterns () const {

    return sourceLibraryManagerWidget->sourceBrowserWidget()->sourceFilePatterns();
}

void SeerGdbWidget::setSourceHeaderFilePatterns (const QStringList& filePatterns) {

    sourceLibraryManagerWidget->sourceBrowserWidget()->setHeaderFilePatterns(filePatterns);
}

const QStringList& SeerGdbWidget::sourceHeaderFilePatterns () const {

    return sourceLibraryManagerWidget->sourceBrowserWidget()->headerFilePatterns();
}

void SeerGdbWidget::setSourceIgnoreFilePatterns (const QStringList& filePatterns) {

    _ignoreFilePatterns = filePatterns;

    sourceLibraryManagerWidget->sourceBrowserWidget()->setIgnoreFilePatterns(sourceIgnoreFilePatterns());
    editorManager()->setEditorIgnoreDirectories(sourceIgnoreFilePatterns());
}

const QStringList& SeerGdbWidget::sourceIgnoreFilePatterns () const {

    return _ignoreFilePatterns;
}

void SeerGdbWidget::setAssemblyShowAssemblyTabOnStartupMode (const QString& mode) {

    editorManager()->setShowAssemblyTabOnStartupMode(mode);
}

QString SeerGdbWidget::assemblyShowAssemblyTabOnStartupMode () const {

    return editorManager()->showAssemblyTabOnStartupMode();
}

void SeerGdbWidget::setAssemblyKeepAssemblyTabOnTop (bool flag) {

    editorManager()->setKeepAssemblyTabOnTop(flag);
}

bool SeerGdbWidget::assemblyKeepAssemblyTabOnTop () const {

    return editorManager()->keepAssemblyTabOnTop();
}

void SeerGdbWidget::setAssemblyDisassemblyFlavor (const QString& flavor) {

    _assemblyDisassemblyFlavor = flavor;

    if (isGdbRuning()) {
        handleGdbAssemblyDisassemblyFlavor();

        emit assemblyConfigChanged();
    }
}

QString SeerGdbWidget::assemblyDisassemblyFlavor () const {

    return _assemblyDisassemblyFlavor;
}

void SeerGdbWidget::setAssemblySymbolDemagling (const QString& onoff) {

    _assemblySymbolDemangling = onoff;

    if (isGdbRuning()) {
        handleGdbAssemblySymbolDemangling();

        emit assemblyConfigChanged();
    }
}

void SeerGdbWidget::handleGdbSchedulerLockingMode (QString mode) {

    if (executableLaunchMode() == "") {
        return;
    }

    handleGdbCommand(QString("-gdb-set scheduler-locking %1").arg(mode));
}

void SeerGdbWidget::handleGdbScheduleMultipleMode (QString mode) {

    if (executableLaunchMode() == "") {
        return;
    }

    handleGdbCommand(QString("-gdb-set schedule-multiple %1").arg(mode));
}

void SeerGdbWidget::handleGdbForkFollowMode (QString mode) {

    if (executableLaunchMode() == "") {
        return;
    }

    if (mode == "parent") {
        handleGdbCommand("-gdb-set follow-fork-mode parent");
        handleGdbCommand("-gdb-set detach-on-fork   on");
    }else if (mode == "child") {
        handleGdbCommand("-gdb-set follow-fork-mode child");
        handleGdbCommand("-gdb-set detach-on-fork   on");
    }else if (mode == "both") {
        handleGdbCommand("-gdb-set follow-fork-mode parent");
        handleGdbCommand("-gdb-set detach-on-fork   off");
    }else{
        qWarning() << "Invalid 'ForkFollowMode' of '" << mode << "'";
    }
}

void SeerGdbWidget::handleGdbLoadMICommands () {

    // Don't do anything, if isn't running.
    if (isGdbRuning() == false) {
        return;
    }

    // Path the MI files in the resources.
    QString miPath = ":/seer/resources/mi-python/"; // Resource file path

    QDir miDirectory(miPath);

    if (!miDirectory.exists()) {
        qDebug() << "Directory does not exist:" << miPath;
        return;
    }

    // Get list of MI files.
    QFileInfoList miList = miDirectory.entryInfoList(QDir::NoDotAndDotDot | QDir::AllEntries);

    // Print the list.
    qDebug() << "Sourcing scripts from:" << miPath;
    foreach (QFileInfo miInfo, miList) {

        // Open the source file from resources.
        QFile miFile(miInfo.absoluteFilePath());
        if (!miFile.exists()) {
            qDebug().nospace().noquote() << "Resource file '" << miInfo << "' does not exist!";
            continue;
        }

        // Destination file path in /tmp.
        QString destinationPath = "/tmp/" + miInfo.fileName();

        // Delete possible old temp version, if it exists.
        if (QFile::exists(destinationPath)) {
            bool f = QFile::remove(destinationPath);
            if (f == false) {
                qDebug().nospace().noquote() << "Old temp Resource file '" << destinationPath << "' can not be deleted!";
                continue;
            }
        }

        // Copy to temp.
        bool f = miFile.copy(destinationPath);
        if (f == false) {
            qDebug().nospace().noquote() << "Resource file '" << miInfo << "' can not be copied to '" << destinationPath << "'!";
            continue;
        }

        // Source it.
        if (QFile::exists(destinationPath) == false) {
            qDebug().nospace().noquote() << "Temp Resource file '" << destinationPath << "' does not exist!";
            continue;
        }

        qDebug() << "source " + miInfo.absoluteFilePath();

        QString command = "source " + destinationPath;

        handleGdbCommand(command);
    }
    qDebug() << "Done.";
}

void SeerGdbWidget::handleGdbSourceScripts () {

    // Don't do anything, if isn't running.
    if (isGdbRuning() == false) {
        return;
    }

    // Get setting's config path.
    QSettings settings;

    QString configFile = settings.fileName();

    if (configFile == "") {
        return;
    }

    QFileInfo configFileInfo(configFile);

    QString configDirectory = configFileInfo.absolutePath();

    // Get a list of files in the "scripts" folder.
    QString scriptsDirectory = configDirectory + "/scripts";

    QDir dir(scriptsDirectory);
    QStringList scripts = dir.entryList(QDir::Files, QDir::Name);

    // Source each one.
    qDebug() << "Sourcing scripts from:" << scriptsDirectory;
    for (const QString& script : scripts) {
        QString command = "source " + scriptsDirectory + "/" + script;

        qDebug() << command;

        handleGdbCommand(command);
    }
    qDebug() << "Done.";
}

void SeerGdbWidget::handleGdbLoadSkips () {

    // Don't do anything, if isn't running.
    if (isGdbRuning() == false) {
        return;
    }

    // Guard agains the remote possibility of no Skip browser
    if (sourceLibraryManagerWidget->skipBrowserWidget() == nullptr) {
        return;
    }

    sourceLibraryManagerWidget->skipBrowserWidget()->loadSkips();
}

void SeerGdbWidget::handleGdbSetArchitectureType () {

    if (gdbArchitectureType() != "") {
        handleGdbCommand(QString("set architecture ") + gdbArchitectureType());
    }
}

QString SeerGdbWidget::assemblySymbolDemagling () const {

    return _assemblySymbolDemangling;
}

void SeerGdbWidget::setAssemblyShowAddressColumn (bool flag) {

    editorManager()->setAssemblyShowAddressColumn(flag);
}

bool SeerGdbWidget::assemblyShowAddressColumn () const {

    return editorManager()->assemblyShowAddressColumn();
}

void SeerGdbWidget::setAssemblyShowOffsetColumn (bool flag) {

    editorManager()->setAssemblyShowOffsetColumn(flag);
}

bool SeerGdbWidget::assemblyShowOffsetColumn () const {

    return editorManager()->assemblyShowOffsetColumn();
}

void SeerGdbWidget::setAssemblyShowOpcodeColumn (bool flag) {

    editorManager()->setAssemblyShowOpcodeColumn(flag);
}

bool SeerGdbWidget::assemblyShowOpcodeColumn () const {

    return editorManager()->assemblyShowOpcodeColumn();
}

void SeerGdbWidget::setAssemblyShowSourceLines (bool flag) {

    editorManager()->setAssemblyShowSourceLines(flag);
}

bool SeerGdbWidget::assemblyShowSourceLines () const {

    return editorManager()->assemblyShowSourceLines();
}

void SeerGdbWidget::setAssemblyRegisterFormat (const QString& format) {

    _assemblyRegisterFormat = format;

    variableManagerWidget->registerValuesBrowserWidget()->setRegisterFormat(_assemblyRegisterFormat);
}

QString SeerGdbWidget::assemblyRegisterFormat () const {

    return _assemblyRegisterFormat;
}

void SeerGdbWidget::setAssemblyDisassemblyMode (const QString& mode, int bytes) {

    _assemblyDisassemblyMode  = mode;
    _assemblyDisassemblyBytes = bytes;
}

QString SeerGdbWidget::assemblyDisassemblyMode () const {

    return _assemblyDisassemblyMode;
}

int SeerGdbWidget::assemblyDisassemblyBytes () const {

    return _assemblyDisassemblyBytes;
}

void SeerGdbWidget::sendGdbInterrupt (int signal) {

    //qDebug() << "Sending an interrupt to the program. Signal =" << signal;

    if (executableLaunchMode() == "") {
        return;
    }

    if (executablePid() < 1) {
        QMessageBox::warning(this, "Seer",
                                   QString("No executable is running or I don't know the PID of the process."),
                                   QMessageBox::Ok);
        return;
    }

    // Use kill() to send the signal to the inferior.
    // -exec-interrupt does not work for -exec-until when the line
    // number is not in the current function. In this case, -exec-until
    // behaves like -exec-continue but -exec-interrupt has no effect. :^(
    // We do have the ability to use a different signal, though. :^)

    if (signal < 0) {
        handleGdbCommand("-exec-interrupt");

    }else{
        int stat = kill(executablePid(), signal);
        if (stat < 0) {
            QMessageBox::warning(this, "Seer",
                                       QString("Unable to send signal '%1' to pid %2.\nError = '%3'").arg(strsignal(signal)).arg(executablePid()).arg(strerror(errno)),
                                       QMessageBox::Ok);
        }
    }
}

// Deleay N seconds by executing Qt's even loop a bunch of times.
// This gives time for certain gdb commands to finish. Like saving the breakpoints before exit.
void SeerGdbWidget::delay (int seconds) {

    QTime dieTime = QTime::currentTime().addSecs(seconds);

    while (QTime::currentTime() < dieTime) {
        QCoreApplication::processEvents(QEventLoop::AllEvents, 100);
    }
}
