diff --git a/src/Cutter.pro b/src/Cutter.pro index 42237dbd..25fbc01c 100644 --- a/src/Cutter.pro +++ b/src/Cutter.pro @@ -219,7 +219,8 @@ SOURCES += \ widgets/ComboQuickFilterView.cpp \ dialogs/HexdumpRangeDialog.cpp \ common/QtResImporter.cpp \ - widgets/CutterSeekable.cpp + widgets/CutterSeekable.cpp \ + common/RefreshDeferrer.cpp HEADERS += \ Cutter.h \ @@ -322,7 +323,8 @@ HEADERS += \ widgets/ComboQuickFilterView.h \ dialogs/HexdumpRangeDialog.h \ common/QtResImporter.h \ - widgets/CutterSeekable.h + widgets/CutterSeekable.h \ + common/RefreshDeferrer.h FORMS += \ dialogs/AboutDialog.ui \ diff --git a/src/common/RefreshDeferrer.cpp b/src/common/RefreshDeferrer.cpp new file mode 100644 index 00000000..6b928716 --- /dev/null +++ b/src/common/RefreshDeferrer.cpp @@ -0,0 +1,37 @@ + +#include "RefreshDeferrer.h" +#include "widgets/CutterDockWidget.h" + +RefreshDeferrer::RefreshDeferrer(RefreshDeferrerAccumulator *acc, QObject *parent) : QObject(parent), + acc(acc) +{ +} + +RefreshDeferrer::~RefreshDeferrer() +{ + delete acc; +} + +bool RefreshDeferrer::attemptRefresh(RefreshDeferrerParams params) +{ + if (dockWidget->isVisibleToUser()) { + return true; + } else { + dirty = true; + acc->accumulate(params); + return false; + } +} + +void RefreshDeferrer::registerFor(CutterDockWidget *dockWidget) +{ + this->dockWidget = dockWidget; + connect(dockWidget, &CutterDockWidget::becameVisibleToUser, this, [this]() { + if(dirty) { + emit refreshNow(acc->result()); + acc->clear(); + dirty = false; + } + }); +} + diff --git a/src/common/RefreshDeferrer.h b/src/common/RefreshDeferrer.h new file mode 100644 index 00000000..74f3a452 --- /dev/null +++ b/src/common/RefreshDeferrer.h @@ -0,0 +1,83 @@ + +#ifndef REFRESHDEFERRER_H +#define REFRESHDEFERRER_H + +#include + +class CutterDockWidget; +class RefreshDeferrer; + +using RefreshDeferrerParams = void *; +using RefreshDeferrerParamsResult = void *; + +class RefreshDeferrerAccumulator +{ + friend class RefreshDeferrer; + +public: + virtual ~RefreshDeferrerAccumulator() = default; + +protected: + virtual void accumulate(RefreshDeferrerParams params) =0; + virtual void ignoreParams(RefreshDeferrerParams params) =0; + virtual void clear() =0; + virtual RefreshDeferrerParamsResult result() =0; +}; + +template +class ReplacingRefreshDeferrerAccumulator: public RefreshDeferrerAccumulator +{ +private: + T *value = nullptr; + +public: + ~ReplacingRefreshDeferrerAccumulator() override + { + delete value; + } + +protected: + void accumulate(RefreshDeferrerParams params) override + { + delete value; + value = static_cast(params); + } + + void ignoreParams(RefreshDeferrerParams params) override + { + delete static_cast(params); + } + + void clear() override + { + delete value; + value = nullptr; + } + + virtual RefreshDeferrerParamsResult result() override + { + return value; + } +}; + +class RefreshDeferrer : public QObject +{ + Q_OBJECT + +private: + CutterDockWidget *dockWidget = nullptr; + RefreshDeferrerAccumulator *acc; + bool dirty = false; + +public: + RefreshDeferrer(RefreshDeferrerAccumulator *acc, QObject *parent = nullptr); + virtual ~RefreshDeferrer(); + + bool attemptRefresh(RefreshDeferrerParams params); + void registerFor(CutterDockWidget *dockWidget); + +signals: + void refreshNow(RefreshDeferrerParamsResult paramsResult); +}; + +#endif //REFRESHDEFERRER_H diff --git a/src/widgets/CutterDockWidget.cpp b/src/widgets/CutterDockWidget.cpp index 004cf7a7..9ccd67f3 100644 --- a/src/widgets/CutterDockWidget.cpp +++ b/src/widgets/CutterDockWidget.cpp @@ -12,10 +12,9 @@ CutterDockWidget::CutterDockWidget(MainWindow *main, QAction *action) : connect(action, &QAction::triggered, this, &CutterDockWidget::toggleDockWidget); } - isVisibleToUserCurrent = false; - // Install event filter to catch redraw widgets when needed installEventFilter(this); + updateIsVisibleToUser(); } CutterDockWidget::~CutterDockWidget() {} diff --git a/src/widgets/CutterDockWidget.h b/src/widgets/CutterDockWidget.h index 8d4143ec..27fcb080 100644 --- a/src/widgets/CutterDockWidget.h +++ b/src/widgets/CutterDockWidget.h @@ -13,6 +13,7 @@ public: explicit CutterDockWidget(MainWindow *main, QAction *action = nullptr); ~CutterDockWidget() override; bool eventFilter(QObject *object, QEvent *event) override; + bool isVisibleToUser() { return isVisibleToUserCurrent; } public slots: void toggleDockWidget(bool show); @@ -28,7 +29,6 @@ private: protected: void closeEvent(QCloseEvent *event) override; - bool isVisibleToUser() { return isVisibleToUserCurrent; } }; #endif // CUTTERWIDGET_H diff --git a/src/widgets/DisassemblyWidget.cpp b/src/widgets/DisassemblyWidget.cpp index 8670476b..dadcb1d1 100644 --- a/src/widgets/DisassemblyWidget.cpp +++ b/src/widgets/DisassemblyWidget.cpp @@ -42,6 +42,7 @@ DisassemblyWidget::DisassemblyWidget(MainWindow *main, QAction *action) , mDisasScrollArea(new DisassemblyScrollArea(this)) , mDisasTextEdit(new DisassemblyTextEdit(this)) , seekable(new CutterSeekable(this)) + , disasmRefresh(new ReplacingRefreshDeferrerAccumulator) { topOffset = bottomOffset = RVA_INVALID; cursorLineOffset = 0; @@ -63,6 +64,13 @@ DisassemblyWidget::DisassemblyWidget(MainWindow *main, QAction *action) setupFonts(); setupColors(); + disasmRefresh.registerFor(this); + connect(&disasmRefresh, &RefreshDeferrer::refreshNow, this, [this](RefreshDeferrerParamsResult paramsResult) { + printf("got refresh now!\n"); + RVA *offset = static_cast(paramsResult); + refreshDisasm(*offset); + }); + maxLines = 0; updateMaxLines(); @@ -175,13 +183,6 @@ DisassemblyWidget::DisassemblyWidget(MainWindow *main, QAction *action) ADD_SHORTCUT(QKeySequence(Qt::CTRL + Qt::Key_Plus), &DisassemblyWidget::zoomIn) ADD_SHORTCUT(QKeySequence(Qt::CTRL + Qt::Key_Minus), &DisassemblyWidget::zoomOut) #undef ADD_SHORTCUT - - connect(this, &CutterDockWidget::becameVisibleToUser, this, [this]() { - printf("ooh! we became visible!\n"); - if (disasmDirty) { - refreshDisasm(disasmDirtyOffset); - } - }); } void DisassemblyWidget::toggleSync() @@ -202,15 +203,11 @@ QWidget *DisassemblyWidget::getTextWidget() void DisassemblyWidget::refreshDisasm(RVA offset) { - if (!isVisibleToUser()) { - printf("setting dirty\n"); - disasmDirty = true; - disasmDirtyOffset = offset; + if(!disasmRefresh.attemptRefresh(new RVA(offset))) { + printf("we tried to refresh, but shouldn't yet.\n"); return; - } else { - printf("now refreshing\n"); - disasmDirty = false; } + printf("ok, actually refreshing now!\n"); if (offset != RVA_INVALID) { topOffset = offset; diff --git a/src/widgets/DisassemblyWidget.h b/src/widgets/DisassemblyWidget.h index d61a488a..ea77334d 100644 --- a/src/widgets/DisassemblyWidget.h +++ b/src/widgets/DisassemblyWidget.h @@ -4,6 +4,8 @@ #include "Cutter.h" #include "CutterDockWidget.h" #include "CutterSeekable.h" +#include "common/RefreshDeferrer.h" + #include #include #include @@ -57,8 +59,7 @@ private: int cursorLineOffset; bool seekFromCursor; - bool disasmDirty = false; - RVA disasmDirtyOffset = RVA_INVALID; + RefreshDeferrer disasmRefresh; RVA readCurrentDisassemblyOffset(); RVA readDisassemblyOffset(QTextCursor tc);