From 2335bb0df8dc00e4fd3373a3e41a7eb531ccf7a5 Mon Sep 17 00:00:00 2001 From: Tim Allen Date: Tue, 31 Jul 2018 20:56:45 +1000 Subject: [PATCH] Update to 20180731 release. byuu says: I've completed moving all the class objects from `unique_pointer` to just T. The one exception is the Emulator::Interface instance. I can absolutely make that a global object, but only in bsnes where there's just the one emulation core. I also moved all the SettingsWindow and ToolsWindow panels out to their own global objects, and fixed a very difficult bug with GTK TabFrame controls. The configuration settings panel is now the emulator settings panel. And I added some spacing between bold label sections on both the emulator and driver settings panels. I gave fixing ComboButtonItem my best shot, given I can't reproduce the crash. Probably won't work, though. Also made a very slight consistency improvement to ruby and renamed driverName() to driver(). ... An important change ... as a result of moving bsnes to global objects, this means that the constructors for all windows run before the presentation window is displayed. Before this change, only the presentation window was constructed first berore displaying it, followed by the construction of the rest of the GUI windows. The upside to this is that as soon as you see the main window, the GUI is ready to go without a period where it's unresponsive. The downside to this is it takes about 1.5 seconds to show the main window, compared to around 0.75 seconds before. I've no intention of changing that back. So if the startup time becomes a problem, then we'll just have to work on optimizing hiro, so that it can construct all the global Window objects quicker. The main way to do that would be to not do calls to the Layout::setGeometry functions for every widget added, and instead wait until the window is displayed. But I don't have an easy way to do that, because you want the widget geometry values to be sane even before the window is visible to help size certain things. --- higan/target-bsnes/bsnes.cpp | 2 +- higan/target-bsnes/input/hotkeys.cpp | 31 +++--- higan/target-bsnes/input/input.cpp | 19 ++-- higan/target-bsnes/input/input.hpp | 3 +- .../presentation/presentation.cpp | 92 +++++++++-------- .../presentation/presentation.hpp | 6 +- higan/target-bsnes/program/audio.cpp | 4 +- higan/target-bsnes/program/game.cpp | 54 +++++----- higan/target-bsnes/program/hacks.cpp | 11 ++- higan/target-bsnes/program/input.cpp | 8 +- higan/target-bsnes/program/platform.cpp | 18 ++-- higan/target-bsnes/program/program.cpp | 53 +++++----- higan/target-bsnes/program/program.hpp | 4 +- higan/target-bsnes/program/states.cpp | 2 +- higan/target-bsnes/program/utility.cpp | 18 ++-- higan/target-bsnes/program/video.cpp | 8 +- higan/target-bsnes/settings/audio.cpp | 8 +- higan/target-bsnes/settings/drivers.cpp | 64 ++++++------ .../{configuration.cpp => emulator.cpp} | 8 +- higan/target-bsnes/settings/hotkeys.cpp | 28 +++--- higan/target-bsnes/settings/input.cpp | 30 +++--- higan/target-bsnes/settings/paths.cpp | 2 +- higan/target-bsnes/settings/settings.cpp | 34 ++++--- higan/target-bsnes/settings/settings.hpp | 37 +++---- higan/target-bsnes/settings/video.cpp | 8 +- higan/target-bsnes/tools/cheat-editor.cpp | 30 +++--- higan/target-bsnes/tools/manifest-viewer.cpp | 6 +- higan/target-bsnes/tools/state-manager.cpp | 32 +++--- higan/target-bsnes/tools/tools.cpp | 26 ++--- higan/target-bsnes/tools/tools.hpp | 28 +++--- hiro/cocoa/object.cpp | 3 - hiro/cocoa/object.hpp | 1 - hiro/core/action/menu.cpp | 4 +- hiro/core/menu-bar.cpp | 2 +- hiro/core/object.cpp | 1 - hiro/core/widget/combo-button.cpp | 14 ++- hiro/gtk/object.cpp | 3 - hiro/gtk/object.hpp | 1 - hiro/gtk/widget/tab-frame-item.cpp | 1 + hiro/gtk/widget/tab-frame.cpp | 66 +++++++------ hiro/gtk/widget/tab-frame.hpp | 1 + hiro/qt/object.cpp | 3 - hiro/qt/object.hpp | 1 - hiro/qt/widget/table-view-column.cpp | 5 +- hiro/qt/widget/table-view-column.hpp | 1 - hiro/windows/object.cpp | 3 - hiro/windows/object.hpp | 1 - ruby/audio/audio.cpp | 98 +++++++++---------- ruby/audio/audio.hpp | 54 +++++----- ruby/audio/oss.cpp | 2 +- ruby/input/input.cpp | 34 +++---- ruby/input/input.hpp | 18 ++-- ruby/input/sdl.cpp | 2 +- ruby/video/glx2.cpp | 2 +- ruby/video/video.cpp | 76 +++++++------- ruby/video/video.hpp | 44 ++++----- ruby/video/xshm.cpp | 2 +- 57 files changed, 557 insertions(+), 560 deletions(-) rename higan/target-bsnes/settings/{configuration.cpp => emulator.cpp} (94%) diff --git a/higan/target-bsnes/bsnes.cpp b/higan/target-bsnes/bsnes.cpp index b174baf5..2ef8f701 100644 --- a/higan/target-bsnes/bsnes.cpp +++ b/higan/target-bsnes/bsnes.cpp @@ -34,6 +34,6 @@ auto nall::main(vector arguments) -> void { Application::locale().scan(locate("locales/")); Application::locale().select(locale); emulator = new SuperFamicom::Interface; - new Program(arguments); + program.create(arguments); Application::run(); } diff --git a/higan/target-bsnes/input/hotkeys.cpp b/higan/target-bsnes/input/hotkeys.cpp index 1f6d6277..7527d4c0 100644 --- a/higan/target-bsnes/input/hotkeys.cpp +++ b/higan/target-bsnes/input/hotkeys.cpp @@ -2,7 +2,7 @@ auto InputManager::bindHotkeys() -> void { static int stateSlot = 1; hotkeys.append(InputHotkey("Toggle Fullscreen Mode").onPress([] { - presentation->toggleFullscreenMode(); + presentation.toggleFullscreenMode(); })); hotkeys.append(InputHotkey("Toggle Mouse Capture").onPress([] { @@ -10,40 +10,37 @@ auto InputManager::bindHotkeys() -> void { })); hotkeys.append(InputHotkey("Toggle Cheat Codes").onPress([] { - toolsWindow->cheatEditor.enableCheats.setChecked( - !toolsWindow->cheatEditor.enableCheats.checked() - ); - toolsWindow->cheatEditor.enableCheats.doToggle(); + cheatEditor.enableCheats.setChecked(!cheatEditor.enableCheats.checked()).doToggle(); })); hotkeys.append(InputHotkey("Save State").onPress([&] { - program->saveState({"quick/slot ", stateSlot}); + program.saveState({"quick/slot ", stateSlot}); })); hotkeys.append(InputHotkey("Load State").onPress([&] { - program->loadState({"quick/slot ", stateSlot}); + program.loadState({"quick/slot ", stateSlot}); })); hotkeys.append(InputHotkey("Load Undo State").onPress([&] { - program->loadState("quick/undo"); + program.loadState("quick/undo"); })); hotkeys.append(InputHotkey("Load Redo State").onPress([&] { - program->loadState("quick/redo"); + program.loadState("quick/redo"); })); hotkeys.append(InputHotkey("Increment State Slot").onPress([&] { if(--stateSlot < 1) stateSlot = 9; - program->showMessage({"Selected state slot ", stateSlot}); + program.showMessage({"Selected state slot ", stateSlot}); })); hotkeys.append(InputHotkey("Decrement State Slot").onPress([&] { if(++stateSlot > 9) stateSlot = 1; - program->showMessage({"Selected state slot ", stateSlot}); + program.showMessage({"Selected state slot ", stateSlot}); })); hotkeys.append(InputHotkey("Capture Screenshot").onPress([] { - program->captureScreenshot(); + program.captureScreenshot(); })); hotkeys.append(InputHotkey("Fast Forward").onPress([] { @@ -55,19 +52,19 @@ auto InputManager::bindHotkeys() -> void { })); hotkeys.append(InputHotkey("Pause Emulation").onPress([] { - presentation->pauseEmulation.setChecked(!presentation->pauseEmulation.checked()); + presentation.pauseEmulation.setChecked(!presentation.pauseEmulation.checked()); })); hotkeys.append(InputHotkey("Frame Advance").onPress([] { - presentation->frameAdvance.doActivate(); + presentation.frameAdvance.doActivate(); })); hotkeys.append(InputHotkey("Reset Emulation").onPress([] { - program->reset(); + program.reset(); })); hotkeys.append(InputHotkey("Quit Emulator").onPress([] { - program->quit(); + program.quit(); })); for(auto& hotkey : hotkeys) { @@ -78,7 +75,7 @@ auto InputManager::bindHotkeys() -> void { } auto InputManager::pollHotkeys() -> void { - if(!program->focused()) return; + if(!program.focused()) return; for(auto& hotkey : hotkeys) { auto state = hotkey.poll(); diff --git a/higan/target-bsnes/input/input.cpp b/higan/target-bsnes/input/input.cpp index cd82f772..d168a4da 100644 --- a/higan/target-bsnes/input/input.cpp +++ b/higan/target-bsnes/input/input.cpp @@ -1,6 +1,6 @@ #include "../bsnes.hpp" #include "hotkeys.cpp" -unique_pointer inputManager; +InputManager inputManager; auto InputMapping::bind() -> void { mappings.reset(); @@ -15,7 +15,7 @@ auto InputMapping::bind() -> void { string qualifier = token(3, "None"); Mapping mapping; - for(auto& device : inputManager->devices) { + for(auto& device : inputManager.devices) { if(id != device->id()) continue; mapping.device = device; @@ -103,9 +103,9 @@ auto InputMapping::unbind() -> void { auto InputMapping::poll() -> int16 { if(turboID) { - auto& mapping = inputManager->ports[portID].devices[deviceID].mappings[turboID()]; + auto& mapping = inputManager.ports[portID].devices[deviceID].mappings[turboID()]; auto result = mapping.poll(); - if(result) return inputManager->turboCounter >= inputManager->turboFrequency; + if(result) return inputManager.turboCounter >= inputManager.turboFrequency; } int16 result; @@ -180,16 +180,11 @@ auto InputMapping::displayName() -> string { // -InputManager::InputManager() { - inputManager = this; -} - auto InputManager::initialize() -> void { devices.reset(); ports.reset(); hotkeys.reset(); - if(!input) return; input.onChange({&InputManager::onChange, this}); lastPoll = chrono::millisecond(); @@ -283,9 +278,9 @@ auto InputManager::frame() -> void { } auto InputManager::onChange(shared_pointer device, uint group, uint input, int16_t oldValue, int16_t newValue) -> void { - if(settingsWindow->focused()) { - settingsWindow->input.inputEvent(device, group, input, oldValue, newValue); - settingsWindow->hotkeys.inputEvent(device, group, input, oldValue, newValue); + if(settingsWindow.focused()) { + inputSettings.inputEvent(device, group, input, oldValue, newValue); + hotkeySettings.inputEvent(device, group, input, oldValue, newValue); } } diff --git a/higan/target-bsnes/input/input.hpp b/higan/target-bsnes/input/input.hpp index cc876eca..5dfda5f2 100644 --- a/higan/target-bsnes/input/input.hpp +++ b/higan/target-bsnes/input/input.hpp @@ -67,7 +67,6 @@ struct InputPort { }; struct InputManager { - InputManager(); auto initialize() -> void; auto bind() -> void; auto poll() -> void; @@ -92,4 +91,4 @@ public: uint turboFrequency = 0; }; -extern unique_pointer inputManager; +extern InputManager inputManager; diff --git a/higan/target-bsnes/presentation/presentation.cpp b/higan/target-bsnes/presentation/presentation.cpp index ad39f174..45c5c562 100644 --- a/higan/target-bsnes/presentation/presentation.cpp +++ b/higan/target-bsnes/presentation/presentation.cpp @@ -1,28 +1,26 @@ #include "../bsnes.hpp" #include "about.cpp" AboutWindow aboutWindow; -unique_pointer presentation; - -Presentation::Presentation() { - presentation = this; +Presentation presentation; +auto Presentation::create() -> void { systemMenu.setText(tr("System")); loadGame.setIcon(Icon::Action::Open).setText({tr("Load Game"), " ..."}).onActivate([&] { - program->load(); + program.load(); }); loadRecentGame.setIcon(Icon::Action::Open).setText(tr("Load Recent Game")); updateRecentGames(); resetSystem.setIcon(Icon::Action::Refresh).setText(tr("Reset System")).setEnabled(false).onActivate([&] { - program->reset(); + program.reset(); }); unloadGame.setIcon(Icon::Action::Remove).setText(tr("Unload Game")).setEnabled(false).onActivate([&] { - program->unload(); + program.unload(); }); controllerPort1.setIcon(Icon::Device::Joypad).setText(tr("Controller Port 1")); controllerPort2.setIcon(Icon::Device::Joypad).setText(tr("Controller Port 2")); expansionPort.setIcon(Icon::Device::Storage).setText(tr("Expansion Port")); updateDeviceMenu(); - quit.setIcon(Icon::Action::Quit).setText(tr("Quit")).onActivate([&] { program->quit(); }); + quit.setIcon(Icon::Action::Quit).setText(tr("Quit")).onActivate([&] { program.quit(); }); settingsMenu.setText(tr("Settings")); sizeMenu.setIcon(Icon::Emblem::Image).setText("Size"); @@ -58,7 +56,7 @@ Presentation::Presentation() { shaderMenu.setIcon(Icon::Emblem::Image).setText("Shader"); muteAudio.setText("Mute Audio").setChecked(settings["Audio/Mute"].boolean()).onToggle([&] { settings["Audio/Mute"].setValue(muteAudio.checked()); - program->updateAudioEffects(); + program.updateAudioEffects(); }); showStatusBar.setText("Show Status Bar").setChecked(settings["UserInterface/ShowStatusBar"].boolean()).onToggle([&] { settings["UserInterface/ShowStatusBar"].setValue(showStatusBar.checked()); @@ -69,13 +67,13 @@ Presentation::Presentation() { } if(visible()) resizeWindow(); }); - videoSettings.setIcon(Icon::Device::Display).setText("Video ...").onActivate([&] { settingsWindow->show(0); }); - audioSettings.setIcon(Icon::Device::Speaker).setText("Audio ...").onActivate([&] { settingsWindow->show(1); }); - inputSettings.setIcon(Icon::Device::Joypad).setText("Input ...").onActivate([&] { settingsWindow->show(2); }); - hotkeySettings.setIcon(Icon::Device::Keyboard).setText("Hotkeys ...").onActivate([&] { settingsWindow->show(3); }); - pathSettings.setIcon(Icon::Emblem::Folder).setText("Paths ...").onActivate([&] { settingsWindow->show(4); }); - configurationSettings.setIcon(Icon::Action::Settings).setText("Configuration ...").onActivate([&] { settingsWindow->show(5); }); - driverSettings.setIcon(Icon::Place::Settings).setText("Drivers ...").onActivate([&] { settingsWindow->show(6); }); + videoSettings.setIcon(Icon::Device::Display).setText("Video ...").onActivate([&] { settingsWindow.show(0); }); + audioSettings.setIcon(Icon::Device::Speaker).setText("Audio ...").onActivate([&] { settingsWindow.show(1); }); + inputSettings.setIcon(Icon::Device::Joypad).setText("Input ...").onActivate([&] { settingsWindow.show(2); }); + hotkeySettings.setIcon(Icon::Device::Keyboard).setText("Hotkeys ...").onActivate([&] { settingsWindow.show(3); }); + pathSettings.setIcon(Icon::Emblem::Folder).setText("Paths ...").onActivate([&] { settingsWindow.show(4); }); + emulatorSettings.setIcon(Icon::Action::Settings).setText("Emulator ...").onActivate([&] { settingsWindow.show(5); }); + driverSettings.setIcon(Icon::Place::Settings).setText("Drivers ...").onActivate([&] { settingsWindow.show(6); }); toolsMenu.setText(tr("Tools")).setVisible(false); saveState.setIcon(Icon::Action::Save).setText("Save State"); @@ -84,7 +82,7 @@ Presentation::Presentation() { item.setProperty("name", {"quick/slot ", 1 + index}); item.setProperty("title", {"Slot ", 1 + index}); item.setText({"Slot ", 1 + index}); - item.onActivate([=] { program->saveState({"quick/slot ", 1 + index}); }); + item.onActivate([=] { program.saveState({"quick/slot ", 1 + index}); }); } loadState.setIcon(Icon::Media::Play).setText("Load State"); for(uint index : range(QuickStates)) { @@ -92,48 +90,48 @@ Presentation::Presentation() { item.setProperty("name", {"quick/slot ", 1 + index}); item.setProperty("title", {"Slot ", 1 + index}); item.setText({"Slot ", 1 + index}); - item.onActivate([=] { program->loadState({"quick/slot ", 1 + index}); }); + item.onActivate([=] { program.loadState({"quick/slot ", 1 + index}); }); } loadState.append(MenuSeparator()); loadState.append(MenuItem() .setProperty("name", "quick/undo") .setProperty("title", "Undo Last Save") .setIcon(Icon::Edit::Undo).setText("Undo Last Save").onActivate([&] { - program->loadState("quick/undo"); + program.loadState("quick/undo"); })); loadState.append(MenuItem() .setProperty("name", "quick/redo") .setProperty("title", "Redo Last Undo") .setIcon(Icon::Edit::Redo).setText("Redo Last Undo").onActivate([&] { - program->loadState("quick/redo"); + program.loadState("quick/redo"); })); loadState.append(MenuItem().setIcon(Icon::Edit::Clear).setText("Remove All States").onActivate([&] { if(MessageDialog("Are you sure you want to permanently remove all quick states for this game?").setParent(*this).question() == "Yes") { - for(uint index : range(QuickStates)) program->removeState({"quick/slot ", 1 + index}); - program->removeState("quick/undo"); - program->removeState("quick/redo"); + for(uint index : range(QuickStates)) program.removeState({"quick/slot ", 1 + index}); + program.removeState("quick/undo"); + program.removeState("quick/redo"); updateStateMenus(); } })); speedMenu.setIcon(Icon::Device::Clock).setText("Speed"); - speedSlowest.setText("50% (Slowest)").setProperty("multiplier", "2.0").onActivate([&] { program->updateAudioFrequency(); }); - speedSlow.setText("75% (Slow)").setProperty("multiplier", "1.333").onActivate([&] { program->updateAudioFrequency(); }); - speedNormal.setText("100% (Normal)").setProperty("multiplier", "1.0").onActivate([&] { program->updateAudioFrequency(); }); - speedFast.setText("150% (Fast)").setProperty("multiplier", "0.667").onActivate([&] { program->updateAudioFrequency(); }); - speedFastest.setText("200% (Fastest)").setProperty("multiplier", "0.5").onActivate([&] { program->updateAudioFrequency(); }); + speedSlowest.setText("50% (Slowest)").setProperty("multiplier", "2.0").onActivate([&] { program.updateAudioFrequency(); }); + speedSlow.setText("75% (Slow)").setProperty("multiplier", "1.333").onActivate([&] { program.updateAudioFrequency(); }); + speedNormal.setText("100% (Normal)").setProperty("multiplier", "1.0").onActivate([&] { program.updateAudioFrequency(); }); + speedFast.setText("150% (Fast)").setProperty("multiplier", "0.667").onActivate([&] { program.updateAudioFrequency(); }); + speedFastest.setText("200% (Fastest)").setProperty("multiplier", "0.5").onActivate([&] { program.updateAudioFrequency(); }); pauseEmulation.setText("Pause Emulation").onToggle([&] { if(pauseEmulation.checked()) audio.clear(); }); frameAdvance.setIcon(Icon::Media::Next).setText("Frame Advance").onActivate([&] { pauseEmulation.setChecked(false); - program->frameAdvance = true; + program.frameAdvance = true; }); captureScreenshot.setIcon(Icon::Emblem::Image).setText("Capture Screenshot").onActivate([&] { - program->captureScreenshot(); + program.captureScreenshot(); }); - cheatEditor.setIcon(Icon::Edit::Replace).setText("Cheat Editor ...").onActivate([&] { toolsWindow->show(0); }); - stateManager.setIcon(Icon::Application::FileManager).setText("State Manager ...").onActivate([&] { toolsWindow->show(1); }); - manifestViewer.setIcon(Icon::Emblem::Text).setText("Manifest Viewer ...").onActivate([&] { toolsWindow->show(2); }); + cheatEditor.setIcon(Icon::Edit::Replace).setText("Cheat Editor ...").onActivate([&] { toolsWindow.show(0); }); + stateManager.setIcon(Icon::Application::FileManager).setText("State Manager ...").onActivate([&] { toolsWindow.show(1); }); + manifestViewer.setIcon(Icon::Emblem::Text).setText("Manifest Viewer ...").onActivate([&] { toolsWindow.show(2); }); helpMenu.setText(tr("Help")); documentation.setIcon(Icon::Application::Browser).setText({tr("Documentation"), " ..."}).onActivate([&] { @@ -144,8 +142,8 @@ Presentation::Presentation() { }); viewport.setDroppable().onDrop([&](vector locations) { - program->gameQueue = locations; - program->load(); + program.gameQueue = locations; + program.load(); setFocused(); }); @@ -175,10 +173,10 @@ Presentation::Presentation() { spacerRight.setBackgroundColor(back).setForegroundColor(fore); - program->updateStatus(); + program.updateStatus(); onClose([&] { - program->quit(); + program.quit(); }); onSize([&] { @@ -199,7 +197,7 @@ Presentation::Presentation() { #if defined(PLATFORM_MACOS) Application::Cocoa::onAbout([&] { about.doActivate(); }); Application::Cocoa::onActivate([&] { setFocused(); }); - Application::Cocoa::onPreferences([&] { settingsWindow->show(2); }); + Application::Cocoa::onPreferences([&] { settingsWindow.show(2); }); Application::Cocoa::onQuit([&] { doClose(); }); #endif } @@ -210,7 +208,7 @@ auto Presentation::updateStatusIcon() -> void { icon.fill(0xff202020); if(emulator->loaded()) { - image emblem{program->verified() ? Icon::Emblem::Program : Icon::Emblem::Binary}; + image emblem{program.verified() ? Icon::Emblem::Program : Icon::Emblem::Binary}; icon.impose(image::blend::sourceAlpha, 0, (StatusHeight - 16) / 2, emblem, 0, 0, 16, 16); } @@ -440,13 +438,13 @@ auto Presentation::updateSizeMenu() -> void { } auto Presentation::updateStateMenus() -> void { - auto states = program->availableStates("quick/"); + auto states = program.availableStates("quick/"); for(auto& action : saveState.actions()) { if(auto item = action.cast()) { if(auto name = item.property("name")) { if(states.find(name)) { - auto timestamp = program->stateTimestamp(item.property("name")); + auto timestamp = program.stateTimestamp(item.property("name")); item.setText({item.property("title"), " [", chrono::local::datetime(timestamp), "]"}); } else { item.setText({item.property("title"), " [Empty]"}); @@ -459,7 +457,7 @@ auto Presentation::updateStateMenus() -> void { if(auto item = action.cast()) { if(auto name = item.property("name")) { if(states.find(name)) { - auto timestamp = program->stateTimestamp(item.property("name")); + auto timestamp = program.stateTimestamp(item.property("name")); item.setEnabled(true); item.setText({item.property("title"), " [", chrono::local::datetime(timestamp), "]"}); } else { @@ -509,8 +507,8 @@ auto Presentation::updateRecentGames() -> void { item.setIcon(games(0).endsWith("/") ? Icon::Action::Open : Icon::Emblem::File); item.setText(displayName); item.onActivate([=] { - program->gameQueue = games; - program->load(); + program.gameQueue = games; + program.load(); }); } else { item.setText({"[", tr("Empty"), "]"}); @@ -551,14 +549,14 @@ auto Presentation::updateShaders() -> void { MenuRadioItem none{&shaderMenu}; none.setText("None").onActivate([&] { settings["Video/Shader"].setValue("None"); - program->updateVideoShader(); + program.updateVideoShader(); }); shaders.append(none); MenuRadioItem blur{&shaderMenu}; blur.setText("Blur").onActivate([&] { settings["Video/Shader"].setValue("Blur"); - program->updateVideoShader(); + program.updateVideoShader(); }); shaders.append(blur); @@ -570,7 +568,7 @@ auto Presentation::updateShaders() -> void { MenuRadioItem item{&shaderMenu}; item.setText(string{shader}.trimRight(".shader/", 1L)).onActivate([=] { settings["Video/Shader"].setValue({location, shader}); - program->updateVideoShader(); + program.updateVideoShader(); }); shaders.append(item); } diff --git a/higan/target-bsnes/presentation/presentation.hpp b/higan/target-bsnes/presentation/presentation.hpp index 9858ada3..fc8c8afb 100644 --- a/higan/target-bsnes/presentation/presentation.hpp +++ b/higan/target-bsnes/presentation/presentation.hpp @@ -20,11 +20,11 @@ struct AboutWindow : Window { struct Presentation : Window { Application::Namespace tr{"Presentation"}; + auto create() -> void; enum : uint { RecentGames = 9, QuickStates = 9 }; enum : uint { StatusHeight = 24 }; - Presentation(); auto updateStatusIcon() -> void; auto drawIcon(uint32_t* output, uint length, uint width, uint height) -> void; auto clearViewport() -> void; @@ -75,7 +75,7 @@ struct Presentation : Window { MenuItem inputSettings{&settingsMenu}; MenuItem hotkeySettings{&settingsMenu}; MenuItem pathSettings{&settingsMenu}; - MenuItem configurationSettings{&settingsMenu}; + MenuItem emulatorSettings{&settingsMenu}; MenuItem driverSettings{&settingsMenu}; Menu toolsMenu{&menuBar}; Menu saveState{&toolsMenu}; @@ -113,4 +113,4 @@ struct Presentation : Window { }; extern AboutWindow aboutWindow; -extern unique_pointer presentation; +extern Presentation presentation; diff --git a/higan/target-bsnes/program/audio.cpp b/higan/target-bsnes/program/audio.cpp index f1d44d67..298ca567 100644 --- a/higan/target-bsnes/program/audio.cpp +++ b/higan/target-bsnes/program/audio.cpp @@ -1,7 +1,7 @@ auto Program::updateAudioDriver(Window parent) -> void { auto changed = (bool)audio; audio.create(settings["Audio/Driver"].text()); - audio.setContext(presentation->viewport.handle()); + audio.setContext(presentation.viewport.handle()); audio.setChannels(2); if(changed) { settings["Audio/Device"].setValue(audio.device()); @@ -54,7 +54,7 @@ auto Program::updateAudioFrequency() -> void { } audio.setFrequency(settings["Audio/Frequency"].real()); double frequency = settings["Audio/Frequency"].real() + settings["Audio/Skew"].integer(); - for(auto item : presentation->speedGroup.objects()) { + for(auto item : presentation.speedGroup.objects()) { if(item.checked()) frequency *= item.property("multiplier").real(); } Emulator::audio.setFrequency(frequency); diff --git a/higan/target-bsnes/program/game.cpp b/higan/target-bsnes/program/game.cpp index 6493a843..560d70aa 100644 --- a/higan/target-bsnes/program/game.cpp +++ b/higan/target-bsnes/program/game.cpp @@ -3,14 +3,14 @@ auto Program::load() -> void { if(auto configuration = string::read(locate("configuration.bml"))) { emulator->configure(configuration); - settingsWindow->configuration.updateConfiguration(); + emulatorSettings.updateConfiguration(); } if(!emulator->load()) return; gameQueue = {}; screenshot = {}; frameAdvance = false; - if(!verified() && settingsWindow->configuration.warnOnUnverifiedGames.checked()) { + if(!verified() && emulatorSettings.warnOnUnverifiedGames.checked()) { auto response = MessageDialog( "Warning: this game image is unverified.\n" "Running it *may* be a security risk.\n\n" @@ -21,37 +21,37 @@ auto Program::load() -> void { return showMessage("Game loading cancelled"); } if(response == "Always") { - settingsWindow->configuration.warnOnUnverifiedGames.setChecked(false).doToggle(); + emulatorSettings.warnOnUnverifiedGames.setChecked(false).doToggle(); } } hackCompatibility(); emulator->power(); - if(settingsWindow->configuration.autoLoadStateOnLoad.checked()) { - program->loadState("quick/undo"); + if(emulatorSettings.autoLoadStateOnLoad.checked()) { + program.loadState("quick/undo"); } showMessage({ verified() ? "Verified game loaded" : "Game loaded", appliedPatch() ? " and patch applied" : "" }); - presentation->setTitle(emulator->titles().merge(" + ")); - presentation->resetSystem.setEnabled(true); - presentation->unloadGame.setEnabled(true); - presentation->toolsMenu.setVisible(true); - presentation->updateStateMenus(); - presentation->speedNormal.setChecked(); - presentation->pauseEmulation.setChecked(false); - presentation->updateStatusIcon(); - presentation->resizeViewport(); - toolsWindow->cheatEditor.loadCheats(); - toolsWindow->stateManager.loadStates(); - toolsWindow->manifestViewer.loadManifest(); + presentation.setTitle(emulator->titles().merge(" + ")); + presentation.resetSystem.setEnabled(true); + presentation.unloadGame.setEnabled(true); + presentation.toolsMenu.setVisible(true); + presentation.updateStateMenus(); + presentation.speedNormal.setChecked(); + presentation.pauseEmulation.setChecked(false); + presentation.updateStatusIcon(); + presentation.resizeViewport(); + cheatEditor.loadCheats(); + stateManager.loadStates(); + manifestViewer.loadManifest(); string locations = superFamicom.location; if(auto& location = gameBoy.location) locations.append("|", location); if(auto& location = bsMemory.location) locations.append("|", location); if(auto& location = sufamiTurboA.location) locations.append("|", location); if(auto& location = sufamiTurboB.location) locations.append("|", location); - presentation->addRecentGame(locations); + presentation.addRecentGame(locations); updateVideoPalette(); updateAudioEffects(); @@ -283,9 +283,9 @@ auto Program::reset() -> void { auto Program::unload() -> void { if(!emulator->loaded()) return; - toolsWindow->cheatEditor.saveCheats(); - toolsWindow->setVisible(false); - if(settingsWindow->configuration.autoSaveStateOnUnload.checked()) { + cheatEditor.saveCheats(); + toolsWindow.setVisible(false); + if(emulatorSettings.autoSaveStateOnUnload.checked()) { saveUndoState(); } if(auto configuration = emulator->configuration()) { @@ -298,12 +298,12 @@ auto Program::unload() -> void { bsMemory = {}; sufamiTurboA = {}; sufamiTurboB = {}; - presentation->setTitle({"bsnes v", Emulator::Version}); - presentation->resetSystem.setEnabled(false); - presentation->unloadGame.setEnabled(false); - presentation->toolsMenu.setVisible(false); - presentation->updateStatusIcon(); - presentation->clearViewport(); + presentation.setTitle({"bsnes v", Emulator::Version}); + presentation.resetSystem.setEnabled(false); + presentation.unloadGame.setEnabled(false); + presentation.toolsMenu.setVisible(false); + presentation.updateStatusIcon(); + presentation.clearViewport(); } //a game is considered verified if the game plus its slot(s) are found in the games database diff --git a/higan/target-bsnes/program/hacks.cpp b/higan/target-bsnes/program/hacks.cpp index 180bf621..260277ed 100644 --- a/higan/target-bsnes/program/hacks.cpp +++ b/higan/target-bsnes/program/hacks.cpp @@ -1,14 +1,15 @@ auto Program::hackCompatibility() -> void { - bool fastPPU = settingsWindow->configuration.fastPPUOption.checked(); - bool fastPPUNoSpriteLimit = settingsWindow->configuration.noSpriteLimit.checked(); - bool fastPPUHiresMode7 = settingsWindow->configuration.hiresMode7.checked(); - bool fastDSP = settingsWindow->configuration.fastDSPOption.checked(); + bool fastPPU = emulatorSettings.fastPPUOption.checked(); + bool fastPPUNoSpriteLimit = emulatorSettings.noSpriteLimit.checked(); + bool fastPPUHiresMode7 = emulatorSettings.hiresMode7.checked(); + bool fastDSP = emulatorSettings.fastDSPOption.checked(); auto label = superFamicom.label; if(label == "AIR STRIKE PATROL" || label == "DESERT FIGHTER") fastPPU = false; if(label == "KOUSHIEN_2") fastDSP = false; if(label == "RENDERING RANGER R2") fastDSP = false; + //todo: update to new emulator->configuration API emulator->set("Fast PPU", fastPPU); emulator->set("Fast PPU/No Sprite Limit", fastPPUNoSpriteLimit); emulator->set("Fast PPU/Hires Mode 7", fastPPUHiresMode7); @@ -33,7 +34,7 @@ auto Program::hackPatchMemory(vector& data) -> void { auto Program::hackOverclockSuperFX() -> void { //todo: implement a better way of detecting SuperFX games //todo: apply multiplier changes on reset, not just on game load? - double multiplier = settingsWindow->configuration.superFXValue.text().natural() / 100.0; + double multiplier = emulatorSettings.superFXValue.text().natural() / 100.0; if(multiplier == 1.0) return; auto label = superFamicom.label; diff --git a/higan/target-bsnes/program/input.cpp b/higan/target-bsnes/program/input.cpp index 241049eb..f2d7533e 100644 --- a/higan/target-bsnes/program/input.cpp +++ b/higan/target-bsnes/program/input.cpp @@ -1,13 +1,13 @@ auto Program::updateInputDriver(Window parent) -> void { auto changed = (bool)input; input.create(settings["Input/Driver"].text()); - input.setContext(presentation->viewport.handle()); + input.setContext(presentation.viewport.handle()); if(changed) { } - inputManager->initialize(); - settingsWindow->input.reloadPorts(); - settingsWindow->hotkeys.reloadMappings(); + inputManager.initialize(); + inputSettings.reloadPorts(); + hotkeySettings.reloadMappings(); if(!input.ready()) { MessageDialog({ diff --git a/higan/target-bsnes/program/platform.cpp b/higan/target-bsnes/program/platform.cpp index 410ef9c3..73c276b4 100644 --- a/higan/target-bsnes/program/platform.cpp +++ b/higan/target-bsnes/program/platform.cpp @@ -92,7 +92,7 @@ auto Program::open(uint id, string name, vfs::file::mode mode, bool required) -> "Error: missing required data: ", name, "\n\n", "Would you like to view the online documentation for more information?" }).setParent(*presentation).error({"Yes", "No"}) == "Yes") { - presentation->documentation.doActivate(); + presentation.documentation.doActivate(); } } @@ -197,7 +197,7 @@ auto Program::videoRefresh(uint display, const uint32* data, uint pitch, uint wi uint length; pitch >>= 2; - if(presentation->overscanCropping.checked()) { + if(presentation.overscanCropping.checked()) { if(height == 240) data += 8 * pitch, height -= 16; if(height == 480) data += 16 * pitch, height -= 32; } @@ -221,11 +221,11 @@ auto Program::videoRefresh(uint display, const uint32* data, uint pitch, uint wi video.output(); } - inputManager->frame(); + inputManager.frame(); if(frameAdvance) { frameAdvance = false; - presentation->pauseEmulation.setChecked(); + presentation.pauseEmulation.setChecked(); } static uint frameCounter = 0; @@ -245,9 +245,9 @@ auto Program::audioSample(const double* samples, uint channels) -> void { } auto Program::inputPoll(uint port, uint device, uint input) -> int16 { - if(focused() || settingsWindow->configuration.allowInput().checked()) { - inputManager->poll(); - if(auto mapping = inputManager->mapping(port, device, input)) { + if(focused() || emulatorSettings.allowInput().checked()) { + inputManager.poll(); + if(auto mapping = inputManager.mapping(port, device, input)) { return mapping->poll(); } } @@ -255,8 +255,8 @@ auto Program::inputPoll(uint port, uint device, uint input) -> int16 { } auto Program::inputRumble(uint port, uint device, uint input, bool enable) -> void { - if(focused() || settingsWindow->configuration.allowInput().checked() || !enable) { - if(auto mapping = inputManager->mapping(port, device, input)) { + if(focused() || emulatorSettings.allowInput().checked() || !enable) { + if(auto mapping = inputManager.mapping(port, device, input)) { return mapping->rumble(enable); } } diff --git a/higan/target-bsnes/program/program.cpp b/higan/target-bsnes/program/program.cpp index 16f15e88..948aa23a 100644 --- a/higan/target-bsnes/program/program.cpp +++ b/higan/target-bsnes/program/program.cpp @@ -11,22 +11,31 @@ #include "utility.cpp" #include "patch.cpp" #include "hacks.cpp" -unique_pointer program; +Program program; -Program::Program(vector arguments) { - program = this; +auto Program::create(vector arguments) -> void { Emulator::platform = this; - new Presentation; - presentation->setVisible(); - - new InputManager; - new SettingsWindow; - new CheatDatabase; - new CheatWindow; - new StateWindow; - new ToolsWindow; aboutWindow.create(); + presentation.create(); + presentation.setVisible(); + + videoSettings.create(); + audioSettings.create(); + inputSettings.create(); + hotkeySettings.create(); + pathSettings.create(); + emulatorSettings.create(); + driverSettings.create(); + settingsWindow.create(); + + cheatDatabase.create(); + cheatWindow.create(); + cheatEditor.create(); + stateWindow.create(); + stateManager.create(); + manifestViewer.create(); + toolsWindow.create(); if(settings["Crashed"].boolean()) { MessageDialog( @@ -40,20 +49,20 @@ Program::Program(vector arguments) { settings["Crashed"].setValue(true); settings.save(); - updateVideoDriver(*presentation); - updateAudioDriver(*presentation); - updateInputDriver(*presentation); + updateVideoDriver(presentation); + updateAudioDriver(presentation); + updateInputDriver(presentation); settings["Crashed"].setValue(false); settings.save(); - settingsWindow->drivers.videoDriverChanged(); - settingsWindow->drivers.audioDriverChanged(); - settingsWindow->drivers.inputDriverChanged(); + driverSettings.videoDriverChanged(); + driverSettings.audioDriverChanged(); + driverSettings.inputDriverChanged(); arguments.takeLeft(); //ignore program location in argument parsing for(auto& argument : arguments) { if(argument == "--fullscreen") { - presentation->toggleFullscreenMode(); + presentation.toggleFullscreenMode(); } else if(inode::exists(argument)) { gameQueue.append(argument); } @@ -68,8 +77,8 @@ auto Program::main() -> void { updateStatus(); video.poll(); - inputManager->poll(); - inputManager->pollHotkeys(); + inputManager.poll(); + inputManager.pollHotkeys(); if(paused()) { audio.clear(); @@ -78,7 +87,7 @@ auto Program::main() -> void { } emulator->run(); - if(settingsWindow->configuration.autoSaveMemory.checked()) { + if(emulatorSettings.autoSaveMemory.checked()) { auto currentTime = chrono::timestamp(); if(currentTime - autoSaveTime >= settings["Emulator/AutoSaveMemory/Interval"].natural()) { autoSaveTime = currentTime; diff --git a/higan/target-bsnes/program/program.hpp b/higan/target-bsnes/program/program.hpp index 5eb23aff..660bc44e 100644 --- a/higan/target-bsnes/program/program.hpp +++ b/higan/target-bsnes/program/program.hpp @@ -2,7 +2,7 @@ struct Program : Emulator::Platform { Application::Namespace tr{"Program"}; //program.cpp - Program(vector arguments); + auto create(vector arguments) -> void; auto main() -> void; auto quit() -> void; @@ -147,4 +147,4 @@ public: string statusFrameRate; }; -extern unique_pointer program; +extern Program program; diff --git a/higan/target-bsnes/program/states.cpp b/higan/target-bsnes/program/states.cpp index 49af5cab..11a38b2e 100644 --- a/higan/target-bsnes/program/states.cpp +++ b/higan/target-bsnes/program/states.cpp @@ -108,7 +108,7 @@ auto Program::saveState(string filename) -> bool { output.append(location, s.data(), s.size()); } - if(filename.beginsWith("quick/")) presentation->updateStateMenus(); + if(filename.beginsWith("quick/")) presentation.updateStateMenus(); return showMessage({"Saved [", prefix, "]"}), true; } diff --git a/higan/target-bsnes/program/utility.cpp b/higan/target-bsnes/program/utility.cpp index 38d5c364..98c49a34 100644 --- a/higan/target-bsnes/program/utility.cpp +++ b/higan/target-bsnes/program/utility.cpp @@ -12,22 +12,22 @@ auto Program::updateStatus() -> void { if(chrono::timestamp() - statusTime <= 2) { message = statusMessage; } - if(message != presentation->statusLeft.text()) { - presentation->statusLeft.setText(message); + if(message != presentation.statusLeft.text()) { + presentation.statusLeft.setText(message); } string frameRate; if(!emulator->loaded()) { frameRate = tr("Unloaded"); - } else if(presentation->pauseEmulation.checked()) { + } else if(presentation.pauseEmulation.checked()) { frameRate = tr("Paused"); - } else if(!focused() && settingsWindow->configuration.pauseEmulation.checked()) { + } else if(!focused() && emulatorSettings.pauseEmulation.checked()) { frameRate = tr("Paused"); } else { frameRate = statusFrameRate; } - if(frameRate != presentation->statusRight.text()) { - presentation->statusRight.setText(frameRate); + if(frameRate != presentation.statusRight.text()) { + presentation.statusRight.setText(frameRate); } } @@ -47,14 +47,14 @@ auto Program::captureScreenshot() -> bool { auto Program::paused() -> bool { if(!emulator->loaded()) return true; - if(presentation->pauseEmulation.checked()) return true; - if(!focused() && settingsWindow->configuration.pauseEmulation.checked()) return true; + if(presentation.pauseEmulation.checked()) return true; + if(!focused() && emulatorSettings.pauseEmulation.checked()) return true; return false; } auto Program::focused() -> bool { //exclusive mode creates its own top-level window: presentation window will not have focus if(video && video.exclusive()) return true; - if(presentation && presentation->focused()) return true; + if(presentation.focused()) return true; return false; } diff --git a/higan/target-bsnes/program/video.cpp b/higan/target-bsnes/program/video.cpp index c09e48f3..99366674 100644 --- a/higan/target-bsnes/program/video.cpp +++ b/higan/target-bsnes/program/video.cpp @@ -1,7 +1,7 @@ auto Program::updateVideoDriver(Window parent) -> void { auto changed = (bool)video; video.create(settings["Video/Driver"].text()); - video.setContext(presentation->viewport.handle()); + video.setContext(presentation.viewport.handle()); if(changed) { settings["Video/Format"].setValue(video.format()); } @@ -12,12 +12,12 @@ auto Program::updateVideoDriver(Window parent) -> void { updateVideoShader(); if(video.ready()) { - presentation->clearViewport(); + presentation.clearViewport(); updateVideoShader(); } video.onUpdate([&](uint width, uint height) { - if(!emulator->loaded()) presentation->clearViewport(); + if(!emulator->loaded()) presentation.clearViewport(); }); if(!video.ready()) { @@ -28,7 +28,7 @@ auto Program::updateVideoDriver(Window parent) -> void { return updateVideoDriver(parent); } - presentation->updateShaders(); + presentation.updateShaders(); } auto Program::updateVideoExclusive() -> void { diff --git a/higan/target-bsnes/settings/audio.cpp b/higan/target-bsnes/settings/audio.cpp index 9826c200..d2babee7 100644 --- a/higan/target-bsnes/settings/audio.cpp +++ b/higan/target-bsnes/settings/audio.cpp @@ -1,4 +1,4 @@ -AudioSettings::AudioSettings(TabFrame* parent) : TabFrameItem(parent) { +auto AudioSettings::create() -> void { setIcon(Icon::Device::Speaker); setText("Audio"); @@ -13,7 +13,7 @@ AudioSettings::AudioSettings(TabFrame* parent) : TabFrameItem(parent) { string value = {skewSlider.position() > 5000 ? "+" : "", (int)skewSlider.position() - 5000}; settings["Audio/Skew"].setValue(value); skewValue.setText(value); - if(audio) program->updateAudioFrequency(); + program.updateAudioFrequency(); }).doChange(); volumeLabel.setText("Volume:"); volumeValue.setAlignment(0.5); @@ -21,7 +21,7 @@ AudioSettings::AudioSettings(TabFrame* parent) : TabFrameItem(parent) { string value = {volumeSlider.position(), "%"}; settings["Audio/Volume"].setValue(value); volumeValue.setText(value); - if(audio) program->updateAudioEffects(); + program.updateAudioEffects(); }).doChange(); balanceLabel.setText("Balance:"); balanceValue.setAlignment(0.5); @@ -29,6 +29,6 @@ AudioSettings::AudioSettings(TabFrame* parent) : TabFrameItem(parent) { string value = {balanceSlider.position(), "%"}; settings["Audio/Balance"].setValue(value); balanceValue.setText(value); - if(audio) program->updateAudioEffects(); + program.updateAudioEffects(); }).doChange(); } diff --git a/higan/target-bsnes/settings/drivers.cpp b/higan/target-bsnes/settings/drivers.cpp index cf861671..fb814e99 100644 --- a/higan/target-bsnes/settings/drivers.cpp +++ b/higan/target-bsnes/settings/drivers.cpp @@ -1,4 +1,4 @@ -DriverSettings::DriverSettings(TabFrame* parent) : TabFrameItem(parent) { +auto DriverSettings::create() -> void { setIcon(Icon::Place::Settings); setText("Drivers"); @@ -8,29 +8,29 @@ DriverSettings::DriverSettings(TabFrame* parent) : TabFrameItem(parent) { videoLayout.setSize({2, 2}); videoDriverLabel.setText("Driver:"); videoDriverOption.onChange([&] { - videoDriverUpdate.setEnabled(videoDriverOption.selected().text() != video.driverName()); + videoDriverUpdate.setEnabled(videoDriverOption.selected().text() != video.driver()); }); videoDriverUpdate.setText("Change").onActivate([&] { videoDriverChange(); }); videoFormatLabel.setText("Format:"); videoFormatOption.onChange([&] { videoFormatChange(); }); videoExclusiveToggle.setText("Exclusive fullscreen").onToggle([&] { settings["Video/Exclusive"].setValue(videoExclusiveToggle.checked()); - program->updateVideoExclusive(); + program.updateVideoExclusive(); }); videoBlockingToggle.setText("Synchronize").onToggle([&] { settings["Video/Blocking"].setValue(videoBlockingToggle.checked()); - program->updateVideoBlocking(); + program.updateVideoBlocking(); }); videoFlushToggle.setText("GPU sync").onToggle([&] { settings["Video/Flush"].setValue(videoFlushToggle.checked()); - program->updateVideoFlush(); + program.updateVideoFlush(); }); audioLabel.setText("Audio").setFont(Font().setBold()); audioLayout.setSize({2, 2}); audioDriverLabel.setText("Driver:"); audioDriverOption.onChange([&] { - audioDriverUpdate.setEnabled(audioDriverOption.selected().text() != audio.driverName()); + audioDriverUpdate.setEnabled(audioDriverOption.selected().text() != audio.driver()); }); audioDriverUpdate.setText("Change").onActivate([&] { audioDriverChange(); }); audioDeviceLabel.setText("Device:"); @@ -41,29 +41,29 @@ DriverSettings::DriverSettings(TabFrame* parent) : TabFrameItem(parent) { audioLatencyOption.onChange([&] { audioLatencyChange(); }); audioExclusiveToggle.setText("Exclusive").onToggle([&] { settings["Audio/Exclusive"].setValue(audioExclusiveToggle.checked()); - program->updateAudioExclusive(); + program.updateAudioExclusive(); }); audioBlockingToggle.setText("Synchronize").onToggle([&] { settings["Audio/Blocking"].setValue(audioBlockingToggle.checked()); - program->updateAudioBlocking(); + program.updateAudioBlocking(); }); audioDynamicToggle.setText("Dynamic rate").onToggle([&] { settings["Audio/Dynamic"].setValue(audioDynamicToggle.checked()); - program->updateAudioDynamic(); + program.updateAudioDynamic(); }); inputLabel.setText("Input").setFont(Font().setBold()); inputLayout.setSize({2, 1}); inputDriverLabel.setText("Driver:"); inputDriverOption.onChange([&] { - inputDriverUpdate.setEnabled(inputDriverOption.selected().text() != input.driverName()); + inputDriverUpdate.setEnabled(inputDriverOption.selected().text() != input.driver()); }); inputDriverUpdate.setText("Change").onActivate([&] { inputDriverChange(); }); - //hide video format for simplicity, as it's not very useful just yet ... - videoLayout.setSize({2, 1}); - videoLayout.remove(videoFormatLabel); - videoLayout.remove(videoPropertyLayout); + //this will hide the video format setting for simplicity, as it's not very useful just yet ... + //videoLayout.setSize({2, 1}); + //videoLayout.remove(videoFormatLabel); + //videoLayout.remove(videoPropertyLayout); } // @@ -73,9 +73,9 @@ auto DriverSettings::videoDriverChanged() -> void { for(auto& driver : video.hasDrivers()) { ComboButtonItem item{&videoDriverOption}; item.setText(driver); - if(driver == video.driverName()) item.setSelected(); + if(driver == video.driver()) item.setSelected(); } - videoDriverActive.setText({"Active driver: ", video.driverName()}); + videoDriverActive.setText({"Active driver: ", video.driver()}); videoDriverOption.doChange(); videoFormatChanged(); videoExclusiveToggle.setChecked(video.exclusive()).setEnabled(video.hasExclusive()); @@ -92,11 +92,11 @@ auto DriverSettings::videoDriverChange() -> void { "It is highly recommended you unload your game first to be safe.\n" "Do you wish to proceed with the video driver change now anyway?" ).setParent(*settingsWindow).question() == "Yes") { - program->save(); - program->saveUndoState(); + program.save(); + program.saveUndoState(); settings["Crashed"].setValue(true); settings.save(); - program->updateVideoDriver(*settingsWindow); + program.updateVideoDriver(settingsWindow); settings["Crashed"].setValue(false); settings.save(); videoDriverChanged(); @@ -127,9 +127,9 @@ auto DriverSettings::audioDriverChanged() -> void { for(auto& driver : audio.hasDrivers()) { ComboButtonItem item{&audioDriverOption}; item.setText(driver); - if(driver == audio.driverName()) item.setSelected(); + if(driver == audio.driver()) item.setSelected(); } - audioDriverActive.setText({"Active driver: ", audio.driverName()}); + audioDriverActive.setText({"Active driver: ", audio.driver()}); audioDriverOption.doChange(); audioDeviceChanged(); audioFrequencyChanged(); @@ -148,11 +148,11 @@ auto DriverSettings::audioDriverChange() -> void { "It is highly recommended you unload your game first to be safe.\n" "Do you wish to proceed with the audio driver change now anyway?" ).setParent(*settingsWindow).question() == "Yes") { - program->save(); - program->saveUndoState(); + program.save(); + program.saveUndoState(); settings["Crashed"].setValue(true); settings.save(); - program->updateAudioDriver(*settingsWindow); + program.updateAudioDriver(settingsWindow); settings["Crashed"].setValue(false); settings.save(); audioDriverChanged(); @@ -173,7 +173,7 @@ auto DriverSettings::audioDeviceChanged() -> void { auto DriverSettings::audioDeviceChange() -> void { auto item = audioDeviceOption.selected(); settings["Audio/Device"].setValue(item.text()); - program->updateAudioDevice(); + program.updateAudioDevice(); audioFrequencyChanged(); audioLatencyChanged(); } @@ -192,7 +192,7 @@ auto DriverSettings::audioFrequencyChanged() -> void { auto DriverSettings::audioFrequencyChange() -> void { auto item = audioFrequencyOption.selected(); settings["Audio/Frequency"].setValue(item.text()); - program->updateAudioFrequency(); + program.updateAudioFrequency(); } auto DriverSettings::audioLatencyChanged() -> void { @@ -209,7 +209,7 @@ auto DriverSettings::audioLatencyChanged() -> void { auto DriverSettings::audioLatencyChange() -> void { auto item = audioLatencyOption.selected(); settings["Audio/Latency"].setValue(item.text()); - program->updateAudioLatency(); + program.updateAudioLatency(); } // @@ -219,9 +219,9 @@ auto DriverSettings::inputDriverChanged() -> void { for(auto& driver : input.hasDrivers()) { ComboButtonItem item{&inputDriverOption}; item.setText(driver); - if(driver == input.driverName()) item.setSelected(); + if(driver == input.driver()) item.setSelected(); } - inputDriverActive.setText({"Active driver: ", input.driverName()}); + inputDriverActive.setText({"Active driver: ", input.driver()}); inputDriverOption.doChange(); layout.setGeometry(layout.geometry()); } @@ -234,11 +234,11 @@ auto DriverSettings::inputDriverChange() -> void { "It is highly recommended you unload your game first to be safe.\n" "Do you wish to proceed with the input driver change now anyway?" ).setParent(*settingsWindow).question() == "Yes") { - program->save(); - program->saveUndoState(); + program.save(); + program.saveUndoState(); settings["Crashed"].setValue(true); settings.save(); - program->updateInputDriver(*settingsWindow); + program.updateInputDriver(settingsWindow); settings["Crashed"].setValue(false); settings.save(); inputDriverChanged(); diff --git a/higan/target-bsnes/settings/configuration.cpp b/higan/target-bsnes/settings/emulator.cpp similarity index 94% rename from higan/target-bsnes/settings/configuration.cpp rename to higan/target-bsnes/settings/emulator.cpp index 89b3f85f..862d205a 100644 --- a/higan/target-bsnes/settings/configuration.cpp +++ b/higan/target-bsnes/settings/emulator.cpp @@ -1,6 +1,6 @@ -ConfigurationSettings::ConfigurationSettings(TabFrame* parent) : TabFrameItem(parent) { +auto EmulatorSettings::create() -> void { setIcon(Icon::Action::Settings); - setText("Configuration"); + setText("Emulator"); layout.setPadding(5); @@ -40,7 +40,7 @@ ConfigurationSettings::ConfigurationSettings(TabFrame* parent) : TabFrameItem(pa Application::setScreenSaver(!suppressScreenSaver.checked()); }); - hacksLabel.setText("Emulator Hacks").setFont(Font().setBold()); + hacksLabel.setText("Hacks").setFont(Font().setBold()); fastPPUOption.setText("Fast PPU").setChecked(settings["Emulator/Hack/FastPPU"].boolean()).onToggle([&] { settings["Emulator/Hack/FastPPU"].setValue(fastPPUOption.checked()); if(!fastPPUOption.checked()) { @@ -69,7 +69,7 @@ ConfigurationSettings::ConfigurationSettings(TabFrame* parent) : TabFrameItem(pa hacksNote.setForegroundColor({224, 0, 0}).setText("Note: some hack setting changes do not take effect until after reloading games."); } -auto ConfigurationSettings::updateConfiguration() -> void { +auto EmulatorSettings::updateConfiguration() -> void { emulator->configure("hacks/ppuFast/enable", fastPPUOption.checked()); emulator->configure("hacks/ppuFast/noSpriteLimit", noSpriteLimit.checked()); emulator->configure("hacks/ppuFast/hiresMode7", hiresMode7.checked()); diff --git a/higan/target-bsnes/settings/hotkeys.cpp b/higan/target-bsnes/settings/hotkeys.cpp index 08e49917..aa46c520 100644 --- a/higan/target-bsnes/settings/hotkeys.cpp +++ b/higan/target-bsnes/settings/hotkeys.cpp @@ -1,4 +1,4 @@ -HotkeySettings::HotkeySettings(TabFrame* parent) : TabFrameItem(parent) { +auto HotkeySettings::create() -> void { setIcon(Icon::Device::Keyboard); setText("Hotkeys"); @@ -17,7 +17,7 @@ HotkeySettings::HotkeySettings(TabFrame* parent) : TabFrameItem(parent) { }); clearButton.setText("Clear").onActivate([&] { for(auto item : mappingList.batched()) { - inputManager->hotkeys[item.offset()].unbind(); + inputManager.hotkeys[item.offset()].unbind(); } refreshMappings(); }); @@ -29,7 +29,7 @@ auto HotkeySettings::reloadMappings() -> void { .append(TableViewColumn().setText("Name")) .append(TableViewColumn().setText("Mapping").setExpandable()) ); - for(auto& hotkey : inputManager->hotkeys) { + for(auto& hotkey : inputManager.hotkeys) { mappingList.append(TableViewItem() .append(TableViewCell().setText(hotkey.name).setFont(Font().setBold()).setBackgroundColor({240, 240, 255})) .append(TableViewCell()) @@ -41,29 +41,29 @@ auto HotkeySettings::reloadMappings() -> void { auto HotkeySettings::refreshMappings() -> void { uint index = 0; - for(auto& hotkey : inputManager->hotkeys) { + for(auto& hotkey : inputManager.hotkeys) { mappingList.item(index++).cell(1).setText(hotkey.displayName()); } mappingList.resizeColumns(); } auto HotkeySettings::assignMapping() -> void { - inputManager->poll(); //clear any pending events first + inputManager.poll(); //clear any pending events first if(auto item = mappingList.selected()) { - activeMapping = inputManager->hotkeys[item.offset()]; - settingsWindow->layout.setEnabled(false); - settingsWindow->statusBar.setText({"Press a key or button to map [", activeMapping->name, "] ..."}); - settingsWindow->setDismissable(false); + activeMapping = inputManager.hotkeys[item.offset()]; + settingsWindow.layout.setEnabled(false); + settingsWindow.statusBar.setText({"Press a key or button to map [", activeMapping->name, "] ..."}); + settingsWindow.setDismissable(false); } } auto HotkeySettings::cancelMapping() -> void { activeMapping.reset(); - settingsWindow->statusBar.setText(); - settingsWindow->layout.setEnabled(); - settingsWindow->doSize(); - settingsWindow->setDismissable(true); + settingsWindow.statusBar.setText(); + settingsWindow.layout.setEnabled(); + settingsWindow.doSize(); + settingsWindow.setDismissable(true); } auto HotkeySettings::inputEvent(shared_pointer device, uint group, uint input, int16 oldValue, int16 newValue) -> void { @@ -72,7 +72,7 @@ auto HotkeySettings::inputEvent(shared_pointer device, uint group, if(activeMapping->bind(device, group, input, oldValue, newValue)) { activeMapping.reset(); - settingsWindow->statusBar.setText("Mapping assigned."); + settingsWindow.statusBar.setText("Mapping assigned."); refreshMappings(); timer.onActivate([&] { timer.setEnabled(false); diff --git a/higan/target-bsnes/settings/input.cpp b/higan/target-bsnes/settings/input.cpp index f6781596..e5cc196a 100644 --- a/higan/target-bsnes/settings/input.cpp +++ b/higan/target-bsnes/settings/input.cpp @@ -1,4 +1,4 @@ -InputSettings::InputSettings(TabFrame* parent) : TabFrameItem(parent) { +auto InputSettings::create() -> void { setIcon(Icon::Device::Joypad); setText("Input"); @@ -16,8 +16,8 @@ InputSettings::InputSettings(TabFrame* parent) : TabFrameItem(parent) { turboList.onChange([&] { uint frequency = turboList.selected().text().natural(); settings["Input/Turbo/Frequency"].setValue(frequency); - inputManager->turboCounter = 0; - inputManager->turboFrequency = frequency; + inputManager.turboCounter = 0; + inputManager.turboFrequency = frequency; }); mappingList.setBatchable(); mappingList.onActivate([&] { if(assignButton.enabled()) assignButton.doActivate(); }); @@ -58,7 +58,7 @@ auto InputSettings::updateControls() -> void { } auto InputSettings::activePort() -> InputPort& { - return inputManager->ports[portList.selected().offset()]; + return inputManager.ports[portList.selected().offset()]; } auto InputSettings::activeDevice() -> InputDevice& { @@ -68,7 +68,7 @@ auto InputSettings::activeDevice() -> InputDevice& { auto InputSettings::reloadPorts() -> void { portList.reset(); - for(auto& port : inputManager->ports) { + for(auto& port : inputManager.ports) { if(port.name == "Expansion Port") continue; portList.append(ComboButtonItem().setText(port.name)); } @@ -113,28 +113,28 @@ auto InputSettings::refreshMappings() -> void { } auto InputSettings::assignMapping() -> void { - inputManager->poll(); //clear any pending events first + inputManager.poll(); //clear any pending events first for(auto mapping : mappingList.batched()) { activeMapping = activeDevice().mappings[mapping.offset()]; - settingsWindow->layout.setEnabled(false); - settingsWindow->statusBar.setText({"Press a key or button to map [", activeMapping->name, "] ..."}); - settingsWindow->setDismissable(false); + settingsWindow.layout.setEnabled(false); + settingsWindow.statusBar.setText({"Press a key or button to map [", activeMapping->name, "] ..."}); + settingsWindow.setDismissable(false); } } auto InputSettings::cancelMapping() -> void { activeMapping.reset(); - settingsWindow->statusBar.setText(); - settingsWindow->layout.setEnabled(); - settingsWindow->doSize(); - settingsWindow->setDismissable(true); + settingsWindow.statusBar.setText(); + settingsWindow.layout.setEnabled(); + settingsWindow.doSize(); + settingsWindow.setDismissable(true); } auto InputSettings::assignMouseInput(uint id) -> void { if(auto mapping = mappingList.selected()) { activeMapping = activeDevice().mappings[mapping.offset()]; - if(auto mouse = inputManager->findMouse()) { + if(auto mouse = inputManager.findMouse()) { if(activeMapping->isDigital()) { return inputEvent(mouse, HID::Mouse::GroupID::Button, id, 0, 1, true); } else if(activeMapping->isAnalog()) { @@ -150,7 +150,7 @@ auto InputSettings::inputEvent(shared_pointer device, uint group, u if(activeMapping->bind(device, group, input, oldValue, newValue)) { activeMapping.reset(); - settingsWindow->statusBar.setText("Mapping assigned."); + settingsWindow.statusBar.setText("Mapping assigned."); refreshMappings(); timer.onActivate([&] { timer.setEnabled(false); diff --git a/higan/target-bsnes/settings/paths.cpp b/higan/target-bsnes/settings/paths.cpp index 621ce651..2c06ed99 100644 --- a/higan/target-bsnes/settings/paths.cpp +++ b/higan/target-bsnes/settings/paths.cpp @@ -1,4 +1,4 @@ -PathSettings::PathSettings(TabFrame* parent) : TabFrameItem(parent) { +auto PathSettings::create() -> void { setIcon(Icon::Emblem::Folder); setText("Paths"); diff --git a/higan/target-bsnes/settings/settings.cpp b/higan/target-bsnes/settings/settings.cpp index 95cb90aa..a66cf0c7 100644 --- a/higan/target-bsnes/settings/settings.cpp +++ b/higan/target-bsnes/settings/settings.cpp @@ -4,10 +4,17 @@ #include "input.cpp" #include "hotkeys.cpp" #include "paths.cpp" -#include "configuration.cpp" +#include "emulator.cpp" #include "drivers.cpp" Settings settings; -unique_pointer settingsWindow; +VideoSettings videoSettings; +AudioSettings audioSettings; +InputSettings inputSettings; +HotkeySettings hotkeySettings; +PathSettings pathSettings; +EmulatorSettings emulatorSettings; +DriverSettings driverSettings; +SettingsWindow settingsWindow; Settings::Settings() { Markup::Node::operator=(BML::unserialize(string::read(locate("settings.bml")))); @@ -84,10 +91,15 @@ auto Settings::save() -> void { file::write(locate("settings.bml"), BML::serialize(*this)); } -SettingsWindow::SettingsWindow() { - settingsWindow = this; - +auto SettingsWindow::create() -> void { layout.setPadding(5); + panel.append(videoSettings); + panel.append(audioSettings); + panel.append(inputSettings); + panel.append(hotkeySettings); + panel.append(pathSettings); + panel.append(emulatorSettings); + panel.append(driverSettings); statusBar.setFont(Font().setBold()); setTitle("Settings"); @@ -96,21 +108,21 @@ SettingsWindow::SettingsWindow() { setDismissable(); onSize([&] { - input.mappingList.resizeColumns(); - hotkeys.mappingList.resizeColumns(); + inputSettings.mappingList.resizeColumns(); + hotkeySettings.mappingList.resizeColumns(); }); onClose([&] { - if(input.activeMapping) input.cancelMapping(); - if(hotkeys.activeMapping) hotkeys.cancelMapping(); + if(inputSettings.activeMapping) inputSettings.cancelMapping(); + if(hotkeySettings.activeMapping) hotkeySettings.cancelMapping(); setVisible(false); }); } auto SettingsWindow::setVisible(bool visible) -> SettingsWindow& { if(visible) { - input.refreshMappings(); - hotkeys.refreshMappings(); + inputSettings.refreshMappings(); + hotkeySettings.refreshMappings(); } return Window::setVisible(visible), *this; } diff --git a/higan/target-bsnes/settings/settings.hpp b/higan/target-bsnes/settings/settings.hpp index c93b29fc..8c2e08a4 100644 --- a/higan/target-bsnes/settings/settings.hpp +++ b/higan/target-bsnes/settings/settings.hpp @@ -4,7 +4,7 @@ struct Settings : Markup::Node { }; struct VideoSettings : TabFrameItem { - VideoSettings(TabFrame*); + auto create() -> void; public: VerticalLayout layout{this}; @@ -24,7 +24,7 @@ public: }; struct AudioSettings : TabFrameItem { - AudioSettings(TabFrame*); + auto create() -> void; public: VerticalLayout layout{this}; @@ -44,7 +44,7 @@ public: }; struct InputSettings : TabFrameItem { - InputSettings(TabFrame*); + auto create() -> void; auto updateControls() -> void; auto activePort() -> InputPort&; auto activeDevice() -> InputDevice&; @@ -80,7 +80,7 @@ public: }; struct HotkeySettings : TabFrameItem { - HotkeySettings(TabFrame*); + auto create() -> void; auto reloadMappings() -> void; auto refreshMappings() -> void; auto assignMapping() -> void; @@ -100,7 +100,7 @@ public: }; struct PathSettings : TabFrameItem { - PathSettings(TabFrame*); + auto create() -> void; auto refreshPaths() -> void; public: @@ -136,8 +136,8 @@ public: Button screenshotsReset{&layout, Size{80, 0}}; }; -struct ConfigurationSettings : TabFrameItem { - ConfigurationSettings(TabFrame*); +struct EmulatorSettings : TabFrameItem { + auto create() -> void; auto updateConfiguration() -> void; public: @@ -155,6 +155,7 @@ public: CheckLabel autoSaveStateOnUnload{&autoStateLayout, Size{0, 0}}; CheckLabel autoLoadStateOnLoad{&autoStateLayout, Size{0, 0}}; CheckLabel suppressScreenSaver{&layout, Size{~0, 0}}; + Widget optionsSpacer{&layout, Size{~0, 10}}; Label hacksLabel{&layout, Size{~0, 0}, 2}; HorizontalLayout fastPPULayout{&layout, Size{~0, 0}}; CheckLabel fastPPUOption{&fastPPULayout, Size{0, 0}}; @@ -169,7 +170,7 @@ public: }; struct DriverSettings : TabFrameItem { - DriverSettings(TabFrame*); + auto create() -> void; auto videoDriverChanged() -> void; auto videoDriverChange() -> void; auto videoFormatChanged() -> void; @@ -201,6 +202,7 @@ public: CheckLabel videoExclusiveToggle{&videoToggleLayout, Size{0, 0}}; CheckLabel videoBlockingToggle{&videoToggleLayout, Size{0, 0}}; CheckLabel videoFlushToggle{&videoToggleLayout, Size{0, 0}}; + Widget videoSpacer{&layout, Size{~0, 10}}; Label audioLabel{&layout, Size{~0, 0}, 2}; TableLayout audioLayout{&layout, Size{~0, 0}}; Label audioDriverLabel{&audioLayout, Size{0, 0}}; @@ -219,6 +221,7 @@ public: CheckLabel audioExclusiveToggle{&audioToggleLayout, Size{0, 0}}; CheckLabel audioBlockingToggle{&audioToggleLayout, Size{0, 0}}; CheckLabel audioDynamicToggle{&audioToggleLayout, Size{0, 0}}; + Widget audioSpacer{&layout, Size{~0, 10}}; Label inputLabel{&layout, Size{~0, 0}, 2}; TableLayout inputLayout{&layout, Size{~0, 0}}; Label inputDriverLabel{&inputLayout, Size{0, 0}}; @@ -229,22 +232,22 @@ public: }; struct SettingsWindow : Window { - SettingsWindow(); + auto create() -> void; auto setVisible(bool visible = true) -> SettingsWindow&; auto show(uint index) -> void; public: VerticalLayout layout{this}; TabFrame panel{&layout, Size{~0, ~0}}; - VideoSettings video{&panel}; - AudioSettings audio{&panel}; - InputSettings input{&panel}; - HotkeySettings hotkeys{&panel}; - PathSettings paths{&panel}; - ConfigurationSettings configuration{&panel}; - DriverSettings drivers{&panel}; StatusBar statusBar{this}; }; extern Settings settings; -extern unique_pointer settingsWindow; +extern VideoSettings videoSettings; +extern AudioSettings audioSettings; +extern InputSettings inputSettings; +extern HotkeySettings hotkeySettings; +extern PathSettings pathSettings; +extern EmulatorSettings emulatorSettings; +extern DriverSettings driverSettings; +extern SettingsWindow settingsWindow; diff --git a/higan/target-bsnes/settings/video.cpp b/higan/target-bsnes/settings/video.cpp index b8620ae4..e3868230 100644 --- a/higan/target-bsnes/settings/video.cpp +++ b/higan/target-bsnes/settings/video.cpp @@ -1,4 +1,4 @@ -VideoSettings::VideoSettings(TabFrame* parent) : TabFrameItem(parent) { +auto VideoSettings::create() -> void { setIcon(Icon::Device::Display); setText("Video"); @@ -13,7 +13,7 @@ VideoSettings::VideoSettings(TabFrame* parent) : TabFrameItem(parent) { string value = {luminanceSlider.position(), "%"}; settings["Video/Luminance"].setValue(value); luminanceValue.setText(value); - program->updateVideoPalette(); + program.updateVideoPalette(); }).doChange(); saturationLabel.setText("Saturation:"); saturationValue.setAlignment(0.5); @@ -21,7 +21,7 @@ VideoSettings::VideoSettings(TabFrame* parent) : TabFrameItem(parent) { string value = {saturationSlider.position(), "%"}; settings["Video/Saturation"].setValue(value); saturationValue.setText(value); - program->updateVideoPalette(); + program.updateVideoPalette(); }).doChange(); gammaLabel.setText("Gamma:"); gammaValue.setAlignment(0.5); @@ -29,6 +29,6 @@ VideoSettings::VideoSettings(TabFrame* parent) : TabFrameItem(parent) { string value = {100 + gammaSlider.position(), "%"}; settings["Video/Gamma"].setValue(value); gammaValue.setText(value); - program->updateVideoPalette(); + program.updateVideoPalette(); }).doChange(); } diff --git a/higan/target-bsnes/tools/cheat-editor.cpp b/higan/target-bsnes/tools/cheat-editor.cpp index 9dc188b8..a9cf270a 100644 --- a/higan/target-bsnes/tools/cheat-editor.cpp +++ b/higan/target-bsnes/tools/cheat-editor.cpp @@ -1,6 +1,4 @@ -CheatDatabase::CheatDatabase() { - cheatDatabase = this; - +auto CheatDatabase::create() -> void { layout.setPadding(5); selectAllButton.setText("Select All").onActivate([&] { for(auto item : cheatList.items()) item.setChecked(true); @@ -44,7 +42,7 @@ auto CheatDatabase::findCheats() -> void { auto CheatDatabase::addCheats() -> void { for(auto item : cheatList.items()) { if(item.checked()) { - toolsWindow->cheatEditor.addCheat({item.text(), item.property("code"), false}); + cheatEditor.addCheat({item.text(), item.property("code"), false}); } } setVisible(false); @@ -52,9 +50,7 @@ auto CheatDatabase::addCheats() -> void { // -CheatWindow::CheatWindow() { - cheatWindow = this; - +auto CheatWindow::create() -> void { layout.setPadding(5); nameLabel.setText("Name:"); nameValue.onActivate([&] { if(acceptButton.enabled()) acceptButton.doActivate(); }); @@ -93,16 +89,16 @@ auto CheatWindow::doChange() -> void { auto CheatWindow::doAccept() -> void { Cheat cheat = {nameValue.text().strip(), codeValue.text().strip(), enableOption.checked()}; if(acceptButton.text() == "Add") { - toolsWindow->cheatEditor.addCheat(cheat); + cheatEditor.addCheat(cheat); } else { - toolsWindow->cheatEditor.editCheat(cheat); + cheatEditor.editCheat(cheat); } setVisible(false); } // -CheatEditor::CheatEditor(TabFrame* parent) : TabFrameItem(parent) { +auto CheatEditor::create() -> void { setIcon(Icon::Edit::Replace); setText("Cheat Editor"); @@ -123,23 +119,23 @@ CheatEditor::CheatEditor(TabFrame* parent) : TabFrameItem(parent) { } }); findCheatsButton.setText("Find Cheats ...").onActivate([&] { - cheatDatabase->findCheats(); + cheatDatabase.findCheats(); }); enableCheats.setText("Enable Cheats").setChecked(settings["Emulator/Cheats/Enable"].boolean()).onToggle([&] { settings["Emulator/Cheats/Enable"].setValue(enableCheats.checked()); if(!enableCheats.checked()) { - program->showMessage("All cheat codes disabled"); + program.showMessage("All cheat codes disabled"); } else { - program->showMessage("Active cheat codes enabled"); + program.showMessage("Active cheat codes enabled"); } synchronizeCodes(); }); addButton.setText("Add").onActivate([&] { - cheatWindow->show(); + cheatWindow.show(); }); editButton.setText("Edit").onActivate([&] { if(auto item = cheatList.selected()) { - cheatWindow->show(cheats[item.offset()]); + cheatWindow.show(cheats[item.offset()]); } }); removeButton.setText("Remove").onActivate([&] { @@ -203,7 +199,7 @@ auto CheatEditor::removeCheats() -> void { auto CheatEditor::loadCheats() -> void { cheats.reset(); - auto location = program->cheatPath(); + auto location = program.cheatPath(); auto document = BML::unserialize(string::read(location)); for(auto cheat : document.find("cheat")) { cheats.append({cheat["name"].text(), cheat["code"].text(), (bool)cheat["enable"]}); @@ -223,7 +219,7 @@ auto CheatEditor::saveCheats() -> void { document.append(" enable\n"); document.append("\n"); } - auto location = program->cheatPath(); + auto location = program.cheatPath(); if(document) { file::write(location, document); } else { diff --git a/higan/target-bsnes/tools/manifest-viewer.cpp b/higan/target-bsnes/tools/manifest-viewer.cpp index d9f79191..70abf8d8 100644 --- a/higan/target-bsnes/tools/manifest-viewer.cpp +++ b/higan/target-bsnes/tools/manifest-viewer.cpp @@ -1,4 +1,4 @@ -ManifestViewer::ManifestViewer(TabFrame* parent) : TabFrameItem(parent) { +auto ManifestViewer::create() -> void { setIcon(Icon::Emblem::Text); setText("Manifest Viewer"); @@ -15,6 +15,6 @@ auto ManifestViewer::loadManifest() -> void { } manifestView.setText(emulator->manifests().merge("\n")); - verifiedIcon.setIcon(program->verified() ? Icon::Emblem::Program : Icon::Emblem::Binary); - verifiedLabel.setText(program->verified() ? "Verified" : "Unverified"); + verifiedIcon.setIcon(program.verified() ? Icon::Emblem::Program : Icon::Emblem::Binary); + verifiedLabel.setText(program.verified() ? "Verified" : "Unverified"); } diff --git a/higan/target-bsnes/tools/state-manager.cpp b/higan/target-bsnes/tools/state-manager.cpp index 33c3b7af..3164f72a 100644 --- a/higan/target-bsnes/tools/state-manager.cpp +++ b/higan/target-bsnes/tools/state-manager.cpp @@ -1,6 +1,4 @@ -StateWindow::StateWindow() { - stateWindow = this; - +auto StateWindow::create() -> void { layout.setPadding(5); nameLabel.setText("Name:"); nameValue.onActivate([&] { @@ -48,7 +46,7 @@ auto StateWindow::doChange() -> void { || c == '|') valid = false; } if(auto input = nameValue.property("input")) { - if(name != input && file::exists({program->statePath(), "managed/", name, ".bst"})) valid = false; + if(name != input && file::exists({program.statePath(), "managed/", name, ".bst"})) valid = false; } nameValue.setBackgroundColor(valid ? Color{} : Color{255, 224, 224}); acceptButton.setEnabled(valid); @@ -56,14 +54,14 @@ auto StateWindow::doChange() -> void { auto StateWindow::doAccept() -> void { if(acceptButton.text() == "Add") { - toolsWindow->stateManager.createState(nameValue.text()); + stateManager.createState(nameValue.text()); } else { - toolsWindow->stateManager.modifyState(nameValue.text()); + stateManager.modifyState(nameValue.text()); } setVisible(false); } -StateManager::StateManager(TabFrame* parent) : TabFrameItem(parent) { +auto StateManager::create() -> void { setIcon(Icon::Application::FileManager); setText("State Manager"); @@ -82,22 +80,22 @@ StateManager::StateManager(TabFrame* parent) : TabFrameItem(parent) { loadButton.setText("Load").onActivate([&] { if(auto item = stateList.selected()) { string filename = {"managed/", item.cell(0).text()}; - program->loadState(filename); + program.loadState(filename); } }); saveButton.setText("Save").onActivate([&] { if(auto item = stateList.selected()) { string filename = {"managed/", item.cell(0).text()}; - program->saveState(filename); - item.cell(1).setText(chrono::local::datetime(program->stateTimestamp(filename))); + program.saveState(filename); + item.cell(1).setText(chrono::local::datetime(program.stateTimestamp(filename))); } }); addButton.setText("Add").onActivate([&] { - stateWindow->show(); + stateWindow.show(); }); editButton.setText("Edit").onActivate([&] { if(auto item = stateList.selected()) { - stateWindow->show(item.cell(0).text()); + stateWindow.show(item.cell(0).text()); } }); removeButton.setText("Remove").onActivate([&] { @@ -111,17 +109,17 @@ auto StateManager::loadStates() -> void { .append(TableViewColumn().setText("Name").setExpandable()) .append(TableViewColumn().setText("Date").setForegroundColor({160, 160, 160})) ); - for(auto& filename : program->availableStates("managed/")) { + for(auto& filename : program.availableStates("managed/")) { stateList.append(TableViewItem() .append(TableViewCell().setText(string{filename}.trimLeft("managed/", 1L))) - .append(TableViewCell().setText(chrono::local::datetime(program->stateTimestamp(filename)))) + .append(TableViewCell().setText(chrono::local::datetime(program.stateTimestamp(filename)))) ); } stateList.resizeColumns().doChange(); } auto StateManager::createState(string name) -> void { - program->saveState({"managed/", name}); + program.saveState({"managed/", name}); loadStates(); for(auto& item : stateList.items()) { if(item.cell(0).text() == name) item.setSelected(); @@ -134,7 +132,7 @@ auto StateManager::modifyState(string name) -> void { string from = {"managed/", item.cell(0).text()}; string to = {"managed/", name}; if(from != to) { - program->renameState(from, to); + program.renameState(from, to); loadStates(); for(auto& item : stateList.items()) { if(item.cell(0).text() == name) item.setSelected(); @@ -149,7 +147,7 @@ auto StateManager::removeStates() -> void { if(MessageDialog("Are you sure you want to permanently remove the selected state(s)?") .setParent(*toolsWindow).question() == "Yes") { for(auto& item : batched) { - program->removeState({"managed/", item.cell(0).text()}); + program.removeState({"managed/", item.cell(0).text()}); } loadStates(); } diff --git a/higan/target-bsnes/tools/tools.cpp b/higan/target-bsnes/tools/tools.cpp index fe6d0d0f..427b63cf 100644 --- a/higan/target-bsnes/tools/tools.cpp +++ b/higan/target-bsnes/tools/tools.cpp @@ -2,15 +2,19 @@ #include "cheat-editor.cpp" #include "state-manager.cpp" #include "manifest-viewer.cpp" -unique_pointer cheatDatabase; -unique_pointer cheatWindow; -unique_pointer stateWindow; -unique_pointer toolsWindow; - -ToolsWindow::ToolsWindow() { - toolsWindow = this; +CheatDatabase cheatDatabase; +CheatWindow cheatWindow; +CheatEditor cheatEditor; +StateWindow stateWindow; +StateManager stateManager; +ManifestViewer manifestViewer; +ToolsWindow toolsWindow; +auto ToolsWindow::create() -> void { layout.setPadding(5); + panel.append(cheatEditor); + panel.append(stateManager); + panel.append(manifestViewer); setTitle("Tools"); setSize({600, 400}); @@ -30,15 +34,15 @@ ToolsWindow::ToolsWindow() { auto ToolsWindow::setVisible(bool visible) -> ToolsWindow& { Window::setVisible(visible); if(!visible) { - cheatDatabase->setVisible(false); - cheatWindow->setVisible(false); - stateWindow->setVisible(false); + cheatDatabase.setVisible(false); + cheatWindow.setVisible(false); + stateWindow.setVisible(false); } return *this; } auto ToolsWindow::show(uint index) -> void { - panel.item(index)->setSelected(); + panel.item(index).setSelected(); setVisible(); setFocused(); doSize(); diff --git a/higan/target-bsnes/tools/tools.hpp b/higan/target-bsnes/tools/tools.hpp index fd556138..512eb06b 100644 --- a/higan/target-bsnes/tools/tools.hpp +++ b/higan/target-bsnes/tools/tools.hpp @@ -13,7 +13,7 @@ struct Cheat { }; struct CheatDatabase : Window { - CheatDatabase(); + auto create() -> void; auto findCheats() -> void; auto addCheats() -> void; @@ -28,7 +28,7 @@ public: }; struct CheatWindow : Window { - CheatWindow(); + auto create() -> void; auto show(Cheat cheat = {}) -> void; auto doChange() -> void; auto doAccept() -> void; @@ -49,7 +49,7 @@ public: }; struct CheatEditor : TabFrameItem { - CheatEditor(TabFrame*); + auto create() -> void; auto refresh() -> void; auto addCheat(Cheat cheat) -> void; auto editCheat(Cheat cheat) -> void; @@ -73,7 +73,7 @@ public: }; struct StateWindow : Window { - StateWindow(); + auto create() -> void; auto show(string name = {}) -> void; auto doChange() -> void; auto doAccept() -> void; @@ -90,7 +90,7 @@ public: }; struct StateManager : TabFrameItem { - StateManager(TabFrame*); + auto create() -> void; auto loadStates() -> void; auto createState(string name) -> void; auto modifyState(string name) -> void; @@ -109,7 +109,7 @@ public: }; struct ManifestViewer : TabFrameItem { - ManifestViewer(TabFrame*); + auto create() -> void; auto loadManifest() -> void; public: @@ -121,19 +121,19 @@ public: }; struct ToolsWindow : Window { - ToolsWindow(); + auto create() -> void; auto setVisible(bool visible = true) -> ToolsWindow&; auto show(uint index) -> void; public: VerticalLayout layout{this}; TabFrame panel{&layout, Size{~0, ~0}}; - CheatEditor cheatEditor{&panel}; - StateManager stateManager{&panel}; - ManifestViewer manifestViewer{&panel}; }; -extern unique_pointer cheatDatabase; -extern unique_pointer cheatWindow; -extern unique_pointer stateWindow; -extern unique_pointer toolsWindow; +extern CheatDatabase cheatDatabase; +extern CheatWindow cheatWindow; +extern CheatEditor cheatEditor; +extern StateWindow stateWindow; +extern StateManager stateManager; +extern ManifestViewer manifestViewer; +extern ToolsWindow toolsWindow; diff --git a/hiro/cocoa/object.cpp b/hiro/cocoa/object.cpp index 3e93e050..3c6ac442 100644 --- a/hiro/cocoa/object.cpp +++ b/hiro/cocoa/object.cpp @@ -27,9 +27,6 @@ auto pObject::setFocused() -> void { auto pObject::setFont(const Font& font) -> void { } -auto pObject::setParent(mObject* parent, int offset) -> void { -} - auto pObject::setVisible(bool visible) -> void { } diff --git a/hiro/cocoa/object.hpp b/hiro/cocoa/object.hpp index ae3f1af3..7f04a5af 100644 --- a/hiro/cocoa/object.hpp +++ b/hiro/cocoa/object.hpp @@ -16,7 +16,6 @@ struct pObject : mLock { virtual auto setEnabled(bool enabled) -> void; virtual auto setFocused() -> void; virtual auto setFont(const Font& font) -> void; - virtual auto setParent(mObject* parent, int offset) -> void; virtual auto setVisible(bool visible) -> void; mObject& reference; diff --git a/hiro/core/action/menu.cpp b/hiro/core/action/menu.cpp index 4444e293..a184d2fc 100644 --- a/hiro/core/action/menu.cpp +++ b/hiro/core/action/menu.cpp @@ -29,7 +29,7 @@ auto mMenu::actions() const -> vector { auto mMenu::append(sAction action) -> type& { state.actions.append(action); action->setParent(this, actionCount() - 1); - signal(append, *action); + signal(append, action); return *this; } @@ -38,7 +38,7 @@ auto mMenu::icon() const -> image { } auto mMenu::remove(sAction action) -> type& { - signal(remove, *action); + signal(remove, action); state.actions.remove(action->offset()); for(auto n : range(action->offset(), actionCount())) { state.actions[n]->adjustOffset(-1); diff --git a/hiro/core/menu-bar.cpp b/hiro/core/menu-bar.cpp index 958ad60b..8c653b4b 100644 --- a/hiro/core/menu-bar.cpp +++ b/hiro/core/menu-bar.cpp @@ -40,7 +40,7 @@ auto mMenuBar::remove() -> type& { auto mMenuBar::remove(sMenu menu) -> type& { signed offset = menu->offset(); - signal(remove, *menu); + signal(remove, menu); state.menus.remove(offset); for(auto n : range(offset, menuCount())) { state.menus[n]->adjustOffset(-1); diff --git a/hiro/core/object.cpp b/hiro/core/object.cpp index 505418d6..a29e2de1 100644 --- a/hiro/core/object.cpp +++ b/hiro/core/object.cpp @@ -298,7 +298,6 @@ auto mObject::setGroup(sGroup group) -> type& { } auto mObject::setParent(mObject* parent, int offset) -> type& { - signal(setParent, parent, offset); destruct(); state.parent = parent; state.offset = offset; diff --git a/hiro/core/widget/combo-button.cpp b/hiro/core/widget/combo-button.cpp index 8291a742..ded7fdfb 100644 --- a/hiro/core/widget/combo-button.cpp +++ b/hiro/core/widget/combo-button.cpp @@ -23,12 +23,12 @@ auto mComboButton::doChange() const -> void { if(state.onChange) return state.onChange(); } -auto mComboButton::item(unsigned position) const -> ComboButtonItem { +auto mComboButton::item(uint position) const -> ComboButtonItem { if(position < itemCount()) return state.items[position]; return {}; } -auto mComboButton::itemCount() const -> unsigned { +auto mComboButton::itemCount() const -> uint { return state.items.size(); } @@ -46,7 +46,7 @@ auto mComboButton::onChange(const function& callback) -> type& { auto mComboButton::remove(sComboButtonItem item) -> type& { signal(remove, item); state.items.remove(item->offset()); - for(auto n : range(item->offset(), itemCount())) { + for(uint n : range(item->offset(), itemCount())) { state.items[n]->adjustOffset(-1); } item->setParent(); @@ -54,9 +54,7 @@ auto mComboButton::remove(sComboButtonItem item) -> type& { } auto mComboButton::reset() -> type& { - signal(reset); - for(auto& item : state.items) item->setParent(); - state.items.reset(); + while(state.items) remove(state.items.last()); return *this; } @@ -67,8 +65,8 @@ auto mComboButton::selected() const -> ComboButtonItem { return {}; } -auto mComboButton::setParent(mObject* parent, signed offset) -> type& { - for(auto& item : state.items) item->destruct(); +auto mComboButton::setParent(mObject* parent, int offset) -> type& { + for(auto& item : reverse(state.items)) item->destruct(); mObject::setParent(parent, offset); for(auto& item : state.items) item->setParent(this, item->offset()); return *this; diff --git a/hiro/gtk/object.cpp b/hiro/gtk/object.cpp index 3e93e050..3c6ac442 100644 --- a/hiro/gtk/object.cpp +++ b/hiro/gtk/object.cpp @@ -27,9 +27,6 @@ auto pObject::setFocused() -> void { auto pObject::setFont(const Font& font) -> void { } -auto pObject::setParent(mObject* parent, int offset) -> void { -} - auto pObject::setVisible(bool visible) -> void { } diff --git a/hiro/gtk/object.hpp b/hiro/gtk/object.hpp index ae3f1af3..7f04a5af 100644 --- a/hiro/gtk/object.hpp +++ b/hiro/gtk/object.hpp @@ -16,7 +16,6 @@ struct pObject : mLock { virtual auto setEnabled(bool enabled) -> void; virtual auto setFocused() -> void; virtual auto setFont(const Font& font) -> void; - virtual auto setParent(mObject* parent, int offset) -> void; virtual auto setVisible(bool visible) -> void; mObject& reference; diff --git a/hiro/gtk/widget/tab-frame-item.cpp b/hiro/gtk/widget/tab-frame-item.cpp index 348d3b4b..eb281a9c 100644 --- a/hiro/gtk/widget/tab-frame-item.cpp +++ b/hiro/gtk/widget/tab-frame-item.cpp @@ -3,6 +3,7 @@ namespace hiro { auto pTabFrameItem::construct() -> void { + if(auto parent = _parent()) parent->_append(); if(auto& sizable = state().sizable) sizable->construct(); } diff --git a/hiro/gtk/widget/tab-frame.cpp b/hiro/gtk/widget/tab-frame.cpp index 6777e79f..5dfd501a 100644 --- a/hiro/gtk/widget/tab-frame.cpp +++ b/hiro/gtk/widget/tab-frame.cpp @@ -63,36 +63,6 @@ auto pTabFrame::destruct() -> void { auto pTabFrame::append(sTabFrameItem item) -> void { lock(); - Tab tab; - tab.child = gtk_fixed_new(); - #if HIRO_GTK==2 - tab.container = gtk_hbox_new(false, 0); - #elif HIRO_GTK==3 - tab.container = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); - #endif - tab.image = gtk_image_new(); - tab.title = gtk_label_new(""); - gtk_misc_set_alignment(GTK_MISC(tab.title), 0.0, 0.5); - tab.close = gtk_button_new_with_label("\u00d7"); //Unicode multiplication sign (looks better than 'X') - gtk_button_set_focus_on_click(GTK_BUTTON(tab.close), false); - gtk_button_set_relief(GTK_BUTTON(tab.close), GTK_RELIEF_NONE); - pFont::setFont(tab.close, Font("sans", 9).setBold()); - auto color = CreateColor({255, 0, 0}); - gtk_widget_modify_fg(gtk_bin_get_child(GTK_BIN(tab.close)), GTK_STATE_PRELIGHT, &color); - tabs.append(tab); - - gtk_widget_show(tab.child); - gtk_widget_show(tab.container); - gtk_widget_show(tab.image); - gtk_widget_show(tab.title); - gtk_widget_show(tab.close); - gtk_box_pack_start(GTK_BOX(tab.container), tab.image, false, false, 0); - gtk_box_pack_start(GTK_BOX(tab.container), tab.title, true, true, 0); - gtk_box_pack_start(GTK_BOX(tab.container), tab.close, false, false, 0); - - g_signal_connect(G_OBJECT(tab.close), "clicked", G_CALLBACK(TabFrame_close), (gpointer)this); - gtk_notebook_append_page(GTK_NOTEBOOK(gtkWidget), tab.child, tab.container); - setFont(self().font(true)); setItemMovable(item->offset(), item->movable()); if(item->selected()) setItemSelected(item->offset()); @@ -210,6 +180,42 @@ auto pTabFrame::setNavigation(Navigation navigation) -> void { setGeometry(self().geometry()); } +//called by pTabFrameItem::construct(), before pTabFrame::append() +//tab needs to be created early, so that pTabFrameItem child widgets calling pWidget::container() can find the tab +auto pTabFrame::_append() -> void { + lock(); + Tab tab; + tab.child = gtk_fixed_new(); + #if HIRO_GTK==2 + tab.container = gtk_hbox_new(false, 0); + #elif HIRO_GTK==3 + tab.container = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); + #endif + tab.image = gtk_image_new(); + tab.title = gtk_label_new(""); + gtk_misc_set_alignment(GTK_MISC(tab.title), 0.0, 0.5); + tab.close = gtk_button_new_with_label("\u00d7"); //Unicode multiplication sign (looks better than 'X') + gtk_button_set_focus_on_click(GTK_BUTTON(tab.close), false); + gtk_button_set_relief(GTK_BUTTON(tab.close), GTK_RELIEF_NONE); + pFont::setFont(tab.close, Font("sans", 9).setBold()); + auto color = CreateColor({255, 0, 0}); + gtk_widget_modify_fg(gtk_bin_get_child(GTK_BIN(tab.close)), GTK_STATE_PRELIGHT, &color); + tabs.append(tab); + + gtk_widget_show(tab.child); + gtk_widget_show(tab.container); + gtk_widget_show(tab.image); + gtk_widget_show(tab.title); + gtk_widget_show(tab.close); + gtk_box_pack_start(GTK_BOX(tab.container), tab.image, false, false, 0); + gtk_box_pack_start(GTK_BOX(tab.container), tab.title, true, true, 0); + gtk_box_pack_start(GTK_BOX(tab.container), tab.close, false, false, 0); + + g_signal_connect(G_OBJECT(tab.close), "clicked", G_CALLBACK(TabFrame_close), (gpointer)this); + gtk_notebook_append_page(GTK_NOTEBOOK(gtkWidget), tab.child, tab.container); + unlock(); +} + auto pTabFrame::_synchronizeLayout() -> void { for(auto& item : state().items) { if(auto& sizable = item->state.sizable) { diff --git a/hiro/gtk/widget/tab-frame.hpp b/hiro/gtk/widget/tab-frame.hpp index deba721d..f61b0b6a 100644 --- a/hiro/gtk/widget/tab-frame.hpp +++ b/hiro/gtk/widget/tab-frame.hpp @@ -18,6 +18,7 @@ struct pTabFrame : pWidget { auto setItemText(unsigned position, const string& text) -> void; auto setNavigation(Navigation navigation) -> void; + auto _append() -> void; auto _synchronizeLayout() -> void; auto _synchronizeTab(unsigned position) -> void; auto _tabHeight() -> unsigned; diff --git a/hiro/qt/object.cpp b/hiro/qt/object.cpp index 3e93e050..3c6ac442 100644 --- a/hiro/qt/object.cpp +++ b/hiro/qt/object.cpp @@ -27,9 +27,6 @@ auto pObject::setFocused() -> void { auto pObject::setFont(const Font& font) -> void { } -auto pObject::setParent(mObject* parent, int offset) -> void { -} - auto pObject::setVisible(bool visible) -> void { } diff --git a/hiro/qt/object.hpp b/hiro/qt/object.hpp index ae3f1af3..7f04a5af 100644 --- a/hiro/qt/object.hpp +++ b/hiro/qt/object.hpp @@ -16,7 +16,6 @@ struct pObject : mLock { virtual auto setEnabled(bool enabled) -> void; virtual auto setFocused() -> void; virtual auto setFont(const Font& font) -> void; - virtual auto setParent(mObject* parent, int offset) -> void; virtual auto setVisible(bool visible) -> void; mObject& reference; diff --git a/hiro/qt/widget/table-view-column.cpp b/hiro/qt/widget/table-view-column.cpp index d5a5419d..90d24ef7 100644 --- a/hiro/qt/widget/table-view-column.cpp +++ b/hiro/qt/widget/table-view-column.cpp @@ -3,6 +3,7 @@ namespace hiro { auto pTableViewColumn::construct() -> void { + if(auto header = _parent()) header->_setState(); } auto pTableViewColumn::destruct() -> void { @@ -44,10 +45,6 @@ auto pTableViewColumn::setIcon(const image& icon) -> void { //unsupported } -auto pTableViewColumn::setParent(mObject* parent, int offset) -> void { - if(auto header = _parent()) header->_setState(); -} - auto pTableViewColumn::setResizable(bool resizable) -> void { _setState(); } diff --git a/hiro/qt/widget/table-view-column.hpp b/hiro/qt/widget/table-view-column.hpp index 1519ce6b..f3933e11 100644 --- a/hiro/qt/widget/table-view-column.hpp +++ b/hiro/qt/widget/table-view-column.hpp @@ -14,7 +14,6 @@ struct pTableViewColumn : pObject { auto setForegroundColor(Color color) -> void; auto setHorizontalAlignment(double alignment) -> void; auto setIcon(const image& icon) -> void; - auto setParent(mObject* parent, int offset) -> void override; auto setResizable(bool resizable) -> void; auto setSortable(bool sortable) -> void; auto setText(const string& text) -> void; diff --git a/hiro/windows/object.cpp b/hiro/windows/object.cpp index 02afbbf0..4cf170d7 100644 --- a/hiro/windows/object.cpp +++ b/hiro/windows/object.cpp @@ -33,9 +33,6 @@ auto pObject::setFont(const Font& font) -> void { auto pObject::setGroup(sGroup group) -> void { } -auto pObject::setParent(mObject* parent, int offset) -> void { -} - auto pObject::setVisible(bool visible) -> void { } diff --git a/hiro/windows/object.hpp b/hiro/windows/object.hpp index 4fefe84f..470ef8ea 100644 --- a/hiro/windows/object.hpp +++ b/hiro/windows/object.hpp @@ -16,7 +16,6 @@ struct pObject : mLock { virtual auto setFocused() -> void; virtual auto setFont(const Font& font) -> void; virtual auto setGroup(sGroup group) -> void; - virtual auto setParent(mObject* parent, int offset) -> void; virtual auto setVisible(bool visible) -> void; mObject& reference; diff --git a/ruby/audio/audio.cpp b/ruby/audio/audio.cpp index 21200187..6da2f2b7 100644 --- a/ruby/audio/audio.cpp +++ b/ruby/audio/audio.cpp @@ -41,144 +41,144 @@ namespace ruby { auto Audio::setExclusive(bool exclusive) -> bool { - if(driver->exclusive == exclusive) return true; - if(!driver->hasExclusive()) return false; - if(!driver->setExclusive(driver->exclusive = exclusive)) return false; + if(instance->exclusive == exclusive) return true; + if(!instance->hasExclusive()) return false; + if(!instance->setExclusive(instance->exclusive = exclusive)) return false; return true; } auto Audio::setContext(uintptr context) -> bool { - if(driver->context == context) return true; - if(!driver->hasContext()) return false; - if(!driver->setContext(driver->context = context)) return false; + if(instance->context == context) return true; + if(!instance->hasContext()) return false; + if(!instance->setContext(instance->context = context)) return false; return true; } auto Audio::setDevice(string device) -> bool { - if(driver->device == device) return true; - if(!driver->hasDevice(device)) return false; - if(!driver->setDevice(driver->device = device)) return false; + if(instance->device == device) return true; + if(!instance->hasDevice(device)) return false; + if(!instance->setDevice(instance->device = device)) return false; return true; } auto Audio::setBlocking(bool blocking) -> bool { - if(driver->blocking == blocking) return true; - if(!driver->hasBlocking()) return false; - if(!driver->setBlocking(driver->blocking = blocking)) return false; - for(auto& resampler : resamplers) resampler.reset(driver->frequency); + if(instance->blocking == blocking) return true; + if(!instance->hasBlocking()) return false; + if(!instance->setBlocking(instance->blocking = blocking)) return false; + for(auto& resampler : resamplers) resampler.reset(instance->frequency); return true; } auto Audio::setDynamic(bool dynamic) -> bool { - if(driver->dynamic == dynamic) return true; - if(!driver->hasDynamic()) return false; - if(!driver->setDynamic(driver->dynamic = dynamic)) return false; + if(instance->dynamic == dynamic) return true; + if(!instance->hasDynamic()) return false; + if(!instance->setDynamic(instance->dynamic = dynamic)) return false; return true; } auto Audio::setChannels(uint channels) -> bool { - if(driver->channels == channels) return true; - if(!driver->hasChannels(channels)) return false; - if(!driver->setChannels(driver->channels = channels)) return false; + if(instance->channels == channels) return true; + if(!instance->hasChannels(channels)) return false; + if(!instance->setChannels(instance->channels = channels)) return false; resamplers.reset(); resamplers.resize(channels); - for(auto& resampler : resamplers) resampler.reset(driver->frequency); + for(auto& resampler : resamplers) resampler.reset(instance->frequency); return true; } auto Audio::setFrequency(uint frequency) -> bool { - if(driver->frequency == frequency) return true; - if(!driver->hasFrequency(frequency)) return false; - if(!driver->setFrequency(driver->frequency = frequency)) return false; - for(auto& resampler : resamplers) resampler.reset(driver->frequency); + if(instance->frequency == frequency) return true; + if(!instance->hasFrequency(frequency)) return false; + if(!instance->setFrequency(instance->frequency = frequency)) return false; + for(auto& resampler : resamplers) resampler.reset(instance->frequency); return true; } auto Audio::setLatency(uint latency) -> bool { - if(driver->latency == latency) return true; - if(!driver->hasLatency(latency)) return false; - if(!driver->setLatency(driver->latency = latency)) return false; + if(instance->latency == latency) return true; + if(!instance->hasLatency(latency)) return false; + if(!instance->setLatency(instance->latency = latency)) return false; return true; } // auto Audio::clear() -> void { - for(auto& resampler : resamplers) resampler.reset(driver->frequency); - return driver->clear(); + for(auto& resampler : resamplers) resampler.reset(instance->frequency); + return instance->clear(); } auto Audio::level() -> double { - return driver->level(); + return instance->level(); } auto Audio::output(const double samples[]) -> void { - if(!driver->dynamic) return driver->output(samples); + if(!instance->dynamic) return instance->output(samples); auto maxDelta = 0.005; - double fillLevel = driver->level(); - double dynamicFrequency = ((1.0 - maxDelta) + 2.0 * fillLevel * maxDelta) * driver->frequency; + double fillLevel = instance->level(); + double dynamicFrequency = ((1.0 - maxDelta) + 2.0 * fillLevel * maxDelta) * instance->frequency; for(auto& resampler : resamplers) { resampler.setInputFrequency(dynamicFrequency); resampler.write(*samples++); } while(resamplers.first().pending()) { - double samples[driver->channels]; - for(uint n : range(driver->channels)) samples[n] = resamplers[n].read(); - driver->output(samples); + double samples[instance->channels]; + for(uint n : range(instance->channels)) samples[n] = resamplers[n].read(); + instance->output(samples); } } // auto Audio::create(string driver) -> bool { - reset(); + self.instance.reset(); if(!driver) driver = optimalDriver(); #if defined(AUDIO_ALSA) - if(driver == "ALSA") self.driver = new AudioALSA(*this); + if(driver == "ALSA") self.instance = new AudioALSA(*this); #endif #if defined(AUDIO_AO) - if(driver == "libao") self.driver = new AudioAO(*this); + if(driver == "libao") self.instance = new AudioAO(*this); #endif #if defined(AUDIO_ASIO) - if(driver == "ASIO") self.driver = new AudioASIO(*this); + if(driver == "ASIO") self.instance = new AudioASIO(*this); #endif #if defined(AUDIO_DIRECTSOUND) - if(driver == "DirectSound") self.driver = new AudioDirectSound(*this); + if(driver == "DirectSound") self.instance = new AudioDirectSound(*this); #endif #if defined(AUDIO_OPENAL) - if(driver == "OpenAL") self.driver = new AudioOpenAL(*this); + if(driver == "OpenAL") self.instance = new AudioOpenAL(*this); #endif #if defined(AUDIO_OSS) - if(driver == "OSS") self.driver = new AudioOSS(*this); + if(driver == "OSS") self.instance = new AudioOSS(*this); #endif #if defined(AUDIO_PULSEAUDIO) - if(driver == "PulseAudio") self.driver = new AudioPulseAudio(*this); + if(driver == "PulseAudio") self.instance = new AudioPulseAudio(*this); #endif #if defined(AUDIO_PULSEAUDIOSIMPLE) - if(driver == "PulseAudioSimple") self.driver = new AudioPulseAudioSimple(*this); + if(driver == "PulseAudioSimple") self.instance = new AudioPulseAudioSimple(*this); #endif #if defined(AUDIO_WASAPI) - if(driver == "WASAPI") self.driver = new AudioWASAPI(*this); + if(driver == "WASAPI") self.instance = new AudioWASAPI(*this); #endif #if defined(AUDIO_XAUDIO2) - if(driver == "XAudio2") self.driver = new AudioXAudio2(*this); + if(driver == "XAudio2") self.instance = new AudioXAudio2(*this); #endif - if(!self.driver) self.driver = new AudioDriver(*this); + if(!self.instance) self.instance = new AudioDriver(*this); - return self.driver->create(); + return self.instance->create(); } auto Audio::hasDrivers() -> vector { diff --git a/ruby/audio/audio.hpp b/ruby/audio/audio.hpp index 8dae8f7b..7338472a 100644 --- a/ruby/audio/audio.hpp +++ b/ruby/audio/audio.hpp @@ -5,7 +5,7 @@ struct AudioDriver { virtual ~AudioDriver() = default; virtual auto create() -> bool { return true; } - virtual auto driverName() -> string { return "None"; } + virtual auto driver() -> string { return "None"; } virtual auto ready() -> bool { return true; } virtual auto hasExclusive() -> bool { return false; } @@ -55,35 +55,35 @@ struct Audio { static auto optimalDriver() -> string; static auto safestDriver() -> string; - Audio() : self(*this) {} - explicit operator bool() const { return (bool)driver; } - auto reset() -> void { driver.reset(); } + Audio() : self(*this) { reset(); } + explicit operator bool() { return instance->driver() != "None"; } + auto reset() -> void { instance = new AudioDriver(*this); } auto create(string driver = "") -> bool; - auto driverName() -> string { return driver->driverName(); } - auto ready() -> bool { return driver->ready(); } + auto driver() -> string { return instance->driver(); } + auto ready() -> bool { return instance->ready(); } - auto hasExclusive() -> bool { return driver->hasExclusive(); } - auto hasContext() -> bool { return driver->hasContext(); } - auto hasDevices() -> vector { return driver->hasDevices(); } - auto hasBlocking() -> bool { return driver->hasBlocking(); } - auto hasDynamic() -> bool { return driver->hasDynamic(); } - auto hasChannels() -> vector { return driver->hasChannels(); } - auto hasFrequencies() -> vector { return driver->hasFrequencies(); } - auto hasLatencies() -> vector { return driver->hasLatencies(); } + auto hasExclusive() -> bool { return instance->hasExclusive(); } + auto hasContext() -> bool { return instance->hasContext(); } + auto hasDevices() -> vector { return instance->hasDevices(); } + auto hasBlocking() -> bool { return instance->hasBlocking(); } + auto hasDynamic() -> bool { return instance->hasDynamic(); } + auto hasChannels() -> vector { return instance->hasChannels(); } + auto hasFrequencies() -> vector { return instance->hasFrequencies(); } + auto hasLatencies() -> vector { return instance->hasLatencies(); } - auto hasDevice(string device) -> bool { return driver->hasDevice(device); } - auto hasChannels(uint channels) -> bool { return driver->hasChannels(channels); } - auto hasFrequency(uint frequency) -> bool { return driver->hasFrequency(frequency); } - auto hasLatency(uint latency) -> bool { return driver->hasLatency(latency); } + auto hasDevice(string device) -> bool { return instance->hasDevice(device); } + auto hasChannels(uint channels) -> bool { return instance->hasChannels(channels); } + auto hasFrequency(uint frequency) -> bool { return instance->hasFrequency(frequency); } + auto hasLatency(uint latency) -> bool { return instance->hasLatency(latency); } - auto exclusive() -> bool { return driver->exclusive; } - auto context() -> uintptr { return driver->context; } - auto device() -> string { return driver->device; } - auto blocking() -> bool { return driver->blocking; } - auto dynamic() -> bool { return driver->dynamic; } - auto channels() -> uint { return driver->channels; } - auto frequency() -> uint { return driver->frequency; } - auto latency() -> uint { return driver->latency; } + auto exclusive() -> bool { return instance->exclusive; } + auto context() -> uintptr { return instance->context; } + auto device() -> string { return instance->device; } + auto blocking() -> bool { return instance->blocking; } + auto dynamic() -> bool { return instance->dynamic; } + auto channels() -> uint { return instance->channels; } + auto frequency() -> uint { return instance->frequency; } + auto latency() -> uint { return instance->latency; } auto setExclusive(bool exclusive) -> bool; auto setContext(uintptr context) -> bool; @@ -100,6 +100,6 @@ struct Audio { protected: Audio& self; - unique_pointer driver; + unique_pointer instance; vector resamplers; }; diff --git a/ruby/audio/oss.cpp b/ruby/audio/oss.cpp index a2d2c702..5e7b2014 100644 --- a/ruby/audio/oss.cpp +++ b/ruby/audio/oss.cpp @@ -28,7 +28,7 @@ struct AudioOSS : AudioDriver { return initialize(); } - auto driverName() -> string override { return "OSS"; } + auto driver() -> string override { return "OSS"; } auto ready() -> bool override { return _fd >= 0; } auto hasBlocking() -> bool override { return true; } diff --git a/ruby/input/input.cpp b/ruby/input/input.cpp index b3193526..4a31cb06 100644 --- a/ruby/input/input.cpp +++ b/ruby/input/input.cpp @@ -25,32 +25,32 @@ namespace ruby { auto Input::setContext(uintptr context) -> bool { - if(driver->context == context) return true; - if(!driver->hasContext()) return false; - if(!driver->setContext(driver->context = context)) return false; + if(instance->context == context) return true; + if(!instance->hasContext()) return false; + if(!instance->setContext(instance->context = context)) return false; return true; } // auto Input::acquired() -> bool { - return driver->acquired(); + return instance->acquired(); } auto Input::acquire() -> bool { - return driver->acquire(); + return instance->acquire(); } auto Input::release() -> bool { - return driver->release(); + return instance->release(); } auto Input::poll() -> vector> { - return driver->poll(); + return instance->poll(); } auto Input::rumble(uint64_t id, bool enable) -> bool { - return driver->rumble(id, enable); + return instance->rumble(id, enable); } // @@ -66,36 +66,36 @@ auto Input::doChange(shared_pointer device, uint group, uint input, // auto Input::create(string driver) -> bool { - reset(); + self.instance.reset(); if(!driver) driver = optimalDriver(); #if defined(INPUT_WINDOWS) - if(driver == "Windows") self.driver = new InputWindows(*this); + if(driver == "Windows") self.instance = new InputWindows(*this); #endif #if defined(INPUT_QUARTZ) - if(driver == "Quartz") self.driver = new InputQuartz(*this); + if(driver == "Quartz") self.instance = new InputQuartz(*this); #endif #if defined(INPUT_CARBON) - if(driver == "Carbon") self.driver = new InputCarbon(*this); + if(driver == "Carbon") self.instance = new InputCarbon(*this); #endif #if defined(INPUT_UDEV) - if(driver == "udev") self.driver = new InputUdev(*this); + if(driver == "udev") self.instance = new InputUdev(*this); #endif #if defined(INPUT_SDL) - if(driver == "SDL") self.driver = new InputSDL(*this); + if(driver == "SDL") self.instance = new InputSDL(*this); #endif #if defined(INPUT_XLIB) - if(driver == "Xlib") self.driver = new InputXlib(*this); + if(driver == "Xlib") self.instance = new InputXlib(*this); #endif - if(!self.driver) self.driver = new InputDriver(*this); + if(!self.instance) self.instance = new InputDriver(*this); - return self.driver->create(); + return self.instance->create(); } auto Input::hasDrivers() -> vector { diff --git a/ruby/input/input.hpp b/ruby/input/input.hpp index 15100cca..05b16817 100644 --- a/ruby/input/input.hpp +++ b/ruby/input/input.hpp @@ -5,7 +5,7 @@ struct InputDriver { virtual ~InputDriver() = default; virtual auto create() -> bool { return true; } - virtual auto driverName() -> string { return "None"; } + virtual auto driver() -> string { return "None"; } virtual auto ready() -> bool { return true; } virtual auto hasContext() -> bool { return false; } @@ -31,16 +31,16 @@ struct Input { static auto optimalDriver() -> string; static auto safestDriver() -> string; - Input() : self(*this) {} - explicit operator bool() const { return (bool)driver; } - auto reset() -> void { driver.reset(); } + Input() : self(*this) { reset(); } + explicit operator bool() { return instance->driver() != "None"; } + auto reset() -> void { instance = new InputDriver(*this); } auto create(string driver = "") -> bool; - auto driverName() -> string { return driver->driverName(); } - auto ready() -> bool { return driver->ready(); } + auto driver() -> string { return instance->driver(); } + auto ready() -> bool { return instance->ready(); } - auto hasContext() -> bool { return driver->hasContext(); } + auto hasContext() -> bool { return instance->hasContext(); } - auto context() -> uintptr { return driver->context; } + auto context() -> uintptr { return instance->context; } auto setContext(uintptr context) -> bool; @@ -55,6 +55,6 @@ struct Input { protected: Input& self; - unique_pointer driver; + unique_pointer instance; function device, uint group, uint input, int16_t oldValue, int16_t newValue)> change; }; diff --git a/ruby/input/sdl.cpp b/ruby/input/sdl.cpp index 6e399673..834493f5 100644 --- a/ruby/input/sdl.cpp +++ b/ruby/input/sdl.cpp @@ -16,7 +16,7 @@ struct InputSDL : InputDriver { return initialize(); } - auto driverName() -> string override { return "SDL"; } + auto driver() -> string override { return "SDL"; } auto ready() -> bool override { return isReady; } auto hasContext() -> bool override { return true; } diff --git a/ruby/video/glx2.cpp b/ruby/video/glx2.cpp index b1668774..cf6a4e86 100644 --- a/ruby/video/glx2.cpp +++ b/ruby/video/glx2.cpp @@ -32,7 +32,7 @@ struct VideoGLX2 : VideoDriver { return initialize(); } - auto driverName() -> string override { return "OpenGL2"; } + auto driver() -> string override { return "OpenGL2"; } auto ready() -> bool override { return _ready; } auto hasContext() -> bool override { return true; } diff --git a/ruby/video/video.cpp b/ruby/video/video.cpp index cde33e75..2de2e124 100644 --- a/ruby/video/video.cpp +++ b/ruby/video/video.cpp @@ -37,74 +37,74 @@ namespace ruby { auto Video::setExclusive(bool exclusive) -> bool { - if(driver->exclusive == exclusive) return true; - if(!driver->hasExclusive()) return false; - if(!driver->setExclusive(driver->exclusive = exclusive)) return false; + if(instance->exclusive == exclusive) return true; + if(!instance->hasExclusive()) return false; + if(!instance->setExclusive(instance->exclusive = exclusive)) return false; return true; } auto Video::setContext(uintptr context) -> bool { - if(driver->context == context) return true; - if(!driver->hasContext()) return false; - if(!driver->setContext(driver->context = context)) return false; + if(instance->context == context) return true; + if(!instance->hasContext()) return false; + if(!instance->setContext(instance->context = context)) return false; return true; } auto Video::setBlocking(bool blocking) -> bool { - if(driver->blocking == blocking) return true; - if(!driver->hasBlocking()) return false; - if(!driver->setBlocking(driver->blocking = blocking)) return false; + if(instance->blocking == blocking) return true; + if(!instance->hasBlocking()) return false; + if(!instance->setBlocking(instance->blocking = blocking)) return false; return true; } auto Video::setFlush(bool flush) -> bool { - if(driver->flush == flush) return true; - if(!driver->hasFlush()) return false; - if(!driver->setFlush(driver->flush = flush)) return false; + if(instance->flush == flush) return true; + if(!instance->hasFlush()) return false; + if(!instance->setFlush(instance->flush = flush)) return false; return true; } auto Video::setFormat(string format) -> bool { - if(driver->format == format) return true; - if(!driver->hasFormat(format)) return false; - if(!driver->setFormat(driver->format = format)) return false; + if(instance->format == format) return true; + if(!instance->hasFormat(format)) return false; + if(!instance->setFormat(instance->format = format)) return false; return true; } auto Video::setSmooth(bool smooth) -> bool { - if(driver->smooth == smooth) return true; - if(!driver->hasSmooth()) return false; - if(!driver->setSmooth(driver->smooth = smooth)) return false; + if(instance->smooth == smooth) return true; + if(!instance->hasSmooth()) return false; + if(!instance->setSmooth(instance->smooth = smooth)) return false; return true; } auto Video::setShader(string shader) -> bool { - if(driver->shader == shader) return true; - if(!driver->hasShader()) return false; - if(!driver->setShader(driver->shader = shader)) return false; + if(instance->shader == shader) return true; + if(!instance->hasShader()) return false; + if(!instance->setShader(instance->shader = shader)) return false; return true; } // auto Video::clear() -> void { - return driver->clear(); + return instance->clear(); } auto Video::acquire(uint32_t*& data, uint& pitch, uint width, uint height) -> bool { - return driver->acquire(data, pitch, width, height); + return instance->acquire(data, pitch, width, height); } auto Video::release() -> void { - return driver->release(); + return instance->release(); } auto Video::output() -> void { - return driver->output(); + return instance->output(); } auto Video::poll() -> void { - return driver->poll(); + return instance->poll(); } // @@ -120,48 +120,48 @@ auto Video::doUpdate(uint width, uint height) -> void { // auto Video::create(string driver) -> bool { - reset(); + self.instance.reset(); if(!driver) driver = optimalDriver(); #if defined(VIDEO_CGL) - if(driver == "OpenGL") self.driver = new VideoCGL(*this); + if(driver == "OpenGL") self.instance = new VideoCGL(*this); #endif #if defined(VIDEO_DIRECT3D) - if(driver == "Direct3D") self.driver = new VideoDirect3D(*this); + if(driver == "Direct3D") self.instance = new VideoDirect3D(*this); #endif #if defined(VIDEO_DIRECTDRAW) - if(driver == "DirectDraw") self.driver = new VideoDirectDraw(*this); + if(driver == "DirectDraw") self.instance = new VideoDirectDraw(*this); #endif #if defined(VIDEO_GDI) - if(driver == "GDI") self.driver = new VideoGDI(*this); + if(driver == "GDI") self.instance = new VideoGDI(*this); #endif #if defined(VIDEO_GLX) - if(driver == "OpenGL") self.driver = new VideoGLX(*this); + if(driver == "OpenGL") self.instance = new VideoGLX(*this); #endif #if defined(VIDEO_GLX2) - if(driver == "OpenGL2") self.driver = new VideoGLX2(*this); + if(driver == "OpenGL2") self.instance = new VideoGLX2(*this); #endif #if defined(VIDEO_WGL) - if(driver == "OpenGL") self.driver = new VideoWGL(*this); + if(driver == "OpenGL") self.instance = new VideoWGL(*this); #endif #if defined(VIDEO_XSHM) - if(driver == "XShm") self.driver = new VideoXShm(*this); + if(driver == "XShm") self.instance = new VideoXShm(*this); #endif #if defined(VIDEO_XVIDEO) - if(driver == "XVideo") self.driver = new VideoXVideo(*this); + if(driver == "XVideo") self.instance = new VideoXVideo(*this); #endif - if(!self.driver) self.driver = new VideoDriver(*this); + if(!self.instance) self.instance = new VideoDriver(*this); - return self.driver->create(); + return self.instance->create(); } auto Video::hasDrivers() -> vector { diff --git a/ruby/video/video.hpp b/ruby/video/video.hpp index 4c270874..29943f9e 100644 --- a/ruby/video/video.hpp +++ b/ruby/video/video.hpp @@ -5,7 +5,7 @@ struct VideoDriver { virtual ~VideoDriver() = default; virtual auto create() -> bool { return true; } - virtual auto driverName() -> string { return "None"; } + virtual auto driver() -> string { return "None"; } virtual auto ready() -> bool { return true; } virtual auto hasExclusive() -> bool { return false; } @@ -51,30 +51,30 @@ struct Video { static auto optimalDriver() -> string; static auto safestDriver() -> string; - Video() : self(*this) {} - explicit operator bool() const { return (bool)driver; } - auto reset() -> void { driver.reset(); } + Video() : self(*this) { reset(); } + explicit operator bool() { return instance->driver() != "None"; } + auto reset() -> void { instance = new VideoDriver(*this); } auto create(string driver = "") -> bool; - auto driverName() -> string { return driver->driverName(); } - auto ready() -> bool { return driver->ready(); } + auto driver() -> string { return instance->driver(); } + auto ready() -> bool { return instance->ready(); } - auto hasExclusive() -> bool { return driver->hasExclusive(); } - auto hasContext() -> bool { return driver->hasContext(); } - auto hasBlocking() -> bool { return driver->hasBlocking(); } - auto hasFlush() -> bool { return driver->hasFlush(); } - auto hasFormats() -> vector { return driver->hasFormats(); } - auto hasSmooth() -> bool { return driver->hasSmooth(); } - auto hasShader() -> bool { return driver->hasShader(); } + auto hasExclusive() -> bool { return instance->hasExclusive(); } + auto hasContext() -> bool { return instance->hasContext(); } + auto hasBlocking() -> bool { return instance->hasBlocking(); } + auto hasFlush() -> bool { return instance->hasFlush(); } + auto hasFormats() -> vector { return instance->hasFormats(); } + auto hasSmooth() -> bool { return instance->hasSmooth(); } + auto hasShader() -> bool { return instance->hasShader(); } - auto hasFormat(string format) -> bool { return driver->hasFormat(format); } + auto hasFormat(string format) -> bool { return instance->hasFormat(format); } - auto exclusive() -> bool { return driver->exclusive; } - auto context() -> uintptr { return driver->context; } - auto blocking() -> bool { return driver->blocking; } - auto flush() -> bool { return driver->flush; } - auto format() -> string { return driver->format; } - auto smooth() -> bool { return driver->smooth; } - auto shader() -> string { return driver->shader; } + auto exclusive() -> bool { return instance->exclusive; } + auto context() -> uintptr { return instance->context; } + auto blocking() -> bool { return instance->blocking; } + auto flush() -> bool { return instance->flush; } + auto format() -> string { return instance->format; } + auto smooth() -> bool { return instance->smooth; } + auto shader() -> string { return instance->shader; } auto setExclusive(bool exclusive) -> bool; auto setContext(uintptr context) -> bool; @@ -95,6 +95,6 @@ struct Video { protected: Video& self; - unique_pointer driver; + unique_pointer instance; function update; }; diff --git a/ruby/video/xshm.cpp b/ruby/video/xshm.cpp index 23a802b9..4f84890f 100644 --- a/ruby/video/xshm.cpp +++ b/ruby/video/xshm.cpp @@ -18,7 +18,7 @@ struct VideoXShm : VideoDriver { return initialize(); } - auto driverName() -> string override { return "XShm"; } + auto driver() -> string override { return "XShm"; } auto ready() -> bool override { return _ready; } auto hasContext() -> bool override { return true; }