7

So i'm trying to add a custom toolbar to IDA 6.4 using their PySide download and the IDAAPI. I've tried adding a toolbar by just creating one but since it doesn't have an exec_() method I can't get it on the screen and it looks like I need to be loading it into a window with something like

self.toolbar = self.addToolBar('var')

though in this case the "self" is a window which makes me think I need a reference to IDA's main window. Anyone know how i can get that reference?

James
  • 193
  • 5
  • not a solution, but just for completeness: in IDA 6.7 + they have significant improvements on this described here: http://www.hexblog.com/?p=886 – w s Oct 28 '15 at 12:12
  • yes I've seen that, but doesn't help me for 6.4, thank you though. I've gotten most of the functionality I need by just building a view that i can dock, not as nice as a toolbar but functional. – James Oct 28 '15 at 12:14

1 Answers1

5

New IDA 6.95 API

Perhaps because they saw this question, maybe because of user requests, version 6.95 was released with two IDAPython API functions for creating a menu and a toolbar: create_menu and create_toolbar so now these can be done trivially.

Old trick - Before 6.95

A hack I've been using is finding the application's main window manually and then adding a toolbar directly using QT. IDA only has one main window.

Adding a toolbar that way makes in completely recognizable by IDA as far as I can tell. You can tick it on and off, you can dock and un-dock it, changing to advanced mode automatically shows it as well. However, IDA won't let you add actions to it in IDA 6.7 and above (as described at hexblog.com/?p=886)

A sample code can look something like that:

 for widget in QtGui.qApp.topLevelWidgets():
     if type(widget) == QtGui.QMainWindow:
         mainWindow = widget
         toolbar = mainWindow.addToolBar("My toolbar")

         # and now for adding stuff to our toolbar
         toolbar.addSeparator()
         toolbar.addWidget(...)

Disclaimer: Keep in mind finding the main window this way if risky, undocumented and might not always work. IDA might not like that you're changing stuff underneath it. I do use it and it is working, but YMMV and UAYOR.

Two additional tips for making this hack functional:

  1. Since IDA's main window is not always visible when plugins are loaded, you might want to set a QTimer on finding the main window.
  2. Because its undocumented, i use more ways to find the main window. Using qApp.activeWindow() and/or qApp.focusWidget() and iterating over their .parent()s are good additional choices.

EDIT:

Here's a more complete example of how to hack a toolbar and a menu in from an IDA plugin, handling different loading modes and retying in case the IDA application is not fully set-up yet:

  def init(self):
    self.setup()

    return idaapi.PLUGIN_KEEP

  def setup(self):
    if not self.get_mainwindow():
      self.delay_setup()
      return

    # Add a toolbar like OP requested
    self.toolbar = self.get_mainwindow().addToolBar("My toolbar")
    self.toolbar.setIconSize(QtCore.QSize(16, 16))

    # Bonus: add a menue
    self.menu = QtGui.QMenu("My menu")
    self.get_mainwindow().menuWidget().addMenu(self.menu)

  def delay_setup(self):
    QtCore.QTimer.singleShot(1000, self.setup)

  def get_mainwindow(self):
    if self.mainwindow:
      return self.mainwindow

    app = QtGui.qApp
    widgets = [app.focusWidget(), app.activeWindow()] + app.topLevelWidgets()
    mainwidgets = filter(None, map(self.search_mainwindow, widgets))

    if mainwidgets:
      self.mainwindow = mainwidgets[0]

    return self.mainwindow

  def search_mainwindow(self, widget):
    while widget != None:
      if isinstance(widget, QtGui.QMainWindow):
        return widget
      widget = widget.parent()
    return None
NirIzr
  • 11,765
  • 1
  • 37
  • 87