From f4c720cffafb70cfb3938065fb93a3615afd01bd Mon Sep 17 00:00:00 2001 From: xarkes Date: Sat, 12 Jan 2019 18:02:51 +0100 Subject: [PATCH] WIP First PoC to draw only visible after seek --- src/MainWindow.cpp | 106 +++++++++++++++--------------- src/widgets/ConsoleWidget.h | 2 + src/widgets/CutterDockWidget.cpp | 33 +++++++++- src/widgets/CutterDockWidget.h | 14 +++- src/widgets/Dashboard.h | 2 + src/widgets/DisassemblyWidget.cpp | 11 +++- src/widgets/DisassemblyWidget.h | 6 +- src/widgets/FunctionsWidget.h | 2 + src/widgets/GraphWidget.cpp | 5 ++ src/widgets/GraphWidget.h | 4 +- src/widgets/HexdumpWidget.cpp | 8 ++- src/widgets/HexdumpWidget.h | 3 +- src/widgets/PseudocodeWidget.cpp | 8 +-- src/widgets/PseudocodeWidget.h | 2 +- 14 files changed, 134 insertions(+), 72 deletions(-) diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index 05d65249..e6cbc8e8 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -177,44 +177,44 @@ void MainWindow::initUI() disassemblyDock = new DisassemblyWidget(this, ui->actionDisassembly); hexdumpDock = new HexdumpWidget(this, ui->actionHexdump); - pseudocodeDock = new PseudocodeWidget(this, ui->actionPseudocode); + //pseudocodeDock = new PseudocodeWidget(this, ui->actionPseudocode); consoleDock = new ConsoleWidget(this, ui->actionConsole); // Add graph view as dockable graphDock = new GraphWidget(this, ui->actionGraph); - sectionsDock = new SectionsWidget(this, ui->actionSections); - segmentsDock = new SegmentsWidget(this, ui->actionSegments); - entrypointDock = new EntrypointWidget(this, ui->actionEntrypoints); + //sectionsDock = new SectionsWidget(this, ui->actionSections); + //segmentsDock = new SegmentsWidget(this, ui->actionSegments); + //entrypointDock = new EntrypointWidget(this, ui->actionEntrypoints); functionsDock = new FunctionsWidget(this, ui->actionFunctions); - importsDock = new ImportsWidget(this, ui->actionImports); - exportsDock = new ExportsWidget(this, ui->actionExports); - headersDock = new HeadersWidget(this, ui->actionHeaders); - zignaturesDock = new ZignaturesWidget(this, ui->actionZignatures); - typesDock = new TypesWidget(this, ui->actionTypes); - searchDock = new SearchWidget(this, ui->actionSearch); - symbolsDock = new SymbolsWidget(this, ui->actionSymbols); - relocsDock = new RelocsWidget(this, ui->actionRelocs); - commentsDock = new CommentsWidget(this, ui->actionComments); - stringsDock = new StringsWidget(this, ui->actionStrings); - flagsDock = new FlagsWidget(this, ui->actionFlags); - stackDock = new StackWidget(this, ui->actionStack); - backtraceDock = new BacktraceWidget(this, ui->actionBacktrace); - registersDock = new RegistersWidget(this, ui->actionRegisters); - memoryMapDock = new MemoryMapWidget(this, ui->actionMemoryMap); - breakpointDock = new BreakpointWidget(this, ui->actionBreakpoint); - registerRefsDock = new RegisterRefsWidget(this, ui->actionRegisterRefs); + //importsDock = new ImportsWidget(this, ui->actionImports); + //exportsDock = new ExportsWidget(this, ui->actionExports); + //headersDock = new HeadersWidget(this, ui->actionHeaders); + //zignaturesDock = new ZignaturesWidget(this, ui->actionZignatures); + //typesDock = new TypesWidget(this, ui->actionTypes); + //searchDock = new SearchWidget(this, ui->actionSearch); + //symbolsDock = new SymbolsWidget(this, ui->actionSymbols); + //relocsDock = new RelocsWidget(this, ui->actionRelocs); + //commentsDock = new CommentsWidget(this, ui->actionComments); + //stringsDock = new StringsWidget(this, ui->actionStrings); + //flagsDock = new FlagsWidget(this, ui->actionFlags); + //stackDock = new StackWidget(this, ui->actionStack); + //backtraceDock = new BacktraceWidget(this, ui->actionBacktrace); + //registersDock = new RegistersWidget(this, ui->actionRegisters); + //memoryMapDock = new MemoryMapWidget(this, ui->actionMemoryMap); + //breakpointDock = new BreakpointWidget(this, ui->actionBreakpoint); + //registerRefsDock = new RegisterRefsWidget(this, ui->actionRegisterRefs); #ifdef CUTTER_ENABLE_JUPYTER - jupyterDock = new JupyterWidget(this, ui->actionJupyter); + //jupyterDock = new JupyterWidget(this, ui->actionJupyter); #else ui->actionJupyter->setEnabled(false); ui->actionJupyter->setVisible(false); #endif dashboardDock = new Dashboard(this, ui->actionDashboard); - sdbDock = new SdbDock(this, ui->actionSDBBrowser); - classesDock = new ClassesWidget(this, ui->actionClasses); - resourcesDock = new ResourcesWidget(this, ui->actionResources); - vTablesDock = new VTablesWidget(this, ui->actionVTables); + //sdbDock = new SdbDock(this, ui->actionSDBBrowser); + //classesDock = new ClassesWidget(this, ui->actionClasses); + //resourcesDock = new ResourcesWidget(this, ui->actionResources); + //vTablesDock = new VTablesWidget(this, ui->actionVTables); // Set up dock widgets default layout @@ -543,7 +543,7 @@ void MainWindow::lockUnlock_Docks(bool what) void MainWindow::restoreDocks() { // In the upper half the functions are the first widget - addDockWidget(Qt::TopDockWidgetArea, functionsDock); + //addDockWidget(Qt::TopDockWidgetArea, functionsDock); // Function | Dashboard splitDockWidget(functionsDock, dashboardDock, Qt::Horizontal); @@ -552,41 +552,41 @@ void MainWindow::restoreDocks() addDockWidget(Qt::BottomDockWidgetArea, consoleDock); // Console | Sections - splitDockWidget(consoleDock, sectionsDock, Qt::Horizontal); - splitDockWidget(consoleDock, segmentsDock, Qt::Horizontal); + //splitDockWidget(consoleDock, sectionsDock, Qt::Horizontal); + //splitDockWidget(consoleDock, segmentsDock, Qt::Horizontal); // Tabs for center (must be applied after splitDockWidget()) - tabifyDockWidget(sectionsDock, commentsDock); - tabifyDockWidget(segmentsDock, commentsDock); + //tabifyDockWidget(sectionsDock, commentsDock); + //tabifyDockWidget(segmentsDock, commentsDock); tabifyDockWidget(dashboardDock, disassemblyDock); tabifyDockWidget(dashboardDock, graphDock); tabifyDockWidget(dashboardDock, hexdumpDock); - tabifyDockWidget(dashboardDock, pseudocodeDock); - tabifyDockWidget(dashboardDock, entrypointDock); - tabifyDockWidget(dashboardDock, flagsDock); - tabifyDockWidget(dashboardDock, stringsDock); - tabifyDockWidget(dashboardDock, relocsDock); - tabifyDockWidget(dashboardDock, importsDock); - tabifyDockWidget(dashboardDock, exportsDock); - tabifyDockWidget(dashboardDock, typesDock); - tabifyDockWidget(dashboardDock, searchDock); - tabifyDockWidget(dashboardDock, headersDock); - tabifyDockWidget(dashboardDock, zignaturesDock); - tabifyDockWidget(dashboardDock, symbolsDock); - tabifyDockWidget(dashboardDock, classesDock); - tabifyDockWidget(dashboardDock, resourcesDock); - tabifyDockWidget(dashboardDock, vTablesDock); + //tabifyDockWidget(dashboardDock, pseudocodeDock); + //tabifyDockWidget(dashboardDock, entrypointDock); + //tabifyDockWidget(dashboardDock, flagsDock); + //tabifyDockWidget(dashboardDock, stringsDock); + //tabifyDockWidget(dashboardDock, relocsDock); + //tabifyDockWidget(dashboardDock, importsDock); + //tabifyDockWidget(dashboardDock, exportsDock); + //tabifyDockWidget(dashboardDock, typesDock); + //tabifyDockWidget(dashboardDock, searchDock); + //tabifyDockWidget(dashboardDock, headersDock); + //tabifyDockWidget(dashboardDock, zignaturesDock); + //tabifyDockWidget(dashboardDock, symbolsDock); + //tabifyDockWidget(dashboardDock, classesDock); + //tabifyDockWidget(dashboardDock, resourcesDock); + //tabifyDockWidget(dashboardDock, vTablesDock); // Add Stack, Registers and Backtrace vertically stacked - addDockWidget(Qt::TopDockWidgetArea, stackDock); - splitDockWidget(stackDock, registersDock, Qt::Vertical); - tabifyDockWidget(stackDock, backtraceDock); + //addDockWidget(Qt::TopDockWidgetArea, stackDock); + //splitDockWidget(stackDock, registersDock, Qt::Vertical); + //tabifyDockWidget(stackDock, backtraceDock); // MemoryMap/Breakpoint/RegRefs widget goes in the center tabs - tabifyDockWidget(dashboardDock, memoryMapDock); - tabifyDockWidget(dashboardDock, breakpointDock); - tabifyDockWidget(dashboardDock, registerRefsDock); + //tabifyDockWidget(dashboardDock, memoryMapDock); + //tabifyDockWidget(dashboardDock, breakpointDock); + //tabifyDockWidget(dashboardDock, registerRefsDock); #ifdef CUTTER_ENABLE_JUPYTER - tabifyDockWidget(dashboardDock, jupyterDock); + //tabifyDockWidget(dashboardDock, jupyterDock); #endif updateDockActionsChecked(); diff --git a/src/widgets/ConsoleWidget.h b/src/widgets/ConsoleWidget.h index dfc2a84c..c87b5cce 100644 --- a/src/widgets/ConsoleWidget.h +++ b/src/widgets/ConsoleWidget.h @@ -57,6 +57,8 @@ private: void removeLastLine(); void executeCommand(const QString &command); + void refreshContent() override { } + QSharedPointer commandTask; std::unique_ptr ui; diff --git a/src/widgets/CutterDockWidget.cpp b/src/widgets/CutterDockWidget.cpp index 710d43e6..b361a031 100644 --- a/src/widgets/CutterDockWidget.cpp +++ b/src/widgets/CutterDockWidget.cpp @@ -11,8 +11,21 @@ CutterDockWidget::CutterDockWidget(MainWindow *main, QAction *action) : main->addDockWidgetAction(this, action); connect(action, &QAction::triggered, this, &CutterDockWidget::toggleDockWidget); } + + // Install event filter to catch redraw widgets when needed + installEventFilter(this); } +CutterDockWidget::~CutterDockWidget() {} + +bool CutterDockWidget::eventFilter(QObject *object, QEvent *event) +{ + if (event->type() == QEvent::FocusIn || event->type() == QEvent::Paint) { + qDebug() << object << "is now focused in"; + refreshIfNeeded(); + } + return QDockWidget::eventFilter(object, event); +} void CutterDockWidget::toggleDockWidget(bool show) { @@ -21,6 +34,15 @@ void CutterDockWidget::toggleDockWidget(bool show) } else { this->show(); this->raise(); + this->refreshIfNeeded(); + } +} + +void CutterDockWidget::refreshIfNeeded() +{ + if (doRefresh) { + refreshContent(); + doRefresh = false; } } @@ -32,4 +54,13 @@ void CutterDockWidget::closeEvent(QCloseEvent *event) QDockWidget::closeEvent(event); } -CutterDockWidget::~CutterDockWidget() {} +bool CutterDockWidget::isVisibleToUser() +{ + // Check if the user can actually see the widget. + bool visibleToUser = this->isVisible() && !this->visibleRegion().isEmpty(); + if (!visibleToUser) { + // If this is called and not visible, it must be refreshed later + doRefresh = true; + } + return visibleToUser; +} diff --git a/src/widgets/CutterDockWidget.h b/src/widgets/CutterDockWidget.h index cffbe8e0..949199c9 100644 --- a/src/widgets/CutterDockWidget.h +++ b/src/widgets/CutterDockWidget.h @@ -7,21 +7,29 @@ class MainWindow; class CutterDockWidget : public QDockWidget { - Q_OBJECT public: explicit CutterDockWidget(MainWindow *main, QAction *action = nullptr); - ~CutterDockWidget(); + ~CutterDockWidget() override; + bool eventFilter(QObject *object, QEvent *event) override; + public slots: void toggleDockWidget(bool show); - private: QAction *action; + /** + * @brief doRefresh tells if the widget must refresh its content. + */ + bool doRefresh = false; + void refreshIfNeeded(); + protected: void closeEvent(QCloseEvent *event) override; + bool isVisibleToUser(); + virtual void refreshContent() = 0; }; #endif // CUTTERWIDGET_H diff --git a/src/widgets/Dashboard.h b/src/widgets/Dashboard.h index 4018a5d0..754e6da5 100644 --- a/src/widgets/Dashboard.h +++ b/src/widgets/Dashboard.h @@ -25,6 +25,8 @@ private slots: private: std::unique_ptr ui; + + void refreshContent() override { }; }; #endif // DASHBOARD_H diff --git a/src/widgets/DisassemblyWidget.cpp b/src/widgets/DisassemblyWidget.cpp index b8b15025..2e9b3772 100644 --- a/src/widgets/DisassemblyWidget.cpp +++ b/src/widgets/DisassemblyWidget.cpp @@ -268,6 +268,11 @@ void DisassemblyWidget::refreshDisasm(RVA offset) mDisasTextEdit->horizontalScrollBar()->setValue(horizontalScrollValue); } +void DisassemblyWidget::refreshContent() +{ + refreshDisasm(); +} + void DisassemblyWidget::scrollInstructions(int count) { @@ -576,7 +581,7 @@ void DisassemblyWidget::moveCursorRelative(bool up, bool page) bool DisassemblyWidget::eventFilter(QObject *obj, QEvent *event) { - if ((obj == mDisasTextEdit || obj == mDisasTextEdit->viewport()) + /*if ((obj == mDisasTextEdit || obj == mDisasTextEdit->viewport()) && event->type() == QEvent::MouseButtonDblClick) { QMouseEvent *mouseEvent = static_cast(event); @@ -599,8 +604,8 @@ bool DisassemblyWidget::eventFilter(QObject *obj, QEvent *event) } return true; - } - return QDockWidget::eventFilter(obj, event); + }*/ + return CutterDockWidget::eventFilter(obj, event); } void DisassemblyWidget::on_seekChanged(RVA offset) diff --git a/src/widgets/DisassemblyWidget.h b/src/widgets/DisassemblyWidget.h index 059a7e89..174efac9 100644 --- a/src/widgets/DisassemblyWidget.h +++ b/src/widgets/DisassemblyWidget.h @@ -24,7 +24,6 @@ public: public slots: void highlightCurrentLine(); void showDisasContextMenu(const QPoint &pt); - void refreshDisasm(RVA offset = RVA_INVALID); void fontsUpdatedSlot(); void colorsUpdatedSlot(); void seekPrev(); @@ -32,6 +31,7 @@ public slots: private slots: void on_seekChanged(RVA offset); + void refreshDisasm(RVA offset = RVA_INVALID); void raisePrioritizedMemoryWidget(CutterCore::MemoryWidgetType type); void scrollInstructions(int count); @@ -59,10 +59,12 @@ private: RVA readCurrentDisassemblyOffset(); RVA readDisassemblyOffset(QTextCursor tc); - bool eventFilter(QObject *obj, QEvent *event); + bool eventFilter(QObject *obj, QEvent *event) override; QList breakpoints; + void refreshContent() override; + void setupFonts(); void setupColors(); diff --git a/src/widgets/FunctionsWidget.h b/src/widgets/FunctionsWidget.h index 8d01a9b0..b8f1279d 100644 --- a/src/widgets/FunctionsWidget.h +++ b/src/widgets/FunctionsWidget.h @@ -137,6 +137,8 @@ private: CutterTreeWidget *tree; void setScrollMode(); + + void refreshContent() override { } }; diff --git a/src/widgets/GraphWidget.cpp b/src/widgets/GraphWidget.cpp index 6c038daa..ec26acf7 100644 --- a/src/widgets/GraphWidget.cpp +++ b/src/widgets/GraphWidget.cpp @@ -39,3 +39,8 @@ GraphWidget::GraphWidget(MainWindow *main, QAction *action) : } GraphWidget::~GraphWidget() {} + +void GraphWidget::refreshContent() +{ + graphView->refreshView(); +} diff --git a/src/widgets/GraphWidget.h b/src/widgets/GraphWidget.h index dd766841..98c98d00 100644 --- a/src/widgets/GraphWidget.h +++ b/src/widgets/GraphWidget.h @@ -12,11 +12,13 @@ class GraphWidget : public CutterDockWidget public: explicit GraphWidget(MainWindow *main, QAction *action = nullptr); - ~GraphWidget(); + ~GraphWidget() override; private: DisassemblerGraphView *graphView; + void refreshContent() override; + }; #endif // GRAPHWIDGET_H diff --git a/src/widgets/HexdumpWidget.cpp b/src/widgets/HexdumpWidget.cpp index 4a663e83..bbc8bed6 100644 --- a/src/widgets/HexdumpWidget.cpp +++ b/src/widgets/HexdumpWidget.cpp @@ -116,7 +116,7 @@ HexdumpWidget::HexdumpWidget(MainWindow *main, QAction *action) : connect(ui->hexHexText, &QTextEdit::cursorPositionChanged, this, &HexdumpWidget::selectionChanged); connect(ui->hexASCIIText, &QTextEdit::cursorPositionChanged, this, &HexdumpWidget::selectionChanged); - connect(seekable, &CutterSeekable::seekableSeekChanged, this, &HexdumpWidget::on_seekChanged); + connect(seekable, &CutterSeekable::seekableSeekChanged, this, &HexdumpWidget::onSeekChanged); connect(&rangeDialog, &QDialog::accepted, this, &HexdumpWidget::on_rangeDialogAccepted); format = Format::Hex; @@ -208,13 +208,15 @@ void HexdumpWidget::setupScrollSync() asciiHexFunc); } -void HexdumpWidget::on_seekChanged(RVA addr) +void HexdumpWidget::onSeekChanged(RVA addr) { if (sent_seek) { sent_seek = false; return; } - refresh(addr); + if (isVisibleToUser()) { + refreshContent(); + } } void HexdumpWidget::raisePrioritizedMemoryWidget(CutterCore::MemoryWidgetType type) diff --git a/src/widgets/HexdumpWidget.h b/src/widgets/HexdumpWidget.h index 02192582..84f97a2a 100644 --- a/src/widgets/HexdumpWidget.h +++ b/src/widgets/HexdumpWidget.h @@ -72,6 +72,7 @@ private: RVA last_loaded_address = RVA_INVALID; void refresh(RVA addr = RVA_INVALID); + void refreshContent() override { refresh(); } void selectHexPreview(); void updateHeaders(); @@ -110,7 +111,7 @@ private: CutterSeekable *seekable; private slots: - void on_seekChanged(RVA addr); + void onSeekChanged(RVA addr); void raisePrioritizedMemoryWidget(CutterCore::MemoryWidgetType type); // Currently unused/untested diff --git a/src/widgets/PseudocodeWidget.cpp b/src/widgets/PseudocodeWidget.cpp index 38e5a035..eab0305f 100644 --- a/src/widgets/PseudocodeWidget.cpp +++ b/src/widgets/PseudocodeWidget.cpp @@ -31,7 +31,7 @@ PseudocodeWidget::PseudocodeWidget(MainWindow *main, QAction *action) : }); connect(ui->refreshButton, &QAbstractButton::clicked, this, [this]() { - refresh(Core()->getOffset()); + doRefresh(Core()->getOffset()); }); if (Core()->getR2DecAvailable()) { @@ -42,13 +42,13 @@ PseudocodeWidget::PseudocodeWidget(MainWindow *main, QAction *action) : ui->decompilerComboBox->setCurrentIndex(DecompilerCBPdc); } - refresh(RVA_INVALID); + doRefresh(RVA_INVALID); } PseudocodeWidget::~PseudocodeWidget() {} -void PseudocodeWidget::refresh(RVA addr) +void PseudocodeWidget::doRefresh(RVA addr) { if (addr == RVA_INVALID) { ui->textEdit->setText(tr("Click Refresh to generate Pseudocode from current offset.")); @@ -78,7 +78,7 @@ void PseudocodeWidget::refresh(RVA addr) void PseudocodeWidget::refreshPseudocode() { - refresh(Core()->getOffset()); + doRefresh(Core()->getOffset()); } void PseudocodeWidget::raisePrioritizedMemoryWidget(CutterCore::MemoryWidgetType type) diff --git a/src/widgets/PseudocodeWidget.h b/src/widgets/PseudocodeWidget.h index 283fc627..314ed7ae 100644 --- a/src/widgets/PseudocodeWidget.h +++ b/src/widgets/PseudocodeWidget.h @@ -33,7 +33,7 @@ private: SyntaxHighlighter *syntaxHighLighter; - void refresh(RVA addr); + void doRefresh(RVA addr); void setupFonts(); };