Page MenuHome

Blender freezes when calling an operator after a dialog window.
Open, Confirmed, MediumPublic

Description

System Information
Operating system: Windows 10 x64

Blender Version
Broken: 2.80 win64, 2019-04-01 19:15
Worked: 2.79b win64, release

Short description of error

If an operator from bpy.ops is called after a dialog window / popup is closed, Blender freezes and has to be manually terminated. A script to reproduce the error is located at the bottom of this task description.

Exact steps for others to reproduce the error

  1. Copy / Paste the code at the bottom of the task description into Blender's text editor
  2. Press "ALT P" to run the script
  3. Place the mouse cursor over a 3D Viewport
  4. Select any object in the 3D View (for example the default cube)
  5. Press "F3" to bring up the search bar
  6. Type in "Popup Input Test" to launch the script
  7. Press "P" to generate a popup dialog
  8. Click the "OK" button in the dialog
  9. Watch Blender freeze and stop responding to input.

Additional Notes

  • The freeze happens at the bpy.ops.transform.translate call in the run_transform function. The following print(" after bpy.ops.transform") statement never executes.
  • The freeze up when executing the run_transform function does not happen if...
    • a popup dialog is not opened first (Press "T" instead of "P" when the script is running).
    • the run_transform function is called from the execute method in the POPUP_OT_input_panel class instead of the draw_callback_px function.
    • the contents of the draw_callback_px function (if self.wait_for_popup ...) are relocated inside the modal method in the POPUP_OT_main class.
    • the script is run in Blender 2.79 instead of 2.80 (the script below can be run in both 2.79 and 2.80).
import bpy
print("\nLoaded add-on.\n")

# globals
popup_active = False
popup_cancel = False


def run_transform():
    print("before bpy.ops.transform")
    bpy.ops.transform.translate(value=(0.0, 0.0, 1.5))
    print("after bpy.ops.transform")


class POPUP_OT_input_panel(bpy.types.Operator):
    bl_idname = "object.popup_input_dialog_op"
    bl_label = "Popup Input Dialog Panel"
    bl_options = {'INTERNAL'}

    def execute(self, context):
        print("\nPOPUP_OT_input_panel: exec")
        global popup_active
        popup_active = False
        #run_transform()
        return {'FINISHED'}

    def invoke(self, context, event):
        print("\nPOPUP_OT_input_panel: Invoke")
        return context.window_manager.invoke_props_dialog(self)

    def cancel(self, context):
        print("\nPOPUP_OT_input_panel: Cancelled")
        global popup_active, popup_cancel
        popup_active = False
        popup_cancel = True


def draw_callback_px(self, context):
    if self.wait_for_popup:
        global popup_active, popup_cancel
        if not popup_active:
            if popup_cancel:
                popup_cancel = False
                self.wait_for_popup = False
            elif not popup_active:
                run_transform()
                self.wait_for_popup = False


class POPUP_OT_main(bpy.types.Operator):
    bl_idname = "view3d.popup_main_op"
    bl_label = "Popup Input Test"

    @classmethod
    def poll(self, context):
        return context.mode == 'OBJECT' or context.mode == 'EDIT_MESH'

    def exit_addon(self):
        bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW')
        print("Exiting addon")
        return {'CANCELLED'}

    def modal(self, context, event):
        context.area.tag_redraw()
        global popup_active

        if event.type in {'A', 'MIDDLEMOUSE', 'WHEELUPMOUSE',
                'WHEELDOWNMOUSE', 'LEFTMOUSE', 'TAB'}:
            return {'PASS_THROUGH'}

        if event.type == 'P' and event.value == 'PRESS':
            if not self.wait_for_popup and not popup_active:
                self.wait_for_popup = True
                popup_active = True
                bpy.ops.object.popup_input_dialog_op('INVOKE_DEFAULT')

        if event.type == 'T' and event.value == 'PRESS':
            if not self.wait_for_popup and not popup_active:
                run_transform()

        elif event.type == 'D' and event.value == 'RELEASE':
            # start debug console
            __import__('code').interact(local=dict(globals(), **locals()))

        elif event.type == 'ESC' and event.value == 'RELEASE':
            return self.exit_addon()

        elif self.force_quit:
            return self.exit_addon()

        #if self.wait_for_popup:

        return {'RUNNING_MODAL'}

    def invoke(self, context, event):
        if context.area.type == 'VIEW_3D':
            args = (self, context)
            self._handle = bpy.types.SpaceView3D.draw_handler_add(
                    draw_callback_px, args, 'WINDOW', 'POST_PIXEL')
            self.force_quit = False
            self.wait_for_popup = False
            context.window_manager.modal_handler_add(self)
            print("Add-on running")
            return {'RUNNING_MODAL'}
        else:
            self.report({'WARNING'}, "View3D not found, cannot run operator")
            return {'CANCELLED'}


def register():
    bpy.utils.register_class(POPUP_OT_input_panel)
    bpy.utils.register_class(POPUP_OT_main)

def unregister():
    bpy.utils.unregister_class(POPUP_OT_input_panel)
    bpy.utils.unregister_class(POPUP_OT_main)

if __name__ == "__main__":
    register()

Details

Type
Bug