Note this only changes cases where the variable was declared inside the for loop. To handle it outside as well is a different challenge. Differential Revision: https://developer.blender.org/D7320
255 lines
7.4 KiB
C
255 lines
7.4 KiB
C
/*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software Foundation,
|
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
/** \file
|
|
* \ingroup wm
|
|
*/
|
|
|
|
#include <string.h>
|
|
|
|
#include "CLG_log.h"
|
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
#include "BLI_listbase.h"
|
|
#include "BLI_utildefines.h"
|
|
|
|
#include "BLI_ghash.h"
|
|
|
|
#include "WM_types.h"
|
|
|
|
#include "message_bus/intern/wm_message_bus_intern.h"
|
|
#include "message_bus/wm_message_bus.h"
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/** \name Public API
|
|
* \{ */
|
|
|
|
static wmMsgTypeInfo wm_msg_types[WM_MSG_TYPE_NUM] = {{{NULL}}};
|
|
|
|
typedef void (*wmMsgTypeInitFn)(wmMsgTypeInfo *);
|
|
|
|
static wmMsgTypeInitFn wm_msg_init_fn[WM_MSG_TYPE_NUM] = {
|
|
WM_msgtypeinfo_init_rna,
|
|
WM_msgtypeinfo_init_static,
|
|
};
|
|
|
|
void WM_msgbus_types_init(void)
|
|
{
|
|
for (uint i = 0; i < WM_MSG_TYPE_NUM; i++) {
|
|
wm_msg_init_fn[i](&wm_msg_types[i]);
|
|
}
|
|
}
|
|
|
|
struct wmMsgBus *WM_msgbus_create(void)
|
|
{
|
|
struct wmMsgBus *mbus = MEM_callocN(sizeof(*mbus), __func__);
|
|
const uint gset_reserve = 512;
|
|
for (uint i = 0; i < WM_MSG_TYPE_NUM; i++) {
|
|
wmMsgTypeInfo *info = &wm_msg_types[i];
|
|
mbus->messages_gset[i] = BLI_gset_new_ex(
|
|
info->gset.hash_fn, info->gset.cmp_fn, __func__, gset_reserve);
|
|
}
|
|
return mbus;
|
|
}
|
|
|
|
void WM_msgbus_destroy(struct wmMsgBus *mbus)
|
|
{
|
|
for (uint i = 0; i < WM_MSG_TYPE_NUM; i++) {
|
|
wmMsgTypeInfo *info = &wm_msg_types[i];
|
|
BLI_gset_free(mbus->messages_gset[i], info->gset.key_free_fn);
|
|
}
|
|
MEM_freeN(mbus);
|
|
}
|
|
|
|
void WM_msgbus_clear_by_owner(struct wmMsgBus *mbus, void *owner)
|
|
{
|
|
wmMsgSubscribeKey *msg_key, *msg_key_next;
|
|
for (msg_key = mbus->messages.first; msg_key; msg_key = msg_key_next) {
|
|
msg_key_next = msg_key->next;
|
|
|
|
wmMsgSubscribeValueLink *msg_lnk_next;
|
|
for (wmMsgSubscribeValueLink *msg_lnk = msg_key->values.first; msg_lnk;
|
|
msg_lnk = msg_lnk_next) {
|
|
msg_lnk_next = msg_lnk->next;
|
|
if (msg_lnk->params.owner == owner) {
|
|
if (msg_lnk->params.tag) {
|
|
mbus->messages_tag_count -= 1;
|
|
}
|
|
if (msg_lnk->params.free_data) {
|
|
msg_lnk->params.free_data(msg_key, &msg_lnk->params);
|
|
}
|
|
BLI_remlink(&msg_key->values, msg_lnk);
|
|
MEM_freeN(msg_lnk);
|
|
}
|
|
}
|
|
|
|
if (BLI_listbase_is_empty(&msg_key->values)) {
|
|
const wmMsg *msg = wm_msg_subscribe_value_msg_cast(msg_key);
|
|
wmMsgTypeInfo *info = &wm_msg_types[msg->type];
|
|
BLI_remlink(&mbus->messages, msg_key);
|
|
bool ok = BLI_gset_remove(mbus->messages_gset[msg->type], msg_key, info->gset.key_free_fn);
|
|
BLI_assert(ok);
|
|
UNUSED_VARS_NDEBUG(ok);
|
|
}
|
|
}
|
|
}
|
|
|
|
void WM_msg_dump(struct wmMsgBus *mbus, const char *info_str)
|
|
{
|
|
printf(">>>> %s\n", info_str);
|
|
LISTBASE_FOREACH (wmMsgSubscribeKey *, key, &mbus->messages) {
|
|
const wmMsg *msg = wm_msg_subscribe_value_msg_cast(key);
|
|
const wmMsgTypeInfo *info = &wm_msg_types[msg->type];
|
|
info->repr(stdout, key);
|
|
}
|
|
printf("<<<< %s\n", info_str);
|
|
}
|
|
|
|
void WM_msgbus_handle(struct wmMsgBus *mbus, struct bContext *C)
|
|
{
|
|
if (mbus->messages_tag_count == 0) {
|
|
// printf("msgbus: skipping\n");
|
|
return;
|
|
}
|
|
|
|
if (false) {
|
|
WM_msg_dump(mbus, __func__);
|
|
}
|
|
|
|
// uint a = 0, b = 0;
|
|
LISTBASE_FOREACH (wmMsgSubscribeKey *, key, &mbus->messages) {
|
|
LISTBASE_FOREACH (wmMsgSubscribeValueLink *, msg_lnk, &key->values) {
|
|
if (msg_lnk->params.tag) {
|
|
msg_lnk->params.notify(C, key, &msg_lnk->params);
|
|
msg_lnk->params.tag = false;
|
|
mbus->messages_tag_count -= 1;
|
|
}
|
|
// b++;
|
|
}
|
|
// a++;
|
|
}
|
|
BLI_assert(mbus->messages_tag_count == 0);
|
|
mbus->messages_tag_count = 0;
|
|
// printf("msgbus: keys=%u values=%u\n", a, b);
|
|
}
|
|
|
|
/**
|
|
* \param msg_key_test: Needs following #wmMsgSubscribeKey fields filled in:
|
|
* - msg.params
|
|
* - msg.head.type
|
|
* - msg.head.id
|
|
* .. other values should be zeroed.
|
|
*
|
|
* \return The key for this subscription.
|
|
* note that this is only needed in rare cases when the key needs further manipulation.
|
|
*/
|
|
wmMsgSubscribeKey *WM_msg_subscribe_with_key(struct wmMsgBus *mbus,
|
|
const wmMsgSubscribeKey *msg_key_test,
|
|
const wmMsgSubscribeValue *msg_val_params)
|
|
{
|
|
const uint type = wm_msg_subscribe_value_msg_cast(msg_key_test)->type;
|
|
const wmMsgTypeInfo *info = &wm_msg_types[type];
|
|
wmMsgSubscribeKey *key;
|
|
|
|
BLI_assert(wm_msg_subscribe_value_msg_cast(msg_key_test)->id != NULL);
|
|
|
|
void **r_key;
|
|
if (!BLI_gset_ensure_p_ex(mbus->messages_gset[type], msg_key_test, &r_key)) {
|
|
key = *r_key = MEM_mallocN(info->msg_key_size, __func__);
|
|
memcpy(key, msg_key_test, info->msg_key_size);
|
|
BLI_addtail(&mbus->messages, key);
|
|
}
|
|
else {
|
|
key = *r_key;
|
|
LISTBASE_FOREACH (wmMsgSubscribeValueLink *, msg_lnk, &key->values) {
|
|
if ((msg_lnk->params.notify == msg_val_params->notify) &&
|
|
(msg_lnk->params.owner == msg_val_params->owner) &&
|
|
(msg_lnk->params.user_data == msg_val_params->user_data)) {
|
|
return key;
|
|
}
|
|
}
|
|
}
|
|
|
|
wmMsgSubscribeValueLink *msg_lnk = MEM_mallocN(sizeof(wmMsgSubscribeValueLink), __func__);
|
|
msg_lnk->params = *msg_val_params;
|
|
BLI_addtail(&key->values, msg_lnk);
|
|
return key;
|
|
}
|
|
|
|
void WM_msg_publish_with_key(struct wmMsgBus *mbus, wmMsgSubscribeKey *msg_key)
|
|
{
|
|
CLOG_INFO(WM_LOG_MSGBUS_SUB,
|
|
2,
|
|
"tagging subscribers: (ptr=%p, len=%d)",
|
|
msg_key,
|
|
BLI_listbase_count(&msg_key->values));
|
|
|
|
LISTBASE_FOREACH (wmMsgSubscribeValueLink *, msg_lnk, &msg_key->values) {
|
|
if (false) { /* make an option? */
|
|
msg_lnk->params.notify(NULL, msg_key, &msg_lnk->params);
|
|
}
|
|
else {
|
|
if (msg_lnk->params.tag == false) {
|
|
msg_lnk->params.tag = true;
|
|
mbus->messages_tag_count += 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void WM_msg_id_update(struct wmMsgBus *mbus, struct ID *id_src, struct ID *id_dst)
|
|
{
|
|
for (uint i = 0; i < WM_MSG_TYPE_NUM; i++) {
|
|
wmMsgTypeInfo *info = &wm_msg_types[i];
|
|
if (info->update_by_id != NULL) {
|
|
info->update_by_id(mbus, id_src, id_dst);
|
|
}
|
|
}
|
|
}
|
|
|
|
void WM_msg_id_remove(struct wmMsgBus *mbus, const struct ID *id)
|
|
{
|
|
for (uint i = 0; i < WM_MSG_TYPE_NUM; i++) {
|
|
wmMsgTypeInfo *info = &wm_msg_types[i];
|
|
if (info->remove_by_id != NULL) {
|
|
info->remove_by_id(mbus, id);
|
|
}
|
|
}
|
|
}
|
|
|
|
/** \} */
|
|
|
|
/* -------------------------------------------------------------------------- */
|
|
/** \name Internal API
|
|
*
|
|
* \note While we could have a separate type for ID's, use RNA since there is enough overlap.
|
|
* \{ */
|
|
|
|
/**
|
|
* \note #wmMsgBus.messages_tag_count isn't updated, caller must handle.
|
|
*/
|
|
void wm_msg_subscribe_value_free(wmMsgSubscribeKey *msg_key, wmMsgSubscribeValueLink *msg_lnk)
|
|
{
|
|
if (msg_lnk->params.free_data) {
|
|
msg_lnk->params.free_data(msg_key, &msg_lnk->params);
|
|
}
|
|
BLI_remlink(&msg_key->values, msg_lnk);
|
|
MEM_freeN(msg_lnk);
|
|
}
|
|
|
|
/** \} */
|