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:
- 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.
- 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