QT Debugger improvements [Andrew Gardner]

- Save and load window locations.
  - Preliminary work on "run and hide" and "hard reset" 
    (don't crash on one of my copmilers but do on another - more work to do!)
  - Fixed color when cursor is the same as PC in debug view.
  - Closing the main window now shuts down the machine (same as quit)
  - Help now wraps to the log window size.
This commit is contained in:
Andrew Gardner 2013-01-24 17:06:42 +00:00
parent 183b9f0638
commit ba61a286f3
10 changed files with 307 additions and 34 deletions

View File

@ -258,7 +258,7 @@ void debug_command_init(running_machine &machine)
}
/* add all the commands */
debug_console_register_command(machine, "help", CMDFLAG_NONE, 0, 0, 1, execute_help);
debug_console_register_command(machine, "help", CMDFLAG_NONE, 0, 0, 2, execute_help);
debug_console_register_command(machine, "print", CMDFLAG_NONE, 0, 1, MAX_COMMAND_PARAMS, execute_print);
debug_console_register_command(machine, "printf", CMDFLAG_NONE, 0, 1, MAX_COMMAND_PARAMS, execute_printf);
debug_console_register_command(machine, "logerror", CMDFLAG_NONE, 0, 1, MAX_COMMAND_PARAMS, execute_logerror);
@ -643,8 +643,14 @@ static void execute_help(running_machine &machine, int ref, int params, const ch
{
if (params == 0)
debug_console_printf_wrap(machine, 80, "%s\n", debug_get_help(""));
else
else if (params == 1)
debug_console_printf_wrap(machine, 80, "%s\n", debug_get_help(param[0]));
else if (params == 2)
{
UINT64 width;
debug_command_parameter_number(machine, param[1], &width);
debug_console_printf_wrap(machine, (int)width, "%s\n", debug_get_help(param[0]));
}
}

View File

@ -16,9 +16,13 @@
#include "emu.h"
#include "osdsdl.h"
#include "config.h"
#include "debugger.h"
#include "debugqtmainwindow.h"
#include "debugqtmemorywindow.h"
#include "debugqtdasmwindow.h"
#include "debugqtlogwindow.h"
//============================================================
@ -32,14 +36,184 @@ bool oneShot = true;
MainWindow* mainQtWindow = NULL;
//============================================================
// XML configuration save/load
//============================================================
// Global variable used to feed the xml configuration callbacks
std::vector<WindowQtConfig> xmlConfigurations;
static void xml_configuration_load(running_machine &machine, int config_type, xml_data_node *parentnode)
{
xml_data_node *wnode;
// We only care about game files
if (config_type != CONFIG_TYPE_GAME)
return;
// Might not have any data
if (parentnode == NULL)
return;
xmlConfigurations.clear();
// Configuration load
for (wnode = xml_get_sibling(parentnode->child, "window"); wnode != NULL; wnode = xml_get_sibling(wnode->next, "window"))
{
WindowQtConfig config;
config.m_size.setX(xml_get_attribute_int(wnode, "size_x", config.m_size.x()));
config.m_size.setY(xml_get_attribute_int(wnode, "size_y", config.m_size.y()));
config.m_position.setX(xml_get_attribute_int(wnode, "position_x", config.m_position.x()));
config.m_position.setY(xml_get_attribute_int(wnode, "position_y", config.m_position.y()));
config.m_type = (WindowQtConfig::WindowType)xml_get_attribute_int(wnode, "type", config.m_type);
xmlConfigurations.push_back(config);
}
}
static void xml_configuration_save(running_machine &machine, int config_type, xml_data_node *parentnode)
{
// We only care about game files
if (config_type != CONFIG_TYPE_GAME)
return;
for (int i = 0; i < xmlConfigurations.size(); i++)
{
// Create an xml node
xml_data_node *debugger_node;
debugger_node = xml_add_child(parentnode, "window", NULL);
if (debugger_node == NULL)
continue;
xml_set_attribute_int(debugger_node, "type", xmlConfigurations[i].m_type);
xml_set_attribute_int(debugger_node, "position_x", xmlConfigurations[i].m_position.x());
xml_set_attribute_int(debugger_node, "position_y", xmlConfigurations[i].m_position.y());
xml_set_attribute_int(debugger_node, "size_x", xmlConfigurations[i].m_size.x());
xml_set_attribute_int(debugger_node, "size_y", xmlConfigurations[i].m_size.y());
}
}
static void gather_save_configurations()
{
xmlConfigurations.clear();
// Loop over all the open windows
foreach (QWidget* widget, QApplication::topLevelWidgets())
{
if (!widget->isVisible())
continue;
if (!widget->isWindow() || widget->windowType() != Qt::Window)
continue;
// Figure out its type
WindowQtConfig::WindowType type = WindowQtConfig::WIN_TYPE_UNKNOWN;
if (dynamic_cast<MainWindow*>(widget))
type = WindowQtConfig::WIN_TYPE_MAIN;
else if (dynamic_cast<MemoryWindow*>(widget))
type = WindowQtConfig::WIN_TYPE_MEMORY;
else if (dynamic_cast<DasmWindow*>(widget))
type = WindowQtConfig::WIN_TYPE_DISASM;
else if (dynamic_cast<LogWindow*>(widget))
type = WindowQtConfig::WIN_TYPE_LOG;
WindowQtConfig config;
config.m_type = type;
config.m_position.setX(widget->geometry().topLeft().x());
config.m_position.setY(widget->geometry().topLeft().y());
config.m_size.setX(widget->size().width());
config.m_size.setY(widget->size().height());
xmlConfigurations.push_back(config);
}
}
//============================================================
// Utilities
//============================================================
static void load_and_clear_main_window_config(std::vector<WindowQtConfig>& configs)
{
if (configs.size() == 0)
return;
int i = 0;
for (i = 0; i < configs.size(); i++)
{
if (configs[i].m_type == WindowQtConfig::WIN_TYPE_MAIN)
{
mainQtWindow->setGeometry(configs[i].m_position.x(), configs[i].m_position.y(),
configs[i].m_size.x(), configs[i].m_size.y());
break;
}
}
configs.erase(configs.begin()+i);
}
static void setup_additional_startup_windows(running_machine& machine, std::vector<WindowQtConfig>& configs)
{
for (int i = 0; i < configs.size(); i++)
{
WindowQt* foo = NULL;
switch (configs[i].m_type)
{
case WindowQtConfig::WIN_TYPE_MEMORY:
foo = new MemoryWindow(&machine); break;
case WindowQtConfig::WIN_TYPE_DISASM:
foo = new DasmWindow(&machine); break;
case WindowQtConfig::WIN_TYPE_LOG:
foo = new LogWindow(&machine); break;
default: break;
}
foo->setGeometry(configs[i].m_position.x(), configs[i].m_position.y(),
configs[i].m_size.x(), configs[i].m_size.y());
foo->show();
}
}
static void bring_main_window_to_front()
{
foreach (QWidget* widget, QApplication::topLevelWidgets())
{
if (!dynamic_cast<MainWindow*>(widget))
continue;
widget->activateWindow();
widget->raise();
}
}
//============================================================
// Core functionality
//============================================================
void sdl_osd_interface::init_debugger()
{
// QT is a magical thing
new QApplication(qtArgc, qtArgv);
if (qApp == NULL)
{
// If you're starting from scratch, create a new qApp
new QApplication(qtArgc, qtArgv);
}
else
{
// If you're doing a hard reset, clear out existing widgets & get ready for re-init
foreach (QWidget* widget, QApplication::topLevelWidgets())
{
if (!widget->isWindow() || widget->windowType() != Qt::Window)
continue;
delete widget;
}
oneShot = true;
}
// Setup the configuration XML saving and loading
config_register(machine(),
"debugger",
config_saveload_delegate(FUNC(xml_configuration_load), &machine()),
config_saveload_delegate(FUNC(xml_configuration_save), &machine()));
}
@ -49,14 +223,26 @@ void sdl_osd_interface::init_debugger()
void sdl_osd_interface::wait_for_debugger(device_t &device, bool firststop)
{
// Dialog initialization
if (oneShot)
{
mainQtWindow = new MainWindow(&device, &machine());
mainQtWindow = new MainWindow(&machine());
load_and_clear_main_window_config(xmlConfigurations);
setup_additional_startup_windows(machine(), xmlConfigurations);
mainQtWindow->show();
oneShot = false;
}
// Make sure the main window displays the proper cpu
// Insure all top level widgets are visible & bring main window to front
foreach (QWidget* widget, QApplication::topLevelWidgets())
{
if (!widget->isWindow() || widget->windowType() != Qt::Window)
continue;
widget->show();
}
bring_main_window_to_front();
// Set the main window to display the proper cpu
mainQtWindow->setProcessor(&device);
// Run our own QT event loop
@ -73,9 +259,25 @@ void sdl_osd_interface::wait_for_debugger(device_t &device, bool firststop)
mainQtWindow->clearRefreshFlag();
}
// Exit if the machine has been instructed to do so
if (machine().exit_pending())
// Hide all top level widgets if requested
if (mainQtWindow->wantsHide())
{
foreach (QWidget* widget, QApplication::topLevelWidgets())
{
if (!widget->isWindow() || widget->windowType() != Qt::Window)
continue;
widget->hide();
}
mainQtWindow->clearHideFlag();
}
// Exit if the machine has been instructed to do so (scheduled event == exit || hard_reset)
if (machine().scheduled_event_pending())
{
// Keep a list of windows we want to save.
// We need to do this here because by the time xml_configuration_save gets called
// all the QT windows are already gone.
gather_save_configurations();
break;
}
}

