This patch makes it possible to call operators from within timers reliably.
The implemented solution is a bit more generic than that, but that's the main purpose for me.
This might not seem like a big deal, but it is the main limitation that stops me from building more
sophisticated tooling in my vs code extension for Blender addon development.
I know that other developers ran into the same limitation as well. I'm not aware of any other reliable
solution to the problem.
This patch adds a new api method called `Region.exec_operator(operator_name) -> OperatorProperties`.
It does not call the operator immediately, but schedules it. Then, Blender will execute it in its main
event loop later on. The operator is executed within the region the `exec_operator` method
was called on.
You can test the basic functionality of the patch by executing the following in the console:
`C.region.exec_operator("mesh.primitive_plane_add").location = (1, 2, 3)`.
This will create a new plane.
When used from within a script, parameters can be passed to the operator as follows.
This matches the convention we use when creating buttons in the ui.
```
lang=python
props = region.exec_operator(operator_name)
props.prop1 = ...
props.prop2 = ...
```
This example will toggle full screen for the 3d view and then open a new file.
This is just to showcase how it generally works, not really a practical use case.
```
lang=python
import bpy
def callback():
for area in bpy.data.window_managers[0].windows[0].screen.areas:
if area.type == "VIEW_3D":
for region in area.regions:
if region.type == "WINDOW":
region.exec_operator("screen.screen_full_area")
def load_other_file():
region = bpy.data.window_managers[0].windows[0].screen.areas[0].regions[0]
region.exec_operator("wm.read_homefile")
bpy.app.timers.register(callback, first_interval=1)
bpy.app.timers.register(callback, first_interval=2)
bpy.app.timers.register(load_other_file, first_interval=3)
```
Here is another example that adds spheres over time. It also seems to work nice with undo.
Every added sphere adds an undo step.
```
lang=python
import bpy
counter = 0
def add_object():
global counter
counter += 1
region = bpy.data.window_managers[0].windows[0].screen.areas[0].regions[0]
props = region.exec_operator("mesh.primitive_uv_sphere_add")
props.location = (counter, 0, 0)
bpy.app.timers.register(add_object, first_interval=1)
bpy.app.timers.register(add_object, first_interval=2)
bpy.app.timers.register(add_object, first_interval=3)
```
I know that the `bpy.data.window_managers[0].windows[0].screen.areas[0].regions[0]` thing is ugly.
However, I think for now it is good to force the developer to pick a region, even if it is not strictly
necessary in all operators.
I also tested this patch with my vs code extension. It allowed me to execute Python scripts
written in vs code directly in Blender in the right context, without having to "touch" the
Blender window.