Merge branch 'mangowm:main' into main

This commit is contained in:
Davide Greco 2026-03-24 10:39:25 +01:00 committed by GitHub
commit 1d10f08ca0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
25 changed files with 261 additions and 89 deletions

View file

@ -723,6 +723,8 @@ void client_animation_next_tick(Client *c) {
c->is_pending_open_animation = false;
client_apply_clip(c, factor);
if (animation_passed >= 1.0) {
// clear the open action state
@ -752,8 +754,6 @@ void client_animation_next_tick(Client *c) {
// end flush in next frame, not the current frame
c->need_output_flush = false;
}
client_apply_clip(c, factor);
}
void init_fadeout_client(Client *c) {

View file

@ -168,6 +168,7 @@ typedef struct {
float mfact;
int32_t nmaster;
int32_t no_render_border;
int32_t open_as_floating;
int32_t no_hide;
} ConfigTagRule;
@ -634,9 +635,14 @@ uint32_t parse_mod(const char *mod_str) {
// 分割处理每个部分
token = strtok_r(input_copy, "+", &saveptr);
while (token != NULL) {
// 去除空白
while (*token == ' ' || *token == '\t')
token++;
// 去除前后空白
trim_whitespace(token);
// 如果 token 变成空字符串则跳过
if (*token == '\0') {
token = strtok_r(NULL, "+", &saveptr);
continue;
}
if (strncmp(token, "code:", 5) == 0) {
// 处理 code: 形式
@ -1197,6 +1203,8 @@ FuncType parse_func_name(char *func_name, Arg *arg, char *arg_value,
} else if (strcmp(func_name, "scroller_stack") == 0) {
func = scroller_stack;
(*arg).i = parse_direction(arg_value);
} else if (strcmp(func_name, "toggle_all_floating") == 0) {
func = toggle_all_floating;
} else {
return NULL;
}
@ -1900,6 +1908,7 @@ bool parse_option(Config *config, char *key, char *value) {
rule->nmaster = 0;
rule->mfact = 0.0f;
rule->no_render_border = 0;
rule->open_as_floating = 0;
rule->no_hide = 0;
bool parse_error = false;
@ -1928,6 +1937,8 @@ bool parse_option(Config *config, char *key, char *value) {
rule->monitor_serial = strdup(val);
} else if (strcmp(key, "no_render_border") == 0) {
rule->no_render_border = CLAMP_INT(atoi(val), 0, 1);
} else if (strcmp(key, "open_as_floating") == 0) {
rule->open_as_floating = CLAMP_INT(atoi(val), 0, 1);
} else if (strcmp(key, "no_hide") == 0) {
rule->no_hide = CLAMP_INT(atoi(val), 0, 1);
} else if (strcmp(key, "nmaster") == 0) {
@ -3605,6 +3616,20 @@ void reapply_monitor_rules(void) {
updatemons(NULL, NULL);
}
void set_xcursor_env() {
if (config.cursor_size > 0) {
char size_str[16];
snprintf(size_str, sizeof(size_str), "%d", config.cursor_size);
setenv("XCURSOR_SIZE", size_str, 1);
} else {
setenv("XCURSOR_SIZE", "24", 1);
}
if (config.cursor_theme) {
setenv("XCURSOR_THEME", config.cursor_theme, 1);
}
}
void reapply_cursor_style(void) {
if (hide_cursor_source) {
wl_event_source_timer_update(hide_cursor_source, 0);
@ -3621,19 +3646,11 @@ void reapply_cursor_style(void) {
cursor_mgr = NULL;
}
set_xcursor_env();
cursor_mgr =
wlr_xcursor_manager_create(config.cursor_theme, config.cursor_size);
if (config.cursor_size > 0) {
char size_str[16];
snprintf(size_str, sizeof(size_str), "%d", config.cursor_size);
setenv("XCURSOR_SIZE", size_str, 1);
}
if (config.cursor_theme) {
setenv("XCURSOR_THEME", config.cursor_theme, 1);
}
Monitor *m = NULL;
wl_list_for_each(m, &mons, link) {
wlr_xcursor_manager_load(cursor_mgr, m->wlr_output->scale);
@ -3775,6 +3792,8 @@ void parse_tagrule(Monitor *m) {
m->pertag->mfacts[tr.id] = tr.mfact;
if (tr.no_render_border >= 0)
m->pertag->no_render_border[tr.id] = tr.no_render_border;
if (tr.open_as_floating >= 0)
m->pertag->open_as_floating[tr.id] = tr.open_as_floating;
}
}

View file

@ -70,3 +70,4 @@ int32_t disable_monitor(const Arg *arg);
int32_t enable_monitor(const Arg *arg);
int32_t toggle_monitor(const Arg *arg);
int32_t scroller_stack(const Arg *arg);
int32_t toggle_all_floating(const Arg *arg);

View file

@ -1870,3 +1870,27 @@ int32_t scroller_stack(const Arg *arg) {
arrange(selmon, false, false);
return 0;
}
int32_t toggle_all_floating(const Arg *arg) {
if (!selmon || !selmon->sel)
return 0;
Client *c = NULL;
bool should_floating = !selmon->sel->isfloating;
wl_list_for_each(c, &clients, link) {
if (VISIBLEON(c, selmon)) {
if (c->isfloating && !should_floating) {
c->old_master_inner_per = 0.0f;
c->old_stack_inner_per = 0.0f;
set_size_per(selmon, c);
}
if (c->isfloating != should_floating) {
setfloating(c, should_floating);
}
}
}
return 0;
}

View file

@ -1,15 +1,12 @@
bool check_hit_no_border(Client *c) {
int32_t i;
bool hit_no_border = false;
if (!render_border) {
hit_no_border = true;
}
for (i = 0; i < config.tag_rules_count; i++) {
if (c->tags & (1 << (config.tag_rules[i].id - 1)) &&
config.tag_rules[i].no_render_border) {
hit_no_border = true;
}
if (c->mon && !c->mon->isoverview &&
c->mon->pertag->no_render_border[get_tags_first_tag_num(c->tags)]) {
hit_no_border = true;
}
if (config.no_border_when_single && c && c->mon &&
@ -19,6 +16,7 @@ bool check_hit_no_border(Client *c) {
}
return hit_no_border;
}
Client *termforwin(Client *w) {
Client *c = NULL;

View file

@ -15,6 +15,9 @@ void restore_size_per(Monitor *m, Client *c) {
if (!m || !c)
return;
if (!m->wlr_output->enabled)
return;
wl_list_for_each(fc, &clients, link) {
if (VISIBLEON(fc, m) && ISTILED(fc)) {
fc->old_ismaster = fc->ismaster;
@ -811,11 +814,6 @@ void pre_caculate_before_arrange(Monitor *m, bool want_animation,
int32_t master_num = 0;
int32_t stack_num = 0;
if (!m)
return;
if (!m->wlr_output->enabled)
return;
m->visible_clients = 0;
m->visible_tiling_clients = 0;
m->visible_scroll_tiling_clients = 0;
@ -912,6 +910,12 @@ void pre_caculate_before_arrange(Monitor *m, bool want_animation,
void // 17
arrange(Monitor *m, bool want_animation, bool from_view) {
if (!m)
return;
if (!m->wlr_output->enabled)
return;
pre_caculate_before_arrange(m, want_animation, from_view, false);
if (m->isoverview) {

View file

@ -913,8 +913,13 @@ static KeyMode keymode = {
.isdefault = true,
};
static char *env_vars[] = {"DISPLAY", "WAYLAND_DISPLAY", "XDG_CURRENT_DESKTOP",
"XDG_SESSION_TYPE", NULL};
static char *env_vars[] = {"DISPLAY",
"WAYLAND_DISPLAY",
"XDG_CURRENT_DESKTOP",
"XDG_SESSION_TYPE",
"XCURSOR_THEME",
"XCURSOR_SIZE",
NULL};
static struct {
enum wp_cursor_shape_device_v1_shape shape;
struct wlr_surface *surface;
@ -929,8 +934,9 @@ struct Pertag {
uint32_t curtag, prevtag; /* current and previous tag */
int32_t nmasters[LENGTH(tags) + 1]; /* number of windows in master area */
float mfacts[LENGTH(tags) + 1]; /* mfacts per tag */
bool no_hide[LENGTH(tags) + 1]; /* no_hide per tag */
bool no_render_border[LENGTH(tags) + 1]; /* no_render_border per tag */
int32_t no_hide[LENGTH(tags) + 1]; /* no_hide per tag */
int32_t no_render_border[LENGTH(tags) + 1]; /* no_render_border per tag */
int32_t open_as_floating[LENGTH(tags) + 1]; /* open_as_floating per tag */
const Layout
*ltidxs[LENGTH(tags) + 1]; /* matrix of tags and layouts indexes */
};
@ -1398,6 +1404,25 @@ void set_float_malposition(Client *tc) {
tc->float_geom.y = tc->geom.y = y;
}
void client_reset_mon_tags(Client *c, Monitor *mon, uint32_t newtags) {
if (!newtags && mon && !mon->isoverview) {
c->tags = mon->tagset[mon->seltags];
} else if (!newtags && mon && mon->isoverview) {
c->tags = mon->ovbk_current_tagset;
} else if (newtags) {
c->tags = newtags;
} else {
c->tags = mon->tagset[mon->seltags];
}
}
void check_match_tag_floating_rule(Client *c, Monitor *mon) {
if (c->tags && !c->isfloating && mon && !c->swallowedby &&
mon->pertag->open_as_floating[get_tags_first_tag_num(c->tags)]) {
c->isfloating = 1;
}
}
void applyrules(Client *c) {
/* rule matching */
const char *appid, *title;
@ -1522,6 +1547,7 @@ void applyrules(Client *c) {
int32_t fullscreen_state_backup =
c->isfullscreen || client_wants_fullscreen(c);
setmon(c, mon, newtags,
!c->isopensilent &&
!(client_is_x11_popup(c) && client_should_ignore_focus(c)) &&
@ -1529,6 +1555,11 @@ void applyrules(Client *c) {
(!c->istagsilent || !newtags ||
newtags & mon->tagset[mon->seltags]));
if (!c->isfloating) {
c->old_stack_inner_per = c->stack_inner_per;
c->old_master_inner_per = c->master_inner_per;
}
if (c->mon &&
!(c->mon == selmon && c->tags & c->mon->tagset[c->mon->seltags]) &&
!c->isopensilent && !c->istagsilent) {
@ -4045,9 +4076,9 @@ void init_client_properties(Client *c) {
c->master_mfact_per = 0.0f;
c->master_inner_per = 0.0f;
c->stack_inner_per = 0.0f;
c->old_stack_inner_per = 1.0f;
c->old_master_inner_per = 1.0f;
c->old_master_mfact_per = 1.0f;
c->old_stack_inner_per = 0.0f;
c->old_master_inner_per = 0.0f;
c->old_master_mfact_per = 0.0f;
c->isterm = 0;
c->allow_csd = 0;
c->force_maximize = 0;
@ -5018,12 +5049,12 @@ setfloating(Client *c, int32_t floating) {
if (floating == 1 && c != grabc) {
if (c->isfullscreen || c->ismaximizescreen) {
c->isfullscreen = 0; // 清除窗口全屏标志
c->ismaximizescreen = 0;
c->bw = c->isnoborder ? 0 : config.borderpx;
if (c->isfullscreen) {
c->isfullscreen = 0;
client_set_fullscreen(c, 0);
}
c->ismaximizescreen = 0;
exit_scroller_stack(c);
// 重新计算居中的坐标
@ -5065,7 +5096,8 @@ setfloating(Client *c, int32_t floating) {
// 让当前tag中的全屏窗口退出全屏参与平铺
wl_list_for_each(fc, &clients,
link) if (fc && fc != c && VISIBLEON(fc, c->mon) &&
c->tags & fc->tags && ISFULLSCREEN(fc)) {
c->tags & fc->tags && ISFULLSCREEN(fc) &&
old_floating_state) {
clear_fullscreen_flag(fc);
}
}
@ -5079,7 +5111,8 @@ setfloating(Client *c, int32_t floating) {
layers[c->isfloating ? LyrTop : LyrTile]);
}
if (!c->isfloating && old_floating_state) {
if (!c->isfloating && old_floating_state &&
(c->old_stack_inner_per > 0.0f || c->old_master_inner_per > 0.0f)) {
restore_size_per(c->mon, c);
}
@ -5098,6 +5131,12 @@ setfloating(Client *c, int32_t floating) {
}
arrange(c->mon, false, false);
if (!c->isfloating) {
c->old_master_inner_per = c->master_inner_per;
c->old_stack_inner_per = c->stack_inner_per;
}
setborder_color(c);
printstatus();
}
@ -5144,14 +5183,13 @@ void setmaximizescreen(Client *c, int32_t maximizescreen) {
if (maximizescreen) {
if (c->isfullscreen)
setfullscreen(c, 0);
if (c->isfullscreen) {
c->isfullscreen = 0;
client_set_fullscreen(c, 0);
}
exit_scroller_stack(c);
if (c->isfloating)
c->float_geom = c->geom;
maximizescreen_box.x = c->mon->w.x + config.gappoh;
maximizescreen_box.y = c->mon->w.y + config.gappov;
maximizescreen_box.width = c->mon->w.width - 2 * config.gappoh;
@ -5212,14 +5250,14 @@ void setfullscreen(Client *c, int32_t fullscreen) // 用自定义全屏代理自
client_set_fullscreen(c, fullscreen);
if (fullscreen) {
if (c->ismaximizescreen)
setmaximizescreen(c, 0);
if (c->ismaximizescreen && !c->force_maximize) {
client_set_maximized(c, false);
}
c->ismaximizescreen = 0;
exit_scroller_stack(c);
if (c->isfloating)
c->float_geom = c->geom;
c->isfakefullscreen = 0;
c->bw = 0;
@ -5378,15 +5416,8 @@ void setmon(Client *c, Monitor *m, uint32_t newtags, bool focus) {
/* Make sure window actually overlaps with the monitor */
reset_foreign_tolevel(c);
resize(c, c->geom, 0);
if (!newtags && !m->isoverview) {
c->tags = m->tagset[m->seltags];
} else if (!newtags && m->isoverview) {
c->tags = m->ovbk_current_tagset;
} else if (newtags) {
c->tags = newtags;
} else {
c->tags = m->tagset[m->seltags];
}
client_reset_mon_tags(c, m, newtags);
check_match_tag_floating_rule(c, m);
setfloating(c, c->isfloating);
setfullscreen(c, c->isfullscreen); /* This will call arrange(c->mon) */
}
@ -5471,8 +5502,8 @@ void handle_print_status(struct wl_listener *listener, void *data) {
void setup(void) {
setenv("XCURSOR_SIZE", "24", 1);
setenv("XDG_CURRENT_DESKTOP", "mango", 1);
setenv("_JAVA_AWT_WM_NONREPARENTING", "1", 1);
parse_config();
if (cli_debug_log) {
@ -5657,10 +5688,11 @@ void setup(void) {
* cursor images are available at all scale factors on the screen
* (necessary for HiDPI support). Scaled cursors will be loaded with
* each output. */
// cursor_mgr = wlr_xcursor_manager_create(cursor_theme, 24);
set_xcursor_env();
cursor_mgr =
wlr_xcursor_manager_create(config.cursor_theme, config.cursor_size);
/*
* wlr_cursor *only* displays an image on screen. It does not move
* around when the pointer moves. However, we can attach input devices