Blender V5.0
wm_message_bus.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include <cstring>
10
11#include "CLG_log.h"
12
13#include "MEM_guardedalloc.h"
14
15#include "BLI_listbase.h"
16#include "BLI_utildefines.h"
17
18#include "BLI_ghash.h"
19
20#include "WM_types.hh"
21
24
25/* -------------------------------------------------------------------------- */
28
30
31using wmMsgTypeInitFn = void (*)(wmMsgTypeInfo *);
32
38
40{
41 for (uint i = 0; i < WM_MSG_TYPE_NUM; i++) {
43 }
44}
45
47{
48 wmMsgBus *mbus = MEM_callocN<wmMsgBus>(__func__);
49 const uint gset_reserve = 512;
50 for (uint i = 0; i < WM_MSG_TYPE_NUM; i++) {
53 info->gset.hash_fn, info->gset.cmp_fn, __func__, gset_reserve);
54 }
55 return mbus;
56}
57
59{
60 for (uint i = 0; i < WM_MSG_TYPE_NUM; i++) {
63 }
64 MEM_freeN(mbus);
65}
66
67void WM_msgbus_clear_by_owner(wmMsgBus *mbus, void *owner)
68{
69 wmMsgSubscribeKey *msg_key, *msg_key_next;
70 for (msg_key = static_cast<wmMsgSubscribeKey *>(mbus->messages.first); msg_key;
71 msg_key = msg_key_next)
72 {
73 msg_key_next = msg_key->next;
74
75 wmMsgSubscribeValueLink *msg_lnk_next;
76 for (wmMsgSubscribeValueLink *msg_lnk =
77 static_cast<wmMsgSubscribeValueLink *>(msg_key->values.first);
78 msg_lnk;
79 msg_lnk = msg_lnk_next)
80 {
81 msg_lnk_next = msg_lnk->next;
82 if (msg_lnk->params.owner == owner) {
83 if (msg_lnk->params.tag) {
84 mbus->messages_tag_count -= 1;
85 }
86 if (msg_lnk->params.free_data) {
87 msg_lnk->params.free_data(msg_key, &msg_lnk->params);
88 }
89 BLI_remlink(&msg_key->values, msg_lnk);
90 MEM_freeN(msg_lnk);
91 }
92 }
93
94 if (BLI_listbase_is_empty(&msg_key->values)) {
95 const wmMsg *msg = wm_msg_subscribe_value_msg_cast(msg_key);
96 wmMsgTypeInfo *info = &wm_msg_types[msg->type];
97 BLI_remlink(&mbus->messages, msg_key);
98 bool ok = BLI_gset_remove(mbus->messages_gset[msg->type], msg_key, info->gset.key_free_fn);
99 BLI_assert(ok);
101 }
102 }
103}
104
105void WM_msg_dump(wmMsgBus *mbus, const char *info_str)
106{
107 printf(">>>> %s\n", info_str);
109 const wmMsg *msg = wm_msg_subscribe_value_msg_cast(key);
110 const wmMsgTypeInfo *info = &wm_msg_types[msg->type];
111 info->repr(stdout, key);
112 }
113 printf("<<<< %s\n", info_str);
114}
115
117{
118 if (mbus->messages_tag_count == 0) {
119 // printf("msgbus: skipping\n");
120 return;
121 }
122
123 if (false) {
124 WM_msg_dump(mbus, __func__);
125 }
126
127 // uint a = 0, b = 0;
129 LISTBASE_FOREACH (wmMsgSubscribeValueLink *, msg_lnk, &key->values) {
130 if (msg_lnk->params.tag) {
131 msg_lnk->params.notify(C, key, &msg_lnk->params);
132 msg_lnk->params.tag = false;
133 mbus->messages_tag_count -= 1;
134 }
135 // b++;
136 }
137 // a++;
138 }
139 BLI_assert(mbus->messages_tag_count == 0);
140 mbus->messages_tag_count = 0;
141 // printf("msgbus: keys=%u values=%u\n", a, b);
142}
143
145 const wmMsgSubscribeKey *msg_key_test,
146 const wmMsgSubscribeValue *msg_val_params)
147{
148 const uint type = wm_msg_subscribe_value_msg_cast(msg_key_test)->type;
149 const wmMsgTypeInfo *info = &wm_msg_types[type];
151
152 BLI_assert(wm_msg_subscribe_value_msg_cast(msg_key_test)->id != nullptr);
153
154 void **r_key;
155 if (!BLI_gset_ensure_p_ex(mbus->messages_gset[type], msg_key_test, &r_key)) {
156 *r_key = info->gset.key_duplicate_fn(msg_key_test);
157 key = static_cast<wmMsgSubscribeKey *>(*r_key);
158 BLI_addtail(&mbus->messages, key);
159 }
160 else {
161 key = static_cast<wmMsgSubscribeKey *>(*r_key);
163 if ((msg_lnk->params.notify == msg_val_params->notify) &&
164 (msg_lnk->params.owner == msg_val_params->owner) &&
165 (msg_lnk->params.user_data == msg_val_params->user_data))
166 {
167 return key;
168 }
169 }
170 }
171
173 msg_lnk->params = *msg_val_params;
174 BLI_addtail(&key->values, msg_lnk);
175 return key;
176}
177
179{
181 "tagging subscribers: (ptr=%p, len=%d)",
182 msg_key,
183 BLI_listbase_count(&msg_key->values));
184
185 LISTBASE_FOREACH (wmMsgSubscribeValueLink *, msg_lnk, &msg_key->values) {
186 if (false) { /* Make an option? */
187 msg_lnk->params.notify(nullptr, msg_key, &msg_lnk->params);
188 }
189 else {
190 if (msg_lnk->params.tag == false) {
191 msg_lnk->params.tag = true;
192 mbus->messages_tag_count += 1;
193 }
194 }
195 }
196}
197
198void WM_msg_id_update(wmMsgBus *mbus, ID *id_src, ID *id_dst)
199{
200 for (uint i = 0; i < WM_MSG_TYPE_NUM; i++) {
201 wmMsgTypeInfo *info = &wm_msg_types[i];
202 if (info->update_by_id != nullptr) {
203 info->update_by_id(mbus, id_src, id_dst);
204 }
205 }
206}
207
208void WM_msg_id_remove(wmMsgBus *mbus, const ID *id)
209{
210 for (uint i = 0; i < WM_MSG_TYPE_NUM; i++) {
211 wmMsgTypeInfo *info = &wm_msg_types[i];
212 if (info->remove_by_id != nullptr) {
213 info->remove_by_id(mbus, id);
214 }
215 }
216}
217
219
220/* -------------------------------------------------------------------------- */
225
227{
228 if (msg_lnk->params.free_data) {
229 msg_lnk->params.free_data(msg_key, &msg_lnk->params);
230 }
231 BLI_remlink(&msg_key->values, msg_lnk);
232 MEM_freeN(msg_lnk);
233}
234
#define BLI_assert(a)
Definition BLI_assert.h:46
bool BLI_gset_ensure_p_ex(GSet *gs, const void *key, void ***r_key)
Definition BLI_ghash.cc:971
GSet * BLI_gset_new_ex(GSetHashFP hashfp, GSetCmpFP cmpfp, const char *info, unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.cc:936
void BLI_gset_free(GSet *gs, GSetKeyFreeFP keyfreefp)
bool BLI_gset_remove(GSet *gs, const void *key, GSetKeyFreeFP keyfreefp)
Definition BLI_ghash.cc:999
#define LISTBASE_FOREACH(type, var, list)
BLI_INLINE bool BLI_listbase_is_empty(const ListBase *lb)
void BLI_addtail(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:111
void BLI_remlink(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:131
int BLI_listbase_count(const ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:524
unsigned int uint
#define UNUSED_VARS_NDEBUG(...)
#define CLOG_DEBUG(clg_ref,...)
Definition CLG_log.h:191
Read Guarded memory(de)allocation.
#define C
Definition RandGen.cpp:29
CLG_LogRef * WM_LOG_MSGBUS_SUB
#define printf(...)
void * MEM_mallocN(size_t len, const char *str)
Definition mallocn.cc:128
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
Definition DNA_ID.h:414
void * first
GSet * messages_gset[WM_MSG_TYPE_NUM]
wmMsgSubscribeKey * next
wmMsgSubscribeValueFreeDataFn free_data
void(* remove_by_id)(wmMsgBus *mbus, const ID *id)
void(* update_by_id)(wmMsgBus *mbus, ID *id_src, ID *id_dst)
struct wmMsgTypeInfo::@062176151244273150215163026361115361006314120344 gset
void *(* key_duplicate_fn)(const void *key)
void(* repr)(FILE *stream, const wmMsgSubscribeKey *msg_key)
unsigned int(* hash_fn)(const void *msg)
void(* key_free_fn)(void *key)
bool(* cmp_fn)(const void *a, const void *b)
unsigned int type
i
Definition text_draw.cc:230
void WM_msgbus_destroy(wmMsgBus *mbus)
void(*)(wmMsgTypeInfo *) wmMsgTypeInitFn
static wmMsgTypeInitFn wm_msg_init_fn[WM_MSG_TYPE_NUM]
static wmMsgTypeInfo wm_msg_types[WM_MSG_TYPE_NUM]
void WM_msg_publish_with_key(wmMsgBus *mbus, wmMsgSubscribeKey *msg_key)
void WM_msg_id_update(wmMsgBus *mbus, ID *id_src, ID *id_dst)
void WM_msgbus_handle(wmMsgBus *mbus, bContext *C)
void WM_msg_id_remove(wmMsgBus *mbus, const ID *id)
void wm_msg_subscribe_value_free(wmMsgSubscribeKey *msg_key, wmMsgSubscribeValueLink *msg_lnk)
wmMsgBus * WM_msgbus_create()
void WM_msgbus_clear_by_owner(wmMsgBus *mbus, void *owner)
wmMsgSubscribeKey * WM_msg_subscribe_with_key(wmMsgBus *mbus, const wmMsgSubscribeKey *msg_key_test, const wmMsgSubscribeValue *msg_val_params)
void WM_msgbus_types_init()
void WM_msg_dump(wmMsgBus *mbus, const char *info_str)
#define WM_MSG_TYPE_NUM
BLI_INLINE const wmMsg * wm_msg_subscribe_value_msg_cast(const wmMsgSubscribeKey *key)
void WM_msgtypeinfo_init_remote_io(wmMsgTypeInfo *msgtype_info)
void WM_msgtypeinfo_init_rna(wmMsgTypeInfo *msgtype_info)
void WM_msgtypeinfo_init_static(wmMsgTypeInfo *msgtype_info)