Blender  V2.93
wm_message_bus.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  */
16 
21 #include <string.h>
22 
23 #include "CLG_log.h"
24 
25 #include "MEM_guardedalloc.h"
26 
27 #include "BLI_listbase.h"
28 #include "BLI_utildefines.h"
29 
30 #include "BLI_ghash.h"
31 
32 #include "WM_types.h"
33 
36 
37 /* -------------------------------------------------------------------------- */
42 
43 typedef void (*wmMsgTypeInitFn)(wmMsgTypeInfo *);
44 
48 };
49 
51 {
52  for (uint i = 0; i < WM_MSG_TYPE_NUM; i++) {
54  }
55 }
56 
58 {
59  struct wmMsgBus *mbus = MEM_callocN(sizeof(*mbus), __func__);
60  const uint gset_reserve = 512;
61  for (uint i = 0; i < WM_MSG_TYPE_NUM; i++) {
62  wmMsgTypeInfo *info = &wm_msg_types[i];
63  mbus->messages_gset[i] = BLI_gset_new_ex(
64  info->gset.hash_fn, info->gset.cmp_fn, __func__, gset_reserve);
65  }
66  return mbus;
67 }
68 
69 void WM_msgbus_destroy(struct wmMsgBus *mbus)
70 {
71  for (uint i = 0; i < WM_MSG_TYPE_NUM; i++) {
72  wmMsgTypeInfo *info = &wm_msg_types[i];
74  }
75  MEM_freeN(mbus);
76 }
77 
78 void WM_msgbus_clear_by_owner(struct wmMsgBus *mbus, void *owner)
79 {
80  wmMsgSubscribeKey *msg_key, *msg_key_next;
81  for (msg_key = mbus->messages.first; msg_key; msg_key = msg_key_next) {
82  msg_key_next = msg_key->next;
83 
84  wmMsgSubscribeValueLink *msg_lnk_next;
85  for (wmMsgSubscribeValueLink *msg_lnk = msg_key->values.first; msg_lnk;
86  msg_lnk = msg_lnk_next) {
87  msg_lnk_next = msg_lnk->next;
88  if (msg_lnk->params.owner == owner) {
89  if (msg_lnk->params.tag) {
90  mbus->messages_tag_count -= 1;
91  }
92  if (msg_lnk->params.free_data) {
93  msg_lnk->params.free_data(msg_key, &msg_lnk->params);
94  }
95  BLI_remlink(&msg_key->values, msg_lnk);
96  MEM_freeN(msg_lnk);
97  }
98  }
99 
100  if (BLI_listbase_is_empty(&msg_key->values)) {
101  const wmMsg *msg = wm_msg_subscribe_value_msg_cast(msg_key);
102  wmMsgTypeInfo *info = &wm_msg_types[msg->type];
103  BLI_remlink(&mbus->messages, msg_key);
104  bool ok = BLI_gset_remove(mbus->messages_gset[msg->type], msg_key, info->gset.key_free_fn);
105  BLI_assert(ok);
106  UNUSED_VARS_NDEBUG(ok);
107  }
108  }
109 }
110 
111 void WM_msg_dump(struct wmMsgBus *mbus, const char *info_str)
112 {
113  printf(">>>> %s\n", info_str);
114  LISTBASE_FOREACH (wmMsgSubscribeKey *, key, &mbus->messages) {
115  const wmMsg *msg = wm_msg_subscribe_value_msg_cast(key);
116  const wmMsgTypeInfo *info = &wm_msg_types[msg->type];
117  info->repr(stdout, key);
118  }
119  printf("<<<< %s\n", info_str);
120 }
121 
122 void WM_msgbus_handle(struct wmMsgBus *mbus, struct bContext *C)
123 {
124  if (mbus->messages_tag_count == 0) {
125  // printf("msgbus: skipping\n");
126  return;
127  }
128 
129  if (false) {
130  WM_msg_dump(mbus, __func__);
131  }
132 
133  // uint a = 0, b = 0;
134  LISTBASE_FOREACH (wmMsgSubscribeKey *, key, &mbus->messages) {
135  LISTBASE_FOREACH (wmMsgSubscribeValueLink *, msg_lnk, &key->values) {
136  if (msg_lnk->params.tag) {
137  msg_lnk->params.notify(C, key, &msg_lnk->params);
138  msg_lnk->params.tag = false;
139  mbus->messages_tag_count -= 1;
140  }
141  // b++;
142  }
143  // a++;
144  }
145  BLI_assert(mbus->messages_tag_count == 0);
146  mbus->messages_tag_count = 0;
147  // printf("msgbus: keys=%u values=%u\n", a, b);
148 }
149 
161  const wmMsgSubscribeKey *msg_key_test,
162  const wmMsgSubscribeValue *msg_val_params)
163 {
164  const uint type = wm_msg_subscribe_value_msg_cast(msg_key_test)->type;
165  const wmMsgTypeInfo *info = &wm_msg_types[type];
166  wmMsgSubscribeKey *key;
167 
168  BLI_assert(wm_msg_subscribe_value_msg_cast(msg_key_test)->id != NULL);
169 
170  void **r_key;
171  if (!BLI_gset_ensure_p_ex(mbus->messages_gset[type], msg_key_test, &r_key)) {
172  key = *r_key = MEM_mallocN(info->msg_key_size, __func__);
173  memcpy(key, msg_key_test, info->msg_key_size);
174  BLI_addtail(&mbus->messages, key);
175  }
176  else {
177  key = *r_key;
178  LISTBASE_FOREACH (wmMsgSubscribeValueLink *, msg_lnk, &key->values) {
179  if ((msg_lnk->params.notify == msg_val_params->notify) &&
180  (msg_lnk->params.owner == msg_val_params->owner) &&
181  (msg_lnk->params.user_data == msg_val_params->user_data)) {
182  return key;
183  }
184  }
185  }
186 
187  wmMsgSubscribeValueLink *msg_lnk = MEM_mallocN(sizeof(wmMsgSubscribeValueLink), __func__);
188  msg_lnk->params = *msg_val_params;
189  BLI_addtail(&key->values, msg_lnk);
190  return key;
191 }
192 
194 {
196  2,
197  "tagging subscribers: (ptr=%p, len=%d)",
198  msg_key,
199  BLI_listbase_count(&msg_key->values));
200 
201  LISTBASE_FOREACH (wmMsgSubscribeValueLink *, msg_lnk, &msg_key->values) {
202  if (false) { /* make an option? */
203  msg_lnk->params.notify(NULL, msg_key, &msg_lnk->params);
204  }
205  else {
206  if (msg_lnk->params.tag == false) {
207  msg_lnk->params.tag = true;
208  mbus->messages_tag_count += 1;
209  }
210  }
211  }
212 }
213 
214 void WM_msg_id_update(struct wmMsgBus *mbus, struct ID *id_src, struct ID *id_dst)
215 {
216  for (uint i = 0; i < WM_MSG_TYPE_NUM; i++) {
217  wmMsgTypeInfo *info = &wm_msg_types[i];
218  if (info->update_by_id != NULL) {
219  info->update_by_id(mbus, id_src, id_dst);
220  }
221  }
222 }
223 
224 void WM_msg_id_remove(struct wmMsgBus *mbus, const struct ID *id)
225 {
226  for (uint i = 0; i < WM_MSG_TYPE_NUM; i++) {
227  wmMsgTypeInfo *info = &wm_msg_types[i];
228  if (info->remove_by_id != NULL) {
229  info->remove_by_id(mbus, id);
230  }
231  }
232 }
233 
236 /* -------------------------------------------------------------------------- */
246 {
247  if (msg_lnk->params.free_data) {
248  msg_lnk->params.free_data(msg_key, &msg_lnk->params);
249  }
250  BLI_remlink(&msg_key->values, msg_lnk);
251  MEM_freeN(msg_lnk);
252 }
253 
#define BLI_assert(a)
Definition: BLI_assert.h:58
bool BLI_gset_ensure_p_ex(GSet *gs, const void *key, void ***r_key)
Definition: BLI_ghash.c:1171
GSet * BLI_gset_new_ex(GSetHashFP hashfp, GSetCmpFP cmpfp, const char *info, const unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:1117
void BLI_gset_free(GSet *gs, GSetKeyFreeFP keyfreefp)
Definition: BLI_ghash.c:1253
bool BLI_gset_remove(GSet *gs, const void *key, GSetKeyFreeFP keyfreefp)
Definition: BLI_ghash.c:1211
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
Definition: BLI_listbase.h:124
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:172
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:110
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:133
int BLI_listbase_count(const struct ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
unsigned int uint
Definition: BLI_sys_types.h:83
#define UNUSED_VARS_NDEBUG(...)
#define CLOG_INFO(clg_ref, level,...)
Definition: CLG_log.h:201
_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 type
Read Guarded memory(de)allocation.
#define C
Definition: RandGen.cpp:39
struct CLG_LogRef * WM_LOG_MSGBUS_SUB
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:45
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:47
Definition: DNA_ID.h:273
void * first
Definition: DNA_listBase.h:47
struct GSet * messages_gset[WM_MSG_TYPE_NUM]
struct wmMsgSubscribeKey * next
wmMsgSubscribeValueFreeDataFn free_data
wmMsgNotifyFn notify
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)
unsigned int(* hash_fn)(const void *msg)
struct wmMsgTypeInfo::@1166 gset
void(* key_free_fn)(void *key)
bool(* cmp_fn)(const void *a, const void *b)
unsigned int type
void WM_msg_id_update(struct wmMsgBus *mbus, struct ID *id_src, struct ID *id_dst)
void WM_msgbus_clear_by_owner(struct wmMsgBus *mbus, void *owner)
static wmMsgTypeInitFn wm_msg_init_fn[WM_MSG_TYPE_NUM]
void WM_msgbus_destroy(struct wmMsgBus *mbus)
static wmMsgTypeInfo wm_msg_types[WM_MSG_TYPE_NUM]
void WM_msg_dump(struct wmMsgBus *mbus, const char *info_str)
void WM_msgbus_types_init(void)
void WM_msg_publish_with_key(struct wmMsgBus *mbus, wmMsgSubscribeKey *msg_key)
void WM_msg_id_remove(struct wmMsgBus *mbus, const struct ID *id)
wmMsgSubscribeKey * WM_msg_subscribe_with_key(struct wmMsgBus *mbus, const wmMsgSubscribeKey *msg_key_test, const wmMsgSubscribeValue *msg_val_params)
void WM_msgbus_handle(struct wmMsgBus *mbus, struct bContext *C)
void wm_msg_subscribe_value_free(wmMsgSubscribeKey *msg_key, wmMsgSubscribeValueLink *msg_lnk)
void(* wmMsgTypeInitFn)(wmMsgTypeInfo *)
struct wmMsgBus * WM_msgbus_create(void)
#define WM_MSG_TYPE_NUM
BLI_INLINE const wmMsg * wm_msg_subscribe_value_msg_cast(const wmMsgSubscribeKey *key)
void WM_msgtypeinfo_init_rna(wmMsgTypeInfo *msgtype_info)
void WM_msgtypeinfo_init_static(wmMsgTypeInfo *msgtype_info)