Blender  V3.3
wm_message_bus_rna.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
7 #include <stdio.h>
8 
9 #include "CLG_log.h"
10 #include "MEM_guardedalloc.h"
11 
12 #include "DNA_ID.h"
13 
14 #include "BLI_ghash.h"
15 #include "BLI_listbase.h"
16 #include "BLI_utildefines.h"
17 
18 #include "WM_message.h"
19 #include "WM_types.h"
21 
22 #include "RNA_access.h"
23 #include "RNA_path.h"
24 
25 /* -------------------------------------------------------------------- */
29 BLI_INLINE uint void_hash_uint(const void *key)
30 {
31  size_t y = (size_t)key >> (sizeof(void *));
32  return (unsigned int)y;
33 }
34 
35 static uint wm_msg_rna_gset_hash(const void *key_p)
36 {
37  const wmMsgSubscribeKey_RNA *key = key_p;
38  const wmMsgParams_RNA *params = &key->msg.params;
39  // printf("%s\n", RNA_struct_identifier(params->ptr.type));
40  uint k = void_hash_uint(params->ptr.type);
41  k ^= void_hash_uint(params->ptr.data);
42  k ^= void_hash_uint(params->ptr.owner_id);
43  k ^= void_hash_uint(params->prop);
44  return k;
45 }
46 static bool wm_msg_rna_gset_cmp(const void *key_a_p, const void *key_b_p)
47 {
48  const wmMsgParams_RNA *params_a = &((const wmMsgSubscribeKey_RNA *)key_a_p)->msg.params;
49  const wmMsgParams_RNA *params_b = &((const wmMsgSubscribeKey_RNA *)key_b_p)->msg.params;
50  return !((params_a->ptr.type == params_b->ptr.type) &&
51  (params_a->ptr.owner_id == params_b->ptr.owner_id) &&
52  (params_a->ptr.data == params_b->ptr.data) && (params_a->prop == params_b->prop));
53 }
54 static void wm_msg_rna_gset_key_free(void *key_p)
55 {
56  wmMsgSubscribeKey_RNA *key = key_p;
57  wmMsgSubscribeValueLink *msg_lnk_next;
58  for (wmMsgSubscribeValueLink *msg_lnk = key->head.values.first; msg_lnk;
59  msg_lnk = msg_lnk_next) {
60  msg_lnk_next = msg_lnk->next;
61  wm_msg_subscribe_value_free(&key->head, msg_lnk);
62  }
63  if (key->msg.params.data_path != NULL) {
65  }
66  MEM_freeN(key);
67 }
68 
69 static void wm_msg_rna_repr(FILE *stream, const wmMsgSubscribeKey *msg_key)
70 {
71  const wmMsgSubscribeKey_RNA *m = (wmMsgSubscribeKey_RNA *)msg_key;
72  const char *none = "<none>";
73  fprintf(stream,
74  "<wmMsg_RNA %p, "
75  "id='%s', "
76  "%s.%s values_len=%d\n",
77  m,
78  m->msg.head.id,
82 }
83 
84 static void wm_msg_rna_update_by_id(struct wmMsgBus *mbus, ID *id_src, ID *id_dst)
85 {
86  GSet *gs = mbus->messages_gset[WM_MSG_TYPE_RNA];
87  GSetIterator gs_iter;
88  BLI_gsetIterator_init(&gs_iter, gs);
89  while (BLI_gsetIterator_done(&gs_iter) == false) {
91  BLI_gsetIterator_step(&gs_iter);
92  if (key->msg.params.ptr.owner_id == id_src) {
93 
94  /* GSet always needs updating since the key changes. */
95  BLI_gset_remove(gs, key, NULL);
96 
97  /* Remove any non-persistent values, so a single persistent
98  * value doesn't modify behavior for the rest. */
99  for (wmMsgSubscribeValueLink *msg_lnk = key->head.values.first, *msg_lnk_next; msg_lnk;
100  msg_lnk = msg_lnk_next) {
101  msg_lnk_next = msg_lnk->next;
102  if (msg_lnk->params.is_persistent == false) {
103  if (msg_lnk->params.tag) {
104  mbus->messages_tag_count -= 1;
105  }
106  wm_msg_subscribe_value_free(&key->head, msg_lnk);
107  }
108  }
109 
110  bool remove = true;
111 
112  if (BLI_listbase_is_empty(&key->head.values)) {
113  /* Remove, no reason to keep. */
114  }
115  else if (key->msg.params.ptr.data == key->msg.params.ptr.owner_id) {
116  /* Simple, just update the ID. */
117  key->msg.params.ptr.data = id_dst;
118  key->msg.params.ptr.owner_id = id_dst;
119  remove = false;
120  }
121  else {
122  /* We need to resolve this from the new ID pointer. */
123  PointerRNA idptr;
124  RNA_id_pointer_create(id_dst, &idptr);
125  PointerRNA ptr;
126  PropertyRNA *prop = NULL;
127  if (RNA_path_resolve(&idptr, key->msg.params.data_path, &ptr, &prop) &&
128  (prop == NULL) == (key->msg.params.prop == NULL)) {
129  key->msg.params.ptr = ptr;
130  key->msg.params.prop = prop;
131  remove = false;
132  }
133  }
134 
135  if (remove) {
136  for (wmMsgSubscribeValueLink *msg_lnk = key->head.values.first, *msg_lnk_next; msg_lnk;
137  msg_lnk = msg_lnk_next) {
138  msg_lnk_next = msg_lnk->next;
139  if (msg_lnk->params.is_persistent == false) {
140  if (msg_lnk->params.tag) {
141  mbus->messages_tag_count -= 1;
142  }
143  wm_msg_subscribe_value_free(&key->head, msg_lnk);
144  }
145  }
146  /* Failed to persist, remove the key. */
147  BLI_remlink(&mbus->messages, key);
149  }
150  else {
151  /* Note that it's not impossible this key exists, however it is very unlikely
152  * since a subscriber would need to register in the middle of an undo for eg.
153  * so assert for now. */
154  BLI_assert(!BLI_gset_haskey(gs, key));
155  BLI_gset_add(gs, key);
156  }
157  }
158  }
159 }
160 
161 static void wm_msg_rna_remove_by_id(struct wmMsgBus *mbus, const ID *id)
162 {
163  GSet *gs = mbus->messages_gset[WM_MSG_TYPE_RNA];
164  GSetIterator gs_iter;
165  BLI_gsetIterator_init(&gs_iter, gs);
166  while (BLI_gsetIterator_done(&gs_iter) == false) {
168  BLI_gsetIterator_step(&gs_iter);
169  if (key->msg.params.ptr.owner_id == id) {
170  /* Clear here so we can decrement 'messages_tag_count'. */
171  for (wmMsgSubscribeValueLink *msg_lnk = key->head.values.first, *msg_lnk_next; msg_lnk;
172  msg_lnk = msg_lnk_next) {
173  msg_lnk_next = msg_lnk->next;
174  if (msg_lnk->params.tag) {
175  mbus->messages_tag_count -= 1;
176  }
177  wm_msg_subscribe_value_free(&key->head, msg_lnk);
178  }
179 
180  BLI_remlink(&mbus->messages, key);
181  BLI_gset_remove(gs, key, NULL);
183  }
184  }
185 }
186 
188 {
189  msgtype_info->gset.hash_fn = wm_msg_rna_gset_hash;
190  msgtype_info->gset.cmp_fn = wm_msg_rna_gset_cmp;
191  msgtype_info->gset.key_free_fn = wm_msg_rna_gset_key_free;
192 
193  msgtype_info->repr = wm_msg_rna_repr;
194  msgtype_info->update_by_id = wm_msg_rna_update_by_id;
195  msgtype_info->remove_by_id = wm_msg_rna_remove_by_id;
196 
197  msgtype_info->msg_key_size = sizeof(wmMsgSubscribeKey_RNA);
198 }
199 
202 /* -------------------------------------------------------------------- */
207  const wmMsgParams_RNA *msg_key_params)
208 {
209  wmMsgSubscribeKey_RNA key_test;
210  key_test.msg.params = *msg_key_params;
211  return BLI_gset_lookup(mbus->messages_gset[WM_MSG_TYPE_RNA], &key_test);
212 }
213 
214 void WM_msg_publish_rna_params(struct wmMsgBus *mbus, const wmMsgParams_RNA *msg_key_params)
215 {
217 
218  const char *none = "<none>";
220  2,
221  "rna(id='%s', %s.%s)",
222  msg_key_params->ptr.owner_id ? ((ID *)msg_key_params->ptr.owner_id)->name : none,
223  msg_key_params->ptr.type ? RNA_struct_identifier(msg_key_params->ptr.type) : none,
224  msg_key_params->prop ? RNA_property_identifier((PropertyRNA *)msg_key_params->prop) :
225  none);
226 
227  if ((key = WM_msg_lookup_rna(mbus, msg_key_params))) {
228  WM_msg_publish_with_key(mbus, &key->head);
229  }
230 
231  /* Support anonymous subscribers, this may be some extra overhead
232  * but we want to be able to be more ambiguous. */
233  if (msg_key_params->ptr.owner_id || msg_key_params->ptr.data) {
234  wmMsgParams_RNA msg_key_params_anon = *msg_key_params;
235 
236  /* We might want to enable this later? */
237  if (msg_key_params_anon.prop != NULL) {
238  /* All properties for this type. */
239  msg_key_params_anon.prop = NULL;
240  if ((key = WM_msg_lookup_rna(mbus, &msg_key_params_anon))) {
241  WM_msg_publish_with_key(mbus, &key->head);
242  }
243  msg_key_params_anon.prop = msg_key_params->prop;
244  }
245 
246  msg_key_params_anon.ptr.owner_id = NULL;
247  msg_key_params_anon.ptr.data = NULL;
248  if ((key = WM_msg_lookup_rna(mbus, &msg_key_params_anon))) {
249  WM_msg_publish_with_key(mbus, &key->head);
250  }
251 
252  /* Support subscribers to a type. */
253  if (msg_key_params->prop) {
254  msg_key_params_anon.prop = NULL;
255  if ((key = WM_msg_lookup_rna(mbus, &msg_key_params_anon))) {
256  WM_msg_publish_with_key(mbus, &key->head);
257  }
258  }
259  }
260 }
261 
263 {
265  &(wmMsgParams_RNA){
266  .ptr = *ptr,
267  .prop = prop,
268  });
269 }
270 
272  const wmMsgParams_RNA *msg_key_params,
273  const wmMsgSubscribeValue *msg_val_params,
274  const char *id_repr)
275 {
276  wmMsgSubscribeKey_RNA msg_key_test = {{NULL}};
277 
278  /* use when added */
279  msg_key_test.msg.head.id = id_repr;
280  msg_key_test.msg.head.type = WM_MSG_TYPE_RNA;
281  /* for lookup */
282  msg_key_test.msg.params = *msg_key_params;
283 
284  const char *none = "<none>";
286  3,
287  "rna(id='%s', %s.%s, info='%s')",
288  msg_key_params->ptr.owner_id ? ((ID *)msg_key_params->ptr.owner_id)->name : none,
289  msg_key_params->ptr.type ? RNA_struct_identifier(msg_key_params->ptr.type) : none,
290  msg_key_params->prop ? RNA_property_identifier((PropertyRNA *)msg_key_params->prop) :
291  none,
292  id_repr);
293 
295  mbus, &msg_key_test.head, msg_val_params);
296 
297  if (msg_val_params->is_persistent) {
298  if (msg_key->msg.params.data_path == NULL) {
299  if (msg_key->msg.params.ptr.data != msg_key->msg.params.ptr.owner_id) {
300  /* We assume prop type can't change. */
302  }
303  }
304  }
305 }
306 
307 void WM_msg_subscribe_rna(struct wmMsgBus *mbus,
308  PointerRNA *ptr,
309  const PropertyRNA *prop,
310  const wmMsgSubscribeValue *msg_val_params,
311  const char *id_repr)
312 {
314  &(const wmMsgParams_RNA){
315  .ptr = *ptr,
316  .prop = prop,
317  },
318  msg_val_params,
319  id_repr);
320 }
321 
324 /* -------------------------------------------------------------------------- */
330 void WM_msg_subscribe_ID(struct wmMsgBus *mbus,
331  ID *id,
332  const wmMsgSubscribeValue *msg_val_params,
333  const char *id_repr)
334 {
335  wmMsgParams_RNA msg_key_params = {{NULL}};
336  RNA_id_pointer_create(id, &msg_key_params.ptr);
337  WM_msg_subscribe_rna_params(mbus, &msg_key_params, msg_val_params, id_repr);
338 }
339 
340 void WM_msg_publish_ID(struct wmMsgBus *mbus, ID *id)
341 {
342  wmMsgParams_RNA msg_key_params = {{NULL}};
343  RNA_id_pointer_create(id, &msg_key_params.ptr);
344  WM_msg_publish_rna_params(mbus, &msg_key_params);
345 }
346 
#define BLI_assert(a)
Definition: BLI_assert.h:46
#define BLI_INLINE
struct GSet GSet
Definition: BLI_ghash.h:340
bool BLI_gset_haskey(const GSet *gs, const void *key) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:1007
BLI_INLINE bool BLI_gsetIterator_done(const GSetIterator *gsi)
Definition: BLI_ghash.h:466
void * BLI_gset_lookup(const GSet *gs, const void *key) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:1061
BLI_INLINE void BLI_gsetIterator_init(GSetIterator *gsi, GSet *gs)
Definition: BLI_ghash.h:450
BLI_INLINE void BLI_gsetIterator_step(GSetIterator *gsi)
Definition: BLI_ghash.h:462
BLI_INLINE void * BLI_gsetIterator_getKey(GSetIterator *gsi)
Definition: BLI_ghash.h:458
bool BLI_gset_add(GSet *gs, void *key)
Definition: BLI_ghash.c:969
bool BLI_gset_remove(GSet *gs, const void *key, GSetKeyFreeFP keyfreefp)
Definition: BLI_ghash.c:1002
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
Definition: BLI_listbase.h:269
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:100
int BLI_listbase_count(const struct ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
unsigned int uint
Definition: BLI_sys_types.h:67
#define CLOG_INFO(clg_ref, level,...)
Definition: CLG_log.h:187
ID and Library types, which are fundamental for sdna.
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint y
Read Guarded memory(de)allocation.
struct CLG_LogRef * WM_LOG_MSGBUS_SUB
struct CLG_LogRef * WM_LOG_MSGBUS_PUB
__forceinline bool none(const avxb &b)
Definition: avxb.h:209
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
bool remove(void *owner, const AttributeIDRef &attribute_id)
const char * RNA_struct_identifier(const StructRNA *type)
Definition: rna_access.c:586
void RNA_id_pointer_create(ID *id, PointerRNA *r_ptr)
Definition: rna_access.c:112
const char * RNA_property_identifier(const PropertyRNA *prop)
Definition: rna_access.c:1000
char * RNA_path_from_ID_to_struct(const PointerRNA *ptr)
Definition: rna_path.cc:981
bool RNA_path_resolve(const PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop)
Definition: rna_path.cc:503
Definition: DNA_ID.h:368
char name[66]
Definition: DNA_ID.h:378
void * first
Definition: DNA_listBase.h:31
struct StructRNA * type
Definition: RNA_types.h:37
void * data
Definition: RNA_types.h:38
struct ID * owner_id
Definition: RNA_types.h:36
struct GSet * messages_gset[WM_MSG_TYPE_NUM]
const PropertyRNA * prop
wmMsgSubscribeKey head
void(* remove_by_id)(struct wmMsgBus *mbus, const struct ID *id)
void(* update_by_id)(struct wmMsgBus *mbus, struct ID *id_src, struct ID *id_dst)
void(* repr)(FILE *stream, const struct wmMsgSubscribeKey *msg_key)
struct wmMsgTypeInfo::@1202 gset
unsigned int(* hash_fn)(const void *msg)
void(* key_free_fn)(void *key)
bool(* cmp_fn)(const void *a, const void *b)
wmMsgParams_RNA params
unsigned int type
const char * id
PointerRNA * ptr
Definition: wm_files.c:3480
void WM_msg_publish_with_key(struct wmMsgBus *mbus, wmMsgSubscribeKey *msg_key)
wmMsgSubscribeKey * WM_msg_subscribe_with_key(struct wmMsgBus *mbus, const wmMsgSubscribeKey *msg_key_test, const wmMsgSubscribeValue *msg_val_params)
void wm_msg_subscribe_value_free(wmMsgSubscribeKey *msg_key, wmMsgSubscribeValueLink *msg_lnk)
struct wmMsgSubscribeKey_RNA wmMsgSubscribeKey_RNA
@ WM_MSG_TYPE_RNA
void WM_msg_subscribe_rna_params(struct wmMsgBus *mbus, const wmMsgParams_RNA *msg_key_params, const wmMsgSubscribeValue *msg_val_params, const char *id_repr)
void WM_msg_publish_rna_params(struct wmMsgBus *mbus, const wmMsgParams_RNA *msg_key_params)
BLI_INLINE uint void_hash_uint(const void *key)
wmMsgSubscribeKey_RNA * WM_msg_lookup_rna(struct wmMsgBus *mbus, const wmMsgParams_RNA *msg_key_params)
void WM_msgtypeinfo_init_rna(wmMsgTypeInfo *msgtype_info)
static void wm_msg_rna_remove_by_id(struct wmMsgBus *mbus, const ID *id)
static void wm_msg_rna_repr(FILE *stream, const wmMsgSubscribeKey *msg_key)
static bool wm_msg_rna_gset_cmp(const void *key_a_p, const void *key_b_p)
void WM_msg_publish_rna(struct wmMsgBus *mbus, PointerRNA *ptr, PropertyRNA *prop)
void WM_msg_publish_ID(struct wmMsgBus *mbus, ID *id)
static void wm_msg_rna_update_by_id(struct wmMsgBus *mbus, ID *id_src, ID *id_dst)
static void wm_msg_rna_gset_key_free(void *key_p)
static uint wm_msg_rna_gset_hash(const void *key_p)
void WM_msg_subscribe_rna(struct wmMsgBus *mbus, PointerRNA *ptr, const PropertyRNA *prop, const wmMsgSubscribeValue *msg_val_params, const char *id_repr)
void WM_msg_subscribe_ID(struct wmMsgBus *mbus, ID *id, const wmMsgSubscribeValue *msg_val_params, const char *id_repr)