Is there any way to detect an active modal operation?

You can check for an active operator using bpy.context.active_operator, but that’s not actually what I’m looking for here. context.active_operator only gives you the last operator that reported ‘FINISHED’, not one that is currently being executed and is RUNNING_MODAL or PASS_THROUGH. For example, when you hit G and start dragging an object around the scene- is there any way to know that the translate operator has started, and is currently running modal but is not yet finished?

3 Likes

Bumping this as a last ditch effort… I’m trying to fix a hitching issue with my incremental autosave addon (file.001.blend, file.002.blend, etc), where if an autosave triggers in the middle of a modal operator there is an unpleasant hitch. I’m currently using a timer to handle the heavy lifting, and I can even avoid auto saving during renders or playback thanks to event handler callbacks. This is the ONE thing holding me back from releasing this addon (well, that and a recent bug in blender, which I have a workaround for). If anybody knows a way around this I’d appreciate some insight… this is a highly requested feature at my studio and the community in general… I hate to see it rot on the vine like this but I’m ready to table the addon and move on to other things if this is a dead end.

I mean, one would think that when you use wm.modal_handler_add(), the reference to that operator would wind up in bpy.data somewhere, but my digging has turned up nothing.

I did some scanning using the gc module to see if python actually stores a handler. These are the results I got in between running a modal.

<bpy_struct, Event at 0x000001B486118E48>
<bpy_struct, Event at 0x000001B4F7EDD908>
<bpy_struct, OBJECT_OT_modal_operator("OBJECT_OT_modal_operator")>
<function scan_gc at 0x000001B486A071E0>

Which leads me to believe that the handler isn’t actually exposed as a python object. Even worse, modal operators written in C don’t show up at all. So, this looks like a dead end for now.

I think an alternative approach could be to handle any exceptions or set a timeout after which it still fails to save, either alert the user or design a timer around it. Which from by the look of things is what you already did.

Bummer, thanks for the effort in finding a way!

This issue has been bothering me for a long time as well. Shame it’s still not solved :frowning_face:

kaio, do I understand correctly that you used gc.get_objects()? It seems that a python-based active/modal operator can be distinguished by not having a dot (".") in bl_idname and having some other attributes (e.g. “report”).

I also noticed that Blender hides gizmos during some of its built-in operations (move, rotate, scale, etc.). So, under certain assumptions (that there is a 3D view with gizmos enabled), it could be possible to detect at least some of the the built-in modal operators, in a roundabout way (e.g. by checking when a dummy gizmo’s draw() method stops being called).

Turns out modal handlers are stored in a linked list on the window struct. In other words not accessible through the api, but with ctypes.

Python defined modal operators are fairly easy to hook into. You just wrap the modal. But it wouldn’t work for C operators.

active_modals = set()

def callback(func):
    def modal_wrapper(self, context, event):
        cls = type(self)
        _ret, = ret = func(self, context, event)
        if _ret in {'RUNNING_MODAL', 'PASS_THROUGH'}:
            active_modals.add(cls)
        elif _ret in {'FINISHED', 'CANCELLED'}:
            active_modals.discard(cls)
        return ret
    return modal_wrapper

for cls in bpy.types.Operator.__subclasses__():
    if hasattr(cls, "modal"):
        cls.modal = callback(cls.modal)
2 Likes

Wow, thanks! :slightly_smiling_face:

yea, i should have posted the solution here but forgot- I asked over on blenderartists and got the ctypes solution:

1 Like