[Bf-blender-cvs] [d67aab6] object_nodes: Fix for re-entrant update problems, using a base class with a context manager.
Lukas Tönne
noreply at git.blender.org
Sun Dec 6 15:24:00 CET 2015
Commit: d67aab6467da5696e289b940721df8e0bd6f4513
Author: Lukas Tönne
Date: Sun Dec 6 15:21:50 2015 +0100
Branches: object_nodes
https://developer.blender.org/rBd67aab6467da5696e289b940721df8e0bd6f4513
Fix for re-entrant update problems, using a base class with a context manager.
===================================================================
M release/scripts/nodes/common_nodes.py
M release/scripts/nodes/forcefield_nodes.py
M release/scripts/nodes/geometry_nodes.py
M release/scripts/nodes/group_nodes.py
M release/scripts/nodes/object_nodes.py
===================================================================
diff --git a/release/scripts/nodes/common_nodes.py b/release/scripts/nodes/common_nodes.py
index 0377118..8ee2ef0 100644
--- a/release/scripts/nodes/common_nodes.py
+++ b/release/scripts/nodes/common_nodes.py
@@ -18,7 +18,7 @@
# <pep8-80 compliant>
-import bpy
+import bpy, contextlib
import nodeitems_utils
from bpy.types import Operator, ObjectNode
from bpy.props import *
@@ -51,10 +51,24 @@ class NodeTreeBase():
dst = (blink.to_node, blink.to_socket)
compiler.link(output_map[src], input_map[dst])
+class NodeBase():
+ # XXX used to prevent reentrant updates due to RNA calls
+ # this should be fixed in future by avoiding low-level update recursion on the RNA side
+ is_updating = BoolProperty(options={'HIDDEN'})
+
+ @contextlib.contextmanager
+ def update_lock(self):
+ self.is_updating = True
+ try:
+ yield
+ finally:
+ self.is_updating = False
+
+
###############################################################################
# Generic Nodes
-class CommonNodeBase():
+class CommonNodeBase(NodeBase):
@classmethod
def poll(cls, ntree):
return isinstance(ntree, NodeTreeBase)
diff --git a/release/scripts/nodes/forcefield_nodes.py b/release/scripts/nodes/forcefield_nodes.py
index 8245f8a..1e3cb61 100644
--- a/release/scripts/nodes/forcefield_nodes.py
+++ b/release/scripts/nodes/forcefield_nodes.py
@@ -24,7 +24,7 @@ from bpy.types import Operator, ObjectNode, NodeTree, Node, NodeSocket
from bpy.props import *
from nodeitems_utils import NodeCategory, NodeItem
from mathutils import *
-from common_nodes import NodeTreeBase
+from common_nodes import NodeTreeBase, NodeBase
###############################################################################
@@ -50,7 +50,7 @@ class ForceFieldNodeTree(NodeTreeBase, NodeTree):
return False
-class ForceNodeBase():
+class ForceNodeBase(NodeBase):
@classmethod
def poll(cls, ntree):
return ntree.bl_idname == 'ForceFieldNodeTree'
diff --git a/release/scripts/nodes/geometry_nodes.py b/release/scripts/nodes/geometry_nodes.py
index 8a162d3..9ff7432 100644
--- a/release/scripts/nodes/geometry_nodes.py
+++ b/release/scripts/nodes/geometry_nodes.py
@@ -24,7 +24,7 @@ from bpy.types import Operator, ObjectNode, NodeTree, Node
from bpy.props import *
from nodeitems_utils import NodeCategory, NodeItem
from mathutils import *
-from common_nodes import NodeTreeBase
+from common_nodes import NodeTreeBase, NodeBase
import group_nodes
###############################################################################
@@ -52,7 +52,7 @@ class GeometryNodeTree(NodeTreeBase, NodeTree):
return False
-class GeometryNodeBase():
+class GeometryNodeBase(NodeBase):
@classmethod
def poll(cls, ntree):
return ntree.bl_idname == 'GeometryNodeTree'
@@ -94,39 +94,45 @@ class GeometryMeshCombineNode(GeometryNodeBase, ObjectNode):
return socket
def init(self, context):
- self.add_extender()
- self.outputs.new('GeometrySocket', "")
+ if self.is_updating:
+ return
+ with self.update_lock():
+ self.add_extender()
+ self.outputs.new('GeometrySocket', "")
def update_inputs(self, insert=None):
- ntree = self.id_data
-
- # build map of connected inputs
- input_links = dict()
- for link in ntree.links:
- if link.to_node == self:
- input_links[link.to_socket] = (link, link.from_socket)
-
- # remove unconnected sockets
- for socket in self.inputs:
- if socket not in input_links and socket != insert:
- self.inputs.remove(socket)
- else:
- socket.is_placeholder = False
-
- # shift sockets to make room for a new link
- if insert is not None:
- self.inputs.new('GeometrySocket', "")
- nsocket = self.inputs[-1]
- for socket in reversed(self.inputs[:-1]):
- link, from_socket = input_links.get(socket, (None, None))
- if link is not None:
- ntree.links.remove(link)
- ntree.links.new(from_socket, nsocket)
- nsocket = socket
- if socket == insert:
- break
-
- self.add_extender()
+ if self.is_updating:
+ return
+ with self.update_lock():
+ ntree = self.id_data
+
+ # build map of connected inputs
+ input_links = dict()
+ for link in ntree.links:
+ if link.to_node == self:
+ input_links[link.to_socket] = (link, link.from_socket)
+
+ # remove unconnected sockets
+ for socket in self.inputs:
+ if socket not in input_links and socket != insert:
+ self.inputs.remove(socket)
+ else:
+ socket.is_placeholder = False
+
+ # shift sockets to make room for a new link
+ if insert is not None:
+ self.inputs.new('GeometrySocket', "")
+ nsocket = self.inputs[-1]
+ for socket in reversed(self.inputs[:-1]):
+ link, from_socket = input_links.get(socket, (None, None))
+ if link is not None:
+ ntree.links.remove(link)
+ ntree.links.new(from_socket, nsocket)
+ nsocket = socket
+ if socket == insert:
+ break
+
+ self.add_extender()
def update(self):
self.update_inputs()
diff --git a/release/scripts/nodes/group_nodes.py b/release/scripts/nodes/group_nodes.py
index d69bd92..2f2d04e 100644
--- a/release/scripts/nodes/group_nodes.py
+++ b/release/scripts/nodes/group_nodes.py
@@ -277,10 +277,6 @@ def make_node_group_types(prefix, treetype, node_base):
bl_ntree_idname = ntree_idname
bl_id_property_type = 'NODETREE'
- # XXX used to prevent reentrant updates due to RNA calls
- # this should be fixed in future by avoiding low-level update recursion on the RNA side
- is_updating_nodegroup = BoolProperty(options={'HIDDEN'})
-
def bl_id_property_poll(self, ntree):
if not isinstance(ntree, treetype):
return False
@@ -303,13 +299,13 @@ def make_node_group_types(prefix, treetype, node_base):
layout.template_ID(self, "id", new="object_nodes.geometry_nodes_new")
def update(self):
- if not self.is_updating_nodegroup:
- self.is_updating_nodegroup = True
+ if self.is_updating:
+ return
+ with self.update_lock():
gtree = self.id
if gtree:
node_sockets_sync(self.inputs, gtree.inputs)
node_sockets_sync(self.outputs, gtree.outputs)
- self.is_updating_nodegroup = False
def compile(self, compiler):
if self.id is not None:
@@ -320,16 +316,11 @@ def make_node_group_types(prefix, treetype, node_base):
bl_idname = '%sGroupInputNode' % prefix
bl_label = 'Group Inputs'
- # XXX used to prevent reentrant updates due to RNA calls
- # this should be fixed in future by avoiding low-level update recursion on the RNA side
- is_updating_nodegroup = BoolProperty(options={'HIDDEN'})
-
def update(self):
- if not self.is_updating_nodegroup:
- self.is_updating_nodegroup = True
+ if self.is_updating:
+ return
+ with self.update_lock():
node_sockets_sync(self.outputs, self.id_data.inputs)
- self.is_updating_nodegroup = False
- pass
def compile(self, compiler):
gtree = self.id_data
@@ -343,16 +334,11 @@ def make_node_group_types(prefix, treetype, node_base):
bl_idname = '%sGroupOutputNode' % prefix
bl_label = 'Group Outputs'
- # XXX used to prevent reentrant updates due to RNA calls
- # this should be fixed in future by avoiding low-level update recursion on the RNA side
- is_updating_nodegroup = BoolProperty(options={'HIDDEN'})
-
def update(self):
- if not self.is_updating_nodegroup:
- self.is_updating_nodegroup = True
+ if self.is_updating:
+ return
+ with self.update_lock():
node_sockets_sync(self.inputs, self.id_data.outputs)
- self.is_updating_nodegroup = False
- pass
def compile(self, compiler):
gtree = self.id_data
diff --git a/release/scripts/nodes/object_nodes.py b/release/scripts/nodes/object_nodes.py
index 1581b9a..fde964f 100644
--- a/release/scripts/nodes/object_nodes.py
+++ b/release/scripts/nodes/object_nodes.py
@@ -24,7 +24,7 @@ from bpy.types import Operator, ObjectNode, NodeTree, Node, NodeSocket
from bpy.props import *
from nodeitems_utils import NodeCategory, NodeItem
from mathutils import *
-from common_nodes import NodeTreeBase
+from common_nodes import NodeTreeBase, NodeBase
###############################################################################
@@ -53,7 +53,7 @@ class ObjectNodeTree(NodeTreeBase, NodeTree):
return None, None, None
-class ObjectNodeBase():
+class ObjectNodeBase(NodeBase):
@classmethod
def poll(cls, ntree):
return ntree.bl_idname == 'ObjectNodeTree'
More information about the Bf-blender-cvs
mailing list