View File

@ -8,10 +8,14 @@
DasmWindow::DasmWindow(running_machine* machine, QWidget* parent) :
WindowQt(machine, parent)
{
QPoint parentPos = parent->pos();
setGeometry(parentPos.x()+100, parentPos.y()+100, 800, 400);
setWindowTitle("Debug: Disassembly View");
if (parent != NULL)
{
QPoint parentPos = parent->pos();
setGeometry(parentPos.x()+100, parentPos.y()+100, 800, 400);
}
//
// The main frame and its input and log widgets
//

View File

@ -8,10 +8,14 @@
LogWindow::LogWindow(running_machine* machine, QWidget* parent) :
WindowQt(machine, parent)
{
QPoint parentPos = parent->pos();
setGeometry(parentPos.x()+100, parentPos.y()+100, 800, 400);
setWindowTitle("Debug: Machine Log");
if (parent != NULL)
{
QPoint parentPos = parent->pos();
setGeometry(parentPos.x()+100, parentPos.y()+100, 800, 400);
}
//
// The main frame and its input and log widgets
//

View File

@ -4,9 +4,7 @@
#include "debug/dvdisasm.h"
MainWindow::MainWindow(device_t* processor,
running_machine* machine,
QWidget* parent) :
MainWindow::MainWindow(running_machine* machine, QWidget* parent) :
WindowQt(machine, parent),
m_historyIndex(0),
m_inputHistory()
@ -100,11 +98,6 @@ MainWindow::MainWindow(device_t* processor,
addDockWidget(Qt::TopDockWidgetArea, dasmDock);
dockMenu->addAction(dasmDock->toggleViewAction());
// Window title
astring title;
title.printf("Debug: %s - %s '%s'", m_machine->system().name, processor->name(), processor->tag());
setWindowTitle(title.cstr());
}
@ -261,18 +254,32 @@ void MainWindow::rightBarChanged(QAction* changedTo)
void MainWindow::executeCommand(bool withClear)
{
if (m_inputEdit->text() == "")
QString command = m_inputEdit->text();
// A blank command is a "silent step"
if (command == "")
{
debug_cpu_get_visible_cpu(*m_machine)->debug()->single_step();
return;
}
// If the user asked for help on a specific command, enhance the call
if (command.trimmed().startsWith("help", Qt::CaseInsensitive))
{
if (command.split(" ", QString::SkipEmptyParts).length() == 2)
{
const int width = m_consoleView->view()->visible_size().x;
command.append(QString(", %1").arg(width, 1, 16));
}
}
// Send along the command
debug_console_execute_command(*m_machine,
m_inputEdit->text().toLocal8Bit().data(),
command.toLocal8Bit().data(),
true);
// Add history & set the index to be the top of the stack
addToHistory(m_inputEdit->text());
addToHistory(command);
// Clear out the text and reset the history pointer only if asked
if (withClear)
@ -288,6 +295,12 @@ void MainWindow::executeCommand(bool withClear)
}
void MainWindow::debugActClose()
{
m_machine->schedule_exit();
}
void MainWindow::addToHistory(const QString& command)
{
if (command == "")

View File

@ -21,9 +21,7 @@ class MainWindow : public WindowQt
Q_OBJECT
public:
MainWindow(device_t* processor,
running_machine* machine,
QWidget* parent=NULL);
MainWindow(running_machine* machine, QWidget* parent=NULL);
virtual ~MainWindow() {}
void setProcessor(device_t* processor);
@ -44,6 +42,9 @@ private slots:
void executeCommand(bool withClear=true);
// Closing the main window actually exits the program
void debugActClose();
private:
// Widgets and docks

View File

@ -1,7 +1,6 @@
#include "debugqtmemorywindow.h"
#include "debug/dvmemory.h"
#include "debug/debugvw.h"
#include "debug/debugcon.h"
#include "debug/debugcpu.h"
@ -9,10 +8,14 @@
MemoryWindow::MemoryWindow(running_machine* machine, QWidget* parent) :
WindowQt(machine, parent)
{
QPoint parentPos = parent->pos();
setGeometry(parentPos.x()+100, parentPos.y()+100, 800, 400);
setWindowTitle("Debug: Memory View");
if (parent != NULL)
{
QPoint parentPos = parent->pos();
setGeometry(parentPos.x()+100, parentPos.y()+100, 800, 400);
}
//
// The main frame and its input and log widgets
//

View File

@ -89,6 +89,10 @@ void DebuggerView::paintEvent(QPaintEvent* event)
{
bgColor.setRgb(0xff, 0xff, 0x00);
}
if ((textAttr & DCA_SELECTED) && (textAttr & DCA_CURRENT))
{
bgColor.setRgb(0xff,0xc0,0x80);
}
if(textAttr & DCA_CHANGED)
{
fgColor.setRgb(0xff, 0x00, 0x00);

View File

@ -9,12 +9,15 @@
#include "debugqtmemorywindow.h"
bool WindowQt::s_refreshAll = false;
bool WindowQt::s_hideAll = false;
WindowQt::WindowQt(running_machine* machine, QWidget* parent) :
QMainWindow(parent),
m_machine(machine)
{
//setAttribute(Qt::WA_DeleteOnClose, true);
// The Debug menu bar
QAction* debugActOpenMemory = new QAction("New &Memory Window", this);
debugActOpenMemory->setShortcut(QKeySequence("Ctrl+M"));
@ -83,6 +86,7 @@ WindowQt::WindowQt(running_machine* machine, QWidget* parent) :
debugMenu->addAction(debugActOpenLog);
debugMenu->addSeparator();
debugMenu->addAction(dbgActRun);
debugMenu->addAction(dbgActRunAndHide);
debugMenu->addAction(dbgActRunToNextCpu);
debugMenu->addAction(dbgActRunNextInt);
debugMenu->addAction(dbgActRunNextVBlank);
@ -137,7 +141,7 @@ void WindowQt::debugActRun()
void WindowQt::debugActRunAndHide()
{
debug_cpu_get_visible_cpu(*m_machine)->debug()->go();
// TODO: figure out hide
hideAll();
}
void WindowQt::debugActRunToNextCpu()
@ -173,13 +177,12 @@ void WindowQt::debugActStepOut()
void WindowQt::debugActSoftReset()
{
m_machine->schedule_soft_reset();
debug_cpu_get_visible_cpu(*m_machine)->debug()->single_step();
}
void WindowQt::debugActHardReset()
{
// TODO: Figure out segfault
m_machine->schedule_hard_reset();
debug_cpu_get_visible_cpu(*m_machine)->debug()->go();
}
void WindowQt::debugActClose()
@ -190,5 +193,4 @@ void WindowQt::debugActClose()
void WindowQt::debugActQuit()
{
m_machine->schedule_exit();
qApp->closeAllWindows();
}

View File

@ -22,6 +22,10 @@ public:
bool wantsRefresh() { return s_refreshAll; }
void clearRefreshFlag() { s_refreshAll = false; }
void hideAll() { s_hideAll = true; }
bool wantsHide() { return s_hideAll; }
void clearHideFlag() { s_hideAll = false; }
protected slots:
void debugActOpenMemory();
@ -37,7 +41,7 @@ protected slots:
void debugActStepOut();
void debugActSoftReset();
void debugActHardReset();
void debugActClose();
virtual void debugActClose();
void debugActQuit();
@ -45,7 +49,37 @@ protected:
running_machine* m_machine;
static bool s_refreshAll;
static bool s_hideAll;
};
//=======================================================================
// A way to store the configuration of a window long enough to use it.
//=======================================================================
class WindowQtConfig
{
public:
// This is a holdover from the old debugger - TODO: remove
enum WindowType
{
WIN_TYPE_MAIN = 0x01,
WIN_TYPE_MEMORY = 0x02,
WIN_TYPE_DISASM = 0x04,
WIN_TYPE_LOG = 0x08,
WIN_TYPE_UNKNOWN = 0x10,
};
public:
WindowQtConfig() :
m_type(WIN_TYPE_MAIN),
m_size(800, 600),
m_position(120, 120)
{}
~WindowQtConfig() {}
WindowType m_type;
QPoint m_size;
QPoint m_position;
};
#endif