# Constantly running modal operator

TL;DR: Skip middle paragraph.

I'm trying to make an addon that draws certain info in the view, and have it do that basically all the time that the addon is on.

The way I've been told bgl drawing works is that you put the drawing code in a modal operator. However, all examples I've seen involve starting it from the invoke() method, which is run when the user executes the operator - not what I want. I've also tried putting the bpy.context.window_manager.modal_handler_add(self) code in the register() class method, but because that method does not have access to self, I only got errors with the various arguments I tried (which were: none, the class (its general name), the cls argument that register(cls) gets, and some others. If needed I'll expand on this).

How do I make the operator run "on startup", or how else can I achieve my goal?

• have you tried bpy.app.handlers.load_post.append(load_handler) for running at startup – Chebhou Apr 26 '15 at 20:00
• No, I haven't. What would load_handlerbe in that context? – Ludwik Apr 26 '15 at 20:26
• Ohh, I'm reading the docs right now, handlers might just be awesome! – Ludwik Apr 26 '15 at 20:27
• But hey - couldn't I just use bpy.app.handlers.frame_change_post to draw my stuff and skip the operator altogether? – Ludwik Apr 26 '15 at 20:36
• that would be while the animation playing only – Chebhou Apr 26 '15 at 20:37

I am afraid this is a limitation and you cannot interactively draw with bgl outside of modal operator. There is no way to initialize the drawing handler because it needs the modal operator for access to events and the modal loop where tag redraw would happen.

Tag redraw could be done but the events are the bummer. Linking similar: Get events without running modal

From blender api user events outside of modal can't be caught. There is probably a possibility to catch them with python in monitor space and from blender areas and window positions get them local (like mouse coords).

From user perspective how blender is made it seems the philosophy is that user should have control over modal operators and start/end them manually ideally with button in ui. So something doesn't run in the background without your knowledge. There is somewhere an answer from Brecht on something similar but couln't find it.

There is possibility to call an operator from handlers, but mostly you will get another limitation:

 "RuntimeError: maximum recursion depth exceeded"


Calling the operator from load_pre handler should be fine though. See similar: My custom timer is cancelled when loading a *.blend file

• Yes, I am beginning to see that this might border on the impossible. However, load_pre is not good either because, from what I know, it only runs wneh I'm opening a new file. Or am I wrong? – Ludwik Apr 27 '15 at 10:25
• @Ludwik you are correct, what we need is to monitor whether the modal operator is running or not in the scene_update_pre handler and call it if its not running. This however gives the runtime error :( .. I once came across same issue when trying to display a code minimap in text editor that would display automatically. – Jaroslav Jerryno Novotny Apr 27 '15 at 11:30
• Wrong! I actually just found a way to draw outside a modal operator. Will add my own answer soon. Nevertheless, thanks ;) – Ludwik Apr 28 '15 at 9:47
• @Ludwik If you did your will be a hero and I would thank you billion times! – Jaroslav Jerryno Novotny Apr 28 '15 at 12:38

It seems impossible to make a modal operator run "on startup", without the user starting it. However, it also seems that the following code adds a drawing function on startup (when the addon is registered) and that that function gets executed indefinitely:

def draw_callback_px():
#draw whatever you want here, just thought I'd add something

bgl.glEnable(bgl.GL_BLEND)
bgl.glColor4f(0.0, 0.0, 0.0, 0.5)
bgl.glLineWidth(2)

bgl.glBegin(bgl.GL_LINE_STRIP)

bgl.glVertex3f(0, 0, 0)
bgl.glVertex3f(1, 0, 0)
bgl.glVertex3f(1, 1, 0)
bgl.glVertex3f(1, 1, 1)

bgl.glEnd()

# restore opengl defaults
bgl.glLineWidth(1)
bgl.glDisable(bgl.GL_BLEND)
bgl.glColor4f(0.0, 0.0, 0.0, 1.0)

def register():

• maybe adding bpy.ops.wm.redraw_timer(type='DRAW_WIN_SWAP', iterations=1) to force redraw will solve the "caveat" – Chebhou Apr 28 '15 at 13:36