//============================================================ // // debugqt.c - SDL/QT debug window handling // // Copyright (c) 1996-2010, Nicola Salmoria and the MAME Team. // Visit http://mamedev.org for licensing and usage restrictions. // // SDLMAME by Olivier Galibert and R. Belmont // //============================================================ #if !defined(NO_DEBUGGER) #define NO_MEM_TRACKING #include #include #include #include "emu.h" #if defined(WIN32) #include "winmain.h" #define xxx_osd_interface windows_osd_interface #else #include "osdsdl.h" #define xxx_osd_interface sdl_osd_interface #endif #include "config.h" #include "debugger.h" #include "debugqtlogwindow.h" #include "debugqtmainwindow.h" #include "debugqtdasmwindow.h" #include "debugqtmemorywindow.h" //============================================================ // "Global" variables to make QT happy //============================================================ int qtArgc = 0; char** qtArgv = NULL; 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) { // We only care about game files if (config_type != CONFIG_TYPE_GAME) return; // Might not have any data if (parentnode == NULL) return; for (int i = 0; i < xmlConfigurations.size(); i++) delete xmlConfigurations[i]; xmlConfigurations.clear(); // Configuration load xml_data_node* wnode = NULL; for (wnode = xml_get_sibling(parentnode->child, "window"); wnode != NULL; wnode = xml_get_sibling(wnode->next, "window")) { WindowQtConfig::WindowType type = (WindowQtConfig::WindowType)xml_get_attribute_int(wnode, "type", WindowQtConfig::WIN_TYPE_UNKNOWN); switch (type) { case WindowQtConfig::WIN_TYPE_MAIN: xmlConfigurations.push_back(new MainWindowQtConfig()); break; case WindowQtConfig::WIN_TYPE_MEMORY: xmlConfigurations.push_back(new MemoryWindowQtConfig()); break; case WindowQtConfig::WIN_TYPE_DASM: xmlConfigurations.push_back(new DasmWindowQtConfig()); break; case WindowQtConfig::WIN_TYPE_LOG: xmlConfigurations.push_back(new LogWindowQtConfig()); break; default: continue; } xmlConfigurations.back()->recoverFromXmlNode(wnode); } } static void xml_configuration_save(running_machine &machine, int config_type, xml_data_node *parentnode) { // We only write to game configurations if (config_type != CONFIG_TYPE_GAME) return; for (int i = 0; i < xmlConfigurations.size(); i++) { WindowQtConfig* config = xmlConfigurations[i]; // Create an xml node xml_data_node *debugger_node; debugger_node = xml_add_child(parentnode, "window", NULL); if (debugger_node == NULL) continue; // Insert the appropriate information config->addToXmlDataNode(debugger_node); } } static void gather_save_configurations() { for (int i = 0; i < xmlConfigurations.size(); i++) delete xmlConfigurations[i]; 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 if (dynamic_cast(widget)) xmlConfigurations.push_back(new MainWindowQtConfig()); else if (dynamic_cast(widget)) xmlConfigurations.push_back(new MemoryWindowQtConfig()); else if (dynamic_cast(widget)) xmlConfigurations.push_back(new DasmWindowQtConfig()); else if (dynamic_cast(widget)) xmlConfigurations.push_back(new LogWindowQtConfig()); xmlConfigurations.back()->buildFromQWidget(widget); } } //============================================================ // Utilities //============================================================ static void load_and_clear_main_window_config(std::vector& configList) { for (int i = 0; i < configList.size(); i++) { WindowQtConfig* config = configList[i]; if (config->m_type == WindowQtConfig::WIN_TYPE_MAIN) { config->applyToQWidget(mainQtWindow); configList.erase(configList.begin()+i); break; } } } static void setup_additional_startup_windows(running_machine& machine, std::vector& configList) { for (int i = 0; i < configList.size(); i++) { WindowQtConfig* config = configList[i]; WindowQt* foo = NULL; switch (config->m_type) { case WindowQtConfig::WIN_TYPE_MEMORY: foo = new MemoryWindow(&machine); break; case WindowQtConfig::WIN_TYPE_DASM: foo = new DasmWindow(&machine); break; case WindowQtConfig::WIN_TYPE_LOG: foo = new LogWindow(&machine); break; default: break; } config->applyToQWidget(foo); 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 xxx_osd_interface::init_debugger() { if (qApp == NULL) { // If you're starting from scratch, create a new qApp new QApplication(qtArgc, qtArgv); } else { // If you've done 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())); } //============================================================ // Core functionality //============================================================ #ifdef SDLMAME_UNIX extern int sdl_entered_debugger; #endif void xxx_osd_interface::wait_for_debugger(device_t &device, bool firststop) { #ifdef SDLMAME_UNIX sdl_entered_debugger = 1; #endif // Dialog initialization if (oneShot) { mainQtWindow = new MainWindow(&machine()); load_and_clear_main_window_config(xmlConfigurations); setup_additional_startup_windows(machine(), xmlConfigurations); mainQtWindow->show(); oneShot = false; } // 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 while (debug_cpu_is_stopped(machine())) { qApp->processEvents(QEventLoop::AllEvents, 1); // Refresh everyone if requested if (mainQtWindow->wantsRefresh()) { QWidgetList allWidgets = qApp->allWidgets(); for (int i = 0; i < allWidgets.length(); i++) allWidgets[i]->update(); mainQtWindow->clearRefreshFlag(); } // 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; } } } //============================================================ // Available for video.* //============================================================ void debugwin_update_during_game(running_machine &machine) { qApp->processEvents(QEventLoop::AllEvents, 1); } #else #include "sdlinc.h" #include "emu.h" #include "osdepend.h" #include "osdsdl.h" // win32 stubs for linking void sdl_osd_interface::init_debugger() { } void sdl_osd_interface::wait_for_debugger(device_t &device, bool firststop) { } // win32 stubs for linking void debugwin_update_during_game(running_machine &machine) { } #endif