Compare commits
10 Commits
3be83aefdf
...
9f9adf7e2e
| Author | SHA1 | Date | |
|---|---|---|---|
|
9f9adf7e2e
|
|||
|
00df685184
|
|||
|
6d06b61134
|
|||
|
30dfb19a7b
|
|||
|
195733e008
|
|||
|
6f1421f5b5
|
|||
|
9bbdb26f06
|
|||
|
6e3e7ee937
|
|||
|
9d35d17493
|
|||
|
a4bd0b53de
|
@@ -33,6 +33,7 @@ add_executable(${APP_NAME}
|
||||
${SOURCE_DIR}/bar/binding.c
|
||||
${SOURCE_DIR}/bar/cell.c
|
||||
${SOURCE_DIR}/bar/text.c
|
||||
${SOURCE_DIR}/bar/windows.c
|
||||
${SOURCE_DIR}/bar/workspaces.c
|
||||
|
||||
${SOURCE_DIR}/base/color.c
|
||||
|
||||
@@ -39,6 +39,7 @@ typedef struct zdwm_bar_config_t {
|
||||
const char *binding_mode_bg;
|
||||
const char *binding_mode_fg;
|
||||
|
||||
uint32_t window_padding_x;
|
||||
const char *window_bg;
|
||||
const char *window_fg;
|
||||
const char *window_focused_bg;
|
||||
|
||||
@@ -60,6 +60,21 @@ static void atoms_init(backend_t *backend) {
|
||||
*atom->atom = reply->atom;
|
||||
p_delete(&reply);
|
||||
}
|
||||
|
||||
#define EWMH_ITEM(name) atoms->name,
|
||||
xcb_atom_t ewmh_supported_atoms[] = {EWMH_ATOMS(EWMH_ITEM)};
|
||||
#undef EWMH_ITEM
|
||||
auto root = backend->screen->root;
|
||||
xcb_change_property(
|
||||
conn,
|
||||
XCB_PROP_MODE_REPLACE,
|
||||
root,
|
||||
atoms->_NET_SUPPORTED,
|
||||
XCB_ATOM_ATOM,
|
||||
32,
|
||||
countof(ewmh_supported_atoms),
|
||||
ewmh_supported_atoms
|
||||
);
|
||||
}
|
||||
|
||||
static void create_wm_check_window(backend_t *backend) {
|
||||
|
||||
@@ -492,7 +492,8 @@ bool backend_poll_event(backend_t *backend, event_t *event) {
|
||||
auto raw_event = xcb_poll_for_event(backend->conn);
|
||||
if (!raw_event) return false;
|
||||
|
||||
return handle_event(backend, raw_event, event);
|
||||
handle_event(backend, raw_event, event);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool backend_next_event(backend_t *backend, event_t *event) {
|
||||
|
||||
@@ -9,21 +9,9 @@
|
||||
#include "base/window_list.h"
|
||||
#include "core/event.h"
|
||||
|
||||
#define ATOM_LIST(X) \
|
||||
X(COMPOUND_TEXT) \
|
||||
X(UTF8_STRING) \
|
||||
\
|
||||
X(WM_WINDOW_ROLE) \
|
||||
X(WM_NAME) \
|
||||
X(WM_CHANGE_STATE) \
|
||||
#define EWMH_ATOMS(X) \
|
||||
X(_NET_WM_NAME) \
|
||||
\
|
||||
X(WM_PROTOCOLS) \
|
||||
X(WM_TAKE_FOCUS) \
|
||||
X(WM_DELETE_WINDOW) \
|
||||
X(_NET_ACTIVE_WINDOW) \
|
||||
\
|
||||
X(_NET_SUPPORTING_WM_CHECK) \
|
||||
X(_NET_WM_PID) \
|
||||
\
|
||||
X(_NET_CLIENT_LIST) \
|
||||
@@ -56,6 +44,22 @@
|
||||
X(_NET_WM_WINDOW_TYPE_DND) \
|
||||
X(_NET_WM_WINDOW_TYPE_NOTIFICATION)
|
||||
|
||||
#define ATOM_LIST(X) \
|
||||
X(COMPOUND_TEXT) \
|
||||
X(UTF8_STRING) \
|
||||
\
|
||||
X(WM_WINDOW_ROLE) \
|
||||
X(WM_NAME) \
|
||||
X(WM_CHANGE_STATE) \
|
||||
\
|
||||
X(WM_PROTOCOLS) \
|
||||
X(WM_TAKE_FOCUS) \
|
||||
X(WM_DELETE_WINDOW) \
|
||||
\
|
||||
X(_NET_SUPPORTING_WM_CHECK) \
|
||||
X(_NET_SUPPORTED) \
|
||||
EWMH_ATOMS(X)
|
||||
|
||||
typedef struct atoms_t {
|
||||
#define DECLARATION_ATOM(name) xcb_atom_t name;
|
||||
ATOM_LIST(DECLARATION_ATOM);
|
||||
|
||||
@@ -12,8 +12,10 @@
|
||||
#include "bar/cell.h"
|
||||
#include "bar/text.h"
|
||||
#include "bar/types.h"
|
||||
#include "bar/windows.h"
|
||||
#include "bar/workspaces.h"
|
||||
#include "base/array.h"
|
||||
#include "base/color.h"
|
||||
#include "base/macros.h"
|
||||
#include "base/memory.h"
|
||||
#include "base/time.h"
|
||||
@@ -103,6 +105,31 @@ static void bar_output_add_binding(
|
||||
bar_binding_add_listeners(listeners, item->state);
|
||||
}
|
||||
|
||||
static void bar_output_add_windows(
|
||||
bar_output_t *bar_output,
|
||||
zdwm_bar_config_t *config,
|
||||
listeners_t *listeners
|
||||
) {
|
||||
auto item = &bar_output->center;
|
||||
|
||||
bar_windows_config_t window_config = {
|
||||
.cell_padding = VALUE(config->window_padding_x, config->padding_x),
|
||||
.bg = VALUE(config->window_bg, config->bg),
|
||||
.fg = VALUE(config->window_fg, config->fg),
|
||||
.focused_bg = VALUE(config->window_focused_bg, config->bg),
|
||||
.focused_fg = VALUE(config->window_focused_fg, config->fg),
|
||||
};
|
||||
item->cell_padding = window_config.cell_padding;
|
||||
|
||||
item->api = bar_windows;
|
||||
|
||||
auto create_state = item->api.create_state;
|
||||
auto output_id = bar_output->output_id;
|
||||
if (create_state) item->state = create_state(output_id, &window_config);
|
||||
|
||||
bar_windows_add_listeners(listeners, item->state);
|
||||
}
|
||||
|
||||
void bar_init(bar_t *bar, listeners_t *listeners) {
|
||||
auto c = &bar->config;
|
||||
bar->ctx = text_context_create(c->font_family, c->font_size, c->dpi);
|
||||
@@ -113,6 +140,7 @@ void bar_init(bar_t *bar, listeners_t *listeners) {
|
||||
bar_output->height = bar->config.height;
|
||||
bar_output_add_workspace(bar_output, &bar->config, listeners);
|
||||
bar_output_add_binding(bar_output, &bar->config, listeners);
|
||||
bar_output_add_windows(bar_output, &bar->config, listeners);
|
||||
}
|
||||
|
||||
bar->timerfd = time_create_monotonic_timerfd_by_fps(bar->config.fps);
|
||||
@@ -233,6 +261,7 @@ static void bar_output_layout(bar_output_t *bar_output, text_context_t *ctx) {
|
||||
.start = start,
|
||||
.end = start + width + center->cell_padding * 2,
|
||||
};
|
||||
start = region.end;
|
||||
bar_cell_set_region(center, i, region);
|
||||
}
|
||||
}
|
||||
@@ -281,7 +310,7 @@ static void bar_item_draw(
|
||||
.width = cell_area.width - item->cell_padding * 2,
|
||||
.height = height,
|
||||
};
|
||||
if (text_area.width > 0) {
|
||||
if (text_area.width > 0 && cell->text && cell->text[0] != '\0') {
|
||||
draw_text(cr, ctx, cell->text, &cell->fg, text_area);
|
||||
}
|
||||
|
||||
@@ -317,8 +346,25 @@ static inline bool bar_output_is_dirty(bar_output_t *bar_output) {
|
||||
return false;
|
||||
}
|
||||
|
||||
static void bar_output_draw(bar_output_t *bar_output, text_context_t *ctx) {
|
||||
static inline void clean_cairo_context(cairo_t *cr) {
|
||||
cairo_save(cr);
|
||||
cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR);
|
||||
cairo_paint(cr);
|
||||
cairo_restore(cr);
|
||||
}
|
||||
|
||||
static void
|
||||
bar_output_draw(bar_output_t *bar_output, text_context_t *ctx, color_t *bg) {
|
||||
auto cr = bar_output->cr;
|
||||
clean_cairo_context(cr);
|
||||
|
||||
zdwm_rect_t output_area = {
|
||||
.x = 0,
|
||||
.y = 0,
|
||||
.width = bar_output->width,
|
||||
.height = bar_output->height,
|
||||
};
|
||||
draw_background(cr, bg, output_area);
|
||||
|
||||
auto left = &bar_output->left;
|
||||
for (size_t i = 0; i < left->count; ++i) {
|
||||
@@ -342,7 +388,7 @@ bool bar_draw(bar_t *bar) {
|
||||
if (!bar_output_is_dirty(bar_output)) continue;
|
||||
|
||||
bar_output_layout(bar_output, ctx);
|
||||
bar_output_draw(bar_output, ctx);
|
||||
bar_output_draw(bar_output, ctx, &bar->palette.bg);
|
||||
changed = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ static void bar_cell_set_count(zdwm_bar_item_t *item, size_t count) {
|
||||
|
||||
for (size_t i = 0; i < item->count; ++i) {
|
||||
auto cell = &item->cells[i];
|
||||
p_delete(cell->text);
|
||||
p_delete(&cell->text);
|
||||
p_delete(&cell->fg_text);
|
||||
p_delete(&cell->bg_text);
|
||||
}
|
||||
@@ -51,6 +51,7 @@ bar_cell_set_bg(zdwm_bar_item_t *item, size_t index, const char *color) {
|
||||
|
||||
if (cell->bg_text && strcmp(color, cell->bg_text) == 0) return;
|
||||
|
||||
p_delete(&cell->bg_text);
|
||||
cell->bg_text = p_strdup(color);
|
||||
color_parse(color, &cell->bg);
|
||||
|
||||
@@ -65,6 +66,7 @@ bar_cell_set_fg(zdwm_bar_item_t *item, size_t index, const char *color) {
|
||||
auto cell = &item->cells[index];
|
||||
if (cell->fg_text && strcmp(color, cell->fg_text) == 0) return;
|
||||
|
||||
p_delete(&cell->fg_text);
|
||||
cell->fg_text = p_strdup(color);
|
||||
color_parse(color, &cell->fg);
|
||||
|
||||
|
||||
175
src/bar/windows.c
Normal file
175
src/bar/windows.c
Normal file
@@ -0,0 +1,175 @@
|
||||
#include "bar/windows.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
#include <zdwm/bar.h>
|
||||
#include <zdwm/listeners.h>
|
||||
#include <zdwm/types.h>
|
||||
|
||||
#include "base/array.h"
|
||||
#include "base/memory.h"
|
||||
#include "core/listeners.h"
|
||||
|
||||
typedef struct bar_windows_state_t {
|
||||
zdwm_output_id_t output_id;
|
||||
zdwm_workspace_id_t workspace_id;
|
||||
|
||||
zdwm_window_t *windows;
|
||||
size_t count;
|
||||
size_t capacity;
|
||||
|
||||
bar_windows_config_t config;
|
||||
|
||||
bool workspace_inited;
|
||||
bool dirty;
|
||||
} bar_windows_state_t;
|
||||
|
||||
static zdwm_window_t *
|
||||
state_get_window(bar_windows_state_t *state, zdwm_window_id_t window_id) {
|
||||
for (size_t i = 0; i < state->count; ++i) {
|
||||
auto window = &state->windows[i];
|
||||
if (window->id == window_id) return window;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static void *
|
||||
bar_windows_create_state(zdwm_output_id_t output_id, void *config) {
|
||||
const bar_windows_config_t *windows_config = config;
|
||||
assert(windows_config);
|
||||
|
||||
auto state = p_new(bar_windows_state_t, 1);
|
||||
state->output_id = output_id;
|
||||
state->workspace_id = ZDWM_WORKSPACE_ID_INVALID;
|
||||
state->config = *windows_config;
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
static void bar_windows_update(
|
||||
zdwm_bar_item_t *item,
|
||||
const zdwm_bar_cell_api_t *cells,
|
||||
void *state
|
||||
) {
|
||||
bar_windows_state_t *data = state;
|
||||
if (!data->workspace_inited || !data->dirty) return;
|
||||
|
||||
zdwm_window_t *windows = nullptr;
|
||||
size_t count = 0, capacity = 0;
|
||||
for (size_t i = 0; i < data->count; ++i) {
|
||||
auto win = &data->windows[i];
|
||||
if (win->workspace != data->workspace_id || win->skip_taskbar) continue;
|
||||
|
||||
auto window = array_push(windows, count, capacity);
|
||||
*window = *win;
|
||||
}
|
||||
|
||||
cells->set_cell_count(item, count);
|
||||
for (size_t i = 0; i < count; ++i) {
|
||||
auto window = &windows[i];
|
||||
auto bg = window->focused ? data->config.focused_bg : data->config.bg;
|
||||
auto fg = window->focused ? data->config.focused_fg : data->config.fg;
|
||||
cells->cell_set_text(item, i, window->title);
|
||||
cells->cell_set_bg(item, i, bg);
|
||||
cells->cell_set_fg(item, i, fg);
|
||||
}
|
||||
p_delete(&windows);
|
||||
|
||||
data->dirty = false;
|
||||
}
|
||||
|
||||
static void bar_windows_destroy_state(void *state) {
|
||||
bar_windows_state_t *data = state;
|
||||
|
||||
p_delete(&data->windows);
|
||||
p_delete(&data);
|
||||
}
|
||||
|
||||
zdwm_bar_item_type_t bar_windows = {
|
||||
.create_state = bar_windows_create_state,
|
||||
.update = bar_windows_update,
|
||||
.destroy_state = bar_windows_destroy_state,
|
||||
.update_interval_ms = 0,
|
||||
};
|
||||
|
||||
static void bar_windows_workspace_active(
|
||||
zdwm_output_id_t output_id,
|
||||
zdwm_workspace_id_t workspace_id,
|
||||
void *user_data
|
||||
) {
|
||||
bar_windows_state_t *state = user_data;
|
||||
if (state->output_id != output_id) return;
|
||||
if (state->workspace_id == workspace_id) return;
|
||||
|
||||
state->workspace_id = workspace_id;
|
||||
|
||||
state->workspace_inited = true;
|
||||
state->dirty = true;
|
||||
}
|
||||
|
||||
static void
|
||||
bar_windows_add_window(const zdwm_window_t *window, void *user_data) {
|
||||
bar_windows_state_t *state = user_data;
|
||||
auto win = array_push(state->windows, state->count, state->capacity);
|
||||
*win = *window;
|
||||
|
||||
state->dirty = true;
|
||||
}
|
||||
|
||||
static void
|
||||
bar_windows_initial(const zdwm_window_t *list, size_t count, void *user_data) {
|
||||
bar_windows_state_t *state = user_data;
|
||||
|
||||
for (size_t i = 0; i < count; ++i) {
|
||||
auto window = &list[i];
|
||||
bar_windows_add_window(window, state);
|
||||
}
|
||||
|
||||
state->dirty = true;
|
||||
}
|
||||
|
||||
static void
|
||||
bar_windows_update_window(const zdwm_window_t *window, void *user_data) {
|
||||
bar_windows_state_t *state = user_data;
|
||||
|
||||
auto old_window = state_get_window(state, window->id);
|
||||
*old_window = *window;
|
||||
|
||||
state->dirty = true;
|
||||
}
|
||||
|
||||
static void
|
||||
bar_windows_remove_window(zdwm_window_id_t window_id, void *user_data) {
|
||||
bar_windows_state_t *state = user_data;
|
||||
|
||||
bool found = false;
|
||||
size_t index = 0;
|
||||
|
||||
for (size_t i = 0; i < state->count; ++i) {
|
||||
auto window = &state->windows[i];
|
||||
if (window->id == window_id) {
|
||||
found = true;
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) return;
|
||||
|
||||
if (array_erase(state->windows, state->count, index)) {
|
||||
state->dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
void bar_windows_add_listeners(listeners_t *listeners, void *state) {
|
||||
#define ADD(ADD_FN, LISTENER) ADD_FN(listeners, LISTENER, state)
|
||||
|
||||
ADD(listeners_add_active_workspace_listener, bar_windows_workspace_active);
|
||||
ADD(listeners_add_initial_window_listener, bar_windows_initial);
|
||||
ADD(listeners_add_window_added_listener, bar_windows_add_window);
|
||||
ADD(listeners_add_window_updated_listener, bar_windows_update_window);
|
||||
ADD(listeners_add_window_removed_listener, bar_windows_remove_window);
|
||||
|
||||
#undef ADD
|
||||
}
|
||||
18
src/bar/windows.h
Normal file
18
src/bar/windows.h
Normal file
@@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <zdwm/bar.h>
|
||||
|
||||
#include "core/listeners.h"
|
||||
|
||||
typedef struct bar_windows_config_t {
|
||||
uint32_t cell_padding;
|
||||
const char *bg;
|
||||
const char *fg;
|
||||
const char *focused_bg;
|
||||
const char *focused_fg;
|
||||
} bar_windows_config_t;
|
||||
|
||||
extern zdwm_bar_item_type_t bar_windows;
|
||||
|
||||
void bar_windows_add_listeners(listeners_t *listeners, void *state);
|
||||
@@ -276,6 +276,7 @@ void bar_workspace_window_removed(zdwm_window_id_t window_id, void *user_data) {
|
||||
if (window->id == window_id) {
|
||||
found = true;
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -178,6 +178,7 @@ bool config_defaults_build(
|
||||
.dpi = 144,
|
||||
|
||||
.bg = "#222222",
|
||||
.fg = "#bbbbbb",
|
||||
|
||||
.tag_cell_padding_x = 10,
|
||||
.tag_indicator_width = 4,
|
||||
@@ -194,6 +195,9 @@ bool config_defaults_build(
|
||||
.binding_padding_x = 2,
|
||||
.binding_mode_bg = "#900000",
|
||||
.binding_mode_fg = "#ffffff",
|
||||
|
||||
.window_focused_bg = "#005577",
|
||||
.window_focused_fg = "#eeeeee",
|
||||
};
|
||||
api->set_bar_config(builder, bar_config);
|
||||
|
||||
|
||||
@@ -21,6 +21,16 @@ backend_detect_t *backend_detect(backend_t *backend);
|
||||
void backend_detect_destroy(backend_detect_t *detect);
|
||||
|
||||
int backend_get_fd(backend_t *backend);
|
||||
|
||||
/**
|
||||
* @brief 非阻塞地从 backend 中读取下一个归一化的事件
|
||||
*
|
||||
* @details
|
||||
* 1. 函数立即返回
|
||||
* 2. 只要取到了事件,函数就返回 true ,事件填充到 event 参数中
|
||||
*
|
||||
* @returns 如果还有下一个事件待读取,返回 true ,否则返回 false
|
||||
*/
|
||||
bool backend_poll_event(backend_t *backend, event_t *event);
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include "core/window.h"
|
||||
|
||||
void event_cleanup(event_t *event) {
|
||||
if (!event) return;
|
||||
if (!event || event->type == ZDWM_EVENT_NONE) return;
|
||||
|
||||
switch (event->type) {
|
||||
case ZDWM_EVENT_WINDOW_MAP_REQUEST:
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "core/window.h"
|
||||
|
||||
typedef enum event_type_t {
|
||||
ZDWM_EVENT_NONE,
|
||||
ZDWM_EVENT_KEY_PRESS,
|
||||
ZDWM_EVENT_POINTER_BUTTON_PRESS,
|
||||
ZDWM_EVENT_POINTER_BUTTON_RELEASE,
|
||||
|
||||
@@ -558,9 +558,11 @@ static void route_window_remove(
|
||||
}
|
||||
|
||||
static void route_window_metadata_changed(
|
||||
state_t *state,
|
||||
const policy_context_t *ctx,
|
||||
const window_metadata_change_event_t *e
|
||||
) {
|
||||
auto state = ctx->state;
|
||||
|
||||
auto window = state_window_get(state, e->window);
|
||||
if (!window) return;
|
||||
|
||||
@@ -582,6 +584,7 @@ static void route_window_metadata_changed(
|
||||
if (e->changed_fields & ZDWM_WINDOW_METADATA_CHANGE_INSTANCE) {
|
||||
state_window_set_instance(state, window_id, metadata->instance_name);
|
||||
}
|
||||
listeners_notify_window_updated(ctx->listeners, state, window_id);
|
||||
}
|
||||
|
||||
static void route_window_activate_request(
|
||||
@@ -683,7 +686,7 @@ void policy_route_event(
|
||||
route_window_remove(state, &event->as.window_remove, out);
|
||||
break;
|
||||
case ZDWM_EVENT_WINDOW_METADATA_CHANGED:
|
||||
route_window_metadata_changed(state, &event->as.window_metadata_change);
|
||||
route_window_metadata_changed(ctx, &event->as.window_metadata_change);
|
||||
break;
|
||||
case ZDWM_EVENT_WINDOW_ACTIVATE_REQUEST: {
|
||||
auto data = &event->as.window_activate_request;
|
||||
@@ -857,8 +860,10 @@ unmanage_window(const policy_context_t *ctx, window_id_t window, plan_t *plan) {
|
||||
|
||||
if (output->current_workspace_id != workspace_id) return;
|
||||
|
||||
if (old_focused_window != workspace->focused_window_id) {
|
||||
plan_push_focus_effect(plan, workspace->focused_window_id);
|
||||
auto focused_window_id = workspace->focused_window_id;
|
||||
if (old_focused_window != focused_window_id) {
|
||||
plan_push_focus_effect(plan, focused_window_id);
|
||||
listeners_notify_window_updated(ctx->listeners, state, focused_window_id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -877,6 +882,7 @@ focus_window(const policy_context_t *ctx, window_id_t window, plan_t *plan) {
|
||||
|
||||
plan_push_focus_effect(plan, workspace->focused_window_id);
|
||||
listeners_notify_window_updated(ctx->listeners, state, window);
|
||||
listeners_notify_window_updated(ctx->listeners, state, old_focused_window);
|
||||
}
|
||||
|
||||
static void kill_window(state_t *state, window_id_t window, plan_t *plan) {
|
||||
|
||||
Reference in New Issue
Block a user