Multiple Operator Modal Timers

I have used the Operator Modal Timer template to make two different modal timers. One fires every second, the other every five seconds. When the second ‘TIMER’ event type fires, so does the first one.

Is it possible to determine which of the two timers fired the ‘TIMER’ event type?

edit - I noticed in the API documentation https://docs.blender.org/api/master/bpy.types.Event.html?highlight=modal%20timer there are also events for ‘TIMER 0’ and ‘TIMER 1’ etc. What are these used for?

import bpy


class ModalTimerOperator1(bpy.types.Operator):
    """Operator which runs its self from a timer"""
    bl_idname = "wm.modal_timer_operator_1"
    bl_label = "Modal Timer Operator 1"

    _timer = None

    def modal(self, context, event):
        if event.type in {'RIGHTMOUSE', 'ESC'}:
            self.cancel(context)
            return {'CANCELLED'}

        if event.type == 'TIMER':
            # This timer event gets triggered from wm.modal_timer_operator_2
            print("event timer")

        return {'PASS_THROUGH'}

    def execute(self, context):
        wm = context.window_manager
        self._timer = wm.event_timer_add(1.0, window=context.window)
        wm.modal_handler_add(self)
        return {'RUNNING_MODAL'}

    def cancel(self, context):
        wm = context.window_manager
        wm.event_timer_remove(self._timer)
    
    
class ModalTimerOperator2(bpy.types.Operator):
    """Operator which runs its self from a timer"""
    bl_idname = "wm.modal_timer_operator_2"
    bl_label = "Modal Timer Operator 2"

    _timer = None

    def modal(self, context, event):
        if event.type in {'RIGHTMOUSE', 'ESC'}:
            self.cancel(context)
            return {'CANCELLED'}

        if event.type == 'TIMER':
            pass

        return {'PASS_THROUGH'}

    def execute(self, context):
        wm = context.window_manager
        self._timer = wm.event_timer_add(5.0, window=context.window)
        wm.modal_handler_add(self)
        return {'RUNNING_MODAL'}

    def cancel(self, context):
        wm = context.window_manager
        wm.event_timer_remove(self._timer)


def register():
    bpy.utils.register_class(ModalTimerOperator1)
    bpy.utils.register_class(ModalTimerOperator2)


def unregister():
    bpy.utils.unregister_class(ModalTimerOperator2)
    bpy.utils.unregister_class(ModalTimerOperator1)


if __name__ == "__main__":
    register()

Afaik event.type is a global property and acts like a stdout for all captured events. The other types of timers are for internal use. Eg. viewport tweening uses one type of timer to call the smooth view operator, and operators that use self.report() use a different one to generate motion and color flashing when messages are displayed in the status bar.

If you really want multiple distinct timers, you could make a separate timer object that calls the modal function.

Makes perfect sense! I did suspect it was global. I was wondering if I could filter the event using something like event.source or similar. I have used the new application timers to solve my problem. https://docs.blender.org/api/blender2.8/bpy.app.timers.html

Thanks for your help kaio, really appreciate it.

1 Like