diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index 7d7019d8..47d95fe8 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -628,25 +628,38 @@ void CutterCore::seek(ut64 offset) } cmd(QString("s %1").arg(offset)); // cmd already does emit seekChanged(core_->offset); - triggerRaisePrioritizedMemoryWidget(); +} + +void CutterCore::showMemoryWidget() +{ + emit showMemoryWidgetRequested(); +} + +void CutterCore::seekAndShow(ut64 offset) +{ + seek(offset); + showMemoryWidget(); +} + +void CutterCore::seekAndShow(QString offset) +{ + seek(offset); + showMemoryWidget(); } void CutterCore::seek(QString thing) { cmdRaw(QString("s %1").arg(thing)); - triggerRaisePrioritizedMemoryWidget(); } void CutterCore::seekPrev() { cmd("s-"); - triggerRaisePrioritizedMemoryWidget(); } void CutterCore::seekNext() { cmd("s+"); - triggerRaisePrioritizedMemoryWidget(); } void CutterCore::updateSeek() @@ -1116,7 +1129,7 @@ void CutterCore::attachDebug(int pid) // attach to process with dbg plugin cmd("o-*; e cfg.debug = true; o+ dbg://" + QString::number(pid)); QString programCounterValue = cmd("dr?`drn PC`").trimmed(); - seek(programCounterValue); + seekAndShow(programCounterValue); emit registersChanged(); if (!currentlyDebugging || !currentlyEmulating) { // prevent register flags from appearing during debug/emul @@ -1141,7 +1154,7 @@ void CutterCore::stopDebug() } else { cmd("dk 9; oo; .ar-"); } - seek(offsetPriorDebugging); + seekAndShow(offsetPriorDebugging); setConfig("asm.flags", true); setConfig("io.cache", false); currentlyDebugging = false; @@ -1185,7 +1198,7 @@ void CutterCore::continueUntilCall() cmd("dcc"); } QString programCounterValue = cmd("dr?`drn PC`").trimmed(); - seek(programCounterValue); + seekAndShow(programCounterValue); emit registersChanged(); } } @@ -1199,7 +1212,7 @@ void CutterCore::continueUntilSyscall() cmd("dcs"); } QString programCounterValue = cmd("dr?`drn PC`").trimmed(); - seek(programCounterValue); + seekAndShow(programCounterValue); emit registersChanged(); } } @@ -1209,7 +1222,7 @@ void CutterCore::stepDebug() if (currentlyDebugging) { cmdEsil("ds"); QString programCounterValue = cmd("dr?`drn PC`").trimmed(); - seek(programCounterValue); + seekAndShow(programCounterValue); emit registersChanged(); } } @@ -1219,7 +1232,7 @@ void CutterCore::stepOverDebug() if (currentlyDebugging) { cmdEsil("dso"); QString programCounterValue = cmd("dr?`drn PC`").trimmed(); - seek(programCounterValue); + seekAndShow(programCounterValue); emit registersChanged(); } } @@ -1229,7 +1242,7 @@ void CutterCore::stepOutDebug() if (currentlyDebugging) { cmd("dsf"); QString programCounterValue = cmd("dr?`drn PC`").trimmed(); - seek(programCounterValue); + seekAndShow(programCounterValue); emit registersChanged(); } } diff --git a/src/core/Cutter.h b/src/core/Cutter.h index eae18004..26dbd699 100644 --- a/src/core/Cutter.h +++ b/src/core/Cutter.h @@ -35,7 +35,6 @@ public: RCore *operator->() const; }; - class CutterCore: public QObject { Q_OBJECT @@ -150,25 +149,25 @@ public: void seekPrev(); void seekNext(); void updateSeek(); + /** + * @brief Raise a memory widget showing current offset, prefer last active + * memory widget. + */ + void showMemoryWidget(); + /** + * @brief Seek to \p offset and raise a memory widget showing it. + * @param offset + */ + void seekAndShow(ut64 offset); + /** + * @brief \see CutterCore::show(ut64) + * @param thing - addressable expression + */ + void seekAndShow(QString thing); RVA getOffset(); RVA prevOpAddr(RVA startAddr, int count); RVA nextOpAddr(RVA startAddr, int count); - /* Disassembly/Graph/Hexdump/Pseudocode view priority */ - enum class MemoryWidgetType { Disassembly, Graph, Hexdump, Pseudocode }; - MemoryWidgetType getMemoryWidgetPriority() const - { - return memoryWidgetPriority; - } - void setMemoryWidgetPriority(MemoryWidgetType type) - { - memoryWidgetPriority = type; - } - void triggerRaisePrioritizedMemoryWidget() - { - emit raisePrioritizedMemoryWidget(memoryWidgetPriority); - } - /* Math functions */ ut64 math(const QString &expr); ut64 num(const QString &expr); @@ -444,16 +443,15 @@ signals: */ void seekChanged(RVA offset); - void raisePrioritizedMemoryWidget(CutterCore::MemoryWidgetType type); void changeDefinedView(); void changeDebugView(); void newMessage(const QString &msg); void newDebugMessage(const QString &msg); -private: - MemoryWidgetType memoryWidgetPriority; + void showMemoryWidgetRequested(); +private: QString notes; RCore *core_ = nullptr; AsyncTaskManager *asyncTaskManager; diff --git a/src/core/MainWindow.cpp b/src/core/MainWindow.cpp index 5b9a733d..f2edeee1 100644 --- a/src/core/MainWindow.cpp +++ b/src/core/MainWindow.cpp @@ -171,6 +171,9 @@ void MainWindow::initUI() connect(core, SIGNAL(newDebugMessage(const QString &)), this->consoleDock, SLOT(addDebugOutput(const QString &))); + connect(core, &CutterCore::showMemoryWidgetRequested, + this, static_cast(&MainWindow::showMemoryWidget)); + updateTasksIndicator(); connect(core->getAsyncTaskManager(), &AsyncTaskManager::tasksChanged, this, &MainWindow::updateTasksIndicator); @@ -178,7 +181,7 @@ void MainWindow::initUI() //Undo and redo seek ui->actionBackward->setShortcut(QKeySequence::Back); ui->actionForward->setShortcut(QKeySequence::Forward); - + /* Setup plugins interfaces */ for (auto plugin : Plugins()->getPlugins()) { plugin->setupInterface(this); @@ -190,7 +193,7 @@ void MainWindow::initUI() void MainWindow::initToolBar() { chooseThemeIcons(); - + // Sepparator between undo/redo and goto lineEdit QWidget *spacer3 = new QWidget(); spacer3->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); @@ -319,7 +322,7 @@ void MainWindow::initDocks() QString className; for (const auto &it : docks) { if (std::none_of(dockWidgets.constBegin(), dockWidgets.constEnd(), - [&it](QDockWidget *w) { return w->objectName() == it; })) { + [&it](QDockWidget * w) { return w->objectName() == it; })) { className = it.split(';').at(0); if (widgetTypeToConstructorMap.contains(className)) { auto widget = widgetTypeToConstructorMap[className](this, nullptr); @@ -839,6 +842,14 @@ void MainWindow::updateDockActionsChecked() } } +MemoryWidgetType MainWindow::getMemoryWidgetTypeToRestore() +{ + if (lastMemoryWidget) { + return lastMemoryWidget->getType(); + } + return MemoryWidgetType::Disassembly; +} + QString MainWindow::getUniqueObjectName(const QString &widgetType) const { QStringList docks; @@ -863,6 +874,90 @@ QString MainWindow::getUniqueObjectName(const QString &widgetType) const return widgetType + ";" + QString::number(id); } +void MainWindow::showMemoryWidget() +{ + if (lastMemoryWidget) { + if (lastMemoryWidget->tryRaiseMemoryWidget()) { + return; + } + } + showMemoryWidget(MemoryWidgetType::Disassembly); +} + +void MainWindow::showMemoryWidget(MemoryWidgetType type) +{ + for (auto &dock : dockWidgets) { + if (auto memoryWidget = qobject_cast(dock)) { + if (memoryWidget->getType() == type && memoryWidget->getSeekable()->isSynchronized()) { + memoryWidget->tryRaiseMemoryWidget(); + return; + } + } + } + auto memoryDockWidget = addNewMemoryWidget(type, Core()->getOffset()); + memoryDockWidget->raiseMemoryWidget(); +} + +QMenu *MainWindow::createShowInMenu(QWidget *parent, RVA address) +{ + QMenu *menu = new QMenu(parent); + for (auto &dock : dockWidgets) { + if (auto memoryWidget = qobject_cast(dock)) { + QAction *action = new QAction(memoryWidget->windowTitle(), menu); + connect(action, &QAction::triggered, this, [this, memoryWidget, address](){ + memoryWidget->getSeekable()->seek(address); + memoryWidget->raiseMemoryWidget(); + }); + menu->addAction(action); + } + } + menu->addSeparator(); + auto createAddNewWidgetAction = [this, menu, address](QString label, MemoryWidgetType type) { + QAction *action = new QAction(label, menu); + connect(action, &QAction::triggered, this, [this, address, type](){ + addNewMemoryWidget(type, address, true); + }); + menu->addAction(action); + }; + createAddNewWidgetAction(tr("New disassembly"), MemoryWidgetType::Disassembly); + createAddNewWidgetAction(tr("New graph"), MemoryWidgetType::Graph); + createAddNewWidgetAction(tr("New hexdump"), MemoryWidgetType::Hexdump); + + return menu; +} + +void MainWindow::setCurrentMemoryWidget(MemoryDockWidget *memoryWidget) +{ + if (memoryWidget->getSeekable()->isSynchronized()) { + lastMemoryWidget = memoryWidget; + } +} + +MemoryDockWidget *MainWindow::addNewMemoryWidget(MemoryWidgetType type, RVA address, + bool synchronized) +{ + MemoryDockWidget *memoryWidget = nullptr; + switch (type) { + case MemoryWidgetType::Graph: + memoryWidget = new GraphWidget(this); + break; + case MemoryWidgetType::Hexdump: + memoryWidget = new HexdumpWidget(this); + break; + case MemoryWidgetType::Disassembly: + memoryWidget = new DisassemblyWidget(this); + break; + case MemoryWidgetType::Pseudocode: + memoryWidget = new PseudocodeWidget(this); + break; + } + auto seekable = memoryWidget->getSeekable(); + seekable->setSynchronization(synchronized); + seekable->seek(address); + addExtraWidget(memoryWidget); + return memoryWidget; +} + void MainWindow::initCorners() { // TODO: Allow the user to select this option visually in the GUI settings @@ -889,12 +984,24 @@ void MainWindow::addWidget(QDockWidget* widget) } updateDockActionsChecked(); }); - } + } +} + +void MainWindow::addMemoryDockWidget(MemoryDockWidget *widget) +{ + connect(widget, &QDockWidget::visibilityChanged, this, [this, widget](bool visibility) { + if (visibility) { + setCurrentMemoryWidget(widget); + } + }); } void MainWindow::removeWidget(QDockWidget *widget) { dockWidgets.removeAll(widget); + if (lastMemoryWidget == widget) { + lastMemoryWidget = nullptr; + } } void MainWindow::updateDockActionChecked(QAction *action) @@ -968,11 +1075,11 @@ void MainWindow::resetToDefaultLayout() void MainWindow::resetToDebugLayout() { - CutterCore::MemoryWidgetType memType = core->getMemoryWidgetPriority(); + MemoryWidgetType memType = getMemoryWidgetTypeToRestore(); hideAllDocks(); restoreDocks(); showDebugDocks(); - core->raisePrioritizedMemoryWidget(memType); + showMemoryWidget(memType); auto restoreStackDock = qhelpers::forceWidth(stackDock->widget(), 400); qApp->processEvents(); @@ -981,13 +1088,13 @@ void MainWindow::resetToDebugLayout() void MainWindow::restoreDebugLayout() { - CutterCore::MemoryWidgetType memType = core->getMemoryWidgetPriority(); + MemoryWidgetType memType = getMemoryWidgetTypeToRestore(); bool isMaxim = isMaximized(); hideAllDocks(); restoreDocks(); showDebugDocks(); readDebugSettings(); - core->raisePrioritizedMemoryWidget(memType); + showMemoryWidget(memType); if (isMaxim) { showMaximized(); } else { @@ -1319,12 +1426,12 @@ void MainWindow::changeDebugView() void MainWindow::changeDefinedView() { saveDebugSettings(); - CutterCore::MemoryWidgetType memType = core->getMemoryWidgetPriority(); + MemoryWidgetType memType = getMemoryWidgetTypeToRestore(); hideAllDocks(); restoreDocks(); readSettingsOrDefault(); enableDebugWidgetsMenu(false); - core->raisePrioritizedMemoryWidget(memType); + showMemoryWidget(memType); } void MainWindow::mousePressEvent(QMouseEvent *event) diff --git a/src/core/MainWindow.h b/src/core/MainWindow.h index 8fcfa951..2f784c8f 100644 --- a/src/core/MainWindow.h +++ b/src/core/MainWindow.h @@ -6,6 +6,7 @@ #include "dialogs/WelcomeDialog.h" #include "common/Configuration.h" #include "common/InitialOptions.h" +#include "MemoryDockWidget.h" #include @@ -54,7 +55,6 @@ namespace Ui { class MainWindow; } - class MainWindow : public QMainWindow { Q_OBJECT @@ -95,8 +95,11 @@ public: void refreshOmniBar(const QStringList &flags); void addWidget(QDockWidget *widget); + void addMemoryDockWidget(MemoryDockWidget *widget); void removeWidget(QDockWidget *widget); void addExtraWidget(CutterDockWidget *extraDock); + MemoryDockWidget *addNewMemoryWidget(MemoryWidgetType type, RVA address, bool synchronized = true); + void addPluginDockWidget(QDockWidget *dockWidget, QAction *action); enum class MenuType { File, Edit, View, Windows, Debug, Help, Plugins }; @@ -112,6 +115,11 @@ public: void messageBoxWarning(QString title, QString message); QString getUniqueObjectName(const QString &widgetType) const; + void showMemoryWidget(); + void showMemoryWidget(MemoryWidgetType type); + + QMenu *createShowInMenu(QWidget *parent, RVA address); + void setCurrentMemoryWidget(MemoryDockWidget* memoryWidget); public slots: void finalizeOpen(); @@ -271,10 +279,14 @@ private: void setOverviewData(); bool isOverviewActive(); + MemoryWidgetType getMemoryWidgetTypeToRestore(); + /** * @brief Map from a widget type (e.g. DisassemblyWidget::getWidgetType()) to the respective contructor of the widget */ QMap> widgetTypeToConstructorMap; + + MemoryDockWidget* lastMemoryWidget = nullptr; }; #endif // MAINWINDOW_H diff --git a/src/dialogs/LinkTypeDialog.cpp b/src/dialogs/LinkTypeDialog.cpp index 824bc7cc..6ada457a 100644 --- a/src/dialogs/LinkTypeDialog.cpp +++ b/src/dialogs/LinkTypeDialog.cpp @@ -67,7 +67,7 @@ void LinkTypeDialog::done(int r) QDialog::done(r); // Seek to the specified address - Core()->seek(address); + Core()->seekAndShow(address); // Refresh the views emit Core()->refreshCodeViews(); diff --git a/src/dialogs/XrefsDialog.cpp b/src/dialogs/XrefsDialog.cpp index f7f1c8d5..ef111848 100644 --- a/src/dialogs/XrefsDialog.cpp +++ b/src/dialogs/XrefsDialog.cpp @@ -75,7 +75,7 @@ void XrefsDialog::on_fromTreeWidget_itemDoubleClicked(QTreeWidgetItem *item, int Q_UNUSED(column); XrefDescription xref = item->data(0, Qt::UserRole).value(); - Core()->seek(xref.to); + Core()->seekAndShow(xref.to); this->close(); } @@ -84,7 +84,7 @@ void XrefsDialog::on_toTreeWidget_itemDoubleClicked(QTreeWidgetItem *item, int c Q_UNUSED(column); XrefDescription xref = item->data(0, Qt::UserRole).value(); - Core()->seek(xref.from); + Core()->seekAndShow(xref.from); this->close(); } diff --git a/src/menus/DisassemblyContextMenu.cpp b/src/menus/DisassemblyContextMenu.cpp index b1770351..bb20c09f 100644 --- a/src/menus/DisassemblyContextMenu.cpp +++ b/src/menus/DisassemblyContextMenu.cpp @@ -9,6 +9,7 @@ #include "dialogs/SetToDataDialog.h" #include "dialogs/EditFunctionDialog.h" #include "dialogs/LinkTypeDialog.h" +#include "MainWindow.h" #include #include @@ -17,10 +18,11 @@ #include #include -DisassemblyContextMenu::DisassemblyContextMenu(QWidget *parent) +DisassemblyContextMenu::DisassemblyContextMenu(QWidget *parent, MainWindow* mainWindow) : QMenu(parent), offset(0), - canCopy(false) + canCopy(false), + mainWindow(mainWindow) { initAction(&actionCopy, tr("Copy"), SLOT(on_actionCopy_triggered()), getCopySequence()); addAction(&actionCopy); @@ -28,6 +30,9 @@ DisassemblyContextMenu::DisassemblyContextMenu(QWidget *parent) initAction(&actionCopyAddr, tr("Copy address"), SLOT(on_actionCopyAddr_triggered()), getCopyAddressSequence()); addAction(&actionCopyAddr); + initAction(&showInSubmenu, tr("Show in"), nullptr); + addAction(&showInSubmenu); + copySeparator = addSeparator(); initAction(&actionAddComment, tr("Add Comment"), @@ -379,6 +384,11 @@ void DisassemblyContextMenu::aboutToShowSlot() // Decide to show Reverse jmp option showReverseJmpQuery(); + if (showInSubmenu.menu() != nullptr) { + showInSubmenu.menu()->deleteLater(); + } + showInSubmenu.setMenu(mainWindow->createShowInMenu(this, offset)); + // Only show debug options if we are currently debugging debugMenu->menuAction()->setVisible(Core()->currentlyDebugging); QString progCounterName = Core()->getRegisterName("PC"); diff --git a/src/menus/DisassemblyContextMenu.h b/src/menus/DisassemblyContextMenu.h index 08ae9cf5..3225ab7c 100644 --- a/src/menus/DisassemblyContextMenu.h +++ b/src/menus/DisassemblyContextMenu.h @@ -10,7 +10,7 @@ class DisassemblyContextMenu : public QMenu Q_OBJECT public: - DisassemblyContextMenu(QWidget *parent = nullptr); + DisassemblyContextMenu(QWidget *parent, MainWindow* mainWindow); ~DisassemblyContextMenu(); signals: @@ -101,6 +101,7 @@ private: RVA offset; bool canCopy; QString curHighlightedWord; // The current highlighted word + MainWindow* mainWindow; QList anonymousActions; @@ -164,6 +165,8 @@ private: QAction actionSetToDataDword; QAction actionSetToDataQword; + QAction showInSubmenu; + // For creating anonymous entries (that are always visible) QAction *addAnonymousAction(QString name, const char *slot, QKeySequence shortcut); diff --git a/src/widgets/BreakpointWidget.cpp b/src/widgets/BreakpointWidget.cpp index 3aadf100..af71fd20 100644 --- a/src/widgets/BreakpointWidget.cpp +++ b/src/widgets/BreakpointWidget.cpp @@ -168,7 +168,7 @@ void BreakpointWidget::on_breakpointTreeView_doubleClicked(const QModelIndex &in { BreakpointDescription item = index.data( BreakpointModel::BreakpointDescriptionRole).value(); - Core()->seek(item.addr); + Core()->seekAndShow(item.addr); } void BreakpointWidget::showBreakpointContextMenu(const QPoint &pt) diff --git a/src/widgets/ClassesWidget.cpp b/src/widgets/ClassesWidget.cpp index cc782286..741ce18d 100644 --- a/src/widgets/ClassesWidget.cpp +++ b/src/widgets/ClassesWidget.cpp @@ -634,7 +634,7 @@ void ClassesWidget::on_classesTreeView_doubleClicked(const QModelIndex &index) return; } RVA offset = offsetData.value(); - Core()->seek(offset); + Core()->seekAndShow(offset); } void ClassesWidget::showContextMenu(const QPoint &pt) @@ -696,7 +696,7 @@ void ClassesWidget::on_seekToVTableAction_triggered() return; } - Core()->seek(vtables[0].addr + desc.vtableOffset); + Core()->seekAndShow(vtables[0].addr + desc.vtableOffset); } void ClassesWidget::on_addMethodAction_triggered() diff --git a/src/widgets/CommentsWidget.cpp b/src/widgets/CommentsWidget.cpp index a4ef3365..bf1063b9 100644 --- a/src/widgets/CommentsWidget.cpp +++ b/src/widgets/CommentsWidget.cpp @@ -272,7 +272,7 @@ void CommentsWidget::on_commentsTreeView_doubleClicked(const QModelIndex &index) return; auto comment = index.data(CommentsModel::CommentDescriptionRole).value(); - Core()->seek(comment.offset); + Core()->seekAndShow(comment.offset); } void CommentsWidget::on_actionHorizontal_triggered() diff --git a/src/widgets/CutterDockWidget.cpp b/src/widgets/CutterDockWidget.cpp index 26cf0b87..23ca259e 100644 --- a/src/widgets/CutterDockWidget.cpp +++ b/src/widgets/CutterDockWidget.cpp @@ -86,3 +86,15 @@ QAction *CutterDockWidget::getBoundAction() const return action; } +QString CutterDockWidget::getDockNumber() +{ + auto name = this->objectName(); + if (name.contains(';')) { + auto parts = name.split(';'); + if (parts.size() >= 2) { + return parts[1]; + } + } + return QString(); +} + diff --git a/src/widgets/CutterDockWidget.h b/src/widgets/CutterDockWidget.h index a800b052..b4c1a755 100644 --- a/src/widgets/CutterDockWidget.h +++ b/src/widgets/CutterDockWidget.h @@ -67,9 +67,11 @@ protected: void closeEvent(QCloseEvent *event) override; QAction *getBoundAction() const; + QString getDockNumber(); + + MainWindow *mainWindow; private: - MainWindow *mainWindow; QAction *action; bool isTransient = false; diff --git a/src/widgets/DisassemblerGraphView.cpp b/src/widgets/DisassemblerGraphView.cpp index 0caa856c..38484b96 100644 --- a/src/widgets/DisassemblerGraphView.cpp +++ b/src/widgets/DisassemblerGraphView.cpp @@ -29,10 +29,10 @@ #include -DisassemblerGraphView::DisassemblerGraphView(QWidget *parent, CutterSeekable* seekable) +DisassemblerGraphView::DisassemblerGraphView(QWidget *parent, CutterSeekable* seekable, MainWindow* mainWindow) : GraphView(parent), mFontMetrics(nullptr), - blockMenu(new DisassemblyContextMenu(this)), + blockMenu(new DisassemblyContextMenu(this, mainWindow)), contextMenu(new QMenu(this)), seekable(seekable) { @@ -55,13 +55,6 @@ DisassemblerGraphView::DisassemblerGraphView(QWidget *parent, CutterSeekable* se connect(Config(), SIGNAL(fontsUpdated()), this, SLOT(fontsUpdatedSlot())); connectSeekChanged(false); - // Space to switch to disassembly - QShortcut *shortcut_disassembly = new QShortcut(QKeySequence(Qt::Key_Space), this); - shortcut_disassembly->setContext(Qt::WidgetShortcut); - connect(shortcut_disassembly, &QShortcut::activated, this, [] { - Core()->setMemoryWidgetPriority(CutterCore::MemoryWidgetType::Disassembly); - Core()->triggerRaisePrioritizedMemoryWidget(); - }); // ESC for previous QShortcut *shortcut_escape = new QShortcut(QKeySequence(Qt::Key_Escape), this); shortcut_escape->setContext(Qt::WidgetShortcut); @@ -95,7 +88,6 @@ DisassemblerGraphView::DisassemblerGraphView(QWidget *parent, CutterSeekable* se QShortcut *shortcut_prev_instr = new QShortcut(QKeySequence(Qt::Key_K), this); shortcut_prev_instr->setContext(Qt::WidgetShortcut); connect(shortcut_prev_instr, SIGNAL(activated()), this, SLOT(prevInstr())); - shortcuts.append(shortcut_disassembly); shortcuts.append(shortcut_escape); shortcuts.append(shortcut_zoom_in); shortcuts.append(shortcut_zoom_out); diff --git a/src/widgets/DisassemblerGraphView.h b/src/widgets/DisassemblerGraphView.h index 2a616ea5..b062dc44 100644 --- a/src/widgets/DisassemblerGraphView.h +++ b/src/widgets/DisassemblerGraphView.h @@ -87,7 +87,7 @@ class DisassemblerGraphView : public GraphView }; public: - DisassemblerGraphView(QWidget *parent, CutterSeekable* seekable); + DisassemblerGraphView(QWidget *parent, CutterSeekable* seekable, MainWindow* mainWindow); ~DisassemblerGraphView() override; std::unordered_map disassembly_blocks; virtual void drawBlock(QPainter &p, GraphView::GraphBlock &block) override; diff --git a/src/widgets/DisassemblyWidget.cpp b/src/widgets/DisassemblyWidget.cpp index 74a3e24e..032b4973 100644 --- a/src/widgets/DisassemblyWidget.cpp +++ b/src/widgets/DisassemblyWidget.cpp @@ -39,8 +39,8 @@ static DisassemblyTextBlockUserData *getUserData(const QTextBlock &block) } DisassemblyWidget::DisassemblyWidget(MainWindow *main, QAction *action) - : MemoryDockWidget(CutterCore::MemoryWidgetType::Disassembly, main, action) - , mCtxMenu(new DisassemblyContextMenu(this)) + : MemoryDockWidget(MemoryWidgetType::Disassembly, main, action) + , mCtxMenu(new DisassemblyContextMenu(this, main)) , mDisasScrollArea(new DisassemblyScrollArea(this)) , mDisasTextEdit(new DisassemblyTextEdit(this)) { @@ -161,14 +161,6 @@ DisassemblyWidget::DisassemblyWidget(MainWindow *main, QAction *action) connect(Config(), SIGNAL(fontsUpdated()), this, SLOT(fontsUpdatedSlot())); connect(Config(), SIGNAL(colorsUpdated()), this, SLOT(colorsUpdatedSlot())); - connect(this, &QDockWidget::visibilityChanged, this, [](bool visibility) { - bool emptyGraph = (Core()->getMemoryWidgetPriority() == CutterCore::MemoryWidgetType::Graph - && Core()->isGraphEmpty()); - if (visibility && !emptyGraph) { - Core()->setMemoryWidgetPriority(CutterCore::MemoryWidgetType::Disassembly); - } - }); - connect(Core(), &CutterCore::refreshAll, this, [this]() { refreshDisasm(seekable->getOffset()); }); @@ -192,9 +184,8 @@ DisassemblyWidget::DisassemblyWidget(MainWindow *main, QAction *action) connect(a, &QAction::triggered, this, (slot)); } // Space to switch to graph - ADD_ACTION(Qt::Key_Space, Qt::WidgetWithChildrenShortcut, [] { - Core()->setMemoryWidgetPriority(CutterCore::MemoryWidgetType::Graph); - Core()->triggerRaisePrioritizedMemoryWidget(); + ADD_ACTION(Qt::Key_Space, Qt::WidgetWithChildrenShortcut, [this] { + mainWindow->showMemoryWidget(MemoryWidgetType::Graph); }) ADD_ACTION(Qt::Key_Escape, Qt::WidgetWithChildrenShortcut, &DisassemblyWidget::seekPrev) diff --git a/src/widgets/EntrypointWidget.cpp b/src/widgets/EntrypointWidget.cpp index 831bd404..8e12b80b 100644 --- a/src/widgets/EntrypointWidget.cpp +++ b/src/widgets/EntrypointWidget.cpp @@ -51,5 +51,5 @@ void EntrypointWidget::on_entrypointTreeWidget_itemDoubleClicked(QTreeWidgetItem return; EntrypointDescription ep = item->data(0, Qt::UserRole).value(); - Core()->seek(ep.vaddr); + Core()->seekAndShow(ep.vaddr); } diff --git a/src/widgets/ExportsWidget.cpp b/src/widgets/ExportsWidget.cpp index af948da8..05061d3d 100644 --- a/src/widgets/ExportsWidget.cpp +++ b/src/widgets/ExportsWidget.cpp @@ -183,5 +183,5 @@ void ExportsWidget::on_exportsTreeView_doubleClicked(const QModelIndex &index) return; ExportDescription exp = index.data(ExportsModel::ExportDescriptionRole).value(); - Core()->seek(exp.vaddr); + Core()->seekAndShow(exp.vaddr); } diff --git a/src/widgets/FlagsWidget.cpp b/src/widgets/FlagsWidget.cpp index bc6d9a3a..528d5a36 100644 --- a/src/widgets/FlagsWidget.cpp +++ b/src/widgets/FlagsWidget.cpp @@ -174,7 +174,7 @@ void FlagsWidget::on_flagsTreeView_doubleClicked(const QModelIndex &index) return; FlagDescription flag = index.data(FlagsModel::FlagDescriptionRole).value(); - Core()->seek(flag.offset); + Core()->seekAndShow(flag.offset); } void FlagsWidget::on_flagspaceCombo_currentTextChanged(const QString &arg1) diff --git a/src/widgets/FunctionsWidget.cpp b/src/widgets/FunctionsWidget.cpp index 2ed96fd4..5f0349b6 100644 --- a/src/widgets/FunctionsWidget.cpp +++ b/src/widgets/FunctionsWidget.cpp @@ -522,7 +522,7 @@ void FunctionsWidget::onFunctionsDoubleClicked(const QModelIndex &index) FunctionDescription function = index.data( FunctionModel::FunctionDescriptionRole).value(); - Core()->seek(function.offset); + Core()->seekAndShow(function.offset); } void FunctionsWidget::showFunctionsContextMenu(const QPoint &pt) @@ -556,7 +556,7 @@ void FunctionsWidget::on_actionDisasAdd_comment_triggered() // Rename function in r2 core Core()->setComment(function.offset, comment); // Seek to new renamed function - Core()->seek(function.offset); + Core()->seekAndShow(function.offset); // TODO: Refresh functions tree widget } } @@ -581,7 +581,7 @@ void FunctionsWidget::on_actionFunctionsRename_triggered() Core()->renameFunction(function.name, new_name); // Seek to new renamed function - Core()->seek(function.offset); + Core()->seekAndShow(function.offset); } } diff --git a/src/widgets/GraphWidget.cpp b/src/widgets/GraphWidget.cpp index ec80f5cd..ac37b8ef 100644 --- a/src/widgets/GraphWidget.cpp +++ b/src/widgets/GraphWidget.cpp @@ -5,7 +5,7 @@ #include GraphWidget::GraphWidget(MainWindow *main, QAction *action) : - MemoryDockWidget(CutterCore::MemoryWidgetType::Graph, main, action) + MemoryDockWidget(MemoryWidgetType::Graph, main, action) { setObjectName(main ? main->getUniqueObjectName(getWidgetType()) @@ -23,7 +23,7 @@ GraphWidget::GraphWidget(MainWindow *main, QAction *action) : header->setReadOnly(true); layout->addWidget(header); - graphView = new DisassemblerGraphView(layoutWidget, seekable); + graphView = new DisassemblerGraphView(layoutWidget, seekable, main); layout->addWidget(graphView); // getting the name of the class is implementation defined, and cannot be @@ -40,16 +40,24 @@ GraphWidget::GraphWidget(MainWindow *main, QAction *action) : connect(this, &QDockWidget::visibilityChanged, this, [ = ](bool visibility) { main->toggleOverview(visibility, this); if (visibility) { - Core()->setMemoryWidgetPriority(CutterCore::MemoryWidgetType::Graph); graphView->onSeekChanged(Core()->getOffset()); } }); + QAction *switchAction = new QAction(this); + switchAction->setShortcut(Qt::Key_Space); + switchAction->setShortcutContext(Qt::WidgetWithChildrenShortcut); + addAction(switchAction); + connect(switchAction, &QAction::triggered, this, [this] { + mainWindow->showMemoryWidget(MemoryWidgetType::Disassembly); + }); + connect(graphView, &DisassemblerGraphView::graphMoved, this, [ = ]() { main->toggleOverview(true, this); }); connect(seekable, &CutterSeekable::seekableSeekChanged, this, &GraphWidget::prepareHeader); connect(Core(), &CutterCore::functionRenamed, this, &GraphWidget::prepareHeader); + graphView->installEventFilter(this); } QWidget *GraphWidget::widgetToFocusOnRaise() diff --git a/src/widgets/HeadersWidget.cpp b/src/widgets/HeadersWidget.cpp index 58f4cd44..403739cf 100644 --- a/src/widgets/HeadersWidget.cpp +++ b/src/widgets/HeadersWidget.cpp @@ -134,5 +134,5 @@ void HeadersWidget::setScrollMode() void HeadersWidget::on_headersTreeView_doubleClicked(const QModelIndex &index) { HeaderDescription item = index.data(HeadersModel::HeaderDescriptionRole).value(); - Core()->seek(item.vaddr); + Core()->seekAndShow(item.vaddr); } diff --git a/src/widgets/HexdumpWidget.cpp b/src/widgets/HexdumpWidget.cpp index 95498b79..a8c1f6ca 100644 --- a/src/widgets/HexdumpWidget.cpp +++ b/src/widgets/HexdumpWidget.cpp @@ -17,7 +17,7 @@ #include HexdumpWidget::HexdumpWidget(MainWindow *main, QAction *action) : - MemoryDockWidget(CutterCore::MemoryWidgetType::Hexdump, main, action), + MemoryDockWidget(MemoryWidgetType::Hexdump, main, action), ui(new Ui::HexdumpWidget) { ui->setupUi(this); @@ -78,13 +78,6 @@ HexdumpWidget::HexdumpWidget(MainWindow *main, QAction *action) : this->ui->hexTextView->addAction(&syncAction); connect(Config(), SIGNAL(fontsUpdated()), this, SLOT(fontsUpdated())); - - connect(this, &QDockWidget::visibilityChanged, this, [](bool visibility) { - if (visibility) { - Core()->setMemoryWidgetPriority(CutterCore::MemoryWidgetType::Hexdump); - } - }); - connect(Core(), &CutterCore::refreshAll, this, [this]() { refresh(); }); connect(seekable, &CutterSeekable::seekableSeekChanged, this, &HexdumpWidget::onSeekChanged); @@ -97,6 +90,7 @@ HexdumpWidget::HexdumpWidget(MainWindow *main, QAction *action) : }); connect(ui->hexTextView, &HexWidget::selectionChanged, this, &HexdumpWidget::selectionChanged); connect(ui->hexSideTab_2, &QTabWidget::currentChanged, this, &HexdumpWidget::refreshSelectionInfo); + ui->hexTextView->installEventFilter(this); initParsing(); selectHexPreview(); diff --git a/src/widgets/ImportsWidget.cpp b/src/widgets/ImportsWidget.cpp index 18d438f8..364764a3 100644 --- a/src/widgets/ImportsWidget.cpp +++ b/src/widgets/ImportsWidget.cpp @@ -194,5 +194,5 @@ void ImportsWidget::on_importsTreeView_doubleClicked(const QModelIndex &index) if (!index.isValid()) return; - Core()->seek(index.data(ImportsModel::AddressRole).toLongLong()); + Core()->seekAndShow(index.data(ImportsModel::AddressRole).toLongLong()); } diff --git a/src/widgets/MemoryDockWidget.cpp b/src/widgets/MemoryDockWidget.cpp index 15da22fd..11a5163f 100644 --- a/src/widgets/MemoryDockWidget.cpp +++ b/src/widgets/MemoryDockWidget.cpp @@ -1,44 +1,64 @@ #include "MemoryDockWidget.h" #include "common/CutterSeekable.h" - +#include "MainWindow.h" #include +#include -MemoryDockWidget::MemoryDockWidget(CutterCore::MemoryWidgetType type, MainWindow *parent, QAction *action) +MemoryDockWidget::MemoryDockWidget(MemoryWidgetType type, MainWindow *parent, QAction *action) : CutterDockWidget(parent, action) , mType(type), seekable(new CutterSeekable(this)) { - connect(Core(), &CutterCore::raisePrioritizedMemoryWidget, this, &MemoryDockWidget::handleRaiseMemoryWidget); + if (parent) { + parent->addMemoryDockWidget(this); + } connect(seekable, &CutterSeekable::syncChanged, this, &MemoryDockWidget::updateWindowTitle); } -void MemoryDockWidget::handleRaiseMemoryWidget(CutterCore::MemoryWidgetType raiseType) +bool MemoryDockWidget::tryRaiseMemoryWidget() { if (!seekable->isSynchronized()) { - return; - } - bool raisingEmptyGraph = (raiseType == CutterCore::MemoryWidgetType::Graph && Core()->isGraphEmpty()); - if (raisingEmptyGraph) { - raiseType = CutterCore::MemoryWidgetType::Disassembly; + return false; } - if (raiseType == mType) { - if (getBoundAction()) { - getBoundAction()->setChecked(true); - } - - show(); - raise(); - widgetToFocusOnRaise()->setFocus(Qt::FocusReason::TabFocusReason); + if (mType == MemoryWidgetType::Graph && Core()->isGraphEmpty()) { + return false; } + raiseMemoryWidget(); + + return true; +} + +void MemoryDockWidget::raiseMemoryWidget() +{ + + if (getBoundAction()) { + getBoundAction()->setChecked(true); + } + + show(); + raise(); + widgetToFocusOnRaise()->setFocus(Qt::FocusReason::TabFocusReason); +} + +bool MemoryDockWidget::eventFilter(QObject *object, QEvent *event) +{ + if (event->type() == QEvent::FocusIn) { + mainWindow->setCurrentMemoryWidget(this); + } + return CutterDockWidget::eventFilter(object, event); } void MemoryDockWidget::updateWindowTitle() { - if (seekable->isSynchronized()) { - setWindowTitle(getWindowTitle()); - } else { - setWindowTitle(getWindowTitle() + CutterSeekable::tr(" (unsynced)")); + QString name = getWindowTitle(); + QString id = getDockNumber(); + if (!id.isEmpty()) { + name += " " + id; } + if (!seekable->isSynchronized()) { + name += CutterSeekable::tr(" (unsynced)"); + } + setWindowTitle(name); } CutterSeekable* MemoryDockWidget::getSeekable() const diff --git a/src/widgets/MemoryDockWidget.h b/src/widgets/MemoryDockWidget.h index f5a10bf9..ae9fb1bd 100644 --- a/src/widgets/MemoryDockWidget.h +++ b/src/widgets/MemoryDockWidget.h @@ -6,19 +6,28 @@ class CutterSeekable; +/* Disassembly/Graph/Hexdump/Pseudocode view priority */ +enum class MemoryWidgetType { Disassembly, Graph, Hexdump, Pseudocode }; + class MemoryDockWidget : public CutterDockWidget { Q_OBJECT public: - MemoryDockWidget(CutterCore::MemoryWidgetType type, MainWindow *parent, QAction *action = nullptr); + MemoryDockWidget(MemoryWidgetType type, MainWindow *parent, QAction *action = nullptr); ~MemoryDockWidget() {} CutterSeekable* getSeekable() const; + bool tryRaiseMemoryWidget(); + void raiseMemoryWidget(); + MemoryWidgetType getType() const + { + return mType; + } + bool eventFilter(QObject *object, QEvent *event); private: - void handleRaiseMemoryWidget(CutterCore::MemoryWidgetType raiseType); - CutterCore::MemoryWidgetType mType; + MemoryWidgetType mType; public slots: void updateWindowTitle(); diff --git a/src/widgets/MemoryMapWidget.cpp b/src/widgets/MemoryMapWidget.cpp index 5fe7e18e..3aaa70eb 100644 --- a/src/widgets/MemoryMapWidget.cpp +++ b/src/widgets/MemoryMapWidget.cpp @@ -152,5 +152,5 @@ void MemoryMapWidget::on_memoryTreeView_doubleClicked(const QModelIndex &index) { MemoryMapDescription item = index.data( MemoryMapModel::MemoryDescriptionRole).value(); - Core()->seek(item.addrStart); + Core()->seekAndShow(item.addrStart); } diff --git a/src/widgets/Omnibar.cpp b/src/widgets/Omnibar.cpp index a35b744c..3959afa9 100644 --- a/src/widgets/Omnibar.cpp +++ b/src/widgets/Omnibar.cpp @@ -69,7 +69,7 @@ void Omnibar::on_gotoEntry_returnPressed() { QString str = this->text(); if (!str.isEmpty()) { - Core()->seek(str); + Core()->seekAndShow(str); } this->setText(""); diff --git a/src/widgets/PseudocodeWidget.cpp b/src/widgets/PseudocodeWidget.cpp index 5e68c30d..72791b9e 100644 --- a/src/widgets/PseudocodeWidget.cpp +++ b/src/widgets/PseudocodeWidget.cpp @@ -35,7 +35,7 @@ struct DecompiledCodeTextLine PseudocodeWidget::PseudocodeWidget(MainWindow *main, QAction *action) : - MemoryDockWidget(CutterCore::MemoryWidgetType::Pseudocode, main, action), + MemoryDockWidget(MemoryWidgetType::Pseudocode, main, action), ui(new Ui::PseudocodeWidget) { ui->setupUi(this); @@ -48,12 +48,6 @@ PseudocodeWidget::PseudocodeWidget(MainWindow *main, QAction *action) : connect(Config(), SIGNAL(fontsUpdated()), this, SLOT(fontsUpdated())); connect(Config(), SIGNAL(colorsUpdated()), this, SLOT(colorsUpdatedSlot())); - connect(this, &QDockWidget::visibilityChanged, this, [](bool visibility) { - if (visibility) { - Core()->setMemoryWidgetPriority(CutterCore::MemoryWidgetType::Pseudocode); - } - }); - // TODO Use RefreshDeferrer and remove the refresh button connect(ui->refreshButton, &QAbstractButton::clicked, this, [this]() { doRefresh(Core()->getOffset()); diff --git a/src/widgets/RegisterRefsWidget.cpp b/src/widgets/RegisterRefsWidget.cpp index a905bca6..e75c09f2 100644 --- a/src/widgets/RegisterRefsWidget.cpp +++ b/src/widgets/RegisterRefsWidget.cpp @@ -179,7 +179,7 @@ void RegisterRefsWidget::on_registerRefTreeView_doubleClicked(const QModelIndex { RegisterRefDescription item = index.data( RegisterRefModel::RegisterRefDescriptionRole).value(); - Core()->seek(item.value); + Core()->seekAndShow(item.value); } void RegisterRefsWidget::showRegRefContextMenu(const QPoint &pt) diff --git a/src/widgets/RelocsWidget.cpp b/src/widgets/RelocsWidget.cpp index 39b915f8..67118794 100644 --- a/src/widgets/RelocsWidget.cpp +++ b/src/widgets/RelocsWidget.cpp @@ -147,7 +147,7 @@ void RelocsWidget::on_relocsTreeView_doubleClicked(const QModelIndex &index) if (!index.isValid()) return; - Core()->seek(index.data(RelocsModel::AddressRole).toLongLong()); + Core()->seekAndShow(index.data(RelocsModel::AddressRole).toLongLong()); } void RelocsWidget::refreshRelocs() diff --git a/src/widgets/ResourcesWidget.cpp b/src/widgets/ResourcesWidget.cpp index 3d823ca9..de6ecc85 100644 --- a/src/widgets/ResourcesWidget.cpp +++ b/src/widgets/ResourcesWidget.cpp @@ -107,5 +107,5 @@ void ResourcesWidget::onDoubleClicked(const QModelIndex &index) return; ResourcesDescription res = index.data(Qt::UserRole).value(); - Core()->seek(res.vaddr); + Core()->seekAndShow(res.vaddr); } diff --git a/src/widgets/SearchWidget.cpp b/src/widgets/SearchWidget.cpp index 2c9db07c..5f3fb73e 100644 --- a/src/widgets/SearchWidget.cpp +++ b/src/widgets/SearchWidget.cpp @@ -206,7 +206,7 @@ void SearchWidget::on_searchTreeView_doubleClicked(const QModelIndex &index) SearchDescription search = index.data( SearchModel::SearchDescriptionRole).value(); - Core()->seek(search.offset); + Core()->seekAndShow(search.offset); } void SearchWidget::searchChanged() diff --git a/src/widgets/SectionsWidget.cpp b/src/widgets/SectionsWidget.cpp index 30533aa3..f825b740 100644 --- a/src/widgets/SectionsWidget.cpp +++ b/src/widgets/SectionsWidget.cpp @@ -303,7 +303,7 @@ void SectionsWidget::onSectionsDoubleClicked(const QModelIndex &index) } auto section = index.data(SectionsModel::SectionDescriptionRole).value(); - Core()->seek(section.vaddr); + Core()->seekAndShow(section.vaddr); } void SectionsWidget::resizeEvent(QResizeEvent *event) { @@ -470,7 +470,7 @@ void AddrDockScene::mousePressEvent(QGraphicsSceneMouseEvent *event) if (event->buttons() & Qt::LeftButton) { RVA seekAddr = getAddrFromPos((int)event->scenePos().y(), true); disableCenterOn = true; - Core()->seek(seekAddr); + Core()->seekAndShow(seekAddr); disableCenterOn = false; return; } diff --git a/src/widgets/SegmentsWidget.cpp b/src/widgets/SegmentsWidget.cpp index b97565af..5f24316a 100644 --- a/src/widgets/SegmentsWidget.cpp +++ b/src/widgets/SegmentsWidget.cpp @@ -188,5 +188,5 @@ void SegmentsWidget::onSegmentsDoubleClicked(const QModelIndex &index) return; auto segment = index.data(SegmentsModel::SegmentDescriptionRole).value(); - Core()->seek(segment.vaddr); + Core()->seekAndShow(segment.vaddr); } diff --git a/src/widgets/StackWidget.cpp b/src/widgets/StackWidget.cpp index 68bb5877..660dcf3b 100644 --- a/src/widgets/StackWidget.cpp +++ b/src/widgets/StackWidget.cpp @@ -108,7 +108,7 @@ void StackWidget::onDoubleClicked(const QModelIndex &index) // Check if we are clicking on the offset or value columns and seek if it is the case if (index.column() <= 1) { QString item = index.data().toString(); - Core()->seek(item); + Core()->seekAndShow(item); } } @@ -123,7 +123,7 @@ void StackWidget::customMenuRequested(QPoint pos) void StackWidget::seekOffset() { QString offset = viewStack->selectionModel()->currentIndex().data().toString(); - Core()->seek(offset); + Core()->seekAndShow(offset); } void StackWidget::editStack() diff --git a/src/widgets/StringsWidget.cpp b/src/widgets/StringsWidget.cpp index 716fcf6b..1564365b 100644 --- a/src/widgets/StringsWidget.cpp +++ b/src/widgets/StringsWidget.cpp @@ -204,7 +204,7 @@ void StringsWidget::on_stringsTreeView_doubleClicked(const QModelIndex &index) } StringDescription str = index.data(StringsModel::StringDescriptionRole).value(); - Core()->seek(str.vaddr); + Core()->seekAndShow(str.vaddr); } void StringsWidget::refreshStrings() diff --git a/src/widgets/SymbolsWidget.cpp b/src/widgets/SymbolsWidget.cpp index 942068a2..1d85c940 100644 --- a/src/widgets/SymbolsWidget.cpp +++ b/src/widgets/SymbolsWidget.cpp @@ -150,7 +150,7 @@ void SymbolsWidget::on_symbolsTreeView_doubleClicked(const QModelIndex &index) } auto symbol = index.data(SymbolsModel::SymbolDescriptionRole).value(); - Core()->seek(symbol.vaddr); + Core()->seekAndShow(symbol.vaddr); } void SymbolsWidget::refreshSymbols() diff --git a/src/widgets/VTablesWidget.cpp b/src/widgets/VTablesWidget.cpp index f04d70c2..9cde2777 100644 --- a/src/widgets/VTablesWidget.cpp +++ b/src/widgets/VTablesWidget.cpp @@ -188,10 +188,10 @@ void VTablesWidget::on_vTableTreeView_doubleClicked(const QModelIndex &index) QModelIndex parent = index.parent(); if (parent.isValid()) { - Core()->seek(index.data( + Core()->seekAndShow(index.data( VTableModel::VTableDescriptionRole).value().addr); } else { - Core()->seek(index.data( + Core()->seekAndShow(index.data( VTableModel::VTableDescriptionRole).value().addr); } } diff --git a/src/widgets/ZignaturesWidget.cpp b/src/widgets/ZignaturesWidget.cpp index f98d217c..f8cd63d0 100644 --- a/src/widgets/ZignaturesWidget.cpp +++ b/src/widgets/ZignaturesWidget.cpp @@ -151,5 +151,5 @@ void ZignaturesWidget::on_zignaturesTreeView_doubleClicked(const QModelIndex &in { ZignatureDescription item = index.data( ZignaturesModel::ZignatureDescriptionRole).value(); - Core()->seek(item.offset); + Core()->seekAndShow(item.offset); }