Add Chromium-only Blender WebEngine parity work

This commit is contained in:
mes123456
2026-08-12 04:47:48 -04:00
commit 9fd26010f6
18225 changed files with 11622124 additions and 0 deletions

View File

@@ -0,0 +1,239 @@
/* SPDX-FileCopyrightText: 2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup wm
*/
#include <cstring>
#include "CLG_log.h"
#include "MEM_guardedalloc.h"
#include "BLI_listbase.h"
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
#include "WM_types.hh"
#include "message_bus/intern/wm_message_bus_intern.hh"
#include "message_bus/wm_message_bus.hh"
namespace blender {
/* -------------------------------------------------------------------------- */
/** \name Public API
* \{ */
static wmMsgTypeInfo wm_msg_types[WM_MSG_TYPE_NUM] = {{{nullptr}}};
using wmMsgTypeInitFn = void (*)(wmMsgTypeInfo *);
static wmMsgTypeInitFn wm_msg_init_fn[WM_MSG_TYPE_NUM] = {
WM_msgtypeinfo_init_rna,
WM_msgtypeinfo_init_static,
WM_msgtypeinfo_init_remote_io,
};
void WM_msgbus_types_init()
{
for (uint i = 0; i < WM_MSG_TYPE_NUM; i++) {
wm_msg_init_fn[i](&wm_msg_types[i]);
}
}
wmMsgBus *WM_msgbus_create()
{
wmMsgBus *mbus = MEM_new_zeroed<wmMsgBus>(__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(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_delete(mbus);
}
void WM_msgbus_clear_by_owner(wmMsgBus *mbus, void *owner)
{
wmMsgSubscribeKey *msg_key, *msg_key_next;
for (msg_key = static_cast<wmMsgSubscribeKey *>(mbus->messages.first); msg_key;
msg_key = msg_key_next)
{
msg_key_next = msg_key->next;
wmMsgSubscribeValueLink *msg_lnk_next;
for (wmMsgSubscribeValueLink *msg_lnk =
static_cast<wmMsgSubscribeValueLink *>(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_delete(msg_lnk);
}
}
if (msg_key->values.is_empty()) {
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(wmMsgBus *mbus, const char *info_str)
{
printf(">>>> %s\n", info_str);
for (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(wmMsgBus *mbus, 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;
for (wmMsgSubscribeKey &key : mbus->messages) {
for (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);
}
wmMsgSubscribeKey *WM_msg_subscribe_with_key(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 != nullptr);
void **r_key;
if (!BLI_gset_ensure_p_ex(mbus->messages_gset[type], msg_key_test, &r_key)) {
*r_key = info->gset.key_duplicate_fn(msg_key_test);
key = static_cast<wmMsgSubscribeKey *>(*r_key);
BLI_addtail(&mbus->messages, key);
}
else {
key = static_cast<wmMsgSubscribeKey *>(*r_key);
for (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_new_uninitialized<wmMsgSubscribeValueLink>(__func__);
msg_lnk->params = *msg_val_params;
BLI_addtail(&key->values, msg_lnk);
return key;
}
void WM_msg_publish_with_key(wmMsgBus *mbus, wmMsgSubscribeKey *msg_key)
{
CLOG_DEBUG(WM_LOG_MSGBUS_SUB,
"tagging subscribers: (ptr=%p, len=%d)",
msg_key,
msg_key->values.count());
for (wmMsgSubscribeValueLink &msg_lnk : msg_key->values) {
if (false) { /* Make an option? */
msg_lnk.params.notify(nullptr, 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(wmMsgBus *mbus, ID *id_src, ID *id_dst)
{
for (uint i = 0; i < WM_MSG_TYPE_NUM; i++) {
wmMsgTypeInfo *info = &wm_msg_types[i];
if (info->update_by_id != nullptr) {
info->update_by_id(mbus, id_src, id_dst);
}
}
}
void WM_msg_id_remove(wmMsgBus *mbus, const ID *id)
{
for (uint i = 0; i < WM_MSG_TYPE_NUM; i++) {
wmMsgTypeInfo *info = &wm_msg_types[i];
if (info->remove_by_id != nullptr) {
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.
* \{ */
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_delete(msg_lnk);
}
/** \} */
} // namespace blender

View File

@@ -0,0 +1,45 @@
/* SPDX-FileCopyrightText: 2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup wm
*/
#pragma once
#include "../wm_message_bus.hh"
struct GSet;
namespace blender {
struct wmMsgBus {
GSet *messages_gset[WM_MSG_TYPE_NUM];
/** Messages in order of being added. */
ListBaseT<wmMsgSubscribeKey> messages;
/** Avoid checking messages when no tags exist. */
uint messages_tag_count;
};
/**
* \note #wmMsgBus.messages_tag_count isn't updated, caller must handle.
*/
void wm_msg_subscribe_value_free(wmMsgSubscribeKey *msg_key, wmMsgSubscribeValueLink *msg_lnk);
struct wmMsgSubscribeKey_Generic {
wmMsgSubscribeKey head;
wmMsg msg;
};
BLI_INLINE const wmMsg *wm_msg_subscribe_value_msg_cast(const wmMsgSubscribeKey *key)
{
return &(reinterpret_cast<wmMsgSubscribeKey_Generic *>(const_cast<wmMsgSubscribeKey *>(key)))
->msg;
}
BLI_INLINE wmMsg *wm_msg_subscribe_value_msg_cast_mut(wmMsgSubscribeKey *key)
{
return &(reinterpret_cast<wmMsgSubscribeKey_Generic *>(key))->msg;
}
} // namespace blender

View File

@@ -0,0 +1,149 @@
/* SPDX-FileCopyrightText: 2025 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup wm
*/
#include "CLG_log.h"
#include "MEM_guardedalloc.h"
#include "BLI_ghash.h"
#include "BLI_hash.h"
#include "BLI_listbase.h"
#include "BLI_string.h"
#include "BLI_string_ref.hh"
#include "WM_types.hh"
#include "message_bus/intern/wm_message_bus_intern.hh"
namespace blender {
/* -------------------------------------------------------------------------- */
static uint wm_msg_remote_io_gset_hash(const void *key_p)
{
const wmMsgSubscribeKey_RemoteIO *key = static_cast<const wmMsgSubscribeKey_RemoteIO *>(key_p);
const wmMsgParams_RemoteIO *params = &key->msg.params;
uint k = BLI_hash_string(params->remote_url);
return k;
}
static bool wm_msg_remote_io_gset_cmp(const void *key_a_p, const void *key_b_p)
{
const wmMsgParams_RemoteIO *params_a =
&(static_cast<const wmMsgSubscribeKey_RemoteIO *>(key_a_p))->msg.params;
const wmMsgParams_RemoteIO *params_b =
&(static_cast<const wmMsgSubscribeKey_RemoteIO *>(key_b_p))->msg.params;
return !STREQ(params_a->remote_url, params_b->remote_url);
}
static void *wm_msg_remote_io_gset_key_duplicate(const void *key_p)
{
const wmMsgSubscribeKey_RemoteIO *key_src = static_cast<const wmMsgSubscribeKey_RemoteIO *>(
key_p);
wmMsgSubscribeKey_RemoteIO *key = MEM_new<wmMsgSubscribeKey_RemoteIO>(__func__, *key_src);
key->msg.params.remote_url = BLI_strdup(key_src->msg.params.remote_url);
return key;
}
static void wm_msg_remote_io_gset_key_free(void *key_p)
{
wmMsgSubscribeKey_RemoteIO *key = static_cast<wmMsgSubscribeKey_RemoteIO *>(key_p);
MEM_delete(key->msg.params.remote_url);
wmMsgSubscribeValueLink *msg_lnk_next;
for (wmMsgSubscribeValueLink *msg_lnk =
static_cast<wmMsgSubscribeValueLink *>(key->head.values.first);
msg_lnk;
msg_lnk = msg_lnk_next)
{
msg_lnk_next = msg_lnk->next;
BLI_remlink(&key->head.values, msg_lnk);
MEM_delete(msg_lnk);
}
MEM_delete(key);
}
static void wm_msg_remote_io_repr(FILE *stream, const wmMsgSubscribeKey *msg_key)
{
const wmMsgSubscribeKey_RemoteIO *m = reinterpret_cast<wmMsgSubscribeKey_RemoteIO *>(
const_cast<wmMsgSubscribeKey *>(msg_key));
fprintf(stream,
"<wmMsg_RemoteIO %p, "
"id='%s', "
"values_len=%d\n",
m,
m->msg.head.id,
m->head.values.count());
}
void WM_msgtypeinfo_init_remote_io(wmMsgTypeInfo *msgtype_info)
{
msgtype_info->gset.hash_fn = wm_msg_remote_io_gset_hash;
msgtype_info->gset.cmp_fn = wm_msg_remote_io_gset_cmp;
msgtype_info->gset.key_duplicate_fn = wm_msg_remote_io_gset_key_duplicate;
msgtype_info->gset.key_free_fn = wm_msg_remote_io_gset_key_free;
msgtype_info->repr = wm_msg_remote_io_repr;
}
/* -------------------------------------------------------------------------- */
wmMsgSubscribeKey_RemoteIO *WM_msg_lookup_remote_io(wmMsgBus *mbus,
const wmMsgParams_RemoteIO *msg_key_params)
{
wmMsgSubscribeKey_RemoteIO key_test;
key_test.msg.params = *msg_key_params;
return static_cast<wmMsgSubscribeKey_RemoteIO *>(
BLI_gset_lookup(mbus->messages_gset[WM_MSG_TYPE_REMOTE_IO], &key_test));
}
void WM_msg_publish_remote_io_params(wmMsgBus *mbus, const wmMsgParams_RemoteIO *msg_key_params)
{
CLOG_DEBUG(WM_LOG_MSGBUS_PUB, "remote_io(remote_url=%s)", msg_key_params->remote_url);
wmMsgSubscribeKey_RemoteIO *key = WM_msg_lookup_remote_io(mbus, msg_key_params);
if (key) {
WM_msg_publish_with_key(mbus, &key->head);
}
}
void WM_msg_publish_remote_io(wmMsgBus *mbus, const StringRef remote_url)
{
wmMsgParams_RemoteIO params{};
params.remote_url = BLI_strdupn(remote_url.data(), remote_url.size());
WM_msg_publish_remote_io_params(mbus, &params);
/* Value was copied into the publish key. */
MEM_delete(params.remote_url);
}
void WM_msg_subscribe_remote_io_params(wmMsgBus *mbus,
const wmMsgParams_RemoteIO *msg_key_params,
const wmMsgSubscribeValue *msg_val_params,
const char *id_repr)
{
wmMsgSubscribeKey_RemoteIO msg_key_test{};
/* Use when added. */
msg_key_test.msg.head.id = id_repr;
msg_key_test.msg.head.type = WM_MSG_TYPE_REMOTE_IO;
/* For lookup. */
msg_key_test.msg.params = *msg_key_params;
WM_msg_subscribe_with_key(mbus, &msg_key_test.head, msg_val_params);
}
void WM_msg_subscribe_remote_io(wmMsgBus *mbus,
const StringRef remote_url,
const wmMsgSubscribeValue *msg_val_params,
const char *id_repr)
{
wmMsgParams_RemoteIO params{};
params.remote_url = BLI_strdupn(remote_url.data(), remote_url.size());
WM_msg_subscribe_remote_io_params(mbus, &params, msg_val_params, id_repr);
/* Value was copied into the subscribe key. */
MEM_delete(params.remote_url);
}
} // namespace blender

View File

@@ -0,0 +1,376 @@
/* SPDX-FileCopyrightText: 2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup wm
*/
#include <cstdio>
#include "CLG_log.h"
#include "MEM_guardedalloc.h"
#include "DNA_ID.h"
#include "BLI_ghash.h"
#include "BLI_listbase.h"
#include "BLI_string.h"
#include "WM_message.hh"
#include "WM_types.hh"
#include "message_bus/intern/wm_message_bus_intern.hh"
#include "RNA_access.hh"
#include "RNA_path.hh"
namespace blender {
/* -------------------------------------------------------------------- */
/** \name Internal Utilities
* \{ */
BLI_INLINE uint void_hash_uint(const void *key)
{
size_t y = size_t(key) >> sizeof(void *);
return uint(y);
}
static uint wm_msg_rna_gset_hash(const void *key_p)
{
const wmMsgSubscribeKey_RNA *key = static_cast<const wmMsgSubscribeKey_RNA *>(key_p);
const wmMsgParams_RNA *params = &key->msg.params;
// printf("%s\n", RNA_struct_identifier(params->ptr.type));
uint k = void_hash_uint(params->ptr.type);
k ^= void_hash_uint(params->ptr.data);
k ^= void_hash_uint(params->ptr.owner_id);
k ^= void_hash_uint(params->prop);
return k;
}
static bool wm_msg_rna_gset_cmp(const void *key_a_p, const void *key_b_p)
{
const wmMsgParams_RNA *params_a =
&(static_cast<const wmMsgSubscribeKey_RNA *>(key_a_p))->msg.params;
const wmMsgParams_RNA *params_b =
&(static_cast<const wmMsgSubscribeKey_RNA *>(key_b_p))->msg.params;
return !((params_a->ptr.type == params_b->ptr.type) &&
(params_a->ptr.owner_id == params_b->ptr.owner_id) &&
(params_a->ptr.data == params_b->ptr.data) && (params_a->prop == params_b->prop));
}
static void *wm_msg_rna_gset_key_duplicate(const void *key_p)
{
const wmMsgSubscribeKey_RNA *key_src = static_cast<const wmMsgSubscribeKey_RNA *>(key_p);
return MEM_new<wmMsgSubscribeKey_RNA>(__func__, *key_src);
}
static void wm_msg_rna_gset_key_free(void *key_p)
{
wmMsgSubscribeKey_RNA *key = static_cast<wmMsgSubscribeKey_RNA *>(key_p);
wmMsgSubscribeValueLink *msg_lnk_next;
for (wmMsgSubscribeValueLink *msg_lnk =
static_cast<wmMsgSubscribeValueLink *>(key->head.values.first);
msg_lnk;
msg_lnk = msg_lnk_next)
{
msg_lnk_next = msg_lnk->next;
wm_msg_subscribe_value_free(&key->head, msg_lnk);
}
if (key->msg.params.data_path != nullptr) {
MEM_delete(key->msg.params.data_path);
}
MEM_delete(key);
}
static void wm_msg_rna_repr(FILE *stream, const wmMsgSubscribeKey *msg_key)
{
const wmMsgSubscribeKey_RNA *m = reinterpret_cast<wmMsgSubscribeKey_RNA *>(
const_cast<wmMsgSubscribeKey *>(msg_key));
const char *none = "<none>";
fprintf(stream,
"<wmMsg_RNA %p, "
"id='%s', "
"%s.%s values_len=%d\n",
m,
m->msg.head.id,
m->msg.params.ptr.type ? RNA_struct_identifier(m->msg.params.ptr.type) : none,
m->msg.params.prop ?
RNA_property_identifier(const_cast<PropertyRNA *>(m->msg.params.prop)) :
none,
m->head.values.count());
}
static void wm_msg_rna_update_by_id(wmMsgBus *mbus, ID *id_src, ID *id_dst)
{
GSet *gs = mbus->messages_gset[WM_MSG_TYPE_RNA];
GSetIterator gs_iter;
BLI_gsetIterator_init(&gs_iter, gs);
while (BLI_gsetIterator_done(&gs_iter) == false) {
wmMsgSubscribeKey_RNA *key = static_cast<wmMsgSubscribeKey_RNA *>(
BLI_gsetIterator_getKey(&gs_iter));
BLI_gsetIterator_step(&gs_iter);
if (key->msg.params.ptr.owner_id == id_src) {
/* GSet always needs updating since the key changes. */
BLI_gset_remove(gs, key, nullptr);
/* Remove any non-persistent values, so a single persistent
* value doesn't modify behavior for the rest. */
for (wmMsgSubscribeValueLink *
msg_lnk = static_cast<wmMsgSubscribeValueLink *>(key->head.values.first),
*msg_lnk_next;
msg_lnk;
msg_lnk = msg_lnk_next)
{
msg_lnk_next = msg_lnk->next;
if (msg_lnk->params.is_persistent == false) {
if (msg_lnk->params.tag) {
mbus->messages_tag_count -= 1;
}
wm_msg_subscribe_value_free(&key->head, msg_lnk);
}
}
bool remove = true;
if (key->head.values.is_empty()) {
/* Remove, no reason to keep. */
}
else if (key->msg.params.ptr.data == key->msg.params.ptr.owner_id) {
/* Simple, just update the ID. */
key->msg.params.ptr.data = id_dst;
key->msg.params.ptr.owner_id = id_dst;
remove = false;
}
else {
/* We need to resolve this from the new ID pointer. */
PointerRNA idptr = RNA_id_pointer_create(id_dst);
PointerRNA ptr;
PropertyRNA *prop = nullptr;
if (RNA_path_resolve(&idptr, key->msg.params.data_path, &ptr, &prop) &&
(prop == nullptr) == (key->msg.params.prop == nullptr))
{
key->msg.params.ptr = ptr;
key->msg.params.prop = prop;
remove = false;
}
}
if (remove) {
for (wmMsgSubscribeValueLink *
msg_lnk = static_cast<wmMsgSubscribeValueLink *>(key->head.values.first),
*msg_lnk_next;
msg_lnk;
msg_lnk = msg_lnk_next)
{
msg_lnk_next = msg_lnk->next;
if (msg_lnk->params.is_persistent == false) {
if (msg_lnk->params.tag) {
mbus->messages_tag_count -= 1;
}
wm_msg_subscribe_value_free(&key->head, msg_lnk);
}
}
/* Failed to persist, remove the key. */
BLI_remlink(&mbus->messages, key);
wm_msg_rna_gset_key_free(key);
}
else {
/* Note that it's not impossible this key exists, however it is very unlikely
* since a subscriber would need to register in the middle of an undo for eg.
* so assert for now. */
BLI_assert(!BLI_gset_haskey(gs, key));
BLI_gset_add(gs, key);
}
}
}
}
static void wm_msg_rna_remove_by_id(wmMsgBus *mbus, const ID *id)
{
GSet *gs = mbus->messages_gset[WM_MSG_TYPE_RNA];
GSetIterator gs_iter;
BLI_gsetIterator_init(&gs_iter, gs);
while (BLI_gsetIterator_done(&gs_iter) == false) {
wmMsgSubscribeKey_RNA *key = static_cast<wmMsgSubscribeKey_RNA *>(
BLI_gsetIterator_getKey(&gs_iter));
BLI_gsetIterator_step(&gs_iter);
if (key->msg.params.ptr.owner_id == id) {
/* Clear here so we can decrement 'messages_tag_count'. */
for (wmMsgSubscribeValueLink *
msg_lnk = static_cast<wmMsgSubscribeValueLink *>(key->head.values.first),
*msg_lnk_next;
msg_lnk;
msg_lnk = msg_lnk_next)
{
msg_lnk_next = msg_lnk->next;
if (msg_lnk->params.tag) {
mbus->messages_tag_count -= 1;
}
wm_msg_subscribe_value_free(&key->head, msg_lnk);
}
BLI_remlink(&mbus->messages, key);
BLI_gset_remove(gs, key, nullptr);
wm_msg_rna_gset_key_free(key);
}
}
}
void WM_msgtypeinfo_init_rna(wmMsgTypeInfo *msgtype_info)
{
msgtype_info->gset.hash_fn = wm_msg_rna_gset_hash;
msgtype_info->gset.cmp_fn = wm_msg_rna_gset_cmp;
msgtype_info->gset.key_duplicate_fn = wm_msg_rna_gset_key_duplicate;
msgtype_info->gset.key_free_fn = wm_msg_rna_gset_key_free;
msgtype_info->repr = wm_msg_rna_repr;
msgtype_info->update_by_id = wm_msg_rna_update_by_id;
msgtype_info->remove_by_id = wm_msg_rna_remove_by_id;
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name RNA API
* \{ */
wmMsgSubscribeKey_RNA *WM_msg_lookup_rna(wmMsgBus *mbus, const wmMsgParams_RNA *msg_key_params)
{
wmMsgSubscribeKey_RNA key_test;
key_test.msg.params = *msg_key_params;
return static_cast<wmMsgSubscribeKey_RNA *>(
BLI_gset_lookup(mbus->messages_gset[WM_MSG_TYPE_RNA], &key_test));
}
void WM_msg_publish_rna_params(wmMsgBus *mbus, const wmMsgParams_RNA *msg_key_params)
{
wmMsgSubscribeKey_RNA *key;
const char *none = "<none>";
CLOG_DEBUG(WM_LOG_MSGBUS_PUB,
"rna(id='%s', %s.%s)",
msg_key_params->ptr.owner_id ? ((ID *)msg_key_params->ptr.owner_id)->name : none,
msg_key_params->ptr.type ? RNA_struct_identifier(msg_key_params->ptr.type) : none,
msg_key_params->prop ? RNA_property_identifier((PropertyRNA *)msg_key_params->prop) :
none);
if ((key = WM_msg_lookup_rna(mbus, msg_key_params))) {
WM_msg_publish_with_key(mbus, &key->head);
}
/* Support anonymous subscribers, this may be some extra overhead
* but we want to be able to be more ambiguous. */
if (msg_key_params->ptr.owner_id || msg_key_params->ptr.data) {
wmMsgParams_RNA msg_key_params_anon = *msg_key_params;
/* We might want to enable this later? */
if (msg_key_params_anon.prop != nullptr) {
/* All properties for this type. */
msg_key_params_anon.prop = nullptr;
if ((key = WM_msg_lookup_rna(mbus, &msg_key_params_anon))) {
WM_msg_publish_with_key(mbus, &key->head);
}
msg_key_params_anon.prop = msg_key_params->prop;
}
msg_key_params_anon.ptr.owner_id = nullptr;
msg_key_params_anon.ptr.data = nullptr;
if ((key = WM_msg_lookup_rna(mbus, &msg_key_params_anon))) {
WM_msg_publish_with_key(mbus, &key->head);
}
/* Support subscribers to a type. */
if (msg_key_params->prop) {
msg_key_params_anon.prop = nullptr;
if ((key = WM_msg_lookup_rna(mbus, &msg_key_params_anon))) {
WM_msg_publish_with_key(mbus, &key->head);
}
}
}
}
void WM_msg_publish_rna(wmMsgBus *mbus, PointerRNA *ptr, PropertyRNA *prop)
{
wmMsgParams_RNA params{};
params.ptr = *ptr;
params.prop = prop;
WM_msg_publish_rna_params(mbus, &params);
}
void WM_msg_subscribe_rna_params(wmMsgBus *mbus,
const wmMsgParams_RNA *msg_key_params,
const wmMsgSubscribeValue *msg_val_params,
const char *id_repr)
{
wmMsgSubscribeKey_RNA msg_key_test{};
/* Use when added. */
msg_key_test.msg.head.id = id_repr;
msg_key_test.msg.head.type = WM_MSG_TYPE_RNA;
/* For lookup. */
msg_key_test.msg.params = *msg_key_params;
const char *none = "<none>";
CLOG_TRACE(WM_LOG_MSGBUS_SUB,
"rna(id='%s', %s.%s, info='%s')",
msg_key_params->ptr.owner_id ? ((ID *)msg_key_params->ptr.owner_id)->name : none,
msg_key_params->ptr.type ? RNA_struct_identifier(msg_key_params->ptr.type) : none,
msg_key_params->prop ? RNA_property_identifier((PropertyRNA *)msg_key_params->prop) :
none,
id_repr);
wmMsgSubscribeKey_RNA *msg_key = reinterpret_cast<wmMsgSubscribeKey_RNA *>(
WM_msg_subscribe_with_key(mbus, &msg_key_test.head, msg_val_params));
if (msg_val_params->is_persistent) {
if (msg_key->msg.params.data_path == nullptr) {
if (msg_key->msg.params.ptr.data != msg_key->msg.params.ptr.owner_id) {
/* We assume prop type can't change. */
const std::optional<std::string> str = RNA_path_from_ID_to_struct(
&msg_key->msg.params.ptr);
msg_key->msg.params.data_path = str ? BLI_strdupn(str->c_str(), str->size()) : nullptr;
}
}
}
}
void WM_msg_subscribe_rna(wmMsgBus *mbus,
PointerRNA *ptr,
const PropertyRNA *prop,
const wmMsgSubscribeValue *msg_val_params,
const char *id_repr)
{
wmMsgParams_RNA params{};
params.ptr = *ptr;
params.prop = prop;
WM_msg_subscribe_rna_params(mbus, &params, msg_val_params, id_repr);
}
/** \} */
/* -------------------------------------------------------------------------- */
/** \name ID variants of RNA API
*
* \note While we could have a separate type for ID's, use RNA since there is enough overlap.
* \{ */
void WM_msg_subscribe_ID(wmMsgBus *mbus,
ID *id,
const wmMsgSubscribeValue *msg_val_params,
const char *id_repr)
{
wmMsgParams_RNA msg_key_params = {{}};
msg_key_params.ptr = RNA_id_pointer_create(id);
WM_msg_subscribe_rna_params(mbus, &msg_key_params, msg_val_params, id_repr);
}
void WM_msg_publish_ID(wmMsgBus *mbus, ID *id)
{
wmMsgParams_RNA msg_key_params = {{}};
msg_key_params.ptr = RNA_id_pointer_create(id);
WM_msg_publish_rna_params(mbus, &msg_key_params);
}
/** \} */
} // namespace blender

View File

@@ -0,0 +1,139 @@
/* SPDX-FileCopyrightText: 2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup wm
*/
#include <cstdio>
#include "CLG_log.h"
#include "MEM_guardedalloc.h"
#include "BLI_ghash.h"
#include "BLI_listbase.h"
#include "WM_message.hh"
#include "WM_types.hh"
#include "message_bus/intern/wm_message_bus_intern.hh"
namespace blender {
/* -------------------------------------------------------------------------- */
static uint wm_msg_static_gset_hash(const void *key_p)
{
const wmMsgSubscribeKey_Static *key = static_cast<const wmMsgSubscribeKey_Static *>(key_p);
const wmMsgParams_Static *params = &key->msg.params;
uint k = params->event;
return k;
}
static bool wm_msg_static_gset_cmp(const void *key_a_p, const void *key_b_p)
{
const wmMsgParams_Static *params_a =
&(static_cast<const wmMsgSubscribeKey_Static *>(key_a_p))->msg.params;
const wmMsgParams_Static *params_b =
&(static_cast<const wmMsgSubscribeKey_Static *>(key_b_p))->msg.params;
return !(params_a->event == params_b->event);
}
static void *wm_msg_static_gset_key_duplicate(const void *key_p)
{
const wmMsgSubscribeKey *key_src = static_cast<const wmMsgSubscribeKey *>(key_p);
return MEM_new<wmMsgSubscribeKey>(__func__, *key_src);
}
static void wm_msg_static_gset_key_free(void *key_p)
{
wmMsgSubscribeKey *key = static_cast<wmMsgSubscribeKey *>(key_p);
wmMsgSubscribeValueLink *msg_lnk_next;
for (wmMsgSubscribeValueLink *msg_lnk =
static_cast<wmMsgSubscribeValueLink *>(key->values.first);
msg_lnk;
msg_lnk = msg_lnk_next)
{
msg_lnk_next = msg_lnk->next;
BLI_remlink(&key->values, msg_lnk);
MEM_delete(msg_lnk);
}
MEM_delete(key);
}
static void wm_msg_static_repr(FILE *stream, const wmMsgSubscribeKey *msg_key)
{
const wmMsgSubscribeKey_Static *m = reinterpret_cast<wmMsgSubscribeKey_Static *>(
const_cast<wmMsgSubscribeKey *>(msg_key));
fprintf(stream,
"<wmMsg_Static %p, "
"id='%s', "
"values_len=%d\n",
m,
m->msg.head.id,
m->head.values.count());
}
void WM_msgtypeinfo_init_static(wmMsgTypeInfo *msgtype_info)
{
msgtype_info->gset.hash_fn = wm_msg_static_gset_hash;
msgtype_info->gset.cmp_fn = wm_msg_static_gset_cmp;
msgtype_info->gset.key_duplicate_fn = wm_msg_static_gset_key_duplicate;
msgtype_info->gset.key_free_fn = wm_msg_static_gset_key_free;
msgtype_info->repr = wm_msg_static_repr;
}
/* -------------------------------------------------------------------------- */
wmMsgSubscribeKey_Static *WM_msg_lookup_static(wmMsgBus *mbus,
const wmMsgParams_Static *msg_key_params)
{
wmMsgSubscribeKey_Static key_test;
key_test.msg.params = *msg_key_params;
return static_cast<wmMsgSubscribeKey_Static *>(
BLI_gset_lookup(mbus->messages_gset[WM_MSG_TYPE_STATIC], &key_test));
}
void WM_msg_publish_static_params(wmMsgBus *mbus, const wmMsgParams_Static *msg_key_params)
{
CLOG_DEBUG(WM_LOG_MSGBUS_PUB, "static(event=%d)", msg_key_params->event);
wmMsgSubscribeKey_Static *key = WM_msg_lookup_static(mbus, msg_key_params);
if (key) {
WM_msg_publish_with_key(mbus, &key->head);
}
}
void WM_msg_publish_static(wmMsgBus *mbus, int event)
{
wmMsgParams_Static params{};
params.event = event;
WM_msg_publish_static_params(mbus, &params);
}
void WM_msg_subscribe_static_params(wmMsgBus *mbus,
const wmMsgParams_Static *msg_key_params,
const wmMsgSubscribeValue *msg_val_params,
const char *id_repr)
{
wmMsgSubscribeKey_Static msg_key_test{};
/* Use when added. */
msg_key_test.msg.head.id = id_repr;
msg_key_test.msg.head.type = WM_MSG_TYPE_STATIC;
/* For lookup. */
msg_key_test.msg.params = *msg_key_params;
WM_msg_subscribe_with_key(mbus, &msg_key_test.head, msg_val_params);
}
void WM_msg_subscribe_static(wmMsgBus *mbus,
int event,
const wmMsgSubscribeValue *msg_val_params,
const char *id_repr)
{
wmMsgParams_Static params{};
params.event = event;
WM_msg_subscribe_static_params(mbus, &params, msg_val_params, id_repr);
}
} // namespace blender

View File

@@ -0,0 +1,299 @@
/* SPDX-FileCopyrightText: 2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup wm
*/
#pragma once
#include "BLI_string_ref.hh"
#include "DNA_listBase.h"
#include "RNA_prototypes.hh"
#include "RNA_types.hh"
#include <cstdio>
namespace blender {
struct ID;
struct bContext;
struct wmMsg;
/* Opaque (don't expose outside `wm_message_bus.cc`). */
struct wmMsgBus;
struct wmMsgSubscribeKey;
struct wmMsgSubscribeValue;
struct wmMsgSubscribeValueLink;
using wmMsgNotifyFn = void (*)(bContext *C,
wmMsgSubscribeKey *msg_key,
wmMsgSubscribeValue *msg_val);
using wmMsgSubscribeValueFreeDataFn = void (*)(wmMsgSubscribeKey *msg_key,
wmMsgSubscribeValue *msg_val);
/* Exactly what arguments here is not obvious. */
using wmMsgSubscribeValueUpdateIdFn =
void (*)(bContext *C, wmMsgBus *mbus, ID *id_src, ID *id_dst, wmMsgSubscribeValue *msg_val);
enum {
WM_MSG_TYPE_RNA = 0,
WM_MSG_TYPE_STATIC = 1,
/** Messages relating to some remote resources, like progress reporting for online asset
* downloads. */
WM_MSG_TYPE_REMOTE_IO = 2,
};
#define WM_MSG_TYPE_NUM 3
struct wmMsgTypeInfo {
struct {
unsigned int (*hash_fn)(const void *msg);
bool (*cmp_fn)(const void *a, const void *b);
/* Creation, duplication and deletion callbacks. */
/* Not needed currently, key are always allocated by duplicating from stack data. */
/* void *(*key_alloc_fn)(); */
void *(*key_duplicate_fn)(const void *key);
void (*key_free_fn)(void *key);
} gset;
void (*update_by_id)(wmMsgBus *mbus, ID *id_src, ID *id_dst);
void (*remove_by_id)(wmMsgBus *mbus, const ID *id);
void (*repr)(FILE *stream, const wmMsgSubscribeKey *msg_key);
};
struct wmMsg {
unsigned int type;
// #ifndef NDEBUG
/* For debugging: '__func__:__LINE__'. */
const char *id;
// #endif
};
struct wmMsgSubscribeKey {
/** Linked list for predictable ordering, otherwise we would depend on #GHash bucketing. */
wmMsgSubscribeKey *next, *prev;
ListBaseT<wmMsgSubscribeValueLink> values;
/* Over-allocate, eg: #wmMsgSubscribeKey_RNA. */
/* Last member will be `wmMsg_*`. */
};
/** One of many in #wmMsgSubscribeKey.values. */
struct wmMsgSubscribeValue {
wmMsgSubscribeValue *next, *prev;
/** Handle, used to iterate and clear. */
void *owner;
/** User data, can be whatever we like, free using the 'free_data' callback if it's owned. */
void *user_data;
/** Callbacks. */
wmMsgNotifyFn notify;
wmMsgSubscribeValueUpdateIdFn update_id;
wmMsgSubscribeValueFreeDataFn free_data;
/** Keep this subscriber if possible. */
uint is_persistent : 1;
/* Tag to run when handling events,
* we may want option for immediate execution. */
uint tag : 1;
};
/** One of many in #wmMsgSubscribeKey.values. */
struct wmMsgSubscribeValueLink {
wmMsgSubscribeValueLink *next, *prev;
wmMsgSubscribeValue params;
};
void WM_msgbus_types_init();
wmMsgBus *WM_msgbus_create();
void WM_msgbus_destroy(wmMsgBus *mbus);
void WM_msgbus_clear_by_owner(wmMsgBus *mbus, void *owner);
void WM_msg_dump(wmMsgBus *mbus, const char *info_str);
void WM_msgbus_handle(wmMsgBus *mbus, bContext *C);
void WM_msg_publish_with_key(wmMsgBus *mbus, wmMsgSubscribeKey *msg_key);
/**
* \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(wmMsgBus *mbus,
const wmMsgSubscribeKey *msg_key_test,
const wmMsgSubscribeValue *msg_val_params);
void WM_msg_id_update(wmMsgBus *mbus, ID *id_src, ID *id_dst);
void WM_msg_id_remove(wmMsgBus *mbus, const ID *id);
/* -------------------------------------------------------------------------- */
/* `wm_message_bus_static.cc` */
enum {
/* Generic window redraw. */
WM_MSG_STATICTYPE_WINDOW_DRAW = 0,
WM_MSG_STATICTYPE_SCREEN_EDIT = 1,
WM_MSG_STATICTYPE_FILE_READ = 2,
};
struct wmMsgParams_Static {
int event;
};
struct wmMsg_Static {
wmMsg head; /* Keep first. */
wmMsgParams_Static params;
};
struct wmMsgSubscribeKey_Static {
wmMsgSubscribeKey head;
wmMsg_Static msg;
};
void WM_msgtypeinfo_init_static(wmMsgTypeInfo *msgtype_info);
wmMsgSubscribeKey_Static *WM_msg_lookup_static(wmMsgBus *mbus,
const wmMsgParams_Static *msg_key_params);
void WM_msg_publish_static_params(wmMsgBus *mbus, const wmMsgParams_Static *msg_key_params);
void WM_msg_publish_static(wmMsgBus *mbus,
/* #wmMsgParams_Static (expanded). */
int event);
void WM_msg_subscribe_static_params(wmMsgBus *mbus,
const wmMsgParams_Static *msg_key_params,
const wmMsgSubscribeValue *msg_val_params,
const char *id_repr);
void WM_msg_subscribe_static(wmMsgBus *mbus,
int event,
const wmMsgSubscribeValue *msg_val_params,
const char *id_repr);
/* -------------------------------------------------------------------------- */
/* `wm_message_bus_remote_io.cc` */
struct wmMsgParams_RemoteIO {
/* Owned, needs freeing with `MEM_delete_void()`. */
const char *remote_url;
};
struct wmMsg_RemoteIO {
wmMsg head; /* Keep first. */
wmMsgParams_RemoteIO params;
};
struct wmMsgSubscribeKey_RemoteIO {
wmMsgSubscribeKey head;
wmMsg_RemoteIO msg;
};
void WM_msgtypeinfo_init_remote_io(wmMsgTypeInfo *msgtype_info);
wmMsgSubscribeKey_RemoteIO *WM_msg_lookup_remote_io(wmMsgBus *mbus,
const wmMsgParams_RemoteIO *msg_key_params);
void WM_msg_publish_remote_io_params(wmMsgBus *mbus, const wmMsgParams_RemoteIO *msg_key_params);
void WM_msg_publish_remote_io(wmMsgBus *mbus, StringRef remote_url);
void WM_msg_subscribe_remote_io_params(wmMsgBus *mbus,
const wmMsgParams_RemoteIO *msg_key_params,
const wmMsgSubscribeValue *msg_val_params,
const char *id_repr);
void WM_msg_subscribe_remote_io(wmMsgBus *mbus,
StringRef remote_url,
const wmMsgSubscribeValue *msg_val_params,
const char *id_repr);
/* -------------------------------------------------------------------------- */
/* `wm_message_bus_rna.cc` */
struct wmMsgParams_RNA {
/** When #PointerRNA.data & owner_id are NULL. match against all. */
PointerRNA ptr;
/** When NULL, match against any property. */
const PropertyRNA *prop;
/**
* Optional RNA data path for persistent RNA properties, ignore if NULL.
* otherwise it's allocated.
*/
char *data_path;
};
struct wmMsg_RNA {
wmMsg head; /* Keep first. */
wmMsgParams_RNA params;
};
struct wmMsgSubscribeKey_RNA {
wmMsgSubscribeKey head;
wmMsg_RNA msg;
};
void WM_msgtypeinfo_init_rna(wmMsgTypeInfo *msgtype_info);
wmMsgSubscribeKey_RNA *WM_msg_lookup_rna(wmMsgBus *mbus, const wmMsgParams_RNA *msg_key_params);
void WM_msg_publish_rna_params(wmMsgBus *mbus, const wmMsgParams_RNA *msg_key_params);
void WM_msg_publish_rna(wmMsgBus *mbus,
/* #wmMsgParams_RNA (expanded). */
PointerRNA *ptr,
PropertyRNA *prop);
void WM_msg_subscribe_rna_params(wmMsgBus *mbus,
const wmMsgParams_RNA *msg_key_params,
const wmMsgSubscribeValue *msg_val_params,
const char *id_repr);
void WM_msg_subscribe_rna(wmMsgBus *mbus,
PointerRNA *ptr,
const PropertyRNA *prop,
const wmMsgSubscribeValue *msg_val_params,
const char *id_repr);
/* ID variants. */
void WM_msg_subscribe_ID(wmMsgBus *mbus,
ID *id,
const wmMsgSubscribeValue *msg_val_params,
const char *id_repr);
void WM_msg_publish_ID(wmMsgBus *mbus, ID *id);
#define WM_msg_publish_rna_prop(mbus, id_, data_, type_, prop_) \
{ \
wmMsgParams_RNA msg_key_params_ = {{}}; \
msg_key_params_.ptr = RNA_pointer_create_discrete(id_, RNA_##type_, data_); \
msg_key_params_.prop = &rna_##type_##_##prop_; \
WM_msg_publish_rna_params(mbus, &msg_key_params_); \
} \
((void)0)
#define WM_msg_subscribe_rna_prop(mbus, id_, data_, type_, prop_, value) \
{ \
wmMsgParams_RNA msg_key_params_ = {{}}; \
msg_key_params_.ptr = RNA_pointer_create_discrete(id_, RNA_##type_, data_); \
msg_key_params_.prop = &rna_##type_##_##prop_; \
WM_msg_subscribe_rna_params(mbus, &msg_key_params_, value, __func__); \
} \
((void)0)
/* Anonymous variants (for convenience). */
#define WM_msg_subscribe_rna_anon_type(mbus, type_, value) \
{ \
PointerRNA msg_ptr_ = {nullptr, RNA_##type_, nullptr}; \
wmMsgParams_RNA msg_key_params_ = {{}}; \
msg_key_params_.ptr = msg_ptr_; \
\
WM_msg_subscribe_rna_params(mbus, &msg_key_params_, value, __func__); \
} \
((void)0)
#define WM_msg_subscribe_rna_anon_prop(mbus, type_, prop_, value) \
{ \
PointerRNA msg_ptr_ = {nullptr, RNA_##type_, nullptr}; \
wmMsgParams_RNA msg_key_params_ = {{}}; \
msg_key_params_.ptr = msg_ptr_; \
msg_key_params_.prop = &rna_##type_##_##prop_; \
\
WM_msg_subscribe_rna_params(mbus, &msg_key_params_, value, __func__); \
} \
((void)0)
} // namespace blender