Refactor: Move the notifier event queue to use runtime data.
Also make it a bit more obvious when some functions are for internal use and not.
This commit is contained in:
committed by
Sebastian Parborg
parent
19982a01df
commit
73b7edbe09
@@ -4,18 +4,35 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
struct GSet;
|
||||
|
||||
#include "DNA_windowmanager_types.h"
|
||||
|
||||
namespace blender::bke {
|
||||
|
||||
class WindowManagerRuntime {
|
||||
public:
|
||||
struct WindowManagerRuntime {
|
||||
/** Indicates whether interface is locked for user interaction. */
|
||||
bool is_interface_locked = false;
|
||||
|
||||
/** Information and error reports. */
|
||||
ReportList reports;
|
||||
|
||||
/**
|
||||
* Refresh/redraw #wmNotifier structs.
|
||||
* \note Once in the queue, notifiers should be considered read-only.
|
||||
* With the exception of clearing notifiers for data which has been removed,
|
||||
* see: #NOTE_CATEGORY_TAG_CLEARED.
|
||||
*/
|
||||
ListBase notifier_queue = {nullptr, nullptr};
|
||||
/**
|
||||
* For duplicate detection.
|
||||
* \note keep in sync with `notifier_queue` adding/removing elements must also update this set.
|
||||
*/
|
||||
GSet *notifier_queue_set = nullptr;
|
||||
|
||||
/** The current notifier in the `notifier_queue` being handled (clear instead of freeing). */
|
||||
const wmNotifier *notifier_current = nullptr;
|
||||
|
||||
WindowManagerRuntime();
|
||||
~WindowManagerRuntime();
|
||||
};
|
||||
|
||||
@@ -9,6 +9,9 @@
|
||||
#include "BKE_report.hh"
|
||||
#include "BKE_wm_runtime.hh"
|
||||
|
||||
#include "BLI_ghash.h"
|
||||
#include "BLI_listbase.h"
|
||||
|
||||
namespace blender::bke {
|
||||
|
||||
WindowManagerRuntime::WindowManagerRuntime()
|
||||
@@ -19,6 +22,11 @@ WindowManagerRuntime::WindowManagerRuntime()
|
||||
WindowManagerRuntime::~WindowManagerRuntime()
|
||||
{
|
||||
BKE_reports_free(&this->reports);
|
||||
|
||||
BLI_freelistN(&this->notifier_queue);
|
||||
if (this->notifier_queue_set) {
|
||||
BLI_gset_free(this->notifier_queue_set, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace blender::bke
|
||||
|
||||
@@ -24,7 +24,7 @@ using std_mutex_type = std::mutex;
|
||||
/** Workaround to forward-declare C++ type in C header. */
|
||||
#ifdef __cplusplus
|
||||
namespace blender::bke {
|
||||
class WindowManagerRuntime;
|
||||
struct WindowManagerRuntime;
|
||||
}
|
||||
using WindowManagerRuntimeHandle = blender::bke::WindowManagerRuntime;
|
||||
#else // __cplusplus
|
||||
@@ -171,22 +171,6 @@ typedef struct wmWindowManager {
|
||||
/** Operator registry. */
|
||||
ListBase operators;
|
||||
|
||||
/**
|
||||
* Refresh/redraw #wmNotifier structs.
|
||||
* \note Once in the queue, notifiers should be considered read-only.
|
||||
* With the exception of clearing notifiers for data which has been removed,
|
||||
* see: #NOTE_CATEGORY_TAG_CLEARED.
|
||||
*/
|
||||
ListBase notifier_queue;
|
||||
/**
|
||||
* For duplicate detection.
|
||||
* \note keep in sync with `notifier_queue` adding/removing elements must also update this set.
|
||||
*/
|
||||
struct GSet *notifier_queue_set;
|
||||
|
||||
/** The current notifier in the `notifier_queue` being handled (clear instead of freeing). */
|
||||
const struct wmNotifier *notifier_current;
|
||||
|
||||
/** Available/pending extensions updates. */
|
||||
int extensions_updates;
|
||||
/** Number of blocked & installed extensions. */
|
||||
|
||||
@@ -207,9 +207,6 @@ static void window_manager_blend_read_data(BlendDataReader *reader, ID *id)
|
||||
BLI_listbase_clear(&wm->timers);
|
||||
BLI_listbase_clear(&wm->operators);
|
||||
BLI_listbase_clear(&wm->paintcursors);
|
||||
BLI_listbase_clear(&wm->notifier_queue);
|
||||
wm->notifier_queue_set = nullptr;
|
||||
wm->notifier_current = nullptr;
|
||||
|
||||
BLI_listbase_clear(&wm->keyconfigs);
|
||||
wm->defaultconf = nullptr;
|
||||
@@ -586,14 +583,6 @@ void wm_close_and_free(bContext *C, wmWindowManager *wm)
|
||||
WM_keyconfig_free(keyconf);
|
||||
}
|
||||
|
||||
BLI_freelistN(&wm->notifier_queue);
|
||||
if (wm->notifier_queue_set) {
|
||||
BLI_gset_free(wm->notifier_queue_set, nullptr);
|
||||
wm->notifier_queue_set = nullptr;
|
||||
}
|
||||
BLI_assert(wm->notifier_current == nullptr);
|
||||
wm->notifier_current = nullptr;
|
||||
|
||||
if (wm->message_bus != nullptr) {
|
||||
WM_msgbus_destroy(wm->message_bus);
|
||||
}
|
||||
|
||||
@@ -353,17 +353,12 @@ static bool note_cmp_for_queue_fn(const void *a, const void *b)
|
||||
(note_a->reference == note_b->reference));
|
||||
}
|
||||
|
||||
void WM_event_add_notifier_ex(wmWindowManager *wm, const wmWindow *win, uint type, void *reference)
|
||||
static void wm_event_add_notifier_intern(wmWindowManager *wm,
|
||||
const wmWindow *win,
|
||||
uint type,
|
||||
void *reference)
|
||||
{
|
||||
if (wm == nullptr) {
|
||||
/* There may be some cases where e.g. `G_MAIN` is not actually the real current main, but some
|
||||
* other temporary one (e.g. during liboverride processing over linked data), leading to null
|
||||
* window manager.
|
||||
*
|
||||
* This is fairly bad and weak, but unfortunately RNA does not have any way to operate over
|
||||
* another main than G_MAIN currently. */
|
||||
return;
|
||||
}
|
||||
BLI_assert(wm != nullptr);
|
||||
|
||||
wmNotifier note_test = {nullptr};
|
||||
|
||||
@@ -377,19 +372,33 @@ void WM_event_add_notifier_ex(wmWindowManager *wm, const wmWindow *win, uint typ
|
||||
|
||||
BLI_assert(!wm_notifier_is_clear(¬e_test));
|
||||
|
||||
if (wm->notifier_queue_set == nullptr) {
|
||||
wm->notifier_queue_set = BLI_gset_new_ex(
|
||||
if (wm->runtime->notifier_queue_set == nullptr) {
|
||||
wm->runtime->notifier_queue_set = BLI_gset_new_ex(
|
||||
note_hash_for_queue_fn, note_cmp_for_queue_fn, __func__, 1024);
|
||||
}
|
||||
|
||||
void **note_p;
|
||||
if (BLI_gset_ensure_p_ex(wm->notifier_queue_set, ¬e_test, ¬e_p)) {
|
||||
if (BLI_gset_ensure_p_ex(wm->runtime->notifier_queue_set, ¬e_test, ¬e_p)) {
|
||||
return;
|
||||
}
|
||||
wmNotifier *note = MEM_callocN<wmNotifier>(__func__);
|
||||
*note = note_test;
|
||||
*note_p = note;
|
||||
BLI_addtail(&wm->notifier_queue, note);
|
||||
BLI_addtail(&wm->runtime->notifier_queue, note);
|
||||
}
|
||||
|
||||
void WM_event_add_notifier_ex(wmWindowManager *wm, const wmWindow *win, uint type, void *reference)
|
||||
{
|
||||
if (wm == nullptr) {
|
||||
/* There may be some cases where e.g. `G_MAIN` is not actually the real current main, but some
|
||||
* other temporary one (e.g. during liboverride processing over linked data), leading to null
|
||||
* window manager.
|
||||
*
|
||||
* This is fairly bad and weak, but unfortunately RNA does not have any way to operate over
|
||||
* another main than G_MAIN currently. */
|
||||
return;
|
||||
}
|
||||
wm_event_add_notifier_intern(wm, win, type, reference);
|
||||
}
|
||||
|
||||
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
|
||||
@@ -413,23 +422,23 @@ void WM_main_remove_notifier_reference(const void *reference)
|
||||
wmWindowManager *wm = static_cast<wmWindowManager *>(bmain->wm.first);
|
||||
|
||||
if (wm) {
|
||||
LISTBASE_FOREACH_MUTABLE (wmNotifier *, note, &wm->notifier_queue) {
|
||||
LISTBASE_FOREACH_MUTABLE (wmNotifier *, note, &wm->runtime->notifier_queue) {
|
||||
if (note->reference == reference) {
|
||||
const bool removed = BLI_gset_remove(wm->notifier_queue_set, note, nullptr);
|
||||
const bool removed = BLI_gset_remove(wm->runtime->notifier_queue_set, note, nullptr);
|
||||
BLI_assert(removed);
|
||||
UNUSED_VARS_NDEBUG(removed);
|
||||
|
||||
/* Remove unless this is being iterated over by the caller.
|
||||
* This is done to prevent `wm->notifier_queue` accumulating notifiers
|
||||
* This is done to prevent `wm->runtime->notifier_queue` accumulating notifiers
|
||||
* that aren't handled which can happen when notifiers are added from Python scripts.
|
||||
* see #129323. */
|
||||
if (wm->notifier_current == note) {
|
||||
if (wm->runtime->notifier_current == note) {
|
||||
/* Don't remove because this causes problems for #wm_event_do_notifiers
|
||||
* which may be looping on the data (deleting screens). */
|
||||
wm_notifier_clear(note);
|
||||
}
|
||||
else {
|
||||
BLI_remlink(&wm->notifier_queue, note);
|
||||
BLI_remlink(&wm->runtime->notifier_queue, note);
|
||||
MEM_freeN(note);
|
||||
}
|
||||
}
|
||||
@@ -589,9 +598,10 @@ void wm_event_do_notifiers(bContext *C)
|
||||
|
||||
CTX_wm_window_set(C, win);
|
||||
|
||||
BLI_assert(wm->notifier_current == nullptr);
|
||||
for (const wmNotifier *note = static_cast<const wmNotifier *>(wm->notifier_queue.first),
|
||||
*note_next = nullptr;
|
||||
BLI_assert(wm->runtime->notifier_current == nullptr);
|
||||
for (const wmNotifier *
|
||||
note = static_cast<const wmNotifier *>(wm->runtime->notifier_queue.first),
|
||||
*note_next = nullptr;
|
||||
note;
|
||||
note = note_next)
|
||||
{
|
||||
@@ -601,7 +611,7 @@ void wm_event_do_notifiers(bContext *C)
|
||||
continue;
|
||||
}
|
||||
|
||||
wm->notifier_current = note;
|
||||
wm->runtime->notifier_current = note;
|
||||
|
||||
if (note->category == NC_WM) {
|
||||
if (ELEM(note->data, ND_FILEREAD, ND_FILESAVE)) {
|
||||
@@ -673,11 +683,11 @@ void wm_event_do_notifiers(bContext *C)
|
||||
clear_info_stats = true;
|
||||
}
|
||||
|
||||
wm->notifier_current = nullptr;
|
||||
wm->runtime->notifier_current = nullptr;
|
||||
|
||||
note_next = note->next;
|
||||
if (wm_notifier_is_clear(note)) {
|
||||
BLI_remlink(&wm->notifier_queue, (void *)note);
|
||||
BLI_remlink(&wm->runtime->notifier_queue, (void *)note);
|
||||
MEM_freeN((void *)note);
|
||||
}
|
||||
}
|
||||
@@ -686,7 +696,7 @@ void wm_event_do_notifiers(bContext *C)
|
||||
/* Only do once since adding notifiers is slow when there are many. */
|
||||
ViewLayer *view_layer = CTX_data_view_layer(C);
|
||||
ED_info_stats_clear(wm, view_layer);
|
||||
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_INFO, nullptr);
|
||||
wm_event_add_notifier_intern(wm, CTX_wm_window(C), NC_SPACE | ND_SPACE_INFO, nullptr);
|
||||
}
|
||||
|
||||
if (do_anim) {
|
||||
@@ -702,19 +712,20 @@ void wm_event_do_notifiers(bContext *C)
|
||||
}
|
||||
}
|
||||
|
||||
BLI_assert(wm->notifier_current == nullptr);
|
||||
BLI_assert(wm->runtime->notifier_current == nullptr);
|
||||
|
||||
/* The notifiers are sent without context, to keep it clean. */
|
||||
while (
|
||||
const wmNotifier *note = static_cast<const wmNotifier *>(BLI_pophead(&wm->notifier_queue)))
|
||||
while (const wmNotifier *note = static_cast<const wmNotifier *>(
|
||||
BLI_pophead(&wm->runtime->notifier_queue)))
|
||||
{
|
||||
if (wm_notifier_is_clear(note)) {
|
||||
MEM_freeN((void *)note);
|
||||
continue;
|
||||
}
|
||||
/* NOTE: no need to set `wm->notifier_current` since it's been removed from the queue. */
|
||||
/* NOTE: no need to set `wm->runtime->notifier_current` since it's been removed from the queue.
|
||||
*/
|
||||
|
||||
const bool removed = BLI_gset_remove(wm->notifier_queue_set, note, nullptr);
|
||||
const bool removed = BLI_gset_remove(wm->runtime->notifier_queue_set, note, nullptr);
|
||||
BLI_assert(removed);
|
||||
UNUSED_VARS_NDEBUG(removed);
|
||||
LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
|
||||
|
||||
Reference in New Issue
Block a user