#pragma once #include #include #include #include #include #include "binaryninjaapi.h" #include "action.h" #include "preview.h" #include "uitypes.h" #define PREVIEW_HOVER_TIME 500 typedef bool (*UIPluginInitFunction)(void); typedef void (*UIPluginDependencyFunction)(void); typedef uint32_t (*UIPluginABIVersionFunction)(void); class ViewFrame; class UIActionHandler; class FileContext; class ViewLocation; class Sidebar; class SidebarWidgetContainer; class GlobalArea; class Pane; class ProjectStatusWidget; struct SelectionInfoForXref; /*! \defgroup uicontext UIContext \ingroup uiapi */ /*! Interface used to receive notifications related to files and contexts. Many notifications include the ability to modify the behavior of the context. \ingroup uicontext */ class BINARYNINJAUIAPI UIContextNotification { public: virtual ~UIContextNotification(); /*! Callback after a UIContext is opened (eg MainWindow) \param context Opened context */ virtual void OnContextOpen(UIContext* context) { (void)context; } /*! Callback right before closing a UIContext \param context Closing context */ virtual void OnContextClose(UIContext* context) { (void)context; } /*! Callback before a database (specifically a database, not a raw file) is opened \param context Context opening the database \param metadata Object with info about the database file \return True if the database should be opened */ virtual bool OnBeforeOpenDatabase(UIContext* context, FileMetadataRef metadata) { (void)context; (void)metadata; return true; } /*! Callback after a database (specifically a database, not a raw file) is opened \param context Context which opened the database \param metadata Object with info about the database file \param data Raw data which is backed by the database \return True if the database should be opened */ virtual bool OnAfterOpenDatabase(UIContext* context, FileMetadataRef metadata, BinaryViewRef data) { (void)context; (void)metadata; (void)data; return true; } /*! Callback after a project is opened \param context Context which opened the project \param project Project that was opened \param frame ViewFrame constructed to display the project */ virtual void OnAfterOpenProject(UIContext* context, ProjectRef project) { (void)context; (void)project; } /*! Callback before a project file is opened \param context Context opening the project file \param projectFile Project file that is being opened \return True if the project file should be opened */ virtual bool OnBeforeOpenProjectFile(UIContext* context, ProjectFileRef projectFile) { (void)context; (void)projectFile; return true; } /*! Callback after a project file is opened \param context Context which opened the project file \param projectFile Project file that was opened \param frame ViewFrame constructed to display the project file */ virtual void OnAfterOpenProjectFile(UIContext* context, ProjectFileRef projectFile, ViewFrame* frame) { (void)context; (void)projectFile; (void)frame; } /*! Callback before a file (raw or database) is opened (after OnAfterOpenDatabase if opening a database) \param context Context opening the file \param file Context with the file and ui views \return True if the file should be opened */ virtual bool OnBeforeOpenFile(UIContext* context, FileContext* file) { (void)context; (void)file; return true; } /*! Callback after a file (raw or database) is opened \param context Context which opened the file \param file Context with the file and ui views \param frame ViewFrame constructed to display the file */ virtual void OnAfterOpenFile(UIContext* context, FileContext* file, ViewFrame* frame) { (void)context; (void)file; (void)frame; } /*! Callback before a file is saved (either as a database or raw) \param context Context which is saving the file \param file Context with the file and ui views \param frame ViewFrame for the file \return True if the file should be saved */ virtual bool OnBeforeSaveFile(UIContext* context, FileContext* file, ViewFrame* frame) { (void)context; (void)file; (void)frame; return true; } /*! Callback after a file is saved (either as a database or raw) \param context Context which saved the file \param file Context with the file and ui views \param frame ViewFrame for the file */ virtual void OnAfterSaveFile(UIContext* context, FileContext* file, ViewFrame* frame) { (void)context; (void)file; (void)frame; } /*! Callback before a file is closed \param context Context which is closing the file \param file Context with the file and ui views \param frame ViewFrame for the file \return True if the file should be closed */ virtual bool OnBeforeCloseFile(UIContext* context, FileContext* file, ViewFrame* frame) { (void)context; (void)file; (void)frame; return true; } /*! Callback after a file is closed \param context Context which closed the file \param file Context with the file and ui views \param frame ViewFrame which former showed the file (will be deleted after this) */ virtual void OnAfterCloseFile(UIContext* context, FileContext* file, ViewFrame* frame) { (void)context; (void)file; (void)frame; } /*! Callback after a ViewFrame is replaced in an open file (e.g. on Rebase or Sync) \param context Context which replaced the view \param file Context with the file and ui views \param oldFrame Old ViewFrame being deleted \param newFrame New ViewFrame being created */ virtual void OnViewReplaced( UIContext* context, FileContext* file, ViewFrame* oldFrame, ViewFrame* newFrame ) { (void)context; (void)file; (void)oldFrame; (void)newFrame; } /*! Callback after a BinaryView is replaced in an open file (e.g. on Rebase) \param context Context which replaced the view \param file Context with the file and ui views \param oldData Old BinaryView with that name \param newData New BinaryView with that name */ virtual void OnDataViewReplaced(UIContext* context, FileContext* file, BinaryViewRef oldData, BinaryViewRef newData) { (void)context; (void)file; (void)oldData; (void)newData; } /*! Callback when the ui changes views \param context Context changing views \param frame ViewFrame which changed views \param type New view name */ virtual void OnViewChange(UIContext* context, ViewFrame* frame, const QString& type) { (void)context; (void)frame; (void)type; } /*! Callback when the ui changes address \param context Context changing address \param frame ViewFrame which changed address \param view Currently open View \param location New location */ virtual void OnAddressChange(UIContext* context, ViewFrame* frame, View* view, const ViewLocation& location) { (void)context; (void)frame; (void)view; (void)location; } /*! Callback when the ui changes IL view type \param context Context changing address \param frame ViewFrame which changed address \param view Currently open View \param viewType New view type */ virtual void OnILViewTypeChange( UIContext* context, ViewFrame* frame, View* view, const BinaryNinja::FunctionViewType& viewType) { (void)context; (void)frame; (void)view; (void)viewType; } /*! Callback to modify the displayed file name for a FileContext (eg in the window title or tab title) Note: Due to the out param &name, this is not usable from Python with PySide \param context Context which will display this name \param file File whose name to get \param name [Out] Name to be displayed \return True if the value in name should be used */ virtual bool GetNameForFile(UIContext* context, FileContext* file, QString& name) { (void)context; (void)file; (void)name; return false; } /*! Callback to modify the displayed file name for a file path (eg in the new tab widget) Note: Due to the out param &name, this is not usable from Python with PySide \param context Context which will display this name \param path Path to file whose name to get \param name [Out] Name to be displayed \return True if the value in name should be used */ virtual bool GetNameForPath(UIContext* context, const QString& path, QString& name) { (void)context; (void)path; (void)name; return false; } /*! Callback when the ui changes selection and should update cross references \param context Context changing selection \param frame ViewFrame which changed selection \param view View that changed selection \param selection New selection */ virtual void OnNewSelectionForXref( UIContext* context, ViewFrame* frame, View* view, const SelectionInfoForXref& selection) { (void)context; (void)frame; (void)view; (void)selection; } /*! Callback when an action is executed, allowing plugins to intercept and modify the behavior of the action. Plugins may modify the `action` parameter and specify new behavior for the action to execute, which will happen immediately after all registered notifications have been notified. The original behavior (potentially modified by another notification) can be executed by saving a copy of the value of `action` and calling it from within your modified value. \param context \param handler \param name \param ctx \param action */ virtual void OnActionExecuted(UIContext* context, UIActionHandler* handler, const QString& name, const UIActionContext& ctx, std::function& action) { (void)context; (void)handler; (void)name; (void)ctx; (void)action; } /*! * Callback when an action is executed. Unlike OnActionExecuted, plugins cannot * modify the behavior of the action. * * \param context * \param handler * \param name * \param ctx */ virtual void OnActionExecutedImmutable(UIContext* context, UIActionHandler* handler, const QString& name, const UIActionContext& ctx) { (void)context; (void)handler; (void)name; (void)ctx; } /*! Callback when a context menu is created, allowing plugins to modify the menu, e.g., registering and adding new actions into it. This allow plugins to add new entries into the top-level context menu in a non-hacky way. However, it is advised that the plugin should only use this instead of PluginCommand::Register or similar APIs when it is necessary. Besides, if a plugins wishes to add multiple actions, it is better to put them as sub-menus under a single top-level entry, avoiding making the context menu crowded. This only works for linear/graph/hex/types/stack view due to the way other views create the context menus. \param context \param view \param menu */ virtual void OnContextMenuCreated(UIContext* context, View* view, Menu& menu) { (void)context; (void)view; (void)menu; } }; /*! \ingroup uicontext */ class BINARYNINJAUIAPI UIContextHandler { public: virtual ~UIContextHandler(); virtual void updateStatus() = 0; virtual void notifyThemeChanged() = 0; virtual void registerFileOpenMode(const QString& buttonName, const QString& description, const QString& action); }; /*! \ingroup uicontext */ class BINARYNINJAUIAPI UIContext { static UIContextHandler* m_handler; static std::set m_contexts; UIActionHandler m_globalActions; static std::list m_notifications; static QPointer m_currentPreview; QSettings m_qsettings; protected: void setupUIContext(QWidget* obj); public: UIContext(); virtual ~UIContext(); virtual QMainWindow* mainWindow() = 0; virtual void releaseBinaryView(BinaryViewRef view); virtual void viewChanged(ViewFrame* frame, const QString& type); virtual bool navigateForBinaryView(BinaryViewRef view, uint64_t addr); /*! Navigate to a named type in the context, optionally at a member offset \param name Name of type to which to navigate \param offset Offset of member in type to which to navigate \return True if navigation succeeded */ virtual bool navigateToType(const std::string& name, uint64_t offset = 0) = 0; /*! Get a list of all opened binary views, and their names \return List of binary views and names */ virtual std::vector> getAvailableBinaryViews() = 0; /*! Gets the tab for for a given sessionId */ virtual QWidget* getTabForSessionId(uint64_t sessionId) = 0; /*! Gets the name of a tab for the given session */ virtual QString getTabNameForSessionId(uint64_t sessionId) = 0; /*! Get the currently visible View for the currently visible ViewFrame (if it exists) \return Current View or nullptr if the current ViewFrame is null or does not have a View */ virtual View* getCurrentView() = 0; /*! Get the currently visible ViewFrame (if it exists) \return Current ViewFrame or nullptr if the current widget does not have a ViewFrame */ virtual ViewFrame* getCurrentViewFrame() = 0; /*! Get the current Action Handler for the focused widget \return Current Action Handler if the focused widget (or one of its parents) has one, else nullptr */ virtual UIActionHandler* getCurrentActionHandler() = 0; /*! Rebase the current BinaryView to a new address, updating the UI appropriately. \param address New address for rebasing the current BinaryView \return True if the rebase was successful, false otherwise */ virtual bool rebaseCurrentView(uint64_t address) = 0; /*! Open a tab containing the given widget with the given name \param name Name for tab \param widget Widget to display in the tab (optionally a ViewFrame) \return Index of created tab */ virtual int createTabForWidget(const QString& name, QWidget* widget) = 0; /*! * Open a new window with the same file context and Navigate to a given location * @param location */ virtual void splitToNewWindowAndNavigateToLocation(uint64_t location) = 0; /*! * Open a new tab with the same file context and Navigate to a given location * @param location */ virtual void splitToNewTabAndNavigateToLocation(uint64_t location) = 0; /*! Open a new pane in the active tab \param pane Pane widget to open \param primaryDirection Primary axis for content in pane (determines default split direction) */ virtual void openPane(Pane* pane, Qt::Orientation primaryDirection = Qt::Vertical) = 0; /*! Get a list of all tabs as QWidgets \return All tabs */ virtual QList getTabs() = 0; /*! Get the QWidget responsible for the tab with the given name \param name Name of tab to get \return QWidget of tab if one with that name exists */ virtual QWidget* getTabForName(const QString& name) = 0; /*! Get the QWidget responsible for the tab with the given file \param file File of tab to get \return QWidget of tab if one with that file exists */ virtual QWidget* getTabForFile(FileContext* file) = 0; /*! Get the name of the tab with the given QWidget \param tab QWidget which is in a tab \return Name of the tab, or empty string if no tab is found */ virtual QString getNameForTab(QWidget* tab) = 0; /*! Activate and make visible the tab with the given QWidget \param tab QWidget which is in a tab */ virtual void activateTab(QWidget* tab) = 0; /*! Close the tab with the given QWidget \param tab QWidget which is in a tab \param closeWindowIfLast If false, displays the new tab page if the widget was the last tab */ virtual void closeTab(QWidget* tab, bool closeWindowIfLast = false) = 0; /*! Get the QWidget in the currently open tab \return QWidget for current tab. Qt claims "this value is never 0 (but if you try hard enough, it can be)" */ virtual QWidget* getCurrentTab() = 0; virtual QWidget* createNewTab(bool focus = true) = 0; /*! Get the current View associated with the given QWidget, if it exists \param tab QWidget which could be a ViewFrame \return View for the QWidget, or nullptr if the QWidget is not a ViewFrame or does not have a View */ virtual View* getViewForTab(QWidget* tab) = 0; /*! Get the active ViewFrame associated with the given QWidget, if it exists \param tab QWidget which could be a ViewFrame \return ViewFrame for the QWidget (which is likely itself), or nullptr if the QWidget is not a ViewFrame */ virtual ViewFrame* getViewFrameForTab(QWidget* tab) const = 0; /*! Get all ViewFrame instances associated with the given QWidget, if they exist \param tab QWidget which could contain a ViewFrame \return List of ViewFrame objects for the QWidget */ virtual std::vector getAllViewFramesForTab(QWidget* tab) const = 0; virtual ProjectRef getProject(); virtual ProjectStatusWidget* getProjectStatusWidget(); virtual bool openFilename(const QString& path, bool openOptions = false, bool forceContainerBrowser = false); virtual ProjectRef openProject(const QString& path); virtual ViewFrame* openFileContext(FileContext* file, const QString& forcedView = "", bool addTab = true); virtual bool openProjectFile(ProjectFileRef file, ExternalLocationRef loc = nullptr, bool openWithOptions = false, bool forceContainerBrowser = false); virtual bool openUrl(const QUrl& url, bool openWithOptions = false); virtual void recreateViewFrames(FileContext* file) = 0; virtual void refreshCurrentViewContents(); UIActionHandler* globalActions() { return &m_globalActions; } virtual UIActionHandler* contentActionHandler() = 0; virtual Sidebar* sidebar() = 0; virtual GlobalArea* globalArea() = 0; void NotifyOnContextOpen(); void NotifyOnContextClose(); bool NotifyOnBeforeOpenDatabase(FileMetadataRef metadata); bool NotifyOnAfterOpenDatabase(FileMetadataRef metadata, BinaryViewRef data); void NotifyOnAfterOpenProject(ProjectRef project); bool NotifyOnBeforeOpenProjectFile(ProjectFileRef projectFile); void NotifyOnAfterOpenProjectFile(ProjectFileRef projectFile, ViewFrame* frame); bool NotifyOnBeforeOpenFile(FileContext* file); void NotifyOnAfterOpenFile(FileContext* file, ViewFrame* frame); bool NotifyOnBeforeSaveFile(FileContext* file, ViewFrame* frame); void NotifyOnAfterSaveFile(FileContext* file, ViewFrame* frame); bool NotifyOnBeforeCloseFile(FileContext* file, ViewFrame* frame); void NotifyOnAfterCloseFile(FileContext* file, ViewFrame* frame); void NotifyOnViewReplaced(FileContext* file, ViewFrame* oldFrame, ViewFrame* newFrame); void NotifyOnDataViewReplaced(FileContext* file, BinaryViewRef oldView, BinaryViewRef newView); void NotifyOnViewChange(ViewFrame* frame, const QString& type); void NotifyOnAddressChange(ViewFrame* frame, View* view, const ViewLocation& location); void NotifyOnILViewTypeChange(ViewFrame* frame, View* view, const BinaryNinja::FunctionViewType& viewType); virtual void updateCrossReferences(ViewFrame* frame, View* view, const SelectionInfoForXref& selection); void NotifyOnActionExecuted(UIActionHandler* handler, const QString& name, const UIActionContext& ctx, std::function& action); void NotifyOnActionExecutedImmutable(UIActionHandler* handler, const QString& name, const UIActionContext& ctx); void NotifyOnContextMenuCreated(View* view, Menu& menu); virtual void findAll(const BinaryNinja::FindParameters& params); virtual void beginNavigationForCrossReference(ViewFrame* frame, const SelectionInfoForXref& selection) = 0; virtual void endNavigationForCrossReference() = 0; virtual bool isNavigatingForCrossReference() = 0; /*! Register an object to receive notifications of UIContext events \param notification Object which will receive notifications */ static void registerNotification(UIContextNotification* notification); /*! Unregister an object from receiving notifications of UIContext events \param notification Object which will no longer receive notifications */ static void unregisterNotification(UIContextNotification* notification); /*! Get the displayed name for a given file \param file File whose displayed name to get \return Name to display for this file */ QString GetNameForFile(FileContext* file); /*! Get the displayed name for a path to a file \param path Path to file whose displayed name you want \return Name to display for this path */ QString GetNameForPath(const QString& path); /*! Get the displayed name for a file, resolving container entries within projects \param metadata FileMetadata whose displayed name you want \return Name to display for this file */ QString GetNameForPath(FileMetadataRef metadata); virtual QWidget* fileContentsLockStatusWidget() = 0; void associateAdditionalWindowWithContext(QWidget* window); static void deassociateAdditionalWindowWithContext(QWidget* window); static void setHandler(UIContextHandler* handler); static QSize getScaledWindowSize(int x, int y); static void updateStatus(); static void notifyThemeChanged(); static void showPreview(QWidget* parent, PreviewWidget* preview, QPoint localPos, bool anchorAtPoint = false); static void closePreview(); static bool sendPreviewWheelEvent(QWheelEvent* event); static void closeOtherActiveModalWidget(QWidget* current); static void registerFileOpenMode(const QString& buttonName, const QString& description, const QString& action); static UIContext* contextForWidget(QWidget* widget); static UIContext* activeContext(); static std::set allContexts(); static QWidget* topLevelAt(const QPoint& pt, QWidget* ignoreWidget = nullptr); static QRect placeNewTopLevelWindow(QScreen* screen, const QPoint& pos, QWidget* existingWidget); static ViewFrame* currentViewFrameForWidget(QWidget* widget); }; Q_DECLARE_METATYPE(UIContext*) /*! @addtogroup uicontext @{ */ void BINARYNINJAUIAPI InitUIViews(); void BINARYNINJAUIAPI InitUIActions(); void BINARYNINJAUIAPI InitUIPlugins(); void BINARYNINJAUIAPI SetCurrentUIPluginLoadOrder(BNPluginLoadPhase order); void BINARYNINJAUIAPI AddRequiredUIPluginDependency(const std::string& name); void BINARYNINJAUIAPI AddOptionalUIPluginDependency(const std::string& name); /*! @} */