diff options
Diffstat (limited to 'src/citra_qt')
| -rw-r--r-- | src/citra_qt/bootmanager.cpp | 55 | ||||
| -rw-r--r-- | src/citra_qt/bootmanager.h | 12 | ||||
| -rw-r--r-- | src/citra_qt/config.cpp | 2 | ||||
| -rw-r--r-- | src/citra_qt/debugger/callstack.cpp | 18 | ||||
| -rw-r--r-- | src/citra_qt/debugger/callstack.h | 6 | ||||
| -rw-r--r-- | src/citra_qt/debugger/disassembler.cpp | 7 | ||||
| -rw-r--r-- | src/citra_qt/debugger/disassembler.h | 3 | ||||
| -rw-r--r-- | src/citra_qt/debugger/graphics_cmdlists.cpp | 2 | ||||
| -rw-r--r-- | src/citra_qt/debugger/graphics_framebuffer.cpp | 4 | ||||
| -rw-r--r-- | src/citra_qt/debugger/registers.cpp | 7 | ||||
| -rw-r--r-- | src/citra_qt/debugger/registers.h | 3 | ||||
| -rw-r--r-- | src/citra_qt/main.cpp | 39 | ||||
| -rw-r--r-- | src/citra_qt/main.h | 1 | ||||
| -rw-r--r-- | src/citra_qt/main.ui | 94 | ||||
| -rw-r--r-- | src/citra_qt/util/spinbox.cpp | 2 |
15 files changed, 183 insertions, 72 deletions
diff --git a/src/citra_qt/bootmanager.cpp b/src/citra_qt/bootmanager.cpp index 3e24da596..22a7842bf 100644 --- a/src/citra_qt/bootmanager.cpp +++ b/src/citra_qt/bootmanager.cpp @@ -40,18 +40,35 @@ void EmuThread::SetFilename(std::string filename) void EmuThread::run() { stop_run = false; + + // holds whether the cpu was running during the last iteration, + // so that the DebugModeLeft signal can be emitted before the + // next execution step + bool was_active = false; while (!stop_run) { if (cpu_running) { + if (!was_active) + emit DebugModeLeft(); + Core::RunLoop(); + + was_active = cpu_running || exec_cpu_step; + if (!was_active) + emit DebugModeEntered(); } else if (exec_cpu_step) { + if (!was_active) + emit DebugModeLeft(); + exec_cpu_step = false; Core::SingleStep(); - emit CPUStepped(); + emit DebugModeEntered(); yieldCurrentThread(); + + was_active = false; } } render_window->moveContext(); @@ -251,33 +268,33 @@ QByteArray GRenderWindow::saveGeometry() void GRenderWindow::keyPressEvent(QKeyEvent* event) { EmuWindow::KeyPressed({event->key(), keyboard_id}); - HID_User::PadUpdateComplete(); + Service::HID::PadUpdateComplete(); } void GRenderWindow::keyReleaseEvent(QKeyEvent* event) { EmuWindow::KeyReleased({event->key(), keyboard_id}); - HID_User::PadUpdateComplete(); + Service::HID::PadUpdateComplete(); } void GRenderWindow::ReloadSetKeymaps() { - KeyMap::SetKeyMapping({Settings::values.pad_a_key, keyboard_id}, HID_User::PAD_A); - KeyMap::SetKeyMapping({Settings::values.pad_b_key, keyboard_id}, HID_User::PAD_B); - KeyMap::SetKeyMapping({Settings::values.pad_select_key, keyboard_id}, HID_User::PAD_SELECT); - KeyMap::SetKeyMapping({Settings::values.pad_start_key, keyboard_id}, HID_User::PAD_START); - KeyMap::SetKeyMapping({Settings::values.pad_dright_key, keyboard_id}, HID_User::PAD_RIGHT); - KeyMap::SetKeyMapping({Settings::values.pad_dleft_key, keyboard_id}, HID_User::PAD_LEFT); - KeyMap::SetKeyMapping({Settings::values.pad_dup_key, keyboard_id}, HID_User::PAD_UP); - KeyMap::SetKeyMapping({Settings::values.pad_ddown_key, keyboard_id}, HID_User::PAD_DOWN); - KeyMap::SetKeyMapping({Settings::values.pad_r_key, keyboard_id}, HID_User::PAD_R); - KeyMap::SetKeyMapping({Settings::values.pad_l_key, keyboard_id}, HID_User::PAD_L); - KeyMap::SetKeyMapping({Settings::values.pad_x_key, keyboard_id}, HID_User::PAD_X); - KeyMap::SetKeyMapping({Settings::values.pad_y_key, keyboard_id}, HID_User::PAD_Y); - KeyMap::SetKeyMapping({Settings::values.pad_sright_key, keyboard_id}, HID_User::PAD_CIRCLE_RIGHT); - KeyMap::SetKeyMapping({Settings::values.pad_sleft_key, keyboard_id}, HID_User::PAD_CIRCLE_LEFT); - KeyMap::SetKeyMapping({Settings::values.pad_sup_key, keyboard_id}, HID_User::PAD_CIRCLE_UP); - KeyMap::SetKeyMapping({Settings::values.pad_sdown_key, keyboard_id}, HID_User::PAD_CIRCLE_DOWN); + KeyMap::SetKeyMapping({Settings::values.pad_a_key, keyboard_id}, Service::HID::PAD_A); + KeyMap::SetKeyMapping({Settings::values.pad_b_key, keyboard_id}, Service::HID::PAD_B); + KeyMap::SetKeyMapping({Settings::values.pad_select_key, keyboard_id}, Service::HID::PAD_SELECT); + KeyMap::SetKeyMapping({Settings::values.pad_start_key, keyboard_id}, Service::HID::PAD_START); + KeyMap::SetKeyMapping({Settings::values.pad_dright_key, keyboard_id}, Service::HID::PAD_RIGHT); + KeyMap::SetKeyMapping({Settings::values.pad_dleft_key, keyboard_id}, Service::HID::PAD_LEFT); + KeyMap::SetKeyMapping({Settings::values.pad_dup_key, keyboard_id}, Service::HID::PAD_UP); + KeyMap::SetKeyMapping({Settings::values.pad_ddown_key, keyboard_id}, Service::HID::PAD_DOWN); + KeyMap::SetKeyMapping({Settings::values.pad_r_key, keyboard_id}, Service::HID::PAD_R); + KeyMap::SetKeyMapping({Settings::values.pad_l_key, keyboard_id}, Service::HID::PAD_L); + KeyMap::SetKeyMapping({Settings::values.pad_x_key, keyboard_id}, Service::HID::PAD_X); + KeyMap::SetKeyMapping({Settings::values.pad_y_key, keyboard_id}, Service::HID::PAD_Y); + KeyMap::SetKeyMapping({Settings::values.pad_sright_key, keyboard_id}, Service::HID::PAD_CIRCLE_RIGHT); + KeyMap::SetKeyMapping({Settings::values.pad_sleft_key, keyboard_id}, Service::HID::PAD_CIRCLE_LEFT); + KeyMap::SetKeyMapping({Settings::values.pad_sup_key, keyboard_id}, Service::HID::PAD_CIRCLE_UP); + KeyMap::SetKeyMapping({Settings::values.pad_sdown_key, keyboard_id}, Service::HID::PAD_CIRCLE_DOWN); } void GRenderWindow::OnClientAreaResized(unsigned width, unsigned height) diff --git a/src/citra_qt/bootmanager.h b/src/citra_qt/bootmanager.h index 1c893384c..a55db682a 100644 --- a/src/citra_qt/bootmanager.h +++ b/src/citra_qt/bootmanager.h @@ -81,12 +81,18 @@ private: signals: /** - * Emitted when CPU when we've finished processing a single Gekko instruction + * Emitted when the CPU has halted execution * - * @warning This will only be emitted when the CPU is not running (SetCpuRunning(false)) * @warning When connecting to this signal from other threads, make sure to specify either Qt::QueuedConnection (invoke slot within the destination object's message thread) or even Qt::BlockingQueuedConnection (additionally block source thread until slot returns) */ - void CPUStepped(); + void DebugModeEntered(); + + /** + * Emitted right before the CPU continues execution + * + * @warning When connecting to this signal from other threads, make sure to specify either Qt::QueuedConnection (invoke slot within the destination object's message thread) or even Qt::BlockingQueuedConnection (additionally block source thread until slot returns) + */ + void DebugModeLeft(); }; class GRenderWindow : public QWidget, public EmuWindow diff --git a/src/citra_qt/config.cpp b/src/citra_qt/config.cpp index 1596c08d7..955c8a4e0 100644 --- a/src/citra_qt/config.cpp +++ b/src/citra_qt/config.cpp @@ -43,7 +43,6 @@ void Config::ReadValues() { qt_config->endGroup(); qt_config->beginGroup("Core"); - Settings::values.cpu_core = qt_config->value("cpu_core", Core::CPU_Interpreter).toInt(); Settings::values.gpu_refresh_rate = qt_config->value("gpu_refresh_rate", 30).toInt(); Settings::values.frame_skip = qt_config->value("frame_skip", 0).toInt(); qt_config->endGroup(); @@ -79,7 +78,6 @@ void Config::SaveValues() { qt_config->endGroup(); qt_config->beginGroup("Core"); - qt_config->setValue("cpu_core", Settings::values.cpu_core); qt_config->setValue("gpu_refresh_rate", Settings::values.gpu_refresh_rate); qt_config->setValue("frame_skip", Settings::values.frame_skip); qt_config->endGroup(); diff --git a/src/citra_qt/debugger/callstack.cpp b/src/citra_qt/debugger/callstack.cpp index 274c5cccd..9bb22ca2e 100644 --- a/src/citra_qt/debugger/callstack.cpp +++ b/src/citra_qt/debugger/callstack.cpp @@ -25,7 +25,7 @@ CallstackWidget::CallstackWidget(QWidget* parent): QDockWidget(parent) ui.treeView->setModel(callstack_model); } -void CallstackWidget::OnCPUStepped() +void CallstackWidget::OnDebugModeEntered() { ARM_Disasm* disasm = new ARM_Disasm(); ARM_Interface* app_core = Core::g_app_core; @@ -33,6 +33,8 @@ void CallstackWidget::OnCPUStepped() u32 sp = app_core->GetReg(13); //stack pointer u32 ret_addr, call_addr, func_addr; + Clear(); + int counter = 0; for (u32 addr = 0x10000000; addr >= sp; addr -= 4) { @@ -71,3 +73,17 @@ void CallstackWidget::OnCPUStepped() } } } + +void CallstackWidget::OnDebugModeLeft() +{ + +} + +void CallstackWidget::Clear() +{ + for (int row = 0; row < callstack_model->rowCount(); row++) { + for (int column = 0; column < callstack_model->columnCount(); column++) { + callstack_model->setItem(row, column, new QStandardItem()); + } + } +} diff --git a/src/citra_qt/debugger/callstack.h b/src/citra_qt/debugger/callstack.h index 4f4f74823..1a9b6dc81 100644 --- a/src/citra_qt/debugger/callstack.h +++ b/src/citra_qt/debugger/callstack.h @@ -15,9 +15,13 @@ public: CallstackWidget(QWidget* parent = 0); public slots: - void OnCPUStepped(); + void OnDebugModeEntered(); + void OnDebugModeLeft(); private: Ui::CallStack ui; QStandardItemModel* callstack_model; + + /// Clears the callstack widget while keeping the column widths the same + void Clear(); }; diff --git a/src/citra_qt/debugger/disassembler.cpp b/src/citra_qt/debugger/disassembler.cpp index da084ab24..c61ace925 100644 --- a/src/citra_qt/debugger/disassembler.cpp +++ b/src/citra_qt/debugger/disassembler.cpp @@ -235,7 +235,7 @@ void DisassemblerWidget::OnToggleStartStop() emu_thread.SetCpuRunning(!emu_thread.IsCpuRunning()); } -void DisassemblerWidget::OnCPUStepped() +void DisassemblerWidget::OnDebugModeEntered() { ARMword next_instr = Core::g_app_core->GetPC(); @@ -252,6 +252,11 @@ void DisassemblerWidget::OnCPUStepped() disasm_ui.treeView->selectionModel()->setCurrentIndex(model_index, QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows); } +void DisassemblerWidget::OnDebugModeLeft() +{ + +} + int DisassemblerWidget::SelectedRow() { QModelIndex index = disasm_ui.treeView->selectionModel()->currentIndex(); diff --git a/src/citra_qt/debugger/disassembler.h b/src/citra_qt/debugger/disassembler.h index 6d3cef108..0deccc240 100644 --- a/src/citra_qt/debugger/disassembler.h +++ b/src/citra_qt/debugger/disassembler.h @@ -61,7 +61,8 @@ public slots: void OnPause(); void OnToggleStartStop(); - void OnCPUStepped(); + void OnDebugModeEntered(); + void OnDebugModeLeft(); private: // returns -1 if no row is selected diff --git a/src/citra_qt/debugger/graphics_cmdlists.cpp b/src/citra_qt/debugger/graphics_cmdlists.cpp index 4a6159fdf..bd420f24a 100644 --- a/src/citra_qt/debugger/graphics_cmdlists.cpp +++ b/src/citra_qt/debugger/graphics_cmdlists.cpp @@ -76,6 +76,8 @@ TextureInfoDockWidget::TextureInfoDockWidget(const Pica::DebugUtils::TextureInfo format_choice->addItem(tr("IA4")); format_choice->addItem(tr("UNK10")); format_choice->addItem(tr("A4")); + format_choice->addItem(tr("ETC1")); + format_choice->addItem(tr("ETC1A4")); format_choice->setCurrentIndex(static_cast<int>(info.format)); connect(format_choice, SIGNAL(currentIndexChanged(int)), this, SLOT(OnFormatChanged(int))); diff --git a/src/citra_qt/debugger/graphics_framebuffer.cpp b/src/citra_qt/debugger/graphics_framebuffer.cpp index a9423d6c7..43c59738f 100644 --- a/src/citra_qt/debugger/graphics_framebuffer.cpp +++ b/src/citra_qt/debugger/graphics_framebuffer.cpp @@ -170,8 +170,8 @@ void GraphicsFramebufferWidget::OnFramebufferWidthChanged(int new_value) void GraphicsFramebufferWidget::OnFramebufferHeightChanged(int new_value) { - if (framebuffer_height != new_value) { - framebuffer_height = new_value; + if (framebuffer_height != static_cast<unsigned>(new_value)) { + framebuffer_height = static_cast<unsigned>(new_value); framebuffer_source_list->setCurrentIndex(static_cast<int>(Source::Custom)); emit Update(); diff --git a/src/citra_qt/debugger/registers.cpp b/src/citra_qt/debugger/registers.cpp index e982dfb3f..ab3666156 100644 --- a/src/citra_qt/debugger/registers.cpp +++ b/src/citra_qt/debugger/registers.cpp @@ -41,7 +41,7 @@ RegistersWidget::RegistersWidget(QWidget* parent) : QDockWidget(parent) CSPR->addChild(new QTreeWidgetItem(QStringList("N"))); } -void RegistersWidget::OnCPUStepped() +void RegistersWidget::OnDebugModeEntered() { ARM_Interface* app_core = Core::g_app_core; @@ -65,3 +65,8 @@ void RegistersWidget::OnCPUStepped() CSPR->child(13)->setText(1, QString("%1").arg((app_core->GetCPSR() >> 30) & 0x1)); // Z - Zero CSPR->child(14)->setText(1, QString("%1").arg((app_core->GetCPSR() >> 31) & 0x1)); // N - Negative/Less than } + +void RegistersWidget::OnDebugModeLeft() +{ + +} diff --git a/src/citra_qt/debugger/registers.h b/src/citra_qt/debugger/registers.h index ac8429f2b..bf8955625 100644 --- a/src/citra_qt/debugger/registers.h +++ b/src/citra_qt/debugger/registers.h @@ -17,7 +17,8 @@ public: RegistersWidget(QWidget* parent = NULL); public slots: - void OnCPUStepped(); + void OnDebugModeEntered(); + void OnDebugModeLeft(); private: Ui::ARMRegisters cpu_regs_ui; diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp index c6671bef1..653ffec75 100644 --- a/src/citra_qt/main.cpp +++ b/src/citra_qt/main.cpp @@ -114,6 +114,9 @@ GMainWindow::GMainWindow() ui.action_Single_Window_Mode->setChecked(settings.value("singleWindowMode", true).toBool()); ToggleWindowMode(); + ui.actionDisplay_widget_title_bars->setChecked(settings.value("displayTitleBars", true).toBool()); + OnDisplayTitleBars(ui.actionDisplay_widget_title_bars->isChecked()); + // Setup connections connect(ui.action_Load_File, SIGNAL(triggered()), this, SLOT(OnMenuLoadFile())); connect(ui.action_Load_Symbol_Map, SIGNAL(triggered()), this, SLOT(OnMenuLoadSymbolMap())); @@ -124,9 +127,13 @@ GMainWindow::GMainWindow() connect(ui.action_Hotkeys, SIGNAL(triggered()), this, SLOT(OnOpenHotkeysDialog())); // BlockingQueuedConnection is important here, it makes sure we've finished refreshing our views before the CPU continues - connect(&render_window->GetEmuThread(), SIGNAL(CPUStepped()), disasmWidget, SLOT(OnCPUStepped()), Qt::BlockingQueuedConnection); - connect(&render_window->GetEmuThread(), SIGNAL(CPUStepped()), registersWidget, SLOT(OnCPUStepped()), Qt::BlockingQueuedConnection); - connect(&render_window->GetEmuThread(), SIGNAL(CPUStepped()), callstackWidget, SLOT(OnCPUStepped()), Qt::BlockingQueuedConnection); + connect(&render_window->GetEmuThread(), SIGNAL(DebugModeEntered()), disasmWidget, SLOT(OnDebugModeEntered()), Qt::BlockingQueuedConnection); + connect(&render_window->GetEmuThread(), SIGNAL(DebugModeEntered()), registersWidget, SLOT(OnDebugModeEntered()), Qt::BlockingQueuedConnection); + connect(&render_window->GetEmuThread(), SIGNAL(DebugModeEntered()), callstackWidget, SLOT(OnDebugModeEntered()), Qt::BlockingQueuedConnection); + + connect(&render_window->GetEmuThread(), SIGNAL(DebugModeLeft()), disasmWidget, SLOT(OnDebugModeLeft()), Qt::BlockingQueuedConnection); + connect(&render_window->GetEmuThread(), SIGNAL(DebugModeLeft()), registersWidget, SLOT(OnDebugModeLeft()), Qt::BlockingQueuedConnection); + connect(&render_window->GetEmuThread(), SIGNAL(DebugModeLeft()), callstackWidget, SLOT(OnDebugModeLeft()), Qt::BlockingQueuedConnection); // Setup hotkeys RegisterHotkey("Main Window", "Load File", QKeySequence::Open); @@ -156,6 +163,27 @@ GMainWindow::~GMainWindow() Pica::g_debug_context.reset(); } +void GMainWindow::OnDisplayTitleBars(bool show) +{ + QList<QDockWidget*> widgets = findChildren<QDockWidget*>(); + + if (show) { + for (QDockWidget* widget: widgets) { + QWidget* old = widget->titleBarWidget(); + widget->setTitleBarWidget(nullptr); + if (old != nullptr) + delete old; + } + } else { + for (QDockWidget* widget: widgets) { + QWidget* old = widget->titleBarWidget(); + widget->setTitleBarWidget(new QWidget()); + if (old != nullptr) + delete old; + } + } +} + void GMainWindow::BootGame(std::string filename) { LOG_INFO(Frontend, "Citra starting...\n"); @@ -167,8 +195,8 @@ void GMainWindow::BootGame(std::string filename) } disasmWidget->Init(); - registersWidget->OnCPUStepped(); - callstackWidget->OnCPUStepped(); + registersWidget->OnDebugModeEntered(); + callstackWidget->OnDebugModeEntered(); render_window->GetEmuThread().SetFilename(filename); render_window->GetEmuThread().start(); @@ -259,6 +287,7 @@ void GMainWindow::closeEvent(QCloseEvent* event) settings.setValue("state", saveState()); settings.setValue("geometryRenderWindow", render_window->saveGeometry()); settings.setValue("singleWindowMode", ui.action_Single_Window_Mode->isChecked()); + settings.setValue("displayTitleBars", ui.actionDisplay_widget_title_bars->isChecked()); settings.setValue("firstStart", false); SaveHotkeys(settings); diff --git a/src/citra_qt/main.h b/src/citra_qt/main.h index 72df17c50..dd53489dd 100644 --- a/src/citra_qt/main.h +++ b/src/citra_qt/main.h @@ -46,6 +46,7 @@ private slots: void OnMenuLoadSymbolMap(); void OnOpenHotkeysDialog(); void OnConfigure(); + void OnDisplayTitleBars(bool); void ToggleWindowMode(); private: diff --git a/src/citra_qt/main.ui b/src/citra_qt/main.ui index d06c207a0..a3752ac1e 100644 --- a/src/citra_qt/main.ui +++ b/src/citra_qt/main.ui @@ -32,7 +32,7 @@ <x>0</x> <y>0</y> <width>1081</width> - <height>20</height> + <height>21</height> </rect> </property> <widget class="QMenu" name="menu_File"> @@ -59,6 +59,7 @@ <string>&View</string> </property> <addaction name="action_Single_Window_Mode"/> + <addaction name="actionDisplay_widget_title_bars"/> <addaction name="action_Hotkeys"/> </widget> <widget class="QMenu" name="menu_Help"> @@ -73,17 +74,17 @@ <addaction name="menu_Help"/> </widget> <widget class="QStatusBar" name="statusbar"/> - <action name="action_Load_File"> - <property name="text"> - <string>Load File...</string> - </property> - </action> - <action name="action_Load_Symbol_Map"> - <property name="text"> - <string>Load Symbol Map...</string> - </property> - </action> - <action name="action_Exit"> + <action name="action_Load_File"> + <property name="text"> + <string>Load File...</string> + </property> + </action> + <action name="action_Load_Symbol_Map"> + <property name="text"> + <string>Load Symbol Map...</string> + </property> + </action> + <action name="action_Exit"> <property name="text"> <string>E&xit</string> </property> @@ -101,28 +102,28 @@ <string>&Pause</string> </property> </action> - <action name="action_Stop"> - <property name="enabled"> - <bool>false</bool> - </property> - <property name="text"> - <string>&Stop</string> - </property> - </action> - <action name="action_About"> - <property name="text"> - <string>About Citra</string> - </property> - </action> - <action name="action_Single_Window_Mode"> - <property name="checkable"> - <bool>true</bool> - </property> - <property name="text"> - <string>Single Window Mode</string> - </property> - </action> - <action name="action_Hotkeys"> + <action name="action_Stop"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>&Stop</string> + </property> + </action> + <action name="action_About"> + <property name="text"> + <string>About Citra</string> + </property> + </action> + <action name="action_Single_Window_Mode"> + <property name="checkable"> + <bool>true</bool> + </property> + <property name="text"> + <string>Single Window Mode</string> + </property> + </action> + <action name="action_Hotkeys"> <property name="text"> <string>Configure &Hotkeys ...</string> </property> @@ -132,6 +133,14 @@ <string>Configure ...</string> </property> </action> + <action name="actionDisplay_widget_title_bars"> + <property name="checkable"> + <bool>true</bool> + </property> + <property name="text"> + <string>Display Dock Widget Headers</string> + </property> + </action> </widget> <resources/> <connections> @@ -167,8 +176,25 @@ </hint> </hints> </connection> + <connection> + <sender>actionDisplay_widget_title_bars</sender> + <signal>triggered(bool)</signal> + <receiver>MainWindow</receiver> + <slot>OnDisplayTitleBars(bool)</slot> + <hints> + <hint type="sourcelabel"> + <x>-1</x> + <y>-1</y> + </hint> + <hint type="destinationlabel"> + <x>540</x> + <y>364</y> + </hint> + </hints> + </connection> </connections> <slots> <slot>OnConfigure()</slot> + <slot>OnDisplayTitleBars(bool)</slot> </slots> </ui> diff --git a/src/citra_qt/util/spinbox.cpp b/src/citra_qt/util/spinbox.cpp index 54f628e4c..1e3767c18 100644 --- a/src/citra_qt/util/spinbox.cpp +++ b/src/citra_qt/util/spinbox.cpp @@ -36,7 +36,7 @@ #include "spinbox.h" -CSpinBox::CSpinBox(QWidget* parent) : QAbstractSpinBox(parent), base(10), min_value(-100), max_value(100), value(0), num_digits(0) +CSpinBox::CSpinBox(QWidget* parent) : QAbstractSpinBox(parent), min_value(-100), max_value(100), value(0), base(10), num_digits(0) { // TODO: Might be nice to not immediately call the slot. // Think of an address that is being replaced by a different one, in which case a lot |
