From ba61a286f382eb9268a6f455365fad9546274e75 Mon Sep 17 00:00:00 2001 From: Andrew Gardner Date: Thu, 24 Jan 2013 17:06:42 +0000 Subject: [PATCH] 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. --- src/emu/debug/debugcmd.c | 10 +- src/osd/sdl/debugqt.c | 214 +++++++++++++++++++++++++++++- src/osd/sdl/debugqtdasmwindow.c | 8 +- src/osd/sdl/debugqtlogwindow.c | 8 +- src/osd/sdl/debugqtmainwindow.c | 35 +++-- src/osd/sdl/debugqtmainwindow.h | 7 +- src/osd/sdl/debugqtmemorywindow.c | 9 +- src/osd/sdl/debugqtview.c | 4 + src/osd/sdl/debugqtwindow.c | 10 +- src/osd/sdl/debugqtwindow.h | 36 ++++- 10 files changed, 307 insertions(+), 34 deletions(-) diff --git a/src/emu/debug/debugcmd.c b/src/emu/debug/debugcmd.c index ad9ff5f7e47..e864126a34f 100644 --- a/src/emu/debug/debugcmd.c +++ b/src/emu/debug/debugcmd.c @@ -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])); + } } diff --git a/src/osd/sdl/debugqt.c b/src/osd/sdl/debugqt.c index 7998b810c85..8a4972da48d 100644 --- a/src/osd/sdl/debugqt.c +++ b/src/osd/sdl/debugqt.c @@ -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 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(widget)) + type = WindowQtConfig::WIN_TYPE_MAIN; + else if (dynamic_cast(widget)) + type = WindowQtConfig::WIN_TYPE_MEMORY; + else if (dynamic_cast(widget)) + type = WindowQtConfig::WIN_TYPE_DISASM; + else if (dynamic_cast(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& 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& 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(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; } } diff --git a/src/osd/sdl/debugqtdasmwindow.c b/src/osd/sdl/debugqtdasmwindow.c index f9b126da78d..da35ce76f4c 100644 --- a/src/osd/sdl/debugqtdasmwindow.c +++ b/src/osd/sdl/debugqtdasmwindow.c @@ -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 // diff --git a/src/osd/sdl/debugqtlogwindow.c b/src/osd/sdl/debugqtlogwindow.c index 16a335a3aa2..a332188fa3d 100644 --- a/src/osd/sdl/debugqtlogwindow.c +++ b/src/osd/sdl/debugqtlogwindow.c @@ -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 // diff --git a/src/osd/sdl/debugqtmainwindow.c b/src/osd/sdl/debugqtmainwindow.c index 56ff9ed991d..58630e390e8 100644 --- a/src/osd/sdl/debugqtmainwindow.c +++ b/src/osd/sdl/debugqtmainwindow.c @@ -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 == "") diff --git a/src/osd/sdl/debugqtmainwindow.h b/src/osd/sdl/debugqtmainwindow.h index 452d8b56bcf..93ff103aac5 100644 --- a/src/osd/sdl/debugqtmainwindow.h +++ b/src/osd/sdl/debugqtmainwindow.h @@ -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 diff --git a/src/osd/sdl/debugqtmemorywindow.c b/src/osd/sdl/debugqtmemorywindow.c index 94670051ddf..57e3794f4ac 100644 --- a/src/osd/sdl/debugqtmemorywindow.c +++ b/src/osd/sdl/debugqtmemorywindow.c @@ -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 // diff --git a/src/osd/sdl/debugqtview.c b/src/osd/sdl/debugqtview.c index c809e5e7953..45432a41269 100644 --- a/src/osd/sdl/debugqtview.c +++ b/src/osd/sdl/debugqtview.c @@ -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); diff --git a/src/osd/sdl/debugqtwindow.c b/src/osd/sdl/debugqtwindow.c index 956035a4975..997cfe54f44 100644 --- a/src/osd/sdl/debugqtwindow.c +++ b/src/osd/sdl/debugqtwindow.c @@ -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(); } diff --git a/src/osd/sdl/debugqtwindow.h b/src/osd/sdl/debugqtwindow.h index ba6c0919236..ae87a767c05 100644 --- a/src/osd/sdl/debugqtwindow.h +++ b/src/osd/sdl/debugqtwindow.h @@ -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