Compare commits
8 Commits
539563c53f
...
dee4073996
| Author | SHA1 | Date | |
|---|---|---|---|
|
dee4073996
|
|||
|
e8b59e914c
|
|||
|
ac65180203
|
|||
|
30e9751119
|
|||
|
41f82d7039
|
|||
|
d0127f66e4
|
|||
|
4cef809f3c
|
|||
|
d97cfba8dd
|
@@ -30,6 +30,7 @@ add_executable(${APP_NAME}
|
||||
${SOURCE_DIR}/backend/x11/window.c
|
||||
|
||||
${SOURCE_DIR}/bar/bar.c
|
||||
${SOURCE_DIR}/bar/binding.c
|
||||
${SOURCE_DIR}/bar/cell.c
|
||||
${SOURCE_DIR}/bar/text.c
|
||||
${SOURCE_DIR}/bar/workspaces.c
|
||||
@@ -37,6 +38,7 @@ add_executable(${APP_NAME}
|
||||
${SOURCE_DIR}/base/color.c
|
||||
${SOURCE_DIR}/base/log.c
|
||||
${SOURCE_DIR}/base/process.c
|
||||
${SOURCE_DIR}/base/time.c
|
||||
${SOURCE_DIR}/base/window_list.c
|
||||
|
||||
${SOURCE_DIR}/config/defaults.c
|
||||
|
||||
@@ -33,8 +33,12 @@ typedef struct zdwm_bar_config_t {
|
||||
|
||||
const char *layout_bg;
|
||||
const char *layout_fg;
|
||||
|
||||
bool binding_show_default;
|
||||
uint32_t binding_padding_x;
|
||||
const char *binding_mode_bg;
|
||||
const char *binding_mode_fg;
|
||||
|
||||
const char *window_bg;
|
||||
const char *window_fg;
|
||||
const char *window_focused_bg;
|
||||
|
||||
@@ -1,16 +1,14 @@
|
||||
#include "bar/bar.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <bits/time.h>
|
||||
#include <bits/types/struct_itimerspec.h>
|
||||
#include <cairo.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/timerfd.h>
|
||||
#include <unistd.h>
|
||||
#include <zdwm/bar.h>
|
||||
#include <zdwm/types.h>
|
||||
|
||||
#include "bar/binding.h"
|
||||
#include "bar/cell.h"
|
||||
#include "bar/text.h"
|
||||
#include "bar/types.h"
|
||||
@@ -18,6 +16,7 @@
|
||||
#include "base/array.h"
|
||||
#include "base/macros.h"
|
||||
#include "base/memory.h"
|
||||
#include "base/time.h"
|
||||
#include "core/listeners.h"
|
||||
|
||||
static zdwm_bar_item_t *bar_add_item(
|
||||
@@ -65,6 +64,8 @@ void bar_output_add_workspace(
|
||||
.active_fg = config->tag_active_fg,
|
||||
.urgent_bg = config->tag_urgent_bg,
|
||||
.urgent_fg = config->tag_urgent_fg,
|
||||
.layout_bg = VALUE(config->layout_bg, config->bg),
|
||||
.layout_fg = VALUE(config->layout_fg, config->fg),
|
||||
};
|
||||
auto item = bar_add_item(
|
||||
bar_output->output_id,
|
||||
@@ -78,6 +79,28 @@ void bar_output_add_workspace(
|
||||
bar_workspace_add_listeners(listeners, item->state);
|
||||
}
|
||||
|
||||
static void bar_output_add_binding(
|
||||
bar_output_t *bar_output,
|
||||
zdwm_bar_config_t *config,
|
||||
listeners_t *listeners
|
||||
) {
|
||||
bar_binding_config_t binding_config = {
|
||||
.show_default = config->binding_show_default,
|
||||
.cell_padding = VALUE(config->binding_padding_x, config->padding_x),
|
||||
.bg = VALUE(config->binding_mode_bg, config->bg),
|
||||
.fg = VALUE(config->binding_mode_fg, config->fg),
|
||||
};
|
||||
auto item = bar_add_item(
|
||||
bar_output->output_id,
|
||||
&bar_output->left,
|
||||
bar_binding,
|
||||
&binding_config
|
||||
);
|
||||
item->cell_padding = binding_config.cell_padding;
|
||||
|
||||
bar_binding_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);
|
||||
@@ -87,23 +110,10 @@ 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->timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC);
|
||||
auto interval_ns = 1'000'000'000ULL / bar->config.fps;
|
||||
|
||||
struct itimerspec timer_spec = {
|
||||
.it_interval =
|
||||
{
|
||||
.tv_sec = interval_ns / 1'000'000'000,
|
||||
.tv_nsec = interval_ns % 1'000'000'000,
|
||||
},
|
||||
.it_value = {
|
||||
.tv_sec = 0,
|
||||
.tv_nsec = interval_ns % 1'000'000'000,
|
||||
},
|
||||
};
|
||||
timerfd_settime(bar->timerfd, 0, &timer_spec, nullptr);
|
||||
bar->timerfd = time_create_monotonic_timerfd_by_fps(bar->config.fps);
|
||||
}
|
||||
|
||||
static void bar_side_cleanup(bar_side_t *side) {
|
||||
@@ -137,7 +147,15 @@ void bar_cleanup(bar_t *bar) {
|
||||
|
||||
static inline void bar_item_update(zdwm_bar_item_t *item) {
|
||||
auto update = item->api.update;
|
||||
if (update) update(item, &bar_cell_api, item->state);
|
||||
if (!update) return;
|
||||
|
||||
auto update_interval_ms = item->api.update_interval_ms;
|
||||
auto last_updated_time = item->last_updated_time;
|
||||
auto now = time_monotonic_ms();
|
||||
if (now < last_updated_time + update_interval_ms) return;
|
||||
|
||||
item->last_updated_time = now;
|
||||
update(item, &bar_cell_api, item->state);
|
||||
}
|
||||
|
||||
static inline void bar_side_update(bar_side_t *side) {
|
||||
@@ -300,8 +318,6 @@ static inline bool bar_output_is_dirty(bar_output_t *bar_output) {
|
||||
}
|
||||
|
||||
static void bar_output_draw(bar_output_t *bar_output, text_context_t *ctx) {
|
||||
if (!bar_output_is_dirty(bar_output)) return;
|
||||
|
||||
auto cr = bar_output->cr;
|
||||
|
||||
auto left = &bar_output->left;
|
||||
@@ -316,12 +332,19 @@ static void bar_output_draw(bar_output_t *bar_output, text_context_t *ctx) {
|
||||
bar_item_draw(cr, &bar_output->center, ctx, bar_output->height);
|
||||
}
|
||||
|
||||
void bar_draw(bar_t *bar) {
|
||||
bool bar_draw(bar_t *bar) {
|
||||
auto ctx = bar->ctx;
|
||||
|
||||
bool changed = false;
|
||||
|
||||
for (size_t i = 0; i < bar->count; ++i) {
|
||||
auto bar_output = &bar->bars[i];
|
||||
if (!bar_output_is_dirty(bar_output)) continue;
|
||||
|
||||
bar_output_layout(bar_output, ctx);
|
||||
bar_output_draw(bar_output, ctx);
|
||||
changed = true;
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
@@ -41,4 +41,4 @@ typedef struct bar_t {
|
||||
void bar_init(bar_t *bar, listeners_t *listeners);
|
||||
void bar_cleanup(bar_t *bar);
|
||||
void bar_update(bar_t *bar);
|
||||
void bar_draw(bar_t *bar);
|
||||
bool bar_draw(bar_t *bar);
|
||||
|
||||
104
src/bar/binding.c
Normal file
104
src/bar/binding.c
Normal file
@@ -0,0 +1,104 @@
|
||||
#include "bar/binding.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <zdwm/action.h>
|
||||
#include <zdwm/bar.h>
|
||||
#include <zdwm/listeners.h>
|
||||
#include <zdwm/types.h>
|
||||
|
||||
#include "base/memory.h"
|
||||
#include "core/listeners.h"
|
||||
|
||||
typedef struct bar_binding_state_t {
|
||||
zdwm_binding_mode_notify_t mode;
|
||||
|
||||
bar_binding_config_t config;
|
||||
|
||||
bool inited;
|
||||
bool dirty;
|
||||
} bar_binding_state_t;
|
||||
|
||||
static void *
|
||||
bar_binding_create_state(zdwm_output_id_t output_id, void *config) {
|
||||
const bar_binding_config_t *bar_config = config;
|
||||
assert(bar_config);
|
||||
|
||||
auto state = p_new(bar_binding_state_t, 1);
|
||||
state->config = *bar_config;
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
static void bar_binding_update(
|
||||
zdwm_bar_item_t *item,
|
||||
const zdwm_bar_cell_api_t *cells,
|
||||
void *state
|
||||
) {
|
||||
auto data = (bar_binding_state_t *)state;
|
||||
if (!data->inited || !data->dirty) return;
|
||||
|
||||
auto config = &data->config;
|
||||
auto mode = &data->mode;
|
||||
|
||||
if (!config->show_default && mode->is_default_mode) {
|
||||
cells->set_cell_count(item, 0);
|
||||
} else {
|
||||
constexpr auto index = 0;
|
||||
cells->set_cell_count(item, 1);
|
||||
cells->cell_set_text(item, index, mode->name);
|
||||
cells->cell_set_bg(item, index, config->bg);
|
||||
cells->cell_set_fg(item, index, config->fg);
|
||||
}
|
||||
|
||||
data->dirty = false;
|
||||
}
|
||||
|
||||
static zdwm_action_t bar_binding_on_click(
|
||||
zdwm_bar_item_t *item,
|
||||
size_t cell_index,
|
||||
int32_t x,
|
||||
void *state
|
||||
) {
|
||||
return (zdwm_action_t){
|
||||
.type = ZDWM_ACTION_BINDING_MODE_CYCLE,
|
||||
.as.binding_mode_cycle = {.delta = 1},
|
||||
};
|
||||
}
|
||||
|
||||
static void bar_binding_destroy_state(void *state) {
|
||||
if (!state) return;
|
||||
|
||||
auto data = (bar_binding_state_t *)state;
|
||||
p_delete(&data);
|
||||
}
|
||||
|
||||
zdwm_bar_item_type_t bar_binding = {
|
||||
.create_state = bar_binding_create_state,
|
||||
.update = bar_binding_update,
|
||||
.on_click = bar_binding_on_click,
|
||||
.destroy_state = bar_binding_destroy_state,
|
||||
.update_interval_ms = 0,
|
||||
};
|
||||
|
||||
static void
|
||||
bar_binding_mode_notify(zdwm_binding_mode_notify_t mode, void *user_data) {
|
||||
auto state = (bar_binding_state_t *)user_data;
|
||||
if (!state->inited) {
|
||||
state->mode = mode;
|
||||
|
||||
state->inited = true;
|
||||
state->dirty = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (state->mode.id == mode.id) return;
|
||||
state->mode = mode;
|
||||
|
||||
state->dirty = true;
|
||||
}
|
||||
|
||||
void bar_binding_add_listeners(listeners_t *listeners, void *state) {
|
||||
listeners_add_binding_mode_notify(listeners, bar_binding_mode_notify, state);
|
||||
}
|
||||
17
src/bar/binding.h
Normal file
17
src/bar/binding.h
Normal file
@@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <zdwm/bar.h>
|
||||
|
||||
#include "core/listeners.h"
|
||||
|
||||
typedef struct bar_binding_config_t {
|
||||
bool show_default;
|
||||
uint32_t cell_padding;
|
||||
const char *bg;
|
||||
const char *fg;
|
||||
} bar_binding_config_t;
|
||||
|
||||
extern zdwm_bar_item_type_t bar_binding;
|
||||
|
||||
void bar_binding_add_listeners(listeners_t *listeners, void *state);
|
||||
@@ -32,6 +32,7 @@ struct zdwm_bar_item_t {
|
||||
void *state;
|
||||
zdwm_bar_item_type_t api;
|
||||
bool dirty;
|
||||
uint64_t last_updated_time;
|
||||
};
|
||||
|
||||
typedef struct bar_side_t {
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
typedef struct bar_workspace_t {
|
||||
zdwm_workspace_t info;
|
||||
zdwm_layout_notify_t layout;
|
||||
size_t window_count;
|
||||
size_t urgent_window_count;
|
||||
} bar_workspace_t;
|
||||
@@ -101,9 +102,9 @@ static void bar_workspaces_update(
|
||||
auto data = (bar_workspace_state_t *)state;
|
||||
if (!data->list_inited || !data->active_inited || !data->dirty) return;
|
||||
|
||||
if (data->count != cell_api->get_cell_count(item)) {
|
||||
cell_api->set_cell_count(item, data->count);
|
||||
}
|
||||
/* 当前 workspace 的 layout 指示器放在最后 */
|
||||
cell_api->set_cell_count(item, data->count + 1);
|
||||
auto layout_index = data->count;
|
||||
|
||||
auto config = &data->config;
|
||||
for (size_t i = 0; i < data->count; ++i) {
|
||||
@@ -121,6 +122,11 @@ static void bar_workspaces_update(
|
||||
if (info->id == data->workspace_id) {
|
||||
cell_api->cell_set_bg(item, i, config->active_bg);
|
||||
cell_api->cell_set_fg(item, i, config->active_fg);
|
||||
|
||||
cell_api->cell_set_bg(item, layout_index, config->layout_bg);
|
||||
cell_api->cell_set_fg(item, layout_index, config->layout_fg);
|
||||
cell_api->cell_set_text(item, layout_index, workspace->layout.symbol);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -161,6 +167,7 @@ static void bar_workspace_destroy_state(void *state) {
|
||||
|
||||
auto data = (bar_workspace_state_t *)state;
|
||||
p_delete(&data->workspaces);
|
||||
p_delete(&data->windows);
|
||||
p_delete(&data);
|
||||
}
|
||||
|
||||
@@ -212,6 +219,20 @@ static void bar_workspace_active_updated(
|
||||
state->dirty = true;
|
||||
}
|
||||
|
||||
static void
|
||||
bar_workspace_layout_notify(zdwm_layout_notify_t layout, void *user_data) {
|
||||
auto state = (bar_workspace_state_t *)user_data;
|
||||
|
||||
for (size_t i = 0; i < state->count; ++i) {
|
||||
auto workspace = &state->workspaces[i];
|
||||
if (workspace->info.id == layout.workspace) {
|
||||
workspace->layout = layout;
|
||||
state->dirty = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void bar_workspace_window_added(const zdwm_window_t *window, void *user_data) {
|
||||
auto state = (bar_workspace_state_t *)user_data;
|
||||
|
||||
@@ -270,6 +291,7 @@ void bar_workspace_add_listeners(listeners_t *listeners, void *state) {
|
||||
|
||||
ADD(listeners_add_initial_workspace_listener, bar_workspace_list_filter);
|
||||
ADD(listeners_add_active_workspace_listener, bar_workspace_active_updated);
|
||||
ADD(listeners_add_layout_notify, bar_workspace_layout_notify);
|
||||
ADD(listeners_add_initial_window_listener, bar_workspace_initial_windows);
|
||||
ADD(listeners_add_window_added_listener, bar_workspace_window_added);
|
||||
ADD(listeners_add_window_updated_listener, bar_workspace_window_updated);
|
||||
|
||||
@@ -14,6 +14,8 @@ typedef struct bar_workspace_config_t {
|
||||
const char *active_fg;
|
||||
const char *urgent_bg;
|
||||
const char *urgent_fg;
|
||||
const char *layout_bg;
|
||||
const char *layout_fg;
|
||||
} bar_workspace_config_t;
|
||||
|
||||
extern zdwm_bar_item_type_t bar_workspace;
|
||||
|
||||
56
src/base/time.c
Normal file
56
src/base/time.c
Normal file
@@ -0,0 +1,56 @@
|
||||
#include "base/time.h"
|
||||
|
||||
#include <bits/time.h>
|
||||
#include <bits/types/struct_itimerspec.h>
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <sys/timerfd.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "base/log.h"
|
||||
|
||||
static int time_create_monotonic_timerfd(const struct itimerspec *itimerspec) {
|
||||
auto timerfd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC);
|
||||
if (timerfd == -1) {
|
||||
auto err = errno;
|
||||
warn("time_create_timerfd failed: %s", strerror(err));
|
||||
return timerfd;
|
||||
}
|
||||
|
||||
timerfd_settime(timerfd, 0, itimerspec, nullptr);
|
||||
return timerfd;
|
||||
}
|
||||
|
||||
static constexpr auto NANOSECONDS_OF_ONE_SECOND = 1'000'000'000ULL;
|
||||
|
||||
int time_create_monotonic_timerfd_by_fps(uint32_t fps) {
|
||||
if (fps == 0) fps = 30;
|
||||
|
||||
auto interval_ns = NANOSECONDS_OF_ONE_SECOND / fps;
|
||||
|
||||
/* clang-format off */
|
||||
struct itimerspec timer_spec = {
|
||||
.it_value = {
|
||||
.tv_sec = 0,
|
||||
.tv_nsec = interval_ns % NANOSECONDS_OF_ONE_SECOND,
|
||||
},
|
||||
.it_interval = {
|
||||
.tv_sec = interval_ns / NANOSECONDS_OF_ONE_SECOND,
|
||||
.tv_nsec = interval_ns % NANOSECONDS_OF_ONE_SECOND,
|
||||
},
|
||||
};
|
||||
/* clang-format on */
|
||||
|
||||
return time_create_monotonic_timerfd(&timer_spec);
|
||||
}
|
||||
|
||||
static uint64_t time_monotonic_ns(void) {
|
||||
struct timespec timestamp = {0};
|
||||
if (clock_gettime(CLOCK_MONOTONIC, ×tamp) == -1) {
|
||||
warn("clock_gettime failed: %s", strerror(errno));
|
||||
}
|
||||
return timestamp.tv_sec * NANOSECONDS_OF_ONE_SECOND + timestamp.tv_nsec;
|
||||
}
|
||||
|
||||
uint64_t time_monotonic_ms(void) { return time_monotonic_ns() / 1'000'000U; }
|
||||
6
src/base/time.h
Normal file
6
src/base/time.h
Normal file
@@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
int time_create_monotonic_timerfd_by_fps(uint32_t fps);
|
||||
uint64_t time_monotonic_ms(void);
|
||||
@@ -187,6 +187,13 @@ bool config_defaults_build(
|
||||
.tag_active_fg = "#eeeeee",
|
||||
.tag_urgent_bg = "#222222",
|
||||
.tag_urgent_fg = "#ff0000",
|
||||
.layout_bg = "#222222",
|
||||
.layout_fg = "#bbbbbb",
|
||||
|
||||
.binding_show_default = true,
|
||||
.binding_padding_x = 2,
|
||||
.binding_mode_bg = "#900000",
|
||||
.binding_mode_fg = "#ffffff",
|
||||
};
|
||||
api->set_bar_config(builder, bar_config);
|
||||
|
||||
|
||||
@@ -772,6 +772,7 @@ static void manage_window(
|
||||
state_window_set_floating(state, window_id, command->floating);
|
||||
set_foucs_window(ctx, workspace_id, window_id, plan);
|
||||
push_window_list_effect(state, plan);
|
||||
listeners_notify_window_added(ctx->listeners, state, window_id);
|
||||
|
||||
auto need_layout = window_need_layout(window);
|
||||
if (need_layout) {
|
||||
@@ -847,6 +848,7 @@ unmanage_window(const policy_context_t *ctx, window_id_t window, plan_t *plan) {
|
||||
state_window_remove(state, window);
|
||||
|
||||
push_window_list_effect(state, plan);
|
||||
listeners_notify_window_removed(ctx->listeners, window);
|
||||
|
||||
if (need_layout) {
|
||||
adjust_layout_windows_border_width(state, ctx->border->width, workspace_id);
|
||||
@@ -874,6 +876,7 @@ focus_window(const policy_context_t *ctx, window_id_t window, plan_t *plan) {
|
||||
if (old_focused_window == workspace->focused_window_id) return;
|
||||
|
||||
plan_push_focus_effect(plan, workspace->focused_window_id);
|
||||
listeners_notify_window_updated(ctx->listeners, state, window);
|
||||
}
|
||||
|
||||
static void kill_window(state_t *state, window_id_t window, plan_t *plan) {
|
||||
@@ -903,11 +906,15 @@ static void raise_window(state_t *state, window_id_t window, plan_t *plan) {
|
||||
plan_push_effect(plan, &restack_windows_effect);
|
||||
}
|
||||
|
||||
static void withdraw_window(state_t *state, window_id_t window, plan_t *plan) {
|
||||
static void
|
||||
withdraw_window(const policy_context_t *ctx, window_id_t window, plan_t *plan) {
|
||||
auto state = ctx->state;
|
||||
|
||||
auto win = state_window_get(state, window);
|
||||
if (!win) return;
|
||||
|
||||
plan_push_withdraw_effect(plan, window);
|
||||
listeners_notify_window_removed(ctx->listeners, window);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1183,6 +1190,8 @@ static void change_window_state(
|
||||
state_window_set_fixed_size(state, window->id, value);
|
||||
break;
|
||||
}
|
||||
|
||||
listeners_notify_window_updated(ctx->listeners, state, command->window);
|
||||
}
|
||||
|
||||
static void send_window_to_workspace(
|
||||
@@ -1449,7 +1458,7 @@ void policy_apply_command(
|
||||
raise_window(state, cmd->as.raise.window, plan);
|
||||
break;
|
||||
case ZDWM_COMMAND_WITHDRAW_WINDOW:
|
||||
withdraw_window(state, cmd->as.withdraw.window, plan);
|
||||
withdraw_window(ctx, cmd->as.withdraw.window, plan);
|
||||
break;
|
||||
case ZDWM_COMMAND_CONFIGURE_WINDOW:
|
||||
configure_window(state, &cmd->as.configure, plan);
|
||||
|
||||
@@ -484,9 +484,10 @@ static void runtime_handle_event(runtime_t *runtime, short int revents) {
|
||||
|
||||
static inline void runtime_update_bar(runtime_t *runtime) {
|
||||
auto bar = &runtime->bar;
|
||||
if (!bar->visible) return;
|
||||
|
||||
bar_update(bar);
|
||||
bar_draw(bar);
|
||||
backend_flush(runtime->backend);
|
||||
if (bar_draw(bar)) backend_flush(runtime->backend);
|
||||
}
|
||||
|
||||
static void runtime_run_event_loop(runtime_t *runtime) {
|
||||
|
||||
Reference in New Issue
Block a user