Merge pull request #1079 from mangowm/group

mango 0.15.0
This commit is contained in:
DreamMaoMao 2026-07-08 12:40:14 +08:00 committed by GitHub
commit 621ea37a24
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
48 changed files with 2500 additions and 4052 deletions

View file

@ -46,8 +46,8 @@ static void finish_exchange_arrange_and_focus(Client *c1, Client *c2,
} else {
arrange(c1->mon, false, false);
}
wl_list_remove(&c2->flink);
wl_list_insert(&c1->flink, &c2->flink);
wl_list_safe_reinsert_next(&c1->flink, &c2->flink);
if (config.warpcursor)
warp_cursor(c1);
@ -57,7 +57,14 @@ void client_tile_resize(Client *c, struct wlr_box geo, int32_t interact) {
if (!ISFAKETILED(c))
return;
if (!c->isfullscreen && !c->ismaximizescreen) {
if (!c->mon->isoverview && !c->isfullscreen &&
(c->group_next || c->group_prev)) {
geo.y = geo.y + config.group_bar_height;
geo.height -= config.group_bar_height;
}
if ((!c->isfullscreen && !c->ismaximizescreen) ||
is_scroller_layout(c->mon)) {
resize(c, geo, interact);
}
}
@ -73,7 +80,7 @@ void client_active(Client *c) {
return;
}
if (c->swallowing || !c->mon)
if (c->swallowdby || !c->mon)
return;
if (c->isminimized) {
@ -104,19 +111,199 @@ void client_add_jump_label_node(Client *c) {
wlr_scene_node_set_enabled(&c->jump_label_node->scene_buffer->node, false);
}
void client_add_tab_bar_node(Client *c) {
void client_add_group_bar(Client *c) {
if (config.tab_bar_height <= 0) {
if (config.group_bar_height <= 0) {
return;
}
MangoNodeData *mangonodedata = ecalloc(1, sizeof(MangoNodeData));
mangonodedata->node_data = c;
mangonodedata->type = MANGO_TITLE_NODE;
uint32_t layer = c->isoverlay ? LyrOverlay
: c->isfloating || c->isfullscreen ? LyrTop
: c->ismaximizescreen ? LyrMaximize
: LyrTile;
c->tab_bar_node = mango_tab_bar_node_create(
mangonodedata, layers[LyrDecorate], config.tabdata, 0, 0);
wlr_scene_node_lower_to_bottom(&c->tab_bar_node->scene_buffer->node);
wlr_scene_node_set_enabled(&c->tab_bar_node->scene_buffer->node, false);
mango_tab_bar_node_update(c->tab_bar_node, client_get_title(c), 1.0);
c->group_bar = mango_group_bar_create(c, GroupBar, layers[layer],
config.groupbardata, 0, 0);
wlr_scene_node_lower_to_bottom(&c->group_bar->scene_buffer->node);
wlr_scene_node_set_enabled(&c->group_bar->scene_buffer->node, false);
mango_group_bar_update(c->group_bar, client_get_title(c),
c->mon ? c->mon->wlr_output->scale
: selmon ? selmon->wlr_output->scale
: 1.0f);
}
void client_focus_group_member(Client *c) {
if (!c->group_prev && !c->group_next)
return;
if (c->isgroupfocusing)
return;
Client *head = c;
while (head->group_prev)
head = head->group_prev;
Client *cur_focusing = NULL;
while (head) {
if (head->isgroupfocusing) {
cur_focusing = head;
break;
}
head = head->group_next;
}
if (!cur_focusing || !cur_focusing->mon)
return;
if (cur_focusing && cur_focusing->mon->isoverview)
return;
cur_focusing->isgroupfocusing = false;
c->mon = cur_focusing->mon;
client_replace(c, cur_focusing, true, false);
mango_group_bar_set_focus(cur_focusing->group_bar, false);
c->isgroupfocusing = true;
mango_group_bar_set_focus(c->group_bar, true);
client_reparent_group(c);
focusclient(c, 1);
arrange(c->mon, false, false);
}
void client_check_tab_node_visible(Client *c) {
if (!c || !c->mon)
return;
Client *head = c;
while (head->group_prev)
head = head->group_prev;
Client *cur = head;
while (cur) {
if (!c->mon->isoverview && cur->group_bar &&
(cur->group_next || cur->group_prev) && TAGMATCH(c, c->mon) &&
ISNORMAL(c) && !c->isfullscreen) {
wlr_scene_node_set_enabled(&cur->group_bar->scene_buffer->node,
true);
} else {
wlr_scene_node_set_enabled(&cur->group_bar->scene_buffer->node,
false);
}
cur = cur->group_next;
}
}
void client_raise_group(Client *c) {
if (!c || !c->mon)
return;
Client *head = c;
while (head->group_prev)
head = head->group_prev;
Client *cur = head;
while (cur) {
if (cur->group_bar) {
wlr_scene_node_raise_to_top(&cur->group_bar->scene_buffer->node);
}
wlr_scene_node_raise_to_top(&cur->scene->node);
cur = cur->group_next;
}
}
void client_reparent_group(Client *c) {
if (!c || !c->mon)
return;
int32_t layer = c->isoverlay ? LyrOverlay
: c->isfloating || c->isfullscreen ? LyrTop
: c->ismaximizescreen ? LyrMaximize
: LyrTile;
Client *head = c;
while (head->group_prev)
head = head->group_prev;
Client *cur = head;
while (cur) {
if (cur->group_bar) {
wlr_scene_node_reparent(&cur->group_bar->scene_buffer->node,
layers[layer]);
}
wlr_scene_node_reparent(&cur->scene->node, layers[layer]);
cur = cur->group_next;
}
}
void client_handle_decorate_click(MangoGroupBar *gb) {
if (!gb)
return;
if (gb->node_data) {
Client *c = gb->node_data;
client_focus_group_member(c);
}
}
void client_set_group_mon(Client *c, Monitor *m) {
Client *head = c;
while (head->group_prev)
head = head->group_prev;
Client *cur = head;
while (cur) {
client_change_mon(cur, m);
cur = cur->group_next;
}
}
void client_set_group_config(Client *c) {
Client *head = c;
while (head->group_prev)
head = head->group_prev;
Client *cur = head;
while (cur) {
mango_jump_label_node_apply_config(cur->jump_label_node,
&config.jumplabeldata);
wlr_scene_rect_set_color(cur->droparea, config.dropcolor);
wlr_scene_rect_set_color(cur->splitindicator[0], config.splitcolor);
wlr_scene_rect_set_color(cur->splitindicator[1], config.splitcolor);
mango_group_bar_apply_config(cur->group_bar, &config.groupbardata);
cur = cur->group_next;
}
}
void client_group_detach(Client *c) {
if (c->group_prev)
c->group_prev->group_next = c->group_next;
if (c->group_next)
c->group_next->group_prev = c->group_prev;
c->group_prev = NULL;
c->group_next = NULL;
c->isgroupfocusing = false;
}
void client_group_replace(Client *old, Client *new) {
client_group_detach(new);
new->group_prev = old->group_prev;
new->group_next = old->group_next;
if (old->group_prev)
old->group_prev->group_next = new;
if (old->group_next)
old->group_next->group_prev = new;
old->group_prev = NULL;
old->group_next = NULL;
if (old->is_logic_hide || (!new->group_prev && !new->group_next)) {
new->isgroupfocusing = false;
} else {
new->isgroupfocusing = old->isgroupfocusing;
}
}

61
src/action/monitor.h Normal file
View file

@ -0,0 +1,61 @@
bool mango_scene_output_commit(struct wlr_scene_output *scene_output,
struct wlr_output_state *state) {
struct wlr_output *wlr_output = scene_output->output;
Monitor *m = wlr_output->data;
bool committed = false;
bool frame_allow_tearing = check_tearing_frame_allow(m);
if (!wlr_scene_output_needs_frame(scene_output))
return true;
// 构建状态,将场景的 Buffer 附着到 state 上
if (!wlr_scene_output_build_state(scene_output, state, NULL))
return false;
if (frame_allow_tearing) {
state->tearing_page_flip = true;
} else {
state->tearing_page_flip = false;
}
// 测试是否支持撕裂
if (state->tearing_page_flip == true) {
if (!wlr_output_test_state(wlr_output, state)) {
// 如果 DRM 拒绝(例如当前输出/驱动不支持撕裂),降级关闭撕裂
state->tearing_page_flip = false;
}
}
// 提交状态
committed = wlr_output_commit_state(wlr_output, state);
if (!committed && state->tearing_page_flip) {
// 重试一次
state->tearing_page_flip = false;
committed = wlr_output_commit_state(wlr_output, state);
}
if (committed) {
if (state == &m->pending) {
wlr_output_state_finish(&m->pending);
wlr_output_state_init(&m->pending);
}
} else {
wlr_log(WLR_INFO, "Failed to commit output %s", m->wlr_output->name);
return false;
}
return committed;
}
bool mango_output_commit(Monitor *m) {
bool committed = wlr_output_commit_state(m->wlr_output, &m->pending);
if (committed) {
wlr_output_state_finish(&m->pending);
wlr_output_state_init(&m->pending);
} else {
wlr_log(WLR_ERROR, "Failed to commit frame");
}
return committed;
}

File diff suppressed because it is too large Load diff

View file

@ -30,7 +30,7 @@ struct dvec2 calculate_animation_curve_at(double t, int32_t type) {
void handle_snapshot_meta_destroy(struct wl_listener *listener, void *data) {
SnapshotMetadata *meta = wl_container_of(listener, meta, destroy);
wl_list_remove(&meta->destroy.link); // 安全移除监听器
wl_list_remove(&meta->destroy.link);
free(meta);
}
@ -175,6 +175,7 @@ static bool scene_node_snapshot(struct wlr_scene_node *node, int32_t lx,
}
meta->orig_width = scene_buffer->dst_width;
meta->orig_height = scene_buffer->dst_height;
meta->type = Snapshot;
struct wlr_scene_surface *scene_surface =
wlr_scene_surface_try_from_buffer(scene_buffer);
@ -212,11 +213,8 @@ static bool scene_node_snapshot(struct wlr_scene_node *node, int32_t lx,
// Effects
wlr_scene_buffer_set_opacity(snapshot_buffer, scene_buffer->opacity);
wlr_scene_buffer_set_corner_radius(snapshot_buffer,
scene_buffer->corner_radius,
scene_buffer->corners);
wlr_scene_buffer_set_backdrop_blur(snapshot_buffer, false);
wlr_scene_buffer_set_corner_radii(snapshot_buffer,
scene_buffer->corners);
if (scene_surface != NULL && scene_surface->surface->buffer != NULL) {
wlr_scene_buffer_set_buffer(snapshot_buffer,
@ -248,6 +246,8 @@ static bool scene_node_snapshot(struct wlr_scene_node *node, int32_t lx,
break;
}
case WLR_SCENE_NODE_BLUR:
break;
case WLR_SCENE_NODE_OPTIMIZED_BLUR:
return true;
}

View file

@ -1,13 +1,11 @@
void layer_actual_size(LayerSurface *l, int32_t *width, int32_t *height) {
struct wlr_box box;
if (l->animation.running) {
*width = l->animation.current.width;
*height = l->animation.current.height;
} else {
get_layer_target_geometry(l, &box);
*width = box.width;
*height = box.height;
*width = l->geom.width;
*height = l->geom.height;
}
}
@ -151,6 +149,34 @@ void set_layer_dir_animaiton(LayerSurface *l, struct wlr_box *geo) {
}
}
void layer_draw_shield(LayerSurface *l) {
int32_t width, height;
if (!l->mapped)
return;
if (active_capture_count > 0 && l->shield_when_capture) {
layer_actual_size(l, &width, &height);
if (width <= 0 || height <= 0) {
wlr_scene_node_set_enabled(&l->shield->node, false);
return;
}
wlr_scene_node_raise_to_top(&l->shield->node);
wlr_scene_node_set_position(&l->shield->node, 0, 0);
wlr_scene_rect_set_size(l->shield, width, height);
wlr_scene_node_set_enabled(&l->shield->node, true);
} else {
if (l->shield->node.enabled) {
wlr_scene_node_lower_to_bottom(&l->shield->node);
wlr_scene_node_set_position(&l->shield->node, 0, 0);
wlr_scene_node_set_enabled(&l->shield->node, false);
}
}
}
void layer_draw_shadow(LayerSurface *l) {
if (!l->mapped || !l->shadow)
@ -187,8 +213,7 @@ void layer_draw_shadow(LayerSurface *l) {
struct clipped_region clipped_region = {
.area = intersection_box,
.corner_radius = config.border_radius,
.corners = config.border_radius_location_default,
.corners = corner_radii_all(config.border_radius),
};
wlr_scene_node_set_position(&l->shadow->node, shadow_box.x, shadow_box.y);
@ -328,9 +353,14 @@ void layer_animation_next_tick(LayerSurface *l) {
(1.0 - config.fadein_begin_opacity),
1.0f);
if (config.animation_fade_in)
if (config.animation_fade_in) {
if (config.blur && !l->noblur && !config.blur_optimized) {
wlr_scene_blur_set_strength(l->blur, opacity);
wlr_scene_blur_set_alpha(l->blur, opacity);
}
wlr_scene_node_for_each_buffer(&l->scene->node,
scene_buffer_apply_opacity, &opacity);
}
wlr_scene_node_set_position(&l->scene->node, x, y);
@ -358,6 +388,10 @@ void layer_animation_next_tick(LayerSurface *l) {
.height = height,
};
if (config.blur && config.blur_layer && !l->noblur && l->blur)
wlr_scene_blur_set_size(l->blur, l->animation.current.width,
l->animation.current.height);
if (animation_passed >= 1.0) {
l->animation.running = false;
l->need_output_flush = false;
@ -374,6 +408,10 @@ void init_fadeout_layers(LayerSurface *l) {
if (!l->mon || !l->scene)
return;
if (l->shield_when_capture) {
return;
}
if ((l->animation_type_close &&
strcmp(l->animation_type_close, "none") == 0) ||
(!l->animation_type_close &&
@ -567,8 +605,10 @@ bool layer_draw_frame(LayerSurface *l) {
if (config.animations && config.layer_animations && l->animation.running &&
!l->noanim) {
layer_animation_next_tick(l);
layer_draw_shield(l);
layer_draw_shadow(l);
} else {
layer_draw_shield(l);
layer_draw_shadow(l);
l->need_output_flush = false;
}

View file

@ -45,10 +45,9 @@ void set_tagin_animation(Monitor *m, Client *c) {
void set_arrange_visible(Monitor *m, Client *c, bool want_animation) {
if (!ISTILED(c) || ((!c->is_clip_to_hide || !is_scroller_layout(c->mon)) &&
(!c->is_monocle_hide || !is_monocle_layout(c->mon)))) {
if (!ISTILED(c) || (!c->is_clip_to_hide || !is_scroller_layout(c->mon))) {
c->is_clip_to_hide = false;
c->is_monocle_hide = false;
c->is_logic_hide = false;
wlr_scene_node_set_enabled(&c->scene->node, true);
wlr_scene_node_set_enabled(&c->scene_surface->node, true);
}

View file

@ -205,4 +205,30 @@ void wl_list_swap(struct wl_list *l1, struct wl_list *l2) {
tmp2_prev->next = l1;
tmp2_next->prev = l1;
}
}
void wl_list_safe_reinsert_prev(struct wl_list *l1, struct wl_list *l2) {
if (!l1 || !l2)
return;
if (l1 == l2)
return;
if (l1->prev == l2)
return;
wl_list_remove(l2);
wl_list_init(l2);
wl_list_insert(l1->prev, l2);
}
void wl_list_safe_reinsert_next(struct wl_list *l1, struct wl_list *l2) {
if (!l1 || !l2)
return;
if (l1 == l2)
return;
if (l1->next == l2)
return;
wl_list_remove(l2);
wl_list_init(l2);
wl_list_insert(l1, l2);
}

View file

@ -12,4 +12,6 @@ char *join_strings(char *arr[], const char *sep);
char *join_strings_with_suffix(char *arr[], const char *suffix,
const char *sep);
char *string_printf(const char *fmt, ...);
void wl_list_swap(struct wl_list *l1, struct wl_list *l2);
void wl_list_swap(struct wl_list *l1, struct wl_list *l2);
void wl_list_safe_reinsert_prev(struct wl_list *l1, struct wl_list *l2);
void wl_list_safe_reinsert_next(struct wl_list *l1, struct wl_list *l2);

View file

@ -22,6 +22,11 @@ enum { NUM_TYPE_MINUS, NUM_TYPE_PLUS, NUM_TYPE_DEFAULT };
enum { KEY_TYPE_CODE, KEY_TYPE_SYM };
enum render_bit_depth {
MANGO_RENDER_BIT_DEPTH_DEFAULT = 0,
MANGO_RENDER_BIT_DEPTH_8,
MANGO_RENDER_BIT_DEPTH_10,
};
typedef struct {
uint32_t keycode1;
uint32_t keycode2;
@ -74,11 +79,13 @@ typedef struct {
int32_t isunglobal;
int32_t isglobal;
int32_t isoverlay;
int32_t shield_when_capture;
int32_t allow_shortcuts_inhibit;
int32_t ignore_maximize;
int32_t ignore_minimize;
int32_t isnosizehint;
int32_t idleinhibit_when_focus;
int32_t vrr_only_fullscreen;
char *monitor;
int32_t offsetx;
int32_t offsety;
@ -113,6 +120,8 @@ typedef struct {
float refresh; // Refresh rate
int32_t vrr; // variable refresh rate
int32_t custom; // enable custom mode
int32_t hdr; // enable hdr mode
int32_t disable; // prefer disable
} ConfigMonitorRule;
// 修改后的宏定义
@ -179,6 +188,7 @@ typedef struct {
char *layer_name; // 布局名称
char *animation_type_open;
char *animation_type_close;
int32_t shield_when_capture;
int32_t noblur;
int32_t noanim;
int32_t noshadow;
@ -332,7 +342,7 @@ typedef struct {
uint32_t gappoh;
uint32_t gappov;
uint32_t borderpx;
uint32_t tab_bar_height;
uint32_t group_bar_height;
float scratchpad_width_ratio;
float scratchpad_height_ratio;
float rootcolor[4];
@ -410,7 +420,9 @@ typedef struct {
struct xkb_context *ctx;
struct xkb_keymap *keymap;
DecorateDrawData jumplabeldata;
DecorateDrawData tabdata;
DecorateDrawData groupbardata;
int32_t hdr_depth;
} Config;
typedef int32_t (*FuncType)(const Arg *);
@ -418,7 +430,7 @@ Config config;
bool parse_config_file(Config *config, const char *file_path, bool must_exist);
bool apply_rule_to_state(Monitor *m, const ConfigMonitorRule *rule,
struct wlr_output_state *state, int vrr, int custom);
struct wlr_output_state *state);
bool monitor_matches_rule(Monitor *m, const ConfigMonitorRule *rule);
// Helper function to trim whitespace from start and end of a string
@ -1010,9 +1022,17 @@ FuncType parse_func_name(char *func_name, Arg *arg, char *arg_value,
if (strcmp(func_name, "focusstack") == 0) {
func = focusstack;
(*arg).i = parse_circle_direction(arg_value);
} else if (strcmp(func_name, "groupfocus") == 0) {
func = groupfocus;
(*arg).i = parse_circle_direction(arg_value);
} else if (strcmp(func_name, "focusdir") == 0) {
func = focusdir;
(*arg).i = parse_direction(arg_value);
} else if (strcmp(func_name, "groupjoin") == 0) {
func = groupjoin;
(*arg).i = parse_direction(arg_value);
} else if (strcmp(func_name, "groupleave") == 0) {
func = groupleave;
} else if (strcmp(func_name, "focusid") == 0) {
func = focusid;
} else if (strcmp(func_name, "incnmaster") == 0) {
@ -1277,6 +1297,15 @@ FuncType parse_func_name(char *func_name, Arg *arg, char *arg_value,
} else if (strcmp(func_name, "toggle_monitor") == 0) {
func = toggle_monitor;
(*arg).v = strdup(arg_value);
} else if (strcmp(func_name, "sleep_monitor") == 0) {
func = sleep_monitor;
(*arg).v = strdup(arg_value);
} else if (strcmp(func_name, "wakeup_monitor") == 0) {
func = wakeup_monitor;
(*arg).v = strdup(arg_value);
} else if (strcmp(func_name, "sleep_toggle_monitor") == 0) {
func = sleep_toggle_monitor;
(*arg).v = strdup(arg_value);
} else if (strcmp(func_name, "scroller_stack") == 0) {
func = scroller_stack;
(*arg).i = parse_direction(arg_value);
@ -1510,6 +1539,8 @@ bool parse_option(Config *config, char *key, char *value) {
config->drag_floating_refresh_interval = atof(value);
} else if (strcmp(key, "allow_tearing") == 0) {
config->allow_tearing = atoi(value);
} else if (strcmp(key, "hdr_depth") == 0) {
config->hdr_depth = atoi(value);
} else if (strcmp(key, "allow_shortcuts_inhibit") == 0) {
config->allow_shortcuts_inhibit = atoi(value);
} else if (strcmp(key, "allow_lock_transparent") == 0) {
@ -1765,76 +1796,76 @@ bool parse_option(Config *config, char *key, char *value) {
config->cursor_size = atoi(value);
} else if (strcmp(key, "cursor_theme") == 0) {
config->cursor_theme = strdup(value);
} else if (strcmp(key, "tab_bar_decorate_font_desc") == 0) {
config->tabdata.font_desc = strdup(value);
} else if (strcmp(key, "tab_bar_decorate_fg_color") == 0) {
} else if (strcmp(key, "group_bar_decorate_font_desc") == 0) {
config->groupbardata.font_desc = strdup(value);
} else if (strcmp(key, "group_bar_decorate_fg_color") == 0) {
int64_t color = parse_color(value);
if (color == -1) {
fprintf(stderr,
"\033[1m\033[31m[ERROR]:\033[33m Invalid "
"tab_bar_decorate_fg_color "
"group_bar_decorate_fg_color "
"format: %s\n",
value);
return false;
} else {
convert_hex_to_rgba(config->tabdata.fg_color, color);
convert_hex_to_rgba(config->groupbardata.fg_color, color);
}
} else if (strcmp(key, "tab_bar_decorate_bg_color") == 0) {
} else if (strcmp(key, "group_bar_decorate_bg_color") == 0) {
int64_t color = parse_color(value);
if (color == -1) {
fprintf(stderr,
"\033[1m\033[31m[ERROR]:\033[33m Invalid "
"tab_bar_decorate_bg_color "
"group_bar_decorate_bg_color "
"format: %s\n",
value);
return false;
} else {
convert_hex_to_rgba(config->tabdata.bg_color, color);
convert_hex_to_rgba(config->groupbardata.bg_color, color);
}
} else if (strcmp(key, "tab_bar_decorate_focus_fg_color") == 0) {
} else if (strcmp(key, "group_bar_decorate_focus_fg_color") == 0) {
int64_t color = parse_color(value);
if (color == -1) {
fprintf(stderr,
"\033[1m\033[31m[ERROR]:\033[33m Invalid "
"tab_bar_decorate_focus_fg_color "
"group_bar_decorate_focus_fg_color "
"format: %s\n",
value);
return false;
} else {
convert_hex_to_rgba(config->tabdata.focus_fg_color, color);
convert_hex_to_rgba(config->groupbardata.focus_fg_color, color);
}
} else if (strcmp(key, "tab_bar_decorate_focus_bg_color") == 0) {
} else if (strcmp(key, "group_bar_decorate_focus_bg_color") == 0) {
int64_t color = parse_color(value);
if (color == -1) {
fprintf(stderr,
"\033[1m\033[31m[ERROR]:\033[33m Invalid "
"tab_bar_decorate_focus_bg_color "
"group_bar_decorate_focus_bg_color "
"format: %s\n",
value);
return false;
} else {
convert_hex_to_rgba(config->tabdata.focus_bg_color, color);
convert_hex_to_rgba(config->groupbardata.focus_bg_color, color);
}
} else if (strcmp(key, "tab_bar_decorate_border_color") == 0) {
} else if (strcmp(key, "group_bar_decorate_border_color") == 0) {
int64_t color = parse_color(value);
if (color == -1) {
fprintf(stderr,
"\033[1m\033[31m[ERROR]:\033[33m Invalid "
"tab_bar_decorate_border_color "
"group_bar_decorate_border_color "
"format: %s\n",
value);
return false;
} else {
convert_hex_to_rgba(config->tabdata.border_color, color);
convert_hex_to_rgba(config->groupbardata.border_color, color);
}
} else if (strcmp(key, "tab_bar_decorate_border_width") == 0) {
config->tabdata.border_width = CLAMP_INT(atoi(value), 0, 100);
} else if (strcmp(key, "tab_bar_decorate_corner_radius") == 0) {
config->tabdata.corner_radius = CLAMP_INT(atoi(value), 0, 100);
} else if (strcmp(key, "tab_bar_decorate_padding_x") == 0) {
config->tabdata.padding_x = CLAMP_INT(atoi(value), 0, 100);
} else if (strcmp(key, "tab_bar_decorate_padding_y") == 0) {
config->tabdata.padding_y = CLAMP_INT(atoi(value), 0, 100);
} else if (strcmp(key, "group_bar_decorate_border_width") == 0) {
config->groupbardata.border_width = CLAMP_INT(atoi(value), 0, 100);
} else if (strcmp(key, "group_bar_decorate_corner_radius") == 0) {
config->groupbardata.corner_radius = CLAMP_INT(atoi(value), 0, 100);
} else if (strcmp(key, "group_bar_decorate_padding_x") == 0) {
config->groupbardata.padding_x = CLAMP_INT(atoi(value), 0, 100);
} else if (strcmp(key, "group_bar_decorate_padding_y") == 0) {
config->groupbardata.padding_y = CLAMP_INT(atoi(value), 0, 100);
} else if (strcmp(key, "jump_label_decorate_font_desc") == 0) {
config->jumplabeldata.font_desc = strdup(value);
} else if (strcmp(key, "jump_label_decorate_fg_color") == 0) {
@ -1951,8 +1982,8 @@ bool parse_option(Config *config, char *key, char *value) {
config->scratchpad_height_ratio = atof(value);
} else if (strcmp(key, "borderpx") == 0) {
config->borderpx = atoi(value);
} else if (strcmp(key, "tab_bar_height") == 0) {
config->tab_bar_height = atoi(value);
} else if (strcmp(key, "group_bar_height") == 0) {
config->group_bar_height = atoi(value);
} else if (strcmp(key, "rootcolor") == 0) {
int64_t color = parse_color(value);
if (color == -1) {
@ -2106,7 +2137,9 @@ bool parse_option(Config *config, char *key, char *value) {
rule->height = -1;
rule->refresh = 0.0f;
rule->vrr = 0;
rule->hdr = 0;
rule->custom = 0;
rule->disable = 0;
bool parse_error = false;
char *token = strtok(value, ",");
@ -2144,6 +2177,10 @@ bool parse_option(Config *config, char *key, char *value) {
rule->refresh = CLAMP_FLOAT(atof(val), 0.001f, 1000.0f);
} else if (strcmp(key, "vrr") == 0) {
rule->vrr = CLAMP_INT(atoi(val), 0, 1);
} else if (strcmp(key, "hdr") == 0) {
rule->hdr = CLAMP_INT(atoi(val), 0, 1);
} else if (strcmp(key, "disable") == 0) {
rule->disable = CLAMP_INT(atoi(val), 0, 1);
} else if (strcmp(key, "custom") == 0) {
rule->custom = CLAMP_INT(atoi(val), 0, 1);
} else {
@ -2274,6 +2311,7 @@ bool parse_option(Config *config, char *key, char *value) {
rule->layer_name = NULL;
rule->animation_type_open = NULL;
rule->animation_type_close = NULL;
rule->shield_when_capture = 0;
rule->noblur = 0;
rule->noanim = 0;
rule->noshadow = 0;
@ -2296,6 +2334,8 @@ bool parse_option(Config *config, char *key, char *value) {
rule->animation_type_open = strdup(val);
} else if (strcmp(key, "animation_type_close") == 0) {
rule->animation_type_close = strdup(val);
} else if (strcmp(key, "shield_when_capture") == 0) {
rule->shield_when_capture = CLAMP_INT(atoi(val), 0, 1);
} else if (strcmp(key, "noblur") == 0) {
rule->noblur = CLAMP_INT(atoi(val), 0, 1);
} else if (strcmp(key, "noanim") == 0) {
@ -2349,11 +2389,13 @@ bool parse_option(Config *config, char *key, char *value) {
rule->isunglobal = -1;
rule->isglobal = -1;
rule->isoverlay = -1;
rule->shield_when_capture = -1;
rule->allow_shortcuts_inhibit = -1;
rule->ignore_maximize = -1;
rule->ignore_minimize = -1;
rule->isnosizehint = -1;
rule->idleinhibit_when_focus = -1;
rule->vrr_only_fullscreen = -1;
rule->isterm = -1;
rule->allow_csd = -1;
rule->force_fakemaximize = -1;
@ -2456,6 +2498,8 @@ bool parse_option(Config *config, char *key, char *value) {
rule->focused_opacity = atof(val);
} else if (strcmp(key, "isoverlay") == 0) {
rule->isoverlay = atoi(val);
} else if (strcmp(key, "shield_when_capture") == 0) {
rule->shield_when_capture = atoi(val);
} else if (strcmp(key, "allow_shortcuts_inhibit") == 0) {
rule->allow_shortcuts_inhibit = atoi(val);
} else if (strcmp(key, "ignore_maximize") == 0) {
@ -2466,6 +2510,8 @@ bool parse_option(Config *config, char *key, char *value) {
rule->isnosizehint = atoi(val);
} else if (strcmp(key, "idleinhibit_when_focus") == 0) {
rule->idleinhibit_when_focus = atoi(val);
} else if (strcmp(key, "vrr_only_fullscreen") == 0) {
rule->vrr_only_fullscreen = atoi(val);
} else if (strcmp(key, "isterm") == 0) {
rule->isterm = atoi(val);
} else if (strcmp(key, "allow_csd") == 0) {
@ -3401,9 +3447,9 @@ void free_config(void) {
config.jumplabeldata.font_desc = NULL;
}
if (config.tabdata.font_desc) {
free((void *)config.tabdata.font_desc);
config.tabdata.font_desc = NULL;
if (config.groupbardata.font_desc) {
free((void *)config.groupbardata.font_desc);
config.groupbardata.font_desc = NULL;
}
if (config.tablet_map_to_mon) {
@ -3496,6 +3542,7 @@ void override_config(void) {
config.drag_tile_to_tile = CLAMP_INT(config.drag_tile_to_tile, 0, 1);
config.drag_tile_small = CLAMP_INT(config.drag_tile_small, 0, 1);
config.allow_tearing = CLAMP_INT(config.allow_tearing, 0, 2);
config.hdr_depth = CLAMP_INT(config.hdr_depth, 0, 2);
config.allow_shortcuts_inhibit =
CLAMP_INT(config.allow_shortcuts_inhibit, 0, 1);
config.allow_lock_transparent =
@ -3569,7 +3616,7 @@ void override_config(void) {
config.scratchpad_height_ratio =
CLAMP_FLOAT(config.scratchpad_height_ratio, 0.1f, 1.0f);
config.borderpx = CLAMP_INT(config.borderpx, 0, 200);
config.tab_bar_height = CLAMP_INT(config.tab_bar_height, 0, 500);
config.group_bar_height = CLAMP_INT(config.group_bar_height, 0, 500);
config.smartgaps = CLAMP_INT(config.smartgaps, 0, 1);
config.blur = CLAMP_INT(config.blur, 0, 1);
config.blur_layer = CLAMP_INT(config.blur_layer, 0, 1);
@ -3598,12 +3645,14 @@ void override_config(void) {
config.unfocused_opacity =
CLAMP_FLOAT(config.unfocused_opacity, 0.0f, 1.0f);
config.tabdata.border_width =
CLAMP_INT(config.tabdata.border_width, 0, 100);
config.tabdata.corner_radius =
CLAMP_INT(config.tabdata.corner_radius, 0, 100);
config.tabdata.padding_x = CLAMP_INT(config.tabdata.padding_x, 0, 100);
config.tabdata.padding_y = CLAMP_INT(config.tabdata.padding_y, 0, 100);
config.groupbardata.border_width =
CLAMP_INT(config.groupbardata.border_width, 0, 100);
config.groupbardata.corner_radius =
CLAMP_INT(config.groupbardata.corner_radius, 0, 100);
config.groupbardata.padding_x =
CLAMP_INT(config.groupbardata.padding_x, 0, 100);
config.groupbardata.padding_y =
CLAMP_INT(config.groupbardata.padding_y, 0, 100);
config.jumplabeldata.border_width =
CLAMP_INT(config.jumplabeldata.border_width, 0, 100);
@ -3683,11 +3732,12 @@ void set_value_default() {
config.view_current_to_back = 0;
config.single_scratchpad = 1;
config.xwayland_persistence = 1;
config.syncobj_enable = 0;
config.syncobj_enable = 1;
config.tag_carousel = 0;
config.drag_tile_refresh_interval = 8.0f;
config.drag_floating_refresh_interval = 8.0f;
config.allow_tearing = TEARING_DISABLED;
config.hdr_depth = MANGO_RENDER_BIT_DEPTH_10;
config.allow_shortcuts_inhibit = SHORTCUTS_INHIBIT_ENABLE;
config.allow_lock_transparent = 0;
config.no_border_when_single = 0;
@ -3701,7 +3751,7 @@ void set_value_default() {
config.idleinhibit_ignore_visible = 0;
config.borderpx = 4;
config.tab_bar_height = 50;
config.group_bar_height = 50;
config.overviewgappi = 5;
config.overviewgappo = 30;
config.cursor_hide_timeout = 0;
@ -3738,7 +3788,6 @@ void set_value_default() {
config.blur_layer = 0;
config.blur_optimized = 1;
config.border_radius = 0;
config.border_radius_location_default = CORNER_LOCATION_ALL;
config.blur_params.num_passes = 1;
config.blur_params.radius = 5;
config.blur_params.noise = 0.02f;
@ -3789,30 +3838,30 @@ void set_value_default() {
config.animation_curve_opafadeout[2] = 0.5;
config.animation_curve_opafadeout[3] = 0.5;
config.tabdata.fg_color[0] = 0xc4 / 255.0f;
config.tabdata.fg_color[1] = 0x93 / 255.0f;
config.tabdata.fg_color[2] = 0x9d / 255.0f;
config.tabdata.fg_color[3] = 1.0f;
config.tabdata.bg_color[0] = 0x32 / 255.0f;
config.tabdata.bg_color[1] = 0x32 / 255.0f;
config.tabdata.bg_color[2] = 0x32 / 255.0f;
config.tabdata.bg_color[3] = 1.0f;
config.tabdata.focus_fg_color[0] = 0xed / 255.0f;
config.tabdata.focus_fg_color[1] = 0xa6 / 255.0f;
config.tabdata.focus_fg_color[2] = 0xb4 / 255.0f;
config.tabdata.focus_fg_color[3] = 1.0f;
config.tabdata.focus_bg_color[0] = 0x4e / 255.0f;
config.tabdata.focus_bg_color[1] = 0x45 / 255.0f;
config.tabdata.focus_bg_color[2] = 0x3c / 255.0f;
config.tabdata.focus_bg_color[3] = 1.0f;
config.tabdata.border_color[0] = 0x8b / 255.0f;
config.tabdata.border_color[1] = 0xaa / 255.0f;
config.tabdata.border_color[2] = 0x9b / 255.0f;
config.tabdata.border_color[3] = 1.0f;
config.tabdata.border_width = 4;
config.tabdata.corner_radius = 5;
config.tabdata.padding_x = 0;
config.tabdata.padding_y = 0;
config.groupbardata.fg_color[0] = 0xc4 / 255.0f;
config.groupbardata.fg_color[1] = 0x93 / 255.0f;
config.groupbardata.fg_color[2] = 0x9d / 255.0f;
config.groupbardata.fg_color[3] = 1.0f;
config.groupbardata.bg_color[0] = 0x32 / 255.0f;
config.groupbardata.bg_color[1] = 0x32 / 255.0f;
config.groupbardata.bg_color[2] = 0x32 / 255.0f;
config.groupbardata.bg_color[3] = 1.0f;
config.groupbardata.focus_fg_color[0] = 0xed / 255.0f;
config.groupbardata.focus_fg_color[1] = 0xa6 / 255.0f;
config.groupbardata.focus_fg_color[2] = 0xb4 / 255.0f;
config.groupbardata.focus_fg_color[3] = 1.0f;
config.groupbardata.focus_bg_color[0] = 0x4e / 255.0f;
config.groupbardata.focus_bg_color[1] = 0x45 / 255.0f;
config.groupbardata.focus_bg_color[2] = 0x3c / 255.0f;
config.groupbardata.focus_bg_color[3] = 1.0f;
config.groupbardata.border_color[0] = 0x8b / 255.0f;
config.groupbardata.border_color[1] = 0xaa / 255.0f;
config.groupbardata.border_color[2] = 0x9b / 255.0f;
config.groupbardata.border_color[3] = 1.0f;
config.groupbardata.border_width = 4;
config.groupbardata.corner_radius = 5;
config.groupbardata.padding_x = 0;
config.groupbardata.padding_y = 0;
config.jumplabeldata.fg_color[0] = 0xc4 / 255.0f;
config.jumplabeldata.fg_color[1] = 0x93 / 255.0f;
@ -3952,7 +4001,7 @@ bool parse_config(void) {
config.tag_rules_count = 0;
config.cursor_theme = NULL;
config.jumplabeldata.font_desc = NULL;
config.tabdata.font_desc = NULL;
config.groupbardata.font_desc = NULL;
config.tablet_map_to_mon = NULL;
strcpy(config.keymode, "default");
@ -4017,16 +4066,13 @@ void reset_blur_params(void) {
void reapply_monitor_rules(void) {
ConfigMonitorRule *mr;
Monitor *m = NULL;
int32_t ji, vrr, custom;
int32_t ji;
int32_t mx, my;
struct wlr_output_state state;
wl_list_for_each(m, &mons, link) {
if (!m->wlr_output->enabled)
continue;
wlr_output_state_init(&state);
for (ji = 0; ji < config.monitor_rules_count; ji++) {
if (config.monitor_rules_count < 1)
break;
@ -4036,18 +4082,33 @@ void reapply_monitor_rules(void) {
if (monitor_matches_rule(m, mr)) {
mx = mr->x == INT32_MAX ? m->m.x : mr->x;
my = mr->y == INT32_MAX ? m->m.y : mr->y;
vrr = mr->vrr >= 0 ? mr->vrr : 0;
custom = mr->custom >= 0 ? mr->custom : 0;
(void)apply_rule_to_state(m, mr, &state, vrr, custom);
apply_rule_to_state(m, mr, &m->pending);
wlr_output_layout_add(output_layout, m->wlr_output, mx, my);
wlr_output_commit_state(m->wlr_output, &state);
break;
}
}
wlr_output_state_finish(&state);
if (m->prefer_disable) {
wlr_output_state_set_enabled(&m->pending, false);
} else {
wlr_output_state_set_enabled(&m->pending, true);
}
if (m->hdr_enable) {
output_state_setup_hdr(m, false, &m->pending);
}
if (!(mango_scene_output_commit(m->scene_output, &m->pending))) {
if (m->hdr_enable) {
output_state_setup_hdr(m, true, &m->pending);
}
}
wlr_output_effective_resolution(m->wlr_output, &m->m.width,
&m->m.height);
}
updatemons(NULL, NULL);
}
@ -4116,14 +4177,7 @@ void reapply_property(void) {
if (!c->isnoborder && !c->isfullscreen) {
c->bw = config.borderpx;
}
mango_jump_label_node_apply_config(c->jump_label_node,
&config.jumplabeldata);
mango_tab_bar_node_apply_config(c->tab_bar_node, &config.tabdata);
wlr_scene_rect_set_color(c->droparea, config.dropcolor);
wlr_scene_rect_set_color(c->splitindicator[0], config.splitcolor);
wlr_scene_rect_set_color(c->splitindicator[1], config.splitcolor);
client_set_group_config(c);
}
}
}

View file

@ -2,6 +2,8 @@ int32_t minimized(const Arg *arg);
int32_t restore_minimized(const Arg *arg);
int32_t toggle_scratchpad(const Arg *arg);
int32_t focusdir(const Arg *arg);
int32_t groupjoin(const Arg *arg);
int32_t groupleave(const Arg *arg);
int32_t toggleoverview(const Arg *arg);
int32_t togglejump(const Arg *arg);
int32_t set_proportion(const Arg *arg);
@ -38,6 +40,7 @@ int32_t toggleglobal(const Arg *arg);
int32_t incnmaster(const Arg *arg);
int32_t focusmon(const Arg *arg);
int32_t focusstack(const Arg *arg);
int32_t groupfocus(const Arg *arg);
int32_t chvt(const Arg *arg);
int32_t reload_config(const Arg *arg);
int32_t smartmovewin(const Arg *arg);
@ -70,6 +73,9 @@ int32_t setoption(const Arg *arg);
int32_t disable_monitor(const Arg *arg);
int32_t enable_monitor(const Arg *arg);
int32_t toggle_monitor(const Arg *arg);
int32_t sleep_monitor(const Arg *arg);
int32_t wakeup_monitor(const Arg *arg);
int32_t sleep_toggle_monitor(const Arg *arg);
int32_t scroller_stack(const Arg *arg);
int32_t toggle_all_floating(const Arg *arg);
int32_t dwindle_toggle_split_direction(const Arg *arg);

View file

@ -156,6 +156,94 @@ int32_t focusdir(const Arg *arg) {
return 0;
}
int32_t groupjoin(const Arg *arg) {
if (!selmon)
return 0;
Monitor *oldmon = NULL;
Client *need_join_client = arg->tc ? arg->tc : selmon->sel;
if (!need_join_client || !need_join_client->mon)
return 0;
if (need_join_client->mon->isoverview)
return 0;
Client *need_replace_client = NULL;
need_replace_client = direction_select(arg);
if (!need_replace_client || !need_replace_client->mon)
return 0;
if (need_join_client == need_replace_client)
return 0;
if (need_join_client->group_next || need_join_client->group_prev) {
groupleave(&(Arg){.tc = need_join_client});
}
if (need_join_client->mon != need_replace_client->mon) {
oldmon = need_join_client->mon;
need_join_client->mon = need_replace_client->mon;
}
if (!need_replace_client->group_prev && !need_replace_client->group_next) {
need_replace_client->isgroupfocusing = true;
}
need_join_client->group_next = need_replace_client;
if (need_replace_client->group_prev) {
need_replace_client->group_prev->group_next = need_join_client;
}
need_join_client->group_prev = need_replace_client->group_prev;
need_replace_client->group_prev = need_join_client;
client_focus_group_member(need_join_client);
arrange(need_join_client->mon, false, false);
// oldmon可能已经死掉了
if (oldmon) {
arrange(oldmon, false, false);
}
return 0;
}
int32_t groupleave(const Arg *arg) {
if (!selmon)
return 0;
Client *tc = arg->tc ? arg->tc : selmon->sel;
if (!tc || !tc->mon || !tc->isgroupfocusing)
return 0;
if (!tc->group_next && !tc->group_prev) {
return 0;
}
if (tc->mon->isoverview)
return 0;
Client *rc = tc->group_next ? tc->group_next : tc->group_prev;
client_focus_group_member(rc);
client_group_detach(tc);
tc->isgroupfocusing = false;
tc->is_logic_hide = false;
if (!rc->group_prev && !rc->group_next) {
rc->isgroupfocusing = false;
}
arrange(tc->mon, false, false);
return 0;
}
int32_t focuslast(const Arg *arg) {
Client *c = NULL;
Client *tc = NULL;
@ -261,6 +349,34 @@ int32_t focusstack(const Arg *arg) {
return 0;
}
int32_t groupfocus(const Arg *arg) {
Client *c = arg->tc ? arg->tc : selmon->sel;
if (!c || !c->mon)
return 0;
if (!c->group_prev && !c->group_next) {
return 0;
}
if (c->mon->isoverview)
return 0;
Client *tc = NULL;
if (arg->i == NEXT) {
tc = c->group_next;
} else {
tc = c->group_prev;
}
if (!tc)
return 0;
client_focus_group_member(tc);
arrange(tc->mon, false, false);
return 0;
}
int32_t incnmaster(const Arg *arg) {
if (!arg || !selmon)
return 0;
@ -366,7 +482,7 @@ int32_t moveresize(const Arg *arg) {
if (cursor_mode != CurNormal && cursor_mode != CurPressed)
return 0;
xytonode(cursor->x, cursor->y, NULL, &grabc, NULL, NULL, NULL);
xytonode(cursor->x, cursor->y, NULL, &grabc, NULL, NULL, NULL, NULL);
if (!grabc || client_is_unmanaged(grabc) || grabc->isfullscreen ||
grabc->ismaximizescreen) {
grabc = NULL;
@ -1427,15 +1543,7 @@ int32_t toggleoverlay(const Arg *arg) {
c->isoverlay ^= 1;
if (c->isoverlay) {
wlr_scene_node_reparent(&c->scene->node, layers[LyrOverlay]);
wlr_scene_node_raise_to_top(&c->scene->node);
} else if (client_should_overtop(c) && c->isfloating) {
wlr_scene_node_reparent(&c->scene->node, layers[LyrTop]);
} else {
wlr_scene_node_reparent(&c->scene->node,
layers[c->isfloating ? LyrTop : LyrTile]);
}
client_reparent_group(c);
setborder_color(c);
return 0;
}
@ -1825,12 +1933,12 @@ int32_t togglejump(const Arg *arg) {
int32_t disable_monitor(const Arg *arg) {
Monitor *m = NULL;
struct wlr_output_state state = {0};
wl_list_for_each(m, &mons, link) {
if (match_monitor_spec(arg->v, m)) {
wlr_output_state_set_enabled(&state, false);
wlr_output_commit_state(m->wlr_output, &state);
m->asleep = 1;
wlr_output_state_set_enabled(&m->pending, false);
mango_output_commit(m);
m->only_sleep = 0;
updatemons(NULL, NULL);
break;
}
@ -1840,12 +1948,11 @@ int32_t disable_monitor(const Arg *arg) {
int32_t enable_monitor(const Arg *arg) {
Monitor *m = NULL;
struct wlr_output_state state = {0};
wl_list_for_each(m, &mons, link) {
if (match_monitor_spec(arg->v, m)) {
wlr_output_state_set_enabled(&state, true);
wlr_output_commit_state(m->wlr_output, &state);
m->asleep = 0;
wlr_output_state_set_enabled(&m->pending, true);
mango_output_commit(m);
m->only_sleep = 0;
updatemons(NULL, NULL);
break;
}
@ -1855,12 +1962,54 @@ int32_t enable_monitor(const Arg *arg) {
int32_t toggle_monitor(const Arg *arg) {
Monitor *m = NULL;
struct wlr_output_state state = {0};
wl_list_for_each(m, &mons, link) {
if (match_monitor_spec(arg->v, m)) {
wlr_output_state_set_enabled(&state, !m->wlr_output->enabled);
wlr_output_commit_state(m->wlr_output, &state);
m->asleep = !m->wlr_output->enabled;
wlr_output_state_set_enabled(&m->pending, !m->wlr_output->enabled);
mango_output_commit(m);
m->only_sleep = 0;
updatemons(NULL, NULL);
break;
}
}
return 0;
}
int32_t sleep_monitor(const Arg *arg) {
Monitor *m = NULL;
wl_list_for_each(m, &mons, link) {
if (match_monitor_spec(arg->v, m)) {
wlr_output_state_set_enabled(&m->pending, false);
mango_output_commit(m);
m->only_sleep = 1;
updatemons(NULL, NULL);
break;
}
}
return 0;
}
int32_t wakeup_monitor(const Arg *arg) {
Monitor *m = NULL;
wl_list_for_each(m, &mons, link) {
if (match_monitor_spec(arg->v, m)) {
wlr_output_state_set_enabled(&m->pending, true);
mango_output_commit(m);
m->only_sleep = 0;
updatemons(NULL, NULL);
break;
}
}
return 0;
}
int32_t sleep_toggle_monitor(const Arg *arg) {
Monitor *m = NULL;
wl_list_for_each(m, &mons, link) {
if (match_monitor_spec(arg->v, m)) {
wlr_output_state_set_enabled(&m->pending, !m->wlr_output->enabled);
mango_output_commit(m);
m->only_sleep = !m->wlr_output->enabled;
updatemons(NULL, NULL);
break;
}
@ -1912,13 +2061,11 @@ int32_t scroller_apply_stack(Client *c, Client *target_client,
if (direction == LEFT || direction == UP) {
if (c != stack_head) {
wl_list_remove(&c->link);
wl_list_insert(stack_head->link.prev, &c->link);
wl_list_safe_reinsert_prev(&stack_head->link, &c->link);
}
} else if (direction == RIGHT || direction == DOWN) {
if (c != stack_tail) {
wl_list_remove(&c->link);
wl_list_insert(&stack_tail->link, &c->link);
wl_list_safe_reinsert_next(&stack_head->link, &c->link);
}
}
sync_scroller_state_to_clients(m, tag);
@ -2001,7 +2148,8 @@ int32_t dwindle_set_split_direction(Client *c, bool istoggle, bool horizontal) {
leaf->custom_leaf_split_h = false;
}
bool hit_no_border = check_hit_no_border(c);
apply_split_border(c, hit_no_border);
struct ivec2 offsets = compute_edge_offsets(c);
client_draw_split_border(c, hit_no_border, offsets);
return 0;
}
@ -2040,6 +2188,13 @@ int32_t focusid(const Arg *arg) {
return 0;
Client *c = arg->tc;
if (c->swallowdby)
return 0;
if (c->group_next || c->group_prev)
client_focus_group_member(c);
client_active(c);
return 0;
}

View file

@ -59,10 +59,9 @@ static const struct wlr_buffer_impl text_buffer_impl = {
.end_data_ptr_access = text_buffer_end_data_ptr_access,
};
struct mango_jump_label_node *
mango_jump_label_node_create(struct wlr_scene_tree *parent,
DecorateDrawData data) {
struct mango_jump_label_node *node = calloc(1, sizeof(*node));
MangoJumpLabel *mango_jump_label_node_create(struct wlr_scene_tree *parent,
DecorateDrawData data) {
MangoJumpLabel *node = calloc(1, sizeof(*node));
if (!node)
return NULL;
@ -104,7 +103,7 @@ mango_jump_label_node_create(struct wlr_scene_tree *parent,
return node;
}
void mango_jump_label_node_destroy(struct mango_jump_label_node *node) {
void mango_jump_label_node_destroy(MangoJumpLabel *node) {
if (!node)
return;
@ -136,8 +135,8 @@ void mango_jump_label_node_destroy(struct mango_jump_label_node *node) {
free(node);
}
void mango_jump_label_node_set_background(struct mango_jump_label_node *node,
float r, float g, float b, float a) {
void mango_jump_label_node_set_background(MangoJumpLabel *node, float r,
float g, float b, float a) {
if (!node)
return;
node->bg_color[0] = r;
@ -146,9 +145,9 @@ void mango_jump_label_node_set_background(struct mango_jump_label_node *node,
node->bg_color[3] = a;
}
void mango_jump_label_node_set_border(struct mango_jump_label_node *node,
float r, float g, float b, float a,
int32_t width, int32_t radius) {
void mango_jump_label_node_set_border(MangoJumpLabel *node, float r, float g,
float b, float a, int32_t width,
int32_t radius) {
if (!node)
return;
node->border_color[0] = r;
@ -159,17 +158,16 @@ void mango_jump_label_node_set_border(struct mango_jump_label_node *node,
node->corner_radius = radius;
}
void mango_jump_label_node_set_padding(struct mango_jump_label_node *node,
int32_t pad_x, int32_t pad_y) {
void mango_jump_label_node_set_padding(MangoJumpLabel *node, int32_t pad_x,
int32_t pad_y) {
if (!node)
return;
node->padding_x = pad_x >= 0 ? pad_x : 0;
node->padding_y = pad_y >= 0 ? pad_y : 0;
}
static void get_text_pixel_size(struct mango_jump_label_node *node,
const char *text, float scale, int32_t *out_w,
int32_t *out_h) {
static void get_text_pixel_size(MangoJumpLabel *node, const char *text,
float scale, int32_t *out_w, int32_t *out_h) {
if (node->measure_scale != scale) {
pango_cairo_context_set_resolution(node->measure_context, 96.0 * scale);
node->measure_scale = scale;
@ -184,6 +182,10 @@ static void get_text_pixel_size(struct mango_jump_label_node *node,
static void draw_rounded_rect(cairo_t *cr, double x, double y, double w,
double h, double r) {
// 宽高非正时不绘制任何东西
if (w <= 0.0 || h <= 0.0)
return;
double degrees = G_PI / 180.0;
cairo_new_sub_path(cr);
cairo_arc(cr, x + w - r, y + r, r, -90 * degrees, 0 * degrees);
@ -193,14 +195,14 @@ static void draw_rounded_rect(cairo_t *cr, double x, double y, double w,
cairo_close_path(cr);
}
void mango_jump_label_node_update(struct mango_jump_label_node *node,
const char *text, float scale) {
void mango_jump_label_node_update(MangoJumpLabel *node, const char *text,
float scale) {
if (!node || !text)
return;
if (scale <= 0.0f)
scale = 1.0f;
/* 脏检查,加入 focused 状态 */
// 脏检查
if (node->cached_scale == scale && node->cached_font_desc &&
strcmp(node->cached_font_desc, node->font_desc) == 0 &&
node->cached_text && strcmp(node->cached_text, text) == 0 &&
@ -222,7 +224,7 @@ void mango_jump_label_node_update(struct mango_jump_label_node *node,
return;
}
/* 更新缓存 */
// 更新缓存
g_free(node->cached_text);
node->cached_text = g_strdup(text);
g_free(node->cached_font_desc);
@ -266,6 +268,7 @@ void mango_jump_label_node_update(struct mango_jump_label_node *node,
int32_t box_logical_w = logical_text_w + 2 * node->padding_x;
int32_t box_logical_h = logical_text_h + 2 * node->padding_y;
// 物理像素尺寸包含边框,避免边框越界
int32_t required_pixel_w =
(int32_t)((box_logical_w + 2 * node->border_width) * scale + 0.5f);
int32_t required_pixel_h =
@ -318,13 +321,15 @@ void mango_jump_label_node_update(struct mango_jump_label_node *node,
radius = bg_w / 2.0;
if (radius > bg_h / 2.0)
radius = bg_h / 2.0;
if (radius < 0.0)
radius = 0.0;
const float *active_bg =
node->focused ? node->focus_bg_color : node->bg_color;
const float *active_fg =
node->focused ? node->focus_fg_color : node->fg_color;
bool draw_bg = (active_bg[3] > 0.0f); // 使用 active_bg
bool draw_bg = (active_bg[3] > 0.0f) && (bg_w > 0.0 && bg_h > 0.0);
bool draw_border =
(node->border_width > 0) && (node->border_color[3] > 0.0f);
@ -340,25 +345,28 @@ void mango_jump_label_node_update(struct mango_jump_label_node *node,
}
}
cairo_save(cr);
double text_x = (node->border_width + node->padding_x) * scale;
double text_y = (node->border_width + node->padding_y) * scale;
cairo_translate(cr, text_x, text_y);
// 文本绘制仅在背景区域有有效空间时进行
if (bg_w > 0.0 && bg_h > 0.0) {
cairo_save(cr);
double text_x = (node->border_width + node->padding_x) * scale;
double text_y = (node->border_width + node->padding_y) * scale;
cairo_translate(cr, text_x, text_y);
PangoContext *ctx = pango_cairo_create_context(cr);
pango_cairo_context_set_resolution(ctx, 96.0 * scale);
PangoLayout *layout = pango_layout_new(ctx);
PangoFontDescription *desc = get_cached_font_desc(node->font_desc);
pango_layout_set_font_description(layout, desc);
pango_layout_set_text(layout, text, -1);
PangoContext *ctx = pango_cairo_create_context(cr);
pango_cairo_context_set_resolution(ctx, 96.0 * scale);
PangoLayout *layout = pango_layout_new(ctx);
PangoFontDescription *desc = get_cached_font_desc(node->font_desc);
pango_layout_set_font_description(layout, desc);
pango_layout_set_text(layout, text, -1);
cairo_set_source_rgba(cr, active_fg[0], active_fg[1], active_fg[2],
active_fg[3]);
pango_cairo_show_layout(cr, layout);
cairo_set_source_rgba(cr, active_fg[0], active_fg[1], active_fg[2],
active_fg[3]);
pango_cairo_show_layout(cr, layout);
g_object_unref(layout);
g_object_unref(ctx);
cairo_restore(cr);
g_object_unref(layout);
g_object_unref(ctx);
cairo_restore(cr);
}
if (draw_border) {
cairo_set_source_rgba(cr, node->border_color[0], node->border_color[1],
@ -371,15 +379,35 @@ void mango_jump_label_node_update(struct mango_jump_label_node *node,
double bw = bg_w + border;
double bh = bg_h + border;
if (radius > 0.0) {
double outer_radius = radius + half_lw;
if (outer_radius < 0.0)
outer_radius = 0.0;
draw_rounded_rect(cr, bx, by, bw, bh, outer_radius);
} else {
cairo_rectangle(cr, bx, by, bw, bh);
// 确保边框矩形不越界且宽高为正
if (bx < 0.0) {
bw += bx; // bx 为负bw 缩小
bx = 0.0;
}
if (by < 0.0) {
bh += by;
by = 0.0;
}
if (bx + bw > (double)node->surface_pixel_w)
bw = (double)node->surface_pixel_w - bx;
if (by + bh > (double)node->surface_pixel_h)
bh = (double)node->surface_pixel_h - by;
if (bw < 0.0)
bw = 0.0;
if (bh < 0.0)
bh = 0.0;
if (bw > 0.0 && bh > 0.0) {
if (radius > 0.0) {
double outer_radius = radius + half_lw;
if (outer_radius < 0.0)
outer_radius = 0.0;
draw_rounded_rect(cr, bx, by, bw, bh, outer_radius);
} else {
cairo_rectangle(cr, bx, by, bw, bh);
}
cairo_stroke(cr);
}
cairo_stroke(cr);
}
cairo_surface_flush(node->surface);
@ -407,67 +435,71 @@ void mango_jump_label_node_update(struct mango_jump_label_node *node,
node->logical_height);
}
void mango_jump_label_node_set_focus(struct mango_jump_label_node *node,
bool focused) {
void mango_jump_label_node_set_focus(MangoJumpLabel *node, bool focused) {
if (!node || node->focused == focused)
return;
node->focused = focused;
// 使用缓存的文本和缩放触发重绘(如果无文本则不重绘)
if (node->cached_text && node->cached_scale > 0.0f) {
mango_jump_label_node_update(node, node->cached_text,
node->cached_scale);
}
}
struct mango_tab_bar_node *
mango_tab_bar_node_create(void *mango_node_data, struct wlr_scene_tree *parent,
DecorateDrawData data, int32_t width,
int32_t height) {
struct mango_tab_bar_node *node = calloc(1, sizeof(*node));
if (!node)
MangoGroupBar *mango_group_bar_create(void *cdata, uint32_t type,
struct wlr_scene_tree *parent,
DecorateDrawData data, int32_t width,
int32_t height) {
MangoGroupBar *mangobar = calloc(1, sizeof(*mangobar));
if (!mangobar)
return NULL;
node->scene_buffer = wlr_scene_buffer_create(parent, NULL);
if (!node->scene_buffer) {
free(node);
mangobar->scene_buffer = wlr_scene_buffer_create(parent, NULL);
if (!mangobar->scene_buffer) {
free(mangobar);
return NULL;
}
memcpy(node->fg_color, data.fg_color, sizeof(node->fg_color));
memcpy(node->bg_color, data.bg_color, sizeof(node->bg_color));
memcpy(node->focus_fg_color, data.focus_fg_color,
sizeof(node->focus_fg_color));
memcpy(node->focus_bg_color, data.focus_bg_color,
sizeof(node->focus_bg_color));
memcpy(node->border_color, data.border_color, sizeof(node->border_color));
node->border_width = data.border_width;
node->corner_radius = data.corner_radius;
node->padding_x = data.padding_x;
node->padding_y = data.padding_y;
node->font_desc =
memcpy(mangobar->fg_color, data.fg_color, sizeof(mangobar->fg_color));
memcpy(mangobar->bg_color, data.bg_color, sizeof(mangobar->bg_color));
memcpy(mangobar->focus_fg_color, data.focus_fg_color,
sizeof(mangobar->focus_fg_color));
memcpy(mangobar->focus_bg_color, data.focus_bg_color,
sizeof(mangobar->focus_bg_color));
memcpy(mangobar->border_color, data.border_color,
sizeof(mangobar->border_color));
mangobar->border_width = data.border_width;
mangobar->corner_radius = data.corner_radius;
mangobar->padding_x = data.padding_x;
mangobar->padding_y = data.padding_y;
mangobar->font_desc =
g_strdup(data.font_desc ? data.font_desc : "monospace Bold 16");
node->target_width = width;
node->target_height = height;
node->focused = false;
node->cached_focused = false;
mangobar->target_width = width;
mangobar->target_height = height;
mangobar->focused = false;
mangobar->cached_focused = false;
node->measure_surface =
mangobar->measure_surface =
cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 1, 1);
node->measure_cr = cairo_create(node->measure_surface);
node->measure_context = pango_cairo_create_context(node->measure_cr);
node->measure_layout = pango_layout_new(node->measure_context);
node->measure_scale = 1.0f;
mangobar->measure_cr = cairo_create(mangobar->measure_surface);
mangobar->measure_context =
pango_cairo_create_context(mangobar->measure_cr);
mangobar->measure_layout = pango_layout_new(mangobar->measure_context);
mangobar->measure_scale = 1.0f;
node->cached_scale = -1.0f;
node->last_text = NULL;
node->last_scale = 0.0f;
node->scene_buffer->node.data = mango_node_data;
mangobar->cached_scale = -1.0f;
mangobar->last_text = NULL;
mangobar->last_scale = 0.0f;
return node;
mangobar->type = type;
mangobar->node_data = cdata;
mangobar->scene_buffer->node.data = mangobar;
return mangobar;
}
void mango_tab_bar_node_destroy(struct mango_tab_bar_node *node) {
void mango_group_bar_destroy(MangoGroupBar *node) {
if (!node)
return;
@ -492,19 +524,17 @@ void mango_tab_bar_node_destroy(struct mango_tab_bar_node *node) {
if (node->measure_cr)
cairo_destroy(node->measure_cr);
void *data = node->scene_buffer->node.data;
wlr_scene_node_destroy(&node->scene_buffer->node);
g_free(node->font_desc);
g_free(node->cached_text);
g_free(node->cached_font_desc);
g_free(node->last_text);
free(data);
free(node);
}
void mango_tab_bar_node_set_size(struct mango_tab_bar_node *node, int32_t width,
int32_t height) {
void mango_group_bar_set_size(MangoGroupBar *node, int32_t width,
int32_t height) {
if (!node)
return;
@ -522,11 +552,11 @@ void mango_tab_bar_node_set_size(struct mango_tab_bar_node *node, int32_t width,
const char *redraw_text = node->last_text ? node->last_text : "";
float redraw_scale = node->last_scale > 0.0f ? node->last_scale : 1.0f;
mango_tab_bar_node_update(node, redraw_text, redraw_scale);
mango_group_bar_update(node, redraw_text, redraw_scale);
}
void mango_tab_bar_node_update(struct mango_tab_bar_node *node,
const char *text, float scale) {
void mango_group_bar_update(MangoGroupBar *node, const char *text,
float scale) {
if (!node || !text)
return;
if (scale <= 0.0f)
@ -538,7 +568,7 @@ void mango_tab_bar_node_update(struct mango_tab_bar_node *node,
node->last_text = safe_text; // 所有权转移
node->last_scale = scale;
// 脏检查加入 focused
// 脏检查
if (node->cached_scale == scale && node->cached_font_desc &&
strcmp(node->cached_font_desc, node->font_desc) == 0 &&
node->cached_text && strcmp(node->cached_text, safe_text) == 0 &&
@ -608,8 +638,18 @@ void mango_tab_bar_node_update(struct mango_tab_bar_node *node,
if (box_logical_h < 0)
box_logical_h = 0;
// surface 物理尺寸包含边框,避免边框绘制越界
int32_t required_pixel_w = (int32_t)(node->target_width * scale + 0.5f);
int32_t required_pixel_h = (int32_t)(node->target_height * scale + 0.5f);
// 如果边框会伸出 target 区域,则扩展 surface 尺寸以完全容纳
double border_phys = node->border_width * scale;
if (border_phys > 0.0) {
// 边框描边会向外延伸 half line width所以需要额外空间
int extra_w = (int32_t)ceil(border_phys * 0.5);
int extra_h = (int32_t)ceil(border_phys * 0.5);
required_pixel_w += extra_w;
required_pixel_h += extra_h;
}
if (required_pixel_w < 1)
required_pixel_w = 1;
if (required_pixel_h < 1)
@ -641,7 +681,6 @@ void mango_tab_bar_node_update(struct mango_tab_bar_node *node,
cairo_paint(cr);
cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
double border_phys = node->border_width * scale;
double bg_x = border_phys;
double bg_y = border_phys;
double bg_w = box_logical_w * scale;
@ -657,13 +696,15 @@ void mango_tab_bar_node_update(struct mango_tab_bar_node *node,
radius = bg_w / 2.0;
if (radius > bg_h / 2.0)
radius = bg_h / 2.0;
if (radius < 0.0)
radius = 0.0;
const float *active_bg =
node->focused ? node->focus_bg_color : node->bg_color;
const float *active_fg =
node->focused ? node->focus_fg_color : node->fg_color;
bool draw_bg = (active_bg[3] > 0.0f);
bool draw_bg = (active_bg[3] > 0.0f) && (bg_w > 0.0 && bg_h > 0.0);
bool draw_border =
(node->border_width > 0) && (node->border_color[3] > 0.0f);
@ -679,43 +720,46 @@ void mango_tab_bar_node_update(struct mango_tab_bar_node *node,
}
}
int32_t text_area_logical_w = box_logical_w - 2 * node->padding_x;
int32_t text_area_logical_h = box_logical_h - 2 * node->padding_y;
if (text_area_logical_w > 0 && text_area_logical_h > 0) {
cairo_save(cr);
// 仅在背景区域有空间时进行
if (bg_w > 0.0 && bg_h > 0.0) {
int32_t text_area_logical_w = box_logical_w - 2 * node->padding_x;
int32_t text_area_logical_h = box_logical_h - 2 * node->padding_y;
if (text_area_logical_w > 0 && text_area_logical_h > 0) {
cairo_save(cr);
double text_x = (node->border_width + node->padding_x) * scale;
double text_y = (node->border_width + node->padding_y) * scale;
double text_area_w = text_area_logical_w * scale;
double text_area_h = text_area_logical_h * scale;
double text_x = (node->border_width + node->padding_x) * scale;
double text_y = (node->border_width + node->padding_y) * scale;
double text_area_w = text_area_logical_w * scale;
double text_area_h = text_area_logical_h * scale;
PangoContext *ctx = pango_cairo_create_context(cr);
pango_cairo_context_set_resolution(ctx, 96.0 * scale);
PangoLayout *layout = pango_layout_new(ctx);
PangoFontDescription *desc = get_cached_font_desc(node->font_desc);
pango_layout_set_font_description(layout, desc);
pango_layout_set_text(layout, safe_text, -1);
PangoContext *ctx = pango_cairo_create_context(cr);
pango_cairo_context_set_resolution(ctx, 96.0 * scale);
PangoLayout *layout = pango_layout_new(ctx);
PangoFontDescription *desc = get_cached_font_desc(node->font_desc);
pango_layout_set_font_description(layout, desc);
pango_layout_set_text(layout, safe_text, -1);
pango_layout_set_wrap(layout, PANGO_WRAP_NONE);
pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_END);
pango_layout_set_alignment(layout, PANGO_ALIGN_CENTER);
pango_layout_set_width(layout, (int)(text_area_w * PANGO_SCALE));
pango_layout_set_wrap(layout, PANGO_WRAP_NONE);
pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_END);
pango_layout_set_alignment(layout, PANGO_ALIGN_CENTER);
pango_layout_set_width(layout, (int)(text_area_w * PANGO_SCALE));
int text_pixel_w, text_pixel_h;
pango_layout_get_pixel_size(layout, &text_pixel_w, &text_pixel_h);
double y_offset = (text_area_h - text_pixel_h) / 2.0;
if (y_offset < 0)
y_offset = 0;
int text_pixel_w, text_pixel_h;
pango_layout_get_pixel_size(layout, &text_pixel_w, &text_pixel_h);
double y_offset = (text_area_h - text_pixel_h) / 2.0;
if (y_offset < 0)
y_offset = 0;
cairo_translate(cr, text_x, text_y + y_offset);
cairo_translate(cr, text_x, text_y + y_offset);
cairo_set_source_rgba(cr, active_fg[0], active_fg[1], active_fg[2],
active_fg[3]);
pango_cairo_show_layout(cr, layout);
cairo_set_source_rgba(cr, active_fg[0], active_fg[1], active_fg[2],
active_fg[3]);
pango_cairo_show_layout(cr, layout);
g_object_unref(layout);
g_object_unref(ctx);
cairo_restore(cr);
g_object_unref(layout);
g_object_unref(ctx);
cairo_restore(cr);
}
}
if (draw_border) {
@ -729,15 +773,35 @@ void mango_tab_bar_node_update(struct mango_tab_bar_node *node,
double bw = bg_w + border_phys;
double bh = bg_h + border_phys;
if (radius > 0.0) {
double outer_radius = radius + half_lw;
if (outer_radius < 0.0)
outer_radius = 0.0;
draw_rounded_rect(cr, bx, by, bw, bh, outer_radius);
} else {
cairo_rectangle(cr, bx, by, bw, bh);
// 确保边框矩形不越界且宽高为正
if (bx < 0.0) {
bw += bx;
bx = 0.0;
}
if (by < 0.0) {
bh += by;
by = 0.0;
}
if (bx + bw > (double)node->surface_pixel_w)
bw = (double)node->surface_pixel_w - bx;
if (by + bh > (double)node->surface_pixel_h)
bh = (double)node->surface_pixel_h - by;
if (bw < 0.0)
bw = 0.0;
if (bh < 0.0)
bh = 0.0;
if (bw > 0.0 && bh > 0.0) {
if (radius > 0.0) {
double outer_radius = radius + half_lw;
if (outer_radius < 0.0)
outer_radius = 0.0;
draw_rounded_rect(cr, bx, by, bw, bh, outer_radius);
} else {
cairo_rectangle(cr, bx, by, bw, bh);
}
cairo_stroke(cr);
}
cairo_stroke(cr);
}
cairo_surface_flush(node->surface);
@ -765,19 +829,18 @@ void mango_tab_bar_node_update(struct mango_tab_bar_node *node,
node->logical_height);
}
void mango_tab_bar_node_set_focus(struct mango_tab_bar_node *node,
bool focused) {
void mango_group_bar_set_focus(MangoGroupBar *node, bool focused) {
if (!node || node->focused == focused)
return;
node->focused = focused;
if (node->last_text) {
float scale = node->last_scale > 0.0f ? node->last_scale : 1.0f;
mango_tab_bar_node_update(node, node->last_text, scale);
mango_group_bar_update(node, node->last_text, scale);
}
}
void mango_tab_bar_node_set_colors(struct mango_tab_bar_node *node,
const float fg[4], const float bg[4]) {
void mango_group_bar_set_colors(MangoGroupBar *node, const float fg[4],
const float bg[4]) {
if (!node)
return;
@ -786,11 +849,11 @@ void mango_tab_bar_node_set_colors(struct mango_tab_bar_node *node,
if (!node->focused && node->last_text) {
float scale = node->last_scale > 0.0f ? node->last_scale : 1.0f;
mango_tab_bar_node_update(node, node->last_text, scale);
mango_group_bar_update(node, node->last_text, scale);
}
}
void mango_jump_label_node_apply_config(struct mango_jump_label_node *node,
void mango_jump_label_node_apply_config(MangoJumpLabel *node,
const DecorateDrawData *data) {
if (!node || !data)
return;
@ -817,8 +880,8 @@ void mango_jump_label_node_apply_config(struct mango_jump_label_node *node,
}
}
void mango_tab_bar_node_apply_config(struct mango_tab_bar_node *node,
const DecorateDrawData *data) {
void mango_group_bar_apply_config(MangoGroupBar *node,
const DecorateDrawData *data) {
if (!node || !data)
return;
@ -840,6 +903,6 @@ void mango_tab_bar_node_apply_config(struct mango_tab_bar_node *node,
if (node->last_text) {
float scale = node->last_scale > 0.0f ? node->last_scale : 1.0f;
mango_tab_bar_node_update(node, node->last_text, scale);
mango_group_bar_update(node, node->last_text, scale);
}
}

View file

@ -26,8 +26,7 @@ struct mango_text_buffer {
struct wlr_buffer base;
cairo_surface_t *surface;
};
struct mango_jump_label_node {
typedef struct {
struct wlr_scene_buffer *scene_buffer;
struct mango_text_buffer *buffer;
cairo_surface_t *surface;
@ -70,13 +69,15 @@ struct mango_jump_label_node {
int32_t logical_width;
int32_t logical_height;
};
} MangoJumpLabel;
struct mango_tab_bar_node {
typedef struct {
uint32_t type; // must at first in struct
struct wlr_scene_buffer *scene_buffer;
struct mango_text_buffer *buffer;
cairo_surface_t *surface;
int surface_pixel_w, surface_pixel_h;
void *node_data; // 存储窗口指针
// 初始配置
float fg_color[4];
@ -126,41 +127,38 @@ struct mango_tab_bar_node {
int32_t logical_width;
int32_t logical_height;
};
} MangoGroupBar;
void mango_text_global_finish(void);
struct mango_jump_label_node *
mango_jump_label_node_create(struct wlr_scene_tree *parent,
DecorateDrawData data);
void mango_jump_label_node_destroy(struct mango_jump_label_node *node);
void mango_jump_label_node_set_background(struct mango_jump_label_node *node,
float r, float g, float b, float a);
void mango_jump_label_node_set_border(struct mango_jump_label_node *node,
float r, float g, float b, float a,
int32_t width, int32_t radius);
void mango_jump_label_node_set_padding(struct mango_jump_label_node *node,
int32_t pad_x, int32_t pad_y);
void mango_jump_label_node_update(struct mango_jump_label_node *node,
const char *text, float scale);
MangoJumpLabel *mango_jump_label_node_create(struct wlr_scene_tree *parent,
DecorateDrawData data);
void mango_jump_label_node_destroy(MangoJumpLabel *node);
void mango_jump_label_node_set_background(MangoJumpLabel *node, float r,
float g, float b, float a);
void mango_jump_label_node_set_border(MangoJumpLabel *node, float r, float g,
float b, float a, int32_t width,
int32_t radius);
void mango_jump_label_node_set_padding(MangoJumpLabel *node, int32_t pad_x,
int32_t pad_y);
void mango_jump_label_node_update(MangoJumpLabel *node, const char *text,
float scale);
struct mango_tab_bar_node *
mango_tab_bar_node_create(void *mango_node_data, struct wlr_scene_tree *parent,
DecorateDrawData data, int32_t width, int32_t height);
void mango_tab_bar_node_destroy(struct mango_tab_bar_node *node);
void mango_tab_bar_node_set_size(struct mango_tab_bar_node *node, int32_t width,
int32_t height);
void mango_tab_bar_node_update(struct mango_tab_bar_node *node,
const char *text, float scale);
MangoGroupBar *mango_group_bar_create(void *cdata, uint32_t type,
struct wlr_scene_tree *parent,
DecorateDrawData data, int32_t width,
int32_t height);
void mango_group_bar_destroy(MangoGroupBar *node);
void mango_group_bar_set_size(MangoGroupBar *node, int32_t width,
int32_t height);
void mango_group_bar_update(MangoGroupBar *node, const char *text, float scale);
void mango_jump_label_node_set_focus(struct mango_jump_label_node *node,
bool focused);
void mango_tab_bar_node_set_focus(struct mango_tab_bar_node *node,
bool focused);
void mango_jump_label_node_set_focus(MangoJumpLabel *node, bool focused);
void mango_group_bar_set_focus(MangoGroupBar *node, bool focused);
void mango_tab_bar_node_set_colors(struct mango_tab_bar_node *node,
const float fg[4], const float bg[4]);
void mango_jump_label_node_apply_config(struct mango_jump_label_node *node,
void mango_group_bar_set_colors(MangoGroupBar *node, const float fg[4],
const float bg[4]);
void mango_jump_label_node_apply_config(MangoJumpLabel *node,
const DecorateDrawData *data);
void mango_tab_bar_node_apply_config(struct mango_tab_bar_node *node,
const DecorateDrawData *data);
void mango_group_bar_apply_config(MangoGroupBar *node,
const DecorateDrawData *data);
#endif // jump_label_node_H

View file

@ -1,6 +1,6 @@
#include "dwl-ipc.h"
#include "ext-workspace.h"
#include "foreign-toplevel.h"
#include "hdr.h"
#include "tablet.h"
#include "tearing.h"
#include "text-input.h"

View file

@ -1,309 +0,0 @@
#include "dwl-ipc-unstable-v2-protocol.h"
static void dwl_ipc_manager_bind(struct wl_client *client, void *data,
uint32_t version, uint32_t id);
static void dwl_ipc_manager_destroy(struct wl_resource *resource);
static void dwl_ipc_manager_get_output(struct wl_client *client,
struct wl_resource *resource,
uint32_t id, struct wl_resource *output);
static void dwl_ipc_manager_release(struct wl_client *client,
struct wl_resource *resource);
static void dwl_ipc_output_destroy(struct wl_resource *resource);
static void dwl_ipc_output_printstatus(Monitor *monitor);
static void dwl_ipc_output_printstatus_to(DwlIpcOutput *ipc_output);
static void dwl_ipc_output_set_client_tags(struct wl_client *client,
struct wl_resource *resource,
uint32_t and_tags,
uint32_t xor_tags);
static void dwl_ipc_output_set_layout(struct wl_client *client,
struct wl_resource *resource,
uint32_t index);
static void dwl_ipc_output_set_tags(struct wl_client *client,
struct wl_resource *resource,
uint32_t tagmask, uint32_t toggle_tagset);
static void dwl_ipc_output_quit(struct wl_client *client,
struct wl_resource *resource);
static void dwl_ipc_output_dispatch(struct wl_client *client,
struct wl_resource *resource,
const char *dispatch, const char *arg1,
const char *arg2, const char *arg3,
const char *arg4, const char *arg5);
static void dwl_ipc_output_release(struct wl_client *client,
struct wl_resource *resource);
/* global event handlers */
static struct zdwl_ipc_manager_v2_interface dwl_manager_implementation = {
.release = dwl_ipc_manager_release,
.get_output = dwl_ipc_manager_get_output};
static struct zdwl_ipc_output_v2_interface dwl_output_implementation = {
.release = dwl_ipc_output_release,
.set_tags = dwl_ipc_output_set_tags,
.quit = dwl_ipc_output_quit,
.dispatch = dwl_ipc_output_dispatch,
.set_layout = dwl_ipc_output_set_layout,
.set_client_tags = dwl_ipc_output_set_client_tags};
void dwl_ipc_manager_bind(struct wl_client *client, void *data,
uint32_t version, uint32_t id) {
struct wl_resource *manager_resource =
wl_resource_create(client, &zdwl_ipc_manager_v2_interface, version, id);
if (!manager_resource) {
wl_client_post_no_memory(client);
return;
}
wl_resource_set_implementation(manager_resource,
&dwl_manager_implementation, NULL,
dwl_ipc_manager_destroy);
zdwl_ipc_manager_v2_send_tags(manager_resource, LENGTH(tags));
for (uint32_t i = 0; i < LENGTH(layouts); i++)
zdwl_ipc_manager_v2_send_layout(manager_resource, layouts[i].symbol);
}
void dwl_ipc_manager_destroy(struct wl_resource *resource) {
/* No state to destroy */
}
void dwl_ipc_manager_get_output(struct wl_client *client,
struct wl_resource *resource, uint32_t id,
struct wl_resource *output) {
DwlIpcOutput *ipc_output;
struct wlr_output *op = wlr_output_from_resource(output);
if (!op)
return;
Monitor *monitor = op->data;
struct wl_resource *output_resource =
wl_resource_create(client, &zdwl_ipc_output_v2_interface,
wl_resource_get_version(resource), id);
if (!output_resource)
return;
ipc_output = ecalloc(1, sizeof(*ipc_output));
ipc_output->resource = output_resource;
ipc_output->mon = monitor;
wl_resource_set_implementation(output_resource, &dwl_output_implementation,
ipc_output, dwl_ipc_output_destroy);
wl_list_insert(&monitor->dwl_ipc_outputs, &ipc_output->link);
dwl_ipc_output_printstatus_to(ipc_output);
}
void dwl_ipc_manager_release(struct wl_client *client,
struct wl_resource *resource) {
wl_resource_destroy(resource);
}
static void dwl_ipc_output_destroy(struct wl_resource *resource) {
DwlIpcOutput *ipc_output = wl_resource_get_user_data(resource);
wl_list_remove(&ipc_output->link);
free(ipc_output);
}
// 修改IPC输出函数接受掩码参数
void dwl_ipc_output_printstatus(Monitor *monitor) {
DwlIpcOutput *ipc_output;
wl_list_for_each(ipc_output, &monitor->dwl_ipc_outputs, link)
dwl_ipc_output_printstatus_to(ipc_output);
}
// 修改主IPC输出函数根据掩码发送相应事件
void dwl_ipc_output_printstatus_to(DwlIpcOutput *ipc_output) {
Monitor *monitor = ipc_output->mon;
Client *c = NULL, *focused = NULL;
struct wlr_keyboard *keyboard;
xkb_layout_index_t current;
int32_t tagmask, state, numclients, focused_client, tag;
const char *title, *appid, *symbol;
char kb_layout[32];
focused = focustop(monitor);
zdwl_ipc_output_v2_send_active(ipc_output->resource, monitor == selmon);
for (tag = 0; tag < LENGTH(tags); tag++) {
numclients = state = focused_client = 0;
tagmask = 1 << tag;
if ((tagmask & monitor->tagset[monitor->seltags]) != 0)
state |= ZDWL_IPC_OUTPUT_V2_TAG_STATE_ACTIVE;
wl_list_for_each(c, &clients, link) {
if (c->mon != monitor)
continue;
if (!(c->tags & tagmask))
continue;
if (c == focused)
focused_client = 1;
if (c->isurgent)
state |= ZDWL_IPC_OUTPUT_V2_TAG_STATE_URGENT;
numclients++;
}
zdwl_ipc_output_v2_send_tag(ipc_output->resource, tag, state,
numclients, focused_client);
}
title = focused ? client_get_title(focused) : "";
appid = focused ? client_get_appid(focused) : "";
if (monitor->isoverview) {
symbol = overviewlayout.symbol;
} else {
symbol = monitor->pertag->ltidxs[monitor->pertag->curtag]->symbol;
}
keyboard = &kb_group->wlr_group->keyboard;
current = xkb_state_serialize_layout(keyboard->xkb_state,
XKB_STATE_LAYOUT_EFFECTIVE);
get_layout_abbr(kb_layout,
xkb_keymap_layout_get_name(keyboard->keymap, current));
zdwl_ipc_output_v2_send_layout(
ipc_output->resource,
monitor->pertag->ltidxs[monitor->pertag->curtag] - layouts);
zdwl_ipc_output_v2_send_title(ipc_output->resource, title ? title : broken);
zdwl_ipc_output_v2_send_appid(ipc_output->resource, appid ? appid : broken);
zdwl_ipc_output_v2_send_layout_symbol(ipc_output->resource, symbol);
if (wl_resource_get_version(ipc_output->resource) >=
ZDWL_IPC_OUTPUT_V2_FULLSCREEN_SINCE_VERSION) {
zdwl_ipc_output_v2_send_fullscreen(ipc_output->resource,
focused ? focused->isfullscreen : 0);
}
if (wl_resource_get_version(ipc_output->resource) >=
ZDWL_IPC_OUTPUT_V2_FLOATING_SINCE_VERSION) {
zdwl_ipc_output_v2_send_floating(ipc_output->resource,
focused ? focused->isfloating : 0);
}
if (wl_resource_get_version(ipc_output->resource) >=
ZDWL_IPC_OUTPUT_V2_X_SINCE_VERSION) {
zdwl_ipc_output_v2_send_x(ipc_output->resource,
focused ? focused->geom.x : 0);
}
if (wl_resource_get_version(ipc_output->resource) >=
ZDWL_IPC_OUTPUT_V2_Y_SINCE_VERSION) {
zdwl_ipc_output_v2_send_y(ipc_output->resource,
focused ? focused->geom.y : 0);
}
if (wl_resource_get_version(ipc_output->resource) >=
ZDWL_IPC_OUTPUT_V2_WIDTH_SINCE_VERSION) {
zdwl_ipc_output_v2_send_width(ipc_output->resource,
focused ? focused->geom.width : 0);
}
if (wl_resource_get_version(ipc_output->resource) >=
ZDWL_IPC_OUTPUT_V2_HEIGHT_SINCE_VERSION) {
zdwl_ipc_output_v2_send_height(ipc_output->resource,
focused ? focused->geom.height : 0);
}
if (wl_resource_get_version(ipc_output->resource) >=
ZDWL_IPC_OUTPUT_V2_LAST_LAYER_SINCE_VERSION) {
zdwl_ipc_output_v2_send_last_layer(ipc_output->resource,
monitor->last_open_surface);
}
if (wl_resource_get_version(ipc_output->resource) >=
ZDWL_IPC_OUTPUT_V2_KB_LAYOUT_SINCE_VERSION) {
zdwl_ipc_output_v2_send_kb_layout(ipc_output->resource, kb_layout);
}
if (wl_resource_get_version(ipc_output->resource) >=
ZDWL_IPC_OUTPUT_V2_KEYMODE_SINCE_VERSION) {
zdwl_ipc_output_v2_send_keymode(ipc_output->resource, keymode.mode);
}
if (wl_resource_get_version(ipc_output->resource) >=
ZDWL_IPC_OUTPUT_V2_SCALEFACTOR_SINCE_VERSION) {
zdwl_ipc_output_v2_send_scalefactor(ipc_output->resource,
monitor->wlr_output->scale * 100);
}
zdwl_ipc_output_v2_send_frame(ipc_output->resource);
}
void dwl_ipc_output_set_client_tags(struct wl_client *client,
struct wl_resource *resource,
uint32_t and_tags, uint32_t xor_tags) {
DwlIpcOutput *ipc_output;
Monitor *monitor = NULL;
Client *selected_client = NULL;
uint32_t newtags = 0;
ipc_output = wl_resource_get_user_data(resource);
if (!ipc_output)
return;
monitor = ipc_output->mon;
selected_client = focustop(monitor);
if (!selected_client)
return;
newtags = (selected_client->tags & and_tags) ^ xor_tags;
if (!newtags)
return;
selected_client->tags = newtags;
if (selmon == monitor)
focusclient(focustop(monitor), 1);
arrange(selmon, false, false);
printstatus(IPC_WATCH_ARRANGGE);
}
void dwl_ipc_output_set_layout(struct wl_client *client,
struct wl_resource *resource, uint32_t index) {
DwlIpcOutput *ipc_output;
Monitor *monitor = NULL;
ipc_output = wl_resource_get_user_data(resource);
if (!ipc_output)
return;
monitor = ipc_output->mon;
if (index >= LENGTH(layouts))
index = 0;
monitor->pertag->ltidxs[monitor->pertag->curtag] = &layouts[index];
clear_fullscreen_and_maximized_state(monitor);
arrange(monitor, false, false);
printstatus(IPC_WATCH_ARRANGGE);
}
void dwl_ipc_output_set_tags(struct wl_client *client,
struct wl_resource *resource, uint32_t tagmask,
uint32_t toggle_tagset) {
DwlIpcOutput *ipc_output;
Monitor *monitor = NULL;
uint32_t newtags = tagmask & TAGMASK;
ipc_output = wl_resource_get_user_data(resource);
if (!ipc_output)
return;
monitor = ipc_output->mon;
view_in_mon(&(Arg){.ui = newtags}, true, monitor, true);
}
void dwl_ipc_output_quit(struct wl_client *client,
struct wl_resource *resource) {
quit(&(Arg){0});
}
void dwl_ipc_output_dispatch(struct wl_client *client,
struct wl_resource *resource, const char *dispatch,
const char *arg1, const char *arg2,
const char *arg3, const char *arg4,
const char *arg5) {
int32_t (*func)(const Arg *);
Arg arg;
func = parse_func_name((char *)dispatch, &arg, (char *)arg1, (char *)arg2,
(char *)arg3, (char *)arg4, (char *)arg5);
if (func) {
func(&arg);
}
if (arg.v)
free(arg.v);
if (arg.v2)
free(arg.v2);
if (arg.v3)
free(arg.v3);
}
void dwl_ipc_output_release(struct wl_client *client,
struct wl_resource *resource) {
wl_resource_destroy(resource);
}

View file

@ -1,4 +1,4 @@
#include "wlr_ext_workspace_v1.h"
#include <wlr/types/wlr_ext_workspace_v1.h>
#define EXT_WORKSPACE_ENABLE_CAPS \
EXT_WORKSPACE_HANDLE_V1_WORKSPACE_CAPABILITIES_ACTIVATE | \
@ -148,7 +148,7 @@ static void add_workspace_by_tag(int32_t tag, Monitor *m) {
wlr_ext_workspace_handle_v1_set_name(workspace->ext_workspace, name);
}
void dwl_ext_workspace_printstatus(Monitor *m) {
void mango_ext_workspace_printstatus(Monitor *m) {
struct workspace *w;
uint32_t tag_status = 0;
@ -199,7 +199,7 @@ void refresh_monitors_workspaces_status(Monitor *m) {
}
}
dwl_ext_workspace_printstatus(m);
mango_ext_workspace_printstatus(m);
}
void workspaces_init() {

View file

@ -12,7 +12,7 @@ void handle_foreign_maximize_request(struct wl_listener *listener, void *data) {
Client *c = wl_container_of(listener, c, foreign_maximize_request);
struct wlr_foreign_toplevel_handle_v1_maximized_event *event = data;
if (c->swallowing || !c->mon)
if (c->swallowdby || !c->mon)
return;
if (c->ismaximizescreen && !event->maximized) {
@ -30,7 +30,7 @@ void handle_foreign_minimize_request(struct wl_listener *listener, void *data) {
Client *c = wl_container_of(listener, c, foreign_minimize_request);
struct wlr_foreign_toplevel_handle_v1_minimized_event *event = data;
if (c->swallowing || !c->mon)
if (c->swallowdby || !c->mon)
return;
if (!c->isminimized && event->minimized) {
@ -55,7 +55,7 @@ void handle_foreign_fullscreen_request(struct wl_listener *listener,
Client *c = wl_container_of(listener, c, foreign_fullscreen_request);
struct wlr_foreign_toplevel_handle_v1_fullscreen_event *event = data;
if (c->swallowing || !c->mon)
if (c->swallowdby || !c->mon)
return;
if (c->isfullscreen && !event->fullscreen) {

131
src/ext-protocol/hdr.h Normal file
View file

@ -0,0 +1,131 @@
#include <drm_fourcc.h>
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
static uint32_t output_formats_8bit[] = {
DRM_FORMAT_XRGB8888, DRM_FORMAT_XBGR8888, DRM_FORMAT_RGBX8888,
DRM_FORMAT_BGRX8888, DRM_FORMAT_ARGB8888, DRM_FORMAT_ABGR8888,
DRM_FORMAT_RGBA8888, DRM_FORMAT_BGRA8888, DRM_FORMAT_RGB888,
DRM_FORMAT_BGR888,
};
static uint32_t output_formats_10bit[] = {
DRM_FORMAT_XRGB2101010, DRM_FORMAT_XBGR2101010, DRM_FORMAT_RGBX1010102,
DRM_FORMAT_BGRX1010102, DRM_FORMAT_ARGB2101010, DRM_FORMAT_ABGR2101010,
DRM_FORMAT_RGBA1010102, DRM_FORMAT_BGRA1010102,
};
static bool output_set_render_format(Monitor *m, uint32_t candidates[],
size_t count,
struct wlr_output_state *state) {
for (size_t i = 0; i < count; i++) {
wlr_output_state_set_render_format(state, candidates[i]);
if (wlr_output_test_state(m->wlr_output, state))
return true;
}
return false;
}
static bool output_format_in_candidates(uint32_t format, uint32_t candidates[],
size_t count) {
for (size_t i = 0; i < count; i++)
if (candidates[i] == format)
return true;
return false;
}
static enum render_bit_depth bit_depth_from_format(uint32_t render_format) {
if (output_format_in_candidates(render_format, output_formats_10bit,
ARRAY_SIZE(output_formats_10bit)))
return MANGO_RENDER_BIT_DEPTH_10;
if (output_format_in_candidates(render_format, output_formats_8bit,
ARRAY_SIZE(output_formats_8bit)))
return MANGO_RENDER_BIT_DEPTH_8;
return MANGO_RENDER_BIT_DEPTH_DEFAULT;
}
static bool output_supports_hdr(const struct wlr_output *output,
const char **reason) {
const char *r = NULL;
if (!(output->supported_primaries & WLR_COLOR_NAMED_PRIMARIES_BT2020))
r = "BT2020 primaries not supported";
else if (!(output->supported_transfer_functions &
WLR_COLOR_TRANSFER_FUNCTION_ST2084_PQ))
r = "PQ transfer function not supported";
else if (!drw->features.output_color_transform)
r = "renderer doesn't support output color transforms";
if (reason)
*reason = r;
return !r;
}
void output_enable_hdr(Monitor *m, struct wlr_output_state *os, bool enabled,
bool silent) {
if (enabled && !output_supports_hdr(m->wlr_output, NULL))
enabled = false;
if (!enabled) {
if (m->wlr_output->supported_primaries ||
m->wlr_output->supported_transfer_functions) {
if (!silent)
wlr_log(WLR_DEBUG, "Disabling HDR on output %s",
m->wlr_output->name);
wlr_output_state_set_image_description(os, NULL);
}
return;
}
if (!silent)
wlr_log(WLR_DEBUG, "Enabling HDR on output %s", m->wlr_output->name);
struct wlr_output_image_description desc = {
.primaries = WLR_COLOR_NAMED_PRIMARIES_BT2020,
.transfer_function = WLR_COLOR_TRANSFER_FUNCTION_ST2084_PQ,
};
wlr_output_state_set_image_description(os, &desc);
}
void output_state_setup_hdr(Monitor *m, bool silent,
struct wlr_output_state *state) {
uint32_t render_format = m->wlr_output->render_format;
const char *unsupported_reason = NULL;
bool hdr_supported =
output_supports_hdr(m->wlr_output, &unsupported_reason);
bool hdr_succeeded = false;
enum render_bit_depth depth = config.hdr_depth;
if (depth == MANGO_RENDER_BIT_DEPTH_DEFAULT)
depth = bit_depth_from_format(render_format);
if (!hdr_supported && depth == MANGO_RENDER_BIT_DEPTH_10) {
if (!silent)
wlr_log(WLR_INFO, "Cannot enable HDR on output %s: %s",
m->wlr_output->name, unsupported_reason);
depth = MANGO_RENDER_BIT_DEPTH_8;
}
if (depth == MANGO_RENDER_BIT_DEPTH_10 &&
bit_depth_from_format(render_format) == depth) {
hdr_succeeded = true; // 上次已经成功设置10位直接复用
} else if (depth == MANGO_RENDER_BIT_DEPTH_10) {
hdr_succeeded = output_set_render_format(
m, output_formats_10bit, ARRAY_SIZE(output_formats_10bit), state);
if (!hdr_succeeded) {
if (!silent)
wlr_log(WLR_INFO,
"No 10 bit color formats supported, HDR disabled.");
if (!output_set_render_format(m, output_formats_8bit,
ARRAY_SIZE(output_formats_8bit),
state))
if (!silent)
wlr_log(WLR_ERROR, "No 8 bit color formats either!");
}
} else {
// 明确要求8位或自动降级
if (!output_set_render_format(m, output_formats_8bit,
ARRAY_SIZE(output_formats_8bit), state))
if (!silent)
wlr_log(WLR_ERROR, "No 8 bit color formats supported!");
}
output_enable_hdr(m, state, hdr_succeeded, silent);
}

View file

@ -281,7 +281,7 @@ void tablettoolmotion(struct TabletTool *tool, bool change_x, bool change_y,
if (config.sloppyfocus)
selmon = xytomon(cursor->x, cursor->y);
xytonode(cursor->x, cursor->y, &surface, &c, NULL, &sx, &sy);
xytonode(cursor->x, cursor->y, &surface, &c, NULL, NULL, &sx, &sy);
if (cursor_mode == CurPressed && !seat->drag &&
surface != seat->pointer_state.focused_surface &&
toplevel_from_wlr_surface(seat->pointer_state.focused_surface, &w,

View file

@ -1,3 +1,4 @@
#include <stdbool.h>
#include <wlr/types/wlr_tearing_control_v1.h>
struct tearing_controller {
@ -64,6 +65,9 @@ bool check_tearing_frame_allow(Monitor *m) {
return false;
}
if (!selmon)
return false;
Client *c = selmon->sel;
/* tearing is only allowed for the output with the active client */
@ -94,79 +98,3 @@ bool check_tearing_frame_allow(Monitor *m) {
/* honor tearing as requested by action */
return c->force_tearing == STATE_ENABLED;
}
bool custom_wlr_scene_output_commit(struct wlr_scene_output *scene_output,
struct wlr_output_state *state) {
struct wlr_output *wlr_output = scene_output->output;
Monitor *m = wlr_output->data;
// 检查是否需要帧
if (!wlr_scene_output_needs_frame(scene_output)) {
wlr_log(WLR_DEBUG, "No frame needed for output %s", wlr_output->name);
return true;
}
// 构建输出状态
if (!wlr_scene_output_build_state(scene_output, state, NULL)) {
wlr_log(WLR_ERROR, "Failed to build output state for %s",
wlr_output->name);
return false;
}
// 测试撕裂翻页
if (state->tearing_page_flip) {
if (!wlr_output_test_state(wlr_output, state)) {
state->tearing_page_flip = false;
}
}
// 尝试提交
bool committed = wlr_output_commit_state(wlr_output, state);
// 如果启用撕裂翻页但提交失败,重试禁用撕裂翻页
if (!committed && state->tearing_page_flip) {
wlr_log(WLR_DEBUG, "Retrying commit without tearing for %s",
wlr_output->name);
state->tearing_page_flip = false;
committed = wlr_output_commit_state(wlr_output, state);
}
// 处理状态清理
if (committed) {
wlr_log(WLR_DEBUG, "Successfully committed output %s",
wlr_output->name);
if (state == &m->pending) {
wlr_output_state_finish(&m->pending);
wlr_output_state_init(&m->pending);
}
} else {
wlr_log(WLR_ERROR, "Failed to commit output %s", wlr_output->name);
// 即使提交失败,也清理状态避免积累
if (state == &m->pending) {
wlr_output_state_finish(&m->pending);
wlr_output_state_init(&m->pending);
}
return false;
}
return true;
}
void apply_tear_state(Monitor *m) {
if (wlr_scene_output_needs_frame(m->scene_output)) {
wlr_output_state_init(&m->pending);
if (wlr_scene_output_build_state(m->scene_output, &m->pending, NULL)) {
struct wlr_output_state *pending = &m->pending;
pending->tearing_page_flip = true;
if (!custom_wlr_scene_output_commit(m->scene_output, pending)) {
wlr_log(WLR_ERROR, "Failed to commit output %s",
m->scene_output->output->name);
}
} else {
wlr_log(WLR_ERROR, "Failed to build state for output %s",
m->scene_output->output->name);
wlr_output_state_finish(&m->pending);
}
}
}

View file

@ -2,7 +2,7 @@
#include <wlr/types/wlr_input_method_v2.h>
#include <wlr/types/wlr_text_input_v3.h>
struct dwl_input_method_relay {
struct mango_input_method_relay {
struct wl_list text_inputs;
struct wlr_input_method_v2 *input_method;
struct wlr_surface *focused_surface;
@ -26,11 +26,12 @@ struct dwl_input_method_relay {
struct wl_listener focused_surface_destroy;
};
struct dwl_input_method_popup {
struct mango_input_method_popup {
uint32_t type; // must at first in struct
struct wlr_input_popup_surface_v2 *popup_surface;
struct wlr_scene_tree *tree;
struct wlr_scene_tree *scene_surface;
struct dwl_input_method_relay *relay;
struct mango_input_method_relay *relay;
struct wl_list link;
struct wl_listener destroy;
@ -38,7 +39,7 @@ struct dwl_input_method_popup {
};
struct text_input {
struct dwl_input_method_relay *relay;
struct mango_input_method_relay *relay;
struct wlr_text_input_v3 *input;
struct wl_list link;
@ -50,20 +51,20 @@ struct text_input {
struct wlr_input_method_manager_v2 *input_method_manager;
struct wlr_text_input_manager_v3 *text_input_manager;
struct dwl_input_method_relay *dwl_input_method_relay;
struct mango_input_method_relay *mango_input_method_relay;
/*-------------------封装给外部调用-------------------------------*/
bool dwl_im_keyboard_grab_forward_key(KeyboardGroup *keyboard,
struct wlr_keyboard_key_event *event);
bool mango_im_keyboard_grab_forward_key(KeyboardGroup *keyboard,
struct wlr_keyboard_key_event *event);
bool dwl_im_keyboard_grab_forward_modifiers(KeyboardGroup *keyboard);
bool mango_im_keyboard_grab_forward_modifiers(KeyboardGroup *keyboard);
struct dwl_input_method_relay *dwl_im_relay_create();
struct mango_input_method_relay *mango_im_relay_create();
void dwl_im_relay_finish(struct dwl_input_method_relay *relay);
void mango_im_relay_finish(struct mango_input_method_relay *relay);
void dwl_im_relay_set_focus(struct dwl_input_method_relay *relay,
struct wlr_surface *surface);
void mango_im_relay_set_focus(struct mango_input_method_relay *relay,
struct wlr_surface *surface);
/*----------------------------------------------------------*/
/*------------------协议内部代码------------------------------*/
@ -97,7 +98,7 @@ is_keyboard_emulated_by_input_method(struct wlr_keyboard *keyboard,
static struct wlr_input_method_keyboard_grab_v2 *
get_keyboard_grab(KeyboardGroup *keyboard) {
struct wlr_input_method_v2 *input_method =
dwl_input_method_relay->input_method;
mango_input_method_relay->input_method;
if (!input_method || !input_method->keyboard_grab) {
return NULL;
}
@ -114,7 +115,7 @@ get_keyboard_grab(KeyboardGroup *keyboard) {
return input_method->keyboard_grab;
}
bool dwl_im_keyboard_grab_forward_modifiers(KeyboardGroup *keyboard) {
bool mango_im_keyboard_grab_forward_modifiers(KeyboardGroup *keyboard) {
struct wlr_input_method_keyboard_grab_v2 *keyboard_grab =
get_keyboard_grab(keyboard);
@ -132,8 +133,8 @@ bool dwl_im_keyboard_grab_forward_modifiers(KeyboardGroup *keyboard) {
}
}
bool dwl_im_keyboard_grab_forward_key(KeyboardGroup *keyboard,
struct wlr_keyboard_key_event *event) {
bool mango_im_keyboard_grab_forward_key(KeyboardGroup *keyboard,
struct wlr_keyboard_key_event *event) {
struct wlr_input_method_keyboard_grab_v2 *keyboard_grab =
get_keyboard_grab(keyboard);
@ -149,7 +150,7 @@ bool dwl_im_keyboard_grab_forward_key(KeyboardGroup *keyboard,
}
static struct text_input *
get_active_text_input(struct dwl_input_method_relay *relay) {
get_active_text_input(struct mango_input_method_relay *relay) {
struct text_input *text_input;
if (!relay->input_method) {
@ -164,7 +165,7 @@ get_active_text_input(struct dwl_input_method_relay *relay) {
return NULL;
}
static void update_active_text_input(struct dwl_input_method_relay *relay) {
static void update_active_text_input(struct mango_input_method_relay *relay) {
struct text_input *active_text_input = get_active_text_input(relay);
if (relay->input_method && relay->active_text_input != active_text_input) {
@ -180,7 +181,7 @@ static void update_active_text_input(struct dwl_input_method_relay *relay) {
}
static void
update_text_inputs_focused_surface(struct dwl_input_method_relay *relay) {
update_text_inputs_focused_surface(struct mango_input_method_relay *relay) {
struct text_input *text_input;
wl_list_for_each(text_input, &relay->text_inputs, link) {
struct wlr_text_input_v3 *input = text_input->input;
@ -206,8 +207,8 @@ update_text_inputs_focused_surface(struct dwl_input_method_relay *relay) {
}
}
static void update_popup_position(struct dwl_input_method_popup *popup) {
struct dwl_input_method_relay *relay = popup->relay;
static void update_popup_position(struct mango_input_method_popup *popup) {
struct mango_input_method_relay *relay = popup->relay;
struct text_input *text_input = relay->active_text_input;
struct wlr_box cursor_rect;
struct wlr_xdg_surface *xdg_surface;
@ -281,8 +282,8 @@ static void update_popup_position(struct dwl_input_method_popup *popup) {
});
}
static void update_popups_position(struct dwl_input_method_relay *relay) {
struct dwl_input_method_popup *popup;
static void update_popups_position(struct mango_input_method_relay *relay) {
struct mango_input_method_popup *popup;
wl_list_for_each(popup, &relay->popups, link) {
update_popup_position(popup);
}
@ -290,11 +291,10 @@ static void update_popups_position(struct dwl_input_method_relay *relay) {
static void handle_input_method_commit(struct wl_listener *listener,
void *data) {
struct dwl_input_method_relay *relay =
struct mango_input_method_relay *relay =
wl_container_of(listener, relay, input_method_commit);
struct wlr_input_method_v2 *input_method = data;
struct text_input *text_input;
assert(relay->input_method == input_method);
struct wlr_input_method_v2 *input_method = relay->input_method;
text_input = relay->active_text_input;
if (!text_input) {
@ -322,9 +322,10 @@ static void handle_input_method_commit(struct wl_listener *listener,
static void handle_keyboard_grab_destroy(struct wl_listener *listener,
void *data) {
struct dwl_input_method_relay *relay =
struct mango_input_method_relay *relay =
wl_container_of(listener, relay, keyboard_grab_destroy);
struct wlr_input_method_keyboard_grab_v2 *keyboard_grab = data;
struct wlr_input_method_keyboard_grab_v2 *keyboard_grab =
relay->input_method->keyboard_grab;
wl_list_remove(&relay->keyboard_grab_destroy.link);
if (keyboard_grab->keyboard) {
@ -335,7 +336,7 @@ static void handle_keyboard_grab_destroy(struct wl_listener *listener,
static void handle_input_method_grab_keyboard(struct wl_listener *listener,
void *data) {
struct dwl_input_method_relay *relay =
struct mango_input_method_relay *relay =
wl_container_of(listener, relay, input_method_grab_keyboard);
struct wlr_input_method_keyboard_grab_v2 *keyboard_grab = data;
@ -354,9 +355,8 @@ static void handle_input_method_grab_keyboard(struct wl_listener *listener,
static void handle_input_method_destroy(struct wl_listener *listener,
void *data) {
struct dwl_input_method_relay *relay =
struct mango_input_method_relay *relay =
wl_container_of(listener, relay, input_method_destroy);
assert(relay->input_method == data);
wl_list_remove(&relay->input_method_commit.link);
wl_list_remove(&relay->input_method_grab_keyboard.link);
wl_list_remove(&relay->input_method_new_popup_surface.link);
@ -369,7 +369,7 @@ static void handle_input_method_destroy(struct wl_listener *listener,
static void handle_popup_surface_destroy(struct wl_listener *listener,
void *data) {
struct dwl_input_method_popup *popup =
struct mango_input_method_popup *popup =
wl_container_of(listener, popup, destroy);
wlr_scene_node_destroy(&popup->tree->node);
wl_list_remove(&popup->destroy.link);
@ -380,18 +380,18 @@ static void handle_popup_surface_destroy(struct wl_listener *listener,
static void handle_popup_surface_commit(struct wl_listener *listener,
void *data) {
struct dwl_input_method_popup *popup =
struct mango_input_method_popup *popup =
wl_container_of(listener, popup, commit);
update_popup_position(popup);
}
static void handle_input_method_new_popup_surface(struct wl_listener *listener,
void *data) {
struct dwl_input_method_relay *relay =
struct mango_input_method_relay *relay =
wl_container_of(listener, relay, input_method_new_popup_surface);
struct dwl_input_method_popup *popup =
ecalloc(1, sizeof(struct dwl_input_method_popup));
struct mango_input_method_popup *popup =
ecalloc(1, sizeof(struct mango_input_method_popup));
popup->popup_surface = data;
popup->relay = relay;
@ -405,6 +405,8 @@ static void handle_input_method_new_popup_surface(struct wl_listener *listener,
popup->tree = wlr_scene_tree_create(layers[LyrIMPopup]);
popup->scene_surface = wlr_scene_subsurface_tree_create(
popup->tree, popup->popup_surface->surface);
popup->type = XdgImPopup;
popup->scene_surface->node.data = popup;
wl_list_insert(&relay->popups, &popup->link);
@ -413,7 +415,7 @@ static void handle_input_method_new_popup_surface(struct wl_listener *listener,
}
static void handle_new_input_method(struct wl_listener *listener, void *data) {
struct dwl_input_method_relay *relay =
struct mango_input_method_relay *relay =
wl_container_of(listener, relay, new_input_method);
struct wlr_input_method_v2 *input_method = data;
if (seat != input_method->seat) {
@ -449,7 +451,7 @@ static void handle_new_input_method(struct wl_listener *listener, void *data) {
update_active_text_input(relay);
}
static void send_state_to_input_method(struct dwl_input_method_relay *relay) {
static void send_state_to_input_method(struct mango_input_method_relay *relay) {
struct wlr_input_method_v2 *input_method = relay->input_method;
struct wlr_text_input_v3 *input = relay->active_text_input->input;
@ -474,7 +476,7 @@ static void send_state_to_input_method(struct dwl_input_method_relay *relay) {
static void handle_text_input_enable(struct wl_listener *listener, void *data) {
struct text_input *text_input =
wl_container_of(listener, text_input, enable);
struct dwl_input_method_relay *relay = text_input->relay;
struct mango_input_method_relay *relay = text_input->relay;
update_active_text_input(relay);
if (relay->active_text_input == text_input) {
@ -495,7 +497,7 @@ static void handle_text_input_disable(struct wl_listener *listener,
static void handle_text_input_commit(struct wl_listener *listener, void *data) {
struct text_input *text_input =
wl_container_of(listener, text_input, commit);
struct dwl_input_method_relay *relay = text_input->relay;
struct mango_input_method_relay *relay = text_input->relay;
if (relay->active_text_input == text_input) {
update_popups_position(relay);
@ -517,7 +519,7 @@ static void handle_text_input_destroy(struct wl_listener *listener,
}
static void handle_new_text_input(struct wl_listener *listener, void *data) {
struct dwl_input_method_relay *relay =
struct mango_input_method_relay *relay =
wl_container_of(listener, relay, new_text_input);
struct wlr_text_input_v3 *wlr_text_input = data;
struct text_input *text_input = ecalloc(1, sizeof(struct text_input));
@ -547,26 +549,26 @@ static void handle_new_text_input(struct wl_listener *listener, void *data) {
static void handle_focused_surface_destroy(struct wl_listener *listener,
void *data) {
struct dwl_input_method_relay *relay =
struct mango_input_method_relay *relay =
wl_container_of(listener, relay, focused_surface_destroy);
assert(relay->focused_surface == data);
dwl_im_relay_set_focus(relay, NULL);
mango_im_relay_set_focus(relay, NULL);
}
struct dwl_input_method_relay *dwl_im_relay_create() {
struct dwl_input_method_relay *relay =
ecalloc(1, sizeof(struct dwl_input_method_relay));
struct mango_input_method_relay *mango_im_relay_create() {
struct mango_input_method_relay *relay =
ecalloc(1, sizeof(struct mango_input_method_relay));
wl_list_init(&relay->text_inputs);
wl_list_init(&relay->popups);
relay->popup_tree = wlr_scene_tree_create(&scene->tree);
relay->new_text_input.notify = handle_new_text_input;
wl_signal_add(&text_input_manager->events.text_input,
wl_signal_add(&text_input_manager->events.new_text_input,
&relay->new_text_input);
relay->new_input_method.notify = handle_new_input_method;
wl_signal_add(&input_method_manager->events.input_method,
wl_signal_add(&input_method_manager->events.new_input_method,
&relay->new_input_method);
relay->focused_surface_destroy.notify = handle_focused_surface_destroy;
@ -574,14 +576,14 @@ struct dwl_input_method_relay *dwl_im_relay_create() {
return relay;
}
void dwl_im_relay_finish(struct dwl_input_method_relay *relay) {
void mango_im_relay_finish(struct mango_input_method_relay *relay) {
wl_list_remove(&relay->new_text_input.link);
wl_list_remove(&relay->new_input_method.link);
free(relay);
}
void dwl_im_relay_set_focus(struct dwl_input_method_relay *relay,
struct wlr_surface *surface) {
void mango_im_relay_set_focus(struct mango_input_method_relay *relay,
struct wlr_surface *surface) {
if (relay->focused_surface == surface) {
return;
}

View file

@ -1,975 +0,0 @@
#include "wlr_ext_workspace_v1.h"
#include "ext-workspace-v1-protocol.h"
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <wlr/types/wlr_output.h>
#define EXT_WORKSPACE_V1_VERSION 1
struct wlr_ext_workspace_v1_group_output {
struct wlr_output *output;
struct wlr_ext_workspace_group_handle_v1 *group;
struct wl_listener output_bind;
struct wl_listener output_destroy;
struct wl_list link;
};
// These structs wrap wl_resource of each interface to access the request queue
// (wlr_ext_workspace_manager_v1_resource.requests) assigned per manager
// resource
struct wlr_ext_workspace_manager_v1_resource {
struct wl_resource *resource;
struct wlr_ext_workspace_manager_v1 *manager;
struct wl_list requests; // wlr_ext_workspace_v1_request.link
struct wl_list workspace_resources; // wlr_ext_workspace_v1_resource.link
struct wl_list group_resources; // wlr_ext_workspace_group_v1_resource.link
struct wl_list link; // wlr_ext_workspace_manager_v1.resources
};
struct wlr_ext_workspace_group_v1_resource {
struct wl_resource *resource;
struct wlr_ext_workspace_group_handle_v1 *group;
struct wlr_ext_workspace_manager_v1_resource *manager;
struct wl_list link; // wlr_ext_workspace_group_v1.resources
struct wl_list
manager_resource_link; // wlr_ext_workspace_manager_v1_resource.group_resources
};
struct wlr_ext_workspace_v1_resource {
struct wl_resource *resource;
struct wlr_ext_workspace_handle_v1 *workspace;
struct wlr_ext_workspace_manager_v1_resource *manager;
struct wl_list link; // wlr_ext_workspace_v1.resources
struct wl_list
manager_resource_link; // wlr_ext_workspace_manager_v1_resource.workspace_resources
};
static const struct ext_workspace_group_handle_v1_interface group_impl;
static struct wlr_ext_workspace_group_v1_resource *
group_resource_from_resource(struct wl_resource *resource) {
assert(wl_resource_instance_of(
resource, &ext_workspace_group_handle_v1_interface, &group_impl));
return wl_resource_get_user_data(resource);
}
static const struct ext_workspace_handle_v1_interface workspace_impl;
static struct wlr_ext_workspace_v1_resource *
workspace_resource_from_resource(struct wl_resource *resource) {
assert(wl_resource_instance_of(resource, &ext_workspace_handle_v1_interface,
&workspace_impl));
return wl_resource_get_user_data(resource);
}
static const struct ext_workspace_manager_v1_interface manager_impl;
static struct wlr_ext_workspace_manager_v1_resource *
manager_resource_from_resource(struct wl_resource *resource) {
assert(wl_resource_instance_of(
resource, &ext_workspace_manager_v1_interface, &manager_impl));
return wl_resource_get_user_data(resource);
}
static void workspace_handle_destroy(struct wl_client *client,
struct wl_resource *resource) {
wl_resource_destroy(resource);
}
static void workspace_handle_activate(struct wl_client *client,
struct wl_resource *workspace_resource) {
struct wlr_ext_workspace_v1_resource *workspace_res =
workspace_resource_from_resource(workspace_resource);
if (!workspace_res) {
return;
}
struct wlr_ext_workspace_v1_request *req = calloc(1, sizeof(*req));
if (!req) {
wl_resource_post_no_memory(workspace_resource);
return;
}
req->type = WLR_EXT_WORKSPACE_V1_REQUEST_ACTIVATE;
req->activate.workspace = workspace_res->workspace;
wl_list_insert(workspace_res->manager->requests.prev, &req->link);
}
static void
workspace_handle_deactivate(struct wl_client *client,
struct wl_resource *workspace_resource) {
struct wlr_ext_workspace_v1_resource *workspace_res =
workspace_resource_from_resource(workspace_resource);
if (!workspace_res) {
return;
}
struct wlr_ext_workspace_v1_request *req = calloc(1, sizeof(*req));
if (!req) {
wl_resource_post_no_memory(workspace_resource);
return;
}
req->type = WLR_EXT_WORKSPACE_V1_REQUEST_DEACTIVATE;
req->deactivate.workspace = workspace_res->workspace;
wl_list_insert(workspace_res->manager->requests.prev, &req->link);
}
static void workspace_handle_assign(struct wl_client *client,
struct wl_resource *workspace_resource,
struct wl_resource *group_resource) {
struct wlr_ext_workspace_v1_resource *workspace_res =
workspace_resource_from_resource(workspace_resource);
struct wlr_ext_workspace_group_v1_resource *group_res =
group_resource_from_resource(group_resource);
if (!workspace_res || !group_res) {
return;
}
struct wlr_ext_workspace_v1_request *req = calloc(1, sizeof(*req));
if (!req) {
wl_resource_post_no_memory(workspace_resource);
return;
}
req->type = WLR_EXT_WORKSPACE_V1_REQUEST_ASSIGN;
req->assign.group = group_res->group;
req->assign.workspace = workspace_res->workspace;
wl_list_insert(workspace_res->manager->requests.prev, &req->link);
}
static void workspace_handle_remove(struct wl_client *client,
struct wl_resource *workspace_resource) {
struct wlr_ext_workspace_v1_resource *workspace_res =
workspace_resource_from_resource(workspace_resource);
if (!workspace_res) {
return;
}
struct wlr_ext_workspace_v1_request *req = calloc(1, sizeof(*req));
if (!req) {
wl_resource_post_no_memory(workspace_resource);
return;
}
req->type = WLR_EXT_WORKSPACE_V1_REQUEST_REMOVE;
req->remove.workspace = workspace_res->workspace;
wl_list_insert(workspace_res->manager->requests.prev, &req->link);
}
static const struct ext_workspace_handle_v1_interface workspace_impl = {
.destroy = workspace_handle_destroy,
.activate = workspace_handle_activate,
.deactivate = workspace_handle_deactivate,
.assign = workspace_handle_assign,
.remove = workspace_handle_remove,
};
static void group_handle_create_workspace(struct wl_client *client,
struct wl_resource *group_resource,
const char *name) {
struct wlr_ext_workspace_group_v1_resource *group_res =
group_resource_from_resource(group_resource);
if (!group_res) {
return;
}
struct wlr_ext_workspace_v1_request *req = calloc(1, sizeof(*req));
if (!req) {
wl_resource_post_no_memory(group_resource);
return;
}
req->create_workspace.name = strdup(name);
if (!req->create_workspace.name) {
free(req);
wl_resource_post_no_memory(group_resource);
return;
}
req->type = WLR_EXT_WORKSPACE_V1_REQUEST_CREATE_WORKSPACE;
req->create_workspace.group = group_res->group;
wl_list_insert(group_res->manager->requests.prev, &req->link);
}
static void group_handle_destroy(struct wl_client *client,
struct wl_resource *resource) {
wl_resource_destroy(resource);
}
static const struct ext_workspace_group_handle_v1_interface group_impl = {
.create_workspace = group_handle_create_workspace,
.destroy = group_handle_destroy,
};
static void destroy_workspace_resource(
struct wlr_ext_workspace_v1_resource *workspace_res) {
wl_list_remove(&workspace_res->link);
wl_list_remove(&workspace_res->manager_resource_link);
wl_resource_set_user_data(workspace_res->resource, NULL);
free(workspace_res);
}
static void workspace_resource_destroy(struct wl_resource *resource) {
struct wlr_ext_workspace_v1_resource *workspace_res =
workspace_resource_from_resource(resource);
if (workspace_res) {
destroy_workspace_resource(workspace_res);
}
}
static struct wlr_ext_workspace_v1_resource *create_workspace_resource(
struct wlr_ext_workspace_handle_v1 *workspace,
struct wlr_ext_workspace_manager_v1_resource *manager_res) {
struct wlr_ext_workspace_v1_resource *workspace_res =
calloc(1, sizeof(*workspace_res));
if (!workspace_res) {
return NULL;
}
struct wl_client *client = wl_resource_get_client(manager_res->resource);
workspace_res->resource =
wl_resource_create(client, &ext_workspace_handle_v1_interface,
wl_resource_get_version(manager_res->resource), 0);
if (!workspace_res->resource) {
free(workspace_res);
return NULL;
}
wl_resource_set_implementation(workspace_res->resource, &workspace_impl,
workspace_res, workspace_resource_destroy);
workspace_res->workspace = workspace;
workspace_res->manager = manager_res;
wl_list_insert(&workspace->resources, &workspace_res->link);
wl_list_insert(&manager_res->workspace_resources,
&workspace_res->manager_resource_link);
return workspace_res;
}
static void
destroy_group_resource(struct wlr_ext_workspace_group_v1_resource *group_res) {
wl_list_remove(&group_res->link);
wl_list_remove(&group_res->manager_resource_link);
wl_resource_set_user_data(group_res->resource, NULL);
free(group_res);
}
static void group_handle_resource_destroy(struct wl_resource *resource) {
struct wlr_ext_workspace_group_v1_resource *group_res =
group_resource_from_resource(resource);
if (group_res) {
destroy_group_resource(group_res);
}
}
static struct wlr_ext_workspace_group_v1_resource *create_group_resource(
struct wlr_ext_workspace_group_handle_v1 *group,
struct wlr_ext_workspace_manager_v1_resource *manager_res) {
struct wlr_ext_workspace_group_v1_resource *group_res =
calloc(1, sizeof(*group_res));
if (!group_res) {
return NULL;
}
struct wl_client *client = wl_resource_get_client(manager_res->resource);
uint32_t version = wl_resource_get_version(manager_res->resource);
group_res->resource = wl_resource_create(
client, &ext_workspace_group_handle_v1_interface, version, 0);
if (group_res->resource == NULL) {
free(group_res);
return NULL;
}
wl_resource_set_implementation(group_res->resource, &group_impl, group_res,
group_handle_resource_destroy);
group_res->group = group;
group_res->manager = manager_res;
wl_list_insert(&group->resources, &group_res->link);
wl_list_insert(&manager_res->group_resources,
&group_res->manager_resource_link);
return group_res;
}
static void
destroy_requests(struct wlr_ext_workspace_manager_v1_resource *manager_res) {
struct wlr_ext_workspace_v1_request *req, *tmp;
wl_list_for_each_safe(req, tmp, &manager_res->requests, link) {
if (req->type == WLR_EXT_WORKSPACE_V1_REQUEST_CREATE_WORKSPACE) {
free(req->create_workspace.name);
}
wl_list_remove(&req->link);
free(req);
}
}
static void
clear_requests_by(struct wlr_ext_workspace_manager_v1_resource *manager_res,
struct wlr_ext_workspace_group_handle_v1 *group,
struct wlr_ext_workspace_handle_v1 *workspace) {
struct wlr_ext_workspace_v1_request *req, *tmp;
wl_list_for_each_safe(req, tmp, &manager_res->requests, link) {
switch (req->type) {
case WLR_EXT_WORKSPACE_V1_REQUEST_CREATE_WORKSPACE:
if (group && req->create_workspace.group == group) {
req->create_workspace.group = NULL;
}
break;
case WLR_EXT_WORKSPACE_V1_REQUEST_ACTIVATE:
if (workspace && req->activate.workspace == workspace) {
req->activate.workspace = NULL;
}
break;
case WLR_EXT_WORKSPACE_V1_REQUEST_DEACTIVATE:
if (workspace && req->deactivate.workspace == workspace) {
req->deactivate.workspace = NULL;
}
break;
case WLR_EXT_WORKSPACE_V1_REQUEST_ASSIGN:
if (workspace && req->assign.workspace == workspace) {
req->assign.workspace = NULL;
}
if (group && req->assign.group == group) {
req->assign.group = NULL;
}
break;
case WLR_EXT_WORKSPACE_V1_REQUEST_REMOVE:
if (workspace && req->remove.workspace == workspace) {
req->remove.workspace = NULL;
}
break;
}
}
}
static void manager_handle_commit(struct wl_client *client,
struct wl_resource *resource) {
struct wlr_ext_workspace_manager_v1_resource *manager_res =
manager_resource_from_resource(resource);
if (!manager_res) {
return;
}
struct wlr_ext_workspace_v1_commit_event commit_event = {
.requests = &manager_res->requests,
};
wl_signal_emit_mutable(&manager_res->manager->events.commit, &commit_event);
destroy_requests(manager_res);
}
static void handle_idle(void *data) {
struct wlr_ext_workspace_manager_v1 *manager = data;
struct wlr_ext_workspace_manager_v1_resource *manager_res;
wl_list_for_each(manager_res, &manager->resources, link) {
ext_workspace_manager_v1_send_done(manager_res->resource);
}
manager->idle_source = NULL;
}
static void
manager_schedule_done(struct wlr_ext_workspace_manager_v1 *manager) {
if (!manager->idle_source) {
manager->idle_source =
wl_event_loop_add_idle(manager->event_loop, handle_idle, manager);
}
}
static void
workspace_send_details(struct wlr_ext_workspace_v1_resource *workspace_res) {
struct wlr_ext_workspace_handle_v1 *workspace = workspace_res->workspace;
struct wl_resource *resource = workspace_res->resource;
ext_workspace_handle_v1_send_capabilities(resource, workspace->caps);
if (workspace->coordinates.size > 0) {
ext_workspace_handle_v1_send_coordinates(resource,
&workspace->coordinates);
}
if (workspace->name) {
ext_workspace_handle_v1_send_name(resource, workspace->name);
}
if (workspace->id) {
ext_workspace_handle_v1_send_id(resource, workspace->id);
}
ext_workspace_handle_v1_send_state(resource, workspace->state);
manager_schedule_done(workspace->manager);
}
static void manager_handle_stop(struct wl_client *client,
struct wl_resource *resource) {
ext_workspace_manager_v1_send_finished(resource);
wl_resource_destroy(resource);
}
static const struct ext_workspace_manager_v1_interface manager_impl = {
.commit = manager_handle_commit,
.stop = manager_handle_stop,
};
static void destroy_manager_resource(
struct wlr_ext_workspace_manager_v1_resource *manager_res) {
destroy_requests(manager_res);
struct wlr_ext_workspace_v1_resource *workspace_res, *tmp2;
wl_list_for_each_safe(workspace_res, tmp2,
&manager_res->workspace_resources,
manager_resource_link) {
destroy_workspace_resource(workspace_res);
}
struct wlr_ext_workspace_group_v1_resource *group_res, *tmp3;
wl_list_for_each_safe(group_res, tmp3, &manager_res->group_resources,
manager_resource_link) {
destroy_group_resource(group_res);
}
wl_list_remove(&manager_res->link);
wl_resource_set_user_data(manager_res->resource, NULL);
free(manager_res);
}
static void manager_resource_destroy(struct wl_resource *resource) {
struct wlr_ext_workspace_manager_v1_resource *manager_res =
manager_resource_from_resource(resource);
if (manager_res) {
destroy_manager_resource(manager_res);
}
}
static void
group_send_details(struct wlr_ext_workspace_group_v1_resource *group_res) {
struct wlr_ext_workspace_group_handle_v1 *group = group_res->group;
struct wl_resource *resource = group_res->resource;
struct wl_client *client = wl_resource_get_client(resource);
ext_workspace_group_handle_v1_send_capabilities(resource, group->caps);
struct wlr_ext_workspace_v1_group_output *group_output;
wl_list_for_each(group_output, &group->outputs, link) {
struct wl_resource *output_resource;
wl_resource_for_each(output_resource,
&group_output->output->resources) {
if (wl_resource_get_client(output_resource) == client) {
ext_workspace_group_handle_v1_send_output_enter(
resource, output_resource);
}
}
}
manager_schedule_done(group->manager);
}
static void manager_bind(struct wl_client *client, void *data, uint32_t version,
uint32_t id) {
struct wlr_ext_workspace_manager_v1 *manager = data;
struct wlr_ext_workspace_manager_v1_resource *manager_res =
calloc(1, sizeof(*manager_res));
if (!manager_res) {
wl_client_post_no_memory(client);
return;
}
manager_res->manager = manager;
wl_list_init(&manager_res->requests);
wl_list_init(&manager_res->workspace_resources);
wl_list_init(&manager_res->group_resources);
manager_res->resource = wl_resource_create(
client, &ext_workspace_manager_v1_interface, version, id);
if (!manager_res->resource) {
free(manager_res);
wl_client_post_no_memory(client);
return;
}
wl_resource_set_implementation(manager_res->resource, &manager_impl,
manager_res, manager_resource_destroy);
wl_list_insert(&manager->resources, &manager_res->link);
struct wlr_ext_workspace_group_handle_v1 *group;
wl_list_for_each(group, &manager->groups, link) {
struct wlr_ext_workspace_group_v1_resource *group_res =
create_group_resource(group, manager_res);
if (!group_res) {
wl_resource_post_no_memory(manager_res->resource);
continue;
}
ext_workspace_manager_v1_send_workspace_group(manager_res->resource,
group_res->resource);
group_send_details(group_res);
}
struct wlr_ext_workspace_handle_v1 *workspace;
wl_list_for_each(workspace, &manager->workspaces, link) {
struct wlr_ext_workspace_v1_resource *workspace_res =
create_workspace_resource(workspace, manager_res);
if (!workspace_res) {
wl_resource_post_no_memory(manager_res->resource);
continue;
}
ext_workspace_manager_v1_send_workspace(manager_res->resource,
workspace_res->resource);
workspace_send_details(workspace_res);
if (!workspace->group) {
continue;
}
struct wlr_ext_workspace_group_v1_resource *group_res;
wl_list_for_each(group_res, &workspace->group->resources, link) {
if (group_res->manager == manager_res) {
ext_workspace_group_handle_v1_send_workspace_enter(
group_res->resource, workspace_res->resource);
}
}
}
ext_workspace_manager_v1_send_done(manager_res->resource);
}
static void manager_handle_display_destroy(struct wl_listener *listener,
void *data) {
struct wlr_ext_workspace_manager_v1 *manager =
wl_container_of(listener, manager, display_destroy);
wl_signal_emit_mutable(&manager->events.destroy, NULL);
assert(wl_list_empty(&manager->events.commit.listener_list));
assert(wl_list_empty(&manager->events.destroy.listener_list));
struct wlr_ext_workspace_group_handle_v1 *group, *tmp;
wl_list_for_each_safe(group, tmp, &manager->groups, link) {
wlr_ext_workspace_group_handle_v1_destroy(group);
}
struct wlr_ext_workspace_handle_v1 *workspace, *tmp2;
wl_list_for_each_safe(workspace, tmp2, &manager->workspaces, link) {
wlr_ext_workspace_handle_v1_destroy(workspace);
}
struct wlr_ext_workspace_manager_v1_resource *manager_res, *tmp3;
wl_list_for_each_safe(manager_res, tmp3, &manager->resources, link) {
destroy_manager_resource(manager_res);
}
if (manager->idle_source) {
wl_event_source_remove(manager->idle_source);
}
wl_list_remove(&manager->display_destroy.link);
wl_global_destroy(manager->global);
free(manager);
}
struct wlr_ext_workspace_manager_v1 *
wlr_ext_workspace_manager_v1_create(struct wl_display *display,
uint32_t version) {
assert(version <= EXT_WORKSPACE_V1_VERSION);
struct wlr_ext_workspace_manager_v1 *manager = calloc(1, sizeof(*manager));
if (!manager) {
return NULL;
}
manager->global =
wl_global_create(display, &ext_workspace_manager_v1_interface, version,
manager, manager_bind);
if (!manager->global) {
free(manager);
return NULL;
}
manager->event_loop = wl_display_get_event_loop(display);
manager->display_destroy.notify = manager_handle_display_destroy;
wl_display_add_destroy_listener(display, &manager->display_destroy);
wl_list_init(&manager->groups);
wl_list_init(&manager->workspaces);
wl_list_init(&manager->resources);
wl_signal_init(&manager->events.commit);
wl_signal_init(&manager->events.destroy);
return manager;
}
struct wlr_ext_workspace_group_handle_v1 *
wlr_ext_workspace_group_handle_v1_create(
struct wlr_ext_workspace_manager_v1 *manager, uint32_t caps) {
struct wlr_ext_workspace_group_handle_v1 *group = calloc(1, sizeof(*group));
if (!group) {
return NULL;
}
group->manager = manager;
group->caps = caps;
wl_list_init(&group->outputs);
wl_list_init(&group->resources);
wl_signal_init(&group->events.destroy);
wl_list_insert(manager->groups.prev, &group->link);
struct wlr_ext_workspace_manager_v1_resource *manager_res;
wl_list_for_each(manager_res, &manager->resources, link) {
struct wlr_ext_workspace_group_v1_resource *group_res =
create_group_resource(group, manager_res);
if (!group_res) {
continue;
}
ext_workspace_manager_v1_send_workspace_group(manager_res->resource,
group_res->resource);
group_send_details(group_res);
}
manager_schedule_done(manager);
return group;
}
static void
workspace_send_group(struct wlr_ext_workspace_handle_v1 *workspace,
struct wlr_ext_workspace_group_handle_v1 *group,
bool enter) {
struct wlr_ext_workspace_v1_resource *workspace_res;
wl_list_for_each(workspace_res, &workspace->resources, link) {
struct wlr_ext_workspace_group_v1_resource *group_res;
wl_list_for_each(group_res, &group->resources, link) {
if (group_res->manager != workspace_res->manager) {
continue;
}
if (enter) {
ext_workspace_group_handle_v1_send_workspace_enter(
group_res->resource, workspace_res->resource);
} else {
ext_workspace_group_handle_v1_send_workspace_leave(
group_res->resource, workspace_res->resource);
}
}
}
manager_schedule_done(workspace->manager);
}
static void
destroy_group_output(struct wlr_ext_workspace_v1_group_output *group_output) {
wl_list_remove(&group_output->output_bind.link);
wl_list_remove(&group_output->output_destroy.link);
wl_list_remove(&group_output->link);
free(group_output);
}
static void group_send_output(struct wlr_ext_workspace_group_handle_v1 *group,
struct wlr_output *output, bool enter) {
struct wlr_ext_workspace_group_v1_resource *group_res;
wl_list_for_each(group_res, &group->resources, link) {
struct wl_client *client = wl_resource_get_client(group_res->resource);
struct wl_resource *output_resource;
wl_resource_for_each(output_resource, &output->resources) {
if (wl_resource_get_client(output_resource) != client) {
continue;
}
if (enter) {
ext_workspace_group_handle_v1_send_output_enter(
group_res->resource, output_resource);
} else {
ext_workspace_group_handle_v1_send_output_leave(
group_res->resource, output_resource);
}
}
}
manager_schedule_done(group->manager);
}
void wlr_ext_workspace_group_handle_v1_destroy(
struct wlr_ext_workspace_group_handle_v1 *group) {
if (!group) {
return;
}
wl_signal_emit_mutable(&group->events.destroy, NULL);
assert(wl_list_empty(&group->events.destroy.listener_list));
struct wlr_ext_workspace_handle_v1 *workspace;
wl_list_for_each(workspace, &group->manager->workspaces, link) {
if (workspace->group == group) {
workspace_send_group(workspace, group, false);
workspace->group = NULL;
}
}
struct wlr_ext_workspace_group_v1_resource *group_res, *tmp;
wl_list_for_each_safe(group_res, tmp, &group->resources, link) {
ext_workspace_group_handle_v1_send_removed(group_res->resource);
destroy_group_resource(group_res);
}
struct wlr_ext_workspace_manager_v1_resource *manager_res;
wl_list_for_each(manager_res, &group->manager->resources, link) {
clear_requests_by(manager_res, group, NULL);
}
struct wlr_ext_workspace_v1_group_output *group_output, *tmp3;
wl_list_for_each_safe(group_output, tmp3, &group->outputs, link) {
group_send_output(group, group_output->output, false);
destroy_group_output(group_output);
}
manager_schedule_done(group->manager);
wl_list_remove(&group->link);
free(group);
}
static void handle_output_bind(struct wl_listener *listener, void *data) {
struct wlr_ext_workspace_v1_group_output *group_output =
wl_container_of(listener, group_output, output_bind);
struct wlr_output_event_bind *event = data;
struct wl_client *client = wl_resource_get_client(event->resource);
struct wlr_ext_workspace_group_v1_resource *group_res;
wl_list_for_each(group_res, &group_output->group->resources, link) {
if (wl_resource_get_client(group_res->resource) == client) {
ext_workspace_group_handle_v1_send_output_enter(group_res->resource,
event->resource);
}
}
manager_schedule_done(group_output->group->manager);
}
static void handle_output_destroy(struct wl_listener *listener, void *data) {
struct wlr_ext_workspace_v1_group_output *group_output =
wl_container_of(listener, group_output, output_destroy);
group_send_output(group_output->group, group_output->output, false);
destroy_group_output(group_output);
}
static struct wlr_ext_workspace_v1_group_output *
get_group_output(struct wlr_ext_workspace_group_handle_v1 *group,
struct wlr_output *output) {
struct wlr_ext_workspace_v1_group_output *group_output;
wl_list_for_each(group_output, &group->outputs, link) {
if (group_output->output == output) {
return group_output;
}
}
return NULL;
}
void wlr_ext_workspace_group_handle_v1_output_enter(
struct wlr_ext_workspace_group_handle_v1 *group,
struct wlr_output *output) {
if (get_group_output(group, output)) {
return;
}
struct wlr_ext_workspace_v1_group_output *group_output =
calloc(1, sizeof(*group_output));
if (!group_output) {
return;
}
group_output->output = output;
group_output->group = group;
wl_list_insert(&group->outputs, &group_output->link);
group_output->output_bind.notify = handle_output_bind;
wl_signal_add(&output->events.bind, &group_output->output_bind);
group_output->output_destroy.notify = handle_output_destroy;
wl_signal_add(&output->events.destroy, &group_output->output_destroy);
group_send_output(group, output, true);
}
void wlr_ext_workspace_group_handle_v1_output_leave(
struct wlr_ext_workspace_group_handle_v1 *group,
struct wlr_output *output) {
struct wlr_ext_workspace_v1_group_output *group_output =
get_group_output(group, output);
if (!group_output) {
return;
}
group_send_output(group, output, false);
destroy_group_output(group_output);
}
struct wlr_ext_workspace_handle_v1 *
wlr_ext_workspace_handle_v1_create(struct wlr_ext_workspace_manager_v1 *manager,
const char *id, uint32_t caps) {
struct wlr_ext_workspace_handle_v1 *workspace =
calloc(1, sizeof(*workspace));
if (!workspace) {
return NULL;
}
workspace->manager = manager;
workspace->caps = caps;
if (id) {
workspace->id = strdup(id);
if (!workspace->id) {
free(workspace);
return NULL;
}
}
wl_list_init(&workspace->resources);
wl_array_init(&workspace->coordinates);
wl_signal_init(&workspace->events.destroy);
wl_list_insert(manager->workspaces.prev, &workspace->link);
struct wlr_ext_workspace_manager_v1_resource *manager_res;
wl_list_for_each(manager_res, &manager->resources, link) {
struct wlr_ext_workspace_v1_resource *workspace_res =
create_workspace_resource(workspace, manager_res);
if (!workspace_res) {
continue;
}
ext_workspace_manager_v1_send_workspace(manager_res->resource,
workspace_res->resource);
workspace_send_details(workspace_res);
}
manager_schedule_done(manager);
return workspace;
}
void wlr_ext_workspace_handle_v1_destroy(
struct wlr_ext_workspace_handle_v1 *workspace) {
if (!workspace) {
return;
}
wl_signal_emit_mutable(&workspace->events.destroy, NULL);
assert(wl_list_empty(&workspace->events.destroy.listener_list));
if (workspace->group) {
workspace_send_group(workspace, workspace->group, false);
}
struct wlr_ext_workspace_v1_resource *workspace_res, *tmp;
wl_list_for_each_safe(workspace_res, tmp, &workspace->resources, link) {
ext_workspace_handle_v1_send_removed(workspace_res->resource);
destroy_workspace_resource(workspace_res);
}
struct wlr_ext_workspace_manager_v1_resource *manager_res;
wl_list_for_each(manager_res, &workspace->manager->resources, link) {
clear_requests_by(manager_res, NULL, workspace);
}
manager_schedule_done(workspace->manager);
wl_list_remove(&workspace->link);
wl_array_release(&workspace->coordinates);
free(workspace->id);
free(workspace->name);
free(workspace);
}
void wlr_ext_workspace_handle_v1_set_group(
struct wlr_ext_workspace_handle_v1 *workspace,
struct wlr_ext_workspace_group_handle_v1 *group) {
if (workspace->group == group) {
return;
}
if (workspace->group) {
workspace_send_group(workspace, workspace->group, false);
}
workspace->group = group;
if (group) {
workspace_send_group(workspace, group, true);
}
}
void wlr_ext_workspace_handle_v1_set_name(
struct wlr_ext_workspace_handle_v1 *workspace, const char *name) {
assert(name);
if (workspace->name && strcmp(workspace->name, name) == 0) {
return;
}
free(workspace->name);
workspace->name = strdup(name);
if (workspace->name == NULL) {
return;
}
struct wlr_ext_workspace_v1_resource *workspace_res;
wl_list_for_each(workspace_res, &workspace->resources, link) {
ext_workspace_handle_v1_send_name(workspace_res->resource,
workspace->name);
}
manager_schedule_done(workspace->manager);
}
void wlr_ext_workspace_handle_v1_set_coordinates(
struct wlr_ext_workspace_handle_v1 *workspace, const uint32_t *coords,
size_t coords_len) {
size_t size = coords_len * sizeof(coords[0]);
if (size == workspace->coordinates.size &&
(size == 0 || memcmp(workspace->coordinates.data, coords, size) == 0)) {
return;
}
wl_array_release(&workspace->coordinates);
wl_array_init(&workspace->coordinates);
struct wl_array arr = {
.data = (void *)coords,
.size = size,
};
wl_array_copy(&workspace->coordinates, &arr);
struct wlr_ext_workspace_v1_resource *workspace_res;
wl_list_for_each(workspace_res, &workspace->resources, link) {
ext_workspace_handle_v1_send_coordinates(workspace_res->resource,
&workspace->coordinates);
}
manager_schedule_done(workspace->manager);
}
static void workspace_set_state(struct wlr_ext_workspace_handle_v1 *workspace,
enum ext_workspace_handle_v1_state state,
bool enabled) {
uint32_t old_state = workspace->state;
if (enabled) {
workspace->state |= state;
} else {
workspace->state &= ~state;
}
if (old_state == workspace->state) {
return;
}
struct wlr_ext_workspace_v1_resource *workspace_res;
wl_list_for_each(workspace_res, &workspace->resources, link) {
ext_workspace_handle_v1_send_state(workspace_res->resource,
workspace->state);
}
manager_schedule_done(workspace->manager);
}
void wlr_ext_workspace_handle_v1_set_active(
struct wlr_ext_workspace_handle_v1 *workspace, bool enabled) {
workspace_set_state(workspace, EXT_WORKSPACE_HANDLE_V1_STATE_ACTIVE,
enabled);
}
void wlr_ext_workspace_handle_v1_set_urgent(
struct wlr_ext_workspace_handle_v1 *workspace, bool enabled) {
workspace_set_state(workspace, EXT_WORKSPACE_HANDLE_V1_STATE_URGENT,
enabled);
}
void wlr_ext_workspace_handle_v1_set_hidden(
struct wlr_ext_workspace_handle_v1 *workspace, bool enabled) {
workspace_set_state(workspace, EXT_WORKSPACE_HANDLE_V1_STATE_HIDDEN,
enabled);
}

View file

@ -1,150 +0,0 @@
/*
* This an unstable interface of wlroots. No guarantees are made regarding the
* future consistency of this API.
*/
#ifndef WLR_USE_UNSTABLE
#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features"
#endif
#ifndef WLR_TYPES_WLR_EXT_WORKSPACE_V1_H
#define WLR_TYPES_WLR_EXT_WORKSPACE_V1_H
#include <wayland-protocols/ext-workspace-v1-enum.h>
#include <wayland-server-core.h>
struct wlr_output;
enum wlr_ext_workspace_v1_request_type {
WLR_EXT_WORKSPACE_V1_REQUEST_CREATE_WORKSPACE,
WLR_EXT_WORKSPACE_V1_REQUEST_ACTIVATE,
WLR_EXT_WORKSPACE_V1_REQUEST_DEACTIVATE,
WLR_EXT_WORKSPACE_V1_REQUEST_ASSIGN,
WLR_EXT_WORKSPACE_V1_REQUEST_REMOVE,
};
struct wlr_ext_workspace_v1_request {
enum wlr_ext_workspace_v1_request_type type;
struct wl_list link; // wlr_ext_workspace_manager_v1_resource.requests
union {
struct {
char *name;
struct wlr_ext_workspace_group_handle_v1
*group; // NULL if destroyed
} create_workspace;
struct {
struct wlr_ext_workspace_handle_v1 *workspace; // NULL if destroyed
} activate;
struct {
struct wlr_ext_workspace_handle_v1 *workspace; // NULL if destroyed
} deactivate;
struct {
struct wlr_ext_workspace_handle_v1 *workspace; // NULL if destroyed
struct wlr_ext_workspace_group_handle_v1
*group; // NULL if destroyed
} assign;
struct {
struct wlr_ext_workspace_handle_v1 *workspace; // NULL if destroyed
} remove;
};
};
struct wlr_ext_workspace_v1_commit_event {
struct wl_list *requests; // wlr_ext_workspace_v1_request.link
};
struct wlr_ext_workspace_manager_v1 {
struct wl_global *global;
struct wl_list groups; // wlr_ext_workspace_group_handle_v1.link
struct wl_list workspaces; // wlr_ext_workspace_handle_v1.link
struct {
struct wl_signal commit; // wlr_ext_workspace_v1_commit_event
struct wl_signal destroy;
} events;
void *data;
struct {
struct wl_list resources; // wlr_ext_workspace_manager_v1_resource.link
struct wl_event_source *idle_source;
struct wl_event_loop *event_loop;
struct wl_listener display_destroy;
};
};
struct wlr_ext_workspace_group_handle_v1 {
struct wlr_ext_workspace_manager_v1 *manager;
uint32_t caps; // ext_workspace_group_handle_v1_group_capabilities
struct {
struct wl_signal destroy;
} events;
struct wl_list link; // wlr_ext_workspace_manager_v1.groups
void *data;
struct {
struct wl_list outputs; // wlr_ext_workspace_v1_group_output.link
struct wl_list resources; // wlr_ext_workspace_manager_v1_resource.link
};
};
struct wlr_ext_workspace_handle_v1 {
struct wlr_ext_workspace_manager_v1 *manager;
struct wlr_ext_workspace_group_handle_v1 *group; // May be NULL
char *id;
char *name;
struct wl_array coordinates;
uint32_t caps; // ext_workspace_handle_v1_workspace_capabilities
uint32_t state; // ext_workspace_handle_v1_state
struct {
struct wl_signal destroy;
} events;
struct wl_list link; // wlr_ext_workspace_manager_v1.workspaces
void *data;
struct {
struct wl_list resources; // wlr_ext_workspace_v1_resource.link
};
};
struct wlr_ext_workspace_manager_v1 *
wlr_ext_workspace_manager_v1_create(struct wl_display *display,
uint32_t version);
struct wlr_ext_workspace_group_handle_v1 *
wlr_ext_workspace_group_handle_v1_create(
struct wlr_ext_workspace_manager_v1 *manager, uint32_t caps);
void wlr_ext_workspace_group_handle_v1_destroy(
struct wlr_ext_workspace_group_handle_v1 *group);
void wlr_ext_workspace_group_handle_v1_output_enter(
struct wlr_ext_workspace_group_handle_v1 *group, struct wlr_output *output);
void wlr_ext_workspace_group_handle_v1_output_leave(
struct wlr_ext_workspace_group_handle_v1 *group, struct wlr_output *output);
struct wlr_ext_workspace_handle_v1 *
wlr_ext_workspace_handle_v1_create(struct wlr_ext_workspace_manager_v1 *manager,
const char *id, uint32_t caps);
void wlr_ext_workspace_handle_v1_destroy(
struct wlr_ext_workspace_handle_v1 *workspace);
void wlr_ext_workspace_handle_v1_set_group(
struct wlr_ext_workspace_handle_v1 *workspace,
struct wlr_ext_workspace_group_handle_v1 *group);
void wlr_ext_workspace_handle_v1_set_name(
struct wlr_ext_workspace_handle_v1 *workspace, const char *name);
void wlr_ext_workspace_handle_v1_set_coordinates(
struct wlr_ext_workspace_handle_v1 *workspace, const uint32_t *coords,
size_t coords_len);
void wlr_ext_workspace_handle_v1_set_active(
struct wlr_ext_workspace_handle_v1 *workspace, bool enabled);
void wlr_ext_workspace_handle_v1_set_urgent(
struct wlr_ext_workspace_handle_v1 *workspace, bool enabled);
void wlr_ext_workspace_handle_v1_set_hidden(
struct wlr_ext_workspace_handle_v1 *workspace, bool enabled);
#endif

View file

@ -31,7 +31,7 @@ Client *termforwin(Client *w) {
return NULL;
wl_list_for_each(c, &fstack, flink) {
if (c->isterm && !c->swallowing && c->pid &&
if (c->isterm && !c->swallowdby && c->pid &&
isdescprocess(c->pid, w->pid)) {
return c;
}
@ -48,9 +48,9 @@ Client *get_client_by_id_or_title(const char *arg_id, const char *arg_title) {
continue;
}
if (c->swallowedby) {
appid = client_get_appid(c->swallowedby);
title = client_get_title(c->swallowedby);
if (c->swallowing) {
appid = client_get_appid(c->swallowing);
title = client_get_title(c->swallowing);
} else {
appid = client_get_appid(c);
title = client_get_title(c);
@ -184,11 +184,11 @@ Client *find_client_by_direction(Client *tc, const Arg *arg,
break;
wl_list_for_each(c, &clients, link) {
if (!c || c == tc)
if (!c || !c->mon || c == tc)
continue;
if (!findfloating && c->isfloating)
continue;
if (c->is_monocle_hide)
if (!VISIBLEON(c, c->mon))
continue;
if (c->isunglobal)
continue;
@ -197,11 +197,6 @@ Client *find_client_by_direction(Client *tc, const Arg *arg,
if (!(c->tags & c->mon->tagset[c->mon->seltags]))
continue;
if (step == 0 && ((!tc->mon->isoverview &&
!client_is_in_same_stack(tc, c, NULL)) ||
c->mon != tc->mon))
continue;
int32_t c_l = c->geom.x;
int32_t c_r = c->geom.x + c->geom.width;
int32_t c_t = c->geom.y;
@ -257,17 +252,24 @@ Client *find_client_by_direction(Client *tc, const Arg *arg,
if (!match_dir)
continue;
if (step == 0) {
if (c->mon != tc->mon)
continue;
if (!tc->mon->isoverview &&
!client_is_in_same_stack(tc, c, NULL))
continue;
if (orth_dist != 0)
continue;
}
int64_t penalty = 0;
if (main_dist < 0) {
penalty = 10000000000LL; // 主方向重叠(反方向)的极大惩罚
penalty = 10000000000LL;
main_dist = -main_dist;
}
// 正交方向无重叠惩罚,优先选择在同一行/列的窗口
int64_t no_overlap_penalty = 0;
if (orth_dist > 0) {
// LEFT/RIGHT 时 orth_dist 是垂直间距,>0 表示垂直无重叠
// UP/DOWN 时 orth_dist 是水平间距,>0 表示水平无重叠
no_overlap_penalty = 10000000LL;
}
@ -442,7 +444,7 @@ Client *get_focused_stack_client(Client *sc, Client *custom_focus_client) {
return sc;
wl_list_for_each(tc, &fstack, flink) {
if (tc->iskilling || tc->isunglobal || tc->is_monocle_hide)
if (tc->iskilling || tc->isunglobal)
continue;
if (!VISIBLEON(tc, sc->mon))
continue;

View file

@ -100,23 +100,30 @@ static bool layer_ignores_focus(LayerSurface *l) {
}
void xytonode(double x, double y, struct wlr_surface **psurface, Client **pc,
LayerSurface **pl, double *nx, double *ny) {
struct wlr_scene_node *node, *pnode;
LayerSurface **pl, MangoGroupBar **gb, double *nx, double *ny) {
struct wlr_scene_node *node = NULL, *pnode = NULL;
struct wlr_surface *surface = NULL;
Client *c = NULL;
LayerSurface *l = NULL;
MangoGroupBar *mangogroupbar = NULL;
int32_t layer;
Client *ovc = NULL;
for (layer = NUM_LAYERS - 1; !surface && layer >= 0; layer--) {
if (psurface)
*psurface = NULL;
if (pc)
*pc = NULL;
if (pl)
*pl = NULL;
if (gb)
*gb = NULL;
for (layer = NUM_LAYERS - 1; layer >= 0; layer--) {
if (layer == LyrFadeOut)
continue;
if (!(node = wlr_scene_node_at(&layers[layer]->node, x, y, nx, ny)))
continue;
if (!node->enabled)
node = wlr_scene_node_at(&layers[layer]->node, x, y, nx, ny);
if (!node)
continue;
if (node->type == WLR_SCENE_NODE_BUFFER) {
@ -125,32 +132,44 @@ void xytonode(double x, double y, struct wlr_surface **psurface, Client **pc,
wlr_scene_buffer_from_node(node));
if (scene_surface) {
surface = scene_surface->surface;
} else {
continue;
}
}
/* start from the topmost layer,
find a sureface that can be focused by pointer,
impopup neither a client nor a layer surface.*/
if (layer == LyrIMPopup) {
c = NULL;
l = NULL;
} else {
for (pnode = node; pnode && !c; pnode = &pnode->parent->node)
c = pnode->data;
if (c && c->type == LayerShell) {
l = (LayerSurface *)c;
c = NULL;
void *data = NULL;
for (pnode = node; pnode; pnode = &pnode->parent->node) {
if (pnode->data) {
data = pnode->data;
break;
}
}
if (data) {
Client *temp_c = (Client *)data;
if (temp_c->type == LayerShell) {
l = (LayerSurface *)temp_c;
} else if (temp_c->type == GroupBar) {
mangogroupbar = (MangoGroupBar *)temp_c;
} else if (temp_c->type == XDGShell || temp_c->type == X11) {
c = temp_c;
}
}
}
if (node->type == WLR_SCENE_NODE_RECT) {
if (c) {
if (c && (c->type == XDGShell || c->type == X11)) {
surface = client_surface(c);
}
break;
if (l && l->type == LayerShell) {
surface = l->layer_surface->surface;
}
}
break;
}
if (psurface)
@ -159,6 +178,8 @@ void xytonode(double x, double y, struct wlr_surface **psurface, Client **pc,
*pc = c;
if (pl)
*pl = l;
if (gb)
*gb = mangogroupbar;
if (selmon && selmon->isoverview && config.ov_no_resize) {
ovc = xytoclient(x, y);
@ -174,12 +195,12 @@ void xytonode(double x, double y, struct wlr_surface **psurface, Client **pc,
if (ovc && (!l || layer_ignores_focus(l) || is_below)) {
if (pc)
*pc = ovc;
if (psurface)
*psurface = ovc ? client_surface(ovc) : NULL;
if (pl && ovc)
if (pl)
*pl = NULL;
if (gb)
*gb = NULL;
}
}
}

View file

@ -181,4 +181,4 @@ bool match_monitor_spec(char *spec, Monitor *m) {
free(serial_rule);
return match;
}
}

View file

@ -143,11 +143,17 @@ static cJSON *build_client_json(Client *c) {
cJSON_AddNumberToObject(obj, "id", c->id);
cJSON_AddNumberToObject(obj, "pid", c->pid);
cJSON_AddStringToObject(obj, "foreign_toplevel_id",
c->ext_foreign_toplevel->identifier);
cJSON_AddStringToObject(obj, "title", client_get_title(c));
cJSON_AddStringToObject(obj, "appid", client_get_appid(c));
cJSON_AddStringToObject(obj, "monitor",
c->mon ? c->mon->wlr_output->name : "");
cJSON_AddItemToObject(obj, "tags", tags_mask_to_array(c->tags));
cJSON_AddBoolToObject(obj, "is_swallowing", c->swallowing ? true : false);
cJSON_AddBoolToObject(obj, "is_swallowedby", c->swallowdby ? true : false);
cJSON_AddBoolToObject(obj, "is_group", c->group_prev || c->group_next);
cJSON_AddBoolToObject(obj, "is_visible", c->mon && VISIBLEON(c, c->mon));
cJSON_AddBoolToObject(obj, "is_focused", c->isfocusing);
cJSON_AddBoolToObject(obj, "is_fullscreen", c->isfullscreen);
cJSON_AddBoolToObject(obj, "is_floating", c->isfloating);

View file

@ -20,7 +20,7 @@ void set_size_per(Monitor *m, Client *c) {
}
}
if (!found) {
if (!found || c->isfloating) {
c->master_mfact_per = m->pertag->mfacts[m->pertag->curtag];
c->master_inner_per = 1.0f;
c->stack_inner_per = 1.0f;
@ -37,21 +37,6 @@ void set_size_per(Monitor *m, Client *c) {
}
}
void monocle_set_focus(Client *c, bool focused) {
if (!c || !c->mon)
return;
c->is_monocle_hide = !focused;
mango_tab_bar_node_set_focus(c->tab_bar_node, focused);
wlr_scene_node_set_enabled(&c->scene->node, focused);
if (!focused) {
c->animation.current = c->animainit_geom = c->animation.initial =
c->pending = c->current = c->geom;
}
}
void resize_tile_master_horizontal(Client *grabc, bool isdrag, int32_t offsetx,
int32_t offsety, uint32_t time,
int32_t type) {
@ -1147,14 +1132,8 @@ void pre_caculate_before_arrange(Monitor *m, bool want_animation,
client_add_jump_label_node(c);
}
if (m->pertag->ltidxs[m->pertag->curtag]->id == MONOCLE &&
!c->tab_bar_node) {
client_add_tab_bar_node(c);
}
if (c->tab_bar_node && c->mon == m) {
wlr_scene_node_set_enabled(&c->tab_bar_node->scene_buffer->node,
false);
if (c->group_bar->scene_buffer->node.enabled) {
client_check_tab_node_visible(c);
}
if (c->mon == m && (c->isglobal || c->isunglobal)) {

View file

@ -261,7 +261,7 @@ static void dwindle_assign(DwindleNode *node, int32_t ax, int32_t ay,
!node->client->ismaximizescreen) {
struct wlr_box box = {ax, ay, MANGO_MAX(1, aw),
MANGO_MAX(1, ah)};
resize(node->client, box, 0);
client_tile_resize(node->client, box, 0);
}
}
return;

View file

@ -290,18 +290,37 @@ void center_tile(Monitor *m) {
int32_t should_overspread =
config.center_master_overspread && (n <= nmasters);
int32_t left_num = 0;
int32_t right_num = 0;
for (int j = 0; j < stack_num; j++) {
if ((j % 2) ^ (n % 2 == 0)) {
right_num++;
} else {
left_num++;
}
}
int32_t master_surplus_height =
(m->w.height - 2 * cur_gappov - cur_gappiv * ie * (master_num - 1));
(m->w.height - 2 * cur_gappov -
cur_gappiv * ie * (master_num > 0 ? master_num - 1 : 0));
float master_surplus_ratio = 1.0;
int32_t init_master_surplus = master_surplus_height;
int32_t slave_left_surplus_height =
(m->w.height - 2 * cur_gappov - cur_gappiv * ie * (stack_num / 2 - 1));
(m->w.height - 2 * cur_gappov -
cur_gappiv * ie * (left_num > 0 ? left_num - 1 : 0));
float slave_left_surplus_ratio = 1.0;
int32_t init_slave_left_surplus = slave_left_surplus_height;
int32_t slave_right_surplus_height =
(m->w.height - 2 * cur_gappov -
cur_gappiv * ie * ((stack_num + 1) / 2 - 1));
cur_gappiv * ie * (right_num > 0 ? right_num - 1 : 0));
float slave_right_surplus_ratio = 1.0;
int32_t init_slave_right_surplus = slave_right_surplus_height;
int32_t init_single_stack_surplus =
(m->w.height - 2 * cur_gappov -
cur_gappiv * ie * (stack_num > 0 ? stack_num - 1 : 0));
if (n > nmasters || !should_overspread) {
// 计算主区域宽度(居中模式)
@ -349,6 +368,8 @@ void center_tile(Monitor *m) {
if (c->master_inner_per > 0.0f) {
h = master_surplus_height * c->master_inner_per /
master_surplus_ratio;
if (r == 1)
h = m->w.height - my - cur_gappov;
master_surplus_height = master_surplus_height - h;
master_surplus_ratio =
master_surplus_ratio - c->master_inner_per;
@ -357,8 +378,12 @@ void center_tile(Monitor *m) {
h = (m->w.height - my - cur_gappov -
cur_gappiv * ie * (r - 1)) /
r;
c->master_inner_per = h / (m->w.height - my - cur_gappov -
cur_gappiv * ie * (r - 1));
if (r == 1)
h = m->w.height - my - cur_gappov;
c->master_inner_per =
init_master_surplus > 0
? ((float)h / (float)init_master_surplus)
: 0;
c->master_mfact_per = mfact;
}
@ -377,16 +402,20 @@ void center_tile(Monitor *m) {
// 单个堆叠窗口
r = n - i;
if (c->stack_inner_per > 0.0f) {
h = (m->w.height - 2 * cur_gappov -
cur_gappiv * ie * (stack_num - 1)) *
c->stack_inner_per;
h = init_single_stack_surplus * c->stack_inner_per;
if (r == 1)
h = m->w.height - ety - cur_gappov;
c->master_mfact_per = mfact;
} else {
h = (m->w.height - ety - cur_gappov -
cur_gappiv * ie * (r - 1)) /
r;
c->stack_inner_per = h / (m->w.height - ety - cur_gappov -
cur_gappiv * ie * (r - 1));
if (r == 1)
h = m->w.height - ety - cur_gappov;
c->stack_inner_per =
init_single_stack_surplus > 0
? ((float)h / (float)init_single_stack_surplus)
: 0;
c->master_mfact_per = mfact;
}
@ -403,7 +432,7 @@ void center_tile(Monitor *m) {
.width = tw,
.height = h},
0);
ety += h + cur_gappiv * ie; // 使用理论高度累加
ety += h + cur_gappiv * ie;
} else {
// 多个堆叠窗口:交替放在左右两侧
r = (n - i + 1) / 2;
@ -413,6 +442,8 @@ void center_tile(Monitor *m) {
if (c->stack_inner_per > 0.0f) {
h = slave_right_surplus_height * c->stack_inner_per /
slave_right_surplus_ratio;
if (r == 1)
h = m->w.height - ety - cur_gappov;
slave_right_surplus_height =
slave_right_surplus_height - h;
slave_right_surplus_ratio =
@ -422,9 +453,12 @@ void center_tile(Monitor *m) {
h = (m->w.height - ety - cur_gappov -
cur_gappiv * ie * (r - 1)) /
r;
if (r == 1)
h = m->w.height - ety - cur_gappov;
c->stack_inner_per =
h / (m->w.height - ety - cur_gappov -
cur_gappiv * ie * (r - 1));
init_slave_right_surplus > 0
? ((float)h / (float)init_slave_right_surplus)
: 0;
c->master_mfact_per = mfact;
}
@ -436,12 +470,14 @@ void center_tile(Monitor *m) {
.width = tw,
.height = h},
0);
ety += h + cur_gappiv * ie; // 使用理论高度累加
ety += h + cur_gappiv * ie;
} else {
// 左侧堆叠窗口
if (c->stack_inner_per > 0.0f) {
h = slave_left_surplus_height * c->stack_inner_per /
slave_left_surplus_ratio;
if (r == 1)
h = m->w.height - oty - cur_gappov;
slave_left_surplus_height =
slave_left_surplus_height - h;
slave_left_surplus_ratio =
@ -451,9 +487,12 @@ void center_tile(Monitor *m) {
h = (m->w.height - oty - cur_gappov -
cur_gappiv * ie * (r - 1)) /
r;
if (r == 1)
h = m->w.height - oty - cur_gappov;
c->stack_inner_per =
h / (m->w.height - oty - cur_gappov -
cur_gappiv * ie * (r - 1));
init_slave_left_surplus > 0
? ((float)h / (float)init_slave_left_surplus)
: 0;
c->master_mfact_per = mfact;
}
@ -464,7 +503,7 @@ void center_tile(Monitor *m) {
.width = tw,
.height = h},
0);
oty += h + cur_gappiv * ie; // 使用理论高度累加
oty += h + cur_gappiv * ie;
}
}
}
@ -545,83 +584,32 @@ void deck(Monitor *m) {
}
}
void monocle(Monitor *m) {
Client *c = NULL, *fc = NULL;
void // 17
monocle(Monitor *m) {
Client *c = NULL;
struct wlr_box geom;
int32_t cur_gappov = enablegaps ? m->gappov : 0;
int32_t cur_gappoh = enablegaps ? m->gappoh : 0;
int32_t cur_gapiv = enablegaps ? m->gappiv : 0;
int32_t cur_gapih = enablegaps ? m->gappih : 0;
if (config.smartgaps && m->visible_fake_tiling_clients == 1) {
cur_gappov = cur_gappoh = cur_gapiv = cur_gapih = 0;
}
int n = m->visible_fake_tiling_clients;
if (n == 0)
return;
wl_list_for_each(c, &fstack, flink) {
if (c->iskilling || c->isunglobal || !ISFAKETILED(c))
continue;
if (VISIBLEON(c, m)) {
fc = c;
break;
}
}
if (n == 1) {
geom.x = m->w.x + cur_gappoh;
geom.y = m->w.y + cur_gappov;
geom.width = m->w.width - 2 * cur_gappoh;
geom.height = m->w.height - 2 * cur_gappov;
client_tile_resize(fc, geom, 0);
monocle_set_focus(fc, true);
return;
}
int tab_bar_height = config.tab_bar_height;
int tab_bar_inner_gap_height =
config.tab_bar_height > 0 ? 2 * cur_gapiv : 0;
int tab_bar_y_offset = config.tab_bar_height > 0 ? cur_gapiv : 0;
int tab_y = m->w.y + cur_gappov;
int main_y = tab_y + tab_bar_height + tab_bar_y_offset;
int main_height = m->w.height - 2 * cur_gappov - tab_bar_inner_gap_height -
tab_bar_height;
int tab_area_width = m->w.width - 2 * cur_gappoh;
int total_gaps = (n - 1) * cur_gapih;
int base_width = (tab_area_width - total_gaps) / n;
int remainder = (tab_area_width - total_gaps) % n;
int tab_x = m->w.x + cur_gappoh;
int idx = 0;
cur_gappoh = config.smartgaps && m->visible_fake_tiling_clients == 1
? 0
: cur_gappoh;
cur_gappov = config.smartgaps && m->visible_fake_tiling_clients == 1
? 0
: cur_gappov;
wl_list_for_each(c, &clients, link) {
if (!VISIBLEON(c, m) || !ISFAKETILED(c))
continue;
if (c == fc) {
monocle_set_focus(c, true);
} else {
monocle_set_focus(c, false);
}
geom.x = m->w.x + cur_gappoh;
geom.y = main_y;
geom.y = m->w.y + cur_gappov;
geom.width = m->w.width - 2 * cur_gappoh;
geom.height = main_height;
geom.height = m->w.height - 2 * cur_gappov;
client_tile_resize(c, geom, 0);
int tw = base_width + (idx < remainder ? 1 : 0);
global_draw_tab_bar(c, tab_x, tab_y, tw, tab_bar_height);
tab_x += tw + cur_gapih;
idx++;
}
if ((c = focustop(m)))
wlr_scene_node_raise_to_top(&c->scene->node);
}
// 网格布局窗口大小和位置计算

View file

@ -1,4 +1,3 @@
typedef struct {
float x, y, w, h;
} OvPlacedRect;
@ -232,16 +231,20 @@ void overview_scale(Monitor *m) {
float base_x = m->w.x + target_gappo + dx;
float base_y = m->w.y + target_gappo + dy;
// 收集所有客户端的目标几何,最后统一调用 client_tile_resize
struct wlr_box overview_boxes[n]; // C99 VLAn > 0 时有效
for (int k = 0; k < n; k++) {
Client *cl = items[k].c;
struct wlr_box geom;
geom.x = (int)(base_x + placed[k].x + 0.5f);
geom.y = (int)(base_y + placed[k].y + 0.5f);
float w = items[k].orig_w * best_s;
float h = items[k].orig_h * best_s;
geom.width = (int)(geom.x + w + 0.5f) - geom.x;
geom.height = (int)(geom.y + h + 0.5f) - geom.y;
resize(cl, geom, 0);
int ix = (int)(base_x + placed[k].x + 0.5f);
int iy = (int)(base_y + placed[k].y + 0.5f);
int iw = (int)(ix + w + 0.5f) - ix;
int ih = (int)(iy + h + 0.5f) - iy;
overview_boxes[k] = (struct wlr_box){ix, iy, iw, ih};
}
for (int k = 0; k < n; k++) {
client_tile_resize(items[k].c, overview_boxes[k], 0);
}
}
@ -280,74 +283,69 @@ void overview_resize(Monitor *m) {
return;
}
// 临时存储每个客户端的目标几何
struct wlr_box boxes[n]; // C99 VLA
if (n == 1) {
int32_t cw = (m->w.width - 2 * target_gappo) * single_width_ratio;
int32_t ch = (m->w.height - 2 * target_gappo) * single_height_ratio;
c_arr[0]->geom.x = m->w.x + (m->w.width - cw) / 2;
c_arr[0]->geom.y = m->w.y + (m->w.height - ch) / 2;
c_arr[0]->geom.width = cw;
c_arr[0]->geom.height = ch;
resize(c_arr[0], c_arr[0]->geom, 0);
free(c_arr);
return;
}
if (n == 2) {
boxes[0].x = m->w.x + (m->w.width - cw) / 2;
boxes[0].y = m->w.y + (m->w.height - ch) / 2;
boxes[0].width = cw;
boxes[0].height = ch;
} else if (n == 2) {
int32_t cw = (m->w.width - 2 * target_gappo - target_gappi) / 2;
int32_t ch = (m->w.height - 2 * target_gappo) * 0.65f;
c_arr[0]->geom.x = m->w.x + target_gappo;
c_arr[0]->geom.y = m->w.y + (m->w.height - ch) / 2 + target_gappo;
c_arr[0]->geom.width = cw;
c_arr[0]->geom.height = ch;
resize(c_arr[0], c_arr[0]->geom, 0);
boxes[0].x = m->w.x + target_gappo;
boxes[0].y = m->w.y + (m->w.height - ch) / 2 + target_gappo;
boxes[0].width = cw;
boxes[0].height = ch;
c_arr[1]->geom.x = m->w.x + cw + target_gappo + target_gappi;
c_arr[1]->geom.y = m->w.y + (m->w.height - ch) / 2 + target_gappo;
c_arr[1]->geom.width = cw;
c_arr[1]->geom.height = ch;
resize(c_arr[1], c_arr[1]->geom, 0);
boxes[1].x = m->w.x + cw + target_gappo + target_gappi;
boxes[1].y = m->w.y + (m->w.height - ch) / 2 + target_gappo;
boxes[1].width = cw;
boxes[1].height = ch;
} else {
int32_t cols = 1;
while (cols * cols < n)
cols++;
int32_t rows = (n + cols - 1) / cols;
free(c_arr);
return;
}
int32_t ch =
(m->w.height - 2 * target_gappo - (rows - 1) * target_gappi) / rows;
int32_t cw =
(m->w.width - 2 * target_gappo - (cols - 1) * target_gappi) / cols;
int32_t cols = 1;
while (cols * cols < n) {
cols++;
}
int32_t rows = (n + cols - 1) / cols;
if (ch < 1)
ch = 1;
if (cw < 1)
cw = 1;
int32_t ch =
(m->w.height - 2 * target_gappo - (rows - 1) * target_gappi) / rows;
int32_t cw =
(m->w.width - 2 * target_gappo - (cols - 1) * target_gappi) / cols;
if (ch < 1)
ch = 1;
if (cw < 1)
cw = 1;
int32_t overcols = n % cols;
int32_t dx = 0;
if (overcols) {
dx = (m->w.width - overcols * cw - (overcols - 1) * target_gappi) / 2 -
target_gappo;
}
for (int i = 0; i < n; i++) {
int32_t cx = m->w.x + (i % cols) * (cw + target_gappi);
int32_t cy = m->w.y + (i / cols) * (ch + target_gappi);
if (overcols && i >= n - overcols) {
cx += dx;
int32_t overcols = n % cols;
int32_t dx = 0;
if (overcols) {
dx = (m->w.width - overcols * cw - (overcols - 1) * target_gappi) /
2 -
target_gappo;
}
c_arr[i]->geom.x = cx + target_gappo;
c_arr[i]->geom.y = cy + target_gappo;
c_arr[i]->geom.width = cw;
c_arr[i]->geom.height = ch;
resize(c_arr[i], c_arr[i]->geom, 0);
for (int i = 0; i < n; i++) {
int32_t cx = m->w.x + (i % cols) * (cw + target_gappi);
int32_t cy = m->w.y + (i / cols) * (ch + target_gappi);
if (overcols && i >= n - overcols)
cx += dx;
boxes[i].x = cx + target_gappo;
boxes[i].y = cy + target_gappo;
boxes[i].width = cw;
boxes[i].height = ch;
}
}
// 统一应用所有几何变更,使用 client_tile_resize
for (int k = 0; k < n; k++) {
client_tile_resize(c_arr[k], boxes[k], 0);
}
free(c_arr);
@ -365,10 +363,9 @@ void create_jump_hints(Monitor *m) {
char c_char = jump_labels[label_idx];
c->jump_char = c_char;
// 把字符变成字符串
char label_text[2] = {c_char, '\0'};
mango_jump_label_node_update(c->jump_label_node, label_text, 1.0f);
mango_jump_label_node_update(c->jump_label_node, label_text,
m->wlr_output->scale);
wlr_scene_node_set_enabled(&c->jump_label_node->scene_buffer->node,
true);
wlr_scene_node_raise_to_top(
@ -385,12 +382,10 @@ void create_jump_hints(Monitor *m) {
void begin_jump_mode(Monitor *m) { m->is_jump_mode = 1; }
void finish_jump_mode(Monitor *m) {
Client *c = NULL;
if (!m->is_jump_mode) {
if (!m->is_jump_mode)
return;
}
Client *c;
wl_list_for_each(c, &clients, link) {
if (VISIBLEON(c, m)) {
if (c->jump_label_node->scene_buffer->node.enabled) {
@ -400,12 +395,10 @@ void finish_jump_mode(Monitor *m) {
}
}
}
m->is_jump_mode = 0;
}
void overview(Monitor *m) {
if (config.ov_no_resize) {
overview_scale(m);
} else {
@ -415,4 +408,4 @@ void overview(Monitor *m) {
if (m->is_jump_mode) {
create_jump_hints(m);
}
}
}

View file

@ -36,7 +36,6 @@ scroller_node_create(struct TagScrollerState *st, Client *c) {
return n;
}
/* 从 tag 状态中移除一个节点并释放 */
static void scroller_node_remove(struct TagScrollerState *st,
struct ScrollerStackNode *target) {
if (!st || !target)
@ -223,7 +222,7 @@ void arrange_stack_node(struct ScrollerStackNode *head, struct wlr_box geometry,
.y = current_y,
.width = geometry.width,
.height = client_height};
resize(iter->client, client_geom, 0);
client_tile_resize(iter->client, client_geom, 0);
remain_proportion -= iter->stack_proportion;
remain_client_height -= client_height;
current_y += client_height + gappiv;
@ -272,7 +271,7 @@ void arrange_stack_vertical_node(struct ScrollerStackNode *head,
.x = current_x,
.height = geometry.height,
.width = client_width};
resize(iter->client, client_geom, 0);
client_tile_resize(iter->client, client_geom, 0);
remain_proportion -= iter->stack_proportion;
remain_client_width -= client_width;
current_x += client_width + gappih;
@ -508,6 +507,7 @@ void scroller(Monitor *m) {
void vertical_scroller(Monitor *m) {
uint32_t tag = m->pertag->curtag;
int32_t bar_height = 0;
struct TagScrollerState *st = ensure_scroller_state(m, tag);
Client *c = NULL;
float scroller_default_proportion_single =
@ -696,7 +696,12 @@ void vertical_scroller(Monitor *m) {
arrange_stack_vertical_node(heads[focus_index], target_geom,
cur_gappih);
} else {
target_geom.y = root_client->geom.y;
bar_height = !root_client->isfullscreen && (root_client->group_prev ||
root_client->group_next)
? config.group_bar_height
: 0;
target_geom.y = root_client->geom.y - bar_height;
vertical_check_scroller_root_inside_mon(heads[focus_index]->client,
&target_geom);
arrange_stack_vertical_node(heads[focus_index], target_geom,
@ -709,8 +714,15 @@ void vertical_scroller(Monitor *m) {
up_geom.width = m->w.width - 2 * cur_gappoh;
up_geom.height = max_client_height * cur->scroller_proportion;
vertical_scroll_adjust_fullandmax(cur->client, &up_geom);
bar_height = !heads[focus_index - i + 1]->client->isfullscreen &&
(heads[focus_index - i + 1]->client->group_prev ||
heads[focus_index - i + 1]->client->group_next)
? config.group_bar_height
: 0;
up_geom.y = heads[focus_index - i + 1]->client->geom.y - cur_gappiv -
up_geom.height;
up_geom.height - bar_height;
arrange_stack_vertical_node(cur, up_geom, cur_gappih);
}
@ -773,16 +785,14 @@ void scroller_insert_stack(Client *c, Client *target_client,
if (tnode->prev_in_stack)
tnode->prev_in_stack->next_in_stack = newnode;
tnode->prev_in_stack = newnode;
wl_list_remove(&c->link);
wl_list_insert(tnode->client->link.prev, &c->link);
wl_list_safe_reinsert_prev(&tnode->client->link, &c->link);
} else {
newnode->prev_in_stack = tnode;
newnode->next_in_stack = tnode->next_in_stack;
if (tnode->next_in_stack)
tnode->next_in_stack->prev_in_stack = newnode;
tnode->next_in_stack = newnode;
wl_list_remove(&c->link);
wl_list_insert(&tnode->client->link, &c->link);
wl_list_safe_reinsert_next(&tnode->client->link, &c->link);
}
/* 处理堆叠头部的全屏/最大化状态*/
@ -821,13 +831,11 @@ void scroller_drop_tile(Client *c, Client *closest, int vertical) {
return;
} else if (closest->drop_direction == UP) {
if (c != stack_head) {
wl_list_remove(&c->link);
wl_list_insert(stack_head->link.prev, &c->link);
wl_list_safe_reinsert_prev(&stack_head->link, &c->link);
}
} else if (closest->drop_direction == DOWN) {
if (c != stack_tail) {
wl_list_remove(&c->link);
wl_list_insert(&stack_tail->link, &c->link);
wl_list_safe_reinsert_next(&stack_head->link, &c->link);
}
}
} else {
@ -841,13 +849,11 @@ void scroller_drop_tile(Client *c, Client *closest, int vertical) {
return;
} else if (closest->drop_direction == LEFT) {
if (c != stack_head) {
wl_list_remove(&c->link);
wl_list_insert(stack_head->link.prev, &c->link);
wl_list_safe_reinsert_prev(&stack_head->link, &c->link);
}
} else if (closest->drop_direction == RIGHT) {
if (c != stack_tail) {
wl_list_remove(&c->link);
wl_list_insert(&stack_tail->link, &c->link);
wl_list_safe_reinsert_next(&stack_head->link, &c->link);
}
}
}
@ -902,7 +908,6 @@ static void update_scroller_state(Monitor *m) {
break;
}
/* 移除不再可见的节点 */
struct ScrollerStackNode *n = st->all_first;
while (n) {
bool found = false;

File diff suppressed because it is too large Load diff