feat(listeners): 实现 listener 通知分发和清理功能
This commit is contained in:
@@ -269,3 +269,48 @@ binding_table_get_current_bindings(binding_table_t *table, size_t *count) {
|
|||||||
*count = mode->count;
|
*count = mode->count;
|
||||||
return mode->items;
|
return mode->items;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t binding_table_mode_count(const binding_table_t *table) {
|
||||||
|
if (!table) return 0;
|
||||||
|
return table->count;
|
||||||
|
}
|
||||||
|
|
||||||
|
zdwm_binding_mode_id_t binding_table_get_default_mode(
|
||||||
|
const binding_table_t *table
|
||||||
|
) {
|
||||||
|
if (!table) return ZDWM_BINDING_MODE_ID_INVALID;
|
||||||
|
return table->default_mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
zdwm_binding_mode_id_t binding_table_get_current_mode(
|
||||||
|
const binding_table_t *table
|
||||||
|
) {
|
||||||
|
if (!table) return ZDWM_BINDING_MODE_ID_INVALID;
|
||||||
|
return table->current_mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const binding_mode_t *binding_table_get_mode_const(
|
||||||
|
const binding_table_t *table,
|
||||||
|
zdwm_binding_mode_id_t mode_id
|
||||||
|
) {
|
||||||
|
if (!table || mode_id >= table->count) return nullptr;
|
||||||
|
|
||||||
|
const binding_mode_t *mode = &table->modes[mode_id];
|
||||||
|
if (mode->id == mode_id) return mode;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < table->count; ++i) {
|
||||||
|
mode = &table->modes[i];
|
||||||
|
if (mode->id == mode_id) return mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *binding_table_get_mode_name(
|
||||||
|
const binding_table_t *table,
|
||||||
|
zdwm_binding_mode_id_t mode_id
|
||||||
|
) {
|
||||||
|
auto mode = binding_table_get_mode_const(table, mode_id);
|
||||||
|
if (!mode) return nullptr;
|
||||||
|
return mode->name;
|
||||||
|
}
|
||||||
|
|||||||
@@ -107,3 +107,15 @@ bool binding_table_cycle_mode(binding_table_t *table, int delta);
|
|||||||
*/
|
*/
|
||||||
const key_binding_t *
|
const key_binding_t *
|
||||||
binding_table_get_current_bindings(binding_table_t *table, size_t *count);
|
binding_table_get_current_bindings(binding_table_t *table, size_t *count);
|
||||||
|
|
||||||
|
size_t binding_table_mode_count(const binding_table_t *table);
|
||||||
|
zdwm_binding_mode_id_t binding_table_get_default_mode(
|
||||||
|
const binding_table_t *table
|
||||||
|
);
|
||||||
|
zdwm_binding_mode_id_t binding_table_get_current_mode(
|
||||||
|
const binding_table_t *table
|
||||||
|
);
|
||||||
|
const char *binding_table_get_mode_name(
|
||||||
|
const binding_table_t *table,
|
||||||
|
zdwm_binding_mode_id_t mode_id
|
||||||
|
);
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
#include "core/listeners.h"
|
#include "core/listeners.h"
|
||||||
|
|
||||||
#include "base/array.h"
|
#include "base/array.h"
|
||||||
|
#include "base/memory.h"
|
||||||
|
#include "core/binding.h"
|
||||||
|
#include "core/layout.h"
|
||||||
|
#include "core/state.h"
|
||||||
|
|
||||||
#define ADD_LISTENER(FIELD) \
|
#define ADD_LISTENER(FIELD) \
|
||||||
auto list = &listeners->FIELD; \
|
auto list = &listeners->FIELD; \
|
||||||
@@ -81,3 +85,207 @@ void listeners_add_window_removed_listener(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#undef ADD_LISTENER
|
#undef ADD_LISTENER
|
||||||
|
|
||||||
|
#define CLEANUP_LIST(FIELD) \
|
||||||
|
p_delete(&listeners->FIELD.items); \
|
||||||
|
listeners->FIELD.count = 0; \
|
||||||
|
listeners->FIELD.capacity = 0
|
||||||
|
|
||||||
|
void listeners_cleanup(listeners_t *listeners) {
|
||||||
|
if (!listeners) return;
|
||||||
|
|
||||||
|
CLEANUP_LIST(output_listeners);
|
||||||
|
CLEANUP_LIST(initial_workspace_listeners);
|
||||||
|
CLEANUP_LIST(active_workspace_listeners);
|
||||||
|
CLEANUP_LIST(layout_listeners);
|
||||||
|
CLEANUP_LIST(binding_mode_listeners);
|
||||||
|
CLEANUP_LIST(initial_window_listeners);
|
||||||
|
CLEANUP_LIST(window_added_listeners);
|
||||||
|
CLEANUP_LIST(window_updated_listeners);
|
||||||
|
CLEANUP_LIST(window_removed_listeners);
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef CLEANUP_LIST
|
||||||
|
|
||||||
|
#define FOR_EACH_LISTENER(FIELD, BODY) \
|
||||||
|
do { \
|
||||||
|
if (!(listeners)) return; \
|
||||||
|
auto list = &(listeners)->FIELD; \
|
||||||
|
for (size_t i = 0; i < list->count; ++i) { \
|
||||||
|
auto item = &list->items[i]; \
|
||||||
|
BODY; \
|
||||||
|
} \
|
||||||
|
} while (false)
|
||||||
|
|
||||||
|
void listeners_notify_current_output(
|
||||||
|
const listeners_t *listeners,
|
||||||
|
output_id_t output_id
|
||||||
|
) {
|
||||||
|
FOR_EACH_LISTENER(output_listeners, item->fn(output_id, item->user_data));
|
||||||
|
}
|
||||||
|
|
||||||
|
void listeners_notify_initial_workspaces(
|
||||||
|
const listeners_t *listeners,
|
||||||
|
const state_t *state
|
||||||
|
) {
|
||||||
|
if (!listeners || !state) return;
|
||||||
|
|
||||||
|
size_t count = state_workspace_count(state);
|
||||||
|
auto items = count ? p_new(zdwm_workspace_t, count) : nullptr;
|
||||||
|
for (size_t i = 0; i < count; ++i) {
|
||||||
|
auto workspace = state_workspace_at(state, i);
|
||||||
|
|
||||||
|
items[i] = (zdwm_workspace_t){
|
||||||
|
.output_id = workspace->output_id,
|
||||||
|
.id = workspace->id,
|
||||||
|
.name = workspace->name,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
FOR_EACH_LISTENER(
|
||||||
|
initial_workspace_listeners,
|
||||||
|
item->fn(items, count, item->user_data)
|
||||||
|
);
|
||||||
|
|
||||||
|
p_delete(&items);
|
||||||
|
}
|
||||||
|
|
||||||
|
void listeners_notify_workspace_active(
|
||||||
|
const listeners_t *listeners,
|
||||||
|
output_id_t output_id,
|
||||||
|
workspace_id_t workspace_id
|
||||||
|
) {
|
||||||
|
FOR_EACH_LISTENER(
|
||||||
|
active_workspace_listeners,
|
||||||
|
item->fn(output_id, workspace_id, item->user_data)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void listeners_notify_layout(
|
||||||
|
const listeners_t *listeners,
|
||||||
|
const layout_registry_t *layouts,
|
||||||
|
workspace_id_t workspace_id,
|
||||||
|
layout_id_t layout_id
|
||||||
|
) {
|
||||||
|
if (!listeners || !layouts) return;
|
||||||
|
|
||||||
|
auto slot = layout_slot_get(layouts, layout_id);
|
||||||
|
if (!slot) return;
|
||||||
|
|
||||||
|
zdwm_layout_notify_t notify = {
|
||||||
|
.workspace = workspace_id,
|
||||||
|
.id = layout_id,
|
||||||
|
.symbol = slot->symbol,
|
||||||
|
};
|
||||||
|
|
||||||
|
FOR_EACH_LISTENER(layout_listeners, item->fn(notify, item->user_data));
|
||||||
|
}
|
||||||
|
|
||||||
|
void listeners_notify_binding_mode(
|
||||||
|
const listeners_t *listeners,
|
||||||
|
const binding_table_t *binding_table
|
||||||
|
) {
|
||||||
|
if (!listeners || !binding_table) return;
|
||||||
|
|
||||||
|
auto default_mode = binding_table_get_default_mode(binding_table);
|
||||||
|
auto current_mode = binding_table_get_current_mode(binding_table);
|
||||||
|
auto name = binding_table_get_mode_name(binding_table, current_mode);
|
||||||
|
|
||||||
|
zdwm_binding_mode_notify_t notify = {
|
||||||
|
.is_default_mode = default_mode == current_mode,
|
||||||
|
.id = current_mode,
|
||||||
|
.name = name,
|
||||||
|
};
|
||||||
|
|
||||||
|
FOR_EACH_LISTENER(binding_mode_listeners, item->fn(notify, item->user_data));
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool listeners_window_snapshot(
|
||||||
|
const state_t *state,
|
||||||
|
window_id_t window_id,
|
||||||
|
zdwm_window_t *out
|
||||||
|
) {
|
||||||
|
if (!state || !out || window_id_invalid(window_id)) return false;
|
||||||
|
|
||||||
|
auto window = state_window_get(state, window_id);
|
||||||
|
if (!window) return false;
|
||||||
|
|
||||||
|
auto workspace = state_workspace_get(state, window->workspace_id);
|
||||||
|
if (!workspace) return false;
|
||||||
|
|
||||||
|
*out = (zdwm_window_t){
|
||||||
|
.workspace = window->workspace_id,
|
||||||
|
.id = window->id,
|
||||||
|
.title = window->title,
|
||||||
|
.focused = workspace->focused_window_id == window->id,
|
||||||
|
.urgent = window->urgent,
|
||||||
|
.skip_taskbar = window->skip_taskbar,
|
||||||
|
};
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void listeners_notify_initial_windows(
|
||||||
|
const listeners_t *listeners,
|
||||||
|
const state_t *state
|
||||||
|
) {
|
||||||
|
if (!listeners || !state) return;
|
||||||
|
|
||||||
|
size_t count = state_window_count(state);
|
||||||
|
zdwm_window_t *items = count ? p_new(zdwm_window_t, count) : nullptr;
|
||||||
|
for (size_t i = 0; i < count; ++i) {
|
||||||
|
auto window = state_window_at(state, i);
|
||||||
|
if (!listeners_window_snapshot(state, window->id, &items[i])) {
|
||||||
|
p_clear(&items[i], 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FOR_EACH_LISTENER(
|
||||||
|
initial_window_listeners,
|
||||||
|
item->fn(items, count, item->user_data)
|
||||||
|
);
|
||||||
|
|
||||||
|
p_delete(&items);
|
||||||
|
}
|
||||||
|
|
||||||
|
void listeners_notify_window_added(
|
||||||
|
const listeners_t *listeners,
|
||||||
|
const state_t *state,
|
||||||
|
window_id_t window_id
|
||||||
|
) {
|
||||||
|
if (!listeners || !state) return;
|
||||||
|
|
||||||
|
zdwm_window_t window = {0};
|
||||||
|
if (!listeners_window_snapshot(state, window_id, &window)) return;
|
||||||
|
|
||||||
|
FOR_EACH_LISTENER(window_added_listeners, item->fn(&window, item->user_data));
|
||||||
|
}
|
||||||
|
|
||||||
|
void listeners_notify_window_updated(
|
||||||
|
const listeners_t *listeners,
|
||||||
|
const state_t *state,
|
||||||
|
window_id_t window_id
|
||||||
|
) {
|
||||||
|
if (!listeners || !state) return;
|
||||||
|
|
||||||
|
zdwm_window_t window = {0};
|
||||||
|
if (!listeners_window_snapshot(state, window_id, &window)) return;
|
||||||
|
|
||||||
|
FOR_EACH_LISTENER(
|
||||||
|
window_updated_listeners,
|
||||||
|
item->fn(&window, item->user_data)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void listeners_notify_window_removed(
|
||||||
|
const listeners_t *listeners,
|
||||||
|
window_id_t window_id
|
||||||
|
) {
|
||||||
|
if (!listeners || window_id_invalid(window_id)) return;
|
||||||
|
|
||||||
|
FOR_EACH_LISTENER(
|
||||||
|
window_removed_listeners,
|
||||||
|
item->fn(window_id, item->user_data)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef FOR_EACH_LISTENER
|
||||||
|
|||||||
@@ -3,6 +3,12 @@
|
|||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <zdwm/listeners.h>
|
#include <zdwm/listeners.h>
|
||||||
|
|
||||||
|
#include "core/types.h"
|
||||||
|
|
||||||
|
typedef struct binding_table_t binding_table_t;
|
||||||
|
typedef struct layout_registry_t layout_registry_t;
|
||||||
|
typedef struct state_t state_t;
|
||||||
|
|
||||||
#define ITEM(NAME, FN_TYPE) \
|
#define ITEM(NAME, FN_TYPE) \
|
||||||
typedef struct NAME##_listener_item_t { \
|
typedef struct NAME##_listener_item_t { \
|
||||||
FN_TYPE *fn; \
|
FN_TYPE *fn; \
|
||||||
@@ -87,3 +93,46 @@ void listeners_add_window_removed_listener(
|
|||||||
zdwm_window_removed fn,
|
zdwm_window_removed fn,
|
||||||
void *user_data
|
void *user_data
|
||||||
);
|
);
|
||||||
|
|
||||||
|
void listeners_cleanup(listeners_t *listeners);
|
||||||
|
void listeners_notify_current_output(
|
||||||
|
const listeners_t *listeners,
|
||||||
|
output_id_t output_id
|
||||||
|
);
|
||||||
|
void listeners_notify_initial_workspaces(
|
||||||
|
const listeners_t *listeners,
|
||||||
|
const state_t *state
|
||||||
|
);
|
||||||
|
void listeners_notify_workspace_active(
|
||||||
|
const listeners_t *listeners,
|
||||||
|
output_id_t output_id,
|
||||||
|
workspace_id_t workspace_id
|
||||||
|
);
|
||||||
|
void listeners_notify_layout(
|
||||||
|
const listeners_t *listeners,
|
||||||
|
const layout_registry_t *layouts,
|
||||||
|
workspace_id_t workspace_id,
|
||||||
|
layout_id_t layout_id
|
||||||
|
);
|
||||||
|
void listeners_notify_binding_mode(
|
||||||
|
const listeners_t *listeners,
|
||||||
|
const binding_table_t *binding_table
|
||||||
|
);
|
||||||
|
void listeners_notify_initial_windows(
|
||||||
|
const listeners_t *listeners,
|
||||||
|
const state_t *state
|
||||||
|
);
|
||||||
|
void listeners_notify_window_added(
|
||||||
|
const listeners_t *listeners,
|
||||||
|
const state_t *state,
|
||||||
|
window_id_t window_id
|
||||||
|
);
|
||||||
|
void listeners_notify_window_updated(
|
||||||
|
const listeners_t *listeners,
|
||||||
|
const state_t *state,
|
||||||
|
window_id_t window_id
|
||||||
|
);
|
||||||
|
void listeners_notify_window_removed(
|
||||||
|
const listeners_t *listeners,
|
||||||
|
window_id_t window_id
|
||||||
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user