From 4cdc954618735a2d7ecc27f2ff52607be5fbb7cd Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Fri, 1 Aug 2025 19:27:57 +0800 Subject: [PATCH 001/591] update readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9c39e973..cadc5f8b 100644 --- a/README.md +++ b/README.md @@ -144,7 +144,7 @@ sudo ninja -C build install - Dependencies ```bash -yay -S rofi-wayland foot xdg-desktop-portal-wlr swaybg waybar wl-clip-persist cliphist wl-clipboard wlsunset xfce-polkit swaync pamixer lavalauncher-mao-git wlr-dpms sway-audio-idle-inhibit-git swayidle dimland-git brightnessctl swayosd wlr-randr grim slurp satty swaylock-effects-git wlogout +yay -S rofi-wayland foot xdg-desktop-portal-wlr swaybg waybar wl-clip-persist cliphist wl-clipboard wlsunset xfce-polkit swaync pamixer lavalauncher-mao-git wlr-dpms sway-audio-idle-inhibit-git swayidle dimland-git brightnessctl swayosd wlr-randr grim slurp satty swaylock-effects-git wlogout sox ``` - use my config From 4d649e73136906452ff20010127e0f6efd083b96 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Fri, 1 Aug 2025 22:10:02 +0800 Subject: [PATCH 002/591] opt: both set maximized and tile state to client --- src/client/client.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/client/client.h b/src/client/client.h index 4489f007..c2acbd13 100644 --- a/src/client/client.h +++ b/src/client/client.h @@ -354,10 +354,10 @@ static inline void client_set_tiled(Client *c, uint32_t edges) { if (wl_resource_get_version(c->surface.xdg->toplevel->resource) >= XDG_TOPLEVEL_STATE_TILED_RIGHT_SINCE_VERSION) { wlr_xdg_toplevel_set_tiled(c->surface.xdg->toplevel, edges); - } else { - wlr_xdg_toplevel_set_maximized(c->surface.xdg->toplevel, - edges != WLR_EDGE_NONE); } + + wlr_xdg_toplevel_set_maximized(c->surface.xdg->toplevel, + edges != WLR_EDGE_NONE); } static inline void client_set_suspended(Client *c, int suspended) { From d4c0ebfa5b5117de7077d6254626cc288da087c7 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sat, 2 Aug 2025 10:07:25 +0800 Subject: [PATCH 003/591] fix: geometry error when no animation --- src/mango.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/mango.c b/src/mango.c index 48626455..86e25533 100644 --- a/src/mango.c +++ b/src/mango.c @@ -2181,6 +2181,8 @@ void commitnotify(struct wl_listener *listener, void *data) { setmon(c, NULL, 0, true); /* Make sure to reapply rules in mapnotify() */ + client_set_tiled(c, WLR_EDGE_TOP | WLR_EDGE_BOTTOM | WLR_EDGE_LEFT | + WLR_EDGE_RIGHT); uint32_t serial = wlr_xdg_surface_schedule_configure(c->surface.xdg); if (serial > 0) { c->configure_serial = serial; From b18ca70ac4448b5c8ad7bdde72fdb6d968faf0d5 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sat, 2 Aug 2025 22:06:17 +0800 Subject: [PATCH 004/591] fix: error judge minimize request --- src/mango.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/mango.c b/src/mango.c index 86e25533..715db1db 100644 --- a/src/mango.c +++ b/src/mango.c @@ -3418,11 +3418,21 @@ minimizenotify(struct wl_listener *listener, void *data) { // < XDG_TOPLEVEL_WM_CAPABILITIES_SINCE_VERSION) // wlr_xdg_surface_schedule_configure(c->surface.xdg); // togglemaxmizescreen(&(Arg){0}); + Client *c = wl_container_of(listener, c, minimize); + struct wlr_xwayland_minimize_event *event = data; if (!c || !c->mon || c->iskilling || c->isminied) return; + if (!client_is_x11(c)) { + if (!c->surface.xdg->toplevel->requested.minimized) + return; + } else { + if (!event->minimize) + return; + } + set_minized(c); } From 3bf524929b22bbe77d224439ece7bdabe82f8067 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sat, 2 Aug 2025 23:02:21 +0800 Subject: [PATCH 005/591] opt: optimize init commit for no anim --- src/animation/client.h | 1 + src/mango.c | 19 +++++++++---------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/animation/client.h b/src/animation/client.h index 858f923c..98b9a99c 100644 --- a/src/animation/client.h +++ b/src/animation/client.h @@ -902,6 +902,7 @@ void resize(Client *c, struct wlr_box geo, int interact) { return; c->need_output_flush = true; + c->dirty = true; // oldgeom = c->geom; bbox = (interact || c->isfloating || c->isfullscreen) ? &sgeom : &c->mon->w; diff --git a/src/mango.c b/src/mango.c index 715db1db..ab008e71 100644 --- a/src/mango.c +++ b/src/mango.c @@ -2181,8 +2181,9 @@ void commitnotify(struct wl_listener *listener, void *data) { setmon(c, NULL, 0, true); /* Make sure to reapply rules in mapnotify() */ - client_set_tiled(c, WLR_EDGE_TOP | WLR_EDGE_BOTTOM | WLR_EDGE_LEFT | - WLR_EDGE_RIGHT); + // client_set_tiled(c, WLR_EDGE_TOP | WLR_EDGE_BOTTOM | WLR_EDGE_LEFT | + // WLR_EDGE_RIGHT); + uint32_t serial = wlr_xdg_surface_schedule_configure(c->surface.xdg); if (serial > 0) { c->configure_serial = serial; @@ -2203,17 +2204,15 @@ void commitnotify(struct wl_listener *listener, void *data) { c->animation.tagining) return; - if (c == grabc) + if (c == grabc || !c->dirty) return; - struct wlr_box *new_geo = &c->surface.xdg->geometry; - bool need_resize = new_geo->width != c->geom.width - 2 * c->bw || - new_geo->height != c->geom.height - 2 * c->bw || - new_geo->x != 0 || new_geo->y != 0; + resize(c, c->geom, 0); - if (need_resize) { - resize(c, c->geom, 0); - } + struct wlr_box *new_geo = &c->surface.xdg->geometry; + c->dirty = new_geo->width != c->geom.width - 2 * c->bw || + new_geo->height != c->geom.height - 2 * c->bw || + new_geo->x != 0 || new_geo->y != 0; } void destroydecoration(struct wl_listener *listener, void *data) { From e18839ec1113df3a0821a9dc07eb5a2c50d65408 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sun, 3 Aug 2025 07:11:17 +0800 Subject: [PATCH 006/591] opt: exclude some windows that cannot be maximized --- src/client/client.h | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/client/client.h b/src/client/client.h index c2acbd13..93a574f9 100644 --- a/src/client/client.h +++ b/src/client/client.h @@ -343,6 +343,9 @@ static inline uint32_t client_set_size(Client *c, uint32_t width, } static inline void client_set_tiled(Client *c, uint32_t edges) { + struct wlr_xdg_toplevel *toplevel; + struct wlr_xdg_toplevel_state state; + bool need_maximize = false; #ifdef XWAYLAND if (client_is_x11(c)) { wlr_xwayland_surface_set_maximized(c->surface.xwayland, @@ -351,13 +354,25 @@ static inline void client_set_tiled(Client *c, uint32_t edges) { return; } #endif + + toplevel = c->surface.xdg->toplevel; + state = toplevel->current; + if (wl_resource_get_version(c->surface.xdg->toplevel->resource) >= XDG_TOPLEVEL_STATE_TILED_RIGHT_SINCE_VERSION) { wlr_xdg_toplevel_set_tiled(c->surface.xdg->toplevel, edges); + } else { + need_maximize = true; } - wlr_xdg_toplevel_set_maximized(c->surface.xdg->toplevel, - edges != WLR_EDGE_NONE); + // exclude some windows that cannot be maximized, + // such as the login window of linuxqq + if (state.min_width == 0 || state.min_height == 0) + need_maximize = false; + + if (need_maximize) { + wlr_xdg_toplevel_set_maximized(toplevel, edges != WLR_EDGE_NONE); + } } static inline void client_set_suspended(Client *c, int suspended) { From c5591950e5b8151e51ae374adf883748911d1cde Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sun, 3 Aug 2025 07:43:00 +0800 Subject: [PATCH 007/591] opt: optimize fullscreen fakefullscreen and maximizescreen state convert --- src/dispatch/bind_define.h | 4 ++-- src/mango.c | 25 +++++++++++++++---------- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index bac21498..bdcd921f 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -976,7 +976,7 @@ void togglefullscreen(const Arg *arg) { sel->is_in_scratchpad = 0; sel->isnamedscratchpad = 0; - if (sel->isfullscreen || sel->ismaxmizescreen) + if (sel->isfullscreen) setfullscreen(sel, 0); else setfullscreen(sel, 1); @@ -1011,7 +1011,7 @@ void togglemaxmizescreen(const Arg *arg) { sel->is_in_scratchpad = 0; sel->isnamedscratchpad = 0; - if (sel->isfullscreen || sel->ismaxmizescreen) + if (sel->ismaxmizescreen) setmaxmizescreen(sel, 0); else setmaxmizescreen(sel, 1); diff --git a/src/mango.c b/src/mango.c index ab008e71..0213ec0f 100644 --- a/src/mango.c +++ b/src/mango.c @@ -845,13 +845,13 @@ void applybounds(Client *c, struct wlr_box *bbox) { /*清除全屏标志,还原全屏时清0的border*/ void clear_fullscreen_flag(Client *c) { - if (c->isfullscreen || c->ismaxmizescreen) { - c->isfullscreen = 0; - c->isfloating = 0; - c->ismaxmizescreen = 0; - c->bw = c->isnoborder ? 0 : borderpx; + if (c->isfullscreen) { setfullscreen(c, false); } + + if (c->ismaxmizescreen) { + setmaxmizescreen(c, 0); + } } void minized(const Arg *arg) { @@ -4049,6 +4049,10 @@ void setmaxmizescreen(Client *c, int maxmizescreen) { : LyrTile]); if (maxmizescreen) { + + if (c->isfullscreen) + setfullscreen(c, 0); + if (c->isfloating) c->oldgeom = c->geom; if (selmon->isoverview) { @@ -4066,8 +4070,6 @@ void setmaxmizescreen(Client *c, int maxmizescreen) { } else { c->bw = c->isnoborder ? 0 : borderpx; c->ismaxmizescreen = 0; - c->isfullscreen = 0; - setfullscreen(c, false); if (c->isfloating) setfloating(c, 1); arrange(c->mon, false); @@ -4080,7 +4082,8 @@ void setfakefullscreen(Client *c, int fakefullscreen) { return; if (c->isfullscreen) setfullscreen(c, 0); - client_set_fullscreen(c, fakefullscreen); + else + client_set_fullscreen(c, fakefullscreen); } void setfullscreen(Client *c, int fullscreen) // 用自定义全屏代理自带全屏 @@ -4104,6 +4107,9 @@ void setfullscreen(Client *c, int fullscreen) // 用自定义全屏代理自带 } if (fullscreen) { + if (c->ismaxmizescreen) + setmaxmizescreen(c, 0); + if (c->isfloating) c->oldgeom = c->geom; if (selmon->isoverview) { @@ -4119,8 +4125,7 @@ void setfullscreen(Client *c, int fullscreen) // 用自定义全屏代理自带 } else { c->bw = c->isnoborder ? 0 : borderpx; c->isfullscreen = 0; - c->isfullscreen = 0; - c->ismaxmizescreen = 0; + c->isfakefullscreen = 0; if (c->isfloating) setfloating(c, 1); arrange(c->mon, false); From a3b3b6146287be2e5e7cb5e4223c02cb0c521f7f Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sun, 3 Aug 2025 12:37:51 +0800 Subject: [PATCH 008/591] opt: optimize layer convert in maxmizescreen and fullscreen --- src/dispatch/bind_define.h | 2 ++ src/mango.c | 30 +++++++++++++++--------------- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index bdcd921f..c814c5b6 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -1015,6 +1015,8 @@ void togglemaxmizescreen(const Arg *arg) { setmaxmizescreen(sel, 0); else setmaxmizescreen(sel, 1); + + setborder_color(sel); } void toggleoverlay(const Arg *arg) { if (!selmon->sel || !selmon->sel->mon || selmon->sel->isfullscreen) { diff --git a/src/mango.c b/src/mango.c index 0213ec0f..ade4f510 100644 --- a/src/mango.c +++ b/src/mango.c @@ -4044,10 +4044,6 @@ void setmaxmizescreen(Client *c, int maxmizescreen) { c->ismaxmizescreen = maxmizescreen; - wlr_scene_node_reparent(&c->scene->node, layers[maxmizescreen ? LyrTile - : c->isfloating ? LyrFloat - : LyrTile]); - if (maxmizescreen) { if (c->isfullscreen) @@ -4074,6 +4070,10 @@ void setmaxmizescreen(Client *c, int maxmizescreen) { setfloating(c, 1); arrange(c->mon, false); } + + wlr_scene_node_reparent(&c->scene->node, layers[maxmizescreen ? LyrTile + : c->isfloating ? LyrFloat + : LyrTile]); } void setfakefullscreen(Client *c, int fakefullscreen) { @@ -4095,17 +4095,6 @@ void setfullscreen(Client *c, int fullscreen) // 用自定义全屏代理自带 client_set_fullscreen(c, fullscreen); - if (c->isoverlay) { - wlr_scene_node_reparent(&c->scene->node, layers[LyrOverlay]); - } else if (client_should_overtop(c) && c->isfloating) { - wlr_scene_node_reparent(&c->scene->node, layers[LyrFSorOverTop]); - } else { - wlr_scene_node_reparent(&c->scene->node, - layers[fullscreen ? LyrFSorOverTop - : c->isfloating ? LyrFloat - : LyrTile]); - } - if (fullscreen) { if (c->ismaxmizescreen) setmaxmizescreen(c, 0); @@ -4130,6 +4119,17 @@ void setfullscreen(Client *c, int fullscreen) // 用自定义全屏代理自带 setfloating(c, 1); arrange(c->mon, false); } + + if (c->isoverlay) { + wlr_scene_node_reparent(&c->scene->node, layers[LyrOverlay]); + } else if (client_should_overtop(c) && c->isfloating) { + wlr_scene_node_reparent(&c->scene->node, layers[LyrFSorOverTop]); + } else { + wlr_scene_node_reparent(&c->scene->node, + layers[fullscreen ? LyrFSorOverTop + : c->isfloating ? LyrFloat + : LyrTile]); + } } void setgaps(int oh, int ov, int ih, int iv) { From 692b7f867c75f1e8eb7b881a23747a121e716591 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sun, 3 Aug 2025 12:52:14 +0800 Subject: [PATCH 009/591] opt: optimize code struct --- src/mango.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/mango.c b/src/mango.c index ade4f510..c75ed15b 100644 --- a/src/mango.c +++ b/src/mango.c @@ -3963,15 +3963,6 @@ setfloating(Client *c, int floating) { if (!c || !c->mon || !client_surface(c)->mapped || c->iskilling) return; - if (c->isoverlay) { - wlr_scene_node_reparent(&c->scene->node, layers[LyrOverlay]); - } else if (client_should_overtop(c) && c->isfloating) { - wlr_scene_node_reparent(&c->scene->node, layers[LyrFSorOverTop]); - } else { - wlr_scene_node_reparent(&c->scene->node, - layers[c->isfloating ? LyrFloat : LyrTile]); - } - target_box = c->geom; if (floating == 1 && c != grabc) { @@ -4024,6 +4015,15 @@ setfloating(Client *c, int floating) { } } + if (c->isoverlay) { + wlr_scene_node_reparent(&c->scene->node, layers[LyrOverlay]); + } else if (client_should_overtop(c) && c->isfloating) { + wlr_scene_node_reparent(&c->scene->node, layers[LyrFSorOverTop]); + } else { + wlr_scene_node_reparent(&c->scene->node, + layers[c->isfloating ? LyrFloat : LyrTile]); + } + arrange(c->mon, false); setborder_color(c); printstatus(); From 47809c57834677da09ddf7362d1d8b22cb7c340e Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Mon, 4 Aug 2025 10:40:29 +0800 Subject: [PATCH 010/591] fix: build fail for non xwayland --- src/client/client.h | 12 ++++++++++++ src/mango.c | 11 ++--------- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/client/client.h b/src/client/client.h index 93a574f9..215d56ed 100644 --- a/src/client/client.h +++ b/src/client/client.h @@ -456,3 +456,15 @@ static inline int client_wants_fullscreen(Client *c) { #endif return c->surface.xdg->toplevel->requested.fullscreen; } + +static inline bool client_request_minimize(Client *c, void *data) { + +#ifdef XWAYLAND + if (client_is_x11(c)) { + struct wlr_xwayland_minimize_event *event = data; + return event->minimize; + } +#endif + + return c->surface.xdg->toplevel->requested.minimized; +} \ No newline at end of file diff --git a/src/mango.c b/src/mango.c index c75ed15b..313e7668 100644 --- a/src/mango.c +++ b/src/mango.c @@ -3419,20 +3419,13 @@ minimizenotify(struct wl_listener *listener, void *data) { // togglemaxmizescreen(&(Arg){0}); Client *c = wl_container_of(listener, c, minimize); - struct wlr_xwayland_minimize_event *event = data; if (!c || !c->mon || c->iskilling || c->isminied) return; - if (!client_is_x11(c)) { - if (!c->surface.xdg->toplevel->requested.minimized) - return; - } else { - if (!event->minimize) - return; + if (client_request_minimize(c, data)) { + set_minized(c); } - - set_minized(c); } void motionabsolute(struct wl_listener *listener, void *data) { From c6102ddca1eda5e3bf374bd3dbef764a9611bd40 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Tue, 5 Aug 2025 12:30:06 +0800 Subject: [PATCH 011/591] feat: respect the min and max size hint for the floating window --- src/animation/client.h | 5 ++++ src/client/client.h | 52 ++++++++++++++++++++++++++++++++++++++++++ src/mango.c | 3 +++ 3 files changed, 60 insertions(+) diff --git a/src/animation/client.h b/src/animation/client.h index 98b9a99c..c5105f43 100644 --- a/src/animation/client.h +++ b/src/animation/client.h @@ -921,6 +921,10 @@ void resize(Client *c, struct wlr_box geo, int interact) { bbox); // 去掉这个推荐的窗口大小,因为有时推荐的窗口特别大导致平铺异常 } + if (!c->ismaxmizescreen && !c->isfullscreen && c->isfloating) { + client_set_size_bound(c); + } + if (!c->is_pending_open_animation) { c->animation.begin_fade_in = false; } @@ -965,6 +969,7 @@ void resize(Client *c, struct wlr_box geo, int interact) { if (c == grabc) { c->animation.running = false; c->need_output_flush = false; + c->animainit_geom = c->current = c->pending = c->animation.current = c->geom; wlr_scene_node_set_position(&c->scene->node, c->geom.x, c->geom.y); diff --git a/src/client/client.h b/src/client/client.h index 215d56ed..2bf82039 100644 --- a/src/client/client.h +++ b/src/client/client.h @@ -213,6 +213,10 @@ static inline int client_is_float_type(Client *c) { if (client_is_x11(c)) { struct wlr_xwayland_surface *surface = c->surface.xwayland; xcb_size_hints_t *size_hints = surface->size_hints; + + if (!size_hints) + return 0; + if (surface->modal) return 1; @@ -467,4 +471,52 @@ static inline bool client_request_minimize(Client *c, void *data) { #endif return c->surface.xdg->toplevel->requested.minimized; +} + +static inline void client_set_size_bound(Client *c) { + struct wlr_xdg_toplevel *toplevel; + struct wlr_xdg_toplevel_state state; + +#ifdef XWAYLAND + if (client_is_x11(c)) { + struct wlr_xwayland_surface *surface = c->surface.xwayland; + xcb_size_hints_t *size_hints = surface->size_hints; + + if (!size_hints) + return; + + if ((unsigned int)c->geom.width - 2 * c->bw < size_hints->min_width && + size_hints->min_width > 0) + c->geom.width = size_hints->min_width + 2 * c->bw; + if ((unsigned int)c->geom.height - 2 * c->bw < size_hints->min_height && + size_hints->min_height > 0) + c->geom.height = size_hints->min_height + 2 * c->bw; + if ((unsigned int)c->geom.width - 2 * c->bw > size_hints->max_width && + size_hints->max_width > 0) + c->geom.width = size_hints->max_width + 2 * c->bw; + if ((unsigned int)c->geom.height - 2 * c->bw > size_hints->max_height && + size_hints->max_height > 0) + c->geom.height = size_hints->max_height + 2 * c->bw; + return; + } +#endif + + toplevel = c->surface.xdg->toplevel; + state = toplevel->current; + if ((unsigned int)c->geom.width - 2 * c->bw < state.min_width && + state.min_width > 0) { + c->geom.width = state.min_width + 2 * c->bw; + } + if ((unsigned int)c->geom.height - 2 * c->bw < state.min_height && + state.min_height > 0) { + c->geom.height = state.min_height + 2 * c->bw; + } + if ((unsigned int)c->geom.width - 2 * c->bw > state.max_width && + state.max_width > 0) { + c->geom.width = state.max_width + 2 * c->bw; + } + if ((unsigned int)c->geom.height - 2 * c->bw > state.max_height && + state.max_height > 0) { + c->geom.height = state.max_height + 2 * c->bw; + } } \ No newline at end of file diff --git a/src/mango.c b/src/mango.c index 313e7668..5f11604b 100644 --- a/src/mango.c +++ b/src/mango.c @@ -1077,6 +1077,7 @@ int applyrulesgeom(Client *c) { c->geom.width = r->width > 0 ? r->width : c->geom.width; c->geom.height = r->height > 0 ? r->height : c->geom.height; + client_set_size_bound(c); // 重新计算居中的坐标 if (r->offsetx != 0 || r->offsety != 0 || r->width > 0 || r->height > 0) @@ -1135,6 +1136,8 @@ void applyrules(Client *c) { if (r->height > 0) c->geom.height = r->height; + client_set_size_bound(c); + if (r->offsetx || r->offsety || r->width > 0 || r->height > 0) { hit_rule_pos = true; c->oldgeom = c->geom = setclient_coordinate_center( From 7f32adbdd96d1055e1c7079b39b773257ec7ac8b Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Tue, 5 Aug 2025 21:04:05 +0800 Subject: [PATCH 012/591] feat: add isnosizehit option to windowrule --- src/animation/client.h | 3 ++- src/config/parse_config.h | 4 ++++ src/mango.c | 10 +++++++--- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/animation/client.h b/src/animation/client.h index c5105f43..9e8a3cdf 100644 --- a/src/animation/client.h +++ b/src/animation/client.h @@ -921,7 +921,8 @@ void resize(Client *c, struct wlr_box geo, int interact) { bbox); // 去掉这个推荐的窗口大小,因为有时推荐的窗口特别大导致平铺异常 } - if (!c->ismaxmizescreen && !c->isfullscreen && c->isfloating) { + if (!c->isnosizehint && !c->ismaxmizescreen && !c->isfullscreen && + c->isfloating) { client_set_size_bound(c); } diff --git a/src/config/parse_config.h b/src/config/parse_config.h index 4f3a533e..fe8aca8f 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -50,6 +50,7 @@ typedef struct { int isunglobal; int isglobal; int isoverlay; + int isnosizehint; const char *monitor; int offsetx; int offsety; @@ -1415,6 +1416,7 @@ void parse_config_line(Config *config, const char *line) { rule->isunglobal = -1; rule->isglobal = -1; rule->isoverlay = -1; + rule->isnosizehint = -1; rule->isterm = -1; rule->noswallow = -1; rule->noblur = -1; @@ -1497,6 +1499,8 @@ void parse_config_line(Config *config, const char *line) { rule->focused_opacity = atof(val); } else if (strcmp(key, "isoverlay") == 0) { rule->isoverlay = atoi(val); + } else if (strcmp(key, "isnosizehint") == 0) { + rule->isnosizehint = atoi(val); } else if (strcmp(key, "isterm") == 0) { rule->isterm = atoi(val); } else if (strcmp(key, "noswallow") == 0) { diff --git a/src/mango.c b/src/mango.c index 5f11604b..61909d0a 100644 --- a/src/mango.c +++ b/src/mango.c @@ -265,7 +265,7 @@ struct Client { unsigned int configure_serial; struct wlr_foreign_toplevel_handle_v1 *foreign_toplevel; int isfloating, isurgent, isfullscreen, isfakefullscreen, - need_float_size_reduce, isminied, isoverlay; + need_float_size_reduce, isminied, isoverlay, isnosizehint; int ismaxmizescreen; int overview_backup_bw; int fullscreen_backup_x, fullscreen_backup_y, fullscreen_backup_w, @@ -1042,6 +1042,7 @@ static void apply_rule_properties(Client *c, const ConfigWinRule *r) { APPLY_INT_PROP(c, r, isnamedscratchpad); APPLY_INT_PROP(c, r, isglobal); APPLY_INT_PROP(c, r, isoverlay); + APPLY_INT_PROP(c, r, isnosizehint); APPLY_INT_PROP(c, r, isunglobal); APPLY_INT_PROP(c, r, scratchpad_width); APPLY_INT_PROP(c, r, scratchpad_height); @@ -1077,7 +1078,9 @@ int applyrulesgeom(Client *c) { c->geom.width = r->width > 0 ? r->width : c->geom.width; c->geom.height = r->height > 0 ? r->height : c->geom.height; - client_set_size_bound(c); + + if (!c->isnosizehint) + client_set_size_bound(c); // 重新计算居中的坐标 if (r->offsetx != 0 || r->offsety != 0 || r->width > 0 || r->height > 0) @@ -1136,7 +1139,8 @@ void applyrules(Client *c) { if (r->height > 0) c->geom.height = r->height; - client_set_size_bound(c); + if (!c->isnosizehint) + client_set_size_bound(c); if (r->offsetx || r->offsety || r->width > 0 || r->height > 0) { hit_rule_pos = true; From bdcfa1d542b261c2108c6a06c26db58ac1e24837 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Tue, 5 Aug 2025 21:06:21 +0800 Subject: [PATCH 013/591] fix: miss set isunglobal and isnosizehint var init value --- src/mango.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/mango.c b/src/mango.c index 61909d0a..7b31b57a 100644 --- a/src/mango.c +++ b/src/mango.c @@ -3253,6 +3253,8 @@ void init_client_properties(Client *c) { c->no_force_center = 0; c->scratchpad_width = 0; c->scratchpad_height = 0; + c->isnoborder = 0; + c->isnosizehint = 0; } void // old fix to 0.5 From f9dcaaae777b2d15c2a6802344d97fc34ed9580f Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Wed, 6 Aug 2025 12:04:44 +0800 Subject: [PATCH 014/591] fix: Fix memory leaks --- src/mango.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mango.c b/src/mango.c index 7b31b57a..e58d1007 100644 --- a/src/mango.c +++ b/src/mango.c @@ -1965,6 +1965,7 @@ void cleanupmon(struct wl_listener *listener, void *data) { wlr_scene_node_destroy(&m->blur->node); m->blur = NULL; } + free(m->pertag); free(m); } @@ -4569,7 +4570,6 @@ void setup(void) { input_method_manager = wlr_input_method_manager_v2_create(dpy); text_input_manager = wlr_text_input_manager_v3_create(dpy); - dwl_input_method_relay = calloc(1, sizeof(*dwl_input_method_relay)); dwl_input_method_relay = dwl_im_relay_create(); wl_global_create(dpy, &zdwl_ipc_manager_v2_interface, 2, NULL, From 3ca40b49f5b364eeb3c48e55405fe0e62d90c732 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Thu, 7 Aug 2025 10:06:53 +0800 Subject: [PATCH 015/591] fix: avoid to set null client --- src/dispatch/bind_define.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index c814c5b6..19947d5c 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -872,7 +872,12 @@ void tagmon(const Arg *arg) { void tagsilent(const Arg *arg) { Client *fc; - Client *target_client = selmon->sel; + Client *target_client; + + if (!selmon || !selmon->sel) + return; + + target_client = selmon->sel; target_client->tags = arg->ui & TAGMASK; wl_list_for_each(fc, &clients, link) { if (fc && fc != target_client && target_client->tags & fc->tags && From 3efb82fd7bc5b0ecc06fc5185c824f060e147ce4 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Thu, 7 Aug 2025 11:34:14 +0800 Subject: [PATCH 016/591] opt: not convert kb layout exclude us layout --- src/config/parse_config.h | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/config/parse_config.h b/src/config/parse_config.h index fe8aca8f..39d8476a 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -462,14 +462,6 @@ xkb_keysym_t normalize_keysym(xkb_keysym_t sym) { case XKB_KEY_parenright: return XKB_KEY_0; // ) - // 其他布局可能需要的变体(如欧洲键盘) - case XKB_KEY_quotedbl: - return XKB_KEY_2; // " - case XKB_KEY_section: - return XKB_KEY_6; // § - case XKB_KEY_degree: - return XKB_KEY_0; // ° - default: return sym; } From 5be3d63ea73f34d71453672a6ce05d338a9a2ee1 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Thu, 7 Aug 2025 21:30:45 +0800 Subject: [PATCH 017/591] opt: change unmanaged window layer to overlay --- src/mango.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mango.c b/src/mango.c index e58d1007..e4ebad01 100644 --- a/src/mango.c +++ b/src/mango.c @@ -3295,7 +3295,7 @@ mapnotify(struct wl_listener *listener, void *data) { /* Handle unmanaged clients first so we can return prior create borders */ if (client_is_unmanaged(c)) { /* Unmanaged clients always are floating */ - wlr_scene_node_reparent(&c->scene->node, layers[LyrFSorOverTop]); + wlr_scene_node_reparent(&c->scene->node, layers[LyrOverlay]); wlr_scene_node_set_position(&c->scene->node, c->geom.x, c->geom.y); if (client_wants_focus(c)) { focusclient(c, 1); From a89d999ad60fb8d8485ef49e5af88e317a33f4d2 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sat, 9 Aug 2025 11:48:29 +0800 Subject: [PATCH 018/591] bump version 0.8.1 --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 85bd5399..73725d17 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('mango', ['c', 'cpp'], - version : '0.8.0' + version : '0.8.1' ) subdir('protocols') From 1b7769992c77aa7c079672e506b2f61466bfd3e2 Mon Sep 17 00:00:00 2001 From: Lin Xianyi Date: Sun, 10 Aug 2025 08:41:38 +0800 Subject: [PATCH 019/591] nix: Use types.lines for settings and autostart_sh --- nix/hm-modules.nix | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nix/hm-modules.nix b/nix/hm-modules.nix index 38875a41..1d1edd4c 100644 --- a/nix/hm-modules.nix +++ b/nix/hm-modules.nix @@ -72,7 +72,7 @@ in { }; settings = mkOption { description = "mango config content"; - type = types.str; + type = types.lines; default = ""; example = '' # menu and terminal @@ -82,7 +82,7 @@ in { }; autostart_sh = mkOption { description = "WARRNING: This is a shell script, but no need to add shebang"; - type = types.str; + type = types.lines; default = ""; example = '' waybar & From b606c325c817833681e0a07405970995ba236f58 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sun, 10 Aug 2025 12:25:08 +0800 Subject: [PATCH 020/591] opt: default maximize all client --- src/client/client.h | 12 +----------- src/config/parse_config.h | 4 ++++ src/mango.c | 16 +++++++++------- 3 files changed, 14 insertions(+), 18 deletions(-) diff --git a/src/client/client.h b/src/client/client.h index 2bf82039..ddbc9c66 100644 --- a/src/client/client.h +++ b/src/client/client.h @@ -348,8 +348,6 @@ static inline uint32_t client_set_size(Client *c, uint32_t width, static inline void client_set_tiled(Client *c, uint32_t edges) { struct wlr_xdg_toplevel *toplevel; - struct wlr_xdg_toplevel_state state; - bool need_maximize = false; #ifdef XWAYLAND if (client_is_x11(c)) { wlr_xwayland_surface_set_maximized(c->surface.xwayland, @@ -360,21 +358,13 @@ static inline void client_set_tiled(Client *c, uint32_t edges) { #endif toplevel = c->surface.xdg->toplevel; - state = toplevel->current; if (wl_resource_get_version(c->surface.xdg->toplevel->resource) >= XDG_TOPLEVEL_STATE_TILED_RIGHT_SINCE_VERSION) { wlr_xdg_toplevel_set_tiled(c->surface.xdg->toplevel, edges); - } else { - need_maximize = true; } - // exclude some windows that cannot be maximized, - // such as the login window of linuxqq - if (state.min_width == 0 || state.min_height == 0) - need_maximize = false; - - if (need_maximize) { + if (!c->ignore_maximize) { wlr_xdg_toplevel_set_maximized(toplevel, edges != WLR_EDGE_NONE); } } diff --git a/src/config/parse_config.h b/src/config/parse_config.h index 39d8476a..32925b99 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -50,6 +50,7 @@ typedef struct { int isunglobal; int isglobal; int isoverlay; + int ignore_maximize; int isnosizehint; const char *monitor; int offsetx; @@ -1408,6 +1409,7 @@ void parse_config_line(Config *config, const char *line) { rule->isunglobal = -1; rule->isglobal = -1; rule->isoverlay = -1; + rule->ignore_maximize = -1; rule->isnosizehint = -1; rule->isterm = -1; rule->noswallow = -1; @@ -1491,6 +1493,8 @@ void parse_config_line(Config *config, const char *line) { rule->focused_opacity = atof(val); } else if (strcmp(key, "isoverlay") == 0) { rule->isoverlay = atoi(val); + } else if (strcmp(key, "ignore_maximize") == 0) { + rule->ignore_maximize = atoi(val); } else if (strcmp(key, "isnosizehint") == 0) { rule->isnosizehint = atoi(val); } else if (strcmp(key, "isterm") == 0) { diff --git a/src/mango.c b/src/mango.c index e4ebad01..55b1a78f 100644 --- a/src/mango.c +++ b/src/mango.c @@ -265,7 +265,8 @@ struct Client { unsigned int configure_serial; struct wlr_foreign_toplevel_handle_v1 *foreign_toplevel; int isfloating, isurgent, isfullscreen, isfakefullscreen, - need_float_size_reduce, isminied, isoverlay, isnosizehint; + need_float_size_reduce, isminied, isoverlay, isnosizehint, + ignore_maximize; int ismaxmizescreen; int overview_backup_bw; int fullscreen_backup_x, fullscreen_backup_y, fullscreen_backup_w, @@ -1042,6 +1043,7 @@ static void apply_rule_properties(Client *c, const ConfigWinRule *r) { APPLY_INT_PROP(c, r, isnamedscratchpad); APPLY_INT_PROP(c, r, isglobal); APPLY_INT_PROP(c, r, isoverlay); + APPLY_INT_PROP(c, r, ignore_maximize); APPLY_INT_PROP(c, r, isnosizehint); APPLY_INT_PROP(c, r, isunglobal); APPLY_INT_PROP(c, r, scratchpad_width); @@ -2189,8 +2191,8 @@ void commitnotify(struct wl_listener *listener, void *data) { setmon(c, NULL, 0, true); /* Make sure to reapply rules in mapnotify() */ - // client_set_tiled(c, WLR_EDGE_TOP | WLR_EDGE_BOTTOM | WLR_EDGE_LEFT | - // WLR_EDGE_RIGHT); + client_set_tiled(c, WLR_EDGE_TOP | WLR_EDGE_BOTTOM | WLR_EDGE_LEFT | + WLR_EDGE_RIGHT); uint32_t serial = wlr_xdg_surface_schedule_configure(c->surface.xdg); if (serial > 0) { @@ -3256,6 +3258,7 @@ void init_client_properties(Client *c) { c->scratchpad_height = 0; c->isnoborder = 0; c->isnosizehint = 0; + c->ignore_maximize = 0; } void // old fix to 0.5 @@ -3325,10 +3328,6 @@ mapnotify(struct wl_listener *listener, void *data) { wlr_scene_node_lower_to_bottom(&c->shadow->node); wlr_scene_node_set_enabled(&c->shadow->node, true); - /* Initialize client geometry with room for border */ - client_set_tiled(c, WLR_EDGE_TOP | WLR_EDGE_BOTTOM | WLR_EDGE_LEFT | - WLR_EDGE_RIGHT); - if (new_is_master && selmon && !is_scroller_layout(selmon)) // tile at the top wl_list_insert(&clients, &c->link); // 新窗口是master,头部入栈 @@ -3353,6 +3352,9 @@ mapnotify(struct wl_listener *listener, void *data) { applyrules(c); } + client_set_tiled(c, WLR_EDGE_TOP | WLR_EDGE_BOTTOM | WLR_EDGE_LEFT | + WLR_EDGE_RIGHT); + // apply buffer effects of client wlr_scene_node_for_each_buffer(&c->scene_surface->node, iter_xdg_scene_buffers, c); From 12b1a4c6cf9521bedaf89d35d375d37eff8aef0d Mon Sep 17 00:00:00 2001 From: Yappaholic Date: Sun, 10 Aug 2025 14:12:16 +0300 Subject: [PATCH 021/591] docs: fix gentoo installation steps --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index cadc5f8b..e042e323 100644 --- a/README.md +++ b/README.md @@ -89,12 +89,12 @@ eselect repository enable guru emerge --sync guru ``` -Then, add `gui-libs/scenefx` and `gui-wm/mango` to the `package.accept_keywords`. +Then, add `gui-libs/scenefx` and `gui-wm/mangowc` to the `package.accept_keywords`. Finally, install the package: ```bash -emerge --ask --verbose gui-wm/mango +emerge --ask --verbose gui-wm/mangowc ``` Patching wlroots is done by getting the patch with git from [the repository](https://github.com/DreamMaoMao/wlroots.git) @@ -237,6 +237,7 @@ To package mango for other distributions, you can check the reference setup for: - [nix](https://github.com/DreamMaoMao/mango/blob/main/nix/default.nix) - [arch](https://aur.archlinux.org/cgit/aur.git/tree/PKGBUILD?h=mango-git). +- [gentoo](https://data.gpo.zugaina.org/guru/gui-wm/mangowc) Currently building mango requires a patched version of `wlroots-0.19`. If possible, the patch can be extracted from the [latest commit](https://github.com/DreamMaoMao/wlroots.git) and applied on `prepare` step. If it is not possible, you will need to create a separate `wlroots` package and make it a build dependency. From 125968302721572885bb6ec8eb5bb74c790c55da Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Tue, 12 Aug 2025 11:31:54 +0800 Subject: [PATCH 022/591] fix: set wrong keyboard_grab in handle_input_method_grab_keyboard This results in the inability to continuously use the mod key and mouse to drag the window the problem also in axisbind and gesturebind --- src/ext-protocol/text-input.h | 6 +++++- src/mango.c | 9 ++++++--- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/ext-protocol/text-input.h b/src/ext-protocol/text-input.h index ee647a20..0577d029 100644 --- a/src/ext-protocol/text-input.h +++ b/src/ext-protocol/text-input.h @@ -111,6 +111,8 @@ get_keyboard_grab(KeyboardGroup *keyboard) { return NULL; } + // 如果键盘不是物理键盘组的键盘,则返回NULL + // kb_group是一个物理键盘组,它的键盘是物理键盘 if (keyboard != kb_group) return NULL; @@ -347,7 +349,9 @@ static void handle_input_method_grab_keyboard(struct wl_listener *listener, wl_container_of(listener, relay, input_method_grab_keyboard); struct wlr_input_method_keyboard_grab_v2 *keyboard_grab = data; - struct wlr_keyboard *active_keyboard = wlr_seat_get_keyboard(seat); + // 活动键盘应该是从物理键盘组中获取的, + // wlr_seat_get_keyboard可能获取到的是虚拟键盘,所以会造成设置错误 + struct wlr_keyboard *active_keyboard = &kb_group->wlr_group->keyboard; if (!is_keyboard_emulated_by_input_method(active_keyboard, relay->input_method)) { diff --git a/src/mango.c b/src/mango.c index 55b1a78f..184ca7ff 100644 --- a/src/mango.c +++ b/src/mango.c @@ -1545,7 +1545,7 @@ axisnotify(struct wl_listener *listener, void *data) { // IDLE_NOTIFY_ACTIVITY; handlecursoractivity(); wlr_idle_notifier_v1_notify_activity(idle_notifier, seat); - keyboard = wlr_seat_get_keyboard(seat); + keyboard = &kb_group->wlr_group->keyboard; // 获取当前按键的mask,比如alt+super或者alt+ctrl mods = keyboard ? wlr_keyboard_get_modifiers(keyboard) : 0; @@ -1610,7 +1610,7 @@ int ongesture(struct wlr_pointer_swipe_end_event *event) { motion = swipe_dy < 0 ? SWIPE_UP : SWIPE_DOWN; } - keyboard = wlr_seat_get_keyboard(seat); + keyboard = &kb_group->wlr_group->keyboard; mods = keyboard ? wlr_keyboard_get_modifiers(keyboard) : 0; for (ji = 0; ji < config.gesture_bindings_count; ji++) { @@ -1773,7 +1773,7 @@ buttonpress(struct wl_listener *listener, void *data) { } } - keyboard = wlr_seat_get_keyboard(seat); + keyboard = &kb_group->wlr_group->keyboard; mods = keyboard ? wlr_keyboard_get_modifiers(keyboard) : 0; for (ji = 0; ji < config.mouse_bindings_count; ji++) { if (config.mouse_bindings_count < 1) @@ -3164,7 +3164,10 @@ void keypressmod(struct wl_listener *listener, void *data) { * pressed. We simply communicate this to the client. */ KeyboardGroup *group = wl_container_of(listener, group, modifiers); + wlr_log(WLR_ERROR, "0"); if (!dwl_im_keyboard_grab_forward_modifiers(group)) { + wlr_log(WLR_ERROR, "1"); + wlr_seat_set_keyboard(seat, &group->wlr_group->keyboard); /* Send modifiers to the client. */ wlr_seat_keyboard_notify_modifiers( From b6c4f59a071671822675ec54818fa49686436e7b Mon Sep 17 00:00:00 2001 From: Lin Xianyi Date: Tue, 12 Aug 2025 17:07:45 +0800 Subject: [PATCH 023/591] nix: add package option for home-manager --- nix/hm-modules.nix | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/nix/hm-modules.nix b/nix/hm-modules.nix index 1d1edd4c..72628b1d 100644 --- a/nix/hm-modules.nix +++ b/nix/hm-modules.nix @@ -4,7 +4,6 @@ self: { pkgs, ... }: let - inherit (self.packages.${pkgs.system}) mango; cfg = config.wayland.windowManager.mango; variables = lib.concatStringsSep " " cfg.systemd.variables; extraCommands = lib.concatStringsSep " && " cfg.systemd.extraCommands; @@ -20,6 +19,11 @@ in { type = types.bool; default = false; }; + package = lib.mkOption { + type = lib.types.package; + default = self.packages.${pkgs.system}.mango; + description = "The mango package to use"; + }; systemd = { enable = mkOption { type = types.bool; @@ -92,7 +96,7 @@ in { }; config = lib.mkIf cfg.enable { - home.packages = [mango]; + home.packages = [ cfg.package ]; home.activation = lib.optionalAttrs (cfg.autostart_sh != "") { createMangoScript = lib.hm.dag.entryAfter ["clearMangoConfig"] '' From 27aeec703c6eceb543acab1d9b82e94bca27d695 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Tue, 12 Aug 2025 11:31:54 +0800 Subject: [PATCH 024/591] fix: set wrong keyboard_grab in handle_input_method_grab_keyboard This results in the inability to continuously use the mod key and mouse to drag the window the problem also in axisbind and gesturebind --- src/ext-protocol/text-input.h | 6 +++++- src/mango.c | 7 ++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/ext-protocol/text-input.h b/src/ext-protocol/text-input.h index ee647a20..0577d029 100644 --- a/src/ext-protocol/text-input.h +++ b/src/ext-protocol/text-input.h @@ -111,6 +111,8 @@ get_keyboard_grab(KeyboardGroup *keyboard) { return NULL; } + // 如果键盘不是物理键盘组的键盘,则返回NULL + // kb_group是一个物理键盘组,它的键盘是物理键盘 if (keyboard != kb_group) return NULL; @@ -347,7 +349,9 @@ static void handle_input_method_grab_keyboard(struct wl_listener *listener, wl_container_of(listener, relay, input_method_grab_keyboard); struct wlr_input_method_keyboard_grab_v2 *keyboard_grab = data; - struct wlr_keyboard *active_keyboard = wlr_seat_get_keyboard(seat); + // 活动键盘应该是从物理键盘组中获取的, + // wlr_seat_get_keyboard可能获取到的是虚拟键盘,所以会造成设置错误 + struct wlr_keyboard *active_keyboard = &kb_group->wlr_group->keyboard; if (!is_keyboard_emulated_by_input_method(active_keyboard, relay->input_method)) { diff --git a/src/mango.c b/src/mango.c index 55b1a78f..e32b7232 100644 --- a/src/mango.c +++ b/src/mango.c @@ -1545,7 +1545,7 @@ axisnotify(struct wl_listener *listener, void *data) { // IDLE_NOTIFY_ACTIVITY; handlecursoractivity(); wlr_idle_notifier_v1_notify_activity(idle_notifier, seat); - keyboard = wlr_seat_get_keyboard(seat); + keyboard = &kb_group->wlr_group->keyboard; // 获取当前按键的mask,比如alt+super或者alt+ctrl mods = keyboard ? wlr_keyboard_get_modifiers(keyboard) : 0; @@ -1610,7 +1610,7 @@ int ongesture(struct wlr_pointer_swipe_end_event *event) { motion = swipe_dy < 0 ? SWIPE_UP : SWIPE_DOWN; } - keyboard = wlr_seat_get_keyboard(seat); + keyboard = &kb_group->wlr_group->keyboard; mods = keyboard ? wlr_keyboard_get_modifiers(keyboard) : 0; for (ji = 0; ji < config.gesture_bindings_count; ji++) { @@ -1773,7 +1773,7 @@ buttonpress(struct wl_listener *listener, void *data) { } } - keyboard = wlr_seat_get_keyboard(seat); + keyboard = &kb_group->wlr_group->keyboard; mods = keyboard ? wlr_keyboard_get_modifiers(keyboard) : 0; for (ji = 0; ji < config.mouse_bindings_count; ji++) { if (config.mouse_bindings_count < 1) @@ -3165,6 +3165,7 @@ void keypressmod(struct wl_listener *listener, void *data) { KeyboardGroup *group = wl_container_of(listener, group, modifiers); if (!dwl_im_keyboard_grab_forward_modifiers(group)) { + wlr_seat_set_keyboard(seat, &group->wlr_group->keyboard); /* Send modifiers to the client. */ wlr_seat_keyboard_notify_modifiers( From 3425d143974cee00172dc6221371ccb8f9a3322a Mon Sep 17 00:00:00 2001 From: Lin Xianyi Date: Tue, 12 Aug 2025 19:42:16 +0800 Subject: [PATCH 025/591] nix: expose mmsg in packages --- flake.nix | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/flake.nix b/flake.nix index 9da11680..a3bd8e6d 100644 --- a/flake.nix +++ b/flake.nix @@ -32,12 +32,10 @@ pkgs, ... }: let - inherit - (pkgs) - callPackage - ; + inherit (pkgs) callPackage ; + inherit (inputs.mmsg.packages.${pkgs.system}) mmsg; mango = callPackage ./nix { - inherit (inputs.mmsg.packages.${pkgs.system}) mmsg; + inherit mmsg; inherit (inputs.scenefx.packages.${pkgs.system}) scenefx; }; shellOverride = old: { @@ -51,6 +49,7 @@ }; packages = { inherit mango; + inherit mmsg; }; devShells.default = mango.overrideAttrs shellOverride; formatter = pkgs.alejandra; From 0bfdb1ab4c2e754791f1b0e0d1886e049b6b7f8b Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Wed, 13 Aug 2025 11:34:29 +0800 Subject: [PATCH 026/591] fix: crash when use focuslast dispatch --- src/dispatch/bind_define.h | 35 ++++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index 19947d5c..428498ab 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -66,26 +66,35 @@ void focusdir(const Arg *arg) { } void focuslast(const Arg *arg) { - Client *c, *prev = NULL; + Client *c = NULL; + bool begin = false; + unsigned int target = 0; + wl_list_for_each(c, &fstack, flink) { - if (c->iskilling || c->isminied || c->isunglobal) + if (c->iskilling || c->isminied || c->isunglobal || + client_is_unmanaged(c) || client_should_ignore_focus(c)) continue; - if (c) + + if (selmon && !selmon->sel) { + break; + } + + if (selmon && c == selmon->sel && !begin) { + begin = true; + continue; + } + + if (begin) break; } - struct wl_list *prev_node = c->flink.next; - prev = wl_container_of(prev_node, prev, flink); + if (!c) + return; - unsigned int target; - if (prev) { - if (prev->mon != selmon) { - selmon = prev->mon; - warp_cursor_to_selmon(selmon); - } - target = get_tags_first_tag(prev->tags); + if ((int)c->tags > 0) { + focusclient(c, 1); + target = get_tags_first_tag(c->tags); view(&(Arg){.ui = target}, true); - focusclient(prev, 1); } } From e03a27e90ef7588965cf65d2d26f7b6a11c3b110 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Wed, 13 Aug 2025 12:11:32 +0800 Subject: [PATCH 027/591] fix: miss exclude unmap client in focuslast --- src/dispatch/bind_define.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index 428498ab..8ba8e4c8 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -72,7 +72,8 @@ void focuslast(const Arg *arg) { wl_list_for_each(c, &fstack, flink) { if (c->iskilling || c->isminied || c->isunglobal || - client_is_unmanaged(c) || client_should_ignore_focus(c)) + !client_surface(c)->mapped || client_is_unmanaged(c) || + client_should_ignore_focus(c)) continue; if (selmon && !selmon->sel) { @@ -88,7 +89,7 @@ void focuslast(const Arg *arg) { break; } - if (!c) + if (!c || !client_surface(c)->mapped) return; if ((int)c->tags > 0) { From 5b93990d5bfdb400a4df706506ac99c0a75cbd7a Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Wed, 6 Aug 2025 11:49:04 +0800 Subject: [PATCH 028/591] feat: make asan as the debug type feature --- meson.build | 24 ++++++++++++++++++++---- meson_options.txt | 1 + 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/meson.build b/meson.build index 73725d17..53bce672 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('mango', ['c', 'cpp'], - version : '0.8.1' + version : '0.8.1', ) subdir('protocols') @@ -60,14 +60,29 @@ c_args = [ '-Wno-unused-function', '-DWLR_USE_UNSTABLE', '-D_POSIX_C_SOURCE=200809L', - '-DVERSION="@0@"'.format(version_with_hash), # 版本信息包含 Commit Hash 和最新的 tag - '-DSYSCONFDIR="@0@"'.format('/etc'), # 添加 sysconfdir + '-DVERSION="@0@"'.format(version_with_hash), + '-DSYSCONFDIR="@0@"'.format('/etc'), ] +# 仅在 debug 选项启用时添加调试参数 +if get_option('asan') + c_args += [ + '-fsanitize=address', + '-fno-omit-frame-pointer', + '-fno-optimize-sibling-calls' + ] +endif + if xcb.found() and xlibs.found() c_args += '-DXWAYLAND' endif +# 链接参数(根据 debug 状态添加 ASAN) +link_args = [] +if get_option('asan') + link_args += '-fsanitize=address' +endif + executable('mango', 'src/mango.c', 'src/common/util.c', @@ -85,7 +100,8 @@ executable('mango', pcre2_dep, ], install : true, - c_args : c_args + c_args : c_args, + link_args : link_args, ) desktop_install_dir = join_paths(prefix, 'share/wayland-sessions') diff --git a/meson_options.txt b/meson_options.txt index 63b4edea..2521b28c 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -1 +1,2 @@ option('xwayland', type : 'feature', value : 'enabled') +option('asan', type : 'boolean', value : false) From 9a591993d638b204f20b0b1fc94b17db46352b23 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Thu, 14 Aug 2025 13:28:03 +0800 Subject: [PATCH 029/591] update github workflow --- .github/ISSUE_TEMPLATE/bug_report.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index af52b6ea..5576f632 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -17,6 +17,20 @@ https://github.com/DreamMaoMao/wlroots.git mango version: wlroots version: +## Crash track +1.you need to build mango by enable asan flag. +```bash +meson build -Dprefix=/usr -Dasan=true +`` +2.run mango in tty. +```bash +export ASAN_OPTIONS="detect_leaks=1:halt_on_error=0:log_path=/home/xxx/asan.log" +mango + +``` + +3.after mango crash,paste the log file `/home/xxx/asan.log` here. + ## Description + + + This protocol allows clients to update and get updates from dwl. + + Warning! The protocol described in this file is experimental and + backward incompatible changes may be made. Backward compatible + changes may be added together with the corresponding interface + version bump. + Backward incompatible changes are done by bumping the version + number in the protocol and interface names and resetting the + interface version. Once the protocol is to be declared stable, + the 'z' prefix and the version number in the protocol and + interface names are removed and the interface version number is + reset. + + + + + This interface is exposed as a global in wl_registry. + + Clients can use this interface to get a dwl_ipc_output. + After binding the client will recieve the dwl_ipc_manager.tags and dwl_ipc_manager.layout events. + The dwl_ipc_manager.tags and dwl_ipc_manager.layout events expose tags and layouts to the client. + + + + + Indicates that the client will not the dwl_ipc_manager object anymore. + Objects created through this instance are not affected. + + + + + + Get a dwl_ipc_outout for the specified wl_output. + + + + + + + + This event is sent after binding. + A roundtrip after binding guarantees the client recieved all tags. + + + + + + + This event is sent after binding. + A roundtrip after binding guarantees the client recieved all layouts. + + + + + + + + Observe and control a dwl output. + + Events are double-buffered: + Clients should cache events and redraw when a dwl_ipc_output.frame event is sent. + + Request are not double-buffered: + The compositor will update immediately upon request. + + + + + + + + + + + Indicates to that the client no longer needs this dwl_ipc_output. + + + + + + Indicates the client should hide or show themselves. + If the client is visible then hide, if hidden then show. + + + + + + Indicates if the output is active. Zero is invalid, nonzero is valid. + + + + + + + Indicates that a tag has been updated. + + + + + + + + + + Indicates a new layout is selected. + + + + + + + Indicates the title has changed. + + + + + + + Indicates the appid has changed. + + + + + + + Indicates the layout has changed. Since layout symbols are dynamic. + As opposed to the zdwl_ipc_manager.layout event, this should take precendence when displaying. + You can ignore the zdwl_ipc_output.layout event. + + + + + + + Indicates that a sequence of status updates have finished and the client should redraw. + + + + + + + + + + + + The tags are updated as follows: + new_tags = (current_tags AND and_tags) XOR xor_tags + + + + + + + + + + + + This request allows clients to instruct the compositor to quit mango. + + + + + + + + + + + + + + + + Indicates if the selected client on this output is fullscreen. + + + + + + + Indicates if the selected client on this output is floating. + + + + + + + Indicates if x coordinates of the selected client. + + + + + + + Indicates if y coordinates of the selected client. + + + + + + + Indicates if width of the selected client. + + + + + + + Indicates if height of the selected client. + + + + + + + last map layer. + + + + + + + current keyboard layout. + + + + + + + current keybind mode. + + + + + + + diff --git a/mmsg/src/arg.h b/mmsg/src/arg.h new file mode 100644 index 00000000..ccbd65ab --- /dev/null +++ b/mmsg/src/arg.h @@ -0,0 +1,65 @@ +/* + * Copy me if you can. + * by 20h + */ + +#ifndef ARG_H__ +#define ARG_H__ + +extern char *argv0; + +/* use main(int argc, char *argv[]) */ +#define ARGBEGIN \ + for (argv0 = *argv, argv++, argc--; \ + argv[0] && argv[0][0] == '-' && argv[0][1]; argc--, argv++) { \ + char argc_; \ + char **argv_; \ + int brk_; \ + if (argv[0][1] == '-' && argv[0][2] == '\0') { \ + argv++; \ + argc--; \ + break; \ + } \ + for (brk_ = 0, argv[0]++, argv_ = argv; argv[0][0] && !brk_; \ + argv[0]++) { \ + if (argv_ != argv) \ + break; \ + argc_ = argv[0][0]; \ + switch (argc_) + +/* Handles obsolete -NUM syntax */ +#define ARGNUM \ + case '0': \ + case '1': \ + case '2': \ + case '3': \ + case '4': \ + case '5': \ + case '6': \ + case '7': \ + case '8': \ + case '9' + +#define ARGEND \ + } \ + } + +#define ARGC() argc_ + +#define ARGNUMF() (brk_ = 1, estrtonum(argv[0], 0, INT_MAX)) + +#define EARGF(x) \ + ((argv[0][1] == '\0' && argv[1] == NULL) \ + ? ((x), abort(), (char *)0) \ + : (brk_ = 1, \ + (argv[0][1] != '\0') ? (&argv[0][1]) : (argc--, argv++, argv[0]))) + +#define ARGF() \ + ((argv[0][1] == '\0' && argv[1] == NULL) \ + ? (char *)0 \ + : (brk_ = 1, \ + (argv[0][1] != '\0') ? (&argv[0][1]) : (argc--, argv++, argv[0]))) + +#define LNGARG() &argv[0][0] + +#endif diff --git a/mmsg/src/dynarr.h b/mmsg/src/dynarr.h new file mode 100644 index 00000000..45cd356a --- /dev/null +++ b/mmsg/src/dynarr.h @@ -0,0 +1,30 @@ +#ifndef DYNARR_H__ +#define DYNARR_H__ + +#define DYNARR_DEF(t) \ + struct { \ + t *arr; \ + size_t len, cap, size; \ + } + +#define DYNARR_INIT(p) \ + ((p)->arr = reallocarray((p)->arr, ((p)->cap = 1), \ + ((p)->size = sizeof(((p)->arr[0]))))) + +#define DYNARR_FINI(p) free((p)->arr) + +#define DYNARR_PUSH(p, v) \ + do { \ + if ((p)->len >= (p)->cap) { \ + while ((p)->len >= ((p)->cap *= 2)) \ + ; \ + (p)->arr = reallocarray((p)->arr, (p)->cap, (p)->size); \ + } \ + (p)->arr[(p)->len++] = (v); \ + } while (0) + +#define DYNARR_POP(p) ((p)->arr[(p)->len--]) + +#define DYNARR_CLR(p) ((p)->len = 0) + +#endif diff --git a/mmsg/src/mmsg.c b/mmsg/src/mmsg.c new file mode 100644 index 00000000..ae9270d7 --- /dev/null +++ b/mmsg/src/mmsg.c @@ -0,0 +1,766 @@ +#include "arg.h" +#include "dwl-ipc-unstable-v2-protocol.h" +#include "dynarr.h" +#include +#include +#include +#include +#include +#include +#include + +#define die(fmt, ...) \ + do { \ + fprintf(stderr, fmt "\n", ##__VA_ARGS__); \ + exit(EXIT_FAILURE); \ + } while (0) + +char *argv0; + +static enum { + NONE = 0, + SET = 1 << 0, + GET = 1 << 1, + WATCH = 1 << 2 | GET, +} mode = NONE; + +static int Oflag; +static int Tflag; +static int Lflag; +static int oflag; +static int tflag; +static int lflag; +static int cflag; +static int vflag; +static int mflag; +static int fflag; +static int qflag; +static int dflag; +static int xflag; +static int eflag; +static int kflag; +static int bflag; + +static uint32_t occ, seltags, total_clients, urg; + +static char *output_name; +static int tagcount; +static char *tagset; +static char *layout_name; +static int layoutcount, layout_idx; +static char *client_tags; +static char *dispatch_cmd; +static char *dispatch_arg1; +static char *dispatch_arg2; +static char *dispatch_arg3; +static char *dispatch_arg4; +static char *dispatch_arg5; + +struct output { + char *output_name; + uint32_t name; +}; +static DYNARR_DEF(struct output) outputs; + +static struct wl_display *display; +static struct zdwl_ipc_manager_v2 *dwl_ipc_manager; + +// 为每个回调定义专用的空函数 +static void noop_geometry(void *data, struct wl_output *wl_output, int32_t x, + int32_t y, int32_t physical_width, + int32_t physical_height, int32_t subpixel, + const char *make, const char *model, + int32_t transform) {} + +static void noop_mode(void *data, struct wl_output *wl_output, uint32_t flags, + int32_t width, int32_t height, int32_t refresh) {} + +static void noop_done(void *data, struct wl_output *wl_output) {} + +static void noop_scale(void *data, struct wl_output *wl_output, + int32_t factor) {} + +static void noop_description(void *data, struct wl_output *wl_output, + const char *description) {} + +// 将 n 转换为 9 位二进制字符串,结果存入 buf(至少长度 10) +void bin_str_9bits(char *buf, unsigned int n) { + for (int i = 8; i >= 0; i--) { + *buf++ = ((n >> i) & 1) ? '1' : '0'; + } + *buf = '\0'; // 字符串结尾 +} + +static void dwl_ipc_tags(void *data, + struct zdwl_ipc_manager_v2 *dwl_ipc_manager, + uint32_t count) { + tagcount = count; + if (Tflag && mode & GET) + printf("%d\n", tagcount); +} + +static void dwl_ipc_layout(void *data, + struct zdwl_ipc_manager_v2 *dwl_ipc_manager, + const char *name) { + if (lflag && mode & SET && strcmp(layout_name, name) == 0) + layout_idx = layoutcount; + if (Lflag && mode & GET) + printf("%s\n", name); + layoutcount++; +} + +static const struct zdwl_ipc_manager_v2_listener dwl_ipc_listener = { + .tags = dwl_ipc_tags, .layout = dwl_ipc_layout}; + +static void +dwl_ipc_output_toggle_visibility(void *data, + struct zdwl_ipc_output_v2 *dwl_ipc_output) { + if (!vflag) + return; + char *output_name = data; + if (output_name) + printf("%s ", output_name); + printf("toggle\n"); +} + +static void dwl_ipc_output_active(void *data, + struct zdwl_ipc_output_v2 *dwl_ipc_output, + uint32_t active) { + if (!oflag) { + if (mode & SET && !output_name && active) + output_name = strdup(data); + return; + } + char *output_name = data; + if (output_name) + printf("%s ", output_name); + printf("selmon %u\n", active ? 1 : 0); +} + +static void dwl_ipc_output_tag(void *data, + struct zdwl_ipc_output_v2 *dwl_ipc_output, + uint32_t tag, uint32_t state, uint32_t clients, + uint32_t focused) { + if (!tflag) + return; + if (state == ZDWL_IPC_OUTPUT_V2_TAG_STATE_ACTIVE) + seltags |= 1 << tag; + if (state == ZDWL_IPC_OUTPUT_V2_TAG_STATE_URGENT) + urg |= 1 << tag; + if (clients > 0) + occ |= 1 << tag; + + // 累计所有 tag 的 clients 总数 + total_clients += clients; + + if (!(mode & GET)) + return; + char *output_name = data; + if (output_name) + printf("%s ", output_name); + printf("tag %u %u %u %u\n", tag + 1, state, clients, focused); +} + +static void dwl_ipc_output_layout(void *data, + struct zdwl_ipc_output_v2 *dwl_ipc_output, + uint32_t layout) {} + +static void dwl_ipc_output_layout_symbol( + void *data, struct zdwl_ipc_output_v2 *dwl_ipc_output, const char *layout) { + if (!(lflag && mode & GET)) + return; + char *output_name = data; + if (output_name) + printf("%s ", output_name); + printf("layout %s\n", layout); +} + +static void dwl_ipc_output_title(void *data, + struct zdwl_ipc_output_v2 *dwl_ipc_output, + const char *title) { + if (!(cflag && mode & GET)) + return; + char *output_name = data; + if (output_name) + printf("%s ", output_name); + printf("title %s\n", title); +} + +static void dwl_ipc_output_appid(void *data, + struct zdwl_ipc_output_v2 *dwl_ipc_output, + const char *appid) { + if (!(cflag && mode & GET)) + return; + char *output_name = data; + if (output_name) + printf("%s ", output_name); + printf("appid %s\n", appid); +} + +static void dwl_ipc_output_x(void *data, + struct zdwl_ipc_output_v2 *dwl_ipc_output, + int32_t x) { + if (!xflag) + return; + char *output_name = data; + if (output_name) + printf("%s ", output_name); + printf("x %d\n", x); +} + +static void dwl_ipc_output_y(void *data, + struct zdwl_ipc_output_v2 *dwl_ipc_output, + int32_t y) { + if (!xflag) + return; + char *output_name = data; + if (output_name) + printf("%s ", output_name); + printf("y %d\n", y); +} + +static void dwl_ipc_output_width(void *data, + struct zdwl_ipc_output_v2 *dwl_ipc_output, + int32_t width) { + if (!xflag) + return; + char *output_name = data; + if (output_name) + printf("%s ", output_name); + printf("width %d\n", width); +} + +static void dwl_ipc_output_height(void *data, + struct zdwl_ipc_output_v2 *dwl_ipc_output, + int32_t height) { + if (!xflag) + return; + char *output_name = data; + if (output_name) + printf("%s ", output_name); + printf("height %d\n", height); +} + +static void dwl_ipc_output_last_layer(void *data, + struct zdwl_ipc_output_v2 *dwl_ipc_output, + const char *last_layer) { + if (!eflag) + return; + char *output_name = data; + if (output_name) + printf("%s ", output_name); + printf("last_layer %s\n", last_layer); +} + +static void dwl_ipc_output_kb_layout(void *data, + struct zdwl_ipc_output_v2 *dwl_ipc_output, + const char *kb_layout) { + if (!kflag) + return; + char *output_name = data; + if (output_name) + printf("%s ", output_name); + printf("kb_layout %s\n", kb_layout); +} + +static void dwl_ipc_output_keymode(void *data, + struct zdwl_ipc_output_v2 *dwl_ipc_output, + const char *keymode) { + if (!bflag) + return; + char *output_name = data; + if (output_name) + printf("%s ", output_name); + printf("keymode %s\n", keymode); +} + +static void dwl_ipc_output_fullscreen(void *data, + struct zdwl_ipc_output_v2 *dwl_ipc_output, + uint32_t is_fullscreen) { + if (!mflag) + return; + char *output_name = data; + if (output_name) + printf("%s ", output_name); + printf("fullscreen %u\n", is_fullscreen); +} + +static void dwl_ipc_output_floating(void *data, + struct zdwl_ipc_output_v2 *dwl_ipc_output, + uint32_t is_floating) { + if (!fflag) + return; + char *output_name = data; + if (output_name) + printf("%s ", output_name); + printf("floating %u\n", is_floating); +} + +static void dwl_ipc_output_frame(void *data, + struct zdwl_ipc_output_v2 *dwl_ipc_output) { + if (mode & SET) { + if (data && (!output_name || strcmp(output_name, (char *)data))) + return; + if (qflag) { + zdwl_ipc_output_v2_quit(dwl_ipc_output); + } + if (lflag) { + zdwl_ipc_output_v2_set_layout(dwl_ipc_output, layout_idx); + } + if (tflag) { + uint32_t mask = seltags; + char *t = tagset; + int i = 0; + + for (; *t && *t >= '0' && *t <= '9'; t++) + i = *t - '0' + i * 10; + + if (!*t) + mask = 1 << (i - 1); + + for (; *t; t++, i++) { + switch (*t) { + case '-': + mask &= ~(1 << (i - 1)); + break; + case '+': + mask |= 1 << (i - 1); + break; + case '^': + mask ^= 1 << (i - 1); + break; + } + } + + if ((i - 1) > tagcount) + die("bad tagset %s", tagset); + + zdwl_ipc_output_v2_set_tags(dwl_ipc_output, mask, 0); + } + if (cflag) { + uint32_t and = ~0, xor = 0; + char *t = client_tags; + int i = 0; + + for (; *t && *t >= '0' && *t <= '9'; t++) + i = *t - '0' + i * 10; + + if (!*t) + t = "+"; + + for (; *t; t++, i++) { + switch (*t) { + case '-': + and &= ~(1 << (i - 1)); + break; + case '+': + and &= ~(1 << (i - 1)); + xor |= 1 << (i - 1); + break; + case '^': + xor |= 1 << (i - 1); + break; + } + } + if ((i - 1) > tagcount) + die("bad client tagset %s", client_tags); + + zdwl_ipc_output_v2_set_client_tags(dwl_ipc_output, and, xor); + } + if (dflag) { + zdwl_ipc_output_v2_dispatch( + dwl_ipc_output, dispatch_cmd, dispatch_arg1, dispatch_arg2, + dispatch_arg3, dispatch_arg4, dispatch_arg5); + } + wl_display_flush(display); + exit(0); + } else { + if (tflag) { + char *output_name = data; + + printf("%s clients %u\n", output_name, total_clients); + + char occ_str[10], seltags_str[10], urg_str[10]; + + bin_str_9bits(occ_str, occ); + bin_str_9bits(seltags_str, seltags); + bin_str_9bits(urg_str, urg); + printf("%s tags %u %u %u\n", output_name, occ, seltags, urg); + printf("%s tags %s %s %s\n", output_name, occ_str, seltags_str, + urg_str); + occ = seltags = total_clients = urg = 0; + } + } + fflush(stdout); +} + +static const struct zdwl_ipc_output_v2_listener dwl_ipc_output_listener = { + .toggle_visibility = dwl_ipc_output_toggle_visibility, + .active = dwl_ipc_output_active, + .tag = dwl_ipc_output_tag, + .layout = dwl_ipc_output_layout, + .title = dwl_ipc_output_title, + .appid = dwl_ipc_output_appid, + .layout_symbol = dwl_ipc_output_layout_symbol, + .fullscreen = dwl_ipc_output_fullscreen, + .floating = dwl_ipc_output_floating, + .x = dwl_ipc_output_x, + .y = dwl_ipc_output_y, + .width = dwl_ipc_output_width, + .height = dwl_ipc_output_height, + .last_layer = dwl_ipc_output_last_layer, + .kb_layout = dwl_ipc_output_kb_layout, + .keymode = dwl_ipc_output_keymode, + .frame = dwl_ipc_output_frame, +}; + +static void wl_output_name(void *data, struct wl_output *output, + const char *name) { + if (outputs.arr) { + struct output *o = (struct output *)data; + o->output_name = strdup(name); + printf("+ "); + } + if (Oflag) + printf("%s\n", name); + if (output_name && strcmp(output_name, name) != 0) { + wl_output_release(output); + return; + } + struct zdwl_ipc_output_v2 *dwl_ipc_output = + zdwl_ipc_manager_v2_get_output(dwl_ipc_manager, output); + zdwl_ipc_output_v2_add_listener(dwl_ipc_output, &dwl_ipc_output_listener, + output_name ? NULL : strdup(name)); +} + +static const struct wl_output_listener output_listener = { + .geometry = noop_geometry, + .mode = noop_mode, + .done = noop_done, + .scale = noop_scale, + .name = wl_output_name, + .description = noop_description, +}; + +static void global_add(void *data, struct wl_registry *wl_registry, + uint32_t name, const char *interface, uint32_t version) { + if (strcmp(interface, wl_output_interface.name) == 0) { + struct wl_output *o = + wl_registry_bind(wl_registry, name, &wl_output_interface, + WL_OUTPUT_NAME_SINCE_VERSION); + if (!outputs.arr) { + wl_output_add_listener(o, &output_listener, NULL); + } else { + DYNARR_PUSH(&outputs, (struct output){.name = name}); + wl_output_add_listener(o, &output_listener, + &outputs.arr[outputs.len - 1]); + } + } else if (strcmp(interface, zdwl_ipc_manager_v2_interface.name) == 0) { + dwl_ipc_manager = wl_registry_bind(wl_registry, name, + &zdwl_ipc_manager_v2_interface, 2); + zdwl_ipc_manager_v2_add_listener(dwl_ipc_manager, &dwl_ipc_listener, + NULL); + } +} + +static void global_remove(void *data, struct wl_registry *wl_registry, + uint32_t name) { + if (!outputs.arr) + return; + struct output *o = outputs.arr; + for (size_t i = 0; i < outputs.len; i++, o++) { + if (o->name == name) { + printf("- %s\n", o->output_name); + free(o->output_name); + *o = DYNARR_POP(&outputs); + } + } +} + +static const struct wl_registry_listener registry_listener = { + .global = global_add, + .global_remove = global_remove, +}; + +static void usage(void) { + fprintf(stderr, + "usage:" + "\t%s [-OTLq]\n" + "\t%s [-o ] -s [-t ] [-l ] [-c ] [-d " + ",,,,,]\n" + "\t%s [-o ] (-g | -w) [-Ootlcvmfxekb]\n", + argv0, argv0, argv0); + exit(2); +} + +int main(int argc, char *argv[]) { + ARGBEGIN { + case 'q': + qflag = 1; + if (!(mode & GET)) { + mode = SET; + } + break; + case 's': + if (mode != NONE) + usage(); + mode = SET; + break; + case 'g': + if (mode != NONE) + usage(); + mode = GET; + break; + case 'w': + if (mode != NONE) + usage(); + mode = WATCH; + break; + case 'o': + if (mode == SET) + output_name = EARGF(usage()); + else + output_name = ARGF(); + if (!output_name) + oflag = 1; + break; + case 't': + tflag = 1; + if (!(mode & GET)) { + mode = SET; + tagset = EARGF(usage()); + } + break; + case 'l': + lflag = 1; + if (!(mode & GET)) { + mode = SET; + layout_name = EARGF(usage()); + } + break; + case 'c': + cflag = 1; + if (!(mode & GET)) { + mode = SET; + client_tags = EARGF(usage()); + } + break; + case 'd': + dflag = 1; + if (!(mode & GET)) { + mode = SET; + char *arg = EARGF(usage()); + + // Trim leading and trailing whitespace from entire argument first + while (isspace(*arg)) + arg++; + char *end = arg + strlen(arg) - 1; + while (end > arg && isspace(*end)) + end--; + *(end + 1) = '\0'; + + dispatch_cmd = arg; + char *comma1 = strchr(arg, ','); + if (comma1) { + *comma1 = '\0'; + + // Trim trailing whitespace from command + end = dispatch_cmd + strlen(dispatch_cmd) - 1; + while (end > dispatch_cmd && isspace(*end)) + end--; + *(end + 1) = '\0'; + + dispatch_arg1 = comma1 + 1; + // Trim leading whitespace from arg1 + while (isspace(*dispatch_arg1)) + dispatch_arg1++; + + // Trim trailing whitespace from arg1 before looking for next + // comma + end = dispatch_arg1 + strlen(dispatch_arg1) - 1; + while (end > dispatch_arg1 && isspace(*end)) + end--; + *(end + 1) = '\0'; + + char *comma2 = strchr(dispatch_arg1, ','); + if (comma2) { + *comma2 = '\0'; + dispatch_arg2 = comma2 + 1; + // Trim leading whitespace from arg2 + while (isspace(*dispatch_arg2)) + dispatch_arg2++; + + // Trim trailing whitespace from arg2 before looking for + // next comma + end = dispatch_arg2 + strlen(dispatch_arg2) - 1; + while (end > dispatch_arg2 && isspace(*end)) + end--; + *(end + 1) = '\0'; + + char *comma3 = strchr(dispatch_arg2, ','); + if (comma3) { + *comma3 = '\0'; + dispatch_arg3 = comma3 + 1; + // Trim leading whitespace from arg3 + while (isspace(*dispatch_arg3)) + dispatch_arg3++; + + // Trim trailing whitespace from arg3 before looking for + // next comma + end = dispatch_arg3 + strlen(dispatch_arg3) - 1; + while (end > dispatch_arg3 && isspace(*end)) + end--; + *(end + 1) = '\0'; + + char *comma4 = strchr(dispatch_arg3, ','); + if (comma4) { + *comma4 = '\0'; + dispatch_arg4 = comma4 + 1; + // Trim leading whitespace from arg4 + while (isspace(*dispatch_arg4)) + dispatch_arg4++; + + // Trim trailing whitespace from arg4 before looking + // for next comma + end = dispatch_arg4 + strlen(dispatch_arg4) - 1; + while (end > dispatch_arg4 && isspace(*end)) + end--; + *(end + 1) = '\0'; + + char *comma5 = strchr(dispatch_arg4, ','); + if (comma5) { + *comma5 = '\0'; + dispatch_arg5 = comma5 + 1; + // Trim leading whitespace from arg5 + while (isspace(*dispatch_arg5)) + dispatch_arg5++; + + // Trim trailing whitespace from arg5 + end = dispatch_arg5 + strlen(dispatch_arg5) - 1; + while (end > dispatch_arg5 && isspace(*end)) + end--; + *(end + 1) = '\0'; + } else { + dispatch_arg5 = ""; + } + } else { + dispatch_arg4 = ""; + dispatch_arg5 = ""; + } + } else { + dispatch_arg3 = ""; + dispatch_arg4 = ""; + dispatch_arg5 = ""; + } + } else { + dispatch_arg2 = ""; + dispatch_arg3 = ""; + dispatch_arg4 = ""; + dispatch_arg5 = ""; + } + } else { + dispatch_arg1 = ""; + dispatch_arg2 = ""; + dispatch_arg3 = ""; + dispatch_arg4 = ""; + dispatch_arg5 = ""; + } + } + break; + case 'O': + Oflag = 1; + if (mode && !(mode & GET)) + usage(); + if (mode & WATCH) + DYNARR_INIT(&outputs); + else + mode = GET; + break; + case 'T': + Tflag = 1; + if (mode && mode != GET) + usage(); + mode = GET; + break; + case 'L': + Lflag = 1; + if (mode && mode != GET) + usage(); + mode = GET; + break; + case 'v': + vflag = 1; + if (mode == SET) + usage(); + mode |= GET; + break; + case 'm': + mflag = 1; + if (mode == SET) + usage(); + mode |= GET; + break; + case 'f': + fflag = 1; + if (mode == SET) + usage(); + mode |= GET; + break; + case 'x': + xflag = 1; + if (mode == SET) + usage(); + mode |= GET; + break; + case 'e': + eflag = 1; + if (mode == SET) + usage(); + mode |= GET; + break; + case 'k': + kflag = 1; + if (mode == SET) + usage(); + mode |= GET; + break; + case 'b': + bflag = 1; + if (mode == SET) + usage(); + mode |= GET; + break; + default: + fprintf(stderr, "bad option %c\n", ARGC()); + usage(); + } + ARGEND + if (mode == NONE) + usage(); + if (mode & GET && !output_name && + !(oflag || tflag || lflag || Oflag || Tflag || Lflag || cflag || + vflag || mflag || fflag || xflag || eflag || kflag || bflag || dflag)) + oflag = tflag = lflag = cflag = vflag = mflag = fflag = xflag = eflag = + kflag = bflag = 1; + + display = wl_display_connect(NULL); + if (!display) + die("bad display"); + + struct wl_registry *registry = wl_display_get_registry(display); + wl_registry_add_listener(registry, ®istry_listener, NULL); + + wl_display_dispatch(display); + wl_display_roundtrip(display); + + if (!dwl_ipc_manager) + die("bad dwl-ipc protocol"); + + wl_display_roundtrip(display); + + if (mode == WATCH) + while (wl_display_dispatch(display) != -1) + ; + + return 0; +} From 80efd31e217b5dbc2974dd125b27bdb9a08ead73 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sat, 18 Oct 2025 13:03:00 +0800 Subject: [PATCH 238/591] opt: fix build warnning --- src/layout/arrange.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/layout/arrange.h b/src/layout/arrange.h index d96c9284..1fc5552d 100644 --- a/src/layout/arrange.h +++ b/src/layout/arrange.h @@ -505,7 +505,7 @@ void reset_size_per_mon(Monitor *m, int tile_cilent_num, int stack_num) { Client *c = NULL; int i = 0; - unsigned int stack_index; + unsigned int stack_index = 0; unsigned int nmasters = m->pertag->nmasters[m->pertag->curtag]; if (m->pertag->ltidxs[m->pertag->curtag]->id != CENTER_TILE) { From 02d65c33e44666df9124854314266c98e63bfa09 Mon Sep 17 00:00:00 2001 From: ProggerX Date: Sat, 18 Oct 2025 09:46:18 +0300 Subject: [PATCH 239/591] nix: merge mmsg to mangowc project --- flake.lock | 55 ------------------------------------------- flake.nix | 7 ------ nix/default.nix | 4 +--- nix/nixos-modules.nix | 7 +----- 4 files changed, 2 insertions(+), 71 deletions(-) diff --git a/flake.lock b/flake.lock index 28a8ac61..2917a6fd 100644 --- a/flake.lock +++ b/flake.lock @@ -18,45 +18,6 @@ "type": "github" } }, - "flake-parts_2": { - "inputs": { - "nixpkgs-lib": "nixpkgs-lib_2" - }, - "locked": { - "lastModified": 1741352980, - "narHash": "sha256-+u2UunDA4Cl5Fci3m7S643HzKmIDAe+fiXrLqYsR2fs=", - "owner": "hercules-ci", - "repo": "flake-parts", - "rev": "f4330d22f1c5d2ba72d3d22df5597d123fdb60a9", - "type": "github" - }, - "original": { - "owner": "hercules-ci", - "repo": "flake-parts", - "type": "github" - } - }, - "mmsg": { - "inputs": { - "flake-parts": "flake-parts_2", - "nixpkgs": [ - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1758702011, - "narHash": "sha256-bUDn7H0Kt0Z4pjgki8B6jP1HMAklN0Fh+7zwW3JTw4I=", - "owner": "DreamMaoMao", - "repo": "mmsg", - "rev": "55b64e3728c3a95673ff73ccd9c3865db86f4fec", - "type": "github" - }, - "original": { - "owner": "DreamMaoMao", - "repo": "mmsg", - "type": "github" - } - }, "nixpkgs": { "locked": { "lastModified": 1750386251, @@ -88,25 +49,9 @@ "type": "github" } }, - "nixpkgs-lib_2": { - "locked": { - "lastModified": 1740877520, - "narHash": "sha256-oiwv/ZK/2FhGxrCkQkB83i7GnWXPPLzoqFHpDD3uYpk=", - "owner": "nix-community", - "repo": "nixpkgs.lib", - "rev": "147dee35aab2193b174e4c0868bd80ead5ce755c", - "type": "github" - }, - "original": { - "owner": "nix-community", - "repo": "nixpkgs.lib", - "type": "github" - } - }, "root": { "inputs": { "flake-parts": "flake-parts", - "mmsg": "mmsg", "nixpkgs": "nixpkgs", "scenefx": "scenefx" } diff --git a/flake.nix b/flake.nix index a3bd8e6d..ff88ba0c 100644 --- a/flake.nix +++ b/flake.nix @@ -2,10 +2,6 @@ inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; flake-parts.url = "github:hercules-ci/flake-parts"; - mmsg = { - url = "github:DreamMaoMao/mmsg"; - inputs.nixpkgs.follows = "nixpkgs"; - }; scenefx = { url = "github:wlrfx/scenefx"; inputs.nixpkgs.follows = "nixpkgs"; @@ -33,9 +29,7 @@ ... }: let inherit (pkgs) callPackage ; - inherit (inputs.mmsg.packages.${pkgs.system}) mmsg; mango = callPackage ./nix { - inherit mmsg; inherit (inputs.scenefx.packages.${pkgs.system}) scenefx; }; shellOverride = old: { @@ -49,7 +43,6 @@ }; packages = { inherit mango; - inherit mmsg; }; devShells.default = mango.overrideAttrs shellOverride; formatter = pkgs.alejandra; diff --git a/nix/default.nix b/nix/default.nix index 37bff529..b72977d3 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -16,7 +16,6 @@ enableXWayland ? true, meson, ninja, - mmsg, scenefx, wlroots_0_19, libGL, @@ -60,7 +59,6 @@ in passthru = { providedSessions = ["mango"]; - inherit mmsg; }; meta = { @@ -71,4 +69,4 @@ in maintainers = []; platforms = lib.platforms.unix; }; - } \ No newline at end of file + } diff --git a/nix/nixos-modules.nix b/nix/nixos-modules.nix index 0cae15c4..9e73d6af 100644 --- a/nix/nixos-modules.nix +++ b/nix/nixos-modules.nix @@ -21,12 +21,7 @@ in { environment.systemPackages = [ cfg.package - ] - ++ ( - if (builtins.hasAttr "mmsg" cfg.package) - then [cfg.package.mmsg] - else [] - ); + ]; xdg.portal = { enable = lib.mkDefault true; From 17009f536448c0452ee6a78ff2f9883dc877c74d Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sat, 18 Oct 2025 20:39:31 +0800 Subject: [PATCH 240/591] fix: should set global client tag before caculate number of client in arrange --- src/animation/client.h | 2 +- src/layout/arrange.h | 13 +++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/animation/client.h b/src/animation/client.h index b77dd592..b7e3789b 100644 --- a/src/animation/client.h +++ b/src/animation/client.h @@ -1030,7 +1030,7 @@ void resize(Client *c, struct wlr_box geo, int interact) { c->animainit_geom = c->geom; } - if (c->scratchpad_switching_mon) { + if (c->scratchpad_switching_mon && c->isfloating) { c->animainit_geom = c->geom; } diff --git a/src/layout/arrange.h b/src/layout/arrange.h index 1fc5552d..404df45b 100644 --- a/src/layout/arrange.h +++ b/src/layout/arrange.h @@ -597,6 +597,13 @@ arrange(Monitor *m, bool want_animation) { m->visible_tiling_clients = 0; wl_list_for_each(c, &clients, link) { + + if (c->mon == m && (c->isglobal || c->isunglobal)) { + c->tags = m->tagset[m->seltags]; + if (c->mon->sel == NULL) + focusclient(c, 0); + } + if (VISIBLEON(c, m)) { m->visible_clients++; if (ISTILED(c)) { @@ -611,12 +618,6 @@ arrange(Monitor *m, bool want_animation) { if (c->iskilling) continue; - if (c->mon == m && (c->isglobal || c->isunglobal)) { - c->tags = m->tagset[m->seltags]; - if (c->mon->sel == NULL) - focusclient(c, 0); - } - if (c->mon == m) { if (VISIBLEON(c, m)) { if (ISTILED(c)) { From 5ed681cbe5f132db7e17cc478889f620bc192ead Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sun, 19 Oct 2025 09:54:17 +0800 Subject: [PATCH 241/591] opt: reduce times of resize request when drag window to resize --- src/config/preset.h | 1 + src/layout/arrange.h | 9 +++------ 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/config/preset.h b/src/config/preset.h index a6bde57e..31956cf9 100644 --- a/src/config/preset.h +++ b/src/config/preset.h @@ -100,6 +100,7 @@ int warpcursor = 1; /* Warp cursor to focused client */ int xwayland_persistence = 1; /* xwayland persistence */ int syncobj_enable = 0; int adaptive_sync = 0; +double drag_refresh_interval = 30.0; /* keyboard */ diff --git a/src/layout/arrange.h b/src/layout/arrange.h index 404df45b..0a4eca2b 100644 --- a/src/layout/arrange.h +++ b/src/layout/arrange.h @@ -26,7 +26,6 @@ void resize_tile_master_horizontal(Client *grabc, bool isdrag, int offsetx, Client *prev = NULL; Client *nextnext = NULL; Client *prevprev = NULL; - double refresh_interval = 1000000.0 / grabc->mon->wlr_output->refresh; struct wl_list *node; bool begin_find_nextnext = false; bool begin_find_prevprev = false; @@ -206,7 +205,7 @@ void resize_tile_master_horizontal(Client *grabc, bool isdrag, int offsetx, } if (last_apply_drap_time == 0 || - time - last_apply_drap_time > refresh_interval) { + time - last_apply_drap_time > drag_refresh_interval) { arrange(grabc->mon, false); last_apply_drap_time = time; } @@ -219,7 +218,6 @@ void resize_tile_master_vertical(Client *grabc, bool isdrag, int offsetx, float delta_x, delta_y; Client *next = NULL; Client *prev = NULL; - double refresh_interval = 1000000.0 / grabc->mon->wlr_output->refresh; struct wl_list *node; // 从当前节点的下一个开始遍历 @@ -364,7 +362,7 @@ void resize_tile_master_vertical(Client *grabc, bool isdrag, int offsetx, } if (last_apply_drap_time == 0 || - time - last_apply_drap_time > refresh_interval) { + time - last_apply_drap_time > drag_refresh_interval) { arrange(grabc->mon, false); last_apply_drap_time = time; } @@ -375,7 +373,6 @@ void resize_tile_scroller(Client *grabc, bool isdrag, int offsetx, int offsety, unsigned int time, bool isvertical) { float delta_x, delta_y; float new_scroller_proportion; - double refresh_interval = 1000000.0 / grabc->mon->wlr_output->refresh; if (!start_drag_window && isdrag) { drag_begin_cursorx = cursor->x; @@ -465,7 +462,7 @@ void resize_tile_scroller(Client *grabc, bool isdrag, int offsetx, int offsety, } if (last_apply_drap_time == 0 || - time - last_apply_drap_time > refresh_interval) { + time - last_apply_drap_time > drag_refresh_interval) { arrange(grabc->mon, false); last_apply_drap_time = time; } From 346b39c580719c11cd8ab71439e08831cb76ca4d Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sun, 19 Oct 2025 11:03:27 +0800 Subject: [PATCH 242/591] bump version to 0.10.1 --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 2ab74a10..0d2853a1 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('mango', ['c', 'cpp'], - version : '0.10.0', + version : '0.10.1', ) subdir('protocols') From a707feeb117af826a3afd130783ff2778e47c8ad Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sun, 19 Oct 2025 14:32:33 +0800 Subject: [PATCH 243/591] opt: remove useless keyboard code --- src/config/parse_config.h | 11 ++++--- src/mango.c | 64 +++++++++++---------------------------- 2 files changed, 25 insertions(+), 50 deletions(-) diff --git a/src/config/parse_config.h b/src/config/parse_config.h index ddd5fa7b..d6260c9d 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -2949,10 +2949,13 @@ void reapply_border(void) { } void reapply_keyboard(void) { - Keyboard *kb; - wl_list_for_each(kb, &keyboards, link) { - wlr_keyboard_set_repeat_info(kb->wlr_keyboard, repeat_rate, - repeat_delay); + InputDevice *id; + wl_list_for_each(id, &inputdevices, link) { + if (id->wlr_device->type != WLR_INPUT_DEVICE_KEYBOARD) { + continue; + } + wlr_keyboard_set_repeat_info((struct wlr_keyboard *)id->device_data, + repeat_rate, repeat_delay); } } diff --git a/src/mango.c b/src/mango.c index d44c8c90..218e5024 100644 --- a/src/mango.c +++ b/src/mango.c @@ -375,20 +375,6 @@ typedef struct { struct wl_listener destroy; } KeyboardGroup; -typedef struct { - struct wl_list link; - struct wlr_keyboard *wlr_keyboard; - - int nsyms; - const xkb_keysym_t *keysyms; /* invalid if nsyms == 0 */ - unsigned int mods; /* invalid if nsyms == 0 */ - struct wl_event_source *key_repeat_source; - - struct wl_listener modifiers; - struct wl_listener key; - struct wl_listener destroy; -} Keyboard; - typedef struct { /* Must keep these three elements in this order */ unsigned int type; /* LayerShell */ @@ -466,21 +452,6 @@ typedef struct { struct wl_listener destroy; } PointerConstraint; -typedef struct { - const char *id; - const char *title; - unsigned int tags; - int isfloating; - int isfullscreen; - float scroller_proportion; - const char *animation_type_open; - const char *animation_type_close; - int isnoborder; - int monitor; - unsigned int width; - unsigned int height; -} Rule; - typedef struct { struct wlr_scene_tree *scene; @@ -516,9 +487,7 @@ static void pinch_end(struct wl_listener *listener, void *data); static void hold_begin(struct wl_listener *listener, void *data); static void hold_end(struct wl_listener *listener, void *data); static void checkidleinhibitor(struct wlr_surface *exclude); -static void cleanup(void); // 退出清理 -static void cleanupkeyboard(struct wl_listener *listener, - void *data); // 退出清理 +static void cleanup(void); // 退出清理 static void cleanupmon(struct wl_listener *listener, void *data); // 退出清理 static void closemon(Monitor *m); static void cleanuplisteners(void); @@ -776,7 +745,6 @@ static struct wlr_pointer_constraint_v1 *active_constraint; static struct wlr_seat *seat; static KeyboardGroup *kb_group; -static struct wl_list keyboards; static struct wl_list inputdevices; static unsigned int cursor_mode; static Client *grabc; @@ -2000,18 +1968,6 @@ void cleanup(void) { wlr_scene_node_destroy(&scene->tree.node); } -void // 17 -cleanupkeyboard(struct wl_listener *listener, void *data) { - Keyboard *kb = wl_container_of(listener, kb, destroy); - - wl_event_source_remove(kb->key_repeat_source); - wl_list_remove(&kb->link); - wl_list_remove(&kb->modifiers.link); - wl_list_remove(&kb->key.link); - wl_list_remove(&kb->destroy.link); - free(kb); -} - void cleanupmon(struct wl_listener *listener, void *data) { Monitor *m = wl_container_of(listener, m, destroy); LayerSurface *l = NULL, *tmp = NULL; @@ -2375,6 +2331,23 @@ void createidleinhibitor(struct wl_listener *listener, void *data) { void createkeyboard(struct wlr_keyboard *keyboard) { + struct libinput_device *device = NULL; + + if (wlr_input_device_is_libinput(&keyboard->base) && + (device = wlr_libinput_get_device_handle(&keyboard->base))) { + + InputDevice *input_dev = calloc(1, sizeof(InputDevice)); + input_dev->wlr_device = &keyboard->base; + input_dev->libinput_device = device; + input_dev->device_data = keyboard; + + input_dev->destroy_listener.notify = destroyinputdevice; + wl_signal_add(&keyboard->base.events.destroy, + &input_dev->destroy_listener); + + wl_list_insert(&inputdevices, &input_dev->link); + } + /* Set the keymap to match the group keymap */ wlr_keyboard_set_keymap(keyboard, kb_group->wlr_group->keyboard.keymap); @@ -4947,7 +4920,6 @@ void setup(void) { * pointer, touch, and drawing tablet device. We also rig up a listener * to let us know when new input devices are available on the backend. */ - wl_list_init(&keyboards); wl_list_init(&inputdevices); wl_signal_add(&backend->events.new_input, &new_input_device); virtual_keyboard_mgr = wlr_virtual_keyboard_manager_v1_create(dpy); From 59d86e71692a62c365446025c0b20a1589e242ea Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sun, 19 Oct 2025 18:09:34 +0800 Subject: [PATCH 244/591] project: merge mmsg meson.build file into mango meson.build --- format.sh | 2 +- meson.build | 34 +++- mmsg/{src => }/arg.h | 0 mmsg/{src => }/dynarr.h | 0 mmsg/meson.build | 33 ---- mmsg/{src => }/mmsg.c | 0 mmsg/protocols/dwl-ipc-unstable-v2.xml | 246 ------------------------- 7 files changed, 32 insertions(+), 283 deletions(-) rename mmsg/{src => }/arg.h (100%) rename mmsg/{src => }/dynarr.h (100%) delete mode 100644 mmsg/meson.build rename mmsg/{src => }/mmsg.c (100%) delete mode 100644 mmsg/protocols/dwl-ipc-unstable-v2.xml diff --git a/format.sh b/format.sh index af4a82aa..1291ff8f 100644 --- a/format.sh +++ b/format.sh @@ -1,3 +1,3 @@ #!/usr/bin/bash -clang-format -i src/*/*.h -i src/*/*.c -i src/mango.c -i mmsg/src/mmsg.c -i mmsg/src/arg.h -i mmsg/src/dynarr.h +clang-format -i src/*/*.h -i src/*/*.c -i src/mango.c -i mmsg/mmsg.c -i mmsg/arg.h -i mmsg/dynarr.h diff --git a/meson.build b/meson.build index 0d2853a1..12048724 100644 --- a/meson.build +++ b/meson.build @@ -3,7 +3,6 @@ project('mango', ['c', 'cpp'], ) subdir('protocols') -subdir('mmsg') is_nixos = false os_release = run_command('cat', '/etc/os-release', check: false) @@ -117,8 +116,37 @@ executable('mango', link_args : link_args, ) +# build mmsg +dwl_ipc_protocol = 'protocols/dwl-ipc-unstable-v2.xml' +dwl_ipc_header = custom_target( + 'dwl-ipc-header', + input: dwl_ipc_protocol, + output: 'dwl-ipc-unstable-v2-protocol.h', + command: [wayland_scanner, 'client-header', '@INPUT@', '@OUTPUT@'], + build_by_default: true, +) +dwl_ipc_source = custom_target( + 'dwl-ipc-source', + input: dwl_ipc_protocol, + output: 'dwl-ipc-unstable-v2-protocol.c', + command: [wayland_scanner, 'private-code', '@INPUT@', '@OUTPUT@'], + build_by_default: true, +) + +executable('mmsg', + 'mmsg/mmsg.c', + dwl_ipc_source, + dependencies: [ + libwayland_client_dep + ], + install: true, + c_args: [ + '-g', + '-Wno-unused-function', + ], +) + + desktop_install_dir = join_paths(prefix, 'share/wayland-sessions') install_data('mango.desktop', install_dir : desktop_install_dir) - -# 安装 config.conf install_data('config.conf', install_dir : join_paths(sysconfdir, 'mango')) diff --git a/mmsg/src/arg.h b/mmsg/arg.h similarity index 100% rename from mmsg/src/arg.h rename to mmsg/arg.h diff --git a/mmsg/src/dynarr.h b/mmsg/dynarr.h similarity index 100% rename from mmsg/src/dynarr.h rename to mmsg/dynarr.h diff --git a/mmsg/meson.build b/mmsg/meson.build deleted file mode 100644 index 6d0b1e81..00000000 --- a/mmsg/meson.build +++ /dev/null @@ -1,33 +0,0 @@ -wayland_scanner = find_program('wayland-scanner') - -dwl_ipc_protocol = 'protocols/dwl-ipc-unstable-v2.xml' - -dwl_ipc_header = custom_target( - 'dwl-ipc-header', - input: dwl_ipc_protocol, - output: 'dwl-ipc-unstable-v2-protocol.h', - command: [wayland_scanner, 'client-header', '@INPUT@', '@OUTPUT@'], - build_by_default: true, -) - -dwl_ipc_source = custom_target( - 'dwl-ipc-source', - input: dwl_ipc_protocol, - output: 'dwl-ipc-unstable-v2-protocol.c', - command: [wayland_scanner, 'private-code', '@INPUT@', '@OUTPUT@'], - build_by_default: true, -) - -executable('mmsg', - 'src/mmsg.c', - dwl_ipc_source, - dependencies: [ - dependency('wayland-client'), - ], - include_directories: include_directories('.'), - install: true, - c_args: [ - '-g', - '-Wno-unused-function', - ], -) \ No newline at end of file diff --git a/mmsg/src/mmsg.c b/mmsg/mmsg.c similarity index 100% rename from mmsg/src/mmsg.c rename to mmsg/mmsg.c diff --git a/mmsg/protocols/dwl-ipc-unstable-v2.xml b/mmsg/protocols/dwl-ipc-unstable-v2.xml deleted file mode 100644 index a43a7f06..00000000 --- a/mmsg/protocols/dwl-ipc-unstable-v2.xml +++ /dev/null @@ -1,246 +0,0 @@ - - - - - This protocol allows clients to update and get updates from dwl. - - Warning! The protocol described in this file is experimental and - backward incompatible changes may be made. Backward compatible - changes may be added together with the corresponding interface - version bump. - Backward incompatible changes are done by bumping the version - number in the protocol and interface names and resetting the - interface version. Once the protocol is to be declared stable, - the 'z' prefix and the version number in the protocol and - interface names are removed and the interface version number is - reset. - - - - - This interface is exposed as a global in wl_registry. - - Clients can use this interface to get a dwl_ipc_output. - After binding the client will recieve the dwl_ipc_manager.tags and dwl_ipc_manager.layout events. - The dwl_ipc_manager.tags and dwl_ipc_manager.layout events expose tags and layouts to the client. - - - - - Indicates that the client will not the dwl_ipc_manager object anymore. - Objects created through this instance are not affected. - - - - - - Get a dwl_ipc_outout for the specified wl_output. - - - - - - - - This event is sent after binding. - A roundtrip after binding guarantees the client recieved all tags. - - - - - - - This event is sent after binding. - A roundtrip after binding guarantees the client recieved all layouts. - - - - - - - - Observe and control a dwl output. - - Events are double-buffered: - Clients should cache events and redraw when a dwl_ipc_output.frame event is sent. - - Request are not double-buffered: - The compositor will update immediately upon request. - - - - - - - - - - - Indicates to that the client no longer needs this dwl_ipc_output. - - - - - - Indicates the client should hide or show themselves. - If the client is visible then hide, if hidden then show. - - - - - - Indicates if the output is active. Zero is invalid, nonzero is valid. - - - - - - - Indicates that a tag has been updated. - - - - - - - - - - Indicates a new layout is selected. - - - - - - - Indicates the title has changed. - - - - - - - Indicates the appid has changed. - - - - - - - Indicates the layout has changed. Since layout symbols are dynamic. - As opposed to the zdwl_ipc_manager.layout event, this should take precendence when displaying. - You can ignore the zdwl_ipc_output.layout event. - - - - - - - Indicates that a sequence of status updates have finished and the client should redraw. - - - - - - - - - - - - The tags are updated as follows: - new_tags = (current_tags AND and_tags) XOR xor_tags - - - - - - - - - - - - This request allows clients to instruct the compositor to quit mango. - - - - - - - - - - - - - - - - Indicates if the selected client on this output is fullscreen. - - - - - - - Indicates if the selected client on this output is floating. - - - - - - - Indicates if x coordinates of the selected client. - - - - - - - Indicates if y coordinates of the selected client. - - - - - - - Indicates if width of the selected client. - - - - - - - Indicates if height of the selected client. - - - - - - - last map layer. - - - - - - - current keyboard layout. - - - - - - - current keybind mode. - - - - - - - From 9ad13ca2224ed44f19ed6fc9ed8262dad7220809 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sun, 19 Oct 2025 19:04:25 +0800 Subject: [PATCH 245/591] project: optimize mmsg build action --- meson.build | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/meson.build b/meson.build index 12048724..ca9f4ab4 100644 --- a/meson.build +++ b/meson.build @@ -118,24 +118,24 @@ executable('mango', # build mmsg dwl_ipc_protocol = 'protocols/dwl-ipc-unstable-v2.xml' -dwl_ipc_header = custom_target( - 'dwl-ipc-header', - input: dwl_ipc_protocol, - output: 'dwl-ipc-unstable-v2-protocol.h', - command: [wayland_scanner, 'client-header', '@INPUT@', '@OUTPUT@'], - build_by_default: true, -) -dwl_ipc_source = custom_target( - 'dwl-ipc-source', - input: dwl_ipc_protocol, - output: 'dwl-ipc-unstable-v2-protocol.c', - command: [wayland_scanner, 'private-code', '@INPUT@', '@OUTPUT@'], - build_by_default: true, + +wayland_scanner_client_header = generator( + wayland_scanner, + output: '@BASENAME@-protocol.h', + arguments: ['client-header', '@INPUT@', '@OUTPUT@'] ) +wayland_scanner_private_code = generator( + wayland_scanner, + output: '@BASENAME@-protocol.c', + arguments: ['private-code', '@INPUT@', '@OUTPUT@'] +) + +# 在 mmsg 目标中使用生成器 executable('mmsg', 'mmsg/mmsg.c', - dwl_ipc_source, + wayland_scanner_private_code.process(dwl_ipc_protocol), + wayland_scanner_client_header.process(dwl_ipc_protocol), dependencies: [ libwayland_client_dep ], @@ -146,7 +146,6 @@ executable('mmsg', ], ) - desktop_install_dir = join_paths(prefix, 'share/wayland-sessions') install_data('mango.desktop', install_dir : desktop_install_dir) install_data('config.conf', install_dir : join_paths(sysconfdir, 'mango')) From b1a49f871064da6d96dbf0b68f3dc94d22d4924b Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sun, 19 Oct 2025 19:44:42 +0800 Subject: [PATCH 246/591] bump version to 0.10.2 --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index ca9f4ab4..de992266 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('mango', ['c', 'cpp'], - version : '0.10.1', + version : '0.10.2', ) subdir('protocols') From 3ec1a0198b76ce438ee98bc6cb7bf1f76584b6c6 Mon Sep 17 00:00:00 2001 From: werapi Date: Sun, 19 Oct 2025 17:00:43 +0200 Subject: [PATCH 247/591] opt: make focusmon and tagmon respect warpcursor setting --- src/dispatch/bind_define.h | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index eceec3ab..d42e772b 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -190,7 +190,9 @@ int focusmon(const Arg *arg) { old_selmon_sel = selmon->sel; selmon = m; - warp_cursor_to_selmon(selmon); + if (warpcursor) { + warp_cursor_to_selmon(selmon); + } c = focustop(selmon); if (!c) { selmon->sel = NULL; @@ -1071,7 +1073,9 @@ int tagmon(const Arg *arg) { focusclient(c, 1); arrange(selmon, false); } - warp_cursor_to_selmon(c->mon); + if (warpcursor) { + warp_cursor_to_selmon(c->mon); + } return 0; } @@ -1528,4 +1532,4 @@ int toggleoverview(const Arg *arg) { refresh_monitors_workspaces_status(selmon); return 0; -} \ No newline at end of file +} From 75475e294dbd3b3e83d7bada4c6dcc54e0c9ae71 Mon Sep 17 00:00:00 2001 From: Cheetah Date: Mon, 20 Oct 2025 11:20:15 +0200 Subject: [PATCH 248/591] Update Installation on Arch Linux section in README.md Added better installation instructions for arch --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b2626176..10c35ccf 100644 --- a/README.md +++ b/README.md @@ -70,7 +70,7 @@ https://github.com/user-attachments/assets/014c893f-115c-4ae9-8342-f9ae3e9a0df0 - pcre2 ## Arch Linux - +The package is in the Arch User Repository and is availble for manual download [here](https://aur.archlinux.org/packages/mangowc-git) or through a AUR helper like yay: ```bash yay -S mangowc-git From d40d4a2ea6c827cb03405feeb54e3c8931901a99 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Mon, 20 Oct 2025 12:14:58 +0800 Subject: [PATCH 249/591] opt: reset master per when setmfact toggle --- src/dispatch/bind_define.h | 8 +++++++- src/layout/arrange.h | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index d42e772b..93de6d7f 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -295,6 +295,7 @@ int increase_proportion(const Arg *arg) { int setmfact(const Arg *arg) { float f; + Client *c = NULL; if (!arg || !selmon || !selmon->pertag->ltidxs[selmon->pertag->curtag]->arrange) @@ -303,8 +304,13 @@ int setmfact(const Arg *arg) { : arg->f - 1.0; if (f < 0.1 || f > 0.9) return 0; - // selmon->mfact = f; + selmon->pertag->mfacts[selmon->pertag->curtag] = f; + wl_list_for_each(c, &clients, link) { + if (VISIBLEON(c, selmon) && ISTILED(c)) { + c->master_mfact_per = f; + } + } arrange(selmon, false); return 0; } diff --git a/src/layout/arrange.h b/src/layout/arrange.h index 0a4eca2b..18d6b15e 100644 --- a/src/layout/arrange.h +++ b/src/layout/arrange.h @@ -12,7 +12,7 @@ void set_size_per(Monitor *m, Client *c) { } if (!found) { - c->master_mfact_per = default_mfact; + c->master_mfact_per = m->pertag->mfacts[m->pertag->curtag]; c->master_inner_per = 1.0f; c->stack_innder_per = 1.0f; } From cc2bd9d599989d92d1e3267d93e8243435e0fb16 Mon Sep 17 00:00:00 2001 From: David Delarosa Date: Mon, 20 Oct 2025 13:50:43 +0300 Subject: [PATCH 250/591] opt: limit scanf string length to 255 --- src/config/parse_config.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/config/parse_config.h b/src/config/parse_config.h index d6260c9d..8e509cc2 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -1812,7 +1812,7 @@ void parse_option(Config *config, char *key, char *value) { arg_value[256] = "0\0", arg_value2[256] = "0\0", arg_value3[256] = "0\0", arg_value4[256] = "0\0", arg_value5[256] = "0\0"; - if (sscanf(value, "%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^\n]", + if (sscanf(value, "%255[^,],%255[^,],%255[^,],%255[^,],%255[^,],%255[^,],%255[^,],%255[^\n]", mod_str, keysym_str, func_name, arg_value, arg_value2, arg_value3, arg_value4, arg_value5) < 3) { fprintf(stderr, "Error: Invalid bind format: %s\n", value); From 242cfb3c2ff9f461e63be3f8d47ea94092d11a78 Mon Sep 17 00:00:00 2001 From: werapi Date: Mon, 20 Oct 2025 19:11:27 +0200 Subject: [PATCH 251/591] fix: ensure tag changes happen on correct monitor --- src/ext-protocol/foreign-toplevel.h | 2 +- src/mango.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ext-protocol/foreign-toplevel.h b/src/ext-protocol/foreign-toplevel.h index fb441351..adfcd21b 100644 --- a/src/ext-protocol/foreign-toplevel.h +++ b/src/ext-protocol/foreign-toplevel.h @@ -25,7 +25,7 @@ void handle_foreign_activate_request(struct wl_listener *listener, void *data) { } target = get_tags_first_tag(c->tags); - view(&(Arg){.ui = target}, true); + view_in_mon(&(Arg){.ui = target}, true, c->mon, true); focusclient(c, 1); wlr_foreign_toplevel_handle_v1_set_activated(c->foreign_toplevel, true); } diff --git a/src/mango.c b/src/mango.c index 218e5024..c9f4bd0c 100644 --- a/src/mango.c +++ b/src/mango.c @@ -5395,7 +5395,7 @@ urgent(struct wl_listener *listener, void *data) { if (focus_on_activate && !c->istagsilent && c != selmon->sel) { if (!(c->mon == selmon && c->tags & c->mon->tagset[c->mon->seltags])) - view(&(Arg){.ui = c->tags}, true); + view_in_mon(&(Arg){.ui = c->tags}, true, c->mon, true); focusclient(c, 1); } else if (c != focustop(selmon)) { if (client_surface(c)->mapped) @@ -5542,7 +5542,7 @@ void activatex11(struct wl_listener *listener, void *data) { if (focus_on_activate && !c->istagsilent && c != selmon->sel) { if (!(c->mon == selmon && c->tags & c->mon->tagset[c->mon->seltags])) - view(&(Arg){.ui = c->tags}, true); + view_in_mon(&(Arg){.ui = c->tags}, true, c->mon, true); wlr_xwayland_surface_activate(c->surface.xwayland, 1); focusclient(c, 1); need_arrange = true; From 67b5e82bbe444033c8e9de24692384b3c2522ab6 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Mon, 20 Oct 2025 19:16:36 +0800 Subject: [PATCH 252/591] opt: limit config parse string length to 255 --- src/config/parse_config.h | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/src/config/parse_config.h b/src/config/parse_config.h index 8e509cc2..e4f00b1d 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -1412,14 +1412,6 @@ void parse_option(Config *config, char *key, char *value) { } else { convert_hex_to_rgba(config->overlaycolor, color); } - } else if (strcmp(key, "autostart") == 0) { - if (sscanf(value, "%[^,],%[^,],%[^,]", config->autostart[0], - config->autostart[1], config->autostart[2]) != 3) { - fprintf(stderr, "Error: Invalid autostart format: %s\n", value); - } - trim_whitespace(config->autostart[0]); - trim_whitespace(config->autostart[1]); - trim_whitespace(config->autostart[2]); } else if (strcmp(key, "tagrule") == 0) { config->tag_rules = realloc(config->tag_rules, @@ -1654,7 +1646,7 @@ void parse_option(Config *config, char *key, char *value) { rule->isfullscreen = atoi(val); } else if (strcmp(key, "globalkeybinding") == 0) { char mod_str[256], keysym_str[256]; - sscanf(val, "%[^-]-%[a-zA-Z]", mod_str, keysym_str); + sscanf(val, "%255[^-]-%255[a-zA-Z]", mod_str, keysym_str); trim_whitespace(mod_str); trim_whitespace(keysym_str); rule->globalkeybinding.mod = parse_mod(mod_str); @@ -1736,7 +1728,7 @@ void parse_option(Config *config, char *key, char *value) { } else if (strncmp(key, "env", 3) == 0) { char env_type[256], env_value[256]; - if (sscanf(value, "%[^,],%[^\n]", env_type, env_value) < 2) { + if (sscanf(value, "%255[^,],%255[^\n]", env_type, env_value) < 2) { fprintf(stderr, "Error: Invalid bind format: %s\n", value); return; } @@ -1812,7 +1804,9 @@ void parse_option(Config *config, char *key, char *value) { arg_value[256] = "0\0", arg_value2[256] = "0\0", arg_value3[256] = "0\0", arg_value4[256] = "0\0", arg_value5[256] = "0\0"; - if (sscanf(value, "%255[^,],%255[^,],%255[^,],%255[^,],%255[^,],%255[^,],%255[^,],%255[^\n]", + if (sscanf(value, + "%255[^,],%255[^,],%255[^,],%255[^,],%255[^,],%255[^,],%255[" + "^,],%255[^\n]", mod_str, keysym_str, func_name, arg_value, arg_value2, arg_value3, arg_value4, arg_value5) < 3) { fprintf(stderr, "Error: Invalid bind format: %s\n", value); @@ -1883,7 +1877,9 @@ void parse_option(Config *config, char *key, char *value) { arg_value[256] = "0\0", arg_value2[256] = "0\0", arg_value3[256] = "0\0", arg_value4[256] = "0\0", arg_value5[256] = "0\0"; - if (sscanf(value, "%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^\n]", + if (sscanf(value, + "%255[^,],%255[^,],%255[^,],%255[^,],%255[^,],%255[^,],%255[" + "^,],%255[^\n]", mod_str, button_str, func_name, arg_value, arg_value2, arg_value3, arg_value4, arg_value5) < 3) { fprintf(stderr, "Error: Invalid mousebind format: %s\n", value); @@ -1942,7 +1938,9 @@ void parse_option(Config *config, char *key, char *value) { arg_value[256] = "0\0", arg_value2[256] = "0\0", arg_value3[256] = "0\0", arg_value4[256] = "0\0", arg_value5[256] = "0\0"; - if (sscanf(value, "%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^\n]", + if (sscanf(value, + "%255[^,],%255[^,],%255[^,],%255[^,],%255[^,],%255[^,],%255[" + "^,],%255[^\n]", mod_str, dir_str, func_name, arg_value, arg_value2, arg_value3, arg_value4, arg_value5) < 3) { fprintf(stderr, "Error: Invalid axisbind format: %s\n", value); @@ -2004,7 +2002,9 @@ void parse_option(Config *config, char *key, char *value) { arg_value[256] = "0\0", arg_value2[256] = "0\0", arg_value3[256] = "0\0", arg_value4[256] = "0\0", arg_value5[256] = "0\0"; - if (sscanf(value, "%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^\n]", + if (sscanf(value, + "%255[^,],%255[^,],%255[^,],%255[^,],%255[^,],%255[^,],%255[" + "^\n]", fold_str, func_name, arg_value, arg_value2, arg_value3, arg_value4, arg_value5) < 3) { fprintf(stderr, "Error: Invalid switchbind format: %s\n", value); @@ -2061,7 +2061,8 @@ void parse_option(Config *config, char *key, char *value) { arg_value3[256] = "0\0", arg_value4[256] = "0\0", arg_value5[256] = "0\0"; if (sscanf(value, - "%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^\n]", + "%255[^,],%255[^,],%255[^,],%255[^,],%255[^,],%255[^,],%255[" + "^,],%255[^,],%255[^\n]", mod_str, motion_str, fingers_count_str, func_name, arg_value, arg_value2, arg_value3, arg_value4, arg_value5) < 4) { fprintf(stderr, "Error: Invalid gesturebind format: %s\n", value); @@ -2116,7 +2117,7 @@ void parse_option(Config *config, char *key, char *value) { void parse_config_line(Config *config, const char *line) { char key[256], value[256]; - if (sscanf(line, "%[^=]=%[^\n]", key, value) != 2) { + if (sscanf(line, "%255[^=]=%255[^\n]", key, value) != 2) { // fprintf(stderr, "Error: Invalid line format: %s\n", line); return; } From 5429b723f65f50fa34e51b3e5d26c869a056bfc0 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Mon, 20 Oct 2025 17:58:01 +0800 Subject: [PATCH 253/591] opt: make tag animation more consistent --- src/animation/tag.h | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/src/animation/tag.h b/src/animation/tag.h index 4110efbe..8e65a93a 100644 --- a/src/animation/tag.h +++ b/src/animation/tag.h @@ -9,19 +9,23 @@ void set_tagin_animation(Monitor *m, Client *c) { c->animainit_geom.x = tag_animation_direction == VERTICAL ? c->animation.current.x - : c->mon->m.x + c->mon->m.width; + : MAX(c->mon->m.x + c->mon->m.width, + c->geom.x + c->mon->m.width); c->animainit_geom.y = tag_animation_direction == VERTICAL - ? c->mon->m.y + c->mon->m.height + ? MAX(c->mon->m.y + c->mon->m.height, + c->geom.y + c->mon->m.height) : c->animation.current.y; } else { - c->animainit_geom.x = tag_animation_direction == VERTICAL - ? c->animation.current.x - : m->m.x - c->geom.width; - c->animainit_geom.y = tag_animation_direction == VERTICAL - ? m->m.y - c->geom.height - : c->animation.current.y; + c->animainit_geom.x = + tag_animation_direction == VERTICAL + ? c->animation.current.x + : MIN(m->m.x - c->geom.width, c->geom.x - c->mon->m.width); + c->animainit_geom.y = + tag_animation_direction == VERTICAL + ? MIN(m->m.y - c->geom.height, c->geom.y - c->mon->m.height) + : c->animation.current.y; } } @@ -52,11 +56,13 @@ void set_arrange_visible(Monitor *m, Client *c, bool want_animation) { void set_tagout_animation(Monitor *m, Client *c) { if (m->pertag->curtag > m->pertag->prevtag) { c->pending = c->geom; - c->pending.x = tag_animation_direction == VERTICAL - ? c->animation.current.x - : c->mon->m.x - c->geom.width; + c->pending.x = + tag_animation_direction == VERTICAL + ? c->animation.current.x + : MIN(c->mon->m.x - c->geom.width, c->geom.x - c->mon->m.width); c->pending.y = tag_animation_direction == VERTICAL - ? c->mon->m.y - c->geom.height + ? MIN(c->mon->m.y - c->geom.height, + c->geom.y - c->mon->m.height) : c->animation.current.y; resize(c, c->geom, 0); @@ -64,9 +70,11 @@ void set_tagout_animation(Monitor *m, Client *c) { c->pending = c->geom; c->pending.x = tag_animation_direction == VERTICAL ? c->animation.current.x - : c->mon->m.x + c->mon->m.width; + : MAX(c->mon->m.x + c->mon->m.width, + c->geom.x + c->mon->m.width); c->pending.y = tag_animation_direction == VERTICAL - ? c->mon->m.y + c->mon->m.height + ? MAX(c->mon->m.y + c->mon->m.height, + c->geom.y + c->mon->m.height) : c->animation.current.y; resize(c, c->geom, 0); } From f7379f625d855439974179ae0c317b035f0922ad Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Tue, 21 Oct 2025 18:04:10 +0800 Subject: [PATCH 254/591] fix: only set maxmize when ismaxmizescreen is true --- src/mango.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mango.c b/src/mango.c index c9f4bd0c..36c02804 100644 --- a/src/mango.c +++ b/src/mango.c @@ -4451,7 +4451,7 @@ void setmaxmizescreen(Client *c, int maxmizescreen) { if (!c->force_maximize && !c->ismaxmizescreen) { client_set_maximized(c, false); - } else { + } else if (!c->force_maximize && c->ismaxmizescreen) { client_set_maximized(c, true); } From 5e8c5c8732f0c8ecf931119cac2e67b6dd9e9e6b Mon Sep 17 00:00:00 2001 From: werapi Date: Tue, 21 Oct 2025 13:36:34 +0200 Subject: [PATCH 255/591] feat: add support for DRM lease protocol This implementation is based on a patch authored by Micah Gorrell (minego) for dwl. Original repository: https://github.com/minego/dwl Original commit: 94c448a842fc3a9fae454646e149ac63b69e7ef8 --- src/mango.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/mango.c b/src/mango.c index 36c02804..e736d53a 100644 --- a/src/mango.c +++ b/src/mango.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -571,6 +572,7 @@ static void quitsignal(int signo); static void powermgrsetmode(struct wl_listener *listener, void *data); static void rendermon(struct wl_listener *listener, void *data); static void requestdecorationmode(struct wl_listener *listener, void *data); +static void requestdrmlease(struct wl_listener *listener, void *data); static void requeststartdrag(struct wl_listener *listener, void *data); static void resize(Client *c, struct wlr_box geo, int interact); static void run(char *startup_cmd); @@ -727,6 +729,7 @@ static struct wlr_virtual_keyboard_manager_v1 *virtual_keyboard_mgr; static struct wlr_virtual_pointer_manager_v1 *virtual_pointer_mgr; static struct wlr_output_power_manager_v1 *power_mgr; static struct wlr_pointer_gestures_v1 *pointer_gestures; +static struct wlr_drm_lease_v1_manager *drm_lease_manager; static struct wlr_cursor *cursor; static struct wlr_xcursor_manager *cursor_mgr; @@ -830,6 +833,7 @@ static struct wl_listener request_set_cursor_shape = {.notify = setcursorshape}; static struct wl_listener request_start_drag = {.notify = requeststartdrag}; static struct wl_listener start_drag = {.notify = startdrag}; static struct wl_listener new_session_lock = {.notify = locksession}; +static struct wl_listener drm_lease_request = {.notify = requestdrmlease}; #ifdef XWAYLAND static void activatex11(struct wl_listener *listener, void *data); @@ -1934,6 +1938,7 @@ void cleanuplisteners(void) { wl_list_remove(&request_start_drag.link); wl_list_remove(&start_drag.link); wl_list_remove(&new_session_lock.link); + wl_list_remove(&drm_lease_request.link); #ifdef XWAYLAND wl_list_remove(&new_xwayland_surface.link); wl_list_remove(&xwayland_ready.link); @@ -2518,6 +2523,14 @@ void createmon(struct wl_listener *listener, void *data) { if (!wlr_output_init_render(wlr_output, alloc, drw)) return; + if (wlr_output->non_desktop) { + if (drm_lease_manager) { + wlr_drm_lease_v1_manager_offer_output(drm_lease_manager, + wlr_output); + } + return; + } + m = wlr_output->data = ecalloc(1, sizeof(*m)); m->wlr_output = wlr_output; @@ -4109,6 +4122,16 @@ void requestdecorationmode(struct wl_listener *listener, void *data) { } } +static void requestdrmlease(struct wl_listener *listener, void *data) { + struct wlr_drm_lease_request_v1 *req = data; + struct wlr_drm_lease_v1 *lease = wlr_drm_lease_request_v1_grant(req); + + if (!lease) { + wlr_log(WLR_ERROR, "Failed to grant lease request"); + wlr_drm_lease_request_v1_reject(req); + } +} + void requeststartdrag(struct wl_listener *listener, void *data) { struct wlr_seat_request_start_drag_event *event = data; @@ -4965,6 +4988,14 @@ void setup(void) { dwl_input_method_relay = dwl_im_relay_create(); + drm_lease_manager = wlr_drm_lease_v1_manager_create(dpy, backend); + if (drm_lease_manager) { + wl_signal_add(&drm_lease_manager->events.request, &drm_lease_request); + } else { + wlr_log(WLR_ERROR, "Failed to create wlr_drm_lease_device_v1; VR will " + "not be available"); + } + wl_global_create(dpy, &zdwl_ipc_manager_v2_interface, 2, NULL, dwl_ipc_manager_bind); From 776738cc284721ab78585b3e3fb2e4ee3da149af Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Tue, 21 Oct 2025 22:59:14 +0800 Subject: [PATCH 256/591] bump version to 0.10.3 --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index de992266..08f0e718 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('mango', ['c', 'cpp'], - version : '0.10.2', + version : '0.10.3', ) subdir('protocols') From e9565f88f623c3ef45d4b094066cf40ce79e5944 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Wed, 22 Oct 2025 09:17:52 +0800 Subject: [PATCH 257/591] feat: auto convert keysym to keycode bind --- src/config/parse_config.h | 133 ++++++++++++++++++++++++++++++++++--- src/config/preset.h | 9 +++ src/dispatch/bind_define.h | 7 ++ src/mango.c | 124 +++++++++++++++++++++++++--------- 4 files changed, 232 insertions(+), 41 deletions(-) diff --git a/src/config/parse_config.h b/src/config/parse_config.h index e4f00b1d..7ddd00fb 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -20,9 +20,15 @@ enum { NUM_TYPE_MINUS, NUM_TYPE_PLUS, NUM_TYPE_DEFAULT }; enum { KEY_TYPE_SYM, KEY_TYPE_CODE }; +typedef struct { + uint32_t keycode1; + uint32_t keycode2; + uint32_t keycode3; +} MultiKeycode; + typedef struct { xkb_keysym_t keysym; - uint32_t keycode; + MultiKeycode keycode; int type; } KeySymCode; @@ -325,6 +331,8 @@ typedef struct { char keymode[28]; + struct xkb_context *ctx; + struct xkb_keymap *keymap; } Config; typedef int (*FuncType)(const Arg *); @@ -613,23 +621,120 @@ uint32_t parse_mod(const char *mod_str) { return mod; } -KeySymCode parse_key(const char *key_str) { - KeySymCode kc; +// 定义辅助函数:在 keymap 中查找 keysym 对应的多个 keycode +static int find_keycodes_for_keysym(struct xkb_keymap *keymap, xkb_keysym_t sym, + MultiKeycode *multi_kc) { + xkb_keycode_t min_keycode = xkb_keymap_min_keycode(keymap); + xkb_keycode_t max_keycode = xkb_keymap_max_keycode(keymap); + + multi_kc->keycode1 = 0; + multi_kc->keycode2 = 0; + multi_kc->keycode3 = 0; + + int found_count = 0; + + for (xkb_keycode_t keycode = min_keycode; + keycode <= max_keycode && found_count < 3; keycode++) { + // 使用布局0和层级0 + const xkb_keysym_t *syms; + int num_syms = + xkb_keymap_key_get_syms_by_level(keymap, keycode, 0, 0, &syms); + + for (int i = 0; i < num_syms; i++) { + if (syms[i] == sym) { + switch (found_count) { + case 0: + multi_kc->keycode1 = keycode; + break; + case 1: + multi_kc->keycode2 = keycode; + break; + case 2: + multi_kc->keycode3 = keycode; + break; + } + found_count++; + break; + } + } + } + + return found_count; +} + +void cleanup_config_keymap(void) { + if (config.keymap != NULL) { + xkb_keymap_unref(config.keymap); + config.keymap = NULL; + } + if (config.ctx != NULL) { + xkb_context_unref(config.ctx); + config.ctx = NULL; + } +} + +void create_config_keymap(void) { + // 初始化 xkb 上下文和 keymap + + if (config.ctx == NULL) { + config.ctx = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + } + + if (config.keymap == NULL) { + config.keymap = xkb_keymap_new_from_names( + config.ctx, &xkb_fallback_rules, XKB_KEYMAP_COMPILE_NO_FLAGS); + } +} + +KeySymCode parse_key(const char *key_str, bool isbindsym) { + KeySymCode kc = {0}; // 初始化为0 + + if (config.keymap == NULL || config.ctx == NULL) { + // 处理错误 + kc.type = KEY_TYPE_SYM; + kc.keysym = XKB_KEY_NoSymbol; + return kc; + } // 处理 code: 前缀的情况 if (strncmp(key_str, "code:", 5) == 0) { char *endptr; xkb_keycode_t keycode = (xkb_keycode_t)strtol(key_str + 5, &endptr, 10); kc.type = KEY_TYPE_CODE; - kc.keycode = keycode; + kc.keycode.keycode1 = keycode; // 只设置第一个 + kc.keycode.keycode2 = 0; + kc.keycode.keycode3 = 0; return kc; } // 普通键名直接转换 xkb_keysym_t sym = xkb_keysym_from_name(key_str, XKB_KEYSYM_NO_FLAGS); - kc.type = KEY_TYPE_SYM; - kc.keycode = 0; - kc.keysym = sym; + + if (isbindsym) { + kc.type = KEY_TYPE_SYM; + kc.keysym = sym; + return kc; + } + + if (sym != XKB_KEY_NoSymbol) { + // 尝试找到对应的多个 keycode + int found_count = + find_keycodes_for_keysym(config.keymap, sym, &kc.keycode); + if (found_count > 0) { + kc.type = KEY_TYPE_CODE; + kc.keysym = sym; // 仍然保存 keysym 供参考 + } else { + kc.type = KEY_TYPE_SYM; + kc.keysym = sym; + // keycode 字段保持为0 + } + } else { + // 无法解析的键名 + kc.type = KEY_TYPE_SYM; + kc.keysym = XKB_KEY_NoSymbol; + // keycode 字段保持为0 + } + return kc; } @@ -1650,7 +1755,8 @@ void parse_option(Config *config, char *key, char *value) { trim_whitespace(mod_str); trim_whitespace(keysym_str); rule->globalkeybinding.mod = parse_mod(mod_str); - rule->globalkeybinding.keysymcode = parse_key(keysym_str); + rule->globalkeybinding.keysymcode = + parse_key(keysym_str, false); } } token = strtok(NULL, ","); @@ -1787,7 +1893,8 @@ void parse_option(Config *config, char *key, char *value) { config->exec_once_count++; - } else if (strncmp(key, "bind", 4) == 0) { + } else if (strncmp(key, "bind", 4) == 0 || + strncmp(key, "bindsym", 7) == 0) { config->key_bindings = realloc(config->key_bindings, (config->key_bindings_count + 1) * sizeof(KeyBinding)); @@ -1834,7 +1941,8 @@ void parse_option(Config *config, char *key, char *value) { } binding->mod = parse_mod(mod_str); - binding->keysymcode = parse_key(keysym_str); + binding->keysymcode = + parse_key(keysym_str, strncmp(key, "bindsym", 7) == 0); binding->arg.v = NULL; binding->arg.v2 = NULL; binding->arg.v3 = NULL; @@ -2432,6 +2540,9 @@ void free_config(void) { // 释放动画资源 free_baked_points(); + + // 清理解析按键用的keymap + cleanup_config_keymap(); } void override_config(void) { @@ -2815,6 +2926,8 @@ void parse_config(void) { config.cursor_theme = NULL; strcpy(config.keymode, "default"); + create_config_keymap(); + // 获取 MANGOCONFIG 环境变量 const char *mangoconfig = getenv("MANGOCONFIG"); diff --git a/src/config/preset.h b/src/config/preset.h index 31956cf9..ef0894b5 100644 --- a/src/config/preset.h +++ b/src/config/preset.h @@ -114,6 +114,15 @@ char xkb_rules_layout[256]; char xkb_rules_variant[256]; char xkb_rules_options[256]; +/* keyboard */ +static const struct xkb_rule_names xkb_fallback_rules = { + .layout = "us", + .variant = NULL, + .model = NULL, + .rules = NULL, + .options = NULL, +}; + struct xkb_rule_names xkb_rules = { /* can specify fields: rules, model, layout, variant, options */ /* example: diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index 93de6d7f..6e29ca88 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -861,6 +861,13 @@ int switch_keyboard_layout(const Arg *arg) { // 4. 直接修改 rules.layout(保持原有逻辑) struct xkb_rule_names rules = xkb_rules; + // 验证规则是否有效 + if (!check_keyboard_rules_validate(&rules)) { + wlr_log(WLR_ERROR, + "Keyboard rules validation failed, skipping layout reset"); + rules = xkb_fallback_rules; + } + char *layout_buf = (char *)rules.layout; // 假设这是可修改的 // 清空原有内容(安全方式) diff --git a/src/mango.c b/src/mango.c index 36c02804..b3378401 100644 --- a/src/mango.c +++ b/src/mango.c @@ -690,6 +690,7 @@ static void resize_tile_client(Client *grabc, bool isdrag, int offsetx, int offsety, unsigned int time); static void refresh_monitors_workspaces_status(Monitor *m); static void init_client_properties(Client *c); +static bool check_keyboard_rules_validate(struct xkb_rule_names *rules); #include "data/static_keymap.h" #include "dispatch/bind_declare.h" @@ -2365,9 +2366,18 @@ KeyboardGroup *createkeyboardgroup(void) { group->wlr_group = wlr_keyboard_group_create(); group->wlr_group->data = group; + // 4. 直接修改 rules.layout(保持原有逻辑) + struct xkb_rule_names rules = xkb_rules; + // 验证规则是否有效 + if (!check_keyboard_rules_validate(&rules)) { + wlr_log(WLR_ERROR, + "Keyboard rules validation failed, skipping layout reset"); + rules = xkb_fallback_rules; + } + /* Prepare an XKB keymap and assign it to the keyboard group. */ context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); - if (!(keymap = xkb_keymap_new_from_names(context, &xkb_rules, + if (!(keymap = xkb_keymap_new_from_names(context, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS))) die("failed to compile keymap"); @@ -3226,7 +3236,9 @@ keybinding(unsigned int mods, xkb_keysym_t sym, unsigned int keycode) { normalize_keysym(sym) == normalize_keysym(k->keysymcode.keysym)) || (k->keysymcode.type == KEY_TYPE_CODE && - keycode == k->keysymcode.keycode)) && + (keycode == k->keysymcode.keycode.keycode1 || + keycode == k->keysymcode.keycode.keycode2 || + keycode == k->keysymcode.keycode.keycode3))) && k->func) { isbreak = k->func(&k->arg); @@ -3258,14 +3270,18 @@ bool keypressglobal(struct wlr_surface *last_surface, if (!r->globalkeybinding.mod || (!r->globalkeybinding.keysymcode.keysym && - !r->globalkeybinding.keysymcode.keycode)) + !r->globalkeybinding.keysymcode.keycode.keycode1 && + !r->globalkeybinding.keysymcode.keycode.keycode2 && + !r->globalkeybinding.keysymcode.keycode.keycode3)) continue; /* match key only (case insensitive) ignoring mods */ if (((r->globalkeybinding.keysymcode.type == KEY_TYPE_SYM && r->globalkeybinding.keysymcode.keysym == keysym) || (r->globalkeybinding.keysymcode.type == KEY_TYPE_CODE && - r->globalkeybinding.keysymcode.keycode == keycode)) && + (r->globalkeybinding.keysymcode.keycode.keycode1 == keycode || + r->globalkeybinding.keysymcode.keycode.keycode2 == keycode || + r->globalkeybinding.keysymcode.keycode.keycode3 == keycode))) && r->globalkeybinding.mod == mods) { wl_list_for_each(c, &clients, link) { if (c && c != lastc) { @@ -4526,6 +4542,46 @@ void setgaps(int oh, int ov, int ih, int iv) { arrange(selmon, false); } +// 验证键盘规则是否有效 +bool check_keyboard_rules_validate(struct xkb_rule_names *rules) { + if (!rules) { + wlr_log(WLR_ERROR, "Keyboard rules are NULL"); + return false; + } + + struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + if (!context) { + wlr_log(WLR_ERROR, "Failed to create XKB context for validation"); + return false; + } + + bool valid = false; + struct xkb_keymap *test_keymap = + xkb_keymap_new_from_names(context, rules, XKB_KEYMAP_COMPILE_NO_FLAGS); + + if (test_keymap) { + // 检查keymap是否至少有一个布局 + if (xkb_keymap_num_layouts(test_keymap) > 0) { + valid = true; + } else { + wlr_log(WLR_ERROR, "Keymap has no layouts"); + } + xkb_keymap_unref(test_keymap); + } else { + wlr_log(WLR_ERROR, + "Invalid keyboard rules: rules=%s, model=%s, layout=%s, " + "variant=%s, options=%s", + rules->rules ? rules->rules : "NULL", + rules->model ? rules->model : "NULL", + rules->layout ? rules->layout : "NULL", + rules->variant ? rules->variant : "NULL", + rules->options ? rules->options : "NULL"); + } + + xkb_context_unref(context); + return valid; +} + void reset_keyboard_layout(void) { if (!kb_group || !kb_group->wlr_group || !seat) { wlr_log(WLR_ERROR, "Invalid keyboard group or seat"); @@ -4547,6 +4603,16 @@ void reset_keyboard_layout(void) { return; } + // Keep the same rules but just reapply them + struct xkb_rule_names rules = xkb_rules; + + // 验证规则是否有效 + if (!check_keyboard_rules_validate(&rules)) { + wlr_log(WLR_ERROR, + "Keyboard rules validation failed, skipping layout reset"); + rules = xkb_fallback_rules; + } + // Create context struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); if (!context) { @@ -4554,35 +4620,34 @@ void reset_keyboard_layout(void) { return; } - // Get layout abbreviations - const char **layout_ids = calloc(num_layouts, sizeof(char *)); - if (!layout_ids) { - wlr_log(WLR_ERROR, "Failed to allocate layout IDs"); - goto cleanup_context; - } - - for (int i = 0; i < num_layouts; i++) { - layout_ids[i] = - get_layout_abbr(xkb_keymap_layout_get_name(keyboard->keymap, i)); - if (!layout_ids[i]) { - wlr_log(WLR_ERROR, "Failed to get layout abbreviation"); - goto cleanup_layouts; - } - } - - // Keep the same rules but just reapply them - struct xkb_rule_names rules = xkb_rules; - - // Create new keymap with current rules + // 现在安全地创建真正的keymap struct xkb_keymap *new_keymap = xkb_keymap_new_from_names(context, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS); if (!new_keymap) { - wlr_log(WLR_ERROR, "Failed to create keymap for layouts: %s", - rules.layout); - goto cleanup_layouts; + // 理论上这里不应该失败,因为前面已经验证过了 + wlr_log(WLR_ERROR, + "Unexpected failure to create keymap after validation"); + goto cleanup_context; } - // Apply the same keymap (this will reset the layout state) + // 验证新keymap是否有布局 + const int new_num_layouts = xkb_keymap_num_layouts(new_keymap); + if (new_num_layouts < 1) { + wlr_log(WLR_ERROR, "New keymap has no layouts"); + xkb_keymap_unref(new_keymap); + goto cleanup_context; + } + + // 确保当前布局索引在新keymap中有效 + if (current >= new_num_layouts) { + wlr_log(WLR_INFO, + "Current layout index %u out of range for new keymap, " + "resetting to 0", + current); + current = 0; + } + + // Apply the new keymap unsigned int depressed = keyboard->modifiers.depressed; unsigned int latched = keyboard->modifiers.latched; unsigned int locked = keyboard->modifiers.locked; @@ -4599,9 +4664,6 @@ void reset_keyboard_layout(void) { // Cleanup xkb_keymap_unref(new_keymap); -cleanup_layouts: - free(layout_ids); - cleanup_context: xkb_context_unref(context); } From bf6644c9f55140840e28d5c276f49cca794d3fe3 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Wed, 22 Oct 2025 13:24:36 +0800 Subject: [PATCH 258/591] opt: optimize keymap set --- src/config/preset.h | 4 ++++ src/dispatch/bind_define.h | 2 +- src/mango.c | 4 ++-- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/config/preset.h b/src/config/preset.h index ef0894b5..ecec2923 100644 --- a/src/config/preset.h +++ b/src/config/preset.h @@ -123,6 +123,10 @@ static const struct xkb_rule_names xkb_fallback_rules = { .options = NULL, }; +static const struct xkb_rule_names xkb_default_rules = { + .options = NULL, +}; + struct xkb_rule_names xkb_rules = { /* can specify fields: rules, model, layout, variant, options */ /* example: diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index 6e29ca88..87babc3b 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -865,7 +865,7 @@ int switch_keyboard_layout(const Arg *arg) { if (!check_keyboard_rules_validate(&rules)) { wlr_log(WLR_ERROR, "Keyboard rules validation failed, skipping layout reset"); - rules = xkb_fallback_rules; + rules = xkb_default_rules; } char *layout_buf = (char *)rules.layout; // 假设这是可修改的 diff --git a/src/mango.c b/src/mango.c index 7dbf0010..dc459dfe 100644 --- a/src/mango.c +++ b/src/mango.c @@ -2377,7 +2377,7 @@ KeyboardGroup *createkeyboardgroup(void) { if (!check_keyboard_rules_validate(&rules)) { wlr_log(WLR_ERROR, "Keyboard rules validation failed, skipping layout reset"); - rules = xkb_fallback_rules; + rules = xkb_default_rules; } /* Prepare an XKB keymap and assign it to the keyboard group. */ @@ -4633,7 +4633,7 @@ void reset_keyboard_layout(void) { if (!check_keyboard_rules_validate(&rules)) { wlr_log(WLR_ERROR, "Keyboard rules validation failed, skipping layout reset"); - rules = xkb_fallback_rules; + rules = xkb_default_rules; } // Create context From 3fa306fc191fd70ea2cdb8f2328685af7d44e419 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Wed, 22 Oct 2025 14:04:39 +0800 Subject: [PATCH 259/591] opt: default numlock to 0 --- config.conf | 2 +- src/config/preset.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/config.conf b/config.conf index 06fc49ae..24e65ebe 100644 --- a/config.conf +++ b/config.conf @@ -86,7 +86,7 @@ drag_tile_to_tile=1 # keyboard repeat_rate=25 repeat_delay=600 -numlockon=1 +numlockon=0 xkb_rules_layout=us # Trackpad diff --git a/src/config/preset.h b/src/config/preset.h index ecec2923..e03b1546 100644 --- a/src/config/preset.h +++ b/src/config/preset.h @@ -40,7 +40,7 @@ int center_master_overspread = 0; // 中心master时是否铺满 int center_when_single_stack = 1; // 单个stack时是否居中 /* logging */ int log_level = WLR_ERROR; -unsigned int numlockon = 1; // 是否打开右边小键盘 +unsigned int numlockon = 0; // 是否打开右边小键盘 unsigned int capslock = 0; // 是否启用快捷键 unsigned int ov_tab_mode = 0; // alt tab切换模式 From c20a4139a10a507084e90f34dbaae71fad9e015b Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sat, 25 Oct 2025 14:38:52 +0800 Subject: [PATCH 260/591] opt: dont set border for fullscreen window when reload config --- src/config/parse_config.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/config/parse_config.h b/src/config/parse_config.h index 7ddd00fb..9f63d104 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -3055,7 +3055,7 @@ void reapply_border(void) { // reset border width when config change wl_list_for_each(c, &clients, link) { if (c && !c->iskilling) { - if (!c->isnoborder) { + if (!c->isnoborder && !c->isfullscreen) { c->bw = borderpx; } } From bc2b22946cda8ee77510eb5c208ddf465cdbdf08 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sun, 26 Oct 2025 15:38:19 +0800 Subject: [PATCH 261/591] opt: only find same monitor when find same x and same y client --- src/fetch/client.h | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/fetch/client.h b/src/fetch/client.h index 961aac3d..24b0baf6 100644 --- a/src/fetch/client.h +++ b/src/fetch/client.h @@ -150,7 +150,7 @@ Client *find_client_by_direction(Client *tc, const Arg *arg, bool findfloating, // 第一次遍历,计算客户端数量 wl_list_for_each(c, &clients, link) { if (c && (findfloating || !c->isfloating) && !c->isunglobal && - (focus_cross_monitor || c->mon == selmon) && + (focus_cross_monitor || c->mon == tc->mon) && (c->tags & c->mon->tagset[c->mon->seltags])) { last++; } @@ -171,7 +171,7 @@ Client *find_client_by_direction(Client *tc, const Arg *arg, bool findfloating, last = -1; wl_list_for_each(c, &clients, link) { if (c && (findfloating || !c->isfloating) && !c->isunglobal && - (focus_cross_monitor || c->mon == selmon) && + (focus_cross_monitor || c->mon == tc->mon) && (c->tags & c->mon->tagset[c->mon->seltags])) { last++; tempClients[last] = c; @@ -187,7 +187,8 @@ Client *find_client_by_direction(Client *tc, const Arg *arg, bool findfloating, case UP: for (int _i = 0; _i <= last; _i++) { if (tempClients[_i]->geom.y < sel_y && - tempClients[_i]->geom.x == sel_x) { + tempClients[_i]->geom.x == sel_x && + tempClients[_i]->mon == tc->mon) { int dis_x = tempClients[_i]->geom.x - sel_x; int dis_y = tempClients[_i]->geom.y - sel_y; long long int tmp_distance = @@ -216,7 +217,8 @@ Client *find_client_by_direction(Client *tc, const Arg *arg, bool findfloating, case DOWN: for (int _i = 0; _i <= last; _i++) { if (tempClients[_i]->geom.y > sel_y && - tempClients[_i]->geom.x == sel_x) { + tempClients[_i]->geom.x == sel_x && + tempClients[_i]->mon == tc->mon) { int dis_x = tempClients[_i]->geom.x - sel_x; int dis_y = tempClients[_i]->geom.y - sel_y; long long int tmp_distance = @@ -245,7 +247,8 @@ Client *find_client_by_direction(Client *tc, const Arg *arg, bool findfloating, case LEFT: for (int _i = 0; _i <= last; _i++) { if (tempClients[_i]->geom.x < sel_x && - tempClients[_i]->geom.y == sel_y) { + tempClients[_i]->geom.y == sel_y && + tempClients[_i]->mon == tc->mon) { int dis_x = tempClients[_i]->geom.x - sel_x; int dis_y = tempClients[_i]->geom.y - sel_y; long long int tmp_distance = @@ -274,7 +277,8 @@ Client *find_client_by_direction(Client *tc, const Arg *arg, bool findfloating, case RIGHT: for (int _i = 0; _i <= last; _i++) { if (tempClients[_i]->geom.x > sel_x && - tempClients[_i]->geom.y == sel_y) { + tempClients[_i]->geom.y == sel_y && + tempClients[_i]->mon == tc->mon) { int dis_x = tempClients[_i]->geom.x - sel_x; int dis_y = tempClients[_i]->geom.y - sel_y; long long int tmp_distance = From 6ab7f822c12848b8adee3d7c60890ac82a9919e1 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sun, 26 Oct 2025 18:10:48 +0800 Subject: [PATCH 262/591] update readme --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 10c35ccf..844ae900 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,9 @@ Layer animaiton https://github.com/user-attachments/assets/014c893f-115c-4ae9-8342-f9ae3e9a0df0 +# Our discord +[mangowc](https://discord.gg/CPjbDxesh5) + # Supported layouts - tile From 04e3bd6861272c1975876cf70f0be17a706769cf Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Mon, 27 Oct 2025 12:29:41 +0800 Subject: [PATCH 263/591] opt: delay 1ms before exit when mmsg send request --- mmsg/mmsg.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mmsg/mmsg.c b/mmsg/mmsg.c index ae9270d7..7f406d5e 100644 --- a/mmsg/mmsg.c +++ b/mmsg/mmsg.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -373,6 +374,7 @@ static void dwl_ipc_output_frame(void *data, dispatch_arg3, dispatch_arg4, dispatch_arg5); } wl_display_flush(display); + usleep(1000); exit(0); } else { if (tflag) { From 918a00d5789a03ed7d131271c29996c9b78a53c1 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Mon, 27 Oct 2025 12:46:04 +0800 Subject: [PATCH 264/591] opt: allow switch focus between fullscreen and floating window in focusstack --- src/dispatch/bind_define.h | 2 +- src/fetch/client.h | 6 ++++++ src/layout/arrange.h | 5 +++++ src/mango.c | 2 +- 4 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index 87babc3b..21f2884b 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -212,7 +212,7 @@ int focusstack(const Arg *arg) { Client *sel = focustop(selmon); Client *tc = NULL; - if (!sel || (sel->isfullscreen && !client_has_children(sel))) + if (!sel) return 0; if (arg->i == NEXT) { tc = get_next_stack_client(sel, false); diff --git a/src/fetch/client.h b/src/fetch/client.h index 24b0baf6..609caa0c 100644 --- a/src/fetch/client.h +++ b/src/fetch/client.h @@ -343,11 +343,17 @@ Client *get_next_stack_client(Client *c, bool reverse) { Client *next = NULL; if (reverse) { wl_list_for_each_reverse(next, &c->link, link) { + if (c->mon->has_visible_fullscreen_client && !next->isfloating && + !next->isfullscreen) + continue; if (VISIBLEON(next, c->mon) && next != c) return next; } } else { wl_list_for_each(next, &c->link, link) { + if (c->mon->has_visible_fullscreen_client && !next->isfloating && + !next->isfullscreen) + continue; if (VISIBLEON(next, c->mon) && next != c) return next; } diff --git a/src/layout/arrange.h b/src/layout/arrange.h index 18d6b15e..c7935a96 100644 --- a/src/layout/arrange.h +++ b/src/layout/arrange.h @@ -592,6 +592,7 @@ arrange(Monitor *m, bool want_animation) { return; m->visible_clients = 0; m->visible_tiling_clients = 0; + m->has_visible_fullscreen_client = false; wl_list_for_each(c, &clients, link) { @@ -603,6 +604,10 @@ arrange(Monitor *m, bool want_animation) { if (VISIBLEON(c, m)) { m->visible_clients++; + + if (c->isfullscreen) + m->has_visible_fullscreen_client = true; + if (ISTILED(c)) { m->visible_tiling_clients++; } diff --git a/src/mango.c b/src/mango.c index dc459dfe..233c989f 100644 --- a/src/mango.c +++ b/src/mango.c @@ -443,6 +443,7 @@ struct Monitor { int asleep; unsigned int visible_clients; unsigned int visible_tiling_clients; + bool has_visible_fullscreen_client; struct wlr_scene_optimized_blur *blur; char last_surface_ws_name[256]; struct wlr_ext_workspace_group_handle_v1 *ext_group; @@ -4531,7 +4532,6 @@ void setfullscreen(Client *c, int fullscreen) // 用自定义全屏代理自带 wlr_scene_node_raise_to_top(&c->scene->node); // 将视图提升到顶层 resize(c, c->mon->m, 1); c->isfullscreen = 1; - // c->isfloating = 0; } else { c->bw = c->isnoborder ? 0 : borderpx; c->isfullscreen = 0; From 3e83e0788962320fec474143b36a85870e788d59 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Tue, 28 Oct 2025 14:21:13 +0800 Subject: [PATCH 265/591] bump version to 0.10.4 --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 08f0e718..0d33badf 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('mango', ['c', 'cpp'], - version : '0.10.3', + version : '0.10.4', ) subdir('protocols') From cbcbda25cd983e532fbe468ef3b2ad07e9321045 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Tue, 28 Oct 2025 18:51:37 +0800 Subject: [PATCH 266/591] break change: correct maxmize to maximize --- config.conf | 6 +-- src/animation/client.h | 2 +- src/config/parse_config.h | 20 +++---- src/config/preset.h | 2 +- src/dispatch/bind_declare.h | 2 +- src/dispatch/bind_define.h | 18 +++---- src/fetch/client.h | 2 +- src/layout/arrange.h | 6 +-- src/layout/horizontal.h | 2 +- src/layout/vertical.h | 2 +- src/mango.c | 102 ++++++++++++++++++------------------ 11 files changed, 82 insertions(+), 82 deletions(-) diff --git a/config.conf b/config.conf index 24e65ebe..353bdab3 100644 --- a/config.conf +++ b/config.conf @@ -116,7 +116,7 @@ borderpx=4 rootcolor=0x201b14ff bordercolor=0x444444ff focuscolor=0xc9b890ff -maxmizescreencolor=0x89aa61ff +maximizescreencolor=0x89aa61ff urgentcolor=0xad401fff scratchpadcolor=0x516c93ff globalcolor=0xb153a7ff @@ -166,7 +166,7 @@ bind=SUPER+SHIFT,Right,exchange_client,right bind=SUPER,g,toggleglobal, bind=ALT,Tab,toggleoverview, bind=ALT,backslash,togglefloating, -bind=ALT,a,togglemaxmizescreen, +bind=ALT,a,togglemaximizescreen, bind=ALT,f,togglefullscreen, bind=ALT+SHIFT,f,togglefakefullscreen, bind=SUPER,i,minimized, @@ -238,7 +238,7 @@ bind=CTRL+ALT,Right,resizewin,+50,+0 # Mouse Button Bindings # NONE mode key only work in ov mode mousebind=SUPER,btn_left,moveresize,curmove -mousebind=NONE,btn_middle,togglemaxmizescreen,0 +mousebind=NONE,btn_middle,togglemaximizescreen,0 mousebind=SUPER,btn_right,moveresize,curresize mousebind=NONE,btn_left,toggleoverview,-1 mousebind=NONE,btn_right,killclient,0 diff --git a/src/animation/client.h b/src/animation/client.h index b7e3789b..249b7945 100644 --- a/src/animation/client.h +++ b/src/animation/client.h @@ -951,7 +951,7 @@ void resize(Client *c, struct wlr_box geo, int interact) { bbox); // 去掉这个推荐的窗口大小,因为有时推荐的窗口特别大导致平铺异常 } - if (!c->isnosizehint && !c->ismaxmizescreen && !c->isfullscreen && + if (!c->isnosizehint && !c->ismaximizescreen && !c->isfullscreen && c->isfloating) { client_set_size_bound(c); } diff --git a/src/config/parse_config.h b/src/config/parse_config.h index 9f63d104..f12bd93c 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -275,7 +275,7 @@ typedef struct { float rootcolor[4]; float bordercolor[4]; float focuscolor[4]; - float maxmizescreencolor[4]; + float maximizescreencolor[4]; float urgentcolor[4]; float scratchpadcolor[4]; float globalcolor[4]; @@ -986,8 +986,8 @@ FuncType parse_func_name(char *func_name, Arg *arg, char *arg_value, } else if (strcmp(func_name, "moveresize") == 0) { func = moveresize; (*arg).ui = parse_mouse_action(arg_value); - } else if (strcmp(func_name, "togglemaxmizescreen") == 0) { - func = togglemaxmizescreen; + } else if (strcmp(func_name, "togglemaximizescreen") == 0) { + func = togglemaximizescreen; } else if (strcmp(func_name, "viewtoleft_have_client") == 0) { func = viewtoleft_have_client; (*arg).i = atoi(arg_value); @@ -1480,13 +1480,13 @@ void parse_option(Config *config, char *key, char *value) { } else { convert_hex_to_rgba(config->focuscolor, color); } - } else if (strcmp(key, "maxmizescreencolor") == 0) { + } else if (strcmp(key, "maximizescreencolor") == 0) { long int color = parse_color(value); if (color == -1) { - fprintf(stderr, "Error: Invalid maxmizescreencolor format: %s\n", + fprintf(stderr, "Error: Invalid maximizescreencolor format: %s\n", value); } else { - convert_hex_to_rgba(config->maxmizescreencolor, color); + convert_hex_to_rgba(config->maximizescreencolor, color); } } else if (strcmp(key, "urgentcolor") == 0) { long int color = parse_color(value); @@ -2694,8 +2694,8 @@ void override_config(void) { memcpy(rootcolor, config.rootcolor, sizeof(rootcolor)); memcpy(bordercolor, config.bordercolor, sizeof(bordercolor)); memcpy(focuscolor, config.focuscolor, sizeof(focuscolor)); - memcpy(maxmizescreencolor, config.maxmizescreencolor, - sizeof(maxmizescreencolor)); + memcpy(maximizescreencolor, config.maximizescreencolor, + sizeof(maximizescreencolor)); memcpy(urgentcolor, config.urgentcolor, sizeof(urgentcolor)); memcpy(scratchpadcolor, config.scratchpadcolor, sizeof(scratchpadcolor)); memcpy(globalcolor, config.globalcolor, sizeof(globalcolor)); @@ -2853,8 +2853,8 @@ void set_value_default() { memcpy(config.rootcolor, rootcolor, sizeof(rootcolor)); memcpy(config.bordercolor, bordercolor, sizeof(bordercolor)); memcpy(config.focuscolor, focuscolor, sizeof(focuscolor)); - memcpy(config.maxmizescreencolor, maxmizescreencolor, - sizeof(maxmizescreencolor)); + memcpy(config.maximizescreencolor, maximizescreencolor, + sizeof(maximizescreencolor)); memcpy(config.urgentcolor, urgentcolor, sizeof(urgentcolor)); memcpy(config.scratchpadcolor, scratchpadcolor, sizeof(scratchpadcolor)); memcpy(config.globalcolor, globalcolor, sizeof(globalcolor)); diff --git a/src/config/preset.h b/src/config/preset.h index e03b1546..d9425a7e 100644 --- a/src/config/preset.h +++ b/src/config/preset.h @@ -82,7 +82,7 @@ unsigned int borderpx = 4; /* border pixel of windows */ float rootcolor[] = COLOR(0x323232ff); float bordercolor[] = COLOR(0x444444ff); float focuscolor[] = COLOR(0xc66b25ff); -float maxmizescreencolor[] = COLOR(0x89aa61ff); +float maximizescreencolor[] = COLOR(0x89aa61ff); float urgentcolor[] = COLOR(0xad401fff); float scratchpadcolor[] = COLOR(0x516c93ff); float globalcolor[] = COLOR(0xb153a7ff); diff --git a/src/dispatch/bind_declare.h b/src/dispatch/bind_declare.h index cc84923c..b8470fcb 100644 --- a/src/dispatch/bind_declare.h +++ b/src/dispatch/bind_declare.h @@ -16,7 +16,7 @@ int viewtoleft_have_client(const Arg *arg); int viewtoright_have_client(const Arg *arg); int togglefloating(const Arg *arg); int togglefullscreen(const Arg *arg); -int togglemaxmizescreen(const Arg *arg); +int togglemaximizescreen(const Arg *arg); int togglegaps(const Arg *arg); int tagmon(const Arg *arg); int spawn(const Arg *arg); diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index 21f2884b..5765537f 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -80,7 +80,7 @@ int defaultgaps(const Arg *arg) { int exchange_client(const Arg *arg) { Client *c = selmon->sel; - if (!c || c->isfloating || c->isfullscreen || c->ismaxmizescreen) + if (!c || c->isfloating || c->isfullscreen || c->ismaximizescreen) return 0; exchange_two_client(c, direction_select(arg)); return 0; @@ -89,7 +89,7 @@ int exchange_client(const Arg *arg) { int exchange_stack_client(const Arg *arg) { Client *c = selmon->sel; Client *tc = NULL; - if (!c || c->isfloating || c->isfullscreen || c->ismaxmizescreen) + if (!c || c->isfloating || c->isfullscreen || c->ismaximizescreen) return 0; if (arg->i == NEXT) { tc = get_next_stack_client(c, false); @@ -329,7 +329,7 @@ int moveresize(const Arg *arg) { return 0; xytonode(cursor->x, cursor->y, NULL, &grabc, NULL, NULL, NULL); if (!grabc || client_is_unmanaged(grabc) || grabc->isfullscreen || - grabc->ismaxmizescreen) { + grabc->ismaximizescreen) { grabc = NULL; return 0; } @@ -410,7 +410,7 @@ int resizewin(const Arg *arg) { c = selmon->sel; int offsetx = 0, offsety = 0; - if (!c || c->isfullscreen || c->ismaxmizescreen) + if (!c || c->isfullscreen || c->ismaximizescreen) return 0; if (ISTILED(c)) { @@ -1200,7 +1200,7 @@ int togglefloating(const Arg *arg) { if (!sel) return 0; - if ((sel->isfullscreen || sel->ismaxmizescreen)) { + if ((sel->isfullscreen || sel->ismaximizescreen)) { sel->isfloating = 1; } else { sel->isfloating = !sel->isfloating; @@ -1248,7 +1248,7 @@ int togglegaps(const Arg *arg) { return 0; } -int togglemaxmizescreen(const Arg *arg) { +int togglemaximizescreen(const Arg *arg) { Client *sel = focustop(selmon); if (!sel) return 0; @@ -1257,10 +1257,10 @@ int togglemaxmizescreen(const Arg *arg) { sel->is_in_scratchpad = 0; sel->isnamedscratchpad = 0; - if (sel->ismaxmizescreen) - setmaxmizescreen(sel, 0); + if (sel->ismaximizescreen) + setmaximizescreen(sel, 0); else - setmaxmizescreen(sel, 1); + setmaximizescreen(sel, 1); setborder_color(sel); return 0; diff --git a/src/fetch/client.h b/src/fetch/client.h index 609caa0c..f0a4868e 100644 --- a/src/fetch/client.h +++ b/src/fetch/client.h @@ -317,7 +317,7 @@ Client *direction_select(const Arg *arg) { if (!tc) return NULL; - if (tc && (tc->isfullscreen || tc->ismaxmizescreen)) { + if (tc && (tc->isfullscreen || tc->ismaximizescreen)) { // 不支持全屏窗口的焦点切换 return NULL; } diff --git a/src/layout/arrange.h b/src/layout/arrange.h index c7935a96..69393c7e 100644 --- a/src/layout/arrange.h +++ b/src/layout/arrange.h @@ -472,7 +472,7 @@ void resize_tile_scroller(Client *grabc, bool isdrag, int offsetx, int offsety, void resize_tile_client(Client *grabc, bool isdrag, int offsetx, int offsety, unsigned int time) { - if (!grabc || grabc->isfullscreen || grabc->ismaxmizescreen) + if (!grabc || grabc->isfullscreen || grabc->ismaximizescreen) return; const Layout *current_layout = @@ -652,9 +652,9 @@ arrange(Monitor *m, bool want_animation) { } } - if (c->mon == m && c->ismaxmizescreen && !c->animation.tagouted && + if (c->mon == m && c->ismaximizescreen && !c->animation.tagouted && !c->animation.tagouting && VISIBLEON(c, m)) { - reset_maxmizescreen_size(c); + reset_maximizescreen_size(c); } } diff --git a/src/layout/horizontal.h b/src/layout/horizontal.h index 3bebd3de..3a376b50 100644 --- a/src/layout/horizontal.h +++ b/src/layout/horizontal.h @@ -246,7 +246,7 @@ void scroller(Monitor *m) { } if (m->sel && !client_is_unmanaged(m->sel) && !m->sel->isfloating && - !m->sel->ismaxmizescreen && !m->sel->isfullscreen) { + !m->sel->ismaximizescreen && !m->sel->isfullscreen) { root_client = m->sel; } else if (m->prevsel && ISTILED(m->prevsel) && VISIBLEON(m->prevsel, m) && !client_is_unmanaged(m->prevsel)) { diff --git a/src/layout/vertical.h b/src/layout/vertical.h index 3cddcba8..7e1df68f 100644 --- a/src/layout/vertical.h +++ b/src/layout/vertical.h @@ -205,7 +205,7 @@ void vertical_scroller(Monitor *m) { } if (m->sel && !client_is_unmanaged(m->sel) && !m->sel->isfloating && - !m->sel->ismaxmizescreen && !m->sel->isfullscreen) { + !m->sel->ismaximizescreen && !m->sel->isfullscreen) { root_client = m->sel; } else if (m->prevsel && ISTILED(m->prevsel) && VISIBLEON(m->prevsel, m) && !client_is_unmanaged(m->prevsel)) { diff --git a/src/mango.c b/src/mango.c index 233c989f..101c1245 100644 --- a/src/mango.c +++ b/src/mango.c @@ -102,7 +102,7 @@ A->geom.y + A->geom.height <= A->mon->m.y + A->mon->m.height) #define ISTILED(A) \ (A && !(A)->isfloating && !(A)->isminied && !(A)->iskilling && \ - !(A)->ismaxmizescreen && !(A)->isfullscreen) + !(A)->ismaximizescreen && !(A)->isfullscreen) #define VISIBLEON(C, M) \ ((M) && (C)->mon == (M) && ((C)->tags & (M)->tagset[(M)->seltags])) #define LENGTH(X) (sizeof X / sizeof X[0]) @@ -110,8 +110,8 @@ #define TAGMASK ((1 << LENGTH(tags)) - 1) #define LISTEN(E, L, H) wl_signal_add((E), ((L)->notify = (H), (L))) #define ISFULLSCREEN(A) \ - ((A)->isfullscreen || (A)->ismaxmizescreen || \ - (A)->overview_ismaxmizescreenbak || (A)->overview_isfullscreenbak) + ((A)->isfullscreen || (A)->ismaximizescreen || \ + (A)->overview_ismaximizescreenbak || (A)->overview_isfullscreenbak) #define LISTEN_STATIC(E, H) \ do { \ struct wl_listener *_l = ecalloc(1, sizeof(*_l)); \ @@ -292,11 +292,11 @@ struct Client { int isfloating, isurgent, isfullscreen, isfakefullscreen, need_float_size_reduce, isminied, isoverlay, isnosizehint, ignore_maximize, ignore_minimize; - int ismaxmizescreen; + int ismaximizescreen; int overview_backup_bw; int fullscreen_backup_x, fullscreen_backup_y, fullscreen_backup_w, fullscreen_backup_h; - int overview_isfullscreenbak, overview_ismaxmizescreenbak, + int overview_isfullscreenbak, overview_ismaximizescreenbak, overview_isfloatingbak; struct wlr_xdg_toplevel_decoration_v1 *decoration; @@ -581,8 +581,8 @@ static void setcursor(struct wl_listener *listener, void *data); static void setfloating(Client *c, int floating); static void setfakefullscreen(Client *c, int fakefullscreen); static void setfullscreen(Client *c, int fullscreen); -static void setmaxmizescreen(Client *c, int maxmizescreen); -static void reset_maxmizescreen_size(Client *c); +static void setmaximizescreen(Client *c, int maximizescreen); +static void reset_maximizescreen_size(Client *c); static void setgaps(int oh, int ov, int ih, int iv); static void setmon(Client *c, Monitor *m, unsigned int newtags, bool focus); @@ -892,16 +892,16 @@ void clear_fullscreen_flag(Client *c) { setfullscreen(c, false); } - if (c->ismaxmizescreen) { - setmaxmizescreen(c, 0); + if (c->ismaximizescreen) { + setmaximizescreen(c, 0); } } void show_scratchpad(Client *c) { c->is_scratchpad_show = 1; - if (c->isfullscreen || c->ismaxmizescreen) { + if (c->isfullscreen || c->ismaximizescreen) { c->isfullscreen = 0; // 清除窗口全屏标志 - c->ismaxmizescreen = 0; + c->ismaximizescreen = 0; c->bw = c->isnoborder ? 0 : borderpx; } @@ -941,7 +941,7 @@ void swallow(Client *c, Client *w) { c->isfloating = w->isfloating; c->isurgent = w->isurgent; c->isfullscreen = w->isfullscreen; - c->ismaxmizescreen = w->ismaxmizescreen; + c->ismaximizescreen = w->ismaximizescreen; c->isminied = w->isminied; c->is_in_scratchpad = w->is_in_scratchpad; c->is_scratchpad_show = w->is_scratchpad_show; @@ -3090,7 +3090,7 @@ void focusclient(Client *c, int lift) { if (c && selmon->prevsel && (selmon->prevsel->tags & selmon->tagset[selmon->seltags]) && (c->tags & selmon->tagset[selmon->seltags]) && !c->isfloating && - !c->isfullscreen && !c->ismaxmizescreen && + !c->isfullscreen && !c->ismaximizescreen && is_scroller_layout(selmon)) { arrange(selmon, false); } @@ -3489,7 +3489,7 @@ static void iter_xdg_scene_buffers(struct wlr_scene_buffer *buffer, int sx, } void init_client_properties(Client *c) { - c->ismaxmizescreen = 0; + c->ismaximizescreen = 0; c->isfullscreen = 0; c->need_float_size_reduce = 0; c->iskilling = 0; @@ -3666,16 +3666,16 @@ maximizenotify(struct wl_listener *listener, void *data) { // if (wl_resource_get_version(c->surface.xdg->toplevel->resource) // < XDG_TOPLEVEL_WM_CAPABILITIES_SINCE_VERSION) // wlr_xdg_surface_schedule_configure(c->surface.xdg); - // togglemaxmizescreen(&(Arg){0}); + // togglemaximizescreen(&(Arg){0}); Client *c = wl_container_of(listener, c, maximize); if (!c || !c->mon || c->iskilling || c->ignore_maximize) return; - if (c->ismaxmizescreen || c->isfullscreen) - setmaxmizescreen(c, 0); + if (c->ismaximizescreen || c->isfullscreen) + setmaximizescreen(c, 0); else - setmaxmizescreen(c, 1); + setmaximizescreen(c, 1); } void unminimize(Client *c) { @@ -3734,7 +3734,7 @@ minimizenotify(struct wl_listener *listener, void *data) { // if (wl_resource_get_version(c->surface.xdg->toplevel->resource) // < XDG_TOPLEVEL_WM_CAPABILITIES_SINCE_VERSION) // wlr_xdg_surface_schedule_configure(c->surface.xdg); - // togglemaxmizescreen(&(Arg){0}); + // togglemaximizescreen(&(Arg){0}); Client *c = wl_container_of(listener, c, minimize); @@ -4172,8 +4172,8 @@ void setborder_color(Client *c) { client_set_border_color(c, globalcolor); } else if (c->isoverlay && selmon && c == selmon->sel) { client_set_border_color(c, overlaycolor); - } else if (c->ismaxmizescreen && selmon && c == selmon->sel) { - client_set_border_color(c, maxmizescreencolor); + } else if (c->ismaximizescreen && selmon && c == selmon->sel) { + client_set_border_color(c, maximizescreencolor); } else if (selmon && c == selmon->sel) { client_set_border_color(c, focuscolor); } else { @@ -4371,9 +4371,9 @@ setfloating(Client *c, int floating) { if (floating == 1 && c != grabc) { - if (c->isfullscreen || c->ismaxmizescreen) { + if (c->isfullscreen || c->ismaximizescreen) { c->isfullscreen = 0; // 清除窗口全屏标志 - c->ismaxmizescreen = 0; + c->ismaximizescreen = 0; c->bw = c->isnoborder ? 0 : borderpx; } @@ -4441,7 +4441,7 @@ setfloating(Client *c, int floating) { printstatus(); } -void reset_maxmizescreen_size(Client *c) { +void reset_maximizescreen_size(Client *c) { c->geom.x = c->mon->w.x + gappoh; c->geom.y = c->mon->w.y + gappov; c->geom.width = c->mon->w.width - 2 * gappoh; @@ -4449,14 +4449,14 @@ void reset_maxmizescreen_size(Client *c) { resize(c, c->geom, 0); } -void setmaxmizescreen(Client *c, int maxmizescreen) { - struct wlr_box maxmizescreen_box; +void setmaximizescreen(Client *c, int maximizescreen) { + struct wlr_box maximizescreen_box; if (!c || !c->mon || !client_surface(c)->mapped || c->iskilling) return; - c->ismaxmizescreen = maxmizescreen; + c->ismaximizescreen = maximizescreen; - if (maxmizescreen) { + if (maximizescreen) { if (c->isfullscreen) setfullscreen(c, 0); @@ -4468,30 +4468,30 @@ void setmaxmizescreen(Client *c, int maxmizescreen) { toggleoverview(&arg); } - maxmizescreen_box.x = c->mon->w.x + gappoh; - maxmizescreen_box.y = c->mon->w.y + gappov; - maxmizescreen_box.width = c->mon->w.width - 2 * gappoh; - maxmizescreen_box.height = c->mon->w.height - 2 * gappov; + maximizescreen_box.x = c->mon->w.x + gappoh; + maximizescreen_box.y = c->mon->w.y + gappov; + maximizescreen_box.width = c->mon->w.width - 2 * gappoh; + maximizescreen_box.height = c->mon->w.height - 2 * gappov; wlr_scene_node_raise_to_top(&c->scene->node); // 将视图提升到顶层 - resize(c, maxmizescreen_box, 0); - c->ismaxmizescreen = 1; + resize(c, maximizescreen_box, 0); + c->ismaximizescreen = 1; } else { c->bw = c->isnoborder ? 0 : borderpx; - c->ismaxmizescreen = 0; + c->ismaximizescreen = 0; if (c->isfloating) setfloating(c, 1); } - wlr_scene_node_reparent(&c->scene->node, layers[maxmizescreen ? LyrTile + wlr_scene_node_reparent(&c->scene->node, layers[maximizescreen ? LyrTile : c->isfloating ? LyrTop : LyrTile]); - if (!c->ismaxmizescreen) { + if (!c->ismaximizescreen) { set_size_per(c->mon, c); } - if (!c->force_maximize && !c->ismaxmizescreen) { + if (!c->force_maximize && !c->ismaximizescreen) { client_set_maximized(c, false); - } else if (!c->force_maximize && c->ismaxmizescreen) { + } else if (!c->force_maximize && c->ismaximizescreen) { client_set_maximized(c, true); } @@ -4518,8 +4518,8 @@ void setfullscreen(Client *c, int fullscreen) // 用自定义全屏代理自带 client_set_fullscreen(c, fullscreen); if (fullscreen) { - if (c->ismaxmizescreen) - setmaxmizescreen(c, 0); + if (c->ismaximizescreen) + setmaximizescreen(c, 0); if (c->isfloating) c->float_geom = c->geom; @@ -5139,7 +5139,7 @@ unsigned int want_restore_fullscreen(Client *target_client) { void overview_backup(Client *c) { c->overview_isfloatingbak = c->isfloating; c->overview_isfullscreenbak = c->isfullscreen; - c->overview_ismaxmizescreenbak = c->ismaxmizescreen; + c->overview_ismaximizescreenbak = c->ismaximizescreen; c->overview_isfullscreenbak = c->isfullscreen; c->animation.tagining = false; c->animation.tagouted = false; @@ -5149,9 +5149,9 @@ void overview_backup(Client *c) { if (c->isfloating) { c->isfloating = 0; } - if (c->isfullscreen || c->ismaxmizescreen) { + if (c->isfullscreen || c->ismaximizescreen) { c->isfullscreen = 0; // 清除窗口全屏标志 - c->ismaxmizescreen = 0; + c->ismaximizescreen = 0; } c->bw = c->isnoborder ? 0 : borderpx; } @@ -5160,10 +5160,10 @@ void overview_backup(Client *c) { void overview_restore(Client *c, const Arg *arg) { c->isfloating = c->overview_isfloatingbak; c->isfullscreen = c->overview_isfullscreenbak; - c->ismaxmizescreen = c->overview_ismaxmizescreenbak; + c->ismaximizescreen = c->overview_ismaximizescreenbak; c->overview_isfloatingbak = 0; c->overview_isfullscreenbak = 0; - c->overview_ismaxmizescreenbak = 0; + c->overview_ismaximizescreenbak = 0; c->geom = c->overview_backup_geom; c->bw = c->overview_backup_bw; c->animation.tagining = false; @@ -5172,14 +5172,14 @@ void overview_restore(Client *c, const Arg *arg) { if (c->isfloating) { // XRaiseWindow(dpy, c->win); // 提升悬浮窗口到顶层 resize(c, c->overview_backup_geom, 0); - } else if (c->isfullscreen || c->ismaxmizescreen) { - if (want_restore_fullscreen(c) && c->ismaxmizescreen) { - setmaxmizescreen(c, 1); + } else if (c->isfullscreen || c->ismaximizescreen) { + if (want_restore_fullscreen(c) && c->ismaximizescreen) { + setmaximizescreen(c, 1); } else if (want_restore_fullscreen(c) && c->isfullscreen) { setfullscreen(c, 1); } else { c->isfullscreen = 0; - c->ismaxmizescreen = 0; + c->ismaximizescreen = 0; setfullscreen(c, false); } } else { @@ -5309,7 +5309,7 @@ void unmapnotify(struct wl_listener *listener, void *data) { } if (c->swallowedby) { - setmaxmizescreen(c->swallowedby, c->ismaxmizescreen); + setmaximizescreen(c->swallowedby, c->ismaximizescreen); setfullscreen(c->swallowedby, c->isfullscreen); c->swallowedby->swallowing = NULL; c->swallowedby = NULL; From 9b5ea5009518cc45cf1e104239321062e9618039 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Wed, 29 Oct 2025 13:06:05 +0800 Subject: [PATCH 267/591] feat: add dispatch viewcrossmon and tagcrossmon --- src/config/parse_config.h | 10 +++++++++- src/dispatch/bind_declare.h | 2 ++ src/dispatch/bind_define.h | 25 +++++++++++++++++++++++-- 3 files changed, 34 insertions(+), 3 deletions(-) diff --git a/src/config/parse_config.h b/src/config/parse_config.h index f12bd93c..57ba70d7 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -955,7 +955,7 @@ FuncType parse_func_name(char *func_name, Arg *arg, char *arg_value, } else if (strcmp(func_name, "tagmon") == 0) { func = tagmon; (*arg).i = parse_direction(arg_value); - (*arg).ui = atoi(arg_value2); + (*arg).i2 = atoi(arg_value2); if ((*arg).i == UNDIR) { (*arg).v = strdup(arg_value); }; @@ -1004,6 +1004,14 @@ FuncType parse_func_name(char *func_name, Arg *arg, char *arg_value, func = bind_to_view; (*arg).ui = 1 << (atoi(arg_value) - 1); (*arg).i = atoi(arg_value2); + } else if (strcmp(func_name, "viewcrossmon") == 0) { + func = viewcrossmon; + (*arg).ui = 1 << (atoi(arg_value) - 1); + (*arg).v = strdup(arg_value2); + } else if (strcmp(func_name, "tagcrossmon") == 0) { + func = tagcrossmon; + (*arg).ui = 1 << (atoi(arg_value) - 1); + (*arg).v = strdup(arg_value2); } else if (strcmp(func_name, "toggletag") == 0) { func = toggletag; (*arg).ui = 1 << (atoi(arg_value) - 1); diff --git a/src/dispatch/bind_declare.h b/src/dispatch/bind_declare.h index b8470fcb..c57a132d 100644 --- a/src/dispatch/bind_declare.h +++ b/src/dispatch/bind_declare.h @@ -10,10 +10,12 @@ int zoom(const Arg *arg); int tagsilent(const Arg *arg); int tagtoleft(const Arg *arg); int tagtoright(const Arg *arg); +int tagcrossmon(const Arg *arg); int viewtoleft(const Arg *arg); int viewtoright(const Arg *arg); int viewtoleft_have_client(const Arg *arg); int viewtoright_have_client(const Arg *arg); +int viewcrossmon(const Arg *arg); int togglefloating(const Arg *arg); int togglefullscreen(const Arg *arg); int togglemaximizescreen(const Arg *arg); diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index 5765537f..b2dd637c 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -1051,11 +1051,17 @@ int tagmon(const Arg *arg) { return 0; } - if (!m || !m->wlr_output->enabled || m == c->mon) + if (!m || !m->wlr_output->enabled) return 0; - unsigned int newtags = arg->ui ? c->tags : 0; + unsigned int newtags = arg->ui ? arg->ui : arg->i2 ? c->tags : 0; unsigned int target; + + if (c->mon == m) { + view(&(Arg){.ui = newtags}, true); + return 0; + } + if (c == selmon->sel) { selmon->sel = NULL; } @@ -1072,6 +1078,7 @@ int tagmon(const Arg *arg) { selmon = c->mon; c->float_geom = setclient_coordinate_center(c, c->float_geom, 0, 0); + // 重新计算居中的坐标 // 重新计算居中的坐标 if (c->isfloating) { c->geom = c->float_geom; @@ -1415,6 +1422,20 @@ int viewtoright_have_client(const Arg *arg) { return 0; } +int viewcrossmon(const Arg *arg) { + focusmon(arg); + view_in_mon(arg, true, selmon, true); + return 0; +} + +int tagcrossmon(const Arg *arg) { + if (!selmon->sel) + return 0; + + tagmon(&(Arg){.ui = arg->ui, .i = UNDIR, .v = arg->v}); + return 0; +} + int comboview(const Arg *arg) { unsigned int newtags = arg->ui & TAGMASK; From 3e6d8c6a18231ea2cf9ed85020261c4e08e3a9cc Mon Sep 17 00:00:00 2001 From: 4zv4l <4zv4l@protonmail.com> Date: Wed, 29 Oct 2025 21:34:22 +0800 Subject: [PATCH 268/591] feat: allow to build using Guix --- mangowc.scm | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 mangowc.scm diff --git a/mangowc.scm b/mangowc.scm new file mode 100644 index 00000000..94e80c02 --- /dev/null +++ b/mangowc.scm @@ -0,0 +1,52 @@ +(define-module (mangowc) + #:use-module (guix packages) + #:use-module (guix download) + #:use-module (guix git-download) + #:use-module (gnu packages wm) + #:use-module (gnu packages freedesktop) + #:use-module (gnu packages xdisorg) + #:use-module (gnu packages pciutils) + #:use-module (gnu packages admin) + #:use-module (gnu packages pcre) + #:use-module (gnu packages xorg) + #:use-module (gnu packages build-tools) + #:use-module (gnu packages ninja) + #:use-module (gnu packages pkg-config) + #:use-module (guix build-system meson) + #:use-module (guix licenses)) + + +(define-public mangowc + (package + (name "mangowc") + (version "0.10.4") + (source + (origin + (method git-fetch) + (uri (git-reference + (url "https://github.com/DreamMaoMao/mangowc") + (commit "0.10.4"))) + (sha256 + (base32 "0cayb2r69zcp5q810bqhq27xi0b5dlk81qwl6zj6aqjphh6yzpv9")))) + (build-system meson-build-system) + (inputs (list wayland + wayland-protocols + libinput + libdrm + libxkbcommon + pixman + libdisplay-info + libliftoff + hwdata + seatd + pcre2 + libxcb + xcb-util-wm + wlroots + scenefx)) + (native-inputs (list meson ninja pkg-config)) + (home-page "https://github.com/DreamMaoMao/mangowc") + (synopsis "Wayland compositor based on wlroots and scenefx") + (description "A Wayland compositor based on wlroots and scenefx, +inspired by dwl but aiming to be more feature-rich.") + (license gpl3))) From 26fd6894eb7ebf839c6571c0c336d807f9ef20f5 Mon Sep 17 00:00:00 2001 From: reDpz Date: Wed, 29 Oct 2025 14:41:29 +0000 Subject: [PATCH 269/591] Set arg.i = UNDIR so that focusmon uses arg.v to select monitor --- src/dispatch/bind_define.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index b2dd637c..ea7ca646 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -1423,7 +1423,10 @@ int viewtoright_have_client(const Arg *arg) { } int viewcrossmon(const Arg *arg) { - focusmon(arg); + // Don't switch monitors if monitor is already focused + // This also prevents cursorwarp + if (!regex_match(arg->v, selmon->wlr_output->name)) + focusmon(&(Arg){.v = arg->v, .i = UNDIR}); view_in_mon(arg, true, selmon, true); return 0; } From 27fdead702de39640e1089cd76f0b85b1f653fca Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Thu, 30 Oct 2025 13:30:02 +0800 Subject: [PATCH 270/591] feat: add dispatch enable_monitor,disable_monitr,toggle_monitor --- src/config/parse_config.h | 9 ++++++++ src/dispatch/bind_declare.h | 5 ++++- src/dispatch/bind_define.h | 45 +++++++++++++++++++++++++++++++++++++ src/mango.c | 6 ----- 4 files changed, 58 insertions(+), 7 deletions(-) diff --git a/src/config/parse_config.h b/src/config/parse_config.h index 57ba70d7..16b85e64 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -1048,6 +1048,15 @@ FuncType parse_func_name(char *func_name, Arg *arg, char *arg_value, (*arg).v = strdup(arg_value); (*arg).v2 = strdup(arg_value2); (*arg).v3 = strdup(arg_value3); + } else if (strcmp(func_name, "disable_monitor") == 0) { + func = disable_monitor; + (*arg).v = strdup(arg_value); + } else if (strcmp(func_name, "enable_monitor") == 0) { + func = enable_monitor; + (*arg).v = strdup(arg_value); + } else if (strcmp(func_name, "toggle_monitor") == 0) { + func = toggle_monitor; + (*arg).v = strdup(arg_value); } else { return NULL; } diff --git a/src/dispatch/bind_declare.h b/src/dispatch/bind_declare.h index c57a132d..b02ccf99 100644 --- a/src/dispatch/bind_declare.h +++ b/src/dispatch/bind_declare.h @@ -66,4 +66,7 @@ int create_virtual_output(const Arg *arg); int destroy_all_virtual_output(const Arg *arg); int focuslast(const Arg *arg); int toggle_trackpad_enable(const Arg *arg); -int setoption(const Arg *arg); \ No newline at end of file +int setoption(const Arg *arg); +int disable_monitor(const Arg *arg); +int enable_monitor(const Arg *arg); +int toggle_monitor(const Arg *arg); \ No newline at end of file diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index ea7ca646..8c25efb9 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -1570,3 +1570,48 @@ int toggleoverview(const Arg *arg) { refresh_monitors_workspaces_status(selmon); return 0; } + +int disable_monitor(const Arg *arg) { + Monitor *m = NULL; + struct wlr_output_state state = {0}; + wl_list_for_each(m, &mons, link) { + if (regex_match(arg->v, m->wlr_output->name)) { + wlr_output_state_set_enabled(&state, false); + wlr_output_commit_state(m->wlr_output, &state); + m->asleep = 1; + updatemons(NULL, NULL); + break; + } + } + return 0; +} + +int enable_monitor(const Arg *arg) { + Monitor *m = NULL; + struct wlr_output_state state = {0}; + wl_list_for_each(m, &mons, link) { + if (regex_match(arg->v, m->wlr_output->name)) { + wlr_output_state_set_enabled(&state, true); + wlr_output_commit_state(m->wlr_output, &state); + m->asleep = 0; + updatemons(NULL, NULL); + break; + } + } + return 0; +} + +int toggle_monitor(const Arg *arg) { + Monitor *m = NULL; + struct wlr_output_state state = {0}; + wl_list_for_each(m, &mons, link) { + if (regex_match(arg->v, m->wlr_output->name)) { + wlr_output_state_set_enabled(&state, !m->wlr_output->enabled); + wlr_output_commit_state(m->wlr_output, &state); + m->asleep = !m->wlr_output->enabled; + updatemons(NULL, NULL); + break; + } + } + return 0; +} \ No newline at end of file diff --git a/src/mango.c b/src/mango.c index 101c1245..858f8f7e 100644 --- a/src/mango.c +++ b/src/mango.c @@ -439,7 +439,6 @@ struct Monitor { Client *sel, *prevsel; int isoverview; int is_in_hotarea; - int gamma_lut_changed; int asleep; unsigned int visible_clients; unsigned int visible_tiling_clients; @@ -4050,7 +4049,6 @@ void powermgrsetmode(struct wl_listener *listener, void *data) { if (!m) return; - m->gamma_lut_changed = 1; /* Reapply gamma LUT when re-enabling the ouput */ wlr_output_state_set_enabled(&state, event->mode); wlr_output_commit_state(m->wlr_output, &state); @@ -5427,10 +5425,6 @@ void updatemons(struct wl_listener *listener, void *data) { if ((c = focustop(m)) && c->isfullscreen) resize(c, m->m, 0); - /* Try to re-set the gamma LUT when updating monitors, - * it's only really needed when enabling a disabled output, but meh. - */ - m->gamma_lut_changed = 1; config_head->state.x = m->m.x; config_head->state.y = m->m.y; From 05e9d149c1944c6ccb2700dbc894b4d941ba8188 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Thu, 30 Oct 2025 14:13:54 +0800 Subject: [PATCH 271/591] feat: support get scale by mmsg --- mmsg/mmsg.c | 27 ++++++++++++++++++++++++--- protocols/dwl-ipc-unstable-v2.xml | 7 +++++++ src/ext-protocol/dwl-ipc.h | 6 ++++++ src/mango.c | 1 - 4 files changed, 37 insertions(+), 4 deletions(-) diff --git a/mmsg/mmsg.c b/mmsg/mmsg.c index 7f406d5e..6f350ed0 100644 --- a/mmsg/mmsg.c +++ b/mmsg/mmsg.c @@ -41,6 +41,7 @@ static int xflag; static int eflag; static int kflag; static int bflag; +static int Aflag; static uint32_t occ, seltags, total_clients, urg; @@ -264,6 +265,18 @@ static void dwl_ipc_output_kb_layout(void *data, printf("kb_layout %s\n", kb_layout); } +static void +dwl_ipc_output_scalefactor(void *data, + struct zdwl_ipc_output_v2 *dwl_ipc_output, + const unsigned int scalefactor) { + if (!Aflag) + return; + char *output_name = data; + if (output_name) + printf("%s ", output_name); + printf("scale_factor %f\n", scalefactor / 100.0f); +} + static void dwl_ipc_output_keymode(void *data, struct zdwl_ipc_output_v2 *dwl_ipc_output, const char *keymode) { @@ -413,6 +426,7 @@ static const struct zdwl_ipc_output_v2_listener dwl_ipc_output_listener = { .last_layer = dwl_ipc_output_last_layer, .kb_layout = dwl_ipc_output_kb_layout, .keymode = dwl_ipc_output_keymode, + .scalefactor = dwl_ipc_output_scalefactor, .frame = dwl_ipc_output_frame, }; @@ -490,7 +504,7 @@ static void usage(void) { "\t%s [-OTLq]\n" "\t%s [-o ] -s [-t ] [-l ] [-c ] [-d " ",,,,,]\n" - "\t%s [-o ] (-g | -w) [-Ootlcvmfxekb]\n", + "\t%s [-o ] (-g | -w) [-OotlcvmfxekbA]\n", argv0, argv0, argv0); exit(2); } @@ -732,6 +746,12 @@ int main(int argc, char *argv[]) { usage(); mode |= GET; break; + case 'A': + Aflag = 1; + if (mode == SET) + usage(); + mode |= GET; + break; default: fprintf(stderr, "bad option %c\n", ARGC()); usage(); @@ -741,9 +761,10 @@ int main(int argc, char *argv[]) { usage(); if (mode & GET && !output_name && !(oflag || tflag || lflag || Oflag || Tflag || Lflag || cflag || - vflag || mflag || fflag || xflag || eflag || kflag || bflag || dflag)) + vflag || mflag || fflag || xflag || eflag || kflag || bflag || + Aflag || dflag)) oflag = tflag = lflag = cflag = vflag = mflag = fflag = xflag = eflag = - kflag = bflag = 1; + kflag = bflag = Aflag = 1; display = wl_display_connect(NULL); if (!display) diff --git a/protocols/dwl-ipc-unstable-v2.xml b/protocols/dwl-ipc-unstable-v2.xml index a43a7f06..5852107e 100644 --- a/protocols/dwl-ipc-unstable-v2.xml +++ b/protocols/dwl-ipc-unstable-v2.xml @@ -241,6 +241,13 @@ I would probably just submit raphi's patchset but I don't think that would be po + + + scale factor of monitor. + + + + diff --git a/src/ext-protocol/dwl-ipc.h b/src/ext-protocol/dwl-ipc.h index 23207d01..5ecb06eb 100644 --- a/src/ext-protocol/dwl-ipc.h +++ b/src/ext-protocol/dwl-ipc.h @@ -204,6 +204,12 @@ void dwl_ipc_output_printstatus_to(DwlIpcOutput *ipc_output) { 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); } diff --git a/src/mango.c b/src/mango.c index 858f8f7e..2e290175 100644 --- a/src/mango.c +++ b/src/mango.c @@ -5425,7 +5425,6 @@ void updatemons(struct wl_listener *listener, void *data) { if ((c = focustop(m)) && c->isfullscreen) resize(c, m->m, 0); - config_head->state.x = m->m.x; config_head->state.y = m->m.y; From 99854aa4ea876ad25b387a266e490f8f12a09eae Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Thu, 30 Oct 2025 22:20:13 +0800 Subject: [PATCH 272/591] opt: optimize viewcrossmon --- src/dispatch/bind_define.h | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index 8c25efb9..5a092ccc 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -185,7 +185,7 @@ int focusmon(const Arg *arg) { return 0; } - if (!m || !m->wlr_output->enabled) + if (!m || !m->wlr_output->enabled || m == selmon) return 0; old_selmon_sel = selmon->sel; @@ -1423,10 +1423,7 @@ int viewtoright_have_client(const Arg *arg) { } int viewcrossmon(const Arg *arg) { - // Don't switch monitors if monitor is already focused - // This also prevents cursorwarp - if (!regex_match(arg->v, selmon->wlr_output->name)) - focusmon(&(Arg){.v = arg->v, .i = UNDIR}); + focusmon(&(Arg){.v = arg->v, .i = UNDIR}); view_in_mon(arg, true, selmon, true); return 0; } From cc6aa37170349f5331d0d6086f7c4281db3808ab Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Fri, 31 Oct 2025 10:42:38 +0800 Subject: [PATCH 273/591] update readme --- README.md | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 844ae900..1a8b4a52 100644 --- a/README.md +++ b/README.md @@ -119,6 +119,10 @@ sudo ninja -C build install ## Suggested Tools +### integrated component +- [dms-shell](https://github.com/AvengeMedia/DankMaterialShell) + +### Independent component - Application launcher (rofi, bemenu, wmenu, fuzzel) - Terminal emulator (foot, wezterm, alacritty, kitty, ghostty) - Status bar (waybar, eww, quickshell, ags), waybar is preferred @@ -139,13 +143,25 @@ sudo ninja -C build install ## My Dotfiles +### Daily - Dependencies ```bash yay -S rofi foot xdg-desktop-portal-wlr swaybg waybar wl-clip-persist cliphist wl-clipboard wlsunset xfce-polkit swaync pamixer wlr-dpms sway-audio-idle-inhibit-git swayidle dimland-git brightnessctl swayosd wlr-randr grim slurp satty swaylock-effects-git wlogout sox ``` -- use my config +### Dms +- Dependencies +```bash +yay -S foot xdg-desktop-portal-wlr swaybg wl-clip-persist cliphist wl-clipboard xfce-polkit sway-audio-idle-inhibit-git brightnessctl grim slurp satty matugen-bin dms-shell-git + +``` +- use my dms config + +```bash +git clone -b dms https://github.com/DreamMaoMao/mango-config.git ~/.config/mango +``` +- use my daily config ```bash git clone https://github.com/DreamMaoMao/mango-config.git ~/.config/mango From 17f0562cfb9859ef00f851e649dcfb3005f788ca Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Fri, 31 Oct 2025 14:15:17 +0800 Subject: [PATCH 274/591] opt: default ignore maximize request --- src/client/client.h | 2 +- src/mango.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/client/client.h b/src/client/client.h index 90be17e0..fd737309 100644 --- a/src/client/client.h +++ b/src/client/client.h @@ -374,7 +374,7 @@ static inline void client_set_tiled(Client *c, uint32_t edges) { wlr_xdg_toplevel_set_tiled(c->surface.xdg->toplevel, edges); } - if (!c->ignore_maximize && c->force_maximize) { + if (c->force_maximize) { wlr_xdg_toplevel_set_maximized(toplevel, edges != WLR_EDGE_NONE); } } diff --git a/src/mango.c b/src/mango.c index 2e290175..1431274c 100644 --- a/src/mango.c +++ b/src/mango.c @@ -3517,7 +3517,7 @@ void init_client_properties(Client *c) { c->no_force_center = 0; c->isnoborder = 0; c->isnosizehint = 0; - c->ignore_maximize = 0; + c->ignore_maximize = 1; c->ignore_minimize = 1; c->iscustomsize = 0; c->master_mfact_per = 0.0f; From 5bb149f84e1c75a4b271e98847a4a241dea5f9ec Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Fri, 31 Oct 2025 18:30:53 +0800 Subject: [PATCH 275/591] opt: Distinguish whether to maximize based on the client's request --- src/client/client.h | 12 ++++++++++++ src/mango.c | 46 +++++++++++---------------------------------- 2 files changed, 23 insertions(+), 35 deletions(-) diff --git a/src/client/client.h b/src/client/client.h index fd737309..a9f7313d 100644 --- a/src/client/client.h +++ b/src/client/client.h @@ -473,6 +473,18 @@ static inline bool client_request_minimize(Client *c, void *data) { return c->surface.xdg->toplevel->requested.minimized; } +static inline bool client_request_maximize(Client *c, void *data) { + +#ifdef XWAYLAND + if (client_is_x11(c)) { + struct wlr_xwayland_surface *surface = c->surface.xwayland; + return surface->maximized_vert || surface->maximized_horz; + } +#endif + + return c->surface.xdg->toplevel->requested.maximized; +} + static inline void client_set_size_bound(Client *c) { struct wlr_xdg_toplevel *toplevel; struct wlr_xdg_toplevel_state state; diff --git a/src/mango.c b/src/mango.c index 1431274c..17a93a5f 100644 --- a/src/mango.c +++ b/src/mango.c @@ -3650,31 +3650,22 @@ mapnotify(struct wl_listener *listener, void *data) { printstatus(); } -void // 0.5 custom -maximizenotify(struct wl_listener *listener, void *data) { - /* This event is raised when a client would like to maximize itself, - * typically because the user clicked on the maximize button on - * client-side decorations. dwl doesn't support maximization, but - * to conform to xdg-shell protocol we still must send a configure. - * Since xdg-shell protocol v5 we should ignore request of unsupported - * capabilities, just schedule a empty configure when the client uses <5 - * protocol version - * wlr_xdg_surface_schedule_configure() is used to send an empty reply. - */ - // Client *c = wl_container_of(listener, c, maximize); - // if (wl_resource_get_version(c->surface.xdg->toplevel->resource) - // < XDG_TOPLEVEL_WM_CAPABILITIES_SINCE_VERSION) - // wlr_xdg_surface_schedule_configure(c->surface.xdg); - // togglemaximizescreen(&(Arg){0}); +void maximizenotify(struct wl_listener *listener, void *data) { + Client *c = wl_container_of(listener, c, maximize); if (!c || !c->mon || c->iskilling || c->ignore_maximize) return; - if (c->ismaximizescreen || c->isfullscreen) - setmaximizescreen(c, 0); - else + if (!client_is_x11(c) && !c->surface.xdg->initialized) { + return; + } + + if (client_request_maximize(c, data)) { setmaximizescreen(c, 1); + } else { + setmaximizescreen(c, 0); + } } void unminimize(Client *c) { @@ -3718,22 +3709,7 @@ void set_minimized(Client *c) { wl_list_insert(clients.prev, &c->link); // 插入尾部 } -void // 0.5 custom -minimizenotify(struct wl_listener *listener, void *data) { - /* This event is raised when a client would like to maximize itself, - * typically because the user clicked on the maximize button on - * client-side decorations. dwl doesn't support maximization, but - * to conform to xdg-shell protocol we still must send a configure. - * Since xdg-shell protocol v5 we should ignore request of unsupported - * capabilities, just schedule a empty configure when the client uses <5 - * protocol version - * wlr_xdg_surface_schedule_configure() is used to send an empty reply. - */ - // Client *c = wl_container_of(listener, c, maximize); - // if (wl_resource_get_version(c->surface.xdg->toplevel->resource) - // < XDG_TOPLEVEL_WM_CAPABILITIES_SINCE_VERSION) - // wlr_xdg_surface_schedule_configure(c->surface.xdg); - // togglemaximizescreen(&(Arg){0}); +void minimizenotify(struct wl_listener *listener, void *data) { Client *c = wl_container_of(listener, c, minimize); From 8f706688debfd0b6bb2389e9f0895b30a9783cb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szymon=20R=C4=85czka?= <04_barista_pads@icloud.com> Date: Fri, 31 Oct 2025 22:33:38 +0100 Subject: [PATCH 276/591] feat: add smooth focus transition animation for opacity and border This adds animated transitions when switching focus between windows. Both window opacity and border color now fade smoothly using cubic bezier easing instead of changing instantly. Implementation: - Added animation_duration_focus config option (default 400ms) - Added animation_curve_focus for cubic bezier easing curve - Window opacity and border color animate together when focus changes - Uses existing animation infrastructure (baked bezier points) The feature is backwards compatible and can be disabled by setting animation_duration_focus=0 in config file. Changes affect 5 files with minimal additions to keep code clean. --- src/animation/client.h | 31 +++++++++++++++++++++++++++---- src/animation/common.h | 10 ++++++++++ src/config/parse_config.h | 19 +++++++++++++++++++ src/config/preset.h | 2 ++ src/mango.c | 31 ++++++++++++++++++++++++++++--- 5 files changed, 86 insertions(+), 7 deletions(-) diff --git a/src/animation/client.h b/src/animation/client.h index 249b7945..1c4e567f 100644 --- a/src/animation/client.h +++ b/src/animation/client.h @@ -1053,12 +1053,35 @@ bool client_draw_frame(Client *c) { if (!c || !client_surface(c)->mapped) return false; + // Animate focus transitions (opacity + border color) if (c->isfullscreen) { client_set_opacity(c, 1); - } else if (c == selmon->sel && !c->animation.running) { - client_set_opacity(c, c->focused_opacity); - } else if (!c->animation.running) { - client_set_opacity(c, c->unfocused_opacity); + c->current_opacity = 1; + c->target_opacity = 1; + } else if (c->opacity_animation_frames > 0 && c->opacity_animation_passed < c->opacity_animation_frames) { + float linear_progress = (float)c->opacity_animation_passed / c->opacity_animation_frames; + float eased_progress = find_animation_curve_at(linear_progress, FOCUS); + + // Animate opacity + float opacity_start = (c->target_opacity == c->focused_opacity) ? c->unfocused_opacity : c->focused_opacity; + c->current_opacity = opacity_start + (c->target_opacity - opacity_start) * eased_progress; + client_set_opacity(c, c->current_opacity); + + // Animate border color + bool focusing = (c->target_border_color[0] == focuscolor[0]); + float *border_start = focusing ? bordercolor : focuscolor; + for (int i = 0; i < 4; i++) { + c->current_border_color[i] = border_start[i] + (c->target_border_color[i] - border_start[i]) * eased_progress; + } + client_set_border_color(c, c->current_border_color); + + c->opacity_animation_passed++; + } else { + // Animation complete or disabled - apply target values + c->current_opacity = c->target_opacity; + client_set_opacity(c, c->current_opacity); + memcpy(c->current_border_color, c->target_border_color, sizeof(c->current_border_color)); + client_set_border_color(c, c->current_border_color); } if (!c->need_output_flush) diff --git a/src/animation/common.h b/src/animation/common.h index 70a595c0..2d283772 100644 --- a/src/animation/common.h +++ b/src/animation/common.h @@ -9,6 +9,8 @@ struct dvec2 calculate_animation_curve_at(double t, int type) { animation_curve = animation_curve_tag; } else if (type == CLOSE) { animation_curve = animation_curve_close; + } else if (type == FOCUS) { + animation_curve = animation_curve_focus; } else { animation_curve = animation_curve_move; } @@ -28,6 +30,8 @@ void init_baked_points(void) { baked_points_tag = calloc(BAKED_POINTS_COUNT, sizeof(*baked_points_tag)); baked_points_close = calloc(BAKED_POINTS_COUNT, sizeof(*baked_points_close)); + baked_points_focus = + calloc(BAKED_POINTS_COUNT, sizeof(*baked_points_focus)); for (unsigned int i = 0; i < BAKED_POINTS_COUNT; i++) { baked_points_move[i] = calculate_animation_curve_at( @@ -45,6 +49,10 @@ void init_baked_points(void) { baked_points_close[i] = calculate_animation_curve_at( (double)i / (BAKED_POINTS_COUNT - 1), CLOSE); } + for (unsigned int i = 0; i < BAKED_POINTS_COUNT; i++) { + baked_points_focus[i] = calculate_animation_curve_at( + (double)i / (BAKED_POINTS_COUNT - 1), FOCUS); + } } double find_animation_curve_at(double t, int type) { @@ -61,6 +69,8 @@ double find_animation_curve_at(double t, int type) { baked_points = baked_points_tag; } else if (type == CLOSE) { baked_points = baked_points_close; + } else if (type == FOCUS) { + baked_points = baked_points_focus; } else { baked_points = baked_points_move; } diff --git a/src/config/parse_config.h b/src/config/parse_config.h index 16b85e64..3c372ff1 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -178,10 +178,12 @@ typedef struct { uint32_t animation_duration_open; uint32_t animation_duration_tag; uint32_t animation_duration_close; + uint32_t animation_duration_focus; double animation_curve_move[4]; double animation_curve_open[4]; double animation_curve_tag[4]; double animation_curve_close[4]; + double animation_curve_focus[4]; int scroller_structs; float scroller_default_proportion; @@ -1132,6 +1134,8 @@ void parse_option(Config *config, char *key, char *value) { config->animation_duration_tag = atoi(value); } else if (strcmp(key, "animation_duration_close") == 0) { config->animation_duration_close = atoi(value); + } else if (strcmp(key, "animation_duration_focus") == 0) { + config->animation_duration_focus = atoi(value); } else if (strcmp(key, "animation_curve_move") == 0) { int num = parse_double_array(value, config->animation_curve_move, 4); if (num != 4) { @@ -1157,6 +1161,13 @@ void parse_option(Config *config, char *key, char *value) { "Error: Failed to parse animation_curve_close: %s\n", value); } + } else if (strcmp(key, "animation_curve_focus") == 0) { + int num = parse_double_array(value, config->animation_curve_focus, 4); + if (num != 4) { + fprintf(stderr, + "Error: Failed to parse animation_curve_focus: %s\n", + value); + } } else if (strcmp(key, "scroller_structs") == 0) { config->scroller_structs = atoi(value); } else if (strcmp(key, "scroller_default_proportion") == 0) { @@ -2595,6 +2606,8 @@ void override_config(void) { animation_duration_tag = CLAMP_INT(config.animation_duration_tag, 1, 50000); animation_duration_close = CLAMP_INT(config.animation_duration_close, 1, 50000); + animation_duration_focus = + CLAMP_INT(config.animation_duration_focus, 1, 50000); // 滚动布局设置 scroller_default_proportion = @@ -2727,6 +2740,8 @@ void override_config(void) { sizeof(animation_curve_tag)); memcpy(animation_curve_close, config.animation_curve_close, sizeof(animation_curve_close)); + memcpy(animation_curve_focus, config.animation_curve_focus, + sizeof(animation_curve_focus)); } void set_value_default() { @@ -2749,6 +2764,8 @@ void set_value_default() { animation_duration_tag; // Animation tag speed config.animation_duration_close = animation_duration_close; // Animation tag speed + config.animation_duration_focus = + animation_duration_focus; // Animation focus opacity speed /* appearance */ config.axis_bind_apply_timeout = @@ -2866,6 +2883,8 @@ void set_value_default() { sizeof(animation_curve_tag)); memcpy(config.animation_curve_close, animation_curve_close, sizeof(animation_curve_close)); + memcpy(config.animation_curve_focus, animation_curve_focus, + sizeof(animation_curve_focus)); memcpy(config.rootcolor, rootcolor, sizeof(rootcolor)); memcpy(config.bordercolor, bordercolor, sizeof(bordercolor)); diff --git a/src/config/preset.h b/src/config/preset.h index d9425a7e..b15860a4 100644 --- a/src/config/preset.h +++ b/src/config/preset.h @@ -25,10 +25,12 @@ uint32_t animation_duration_move = 500; // Animation move speed uint32_t animation_duration_open = 400; // Animation open speed uint32_t animation_duration_tag = 300; // Animation tag speed uint32_t animation_duration_close = 300; // Animation close speed +uint32_t animation_duration_focus = 400; // Animation focus opacity speed double animation_curve_move[4] = {0.46, 1.0, 0.29, 0.99}; // 动画曲线 double animation_curve_open[4] = {0.46, 1.0, 0.29, 0.99}; // 动画曲线 double animation_curve_tag[4] = {0.46, 1.0, 0.29, 0.99}; // 动画曲线 double animation_curve_close[4] = {0.46, 1.0, 0.29, 0.99}; // 动画曲线 +double animation_curve_focus[4] = {0.08, 0.82, 0.17, 1}; // 动画曲线 /* appearance */ unsigned int axis_bind_apply_timeout = 100; // 滚轮绑定动作的触发的时间间隔 diff --git a/src/mango.c b/src/mango.c index 17a93a5f..683b304f 100644 --- a/src/mango.c +++ b/src/mango.c @@ -161,7 +161,7 @@ enum { }; /* EWMH atoms */ #endif enum { UP, DOWN, LEFT, RIGHT, UNDIR }; /* smartmovewin */ -enum { NONE, OPEN, MOVE, CLOSE, TAG }; +enum { NONE, OPEN, MOVE, CLOSE, TAG, FOCUS }; enum { UNFOLD, FOLD, INVALIDFOLD }; enum { PREV, NEXT }; @@ -339,6 +339,12 @@ struct Client { int isunglobal; float focused_opacity; float unfocused_opacity; + float current_opacity; + float target_opacity; + unsigned int opacity_animation_frames; + unsigned int opacity_animation_passed; + float current_border_color[4]; + float target_border_color[4]; char oldmonname[128]; int noblur; double master_mfact_per, master_inner_per, stack_innder_per; @@ -777,6 +783,7 @@ struct dvec2 *baked_points_move; struct dvec2 *baked_points_open; struct dvec2 *baked_points_tag; struct dvec2 *baked_points_close; +struct dvec2 *baked_points_focus; static struct wl_event_source *hide_source; static bool cursor_hidden = false; @@ -3100,7 +3107,13 @@ void focusclient(Client *c, int lift) { // change border color c->isurgent = 0; - setborder_color(c); + // Start border color animation to focused + memcpy(c->target_border_color, focuscolor, sizeof(c->target_border_color)); + + // Start opacity animation to focused + c->target_opacity = c->focused_opacity; + c->opacity_animation_frames = (animation_duration_focus * 60) / 1000; // 60fps + c->opacity_animation_passed = 0; } if (c && !c->iskilling && c->foreign_toplevel) @@ -3128,7 +3141,13 @@ void focusclient(Client *c, int lift) { * probably other clients */ } else if (w && !client_is_unmanaged(w) && (!c || !client_wants_focus(c))) { - setborder_color(w); + // Start border color animation to unfocused + memcpy(w->target_border_color, bordercolor, sizeof(w->target_border_color)); + + // Start opacity animation to unfocused + w->target_opacity = w->unfocused_opacity; + w->opacity_animation_frames = (animation_duration_focus * 60) / 1000; // 60fps + w->opacity_animation_passed = 0; client_activate_surface(old_keyboard_focus_surface, 0); } @@ -3512,6 +3531,12 @@ void init_client_properties(Client *c) { c->fake_no_border = false; c->focused_opacity = focused_opacity; c->unfocused_opacity = unfocused_opacity; + c->current_opacity = unfocused_opacity; + c->target_opacity = unfocused_opacity; + c->opacity_animation_frames = 0; + c->opacity_animation_passed = 0; + memcpy(c->current_border_color, bordercolor, sizeof(c->current_border_color)); + memcpy(c->target_border_color, bordercolor, sizeof(c->target_border_color)); c->nofadein = 0; c->nofadeout = 0; c->no_force_center = 0; From ef92281b2a4ea7cb85bf6a342a9fa3b3e121ad51 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sat, 1 Nov 2025 14:29:53 +0800 Subject: [PATCH 277/591] opt: avoid crash when Incorrect Settings for keyboard layout --- src/dispatch/bind_define.h | 31 +++++++++++++++++++++++++------ src/mango.c | 3 +++ 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index 5a092ccc..21b38cf6 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -859,8 +859,9 @@ int switch_keyboard_layout(const Arg *arg) { } } - // 4. 直接修改 rules.layout(保持原有逻辑) + // 4. 安全地处理 rules.layout struct xkb_rule_names rules = xkb_rules; + // 验证规则是否有效 if (!check_keyboard_rules_validate(&rules)) { wlr_log(WLR_ERROR, @@ -868,15 +869,27 @@ int switch_keyboard_layout(const Arg *arg) { rules = xkb_default_rules; } - char *layout_buf = (char *)rules.layout; // 假设这是可修改的 + // 安全地处理 layout 字符串 + const char *current_layout = rules.layout; + if (!current_layout || strlen(current_layout) == 0) { + wlr_log(WLR_INFO, "Using default layout 'us'"); + current_layout = "us"; + } - // 清空原有内容(安全方式) - unsigned int layout_buf_size = strlen(layout_buf) + 1; - memset(layout_buf, 0, layout_buf_size); + // 创建足够大的缓冲区来构建新的布局字符串 + unsigned int layout_buf_size = + 1024; // 使用固定大小,避免依赖可能为NULL的字符串 + char *layout_buf = calloc(layout_buf_size, sizeof(char)); + if (!layout_buf) { + wlr_log(WLR_ERROR, "Failed to allocate layout buffer"); + goto cleanup_layouts; + } // 构建新的布局字符串 for (int i = 0; i < num_layouts; i++) { const char *layout = layout_ids[(next + i) % num_layouts]; + if (!layout) + continue; if (i > 0) { strncat(layout_buf, ",", layout_buf_size - strlen(layout_buf) - 1); @@ -897,13 +910,16 @@ int switch_keyboard_layout(const Arg *arg) { } } + // 更新 rules 结构体 + rules.layout = layout_buf; + // 5. 创建新 keymap struct xkb_keymap *new_keymap = xkb_keymap_new_from_names(context, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS); if (!new_keymap) { wlr_log(WLR_ERROR, "Failed to create keymap for layouts: %s", rules.layout); - goto cleanup_layouts; + goto cleanup_layout_buf; } // 6. 应用新 keymap @@ -922,6 +938,9 @@ int switch_keyboard_layout(const Arg *arg) { // 8. 清理资源 xkb_keymap_unref(new_keymap); +cleanup_layout_buf: + free(layout_buf); + cleanup_layouts: free(layout_ids); diff --git a/src/mango.c b/src/mango.c index 17a93a5f..41ddd2c4 100644 --- a/src/mango.c +++ b/src/mango.c @@ -4546,6 +4546,9 @@ bool check_keyboard_rules_validate(struct xkb_rule_names *rules) { return false; } + if (!rules->layout || strlen(rules->layout) == 0) + return false; + struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); if (!context) { wlr_log(WLR_ERROR, "Failed to create XKB context for validation"); From 0ab38c6aa6383343262e8688e6c087dda7f63dfe Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sat, 1 Nov 2025 14:39:32 +0800 Subject: [PATCH 278/591] opt: optimize null check in get_next_stack_client --- src/fetch/client.h | 16 ++++++++++++++-- src/mango.c | 2 +- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/fetch/client.h b/src/fetch/client.h index f0a4868e..ce93a3bc 100644 --- a/src/fetch/client.h +++ b/src/fetch/client.h @@ -340,21 +340,33 @@ Client *focustop(Monitor *m) { } Client *get_next_stack_client(Client *c, bool reverse) { + if (!c || !c->mon) + return NULL; // 添加输入检查 + Client *next = NULL; if (reverse) { wl_list_for_each_reverse(next, &c->link, link) { + if (!next) + continue; // 安全检查 + if (c->mon->has_visible_fullscreen_client && !next->isfloating && !next->isfullscreen) continue; - if (VISIBLEON(next, c->mon) && next != c) + + // 添加更安全的 VISIBLEON 检查 + if (next != c && next->mon && VISIBLEON(next, c->mon)) return next; } } else { wl_list_for_each(next, &c->link, link) { + if (!next) + continue; // 安全检查 + if (c->mon->has_visible_fullscreen_client && !next->isfloating && !next->isfullscreen) continue; - if (VISIBLEON(next, c->mon) && next != c) + + if (next != c && next->mon && VISIBLEON(next, c->mon)) return next; } } diff --git a/src/mango.c b/src/mango.c index 41ddd2c4..31df40c6 100644 --- a/src/mango.c +++ b/src/mango.c @@ -104,7 +104,7 @@ (A && !(A)->isfloating && !(A)->isminied && !(A)->iskilling && \ !(A)->ismaximizescreen && !(A)->isfullscreen) #define VISIBLEON(C, M) \ - ((M) && (C)->mon == (M) && ((C)->tags & (M)->tagset[(M)->seltags])) + ((C) && (M) && (C)->mon == (M) && ((C)->tags & (M)->tagset[(M)->seltags])) #define LENGTH(X) (sizeof X / sizeof X[0]) #define END(A) ((A) + LENGTH(A)) #define TAGMASK ((1 << LENGTH(tags)) - 1) From 6fdb9627861ac5617f7fe980a5eb72faa06775b0 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sat, 1 Nov 2025 12:08:39 +0800 Subject: [PATCH 279/591] fix: fix focus animation error --- config.conf | 2 + src/animation/client.h | 171 ++++++++++++++++++++++++++++------------- src/config/preset.h | 4 +- src/fetch/client.h | 18 +++++ src/mango.c | 90 +++++++++------------- 5 files changed, 174 insertions(+), 111 deletions(-) diff --git a/config.conf b/config.conf index 353bdab3..59e4631d 100644 --- a/config.conf +++ b/config.conf @@ -42,10 +42,12 @@ animation_duration_move=500 animation_duration_open=400 animation_duration_tag=350 animation_duration_close=800 +animation_duration_focus=0 animation_curve_open=0.46,1.0,0.29,1 animation_curve_move=0.46,1.0,0.29,1 animation_curve_tag=0.46,1.0,0.29,1 animation_curve_close=0.08,0.92,0,1 +animation_curve_focus=0.46,1.0,0.29,1 # Scroller Layout Setting scroller_structs=20 diff --git a/src/animation/client.h b/src/animation/client.h index 1c4e567f..671b8991 100644 --- a/src/animation/client.h +++ b/src/animation/client.h @@ -225,12 +225,6 @@ void scene_buffer_apply_effect(struct wlr_scene_buffer *buffer, int sx, int sy, wlr_scene_buffer_set_corner_radius(buffer, border_radius, buffer_data->corner_location); - - float target_opacity = buffer_data->percent + fadein_begin_opacity; - if (target_opacity > buffer_data->opacity) { - target_opacity = buffer_data->opacity; - } - wlr_scene_buffer_set_opacity(buffer, target_opacity); } void buffer_set_effect(Client *c, BufferData data) { @@ -517,7 +511,6 @@ void client_apply_clip(Client *c, float factor) { bool should_render_client_surface = false; struct ivec2 offset; BufferData buffer_data; - float opacity, percent; enum corner_location current_corner_location = set_client_corner_location(c); @@ -537,29 +530,17 @@ void client_apply_clip(Client *c, float factor) { apply_border(c); client_draw_shadow(c); - opacity = c->isfullscreen ? 1 - : c == selmon->sel ? c->focused_opacity - : c->unfocused_opacity; - if (clip_box.width <= 0 || clip_box.height <= 0) { return; } wlr_scene_subsurface_tree_set_clip(&c->scene_surface->node, &clip_box); buffer_set_effect(c, (BufferData){1.0f, 1.0f, clip_box.width, - clip_box.height, opacity, opacity, + clip_box.height, current_corner_location, true}); return; } - percent = - c->animation.action == OPEN && animation_fade_in && !c->nofadein - ? (double)c->animation.passed_frames / c->animation.total_frames - : 1.0; - opacity = c->isfullscreen ? 1 - : c == selmon->sel ? c->focused_opacity - : c->unfocused_opacity; - // 获取窗口动画实时位置矩形 unsigned int width, height; client_actual_size(c, &width, &height); @@ -614,8 +595,6 @@ void client_apply_clip(Client *c, float factor) { buffer_data.width = clip_box.width; buffer_data.height = clip_box.height; buffer_data.corner_location = current_corner_location; - buffer_data.percent = percent; - buffer_data.opacity = opacity; if (factor == 1.0) { buffer_data.width_scale = 1.0; @@ -1048,45 +1027,128 @@ bool client_draw_fadeout_frame(Client *c) { return true; } +void client_set_focused_opacity_animation(Client *c) { + float *border_color = get_border_color(c); + memcpy(c->opacity_animation.target_border_color, border_color, + sizeof(c->opacity_animation.target_border_color)); + c->opacity_animation.target_opacity = c->focused_opacity; + c->opacity_animation.total_frames = + animation_duration_focus / all_output_frame_duration_ms(); + c->opacity_animation.passed_frames = 0; + if (c->opacity_animation.running) { + memcpy(c->opacity_animation.initial_border_color, + c->opacity_animation.current_border_color, + sizeof(c->opacity_animation.initial_border_color)); + c->opacity_animation.initial_opacity = + c->opacity_animation.current_opacity; + } else { + memcpy(c->opacity_animation.initial_border_color, border_color, + sizeof(c->opacity_animation.initial_border_color)); + c->opacity_animation.initial_opacity = c->unfocused_opacity; + } + c->opacity_animation.running = true; +} + +void cleint_set_unfocused_opacity_animation(Client *c) { + // Start border color animation to unfocused + float *border_color = get_border_color(c); + memcpy(c->opacity_animation.target_border_color, border_color, + sizeof(c->opacity_animation.target_border_color)); + // Start opacity animation to unfocused + c->opacity_animation.target_opacity = c->unfocused_opacity; + c->opacity_animation.total_frames = + animation_duration_focus / all_output_frame_duration_ms(); + c->opacity_animation.passed_frames = 0; + + if (c->opacity_animation.running) { + memcpy(c->opacity_animation.initial_border_color, + c->opacity_animation.current_border_color, + sizeof(c->opacity_animation.initial_border_color)); + c->opacity_animation.initial_opacity = + c->opacity_animation.current_opacity; + } else { + memcpy(c->opacity_animation.initial_border_color, border_color, + sizeof(c->opacity_animation.initial_border_color)); + c->opacity_animation.initial_opacity = c->focused_opacity; + } + + c->opacity_animation.running = true; +} + +bool client_apply_focus_opacity(Client *c) { + // Animate focus transitions (opacity + border color) + float *border_color = get_border_color(c); + if (c->isfullscreen) { + c->opacity_animation.running = false; + client_set_opacity(c, 1); + } else if (c->animation.running && c->animation.action == OPEN) { + c->opacity_animation.running = false; + float percent = + animation_fade_in && !c->nofadein + ? (double)c->animation.passed_frames / c->animation.total_frames + : 1.0; + float opacity = c->isfullscreen ? 1 + : c == selmon->sel ? c->focused_opacity + : c->unfocused_opacity; + + float target_opacity = percent + fadein_begin_opacity; + if (target_opacity > opacity) { + target_opacity = opacity; + } + client_set_opacity(c, target_opacity); + } else if (animations && c->opacity_animation.running) { + float linear_progress = (float)c->opacity_animation.passed_frames / + c->opacity_animation.total_frames; + float eased_progress = find_animation_curve_at(linear_progress, FOCUS); + + c->opacity_animation.current_opacity = + c->opacity_animation.initial_opacity + + (c->opacity_animation.target_opacity - + c->opacity_animation.initial_opacity) * + eased_progress; + client_set_opacity(c, c->opacity_animation.current_opacity); + + // Animate border color + for (int i = 0; i < 4; i++) { + c->opacity_animation.current_border_color[i] = + c->opacity_animation.initial_border_color[i] + + (c->opacity_animation.target_border_color[i] - + c->opacity_animation.initial_border_color[i]) * + eased_progress; + } + client_set_border_color(c, c->opacity_animation.current_border_color); + if (linear_progress == 1.0f) { + c->opacity_animation.running = false; + } else { + c->opacity_animation.passed_frames++; + return true; + } + } else if (c == selmon->sel) { + c->opacity_animation.running = false; + c->opacity_animation.current_opacity = c->focused_opacity; + memcpy(c->opacity_animation.current_border_color, border_color, + sizeof(c->opacity_animation.current_border_color)); + client_set_opacity(c, c->focused_opacity); + } else { + c->opacity_animation.running = false; + c->opacity_animation.current_opacity = c->unfocused_opacity; + memcpy(c->opacity_animation.current_border_color, border_color, + sizeof(c->opacity_animation.current_border_color)); + client_set_opacity(c, c->unfocused_opacity); + } + + return false; +} + bool client_draw_frame(Client *c) { if (!c || !client_surface(c)->mapped) return false; - // Animate focus transitions (opacity + border color) - if (c->isfullscreen) { - client_set_opacity(c, 1); - c->current_opacity = 1; - c->target_opacity = 1; - } else if (c->opacity_animation_frames > 0 && c->opacity_animation_passed < c->opacity_animation_frames) { - float linear_progress = (float)c->opacity_animation_passed / c->opacity_animation_frames; - float eased_progress = find_animation_curve_at(linear_progress, FOCUS); - - // Animate opacity - float opacity_start = (c->target_opacity == c->focused_opacity) ? c->unfocused_opacity : c->focused_opacity; - c->current_opacity = opacity_start + (c->target_opacity - opacity_start) * eased_progress; - client_set_opacity(c, c->current_opacity); - - // Animate border color - bool focusing = (c->target_border_color[0] == focuscolor[0]); - float *border_start = focusing ? bordercolor : focuscolor; - for (int i = 0; i < 4; i++) { - c->current_border_color[i] = border_start[i] + (c->target_border_color[i] - border_start[i]) * eased_progress; - } - client_set_border_color(c, c->current_border_color); - - c->opacity_animation_passed++; - } else { - // Animation complete or disabled - apply target values - c->current_opacity = c->target_opacity; - client_set_opacity(c, c->current_opacity); - memcpy(c->current_border_color, c->target_border_color, sizeof(c->current_border_color)); - client_set_border_color(c, c->current_border_color); + if (!c->need_output_flush) { + return client_apply_focus_opacity(c); } - if (!c->need_output_flush) - return false; - if (animations && c->animation.running) { client_animation_next_tick(c); } else { @@ -1097,5 +1159,6 @@ bool client_draw_frame(Client *c) { client_apply_clip(c, 1.0); c->need_output_flush = false; } + client_apply_focus_opacity(c); return true; } diff --git a/src/config/preset.h b/src/config/preset.h index b15860a4..39cf5096 100644 --- a/src/config/preset.h +++ b/src/config/preset.h @@ -25,12 +25,12 @@ uint32_t animation_duration_move = 500; // Animation move speed uint32_t animation_duration_open = 400; // Animation open speed uint32_t animation_duration_tag = 300; // Animation tag speed uint32_t animation_duration_close = 300; // Animation close speed -uint32_t animation_duration_focus = 400; // Animation focus opacity speed +uint32_t animation_duration_focus = 0; // Animation focus opacity speed double animation_curve_move[4] = {0.46, 1.0, 0.29, 0.99}; // 动画曲线 double animation_curve_open[4] = {0.46, 1.0, 0.29, 0.99}; // 动画曲线 double animation_curve_tag[4] = {0.46, 1.0, 0.29, 0.99}; // 动画曲线 double animation_curve_close[4] = {0.46, 1.0, 0.29, 0.99}; // 动画曲线 -double animation_curve_focus[4] = {0.08, 0.82, 0.17, 1}; // 动画曲线 +double animation_curve_focus[4] = {0.46, 1.0, 0.29, 0.99}; // 动画曲线 /* appearance */ unsigned int axis_bind_apply_timeout = 100; // 滚轮绑定动作的触发的时间间隔 diff --git a/src/fetch/client.h b/src/fetch/client.h index f0a4868e..cfc5232b 100644 --- a/src/fetch/client.h +++ b/src/fetch/client.h @@ -360,3 +360,21 @@ Client *get_next_stack_client(Client *c, bool reverse) { } return NULL; } + +float *get_border_color(Client *c) { + if (c->isurgent) { + return urgentcolor; + } else if (c->is_in_scratchpad && selmon && c == selmon->sel) { + return scratchpadcolor; + } else if (c->isglobal && selmon && c == selmon->sel) { + return globalcolor; + } else if (c->isoverlay && selmon && c == selmon->sel) { + return overlaycolor; + } else if (c->ismaximizescreen && selmon && c == selmon->sel) { + return maximizescreencolor; + } else if (selmon && c == selmon->sel) { + return focuscolor; + } else { + return bordercolor; + } +} \ No newline at end of file diff --git a/src/mango.c b/src/mango.c index 683b304f..b125e616 100644 --- a/src/mango.c +++ b/src/mango.c @@ -104,7 +104,7 @@ (A && !(A)->isfloating && !(A)->isminied && !(A)->iskilling && \ !(A)->ismaximizescreen && !(A)->isfullscreen) #define VISIBLEON(C, M) \ - ((M) && (C)->mon == (M) && ((C)->tags & (M)->tagset[(M)->seltags])) + ((C) && (M) && (C)->mon == (M) && ((C)->tags & (M)->tagset[(M)->seltags])) #define LENGTH(X) (sizeof X / sizeof X[0]) #define END(A) ((A) + LENGTH(A)) #define TAGMASK ((1 << LENGTH(tags)) - 1) @@ -239,13 +239,23 @@ struct dwl_animation { int action; }; +struct dwl_opacity_animation { + bool running; + float current_opacity; + float target_opacity; + float initial_opacity; + unsigned int total_frames; + unsigned int passed_frames; + float current_border_color[4]; + float target_border_color[4]; + float initial_border_color[4]; +}; + typedef struct { float width_scale; float height_scale; int width; int height; - double percent; - float opacity; enum corner_location corner_location; bool should_scale; } BufferData; @@ -324,6 +334,7 @@ struct Client { float scroller_proportion; bool need_output_flush; struct dwl_animation animation; + struct dwl_opacity_animation opacity_animation; int isterm, noswallow; int allow_csd; int force_maximize; @@ -339,12 +350,6 @@ struct Client { int isunglobal; float focused_opacity; float unfocused_opacity; - float current_opacity; - float target_opacity; - unsigned int opacity_animation_frames; - unsigned int opacity_animation_passed; - float current_border_color[4]; - float target_border_color[4]; char oldmonname[128]; int noblur; double master_mfact_per, master_inner_per, stack_innder_per; @@ -699,6 +704,7 @@ static void resize_tile_client(Client *grabc, bool isdrag, int offsetx, static void refresh_monitors_workspaces_status(Monitor *m); static void init_client_properties(Client *c); static bool check_keyboard_rules_validate(struct xkb_rule_names *rules); +static float *get_border_color(Client *c); #include "data/static_keymap.h" #include "dispatch/bind_declare.h" @@ -3091,6 +3097,12 @@ void focusclient(Client *c, int lift) { selmon->prevsel = selmon->sel; selmon->sel = c; + if (selmon->prevsel && !selmon->prevsel->iskilling) { + cleint_set_unfocused_opacity_animation(selmon->prevsel); + } + + client_set_focused_opacity_animation(c); + // decide whether need to re-arrange if (c && selmon->prevsel && @@ -3107,13 +3119,6 @@ void focusclient(Client *c, int lift) { // change border color c->isurgent = 0; - // Start border color animation to focused - memcpy(c->target_border_color, focuscolor, sizeof(c->target_border_color)); - - // Start opacity animation to focused - c->target_opacity = c->focused_opacity; - c->opacity_animation_frames = (animation_duration_focus * 60) / 1000; // 60fps - c->opacity_animation_passed = 0; } if (c && !c->iskilling && c->foreign_toplevel) @@ -3141,24 +3146,17 @@ void focusclient(Client *c, int lift) { * probably other clients */ } else if (w && !client_is_unmanaged(w) && (!c || !client_wants_focus(c))) { - // Start border color animation to unfocused - memcpy(w->target_border_color, bordercolor, sizeof(w->target_border_color)); - - // Start opacity animation to unfocused - w->target_opacity = w->unfocused_opacity; - w->opacity_animation_frames = (animation_duration_focus * 60) / 1000; // 60fps - w->opacity_animation_passed = 0; - client_activate_surface(old_keyboard_focus_surface, 0); } } printstatus(); if (!c) { - /* With no client, all we have left is to clear focus */ - if (selmon && selmon->sel) - selmon->sel = - NULL; // 这个很关键,因为很多地方用到当前窗口做计算,不重置成NULL就会到处有野指针 + + if (selmon && selmon->sel && + (!VISIBLEON(selmon->sel, selmon) || selmon->sel->iskilling || + !client_surface(selmon->sel)->mapped)) + selmon->sel = NULL; // clear text input focus state dwl_im_relay_set_focus(dwl_input_method_relay, NULL); @@ -3531,12 +3529,6 @@ void init_client_properties(Client *c) { c->fake_no_border = false; c->focused_opacity = focused_opacity; c->unfocused_opacity = unfocused_opacity; - c->current_opacity = unfocused_opacity; - c->target_opacity = unfocused_opacity; - c->opacity_animation_frames = 0; - c->opacity_animation_passed = 0; - memcpy(c->current_border_color, bordercolor, sizeof(c->current_border_color)); - memcpy(c->target_border_color, bordercolor, sizeof(c->target_border_color)); c->nofadein = 0; c->nofadeout = 0; c->no_force_center = 0; @@ -4161,23 +4153,11 @@ void requeststartdrag(struct wl_listener *listener, void *data) { void setborder_color(Client *c) { if (!c || !c->mon) return; - if (c->isurgent) { - client_set_border_color(c, urgentcolor); - return; - } - if (c->is_in_scratchpad && selmon && c == selmon->sel) { - client_set_border_color(c, scratchpadcolor); - } else if (c->isglobal && selmon && c == selmon->sel) { - client_set_border_color(c, globalcolor); - } else if (c->isoverlay && selmon && c == selmon->sel) { - client_set_border_color(c, overlaycolor); - } else if (c->ismaximizescreen && selmon && c == selmon->sel) { - client_set_border_color(c, maximizescreencolor); - } else if (selmon && c == selmon->sel) { - client_set_border_color(c, focuscolor); - } else { - client_set_border_color(c, bordercolor); - } + + float *border_color = get_border_color(c); + memcpy(c->opacity_animation.target_border_color, border_color, + sizeof(c->opacity_animation.target_border_color)); + client_set_border_color(c, border_color); } void exchange_two_client(Client *c1, Client *c2) { @@ -5485,9 +5465,9 @@ urgent(struct wl_listener *listener, void *data) { view_in_mon(&(Arg){.ui = c->tags}, true, c->mon, true); focusclient(c, 1); } else if (c != focustop(selmon)) { - if (client_surface(c)->mapped) - client_set_border_color(c, urgentcolor); c->isurgent = 1; + if (client_surface(c)->mapped) + setborder_color(c); printstatus(); } } @@ -5636,7 +5616,7 @@ void activatex11(struct wl_listener *listener, void *data) { } else if (c != focustop(selmon)) { c->isurgent = 1; if (client_surface(c)->mapped) - client_set_border_color(c, urgentcolor); + setborder_color(c); } if (need_arrange) { @@ -5718,7 +5698,7 @@ void sethints(struct wl_listener *listener, void *data) { printstatus(); if (c->isurgent && surface && surface->mapped) - client_set_border_color(c, urgentcolor); + setborder_color(c); } void xwaylandready(struct wl_listener *listener, void *data) { From d05a2b5b00dbb802aad7ec9e557aa01b5603bbfe Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sat, 1 Nov 2025 16:50:45 +0800 Subject: [PATCH 280/591] opt: optimize config reload fresh --- src/config/parse_config.h | 1 + src/ext-protocol/ext-workspace.h | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/src/config/parse_config.h b/src/config/parse_config.h index 16b85e64..4ee011ae 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -3177,5 +3177,6 @@ void reset_option(void) { int reload_config(const Arg *arg) { parse_config(); reset_option(); + printstatus(); return 0; } diff --git a/src/ext-protocol/ext-workspace.h b/src/ext-protocol/ext-workspace.h index 6e1a747b..61e36da3 100644 --- a/src/ext-protocol/ext-workspace.h +++ b/src/ext-protocol/ext-workspace.h @@ -134,6 +134,10 @@ void dwl_ext_workspace_printstatus(Monitor *m) { if (!w->m->pertag->no_hide[w->tag]) wlr_ext_workspace_handle_v1_set_hidden(w->ext_workspace, true); + else { + wlr_ext_workspace_handle_v1_set_hidden(w->ext_workspace, + false); + } } if ((m->tagset[m->seltags] & (1 << (w->tag - 1)) & TAGMASK) || From 3ed36a6ea6564af8a2dcb1e71fe42404ad48f48c Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sat, 1 Nov 2025 19:06:04 +0800 Subject: [PATCH 281/591] break change: remove switch_keyboard_layout dispatch --- src/config/parse_config.h | 2 - src/dispatch/bind_declare.h | 1 - src/dispatch/bind_define.h | 137 ------------------------------------ src/mango.c | 69 +----------------- 4 files changed, 3 insertions(+), 206 deletions(-) diff --git a/src/config/parse_config.h b/src/config/parse_config.h index 4ee011ae..405ae937 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -928,8 +928,6 @@ FuncType parse_func_name(char *func_name, Arg *arg, char *arg_value, (*arg).v = strdup(arg_value); } else if (strcmp(func_name, "switch_layout") == 0) { func = switch_layout; - } else if (strcmp(func_name, "switch_keyboard_layout") == 0) { - func = switch_keyboard_layout; } else if (strcmp(func_name, "togglefloating") == 0) { func = togglefloating; } else if (strcmp(func_name, "togglefullscreen") == 0) { diff --git a/src/dispatch/bind_declare.h b/src/dispatch/bind_declare.h index b02ccf99..a1dfbad3 100644 --- a/src/dispatch/bind_declare.h +++ b/src/dispatch/bind_declare.h @@ -27,7 +27,6 @@ int spawn_on_empty(const Arg *arg); int setkeymode(const Arg *arg); int setlayout(const Arg *arg); int switch_layout(const Arg *arg); -int switch_keyboard_layout(const Arg *arg); int setmfact(const Arg *arg); int quit(const Arg *arg); int moveresize(const Arg *arg); diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index 21b38cf6..7d39186c 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -814,143 +814,6 @@ int spawn_on_empty(const Arg *arg) { return 0; } -int switch_keyboard_layout(const Arg *arg) { - if (!kb_group || !kb_group->wlr_group || !seat) { - wlr_log(WLR_ERROR, "Invalid keyboard group or seat"); - return 0; - } - - struct wlr_keyboard *keyboard = &kb_group->wlr_group->keyboard; - if (!keyboard || !keyboard->keymap) { - wlr_log(WLR_ERROR, "Invalid keyboard or keymap"); - return 0; - } - - // 1. 获取当前布局和计算下一个布局 - xkb_layout_index_t current = xkb_state_serialize_layout( - keyboard->xkb_state, XKB_STATE_LAYOUT_EFFECTIVE); - const int num_layouts = xkb_keymap_num_layouts(keyboard->keymap); - if (num_layouts < 2) { - wlr_log(WLR_INFO, "Only one layout available"); - return 0; - } - xkb_layout_index_t next = (current + 1) % num_layouts; - - // 2. 创建上下文 - struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); - if (!context) { - wlr_log(WLR_ERROR, "Failed to create XKB context"); - return 0; - } - - // 3. 分配并获取布局缩写 - const char **layout_ids = calloc(num_layouts, sizeof(char *)); - if (!layout_ids) { - wlr_log(WLR_ERROR, "Failed to allocate layout IDs"); - goto cleanup_context; - } - - for (int i = 0; i < num_layouts; i++) { - layout_ids[i] = - get_layout_abbr(xkb_keymap_layout_get_name(keyboard->keymap, i)); - if (!layout_ids[i]) { - wlr_log(WLR_ERROR, "Failed to get layout abbreviation"); - goto cleanup_layouts; - } - } - - // 4. 安全地处理 rules.layout - struct xkb_rule_names rules = xkb_rules; - - // 验证规则是否有效 - if (!check_keyboard_rules_validate(&rules)) { - wlr_log(WLR_ERROR, - "Keyboard rules validation failed, skipping layout reset"); - rules = xkb_default_rules; - } - - // 安全地处理 layout 字符串 - const char *current_layout = rules.layout; - if (!current_layout || strlen(current_layout) == 0) { - wlr_log(WLR_INFO, "Using default layout 'us'"); - current_layout = "us"; - } - - // 创建足够大的缓冲区来构建新的布局字符串 - unsigned int layout_buf_size = - 1024; // 使用固定大小,避免依赖可能为NULL的字符串 - char *layout_buf = calloc(layout_buf_size, sizeof(char)); - if (!layout_buf) { - wlr_log(WLR_ERROR, "Failed to allocate layout buffer"); - goto cleanup_layouts; - } - - // 构建新的布局字符串 - for (int i = 0; i < num_layouts; i++) { - const char *layout = layout_ids[(next + i) % num_layouts]; - if (!layout) - continue; - - if (i > 0) { - strncat(layout_buf, ",", layout_buf_size - strlen(layout_buf) - 1); - } - - if (strchr(layout, ',')) { - // 处理包含逗号的布局名 - char *quoted = malloc(strlen(layout) + 3); - if (quoted) { - snprintf(quoted, strlen(layout) + 3, "\"%s\"", layout); - strncat(layout_buf, quoted, - layout_buf_size - strlen(layout_buf) - 1); - free(quoted); - } - } else { - strncat(layout_buf, layout, - layout_buf_size - strlen(layout_buf) - 1); - } - } - - // 更新 rules 结构体 - rules.layout = layout_buf; - - // 5. 创建新 keymap - struct xkb_keymap *new_keymap = - xkb_keymap_new_from_names(context, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS); - if (!new_keymap) { - wlr_log(WLR_ERROR, "Failed to create keymap for layouts: %s", - rules.layout); - goto cleanup_layout_buf; - } - - // 6. 应用新 keymap - unsigned int depressed = keyboard->modifiers.depressed; - unsigned int latched = keyboard->modifiers.latched; - unsigned int locked = keyboard->modifiers.locked; - - wlr_keyboard_set_keymap(keyboard, new_keymap); - wlr_keyboard_notify_modifiers(keyboard, depressed, latched, locked, 0); - keyboard->modifiers.group = 0; - - // 7. 更新 seat - wlr_seat_set_keyboard(seat, keyboard); - wlr_seat_keyboard_notify_modifiers(seat, &keyboard->modifiers); - - // 8. 清理资源 - xkb_keymap_unref(new_keymap); - -cleanup_layout_buf: - free(layout_buf); - -cleanup_layouts: - free(layout_ids); - -cleanup_context: - xkb_context_unref(context); - - printstatus(); - return 0; -} - int switch_layout(const Arg *arg) { int jk, ji; diff --git a/src/mango.c b/src/mango.c index 31df40c6..2056aeda 100644 --- a/src/mango.c +++ b/src/mango.c @@ -692,7 +692,6 @@ static void resize_tile_client(Client *grabc, bool isdrag, int offsetx, int offsety, unsigned int time); static void refresh_monitors_workspaces_status(Monitor *m); static void init_client_properties(Client *c); -static bool check_keyboard_rules_validate(struct xkb_rule_names *rules); #include "data/static_keymap.h" #include "dispatch/bind_declare.h" @@ -2371,18 +2370,9 @@ KeyboardGroup *createkeyboardgroup(void) { group->wlr_group = wlr_keyboard_group_create(); group->wlr_group->data = group; - // 4. 直接修改 rules.layout(保持原有逻辑) - struct xkb_rule_names rules = xkb_rules; - // 验证规则是否有效 - if (!check_keyboard_rules_validate(&rules)) { - wlr_log(WLR_ERROR, - "Keyboard rules validation failed, skipping layout reset"); - rules = xkb_default_rules; - } - /* Prepare an XKB keymap and assign it to the keyboard group. */ context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); - if (!(keymap = xkb_keymap_new_from_names(context, &rules, + if (!(keymap = xkb_keymap_new_from_names(context, &xkb_rules, XKB_KEYMAP_COMPILE_NO_FLAGS))) die("failed to compile keymap"); @@ -4539,49 +4529,6 @@ void setgaps(int oh, int ov, int ih, int iv) { arrange(selmon, false); } -// 验证键盘规则是否有效 -bool check_keyboard_rules_validate(struct xkb_rule_names *rules) { - if (!rules) { - wlr_log(WLR_ERROR, "Keyboard rules are NULL"); - return false; - } - - if (!rules->layout || strlen(rules->layout) == 0) - return false; - - struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); - if (!context) { - wlr_log(WLR_ERROR, "Failed to create XKB context for validation"); - return false; - } - - bool valid = false; - struct xkb_keymap *test_keymap = - xkb_keymap_new_from_names(context, rules, XKB_KEYMAP_COMPILE_NO_FLAGS); - - if (test_keymap) { - // 检查keymap是否至少有一个布局 - if (xkb_keymap_num_layouts(test_keymap) > 0) { - valid = true; - } else { - wlr_log(WLR_ERROR, "Keymap has no layouts"); - } - xkb_keymap_unref(test_keymap); - } else { - wlr_log(WLR_ERROR, - "Invalid keyboard rules: rules=%s, model=%s, layout=%s, " - "variant=%s, options=%s", - rules->rules ? rules->rules : "NULL", - rules->model ? rules->model : "NULL", - rules->layout ? rules->layout : "NULL", - rules->variant ? rules->variant : "NULL", - rules->options ? rules->options : "NULL"); - } - - xkb_context_unref(context); - return valid; -} - void reset_keyboard_layout(void) { if (!kb_group || !kb_group->wlr_group || !seat) { wlr_log(WLR_ERROR, "Invalid keyboard group or seat"); @@ -4603,16 +4550,6 @@ void reset_keyboard_layout(void) { return; } - // Keep the same rules but just reapply them - struct xkb_rule_names rules = xkb_rules; - - // 验证规则是否有效 - if (!check_keyboard_rules_validate(&rules)) { - wlr_log(WLR_ERROR, - "Keyboard rules validation failed, skipping layout reset"); - rules = xkb_default_rules; - } - // Create context struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); if (!context) { @@ -4621,8 +4558,8 @@ void reset_keyboard_layout(void) { } // 现在安全地创建真正的keymap - struct xkb_keymap *new_keymap = - xkb_keymap_new_from_names(context, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS); + struct xkb_keymap *new_keymap = xkb_keymap_new_from_names( + context, &xkb_rules, XKB_KEYMAP_COMPILE_NO_FLAGS); if (!new_keymap) { // 理论上这里不应该失败,因为前面已经验证过了 wlr_log(WLR_ERROR, From 78f7cb40c7ffd56ca8e7764ac5f56b37e5f26579 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sat, 1 Nov 2025 19:24:37 +0800 Subject: [PATCH 282/591] opt: optimize animaiton frame fresh --- src/animation/client.h | 4 ++-- src/animation/common.h | 10 ++++++++++ src/mango.c | 3 ++- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/animation/client.h b/src/animation/client.h index 249b7945..c53638e2 100644 --- a/src/animation/client.h +++ b/src/animation/client.h @@ -848,7 +848,7 @@ void init_fadeout_client(Client *c) { wl_list_insert(&fadeout_clients, &fadeout_cient->fadeout_link); // 请求刷新屏幕 - wlr_output_schedule_frame(c->mon->wlr_output); + request_fresh_all_monitors(); } void client_commit(Client *c) { @@ -879,7 +879,7 @@ void client_commit(Client *c) { } } // 请求刷新屏幕 - wlr_output_schedule_frame(c->mon->wlr_output); + request_fresh_all_monitors(); } void client_set_pending_state(Client *c) { diff --git a/src/animation/common.h b/src/animation/common.h index 70a595c0..edd7517a 100644 --- a/src/animation/common.h +++ b/src/animation/common.h @@ -234,4 +234,14 @@ struct wlr_scene_tree *wlr_scene_tree_snapshot(struct wlr_scene_node *node, wlr_scene_node_set_enabled(&snapshot->node, true); return snapshot; +} + +void request_fresh_all_monitors(void) { + Monitor *m = NULL; + wl_list_for_each(m, &mons, link) { + if (!m->wlr_output->enabled) { + continue; + } + wlr_output_schedule_frame(m->wlr_output); + } } \ No newline at end of file diff --git a/src/mango.c b/src/mango.c index 2056aeda..6602a8dc 100644 --- a/src/mango.c +++ b/src/mango.c @@ -692,6 +692,7 @@ static void resize_tile_client(Client *grabc, bool isdrag, int offsetx, int offsety, unsigned int time); static void refresh_monitors_workspaces_status(Monitor *m); static void init_client_properties(Client *c); +static void request_fresh_all_monitors(void); #include "data/static_keymap.h" #include "dispatch/bind_declare.h" @@ -4081,7 +4082,7 @@ skip: wlr_output_state_finish(&pending); if (need_more_frames) { - wlr_output_schedule_frame(m->wlr_output); + request_fresh_all_monitors(); } } From d75d819e28b873167f117a2419217fc19b1e5470 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sat, 1 Nov 2025 19:06:04 +0800 Subject: [PATCH 283/591] feat: add back switch_keybaord_layout --- src/config/parse_config.h | 2 + src/dispatch/bind_declare.h | 1 + src/dispatch/bind_define.h | 86 +++++++++++++++++++++++++++++++++++++ src/mango.c | 1 - 4 files changed, 89 insertions(+), 1 deletion(-) diff --git a/src/config/parse_config.h b/src/config/parse_config.h index 97db321a..ae1fd048 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -925,6 +925,8 @@ FuncType parse_func_name(char *func_name, Arg *arg, char *arg_value, } else if (strcmp(func_name, "setkeymode") == 0) { func = setkeymode; (*arg).v = strdup(arg_value); + } else if (strcmp(func_name, "switch_keyboard_layout") == 0) { + func = switch_keyboard_layout; } else if (strcmp(func_name, "setlayout") == 0) { func = setlayout; (*arg).v = strdup(arg_value); diff --git a/src/dispatch/bind_declare.h b/src/dispatch/bind_declare.h index a1dfbad3..b38e2da5 100644 --- a/src/dispatch/bind_declare.h +++ b/src/dispatch/bind_declare.h @@ -25,6 +25,7 @@ int spawn(const Arg *arg); int spawn_shell(const Arg *arg); int spawn_on_empty(const Arg *arg); int setkeymode(const Arg *arg); +int switch_keyboard_layout(const Arg *arg); int setlayout(const Arg *arg); int switch_layout(const Arg *arg); int setmfact(const Arg *arg); diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index 7d39186c..7dabc628 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -814,6 +814,92 @@ int spawn_on_empty(const Arg *arg) { return 0; } +int switch_keyboard_layout(const Arg *arg) { + if (!kb_group || !kb_group->wlr_group || !seat) { + wlr_log(WLR_ERROR, "Invalid keyboard group or seat"); + return 0; + } + + struct wlr_keyboard *keyboard = &kb_group->wlr_group->keyboard; + if (!keyboard || !keyboard->keymap) { + wlr_log(WLR_ERROR, "Invalid keyboard or keymap"); + return 0; + } + + // 1. 获取当前布局和计算下一个布局 + xkb_layout_index_t current = xkb_state_serialize_layout( + keyboard->xkb_state, XKB_STATE_LAYOUT_EFFECTIVE); + const int num_layouts = xkb_keymap_num_layouts(keyboard->keymap); + if (num_layouts < 2) { + wlr_log(WLR_INFO, "Only one layout available"); + return 0; + } + xkb_layout_index_t next = (current + 1) % num_layouts; + + // 2. 创建上下文 + struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + if (!context) { + wlr_log(WLR_ERROR, "Failed to create XKB context"); + return 0; + } + + // 安全地处理 layout 字符串 + const char *current_layout = xkb_rules.layout; + if (!current_layout || strlen(current_layout) == 0) { + wlr_log(WLR_INFO, "Using default layout 'us'"); + current_layout = "us"; + } + + // 5. 创建新 keymap + struct xkb_keymap *new_keymap = xkb_keymap_new_from_names( + context, &xkb_rules, XKB_KEYMAP_COMPILE_NO_FLAGS); + if (!new_keymap) { + wlr_log(WLR_ERROR, "Failed to create keymap for layouts: %s", + xkb_rules.layout); + goto cleanup_context; + } + + // 6. 应用新 keymap + unsigned int depressed = keyboard->modifiers.depressed; + unsigned int latched = keyboard->modifiers.latched; + unsigned int locked = keyboard->modifiers.locked; + + wlr_keyboard_set_keymap(keyboard, new_keymap); + wlr_keyboard_notify_modifiers(keyboard, depressed, latched, locked, next); + keyboard->modifiers.group = 0; + + // 7. 更新 seat + wlr_seat_set_keyboard(seat, keyboard); + wlr_seat_keyboard_notify_modifiers(seat, &keyboard->modifiers); + + InputDevice *id; + wl_list_for_each(id, &inputdevices, link) { + if (id->wlr_device->type != WLR_INPUT_DEVICE_KEYBOARD) { + continue; + } + + keyboard = (struct wlr_keyboard *)id->device_data; + + wlr_keyboard_set_keymap(keyboard, new_keymap); + wlr_keyboard_notify_modifiers(keyboard, depressed, latched, locked, + next); + keyboard->modifiers.group = 0; + + // 7. 更新 seat + wlr_seat_set_keyboard(seat, keyboard); + wlr_seat_keyboard_notify_modifiers(seat, &keyboard->modifiers); + } + + // 8. 清理资源 + xkb_keymap_unref(new_keymap); + +cleanup_context: + xkb_context_unref(context); + + printstatus(); + return 0; +} + int switch_layout(const Arg *arg) { int jk, ji; diff --git a/src/mango.c b/src/mango.c index 412a27fa..5a85a790 100644 --- a/src/mango.c +++ b/src/mango.c @@ -703,7 +703,6 @@ static void resize_tile_client(Client *grabc, bool isdrag, int offsetx, int offsety, unsigned int time); static void refresh_monitors_workspaces_status(Monitor *m); static void init_client_properties(Client *c); -static bool check_keyboard_rules_validate(struct xkb_rule_names *rules); static float *get_border_color(Client *c); static void request_fresh_all_monitors(void); From f8060d2f8f59a726f978f5565e086cc0ac5010b6 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sat, 1 Nov 2025 21:42:26 +0800 Subject: [PATCH 284/591] opt: simple keyboard layout switch --- src/dispatch/bind_define.h | 44 ++++++-------------------------------- 1 file changed, 7 insertions(+), 37 deletions(-) diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index 7dabc628..57efa883 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -836,35 +836,12 @@ int switch_keyboard_layout(const Arg *arg) { } xkb_layout_index_t next = (current + 1) % num_layouts; - // 2. 创建上下文 - struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); - if (!context) { - wlr_log(WLR_ERROR, "Failed to create XKB context"); - return 0; - } - - // 安全地处理 layout 字符串 - const char *current_layout = xkb_rules.layout; - if (!current_layout || strlen(current_layout) == 0) { - wlr_log(WLR_INFO, "Using default layout 'us'"); - current_layout = "us"; - } - - // 5. 创建新 keymap - struct xkb_keymap *new_keymap = xkb_keymap_new_from_names( - context, &xkb_rules, XKB_KEYMAP_COMPILE_NO_FLAGS); - if (!new_keymap) { - wlr_log(WLR_ERROR, "Failed to create keymap for layouts: %s", - xkb_rules.layout); - goto cleanup_context; - } - // 6. 应用新 keymap unsigned int depressed = keyboard->modifiers.depressed; unsigned int latched = keyboard->modifiers.latched; unsigned int locked = keyboard->modifiers.locked; - wlr_keyboard_set_keymap(keyboard, new_keymap); + wlr_keyboard_set_keymap(keyboard, keyboard->keymap); wlr_keyboard_notify_modifiers(keyboard, depressed, latched, locked, next); keyboard->modifiers.group = 0; @@ -878,24 +855,17 @@ int switch_keyboard_layout(const Arg *arg) { continue; } - keyboard = (struct wlr_keyboard *)id->device_data; + struct wlr_keyboard *tkb = (struct wlr_keyboard *)id->device_data; - wlr_keyboard_set_keymap(keyboard, new_keymap); - wlr_keyboard_notify_modifiers(keyboard, depressed, latched, locked, - next); - keyboard->modifiers.group = 0; + wlr_keyboard_set_keymap(tkb, keyboard->keymap); + wlr_keyboard_notify_modifiers(tkb, depressed, latched, locked, next); + tkb->modifiers.group = 0; // 7. 更新 seat - wlr_seat_set_keyboard(seat, keyboard); - wlr_seat_keyboard_notify_modifiers(seat, &keyboard->modifiers); + wlr_seat_set_keyboard(seat, tkb); + wlr_seat_keyboard_notify_modifiers(seat, &tkb->modifiers); } - // 8. 清理资源 - xkb_keymap_unref(new_keymap); - -cleanup_context: - xkb_context_unref(context); - printstatus(); return 0; } From 30dd766abcea74908f798d251dd56afe73ed67a3 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sat, 1 Nov 2025 22:41:22 +0800 Subject: [PATCH 285/591] fix: miss free baked_points_focus when reload config --- src/config/parse_config.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/config/parse_config.h b/src/config/parse_config.h index ae1fd048..13cd4230 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -2335,6 +2335,10 @@ void free_baked_points(void) { free(baked_points_tag); baked_points_tag = NULL; } + if (baked_points_focus) { + free(baked_points_focus); + baked_points_focus = NULL; + } } void free_config(void) { From 12e5c03600d9df63bc85b70f78fc11b117edc5bd Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sat, 1 Nov 2025 22:54:53 +0800 Subject: [PATCH 286/591] fix: miss free kb_layout string --- src/ext-protocol/dwl-ipc.h | 7 +++-- src/fetch/common.h | 57 +++++++++++++++++--------------------- src/mango.c | 2 +- 3 files changed, 31 insertions(+), 35 deletions(-) diff --git a/src/ext-protocol/dwl-ipc.h b/src/ext-protocol/dwl-ipc.h index 5ecb06eb..6b0c4c54 100644 --- a/src/ext-protocol/dwl-ipc.h +++ b/src/ext-protocol/dwl-ipc.h @@ -113,7 +113,8 @@ void dwl_ipc_output_printstatus_to(DwlIpcOutput *ipc_output) { struct wlr_keyboard *keyboard; xkb_layout_index_t current; int tagmask, state, numclients, focused_client, tag; - const char *title, *appid, *symbol, *kb_layout; + const char *title, *appid, *symbol; + char kb_layout[32]; focused = focustop(monitor); zdwl_ipc_output_v2_send_active(ipc_output->resource, monitor == selmon); @@ -149,8 +150,8 @@ void dwl_ipc_output_printstatus_to(DwlIpcOutput *ipc_output) { keyboard = &kb_group->wlr_group->keyboard; current = xkb_state_serialize_layout(keyboard->xkb_state, XKB_STATE_LAYOUT_EFFECTIVE); - kb_layout = - get_layout_abbr(xkb_keymap_layout_get_name(keyboard->keymap, current)); + get_layout_abbr(kb_layout, + xkb_keymap_layout_get_name(keyboard->keymap, current)); zdwl_ipc_output_v2_send_layout( ipc_output->resource, diff --git a/src/fetch/common.h b/src/fetch/common.h index afa49f64..33d7272f 100644 --- a/src/fetch/common.h +++ b/src/fetch/common.h @@ -44,11 +44,15 @@ char *get_autostart_path(char *autostart_path, unsigned int buf_size) { return autostart_path; } -const char *get_layout_abbr(const char *full_name) { +void get_layout_abbr(char *abbr, const char *full_name) { + // 清空输出缓冲区 + abbr[0] = '\0'; + // 1. 尝试在映射表中查找 for (int i = 0; layout_mappings[i].full_name != NULL; i++) { if (strcmp(full_name, layout_mappings[i].full_name) == 0) { - return layout_mappings[i].abbr; + strcpy(abbr, layout_mappings[i].abbr); + return; } } @@ -58,46 +62,37 @@ const char *get_layout_abbr(const char *full_name) { if (open && close && close > open) { unsigned int len = close - open - 1; if (len > 0 && len <= 4) { - char *abbr = malloc(len + 1); - if (abbr) { - // 提取并转换为小写 - for (unsigned int j = 0; j < len; j++) { - abbr[j] = tolower(open[j + 1]); - } - abbr[len] = '\0'; - return abbr; + // 提取并转换为小写 + for (unsigned int j = 0; j < len; j++) { + abbr[j] = tolower(open[j + 1]); } + abbr[len] = '\0'; + return; } } // 3. 提取前2-3个字母并转换为小写 - char *abbr = malloc(4); - if (abbr) { - unsigned int j = 0; - for (unsigned int i = 0; full_name[i] != '\0' && j < 3; i++) { - if (isalpha(full_name[i])) { - abbr[j++] = tolower(full_name[i]); - } + unsigned int j = 0; + for (unsigned int i = 0; full_name[i] != '\0' && j < 3; i++) { + if (isalpha(full_name[i])) { + abbr[j++] = tolower(full_name[i]); } - abbr[j] = '\0'; + } + abbr[j] = '\0'; - // 确保至少2个字符 - if (j >= 2) - return abbr; - free(abbr); + // 确保至少2个字符 + if (j >= 2) { + return; } // 4. 回退方案:使用首字母小写 - char *fallback = malloc(3); - if (fallback) { - fallback[0] = tolower(full_name[0]); - fallback[1] = full_name[1] ? tolower(full_name[1]) : '\0'; - fallback[2] = '\0'; - return fallback; + if (j == 1) { + abbr[1] = full_name[1] ? tolower(full_name[1]) : '\0'; + abbr[2] = '\0'; + } else { + // 5. 最终回退:返回 "xx" + strcpy(abbr, "xx"); } - - // 5. 最终回退:返回 "xx" - return strdup("xx"); } void xytonode(double x, double y, struct wlr_surface **psurface, Client **pc, diff --git a/src/mango.c b/src/mango.c index 5a85a790..80cfed0b 100644 --- a/src/mango.c +++ b/src/mango.c @@ -688,7 +688,7 @@ wlr_scene_tree_snapshot(struct wlr_scene_node *node, struct wlr_scene_tree *parent); static bool is_scroller_layout(Monitor *m); static void create_output(struct wlr_backend *backend, void *data); -static const char *get_layout_abbr(const char *full_name); +static void get_layout_abbr(char *abbr, const char *full_name); static void apply_named_scratchpad(Client *target_client); static Client *get_client_by_id_or_title(const char *arg_id, const char *arg_title); From f780bb1dc96b4a054c66a14834846858fc23aee7 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sun, 2 Nov 2025 08:51:06 +0800 Subject: [PATCH 287/591] update readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1a8b4a52..57023fc2 100644 --- a/README.md +++ b/README.md @@ -153,7 +153,7 @@ yay -S rofi foot xdg-desktop-portal-wlr swaybg waybar wl-clip-persist cliphist w ### Dms - Dependencies ```bash -yay -S foot xdg-desktop-portal-wlr swaybg wl-clip-persist cliphist wl-clipboard xfce-polkit sway-audio-idle-inhibit-git brightnessctl grim slurp satty matugen-bin dms-shell-git +yay -S foot xdg-desktop-portal-wlr swaybg wl-clip-persist cliphist wl-clipboard sway-audio-idle-inhibit-git brightnessctl grim slurp satty matugen-bin dms-shell-git ``` - use my dms config From f4a3e55515ee26f796d111193f2ee69032480e05 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sun, 2 Nov 2025 09:24:59 +0800 Subject: [PATCH 288/591] opt: optimize fade in animaiton --- src/animation/client.h | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/animation/client.h b/src/animation/client.h index 56a40d5a..8ba86b9d 100644 --- a/src/animation/client.h +++ b/src/animation/client.h @@ -1083,15 +1083,16 @@ bool client_apply_focus_opacity(Client *c) { client_set_opacity(c, 1); } else if (c->animation.running && c->animation.action == OPEN) { c->opacity_animation.running = false; - float percent = - animation_fade_in && !c->nofadein - ? (double)c->animation.passed_frames / c->animation.total_frames - : 1.0; - float opacity = c->isfullscreen ? 1 - : c == selmon->sel ? c->focused_opacity - : c->unfocused_opacity; + float linear_progress = + (float)c->animation.passed_frames / c->animation.total_frames; - float target_opacity = percent + fadein_begin_opacity; + float percent = + animation_fade_in && !c->nofadein ? linear_progress : 1.0; + float opacity = + c == selmon->sel ? c->focused_opacity : c->unfocused_opacity; + + float target_opacity = + percent * (1.0 - fadein_begin_opacity) + fadein_begin_opacity; if (target_opacity > opacity) { target_opacity = opacity; } From 4b1d2ef88aaecfba23474216472574f76337ec97 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sun, 2 Nov 2025 09:31:02 +0800 Subject: [PATCH 289/591] opt: optimize layer fadein animaiton --- src/animation/layer.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/animation/layer.h b/src/animation/layer.h index 3b81fc2b..2487a9cf 100644 --- a/src/animation/layer.h +++ b/src/animation/layer.h @@ -315,7 +315,9 @@ void layer_animation_next_tick(LayerSurface *l) { unsigned int y = l->animation.initial.y + (l->current.y - l->animation.initial.y) * factor; - double opacity = MIN(fadein_begin_opacity + animation_passed, 1.0f); + double opacity = MIN(fadein_begin_opacity + + animation_passed * (1.0 - fadein_begin_opacity), + 1.0f); if (animation_fade_in) wlr_scene_node_for_each_buffer(&l->scene->node, From 6f7fc3745f01b67645fee400df32a25889f2ef30 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sun, 2 Nov 2025 09:58:47 +0800 Subject: [PATCH 290/591] opt: support hot-reload xkb_rules --- src/config/parse_config.h | 5 +++++ src/mango.c | 17 +++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/src/config/parse_config.h b/src/config/parse_config.h index 13cd4230..72140d1f 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -2935,6 +2935,11 @@ void parse_config(void) { // 重置config结构体,确保所有指针初始化为NULL memset(&config, 0, sizeof(config)); + memset(&xkb_rules_rules, 0, sizeof(xkb_rules_rules)); + memset(&xkb_rules_model, 0, sizeof(xkb_rules_model)); + memset(&xkb_rules_layout, 0, sizeof(xkb_rules_layout)); + memset(&xkb_rules_variant, 0, sizeof(xkb_rules_variant)); + memset(&xkb_rules_options, 0, sizeof(xkb_rules_options)); // 初始化动态数组的指针为NULL,避免野指针 config.window_rules = NULL; diff --git a/src/mango.c b/src/mango.c index 80cfed0b..f46460c9 100644 --- a/src/mango.c +++ b/src/mango.c @@ -4604,6 +4604,23 @@ void reset_keyboard_layout(void) { wlr_seat_set_keyboard(seat, keyboard); wlr_seat_keyboard_notify_modifiers(seat, &keyboard->modifiers); + InputDevice *id; + wl_list_for_each(id, &inputdevices, link) { + if (id->wlr_device->type != WLR_INPUT_DEVICE_KEYBOARD) { + continue; + } + + struct wlr_keyboard *tkb = (struct wlr_keyboard *)id->device_data; + + wlr_keyboard_set_keymap(tkb, keyboard->keymap); + wlr_keyboard_notify_modifiers(tkb, depressed, latched, locked, 0); + tkb->modifiers.group = 0; + + // 7. 更新 seat + wlr_seat_set_keyboard(seat, tkb); + wlr_seat_keyboard_notify_modifiers(seat, &tkb->modifiers); + } + // Cleanup xkb_keymap_unref(new_keymap); From d73f51ec70547d14a2bb97ab4f48a7aad8b3789e Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sun, 2 Nov 2025 12:04:15 +0800 Subject: [PATCH 291/591] opt: optimize client live check --- src/animation/client.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/animation/client.h b/src/animation/client.h index 8ba86b9d..c4b71d7a 100644 --- a/src/animation/client.h +++ b/src/animation/client.h @@ -863,6 +863,9 @@ void client_commit(Client *c) { void client_set_pending_state(Client *c) { + if (!c || c->iskilling) + return; + // 判断是否需要动画 if (!animations) { c->animation.should_animate = false; From 96938f5f86653bbcd19e82bf2f94d79ce34d4028 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sun, 2 Nov 2025 12:18:37 +0800 Subject: [PATCH 292/591] opt: optimize focus animaiton init value --- src/animation/client.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/animation/client.h b/src/animation/client.h index c4b71d7a..b1519205 100644 --- a/src/animation/client.h +++ b/src/animation/client.h @@ -1047,7 +1047,10 @@ void client_set_focused_opacity_animation(Client *c) { } else { memcpy(c->opacity_animation.initial_border_color, border_color, sizeof(c->opacity_animation.initial_border_color)); + memcpy(c->opacity_animation.current_border_color, border_color, + sizeof(c->opacity_animation.current_border_color)); c->opacity_animation.initial_opacity = c->unfocused_opacity; + c->opacity_animation.current_opacity = c->unfocused_opacity; } c->opacity_animation.running = true; } @@ -1072,7 +1075,10 @@ void cleint_set_unfocused_opacity_animation(Client *c) { } else { memcpy(c->opacity_animation.initial_border_color, border_color, sizeof(c->opacity_animation.initial_border_color)); + memcpy(c->opacity_animation.current_border_color, border_color, + sizeof(c->opacity_animation.current_border_color)); c->opacity_animation.initial_opacity = c->focused_opacity; + c->opacity_animation.current_opacity = c->focused_opacity; } c->opacity_animation.running = true; From 32c4d621fd8ac1f7313acd3ca351cc881acad678 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Mon, 3 Nov 2025 09:22:04 +0800 Subject: [PATCH 293/591] opt: not allow modifier keys as keybind key --- src/mango.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/mango.c b/src/mango.c index f46460c9..6c2e81c4 100644 --- a/src/mango.c +++ b/src/mango.c @@ -3246,6 +3246,11 @@ keybinding(unsigned int mods, xkb_keysym_t sym, unsigned int keycode) { int ji; int isbreak = 0; + // not allow modifier keys to be used as a keybinding + if (keycode == 50 || keycode == 37 || keycode == 133 || keycode == 64 || + keycode == 62 || keycode == 108 || keycode == 105 || keycode == 134) + return false; + for (ji = 0; ji < config.key_bindings_count; ji++) { if (config.key_bindings_count < 1) break; From f103ed46c04be878bbc50aeed55977d93c33d251 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Mon, 3 Nov 2025 09:37:10 +0800 Subject: [PATCH 294/591] opt: not set maximized state in init when force_maximzie disable --- src/client/client.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/client/client.h b/src/client/client.h index a9f7313d..a3c9073f 100644 --- a/src/client/client.h +++ b/src/client/client.h @@ -359,7 +359,7 @@ static inline void client_set_maximized(Client *c, bool maximized) { static inline void client_set_tiled(Client *c, uint32_t edges) { struct wlr_xdg_toplevel *toplevel; #ifdef XWAYLAND - if (client_is_x11(c)) { + if (client_is_x11(c) && c->force_maximize) { wlr_xwayland_surface_set_maximized(c->surface.xwayland, edges != WLR_EDGE_NONE, edges != WLR_EDGE_NONE); From 2c38aee15a0e7787a62f12635d419989d1611cef Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Mon, 3 Nov 2025 10:54:39 +0800 Subject: [PATCH 295/591] opt: use new mango logo --- assets/mango-black.png | Bin 82665 -> 0 bytes assets/mango-transparency-128.png | Bin 8232 -> 13507 bytes assets/mango-transparency-256.png | Bin 23799 -> 41428 bytes assets/mango-transparency.png | Bin 82369 -> 130578 bytes assets/mango.png | Bin 296623 -> 39932 bytes 5 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 assets/mango-black.png diff --git a/assets/mango-black.png b/assets/mango-black.png deleted file mode 100644 index fabfe017692bc08bfbac70482641ef83ff08b3c7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 82665 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 literal 8232 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 diff --git a/assets/mango-transparency-256.png b/assets/mango-transparency-256.png index 3bb4d6534a5816d6ac89088aae071781355d0a81..974ab3f67034fe865001d912596e58bf882177be 100644 GIT binary patch literal 41428 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 JtaD0e0sxLs%u4_O literal 23799 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 OYqX+?9;wI7!(wQe+PXzUO=G@~Ocbk%~W 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 Pz`)??>gTe~DWM4fO;q3` diff --git a/assets/mango-transparency.png b/assets/mango-transparency.png index 25e5385665773bb3d9668bf68de12cc43c420f77..488a31ecbfcb82a1f0ffa8f6b8e2fcecbab9a15d 100644 GIT binary patch literal 130578 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 ksEdt(fq@OwymdKI;Vst00|fy6aWAK literal 82369 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

3zLYQX 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 N!PC{xWt~$(69A2HpQ-== diff --git a/assets/mango.png b/assets/mango.png index eb14740468318eec2da5cfd38d305866522a546e..5a8136f762c59b8edf6739cbd176d758c0ac76ba 100644 GIT binary patch literal 39932 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�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­%aIDE$b>PUK4cYQo+j~4E5ix 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 From 46c1acc2a58a8ed8cd1e061ade51cf6fef179941 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Mon, 3 Nov 2025 10:55:54 +0800 Subject: [PATCH 296/591] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 57023fc2..c90cee1f 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # MangoWC -mango-transparency-256 +mango-transparency-256 This project's development is based on [dwl](https://codeberg.org/dwl/dwl/). From e47dc831c4e8a981679d0b3c6dd492f442d114ab Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Mon, 3 Nov 2025 12:18:10 +0800 Subject: [PATCH 297/591] opt: change drm_lease create fail log to info --- src/mango.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mango.c b/src/mango.c index 6c2e81c4..564bcbef 100644 --- a/src/mango.c +++ b/src/mango.c @@ -4996,8 +4996,8 @@ void setup(void) { if (drm_lease_manager) { wl_signal_add(&drm_lease_manager->events.request, &drm_lease_request); } else { - wlr_log(WLR_ERROR, "Failed to create wlr_drm_lease_device_v1; VR will " - "not be available"); + wlr_log(WLR_DEBUG, "Failed to create wlr_drm_lease_device_v1."); + wlr_log(WLR_INFO, "VR will not be available."); } wl_global_create(dpy, &zdwl_ipc_manager_v2_interface, 2, NULL, From 1271832e947d3d4af27b36f687edd2f2e535f051 Mon Sep 17 00:00:00 2001 From: ColorSkyFun Date: Mon, 3 Nov 2025 13:17:25 +0800 Subject: [PATCH 298/591] nix: fix warning by replacing pkgs.system with pkgs.stdenv.hostPlatform.system --- flake.nix | 2 +- nix/hm-modules.nix | 2 +- nix/nixos-modules.nix | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/flake.nix b/flake.nix index ff88ba0c..b7158bbd 100644 --- a/flake.nix +++ b/flake.nix @@ -30,7 +30,7 @@ }: let inherit (pkgs) callPackage ; mango = callPackage ./nix { - inherit (inputs.scenefx.packages.${pkgs.system}) scenefx; + inherit (inputs.scenefx.packages.${pkgs.stdenv.hostPlatform.system}) scenefx; }; shellOverride = old: { nativeBuildInputs = old.nativeBuildInputs ++ []; diff --git a/nix/hm-modules.nix b/nix/hm-modules.nix index 286f0cbb..85d57908 100644 --- a/nix/hm-modules.nix +++ b/nix/hm-modules.nix @@ -21,7 +21,7 @@ in { }; package = lib.mkOption { type = lib.types.package; - default = self.packages.${pkgs.system}.mango; + default = self.packages.${pkgs.stdenv.hostPlatform.system}.mango; description = "The mango package to use"; }; systemd = { diff --git a/nix/nixos-modules.nix b/nix/nixos-modules.nix index 9e73d6af..5d0aa61e 100644 --- a/nix/nixos-modules.nix +++ b/nix/nixos-modules.nix @@ -11,7 +11,7 @@ in { enable = lib.mkEnableOption "mango, a wayland compositor based on dwl"; package = lib.mkOption { type = lib.types.package; - default = self.packages.${pkgs.system}.mango; + default = self.packages.${pkgs.stdenv.hostPlatform.system}.mango; description = "The mango package to use"; }; }; From 70eb70ef0d32b86bfc40e8f51916d801742c2671 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Mon, 3 Nov 2025 19:18:39 +0800 Subject: [PATCH 299/591] break change: default force_maximize to 0 --- src/mango.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mango.c b/src/mango.c index 564bcbef..0779e9f2 100644 --- a/src/mango.c +++ b/src/mango.c @@ -3538,7 +3538,7 @@ void init_client_properties(Client *c) { c->stack_innder_per = 0.0f; c->isterm = 0; c->allow_csd = 0; - c->force_maximize = 1; + c->force_maximize = 0; } void // old fix to 0.5 From b39ab429f5742d797dced9017ed36e27c4b9266b Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Tue, 4 Nov 2025 11:31:04 +0800 Subject: [PATCH 300/591] feat: Calculate animation curve by time points rather than passed frames --- src/animation/client.h | 77 ++++++++++++++++++++++-------------------- src/animation/common.h | 16 --------- src/animation/layer.h | 45 ++++++++++-------------- src/common/util.c | 13 +++++++ src/common/util.h | 2 ++ src/mango.c | 7 ++-- 6 files changed, 76 insertions(+), 84 deletions(-) diff --git a/src/animation/client.h b/src/animation/client.h index b1519205..c098a7a1 100644 --- a/src/animation/client.h +++ b/src/animation/client.h @@ -615,10 +615,15 @@ void fadeout_client_animation_next_tick(Client *c) { BufferData buffer_data; + struct timespec now; + clock_gettime(CLOCK_MONOTONIC, &now); + + uint32_t passed_time = timespec_to_ms(&now) - c->animation.time_started; double animation_passed = - c->animation.total_frames - ? (double)c->animation.passed_frames / c->animation.total_frames + c->animation.duration + ? (double)passed_time / (double)c->animation.duration : 1.0; + int type = c->animation.action = c->animation.action; double factor = find_animation_curve_at(animation_passed, type); unsigned int width = @@ -662,20 +667,22 @@ void fadeout_client_animation_next_tick(Client *c) { &c->scene->node, snap_scene_buffer_apply_effect, &buffer_data); } - if (animation_passed == 1.0) { + if (animation_passed >= 1.0) { wl_list_remove(&c->fadeout_link); wlr_scene_node_destroy(&c->scene->node); free(c); c = NULL; - } else { - c->animation.passed_frames++; } } void client_animation_next_tick(Client *c) { + struct timespec now; + clock_gettime(CLOCK_MONOTONIC, &now); + + uint32_t passed_time = timespec_to_ms(&now) - c->animation.time_started; double animation_passed = - c->animation.total_frames - ? (double)c->animation.passed_frames / c->animation.total_frames + c->animation.duration + ? (double)passed_time / (double)c->animation.duration : 1.0; int type = c->animation.action == NONE ? MOVE : c->animation.action; @@ -707,7 +714,7 @@ void client_animation_next_tick(Client *c) { c->is_pending_open_animation = false; - if (animation_passed == 1.0) { + if (animation_passed >= 1.0) { // clear the open action state // To prevent him from being mistaken that @@ -735,8 +742,6 @@ void client_animation_next_tick(Client *c) { // end flush in next frame, not the current frame c->need_output_flush = false; - } else { - c->animation.passed_frames++; } client_apply_clip(c, factor); @@ -820,9 +825,7 @@ void init_fadeout_client(Client *c) { fadeout_cient->geom.height * zoom_end_ratio; } - fadeout_cient->animation.passed_frames = 0; - fadeout_cient->animation.total_frames = - fadeout_cient->animation.duration / all_output_frame_duration_ms(); + fadeout_cient->animation.time_started = get_now_in_ms(); wlr_scene_node_set_enabled(&fadeout_cient->scene->node, true); wl_list_insert(&fadeout_clients, &fadeout_cient->fadeout_link); @@ -839,23 +842,11 @@ void client_commit(Client *c) { } c->animation.initial = c->animainit_geom; - // 设置动画速度 - c->animation.passed_frames = 0; - c->animation.total_frames = - c->animation.duration / all_output_frame_duration_ms(); + c->animation.time_started = get_now_in_ms(); // 标记动画开始 c->animation.running = true; c->animation.should_animate = false; - } else { - // 如果动画没有开始,且被判定为不应该动画, - // 则设置总帧数为1,不然其他地方一旦获取动画 - // 进度,总帧数作为分母会造成除零 - // 比如动画类型为none的时候 - if (!c->animation.running) { - c->animation.passed_frames = 1; - c->animation.total_frames = 1; - } } // 请求刷新屏幕 request_fresh_all_monitors(); @@ -1032,12 +1023,11 @@ bool client_draw_fadeout_frame(Client *c) { void client_set_focused_opacity_animation(Client *c) { float *border_color = get_border_color(c); + c->opacity_animation.duration = animation_duration_focus; memcpy(c->opacity_animation.target_border_color, border_color, sizeof(c->opacity_animation.target_border_color)); c->opacity_animation.target_opacity = c->focused_opacity; - c->opacity_animation.total_frames = - animation_duration_focus / all_output_frame_duration_ms(); - c->opacity_animation.passed_frames = 0; + c->opacity_animation.time_started = get_now_in_ms(); if (c->opacity_animation.running) { memcpy(c->opacity_animation.initial_border_color, c->opacity_animation.current_border_color, @@ -1058,13 +1048,12 @@ void client_set_focused_opacity_animation(Client *c) { void cleint_set_unfocused_opacity_animation(Client *c) { // Start border color animation to unfocused float *border_color = get_border_color(c); + c->opacity_animation.duration = animation_duration_focus; memcpy(c->opacity_animation.target_border_color, border_color, sizeof(c->opacity_animation.target_border_color)); // Start opacity animation to unfocused c->opacity_animation.target_opacity = c->unfocused_opacity; - c->opacity_animation.total_frames = - animation_duration_focus / all_output_frame_duration_ms(); - c->opacity_animation.passed_frames = 0; + c->opacity_animation.time_started = get_now_in_ms(); if (c->opacity_animation.running) { memcpy(c->opacity_animation.initial_border_color, @@ -1092,8 +1081,14 @@ bool client_apply_focus_opacity(Client *c) { client_set_opacity(c, 1); } else if (c->animation.running && c->animation.action == OPEN) { c->opacity_animation.running = false; - float linear_progress = - (float)c->animation.passed_frames / c->animation.total_frames; + struct timespec now; + clock_gettime(CLOCK_MONOTONIC, &now); + + uint32_t passed_time = timespec_to_ms(&now) - c->animation.time_started; + double linear_progress = + c->animation.duration + ? (double)passed_time / (double)c->animation.duration + : 1.0; float percent = animation_fade_in && !c->nofadein ? linear_progress : 1.0; @@ -1107,8 +1102,17 @@ bool client_apply_focus_opacity(Client *c) { } client_set_opacity(c, target_opacity); } else if (animations && c->opacity_animation.running) { - float linear_progress = (float)c->opacity_animation.passed_frames / - c->opacity_animation.total_frames; + + struct timespec now; + clock_gettime(CLOCK_MONOTONIC, &now); + + uint32_t passed_time = + timespec_to_ms(&now) - c->opacity_animation.time_started; + double linear_progress = + c->opacity_animation.duration + ? (double)passed_time / (double)c->opacity_animation.duration + : 1.0; + float eased_progress = find_animation_curve_at(linear_progress, FOCUS); c->opacity_animation.current_opacity = @@ -1130,7 +1134,6 @@ bool client_apply_focus_opacity(Client *c) { if (linear_progress == 1.0f) { c->opacity_animation.running = false; } else { - c->opacity_animation.passed_frames++; return true; } } else if (c == selmon->sel) { diff --git a/src/animation/common.h b/src/animation/common.h index edd39b04..06ffe1ab 100644 --- a/src/animation/common.h +++ b/src/animation/common.h @@ -86,22 +86,6 @@ double find_animation_curve_at(double t, int type) { return baked_points[up].y; } -double all_output_frame_duration_ms() { - int32_t refresh_total = 0; - Monitor *m = NULL; - wl_list_for_each(m, &mons, link) { - if (!m->wlr_output->enabled) { - continue; - } - refresh_total += m->wlr_output->refresh; - } - return 1000000.0 / refresh_total; -} - -double output_frame_duration_ms(Monitor *m) { - return 1000000.0 / m->wlr_output->refresh; -} - static bool scene_node_snapshot(struct wlr_scene_node *node, int lx, int ly, struct wlr_scene_tree *snapshot_tree) { if (!node->enabled && node->type != WLR_SCENE_NODE_TREE) { diff --git a/src/animation/layer.h b/src/animation/layer.h index 2487a9cf..48ceb211 100644 --- a/src/animation/layer.h +++ b/src/animation/layer.h @@ -234,10 +234,15 @@ void fadeout_layer_animation_next_tick(LayerSurface *l) { if (!l) return; + struct timespec now; + clock_gettime(CLOCK_MONOTONIC, &now); + + uint32_t passed_time = timespec_to_ms(&now) - l->animation.time_started; double animation_passed = - l->animation.total_frames - ? (double)l->animation.passed_frames / l->animation.total_frames + l->animation.duration + ? (double)passed_time / (double)l->animation.duration : 1.0; + int type = l->animation.action = l->animation.action; double factor = find_animation_curve_at(animation_passed, type); unsigned int width = @@ -280,13 +285,11 @@ void fadeout_layer_animation_next_tick(LayerSurface *l) { wlr_scene_node_for_each_buffer(&l->scene->node, scene_buffer_apply_opacity, &opacity); - if (animation_passed == 1.0) { + if (animation_passed >= 1.0) { wl_list_remove(&l->fadeout_link); wlr_scene_node_destroy(&l->scene->node); free(l); l = NULL; - } else { - l->animation.passed_frames++; } } @@ -295,9 +298,13 @@ void layer_animation_next_tick(LayerSurface *l) { if (!l || !l->mapped) return; + struct timespec now; + clock_gettime(CLOCK_MONOTONIC, &now); + + uint32_t passed_time = timespec_to_ms(&now) - l->animation.time_started; double animation_passed = - l->animation.total_frames - ? (double)l->animation.passed_frames / l->animation.total_frames + l->animation.duration + ? (double)passed_time / (double)l->animation.duration : 1.0; int type = l->animation.action == NONE ? MOVE : l->animation.action; @@ -349,12 +356,10 @@ void layer_animation_next_tick(LayerSurface *l) { .height = height, }; - if (animation_passed == 1.0) { + if (animation_passed >= 1.0) { l->animation.running = false; l->need_output_flush = false; l->animation.action = MOVE; - } else { - l->animation.passed_frames++; } } @@ -448,10 +453,8 @@ void init_fadeout_layers(LayerSurface *l) { fadeout_layer->current.height = 0; } - // 计算动画帧数 - fadeout_layer->animation.passed_frames = 0; - fadeout_layer->animation.total_frames = - fadeout_layer->animation.duration / all_output_frame_duration_ms(); + // 动画开始时间 + fadeout_layer->animation.time_started = get_now_in_ms(); // 将节点插入到关闭动画链表中,屏幕刷新哪里会检查链表中是否有节点可以应用于动画 wlr_scene_node_set_enabled(&fadeout_layer->scene->node, true); @@ -534,23 +537,11 @@ void layer_commit(LayerSurface *l) { } l->animation.initial = l->animainit_geom; - // 设置动画速度 - l->animation.passed_frames = 0; - l->animation.total_frames = - l->animation.duration / output_frame_duration_ms(l->mon); + l->animation.time_started = get_now_in_ms(); // 标记动画开始 l->animation.running = true; l->animation.should_animate = false; - } else { - // 如果动画没有开始,且被判定为不应该动画, - // 则设置总帧数为1,不然其他地方一旦获取动画 - // 进度,总帧数作为分母会造成除零 - // 比如动画类型为none的时候 - if (!l->animation.running) { - l->animation.passed_frames = 1; - l->animation.total_frames = 1; - } } // 请求刷新屏幕 wlr_output_schedule_frame(l->mon->wlr_output); diff --git a/src/common/util.c b/src/common/util.c index 272340cd..6eadbc67 100644 --- a/src/common/util.c +++ b/src/common/util.c @@ -4,6 +4,7 @@ #include #include #include +#include #include "util.h" @@ -80,3 +81,15 @@ int regex_match(const char *pattern, const char *str) { void wl_list_append(struct wl_list *list, struct wl_list *object) { wl_list_insert(list->prev, object); } + +unsigned int get_now_in_ms(void) { + struct timespec now; + clock_gettime(CLOCK_MONOTONIC, &now); + + return timespec_to_ms(&now); +} + +unsigned int timespec_to_ms(struct timespec *ts) { + return (unsigned int)ts->tv_sec * 1000 + + (unsigned int)ts->tv_nsec / 1000000; +} diff --git a/src/common/util.h b/src/common/util.h index 2ebef43a..3a0f6dae 100644 --- a/src/common/util.h +++ b/src/common/util.h @@ -6,3 +6,5 @@ void *ecalloc(size_t nmemb, size_t size); int fd_set_nonblock(int fd); int regex_match(const char *pattern_mb, const char *str_mb); void wl_list_append(struct wl_list *list, struct wl_list *object); +unsigned int get_now_in_ms(void); +unsigned int timespec_to_ms(struct timespec *ts); \ No newline at end of file diff --git a/src/mango.c b/src/mango.c index 0779e9f2..690775ba 100644 --- a/src/mango.c +++ b/src/mango.c @@ -231,8 +231,7 @@ struct dwl_animation { bool tagouting; bool begin_fade_in; bool tag_from_rule; - unsigned int total_frames; - unsigned int passed_frames; + unsigned int time_started; unsigned int duration; struct wlr_box initial; struct wlr_box current; @@ -244,8 +243,8 @@ struct dwl_opacity_animation { float current_opacity; float target_opacity; float initial_opacity; - unsigned int total_frames; - unsigned int passed_frames; + unsigned int time_started; + unsigned int duration; float current_border_color[4]; float target_border_color[4]; float initial_border_color[4]; From 3645817f2d9c1ceb27c440a20fca6f5c5dc13a27 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Tue, 4 Nov 2025 13:49:26 +0800 Subject: [PATCH 301/591] bump version to 0.10.5 --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 0d33badf..27b717c7 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('mango', ['c', 'cpp'], - version : '0.10.4', + version : '0.10.5', ) subdir('protocols') From 9c7436ba71b77184403f24be0fd4ff824c9727a0 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Tue, 4 Nov 2025 23:02:29 +0800 Subject: [PATCH 302/591] feat: tearing support --- protocols/meson.build | 1 + src/client/client.h | 14 ++++ src/config/parse_config.h | 9 ++ src/config/preset.h | 1 + src/ext-protocol/all.h | 1 + src/ext-protocol/tearing.h | 168 +++++++++++++++++++++++++++++++++++++ src/mango.c | 51 ++++++++--- 7 files changed, 234 insertions(+), 11 deletions(-) create mode 100644 src/ext-protocol/tearing.h diff --git a/protocols/meson.build b/protocols/meson.build index 1069157c..cafab64a 100644 --- a/protocols/meson.build +++ b/protocols/meson.build @@ -19,6 +19,7 @@ wayland_xmls = [ wl_protocol_dir + '/staging/ext-image-capture-source/ext-image-capture-source-v1.xml', wl_protocol_dir + '/staging/ext-foreign-toplevel-list/ext-foreign-toplevel-list-v1.xml', wl_protocol_dir + '/staging/ext-workspace/ext-workspace-v1.xml', + wl_protocol_dir + '/staging/tearing-control/tearing-control-v1.xml', 'wlr-foreign-toplevel-management-unstable-v1.xml', 'dwl-ipc-unstable-v2.xml', 'wlr-layer-shell-unstable-v1.xml', diff --git a/src/client/client.h b/src/client/client.h index a3c9073f..2b763fab 100644 --- a/src/client/client.h +++ b/src/client/client.h @@ -153,6 +153,20 @@ static inline void client_get_geometry(Client *c, struct wlr_box *geom) { *geom = c->surface.xdg->geometry; } +static inline Client *get_client_from_surface(struct wlr_surface *surface) { + if (!surface) + return NULL; + + // 从 surface 的 data 指针获取 scene tree + struct wlr_scene_tree *scene_tree = surface->data; + if (!scene_tree) + return NULL; + + // 从 scene tree 的 node data 获取 Client + Client *c = scene_tree->node.data; + return c; +} + static inline Client *client_get_parent(Client *c) { Client *p = NULL; #ifdef XWAYLAND diff --git a/src/config/parse_config.h b/src/config/parse_config.h index 72140d1f..7e1be635 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -79,6 +79,7 @@ typedef struct { int isterm; int allow_csd; int force_maximize; + int force_tearing; int noswallow; int noblur; float focused_opacity; @@ -328,6 +329,7 @@ typedef struct { int xwayland_persistence; int syncobj_enable; int adaptive_sync; + int allow_tearing; struct xkb_rule_names xkb_rules; @@ -1232,6 +1234,8 @@ void parse_option(Config *config, char *key, char *value) { config->syncobj_enable = atoi(value); } else if (strcmp(key, "adaptive_sync") == 0) { config->adaptive_sync = atoi(value); + } else if (strcmp(key, "allow_tearing") == 0) { + config->allow_tearing = atoi(value); } else if (strcmp(key, "no_border_when_single") == 0) { config->no_border_when_single = atoi(value); } else if (strcmp(key, "no_radius_when_single") == 0) { @@ -1673,6 +1677,7 @@ void parse_option(Config *config, char *key, char *value) { rule->isterm = -1; rule->allow_csd = -1; rule->force_maximize = -1; + rule->force_tearing = -1; rule->noswallow = -1; rule->noblur = -1; rule->nofadein = -1; @@ -1769,6 +1774,8 @@ void parse_option(Config *config, char *key, char *value) { rule->allow_csd = atoi(val); } else if (strcmp(key, "force_maximize") == 0) { rule->force_maximize = atoi(val); + } else if (strcmp(key, "force_tearing") == 0) { + rule->force_tearing = atoi(val); } else if (strcmp(key, "noswallow") == 0) { rule->noswallow = atoi(val); } else if (strcmp(key, "noblur") == 0) { @@ -2642,6 +2649,7 @@ void override_config(void) { xwayland_persistence = CLAMP_INT(config.xwayland_persistence, 0, 1); syncobj_enable = CLAMP_INT(config.syncobj_enable, 0, 1); adaptive_sync = CLAMP_INT(config.adaptive_sync, 0, 1); + allow_tearing = CLAMP_INT(config.allow_tearing, 0, 2); axis_bind_apply_timeout = CLAMP_INT(config.axis_bind_apply_timeout, 0, 1000); focus_on_activate = CLAMP_INT(config.focus_on_activate, 0, 1); @@ -2816,6 +2824,7 @@ void set_value_default() { config.xwayland_persistence = xwayland_persistence; config.syncobj_enable = syncobj_enable; config.adaptive_sync = adaptive_sync; + config.allow_tearing = allow_tearing; config.no_border_when_single = no_border_when_single; config.no_radius_when_single = no_radius_when_single; config.snap_distance = snap_distance; diff --git a/src/config/preset.h b/src/config/preset.h index 39cf5096..2f994ec1 100644 --- a/src/config/preset.h +++ b/src/config/preset.h @@ -103,6 +103,7 @@ int xwayland_persistence = 1; /* xwayland persistence */ int syncobj_enable = 0; int adaptive_sync = 0; double drag_refresh_interval = 30.0; +int allow_tearing = TEARING_DISABLED; /* keyboard */ diff --git a/src/ext-protocol/all.h b/src/ext-protocol/all.h index 0103248b..bc690fe7 100644 --- a/src/ext-protocol/all.h +++ b/src/ext-protocol/all.h @@ -1,4 +1,5 @@ #include "dwl-ipc.h" #include "ext-workspace.h" #include "foreign-toplevel.h" +#include "tearing.h" #include "text-input.h" \ No newline at end of file diff --git a/src/ext-protocol/tearing.h b/src/ext-protocol/tearing.h new file mode 100644 index 00000000..5ad36e8a --- /dev/null +++ b/src/ext-protocol/tearing.h @@ -0,0 +1,168 @@ +#include + +struct tearing_controller { + struct wlr_tearing_control_v1 *tearing_control; + struct wl_listener set_hint; + struct wl_listener destroy; +}; + +struct wlr_tearing_control_manager_v1 *tearing_control; +struct wl_listener tearing_new_object; + +static void handle_controller_set_hint(struct wl_listener *listener, + void *data) { + struct tearing_controller *controller = + wl_container_of(listener, controller, set_hint); + Client *c = get_client_from_surface(controller->tearing_control->surface); + if (c) { + /* + * tearing_control->current is actually an enum: + * WP_TEARING_CONTROL_V1_PRESENTATION_HINT_VSYNC = 0 + * WP_TEARING_CONTROL_V1_PRESENTATION_HINT_ASYNC = 1 + * + * Using it as a bool here allows us to not ship the XML. + */ + c->tearing_hint = controller->tearing_control->current; + } +} + +static void handle_controller_destroy(struct wl_listener *listener, + void *data) { + struct tearing_controller *controller = + wl_container_of(listener, controller, destroy); + wl_list_remove(&controller->set_hint.link); + wl_list_remove(&controller->destroy.link); + free(controller); +} + +void handle_tearing_new_object(struct wl_listener *listener, void *data) { + struct wlr_tearing_control_v1 *new_tearing_control = data; + + enum wp_tearing_control_v1_presentation_hint hint = + wlr_tearing_control_manager_v1_surface_hint_from_surface( + tearing_control, new_tearing_control->surface); + wlr_log(WLR_DEBUG, "New presentation hint %d received for surface %p", hint, + new_tearing_control->surface); + + struct tearing_controller *controller = + ecalloc(1, sizeof(struct tearing_controller)); + controller->tearing_control = new_tearing_control; + + controller->set_hint.notify = handle_controller_set_hint; + wl_signal_add(&new_tearing_control->events.set_hint, &controller->set_hint); + + controller->destroy.notify = handle_controller_destroy; + wl_signal_add(&new_tearing_control->events.destroy, &controller->destroy); +} + +bool check_tearing_frame_allow(Monitor *m) { + /* never allow tearing when disabled */ + if (!allow_tearing) { + return false; + } + + Client *c = selmon->sel; + + /* tearing is only allowed for the output with the active client */ + if (!c || c->mon != m) { + return false; + } + + /* allow tearing for any window when requested or forced */ + if (allow_tearing == TEARING_ENABLED) { + if (c->force_tearing == STATE_UNSPECIFIED) { + return c->tearing_hint; + } else { + return c->force_tearing == STATE_ENABLED; + } + } + + /* remaining tearing options apply only to full-screen windows */ + if (!c->isfullscreen) { + return false; + } + + if (c->force_tearing == STATE_UNSPECIFIED) { + /* honor the tearing hint or the fullscreen-force preference */ + return c->tearing_hint || allow_tearing == TEARING_FULLSCREEN_ONLY; + } + + /* 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); + } + } +} \ No newline at end of file diff --git a/src/mango.c b/src/mango.c index 690775ba..6e48eb12 100644 --- a/src/mango.c +++ b/src/mango.c @@ -164,6 +164,13 @@ enum { UP, DOWN, LEFT, RIGHT, UNDIR }; /* smartmovewin */ enum { NONE, OPEN, MOVE, CLOSE, TAG, FOCUS }; enum { UNFOLD, FOLD, INVALIDFOLD }; enum { PREV, NEXT }; +enum { STATE_UNSPECIFIED = 0, STATE_ENABLED, STATE_DISABLED }; + +enum tearing_mode { + TEARING_DISABLED = 0, + TEARING_ENABLED, + TEARING_FULLSCREEN_ONLY, +}; typedef struct Pertag Pertag; typedef struct Monitor Monitor; @@ -357,6 +364,8 @@ struct Client { bool ismaster; bool cursor_in_upper_half, cursor_in_left_half; bool isleftstack; + int tearing_hint; + int force_tearing; }; typedef struct { @@ -426,6 +435,7 @@ struct Monitor { struct wl_list link; struct wlr_output *wlr_output; struct wlr_scene_output *scene_output; + struct wlr_output_state pending; struct wl_listener frame; struct wl_listener destroy; struct wl_listener request_state; @@ -1117,6 +1127,7 @@ static void apply_rule_properties(Client *c, const ConfigWinRule *r) { APPLY_INT_PROP(c, r, isterm); APPLY_INT_PROP(c, r, allow_csd); APPLY_INT_PROP(c, r, force_maximize); + APPLY_INT_PROP(c, r, force_tearing); APPLY_INT_PROP(c, r, noswallow); APPLY_INT_PROP(c, r, nofadein); APPLY_INT_PROP(c, r, nofadeout); @@ -1952,6 +1963,7 @@ void cleanuplisteners(void) { wl_list_remove(&start_drag.link); wl_list_remove(&new_session_lock.link); wl_list_remove(&drm_lease_request.link); + wl_list_remove(&tearing_new_object.link); #ifdef XWAYLAND wl_list_remove(&new_xwayland_surface.link); wl_list_remove(&xwayland_ready.link); @@ -2017,6 +2029,7 @@ void cleanupmon(struct wl_listener *listener, void *data) { wlr_scene_node_destroy(&m->blur->node); m->blur = NULL; } + m->wlr_output->data = NULL; free(m->pertag); free(m); } @@ -2546,6 +2559,7 @@ void createmon(struct wl_listener *listener, void *data) { m = wlr_output->data = ecalloc(1, sizeof(*m)); m->wlr_output = wlr_output; + m->wlr_output->data = m; wl_list_init(&m->dwl_ipc_outputs); @@ -3538,6 +3552,7 @@ void init_client_properties(Client *c) { c->isterm = 0; c->allow_csd = 0; c->force_maximize = 0; + c->force_tearing = 0; } void // old fix to 0.5 @@ -4066,10 +4081,11 @@ void rendermon(struct wl_listener *listener, void *data) { struct timespec now; bool need_more_frames = false; + bool frame_allow_tearing = check_tearing_frame_allow(m); + // 绘制层和淡出效果 for (i = 0; i < LENGTH(m->layers); i++) { layer_list = &m->layers[i]; - // Draw frames for all layer wl_list_for_each_safe(l, tmpl, layer_list, link) { need_more_frames = layer_draw_frame(l) || need_more_frames; } @@ -4083,25 +4099,34 @@ void rendermon(struct wl_listener *listener, void *data) { need_more_frames = layer_draw_fadeout_frame(l) || need_more_frames; } - // Draw frames for all clients + // 绘制客户端 wl_list_for_each(c, &clients, link) { need_more_frames = client_draw_frame(c) || need_more_frames; - if (!animations && c->configure_serial && !c->isfloating && - client_is_rendered_on_mon(c, m) && !client_is_stopped(c)) + if (!animations && !allow_tearing && c->configure_serial && + !c->isfloating && client_is_rendered_on_mon(c, m) && + !client_is_stopped(c)) { goto skip; + } } - wlr_scene_output_commit(m->scene_output, NULL); + // 只有在需要帧时才构建和提交状态 + if (allow_tearing && frame_allow_tearing) { + apply_tear_state(m); + } else { + wlr_scene_output_commit(m->scene_output, NULL); + } skip: - - // Send frame done notification + // 发送帧完成通知 clock_gettime(CLOCK_MONOTONIC, &now); - wlr_scene_output_send_frame_done(m->scene_output, &now); - - // // Clean up pending state - wlr_output_state_finish(&pending); + if (allow_tearing && frame_allow_tearing) { + wlr_scene_output_send_frame_done(m->scene_output, &now); + } else { + wlr_scene_output_send_frame_done(m->scene_output, &now); + wlr_output_state_finish(&pending); + } + // 如果需要更多帧,确保安排下一帧 if (need_more_frames) { request_fresh_all_monitors(); } @@ -4843,6 +4868,10 @@ void setup(void) { power_mgr = wlr_output_power_manager_v1_create(dpy); wl_signal_add(&power_mgr->events.set_mode, &output_power_mgr_set_mode); + tearing_control = wlr_tearing_control_manager_v1_create(dpy, 1); + tearing_new_object.notify = handle_tearing_new_object; + wl_signal_add(&tearing_control->events.new_object, &tearing_new_object); + /* Creates an output layout, which a wlroots utility for working with an * arrangement of screens in a physical layout. */ output_layout = wlr_output_layout_create(dpy); From cca92ec50d41eeeb71d82be4dbdf821646163c9f Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Wed, 5 Nov 2025 09:44:40 +0800 Subject: [PATCH 303/591] fix: border color not change when focus change when disable animaitons --- src/animation/client.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/animation/client.h b/src/animation/client.h index c098a7a1..09d14162 100644 --- a/src/animation/client.h +++ b/src/animation/client.h @@ -1023,6 +1023,12 @@ bool client_draw_fadeout_frame(Client *c) { void client_set_focused_opacity_animation(Client *c) { float *border_color = get_border_color(c); + + if (!animations) { + setborder_color(c); + return; + } + c->opacity_animation.duration = animation_duration_focus; memcpy(c->opacity_animation.target_border_color, border_color, sizeof(c->opacity_animation.target_border_color)); @@ -1048,6 +1054,12 @@ void client_set_focused_opacity_animation(Client *c) { void cleint_set_unfocused_opacity_animation(Client *c) { // Start border color animation to unfocused float *border_color = get_border_color(c); + + if (!animations) { + setborder_color(c); + return; + } + c->opacity_animation.duration = animation_duration_focus; memcpy(c->opacity_animation.target_border_color, border_color, sizeof(c->opacity_animation.target_border_color)); From 48c34802f3c6b66d4e03e2cefe20069ede8c0abf Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Wed, 5 Nov 2025 16:26:11 +0800 Subject: [PATCH 304/591] fix: double create relative_pointer_manager --- src/mango.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/mango.c b/src/mango.c index 6e48eb12..f580d558 100644 --- a/src/mango.c +++ b/src/mango.c @@ -727,7 +727,6 @@ static unsigned int locked_mods = 0; static void *exclusive_focus; static struct wl_display *dpy; static struct wl_event_loop *event_loop; -static struct wlr_relative_pointer_manager_v1 *pointer_manager; static struct wlr_backend *backend; static struct wlr_backend *headless_backend; static struct wlr_scene *scene; @@ -4782,7 +4781,6 @@ void setup(void) { * clients from the Unix socket, manging Wayland globals, and so on. */ dpy = wl_display_create(); event_loop = wl_display_get_event_loop(dpy); - pointer_manager = wlr_relative_pointer_manager_v1_create(dpy); /* The backend is a wlroots feature which abstracts the underlying input * and output hardware. The autocreate option will choose the most * suitable backend based on the current environment, such as opening an From 539fd233da13b779f8624d7da74a33eb3686b56a Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Thu, 6 Nov 2025 09:14:48 +0800 Subject: [PATCH 305/591] break change: support bind flag --- src/config/parse_config.h | 39 +++++++++++++++++++++++++++++++++++---- src/mango.c | 35 +++++++++++++++++++++++++++-------- 2 files changed, 62 insertions(+), 12 deletions(-) diff --git a/src/config/parse_config.h b/src/config/parse_config.h index 7e1be635..36aa1db6 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -40,6 +40,8 @@ typedef struct { char mode[28]; bool iscommonmode; bool isdefaultmode; + bool islockapply; + bool isreleaseapply; } KeyBinding; typedef struct { @@ -410,6 +412,35 @@ char *sanitize_string(char *str) { return str; } +// 解析bind组合字符串 +void parse_bind_flags(const char *str, KeyBinding *kb) { + + // 检查是否以"bind"开头 + if (strncmp(str, "bind", 4) != 0) { + return; + } + + const char *suffix = str + 4; // 跳过"bind" + + // 遍历后缀字符 + for (int i = 0; suffix[i] != '\0'; i++) { + switch (suffix[i]) { + case 's': + kb->keysymcode.type = KEY_TYPE_SYM; + break; + case 'l': + kb->islockapply = true; + break; + case 'r': + kb->isreleaseapply = true; + break; + default: + // 忽略其他字符或可根据需要处理错误 + break; + } + } +} + int parse_circle_direction(const char *str) { // 将输入字符串转换为小写 char lowerStr[10]; @@ -1928,8 +1959,7 @@ void parse_option(Config *config, char *key, char *value) { config->exec_once_count++; - } else if (strncmp(key, "bind", 4) == 0 || - strncmp(key, "bindsym", 7) == 0) { + } else if (regex_match("^bind[s|l|r]*$", key)) { config->key_bindings = realloc(config->key_bindings, (config->key_bindings_count + 1) * sizeof(KeyBinding)); @@ -1975,9 +2005,9 @@ void parse_option(Config *config, char *key, char *value) { binding->iscommonmode = false; } + parse_bind_flags(key, binding); + binding->keysymcode = parse_key(keysym_str, binding->keysymcode.type); binding->mod = parse_mod(mod_str); - binding->keysymcode = - parse_key(keysym_str, strncmp(key, "bindsym", 7) == 0); binding->arg.v = NULL; binding->arg.v2 = NULL; binding->arg.v3 = NULL; @@ -2930,6 +2960,7 @@ void set_default_key_bindings(Config *config) { default_key_bindings[i]; config->key_bindings[config->key_bindings_count + i].iscommonmode = true; + config->key_bindings[config->key_bindings_count + i].islockapply = true; } // 更新按键绑定的总数 diff --git a/src/mango.c b/src/mango.c index f580d558..7ce58314 100644 --- a/src/mango.c +++ b/src/mango.c @@ -558,8 +558,8 @@ static void gpureset(struct wl_listener *listener, void *data); static int keyrepeat(void *data); static void inputdevice(struct wl_listener *listener, void *data); -static int keybinding(unsigned int mods, xkb_keysym_t sym, - unsigned int keycode); +static int keybinding(unsigned int state, bool locked, unsigned int mods, + xkb_keysym_t sym, unsigned int keycode); static void keypress(struct wl_listener *listener, void *data); static void keypressmod(struct wl_listener *listener, void *data); static bool keypressglobal(struct wlr_surface *last_surface, @@ -3241,13 +3241,15 @@ int keyrepeat(void *data) { 1000 / group->wlr_group->keyboard.repeat_info.rate); for (i = 0; i < group->nsyms; i++) - keybinding(group->mods, group->keysyms[i], group->keycode); + keybinding(WL_KEYBOARD_KEY_STATE_PRESSED, false, group->mods, + group->keysyms[i], group->keycode); return 0; } int // 17 -keybinding(unsigned int mods, xkb_keysym_t sym, unsigned int keycode) { +keybinding(unsigned int state, bool locked, unsigned int mods, xkb_keysym_t sym, + unsigned int keycode) { /* * Here we handle compositor keybindings. This is when the compositor is * processing keys, rather than passing them on to the client for its @@ -3266,6 +3268,22 @@ keybinding(unsigned int mods, xkb_keysym_t sym, unsigned int keycode) { for (ji = 0; ji < config.key_bindings_count; ji++) { if (config.key_bindings_count < 1) break; + + if (locked && config.key_bindings[ji].islockapply == false) + continue; + + if (state == WL_KEYBOARD_KEY_STATE_RELEASED && + config.key_bindings[ji].isreleaseapply == false) + continue; + + if (state == WL_KEYBOARD_KEY_STATE_PRESSED && + config.key_bindings[ji].isreleaseapply == true) + continue; + + if (state != WL_KEYBOARD_KEY_STATE_PRESSED && + state != WL_KEYBOARD_KEY_STATE_RELEASED) + continue; + k = &config.key_bindings[ji]; if ((k->iscommonmode || (k->isdefaultmode && keymode.isdefault) || (strcmp(keymode.mode, k->mode) == 0)) && @@ -3394,10 +3412,11 @@ void keypress(struct wl_listener *listener, void *data) { /* On _press_ if there is no active screen locker, * attempt to process a compositor keybinding. */ - if (!locked && event->state == WL_KEYBOARD_KEY_STATE_PRESSED) { - for (i = 0; i < nsyms; i++) - handled = keybinding(mods, syms[i], keycode) || handled; - } else if (event->state == WL_KEYBOARD_KEY_STATE_RELEASED) { + for (i = 0; i < nsyms; i++) + handled = + keybinding(event->state, locked, mods, syms[i], keycode) || handled; + + if (event->state == WL_KEYBOARD_KEY_STATE_RELEASED) { tag_combo = false; } From 12ab7d63eca9af4e5920ac68166bea079bda6a04 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Thu, 6 Nov 2025 11:28:21 +0800 Subject: [PATCH 306/591] opt: optimize frame skip judge --- src/mango.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mango.c b/src/mango.c index 7ce58314..2d6f1f7f 100644 --- a/src/mango.c +++ b/src/mango.c @@ -4120,9 +4120,9 @@ void rendermon(struct wl_listener *listener, void *data) { // 绘制客户端 wl_list_for_each(c, &clients, link) { need_more_frames = client_draw_frame(c) || need_more_frames; - if (!animations && !allow_tearing && c->configure_serial && - !c->isfloating && client_is_rendered_on_mon(c, m) && - !client_is_stopped(c)) { + if (!animations && !(allow_tearing && frame_allow_tearing) && + c->configure_serial && !c->isfloating && + client_is_rendered_on_mon(c, m) && !client_is_stopped(c)) { goto skip; } } From 6cf36dfa67b9396c3881e0773b7cc62f9f2ab88e Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Thu, 6 Nov 2025 13:13:08 +0800 Subject: [PATCH 307/591] project: clarify the dependent version --- meson.build | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/meson.build b/meson.build index 27b717c7..041a1fdf 100644 --- a/meson.build +++ b/meson.build @@ -32,10 +32,10 @@ cc = meson.get_compiler('c') libm = cc.find_library('m') xcb = dependency('xcb', required : get_option('xwayland')) xlibs = dependency('xcb-icccm', required : get_option('xwayland')) -wayland_server_dep = dependency('wayland-server') +wayland_server_dep = dependency('wayland-server',version: '>=1.23.1') wlroots_dep = dependency('wlroots-0.19',version: '>=0.19.0') xkbcommon_dep = dependency('xkbcommon') -libinput_dep = dependency('libinput') +libinput_dep = dependency('libinput',version: '>=1.27.1') libwayland_client_dep = dependency('wayland-client') pcre2_dep = dependency('libpcre2-8') libscenefx_dep = dependency('scenefx-0.4',version: '>=0.4.1') From 40b6f828237d2329b2f6b08e7582e1e230876dac Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Thu, 6 Nov 2025 14:14:02 +0800 Subject: [PATCH 308/591] fix: fix ov_tab_mode arg --- config.conf | 2 +- src/config/parse_config.h | 1 + src/dispatch/bind_define.h | 6 +----- src/mango.c | 2 +- 4 files changed, 4 insertions(+), 7 deletions(-) diff --git a/config.conf b/config.conf index 59e4631d..4c8d8d3a 100644 --- a/config.conf +++ b/config.conf @@ -242,7 +242,7 @@ bind=CTRL+ALT,Right,resizewin,+50,+0 mousebind=SUPER,btn_left,moveresize,curmove mousebind=NONE,btn_middle,togglemaximizescreen,0 mousebind=SUPER,btn_right,moveresize,curresize -mousebind=NONE,btn_left,toggleoverview,-1 +mousebind=NONE,btn_left,toggleoverview,1 mousebind=NONE,btn_right,killclient,0 # Axis Bindings diff --git a/src/config/parse_config.h b/src/config/parse_config.h index 36aa1db6..a20a60a5 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -880,6 +880,7 @@ FuncType parse_func_name(char *func_name, Arg *arg, char *arg_value, func = toggleglobal; } else if (strcmp(func_name, "toggleoverview") == 0) { func = toggleoverview; + (*arg).i = atoi(arg_value); } else if (strcmp(func_name, "set_proportion") == 0) { func = set_proportion; (*arg).f = atof(arg_value); diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index 57efa883..b5a44821 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -1447,7 +1447,7 @@ int minimized(const Arg *arg) { int toggleoverview(const Arg *arg) { Client *c = NULL; - if (selmon->isoverview && ov_tab_mode && arg->i != -1 && selmon->sel) { + if (selmon->isoverview && ov_tab_mode && arg->i != 1 && selmon->sel) { focusstack(&(Arg){.i = 1}); return 0; } @@ -1498,10 +1498,6 @@ int toggleoverview(const Arg *arg) { view(&(Arg){.ui = target}, false); - if (ov_tab_mode && selmon->isoverview && selmon->sel) { - focusstack(&(Arg){.i = 1}); - } - refresh_monitors_workspaces_status(selmon); return 0; } diff --git a/src/mango.c b/src/mango.c index 2d6f1f7f..e946d415 100644 --- a/src/mango.c +++ b/src/mango.c @@ -3406,7 +3406,7 @@ void keypress(struct wl_listener *listener, void *data) { keycode == 134 || keycode == 105 || keycode == 108 || keycode == 62) && selmon && selmon->sel) { if (selmon->isoverview && selmon->sel) { - toggleoverview(&(Arg){.i = -1}); + toggleoverview(&(Arg){.i = 1}); } } From 5b60999075426f18a29dbaebefafbb5ed53f905e Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Thu, 6 Nov 2025 19:01:18 +0800 Subject: [PATCH 309/591] feat: add windowrule option isnoshadow,isnoanimation --- src/animation/client.h | 7 ++++++- src/config/parse_config.h | 8 ++++++++ src/mango.c | 4 ++++ 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/animation/client.h b/src/animation/client.h index 09d14162..90b664b5 100644 --- a/src/animation/client.h +++ b/src/animation/client.h @@ -251,7 +251,7 @@ void buffer_set_effect(Client *c, BufferData data) { void client_draw_shadow(Client *c) { - if (c->iskilling || !client_surface(c)->mapped) + if (c->iskilling || !client_surface(c)->mapped || c->isnoshadow) return; if (!shadows || (!c->isfloating && shadow_only_floating)) { @@ -888,6 +888,11 @@ void client_set_pending_state(Client *c) { c->animation.duration = 0; } + if (c->isnoanimation) { + c->animation.should_animate = false; + c->animation.duration = 0; + } + // 开始动画 client_commit(c); c->dirty = true; diff --git a/src/config/parse_config.h b/src/config/parse_config.h index a20a60a5..c94e8662 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -61,6 +61,8 @@ typedef struct { const char *layer_animation_type_open; const char *layer_animation_type_close; int isnoborder; + int isnoshadow; + int isnoanimation; int isopensilent; int istagsilent; int isnamedscratchpad; @@ -1697,6 +1699,8 @@ void parse_option(Config *config, char *key, char *value) { rule->isfloating = -1; rule->isfullscreen = -1; rule->isnoborder = -1; + rule->isnoshadow = -1; + rule->isnoanimation = -1; rule->isopensilent = -1; rule->istagsilent = -1; rule->isnamedscratchpad = -1; @@ -1778,6 +1782,10 @@ void parse_option(Config *config, char *key, char *value) { rule->height = atoi(val); } else if (strcmp(key, "isnoborder") == 0) { rule->isnoborder = atoi(val); + } else if (strcmp(key, "isnoshadow") == 0) { + rule->isnoshadow = atoi(val); + } else if (strcmp(key, "isnoanimation") == 0) { + rule->isnoanimation = atoi(val); } else if (strcmp(key, "isopensilent") == 0) { rule->isopensilent = atoi(val); } else if (strcmp(key, "istagsilent") == 0) { diff --git a/src/mango.c b/src/mango.c index e946d415..f26d6f06 100644 --- a/src/mango.c +++ b/src/mango.c @@ -330,6 +330,8 @@ struct Client { int is_scratchpad_show; int isglobal; int isnoborder; + int isnoshadow; + int isnoanimation; int isopensilent; int istagsilent; int iskilling; @@ -1134,6 +1136,8 @@ static void apply_rule_properties(Client *c, const ConfigWinRule *r) { APPLY_INT_PROP(c, r, isfloating); APPLY_INT_PROP(c, r, isfullscreen); APPLY_INT_PROP(c, r, isnoborder); + APPLY_INT_PROP(c, r, isnoshadow); + APPLY_INT_PROP(c, r, isnoanimation); APPLY_INT_PROP(c, r, isopensilent); APPLY_INT_PROP(c, r, istagsilent); APPLY_INT_PROP(c, r, isnamedscratchpad); From 6bd9172fb26da0f998a8d77c67b8cc81b87c27d2 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Thu, 6 Nov 2025 19:14:13 +0800 Subject: [PATCH 310/591] opt: overview not tile isunglobal window --- src/layout/arrange.h | 3 ++- src/mango.c | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/layout/arrange.h b/src/layout/arrange.h index 69393c7e..4df97865 100644 --- a/src/layout/arrange.h +++ b/src/layout/arrange.h @@ -603,7 +603,8 @@ arrange(Monitor *m, bool want_animation) { } if (VISIBLEON(c, m)) { - m->visible_clients++; + if (!c->isunglobal) + m->visible_clients++; if (c->isfullscreen) m->has_visible_fullscreen_client = true; diff --git a/src/mango.c b/src/mango.c index f26d6f06..3a5d28bc 100644 --- a/src/mango.c +++ b/src/mango.c @@ -102,7 +102,7 @@ A->geom.y + A->geom.height <= A->mon->m.y + A->mon->m.height) #define ISTILED(A) \ (A && !(A)->isfloating && !(A)->isminied && !(A)->iskilling && \ - !(A)->ismaximizescreen && !(A)->isfullscreen) + !(A)->ismaximizescreen && !(A)->isfullscreen && !(A)->isunglobal) #define VISIBLEON(C, M) \ ((C) && (M) && (C)->mon == (M) && ((C)->tags & (M)->tagset[(M)->seltags])) #define LENGTH(X) (sizeof X / sizeof X[0]) From 474c70456264267f6882e78476e4f12badc2a68c Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Thu, 6 Nov 2025 19:45:16 +0800 Subject: [PATCH 311/591] opt: optimize xwayland focus ignore judge --- src/client/client.h | 17 ++++++++++++++++- src/dispatch/bind_define.h | 9 +++++---- src/layout/horizontal.h | 7 ++++--- src/layout/vertical.h | 7 ++++--- src/mango.c | 11 +++++------ 5 files changed, 34 insertions(+), 17 deletions(-) diff --git a/src/client/client.h b/src/client/client.h index 2b763fab..5480f62d 100644 --- a/src/client/client.h +++ b/src/client/client.h @@ -402,7 +402,22 @@ static inline void client_set_suspended(Client *c, int suspended) { wlr_xdg_toplevel_set_suspended(c->surface.xdg->toplevel, suspended); } -static inline int client_should_ignore_focus(Client *c) { +static inline int client_should_ignore_focus_always(Client *c) { + +#ifdef XWAYLAND + if (client_is_x11(c)) { + struct wlr_xwayland_surface *surface = c->surface.xwayland; + + if (!surface->hints) + return 0; + + return !surface->hints->input; + } +#endif + return 0; +} + +static inline int client_should_ignore_focus_open(Client *c) { #ifdef XWAYLAND if (client_is_x11(c)) { diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index b5a44821..bc43ef1e 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -131,7 +131,7 @@ int focuslast(const Arg *arg) { wl_list_for_each(c, &fstack, flink) { if (c->iskilling || c->isminied || c->isunglobal || !client_surface(c)->mapped || client_is_unmanaged(c) || - client_should_ignore_focus(c)) + client_should_ignore_focus_open(c)) continue; if (selmon && !selmon->sel) { @@ -1460,7 +1460,7 @@ int toggleoverview(const Arg *arg) { wl_list_for_each(c, &clients, link) if (c && c->mon == selmon && !client_is_unmanaged(c) && - !client_should_ignore_focus(c) && + !client_should_ignore_focus_open(c) && !c->isminied && !c->isunglobal) { visible_client_number++; } @@ -1484,14 +1484,15 @@ int toggleoverview(const Arg *arg) { if (selmon->isoverview) { wl_list_for_each(c, &clients, link) { if (c && c->mon == selmon && !client_is_unmanaged(c) && - !client_should_ignore_focus(c) && !c->isunglobal) + !client_should_ignore_focus_open(c) && !c->isunglobal) overview_backup(c); } } else { wl_list_for_each(c, &clients, link) { if (c && c->mon == selmon && !c->iskilling && !client_is_unmanaged(c) && !c->isunglobal && - !client_should_ignore_focus(c) && client_surface(c)->mapped) + !client_should_ignore_focus_open(c) && + client_surface(c)->mapped) overview_restore(c, &(Arg){.ui = target}); } } diff --git a/src/layout/horizontal.h b/src/layout/horizontal.h index 3a376b50..9090688c 100644 --- a/src/layout/horizontal.h +++ b/src/layout/horizontal.h @@ -28,7 +28,7 @@ void grid(Monitor *m) { ? 0 : borderpx; if (VISIBLEON(c, m) && !c->isunglobal && - ((m->isoverview && !client_should_ignore_focus(c)) || + ((m->isoverview && !client_should_ignore_focus_open(c)) || ISTILED(c))) { cw = (m->w.width - 2 * target_gappo) * single_width_ratio; ch = (m->w.height - 2 * target_gappo) * single_height_ratio; @@ -55,7 +55,7 @@ void grid(Monitor *m) { ? 0 : borderpx; if (VISIBLEON(c, m) && !c->isunglobal && - ((m->isoverview && !client_should_ignore_focus(c)) || + ((m->isoverview && !client_should_ignore_focus_open(c)) || ISTILED(c))) { if (i == 0) { c->geom.x = m->w.x + target_gappo; @@ -106,7 +106,8 @@ void grid(Monitor *m) { ? 0 : borderpx; if (VISIBLEON(c, m) && !c->isunglobal && - ((m->isoverview && !client_should_ignore_focus(c)) || ISTILED(c))) { + ((m->isoverview && !client_should_ignore_focus_open(c)) || + ISTILED(c))) { cx = m->w.x + (i % cols) * (cw + target_gappi); cy = m->w.y + (i / cols) * (ch + target_gappi); if (overcols && i >= n - overcols) { diff --git a/src/layout/vertical.h b/src/layout/vertical.h index 7e1df68f..585c2f0f 100644 --- a/src/layout/vertical.h +++ b/src/layout/vertical.h @@ -310,7 +310,7 @@ void vertical_grid(Monitor *m) { ? 0 : borderpx; if (VISIBLEON(c, m) && !c->isunglobal && - ((m->isoverview && !client_should_ignore_focus(c)) || + ((m->isoverview && !client_should_ignore_focus_open(c)) || ISTILED(c))) { ch = (m->w.height - 2 * target_gappo) * single_height_ratio; cw = (m->w.width - 2 * target_gappo) * single_width_ratio; @@ -338,7 +338,7 @@ void vertical_grid(Monitor *m) { ? 0 : borderpx; if (VISIBLEON(c, m) && !c->isunglobal && - ((m->isoverview && !client_should_ignore_focus(c)) || + ((m->isoverview && !client_should_ignore_focus_open(c)) || ISTILED(c))) { if (i == 0) { c->geom.x = m->w.x + (m->w.width - cw) / 2 + target_gappo; @@ -385,7 +385,8 @@ void vertical_grid(Monitor *m) { ? 0 : borderpx; if (VISIBLEON(c, m) && !c->isunglobal && - ((m->isoverview && !client_should_ignore_focus(c)) || ISTILED(c))) { + ((m->isoverview && !client_should_ignore_focus_open(c)) || + ISTILED(c))) { cx = m->w.x + (i / rows) * (cw + target_gappi); cy = m->w.y + (i % rows) * (ch + target_gappi); if (overrows && i >= n - overrows) { diff --git a/src/mango.c b/src/mango.c index 3a5d28bc..061d39a5 100644 --- a/src/mango.c +++ b/src/mango.c @@ -1305,7 +1305,7 @@ void applyrules(Client *c) { // if no geom rule hit and is normal winodw, use the center pos and record // the hit size if (!hit_rule_pos && - (!client_is_x11(c) || !client_should_ignore_focus(c))) { + (!client_is_x11(c) || !client_should_ignore_focus_open(c))) { c->float_geom = c->geom = setclient_coordinate_center(c, c->geom, 0, 0); } @@ -3080,9 +3080,8 @@ void focusclient(Client *c, int lift) { if (c && !client_surface(c)->mapped) return; - if (c && client_should_ignore_focus(c)) { + if (c && client_should_ignore_focus_always(c)) return; - } /* Raise client in stacking order if requested */ if (c && lift) @@ -3598,7 +3597,7 @@ mapnotify(struct wl_listener *listener, void *data) { init_client_properties(c); // set special window properties - if (client_is_unmanaged(c) || client_should_ignore_focus(c)) { + if (client_is_unmanaged(c) || client_should_ignore_focus_open(c)) { c->bw = 0; c->isnoborder = 1; } else { @@ -4399,7 +4398,7 @@ setfloating(Client *c, int floating) { } // 重新计算居中的坐标 - if (!client_is_x11(c) || !client_should_ignore_focus(c)) + if (!client_is_x11(c) || !client_should_ignore_focus_open(c)) target_box = setclient_coordinate_center(c, target_box, 0, 0); backup_box = c->geom; hit = applyrulesgeom(c); @@ -4708,7 +4707,7 @@ void setmon(Client *c, Monitor *m, unsigned int newtags, bool focus) { setfullscreen(c, c->isfullscreen); /* This will call arrange(c->mon) */ } - if (focus) { + if (focus && !client_should_ignore_focus_open(c)) { focusclient(focustop(selmon), 1); } From 5bbe6c5c1ae30453360522fde7810a8bb140670e Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Thu, 6 Nov 2025 21:10:11 +0800 Subject: [PATCH 312/591] fix: binds not work --- src/config/parse_config.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/config/parse_config.h b/src/config/parse_config.h index c94e8662..19e64b70 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -18,7 +18,7 @@ enum { NUM_TYPE_MINUS, NUM_TYPE_PLUS, NUM_TYPE_DEFAULT }; -enum { KEY_TYPE_SYM, KEY_TYPE_CODE }; +enum { KEY_TYPE_CODE, KEY_TYPE_SYM }; typedef struct { uint32_t keycode1; @@ -2015,7 +2015,8 @@ void parse_option(Config *config, char *key, char *value) { } parse_bind_flags(key, binding); - binding->keysymcode = parse_key(keysym_str, binding->keysymcode.type); + binding->keysymcode = + parse_key(keysym_str, binding->keysymcode.type == KEY_TYPE_SYM); binding->mod = parse_mod(mod_str); binding->arg.v = NULL; binding->arg.v2 = NULL; From df46194b5f720eaa9650e16d316a2bb340d424f8 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Fri, 7 Nov 2025 11:34:12 +0800 Subject: [PATCH 313/591] opt: optimize x11 popup focus ignore --- src/client/client.h | 4 ++-- src/dispatch/bind_define.h | 17 ++++++++--------- src/layout/horizontal.h | 9 +++------ src/layout/vertical.h | 9 +++------ src/mango.c | 11 +++++------ 5 files changed, 21 insertions(+), 29 deletions(-) diff --git a/src/client/client.h b/src/client/client.h index 5480f62d..06f629de 100644 --- a/src/client/client.h +++ b/src/client/client.h @@ -402,7 +402,7 @@ static inline void client_set_suspended(Client *c, int suspended) { wlr_xdg_toplevel_set_suspended(c->surface.xdg->toplevel, suspended); } -static inline int client_should_ignore_focus_always(Client *c) { +static inline int client_should_ignore_focus(Client *c) { #ifdef XWAYLAND if (client_is_x11(c)) { @@ -417,7 +417,7 @@ static inline int client_should_ignore_focus_always(Client *c) { return 0; } -static inline int client_should_ignore_focus_open(Client *c) { +static inline int client_is_x11_popup(Client *c) { #ifdef XWAYLAND if (client_is_x11(c)) { diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index bc43ef1e..57288b4c 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -131,7 +131,7 @@ int focuslast(const Arg *arg) { wl_list_for_each(c, &fstack, flink) { if (c->iskilling || c->isminied || c->isunglobal || !client_surface(c)->mapped || client_is_unmanaged(c) || - client_should_ignore_focus_open(c)) + client_is_x11_popup(c)) continue; if (selmon && !selmon->sel) { @@ -1457,11 +1457,11 @@ int toggleoverview(const Arg *arg) { unsigned int visible_client_number = 0; if (selmon->isoverview) { - wl_list_for_each(c, &clients, - link) if (c && c->mon == selmon && - !client_is_unmanaged(c) && - !client_should_ignore_focus_open(c) && - !c->isminied && !c->isunglobal) { + wl_list_for_each(c, &clients, link) if (c && c->mon == selmon && + !client_is_unmanaged(c) && + !client_is_x11_popup(c) && + !c->isminied && + !c->isunglobal) { visible_client_number++; } if (visible_client_number > 0) { @@ -1484,15 +1484,14 @@ int toggleoverview(const Arg *arg) { if (selmon->isoverview) { wl_list_for_each(c, &clients, link) { if (c && c->mon == selmon && !client_is_unmanaged(c) && - !client_should_ignore_focus_open(c) && !c->isunglobal) + !client_is_x11_popup(c) && !c->isunglobal) overview_backup(c); } } else { wl_list_for_each(c, &clients, link) { if (c && c->mon == selmon && !c->iskilling && !client_is_unmanaged(c) && !c->isunglobal && - !client_should_ignore_focus_open(c) && - client_surface(c)->mapped) + !client_is_x11_popup(c) && client_surface(c)->mapped) overview_restore(c, &(Arg){.ui = target}); } } diff --git a/src/layout/horizontal.h b/src/layout/horizontal.h index 9090688c..b2d76bb3 100644 --- a/src/layout/horizontal.h +++ b/src/layout/horizontal.h @@ -28,8 +28,7 @@ void grid(Monitor *m) { ? 0 : borderpx; if (VISIBLEON(c, m) && !c->isunglobal && - ((m->isoverview && !client_should_ignore_focus_open(c)) || - ISTILED(c))) { + ((m->isoverview && !client_is_x11_popup(c)) || ISTILED(c))) { cw = (m->w.width - 2 * target_gappo) * single_width_ratio; ch = (m->w.height - 2 * target_gappo) * single_height_ratio; c->geom.x = m->w.x + (m->w.width - cw) / 2; @@ -55,8 +54,7 @@ void grid(Monitor *m) { ? 0 : borderpx; if (VISIBLEON(c, m) && !c->isunglobal && - ((m->isoverview && !client_should_ignore_focus_open(c)) || - ISTILED(c))) { + ((m->isoverview && !client_is_x11_popup(c)) || ISTILED(c))) { if (i == 0) { c->geom.x = m->w.x + target_gappo; c->geom.y = m->w.y + (m->w.height - ch) / 2 + target_gappo; @@ -106,8 +104,7 @@ void grid(Monitor *m) { ? 0 : borderpx; if (VISIBLEON(c, m) && !c->isunglobal && - ((m->isoverview && !client_should_ignore_focus_open(c)) || - ISTILED(c))) { + ((m->isoverview && !client_is_x11_popup(c)) || ISTILED(c))) { cx = m->w.x + (i % cols) * (cw + target_gappi); cy = m->w.y + (i / cols) * (ch + target_gappi); if (overcols && i >= n - overcols) { diff --git a/src/layout/vertical.h b/src/layout/vertical.h index 585c2f0f..3c744639 100644 --- a/src/layout/vertical.h +++ b/src/layout/vertical.h @@ -310,8 +310,7 @@ void vertical_grid(Monitor *m) { ? 0 : borderpx; if (VISIBLEON(c, m) && !c->isunglobal && - ((m->isoverview && !client_should_ignore_focus_open(c)) || - ISTILED(c))) { + ((m->isoverview && !client_is_x11_popup(c)) || ISTILED(c))) { ch = (m->w.height - 2 * target_gappo) * single_height_ratio; cw = (m->w.width - 2 * target_gappo) * single_width_ratio; c->geom.x = m->w.x + (m->w.width - cw) / 2; @@ -338,8 +337,7 @@ void vertical_grid(Monitor *m) { ? 0 : borderpx; if (VISIBLEON(c, m) && !c->isunglobal && - ((m->isoverview && !client_should_ignore_focus_open(c)) || - ISTILED(c))) { + ((m->isoverview && !client_is_x11_popup(c)) || ISTILED(c))) { if (i == 0) { c->geom.x = m->w.x + (m->w.width - cw) / 2 + target_gappo; c->geom.y = m->w.y + target_gappo; @@ -385,8 +383,7 @@ void vertical_grid(Monitor *m) { ? 0 : borderpx; if (VISIBLEON(c, m) && !c->isunglobal && - ((m->isoverview && !client_should_ignore_focus_open(c)) || - ISTILED(c))) { + ((m->isoverview && !client_is_x11_popup(c)) || ISTILED(c))) { cx = m->w.x + (i / rows) * (cw + target_gappi); cy = m->w.y + (i % rows) * (ch + target_gappi); if (overrows && i >= n - overrows) { diff --git a/src/mango.c b/src/mango.c index 061d39a5..36cbbbfa 100644 --- a/src/mango.c +++ b/src/mango.c @@ -1304,8 +1304,7 @@ void applyrules(Client *c) { // if no geom rule hit and is normal winodw, use the center pos and record // the hit size - if (!hit_rule_pos && - (!client_is_x11(c) || !client_should_ignore_focus_open(c))) { + if (!hit_rule_pos && (!client_is_x11(c) || !client_is_x11_popup(c))) { c->float_geom = c->geom = setclient_coordinate_center(c, c->geom, 0, 0); } @@ -3080,7 +3079,7 @@ void focusclient(Client *c, int lift) { if (c && !client_surface(c)->mapped) return; - if (c && client_should_ignore_focus_always(c)) + if (c && client_should_ignore_focus(c) && client_is_x11_popup(c)) return; /* Raise client in stacking order if requested */ @@ -3597,7 +3596,7 @@ mapnotify(struct wl_listener *listener, void *data) { init_client_properties(c); // set special window properties - if (client_is_unmanaged(c) || client_should_ignore_focus_open(c)) { + if (client_is_unmanaged(c) || client_is_x11_popup(c)) { c->bw = 0; c->isnoborder = 1; } else { @@ -4398,7 +4397,7 @@ setfloating(Client *c, int floating) { } // 重新计算居中的坐标 - if (!client_is_x11(c) || !client_should_ignore_focus_open(c)) + if (!client_is_x11(c) || !client_is_x11_popup(c)) target_box = setclient_coordinate_center(c, target_box, 0, 0); backup_box = c->geom; hit = applyrulesgeom(c); @@ -4707,7 +4706,7 @@ void setmon(Client *c, Monitor *m, unsigned int newtags, bool focus) { setfullscreen(c, c->isfullscreen); /* This will call arrange(c->mon) */ } - if (focus && !client_should_ignore_focus_open(c)) { + if (focus && !client_is_x11_popup(c)) { focusclient(focustop(selmon), 1); } From 1029936b18f9e40be424ad1d542573f4c79398b4 Mon Sep 17 00:00:00 2001 From: eater <=@eater.me> Date: Fri, 7 Nov 2025 15:44:47 +0100 Subject: [PATCH 314/591] check is drm_release_manager is set before cleaning up to avoid segfault --- src/mango.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/mango.c b/src/mango.c index 36cbbbfa..09625204 100644 --- a/src/mango.c +++ b/src/mango.c @@ -1964,7 +1964,9 @@ void cleanuplisteners(void) { wl_list_remove(&request_start_drag.link); wl_list_remove(&start_drag.link); wl_list_remove(&new_session_lock.link); - wl_list_remove(&drm_lease_request.link); + if (drm_lease_manager) { + wl_list_remove(&drm_lease_request.link); + } wl_list_remove(&tearing_new_object.link); #ifdef XWAYLAND wl_list_remove(&new_xwayland_surface.link); From e0bc7fb5e47c545ce15e2be012a6c18b76894a55 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Fri, 7 Nov 2025 21:56:25 +0800 Subject: [PATCH 315/591] fix: crash when click waybar overview button --- src/ext-protocol/ext-workspace.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/ext-protocol/ext-workspace.h b/src/ext-protocol/ext-workspace.h index 61e36da3..930e6c98 100644 --- a/src/ext-protocol/ext-workspace.h +++ b/src/ext-protocol/ext-workspace.h @@ -47,6 +47,11 @@ static void handle_ext_workspace_activate(struct wl_listener *listener, void *data) { struct workspace *workspace = wl_container_of(listener, workspace, activate); + + if (workspace->m->isoverview) { + return; + } + goto_workspace(workspace); wlr_log(WLR_INFO, "ext activating workspace %d", workspace->tag); } @@ -55,6 +60,11 @@ static void handle_ext_workspace_deactivate(struct wl_listener *listener, void *data) { struct workspace *workspace = wl_container_of(listener, workspace, deactivate); + + if (workspace->m->isoverview) { + return; + } + toggle_workspace(workspace); wlr_log(WLR_INFO, "ext deactivating workspace %d", workspace->tag); } From 9d6436cf42e89835f40664d5aa93c44b016ed679 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Wed, 12 Nov 2025 12:55:06 +0800 Subject: [PATCH 316/591] feat: support keyboard shortcut inhibitor --- src/config/parse_config.h | 9 ++++ src/config/preset.h | 1 + src/mango.c | 88 ++++++++++++++++++++++++++++++++++++++- 3 files changed, 97 insertions(+), 1 deletion(-) diff --git a/src/config/parse_config.h b/src/config/parse_config.h index 0e9e15c5..a71d4f1e 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -69,6 +69,7 @@ typedef struct { int isunglobal; int isglobal; int isoverlay; + int allow_shortcuts_inhibit; int ignore_maximize; int ignore_minimize; int isnosizehint; @@ -336,6 +337,7 @@ typedef struct { int syncobj_enable; int adaptive_sync; int allow_tearing; + int allow_shortcuts_inhibit; struct xkb_rule_names xkb_rules; @@ -1271,6 +1273,8 @@ void parse_option(Config *config, char *key, char *value) { config->adaptive_sync = atoi(value); } else if (strcmp(key, "allow_tearing") == 0) { config->allow_tearing = atoi(value); + } else if (strcmp(key, "allow_shortcuts_inhibit") == 0) { + config->allow_shortcuts_inhibit = atoi(value); } else if (strcmp(key, "no_border_when_single") == 0) { config->no_border_when_single = atoi(value); } else if (strcmp(key, "no_radius_when_single") == 0) { @@ -1708,6 +1712,7 @@ void parse_option(Config *config, char *key, char *value) { rule->isunglobal = -1; rule->isglobal = -1; rule->isoverlay = -1; + rule->allow_shortcuts_inhibit = -1; rule->ignore_maximize = -1; rule->ignore_minimize = -1; rule->isnosizehint = -1; @@ -1806,6 +1811,8 @@ void 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, "allow_shortcuts_inhibit") == 0) { + rule->allow_shortcuts_inhibit = atoi(val); } else if (strcmp(key, "ignore_maximize") == 0) { rule->ignore_maximize = atoi(val); } else if (strcmp(key, "ignore_minimize") == 0) { @@ -2696,6 +2703,7 @@ void override_config(void) { syncobj_enable = CLAMP_INT(config.syncobj_enable, 0, 1); adaptive_sync = CLAMP_INT(config.adaptive_sync, 0, 1); allow_tearing = CLAMP_INT(config.allow_tearing, 0, 2); + allow_shortcuts_inhibit = CLAMP_INT(config.allow_shortcuts_inhibit, 0, 1); axis_bind_apply_timeout = CLAMP_INT(config.axis_bind_apply_timeout, 0, 1000); focus_on_activate = CLAMP_INT(config.focus_on_activate, 0, 1); @@ -2873,6 +2881,7 @@ void set_value_default() { config.syncobj_enable = syncobj_enable; config.adaptive_sync = adaptive_sync; config.allow_tearing = allow_tearing; + config.allow_shortcuts_inhibit = allow_shortcuts_inhibit; config.no_border_when_single = no_border_when_single; config.no_radius_when_single = no_radius_when_single; config.snap_distance = snap_distance; diff --git a/src/config/preset.h b/src/config/preset.h index be1c1b0a..eaa7be22 100644 --- a/src/config/preset.h +++ b/src/config/preset.h @@ -105,6 +105,7 @@ int syncobj_enable = 0; int adaptive_sync = 0; double drag_refresh_interval = 30.0; int allow_tearing = TEARING_DISABLED; +int allow_shortcuts_inhibit = SHORTCUTS_INHIBIT_ENABLE; /* keyboard */ diff --git a/src/mango.c b/src/mango.c index 7ad9aa6f..6a66d0a4 100644 --- a/src/mango.c +++ b/src/mango.c @@ -48,6 +48,7 @@ #include #include #include +#include #include #include #include @@ -172,6 +173,11 @@ enum tearing_mode { TEARING_FULLSCREEN_ONLY, }; +enum seat_config_shortcuts_inhibit { + SHORTCUTS_INHIBIT_DISABLE, + SHORTCUTS_INHIBIT_ENABLE, +}; + typedef struct Pertag Pertag; typedef struct Monitor Monitor; typedef struct Client Client; @@ -369,6 +375,7 @@ struct Client { bool isleftstack; int tearing_hint; int force_tearing; + int allow_shortcuts_inhibit; }; typedef struct { @@ -398,6 +405,12 @@ typedef struct { struct wl_listener destroy; } KeyboardGroup; +typedef struct { + struct wlr_keyboard_shortcuts_inhibitor_v1 *inhibitor; + struct wl_listener destroy; + struct wl_list link; +} KeyboardShortcutsInhibitor; + typedef struct { /* Must keep these three elements in this order */ unsigned int type; /* LayerShell */ @@ -622,7 +635,9 @@ static void urgent(struct wl_listener *listener, void *data); static void view(const Arg *arg, bool want_animation); static void handlesig(int signo); - +static void +handle_keyboard_shortcuts_inhibit_new_inhibitor(struct wl_listener *listener, + void *data); static void virtualkeyboard(struct wl_listener *listener, void *data); static void virtualpointer(struct wl_listener *listener, void *data); static void warp_cursor(const Client *c); @@ -750,6 +765,8 @@ static struct wlr_idle_inhibit_manager_v1 *idle_inhibit_mgr; static struct wlr_layer_shell_v1 *layer_shell; static struct wlr_output_manager_v1 *output_mgr; static struct wlr_virtual_keyboard_manager_v1 *virtual_keyboard_mgr; +static struct wlr_keyboard_shortcuts_inhibit_manager_v1 + *keyboard_shortcuts_inhibit; static struct wlr_virtual_pointer_manager_v1 *virtual_pointer_mgr; static struct wlr_output_power_manager_v1 *power_mgr; static struct wlr_pointer_gestures_v1 *pointer_gestures; @@ -773,6 +790,7 @@ static struct wlr_pointer_constraint_v1 *active_constraint; static struct wlr_seat *seat; static KeyboardGroup *kb_group; static struct wl_list inputdevices; +static struct wl_list keyboard_shortcut_inhibitors; static unsigned int cursor_mode; static Client *grabc; static int grabcx, grabcy; /* client-relative */ @@ -859,6 +877,8 @@ static struct wl_listener request_start_drag = {.notify = requeststartdrag}; static struct wl_listener start_drag = {.notify = startdrag}; static struct wl_listener new_session_lock = {.notify = locksession}; static struct wl_listener drm_lease_request = {.notify = requestdrmlease}; +static struct wl_listener keyboard_shortcuts_inhibit_new_inhibitor = { + .notify = handle_keyboard_shortcuts_inhibit_new_inhibitor}; #ifdef XWAYLAND static void activatex11(struct wl_listener *listener, void *data); @@ -1150,6 +1170,7 @@ static void apply_rule_properties(Client *c, const ConfigWinRule *r) { APPLY_INT_PROP(c, r, isnosizehint); APPLY_INT_PROP(c, r, isunglobal); APPLY_INT_PROP(c, r, noblur); + APPLY_INT_PROP(c, r, allow_shortcuts_inhibit); APPLY_FLOAT_PROP(c, r, scroller_proportion); APPLY_FLOAT_PROP(c, r, focused_opacity); @@ -1977,6 +1998,7 @@ void cleanuplisteners(void) { wl_list_remove(&start_drag.link); wl_list_remove(&new_session_lock.link); wl_list_remove(&tearing_new_object.link); + wl_list_remove(&keyboard_shortcuts_inhibit_new_inhibitor.link); if (drm_lease_manager) { wl_list_remove(&drm_lease_request.link); } @@ -3266,6 +3288,17 @@ int keyrepeat(void *data) { return 0; } +bool is_keyboard_shortcut_inhibitor(struct wlr_surface *surface) { + KeyboardShortcutsInhibitor *kbsinhibitor; + + wl_list_for_each(kbsinhibitor, &keyboard_shortcut_inhibitors, link) { + if (kbsinhibitor->inhibitor->surface == surface) { + return true; + } + } + return false; +} + int // 17 keybinding(unsigned int state, bool locked, unsigned int mods, xkb_keysym_t sym, unsigned int keycode) { @@ -3284,6 +3317,10 @@ keybinding(unsigned int state, bool locked, unsigned int mods, xkb_keysym_t sym, keycode == 62 || keycode == 108 || keycode == 105 || keycode == 134) return false; + if (is_keyboard_shortcut_inhibitor(seat->keyboard_state.focused_surface)) { + return false; + } + for (ji = 0; ji < config.key_bindings_count; ji++) { if (config.key_bindings_count < 1) break; @@ -3591,6 +3628,7 @@ void init_client_properties(Client *c) { c->allow_csd = 0; c->force_maximize = 0; c->force_tearing = 0; + c->allow_shortcuts_inhibit = SHORTCUTS_INHIBIT_ENABLE; } void // old fix to 0.5 @@ -5003,6 +5041,7 @@ void setup(void) { * to let us know when new input devices are available on the backend. */ wl_list_init(&inputdevices); + wl_list_init(&keyboard_shortcut_inhibitors); wl_signal_add(&backend->events.new_input, &new_input_device); virtual_keyboard_mgr = wlr_virtual_keyboard_manager_v1_create(dpy); wl_signal_add(&virtual_keyboard_mgr->events.new_virtual_keyboard, @@ -5032,6 +5071,10 @@ void setup(void) { kb_group = createkeyboardgroup(); wl_list_init(&kb_group->destroy.link); + keyboard_shortcuts_inhibit = wlr_keyboard_shortcuts_inhibit_v1_create(dpy); + wl_signal_add(&keyboard_shortcuts_inhibit->events.new_inhibitor, + &keyboard_shortcuts_inhibit_new_inhibitor); + output_mgr = wlr_output_manager_v1_create(dpy); wl_signal_add(&output_mgr->events.apply, &output_mgr_apply); wl_signal_add(&output_mgr->events.test, &output_mgr_test); @@ -5559,6 +5602,49 @@ void view(const Arg *arg, bool want_animation) { } } +static void +handle_keyboard_shortcuts_inhibitor_destroy(struct wl_listener *listener, + void *data) { + KeyboardShortcutsInhibitor *inhibitor = + wl_container_of(listener, inhibitor, destroy); + + wlr_log(WLR_DEBUG, "Removing keyboard shortcuts inhibitor"); + + wl_list_remove(&inhibitor->link); + wl_list_remove(&inhibitor->destroy.link); + free(inhibitor); +} + +void handle_keyboard_shortcuts_inhibit_new_inhibitor( + struct wl_listener *listener, void *data) { + + struct wlr_keyboard_shortcuts_inhibitor_v1 *inhibitor = data; + + if (allow_shortcuts_inhibit == SHORTCUTS_INHIBIT_DISABLE) { + return; + } + + // per-view, seat-agnostic config via criteria + Client *c = get_client_from_surface(inhibitor->surface); + if (c && !c->allow_shortcuts_inhibit) { + return; + } + + wlr_log(WLR_DEBUG, "Adding keyboard shortcuts inhibitor"); + + KeyboardShortcutsInhibitor *kbsinhibitor = + calloc(1, sizeof(KeyboardShortcutsInhibitor)); + + kbsinhibitor->inhibitor = inhibitor; + + kbsinhibitor->destroy.notify = handle_keyboard_shortcuts_inhibitor_destroy; + wl_signal_add(&inhibitor->events.destroy, &kbsinhibitor->destroy); + + wl_list_insert(&keyboard_shortcut_inhibitors, &kbsinhibitor->link); + + wlr_keyboard_shortcuts_inhibitor_v1_activate(inhibitor); +} + void virtualkeyboard(struct wl_listener *listener, void *data) { struct wlr_virtual_keyboard_v1 *kb = data; /* virtual keyboards shouldn't share keyboard group */ From 18ad32384b1ab75c2e92d42b4d8775ff11c31d2e Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sat, 8 Nov 2025 10:35:16 +0800 Subject: [PATCH 317/591] feat: add global option scroller_ignore_proportion_single --- src/config/parse_config.h | 7 +++++++ src/config/preset.h | 1 + src/layout/horizontal.h | 6 +++++- src/layout/vertical.h | 9 ++++++++- 4 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/config/parse_config.h b/src/config/parse_config.h index 19e64b70..30e118e8 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -193,6 +193,7 @@ typedef struct { int scroller_structs; float scroller_default_proportion; float scroller_default_proportion_single; + int scroller_ignore_proportion_single; int scroller_focus_center; int scroller_prefer_center; int edge_scroller_pointer_focus; @@ -1210,6 +1211,8 @@ void parse_option(Config *config, char *key, char *value) { config->scroller_default_proportion = atof(value); } else if (strcmp(key, "scroller_default_proportion_single") == 0) { config->scroller_default_proportion_single = atof(value); + } else if (strcmp(key, "scroller_ignore_proportion_single") == 0) { + config->scroller_ignore_proportion_single = atoi(value); } else if (strcmp(key, "scroller_focus_center") == 0) { config->scroller_focus_center = atoi(value); } else if (strcmp(key, "scroller_prefer_center") == 0) { @@ -2665,6 +2668,8 @@ void override_config(void) { CLAMP_FLOAT(config.scroller_default_proportion, 0.1f, 1.0f); scroller_default_proportion_single = CLAMP_FLOAT(config.scroller_default_proportion_single, 0.1f, 1.0f); + scroller_ignore_proportion_single = + CLAMP_INT(config.scroller_ignore_proportion_single, 0, 1); scroller_focus_center = CLAMP_INT(config.scroller_focus_center, 0, 1); scroller_prefer_center = CLAMP_INT(config.scroller_prefer_center, 0, 1); edge_scroller_pointer_focus = @@ -2852,6 +2857,8 @@ void set_value_default() { config.scroller_default_proportion = scroller_default_proportion; config.scroller_default_proportion_single = scroller_default_proportion_single; + config.scroller_ignore_proportion_single = + scroller_ignore_proportion_single; config.scroller_focus_center = scroller_focus_center; config.scroller_prefer_center = scroller_prefer_center; config.edge_scroller_pointer_focus = edge_scroller_pointer_focus; diff --git a/src/config/preset.h b/src/config/preset.h index 2f994ec1..be1c1b0a 100644 --- a/src/config/preset.h +++ b/src/config/preset.h @@ -60,6 +60,7 @@ float scratchpad_height_ratio = 0.9; int scroller_structs = 20; float scroller_default_proportion = 0.9; float scroller_default_proportion_single = 1.0; +int scroller_ignore_proportion_single = 0; int scroller_focus_center = 0; int scroller_prefer_center = 0; int focus_cross_monitor = 0; diff --git a/src/layout/horizontal.h b/src/layout/horizontal.h index b2d76bb3..178ae9e0 100644 --- a/src/layout/horizontal.h +++ b/src/layout/horizontal.h @@ -231,7 +231,7 @@ void scroller(Monitor *m) { } } - if (n == 1) { + if (n == 1 && !scroller_ignore_proportion_single) { c = tempClients[0]; target_geom.height = m->w.height - 2 * cur_gappov; target_geom.width = @@ -274,6 +274,10 @@ void scroller(Monitor *m) { } } + if (n == 1 && scroller_ignore_proportion_single) { + need_scroller = true; + } + if (start_drag_window) need_scroller = false; diff --git a/src/layout/vertical.h b/src/layout/vertical.h index 3c744639..6ae21a6c 100644 --- a/src/layout/vertical.h +++ b/src/layout/vertical.h @@ -192,7 +192,7 @@ void vertical_scroller(Monitor *m) { } } - if (n == 1) { + if (n == 1 && !scroller_ignore_proportion_single) { c = tempClients[0]; target_geom.width = m->w.width - 2 * cur_gappoh; target_geom.height = @@ -235,6 +235,13 @@ void vertical_scroller(Monitor *m) { } } + if (n == 1 && scroller_ignore_proportion_single) { + need_scroller = true; + } + + if (start_drag_window) + need_scroller = false; + target_geom.width = m->w.width - 2 * cur_gappoh; target_geom.height = max_client_height * c->scroller_proportion; target_geom.x = m->w.x + (m->w.width - target_geom.width) / 2; From d32fecfd2375ec9f89662b224230e23c13447be3 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Wed, 12 Nov 2025 23:10:09 +0800 Subject: [PATCH 318/591] fix: crash in some crossmon dispatch --- src/dispatch/bind_define.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index 65c2b03e..168852f4 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -971,7 +971,7 @@ int tag(const Arg *arg) { } int tagmon(const Arg *arg) { - Monitor *m = NULL; + Monitor *m = NULL,*cm = NULL; Client *c = focustop(selmon); if (!c) @@ -980,11 +980,12 @@ int tagmon(const Arg *arg) { if (arg->i != UNDIR) { m = dirtomon(arg->i); } else if (arg->v) { - wl_list_for_each(m, &mons, link) { - if (!m->wlr_output->enabled) { + wl_list_for_each(cm, &mons, link) { + if (!cm->wlr_output->enabled) { continue; } - if (regex_match(arg->v, m->wlr_output->name)) { + if (regex_match(arg->v, cm->wlr_output->name)) { + m = cm; break; } } From 5774df00e09d43ffe6148e6c84541a31793786bf Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sat, 8 Nov 2025 12:39:41 +0800 Subject: [PATCH 319/591] opt:optimize code struct --- src/mango.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mango.c b/src/mango.c index 09625204..96970aa2 100644 --- a/src/mango.c +++ b/src/mango.c @@ -1964,10 +1964,10 @@ void cleanuplisteners(void) { wl_list_remove(&request_start_drag.link); wl_list_remove(&start_drag.link); wl_list_remove(&new_session_lock.link); + wl_list_remove(&tearing_new_object.link); if (drm_lease_manager) { wl_list_remove(&drm_lease_request.link); } - wl_list_remove(&tearing_new_object.link); #ifdef XWAYLAND wl_list_remove(&new_xwayland_surface.link); wl_list_remove(&xwayland_ready.link); From e09748764d7f6501eeef71a4fff5b65cace0b88e Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Thu, 13 Nov 2025 10:42:35 +0800 Subject: [PATCH 320/591] opt: remove useless normalize keysym convert --- src/config/parse_config.h | 55 -------------------------------------- src/dispatch/bind_define.h | 2 +- src/mango.c | 4 +-- 3 files changed, 3 insertions(+), 58 deletions(-) diff --git a/src/config/parse_config.h b/src/config/parse_config.h index a71d4f1e..a6cfb647 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -517,61 +517,6 @@ long int parse_color(const char *hex_str) { return hex_num; } -xkb_keysym_t normalize_keysym(xkb_keysym_t sym) { - // 首先转换为小写(主要影响字母键) - sym = xkb_keysym_to_lower(sym); - - // 将数字小键盘键转换为普通数字键 - switch (sym) { - // 小键盘数字转换 - case XKB_KEY_KP_0: - return XKB_KEY_0; - case XKB_KEY_KP_1: - return XKB_KEY_1; - case XKB_KEY_KP_2: - return XKB_KEY_2; - case XKB_KEY_KP_3: - return XKB_KEY_3; - case XKB_KEY_KP_4: - return XKB_KEY_4; - case XKB_KEY_KP_5: - return XKB_KEY_5; - case XKB_KEY_KP_6: - return XKB_KEY_6; - case XKB_KEY_KP_7: - return XKB_KEY_7; - case XKB_KEY_KP_8: - return XKB_KEY_8; - case XKB_KEY_KP_9: - return XKB_KEY_9; - - // 将 Shift+数字 的符号转换回基础数字 - case XKB_KEY_exclam: - return XKB_KEY_1; // ! - case XKB_KEY_at: - return XKB_KEY_2; // @ - case XKB_KEY_numbersign: - return XKB_KEY_3; // # - case XKB_KEY_dollar: - return XKB_KEY_4; // $ - case XKB_KEY_percent: - return XKB_KEY_5; // % - case XKB_KEY_asciicircum: - return XKB_KEY_6; // ^ - case XKB_KEY_ampersand: - return XKB_KEY_7; // & - case XKB_KEY_asterisk: - return XKB_KEY_8; // * - case XKB_KEY_parenleft: - return XKB_KEY_9; // ( - case XKB_KEY_parenright: - return XKB_KEY_0; // ) - - default: - return sym; - } -} - // 辅助函数:检查字符串是否以指定的前缀开头(忽略大小写) static bool starts_with_ignore_case(const char *str, const char *prefix) { while (*prefix) { diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index 168852f4..d3ab6298 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -971,7 +971,7 @@ int tag(const Arg *arg) { } int tagmon(const Arg *arg) { - Monitor *m = NULL,*cm = NULL; + Monitor *m = NULL, *cm = NULL; Client *c = focustop(selmon); if (!c) diff --git a/src/mango.c b/src/mango.c index 6a66d0a4..eff7dde9 100644 --- a/src/mango.c +++ b/src/mango.c @@ -3345,8 +3345,8 @@ keybinding(unsigned int state, bool locked, unsigned int mods, xkb_keysym_t sym, (strcmp(keymode.mode, k->mode) == 0)) && CLEANMASK(mods) == CLEANMASK(k->mod) && ((k->keysymcode.type == KEY_TYPE_SYM && - normalize_keysym(sym) == - normalize_keysym(k->keysymcode.keysym)) || + xkb_keysym_to_lower(sym) == + xkb_keysym_to_lower(k->keysymcode.keysym)) || (k->keysymcode.type == KEY_TYPE_CODE && (keycode == k->keysymcode.keycode.keycode1 || keycode == k->keysymcode.keycode.keycode2 || From 6010cea8051b82004392b092958b960d280271ce Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sat, 8 Nov 2025 20:10:11 +0800 Subject: [PATCH 321/591] opt: optimize shadow node and blur node enable --- src/animation/client.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/animation/client.h b/src/animation/client.h index 90b664b5..bf8864bd 100644 --- a/src/animation/client.h +++ b/src/animation/client.h @@ -255,8 +255,12 @@ void client_draw_shadow(Client *c) { return; if (!shadows || (!c->isfloating && shadow_only_floating)) { - wlr_scene_shadow_set_size(c->shadow, 0, 0); + if (c->shadow->node.enabled) + wlr_scene_node_set_enabled(&c->shadow->node, false); return; + } else { + if (c->scene_surface->node.enabled && !c->shadow->node.enabled) + wlr_scene_node_set_enabled(&c->shadow->node, true); } bool hit_no_border = check_hit_no_border(c); From 050171960420c438d7345395f4752fa5232cda59 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Thu, 13 Nov 2025 10:49:44 +0800 Subject: [PATCH 322/591] opt: spawn_on_empty and toggle_named_scratchapd use spawn_shell --- src/dispatch/bind_define.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index d3ab6298..27f79775 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -805,7 +805,7 @@ int spawn_on_empty(const Arg *arg) { return 0; } else { view(arg, true); - spawn(arg); + spawn_shell(arg); } return 0; } @@ -1088,7 +1088,7 @@ int toggle_named_scratchpad(const Arg *arg) { if (!target_client && arg->v3) { Arg arg_spawn = {.v = arg->v3}; - spawn(&arg_spawn); + spawn_shell(&arg_spawn); return 0; } From 64dc30dc31d585e6e5d2c3547488282b124130f6 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sat, 8 Nov 2025 20:17:16 +0800 Subject: [PATCH 323/591] opt: disable resize scroller window when it force to default single size --- src/layout/arrange.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/layout/arrange.h b/src/layout/arrange.h index 4df97865..b53592f3 100644 --- a/src/layout/arrange.h +++ b/src/layout/arrange.h @@ -374,6 +374,10 @@ void resize_tile_scroller(Client *grabc, bool isdrag, int offsetx, int offsety, float delta_x, delta_y; float new_scroller_proportion; + if (grabc && grabc->mon->visible_tiling_clients == 1 && + !scroller_ignore_proportion_single) + return; + if (!start_drag_window && isdrag) { drag_begin_cursorx = cursor->x; drag_begin_cursory = cursor->y; From 17f1ae2463146d2525a389121df5129316a538fa Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Thu, 13 Nov 2025 10:55:44 +0800 Subject: [PATCH 324/591] opt: optmize restore_minimized size and not restore namedscratchpad --- src/dispatch/bind_define.h | 2 +- src/mango.c | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index 27f79775..d653bb18 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -476,7 +476,7 @@ int restore_minimized(const Arg *arg) { } wl_list_for_each(c, &clients, link) { - if (c->isminied) { + if (c->isminied && !c->isnamedscratchpad) { c->is_scratchpad_show = 0; c->is_in_scratchpad = 0; c->isnamedscratchpad = 0; diff --git a/src/mango.c b/src/mango.c index eff7dde9..aa22de3c 100644 --- a/src/mango.c +++ b/src/mango.c @@ -4793,8 +4793,11 @@ void setsel(struct wl_listener *listener, void *data) { } void show_hide_client(Client *c) { + unsigned int target = 1; + + set_size_per(c->mon, c); + target = get_tags_first_tag(c->oldtags); - unsigned int target = get_tags_first_tag(c->oldtags); if (!c->is_in_scratchpad) { tag_client(&(Arg){.ui = target}, c); } else { From 5ba7da0570b0f66e69604e1a06b24b45114d455c Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sat, 8 Nov 2025 22:47:18 +0800 Subject: [PATCH 325/591] opt: remove increase_proportion dispatch should use resizewin to replace it --- src/config/parse_config.h | 3 --- src/dispatch/bind_declare.h | 1 - src/dispatch/bind_define.h | 12 ------------ 3 files changed, 16 deletions(-) diff --git a/src/config/parse_config.h b/src/config/parse_config.h index 30e118e8..321de209 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -887,9 +887,6 @@ FuncType parse_func_name(char *func_name, Arg *arg, char *arg_value, } else if (strcmp(func_name, "set_proportion") == 0) { func = set_proportion; (*arg).f = atof(arg_value); - } else if (strcmp(func_name, "increase_proportion") == 0) { - func = increase_proportion; - (*arg).f = atof(arg_value); } else if (strcmp(func_name, "switch_proportion_preset") == 0) { func = switch_proportion_preset; } else if (strcmp(func_name, "viewtoleft") == 0) { diff --git a/src/dispatch/bind_declare.h b/src/dispatch/bind_declare.h index b38e2da5..5bc215a2 100644 --- a/src/dispatch/bind_declare.h +++ b/src/dispatch/bind_declare.h @@ -4,7 +4,6 @@ int toggle_scratchpad(const Arg *arg); int focusdir(const Arg *arg); int toggleoverview(const Arg *arg); int set_proportion(const Arg *arg); -int increase_proportion(const Arg *arg); int switch_proportion_preset(const Arg *arg); int zoom(const Arg *arg); int tagsilent(const Arg *arg); diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index 57288b4c..464e2a6c 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -281,18 +281,6 @@ int incovgaps(const Arg *arg) { return 0; } -int increase_proportion(const Arg *arg) { - if (selmon->sel) { - unsigned int max_client_width = - selmon->w.width - 2 * scroller_structs - gappih; - selmon->sel->scroller_proportion = - MIN(MAX(arg->f + selmon->sel->scroller_proportion, 0.1), 1.0); - selmon->sel->geom.width = max_client_width * arg->f; - arrange(selmon, false); - } - return 0; -} - int setmfact(const Arg *arg) { float f; Client *c = NULL; From 16296898ce694ced439b1bd2aa2080b45859c51f Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Fri, 14 Nov 2025 11:53:41 +0800 Subject: [PATCH 326/591] fix: tagrule not apply correctly --- src/config/parse_config.h | 46 +++++++++++++++++++++------------------ src/mango.c | 13 +---------- 2 files changed, 26 insertions(+), 33 deletions(-) diff --git a/src/config/parse_config.h b/src/config/parse_config.h index a6cfb647..59cb37bc 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -3165,33 +3165,37 @@ void reapply_master(void) { } } +void parse_tagrule(Monitor *m) { + int i, jk; + + for (i = 0; i < config.tag_rules_count; i++) { + + if (config.tag_rules_count > 0 && + (!config.tag_rules[i].monitor_name || + regex_match(config.tag_rules[i].monitor_name, + m->wlr_output->name))) { + + for (jk = 0; jk < LENGTH(layouts); jk++) { + if (config.tag_rules[i].layout_name && + strcmp(layouts[jk].name, config.tag_rules[i].layout_name) == + 0) { + m->pertag->ltidxs[config.tag_rules[i].id] = &layouts[jk]; + } + } + + m->pertag->no_hide[config.tag_rules[i].id] = + config.tag_rules[i].no_hide; + } + } +} + void reapply_tagrule(void) { Monitor *m = NULL; - int i, jk; - char *rule_monitor_name = NULL; wl_list_for_each(m, &mons, link) { if (!m->wlr_output->enabled) { continue; } - - // apply tag rule - for (i = 1; i <= config.tag_rules_count; i++) { - rule_monitor_name = config.tag_rules[i - 1].monitor_name; - if (regex_match(rule_monitor_name, m->wlr_output->name) || - !rule_monitor_name) { - for (jk = 0; jk < LENGTH(layouts); jk++) { - if (config.tag_rules_count > 0 && - config.tag_rules[i - 1].layout_name && - strcmp(layouts[jk].name, - config.tag_rules[i - 1].layout_name) == 0) { - m->pertag->ltidxs[config.tag_rules[i - 1].id] = - &layouts[jk]; - m->pertag->no_hide[config.tag_rules[i - 1].id] = - config.tag_rules[i - 1].no_hide; - } - } - } - } + parse_tagrule(m); } } diff --git a/src/mango.c b/src/mango.c index aa22de3c..2ab3eabe 100644 --- a/src/mango.c +++ b/src/mango.c @@ -2694,18 +2694,7 @@ void createmon(struct wl_listener *listener, void *data) { } // apply tag rule - for (i = 1; i <= config.tag_rules_count; i++) { - for (jk = 0; jk < LENGTH(layouts); jk++) { - if (config.tag_rules_count > 0 && - config.tag_rules[i - 1].layout_name && - strcmp(layouts[jk].name, config.tag_rules[i - 1].layout_name) == - 0) { - m->pertag->ltidxs[config.tag_rules[i - 1].id] = &layouts[jk]; - m->pertag->no_hide[config.tag_rules[i - 1].id] = - config.tag_rules[i - 1].no_hide; - } - } - } + parse_tagrule(m); /* The xdg-protocol specifies: * From 33a0fe24850785b57c97308d3c15553a41920f8a Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sat, 8 Nov 2025 22:48:53 +0800 Subject: [PATCH 327/591] opt: not resizewin in overview --- src/layout/arrange.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/layout/arrange.h b/src/layout/arrange.h index b53592f3..aafb79e0 100644 --- a/src/layout/arrange.h +++ b/src/layout/arrange.h @@ -479,6 +479,9 @@ void resize_tile_client(Client *grabc, bool isdrag, int offsetx, int offsety, if (!grabc || grabc->isfullscreen || grabc->ismaximizescreen) return; + if (grabc->mon->isoverview) + return; + const Layout *current_layout = grabc->mon->pertag->ltidxs[grabc->mon->pertag->curtag]; if (current_layout->id == TILE || current_layout->id == DECK || From d85f4375c8fee672e376e81df6e42f2043176988 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Fri, 14 Nov 2025 12:15:34 +0800 Subject: [PATCH 328/591] fix: fix border color change when swithc mon focus --- src/animation/client.h | 2 +- src/dispatch/bind_define.h | 2 +- src/fetch/client.h | 5 ++++- src/mango.c | 9 +++++++-- 4 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/animation/client.h b/src/animation/client.h index bf8864bd..e3673a20 100644 --- a/src/animation/client.h +++ b/src/animation/client.h @@ -1060,7 +1060,7 @@ void client_set_focused_opacity_animation(Client *c) { c->opacity_animation.running = true; } -void cleint_set_unfocused_opacity_animation(Client *c) { +void client_set_unfocused_opacity_animation(Client *c) { // Start border color animation to unfocused float *border_color = get_border_color(c); diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index d653bb18..c812bf14 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -202,7 +202,7 @@ int focusmon(const Arg *arg) { focusclient(c, 1); if (old_selmon_sel) { - setborder_color(old_selmon_sel); + client_set_unfocused_opacity_animation(old_selmon_sel); } return 0; } diff --git a/src/fetch/client.h b/src/fetch/client.h index 6e675223..5f62d234 100644 --- a/src/fetch/client.h +++ b/src/fetch/client.h @@ -374,7 +374,10 @@ Client *get_next_stack_client(Client *c, bool reverse) { } float *get_border_color(Client *c) { - if (c->isurgent) { + + if (c->mon != selmon) { + return bordercolor; + } else if (c->isurgent) { return urgentcolor; } else if (c->is_in_scratchpad && selmon && c == selmon->sel) { return scratchpadcolor; diff --git a/src/mango.c b/src/mango.c index 2ab3eabe..7bb3bb24 100644 --- a/src/mango.c +++ b/src/mango.c @@ -3092,6 +3092,9 @@ void destroykeyboardgroup(struct wl_listener *listener, void *data) { } void focusclient(Client *c, int lift) { + + Client *last_focus_client = NULL; + struct wlr_surface *old_keyboard_focus_surface = seat->keyboard_state.focused_surface; @@ -3126,12 +3129,14 @@ void focusclient(Client *c, int lift) { if (c && !c->iskilling && !client_is_unmanaged(c) && c->mon) { + last_focus_client = selmon->sel; selmon = c->mon; selmon->prevsel = selmon->sel; selmon->sel = c; - if (selmon->prevsel && !selmon->prevsel->iskilling) { - cleint_set_unfocused_opacity_animation(selmon->prevsel); + if (last_focus_client && !last_focus_client->iskilling && + last_focus_client != c) { + client_set_unfocused_opacity_animation(last_focus_client); } client_set_focused_opacity_animation(c); From f542d5d5e6d9999b627ffd5f55bf4a2085a36041 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sat, 8 Nov 2025 23:26:52 +0800 Subject: [PATCH 329/591] opt: disable switch proportion action in some case --- src/dispatch/bind_define.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index 464e2a6c..65c2b03e 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -518,6 +518,14 @@ int setkeymode(const Arg *arg) { } int set_proportion(const Arg *arg) { + + if (selmon->isoverview || !is_scroller_layout(selmon)) + return 0; + + if (selmon->visible_tiling_clients == 1 && + !scroller_ignore_proportion_single) + return 0; + if (selmon->sel) { unsigned int max_client_width = selmon->w.width - 2 * scroller_structs - gappih; @@ -919,6 +927,13 @@ int switch_proportion_preset(const Arg *arg) { return 0; } + if (selmon->isoverview || !is_scroller_layout(selmon)) + return 0; + + if (selmon->visible_tiling_clients == 1 && + !scroller_ignore_proportion_single) + return 0; + if (selmon->sel) { for (int i = 0; i < config.scroller_proportion_preset_count; i++) { From 514c9166785274ed525ecc3ef4697d71c47b2ab4 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Fri, 14 Nov 2025 12:32:07 +0800 Subject: [PATCH 330/591] opt: optimize code struct --- src/config/parse_config.h | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/config/parse_config.h b/src/config/parse_config.h index 59cb37bc..63580830 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -3167,24 +3167,24 @@ void reapply_master(void) { void parse_tagrule(Monitor *m) { int i, jk; + ConfigTagRule tr; for (i = 0; i < config.tag_rules_count; i++) { + tr = config.tag_rules[i]; + if (config.tag_rules_count > 0 && - (!config.tag_rules[i].monitor_name || - regex_match(config.tag_rules[i].monitor_name, - m->wlr_output->name))) { + (!tr.monitor_name || + regex_match(tr.monitor_name, m->wlr_output->name))) { for (jk = 0; jk < LENGTH(layouts); jk++) { - if (config.tag_rules[i].layout_name && - strcmp(layouts[jk].name, config.tag_rules[i].layout_name) == - 0) { - m->pertag->ltidxs[config.tag_rules[i].id] = &layouts[jk]; + if (tr.layout_name && + strcmp(layouts[jk].name, tr.layout_name) == 0) { + m->pertag->ltidxs[tr.id] = &layouts[jk]; } } - m->pertag->no_hide[config.tag_rules[i].id] = - config.tag_rules[i].no_hide; + m->pertag->no_hide[tr.id] = tr.no_hide; } } } From 8875156760b48d82c209cff895b61aa5b3817f4a Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sun, 9 Nov 2025 15:40:51 +0800 Subject: [PATCH 331/591] feat: support nofucs rule for some special window --- src/config/parse_config.h | 4 ++++ src/mango.c | 42 +++++++++++++++++++++++---------------- 2 files changed, 29 insertions(+), 17 deletions(-) diff --git a/src/config/parse_config.h b/src/config/parse_config.h index 321de209..0e9e15c5 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -77,6 +77,7 @@ typedef struct { int offsety; int width; int height; + int nofocus; int nofadein; int nofadeout; int no_force_center; @@ -1716,6 +1717,7 @@ void parse_option(Config *config, char *key, char *value) { rule->force_tearing = -1; rule->noswallow = -1; rule->noblur = -1; + rule->nofocus = -1; rule->nofadein = -1; rule->nofadeout = -1; rule->no_force_center = -1; @@ -1770,6 +1772,8 @@ void parse_option(Config *config, char *key, char *value) { rule->offsetx = atoi(val); } else if (strcmp(key, "offsety") == 0) { rule->offsety = atoi(val); + } else if (strcmp(key, "nofocus") == 0) { + rule->nofocus = atoi(val); } else if (strcmp(key, "nofadein") == 0) { rule->nofadein = atoi(val); } else if (strcmp(key, "nofadeout") == 0) { diff --git a/src/mango.c b/src/mango.c index 96970aa2..f7440f49 100644 --- a/src/mango.c +++ b/src/mango.c @@ -352,6 +352,7 @@ struct Client { bool drag_to_tile; bool scratchpad_switching_mon; bool fake_no_border; + int nofocus; int nofadein; int nofadeout; int no_force_center; @@ -1130,6 +1131,7 @@ static void apply_rule_properties(Client *c, const ConfigWinRule *r) { APPLY_INT_PROP(c, r, force_maximize); APPLY_INT_PROP(c, r, force_tearing); APPLY_INT_PROP(c, r, noswallow); + APPLY_INT_PROP(c, r, nofocus); APPLY_INT_PROP(c, r, nofadein); APPLY_INT_PROP(c, r, nofadeout); APPLY_INT_PROP(c, r, no_force_center); @@ -1243,11 +1245,16 @@ void applyrules(Client *c) { const char *appid, *title; unsigned int i, newtags = 0; const ConfigWinRule *r; - Monitor *mon = selmon, *m = NULL; + Monitor *m = NULL; Client *fc = NULL; bool hit_rule_pos = false; + Client *parent = NULL; - c->isfloating = client_is_float_type(c); + parent = client_get_parent(c); + + Monitor *mon = parent && parent->mon ? parent->mon : selmon; + + c->isfloating = client_is_float_type(c) || parent; if (!(appid = client_get_appid(c))) appid = broken; if (!(title = client_get_title(c))) @@ -1264,8 +1271,14 @@ void applyrules(Client *c) { // set general properties apply_rule_properties(c, r); - // set tags - newtags |= (r->tags > 0) ? r->tags : 0; + // // set tags + if (r->tags > 0) { + newtags |= r->tags; + } else if (parent) { + newtags = parent->tags; + } else { + newtags |= 0; + } // set monitor of client wl_list_for_each(m, &mons, link) { @@ -1334,8 +1347,9 @@ void applyrules(Client *c) { int fullscreen_state_backup = c->isfullscreen || client_wants_fullscreen(c); setmon(c, mon, newtags, - !c->isopensilent && (!c->istagsilent || !newtags || - newtags & mon->tagset[mon->seltags])); + !c->isopensilent && !client_should_ignore_focus(c) && + (!c->istagsilent || !newtags || + newtags & mon->tagset[mon->seltags])); if (c->mon && !(c->mon == selmon && c->tags & c->mon->tagset[c->mon->seltags]) && @@ -3084,6 +3098,9 @@ void focusclient(Client *c, int lift) { if (c && client_should_ignore_focus(c) && client_is_x11_popup(c)) return; + if (c && c->nofocus) + return; + /* Raise client in stacking order if requested */ if (c && lift) wlr_scene_node_raise_to_top(&c->scene->node); // 将视图提升到顶层 @@ -3560,6 +3577,7 @@ void init_client_properties(Client *c) { c->fake_no_border = false; c->focused_opacity = focused_opacity; c->unfocused_opacity = unfocused_opacity; + c->nofocus = 0; c->nofadein = 0; c->nofadeout = 0; c->no_force_center = 0; @@ -3580,7 +3598,6 @@ void init_client_properties(Client *c) { void // old fix to 0.5 mapnotify(struct wl_listener *listener, void *data) { /* Called when the surface is mapped, or ready to display on-screen. */ - Client *p = NULL; Client *at_client = NULL; Client *c = wl_container_of(listener, c, map); /* Create scene tree for this client and its border */ @@ -3672,16 +3689,7 @@ mapnotify(struct wl_listener *listener, void *data) { wl_list_insert(clients.prev, &c->link); // 尾部入栈 wl_list_insert(&fstack, &c->flink); - /* Set initial monitor, tags, floating status, and focus: - * we always consider floating, clients that have parent and thus - * we set the same tags and monitor than its parent, if not - * try to apply rules for them */ - if ((p = client_get_parent(c))) { - c->isfloating = 1; - setmon(c, p->mon, p->tags, true); - } else { - applyrules(c); - } + applyrules(c); client_set_tiled(c, WLR_EDGE_TOP | WLR_EDGE_BOTTOM | WLR_EDGE_LEFT | WLR_EDGE_RIGHT); From 407c9d74a42763f56817af2ee4821c92e9eba4f7 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Fri, 14 Nov 2025 15:39:04 +0800 Subject: [PATCH 332/591] feat: add windowrule option scroller_proportion_single --- src/config/parse_config.h | 4 ++++ src/layout/horizontal.h | 9 +++++++-- src/layout/vertical.h | 10 ++++++++-- src/mango.c | 3 +++ 4 files changed, 22 insertions(+), 4 deletions(-) diff --git a/src/config/parse_config.h b/src/config/parse_config.h index 63580830..074660bf 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -90,6 +90,7 @@ typedef struct { int noblur; float focused_opacity; float unfocused_opacity; + float scroller_proportion_single; uint32_t passmod; xkb_keysym_t keysym; KeyBinding globalkeybinding; @@ -1679,6 +1680,7 @@ void parse_option(Config *config, char *key, char *value) { // float rule value, relay to a client property rule->focused_opacity = 0; rule->unfocused_opacity = 0; + rule->scroller_proportion_single = 0.0f; rule->scroller_proportion = 0; // special rule value,not directly set to client property @@ -1750,6 +1752,8 @@ void parse_option(Config *config, char *key, char *value) { rule->isunglobal = atoi(val); } else if (strcmp(key, "isglobal") == 0) { rule->isglobal = atoi(val); + } else if (strcmp(key, "scroller_proportion_single") == 0) { + rule->scroller_proportion_single = atof(val); } else if (strcmp(key, "unfocused_opacity") == 0) { rule->unfocused_opacity = atof(val); } else if (strcmp(key, "focused_opacity") == 0) { diff --git a/src/layout/horizontal.h b/src/layout/horizontal.h index 178ae9e0..934dc136 100644 --- a/src/layout/horizontal.h +++ b/src/layout/horizontal.h @@ -192,6 +192,7 @@ void deck(Monitor *m) { // 滚动布局 void scroller(Monitor *m) { unsigned int i, n, j; + float single_proportion = 1.0; Client *c = NULL, *root_client = NULL; Client **tempClients = NULL; // 初始化为 NULL @@ -233,9 +234,13 @@ void scroller(Monitor *m) { if (n == 1 && !scroller_ignore_proportion_single) { c = tempClients[0]; + + single_proportion = c->scroller_proportion_single > 0.0f + ? c->scroller_proportion_single + : scroller_default_proportion_single; + target_geom.height = m->w.height - 2 * cur_gappov; - target_geom.width = - (m->w.width - 2 * cur_gappoh) * scroller_default_proportion_single; + target_geom.width = (m->w.width - 2 * cur_gappoh) * single_proportion; target_geom.x = m->w.x + (m->w.width - target_geom.width) / 2; target_geom.y = m->w.y + (m->w.height - target_geom.height) / 2; resize(c, target_geom, 0); diff --git a/src/layout/vertical.h b/src/layout/vertical.h index 6ae21a6c..46ca3b65 100644 --- a/src/layout/vertical.h +++ b/src/layout/vertical.h @@ -157,6 +157,8 @@ void vertical_deck(Monitor *m) { void vertical_scroller(Monitor *m) { unsigned int i, n, j; + float single_proportion = 1.0; + Client *c = NULL, *root_client = NULL; Client **tempClients = NULL; struct wlr_box target_geom; @@ -194,9 +196,13 @@ void vertical_scroller(Monitor *m) { if (n == 1 && !scroller_ignore_proportion_single) { c = tempClients[0]; + + single_proportion = c->scroller_proportion_single > 0.0f + ? c->scroller_proportion_single + : scroller_default_proportion_single; + target_geom.width = m->w.width - 2 * cur_gappoh; - target_geom.height = - (m->w.height - 2 * cur_gappov) * scroller_default_proportion_single; + target_geom.height = (m->w.height - 2 * cur_gappov) * single_proportion; target_geom.x = m->w.x + (m->w.width - target_geom.width) / 2; target_geom.y = m->w.y + (m->w.height - target_geom.height) / 2; resize(c, target_geom, 0); diff --git a/src/mango.c b/src/mango.c index 7bb3bb24..601c36f5 100644 --- a/src/mango.c +++ b/src/mango.c @@ -376,6 +376,7 @@ struct Client { int tearing_hint; int force_tearing; int allow_shortcuts_inhibit; + float scroller_proportion_single; }; typedef struct { @@ -1173,6 +1174,7 @@ static void apply_rule_properties(Client *c, const ConfigWinRule *r) { APPLY_INT_PROP(c, r, allow_shortcuts_inhibit); APPLY_FLOAT_PROP(c, r, scroller_proportion); + APPLY_FLOAT_PROP(c, r, scroller_proportion_single); APPLY_FLOAT_PROP(c, r, focused_opacity); APPLY_FLOAT_PROP(c, r, unfocused_opacity); @@ -3623,6 +3625,7 @@ void init_client_properties(Client *c) { c->force_maximize = 0; c->force_tearing = 0; c->allow_shortcuts_inhibit = SHORTCUTS_INHIBIT_ENABLE; + c->scroller_proportion_single = 0.0f; } void // old fix to 0.5 From f2b98352431838fdadd60e4fb5b8475027ffe2fe Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sun, 9 Nov 2025 23:19:49 +0800 Subject: [PATCH 333/591] opt: remove useless code --- src/mango.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/mango.c b/src/mango.c index f7440f49..7ad9aa6f 100644 --- a/src/mango.c +++ b/src/mango.c @@ -1276,8 +1276,6 @@ void applyrules(Client *c) { newtags |= r->tags; } else if (parent) { newtags = parent->tags; - } else { - newtags |= 0; } // set monitor of client From fce47b37d941808260c757fc68658d1b54fd1f01 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Fri, 14 Nov 2025 17:13:26 +0800 Subject: [PATCH 334/591] opt: optimize init focus for x11 window --- src/mango.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/mango.c b/src/mango.c index 601c36f5..06e1d616 100644 --- a/src/mango.c +++ b/src/mango.c @@ -1368,7 +1368,8 @@ void applyrules(Client *c) { int fullscreen_state_backup = c->isfullscreen || client_wants_fullscreen(c); setmon(c, mon, newtags, - !c->isopensilent && !client_should_ignore_focus(c) && + !c->isopensilent && + !(client_is_x11_popup(c) && client_should_ignore_focus(c)) && (!c->istagsilent || !newtags || newtags & mon->tagset[mon->seltags])); From ecab47fe929519349735ce489b69b8e8744387fb Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Mon, 10 Nov 2025 14:30:20 +0800 Subject: [PATCH 335/591] update readme --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c90cee1f..8e982b60 100644 --- a/README.md +++ b/README.md @@ -101,7 +101,7 @@ emerge --ask --verbose gui-wm/mangowc ## Other ```bash -git clone -b 0.19.1 https://gitlab.freedesktop.org/wlroots/wlroots.git +git clone -b 0.19.2 https://gitlab.freedesktop.org/wlroots/wlroots.git cd wlroots meson build -Dprefix=/usr sudo ninja -C build install @@ -119,7 +119,7 @@ sudo ninja -C build install ## Suggested Tools -### integrated component +### Hybrid component - [dms-shell](https://github.com/AvengeMedia/DankMaterialShell) ### Independent component From cdcc64ab5fc656e1d314f719f5a6e416bbdcb04c Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sat, 15 Nov 2025 00:08:57 +0800 Subject: [PATCH 336/591] feat: support scroll maximize and fullscreen window --- src/dispatch/bind_define.h | 11 +++- src/ext-protocol/dwl-ipc.h | 1 + src/fetch/client.h | 113 ++++++++++++++++++++----------------- src/layout/arrange.h | 5 ++ src/layout/horizontal.h | 71 ++++++++++++++++++----- src/layout/vertical.h | 72 ++++++++++++++++++----- src/mango.c | 45 ++++++++++++--- 7 files changed, 228 insertions(+), 90 deletions(-) diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index c812bf14..d79a7c65 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -80,8 +80,12 @@ int defaultgaps(const Arg *arg) { int exchange_client(const Arg *arg) { Client *c = selmon->sel; - if (!c || c->isfloating || c->isfullscreen || c->ismaximizescreen) + if (!c || c->isfloating) return 0; + + if ((c->isfullscreen || c->ismaximizescreen) && !is_scroller_layout(c->mon)) + return 0; + exchange_two_client(c, direction_select(arg)); return 0; } @@ -497,7 +501,7 @@ int setlayout(const Arg *arg) { for (jk = 0; jk < LENGTH(layouts); jk++) { if (strcmp(layouts[jk].name, arg->v) == 0) { selmon->pertag->ltidxs[selmon->pertag->curtag] = &layouts[jk]; - + clear_fullscreen_and_maximized_state(selmon); arrange(selmon, false); printstatus(); return 0; @@ -901,7 +905,7 @@ int switch_layout(const Arg *arg) { break; } } - + clear_fullscreen_and_maximized_state(selmon); arrange(selmon, false); printstatus(); return 0; @@ -912,6 +916,7 @@ int switch_layout(const Arg *arg) { selmon->pertag->ltidxs[selmon->pertag->curtag]->name) == 0) { selmon->pertag->ltidxs[selmon->pertag->curtag] = jk == LENGTH(layouts) - 1 ? &layouts[0] : &layouts[jk + 1]; + clear_fullscreen_and_maximized_state(selmon); arrange(selmon, false); printstatus(); return 0; diff --git a/src/ext-protocol/dwl-ipc.h b/src/ext-protocol/dwl-ipc.h index 6b0c4c54..15b2376a 100644 --- a/src/ext-protocol/dwl-ipc.h +++ b/src/ext-protocol/dwl-ipc.h @@ -258,6 +258,7 @@ void dwl_ipc_output_set_layout(struct wl_client *client, index = 0; monitor->pertag->ltidxs[monitor->pertag->curtag] = &layouts[index]; + clear_fullscreen_and_maximized_state(monitor); arrange(monitor, false); printstatus(); } diff --git a/src/fetch/client.h b/src/fetch/client.h index 5f62d234..c2b0abdd 100644 --- a/src/fetch/client.h +++ b/src/fetch/client.h @@ -142,7 +142,7 @@ Client *center_tiled_select(Monitor *m) { return target_c; } Client *find_client_by_direction(Client *tc, const Arg *arg, bool findfloating, - bool align) { + bool ignore_align) { Client *c = NULL; Client **tempClients = NULL; // 初始化为 NULL int last = -1; @@ -185,21 +185,23 @@ Client *find_client_by_direction(Client *tc, const Arg *arg, bool findfloating, switch (arg->i) { case UP: - for (int _i = 0; _i <= last; _i++) { - if (tempClients[_i]->geom.y < sel_y && - tempClients[_i]->geom.x == sel_x && - tempClients[_i]->mon == tc->mon) { - int dis_x = tempClients[_i]->geom.x - sel_x; - int dis_y = tempClients[_i]->geom.y - sel_y; - long long int tmp_distance = - dis_x * dis_x + dis_y * dis_y; // 计算距离 - if (tmp_distance < distance) { - distance = tmp_distance; - tempFocusClients = tempClients[_i]; + if (!ignore_align) { + for (int _i = 0; _i <= last; _i++) { + if (tempClients[_i]->geom.y < sel_y && + tempClients[_i]->geom.x == sel_x && + tempClients[_i]->mon == tc->mon) { + int dis_x = tempClients[_i]->geom.x - sel_x; + int dis_y = tempClients[_i]->geom.y - sel_y; + long long int tmp_distance = + dis_x * dis_x + dis_y * dis_y; // 计算距离 + if (tmp_distance < distance) { + distance = tmp_distance; + tempFocusClients = tempClients[_i]; + } } } } - if (!tempFocusClients && !align) { + if (!tempFocusClients) { for (int _i = 0; _i <= last; _i++) { if (tempClients[_i]->geom.y < sel_y) { int dis_x = tempClients[_i]->geom.x - sel_x; @@ -215,21 +217,23 @@ Client *find_client_by_direction(Client *tc, const Arg *arg, bool findfloating, } break; case DOWN: - for (int _i = 0; _i <= last; _i++) { - if (tempClients[_i]->geom.y > sel_y && - tempClients[_i]->geom.x == sel_x && - tempClients[_i]->mon == tc->mon) { - int dis_x = tempClients[_i]->geom.x - sel_x; - int dis_y = tempClients[_i]->geom.y - sel_y; - long long int tmp_distance = - dis_x * dis_x + dis_y * dis_y; // 计算距离 - if (tmp_distance < distance) { - distance = tmp_distance; - tempFocusClients = tempClients[_i]; + if (!ignore_align) { + for (int _i = 0; _i <= last; _i++) { + if (tempClients[_i]->geom.y > sel_y && + tempClients[_i]->geom.x == sel_x && + tempClients[_i]->mon == tc->mon) { + int dis_x = tempClients[_i]->geom.x - sel_x; + int dis_y = tempClients[_i]->geom.y - sel_y; + long long int tmp_distance = + dis_x * dis_x + dis_y * dis_y; // 计算距离 + if (tmp_distance < distance) { + distance = tmp_distance; + tempFocusClients = tempClients[_i]; + } } } } - if (!tempFocusClients && !align) { + if (!tempFocusClients) { for (int _i = 0; _i <= last; _i++) { if (tempClients[_i]->geom.y > sel_y) { int dis_x = tempClients[_i]->geom.x - sel_x; @@ -245,21 +249,23 @@ Client *find_client_by_direction(Client *tc, const Arg *arg, bool findfloating, } break; case LEFT: - for (int _i = 0; _i <= last; _i++) { - if (tempClients[_i]->geom.x < sel_x && - tempClients[_i]->geom.y == sel_y && - tempClients[_i]->mon == tc->mon) { - int dis_x = tempClients[_i]->geom.x - sel_x; - int dis_y = tempClients[_i]->geom.y - sel_y; - long long int tmp_distance = - dis_x * dis_x + dis_y * dis_y; // 计算距离 - if (tmp_distance < distance) { - distance = tmp_distance; - tempFocusClients = tempClients[_i]; + if (!ignore_align) { + for (int _i = 0; _i <= last; _i++) { + if (tempClients[_i]->geom.x < sel_x && + tempClients[_i]->geom.y == sel_y && + tempClients[_i]->mon == tc->mon) { + int dis_x = tempClients[_i]->geom.x - sel_x; + int dis_y = tempClients[_i]->geom.y - sel_y; + long long int tmp_distance = + dis_x * dis_x + dis_y * dis_y; // 计算距离 + if (tmp_distance < distance) { + distance = tmp_distance; + tempFocusClients = tempClients[_i]; + } } } } - if (!tempFocusClients && !align) { + if (!tempFocusClients) { for (int _i = 0; _i <= last; _i++) { if (tempClients[_i]->geom.x < sel_x) { int dis_x = tempClients[_i]->geom.x - sel_x; @@ -275,21 +281,23 @@ Client *find_client_by_direction(Client *tc, const Arg *arg, bool findfloating, } break; case RIGHT: - for (int _i = 0; _i <= last; _i++) { - if (tempClients[_i]->geom.x > sel_x && - tempClients[_i]->geom.y == sel_y && - tempClients[_i]->mon == tc->mon) { - int dis_x = tempClients[_i]->geom.x - sel_x; - int dis_y = tempClients[_i]->geom.y - sel_y; - long long int tmp_distance = - dis_x * dis_x + dis_y * dis_y; // 计算距离 - if (tmp_distance < distance) { - distance = tmp_distance; - tempFocusClients = tempClients[_i]; + if (!ignore_align) { + for (int _i = 0; _i <= last; _i++) { + if (tempClients[_i]->geom.x > sel_x && + tempClients[_i]->geom.y == sel_y && + tempClients[_i]->mon == tc->mon) { + int dis_x = tempClients[_i]->geom.x - sel_x; + int dis_y = tempClients[_i]->geom.y - sel_y; + long long int tmp_distance = + dis_x * dis_x + dis_y * dis_y; // 计算距离 + if (tmp_distance < distance) { + distance = tmp_distance; + tempFocusClients = tempClients[_i]; + } } } } - if (!tempFocusClients && !align) { + if (!tempFocusClients) { for (int _i = 0; _i <= last; _i++) { if (tempClients[_i]->geom.x > sel_x) { int dis_x = tempClients[_i]->geom.x - sel_x; @@ -317,12 +325,13 @@ Client *direction_select(const Arg *arg) { if (!tc) return NULL; - if (tc && (tc->isfullscreen || tc->ismaximizescreen)) { - // 不支持全屏窗口的焦点切换 + if (tc && (tc->isfullscreen || tc->ismaximizescreen) && + (!is_scroller_layout(selmon) || tc->isfloating)) { return NULL; } - return find_client_by_direction(tc, arg, true, false); + return find_client_by_direction( + tc, arg, true, is_scroller_layout(selmon) && !selmon->isoverview); } /* We probably should change the name of this, it sounds like diff --git a/src/layout/arrange.h b/src/layout/arrange.h index aafb79e0..ba1391e6 100644 --- a/src/layout/arrange.h +++ b/src/layout/arrange.h @@ -599,6 +599,7 @@ arrange(Monitor *m, bool want_animation) { return; m->visible_clients = 0; m->visible_tiling_clients = 0; + m->visible_scroll_tiling_clients = 0; m->has_visible_fullscreen_client = false; wl_list_for_each(c, &clients, link) { @@ -619,6 +620,10 @@ arrange(Monitor *m, bool want_animation) { if (ISTILED(c)) { m->visible_tiling_clients++; } + + if (ISSCROLLTILED(c)) { + m->visible_scroll_tiling_clients++; + } } } diff --git a/src/layout/horizontal.h b/src/layout/horizontal.h index 934dc136..ff517cc1 100644 --- a/src/layout/horizontal.h +++ b/src/layout/horizontal.h @@ -189,6 +189,38 @@ void deck(Monitor *m) { } } +void horizontal_scroll_adjust_fullandmax(Client *c, + struct wlr_box *target_geom) { + Monitor *m = c->mon; + unsigned int cur_gappih = enablegaps ? m->gappih : 0; + unsigned int cur_gappoh = enablegaps ? m->gappoh : 0; + unsigned int cur_gappov = enablegaps ? m->gappov : 0; + + cur_gappih = + smartgaps && m->visible_scroll_tiling_clients == 1 ? 0 : cur_gappih; + cur_gappoh = + smartgaps && m->visible_scroll_tiling_clients == 1 ? 0 : cur_gappoh; + cur_gappov = + smartgaps && m->visible_scroll_tiling_clients == 1 ? 0 : cur_gappov; + + if (c->isfullscreen) { + target_geom->height = m->m.height; + target_geom->width = m->m.width; + target_geom->y = m->m.y; + return; + } + + if (c->ismaximizescreen) { + target_geom->height = m->w.height - 2 * cur_gappov; + target_geom->width = m->w.width - 2 * cur_gappoh; + target_geom->y = m->w.y + cur_gappov; + return; + } + + target_geom->height = m->w.height - 2 * cur_gappov; + target_geom->y = m->w.y + (m->w.height - target_geom->height) / 2; +} + // 滚动布局 void scroller(Monitor *m) { unsigned int i, n, j; @@ -203,14 +235,17 @@ void scroller(Monitor *m) { unsigned int cur_gappoh = enablegaps ? m->gappoh : 0; unsigned int cur_gappov = enablegaps ? m->gappov : 0; - cur_gappih = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappih; - cur_gappoh = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappoh; - cur_gappov = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappov; + cur_gappih = + smartgaps && m->visible_scroll_tiling_clients == 1 ? 0 : cur_gappih; + cur_gappoh = + smartgaps && m->visible_scroll_tiling_clients == 1 ? 0 : cur_gappoh; + cur_gappov = + smartgaps && m->visible_scroll_tiling_clients == 1 ? 0 : cur_gappov; unsigned int max_client_width = m->w.width - 2 * scroller_structs - cur_gappih; - n = m->visible_tiling_clients; + n = m->visible_scroll_tiling_clients; if (n == 0) { return; // 没有需要处理的客户端,直接返回 @@ -226,13 +261,14 @@ void scroller(Monitor *m) { // 第二次遍历,填充 tempClients j = 0; wl_list_for_each(c, &clients, link) { - if (VISIBLEON(c, m) && ISTILED(c)) { + if (VISIBLEON(c, m) && ISSCROLLTILED(c)) { tempClients[j] = c; j++; } } - if (n == 1 && !scroller_ignore_proportion_single) { + if (n == 1 && !scroller_ignore_proportion_single && + !tempClients[0]->isfullscreen && !tempClients[0]->ismaximizescreen) { c = tempClients[0]; single_proportion = c->scroller_proportion_single > 0.0f @@ -248,11 +284,10 @@ void scroller(Monitor *m) { return; } - if (m->sel && !client_is_unmanaged(m->sel) && !m->sel->isfloating && - !m->sel->ismaximizescreen && !m->sel->isfullscreen) { + if (m->sel && !client_is_unmanaged(m->sel) && !m->sel->isfloating) { root_client = m->sel; - } else if (m->prevsel && ISTILED(m->prevsel) && VISIBLEON(m->prevsel, m) && - !client_is_unmanaged(m->prevsel)) { + } else if (m->prevsel && ISSCROLLTILED(m->prevsel) && + VISIBLEON(m->prevsel, m) && !client_is_unmanaged(m->prevsel)) { root_client = m->prevsel; } else { root_client = center_tiled_select(m); @@ -289,11 +324,18 @@ void scroller(Monitor *m) { target_geom.height = m->w.height - 2 * cur_gappov; target_geom.width = max_client_width * c->scroller_proportion; target_geom.y = m->w.y + (m->w.height - target_geom.height) / 2; - - if (need_scroller) { + horizontal_scroll_adjust_fullandmax(tempClients[focus_client_index], + &target_geom); + if (tempClients[focus_client_index]->isfullscreen) { + target_geom.x = m->m.x; + resize(tempClients[focus_client_index], target_geom, 0); + } else if (tempClients[focus_client_index]->ismaximizescreen) { + target_geom.x = m->w.x + cur_gappoh; + resize(tempClients[focus_client_index], target_geom, 0); + } else if (need_scroller) { if (scroller_focus_center || ((!m->prevsel || - (ISTILED(m->prevsel) && + (ISSCROLLTILED(m->prevsel) && (m->prevsel->scroller_proportion * max_client_width) + (root_client->scroller_proportion * max_client_width) > m->w.width - 2 * scroller_structs - cur_gappih)) && @@ -316,14 +358,17 @@ void scroller(Monitor *m) { for (i = 1; i <= focus_client_index; i++) { c = tempClients[focus_client_index - i]; target_geom.width = max_client_width * c->scroller_proportion; + horizontal_scroll_adjust_fullandmax(c, &target_geom); target_geom.x = tempClients[focus_client_index - i + 1]->geom.x - cur_gappih - target_geom.width; + resize(c, target_geom, 0); } for (i = 1; i < n - focus_client_index; i++) { c = tempClients[focus_client_index + i]; target_geom.width = max_client_width * c->scroller_proportion; + horizontal_scroll_adjust_fullandmax(c, &target_geom); target_geom.x = tempClients[focus_client_index + i - 1]->geom.x + cur_gappih + tempClients[focus_client_index + i - 1]->geom.width; diff --git a/src/layout/vertical.h b/src/layout/vertical.h index 46ca3b65..cef0e3bb 100644 --- a/src/layout/vertical.h +++ b/src/layout/vertical.h @@ -155,6 +155,38 @@ void vertical_deck(Monitor *m) { } } +void vertical_scroll_adjust_fullandmax(Client *c, struct wlr_box *target_geom) { + Monitor *m = c->mon; + unsigned int cur_gappiv = enablegaps ? m->gappiv : 0; + unsigned int cur_gappov = enablegaps ? m->gappov : 0; + unsigned int cur_gappoh = enablegaps ? m->gappoh : 0; + + cur_gappiv = + smartgaps && m->visible_scroll_tiling_clients == 1 ? 0 : cur_gappiv; + cur_gappov = + smartgaps && m->visible_scroll_tiling_clients == 1 ? 0 : cur_gappov; + cur_gappoh = + smartgaps && m->visible_scroll_tiling_clients == 1 ? 0 : cur_gappoh; + + if (c->isfullscreen) { + target_geom->width = m->m.width; + target_geom->height = m->m.height; + target_geom->x = m->m.x; + return; + } + + if (c->ismaximizescreen) { + target_geom->width = m->w.width - 2 * cur_gappoh; + target_geom->height = m->w.height - 2 * cur_gappov; + target_geom->x = m->w.x + cur_gappoh; + return; + } + + target_geom->width = m->w.width - 2 * cur_gappoh; + target_geom->x = m->w.x + (m->w.width - target_geom->width) / 2; +} + +// 竖屏滚动布局 void vertical_scroller(Monitor *m) { unsigned int i, n, j; float single_proportion = 1.0; @@ -168,14 +200,17 @@ void vertical_scroller(Monitor *m) { unsigned int cur_gappov = enablegaps ? m->gappov : 0; unsigned int cur_gappoh = enablegaps ? m->gappoh : 0; - cur_gappiv = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappiv; - cur_gappov = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappov; - cur_gappoh = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappoh; + cur_gappiv = + smartgaps && m->visible_scroll_tiling_clients == 1 ? 0 : cur_gappiv; + cur_gappov = + smartgaps && m->visible_scroll_tiling_clients == 1 ? 0 : cur_gappov; + cur_gappoh = + smartgaps && m->visible_scroll_tiling_clients == 1 ? 0 : cur_gappoh; unsigned int max_client_height = m->w.height - 2 * scroller_structs - cur_gappiv; - n = m->visible_tiling_clients; + n = m->visible_scroll_tiling_clients; if (n == 0) { return; @@ -188,13 +223,14 @@ void vertical_scroller(Monitor *m) { j = 0; wl_list_for_each(c, &clients, link) { - if (VISIBLEON(c, m) && ISTILED(c)) { + if (VISIBLEON(c, m) && ISSCROLLTILED(c)) { tempClients[j] = c; j++; } } - if (n == 1 && !scroller_ignore_proportion_single) { + if (n == 1 && !scroller_ignore_proportion_single && + !tempClients[0]->isfullscreen && !tempClients[0]->ismaximizescreen) { c = tempClients[0]; single_proportion = c->scroller_proportion_single > 0.0f @@ -203,18 +239,17 @@ void vertical_scroller(Monitor *m) { target_geom.width = m->w.width - 2 * cur_gappoh; target_geom.height = (m->w.height - 2 * cur_gappov) * single_proportion; - target_geom.x = m->w.x + (m->w.width - target_geom.width) / 2; target_geom.y = m->w.y + (m->w.height - target_geom.height) / 2; + target_geom.x = m->w.x + (m->w.width - target_geom.width) / 2; resize(c, target_geom, 0); free(tempClients); return; } - if (m->sel && !client_is_unmanaged(m->sel) && !m->sel->isfloating && - !m->sel->ismaximizescreen && !m->sel->isfullscreen) { + if (m->sel && !client_is_unmanaged(m->sel) && !m->sel->isfloating) { root_client = m->sel; - } else if (m->prevsel && ISTILED(m->prevsel) && VISIBLEON(m->prevsel, m) && - !client_is_unmanaged(m->prevsel)) { + } else if (m->prevsel && ISSCROLLTILED(m->prevsel) && + VISIBLEON(m->prevsel, m) && !client_is_unmanaged(m->prevsel)) { root_client = m->prevsel; } else { root_client = center_tiled_select(m); @@ -251,11 +286,19 @@ void vertical_scroller(Monitor *m) { target_geom.width = m->w.width - 2 * cur_gappoh; target_geom.height = max_client_height * c->scroller_proportion; target_geom.x = m->w.x + (m->w.width - target_geom.width) / 2; + vertical_scroll_adjust_fullandmax(tempClients[focus_client_index], + &target_geom); - if (need_scroller) { + if (tempClients[focus_client_index]->isfullscreen) { + target_geom.y = m->m.y; + resize(tempClients[focus_client_index], target_geom, 0); + } else if (tempClients[focus_client_index]->ismaximizescreen) { + target_geom.y = m->w.y + cur_gappov; + resize(tempClients[focus_client_index], target_geom, 0); + } else if (need_scroller) { if (scroller_focus_center || ((!m->prevsel || - (ISTILED(m->prevsel) && + (ISSCROLLTILED(m->prevsel) && (m->prevsel->scroller_proportion * max_client_height) + (root_client->scroller_proportion * max_client_height) > m->w.height - 2 * scroller_structs - cur_gappiv)) && @@ -278,14 +321,17 @@ void vertical_scroller(Monitor *m) { for (i = 1; i <= focus_client_index; i++) { c = tempClients[focus_client_index - i]; target_geom.height = max_client_height * c->scroller_proportion; + vertical_scroll_adjust_fullandmax(c, &target_geom); target_geom.y = tempClients[focus_client_index - i + 1]->geom.y - cur_gappiv - target_geom.height; + resize(c, target_geom, 0); } for (i = 1; i < n - focus_client_index; i++) { c = tempClients[focus_client_index + i]; target_geom.height = max_client_height * c->scroller_proportion; + vertical_scroll_adjust_fullandmax(c, &target_geom); target_geom.y = tempClients[focus_client_index + i - 1]->geom.y + cur_gappiv + tempClients[focus_client_index + i - 1]->geom.height; diff --git a/src/mango.c b/src/mango.c index 06e1d616..540a0257 100644 --- a/src/mango.c +++ b/src/mango.c @@ -104,6 +104,9 @@ #define ISTILED(A) \ (A && !(A)->isfloating && !(A)->isminied && !(A)->iskilling && \ !(A)->ismaximizescreen && !(A)->isfullscreen && !(A)->isunglobal) +#define ISSCROLLTILED(A) \ + (A && !(A)->isfloating && !(A)->isminied && !(A)->iskilling && \ + !(A)->isunglobal) #define VISIBLEON(C, M) \ ((C) && (M) && (C)->mon == (M) && ((C)->tags & (M)->tagset[(M)->seltags])) #define LENGTH(X) (sizeof X / sizeof X[0]) @@ -479,6 +482,7 @@ struct Monitor { int asleep; unsigned int visible_clients; unsigned int visible_tiling_clients; + unsigned int visible_scroll_tiling_clients; bool has_visible_fullscreen_client; struct wlr_scene_optimized_blur *blur; char last_surface_ws_name[256]; @@ -733,6 +737,7 @@ static void refresh_monitors_workspaces_status(Monitor *m); static void init_client_properties(Client *c); static float *get_border_color(Client *c); static void request_fresh_all_monitors(void); +static void clear_fullscreen_and_maximized_state(Monitor *m); #include "data/static_keymap.h" #include "dispatch/bind_declare.h" @@ -930,8 +935,26 @@ void applybounds(Client *c, struct wlr_box *bbox) { c->geom.y = bbox->y; } +void clear_fullscreen_and_maximized_state(Monitor *m) { + Client *fc = NULL; + wl_list_for_each(fc, &clients, link) { + if (fc && VISIBLEON(fc, m) && ISFULLSCREEN(fc)) { + clear_fullscreen_flag(fc); + } + } +} + /*清除全屏标志,还原全屏时清0的border*/ void clear_fullscreen_flag(Client *c) { + + if ((c->mon->pertag->ltidxs[get_tags_first_tag_num(c->tags)]->id == + SCROLLER || + c->mon->pertag->ltidxs[get_tags_first_tag_num(c->tags)]->id == + VERTICAL_SCROLLER) && + !c->isfloating) { + return; + } + if (c->isfullscreen) { setfullscreen(c, false); } @@ -3149,7 +3172,6 @@ void focusclient(Client *c, int lift) { if (c && selmon->prevsel && (selmon->prevsel->tags & selmon->tagset[selmon->seltags]) && (c->tags & selmon->tagset[selmon->seltags]) && !c->isfloating && - !c->isfullscreen && !c->ismaximizescreen && is_scroller_layout(selmon)) { arrange(selmon, false); } @@ -3702,9 +3724,9 @@ mapnotify(struct wl_listener *listener, void *data) { // tile at the top wl_list_insert(&clients, &c->link); // 新窗口是master,头部入栈 else if (selmon && is_scroller_layout(selmon) && - selmon->visible_tiling_clients > 0) { + selmon->visible_scroll_tiling_clients > 0) { - if (selmon->sel && ISTILED(selmon->sel) && + if (selmon->sel && ISSCROLLTILED(selmon->sel) && VISIBLEON(selmon->sel, selmon)) { at_client = selmon->sel; } else { @@ -4536,7 +4558,8 @@ void setmaximizescreen(Client *c, int maximizescreen) { maximizescreen_box.width = c->mon->w.width - 2 * gappoh; maximizescreen_box.height = c->mon->w.height - 2 * gappov; wlr_scene_node_raise_to_top(&c->scene->node); // 将视图提升到顶层 - resize(c, maximizescreen_box, 0); + if (!is_scroller_layout(c->mon) || c->isfloating) + resize(c, maximizescreen_box, 0); c->ismaximizescreen = 1; } else { c->bw = c->isnoborder ? 0 : borderpx; @@ -4545,9 +4568,8 @@ void setmaximizescreen(Client *c, int maximizescreen) { setfloating(c, 1); } - wlr_scene_node_reparent(&c->scene->node, layers[maximizescreen ? LyrTile - : c->isfloating ? LyrTop - : LyrTile]); + wlr_scene_node_reparent(&c->scene->node, + layers[c->isfloating ? LyrTop : LyrTile]); if (!c->ismaximizescreen) { set_size_per(c->mon, c); } @@ -4593,7 +4615,8 @@ void setfullscreen(Client *c, int fullscreen) // 用自定义全屏代理自带 c->bw = 0; wlr_scene_node_raise_to_top(&c->scene->node); // 将视图提升到顶层 - resize(c, c->mon->m, 1); + if (!is_scroller_layout(c->mon) || c->isfloating) + resize(c, c->mon->m, 1); c->isfullscreen = 1; } else { c->bw = c->isnoborder ? 0 : borderpx; @@ -5168,7 +5191,11 @@ unsigned int want_restore_fullscreen(Client *target_client) { Client *c = NULL; wl_list_for_each(c, &clients, link) { if (c && c != target_client && c->tags == target_client->tags && - c == selmon->sel) { + c == selmon->sel && + c->mon->pertag->ltidxs[get_tags_first_tag_num(c->tags)]->id != + SCROLLER && + c->mon->pertag->ltidxs[get_tags_first_tag_num(c->tags)]->id != + VERTICAL_SCROLLER) { return 0; } } From 9c8f9e3b38f64b5aeee09ebc60d1468f3975dee9 Mon Sep 17 00:00:00 2001 From: Jorrit van der Heide Date: Tue, 11 Nov 2025 17:03:43 +0100 Subject: [PATCH 337/591] fix: nixos example --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 8e982b60..967e66a7 100644 --- a/README.md +++ b/README.md @@ -189,7 +189,10 @@ Here's an example of using the modules in a flake: inputs.nixpkgs.follows = "nixpkgs"; }; flake-parts.url = "github:hercules-ci/flake-parts"; - mango.url = "github:DreamMaoMao/mango"; + mango = { + url = "github:DreamMaoMao/mango"; + inputs.nixpkgs.follows = "nixpkgs"; + }; }; outputs = inputs@{ self, flake-parts, ... }: From d941e0078eb7773a27f72890425eb62f085e417d Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sun, 16 Nov 2025 07:19:29 +0800 Subject: [PATCH 338/591] fix: fullscreen and maximize window overflow screen --- src/animation/client.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/animation/client.h b/src/animation/client.h index e3673a20..d26265bb 100644 --- a/src/animation/client.h +++ b/src/animation/client.h @@ -446,7 +446,7 @@ struct ivec2 clip_to_hide(Client *c, struct wlr_box *clip_box) { int offsetx = 0, offsety = 0, offsetw = 0, offseth = 0; struct ivec2 offset = {0, 0, 0, 0}; - if (!ISTILED(c) && !c->animation.tagining && !c->animation.tagouted && + if (!ISSCROLLTILED(c) && !c->animation.tagining && !c->animation.tagouted && !c->animation.tagouting) return offset; @@ -467,7 +467,7 @@ struct ivec2 clip_to_hide(Client *c, struct wlr_box *clip_box) { 需要主要border超出屏幕的时候不计算如偏差之内而是 要等窗口表面超出才开始计算偏差 */ - if (ISTILED(c) || c->animation.tagining || c->animation.tagouted || + if (ISSCROLLTILED(c) || c->animation.tagining || c->animation.tagouted || c->animation.tagouting) { if (left_out_offset > 0) { offsetx = GEZERO(left_out_offset - bw); @@ -495,7 +495,7 @@ struct ivec2 clip_to_hide(Client *c, struct wlr_box *clip_box) { offset.height = offseth; if ((clip_box->width + bw <= 0 || clip_box->height + bw <= 0) && - (ISTILED(c) || c->animation.tagouting || c->animation.tagining)) { + (ISSCROLLTILED(c) || c->animation.tagouting || c->animation.tagining)) { c->is_clip_to_hide = true; wlr_scene_node_set_enabled(&c->scene->node, false); } else if (c->is_clip_to_hide && VISIBLEON(c, c->mon)) { From 58d5938e147bb2b1173ffd69ef00dc18d0e87c54 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Tue, 18 Nov 2025 19:21:19 +0800 Subject: [PATCH 339/591] opt: support hot reload cursor config --- src/config/parse_config.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/config/parse_config.h b/src/config/parse_config.h index 074660bf..d7b32234 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -3110,6 +3110,12 @@ void reapply_monitor_rules(void) { } } +void reapply_cursor_style(void) { + if (cursor_mgr) + wlr_xcursor_manager_destroy(cursor_mgr); + cursor_mgr = wlr_xcursor_manager_create(config.cursor_theme, cursor_size); +} + void reapply_border(void) { Client *c = NULL; @@ -3211,6 +3217,7 @@ void reset_option(void) { set_env(); run_exec(); + reapply_cursor_style(); reapply_border(); reapply_keyboard(); reapply_pointer(); From 8e4d3b7aac483c31514fe93c9898037889620475 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Wed, 19 Nov 2025 12:45:04 +0800 Subject: [PATCH 340/591] update readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 967e66a7..b321be5b 100644 --- a/README.md +++ b/README.md @@ -106,7 +106,7 @@ cd wlroots meson build -Dprefix=/usr sudo ninja -C build install -git clone https://github.com/wlrfx/scenefx.git +git clone -b 0.4.1 https://github.com/wlrfx/scenefx.git cd scenefx meson build -Dprefix=/usr sudo ninja -C build install From e22cf99e742bfc93f73c862b351ee2557f20b1ab Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Thu, 20 Nov 2025 10:34:32 +0800 Subject: [PATCH 341/591] feat: support relative path for source keyword --- src/config/parse_config.h | 48 +++++++++++++++++++++++++++------------ 1 file changed, 33 insertions(+), 15 deletions(-) diff --git a/src/config/parse_config.h b/src/config/parse_config.h index d7b32234..a58a106f 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -2274,35 +2274,53 @@ void parse_config_line(Config *config, const char *line) { void parse_config_file(Config *config, const char *file_path) { FILE *file; - // 检查路径是否以 ~/ 开头 - if (file_path[0] == '~' && (file_path[1] == '/' || file_path[1] == '\0')) { + char full_path[1024]; + + if (file_path[0] == '.' && file_path[1] == '/') { + // Relative path + + const char *mangoconfig = getenv("MANGOCONFIG"); + if (mangoconfig && mangoconfig[0] != '\0') { + snprintf(full_path, sizeof(full_path), "%s/%s", mangoconfig, + file_path + 1); + } else { + const char *home = getenv("HOME"); + if (!home) { + fprintf(stderr, "Error: HOME environment variable not set.\n"); + return; + } + snprintf(full_path, sizeof(full_path), "%s/.config/mango/%s", home, + file_path + 1); + } + file = fopen(full_path, "r"); + + } else if (file_path[0] == '~' && + (file_path[1] == '/' || file_path[1] == '\0')) { + // Home directory + const char *home = getenv("HOME"); if (!home) { fprintf(stderr, "Error: HOME environment variable not set.\n"); return; } - - // 构建完整路径(家目录 + / + 原路径去掉 ~) - char full_path[1024]; snprintf(full_path, sizeof(full_path), "%s%s", home, file_path + 1); - file = fopen(full_path, "r"); - if (!file) { - perror("Error opening file"); - return; - } + } else { + // Absolute path file = fopen(file_path, "r"); - if (!file) { - perror("Error opening file"); - return; - } + } + + if (!file) { + perror("Error opening file"); + return; } char line[512]; while (fgets(line, sizeof(line), file)) { - if (line[0] == '#' || line[0] == '\n') + if (line[0] == '#' || line[0] == '\n') { continue; + } parse_config_line(config, line); } From e7cb4f77f37c3ebb15bcd803adcadd9d64f92039 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Thu, 20 Nov 2025 21:21:29 +0800 Subject: [PATCH 342/591] fix: wrong scroll judge when disable animaitons --- src/layout/horizontal.h | 2 +- src/layout/vertical.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/layout/horizontal.h b/src/layout/horizontal.h index ff517cc1..99bb0926 100644 --- a/src/layout/horizontal.h +++ b/src/layout/horizontal.h @@ -301,7 +301,7 @@ void scroller(Monitor *m) { for (i = 0; i < n; i++) { c = tempClients[i]; if (root_client == c) { - if (!c->is_pending_open_animation && + if ((!c->is_pending_open_animation || !animations) && c->geom.x >= m->w.x + scroller_structs && c->geom.x + c->geom.width <= m->w.x + m->w.width - scroller_structs) { diff --git a/src/layout/vertical.h b/src/layout/vertical.h index cef0e3bb..5cc8ceb1 100644 --- a/src/layout/vertical.h +++ b/src/layout/vertical.h @@ -263,7 +263,7 @@ void vertical_scroller(Monitor *m) { for (i = 0; i < n; i++) { c = tempClients[i]; if (root_client == c) { - if (!c->is_pending_open_animation && + if ((!c->is_pending_open_animation || !animations) && c->geom.y >= m->w.y + scroller_structs && c->geom.y + c->geom.height <= m->w.y + m->w.height - scroller_structs) { From a0824c05df5482fde37898b9a5d81f779167b60e Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Thu, 20 Nov 2025 22:47:12 +0800 Subject: [PATCH 343/591] opt: optimize scroll judge when open new client --- src/layout/horizontal.h | 3 +-- src/layout/vertical.h | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/layout/horizontal.h b/src/layout/horizontal.h index 99bb0926..2385c848 100644 --- a/src/layout/horizontal.h +++ b/src/layout/horizontal.h @@ -301,8 +301,7 @@ void scroller(Monitor *m) { for (i = 0; i < n; i++) { c = tempClients[i]; if (root_client == c) { - if ((!c->is_pending_open_animation || !animations) && - c->geom.x >= m->w.x + scroller_structs && + if (c->geom.x >= m->w.x + scroller_structs && c->geom.x + c->geom.width <= m->w.x + m->w.width - scroller_structs) { need_scroller = false; diff --git a/src/layout/vertical.h b/src/layout/vertical.h index 5cc8ceb1..7eb95291 100644 --- a/src/layout/vertical.h +++ b/src/layout/vertical.h @@ -263,8 +263,7 @@ void vertical_scroller(Monitor *m) { for (i = 0; i < n; i++) { c = tempClients[i]; if (root_client == c) { - if ((!c->is_pending_open_animation || !animations) && - c->geom.y >= m->w.y + scroller_structs && + if (c->geom.y >= m->w.y + scroller_structs && c->geom.y + c->geom.height <= m->w.y + m->w.height - scroller_structs) { need_scroller = false; From 03ee277ef604639e623a2c7a5cbafa7ecf3c76d4 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Fri, 21 Nov 2025 14:50:27 +0800 Subject: [PATCH 344/591] opt: allow init focus to on-demand-focus layer --- src/mango.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/mango.c b/src/mango.c index 540a0257..8a27b751 100644 --- a/src/mango.c +++ b/src/mango.c @@ -2210,6 +2210,15 @@ void maplayersurfacenotify(struct wl_listener *listener, void *data) { } // 刷新布局,让窗口能感应到exclude_zone变化以及设置独占表面 arrangelayers(l->mon); + + // 按需交互layer需要像正常窗口一样抢占非独占layer的焦点 + if (!exclusive_focus && + l->layer_surface->current.keyboard_interactive == + ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_ON_DEMAND) { + focusclient(NULL, 0); + client_notify_enter(l->layer_surface->surface, + wlr_seat_get_keyboard(seat)); + } } void commitlayersurfacenotify(struct wl_listener *listener, void *data) { From c004f7460c48a5c317df1ec2b4cb4ed6c3ca57a6 Mon Sep 17 00:00:00 2001 From: David Delarosa Date: Thu, 20 Nov 2025 14:40:34 +0200 Subject: [PATCH 345/591] nix: add portals.conf file --- nix/nixos-modules.nix | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/nix/nixos-modules.nix b/nix/nixos-modules.nix index 5d0aa61e..33811022 100644 --- a/nix/nixos-modules.nix +++ b/nix/nixos-modules.nix @@ -26,6 +26,25 @@ in { xdg.portal = { enable = lib.mkDefault true; + config = { + mango = { + default = [ + "gtk" + ]; + # except those + "org.freedesktop.impl.portal.Secret" = ["gnome-keyring"]; + "org.freedesktop.impl.portal.ScreenCast" = ["wlr"]; + "org.freedesktop.impl.portal.ScreenShot" = ["wlr"]; + + # wlr does not have this interface + "org.freedesktop.impl.portal.Inhibit" = []; + }; + }; + extraPortals = with pkgs; [ + xdg-desktop-portal-wlr + xdg-desktop-portal-gtk + ]; + wlr.enable = lib.mkDefault true; configPackages = [cfg.package]; From e2ee985b8fa72aa4755718187de4e520cdbf63e4 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Wed, 26 Nov 2025 10:09:06 +0800 Subject: [PATCH 346/591] bump version to 0.10.6 --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 041a1fdf..b02e0fd1 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('mango', ['c', 'cpp'], - version : '0.10.5', + version : '0.10.6', ) subdir('protocols') From 2f9cabe4b23cb91ebda707b27df12fe30ddeb86e Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Thu, 27 Nov 2025 22:40:41 +0800 Subject: [PATCH 347/591] fix: sloppyfocus not work when move cursor slowly --- src/fetch/common.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/fetch/common.h b/src/fetch/common.h index 33d7272f..41dc9944 100644 --- a/src/fetch/common.h +++ b/src/fetch/common.h @@ -115,6 +115,10 @@ void xytonode(double x, double y, struct wlr_surface **psurface, Client **pc, surface = wlr_scene_surface_try_from_buffer( wlr_scene_buffer_from_node(node)) ->surface; + else if (node->type == WLR_SCENE_NODE_RECT) { + surface = NULL; + break; + } /* start from the topmost layer, find a sureface that can be focused by pointer, From 28ab0e6343a701d552a755ff41ff128a42ede8a8 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Fri, 28 Nov 2025 11:34:48 +0800 Subject: [PATCH 348/591] opt: re-judge the focus strategy of the layer when re-arrangelayer --- src/mango.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/mango.c b/src/mango.c index 8a27b751..02b6ffc7 100644 --- a/src/mango.c +++ b/src/mango.c @@ -1563,6 +1563,7 @@ void reset_exclusive_layer(Monitor *m) { unsigned int layers_above_shell[] = { ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY, ZWLR_LAYER_SHELL_V1_LAYER_TOP, + ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM, }; if (!m) @@ -1570,6 +1571,16 @@ void reset_exclusive_layer(Monitor *m) { for (i = 0; i < (int)LENGTH(layers_above_shell); i++) { wl_list_for_each_reverse(l, &m->layers[layers_above_shell[i]], link) { + if (l == exclusive_focus && + l->layer_surface->current.keyboard_interactive != + ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE) + exclusive_focus = NULL; + if (l->layer_surface->current.keyboard_interactive == + ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE && + l->layer_surface->surface == + seat->keyboard_state.focused_surface) + focusclient(focustop(selmon), 1); + if (locked || l->layer_surface->current.keyboard_interactive != ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE || From b768f72eaa82eec6ea75811e2a45253671eda472 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Fri, 28 Nov 2025 12:42:18 +0800 Subject: [PATCH 349/591] opt: allow ime in on-demand layer --- src/mango.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/mango.c b/src/mango.c index 02b6ffc7..ee3b4280 100644 --- a/src/mango.c +++ b/src/mango.c @@ -2227,6 +2227,8 @@ void maplayersurfacenotify(struct wl_listener *listener, void *data) { l->layer_surface->current.keyboard_interactive == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_ON_DEMAND) { focusclient(NULL, 0); + dwl_im_relay_set_focus(dwl_input_method_relay, + l->layer_surface->surface); client_notify_enter(l->layer_surface->surface, wlr_seat_get_keyboard(seat)); } From 16368a8781b278fd76eb3757dc9692967e9db19f Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Fri, 28 Nov 2025 12:49:06 +0800 Subject: [PATCH 350/591] opt: optimize code struct --- src/mango.c | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/src/mango.c b/src/mango.c index ee3b4280..016f06c6 100644 --- a/src/mango.c +++ b/src/mango.c @@ -1557,6 +1557,12 @@ void apply_window_snap(Client *c) { resize(c, c->geom, 0); } +void focuslayer(LayerSurface *l) { + focusclient(NULL, 0); + dwl_im_relay_set_focus(dwl_input_method_relay, l->layer_surface->surface); + client_notify_enter(l->layer_surface->surface, wlr_seat_get_keyboard(seat)); +} + void reset_exclusive_layer(Monitor *m) { LayerSurface *l = NULL; int i; @@ -1587,12 +1593,8 @@ void reset_exclusive_layer(Monitor *m) { !l->mapped || l == exclusive_focus) continue; /* Deactivate the focused client. */ - focusclient(NULL, 0); exclusive_focus = l; - dwl_im_relay_set_focus(dwl_input_method_relay, - l->layer_surface->surface); - client_notify_enter(l->layer_surface->surface, - wlr_seat_get_keyboard(seat)); + focuslayer(l); return; } } @@ -1893,11 +1895,7 @@ buttonpress(struct wl_listener *listener, void *data) { if (l && !exclusive_focus && l->layer_surface->current.keyboard_interactive == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_ON_DEMAND) { - focusclient(NULL, 0); - dwl_im_relay_set_focus(dwl_input_method_relay, - l->layer_surface->surface); - client_notify_enter(l->layer_surface->surface, - wlr_seat_get_keyboard(seat)); + focuslayer(l); } } @@ -2226,11 +2224,7 @@ void maplayersurfacenotify(struct wl_listener *listener, void *data) { if (!exclusive_focus && l->layer_surface->current.keyboard_interactive == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_ON_DEMAND) { - focusclient(NULL, 0); - dwl_im_relay_set_focus(dwl_input_method_relay, - l->layer_surface->surface); - client_notify_enter(l->layer_surface->surface, - wlr_seat_get_keyboard(seat)); + focuslayer(l); } } From 006cf46c52467ba44b7a0e23cc4a981c0f34e9dc Mon Sep 17 00:00:00 2001 From: Rexiel Scarlet <37258415+Rexcrazy804@users.noreply.github.com> Date: Sun, 23 Nov 2025 20:20:47 +0400 Subject: [PATCH 351/591] feat: support transparent wlr session lock --- src/config/parse_config.h | 5 +++++ src/config/preset.h | 1 + src/mango.c | 8 ++++++-- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/config/parse_config.h b/src/config/parse_config.h index a58a106f..b750c7c2 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -339,6 +339,7 @@ typedef struct { int adaptive_sync; int allow_tearing; int allow_shortcuts_inhibit; + int transparent_wlr_lock; struct xkb_rule_names xkb_rules; @@ -1221,6 +1222,8 @@ void parse_option(Config *config, char *key, char *value) { config->allow_tearing = atoi(value); } else if (strcmp(key, "allow_shortcuts_inhibit") == 0) { config->allow_shortcuts_inhibit = atoi(value); + } else if (strcmp(key, "transparent_wlr_lock") == 0) { + config->transparent_wlr_lock = atoi(value); } else if (strcmp(key, "no_border_when_single") == 0) { config->no_border_when_single = atoi(value); } else if (strcmp(key, "no_radius_when_single") == 0) { @@ -2671,6 +2674,7 @@ void override_config(void) { adaptive_sync = CLAMP_INT(config.adaptive_sync, 0, 1); allow_tearing = CLAMP_INT(config.allow_tearing, 0, 2); allow_shortcuts_inhibit = CLAMP_INT(config.allow_shortcuts_inhibit, 0, 1); + transparent_wlr_lock = CLAMP_INT(config.transparent_wlr_lock, 0, 1); axis_bind_apply_timeout = CLAMP_INT(config.axis_bind_apply_timeout, 0, 1000); focus_on_activate = CLAMP_INT(config.focus_on_activate, 0, 1); @@ -2849,6 +2853,7 @@ void set_value_default() { config.adaptive_sync = adaptive_sync; config.allow_tearing = allow_tearing; config.allow_shortcuts_inhibit = allow_shortcuts_inhibit; + config.transparent_wlr_lock = transparent_wlr_lock; config.no_border_when_single = no_border_when_single; config.no_radius_when_single = no_radius_when_single; config.snap_distance = snap_distance; diff --git a/src/config/preset.h b/src/config/preset.h index eaa7be22..da8100ab 100644 --- a/src/config/preset.h +++ b/src/config/preset.h @@ -103,6 +103,7 @@ int warpcursor = 1; /* Warp cursor to focused client */ int xwayland_persistence = 1; /* xwayland persistence */ int syncobj_enable = 0; int adaptive_sync = 0; +int transparent_wlr_lock = 0; double drag_refresh_interval = 30.0; int allow_tearing = TEARING_DISABLED; int allow_shortcuts_inhibit = SHORTCUTS_INHIBIT_ENABLE; diff --git a/src/mango.c b/src/mango.c index 8a27b751..287e4a6b 100644 --- a/src/mango.c +++ b/src/mango.c @@ -3029,7 +3029,9 @@ void destroylock(SessionLock *lock, int unlock) { if ((locked = !unlock)) goto destroy; - wlr_scene_node_set_enabled(&locked_bg->node, false); + if (locked_bg->node.enabled) { + wlr_scene_node_set_enabled(&locked_bg->node, false); + } focusclient(focustop(selmon), 0); motionnotify(0, NULL, 0, 0, 0, 0); @@ -3567,7 +3569,9 @@ void pending_kill_client(Client *c) { void locksession(struct wl_listener *listener, void *data) { struct wlr_session_lock_v1 *session_lock = data; SessionLock *lock; - wlr_scene_node_set_enabled(&locked_bg->node, true); + if (!transparent_wlr_lock) { + wlr_scene_node_set_enabled(&locked_bg->node, true); + } if (cur_lock) { wlr_session_lock_v1_destroy(session_lock); return; From 7c7a9437e67b120df24fd4aa0d6ab5a963bc934d Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sat, 29 Nov 2025 16:31:09 +0800 Subject: [PATCH 352/591] opt: optimize option name transparent_wlr_lock to allow_lock_transparent --- src/config/parse_config.h | 10 +++++----- src/config/preset.h | 2 +- src/mango.c | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/config/parse_config.h b/src/config/parse_config.h index b750c7c2..7196270d 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -339,7 +339,7 @@ typedef struct { int adaptive_sync; int allow_tearing; int allow_shortcuts_inhibit; - int transparent_wlr_lock; + int allow_lock_transparent; struct xkb_rule_names xkb_rules; @@ -1222,8 +1222,8 @@ void parse_option(Config *config, char *key, char *value) { config->allow_tearing = atoi(value); } else if (strcmp(key, "allow_shortcuts_inhibit") == 0) { config->allow_shortcuts_inhibit = atoi(value); - } else if (strcmp(key, "transparent_wlr_lock") == 0) { - config->transparent_wlr_lock = atoi(value); + } else if (strcmp(key, "allow_lock_transparent") == 0) { + config->allow_lock_transparent = atoi(value); } else if (strcmp(key, "no_border_when_single") == 0) { config->no_border_when_single = atoi(value); } else if (strcmp(key, "no_radius_when_single") == 0) { @@ -2674,7 +2674,7 @@ void override_config(void) { adaptive_sync = CLAMP_INT(config.adaptive_sync, 0, 1); allow_tearing = CLAMP_INT(config.allow_tearing, 0, 2); allow_shortcuts_inhibit = CLAMP_INT(config.allow_shortcuts_inhibit, 0, 1); - transparent_wlr_lock = CLAMP_INT(config.transparent_wlr_lock, 0, 1); + allow_lock_transparent = CLAMP_INT(config.allow_lock_transparent, 0, 1); axis_bind_apply_timeout = CLAMP_INT(config.axis_bind_apply_timeout, 0, 1000); focus_on_activate = CLAMP_INT(config.focus_on_activate, 0, 1); @@ -2853,7 +2853,7 @@ void set_value_default() { config.adaptive_sync = adaptive_sync; config.allow_tearing = allow_tearing; config.allow_shortcuts_inhibit = allow_shortcuts_inhibit; - config.transparent_wlr_lock = transparent_wlr_lock; + config.allow_lock_transparent = allow_lock_transparent; config.no_border_when_single = no_border_when_single; config.no_radius_when_single = no_radius_when_single; config.snap_distance = snap_distance; diff --git a/src/config/preset.h b/src/config/preset.h index da8100ab..4032a757 100644 --- a/src/config/preset.h +++ b/src/config/preset.h @@ -103,7 +103,7 @@ int warpcursor = 1; /* Warp cursor to focused client */ int xwayland_persistence = 1; /* xwayland persistence */ int syncobj_enable = 0; int adaptive_sync = 0; -int transparent_wlr_lock = 0; +int allow_lock_transparent = 0; double drag_refresh_interval = 30.0; int allow_tearing = TEARING_DISABLED; int allow_shortcuts_inhibit = SHORTCUTS_INHIBIT_ENABLE; diff --git a/src/mango.c b/src/mango.c index ca8d8c9b..ff9ed6eb 100644 --- a/src/mango.c +++ b/src/mango.c @@ -3576,7 +3576,7 @@ void pending_kill_client(Client *c) { void locksession(struct wl_listener *listener, void *data) { struct wlr_session_lock_v1 *session_lock = data; SessionLock *lock; - if (!transparent_wlr_lock) { + if (!allow_lock_transparent) { wlr_scene_node_set_enabled(&locked_bg->node, true); } if (cur_lock) { From b3ccf43453491196be8a94c672394dcc527803a0 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sat, 29 Nov 2025 17:30:01 +0800 Subject: [PATCH 353/591] opt: not swallow the isminied window --- src/mango.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mango.c b/src/mango.c index ff9ed6eb..b80d3d89 100644 --- a/src/mango.c +++ b/src/mango.c @@ -1376,7 +1376,7 @@ void applyrules(Client *c) { if (!c->noswallow && !c->isfloating && !client_is_float_type(c) && !c->surface.xdg->initial_commit) { Client *p = termforwin(c); - if (p) { + if (p && !p->isminied) { c->swallowedby = p; p->swallowing = c; wl_list_remove(&c->link); From 09c19205150f067fd524feafebbaa8744a3e0885 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sat, 29 Nov 2025 17:33:57 +0800 Subject: [PATCH 354/591] opt: correct var isminized to isminimized --- src/dispatch/bind_define.h | 12 +++++----- src/ext-protocol/foreign-toplevel.h | 4 ++-- src/mango.c | 34 ++++++++++++++--------------- 3 files changed, 25 insertions(+), 25 deletions(-) diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index d79a7c65..a1418300 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -133,7 +133,7 @@ int focuslast(const Arg *arg) { unsigned int target = 0; wl_list_for_each(c, &fstack, flink) { - if (c->iskilling || c->isminied || c->isunglobal || + if (c->iskilling || c->isminimized || c->isunglobal || !client_surface(c)->mapped || client_is_unmanaged(c) || client_is_x11_popup(c)) continue; @@ -471,7 +471,7 @@ int restore_minimized(const Arg *arg) { if (selmon && selmon->sel && selmon->sel->is_in_scratchpad && selmon->sel->is_scratchpad_show) { - selmon->sel->isminied = 0; + selmon->sel->isminimized = 0; selmon->sel->is_scratchpad_show = 0; selmon->sel->is_in_scratchpad = 0; selmon->sel->isnamedscratchpad = 0; @@ -480,7 +480,7 @@ int restore_minimized(const Arg *arg) { } wl_list_for_each(c, &clients, link) { - if (c->isminied && !c->isnamedscratchpad) { + if (c->isminimized && !c->isnamedscratchpad) { c->is_scratchpad_show = 0; c->is_in_scratchpad = 0; c->isnamedscratchpad = 0; @@ -1122,7 +1122,7 @@ int toggle_scratchpad(const Arg *arg) { continue; } - if (single_scratchpad && c->isnamedscratchpad && !c->isminied) { + if (single_scratchpad && c->isnamedscratchpad && !c->isminimized) { set_minimized(c); continue; } @@ -1447,7 +1447,7 @@ int minimized(const Arg *arg) { if (selmon && selmon->isoverview) return 0; - if (selmon->sel && !selmon->sel->isminied) { + if (selmon->sel && !selmon->sel->isminimized) { set_minimized(selmon->sel); } return 0; @@ -1469,7 +1469,7 @@ int toggleoverview(const Arg *arg) { wl_list_for_each(c, &clients, link) if (c && c->mon == selmon && !client_is_unmanaged(c) && !client_is_x11_popup(c) && - !c->isminied && + !c->isminimized && !c->isunglobal) { visible_client_number++; } diff --git a/src/ext-protocol/foreign-toplevel.h b/src/ext-protocol/foreign-toplevel.h index adfcd21b..0bb649e0 100644 --- a/src/ext-protocol/foreign-toplevel.h +++ b/src/ext-protocol/foreign-toplevel.h @@ -9,12 +9,12 @@ void handle_foreign_activate_request(struct wl_listener *listener, void *data) { if (c && c->swallowing) return; - if (c && !c->isminied && c == selmon->sel) { + if (c && !c->isminimized && c == selmon->sel) { set_minimized(c); return; } - if (c->isminied) { + if (c->isminimized) { c->is_in_scratchpad = 0; c->isnamedscratchpad = 0; c->is_scratchpad_show = 0; diff --git a/src/mango.c b/src/mango.c index b80d3d89..5c804a0a 100644 --- a/src/mango.c +++ b/src/mango.c @@ -102,10 +102,10 @@ A->geom.x + A->geom.width <= A->mon->m.x + A->mon->m.width && \ A->geom.y + A->geom.height <= A->mon->m.y + A->mon->m.height) #define ISTILED(A) \ - (A && !(A)->isfloating && !(A)->isminied && !(A)->iskilling && \ + (A && !(A)->isfloating && !(A)->isminimized && !(A)->iskilling && \ !(A)->ismaximizescreen && !(A)->isfullscreen && !(A)->isunglobal) #define ISSCROLLTILED(A) \ - (A && !(A)->isfloating && !(A)->isminied && !(A)->iskilling && \ + (A && !(A)->isfloating && !(A)->isminimized && !(A)->iskilling && \ !(A)->isunglobal) #define VISIBLEON(C, M) \ ((C) && (M) && (C)->mon == (M) && ((C)->tags & (M)->tagset[(M)->seltags])) @@ -315,7 +315,7 @@ struct Client { unsigned int configure_serial; struct wlr_foreign_toplevel_handle_v1 *foreign_toplevel; int isfloating, isurgent, isfullscreen, isfakefullscreen, - need_float_size_reduce, isminied, isoverlay, isnosizehint, + need_float_size_reduce, isminimized, isoverlay, isnosizehint, ignore_maximize, ignore_minimize; int ismaximizescreen; int overview_backup_bw; @@ -1009,7 +1009,7 @@ void swallow(Client *c, Client *w) { c->isurgent = w->isurgent; c->isfullscreen = w->isfullscreen; c->ismaximizescreen = w->ismaximizescreen; - c->isminied = w->isminied; + c->isminimized = w->isminimized; c->is_in_scratchpad = w->is_in_scratchpad; c->is_scratchpad_show = w->is_scratchpad_show; c->tags = w->tags; @@ -1029,7 +1029,7 @@ void swallow(Client *c, Client *w) { if (!c->foreign_toplevel && c->mon) add_foreign_toplevel(c); - if (c->isminied && c->foreign_toplevel) { + if (c->isminimized && c->foreign_toplevel) { wlr_foreign_toplevel_handle_v1_set_activated(c->foreign_toplevel, false); wlr_foreign_toplevel_handle_v1_set_minimized(c->foreign_toplevel, true); @@ -1376,7 +1376,7 @@ void applyrules(Client *c) { if (!c->noswallow && !c->isfloating && !client_is_float_type(c) && !c->surface.xdg->initial_commit) { Client *p = termforwin(c); - if (p && !p->isminied) { + if (p && !p->isminimized) { c->swallowedby = p; p->swallowing = c; wl_list_remove(&c->link); @@ -3633,7 +3633,7 @@ void init_client_properties(Client *c) { c->iskilling = 0; c->istagswitching = 0; c->isglobal = 0; - c->isminied = 0; + c->isminimized = 0; c->isoverlay = 0; c->isunglobal = 0; c->is_in_scratchpad = 0; @@ -3803,7 +3803,7 @@ void maximizenotify(struct wl_listener *listener, void *data) { void unminimize(Client *c) { if (c && c->is_in_scratchpad && c->is_scratchpad_show) { - c->isminied = 0; + c->isminimized = 0; c->is_scratchpad_show = 0; c->is_in_scratchpad = 0; c->isnamedscratchpad = 0; @@ -3811,7 +3811,7 @@ void unminimize(Client *c) { return; } - if (c && c->isminied) { + if (c && c->isminimized) { show_hide_client(c); c->is_scratchpad_show = 0; c->is_in_scratchpad = 0; @@ -3831,7 +3831,7 @@ void set_minimized(Client *c) { c->oldtags = c->mon->tagset[c->mon->seltags]; c->mini_restore_tag = c->tags; c->tags = 0; - c->isminied = 1; + c->isminimized = 1; c->is_in_scratchpad = 1; c->is_scratchpad_show = 0; focusclient(focustop(selmon), 1); @@ -3846,15 +3846,15 @@ void minimizenotify(struct wl_listener *listener, void *data) { Client *c = wl_container_of(listener, c, minimize); - if (!c || !c->mon || c->iskilling || c->isminied) + if (!c || !c->mon || c->iskilling || c->isminimized) return; if (client_request_minimize(c, data) && !c->ignore_minimize) { - if (!c->isminied) + if (!c->isminimized) set_minimized(c); client_set_minimized(c, true); } else { - if (c->isminied) + if (c->isminimized) unminimize(c); client_set_minimized(c, false); } @@ -4845,7 +4845,7 @@ void show_hide_client(Client *c) { c->tags = c->oldtags; arrange(c->mon, false); } - c->isminied = 0; + c->isminimized = 0; wlr_foreign_toplevel_handle_v1_set_minimized(c->foreign_toplevel, false); focusclient(c, 1); wlr_foreign_toplevel_handle_v1_set_activated(c->foreign_toplevel, true); @@ -5334,7 +5334,7 @@ void unmapnotify(struct wl_listener *listener, void *data) { Monitor *m = NULL; c->iskilling = 1; - if (animations && !c->is_clip_to_hide && !c->isminied && + if (animations && !c->is_clip_to_hide && !c->isminimized && (!c->mon || VISIBLEON(c, c->mon))) init_fadeout_client(c); @@ -5745,8 +5745,8 @@ void activatex11(struct wl_listener *listener, void *data) { if (c && c->swallowing) return; - if (c->isminied) { - c->isminied = 0; + if (c->isminimized) { + c->isminimized = 0; c->tags = c->mini_restore_tag; c->is_scratchpad_show = 0; c->is_in_scratchpad = 0; From 113e73fe4acc721c95f7f2a8dc68d75262ec258b Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sat, 29 Nov 2025 22:46:47 +0800 Subject: [PATCH 355/591] opt: avoid toggle overview when setfullscreen and setmaximziescreen --- src/mango.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/src/mango.c b/src/mango.c index 5c804a0a..70b22187 100644 --- a/src/mango.c +++ b/src/mango.c @@ -102,10 +102,10 @@ A->geom.x + A->geom.width <= A->mon->m.x + A->mon->m.width && \ A->geom.y + A->geom.height <= A->mon->m.y + A->mon->m.height) #define ISTILED(A) \ - (A && !(A)->isfloating && !(A)->isminimized && !(A)->iskilling && \ + (A && !(A)->isfloating && !(A)->isminimized && !(A)->iskilling && \ !(A)->ismaximizescreen && !(A)->isfullscreen && !(A)->isunglobal) #define ISSCROLLTILED(A) \ - (A && !(A)->isfloating && !(A)->isminimized && !(A)->iskilling && \ + (A && !(A)->isfloating && !(A)->isminimized && !(A)->iskilling && \ !(A)->isunglobal) #define VISIBLEON(C, M) \ ((C) && (M) && (C)->mon == (M) && ((C)->tags & (M)->tagset[(M)->seltags])) @@ -4559,6 +4559,9 @@ void setmaximizescreen(Client *c, int maximizescreen) { if (!c || !c->mon || !client_surface(c)->mapped || c->iskilling) return; + if (c->mon->isoverview) + return; + c->ismaximizescreen = maximizescreen; if (maximizescreen) { @@ -4568,10 +4571,6 @@ void setmaximizescreen(Client *c, int maximizescreen) { if (c->isfloating) c->float_geom = c->geom; - if (selmon->isoverview) { - Arg arg = {0}; - toggleoverview(&arg); - } maximizescreen_box.x = c->mon->w.x + gappoh; maximizescreen_box.y = c->mon->w.y + gappov; @@ -4615,11 +4614,15 @@ void setfakefullscreen(Client *c, int fakefullscreen) { void setfullscreen(Client *c, int fullscreen) // 用自定义全屏代理自带全屏 { - c->isfullscreen = fullscreen; if (!c || !c->mon || !client_surface(c)->mapped || c->iskilling) return; + if (c->mon->isoverview) + return; + + c->isfullscreen = fullscreen; + client_set_fullscreen(c, fullscreen); if (fullscreen) { @@ -4628,10 +4631,6 @@ void setfullscreen(Client *c, int fullscreen) // 用自定义全屏代理自带 if (c->isfloating) c->float_geom = c->geom; - if (selmon->isoverview) { - Arg arg = {0}; - toggleoverview(&arg); - } c->bw = 0; wlr_scene_node_raise_to_top(&c->scene->node); // 将视图提升到顶层 From 992822e309a814c003d3dc62bf1b56da2ee8765c Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sun, 30 Nov 2025 10:52:02 +0800 Subject: [PATCH 356/591] opt: not handle virtual group keyborad ov_tab_mode detect --- src/mango.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mango.c b/src/mango.c index 70b22187..c80eed1d 100644 --- a/src/mango.c +++ b/src/mango.c @@ -3493,7 +3493,7 @@ void keypress(struct wl_listener *listener, void *data) { wlr_idle_notifier_v1_notify_activity(idle_notifier, seat); // ov tab mode detect moe key release - if (ov_tab_mode && !locked && + if (ov_tab_mode && !locked && group == kb_group && event->state == WL_KEYBOARD_KEY_STATE_RELEASED && (keycode == 133 || keycode == 37 || keycode == 64 || keycode == 50 || keycode == 134 || keycode == 105 || keycode == 108 || keycode == 62) && From 1b7e998b678ef040adb384a308772da5d3dee3f7 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sun, 30 Nov 2025 11:57:34 +0800 Subject: [PATCH 357/591] opt: optimize scroller layout center client judge --- src/fetch/client.h | 5 +++-- src/layout/horizontal.h | 2 +- src/layout/vertical.h | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/fetch/client.h b/src/fetch/client.h index c2b0abdd..a9cfed07 100644 --- a/src/fetch/client.h +++ b/src/fetch/client.h @@ -128,8 +128,9 @@ Client *center_tiled_select(Monitor *m) { int dirx, diry; long int distance; wl_list_for_each(c, &clients, link) { - if (c && VISIBLEON(c, m) && ISTILED(c) && client_surface(c)->mapped && - !c->isfloating && !client_is_unmanaged(c)) { + if (c && VISIBLEON(c, m) && ISSCROLLTILED(c) && + client_surface(c)->mapped && !c->isfloating && + !client_is_unmanaged(c)) { dirx = c->geom.x + c->geom.width / 2 - (m->w.x + m->w.width / 2); diry = c->geom.y + c->geom.height / 2 - (m->w.y + m->w.height / 2); distance = dirx * dirx + diry * diry; diff --git a/src/layout/horizontal.h b/src/layout/horizontal.h index 2385c848..3471fdf7 100644 --- a/src/layout/horizontal.h +++ b/src/layout/horizontal.h @@ -284,7 +284,7 @@ void scroller(Monitor *m) { return; } - if (m->sel && !client_is_unmanaged(m->sel) && !m->sel->isfloating) { + if (m->sel && !client_is_unmanaged(m->sel) && ISSCROLLTILED(m->sel)) { root_client = m->sel; } else if (m->prevsel && ISSCROLLTILED(m->prevsel) && VISIBLEON(m->prevsel, m) && !client_is_unmanaged(m->prevsel)) { diff --git a/src/layout/vertical.h b/src/layout/vertical.h index 7eb95291..f6aa6b86 100644 --- a/src/layout/vertical.h +++ b/src/layout/vertical.h @@ -246,7 +246,7 @@ void vertical_scroller(Monitor *m) { return; } - if (m->sel && !client_is_unmanaged(m->sel) && !m->sel->isfloating) { + if (m->sel && !client_is_unmanaged(m->sel) && ISSCROLLTILED(m->sel)) { root_client = m->sel; } else if (m->prevsel && ISSCROLLTILED(m->prevsel) && VISIBLEON(m->prevsel, m) && !client_is_unmanaged(m->prevsel)) { From e0c80af6b17f8a875de9fdf97bcb736447287843 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Mon, 1 Dec 2025 11:23:18 +0800 Subject: [PATCH 358/591] update readme --- README.md | 8 -------- 1 file changed, 8 deletions(-) diff --git a/README.md b/README.md index b321be5b..5701178b 100644 --- a/README.md +++ b/README.md @@ -248,14 +248,6 @@ Here's an example of using the modules in a flake: } ``` - -# Sponsor - -My current device is a bit outdated and doesn't support certain features like HDR or VRR. If you'd like to support this project, here's how you can help. Thanks! - -![Screenshot_2025-10-13-20-06-49-26_ee1cec40dcf6eb3](https://github.com/user-attachments/assets/240a0727-9eb5-4212-a84c-10fa9f093147) - - # Packaging mango To package mango for other distributions, you can check the reference setup for: From 075d4979b6750e46b034573a662f1846c37faedb Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Tue, 2 Dec 2025 16:19:31 +0800 Subject: [PATCH 359/591] opt: use signal to handle printstauts --- src/mango.c | 56 ++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 43 insertions(+), 13 deletions(-) diff --git a/src/mango.c b/src/mango.c index c80eed1d..62656dbc 100644 --- a/src/mango.c +++ b/src/mango.c @@ -204,6 +204,9 @@ typedef struct { unsigned int ui; unsigned int ui2; } Arg; +struct mango_print_status_manager { + struct wl_signal print_status; +}; typedef struct { unsigned int mod; @@ -515,6 +518,7 @@ static void arrangelayer(Monitor *m, struct wl_list *list, struct wlr_box *usable_area, int exclusive); static void arrangelayers(Monitor *m); static char *get_autostart_path(char *, unsigned int); // 自启动命令执行 +static void handle_print_status(struct wl_listener *listener, void *data); static void axisnotify(struct wl_listener *listener, void *data); // 滚轮事件处理 static void buttonpress(struct wl_listener *listener, @@ -777,6 +781,7 @@ static struct wlr_virtual_pointer_manager_v1 *virtual_pointer_mgr; static struct wlr_output_power_manager_v1 *power_mgr; static struct wlr_pointer_gestures_v1 *pointer_gestures; static struct wlr_drm_lease_v1_manager *drm_lease_manager; +struct mango_print_status_manager *print_status_manager; static struct wlr_cursor *cursor; static struct wlr_xcursor_manager *cursor_mgr; @@ -852,6 +857,8 @@ struct Pertag { *ltidxs[LENGTH(tags) + 1]; /* matrix of tags and layouts indexes */ }; +static struct wl_listener print_status_listener = {.notify = + handle_print_status}; static struct wl_listener cursor_axis = {.notify = axisnotify}; static struct wl_listener cursor_button = {.notify = buttonpress}; static struct wl_listener cursor_frame = {.notify = cursorframe}; @@ -2004,6 +2011,7 @@ void setcursorshape(struct wl_listener *listener, void *data) { } void cleanuplisteners(void) { + wl_list_remove(&print_status_listener.link); wl_list_remove(&cursor_axis.link); wl_list_remove(&cursor_button.link); wl_list_remove(&cursor_frame.link); @@ -4135,19 +4143,8 @@ void pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy, wlr_seat_pointer_notify_motion(seat, time, sx, sy); } -void // 17 -printstatus(void) { - Monitor *m = NULL; - wl_list_for_each(m, &mons, link) { - if (!m->wlr_output->enabled) { - continue; - } - // Update workspace active states - dwl_ext_workspace_printstatus(m); - - // Update IPC output status - dwl_ipc_output_printstatus(m); - } +void printstatus(void) { + wl_signal_emit(&print_status_manager->print_status, NULL); } void powermgrsetmode(struct wl_listener *listener, void *data) { @@ -4871,6 +4868,35 @@ void create_output(struct wlr_backend *backend, void *data) { #endif } +// 创建函数 +struct mango_print_status_manager *mango_print_status_manager_create() { + struct mango_print_status_manager *manager = calloc(1, sizeof(*manager)); + if (!manager) + return NULL; + + // 初始化 print_status 信号,不是 event_signal + wl_signal_init(&manager->print_status); + + return manager; +} + +void handle_print_status(struct wl_listener *listener, void *data) { + struct mango_print_status_manager *manager = + wl_container_of(listener, manager, print_status); + // struct wlr_print_status *status = data; + Monitor *m = NULL; + wl_list_for_each(m, &mons, link) { + if (!m->wlr_output->enabled) { + continue; + } + // Update workspace active states + dwl_ext_workspace_printstatus(m); + + // Update IPC output status + dwl_ipc_output_printstatus(m); + } +} + void setup(void) { setenv("XCURSOR_SIZE", "24", 1); @@ -4966,6 +4992,10 @@ void setup(void) { wlr_alpha_modifier_v1_create(dpy); wlr_ext_data_control_manager_v1_create(dpy, 1); + // 在 setup 函数中 + print_status_manager = mango_print_status_manager_create(); + wl_signal_add(&print_status_manager->print_status, &print_status_listener); + /* Initializes the interface used to implement urgency hints */ activation = wlr_xdg_activation_v1_create(dpy); wl_signal_add(&activation->events.request_activate, &request_activate); From 9196e2a50be7c1de84da08ef50fba8c440f1c6b2 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Tue, 2 Dec 2025 16:46:11 +0800 Subject: [PATCH 360/591] opt: use event mask to decide whether print ipc message --- src/config/parse_config.h | 2 +- src/dispatch/bind_define.h | 16 +-- src/ext-protocol/dwl-ipc.h | 208 +++++++++++++++++++++++++------------ src/mango.c | 75 +++++++++---- 4 files changed, 205 insertions(+), 96 deletions(-) diff --git a/src/config/parse_config.h b/src/config/parse_config.h index 7196270d..afc9acb8 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -3255,6 +3255,6 @@ void reset_option(void) { int reload_config(const Arg *arg) { parse_config(); reset_option(); - printstatus(); + printstatus(PRINT_ALL); return 0; } diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index a1418300..a782d4f1 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -503,7 +503,7 @@ int setlayout(const Arg *arg) { selmon->pertag->ltidxs[selmon->pertag->curtag] = &layouts[jk]; clear_fullscreen_and_maximized_state(selmon); arrange(selmon, false); - printstatus(); + printstatus(PRINT_ALL); return 0; } } @@ -517,7 +517,7 @@ int setkeymode(const Arg *arg) { } else { keymode.isdefault = false; } - printstatus(); + printstatus(PRINT_KEYMODE); return 1; } @@ -866,7 +866,7 @@ int switch_keyboard_layout(const Arg *arg) { wlr_seat_keyboard_notify_modifiers(seat, &tkb->modifiers); } - printstatus(); + printstatus(PRINT_KB_LAYOUT); return 0; } @@ -907,7 +907,7 @@ int switch_layout(const Arg *arg) { } clear_fullscreen_and_maximized_state(selmon); arrange(selmon, false); - printstatus(); + printstatus(PRINT_ALL); return 0; } @@ -918,7 +918,7 @@ int switch_layout(const Arg *arg) { jk == LENGTH(layouts) - 1 ? &layouts[0] : &layouts[jk + 1]; clear_fullscreen_and_maximized_state(selmon); arrange(selmon, false); - printstatus(); + printstatus(PRINT_ALL); return 0; } } @@ -1260,7 +1260,7 @@ int toggletag(const Arg *arg) { focusclient(focustop(selmon), 1); arrange(selmon, false); } - printstatus(); + printstatus(PRINT_ALL); return 0; } @@ -1278,7 +1278,7 @@ int toggleview(const Arg *arg) { focusclient(focustop(selmon), 1); arrange(selmon, false); } - printstatus(); + printstatus(PRINT_ALL); return 0; } @@ -1398,7 +1398,7 @@ int comboview(const Arg *arg) { view(&(Arg){.ui = newtags}, false); } - printstatus(); + printstatus(PRINT_ALL); return 0; } diff --git a/src/ext-protocol/dwl-ipc.h b/src/ext-protocol/dwl-ipc.h index 15b2376a..1d861b91 100644 --- a/src/ext-protocol/dwl-ipc.h +++ b/src/ext-protocol/dwl-ipc.h @@ -10,8 +10,9 @@ static void dwl_ipc_manager_get_output(struct wl_client *client, 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_printstatus(Monitor *monitor, uint32_t event_mask); +static void dwl_ipc_output_printstatus_to(DwlIpcOutput *ipc_output, + uint32_t event_mask); static void dwl_ipc_output_set_client_tags(struct wl_client *client, struct wl_resource *resource, unsigned int and_tags, @@ -87,7 +88,7 @@ void dwl_ipc_manager_get_output(struct wl_client *client, 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); + dwl_ipc_output_printstatus_to(ipc_output, PRINT_ALL); } void dwl_ipc_manager_release(struct wl_client *client, @@ -101,13 +102,16 @@ static void dwl_ipc_output_destroy(struct wl_resource *resource) { free(ipc_output); } -void dwl_ipc_output_printstatus(Monitor *monitor) { +// 修改IPC输出函数,接受掩码参数 +void dwl_ipc_output_printstatus(Monitor *monitor, uint32_t event_mask) { DwlIpcOutput *ipc_output; wl_list_for_each(ipc_output, &monitor->dwl_ipc_outputs, link) - dwl_ipc_output_printstatus_to(ipc_output); + dwl_ipc_output_printstatus_to(ipc_output, event_mask); } -void dwl_ipc_output_printstatus_to(DwlIpcOutput *ipc_output) { +// 修改主IPC输出函数,根据掩码发送相应事件 +void dwl_ipc_output_printstatus_to(DwlIpcOutput *ipc_output, + uint32_t event_mask) { Monitor *monitor = ipc_output->mon; Client *c = NULL, *focused = NULL; struct wlr_keyboard *keyboard; @@ -115,103 +119,175 @@ void dwl_ipc_output_printstatus_to(DwlIpcOutput *ipc_output) { int 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++; + // 只在需要时才获取这些数据 + if (event_mask & (PRINT_ACTIVE | PRINT_TAG | PRINT_TITLE | PRINT_APPID | + PRINT_FULLSCREEN | PRINT_FLOATING | PRINT_X | PRINT_Y | + PRINT_WIDTH | PRINT_HEIGHT)) { + focused = focustop(monitor); + } + + // 发送活动状态 + if (event_mask & PRINT_ACTIVE) { + zdwl_ipc_output_v2_send_active(ipc_output->resource, monitor == selmon); + } + + // 发送标签状态 + if (event_mask & PRINT_TAG) { + 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; + + if (focused) { + 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); } - 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; + // 只在需要时才获取标题和应用ID + if (event_mask & (PRINT_TITLE | PRINT_APPID)) { + title = focused ? client_get_title(focused) : ""; + appid = focused ? client_get_appid(focused) : ""; } - 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)); + // 获取布局符号 + if (event_mask & PRINT_LAYOUT_SYMBOL) { + if (monitor->isoverview) { + symbol = overviewlayout.symbol; + } else { + symbol = monitor->pertag->ltidxs[monitor->pertag->curtag]->symbol; + } + } - 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) { + // 发送布局索引 + if (event_mask & PRINT_LAYOUT) { + zdwl_ipc_output_v2_send_layout( + ipc_output->resource, + monitor->pertag->ltidxs[monitor->pertag->curtag] - layouts); + } + + // 发送标题 + if (event_mask & PRINT_TITLE) { + zdwl_ipc_output_v2_send_title(ipc_output->resource, + title ? title : broken); + } + + // 发送应用ID + if (event_mask & PRINT_APPID) { + zdwl_ipc_output_v2_send_appid(ipc_output->resource, + appid ? appid : broken); + } + + // 发送布局符号 + if (event_mask & PRINT_LAYOUT_SYMBOL) { + zdwl_ipc_output_v2_send_layout_symbol(ipc_output->resource, symbol); + } + + // 发送全屏状态 + if ((event_mask & PRINT_FULLSCREEN) && + 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) { + + // 发送浮动状态 + if ((event_mask & PRINT_FLOATING) && + 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) { + + // 发送X坐标 + if ((event_mask & PRINT_X) && + 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) { + + // 发送Y坐标 + if ((event_mask & PRINT_Y) && + 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) { + + // 发送宽度 + if ((event_mask & PRINT_WIDTH) && + 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) { + + // 发送高度 + if ((event_mask & PRINT_HEIGHT) && + 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) { + + // 发送最后图层 + if ((event_mask & PRINT_LAST_LAYER) && + 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_surface_ws_name); } - if (wl_resource_get_version(ipc_output->resource) >= - ZDWL_IPC_OUTPUT_V2_KB_LAYOUT_SINCE_VERSION) { + // 获取键盘布局(只在需要时) + if (event_mask & PRINT_KB_LAYOUT) { + 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)); + } + + // 发送键盘布局 + if ((event_mask & PRINT_KB_LAYOUT) && + 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) { + // 发送键模式 + if ((event_mask & PRINT_KEYMODE) && + 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) { + // 发送缩放因子 + if ((event_mask & PRINT_SCALEFACTOR) && + 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); + // 发送帧结束标记 + if (event_mask & PRINT_FRAME) { + zdwl_ipc_output_v2_send_frame(ipc_output->resource); + } } void dwl_ipc_output_set_client_tags(struct wl_client *client, @@ -240,7 +316,7 @@ void dwl_ipc_output_set_client_tags(struct wl_client *client, if (selmon == monitor) focusclient(focustop(monitor), 1); arrange(selmon, false); - printstatus(); + printstatus(PRINT_ALL); } void dwl_ipc_output_set_layout(struct wl_client *client, @@ -260,7 +336,7 @@ void dwl_ipc_output_set_layout(struct wl_client *client, monitor->pertag->ltidxs[monitor->pertag->curtag] = &layouts[index]; clear_fullscreen_and_maximized_state(monitor); arrange(monitor, false); - printstatus(); + printstatus(PRINT_ALL); } void dwl_ipc_output_set_tags(struct wl_client *client, diff --git a/src/mango.c b/src/mango.c index 62656dbc..1a1ea665 100644 --- a/src/mango.c +++ b/src/mango.c @@ -181,6 +181,28 @@ enum seat_config_shortcuts_inhibit { SHORTCUTS_INHIBIT_ENABLE, }; +// 事件掩码枚举 +enum print_event_type { + PRINT_ACTIVE = 1 << 0, + PRINT_TAG = 1 << 1, + PRINT_LAYOUT = 1 << 2, + PRINT_TITLE = 1 << 3, + PRINT_APPID = 1 << 4, + PRINT_LAYOUT_SYMBOL = 1 << 5, + PRINT_FULLSCREEN = 1 << 6, + PRINT_FLOATING = 1 << 7, + PRINT_X = 1 << 8, + PRINT_Y = 1 << 9, + PRINT_WIDTH = 1 << 10, + PRINT_HEIGHT = 1 << 11, + PRINT_LAST_LAYER = 1 << 12, + PRINT_KB_LAYOUT = 1 << 13, + PRINT_KEYMODE = 1 << 14, + PRINT_SCALEFACTOR = 1 << 15, + PRINT_FRAME = 1 << 16, + PRINT_ALL = (1 << 17) - 1 // 所有位都设为1 +}; + typedef struct Pertag Pertag; typedef struct Monitor Monitor; typedef struct Client Client; @@ -612,7 +634,7 @@ static void outputmgrapplyortest(struct wlr_output_configuration_v1 *config, static void outputmgrtest(struct wl_listener *listener, void *data); static void pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy, unsigned int time); -static void printstatus(void); +static void printstatus(unsigned int event_mask); static void quitsignal(int signo); static void powermgrsetmode(struct wl_listener *listener, void *data); static void rendermon(struct wl_listener *listener, void *data); @@ -2148,7 +2170,7 @@ void closemon(Monitor *m) { } if (selmon) { focusclient(focustop(selmon), 1); - printstatus(); + printstatus(PRINT_ALL); } } @@ -2782,7 +2804,7 @@ void createmon(struct wl_listener *listener, void *data) { add_workspace_by_tag(i, m); } - printstatus(); + printstatus(PRINT_ALL); } void // fix for 0.5 @@ -3238,7 +3260,7 @@ void focusclient(Client *c, int lift) { client_activate_surface(old_keyboard_focus_surface, 0); } } - printstatus(); + printstatus(PRINT_ALL); if (!c) { @@ -3788,7 +3810,7 @@ mapnotify(struct wl_listener *listener, void *data) { // make sure the animation is open type c->is_pending_open_animation = true; resize(c, c->geom, 0); - printstatus(); + printstatus(PRINT_ALL); } void maximizenotify(struct wl_listener *listener, void *data) { @@ -4143,8 +4165,10 @@ void pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy, wlr_seat_pointer_notify_motion(seat, time, sx, sy); } -void printstatus(void) { - wl_signal_emit(&print_status_manager->print_status, NULL); +// 修改printstatus函数,接受掩码参数 +void printstatus(unsigned int event_mask) { + wl_signal_emit(&print_status_manager->print_status, + (void *)(uintptr_t)event_mask); } void powermgrsetmode(struct wl_listener *listener, void *data) { @@ -4405,7 +4429,7 @@ run(char *startup_cmd) { if (fd_set_nonblock(STDOUT_FILENO) < 0) close(STDOUT_FILENO); - printstatus(); + printstatus(PRINT_ALL); /* At this point the outputs are initialized, choose initial selmon * based on cursor position, and set default cursor image */ @@ -4540,7 +4564,7 @@ setfloating(Client *c, int floating) { arrange(c->mon, false); setborder_color(c); - printstatus(); + printstatus(PRINT_ALL); } void reset_maximizescreen_size(Client *c) { @@ -4880,20 +4904,29 @@ struct mango_print_status_manager *mango_print_status_manager_create() { return manager; } +// 修改信号处理函数,接收掩码参数 void handle_print_status(struct wl_listener *listener, void *data) { struct mango_print_status_manager *manager = wl_container_of(listener, manager, print_status); - // struct wlr_print_status *status = data; + + uint32_t event_mask = (uintptr_t)data; + // 如果传入的是NULL(旧代码)或0,使用默认的所有事件 + if (!event_mask) { + event_mask = PRINT_ALL; + } + Monitor *m = NULL; wl_list_for_each(m, &mons, link) { if (!m->wlr_output->enabled) { continue; } - // Update workspace active states - dwl_ext_workspace_printstatus(m); + // 更新workspace状态(根据掩码决定是否更新) + if (event_mask & PRINT_TAG || event_mask & PRINT_ACTIVE) { + dwl_ext_workspace_printstatus(m); + } - // Update IPC output status - dwl_ipc_output_printstatus(m); + // 更新IPC输出状态(传入掩码) + dwl_ipc_output_printstatus(m, event_mask); } } @@ -5230,7 +5263,7 @@ void tag_client(const Arg *arg, Client *target_client) { } focusclient(target_client, 1); - printstatus(); + printstatus(PRINT_ALL); } void overview(Monitor *m) { grid(m); } @@ -5438,7 +5471,7 @@ void unmapnotify(struct wl_listener *listener, void *data) { } wlr_scene_node_destroy(&c->scene->node); - printstatus(); + printstatus(PRINT_ALL); motionnotify(0, NULL, 0, 0, 0, 0); } @@ -5586,7 +5619,7 @@ void updatetitle(struct wl_listener *listener, void *data) { if (title && c->foreign_toplevel) wlr_foreign_toplevel_handle_v1_set_title(c->foreign_toplevel, title); if (c == focustop(c->mon)) - printstatus(); + printstatus(PRINT_TITLE); } void // 17 fix to 0.5 @@ -5606,7 +5639,7 @@ urgent(struct wl_listener *listener, void *data) { c->isurgent = 1; if (client_surface(c)->mapped) setborder_color(c); - printstatus(); + printstatus(PRINT_ALL); } } @@ -5661,7 +5694,7 @@ toggleseltags: if (changefocus) focusclient(focustop(m), 1); arrange(m, want_animation); - printstatus(); + printstatus(PRINT_ALL); } void view(const Arg *arg, bool want_animation) { @@ -5804,7 +5837,7 @@ void activatex11(struct wl_listener *listener, void *data) { arrange(c->mon, false); } - printstatus(); + printstatus(PRINT_ALL); } void configurex11(struct wl_listener *listener, void *data) { @@ -5876,7 +5909,7 @@ void sethints(struct wl_listener *listener, void *data) { return; c->isurgent = xcb_icccm_wm_hints_get_urgency(c->surface.xwayland->hints); - printstatus(); + printstatus(PRINT_ALL); if (c->isurgent && surface && surface->mapped) setborder_color(c); From b9952f03b53da2e7a64dd966404fd0b431dde1de Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Tue, 2 Dec 2025 16:57:24 +0800 Subject: [PATCH 361/591] opt: change unsigned int to uint32_t --- mmsg/mmsg.c | 4 +- src/animation/client.h | 40 ++++--- src/animation/common.h | 16 +-- src/animation/layer.h | 38 +++---- src/client/client.h | 16 +-- src/common/util.c | 7 +- src/common/util.h | 4 +- src/config/parse_config.h | 66 ++++++------ src/config/preset.h | 48 ++++----- src/dispatch/bind_define.h | 46 ++++---- src/ext-protocol/dwl-ipc.h | 34 +++--- src/ext-protocol/ext-workspace.h | 12 +-- src/ext-protocol/foreign-toplevel.h | 2 +- src/fetch/client.h | 2 +- src/fetch/common.h | 12 +-- src/fetch/monitor.h | 12 +-- src/layout/arrange.h | 12 +-- src/layout/horizontal.h | 71 ++++++------- src/layout/vertical.h | 42 ++++---- src/mango.c | 159 ++++++++++++++-------------- 20 files changed, 314 insertions(+), 329 deletions(-) diff --git a/mmsg/mmsg.c b/mmsg/mmsg.c index 6f350ed0..2bbe870e 100644 --- a/mmsg/mmsg.c +++ b/mmsg/mmsg.c @@ -86,7 +86,7 @@ static void noop_description(void *data, struct wl_output *wl_output, const char *description) {} // 将 n 转换为 9 位二进制字符串,结果存入 buf(至少长度 10) -void bin_str_9bits(char *buf, unsigned int n) { +void bin_str_9bits(char *buf, uint32_t n) { for (int i = 8; i >= 0; i--) { *buf++ = ((n >> i) & 1) ? '1' : '0'; } @@ -268,7 +268,7 @@ static void dwl_ipc_output_kb_layout(void *data, static void dwl_ipc_output_scalefactor(void *data, struct zdwl_ipc_output_v2 *dwl_ipc_output, - const unsigned int scalefactor) { + const uint32_t scalefactor) { if (!Aflag) return; char *output_name = data; diff --git a/src/animation/client.h b/src/animation/client.h index d26265bb..67f4c10f 100644 --- a/src/animation/client.h +++ b/src/animation/client.h @@ -1,4 +1,4 @@ -void client_actual_size(Client *c, unsigned int *width, unsigned int *height) { +void client_actual_size(Client *c, uint32_t *width, uint32_t *height) { *width = c->animation.current.width - c->bw; *height = c->animation.current.height - c->bw; @@ -183,8 +183,8 @@ void scene_buffer_apply_effect(struct wlr_scene_buffer *buffer, int sx, int sy, if (buffer_data->should_scale) { - unsigned int surface_width = surface->current.width; - unsigned int surface_height = surface->current.height; + uint32_t surface_width = surface->current.width; + uint32_t surface_height = surface->current.height; surface_width = buffer_data->width_scale < 1 ? surface_width @@ -270,7 +270,7 @@ void client_draw_shadow(Client *c) { ? CORNER_LOCATION_NONE : CORNER_LOCATION_ALL; - unsigned int bwoffset = c->bw != 0 && hit_no_border ? c->bw : 0; + uint32_t bwoffset = c->bw != 0 && hit_no_border ? c->bw : 0; uint32_t width, height; client_actual_size(c, &width, &height); @@ -546,7 +546,7 @@ void client_apply_clip(Client *c, float factor) { } // 获取窗口动画实时位置矩形 - unsigned int width, height; + uint32_t width, height; client_actual_size(c, &width, &height); // 计算出除了边框的窗口实际剪切大小 @@ -630,17 +630,16 @@ void fadeout_client_animation_next_tick(Client *c) { int type = c->animation.action = c->animation.action; double factor = find_animation_curve_at(animation_passed, type); - unsigned int width = - c->animation.initial.width + - (c->current.width - c->animation.initial.width) * factor; - unsigned int height = + uint32_t width = c->animation.initial.width + + (c->current.width - c->animation.initial.width) * factor; + uint32_t height = c->animation.initial.height + (c->current.height - c->animation.initial.height) * factor; - unsigned int x = c->animation.initial.x + - (c->current.x - c->animation.initial.x) * factor; - unsigned int y = c->animation.initial.y + - (c->current.y - c->animation.initial.y) * factor; + uint32_t x = c->animation.initial.x + + (c->current.x - c->animation.initial.x) * factor; + uint32_t y = c->animation.initial.y + + (c->current.y - c->animation.initial.y) * factor; wlr_scene_node_set_position(&c->scene->node, x, y); @@ -696,17 +695,16 @@ void client_animation_next_tick(Client *c) { double sx = 0, sy = 0; struct wlr_surface *surface = NULL; - unsigned int width = - c->animation.initial.width + - (c->current.width - c->animation.initial.width) * factor; - unsigned int height = + uint32_t width = c->animation.initial.width + + (c->current.width - c->animation.initial.width) * factor; + uint32_t height = c->animation.initial.height + (c->current.height - c->animation.initial.height) * factor; - unsigned int x = c->animation.initial.x + - (c->current.x - c->animation.initial.x) * factor; - unsigned int y = c->animation.initial.y + - (c->current.y - c->animation.initial.y) * factor; + uint32_t x = c->animation.initial.x + + (c->current.x - c->animation.initial.x) * factor; + uint32_t y = c->animation.initial.y + + (c->current.y - c->animation.initial.y) * factor; wlr_scene_node_set_position(&c->scene->node, x, y); c->animation.current = (struct wlr_box){ diff --git a/src/animation/common.h b/src/animation/common.h index 06ffe1ab..2ff6744a 100644 --- a/src/animation/common.h +++ b/src/animation/common.h @@ -33,33 +33,33 @@ void init_baked_points(void) { baked_points_focus = calloc(BAKED_POINTS_COUNT, sizeof(*baked_points_focus)); - for (unsigned int i = 0; i < BAKED_POINTS_COUNT; i++) { + for (uint32_t i = 0; i < BAKED_POINTS_COUNT; i++) { baked_points_move[i] = calculate_animation_curve_at( (double)i / (BAKED_POINTS_COUNT - 1), MOVE); } - for (unsigned int i = 0; i < BAKED_POINTS_COUNT; i++) { + for (uint32_t i = 0; i < BAKED_POINTS_COUNT; i++) { baked_points_open[i] = calculate_animation_curve_at( (double)i / (BAKED_POINTS_COUNT - 1), OPEN); } - for (unsigned int i = 0; i < BAKED_POINTS_COUNT; i++) { + for (uint32_t i = 0; i < BAKED_POINTS_COUNT; i++) { baked_points_tag[i] = calculate_animation_curve_at( (double)i / (BAKED_POINTS_COUNT - 1), TAG); } - for (unsigned int i = 0; i < BAKED_POINTS_COUNT; i++) { + for (uint32_t i = 0; i < BAKED_POINTS_COUNT; i++) { baked_points_close[i] = calculate_animation_curve_at( (double)i / (BAKED_POINTS_COUNT - 1), CLOSE); } - for (unsigned int i = 0; i < BAKED_POINTS_COUNT; i++) { + for (uint32_t i = 0; i < BAKED_POINTS_COUNT; i++) { baked_points_focus[i] = calculate_animation_curve_at( (double)i / (BAKED_POINTS_COUNT - 1), FOCUS); } } double find_animation_curve_at(double t, int type) { - unsigned int down = 0; - unsigned int up = BAKED_POINTS_COUNT - 1; + uint32_t down = 0; + uint32_t up = BAKED_POINTS_COUNT - 1; - unsigned int middle = (up + down) / 2; + uint32_t middle = (up + down) / 2; struct dvec2 *baked_points; if (type == MOVE) { baked_points = baked_points_move; diff --git a/src/animation/layer.h b/src/animation/layer.h index 48ceb211..e36ddd10 100644 --- a/src/animation/layer.h +++ b/src/animation/layer.h @@ -1,5 +1,4 @@ -void layer_actual_size(LayerSurface *l, unsigned int *width, - unsigned int *height) { +void layer_actual_size(LayerSurface *l, uint32_t *width, uint32_t *height) { struct wlr_box box; if (l->animation.running) { @@ -213,9 +212,8 @@ void layer_scene_buffer_apply_effect(struct wlr_scene_buffer *buffer, int sx, struct wlr_surface *surface = scene_surface->surface; - unsigned int surface_width = - surface->current.width * buffer_data->width_scale; - unsigned int surface_height = + uint32_t surface_width = surface->current.width * buffer_data->width_scale; + uint32_t surface_height = surface->current.height * buffer_data->height_scale; if (surface_height > 0 && surface_width > 0) { @@ -245,17 +243,16 @@ void fadeout_layer_animation_next_tick(LayerSurface *l) { int type = l->animation.action = l->animation.action; double factor = find_animation_curve_at(animation_passed, type); - unsigned int width = - l->animation.initial.width + - (l->current.width - l->animation.initial.width) * factor; - unsigned int height = + uint32_t width = l->animation.initial.width + + (l->current.width - l->animation.initial.width) * factor; + uint32_t height = l->animation.initial.height + (l->current.height - l->animation.initial.height) * factor; - unsigned int x = l->animation.initial.x + - (l->current.x - l->animation.initial.x) * factor; - unsigned int y = l->animation.initial.y + - (l->current.y - l->animation.initial.y) * factor; + uint32_t x = l->animation.initial.x + + (l->current.x - l->animation.initial.x) * factor; + uint32_t y = l->animation.initial.y + + (l->current.y - l->animation.initial.y) * factor; wlr_scene_node_set_position(&l->scene->node, x, y); @@ -310,17 +307,16 @@ void layer_animation_next_tick(LayerSurface *l) { int type = l->animation.action == NONE ? MOVE : l->animation.action; double factor = find_animation_curve_at(animation_passed, type); - unsigned int width = - l->animation.initial.width + - (l->current.width - l->animation.initial.width) * factor; - unsigned int height = + uint32_t width = l->animation.initial.width + + (l->current.width - l->animation.initial.width) * factor; + uint32_t height = l->animation.initial.height + (l->current.height - l->animation.initial.height) * factor; - unsigned int x = l->animation.initial.x + - (l->current.x - l->animation.initial.x) * factor; - unsigned int y = l->animation.initial.y + - (l->current.y - l->animation.initial.y) * factor; + uint32_t x = l->animation.initial.x + + (l->current.x - l->animation.initial.x) * factor; + uint32_t y = l->animation.initial.y + + (l->current.y - l->animation.initial.y) * factor; double opacity = MIN(fadein_begin_opacity + animation_passed * (1.0 - fadein_begin_opacity), diff --git a/src/client/client.h b/src/client/client.h index 06f629de..10ecfdf7 100644 --- a/src/client/client.h +++ b/src/client/client.h @@ -526,16 +526,16 @@ static inline void client_set_size_bound(Client *c) { if (!size_hints) return; - if ((unsigned int)c->geom.width - 2 * c->bw < size_hints->min_width && + if ((uint32_t)c->geom.width - 2 * c->bw < size_hints->min_width && size_hints->min_width > 0) c->geom.width = size_hints->min_width + 2 * c->bw; - if ((unsigned int)c->geom.height - 2 * c->bw < size_hints->min_height && + if ((uint32_t)c->geom.height - 2 * c->bw < size_hints->min_height && size_hints->min_height > 0) c->geom.height = size_hints->min_height + 2 * c->bw; - if ((unsigned int)c->geom.width - 2 * c->bw > size_hints->max_width && + if ((uint32_t)c->geom.width - 2 * c->bw > size_hints->max_width && size_hints->max_width > 0) c->geom.width = size_hints->max_width + 2 * c->bw; - if ((unsigned int)c->geom.height - 2 * c->bw > size_hints->max_height && + if ((uint32_t)c->geom.height - 2 * c->bw > size_hints->max_height && size_hints->max_height > 0) c->geom.height = size_hints->max_height + 2 * c->bw; return; @@ -544,19 +544,19 @@ static inline void client_set_size_bound(Client *c) { toplevel = c->surface.xdg->toplevel; state = toplevel->current; - if ((unsigned int)c->geom.width - 2 * c->bw < state.min_width && + if ((uint32_t)c->geom.width - 2 * c->bw < state.min_width && state.min_width > 0) { c->geom.width = state.min_width + 2 * c->bw; } - if ((unsigned int)c->geom.height - 2 * c->bw < state.min_height && + if ((uint32_t)c->geom.height - 2 * c->bw < state.min_height && state.min_height > 0) { c->geom.height = state.min_height + 2 * c->bw; } - if ((unsigned int)c->geom.width - 2 * c->bw > state.max_width && + if ((uint32_t)c->geom.width - 2 * c->bw > state.max_width && state.max_width > 0) { c->geom.width = state.max_width + 2 * c->bw; } - if ((unsigned int)c->geom.height - 2 * c->bw > state.max_height && + if ((uint32_t)c->geom.height - 2 * c->bw > state.max_height && state.max_height > 0) { c->geom.height = state.max_height + 2 * c->bw; } diff --git a/src/common/util.c b/src/common/util.c index 6eadbc67..79972054 100644 --- a/src/common/util.c +++ b/src/common/util.c @@ -82,14 +82,13 @@ void wl_list_append(struct wl_list *list, struct wl_list *object) { wl_list_insert(list->prev, object); } -unsigned int get_now_in_ms(void) { +uint32_t get_now_in_ms(void) { struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); return timespec_to_ms(&now); } -unsigned int timespec_to_ms(struct timespec *ts) { - return (unsigned int)ts->tv_sec * 1000 + - (unsigned int)ts->tv_nsec / 1000000; +uint32_t timespec_to_ms(struct timespec *ts) { + return (uint32_t)ts->tv_sec * 1000 + (uint32_t)ts->tv_nsec / 1000000; } diff --git a/src/common/util.h b/src/common/util.h index 3a0f6dae..2718eae8 100644 --- a/src/common/util.h +++ b/src/common/util.h @@ -6,5 +6,5 @@ void *ecalloc(size_t nmemb, size_t size); int fd_set_nonblock(int fd); int regex_match(const char *pattern_mb, const char *str_mb); void wl_list_append(struct wl_list *list, struct wl_list *object); -unsigned int get_now_in_ms(void); -unsigned int timespec_to_ms(struct timespec *ts); \ No newline at end of file +uint32_t get_now_in_ms(void); +uint32_t timespec_to_ms(struct timespec *ts); \ No newline at end of file diff --git a/src/config/parse_config.h b/src/config/parse_config.h index afc9acb8..7c76c5e0 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -52,7 +52,7 @@ typedef struct { typedef struct { const char *id; const char *title; - unsigned int tags; + uint32_t tags; int isfloating; int isfullscreen; float scroller_proportion; @@ -124,29 +124,29 @@ KeyBinding default_key_bindings[] = {CHVT(1), CHVT(2), CHVT(3), CHVT(4), CHVT(9), CHVT(10), CHVT(11), CHVT(12)}; typedef struct { - unsigned int mod; - unsigned int button; + uint32_t mod; + uint32_t button; int (*func)(const Arg *); Arg arg; } MouseBinding; typedef struct { - unsigned int mod; - unsigned int dir; + uint32_t mod; + uint32_t dir; int (*func)(const Arg *); Arg arg; } AxisBinding; typedef struct { - unsigned int fold; + uint32_t fold; int (*func)(const Arg *); Arg arg; } SwitchBinding; typedef struct { - unsigned int mod; - unsigned int motion; - unsigned int fingers_count; + uint32_t mod; + uint32_t motion; + uint32_t fingers_count; int (*func)(const Arg *); Arg arg; } GestureBinding; @@ -210,7 +210,7 @@ typedef struct { int snap_distance; int enable_floating_snap; int drag_tile_to_tile; - unsigned int swipe_min_threshold; + uint32_t swipe_min_threshold; float focused_opacity; float unfocused_opacity; float *scroller_proportion_preset; @@ -219,21 +219,21 @@ typedef struct { char **circle_layout; int circle_layout_count; - unsigned int new_is_master; + uint32_t new_is_master; float default_mfact; - unsigned int default_nmaster; + uint32_t default_nmaster; int center_master_overspread; int center_when_single_stack; - unsigned int hotarea_size; - unsigned int enable_hotarea; - unsigned int ov_tab_mode; + uint32_t hotarea_size; + uint32_t enable_hotarea; + uint32_t ov_tab_mode; int overviewgappi; int overviewgappo; - unsigned int cursor_hide_timeout; + uint32_t cursor_hide_timeout; - unsigned int axis_bind_apply_timeout; - unsigned int focus_on_activate; + uint32_t axis_bind_apply_timeout; + uint32_t focus_on_activate; int inhibit_regardless_of_visibility; int sloppyfocus; int warpcursor; @@ -241,7 +241,7 @@ typedef struct { /* keyboard */ int repeat_rate; int repeat_delay; - unsigned int numlockon; + uint32_t numlockon; /* Trackpad */ int disable_trackpad; @@ -253,13 +253,13 @@ typedef struct { int disable_while_typing; int left_handed; int middle_button_emulation; - unsigned int accel_profile; + uint32_t accel_profile; double accel_speed; - unsigned int scroll_method; - unsigned int scroll_button; - unsigned int click_method; - unsigned int send_events_mode; - unsigned int button_map; + uint32_t scroll_method; + uint32_t scroll_button; + uint32_t click_method; + uint32_t send_events_mode; + uint32_t button_map; int blur; int blur_layer; @@ -269,18 +269,18 @@ typedef struct { int shadows; int shadow_only_floating; int layer_shadows; - unsigned int shadows_size; + uint32_t shadows_size; float shadows_blur; int shadows_position_x; int shadows_position_y; float shadowscolor[4]; int smartgaps; - unsigned int gappih; - unsigned int gappiv; - unsigned int gappoh; - unsigned int gappov; - unsigned int borderpx; + uint32_t gappih; + uint32_t gappiv; + uint32_t gappoh; + uint32_t gappov; + uint32_t borderpx; float scratchpad_width_ratio; float scratchpad_height_ratio; float rootcolor[4]; @@ -331,7 +331,7 @@ typedef struct { int exec_once_count; char *cursor_theme; - unsigned int cursor_size; + uint32_t cursor_size; int single_scratchpad; int xwayland_persistence; @@ -789,7 +789,7 @@ void convert_hex_to_rgba(float *color, unsigned long int hex) { color[3] = (hex & 0xFF) / 255.0f; } -unsigned int parse_num_type(char *str) { +uint32_t parse_num_type(char *str) { switch (str[0]) { case '-': return NUM_TYPE_MINUS; diff --git a/src/config/preset.h b/src/config/preset.h index 4032a757..ed743a83 100644 --- a/src/config/preset.h +++ b/src/config/preset.h @@ -33,27 +33,27 @@ double animation_curve_close[4] = {0.46, 1.0, 0.29, 0.99}; // 动画曲线 double animation_curve_focus[4] = {0.46, 1.0, 0.29, 0.99}; // 动画曲线 /* appearance */ -unsigned int axis_bind_apply_timeout = 100; // 滚轮绑定动作的触发的时间间隔 -unsigned int focus_on_activate = 1; // 收到窗口激活请求是否自动跳转聚焦 -unsigned int new_is_master = 1; // 新窗口是否插在头部 -double default_mfact = 0.55f; // master 窗口比例 -unsigned int default_nmaster = 1; // 默认master数量 -int center_master_overspread = 0; // 中心master时是否铺满 -int center_when_single_stack = 1; // 单个stack时是否居中 +uint32_t axis_bind_apply_timeout = 100; // 滚轮绑定动作的触发的时间间隔 +uint32_t focus_on_activate = 1; // 收到窗口激活请求是否自动跳转聚焦 +uint32_t new_is_master = 1; // 新窗口是否插在头部 +double default_mfact = 0.55f; // master 窗口比例 +uint32_t default_nmaster = 1; // 默认master数量 +int center_master_overspread = 0; // 中心master时是否铺满 +int center_when_single_stack = 1; // 单个stack时是否居中 /* logging */ int log_level = WLR_ERROR; -unsigned int numlockon = 0; // 是否打开右边小键盘 -unsigned int capslock = 0; // 是否启用快捷键 +uint32_t numlockon = 0; // 是否打开右边小键盘 +uint32_t capslock = 0; // 是否启用快捷键 -unsigned int ov_tab_mode = 0; // alt tab切换模式 -unsigned int hotarea_size = 10; // 热区大小,10x10 -unsigned int enable_hotarea = 1; // 是否启用鼠标热区 -int smartgaps = 0; /* 1 means no outer gap when there is only one window */ -int sloppyfocus = 1; /* focus follows mouse */ -unsigned int gappih = 5; /* horiz inner gap between windows */ -unsigned int gappiv = 5; /* vert inner gap between windows */ -unsigned int gappoh = 10; /* horiz outer gap between windows and screen edge */ -unsigned int gappov = 10; /* vert outer gap between windows and screen edge */ +uint32_t ov_tab_mode = 0; // alt tab切换模式 +uint32_t hotarea_size = 10; // 热区大小,10x10 +uint32_t enable_hotarea = 1; // 是否启用鼠标热区 +int smartgaps = 0; /* 1 means no outer gap when there is only one window */ +int sloppyfocus = 1; /* focus follows mouse */ +uint32_t gappih = 5; /* horiz inner gap between windows */ +uint32_t gappiv = 5; /* vert inner gap between windows */ +uint32_t gappoh = 10; /* horiz outer gap between windows and screen edge */ +uint32_t gappov = 10; /* vert outer gap between windows and screen edge */ float scratchpad_width_ratio = 0.8; float scratchpad_height_ratio = 0.9; @@ -73,15 +73,15 @@ int no_radius_when_single = 0; int snap_distance = 30; int enable_floating_snap = 0; int drag_tile_to_tile = 0; -unsigned int cursor_size = 24; -unsigned int cursor_hide_timeout = 0; +uint32_t cursor_size = 24; +uint32_t cursor_hide_timeout = 0; -unsigned int swipe_min_threshold = 1; +uint32_t swipe_min_threshold = 1; int inhibit_regardless_of_visibility = 0; /* 1 means idle inhibitors will disable idle tracking even if it's surface isn't visible */ -unsigned int borderpx = 4; /* border pixel of windows */ +uint32_t borderpx = 4; /* border pixel of windows */ float rootcolor[] = COLOR(0x323232ff); float bordercolor[] = COLOR(0x444444ff); float focuscolor[] = COLOR(0xc66b25ff); @@ -166,7 +166,7 @@ LIBINPUT_CONFIG_SCROLL_EDGE LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN */ enum libinput_config_scroll_method scroll_method = LIBINPUT_CONFIG_SCROLL_2FG; -unsigned int scroll_button = 274; +uint32_t scroll_button = 274; /* You can choose between: LIBINPUT_CONFIG_CLICK_METHOD_NONE @@ -224,7 +224,7 @@ float blur_params_saturation = 1.2; int shadows = 0; int shadow_only_floating = 1; int layer_shadows = 0; -unsigned int shadows_size = 10; +uint32_t shadows_size = 10; double shadows_blur = 15; int shadows_position_x = 0; int shadows_position_y = 0; diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index a782d4f1..1dc29daf 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -1,6 +1,6 @@ int bind_to_view(const Arg *arg) { - unsigned int target = arg->ui; + uint32_t target = arg->ui; if (view_current_to_back && selmon->pertag->curtag && (target & TAGMASK) == (selmon->tagset[selmon->seltags])) { @@ -130,7 +130,7 @@ int focuslast(const Arg *arg) { Client *c = NULL; Client *tc = NULL; bool begin = false; - unsigned int target = 0; + uint32_t target = 0; wl_list_for_each(c, &fstack, flink) { if (c->iskilling || c->isminimized || c->isunglobal || @@ -531,7 +531,7 @@ int set_proportion(const Arg *arg) { return 0; if (selmon->sel) { - unsigned int max_client_width = + uint32_t max_client_width = selmon->w.width - 2 * scroller_structs - gappih; selmon->sel->scroller_proportion = arg->f; selmon->sel->geom.width = max_client_width * arg->f; @@ -837,9 +837,9 @@ int switch_keyboard_layout(const Arg *arg) { xkb_layout_index_t next = (current + 1) % num_layouts; // 6. 应用新 keymap - unsigned int depressed = keyboard->modifiers.depressed; - unsigned int latched = keyboard->modifiers.latched; - unsigned int locked = keyboard->modifiers.locked; + uint32_t depressed = keyboard->modifiers.depressed; + uint32_t latched = keyboard->modifiers.latched; + uint32_t locked = keyboard->modifiers.locked; wlr_keyboard_set_keymap(keyboard, keyboard->keymap); wlr_keyboard_notify_modifiers(keyboard, depressed, latched, locked, next); @@ -874,7 +874,7 @@ int switch_layout(const Arg *arg) { int jk, ji; char *target_layout_name = NULL; - unsigned int len; + uint32_t len; if (config.circle_layout_count != 0) { for (jk = 0; jk < config.circle_layout_count; jk++) { @@ -959,7 +959,7 @@ int switch_proportion_preset(const Arg *arg) { target_proportion = config.scroller_proportion_preset[0]; } - unsigned int max_client_width = + uint32_t max_client_width = selmon->w.width - 2 * scroller_structs - gappih; selmon->sel->scroller_proportion = target_proportion; selmon->sel->geom.width = max_client_width * target_proportion; @@ -1001,8 +1001,8 @@ int tagmon(const Arg *arg) { if (!m || !m->wlr_output->enabled) return 0; - unsigned int newtags = arg->ui ? arg->ui : arg->i2 ? c->tags : 0; - unsigned int target; + uint32_t newtags = arg->ui ? arg->ui : arg->i2 ? c->tags : 0; + uint32_t target; if (c->mon == m) { view(&(Arg){.ui = newtags}, true); @@ -1242,7 +1242,7 @@ int toggleoverlay(const Arg *arg) { } int toggletag(const Arg *arg) { - unsigned int newtags; + uint32_t newtags; Client *sel = focustop(selmon); if (!sel) return 0; @@ -1265,8 +1265,8 @@ int toggletag(const Arg *arg) { } int toggleview(const Arg *arg) { - unsigned int newtagset; - unsigned int target; + uint32_t newtagset; + uint32_t target; target = arg->ui == 0 ? ~0 & TAGMASK : arg->ui; @@ -1283,7 +1283,7 @@ int toggleview(const Arg *arg) { } int viewtoleft(const Arg *arg) { - unsigned int target = selmon->tagset[selmon->seltags]; + uint32_t target = selmon->tagset[selmon->seltags]; if (selmon->isoverview || selmon->pertag->curtag == 0) { return 0; @@ -1306,7 +1306,7 @@ int viewtoright(const Arg *arg) { if (selmon->isoverview || selmon->pertag->curtag == 0) { return 0; } - unsigned int target = selmon->tagset[selmon->seltags]; + uint32_t target = selmon->tagset[selmon->seltags]; target <<= 1; if (!selmon || (target) == selmon->tagset[selmon->seltags]) @@ -1320,9 +1320,8 @@ int viewtoright(const Arg *arg) { } int viewtoleft_have_client(const Arg *arg) { - unsigned int n; - unsigned int current = - get_tags_first_tag_num(selmon->tagset[selmon->seltags]); + uint32_t n; + uint32_t current = get_tags_first_tag_num(selmon->tagset[selmon->seltags]); bool found = false; if (selmon->isoverview) { @@ -1345,9 +1344,8 @@ int viewtoleft_have_client(const Arg *arg) { } int viewtoright_have_client(const Arg *arg) { - unsigned int n; - unsigned int current = - get_tags_first_tag_num(selmon->tagset[selmon->seltags]); + uint32_t n; + uint32_t current = get_tags_first_tag_num(selmon->tagset[selmon->seltags]); bool found = false; if (selmon->isoverview) { @@ -1384,7 +1382,7 @@ int tagcrossmon(const Arg *arg) { } int comboview(const Arg *arg) { - unsigned int newtags = arg->ui & TAGMASK; + uint32_t newtags = arg->ui & TAGMASK; if (!newtags || !selmon) return 0; @@ -1462,8 +1460,8 @@ int toggleoverview(const Arg *arg) { } selmon->isoverview ^= 1; - unsigned int target; - unsigned int visible_client_number = 0; + uint32_t target; + uint32_t visible_client_number = 0; if (selmon->isoverview) { wl_list_for_each(c, &clients, link) if (c && c->mon == selmon && diff --git a/src/ext-protocol/dwl-ipc.h b/src/ext-protocol/dwl-ipc.h index 1d861b91..649c5f3a 100644 --- a/src/ext-protocol/dwl-ipc.h +++ b/src/ext-protocol/dwl-ipc.h @@ -1,12 +1,11 @@ #include "dwl-ipc-unstable-v2-protocol.h" static void dwl_ipc_manager_bind(struct wl_client *client, void *data, - unsigned int version, unsigned int id); + 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, - unsigned int id, - struct wl_resource *output); + 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); @@ -15,15 +14,14 @@ static void dwl_ipc_output_printstatus_to(DwlIpcOutput *ipc_output, uint32_t event_mask); static void dwl_ipc_output_set_client_tags(struct wl_client *client, struct wl_resource *resource, - unsigned int and_tags, - unsigned int xor_tags); + uint32_t and_tags, + uint32_t xor_tags); static void dwl_ipc_output_set_layout(struct wl_client *client, struct wl_resource *resource, - unsigned int index); + uint32_t index); static void dwl_ipc_output_set_tags(struct wl_client *client, struct wl_resource *resource, - unsigned int tagmask, - unsigned int toggle_tagset); + 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, @@ -47,7 +45,7 @@ static struct zdwl_ipc_output_v2_interface dwl_output_implementation = { .set_client_tags = dwl_ipc_output_set_client_tags}; void dwl_ipc_manager_bind(struct wl_client *client, void *data, - unsigned int version, unsigned int id) { + 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) { @@ -60,7 +58,7 @@ void dwl_ipc_manager_bind(struct wl_client *client, void *data, zdwl_ipc_manager_v2_send_tags(manager_resource, LENGTH(tags)); - for (unsigned int i = 0; i < LENGTH(layouts); i++) + for (uint32_t i = 0; i < LENGTH(layouts); i++) zdwl_ipc_manager_v2_send_layout(manager_resource, layouts[i].symbol); } @@ -69,7 +67,7 @@ void dwl_ipc_manager_destroy(struct wl_resource *resource) { } void dwl_ipc_manager_get_output(struct wl_client *client, - struct wl_resource *resource, unsigned int id, + struct wl_resource *resource, uint32_t id, struct wl_resource *output) { DwlIpcOutput *ipc_output; struct wlr_output *op = wlr_output_from_resource(output); @@ -292,12 +290,11 @@ void dwl_ipc_output_printstatus_to(DwlIpcOutput *ipc_output, void dwl_ipc_output_set_client_tags(struct wl_client *client, struct wl_resource *resource, - unsigned int and_tags, - unsigned int xor_tags) { + uint32_t and_tags, uint32_t xor_tags) { DwlIpcOutput *ipc_output; Monitor *monitor = NULL; Client *selected_client = NULL; - unsigned int newtags = 0; + uint32_t newtags = 0; ipc_output = wl_resource_get_user_data(resource); if (!ipc_output) @@ -320,8 +317,7 @@ void dwl_ipc_output_set_client_tags(struct wl_client *client, } void dwl_ipc_output_set_layout(struct wl_client *client, - struct wl_resource *resource, - unsigned int index) { + struct wl_resource *resource, uint32_t index) { DwlIpcOutput *ipc_output; Monitor *monitor = NULL; @@ -340,11 +336,11 @@ void dwl_ipc_output_set_layout(struct wl_client *client, } void dwl_ipc_output_set_tags(struct wl_client *client, - struct wl_resource *resource, unsigned int tagmask, - unsigned int toggle_tagset) { + struct wl_resource *resource, uint32_t tagmask, + uint32_t toggle_tagset) { DwlIpcOutput *ipc_output; Monitor *monitor = NULL; - unsigned int newtags = tagmask & TAGMASK; + uint32_t newtags = tagmask & TAGMASK; ipc_output = wl_resource_get_user_data(resource); if (!ipc_output) diff --git a/src/ext-protocol/ext-workspace.h b/src/ext-protocol/ext-workspace.h index 930e6c98..d4e0e514 100644 --- a/src/ext-protocol/ext-workspace.h +++ b/src/ext-protocol/ext-workspace.h @@ -8,7 +8,7 @@ typedef struct Monitor Monitor; struct workspace { struct wl_list link; // Link in global workspaces list - unsigned int tag; // Numeric identifier (1-9, 0=overview) + uint32_t tag; // Numeric identifier (1-9, 0=overview) Monitor *m; // Associated monitor struct wlr_ext_workspace_handle_v1 *ext_workspace; // Protocol object /* Event listeners */ @@ -22,7 +22,7 @@ struct wlr_ext_workspace_manager_v1 *ext_manager; struct wl_list workspaces; void goto_workspace(struct workspace *target) { - unsigned int tag; + uint32_t tag; tag = 1 << (target->tag - 1); if (target->tag == 0) { toggleoverview(&(Arg){.i = -1}); @@ -33,7 +33,7 @@ void goto_workspace(struct workspace *target) { } void toggle_workspace(struct workspace *target) { - unsigned int tag; + uint32_t tag; tag = 1 << (target->tag - 1); if (target->tag == 0) { toggleview(&(Arg){.i = -1}); @@ -69,7 +69,7 @@ static void handle_ext_workspace_deactivate(struct wl_listener *listener, wlr_log(WLR_INFO, "ext deactivating workspace %d", workspace->tag); } -static const char *get_name_from_tag(unsigned int tag) { +static const char *get_name_from_tag(uint32_t tag) { static const char *names[] = {"overview", "1", "2", "3", "4", "5", "6", "7", "8", "9"}; return (tag < sizeof(names) / sizeof(names[0])) ? names[tag] : NULL; @@ -92,7 +92,7 @@ void cleanup_workspaces_by_monitor(Monitor *m) { } } -static void remove_workspace_by_tag(unsigned int tag, Monitor *m) { +static void remove_workspace_by_tag(uint32_t tag, Monitor *m) { struct workspace *workspace, *tmp; wl_list_for_each_safe(workspace, tmp, &workspaces, link) { if (workspace->tag == tag && workspace->m == m) { @@ -127,7 +127,7 @@ static void add_workspace_by_tag(int tag, Monitor *m) { void dwl_ext_workspace_printstatus(Monitor *m) { struct workspace *w; - unsigned int tag_status = 0; + uint32_t tag_status = 0; wl_list_for_each(w, &workspaces, link) { if (w && w->m == m) { diff --git a/src/ext-protocol/foreign-toplevel.h b/src/ext-protocol/foreign-toplevel.h index 0bb649e0..3b819485 100644 --- a/src/ext-protocol/foreign-toplevel.h +++ b/src/ext-protocol/foreign-toplevel.h @@ -4,7 +4,7 @@ static struct wlr_foreign_toplevel_manager_v1 *foreign_toplevel_manager; void handle_foreign_activate_request(struct wl_listener *listener, void *data) { Client *c = wl_container_of(listener, c, foreign_activate_request); - unsigned int target; + uint32_t target; if (c && c->swallowing) return; diff --git a/src/fetch/client.h b/src/fetch/client.h index a9cfed07..ca39ab9e 100644 --- a/src/fetch/client.h +++ b/src/fetch/client.h @@ -70,7 +70,7 @@ setclient_coordinate_center(Client *c, struct wlr_box geom, int offsetx, int len = 0; Monitor *m = c->mon ? c->mon : selmon; - unsigned int cbw = check_hit_no_border(c) ? c->bw : 0; + uint32_t cbw = check_hit_no_border(c) ? c->bw : 0; if (!c->no_force_center) { tempbox.x = m->w.x + (m->w.width - geom.width) / 2; diff --git a/src/fetch/common.h b/src/fetch/common.h index 41dc9944..c86a3fef 100644 --- a/src/fetch/common.h +++ b/src/fetch/common.h @@ -1,5 +1,5 @@ pid_t getparentprocess(pid_t p) { - unsigned int v = 0; + uint32_t v = 0; FILE *f; char buf[256]; @@ -26,7 +26,7 @@ int isdescprocess(pid_t p, pid_t c) { return (int)c; } -char *get_autostart_path(char *autostart_path, unsigned int buf_size) { +char *get_autostart_path(char *autostart_path, uint32_t buf_size) { const char *mangoconfig = getenv("MANGOCONFIG"); if (mangoconfig && mangoconfig[0] != '\0') { @@ -60,10 +60,10 @@ void get_layout_abbr(char *abbr, const char *full_name) { const char *open = strrchr(full_name, '('); const char *close = strrchr(full_name, ')'); if (open && close && close > open) { - unsigned int len = close - open - 1; + uint32_t len = close - open - 1; if (len > 0 && len <= 4) { // 提取并转换为小写 - for (unsigned int j = 0; j < len; j++) { + for (uint32_t j = 0; j < len; j++) { abbr[j] = tolower(open[j + 1]); } abbr[len] = '\0'; @@ -72,8 +72,8 @@ void get_layout_abbr(char *abbr, const char *full_name) { } // 3. 提取前2-3个字母并转换为小写 - unsigned int j = 0; - for (unsigned int i = 0; full_name[i] != '\0' && j < 3; i++) { + uint32_t j = 0; + for (uint32_t i = 0; full_name[i] != '\0' && j < 3; i++) { if (isalpha(full_name[i])) { abbr[j++] = tolower(full_name[i]); } diff --git a/src/fetch/monitor.h b/src/fetch/monitor.h index d55e9ab6..47a5b824 100644 --- a/src/fetch/monitor.h +++ b/src/fetch/monitor.h @@ -26,9 +26,9 @@ bool is_scroller_layout(Monitor *m) { return false; } -unsigned int get_tag_status(unsigned int tag, Monitor *m) { +uint32_t get_tag_status(uint32_t tag, Monitor *m) { Client *c = NULL; - unsigned int status = 0; + uint32_t status = 0; wl_list_for_each(c, &clients, link) { if (c->mon == m && c->tags & 1 << (tag - 1) & TAGMASK) { if (c->isurgent) { @@ -41,8 +41,8 @@ unsigned int get_tag_status(unsigned int tag, Monitor *m) { return status; } -unsigned int get_tags_first_tag_num(unsigned int source_tags) { - unsigned int i, tag; +uint32_t get_tags_first_tag_num(uint32_t source_tags) { + uint32_t i, tag; tag = 0; if (!source_tags) { @@ -63,8 +63,8 @@ unsigned int get_tags_first_tag_num(unsigned int source_tags) { } // 获取tags中最前面的tag的tagmask -unsigned int get_tags_first_tag(unsigned int source_tags) { - unsigned int i, tag; +uint32_t get_tags_first_tag(uint32_t source_tags) { + uint32_t i, tag; tag = 0; if (!source_tags) { diff --git a/src/layout/arrange.h b/src/layout/arrange.h index ba1391e6..3fb25a46 100644 --- a/src/layout/arrange.h +++ b/src/layout/arrange.h @@ -19,7 +19,7 @@ void set_size_per(Monitor *m, Client *c) { } void resize_tile_master_horizontal(Client *grabc, bool isdrag, int offsetx, - int offsety, unsigned int time, int type) { + int offsety, uint32_t time, int type) { Client *tc = NULL; float delta_x, delta_y; Client *next = NULL; @@ -213,7 +213,7 @@ void resize_tile_master_horizontal(Client *grabc, bool isdrag, int offsetx, } void resize_tile_master_vertical(Client *grabc, bool isdrag, int offsetx, - int offsety, unsigned int time, int type) { + int offsety, uint32_t time, int type) { Client *tc = NULL; float delta_x, delta_y; Client *next = NULL; @@ -370,7 +370,7 @@ void resize_tile_master_vertical(Client *grabc, bool isdrag, int offsetx, } void resize_tile_scroller(Client *grabc, bool isdrag, int offsetx, int offsety, - unsigned int time, bool isvertical) { + uint32_t time, bool isvertical) { float delta_x, delta_y; float new_scroller_proportion; @@ -474,7 +474,7 @@ void resize_tile_scroller(Client *grabc, bool isdrag, int offsetx, int offsety, } void resize_tile_client(Client *grabc, bool isdrag, int offsetx, int offsety, - unsigned int time) { + uint32_t time) { if (!grabc || grabc->isfullscreen || grabc->ismaximizescreen) return; @@ -509,8 +509,8 @@ void reset_size_per_mon(Monitor *m, int tile_cilent_num, int stack_num) { Client *c = NULL; int i = 0; - unsigned int stack_index = 0; - unsigned int nmasters = m->pertag->nmasters[m->pertag->curtag]; + uint32_t stack_index = 0; + uint32_t nmasters = m->pertag->nmasters[m->pertag->curtag]; if (m->pertag->ltidxs[m->pertag->curtag]->id != CENTER_TILE) { diff --git a/src/layout/horizontal.h b/src/layout/horizontal.h index 3471fdf7..9a6a5950 100644 --- a/src/layout/horizontal.h +++ b/src/layout/horizontal.h @@ -1,9 +1,9 @@ // 网格布局窗口大小和位置计算 void grid(Monitor *m) { - unsigned int i, n; - unsigned int cx, cy, cw, ch; - unsigned int dx; - unsigned int cols, rows, overcols; + uint32_t i, n; + uint32_t cx, cy, cw, ch; + uint32_t dx; + uint32_t cols, rows, overcols; Client *c = NULL; n = 0; int target_gappo = enablegaps ? m->isoverview ? overviewgappo : gappoh : 0; @@ -121,15 +121,15 @@ void grid(Monitor *m) { } void deck(Monitor *m) { - unsigned int mw, my; + uint32_t mw, my; int i, n = 0; Client *c = NULL; Client *fc = NULL; float mfact; - unsigned int cur_gappih = enablegaps ? m->gappih : 0; - unsigned int cur_gappoh = enablegaps ? m->gappoh : 0; - unsigned int cur_gappov = enablegaps ? m->gappov : 0; + uint32_t cur_gappih = enablegaps ? m->gappih : 0; + uint32_t cur_gappoh = enablegaps ? m->gappoh : 0; + uint32_t cur_gappov = enablegaps ? m->gappov : 0; cur_gappih = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappih; cur_gappoh = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappoh; @@ -192,9 +192,9 @@ void deck(Monitor *m) { void horizontal_scroll_adjust_fullandmax(Client *c, struct wlr_box *target_geom) { Monitor *m = c->mon; - unsigned int cur_gappih = enablegaps ? m->gappih : 0; - unsigned int cur_gappoh = enablegaps ? m->gappoh : 0; - unsigned int cur_gappov = enablegaps ? m->gappov : 0; + uint32_t cur_gappih = enablegaps ? m->gappih : 0; + uint32_t cur_gappoh = enablegaps ? m->gappoh : 0; + uint32_t cur_gappov = enablegaps ? m->gappov : 0; cur_gappih = smartgaps && m->visible_scroll_tiling_clients == 1 ? 0 : cur_gappih; @@ -223,7 +223,7 @@ void horizontal_scroll_adjust_fullandmax(Client *c, // 滚动布局 void scroller(Monitor *m) { - unsigned int i, n, j; + uint32_t i, n, j; float single_proportion = 1.0; Client *c = NULL, *root_client = NULL; @@ -231,9 +231,9 @@ void scroller(Monitor *m) { struct wlr_box target_geom; int focus_client_index = 0; bool need_scroller = false; - unsigned int cur_gappih = enablegaps ? m->gappih : 0; - unsigned int cur_gappoh = enablegaps ? m->gappoh : 0; - unsigned int cur_gappov = enablegaps ? m->gappov : 0; + uint32_t cur_gappih = enablegaps ? m->gappih : 0; + uint32_t cur_gappoh = enablegaps ? m->gappoh : 0; + uint32_t cur_gappov = enablegaps ? m->gappov : 0; cur_gappih = smartgaps && m->visible_scroll_tiling_clients == 1 ? 0 : cur_gappih; @@ -242,8 +242,7 @@ void scroller(Monitor *m) { cur_gappov = smartgaps && m->visible_scroll_tiling_clients == 1 ? 0 : cur_gappov; - unsigned int max_client_width = - m->w.width - 2 * scroller_structs - cur_gappih; + uint32_t max_client_width = m->w.width - 2 * scroller_structs - cur_gappih; n = m->visible_scroll_tiling_clients; @@ -378,7 +377,7 @@ void scroller(Monitor *m) { } void center_tile(Monitor *m) { - unsigned int i, n = 0, h, r, ie = enablegaps, mw, mx, my, oty, ety, tw; + uint32_t i, n = 0, h, r, ie = enablegaps, mw, mx, my, oty, ety, tw; Client *c = NULL; Client *fc = NULL; double mfact = 0; @@ -399,10 +398,10 @@ void center_tile(Monitor *m) { } // 间隙参数处理 - unsigned int cur_gappiv = enablegaps ? m->gappiv : 0; // 内部垂直间隙 - unsigned int cur_gappih = enablegaps ? m->gappih : 0; // 内部水平间隙 - unsigned int cur_gappov = enablegaps ? m->gappov : 0; // 外部垂直间隙 - unsigned int cur_gappoh = enablegaps ? m->gappoh : 0; // 外部水平间隙 + uint32_t cur_gappiv = enablegaps ? m->gappiv : 0; // 内部垂直间隙 + uint32_t cur_gappih = enablegaps ? m->gappih : 0; // 内部水平间隙 + uint32_t cur_gappov = enablegaps ? m->gappov : 0; // 外部垂直间隙 + uint32_t cur_gappoh = enablegaps ? m->gappoh : 0; // 外部水平间隙 // 智能间隙处理 cur_gappiv = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappiv; @@ -410,7 +409,7 @@ void center_tile(Monitor *m) { cur_gappov = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappov; cur_gappoh = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappoh; - unsigned int nmasters = m->pertag->nmasters[m->pertag->curtag]; + uint32_t nmasters = m->pertag->nmasters[m->pertag->curtag]; mfact = fc->master_mfact_per > 0.0f ? fc->master_mfact_per : m->pertag->mfacts[m->pertag->curtag]; @@ -489,7 +488,7 @@ void center_tile(Monitor *m) { my += c->geom.height + cur_gappiv * ie; } else { // 堆叠区域窗口 - unsigned int stack_index = i - nmasters; + uint32_t stack_index = i - nmasters; if (n - nmasters == 1) { // 单个堆叠窗口 @@ -587,7 +586,7 @@ void center_tile(Monitor *m) { } void tile(Monitor *m) { - unsigned int i, n = 0, h, r, ie = enablegaps, mw, my, ty; + uint32_t i, n = 0, h, r, ie = enablegaps, mw, my, ty; Client *c = NULL; Client *fc = NULL; double mfact = 0; @@ -601,10 +600,10 @@ void tile(Monitor *m) { if (n == 0) return; - unsigned int cur_gappiv = enablegaps ? m->gappiv : 0; - unsigned int cur_gappih = enablegaps ? m->gappih : 0; - unsigned int cur_gappov = enablegaps ? m->gappov : 0; - unsigned int cur_gappoh = enablegaps ? m->gappoh : 0; + uint32_t cur_gappiv = enablegaps ? m->gappiv : 0; + uint32_t cur_gappih = enablegaps ? m->gappih : 0; + uint32_t cur_gappov = enablegaps ? m->gappov : 0; + uint32_t cur_gappoh = enablegaps ? m->gappoh : 0; cur_gappiv = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappiv; cur_gappih = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappih; @@ -684,7 +683,7 @@ void tile(Monitor *m) { } void right_tile(Monitor *m) { - unsigned int i, n = 0, h, r, ie = enablegaps, mw, my, ty; + uint32_t i, n = 0, h, r, ie = enablegaps, mw, my, ty; Client *c = NULL; Client *fc = NULL; double mfact = 0; @@ -698,10 +697,10 @@ void right_tile(Monitor *m) { if (n == 0) return; - unsigned int cur_gappiv = enablegaps ? m->gappiv : 0; - unsigned int cur_gappih = enablegaps ? m->gappih : 0; - unsigned int cur_gappov = enablegaps ? m->gappov : 0; - unsigned int cur_gappoh = enablegaps ? m->gappoh : 0; + uint32_t cur_gappiv = enablegaps ? m->gappiv : 0; + uint32_t cur_gappih = enablegaps ? m->gappih : 0; + uint32_t cur_gappov = enablegaps ? m->gappov : 0; + uint32_t cur_gappoh = enablegaps ? m->gappoh : 0; cur_gappiv = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappiv; cur_gappih = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappih; @@ -786,8 +785,8 @@ monocle(Monitor *m) { Client *c = NULL; struct wlr_box geom; - unsigned int cur_gappov = enablegaps ? m->gappov : 0; - unsigned int cur_gappoh = enablegaps ? m->gappoh : 0; + uint32_t cur_gappov = enablegaps ? m->gappov : 0; + uint32_t cur_gappoh = enablegaps ? m->gappoh : 0; cur_gappoh = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappoh; cur_gappov = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappov; diff --git a/src/layout/vertical.h b/src/layout/vertical.h index f6aa6b86..5badc72b 100644 --- a/src/layout/vertical.h +++ b/src/layout/vertical.h @@ -1,5 +1,5 @@ void vertical_tile(Monitor *m) { - unsigned int i, n = 0, w, r, ie = enablegaps, mh, mx, tx; + uint32_t i, n = 0, w, r, ie = enablegaps, mh, mx, tx; Client *c = NULL; Client *fc = NULL; double mfact = 0; @@ -13,10 +13,10 @@ void vertical_tile(Monitor *m) { if (n == 0) return; - unsigned int cur_gapih = enablegaps ? m->gappih : 0; - unsigned int cur_gapiv = enablegaps ? m->gappiv : 0; - unsigned int cur_gapoh = enablegaps ? m->gappoh : 0; - unsigned int cur_gapov = enablegaps ? m->gappov : 0; + uint32_t cur_gapih = enablegaps ? m->gappih : 0; + uint32_t cur_gapiv = enablegaps ? m->gappiv : 0; + uint32_t cur_gapoh = enablegaps ? m->gappoh : 0; + uint32_t cur_gapov = enablegaps ? m->gappov : 0; cur_gapih = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gapih; cur_gapiv = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gapiv; @@ -92,15 +92,15 @@ void vertical_tile(Monitor *m) { } void vertical_deck(Monitor *m) { - unsigned int mh, mx; + uint32_t mh, mx; int i, n = 0; Client *c = NULL; Client *fc = NULL; float mfact; - unsigned int cur_gappiv = enablegaps ? m->gappiv : 0; - unsigned int cur_gappoh = enablegaps ? m->gappoh : 0; - unsigned int cur_gappov = enablegaps ? m->gappov : 0; + uint32_t cur_gappiv = enablegaps ? m->gappiv : 0; + uint32_t cur_gappoh = enablegaps ? m->gappoh : 0; + uint32_t cur_gappov = enablegaps ? m->gappov : 0; cur_gappiv = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappiv; cur_gappoh = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappoh; @@ -157,9 +157,9 @@ void vertical_deck(Monitor *m) { void vertical_scroll_adjust_fullandmax(Client *c, struct wlr_box *target_geom) { Monitor *m = c->mon; - unsigned int cur_gappiv = enablegaps ? m->gappiv : 0; - unsigned int cur_gappov = enablegaps ? m->gappov : 0; - unsigned int cur_gappoh = enablegaps ? m->gappoh : 0; + uint32_t cur_gappiv = enablegaps ? m->gappiv : 0; + uint32_t cur_gappov = enablegaps ? m->gappov : 0; + uint32_t cur_gappoh = enablegaps ? m->gappoh : 0; cur_gappiv = smartgaps && m->visible_scroll_tiling_clients == 1 ? 0 : cur_gappiv; @@ -188,7 +188,7 @@ void vertical_scroll_adjust_fullandmax(Client *c, struct wlr_box *target_geom) { // 竖屏滚动布局 void vertical_scroller(Monitor *m) { - unsigned int i, n, j; + uint32_t i, n, j; float single_proportion = 1.0; Client *c = NULL, *root_client = NULL; @@ -196,9 +196,9 @@ void vertical_scroller(Monitor *m) { struct wlr_box target_geom; int focus_client_index = 0; bool need_scroller = false; - unsigned int cur_gappiv = enablegaps ? m->gappiv : 0; - unsigned int cur_gappov = enablegaps ? m->gappov : 0; - unsigned int cur_gappoh = enablegaps ? m->gappoh : 0; + uint32_t cur_gappiv = enablegaps ? m->gappiv : 0; + uint32_t cur_gappov = enablegaps ? m->gappov : 0; + uint32_t cur_gappoh = enablegaps ? m->gappoh : 0; cur_gappiv = smartgaps && m->visible_scroll_tiling_clients == 1 ? 0 : cur_gappiv; @@ -207,7 +207,7 @@ void vertical_scroller(Monitor *m) { cur_gappoh = smartgaps && m->visible_scroll_tiling_clients == 1 ? 0 : cur_gappoh; - unsigned int max_client_height = + uint32_t max_client_height = m->w.height - 2 * scroller_structs - cur_gappiv; n = m->visible_scroll_tiling_clients; @@ -341,10 +341,10 @@ void vertical_scroller(Monitor *m) { } void vertical_grid(Monitor *m) { - unsigned int i, n; - unsigned int cx, cy, cw, ch; - unsigned int dy; - unsigned int rows, cols, overrows; + uint32_t i, n; + uint32_t cx, cy, cw, ch; + uint32_t dy; + uint32_t rows, cols, overrows; Client *c = NULL; int target_gappo = enablegaps ? m->isoverview ? overviewgappo : gappov : 0; int target_gappi = enablegaps ? m->isoverview ? overviewgappi : gappiv : 0; diff --git a/src/mango.c b/src/mango.c index 1a1ea665..00430b18 100644 --- a/src/mango.c +++ b/src/mango.c @@ -223,16 +223,16 @@ typedef struct { char *v; char *v2; char *v3; - unsigned int ui; - unsigned int ui2; + uint32_t ui; + uint32_t ui2; } Arg; struct mango_print_status_manager { struct wl_signal print_status; }; typedef struct { - unsigned int mod; - unsigned int button; + uint32_t mod; + uint32_t button; int (*func)(const Arg *); const Arg arg; } Button; // 鼠标按键 @@ -243,8 +243,8 @@ typedef struct { } KeyMode; typedef struct { - unsigned int mod; - unsigned int dir; + uint32_t mod; + uint32_t dir; int (*func)(const Arg *); const Arg arg; } Axis; @@ -272,8 +272,8 @@ struct dwl_animation { bool tagouting; bool begin_fade_in; bool tag_from_rule; - unsigned int time_started; - unsigned int duration; + uint32_t time_started; + uint32_t duration; struct wlr_box initial; struct wlr_box current; int action; @@ -284,8 +284,8 @@ struct dwl_opacity_animation { float current_opacity; float target_opacity; float initial_opacity; - unsigned int time_started; - unsigned int duration; + uint32_t time_started; + uint32_t duration; float current_border_color[4]; float target_border_color[4]; float initial_border_color[4]; @@ -302,7 +302,7 @@ typedef struct { struct Client { /* Must keep these three elements in this order */ - unsigned int type; /* XDGShell or X11* */ + uint32_t type; /* XDGShell or X11* */ struct wlr_box geom, pending, float_geom, animainit_geom, overview_backup_geom, current, drag_begin_geom; /* layout-relative, includes border */ @@ -334,10 +334,10 @@ struct Client { struct wl_listener set_hints; struct wl_listener set_geometry; #endif - unsigned int bw; - unsigned int tags, oldtags, mini_restore_tag; + uint32_t bw; + uint32_t tags, oldtags, mini_restore_tag; bool dirty; - unsigned int configure_serial; + uint32_t configure_serial; struct wlr_foreign_toplevel_handle_v1 *foreign_toplevel; int isfloating, isurgent, isfullscreen, isfakefullscreen, need_float_size_reduce, isminimized, isoverlay, isnosizehint, @@ -414,7 +414,7 @@ typedef struct { } DwlIpcOutput; typedef struct { - unsigned int mod; + uint32_t mod; xkb_keysym_t keysym; int (*func)(const Arg *); const Arg arg; @@ -425,8 +425,8 @@ typedef struct { int nsyms; const xkb_keysym_t *keysyms; /* invalid if nsyms == 0 */ - unsigned int mods; /* invalid if nsyms == 0 */ - unsigned int keycode; + uint32_t mods; /* invalid if nsyms == 0 */ + uint32_t keycode; struct wl_event_source *key_repeat_source; struct wl_listener modifiers; @@ -442,7 +442,7 @@ typedef struct { typedef struct { /* Must keep these three elements in this order */ - unsigned int type; /* LayerShell */ + uint32_t type; /* LayerShell */ struct wlr_box geom, current, pending, animainit_geom; Monitor *mon; struct wlr_scene_tree *scene; @@ -473,7 +473,7 @@ typedef struct { const char *symbol; void (*arrange)(Monitor *); const char *name; - unsigned int id; + uint32_t id; } Layout; struct Monitor { @@ -490,8 +490,8 @@ struct Monitor { struct wlr_box w; /* window area, layout-relative */ struct wl_list layers[4]; /* LayerSurface::link */ const Layout *lt; - unsigned int seltags; - unsigned int tagset[2]; + uint32_t seltags; + uint32_t tagset[2]; double mfact; int nmaster; @@ -505,9 +505,9 @@ struct Monitor { int isoverview; int is_in_hotarea; int asleep; - unsigned int visible_clients; - unsigned int visible_tiling_clients; - unsigned int visible_scroll_tiling_clients; + uint32_t visible_clients; + uint32_t visible_tiling_clients; + uint32_t visible_scroll_tiling_clients; bool has_visible_fullscreen_client; struct wlr_scene_optimized_blur *blur; char last_surface_ws_name[256]; @@ -539,7 +539,7 @@ arrange(Monitor *m, static void arrangelayer(Monitor *m, struct wl_list *list, struct wlr_box *usable_area, int exclusive); static void arrangelayers(Monitor *m); -static char *get_autostart_path(char *, unsigned int); // 自启动命令执行 +static char *get_autostart_path(char *, uint32_t); // 自启动命令执行 static void handle_print_status(struct wl_listener *listener, void *data); static void axisnotify(struct wl_listener *listener, void *data); // 滚轮事件处理 @@ -605,21 +605,20 @@ static void gpureset(struct wl_listener *listener, void *data); static int keyrepeat(void *data); static void inputdevice(struct wl_listener *listener, void *data); -static int keybinding(unsigned int state, bool locked, unsigned int mods, - xkb_keysym_t sym, unsigned int keycode); +static int keybinding(uint32_t state, bool locked, uint32_t mods, + xkb_keysym_t sym, uint32_t keycode); static void keypress(struct wl_listener *listener, void *data); static void keypressmod(struct wl_listener *listener, void *data); static bool keypressglobal(struct wlr_surface *last_surface, struct wlr_keyboard *keyboard, - struct wlr_keyboard_key_event *event, - unsigned int mods, xkb_keysym_t keysym, - unsigned int keycode); + struct wlr_keyboard_key_event *event, uint32_t mods, + xkb_keysym_t keysym, uint32_t keycode); static void locksession(struct wl_listener *listener, void *data); static void mapnotify(struct wl_listener *listener, void *data); static void maximizenotify(struct wl_listener *listener, void *data); static void minimizenotify(struct wl_listener *listener, void *data); static void motionabsolute(struct wl_listener *listener, void *data); -static void motionnotify(unsigned int time, struct wlr_input_device *device, +static void motionnotify(uint32_t time, struct wlr_input_device *device, double sx, double sy, double sx_unaccel, double sy_unaccel); static void motionrelative(struct wl_listener *listener, void *data); @@ -633,8 +632,8 @@ static void outputmgrapplyortest(struct wlr_output_configuration_v1 *config, int test); static void outputmgrtest(struct wl_listener *listener, void *data); static void pointerfocus(Client *c, struct wlr_surface *surface, double sx, - double sy, unsigned int time); -static void printstatus(unsigned int event_mask); + double sy, uint32_t time); +static void printstatus(uint32_t event_mask); static void quitsignal(int signo); static void powermgrsetmode(struct wl_listener *listener, void *data); static void rendermon(struct wl_listener *listener, void *data); @@ -651,7 +650,7 @@ static void setmaximizescreen(Client *c, int maximizescreen); static void reset_maximizescreen_size(Client *c); static void setgaps(int oh, int ov, int ih, int iv); -static void setmon(Client *c, Monitor *m, unsigned int newtags, bool focus); +static void setmon(Client *c, Monitor *m, uint32_t newtags, bool focus); static void setpsel(struct wl_listener *listener, void *data); static void setsel(struct wl_listener *listener, void *data); static void setup(void); @@ -682,7 +681,7 @@ static Client *termforwin(Client *w); static void swallow(Client *c, Client *w); static void warp_cursor_to_selmon(Monitor *m); -unsigned int want_restore_fullscreen(Client *target_client); +uint32_t want_restore_fullscreen(Client *target_client); static void overview_restore(Client *c, const Arg *arg); static void overview_backup(Client *c); static int applyrulesgeom(Client *c); @@ -695,7 +694,7 @@ static void tag_client(const Arg *arg, Client *target_client); static struct wlr_box setclient_coordinate_center(Client *c, struct wlr_box geom, int offsetx, int offsety); -static unsigned int get_tags_first_tag(unsigned int tags); +static uint32_t get_tags_first_tag(uint32_t tags); static struct wlr_output_mode * get_nearest_output_mode(struct wlr_output *output, int width, int height, @@ -726,11 +725,11 @@ static bool check_hit_no_border(Client *c); static void reset_keyboard_layout(void); static void client_update_oldmonname_record(Client *c, Monitor *m); static void pending_kill_client(Client *c); -static unsigned int get_tags_first_tag_num(unsigned int source_tags); +static uint32_t get_tags_first_tag_num(uint32_t source_tags); static void set_layer_open_animaiton(LayerSurface *l, struct wlr_box geo); static void init_fadeout_layers(LayerSurface *l); -static void layer_actual_size(LayerSurface *l, unsigned int *width, - unsigned int *height); +static void layer_actual_size(LayerSurface *l, uint32_t *width, + uint32_t *height); static void get_layer_target_geometry(LayerSurface *l, struct wlr_box *target_box); static void scene_buffer_apply_effect(struct wlr_scene_buffer *buffer, int sx, @@ -752,13 +751,13 @@ static Client *get_client_by_id_or_title(const char *arg_id, const char *arg_title); static bool switch_scratchpad_client_state(Client *c); static bool check_trackpad_disabled(struct wlr_pointer *pointer); -static unsigned int get_tag_status(unsigned int tag, Monitor *m); +static uint32_t get_tag_status(uint32_t tag, Monitor *m); static void enable_adaptive_sync(Monitor *m, struct wlr_output_state *state); static Client *get_next_stack_client(Client *c, bool reverse); static void set_float_malposition(Client *tc); static void set_size_per(Monitor *m, Client *c); static void resize_tile_client(Client *grabc, bool isdrag, int offsetx, - int offsety, unsigned int time); + int offsety, uint32_t time); static void refresh_monitors_workspaces_status(Monitor *m); static void init_client_properties(Client *c); static float *get_border_color(Client *c); @@ -773,7 +772,7 @@ static void clear_fullscreen_and_maximized_state(Monitor *m); static const char broken[] = "broken"; static pid_t child_pid = -1; static int locked; -static unsigned int locked_mods = 0; +static uint32_t locked_mods = 0; static void *exclusive_focus; static struct wl_display *dpy; static struct wl_event_loop *event_loop; @@ -824,7 +823,7 @@ static struct wlr_seat *seat; static KeyboardGroup *kb_group; static struct wl_list inputdevices; static struct wl_list keyboard_shortcut_inhibitors; -static unsigned int cursor_mode; +static uint32_t cursor_mode; static Client *grabc; static int grabcx, grabcy; /* client-relative */ static int drag_begin_cursorx, drag_begin_cursory; /* client-relative */ @@ -841,7 +840,7 @@ static int axis_apply_time = 0; static int axis_apply_dir = 0; static int scroller_focus_lock = 0; -static unsigned int swipe_fingers = 0; +static uint32_t swipe_fingers = 0; static double swipe_dx = 0; static double swipe_dy = 0; @@ -871,7 +870,7 @@ static struct { #include "config/preset.h" struct Pertag { - unsigned int curtag, prevtag; /* current and previous tag */ + uint32_t curtag, prevtag; /* current and previous tag */ int 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 */ @@ -1318,7 +1317,7 @@ void set_float_malposition(Client *tc) { void applyrules(Client *c) { /* rule matching */ const char *appid, *title; - unsigned int i, newtags = 0; + uint32_t i, newtags = 0; const ConfigWinRule *r; Monitor *m = NULL; Client *fc = NULL; @@ -1493,9 +1492,9 @@ void apply_window_snap(Client *c) { int snap_up_mon = 0, snap_down_mon = 0, snap_left_mon = 0, snap_right_mon = 0; - unsigned int cbw = !render_border || c->fake_no_border ? borderpx : 0; - unsigned int tcbw; - unsigned int cx, cy, cw, ch, tcx, tcy, tcw, tch; + uint32_t cbw = !render_border || c->fake_no_border ? borderpx : 0; + uint32_t tcbw; + uint32_t cx, cy, cw, ch, tcx, tcy, tcw, tch; cx = c->geom.x + cbw; cy = c->geom.y + cbw; cw = c->geom.width - 2 * cbw; @@ -1595,7 +1594,7 @@ void focuslayer(LayerSurface *l) { void reset_exclusive_layer(Monitor *m) { LayerSurface *l = NULL; int i; - unsigned int layers_above_shell[] = { + uint32_t layers_above_shell[] = { ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY, ZWLR_LAYER_SHELL_V1_LAYER_TOP, ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM, @@ -1660,10 +1659,10 @@ axisnotify(struct wl_listener *listener, void *data) { * for example when you move the scroll wheel. */ struct wlr_pointer_axis_event *event = data; struct wlr_keyboard *keyboard, *hard_keyboard; - unsigned int mods, hard_mods; + uint32_t mods, hard_mods; AxisBinding *a; int ji; - unsigned int adir; + uint32_t adir; // IDLE_NOTIFY_ACTIVITY; handlecursoractivity(); wlr_idle_notifier_v1_notify_activity(idle_notifier, seat); @@ -1717,11 +1716,11 @@ axisnotify(struct wl_listener *listener, void *data) { int ongesture(struct wlr_pointer_swipe_end_event *event) { struct wlr_keyboard *keyboard, *hard_keyboard; - unsigned int mods, hard_mods; + uint32_t mods, hard_mods; const GestureBinding *g; - unsigned int motion; - unsigned int adx = (int)round(fabs(swipe_dx)); - unsigned int ady = (int)round(fabs(swipe_dy)); + uint32_t motion; + uint32_t adx = (int)round(fabs(swipe_dx)); + uint32_t ady = (int)round(fabs(swipe_dy)); int handled = 0; int ji; @@ -1886,7 +1885,7 @@ void // 鼠标按键事件 buttonpress(struct wl_listener *listener, void *data) { struct wlr_pointer_button_event *event = data; struct wlr_keyboard *hard_keyboard, *keyboard; - unsigned int hard_mods, mods; + uint32_t hard_mods, mods; Client *c = NULL; LayerSurface *l = NULL; struct wlr_surface *surface; @@ -2104,7 +2103,7 @@ void cleanup(void) { void cleanupmon(struct wl_listener *listener, void *data) { Monitor *m = wl_container_of(listener, m, destroy); LayerSurface *l = NULL, *tmp = NULL; - unsigned int i; + uint32_t i; /* m->layers[i] are intentionally not unlinked */ for (i = 0; i < LENGTH(m->layers); i++) { @@ -2518,14 +2517,14 @@ KeyboardGroup *createkeyboardgroup(void) { xkb_mod_index_t mod_index = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_NUM); if (mod_index != XKB_MOD_INVALID) - locked_mods |= (unsigned int)1 << mod_index; + locked_mods |= (uint32_t)1 << mod_index; } if (capslock) { xkb_mod_index_t mod_index = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_CAPS); if (mod_index != XKB_MOD_INVALID) - locked_mods |= (unsigned int)1 << mod_index; + locked_mods |= (uint32_t)1 << mod_index; } if (locked_mods) @@ -2649,7 +2648,7 @@ void createmon(struct wl_listener *listener, void *data) { * monitor) becomes available. */ struct wlr_output *wlr_output = data; const ConfigMonitorRule *r; - unsigned int i; + uint32_t i; int ji, jk; struct wlr_output_state state; Monitor *m = NULL; @@ -3310,7 +3309,7 @@ void inputdevice(struct wl_listener *listener, void *data) { /* This event is raised by the backend when a new input device becomes * available. */ struct wlr_input_device *device = data; - unsigned int caps; + uint32_t caps; switch (device->type) { case WLR_INPUT_DEVICE_KEYBOARD: @@ -3367,8 +3366,8 @@ bool is_keyboard_shortcut_inhibitor(struct wlr_surface *surface) { } int // 17 -keybinding(unsigned int state, bool locked, unsigned int mods, xkb_keysym_t sym, - unsigned int keycode) { +keybinding(uint32_t state, bool locked, uint32_t mods, xkb_keysym_t sym, + uint32_t keycode) { /* * Here we handle compositor keybindings. This is when the compositor is * processing keys, rather than passing them on to the client for its @@ -3432,10 +3431,10 @@ keybinding(unsigned int state, bool locked, unsigned int mods, xkb_keysym_t sym, bool keypressglobal(struct wlr_surface *last_surface, struct wlr_keyboard *keyboard, - struct wlr_keyboard_key_event *event, unsigned int mods, - xkb_keysym_t keysym, unsigned int keycode) { + struct wlr_keyboard_key_event *event, uint32_t mods, + xkb_keysym_t keysym, uint32_t keycode) { Client *c = NULL, *lastc = focustop(selmon); - unsigned int keycodes[32] = {0}; + uint32_t keycodes[32] = {0}; int reset = false; const char *appid = NULL; const char *title = NULL; @@ -3511,14 +3510,14 @@ void keypress(struct wl_listener *listener, void *data) { #endif /* Translate libinput keycode -> xkbcommon */ - unsigned int keycode = event->keycode + 8; + uint32_t keycode = event->keycode + 8; /* Get a list of keysyms based on the keymap for this keyboard */ const xkb_keysym_t *syms; int nsyms = xkb_state_key_get_syms(group->wlr_group->keyboard.xkb_state, keycode, &syms); int handled = 0; - unsigned int mods = wlr_keyboard_get_modifiers(&group->wlr_group->keyboard); + uint32_t mods = wlr_keyboard_get_modifiers(&group->wlr_group->keyboard); wlr_idle_notifier_v1_notify_activity(idle_notifier, seat); @@ -3915,7 +3914,7 @@ void motionabsolute(struct wl_listener *listener, void *data) { motionnotify(event->time_msec, &event->pointer->base, dx, dy, dx, dy); } -void motionnotify(unsigned int time, struct wlr_input_device *device, double dx, +void motionnotify(uint32_t time, struct wlr_input_device *device, double dx, double dy, double dx_unaccel, double dy_unaccel) { double sx = 0, sy = 0, sx_confined, sy_confined; Client *c = NULL, *w = NULL; @@ -4140,7 +4139,7 @@ void outputmgrtest(struct wl_listener *listener, void *data) { } void pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy, - unsigned int time) { + uint32_t time) { struct timespec now; if (surface != seat->pointer_state.focused_surface && sloppyfocus && time && @@ -4166,7 +4165,7 @@ void pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy, } // 修改printstatus函数,接受掩码参数 -void printstatus(unsigned int event_mask) { +void printstatus(uint32_t event_mask) { wl_signal_emit(&print_status_manager->print_status, (void *)(uintptr_t)event_mask); } @@ -4310,7 +4309,7 @@ void setborder_color(Client *c) { void exchange_two_client(Client *c1, Client *c2) { Monitor *tmp_mon = NULL; - unsigned int tmp_tags; + uint32_t tmp_tags; double master_inner_per = 0.0f; double master_mfact_per = 0.0f; double stack_innder_per = 0.0f; @@ -4747,9 +4746,9 @@ void reset_keyboard_layout(void) { } // Apply the new keymap - unsigned int depressed = keyboard->modifiers.depressed; - unsigned int latched = keyboard->modifiers.latched; - unsigned int locked = keyboard->modifiers.locked; + uint32_t depressed = keyboard->modifiers.depressed; + uint32_t latched = keyboard->modifiers.latched; + uint32_t locked = keyboard->modifiers.locked; wlr_keyboard_set_keymap(keyboard, new_keymap); @@ -4784,7 +4783,7 @@ cleanup_context: xkb_context_unref(context); } -void setmon(Client *c, Monitor *m, unsigned int newtags, bool focus) { +void setmon(Client *c, Monitor *m, uint32_t newtags, bool focus) { Monitor *oldmon = c->mon; if (oldmon == m) @@ -4854,7 +4853,7 @@ void setsel(struct wl_listener *listener, void *data) { } void show_hide_client(Client *c) { - unsigned int target = 1; + uint32_t target = 1; set_size_per(c->mon, c); target = get_tags_first_tag(c->oldtags); @@ -5269,7 +5268,7 @@ void tag_client(const Arg *arg, Client *target_client) { void overview(Monitor *m) { grid(m); } // 目标窗口有其他窗口和它同个tag就返回0 -unsigned int want_restore_fullscreen(Client *target_client) { +uint32_t want_restore_fullscreen(Client *target_client) { Client *c = NULL; wl_list_for_each(c, &clients, link) { if (c && c != target_client && c->tags == target_client->tags && @@ -5645,7 +5644,7 @@ urgent(struct wl_listener *listener, void *data) { void view_in_mon(const Arg *arg, bool want_animation, Monitor *m, bool changefocus) { - unsigned int i, tmptag; + uint32_t i, tmptag; if (!m || (arg->ui != (~0 & TAGMASK) && m->isoverview)) { return; From 88e868caf81624a18420697e492c2f8e20368b6e Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Tue, 2 Dec 2025 18:41:12 +0800 Subject: [PATCH 362/591] opt: simple printstatus signal --- src/mango.c | 26 +++++--------------------- 1 file changed, 5 insertions(+), 21 deletions(-) diff --git a/src/mango.c b/src/mango.c index 00430b18..68d651dd 100644 --- a/src/mango.c +++ b/src/mango.c @@ -226,9 +226,6 @@ typedef struct { uint32_t ui; uint32_t ui2; } Arg; -struct mango_print_status_manager { - struct wl_signal print_status; -}; typedef struct { uint32_t mod; @@ -878,6 +875,8 @@ struct Pertag { *ltidxs[LENGTH(tags) + 1]; /* matrix of tags and layouts indexes */ }; +static struct wl_signal mango_print_status; + static struct wl_listener print_status_listener = {.notify = handle_print_status}; static struct wl_listener cursor_axis = {.notify = axisnotify}; @@ -4166,8 +4165,7 @@ void pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy, // 修改printstatus函数,接受掩码参数 void printstatus(uint32_t event_mask) { - wl_signal_emit(&print_status_manager->print_status, - (void *)(uintptr_t)event_mask); + wl_signal_emit(&mango_print_status, (void *)(uintptr_t)event_mask); } void powermgrsetmode(struct wl_listener *listener, void *data) { @@ -4891,22 +4889,8 @@ void create_output(struct wlr_backend *backend, void *data) { #endif } -// 创建函数 -struct mango_print_status_manager *mango_print_status_manager_create() { - struct mango_print_status_manager *manager = calloc(1, sizeof(*manager)); - if (!manager) - return NULL; - - // 初始化 print_status 信号,不是 event_signal - wl_signal_init(&manager->print_status); - - return manager; -} - // 修改信号处理函数,接收掩码参数 void handle_print_status(struct wl_listener *listener, void *data) { - struct mango_print_status_manager *manager = - wl_container_of(listener, manager, print_status); uint32_t event_mask = (uintptr_t)data; // 如果传入的是NULL(旧代码)或0,使用默认的所有事件 @@ -5025,8 +5009,8 @@ void setup(void) { wlr_ext_data_control_manager_v1_create(dpy, 1); // 在 setup 函数中 - print_status_manager = mango_print_status_manager_create(); - wl_signal_add(&print_status_manager->print_status, &print_status_listener); + wl_signal_init(&mango_print_status); + wl_signal_add(&mango_print_status, &print_status_listener); /* Initializes the interface used to implement urgency hints */ activation = wlr_xdg_activation_v1_create(dpy); From bfcde37aba4e38c05efbf1d41a316defe1e8716a Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Wed, 3 Dec 2025 08:18:35 +0800 Subject: [PATCH 363/591] opt: optimize namedscratchpad when swallow --- src/fetch/client.h | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/fetch/client.h b/src/fetch/client.h index ca39ab9e..44a15e53 100644 --- a/src/fetch/client.h +++ b/src/fetch/client.h @@ -41,10 +41,21 @@ Client *get_client_by_id_or_title(const char *arg_id, const char *arg_title) { continue; } - if (!(appid = client_get_appid(c))) + if (c->swallowedby) { + appid = client_get_appid(c->swallowedby); + title = client_get_title(c->swallowedby); + } else { + appid = client_get_appid(c); + title = client_get_title(c); + } + + if (!appid) { appid = broken; - if (!(title = client_get_title(c))) + } + + if (!title) { title = broken; + } if (arg_id && strncmp(arg_id, "none", 4) == 0) arg_id = NULL; From 559de3c66b0a3e278dc5ea382e1526dcb9203574 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Wed, 3 Dec 2025 08:39:57 +0800 Subject: [PATCH 364/591] feat: support view multi tag in view dispatch --- src/config/parse_config.h | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/src/config/parse_config.h b/src/config/parse_config.h index 7c76c5e0..ec27e761 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -988,7 +988,31 @@ FuncType parse_func_name(char *func_name, Arg *arg, char *arg_value, (*arg).i = atoi(arg_value2); } else if (strcmp(func_name, "view") == 0) { func = bind_to_view; - (*arg).ui = 1 << (atoi(arg_value) - 1); + + u_int32_t mask = 0; + char *token; + char *arg_copy = strdup(arg_value); + + if (arg_copy != NULL) { + char *saveptr = NULL; + token = strtok_r(arg_copy, "|", &saveptr); + + while (token != NULL) { + int num = atoi(token); + if (num > 0 && num <= LENGTH(tags)) { + mask |= (1 << (num - 1)); + } + token = strtok_r(NULL, "|", &saveptr); + } + + free(arg_copy); + } + + if (mask) { + (*arg).ui = mask; + } else { + (*arg).ui = atoi(arg_value); + } (*arg).i = atoi(arg_value2); } else if (strcmp(func_name, "viewcrossmon") == 0) { func = viewcrossmon; From 068ec120dec15b6d0e13efb9294b9ffe513122d2 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Wed, 3 Dec 2025 09:29:14 +0800 Subject: [PATCH 365/591] fix: curtag overflow when view arg is -1 in view dispatch --- src/mango.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mango.c b/src/mango.c index 68d651dd..4542b4eb 100644 --- a/src/mango.c +++ b/src/mango.c @@ -5639,9 +5639,9 @@ void view_in_mon(const Arg *arg, bool want_animation, Monitor *m, } if (arg->ui == UINT32_MAX) { - m->pertag->prevtag = m->tagset[m->seltags]; + m->pertag->prevtag = get_tags_first_tag_num(m->tagset[m->seltags]); m->seltags ^= 1; /* toggle sel tagset */ - m->pertag->curtag = m->tagset[m->seltags]; + m->pertag->curtag = get_tags_first_tag_num(m->tagset[m->seltags]); goto toggleseltags; } From a2902a469bc0e7ad16f7a8418e60bdb5578cd046 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Wed, 3 Dec 2025 13:46:18 +0800 Subject: [PATCH 366/591] opt: optimize code struct --- src/mango.c | 25 ++++--------------------- 1 file changed, 4 insertions(+), 21 deletions(-) diff --git a/src/mango.c b/src/mango.c index 4542b4eb..f27b9021 100644 --- a/src/mango.c +++ b/src/mango.c @@ -4008,35 +4008,18 @@ void motionnotify(uint32_t time, struct wlr_input_device *device, double dx, if (!surface && !seat->drag && !cursor_hidden) wlr_cursor_set_xcursor(cursor, cursor_mgr, "default"); - if (c && c->mon && !c->animation.running && - (!(c->geom.x + c->geom.width > c->mon->m.x + c->mon->m.width || - c->geom.x < c->mon->m.x || - c->geom.y + c->geom.height > c->mon->m.y + c->mon->m.height || - c->geom.y < c->mon->m.y) || - !ISTILED(c))) { + if (c && c->mon && !c->animation.running && (INSIDEMON(c) || !ISTILED(c))) { scroller_focus_lock = 0; } should_lock = false; - if (!scroller_focus_lock || - !(c && c->mon && - (c->geom.x + c->geom.width > c->mon->m.x + c->mon->m.width || - c->geom.x < c->mon->m.x || - c->geom.y + c->geom.height > c->mon->m.y + c->mon->m.height || - c->geom.y < c->mon->m.y))) { - if (c && c->mon && is_scroller_layout(c->mon) && - (c->geom.x + c->geom.width > c->mon->m.x + c->mon->m.width || - c->geom.x < c->mon->m.x || - c->geom.y + c->geom.height > c->mon->m.y + c->mon->m.height || - c->geom.y < c->mon->m.y)) { + if (!scroller_focus_lock || !(c && c->mon && !INSIDEMON(c))) { + if (c && c->mon && is_scroller_layout(c->mon) && !INSIDEMON(c)) { should_lock = true; } if (!(!edge_scroller_pointer_focus && c && c->mon && - is_scroller_layout(c->mon) && - (c->geom.x < c->mon->m.x || c->geom.y < c->mon->m.y || - c->geom.x + c->geom.width > c->mon->m.x + c->mon->m.width || - c->geom.y + c->geom.height > c->mon->m.y + c->mon->m.height))) + is_scroller_layout(c->mon) && !INSIDEMON(c))) pointerfocus(c, surface, sx, sy, time); if (should_lock && c && c->mon && ISTILED(c) && c == c->mon->sel) { From 1ffdc1ef38c476cdeabc928d71b3343afbcea069 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Wed, 3 Dec 2025 16:12:05 +0800 Subject: [PATCH 367/591] feat: support -c option to specified config file --- src/config/parse_config.h | 14 ++++++++++++-- src/fetch/common.h | 7 ++++++- src/mango.c | 5 ++++- 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/src/config/parse_config.h b/src/config/parse_config.h index ec27e761..45c4993b 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -2307,7 +2308,14 @@ void parse_config_file(Config *config, const char *file_path) { // Relative path const char *mangoconfig = getenv("MANGOCONFIG"); - if (mangoconfig && mangoconfig[0] != '\0') { + + if (cli_config_path) { + char *config_path = strdup(cli_config_path); + char *config_dir = dirname(config_path); + snprintf(full_path, sizeof(full_path), "%s/%s", config_dir, + file_path + 1); + free(config_path); + } else if (mangoconfig && mangoconfig[0] != '\0') { snprintf(full_path, sizeof(full_path), "%s/%s", mangoconfig, file_path + 1); } else { @@ -3040,7 +3048,9 @@ void parse_config(void) { const char *mangoconfig = getenv("MANGOCONFIG"); // 如果 MANGOCONFIG 环境变量不存在或为空,则使用 HOME 环境变量 - if (!mangoconfig || mangoconfig[0] == '\0') { + if (cli_config_path) { + snprintf(filename, sizeof(filename), "%s", cli_config_path); + } else if (!mangoconfig || mangoconfig[0] == '\0') { // 获取当前用户家目录 const char *homedir = getenv("HOME"); if (!homedir) { diff --git a/src/fetch/common.h b/src/fetch/common.h index c86a3fef..86d85495 100644 --- a/src/fetch/common.h +++ b/src/fetch/common.h @@ -29,7 +29,12 @@ int isdescprocess(pid_t p, pid_t c) { char *get_autostart_path(char *autostart_path, uint32_t buf_size) { const char *mangoconfig = getenv("MANGOCONFIG"); - if (mangoconfig && mangoconfig[0] != '\0') { + if (cli_config_path) { + char *config_path = strdup(cli_config_path); + char *config_dir = dirname(config_path); + snprintf(autostart_path, buf_size, "%s/autostart.sh", config_dir); + free(config_path); + } else if (mangoconfig && mangoconfig[0] != '\0') { snprintf(autostart_path, buf_size, "%s/autostart.sh", mangoconfig); } else { const char *homedir = getenv("HOME"); diff --git a/src/mango.c b/src/mango.c index f27b9021..25e19ca3 100644 --- a/src/mango.c +++ b/src/mango.c @@ -852,6 +852,7 @@ struct dvec2 *baked_points_focus; static struct wl_event_source *hide_source; static bool cursor_hidden = false; static bool tag_combo = false; +static const char *cli_config_path = NULL; static KeyMode keymode = { .mode = {'d', 'e', 'f', 'a', 'u', 'l', 't', '\0'}, .isdefault = true, @@ -5908,13 +5909,15 @@ int main(int argc, char *argv[]) { char *startup_cmd = NULL; int c; - while ((c = getopt(argc, argv, "s:hdv")) != -1) { + while ((c = getopt(argc, argv, "s:c:hdv")) != -1) { if (c == 's') startup_cmd = optarg; else if (c == 'd') log_level = WLR_DEBUG; else if (c == 'v') die("mango " VERSION); + else if (c == 'c') + cli_config_path = optarg; else goto usage; } From 5c314be8c634524517aea8911ba9a84419c2e824 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Wed, 3 Dec 2025 16:20:47 +0800 Subject: [PATCH 368/591] break change: remove autostar.sh and MANGOCONFIG env --- src/config/parse_config.h | 14 +------------- src/fetch/common.h | 23 ----------------------- src/mango.c | 6 +----- 3 files changed, 2 insertions(+), 41 deletions(-) diff --git a/src/config/parse_config.h b/src/config/parse_config.h index 45c4993b..6db5d85b 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -2307,17 +2307,12 @@ void parse_config_file(Config *config, const char *file_path) { if (file_path[0] == '.' && file_path[1] == '/') { // Relative path - const char *mangoconfig = getenv("MANGOCONFIG"); - if (cli_config_path) { char *config_path = strdup(cli_config_path); char *config_dir = dirname(config_path); snprintf(full_path, sizeof(full_path), "%s/%s", config_dir, file_path + 1); free(config_path); - } else if (mangoconfig && mangoconfig[0] != '\0') { - snprintf(full_path, sizeof(full_path), "%s/%s", mangoconfig, - file_path + 1); } else { const char *home = getenv("HOME"); if (!home) { @@ -3044,13 +3039,9 @@ void parse_config(void) { create_config_keymap(); - // 获取 MANGOCONFIG 环境变量 - const char *mangoconfig = getenv("MANGOCONFIG"); - - // 如果 MANGOCONFIG 环境变量不存在或为空,则使用 HOME 环境变量 if (cli_config_path) { snprintf(filename, sizeof(filename), "%s", cli_config_path); - } else if (!mangoconfig || mangoconfig[0] == '\0') { + } else { // 获取当前用户家目录 const char *homedir = getenv("HOME"); if (!homedir) { @@ -3067,9 +3058,6 @@ void parse_config(void) { snprintf(filename, sizeof(filename), "%s/mango/config.conf", SYSCONFDIR); } - } else { - // 使用 MANGOCONFIG 环境变量作为配置文件夹路径 - snprintf(filename, sizeof(filename), "%s/config.conf", mangoconfig); } set_value_default(); diff --git a/src/fetch/common.h b/src/fetch/common.h index 86d85495..c96ee31b 100644 --- a/src/fetch/common.h +++ b/src/fetch/common.h @@ -26,29 +26,6 @@ int isdescprocess(pid_t p, pid_t c) { return (int)c; } -char *get_autostart_path(char *autostart_path, uint32_t buf_size) { - const char *mangoconfig = getenv("MANGOCONFIG"); - - if (cli_config_path) { - char *config_path = strdup(cli_config_path); - char *config_dir = dirname(config_path); - snprintf(autostart_path, buf_size, "%s/autostart.sh", config_dir); - free(config_path); - } else if (mangoconfig && mangoconfig[0] != '\0') { - snprintf(autostart_path, buf_size, "%s/autostart.sh", mangoconfig); - } else { - const char *homedir = getenv("HOME"); - if (!homedir) { - fprintf(stderr, "Error: HOME environment variable not set.\n"); - return NULL; - } - snprintf(autostart_path, buf_size, "%s/.config/mango/autostart.sh", - homedir); - } - - return autostart_path; -} - void get_layout_abbr(char *abbr, const char *full_name) { // 清空输出缓冲区 abbr[0] = '\0'; diff --git a/src/mango.c b/src/mango.c index 25e19ca3..3282759c 100644 --- a/src/mango.c +++ b/src/mango.c @@ -536,7 +536,6 @@ arrange(Monitor *m, static void arrangelayer(Monitor *m, struct wl_list *list, struct wlr_box *usable_area, int exclusive); static void arrangelayers(Monitor *m); -static char *get_autostart_path(char *, uint32_t); // 自启动命令执行 static void handle_print_status(struct wl_listener *listener, void *data); static void axisnotify(struct wl_listener *listener, void *data); // 滚轮事件处理 @@ -4369,7 +4368,6 @@ run(char *startup_cmd) { set_env(); - char autostart_temp_path[1024]; /* Add a Unix socket to the Wayland display. */ const char *socket = wl_display_add_socket_auto(dpy); if (!socket) @@ -4383,9 +4381,7 @@ run(char *startup_cmd) { /* Now that the socket exists and the backend is started, run the * startup command */ - if (!startup_cmd) - startup_cmd = get_autostart_path(autostart_temp_path, - sizeof(autostart_temp_path)); + if (startup_cmd) { int piperw[2]; if (pipe(piperw) < 0) From e965264f3bdd214d619f92d77aa0f9db54a4ff91 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Wed, 3 Dec 2025 17:22:19 +0800 Subject: [PATCH 369/591] fix: dont use evenmask --- src/config/parse_config.h | 2 +- src/dispatch/bind_define.h | 16 +-- src/ext-protocol/dwl-ipc.h | 206 ++++++++++++------------------------- src/mango.c | 46 +++------ 4 files changed, 92 insertions(+), 178 deletions(-) diff --git a/src/config/parse_config.h b/src/config/parse_config.h index 6db5d85b..c94bf717 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -3277,6 +3277,6 @@ void reset_option(void) { int reload_config(const Arg *arg) { parse_config(); reset_option(); - printstatus(PRINT_ALL); + printstatus(); return 0; } diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index 1dc29daf..4850889b 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -503,7 +503,7 @@ int setlayout(const Arg *arg) { selmon->pertag->ltidxs[selmon->pertag->curtag] = &layouts[jk]; clear_fullscreen_and_maximized_state(selmon); arrange(selmon, false); - printstatus(PRINT_ALL); + printstatus(); return 0; } } @@ -517,7 +517,7 @@ int setkeymode(const Arg *arg) { } else { keymode.isdefault = false; } - printstatus(PRINT_KEYMODE); + printstatus(); return 1; } @@ -866,7 +866,7 @@ int switch_keyboard_layout(const Arg *arg) { wlr_seat_keyboard_notify_modifiers(seat, &tkb->modifiers); } - printstatus(PRINT_KB_LAYOUT); + printstatus(); return 0; } @@ -907,7 +907,7 @@ int switch_layout(const Arg *arg) { } clear_fullscreen_and_maximized_state(selmon); arrange(selmon, false); - printstatus(PRINT_ALL); + printstatus(); return 0; } @@ -918,7 +918,7 @@ int switch_layout(const Arg *arg) { jk == LENGTH(layouts) - 1 ? &layouts[0] : &layouts[jk + 1]; clear_fullscreen_and_maximized_state(selmon); arrange(selmon, false); - printstatus(PRINT_ALL); + printstatus(); return 0; } } @@ -1260,7 +1260,7 @@ int toggletag(const Arg *arg) { focusclient(focustop(selmon), 1); arrange(selmon, false); } - printstatus(PRINT_ALL); + printstatus(); return 0; } @@ -1278,7 +1278,7 @@ int toggleview(const Arg *arg) { focusclient(focustop(selmon), 1); arrange(selmon, false); } - printstatus(PRINT_ALL); + printstatus(); return 0; } @@ -1396,7 +1396,7 @@ int comboview(const Arg *arg) { view(&(Arg){.ui = newtags}, false); } - printstatus(PRINT_ALL); + printstatus(); return 0; } diff --git a/src/ext-protocol/dwl-ipc.h b/src/ext-protocol/dwl-ipc.h index 649c5f3a..eda3f49f 100644 --- a/src/ext-protocol/dwl-ipc.h +++ b/src/ext-protocol/dwl-ipc.h @@ -9,9 +9,8 @@ static void dwl_ipc_manager_get_output(struct wl_client *client, 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, uint32_t event_mask); -static void dwl_ipc_output_printstatus_to(DwlIpcOutput *ipc_output, - uint32_t event_mask); +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, @@ -86,7 +85,7 @@ void dwl_ipc_manager_get_output(struct wl_client *client, 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, PRINT_ALL); + dwl_ipc_output_printstatus_to(ipc_output); } void dwl_ipc_manager_release(struct wl_client *client, @@ -101,15 +100,14 @@ static void dwl_ipc_output_destroy(struct wl_resource *resource) { } // 修改IPC输出函数,接受掩码参数 -void dwl_ipc_output_printstatus(Monitor *monitor, uint32_t event_mask) { +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, event_mask); + dwl_ipc_output_printstatus_to(ipc_output); } // 修改主IPC输出函数,根据掩码发送相应事件 -void dwl_ipc_output_printstatus_to(DwlIpcOutput *ipc_output, - uint32_t event_mask) { +void dwl_ipc_output_printstatus_to(DwlIpcOutput *ipc_output) { Monitor *monitor = ipc_output->mon; Client *c = NULL, *focused = NULL; struct wlr_keyboard *keyboard; @@ -117,175 +115,103 @@ void dwl_ipc_output_printstatus_to(DwlIpcOutput *ipc_output, int 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); - // 只在需要时才获取这些数据 - if (event_mask & (PRINT_ACTIVE | PRINT_TAG | PRINT_TITLE | PRINT_APPID | - PRINT_FULLSCREEN | PRINT_FLOATING | PRINT_X | PRINT_Y | - PRINT_WIDTH | PRINT_HEIGHT)) { - focused = focustop(monitor); - } - - // 发送活动状态 - if (event_mask & PRINT_ACTIVE) { - zdwl_ipc_output_v2_send_active(ipc_output->resource, monitor == selmon); - } - - // 发送标签状态 - if (event_mask & PRINT_TAG) { - 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; - - if (focused) { - 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); + 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); } - // 只在需要时才获取标题和应用ID - if (event_mask & (PRINT_TITLE | PRINT_APPID)) { - title = focused ? client_get_title(focused) : ""; - appid = focused ? client_get_appid(focused) : ""; + 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; } - // 获取布局符号 - if (event_mask & PRINT_LAYOUT_SYMBOL) { - 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)); - // 发送布局索引 - if (event_mask & PRINT_LAYOUT) { - zdwl_ipc_output_v2_send_layout( - ipc_output->resource, - monitor->pertag->ltidxs[monitor->pertag->curtag] - layouts); - } - - // 发送标题 - if (event_mask & PRINT_TITLE) { - zdwl_ipc_output_v2_send_title(ipc_output->resource, - title ? title : broken); - } - - // 发送应用ID - if (event_mask & PRINT_APPID) { - zdwl_ipc_output_v2_send_appid(ipc_output->resource, - appid ? appid : broken); - } - - // 发送布局符号 - if (event_mask & PRINT_LAYOUT_SYMBOL) { - zdwl_ipc_output_v2_send_layout_symbol(ipc_output->resource, symbol); - } - - // 发送全屏状态 - if ((event_mask & PRINT_FULLSCREEN) && - wl_resource_get_version(ipc_output->resource) >= - ZDWL_IPC_OUTPUT_V2_FULLSCREEN_SINCE_VERSION) { + 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 ((event_mask & PRINT_FLOATING) && - wl_resource_get_version(ipc_output->resource) >= - ZDWL_IPC_OUTPUT_V2_FLOATING_SINCE_VERSION) { + 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); } - - // 发送X坐标 - if ((event_mask & PRINT_X) && - wl_resource_get_version(ipc_output->resource) >= - ZDWL_IPC_OUTPUT_V2_X_SINCE_VERSION) { + 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); } - - // 发送Y坐标 - if ((event_mask & PRINT_Y) && - wl_resource_get_version(ipc_output->resource) >= - ZDWL_IPC_OUTPUT_V2_Y_SINCE_VERSION) { + 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 ((event_mask & PRINT_WIDTH) && - wl_resource_get_version(ipc_output->resource) >= - ZDWL_IPC_OUTPUT_V2_WIDTH_SINCE_VERSION) { + 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 ((event_mask & PRINT_HEIGHT) && - wl_resource_get_version(ipc_output->resource) >= - ZDWL_IPC_OUTPUT_V2_HEIGHT_SINCE_VERSION) { + 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 ((event_mask & PRINT_LAST_LAYER) && - wl_resource_get_version(ipc_output->resource) >= - ZDWL_IPC_OUTPUT_V2_LAST_LAYER_SINCE_VERSION) { + 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_surface_ws_name); } - // 获取键盘布局(只在需要时) - if (event_mask & PRINT_KB_LAYOUT) { - 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)); - } - - // 发送键盘布局 - if ((event_mask & PRINT_KB_LAYOUT) && - wl_resource_get_version(ipc_output->resource) >= - ZDWL_IPC_OUTPUT_V2_KB_LAYOUT_SINCE_VERSION) { + 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 ((event_mask & PRINT_KEYMODE) && - wl_resource_get_version(ipc_output->resource) >= - ZDWL_IPC_OUTPUT_V2_KEYMODE_SINCE_VERSION) { + 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 ((event_mask & PRINT_SCALEFACTOR) && - wl_resource_get_version(ipc_output->resource) >= - ZDWL_IPC_OUTPUT_V2_SCALEFACTOR_SINCE_VERSION) { + 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); } - // 发送帧结束标记 - if (event_mask & PRINT_FRAME) { - zdwl_ipc_output_v2_send_frame(ipc_output->resource); - } + zdwl_ipc_output_v2_send_frame(ipc_output->resource); } void dwl_ipc_output_set_client_tags(struct wl_client *client, @@ -313,7 +239,7 @@ void dwl_ipc_output_set_client_tags(struct wl_client *client, if (selmon == monitor) focusclient(focustop(monitor), 1); arrange(selmon, false); - printstatus(PRINT_ALL); + printstatus(); } void dwl_ipc_output_set_layout(struct wl_client *client, @@ -332,7 +258,7 @@ void dwl_ipc_output_set_layout(struct wl_client *client, monitor->pertag->ltidxs[monitor->pertag->curtag] = &layouts[index]; clear_fullscreen_and_maximized_state(monitor); arrange(monitor, false); - printstatus(PRINT_ALL); + printstatus(); } void dwl_ipc_output_set_tags(struct wl_client *client, diff --git a/src/mango.c b/src/mango.c index 3282759c..e051cffe 100644 --- a/src/mango.c +++ b/src/mango.c @@ -629,7 +629,7 @@ static void outputmgrapplyortest(struct wlr_output_configuration_v1 *config, static void outputmgrtest(struct wl_listener *listener, void *data); static void pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy, uint32_t time); -static void printstatus(uint32_t event_mask); +static void printstatus(void); static void quitsignal(int signo); static void powermgrsetmode(struct wl_listener *listener, void *data); static void rendermon(struct wl_listener *listener, void *data); @@ -2168,7 +2168,7 @@ void closemon(Monitor *m) { } if (selmon) { focusclient(focustop(selmon), 1); - printstatus(PRINT_ALL); + printstatus(); } } @@ -2802,7 +2802,7 @@ void createmon(struct wl_listener *listener, void *data) { add_workspace_by_tag(i, m); } - printstatus(PRINT_ALL); + printstatus(); } void // fix for 0.5 @@ -3258,7 +3258,7 @@ void focusclient(Client *c, int lift) { client_activate_surface(old_keyboard_focus_surface, 0); } } - printstatus(PRINT_ALL); + printstatus(); if (!c) { @@ -3808,7 +3808,7 @@ mapnotify(struct wl_listener *listener, void *data) { // make sure the animation is open type c->is_pending_open_animation = true; resize(c, c->geom, 0); - printstatus(PRINT_ALL); + printstatus(); } void maximizenotify(struct wl_listener *listener, void *data) { @@ -4147,9 +4147,7 @@ void pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy, } // 修改printstatus函数,接受掩码参数 -void printstatus(uint32_t event_mask) { - wl_signal_emit(&mango_print_status, (void *)(uintptr_t)event_mask); -} +void printstatus(void) { wl_signal_emit(&mango_print_status, NULL); } void powermgrsetmode(struct wl_listener *listener, void *data) { struct wlr_output_power_v1_set_mode_event *event = data; @@ -4406,7 +4404,7 @@ run(char *startup_cmd) { if (fd_set_nonblock(STDOUT_FILENO) < 0) close(STDOUT_FILENO); - printstatus(PRINT_ALL); + printstatus(); /* At this point the outputs are initialized, choose initial selmon * based on cursor position, and set default cursor image */ @@ -4541,7 +4539,7 @@ setfloating(Client *c, int floating) { arrange(c->mon, false); setborder_color(c); - printstatus(PRINT_ALL); + printstatus(); } void reset_maximizescreen_size(Client *c) { @@ -4872,24 +4870,14 @@ void create_output(struct wlr_backend *backend, void *data) { // 修改信号处理函数,接收掩码参数 void handle_print_status(struct wl_listener *listener, void *data) { - uint32_t event_mask = (uintptr_t)data; - // 如果传入的是NULL(旧代码)或0,使用默认的所有事件 - if (!event_mask) { - event_mask = PRINT_ALL; - } - Monitor *m = NULL; wl_list_for_each(m, &mons, link) { if (!m->wlr_output->enabled) { continue; } - // 更新workspace状态(根据掩码决定是否更新) - if (event_mask & PRINT_TAG || event_mask & PRINT_ACTIVE) { - dwl_ext_workspace_printstatus(m); - } + dwl_ext_workspace_printstatus(m); - // 更新IPC输出状态(传入掩码) - dwl_ipc_output_printstatus(m, event_mask); + dwl_ipc_output_printstatus(m); } } @@ -5226,7 +5214,7 @@ void tag_client(const Arg *arg, Client *target_client) { } focusclient(target_client, 1); - printstatus(PRINT_ALL); + printstatus(); } void overview(Monitor *m) { grid(m); } @@ -5434,7 +5422,7 @@ void unmapnotify(struct wl_listener *listener, void *data) { } wlr_scene_node_destroy(&c->scene->node); - printstatus(PRINT_ALL); + printstatus(); motionnotify(0, NULL, 0, 0, 0, 0); } @@ -5582,7 +5570,7 @@ void updatetitle(struct wl_listener *listener, void *data) { if (title && c->foreign_toplevel) wlr_foreign_toplevel_handle_v1_set_title(c->foreign_toplevel, title); if (c == focustop(c->mon)) - printstatus(PRINT_TITLE); + printstatus(); } void // 17 fix to 0.5 @@ -5602,7 +5590,7 @@ urgent(struct wl_listener *listener, void *data) { c->isurgent = 1; if (client_surface(c)->mapped) setborder_color(c); - printstatus(PRINT_ALL); + printstatus(); } } @@ -5657,7 +5645,7 @@ toggleseltags: if (changefocus) focusclient(focustop(m), 1); arrange(m, want_animation); - printstatus(PRINT_ALL); + printstatus(); } void view(const Arg *arg, bool want_animation) { @@ -5800,7 +5788,7 @@ void activatex11(struct wl_listener *listener, void *data) { arrange(c->mon, false); } - printstatus(PRINT_ALL); + printstatus(); } void configurex11(struct wl_listener *listener, void *data) { @@ -5872,7 +5860,7 @@ void sethints(struct wl_listener *listener, void *data) { return; c->isurgent = xcb_icccm_wm_hints_get_urgency(c->surface.xwayland->hints); - printstatus(PRINT_ALL); + printstatus(); if (c->isurgent && surface && surface->mapped) setborder_color(c); From 42771592198992ca48253f50f1012ec723dfe74e Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Wed, 3 Dec 2025 17:32:53 +0800 Subject: [PATCH 370/591] opt: add some usage message --- src/mango.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mango.c b/src/mango.c index e051cffe..6c67d70c 100644 --- a/src/mango.c +++ b/src/mango.c @@ -5919,5 +5919,5 @@ int main(int argc, char *argv[]) { return EXIT_SUCCESS; usage: - die("Usage: %s [-v] [-d] [-s startup command]", argv[0]); + die("Usage: %s [-v] [-d] [-c config file] [-s startup command]", argv[0]); } From 02377e2867845e2d450d346253b10b61c2d02f5e Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Wed, 3 Dec 2025 17:43:19 +0800 Subject: [PATCH 371/591] fix: change u_int32_t to uint32_t --- src/config/parse_config.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/config/parse_config.h b/src/config/parse_config.h index c94bf717..d845e2ab 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -990,7 +990,7 @@ FuncType parse_func_name(char *func_name, Arg *arg, char *arg_value, } else if (strcmp(func_name, "view") == 0) { func = bind_to_view; - u_int32_t mask = 0; + uint32_t mask = 0; char *token; char *arg_copy = strdup(arg_value); From 2258574e25f4612affdc92621c8aef70e5c134e1 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Wed, 3 Dec 2025 18:15:56 +0800 Subject: [PATCH 372/591] bump version to 0.10.7 --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index b02e0fd1..460328ef 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('mango', ['c', 'cpp'], - version : '0.10.6', + version : '0.10.7', ) subdir('protocols') From 44c271ee529c33b3312e7ec3dd47e77ced1eb64e Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Wed, 3 Dec 2025 21:07:45 +0800 Subject: [PATCH 373/591] opt: optimize border color set when change monitor --- src/dispatch/bind_define.h | 6 +----- src/mango.c | 8 ++++++++ 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index 4850889b..004147fa 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -171,7 +171,7 @@ int toggle_trackpad_enable(const Arg *arg) { } int focusmon(const Arg *arg) { - Client *c = NULL, *old_selmon_sel = NULL; + Client *c = NULL; Monitor *m = NULL; if (arg->i != UNDIR) { @@ -192,7 +192,6 @@ int focusmon(const Arg *arg) { if (!m || !m->wlr_output->enabled || m == selmon) return 0; - old_selmon_sel = selmon->sel; selmon = m; if (warpcursor) { warp_cursor_to_selmon(selmon); @@ -205,9 +204,6 @@ int focusmon(const Arg *arg) { } else focusclient(c, 1); - if (old_selmon_sel) { - client_set_unfocused_opacity_animation(old_selmon_sel); - } return 0; } diff --git a/src/mango.c b/src/mango.c index 6c67d70c..47e785a8 100644 --- a/src/mango.c +++ b/src/mango.c @@ -3166,6 +3166,7 @@ void destroykeyboardgroup(struct wl_listener *listener, void *data) { void focusclient(Client *c, int lift) { Client *last_focus_client = NULL; + Monitor *um = NULL; struct wlr_surface *old_keyboard_focus_surface = seat->keyboard_state.focused_surface; @@ -3211,6 +3212,13 @@ void focusclient(Client *c, int lift) { client_set_unfocused_opacity_animation(last_focus_client); } + wl_list_for_each(um, &mons, link) { + if (um->wlr_output->enabled && um != selmon && um->sel && + !um->sel->iskilling) { + client_set_unfocused_opacity_animation(um->sel); + } + } + client_set_focused_opacity_animation(c); // decide whether need to re-arrange From 11b425faad2e9650628ccab8be03bc389a2082f0 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Wed, 3 Dec 2025 22:06:10 +0800 Subject: [PATCH 374/591] opt: avoid unnecessary focus animations --- src/mango.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/mango.c b/src/mango.c index 47e785a8..0e52883b 100644 --- a/src/mango.c +++ b/src/mango.c @@ -402,6 +402,7 @@ struct Client { int force_tearing; int allow_shortcuts_inhibit; float scroller_proportion_single; + bool isfocusing; }; typedef struct { @@ -3206,15 +3207,18 @@ void focusclient(Client *c, int lift) { selmon = c->mon; selmon->prevsel = selmon->sel; selmon->sel = c; + c->isfocusing = true; if (last_focus_client && !last_focus_client->iskilling && last_focus_client != c) { + last_focus_client->isfocusing = false; client_set_unfocused_opacity_animation(last_focus_client); } wl_list_for_each(um, &mons, link) { if (um->wlr_output->enabled && um != selmon && um->sel && - !um->sel->iskilling) { + !um->sel->iskilling && um->sel->isfocusing) { + um->sel->isfocusing = false; client_set_unfocused_opacity_animation(um->sel); } } @@ -3663,6 +3667,7 @@ static void iter_xdg_scene_buffers(struct wlr_scene_buffer *buffer, int sx, } void init_client_properties(Client *c) { + c->isfocusing = false; c->ismaximizescreen = 0; c->isfullscreen = 0; c->need_float_size_reduce = 0; From 1b739a1c7e19116b81dcaf275b08d12655dcd66f Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Wed, 3 Dec 2025 23:19:58 +0800 Subject: [PATCH 375/591] update readme --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 5701178b..af1d2977 100644 --- a/README.md +++ b/README.md @@ -71,6 +71,8 @@ https://github.com/user-attachments/assets/014c893f-115c-4ae9-8342-f9ae3e9a0df0 - hwdata - seatd - pcre2 +- xorg-xwayland +- libxcb ## Arch Linux The package is in the Arch User Repository and is availble for manual download [here](https://aur.archlinux.org/packages/mangowc-git) or through a AUR helper like yay: From e602605fa4b9c145f7275b1bca149967bdc472de Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Thu, 4 Dec 2025 09:58:16 +0800 Subject: [PATCH 376/591] opt: optimize focus change when change monitor --- src/dispatch/bind_define.h | 1 + src/mango.c | 17 +++++++++-------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index 004147fa..c167915c 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -201,6 +201,7 @@ int focusmon(const Arg *arg) { selmon->sel = NULL; wlr_seat_pointer_notify_clear_focus(seat); wlr_seat_keyboard_notify_clear_focus(seat); + focusclient(NULL, 0); } else focusclient(c, 1); diff --git a/src/mango.c b/src/mango.c index 0e52883b..8811c849 100644 --- a/src/mango.c +++ b/src/mango.c @@ -3215,14 +3215,6 @@ void focusclient(Client *c, int lift) { client_set_unfocused_opacity_animation(last_focus_client); } - wl_list_for_each(um, &mons, link) { - if (um->wlr_output->enabled && um != selmon && um->sel && - !um->sel->iskilling && um->sel->isfocusing) { - um->sel->isfocusing = false; - client_set_unfocused_opacity_animation(um->sel); - } - } - client_set_focused_opacity_animation(c); // decide whether need to re-arrange @@ -3242,6 +3234,15 @@ void focusclient(Client *c, int lift) { c->isurgent = 0; } + // update other monitor focus disappear + wl_list_for_each(um, &mons, link) { + if (um->wlr_output->enabled && um != selmon && um->sel && + !um->sel->iskilling && um->sel->isfocusing) { + um->sel->isfocusing = false; + client_set_unfocused_opacity_animation(um->sel); + } + } + if (c && !c->iskilling && c->foreign_toplevel) wlr_foreign_toplevel_handle_v1_set_activated(c->foreign_toplevel, true); From 0e59209d2b2911f4d1cc850e7a94cd386e8b4508 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Thu, 4 Dec 2025 17:39:13 +0800 Subject: [PATCH 377/591] opt: focusdir use same monitor client first --- src/fetch/client.h | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/src/fetch/client.h b/src/fetch/client.h index 44a15e53..7b44344f 100644 --- a/src/fetch/client.h +++ b/src/fetch/client.h @@ -193,7 +193,9 @@ Client *find_client_by_direction(Client *tc, const Arg *arg, bool findfloating, int sel_x = tc->geom.x; int sel_y = tc->geom.y; long long int distance = LLONG_MAX; + long long int same_monitor_distance = LLONG_MAX; Client *tempFocusClients = NULL; + Client *tempSameMonitorFocusClients = NULL; switch (arg->i) { case UP: @@ -224,6 +226,11 @@ Client *find_client_by_direction(Client *tc, const Arg *arg, bool findfloating, distance = tmp_distance; tempFocusClients = tempClients[_i]; } + if (tempClients[_i]->mon == tc->mon && + tmp_distance < same_monitor_distance) { + same_monitor_distance = tmp_distance; + tempSameMonitorFocusClients = tempClients[_i]; + } } } } @@ -256,6 +263,11 @@ Client *find_client_by_direction(Client *tc, const Arg *arg, bool findfloating, distance = tmp_distance; tempFocusClients = tempClients[_i]; } + if (tempClients[_i]->mon == tc->mon && + tmp_distance < same_monitor_distance) { + same_monitor_distance = tmp_distance; + tempSameMonitorFocusClients = tempClients[_i]; + } } } } @@ -288,6 +300,11 @@ Client *find_client_by_direction(Client *tc, const Arg *arg, bool findfloating, distance = tmp_distance; tempFocusClients = tempClients[_i]; } + if (tempClients[_i]->mon == tc->mon && + tmp_distance < same_monitor_distance) { + same_monitor_distance = tmp_distance; + tempSameMonitorFocusClients = tempClients[_i]; + } } } } @@ -320,6 +337,11 @@ Client *find_client_by_direction(Client *tc, const Arg *arg, bool findfloating, distance = tmp_distance; tempFocusClients = tempClients[_i]; } + if (tempClients[_i]->mon == tc->mon && + tmp_distance < same_monitor_distance) { + same_monitor_distance = tmp_distance; + tempSameMonitorFocusClients = tempClients[_i]; + } } } } @@ -327,7 +349,11 @@ Client *find_client_by_direction(Client *tc, const Arg *arg, bool findfloating, } free(tempClients); // 释放内存 - return tempFocusClients; + if(tempSameMonitorFocusClients) { + return tempSameMonitorFocusClients; + } else { + return tempFocusClients; + } } Client *direction_select(const Arg *arg) { From 6086507c5ae355d63273ed4f3714158469b31ea6 Mon Sep 17 00:00:00 2001 From: Owen-sz Date: Sat, 6 Dec 2025 14:50:54 -0600 Subject: [PATCH 378/591] doc: add Fedora install instructions Signed-off-by: Owen-sz --- README.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index af1d2977..b2bd4964 100644 --- a/README.md +++ b/README.md @@ -82,7 +82,6 @@ yay -S mangowc-git ``` ## Gentoo Linux - The package is in the community-maintained repository called GURU. First, add GURU repository: @@ -100,6 +99,16 @@ Finally, install the package: emerge --ask --verbose gui-wm/mangowc ``` +## Fedora Linux +The package is in the third-party Terra repository. +First, add the [Terra Repository](https://terra.fyralabs.com/). + +Then, install the package: + +```bash +dnf install mangowc +``` + ## Other ```bash From f3f321579173805051333057cf65439c0e7972f6 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sun, 7 Dec 2025 21:12:45 +0800 Subject: [PATCH 379/591] fix: nmaster num caculate error in master layout --- src/fetch/client.h | 2 +- src/layout/arrange.h | 18 +++++++----------- src/layout/horizontal.h | 4 ++++ src/layout/vertical.h | 1 + 4 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/fetch/client.h b/src/fetch/client.h index 7b44344f..0bc84881 100644 --- a/src/fetch/client.h +++ b/src/fetch/client.h @@ -349,7 +349,7 @@ Client *find_client_by_direction(Client *tc, const Arg *arg, bool findfloating, } free(tempClients); // 释放内存 - if(tempSameMonitorFocusClients) { + if (tempSameMonitorFocusClients) { return tempSameMonitorFocusClients; } else { return tempFocusClients; diff --git a/src/layout/arrange.h b/src/layout/arrange.h index 3fb25a46..7a1d6205 100644 --- a/src/layout/arrange.h +++ b/src/layout/arrange.h @@ -516,17 +516,15 @@ void reset_size_per_mon(Monitor *m, int tile_cilent_num, wl_list_for_each(c, &clients, link) { if (VISIBLEON(c, m) && ISTILED(c)) { - - if (total_master_inner_percent <= 0.0) - return; - if (i < m->pertag->nmasters[m->pertag->curtag]) { + if (total_master_inner_percent > 0.0 && i < nmasters) { c->ismaster = true; c->stack_innder_per = stack_num ? 1.0f / stack_num : 1.0f; c->master_inner_per = c->master_inner_per / total_master_inner_percent; } else { c->ismaster = false; - c->master_inner_per = 1.0f / master_num; + c->master_inner_per = + master_num > 0 ? 1.0f / master_num : 1.0f; c->stack_innder_per = total_stack_hight_percent ? c->stack_innder_per / total_stack_hight_percent @@ -538,10 +536,7 @@ void reset_size_per_mon(Monitor *m, int tile_cilent_num, } else { wl_list_for_each(c, &clients, link) { if (VISIBLEON(c, m) && ISTILED(c)) { - - if (total_master_inner_percent <= 0.0) - return; - if (i < m->pertag->nmasters[m->pertag->curtag]) { + if (total_master_inner_percent > 0.0 && i < nmasters) { c->ismaster = true; if ((stack_index % 2) ^ (tile_cilent_num % 2 == 0)) { c->stack_innder_per = @@ -558,7 +553,8 @@ void reset_size_per_mon(Monitor *m, int tile_cilent_num, stack_index = i - nmasters; c->ismaster = false; - c->master_inner_per = 1.0f / master_num; + c->master_inner_per = + master_num > 0 ? 1.0f / master_num : 1.0f; if ((stack_index % 2) ^ (tile_cilent_num % 2 == 0)) { c->stack_innder_per = total_right_stack_hight_percent @@ -637,7 +633,7 @@ arrange(Monitor *m, bool want_animation) { if (VISIBLEON(c, m)) { if (ISTILED(c)) { - if (i < m->pertag->nmasters[m->pertag->curtag]) { + if (i < nmasters) { master_num++; total_master_inner_percent += c->master_inner_per; } else { diff --git a/src/layout/horizontal.h b/src/layout/horizontal.h index 9a6a5950..7368ddb7 100644 --- a/src/layout/horizontal.h +++ b/src/layout/horizontal.h @@ -386,6 +386,8 @@ void center_tile(Monitor *m) { n = m->visible_tiling_clients; master_num = m->pertag->nmasters[m->pertag->curtag]; + master_num = n > master_num ? master_num : n; + stack_num = n - master_num; if (n == 0) @@ -595,6 +597,7 @@ void tile(Monitor *m) { n = m->visible_tiling_clients; master_num = m->pertag->nmasters[m->pertag->curtag]; + master_num = n > master_num ? master_num : n; stack_num = n - master_num; if (n == 0) @@ -692,6 +695,7 @@ void right_tile(Monitor *m) { n = m->visible_tiling_clients; master_num = m->pertag->nmasters[m->pertag->curtag]; + master_num = n > master_num ? master_num : n; stack_num = n - master_num; if (n == 0) diff --git a/src/layout/vertical.h b/src/layout/vertical.h index 5badc72b..07cb3ba8 100644 --- a/src/layout/vertical.h +++ b/src/layout/vertical.h @@ -8,6 +8,7 @@ void vertical_tile(Monitor *m) { n = m->visible_tiling_clients; master_num = m->pertag->nmasters[m->pertag->curtag]; + master_num = n > master_num ? master_num : n; stack_num = n - master_num; if (n == 0) From dd72e472bf75bc9cf0302e7ef3157063b50d8e63 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Mon, 8 Dec 2025 09:42:18 +0800 Subject: [PATCH 380/591] update readme --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index b2bd4964..9780ac6e 100644 --- a/README.md +++ b/README.md @@ -181,7 +181,9 @@ git clone https://github.com/DreamMaoMao/mango-config.git ~/.config/mango ## Config Documentation -Refer to the [wiki](https://github.com/DreamMaoMao/mango/wiki/) +Refer to the repo wiki [wiki](https://github.com/DreamMaoMao/mango/wiki/) + +or the website docs [docs](https://mangowc.vercel.app/docs) # NixOS + Home-manager From 9a2d2397c1cd1edb64a47f85ae8377ea0954e4c6 Mon Sep 17 00:00:00 2001 From: Mental-Vortex <206187961+Mental-Vortex@users.noreply.github.com> Date: Sun, 7 Dec 2025 17:35:50 +0800 Subject: [PATCH 381/591] feat: support centerwin in scroller window --- src/dispatch/bind_define.h | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index c167915c..92e264e4 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -713,14 +713,26 @@ int centerwin(const Arg *arg) { Client *c = NULL; c = selmon->sel; - if (!c || c->isfullscreen) + if (!c || c->isfullscreen || c->ismaximizescreen) return 0; - if (!c->isfloating) - setfloating(c, true); - c->float_geom = setclient_coordinate_center(c, c->geom, 0, 0); - c->iscustomsize = 1; - resize(c, c->float_geom, 1); + if (c->isfloating) { + c->float_geom = setclient_coordinate_center(c, c->geom, 0, 0); + c->iscustomsize = 1; + resize(c, c->float_geom, 1); + return 0; + } + + if (!is_scroller_layout(selmon)) + return 0; + + if (selmon->pertag->ltidxs[selmon->pertag->curtag]->id == SCROLLER) { + c->geom.x = selmon->w.x + (selmon->w.width - c->geom.width) / 2; + } else { + c->geom.y = selmon->w.y + (selmon->w.height - c->geom.height) / 2; + } + + arrange(selmon, false); return 0; } @@ -1549,4 +1561,4 @@ int toggle_monitor(const Arg *arg) { } } return 0; -} \ No newline at end of file +} From dfb59d12c2b488d601792ea7c8108a7ff0b5ca11 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Tue, 9 Dec 2025 09:40:22 +0800 Subject: [PATCH 382/591] fix: excrescent border in grid layout --- src/layout/horizontal.h | 13 +------------ src/layout/vertical.h | 12 ------------ 2 files changed, 1 insertion(+), 24 deletions(-) diff --git a/src/layout/horizontal.h b/src/layout/horizontal.h index 7368ddb7..3ded199c 100644 --- a/src/layout/horizontal.h +++ b/src/layout/horizontal.h @@ -23,10 +23,6 @@ void grid(Monitor *m) { if (c->mon != m) continue; - c->bw = m->visible_tiling_clients == 1 && no_border_when_single && - smartgaps - ? 0 - : borderpx; if (VISIBLEON(c, m) && !c->isunglobal && ((m->isoverview && !client_is_x11_popup(c)) || ISTILED(c))) { cw = (m->w.width - 2 * target_gappo) * single_width_ratio; @@ -49,10 +45,6 @@ void grid(Monitor *m) { if (c->mon != m) continue; - c->bw = m->visible_tiling_clients == 1 && no_border_when_single && - smartgaps - ? 0 - : borderpx; if (VISIBLEON(c, m) && !c->isunglobal && ((m->isoverview && !client_is_x11_popup(c)) || ISTILED(c))) { if (i == 0) { @@ -99,10 +91,7 @@ void grid(Monitor *m) { if (c->mon != m) continue; - c->bw = - m->visible_tiling_clients == 1 && no_border_when_single && smartgaps - ? 0 - : borderpx; + if (VISIBLEON(c, m) && !c->isunglobal && ((m->isoverview && !client_is_x11_popup(c)) || ISTILED(c))) { cx = m->w.x + (i % cols) * (cw + target_gappi); diff --git a/src/layout/vertical.h b/src/layout/vertical.h index 07cb3ba8..713c385f 100644 --- a/src/layout/vertical.h +++ b/src/layout/vertical.h @@ -364,10 +364,6 @@ void vertical_grid(Monitor *m) { if (c->mon != m) continue; - c->bw = m->visible_tiling_clients == 1 && no_border_when_single && - smartgaps - ? 0 - : borderpx; if (VISIBLEON(c, m) && !c->isunglobal && ((m->isoverview && !client_is_x11_popup(c)) || ISTILED(c))) { ch = (m->w.height - 2 * target_gappo) * single_height_ratio; @@ -391,10 +387,6 @@ void vertical_grid(Monitor *m) { if (c->mon != m) continue; - c->bw = m->visible_tiling_clients == 1 && no_border_when_single && - smartgaps - ? 0 - : borderpx; if (VISIBLEON(c, m) && !c->isunglobal && ((m->isoverview && !client_is_x11_popup(c)) || ISTILED(c))) { if (i == 0) { @@ -437,10 +429,6 @@ void vertical_grid(Monitor *m) { if (c->mon != m) continue; - c->bw = - m->visible_tiling_clients == 1 && no_border_when_single && smartgaps - ? 0 - : borderpx; if (VISIBLEON(c, m) && !c->isunglobal && ((m->isoverview && !client_is_x11_popup(c)) || ISTILED(c))) { cx = m->w.x + (i / rows) * (cw + target_gappi); From 318dc85b22cb66c6bc4fcdb2b39cf8cf14cee0d3 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Tue, 9 Dec 2025 20:35:21 +0800 Subject: [PATCH 383/591] opt: eliminate the positional deviation in master layout --- src/layout/horizontal.h | 81 ++++++++++++++++++++++++++++++----------- src/layout/vertical.h | 24 +++++++++--- 2 files changed, 78 insertions(+), 27 deletions(-) diff --git a/src/layout/horizontal.h b/src/layout/horizontal.h index 3ded199c..c036cfbe 100644 --- a/src/layout/horizontal.h +++ b/src/layout/horizontal.h @@ -413,6 +413,21 @@ void center_tile(Monitor *m) { // 判断是否需要主区域铺满 int should_overspread = center_master_overspread && (n <= nmasters); + uint32_t master_surplus_height = + (m->w.height - 2 * cur_gappov - + cur_gappiv * ie * (master_num - 1)); + float master_surplus_ratio = 1.0; + + uint32_t slave_left_surplus_height = + (m->w.height - 2 * cur_gappov - + cur_gappiv * ie * (stack_num / 2 - 1)); + float slave_left_surplus_ratio = 1.0; + + uint32_t slave_right_surplus_height = + (m->w.height - 2 * cur_gappov - + cur_gappiv * ie * ((stack_num + 1) / 2 - 1)); + float slave_right_surplus_ratio = 1.0; + if (n > nmasters || !should_overspread) { // 计算主区域宽度(居中模式) mw = nmasters ? (m->w.width - 2 * cur_gappoh - cur_gappih * ie) * mfact @@ -457,9 +472,9 @@ void center_tile(Monitor *m) { // 主区域窗口 r = MIN(n, nmasters) - i; if (c->master_inner_per > 0.0f) { - h = (m->w.height - 2 * cur_gappov - - cur_gappiv * ie * (master_num - 1)) * - c->master_inner_per; + h = master_surplus_height * c->master_inner_per / master_surplus_ratio; + master_surplus_height = master_surplus_height - h; + master_surplus_ratio = master_surplus_ratio - c->master_inner_per; c->master_mfact_per = mfact; } else { h = (m->w.height - my - cur_gappov - @@ -521,9 +536,9 @@ void center_tile(Monitor *m) { if ((stack_index % 2) ^ (n % 2 == 0)) { // 右侧堆叠窗口 if (c->stack_innder_per > 0.0f) { - h = (m->w.height - 2 * cur_gappov - - cur_gappiv * ie * ((stack_num + 1) / 2 - 1)) * - c->stack_innder_per; + h = slave_right_surplus_height * c->stack_innder_per / slave_right_surplus_ratio; + slave_right_surplus_height = slave_right_surplus_height - h; + slave_right_surplus_ratio = slave_right_surplus_ratio - c->stack_innder_per; c->master_mfact_per = mfact; } else { h = (m->w.height - ety - cur_gappov - @@ -547,9 +562,9 @@ void center_tile(Monitor *m) { } else { // 左侧堆叠窗口 if (c->stack_innder_per > 0.0f) { - h = (m->w.height - 2 * cur_gappov - - cur_gappiv * ie * (stack_num / 2 - 1)) * - c->stack_innder_per; + h = slave_left_surplus_height * c->stack_innder_per / slave_left_surplus_ratio; + slave_left_surplus_height = slave_left_surplus_height - h; + slave_left_surplus_ratio = slave_left_surplus_ratio - c->stack_innder_per; c->master_mfact_per = mfact; } else { h = (m->w.height - oty - cur_gappov - @@ -619,15 +634,26 @@ void tile(Monitor *m) { mw = m->w.width - 2 * cur_gappoh + cur_gappih * ie; i = 0; my = ty = cur_gappov; + + uint32_t master_surplus_height = + (m->w.height - 2 * cur_gappov - cur_gappiv * ie * (master_num - 1)); + float master_surplus_ratio = 1.0; + + uint32_t slave_surplus_height = + (m->w.height - 2 * cur_gappov - cur_gappiv * ie * (stack_num - 1)); + float slave_surplus_ratio = 1.0; + wl_list_for_each(c, &clients, link) { if (!VISIBLEON(c, m) || !ISTILED(c)) continue; if (i < m->pertag->nmasters[m->pertag->curtag]) { r = MIN(n, m->pertag->nmasters[m->pertag->curtag]) - i; if (c->master_inner_per > 0.0f) { - h = (m->w.height - 2 * cur_gappov - - cur_gappiv * ie * (master_num - 1)) * - c->master_inner_per; + h = master_surplus_height * c->master_inner_per / + master_surplus_ratio; + master_surplus_height = master_surplus_height - h; + master_surplus_ratio = + master_surplus_ratio - c->master_inner_per; c->master_mfact_per = mfact; } else { h = (m->w.height - my - cur_gappov - @@ -647,9 +673,10 @@ void tile(Monitor *m) { } else { r = n - i; if (c->stack_innder_per > 0.0f) { - h = (m->w.height - 2 * cur_gappov - - cur_gappiv * ie * (stack_num - 1)) * - c->stack_innder_per; + h = slave_surplus_height * c->stack_innder_per / + slave_surplus_ratio; + slave_surplus_height = slave_surplus_height - h; + slave_surplus_ratio = slave_surplus_ratio - c->stack_innder_per; c->master_mfact_per = mfact; } else { h = (m->w.height - ty - cur_gappov - @@ -717,15 +744,26 @@ void right_tile(Monitor *m) { mw = m->w.width - 2 * cur_gappoh + cur_gappih * ie; i = 0; my = ty = cur_gappov; + + uint32_t master_surplus_height = + (m->w.height - 2 * cur_gappov - cur_gappiv * ie * (master_num - 1)); + float master_surplus_ratio = 1.0; + + uint32_t slave_surplus_height = + (m->w.height - 2 * cur_gappov - cur_gappiv * ie * (stack_num - 1)); + float slave_surplus_ratio = 1.0; + wl_list_for_each(c, &clients, link) { if (!VISIBLEON(c, m) || !ISTILED(c)) continue; if (i < m->pertag->nmasters[m->pertag->curtag]) { r = MIN(n, m->pertag->nmasters[m->pertag->curtag]) - i; if (c->master_inner_per > 0.0f) { - h = (m->w.height - 2 * cur_gappov - - cur_gappiv * ie * (master_num - 1)) * - c->master_inner_per; + h = master_surplus_height * c->master_inner_per / + master_surplus_ratio; + master_surplus_height = master_surplus_height - h; + master_surplus_ratio = + master_surplus_ratio - c->master_inner_per; c->master_mfact_per = mfact; } else { h = (m->w.height - my - cur_gappov - @@ -746,9 +784,10 @@ void right_tile(Monitor *m) { } else { r = n - i; if (c->stack_innder_per > 0.0f) { - h = (m->w.height - 2 * cur_gappov - - cur_gappiv * ie * (stack_num - 1)) * - c->stack_innder_per; + h = slave_surplus_height * c->stack_innder_per / + slave_surplus_ratio; + slave_surplus_height = slave_surplus_height - h; + slave_surplus_ratio = slave_surplus_ratio - c->stack_innder_per; c->master_mfact_per = mfact; } else { h = (m->w.height - ty - cur_gappov - diff --git a/src/layout/vertical.h b/src/layout/vertical.h index 713c385f..3893a4ca 100644 --- a/src/layout/vertical.h +++ b/src/layout/vertical.h @@ -41,15 +41,26 @@ void vertical_tile(Monitor *m) { i = 0; mx = tx = cur_gapih; + + uint32_t master_surplus_width = + (m->w.width - 2 * cur_gapih - cur_gapih * ie * (master_num - 1)); + float master_surplus_ratio = 1.0; + + uint32_t slave_surplus_width = + (m->w.width - 2 * cur_gapih - cur_gapih * ie * (stack_num - 1)); + float slave_surplus_ratio = 1.0; + wl_list_for_each(c, &clients, link) { if (!VISIBLEON(c, m) || !ISTILED(c)) continue; if (i < m->pertag->nmasters[m->pertag->curtag]) { r = MIN(n, m->pertag->nmasters[m->pertag->curtag]) - i; if (c->master_inner_per > 0.0f) { - w = (m->w.width - 2 * cur_gapih - - cur_gapih * ie * (master_num - 1)) * - c->master_inner_per; + w = master_surplus_width * c->master_inner_per / + master_surplus_ratio; + master_surplus_width = master_surplus_width - w; + master_surplus_ratio = + master_surplus_ratio - c->master_inner_per; c->master_mfact_per = mfact; } else { w = (m->w.width - mx - cur_gapih - cur_gapih * ie * (r - 1)) / @@ -68,9 +79,10 @@ void vertical_tile(Monitor *m) { } else { r = n - i; if (c->stack_innder_per > 0.0f) { - w = (m->w.width - 2 * cur_gapih - - cur_gapih * ie * (stack_num - 1)) * - c->stack_innder_per; + w = slave_surplus_width * c->stack_innder_per / + slave_surplus_ratio; + slave_surplus_width = slave_surplus_width - w; + slave_surplus_ratio = slave_surplus_ratio - c->stack_innder_per; c->master_mfact_per = mfact; } else { w = (m->w.width - tx - cur_gapih - cur_gapih * ie * (r - 1)) / From 01e957f2aeab745c4969e928a1ed2b9f0a0968b5 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Wed, 10 Dec 2025 18:29:16 +0800 Subject: [PATCH 384/591] opt: allow layershell surface toggle shortcut inhibit --- src/mango.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/mango.c b/src/mango.c index 8811c849..8950d3bf 100644 --- a/src/mango.c +++ b/src/mango.c @@ -5700,8 +5700,15 @@ void handle_keyboard_shortcuts_inhibit_new_inhibitor( } // per-view, seat-agnostic config via criteria - Client *c = get_client_from_surface(inhibitor->surface); - if (c && !c->allow_shortcuts_inhibit) { + Client *c = NULL; + LayerSurface *l = NULL; + + int type = toplevel_from_wlr_surface(inhibitor->surface, &c, &l); + + if (type < 0) + return; + + if (type != LayerShell && c && !c->allow_shortcuts_inhibit) { return; } From 2aa7e58d7cb059ad56cdad0ab6eb266aae4734cc Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Wed, 10 Dec 2025 18:30:45 +0800 Subject: [PATCH 385/591] opt: optimize get client from surface --- src/client/client.h | 14 -------------- src/ext-protocol/tearing.h | 5 ++++- 2 files changed, 4 insertions(+), 15 deletions(-) diff --git a/src/client/client.h b/src/client/client.h index 10ecfdf7..bc7706d7 100644 --- a/src/client/client.h +++ b/src/client/client.h @@ -153,20 +153,6 @@ static inline void client_get_geometry(Client *c, struct wlr_box *geom) { *geom = c->surface.xdg->geometry; } -static inline Client *get_client_from_surface(struct wlr_surface *surface) { - if (!surface) - return NULL; - - // 从 surface 的 data 指针获取 scene tree - struct wlr_scene_tree *scene_tree = surface->data; - if (!scene_tree) - return NULL; - - // 从 scene tree 的 node data 获取 Client - Client *c = scene_tree->node.data; - return c; -} - static inline Client *client_get_parent(Client *c) { Client *p = NULL; #ifdef XWAYLAND diff --git a/src/ext-protocol/tearing.h b/src/ext-protocol/tearing.h index 5ad36e8a..8e02656a 100644 --- a/src/ext-protocol/tearing.h +++ b/src/ext-protocol/tearing.h @@ -13,7 +13,10 @@ static void handle_controller_set_hint(struct wl_listener *listener, void *data) { struct tearing_controller *controller = wl_container_of(listener, controller, set_hint); - Client *c = get_client_from_surface(controller->tearing_control->surface); + Client *c = NULL; + + toplevel_from_wlr_surface(controller->tearing_control->surface, &c, NULL); + if (c) { /* * tearing_control->current is actually an enum: From 31d29fb48cc97b2f7e8de51f4e0c7b268f2a39e4 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Wed, 10 Dec 2025 18:32:06 +0800 Subject: [PATCH 386/591] opt: format code --- src/layout/horizontal.h | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/src/layout/horizontal.h b/src/layout/horizontal.h index c036cfbe..0a7613da 100644 --- a/src/layout/horizontal.h +++ b/src/layout/horizontal.h @@ -414,18 +414,16 @@ void center_tile(Monitor *m) { int should_overspread = center_master_overspread && (n <= nmasters); uint32_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 - 1)); float master_surplus_ratio = 1.0; uint32_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 * (stack_num / 2 - 1)); float slave_left_surplus_ratio = 1.0; uint32_t slave_right_surplus_height = - (m->w.height - 2 * cur_gappov - - cur_gappiv * ie * ((stack_num + 1) / 2 - 1)); + (m->w.height - 2 * cur_gappov - + cur_gappiv * ie * ((stack_num + 1) / 2 - 1)); float slave_right_surplus_ratio = 1.0; if (n > nmasters || !should_overspread) { @@ -472,9 +470,11 @@ void center_tile(Monitor *m) { // 主区域窗口 r = MIN(n, nmasters) - i; if (c->master_inner_per > 0.0f) { - h = master_surplus_height * c->master_inner_per / master_surplus_ratio; + h = master_surplus_height * c->master_inner_per / + master_surplus_ratio; master_surplus_height = master_surplus_height - h; - master_surplus_ratio = master_surplus_ratio - c->master_inner_per; + master_surplus_ratio = + master_surplus_ratio - c->master_inner_per; c->master_mfact_per = mfact; } else { h = (m->w.height - my - cur_gappov - @@ -536,9 +536,12 @@ void center_tile(Monitor *m) { if ((stack_index % 2) ^ (n % 2 == 0)) { // 右侧堆叠窗口 if (c->stack_innder_per > 0.0f) { - h = slave_right_surplus_height * c->stack_innder_per / slave_right_surplus_ratio; - slave_right_surplus_height = slave_right_surplus_height - h; - slave_right_surplus_ratio = slave_right_surplus_ratio - c->stack_innder_per; + h = slave_right_surplus_height * c->stack_innder_per / + slave_right_surplus_ratio; + slave_right_surplus_height = + slave_right_surplus_height - h; + slave_right_surplus_ratio = + slave_right_surplus_ratio - c->stack_innder_per; c->master_mfact_per = mfact; } else { h = (m->w.height - ety - cur_gappov - @@ -562,9 +565,12 @@ void center_tile(Monitor *m) { } else { // 左侧堆叠窗口 if (c->stack_innder_per > 0.0f) { - h = slave_left_surplus_height * c->stack_innder_per / slave_left_surplus_ratio; - slave_left_surplus_height = slave_left_surplus_height - h; - slave_left_surplus_ratio = slave_left_surplus_ratio - c->stack_innder_per; + h = slave_left_surplus_height * c->stack_innder_per / + slave_left_surplus_ratio; + slave_left_surplus_height = + slave_left_surplus_height - h; + slave_left_surplus_ratio = + slave_left_surplus_ratio - c->stack_innder_per; c->master_mfact_per = mfact; } else { h = (m->w.height - oty - cur_gappov - From 4e296671c277a38cf31b5619bc96e2bf92ddaa8b Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Wed, 10 Dec 2025 19:36:32 +0800 Subject: [PATCH 387/591] feat: handle foreign toplevel minimize and maximize request --- src/ext-protocol/foreign-toplevel.h | 41 +++++++++++++++++++++++++---- src/mango.c | 2 ++ 2 files changed, 38 insertions(+), 5 deletions(-) diff --git a/src/ext-protocol/foreign-toplevel.h b/src/ext-protocol/foreign-toplevel.h index 3b819485..4a725796 100644 --- a/src/ext-protocol/foreign-toplevel.h +++ b/src/ext-protocol/foreign-toplevel.h @@ -6,6 +6,36 @@ void handle_foreign_activate_request(struct wl_listener *listener, void *data) { Client *c = wl_container_of(listener, c, foreign_activate_request); uint32_t target; + if (c && c->swallowing) + return; + + if (c->isminimized) { + c->is_in_scratchpad = 0; + c->isnamedscratchpad = 0; + c->is_scratchpad_show = 0; + setborder_color(c); + show_hide_client(c); + arrange(c->mon, true); + return; + } + + target = get_tags_first_tag(c->tags); + view_in_mon(&(Arg){.ui = target}, true, c->mon, true); + focusclient(c, 1); + wlr_foreign_toplevel_handle_v1_set_activated(c->foreign_toplevel, true); +} + +void handle_foreign_maximize_request(struct wl_listener *listener, void *data) { + Client *c = wl_container_of(listener, c, foreign_maximize_request); + if (c->ismaximizescreen) { + setmaximizescreen(c, 0); + } else { + setmaximizescreen(c, 1); + } +} + +void handle_foreign_minimize_request(struct wl_listener *listener, void *data) { + Client *c = wl_container_of(listener, c, foreign_minimize_request); if (c && c->swallowing) return; @@ -23,11 +53,6 @@ void handle_foreign_activate_request(struct wl_listener *listener, void *data) { arrange(c->mon, true); return; } - - target = get_tags_first_tag(c->tags); - view_in_mon(&(Arg){.ui = target}, true, c->mon, true); - focusclient(c, 1); - wlr_foreign_toplevel_handle_v1_set_activated(c->foreign_toplevel, true); } void handle_foreign_fullscreen_request(struct wl_listener *listener, @@ -46,6 +71,8 @@ void handle_foreign_destroy(struct wl_listener *listener, void *data) { Client *c = wl_container_of(listener, c, foreign_destroy); if (c) { wl_list_remove(&c->foreign_activate_request.link); + wl_list_remove(&c->foreign_minimize_request.link); + wl_list_remove(&c->foreign_maximize_request.link); wl_list_remove(&c->foreign_fullscreen_request.link); wl_list_remove(&c->foreign_close_request.link); wl_list_remove(&c->foreign_destroy.link); @@ -67,6 +94,10 @@ void add_foreign_toplevel(Client *c) { if (c->foreign_toplevel) { LISTEN(&(c->foreign_toplevel->events.request_activate), &c->foreign_activate_request, handle_foreign_activate_request); + LISTEN(&(c->foreign_toplevel->events.request_minimize), + &c->foreign_minimize_request, handle_foreign_minimize_request); + LISTEN(&(c->foreign_toplevel->events.request_maximize), + &c->foreign_maximize_request, handle_foreign_maximize_request); LISTEN(&(c->foreign_toplevel->events.request_fullscreen), &c->foreign_fullscreen_request, handle_foreign_fullscreen_request); diff --git a/src/mango.c b/src/mango.c index 8950d3bf..53fffeca 100644 --- a/src/mango.c +++ b/src/mango.c @@ -351,6 +351,8 @@ struct Client { struct wl_listener foreign_fullscreen_request; struct wl_listener foreign_close_request; struct wl_listener foreign_destroy; + struct wl_listener foreign_minimize_request; + struct wl_listener foreign_maximize_request; struct wl_listener set_decoration_mode; struct wl_listener destroy_decoration; From 64d350ee9b7f78ed06389dfc198e058b52c60336 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Wed, 10 Dec 2025 20:11:55 +0800 Subject: [PATCH 388/591] feat: add bing flag p --- src/config/parse_config.h | 6 +++++- src/mango.c | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/config/parse_config.h b/src/config/parse_config.h index d845e2ab..0479c6d2 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -43,6 +43,7 @@ typedef struct { bool isdefaultmode; bool islockapply; bool isreleaseapply; + bool ispassapply; } KeyBinding; typedef struct { @@ -443,6 +444,9 @@ void parse_bind_flags(const char *str, KeyBinding *kb) { case 'r': kb->isreleaseapply = true; break; + case 'p': + kb->ispassapply = true; + break; default: // 忽略其他字符或可根据需要处理错误 break; @@ -1956,7 +1960,7 @@ void parse_option(Config *config, char *key, char *value) { config->exec_once_count++; - } else if (regex_match("^bind[s|l|r]*$", key)) { + } else if (regex_match("^bind[s|l|r|p]*$", key)) { config->key_bindings = realloc(config->key_bindings, (config->key_bindings_count + 1) * sizeof(KeyBinding)); diff --git a/src/mango.c b/src/mango.c index 53fffeca..4a87c607 100644 --- a/src/mango.c +++ b/src/mango.c @@ -3434,7 +3434,11 @@ keybinding(uint32_t state, bool locked, uint32_t mods, xkb_keysym_t sym, k->func) { isbreak = k->func(&k->arg); - handled = 1; + + if (!k->ispassapply) + handled = 1; + else + handled = 0; if (isbreak) break; From f771e56c31f6febc6ce04f2fbc0697dc487fdef4 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Wed, 10 Dec 2025 22:35:45 +0800 Subject: [PATCH 389/591] opt: optimize handle foreign toplevel --- src/ext-protocol/foreign-toplevel.h | 59 +++++++++++++++++++---------- src/layout/arrange.h | 2 + 2 files changed, 42 insertions(+), 19 deletions(-) diff --git a/src/ext-protocol/foreign-toplevel.h b/src/ext-protocol/foreign-toplevel.h index 4a725796..01c384fb 100644 --- a/src/ext-protocol/foreign-toplevel.h +++ b/src/ext-protocol/foreign-toplevel.h @@ -6,7 +6,7 @@ void handle_foreign_activate_request(struct wl_listener *listener, void *data) { Client *c = wl_container_of(listener, c, foreign_activate_request); uint32_t target; - if (c && c->swallowing) + if (c->swallowing) return; if (c->isminimized) { @@ -22,29 +22,39 @@ void handle_foreign_activate_request(struct wl_listener *listener, void *data) { target = get_tags_first_tag(c->tags); view_in_mon(&(Arg){.ui = target}, true, c->mon, true); focusclient(c, 1); - wlr_foreign_toplevel_handle_v1_set_activated(c->foreign_toplevel, true); } void handle_foreign_maximize_request(struct wl_listener *listener, void *data) { Client *c = wl_container_of(listener, c, foreign_maximize_request); - if (c->ismaximizescreen) { + struct wlr_foreign_toplevel_handle_v1_maximized_event *event = data; + + if (c->swallowing) + return; + + if (c->ismaximizescreen && !event->maximized) { setmaximizescreen(c, 0); - } else { + return; + } + + if (!c->ismaximizescreen && event->maximized) { setmaximizescreen(c, 1); + return; } } void handle_foreign_minimize_request(struct wl_listener *listener, void *data) { Client *c = wl_container_of(listener, c, foreign_minimize_request); - if (c && c->swallowing) + struct wlr_foreign_toplevel_handle_v1_minimized_event *event = data; + + if (c->swallowing) return; - if (c && !c->isminimized && c == selmon->sel) { + if (!c->isminimized && event->minimized) { set_minimized(c); return; } - if (c->isminimized) { + if (c->isminimized && !event->minimized) { c->is_in_scratchpad = 0; c->isnamedscratchpad = 0; c->is_scratchpad_show = 0; @@ -57,26 +67,37 @@ void handle_foreign_minimize_request(struct wl_listener *listener, void *data) { void handle_foreign_fullscreen_request(struct wl_listener *listener, void *data) { - return; + + Client *c = wl_container_of(listener, c, foreign_fullscreen_request); + struct wlr_foreign_toplevel_handle_v1_fullscreen_event *event = data; + + if (c->swallowing) + return; + + if (c->isfullscreen && !event->fullscreen) { + setfullscreen(c, 0); + return; + } + + if (!c->isfullscreen && event->fullscreen) { + setfullscreen(c, 1); + return; + } } void handle_foreign_close_request(struct wl_listener *listener, void *data) { Client *c = wl_container_of(listener, c, foreign_close_request); - if (c) { - pending_kill_client(c); - } + pending_kill_client(c); } void handle_foreign_destroy(struct wl_listener *listener, void *data) { Client *c = wl_container_of(listener, c, foreign_destroy); - if (c) { - wl_list_remove(&c->foreign_activate_request.link); - wl_list_remove(&c->foreign_minimize_request.link); - wl_list_remove(&c->foreign_maximize_request.link); - wl_list_remove(&c->foreign_fullscreen_request.link); - wl_list_remove(&c->foreign_close_request.link); - wl_list_remove(&c->foreign_destroy.link); - } + wl_list_remove(&c->foreign_activate_request.link); + wl_list_remove(&c->foreign_minimize_request.link); + wl_list_remove(&c->foreign_maximize_request.link); + wl_list_remove(&c->foreign_fullscreen_request.link); + wl_list_remove(&c->foreign_close_request.link); + wl_list_remove(&c->foreign_destroy.link); } void remove_foreign_topleve(Client *c) { diff --git a/src/layout/arrange.h b/src/layout/arrange.h index 7a1d6205..f8966733 100644 --- a/src/layout/arrange.h +++ b/src/layout/arrange.h @@ -682,4 +682,6 @@ arrange(Monitor *m, bool want_animation) { motionnotify(0, NULL, 0, 0, 0, 0); checkidleinhibitor(NULL); } + + printstatus(); } From 2c893c3345b4715f2d34eb23df41738267a9d99c Mon Sep 17 00:00:00 2001 From: 4zv4l <4zv4l@protonmail.com> Date: Sun, 30 Nov 2025 23:19:55 +0800 Subject: [PATCH 390/591] guix: not pin hash in repo --- mangowc.scm | 38 +++++++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/mangowc.scm b/mangowc.scm index 94e80c02..9c55d43e 100644 --- a/mangowc.scm +++ b/mangowc.scm @@ -1,7 +1,9 @@ (define-module (mangowc) - #:use-module (guix packages) #:use-module (guix download) #:use-module (guix git-download) + #:use-module (guix gexp) + #:use-module (guix packages) + #:use-module (guix utils) #:use-module (gnu packages wm) #:use-module (gnu packages freedesktop) #:use-module (gnu packages xdisorg) @@ -16,21 +18,29 @@ #:use-module (guix licenses)) -(define-public mangowc +(define-public mangowc-git (package (name "mangowc") - (version "0.10.4") - (source - (origin - (method git-fetch) - (uri (git-reference - (url "https://github.com/DreamMaoMao/mangowc") - (commit "0.10.4"))) - (sha256 - (base32 "0cayb2r69zcp5q810bqhq27xi0b5dlk81qwl6zj6aqjphh6yzpv9")))) + (version "git") + (source (local-file "." "mangowc-checkout" + #:recursive? #t + #:select? (or (git-predicate (current-source-directory)) + (const #t)))) (build-system meson-build-system) + (arguments + (list + #:configure-flags + #~(list (string-append "-Dsysconfdir=" #$output "/etc")) + #:phases + #~(modify-phases %standard-phases + (add-before 'configure 'patch-meson + (lambda _ + (substitute* "meson.build" + (("'-DSYSCONFDIR=\\\"@0@\\\"'.format\\('/etc'\\)") + "'-DSYSCONFDIR=\"@0@\"'.format(sysconfdir)") + (("sysconfdir = sysconfdir.substring\\(prefix.length\\(\\)\\)") + ""))))))) (inputs (list wayland - wayland-protocols libinput libdrm libxkbcommon @@ -44,9 +54,11 @@ xcb-util-wm wlroots scenefx)) - (native-inputs (list meson ninja pkg-config)) + (native-inputs (list pkg-config wayland-protocols)) (home-page "https://github.com/DreamMaoMao/mangowc") (synopsis "Wayland compositor based on wlroots and scenefx") (description "A Wayland compositor based on wlroots and scenefx, inspired by dwl but aiming to be more feature-rich.") (license gpl3))) + +mangowc-git From ddc2448d1c38dbd979ba0c76e8fef4d4c9149f2e Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Thu, 11 Dec 2025 15:44:08 +0800 Subject: [PATCH 391/591] fix: fix typo --- src/layout/arrange.h | 60 ++++++++++++++++++++--------------------- src/layout/horizontal.h | 48 ++++++++++++++++----------------- src/layout/vertical.h | 10 +++---- src/mango.c | 14 +++++----- 4 files changed, 66 insertions(+), 66 deletions(-) diff --git a/src/layout/arrange.h b/src/layout/arrange.h index f8966733..3b52bd44 100644 --- a/src/layout/arrange.h +++ b/src/layout/arrange.h @@ -5,7 +5,7 @@ void set_size_per(Monitor *m, Client *c) { if (VISIBLEON(fc, m) && ISTILED(fc) && fc != c) { c->master_mfact_per = fc->master_mfact_per; c->master_inner_per = fc->master_inner_per; - c->stack_innder_per = fc->stack_innder_per; + c->stack_inner_per = fc->stack_inner_per; found = true; break; } @@ -14,7 +14,7 @@ void set_size_per(Monitor *m, Client *c) { if (!found) { c->master_mfact_per = m->pertag->mfacts[m->pertag->curtag]; c->master_inner_per = 1.0f; - c->stack_innder_per = 1.0f; + c->stack_inner_per = 1.0f; } } @@ -70,7 +70,7 @@ void resize_tile_master_horizontal(Client *grabc, bool isdrag, int offsetx, // 记录初始状态 grabc->old_master_mfact_per = grabc->master_mfact_per; grabc->old_master_inner_per = grabc->master_inner_per; - grabc->old_stack_innder_per = grabc->stack_innder_per; + grabc->old_stack_inner_per = grabc->stack_inner_per; grabc->cursor_in_upper_half = cursor->y < grabc->geom.y + grabc->geom.height / 2; grabc->cursor_in_left_half = @@ -86,7 +86,7 @@ void resize_tile_master_horizontal(Client *grabc, bool isdrag, int offsetx, } else { grabc->old_master_mfact_per = grabc->master_mfact_per; grabc->old_master_inner_per = grabc->master_inner_per; - grabc->old_stack_innder_per = grabc->stack_innder_per; + grabc->old_stack_inner_per = grabc->stack_inner_per; grabc->drag_begin_geom = grabc->geom; grabc->cursor_in_upper_half = true; grabc->cursor_in_left_half = false; @@ -100,7 +100,7 @@ void resize_tile_master_horizontal(Client *grabc, bool isdrag, int offsetx, } else { delta_x = (float)(offsetx) * (1 - grabc->old_master_mfact_per) / grabc->drag_begin_geom.width; - delta_y = (float)(offsety) * (grabc->old_stack_innder_per) / + delta_y = (float)(offsety) * (grabc->old_stack_inner_per) / grabc->drag_begin_geom.height; } bool moving_up; @@ -182,12 +182,12 @@ void resize_tile_master_horizontal(Client *grabc, bool isdrag, int offsetx, // 直接设置新的比例,基于初始值 + 变化量 float new_master_mfact_per = grabc->old_master_mfact_per + delta_x; float new_master_inner_per = grabc->old_master_inner_per + delta_y; - float new_stack_innder_per = grabc->old_stack_innder_per + delta_y; + float new_stack_inner_per = grabc->old_stack_inner_per + delta_y; // 应用限制,确保比例在合理范围内 new_master_mfact_per = fmaxf(0.1f, fminf(0.9f, new_master_mfact_per)); new_master_inner_per = fmaxf(0.1f, fminf(0.9f, new_master_inner_per)); - new_stack_innder_per = fmaxf(0.1f, fminf(0.9f, new_stack_innder_per)); + new_stack_inner_per = fmaxf(0.1f, fminf(0.9f, new_stack_inner_per)); // 应用到所有平铺窗口 wl_list_for_each(tc, &clients, link) { @@ -197,7 +197,7 @@ void resize_tile_master_horizontal(Client *grabc, bool isdrag, int offsetx, } grabc->master_inner_per = new_master_inner_per; - grabc->stack_innder_per = new_stack_innder_per; + grabc->stack_inner_per = new_stack_inner_per; if (!isdrag) { arrange(grabc->mon, false); @@ -250,7 +250,7 @@ void resize_tile_master_vertical(Client *grabc, bool isdrag, int offsetx, // 记录初始状态 grabc->old_master_mfact_per = grabc->master_mfact_per; grabc->old_master_inner_per = grabc->master_inner_per; - grabc->old_stack_innder_per = grabc->stack_innder_per; + grabc->old_stack_inner_per = grabc->stack_inner_per; grabc->cursor_in_upper_half = cursor->y < grabc->geom.y + grabc->geom.height / 2; grabc->cursor_in_left_half = @@ -267,7 +267,7 @@ void resize_tile_master_vertical(Client *grabc, bool isdrag, int offsetx, } else { grabc->old_master_mfact_per = grabc->master_mfact_per; grabc->old_master_inner_per = grabc->master_inner_per; - grabc->old_stack_innder_per = grabc->stack_innder_per; + grabc->old_stack_inner_per = grabc->stack_inner_per; grabc->drag_begin_geom = grabc->geom; grabc->cursor_in_upper_half = true; grabc->cursor_in_left_half = false; @@ -280,7 +280,7 @@ void resize_tile_master_vertical(Client *grabc, bool isdrag, int offsetx, delta_y = (float)(offsety) * (grabc->old_master_mfact_per) / grabc->drag_begin_geom.height; } else { - delta_x = (float)(offsetx) * (grabc->old_stack_innder_per) / + delta_x = (float)(offsetx) * (grabc->old_stack_inner_per) / grabc->drag_begin_geom.width; delta_y = (float)(offsety) * (1 - grabc->old_master_mfact_per) / grabc->drag_begin_geom.height; @@ -338,13 +338,13 @@ void resize_tile_master_vertical(Client *grabc, bool isdrag, int offsetx, delta_y; // 垂直:delta_y调整主区域高度 float new_master_inner_per = grabc->old_master_inner_per + delta_x; // 垂直:delta_x调整主区域内部宽度 - float new_stack_innder_per = grabc->old_stack_innder_per + - delta_x; // 垂直:delta_x调整栈区域内部宽度 + float new_stack_inner_per = grabc->old_stack_inner_per + + delta_x; // 垂直:delta_x调整栈区域内部宽度 // 应用限制,确保比例在合理范围内 new_master_mfact_per = fmaxf(0.1f, fminf(0.9f, new_master_mfact_per)); new_master_inner_per = fmaxf(0.1f, fminf(0.9f, new_master_inner_per)); - new_stack_innder_per = fmaxf(0.1f, fminf(0.9f, new_stack_innder_per)); + new_stack_inner_per = fmaxf(0.1f, fminf(0.9f, new_stack_inner_per)); // 应用到所有平铺窗口 wl_list_for_each(tc, &clients, link) { @@ -354,7 +354,7 @@ void resize_tile_master_vertical(Client *grabc, bool isdrag, int offsetx, } grabc->master_inner_per = new_master_inner_per; - grabc->stack_innder_per = new_stack_innder_per; + grabc->stack_inner_per = new_stack_inner_per; if (!isdrag) { arrange(grabc->mon, false); @@ -402,7 +402,7 @@ void resize_tile_scroller(Client *grabc, bool isdrag, int offsetx, int offsety, } else { grabc->old_master_mfact_per = grabc->master_mfact_per; grabc->old_master_inner_per = grabc->master_inner_per; - grabc->old_stack_innder_per = grabc->stack_innder_per; + grabc->old_stack_inner_per = grabc->stack_inner_per; grabc->drag_begin_geom = grabc->geom; grabc->old_scroller_pproportion = grabc->scroller_proportion; grabc->cursor_in_upper_half = false; @@ -518,16 +518,16 @@ void reset_size_per_mon(Monitor *m, int tile_cilent_num, if (VISIBLEON(c, m) && ISTILED(c)) { if (total_master_inner_percent > 0.0 && i < nmasters) { c->ismaster = true; - c->stack_innder_per = stack_num ? 1.0f / stack_num : 1.0f; + c->stack_inner_per = stack_num ? 1.0f / stack_num : 1.0f; c->master_inner_per = c->master_inner_per / total_master_inner_percent; } else { c->ismaster = false; c->master_inner_per = master_num > 0 ? 1.0f / master_num : 1.0f; - c->stack_innder_per = + c->stack_inner_per = total_stack_hight_percent - ? c->stack_innder_per / total_stack_hight_percent + ? c->stack_inner_per / total_stack_hight_percent : 1.0f; } i++; @@ -539,11 +539,11 @@ void reset_size_per_mon(Monitor *m, int tile_cilent_num, if (total_master_inner_percent > 0.0 && i < nmasters) { c->ismaster = true; if ((stack_index % 2) ^ (tile_cilent_num % 2 == 0)) { - c->stack_innder_per = + c->stack_inner_per = stack_num > 1 ? 1.0f / ((stack_num - 1) / 2) : 1.0f; } else { - c->stack_innder_per = + c->stack_inner_per = stack_num > 1 ? 2.0f / stack_num : 1.0f; } @@ -556,15 +556,15 @@ void reset_size_per_mon(Monitor *m, int tile_cilent_num, c->master_inner_per = master_num > 0 ? 1.0f / master_num : 1.0f; if ((stack_index % 2) ^ (tile_cilent_num % 2 == 0)) { - c->stack_innder_per = + c->stack_inner_per = total_right_stack_hight_percent - ? c->stack_innder_per / + ? c->stack_inner_per / total_right_stack_hight_percent : 1.0f; } else { - c->stack_innder_per = + c->stack_inner_per = total_left_stack_hight_percent - ? c->stack_innder_per / + ? c->stack_inner_per / total_left_stack_hight_percent : 1.0f; } @@ -578,7 +578,7 @@ void reset_size_per_mon(Monitor *m, int tile_cilent_num, void // 17 arrange(Monitor *m, bool want_animation) { Client *c = NULL; - double total_stack_innder_percent = 0; + double total_stack_inner_percent = 0; double total_master_inner_percent = 0; double total_right_stack_hight_percent = 0; double total_left_stack_hight_percent = 0; @@ -638,17 +638,17 @@ arrange(Monitor *m, bool want_animation) { total_master_inner_percent += c->master_inner_per; } else { stack_num++; - total_stack_innder_percent += c->stack_innder_per; + total_stack_inner_percent += c->stack_inner_per; stack_index = i - nmasters; if ((stack_index % 2) ^ (m->visible_tiling_clients % 2 == 0)) { c->isleftstack = false; total_right_stack_hight_percent += - c->stack_innder_per; + c->stack_inner_per; } else { c->isleftstack = true; total_left_stack_hight_percent += - c->stack_innder_per; + c->stack_inner_per; } } @@ -669,7 +669,7 @@ arrange(Monitor *m, bool want_animation) { reset_size_per_mon( m, m->visible_tiling_clients, total_left_stack_hight_percent, - total_right_stack_hight_percent, total_stack_innder_percent, + total_right_stack_hight_percent, total_stack_inner_percent, total_master_inner_percent, master_num, stack_num); if (m->isoverview) { diff --git a/src/layout/horizontal.h b/src/layout/horizontal.h index 0a7613da..ce6617d5 100644 --- a/src/layout/horizontal.h +++ b/src/layout/horizontal.h @@ -499,17 +499,17 @@ void center_tile(Monitor *m) { if (n - nmasters == 1) { // 单个堆叠窗口 r = n - i; - if (c->stack_innder_per > 0.0f) { + if (c->stack_inner_per > 0.0f) { h = (m->w.height - 2 * cur_gappov - cur_gappiv * ie * (stack_num - 1)) * - c->stack_innder_per; + c->stack_inner_per; c->master_mfact_per = mfact; } else { h = (m->w.height - ety - cur_gappov - cur_gappiv * ie * (r - 1)) / r; - c->stack_innder_per = h / (m->w.height - ety - cur_gappov - - cur_gappiv * ie * (r - 1)); + c->stack_inner_per = h / (m->w.height - ety - cur_gappov - + cur_gappiv * ie * (r - 1)); c->master_mfact_per = mfact; } @@ -535,19 +535,19 @@ void center_tile(Monitor *m) { if ((stack_index % 2) ^ (n % 2 == 0)) { // 右侧堆叠窗口 - if (c->stack_innder_per > 0.0f) { - h = slave_right_surplus_height * c->stack_innder_per / + if (c->stack_inner_per > 0.0f) { + h = slave_right_surplus_height * c->stack_inner_per / slave_right_surplus_ratio; slave_right_surplus_height = slave_right_surplus_height - h; slave_right_surplus_ratio = - slave_right_surplus_ratio - c->stack_innder_per; + slave_right_surplus_ratio - c->stack_inner_per; c->master_mfact_per = mfact; } else { h = (m->w.height - ety - cur_gappov - cur_gappiv * ie * (r - 1)) / r; - c->stack_innder_per = + c->stack_inner_per = h / (m->w.height - ety - cur_gappov - cur_gappiv * ie * (r - 1)); c->master_mfact_per = mfact; @@ -564,19 +564,19 @@ void center_tile(Monitor *m) { ety += c->geom.height + cur_gappiv * ie; } else { // 左侧堆叠窗口 - if (c->stack_innder_per > 0.0f) { - h = slave_left_surplus_height * c->stack_innder_per / + if (c->stack_inner_per > 0.0f) { + h = slave_left_surplus_height * c->stack_inner_per / slave_left_surplus_ratio; slave_left_surplus_height = slave_left_surplus_height - h; slave_left_surplus_ratio = - slave_left_surplus_ratio - c->stack_innder_per; + slave_left_surplus_ratio - c->stack_inner_per; c->master_mfact_per = mfact; } else { h = (m->w.height - oty - cur_gappov - cur_gappiv * ie * (r - 1)) / r; - c->stack_innder_per = + c->stack_inner_per = h / (m->w.height - oty - cur_gappov - cur_gappiv * ie * (r - 1)); c->master_mfact_per = mfact; @@ -678,22 +678,22 @@ void tile(Monitor *m) { my += c->geom.height + cur_gappiv * ie; } else { r = n - i; - if (c->stack_innder_per > 0.0f) { - h = slave_surplus_height * c->stack_innder_per / + if (c->stack_inner_per > 0.0f) { + h = slave_surplus_height * c->stack_inner_per / slave_surplus_ratio; slave_surplus_height = slave_surplus_height - h; - slave_surplus_ratio = slave_surplus_ratio - c->stack_innder_per; + slave_surplus_ratio = slave_surplus_ratio - c->stack_inner_per; c->master_mfact_per = mfact; } else { h = (m->w.height - ty - cur_gappov - cur_gappiv * ie * (r - 1)) / r; - c->stack_innder_per = h / (m->w.height - ty - cur_gappov - - cur_gappiv * ie * (r - 1)); + c->stack_inner_per = h / (m->w.height - ty - cur_gappov - + cur_gappiv * ie * (r - 1)); c->master_mfact_per = mfact; } - // wlr_log(WLR_ERROR, "stack_innder_per: %f", c->stack_innder_per); + // wlr_log(WLR_ERROR, "stack_inner_per: %f", c->stack_inner_per); resize(c, (struct wlr_box){.x = m->w.x + mw + cur_gappoh, @@ -789,22 +789,22 @@ void right_tile(Monitor *m) { my += c->geom.height + cur_gappiv * ie; } else { r = n - i; - if (c->stack_innder_per > 0.0f) { - h = slave_surplus_height * c->stack_innder_per / + if (c->stack_inner_per > 0.0f) { + h = slave_surplus_height * c->stack_inner_per / slave_surplus_ratio; slave_surplus_height = slave_surplus_height - h; - slave_surplus_ratio = slave_surplus_ratio - c->stack_innder_per; + slave_surplus_ratio = slave_surplus_ratio - c->stack_inner_per; c->master_mfact_per = mfact; } else { h = (m->w.height - ty - cur_gappov - cur_gappiv * ie * (r - 1)) / r; - c->stack_innder_per = h / (m->w.height - ty - cur_gappov - - cur_gappiv * ie * (r - 1)); + c->stack_inner_per = h / (m->w.height - ty - cur_gappov - + cur_gappiv * ie * (r - 1)); c->master_mfact_per = mfact; } - // wlr_log(WLR_ERROR, "stack_innder_per: %f", c->stack_innder_per); + // wlr_log(WLR_ERROR, "stack_inner_per: %f", c->stack_inner_per); resize(c, (struct wlr_box){.x = m->w.x + cur_gappoh, diff --git a/src/layout/vertical.h b/src/layout/vertical.h index 3893a4ca..b6dd27da 100644 --- a/src/layout/vertical.h +++ b/src/layout/vertical.h @@ -78,17 +78,17 @@ void vertical_tile(Monitor *m) { mx += c->geom.width + cur_gapih * ie; } else { r = n - i; - if (c->stack_innder_per > 0.0f) { - w = slave_surplus_width * c->stack_innder_per / + if (c->stack_inner_per > 0.0f) { + w = slave_surplus_width * c->stack_inner_per / slave_surplus_ratio; slave_surplus_width = slave_surplus_width - w; - slave_surplus_ratio = slave_surplus_ratio - c->stack_innder_per; + slave_surplus_ratio = slave_surplus_ratio - c->stack_inner_per; c->master_mfact_per = mfact; } else { w = (m->w.width - tx - cur_gapih - cur_gapih * ie * (r - 1)) / r; - c->stack_innder_per = w / (m->w.width - tx - cur_gapih - - cur_gapih * ie * (r - 1)); + c->stack_inner_per = w / (m->w.width - tx - cur_gapih - + cur_gapih * ie * (r - 1)); c->master_mfact_per = mfact; } diff --git a/src/mango.c b/src/mango.c index 4a87c607..ce22e31d 100644 --- a/src/mango.c +++ b/src/mango.c @@ -394,8 +394,8 @@ struct Client { float unfocused_opacity; char oldmonname[128]; int noblur; - double master_mfact_per, master_inner_per, stack_innder_per; - double old_master_mfact_per, old_master_inner_per, old_stack_innder_per; + double master_mfact_per, master_inner_per, stack_inner_per; + double old_master_mfact_per, old_master_inner_per, old_stack_inner_per; double old_scroller_pproportion; bool ismaster; bool cursor_in_upper_half, cursor_in_left_half; @@ -3710,7 +3710,7 @@ void init_client_properties(Client *c) { c->iscustomsize = 0; c->master_mfact_per = 0.0f; c->master_inner_per = 0.0f; - c->stack_innder_per = 0.0f; + c->stack_inner_per = 0.0f; c->isterm = 0; c->allow_csd = 0; c->force_maximize = 0; @@ -4311,7 +4311,7 @@ void exchange_two_client(Client *c1, Client *c2) { uint32_t tmp_tags; double master_inner_per = 0.0f; double master_mfact_per = 0.0f; - double stack_innder_per = 0.0f; + double stack_inner_per = 0.0f; if (c1 == NULL || c2 == NULL || (!exchange_cross_monitor && c1->mon != c2->mon)) { @@ -4320,15 +4320,15 @@ void exchange_two_client(Client *c1, Client *c2) { master_inner_per = c1->master_inner_per; master_mfact_per = c1->master_mfact_per; - stack_innder_per = c1->stack_innder_per; + stack_inner_per = c1->stack_inner_per; c1->master_inner_per = c2->master_inner_per; c1->master_mfact_per = c2->master_mfact_per; - c1->stack_innder_per = c2->stack_innder_per; + c1->stack_inner_per = c2->stack_inner_per; c2->master_inner_per = master_inner_per; c2->master_mfact_per = master_mfact_per; - c2->stack_innder_per = stack_innder_per; + c2->stack_inner_per = stack_inner_per; struct wl_list *tmp1_prev = c1->link.prev; struct wl_list *tmp2_prev = c2->link.prev; From 91f4604199d6fc7f0296fc4e0f78e342b8761d01 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Fri, 12 Dec 2025 11:08:53 +0800 Subject: [PATCH 392/591] feat: add fadein fadeout curve --- config.conf | 2 ++ src/animation/client.h | 14 ++++++++++++-- src/animation/common.h | 20 ++++++++++++++++++++ src/animation/layer.h | 18 ++++++++++++++---- src/config/parse_config.h | 34 ++++++++++++++++++++++++++++++++++ src/config/preset.h | 12 +++++++----- src/mango.c | 4 +++- 7 files changed, 92 insertions(+), 12 deletions(-) diff --git a/config.conf b/config.conf index 4c8d8d3a..e93b3e6c 100644 --- a/config.conf +++ b/config.conf @@ -48,6 +48,8 @@ animation_curve_move=0.46,1.0,0.29,1 animation_curve_tag=0.46,1.0,0.29,1 animation_curve_close=0.08,0.92,0,1 animation_curve_focus=0.46,1.0,0.29,1 +animation_curve_opafadeout=0.5,0.5,0.5,0.5 +animation_curve_opafadein=0.46,1.0,0.29,1 # Scroller Layout Setting scroller_structs=20 diff --git a/src/animation/client.h b/src/animation/client.h index 67f4c10f..b4f70e0c 100644 --- a/src/animation/client.h +++ b/src/animation/client.h @@ -630,6 +630,7 @@ void fadeout_client_animation_next_tick(Client *c) { int type = c->animation.action = c->animation.action; double factor = find_animation_curve_at(animation_passed, type); + uint32_t width = c->animation.initial.width + (c->current.width - c->animation.initial.width) * factor; uint32_t height = @@ -650,7 +651,13 @@ void fadeout_client_animation_next_tick(Client *c) { .height = height, }; - double opacity = MAX(fadeout_begin_opacity - animation_passed, 0); + double opacity_eased_progress = + find_animation_curve_at(animation_passed, OPAFADEOUT); + + double percent = fadeout_begin_opacity - + (opacity_eased_progress * fadeout_begin_opacity); + + double opacity = MAX(percent, 0); if (animation_fade_out && !c->nofadeout) wlr_scene_node_for_each_buffer(&c->scene->node, @@ -1109,8 +1116,11 @@ bool client_apply_focus_opacity(Client *c) { ? (double)passed_time / (double)c->animation.duration : 1.0; + double opacity_eased_progress = + find_animation_curve_at(linear_progress, OPAFADEIN); + float percent = - animation_fade_in && !c->nofadein ? linear_progress : 1.0; + animation_fade_in && !c->nofadein ? opacity_eased_progress : 1.0; float opacity = c == selmon->sel ? c->focused_opacity : c->unfocused_opacity; diff --git a/src/animation/common.h b/src/animation/common.h index 2ff6744a..0f662d62 100644 --- a/src/animation/common.h +++ b/src/animation/common.h @@ -11,6 +11,10 @@ struct dvec2 calculate_animation_curve_at(double t, int type) { animation_curve = animation_curve_close; } else if (type == FOCUS) { animation_curve = animation_curve_focus; + } else if (type == OPAFADEIN) { + animation_curve = animation_curve_opafadein; + } else if (type == OPAFADEOUT) { + animation_curve = animation_curve_opafadeout; } else { animation_curve = animation_curve_move; } @@ -32,6 +36,10 @@ void init_baked_points(void) { calloc(BAKED_POINTS_COUNT, sizeof(*baked_points_close)); baked_points_focus = calloc(BAKED_POINTS_COUNT, sizeof(*baked_points_focus)); + baked_points_opafadein = + calloc(BAKED_POINTS_COUNT, sizeof(*baked_points_opafadein)); + baked_points_opafadeout = + calloc(BAKED_POINTS_COUNT, sizeof(*baked_points_opafadeout)); for (uint32_t i = 0; i < BAKED_POINTS_COUNT; i++) { baked_points_move[i] = calculate_animation_curve_at( @@ -53,6 +61,14 @@ void init_baked_points(void) { baked_points_focus[i] = calculate_animation_curve_at( (double)i / (BAKED_POINTS_COUNT - 1), FOCUS); } + for (uint32_t i = 0; i < BAKED_POINTS_COUNT; i++) { + baked_points_opafadein[i] = calculate_animation_curve_at( + (double)i / (BAKED_POINTS_COUNT - 1), OPAFADEIN); + } + for (uint32_t i = 0; i < BAKED_POINTS_COUNT; i++) { + baked_points_opafadeout[i] = calculate_animation_curve_at( + (double)i / (BAKED_POINTS_COUNT - 1), OPAFADEOUT); + } } double find_animation_curve_at(double t, int type) { @@ -71,6 +87,10 @@ double find_animation_curve_at(double t, int type) { baked_points = baked_points_close; } else if (type == FOCUS) { baked_points = baked_points_focus; + } else if (type == OPAFADEIN) { + baked_points = baked_points_opafadein; + } else if (type == OPAFADEOUT) { + baked_points = baked_points_opafadeout; } else { baked_points = baked_points_move; } diff --git a/src/animation/layer.h b/src/animation/layer.h index e36ddd10..57e0c149 100644 --- a/src/animation/layer.h +++ b/src/animation/layer.h @@ -276,7 +276,13 @@ void fadeout_layer_animation_next_tick(LayerSurface *l) { .height = height, }; - double opacity = MAX(fadeout_begin_opacity - animation_passed, 0.0f); + double opacity_eased_progress = + find_animation_curve_at(animation_passed, OPAFADEOUT); + + double percent = fadeout_begin_opacity - + (opacity_eased_progress * fadeout_begin_opacity); + + double opacity = MAX(percent, 0.0f); if (animation_fade_out) wlr_scene_node_for_each_buffer(&l->scene->node, @@ -318,9 +324,13 @@ void layer_animation_next_tick(LayerSurface *l) { uint32_t y = l->animation.initial.y + (l->current.y - l->animation.initial.y) * factor; - double opacity = MIN(fadein_begin_opacity + - animation_passed * (1.0 - fadein_begin_opacity), - 1.0f); + double opacity_eased_progress = + find_animation_curve_at(animation_passed, OPAFADEIN); + + double opacity = + MIN(fadein_begin_opacity + + opacity_eased_progress * (1.0 - fadein_begin_opacity), + 1.0f); if (animation_fade_in) wlr_scene_node_for_each_buffer(&l->scene->node, diff --git a/src/config/parse_config.h b/src/config/parse_config.h index 0479c6d2..4da82c50 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -194,6 +194,8 @@ typedef struct { double animation_curve_tag[4]; double animation_curve_close[4]; double animation_curve_focus[4]; + double animation_curve_opafadein[4]; + double animation_curve_opafadeout[4]; int scroller_structs; float scroller_default_proportion; @@ -1181,6 +1183,22 @@ void parse_option(Config *config, char *key, char *value) { "Error: Failed to parse animation_curve_focus: %s\n", value); } + } else if (strcmp(key, "animation_curve_opafadein") == 0) { + int num = + parse_double_array(value, config->animation_curve_opafadein, 4); + if (num != 4) { + fprintf(stderr, + "Error: Failed to parse animation_curve_opafadein: %s\n", + value); + } + } else if (strcmp(key, "animation_curve_opafadeout") == 0) { + int num = + parse_double_array(value, config->animation_curve_opafadeout, 4); + if (num != 4) { + fprintf(stderr, + "Error: Failed to parse animation_curve_opafadeout: %s\n", + value); + } } else if (strcmp(key, "scroller_structs") == 0) { config->scroller_structs = atoi(value); } else if (strcmp(key, "scroller_default_proportion") == 0) { @@ -2398,6 +2416,14 @@ void free_baked_points(void) { free(baked_points_focus); baked_points_focus = NULL; } + if (baked_points_opafadein) { + free(baked_points_opafadein); + baked_points_opafadein = NULL; + } + if (baked_points_opafadeout) { + free(baked_points_opafadeout); + baked_points_opafadeout = NULL; + } } void free_config(void) { @@ -2810,6 +2836,10 @@ void override_config(void) { sizeof(animation_curve_close)); memcpy(animation_curve_focus, config.animation_curve_focus, sizeof(animation_curve_focus)); + memcpy(animation_curve_opafadein, config.animation_curve_opafadein, + sizeof(animation_curve_opafadein)); + memcpy(animation_curve_opafadeout, config.animation_curve_opafadeout, + sizeof(animation_curve_opafadeout)); } void set_value_default() { @@ -2958,6 +2988,10 @@ void set_value_default() { sizeof(animation_curve_close)); memcpy(config.animation_curve_focus, animation_curve_focus, sizeof(animation_curve_focus)); + memcpy(config.animation_curve_opafadein, animation_curve_opafadein, + sizeof(animation_curve_opafadein)); + memcpy(config.animation_curve_opafadeout, animation_curve_opafadeout, + sizeof(animation_curve_opafadeout)); memcpy(config.rootcolor, rootcolor, sizeof(rootcolor)); memcpy(config.bordercolor, bordercolor, sizeof(bordercolor)); diff --git a/src/config/preset.h b/src/config/preset.h index ed743a83..7b45315d 100644 --- a/src/config/preset.h +++ b/src/config/preset.h @@ -26,11 +26,13 @@ uint32_t animation_duration_open = 400; // Animation open speed uint32_t animation_duration_tag = 300; // Animation tag speed uint32_t animation_duration_close = 300; // Animation close speed uint32_t animation_duration_focus = 0; // Animation focus opacity speed -double animation_curve_move[4] = {0.46, 1.0, 0.29, 0.99}; // 动画曲线 -double animation_curve_open[4] = {0.46, 1.0, 0.29, 0.99}; // 动画曲线 -double animation_curve_tag[4] = {0.46, 1.0, 0.29, 0.99}; // 动画曲线 -double animation_curve_close[4] = {0.46, 1.0, 0.29, 0.99}; // 动画曲线 -double animation_curve_focus[4] = {0.46, 1.0, 0.29, 0.99}; // 动画曲线 +double animation_curve_move[4] = {0.46, 1.0, 0.29, 0.99}; // 动画曲线 +double animation_curve_open[4] = {0.46, 1.0, 0.29, 0.99}; // 动画曲线 +double animation_curve_tag[4] = {0.46, 1.0, 0.29, 0.99}; // 动画曲线 +double animation_curve_close[4] = {0.46, 1.0, 0.29, 0.99}; // 动画曲线 +double animation_curve_focus[4] = {0.46, 1.0, 0.29, 0.99}; // 动画曲线 +double animation_curve_opafadein[4] = {0.46, 1.0, 0.29, 0.99}; // 动画曲线 +double animation_curve_opafadeout[4] = {0.5, 0.5, 0.5, 0.5}; // 动画曲线 /* appearance */ uint32_t axis_bind_apply_timeout = 100; // 滚轮绑定动作的触发的时间间隔 diff --git a/src/mango.c b/src/mango.c index ce22e31d..45a0e64b 100644 --- a/src/mango.c +++ b/src/mango.c @@ -165,7 +165,7 @@ enum { }; /* EWMH atoms */ #endif enum { UP, DOWN, LEFT, RIGHT, UNDIR }; /* smartmovewin */ -enum { NONE, OPEN, MOVE, CLOSE, TAG, FOCUS }; +enum { NONE, OPEN, MOVE, CLOSE, TAG, FOCUS, OPAFADEIN, OPAFADEOUT }; enum { UNFOLD, FOLD, INVALIDFOLD }; enum { PREV, NEXT }; enum { STATE_UNSPECIFIED = 0, STATE_ENABLED, STATE_DISABLED }; @@ -850,6 +850,8 @@ struct dvec2 *baked_points_open; struct dvec2 *baked_points_tag; struct dvec2 *baked_points_close; struct dvec2 *baked_points_focus; +struct dvec2 *baked_points_opafadein; +struct dvec2 *baked_points_opafadeout; static struct wl_event_source *hide_source; static bool cursor_hidden = false; From fa4eb322b6dc84633ece83b100e4e496bff373be Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Fri, 12 Dec 2025 12:23:46 +0800 Subject: [PATCH 393/591] fix: crash when reload_config --- src/config/parse_config.h | 2 +- src/mango.c | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/config/parse_config.h b/src/config/parse_config.h index 4da82c50..2e5549be 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -3316,5 +3316,5 @@ int reload_config(const Arg *arg) { parse_config(); reset_option(); printstatus(); - return 0; + return 1; } diff --git a/src/mango.c b/src/mango.c index 45a0e64b..ae840912 100644 --- a/src/mango.c +++ b/src/mango.c @@ -3435,13 +3435,14 @@ keybinding(uint32_t state, bool locked, uint32_t mods, xkb_keysym_t sym, keycode == k->keysymcode.keycode.keycode3))) && k->func) { - isbreak = k->func(&k->arg); - if (!k->ispassapply) handled = 1; else handled = 0; + isbreak = k->func(&k->arg); + + if (isbreak) break; } From 47ad3b7c2b128d9d77fb8a6a6a95d3ffc74658a5 Mon Sep 17 00:00:00 2001 From: hsd_ Date: Fri, 12 Dec 2025 13:31:47 +0000 Subject: [PATCH 394/591] fix typo in 'layer animation' section --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9780ac6e..7818c36b 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ Scroller Layout https://github.com/user-attachments/assets/c9bf9415-fad1-4400-bcdc-3ad2d76de85a -Layer animaiton +Layer animation https://github.com/user-attachments/assets/014c893f-115c-4ae9-8342-f9ae3e9a0df0 From 06dd3423a19768b1b33f7a78167b222fa6380ec9 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sat, 13 Dec 2025 09:50:36 +0800 Subject: [PATCH 395/591] opt: optimize ws module --- src/ext-protocol/ext-workspace.h | 4 +- src/ext-protocol/wlr_ext_workspace_v1.c | 478 +++++++++++++----------- src/ext-protocol/wlr_ext_workspace_v1.h | 58 ++- src/mango.c | 1 - 4 files changed, 285 insertions(+), 256 deletions(-) diff --git a/src/ext-protocol/ext-workspace.h b/src/ext-protocol/ext-workspace.h index d4e0e514..8ff53cc0 100644 --- a/src/ext-protocol/ext-workspace.h +++ b/src/ext-protocol/ext-workspace.h @@ -1,8 +1,8 @@ #include "wlr_ext_workspace_v1.h" #define EXT_WORKSPACE_ENABLE_CAPS \ - WLR_EXT_WORKSPACE_HANDLE_V1_CAP_ACTIVATE | \ - WLR_EXT_WORKSPACE_HANDLE_V1_CAP_DEACTIVATE + EXT_WORKSPACE_HANDLE_V1_WORKSPACE_CAPABILITIES_ACTIVATE | \ + EXT_WORKSPACE_HANDLE_V1_WORKSPACE_CAPABILITIES_DEACTIVATE typedef struct Monitor Monitor; diff --git a/src/ext-protocol/wlr_ext_workspace_v1.c b/src/ext-protocol/wlr_ext_workspace_v1.c index 3f80e9f2..2d781b34 100644 --- a/src/ext-protocol/wlr_ext_workspace_v1.c +++ b/src/ext-protocol/wlr_ext_workspace_v1.c @@ -29,7 +29,7 @@ struct wlr_ext_workspace_v1_request { // ACTIVATE / DEACTIVATE / ASSIGN / REMOVE struct wlr_ext_workspace_handle_v1 *workspace; - struct wl_list link; // wlr_ext_workspace_manager_client_v1.requests + struct wl_list link; // wlr_ext_workspace_manager_v1_resource.requests }; struct wlr_ext_workspace_v1_group_output { @@ -41,33 +41,40 @@ struct wlr_ext_workspace_v1_group_output { }; // These structs wrap wl_resource of each interface to access the request queue -// (wlr_ext_workspace_manager_client_v1.requests) assigned per manager resource +// (wlr_ext_workspace_manager_v1_resource.requests) assigned per manager +// resource -struct wlr_ext_workspace_manager_client_v1 { +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 link; // wlr_ext_workspace_manager_v1.clients + 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_client_v1 { +struct wlr_ext_workspace_group_v1_resource { struct wl_resource *resource; struct wlr_ext_workspace_group_handle_v1 *group; - struct wlr_ext_workspace_manager_client_v1 *manager; - struct wl_list link; // wlr_ext_workspace_group_v1.clients + 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_client_v1 { +struct wlr_ext_workspace_v1_resource { struct wl_resource *resource; struct wlr_ext_workspace_handle_v1 *workspace; - struct wlr_ext_workspace_manager_client_v1 *manager; - struct wl_list link; // wlr_ext_workspace_v1.clients + 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_client_v1 * -group_client_from_resource(struct wl_resource *resource) { +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); @@ -75,8 +82,8 @@ group_client_from_resource(struct wl_resource *resource) { static const struct ext_workspace_handle_v1_interface workspace_impl; -static struct wlr_ext_workspace_client_v1 * -workspace_client_from_resource(struct wl_resource *resource) { +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); @@ -84,8 +91,8 @@ workspace_client_from_resource(struct wl_resource *resource) { static const struct ext_workspace_manager_v1_interface manager_impl; -static struct wlr_ext_workspace_manager_client_v1 * -manager_client_from_resource(struct wl_resource *resource) { +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); @@ -98,9 +105,9 @@ static void workspace_handle_destroy(struct wl_client *client, static void workspace_handle_activate(struct wl_client *client, struct wl_resource *workspace_resource) { - struct wlr_ext_workspace_client_v1 *workspace = - workspace_client_from_resource(workspace_resource); - if (!workspace) { + struct wlr_ext_workspace_v1_resource *workspace_res = + workspace_resource_from_resource(workspace_resource); + if (!workspace_res) { return; } @@ -110,16 +117,16 @@ static void workspace_handle_activate(struct wl_client *client, return; } req->type = WLR_EXT_WORKSPACE_V1_REQUEST_ACTIVATE; - req->workspace = workspace->workspace; - wl_list_insert(workspace->manager->requests.prev, &req->link); + req->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_client_v1 *workspace = - workspace_client_from_resource(workspace_resource); - if (!workspace) { + struct wlr_ext_workspace_v1_resource *workspace_res = + workspace_resource_from_resource(workspace_resource); + if (!workspace_res) { return; } @@ -129,18 +136,18 @@ workspace_handle_deactivate(struct wl_client *client, return; } req->type = WLR_EXT_WORKSPACE_V1_REQUEST_DEACTIVATE; - req->workspace = workspace->workspace; - wl_list_insert(workspace->manager->requests.prev, &req->link); + req->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_client_v1 *workspace = - workspace_client_from_resource(workspace_resource); - struct wlr_ext_workspace_group_client_v1 *group = - group_client_from_resource(group_resource); - if (!workspace || !group) { + 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; } @@ -150,16 +157,16 @@ static void workspace_handle_assign(struct wl_client *client, return; } req->type = WLR_EXT_WORKSPACE_V1_REQUEST_ASSIGN; - req->group = group->group; - req->workspace = workspace->workspace; - wl_list_insert(workspace->manager->requests.prev, &req->link); + req->group = group_res->group; + req->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_client_v1 *workspace = - workspace_client_from_resource(workspace_resource); - if (!workspace) { + struct wlr_ext_workspace_v1_resource *workspace_res = + workspace_resource_from_resource(workspace_resource); + if (!workspace_res) { return; } @@ -169,8 +176,8 @@ static void workspace_handle_remove(struct wl_client *client, return; } req->type = WLR_EXT_WORKSPACE_V1_REQUEST_REMOVE; - req->workspace = workspace->workspace; - wl_list_insert(workspace->manager->requests.prev, &req->link); + req->workspace = workspace_res->workspace; + wl_list_insert(workspace_res->manager->requests.prev, &req->link); } static const struct ext_workspace_handle_v1_interface workspace_impl = { @@ -184,9 +191,9 @@ static const struct ext_workspace_handle_v1_interface workspace_impl = { static void group_handle_create_workspace(struct wl_client *client, struct wl_resource *group_resource, const char *name) { - struct wlr_ext_workspace_group_client_v1 *group = - group_client_from_resource(group_resource); - if (!group) { + struct wlr_ext_workspace_group_v1_resource *group_res = + group_resource_from_resource(group_resource); + if (!group_res) { return; } @@ -195,9 +202,15 @@ static void group_handle_create_workspace(struct wl_client *client, wl_resource_post_no_memory(group_resource); return; } + req->name = strdup(name); + if (!req->name) { + free(req); + wl_resource_post_no_memory(group_resource); + return; + } req->type = WLR_EXT_WORKSPACE_V1_REQUEST_CREATE_WORKSPACE; - req->group = group->group; - wl_list_insert(group->manager->requests.prev, &req->link); + req->group = group_res->group; + wl_list_insert(group_res->manager->requests.prev, &req->link); } static void group_handle_destroy(struct wl_client *client, @@ -210,89 +223,94 @@ static const struct ext_workspace_group_handle_v1_interface group_impl = { .destroy = group_handle_destroy, }; -static void -destroy_workspace_client(struct wlr_ext_workspace_client_v1 *workspace_client) { - wl_list_remove(&workspace_client->link); - wl_resource_set_user_data(workspace_client->resource, NULL); - free(workspace_client); +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_client_v1 *workspace_client = - workspace_client_from_resource(resource); - if (workspace_client) { - destroy_workspace_client(workspace_client); + 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_client_v1 *create_workspace_client( +static struct wlr_ext_workspace_v1_resource *create_workspace_resource( struct wlr_ext_workspace_handle_v1 *workspace, - struct wlr_ext_workspace_manager_client_v1 *manager_client) { - struct wlr_ext_workspace_client_v1 *workspace_client = - calloc(1, sizeof(*workspace_client)); - if (!workspace_client) { + 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_client->resource); - workspace_client->resource = wl_resource_create( - client, &ext_workspace_handle_v1_interface, - wl_resource_get_version(manager_client->resource), 0); - if (!workspace_client->resource) { - free(workspace_client); + 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_client->resource, &workspace_impl, - workspace_client, - workspace_resource_destroy); + wl_resource_set_implementation(workspace_res->resource, &workspace_impl, + workspace_res, workspace_resource_destroy); - workspace_client->workspace = workspace; - workspace_client->manager = manager_client; - wl_list_insert(&workspace->clients, &workspace_client->link); + 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_client; + return workspace_res; } static void -destroy_group_client(struct wlr_ext_workspace_group_client_v1 *group_client) { - wl_list_remove(&group_client->link); - wl_resource_set_user_data(group_client->resource, NULL); - free(group_client); +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_client_v1 *group_client = - group_client_from_resource(resource); - if (group_client) { - destroy_group_client(group_client); + 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_client_v1 *create_group_client( +static struct wlr_ext_workspace_group_v1_resource *create_group_resource( struct wlr_ext_workspace_group_handle_v1 *group, - struct wlr_ext_workspace_manager_client_v1 *manager_client) { - struct wlr_ext_workspace_group_client_v1 *group_client = - calloc(1, sizeof(*group_client)); - if (!group_client) { + 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_client->resource); - uint32_t version = wl_resource_get_version(manager_client->resource); - group_client->resource = wl_resource_create( + 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_client->resource == NULL) { - free(group_client); + if (group_res->resource == NULL) { + free(group_res); return NULL; } - wl_resource_set_implementation(group_client->resource, &group_impl, - group_client, group_handle_resource_destroy); + wl_resource_set_implementation(group_res->resource, &group_impl, group_res, + group_handle_resource_destroy); - group_client->group = group; - group_client->manager = manager_client; - wl_list_insert(&group->clients, &group_client->link); + 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_client; + return group_res; } static void destroy_request(struct wlr_ext_workspace_v1_request *req) { @@ -303,18 +321,22 @@ static void destroy_request(struct wlr_ext_workspace_v1_request *req) { static void manager_handle_commit(struct wl_client *client, struct wl_resource *resource) { - struct wlr_ext_workspace_manager_client_v1 *manager = - manager_client_from_resource(resource); - if (!manager) { + struct wlr_ext_workspace_manager_v1_resource *manager_res = + manager_resource_from_resource(resource); + if (!manager_res) { return; } struct wlr_ext_workspace_v1_request *req, *tmp; - wl_list_for_each_safe(req, tmp, &manager->requests, link) { + wl_list_for_each_safe(req, tmp, &manager_res->requests, link) { switch (req->type) { - case WLR_EXT_WORKSPACE_V1_REQUEST_CREATE_WORKSPACE: + case WLR_EXT_WORKSPACE_V1_REQUEST_CREATE_WORKSPACE:; + struct wlr_ext_workspace_group_handle_v1_create_workspace_event + event = { + .name = req->name, + }; wl_signal_emit_mutable(&req->group->events.create_workspace, - req->name); + &event); break; case WLR_EXT_WORKSPACE_V1_REQUEST_ACTIVATE: wl_signal_emit_mutable(&req->workspace->events.activate, NULL); @@ -323,13 +345,11 @@ static void manager_handle_commit(struct wl_client *client, wl_signal_emit_mutable(&req->workspace->events.deactivate, NULL); break; case WLR_EXT_WORKSPACE_V1_REQUEST_ASSIGN: - wl_signal_emit_mutable(&req->workspace->events.assign, &req->group); + wl_signal_emit_mutable(&req->workspace->events.assign, req->group); break; case WLR_EXT_WORKSPACE_V1_REQUEST_REMOVE: wl_signal_emit_mutable(&req->workspace->events.remove, NULL); break; - default: - abort(); } destroy_request(req); } @@ -338,9 +358,9 @@ static void manager_handle_commit(struct wl_client *client, static void handle_idle(void *data) { struct wlr_ext_workspace_manager_v1 *manager = data; - struct wlr_ext_workspace_manager_client_v1 *manager_client; - wl_list_for_each(manager_client, &manager->clients, link) { - ext_workspace_manager_v1_send_done(manager_client->resource); + 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; } @@ -354,9 +374,9 @@ manager_schedule_done(struct wlr_ext_workspace_manager_v1 *manager) { } static void -workspace_send_details(struct wlr_ext_workspace_client_v1 *workspace_client) { - struct wlr_ext_workspace_handle_v1 *workspace = workspace_client->workspace; - struct wl_resource *resource = workspace_client->resource; +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) { @@ -384,29 +404,41 @@ static const struct ext_workspace_manager_v1_interface manager_impl = { .stop = manager_handle_stop, }; -static void destroy_manager_client( - struct wlr_ext_workspace_manager_client_v1 *manager_client) { +static void destroy_manager_resource( + 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_client->requests, link) { + wl_list_for_each_safe(req, tmp, &manager_res->requests, link) { destroy_request(req); } - wl_list_remove(&manager_client->link); - wl_resource_set_user_data(manager_client->resource, NULL); - free(manager_client); + 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_client_v1 *manager_client = - manager_client_from_resource(resource); - if (manager_client) { - destroy_manager_client(manager_client); + 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_client_v1 *group_client) { - struct wlr_ext_workspace_group_handle_v1 *group = group_client->group; - struct wl_resource *resource = group_client->resource; +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); @@ -430,65 +462,67 @@ 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_client_v1 *manager_client = - calloc(1, sizeof(*manager_client)); - if (!manager_client) { + 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_client->manager = manager; - wl_list_init(&manager_client->requests); - wl_list_insert(&manager->clients, &manager_client->link); + 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_client->resource = wl_resource_create( + manager_res->resource = wl_resource_create( client, &ext_workspace_manager_v1_interface, version, id); - if (!manager_client->resource) { - free(manager_client); + if (!manager_res->resource) { + free(manager_res); wl_client_post_no_memory(client); return; } - wl_resource_set_implementation(manager_client->resource, &manager_impl, - manager_client, manager_resource_destroy); + 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_client_v1 *group_client = - create_group_client(group, manager_client); - if (!group_client) { - wl_resource_post_no_memory(manager_client->resource); + 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_client->resource, - group_client->resource); - group_send_details(group_client); + 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_client_v1 *workspace_client = - create_workspace_client(workspace, manager_client); - if (!workspace) { - wl_client_post_no_memory(client); + 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_client->resource, - workspace_client->resource); - workspace_send_details(workspace_client); + 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_client_v1 *group_client; - wl_list_for_each(group_client, &workspace->group->clients, link) { - if (group_client->manager == manager_client) { + 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_client->resource, workspace_client->resource); + group_res->resource, workspace_res->resource); } } } - manager_schedule_done(manager); + ext_workspace_manager_v1_send_done(manager_res->resource); } static void manager_handle_display_destroy(struct wl_listener *listener, @@ -509,9 +543,9 @@ static void manager_handle_display_destroy(struct wl_listener *listener, wlr_ext_workspace_handle_v1_destroy(workspace); } - struct wlr_ext_workspace_manager_client_v1 *manager_client, *tmp3; - wl_list_for_each_safe(manager_client, tmp3, &manager->clients, link) { - destroy_manager_client(manager_client); + 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) { @@ -548,7 +582,7 @@ wlr_ext_workspace_manager_v1_create(struct wl_display *display, wl_list_init(&manager->groups); wl_list_init(&manager->workspaces); - wl_list_init(&manager->clients); + wl_list_init(&manager->resources); wl_signal_init(&manager->events.destroy); return manager; @@ -566,22 +600,22 @@ wlr_ext_workspace_group_handle_v1_create( group->caps = caps; wl_list_init(&group->outputs); - wl_list_init(&group->clients); + wl_list_init(&group->resources); wl_signal_init(&group->events.create_workspace); wl_signal_init(&group->events.destroy); wl_list_insert(manager->groups.prev, &group->link); - struct wlr_ext_workspace_manager_client_v1 *manager_client; - wl_list_for_each(manager_client, &manager->clients, link) { - struct wlr_ext_workspace_group_client_v1 *group_client = - create_group_client(group, manager_client); - if (!group_client) { + 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_client->resource, - group_client->resource); - group_send_details(group_client); + ext_workspace_manager_v1_send_workspace_group(manager_res->resource, + group_res->resource); + group_send_details(group_res); } manager_schedule_done(manager); @@ -594,19 +628,19 @@ workspace_send_group(struct wlr_ext_workspace_handle_v1 *workspace, struct wlr_ext_workspace_group_handle_v1 *group, bool enter) { - struct wlr_ext_workspace_client_v1 *workspace_client; - wl_list_for_each(workspace_client, &workspace->clients, link) { - struct wlr_ext_workspace_group_client_v1 *group_client; - wl_list_for_each(group_client, &group->clients, link) { - if (group_client->manager != workspace_client->manager) { + 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_client->resource, workspace_client->resource); + group_res->resource, workspace_res->resource); } else { ext_workspace_group_handle_v1_send_workspace_leave( - group_client->resource, workspace_client->resource); + group_res->resource, workspace_res->resource); } } } @@ -625,10 +659,9 @@ destroy_group_output(struct wlr_ext_workspace_v1_group_output *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_client_v1 *group_client; - wl_list_for_each(group_client, &group->clients, link) { - struct wl_client *client = - wl_resource_get_client(group_client->resource); + 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) { @@ -637,10 +670,10 @@ static void group_send_output(struct wlr_ext_workspace_group_handle_v1 *group, } if (enter) { ext_workspace_group_handle_v1_send_output_enter( - group_client->resource, output_resource); + group_res->resource, output_resource); } else { ext_workspace_group_handle_v1_send_output_leave( - group_client->resource, output_resource); + group_res->resource, output_resource); } } } @@ -650,6 +683,10 @@ static void group_send_output(struct wlr_ext_workspace_group_handle_v1 *group, 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.create_workspace.listener_list)); @@ -663,16 +700,16 @@ void wlr_ext_workspace_group_handle_v1_destroy( } } - struct wlr_ext_workspace_group_client_v1 *group_client, *tmp; - wl_list_for_each_safe(group_client, tmp, &group->clients, link) { - ext_workspace_group_handle_v1_send_removed(group_client->resource); - destroy_group_client(group_client); + 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_client_v1 *manager_client; - wl_list_for_each(manager_client, &group->manager->clients, link) { + struct wlr_ext_workspace_manager_v1_resource *manager_res; + wl_list_for_each(manager_res, &group->manager->resources, link) { struct wlr_ext_workspace_v1_request *req, *tmp2; - wl_list_for_each_safe(req, tmp2, &manager_client->requests, link) { + wl_list_for_each_safe(req, tmp2, &manager_res->requests, link) { if (req->group == group) { destroy_request(req); } @@ -697,11 +734,11 @@ static void handle_output_bind(struct wl_listener *listener, void *data) { struct wlr_output_event_bind *event = data; struct wl_client *client = wl_resource_get_client(event->resource); - struct wlr_ext_workspace_group_client_v1 *group_client; - wl_list_for_each(group_client, &group_output->group->clients, link) { - if (wl_resource_get_client(group_client->resource) == client) { - ext_workspace_group_handle_v1_send_output_enter( - group_client->resource, 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); } } @@ -778,11 +815,12 @@ wlr_ext_workspace_handle_v1_create(struct wlr_ext_workspace_manager_v1 *manager, if (id) { workspace->id = strdup(id); if (!workspace->id) { + free(workspace); return NULL; } } - wl_list_init(&workspace->clients); + wl_list_init(&workspace->resources); wl_array_init(&workspace->coordinates); wl_signal_init(&workspace->events.activate); wl_signal_init(&workspace->events.deactivate); @@ -792,16 +830,16 @@ wlr_ext_workspace_handle_v1_create(struct wlr_ext_workspace_manager_v1 *manager, wl_list_insert(&manager->workspaces, &workspace->link); - struct wlr_ext_workspace_manager_client_v1 *manager_client; - wl_list_for_each(manager_client, &manager->clients, link) { - struct wlr_ext_workspace_client_v1 *workspace_client = - create_workspace_client(workspace, manager_client); - if (!workspace_client) { + 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_client->resource, - workspace_client->resource); - workspace_send_details(workspace_client); + ext_workspace_manager_v1_send_workspace(manager_res->resource, + workspace_res->resource); + workspace_send_details(workspace_res); } manager_schedule_done(manager); @@ -811,6 +849,10 @@ wlr_ext_workspace_handle_v1_create(struct wlr_ext_workspace_manager_v1 *manager, 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.activate.listener_list)); @@ -823,16 +865,16 @@ void wlr_ext_workspace_handle_v1_destroy( workspace_send_group(workspace, workspace->group, false); } - struct wlr_ext_workspace_client_v1 *workspace_client, *tmp; - wl_list_for_each_safe(workspace_client, tmp, &workspace->clients, link) { - ext_workspace_handle_v1_send_removed(workspace_client->resource); - destroy_workspace_client(workspace_client); + 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_client_v1 *manager_client; - wl_list_for_each(manager_client, &workspace->manager->clients, link) { + struct wlr_ext_workspace_manager_v1_resource *manager_res; + wl_list_for_each(manager_res, &workspace->manager->resources, link) { struct wlr_ext_workspace_v1_request *req, *tmp2; - wl_list_for_each_safe(req, tmp2, &manager_client->requests, link) { + wl_list_for_each_safe(req, tmp2, &manager_res->requests, link) { if (req->workspace == workspace) { destroy_request(req); } @@ -856,7 +898,7 @@ void wlr_ext_workspace_handle_v1_set_group( } if (workspace->group) { - workspace_send_group(workspace, group, false); + workspace_send_group(workspace, workspace->group, false); } workspace->group = group; if (group) { @@ -878,9 +920,9 @@ void wlr_ext_workspace_handle_v1_set_name( return; } - struct wlr_ext_workspace_client_v1 *workspace_client; - wl_list_for_each(workspace_client, &workspace->clients, link) { - ext_workspace_handle_v1_send_name(workspace_client->resource, + 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); } @@ -905,9 +947,9 @@ void wlr_ext_workspace_handle_v1_set_coordinates( wl_array_init(&workspace->coordinates); wl_array_copy(&workspace->coordinates, coordinates); - struct wlr_ext_workspace_client_v1 *workspace_client; - wl_list_for_each(workspace_client, &workspace->clients, link) { - ext_workspace_handle_v1_send_coordinates(workspace_client->resource, + 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); } @@ -927,9 +969,9 @@ static void workspace_set_state(struct wlr_ext_workspace_handle_v1 *workspace, return; } - struct wlr_ext_workspace_client_v1 *workspace_client; - wl_list_for_each(workspace_client, &workspace->clients, link) { - ext_workspace_handle_v1_send_state(workspace_client->resource, + 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); } diff --git a/src/ext-protocol/wlr_ext_workspace_v1.h b/src/ext-protocol/wlr_ext_workspace_v1.h index e1d285b2..a2a733b3 100644 --- a/src/ext-protocol/wlr_ext_workspace_v1.h +++ b/src/ext-protocol/wlr_ext_workspace_v1.h @@ -2,32 +2,11 @@ // TODO: remove this file // refer: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/5115 -/* - * 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 #include struct wlr_output; -enum wlr_ext_workspace_group_handle_v1_cap { - WLR_EXT_WORKSPACE_GROUP_HANDLE_V1_CAP_CREATE_WORKSPACE = 1 << 0, -}; - -enum wlr_ext_workspace_handle_v1_cap { - WLR_EXT_WORKSPACE_HANDLE_V1_CAP_ACTIVATE = 1 << 0, - WLR_EXT_WORKSPACE_HANDLE_V1_CAP_DEACTIVATE = 1 << 1, - WLR_EXT_WORKSPACE_HANDLE_V1_CAP_REMOVE = 1 << 2, - WLR_EXT_WORKSPACE_HANDLE_V1_CAP_ASSIGN = 1 << 3, -}; - struct wlr_ext_workspace_manager_v1 { struct wl_global *global; struct wl_list groups; // wlr_ext_workspace_group_handle_v1.link @@ -37,24 +16,33 @@ struct wlr_ext_workspace_manager_v1 { struct wl_signal destroy; } events; - struct wl_list clients; // wlr_ext_workspace_manager_client_v1.link - struct wl_event_source *idle_source; - struct wl_event_loop *event_loop; - struct wl_listener display_destroy; + 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_create_workspace_event { + const char *name; }; struct wlr_ext_workspace_group_handle_v1 { struct wlr_ext_workspace_manager_v1 *manager; - uint32_t caps; // wlr_ext_workspace_group_handle_v1_cap + uint32_t caps; // ext_workspace_group_handle_v1_group_capabilities struct { - struct wl_signal create_workspace; // const char * + struct wl_signal + create_workspace; // wlr_ext_workspace_group_handle_v1_create_workspace_event struct wl_signal destroy; } events; struct wl_list link; // wlr_ext_workspace_manager_v1.groups - struct wl_list outputs; // wlr_ext_workspace_v1_group_output.link - struct wl_list clients; // wlr_ext_workspace_manager_client_v1.link + 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 { @@ -63,7 +51,7 @@ struct wlr_ext_workspace_handle_v1 { char *id; char *name; struct wl_array coordinates; - uint32_t caps; // wlr_ext_workspace_handle_v1_cap + uint32_t caps; // ext_workspace_handle_v1_workspace_capabilities uint32_t state; // ext_workspace_handle_v1_state struct { @@ -74,9 +62,11 @@ struct wlr_ext_workspace_handle_v1 { struct wl_signal destroy; } events; - struct wl_list link; // wlr_ext_workspace_manager_v1.workspaces; + struct wl_list link; // wlr_ext_workspace_manager_v1.workspaces - struct wl_list clients; + struct { + struct wl_list resources; // wlr_ext_workspace_v1_resource.link + }; }; struct wlr_ext_workspace_manager_v1 * @@ -114,5 +104,3 @@ 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 diff --git a/src/mango.c b/src/mango.c index ae840912..1bd2c1fa 100644 --- a/src/mango.c +++ b/src/mango.c @@ -3442,7 +3442,6 @@ keybinding(uint32_t state, bool locked, uint32_t mods, xkb_keysym_t sym, isbreak = k->func(&k->arg); - if (isbreak) break; } From c151ad46e63ad07dff6026b065a2e02ce61a9ac7 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sat, 13 Dec 2025 11:43:39 +0800 Subject: [PATCH 396/591] feat: add layout tgmix --- src/layout/arrange.h | 3 ++- src/layout/horizontal.h | 11 +++++++++++ src/layout/layout.h | 3 +++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/layout/arrange.h b/src/layout/arrange.h index 3b52bd44..4a910aaf 100644 --- a/src/layout/arrange.h +++ b/src/layout/arrange.h @@ -485,7 +485,8 @@ void resize_tile_client(Client *grabc, bool isdrag, int offsetx, int offsety, const Layout *current_layout = grabc->mon->pertag->ltidxs[grabc->mon->pertag->curtag]; if (current_layout->id == TILE || current_layout->id == DECK || - current_layout->id == CENTER_TILE || current_layout->id == RIGHT_TILE + current_layout->id == CENTER_TILE || current_layout->id == RIGHT_TILE || + (current_layout->id == TGMIX && grabc->mon->visible_tiling_clients <= 3) ) { resize_tile_master_horizontal(grabc, isdrag, offsetx, offsety, time, diff --git a/src/layout/horizontal.h b/src/layout/horizontal.h index ce6617d5..a9d6248a 100644 --- a/src/layout/horizontal.h +++ b/src/layout/horizontal.h @@ -840,4 +840,15 @@ monocle(Monitor *m) { } if ((c = focustop(m))) wlr_scene_node_raise_to_top(&c->scene->node); +} + +void tgmix(Monitor *m) { + uint32_t n = m->visible_tiling_clients; + if (n <= 3) { + tile(m); + return; + } else { + grid(m); + return; + } } \ No newline at end of file diff --git a/src/layout/layout.h b/src/layout/layout.h index 62a3227d..169ab119 100644 --- a/src/layout/layout.h +++ b/src/layout/layout.h @@ -11,6 +11,7 @@ static void vertical_overview(Monitor *m); static void vertical_grid(Monitor *m); static void vertical_scroller(Monitor *m); static void vertical_deck(Monitor *mon); +static void tgmix(Monitor *m); /* layout(s) */ Layout overviewlayout = {"󰃇", overview, "overview"}; @@ -27,6 +28,7 @@ enum { VERTICAL_GRID, VERTICAL_DECK, RIGHT_TILE, + TGMIX, }; Layout layouts[] = { @@ -44,4 +46,5 @@ Layout layouts[] = { {"VT", vertical_tile, "vertical_tile", VERTICAL_TILE}, // 垂直平铺布局 {"VG", vertical_grid, "vertical_grid", VERTICAL_GRID}, // 垂直格子布局 {"VK", vertical_deck, "vertical_deck", VERTICAL_DECK}, // 垂直卡片布局 + {"TG", tgmix, "tgmix", TGMIX}, // 混合布局 }; \ No newline at end of file From 5b0c2d834f34f882c914f78d82aa1d75a6600875 Mon Sep 17 00:00:00 2001 From: Rexiel Scarlet <37258415+Rexcrazy804@users.noreply.github.com> Date: Sat, 13 Dec 2025 11:36:44 +0400 Subject: [PATCH 397/591] fix(nix): correctly set meson opt for enableXwayland flag --- nix/default.nix | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/nix/default.nix b/nix/default.nix index b72977d3..fd94bef2 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -31,6 +31,10 @@ in name = "source"; }; + mesonFlags = [ + (lib.mesonEnable "xwayland" enableXWayland) + ]; + nativeBuildInputs = [ meson ninja From 1d79b10437712c51ee45bf451fe683b268c8700e Mon Sep 17 00:00:00 2001 From: Rexiel Scarlet <37258415+Rexcrazy804@users.noreply.github.com> Date: Sat, 13 Dec 2025 11:38:12 +0400 Subject: [PATCH 398/591] refactor(nix): removed redundandt let in + formatting --- nix/default.nix | 98 ++++++++++++++++++++++++------------------------- 1 file changed, 48 insertions(+), 50 deletions(-) diff --git a/nix/default.nix b/nix/default.nix index fd94bef2..f2676a12 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -13,64 +13,62 @@ wayland-scanner, xcbutilwm, xwayland, - enableXWayland ? true, meson, ninja, scenefx, wlroots_0_19, libGL, -}: let + enableXWayland ? true, +}: +stdenv.mkDerivation { pname = "mango"; -in - stdenv.mkDerivation { - inherit pname; - version = "nightly"; + version = "nightly"; - src = builtins.path { - path = ../.; - name = "source"; - }; + src = builtins.path { + path = ../.; + name = "source"; + }; - mesonFlags = [ - (lib.mesonEnable "xwayland" enableXWayland) + mesonFlags = [ + (lib.mesonEnable "xwayland" enableXWayland) + ]; + + nativeBuildInputs = [ + meson + ninja + pkg-config + wayland-scanner + ]; + + buildInputs = + [ + libinput + libxcb + libxkbcommon + pcre2 + pixman + wayland + wayland-protocols + wlroots_0_19 + scenefx + libGL + ] + ++ lib.optionals enableXWayland [ + libX11 + xcbutilwm + xwayland ]; - nativeBuildInputs = [ - meson - ninja - pkg-config - wayland-scanner - ]; + passthru = { + providedSessions = ["mango"]; + }; - buildInputs = - [ - libinput - libxcb - libxkbcommon - pcre2 - pixman - wayland - wayland-protocols - wlroots_0_19 - scenefx - libGL - ] - ++ lib.optionals enableXWayland [ - libX11 - xcbutilwm - xwayland - ]; - - passthru = { - providedSessions = ["mango"]; - }; - - meta = { - mainProgram = "mango"; - description = "A streamlined but feature-rich Wayland compositor"; - homepage = "https://github.com/DreamMaoMao/mango"; - license = lib.licenses.gpl3Plus; - maintainers = []; - platforms = lib.platforms.unix; - }; - } + meta = { + mainProgram = "mango"; + description = "A streamlined but feature-rich Wayland compositor"; + homepage = "https://github.com/DreamMaoMao/mango"; + license = lib.licenses.gpl3Plus; + maintainers = []; + platforms = lib.platforms.unix; + }; +} From 20a0905ba79c70cb73fc23aea655cbd5cb98c80c Mon Sep 17 00:00:00 2001 From: Rexiel Scarlet <37258415+Rexcrazy804@users.noreply.github.com> Date: Sat, 13 Dec 2025 11:39:37 +0400 Subject: [PATCH 399/591] feat(nix): support debug override for setting asan opt --- nix/default.nix | 2 ++ 1 file changed, 2 insertions(+) diff --git a/nix/default.nix b/nix/default.nix index f2676a12..6085565e 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -19,6 +19,7 @@ wlroots_0_19, libGL, enableXWayland ? true, + debug ? false, }: stdenv.mkDerivation { pname = "mango"; @@ -31,6 +32,7 @@ stdenv.mkDerivation { mesonFlags = [ (lib.mesonEnable "xwayland" enableXWayland) + (lib.mesonBool "asan" debug) ]; nativeBuildInputs = [ From 0f861e79a0d5a53a4a0df3b6226bd1d5452ca37b Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sat, 13 Dec 2025 17:58:49 +0800 Subject: [PATCH 400/591] fix: avoid using old cursor_mgr in cursor timer --- src/config/parse_config.h | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/src/config/parse_config.h b/src/config/parse_config.h index 2e5549be..8f11f14c 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -3194,9 +3194,37 @@ void reapply_monitor_rules(void) { } void reapply_cursor_style(void) { - if (cursor_mgr) + if (hide_source) { + wl_event_source_timer_update(hide_source, 0); + wl_event_source_remove(hide_source); + hide_source = NULL; + } + + wlr_cursor_unset_image(cursor); + + wlr_cursor_set_surface(cursor, NULL, 0, 0); + + if (cursor_mgr) { wlr_xcursor_manager_destroy(cursor_mgr); + cursor_mgr = NULL; + } + cursor_mgr = wlr_xcursor_manager_create(config.cursor_theme, cursor_size); + + Monitor *m = NULL; + wl_list_for_each(m, &mons, link) { + wlr_xcursor_manager_load(cursor_mgr, m->wlr_output->scale); + } + + wlr_cursor_set_xcursor(cursor, cursor_mgr, "left_ptr"); + + hide_source = wl_event_loop_add_timer(wl_display_get_event_loop(dpy), + hidecursor, cursor); + if (cursor_hidden) { + wlr_cursor_unset_image(cursor); + } else { + wl_event_source_timer_update(hide_source, cursor_hide_timeout * 1000); + } } void reapply_border(void) { From 75407c97273852c2696b8fa4bc8e8bc700e54139 Mon Sep 17 00:00:00 2001 From: Andrej Novikov Date: Sun, 14 Dec 2025 14:26:01 +0200 Subject: [PATCH 401/591] fix: scroller layout window overlap caused by uint --- src/animation/client.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/animation/client.h b/src/animation/client.h index b4f70e0c..b5b7c5dd 100644 --- a/src/animation/client.h +++ b/src/animation/client.h @@ -708,10 +708,10 @@ void client_animation_next_tick(Client *c) { c->animation.initial.height + (c->current.height - c->animation.initial.height) * factor; - uint32_t x = c->animation.initial.x + - (c->current.x - c->animation.initial.x) * factor; - uint32_t y = c->animation.initial.y + - (c->current.y - c->animation.initial.y) * factor; + int32_t x = c->animation.initial.x + + (c->current.x - c->animation.initial.x) * factor; + int32_t y = c->animation.initial.y + + (c->current.y - c->animation.initial.y) * factor; wlr_scene_node_set_position(&c->scene->node, x, y); c->animation.current = (struct wlr_box){ From a1a7cf5a7a8a801c1833e1c2f4f4bfa4e3af601e Mon Sep 17 00:00:00 2001 From: Andrej Novikov Date: Sun, 14 Dec 2025 15:15:21 +0200 Subject: [PATCH 402/591] fix: rounded corners being drawn on windows that extend out of screen --- src/animation/client.h | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/animation/client.h b/src/animation/client.h index b5b7c5dd..eb9ff4e4 100644 --- a/src/animation/client.h +++ b/src/animation/client.h @@ -354,11 +354,13 @@ void apply_border(Client *c) { return; bool hit_no_border = check_hit_no_border(c); - enum corner_location current_corner_location = - c->isfullscreen || (no_radius_when_single && c->mon && - c->mon->visible_tiling_clients == 1) - ? CORNER_LOCATION_NONE - : CORNER_LOCATION_ALL; + enum corner_location current_corner_location; + if (c->isfullscreen || (no_radius_when_single && c->mon && + c->mon->visible_tiling_clients == 1)) { + current_corner_location = CORNER_LOCATION_NONE; + } else { + current_corner_location = set_client_corner_location(c); + } // Handle no-border cases if (hit_no_border && smartgaps) { From db2151af64196c48c5966f24170f8e3d90513c7a Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Tue, 16 Dec 2025 11:34:52 +0800 Subject: [PATCH 403/591] fix: crash when focusmon to invalid monitor --- src/dispatch/bind_define.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index 92e264e4..6544cab8 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -173,15 +173,17 @@ int toggle_trackpad_enable(const Arg *arg) { int focusmon(const Arg *arg) { Client *c = NULL; Monitor *m = NULL; + Monitor *tm = NULL; if (arg->i != UNDIR) { - m = dirtomon(arg->i); + tm = dirtomon(arg->i); } else if (arg->v) { wl_list_for_each(m, &mons, link) { if (!m->wlr_output->enabled) { continue; } if (regex_match(arg->v, m->wlr_output->name)) { + tm = m; break; } } @@ -189,10 +191,10 @@ int focusmon(const Arg *arg) { return 0; } - if (!m || !m->wlr_output->enabled || m == selmon) + if (!tm || !tm->wlr_output->enabled || tm == selmon) return 0; - selmon = m; + selmon = tm; if (warpcursor) { warp_cursor_to_selmon(selmon); } From b5848f38b4a5a8831c12b7b4d5a21d1f745355b4 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Tue, 16 Dec 2025 11:57:56 +0800 Subject: [PATCH 404/591] fix: crash when use focusstack --- src/fetch/client.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/fetch/client.h b/src/fetch/client.h index 0bc84881..e31e89d8 100644 --- a/src/fetch/client.h +++ b/src/fetch/client.h @@ -393,8 +393,8 @@ Client *get_next_stack_client(Client *c, bool reverse) { Client *next = NULL; if (reverse) { wl_list_for_each_reverse(next, &c->link, link) { - if (!next) - continue; // 安全检查 + if (&next->link == &clients) + continue; /* wrap past the sentinel node */ if (c->mon->has_visible_fullscreen_client && !next->isfloating && !next->isfullscreen) @@ -406,8 +406,8 @@ Client *get_next_stack_client(Client *c, bool reverse) { } } else { wl_list_for_each(next, &c->link, link) { - if (!next) - continue; // 安全检查 + if (&next->link == &clients) + continue; /* wrap past the sentinel node */ if (c->mon->has_visible_fullscreen_client && !next->isfloating && !next->isfullscreen) From 0212ee7177900112e51d48311ff83e7902504efd Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Tue, 16 Dec 2025 12:02:34 +0800 Subject: [PATCH 405/591] opt: remove useless code --- src/fetch/client.h | 11 +---------- src/layout/arrange.h | 4 ---- src/mango.c | 1 - 3 files changed, 1 insertion(+), 15 deletions(-) diff --git a/src/fetch/client.h b/src/fetch/client.h index e31e89d8..5dc0edd0 100644 --- a/src/fetch/client.h +++ b/src/fetch/client.h @@ -388,7 +388,7 @@ Client *focustop(Monitor *m) { Client *get_next_stack_client(Client *c, bool reverse) { if (!c || !c->mon) - return NULL; // 添加输入检查 + return NULL; Client *next = NULL; if (reverse) { @@ -396,11 +396,6 @@ Client *get_next_stack_client(Client *c, bool reverse) { if (&next->link == &clients) continue; /* wrap past the sentinel node */ - if (c->mon->has_visible_fullscreen_client && !next->isfloating && - !next->isfullscreen) - continue; - - // 添加更安全的 VISIBLEON 检查 if (next != c && next->mon && VISIBLEON(next, c->mon)) return next; } @@ -409,10 +404,6 @@ Client *get_next_stack_client(Client *c, bool reverse) { if (&next->link == &clients) continue; /* wrap past the sentinel node */ - if (c->mon->has_visible_fullscreen_client && !next->isfloating && - !next->isfullscreen) - continue; - if (next != c && next->mon && VISIBLEON(next, c->mon)) return next; } diff --git a/src/layout/arrange.h b/src/layout/arrange.h index 4a910aaf..a7805aff 100644 --- a/src/layout/arrange.h +++ b/src/layout/arrange.h @@ -597,7 +597,6 @@ arrange(Monitor *m, bool want_animation) { m->visible_clients = 0; m->visible_tiling_clients = 0; m->visible_scroll_tiling_clients = 0; - m->has_visible_fullscreen_client = false; wl_list_for_each(c, &clients, link) { @@ -611,9 +610,6 @@ arrange(Monitor *m, bool want_animation) { if (!c->isunglobal) m->visible_clients++; - if (c->isfullscreen) - m->has_visible_fullscreen_client = true; - if (ISTILED(c)) { m->visible_tiling_clients++; } diff --git a/src/mango.c b/src/mango.c index 1bd2c1fa..766e0987 100644 --- a/src/mango.c +++ b/src/mango.c @@ -508,7 +508,6 @@ struct Monitor { uint32_t visible_clients; uint32_t visible_tiling_clients; uint32_t visible_scroll_tiling_clients; - bool has_visible_fullscreen_client; struct wlr_scene_optimized_blur *blur; char last_surface_ws_name[256]; struct wlr_ext_workspace_group_handle_v1 *ext_group; From ff35c7afe92e77017fdcf3396ea51aa5f29b7a84 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Wed, 17 Dec 2025 11:04:13 +0800 Subject: [PATCH 406/591] bump version to 0.10.8 --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 460328ef..9f197ab1 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('mango', ['c', 'cpp'], - version : '0.10.7', + version : '0.10.8', ) subdir('protocols') From 5f884bdf514c8dc96f2bbd0a78987bc28982fe61 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Thu, 18 Dec 2025 10:50:52 +0800 Subject: [PATCH 407/591] opt: opt optimize idleinhibit check --- src/mango.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/mango.c b/src/mango.c index 766e0987..c96126ff 100644 --- a/src/mango.c +++ b/src/mango.c @@ -2000,16 +2000,24 @@ buttonpress(struct wl_listener *listener, void *data) { } void checkidleinhibitor(struct wlr_surface *exclude) { - int inhibited = 0, unused_lx, unused_ly; + int inhibited = 0; struct wlr_idle_inhibitor_v1 *inhibitor; + wl_list_for_each(inhibitor, &idle_inhibit_mgr->inhibitors, link) { struct wlr_surface *surface = wlr_surface_get_root_surface(inhibitor->surface); + + if (exclude == surface) { + continue; + } + + if (inhibit_regardless_of_visibility) { + inhibited = 1; + break; + } + struct wlr_scene_tree *tree = surface->data; - if (exclude != surface && - (inhibit_regardless_of_visibility || - (!tree || - wlr_scene_node_coords(&tree->node, &unused_lx, &unused_ly)))) { + if (!tree || tree->node.enabled) { inhibited = 1; break; } From bce6c0498e7406abaa33b0f28c22457a0e87ddc3 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Fri, 19 Dec 2025 14:35:43 +0800 Subject: [PATCH 408/591] fix: inhibit_regardless_of_visibility not apply in some case --- src/mango.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/mango.c b/src/mango.c index c96126ff..c5383038 100644 --- a/src/mango.c +++ b/src/mango.c @@ -2001,23 +2001,26 @@ buttonpress(struct wl_listener *listener, void *data) { void checkidleinhibitor(struct wlr_surface *exclude) { int inhibited = 0; + Client *c = NULL; + struct wlr_surface *surface = NULL; struct wlr_idle_inhibitor_v1 *inhibitor; wl_list_for_each(inhibitor, &idle_inhibit_mgr->inhibitors, link) { - struct wlr_surface *surface = - wlr_surface_get_root_surface(inhibitor->surface); + surface = wlr_surface_get_root_surface(inhibitor->surface); if (exclude == surface) { continue; } + toplevel_from_wlr_surface(inhibitor->surface, &c, NULL); + if (inhibit_regardless_of_visibility) { inhibited = 1; break; } struct wlr_scene_tree *tree = surface->data; - if (!tree || tree->node.enabled) { + if (!tree || (tree->node.enabled && (!c || !c->animation.tagouting))) { inhibited = 1; break; } From f54d7b3483d9ecb43f518c1d21d293de4007afc6 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Fri, 19 Dec 2025 14:40:32 +0800 Subject: [PATCH 409/591] break change: inhibit_regardless_of_visibility rename to idleinhibit_ignore_visible --- config.conf | 2 +- src/config/parse_config.h | 14 +++++++------- src/config/preset.h | 2 +- src/mango.c | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/config.conf b/config.conf index e93b3e6c..5483a141 100644 --- a/config.conf +++ b/config.conf @@ -77,7 +77,7 @@ overviewgappo=30 no_border_when_single=0 axis_bind_apply_timeout=100 focus_on_activate=1 -inhibit_regardless_of_visibility=0 +idleinhibit_ignore_visible=0 sloppyfocus=1 warpcursor=1 focus_cross_monitor=0 diff --git a/src/config/parse_config.h b/src/config/parse_config.h index 8f11f14c..08659c31 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -238,7 +238,7 @@ typedef struct { uint32_t axis_bind_apply_timeout; uint32_t focus_on_activate; - int inhibit_regardless_of_visibility; + int idleinhibit_ignore_visible; int sloppyfocus; int warpcursor; @@ -1456,8 +1456,8 @@ void parse_option(Config *config, char *key, char *value) { config->focus_on_activate = atoi(value); } else if (strcmp(key, "numlockon") == 0) { config->numlockon = atoi(value); - } else if (strcmp(key, "inhibit_regardless_of_visibility") == 0) { - config->inhibit_regardless_of_visibility = atoi(value); + } else if (strcmp(key, "idleinhibit_ignore_visible") == 0) { + config->idleinhibit_ignore_visible = atoi(value); } else if (strcmp(key, "sloppyfocus") == 0) { config->sloppyfocus = atoi(value); } else if (strcmp(key, "warpcursor") == 0) { @@ -2735,8 +2735,8 @@ void override_config(void) { axis_bind_apply_timeout = CLAMP_INT(config.axis_bind_apply_timeout, 0, 1000); focus_on_activate = CLAMP_INT(config.focus_on_activate, 0, 1); - inhibit_regardless_of_visibility = - CLAMP_INT(config.inhibit_regardless_of_visibility, 0, 1); + idleinhibit_ignore_visible = + CLAMP_INT(config.idleinhibit_ignore_visible, 0, 1); sloppyfocus = CLAMP_INT(config.sloppyfocus, 0, 1); warpcursor = CLAMP_INT(config.warpcursor, 0, 1); focus_cross_monitor = CLAMP_INT(config.focus_cross_monitor, 0, 1); @@ -2922,8 +2922,8 @@ void set_value_default() { config.enable_floating_snap = enable_floating_snap; config.swipe_min_threshold = swipe_min_threshold; - config.inhibit_regardless_of_visibility = - inhibit_regardless_of_visibility; /* 1 means idle inhibitors will + config.idleinhibit_ignore_visible = + idleinhibit_ignore_visible; /* 1 means idle inhibitors will disable idle tracking even if it's surface isn't visible */ diff --git a/src/config/preset.h b/src/config/preset.h index 7b45315d..e13be4d0 100644 --- a/src/config/preset.h +++ b/src/config/preset.h @@ -80,7 +80,7 @@ uint32_t cursor_hide_timeout = 0; uint32_t swipe_min_threshold = 1; -int inhibit_regardless_of_visibility = +int idleinhibit_ignore_visible = 0; /* 1 means idle inhibitors will disable idle tracking even if it's surface isn't visible */ uint32_t borderpx = 4; /* border pixel of windows */ diff --git a/src/mango.c b/src/mango.c index c5383038..291b815e 100644 --- a/src/mango.c +++ b/src/mango.c @@ -2014,7 +2014,7 @@ void checkidleinhibitor(struct wlr_surface *exclude) { toplevel_from_wlr_surface(inhibitor->surface, &c, NULL); - if (inhibit_regardless_of_visibility) { + if (idleinhibit_ignore_visible) { inhibited = 1; break; } From a8f7dc3e68a54851903e3ec48bbcb346625df3cc Mon Sep 17 00:00:00 2001 From: meeeee3 <68552560+meeeee3@users.noreply.github.com> Date: Fri, 19 Dec 2025 14:19:10 +0800 Subject: [PATCH 410/591] feat: add wheel scroll factor --- src/config/parse_config.h | 6 ++++++ src/config/preset.h | 2 ++ src/mango.c | 9 +++++---- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/config/parse_config.h b/src/config/parse_config.h index 8f11f14c..da9cc8dc 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -265,6 +265,8 @@ typedef struct { uint32_t send_events_mode; uint32_t button_map; + double axis_scroll_factor; + int blur; int blur_layer; int blur_optimized; @@ -1504,6 +1506,8 @@ void parse_option(Config *config, char *key, char *value) { config->send_events_mode = atoi(value); } else if (strcmp(key, "button_map") == 0) { config->button_map = atoi(value); + } else if (strcmp(key, "axis_scroll_factor") == 0) { + config->axis_scroll_factor = atof(value); } else if (strcmp(key, "gappih") == 0) { config->gappih = atoi(value); } else if (strcmp(key, "gappiv") == 0) { @@ -2780,6 +2784,7 @@ void override_config(void) { click_method = CLAMP_INT(config.click_method, 0, 2); send_events_mode = CLAMP_INT(config.send_events_mode, 0, 2); button_map = CLAMP_INT(config.button_map, 0, 1); + axis_scroll_factor = CLAMP_FLOAT(config.axis_scroll_factor, 0.1f, 10.0f); // 外观设置 gappih = CLAMP_INT(config.gappih, 0, 1000); @@ -2907,6 +2912,7 @@ void set_value_default() { config.exchange_cross_monitor = exchange_cross_monitor; config.scratchpad_cross_monitor = scratchpad_cross_monitor; config.focus_cross_tag = focus_cross_tag; + config.axis_scroll_factor = axis_scroll_factor; config.view_current_to_back = view_current_to_back; config.single_scratchpad = single_scratchpad; config.xwayland_persistence = xwayland_persistence; diff --git a/src/config/preset.h b/src/config/preset.h index 7b45315d..cae88144 100644 --- a/src/config/preset.h +++ b/src/config/preset.h @@ -178,6 +178,8 @@ LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER enum libinput_config_click_method click_method = LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS; +double axis_scroll_factor = 1.0; + /* You can choose between: LIBINPUT_CONFIG_SEND_EVENTS_ENABLED LIBINPUT_CONFIG_SEND_EVENTS_DISABLED diff --git a/src/mango.c b/src/mango.c index c96126ff..0ba3eaba 100644 --- a/src/mango.c +++ b/src/mango.c @@ -1711,10 +1711,11 @@ axisnotify(struct wl_listener *listener, void *data) { * implemented checking the event's orientation and the delta of the event */ /* Notify the client with pointer focus of the axis event. */ - wlr_seat_pointer_notify_axis(seat, // 滚轮事件发送给客户端也就是窗口 - event->time_msec, event->orientation, - event->delta, event->delta_discrete, - event->source, event->relative_direction); + wlr_seat_pointer_notify_axis( + seat, // 滚轮事件发送给客户端也就是窗口 + event->time_msec, event->orientation, event->delta * axis_scroll_factor, + roundf(event->delta_discrete * axis_scroll_factor), event->source, + event->relative_direction); } int ongesture(struct wlr_pointer_swipe_end_event *event) { From 9aa8dab8ac4597d4d06c14282aa4c914f7824cd8 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Fri, 19 Dec 2025 17:34:29 +0800 Subject: [PATCH 411/591] opt: reset float geom record when remap --- src/mango.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/mango.c b/src/mango.c index b025539e..ac86bf95 100644 --- a/src/mango.c +++ b/src/mango.c @@ -3730,6 +3730,10 @@ void init_client_properties(Client *c) { c->force_tearing = 0; c->allow_shortcuts_inhibit = SHORTCUTS_INHIBIT_ENABLE; c->scroller_proportion_single = 0.0f; + c->float_geom.width = 0; + c->float_geom.height = 0; + c->float_geom.x = 0; + c->float_geom.y = 0; } void // old fix to 0.5 From a67083bdb46347ebf465332dd28bf5e771ff7d63 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Fri, 19 Dec 2025 17:45:34 +0800 Subject: [PATCH 412/591] opt: no force center x11 window when map --- src/mango.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/mango.c b/src/mango.c index ac86bf95..5a9a5ad2 100644 --- a/src/mango.c +++ b/src/mango.c @@ -1392,8 +1392,11 @@ void applyrules(Client *c) { // if no geom rule hit and is normal winodw, use the center pos and record // the hit size - if (!hit_rule_pos && (!client_is_x11(c) || !client_is_x11_popup(c))) { + if (!hit_rule_pos && + (!client_is_x11(c) || (c->geom.x == 0 && c->geom.y == 0))) { c->float_geom = c->geom = setclient_coordinate_center(c, c->geom, 0, 0); + } else { + c->float_geom = c->geom; } /*-----------------------apply rule action-------------------------*/ @@ -4516,7 +4519,7 @@ setfloating(Client *c, int floating) { } // 重新计算居中的坐标 - if (!client_is_x11(c) || !client_is_x11_popup(c)) + if (!client_is_x11(c) || (c->geom.x == 0 && c->geom.y == 0)) target_box = setclient_coordinate_center(c, target_box, 0, 0); backup_box = c->geom; hit = applyrulesgeom(c); From df0e18481b0cdf9b216186c26e00de126550474b Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Fri, 19 Dec 2025 23:08:19 +0800 Subject: [PATCH 413/591] opt: reduce cursor resize request --- src/config/preset.h | 2 +- src/mango.c | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/config/preset.h b/src/config/preset.h index a371a420..31f514f8 100644 --- a/src/config/preset.h +++ b/src/config/preset.h @@ -106,7 +106,7 @@ int xwayland_persistence = 1; /* xwayland persistence */ int syncobj_enable = 0; int adaptive_sync = 0; int allow_lock_transparent = 0; -double drag_refresh_interval = 30.0; +double drag_refresh_interval = 16.0; int allow_tearing = TEARING_DISABLED; int allow_shortcuts_inhibit = SHORTCUTS_INHIBIT_ENABLE; diff --git a/src/mango.c b/src/mango.c index 5a9a5ad2..4d685ecf 100644 --- a/src/mango.c +++ b/src/mango.c @@ -4035,7 +4035,11 @@ void motionnotify(uint32_t time, struct wlr_input_device *device, double dx, .y = grabc->geom.y, .width = (int)round(cursor->x) - grabc->geom.x, .height = (int)round(cursor->y) - grabc->geom.y}; - resize(grabc, grabc->float_geom, 1); + if (last_apply_drap_time == 0 || + time - last_apply_drap_time > drag_refresh_interval) { + resize(grabc, grabc->float_geom, 1); + last_apply_drap_time = time; + } return; } else { resize_tile_client(grabc, true, 0, 0, time); From 471c71f65c3c15ebe633edf4757361649757f990 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sat, 20 Dec 2025 11:39:53 +0800 Subject: [PATCH 414/591] feat: add windowrule option isnoradius --- src/animation/client.h | 5 +++-- src/config/parse_config.h | 4 ++++ src/mango.c | 4 ++++ 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/animation/client.h b/src/animation/client.h index eb9ff4e4..596336f7 100644 --- a/src/animation/client.h +++ b/src/animation/client.h @@ -240,8 +240,9 @@ void buffer_set_effect(Client *c, BufferData data) { if (c == grabc) data.should_scale = false; - if (c->isfullscreen || (no_radius_when_single && c->mon && - c->mon->visible_tiling_clients == 1)) { + if (c->isnoradius || c->isfullscreen || + (no_radius_when_single && c->mon && + c->mon->visible_tiling_clients == 1)) { data.corner_location = CORNER_LOCATION_NONE; } diff --git a/src/config/parse_config.h b/src/config/parse_config.h index 1d66f34d..074b5227 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -64,6 +64,7 @@ typedef struct { const char *layer_animation_type_close; int isnoborder; int isnoshadow; + int isnoradius; int isnoanimation; int isopensilent; int istagsilent; @@ -1705,6 +1706,7 @@ void parse_option(Config *config, char *key, char *value) { rule->isfullscreen = -1; rule->isnoborder = -1; rule->isnoshadow = -1; + rule->isnoradius = -1; rule->isnoanimation = -1; rule->isopensilent = -1; rule->istagsilent = -1; @@ -1794,6 +1796,8 @@ void parse_option(Config *config, char *key, char *value) { rule->isnoborder = atoi(val); } else if (strcmp(key, "isnoshadow") == 0) { rule->isnoshadow = atoi(val); + } else if (strcmp(key, "isnoradius") == 0) { + rule->isnoradius = atoi(val); } else if (strcmp(key, "isnoanimation") == 0) { rule->isnoanimation = atoi(val); } else if (strcmp(key, "isopensilent") == 0) { diff --git a/src/mango.c b/src/mango.c index 4d685ecf..4570a201 100644 --- a/src/mango.c +++ b/src/mango.c @@ -364,6 +364,7 @@ struct Client { int isglobal; int isnoborder; int isnoshadow; + int isnoradius; int isnoanimation; int isopensilent; int istagsilent; @@ -1214,6 +1215,7 @@ static void apply_rule_properties(Client *c, const ConfigWinRule *r) { APPLY_INT_PROP(c, r, isfullscreen); APPLY_INT_PROP(c, r, isnoborder); APPLY_INT_PROP(c, r, isnoshadow); + APPLY_INT_PROP(c, r, isnoradius); APPLY_INT_PROP(c, r, isnoanimation); APPLY_INT_PROP(c, r, isopensilent); APPLY_INT_PROP(c, r, istagsilent); @@ -3721,6 +3723,8 @@ void init_client_properties(Client *c) { c->no_force_center = 0; c->isnoborder = 0; c->isnosizehint = 0; + c->isnoradius = 0; + c->isnoshadow = 0; c->ignore_maximize = 1; c->ignore_minimize = 1; c->iscustomsize = 0; From 14f15ec997694a19326c0d132148d35c934bf665 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Fri, 26 Dec 2025 08:35:02 +0800 Subject: [PATCH 415/591] fix: gapoh not apply correctly in VT layout --- src/layout/vertical.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/layout/vertical.h b/src/layout/vertical.h index b6dd27da..da6a1279 100644 --- a/src/layout/vertical.h +++ b/src/layout/vertical.h @@ -40,14 +40,14 @@ void vertical_tile(Monitor *m) { mh = m->w.height - 2 * cur_gapov + cur_gapiv * ie; i = 0; - mx = tx = cur_gapih; + mx = tx = cur_gapoh; uint32_t master_surplus_width = - (m->w.width - 2 * cur_gapih - cur_gapih * ie * (master_num - 1)); + (m->w.width - 2 * cur_gapoh - cur_gapih * ie * (master_num - 1)); float master_surplus_ratio = 1.0; uint32_t slave_surplus_width = - (m->w.width - 2 * cur_gapih - cur_gapih * ie * (stack_num - 1)); + (m->w.width - 2 * cur_gapoh - cur_gapih * ie * (stack_num - 1)); float slave_surplus_ratio = 1.0; wl_list_for_each(c, &clients, link) { From 526a09c4808808de638d876dbe43a114509f3b88 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sat, 27 Dec 2025 09:54:29 +0800 Subject: [PATCH 416/591] opt: not search disable node in xytonode --- src/fetch/common.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/fetch/common.h b/src/fetch/common.h index c96ee31b..68407500 100644 --- a/src/fetch/common.h +++ b/src/fetch/common.h @@ -93,6 +93,9 @@ void xytonode(double x, double y, struct wlr_surface **psurface, Client **pc, if (!(node = wlr_scene_node_at(&layers[layer]->node, x, y, nx, ny))) continue; + if (!node->enabled) + continue; + if (node->type == WLR_SCENE_NODE_BUFFER) surface = wlr_scene_surface_try_from_buffer( wlr_scene_buffer_from_node(node)) From 81319e99de0625e792419358771cfa87c0254dc8 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sat, 27 Dec 2025 12:07:41 +0800 Subject: [PATCH 417/591] update readme --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 7818c36b..087bf13b 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ -# MangoWC - -mango-transparency-256 - +# Mango Wayland Compositor +

This project's development is based on [dwl](https://codeberg.org/dwl/dwl/). From af1f7850ee788c6a23085c117d0310f631b9c271 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sat, 27 Dec 2025 22:29:24 +0800 Subject: [PATCH 418/591] opt: avoid pointer focus disable scene node --- src/mango.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/mango.c b/src/mango.c index 4570a201..d7f0de25 100644 --- a/src/mango.c +++ b/src/mango.c @@ -1920,7 +1920,8 @@ buttonpress(struct wl_listener *listener, void *data) { xytonode(cursor->x, cursor->y, &surface, NULL, NULL, NULL, NULL); if (toplevel_from_wlr_surface(surface, &c, &l) >= 0) { - if (c && (!client_is_unmanaged(c) || client_wants_focus(c))) + if (c && c->scene->node.enabled && + (!client_is_unmanaged(c) || client_wants_focus(c))) focusclient(c, 1); if (surface != old_pointer_focus_surface) { @@ -4173,7 +4174,7 @@ void pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy, struct timespec now; if (surface != seat->pointer_state.focused_surface && sloppyfocus && time && - c && !client_is_unmanaged(c)) + c && c->scene->node.enabled && !client_is_unmanaged(c)) focusclient(c, 0); /* If surface is NULL, clear pointer focus */ From 42f722ada2fa4cba0d9426b4273d269e1ba59d53 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Mon, 29 Dec 2025 09:51:12 +0800 Subject: [PATCH 419/591] opt: reset global window record per when arrange --- src/fetch/client.h | 11 +++++++++++ src/layout/arrange.h | 17 +++++++++++++++++ src/mango.c | 1 + 3 files changed, 29 insertions(+) diff --git a/src/fetch/client.h b/src/fetch/client.h index 5dc0edd0..56ca9822 100644 --- a/src/fetch/client.h +++ b/src/fetch/client.h @@ -430,4 +430,15 @@ float *get_border_color(Client *c) { } else { return bordercolor; } +} + +int is_single_bit_set(uint32_t x) { return x && !(x & (x - 1)); } + +bool client_only_in_one_tag(Client *c) { + uint32_t masked = c->tags & TAGMASK; + if (is_single_bit_set(masked)) { + return true; + } else { + return false; + } } \ No newline at end of file diff --git a/src/layout/arrange.h b/src/layout/arrange.h index a7805aff..dc8b47e0 100644 --- a/src/layout/arrange.h +++ b/src/layout/arrange.h @@ -576,6 +576,23 @@ void reset_size_per_mon(Monitor *m, int tile_cilent_num, } } +void reset_multi_tag_client_per(Monitor *m) { + Client *c = NULL; + wl_list_for_each(c, &clients, link) { + + if (c->isglobal || c->isunglobal) { + set_size_per(m, c); + } + + if (!VISIBLEON(c, m)) + continue; + + if (!client_only_in_one_tag(c)) { + set_size_per(m, c); + } + } +} + void // 17 arrange(Monitor *m, bool want_animation) { Client *c = NULL; diff --git a/src/mango.c b/src/mango.c index d7f0de25..230387c7 100644 --- a/src/mango.c +++ b/src/mango.c @@ -5693,6 +5693,7 @@ toggleseltags: if (changefocus) focusclient(focustop(m), 1); + reset_multi_tag_client_per(m); arrange(m, want_animation); printstatus(); } From f749500449920bf41b5ca256367d895c25bc61cd Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Mon, 29 Dec 2025 11:13:50 +0800 Subject: [PATCH 420/591] feat: restore the current tag when after chvt --- src/dispatch/bind_define.h | 8 +++++++- src/mango.c | 27 +++++++++++++++++++++++---- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index 6544cab8..80512d75 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -31,8 +31,14 @@ int bind_to_view(const Arg *arg) { } int chvt(const Arg *arg) { + + if (selmon) { + chvt_backup_tag = selmon->pertag->curtag; + strncpy(chvt_backup_selmon, selmon->wlr_output->name, + sizeof(chvt_backup_selmon) - 1); + } wlr_session_change_vt(session, arg->ui); - return 0; + return 1; } int create_virtual_output(const Arg *arg) { diff --git a/src/mango.c b/src/mango.c index 230387c7..fe5f4cb2 100644 --- a/src/mango.c +++ b/src/mango.c @@ -845,6 +845,9 @@ static double swipe_dy = 0; bool render_border = true; +uint32_t chvt_backup_tag = 0; +char chvt_backup_selmon[32] = {0}; + struct dvec2 *baked_points_move; struct dvec2 *baked_points_open; struct dvec2 *baked_points_tag; @@ -2705,7 +2708,6 @@ void createmon(struct wl_listener *listener, void *data) { m->isoverview = 0; m->sel = NULL; m->is_in_hotarea = 0; - m->tagset[0] = m->tagset[1] = 1; float scale = 1; m->mfact = default_mfact; m->nmaster = default_nmaster; @@ -2777,7 +2779,16 @@ void createmon(struct wl_listener *listener, void *data) { wl_list_insert(&mons, &m->link); m->pertag = calloc(1, sizeof(Pertag)); - m->pertag->curtag = m->pertag->prevtag = 1; + if (chvt_backup_tag && + regex_match(chvt_backup_selmon, m->wlr_output->name)) { + m->tagset[0] = m->tagset[1] = (1 << (chvt_backup_tag - 1)) & TAGMASK; + m->pertag->curtag = m->pertag->prevtag = chvt_backup_tag; + chvt_backup_tag = 0; + memset(chvt_backup_selmon, 0, sizeof(chvt_backup_selmon)); + } else { + m->tagset[0] = m->tagset[1] = 1; + m->pertag->curtag = m->pertag->prevtag = 1; + } for (i = 0; i <= LENGTH(tags); i++) { m->pertag->nmasters[i] = m->nmaster; @@ -4232,10 +4243,18 @@ void rendermon(struct wl_listener *listener, void *data) { LayerSurface *l = NULL, *tmpl = NULL; int i; struct wl_list *layer_list; - + bool frame_allow_tearing = false; struct timespec now; bool need_more_frames = false; - bool frame_allow_tearing = check_tearing_frame_allow(m); + + if (session && !session->active) { + return; + } + + if (!m->wlr_output->enabled) + return; + + frame_allow_tearing = check_tearing_frame_allow(m); // 绘制层和淡出效果 for (i = 0; i < LENGTH(m->layers); i++) { From d3790e9c7ac29b97d8bdf3c83513b97710abafdf Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Mon, 29 Dec 2025 13:27:11 +0800 Subject: [PATCH 421/591] opt: optimzie handle requestmonstate --- src/mango.c | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/src/mango.c b/src/mango.c index fe5f4cb2..54b56cb1 100644 --- a/src/mango.c +++ b/src/mango.c @@ -3344,9 +3344,31 @@ fullscreennotify(struct wl_listener *listener, void *data) { } void requestmonstate(struct wl_listener *listener, void *data) { - struct wlr_output_event_request_state *event = data; - wlr_output_commit_state(event->output, event->state); - updatemons(NULL, NULL); + /* This ensures nested backends can be resized */ + Monitor *m = wl_container_of(listener, m, request_state); + const struct wlr_output_event_request_state *event = data; + + if (event->state->committed == WLR_OUTPUT_STATE_MODE) { + switch (event->state->mode_type) { + case WLR_OUTPUT_STATE_MODE_FIXED: + wlr_output_state_set_mode(&m->pending, event->state->mode); + break; + case WLR_OUTPUT_STATE_MODE_CUSTOM: + wlr_output_state_set_custom_mode(&m->pending, + event->state->custom_mode.width, + event->state->custom_mode.height, + event->state->custom_mode.refresh); + break; + } + updatemons(NULL, NULL); + wlr_output_schedule_frame(m->wlr_output); + return; + } + + if (!wlr_output_commit_state(m->wlr_output, event->state)) { + wlr_log(WLR_ERROR, + "Backend requested a new state that could not be applied"); + } } void inputdevice(struct wl_listener *listener, void *data) { From 35dd788ca382822cf225ed2b17297b8844f7ae51 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Mon, 29 Dec 2025 18:33:37 +0800 Subject: [PATCH 422/591] fix: fix error offset for shadow and surface clip --- src/animation/client.h | 24 +++++++++++------------- src/client/client.h | 4 ++-- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/src/animation/client.h b/src/animation/client.h index 596336f7..faef7c28 100644 --- a/src/animation/client.h +++ b/src/animation/client.h @@ -1,7 +1,7 @@ void client_actual_size(Client *c, uint32_t *width, uint32_t *height) { - *width = c->animation.current.width - c->bw; + *width = c->animation.current.width - 2 * c->bw; - *height = c->animation.current.height - c->bw; + *height = c->animation.current.height - 2 * c->bw; } void set_rect_size(struct wlr_scene_rect *rect, int width, int height) { @@ -271,7 +271,7 @@ void client_draw_shadow(Client *c) { ? CORNER_LOCATION_NONE : CORNER_LOCATION_ALL; - uint32_t bwoffset = c->bw != 0 && hit_no_border ? c->bw : 0; + int bwoffset = c->bw != 0 && hit_no_border ? (int)c->bw : 0; uint32_t width, height; client_actual_size(c, &width, &height); @@ -282,13 +282,13 @@ void client_draw_shadow(Client *c) { struct wlr_box client_box = { .x = bwoffset, .y = bwoffset, - .width = width - 2 * bwoffset, - .height = height - 2 * bwoffset, + .width = width + (int)c->bw - bwoffset, + .height = height + (int)c->bw - bwoffset, }; struct wlr_box shadow_box = { - .x = shadows_position_x, - .y = shadows_position_y, + .x = shadows_position_x + bwoffset, + .y = shadows_position_y + bwoffset, .width = width + 2 * delta, .height = height + 2 * delta, }; @@ -297,8 +297,8 @@ void client_draw_shadow(Client *c) { wlr_box_intersection(&intersection_box, &client_box, &shadow_box); /* clipped region takes shadow relative coords, so we translate everything * by its position */ - intersection_box.x -= shadows_position_x; - intersection_box.y -= shadows_position_y; + intersection_box.x -= shadows_position_x + bwoffset; + intersection_box.y -= shadows_position_y + bwoffset; struct clipped_region clipped_region = { .area = intersection_box, @@ -522,8 +522,6 @@ void client_apply_clip(Client *c, float factor) { enum corner_location current_corner_location = set_client_corner_location(c); - int bw = (int)c->bw; - if (!animations) { c->animation.running = false; c->need_output_flush = false; @@ -558,8 +556,8 @@ void client_apply_clip(Client *c, float factor) { clip_box = (struct wlr_box){ .x = geometry.x, .y = geometry.y, - .width = width - bw, - .height = height - bw, + .width = width, + .height = height, }; if (client_is_x11(c)) { diff --git a/src/client/client.h b/src/client/client.h index bc7706d7..a5d03d8b 100644 --- a/src/client/client.h +++ b/src/client/client.h @@ -127,8 +127,8 @@ static inline void client_get_clip(Client *c, struct wlr_box *clip) { *clip = (struct wlr_box){ .x = 0, .y = 0, - .width = c->geom.width - c->bw, - .height = c->geom.height - c->bw, + .width = c->geom.width - 2 * c->bw, + .height = c->geom.height - 2 * c->bw, }; #ifdef XWAYLAND From ed1612f1bd62276fb01563a998684a0904decedb Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Tue, 30 Dec 2025 10:25:00 +0800 Subject: [PATCH 423/591] fix: switch to mango session fail from other vt --- src/animation/client.h | 6 ++++-- src/animation/common.h | 10 ---------- src/animation/layer.h | 6 ++++-- src/mango.c | 11 +++++------ 4 files changed, 13 insertions(+), 20 deletions(-) diff --git a/src/animation/client.h b/src/animation/client.h index faef7c28..56ca3d66 100644 --- a/src/animation/client.h +++ b/src/animation/client.h @@ -840,7 +840,8 @@ void init_fadeout_client(Client *c) { wl_list_insert(&fadeout_clients, &fadeout_cient->fadeout_link); // 请求刷新屏幕 - request_fresh_all_monitors(); + if (c->mon) + wlr_output_schedule_frame(c->mon->wlr_output); } void client_commit(Client *c) { @@ -859,7 +860,8 @@ void client_commit(Client *c) { c->animation.should_animate = false; } // 请求刷新屏幕 - request_fresh_all_monitors(); + if (c->mon) + wlr_output_schedule_frame(c->mon->wlr_output); } void client_set_pending_state(Client *c) { diff --git a/src/animation/common.h b/src/animation/common.h index 0f662d62..6e6fa048 100644 --- a/src/animation/common.h +++ b/src/animation/common.h @@ -249,13 +249,3 @@ struct wlr_scene_tree *wlr_scene_tree_snapshot(struct wlr_scene_node *node, return snapshot; } - -void request_fresh_all_monitors(void) { - Monitor *m = NULL; - wl_list_for_each(m, &mons, link) { - if (!m->wlr_output->enabled) { - continue; - } - wlr_output_schedule_frame(m->wlr_output); - } -} \ No newline at end of file diff --git a/src/animation/layer.h b/src/animation/layer.h index 57e0c149..141f1320 100644 --- a/src/animation/layer.h +++ b/src/animation/layer.h @@ -467,7 +467,8 @@ void init_fadeout_layers(LayerSurface *l) { wl_list_insert(&fadeout_layers, &fadeout_layer->fadeout_link); // 请求刷新屏幕 - wlr_output_schedule_frame(l->mon->wlr_output); + if (l->mon) + wlr_output_schedule_frame(l->mon->wlr_output); } void layer_set_pending_state(LayerSurface *l) { @@ -550,7 +551,8 @@ void layer_commit(LayerSurface *l) { l->animation.should_animate = false; } // 请求刷新屏幕 - wlr_output_schedule_frame(l->mon->wlr_output); + if (l->mon) + wlr_output_schedule_frame(l->mon->wlr_output); } bool layer_draw_frame(LayerSurface *l) { diff --git a/src/mango.c b/src/mango.c index 54b56cb1..6726a6c5 100644 --- a/src/mango.c +++ b/src/mango.c @@ -760,7 +760,6 @@ static void resize_tile_client(Client *grabc, bool isdrag, int offsetx, static void refresh_monitors_workspaces_status(Monitor *m); static void init_client_properties(Client *c); static float *get_border_color(Client *c); -static void request_fresh_all_monitors(void); static void clear_fullscreen_and_maximized_state(Monitor *m); #include "data/static_keymap.h" @@ -4294,6 +4293,11 @@ void rendermon(struct wl_listener *listener, void *data) { need_more_frames = layer_draw_fadeout_frame(l) || need_more_frames; } + // 如果需要更多帧,确保安排下一帧 + if (need_more_frames) { + wlr_output_schedule_frame(m->wlr_output); + } + // 绘制客户端 wl_list_for_each(c, &clients, link) { need_more_frames = client_draw_frame(c) || need_more_frames; @@ -4320,11 +4324,6 @@ skip: wlr_scene_output_send_frame_done(m->scene_output, &now); wlr_output_state_finish(&pending); } - - // 如果需要更多帧,确保安排下一帧 - if (need_more_frames) { - request_fresh_all_monitors(); - } } void requestdecorationmode(struct wl_listener *listener, void *data) { From d6dbb7a7016501993c75a6eeb38fa2f0d83ab8de Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Tue, 30 Dec 2025 11:45:37 +0800 Subject: [PATCH 424/591] bump version to 0.10.9 --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 9f197ab1..c56650ed 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('mango', ['c', 'cpp'], - version : '0.10.8', + version : '0.10.9', ) subdir('protocols') From b35a7f03e978e11aa91abd775f674b058e3a21cd Mon Sep 17 00:00:00 2001 From: Smriti Khanal Date: Wed, 31 Dec 2025 12:01:11 +0545 Subject: [PATCH 425/591] Fixed offset not applying --- src/mango.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mango.c b/src/mango.c index 6726a6c5..1ba59e76 100644 --- a/src/mango.c +++ b/src/mango.c @@ -1380,7 +1380,7 @@ void applyrules(Client *c) { if (r->offsetx || r->offsety || r->width > 0 || r->height > 0) { hit_rule_pos = r->offsetx || r->offsety ? true : false; c->iscustomsize = 1; - c->float_geom = setclient_coordinate_center(c, c->float_geom, + c->float_geom = c->geom = setclient_coordinate_center(c, c->float_geom, r->offsetx, r->offsety); } if (c->isfloating) { From 0edcd32271d48e1a1ec21e8277cdc3e0ccde4c9a Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Wed, 31 Dec 2025 16:28:47 +0800 Subject: [PATCH 426/591] fix: offsetx and offsety not apply --- src/mango.c | 67 +++++++++++------------------------------------------ 1 file changed, 14 insertions(+), 53 deletions(-) diff --git a/src/mango.c b/src/mango.c index 1ba59e76..ccdbf6f7 100644 --- a/src/mango.c +++ b/src/mango.c @@ -360,6 +360,7 @@ struct Client { const char *animation_type_close; int is_in_scratchpad; int iscustomsize; + int iscustompos; int is_scratchpad_show; int isglobal; int isnoborder; @@ -683,7 +684,6 @@ static void warp_cursor_to_selmon(Monitor *m); uint32_t want_restore_fullscreen(Client *target_client); static void overview_restore(Client *c, const Arg *arg); static void overview_backup(Client *c); -static int applyrulesgeom(Client *c); static void set_minimized(Client *c); static void show_scratchpad(Client *c); @@ -1240,46 +1240,6 @@ static void apply_rule_properties(Client *c, const ConfigWinRule *r) { APPLY_STRING_PROP(c, r, animation_type_close); } -int applyrulesgeom(Client *c) { - /* rule matching */ - const char *appid, *title; - ConfigWinRule *r; - int hit = 0; - int ji; - - if (!(appid = client_get_appid(c))) - appid = broken; - if (!(title = client_get_title(c))) - title = broken; - - for (ji = 0; ji < config.window_rules_count; ji++) { - if (config.window_rules_count < 1) - break; - r = &config.window_rules[ji]; - - if (!is_window_rule_matches(r, appid, title)) - continue; - - c->geom.width = r->width > 0 ? r->width : c->geom.width; - c->geom.height = r->height > 0 ? r->height : c->geom.height; - - if (!c->isnosizehint) - client_set_size_bound(c); - - // 重新计算居中的坐标 - if (r->offsetx != 0 || r->offsety != 0 || r->width > 0 || r->height > 0) - c->geom = - setclient_coordinate_center(c, c->geom, r->offsetx, r->offsety); - if (r->height > 0 || r->width > 0 || r->offsetx != 0 || - r->offsety != 0) { - hit = 1; - } else { - hit = 0; - } - } - return hit; -} - void set_float_malposition(Client *tc) { Client *c = NULL; int x, y, offset, xreverse, yreverse; @@ -1377,11 +1337,14 @@ void applyrules(Client *c) { if (r->height > 0) c->float_geom.height = r->height; - if (r->offsetx || r->offsety || r->width > 0 || r->height > 0) { - hit_rule_pos = r->offsetx || r->offsety ? true : false; + if (r->width > 0 || r->height > 0) { c->iscustomsize = 1; - c->float_geom = c->geom = setclient_coordinate_center(c, c->float_geom, - r->offsetx, r->offsety); + } + + if (r->offsetx || r->offsety) { + c->iscustompos = 1; + c->float_geom = c->geom = setclient_coordinate_center( + c, c->float_geom, r->offsetx, r->offsety); } if (c->isfloating) { c->geom = c->float_geom.width > 0 && c->float_geom.height > 0 @@ -1396,7 +1359,7 @@ void applyrules(Client *c) { // if no geom rule hit and is normal winodw, use the center pos and record // the hit size - if (!hit_rule_pos && + if (!c->iscustompos && (!client_is_x11(c) || (c->geom.x == 0 && c->geom.y == 0))) { c->float_geom = c->geom = setclient_coordinate_center(c, c->geom, 0, 0); } else { @@ -3761,6 +3724,7 @@ void init_client_properties(Client *c) { c->ignore_maximize = 1; c->ignore_minimize = 1; c->iscustomsize = 0; + c->iscustompos = 0; c->master_mfact_per = 0.0f; c->master_inner_per = 0.0f; c->stack_inner_per = 0.0f; @@ -4549,8 +4513,7 @@ void // 0.5 setfloating(Client *c, int floating) { Client *fc = NULL; - int hit; - struct wlr_box target_box, backup_box; + struct wlr_box target_box; c->isfloating = floating; bool window_size_outofrange = false; @@ -4568,12 +4531,10 @@ setfloating(Client *c, int floating) { } // 重新计算居中的坐标 - if (!client_is_x11(c) || (c->geom.x == 0 && c->geom.y == 0)) + if (!client_is_x11(c) && !c->iscustompos) target_box = setclient_coordinate_center(c, target_box, 0, 0); - backup_box = c->geom; - hit = applyrulesgeom(c); - target_box = hit == 1 ? c->geom : target_box; - c->geom = backup_box; + else + target_box = c->geom; // restore to the memeroy geom if (c->float_geom.width > 0 && c->float_geom.height > 0) { From 5ee43c302a3ba79adc64b4890f128c62bbcb6e68 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Wed, 31 Dec 2025 17:27:43 +0800 Subject: [PATCH 427/591] opt: not focus isunglobal window when focusstack --- src/fetch/client.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/fetch/client.h b/src/fetch/client.h index 56ca9822..c7ae1f26 100644 --- a/src/fetch/client.h +++ b/src/fetch/client.h @@ -396,6 +396,9 @@ Client *get_next_stack_client(Client *c, bool reverse) { if (&next->link == &clients) continue; /* wrap past the sentinel node */ + if (next->isunglobal) + continue; + if (next != c && next->mon && VISIBLEON(next, c->mon)) return next; } @@ -404,6 +407,9 @@ Client *get_next_stack_client(Client *c, bool reverse) { if (&next->link == &clients) continue; /* wrap past the sentinel node */ + if (next->isunglobal) + continue; + if (next != c && next->mon && VISIBLEON(next, c->mon)) return next; } From df2040c1dce76df162d05ad62e627bb024498069 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Wed, 31 Dec 2025 17:32:15 +0800 Subject: [PATCH 428/591] fix: isoverlay windowrule not set to correct client --- src/mango.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mango.c b/src/mango.c index ccdbf6f7..ef138a01 100644 --- a/src/mango.c +++ b/src/mango.c @@ -1431,8 +1431,8 @@ void applyrules(Client *c) { // apply overlay rule if (c->isoverlay) { - wlr_scene_node_reparent(&selmon->sel->scene->node, layers[LyrOverlay]); - wlr_scene_node_raise_to_top(&selmon->sel->scene->node); + wlr_scene_node_reparent(&c->scene->node, layers[LyrOverlay]); + wlr_scene_node_raise_to_top(&c->scene->node); } } From ec6d54148dd35d50a3fade45b852b23210ad0208 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Thu, 1 Jan 2026 09:49:33 +0800 Subject: [PATCH 429/591] opt: change view_current_to_back default to 0 --- src/config/preset.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/config/preset.h b/src/config/preset.h index 31f514f8..1d282cbd 100644 --- a/src/config/preset.h +++ b/src/config/preset.h @@ -69,7 +69,7 @@ int focus_cross_monitor = 0; int focus_cross_tag = 0; int exchange_cross_monitor = 0; int scratchpad_cross_monitor = 0; -int view_current_to_back = 1; +int view_current_to_back = 0; int no_border_when_single = 0; int no_radius_when_single = 0; int snap_distance = 30; From 89e0805d54d2cd9c92196e61c48c6ba9dc9facd7 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Thu, 1 Jan 2026 12:26:19 +0800 Subject: [PATCH 430/591] opt: optimize code struct --- src/config/parse_config.h | 2 +- src/dispatch/bind_define.h | 34 ++++++++++----------- src/ext-protocol/dwl-ipc.h | 4 +-- src/ext-protocol/foreign-toplevel.h | 4 +-- src/layout/arrange.h | 39 ++++++++++-------------- src/mango.c | 46 ++++++++++++++--------------- 6 files changed, 59 insertions(+), 70 deletions(-) diff --git a/src/config/parse_config.h b/src/config/parse_config.h index 074b5227..460d997b 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -3347,7 +3347,7 @@ void reset_option(void) { reapply_tagrule(); reapply_monitor_rules(); - arrange(selmon, false); + arrange(selmon, false, false); } int reload_config(const Arg *arg) { diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index 80512d75..96609dd0 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -244,7 +244,7 @@ int incnmaster(const Arg *arg) { return 0; selmon->pertag->nmasters[selmon->pertag->curtag] = MAX(selmon->pertag->nmasters[selmon->pertag->curtag] + arg->i, 0); - arrange(selmon, false); + arrange(selmon, false, false); return 0; } @@ -308,7 +308,7 @@ int setmfact(const Arg *arg) { c->master_mfact_per = f; } } - arrange(selmon, false); + arrange(selmon, false, false); return 0; } @@ -491,7 +491,7 @@ int restore_minimized(const Arg *arg) { c->isnamedscratchpad = 0; show_hide_client(c); setborder_color(c); - arrange(c->mon, false); + arrange(c->mon, false, false); focusclient(c, 0); warp_cursor(c); return 0; @@ -507,7 +507,7 @@ int setlayout(const Arg *arg) { if (strcmp(layouts[jk].name, arg->v) == 0) { selmon->pertag->ltidxs[selmon->pertag->curtag] = &layouts[jk]; clear_fullscreen_and_maximized_state(selmon); - arrange(selmon, false); + arrange(selmon, false, false); printstatus(); return 0; } @@ -541,7 +541,7 @@ int set_proportion(const Arg *arg) { selmon->sel->scroller_proportion = arg->f; selmon->sel->geom.width = max_client_width * arg->f; // resize(selmon->sel, selmon->sel->geom, 0); - arrange(selmon, false); + arrange(selmon, false, false); } return 0; } @@ -740,7 +740,7 @@ int centerwin(const Arg *arg) { c->geom.y = selmon->w.y + (selmon->w.height - c->geom.height) / 2; } - arrange(selmon, false); + arrange(selmon, false, false); return 0; } @@ -923,7 +923,7 @@ int switch_layout(const Arg *arg) { } } clear_fullscreen_and_maximized_state(selmon); - arrange(selmon, false); + arrange(selmon, false, false); printstatus(); return 0; } @@ -934,7 +934,7 @@ int switch_layout(const Arg *arg) { selmon->pertag->ltidxs[selmon->pertag->curtag] = jk == LENGTH(layouts) - 1 ? &layouts[0] : &layouts[jk + 1]; clear_fullscreen_and_maximized_state(selmon); - arrange(selmon, false); + arrange(selmon, false, false); printstatus(); return 0; } @@ -981,7 +981,7 @@ int switch_proportion_preset(const Arg *arg) { selmon->sel->scroller_proportion = target_proportion; selmon->sel->geom.width = max_client_width * target_proportion; // resize(selmon->sel, selmon->sel->geom, 0); - arrange(selmon, false); + arrange(selmon, false, false); } return 0; } @@ -1055,7 +1055,7 @@ int tagmon(const Arg *arg) { target = get_tags_first_tag(c->tags); view(&(Arg){.ui = target}, true); focusclient(c, 1); - arrange(selmon, false); + arrange(selmon, false, false); } if (warpcursor) { warp_cursor_to_selmon(c->mon); @@ -1079,7 +1079,7 @@ int tagsilent(const Arg *arg) { } } focusclient(focustop(selmon), 1); - arrange(target_client->mon, false); + arrange(target_client->mon, false, false); return 0; } @@ -1122,7 +1122,7 @@ int toggle_named_scratchpad(const Arg *arg) { int toggle_render_border(const Arg *arg) { render_border = !render_border; - arrange(selmon, false); + arrange(selmon, false, false); return 0; } @@ -1215,7 +1215,7 @@ int toggleglobal(const Arg *arg) { int togglegaps(const Arg *arg) { enablegaps ^= 1; - arrange(selmon, false); + arrange(selmon, false, false); return 0; } @@ -1275,7 +1275,7 @@ int toggletag(const Arg *arg) { if (newtags) { sel->tags = newtags; focusclient(focustop(selmon), 1); - arrange(selmon, false); + arrange(selmon, false, false); } printstatus(); return 0; @@ -1293,7 +1293,7 @@ int toggleview(const Arg *arg) { if (newtagset) { selmon->tagset[selmon->seltags] = newtagset; focusclient(focustop(selmon), 1); - arrange(selmon, false); + arrange(selmon, false, false); } printstatus(); return 0; @@ -1407,7 +1407,7 @@ int comboview(const Arg *arg) { if (tag_combo) { selmon->tagset[selmon->seltags] |= newtags; focusclient(focustop(selmon), 1); - arrange(selmon, false); + arrange(selmon, false, false); } else { tag_combo = true; view(&(Arg){.ui = newtags}, false); @@ -1446,7 +1446,7 @@ int zoom(const Arg *arg) { wl_list_insert(&clients, &sel->link); focusclient(sel, 1); - arrange(selmon, false); + arrange(selmon, false, false); return 0; } diff --git a/src/ext-protocol/dwl-ipc.h b/src/ext-protocol/dwl-ipc.h index eda3f49f..0ce52065 100644 --- a/src/ext-protocol/dwl-ipc.h +++ b/src/ext-protocol/dwl-ipc.h @@ -238,7 +238,7 @@ void dwl_ipc_output_set_client_tags(struct wl_client *client, selected_client->tags = newtags; if (selmon == monitor) focusclient(focustop(monitor), 1); - arrange(selmon, false); + arrange(selmon, false, false); printstatus(); } @@ -257,7 +257,7 @@ void dwl_ipc_output_set_layout(struct wl_client *client, monitor->pertag->ltidxs[monitor->pertag->curtag] = &layouts[index]; clear_fullscreen_and_maximized_state(monitor); - arrange(monitor, false); + arrange(monitor, false, false); printstatus(); } diff --git a/src/ext-protocol/foreign-toplevel.h b/src/ext-protocol/foreign-toplevel.h index 01c384fb..89f3839a 100644 --- a/src/ext-protocol/foreign-toplevel.h +++ b/src/ext-protocol/foreign-toplevel.h @@ -15,7 +15,7 @@ void handle_foreign_activate_request(struct wl_listener *listener, void *data) { c->is_scratchpad_show = 0; setborder_color(c); show_hide_client(c); - arrange(c->mon, true); + arrange(c->mon, true, false); return; } @@ -60,7 +60,7 @@ void handle_foreign_minimize_request(struct wl_listener *listener, void *data) { c->is_scratchpad_show = 0; setborder_color(c); show_hide_client(c); - arrange(c->mon, true); + arrange(c->mon, true, false); return; } } diff --git a/src/layout/arrange.h b/src/layout/arrange.h index dc8b47e0..25a057b6 100644 --- a/src/layout/arrange.h +++ b/src/layout/arrange.h @@ -200,13 +200,13 @@ void resize_tile_master_horizontal(Client *grabc, bool isdrag, int offsetx, grabc->stack_inner_per = new_stack_inner_per; if (!isdrag) { - arrange(grabc->mon, false); + arrange(grabc->mon, false, false); return; } if (last_apply_drap_time == 0 || time - last_apply_drap_time > drag_refresh_interval) { - arrange(grabc->mon, false); + arrange(grabc->mon, false, false); last_apply_drap_time = time; } } @@ -357,13 +357,13 @@ void resize_tile_master_vertical(Client *grabc, bool isdrag, int offsetx, grabc->stack_inner_per = new_stack_inner_per; if (!isdrag) { - arrange(grabc->mon, false); + arrange(grabc->mon, false, false); return; } if (last_apply_drap_time == 0 || time - last_apply_drap_time > drag_refresh_interval) { - arrange(grabc->mon, false); + arrange(grabc->mon, false, false); last_apply_drap_time = time; } } @@ -461,13 +461,13 @@ void resize_tile_scroller(Client *grabc, bool isdrag, int offsetx, int offsety, grabc->scroller_proportion = new_scroller_proportion; if (!isdrag) { - arrange(grabc->mon, false); + arrange(grabc->mon, false, false); return; } if (last_apply_drap_time == 0 || time - last_apply_drap_time > drag_refresh_interval) { - arrange(grabc->mon, false); + arrange(grabc->mon, false, false); last_apply_drap_time = time; } } @@ -576,25 +576,8 @@ void reset_size_per_mon(Monitor *m, int tile_cilent_num, } } -void reset_multi_tag_client_per(Monitor *m) { - Client *c = NULL; - wl_list_for_each(c, &clients, link) { - - if (c->isglobal || c->isunglobal) { - set_size_per(m, c); - } - - if (!VISIBLEON(c, m)) - continue; - - if (!client_only_in_one_tag(c)) { - set_size_per(m, c); - } - } -} - void // 17 -arrange(Monitor *m, bool want_animation) { +arrange(Monitor *m, bool want_animation, bool from_view) { Client *c = NULL; double total_stack_inner_percent = 0; double total_master_inner_percent = 0; @@ -617,6 +600,10 @@ arrange(Monitor *m, bool want_animation) { wl_list_for_each(c, &clients, link) { + if (from_view && (c->isglobal || c->isunglobal)) { + set_size_per(m, c); + } + if (c->mon == m && (c->isglobal || c->isunglobal)) { c->tags = m->tagset[m->seltags]; if (c->mon->sel == NULL) @@ -624,6 +611,10 @@ arrange(Monitor *m, bool want_animation) { } if (VISIBLEON(c, m)) { + if (from_view && !client_only_in_one_tag(c)) { + set_size_per(m, c); + } + if (!c->isunglobal) m->visible_clients++; diff --git a/src/mango.c b/src/mango.c index ef138a01..2e70acf0 100644 --- a/src/mango.c +++ b/src/mango.c @@ -534,9 +534,8 @@ static void applybounds( Client *c, struct wlr_box *bbox); // 设置边界规则,能让一些窗口拥有比较适合的大小 static void applyrules(Client *c); // 窗口规则应用,应用config.h中定义的窗口规则 -static void -arrange(Monitor *m, - bool want_animation); // 布局函数,让窗口俺平铺规则移动和重置大小 +static void arrange(Monitor *m, bool want_animation, + bool from_view); // 布局函数,让窗口俺平铺规则移动和重置大小 static void arrangelayer(Monitor *m, struct wl_list *list, struct wlr_box *usable_area, int exclusive); static void arrangelayers(Monitor *m); @@ -1093,7 +1092,7 @@ bool switch_scratchpad_client_state(Client *c) { if (c->is_scratchpad_show) { c->tags = get_tags_first_tag(selmon->tagset[selmon->seltags]); resize(c, c->float_geom, 0); - arrange(selmon, false); + arrange(selmon, false, false); focusclient(c, true); c->scratchpad_switching_mon = false; return true; @@ -1106,7 +1105,7 @@ bool switch_scratchpad_client_state(Client *c) { if (c->is_in_scratchpad && c->is_scratchpad_show && (c->mon->tagset[c->mon->seltags] & c->tags) == 0) { c->tags = c->mon->tagset[c->mon->seltags]; - arrange(c->mon, false); + arrange(c->mon, false, false); focusclient(c, true); return true; } else if (c->is_in_scratchpad && c->is_scratchpad_show && @@ -1415,7 +1414,7 @@ void applyrules(Client *c) { VISIBLEON(fc, c->mon) && ISFULLSCREEN(fc) && !c->isfloating) { clear_fullscreen_flag(fc); - arrange(c->mon, false); + arrange(c->mon, false, false); } if (c->isfloating && !hit_rule_pos && !c->isnamedscratchpad) { @@ -1614,7 +1613,7 @@ void arrangelayers(Monitor *m) { if (!wlr_box_equal(&usable_area, &m->w)) { m->w = usable_area; - arrange(m, false); + arrange(m, false, false); } /* Arrange non-exlusive surfaces from top->bottom */ @@ -3217,7 +3216,7 @@ void focusclient(Client *c, int lift) { (selmon->prevsel->tags & selmon->tagset[selmon->seltags]) && (c->tags & selmon->tagset[selmon->seltags]) && !c->isfloating && is_scroller_layout(selmon)) { - arrange(selmon, false); + arrange(selmon, false, false); } // change focus link position @@ -3886,7 +3885,7 @@ void unminimize(Client *c) { c->is_in_scratchpad = 0; c->isnamedscratchpad = 0; setborder_color(c); - arrange(c->mon, false); + arrange(c->mon, false, false); return; } } @@ -3904,7 +3903,7 @@ void set_minimized(Client *c) { c->is_in_scratchpad = 1; c->is_scratchpad_show = 0; focusclient(focustop(selmon), 1); - arrange(c->mon, false); + arrange(c->mon, false, false); wlr_foreign_toplevel_handle_v1_set_activated(c->foreign_toplevel, false); wlr_foreign_toplevel_handle_v1_set_minimized(c->foreign_toplevel, true); wl_list_remove(&c->link); // 从原来位置移除 @@ -4405,11 +4404,11 @@ void exchange_two_client(Client *c1, Client *c2) { tmp_tags = c2->tags; setmon(c2, c1->mon, c1->tags, false); setmon(c1, tmp_mon, tmp_tags, false); - arrange(c1->mon, false); - arrange(c2->mon, false); + arrange(c1->mon, false, false); + arrange(c2->mon, false, false); focusclient(c1, 0); } else { - arrange(c1->mon, false); + arrange(c1->mon, false, false); focusclient(c1, 0); } } @@ -4587,7 +4586,7 @@ setfloating(Client *c, int floating) { if (!c->force_maximize) client_set_maximized(c, false); - arrange(c->mon, false); + arrange(c->mon, false, false); setborder_color(c); printstatus(); } @@ -4645,7 +4644,7 @@ void setmaximizescreen(Client *c, int maximizescreen) { client_set_maximized(c, true); } - arrange(c->mon, false); + arrange(c->mon, false, false); } void setfakefullscreen(Client *c, int fakefullscreen) { @@ -4705,7 +4704,7 @@ void setfullscreen(Client *c, int fullscreen) // 用自定义全屏代理自带 set_size_per(c->mon, c); } - arrange(c->mon, false); + arrange(c->mon, false, false); } void setgaps(int oh, int ov, int ih, int iv) { @@ -4713,7 +4712,7 @@ void setgaps(int oh, int ov, int ih, int iv) { selmon->gappov = MAX(ov, 0); selmon->gappih = MAX(ih, 0); selmon->gappiv = MAX(iv, 0); - arrange(selmon, false); + arrange(selmon, false, false); } void reset_keyboard_layout(void) { @@ -4827,7 +4826,7 @@ void setmon(Client *c, Monitor *m, uint32_t newtags, bool focus) { /* Scene graph sends surface leave/enter events on move and resize */ if (oldmon) - arrange(oldmon, false); + arrange(oldmon, false, false); if (m) { /* Make sure window actually overlaps with the monitor */ resize(c, c->geom, 0); @@ -4888,7 +4887,7 @@ void show_hide_client(Client *c) { tag_client(&(Arg){.ui = target}, c); } else { c->tags = c->oldtags; - arrange(c->mon, false); + arrange(c->mon, false, false); } c->isminimized = 0; wlr_foreign_toplevel_handle_v1_set_minimized(c->foreign_toplevel, false); @@ -5573,7 +5572,7 @@ void updatemons(struct wl_listener *listener, void *data) { /* Calculate the effective monitor geometry to use for clients */ arrangelayers(m); /* Don't move clients to the left output when plugging monitors */ - arrange(m, false); + arrange(m, false, false); /* make sure fullscreen clients have the right size */ if ((c = focustop(m)) && c->isfullscreen) resize(c, m->m, 0); @@ -5694,8 +5693,7 @@ toggleseltags: if (changefocus) focusclient(focustop(m), 1); - reset_multi_tag_client_per(m); - arrange(m, want_animation); + arrange(m, want_animation, true); printstatus(); } @@ -5843,7 +5841,7 @@ void activatex11(struct wl_listener *listener, void *data) { } if (need_arrange) { - arrange(c->mon, false); + arrange(c->mon, false, false); } printstatus(); @@ -5872,7 +5870,7 @@ void configurex11(struct wl_listener *listener, void *data) { .height = event->height + c->bw * 2}, 0); } else { - arrange(c->mon, false); + arrange(c->mon, false, false); } } From ed557fa5aa8fc8fdcb3ae5422a318007603680b8 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Thu, 1 Jan 2026 12:37:00 +0800 Subject: [PATCH 431/591] fix: miss set floating window not overlap to non-custom pos client --- src/mango.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/mango.c b/src/mango.c index 2e70acf0..1aea2314 100644 --- a/src/mango.c +++ b/src/mango.c @@ -1287,7 +1287,6 @@ void applyrules(Client *c) { const ConfigWinRule *r; Monitor *m = NULL; Client *fc = NULL; - bool hit_rule_pos = false; Client *parent = NULL; parent = client_get_parent(c); @@ -1417,7 +1416,7 @@ void applyrules(Client *c) { arrange(c->mon, false, false); } - if (c->isfloating && !hit_rule_pos && !c->isnamedscratchpad) { + if (c->isfloating && !c->iscustompos && !c->isnamedscratchpad) { wl_list_remove(&c->link); wl_list_insert(clients.prev, &c->link); set_float_malposition(c); From 23d550e04d5873f3b5194ab92321ff0c1fa1e5d3 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Thu, 1 Jan 2026 14:48:49 +0800 Subject: [PATCH 432/591] fix: avoid use null mon when session not active --- src/fetch/client.h | 2 +- src/layout/arrange.h | 4 ++++ src/mango.c | 3 ++- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/fetch/client.h b/src/fetch/client.h index c7ae1f26..cf211cce 100644 --- a/src/fetch/client.h +++ b/src/fetch/client.h @@ -83,7 +83,7 @@ setclient_coordinate_center(Client *c, struct wlr_box geom, int offsetx, uint32_t cbw = check_hit_no_border(c) ? c->bw : 0; - if (!c->no_force_center) { + if (!c->no_force_center && m) { tempbox.x = m->w.x + (m->w.width - geom.width) / 2; tempbox.y = m->w.y + (m->w.height - geom.height) / 2; } else { diff --git a/src/layout/arrange.h b/src/layout/arrange.h index 25a057b6..afc8c4be 100644 --- a/src/layout/arrange.h +++ b/src/layout/arrange.h @@ -1,6 +1,10 @@ void set_size_per(Monitor *m, Client *c) { Client *fc = NULL; bool found = false; + + if (!m || !c) + return; + wl_list_for_each(fc, &clients, link) { if (VISIBLEON(fc, m) && ISTILED(fc) && fc != c) { c->master_mfact_per = fc->master_mfact_per; diff --git a/src/mango.c b/src/mango.c index 1aea2314..2c7e8753 100644 --- a/src/mango.c +++ b/src/mango.c @@ -1353,7 +1353,8 @@ void applyrules(Client *c) { } } - set_size_per(mon, c); + if (mon) + set_size_per(mon, c); // if no geom rule hit and is normal winodw, use the center pos and record // the hit size From 0d13b1002e0218373f6e3cc6ef0c4c912f6684c4 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sat, 3 Jan 2026 09:19:18 +0800 Subject: [PATCH 433/591] opt: correct the layer animation coordinate data type --- src/animation/layer.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/animation/layer.h b/src/animation/layer.h index 141f1320..e944382f 100644 --- a/src/animation/layer.h +++ b/src/animation/layer.h @@ -319,10 +319,10 @@ void layer_animation_next_tick(LayerSurface *l) { l->animation.initial.height + (l->current.height - l->animation.initial.height) * factor; - uint32_t x = l->animation.initial.x + - (l->current.x - l->animation.initial.x) * factor; - uint32_t y = l->animation.initial.y + - (l->current.y - l->animation.initial.y) * factor; + int32_t x = l->animation.initial.x + + (l->current.x - l->animation.initial.x) * factor; + int32_t y = l->animation.initial.y + + (l->current.y - l->animation.initial.y) * factor; double opacity_eased_progress = find_animation_curve_at(animation_passed, OPAFADEIN); From 2771053ee6ece3dbffb71710f76986b7ac05b76a Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sat, 3 Jan 2026 09:37:34 +0800 Subject: [PATCH 434/591] opt: animations logic all use the int type avoid the coordinates being forcibly limited to positive numbers --- mmsg/arg.h | 4 +- mmsg/mmsg.c | 46 ++-- src/animation/client.h | 134 +++++------ src/animation/common.h | 27 +-- src/animation/layer.h | 63 +++-- src/client/client.h | 43 ++-- src/common/util.c | 10 +- src/common/util.h | 4 +- src/config/parse_config.h | 387 ++++++++++++++++--------------- src/config/preset.h | 138 +++++------ src/dispatch/bind_declare.h | 142 ++++++------ src/dispatch/bind_define.h | 174 +++++++------- src/ext-protocol/dwl-ipc.h | 4 +- src/ext-protocol/ext-workspace.h | 4 +- src/ext-protocol/text-input.h | 4 +- src/fetch/client.h | 92 ++++---- src/fetch/common.h | 8 +- src/layout/arrange.h | 35 +-- src/layout/horizontal.h | 30 +-- src/layout/vertical.h | 14 +- src/mango.c | 374 ++++++++++++++--------------- 21 files changed, 876 insertions(+), 861 deletions(-) diff --git a/mmsg/arg.h b/mmsg/arg.h index ccbd65ab..c3b0d7b9 100644 --- a/mmsg/arg.h +++ b/mmsg/arg.h @@ -8,13 +8,13 @@ extern char *argv0; -/* use main(int argc, char *argv[]) */ +/* use main(int32_t argc, char *argv[]) */ #define ARGBEGIN \ for (argv0 = *argv, argv++, argc--; \ argv[0] && argv[0][0] == '-' && argv[0][1]; argc--, argv++) { \ char argc_; \ char **argv_; \ - int brk_; \ + int32_t brk_; \ if (argv[0][1] == '-' && argv[0][2] == '\0') { \ argv++; \ argc--; \ diff --git a/mmsg/mmsg.c b/mmsg/mmsg.c index 2bbe870e..ba073aad 100644 --- a/mmsg/mmsg.c +++ b/mmsg/mmsg.c @@ -25,31 +25,31 @@ static enum { WATCH = 1 << 2 | GET, } mode = NONE; -static int Oflag; -static int Tflag; -static int Lflag; -static int oflag; -static int tflag; -static int lflag; -static int cflag; -static int vflag; -static int mflag; -static int fflag; -static int qflag; -static int dflag; -static int xflag; -static int eflag; -static int kflag; -static int bflag; -static int Aflag; +static int32_t Oflag; +static int32_t Tflag; +static int32_t Lflag; +static int32_t oflag; +static int32_t tflag; +static int32_t lflag; +static int32_t cflag; +static int32_t vflag; +static int32_t mflag; +static int32_t fflag; +static int32_t qflag; +static int32_t dflag; +static int32_t xflag; +static int32_t eflag; +static int32_t kflag; +static int32_t bflag; +static int32_t Aflag; static uint32_t occ, seltags, total_clients, urg; static char *output_name; -static int tagcount; +static int32_t tagcount; static char *tagset; static char *layout_name; -static int layoutcount, layout_idx; +static int32_t layoutcount, layout_idx; static char *client_tags; static char *dispatch_cmd; static char *dispatch_arg1; @@ -87,7 +87,7 @@ static void noop_description(void *data, struct wl_output *wl_output, // 将 n 转换为 9 位二进制字符串,结果存入 buf(至少长度 10) void bin_str_9bits(char *buf, uint32_t n) { - for (int i = 8; i >= 0; i--) { + for (int32_t i = 8; i >= 0; i--) { *buf++ = ((n >> i) & 1) ? '1' : '0'; } *buf = '\0'; // 字符串结尾 @@ -324,7 +324,7 @@ static void dwl_ipc_output_frame(void *data, if (tflag) { uint32_t mask = seltags; char *t = tagset; - int i = 0; + int32_t i = 0; for (; *t && *t >= '0' && *t <= '9'; t++) i = *t - '0' + i * 10; @@ -354,7 +354,7 @@ static void dwl_ipc_output_frame(void *data, if (cflag) { uint32_t and = ~0, xor = 0; char *t = client_tags; - int i = 0; + int32_t i = 0; for (; *t && *t >= '0' && *t <= '9'; t++) i = *t - '0' + i * 10; @@ -509,7 +509,7 @@ static void usage(void) { exit(2); } -int main(int argc, char *argv[]) { +int32_t main(int32_t argc, char *argv[]) { ARGBEGIN { case 'q': qflag = 1; diff --git a/src/animation/client.h b/src/animation/client.h index 56ca3d66..51ad35e4 100644 --- a/src/animation/client.h +++ b/src/animation/client.h @@ -1,10 +1,10 @@ -void client_actual_size(Client *c, uint32_t *width, uint32_t *height) { - *width = c->animation.current.width - 2 * c->bw; +void client_actual_size(Client *c, int32_t *width, int32_t *height) { + *width = c->animation.current.width - 2 * (int32_t)c->bw; - *height = c->animation.current.height - 2 * c->bw; + *height = c->animation.current.height - 2 * (int32_t)c->bw; } -void set_rect_size(struct wlr_scene_rect *rect, int width, int height) { +void set_rect_size(struct wlr_scene_rect *rect, int32_t width, int32_t height) { wlr_scene_rect_set_size(rect, GEZERO(width), GEZERO(height)); } @@ -47,7 +47,7 @@ bool is_horizontal_right_stack_layout(Monitor *m) { return false; } -int is_special_animaiton_rule(Client *c) { +int32_t is_special_animaiton_rule(Client *c) { if (is_scroller_layout(c->mon) && !c->isfloating) { return DOWN; @@ -71,11 +71,11 @@ int is_special_animaiton_rule(Client *c) { } void set_client_open_animaiton(Client *c, struct wlr_box geo) { - int slide_direction; - int horizontal, horizontal_value; - int vertical, vertical_value; - int special_direction; - int center_x, center_y; + int32_t slide_direction; + int32_t horizontal, horizontal_value; + int32_t vertical, vertical_value; + int32_t special_direction; + int32_t center_x, center_y; if ((!c->animation_type_open && strcmp(animation_type_open, "fade") == 0) || (c->animation_type_open && @@ -147,15 +147,15 @@ void set_client_open_animaiton(Client *c, struct wlr_box geo) { } } -void snap_scene_buffer_apply_effect(struct wlr_scene_buffer *buffer, int sx, - int sy, void *data) { +void snap_scene_buffer_apply_effect(struct wlr_scene_buffer *buffer, int32_t sx, + int32_t sy, void *data) { BufferData *buffer_data = (BufferData *)data; wlr_scene_buffer_set_dest_size(buffer, buffer_data->width, buffer_data->height); } -void scene_buffer_apply_effect(struct wlr_scene_buffer *buffer, int sx, int sy, - void *data) { +void scene_buffer_apply_effect(struct wlr_scene_buffer *buffer, int32_t sx, + int32_t sy, void *data) { BufferData *buffer_data = (BufferData *)data; if (buffer_data->should_scale && buffer_data->height_scale < 1 && @@ -183,8 +183,8 @@ void scene_buffer_apply_effect(struct wlr_scene_buffer *buffer, int sx, int sy, if (buffer_data->should_scale) { - uint32_t surface_width = surface->current.width; - uint32_t surface_height = surface->current.height; + int32_t surface_width = surface->current.width; + int32_t surface_height = surface->current.height; surface_width = buffer_data->width_scale < 1 ? surface_width @@ -271,19 +271,19 @@ void client_draw_shadow(Client *c) { ? CORNER_LOCATION_NONE : CORNER_LOCATION_ALL; - int bwoffset = c->bw != 0 && hit_no_border ? (int)c->bw : 0; + int32_t bwoffset = c->bw != 0 && hit_no_border ? (int32_t)c->bw : 0; - uint32_t width, height; + int32_t width, height; client_actual_size(c, &width, &height); - uint32_t delta = shadows_size + c->bw - bwoffset; + int32_t delta = shadows_size + (int32_t)c->bw - bwoffset; /* we calculate where to clip the shadow */ struct wlr_box client_box = { .x = bwoffset, .y = bwoffset, - .width = width + (int)c->bw - bwoffset, - .height = height + (int)c->bw - bwoffset, + .width = width + (int32_t)c->bw - bwoffset, + .height = height + (int32_t)c->bw - bwoffset, }; struct wlr_box shadow_box = { @@ -313,7 +313,7 @@ void client_draw_shadow(Client *c) { .height = shadow_box.height, }; - int right_offset, bottom_offset, left_offset, top_offset; + int32_t right_offset, bottom_offset, left_offset, top_offset; if (c == grabc) { right_offset = 0; @@ -379,9 +379,9 @@ void apply_border(Client *c) { struct wlr_box clip_box = c->animation.current; // 一但在GEZERO如果使用无符号,那么其他数据也会转换为无符号导致没有负数出错 - int bw = (int)c->bw; + int32_t bw = (int32_t)c->bw; - int right_offset, bottom_offset, left_offset, top_offset; + int32_t right_offset, bottom_offset, left_offset, top_offset; if (c == grabc) { right_offset = 0; @@ -400,25 +400,27 @@ void apply_border(Client *c) { top_offset = GEZERO(c->mon->m.y - c->animation.current.y); } - int inner_surface_width = GEZERO(clip_box.width - 2 * bw); - int inner_surface_height = GEZERO(clip_box.height - 2 * bw); + int32_t inner_surface_width = GEZERO(clip_box.width - 2 * bw); + int32_t inner_surface_height = GEZERO(clip_box.height - 2 * bw); - int inner_surface_x = GEZERO(bw - left_offset); - int inner_surface_y = GEZERO(bw - top_offset); + int32_t inner_surface_x = GEZERO(bw - left_offset); + int32_t inner_surface_y = GEZERO(bw - top_offset); - int rect_x = left_offset; - int rect_y = top_offset; + int32_t rect_x = left_offset; + int32_t rect_y = top_offset; - int rect_width = + int32_t rect_width = GEZERO(c->animation.current.width - left_offset - right_offset); - int rect_height = + int32_t rect_height = GEZERO(c->animation.current.height - top_offset - bottom_offset); if (left_offset > c->bw) - inner_surface_width = inner_surface_width - left_offset + c->bw; + inner_surface_width = + inner_surface_width - left_offset + (int32_t)c->bw; if (top_offset > c->bw) - inner_surface_height = inner_surface_height - top_offset + c->bw; + inner_surface_height = + inner_surface_height - top_offset + (int32_t)c->bw; if (right_offset > 0) { inner_surface_width = @@ -446,24 +448,24 @@ void apply_border(Client *c) { } struct ivec2 clip_to_hide(Client *c, struct wlr_box *clip_box) { - int offsetx = 0, offsety = 0, offsetw = 0, offseth = 0; + int32_t offsetx = 0, offsety = 0, offsetw = 0, offseth = 0; struct ivec2 offset = {0, 0, 0, 0}; if (!ISSCROLLTILED(c) && !c->animation.tagining && !c->animation.tagouted && !c->animation.tagouting) return offset; - int bottom_out_offset = + int32_t bottom_out_offset = GEZERO(c->animation.current.y + c->animation.current.height - c->mon->m.y - c->mon->m.height); - int right_out_offset = + int32_t right_out_offset = GEZERO(c->animation.current.x + c->animation.current.width - c->mon->m.x - c->mon->m.width); - int left_out_offset = GEZERO(c->mon->m.x - c->animation.current.x); - int top_out_offset = GEZERO(c->mon->m.y - c->animation.current.y); + int32_t left_out_offset = GEZERO(c->mon->m.x - c->animation.current.x); + int32_t top_out_offset = GEZERO(c->mon->m.y - c->animation.current.y); // 必须转换为int,否计算会没有负数导致判断错误 - int bw = (int)c->bw; + int32_t bw = (int32_t)c->bw; /* 计算窗口表面超出屏幕四个方向的偏差,避免窗口超出屏幕 @@ -547,7 +549,7 @@ void client_apply_clip(Client *c, float factor) { } // 获取窗口动画实时位置矩形 - uint32_t width, height; + int32_t width, height; client_actual_size(c, &width, &height); // 计算出除了边框的窗口实际剪切大小 @@ -590,8 +592,8 @@ void client_apply_clip(Client *c, float factor) { wlr_scene_subsurface_tree_set_clip(&c->scene_surface->node, &clip_box); // 获取剪切后的表面的实际大小用于计算缩放 - int acutal_surface_width = geometry.width - offset.x - offset.width; - int acutal_surface_height = geometry.height - offset.y - offset.height; + int32_t acutal_surface_width = geometry.width - offset.x - offset.width; + int32_t acutal_surface_height = geometry.height - offset.y - offset.height; if (acutal_surface_width <= 0 || acutal_surface_height <= 0) return; @@ -623,25 +625,24 @@ void fadeout_client_animation_next_tick(Client *c) { struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); - uint32_t passed_time = timespec_to_ms(&now) - c->animation.time_started; + int32_t passed_time = timespec_to_ms(&now) - c->animation.time_started; double animation_passed = c->animation.duration ? (double)passed_time / (double)c->animation.duration : 1.0; - int type = c->animation.action = c->animation.action; + int32_t type = c->animation.action = c->animation.action; double factor = find_animation_curve_at(animation_passed, type); - uint32_t width = c->animation.initial.width + - (c->current.width - c->animation.initial.width) * factor; - uint32_t height = - c->animation.initial.height + - (c->current.height - c->animation.initial.height) * factor; + int32_t width = c->animation.initial.width + + (c->current.width - c->animation.initial.width) * factor; + int32_t height = c->animation.initial.height + + (c->current.height - c->animation.initial.height) * factor; - uint32_t x = c->animation.initial.x + - (c->current.x - c->animation.initial.x) * factor; - uint32_t y = c->animation.initial.y + - (c->current.y - c->animation.initial.y) * factor; + int32_t x = c->animation.initial.x + + (c->current.x - c->animation.initial.x) * factor; + int32_t y = c->animation.initial.y + + (c->current.y - c->animation.initial.y) * factor; wlr_scene_node_set_position(&c->scene->node, x, y); @@ -690,24 +691,23 @@ void client_animation_next_tick(Client *c) { struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); - uint32_t passed_time = timespec_to_ms(&now) - c->animation.time_started; + int32_t passed_time = timespec_to_ms(&now) - c->animation.time_started; double animation_passed = c->animation.duration ? (double)passed_time / (double)c->animation.duration : 1.0; - int type = c->animation.action == NONE ? MOVE : c->animation.action; + int32_t type = c->animation.action == NONE ? MOVE : c->animation.action; double factor = find_animation_curve_at(animation_passed, type); Client *pointer_c = NULL; double sx = 0, sy = 0; struct wlr_surface *surface = NULL; - uint32_t width = c->animation.initial.width + - (c->current.width - c->animation.initial.width) * factor; - uint32_t height = - c->animation.initial.height + - (c->current.height - c->animation.initial.height) * factor; + int32_t width = c->animation.initial.width + + (c->current.width - c->animation.initial.width) * factor; + int32_t height = c->animation.initial.height + + (c->current.height - c->animation.initial.height) * factor; int32_t x = c->animation.initial.x + (c->current.x - c->animation.initial.x) * factor; @@ -910,7 +910,7 @@ void client_set_pending_state(Client *c) { c->dirty = true; } -void resize(Client *c, struct wlr_box geo, int interact) { +void resize(Client *c, struct wlr_box geo, int32_t interact) { // 动画设置的起始函数,这里用来计算一些动画的起始值 // 动画起始位置大小是由于c->animainit_geom确定的 @@ -932,8 +932,8 @@ void resize(Client *c, struct wlr_box geo, int interact) { if (is_scroller_layout(c->mon) && (!c->isfloating || c == grabc)) { c->geom = geo; - c->geom.width = MAX(1 + 2 * (int)c->bw, c->geom.width); - c->geom.height = MAX(1 + 2 * (int)c->bw, c->geom.height); + c->geom.width = MAX(1 + 2 * (int32_t)c->bw, c->geom.width); + c->geom.height = MAX(1 + 2 * (int32_t)c->bw, c->geom.height); } else { // 这里会限制不允许窗口划出屏幕 c->geom = geo; applybounds( @@ -1113,7 +1113,7 @@ bool client_apply_focus_opacity(Client *c) { struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); - uint32_t passed_time = timespec_to_ms(&now) - c->animation.time_started; + int32_t passed_time = timespec_to_ms(&now) - c->animation.time_started; double linear_progress = c->animation.duration ? (double)passed_time / (double)c->animation.duration @@ -1138,7 +1138,7 @@ bool client_apply_focus_opacity(Client *c) { struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); - uint32_t passed_time = + int32_t passed_time = timespec_to_ms(&now) - c->opacity_animation.time_started; double linear_progress = c->opacity_animation.duration @@ -1155,7 +1155,7 @@ bool client_apply_focus_opacity(Client *c) { client_set_opacity(c, c->opacity_animation.current_opacity); // Animate border color - for (int i = 0; i < 4; i++) { + for (int32_t i = 0; i < 4; i++) { c->opacity_animation.current_border_color[i] = c->opacity_animation.initial_border_color[i] + (c->opacity_animation.target_border_color[i] - diff --git a/src/animation/common.h b/src/animation/common.h index 6e6fa048..5e4ded99 100644 --- a/src/animation/common.h +++ b/src/animation/common.h @@ -1,4 +1,4 @@ -struct dvec2 calculate_animation_curve_at(double t, int type) { +struct dvec2 calculate_animation_curve_at(double t, int32_t type) { struct dvec2 point; double *animation_curve; if (type == MOVE) { @@ -41,41 +41,41 @@ void init_baked_points(void) { baked_points_opafadeout = calloc(BAKED_POINTS_COUNT, sizeof(*baked_points_opafadeout)); - for (uint32_t i = 0; i < BAKED_POINTS_COUNT; i++) { + for (int32_t i = 0; i < BAKED_POINTS_COUNT; i++) { baked_points_move[i] = calculate_animation_curve_at( (double)i / (BAKED_POINTS_COUNT - 1), MOVE); } - for (uint32_t i = 0; i < BAKED_POINTS_COUNT; i++) { + for (int32_t i = 0; i < BAKED_POINTS_COUNT; i++) { baked_points_open[i] = calculate_animation_curve_at( (double)i / (BAKED_POINTS_COUNT - 1), OPEN); } - for (uint32_t i = 0; i < BAKED_POINTS_COUNT; i++) { + for (int32_t i = 0; i < BAKED_POINTS_COUNT; i++) { baked_points_tag[i] = calculate_animation_curve_at( (double)i / (BAKED_POINTS_COUNT - 1), TAG); } - for (uint32_t i = 0; i < BAKED_POINTS_COUNT; i++) { + for (int32_t i = 0; i < BAKED_POINTS_COUNT; i++) { baked_points_close[i] = calculate_animation_curve_at( (double)i / (BAKED_POINTS_COUNT - 1), CLOSE); } - for (uint32_t i = 0; i < BAKED_POINTS_COUNT; i++) { + for (int32_t i = 0; i < BAKED_POINTS_COUNT; i++) { baked_points_focus[i] = calculate_animation_curve_at( (double)i / (BAKED_POINTS_COUNT - 1), FOCUS); } - for (uint32_t i = 0; i < BAKED_POINTS_COUNT; i++) { + for (int32_t i = 0; i < BAKED_POINTS_COUNT; i++) { baked_points_opafadein[i] = calculate_animation_curve_at( (double)i / (BAKED_POINTS_COUNT - 1), OPAFADEIN); } - for (uint32_t i = 0; i < BAKED_POINTS_COUNT; i++) { + for (int32_t i = 0; i < BAKED_POINTS_COUNT; i++) { baked_points_opafadeout[i] = calculate_animation_curve_at( (double)i / (BAKED_POINTS_COUNT - 1), OPAFADEOUT); } } -double find_animation_curve_at(double t, int type) { - uint32_t down = 0; - uint32_t up = BAKED_POINTS_COUNT - 1; +double find_animation_curve_at(double t, int32_t type) { + int32_t down = 0; + int32_t up = BAKED_POINTS_COUNT - 1; - uint32_t middle = (up + down) / 2; + int32_t middle = (up + down) / 2; struct dvec2 *baked_points; if (type == MOVE) { baked_points = baked_points_move; @@ -106,7 +106,8 @@ double find_animation_curve_at(double t, int type) { return baked_points[up].y; } -static bool scene_node_snapshot(struct wlr_scene_node *node, int lx, int ly, +static bool scene_node_snapshot(struct wlr_scene_node *node, int32_t lx, + int32_t ly, struct wlr_scene_tree *snapshot_tree) { if (!node->enabled && node->type != WLR_SCENE_NODE_TREE) { return true; diff --git a/src/animation/layer.h b/src/animation/layer.h index e944382f..568d52b3 100644 --- a/src/animation/layer.h +++ b/src/animation/layer.h @@ -1,4 +1,4 @@ -void layer_actual_size(LayerSurface *l, uint32_t *width, uint32_t *height) { +void layer_actual_size(LayerSurface *l, int32_t *width, int32_t *height) { struct wlr_box box; if (l->animation.running) { @@ -42,7 +42,7 @@ void get_layer_target_geometry(LayerSurface *l, struct wlr_box *target_box) { .height = state->desired_height}; // 水平方向定位 - const uint32_t both_horiz = + const int32_t both_horiz = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT; if (box.width == 0) { box.x = bounds.x; @@ -57,7 +57,7 @@ void get_layer_target_geometry(LayerSurface *l, struct wlr_box *target_box) { } // 垂直方向定位 - const uint32_t both_vert = + const int32_t both_vert = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM; if (box.height == 0) { box.y = bounds.y; @@ -101,10 +101,10 @@ void get_layer_target_geometry(LayerSurface *l, struct wlr_box *target_box) { } void set_layer_dir_animaiton(LayerSurface *l, struct wlr_box *geo) { - int slide_direction; - int horizontal, horizontal_value; - int vertical, vertical_value; - int center_x, center_y; + int32_t slide_direction; + int32_t horizontal, horizontal_value; + int32_t vertical, vertical_value; + int32_t center_x, center_y; if (!l) return; @@ -161,10 +161,10 @@ void layer_draw_shadow(LayerSurface *l) { return; } - uint32_t width, height; + int32_t width, height; layer_actual_size(l, &width, &height); - uint32_t delta = shadows_size; + int32_t delta = shadows_size; /* we calculate where to clip the shadow */ struct wlr_box layer_box = { @@ -200,8 +200,8 @@ void layer_draw_shadow(LayerSurface *l) { wlr_scene_shadow_set_clipped_region(l->shadow, clipped_region); } -void layer_scene_buffer_apply_effect(struct wlr_scene_buffer *buffer, int sx, - int sy, void *data) { +void layer_scene_buffer_apply_effect(struct wlr_scene_buffer *buffer, + int32_t sx, int32_t sy, void *data) { BufferData *buffer_data = (BufferData *)data; struct wlr_scene_surface *scene_surface = @@ -212,8 +212,8 @@ void layer_scene_buffer_apply_effect(struct wlr_scene_buffer *buffer, int sx, struct wlr_surface *surface = scene_surface->surface; - uint32_t surface_width = surface->current.width * buffer_data->width_scale; - uint32_t surface_height = + int32_t surface_width = surface->current.width * buffer_data->width_scale; + int32_t surface_height = surface->current.height * buffer_data->height_scale; if (surface_height > 0 && surface_width > 0) { @@ -222,7 +222,8 @@ void layer_scene_buffer_apply_effect(struct wlr_scene_buffer *buffer, int sx, } void layer_fadeout_scene_buffer_apply_effect(struct wlr_scene_buffer *buffer, - int sx, int sy, void *data) { + int32_t sx, int32_t sy, + void *data) { BufferData *buffer_data = (BufferData *)data; wlr_scene_buffer_set_dest_size(buffer, buffer_data->width, buffer_data->height); @@ -235,24 +236,23 @@ void fadeout_layer_animation_next_tick(LayerSurface *l) { struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); - uint32_t passed_time = timespec_to_ms(&now) - l->animation.time_started; + int32_t passed_time = timespec_to_ms(&now) - l->animation.time_started; double animation_passed = l->animation.duration ? (double)passed_time / (double)l->animation.duration : 1.0; - int type = l->animation.action = l->animation.action; + int32_t type = l->animation.action = l->animation.action; double factor = find_animation_curve_at(animation_passed, type); - uint32_t width = l->animation.initial.width + - (l->current.width - l->animation.initial.width) * factor; - uint32_t height = - l->animation.initial.height + - (l->current.height - l->animation.initial.height) * factor; + int32_t width = l->animation.initial.width + + (l->current.width - l->animation.initial.width) * factor; + int32_t height = l->animation.initial.height + + (l->current.height - l->animation.initial.height) * factor; - uint32_t x = l->animation.initial.x + - (l->current.x - l->animation.initial.x) * factor; - uint32_t y = l->animation.initial.y + - (l->current.y - l->animation.initial.y) * factor; + int32_t x = l->animation.initial.x + + (l->current.x - l->animation.initial.x) * factor; + int32_t y = l->animation.initial.y + + (l->current.y - l->animation.initial.y) * factor; wlr_scene_node_set_position(&l->scene->node, x, y); @@ -304,20 +304,19 @@ void layer_animation_next_tick(LayerSurface *l) { struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); - uint32_t passed_time = timespec_to_ms(&now) - l->animation.time_started; + int32_t passed_time = timespec_to_ms(&now) - l->animation.time_started; double animation_passed = l->animation.duration ? (double)passed_time / (double)l->animation.duration : 1.0; - int type = l->animation.action == NONE ? MOVE : l->animation.action; + int32_t type = l->animation.action == NONE ? MOVE : l->animation.action; double factor = find_animation_curve_at(animation_passed, type); - uint32_t width = l->animation.initial.width + - (l->current.width - l->animation.initial.width) * factor; - uint32_t height = - l->animation.initial.height + - (l->current.height - l->animation.initial.height) * factor; + int32_t width = l->animation.initial.width + + (l->current.width - l->animation.initial.width) * factor; + int32_t height = l->animation.initial.height + + (l->current.height - l->animation.initial.height) * factor; int32_t x = l->animation.initial.x + (l->current.x - l->animation.initial.x) * factor; diff --git a/src/client/client.h b/src/client/client.h index a5d03d8b..8995a5d0 100644 --- a/src/client/client.h +++ b/src/client/client.h @@ -6,7 +6,7 @@ */ /* Leave these functions first; they're used in the others */ -static inline int client_is_x11(Client *c) { +static inline int32_t client_is_x11(Client *c) { #ifdef XWAYLAND return c->type == X11; #endif @@ -21,14 +21,15 @@ static inline struct wlr_surface *client_surface(Client *c) { return c->surface.xdg->surface; } -static inline int toplevel_from_wlr_surface(struct wlr_surface *s, Client **pc, - LayerSurface **pl) { +static inline int32_t toplevel_from_wlr_surface(struct wlr_surface *s, + Client **pc, + LayerSurface **pl) { struct wlr_xdg_surface *xdg_surface, *tmp_xdg_surface; struct wlr_surface *root_surface; struct wlr_layer_surface_v1 *layer_surface; Client *c = NULL; LayerSurface *l = NULL; - int type = -1; + int32_t type = -1; #ifdef XWAYLAND struct wlr_xwayland_surface *xsurface; #endif @@ -88,7 +89,7 @@ end: /* The others */ static inline void client_activate_surface(struct wlr_surface *s, - int activated) { + int32_t activated) { struct wlr_xdg_toplevel *toplevel; #ifdef XWAYLAND struct wlr_xwayland_surface *xsurface; @@ -113,7 +114,7 @@ static inline const char *client_get_appid(Client *c) { : "broken"; } -static inline int client_get_pid(Client *c) { +static inline int32_t client_get_pid(Client *c) { pid_t pid; #ifdef XWAYLAND if (client_is_x11(c)) @@ -169,7 +170,7 @@ static inline Client *client_get_parent(Client *c) { return p; } -static inline int client_has_children(Client *c) { +static inline int32_t client_has_children(Client *c) { #ifdef XWAYLAND if (client_is_x11(c)) return !wl_list_empty(&c->surface.xwayland->children); @@ -189,7 +190,7 @@ static inline const char *client_get_title(Client *c) { : "broken"; } -static inline int client_is_float_type(Client *c) { +static inline int32_t client_is_float_type(Client *c) { struct wlr_xdg_toplevel *toplevel; struct wlr_xdg_toplevel_state state; @@ -229,12 +230,12 @@ static inline int client_is_float_type(Client *c) { state.min_height == state.max_height)); } -static inline int client_is_rendered_on_mon(Client *c, Monitor *m) { +static inline int32_t client_is_rendered_on_mon(Client *c, Monitor *m) { /* This is needed for when you don't want to check formal assignment, * but rather actual displaying of the pixels. * Usually VISIBLEON suffices and is also faster. */ struct wlr_surface_output *s; - int unused_lx, unused_ly; + int32_t unused_lx, unused_ly; if (!wlr_scene_node_coords(&c->scene->node, &unused_lx, &unused_ly)) return 0; wl_list_for_each(s, &client_surface(c)->current_outputs, @@ -242,8 +243,8 @@ static inline int client_is_rendered_on_mon(Client *c, Monitor *m) { return 0; } -static inline int client_is_stopped(Client *c) { - int pid; +static inline int32_t client_is_stopped(Client *c) { + int32_t pid; siginfo_t in = {0}; #ifdef XWAYLAND if (client_is_x11(c)) @@ -267,7 +268,7 @@ static inline int client_is_stopped(Client *c) { return 0; } -static inline int client_is_unmanaged(Client *c) { +static inline int32_t client_is_unmanaged(Client *c) { #ifdef XWAYLAND if (client_is_x11(c)) return c->surface.xwayland->override_redirect; @@ -299,7 +300,7 @@ static inline void client_set_border_color(Client *c, wlr_scene_rect_set_color(c->border, color); } -static inline void client_set_fullscreen(Client *c, int fullscreen) { +static inline void client_set_fullscreen(Client *c, int32_t fullscreen) { #ifdef XWAYLAND if (client_is_x11(c)) { wlr_xwayland_surface_set_fullscreen(c->surface.xwayland, fullscreen); @@ -379,7 +380,7 @@ static inline void client_set_tiled(Client *c, uint32_t edges) { } } -static inline void client_set_suspended(Client *c, int suspended) { +static inline void client_set_suspended(Client *c, int32_t suspended) { #ifdef XWAYLAND if (client_is_x11(c)) return; @@ -388,7 +389,7 @@ static inline void client_set_suspended(Client *c, int suspended) { wlr_xdg_toplevel_set_suspended(c->surface.xdg->toplevel, suspended); } -static inline int client_should_ignore_focus(Client *c) { +static inline int32_t client_should_ignore_focus(Client *c) { #ifdef XWAYLAND if (client_is_x11(c)) { @@ -403,7 +404,7 @@ static inline int client_should_ignore_focus(Client *c) { return 0; } -static inline int client_is_x11_popup(Client *c) { +static inline int32_t client_is_x11_popup(Client *c) { #ifdef XWAYLAND if (client_is_x11(c)) { @@ -432,7 +433,7 @@ static inline int client_is_x11_popup(Client *c) { return 0; } -static inline int client_should_global(Client *c) { +static inline int32_t client_should_global(Client *c) { #ifdef XWAYLAND if (client_is_x11(c)) { @@ -445,7 +446,7 @@ static inline int client_should_global(Client *c) { return 0; } -static inline int client_should_overtop(Client *c) { +static inline int32_t client_should_overtop(Client *c) { #ifdef XWAYLAND if (client_is_x11(c)) { @@ -457,7 +458,7 @@ static inline int client_should_overtop(Client *c) { return 0; } -static inline int client_wants_focus(Client *c) { +static inline int32_t client_wants_focus(Client *c) { #ifdef XWAYLAND return client_is_unmanaged(c) && wlr_xwayland_surface_override_redirect_wants_focus( @@ -468,7 +469,7 @@ static inline int client_wants_focus(Client *c) { return 0; } -static inline int client_wants_fullscreen(Client *c) { +static inline int32_t client_wants_fullscreen(Client *c) { #ifdef XWAYLAND if (client_is_x11(c)) return c->surface.xwayland->fullscreen; diff --git a/src/common/util.c b/src/common/util.c index 79972054..a15cca7c 100644 --- a/src/common/util.c +++ b/src/common/util.c @@ -36,8 +36,8 @@ void *ecalloc(size_t nmemb, size_t size) { return p; } -int fd_set_nonblock(int fd) { - int flags = fcntl(fd, F_GETFL); +int32_t fd_set_nonblock(int32_t fd) { + int32_t flags = fcntl(fd, F_GETFL); if (flags < 0) { perror("fcntl(F_GETFL):"); return -1; @@ -50,8 +50,8 @@ int fd_set_nonblock(int fd) { return 0; } -int regex_match(const char *pattern, const char *str) { - int errnum; +int32_t regex_match(const char *pattern, const char *str) { + int32_t errnum; PCRE2_SIZE erroffset; if (!pattern || !str) { @@ -70,7 +70,7 @@ int regex_match(const char *pattern, const char *str) { pcre2_match_data *match_data = pcre2_match_data_create_from_pattern(re, NULL); - int ret = + int32_t ret = pcre2_match(re, (PCRE2_SPTR)str, strlen(str), 0, 0, match_data, NULL); pcre2_match_data_free(match_data); diff --git a/src/common/util.h b/src/common/util.h index 2718eae8..8fb60338 100644 --- a/src/common/util.h +++ b/src/common/util.h @@ -3,8 +3,8 @@ void die(const char *fmt, ...); void *ecalloc(size_t nmemb, size_t size); -int fd_set_nonblock(int fd); -int regex_match(const char *pattern_mb, const char *str_mb); +int32_t fd_set_nonblock(int32_t fd); +int32_t regex_match(const char *pattern_mb, const char *str_mb); void wl_list_append(struct wl_list *list, struct wl_list *object); uint32_t get_now_in_ms(void); uint32_t timespec_to_ms(struct timespec *ts); \ No newline at end of file diff --git a/src/config/parse_config.h b/src/config/parse_config.h index 460d997b..9c278724 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -10,8 +10,9 @@ // 整数版本 - 截断小数部分 #define CLAMP_INT(x, min, max) \ - ((int)(x) < (int)(min) ? (int)(min) \ - : ((int)(x) > (int)(max) ? (int)(max) : (int)(x))) + ((int32_t)(x) < (int32_t)(min) \ + ? (int32_t)(min) \ + : ((int32_t)(x) > (int32_t)(max) ? (int32_t)(max) : (int32_t)(x))) // 浮点数版本 - 保留小数部分 #define CLAMP_FLOAT(x, min, max) \ @@ -30,13 +31,13 @@ typedef struct { typedef struct { xkb_keysym_t keysym; MultiKeycode keycode; - int type; + int32_t type; } KeySymCode; typedef struct { uint32_t mod; KeySymCode keysymcode; - int (*func)(const Arg *); + int32_t (*func)(const Arg *); Arg arg; char mode[28]; bool iscommonmode; @@ -55,42 +56,42 @@ typedef struct { const char *id; const char *title; uint32_t tags; - int isfloating; - int isfullscreen; + int32_t isfloating; + int32_t isfullscreen; float scroller_proportion; const char *animation_type_open; const char *animation_type_close; const char *layer_animation_type_open; const char *layer_animation_type_close; - int isnoborder; - int isnoshadow; - int isnoradius; - int isnoanimation; - int isopensilent; - int istagsilent; - int isnamedscratchpad; - int isunglobal; - int isglobal; - int isoverlay; - int allow_shortcuts_inhibit; - int ignore_maximize; - int ignore_minimize; - int isnosizehint; + int32_t isnoborder; + int32_t isnoshadow; + int32_t isnoradius; + int32_t isnoanimation; + int32_t isopensilent; + int32_t istagsilent; + int32_t isnamedscratchpad; + int32_t isunglobal; + int32_t isglobal; + int32_t isoverlay; + int32_t allow_shortcuts_inhibit; + int32_t ignore_maximize; + int32_t ignore_minimize; + int32_t isnosizehint; const char *monitor; - int offsetx; - int offsety; - int width; - int height; - int nofocus; - int nofadein; - int nofadeout; - int no_force_center; - int isterm; - int allow_csd; - int force_maximize; - int force_tearing; - int noswallow; - int noblur; + int32_t offsetx; + int32_t offsety; + int32_t width; + int32_t height; + int32_t nofocus; + int32_t nofadein; + int32_t nofadeout; + int32_t no_force_center; + int32_t isterm; + int32_t allow_csd; + int32_t force_maximize; + int32_t force_tearing; + int32_t noswallow; + int32_t noblur; float focused_opacity; float unfocused_opacity; float scroller_proportion_single; @@ -100,15 +101,15 @@ typedef struct { } ConfigWinRule; typedef struct { - const char *name; // 显示器名称 - float mfact; // 主区域比例 - int nmaster; // 主区域窗口数量 - const char *layout; // 布局名称(字符串) - int rr; // 旋转和翻转(假设为整数) - float scale; // 显示器缩放比例 - int x, y; // 显示器位置 - int width, height; // 显示器分辨率 - float refresh; // 刷新率 + const char *name; // 显示器名称 + float mfact; // 主区域比例 + int32_t nmaster; // 主区域窗口数量 + const char *layout; // 布局名称(字符串) + int32_t rr; // 旋转和翻转(假设为整数) + float scale; // 显示器缩放比例 + int32_t x, y; // 显示器位置 + int32_t width, height; // 显示器分辨率 + float refresh; // 刷新率 } ConfigMonitorRule; // 修改后的宏定义 @@ -129,20 +130,20 @@ KeyBinding default_key_bindings[] = {CHVT(1), CHVT(2), CHVT(3), CHVT(4), typedef struct { uint32_t mod; uint32_t button; - int (*func)(const Arg *); + int32_t (*func)(const Arg *); Arg arg; } MouseBinding; typedef struct { uint32_t mod; uint32_t dir; - int (*func)(const Arg *); + int32_t (*func)(const Arg *); Arg arg; } AxisBinding; typedef struct { uint32_t fold; - int (*func)(const Arg *); + int32_t (*func)(const Arg *); Arg arg; } SwitchBinding; @@ -150,37 +151,37 @@ typedef struct { uint32_t mod; uint32_t motion; uint32_t fingers_count; - int (*func)(const Arg *); + int32_t (*func)(const Arg *); Arg arg; } GestureBinding; typedef struct { - int id; // 标签ID (1-9) + int32_t id; // 标签ID (1-9) char *layout_name; // 布局名称 char *monitor_name; - int no_render_border; - int no_hide; + int32_t no_render_border; + int32_t no_hide; } ConfigTagRule; typedef struct { char *layer_name; // 布局名称 char *animation_type_open; char *animation_type_close; - int noblur; - int noanim; - int noshadow; + int32_t noblur; + int32_t noanim; + int32_t noshadow; } ConfigLayerRule; typedef struct { - int animations; - int layer_animations; + int32_t animations; + int32_t layer_animations; char animation_type_open[10]; char animation_type_close[10]; char layer_animation_type_open[10]; char layer_animation_type_close[10]; - int animation_fade_in; - int animation_fade_out; - int tag_animation_direction; + int32_t animation_fade_in; + int32_t animation_fade_out; + int32_t tag_animation_direction; float zoom_initial_ratio; float zoom_end_ratio; float fadein_begin_opacity; @@ -198,66 +199,66 @@ typedef struct { double animation_curve_opafadein[4]; double animation_curve_opafadeout[4]; - int scroller_structs; + int32_t scroller_structs; float scroller_default_proportion; float scroller_default_proportion_single; - int scroller_ignore_proportion_single; - int scroller_focus_center; - int scroller_prefer_center; - int edge_scroller_pointer_focus; - int focus_cross_monitor; - int exchange_cross_monitor; - int scratchpad_cross_monitor; - int focus_cross_tag; - int view_current_to_back; - int no_border_when_single; - int no_radius_when_single; - int snap_distance; - int enable_floating_snap; - int drag_tile_to_tile; + int32_t scroller_ignore_proportion_single; + int32_t scroller_focus_center; + int32_t scroller_prefer_center; + int32_t edge_scroller_pointer_focus; + int32_t focus_cross_monitor; + int32_t exchange_cross_monitor; + int32_t scratchpad_cross_monitor; + int32_t focus_cross_tag; + int32_t view_current_to_back; + int32_t no_border_when_single; + int32_t no_radius_when_single; + int32_t snap_distance; + int32_t enable_floating_snap; + int32_t drag_tile_to_tile; uint32_t swipe_min_threshold; float focused_opacity; float unfocused_opacity; float *scroller_proportion_preset; - int scroller_proportion_preset_count; + int32_t scroller_proportion_preset_count; char **circle_layout; - int circle_layout_count; + int32_t circle_layout_count; uint32_t new_is_master; float default_mfact; uint32_t default_nmaster; - int center_master_overspread; - int center_when_single_stack; + int32_t center_master_overspread; + int32_t center_when_single_stack; uint32_t hotarea_size; uint32_t enable_hotarea; uint32_t ov_tab_mode; - int overviewgappi; - int overviewgappo; + int32_t overviewgappi; + int32_t overviewgappo; uint32_t cursor_hide_timeout; uint32_t axis_bind_apply_timeout; uint32_t focus_on_activate; - int idleinhibit_ignore_visible; - int sloppyfocus; - int warpcursor; + int32_t idleinhibit_ignore_visible; + int32_t sloppyfocus; + int32_t warpcursor; /* keyboard */ - int repeat_rate; - int repeat_delay; + int32_t repeat_rate; + int32_t repeat_delay; uint32_t numlockon; /* Trackpad */ - int disable_trackpad; - int tap_to_click; - int tap_and_drag; - int drag_lock; - int mouse_natural_scrolling; - int trackpad_natural_scrolling; - int disable_while_typing; - int left_handed; - int middle_button_emulation; + int32_t disable_trackpad; + int32_t tap_to_click; + int32_t tap_and_drag; + int32_t drag_lock; + int32_t mouse_natural_scrolling; + int32_t trackpad_natural_scrolling; + int32_t disable_while_typing; + int32_t left_handed; + int32_t middle_button_emulation; uint32_t accel_profile; double accel_speed; uint32_t scroll_method; @@ -268,21 +269,21 @@ typedef struct { double axis_scroll_factor; - int blur; - int blur_layer; - int blur_optimized; - int border_radius; + int32_t blur; + int32_t blur_layer; + int32_t blur_optimized; + int32_t border_radius; struct blur_data blur_params; - int shadows; - int shadow_only_floating; - int layer_shadows; + int32_t shadows; + int32_t shadow_only_floating; + int32_t layer_shadows; uint32_t shadows_size; float shadows_blur; - int shadows_position_x; - int shadows_position_y; + int32_t shadows_position_x; + int32_t shadows_position_y; float shadowscolor[4]; - int smartgaps; + int32_t smartgaps; uint32_t gappih; uint32_t gappiv; uint32_t gappoh; @@ -302,51 +303,51 @@ typedef struct { char autostart[3][256]; ConfigTagRule *tag_rules; // 动态数组 - int tag_rules_count; // 数量 + int32_t tag_rules_count; // 数量 ConfigLayerRule *layer_rules; // 动态数组 - int layer_rules_count; // 数量 + int32_t layer_rules_count; // 数量 ConfigWinRule *window_rules; - int window_rules_count; + int32_t window_rules_count; ConfigMonitorRule *monitor_rules; // 动态数组 - int monitor_rules_count; // 条数 + int32_t monitor_rules_count; // 条数 KeyBinding *key_bindings; - int key_bindings_count; + int32_t key_bindings_count; MouseBinding *mouse_bindings; - int mouse_bindings_count; + int32_t mouse_bindings_count; AxisBinding *axis_bindings; - int axis_bindings_count; + int32_t axis_bindings_count; SwitchBinding *switch_bindings; - int switch_bindings_count; + int32_t switch_bindings_count; GestureBinding *gesture_bindings; - int gesture_bindings_count; + int32_t gesture_bindings_count; ConfigEnv **env; - int env_count; + int32_t env_count; char **exec; - int exec_count; + int32_t exec_count; char **exec_once; - int exec_once_count; + int32_t exec_once_count; char *cursor_theme; uint32_t cursor_size; - int single_scratchpad; - int xwayland_persistence; - int syncobj_enable; - int adaptive_sync; - int allow_tearing; - int allow_shortcuts_inhibit; - int allow_lock_transparent; + int32_t single_scratchpad; + int32_t xwayland_persistence; + int32_t syncobj_enable; + int32_t adaptive_sync; + int32_t allow_tearing; + int32_t allow_shortcuts_inhibit; + int32_t allow_lock_transparent; struct xkb_rule_names xkb_rules; @@ -356,7 +357,7 @@ typedef struct { struct xkb_keymap *keymap; } Config; -typedef int (*FuncType)(const Arg *); +typedef int32_t (*FuncType)(const Arg *); Config config; void parse_config_file(Config *config, const char *file_path); @@ -387,10 +388,11 @@ void trim_whitespace(char *str) { } } -int parse_double_array(const char *input, double *output, int max_count) { +int32_t parse_double_array(const char *input, double *output, + int32_t max_count) { char *dup = strdup(input); char *token; - int count = 0; + int32_t count = 0; // 先清空整个数组 memset(output, 0, max_count * sizeof(double)); @@ -438,7 +440,7 @@ void parse_bind_flags(const char *str, KeyBinding *kb) { const char *suffix = str + 4; // 跳过"bind" // 遍历后缀字符 - for (int i = 0; suffix[i] != '\0'; i++) { + for (int32_t i = 0; suffix[i] != '\0'; i++) { switch (suffix[i]) { case 's': kb->keysymcode.type = KEY_TYPE_SYM; @@ -459,10 +461,10 @@ void parse_bind_flags(const char *str, KeyBinding *kb) { } } -int parse_circle_direction(const char *str) { +int32_t parse_circle_direction(const char *str) { // 将输入字符串转换为小写 char lowerStr[10]; - int i = 0; + int32_t i = 0; while (str[i] && i < 9) { lowerStr[i] = tolower(str[i]); i++; @@ -477,10 +479,10 @@ int parse_circle_direction(const char *str) { } } -int parse_direction(const char *str) { +int32_t parse_direction(const char *str) { // 将输入字符串转换为小写 char lowerStr[10]; - int i = 0; + int32_t i = 0; while (str[i] && i < 9) { lowerStr[i] = tolower(str[i]); i++; @@ -501,10 +503,10 @@ int parse_direction(const char *str) { } } -int parse_fold_state(const char *str) { +int32_t parse_fold_state(const char *str) { // 将输入字符串转换为小写 char lowerStr[10]; - int i = 0; + int32_t i = 0; while (str[i] && i < 9) { lowerStr[i] = tolower(str[i]); i++; @@ -520,9 +522,9 @@ int parse_fold_state(const char *str) { return INVALIDFOLD; } } -long int parse_color(const char *hex_str) { +int64_t parse_color(const char *hex_str) { char *endptr; - long int hex_num = strtol(hex_str, &endptr, 16); + int64_t hex_num = strtol(hex_str, &endptr, 16); if (*endptr != '\0') { return -1; } @@ -620,8 +622,9 @@ uint32_t parse_mod(const char *mod_str) { } // 定义辅助函数:在 keymap 中查找 keysym 对应的多个 keycode -static int find_keycodes_for_keysym(struct xkb_keymap *keymap, xkb_keysym_t sym, - MultiKeycode *multi_kc) { +static int32_t find_keycodes_for_keysym(struct xkb_keymap *keymap, + xkb_keysym_t sym, + MultiKeycode *multi_kc) { xkb_keycode_t min_keycode = xkb_keymap_min_keycode(keymap); xkb_keycode_t max_keycode = xkb_keymap_max_keycode(keymap); @@ -629,16 +632,16 @@ static int find_keycodes_for_keysym(struct xkb_keymap *keymap, xkb_keysym_t sym, multi_kc->keycode2 = 0; multi_kc->keycode3 = 0; - int found_count = 0; + int32_t found_count = 0; for (xkb_keycode_t keycode = min_keycode; keycode <= max_keycode && found_count < 3; keycode++) { // 使用布局0和层级0 const xkb_keysym_t *syms; - int num_syms = + int32_t num_syms = xkb_keymap_key_get_syms_by_level(keymap, keycode, 0, 0, &syms); - for (int i = 0; i < num_syms; i++) { + for (int32_t i = 0; i < num_syms; i++) { if (syms[i] == sym) { switch (found_count) { case 0: @@ -716,7 +719,7 @@ KeySymCode parse_key(const char *key_str, bool isbindsym) { if (sym != XKB_KEY_NoSymbol) { // 尝试找到对应的多个 keycode - int found_count = + int32_t found_count = find_keycodes_for_keysym(config.keymap, sym, &kc.keycode); if (found_count > 0) { kc.type = KEY_TYPE_CODE; @@ -736,10 +739,10 @@ KeySymCode parse_key(const char *key_str, bool isbindsym) { return kc; } -int parse_button(const char *str) { +int32_t parse_button(const char *str) { // 将输入字符串转换为小写 char lowerStr[20]; - int i = 0; + int32_t i = 0; while (str[i] && i < 19) { lowerStr[i] = tolower(str[i]); i++; @@ -768,10 +771,10 @@ int parse_button(const char *str) { } } -int parse_mouse_action(const char *str) { +int32_t parse_mouse_action(const char *str) { // 将输入字符串转换为小写 char lowerStr[20]; - int i = 0; + int32_t i = 0; while (str[i] && i < 19) { lowerStr[i] = tolower(str[i]); i++; @@ -792,7 +795,7 @@ int parse_mouse_action(const char *str) { } } -void convert_hex_to_rgba(float *color, unsigned long int hex) { +void convert_hex_to_rgba(float *color, uint32_t hex) { color[0] = ((hex >> 24) & 0xFF) / 255.0f; color[1] = ((hex >> 16) & 0xFF) / 255.0f; color[2] = ((hex >> 8) & 0xFF) / 255.0f; @@ -879,7 +882,7 @@ FuncType parse_func_name(char *func_name, Arg *arg, char *arg_value, // 收集需要拼接的参数 const char *non_empty_params[4] = {NULL}; - int param_index = 0; + int32_t param_index = 0; if (arg_value2 && arg_value2[0] != '\0') non_empty_params[param_index++] = arg_value2; @@ -896,7 +899,7 @@ FuncType parse_func_name(char *func_name, Arg *arg, char *arg_value, } else { // 计算总长度 size_t len = 0; - for (int i = 0; i < param_index; i++) { + for (int32_t i = 0; i < param_index; i++) { len += strlen(non_empty_params[i]); } len += (param_index - 1) + 1; // 逗号数 + null终止符 @@ -904,7 +907,7 @@ FuncType parse_func_name(char *func_name, Arg *arg, char *arg_value, char *temp = malloc(len); if (temp) { char *cursor = temp; - for (int i = 0; i < param_index; i++) { + for (int32_t i = 0; i < param_index; i++) { if (i > 0) { *cursor++ = ','; } @@ -1008,7 +1011,7 @@ FuncType parse_func_name(char *func_name, Arg *arg, char *arg_value, token = strtok_r(arg_copy, "|", &saveptr); while (token != NULL) { - int num = atoi(token); + int32_t num = atoi(token); if (num > 0 && num <= LENGTH(tags)) { mask |= (1 << (num - 1)); } @@ -1084,7 +1087,7 @@ FuncType parse_func_name(char *func_name, Arg *arg, char *arg_value, } void set_env() { - for (int i = 0; i < config.env_count; i++) { + for (int32_t i = 0; i < config.env_count; i++) { setenv(config.env[i]->type, config.env[i]->value, 1); } } @@ -1092,7 +1095,7 @@ void set_env() { void run_exec() { Arg arg; - for (int i = 0; i < config.exec_count; i++) { + for (int32_t i = 0; i < config.exec_count; i++) { arg.v = config.exec[i]; spawn_shell(&arg); } @@ -1101,7 +1104,7 @@ void run_exec() { void run_exec_once() { Arg arg; - for (int i = 0; i < config.exec_once_count; i++) { + for (int32_t i = 0; i < config.exec_once_count; i++) { arg.v = config.exec_once[i]; spawn_shell(&arg); } @@ -1155,39 +1158,43 @@ void parse_option(Config *config, char *key, char *value) { } else if (strcmp(key, "animation_duration_focus") == 0) { config->animation_duration_focus = atoi(value); } else if (strcmp(key, "animation_curve_move") == 0) { - int num = parse_double_array(value, config->animation_curve_move, 4); + int32_t num = + parse_double_array(value, config->animation_curve_move, 4); if (num != 4) { fprintf(stderr, "Error: Failed to parse animation_curve_move: %s\n", value); } } else if (strcmp(key, "animation_curve_open") == 0) { - int num = parse_double_array(value, config->animation_curve_open, 4); + int32_t num = + parse_double_array(value, config->animation_curve_open, 4); if (num != 4) { fprintf(stderr, "Error: Failed to parse animation_curve_open: %s\n", value); } } else if (strcmp(key, "animation_curve_tag") == 0) { - int num = parse_double_array(value, config->animation_curve_tag, 4); + int32_t num = parse_double_array(value, config->animation_curve_tag, 4); if (num != 4) { fprintf(stderr, "Error: Failed to parse animation_curve_tag: %s\n", value); } } else if (strcmp(key, "animation_curve_close") == 0) { - int num = parse_double_array(value, config->animation_curve_close, 4); + int32_t num = + parse_double_array(value, config->animation_curve_close, 4); if (num != 4) { fprintf(stderr, "Error: Failed to parse animation_curve_close: %s\n", value); } } else if (strcmp(key, "animation_curve_focus") == 0) { - int num = parse_double_array(value, config->animation_curve_focus, 4); + int32_t num = + parse_double_array(value, config->animation_curve_focus, 4); if (num != 4) { fprintf(stderr, "Error: Failed to parse animation_curve_focus: %s\n", value); } } else if (strcmp(key, "animation_curve_opafadein") == 0) { - int num = + int32_t num = parse_double_array(value, config->animation_curve_opafadein, 4); if (num != 4) { fprintf(stderr, @@ -1195,7 +1202,7 @@ void parse_option(Config *config, char *key, char *value) { value); } } else if (strcmp(key, "animation_curve_opafadeout") == 0) { - int num = + int32_t num = parse_double_array(value, config->animation_curve_opafadeout, 4); if (num != 4) { fprintf(stderr, @@ -1312,12 +1319,12 @@ void parse_option(Config *config, char *key, char *value) { '\0'; // 确保字符串以 null 结尾 } else if (strcmp(key, "scroller_proportion_preset") == 0) { // 1. 统计 value 中有多少个逗号,确定需要解析的浮点数个数 - int count = 0; // 初始化为 0 + int32_t count = 0; // 初始化为 0 for (const char *p = value; *p; p++) { if (*p == ',') count++; } - int float_count = count + 1; // 浮点数的数量是逗号数量加 1 + int32_t float_count = count + 1; // 浮点数的数量是逗号数量加 1 // 2. 动态分配内存,存储浮点数 config->scroller_proportion_preset = @@ -1331,7 +1338,7 @@ void parse_option(Config *config, char *key, char *value) { char *value_copy = strdup(value); // 复制 value,因为 strtok 会修改原字符串 char *token = strtok(value_copy, ","); - int i = 0; + int32_t i = 0; float value_set; while (token != NULL && i < float_count) { @@ -1371,12 +1378,12 @@ void parse_option(Config *config, char *key, char *value) { free(value_copy); } else if (strcmp(key, "circle_layout") == 0) { // 1. 统计 value 中有多少个逗号,确定需要解析的字符串个数 - int count = 0; // 初始化为 0 + int32_t count = 0; // 初始化为 0 for (const char *p = value; *p; p++) { if (*p == ',') count++; } - int string_count = count + 1; // 字符串的数量是逗号数量加 1 + int32_t string_count = count + 1; // 字符串的数量是逗号数量加 1 // 2. 动态分配内存,存储字符串指针 config->circle_layout = (char **)malloc(string_count * sizeof(char *)); @@ -1390,7 +1397,7 @@ void parse_option(Config *config, char *key, char *value) { char *value_copy = strdup(value); // 复制 value,因为 strtok 会修改原字符串 char *token = strtok(value_copy, ","); - int i = 0; + int32_t i = 0; char *cleaned_token; while (token != NULL && i < string_count) { // 为每个字符串分配内存并复制内容 @@ -1401,7 +1408,7 @@ void parse_option(Config *config, char *key, char *value) { "Error: Memory allocation failed for string: %s\n", token); // 释放之前分配的内存 - for (int j = 0; j < i; j++) { + for (int32_t j = 0; j < i; j++) { free(config->circle_layout[j]); } free(config->circle_layout); @@ -1418,7 +1425,7 @@ void parse_option(Config *config, char *key, char *value) { if (i != string_count) { fprintf(stderr, "Error: Invalid circle_layout format: %s\n", value); // 释放之前分配的内存 - for (int j = 0; j < i; j++) { + for (int32_t j = 0; j < i; j++) { free(config->circle_layout[j]); } free(config->circle_layout); @@ -1524,7 +1531,7 @@ void parse_option(Config *config, char *key, char *value) { } else if (strcmp(key, "borderpx") == 0) { config->borderpx = atoi(value); } else if (strcmp(key, "rootcolor") == 0) { - long int color = parse_color(value); + int64_t color = parse_color(value); if (color == -1) { fprintf(stderr, "Error: Invalid rootcolor format: %s\n", value); } else { @@ -1532,28 +1539,28 @@ void parse_option(Config *config, char *key, char *value) { } } else if (strcmp(key, "shadowscolor") == 0) { - long int color = parse_color(value); + int64_t color = parse_color(value); if (color == -1) { fprintf(stderr, "Error: Invalid shadowscolor format: %s\n", value); } else { convert_hex_to_rgba(config->shadowscolor, color); } } else if (strcmp(key, "bordercolor") == 0) { - long int color = parse_color(value); + int64_t color = parse_color(value); if (color == -1) { fprintf(stderr, "Error: Invalid bordercolor format: %s\n", value); } else { convert_hex_to_rgba(config->bordercolor, color); } } else if (strcmp(key, "focuscolor") == 0) { - long int color = parse_color(value); + int64_t color = parse_color(value); if (color == -1) { fprintf(stderr, "Error: Invalid focuscolor format: %s\n", value); } else { convert_hex_to_rgba(config->focuscolor, color); } } else if (strcmp(key, "maximizescreencolor") == 0) { - long int color = parse_color(value); + int64_t color = parse_color(value); if (color == -1) { fprintf(stderr, "Error: Invalid maximizescreencolor format: %s\n", value); @@ -1561,14 +1568,14 @@ void parse_option(Config *config, char *key, char *value) { convert_hex_to_rgba(config->maximizescreencolor, color); } } else if (strcmp(key, "urgentcolor") == 0) { - long int color = parse_color(value); + int64_t color = parse_color(value); if (color == -1) { fprintf(stderr, "Error: Invalid urgentcolor format: %s\n", value); } else { convert_hex_to_rgba(config->urgentcolor, color); } } else if (strcmp(key, "scratchpadcolor") == 0) { - long int color = parse_color(value); + int64_t color = parse_color(value); if (color == -1) { fprintf(stderr, "Error: Invalid scratchpadcolor format: %s\n", value); @@ -1576,14 +1583,14 @@ void parse_option(Config *config, char *key, char *value) { convert_hex_to_rgba(config->scratchpadcolor, color); } } else if (strcmp(key, "globalcolor") == 0) { - long int color = parse_color(value); + int64_t color = parse_color(value); if (color == -1) { fprintf(stderr, "Error: Invalid globalcolor format: %s\n", value); } else { convert_hex_to_rgba(config->globalcolor, color); } } else if (strcmp(key, "overlaycolor") == 0) { - long int color = parse_color(value); + int64_t color = parse_color(value); if (color == -1) { fprintf(stderr, "Error: Invalid overlaycolor format: %s\n", value); } else { @@ -1701,7 +1708,7 @@ void parse_option(Config *config, char *key, char *value) { ConfigWinRule *rule = &config->window_rules[config->window_rules_count]; memset(rule, 0, sizeof(ConfigWinRule)); - // int rule value, relay to a client property + // int32_t rule value, relay to a client property rule->isfloating = -1; rule->isfullscreen = -1; rule->isnoborder = -1; @@ -1876,7 +1883,7 @@ void parse_option(Config *config, char *key, char *value) { raw_height[256], raw_refresh[256]; // 先读取所有字段为字符串 - int parsed = + int32_t parsed = sscanf(value, "%255[^,],%255[^,],%255[^,],%255[^,],%255[^,],%255[" "^,],%255[^,],%255[^,],%255[^,],%255[^,],%255s", @@ -2390,7 +2397,7 @@ void parse_config_file(Config *config, const char *file_path) { void free_circle_layout(Config *config) { if (config->circle_layout) { // 释放每个字符串 - for (int i = 0; i < config->circle_layout_count; i++) { + for (int32_t i = 0; i < config->circle_layout_count; i++) { if (config->circle_layout[i]) { free(config->circle_layout[i]); // 释放单个字符串 config->circle_layout[i] = NULL; // 防止野指针 @@ -2436,11 +2443,11 @@ void free_baked_points(void) { void free_config(void) { // 释放内存 - int i; + int32_t i; // 释放 window_rules if (config.window_rules) { - for (int i = 0; i < config.window_rules_count; i++) { + for (int32_t i = 0; i < config.window_rules_count; i++) { ConfigWinRule *rule = &config.window_rules[i]; if (rule->id) free((void *)rule->id); @@ -2469,7 +2476,7 @@ void free_config(void) { // 释放 monitor_rules if (config.monitor_rules) { - for (int i = 0; i < config.monitor_rules_count; i++) { + for (int32_t i = 0; i < config.monitor_rules_count; i++) { ConfigMonitorRule *rule = &config.monitor_rules[i]; free((void *)rule->name); free((void *)rule->layout); @@ -2586,7 +2593,7 @@ void free_config(void) { // 释放 tag_rules if (config.tag_rules) { - for (int i = 0; i < config.tag_rules_count; i++) { + for (int32_t i = 0; i < config.tag_rules_count; i++) { if (config.tag_rules[i].layout_name) free((void *)config.tag_rules[i].layout_name); if (config.tag_rules[i].monitor_name) @@ -2599,7 +2606,7 @@ void free_config(void) { // 释放 layer_rules if (config.layer_rules) { - for (int i = 0; i < config.layer_rules_count; i++) { + for (int32_t i = 0; i < config.layer_rules_count; i++) { if (config.layer_rules[i].layer_name) free((void *)config.layer_rules[i].layer_name); if (config.layer_rules[i].animation_type_open) @@ -2614,7 +2621,7 @@ void free_config(void) { // 释放 env if (config.env) { - for (int i = 0; i < config.env_count; i++) { + for (int32_t i = 0; i < config.env_count; i++) { if (config.env[i]->type) { free((void *)config.env[i]->type); } @@ -3144,7 +3151,7 @@ void reset_blur_params(void) { void reapply_monitor_rules(void) { ConfigMonitorRule *mr; Monitor *m = NULL; - int ji, jk; + int32_t ji, jk; struct wlr_output_state state; struct wlr_output_mode *internal_mode = NULL; wlr_output_state_init(&state); @@ -3182,7 +3189,7 @@ void reapply_monitor_rules(void) { } else if (wlr_output_is_headless(m->wlr_output)) { wlr_output_state_set_custom_mode( &state, mr->width, mr->height, - (int)roundf(mr->refresh * 1000)); + (int32_t)roundf(mr->refresh * 1000)); } } @@ -3279,7 +3286,7 @@ void reapply_pointer(void) { void reapply_master(void) { - int i; + int32_t i; Monitor *m = NULL; for (i = 0; i <= LENGTH(tags); i++) { wl_list_for_each(m, &mons, link) { @@ -3297,7 +3304,7 @@ void reapply_master(void) { } void parse_tagrule(Monitor *m) { - int i, jk; + int32_t i, jk; ConfigTagRule tr; for (i = 0; i < config.tag_rules_count; i++) { @@ -3350,7 +3357,7 @@ void reset_option(void) { arrange(selmon, false, false); } -int reload_config(const Arg *arg) { +int32_t reload_config(const Arg *arg) { parse_config(); reset_option(); printstatus(); diff --git a/src/config/preset.h b/src/config/preset.h index 1d282cbd..6f3cd891 100644 --- a/src/config/preset.h +++ b/src/config/preset.h @@ -8,17 +8,17 @@ ((hex >> 8) & 0xFF) / 255.0f, (hex & 0xFF) / 255.0f} /* animaion */ -char *animation_type_open = "slide"; // 是否启用动画 //slide,zoom -char *animation_type_close = "slide"; // 是否启用动画 //slide,zoom -char *layer_animation_type_open = "slide"; // 是否启用layer动画 //slide,zoom -char *layer_animation_type_close = "slide"; // 是否启用layer动画 //slide,zoom -int animations = 1; // 是否启用动画 -int layer_animations = 0; // 是否启用layer动画 -int tag_animation_direction = HORIZONTAL; // 标签动画方向 -int animation_fade_in = 1; // Enable animation fade in -int animation_fade_out = 1; // Enable animation fade out -float zoom_initial_ratio = 0.3; // 动画起始窗口比例 -float zoom_end_ratio = 0.8; // 动画结束窗口比例 +char *animation_type_open = "slide"; // 是否启用动画 //slide,zoom +char *animation_type_close = "slide"; // 是否启用动画 //slide,zoom +char *layer_animation_type_open = "slide"; // 是否启用layer动画 //slide,zoom +char *layer_animation_type_close = "slide"; // 是否启用layer动画 //slide,zoom +int32_t animations = 1; // 是否启用动画 +int32_t layer_animations = 0; // 是否启用layer动画 +int32_t tag_animation_direction = HORIZONTAL; // 标签动画方向 +int32_t animation_fade_in = 1; // Enable animation fade in +int32_t animation_fade_out = 1; // Enable animation fade out +float zoom_initial_ratio = 0.3; // 动画起始窗口比例 +float zoom_end_ratio = 0.8; // 动画结束窗口比例 float fadein_begin_opacity = 0.5; // Begin opac window ratio for animations float fadeout_begin_opacity = 0.5; // Begin opac window ratio for animations uint32_t animation_duration_move = 500; // Animation move speed @@ -40,47 +40,47 @@ uint32_t focus_on_activate = 1; // 收到窗口激活请求是否自动跳转 uint32_t new_is_master = 1; // 新窗口是否插在头部 double default_mfact = 0.55f; // master 窗口比例 uint32_t default_nmaster = 1; // 默认master数量 -int center_master_overspread = 0; // 中心master时是否铺满 -int center_when_single_stack = 1; // 单个stack时是否居中 +int32_t center_master_overspread = 0; // 中心master时是否铺满 +int32_t center_when_single_stack = 1; // 单个stack时是否居中 /* logging */ -int log_level = WLR_ERROR; +int32_t log_level = WLR_ERROR; uint32_t numlockon = 0; // 是否打开右边小键盘 uint32_t capslock = 0; // 是否启用快捷键 uint32_t ov_tab_mode = 0; // alt tab切换模式 uint32_t hotarea_size = 10; // 热区大小,10x10 uint32_t enable_hotarea = 1; // 是否启用鼠标热区 -int smartgaps = 0; /* 1 means no outer gap when there is only one window */ -int sloppyfocus = 1; /* focus follows mouse */ -uint32_t gappih = 5; /* horiz inner gap between windows */ -uint32_t gappiv = 5; /* vert inner gap between windows */ -uint32_t gappoh = 10; /* horiz outer gap between windows and screen edge */ -uint32_t gappov = 10; /* vert outer gap between windows and screen edge */ +int32_t smartgaps = 0; /* 1 means no outer gap when there is only one window */ +int32_t sloppyfocus = 1; /* focus follows mouse */ +uint32_t gappih = 5; /* horiz inner gap between windows */ +uint32_t gappiv = 5; /* vert inner gap between windows */ +uint32_t gappoh = 10; /* horiz outer gap between windows and screen edge */ +uint32_t gappov = 10; /* vert outer gap between windows and screen edge */ float scratchpad_width_ratio = 0.8; float scratchpad_height_ratio = 0.9; -int scroller_structs = 20; +int32_t scroller_structs = 20; float scroller_default_proportion = 0.9; float scroller_default_proportion_single = 1.0; -int scroller_ignore_proportion_single = 0; -int scroller_focus_center = 0; -int scroller_prefer_center = 0; -int focus_cross_monitor = 0; -int focus_cross_tag = 0; -int exchange_cross_monitor = 0; -int scratchpad_cross_monitor = 0; -int view_current_to_back = 0; -int no_border_when_single = 0; -int no_radius_when_single = 0; -int snap_distance = 30; -int enable_floating_snap = 0; -int drag_tile_to_tile = 0; +int32_t scroller_ignore_proportion_single = 0; +int32_t scroller_focus_center = 0; +int32_t scroller_prefer_center = 0; +int32_t focus_cross_monitor = 0; +int32_t focus_cross_tag = 0; +int32_t exchange_cross_monitor = 0; +int32_t scratchpad_cross_monitor = 0; +int32_t view_current_to_back = 0; +int32_t no_border_when_single = 0; +int32_t no_radius_when_single = 0; +int32_t snap_distance = 30; +int32_t enable_floating_snap = 0; +int32_t drag_tile_to_tile = 0; uint32_t cursor_size = 24; uint32_t cursor_hide_timeout = 0; uint32_t swipe_min_threshold = 1; -int idleinhibit_ignore_visible = +int32_t idleinhibit_ignore_visible = 0; /* 1 means idle inhibitors will disable idle tracking even if it's surface isn't visible */ uint32_t borderpx = 4; /* border pixel of windows */ @@ -94,21 +94,21 @@ float globalcolor[] = COLOR(0xb153a7ff); float overlaycolor[] = COLOR(0x14a57cff); // char *cursor_theme = "Bibata-Modern-Ice"; -int overviewgappi = 5; /* overview时 窗口与边缘 缝隙大小 */ -int overviewgappo = 30; /* overview时 窗口与窗口 缝隙大小 */ +int32_t overviewgappi = 5; /* overview时 窗口与边缘 缝隙大小 */ +int32_t overviewgappo = 30; /* overview时 窗口与窗口 缝隙大小 */ /* To conform the xdg-protocol, set the alpha to zero to restore the old * behavior */ float fullscreen_bg[] = {0.1, 0.1, 0.1, 1.0}; -int warpcursor = 1; /* Warp cursor to focused client */ -int xwayland_persistence = 1; /* xwayland persistence */ -int syncobj_enable = 0; -int adaptive_sync = 0; -int allow_lock_transparent = 0; +int32_t warpcursor = 1; /* Warp cursor to focused client */ +int32_t xwayland_persistence = 1; /* xwayland persistence */ +int32_t syncobj_enable = 0; +int32_t adaptive_sync = 0; +int32_t allow_lock_transparent = 0; double drag_refresh_interval = 16.0; -int allow_tearing = TEARING_DISABLED; -int allow_shortcuts_inhibit = SHORTCUTS_INHIBIT_ENABLE; +int32_t allow_tearing = TEARING_DISABLED; +int32_t allow_shortcuts_inhibit = SHORTCUTS_INHIBIT_ENABLE; /* keyboard */ @@ -145,21 +145,21 @@ struct xkb_rule_names xkb_rules = { .options = xkb_rules_options, }; -int repeat_rate = 25; -int repeat_delay = 600; +int32_t repeat_rate = 25; +int32_t repeat_delay = 600; /* Trackpad */ -int disable_trackpad = 0; -int tap_to_click = 1; -int tap_and_drag = 1; -int drag_lock = 1; -int mouse_natural_scrolling = 0; -int trackpad_natural_scrolling = 0; -int disable_while_typing = 1; -int left_handed = 0; -int middle_button_emulation = 0; -int single_scratchpad = 1; -int edge_scroller_pointer_focus = 1; +int32_t disable_trackpad = 0; +int32_t tap_to_click = 1; +int32_t tap_and_drag = 1; +int32_t drag_lock = 1; +int32_t mouse_natural_scrolling = 0; +int32_t trackpad_natural_scrolling = 0; +int32_t disable_while_typing = 1; +int32_t left_handed = 0; +int32_t middle_button_emulation = 0; +int32_t single_scratchpad = 1; +int32_t edge_scroller_pointer_focus = 1; /* You can choose between: LIBINPUT_CONFIG_SCROLL_NO_SCROLL @@ -210,27 +210,27 @@ static const char *tags[] = { float focused_opacity = 1.0; float unfocused_opacity = 1.0; -int border_radius = 0; -int border_radius_location_default = CORNER_LOCATION_ALL; -int blur = 0; -int blur_layer = 0; -int blur_optimized = 1; +int32_t border_radius = 0; +int32_t border_radius_location_default = CORNER_LOCATION_ALL; +int32_t blur = 0; +int32_t blur_layer = 0; +int32_t blur_optimized = 1; struct blur_data blur_params; -int blur_params_num_passes = 1; -int blur_params_radius = 5; +int32_t blur_params_num_passes = 1; +int32_t blur_params_radius = 5; float blur_params_noise = 0.02; float blur_params_brightness = 0.9; float blur_params_contrast = 0.9; float blur_params_saturation = 1.2; -int shadows = 0; -int shadow_only_floating = 1; -int layer_shadows = 0; +int32_t shadows = 0; +int32_t shadow_only_floating = 1; +int32_t layer_shadows = 0; uint32_t shadows_size = 10; double shadows_blur = 15; -int shadows_position_x = 0; -int shadows_position_y = 0; +int32_t shadows_position_x = 0; +int32_t shadows_position_y = 0; float shadowscolor[] = COLOR(0x000000ff); ; diff --git a/src/dispatch/bind_declare.h b/src/dispatch/bind_declare.h index 5bc215a2..b197778b 100644 --- a/src/dispatch/bind_declare.h +++ b/src/dispatch/bind_declare.h @@ -1,71 +1,71 @@ -int minimized(const Arg *arg); -int restore_minimized(const Arg *arg); -int toggle_scratchpad(const Arg *arg); -int focusdir(const Arg *arg); -int toggleoverview(const Arg *arg); -int set_proportion(const Arg *arg); -int switch_proportion_preset(const Arg *arg); -int zoom(const Arg *arg); -int tagsilent(const Arg *arg); -int tagtoleft(const Arg *arg); -int tagtoright(const Arg *arg); -int tagcrossmon(const Arg *arg); -int viewtoleft(const Arg *arg); -int viewtoright(const Arg *arg); -int viewtoleft_have_client(const Arg *arg); -int viewtoright_have_client(const Arg *arg); -int viewcrossmon(const Arg *arg); -int togglefloating(const Arg *arg); -int togglefullscreen(const Arg *arg); -int togglemaximizescreen(const Arg *arg); -int togglegaps(const Arg *arg); -int tagmon(const Arg *arg); -int spawn(const Arg *arg); -int spawn_shell(const Arg *arg); -int spawn_on_empty(const Arg *arg); -int setkeymode(const Arg *arg); -int switch_keyboard_layout(const Arg *arg); -int setlayout(const Arg *arg); -int switch_layout(const Arg *arg); -int setmfact(const Arg *arg); -int quit(const Arg *arg); -int moveresize(const Arg *arg); -int exchange_client(const Arg *arg); -int exchange_stack_client(const Arg *arg); -int killclient(const Arg *arg); -int toggleglobal(const Arg *arg); -int incnmaster(const Arg *arg); -int focusmon(const Arg *arg); -int focusstack(const Arg *arg); -int chvt(const Arg *arg); -int reload_config(const Arg *arg); -int smartmovewin(const Arg *arg); -int smartresizewin(const Arg *arg); -int centerwin(const Arg *arg); -int bind_to_view(const Arg *arg); -int toggletag(const Arg *arg); -int toggleview(const Arg *arg); -int tag(const Arg *arg); -int comboview(const Arg *arg); -int incgaps(const Arg *arg); -int incigaps(const Arg *arg); -int incihgaps(const Arg *arg); -int incivgaps(const Arg *arg); -int incogaps(const Arg *arg); -int incohgaps(const Arg *arg); -int incovgaps(const Arg *arg); -int defaultgaps(const Arg *arg); -int togglefakefullscreen(const Arg *arg); -int toggleoverlay(const Arg *arg); -int movewin(const Arg *arg); -int resizewin(const Arg *arg); -int toggle_named_scratchpad(const Arg *arg); -int toggle_render_border(const Arg *arg); -int create_virtual_output(const Arg *arg); -int destroy_all_virtual_output(const Arg *arg); -int focuslast(const Arg *arg); -int toggle_trackpad_enable(const Arg *arg); -int setoption(const Arg *arg); -int disable_monitor(const Arg *arg); -int enable_monitor(const Arg *arg); -int toggle_monitor(const Arg *arg); \ No newline at end of file +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 toggleoverview(const Arg *arg); +int32_t set_proportion(const Arg *arg); +int32_t switch_proportion_preset(const Arg *arg); +int32_t zoom(const Arg *arg); +int32_t tagsilent(const Arg *arg); +int32_t tagtoleft(const Arg *arg); +int32_t tagtoright(const Arg *arg); +int32_t tagcrossmon(const Arg *arg); +int32_t viewtoleft(const Arg *arg); +int32_t viewtoright(const Arg *arg); +int32_t viewtoleft_have_client(const Arg *arg); +int32_t viewtoright_have_client(const Arg *arg); +int32_t viewcrossmon(const Arg *arg); +int32_t togglefloating(const Arg *arg); +int32_t togglefullscreen(const Arg *arg); +int32_t togglemaximizescreen(const Arg *arg); +int32_t togglegaps(const Arg *arg); +int32_t tagmon(const Arg *arg); +int32_t spawn(const Arg *arg); +int32_t spawn_shell(const Arg *arg); +int32_t spawn_on_empty(const Arg *arg); +int32_t setkeymode(const Arg *arg); +int32_t switch_keyboard_layout(const Arg *arg); +int32_t setlayout(const Arg *arg); +int32_t switch_layout(const Arg *arg); +int32_t setmfact(const Arg *arg); +int32_t quit(const Arg *arg); +int32_t moveresize(const Arg *arg); +int32_t exchange_client(const Arg *arg); +int32_t exchange_stack_client(const Arg *arg); +int32_t killclient(const Arg *arg); +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 chvt(const Arg *arg); +int32_t reload_config(const Arg *arg); +int32_t smartmovewin(const Arg *arg); +int32_t smartresizewin(const Arg *arg); +int32_t centerwin(const Arg *arg); +int32_t bind_to_view(const Arg *arg); +int32_t toggletag(const Arg *arg); +int32_t toggleview(const Arg *arg); +int32_t tag(const Arg *arg); +int32_t comboview(const Arg *arg); +int32_t incgaps(const Arg *arg); +int32_t incigaps(const Arg *arg); +int32_t incihgaps(const Arg *arg); +int32_t incivgaps(const Arg *arg); +int32_t incogaps(const Arg *arg); +int32_t incohgaps(const Arg *arg); +int32_t incovgaps(const Arg *arg); +int32_t defaultgaps(const Arg *arg); +int32_t togglefakefullscreen(const Arg *arg); +int32_t toggleoverlay(const Arg *arg); +int32_t movewin(const Arg *arg); +int32_t resizewin(const Arg *arg); +int32_t toggle_named_scratchpad(const Arg *arg); +int32_t toggle_render_border(const Arg *arg); +int32_t create_virtual_output(const Arg *arg); +int32_t destroy_all_virtual_output(const Arg *arg); +int32_t focuslast(const Arg *arg); +int32_t toggle_trackpad_enable(const Arg *arg); +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); \ No newline at end of file diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index 96609dd0..2ade07ee 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -1,4 +1,4 @@ -int bind_to_view(const Arg *arg) { +int32_t bind_to_view(const Arg *arg) { uint32_t target = arg->ui; @@ -15,14 +15,14 @@ int bind_to_view(const Arg *arg) { return 0; } - if ((int)target == INT_MIN && selmon->pertag->curtag == 0) { + if ((int32_t)target == INT_MIN && selmon->pertag->curtag == 0) { if (view_current_to_back && selmon->pertag->prevtag) target = 1 << (selmon->pertag->prevtag - 1); else target = 0; } - if (target == 0 || (int)target == INT_MIN) { + if (target == 0 || (int32_t)target == INT_MIN) { view(&(Arg){.ui = ~0 & TAGMASK, .i = arg->i}, false); } else { view(&(Arg){.ui = target, .i = arg->i}, true); @@ -30,7 +30,7 @@ int bind_to_view(const Arg *arg) { return 0; } -int chvt(const Arg *arg) { +int32_t chvt(const Arg *arg) { if (selmon) { chvt_backup_tag = selmon->pertag->curtag; @@ -41,7 +41,7 @@ int chvt(const Arg *arg) { return 1; } -int create_virtual_output(const Arg *arg) { +int32_t create_virtual_output(const Arg *arg) { if (!wlr_backend_is_multi(backend)) { wlr_log(WLR_ERROR, "Expected a multi backend"); @@ -60,7 +60,7 @@ int create_virtual_output(const Arg *arg) { return 0; } -int destroy_all_virtual_output(const Arg *arg) { +int32_t destroy_all_virtual_output(const Arg *arg) { if (!wlr_backend_is_multi(backend)) { wlr_log(WLR_ERROR, "Expected a multi backend"); @@ -79,12 +79,12 @@ int destroy_all_virtual_output(const Arg *arg) { return 0; } -int defaultgaps(const Arg *arg) { +int32_t defaultgaps(const Arg *arg) { setgaps(gappoh, gappov, gappih, gappiv); return 0; } -int exchange_client(const Arg *arg) { +int32_t exchange_client(const Arg *arg) { Client *c = selmon->sel; if (!c || c->isfloating) return 0; @@ -96,7 +96,7 @@ int exchange_client(const Arg *arg) { return 0; } -int exchange_stack_client(const Arg *arg) { +int32_t exchange_stack_client(const Arg *arg) { Client *c = selmon->sel; Client *tc = NULL; if (!c || c->isfloating || c->isfullscreen || c->ismaximizescreen) @@ -111,7 +111,7 @@ int exchange_stack_client(const Arg *arg) { return 0; } -int focusdir(const Arg *arg) { +int32_t focusdir(const Arg *arg) { Client *c = NULL; c = direction_select(arg); if (c) { @@ -131,7 +131,7 @@ int focusdir(const Arg *arg) { return 0; } -int focuslast(const Arg *arg) { +int32_t focuslast(const Arg *arg) { Client *c = NULL; Client *tc = NULL; @@ -163,7 +163,7 @@ int focuslast(const Arg *arg) { if (!tc || !client_surface(tc)->mapped) return 0; - if ((int)tc->tags > 0) { + if ((int32_t)tc->tags > 0) { focusclient(tc, 1); target = get_tags_first_tag(tc->tags); view(&(Arg){.ui = target}, true); @@ -171,12 +171,12 @@ int focuslast(const Arg *arg) { return 0; } -int toggle_trackpad_enable(const Arg *arg) { +int32_t toggle_trackpad_enable(const Arg *arg) { disable_trackpad = !disable_trackpad; return 0; } -int focusmon(const Arg *arg) { +int32_t focusmon(const Arg *arg) { Client *c = NULL; Monitor *m = NULL; Monitor *tm = NULL; @@ -216,7 +216,7 @@ int focusmon(const Arg *arg) { return 0; } -int focusstack(const Arg *arg) { +int32_t focusstack(const Arg *arg) { /* Focus the next or previous client (in tiling order) on selmon */ Client *sel = focustop(selmon); Client *tc = NULL; @@ -239,7 +239,7 @@ int focusstack(const Arg *arg) { return 0; } -int incnmaster(const Arg *arg) { +int32_t incnmaster(const Arg *arg) { if (!arg || !selmon) return 0; selmon->pertag->nmasters[selmon->pertag->curtag] = @@ -248,49 +248,49 @@ int incnmaster(const Arg *arg) { return 0; } -int incgaps(const Arg *arg) { +int32_t incgaps(const Arg *arg) { setgaps(selmon->gappoh + arg->i, selmon->gappov + arg->i, selmon->gappih + arg->i, selmon->gappiv + arg->i); return 0; } -int incigaps(const Arg *arg) { +int32_t incigaps(const Arg *arg) { setgaps(selmon->gappoh, selmon->gappov, selmon->gappih + arg->i, selmon->gappiv + arg->i); return 0; } -int incogaps(const Arg *arg) { +int32_t incogaps(const Arg *arg) { setgaps(selmon->gappoh + arg->i, selmon->gappov + arg->i, selmon->gappih, selmon->gappiv); return 0; } -int incihgaps(const Arg *arg) { +int32_t incihgaps(const Arg *arg) { setgaps(selmon->gappoh, selmon->gappov, selmon->gappih + arg->i, selmon->gappiv); return 0; } -int incivgaps(const Arg *arg) { +int32_t incivgaps(const Arg *arg) { setgaps(selmon->gappoh, selmon->gappov, selmon->gappih, selmon->gappiv + arg->i); return 0; } -int incohgaps(const Arg *arg) { +int32_t incohgaps(const Arg *arg) { setgaps(selmon->gappoh + arg->i, selmon->gappov, selmon->gappih, selmon->gappiv); return 0; } -int incovgaps(const Arg *arg) { +int32_t incovgaps(const Arg *arg) { setgaps(selmon->gappoh, selmon->gappov + arg->i, selmon->gappih, selmon->gappiv); return 0; } -int setmfact(const Arg *arg) { +int32_t setmfact(const Arg *arg) { float f; Client *c = NULL; @@ -312,7 +312,7 @@ int setmfact(const Arg *arg) { return 0; } -int killclient(const Arg *arg) { +int32_t killclient(const Arg *arg) { Client *c = NULL; c = selmon->sel; if (c) { @@ -321,7 +321,7 @@ int killclient(const Arg *arg) { return 0; } -int moveresize(const Arg *arg) { +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); @@ -359,7 +359,7 @@ int moveresize(const Arg *arg) { return 0; } -int movewin(const Arg *arg) { +int32_t movewin(const Arg *arg) { Client *c = NULL; c = selmon->sel; if (!c || c->isfullscreen) @@ -397,15 +397,15 @@ int movewin(const Arg *arg) { return 0; } -int quit(const Arg *arg) { +int32_t quit(const Arg *arg) { wl_display_terminate(dpy); return 0; } -int resizewin(const Arg *arg) { +int32_t resizewin(const Arg *arg) { Client *c = NULL; c = selmon->sel; - int offsetx = 0, offsety = 0; + int32_t offsetx = 0, offsety = 0; if (!c || c->isfullscreen || c->ismaximizescreen) return 0; @@ -468,7 +468,7 @@ int resizewin(const Arg *arg) { return 0; } -int restore_minimized(const Arg *arg) { +int32_t restore_minimized(const Arg *arg) { Client *c = NULL; if (selmon && selmon->isoverview) @@ -500,8 +500,8 @@ int restore_minimized(const Arg *arg) { return 0; } -int setlayout(const Arg *arg) { - int jk; +int32_t setlayout(const Arg *arg) { + int32_t jk; for (jk = 0; jk < LENGTH(layouts); jk++) { if (strcmp(layouts[jk].name, arg->v) == 0) { @@ -515,7 +515,7 @@ int setlayout(const Arg *arg) { return 0; } -int setkeymode(const Arg *arg) { +int32_t setkeymode(const Arg *arg) { snprintf(keymode.mode, sizeof(keymode.mode), "%.27s", arg->v); if (strcmp(keymode.mode, "default") == 0) { keymode.isdefault = true; @@ -526,7 +526,7 @@ int setkeymode(const Arg *arg) { return 1; } -int set_proportion(const Arg *arg) { +int32_t set_proportion(const Arg *arg) { if (selmon->isoverview || !is_scroller_layout(selmon)) return 0; @@ -546,10 +546,10 @@ int set_proportion(const Arg *arg) { return 0; } -int smartmovewin(const Arg *arg) { +int32_t smartmovewin(const Arg *arg) { Client *c = NULL, *tc = NULL; - int nx, ny; - int buttom, top, left, right, tar; + int32_t nx, ny; + int32_t buttom, top, left, right, tar; c = selmon->sel; if (!c || c->isfullscreen) return 0; @@ -647,10 +647,10 @@ int smartmovewin(const Arg *arg) { return 0; } -int smartresizewin(const Arg *arg) { +int32_t smartresizewin(const Arg *arg) { Client *c = NULL, *tc = NULL; - int nw, nh; - int buttom, top, left, right, tar; + int32_t nw, nh; + int32_t buttom, top, left, right, tar; c = selmon->sel; if (!c || c->isfullscreen) return 0; @@ -717,7 +717,7 @@ int smartresizewin(const Arg *arg) { return 0; } -int centerwin(const Arg *arg) { +int32_t centerwin(const Arg *arg) { Client *c = NULL; c = selmon->sel; @@ -744,7 +744,7 @@ int centerwin(const Arg *arg) { return 0; } -int spawn_shell(const Arg *arg) { +int32_t spawn_shell(const Arg *arg) { if (!arg->v) return 0; @@ -771,7 +771,7 @@ int spawn_shell(const Arg *arg) { return 0; } -int spawn(const Arg *arg) { +int32_t spawn(const Arg *arg) { if (!arg->v) return 0; @@ -787,7 +787,7 @@ int spawn(const Arg *arg) { // 2. 解析参数 char *argv[64]; - int argc = 0; + int32_t argc = 0; char *token = strtok((char *)arg->v, " "); while (token != NULL && argc < 63) { wordexp_t p; @@ -811,7 +811,7 @@ int spawn(const Arg *arg) { return 0; } -int spawn_on_empty(const Arg *arg) { +int32_t spawn_on_empty(const Arg *arg) { bool is_empty = true; Client *c = NULL; @@ -831,7 +831,7 @@ int spawn_on_empty(const Arg *arg) { return 0; } -int switch_keyboard_layout(const Arg *arg) { +int32_t switch_keyboard_layout(const Arg *arg) { if (!kb_group || !kb_group->wlr_group || !seat) { wlr_log(WLR_ERROR, "Invalid keyboard group or seat"); return 0; @@ -846,7 +846,7 @@ int switch_keyboard_layout(const Arg *arg) { // 1. 获取当前布局和计算下一个布局 xkb_layout_index_t current = xkb_state_serialize_layout( keyboard->xkb_state, XKB_STATE_LAYOUT_EFFECTIVE); - const int num_layouts = xkb_keymap_num_layouts(keyboard->keymap); + const int32_t num_layouts = xkb_keymap_num_layouts(keyboard->keymap); if (num_layouts < 2) { wlr_log(WLR_INFO, "Only one layout available"); return 0; @@ -887,9 +887,9 @@ int switch_keyboard_layout(const Arg *arg) { return 0; } -int switch_layout(const Arg *arg) { +int32_t switch_layout(const Arg *arg) { - int jk, ji; + int32_t jk, ji; char *target_layout_name = NULL; uint32_t len; @@ -942,7 +942,7 @@ int switch_layout(const Arg *arg) { return 0; } -int switch_proportion_preset(const Arg *arg) { +int32_t switch_proportion_preset(const Arg *arg) { float target_proportion = 0; if (config.scroller_proportion_preset_count == 0) { @@ -958,7 +958,7 @@ int switch_proportion_preset(const Arg *arg) { if (selmon->sel) { - for (int i = 0; i < config.scroller_proportion_preset_count; i++) { + for (int32_t i = 0; i < config.scroller_proportion_preset_count; i++) { if (config.scroller_proportion_preset[i] == selmon->sel->scroller_proportion) { if (i == config.scroller_proportion_preset_count - 1) { @@ -986,13 +986,13 @@ int switch_proportion_preset(const Arg *arg) { return 0; } -int tag(const Arg *arg) { +int32_t tag(const Arg *arg) { Client *target_client = selmon->sel; tag_client(arg, target_client); return 0; } -int tagmon(const Arg *arg) { +int32_t tagmon(const Arg *arg) { Monitor *m = NULL, *cm = NULL; Client *c = focustop(selmon); @@ -1036,9 +1036,9 @@ int tagmon(const Arg *arg) { reset_foreign_tolevel(c); c->float_geom.width = - (int)(c->float_geom.width * c->mon->w.width / selmon->w.width); + (int32_t)(c->float_geom.width * c->mon->w.width / selmon->w.width); c->float_geom.height = - (int)(c->float_geom.height * c->mon->w.height / selmon->w.height); + (int32_t)(c->float_geom.height * c->mon->w.height / selmon->w.height); selmon = c->mon; c->float_geom = setclient_coordinate_center(c, c->float_geom, 0, 0); @@ -1063,7 +1063,7 @@ int tagmon(const Arg *arg) { return 0; } -int tagsilent(const Arg *arg) { +int32_t tagsilent(const Arg *arg) { Client *fc = NULL; Client *target_client = NULL; @@ -1083,7 +1083,7 @@ int tagsilent(const Arg *arg) { return 0; } -int tagtoleft(const Arg *arg) { +int32_t tagtoleft(const Arg *arg) { if (selmon->sel != NULL && __builtin_popcount(selmon->tagset[selmon->seltags] & TAGMASK) == 1 && selmon->tagset[selmon->seltags] > 1) { @@ -1092,7 +1092,7 @@ int tagtoleft(const Arg *arg) { return 0; } -int tagtoright(const Arg *arg) { +int32_t tagtoright(const Arg *arg) { if (selmon->sel != NULL && __builtin_popcount(selmon->tagset[selmon->seltags] & TAGMASK) == 1 && selmon->tagset[selmon->seltags] & (TAGMASK >> 1)) { @@ -1101,7 +1101,7 @@ int tagtoright(const Arg *arg) { return 0; } -int toggle_named_scratchpad(const Arg *arg) { +int32_t toggle_named_scratchpad(const Arg *arg) { Client *target_client = NULL; char *arg_id = arg->v; char *arg_title = arg->v2; @@ -1120,13 +1120,13 @@ int toggle_named_scratchpad(const Arg *arg) { return 0; } -int toggle_render_border(const Arg *arg) { +int32_t toggle_render_border(const Arg *arg) { render_border = !render_border; arrange(selmon, false, false); return 0; } -int toggle_scratchpad(const Arg *arg) { +int32_t toggle_scratchpad(const Arg *arg) { Client *c = NULL; bool hit = false; Client *tmp = NULL; @@ -1155,14 +1155,14 @@ int toggle_scratchpad(const Arg *arg) { return 0; } -int togglefakefullscreen(const Arg *arg) { +int32_t togglefakefullscreen(const Arg *arg) { Client *sel = focustop(selmon); if (sel) setfakefullscreen(sel, !sel->isfakefullscreen); return 0; } -int togglefloating(const Arg *arg) { +int32_t togglefloating(const Arg *arg) { Client *sel = focustop(selmon); if (selmon && selmon->isoverview) @@ -1181,7 +1181,7 @@ int togglefloating(const Arg *arg) { return 0; } -int togglefullscreen(const Arg *arg) { +int32_t togglefullscreen(const Arg *arg) { Client *sel = focustop(selmon); if (!sel) return 0; @@ -1197,7 +1197,7 @@ int togglefullscreen(const Arg *arg) { return 0; } -int toggleglobal(const Arg *arg) { +int32_t toggleglobal(const Arg *arg) { if (!selmon->sel) return 0; if (selmon->sel->is_in_scratchpad) { @@ -1213,13 +1213,13 @@ int toggleglobal(const Arg *arg) { return 0; } -int togglegaps(const Arg *arg) { +int32_t togglegaps(const Arg *arg) { enablegaps ^= 1; arrange(selmon, false, false); return 0; } -int togglemaximizescreen(const Arg *arg) { +int32_t togglemaximizescreen(const Arg *arg) { Client *sel = focustop(selmon); if (!sel) return 0; @@ -1237,7 +1237,7 @@ int togglemaximizescreen(const Arg *arg) { return 0; } -int toggleoverlay(const Arg *arg) { +int32_t toggleoverlay(const Arg *arg) { if (!selmon->sel || !selmon->sel->mon || selmon->sel->isfullscreen) { return 0; } @@ -1258,15 +1258,15 @@ int toggleoverlay(const Arg *arg) { return 0; } -int toggletag(const Arg *arg) { +int32_t toggletag(const Arg *arg) { uint32_t newtags; Client *sel = focustop(selmon); if (!sel) return 0; - if ((int)arg->ui == INT_MIN && sel->tags != (~0 & TAGMASK)) { + if ((int32_t)arg->ui == INT_MIN && sel->tags != (~0 & TAGMASK)) { newtags = ~0 & TAGMASK; - } else if ((int)arg->ui == INT_MIN && sel->tags == (~0 & TAGMASK)) { + } else if ((int32_t)arg->ui == INT_MIN && sel->tags == (~0 & TAGMASK)) { newtags = 1 << (sel->mon->pertag->curtag - 1); } else { newtags = sel->tags ^ (arg->ui & TAGMASK); @@ -1281,7 +1281,7 @@ int toggletag(const Arg *arg) { return 0; } -int toggleview(const Arg *arg) { +int32_t toggleview(const Arg *arg) { uint32_t newtagset; uint32_t target; @@ -1299,7 +1299,7 @@ int toggleview(const Arg *arg) { return 0; } -int viewtoleft(const Arg *arg) { +int32_t viewtoleft(const Arg *arg) { uint32_t target = selmon->tagset[selmon->seltags]; if (selmon->isoverview || selmon->pertag->curtag == 0) { @@ -1319,7 +1319,7 @@ int viewtoleft(const Arg *arg) { return 0; } -int viewtoright(const Arg *arg) { +int32_t viewtoright(const Arg *arg) { if (selmon->isoverview || selmon->pertag->curtag == 0) { return 0; } @@ -1336,7 +1336,7 @@ int viewtoright(const Arg *arg) { return 0; } -int viewtoleft_have_client(const Arg *arg) { +int32_t viewtoleft_have_client(const Arg *arg) { uint32_t n; uint32_t current = get_tags_first_tag_num(selmon->tagset[selmon->seltags]); bool found = false; @@ -1360,7 +1360,7 @@ int viewtoleft_have_client(const Arg *arg) { return 0; } -int viewtoright_have_client(const Arg *arg) { +int32_t viewtoright_have_client(const Arg *arg) { uint32_t n; uint32_t current = get_tags_first_tag_num(selmon->tagset[selmon->seltags]); bool found = false; @@ -1384,13 +1384,13 @@ int viewtoright_have_client(const Arg *arg) { return 0; } -int viewcrossmon(const Arg *arg) { +int32_t viewcrossmon(const Arg *arg) { focusmon(&(Arg){.v = arg->v, .i = UNDIR}); view_in_mon(arg, true, selmon, true); return 0; } -int tagcrossmon(const Arg *arg) { +int32_t tagcrossmon(const Arg *arg) { if (!selmon->sel) return 0; @@ -1398,7 +1398,7 @@ int tagcrossmon(const Arg *arg) { return 0; } -int comboview(const Arg *arg) { +int32_t comboview(const Arg *arg) { uint32_t newtags = arg->ui & TAGMASK; if (!newtags || !selmon) @@ -1417,7 +1417,7 @@ int comboview(const Arg *arg) { return 0; } -int zoom(const Arg *arg) { +int32_t zoom(const Arg *arg) { Client *c = NULL, *sel = focustop(selmon); if (!sel || !selmon || @@ -1450,14 +1450,14 @@ int zoom(const Arg *arg) { return 0; } -int setoption(const Arg *arg) { +int32_t setoption(const Arg *arg) { parse_option(&config, arg->v, arg->v2); override_config(); reset_option(); return 0; } -int minimized(const Arg *arg) { +int32_t minimized(const Arg *arg) { if (selmon && selmon->isoverview) return 0; @@ -1468,7 +1468,7 @@ int minimized(const Arg *arg) { return 0; } -int toggleoverview(const Arg *arg) { +int32_t toggleoverview(const Arg *arg) { Client *c = NULL; if (selmon->isoverview && ov_tab_mode && arg->i != 1 && selmon->sel) { @@ -1526,7 +1526,7 @@ int toggleoverview(const Arg *arg) { return 0; } -int disable_monitor(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) { @@ -1541,7 +1541,7 @@ int disable_monitor(const Arg *arg) { return 0; } -int enable_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) { @@ -1556,7 +1556,7 @@ int enable_monitor(const Arg *arg) { return 0; } -int toggle_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) { diff --git a/src/ext-protocol/dwl-ipc.h b/src/ext-protocol/dwl-ipc.h index 0ce52065..ab0bdb8d 100644 --- a/src/ext-protocol/dwl-ipc.h +++ b/src/ext-protocol/dwl-ipc.h @@ -112,7 +112,7 @@ void dwl_ipc_output_printstatus_to(DwlIpcOutput *ipc_output) { Client *c = NULL, *focused = NULL; struct wlr_keyboard *keyboard; xkb_layout_index_t current; - int tagmask, state, numclients, focused_client, tag; + int32_t tagmask, state, numclients, focused_client, tag; const char *title, *appid, *symbol; char kb_layout[32]; focused = focustop(monitor); @@ -287,7 +287,7 @@ void dwl_ipc_output_dispatch(struct wl_client *client, const char *arg3, const char *arg4, const char *arg5) { - int (*func)(const Arg *); + int32_t (*func)(const Arg *); Arg arg; func = parse_func_name((char *)dispatch, &arg, (char *)arg1, (char *)arg2, (char *)arg3, (char *)arg4, (char *)arg5); diff --git a/src/ext-protocol/ext-workspace.h b/src/ext-protocol/ext-workspace.h index 8ff53cc0..28aaeeeb 100644 --- a/src/ext-protocol/ext-workspace.h +++ b/src/ext-protocol/ext-workspace.h @@ -102,7 +102,7 @@ static void remove_workspace_by_tag(uint32_t tag, Monitor *m) { } } -static void add_workspace_by_tag(int tag, Monitor *m) { +static void add_workspace_by_tag(int32_t tag, Monitor *m) { const char *name = get_name_from_tag(tag); struct workspace *workspace = ecalloc(1, sizeof(*workspace)); @@ -162,7 +162,7 @@ void dwl_ext_workspace_printstatus(Monitor *m) { } void refresh_monitors_workspaces_status(Monitor *m) { - int i; + int32_t i; if (m->isoverview) { for (i = 1; i <= LENGTH(tags); i++) { diff --git a/src/ext-protocol/text-input.h b/src/ext-protocol/text-input.h index 4c922ac2..dbd97e11 100644 --- a/src/ext-protocol/text-input.h +++ b/src/ext-protocol/text-input.h @@ -77,7 +77,7 @@ Monitor *output_from_wlr_output(struct wlr_output *wlr_output) { return NULL; } -Monitor *output_nearest_to(int lx, int ly) { +Monitor *output_nearest_to(int32_t lx, int32_t ly) { double closest_x, closest_y; wlr_output_layout_closest_point(output_layout, NULL, lx, ly, &closest_x, &closest_y); @@ -225,7 +225,7 @@ static void update_popup_position(struct dwl_input_method_popup *popup) { Monitor *output = NULL; struct wlr_xdg_positioner_rules pointer_rules; struct wlr_box output_box; - int lx, ly; + int32_t lx, ly; struct wlr_box popup_box; if (!text_input || !relay->focused_surface || diff --git a/src/fetch/client.h b/src/fetch/client.h index cf211cce..22db0296 100644 --- a/src/fetch/client.h +++ b/src/fetch/client.h @@ -1,5 +1,5 @@ bool check_hit_no_border(Client *c) { - int i; + int32_t i; bool hit_no_border = false; if (!render_border) { hit_no_border = true; @@ -74,11 +74,11 @@ Client *get_client_by_id_or_title(const char *arg_id, const char *arg_title) { return target_client; } struct wlr_box // 计算客户端居中坐标 -setclient_coordinate_center(Client *c, struct wlr_box geom, int offsetx, - int offsety) { +setclient_coordinate_center(Client *c, struct wlr_box geom, int32_t offsetx, + int32_t offsety) { struct wlr_box tempbox; - int offset = 0; - int len = 0; + int32_t offset = 0; + int32_t len = 0; Monitor *m = c->mon ? c->mon : selmon; uint32_t cbw = check_hit_no_border(c) ? c->bw : 0; @@ -135,9 +135,9 @@ static bool is_window_rule_matches(const ConfigWinRule *r, const char *appid, Client *center_tiled_select(Monitor *m) { Client *c = NULL; Client *target_c = NULL; - long int mini_distance = -1; - int dirx, diry; - long int distance; + int64_t mini_distance = -1; + int32_t dirx, diry; + int64_t distance; wl_list_for_each(c, &clients, link) { if (c && VISIBLEON(c, m) && ISSCROLLTILED(c) && client_surface(c)->mapped && !c->isfloating && @@ -157,7 +157,7 @@ Client *find_client_by_direction(Client *tc, const Arg *arg, bool findfloating, bool ignore_align) { Client *c = NULL; Client **tempClients = NULL; // 初始化为 NULL - int last = -1; + int32_t last = -1; // 第一次遍历,计算客户端数量 wl_list_for_each(c, &clients, link) { @@ -190,23 +190,23 @@ Client *find_client_by_direction(Client *tc, const Arg *arg, bool findfloating, } } - int sel_x = tc->geom.x; - int sel_y = tc->geom.y; - long long int distance = LLONG_MAX; - long long int same_monitor_distance = LLONG_MAX; + int32_t sel_x = tc->geom.x; + int32_t sel_y = tc->geom.y; + int64_t distance = LLONG_MAX; + int64_t same_monitor_distance = LLONG_MAX; Client *tempFocusClients = NULL; Client *tempSameMonitorFocusClients = NULL; switch (arg->i) { case UP: if (!ignore_align) { - for (int _i = 0; _i <= last; _i++) { + for (int32_t _i = 0; _i <= last; _i++) { if (tempClients[_i]->geom.y < sel_y && tempClients[_i]->geom.x == sel_x && tempClients[_i]->mon == tc->mon) { - int dis_x = tempClients[_i]->geom.x - sel_x; - int dis_y = tempClients[_i]->geom.y - sel_y; - long long int tmp_distance = + int32_t dis_x = tempClients[_i]->geom.x - sel_x; + int32_t dis_y = tempClients[_i]->geom.y - sel_y; + int64_t tmp_distance = dis_x * dis_x + dis_y * dis_y; // 计算距离 if (tmp_distance < distance) { distance = tmp_distance; @@ -216,11 +216,11 @@ Client *find_client_by_direction(Client *tc, const Arg *arg, bool findfloating, } } if (!tempFocusClients) { - for (int _i = 0; _i <= last; _i++) { + for (int32_t _i = 0; _i <= last; _i++) { if (tempClients[_i]->geom.y < sel_y) { - int dis_x = tempClients[_i]->geom.x - sel_x; - int dis_y = tempClients[_i]->geom.y - sel_y; - long long int tmp_distance = + int32_t dis_x = tempClients[_i]->geom.x - sel_x; + int32_t dis_y = tempClients[_i]->geom.y - sel_y; + int64_t tmp_distance = dis_x * dis_x + dis_y * dis_y; // 计算距离 if (tmp_distance < distance) { distance = tmp_distance; @@ -237,13 +237,13 @@ Client *find_client_by_direction(Client *tc, const Arg *arg, bool findfloating, break; case DOWN: if (!ignore_align) { - for (int _i = 0; _i <= last; _i++) { + for (int32_t _i = 0; _i <= last; _i++) { if (tempClients[_i]->geom.y > sel_y && tempClients[_i]->geom.x == sel_x && tempClients[_i]->mon == tc->mon) { - int dis_x = tempClients[_i]->geom.x - sel_x; - int dis_y = tempClients[_i]->geom.y - sel_y; - long long int tmp_distance = + int32_t dis_x = tempClients[_i]->geom.x - sel_x; + int32_t dis_y = tempClients[_i]->geom.y - sel_y; + int64_t tmp_distance = dis_x * dis_x + dis_y * dis_y; // 计算距离 if (tmp_distance < distance) { distance = tmp_distance; @@ -253,11 +253,11 @@ Client *find_client_by_direction(Client *tc, const Arg *arg, bool findfloating, } } if (!tempFocusClients) { - for (int _i = 0; _i <= last; _i++) { + for (int32_t _i = 0; _i <= last; _i++) { if (tempClients[_i]->geom.y > sel_y) { - int dis_x = tempClients[_i]->geom.x - sel_x; - int dis_y = tempClients[_i]->geom.y - sel_y; - long long int tmp_distance = + int32_t dis_x = tempClients[_i]->geom.x - sel_x; + int32_t dis_y = tempClients[_i]->geom.y - sel_y; + int64_t tmp_distance = dis_x * dis_x + dis_y * dis_y; // 计算距离 if (tmp_distance < distance) { distance = tmp_distance; @@ -274,13 +274,13 @@ Client *find_client_by_direction(Client *tc, const Arg *arg, bool findfloating, break; case LEFT: if (!ignore_align) { - for (int _i = 0; _i <= last; _i++) { + for (int32_t _i = 0; _i <= last; _i++) { if (tempClients[_i]->geom.x < sel_x && tempClients[_i]->geom.y == sel_y && tempClients[_i]->mon == tc->mon) { - int dis_x = tempClients[_i]->geom.x - sel_x; - int dis_y = tempClients[_i]->geom.y - sel_y; - long long int tmp_distance = + int32_t dis_x = tempClients[_i]->geom.x - sel_x; + int32_t dis_y = tempClients[_i]->geom.y - sel_y; + int64_t tmp_distance = dis_x * dis_x + dis_y * dis_y; // 计算距离 if (tmp_distance < distance) { distance = tmp_distance; @@ -290,11 +290,11 @@ Client *find_client_by_direction(Client *tc, const Arg *arg, bool findfloating, } } if (!tempFocusClients) { - for (int _i = 0; _i <= last; _i++) { + for (int32_t _i = 0; _i <= last; _i++) { if (tempClients[_i]->geom.x < sel_x) { - int dis_x = tempClients[_i]->geom.x - sel_x; - int dis_y = tempClients[_i]->geom.y - sel_y; - long long int tmp_distance = + int32_t dis_x = tempClients[_i]->geom.x - sel_x; + int32_t dis_y = tempClients[_i]->geom.y - sel_y; + int64_t tmp_distance = dis_x * dis_x + dis_y * dis_y; // 计算距离 if (tmp_distance < distance) { distance = tmp_distance; @@ -311,13 +311,13 @@ Client *find_client_by_direction(Client *tc, const Arg *arg, bool findfloating, break; case RIGHT: if (!ignore_align) { - for (int _i = 0; _i <= last; _i++) { + for (int32_t _i = 0; _i <= last; _i++) { if (tempClients[_i]->geom.x > sel_x && tempClients[_i]->geom.y == sel_y && tempClients[_i]->mon == tc->mon) { - int dis_x = tempClients[_i]->geom.x - sel_x; - int dis_y = tempClients[_i]->geom.y - sel_y; - long long int tmp_distance = + int32_t dis_x = tempClients[_i]->geom.x - sel_x; + int32_t dis_y = tempClients[_i]->geom.y - sel_y; + int64_t tmp_distance = dis_x * dis_x + dis_y * dis_y; // 计算距离 if (tmp_distance < distance) { distance = tmp_distance; @@ -327,11 +327,11 @@ Client *find_client_by_direction(Client *tc, const Arg *arg, bool findfloating, } } if (!tempFocusClients) { - for (int _i = 0; _i <= last; _i++) { + for (int32_t _i = 0; _i <= last; _i++) { if (tempClients[_i]->geom.x > sel_x) { - int dis_x = tempClients[_i]->geom.x - sel_x; - int dis_y = tempClients[_i]->geom.y - sel_y; - long long int tmp_distance = + int32_t dis_x = tempClients[_i]->geom.x - sel_x; + int32_t dis_y = tempClients[_i]->geom.y - sel_y; + int64_t tmp_distance = dis_x * dis_x + dis_y * dis_y; // 计算距离 if (tmp_distance < distance) { distance = tmp_distance; @@ -438,7 +438,7 @@ float *get_border_color(Client *c) { } } -int is_single_bit_set(uint32_t x) { return x && !(x & (x - 1)); } +int32_t is_single_bit_set(uint32_t x) { return x && !(x & (x - 1)); } bool client_only_in_one_tag(Client *c) { uint32_t masked = c->tags & TAGMASK; diff --git a/src/fetch/common.h b/src/fetch/common.h index 68407500..58e69dc1 100644 --- a/src/fetch/common.h +++ b/src/fetch/common.h @@ -19,11 +19,11 @@ pid_t getparentprocess(pid_t p) { return (pid_t)v; } -int isdescprocess(pid_t p, pid_t c) { +int32_t isdescprocess(pid_t p, pid_t c) { while (p != c && c != 0) c = getparentprocess(c); - return (int)c; + return (int32_t)c; } void get_layout_abbr(char *abbr, const char *full_name) { @@ -31,7 +31,7 @@ void get_layout_abbr(char *abbr, const char *full_name) { abbr[0] = '\0'; // 1. 尝试在映射表中查找 - for (int i = 0; layout_mappings[i].full_name != NULL; i++) { + for (int32_t i = 0; layout_mappings[i].full_name != NULL; i++) { if (strcmp(full_name, layout_mappings[i].full_name) == 0) { strcpy(abbr, layout_mappings[i].abbr); return; @@ -83,7 +83,7 @@ void xytonode(double x, double y, struct wlr_surface **psurface, Client **pc, struct wlr_surface *surface = NULL; Client *c = NULL; LayerSurface *l = NULL; - int layer; + int32_t layer; for (layer = NUM_LAYERS - 1; !surface && layer >= 0; layer--) { diff --git a/src/layout/arrange.h b/src/layout/arrange.h index afc8c4be..d668f309 100644 --- a/src/layout/arrange.h +++ b/src/layout/arrange.h @@ -22,8 +22,9 @@ void set_size_per(Monitor *m, Client *c) { } } -void resize_tile_master_horizontal(Client *grabc, bool isdrag, int offsetx, - int offsety, uint32_t time, int type) { +void resize_tile_master_horizontal(Client *grabc, bool isdrag, int32_t offsetx, + int32_t offsety, uint32_t time, + int32_t type) { Client *tc = NULL; float delta_x, delta_y; Client *next = NULL; @@ -216,8 +217,8 @@ void resize_tile_master_horizontal(Client *grabc, bool isdrag, int offsetx, } } -void resize_tile_master_vertical(Client *grabc, bool isdrag, int offsetx, - int offsety, uint32_t time, int type) { +void resize_tile_master_vertical(Client *grabc, bool isdrag, int32_t offsetx, + int32_t offsety, uint32_t time, int32_t type) { Client *tc = NULL; float delta_x, delta_y; Client *next = NULL; @@ -373,8 +374,8 @@ void resize_tile_master_vertical(Client *grabc, bool isdrag, int offsetx, } } -void resize_tile_scroller(Client *grabc, bool isdrag, int offsetx, int offsety, - uint32_t time, bool isvertical) { +void resize_tile_scroller(Client *grabc, bool isdrag, int32_t offsetx, + int32_t offsety, uint32_t time, bool isvertical) { float delta_x, delta_y; float new_scroller_proportion; @@ -477,8 +478,8 @@ void resize_tile_scroller(Client *grabc, bool isdrag, int offsetx, int offsety, } } -void resize_tile_client(Client *grabc, bool isdrag, int offsetx, int offsety, - uint32_t time) { +void resize_tile_client(Client *grabc, bool isdrag, int32_t offsetx, + int32_t offsety, uint32_t time) { if (!grabc || grabc->isfullscreen || grabc->ismaximizescreen) return; @@ -506,14 +507,14 @@ void resize_tile_client(Client *grabc, bool isdrag, int offsetx, int offsety, } } -void reset_size_per_mon(Monitor *m, int tile_cilent_num, +void reset_size_per_mon(Monitor *m, int32_t tile_cilent_num, double total_left_stack_hight_percent, double total_right_stack_hight_percent, double total_stack_hight_percent, - double total_master_inner_percent, int master_num, - int stack_num) { + double total_master_inner_percent, int32_t master_num, + int32_t stack_num) { Client *c = NULL; - int i = 0; + int32_t i = 0; uint32_t stack_index = 0; uint32_t nmasters = m->pertag->nmasters[m->pertag->curtag]; @@ -587,11 +588,11 @@ arrange(Monitor *m, bool want_animation, bool from_view) { double total_master_inner_percent = 0; double total_right_stack_hight_percent = 0; double total_left_stack_hight_percent = 0; - int i = 0; - int nmasters = 0; - int stack_index = 0; - int master_num = 0; - int stack_num = 0; + int32_t i = 0; + int32_t nmasters = 0; + int32_t stack_index = 0; + int32_t master_num = 0; + int32_t stack_num = 0; if (!m) return; diff --git a/src/layout/horizontal.h b/src/layout/horizontal.h index a9d6248a..5a75a4c2 100644 --- a/src/layout/horizontal.h +++ b/src/layout/horizontal.h @@ -6,8 +6,10 @@ void grid(Monitor *m) { uint32_t cols, rows, overcols; Client *c = NULL; n = 0; - int target_gappo = enablegaps ? m->isoverview ? overviewgappo : gappoh : 0; - int target_gappi = enablegaps ? m->isoverview ? overviewgappi : gappih : 0; + int32_t target_gappo = + enablegaps ? m->isoverview ? overviewgappo : gappoh : 0; + int32_t target_gappi = + enablegaps ? m->isoverview ? overviewgappi : gappih : 0; float single_width_ratio = m->isoverview ? 0.7 : 0.9; float single_height_ratio = m->isoverview ? 0.8 : 0.9; @@ -111,7 +113,7 @@ void grid(Monitor *m) { void deck(Monitor *m) { uint32_t mw, my; - int i, n = 0; + int32_t i, n = 0; Client *c = NULL; Client *fc = NULL; float mfact; @@ -218,7 +220,7 @@ void scroller(Monitor *m) { Client *c = NULL, *root_client = NULL; Client **tempClients = NULL; // 初始化为 NULL struct wlr_box target_geom; - int focus_client_index = 0; + int32_t focus_client_index = 0; bool need_scroller = false; uint32_t cur_gappih = enablegaps ? m->gappih : 0; uint32_t cur_gappoh = enablegaps ? m->gappoh : 0; @@ -370,8 +372,8 @@ void center_tile(Monitor *m) { Client *c = NULL; Client *fc = NULL; double mfact = 0; - int master_num = 0; - int stack_num = 0; + int32_t master_num = 0; + int32_t stack_num = 0; n = m->visible_tiling_clients; master_num = m->pertag->nmasters[m->pertag->curtag]; @@ -411,7 +413,7 @@ void center_tile(Monitor *m) { tw = mw; // 判断是否需要主区域铺满 - int should_overspread = center_master_overspread && (n <= nmasters); + int32_t should_overspread = center_master_overspread && (n <= nmasters); uint32_t master_surplus_height = (m->w.height - 2 * cur_gappov - cur_gappiv * ie * (master_num - 1)); @@ -513,7 +515,7 @@ void center_tile(Monitor *m) { c->master_mfact_per = mfact; } - int stack_x; + int32_t stack_x; if (center_when_single_stack) { // 放在右侧(master居中时,stack在右边) stack_x = m->w.x + mx + mw + cur_gappih * ie; @@ -553,7 +555,7 @@ void center_tile(Monitor *m) { c->master_mfact_per = mfact; } - int stack_x = m->w.x + mx + mw + cur_gappih * ie; + int32_t stack_x = m->w.x + mx + mw + cur_gappih * ie; resize(c, (struct wlr_box){.x = stack_x, @@ -582,7 +584,7 @@ void center_tile(Monitor *m) { c->master_mfact_per = mfact; } - int stack_x = m->w.x + cur_gappoh; + int32_t stack_x = m->w.x + cur_gappoh; resize(c, (struct wlr_box){.x = stack_x, .y = m->w.y + oty, @@ -602,8 +604,8 @@ void tile(Monitor *m) { Client *c = NULL; Client *fc = NULL; double mfact = 0; - int master_num = 0; - int stack_num = 0; + int32_t master_num = 0; + int32_t stack_num = 0; n = m->visible_tiling_clients; master_num = m->pertag->nmasters[m->pertag->curtag]; @@ -712,8 +714,8 @@ void right_tile(Monitor *m) { Client *c = NULL; Client *fc = NULL; double mfact = 0; - int master_num = 0; - int stack_num = 0; + int32_t master_num = 0; + int32_t stack_num = 0; n = m->visible_tiling_clients; master_num = m->pertag->nmasters[m->pertag->curtag]; diff --git a/src/layout/vertical.h b/src/layout/vertical.h index da6a1279..6222e7c2 100644 --- a/src/layout/vertical.h +++ b/src/layout/vertical.h @@ -3,8 +3,8 @@ void vertical_tile(Monitor *m) { Client *c = NULL; Client *fc = NULL; double mfact = 0; - int master_num = 0; - int stack_num = 0; + int32_t master_num = 0; + int32_t stack_num = 0; n = m->visible_tiling_clients; master_num = m->pertag->nmasters[m->pertag->curtag]; @@ -106,7 +106,7 @@ void vertical_tile(Monitor *m) { void vertical_deck(Monitor *m) { uint32_t mh, mx; - int i, n = 0; + int32_t i, n = 0; Client *c = NULL; Client *fc = NULL; float mfact; @@ -207,7 +207,7 @@ void vertical_scroller(Monitor *m) { Client *c = NULL, *root_client = NULL; Client **tempClients = NULL; struct wlr_box target_geom; - int focus_client_index = 0; + int32_t focus_client_index = 0; bool need_scroller = false; uint32_t cur_gappiv = enablegaps ? m->gappiv : 0; uint32_t cur_gappov = enablegaps ? m->gappov : 0; @@ -359,8 +359,10 @@ void vertical_grid(Monitor *m) { uint32_t dy; uint32_t rows, cols, overrows; Client *c = NULL; - int target_gappo = enablegaps ? m->isoverview ? overviewgappo : gappov : 0; - int target_gappi = enablegaps ? m->isoverview ? overviewgappi : gappiv : 0; + int32_t target_gappo = + enablegaps ? m->isoverview ? overviewgappo : gappov : 0; + int32_t target_gappi = + enablegaps ? m->isoverview ? overviewgappi : gappiv : 0; float single_width_ratio = m->isoverview ? 0.7 : 0.9; float single_height_ratio = m->isoverview ? 0.8 : 0.9; diff --git a/src/mango.c b/src/mango.c index 2c7e8753..b19cfbf5 100644 --- a/src/mango.c +++ b/src/mango.c @@ -212,12 +212,12 @@ struct dvec2 { }; struct ivec2 { - int x, y, width, height; + int32_t x, y, width, height; }; typedef struct { - int i; - int i2; + int32_t i; + int32_t i2; float f; float f2; char *v; @@ -230,7 +230,7 @@ typedef struct { typedef struct { uint32_t mod; uint32_t button; - int (*func)(const Arg *); + int32_t (*func)(const Arg *); const Arg arg; } Button; // 鼠标按键 @@ -242,7 +242,7 @@ typedef struct { typedef struct { uint32_t mod; uint32_t dir; - int (*func)(const Arg *); + int32_t (*func)(const Arg *); const Arg arg; } Axis; @@ -273,7 +273,7 @@ struct dwl_animation { uint32_t duration; struct wlr_box initial; struct wlr_box current; - int action; + int32_t action; }; struct dwl_opacity_animation { @@ -291,8 +291,8 @@ struct dwl_opacity_animation { typedef struct { float width_scale; float height_scale; - int width; - int height; + int32_t width; + int32_t height; enum corner_location corner_location; bool should_scale; } BufferData; @@ -336,14 +336,14 @@ struct Client { bool dirty; uint32_t configure_serial; struct wlr_foreign_toplevel_handle_v1 *foreign_toplevel; - int isfloating, isurgent, isfullscreen, isfakefullscreen, + int32_t isfloating, isurgent, isfullscreen, isfakefullscreen, need_float_size_reduce, isminimized, isoverlay, isnosizehint, ignore_maximize, ignore_minimize; - int ismaximizescreen; - int overview_backup_bw; - int fullscreen_backup_x, fullscreen_backup_y, fullscreen_backup_w, + int32_t ismaximizescreen; + int32_t overview_backup_bw; + int32_t fullscreen_backup_x, fullscreen_backup_y, fullscreen_backup_w, fullscreen_backup_h; - int overview_isfullscreenbak, overview_ismaximizescreenbak, + int32_t overview_isfullscreenbak, overview_ismaximizescreenbak, overview_isfloatingbak; struct wlr_xdg_toplevel_decoration_v1 *decoration; @@ -358,53 +358,53 @@ struct Client { const char *animation_type_open; const char *animation_type_close; - int is_in_scratchpad; - int iscustomsize; - int iscustompos; - int is_scratchpad_show; - int isglobal; - int isnoborder; - int isnoshadow; - int isnoradius; - int isnoanimation; - int isopensilent; - int istagsilent; - int iskilling; - int istagswitching; - int isnamedscratchpad; + int32_t is_in_scratchpad; + int32_t iscustomsize; + int32_t iscustompos; + int32_t is_scratchpad_show; + int32_t isglobal; + int32_t isnoborder; + int32_t isnoshadow; + int32_t isnoradius; + int32_t isnoanimation; + int32_t isopensilent; + int32_t istagsilent; + int32_t iskilling; + int32_t istagswitching; + int32_t isnamedscratchpad; bool is_pending_open_animation; bool is_restoring_from_ov; float scroller_proportion; bool need_output_flush; struct dwl_animation animation; struct dwl_opacity_animation opacity_animation; - int isterm, noswallow; - int allow_csd; - int force_maximize; + int32_t isterm, noswallow; + int32_t allow_csd; + int32_t force_maximize; pid_t pid; Client *swallowing, *swallowedby; bool is_clip_to_hide; bool drag_to_tile; bool scratchpad_switching_mon; bool fake_no_border; - int nofocus; - int nofadein; - int nofadeout; - int no_force_center; - int isunglobal; + int32_t nofocus; + int32_t nofadein; + int32_t nofadeout; + int32_t no_force_center; + int32_t isunglobal; float focused_opacity; float unfocused_opacity; char oldmonname[128]; - int noblur; + int32_t noblur; double master_mfact_per, master_inner_per, stack_inner_per; double old_master_mfact_per, old_master_inner_per, old_stack_inner_per; double old_scroller_pproportion; bool ismaster; bool cursor_in_upper_half, cursor_in_left_half; bool isleftstack; - int tearing_hint; - int force_tearing; - int allow_shortcuts_inhibit; + int32_t tearing_hint; + int32_t force_tearing; + int32_t allow_shortcuts_inhibit; float scroller_proportion_single; bool isfocusing; }; @@ -418,14 +418,14 @@ typedef struct { typedef struct { uint32_t mod; xkb_keysym_t keysym; - int (*func)(const Arg *); + int32_t (*func)(const Arg *); const Arg arg; } Key; typedef struct { struct wlr_keyboard_group *wlr_group; - int nsyms; + int32_t nsyms; const xkb_keysym_t *keysyms; /* invalid if nsyms == 0 */ uint32_t mods; /* invalid if nsyms == 0 */ uint32_t keycode; @@ -453,7 +453,7 @@ typedef struct { struct wlr_scene_layer_surface_v1 *scene_layer; struct wl_list link; struct wl_list fadeout_link; - int mapped; + int32_t mapped; struct wlr_layer_surface_v1 *layer_surface; struct wl_listener destroy; @@ -463,9 +463,9 @@ typedef struct { struct dwl_animation animation; bool dirty; - int noblur; - int noanim; - int noshadow; + int32_t noblur; + int32_t noanim; + int32_t noshadow; char *animation_type_open; char *animation_type_close; bool need_output_flush; @@ -495,18 +495,18 @@ struct Monitor { uint32_t seltags; uint32_t tagset[2]; double mfact; - int nmaster; + int32_t nmaster; struct wl_list dwl_ipc_outputs; - int gappih; /* horizontal gap between windows */ - int gappiv; /* vertical gap between windows */ - int gappoh; /* horizontal outer gaps */ - int gappov; /* vertical outer gaps */ + int32_t gappih; /* horizontal gap between windows */ + int32_t gappiv; /* vertical gap between windows */ + int32_t gappoh; /* horizontal outer gaps */ + int32_t gappov; /* vertical outer gaps */ Pertag *pertag; Client *sel, *prevsel; - int isoverview; - int is_in_hotarea; - int asleep; + int32_t isoverview; + int32_t is_in_hotarea; + int32_t asleep; uint32_t visible_clients; uint32_t visible_tiling_clients; uint32_t visible_scroll_tiling_clients; @@ -537,14 +537,14 @@ static void applyrules(Client *c); // 窗口规则应用,应用config.h中定义 static void arrange(Monitor *m, bool want_animation, bool from_view); // 布局函数,让窗口俺平铺规则移动和重置大小 static void arrangelayer(Monitor *m, struct wl_list *list, - struct wlr_box *usable_area, int exclusive); + struct wlr_box *usable_area, int32_t exclusive); static void arrangelayers(Monitor *m); static void handle_print_status(struct wl_listener *listener, void *data); static void axisnotify(struct wl_listener *listener, void *data); // 滚轮事件处理 static void buttonpress(struct wl_listener *listener, void *data); // 鼠标按键事件处理 -static int ongesture(struct wlr_pointer_swipe_end_event *event); +static int32_t ongesture(struct wlr_pointer_swipe_end_event *event); static void swipe_begin(struct wl_listener *listener, void *data); static void swipe_update(struct wl_listener *listener, void *data); static void swipe_end(struct wl_listener *listener, void *data); @@ -558,7 +558,7 @@ static void cleanup(void); // 退出清理 static void cleanupmon(struct wl_listener *listener, void *data); // 退出清理 static void closemon(Monitor *m); static void cleanuplisteners(void); -static void toggle_hotarea(int x_root, int y_root); // 触发热区 +static void toggle_hotarea(int32_t x_root, int32_t y_root); // 触发热区 static void maplayersurfacenotify(struct wl_listener *listener, void *data); static void commitlayersurfacenotify(struct wl_listener *listener, void *data); static void commitnotify(struct wl_listener *listener, void *data); @@ -585,7 +585,7 @@ static void destroydecoration(struct wl_listener *listener, void *data); static void destroydragicon(struct wl_listener *listener, void *data); static void destroyidleinhibitor(struct wl_listener *listener, void *data); static void destroylayersurfacenotify(struct wl_listener *listener, void *data); -static void destroylock(SessionLock *lock, int unlocked); +static void destroylock(SessionLock *lock, int32_t unlocked); static void destroylocksurface(struct wl_listener *listener, void *data); static void destroynotify(struct wl_listener *listener, void *data); static void destroypointerconstraint(struct wl_listener *listener, void *data); @@ -594,18 +594,18 @@ static void destroykeyboardgroup(struct wl_listener *listener, void *data); static Monitor *dirtomon(enum wlr_direction dir); static void setcursorshape(struct wl_listener *listener, void *data); -static void focusclient(Client *c, int lift); +static void focusclient(Client *c, int32_t lift); static void setborder_color(Client *c); static Client *focustop(Monitor *m); static void fullscreennotify(struct wl_listener *listener, void *data); static void gpureset(struct wl_listener *listener, void *data); -static int keyrepeat(void *data); +static int32_t keyrepeat(void *data); static void inputdevice(struct wl_listener *listener, void *data); -static int keybinding(uint32_t state, bool locked, uint32_t mods, - xkb_keysym_t sym, uint32_t keycode); +static int32_t keybinding(uint32_t state, bool locked, uint32_t mods, + xkb_keysym_t sym, uint32_t keycode); static void keypress(struct wl_listener *listener, void *data); static void keypressmod(struct wl_listener *listener, void *data); static bool keypressglobal(struct wlr_surface *last_surface, @@ -628,26 +628,26 @@ static void add_foreign_topleve(Client *c); static void exchange_two_client(Client *c1, Client *c2); static void outputmgrapply(struct wl_listener *listener, void *data); static void outputmgrapplyortest(struct wlr_output_configuration_v1 *config, - int test); + int32_t test); static void outputmgrtest(struct wl_listener *listener, void *data); static void pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy, uint32_t time); static void printstatus(void); -static void quitsignal(int signo); +static void quitsignal(int32_t signo); static void powermgrsetmode(struct wl_listener *listener, void *data); static void rendermon(struct wl_listener *listener, void *data); static void requestdecorationmode(struct wl_listener *listener, void *data); static void requestdrmlease(struct wl_listener *listener, void *data); static void requeststartdrag(struct wl_listener *listener, void *data); -static void resize(Client *c, struct wlr_box geo, int interact); +static void resize(Client *c, struct wlr_box geo, int32_t interact); static void run(char *startup_cmd); static void setcursor(struct wl_listener *listener, void *data); -static void setfloating(Client *c, int floating); -static void setfakefullscreen(Client *c, int fakefullscreen); -static void setfullscreen(Client *c, int fullscreen); -static void setmaximizescreen(Client *c, int maximizescreen); +static void setfloating(Client *c, int32_t floating); +static void setfakefullscreen(Client *c, int32_t fakefullscreen); +static void setfullscreen(Client *c, int32_t fullscreen); +static void setmaximizescreen(Client *c, int32_t maximizescreen); static void reset_maximizescreen_size(Client *c); -static void setgaps(int oh, int ov, int ih, int iv); +static void setgaps(int32_t oh, int32_t ov, int32_t ih, int32_t iv); static void setmon(Client *c, Monitor *m, uint32_t newtags, bool focus); static void setpsel(struct wl_listener *listener, void *data); @@ -663,7 +663,7 @@ static void updatetitle(struct wl_listener *listener, void *data); static void urgent(struct wl_listener *listener, void *data); static void view(const Arg *arg, bool want_animation); -static void handlesig(int signo); +static void handlesig(int32_t signo); static void handle_keyboard_shortcuts_inhibit_new_inhibitor(struct wl_listener *listener, void *data); @@ -675,7 +675,7 @@ static void xytonode(double x, double y, struct wlr_surface **psurface, Client **pc, LayerSurface **pl, double *nx, double *ny); static void clear_fullscreen_flag(Client *c); static pid_t getparentprocess(pid_t p); -static int isdescprocess(pid_t p, pid_t c); +static int32_t isdescprocess(pid_t p, pid_t c); static Client *termforwin(Client *w); static void swallow(Client *c, Client *w); @@ -691,20 +691,21 @@ static void tag_client(const Arg *arg, Client *target_client); static struct wlr_box setclient_coordinate_center(Client *c, struct wlr_box geom, - int offsetx, int offsety); + int32_t offsetx, + int32_t offsety); static uint32_t get_tags_first_tag(uint32_t tags); static struct wlr_output_mode * -get_nearest_output_mode(struct wlr_output *output, int width, int height, - float refresh); +get_nearest_output_mode(struct wlr_output *output, int32_t width, + int32_t height, float refresh); static void client_commit(Client *c); static void layer_commit(LayerSurface *l); static void apply_border(Client *c); static void client_set_opacity(Client *c, double opacity); static void init_baked_points(void); -static void scene_buffer_apply_opacity(struct wlr_scene_buffer *buffer, int sx, - int sy, void *data); +static void scene_buffer_apply_opacity(struct wlr_scene_buffer *buffer, + int32_t sx, int32_t sy, void *data); static Client *direction_select(const Arg *arg); static void view_in_mon(const Arg *arg, bool want_animation, Monitor *m, @@ -712,13 +713,14 @@ static void view_in_mon(const Arg *arg, bool want_animation, Monitor *m, static void buffer_set_effect(Client *c, BufferData buffer_data); static void snap_scene_buffer_apply_effect(struct wlr_scene_buffer *buffer, - int sx, int sy, void *data); + int32_t sx, int32_t sy, void *data); static void client_set_pending_state(Client *c); static void layer_set_pending_state(LayerSurface *l); -static void set_rect_size(struct wlr_scene_rect *rect, int width, int height); +static void set_rect_size(struct wlr_scene_rect *rect, int32_t width, + int32_t height); static Client *center_tiled_select(Monitor *m); static void handlecursoractivity(void); -static int hidecursor(void *data); +static int32_t hidecursor(void *data); static bool check_hit_no_border(Client *c); static void reset_keyboard_layout(void); static void client_update_oldmonname_record(Client *c, Monitor *m); @@ -726,13 +728,12 @@ static void pending_kill_client(Client *c); static uint32_t get_tags_first_tag_num(uint32_t source_tags); static void set_layer_open_animaiton(LayerSurface *l, struct wlr_box geo); static void init_fadeout_layers(LayerSurface *l); -static void layer_actual_size(LayerSurface *l, uint32_t *width, - uint32_t *height); +static void layer_actual_size(LayerSurface *l, int32_t *width, int32_t *height); static void get_layer_target_geometry(LayerSurface *l, struct wlr_box *target_box); -static void scene_buffer_apply_effect(struct wlr_scene_buffer *buffer, int sx, - int sy, void *data); -static double find_animation_curve_at(double t, int type); +static void scene_buffer_apply_effect(struct wlr_scene_buffer *buffer, + int32_t sx, int32_t sy, void *data); +static double find_animation_curve_at(double t, int32_t type); static void apply_opacity_to_rect_nodes(Client *c, struct wlr_scene_node *node, double animation_passed); @@ -754,8 +755,8 @@ static void enable_adaptive_sync(Monitor *m, struct wlr_output_state *state); static Client *get_next_stack_client(Client *c, bool reverse); static void set_float_malposition(Client *tc); static void set_size_per(Monitor *m, Client *c); -static void resize_tile_client(Client *grabc, bool isdrag, int offsetx, - int offsety, uint32_t time); +static void resize_tile_client(Client *grabc, bool isdrag, int32_t offsetx, + int32_t offsety, uint32_t time); static void refresh_monitors_workspaces_status(Monitor *m); static void init_client_properties(Client *c); static float *get_border_color(Client *c); @@ -768,7 +769,7 @@ static void clear_fullscreen_and_maximized_state(Monitor *m); /* variables */ static const char broken[] = "broken"; static pid_t child_pid = -1; -static int locked; +static int32_t locked; static uint32_t locked_mods = 0; static void *exclusive_focus; static struct wl_display *dpy; @@ -809,7 +810,7 @@ static struct wlr_scene_rect *root_bg; static struct wlr_session_lock_manager_v1 *session_lock_mgr; static struct wlr_scene_rect *locked_bg; static struct wlr_session_lock_v1 *cur_lock; -static const int layermap[] = {LyrBg, LyrBottom, LyrTop, LyrOverlay}; +static const int32_t layermap[] = {LyrBg, LyrBottom, LyrTop, LyrOverlay}; static struct wlr_scene_tree *drag_icon; static struct wlr_cursor_shape_manager_v1 *cursor_shape_mgr; static struct wlr_pointer_constraints_v1 *pointer_constraints; @@ -822,20 +823,20 @@ static struct wl_list inputdevices; static struct wl_list keyboard_shortcut_inhibitors; static uint32_t cursor_mode; static Client *grabc; -static int grabcx, grabcy; /* client-relative */ -static int drag_begin_cursorx, drag_begin_cursory; /* client-relative */ +static int32_t grabcx, grabcy; /* client-relative */ +static int32_t drag_begin_cursorx, drag_begin_cursory; /* client-relative */ static bool start_drag_window = false; -static int last_apply_drap_time = 0; +static int32_t last_apply_drap_time = 0; static struct wlr_output_layout *output_layout; static struct wlr_box sgeom; static struct wl_list mons; static Monitor *selmon; -static int enablegaps = 1; /* enables gaps, used by togglegaps */ -static int axis_apply_time = 0; -static int axis_apply_dir = 0; -static int scroller_focus_lock = 0; +static int32_t enablegaps = 1; /* enables gaps, used by togglegaps */ +static int32_t axis_apply_time = 0; +static int32_t axis_apply_dir = 0; +static int32_t scroller_focus_lock = 0; static uint32_t swipe_fingers = 0; static double swipe_dx = 0; @@ -865,18 +866,18 @@ static KeyMode keymode = { static struct { enum wp_cursor_shape_device_v1_shape shape; struct wlr_surface *surface; - int hotspot_x; - int hotspot_y; + int32_t hotspot_x; + int32_t hotspot_y; } last_cursor; #include "client/client.h" #include "config/preset.h" struct Pertag { - uint32_t curtag, prevtag; /* current and previous tag */ - int 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 */ + 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 */ const Layout *ltidxs[LENGTH(tags) + 1]; /* matrix of tags and layouts indexes */ }; @@ -955,8 +956,8 @@ void client_change_mon(Client *c, Monitor *m) { void applybounds(Client *c, struct wlr_box *bbox) { /* set minimum possible */ - c->geom.width = MAX(1 + 2 * (int)c->bw, c->geom.width); - c->geom.height = MAX(1 + 2 * (int)c->bw, c->geom.height); + c->geom.width = MAX(1 + 2 * (int32_t)c->bw, c->geom.width); + c->geom.height = MAX(1 + 2 * (int32_t)c->bw, c->geom.height); if (c->geom.x >= bbox->x + bbox->width) c->geom.x = bbox->x + bbox->width - c->geom.width; @@ -1082,9 +1083,9 @@ bool switch_scratchpad_client_state(Client *c) { // 根据新monitor调整窗口尺寸 c->float_geom.width = - (int)(c->float_geom.width * c->mon->w.width / oldmon->w.width); - c->float_geom.height = - (int)(c->float_geom.height * c->mon->w.height / oldmon->w.height); + (int32_t)(c->float_geom.width * c->mon->w.width / oldmon->w.width); + c->float_geom.height = (int32_t)(c->float_geom.height * + c->mon->w.height / oldmon->w.height); c->float_geom = setclient_coordinate_center(c, c->float_geom, 0, 0); @@ -1167,7 +1168,7 @@ void gpureset(struct wl_listener *listener, void *data) { wlr_renderer_destroy(old_drw); } -void handlesig(int signo) { +void handlesig(int32_t signo) { if (signo == SIGCHLD) while (waitpid(-1, NULL, WNOHANG) > 0) ; @@ -1175,7 +1176,7 @@ void handlesig(int signo) { quit(NULL); } -void toggle_hotarea(int x_root, int y_root) { +void toggle_hotarea(int32_t x_root, int32_t y_root) { // 左下角热区坐标计算,兼容多显示屏 Arg arg = {0}; @@ -1241,7 +1242,7 @@ static void apply_rule_properties(Client *c, const ConfigWinRule *r) { void set_float_malposition(Client *tc) { Client *c = NULL; - int x, y, offset, xreverse, yreverse; + int32_t x, y, offset, xreverse, yreverse; x = tc->geom.x; y = tc->geom.y; xreverse = 1; @@ -1389,7 +1390,8 @@ void applyrules(Client *c) { } } - int fullscreen_state_backup = c->isfullscreen || client_wants_fullscreen(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)) && @@ -1436,7 +1438,7 @@ void applyrules(Client *c) { } void arrangelayer(Monitor *m, struct wl_list *list, struct wlr_box *usable_area, - int exclusive) { + int32_t exclusive) { LayerSurface *l = NULL; struct wlr_box full_area = m->m; @@ -1455,14 +1457,14 @@ void arrangelayer(Monitor *m, struct wl_list *list, struct wlr_box *usable_area, } void apply_window_snap(Client *c) { - int snap_up = 99999, snap_down = 99999, snap_left = 99999, - snap_right = 99999; - int snap_up_temp = 0, snap_down_temp = 0, snap_left_temp = 0, - snap_right_temp = 0; - int snap_up_screen = 0, snap_down_screen = 0, snap_left_screen = 0, - snap_right_screen = 0; - int snap_up_mon = 0, snap_down_mon = 0, snap_left_mon = 0, - snap_right_mon = 0; + int32_t snap_up = 99999, snap_down = 99999, snap_left = 99999, + snap_right = 99999; + int32_t snap_up_temp = 0, snap_down_temp = 0, snap_left_temp = 0, + snap_right_temp = 0; + int32_t snap_up_screen = 0, snap_down_screen = 0, snap_left_screen = 0, + snap_right_screen = 0; + int32_t snap_up_mon = 0, snap_down_mon = 0, snap_left_mon = 0, + snap_right_mon = 0; uint32_t cbw = !render_border || c->fake_no_border ? borderpx : 0; uint32_t tcbw; @@ -1565,7 +1567,7 @@ void focuslayer(LayerSurface *l) { void reset_exclusive_layer(Monitor *m) { LayerSurface *l = NULL; - int i; + int32_t i; uint32_t layers_above_shell[] = { ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY, ZWLR_LAYER_SHELL_V1_LAYER_TOP, @@ -1575,7 +1577,7 @@ void reset_exclusive_layer(Monitor *m) { if (!m) return; - for (i = 0; i < (int)LENGTH(layers_above_shell); i++) { + for (i = 0; i < (int32_t)LENGTH(layers_above_shell); i++) { wl_list_for_each_reverse(l, &m->layers[layers_above_shell[i]], link) { if (l == exclusive_focus && l->layer_surface->current.keyboard_interactive != @@ -1601,7 +1603,7 @@ void reset_exclusive_layer(Monitor *m) { } void arrangelayers(Monitor *m) { - int i; + int32_t i; struct wlr_box usable_area = m->m; if (!m->wlr_output->enabled) @@ -1633,7 +1635,7 @@ axisnotify(struct wl_listener *listener, void *data) { struct wlr_keyboard *keyboard, *hard_keyboard; uint32_t mods, hard_mods; AxisBinding *a; - int ji; + int32_t ji; uint32_t adir; // IDLE_NOTIFY_ACTIVITY; handlecursoractivity(); @@ -1687,15 +1689,15 @@ axisnotify(struct wl_listener *listener, void *data) { event->relative_direction); } -int ongesture(struct wlr_pointer_swipe_end_event *event) { +int32_t ongesture(struct wlr_pointer_swipe_end_event *event) { struct wlr_keyboard *keyboard, *hard_keyboard; uint32_t mods, hard_mods; const GestureBinding *g; uint32_t motion; - uint32_t adx = (int)round(fabs(swipe_dx)); - uint32_t ady = (int)round(fabs(swipe_dy)); - int handled = 0; - int ji; + uint32_t adx = (int32_t)round(fabs(swipe_dx)); + uint32_t ady = (int32_t)round(fabs(swipe_dy)); + int32_t handled = 0; + int32_t ji; if (event->cancelled) { return handled; @@ -1811,12 +1813,12 @@ void place_drag_tile_client(Client *c) { Client *closest_client = NULL; long min_distant = LONG_MAX; long temp_distant; - int x, y; + int32_t x, y; wl_list_for_each(tc, &clients, link) { if (tc != c && ISTILED(tc) && VISIBLEON(tc, c->mon)) { - x = tc->geom.x + (int)(tc->geom.width / 2) - cursor->x; - y = tc->geom.y + (int)(tc->geom.height / 2) - cursor->y; + x = tc->geom.x + (int32_t)(tc->geom.width / 2) - cursor->x; + y = tc->geom.y + (int32_t)(tc->geom.height / 2) - cursor->y; temp_distant = x * x + y * y; if (temp_distant < min_distant) { min_distant = temp_distant; @@ -1863,7 +1865,7 @@ buttonpress(struct wl_listener *listener, void *data) { LayerSurface *l = NULL; struct wlr_surface *surface; Client *tmpc = NULL; - int ji; + int32_t ji; const MouseBinding *m; struct wlr_surface *old_pointer_focus_surface = seat->pointer_state.focused_surface; @@ -1971,7 +1973,7 @@ buttonpress(struct wl_listener *listener, void *data) { } void checkidleinhibitor(struct wlr_surface *exclude) { - int inhibited = 0; + int32_t inhibited = 0; Client *c = NULL; struct wlr_surface *surface = NULL; struct wlr_idle_inhibitor_v1 *inhibitor; @@ -2125,7 +2127,7 @@ void closemon(Monitor *m) { /* update selmon if needed and * move closed monitor's clients to the focused one */ Client *c = NULL; - int i = 0, nmons = wl_list_length(&mons); + int32_t i = 0, nmons = wl_list_length(&mons); if (!nmons) { selmon = NULL; } else if (m == selmon) { @@ -2158,8 +2160,8 @@ void closemon(Monitor *m) { } } -static void iter_layer_scene_buffers(struct wlr_scene_buffer *buffer, int sx, - int sy, void *user_data) { +static void iter_layer_scene_buffers(struct wlr_scene_buffer *buffer, + int32_t sx, int32_t sy, void *user_data) { struct wlr_scene_surface *scene_surface = wlr_scene_surface_try_from_buffer(buffer); if (!scene_surface) { @@ -2178,7 +2180,7 @@ static void iter_layer_scene_buffers(struct wlr_scene_buffer *buffer, int sx, void maplayersurfacenotify(struct wl_listener *listener, void *data) { LayerSurface *l = wl_container_of(listener, l, map); struct wlr_layer_surface_v1 *layer_surface = l->layer_surface; - int ji; + int32_t ji; ConfigLayerRule *r; l->mapped = 1; @@ -2409,7 +2411,7 @@ void commitpopup(struct wl_listener *listener, void *data) { LayerSurface *l = NULL; Client *c = NULL; struct wlr_box box; - int type = -1; + int32_t type = -1; if (!popup->base->initial_commit) return; @@ -2596,7 +2598,7 @@ void createlocksurface(struct wl_listener *listener, void *data) { } struct wlr_output_mode *get_nearest_output_mode(struct wlr_output *output, - int width, int height, + int32_t width, int32_t height, float refresh) { struct wlr_output_mode *mode, *nearest_mode = NULL; float min_diff = 99999.0f; @@ -2634,7 +2636,7 @@ void createmon(struct wl_listener *listener, void *data) { struct wlr_output *wlr_output = data; const ConfigMonitorRule *r; uint32_t i; - int ji, jk; + int32_t ji, jk; struct wlr_output_state state; Monitor *m = NULL; struct wlr_output_mode *internal_mode = NULL; @@ -2707,7 +2709,7 @@ void createmon(struct wl_listener *listener, void *data) { custom_monitor_mode = true; wlr_output_state_set_custom_mode( &state, r->width, r->height, - (int)roundf(r->refresh * 1000)); + (int32_t)roundf(r->refresh * 1000)); } } wlr_output_state_set_scale(&state, r->scale); @@ -2928,7 +2930,7 @@ void switch_toggle(struct wl_listener *listener, void *data) { // 处理切换事件 struct wlr_switch_toggle_event *event = data; SwitchBinding *s; - int ji; + int32_t ji; for (ji = 0; ji < config.switch_bindings_count; ji++) { if (config.switch_bindings_count < 1) @@ -3053,7 +3055,7 @@ void destroylayersurfacenotify(struct wl_listener *listener, void *data) { free(l); } -void destroylock(SessionLock *lock, int unlock) { +void destroylock(SessionLock *lock, int32_t unlock) { wlr_seat_keyboard_notify_clear_focus(seat); if ((locked = !unlock)) goto destroy; @@ -3157,7 +3159,7 @@ void destroykeyboardgroup(struct wl_listener *listener, void *data) { free(group); } -void focusclient(Client *c, int lift) { +void focusclient(Client *c, int32_t lift) { Client *last_focus_client = NULL; Monitor *um = NULL; @@ -3248,7 +3250,7 @@ void focusclient(Client *c, int lift) { * layer is closed. */ Client *w = NULL; LayerSurface *l = NULL; - int type = + int32_t type = toplevel_from_wlr_surface(old_keyboard_focus_surface, &w, &l); if (type == LayerShell && l->scene->node.enabled && l->layer_surface->current.layer >= ZWLR_LAYER_SHELL_V1_LAYER_TOP && @@ -3364,9 +3366,9 @@ void inputdevice(struct wl_listener *listener, void *data) { wlr_seat_set_capabilities(seat, caps); } -int keyrepeat(void *data) { +int32_t keyrepeat(void *data) { KeyboardGroup *group = data; - int i; + int32_t i; if (!group->nsyms || group->wlr_group->keyboard.repeat_info.rate <= 0) return 0; @@ -3392,7 +3394,7 @@ bool is_keyboard_shortcut_inhibitor(struct wlr_surface *surface) { return false; } -int // 17 +int32_t // 17 keybinding(uint32_t state, bool locked, uint32_t mods, xkb_keysym_t sym, uint32_t keycode) { /* @@ -3400,10 +3402,10 @@ keybinding(uint32_t state, bool locked, uint32_t mods, xkb_keysym_t sym, * processing keys, rather than passing them on to the client for its * own processing. */ - int handled = 0; + int32_t handled = 0; const KeyBinding *k; - int ji; - int isbreak = 0; + int32_t ji; + int32_t isbreak = 0; // not allow modifier keys to be used as a keybinding if (keycode == 50 || keycode == 37 || keycode == 133 || keycode == 64 || @@ -3466,10 +3468,10 @@ bool keypressglobal(struct wlr_surface *last_surface, xkb_keysym_t keysym, uint32_t keycode) { Client *c = NULL, *lastc = focustop(selmon); uint32_t keycodes[32] = {0}; - int reset = false; + int32_t reset = false; const char *appid = NULL; const char *title = NULL; - int ji; + int32_t ji; const ConfigWinRule *r; for (ji = 0; ji < config.window_rules_count; ji++) { @@ -3523,7 +3525,7 @@ done: } void keypress(struct wl_listener *listener, void *data) { - int i; + int32_t i; /* This event is raised when a key is pressed or released. */ KeyboardGroup *group = wl_container_of(listener, group, key); struct wlr_keyboard_key_event *event = data; @@ -3532,7 +3534,7 @@ void keypress(struct wl_listener *listener, void *data) { struct wlr_xdg_surface *xdg_surface = last_surface ? wlr_xdg_surface_try_from_wlr_surface(last_surface) : NULL; - int pass = 0; + int32_t pass = 0; bool hit_global = false; #ifdef XWAYLAND struct wlr_xwayland_surface *xsurface = @@ -3544,10 +3546,10 @@ void keypress(struct wl_listener *listener, void *data) { uint32_t keycode = event->keycode + 8; /* Get a list of keysyms based on the keymap for this keyboard */ const xkb_keysym_t *syms; - int nsyms = xkb_state_key_get_syms(group->wlr_group->keyboard.xkb_state, - keycode, &syms); + int32_t nsyms = xkb_state_key_get_syms(group->wlr_group->keyboard.xkb_state, + keycode, &syms); - int handled = 0; + int32_t handled = 0; uint32_t mods = wlr_keyboard_get_modifiers(&group->wlr_group->keyboard); wlr_idle_notifier_v1_notify_activity(idle_notifier, seat); @@ -3658,8 +3660,8 @@ void locksession(struct wl_listener *listener, void *data) { wlr_session_lock_v1_send_locked(session_lock); } -static void iter_xdg_scene_buffers(struct wlr_scene_buffer *buffer, int sx, - int sy, void *user_data) { +static void iter_xdg_scene_buffers(struct wlr_scene_buffer *buffer, int32_t sx, + int32_t sy, void *user_data) { Client *c = user_data; struct wlr_scene_surface *scene_surface = @@ -4013,16 +4015,16 @@ void motionnotify(uint32_t time, struct wlr_input_device *device, double dx, } /* Update drag icon's position */ - wlr_scene_node_set_position(&drag_icon->node, (int)round(cursor->x), - (int)round(cursor->y)); + wlr_scene_node_set_position(&drag_icon->node, (int32_t)round(cursor->x), + (int32_t)round(cursor->y)); /* If we are currently grabbing the mouse, handle and return */ if (cursor_mode == CurMove) { /* Move the grabbed client to the new position. */ grabc->iscustomsize = 1; grabc->float_geom = - (struct wlr_box){.x = (int)round(cursor->x) - grabcx, - .y = (int)round(cursor->y) - grabcy, + (struct wlr_box){.x = (int32_t)round(cursor->x) - grabcx, + .y = (int32_t)round(cursor->y) - grabcy, .width = grabc->geom.width, .height = grabc->geom.height}; resize(grabc, grabc->float_geom, 1); @@ -4033,8 +4035,8 @@ void motionnotify(uint32_t time, struct wlr_input_device *device, double dx, grabc->float_geom = (struct wlr_box){ .x = grabc->geom.x, .y = grabc->geom.y, - .width = (int)round(cursor->x) - grabc->geom.x, - .height = (int)round(cursor->y) - grabc->geom.y}; + .width = (int32_t)round(cursor->x) - grabc->geom.x, + .height = (int32_t)round(cursor->y) - grabc->geom.y}; if (last_apply_drap_time == 0 || time - last_apply_drap_time > drag_refresh_interval) { resize(grabc, grabc->float_geom, 1); @@ -4097,7 +4099,7 @@ void outputmgrapply(struct wl_listener *listener, void *data) { } void // 0.7 custom -outputmgrapplyortest(struct wlr_output_configuration_v1 *config, int test) { +outputmgrapplyortest(struct wlr_output_configuration_v1 *config, int32_t test) { /* * Called when a client such as wlr-randr requests a change in output * configuration. This is only one way that the layout can be changed, @@ -4105,7 +4107,7 @@ outputmgrapplyortest(struct wlr_output_configuration_v1 *config, int test) { * output_layout.change event, not here. */ struct wlr_output_configuration_head_v1 *config_head; - int ok = 1; + int32_t ok = 1; wl_list_for_each(config_head, &config->heads, link) { struct wlr_output *wlr_output = config_head->state.output; @@ -4208,10 +4210,10 @@ void powermgrsetmode(struct wl_listener *listener, void *data) { updatemons(NULL, NULL); } -void quitsignal(int signo) { quit(NULL); } +void quitsignal(int32_t signo) { quit(NULL); } -void scene_buffer_apply_opacity(struct wlr_scene_buffer *buffer, int sx, int sy, - void *data) { +void scene_buffer_apply_opacity(struct wlr_scene_buffer *buffer, int32_t sx, + int32_t sy, void *data) { wlr_scene_buffer_set_opacity(buffer, *(double *)data); } @@ -4225,7 +4227,7 @@ void rendermon(struct wl_listener *listener, void *data) { Client *c = NULL, *tmp = NULL; struct wlr_output_state pending = {0}; LayerSurface *l = NULL, *tmpl = NULL; - int i; + int32_t i; struct wl_list *layer_list; bool frame_allow_tearing = false; struct timespec now; @@ -4433,7 +4435,7 @@ run(char *startup_cmd) { * startup command */ if (startup_cmd) { - int piperw[2]; + int32_t piperw[2]; if (pipe(piperw) < 0) die("startup: pipe:"); if ((child_pid = fork()) < 0) @@ -4509,7 +4511,7 @@ void setcursor(struct wl_listener *listener, void *data) { } void // 0.5 -setfloating(Client *c, int floating) { +setfloating(Client *c, int32_t floating) { Client *fc = NULL; struct wlr_box target_box; @@ -4599,7 +4601,7 @@ void reset_maximizescreen_size(Client *c) { resize(c, c->geom, 0); } -void setmaximizescreen(Client *c, int maximizescreen) { +void setmaximizescreen(Client *c, int32_t maximizescreen) { struct wlr_box maximizescreen_box; if (!c || !c->mon || !client_surface(c)->mapped || c->iskilling) return; @@ -4647,7 +4649,7 @@ void setmaximizescreen(Client *c, int maximizescreen) { arrange(c->mon, false, false); } -void setfakefullscreen(Client *c, int fakefullscreen) { +void setfakefullscreen(Client *c, int32_t fakefullscreen) { c->isfakefullscreen = fakefullscreen; if (!c->mon) return; @@ -4657,7 +4659,7 @@ void setfakefullscreen(Client *c, int fakefullscreen) { client_set_fullscreen(c, fakefullscreen); } -void setfullscreen(Client *c, int fullscreen) // 用自定义全屏代理自带全屏 +void setfullscreen(Client *c, int32_t fullscreen) // 用自定义全屏代理自带全屏 { if (!c || !c->mon || !client_surface(c)->mapped || c->iskilling) @@ -4707,7 +4709,7 @@ void setfullscreen(Client *c, int fullscreen) // 用自定义全屏代理自带 arrange(c->mon, false, false); } -void setgaps(int oh, int ov, int ih, int iv) { +void setgaps(int32_t oh, int32_t ov, int32_t ih, int32_t iv) { selmon->gappoh = MAX(oh, 0); selmon->gappov = MAX(ov, 0); selmon->gappih = MAX(ih, 0); @@ -4730,7 +4732,7 @@ void reset_keyboard_layout(void) { // Get current layout xkb_layout_index_t current = xkb_state_serialize_layout( keyboard->xkb_state, XKB_STATE_LAYOUT_EFFECTIVE); - const int num_layouts = xkb_keymap_num_layouts(keyboard->keymap); + const int32_t num_layouts = xkb_keymap_num_layouts(keyboard->keymap); if (num_layouts < 1) { wlr_log(WLR_INFO, "No layouts available"); return; @@ -4754,7 +4756,7 @@ void reset_keyboard_layout(void) { } // 验证新keymap是否有布局 - const int new_num_layouts = xkb_keymap_num_layouts(new_keymap); + const int32_t new_num_layouts = xkb_keymap_num_layouts(new_keymap); if (new_num_layouts < 1) { wlr_log(WLR_ERROR, "New keymap has no layouts"); xkb_keymap_unref(new_keymap); @@ -4937,7 +4939,7 @@ void setup(void) { parse_config(); init_baked_points(); - int drm_fd, i, sig[] = {SIGCHLD, SIGINT, SIGTERM, SIGPIPE}; + int32_t drm_fd, i, sig[] = {SIGCHLD, SIGINT, SIGTERM, SIGPIPE}; struct sigaction sa = {.sa_flags = SA_RESTART, .sa_handler = handlesig}; sigemptyset(&sa.sa_mask); @@ -5361,7 +5363,7 @@ void handlecursoractivity(void) { last_cursor.hotspot_x, last_cursor.hotspot_y); } -int hidecursor(void *data) { +int32_t hidecursor(void *data) { wlr_cursor_unset_image(cursor); cursor_hidden = true; return 1; @@ -5488,7 +5490,7 @@ void updatemons(struct wl_listener *listener, void *data) { Client *c = NULL; struct wlr_output_configuration_head_v1 *config_head; Monitor *m = NULL; - int mon_pos_offsetx, mon_pos_offsety, oldx, oldy; + int32_t mon_pos_offsetx, mon_pos_offsety, oldx, oldy; /* First remove from the layout the disabled monitors */ wl_list_for_each(m, &mons, link) { @@ -5738,7 +5740,7 @@ void handle_keyboard_shortcuts_inhibit_new_inhibitor( Client *c = NULL; LayerSurface *l = NULL; - int type = toplevel_from_wlr_surface(inhibitor->surface, &c, &l); + int32_t type = toplevel_from_wlr_surface(inhibitor->surface, &c, &l); if (type < 0) return; @@ -5945,9 +5947,9 @@ static void setgeometrynotify(struct wl_listener *listener, void *data) { } #endif -int main(int argc, char *argv[]) { +int32_t main(int32_t argc, char *argv[]) { char *startup_cmd = NULL; - int c; + int32_t c; while ((c = getopt(argc, argv, "s:c:hdv")) != -1) { if (c == 's') From d2894f0babaa5f934a03eb73a5e2af2965ecbd11 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sat, 3 Jan 2026 10:38:42 +0800 Subject: [PATCH 435/591] opt: use int instaead of uint in layout code --- src/layout/horizontal.h | 86 ++++++++++++++++++++--------------------- src/layout/vertical.h | 47 +++++++++++----------- 2 files changed, 66 insertions(+), 67 deletions(-) diff --git a/src/layout/horizontal.h b/src/layout/horizontal.h index 5a75a4c2..a2f5e5c1 100644 --- a/src/layout/horizontal.h +++ b/src/layout/horizontal.h @@ -1,9 +1,9 @@ // 网格布局窗口大小和位置计算 void grid(Monitor *m) { - uint32_t i, n; - uint32_t cx, cy, cw, ch; - uint32_t dx; - uint32_t cols, rows, overcols; + int32_t i, n; + int32_t cx, cy, cw, ch; + int32_t dx; + int32_t cols, rows, overcols; Client *c = NULL; n = 0; int32_t target_gappo = @@ -112,15 +112,15 @@ void grid(Monitor *m) { } void deck(Monitor *m) { - uint32_t mw, my; + int32_t mw, my; int32_t i, n = 0; Client *c = NULL; Client *fc = NULL; float mfact; - uint32_t cur_gappih = enablegaps ? m->gappih : 0; - uint32_t cur_gappoh = enablegaps ? m->gappoh : 0; - uint32_t cur_gappov = enablegaps ? m->gappov : 0; + int32_t cur_gappih = enablegaps ? m->gappih : 0; + int32_t cur_gappoh = enablegaps ? m->gappoh : 0; + int32_t cur_gappov = enablegaps ? m->gappov : 0; cur_gappih = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappih; cur_gappoh = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappoh; @@ -183,9 +183,9 @@ void deck(Monitor *m) { void horizontal_scroll_adjust_fullandmax(Client *c, struct wlr_box *target_geom) { Monitor *m = c->mon; - uint32_t cur_gappih = enablegaps ? m->gappih : 0; - uint32_t cur_gappoh = enablegaps ? m->gappoh : 0; - uint32_t cur_gappov = enablegaps ? m->gappov : 0; + int32_t cur_gappih = enablegaps ? m->gappih : 0; + int32_t cur_gappoh = enablegaps ? m->gappoh : 0; + int32_t cur_gappov = enablegaps ? m->gappov : 0; cur_gappih = smartgaps && m->visible_scroll_tiling_clients == 1 ? 0 : cur_gappih; @@ -214,7 +214,7 @@ void horizontal_scroll_adjust_fullandmax(Client *c, // 滚动布局 void scroller(Monitor *m) { - uint32_t i, n, j; + int32_t i, n, j; float single_proportion = 1.0; Client *c = NULL, *root_client = NULL; @@ -222,9 +222,9 @@ void scroller(Monitor *m) { struct wlr_box target_geom; int32_t focus_client_index = 0; bool need_scroller = false; - uint32_t cur_gappih = enablegaps ? m->gappih : 0; - uint32_t cur_gappoh = enablegaps ? m->gappoh : 0; - uint32_t cur_gappov = enablegaps ? m->gappov : 0; + int32_t cur_gappih = enablegaps ? m->gappih : 0; + int32_t cur_gappoh = enablegaps ? m->gappoh : 0; + int32_t cur_gappov = enablegaps ? m->gappov : 0; cur_gappih = smartgaps && m->visible_scroll_tiling_clients == 1 ? 0 : cur_gappih; @@ -233,7 +233,7 @@ void scroller(Monitor *m) { cur_gappov = smartgaps && m->visible_scroll_tiling_clients == 1 ? 0 : cur_gappov; - uint32_t max_client_width = m->w.width - 2 * scroller_structs - cur_gappih; + int32_t max_client_width = m->w.width - 2 * scroller_structs - cur_gappih; n = m->visible_scroll_tiling_clients; @@ -368,7 +368,7 @@ void scroller(Monitor *m) { } void center_tile(Monitor *m) { - uint32_t i, n = 0, h, r, ie = enablegaps, mw, mx, my, oty, ety, tw; + int32_t i, n = 0, h, r, ie = enablegaps, mw, mx, my, oty, ety, tw; Client *c = NULL; Client *fc = NULL; double mfact = 0; @@ -391,10 +391,10 @@ void center_tile(Monitor *m) { } // 间隙参数处理 - uint32_t cur_gappiv = enablegaps ? m->gappiv : 0; // 内部垂直间隙 - uint32_t cur_gappih = enablegaps ? m->gappih : 0; // 内部水平间隙 - uint32_t cur_gappov = enablegaps ? m->gappov : 0; // 外部垂直间隙 - uint32_t cur_gappoh = enablegaps ? m->gappoh : 0; // 外部水平间隙 + int32_t cur_gappiv = enablegaps ? m->gappiv : 0; // 内部垂直间隙 + int32_t cur_gappih = enablegaps ? m->gappih : 0; // 内部水平间隙 + int32_t cur_gappov = enablegaps ? m->gappov : 0; // 外部垂直间隙 + int32_t cur_gappoh = enablegaps ? m->gappoh : 0; // 外部水平间隙 // 智能间隙处理 cur_gappiv = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappiv; @@ -402,7 +402,7 @@ void center_tile(Monitor *m) { cur_gappov = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappov; cur_gappoh = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappoh; - uint32_t nmasters = m->pertag->nmasters[m->pertag->curtag]; + int32_t nmasters = m->pertag->nmasters[m->pertag->curtag]; mfact = fc->master_mfact_per > 0.0f ? fc->master_mfact_per : m->pertag->mfacts[m->pertag->curtag]; @@ -415,15 +415,15 @@ void center_tile(Monitor *m) { // 判断是否需要主区域铺满 int32_t should_overspread = center_master_overspread && (n <= nmasters); - uint32_t master_surplus_height = + int32_t master_surplus_height = (m->w.height - 2 * cur_gappov - cur_gappiv * ie * (master_num - 1)); float master_surplus_ratio = 1.0; - uint32_t slave_left_surplus_height = + int32_t slave_left_surplus_height = (m->w.height - 2 * cur_gappov - cur_gappiv * ie * (stack_num / 2 - 1)); float slave_left_surplus_ratio = 1.0; - uint32_t slave_right_surplus_height = + int32_t slave_right_surplus_height = (m->w.height - 2 * cur_gappov - cur_gappiv * ie * ((stack_num + 1) / 2 - 1)); float slave_right_surplus_ratio = 1.0; @@ -496,7 +496,7 @@ void center_tile(Monitor *m) { my += c->geom.height + cur_gappiv * ie; } else { // 堆叠区域窗口 - uint32_t stack_index = i - nmasters; + int32_t stack_index = i - nmasters; if (n - nmasters == 1) { // 单个堆叠窗口 @@ -600,7 +600,7 @@ void center_tile(Monitor *m) { } void tile(Monitor *m) { - uint32_t i, n = 0, h, r, ie = enablegaps, mw, my, ty; + int32_t i, n = 0, h, r, ie = enablegaps, mw, my, ty; Client *c = NULL; Client *fc = NULL; double mfact = 0; @@ -615,10 +615,10 @@ void tile(Monitor *m) { if (n == 0) return; - uint32_t cur_gappiv = enablegaps ? m->gappiv : 0; - uint32_t cur_gappih = enablegaps ? m->gappih : 0; - uint32_t cur_gappov = enablegaps ? m->gappov : 0; - uint32_t cur_gappoh = enablegaps ? m->gappoh : 0; + int32_t cur_gappiv = enablegaps ? m->gappiv : 0; + int32_t cur_gappih = enablegaps ? m->gappih : 0; + int32_t cur_gappov = enablegaps ? m->gappov : 0; + int32_t cur_gappoh = enablegaps ? m->gappoh : 0; cur_gappiv = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappiv; cur_gappih = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappih; @@ -643,11 +643,11 @@ void tile(Monitor *m) { i = 0; my = ty = cur_gappov; - uint32_t master_surplus_height = + int32_t master_surplus_height = (m->w.height - 2 * cur_gappov - cur_gappiv * ie * (master_num - 1)); float master_surplus_ratio = 1.0; - uint32_t slave_surplus_height = + int32_t slave_surplus_height = (m->w.height - 2 * cur_gappov - cur_gappiv * ie * (stack_num - 1)); float slave_surplus_ratio = 1.0; @@ -710,7 +710,7 @@ void tile(Monitor *m) { } void right_tile(Monitor *m) { - uint32_t i, n = 0, h, r, ie = enablegaps, mw, my, ty; + int32_t i, n = 0, h, r, ie = enablegaps, mw, my, ty; Client *c = NULL; Client *fc = NULL; double mfact = 0; @@ -725,10 +725,10 @@ void right_tile(Monitor *m) { if (n == 0) return; - uint32_t cur_gappiv = enablegaps ? m->gappiv : 0; - uint32_t cur_gappih = enablegaps ? m->gappih : 0; - uint32_t cur_gappov = enablegaps ? m->gappov : 0; - uint32_t cur_gappoh = enablegaps ? m->gappoh : 0; + int32_t cur_gappiv = enablegaps ? m->gappiv : 0; + int32_t cur_gappih = enablegaps ? m->gappih : 0; + int32_t cur_gappov = enablegaps ? m->gappov : 0; + int32_t cur_gappoh = enablegaps ? m->gappoh : 0; cur_gappiv = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappiv; cur_gappih = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappih; @@ -753,11 +753,11 @@ void right_tile(Monitor *m) { i = 0; my = ty = cur_gappov; - uint32_t master_surplus_height = + int32_t master_surplus_height = (m->w.height - 2 * cur_gappov - cur_gappiv * ie * (master_num - 1)); float master_surplus_ratio = 1.0; - uint32_t slave_surplus_height = + int32_t slave_surplus_height = (m->w.height - 2 * cur_gappov - cur_gappiv * ie * (stack_num - 1)); float slave_surplus_ratio = 1.0; @@ -825,8 +825,8 @@ monocle(Monitor *m) { Client *c = NULL; struct wlr_box geom; - uint32_t cur_gappov = enablegaps ? m->gappov : 0; - uint32_t cur_gappoh = enablegaps ? m->gappoh : 0; + int32_t cur_gappov = enablegaps ? m->gappov : 0; + int32_t cur_gappoh = enablegaps ? m->gappoh : 0; cur_gappoh = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappoh; cur_gappov = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappov; @@ -845,7 +845,7 @@ monocle(Monitor *m) { } void tgmix(Monitor *m) { - uint32_t n = m->visible_tiling_clients; + int32_t n = m->visible_tiling_clients; if (n <= 3) { tile(m); return; diff --git a/src/layout/vertical.h b/src/layout/vertical.h index 6222e7c2..95138248 100644 --- a/src/layout/vertical.h +++ b/src/layout/vertical.h @@ -1,5 +1,5 @@ void vertical_tile(Monitor *m) { - uint32_t i, n = 0, w, r, ie = enablegaps, mh, mx, tx; + int32_t i, n = 0, w, r, ie = enablegaps, mh, mx, tx; Client *c = NULL; Client *fc = NULL; double mfact = 0; @@ -14,10 +14,10 @@ void vertical_tile(Monitor *m) { if (n == 0) return; - uint32_t cur_gapih = enablegaps ? m->gappih : 0; - uint32_t cur_gapiv = enablegaps ? m->gappiv : 0; - uint32_t cur_gapoh = enablegaps ? m->gappoh : 0; - uint32_t cur_gapov = enablegaps ? m->gappov : 0; + int32_t cur_gapih = enablegaps ? m->gappih : 0; + int32_t cur_gapiv = enablegaps ? m->gappiv : 0; + int32_t cur_gapoh = enablegaps ? m->gappoh : 0; + int32_t cur_gapov = enablegaps ? m->gappov : 0; cur_gapih = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gapih; cur_gapiv = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gapiv; @@ -42,11 +42,11 @@ void vertical_tile(Monitor *m) { i = 0; mx = tx = cur_gapoh; - uint32_t master_surplus_width = + int32_t master_surplus_width = (m->w.width - 2 * cur_gapoh - cur_gapih * ie * (master_num - 1)); float master_surplus_ratio = 1.0; - uint32_t slave_surplus_width = + int32_t slave_surplus_width = (m->w.width - 2 * cur_gapoh - cur_gapih * ie * (stack_num - 1)); float slave_surplus_ratio = 1.0; @@ -105,15 +105,15 @@ void vertical_tile(Monitor *m) { } void vertical_deck(Monitor *m) { - uint32_t mh, mx; + int32_t mh, mx; int32_t i, n = 0; Client *c = NULL; Client *fc = NULL; float mfact; - uint32_t cur_gappiv = enablegaps ? m->gappiv : 0; - uint32_t cur_gappoh = enablegaps ? m->gappoh : 0; - uint32_t cur_gappov = enablegaps ? m->gappov : 0; + int32_t cur_gappiv = enablegaps ? m->gappiv : 0; + int32_t cur_gappoh = enablegaps ? m->gappoh : 0; + int32_t cur_gappov = enablegaps ? m->gappov : 0; cur_gappiv = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappiv; cur_gappoh = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappoh; @@ -170,9 +170,9 @@ void vertical_deck(Monitor *m) { void vertical_scroll_adjust_fullandmax(Client *c, struct wlr_box *target_geom) { Monitor *m = c->mon; - uint32_t cur_gappiv = enablegaps ? m->gappiv : 0; - uint32_t cur_gappov = enablegaps ? m->gappov : 0; - uint32_t cur_gappoh = enablegaps ? m->gappoh : 0; + int32_t cur_gappiv = enablegaps ? m->gappiv : 0; + int32_t cur_gappov = enablegaps ? m->gappov : 0; + int32_t cur_gappoh = enablegaps ? m->gappoh : 0; cur_gappiv = smartgaps && m->visible_scroll_tiling_clients == 1 ? 0 : cur_gappiv; @@ -201,7 +201,7 @@ void vertical_scroll_adjust_fullandmax(Client *c, struct wlr_box *target_geom) { // 竖屏滚动布局 void vertical_scroller(Monitor *m) { - uint32_t i, n, j; + int32_t i, n, j; float single_proportion = 1.0; Client *c = NULL, *root_client = NULL; @@ -209,9 +209,9 @@ void vertical_scroller(Monitor *m) { struct wlr_box target_geom; int32_t focus_client_index = 0; bool need_scroller = false; - uint32_t cur_gappiv = enablegaps ? m->gappiv : 0; - uint32_t cur_gappov = enablegaps ? m->gappov : 0; - uint32_t cur_gappoh = enablegaps ? m->gappoh : 0; + int32_t cur_gappiv = enablegaps ? m->gappiv : 0; + int32_t cur_gappov = enablegaps ? m->gappov : 0; + int32_t cur_gappoh = enablegaps ? m->gappoh : 0; cur_gappiv = smartgaps && m->visible_scroll_tiling_clients == 1 ? 0 : cur_gappiv; @@ -220,8 +220,7 @@ void vertical_scroller(Monitor *m) { cur_gappoh = smartgaps && m->visible_scroll_tiling_clients == 1 ? 0 : cur_gappoh; - uint32_t max_client_height = - m->w.height - 2 * scroller_structs - cur_gappiv; + int32_t max_client_height = m->w.height - 2 * scroller_structs - cur_gappiv; n = m->visible_scroll_tiling_clients; @@ -354,10 +353,10 @@ void vertical_scroller(Monitor *m) { } void vertical_grid(Monitor *m) { - uint32_t i, n; - uint32_t cx, cy, cw, ch; - uint32_t dy; - uint32_t rows, cols, overrows; + int32_t i, n; + int32_t cx, cy, cw, ch; + int32_t dy; + int32_t rows, cols, overrows; Client *c = NULL; int32_t target_gappo = enablegaps ? m->isoverview ? overviewgappo : gappov : 0; From 67b37559a8eb6db9907e0397a00c81ad7a2f818b Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sun, 4 Jan 2026 07:18:04 +0800 Subject: [PATCH 436/591] opt: ensure auto schedule next frame when animaiton not end --- src/animation/client.h | 6 ++---- src/animation/common.h | 10 ++++++++++ src/dispatch/bind_define.h | 15 +++++++++++++++ src/mango.c | 14 ++++++++------ 4 files changed, 35 insertions(+), 10 deletions(-) diff --git a/src/animation/client.h b/src/animation/client.h index 51ad35e4..849bc10e 100644 --- a/src/animation/client.h +++ b/src/animation/client.h @@ -840,8 +840,7 @@ void init_fadeout_client(Client *c) { wl_list_insert(&fadeout_clients, &fadeout_cient->fadeout_link); // 请求刷新屏幕 - if (c->mon) - wlr_output_schedule_frame(c->mon->wlr_output); + request_fresh_all_monitors(); } void client_commit(Client *c) { @@ -860,8 +859,7 @@ void client_commit(Client *c) { c->animation.should_animate = false; } // 请求刷新屏幕 - if (c->mon) - wlr_output_schedule_frame(c->mon->wlr_output); + request_fresh_all_monitors(); } void client_set_pending_state(Client *c) { diff --git a/src/animation/common.h b/src/animation/common.h index 5e4ded99..9f022db2 100644 --- a/src/animation/common.h +++ b/src/animation/common.h @@ -250,3 +250,13 @@ struct wlr_scene_tree *wlr_scene_tree_snapshot(struct wlr_scene_node *node, return snapshot; } + +void request_fresh_all_monitors(void) { + Monitor *m = NULL; + wl_list_for_each(m, &mons, link) { + if (!m->wlr_output->enabled) { + continue; + } + wlr_output_schedule_frame(m->wlr_output); + } +} \ No newline at end of file diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index 2ade07ee..28879df8 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -31,13 +31,28 @@ int32_t bind_to_view(const Arg *arg) { } int32_t chvt(const Arg *arg) { + struct timespec ts; + // prevent the animation to rquest the new frame + allow_frame_scheduling = false; + + // backup current tag and monitor name if (selmon) { chvt_backup_tag = selmon->pertag->curtag; strncpy(chvt_backup_selmon, selmon->wlr_output->name, sizeof(chvt_backup_selmon) - 1); } + wlr_session_change_vt(session, arg->ui); + + // wait for DRM device to stabilize and ensure the session state is inactive + ts.tv_sec = 0; + ts.tv_nsec = 100000000; // 200ms + nanosleep(&ts, NULL); + + // allow frame scheduling, + // because session state is now inactive, rendermon will not enter + allow_frame_scheduling = true; return 1; } diff --git a/src/mango.c b/src/mango.c index b19cfbf5..e3e658a5 100644 --- a/src/mango.c +++ b/src/mango.c @@ -761,6 +761,7 @@ static void refresh_monitors_workspaces_status(Monitor *m); static void init_client_properties(Client *c); static float *get_border_color(Client *c); static void clear_fullscreen_and_maximized_state(Monitor *m); +static void request_fresh_all_monitors(void); #include "data/static_keymap.h" #include "dispatch/bind_declare.h" @@ -845,6 +846,7 @@ static double swipe_dy = 0; bool render_border = true; uint32_t chvt_backup_tag = 0; +bool allow_frame_scheduling = true; char chvt_backup_selmon[32] = {0}; struct dvec2 *baked_points_move; @@ -4237,7 +4239,7 @@ void rendermon(struct wl_listener *listener, void *data) { return; } - if (!m->wlr_output->enabled) + if (!m->wlr_output->enabled || !allow_frame_scheduling) return; frame_allow_tearing = check_tearing_frame_allow(m); @@ -4258,11 +4260,6 @@ void rendermon(struct wl_listener *listener, void *data) { need_more_frames = layer_draw_fadeout_frame(l) || need_more_frames; } - // 如果需要更多帧,确保安排下一帧 - if (need_more_frames) { - wlr_output_schedule_frame(m->wlr_output); - } - // 绘制客户端 wl_list_for_each(c, &clients, link) { need_more_frames = client_draw_frame(c) || need_more_frames; @@ -4289,6 +4286,11 @@ skip: wlr_scene_output_send_frame_done(m->scene_output, &now); wlr_output_state_finish(&pending); } + + // 如果需要更多帧,确保安排下一帧 + if (need_more_frames && allow_frame_scheduling) { + request_fresh_all_monitors(); + } } void requestdecorationmode(struct wl_listener *listener, void *data) { From 775931a4e1dc12779b67ed9561433e0715b59ba4 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sun, 4 Jan 2026 19:59:35 +0800 Subject: [PATCH 437/591] bump version to 0.10.10 --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index c56650ed..83b95135 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('mango', ['c', 'cpp'], - version : '0.10.9', + version : '0.10.10', ) subdir('protocols') From 5a714b756278896d74aae892a58ed740b4c2d27b Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Mon, 5 Jan 2026 22:08:44 +0800 Subject: [PATCH 438/591] opt: optimize sloppyfocus --- src/mango.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/mango.c b/src/mango.c index e3e658a5..89ee23e2 100644 --- a/src/mango.c +++ b/src/mango.c @@ -4172,8 +4172,10 @@ void pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy, uint32_t time) { struct timespec now; - if (surface != seat->pointer_state.focused_surface && sloppyfocus && time && - c && c->scene->node.enabled && !client_is_unmanaged(c)) + if (sloppyfocus && c && time && c->scene->node.enabled && + (surface != seat->pointer_state.focused_surface || + (selmon && selmon->sel && c != selmon->sel)) && + !client_is_unmanaged(c)) focusclient(c, 0); /* If surface is NULL, clear pointer focus */ From c2a7146168dfe4d122beec7e20f36d7742d81e1f Mon Sep 17 00:00:00 2001 From: werapi Date: Wed, 7 Jan 2026 15:46:25 +0100 Subject: [PATCH 439/591] fix: pointer events being one event behind --- src/mango.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/mango.c b/src/mango.c index 89ee23e2..f4f75170 100644 --- a/src/mango.c +++ b/src/mango.c @@ -3966,19 +3966,6 @@ void motionnotify(uint32_t time, struct wlr_input_device *device, double dx, struct wlr_pointer_constraint_v1 *constraint; bool should_lock = false; - /* Find the client under the pointer and send the event along. */ - xytonode(cursor->x, cursor->y, &surface, &c, 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, - &l) >= 0) { - c = w; - surface = seat->pointer_state.focused_surface; - sx = cursor->x - (l ? l->scene->node.x : w->geom.x); - sy = cursor->y - (l ? l->scene->node.y : w->geom.y); - } - /* time is 0 in internal calls meant to restore pointer focus. */ if (time) { wlr_relative_pointer_manager_v1_send_relative_motion( @@ -4016,6 +4003,19 @@ void motionnotify(uint32_t time, struct wlr_input_device *device, double dx, selmon = xytomon(cursor->x, cursor->y); } + /* Find the client under the pointer and send the event along. */ + xytonode(cursor->x, cursor->y, &surface, &c, 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, + &l) >= 0) { + c = w; + surface = seat->pointer_state.focused_surface; + sx = cursor->x - (l ? l->scene->node.x : w->geom.x); + sy = cursor->y - (l ? l->scene->node.y : w->geom.y); + } + /* Update drag icon's position */ wlr_scene_node_set_position(&drag_icon->node, (int32_t)round(cursor->x), (int32_t)round(cursor->y)); From 4efb8c5e06debc3a32a711e3508593cfd1e1fb48 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Thu, 8 Jan 2026 10:13:21 +0800 Subject: [PATCH 440/591] fix: isfloating rule not follow monitor rule --- src/dispatch/bind_define.h | 4 ++-- src/fetch/client.h | 6 +++--- src/mango.c | 20 ++++++++++++-------- 3 files changed, 17 insertions(+), 13 deletions(-) diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index 28879df8..19d743e7 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -740,7 +740,7 @@ int32_t centerwin(const Arg *arg) { return 0; if (c->isfloating) { - c->float_geom = setclient_coordinate_center(c, c->geom, 0, 0); + c->float_geom = setclient_coordinate_center(c, c->mon, c->geom, 0, 0); c->iscustomsize = 1; resize(c, c->float_geom, 1); return 0; @@ -1055,7 +1055,7 @@ int32_t tagmon(const Arg *arg) { c->float_geom.height = (int32_t)(c->float_geom.height * c->mon->w.height / selmon->w.height); selmon = c->mon; - c->float_geom = setclient_coordinate_center(c, c->float_geom, 0, 0); + c->float_geom = setclient_coordinate_center(c, c->mon, c->float_geom, 0, 0); // 重新计算居中的坐标 // 重新计算居中的坐标 diff --git a/src/fetch/client.h b/src/fetch/client.h index 22db0296..0af17238 100644 --- a/src/fetch/client.h +++ b/src/fetch/client.h @@ -74,12 +74,12 @@ Client *get_client_by_id_or_title(const char *arg_id, const char *arg_title) { return target_client; } struct wlr_box // 计算客户端居中坐标 -setclient_coordinate_center(Client *c, struct wlr_box geom, int32_t offsetx, - int32_t offsety) { +setclient_coordinate_center(Client *c, Monitor *tm, struct wlr_box geom, + int32_t offsetx, int32_t offsety) { struct wlr_box tempbox; int32_t offset = 0; int32_t len = 0; - Monitor *m = c->mon ? c->mon : selmon; + Monitor *m = tm ? tm : selmon; uint32_t cbw = check_hit_no_border(c) ? c->bw : 0; diff --git a/src/mango.c b/src/mango.c index 89ee23e2..a22e8be5 100644 --- a/src/mango.c +++ b/src/mango.c @@ -689,7 +689,7 @@ static void show_scratchpad(Client *c); static void show_hide_client(Client *c); static void tag_client(const Arg *arg, Client *target_client); -static struct wlr_box setclient_coordinate_center(Client *c, +static struct wlr_box setclient_coordinate_center(Client *c, Monitor *m, struct wlr_box geom, int32_t offsetx, int32_t offsety); @@ -952,7 +952,8 @@ void client_change_mon(Client *c, Monitor *m) { setmon(c, m, c->tags, true); reset_foreign_tolevel(c); if (c->isfloating) { - c->float_geom = c->geom = setclient_coordinate_center(c, c->geom, 0, 0); + c->float_geom = c->geom = + setclient_coordinate_center(c, c->mon, c->geom, 0, 0); } } @@ -1019,7 +1020,7 @@ void show_scratchpad(Client *c) { : c->mon->w.height * scratchpad_height_ratio; // 重新计算居中的坐标 c->float_geom = c->geom = c->animainit_geom = c->animation.current = - setclient_coordinate_center(c, c->geom, 0, 0); + setclient_coordinate_center(c, c->mon, c->geom, 0, 0); c->iscustomsize = 1; resize(c, c->geom, 0); } @@ -1089,7 +1090,8 @@ bool switch_scratchpad_client_state(Client *c) { c->float_geom.height = (int32_t)(c->float_geom.height * c->mon->w.height / oldmon->w.height); - c->float_geom = setclient_coordinate_center(c, c->float_geom, 0, 0); + c->float_geom = + setclient_coordinate_center(c, c->mon, c->float_geom, 0, 0); // 只有显示状态的scratchpad才需要聚焦和返回true if (c->is_scratchpad_show) { @@ -1345,7 +1347,7 @@ void applyrules(Client *c) { if (r->offsetx || r->offsety) { c->iscustompos = 1; c->float_geom = c->geom = setclient_coordinate_center( - c, c->float_geom, r->offsetx, r->offsety); + c, mon, c->float_geom, r->offsetx, r->offsety); } if (c->isfloating) { c->geom = c->float_geom.width > 0 && c->float_geom.height > 0 @@ -1363,7 +1365,8 @@ void applyrules(Client *c) { // the hit size if (!c->iscustompos && (!client_is_x11(c) || (c->geom.x == 0 && c->geom.y == 0))) { - c->float_geom = c->geom = setclient_coordinate_center(c, c->geom, 0, 0); + c->float_geom = c->geom = + setclient_coordinate_center(c, mon, c->geom, 0, 0); } else { c->float_geom = c->geom; } @@ -4537,7 +4540,8 @@ setfloating(Client *c, int32_t floating) { // 重新计算居中的坐标 if (!client_is_x11(c) && !c->iscustompos) - target_box = setclient_coordinate_center(c, target_box, 0, 0); + target_box = + setclient_coordinate_center(c, c->mon, target_box, 0, 0); else target_box = c->geom; @@ -4553,7 +4557,7 @@ setfloating(Client *c, int32_t floating) { } if (window_size_outofrange) { c->float_geom = - setclient_coordinate_center(c, c->float_geom, 0, 0); + setclient_coordinate_center(c, c->mon, c->float_geom, 0, 0); } resize(c, c->float_geom, 0); } else { From 8e8c513beb79f425d3bb166a96478ba6e87932b2 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Tue, 13 Jan 2026 08:12:41 +0800 Subject: [PATCH 441/591] opt: sloppyfocus not apply to tagouting client --- src/mango.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/mango.c b/src/mango.c index a22e8be5..1d776be4 100644 --- a/src/mango.c +++ b/src/mango.c @@ -4176,9 +4176,10 @@ void pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy, struct timespec now; if (sloppyfocus && c && time && c->scene->node.enabled && + !c->animation.tagining && (surface != seat->pointer_state.focused_surface || (selmon && selmon->sel && c != selmon->sel)) && - !client_is_unmanaged(c)) + !client_is_unmanaged(c) && VISIBLEON(c, c->mon)) focusclient(c, 0); /* If surface is NULL, clear pointer focus */ From 764eb44b9b7231842aaed18773ad2499e215a3bd Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Tue, 13 Jan 2026 20:25:19 +0800 Subject: [PATCH 442/591] Update README.md --- README.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/README.md b/README.md index 087bf13b..d512f39f 100644 --- a/README.md +++ b/README.md @@ -285,3 +285,15 @@ Read The Friendly Manual on packaging software in your distribution first. - https://github.com/swaywm/sway - Sample of Wayland protocol - https://github.com/wlrfx/scenefx - Make it simple to add window effect. + + +# Sponsor +At present, I can only accept sponsorship through an encrypted connection. +If you find this project helpful to you, you can offer sponsorship in the following ways. + +image + + +Thanks to the following friends for their sponsorship of this project + +[@tonybanters](https://github.com/tonybanters) From 373377eb17cd083cccf9d4e62ff4a5cb20e5d237 Mon Sep 17 00:00:00 2001 From: Ad Date: Tue, 13 Jan 2026 23:28:44 -0500 Subject: [PATCH 443/591] fix: comment on tag_animation_direction in default config --- config.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.conf b/config.conf index 5483a141..6cbb3a20 100644 --- a/config.conf +++ b/config.conf @@ -26,7 +26,7 @@ focused_opacity=1.0 unfocused_opacity=1.0 # Animation Configuration(support type:zoom,slide) -# tag_animation_direction: 0-horizontal,1-vertical +# tag_animation_direction: 1-horizontal,0-vertical animations=1 layer_animations=1 animation_type_open=slide From bc1f310e1cab1b514d509833254c520b91e87a60 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Thu, 15 Jan 2026 13:15:34 +0800 Subject: [PATCH 444/591] opt: not apply sloppyfocus if the surface is current pointer-focus surface --- src/mango.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/mango.c b/src/mango.c index 1d776be4..ac5edf9c 100644 --- a/src/mango.c +++ b/src/mango.c @@ -4177,8 +4177,7 @@ void pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy, if (sloppyfocus && c && time && c->scene->node.enabled && !c->animation.tagining && - (surface != seat->pointer_state.focused_surface || - (selmon && selmon->sel && c != selmon->sel)) && + (surface != seat->pointer_state.focused_surface) && !client_is_unmanaged(c) && VISIBLEON(c, c->mon)) focusclient(c, 0); From c0f38e8a36360e418e9d50fe645911a76d810612 Mon Sep 17 00:00:00 2001 From: 0xWal Date: Sat, 17 Jan 2026 09:53:14 +0300 Subject: [PATCH 445/591] =?UTF-8?q?fix:=20fakefullscreen=20toggle=20from?= =?UTF-8?q?=20fullscreen=20state=20=F0=9F=A9=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/mango.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/mango.c b/src/mango.c index ac5edf9c..6760b7b5 100644 --- a/src/mango.c +++ b/src/mango.c @@ -4661,10 +4661,11 @@ void setfakefullscreen(Client *c, int32_t fakefullscreen) { c->isfakefullscreen = fakefullscreen; if (!c->mon) return; + if (c->isfullscreen) setfullscreen(c, 0); - else - client_set_fullscreen(c, fakefullscreen); + + client_set_fullscreen(c, fakefullscreen); } void setfullscreen(Client *c, int32_t fullscreen) // 用自定义全屏代理自带全屏 @@ -4687,6 +4688,8 @@ void setfullscreen(Client *c, int32_t fullscreen) // 用自定义全屏代理自 if (c->isfloating) c->float_geom = c->geom; + c->isfakefullscreen = 0; + c->bw = 0; wlr_scene_node_raise_to_top(&c->scene->node); // 将视图提升到顶层 if (!is_scroller_layout(c->mon) || c->isfloating) @@ -4695,7 +4698,6 @@ void setfullscreen(Client *c, int32_t fullscreen) // 用自定义全屏代理自 } else { c->bw = c->isnoborder ? 0 : borderpx; c->isfullscreen = 0; - c->isfakefullscreen = 0; if (c->isfloating) setfloating(c, 1); } From e0d69ece59235f6d075da03f093d954fc83b5cdc Mon Sep 17 00:00:00 2001 From: nixpup Date: Fri, 16 Jan 2026 18:49:35 +0100 Subject: [PATCH 446/591] feat: add scroller stack support --- src/config/parse_config.h | 3 + src/dispatch/bind_declare.h | 3 +- src/dispatch/bind_define.h | 112 +++++++++++++++++++++++++--- src/fetch/client.h | 8 ++ src/layout/arrange.h | 61 ++++++++++++--- src/layout/horizontal.h | 93 ++++++++++++++++++++--- src/layout/vertical.h | 95 ++++++++++++++++++++++-- src/mango.c | 143 +++++++++++++++++++++++++++++++++--- 8 files changed, 466 insertions(+), 52 deletions(-) diff --git a/src/config/parse_config.h b/src/config/parse_config.h index 9c278724..b2535b15 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -1080,6 +1080,9 @@ 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, "scroller_stack") == 0) { + func = scroller_stack; + (*arg).i = parse_direction(arg_value); } else { return NULL; } diff --git a/src/dispatch/bind_declare.h b/src/dispatch/bind_declare.h index b197778b..22ef6123 100644 --- a/src/dispatch/bind_declare.h +++ b/src/dispatch/bind_declare.h @@ -68,4 +68,5 @@ int32_t toggle_trackpad_enable(const Arg *arg); 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); \ No newline at end of file +int32_t toggle_monitor(const Arg *arg); +int32_t scroller_stack(const Arg *arg); \ No newline at end of file diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index 19d743e7..3ca79978 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -550,12 +550,14 @@ int32_t set_proportion(const Arg *arg) { !scroller_ignore_proportion_single) return 0; - if (selmon->sel) { + Client *tc = selmon->sel; + + if (tc) { + tc = get_scroll_stack_head(tc); uint32_t max_client_width = selmon->w.width - 2 * scroller_structs - gappih; - selmon->sel->scroller_proportion = arg->f; - selmon->sel->geom.width = max_client_width * arg->f; - // resize(selmon->sel, selmon->sel->geom, 0); + tc->scroller_proportion = arg->f; + tc->geom.width = max_client_width * arg->f; arrange(selmon, false, false); } return 0; @@ -971,11 +973,13 @@ int32_t switch_proportion_preset(const Arg *arg) { !scroller_ignore_proportion_single) return 0; - if (selmon->sel) { + Client *tc = selmon->sel; + if (tc) { + tc = get_scroll_stack_head(tc); for (int32_t i = 0; i < config.scroller_proportion_preset_count; i++) { if (config.scroller_proportion_preset[i] == - selmon->sel->scroller_proportion) { + tc->scroller_proportion) { if (i == config.scroller_proportion_preset_count - 1) { target_proportion = config.scroller_proportion_preset[0]; break; @@ -993,9 +997,8 @@ int32_t switch_proportion_preset(const Arg *arg) { uint32_t max_client_width = selmon->w.width - 2 * scroller_structs - gappih; - selmon->sel->scroller_proportion = target_proportion; - selmon->sel->geom.width = max_client_width * target_proportion; - // resize(selmon->sel, selmon->sel->geom, 0); + tc->scroller_proportion = target_proportion; + tc->geom.width = max_client_width * target_proportion; arrange(selmon, false, false); } return 0; @@ -1093,6 +1096,7 @@ int32_t tagsilent(const Arg *arg) { clear_fullscreen_flag(fc); } } + exit_scroller_stack(target_client); focusclient(focustop(selmon), 1); arrange(target_client->mon, false, false); return 0; @@ -1221,9 +1225,11 @@ int32_t toggleglobal(const Arg *arg) { selmon->sel->isnamedscratchpad = 0; } selmon->sel->isglobal ^= 1; - // selmon->sel->tags = - // selmon->sel->isglobal ? TAGMASK : selmon->tagset[selmon->seltags]; - // focustop(selmon); + if (selmon->sel->isglobal && + (selmon->sel->prev_in_stack || selmon->sel->next_in_stack)) { + exit_scroller_stack(selmon->sel); + arrange(selmon, false, false); + } setborder_color(selmon->sel); return 0; } @@ -1585,3 +1591,85 @@ int32_t toggle_monitor(const Arg *arg) { } return 0; } + +int32_t scroller_stack(const Arg *arg) { + Client *c = selmon->sel; + Client *stack_head = NULL; + Client *source_stack_head = NULL; + if (!c || c->isfloating || !is_scroller_layout(selmon)) + return 0; + + if (c && (!client_only_in_one_tag(c) || c->isglobal || c->isunglobal)) + return 0; + + Client *target_client = find_client_by_direction(c, arg, false, true); + + if (target_client && (!client_only_in_one_tag(target_client) || + target_client->isglobal || target_client->isunglobal)) + return 0; + + if (target_client) { + stack_head = get_scroll_stack_head(target_client); + } + + if (c) { + source_stack_head = get_scroll_stack_head(c); + } + + if (stack_head == source_stack_head) { + return 0; + } + + if (c->isfullscreen) { + setfullscreen(c, 0); + } + + if (c->ismaximizescreen) { + setmaximizescreen(c, 0); + } + + if (c->prev_in_stack) { + exit_scroller_stack(c); + if (arg->i == LEFT || arg->i == UP) { + wl_list_remove(&c->link); + wl_list_insert(source_stack_head->link.prev, &c->link); + } else { + wl_list_remove(&c->link); + wl_list_insert(&source_stack_head->link, &c->link); + } + arrange(selmon, false, false); + return 0; + } else if (c->next_in_stack) { + Client *next_in_stack = c->next_in_stack; + exit_scroller_stack(c); + if (arg->i == LEFT || arg->i == UP) { + wl_list_remove(&c->link); + wl_list_insert(next_in_stack->link.prev, &c->link); + } else { + wl_list_remove(&c->link); + wl_list_insert(&next_in_stack->link, &c->link); + } + arrange(selmon, false, false); + return 0; + } + + if (!target_client || target_client->mon != c->mon) { + return 0; + } + + exit_scroller_stack(c); + + // Find the tail of target_client's stack + Client *stack_tail = target_client; + while (stack_tail->next_in_stack) { + stack_tail = stack_tail->next_in_stack; + } + + // Add c to the stack + stack_tail->next_in_stack = c; + c->prev_in_stack = stack_tail; + c->next_in_stack = NULL; + + arrange(selmon, false, false); + return 0; +} \ No newline at end of file diff --git a/src/fetch/client.h b/src/fetch/client.h index 0af17238..4cd0364b 100644 --- a/src/fetch/client.h +++ b/src/fetch/client.h @@ -447,4 +447,12 @@ bool client_only_in_one_tag(Client *c) { } else { return false; } +} + +Client *get_scroll_stack_head(Client *c) { + Client *scroller_stack_head = c; + while (scroller_stack_head->prev_in_stack) { + scroller_stack_head = scroller_stack_head->prev_in_stack; + } + return scroller_stack_head; } \ No newline at end of file diff --git a/src/layout/arrange.h b/src/layout/arrange.h index d668f309..1f7001f5 100644 --- a/src/layout/arrange.h +++ b/src/layout/arrange.h @@ -378,6 +378,8 @@ void resize_tile_scroller(Client *grabc, bool isdrag, int32_t offsetx, int32_t offsety, uint32_t time, bool isvertical) { float delta_x, delta_y; float new_scroller_proportion; + float new_stack_proportion; + Client *stack_head = get_scroll_stack_head(grabc); if (grabc && grabc->mon->visible_tiling_clients == 1 && !scroller_ignore_proportion_single) @@ -389,7 +391,8 @@ void resize_tile_scroller(Client *grabc, bool isdrag, int32_t offsetx, start_drag_window = true; // 记录初始状态 - grabc->old_scroller_pproportion = grabc->scroller_proportion; + stack_head->old_scroller_pproportion = stack_head->scroller_proportion; + grabc->old_stack_proportion = grabc->stack_proportion; grabc->cursor_in_left_half = cursor->x < grabc->geom.x + grabc->geom.width / 2; @@ -409,15 +412,26 @@ void resize_tile_scroller(Client *grabc, bool isdrag, int32_t offsetx, grabc->old_master_inner_per = grabc->master_inner_per; grabc->old_stack_inner_per = grabc->stack_inner_per; grabc->drag_begin_geom = grabc->geom; - grabc->old_scroller_pproportion = grabc->scroller_proportion; + stack_head->old_scroller_pproportion = + stack_head->scroller_proportion; + grabc->old_stack_proportion = grabc->stack_proportion; grabc->cursor_in_upper_half = false; grabc->cursor_in_left_half = false; } - delta_x = (float)(offsetx) * (grabc->old_scroller_pproportion) / - grabc->drag_begin_geom.width; - delta_y = (float)(offsety) * (grabc->old_scroller_pproportion) / - grabc->drag_begin_geom.height; + if (isvertical) { + delta_y = (float)(offsety) * + (stack_head->old_scroller_pproportion) / + grabc->drag_begin_geom.height; + delta_x = (float)(offsetx) * (grabc->old_stack_proportion) / + grabc->drag_begin_geom.width; + } else { + delta_x = (float)(offsetx) * + (stack_head->old_scroller_pproportion) / + grabc->drag_begin_geom.width; + delta_y = (float)(offsety) * (grabc->old_stack_proportion) / + grabc->drag_begin_geom.height; + } bool moving_up; bool moving_down; @@ -452,18 +466,36 @@ void resize_tile_scroller(Client *grabc, bool isdrag, int32_t offsetx, delta_x = -fabsf(delta_x); } + if (isvertical) { + if (!grabc->next_in_stack && grabc->prev_in_stack && !isdrag) { + delta_x = delta_x * -1.0f; + } + } else { + if (!grabc->next_in_stack && grabc->prev_in_stack && !isdrag) { + delta_y = delta_y * -1.0f; + } + } + // 直接设置新的比例,基于初始值 + 变化量 if (isvertical) { - new_scroller_proportion = grabc->old_scroller_pproportion + delta_y; + new_scroller_proportion = + stack_head->old_scroller_pproportion + delta_y; + new_stack_proportion = grabc->old_stack_proportion + delta_x; + } else { - new_scroller_proportion = grabc->old_scroller_pproportion + delta_x; + new_scroller_proportion = + stack_head->old_scroller_pproportion + delta_x; + new_stack_proportion = grabc->old_stack_proportion + delta_y; } // 应用限制,确保比例在合理范围内 new_scroller_proportion = fmaxf(0.1f, fminf(1.0f, new_scroller_proportion)); + new_stack_proportion = fmaxf(0.1f, fminf(1.0f, new_stack_proportion)); - grabc->scroller_proportion = new_scroller_proportion; + grabc->stack_proportion = new_stack_proportion; + + stack_head->scroller_proportion = new_scroller_proportion; if (!isdrag) { arrange(grabc->mon, false, false); @@ -487,6 +519,9 @@ void resize_tile_client(Client *grabc, bool isdrag, int32_t offsetx, if (grabc->mon->isoverview) return; + int32_t animations_state_backup = animations; + animations = 0; + const Layout *current_layout = grabc->mon->pertag->ltidxs[grabc->mon->pertag->curtag]; if (current_layout->id == TILE || current_layout->id == DECK || @@ -505,6 +540,8 @@ void resize_tile_client(Client *grabc, bool isdrag, int32_t offsetx, } else if (current_layout->id == VERTICAL_SCROLLER) { resize_tile_scroller(grabc, isdrag, offsetx, offsety, time, true); } + + animations = animations_state_backup; } void reset_size_per_mon(Monitor *m, int32_t tile_cilent_num, @@ -605,6 +642,10 @@ arrange(Monitor *m, bool want_animation, bool from_view) { wl_list_for_each(c, &clients, link) { + if (!client_only_in_one_tag(c) || c->isglobal || c->isunglobal) { + exit_scroller_stack(c); + } + if (from_view && (c->isglobal || c->isunglobal)) { set_size_per(m, c); } @@ -627,7 +668,7 @@ arrange(Monitor *m, bool want_animation, bool from_view) { m->visible_tiling_clients++; } - if (ISSCROLLTILED(c)) { + if (ISSCROLLTILED(c) && !c->prev_in_stack) { m->visible_scroll_tiling_clients++; } } diff --git a/src/layout/horizontal.h b/src/layout/horizontal.h index a2f5e5c1..87b6033c 100644 --- a/src/layout/horizontal.h +++ b/src/layout/horizontal.h @@ -212,6 +212,66 @@ void horizontal_scroll_adjust_fullandmax(Client *c, target_geom->y = m->w.y + (m->w.height - target_geom->height) / 2; } +void arrange_stack(Client *scroller_stack_head, struct wlr_box geometry, + int32_t gappiv) { + int32_t stack_size = 0; + Client *iter = scroller_stack_head; + + while (iter) { + stack_size++; + iter = iter->next_in_stack; + } + + if (stack_size == 0) + return; + + float total_proportion = 0.0f; + iter = scroller_stack_head; + while (iter) { + if (iter->stack_proportion <= 0.0f || iter->stack_proportion >= 1.0f) { + iter->stack_proportion = + stack_size == 1 ? 1.0f : 1.0f / (stack_size - 1); + } + total_proportion += iter->stack_proportion; + iter = iter->next_in_stack; + } + + iter = scroller_stack_head; + while (iter) { + iter->stack_proportion = iter->stack_proportion / total_proportion; + iter = iter->next_in_stack; + } + + int32_t client_height; + int32_t current_y = geometry.y; + int32_t remain_client_height = geometry.height - (stack_size - 1) * gappiv; + float remain_proportion = 1.0f; + + iter = scroller_stack_head; + while (iter) { + + client_height = + remain_client_height * (iter->stack_proportion / remain_proportion); + + struct wlr_box client_geom = {.x = geometry.x, + .y = current_y, + .width = geometry.width, + .height = client_height}; + resize(iter, client_geom, 0); + remain_proportion -= iter->stack_proportion; + remain_client_height -= client_height; + current_y += client_height + gappiv; + iter = iter->next_in_stack; + } +} + +void horizontal_check_scroller_root_inside_mon(Client *c, + struct wlr_box *geometry) { + if (!GEOMINSIDEMON(geometry, c->mon)) { + geometry->x = c->mon->w.x + (c->mon->w.width - geometry->width) / 2; + } +} + // 滚动布局 void scroller(Monitor *m) { int32_t i, n, j; @@ -225,6 +285,7 @@ void scroller(Monitor *m) { int32_t cur_gappih = enablegaps ? m->gappih : 0; int32_t cur_gappoh = enablegaps ? m->gappoh : 0; int32_t cur_gappov = enablegaps ? m->gappov : 0; + int32_t cur_gappiv = enablegaps ? m->gappiv : 0; cur_gappih = smartgaps && m->visible_scroll_tiling_clients == 1 ? 0 : cur_gappih; @@ -251,7 +312,7 @@ void scroller(Monitor *m) { // 第二次遍历,填充 tempClients j = 0; wl_list_for_each(c, &clients, link) { - if (VISIBLEON(c, m) && ISSCROLLTILED(c)) { + if (VISIBLEON(c, m) && ISSCROLLTILED(c) && !c->prev_in_stack) { tempClients[j] = c; j++; } @@ -269,7 +330,8 @@ void scroller(Monitor *m) { target_geom.width = (m->w.width - 2 * cur_gappoh) * single_proportion; target_geom.x = m->w.x + (m->w.width - target_geom.width) / 2; target_geom.y = m->w.y + (m->w.height - target_geom.height) / 2; - resize(c, target_geom, 0); + horizontal_check_scroller_root_inside_mon(c, &target_geom); + arrange_stack(c, target_geom, cur_gappiv); free(tempClients); // 释放内存 return; } @@ -283,6 +345,11 @@ void scroller(Monitor *m) { root_client = center_tiled_select(m); } + // root_client might be in a stack, find the stack head + if (root_client) { + root_client = get_scroll_stack_head(root_client); + } + if (!root_client) { free(tempClients); // 释放内存 return; @@ -317,10 +384,14 @@ void scroller(Monitor *m) { &target_geom); if (tempClients[focus_client_index]->isfullscreen) { target_geom.x = m->m.x; - resize(tempClients[focus_client_index], target_geom, 0); + horizontal_check_scroller_root_inside_mon( + tempClients[focus_client_index], &target_geom); + arrange_stack(tempClients[focus_client_index], target_geom, cur_gappiv); } else if (tempClients[focus_client_index]->ismaximizescreen) { target_geom.x = m->w.x + cur_gappoh; - resize(tempClients[focus_client_index], target_geom, 0); + horizontal_check_scroller_root_inside_mon( + tempClients[focus_client_index], &target_geom); + arrange_stack(tempClients[focus_client_index], target_geom, cur_gappiv); } else if (need_scroller) { if (scroller_focus_center || ((!m->prevsel || @@ -338,10 +409,14 @@ void scroller(Monitor *m) { scroller_structs) : m->w.x + scroller_structs; } - resize(tempClients[focus_client_index], target_geom, 0); + horizontal_check_scroller_root_inside_mon( + tempClients[focus_client_index], &target_geom); + arrange_stack(tempClients[focus_client_index], target_geom, cur_gappiv); } else { target_geom.x = c->geom.x; - resize(tempClients[focus_client_index], target_geom, 0); + horizontal_check_scroller_root_inside_mon( + tempClients[focus_client_index], &target_geom); + arrange_stack(tempClients[focus_client_index], target_geom, cur_gappiv); } for (i = 1; i <= focus_client_index; i++) { @@ -351,7 +426,7 @@ void scroller(Monitor *m) { target_geom.x = tempClients[focus_client_index - i + 1]->geom.x - cur_gappih - target_geom.width; - resize(c, target_geom, 0); + arrange_stack(c, target_geom, cur_gappiv); } for (i = 1; i < n - focus_client_index; i++) { @@ -361,7 +436,7 @@ void scroller(Monitor *m) { target_geom.x = tempClients[focus_client_index + i - 1]->geom.x + cur_gappih + tempClients[focus_client_index + i - 1]->geom.width; - resize(c, target_geom, 0); + arrange_stack(c, target_geom, cur_gappiv); } free(tempClients); // 最后释放内存 @@ -853,4 +928,4 @@ void tgmix(Monitor *m) { grid(m); return; } -} \ No newline at end of file +} diff --git a/src/layout/vertical.h b/src/layout/vertical.h index 95138248..2c2dc661 100644 --- a/src/layout/vertical.h +++ b/src/layout/vertical.h @@ -199,6 +199,66 @@ void vertical_scroll_adjust_fullandmax(Client *c, struct wlr_box *target_geom) { target_geom->x = m->w.x + (m->w.width - target_geom->width) / 2; } +void arrange_stack_vertical(Client *scroller_stack_head, + struct wlr_box geometry, int32_t gappih) { + int32_t stack_size = 0; + Client *iter = scroller_stack_head; + + while (iter) { + stack_size++; + iter = iter->next_in_stack; + } + + if (stack_size == 0) + return; + + float total_proportion = 0.0f; + iter = scroller_stack_head; + while (iter) { + if (iter->stack_proportion <= 0.0f || iter->stack_proportion >= 1.0f) { + iter->stack_proportion = + stack_size == 1 ? 1.0f : 1.0f / (stack_size - 1); + } + total_proportion += iter->stack_proportion; + iter = iter->next_in_stack; + } + + iter = scroller_stack_head; + while (iter) { + iter->stack_proportion = iter->stack_proportion / total_proportion; + iter = iter->next_in_stack; + } + + int32_t client_width; + int32_t current_x = geometry.x; + int32_t remain_client_width = geometry.width - (stack_size - 1) * gappih; + float remain_proportion = 1.0f; + + iter = scroller_stack_head; + while (iter) { + + client_width = + remain_client_width * (iter->stack_proportion / remain_proportion); + + struct wlr_box client_geom = {.y = geometry.y, + .x = current_x, + .height = geometry.height, + .width = client_width}; + resize(iter, client_geom, 0); + remain_proportion -= iter->stack_proportion; + remain_client_width -= client_width; + current_x += client_width + gappih; + iter = iter->next_in_stack; + } +} + +void vertical_check_scroller_root_inside_mon(Client *c, + struct wlr_box *geometry) { + if (!GEOMINSIDEMON(geometry, c->mon)) { + geometry->y = c->mon->w.y + (c->mon->w.height - geometry->height) / 2; + } +} + // 竖屏滚动布局 void vertical_scroller(Monitor *m) { int32_t i, n, j; @@ -212,6 +272,7 @@ void vertical_scroller(Monitor *m) { int32_t cur_gappiv = enablegaps ? m->gappiv : 0; int32_t cur_gappov = enablegaps ? m->gappov : 0; int32_t cur_gappoh = enablegaps ? m->gappoh : 0; + int32_t cur_gappih = enablegaps ? m->gappih : 0; cur_gappiv = smartgaps && m->visible_scroll_tiling_clients == 1 ? 0 : cur_gappiv; @@ -235,7 +296,7 @@ void vertical_scroller(Monitor *m) { j = 0; wl_list_for_each(c, &clients, link) { - if (VISIBLEON(c, m) && ISSCROLLTILED(c)) { + if (VISIBLEON(c, m) && ISSCROLLTILED(c) && !c->prev_in_stack) { tempClients[j] = c; j++; } @@ -253,7 +314,8 @@ void vertical_scroller(Monitor *m) { target_geom.height = (m->w.height - 2 * cur_gappov) * single_proportion; target_geom.y = m->w.y + (m->w.height - target_geom.height) / 2; target_geom.x = m->w.x + (m->w.width - target_geom.width) / 2; - resize(c, target_geom, 0); + vertical_check_scroller_root_inside_mon(c, &target_geom); + arrange_stack_vertical(c, target_geom, cur_gappih); free(tempClients); return; } @@ -267,6 +329,11 @@ void vertical_scroller(Monitor *m) { root_client = center_tiled_select(m); } + // root_client might be in a stack, find the stack head + if (root_client) { + root_client = get_scroll_stack_head(root_client); + } + if (!root_client) { free(tempClients); return; @@ -302,10 +369,16 @@ void vertical_scroller(Monitor *m) { if (tempClients[focus_client_index]->isfullscreen) { target_geom.y = m->m.y; - resize(tempClients[focus_client_index], target_geom, 0); + vertical_check_scroller_root_inside_mon(tempClients[focus_client_index], + &target_geom); + arrange_stack_vertical(tempClients[focus_client_index], target_geom, + cur_gappih); } else if (tempClients[focus_client_index]->ismaximizescreen) { target_geom.y = m->w.y + cur_gappov; - resize(tempClients[focus_client_index], target_geom, 0); + vertical_check_scroller_root_inside_mon(tempClients[focus_client_index], + &target_geom); + arrange_stack_vertical(tempClients[focus_client_index], target_geom, + cur_gappih); } else if (need_scroller) { if (scroller_focus_center || ((!m->prevsel || @@ -323,10 +396,16 @@ void vertical_scroller(Monitor *m) { scroller_structs) : m->w.y + scroller_structs; } - resize(tempClients[focus_client_index], target_geom, 0); + vertical_check_scroller_root_inside_mon(tempClients[focus_client_index], + &target_geom); + arrange_stack_vertical(tempClients[focus_client_index], target_geom, + cur_gappih); } else { target_geom.y = c->geom.y; - resize(tempClients[focus_client_index], target_geom, 0); + vertical_check_scroller_root_inside_mon(tempClients[focus_client_index], + &target_geom); + arrange_stack_vertical(tempClients[focus_client_index], target_geom, + cur_gappih); } for (i = 1; i <= focus_client_index; i++) { @@ -336,7 +415,7 @@ void vertical_scroller(Monitor *m) { target_geom.y = tempClients[focus_client_index - i + 1]->geom.y - cur_gappiv - target_geom.height; - resize(c, target_geom, 0); + arrange_stack_vertical(c, target_geom, cur_gappih); } for (i = 1; i < n - focus_client_index; i++) { @@ -346,7 +425,7 @@ void vertical_scroller(Monitor *m) { target_geom.y = tempClients[focus_client_index + i - 1]->geom.y + cur_gappiv + tempClients[focus_client_index + i - 1]->geom.height; - resize(c, target_geom, 0); + arrange_stack_vertical(c, target_geom, cur_gappih); } free(tempClients); diff --git a/src/mango.c b/src/mango.c index 6760b7b5..250b89c0 100644 --- a/src/mango.c +++ b/src/mango.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -101,6 +102,10 @@ (A->geom.x >= A->mon->m.x && A->geom.y >= A->mon->m.y && \ A->geom.x + A->geom.width <= A->mon->m.x + A->mon->m.width && \ A->geom.y + A->geom.height <= A->mon->m.y + A->mon->m.height) +#define GEOMINSIDEMON(A, M) \ + (A->x >= M->m.x && A->y >= M->m.y && \ + A->x + A->width <= M->m.x + M->m.width && \ + A->y + A->height <= M->m.y + M->m.height) #define ISTILED(A) \ (A && !(A)->isfloating && !(A)->isminimized && !(A)->iskilling && \ !(A)->ismaximizescreen && !(A)->isfullscreen && !(A)->isunglobal) @@ -375,6 +380,8 @@ struct Client { bool is_pending_open_animation; bool is_restoring_from_ov; float scroller_proportion; + float stack_proportion; + float old_stack_proportion; bool need_output_flush; struct dwl_animation animation; struct dwl_opacity_animation opacity_animation; @@ -407,6 +414,8 @@ struct Client { int32_t allow_shortcuts_inhibit; float scroller_proportion_single; bool isfocusing; + struct Client *next_in_stack; + struct Client *prev_in_stack; }; typedef struct { @@ -762,6 +771,11 @@ static void init_client_properties(Client *c); static float *get_border_color(Client *c); static void clear_fullscreen_and_maximized_state(Monitor *m); static void request_fresh_all_monitors(void); +static Client *find_client_by_direction(Client *tc, const Arg *arg, + bool findfloating, bool ignore_align); +static void exit_scroller_stack(Client *c); +static Client *get_scroll_stack_head(Client *c); +static bool client_only_in_one_tag(Client *c); #include "data/static_keymap.h" #include "dispatch/bind_declare.h" @@ -1053,6 +1067,13 @@ void swallow(Client *c, Client *w) { c->geom = w->geom; c->float_geom = w->float_geom; c->scroller_proportion = w->scroller_proportion; + c->next_in_stack = w->next_in_stack; + c->prev_in_stack = w->prev_in_stack; + if (w->next_in_stack) + w->next_in_stack->prev_in_stack = c; + if (w->prev_in_stack) + w->prev_in_stack->next_in_stack = c; + c->stack_proportion = w->stack_proportion; wl_list_insert(&w->link, &c->link); wl_list_insert(&w->flink, &c->flink); @@ -3636,7 +3657,8 @@ void keypressmod(struct wl_listener *listener, void *data) { } void pending_kill_client(Client *c) { - // c->iskilling = 1; //不可以提前标记已经杀掉,因为有些客户端可能拒绝 + if (!c || c->iskilling) + return; client_send_close(c); } @@ -3744,6 +3766,9 @@ void init_client_properties(Client *c) { c->float_geom.height = 0; c->float_geom.x = 0; c->float_geom.y = 0; + c->stack_proportion = 0.0f; + c->next_in_stack = NULL; + c->prev_in_stack = NULL; } void // old fix to 0.5 @@ -3823,7 +3848,7 @@ mapnotify(struct wl_listener *listener, void *data) { if (selmon->sel && ISSCROLLTILED(selmon->sel) && VISIBLEON(selmon->sel, selmon)) { - at_client = selmon->sel; + at_client = get_scroll_stack_head(selmon->sel); } else { at_client = center_tiled_select(selmon); } @@ -4175,8 +4200,8 @@ void pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy, uint32_t time) { struct timespec now; - if (sloppyfocus && c && time && c->scene->node.enabled && - !c->animation.tagining && + if (sloppyfocus && !start_drag_window && c && time && + c->scene->node.enabled && !c->animation.tagining && (surface != seat->pointer_state.focused_surface) && !client_is_unmanaged(c) && VISIBLEON(c, c->mon)) focusclient(c, 0); @@ -4353,12 +4378,32 @@ void exchange_two_client(Client *c1, Client *c2) { double master_inner_per = 0.0f; double master_mfact_per = 0.0f; double stack_inner_per = 0.0f; + float scroller_proportion = 0.0f; + float stack_proportion = 0.0f; if (c1 == NULL || c2 == NULL || (!exchange_cross_monitor && c1->mon != c2->mon)) { return; } + if (c1->mon != c2->mon && (c1->prev_in_stack || c2->prev_in_stack || + c1->next_in_stack || c2->next_in_stack)) + return; + + Client *c1head = get_scroll_stack_head(c1); + Client *c2head = get_scroll_stack_head(c2); + + // 交换布局参数 + if (c1head == c2head) { + scroller_proportion = c1->scroller_proportion; + stack_proportion = c1->stack_proportion; + + c1->scroller_proportion = c2->scroller_proportion; + c1->stack_proportion = c2->stack_proportion; + c2->scroller_proportion = scroller_proportion; + c2->stack_proportion = stack_proportion; + } + master_inner_per = c1->master_inner_per; master_mfact_per = c1->master_mfact_per; stack_inner_per = c1->stack_inner_per; @@ -4371,17 +4416,46 @@ void exchange_two_client(Client *c1, Client *c2) { c2->master_mfact_per = master_mfact_per; c2->stack_inner_per = stack_inner_per; + // 交换栈链表连接 + Client *tmp1_next_in_stack = c1->next_in_stack; + Client *tmp1_prev_in_stack = c1->prev_in_stack; + Client *tmp2_next_in_stack = c2->next_in_stack; + Client *tmp2_prev_in_stack = c2->prev_in_stack; + + // 处理相邻节点的情况 + if (c1->next_in_stack == c2) { + c1->next_in_stack = tmp2_next_in_stack; + c2->next_in_stack = c1; + c1->prev_in_stack = c2; + c2->prev_in_stack = tmp1_prev_in_stack; + if (tmp1_prev_in_stack) + tmp1_prev_in_stack->next_in_stack = c2; + if (tmp2_next_in_stack) + tmp2_next_in_stack->prev_in_stack = c1; + } else if (c2->next_in_stack == c1) { + c2->next_in_stack = tmp1_next_in_stack; + c1->next_in_stack = c2; + c2->prev_in_stack = c1; + c1->prev_in_stack = tmp2_prev_in_stack; + if (tmp2_prev_in_stack) + tmp2_prev_in_stack->next_in_stack = c1; + if (tmp1_next_in_stack) + tmp1_next_in_stack->prev_in_stack = c2; + } else if (c1->prev_in_stack || c2->prev_in_stack) { + Client *c1head = get_scroll_stack_head(c1); + Client *c2head = get_scroll_stack_head(c2); + exchange_two_client(c1head, c2head); + focusclient(c1, 0); + return; + } + + // 交换全局链表连接 struct wl_list *tmp1_prev = c1->link.prev; struct wl_list *tmp2_prev = c2->link.prev; struct wl_list *tmp1_next = c1->link.next; struct wl_list *tmp2_next = c2->link.next; - // wl_list - // 是双向链表,其中clients是头部节点,它的下一个节点是第一个客户端的链表节点 - // 最后一个客户端的链表节点的下一个节点也指向clients,但clients本身不是客户端的链表节点 - // 客户端遍历从clients的下一个节点开始,到检测到客户端节点的下一个是clients结束 - - // 当c1和c2为相邻节点时 + // 处理相邻节点的情况 if (c1->link.next == &c2->link) { c1->link.next = c2->link.next; c1->link.prev = &c2->link; @@ -4408,6 +4482,7 @@ void exchange_two_client(Client *c1, Client *c2) { tmp2_next->prev = &c1->link; } + // 处理跨监视器交换 if (exchange_cross_monitor) { tmp_mon = c2->mon; tmp_tags = c2->tags; @@ -4418,7 +4493,6 @@ void exchange_two_client(Client *c1, Client *c2) { focusclient(c1, 0); } else { arrange(c1->mon, false, false); - focusclient(c1, 0); } } @@ -4538,6 +4612,8 @@ setfloating(Client *c, int32_t floating) { c->bw = c->isnoborder ? 0 : borderpx; } + exit_scroller_stack(c); + // 重新计算居中的坐标 if (!client_is_x11(c) && !c->iscustompos) target_box = @@ -4609,6 +4685,27 @@ void reset_maximizescreen_size(Client *c) { resize(c, c->geom, 0); } +void exit_scroller_stack(Client *c) { + // If c is already in a stack, remove it. + if (c->prev_in_stack) { + c->prev_in_stack->next_in_stack = c->next_in_stack; + } + + if (!c->prev_in_stack && c->next_in_stack) { + c->next_in_stack->scroller_proportion = c->scroller_proportion; + wl_list_remove(&c->next_in_stack->link); + wl_list_insert(&c->link, &c->next_in_stack->link); + } + + if (c->next_in_stack) { + c->next_in_stack->prev_in_stack = c->prev_in_stack; + } + + c->prev_in_stack = NULL; + c->next_in_stack = NULL; + c->stack_proportion = 0.0f; +} + void setmaximizescreen(Client *c, int32_t maximizescreen) { struct wlr_box maximizescreen_box; if (!c || !c->mon || !client_surface(c)->mapped || c->iskilling) @@ -4624,6 +4721,8 @@ void setmaximizescreen(Client *c, int32_t maximizescreen) { if (c->isfullscreen) setfullscreen(c, 0); + exit_scroller_stack(c); + if (c->isfloating) c->float_geom = c->geom; @@ -4685,6 +4784,8 @@ void setfullscreen(Client *c, int32_t fullscreen) // 用自定义全屏代理自 if (c->ismaximizescreen) setmaximizescreen(c, 0); + exit_scroller_stack(c); + if (c->isfloating) c->float_geom = c->geom; @@ -5259,6 +5360,7 @@ void tag_client(const Arg *arg, Client *target_client) { Client *fc = NULL; if (target_client && arg->ui & TAGMASK) { + exit_scroller_stack(target_client); target_client->tags = arg->ui & TAGMASK; target_client->istagswitching = 1; @@ -5406,15 +5508,22 @@ void unmapnotify(struct wl_listener *listener, void *data) { */ Client *c = wl_container_of(listener, c, unmap); Monitor *m = NULL; + Client *nextfocus = NULL; + Client *next_in_stack = c->next_in_stack; + Client *prev_in_stack = c->prev_in_stack; c->iskilling = 1; if (animations && !c->is_clip_to_hide && !c->isminimized && (!c->mon || VISIBLEON(c, c->mon))) init_fadeout_client(c); + // If the client is in a stack, remove it from the stack + if (c->swallowedby) { c->swallowedby->mon = c->mon; swallow(c->swallowedby, c); + } else { + exit_scroller_stack(c); } if (c == grabc) { @@ -5435,7 +5544,13 @@ void unmapnotify(struct wl_listener *listener, void *data) { } if (c->mon && c->mon == selmon) { - Client *nextfocus = focustop(selmon); + if (next_in_stack && !c->swallowedby) { + nextfocus = next_in_stack; + } else if (prev_in_stack && !c->swallowedby) { + nextfocus = prev_in_stack; + } else { + nextfocus = focustop(selmon); + } if (nextfocus) { focusclient(nextfocus, 0); @@ -5482,6 +5597,10 @@ void unmapnotify(struct wl_listener *listener, void *data) { c->swallowing = NULL; } + c->stack_proportion = 0.0f; + c->next_in_stack = NULL; + c->prev_in_stack = NULL; + wlr_scene_node_destroy(&c->scene->node); printstatus(); motionnotify(0, NULL, 0, 0, 0, 0); From deaa26c7794885c3125088776ec7319f53aa43b5 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sun, 18 Jan 2026 22:54:01 +0800 Subject: [PATCH 447/591] opt: disable animaiton for resize and move window dispatch --- src/dispatch/bind_define.h | 17 +++++++++++++++++ src/layout/arrange.h | 5 ----- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index 3ca79978..c708de8c 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -382,6 +382,9 @@ int32_t movewin(const Arg *arg) { if (!c->isfloating) togglefloating(NULL); + int32_t animations_state_backup = animations; + animations = 0; + switch (arg->ui) { case NUM_TYPE_MINUS: c->geom.x -= arg->i; @@ -409,6 +412,7 @@ int32_t movewin(const Arg *arg) { c->iscustomsize = 1; c->float_geom = c->geom; resize(c, c->geom, 0); + animations = animations_state_backup; return 0; } @@ -425,6 +429,9 @@ int32_t resizewin(const Arg *arg) { if (!c || c->isfullscreen || c->ismaximizescreen) return 0; + int32_t animations_state_backup = animations; + animations = 0; + if (ISTILED(c)) { switch (arg->ui) { case NUM_TYPE_MINUS: @@ -450,6 +457,7 @@ int32_t resizewin(const Arg *arg) { break; } resize_tile_client(c, false, offsetx, offsety, 0); + animations = animations_state_backup; return 0; } @@ -480,6 +488,7 @@ int32_t resizewin(const Arg *arg) { c->iscustomsize = 1; c->float_geom = c->geom; resize(c, c->geom, 0); + animations = animations_state_backup; return 0; } @@ -575,6 +584,9 @@ int32_t smartmovewin(const Arg *arg) { nx = c->geom.x; ny = c->geom.y; + int32_t animations_state_backup = animations; + animations = 0; + switch (arg->i) { case UP: tar = -99999; @@ -661,6 +673,7 @@ int32_t smartmovewin(const Arg *arg) { .x = nx, .y = ny, .width = c->geom.width, .height = c->geom.height}; c->iscustomsize = 1; resize(c, c->float_geom, 1); + animations = animations_state_backup; return 0; } @@ -676,6 +689,9 @@ int32_t smartresizewin(const Arg *arg) { nw = c->geom.width; nh = c->geom.height; + int32_t animations_state_backup = animations; + animations = 0; + switch (arg->i) { case UP: nh -= selmon->w.height / 8; @@ -731,6 +747,7 @@ int32_t smartresizewin(const Arg *arg) { .x = c->geom.x, .y = c->geom.y, .width = nw, .height = nh}; c->iscustomsize = 1; resize(c, c->float_geom, 1); + animations = animations_state_backup; return 0; } diff --git a/src/layout/arrange.h b/src/layout/arrange.h index 1f7001f5..fa8556eb 100644 --- a/src/layout/arrange.h +++ b/src/layout/arrange.h @@ -519,9 +519,6 @@ void resize_tile_client(Client *grabc, bool isdrag, int32_t offsetx, if (grabc->mon->isoverview) return; - int32_t animations_state_backup = animations; - animations = 0; - const Layout *current_layout = grabc->mon->pertag->ltidxs[grabc->mon->pertag->curtag]; if (current_layout->id == TILE || current_layout->id == DECK || @@ -540,8 +537,6 @@ void resize_tile_client(Client *grabc, bool isdrag, int32_t offsetx, } else if (current_layout->id == VERTICAL_SCROLLER) { resize_tile_scroller(grabc, isdrag, offsetx, offsety, time, true); } - - animations = animations_state_backup; } void reset_size_per_mon(Monitor *m, int32_t tile_cilent_num, From 00f56fa3aaa59d2b7ccd727d0b371b618b3d228b Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sun, 18 Jan 2026 23:13:43 +0800 Subject: [PATCH 448/591] opt: ignore direction arg if the direction not match the scroller direction --- src/dispatch/bind_define.h | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index c708de8c..a1f9a3ad 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -1613,12 +1613,16 @@ int32_t scroller_stack(const Arg *arg) { Client *c = selmon->sel; Client *stack_head = NULL; Client *source_stack_head = NULL; - if (!c || c->isfloating || !is_scroller_layout(selmon)) + if (!c || !c->mon || c->isfloating || !is_scroller_layout(selmon)) return 0; if (c && (!client_only_in_one_tag(c) || c->isglobal || c->isunglobal)) return 0; + bool is_horizontal_layout = + c->mon->pertag->ltidxs[c->mon->pertag->curtag]->id == SCROLLER ? true + : false; + Client *target_client = find_client_by_direction(c, arg, false, true); if (target_client && (!client_only_in_one_tag(target_client) || @@ -1646,27 +1650,36 @@ int32_t scroller_stack(const Arg *arg) { } if (c->prev_in_stack) { - exit_scroller_stack(c); - if (arg->i == LEFT || arg->i == UP) { + if ((is_horizontal_layout && arg->i == LEFT) || + (!is_horizontal_layout && arg->i == UP)) { + exit_scroller_stack(c); wl_list_remove(&c->link); wl_list_insert(source_stack_head->link.prev, &c->link); - } else { + arrange(selmon, false, false); + + } else if ((is_horizontal_layout && arg->i == RIGHT) || + (!is_horizontal_layout && arg->i == DOWN)) { + exit_scroller_stack(c); wl_list_remove(&c->link); wl_list_insert(&source_stack_head->link, &c->link); + arrange(selmon, false, false); } - arrange(selmon, false, false); return 0; } else if (c->next_in_stack) { Client *next_in_stack = c->next_in_stack; - exit_scroller_stack(c); - if (arg->i == LEFT || arg->i == UP) { + if ((is_horizontal_layout && arg->i == LEFT) || + (!is_horizontal_layout && arg->i == UP)) { + exit_scroller_stack(c); wl_list_remove(&c->link); wl_list_insert(next_in_stack->link.prev, &c->link); - } else { + arrange(selmon, false, false); + } else if ((is_horizontal_layout && arg->i == RIGHT) || + (!is_horizontal_layout && arg->i == DOWN)) { + exit_scroller_stack(c); wl_list_remove(&c->link); wl_list_insert(&next_in_stack->link, &c->link); + arrange(selmon, false, false); } - arrange(selmon, false, false); return 0; } From 57d7801df2e8dc21414d710d00c4201c6c77a4c0 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sun, 18 Jan 2026 23:31:48 +0800 Subject: [PATCH 449/591] opt: exit stack head client maximize and fullscreen state when toggle scroller stack --- src/dispatch/bind_define.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index a1f9a3ad..6cc66701 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -1700,6 +1700,14 @@ int32_t scroller_stack(const Arg *arg) { c->prev_in_stack = stack_tail; c->next_in_stack = NULL; + if (stack_head->ismaximizescreen) { + setmaximizescreen(stack_head, 0); + } + + if (stack_head->isfullscreen) { + setfullscreen(stack_head, 0); + } + arrange(selmon, false, false); return 0; } \ No newline at end of file From 48c466254a9f88303c367f2e7f4a04e1c6976f09 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Mon, 19 Jan 2026 10:09:35 +0800 Subject: [PATCH 450/591] feat: optimize focusdir to respect focusstack --- src/dispatch/bind_define.h | 1 + src/fetch/client.h | 80 +++++++++++++++++++++++++++++++++++++- src/fetch/monitor.h | 8 ++++ src/mango.c | 3 ++ 4 files changed, 90 insertions(+), 2 deletions(-) diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index 6cc66701..02680789 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -129,6 +129,7 @@ int32_t exchange_stack_client(const Arg *arg) { int32_t focusdir(const Arg *arg) { Client *c = NULL; c = direction_select(arg); + c = get_focused_stack_client(c); if (c) { focusclient(c, 1); if (warpcursor) diff --git a/src/fetch/client.h b/src/fetch/client.h index 4cd0364b..c1ca3cfb 100644 --- a/src/fetch/client.h +++ b/src/fetch/client.h @@ -369,7 +369,9 @@ Client *direction_select(const Arg *arg) { } return find_client_by_direction( - tc, arg, true, is_scroller_layout(selmon) && !selmon->isoverview); + tc, arg, true, + (is_scroller_layout(selmon) || is_centertile_layout(selmon)) && + !selmon->isoverview); } /* We probably should change the name of this, it sounds like @@ -455,4 +457,78 @@ Client *get_scroll_stack_head(Client *c) { scroller_stack_head = scroller_stack_head->prev_in_stack; } return scroller_stack_head; -} \ No newline at end of file +} + +bool client_is_in_same_stack(Client *sc, Client *tc, Client *fc) { + if (!sc || !tc) + return false; + + uint32_t id = sc->mon->pertag->ltidxs[sc->mon->pertag->curtag]->id; + + if (id != SCROLLER && id != VERTICAL_SCROLLER && id != TILE && + id != VERTICAL_TILE && id != DECK && id != VERTICAL_DECK && + id != CENTER_TILE && id != RIGHT_TILE && id != TGMIX) + return false; + + if (id == SCROLLER || id == VERTICAL_SCROLLER) { + if (fc->prev_in_stack) + return false; + Client *source_stack_head = get_scroll_stack_head(sc); + Client *target_stack_head = get_scroll_stack_head(tc); + if (source_stack_head == target_stack_head) + return true; + else + return false; + } + + if (id == TILE || id == VERTICAL_TILE || id == DECK || + id == VERTICAL_DECK || id == RIGHT_TILE) { + if (!fc->ismaster) + return false; + else + return true; + } + + if (id == TGMIX) { + if (!fc->ismaster) + return false; + if (sc->mon->visible_tiling_clients <= 3) + return true; + } + + if (id == CENTER_TILE) { + if (!fc->ismaster) + return false; + if (sc->geom.x == tc->geom.x) + return true; + else + return false; + } + + return false; +} + +Client *get_focused_stack_client(Client *sc) { + if (!sc || sc->isfloating) + return sc; + + Client *tc = NULL; + Client *fc = focustop(sc->mon); + + if (fc->isfloating || sc->isfloating) + return sc; + + wl_list_for_each(tc, &fstack, flink) { + if (tc->iskilling || tc->isunglobal) + continue; + if (!VISIBLEON(tc, sc->mon)) + continue; + if (tc == fc) + continue; + + if (client_is_in_same_stack(sc, tc, fc)) { + return tc; + } + } + return sc; +} diff --git a/src/fetch/monitor.h b/src/fetch/monitor.h index 47a5b824..7a1ca4dc 100644 --- a/src/fetch/monitor.h +++ b/src/fetch/monitor.h @@ -26,6 +26,14 @@ bool is_scroller_layout(Monitor *m) { return false; } +bool is_centertile_layout(Monitor *m) { + + if (m->pertag->ltidxs[m->pertag->curtag]->id == CENTER_TILE) + return true; + + return false; +} + uint32_t get_tag_status(uint32_t tag, Monitor *m) { Client *c = NULL; uint32_t status = 0; diff --git a/src/mango.c b/src/mango.c index 250b89c0..83f31cc6 100644 --- a/src/mango.c +++ b/src/mango.c @@ -752,6 +752,7 @@ static struct wlr_scene_tree * wlr_scene_tree_snapshot(struct wlr_scene_node *node, struct wlr_scene_tree *parent); static bool is_scroller_layout(Monitor *m); +static bool is_centertile_layout(Monitor *m); static void create_output(struct wlr_backend *backend, void *data); static void get_layout_abbr(char *abbr, const char *full_name); static void apply_named_scratchpad(Client *target_client); @@ -776,6 +777,8 @@ static Client *find_client_by_direction(Client *tc, const Arg *arg, static void exit_scroller_stack(Client *c); static Client *get_scroll_stack_head(Client *c); static bool client_only_in_one_tag(Client *c); +static Client *get_focused_stack_client(Client *sc); +static bool client_is_in_same_stack(Client *sc, Client *tc, Client *fc); #include "data/static_keymap.h" #include "dispatch/bind_declare.h" From 34aa2e019e9f206661881144edd2f2f6a55f99f9 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Mon, 19 Jan 2026 11:50:25 +0800 Subject: [PATCH 451/591] opt: optimize drag resize for scoller --- src/layout/arrange.h | 45 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/src/layout/arrange.h b/src/layout/arrange.h index fa8556eb..7f81e5bb 100644 --- a/src/layout/arrange.h +++ b/src/layout/arrange.h @@ -470,10 +470,55 @@ void resize_tile_scroller(Client *grabc, bool isdrag, int32_t offsetx, if (!grabc->next_in_stack && grabc->prev_in_stack && !isdrag) { delta_x = delta_x * -1.0f; } + if (!grabc->next_in_stack && grabc->prev_in_stack && isdrag) { + if (moving_right) { + delta_x = -fabsf(delta_x); + } else { + delta_x = fabsf(delta_x); + } + } + if (!grabc->prev_in_stack && grabc->next_in_stack && isdrag) { + if (moving_left) { + delta_x = -fabsf(delta_x); + } else { + delta_x = fabsf(delta_x); + } + } + + if (isdrag) { + if (moving_up) { + delta_y = -fabsf(delta_y); + } else { + delta_y = fabsf(delta_y); + } + } + } else { if (!grabc->next_in_stack && grabc->prev_in_stack && !isdrag) { delta_y = delta_y * -1.0f; } + if (!grabc->next_in_stack && grabc->prev_in_stack && isdrag) { + if (moving_down) { + delta_y = -fabsf(delta_y); + } else { + delta_y = fabsf(delta_y); + } + } + if (!grabc->prev_in_stack && grabc->next_in_stack && isdrag) { + if (moving_up) { + delta_y = -fabsf(delta_y); + } else { + delta_y = fabsf(delta_y); + } + } + + if (isdrag) { + if (moving_left) { + delta_x = -fabsf(delta_x); + } else { + delta_x = fabsf(delta_x); + } + } } // 直接设置新的比例,基于初始值 + 变化量 From eff11a5912b118f8bace034d9230f2cc3d83acc0 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Mon, 19 Jan 2026 12:13:42 +0800 Subject: [PATCH 452/591] opt: focusdir miss remember focuslink when between two different stack client --- src/fetch/client.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/fetch/client.h b/src/fetch/client.h index c1ca3cfb..6294e171 100644 --- a/src/fetch/client.h +++ b/src/fetch/client.h @@ -471,10 +471,11 @@ bool client_is_in_same_stack(Client *sc, Client *tc, Client *fc) { return false; if (id == SCROLLER || id == VERTICAL_SCROLLER) { - if (fc->prev_in_stack) - return false; Client *source_stack_head = get_scroll_stack_head(sc); Client *target_stack_head = get_scroll_stack_head(tc); + Client *fc_head = get_scroll_stack_head(fc); + if (fc->prev_in_stack && fc_head == source_stack_head) + return false; if (source_stack_head == target_stack_head) return true; else From 43257ad49cd76dc42ab4237dc9650d9f96a7fd26 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Mon, 19 Jan 2026 14:21:28 +0800 Subject: [PATCH 453/591] opt: support center scroller stack in centerwin dispatch --- src/dispatch/bind_define.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index 02680789..2d40c22b 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -769,10 +769,13 @@ int32_t centerwin(const Arg *arg) { if (!is_scroller_layout(selmon)) return 0; + Client *stack_head = get_scroll_stack_head(c); if (selmon->pertag->ltidxs[selmon->pertag->curtag]->id == SCROLLER) { - c->geom.x = selmon->w.x + (selmon->w.width - c->geom.width) / 2; + stack_head->geom.x = + selmon->w.x + (selmon->w.width - stack_head->geom.width) / 2; } else { - c->geom.y = selmon->w.y + (selmon->w.height - c->geom.height) / 2; + stack_head->geom.y = + selmon->w.y + (selmon->w.height - stack_head->geom.height) / 2; } arrange(selmon, false, false); From fc13b0ff15973c66e24ab4a06a31748070af2a51 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Mon, 19 Jan 2026 22:18:05 +0800 Subject: [PATCH 454/591] opt: optimize global client focus logic --- src/layout/arrange.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/layout/arrange.h b/src/layout/arrange.h index 7f81e5bb..6ff1dd25 100644 --- a/src/layout/arrange.h +++ b/src/layout/arrange.h @@ -692,8 +692,10 @@ arrange(Monitor *m, bool want_animation, bool from_view) { if (c->mon == m && (c->isglobal || c->isunglobal)) { c->tags = m->tagset[m->seltags]; - if (c->mon->sel == NULL) - focusclient(c, 0); + } + + if (from_view && m->sel == NULL && c->isglobal && VISIBLEON(c, m)) { + focusclient(c, 1); } if (VISIBLEON(c, m)) { From 04ac4bf99c0682f5a1615adec1b568d55468f547 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Tue, 20 Jan 2026 11:28:33 +0800 Subject: [PATCH 455/591] opt: find same stack first in direction find --- src/fetch/client.h | 104 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 96 insertions(+), 8 deletions(-) diff --git a/src/fetch/client.h b/src/fetch/client.h index 6294e171..e843d691 100644 --- a/src/fetch/client.h +++ b/src/fetch/client.h @@ -215,6 +215,27 @@ Client *find_client_by_direction(Client *tc, const Arg *arg, bool findfloating, } } } + if (!tempFocusClients) { + for (int32_t _i = 0; _i <= last; _i++) { + if (tempClients[_i]->geom.y < sel_y && + tempClients[_i]->mon == tc->mon && + client_is_in_same_stack(tc, tempClients[_i], NULL)) { + int32_t dis_x = tempClients[_i]->geom.x - sel_x; + int32_t dis_y = tempClients[_i]->geom.y - sel_y; + int64_t tmp_distance = + dis_x * dis_x + dis_y * dis_y; // 计算距离 + if (tmp_distance < distance) { + distance = tmp_distance; + tempFocusClients = tempClients[_i]; + } + if (tempClients[_i]->mon == tc->mon && + tmp_distance < same_monitor_distance) { + same_monitor_distance = tmp_distance; + tempSameMonitorFocusClients = tempClients[_i]; + } + } + } + } if (!tempFocusClients) { for (int32_t _i = 0; _i <= last; _i++) { if (tempClients[_i]->geom.y < sel_y) { @@ -252,6 +273,27 @@ Client *find_client_by_direction(Client *tc, const Arg *arg, bool findfloating, } } } + if (!tempFocusClients) { + for (int32_t _i = 0; _i <= last; _i++) { + if (tempClients[_i]->geom.y > sel_y && + tempClients[_i]->mon == tc->mon && + client_is_in_same_stack(tc, tempClients[_i], NULL)) { + int32_t dis_x = tempClients[_i]->geom.x - sel_x; + int32_t dis_y = tempClients[_i]->geom.y - sel_y; + int64_t tmp_distance = + dis_x * dis_x + dis_y * dis_y; // 计算距离 + if (tmp_distance < distance) { + distance = tmp_distance; + tempFocusClients = tempClients[_i]; + } + if (tempClients[_i]->mon == tc->mon && + tmp_distance < same_monitor_distance) { + same_monitor_distance = tmp_distance; + tempSameMonitorFocusClients = tempClients[_i]; + } + } + } + } if (!tempFocusClients) { for (int32_t _i = 0; _i <= last; _i++) { if (tempClients[_i]->geom.y > sel_y) { @@ -289,6 +331,27 @@ Client *find_client_by_direction(Client *tc, const Arg *arg, bool findfloating, } } } + if (!tempFocusClients) { + for (int32_t _i = 0; _i <= last; _i++) { + if (tempClients[_i]->geom.x < sel_x && + tempClients[_i]->mon == tc->mon && + client_is_in_same_stack(tc, tempClients[_i], NULL)) { + int32_t dis_x = tempClients[_i]->geom.x - sel_x; + int32_t dis_y = tempClients[_i]->geom.y - sel_y; + int64_t tmp_distance = + dis_x * dis_x + dis_y * dis_y; // 计算距离 + if (tmp_distance < distance) { + distance = tmp_distance; + tempFocusClients = tempClients[_i]; + } + if (tempClients[_i]->mon == tc->mon && + tmp_distance < same_monitor_distance) { + same_monitor_distance = tmp_distance; + tempSameMonitorFocusClients = tempClients[_i]; + } + } + } + } if (!tempFocusClients) { for (int32_t _i = 0; _i <= last; _i++) { if (tempClients[_i]->geom.x < sel_x) { @@ -326,6 +389,27 @@ Client *find_client_by_direction(Client *tc, const Arg *arg, bool findfloating, } } } + if (!tempFocusClients) { + for (int32_t _i = 0; _i <= last; _i++) { + if (tempClients[_i]->geom.x > sel_x && + tempClients[_i]->mon == tc->mon && + client_is_in_same_stack(tc, tempClients[_i], NULL)) { + int32_t dis_x = tempClients[_i]->geom.x - sel_x; + int32_t dis_y = tempClients[_i]->geom.y - sel_y; + int64_t tmp_distance = + dis_x * dis_x + dis_y * dis_y; // 计算距离 + if (tmp_distance < distance) { + distance = tmp_distance; + tempFocusClients = tempClients[_i]; + } + if (tempClients[_i]->mon == tc->mon && + tmp_distance < same_monitor_distance) { + same_monitor_distance = tmp_distance; + tempSameMonitorFocusClients = tempClients[_i]; + } + } + } + } if (!tempFocusClients) { for (int32_t _i = 0; _i <= last; _i++) { if (tempClients[_i]->geom.x > sel_x) { @@ -453,6 +537,10 @@ bool client_only_in_one_tag(Client *c) { Client *get_scroll_stack_head(Client *c) { Client *scroller_stack_head = c; + + if (!scroller_stack_head) + return NULL; + while (scroller_stack_head->prev_in_stack) { scroller_stack_head = scroller_stack_head->prev_in_stack; } @@ -473,8 +561,8 @@ bool client_is_in_same_stack(Client *sc, Client *tc, Client *fc) { if (id == SCROLLER || id == VERTICAL_SCROLLER) { Client *source_stack_head = get_scroll_stack_head(sc); Client *target_stack_head = get_scroll_stack_head(tc); - Client *fc_head = get_scroll_stack_head(fc); - if (fc->prev_in_stack && fc_head == source_stack_head) + Client *fc_head = fc ? get_scroll_stack_head(fc) : NULL; + if (fc && fc->prev_in_stack && fc_head == source_stack_head) return false; if (source_stack_head == target_stack_head) return true; @@ -484,23 +572,23 @@ bool client_is_in_same_stack(Client *sc, Client *tc, Client *fc) { if (id == TILE || id == VERTICAL_TILE || id == DECK || id == VERTICAL_DECK || id == RIGHT_TILE) { - if (!fc->ismaster) + if (fc && !fc->ismaster) return false; - else + else if (!sc->ismaster) return true; } if (id == TGMIX) { - if (!fc->ismaster) + if (fc && !fc->ismaster) return false; - if (sc->mon->visible_tiling_clients <= 3) + if (!sc->ismaster && sc->mon->visible_tiling_clients <= 3) return true; } if (id == CENTER_TILE) { - if (!fc->ismaster) + if (fc && !fc->ismaster) return false; - if (sc->geom.x == tc->geom.x) + if (!sc->ismaster && sc->geom.x == tc->geom.x) return true; else return false; From 5942c5d80783c78f0c53f19891d6c4354f54655e Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Tue, 20 Jan 2026 13:50:43 +0800 Subject: [PATCH 456/591] opt: only disable animation for resizewin tiling window --- src/dispatch/bind_define.h | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index 2d40c22b..95d365c8 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -383,9 +383,6 @@ int32_t movewin(const Arg *arg) { if (!c->isfloating) togglefloating(NULL); - int32_t animations_state_backup = animations; - animations = 0; - switch (arg->ui) { case NUM_TYPE_MINUS: c->geom.x -= arg->i; @@ -413,7 +410,6 @@ int32_t movewin(const Arg *arg) { c->iscustomsize = 1; c->float_geom = c->geom; resize(c, c->geom, 0); - animations = animations_state_backup; return 0; } @@ -431,7 +427,8 @@ int32_t resizewin(const Arg *arg) { return 0; int32_t animations_state_backup = animations; - animations = 0; + if (!c->isfloating) + animations = 0; if (ISTILED(c)) { switch (arg->ui) { @@ -585,9 +582,6 @@ int32_t smartmovewin(const Arg *arg) { nx = c->geom.x; ny = c->geom.y; - int32_t animations_state_backup = animations; - animations = 0; - switch (arg->i) { case UP: tar = -99999; @@ -674,7 +668,6 @@ int32_t smartmovewin(const Arg *arg) { .x = nx, .y = ny, .width = c->geom.width, .height = c->geom.height}; c->iscustomsize = 1; resize(c, c->float_geom, 1); - animations = animations_state_backup; return 0; } @@ -690,9 +683,6 @@ int32_t smartresizewin(const Arg *arg) { nw = c->geom.width; nh = c->geom.height; - int32_t animations_state_backup = animations; - animations = 0; - switch (arg->i) { case UP: nh -= selmon->w.height / 8; @@ -748,7 +738,6 @@ int32_t smartresizewin(const Arg *arg) { .x = c->geom.x, .y = c->geom.y, .width = nw, .height = nh}; c->iscustomsize = 1; resize(c, c->float_geom, 1); - animations = animations_state_backup; return 0; } From 1124d477861f60d436d15f2d84ae5d0c7ced9091 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Tue, 20 Jan 2026 14:25:07 +0800 Subject: [PATCH 457/591] fix: fix exchange client error when not in scroller layout --- src/mango.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/mango.c b/src/mango.c index 83f31cc6..3a2331df 100644 --- a/src/mango.c +++ b/src/mango.c @@ -4444,7 +4444,8 @@ void exchange_two_client(Client *c1, Client *c2) { tmp2_prev_in_stack->next_in_stack = c1; if (tmp1_next_in_stack) tmp1_next_in_stack->prev_in_stack = c2; - } else if (c1->prev_in_stack || c2->prev_in_stack) { + } else if (is_scroller_layout(c1->mon) && + (c1->prev_in_stack || c2->prev_in_stack)) { Client *c1head = get_scroll_stack_head(c1); Client *c2head = get_scroll_stack_head(c2); exchange_two_client(c1head, c2head); From d78526d1e92acc3c926c1da26d27708f500875aa Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Tue, 20 Jan 2026 20:33:32 +0800 Subject: [PATCH 458/591] bump version to 0.11.0 --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 83b95135..d71eb597 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('mango', ['c', 'cpp'], - version : '0.10.10', + version : '0.11.0', ) subdir('protocols') From 49921eadfa251641379c2f2cd824034eb7075e2f Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Wed, 21 Jan 2026 13:43:40 +0800 Subject: [PATCH 459/591] feat: add drag_corner drag_warp_cursor --- src/config/parse_config.h | 10 ++++++++++ src/config/preset.h | 4 +++- src/dispatch/bind_define.h | 30 ++++++++++++++++++++++++++---- src/mango.c | 32 ++++++++++++++++++++++++++------ 4 files changed, 65 insertions(+), 11 deletions(-) diff --git a/src/config/parse_config.h b/src/config/parse_config.h index b2535b15..15857ae4 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -243,6 +243,8 @@ typedef struct { int32_t idleinhibit_ignore_visible; int32_t sloppyfocus; int32_t warpcursor; + int32_t drag_corner; + int32_t drag_warp_cursor; /* keyboard */ int32_t repeat_rate; @@ -1475,6 +1477,10 @@ void parse_option(Config *config, char *key, char *value) { config->sloppyfocus = atoi(value); } else if (strcmp(key, "warpcursor") == 0) { config->warpcursor = atoi(value); + } else if (strcmp(key, "drag_corner") == 0) { + config->drag_corner = atoi(value); + } else if (strcmp(key, "drag_warp_cursor") == 0) { + config->drag_warp_cursor = atoi(value); } else if (strcmp(key, "smartgaps") == 0) { config->smartgaps = atoi(value); } else if (strcmp(key, "repeat_rate") == 0) { @@ -2757,6 +2763,8 @@ void override_config(void) { CLAMP_INT(config.idleinhibit_ignore_visible, 0, 1); sloppyfocus = CLAMP_INT(config.sloppyfocus, 0, 1); warpcursor = CLAMP_INT(config.warpcursor, 0, 1); + drag_corner = CLAMP_INT(config.drag_corner, 0, 4); + drag_warp_cursor = CLAMP_INT(config.drag_warp_cursor, 0, 1); focus_cross_monitor = CLAMP_INT(config.focus_cross_monitor, 0, 1); exchange_cross_monitor = CLAMP_INT(config.exchange_cross_monitor, 0, 1); scratchpad_cross_monitor = CLAMP_INT(config.scratchpad_cross_monitor, 0, 1); @@ -2954,6 +2962,8 @@ void set_value_default() { config.cursor_hide_timeout = cursor_hide_timeout; config.warpcursor = warpcursor; /* Warp cursor to focused client */ + config.drag_corner = drag_corner; + config.drag_warp_cursor = drag_warp_cursor; config.repeat_rate = repeat_rate; config.repeat_delay = repeat_delay; diff --git a/src/config/preset.h b/src/config/preset.h index 6f3cd891..935ea0c2 100644 --- a/src/config/preset.h +++ b/src/config/preset.h @@ -101,7 +101,9 @@ int32_t overviewgappo = 30; /* overview时 窗口与窗口 缝隙大小 */ * behavior */ float fullscreen_bg[] = {0.1, 0.1, 0.1, 1.0}; -int32_t warpcursor = 1; /* Warp cursor to focused client */ +int32_t warpcursor = 1; +int32_t drag_corner = 3; +int32_t drag_warp_cursor = 1; int32_t xwayland_persistence = 1; /* xwayland persistence */ int32_t syncobj_enable = 0; int32_t adaptive_sync = 0; diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index 95d365c8..f27ed67b 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -338,6 +338,9 @@ int32_t killclient(const Arg *arg) { } int32_t moveresize(const Arg *arg) { + const char *cursors[] = {"nw-resize", "ne-resize", "sw-resize", + "se-resize"}; + if (cursor_mode != CurNormal && cursor_mode != CurPressed) return 0; xytonode(cursor->x, cursor->y, NULL, &grabc, NULL, NULL, NULL); @@ -363,10 +366,29 @@ int32_t moveresize(const Arg *arg) { /* Doesn't work for X11 output - the next absolute motion event * returns the cursor to where it started */ if (grabc->isfloating) { - wlr_cursor_warp_closest(cursor, NULL, - grabc->geom.x + grabc->geom.width, - grabc->geom.y + grabc->geom.height); - wlr_cursor_set_xcursor(cursor, cursor_mgr, "bottom_right_corner"); + rzcorner = drag_corner; + grabcx = (int)round(cursor->x); + grabcy = (int)round(cursor->y); + if (rzcorner == 4) + /* identify the closest corner index */ + rzcorner = (grabcx - grabc->geom.x < + grabc->geom.x + grabc->geom.width - grabcx + ? 0 + : 1) + + (grabcy - grabc->geom.y < + grabc->geom.y + grabc->geom.height - grabcy + ? 0 + : 2); + + if (drag_warp_cursor) { + grabcx = rzcorner & 1 ? grabc->geom.x + grabc->geom.width + : grabc->geom.x; + grabcy = rzcorner & 2 ? grabc->geom.y + grabc->geom.height + : grabc->geom.y; + wlr_cursor_warp_closest(cursor, NULL, grabcx, grabcy); + } + + wlr_cursor_set_xcursor(cursor, cursor_mgr, cursors[rzcorner]); } else { wlr_cursor_set_xcursor(cursor, cursor_mgr, "grab"); } diff --git a/src/mango.c b/src/mango.c index 3a2331df..f61e27f5 100644 --- a/src/mango.c +++ b/src/mango.c @@ -841,6 +841,7 @@ static struct wl_list inputdevices; static struct wl_list keyboard_shortcut_inhibitors; static uint32_t cursor_mode; static Client *grabc; +static int32_t rzcorner; static int32_t grabcx, grabcy; /* client-relative */ static int32_t drag_begin_cursorx, drag_begin_cursory; /* client-relative */ static bool start_drag_window = false; @@ -3988,6 +3989,30 @@ void motionabsolute(struct wl_listener *listener, void *data) { motionnotify(event->time_msec, &event->pointer->base, dx, dy, dx, dy); } +void resize_floating_window(Client *grabc) { + int cdx = (int)round(cursor->x) - grabcx; + int cdy = (int)round(cursor->y) - grabcy; + + cdx = !(rzcorner & 1) && grabc->geom.width - 2 * (int)grabc->bw - cdx < 1 + ? 0 + : cdx; + cdy = !(rzcorner & 2) && grabc->geom.height - 2 * (int)grabc->bw - cdy < 1 + ? 0 + : cdy; + + const struct wlr_box box = { + .x = grabc->geom.x + (rzcorner & 1 ? 0 : cdx), + .y = grabc->geom.y + (rzcorner & 2 ? 0 : cdy), + .width = grabc->geom.width + (rzcorner & 1 ? cdx : -cdx), + .height = grabc->geom.height + (rzcorner & 2 ? cdy : -cdy)}; + + grabc->float_geom = box; + + resize(grabc, box, 1); + grabcx += cdx; + grabcy += cdy; +} + void motionnotify(uint32_t time, struct wlr_input_device *device, double dx, double dy, double dx_unaccel, double dy_unaccel) { double sx = 0, sy = 0, sx_confined, sy_confined; @@ -4065,14 +4090,9 @@ void motionnotify(uint32_t time, struct wlr_input_device *device, double dx, } else if (cursor_mode == CurResize) { if (grabc->isfloating) { grabc->iscustomsize = 1; - grabc->float_geom = (struct wlr_box){ - .x = grabc->geom.x, - .y = grabc->geom.y, - .width = (int32_t)round(cursor->x) - grabc->geom.x, - .height = (int32_t)round(cursor->y) - grabc->geom.y}; if (last_apply_drap_time == 0 || time - last_apply_drap_time > drag_refresh_interval) { - resize(grabc, grabc->float_geom, 1); + resize_floating_window(grabc); last_apply_drap_time = time; } return; From 334bc076a0d0b368efef5626f8e6d4b429133c3f Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sat, 24 Jan 2026 11:43:24 +0800 Subject: [PATCH 460/591] opt: optimize smartgap --- src/fetch/client.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/fetch/client.h b/src/fetch/client.h index e843d691..bf30e175 100644 --- a/src/fetch/client.h +++ b/src/fetch/client.h @@ -12,7 +12,9 @@ bool check_hit_no_border(Client *c) { } } - if (no_border_when_single && c && c->mon && c->mon->visible_clients == 1) { + if (no_border_when_single && c && c->mon && + ((ISSCROLLTILED(c) && c->mon->visible_scroll_tiling_clients == 1) || + c->mon->visible_clients == 1)) { hit_no_border = true; } return hit_no_border; From 0652f99e6e30aaa7e85c6828ba729bf4075a8270 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sat, 24 Jan 2026 12:04:17 +0800 Subject: [PATCH 461/591] opt: change preset config prefer --- src/config/preset.h | 3 +-- src/layout/layout.h | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/config/preset.h b/src/config/preset.h index 935ea0c2..5dea6cb0 100644 --- a/src/config/preset.h +++ b/src/config/preset.h @@ -62,7 +62,7 @@ float scratchpad_height_ratio = 0.9; int32_t scroller_structs = 20; float scroller_default_proportion = 0.9; float scroller_default_proportion_single = 1.0; -int32_t scroller_ignore_proportion_single = 0; +int32_t scroller_ignore_proportion_single = 1; int32_t scroller_focus_center = 0; int32_t scroller_prefer_center = 0; int32_t focus_cross_monitor = 0; @@ -235,4 +235,3 @@ double shadows_blur = 15; int32_t shadows_position_x = 0; int32_t shadows_position_y = 0; float shadowscolor[] = COLOR(0x000000ff); -; diff --git a/src/layout/layout.h b/src/layout/layout.h index 169ab119..f896ac27 100644 --- a/src/layout/layout.h +++ b/src/layout/layout.h @@ -17,8 +17,8 @@ static void tgmix(Monitor *m); Layout overviewlayout = {"󰃇", overview, "overview"}; enum { - SCROLLER, TILE, + SCROLLER, GRID, MONOCLE, DECK, @@ -34,8 +34,8 @@ enum { Layout layouts[] = { // 最少两个,不能删除少于两个 /* symbol arrange function name */ - {"S", scroller, "scroller", SCROLLER}, // 滚动布局 {"T", tile, "tile", TILE}, // 平铺布局 + {"S", scroller, "scroller", SCROLLER}, // 滚动布局 {"G", grid, "grid", GRID}, // 格子布局 {"M", monocle, "monocle", MONOCLE}, // 单屏布局 {"K", deck, "deck", DECK}, // 卡片布局 From f1cca251b8ef2bfce0f5dadbb0d1d609a51bd0ca Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sat, 24 Jan 2026 19:48:43 +0800 Subject: [PATCH 462/591] fix: bordercorlor not update when it is in open animaiton --- src/animation/client.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/animation/client.h b/src/animation/client.h index 849bc10e..3f447277 100644 --- a/src/animation/client.h +++ b/src/animation/client.h @@ -1131,6 +1131,7 @@ bool client_apply_focus_opacity(Client *c) { target_opacity = opacity; } client_set_opacity(c, target_opacity); + client_set_border_color(c, c->opacity_animation.target_border_color); } else if (animations && c->opacity_animation.running) { struct timespec now; From 00de5230393d75d22416c0fbe9c93a6ec5434dea Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sat, 24 Jan 2026 23:02:49 +0800 Subject: [PATCH 463/591] fix: border apply error for smartgap --- src/animation/client.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/animation/client.h b/src/animation/client.h index 3f447277..15a0d164 100644 --- a/src/animation/client.h +++ b/src/animation/client.h @@ -363,7 +363,6 @@ void apply_border(Client *c) { current_corner_location = set_client_corner_location(c); } - // Handle no-border cases if (hit_no_border && smartgaps) { c->bw = 0; c->fake_no_border = true; @@ -981,6 +980,12 @@ void resize(Client *c, struct wlr_box geo, int32_t interact) { c->bw = 0; } + bool hit_no_border = check_hit_no_border(c); + if (hit_no_border && smartgaps) { + c->bw = 0; + c->fake_no_border = true; + } + // c->geom 是真实的窗口大小和位置,跟过度的动画无关,用于计算布局 c->configure_serial = client_set_size(c, c->geom.width - 2 * c->bw, c->geom.height - 2 * c->bw); From 05010a1114bb66cb7a3d0df0f1939e00c338def2 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Mon, 26 Jan 2026 18:35:08 +0800 Subject: [PATCH 464/591] fix: crash when some qt app commit a null surface --- src/mango.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/mango.c b/src/mango.c index f61e27f5..e285a897 100644 --- a/src/mango.c +++ b/src/mango.c @@ -2443,12 +2443,12 @@ void commitpopup(struct wl_listener *listener, void *data) { struct wlr_box box; int32_t type = -1; - if (!popup->base->initial_commit) - return; + if (!popup || !popup->base->initial_commit) + goto commitpopup_listen_free; type = toplevel_from_wlr_surface(popup->base->surface, &c, &l); - if (!popup->parent || type < 0) - return; + if (!popup->parent || !popup->parent->data || type < 0) + goto commitpopup_listen_free; wlr_scene_node_raise_to_top(popup->parent->data); @@ -2456,13 +2456,14 @@ void commitpopup(struct wl_listener *listener, void *data) { wlr_scene_xdg_surface_create(popup->parent->data, popup->base); if ((l && !l->mon) || (c && !c->mon)) { wlr_xdg_popup_destroy(popup); - return; + goto commitpopup_listen_free; } box = type == LayerShell ? l->mon->m : c->mon->w; box.x -= (type == LayerShell ? l->scene->node.x : c->geom.x); box.y -= (type == LayerShell ? l->scene->node.y : c->geom.y); wlr_xdg_popup_unconstrain_from_box(popup, &box); +commitpopup_listen_free: wl_list_remove(&listener->link); free(listener); } From 6624d80522b512a381e88315787e1d5ed8bcdd19 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Tue, 27 Jan 2026 14:45:28 +0800 Subject: [PATCH 465/591] break change: new monitorrule format --- src/config/parse_config.h | 237 ++++++++++++++++++++------------------ src/layout/horizontal.h | 9 +- src/layout/vertical.h | 9 +- src/mango.c | 42 +++---- 4 files changed, 149 insertions(+), 148 deletions(-) diff --git a/src/config/parse_config.h b/src/config/parse_config.h index 15857ae4..f94e6794 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -101,15 +101,13 @@ typedef struct { } ConfigWinRule; typedef struct { - const char *name; // 显示器名称 - float mfact; // 主区域比例 - int32_t nmaster; // 主区域窗口数量 - const char *layout; // 布局名称(字符串) - int32_t rr; // 旋转和翻转(假设为整数) - float scale; // 显示器缩放比例 - int32_t x, y; // 显示器位置 - int32_t width, height; // 显示器分辨率 - float refresh; // 刷新率 + const char *name; // Monitor name + int32_t rr; // Rotate and flip (assume integer) + float scale; // Monitor scale factor + int32_t x, y; // Monitor position + int32_t width, height; // Monitor resolution + float refresh; // Refresh rate + int32_t vrr; // variable refresh rate } ConfigMonitorRule; // 修改后的宏定义 @@ -156,9 +154,11 @@ typedef struct { } GestureBinding; typedef struct { - int32_t id; // 标签ID (1-9) - char *layout_name; // 布局名称 + int32_t id; + char *layout_name; char *monitor_name; + float mfact; + int32_t nmaster; int32_t no_render_border; int32_t no_hide; } ConfigTagRule; @@ -1605,6 +1605,66 @@ void parse_option(Config *config, char *key, char *value) { } else { convert_hex_to_rgba(config->overlaycolor, color); } + } else if (strcmp(key, "monitorrule") == 0) { + config->monitor_rules = + realloc(config->monitor_rules, (config->monitor_rules_count + 1) * + sizeof(ConfigMonitorRule)); + if (!config->monitor_rules) { + fprintf(stderr, + "Error: Failed to allocate memory for monitor rules\n"); + return; + } + + ConfigMonitorRule *rule = + &config->monitor_rules[config->monitor_rules_count]; + memset(rule, 0, sizeof(ConfigMonitorRule)); + + // 设置默认值 + rule->name = NULL; + rule->rr = 0; + rule->scale = 1.0f; + rule->x = INT32_MAX; + rule->y = INT32_MAX; + rule->width = -1; + rule->height = -1; + rule->refresh = 0.0f; + rule->vrr = 0; + + char *token = strtok(value, ","); + while (token != NULL) { + char *colon = strchr(token, ':'); + if (colon != NULL) { + *colon = '\0'; + char *key = token; + char *val = colon + 1; + + trim_whitespace(key); + trim_whitespace(val); + + if (strcmp(key, "name") == 0) { + rule->name = strdup(val); + } else if (strcmp(key, "rr") == 0) { + rule->rr = CLAMP_INT(atoi(val), 0, 7); + } else if (strcmp(key, "scale") == 0) { + rule->scale = CLAMP_FLOAT(atof(val), 0.001f, 1000.0f); + } else if (strcmp(key, "x") == 0) { + rule->x = atoi(val); + } else if (strcmp(key, "y") == 0) { + rule->y = atoi(val); + } else if (strcmp(key, "width") == 0) { + rule->width = CLAMP_INT(atoi(val), 1, INT32_MAX); + } else if (strcmp(key, "height") == 0) { + rule->height = CLAMP_INT(atoi(val), 1, INT32_MAX); + } else if (strcmp(key, "refresh") == 0) { + rule->refresh = CLAMP_FLOAT(atof(val), 0.001f, 1000.0f); + } else if (strcmp(key, "vrr") == 0) { + rule->vrr = CLAMP_INT(atoi(val), 0, 1); + } + } + token = strtok(NULL, ","); + } + + config->monitor_rules_count++; } else if (strcmp(key, "tagrule") == 0) { config->tag_rules = realloc(config->tag_rules, @@ -1621,6 +1681,10 @@ void parse_option(Config *config, char *key, char *value) { rule->id = 0; rule->layout_name = NULL; rule->monitor_name = NULL; + rule->nmaster = 0; + rule->mfact = 0.0f; + rule->no_render_border = 0; + rule->no_hide = 0; char *token = strtok(value, ","); while (token != NULL) { @@ -1643,6 +1707,10 @@ void parse_option(Config *config, char *key, char *value) { rule->no_render_border = 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) { + rule->nmaster = CLAMP_INT(atoi(val), 1, 99); + } else if (strcmp(key, "mfact") == 0) { + rule->mfact = CLAMP_FLOAT(atof(val), 0.1f, 0.9f); } } token = strtok(NULL, ","); @@ -1871,75 +1939,6 @@ void parse_option(Config *config, char *key, char *value) { token = strtok(NULL, ","); } config->window_rules_count++; - } else if (strcmp(key, "monitorrule") == 0) { - config->monitor_rules = - realloc(config->monitor_rules, (config->monitor_rules_count + 1) * - sizeof(ConfigMonitorRule)); - if (!config->monitor_rules) { - fprintf(stderr, - "Error: Failed to allocate memory for monitor rules\n"); - return; - } - - ConfigMonitorRule *rule = - &config->monitor_rules[config->monitor_rules_count]; - memset(rule, 0, sizeof(ConfigMonitorRule)); - - // 临时存储每个字段的原始字符串 - char raw_name[256], raw_layout[256]; - char raw_mfact[256], raw_nmaster[256], raw_rr[256]; - char raw_scale[256], raw_x[256], raw_y[256], raw_width[256], - raw_height[256], raw_refresh[256]; - - // 先读取所有字段为字符串 - int32_t parsed = - sscanf(value, - "%255[^,],%255[^,],%255[^,],%255[^,],%255[^,],%255[" - "^,],%255[^,],%255[^,],%255[^,],%255[^,],%255s", - raw_name, raw_mfact, raw_nmaster, raw_layout, raw_rr, - raw_scale, raw_x, raw_y, raw_width, raw_height, raw_refresh); - - if (parsed == 11) { - // 修剪每个字段的空格 - trim_whitespace(raw_name); - trim_whitespace(raw_mfact); - trim_whitespace(raw_nmaster); - trim_whitespace(raw_layout); - trim_whitespace(raw_rr); - trim_whitespace(raw_scale); - trim_whitespace(raw_x); - trim_whitespace(raw_y); - trim_whitespace(raw_width); - trim_whitespace(raw_height); - trim_whitespace(raw_refresh); - - // 转换修剪后的字符串为特定类型 - rule->name = strdup(raw_name); - rule->layout = strdup(raw_layout); - rule->mfact = atof(raw_mfact); - rule->nmaster = atoi(raw_nmaster); - rule->rr = atoi(raw_rr); - rule->scale = atof(raw_scale); - rule->x = atoi(raw_x); - rule->y = atoi(raw_y); - rule->width = atoi(raw_width); - rule->height = atoi(raw_height); - rule->refresh = atof(raw_refresh); - - if (!rule->name || !rule->layout) { - if (rule->name) - free((void *)rule->name); - if (rule->layout) - free((void *)rule->layout); - fprintf(stderr, - "Error: Failed to allocate memory for monitor rule\n"); - return; - } - - config->monitor_rules_count++; - } else { - fprintf(stderr, "Error: Invalid monitorrule format: %s\n", value); - } } else if (strncmp(key, "env", 3) == 0) { char env_type[256], env_value[256]; @@ -2483,18 +2482,6 @@ void free_config(void) { config.window_rules_count = 0; } - // 释放 monitor_rules - if (config.monitor_rules) { - for (int32_t i = 0; i < config.monitor_rules_count; i++) { - ConfigMonitorRule *rule = &config.monitor_rules[i]; - free((void *)rule->name); - free((void *)rule->layout); - } - free(config.monitor_rules); - config.monitor_rules = NULL; - config.monitor_rules_count = 0; - } - // 释放 key_bindings if (config.key_bindings) { for (i = 0; i < config.key_bindings_count; i++) { @@ -2613,6 +2600,17 @@ void free_config(void) { config.tag_rules_count = 0; } + // 释放 monitor_rules + if (config.monitor_rules) { + for (int32_t i = 0; i < config.monitor_rules_count; i++) { + if (config.monitor_rules[i].name) + free((void *)config.monitor_rules[i].name); + } + free(config.monitor_rules); + config.monitor_rules = NULL; + config.monitor_rules_count = 0; + } + // 释放 layer_rules if (config.layer_rules) { for (int32_t i = 0; i < config.layer_rules_count; i++) { @@ -3164,7 +3162,8 @@ void reset_blur_params(void) { void reapply_monitor_rules(void) { ConfigMonitorRule *mr; Monitor *m = NULL; - int32_t ji, jk; + int32_t ji, vrr; + int32_t mx, my; struct wlr_output_state state; struct wlr_output_mode *internal_mode = NULL; wlr_output_state_init(&state); @@ -3179,20 +3178,11 @@ void reapply_monitor_rules(void) { break; mr = &config.monitor_rules[ji]; - if (!mr->name || regex_match(mr->name, m->wlr_output->name)) { + if (regex_match(mr->name, m->wlr_output->name)) { - m->mfact = mr->mfact; - m->nmaster = mr->nmaster; - m->m.x = mr->x; - m->m.y = mr->y; - - if (mr->layout) { - for (jk = 0; jk < LENGTH(layouts); jk++) { - if (strcmp(layouts[jk].name, mr->layout) == 0) { - m->lt = &layouts[jk]; - } - } - } + 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; if (mr->width > 0 && mr->height > 0 && mr->refresh > 0) { internal_mode = get_nearest_output_mode( @@ -3206,17 +3196,16 @@ void reapply_monitor_rules(void) { } } + if (vrr) { + enable_adaptive_sync(m, &state); + } + wlr_output_state_set_scale(&state, mr->scale); wlr_output_state_set_transform(&state, mr->rr); - wlr_output_layout_add(output_layout, m->wlr_output, mr->x, - mr->y); + wlr_output_layout_add(output_layout, m->wlr_output, mx, my); } } - if (adaptive_sync) { - enable_adaptive_sync(m, &state); - } - wlr_output_commit_state(m->wlr_output, &state); wlr_output_state_finish(&state); updatemons(NULL, NULL); @@ -3319,6 +3308,12 @@ void reapply_master(void) { void parse_tagrule(Monitor *m) { int32_t i, jk; ConfigTagRule tr; + Client *c = NULL; + + for (i = 0; i <= LENGTH(tags); i++) { + m->pertag->nmasters[i] = default_nmaster; + m->pertag->mfacts[i] = default_mfact; + } for (i = 0; i < config.tag_rules_count; i++) { @@ -3335,7 +3330,23 @@ void parse_tagrule(Monitor *m) { } } - m->pertag->no_hide[tr.id] = tr.no_hide; + if (tr.no_hide >= 0) + m->pertag->no_hide[tr.id] = tr.no_hide; + if (tr.nmaster >= 1) + m->pertag->nmasters[tr.id] = tr.nmaster; + if (tr.mfact > 0.0f) + m->pertag->mfacts[tr.id] = tr.mfact; + if (tr.no_render_border >= 0) + m->pertag->no_render_border[tr.id] = tr.no_render_border; + } + } + + for (i = 1; i <= LENGTH(tags); i++) { + wl_list_for_each(c, &clients, link) { + if ((c->tags & (1 << (i - 1)) & TAGMASK) && ISTILED(c)) { + if (m->pertag->mfacts[i] > 0.0f) + c->master_mfact_per = m->pertag->mfacts[i]; + } } } } diff --git a/src/layout/horizontal.h b/src/layout/horizontal.h index 87b6033c..e1a335d1 100644 --- a/src/layout/horizontal.h +++ b/src/layout/horizontal.h @@ -117,6 +117,7 @@ void deck(Monitor *m) { Client *c = NULL; Client *fc = NULL; float mfact; + uint32_t nmasters = m->pertag->nmasters[m->pertag->curtag]; int32_t cur_gappih = enablegaps ? m->gappih : 0; int32_t cur_gappoh = enablegaps ? m->gappoh : 0; @@ -142,8 +143,8 @@ void deck(Monitor *m) { : m->pertag->mfacts[m->pertag->curtag]; // Calculate master width including outer gaps - if (n > m->nmaster) - mw = m->nmaster ? round((m->w.width - 2 * cur_gappoh) * mfact) : 0; + if (n > nmasters) + mw = nmasters ? round((m->w.width - 2 * cur_gappoh) * mfact) : 0; else mw = m->w.width - 2 * cur_gappoh; @@ -151,7 +152,7 @@ void deck(Monitor *m) { wl_list_for_each(c, &clients, link) { if (!VISIBLEON(c, m) || !ISTILED(c)) continue; - if (i < m->nmaster) { + if (i < nmasters) { c->master_mfact_per = mfact; // Master area clients resize( @@ -160,7 +161,7 @@ void deck(Monitor *m) { .y = m->w.y + cur_gappov + my, .width = mw, .height = (m->w.height - 2 * cur_gappov - my) / - (MIN(n, m->nmaster) - i)}, + (MIN(n, nmasters) - i)}, 0); my += c->geom.height; } else { diff --git a/src/layout/vertical.h b/src/layout/vertical.h index 2c2dc661..f7bd442c 100644 --- a/src/layout/vertical.h +++ b/src/layout/vertical.h @@ -110,6 +110,7 @@ void vertical_deck(Monitor *m) { Client *c = NULL; Client *fc = NULL; float mfact; + uint32_t nmasters = m->pertag->nmasters[m->pertag->curtag]; int32_t cur_gappiv = enablegaps ? m->gappiv : 0; int32_t cur_gappoh = enablegaps ? m->gappoh : 0; @@ -134,8 +135,8 @@ void vertical_deck(Monitor *m) { mfact = fc->master_mfact_per > 0.0f ? fc->master_mfact_per : m->pertag->mfacts[m->pertag->curtag]; - if (n > m->nmaster) - mh = m->nmaster ? round((m->w.height - 2 * cur_gappov) * mfact) : 0; + if (n > nmasters) + mh = nmasters ? round((m->w.height - 2 * cur_gappov) * mfact) : 0; else mh = m->w.height - 2 * cur_gappov; @@ -143,13 +144,13 @@ void vertical_deck(Monitor *m) { wl_list_for_each(c, &clients, link) { if (!VISIBLEON(c, m) || !ISTILED(c)) continue; - if (i < m->nmaster) { + if (i < nmasters) { resize( c, (struct wlr_box){.x = m->w.x + cur_gappoh + mx, .y = m->w.y + cur_gappov, .width = (m->w.width - 2 * cur_gappoh - mx) / - (MIN(n, m->nmaster) - i), + (MIN(n, nmasters) - i), .height = mh}, 0); mx += c->geom.width; diff --git a/src/mango.c b/src/mango.c index e285a897..ed4e12a8 100644 --- a/src/mango.c +++ b/src/mango.c @@ -500,11 +500,8 @@ struct Monitor { struct wlr_box m; /* monitor area, layout-relative */ struct wlr_box w; /* window area, layout-relative */ struct wl_list layers[4]; /* LayerSurface::link */ - const Layout *lt; uint32_t seltags; uint32_t tagset[2]; - double mfact; - int32_t nmaster; struct wl_list dwl_ipc_outputs; int32_t gappih; /* horizontal gap between windows */ @@ -898,6 +895,7 @@ struct Pertag { 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 */ const Layout *ltidxs[LENGTH(tags) + 1]; /* matrix of tags and layouts indexes */ }; @@ -2667,7 +2665,7 @@ void createmon(struct wl_listener *listener, void *data) { struct wlr_output *wlr_output = data; const ConfigMonitorRule *r; uint32_t i; - int32_t ji, jk; + int32_t ji, vrr; struct wlr_output_state state; Monitor *m = NULL; struct wlr_output_mode *internal_mode = NULL; @@ -2703,30 +2701,19 @@ void createmon(struct wl_listener *listener, void *data) { m->sel = NULL; m->is_in_hotarea = 0; float scale = 1; - m->mfact = default_mfact; - m->nmaster = default_nmaster; enum wl_output_transform rr = WL_OUTPUT_TRANSFORM_NORMAL; wlr_output_state_set_scale(&state, scale); wlr_output_state_set_transform(&state, rr); - m->lt = &layouts[0]; for (ji = 0; ji < config.monitor_rules_count; ji++) { if (config.monitor_rules_count < 1) break; r = &config.monitor_rules[ji]; - if (!r->name || regex_match(r->name, wlr_output->name)) { - m->mfact = r->mfact; - m->nmaster = r->nmaster; - m->m.x = r->x; - m->m.y = r->y; - if (r->layout) { - for (jk = 0; jk < LENGTH(layouts); jk++) { - if (strcmp(layouts[jk].name, r->layout) == 0) { - m->lt = &layouts[jk]; - } - } - } + if (regex_match(r->name, wlr_output->name)) { + m->m.x = r->x == INT32_MAX ? INT32_MAX : r->x; + m->m.y = r->y == INT32_MAX ? INT32_MAX : r->y; + vrr = r->vrr >= 0 ? r->vrr : 0; scale = r->scale; rr = r->rr; @@ -2743,6 +2730,11 @@ void createmon(struct wl_listener *listener, void *data) { (int32_t)roundf(r->refresh * 1000)); } } + + if (vrr) { + enable_adaptive_sync(m, &state); + } + wlr_output_state_set_scale(&state, r->scale); wlr_output_state_set_transform(&state, r->rr); break; @@ -2757,10 +2749,6 @@ void createmon(struct wl_listener *listener, void *data) { wlr_output_state_set_mode(&state, wlr_output_preferred_mode(wlr_output)); - if (adaptive_sync) { - enable_adaptive_sync(m, &state); - } - /* Set up event listeners */ LISTEN(&wlr_output->events.frame, &m->frame, rendermon); LISTEN(&wlr_output->events.destroy, &m->destroy, cleanupmon); @@ -2785,9 +2773,9 @@ void createmon(struct wl_listener *listener, void *data) { } for (i = 0; i <= LENGTH(tags); i++) { - m->pertag->nmasters[i] = m->nmaster; - m->pertag->mfacts[i] = m->mfact; - m->pertag->ltidxs[i] = m->lt; + m->pertag->nmasters[i] = default_nmaster; + m->pertag->mfacts[i] = default_mfact; + m->pertag->ltidxs[i] = &layouts[0]; } // apply tag rule @@ -2809,7 +2797,7 @@ void createmon(struct wl_listener *listener, void *data) { * output (such as DPI, scale factor, manufacturer, etc). */ m->scene_output = wlr_scene_output_create(scene, wlr_output); - if (m->m.x == -1 && m->m.y == -1) + if (m->m.x == INT32_MAX || m->m.y == INT32_MAX) wlr_output_layout_add_auto(output_layout, wlr_output); else wlr_output_layout_add(output_layout, wlr_output, m->m.x, m->m.y); From 2e6e23633e90c52fcf5fe3af1910326918f7baf0 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Tue, 27 Jan 2026 16:20:45 +0800 Subject: [PATCH 466/591] break change: remove useless option adaptive_sync --- src/config/parse_config.h | 5 ----- src/config/preset.h | 1 - 2 files changed, 6 deletions(-) diff --git a/src/config/parse_config.h b/src/config/parse_config.h index f94e6794..81eda9dd 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -346,7 +346,6 @@ typedef struct { int32_t single_scratchpad; int32_t xwayland_persistence; int32_t syncobj_enable; - int32_t adaptive_sync; int32_t allow_tearing; int32_t allow_shortcuts_inhibit; int32_t allow_lock_transparent; @@ -1278,8 +1277,6 @@ void parse_option(Config *config, char *key, char *value) { config->xwayland_persistence = atoi(value); } else if (strcmp(key, "syncobj_enable") == 0) { config->syncobj_enable = atoi(value); - } else if (strcmp(key, "adaptive_sync") == 0) { - config->adaptive_sync = atoi(value); } else if (strcmp(key, "allow_tearing") == 0) { config->allow_tearing = atoi(value); } else if (strcmp(key, "allow_shortcuts_inhibit") == 0) { @@ -2750,7 +2747,6 @@ void override_config(void) { // 杂项设置 xwayland_persistence = CLAMP_INT(config.xwayland_persistence, 0, 1); syncobj_enable = CLAMP_INT(config.syncobj_enable, 0, 1); - adaptive_sync = CLAMP_INT(config.adaptive_sync, 0, 1); allow_tearing = CLAMP_INT(config.allow_tearing, 0, 2); allow_shortcuts_inhibit = CLAMP_INT(config.allow_shortcuts_inhibit, 0, 1); allow_lock_transparent = CLAMP_INT(config.allow_lock_transparent, 0, 1); @@ -2937,7 +2933,6 @@ void set_value_default() { config.single_scratchpad = single_scratchpad; config.xwayland_persistence = xwayland_persistence; config.syncobj_enable = syncobj_enable; - config.adaptive_sync = adaptive_sync; config.allow_tearing = allow_tearing; config.allow_shortcuts_inhibit = allow_shortcuts_inhibit; config.allow_lock_transparent = allow_lock_transparent; diff --git a/src/config/preset.h b/src/config/preset.h index 5dea6cb0..c8474dda 100644 --- a/src/config/preset.h +++ b/src/config/preset.h @@ -106,7 +106,6 @@ int32_t drag_corner = 3; int32_t drag_warp_cursor = 1; int32_t xwayland_persistence = 1; /* xwayland persistence */ int32_t syncobj_enable = 0; -int32_t adaptive_sync = 0; int32_t allow_lock_transparent = 0; double drag_refresh_interval = 16.0; int32_t allow_tearing = TEARING_DISABLED; From 30692f6da035b69a17ef59c48b1f6a4e1cb4c4ba Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Tue, 27 Jan 2026 19:02:16 +0800 Subject: [PATCH 467/591] feat: add option hotarea_corner --- src/config/parse_config.h | 9 ++++-- src/config/preset.h | 5 ++-- src/mango.c | 58 ++++++++++++++++++++++++++++++++++----- 3 files changed, 61 insertions(+), 11 deletions(-) diff --git a/src/config/parse_config.h b/src/config/parse_config.h index 81eda9dd..c3458365 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -232,6 +232,7 @@ typedef struct { int32_t center_when_single_stack; uint32_t hotarea_size; + uint32_t hotarea_corner; uint32_t enable_hotarea; uint32_t ov_tab_mode; int32_t overviewgappi; @@ -1452,6 +1453,8 @@ void parse_option(Config *config, char *key, char *value) { config->center_when_single_stack = atoi(value); } else if (strcmp(key, "hotarea_size") == 0) { config->hotarea_size = atoi(value); + } else if (strcmp(key, "hotarea_corner") == 0) { + config->hotarea_corner = atoi(value); } else if (strcmp(key, "enable_hotarea") == 0) { config->enable_hotarea = atoi(value); } else if (strcmp(key, "ov_tab_mode") == 0) { @@ -2739,6 +2742,7 @@ void override_config(void) { // 概述模式设置 hotarea_size = CLAMP_INT(config.hotarea_size, 1, 1000); + hotarea_corner = CLAMP_INT(config.hotarea_corner, 0, 3); enable_hotarea = CLAMP_INT(config.enable_hotarea, 0, 1); ov_tab_mode = CLAMP_INT(config.ov_tab_mode, 0, 1); overviewgappi = CLAMP_INT(config.overviewgappi, 0, 1000); @@ -2901,8 +2905,9 @@ void set_value_default() { config.numlockon = numlockon; // 是否打开右边小键盘 - config.ov_tab_mode = ov_tab_mode; // alt tab切换模式 - config.hotarea_size = hotarea_size; // 热区大小,10x10 + config.ov_tab_mode = ov_tab_mode; // alt tab切换模式 + config.hotarea_size = hotarea_size; // 热区大小,10x10 + config.hotarea_corner = hotarea_corner; config.enable_hotarea = enable_hotarea; // 是否启用鼠标热区 config.smartgaps = smartgaps; /* 1 means no outer gap when there is only one window */ diff --git a/src/config/preset.h b/src/config/preset.h index c8474dda..3d05161f 100644 --- a/src/config/preset.h +++ b/src/config/preset.h @@ -47,8 +47,9 @@ int32_t log_level = WLR_ERROR; uint32_t numlockon = 0; // 是否打开右边小键盘 uint32_t capslock = 0; // 是否启用快捷键 -uint32_t ov_tab_mode = 0; // alt tab切换模式 -uint32_t hotarea_size = 10; // 热区大小,10x10 +uint32_t ov_tab_mode = 0; // alt tab切换模式 +uint32_t hotarea_size = 10; // 热区大小,10x10 +uint32_t hotarea_corner = BOTTOM_LEFT; uint32_t enable_hotarea = 1; // 是否启用鼠标热区 int32_t smartgaps = 0; /* 1 means no outer gap when there is only one window */ int32_t sloppyfocus = 1; /* focus follows mouse */ diff --git a/src/mango.c b/src/mango.c index ed4e12a8..a32be837 100644 --- a/src/mango.c +++ b/src/mango.c @@ -143,6 +143,8 @@ #define BAKED_POINTS_COUNT 256 /* enums */ +enum { TOP_LEFT, TOP_RIGHT, BOTTOM_LEFT, BOTTOM_RIGHT }; + enum { VERTICAL, HORIZONTAL }; enum { SWIPE_UP, SWIPE_DOWN, SWIPE_LEFT, SWIPE_RIGHT }; enum { CurNormal, CurPressed, CurMove, CurResize }; /* cursor */ @@ -1215,17 +1217,59 @@ void toggle_hotarea(int32_t x_root, int32_t y_root) { if (grabc) return; - unsigned hx = selmon->m.x + hotarea_size; - unsigned hy = selmon->m.y + selmon->m.height - hotarea_size; + // 根据热角位置计算不同的热区坐标 + unsigned hx, hy; - if (enable_hotarea == 1 && selmon->is_in_hotarea == 0 && y_root > hy && - x_root < hx && x_root >= selmon->m.x && - y_root <= (selmon->m.y + selmon->m.height)) { + switch (hotarea_corner) { + case BOTTOM_RIGHT: // 右下角 + hx = selmon->m.x + selmon->m.width - hotarea_size; + hy = selmon->m.y + selmon->m.height - hotarea_size; + break; + case TOP_LEFT: // 左上角 + hx = selmon->m.x + hotarea_size; + hy = selmon->m.y + hotarea_size; + break; + case TOP_RIGHT: // 右上角 + hx = selmon->m.x + selmon->m.width - hotarea_size; + hy = selmon->m.y + hotarea_size; + break; + case BOTTOM_LEFT: // 左下角(默认) + default: + hx = selmon->m.x + hotarea_size; + hy = selmon->m.y + selmon->m.height - hotarea_size; + break; + } + + // 判断鼠标是否在热区内 + int in_hotarea = 0; + + switch (hotarea_corner) { + case BOTTOM_RIGHT: // 右下角 + in_hotarea = (y_root > hy && x_root > hx && + x_root <= (selmon->m.x + selmon->m.width) && + y_root <= (selmon->m.y + selmon->m.height)); + break; + case TOP_LEFT: // 左上角 + in_hotarea = (y_root < hy && x_root < hx && x_root >= selmon->m.x && + y_root >= selmon->m.y); + break; + case TOP_RIGHT: // 右上角 + in_hotarea = (y_root < hy && x_root > hx && + x_root <= (selmon->m.x + selmon->m.width) && + y_root >= selmon->m.y); + break; + case BOTTOM_LEFT: // 左下角(默认) + default: + in_hotarea = (y_root > hy && x_root < hx && x_root >= selmon->m.x && + y_root <= (selmon->m.y + selmon->m.height)); + break; + } + + if (enable_hotarea == 1 && selmon->is_in_hotarea == 0 && in_hotarea) { toggleoverview(&arg); selmon->is_in_hotarea = 1; } else if (enable_hotarea == 1 && selmon->is_in_hotarea == 1 && - (y_root <= hy || x_root >= hx || x_root < selmon->m.x || - y_root > (selmon->m.y + selmon->m.height))) { + !in_hotarea) { selmon->is_in_hotarea = 0; } } From e535aea28bccaad3dd6dde66fa2e80a68f90f844 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Wed, 28 Jan 2026 14:50:17 +0800 Subject: [PATCH 468/591] fix: avoid redundant frame requests --- src/animation/client.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/animation/client.h b/src/animation/client.h index 15a0d164..7bc47ac0 100644 --- a/src/animation/client.h +++ b/src/animation/client.h @@ -1061,9 +1061,9 @@ void client_set_focused_opacity_animation(Client *c) { c->opacity_animation.initial_opacity = c->opacity_animation.current_opacity; } else { - memcpy(c->opacity_animation.initial_border_color, border_color, + memcpy(c->opacity_animation.initial_border_color, bordercolor, sizeof(c->opacity_animation.initial_border_color)); - memcpy(c->opacity_animation.current_border_color, border_color, + memcpy(c->opacity_animation.current_border_color, bordercolor, sizeof(c->opacity_animation.current_border_color)); c->opacity_animation.initial_opacity = c->unfocused_opacity; c->opacity_animation.current_opacity = c->unfocused_opacity; @@ -1167,7 +1167,7 @@ bool client_apply_focus_opacity(Client *c) { eased_progress; } client_set_border_color(c, c->opacity_animation.current_border_color); - if (linear_progress == 1.0f) { + if (linear_progress >= 1.0f) { c->opacity_animation.running = false; } else { return true; From 4591b69e4d8e212b2b4986abbb1598f968b557d0 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Thu, 29 Jan 2026 09:34:49 +0800 Subject: [PATCH 469/591] fix: accel_profile can't set to 0 --- src/mango.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/mango.c b/src/mango.c index a32be837..0360d4f2 100644 --- a/src/mango.c +++ b/src/mango.c @@ -2958,9 +2958,14 @@ void configure_pointer(struct libinput_device *device) { if (libinput_device_config_send_events_get_modes(device)) libinput_device_config_send_events_set_mode(device, send_events_mode); - if (libinput_device_config_accel_is_available(device)) { + if (accel_profile && libinput_device_config_accel_is_available(device)) { libinput_device_config_accel_set_profile(device, accel_profile); libinput_device_config_accel_set_speed(device, accel_speed); + } else { + // profile cannot be directly applied to 0, need to set to 1 first + libinput_device_config_accel_set_profile(device, 1); + libinput_device_config_accel_set_profile(device, 0); + libinput_device_config_accel_set_speed(device, 0); } } From d9f679a8e371991785e5a8a18f6f5cac11fcd601 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Thu, 29 Jan 2026 09:42:54 +0800 Subject: [PATCH 470/591] fix: tagcrossmon not apply in current monitor --- src/dispatch/bind_define.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index f27ed67b..c0e51dc2 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -1444,9 +1444,14 @@ int32_t viewcrossmon(const Arg *arg) { } int32_t tagcrossmon(const Arg *arg) { - if (!selmon->sel) + if (!selmon || !selmon->sel) return 0; + if (regex_match(selmon->wlr_output->name, arg->v)) { + tag_client(arg, selmon->sel); + return 0; + } + tagmon(&(Arg){.ui = arg->ui, .i = UNDIR, .v = arg->v}); return 0; } From 672706c71f4775dba304af1700451e0eadf8cea1 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Thu, 29 Jan 2026 11:58:28 +0800 Subject: [PATCH 471/591] fix: not apply vrr disalbe when enable it at the beginning --- src/config/parse_config.h | 2 ++ src/mango.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/config/parse_config.h b/src/config/parse_config.h index c3458365..baef79d1 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -3198,6 +3198,8 @@ void reapply_monitor_rules(void) { if (vrr) { enable_adaptive_sync(m, &state); + } else { + wlr_output_state_set_adaptive_sync_enabled(&state, false); } wlr_output_state_set_scale(&state, mr->scale); diff --git a/src/mango.c b/src/mango.c index 0360d4f2..86ea8a95 100644 --- a/src/mango.c +++ b/src/mango.c @@ -2777,6 +2777,8 @@ void createmon(struct wl_listener *listener, void *data) { if (vrr) { enable_adaptive_sync(m, &state); + } else { + wlr_output_state_set_adaptive_sync_enabled(&state, false); } wlr_output_state_set_scale(&state, r->scale); From aa5241fb7b0d5059fdceb3688309cf07fb94fbf2 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Thu, 29 Jan 2026 21:59:39 +0800 Subject: [PATCH 472/591] fix: allow layer surface attach null buffer --- src/mango.c | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/src/mango.c b/src/mango.c index 86ea8a95..ae49a730 100644 --- a/src/mango.c +++ b/src/mango.c @@ -480,6 +480,7 @@ typedef struct { char *animation_type_open; char *animation_type_close; bool need_output_flush; + bool being_unmapped; } LayerSurface; typedef struct { @@ -592,7 +593,7 @@ static void cursorwarptohint(void); static void destroydecoration(struct wl_listener *listener, void *data); static void destroydragicon(struct wl_listener *listener, void *data); static void destroyidleinhibitor(struct wl_listener *listener, void *data); -static void destroylayersurfacenotify(struct wl_listener *listener, void *data); +static void destroylayernodenotify(struct wl_listener *listener, void *data); static void destroylock(SessionLock *lock, int32_t unlocked); static void destroylocksurface(struct wl_listener *listener, void *data); static void destroynotify(struct wl_listener *listener, void *data); @@ -1521,6 +1522,9 @@ void arrangelayer(Monitor *m, struct wl_list *list, struct wlr_box *usable_area, !layer_surface->initialized) continue; + if (l->being_unmapped) + continue; + wlr_scene_layer_surface_v1_configure(l->scene_layer, &full_area, usable_area); wlr_scene_node_set_position(&l->popups->node, l->scene->node.x, @@ -2337,6 +2341,15 @@ void commitlayersurfacenotify(struct wl_listener *listener, void *data) { return; } + // 检查surface是否有buffer + if (!layer_surface->surface->buffer) { + // 空buffer,只是隐藏,不改变mapped状态 + wlr_scene_node_set_enabled(&l->scene->node, false); + return; + } else { + wlr_scene_node_set_enabled(&l->scene->node, true); + } + get_layer_target_geometry(l, &box); if (animations && layer_animations && !l->noanim && l->mapped && @@ -2633,8 +2646,6 @@ void createlayersurface(struct wl_listener *listener, void *data) { LISTEN(&surface->events.commit, &l->surface_commit, commitlayersurfacenotify); LISTEN(&surface->events.unmap, &l->unmap, unmaplayersurfacenotify); - LISTEN(&layer_surface->events.destroy, &l->destroy, - destroylayersurfacenotify); l->layer_surface = layer_surface; l->mon = layer_surface->output->data; @@ -2647,6 +2658,8 @@ void createlayersurface(struct wl_listener *listener, void *data) { : scene_layer); l->scene->node.data = l->popups->node.data = l; + LISTEN(&l->scene->node.events.destroy, &l->destroy, destroylayernodenotify); + wl_list_insert(&l->mon->layers[layer_surface->pending.layer], &l->link); wlr_surface_send_enter(surface, layer_surface->output); } @@ -3112,7 +3125,7 @@ void destroyidleinhibitor(struct wl_listener *listener, void *data) { free(listener); } -void destroylayersurfacenotify(struct wl_listener *listener, void *data) { +void destroylayernodenotify(struct wl_listener *listener, void *data) { LayerSurface *l = wl_container_of(listener, l, destroy); wl_list_remove(&l->link); @@ -3120,7 +3133,6 @@ void destroylayersurfacenotify(struct wl_listener *listener, void *data) { wl_list_remove(&l->map.link); wl_list_remove(&l->unmap.link); wl_list_remove(&l->surface_commit.link); - wlr_scene_node_destroy(&l->scene->node); wlr_scene_node_destroy(&l->popups->node); free(l); } @@ -5554,6 +5566,7 @@ void unmaplayersurfacenotify(struct wl_listener *listener, void *data) { LayerSurface *l = wl_container_of(listener, l, unmap); l->mapped = 0; + l->being_unmapped = true; init_fadeout_layers(l); @@ -5565,6 +5578,9 @@ void unmaplayersurfacenotify(struct wl_listener *listener, void *data) { if (l->layer_surface->surface == seat->keyboard_state.focused_surface) focusclient(focustop(selmon), 1); motionnotify(0, NULL, 0, 0, 0, 0); + l->being_unmapped = false; + wlr_scene_node_destroy(&l->shadow->node); + l->shadow = NULL; } void unmapnotify(struct wl_listener *listener, void *data) { From ca09aa69db29adf7e9cbaab74885724b4d469c66 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Fri, 30 Jan 2026 08:47:12 +0800 Subject: [PATCH 473/591] opt: not hide null buffer layer if is not mapped --- src/mango.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mango.c b/src/mango.c index ae49a730..1d332c45 100644 --- a/src/mango.c +++ b/src/mango.c @@ -2342,8 +2342,8 @@ void commitlayersurfacenotify(struct wl_listener *listener, void *data) { } // 检查surface是否有buffer - if (!layer_surface->surface->buffer) { - // 空buffer,只是隐藏,不改变mapped状态 + // 空buffer,只是隐藏,不改变mapped状态 + if (l->mapped && !layer_surface->surface->buffer) { wlr_scene_node_set_enabled(&l->scene->node, false); return; } else { From 5172444e08b2c2be24bef0b5ccff2d2367332118 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sun, 1 Feb 2026 15:33:05 +0800 Subject: [PATCH 474/591] bump version to 0.12.0 --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index d71eb597..05656093 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('mango', ['c', 'cpp'], - version : '0.11.0', + version : '0.12.0', ) subdir('protocols') From bcee63fa76245c900800c21eac0e999b45b86251 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sun, 1 Feb 2026 19:21:01 +0800 Subject: [PATCH 475/591] feat: add config check in mango cli --- src/config/parse_config.h | 441 ++++++++++++++++++++++++++++---------- src/mango.c | 30 ++- 2 files changed, 354 insertions(+), 117 deletions(-) diff --git a/src/config/parse_config.h b/src/config/parse_config.h index baef79d1..f7ce848b 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -405,7 +405,10 @@ int32_t parse_double_array(const char *input, double *output, char *endptr; double val = strtod(token, &endptr); if (endptr == token || *endptr != '\0') { - fprintf(stderr, "Error: Invalid number in array: %s\n", token); + fprintf( + stderr, + "\033[1m\033[31m[ERROR]:\033[33m Invalid number in array: %s\n", + token); free(dup); return -1; } @@ -457,7 +460,9 @@ void parse_bind_flags(const char *str, KeyBinding *kb) { kb->ispassapply = true; break; default: - // 忽略其他字符或可根据需要处理错误 + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Unknown bind flag: %c\n", + suffix[i]); break; } } @@ -547,13 +552,14 @@ static bool starts_with_ignore_case(const char *str, const char *prefix) { uint32_t parse_mod(const char *mod_str) { if (!mod_str || !*mod_str) { - return 0; + return UINT32_MAX; } uint32_t mod = 0; char input_copy[256]; char *token; char *saveptr = NULL; + bool match_success = false; // 复制并转换为小写 strncpy(input_copy, mod_str, sizeof(input_copy) - 1); @@ -591,35 +597,56 @@ uint32_t parse_mod(const char *mod_str) { case 108: mod |= WLR_MODIFIER_ALT; break; + default: + fprintf(stderr, + "unknown modifier keycode: \033[1m\033[31m%s\n", + token); + break; } } } else { // 完整的 modifier 检查(保留原始所有检查项) - if (strstr(token, "super") || strstr(token, "super_l") || - strstr(token, "super_r")) { + if (!strcmp(token, "super") || !strcmp(token, "super_l") || + !strcmp(token, "super_r")) { mod |= WLR_MODIFIER_LOGO; + match_success = true; } - if (strstr(token, "ctrl") || strstr(token, "ctrl_l") || - strstr(token, "ctrl_r")) { + if (!strcmp(token, "ctrl") || !strcmp(token, "ctrl_l") || + !strcmp(token, "ctrl_r")) { mod |= WLR_MODIFIER_CTRL; + match_success = true; } - if (strstr(token, "shift") || strstr(token, "shift_l") || - strstr(token, "shift_r")) { + if (!strcmp(token, "shift") || !strcmp(token, "shift_l") || + !strcmp(token, "shift_r")) { mod |= WLR_MODIFIER_SHIFT; + match_success = true; } - if (strstr(token, "alt") || strstr(token, "alt_l") || - strstr(token, "alt_r")) { + if (!strcmp(token, "alt") || !strcmp(token, "alt_l") || + !strcmp(token, "alt_r")) { mod |= WLR_MODIFIER_ALT; + match_success = true; } - if (strstr(token, "hyper") || strstr(token, "hyper_l") || - strstr(token, "hyper_r")) { + if (!strcmp(token, "hyper") || !strcmp(token, "hyper_l") || + !strcmp(token, "hyper_r")) { mod |= WLR_MODIFIER_MOD3; + match_success = true; + } + if (!strcmp(token, "none")) { + match_success = true; } } token = strtok_r(NULL, "+", &saveptr); } + if (!match_success) { + mod = UINT32_MAX; + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Unknown modifier: " + "\033[1m\033[31m%s\n", + mod_str); + } + return mod; } @@ -735,13 +762,17 @@ KeySymCode parse_key(const char *key_str, bool isbindsym) { // 无法解析的键名 kc.type = KEY_TYPE_SYM; kc.keysym = XKB_KEY_NoSymbol; + fprintf( + stderr, + "\033[1m\033[31m[ERROR]:\033[33m Unknown key: \033[1m\033[31m%s\n", + key_str); // keycode 字段保持为0 } return kc; } -int32_t parse_button(const char *str) { +uint32_t parse_button(const char *str) { // 将输入字符串转换为小写 char lowerStr[20]; int32_t i = 0; @@ -769,7 +800,11 @@ int32_t parse_button(const char *str) { } else if (strcmp(lowerStr, "btn_task") == 0) { return BTN_TASK; } else { - return 0; + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Unknown button: " + "\033[1m\033[31m%s\n", + str); + return UINT32_MAX; } } @@ -1115,7 +1150,7 @@ void run_exec_once() { } } -void parse_option(Config *config, char *key, char *value) { +bool parse_option(Config *config, char *key, char *value) { if (strcmp(key, "keymode") == 0) { snprintf(config->keymode, sizeof(config->keymode), "%.27s", value); } else if (strcmp(key, "animations") == 0) { @@ -1166,53 +1201,70 @@ void parse_option(Config *config, char *key, char *value) { int32_t num = parse_double_array(value, config->animation_curve_move, 4); if (num != 4) { - fprintf(stderr, "Error: Failed to parse animation_curve_move: %s\n", + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Failed to parse " + "animation_curve_move: %s\n", value); + return false; } } else if (strcmp(key, "animation_curve_open") == 0) { int32_t num = parse_double_array(value, config->animation_curve_open, 4); if (num != 4) { - fprintf(stderr, "Error: Failed to parse animation_curve_open: %s\n", + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Failed to parse " + "animation_curve_open: %s\n", value); + return false; } } else if (strcmp(key, "animation_curve_tag") == 0) { int32_t num = parse_double_array(value, config->animation_curve_tag, 4); if (num != 4) { - fprintf(stderr, "Error: Failed to parse animation_curve_tag: %s\n", + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Failed to parse " + "animation_curve_tag: %s\n", value); + return false; } } else if (strcmp(key, "animation_curve_close") == 0) { int32_t num = parse_double_array(value, config->animation_curve_close, 4); if (num != 4) { fprintf(stderr, - "Error: Failed to parse animation_curve_close: %s\n", + "\033[1m\033[31m[ERROR]:\033[33m Failed to parse " + "animation_curve_close: %s\n", value); + return false; } } else if (strcmp(key, "animation_curve_focus") == 0) { int32_t num = parse_double_array(value, config->animation_curve_focus, 4); if (num != 4) { fprintf(stderr, - "Error: Failed to parse animation_curve_focus: %s\n", + "\033[1m\033[31m[ERROR]:\033[33m Failed to parse " + "animation_curve_focus: %s\n", value); + return false; } } else if (strcmp(key, "animation_curve_opafadein") == 0) { int32_t num = parse_double_array(value, config->animation_curve_opafadein, 4); if (num != 4) { fprintf(stderr, - "Error: Failed to parse animation_curve_opafadein: %s\n", + "\033[1m\033[31m[ERROR]:\033[33m Failed to parse " + "animation_curve_opafadein: %s\n", value); + return false; } } else if (strcmp(key, "animation_curve_opafadeout") == 0) { int32_t num = parse_double_array(value, config->animation_curve_opafadeout, 4); if (num != 4) { fprintf(stderr, - "Error: Failed to parse animation_curve_opafadeout: %s\n", + "\033[1m\033[31m[ERROR]:\033[33m Failed to parse " + "animation_curve_opafadeout: %s\n", value); + return false; } } else if (strcmp(key, "scroller_structs") == 0) { config->scroller_structs = atoi(value); @@ -1333,8 +1385,10 @@ void parse_option(Config *config, char *key, char *value) { config->scroller_proportion_preset = (float *)malloc(float_count * sizeof(float)); if (!config->scroller_proportion_preset) { - fprintf(stderr, "Error: Memory allocation failed\n"); - return; + fprintf( + stderr, + "\033[1m\033[31m[ERROR]:\033[33m Memory allocation failed\n"); + return false; } // 3. 解析 value 中的浮点数 @@ -1346,14 +1400,15 @@ void parse_option(Config *config, char *key, char *value) { while (token != NULL && i < float_count) { if (sscanf(token, "%f", &value_set) != 1) { - fprintf(stderr, - "Error: Invalid float value in " - "scroller_proportion_preset: %s\n", - token); + fprintf( + stderr, + "\033[1m\033[31m[ERROR]:\033[33m Invalid float value in " + "scroller_proportion_preset: %s\n", + token); free(value_copy); free(config->scroller_proportion_preset); config->scroller_proportion_preset = NULL; - return; + return false; } // Clamp the value between 0.0 and 1.0 (or your desired range) @@ -1367,13 +1422,14 @@ void parse_option(Config *config, char *key, char *value) { // 4. 检查解析的浮点数数量是否匹配 if (i != float_count) { fprintf(stderr, - "Error: Invalid scroller_proportion_preset format: %s\n", + "\033[1m\033[31m[ERROR]:\033[33m Invalid " + "scroller_proportion_preset format: %s\n", value); free(value_copy); free(config->scroller_proportion_preset); // 释放已分配的内存 config->scroller_proportion_preset = NULL; // 防止野指针 config->scroller_proportion_preset_count = 0; - return; + return false; } config->scroller_proportion_preset_count = float_count; @@ -1392,8 +1448,10 @@ void parse_option(Config *config, char *key, char *value) { config->circle_layout = (char **)malloc(string_count * sizeof(char *)); memset(config->circle_layout, 0, string_count * sizeof(char *)); if (!config->circle_layout) { - fprintf(stderr, "Error: Memory allocation failed\n"); - return; + fprintf( + stderr, + "\033[1m\033[31m[ERROR]:\033[33m Memory allocation failed\n"); + return false; } // 3. 解析 value 中的字符串 @@ -1408,7 +1466,9 @@ void parse_option(Config *config, char *key, char *value) { config->circle_layout[i] = strdup(cleaned_token); if (!config->circle_layout[i]) { fprintf(stderr, - "Error: Memory allocation failed for string: %s\n", + "\033[1m\033[31m[ERROR]:\033[33m Memory allocation " + "failed for " + "string: %s\n", token); // 释放之前分配的内存 for (int32_t j = 0; j < i; j++) { @@ -1418,7 +1478,7 @@ void parse_option(Config *config, char *key, char *value) { free(value_copy); config->circle_layout = NULL; // 防止野指针 config->circle_layout_count = 0; - return; + return false; } token = strtok(NULL, ","); i++; @@ -1426,7 +1486,10 @@ void parse_option(Config *config, char *key, char *value) { // 4. 检查解析的字符串数量是否匹配 if (i != string_count) { - fprintf(stderr, "Error: Invalid circle_layout format: %s\n", value); + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Invalid circle_layout " + "format: %s\n", + value); // 释放之前分配的内存 for (int32_t j = 0; j < i; j++) { free(config->circle_layout[j]); @@ -1435,7 +1498,7 @@ void parse_option(Config *config, char *key, char *value) { free(value_copy); config->circle_layout = NULL; // 防止野指针 config->circle_layout_count = 0; - return; + return false; } config->circle_layout_count = string_count; @@ -1542,7 +1605,11 @@ void parse_option(Config *config, char *key, char *value) { } else if (strcmp(key, "rootcolor") == 0) { int64_t color = parse_color(value); if (color == -1) { - fprintf(stderr, "Error: Invalid rootcolor format: %s\n", value); + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Invalid rootcolor format: " + "%s\n", + value); + return false; } else { convert_hex_to_rgba(config->rootcolor, color); } @@ -1550,58 +1617,89 @@ void parse_option(Config *config, char *key, char *value) { } else if (strcmp(key, "shadowscolor") == 0) { int64_t color = parse_color(value); if (color == -1) { - fprintf(stderr, "Error: Invalid shadowscolor format: %s\n", value); + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Invalid shadowscolor " + "format: %s\n", + value); + return false; } else { convert_hex_to_rgba(config->shadowscolor, color); } } else if (strcmp(key, "bordercolor") == 0) { int64_t color = parse_color(value); if (color == -1) { - fprintf(stderr, "Error: Invalid bordercolor format: %s\n", value); + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Invalid bordercolor " + "format: %s\n", + value); + return false; } else { convert_hex_to_rgba(config->bordercolor, color); } } else if (strcmp(key, "focuscolor") == 0) { int64_t color = parse_color(value); if (color == -1) { - fprintf(stderr, "Error: Invalid focuscolor format: %s\n", value); + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Invalid focuscolor " + "format: %s\n", + value); + return false; } else { convert_hex_to_rgba(config->focuscolor, color); } } else if (strcmp(key, "maximizescreencolor") == 0) { int64_t color = parse_color(value); if (color == -1) { - fprintf(stderr, "Error: Invalid maximizescreencolor format: %s\n", - value); + fprintf( + stderr, + "\033[1m\033[31m[ERROR]:\033[33m Invalid maximizescreencolor " + "format: %s\n", + value); + return false; } else { convert_hex_to_rgba(config->maximizescreencolor, color); } } else if (strcmp(key, "urgentcolor") == 0) { int64_t color = parse_color(value); if (color == -1) { - fprintf(stderr, "Error: Invalid urgentcolor format: %s\n", value); + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Invalid urgentcolor " + "format: %s\n", + value); + return false; } else { convert_hex_to_rgba(config->urgentcolor, color); } } else if (strcmp(key, "scratchpadcolor") == 0) { int64_t color = parse_color(value); if (color == -1) { - fprintf(stderr, "Error: Invalid scratchpadcolor format: %s\n", + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Invalid scratchpadcolor " + "format: %s\n", value); + return false; } else { convert_hex_to_rgba(config->scratchpadcolor, color); } } else if (strcmp(key, "globalcolor") == 0) { int64_t color = parse_color(value); if (color == -1) { - fprintf(stderr, "Error: Invalid globalcolor format: %s\n", value); + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Invalid globalcolor " + "format: %s\n", + value); + return false; } else { convert_hex_to_rgba(config->globalcolor, color); } } else if (strcmp(key, "overlaycolor") == 0) { int64_t color = parse_color(value); if (color == -1) { - fprintf(stderr, "Error: Invalid overlaycolor format: %s\n", value); + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Invalid overlaycolor " + "format: %s\n", + value); + return false; } else { convert_hex_to_rgba(config->overlaycolor, color); } @@ -1611,8 +1709,9 @@ void parse_option(Config *config, char *key, char *value) { sizeof(ConfigMonitorRule)); if (!config->monitor_rules) { fprintf(stderr, - "Error: Failed to allocate memory for monitor rules\n"); - return; + "\033[1m\033[31m[ERROR]:\033[33m Failed to allocate " + "memory for monitor rules\n"); + return false; } ConfigMonitorRule *rule = @@ -1630,6 +1729,7 @@ void parse_option(Config *config, char *key, char *value) { rule->refresh = 0.0f; rule->vrr = 0; + bool parse_error = false; char *token = strtok(value, ","); while (token != NULL) { char *colon = strchr(token, ':'); @@ -1659,19 +1759,29 @@ void 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 { + fprintf( + stderr, + "\033[1m\033[31m[ERROR]:\033[33m Unknown monitor rule " + "option:\033[1m\033[31m %s\n", + key); + parse_error = true; } } token = strtok(NULL, ","); } config->monitor_rules_count++; + return !parse_error; } else if (strcmp(key, "tagrule") == 0) { config->tag_rules = realloc(config->tag_rules, (config->tag_rules_count + 1) * sizeof(ConfigTagRule)); if (!config->tag_rules) { - fprintf(stderr, "Error: Failed to allocate memory for tag rules\n"); - return; + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Failed to allocate " + "memory for tag rules\n"); + return false; } ConfigTagRule *rule = &config->tag_rules[config->tag_rules_count]; @@ -1686,6 +1796,7 @@ void parse_option(Config *config, char *key, char *value) { rule->no_render_border = 0; rule->no_hide = 0; + bool parse_error = false; char *token = strtok(value, ","); while (token != NULL) { char *colon = strchr(token, ':'); @@ -1711,20 +1822,28 @@ void parse_option(Config *config, char *key, char *value) { rule->nmaster = CLAMP_INT(atoi(val), 1, 99); } else if (strcmp(key, "mfact") == 0) { rule->mfact = CLAMP_FLOAT(atof(val), 0.1f, 0.9f); + } else { + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Unknown tag rule " + "option:\033[1m\033[31m %s\n", + key); + parse_error = true; } } token = strtok(NULL, ","); } config->tag_rules_count++; + return !parse_error; } else if (strcmp(key, "layerrule") == 0) { config->layer_rules = realloc(config->layer_rules, (config->layer_rules_count + 1) * sizeof(ConfigLayerRule)); if (!config->layer_rules) { fprintf(stderr, - "Error: Failed to allocate memory for layer rules\n"); - return; + "\033[1m\033[31m[ERROR]:\033[33m Failed to allocate " + "memory for layer rules\n"); + return false; } ConfigLayerRule *rule = &config->layer_rules[config->layer_rules_count]; @@ -1738,6 +1857,7 @@ void parse_option(Config *config, char *key, char *value) { rule->noanim = 0; rule->noshadow = 0; + bool parse_error = false; char *token = strtok(value, ","); while (token != NULL) { char *colon = strchr(token, ':'); @@ -1761,6 +1881,13 @@ void parse_option(Config *config, char *key, char *value) { rule->noanim = CLAMP_INT(atoi(val), 0, 1); } else if (strcmp(key, "noshadow") == 0) { rule->noshadow = CLAMP_INT(atoi(val), 0, 1); + } else { + fprintf( + stderr, + "\033[1m\033[31m[ERROR]:\033[33m Unknown layer rule " + "option:\033[1m\033[31m %s\n", + key); + parse_error = true; } } token = strtok(NULL, ","); @@ -1772,14 +1899,16 @@ void parse_option(Config *config, char *key, char *value) { } config->layer_rules_count++; + return !parse_error; } else if (strcmp(key, "windowrule") == 0) { config->window_rules = realloc(config->window_rules, (config->window_rules_count + 1) * sizeof(ConfigWinRule)); if (!config->window_rules) { fprintf(stderr, - "Error: Failed to allocate memory for window rules\n"); - return; + "\033[1m\033[31m[ERROR]:\033[33m Failed to allocate " + "memory for window rules\n"); + return false; } ConfigWinRule *rule = &config->window_rules[config->window_rules_count]; @@ -1835,6 +1964,7 @@ void parse_option(Config *config, char *key, char *value) { rule->globalkeybinding = (KeyBinding){0}; + bool parse_error = false; char *token = strtok(value, ","); while (token != NULL) { char *colon = strchr(token, ':'); @@ -1934,17 +2064,37 @@ void parse_option(Config *config, char *key, char *value) { rule->globalkeybinding.mod = parse_mod(mod_str); rule->globalkeybinding.keysymcode = parse_key(keysym_str, false); + if (rule->globalkeybinding.mod == UINT32_MAX) { + return false; + } + if (rule->globalkeybinding.keysymcode.type == + KEY_TYPE_SYM && + rule->globalkeybinding.keysymcode.keysym == + XKB_KEY_NoSymbol) { + return false; + } + } else { + fprintf( + stderr, + "\033[1m\033[31m[ERROR]:\033[33m Unknown window rule " + "option:\033[1m\033[31m %s\n", + key); + parse_error = true; } } token = strtok(NULL, ","); } config->window_rules_count++; + return !parse_error; } else if (strncmp(key, "env", 3) == 0) { char env_type[256], env_value[256]; if (sscanf(value, "%255[^,],%255[^\n]", env_type, env_value) < 2) { - fprintf(stderr, "Error: Invalid bind format: %s\n", value); - return; + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Invalid bind format: " + "\033[1m\033[31m%s\n", + value); + return false; } trim_whitespace(env_type); trim_whitespace(env_value); @@ -1959,8 +2109,9 @@ void parse_option(Config *config, char *key, char *value) { free(env->type); free(env->value); free(env); - fprintf(stderr, "Error: Failed to allocate memory for env\n"); - return; + fprintf(stderr, "\033[1m\033[31m[ERROR]:\033[33m Failed to " + "allocate memory for env\n"); + return false; } config->env[config->env_count] = env; @@ -1970,15 +2121,18 @@ void parse_option(Config *config, char *key, char *value) { char **new_exec = realloc(config->exec, (config->exec_count + 1) * sizeof(char *)); if (!new_exec) { - fprintf(stderr, "Error: Failed to allocate memory for exec\n"); - return; + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Failed to allocate " + "memory for exec\n"); + return false; } config->exec = new_exec; config->exec[config->exec_count] = strdup(value); if (!config->exec[config->exec_count]) { - fprintf(stderr, "Error: Failed to duplicate exec string\n"); - return; + fprintf(stderr, "\033[1m\033[31m[ERROR]:\033[33m Failed to " + "duplicate exec string\n"); + return false; } config->exec_count++; @@ -1988,15 +2142,19 @@ void parse_option(Config *config, char *key, char *value) { char **new_exec_once = realloc( config->exec_once, (config->exec_once_count + 1) * sizeof(char *)); if (!new_exec_once) { - fprintf(stderr, "Error: Failed to allocate memory for exec_once\n"); - return; + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Failed to allocate " + "memory for exec_once\n"); + return false; } config->exec_once = new_exec_once; config->exec_once[config->exec_once_count] = strdup(value); if (!config->exec_once[config->exec_once_count]) { - fprintf(stderr, "Error: Failed to duplicate exec_once string\n"); - return; + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Failed to duplicate " + "exec_once string\n"); + return false; } config->exec_once_count++; @@ -2007,8 +2165,9 @@ void parse_option(Config *config, char *key, char *value) { (config->key_bindings_count + 1) * sizeof(KeyBinding)); if (!config->key_bindings) { fprintf(stderr, - "Error: Failed to allocate memory for key bindings\n"); - return; + "\033[1m\033[31m[ERROR]:\033[33m Failed to allocate " + "memory for key bindings\n"); + return false; } KeyBinding *binding = &config->key_bindings[config->key_bindings_count]; @@ -2023,8 +2182,11 @@ void parse_option(Config *config, char *key, char *value) { "^,],%255[^\n]", mod_str, keysym_str, func_name, arg_value, arg_value2, arg_value3, arg_value4, arg_value5) < 3) { - fprintf(stderr, "Error: Invalid bind format: %s\n", value); - return; + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Invalid bind format: " + "\033[1m\033[31m%s\n", + value); + return false; } trim_whitespace(mod_str); trim_whitespace(keysym_str); @@ -2057,7 +2219,9 @@ void parse_option(Config *config, char *key, char *value) { binding->func = parse_func_name(func_name, &binding->arg, arg_value, arg_value2, arg_value3, arg_value4, arg_value5); - if (!binding->func) { + if (!binding->func || binding->mod == UINT32_MAX || + (binding->keysymcode.type == KEY_TYPE_SYM && + binding->keysymcode.keysym == XKB_KEY_NoSymbol)) { if (binding->arg.v) { free(binding->arg.v); binding->arg.v = NULL; @@ -2070,7 +2234,13 @@ void parse_option(Config *config, char *key, char *value) { free(binding->arg.v3); binding->arg.v3 = NULL; } - fprintf(stderr, "Error: Unknown function in bind: %s\n", func_name); + if (!binding->func) + fprintf( + stderr, + "\033[1m\033[31m[ERROR]:\033[33m Unknown dispatch in bind: " + "\033[1m\033[31m%s\n", + func_name); + return false; } else { config->key_bindings_count++; } @@ -2081,8 +2251,9 @@ void parse_option(Config *config, char *key, char *value) { (config->mouse_bindings_count + 1) * sizeof(MouseBinding)); if (!config->mouse_bindings) { fprintf(stderr, - "Error: Failed to allocate memory for mouse bindings\n"); - return; + "\033[1m\033[31m[ERROR]:\033[33m Failed to allocate " + "memory for mouse bindings\n"); + return false; } MouseBinding *binding = @@ -2098,8 +2269,11 @@ void parse_option(Config *config, char *key, char *value) { "^,],%255[^\n]", mod_str, button_str, func_name, arg_value, arg_value2, arg_value3, arg_value4, arg_value5) < 3) { - fprintf(stderr, "Error: Invalid mousebind format: %s\n", value); - return; + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Invalid mousebind format: " + "%s\n", + value); + return false; } trim_whitespace(mod_str); trim_whitespace(button_str); @@ -2118,7 +2292,8 @@ void parse_option(Config *config, char *key, char *value) { binding->func = parse_func_name(func_name, &binding->arg, arg_value, arg_value2, arg_value3, arg_value4, arg_value5); - if (!binding->func) { + if (!binding->func || binding->mod == UINT32_MAX || + binding->button == UINT32_MAX) { if (binding->arg.v) { free(binding->arg.v); binding->arg.v = NULL; @@ -2131,8 +2306,12 @@ void parse_option(Config *config, char *key, char *value) { free(binding->arg.v3); binding->arg.v3 = NULL; } - fprintf(stderr, "Error: Unknown function in mousebind: %s\n", - func_name); + if (!binding->func) + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Unknown dispatch in " + "mousebind: \033[1m\033[31m%s\n", + func_name); + return false; } else { config->mouse_bindings_count++; } @@ -2142,8 +2321,9 @@ void parse_option(Config *config, char *key, char *value) { (config->axis_bindings_count + 1) * sizeof(AxisBinding)); if (!config->axis_bindings) { fprintf(stderr, - "Error: Failed to allocate memory for axis bindings\n"); - return; + "\033[1m\033[31m[ERROR]:\033[33m Failed to allocate " + "memory for axis bindings\n"); + return false; } AxisBinding *binding = @@ -2159,8 +2339,11 @@ void parse_option(Config *config, char *key, char *value) { "^,],%255[^\n]", mod_str, dir_str, func_name, arg_value, arg_value2, arg_value3, arg_value4, arg_value5) < 3) { - fprintf(stderr, "Error: Invalid axisbind format: %s\n", value); - return; + fprintf( + stderr, + "\033[1m\033[31m[ERROR]:\033[33m Invalid axisbind format: %s\n", + value); + return false; } trim_whitespace(mod_str); @@ -2181,7 +2364,7 @@ void parse_option(Config *config, char *key, char *value) { parse_func_name(func_name, &binding->arg, arg_value, arg_value2, arg_value3, arg_value4, arg_value5); - if (!binding->func) { + if (!binding->func || binding->mod == UINT32_MAX) { if (binding->arg.v) { free(binding->arg.v); binding->arg.v = NULL; @@ -2194,8 +2377,12 @@ void parse_option(Config *config, char *key, char *value) { free(binding->arg.v3); binding->arg.v3 = NULL; } - fprintf(stderr, "Error: Unknown function in axisbind: %s\n", - func_name); + if (!binding->func) + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Unknown dispatch in " + "axisbind: \033[1m\033[31m%s\n", + func_name); + return false; } else { config->axis_bindings_count++; } @@ -2206,8 +2393,9 @@ void parse_option(Config *config, char *key, char *value) { sizeof(SwitchBinding)); if (!config->switch_bindings) { fprintf(stderr, - "Error: Failed to allocate memory for switch bindings\n"); - return; + "\033[1m\033[31m[ERROR]:\033[33m Failed to allocate " + "memory for switch bindings\n"); + return false; } SwitchBinding *binding = @@ -2223,8 +2411,11 @@ void parse_option(Config *config, char *key, char *value) { "^\n]", fold_str, func_name, arg_value, arg_value2, arg_value3, arg_value4, arg_value5) < 3) { - fprintf(stderr, "Error: Invalid switchbind format: %s\n", value); - return; + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Invalid switchbind " + "format: %s\n", + value); + return false; } trim_whitespace(fold_str); trim_whitespace(func_name); @@ -2252,8 +2443,13 @@ void parse_option(Config *config, char *key, char *value) { free(binding->arg.v3); binding->arg.v3 = NULL; } - fprintf(stderr, "Error: Unknown function in switchbind: %s\n", + + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Unknown dispatch in " + "switchbind: " + "\033[1m\033[31m%s\n", func_name); + return false; } else { config->switch_bindings_count++; } @@ -2264,8 +2460,9 @@ void parse_option(Config *config, char *key, char *value) { (config->gesture_bindings_count + 1) * sizeof(GestureBinding)); if (!config->gesture_bindings) { fprintf(stderr, - "Error: Failed to allocate memory for axis gesturebind\n"); - return; + "\033[1m\033[31m[ERROR]:\033[33m Failed to allocate " + "memory for axis gesturebind\n"); + return false; } GestureBinding *binding = @@ -2281,8 +2478,11 @@ void parse_option(Config *config, char *key, char *value) { "^,],%255[^,],%255[^\n]", mod_str, motion_str, fingers_count_str, func_name, arg_value, arg_value2, arg_value3, arg_value4, arg_value5) < 4) { - fprintf(stderr, "Error: Invalid gesturebind format: %s\n", value); - return; + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Invalid gesturebind " + "format: %s\n", + value); + return false; } trim_whitespace(mod_str); @@ -2305,7 +2505,7 @@ void parse_option(Config *config, char *key, char *value) { parse_func_name(func_name, &binding->arg, arg_value, arg_value2, arg_value3, arg_value4, arg_value5); - if (!binding->func) { + if (!binding->func || binding->mod == UINT32_MAX) { if (binding->arg.v) { free(binding->arg.v); binding->arg.v = NULL; @@ -2318,8 +2518,12 @@ void parse_option(Config *config, char *key, char *value) { free(binding->arg.v3); binding->arg.v3 = NULL; } - fprintf(stderr, "Error: Unknown function in axisbind: %s\n", - func_name); + if (!binding->func) + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Unknown dispatch in " + "axisbind: \033[1m\033[31m%s\n", + func_name); + return false; } else { config->gesture_bindings_count++; } @@ -2327,22 +2531,30 @@ void parse_option(Config *config, char *key, char *value) { } else if (strncmp(key, "source", 6) == 0) { parse_config_file(config, value); } else { - fprintf(stderr, "Error: Unknown key: %s\n", key); + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Unknown keyword: " + "\033[1m\033[31m%s\n", + key); + return false; } + + return true; } -void parse_config_line(Config *config, const char *line) { +bool parse_config_line(Config *config, const char *line) { char key[256], value[256]; if (sscanf(line, "%255[^=]=%255[^\n]", key, value) != 2) { - // fprintf(stderr, "Error: Invalid line format: %s\n", line); - return; + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Invalid line format: %s", + line); + return false; } // Then trim each part separately trim_whitespace(key); trim_whitespace(value); - parse_option(config, key, value); + return parse_option(config, key, value); } void parse_config_file(Config *config, const char *file_path) { @@ -2361,7 +2573,9 @@ void parse_config_file(Config *config, const char *file_path) { } else { const char *home = getenv("HOME"); if (!home) { - fprintf(stderr, "Error: HOME environment variable not set.\n"); + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m HOME environment " + "variable not set.\n"); return; } snprintf(full_path, sizeof(full_path), "%s/.config/mango/%s", home, @@ -2375,7 +2589,8 @@ void parse_config_file(Config *config, const char *file_path) { const char *home = getenv("HOME"); if (!home) { - fprintf(stderr, "Error: HOME environment variable not set.\n"); + fprintf(stderr, "\033[1m\033[31m[ERROR]:\033[33m HOME environment " + "variable not set.\n"); return; } snprintf(full_path, sizeof(full_path), "%s%s", home, file_path + 1); @@ -2392,11 +2607,21 @@ void parse_config_file(Config *config, const char *file_path) { } char line[512]; + bool parse_correct = true; + uint32_t line_count = 0; while (fgets(line, sizeof(line), file)) { + line_count++; if (line[0] == '#' || line[0] == '\n') { continue; } - parse_config_line(config, line); + parse_correct = parse_config_line(config, line); + if (!parse_correct) { + fprintf(stderr, + "\033[1;31m╰─\033[1;33m[Index]\033[0m " + "\033[1;36m%s\033[0m:\033[1;35m%d\033[0m\n" + " \033[1;36m╰─\033[0;33m%s\033[0m\n\n", + file_path, line_count, line); + } } fclose(file); diff --git a/src/mango.c b/src/mango.c index 1d332c45..5a8b6fc1 100644 --- a/src/mango.c +++ b/src/mango.c @@ -6160,17 +6160,22 @@ int32_t main(int32_t argc, char *argv[]) { char *startup_cmd = NULL; int32_t c; - while ((c = getopt(argc, argv, "s:c:hdv")) != -1) { - if (c == 's') + while ((c = getopt(argc, argv, "s:c:hdvp")) != -1) { + if (c == 's') { startup_cmd = optarg; - else if (c == 'd') + } else if (c == 'd') { log_level = WLR_DEBUG; - else if (c == 'v') - die("mango " VERSION); - else if (c == 'c') + } else if (c == 'v') { + printf("mango " VERSION "\n"); + return EXIT_SUCCESS; + } else if (c == 'c') { cli_config_path = optarg; - else + } else if (c == 'p') { + parse_config(); + return EXIT_SUCCESS; + } else { goto usage; + } } if (optind < argc) goto usage; @@ -6184,7 +6189,14 @@ int32_t main(int32_t argc, char *argv[]) { run(startup_cmd); cleanup(); return EXIT_SUCCESS; - usage: - die("Usage: %s [-v] [-d] [-c config file] [-s startup command]", argv[0]); + printf("Usage: mango [OPTIONS]\n" + "\n" + "Options:\n" + " -v Show mango version\n" + " -d Enable debug log\n" + " -c Use custom configuration file\n" + " -s Execute startup command\n" + " -p Check configuration file error\n"); + return EXIT_SUCCESS; } From eb0607501d3cdfa352dcc29ba35c46b79bc2fba8 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Mon, 2 Feb 2026 14:47:13 +0800 Subject: [PATCH 476/591] opt: change drag resize request limit to 120hz for floating window --- src/config/preset.h | 3 ++- src/layout/arrange.h | 6 +++--- src/mango.c | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/config/preset.h b/src/config/preset.h index 3d05161f..ae4424f9 100644 --- a/src/config/preset.h +++ b/src/config/preset.h @@ -108,7 +108,8 @@ int32_t drag_warp_cursor = 1; int32_t xwayland_persistence = 1; /* xwayland persistence */ int32_t syncobj_enable = 0; int32_t allow_lock_transparent = 0; -double drag_refresh_interval = 16.0; +double drag_tile_refresh_interval = 16.0; +double drag_floating_refresh_interval = 8.0; int32_t allow_tearing = TEARING_DISABLED; int32_t allow_shortcuts_inhibit = SHORTCUTS_INHIBIT_ENABLE; diff --git a/src/layout/arrange.h b/src/layout/arrange.h index 6ff1dd25..37213640 100644 --- a/src/layout/arrange.h +++ b/src/layout/arrange.h @@ -210,7 +210,7 @@ void resize_tile_master_horizontal(Client *grabc, bool isdrag, int32_t offsetx, } if (last_apply_drap_time == 0 || - time - last_apply_drap_time > drag_refresh_interval) { + time - last_apply_drap_time > drag_tile_refresh_interval) { arrange(grabc->mon, false, false); last_apply_drap_time = time; } @@ -367,7 +367,7 @@ void resize_tile_master_vertical(Client *grabc, bool isdrag, int32_t offsetx, } if (last_apply_drap_time == 0 || - time - last_apply_drap_time > drag_refresh_interval) { + time - last_apply_drap_time > drag_tile_refresh_interval) { arrange(grabc->mon, false, false); last_apply_drap_time = time; } @@ -548,7 +548,7 @@ void resize_tile_scroller(Client *grabc, bool isdrag, int32_t offsetx, } if (last_apply_drap_time == 0 || - time - last_apply_drap_time > drag_refresh_interval) { + time - last_apply_drap_time > drag_tile_refresh_interval) { arrange(grabc->mon, false, false); last_apply_drap_time = time; } diff --git a/src/mango.c b/src/mango.c index 5a8b6fc1..f5583c30 100644 --- a/src/mango.c +++ b/src/mango.c @@ -4143,7 +4143,7 @@ void motionnotify(uint32_t time, struct wlr_input_device *device, double dx, if (grabc->isfloating) { grabc->iscustomsize = 1; if (last_apply_drap_time == 0 || - time - last_apply_drap_time > drag_refresh_interval) { + time - last_apply_drap_time > drag_floating_refresh_interval) { resize_floating_window(grabc); last_apply_drap_time = time; } From 0546a2d4c472390f23171f7750b5702f1acb8582 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Tue, 3 Feb 2026 10:06:26 +0800 Subject: [PATCH 477/591] opt: allow use comma symbol in spawn shell value --- src/config/parse_config.h | 171 +++++++++++++++++++++++++------------- 1 file changed, 114 insertions(+), 57 deletions(-) diff --git a/src/config/parse_config.h b/src/config/parse_config.h index f7ce848b..1a025e90 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -550,6 +550,48 @@ static bool starts_with_ignore_case(const char *str, const char *prefix) { return true; } +static char *combine_args_until_empty(char *values[], int count) { + // find the first empty string + int first_empty = count; + for (int i = 0; i < count; i++) { + // check if it's empty: empty string or only contains "0" (initialized) + if (values[i][0] == '\0' || + (strlen(values[i]) == 1 && values[i][0] == '0')) { + first_empty = i; + break; + } + } + + // if there are no valid parameters, return an empty string + if (first_empty == 0) { + return strdup(""); + } + + // calculate the total length + size_t total_len = 0; + for (int i = 0; i < first_empty; i++) { + total_len += strlen(values[i]); + } + // plus the number of commas (first_empty-1 commas) + total_len += (first_empty - 1); + + // allocate memory and concatenate + char *combined = malloc(total_len + 1); + if (combined == NULL) { + return strdup(""); + } + + combined[0] = '\0'; + for (int i = 0; i < first_empty; i++) { + if (i > 0) { + strcat(combined, ","); + } + strcat(combined, values[i]); + } + + return combined; +} + uint32_t parse_mod(const char *mod_str) { if (!mod_str || !*mod_str) { return UINT32_MAX; @@ -1005,10 +1047,14 @@ FuncType parse_func_name(char *func_name, Arg *arg, char *arg_value, (*arg).ui = atoi(arg_value); } else if (strcmp(func_name, "spawn") == 0) { func = spawn; - (*arg).v = strdup(arg_value); + char *values[] = {arg_value, arg_value2, arg_value3, arg_value4, + arg_value5}; + (*arg).v = combine_args_until_empty(values, 5); } else if (strcmp(func_name, "spawn_shell") == 0) { func = spawn_shell; - (*arg).v = strdup(arg_value); + char *values[] = {arg_value, arg_value2, arg_value3, arg_value4, + arg_value5}; + (*arg).v = combine_args_until_empty(values, 5); } else if (strcmp(func_name, "spawn_on_empty") == 0) { func = spawn_on_empty; (*arg).v = strdup(arg_value); // 注意:之后需要释放这个内存 @@ -1385,9 +1431,8 @@ bool parse_option(Config *config, char *key, char *value) { config->scroller_proportion_preset = (float *)malloc(float_count * sizeof(float)); if (!config->scroller_proportion_preset) { - fprintf( - stderr, - "\033[1m\033[31m[ERROR]:\033[33m Memory allocation failed\n"); + fprintf(stderr, "\033[1m\033[31m[ERROR]:\033[33m Memory " + "allocation failed\n"); return false; } @@ -1400,18 +1445,19 @@ bool parse_option(Config *config, char *key, char *value) { while (token != NULL && i < float_count) { if (sscanf(token, "%f", &value_set) != 1) { - fprintf( - stderr, - "\033[1m\033[31m[ERROR]:\033[33m Invalid float value in " - "scroller_proportion_preset: %s\n", - token); + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Invalid float " + "value in " + "scroller_proportion_preset: %s\n", + token); free(value_copy); free(config->scroller_proportion_preset); config->scroller_proportion_preset = NULL; return false; } - // Clamp the value between 0.0 and 1.0 (or your desired range) + // Clamp the value between 0.0 and 1.0 (or your desired + // range) config->scroller_proportion_preset[i] = CLAMP_FLOAT(value_set, 0.1f, 1.0f); @@ -1448,9 +1494,8 @@ bool parse_option(Config *config, char *key, char *value) { config->circle_layout = (char **)malloc(string_count * sizeof(char *)); memset(config->circle_layout, 0, string_count * sizeof(char *)); if (!config->circle_layout) { - fprintf( - stderr, - "\033[1m\033[31m[ERROR]:\033[33m Memory allocation failed\n"); + fprintf(stderr, "\033[1m\033[31m[ERROR]:\033[33m Memory " + "allocation failed\n"); return false; } @@ -1606,7 +1651,8 @@ bool parse_option(Config *config, char *key, char *value) { int64_t color = parse_color(value); if (color == -1) { fprintf(stderr, - "\033[1m\033[31m[ERROR]:\033[33m Invalid rootcolor format: " + "\033[1m\033[31m[ERROR]:\033[33m Invalid rootcolor " + "format: " "%s\n", value); return false; @@ -1650,11 +1696,11 @@ bool parse_option(Config *config, char *key, char *value) { } else if (strcmp(key, "maximizescreencolor") == 0) { int64_t color = parse_color(value); if (color == -1) { - fprintf( - stderr, - "\033[1m\033[31m[ERROR]:\033[33m Invalid maximizescreencolor " - "format: %s\n", - value); + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Invalid " + "maximizescreencolor " + "format: %s\n", + value); return false; } else { convert_hex_to_rgba(config->maximizescreencolor, color); @@ -1674,7 +1720,8 @@ bool parse_option(Config *config, char *key, char *value) { int64_t color = parse_color(value); if (color == -1) { fprintf(stderr, - "\033[1m\033[31m[ERROR]:\033[33m Invalid scratchpadcolor " + "\033[1m\033[31m[ERROR]:\033[33m Invalid " + "scratchpadcolor " "format: %s\n", value); return false; @@ -1760,11 +1807,11 @@ bool parse_option(Config *config, char *key, char *value) { } else if (strcmp(key, "vrr") == 0) { rule->vrr = CLAMP_INT(atoi(val), 0, 1); } else { - fprintf( - stderr, - "\033[1m\033[31m[ERROR]:\033[33m Unknown monitor rule " - "option:\033[1m\033[31m %s\n", - key); + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Unknown " + "monitor rule " + "option:\033[1m\033[31m %s\n", + key); parse_error = true; } } @@ -1824,7 +1871,8 @@ bool parse_option(Config *config, char *key, char *value) { rule->mfact = CLAMP_FLOAT(atof(val), 0.1f, 0.9f); } else { fprintf(stderr, - "\033[1m\033[31m[ERROR]:\033[33m Unknown tag rule " + "\033[1m\033[31m[ERROR]:\033[33m Unknown " + "tag rule " "option:\033[1m\033[31m %s\n", key); parse_error = true; @@ -1882,11 +1930,11 @@ bool parse_option(Config *config, char *key, char *value) { } else if (strcmp(key, "noshadow") == 0) { rule->noshadow = CLAMP_INT(atoi(val), 0, 1); } else { - fprintf( - stderr, - "\033[1m\033[31m[ERROR]:\033[33m Unknown layer rule " - "option:\033[1m\033[31m %s\n", - key); + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Unknown " + "layer rule " + "option:\033[1m\033[31m %s\n", + key); parse_error = true; } } @@ -2074,11 +2122,11 @@ bool parse_option(Config *config, char *key, char *value) { return false; } } else { - fprintf( - stderr, - "\033[1m\033[31m[ERROR]:\033[33m Unknown window rule " - "option:\033[1m\033[31m %s\n", - key); + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Unknown " + "window rule " + "option:\033[1m\033[31m %s\n", + key); parse_error = true; } } @@ -2178,7 +2226,8 @@ bool parse_option(Config *config, char *key, char *value) { arg_value3[256] = "0\0", arg_value4[256] = "0\0", arg_value5[256] = "0\0"; if (sscanf(value, - "%255[^,],%255[^,],%255[^,],%255[^,],%255[^,],%255[^,],%255[" + "%255[^,],%255[^,],%255[^,],%255[^,],%255[^,],%255[^" + ",],%255[" "^,],%255[^\n]", mod_str, keysym_str, func_name, arg_value, arg_value2, arg_value3, arg_value4, arg_value5) < 3) { @@ -2235,11 +2284,11 @@ bool parse_option(Config *config, char *key, char *value) { binding->arg.v3 = NULL; } if (!binding->func) - fprintf( - stderr, - "\033[1m\033[31m[ERROR]:\033[33m Unknown dispatch in bind: " - "\033[1m\033[31m%s\n", - func_name); + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Unknown " + "dispatch in bind: " + "\033[1m\033[31m%s\n", + func_name); return false; } else { config->key_bindings_count++; @@ -2265,12 +2314,14 @@ bool parse_option(Config *config, char *key, char *value) { arg_value3[256] = "0\0", arg_value4[256] = "0\0", arg_value5[256] = "0\0"; if (sscanf(value, - "%255[^,],%255[^,],%255[^,],%255[^,],%255[^,],%255[^,],%255[" + "%255[^,],%255[^,],%255[^,],%255[^,],%255[^,],%255[^" + ",],%255[" "^,],%255[^\n]", mod_str, button_str, func_name, arg_value, arg_value2, arg_value3, arg_value4, arg_value5) < 3) { fprintf(stderr, - "\033[1m\033[31m[ERROR]:\033[33m Invalid mousebind format: " + "\033[1m\033[31m[ERROR]:\033[33m Invalid mousebind " + "format: " "%s\n", value); return false; @@ -2308,7 +2359,8 @@ bool parse_option(Config *config, char *key, char *value) { } if (!binding->func) fprintf(stderr, - "\033[1m\033[31m[ERROR]:\033[33m Unknown dispatch in " + "\033[1m\033[31m[ERROR]:\033[33m Unknown " + "dispatch in " "mousebind: \033[1m\033[31m%s\n", func_name); return false; @@ -2335,14 +2387,15 @@ bool parse_option(Config *config, char *key, char *value) { arg_value3[256] = "0\0", arg_value4[256] = "0\0", arg_value5[256] = "0\0"; if (sscanf(value, - "%255[^,],%255[^,],%255[^,],%255[^,],%255[^,],%255[^,],%255[" + "%255[^,],%255[^,],%255[^,],%255[^,],%255[^,],%255[^" + ",],%255[" "^,],%255[^\n]", mod_str, dir_str, func_name, arg_value, arg_value2, arg_value3, arg_value4, arg_value5) < 3) { - fprintf( - stderr, - "\033[1m\033[31m[ERROR]:\033[33m Invalid axisbind format: %s\n", - value); + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Invalid axisbind " + "format: %s\n", + value); return false; } @@ -2379,7 +2432,8 @@ bool parse_option(Config *config, char *key, char *value) { } if (!binding->func) fprintf(stderr, - "\033[1m\033[31m[ERROR]:\033[33m Unknown dispatch in " + "\033[1m\033[31m[ERROR]:\033[33m Unknown " + "dispatch in " "axisbind: \033[1m\033[31m%s\n", func_name); return false; @@ -2407,7 +2461,8 @@ bool parse_option(Config *config, char *key, char *value) { arg_value3[256] = "0\0", arg_value4[256] = "0\0", arg_value5[256] = "0\0"; if (sscanf(value, - "%255[^,],%255[^,],%255[^,],%255[^,],%255[^,],%255[^,],%255[" + "%255[^,],%255[^,],%255[^,],%255[^,],%255[^,],%255[^" + ",],%255[" "^\n]", fold_str, func_name, arg_value, arg_value2, arg_value3, arg_value4, arg_value5) < 3) { @@ -2474,7 +2529,8 @@ bool parse_option(Config *config, char *key, char *value) { arg_value3[256] = "0\0", arg_value4[256] = "0\0", arg_value5[256] = "0\0"; if (sscanf(value, - "%255[^,],%255[^,],%255[^,],%255[^,],%255[^,],%255[^,],%255[" + "%255[^,],%255[^,],%255[^,],%255[^,],%255[^,],%255[^" + ",],%255[" "^,],%255[^,],%255[^\n]", mod_str, motion_str, fingers_count_str, func_name, arg_value, arg_value2, arg_value3, arg_value4, arg_value5) < 4) { @@ -2520,7 +2576,8 @@ bool parse_option(Config *config, char *key, char *value) { } if (!binding->func) fprintf(stderr, - "\033[1m\033[31m[ERROR]:\033[33m Unknown dispatch in " + "\033[1m\033[31m[ERROR]:\033[33m Unknown " + "dispatch in " "axisbind: \033[1m\033[31m%s\n", func_name); return false; @@ -3134,8 +3191,8 @@ void set_value_default() { config.hotarea_size = hotarea_size; // 热区大小,10x10 config.hotarea_corner = hotarea_corner; config.enable_hotarea = enable_hotarea; // 是否启用鼠标热区 - config.smartgaps = - smartgaps; /* 1 means no outer gap when there is only one window */ + config.smartgaps = smartgaps; /* 1 means no outer gap when there is + only one window */ config.sloppyfocus = sloppyfocus; /* focus follows mouse */ config.gappih = gappih; /* horiz inner gap between windows */ config.gappiv = gappiv; /* vert inner gap between windows */ From 50b67ac539e65f68ae177de258c7f2fca59bc350 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Tue, 3 Feb 2026 10:15:42 +0800 Subject: [PATCH 478/591] fix: miss init arg value --- src/config/parse_config.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/config/parse_config.h b/src/config/parse_config.h index 1a025e90..e0193c49 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -2262,6 +2262,12 @@ bool parse_option(Config *config, char *key, char *value) { binding->keysymcode = parse_key(keysym_str, binding->keysymcode.type == KEY_TYPE_SYM); binding->mod = parse_mod(mod_str); + binding->arg.i = 0; + binding->arg.i2 = 0; + binding->arg.f = 0.0f; + binding->arg.f2 = 0.0f; + binding->arg.ui = 0; + binding->arg.ui2 = 0; binding->arg.v = NULL; binding->arg.v2 = NULL; binding->arg.v3 = NULL; @@ -2337,6 +2343,12 @@ bool parse_option(Config *config, char *key, char *value) { binding->mod = parse_mod(mod_str); binding->button = parse_button(button_str); + binding->arg.i = 0; + binding->arg.i2 = 0; + binding->arg.f = 0.0f; + binding->arg.f2 = 0.0f; + binding->arg.ui = 0; + binding->arg.ui2 = 0; binding->arg.v = NULL; binding->arg.v2 = NULL; binding->arg.v3 = NULL; @@ -2554,6 +2566,12 @@ bool parse_option(Config *config, char *key, char *value) { binding->mod = parse_mod(mod_str); binding->motion = parse_direction(motion_str); binding->fingers_count = atoi(fingers_count_str); + binding->arg.i = 0; + binding->arg.i2 = 0; + binding->arg.f = 0.0f; + binding->arg.f2 = 0.0f; + binding->arg.ui = 0; + binding->arg.ui2 = 0; binding->arg.v = NULL; binding->arg.v2 = NULL; binding->arg.v3 = NULL; From 336f873d83582a41188893fc0c0849867d28d589 Mon Sep 17 00:00:00 2001 From: quadratic Date: Tue, 3 Feb 2026 21:11:41 +0100 Subject: [PATCH 479/591] fix: uninitialised argument fields when calling mmsg -d --- src/config/parse_config.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/config/parse_config.h b/src/config/parse_config.h index e0193c49..3fcd5188 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -897,6 +897,12 @@ FuncType parse_func_name(char *func_name, Arg *arg, char *arg_value, char *arg_value5) { FuncType func = NULL; + (*arg).i = 0; + (*arg).i2 = 0; + (*arg).f = 0.0f; + (*arg).f2 = 0.0f; + (*arg).ui = 0; + (*arg).ui2 = 0; (*arg).v = NULL; (*arg).v2 = NULL; (*arg).v3 = NULL; From 8ba259fbb7737e4cef29ca20c731ed0a93e4017d Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Wed, 4 Feb 2026 09:45:26 +0800 Subject: [PATCH 480/591] opt: avoid opacity flickering in focus animation when open new window --- src/animation/client.h | 41 +++++++++++++-------------------------- src/config/parse_config.h | 12 ++++++------ src/mango.c | 6 ++++++ 3 files changed, 25 insertions(+), 34 deletions(-) diff --git a/src/animation/client.h b/src/animation/client.h index 7bc47ac0..8de9b068 100644 --- a/src/animation/client.h +++ b/src/animation/client.h @@ -1054,20 +1054,11 @@ void client_set_focused_opacity_animation(Client *c) { sizeof(c->opacity_animation.target_border_color)); c->opacity_animation.target_opacity = c->focused_opacity; c->opacity_animation.time_started = get_now_in_ms(); - if (c->opacity_animation.running) { - memcpy(c->opacity_animation.initial_border_color, - c->opacity_animation.current_border_color, - sizeof(c->opacity_animation.initial_border_color)); - c->opacity_animation.initial_opacity = - c->opacity_animation.current_opacity; - } else { - memcpy(c->opacity_animation.initial_border_color, bordercolor, - sizeof(c->opacity_animation.initial_border_color)); - memcpy(c->opacity_animation.current_border_color, bordercolor, - sizeof(c->opacity_animation.current_border_color)); - c->opacity_animation.initial_opacity = c->unfocused_opacity; - c->opacity_animation.current_opacity = c->unfocused_opacity; - } + memcpy(c->opacity_animation.initial_border_color, + c->opacity_animation.current_border_color, + sizeof(c->opacity_animation.initial_border_color)); + c->opacity_animation.initial_opacity = c->opacity_animation.current_opacity; + c->opacity_animation.running = true; } @@ -1087,20 +1078,10 @@ void client_set_unfocused_opacity_animation(Client *c) { c->opacity_animation.target_opacity = c->unfocused_opacity; c->opacity_animation.time_started = get_now_in_ms(); - if (c->opacity_animation.running) { - memcpy(c->opacity_animation.initial_border_color, - c->opacity_animation.current_border_color, - sizeof(c->opacity_animation.initial_border_color)); - c->opacity_animation.initial_opacity = - c->opacity_animation.current_opacity; - } else { - memcpy(c->opacity_animation.initial_border_color, border_color, - sizeof(c->opacity_animation.initial_border_color)); - memcpy(c->opacity_animation.current_border_color, border_color, - sizeof(c->opacity_animation.current_border_color)); - c->opacity_animation.initial_opacity = c->focused_opacity; - c->opacity_animation.current_opacity = c->focused_opacity; - } + memcpy(c->opacity_animation.initial_border_color, + c->opacity_animation.current_border_color, + sizeof(c->opacity_animation.initial_border_color)); + c->opacity_animation.initial_opacity = c->opacity_animation.current_opacity; c->opacity_animation.running = true; } @@ -1135,6 +1116,10 @@ bool client_apply_focus_opacity(Client *c) { if (target_opacity > opacity) { target_opacity = opacity; } + memcpy(c->opacity_animation.current_border_color, + c->opacity_animation.target_border_color, + sizeof(c->opacity_animation.current_border_color)); + c->opacity_animation.current_opacity = target_opacity; client_set_opacity(c, target_opacity); client_set_border_color(c, c->opacity_animation.target_border_color); } else if (animations && c->opacity_animation.running) { diff --git a/src/config/parse_config.h b/src/config/parse_config.h index 3fcd5188..efc9c962 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -897,12 +897,12 @@ FuncType parse_func_name(char *func_name, Arg *arg, char *arg_value, char *arg_value5) { FuncType func = NULL; - (*arg).i = 0; - (*arg).i2 = 0; - (*arg).f = 0.0f; - (*arg).f2 = 0.0f; - (*arg).ui = 0; - (*arg).ui2 = 0; + (*arg).i = 0; + (*arg).i2 = 0; + (*arg).f = 0.0f; + (*arg).f2 = 0.0f; + (*arg).ui = 0; + (*arg).ui2 = 0; (*arg).v = NULL; (*arg).v2 = NULL; (*arg).v3 = NULL; diff --git a/src/mango.c b/src/mango.c index f5583c30..2584613e 100644 --- a/src/mango.c +++ b/src/mango.c @@ -3825,6 +3825,12 @@ void init_client_properties(Client *c) { c->stack_proportion = 0.0f; c->next_in_stack = NULL; c->prev_in_stack = NULL; + memcpy(c->opacity_animation.initial_border_color, bordercolor, + sizeof(c->opacity_animation.initial_border_color)); + memcpy(c->opacity_animation.current_border_color, bordercolor, + sizeof(c->opacity_animation.current_border_color)); + c->opacity_animation.initial_opacity = c->unfocused_opacity; + c->opacity_animation.current_opacity = c->unfocused_opacity; } void // old fix to 0.5 From b0f839468c6b4a9bd5a037d380f2ed4ee2a89dfe Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Wed, 4 Feb 2026 17:42:13 +0800 Subject: [PATCH 481/591] opt: don't change stack inner per when swallow --- src/mango.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/mango.c b/src/mango.c index 2584613e..b37cc1fd 100644 --- a/src/mango.c +++ b/src/mango.c @@ -1071,6 +1071,9 @@ void swallow(Client *c, Client *w) { c->tags = w->tags; c->geom = w->geom; c->float_geom = w->float_geom; + c->stack_inner_per = w->stack_inner_per; + c->master_inner_per = w->master_inner_per; + c->master_mfact_per = w->master_mfact_per; c->scroller_proportion = w->scroller_proportion; c->next_in_stack = w->next_in_stack; c->prev_in_stack = w->prev_in_stack; @@ -4678,6 +4681,7 @@ setfloating(Client *c, int32_t floating) { Client *fc = NULL; struct wlr_box target_box; + int32_t old_floating_state = c->isfloating; c->isfloating = floating; bool window_size_outofrange = false; @@ -4747,7 +4751,7 @@ setfloating(Client *c, int32_t floating) { layers[c->isfloating ? LyrTop : LyrTile]); } - if (!c->isfloating) { + if (!c->isfloating && old_floating_state) { set_size_per(c->mon, c); } @@ -4796,6 +4800,7 @@ void setmaximizescreen(Client *c, int32_t maximizescreen) { if (c->mon->isoverview) return; + int32_t old_maximizescreen_state = c->ismaximizescreen; c->ismaximizescreen = maximizescreen; if (maximizescreen) { @@ -4825,7 +4830,7 @@ void setmaximizescreen(Client *c, int32_t maximizescreen) { wlr_scene_node_reparent(&c->scene->node, layers[c->isfloating ? LyrTop : LyrTile]); - if (!c->ismaximizescreen) { + if (!c->ismaximizescreen && old_maximizescreen_state) { set_size_per(c->mon, c); } @@ -4858,6 +4863,7 @@ void setfullscreen(Client *c, int32_t fullscreen) // 用自定义全屏代理自 if (c->mon->isoverview) return; + int32_t old_fullscreen_state = c->isfullscreen; c->isfullscreen = fullscreen; client_set_fullscreen(c, fullscreen); @@ -4895,7 +4901,7 @@ void setfullscreen(Client *c, int32_t fullscreen) // 用自定义全屏代理自 layers[fullscreen || c->isfloating ? LyrTop : LyrTile]); } - if (!c->isfullscreen) { + if (!c->isfullscreen && old_fullscreen_state) { set_size_per(c->mon, c); } From a4faf2c494cc09b95ff222959d7f3566d8234c1d Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Wed, 4 Feb 2026 21:29:37 +0800 Subject: [PATCH 482/591] opt: avoid stack inner per change when switch tty --- src/mango.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/mango.c b/src/mango.c index b37cc1fd..171401e7 100644 --- a/src/mango.c +++ b/src/mango.c @@ -5810,7 +5810,8 @@ void updatemons(struct wl_listener *listener, void *data) { if (selmon && selmon->wlr_output->enabled) { wl_list_for_each(c, &clients, link) { if (!c->mon && client_surface(c)->mapped) { - client_change_mon(c, selmon); + c->mon = selmon; + reset_foreign_tolevel(c); } } focusclient(focustop(selmon), 1); From 2bda8e3bf15b82676dc8765c7cf25c67e5041952 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Wed, 4 Feb 2026 21:42:05 +0800 Subject: [PATCH 483/591] opt: avoid double reset foreign toplevel handle --- src/mango.c | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/src/mango.c b/src/mango.c index 171401e7..591d4f65 100644 --- a/src/mango.c +++ b/src/mango.c @@ -969,7 +969,6 @@ static struct wlr_xwayland *xwayland; void client_change_mon(Client *c, Monitor *m) { setmon(c, m, c->tags, true); - reset_foreign_tolevel(c); if (c->isfloating) { c->float_geom = c->geom = setclient_coordinate_center(c, c->mon, c->geom, 0, 0); @@ -2026,7 +2025,6 @@ buttonpress(struct wl_listener *listener, void *data) { selmon = xytomon(cursor->x, cursor->y); client_update_oldmonname_record(grabc, selmon); setmon(grabc, selmon, 0, true); - reset_foreign_tolevel(grabc); selmon->prevsel = ISTILED(selmon->sel) ? selmon->sel : NULL; selmon->sel = grabc; tmpc = grabc; @@ -5030,6 +5028,7 @@ void setmon(Client *c, Monitor *m, uint32_t newtags, bool focus) { arrange(oldmon, false, false); if (m) { /* Make sure window actually overlaps with the monitor */ + reset_foreign_tolevel(c); resize(c, c->geom, 0); c->tags = newtags ? newtags @@ -5041,21 +5040,6 @@ void setmon(Client *c, Monitor *m, uint32_t newtags, bool focus) { if (focus && !client_is_x11_popup(c)) { focusclient(focustop(selmon), 1); } - - if (m) { - - if (c->foreign_toplevel) { - remove_foreign_topleve(c); - } - - add_foreign_toplevel(c); - if (m->sel && m->sel->foreign_toplevel) - wlr_foreign_toplevel_handle_v1_set_activated( - m->sel->foreign_toplevel, false); - if (c->foreign_toplevel) - wlr_foreign_toplevel_handle_v1_set_activated(c->foreign_toplevel, - true); - } } void setpsel(struct wl_listener *listener, void *data) { From 65fcd58949ce55eca3195bdbc6f935058fc3b33c Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Wed, 4 Feb 2026 21:50:44 +0800 Subject: [PATCH 484/591] opt: optimize file detect message --- src/config/parse_config.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/config/parse_config.h b/src/config/parse_config.h index efc9c962..a5594327 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -2683,7 +2683,10 @@ void parse_config_file(Config *config, const char *file_path) { } if (!file) { - perror("Error opening file"); + fprintf(stderr, + "\033[1;31m\033[1;33m[ERROR]:\033[0m Failed to open " + "config file: %s\n", + file_path); return; } From 8e898417a75bc48cdc79409dba2b415f692d7ea6 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Thu, 5 Feb 2026 11:06:40 +0800 Subject: [PATCH 485/591] opt: key name case insensitive in keybind --- src/config/parse_config.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/config/parse_config.h b/src/config/parse_config.h index a5594327..b795a817 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -779,8 +779,9 @@ KeySymCode parse_key(const char *key_str, bool isbindsym) { return kc; } - // 普通键名直接转换 - xkb_keysym_t sym = xkb_keysym_from_name(key_str, XKB_KEYSYM_NO_FLAGS); + // change key string to keysym, case insensitive + xkb_keysym_t sym = + xkb_keysym_from_name(key_str, XKB_KEYSYM_CASE_INSENSITIVE); if (isbindsym) { kc.type = KEY_TYPE_SYM; From 00a7e579c94bd786cf1fd379b5b666e475dd4735 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Fri, 6 Feb 2026 07:43:09 +0800 Subject: [PATCH 486/591] fix: miss reset root color when reload config --- src/config/parse_config.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/config/parse_config.h b/src/config/parse_config.h index b795a817..7e24d43f 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -3558,6 +3558,8 @@ void reapply_cursor_style(void) { } } +void reapply_rootbg(void) { wlr_scene_rect_set_color(root_bg, rootcolor); } + void reapply_border(void) { Client *c = NULL; @@ -3683,6 +3685,7 @@ void reset_option(void) { reapply_cursor_style(); reapply_border(); + reapply_rootbg(); reapply_keyboard(); reapply_pointer(); reapply_master(); From 080dfaa3ae41cca9d02df9a529ed6a65edb97b41 Mon Sep 17 00:00:00 2001 From: Talmed Date: Fri, 6 Feb 2026 19:04:16 +1100 Subject: [PATCH 487/591] Add DesktopNames entry to mango.desktop --- mango.desktop | 1 + 1 file changed, 1 insertion(+) diff --git a/mango.desktop b/mango.desktop index 0c109cea..37c4fad0 100644 --- a/mango.desktop +++ b/mango.desktop @@ -1,6 +1,7 @@ [Desktop Entry] Encoding=UTF-8 Name=Mango +DesktopNames=mango;wlroots Comment=mango WM Exec=mango Icon=mango From 818652d20f43598b245199cac9329edebbbbbae4 Mon Sep 17 00:00:00 2001 From: Lin Xianyi Date: Sat, 7 Feb 2026 12:12:13 +0800 Subject: [PATCH 488/591] fix: -p exits with failure if there are parse failures --- src/config/parse_config.h | 25 +++++++++++++++---------- src/mango.c | 3 +-- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/src/config/parse_config.h b/src/config/parse_config.h index 7e24d43f..b8426e2d 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -362,7 +362,7 @@ typedef struct { typedef int32_t (*FuncType)(const Arg *); Config config; -void parse_config_file(Config *config, const char *file_path); +bool parse_config_file(Config *config, const char *file_path); // Helper function to trim whitespace from start and end of a string void trim_whitespace(char *str) { @@ -2639,7 +2639,7 @@ bool parse_config_line(Config *config, const char *line) { return parse_option(config, key, value); } -void parse_config_file(Config *config, const char *file_path) { +bool parse_config_file(Config *config, const char *file_path) { FILE *file; char full_path[1024]; @@ -2658,7 +2658,7 @@ void parse_config_file(Config *config, const char *file_path) { fprintf(stderr, "\033[1m\033[31m[ERROR]:\033[33m HOME environment " "variable not set.\n"); - return; + return false; } snprintf(full_path, sizeof(full_path), "%s/.config/mango/%s", home, file_path + 1); @@ -2673,7 +2673,7 @@ void parse_config_file(Config *config, const char *file_path) { if (!home) { fprintf(stderr, "\033[1m\033[31m[ERROR]:\033[33m HOME environment " "variable not set.\n"); - return; + return false; } snprintf(full_path, sizeof(full_path), "%s%s", home, file_path + 1); file = fopen(full_path, "r"); @@ -2688,19 +2688,21 @@ void parse_config_file(Config *config, const char *file_path) { "\033[1;31m\033[1;33m[ERROR]:\033[0m Failed to open " "config file: %s\n", file_path); - return; + return false; } char line[512]; bool parse_correct = true; + bool parse_line_correct = true; uint32_t line_count = 0; while (fgets(line, sizeof(line), file)) { line_count++; if (line[0] == '#' || line[0] == '\n') { continue; } - parse_correct = parse_config_line(config, line); - if (!parse_correct) { + parse_line_correct = parse_config_line(config, line); + if (!parse_line_correct) { + parse_correct = false; fprintf(stderr, "\033[1;31m╰─\033[1;33m[Index]\033[0m " "\033[1;36m%s\033[0m:\033[1;35m%d\033[0m\n" @@ -2710,6 +2712,7 @@ void parse_config_file(Config *config, const char *file_path) { } fclose(file); + return parse_correct; } void free_circle_layout(Config *config) { @@ -3369,7 +3372,7 @@ void set_default_key_bindings(Config *config) { config->key_bindings_count += default_key_bindings_count; } -void parse_config(void) { +bool parse_config(void) { char filename[1024]; @@ -3422,7 +3425,7 @@ void parse_config(void) { const char *homedir = getenv("HOME"); if (!homedir) { // 如果获取失败,则无法继续 - return; + return false; } // 构建日志文件路径 snprintf(filename, sizeof(filename), "%s/.config/mango/config.conf", @@ -3436,10 +3439,12 @@ void parse_config(void) { } } + bool parse_correct = true; set_value_default(); - parse_config_file(&config, filename); + parse_correct = parse_config_file(&config, filename); set_default_key_bindings(&config); override_config(); + return parse_correct; } void reset_blur_params(void) { diff --git a/src/mango.c b/src/mango.c index 591d4f65..6b8a3903 100644 --- a/src/mango.c +++ b/src/mango.c @@ -6168,8 +6168,7 @@ int32_t main(int32_t argc, char *argv[]) { } else if (c == 'c') { cli_config_path = optarg; } else if (c == 'p') { - parse_config(); - return EXIT_SUCCESS; + return parse_config() ? EXIT_SUCCESS : EXIT_FAILURE; } else { goto usage; } From 2734d91e6aec9992d0647b447cd0bf23f2bda84a Mon Sep 17 00:00:00 2001 From: Lin Xianyi Date: Sat, 7 Feb 2026 13:31:30 +0800 Subject: [PATCH 489/591] fix: improve help message for mmsg --- mmsg/mmsg.c | 47 +++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 41 insertions(+), 6 deletions(-) diff --git a/mmsg/mmsg.c b/mmsg/mmsg.c index ba073aad..ab87b2b1 100644 --- a/mmsg/mmsg.c +++ b/mmsg/mmsg.c @@ -500,12 +500,47 @@ static const struct wl_registry_listener registry_listener = { static void usage(void) { fprintf(stderr, - "usage:" - "\t%s [-OTLq]\n" - "\t%s [-o ] -s [-t ] [-l ] [-c ] [-d " - ",,,,,]\n" - "\t%s [-o ] (-g | -w) [-OotlcvmfxekbA]\n", - argv0, argv0, argv0); + "mmsg - MangoWC IPC\n" + "\n" + "SYNOPSIS:\n" + "\tmmsg [-OTLq]\n" + "\tmmsg [-o ] -s [-t ] [-l ] [-c ] [-d ,,,,,]\n" + "\tmmsg [-o ] (-g | -w) [-OotlcvmfxekbA]\n" + "\n" + "OPERATION MODES:\n" + "\t-g Get values (tags, layout, focused client)\n" + "\t-s Set values (switch tags, layouts)\n" + "\t-w Watch mode (stream events)\n" + "\n" + "GENERAL OPTIONS:\n" + "\t-O Get all output (monitor) information\n" + "\t-T Get number of tags\n" + "\t-L Get all available layouts\n" + "\t-q Quit MangoWC\n" + "\t-o Select output (monitor)\n" + "\n" + "GET OPTIONS (used with -g or -w):\n" + "\t-O Get output name\n" + "\t-o Get output (monitor) focus information\n" + "\t-t Get selected tags\n" + "\t-l Get current layout\n" + "\t-c Get title and appid of focused clients\n" + "\t-v Get visibility of statusbar\n" + "\t-m Get fullscreen status\n" + "\t-f Get floating status\n" + "\t-x Get focused client geometry\n" + "\t-e Get name of last focused layer\n" + "\t-k Get current keyboard layout\n" + "\t-b Get current keybind mode\n" + "\t-A Get scale factor of monitor\n" + "\n" + "SET OPTIONS (used with -s):\n" + "\t-o Select output (monitor)\n" + "\t-t Set selected tags (can be used with [+-^.] modifiers)\n" + "\t-l Set current layout\n" + "\t-c Get title and appid of focused client\n" + "\t-d , Dispatch internal command (max 5 args)\n" + ); exit(2); } From f8dfeedff1f88e16338c392f50baa7f4f965726e Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sat, 7 Feb 2026 14:04:42 +0800 Subject: [PATCH 490/591] fix: headless backend cant use keybarod and pointer --- src/mango.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/mango.c b/src/mango.c index 6b8a3903..dcd2753b 100644 --- a/src/mango.c +++ b/src/mango.c @@ -3419,7 +3419,9 @@ void requestmonstate(struct wl_listener *listener, void *data) { void inputdevice(struct wl_listener *listener, void *data) { /* This event is raised by the backend when a new input device becomes - * available. */ + * available. + * when the backend is a headless backend, this event will never be triggered. + */ struct wlr_input_device *device = data; uint32_t caps; @@ -5973,6 +5975,8 @@ void handle_keyboard_shortcuts_inhibit_new_inhibitor( void virtualkeyboard(struct wl_listener *listener, void *data) { struct wlr_virtual_keyboard_v1 *kb = data; /* virtual keyboards shouldn't share keyboard group */ + wlr_seat_set_capabilities(seat, + seat->capabilities | WL_SEAT_CAPABILITY_KEYBOARD); KeyboardGroup *group = createkeyboardgroup(); /* Set the keymap to match the group keymap */ wlr_keyboard_set_keymap(&kb->keyboard, group->wlr_group->keyboard.keymap); @@ -6003,7 +6007,8 @@ void warp_cursor_to_selmon(Monitor *m) { void virtualpointer(struct wl_listener *listener, void *data) { struct wlr_virtual_pointer_v1_new_pointer_event *event = data; struct wlr_input_device *device = &event->new_pointer->pointer.base; - + wlr_seat_set_capabilities(seat, + seat->capabilities | WL_SEAT_CAPABILITY_POINTER); wlr_cursor_attach_input_device(cursor, device); if (event->suggested_output) wlr_cursor_map_input_to_output(cursor, device, event->suggested_output); From 3db2ac58b4220dcf1b2e5e2266ed661c4ea31578 Mon Sep 17 00:00:00 2001 From: Yujonpradhananga Date: Fri, 6 Feb 2026 15:18:31 +0545 Subject: [PATCH 491/591] opt: fix spelling mistake --- README.md | 2 +- src/animation/client.h | 74 +++++++++++++++++++++--------------------- src/client/client.h | 4 +-- 3 files changed, 40 insertions(+), 40 deletions(-) diff --git a/README.md b/README.md index d512f39f..8aaaeb9b 100644 --- a/README.md +++ b/README.md @@ -75,7 +75,7 @@ https://github.com/user-attachments/assets/014c893f-115c-4ae9-8342-f9ae3e9a0df0 - libxcb ## Arch Linux -The package is in the Arch User Repository and is availble for manual download [here](https://aur.archlinux.org/packages/mangowc-git) or through a AUR helper like yay: +The package is in the Arch User Repository and is available for manual download [here](https://aur.archlinux.org/packages/mangowc-git) or through a AUR helper like yay: ```bash yay -S mangowc-git diff --git a/src/animation/client.h b/src/animation/client.h index 8de9b068..2588fb1c 100644 --- a/src/animation/client.h +++ b/src/animation/client.h @@ -47,7 +47,7 @@ bool is_horizontal_right_stack_layout(Monitor *m) { return false; } -int32_t is_special_animaiton_rule(Client *c) { +int32_t is_special_animation_rule(Client *c) { if (is_scroller_layout(c->mon) && !c->isfloating) { return DOWN; @@ -70,7 +70,7 @@ int32_t is_special_animaiton_rule(Client *c) { } } -void set_client_open_animaiton(Client *c, struct wlr_box geo) { +void set_client_open_animation(Client *c, struct wlr_box geo) { int32_t slide_direction; int32_t horizontal, horizontal_value; int32_t vertical, vertical_value; @@ -96,7 +96,7 @@ void set_client_open_animaiton(Client *c, struct wlr_box geo) { geo.y + (geo.height - c->animainit_geom.height) / 2; return; } else { - special_direction = is_special_animaiton_rule(c); + special_direction = is_special_animation_rule(c); center_x = c->geom.x + c->geom.width / 2; center_y = c->geom.y + c->geom.height / 2; if (special_direction == UNDIR) { @@ -772,71 +772,71 @@ void init_fadeout_client(Client *c) { return; } - Client *fadeout_cient = ecalloc(1, sizeof(*fadeout_cient)); + Client *fadeout_client = ecalloc(1, sizeof(*fadeout_client)); wlr_scene_node_set_enabled(&c->scene->node, true); client_set_border_color(c, bordercolor); - fadeout_cient->scene = + fadeout_client->scene = wlr_scene_tree_snapshot(&c->scene->node, layers[LyrFadeOut]); wlr_scene_node_set_enabled(&c->scene->node, false); - if (!fadeout_cient->scene) { - free(fadeout_cient); + if (!fadeout_client->scene) { + free(fadeout_client); return; } - fadeout_cient->animation.duration = animation_duration_close; - fadeout_cient->geom = fadeout_cient->current = - fadeout_cient->animainit_geom = fadeout_cient->animation.initial = + fadeout_client->animation.duration = animation_duration_close; + fadeout_client->geom = fadeout_client->current = + fadeout_client->animainit_geom = fadeout_client->animation.initial = c->animation.current; - fadeout_cient->mon = c->mon; - fadeout_cient->animation_type_close = c->animation_type_close; - fadeout_cient->animation.action = CLOSE; - fadeout_cient->bw = c->bw; - fadeout_cient->nofadeout = c->nofadeout; + fadeout_client->mon = c->mon; + fadeout_client->animation_type_close = c->animation_type_close; + fadeout_client->animation.action = CLOSE; + fadeout_client->bw = c->bw; + fadeout_client->nofadeout = c->nofadeout; // 这里snap节点的坐标设置是使用的相对坐标,所以不能加上原来坐标 // 这跟普通node有区别 - fadeout_cient->animation.initial.x = 0; - fadeout_cient->animation.initial.y = 0; + fadeout_client->animation.initial.x = 0; + fadeout_client->animation.initial.y = 0; if ((!c->animation_type_close && strcmp(animation_type_close, "fade") == 0) || (c->animation_type_close && strcmp(c->animation_type_close, "fade") == 0)) { - fadeout_cient->current.x = 0; - fadeout_cient->current.y = 0; - fadeout_cient->current.width = 0; - fadeout_cient->current.height = 0; + fadeout_client->current.x = 0; + fadeout_client->current.y = 0; + fadeout_client->current.width = 0; + fadeout_client->current.height = 0; } else if ((c->animation_type_close && strcmp(c->animation_type_close, "slide") == 0) || (!c->animation_type_close && strcmp(animation_type_close, "slide") == 0)) { - fadeout_cient->current.y = + fadeout_client->current.y = c->geom.y + c->geom.height / 2 > c->mon->m.y + c->mon->m.height / 2 ? c->mon->m.height - (c->animation.current.y - c->mon->m.y) // down out : c->mon->m.y - c->geom.height; // up out - fadeout_cient->current.x = 0; // x无偏差,垂直划出 + fadeout_client->current.x = 0; // x无偏差,垂直划出 } else { - fadeout_cient->current.y = - (fadeout_cient->geom.height - - fadeout_cient->geom.height * zoom_end_ratio) / + fadeout_client->current.y = + (fadeout_client->geom.height - + fadeout_client->geom.height * zoom_end_ratio) / 2; - fadeout_cient->current.x = - (fadeout_cient->geom.width - - fadeout_cient->geom.width * zoom_end_ratio) / + fadeout_client->current.x = + (fadeout_client->geom.width - + fadeout_client->geom.width * zoom_end_ratio) / 2; - fadeout_cient->current.width = - fadeout_cient->geom.width * zoom_end_ratio; - fadeout_cient->current.height = - fadeout_cient->geom.height * zoom_end_ratio; + fadeout_client->current.width = + fadeout_client->geom.width * zoom_end_ratio; + fadeout_client->current.height = + fadeout_client->geom.height * zoom_end_ratio; } - fadeout_cient->animation.time_started = get_now_in_ms(); - wlr_scene_node_set_enabled(&fadeout_cient->scene->node, true); - wl_list_insert(&fadeout_clients, &fadeout_cient->fadeout_link); + fadeout_client->animation.time_started = get_now_in_ms(); + wlr_scene_node_set_enabled(&fadeout_client->scene->node, true); + wl_list_insert(&fadeout_clients, &fadeout_client->fadeout_link); // 请求刷新屏幕 request_fresh_all_monitors(); @@ -971,7 +971,7 @@ void resize(Client *c, struct wlr_box geo, int32_t interact) { c->animainit_geom.height = c->animation.current.height; c->animainit_geom.width = c->animation.current.width; } else if (c->is_pending_open_animation) { - set_client_open_animaiton(c, c->geom); + set_client_open_animation(c, c->geom); } else { c->animainit_geom = c->animation.current; } diff --git a/src/client/client.h b/src/client/client.h index 8995a5d0..49ab3988 100644 --- a/src/client/client.h +++ b/src/client/client.h @@ -254,7 +254,7 @@ static inline int32_t client_is_stopped(Client *c) { wl_client_get_credentials(c->surface.xdg->client->client, &pid, NULL, NULL); if (waitid(P_PID, pid, &in, WNOHANG | WCONTINUED | WSTOPPED | WNOWAIT) < 0) { - /* This process is not our child process, while is very unluckely that + /* This process is not our child process, while is very unlikely that * it is stopped, in order to do not skip frames assume that it is. */ if (errno == ECHILD) return 1; @@ -547,4 +547,4 @@ static inline void client_set_size_bound(Client *c) { state.max_height > 0) { c->geom.height = state.max_height + 2 * c->bw; } -} \ No newline at end of file +} From e658f5c90d7e5337bd90cf818bc7428cae44bcd3 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sat, 7 Feb 2026 19:57:07 +0800 Subject: [PATCH 492/591] opt: fix format --- mmsg/mmsg.c | 9 +++++---- src/mango.c | 5 +++-- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/mmsg/mmsg.c b/mmsg/mmsg.c index ab87b2b1..fb1d04fd 100644 --- a/mmsg/mmsg.c +++ b/mmsg/mmsg.c @@ -504,7 +504,8 @@ static void usage(void) { "\n" "SYNOPSIS:\n" "\tmmsg [-OTLq]\n" - "\tmmsg [-o ] -s [-t ] [-l ] [-c ] [-d ,,,,,]\n" + "\tmmsg [-o ] -s [-t ] [-l ] [-c ] [-d " + ",,,,,]\n" "\tmmsg [-o ] (-g | -w) [-OotlcvmfxekbA]\n" "\n" "OPERATION MODES:\n" @@ -536,11 +537,11 @@ static void usage(void) { "\n" "SET OPTIONS (used with -s):\n" "\t-o Select output (monitor)\n" - "\t-t Set selected tags (can be used with [+-^.] modifiers)\n" + "\t-t Set selected tags (can be used with [+-^.] " + "modifiers)\n" "\t-l Set current layout\n" "\t-c Get title and appid of focused client\n" - "\t-d , Dispatch internal command (max 5 args)\n" - ); + "\t-d , Dispatch internal command (max 5 args)\n"); exit(2); } diff --git a/src/mango.c b/src/mango.c index dcd2753b..8883181e 100644 --- a/src/mango.c +++ b/src/mango.c @@ -3419,8 +3419,9 @@ void requestmonstate(struct wl_listener *listener, void *data) { void inputdevice(struct wl_listener *listener, void *data) { /* This event is raised by the backend when a new input device becomes - * available. - * when the backend is a headless backend, this event will never be triggered. + * available. + * when the backend is a headless backend, this event will never be + * triggered. */ struct wlr_input_device *device = data; uint32_t caps; From 9b92f139c06d319d9fc6066ee194b967b672e369 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sat, 7 Feb 2026 21:46:18 +0800 Subject: [PATCH 493/591] fix: correct dmabuf version --- src/mango.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mango.c b/src/mango.c index 8883181e..d75faed0 100644 --- a/src/mango.c +++ b/src/mango.c @@ -5180,7 +5180,7 @@ void setup(void) { if (wlr_renderer_get_texture_formats(drw, WLR_BUFFER_CAP_DMABUF)) { wlr_drm_create(dpy, drw); wlr_scene_set_linux_dmabuf_v1( - scene, wlr_linux_dmabuf_v1_create_with_renderer(dpy, 5, drw)); + scene, wlr_linux_dmabuf_v1_create_with_renderer(dpy, 4, drw)); } if (syncobj_enable && (drm_fd = wlr_renderer_get_drm_fd(drw)) >= 0 && From 5de87db8ca5870d37a181a4eaf4e8559f04397dc Mon Sep 17 00:00:00 2001 From: Lin Xianyi Date: Sun, 8 Feb 2026 10:46:18 +0800 Subject: [PATCH 494/591] feat: add a source-optional keyword --- src/config/parse_config.h | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/src/config/parse_config.h b/src/config/parse_config.h index b8426e2d..a7959617 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -362,7 +362,7 @@ typedef struct { typedef int32_t (*FuncType)(const Arg *); Config config; -bool parse_config_file(Config *config, const char *file_path); +bool parse_config_file(Config *config, const char *file_path, bool must_exist); // Helper function to trim whitespace from start and end of a string void trim_whitespace(char *str) { @@ -2610,8 +2610,10 @@ bool parse_option(Config *config, char *key, char *value) { config->gesture_bindings_count++; } + } else if (strncmp(key, "source-optional", 15) == 0) { + parse_config_file(config, value, false); } else if (strncmp(key, "source", 6) == 0) { - parse_config_file(config, value); + parse_config_file(config, value, true); } else { fprintf(stderr, "\033[1m\033[31m[ERROR]:\033[33m Unknown keyword: " @@ -2639,7 +2641,7 @@ bool parse_config_line(Config *config, const char *line) { return parse_option(config, key, value); } -bool parse_config_file(Config *config, const char *file_path) { +bool parse_config_file(Config *config, const char *file_path, bool must_exist) { FILE *file; char full_path[1024]; @@ -2684,11 +2686,15 @@ bool parse_config_file(Config *config, const char *file_path) { } if (!file) { - fprintf(stderr, - "\033[1;31m\033[1;33m[ERROR]:\033[0m Failed to open " - "config file: %s\n", - file_path); - return false; + if (must_exist) { + fprintf(stderr, + "\033[1;31m\033[1;33m[ERROR]:\033[0m Failed to open " + "config file: %s\n", + file_path); + return false; + } else { + return true; + } } char line[512]; @@ -3441,7 +3447,7 @@ bool parse_config(void) { bool parse_correct = true; set_value_default(); - parse_correct = parse_config_file(&config, filename); + parse_correct = parse_config_file(&config, filename, true); set_default_key_bindings(&config); override_config(); return parse_correct; From 241afb4b9770a3bb7de2d28966a4298b059f61c0 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sun, 8 Feb 2026 11:18:38 +0800 Subject: [PATCH 495/591] fix: warpcursor not apply in some case --- src/mango.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/mango.c b/src/mango.c index d75faed0..54262812 100644 --- a/src/mango.c +++ b/src/mango.c @@ -5989,8 +5989,7 @@ void virtualkeyboard(struct wl_listener *listener, void *data) { } void warp_cursor(const Client *c) { - if (cursor->x < c->geom.x || cursor->x > c->geom.x + c->geom.width || - cursor->y < c->geom.y || cursor->y > c->geom.y + c->geom.height) { + if (INSIDEMON(c)) { wlr_cursor_warp_closest(cursor, NULL, c->geom.x + c->geom.width / 2.0, c->geom.y + c->geom.height / 2.0); motionnotify(0, NULL, 0, 0, 0, 0); From faf2e1e9da2290d08592f3f625640487b2eeb494 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sun, 8 Feb 2026 12:13:04 +0800 Subject: [PATCH 496/591] opt: sync keymap to xwayland after xwayland ready --- src/dispatch/bind_define.h | 5 ----- src/mango.c | 16 +++++++++++++++- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index c0e51dc2..1d29bc97 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -907,9 +907,7 @@ int32_t switch_keyboard_layout(const Arg *arg) { uint32_t latched = keyboard->modifiers.latched; uint32_t locked = keyboard->modifiers.locked; - wlr_keyboard_set_keymap(keyboard, keyboard->keymap); wlr_keyboard_notify_modifiers(keyboard, depressed, latched, locked, next); - keyboard->modifiers.group = 0; // 7. 更新 seat wlr_seat_set_keyboard(seat, keyboard); @@ -923,10 +921,7 @@ int32_t switch_keyboard_layout(const Arg *arg) { struct wlr_keyboard *tkb = (struct wlr_keyboard *)id->device_data; - wlr_keyboard_set_keymap(tkb, keyboard->keymap); wlr_keyboard_notify_modifiers(tkb, depressed, latched, locked, next); - tkb->modifiers.group = 0; - // 7. 更新 seat wlr_seat_set_keyboard(seat, tkb); wlr_seat_keyboard_notify_modifiers(seat, &tkb->modifiers); diff --git a/src/mango.c b/src/mango.c index 54262812..6609270c 100644 --- a/src/mango.c +++ b/src/mango.c @@ -730,6 +730,7 @@ static void set_rect_size(struct wlr_scene_rect *rect, int32_t width, static Client *center_tiled_select(Monitor *m); static void handlecursoractivity(void); static int32_t hidecursor(void *data); +static int32_t synckeymap(void *data); static bool check_hit_no_border(Client *c); static void reset_keyboard_layout(void); static void client_update_oldmonname_record(Client *c, Monitor *m); @@ -876,6 +877,7 @@ struct dvec2 *baked_points_opafadein; struct dvec2 *baked_points_opafadeout; static struct wl_event_source *hide_source; +static struct wl_event_source *sync_keymap; static bool cursor_hidden = false; static bool tag_combo = false; static const char *cli_config_path = NULL; @@ -5327,7 +5329,8 @@ void setup(void) { &request_set_cursor_shape); hide_source = wl_event_loop_add_timer(wl_display_get_event_loop(dpy), hidecursor, cursor); - + sync_keymap = wl_event_loop_add_timer(wl_display_get_event_loop(dpy), + synckeymap, NULL); /* * Configures a seat, which is a single "seat" at which a user sits and * operates the computer. This conceptually includes up to one keyboard, @@ -5556,6 +5559,13 @@ int32_t hidecursor(void *data) { return 1; } +int32_t synckeymap(void *data) { + reset_keyboard_layout(); + // we only need to sync keymap once + wl_event_source_timer_update(sync_keymap, 0); + return 1; +} + void unlocksession(struct wl_listener *listener, void *data) { SessionLock *lock = wl_container_of(listener, lock, unlock); destroylock(lock, 1); @@ -6147,6 +6157,10 @@ void xwaylandready(struct wl_listener *listener, void *data) { xwayland, xcursor->images[0]->buffer, xcursor->images[0]->width * 4, xcursor->images[0]->width, xcursor->images[0]->height, xcursor->images[0]->hotspot_x, xcursor->images[0]->hotspot_y); + /* xwayland can't auto sync the keymap, so we do it manually + and we need to wait the xwayland completely inited + */ + wl_event_source_timer_update(sync_keymap, 500); } static void setgeometrynotify(struct wl_listener *listener, void *data) { From 4820b7a8abe95c9319ccc76642607a7ab9e7992a Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sun, 8 Feb 2026 12:15:44 +0800 Subject: [PATCH 497/591] feat: allow single mod keybind --- src/mango.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/mango.c b/src/mango.c index 6609270c..e15b08fe 100644 --- a/src/mango.c +++ b/src/mango.c @@ -3495,11 +3495,6 @@ keybinding(uint32_t state, bool locked, uint32_t mods, xkb_keysym_t sym, int32_t ji; int32_t isbreak = 0; - // not allow modifier keys to be used as a keybinding - if (keycode == 50 || keycode == 37 || keycode == 133 || keycode == 64 || - keycode == 62 || keycode == 108 || keycode == 105 || keycode == 134) - return false; - if (is_keyboard_shortcut_inhibitor(seat->keyboard_state.focused_surface)) { return false; } From e8bf6380fba8b7acf7b29f178d9dba8e3481eb16 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sun, 8 Feb 2026 12:44:56 +0800 Subject: [PATCH 498/591] opt: turn keymap sync into XWAYLAND macro --- src/mango.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/mango.c b/src/mango.c index e15b08fe..d6876c5b 100644 --- a/src/mango.c +++ b/src/mango.c @@ -730,7 +730,6 @@ static void set_rect_size(struct wlr_scene_rect *rect, int32_t width, static Client *center_tiled_select(Monitor *m); static void handlecursoractivity(void); static int32_t hidecursor(void *data); -static int32_t synckeymap(void *data); static bool check_hit_no_border(Client *c); static void reset_keyboard_layout(void); static void client_update_oldmonname_record(Client *c, Monitor *m); @@ -877,7 +876,6 @@ struct dvec2 *baked_points_opafadein; struct dvec2 *baked_points_opafadeout; static struct wl_event_source *hide_source; -static struct wl_event_source *sync_keymap; static bool cursor_hidden = false; static bool tag_combo = false; static const char *cli_config_path = NULL; @@ -944,6 +942,7 @@ static struct wl_listener keyboard_shortcuts_inhibit_new_inhibitor = { .notify = handle_keyboard_shortcuts_inhibit_new_inhibitor}; #ifdef XWAYLAND +static int32_t synckeymap(void *data); static void activatex11(struct wl_listener *listener, void *data); static void configurex11(struct wl_listener *listener, void *data); static void createnotifyx11(struct wl_listener *listener, void *data); @@ -955,6 +954,7 @@ static void setgeometrynotify(struct wl_listener *listener, void *data); static struct wl_listener new_xwayland_surface = {.notify = createnotifyx11}; static struct wl_listener xwayland_ready = {.notify = xwaylandready}; static struct wlr_xwayland *xwayland; +static struct wl_event_source *sync_keymap; #endif #include "animation/client.h" @@ -5324,8 +5324,6 @@ void setup(void) { &request_set_cursor_shape); hide_source = wl_event_loop_add_timer(wl_display_get_event_loop(dpy), hidecursor, cursor); - sync_keymap = wl_event_loop_add_timer(wl_display_get_event_loop(dpy), - synckeymap, NULL); /* * Configures a seat, which is a single "seat" at which a user sits and * operates the computer. This conceptually includes up to one keyboard, @@ -5417,6 +5415,8 @@ void setup(void) { fprintf(stderr, "failed to setup XWayland X server, continuing without it\n"); } + sync_keymap = wl_event_loop_add_timer(wl_display_get_event_loop(dpy), + synckeymap, NULL); #endif } @@ -5554,13 +5554,6 @@ int32_t hidecursor(void *data) { return 1; } -int32_t synckeymap(void *data) { - reset_keyboard_layout(); - // we only need to sync keymap once - wl_event_source_timer_update(sync_keymap, 0); - return 1; -} - void unlocksession(struct wl_listener *listener, void *data) { SessionLock *lock = wl_container_of(listener, lock, unlock); destroylock(lock, 1); @@ -6022,6 +6015,13 @@ void virtualpointer(struct wl_listener *listener, void *data) { } #ifdef XWAYLAND +int32_t synckeymap(void *data) { + reset_keyboard_layout(); + // we only need to sync keymap once + wl_event_source_timer_update(sync_keymap, 0); + return 1; +} + void activatex11(struct wl_listener *listener, void *data) { Client *c = wl_container_of(listener, c, activate); bool need_arrange = false; From 69703158223d53e4d40f43a055c6af7d5bc98b6f Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sun, 8 Feb 2026 18:17:55 +0800 Subject: [PATCH 499/591] Update README.md --- README.md | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/README.md b/README.md index 8aaaeb9b..b78ccfa9 100644 --- a/README.md +++ b/README.md @@ -24,18 +24,7 @@ This project's development is based on [dwl](https://codeberg.org/dwl/dwl/). - Hycov-like overview - Window effects from scenefx (blur, shadow, corner radius, opacity) -Master-Stack Layout - -https://github.com/user-attachments/assets/a9d4776e-b50b-48fb-94ce-651d8a749b8a - -Scroller Layout - -https://github.com/user-attachments/assets/c9bf9415-fad1-4400-bcdc-3ad2d76de85a - -Layer animation - -https://github.com/user-attachments/assets/014c893f-115c-4ae9-8342-f9ae3e9a0df0 - +https://github.com/user-attachments/assets/bb83004a-0563-4b48-ad89-6461a9b78b1f # Our discord [mangowc](https://discord.gg/CPjbDxesh5) From 454145f6e03a462b743c64776d2b17121c2637ea Mon Sep 17 00:00:00 2001 From: Daniel Jampen Date: Sun, 8 Feb 2026 17:56:26 +0100 Subject: [PATCH 500/591] support isfakefullscreen as windowrule property --- src/config/parse_config.h | 4 ++++ src/mango.c | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/src/config/parse_config.h b/src/config/parse_config.h index 7e24d43f..49936de3 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -58,6 +58,7 @@ typedef struct { uint32_t tags; int32_t isfloating; int32_t isfullscreen; + int32_t isfakefullscreen; float scroller_proportion; const char *animation_type_open; const char *animation_type_close; @@ -1972,6 +1973,7 @@ bool parse_option(Config *config, char *key, char *value) { // int32_t rule value, relay to a client property rule->isfloating = -1; rule->isfullscreen = -1; + rule->isfakefullscreen = -1; rule->isnoborder = -1; rule->isnoshadow = -1; rule->isnoradius = -1; @@ -2111,6 +2113,8 @@ bool parse_option(Config *config, char *key, char *value) { rule->scroller_proportion = atof(val); } else if (strcmp(key, "isfullscreen") == 0) { rule->isfullscreen = atoi(val); + } else if (strcmp(key, "isfakefullscreen") == 0) { + rule->isfakefullscreen = atoi(val); } else if (strcmp(key, "globalkeybinding") == 0) { char mod_str[256], keysym_str[256]; sscanf(val, "%255[^-]-%255[a-zA-Z]", mod_str, keysym_str); diff --git a/src/mango.c b/src/mango.c index 591d4f65..8ec1b5b0 100644 --- a/src/mango.c +++ b/src/mango.c @@ -1289,6 +1289,7 @@ static void apply_rule_properties(Client *c, const ConfigWinRule *r) { APPLY_INT_PROP(c, r, no_force_center); APPLY_INT_PROP(c, r, isfloating); APPLY_INT_PROP(c, r, isfullscreen); + APPLY_INT_PROP(c, r, isfakefullscreen); APPLY_INT_PROP(c, r, isnoborder); APPLY_INT_PROP(c, r, isnoshadow); APPLY_INT_PROP(c, r, isnoradius); @@ -1482,6 +1483,10 @@ void applyrules(Client *c) { setfullscreen(c, fullscreen_state_backup); + if (c->isfakefullscreen) { + setfakefullscreen(c, 1); + } + /* if there is a new non-floating window in the current tag, the fullscreen window in the current tag will exit fullscreen and participate in tiling From 6b79a432a4e81e757775ce9edf89acc1b4859d74 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Mon, 9 Feb 2026 07:52:10 +0800 Subject: [PATCH 501/591] opt: allow none mode in some mouse button --- config.conf | 5 ++--- src/mango.c | 19 +++++++++++++------ 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/config.conf b/config.conf index 6cbb3a20..15b654c1 100644 --- a/config.conf +++ b/config.conf @@ -240,12 +240,11 @@ bind=CTRL+ALT,Left,resizewin,-50,+0 bind=CTRL+ALT,Right,resizewin,+50,+0 # Mouse Button Bindings -# NONE mode key only work in ov mode +# btn_left and btn_right can't bind none mod key mousebind=SUPER,btn_left,moveresize,curmove mousebind=NONE,btn_middle,togglemaximizescreen,0 mousebind=SUPER,btn_right,moveresize,curresize -mousebind=NONE,btn_left,toggleoverview,1 -mousebind=NONE,btn_right,killclient,0 + # Axis Bindings axisbind=SUPER,UP,viewtoleft_have_client diff --git a/src/mango.c b/src/mango.c index d6876c5b..44f67285 100644 --- a/src/mango.c +++ b/src/mango.c @@ -1998,14 +1998,21 @@ buttonpress(struct wl_listener *listener, void *data) { if (config.mouse_bindings_count < 1) break; m = &config.mouse_bindings[ji]; + + if (selmon->isoverview && event->button == BTN_LEFT && c) { + toggleoverview(&(Arg){.i = 1}); + return; + } + + if (selmon->isoverview && event->button == BTN_RIGHT && c) { + pending_kill_client(c); + return; + } + if (CLEANMASK(mods) == CLEANMASK(m->mod) && event->button == m->button && m->func && - (selmon->isoverview == 1 || m->button == BTN_MIDDLE) && c) { - m->func(&m->arg); - return; - } else if (CLEANMASK(mods) == CLEANMASK(m->mod) && - event->button == m->button && m->func && - CLEANMASK(m->mod) != 0) { + (CLEANMASK(m->mod) != 0 || + (event->button != BTN_LEFT && event->button != BTN_RIGHT))) { m->func(&m->arg); return; } From b05bc1ce65bdb32b9d2db10ef4e1514c34bf10dd Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Mon, 9 Feb 2026 11:50:54 +0800 Subject: [PATCH 502/591] opt: add btn_left and btn_right bind check in config check --- src/config/parse_config.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/config/parse_config.h b/src/config/parse_config.h index a7959617..1ab243c7 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -2359,6 +2359,17 @@ bool parse_option(Config *config, char *key, char *value) { binding->arg.v = NULL; binding->arg.v2 = NULL; binding->arg.v3 = NULL; + + // TODO: remove this in next version + if (binding->mod == 0 && + (binding->button == BTN_LEFT || binding->button == BTN_RIGHT)) { + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m \033[31m%s\033[33m can't " + "bind to \033[31m%s\033[33m mod key\n", + button_str, mod_str); + return false; + } + binding->func = parse_func_name(func_name, &binding->arg, arg_value, arg_value2, arg_value3, arg_value4, arg_value5); @@ -2376,6 +2387,7 @@ bool parse_option(Config *config, char *key, char *value) { free(binding->arg.v3); binding->arg.v3 = NULL; } + if (!binding->func) fprintf(stderr, "\033[1m\033[31m[ERROR]:\033[33m Unknown " From c7f90cbc6901cd2bed2de079c75717052515ef87 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Mon, 9 Feb 2026 18:08:28 +0800 Subject: [PATCH 503/591] bump version to 0.12.1 --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 05656093..478ef0e6 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('mango', ['c', 'cpp'], - version : '0.12.0', + version : '0.12.1', ) subdir('protocols') From 783cb86c56f2c0c433df1e3cd4c0bdeb93db6973 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Tue, 10 Feb 2026 10:03:08 +0800 Subject: [PATCH 504/591] feat: support match monitor make model serial --- src/config/parse_config.h | 117 ++++++++++++++++++++++++++++++++++---- src/mango.c | 35 +++++++++++- 2 files changed, 140 insertions(+), 12 deletions(-) diff --git a/src/config/parse_config.h b/src/config/parse_config.h index 1ab243c7..556fc352 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -101,13 +101,14 @@ typedef struct { } ConfigWinRule; typedef struct { - const char *name; // Monitor name - int32_t rr; // Rotate and flip (assume integer) - float scale; // Monitor scale factor - int32_t x, y; // Monitor position - int32_t width, height; // Monitor resolution - float refresh; // Refresh rate - int32_t vrr; // variable refresh rate + const char *name; // Monitor name + char *make, *model, *serial; // may be NULL + int32_t rr; // Rotate and flip (assume integer) + float scale; // Monitor scale factor + int32_t x, y; // Monitor position + int32_t width, height; // Monitor resolution + float refresh; // Refresh rate + int32_t vrr; // variable refresh rate } ConfigMonitorRule; // 修改后的宏定义 @@ -157,6 +158,9 @@ typedef struct { int32_t id; char *layout_name; char *monitor_name; + char *monitor_make; + char *monitor_model; + char *monitor_serial; float mfact; int32_t nmaster; int32_t no_render_border; @@ -1774,6 +1778,9 @@ bool parse_option(Config *config, char *key, char *value) { // 设置默认值 rule->name = NULL; + rule->make = NULL; + rule->model = NULL; + rule->serial = NULL; rule->rr = 0; rule->scale = 1.0f; rule->x = INT32_MAX; @@ -1797,6 +1804,12 @@ bool parse_option(Config *config, char *key, char *value) { if (strcmp(key, "name") == 0) { rule->name = strdup(val); + } else if (strcmp(key, "make") == 0) { + rule->make = strdup(val); + } else if (strcmp(key, "model") == 0) { + rule->model = strdup(val); + } else if (strcmp(key, "serial") == 0) { + rule->serial = strdup(val); } else if (strcmp(key, "rr") == 0) { rule->rr = CLAMP_INT(atoi(val), 0, 7); } else if (strcmp(key, "scale") == 0) { @@ -1845,6 +1858,9 @@ bool parse_option(Config *config, char *key, char *value) { rule->id = 0; rule->layout_name = NULL; rule->monitor_name = NULL; + rule->monitor_make = NULL; + rule->monitor_model = NULL; + rule->monitor_serial = NULL; rule->nmaster = 0; rule->mfact = 0.0f; rule->no_render_border = 0; @@ -1868,6 +1884,12 @@ bool parse_option(Config *config, char *key, char *value) { rule->layout_name = strdup(val); } else if (strcmp(key, "monitor_name") == 0) { rule->monitor_name = strdup(val); + } else if (strcmp(key, "monitor_make") == 0) { + rule->monitor_make = strdup(val); + } else if (strcmp(key, "monitor_model") == 0) { + rule->monitor_model = strdup(val); + } else if (strcmp(key, "monitor_serial") == 0) { + 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, "no_hide") == 0) { @@ -2925,6 +2947,12 @@ void free_config(void) { free((void *)config.tag_rules[i].layout_name); if (config.tag_rules[i].monitor_name) free((void *)config.tag_rules[i].monitor_name); + if (config.tag_rules[i].monitor_make) + free((void *)config.tag_rules[i].monitor_make); + if (config.tag_rules[i].monitor_model) + free((void *)config.tag_rules[i].monitor_model); + if (config.tag_rules[i].monitor_serial) + free((void *)config.tag_rules[i].monitor_serial); } free(config.tag_rules); config.tag_rules = NULL; @@ -2936,6 +2964,12 @@ void free_config(void) { for (int32_t i = 0; i < config.monitor_rules_count; i++) { if (config.monitor_rules[i].name) free((void *)config.monitor_rules[i].name); + if (config.monitor_rules[i].make) + free((void *)config.monitor_rules[i].make); + if (config.monitor_rules[i].model) + free((void *)config.monitor_rules[i].model); + if (config.monitor_rules[i].serial) + free((void *)config.monitor_rules[i].serial); } free(config.monitor_rules); config.monitor_rules = NULL; @@ -3500,6 +3534,7 @@ void reapply_monitor_rules(void) { struct wlr_output_state state; struct wlr_output_mode *internal_mode = NULL; wlr_output_state_init(&state); + bool match_rule = false; wl_list_for_each(m, &mons, link) { if (!m->wlr_output->enabled) { @@ -3511,8 +3546,40 @@ void reapply_monitor_rules(void) { break; mr = &config.monitor_rules[ji]; - if (regex_match(mr->name, m->wlr_output->name)) { + // 检查是否匹配的变量 + match_rule = true; + + // 检查四个标识字段的匹配 + if (mr->name != NULL) { + if (!regex_match(mr->name, m->wlr_output->name)) { + match_rule = false; + } + } + + if (mr->make != NULL) { + if (m->wlr_output->make == NULL || + strcmp(mr->make, m->wlr_output->make) != 0) { + match_rule = false; + } + } + + if (mr->model != NULL) { + if (m->wlr_output->model == NULL || + strcmp(mr->model, m->wlr_output->model) != 0) { + match_rule = false; + } + } + + if (mr->serial != NULL) { + if (m->wlr_output->serial == NULL || + strcmp(mr->serial, m->wlr_output->serial) != 0) { + match_rule = false; + } + } + + // 只有当所有指定的标识都匹配时才应用规则 + if (match_rule) { 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; @@ -3646,6 +3713,7 @@ void parse_tagrule(Monitor *m) { int32_t i, jk; ConfigTagRule tr; Client *c = NULL; + bool match_rule = false; for (i = 0; i <= LENGTH(tags); i++) { m->pertag->nmasters[i] = default_nmaster; @@ -3656,9 +3724,36 @@ void parse_tagrule(Monitor *m) { tr = config.tag_rules[i]; - if (config.tag_rules_count > 0 && - (!tr.monitor_name || - regex_match(tr.monitor_name, m->wlr_output->name))) { + match_rule = true; + + if (tr.monitor_name != NULL) { + if (!regex_match(tr.monitor_name, m->wlr_output->name)) { + match_rule = false; + } + } + + if (tr.monitor_make != NULL) { + if (m->wlr_output->make == NULL || + strcmp(tr.monitor_make, m->wlr_output->make) != 0) { + match_rule = false; + } + } + + if (tr.monitor_model != NULL) { + if (m->wlr_output->model == NULL || + strcmp(tr.monitor_model, m->wlr_output->model) != 0) { + match_rule = false; + } + } + + if (tr.monitor_serial != NULL) { + if (m->wlr_output->serial == NULL || + strcmp(tr.monitor_serial, m->wlr_output->serial) != 0) { + match_rule = false; + } + } + + if (config.tag_rules_count > 0 && match_rule) { for (jk = 0; jk < LENGTH(layouts); jk++) { if (tr.layout_name && diff --git a/src/mango.c b/src/mango.c index 44f67285..495cba0f 100644 --- a/src/mango.c +++ b/src/mango.c @@ -2737,6 +2737,7 @@ void createmon(struct wl_listener *listener, void *data) { Monitor *m = NULL; struct wlr_output_mode *internal_mode = NULL; bool custom_monitor_mode = false; + bool match_rule = false; if (!wlr_output_init_render(wlr_output, alloc, drw)) return; @@ -2777,7 +2778,39 @@ void createmon(struct wl_listener *listener, void *data) { break; r = &config.monitor_rules[ji]; - if (regex_match(r->name, wlr_output->name)) { + + // 检查是否匹配的变量 + match_rule = true; + + // 检查四个标识字段的匹配 + if (r->name != NULL) { + if (!regex_match(r->name, m->wlr_output->name)) { + match_rule = false; + } + } + + if (r->make != NULL) { + if (m->wlr_output->make == NULL || + strcmp(r->make, m->wlr_output->make) != 0) { + match_rule = false; + } + } + + if (r->model != NULL) { + if (m->wlr_output->model == NULL || + strcmp(r->model, m->wlr_output->model) != 0) { + match_rule = false; + } + } + + if (r->serial != NULL) { + if (m->wlr_output->serial == NULL || + strcmp(r->serial, m->wlr_output->serial) != 0) { + match_rule = false; + } + } + + if (match_rule) { m->m.x = r->x == INT32_MAX ? INT32_MAX : r->x; m->m.y = r->y == INT32_MAX ? INT32_MAX : r->y; vrr = r->vrr >= 0 ? r->vrr : 0; From b5a157038caea46fc1fb710cf7d93a093db0cd25 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Wed, 11 Feb 2026 08:31:22 +0800 Subject: [PATCH 505/591] opt: tell the synckeymap timer not need to call anymore --- src/mango.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/mango.c b/src/mango.c index 495cba0f..31d38ea6 100644 --- a/src/mango.c +++ b/src/mango.c @@ -6058,8 +6058,9 @@ void virtualpointer(struct wl_listener *listener, void *data) { int32_t synckeymap(void *data) { reset_keyboard_layout(); // we only need to sync keymap once + wlr_log(WLR_INFO, "timer to synckeymap done"); wl_event_source_timer_update(sync_keymap, 0); - return 1; + return 0; } void activatex11(struct wl_listener *listener, void *data) { From 8484093e324a5e305e35dbf4c369d9065a0ad26c Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Wed, 11 Feb 2026 20:44:44 +0800 Subject: [PATCH 506/591] fix: crash when pointerfocus to a null scene client --- src/mango.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mango.c b/src/mango.c index 31d38ea6..3ce74222 100644 --- a/src/mango.c +++ b/src/mango.c @@ -4322,7 +4322,7 @@ void pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy, uint32_t time) { struct timespec now; - if (sloppyfocus && !start_drag_window && c && time && + if (sloppyfocus && !start_drag_window && c && time && c->scene && c->scene->node.enabled && !c->animation.tagining && (surface != seat->pointer_state.focused_surface) && !client_is_unmanaged(c) && VISIBLEON(c, c->mon)) From 53ee82a726ba1974ddfb67e182cec486678bbf1b Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Thu, 12 Feb 2026 11:19:39 +0800 Subject: [PATCH 507/591] feat: make force_tiled_state as a option --- src/config/parse_config.h | 4 ++++ src/mango.c | 27 ++++++++++++++++++++++----- 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/src/config/parse_config.h b/src/config/parse_config.h index 556fc352..7e6db028 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -89,6 +89,7 @@ typedef struct { int32_t isterm; int32_t allow_csd; int32_t force_maximize; + int32_t force_tiled_state; int32_t force_tearing; int32_t noswallow; int32_t noblur; @@ -2011,6 +2012,7 @@ bool parse_option(Config *config, char *key, char *value) { rule->isterm = -1; rule->allow_csd = -1; rule->force_maximize = -1; + rule->force_tiled_state = -1; rule->force_tearing = -1; rule->noswallow = -1; rule->noblur = -1; @@ -2123,6 +2125,8 @@ bool parse_option(Config *config, char *key, char *value) { rule->allow_csd = atoi(val); } else if (strcmp(key, "force_maximize") == 0) { rule->force_maximize = atoi(val); + } else if (strcmp(key, "force_tiled_state") == 0) { + rule->force_tiled_state = atoi(val); } else if (strcmp(key, "force_tearing") == 0) { rule->force_tearing = atoi(val); } else if (strcmp(key, "noswallow") == 0) { diff --git a/src/mango.c b/src/mango.c index 3ce74222..63f0e275 100644 --- a/src/mango.c +++ b/src/mango.c @@ -3,6 +3,7 @@ */ #include "wlr-layer-shell-unstable-v1-protocol.h" #include "wlr/util/box.h" +#include "wlr/util/edges.h" #include #include #include @@ -390,6 +391,7 @@ struct Client { int32_t isterm, noswallow; int32_t allow_csd; int32_t force_maximize; + int32_t force_tiled_state; pid_t pid; Client *swallowing, *swallowedby; bool is_clip_to_hide; @@ -1283,6 +1285,7 @@ static void apply_rule_properties(Client *c, const ConfigWinRule *r) { APPLY_INT_PROP(c, r, isterm); APPLY_INT_PROP(c, r, allow_csd); APPLY_INT_PROP(c, r, force_maximize); + APPLY_INT_PROP(c, r, force_tiled_state); APPLY_INT_PROP(c, r, force_tearing); APPLY_INT_PROP(c, r, noswallow); APPLY_INT_PROP(c, r, nofocus); @@ -2438,9 +2441,6 @@ void commitnotify(struct wl_listener *listener, void *data) { setmon(c, NULL, 0, true); /* Make sure to reapply rules in mapnotify() */ - client_set_tiled(c, WLR_EDGE_TOP | WLR_EDGE_BOTTOM | WLR_EDGE_LEFT | - WLR_EDGE_RIGHT); - uint32_t serial = wlr_xdg_surface_schedule_configure(c->surface.xdg); if (serial > 0) { c->configure_serial = serial; @@ -3856,6 +3856,7 @@ void init_client_properties(Client *c) { c->isterm = 0; c->allow_csd = 0; c->force_maximize = 0; + c->force_tiled_state = 1; c->force_tearing = 0; c->allow_shortcuts_inhibit = SHORTCUTS_INHIBIT_ENABLE; c->scroller_proportion_single = 0.0f; @@ -3970,8 +3971,10 @@ mapnotify(struct wl_listener *listener, void *data) { applyrules(c); - client_set_tiled(c, WLR_EDGE_TOP | WLR_EDGE_BOTTOM | WLR_EDGE_LEFT | - WLR_EDGE_RIGHT); + if (!c->isfloating || c->force_tiled_state) { + client_set_tiled(c, WLR_EDGE_TOP | WLR_EDGE_BOTTOM | WLR_EDGE_LEFT | + WLR_EDGE_RIGHT); + } // apply buffer effects of client wlr_scene_node_for_each_buffer(&c->scene_surface->node, @@ -4796,6 +4799,13 @@ setfloating(Client *c, int32_t floating) { if (!c->force_maximize) client_set_maximized(c, false); + if (!c->isfloating || c->force_tiled_state) { + client_set_tiled(c, WLR_EDGE_TOP | WLR_EDGE_BOTTOM | WLR_EDGE_LEFT | + WLR_EDGE_RIGHT); + } else { + client_set_tiled(c, WLR_EDGE_NONE); + } + arrange(c->mon, false, false); setborder_color(c); printstatus(); @@ -5531,6 +5541,9 @@ void overview_backup(Client *c) { c->ismaximizescreen = 0; } c->bw = c->isnoborder ? 0 : borderpx; + + client_set_tiled(c, WLR_EDGE_TOP | WLR_EDGE_BOTTOM | WLR_EDGE_LEFT | + WLR_EDGE_RIGHT); } // overview切回到普通视图还原窗口的状态 @@ -5570,6 +5583,10 @@ void overview_restore(Client *c, const Arg *arg) { !c->isfullscreen) { // 如果是在ov模式中创建的窗口,没有bw记录 c->bw = c->isnoborder ? 0 : borderpx; } + + if (c->isfloating && !c->force_tiled_state) { + client_set_tiled(c, WLR_EDGE_NONE); + } } void handlecursoractivity(void) { From bc52b95c1ef885127c1aa1a63c847db9d2b0c818 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Thu, 12 Feb 2026 16:38:19 +0800 Subject: [PATCH 508/591] opt: make x11 unmanaged window coordinate auto ajust the monitor change --- src/mango.c | 33 +++++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/src/mango.c b/src/mango.c index 63f0e275..e84c4989 100644 --- a/src/mango.c +++ b/src/mango.c @@ -944,6 +944,7 @@ static struct wl_listener keyboard_shortcuts_inhibit_new_inhibitor = { .notify = handle_keyboard_shortcuts_inhibit_new_inhibitor}; #ifdef XWAYLAND +static void fix_xwayland_unmanaged_coordinate(struct wlr_box *box); static int32_t synckeymap(void *data); static void activatex11(struct wl_listener *listener, void *data); static void configurex11(struct wl_listener *listener, void *data); @@ -3914,18 +3915,19 @@ mapnotify(struct wl_listener *listener, void *data) { */ if (client_is_unmanaged(c)) { /* Unmanaged clients always are floating */ +#ifdef XWAYLAND + if (client_is_x11(c)) { + fix_xwayland_unmanaged_coordinate(&c->geom); + LISTEN(&c->surface.xwayland->events.set_geometry, &c->set_geometry, + setgeometrynotify); + } +#endif wlr_scene_node_reparent(&c->scene->node, layers[LyrOverlay]); wlr_scene_node_set_position(&c->scene->node, c->geom.x, c->geom.y); if (client_wants_focus(c)) { focusclient(c, 1); exclusive_focus = c; } -#ifdef XWAYLAND - if (client_is_x11(c)) { - LISTEN(&c->surface.xwayland->events.set_geometry, &c->set_geometry, - setgeometrynotify); - } -#endif return; } @@ -6072,6 +6074,25 @@ void virtualpointer(struct wl_listener *listener, void *data) { } #ifdef XWAYLAND +void fix_xwayland_unmanaged_coordinate(struct wlr_box *box) { + if (!selmon) + return; + if (box->x >= selmon->m.x && box->x <= selmon->m.x + selmon->m.width && + box->y >= selmon->m.y && box->y <= selmon->m.y + selmon->m.height) + return; + + Monitor *source_monitor = xytomon(box->x, box->y); + + if (!source_monitor) + return; + + int xoffset = box->x - source_monitor->m.x; + int yoffset = box->y - source_monitor->m.y; + + box->x = selmon->m.x + xoffset; + box->y = selmon->m.y + yoffset; +} + int32_t synckeymap(void *data) { reset_keyboard_layout(); // we only need to sync keymap once From 17acdae69c2fbda70dfdd22f0cfa268dc75ba5c9 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Thu, 12 Feb 2026 18:12:01 +0800 Subject: [PATCH 509/591] opt: make x11 floating window coordinate auto ajust the monitor change --- src/mango.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/mango.c b/src/mango.c index e84c4989..8633dcd1 100644 --- a/src/mango.c +++ b/src/mango.c @@ -1375,6 +1375,14 @@ void applyrules(Client *c) { Monitor *mon = parent && parent->mon ? parent->mon : selmon; c->isfloating = client_is_float_type(c) || parent; + +#ifdef XWAYLAND + if (c->isfloating && client_is_x11(c)) { + fix_xwayland_unmanaged_coordinate(&c->geom); + c->float_geom = c->geom; + } +#endif + if (!(appid = client_get_appid(c))) appid = broken; if (!(title = client_get_title(c))) From 313adefd10c6de9671aef85fc715df3f7564cf21 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Thu, 12 Feb 2026 18:44:56 +0800 Subject: [PATCH 510/591] opt: better x11 coordinate adjust --- src/mango.c | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/src/mango.c b/src/mango.c index 8633dcd1..ca25dbca 100644 --- a/src/mango.c +++ b/src/mango.c @@ -944,7 +944,7 @@ static struct wl_listener keyboard_shortcuts_inhibit_new_inhibitor = { .notify = handle_keyboard_shortcuts_inhibit_new_inhibitor}; #ifdef XWAYLAND -static void fix_xwayland_unmanaged_coordinate(struct wlr_box *box); +static void fix_xwayland_unmanaged_coordinate(Client *c); static int32_t synckeymap(void *data); static void activatex11(struct wl_listener *listener, void *data); static void configurex11(struct wl_listener *listener, void *data); @@ -1378,7 +1378,7 @@ void applyrules(Client *c) { #ifdef XWAYLAND if (c->isfloating && client_is_x11(c)) { - fix_xwayland_unmanaged_coordinate(&c->geom); + fix_xwayland_unmanaged_coordinate(c); c->float_geom = c->geom; } #endif @@ -3925,7 +3925,7 @@ mapnotify(struct wl_listener *listener, void *data) { /* Unmanaged clients always are floating */ #ifdef XWAYLAND if (client_is_x11(c)) { - fix_xwayland_unmanaged_coordinate(&c->geom); + fix_xwayland_unmanaged_coordinate(c); LISTEN(&c->surface.xwayland->events.set_geometry, &c->set_geometry, setgeometrynotify); } @@ -6082,23 +6082,16 @@ void virtualpointer(struct wl_listener *listener, void *data) { } #ifdef XWAYLAND -void fix_xwayland_unmanaged_coordinate(struct wlr_box *box) { +void fix_xwayland_unmanaged_coordinate(Client *c) { if (!selmon) return; - if (box->x >= selmon->m.x && box->x <= selmon->m.x + selmon->m.width && - box->y >= selmon->m.y && box->y <= selmon->m.y + selmon->m.height) + + // 1. 如果窗口已经在当前活动显示器内,直接返回 + if (c->geom.x >= selmon->m.x && c->geom.x < selmon->m.x + selmon->m.width && + c->geom.y >= selmon->m.y && c->geom.y < selmon->m.y + selmon->m.height) return; - Monitor *source_monitor = xytomon(box->x, box->y); - - if (!source_monitor) - return; - - int xoffset = box->x - source_monitor->m.x; - int yoffset = box->y - source_monitor->m.y; - - box->x = selmon->m.x + xoffset; - box->y = selmon->m.y + yoffset; + c->geom = setclient_coordinate_center(c, selmon, c->geom, 0, 0); } int32_t synckeymap(void *data) { From 5ae8975b11395dd73594fa7ea187fd5798510e30 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Fri, 13 Feb 2026 10:44:17 +0800 Subject: [PATCH 511/591] bump version to 0.12.2 --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 478ef0e6..e7979bdf 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('mango', ['c', 'cpp'], - version : '0.12.1', + version : '0.12.2', ) subdir('protocols') From f25161552455d076f0f15cadf522a8b57b829e2f Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Fri, 13 Feb 2026 11:06:12 +0800 Subject: [PATCH 512/591] opt: flush the blur background cache when unmap a background layer --- src/mango.c | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/src/mango.c b/src/mango.c index ca25dbca..e8fd2e68 100644 --- a/src/mango.c +++ b/src/mango.c @@ -2275,6 +2275,19 @@ static void iter_layer_scene_buffers(struct wlr_scene_buffer *buffer, } } +void layer_flush_blur_background(LayerSurface *l) { + if (!blur) + return; + + // 如果背景层发生变化,标记优化的模糊背景缓存需要更新 + if (l->layer_surface->current.layer == + ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND) { + if (l->mon) { + wlr_scene_optimized_blur_mark_dirty(l->mon->blur); + } + } +} + void maplayersurfacenotify(struct wl_listener *listener, void *data) { LayerSurface *l = wl_container_of(listener, l, map); struct wlr_layer_surface_v1 *layer_surface = l->layer_surface; @@ -2402,15 +2415,7 @@ void commitlayersurfacenotify(struct wl_listener *listener, void *data) { } } - if (blur) { - // 如果背景层发生变化,标记优化的模糊背景缓存需要更新 - if (layer_surface->current.layer == - ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND) { - if (l->mon) { - wlr_scene_optimized_blur_mark_dirty(l->mon->blur); - } - } - } + layer_flush_blur_background(l); if (layer_surface == exclusive_focus && layer_surface->current.keyboard_interactive != @@ -5643,6 +5648,7 @@ void unmaplayersurfacenotify(struct wl_listener *listener, void *data) { focusclient(focustop(selmon), 1); motionnotify(0, NULL, 0, 0, 0, 0); l->being_unmapped = false; + layer_flush_blur_background(l); wlr_scene_node_destroy(&l->shadow->node); l->shadow = NULL; } From 711498490bdf3119ac5cb4debb60f6379e5d5df1 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Fri, 13 Feb 2026 18:11:18 +0800 Subject: [PATCH 513/591] opt: not back to ov tag when view prev tag --- src/dispatch/bind_define.h | 15 ++++++++++++++- src/mango.c | 2 ++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index 1d29bc97..ea213e4f 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -1521,6 +1521,16 @@ int32_t minimized(const Arg *arg) { return 0; } +void fix_mon_tagset_from_overview(Monitor *m) { + if (m->tagset[m->seltags] == (m->ovbk_prev_tagset & TAGMASK)) { + m->tagset[m->seltags ^ 1] = m->ovbk_current_tagset; + m->pertag->prevtag = get_tags_first_tag_num(m->ovbk_current_tagset); + } else { + m->tagset[m->seltags ^ 1] = m->ovbk_prev_tagset; + m->pertag->prevtag = get_tags_first_tag_num(m->ovbk_prev_tagset); + } +} + int32_t toggleoverview(const Arg *arg) { Client *c = NULL; @@ -1542,6 +1552,8 @@ int32_t toggleoverview(const Arg *arg) { visible_client_number++; } if (visible_client_number > 0) { + selmon->ovbk_current_tagset = selmon->tagset[selmon->seltags]; + selmon->ovbk_prev_tagset = selmon->tagset[selmon->seltags ^ 1]; target = ~0 & TAGMASK; } else { selmon->isoverview ^= 1; @@ -1552,6 +1564,7 @@ int32_t toggleoverview(const Arg *arg) { } else if (!selmon->isoverview && !selmon->sel) { target = (1 << (selmon->pertag->prevtag - 1)); view(&(Arg){.ui = target}, false); + fix_mon_tagset_from_overview(selmon); refresh_monitors_workspaces_status(selmon); return 0; } @@ -1574,7 +1587,7 @@ int32_t toggleoverview(const Arg *arg) { } view(&(Arg){.ui = target}, false); - + fix_mon_tagset_from_overview(selmon); refresh_monitors_workspaces_status(selmon); return 0; } diff --git a/src/mango.c b/src/mango.c index e8fd2e68..5c0a610c 100644 --- a/src/mango.c +++ b/src/mango.c @@ -514,6 +514,8 @@ struct Monitor { int32_t gappoh; /* horizontal outer gaps */ int32_t gappov; /* vertical outer gaps */ Pertag *pertag; + uint32_t ovbk_current_tagset; + uint32_t ovbk_prev_tagset; Client *sel, *prevsel; int32_t isoverview; int32_t is_in_hotarea; From 8a924494c6693529eb83b043bf56cbff696e78e1 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Fri, 13 Feb 2026 18:16:06 +0800 Subject: [PATCH 514/591] opt: the tagset is current tagset when open window in ov mode --- src/mango.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/mango.c b/src/mango.c index 5c0a610c..b0fde12f 100644 --- a/src/mango.c +++ b/src/mango.c @@ -5097,9 +5097,15 @@ 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); - c->tags = - newtags ? newtags - : m->tagset[m->seltags]; /* assign tags of target monitor */ + 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]; + } setfloating(c, c->isfloating); setfullscreen(c, c->isfullscreen); /* This will call arrange(c->mon) */ } From c05eec7f53a8f1af25826cdc5bb3104b791e8cbb Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Fri, 13 Feb 2026 20:02:23 +0800 Subject: [PATCH 515/591] feat: support restore stack from non-tile state --- src/dispatch/bind_define.h | 8 +++++--- src/layout/arrange.h | 39 ++++++++++++++++++++++++++++++++++++++ src/mango.c | 6 +++--- 3 files changed, 47 insertions(+), 6 deletions(-) diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index ea213e4f..0bfab158 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -1217,13 +1217,15 @@ int32_t togglefloating(const Arg *arg) { if (!sel) return 0; + bool isfloating = sel->isfloating; + if ((sel->isfullscreen || sel->ismaximizescreen)) { - sel->isfloating = 1; + isfloating = 1; } else { - sel->isfloating = !sel->isfloating; + isfloating = !sel->isfloating; } - setfloating(sel, sel->isfloating); + setfloating(sel, isfloating); return 0; } diff --git a/src/layout/arrange.h b/src/layout/arrange.h index 37213640..cc4bc076 100644 --- a/src/layout/arrange.h +++ b/src/layout/arrange.h @@ -1,3 +1,42 @@ +void restore_size_per(Monitor *m, Client *c) { + Client *fc = NULL; + double total_master_inner_per = 0; + double total_stack_inner_per = 0; + + if (!m || !c) + return; + + const Layout *current_layout = m->pertag->ltidxs[m->pertag->curtag]; + + if (current_layout->id == SCROLLER || + current_layout->id == VERTICAL_SCROLLER || current_layout->id == GRID || + current_layout->id == VERTICAL_GRID || current_layout->id == DECK || + current_layout->id == VERTICAL_DECK || + current_layout->id == CENTER_TILE || current_layout->id == MONOCLE) { + return; + } + + if (current_layout->id == CENTER_TILE || c->ismaster) { + set_size_per(m, c); + return; + } + + wl_list_for_each(fc, &clients, link) { + if (VISIBLEON(fc, m) && ISTILED(fc) && fc != c) { + if (fc->ismaster) { + total_master_inner_per += fc->master_inner_per; + } else { + total_stack_inner_per += fc->stack_inner_per; + } + } + } + + if (!c->ismaster && total_stack_inner_per) { + c->stack_inner_per = total_stack_inner_per * c->stack_inner_per / + (1 - c->stack_inner_per); + } +} + void set_size_per(Monitor *m, Client *c) { Client *fc = NULL; bool found = false; diff --git a/src/mango.c b/src/mango.c index b0fde12f..45e0289c 100644 --- a/src/mango.c +++ b/src/mango.c @@ -4810,7 +4810,7 @@ setfloating(Client *c, int32_t floating) { } if (!c->isfloating && old_floating_state) { - set_size_per(c->mon, c); + restore_size_per(c->mon, c); } if (!c->force_maximize) @@ -4896,7 +4896,7 @@ void setmaximizescreen(Client *c, int32_t maximizescreen) { wlr_scene_node_reparent(&c->scene->node, layers[c->isfloating ? LyrTop : LyrTile]); if (!c->ismaximizescreen && old_maximizescreen_state) { - set_size_per(c->mon, c); + restore_size_per(c->mon, c); } if (!c->force_maximize && !c->ismaximizescreen) { @@ -4967,7 +4967,7 @@ void setfullscreen(Client *c, int32_t fullscreen) // 用自定义全屏代理自 } if (!c->isfullscreen && old_fullscreen_state) { - set_size_per(c->mon, c); + restore_size_per(c->mon, c); } arrange(c->mon, false, false); From 0fe87e6286f2a6b899fa8d7683a982f831c983af Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Fri, 13 Feb 2026 20:23:03 +0800 Subject: [PATCH 516/591] fix: fix multi master focus record error --- src/fetch/client.h | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/fetch/client.h b/src/fetch/client.h index bf30e175..8fccb261 100644 --- a/src/fetch/client.h +++ b/src/fetch/client.h @@ -574,23 +574,29 @@ bool client_is_in_same_stack(Client *sc, Client *tc, Client *fc) { if (id == TILE || id == VERTICAL_TILE || id == DECK || id == VERTICAL_DECK || id == RIGHT_TILE) { - if (fc && !fc->ismaster) + if (tc->ismaster ^ sc->ismaster) return false; - else if (!sc->ismaster) + if (fc && !(fc->ismaster ^ sc->ismaster)) + return false; + else return true; } if (id == TGMIX) { - if (fc && !fc->ismaster) + if (tc->ismaster ^ sc->ismaster) + return false; + if (fc && !(fc->ismaster ^ sc->ismaster)) return false; if (!sc->ismaster && sc->mon->visible_tiling_clients <= 3) return true; } if (id == CENTER_TILE) { - if (fc && !fc->ismaster) + if (tc->ismaster ^ sc->ismaster) return false; - if (!sc->ismaster && sc->geom.x == tc->geom.x) + if (fc && !(fc->ismaster ^ sc->ismaster)) + return false; + if (sc->geom.x == tc->geom.x) return true; else return false; From 89413aacf53e11340d0558e7d18576720a067158 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sat, 14 Feb 2026 08:35:30 +0800 Subject: [PATCH 517/591] fix: fix center tile size per reset --- src/layout/arrange.h | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/layout/arrange.h b/src/layout/arrange.h index cc4bc076..1ef89c3a 100644 --- a/src/layout/arrange.h +++ b/src/layout/arrange.h @@ -11,13 +11,16 @@ void restore_size_per(Monitor *m, Client *c) { if (current_layout->id == SCROLLER || current_layout->id == VERTICAL_SCROLLER || current_layout->id == GRID || current_layout->id == VERTICAL_GRID || current_layout->id == DECK || - current_layout->id == VERTICAL_DECK || - current_layout->id == CENTER_TILE || current_layout->id == MONOCLE) { + current_layout->id == VERTICAL_DECK || current_layout->id == MONOCLE) { return; } if (current_layout->id == CENTER_TILE || c->ismaster) { - set_size_per(m, c); + wl_list_for_each(fc, &clients, link) { + if (VISIBLEON(fc, m) && ISTILED(fc) && !c->ismaster) { + set_size_per(m, fc); + } + } return; } @@ -44,8 +47,13 @@ void set_size_per(Monitor *m, Client *c) { if (!m || !c) return; + const Layout *current_layout = m->pertag->ltidxs[m->pertag->curtag]; + wl_list_for_each(fc, &clients, link) { if (VISIBLEON(fc, m) && ISTILED(fc) && fc != c) { + if (current_layout->id == CENTER_TILE && + !(fc->isleftstack ^ c->isleftstack)) + continue; c->master_mfact_per = fc->master_mfact_per; c->master_inner_per = fc->master_inner_per; c->stack_inner_per = fc->stack_inner_per; From fdd54afb7e49d0dfdf3976b1824a660a83e09713 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sun, 15 Feb 2026 08:00:44 +0800 Subject: [PATCH 518/591] fix: some app frame skip fail when disable animaitons --- src/mango.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/mango.c b/src/mango.c index 2bc21c8b..87d2f7d5 100644 --- a/src/mango.c +++ b/src/mango.c @@ -3835,6 +3835,7 @@ static void iter_xdg_scene_buffers(struct wlr_scene_buffer *buffer, int32_t sx, void init_client_properties(Client *c) { c->isfocusing = false; + c->isfloating = 0; c->ismaximizescreen = 0; c->isfullscreen = 0; c->need_float_size_reduce = 0; @@ -4441,8 +4442,8 @@ void rendermon(struct wl_listener *listener, void *data) { wl_list_for_each(c, &clients, link) { need_more_frames = client_draw_frame(c) || need_more_frames; if (!animations && !(allow_tearing && frame_allow_tearing) && - c->configure_serial && !c->isfloating && - client_is_rendered_on_mon(c, m) && !client_is_stopped(c)) { + c->configure_serial && client_is_rendered_on_mon(c, m) && + !client_is_stopped(c)) { goto skip; } } From 02067e3b1e00b568b63dabb4c1c57b188911c349 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sun, 15 Feb 2026 08:07:00 +0800 Subject: [PATCH 519/591] fix: some client property missing init --- src/mango.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/mango.c b/src/mango.c index 87d2f7d5..6cdd5549 100644 --- a/src/mango.c +++ b/src/mango.c @@ -3836,6 +3836,22 @@ static void iter_xdg_scene_buffers(struct wlr_scene_buffer *buffer, int32_t sx, void init_client_properties(Client *c) { c->isfocusing = false; c->isfloating = 0; + c->isfakefullscreen = 0; + c->isnoanimation = 0; + c->isopensilent = 0; + c->istagsilent = 0; + c->noswallow = 0; + c->isterm = 0; + c->noblur = 0; + c->tearing_hint = 0; + c->overview_isfullscreenbak = 0; + c->overview_ismaximizescreenbak = 0; + c->overview_isfloatingbak = 0; + c->pid = 0; + c->swallowing = NULL; + c->swallowedby = NULL; + c->ismaster = 0; + c->isleftstack = 0; c->ismaximizescreen = 0; c->isfullscreen = 0; c->need_float_size_reduce = 0; @@ -3889,6 +3905,7 @@ void init_client_properties(Client *c) { c->stack_proportion = 0.0f; c->next_in_stack = NULL; c->prev_in_stack = NULL; + memset(c->oldmonname, 0, sizeof(c->oldmonname)); memcpy(c->opacity_animation.initial_border_color, bordercolor, sizeof(c->opacity_animation.initial_border_color)); memcpy(c->opacity_animation.current_border_color, bordercolor, From 842b45b584bd4b9409e474757e79ab7f08e05b21 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sun, 15 Feb 2026 08:32:49 +0800 Subject: [PATCH 520/591] feat: add skip timer to avoid rermanently block render --- src/mango.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/src/mango.c b/src/mango.c index 6cdd5549..ded59587 100644 --- a/src/mango.c +++ b/src/mango.c @@ -502,6 +502,7 @@ struct Monitor { struct wl_listener request_state; struct wl_listener destroy_lock_surface; struct wlr_session_lock_surface_v1 *lock_surface; + struct wl_event_source *skip_timeout; struct wlr_box m; /* monitor area, layout-relative */ struct wlr_box w; /* window area, layout-relative */ struct wl_list layers[4]; /* LayerSurface::link */ @@ -783,6 +784,7 @@ static Client *get_scroll_stack_head(Client *c); static bool client_only_in_one_tag(Client *c); static Client *get_focused_stack_client(Client *sc); static bool client_is_in_same_stack(Client *sc, Client *tc, Client *fc); +static void destroy_monitor_skip_timer(Monitor *m); #include "data/static_keymap.h" #include "dispatch/bind_declare.h" @@ -2223,6 +2225,9 @@ void cleanupmon(struct wl_listener *listener, void *data) { wlr_scene_node_destroy(&m->blur->node); m->blur = NULL; } + if (m->skip_timeout) { + destroy_monitor_skip_timer(m); + } m->wlr_output->data = NULL; free(m->pertag); free(m); @@ -2774,6 +2779,7 @@ void createmon(struct wl_listener *listener, void *data) { m = wlr_output->data = ecalloc(1, sizeof(*m)); m->wlr_output = wlr_output; m->wlr_output->data = m; + m->skip_timeout = NULL; wl_list_init(&m->dwl_ipc_outputs); @@ -4419,6 +4425,37 @@ void client_set_opacity(Client *c, double opacity) { scene_buffer_apply_opacity, &opacity); } +void destroy_monitor_skip_timer(Monitor *m) { + if (m->skip_timeout) { + wl_event_source_timer_update(m->skip_timeout, 0); + wl_event_source_remove(m->skip_timeout); + m->skip_timeout = NULL; + } +} + +static int skip_timeout_callback(void *data) { + Monitor *m = data; + Client *c, *tmp; + + wl_list_for_each_safe(c, tmp, &clients, link) { c->configure_serial = 0; } + + if (m->skip_timeout) { + destroy_monitor_skip_timer(m); + } + return 0; +} + +void check_skip_timeout(Monitor *m) { + if (m->skip_timeout) { + return; + } + struct wl_event_loop *loop = wl_display_get_event_loop(dpy); + m->skip_timeout = wl_event_loop_add_timer(loop, skip_timeout_callback, m); + if (m->skip_timeout) { + wl_event_source_timer_update(m->skip_timeout, 100); // 100ms + } +} + void rendermon(struct wl_listener *listener, void *data) { Monitor *m = wl_container_of(listener, m, frame); Client *c = NULL, *tmp = NULL; @@ -4461,10 +4498,15 @@ void rendermon(struct wl_listener *listener, void *data) { if (!animations && !(allow_tearing && frame_allow_tearing) && c->configure_serial && client_is_rendered_on_mon(c, m) && !client_is_stopped(c)) { + check_skip_timeout(m); goto skip; } } + if (m->skip_timeout) { + destroy_monitor_skip_timer(m); + } + // 只有在需要帧时才构建和提交状态 if (allow_tearing && frame_allow_tearing) { apply_tear_state(m); From 0696fe964de6b820e172ecbed6d3af942996b6bd Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sun, 15 Feb 2026 10:31:23 +0800 Subject: [PATCH 521/591] opt: optimize frame skip logic --- src/mango.c | 47 +++++++++++++++++++++++++++-------------------- 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/src/mango.c b/src/mango.c index ded59587..8ae26031 100644 --- a/src/mango.c +++ b/src/mango.c @@ -508,6 +508,7 @@ struct Monitor { struct wl_list layers[4]; /* LayerSurface::link */ uint32_t seltags; uint32_t tagset[2]; + bool skiping_frame; struct wl_list dwl_ipc_outputs; int32_t gappih; /* horizontal gap between windows */ @@ -784,7 +785,8 @@ static Client *get_scroll_stack_head(Client *c); static bool client_only_in_one_tag(Client *c); static Client *get_focused_stack_client(Client *sc); static bool client_is_in_same_stack(Client *sc, Client *tc, Client *fc); -static void destroy_monitor_skip_timer(Monitor *m); +static void monitor_stop_skip_timer(Monitor *m); +static int monitor_skip_frame_timeout_callback(void *data); #include "data/static_keymap.h" #include "dispatch/bind_declare.h" @@ -2226,7 +2228,9 @@ void cleanupmon(struct wl_listener *listener, void *data) { m->blur = NULL; } if (m->skip_timeout) { - destroy_monitor_skip_timer(m); + monitor_stop_skip_timer(m); + wl_event_source_remove(m->skip_timeout); + m->skip_timeout = NULL; } m->wlr_output->data = NULL; free(m->pertag); @@ -2776,10 +2780,15 @@ void createmon(struct wl_listener *listener, void *data) { return; } + struct wl_event_loop *loop = wl_display_get_event_loop(dpy); m = wlr_output->data = ecalloc(1, sizeof(*m)); + + m->skip_timeout = + wl_event_loop_add_timer(loop, monitor_skip_frame_timeout_callback, m); + m->skiping_frame = false; + m->wlr_output = wlr_output; m->wlr_output->data = m; - m->skip_timeout = NULL; wl_list_init(&m->dwl_ipc_outputs); @@ -4425,34 +4434,32 @@ void client_set_opacity(Client *c, double opacity) { scene_buffer_apply_opacity, &opacity); } -void destroy_monitor_skip_timer(Monitor *m) { - if (m->skip_timeout) { +void monitor_stop_skip_timer(Monitor *m) { + if (m->skip_timeout) wl_event_source_timer_update(m->skip_timeout, 0); - wl_event_source_remove(m->skip_timeout); - m->skip_timeout = NULL; - } + m->skiping_frame = false; } -static int skip_timeout_callback(void *data) { +static int monitor_skip_frame_timeout_callback(void *data) { Monitor *m = data; Client *c, *tmp; wl_list_for_each_safe(c, tmp, &clients, link) { c->configure_serial = 0; } - if (m->skip_timeout) { - destroy_monitor_skip_timer(m); - } - return 0; + monitor_stop_skip_timer(m); + wlr_output_schedule_frame(m->wlr_output); + + return 1; } -void check_skip_timeout(Monitor *m) { - if (m->skip_timeout) { +void monitor_check_skip_frame_timeout(Monitor *m) { + if (m->skiping_frame) { return; } - struct wl_event_loop *loop = wl_display_get_event_loop(dpy); - m->skip_timeout = wl_event_loop_add_timer(loop, skip_timeout_callback, m); + if (m->skip_timeout) { wl_event_source_timer_update(m->skip_timeout, 100); // 100ms + m->skiping_frame = true; } } @@ -4498,13 +4505,13 @@ void rendermon(struct wl_listener *listener, void *data) { if (!animations && !(allow_tearing && frame_allow_tearing) && c->configure_serial && client_is_rendered_on_mon(c, m) && !client_is_stopped(c)) { - check_skip_timeout(m); + monitor_check_skip_frame_timeout(m); goto skip; } } - if (m->skip_timeout) { - destroy_monitor_skip_timer(m); + if (m->skiping_frame) { + monitor_stop_skip_timer(m); } // 只有在需要帧时才构建和提交状态 From 49cb5a9d7efb03e726e4eea1579242e3549f6d8b Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sun, 15 Feb 2026 12:29:12 +0800 Subject: [PATCH 522/591] feat: support frame skip for x11 app resize --- src/client/client.h | 16 +++++++++++++++- src/mango.c | 18 ++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/src/client/client.h b/src/client/client.h index 49ab3988..fbb7a242 100644 --- a/src/client/client.h +++ b/src/client/client.h @@ -319,9 +319,23 @@ static inline uint32_t client_set_size(Client *c, uint32_t width, uint32_t height) { #ifdef XWAYLAND if (client_is_x11(c)) { + + struct wlr_surface_state *state = + &c->surface.xwayland->surface->current; + struct wlr_box new_geo = {0}; + new_geo.width = state->width; + new_geo.height = state->height; + if (c->geom.width - 2 * c->bw == new_geo.width && + c->geom.height - 2 * c->bw == new_geo.height && + c->surface.xwayland->x == c->geom.x + c->bw && + c->surface.xwayland->y == c->geom.y + c->bw) { + c->configure_serial = 0; + return 0; + } + wlr_xwayland_surface_configure(c->surface.xwayland, c->geom.x + c->bw, c->geom.y + c->bw, width, height); - return 0; + return 1; } #endif if ((int32_t)width == c->surface.xdg->toplevel->current.width && diff --git a/src/mango.c b/src/mango.c index 8ae26031..f0aefec3 100644 --- a/src/mango.c +++ b/src/mango.c @@ -338,6 +338,7 @@ struct Client { struct wl_listener configure; struct wl_listener set_hints; struct wl_listener set_geometry; + struct wl_listener commmitx11; #endif uint32_t bw; uint32_t tags, oldtags, mini_restore_tag; @@ -956,6 +957,7 @@ static void activatex11(struct wl_listener *listener, void *data); static void configurex11(struct wl_listener *listener, void *data); static void createnotifyx11(struct wl_listener *listener, void *data); static void dissociatex11(struct wl_listener *listener, void *data); +static void commitx11(struct wl_listener *listener, void *data); static void associatex11(struct wl_listener *listener, void *data); static void sethints(struct wl_listener *listener, void *data); static void xwaylandready(struct wl_listener *listener, void *data); @@ -6280,17 +6282,33 @@ void createnotifyx11(struct wl_listener *listener, void *data) { LISTEN(&xsurface->events.request_minimize, &c->minimize, minimizenotify); } +void commitx11(struct wl_listener *listener, void *data) { + Client *c = wl_container_of(listener, c, commmitx11); + struct wlr_surface_state *state = &c->surface.xwayland->surface->current; + struct wlr_box new_geo = {0}; + new_geo.width = state->width; + new_geo.height = state->height; + if (c->geom.width - 2 * c->bw == new_geo.width && + c->geom.height - 2 * c->bw == new_geo.height && + c->surface.xwayland->x == c->geom.x + c->bw && + c->surface.xwayland->y == c->geom.y + c->bw) { + c->configure_serial = 0; + } +} + void associatex11(struct wl_listener *listener, void *data) { Client *c = wl_container_of(listener, c, associate); LISTEN(&client_surface(c)->events.map, &c->map, mapnotify); LISTEN(&client_surface(c)->events.unmap, &c->unmap, unmapnotify); + LISTEN(&client_surface(c)->events.commit, &c->commmitx11, commitx11); } void dissociatex11(struct wl_listener *listener, void *data) { Client *c = wl_container_of(listener, c, dissociate); wl_list_remove(&c->map.link); wl_list_remove(&c->unmap.link); + wl_list_remove(&c->commmitx11.link); } void sethints(struct wl_listener *listener, void *data) { From 7ccbeae8b8bcf0c9b506579758c6ac499f3d5dab Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sun, 15 Feb 2026 14:08:12 +0800 Subject: [PATCH 523/591] fix: if the progress not the child of main, not assume it is stop --- src/client/client.h | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/client/client.h b/src/client/client.h index fbb7a242..e9519106 100644 --- a/src/client/client.h +++ b/src/client/client.h @@ -254,10 +254,13 @@ static inline int32_t client_is_stopped(Client *c) { wl_client_get_credentials(c->surface.xdg->client->client, &pid, NULL, NULL); if (waitid(P_PID, pid, &in, WNOHANG | WCONTINUED | WSTOPPED | WNOWAIT) < 0) { - /* This process is not our child process, while is very unlikely that - * it is stopped, in order to do not skip frames assume that it is. */ + /* This process is not our child process. We cannot determine its + * stopped state; assume it is not stopped to avoid blocking frame skip. + */ if (errno == ECHILD) - return 1; + return 0; // if not our child, assume not stopped + /* Other errors, also assume not stopped. */ + return 0; } else if (in.si_pid) { if (in.si_code == CLD_STOPPED || in.si_code == CLD_TRAPPED) return 1; From 62ab00a7a3656fcdc39008d048b13369ffe1ad11 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sun, 15 Feb 2026 16:43:02 +0800 Subject: [PATCH 524/591] update readme --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index b78ccfa9..9d14d06b 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,7 @@ This project's development is based on [dwl](https://codeberg.org/dwl/dwl/). - Ipc support(get/send message from/to compositor by external program) - Hycov-like overview - Window effects from scenefx (blur, shadow, corner radius, opacity) + - Zero flickering - every frame is perfect. https://github.com/user-attachments/assets/bb83004a-0563-4b48-ad89-6461a9b78b1f From f75efa13124e6017fbb935d7e3b8d86077660669 Mon Sep 17 00:00:00 2001 From: Ricardo Squassina Lee <8495707+squassina@users.noreply.github.com> Date: Sun, 15 Feb 2026 07:08:35 -0300 Subject: [PATCH 525/591] Fix wayland protocol directory variable retrieval --- protocols/meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/protocols/meson.build b/protocols/meson.build index cafab64a..922a76ed 100644 --- a/protocols/meson.build +++ b/protocols/meson.build @@ -1,6 +1,6 @@ wayland_scanner = find_program('wayland-scanner') wayland_protos_dep = dependency('wayland-protocols') -wl_protocol_dir = wayland_protos_dep.get_pkgconfig_variable('pkgdatadir') +wl_protocol_dir = wayland_protos_dep.get_variable(pkgconfig:'pkgdatadir') wayland_scanner_code = generator( wayland_scanner, output: '@BASENAME@-protocol.c', From 26a616e3d5a99811708b8b0afa62eafd0ca490be Mon Sep 17 00:00:00 2001 From: Yappaholic Date: Sun, 15 Feb 2026 16:50:07 +0300 Subject: [PATCH 526/591] docs: add guix installation instructions --- README.md | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/README.md b/README.md index 9d14d06b..9b558fd1 100644 --- a/README.md +++ b/README.md @@ -99,6 +99,34 @@ Then, install the package: dnf install mangowc ``` +## GuixSD +The package definition is described in the source repository. +First, add `mangowc` channel to `channels.scm` file: + +```scheme +;; In $HOME/.config/guix/channels.scm +(cons (channel + (name 'mangowc) + (url "https://github.com/DreamMaoMao/mangowc.git")) + ... ;; Your other channels + %default-channels) +``` + +Then, run `guix pull` and after update you can either run +`guix install mangowc` or add it to your configuration via: + +```scheme +(use-modules (mangowc)) ;; Add mangowc module + +;; Add mangowc to packages list +(packages (cons + mangowc + ... ;; Other packages you specified + %base-packages)) +``` + +And then rebuild your system. + ## Other ```bash From 1158fb2e3c09424e1d0f3aaf9b77968743cc235e Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Mon, 16 Feb 2026 07:46:42 +0800 Subject: [PATCH 527/591] opt: don't skip frame when grab client --- src/mango.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mango.c b/src/mango.c index f0aefec3..cbdc53a6 100644 --- a/src/mango.c +++ b/src/mango.c @@ -4506,7 +4506,7 @@ void rendermon(struct wl_listener *listener, void *data) { need_more_frames = client_draw_frame(c) || need_more_frames; if (!animations && !(allow_tearing && frame_allow_tearing) && c->configure_serial && client_is_rendered_on_mon(c, m) && - !client_is_stopped(c)) { + !client_is_stopped(c) && !grabc) { monitor_check_skip_frame_timeout(m); goto skip; } From 112fb5c0074f6f2110e70ae4765fe0a46ff04adb Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Mon, 16 Feb 2026 10:06:16 +0800 Subject: [PATCH 528/591] opt: optimize code struct --- src/client/client.h | 16 +++++++++------- src/mango.c | 15 ++++++++------- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/src/client/client.h b/src/client/client.h index e9519106..2174c6fa 100644 --- a/src/client/client.h +++ b/src/client/client.h @@ -325,13 +325,15 @@ static inline uint32_t client_set_size(Client *c, uint32_t width, struct wlr_surface_state *state = &c->surface.xwayland->surface->current; - struct wlr_box new_geo = {0}; - new_geo.width = state->width; - new_geo.height = state->height; - if (c->geom.width - 2 * c->bw == new_geo.width && - c->geom.height - 2 * c->bw == new_geo.height && - c->surface.xwayland->x == c->geom.x + c->bw && - c->surface.xwayland->y == c->geom.y + c->bw) { + + if ((int32_t)c->geom.width - 2 * (int32_t)c->bw == + (int32_t)state->width && + (int32_t)c->geom.height - 2 * (int32_t)c->bw == + (int32_t)state->height && + (int32_t)c->surface.xwayland->x == + (int32_t)c->geom.x + (int32_t)c->bw && + (int32_t)c->surface.xwayland->y == + (int32_t)c->geom.y + (int32_t)c->bw) { c->configure_serial = 0; return 0; } diff --git a/src/mango.c b/src/mango.c index cbdc53a6..540395ae 100644 --- a/src/mango.c +++ b/src/mango.c @@ -6285,13 +6285,14 @@ void createnotifyx11(struct wl_listener *listener, void *data) { void commitx11(struct wl_listener *listener, void *data) { Client *c = wl_container_of(listener, c, commmitx11); struct wlr_surface_state *state = &c->surface.xwayland->surface->current; - struct wlr_box new_geo = {0}; - new_geo.width = state->width; - new_geo.height = state->height; - if (c->geom.width - 2 * c->bw == new_geo.width && - c->geom.height - 2 * c->bw == new_geo.height && - c->surface.xwayland->x == c->geom.x + c->bw && - c->surface.xwayland->y == c->geom.y + c->bw) { + + if ((int32_t)c->geom.width - 2 * (int32_t)c->bw == (int32_t)state->width && + (int32_t)c->geom.height - 2 * (int32_t)c->bw == + (int32_t)state->height && + (int32_t)c->surface.xwayland->x == + (int32_t)c->geom.x + (int32_t)c->bw && + (int32_t)c->surface.xwayland->y == + (int32_t)c->geom.y + (int32_t)c->bw) { c->configure_serial = 0; } } From fa88ebace0cb352cb25fe5f989388df06d709e9c Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Mon, 16 Feb 2026 11:56:42 +0800 Subject: [PATCH 529/591] project: version not use latest tag --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index e7979bdf..5b19f9fc 100644 --- a/meson.build +++ b/meson.build @@ -56,7 +56,7 @@ endif if is_git_repo # 如果是 Git 目录,获取 Commit Hash 和最新的 tag commit_hash = run_command(git, 'rev-parse', '--short', 'HEAD', check : false).stdout().strip() - latest_tag = run_command(git, 'describe', '--tags', '--abbrev=0', check : false).stdout().strip() + latest_tag = meson.project_version() version_with_hash = '@0@(@1@)'.format(latest_tag, commit_hash) else # 如果不是 Git 目录,使用项目版本号和 "release" 字符串 From c3dcee2c8e3ae4e2839fda699a25e2d0a836b341 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Tue, 17 Feb 2026 08:33:45 +0800 Subject: [PATCH 530/591] opt: remove useless code --- src/client/client.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/client/client.h b/src/client/client.h index 2174c6fa..fd81a800 100644 --- a/src/client/client.h +++ b/src/client/client.h @@ -334,7 +334,6 @@ static inline uint32_t client_set_size(Client *c, uint32_t width, (int32_t)c->geom.x + (int32_t)c->bw && (int32_t)c->surface.xwayland->y == (int32_t)c->geom.y + (int32_t)c->bw) { - c->configure_serial = 0; return 0; } From 259fdb3a875e4c5842f75579c3e0dc85d897a4f9 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Wed, 18 Feb 2026 13:26:24 +0800 Subject: [PATCH 531/591] bump versiont to 0.12.3 --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 5b19f9fc..06ccfd75 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('mango', ['c', 'cpp'], - version : '0.12.2', + version : '0.12.3', ) subdir('protocols') From 6924ca8512090c37d64386bb5e6fabb4a6410ecb Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Wed, 18 Feb 2026 23:07:23 +0800 Subject: [PATCH 532/591] feat: add global option prefer_scroller_overspread --- src/config/parse_config.h | 6 ++++ src/config/preset.h | 1 + src/layout/horizontal.h | 66 +++++++++++++++++++++++++++++++++------ src/layout/vertical.h | 62 +++++++++++++++++++++++++++++++----- 4 files changed, 118 insertions(+), 17 deletions(-) diff --git a/src/config/parse_config.h b/src/config/parse_config.h index b7f89d59..64afd889 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -211,6 +211,7 @@ typedef struct { int32_t scroller_ignore_proportion_single; int32_t scroller_focus_center; int32_t scroller_prefer_center; + int32_t scroller_prefer_overspread; int32_t edge_scroller_pointer_focus; int32_t focus_cross_monitor; int32_t exchange_cross_monitor; @@ -1337,6 +1338,8 @@ bool parse_option(Config *config, char *key, char *value) { config->scroller_focus_center = atoi(value); } else if (strcmp(key, "scroller_prefer_center") == 0) { config->scroller_prefer_center = atoi(value); + } else if (strcmp(key, "scroller_prefer_overspread") == 0) { + config->scroller_prefer_overspread = atoi(value); } else if (strcmp(key, "edge_scroller_pointer_focus") == 0) { config->edge_scroller_pointer_focus = atoi(value); } else if (strcmp(key, "focus_cross_monitor") == 0) { @@ -3102,6 +3105,8 @@ void override_config(void) { CLAMP_INT(config.scroller_ignore_proportion_single, 0, 1); scroller_focus_center = CLAMP_INT(config.scroller_focus_center, 0, 1); scroller_prefer_center = CLAMP_INT(config.scroller_prefer_center, 0, 1); + scroller_prefer_overspread = + CLAMP_INT(config.scroller_prefer_overspread, 0, 1); edge_scroller_pointer_focus = CLAMP_INT(config.edge_scroller_pointer_focus, 0, 1); scroller_structs = CLAMP_INT(config.scroller_structs, 0, 1000); @@ -3301,6 +3306,7 @@ void set_value_default() { scroller_ignore_proportion_single; config.scroller_focus_center = scroller_focus_center; config.scroller_prefer_center = scroller_prefer_center; + config.scroller_prefer_overspread = scroller_prefer_overspread; config.edge_scroller_pointer_focus = edge_scroller_pointer_focus; config.focus_cross_monitor = focus_cross_monitor; config.exchange_cross_monitor = exchange_cross_monitor; diff --git a/src/config/preset.h b/src/config/preset.h index ae4424f9..d9824588 100644 --- a/src/config/preset.h +++ b/src/config/preset.h @@ -66,6 +66,7 @@ float scroller_default_proportion_single = 1.0; int32_t scroller_ignore_proportion_single = 1; int32_t scroller_focus_center = 0; int32_t scroller_prefer_center = 0; +int32_t scroller_prefer_overspread = 1; int32_t focus_cross_monitor = 0; int32_t focus_cross_tag = 0; int32_t exchange_cross_monitor = 0; diff --git a/src/layout/horizontal.h b/src/layout/horizontal.h index e1a335d1..b8016d50 100644 --- a/src/layout/horizontal.h +++ b/src/layout/horizontal.h @@ -283,6 +283,7 @@ void scroller(Monitor *m) { struct wlr_box target_geom; int32_t focus_client_index = 0; bool need_scroller = false; + bool over_overspread_to_left = false; int32_t cur_gappih = enablegaps ? m->gappih : 0; int32_t cur_gappoh = enablegaps ? m->gappoh : 0; int32_t cur_gappov = enablegaps ? m->gappov : 0; @@ -371,6 +372,45 @@ void scroller(Monitor *m) { } } + bool need_apply_overspread = + scroller_prefer_overspread && m->visible_scroll_tiling_clients > 1 && + tempClients[focus_client_index]->scroller_proportion < 1.0f; + + if (need_apply_overspread) { + + if (focus_client_index == 0) { + over_overspread_to_left = true; + } else { + over_overspread_to_left = false; + } + + if (over_overspread_to_left && + (!INSIDEMON(tempClients[1]) || + (tempClients[1]->scroller_proportion + + tempClients[focus_client_index]->scroller_proportion >= + 1.0f))) { + need_scroller = true; + } else if (!over_overspread_to_left && + (!INSIDEMON(tempClients[focus_client_index - 1]) || + (tempClients[focus_client_index - 1]->scroller_proportion + + tempClients[focus_client_index]->scroller_proportion >= + 1.0f))) { + need_scroller = true; + } else { + need_apply_overspread = false; + } + } + + bool need_apply_center = + scroller_focus_center || m->visible_scroll_tiling_clients == 1 || + (scroller_prefer_center && !need_apply_overspread && + (!m->prevsel || + (ISSCROLLTILED(m->prevsel) && + (m->prevsel->scroller_proportion * max_client_width) + + (tempClients[focus_client_index]->scroller_proportion * + max_client_width) > + m->w.width - 2 * scroller_structs - cur_gappih))); + if (n == 1 && scroller_ignore_proportion_single) { need_scroller = true; } @@ -394,18 +434,26 @@ void scroller(Monitor *m) { tempClients[focus_client_index], &target_geom); arrange_stack(tempClients[focus_client_index], target_geom, cur_gappiv); } else if (need_scroller) { - if (scroller_focus_center || - ((!m->prevsel || - (ISSCROLLTILED(m->prevsel) && - (m->prevsel->scroller_proportion * max_client_width) + - (root_client->scroller_proportion * max_client_width) > - m->w.width - 2 * scroller_structs - cur_gappih)) && - scroller_prefer_center)) { + if (need_apply_center) { target_geom.x = m->w.x + (m->w.width - target_geom.width) / 2; + } else if (need_apply_overspread) { + if (over_overspread_to_left) { + target_geom.x = m->w.x + scroller_structs; + } else { + target_geom.x = + m->w.x + + (m->w.width - + tempClients[focus_client_index]->scroller_proportion * + max_client_width - + scroller_structs); + } + } else { - target_geom.x = root_client->geom.x > m->w.x + (m->w.width) / 2 + target_geom.x = tempClients[focus_client_index]->geom.x > + m->w.x + (m->w.width) / 2 ? m->w.x + (m->w.width - - root_client->scroller_proportion * + tempClients[focus_client_index] + ->scroller_proportion * max_client_width - scroller_structs) : m->w.x + scroller_structs; diff --git a/src/layout/vertical.h b/src/layout/vertical.h index f7bd442c..f036ca46 100644 --- a/src/layout/vertical.h +++ b/src/layout/vertical.h @@ -270,6 +270,7 @@ void vertical_scroller(Monitor *m) { struct wlr_box target_geom; int32_t focus_client_index = 0; bool need_scroller = false; + bool over_overspread_to_up = false; int32_t cur_gappiv = enablegaps ? m->gappiv : 0; int32_t cur_gappov = enablegaps ? m->gappov : 0; int32_t cur_gappoh = enablegaps ? m->gappoh : 0; @@ -355,6 +356,45 @@ void vertical_scroller(Monitor *m) { } } + bool need_apply_overspread = + scroller_prefer_overspread && m->visible_scroll_tiling_clients > 1 && + tempClients[focus_client_index]->scroller_proportion < 1.0f; + + if (need_apply_overspread) { + + if (focus_client_index == 0) { + over_overspread_to_up = true; + } else { + over_overspread_to_up = false; + } + + if (over_overspread_to_up && + (!INSIDEMON(tempClients[1]) || + (tempClients[1]->scroller_proportion + + tempClients[focus_client_index]->scroller_proportion >= + 1.0f))) { + need_scroller = true; + } else if (!over_overspread_to_up && + (!INSIDEMON(tempClients[focus_client_index - 1]) || + (tempClients[focus_client_index - 1]->scroller_proportion + + tempClients[focus_client_index]->scroller_proportion >= + 1.0f))) { + need_scroller = true; + } else { + need_apply_overspread = false; + } + } + + bool need_apply_center = + scroller_focus_center || m->visible_scroll_tiling_clients == 1 || + (scroller_prefer_center && !need_apply_overspread && + (!m->prevsel || + (ISSCROLLTILED(m->prevsel) && + (m->prevsel->scroller_proportion * max_client_height) + + (tempClients[focus_client_index]->scroller_proportion * + max_client_height) > + m->w.height - 2 * scroller_structs - cur_gappiv))); + if (n == 1 && scroller_ignore_proportion_single) { need_scroller = true; } @@ -381,18 +421,24 @@ void vertical_scroller(Monitor *m) { arrange_stack_vertical(tempClients[focus_client_index], target_geom, cur_gappih); } else if (need_scroller) { - if (scroller_focus_center || - ((!m->prevsel || - (ISSCROLLTILED(m->prevsel) && - (m->prevsel->scroller_proportion * max_client_height) + - (root_client->scroller_proportion * max_client_height) > - m->w.height - 2 * scroller_structs - cur_gappiv)) && - scroller_prefer_center)) { + if (need_apply_center) { target_geom.y = m->w.y + (m->w.height - target_geom.height) / 2; + } else if (need_apply_overspread) { + if (over_overspread_to_up) { + target_geom.y = m->w.y + scroller_structs; + } else { + target_geom.y = + m->w.y + + (m->w.height - + tempClients[focus_client_index]->scroller_proportion * + max_client_height - + scroller_structs); + } } else { target_geom.y = root_client->geom.y > m->w.y + (m->w.height) / 2 ? m->w.y + (m->w.height - - root_client->scroller_proportion * + tempClients[focus_client_index] + ->scroller_proportion * max_client_height - scroller_structs) : m->w.y + scroller_structs; From 23d7b11e27a1078dba9492943662a1fa444a82d7 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Thu, 19 Feb 2026 08:41:42 +0800 Subject: [PATCH 533/591] fix: only apply scroller overspread to head and tail client --- src/layout/horizontal.h | 1 + src/layout/vertical.h | 1 + 2 files changed, 2 insertions(+) diff --git a/src/layout/horizontal.h b/src/layout/horizontal.h index b8016d50..8140934a 100644 --- a/src/layout/horizontal.h +++ b/src/layout/horizontal.h @@ -374,6 +374,7 @@ void scroller(Monitor *m) { bool need_apply_overspread = scroller_prefer_overspread && m->visible_scroll_tiling_clients > 1 && + (focus_client_index == 0 || focus_client_index == n - 1) && tempClients[focus_client_index]->scroller_proportion < 1.0f; if (need_apply_overspread) { diff --git a/src/layout/vertical.h b/src/layout/vertical.h index f036ca46..4759e7a5 100644 --- a/src/layout/vertical.h +++ b/src/layout/vertical.h @@ -358,6 +358,7 @@ void vertical_scroller(Monitor *m) { bool need_apply_overspread = scroller_prefer_overspread && m->visible_scroll_tiling_clients > 1 && + (focus_client_index == 0 || focus_client_index == n - 1) && tempClients[focus_client_index]->scroller_proportion < 1.0f; if (need_apply_overspread) { From 68075c00445e23028ec49fa1008bec8c9bb1cdb7 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Thu, 19 Feb 2026 09:59:58 +0800 Subject: [PATCH 534/591] feat: support index arg in switch_keyboard_layout --- src/config/parse_config.h | 1 + src/dispatch/bind_define.h | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/config/parse_config.h b/src/config/parse_config.h index 64afd889..830d22ba 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -1017,6 +1017,7 @@ FuncType parse_func_name(char *func_name, Arg *arg, char *arg_value, (*arg).v = strdup(arg_value); } else if (strcmp(func_name, "switch_keyboard_layout") == 0) { func = switch_keyboard_layout; + (*arg).i = CLAMP_INT(atoi(arg_value), 0, 100); } else if (strcmp(func_name, "setlayout") == 0) { func = setlayout; (*arg).v = strdup(arg_value); diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index 0bfab158..bd065141 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -900,7 +900,13 @@ int32_t switch_keyboard_layout(const Arg *arg) { wlr_log(WLR_INFO, "Only one layout available"); return 0; } - xkb_layout_index_t next = (current + 1) % num_layouts; + + xkb_layout_index_t next = 0; + if (arg->i > 0 && arg->i <= num_layouts) { + next = arg->i - 1; + } else { + next = (current + 1) % num_layouts; + } // 6. 应用新 keymap uint32_t depressed = keyboard->modifiers.depressed; From 2f12f46919a3e224156f6c83e07aeff1f48b72e2 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Thu, 19 Feb 2026 19:07:36 +0800 Subject: [PATCH 535/591] opt: use base surface of client when xytonode in rect node --- src/fetch/common.h | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/fetch/common.h b/src/fetch/common.h index 58e69dc1..57a1a8e6 100644 --- a/src/fetch/common.h +++ b/src/fetch/common.h @@ -100,10 +100,6 @@ void xytonode(double x, double y, struct wlr_surface **psurface, Client **pc, surface = wlr_scene_surface_try_from_buffer( wlr_scene_buffer_from_node(node)) ->surface; - else if (node->type == WLR_SCENE_NODE_RECT) { - surface = NULL; - break; - } /* start from the topmost layer, find a sureface that can be focused by pointer, @@ -119,6 +115,13 @@ void xytonode(double x, double y, struct wlr_surface **psurface, Client **pc, l = pnode->data; } } + + if (node->type == WLR_SCENE_NODE_RECT) { + if (c) { + surface = client_surface(c); + } + break; + } } if (psurface) From f0259c6285a8a1f1ca5759414fb1bcbe54799956 Mon Sep 17 00:00:00 2001 From: Emil Miler Date: Thu, 19 Feb 2026 15:02:03 +0100 Subject: [PATCH 536/591] Include packaging status in README --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 9b558fd1..05eaaaec 100644 --- a/README.md +++ b/README.md @@ -44,6 +44,8 @@ https://github.com/user-attachments/assets/bb83004a-0563-4b48-ad89-6461a9b78b1f # Installation +[![Packaging status](https://repology.org/badge/vertical-allrepos/mangowc.svg)](https://repology.org/project/mangowc/versions) + ## Dependencies - glibc From 595f9e34327a65828984aa8df1f4f9251d8504e9 Mon Sep 17 00:00:00 2001 From: Baba Date: Thu, 19 Feb 2026 14:24:56 -0600 Subject: [PATCH 537/591] include tgmix in README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9b558fd1..d468e7f7 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ https://github.com/user-attachments/assets/bb83004a-0563-4b48-ad89-6461a9b78b1f - vertical_tile - vertical_grid - vertical_scroller - +- tgmix (tile-grid mix) # Installation ## Dependencies From 07aed60245440fe2b4c6add0d50f7dfbffa550a2 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sat, 21 Feb 2026 16:37:37 +0800 Subject: [PATCH 538/591] opt: improve some risk judgments --- src/dispatch/bind_define.h | 105 +++++++++++++++++++++++++++++++++++-- src/fetch/client.h | 3 ++ src/mango.c | 11 ++-- 3 files changed, 113 insertions(+), 6 deletions(-) diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index bd065141..94d3d4ff 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -1,5 +1,6 @@ int32_t bind_to_view(const Arg *arg) { - + if (!selmon) + return 0; uint32_t target = arg->ui; if (view_current_to_back && selmon->pertag->curtag && @@ -100,6 +101,8 @@ int32_t defaultgaps(const Arg *arg) { } int32_t exchange_client(const Arg *arg) { + if (!selmon) + return 0; Client *c = selmon->sel; if (!c || c->isfloating) return 0; @@ -112,6 +115,9 @@ int32_t exchange_client(const Arg *arg) { } int32_t exchange_stack_client(const Arg *arg) { + if (!selmon) + return 0; + Client *c = selmon->sel; Client *tc = NULL; if (!c || c->isfloating || c->isfullscreen || c->ismaximizescreen) @@ -265,42 +271,56 @@ int32_t incnmaster(const Arg *arg) { } int32_t incgaps(const Arg *arg) { + if (!selmon) + return 0; setgaps(selmon->gappoh + arg->i, selmon->gappov + arg->i, selmon->gappih + arg->i, selmon->gappiv + arg->i); return 0; } int32_t incigaps(const Arg *arg) { + if (!selmon) + return 0; setgaps(selmon->gappoh, selmon->gappov, selmon->gappih + arg->i, selmon->gappiv + arg->i); return 0; } int32_t incogaps(const Arg *arg) { + if (!selmon) + return 0; setgaps(selmon->gappoh + arg->i, selmon->gappov + arg->i, selmon->gappih, selmon->gappiv); return 0; } int32_t incihgaps(const Arg *arg) { + if (!selmon) + return 0; setgaps(selmon->gappoh, selmon->gappov, selmon->gappih + arg->i, selmon->gappiv); return 0; } int32_t incivgaps(const Arg *arg) { + if (!selmon) + return 0; setgaps(selmon->gappoh, selmon->gappov, selmon->gappih, selmon->gappiv + arg->i); return 0; } int32_t incohgaps(const Arg *arg) { + if (!selmon) + return 0; setgaps(selmon->gappoh + arg->i, selmon->gappov, selmon->gappih, selmon->gappiv); return 0; } int32_t incovgaps(const Arg *arg) { + if (!selmon) + return 0; setgaps(selmon->gappoh, selmon->gappov + arg->i, selmon->gappih, selmon->gappiv); return 0; @@ -330,6 +350,8 @@ int32_t setmfact(const Arg *arg) { int32_t killclient(const Arg *arg) { Client *c = NULL; + if (!selmon) + return 0; c = selmon->sel; if (c) { pending_kill_client(c); @@ -399,6 +421,8 @@ int32_t moveresize(const Arg *arg) { int32_t movewin(const Arg *arg) { Client *c = NULL; + if (!selmon) + return 0; c = selmon->sel; if (!c || c->isfullscreen) return 0; @@ -442,6 +466,8 @@ int32_t quit(const Arg *arg) { int32_t resizewin(const Arg *arg) { Client *c = NULL; + if (!selmon) + return 0; c = selmon->sel; int32_t offsetx = 0, offsety = 0; @@ -546,6 +572,8 @@ int32_t restore_minimized(const Arg *arg) { int32_t setlayout(const Arg *arg) { int32_t jk; + if (!selmon) + return 0; for (jk = 0; jk < LENGTH(layouts); jk++) { if (strcmp(layouts[jk].name, arg->v) == 0) { @@ -571,6 +599,8 @@ int32_t setkeymode(const Arg *arg) { } int32_t set_proportion(const Arg *arg) { + if (!selmon) + return 0; if (selmon->isoverview || !is_scroller_layout(selmon)) return 0; @@ -596,6 +626,8 @@ int32_t smartmovewin(const Arg *arg) { Client *c = NULL, *tc = NULL; int32_t nx, ny; int32_t buttom, top, left, right, tar; + if (!selmon) + return 0; c = selmon->sel; if (!c || c->isfullscreen) return 0; @@ -697,6 +729,8 @@ int32_t smartresizewin(const Arg *arg) { Client *c = NULL, *tc = NULL; int32_t nw, nh; int32_t buttom, top, left, right, tar; + if (!selmon) + return 0; c = selmon->sel; if (!c || c->isfullscreen) return 0; @@ -765,6 +799,8 @@ int32_t smartresizewin(const Arg *arg) { int32_t centerwin(const Arg *arg) { Client *c = NULL; + if (!selmon) + return 0; c = selmon->sel; if (!c || c->isfullscreen || c->ismaximizescreen) @@ -943,6 +979,9 @@ int32_t switch_layout(const Arg *arg) { char *target_layout_name = NULL; uint32_t len; + if (!selmon) + return 0; + if (config.circle_layout_count != 0) { for (jk = 0; jk < config.circle_layout_count; jk++) { @@ -994,6 +1033,8 @@ int32_t switch_layout(const Arg *arg) { int32_t switch_proportion_preset(const Arg *arg) { float target_proportion = 0; + if (!selmon) + return 0; if (config.scroller_proportion_preset_count == 0) { return 0; @@ -1038,6 +1079,8 @@ int32_t switch_proportion_preset(const Arg *arg) { } int32_t tag(const Arg *arg) { + if (!selmon) + return 0; Client *target_client = selmon->sel; tag_client(arg, target_client); return 0; @@ -1045,6 +1088,8 @@ int32_t tag(const Arg *arg) { int32_t tagmon(const Arg *arg) { Monitor *m = NULL, *cm = NULL; + if (!selmon) + return 0; Client *c = focustop(selmon); if (!c) @@ -1136,6 +1181,9 @@ int32_t tagsilent(const Arg *arg) { } int32_t tagtoleft(const Arg *arg) { + if (!selmon) + return 0; + if (selmon->sel != NULL && __builtin_popcount(selmon->tagset[selmon->seltags] & TAGMASK) == 1 && selmon->tagset[selmon->seltags] > 1) { @@ -1145,6 +1193,9 @@ int32_t tagtoleft(const Arg *arg) { } int32_t tagtoright(const Arg *arg) { + if (!selmon) + return 0; + if (selmon->sel != NULL && __builtin_popcount(selmon->tagset[selmon->seltags] & TAGMASK) == 1 && selmon->tagset[selmon->seltags] & (TAGMASK >> 1)) { @@ -1173,6 +1224,8 @@ int32_t toggle_named_scratchpad(const Arg *arg) { } int32_t toggle_render_border(const Arg *arg) { + if (!selmon) + return 0; render_border = !render_border; arrange(selmon, false, false); return 0; @@ -1208,6 +1261,8 @@ int32_t toggle_scratchpad(const Arg *arg) { } int32_t togglefakefullscreen(const Arg *arg) { + if (!selmon) + return 0; Client *sel = focustop(selmon); if (sel) setfakefullscreen(sel, !sel->isfakefullscreen); @@ -1215,6 +1270,9 @@ int32_t togglefakefullscreen(const Arg *arg) { } int32_t togglefloating(const Arg *arg) { + if (!selmon) + return 0; + Client *sel = focustop(selmon); if (selmon && selmon->isoverview) @@ -1236,6 +1294,9 @@ int32_t togglefloating(const Arg *arg) { } int32_t togglefullscreen(const Arg *arg) { + if (!selmon) + return 0; + Client *sel = focustop(selmon); if (!sel) return 0; @@ -1252,6 +1313,9 @@ int32_t togglefullscreen(const Arg *arg) { } int32_t toggleglobal(const Arg *arg) { + if (!selmon) + return 0; + if (!selmon->sel) return 0; if (selmon->sel->is_in_scratchpad) { @@ -1270,12 +1334,18 @@ int32_t toggleglobal(const Arg *arg) { } int32_t togglegaps(const Arg *arg) { + if (!selmon) + return 0; + enablegaps ^= 1; arrange(selmon, false, false); return 0; } int32_t togglemaximizescreen(const Arg *arg) { + if (!selmon) + return 0; + Client *sel = focustop(selmon); if (!sel) return 0; @@ -1294,6 +1364,9 @@ int32_t togglemaximizescreen(const Arg *arg) { } int32_t toggleoverlay(const Arg *arg) { + if (!selmon) + return 0; + if (!selmon->sel || !selmon->sel->mon || selmon->sel->isfullscreen) { return 0; } @@ -1315,6 +1388,9 @@ int32_t toggleoverlay(const Arg *arg) { } int32_t toggletag(const Arg *arg) { + if (!selmon) + return 0; + uint32_t newtags; Client *sel = focustop(selmon); if (!sel) @@ -1338,13 +1414,15 @@ int32_t toggletag(const Arg *arg) { } int32_t toggleview(const Arg *arg) { + if (!selmon) + return 0; + uint32_t newtagset; uint32_t target; target = arg->ui == 0 ? ~0 & TAGMASK : arg->ui; - newtagset = - selmon ? selmon->tagset[selmon->seltags] ^ (target & TAGMASK) : 0; + newtagset = selmon->tagset[selmon->seltags] ^ (target & TAGMASK); if (newtagset) { selmon->tagset[selmon->seltags] = newtagset; @@ -1356,6 +1434,9 @@ int32_t toggleview(const Arg *arg) { } int32_t viewtoleft(const Arg *arg) { + if (!selmon) + return 0; + uint32_t target = selmon->tagset[selmon->seltags]; if (selmon->isoverview || selmon->pertag->curtag == 0) { @@ -1376,6 +1457,9 @@ int32_t viewtoleft(const Arg *arg) { } int32_t viewtoright(const Arg *arg) { + if (!selmon) + return 0; + if (selmon->isoverview || selmon->pertag->curtag == 0) { return 0; } @@ -1393,6 +1477,9 @@ int32_t viewtoright(const Arg *arg) { } int32_t viewtoleft_have_client(const Arg *arg) { + if (!selmon) + return 0; + uint32_t n; uint32_t current = get_tags_first_tag_num(selmon->tagset[selmon->seltags]); bool found = false; @@ -1417,6 +1504,9 @@ int32_t viewtoleft_have_client(const Arg *arg) { } int32_t viewtoright_have_client(const Arg *arg) { + if (!selmon) + return 0; + uint32_t n; uint32_t current = get_tags_first_tag_num(selmon->tagset[selmon->seltags]); bool found = false; @@ -1441,6 +1531,9 @@ int32_t viewtoright_have_client(const Arg *arg) { } int32_t viewcrossmon(const Arg *arg) { + if (!selmon) + return 0; + focusmon(&(Arg){.v = arg->v, .i = UNDIR}); view_in_mon(arg, true, selmon, true); return 0; @@ -1519,6 +1612,8 @@ int32_t setoption(const Arg *arg) { } int32_t minimized(const Arg *arg) { + if (!selmon) + return 0; if (selmon && selmon->isoverview) return 0; @@ -1541,6 +1636,8 @@ void fix_mon_tagset_from_overview(Monitor *m) { int32_t toggleoverview(const Arg *arg) { Client *c = NULL; + if (!selmon) + return 0; if (selmon->isoverview && ov_tab_mode && arg->i != 1 && selmon->sel) { focusstack(&(Arg){.i = 1}); @@ -1646,6 +1743,8 @@ int32_t toggle_monitor(const Arg *arg) { } int32_t scroller_stack(const Arg *arg) { + if (!selmon) + return 0; Client *c = selmon->sel; Client *stack_head = NULL; Client *source_stack_head = NULL; diff --git a/src/fetch/client.h b/src/fetch/client.h index 8fccb261..11edb76b 100644 --- a/src/fetch/client.h +++ b/src/fetch/client.h @@ -83,6 +83,9 @@ setclient_coordinate_center(Client *c, Monitor *tm, struct wlr_box geom, int32_t len = 0; Monitor *m = tm ? tm : selmon; + if (!m) + return geom; + uint32_t cbw = check_hit_no_border(c) ? c->bw : 0; if (!c->no_force_center && m) { diff --git a/src/mango.c b/src/mango.c index 540395ae..45d72885 100644 --- a/src/mango.c +++ b/src/mango.c @@ -1379,6 +1379,9 @@ void applyrules(Client *c) { Client *fc = NULL; Client *parent = NULL; + if (!c) + return; + parent = client_get_parent(c); Monitor *mon = parent && parent->mon ? parent->mon : selmon; @@ -1467,7 +1470,8 @@ void applyrules(Client *c) { /*-----------------------apply rule action-------------------------*/ // rule action only apply after map not apply in the init commit - if (!client_surface(c)->mapped) + struct wlr_surface *surface = client_surface(c); + if (!surface || !surface->mapped) return; // apply swallow rule @@ -1493,6 +1497,7 @@ void applyrules(Client *c) { setmon(c, mon, newtags, !c->isopensilent && !(client_is_x11_popup(c) && client_should_ignore_focus(c)) && + mon && (!c->istagsilent || !newtags || newtags & mon->tagset[mon->seltags])); @@ -1514,7 +1519,7 @@ void applyrules(Client *c) { window in the current tag will exit fullscreen and participate in tiling */ wl_list_for_each(fc, &clients, - link) if (fc && fc != c && c->tags & fc->tags && + link) if (fc && fc != c && c->tags & fc->tags && c->mon && VISIBLEON(fc, c->mon) && ISFULLSCREEN(fc) && !c->isfloating) { clear_fullscreen_flag(fc); @@ -1533,7 +1538,7 @@ void applyrules(Client *c) { } // apply overlay rule - if (c->isoverlay) { + if (c->isoverlay && c->scene) { wlr_scene_node_reparent(&c->scene->node, layers[LyrOverlay]); wlr_scene_node_raise_to_top(&c->scene->node); } From 3d680523d6d1d9d2d9ccbb95794bd7affee97121 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sat, 21 Feb 2026 16:53:21 +0800 Subject: [PATCH 539/591] opt: if app open when no monitor, init tags and size in updatemons --- src/mango.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/mango.c b/src/mango.c index 45d72885..93f59800 100644 --- a/src/mango.c +++ b/src/mango.c @@ -5958,6 +5958,10 @@ void updatemons(struct wl_listener *listener, void *data) { c->mon = selmon; reset_foreign_tolevel(c); } + if(c->tags ==0 && !c->is_in_scratchpad) { + c->tags = selmon->tagset[selmon->seltags]; + set_size_per(selmon,c); + } } focusclient(focustop(selmon), 1); if (selmon->lock_surface) { From d1fd12898153853e2e2e77b709f4ea1ea7aa0d7f Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sat, 21 Feb 2026 18:52:54 +0800 Subject: [PATCH 540/591] fix: auto set monitor coordinate when no match monitor rule --- src/mango.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/mango.c b/src/mango.c index 93f59800..2c4fc436 100644 --- a/src/mango.c +++ b/src/mango.c @@ -2811,6 +2811,8 @@ void createmon(struct wl_listener *listener, void *data) { m->isoverview = 0; m->sel = NULL; m->is_in_hotarea = 0; + m->m.x = INT32_MAX; + m->m.y = INT32_MAX; float scale = 1; enum wl_output_transform rr = WL_OUTPUT_TRANSFORM_NORMAL; wlr_output_state_set_scale(&state, scale); From ee8a7b5961bfd306b1b592cc15268ce2a5ab31a8 Mon Sep 17 00:00:00 2001 From: Mujk <119647238+Mujk@users.noreply.github.com> Date: Fri, 20 Feb 2026 19:56:26 +0100 Subject: [PATCH 541/591] docs: fix guix installation instructions - Rename GuixSD to Guix System (the distro was renamed in 2019) --- README.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 05eaaaec..29c356ea 100644 --- a/README.md +++ b/README.md @@ -101,7 +101,7 @@ Then, install the package: dnf install mangowc ``` -## GuixSD +## Guix System The package definition is described in the source repository. First, add `mangowc` channel to `channels.scm` file: @@ -109,7 +109,8 @@ First, add `mangowc` channel to `channels.scm` file: ;; In $HOME/.config/guix/channels.scm (cons (channel (name 'mangowc) - (url "https://github.com/DreamMaoMao/mangowc.git")) + (url "https://github.com/DreamMaoMao/mangowc.git") + (branch "main")) ... ;; Your other channels %default-channels) ``` @@ -121,8 +122,8 @@ Then, run `guix pull` and after update you can either run (use-modules (mangowc)) ;; Add mangowc module ;; Add mangowc to packages list -(packages (cons - mangowc +(packages (cons* + mangowc-git ... ;; Other packages you specified %base-packages)) ``` From 6b2d694b234cae9876eb81e27991439eb51860f1 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sun, 22 Feb 2026 11:11:07 +0800 Subject: [PATCH 542/591] update readme --- README.md | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index c91192d9..45da36cd 100644 --- a/README.md +++ b/README.md @@ -27,11 +27,18 @@ This project's development is based on [dwl](https://codeberg.org/dwl/dwl/). https://github.com/user-attachments/assets/bb83004a-0563-4b48-ad89-6461a9b78b1f +# Mango's Vision + +**Mango's primary goal is stability**: After months of testing and development—and aside from a few lingering GPU compatibility issues—it should now be stable enough. I don't plan on making many breaking changes. + +**Mango's preference is practicality**: I tend to add features that genuinely help with daily workflows—things that make our work more convenient. + +**Mango won't cater to every user preference**: For niche feature requests, I'll take a wait-and-see approach. I'll only consider adding them if they get a significant number of upvotes. + # Our discord [mangowc](https://discord.gg/CPjbDxesh5) # Supported layouts - - tile - scroller - monocle @@ -41,23 +48,20 @@ https://github.com/user-attachments/assets/bb83004a-0563-4b48-ad89-6461a9b78b1f - vertical_tile - vertical_grid - vertical_scroller -- tgmix (tile-grid mix) +- tgmix + # Installation [![Packaging status](https://repology.org/badge/vertical-allrepos/mangowc.svg)](https://repology.org/project/mangowc/versions) ## Dependencies -- glibc - wayland - wayland-protocols - libinput - libdrm - libxkbcommon - pixman -- git -- meson -- ninja - libdisplay-info - libliftoff - hwdata From f8fa7a856c3a569974cc89955d640167b2958205 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Mon, 23 Feb 2026 08:01:45 +0800 Subject: [PATCH 543/591] opt: optimize frame skip logic --- src/animation/client.h | 4 ++++ src/client/client.h | 28 ------------------------- src/mango.c | 47 ++++++++++++++++++++++++------------------ 3 files changed, 31 insertions(+), 48 deletions(-) diff --git a/src/animation/client.h b/src/animation/client.h index 2588fb1c..b6683ecc 100644 --- a/src/animation/client.h +++ b/src/animation/client.h @@ -990,6 +990,10 @@ void resize(Client *c, struct wlr_box geo, int32_t interact) { c->configure_serial = client_set_size(c, c->geom.width - 2 * c->bw, c->geom.height - 2 * c->bw); + if (c->configure_serial != 0) { + c->mon->resizing_count_pending++; + } + if (c == grabc) { c->animation.running = false; c->need_output_flush = false; diff --git a/src/client/client.h b/src/client/client.h index fd81a800..4788e448 100644 --- a/src/client/client.h +++ b/src/client/client.h @@ -243,34 +243,6 @@ static inline int32_t client_is_rendered_on_mon(Client *c, Monitor *m) { return 0; } -static inline int32_t client_is_stopped(Client *c) { - int32_t pid; - siginfo_t in = {0}; -#ifdef XWAYLAND - if (client_is_x11(c)) - return 0; -#endif - - wl_client_get_credentials(c->surface.xdg->client->client, &pid, NULL, NULL); - if (waitid(P_PID, pid, &in, WNOHANG | WCONTINUED | WSTOPPED | WNOWAIT) < - 0) { - /* This process is not our child process. We cannot determine its - * stopped state; assume it is not stopped to avoid blocking frame skip. - */ - if (errno == ECHILD) - return 0; // if not our child, assume not stopped - /* Other errors, also assume not stopped. */ - return 0; - } else if (in.si_pid) { - if (in.si_code == CLD_STOPPED || in.si_code == CLD_TRAPPED) - return 1; - if (in.si_code == CLD_CONTINUED) - return 0; - } - - return 0; -} - static inline int32_t client_is_unmanaged(Client *c) { #ifdef XWAYLAND if (client_is_x11(c)) diff --git a/src/mango.c b/src/mango.c index 2c4fc436..fc7eeebc 100644 --- a/src/mango.c +++ b/src/mango.c @@ -503,13 +503,15 @@ struct Monitor { struct wl_listener request_state; struct wl_listener destroy_lock_surface; struct wlr_session_lock_surface_v1 *lock_surface; - struct wl_event_source *skip_timeout; + struct wl_event_source *skip_frame_timeout; struct wlr_box m; /* monitor area, layout-relative */ struct wlr_box w; /* window area, layout-relative */ struct wl_list layers[4]; /* LayerSurface::link */ uint32_t seltags; uint32_t tagset[2]; bool skiping_frame; + uint32_t resizing_count_pending; + uint32_t resizing_count_current; struct wl_list dwl_ipc_outputs; int32_t gappih; /* horizontal gap between windows */ @@ -786,7 +788,7 @@ static Client *get_scroll_stack_head(Client *c); static bool client_only_in_one_tag(Client *c); static Client *get_focused_stack_client(Client *sc); static bool client_is_in_same_stack(Client *sc, Client *tc, Client *fc); -static void monitor_stop_skip_timer(Monitor *m); +static void monitor_stop_skip_frame_timer(Monitor *m); static int monitor_skip_frame_timeout_callback(void *data); #include "data/static_keymap.h" @@ -2234,10 +2236,10 @@ void cleanupmon(struct wl_listener *listener, void *data) { wlr_scene_node_destroy(&m->blur->node); m->blur = NULL; } - if (m->skip_timeout) { - monitor_stop_skip_timer(m); - wl_event_source_remove(m->skip_timeout); - m->skip_timeout = NULL; + if (m->skip_frame_timeout) { + monitor_stop_skip_frame_timer(m); + wl_event_source_remove(m->skip_frame_timeout); + m->skip_frame_timeout = NULL; } m->wlr_output->data = NULL; free(m->pertag); @@ -2790,9 +2792,11 @@ void createmon(struct wl_listener *listener, void *data) { struct wl_event_loop *loop = wl_display_get_event_loop(dpy); m = wlr_output->data = ecalloc(1, sizeof(*m)); - m->skip_timeout = + m->skip_frame_timeout = wl_event_loop_add_timer(loop, monitor_skip_frame_timeout_callback, m); m->skiping_frame = false; + m->resizing_count_pending = 0; + m->resizing_count_current = 0; m->wlr_output = wlr_output; m->wlr_output->data = m; @@ -4443,10 +4447,12 @@ void client_set_opacity(Client *c, double opacity) { scene_buffer_apply_opacity, &opacity); } -void monitor_stop_skip_timer(Monitor *m) { - if (m->skip_timeout) - wl_event_source_timer_update(m->skip_timeout, 0); +void monitor_stop_skip_frame_timer(Monitor *m) { + if (m->skip_frame_timeout) + wl_event_source_timer_update(m->skip_frame_timeout, 0); m->skiping_frame = false; + m->resizing_count_pending = 0; + m->resizing_count_current = 0; } static int monitor_skip_frame_timeout_callback(void *data) { @@ -4455,20 +4461,22 @@ static int monitor_skip_frame_timeout_callback(void *data) { wl_list_for_each_safe(c, tmp, &clients, link) { c->configure_serial = 0; } - monitor_stop_skip_timer(m); + monitor_stop_skip_frame_timer(m); wlr_output_schedule_frame(m->wlr_output); return 1; } void monitor_check_skip_frame_timeout(Monitor *m) { - if (m->skiping_frame) { + if (m->skiping_frame && + m->resizing_count_pending == m->resizing_count_current) { return; } - if (m->skip_timeout) { - wl_event_source_timer_update(m->skip_timeout, 100); // 100ms + if (m->skip_frame_timeout) { + m->resizing_count_current = m->resizing_count_pending; m->skiping_frame = true; + wl_event_source_timer_update(m->skip_frame_timeout, 100); // 100ms } } @@ -4511,16 +4519,15 @@ void rendermon(struct wl_listener *listener, void *data) { // 绘制客户端 wl_list_for_each(c, &clients, link) { need_more_frames = client_draw_frame(c) || need_more_frames; - if (!animations && !(allow_tearing && frame_allow_tearing) && - c->configure_serial && client_is_rendered_on_mon(c, m) && - !client_is_stopped(c) && !grabc) { + if (!animations && !grabc && c->configure_serial && + client_is_rendered_on_mon(c, m)) { monitor_check_skip_frame_timeout(m); goto skip; } } if (m->skiping_frame) { - monitor_stop_skip_timer(m); + monitor_stop_skip_frame_timer(m); } // 只有在需要帧时才构建和提交状态 @@ -5960,9 +5967,9 @@ void updatemons(struct wl_listener *listener, void *data) { c->mon = selmon; reset_foreign_tolevel(c); } - if(c->tags ==0 && !c->is_in_scratchpad) { + if (c->tags == 0 && !c->is_in_scratchpad) { c->tags = selmon->tagset[selmon->seltags]; - set_size_per(selmon,c); + set_size_per(selmon, c); } } focusclient(focustop(selmon), 1); From 2f630c950e0f7ef4a5bc3c81abf9a6e1d0e88e05 Mon Sep 17 00:00:00 2001 From: Jiatao Liang Date: Thu, 19 Feb 2026 16:20:56 -0500 Subject: [PATCH 544/591] optional-session-manager --- nix/nixos-modules.nix | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/nix/nixos-modules.nix b/nix/nixos-modules.nix index 33811022..7a9f930a 100644 --- a/nix/nixos-modules.nix +++ b/nix/nixos-modules.nix @@ -9,6 +9,10 @@ in { options = { programs.mango = { enable = lib.mkEnableOption "mango, a wayland compositor based on dwl"; + addLoginEntry = lib.mkEnableOption { + default = true; + description = "Whether to add a login entry to the display manager for mango"; + }; package = lib.mkOption { type = lib.types.package; default = self.packages.${pkgs.stdenv.hostPlatform.system}.mango; @@ -55,7 +59,7 @@ in { programs.xwayland.enable = lib.mkDefault true; services = { - displayManager.sessionPackages = [cfg.package]; + displayManager.sessionPackages = lib.mkIf cfg.addLoginEntry [ cfg.package ]; graphical-desktop.enable = lib.mkDefault true; }; From a28647585fc75fa492ae9f29ee7b9e542803ddad Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Tue, 24 Feb 2026 21:40:26 +0800 Subject: [PATCH 545/591] feat: set dbus env auto --- config.conf => assets/config.conf | 0 assets/mango-portals.conf | 10 ++++ mango.desktop => assets/mango.desktop | 0 meson.build | 6 +- src/common/util.c | 82 +++++++++++++++++++++++++++ src/common/util.h | 6 +- src/config/parse_config.h | 10 ++++ src/mango.c | 44 ++++++++++++++ 8 files changed, 155 insertions(+), 3 deletions(-) rename config.conf => assets/config.conf (100%) create mode 100644 assets/mango-portals.conf rename mango.desktop => assets/mango.desktop (100%) diff --git a/config.conf b/assets/config.conf similarity index 100% rename from config.conf rename to assets/config.conf diff --git a/assets/mango-portals.conf b/assets/mango-portals.conf new file mode 100644 index 00000000..645344af --- /dev/null +++ b/assets/mango-portals.conf @@ -0,0 +1,10 @@ +[preferred] +default=gtk +org.freedesktop.impl.portal.ScreenCast=wlr +org.freedesktop.impl.portal.Screenshot=wlr + +### My addition ### +# ignore inhibit bc gtk portal always returns as success, +# despite sway/the wlr portal not having an implementation, +# stopping firefox from using wayland idle-inhibit +org.freedesktop.impl.portal.Inhibit=none diff --git a/mango.desktop b/assets/mango.desktop similarity index 100% rename from mango.desktop rename to assets/mango.desktop diff --git a/meson.build b/meson.build index 06ccfd75..3f2e5e50 100644 --- a/meson.build +++ b/meson.build @@ -147,5 +147,7 @@ executable('mmsg', ) desktop_install_dir = join_paths(prefix, 'share/wayland-sessions') -install_data('mango.desktop', install_dir : desktop_install_dir) -install_data('config.conf', install_dir : join_paths(sysconfdir, 'mango')) +portal_install_dir = join_paths(prefix, 'share/xdg-desktop-portal') +install_data('assets/mango.desktop', install_dir : desktop_install_dir) +install_data('assets/mango-portals.conf', install_dir : portal_install_dir) +install_data('assets/config.conf', install_dir : join_paths(sysconfdir, 'mango')) diff --git a/src/common/util.c b/src/common/util.c index a15cca7c..025aed6d 100644 --- a/src/common/util.c +++ b/src/common/util.c @@ -92,3 +92,85 @@ uint32_t get_now_in_ms(void) { uint32_t timespec_to_ms(struct timespec *ts) { return (uint32_t)ts->tv_sec * 1000 + (uint32_t)ts->tv_nsec / 1000000; } + +char *join_strings(char *arr[], const char *sep) { + if (!arr || !arr[0]) { + char *empty = malloc(1); + if (empty) + empty[0] = '\0'; + return empty; + } + + size_t total_len = 0; + int count = 0; + for (int i = 0; arr[i] != NULL; i++) { + total_len += strlen(arr[i]); + count++; + } + if (count > 0) { + total_len += strlen(sep) * (count - 1); + } + + char *result = malloc(total_len + 1); + if (!result) + return NULL; + + result[0] = '\0'; + for (int i = 0; arr[i] != NULL; i++) { + if (i > 0) + strcat(result, sep); + strcat(result, arr[i]); + } + return result; +} + +char *join_strings_with_suffix(char *arr[], const char *suffix, + const char *sep) { + if (!arr || !arr[0]) { + char *empty = malloc(1); + if (empty) + empty[0] = '\0'; + return empty; + } + + size_t total_len = 0; + int count = 0; + for (int i = 0; arr[i] != NULL; i++) { + total_len += strlen(arr[i]) + strlen(suffix); + count++; + } + if (count > 0) { + total_len += strlen(sep) * (count - 1); + } + + char *result = malloc(total_len + 1); + if (!result) + return NULL; + + result[0] = '\0'; + for (int i = 0; arr[i] != NULL; i++) { + if (i > 0) + strcat(result, sep); + strcat(result, arr[i]); + strcat(result, suffix); + } + return result; +} + +char *string_printf(const char *fmt, ...) { + va_list args; + va_start(args, fmt); + int len = vsnprintf(NULL, 0, fmt, args); + va_end(args); + if (len < 0) + return NULL; + + char *str = malloc(len + 1); + if (!str) + return NULL; + + va_start(args, fmt); + vsnprintf(str, len + 1, fmt, args); + va_end(args); + return str; +} diff --git a/src/common/util.h b/src/common/util.h index 8fb60338..cb232ac5 100644 --- a/src/common/util.h +++ b/src/common/util.h @@ -7,4 +7,8 @@ int32_t fd_set_nonblock(int32_t fd); int32_t regex_match(const char *pattern_mb, const char *str_mb); void wl_list_append(struct wl_list *list, struct wl_list *object); uint32_t get_now_in_ms(void); -uint32_t timespec_to_ms(struct timespec *ts); \ No newline at end of file +uint32_t timespec_to_ms(struct timespec *ts); +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, ...); \ No newline at end of file diff --git a/src/config/parse_config.h b/src/config/parse_config.h index 830d22ba..1c333834 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -3647,6 +3647,16 @@ void reapply_cursor_style(void) { cursor_mgr = wlr_xcursor_manager_create(config.cursor_theme, cursor_size); + if(cursor_size > 0){ + char size_str[16]; + snprintf(size_str, sizeof(size_str), "%d", 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); diff --git a/src/mango.c b/src/mango.c index fc7eeebc..886a8a29 100644 --- a/src/mango.c +++ b/src/mango.c @@ -894,6 +894,12 @@ static KeyMode keymode = { .mode = {'d', 'e', 'f', 'a', 'u', 'l', 't', '\0'}, .isdefault = true, }; + +static char *env_vars[] = {"DISPLAY", + "WAYLAND_DISPLAY", + "XDG_CURRENT_DESKTOP", + "XDG_SESSION_TYPE", + NULL}; static struct { enum wp_cursor_shape_device_v1_shape shape; struct wlr_surface *surface; @@ -4727,6 +4733,41 @@ void exchange_two_client(Client *c1, Client *c2) { } } +void set_activation_env() { + if (!getenv("DBUS_SESSION_BUS_ADDRESS")) { + wlr_log(WLR_INFO, "Not updating dbus execution environment: " + "DBUS_SESSION_BUS_ADDRESS not set"); + return; + } + + wlr_log(WLR_INFO, "Updating dbus execution environment"); + + char *env_keys = join_strings(env_vars, " "); + + // first command: dbus-update-activation-environment + const char *arg1 = env_keys; + char *cmd1 = string_printf("dbus-update-activation-environment %s", arg1); + if (!cmd1) { + wlr_log(WLR_ERROR, "Failed to allocate command string"); + goto cleanup; + } + spawn(&(Arg){.v = cmd1}); + free(cmd1); + + // second command: systemctl --user + const char *action = "import-environment"; + char *cmd2 = string_printf("systemctl --user %s %s", action, env_keys); + if (!cmd2) { + wlr_log(WLR_ERROR, "Failed to allocate command string"); + goto cleanup; + } + spawn(&(Arg){.v = cmd2}); + free(cmd2); + +cleanup: + free(env_keys); +} + void // 17 run(char *startup_cmd) { @@ -4784,6 +4825,8 @@ run(char *startup_cmd) { wlr_cursor_set_xcursor(cursor, cursor_mgr, "left_ptr"); handlecursoractivity(); + set_activation_env(); + run_exec(); run_exec_once(); @@ -5280,6 +5323,7 @@ void setup(void) { setenv("XCURSOR_SIZE", "24", 1); setenv("XDG_CURRENT_DESKTOP", "mango", 1); + parse_config(); init_baked_points(); From 564df864bf3b81c1bcd576a310e5ba297d8880a5 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Wed, 25 Feb 2026 10:06:58 +0800 Subject: [PATCH 546/591] fix: popup position constrain not work for some app --- src/config/parse_config.h | 8 +- src/ext-protocol/text-input.h | 11 +-- src/fetch/monitor.h | 9 +++ src/mango.c | 137 ++++++++++++++++++++++++++-------- 4 files changed, 118 insertions(+), 47 deletions(-) diff --git a/src/config/parse_config.h b/src/config/parse_config.h index 1c333834..95e54c05 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -3647,13 +3647,13 @@ void reapply_cursor_style(void) { cursor_mgr = wlr_xcursor_manager_create(config.cursor_theme, cursor_size); - if(cursor_size > 0){ - char size_str[16]; - snprintf(size_str, sizeof(size_str), "%d", cursor_size); + if (cursor_size > 0) { + char size_str[16]; + snprintf(size_str, sizeof(size_str), "%d", cursor_size); setenv("XCURSOR_SIZE", size_str, 1); } - if(config.cursor_theme){ + if (config.cursor_theme) { setenv("XCURSOR_THEME", config.cursor_theme, 1); } diff --git a/src/ext-protocol/text-input.h b/src/ext-protocol/text-input.h index dbd97e11..e9f221a4 100644 --- a/src/ext-protocol/text-input.h +++ b/src/ext-protocol/text-input.h @@ -77,15 +77,6 @@ Monitor *output_from_wlr_output(struct wlr_output *wlr_output) { return NULL; } -Monitor *output_nearest_to(int32_t lx, int32_t ly) { - double closest_x, closest_y; - wlr_output_layout_closest_point(output_layout, NULL, lx, ly, &closest_x, - &closest_y); - - return output_from_wlr_output( - wlr_output_layout_output_at(output_layout, closest_x, closest_y)); -} - bool output_is_usable(Monitor *m) { return m && m->wlr_output->enabled; } static bool @@ -255,7 +246,7 @@ static void update_popup_position(struct dwl_input_method_popup *popup) { cursor_rect = (struct wlr_box){0}; } - output = output_nearest_to(cursor_rect.x, cursor_rect.y); + output = get_monitor_nearest_to(cursor_rect.x, cursor_rect.y); if (!output_is_usable(output)) { return; } diff --git a/src/fetch/monitor.h b/src/fetch/monitor.h index 7a1ca4dc..fd18498e 100644 --- a/src/fetch/monitor.h +++ b/src/fetch/monitor.h @@ -96,3 +96,12 @@ Monitor *xytomon(double x, double y) { struct wlr_output *o = wlr_output_layout_output_at(output_layout, x, y); return o ? o->data : NULL; } + +Monitor *get_monitor_nearest_to(int32_t lx, int32_t ly) { + double closest_x, closest_y; + wlr_output_layout_closest_point(output_layout, NULL, lx, ly, &closest_x, + &closest_y); + + return output_from_wlr_output( + wlr_output_layout_output_at(output_layout, closest_x, closest_y)); +} \ No newline at end of file diff --git a/src/mango.c b/src/mango.c index 886a8a29..c8288d05 100644 --- a/src/mango.c +++ b/src/mango.c @@ -486,6 +486,16 @@ typedef struct { bool being_unmapped; } LayerSurface; +typedef struct { + struct wlr_xdg_popup *wlr_popup; + Client *client; + LayerSurface *layer; + uint32_t type; + struct wl_listener destroy; + struct wl_listener commit; + struct wl_listener reposition; +} Popup; + typedef struct { const char *symbol; void (*arrange)(Monitor *); @@ -790,6 +800,7 @@ static Client *get_focused_stack_client(Client *sc); static bool client_is_in_same_stack(Client *sc, Client *tc, Client *fc); static void monitor_stop_skip_frame_timer(Monitor *m); static int monitor_skip_frame_timeout_callback(void *data); +static Monitor *get_monitor_nearest_to(int32_t lx, int32_t ly); #include "data/static_keymap.h" #include "dispatch/bind_declare.h" @@ -895,11 +906,8 @@ 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", NULL}; static struct { enum wp_cursor_shape_device_v1_shape shape; struct wlr_surface *surface; @@ -2545,37 +2553,107 @@ void destroydecoration(struct wl_listener *listener, void *data) { wl_list_remove(&c->set_decoration_mode.link); } -void commitpopup(struct wl_listener *listener, void *data) { +static void popup_unconstrain(Popup *popup) { + struct wlr_xdg_popup *wlr_popup = popup->wlr_popup; + + if (!wlr_popup || !wlr_popup->parent) { + return; + } + + struct wlr_scene_node *parent_node = wlr_popup->parent->data; + if (!parent_node) { + wlr_log(WLR_ERROR, "Popup parent has no scene node"); + return; + } + int parent_lx, parent_ly; + wlr_scene_node_coords(parent_node, &parent_lx, &parent_ly); + + struct wlr_box *scheduled = &wlr_popup->scheduled.geometry; + int popup_lx = parent_lx + scheduled->x; + int popup_ly = parent_ly + scheduled->y; + + Monitor *mon = get_monitor_nearest_to(popup_lx, popup_ly); + + struct wlr_box usable = popup->type == LayerShell ? mon->m : mon->w; + + struct wlr_box constraint_box = { + .x = usable.x - parent_lx, + .y = usable.y - parent_ly, + .width = usable.width, + .height = usable.height, + }; + + wlr_xdg_popup_unconstrain_from_box(wlr_popup, &constraint_box); +} + +static void destroypopup(struct wl_listener *listener, void *data) { + Popup *popup = wl_container_of(listener, popup, destroy); + wl_list_remove(&popup->destroy.link); + wl_list_remove(&popup->reposition.link); + free(popup); +} + +static void commitpopup(struct wl_listener *listener, void *data) { + Popup *popup = wl_container_of(listener, popup, commit); + struct wlr_surface *surface = data; - struct wlr_xdg_popup *popup = wlr_xdg_popup_try_from_wlr_surface(surface); - LayerSurface *l = NULL; + struct wlr_xdg_popup *wkr_popup = + wlr_xdg_popup_try_from_wlr_surface(surface); + Client *c = NULL; - struct wlr_box box; + LayerSurface *l = NULL; int32_t type = -1; - if (!popup || !popup->base->initial_commit) + if (!wkr_popup || !wkr_popup->base->initial_commit) goto commitpopup_listen_free; - type = toplevel_from_wlr_surface(popup->base->surface, &c, &l); - if (!popup->parent || !popup->parent->data || type < 0) - goto commitpopup_listen_free; - - wlr_scene_node_raise_to_top(popup->parent->data); - - popup->base->surface->data = - wlr_scene_xdg_surface_create(popup->parent->data, popup->base); - if ((l && !l->mon) || (c && !c->mon)) { - wlr_xdg_popup_destroy(popup); + type = toplevel_from_wlr_surface(wkr_popup->base->surface, &c, &l); + if (!wkr_popup->parent || !wkr_popup->parent->data || type < 0) { + wlr_xdg_popup_destroy(wkr_popup); goto commitpopup_listen_free; } - box = type == LayerShell ? l->mon->m : c->mon->w; - box.x -= (type == LayerShell ? l->scene->node.x : c->geom.x); - box.y -= (type == LayerShell ? l->scene->node.y : c->geom.y); - wlr_xdg_popup_unconstrain_from_box(popup, &box); + + wlr_scene_node_raise_to_top(wkr_popup->parent->data); + + wkr_popup->base->surface->data = + wlr_scene_xdg_surface_create(wkr_popup->parent->data, wkr_popup->base); + if ((l && !l->mon) || (c && !c->mon)) { + wlr_xdg_popup_destroy(wkr_popup); + goto commitpopup_listen_free; + } + + popup->client = c; + popup->layer = l; + popup->type = type; + popup->wlr_popup = wkr_popup; + + popup_unconstrain(popup); commitpopup_listen_free: - wl_list_remove(&listener->link); - free(listener); + wl_list_remove(&popup->commit.link); + popup->commit.notify = NULL; +} + +static void repositionpopup(struct wl_listener *listener, void *data) { + Popup *popup = wl_container_of(listener, popup, reposition); + popup_unconstrain(popup); +} + +static void createpopup(struct wl_listener *listener, void *data) { + struct wlr_xdg_popup *wlr_popup = data; + + Popup *popup = calloc(1, sizeof(Popup)); + if (!popup) + return; + + popup->destroy.notify = destroypopup; + wl_signal_add(&wlr_popup->events.destroy, &popup->destroy); + + popup->commit.notify = commitpopup; + wl_signal_add(&wlr_popup->base->surface->events.commit, &popup->commit); + + popup->reposition.notify = repositionpopup; + wl_signal_add(&wlr_popup->events.reposition, &popup->reposition); } void createdecoration(struct wl_listener *listener, void *data) { @@ -3165,13 +3243,6 @@ void createpointerconstraint(struct wl_listener *listener, void *data) { &pointer_constraint->destroy, destroypointerconstraint); } -void createpopup(struct wl_listener *listener, void *data) { - /* This event is raised when a client (either xdg-shell or layer-shell) - * creates a new popup. */ - struct wlr_xdg_popup *popup = data; - LISTEN_STATIC(&popup->base->surface->events.commit, commitpopup); -} - void cursorconstrain(struct wlr_pointer_constraint_v1 *constraint) { if (active_constraint == constraint) return; From 6894a36019db78395ba10ad01a522233478fbe34 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Wed, 25 Feb 2026 11:15:56 +0800 Subject: [PATCH 547/591] opt: remove some portal file comment --- assets/mango-portals.conf | 5 ----- 1 file changed, 5 deletions(-) diff --git a/assets/mango-portals.conf b/assets/mango-portals.conf index 645344af..aebea31a 100644 --- a/assets/mango-portals.conf +++ b/assets/mango-portals.conf @@ -2,9 +2,4 @@ default=gtk org.freedesktop.impl.portal.ScreenCast=wlr org.freedesktop.impl.portal.Screenshot=wlr - -### My addition ### -# ignore inhibit bc gtk portal always returns as success, -# despite sway/the wlr portal not having an implementation, -# stopping firefox from using wayland idle-inhibit org.freedesktop.impl.portal.Inhibit=none From e1c038ae087b1b683b583383f47b99479f4df67c Mon Sep 17 00:00:00 2001 From: qaqland Date: Wed, 25 Feb 2026 16:58:18 +0800 Subject: [PATCH 548/591] opt: remove unused variable in function rendermon Signed-off-by: qaqland --- src/mango.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/mango.c b/src/mango.c index c8288d05..1ba319a0 100644 --- a/src/mango.c +++ b/src/mango.c @@ -4560,7 +4560,6 @@ void monitor_check_skip_frame_timeout(Monitor *m) { void rendermon(struct wl_listener *listener, void *data) { Monitor *m = wl_container_of(listener, m, frame); Client *c = NULL, *tmp = NULL; - struct wlr_output_state pending = {0}; LayerSurface *l = NULL, *tmpl = NULL; int32_t i; struct wl_list *layer_list; @@ -4621,7 +4620,6 @@ skip: wlr_scene_output_send_frame_done(m->scene_output, &now); } else { wlr_scene_output_send_frame_done(m->scene_output, &now); - wlr_output_state_finish(&pending); } // 如果需要更多帧,确保安排下一帧 From bc5cf2c7d7da4655c8f0139f16a908f93fbb4b2a Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Wed, 25 Feb 2026 17:25:05 +0800 Subject: [PATCH 549/591] opt: remove useless code --- src/mango.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/mango.c b/src/mango.c index 1ba319a0..87423baa 100644 --- a/src/mango.c +++ b/src/mango.c @@ -4616,11 +4616,7 @@ void rendermon(struct wl_listener *listener, void *data) { skip: // 发送帧完成通知 clock_gettime(CLOCK_MONOTONIC, &now); - if (allow_tearing && frame_allow_tearing) { - wlr_scene_output_send_frame_done(m->scene_output, &now); - } else { - wlr_scene_output_send_frame_done(m->scene_output, &now); - } + wlr_scene_output_send_frame_done(m->scene_output, &now); // 如果需要更多帧,确保安排下一帧 if (need_more_frames && allow_frame_scheduling) { From 43d0f0f54a30dbd75027ef1cc9e361abdb71ce13 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Wed, 25 Feb 2026 17:35:19 +0800 Subject: [PATCH 550/591] opt: remove useless code --- src/mango.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/mango.c b/src/mango.c index 87423baa..3344ca7f 100644 --- a/src/mango.c +++ b/src/mango.c @@ -488,8 +488,6 @@ typedef struct { typedef struct { struct wlr_xdg_popup *wlr_popup; - Client *client; - LayerSurface *layer; uint32_t type; struct wl_listener destroy; struct wl_listener commit; @@ -2622,8 +2620,6 @@ static void commitpopup(struct wl_listener *listener, void *data) { goto commitpopup_listen_free; } - popup->client = c; - popup->layer = l; popup->type = type; popup->wlr_popup = wkr_popup; From 6667708d9aa069f72687ab3c015738ea2ddf6684 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Wed, 25 Feb 2026 19:16:06 +0800 Subject: [PATCH 551/591] feat: monitor arg support multi spec match in disptach --- src/dispatch/bind_define.h | 12 +++---- src/fetch/monitor.h | 69 ++++++++++++++++++++++++++++++++++++++ src/mango.c | 1 + 3 files changed, 76 insertions(+), 6 deletions(-) diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index 94d3d4ff..03d34cbb 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -210,7 +210,7 @@ int32_t focusmon(const Arg *arg) { if (!m->wlr_output->enabled) { continue; } - if (regex_match(arg->v, m->wlr_output->name)) { + if (match_monitor_spec(arg->v, m)) { tm = m; break; } @@ -1102,7 +1102,7 @@ int32_t tagmon(const Arg *arg) { if (!cm->wlr_output->enabled) { continue; } - if (regex_match(arg->v, cm->wlr_output->name)) { + if (match_monitor_spec(arg->v, cm)) { m = cm; break; } @@ -1543,7 +1543,7 @@ int32_t tagcrossmon(const Arg *arg) { if (!selmon || !selmon->sel) return 0; - if (regex_match(selmon->wlr_output->name, arg->v)) { + if (match_monitor_spec(arg->v, selmon)) { tag_client(arg, selmon->sel); return 0; } @@ -1701,7 +1701,7 @@ int32_t disable_monitor(const Arg *arg) { Monitor *m = NULL; struct wlr_output_state state = {0}; wl_list_for_each(m, &mons, link) { - if (regex_match(arg->v, m->wlr_output->name)) { + 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; @@ -1716,7 +1716,7 @@ int32_t enable_monitor(const Arg *arg) { Monitor *m = NULL; struct wlr_output_state state = {0}; wl_list_for_each(m, &mons, link) { - if (regex_match(arg->v, m->wlr_output->name)) { + 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; @@ -1731,7 +1731,7 @@ int32_t toggle_monitor(const Arg *arg) { Monitor *m = NULL; struct wlr_output_state state = {0}; wl_list_for_each(m, &mons, link) { - if (regex_match(arg->v, m->wlr_output->name)) { + 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; diff --git a/src/fetch/monitor.h b/src/fetch/monitor.h index fd18498e..d2b4fe62 100644 --- a/src/fetch/monitor.h +++ b/src/fetch/monitor.h @@ -104,4 +104,73 @@ Monitor *get_monitor_nearest_to(int32_t lx, int32_t ly) { return output_from_wlr_output( wlr_output_layout_output_at(output_layout, closest_x, closest_y)); +} + +bool match_monitor_spec(char *spec, Monitor *m) { + if (!spec || !m) + return false; + + // if the spec does not contain a colon, treat it as a match on the monitor + // name + if (strchr(spec, ':') == NULL) { + return regex_match(spec, m->wlr_output->name); + } + + char *spec_copy = strdup(spec); + if (!spec_copy) + return false; + + char *name_rule = NULL; + char *make_rule = NULL; + char *model_rule = NULL; + char *serial_rule = NULL; + + char *token = strtok(spec_copy, "&&"); + while (token) { + char *colon = strchr(token, ':'); + if (colon) { + *colon = '\0'; + char *key = token; + char *value = colon + 1; + + if (strcmp(key, "name") == 0) + name_rule = strdup(value); + else if (strcmp(key, "make") == 0) + make_rule = strdup(value); + else if (strcmp(key, "model") == 0) + model_rule = strdup(value); + else if (strcmp(key, "serial") == 0) + serial_rule = strdup(value); + } + token = strtok(NULL, "&&"); + } + + bool match = true; + + if (name_rule) { + if (!regex_match(name_rule, m->wlr_output->name)) + match = false; + } + if (make_rule) { + if (!m->wlr_output->make || strcmp(make_rule, m->wlr_output->make) != 0) + match = false; + } + if (model_rule) { + if (!m->wlr_output->model || + strcmp(model_rule, m->wlr_output->model) != 0) + match = false; + } + if (serial_rule) { + if (!m->wlr_output->serial || + strcmp(serial_rule, m->wlr_output->serial) != 0) + match = false; + } + + free(spec_copy); + free(name_rule); + free(make_rule); + free(model_rule); + free(serial_rule); + + return match; } \ No newline at end of file diff --git a/src/mango.c b/src/mango.c index 3344ca7f..d4cc1fba 100644 --- a/src/mango.c +++ b/src/mango.c @@ -799,6 +799,7 @@ static bool client_is_in_same_stack(Client *sc, Client *tc, Client *fc); static void monitor_stop_skip_frame_timer(Monitor *m); static int monitor_skip_frame_timeout_callback(void *data); static Monitor *get_monitor_nearest_to(int32_t lx, int32_t ly); +static bool match_monitor_spec(char *spec, Monitor *m); #include "data/static_keymap.h" #include "dispatch/bind_declare.h" From 1dac96b426654056d27c3decf999fdfb687f8282 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Wed, 25 Feb 2026 21:53:35 +0800 Subject: [PATCH 552/591] bump version to 0.12.4 --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 3f2e5e50..32b363be 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('mango', ['c', 'cpp'], - version : '0.12.3', + version : '0.12.4', ) subdir('protocols') From cbc344ab88cc0eef34e8657fbbd7004459a8b3ce Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Thu, 26 Feb 2026 08:29:27 +0800 Subject: [PATCH 553/591] fix: avoid opacity exceeds the threshold due to overshot animation curve --- src/mango.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/mango.c b/src/mango.c index d4cc1fba..4be08c58 100644 --- a/src/mango.c +++ b/src/mango.c @@ -4517,6 +4517,7 @@ void scene_buffer_apply_opacity(struct wlr_scene_buffer *buffer, int32_t sx, } void client_set_opacity(Client *c, double opacity) { + opacity = CLAMP_FLOAT(opacity, 0.0f, 1.0f); wlr_scene_node_for_each_buffer(&c->scene_surface->node, scene_buffer_apply_opacity, &opacity); } From 4787402b12d0092f5db5a6aa8d8a2108f0b5b62d Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Thu, 26 Feb 2026 08:54:15 +0800 Subject: [PATCH 554/591] opt: optimize monitorrule check --- src/config/parse_config.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/config/parse_config.h b/src/config/parse_config.h index 95e54c05..b4fb37e9 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -1844,6 +1844,13 @@ bool parse_option(Config *config, char *key, char *value) { token = strtok(NULL, ","); } + if (!rule->name && !rule->make && !rule->model && !rule->serial) { + fprintf(stderr, "\033[1m\033[31m[ERROR]:\033[33m Monitor rule " + "must have at least one of the following " + "options: name, make, model, serial\n"); + return false; + } + config->monitor_rules_count++; return !parse_error; } else if (strcmp(key, "tagrule") == 0) { From b33839198412d19621c206e5b8a6ad8584224489 Mon Sep 17 00:00:00 2001 From: Noor Latif Date: Thu, 26 Feb 2026 09:25:25 +0000 Subject: [PATCH 555/591] fix(nix): update deprecated xorg package names to top-level MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit xcbutilwm → libxcb-wm This eliminates the deprecation warnings: - "The xorg package set has been deprecated, 'xorg.xcbutilwm' has been renamed to 'libxcb-wm'" Changes: - nix/default.nix:14: xcbutilwm, → libxcb-wm, - nix/default.nix:60: xcbutilwm → libxcb-wm --- nix/default.nix | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nix/default.nix b/nix/default.nix index 6085565e..87d4bfd0 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -11,7 +11,7 @@ wayland, wayland-protocols, wayland-scanner, - xcbutilwm, + libxcb-wm, xwayland, meson, ninja, @@ -57,7 +57,7 @@ stdenv.mkDerivation { ] ++ lib.optionals enableXWayland [ libX11 - xcbutilwm + libxcb-wm xwayland ]; From 835269f86bf8d1f1e05b386a6a548e7c7cae1547 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Thu, 26 Feb 2026 23:22:51 +0800 Subject: [PATCH 556/591] opt: make spawn and spawn_shell log to debug log --- src/dispatch/bind_define.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index 03d34cbb..5cf41d6c 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -848,7 +848,7 @@ int32_t spawn_shell(const Arg *arg) { execlp("bash", "bash", "-c", arg->v, (char *)NULL); // if execlp fails, we should not reach here - wlr_log(WLR_ERROR, + wlr_log(WLR_DEBUG, "mango: failed to execute command '%s' with shell: %s\n", arg->v, strerror(errno)); _exit(EXIT_FAILURE); @@ -889,7 +889,7 @@ int32_t spawn(const Arg *arg) { execvp(argv[0], argv); // 4. execvp 失败时:打印错误并直接退出(避免 coredump) - wlr_log(WLR_ERROR, "mango: execvp '%s' failed: %s\n", argv[0], + wlr_log(WLR_DEBUG, "mango: execvp '%s' failed: %s\n", argv[0], strerror(errno)); _exit(EXIT_FAILURE); // 使用 _exit 避免缓冲区刷新等操作 } From 43965a1155b33c2174a8a829e6426d0088ef2a7a Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sun, 1 Mar 2026 11:21:24 +0800 Subject: [PATCH 557/591] update readme --- README.md | 46 +++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index 45da36cd..b3117018 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Mango Wayland Compositor
- MangoWC Logo + MangoWM Logo
This project's development is based on [dwl](https://codeberg.org/dwl/dwl/). @@ -36,7 +36,7 @@ https://github.com/user-attachments/assets/bb83004a-0563-4b48-ad89-6461a9b78b1f **Mango won't cater to every user preference**: For niche feature requests, I'll take a wait-and-see approach. I'll only consider adding them if they get a significant number of upvotes. # Our discord -[mangowc](https://discord.gg/CPjbDxesh5) +[mangowm](https://discord.gg/CPjbDxesh5) # Supported layouts - tile @@ -52,7 +52,7 @@ https://github.com/user-attachments/assets/bb83004a-0563-4b48-ad89-6461a9b78b1f # Installation -[![Packaging status](https://repology.org/badge/vertical-allrepos/mangowc.svg)](https://repology.org/project/mangowc/versions) +[![Packaging status](https://repology.org/badge/vertical-allrepos/mangowm.svg)](https://repology.org/project/mangowm/versions) ## Dependencies @@ -71,9 +71,9 @@ https://github.com/user-attachments/assets/bb83004a-0563-4b48-ad89-6461a9b78b1f - libxcb ## Arch Linux -The package is in the Arch User Repository and is available for manual download [here](https://aur.archlinux.org/packages/mangowc-git) or through a AUR helper like yay: +The package is in the Arch User Repository and is available for manual download [here](https://aur.archlinux.org/packages/mangowm-git) or through a AUR helper like yay: ```bash -yay -S mangowc-git +yay -S mangowm-git ``` @@ -87,12 +87,12 @@ eselect repository enable guru emerge --sync guru ``` -Then, add `gui-libs/scenefx` and `gui-wm/mangowc` to the `package.accept_keywords`. +Then, add `gui-libs/scenefx` and `gui-wm/mangowm` to the `package.accept_keywords`. Finally, install the package: ```bash -emerge --ask --verbose gui-wm/mangowc +emerge --ask --verbose gui-wm/mangowm ``` ## Fedora Linux @@ -102,32 +102,32 @@ First, add the [Terra Repository](https://terra.fyralabs.com/). Then, install the package: ```bash -dnf install mangowc +dnf install mangowm ``` ## Guix System The package definition is described in the source repository. -First, add `mangowc` channel to `channels.scm` file: +First, add `mangowm` channel to `channels.scm` file: ```scheme ;; In $HOME/.config/guix/channels.scm (cons (channel - (name 'mangowc) - (url "https://github.com/DreamMaoMao/mangowc.git") + (name 'mangowm) + (url "https://github.com/mangowm/mango.git") (branch "main")) ... ;; Your other channels %default-channels) ``` Then, run `guix pull` and after update you can either run -`guix install mangowc` or add it to your configuration via: +`guix install mangowm` or add it to your configuration via: ```scheme -(use-modules (mangowc)) ;; Add mangowc module +(use-modules (mangowm)) ;; Add mangowm module -;; Add mangowc to packages list +;; Add mangowm to packages list (packages (cons* - mangowc-git + mangowm-git ... ;; Other packages you specified %base-packages)) ``` @@ -147,8 +147,8 @@ cd scenefx meson build -Dprefix=/usr sudo ninja -C build install -git clone https://github.com/DreamMaoMao/mangowc.git -cd mangowc +git clone https://github.com/mangowm/mango.git +cd mangowm meson build -Dprefix=/usr sudo ninja -C build install ``` @@ -206,9 +206,9 @@ git clone https://github.com/DreamMaoMao/mango-config.git ~/.config/mango ## Config Documentation -Refer to the repo wiki [wiki](https://github.com/DreamMaoMao/mango/wiki/) +Refer to the repo wiki [wiki](https://github.com/mangowm/mango/wiki/) -or the website docs [docs](https://mangowc.vercel.app/docs) +or the website docs [docs](https://mangowm.vercel.app/docs) # NixOS + Home-manager @@ -228,7 +228,7 @@ Here's an example of using the modules in a flake: }; flake-parts.url = "github:hercules-ci/flake-parts"; mango = { - url = "github:DreamMaoMao/mango"; + url = "github:mangowm/mango"; inputs.nixpkgs.follows = "nixpkgs"; }; }; @@ -290,9 +290,9 @@ Here's an example of using the modules in a flake: To package mango for other distributions, you can check the reference setup for: -- [nix](https://github.com/DreamMaoMao/mangowc/blob/main/nix/default.nix) -- [arch](https://aur.archlinux.org/cgit/aur.git/tree/PKGBUILD?h=mangowc-git). -- [gentoo](https://data.gpo.zugaina.org/guru/gui-wm/mangowc) +- [nix](https://github.com/mangowm/mango/blob/main/nix/default.nix) +- [arch](https://aur.archlinux.org/cgit/aur.git/tree/PKGBUILD?h=mangowm-git). +- [gentoo](https://data.gpo.zugaina.org/guru/gui-wm/mangowm) You might need to package `scenefx` for your distribution, check availability [here](https://github.com/wlrfx/scenefx.git). From e935af07c167933e312fcb8c2cfb970991bb4629 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sun, 1 Mar 2026 11:35:51 +0800 Subject: [PATCH 558/591] project: rename guix file --- mangowc.scm => mangowm.scm | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename mangowc.scm => mangowm.scm (100%) diff --git a/mangowc.scm b/mangowm.scm similarity index 100% rename from mangowc.scm rename to mangowm.scm From 811610e481714df988b6602d7b20fedb4c68ac4c Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sun, 1 Mar 2026 11:38:17 +0800 Subject: [PATCH 559/591] rename mangowc to mangowm --- mangowm.scm | 12 ++++++------ mmsg/mmsg.c | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/mangowm.scm b/mangowm.scm index 9c55d43e..33d95045 100644 --- a/mangowm.scm +++ b/mangowm.scm @@ -1,4 +1,4 @@ -(define-module (mangowc) +(define-module (mangowm) #:use-module (guix download) #:use-module (guix git-download) #:use-module (guix gexp) @@ -18,11 +18,11 @@ #:use-module (guix licenses)) -(define-public mangowc-git +(define-public mangowm-git (package - (name "mangowc") + (name "mangowm") (version "git") - (source (local-file "." "mangowc-checkout" + (source (local-file "." "mangowm-checkout" #:recursive? #t #:select? (or (git-predicate (current-source-directory)) (const #t)))) @@ -55,10 +55,10 @@ wlroots scenefx)) (native-inputs (list pkg-config wayland-protocols)) - (home-page "https://github.com/DreamMaoMao/mangowc") + (home-page "https://github.com/DreamMaoMao/mangowm") (synopsis "Wayland compositor based on wlroots and scenefx") (description "A Wayland compositor based on wlroots and scenefx, inspired by dwl but aiming to be more feature-rich.") (license gpl3))) -mangowc-git +mangowm-git diff --git a/mmsg/mmsg.c b/mmsg/mmsg.c index fb1d04fd..4e0e1d8c 100644 --- a/mmsg/mmsg.c +++ b/mmsg/mmsg.c @@ -500,7 +500,7 @@ static const struct wl_registry_listener registry_listener = { static void usage(void) { fprintf(stderr, - "mmsg - MangoWC IPC\n" + "mmsg - MangoWM IPC\n" "\n" "SYNOPSIS:\n" "\tmmsg [-OTLq]\n" @@ -517,7 +517,7 @@ static void usage(void) { "\t-O Get all output (monitor) information\n" "\t-T Get number of tags\n" "\t-L Get all available layouts\n" - "\t-q Quit MangoWC\n" + "\t-q Quit mango\n" "\t-o Select output (monitor)\n" "\n" "GET OPTIONS (used with -g or -w):\n" From 755ffe06af4d8e93f8863c404024bc96ad0c636a Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sun, 1 Mar 2026 11:42:44 +0800 Subject: [PATCH 560/591] update website in readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b3117018..d5171acc 100644 --- a/README.md +++ b/README.md @@ -208,7 +208,7 @@ git clone https://github.com/DreamMaoMao/mango-config.git ~/.config/mango Refer to the repo wiki [wiki](https://github.com/mangowm/mango/wiki/) -or the website docs [docs](https://mangowm.vercel.app/docs) +or the website docs [docs](https://mangowm.github.io/mango-web/) # NixOS + Home-manager From 243848f43e96e0e6c79210e014219b25c6d35e86 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sun, 1 Mar 2026 12:02:57 +0800 Subject: [PATCH 561/591] bump version to 0.12.5 --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 32b363be..85fe15b6 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('mango', ['c', 'cpp'], - version : '0.12.4', + version : '0.12.5', ) subdir('protocols') From 008cb9726e36c1062f059a0505e4d6671ea425db Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sun, 1 Mar 2026 18:04:21 +0800 Subject: [PATCH 562/591] Revert "Add nix option to enable/disable adding to session manager" --- nix/nixos-modules.nix | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/nix/nixos-modules.nix b/nix/nixos-modules.nix index 7a9f930a..33811022 100644 --- a/nix/nixos-modules.nix +++ b/nix/nixos-modules.nix @@ -9,10 +9,6 @@ in { options = { programs.mango = { enable = lib.mkEnableOption "mango, a wayland compositor based on dwl"; - addLoginEntry = lib.mkEnableOption { - default = true; - description = "Whether to add a login entry to the display manager for mango"; - }; package = lib.mkOption { type = lib.types.package; default = self.packages.${pkgs.stdenv.hostPlatform.system}.mango; @@ -59,7 +55,7 @@ in { programs.xwayland.enable = lib.mkDefault true; services = { - displayManager.sessionPackages = lib.mkIf cfg.addLoginEntry [ cfg.package ]; + displayManager.sessionPackages = [cfg.package]; graphical-desktop.enable = lib.mkDefault true; }; From 9922ed26c7fb1a3456077535c01acec0390bc962 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sun, 1 Mar 2026 18:13:40 +0800 Subject: [PATCH 563/591] update readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d5171acc..b927b920 100644 --- a/README.md +++ b/README.md @@ -208,7 +208,7 @@ git clone https://github.com/DreamMaoMao/mango-config.git ~/.config/mango Refer to the repo wiki [wiki](https://github.com/mangowm/mango/wiki/) -or the website docs [docs](https://mangowm.github.io/mango-web/) +or the website docs [docs](https://mangowm.github.io/) # NixOS + Home-manager From 6cc7d162817941799c5db4af2295f54a5353f778 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Mon, 2 Mar 2026 00:42:07 +0800 Subject: [PATCH 564/591] opt: only set on_demand layer focus when it request in init_commit --- src/mango.c | 37 ++++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/src/mango.c b/src/mango.c index 0864a982..81792b20 100644 --- a/src/mango.c +++ b/src/mango.c @@ -1693,6 +1693,7 @@ void focuslayer(LayerSurface *l) { void reset_exclusive_layer(Monitor *m) { LayerSurface *l = NULL; int32_t i; + bool neet_change_focus_to_client = false; uint32_t layers_above_shell[] = { ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY, ZWLR_LAYER_SHELL_V1_LAYER_TOP, @@ -1706,13 +1707,19 @@ void reset_exclusive_layer(Monitor *m) { wl_list_for_each_reverse(l, &m->layers[layers_above_shell[i]], link) { if (l == exclusive_focus && l->layer_surface->current.keyboard_interactive != - ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE) + ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE) { + exclusive_focus = NULL; + + neet_change_focus_to_client = true; + } + if (l->layer_surface->current.keyboard_interactive == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE && l->layer_surface->surface == - seat->keyboard_state.focused_surface) - focusclient(focustop(selmon), 1); + seat->keyboard_state.focused_surface) { + neet_change_focus_to_client = true; + } if (locked || l->layer_surface->current.keyboard_interactive != @@ -1725,6 +1732,10 @@ void reset_exclusive_layer(Monitor *m) { return; } } + + if (neet_change_focus_to_client) { + focusclient(focustop(selmon), 1); + } } void arrangelayers(Monitor *m) { @@ -2384,13 +2395,6 @@ void maplayersurfacenotify(struct wl_listener *listener, void *data) { } // 刷新布局,让窗口能感应到exclude_zone变化以及设置独占表面 arrangelayers(l->mon); - - // 按需交互layer需要像正常窗口一样抢占非独占layer的焦点 - if (!exclusive_focus && - l->layer_surface->current.keyboard_interactive == - ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_ON_DEMAND) { - focuslayer(l); - } } void commitlayersurfacenotify(struct wl_listener *listener, void *data) { @@ -2411,6 +2415,12 @@ void commitlayersurfacenotify(struct wl_listener *listener, void *data) { arrangelayers(l->mon); l->layer_surface->current = old_state; + // 按需交互layer只在map之前设置焦点 + if (!exclusive_focus && + l->layer_surface->current.keyboard_interactive == + ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_ON_DEMAND) { + focuslayer(l); + } return; } @@ -2455,11 +2465,6 @@ void commitlayersurfacenotify(struct wl_listener *listener, void *data) { layer_flush_blur_background(l); - if (layer_surface == exclusive_focus && - layer_surface->current.keyboard_interactive != - ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE) - exclusive_focus = NULL; - if (layer_surface->current.committed == 0 && l->mapped == layer_surface->surface->mapped) return; @@ -3335,7 +3340,6 @@ void destroylocksurface(struct wl_listener *listener, void *data) { if (lock_surface->surface != seat->keyboard_state.focused_surface) { if (exclusive_focus && !locked) { - exclusive_focus = NULL; reset_exclusive_layer(m); } return; @@ -3345,7 +3349,6 @@ void destroylocksurface(struct wl_listener *listener, void *data) { surface = wl_container_of(cur_lock->surfaces.next, surface, link); client_notify_enter(surface->surface, wlr_seat_get_keyboard(seat)); } else if (!locked) { - exclusive_focus = NULL; reset_exclusive_layer(selmon); focusclient(focustop(selmon), 1); } else { From c403a47894a1fa856ea1a913b30d350185a0b34b Mon Sep 17 00:00:00 2001 From: Han Boetes Date: Sun, 1 Mar 2026 21:58:03 +0100 Subject: [PATCH 565/591] Fix use-after-free crash in cursor surface handling ### Problem `setcursor()` stores the client-provided `wlr_surface` pointer in `last_cursor.surface`, but never registers a destroy listener on it. When the client exits (e.g. closing a launcher like fuzzel), the surface is destroyed, but `last_cursor.surface` still holds the stale pointer. If the cursor hide timeout fires while the cursor surface is alive, and the client then exits, the next mouse movement calls `handlecursoractivity()`, which passes the dangling pointer to `wlr_cursor_set_surface()`. This causes a SIGSEGV in `wl_list_insert()` inside libwayland-server, as the `wl_list` embedded in the destroyed surface struct has been freed. A secondary issue exists in `setcursorshape()`: when a client switches from a custom cursor surface to a shape cursor, `last_cursor.surface` is set to NULL but the destroy listener (if registered) is not removed, leaving a dangling listener on the destroyed surface. The crash only manifests when `cursor_hidden` is true at the moment of the mouse movement, which is why it is intermittent and difficult to reproduce. ### Root cause Confirmed via `coredumpctl debug` and `bt full`: ``` #0 wl_list_insert (libwayland-server.so) #1 wlr_cursor_set_surface (libwlroots) #2 handlecursoractivity (mango.c) #3 motionnotify (mango.c) #4 motionrelative (mango.c) #5 wl_signal_emit_mutable #6 handle_libinput_readable ``` ### Fix - Add a `wl_listener` (`last_cursor_surface_destroy_listener`) that clears `last_cursor.surface` and removes itself when the surface is destroyed. - Initialize the listener's link in `setup()` so `wl_list_empty()` checks are reliable from the start. - In `setcursor()`, remove any existing listener before registering a new one on the incoming surface. - In `setcursorshape()`, remove the destroy listener when switching to a shape cursor. - Add a NULL guard in `handlecursoractivity()` as a safety net. --- src/mango.c | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/src/mango.c b/src/mango.c index 0864a982..cb710d2e 100644 --- a/src/mango.c +++ b/src/mango.c @@ -914,6 +914,15 @@ static struct { int32_t hotspot_y; } last_cursor; +static void last_cursor_surface_destroy(struct wl_listener *listener, void *data) { + last_cursor.surface = NULL; + wl_list_remove(&listener->link); + wl_list_init(&listener->link); +} +static struct wl_listener last_cursor_surface_destroy_listener = { + .notify = last_cursor_surface_destroy +}; + #include "client/client.h" #include "config/preset.h" @@ -2141,6 +2150,11 @@ void setcursorshape(struct wl_listener *listener, void *data) { * actually has pointer focus first. If so, we can tell the cursor to * use the provided cursor shape. */ if (event->seat_client == seat->pointer_state.focused_client) { + /* Remove surface destroy listener if active */ + if (!wl_list_empty(&last_cursor_surface_destroy_listener.link)) + wl_list_remove(&last_cursor_surface_destroy_listener.link); + wl_list_init(&last_cursor_surface_destroy_listener.link); + last_cursor.shape = event->shape; last_cursor.surface = NULL; if (!cursor_hidden) @@ -4918,10 +4932,21 @@ void setcursor(struct wl_listener *listener, void *data) { * hardware cursor on the output that it's currently on and continue to * do so as the cursor moves between outputs. */ if (event->seat_client == seat->pointer_state.focused_client) { + /* Clear previous surface destroy listener if any */ + if (!wl_list_empty(&last_cursor_surface_destroy_listener.link)) + wl_list_remove(&last_cursor_surface_destroy_listener.link); + wl_list_init(&last_cursor_surface_destroy_listener.link); + last_cursor.shape = 0; last_cursor.surface = event->surface; last_cursor.hotspot_x = event->hotspot_x; last_cursor.hotspot_y = event->hotspot_y; + + /* Track surface destruction to avoid dangling pointer */ + if (event->surface) + wl_signal_add(&event->surface->events.destroy, + &last_cursor_surface_destroy_listener); + if (!cursor_hidden) wlr_cursor_set_surface(cursor, event->surface, event->hotspot_x, event->hotspot_y); @@ -5384,6 +5409,8 @@ void handle_print_status(struct wl_listener *listener, void *data) { void setup(void) { + wl_list_init(&last_cursor_surface_destroy_listener.link); + setenv("XCURSOR_SIZE", "24", 1); setenv("XDG_CURRENT_DESKTOP", "mango", 1); @@ -5818,7 +5845,7 @@ void handlecursoractivity(void) { if (last_cursor.shape) wlr_cursor_set_xcursor(cursor, cursor_mgr, wlr_cursor_shape_v1_name(last_cursor.shape)); - else + else if (last_cursor.surface) wlr_cursor_set_surface(cursor, last_cursor.surface, last_cursor.hotspot_x, last_cursor.hotspot_y); } From 263b1845bb1d3ecfc3b40fb463a65e36134056dc Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Mon, 2 Mar 2026 08:15:52 +0800 Subject: [PATCH 566/591] opt: optimize layer focus change logic --- src/mango.c | 37 +++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/src/mango.c b/src/mango.c index 81792b20..641e69ab 100644 --- a/src/mango.c +++ b/src/mango.c @@ -1690,7 +1690,7 @@ void focuslayer(LayerSurface *l) { client_notify_enter(l->layer_surface->surface, wlr_seat_get_keyboard(seat)); } -void reset_exclusive_layer(Monitor *m) { +void reset_exclusive_layers_focus(Monitor *m) { LayerSurface *l = NULL; int32_t i; bool neet_change_focus_to_client = false; @@ -1704,7 +1704,7 @@ void reset_exclusive_layer(Monitor *m) { return; for (i = 0; i < (int32_t)LENGTH(layers_above_shell); i++) { - wl_list_for_each_reverse(l, &m->layers[layers_above_shell[i]], link) { + wl_list_for_each(l, &m->layers[layers_above_shell[i]], link) { if (l == exclusive_focus && l->layer_surface->current.keyboard_interactive != ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE) { @@ -1714,6 +1714,12 @@ void reset_exclusive_layer(Monitor *m) { neet_change_focus_to_client = true; } + if (l->layer_surface->surface == + seat->keyboard_state.focused_surface && + l->being_unmapped) { + neet_change_focus_to_client = true; + } + if (l->layer_surface->current.keyboard_interactive == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE && l->layer_surface->surface == @@ -1724,11 +1730,14 @@ void reset_exclusive_layer(Monitor *m) { if (locked || l->layer_surface->current.keyboard_interactive != ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE || - !l->mapped || l == exclusive_focus) + l->being_unmapped) continue; /* Deactivate the focused client. */ exclusive_focus = l; - focuslayer(l); + neet_change_focus_to_client = false; + if (l->layer_surface->surface != + seat->keyboard_state.focused_surface) + focuslayer(l); return; } } @@ -1757,9 +1766,6 @@ void arrangelayers(Monitor *m) { /* Arrange non-exlusive surfaces from top->bottom */ for (i = 3; i >= 0; i--) arrangelayer(m, &m->layers[i], &usable_area, 0); - - /* Find topmost keyboard interactive layer, if such a layer exists */ - reset_exclusive_layer(m); } void // 鼠标滚轮事件 @@ -2395,6 +2401,7 @@ void maplayersurfacenotify(struct wl_listener *listener, void *data) { } // 刷新布局,让窗口能感应到exclude_zone变化以及设置独占表面 arrangelayers(l->mon); + reset_exclusive_layers_focus(l->mon); } void commitlayersurfacenotify(struct wl_listener *listener, void *data) { @@ -2414,7 +2421,6 @@ void commitlayersurfacenotify(struct wl_listener *listener, void *data) { l->layer_surface->current = l->layer_surface->pending; arrangelayers(l->mon); l->layer_surface->current = old_state; - // 按需交互layer只在map之前设置焦点 if (!exclusive_focus && l->layer_surface->current.keyboard_interactive == @@ -2482,6 +2488,7 @@ void commitlayersurfacenotify(struct wl_listener *listener, void *data) { } arrangelayers(l->mon); + reset_exclusive_layers_focus(l->mon); } void commitnotify(struct wl_listener *listener, void *data) { @@ -3340,7 +3347,7 @@ void destroylocksurface(struct wl_listener *listener, void *data) { if (lock_surface->surface != seat->keyboard_state.focused_surface) { if (exclusive_focus && !locked) { - reset_exclusive_layer(m); + reset_exclusive_layers_focus(m); } return; } @@ -3349,8 +3356,7 @@ void destroylocksurface(struct wl_listener *listener, void *data) { surface = wl_container_of(cur_lock->surfaces.next, surface, link); client_notify_enter(surface->surface, wlr_seat_get_keyboard(seat)); } else if (!locked) { - reset_exclusive_layer(selmon); - focusclient(focustop(selmon), 1); + reset_exclusive_layers_focus(selmon); } else { wlr_seat_keyboard_clear_focus(seat); } @@ -5846,17 +5852,20 @@ void unmaplayersurfacenotify(struct wl_listener *listener, void *data) { init_fadeout_layers(l); wlr_scene_node_set_enabled(&l->scene->node, false); + if (l == exclusive_focus) exclusive_focus = NULL; + if (l->layer_surface->output && (l->mon = l->layer_surface->output->data)) arrangelayers(l->mon); - if (l->layer_surface->surface == seat->keyboard_state.focused_surface) - focusclient(focustop(selmon), 1); + + reset_exclusive_layers_focus(l->mon); + motionnotify(0, NULL, 0, 0, 0, 0); - l->being_unmapped = false; layer_flush_blur_background(l); wlr_scene_node_destroy(&l->shadow->node); l->shadow = NULL; + l->being_unmapped = false; } void unmapnotify(struct wl_listener *listener, void *data) { From 20dbffdfafbdc7c4aa5fa464b3422709076667a6 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Mon, 2 Mar 2026 08:35:32 +0800 Subject: [PATCH 567/591] opt: avoid unnecessary action when layer surface commit --- src/mango.c | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/src/mango.c b/src/mango.c index 641e69ab..2faf35da 100644 --- a/src/mango.c +++ b/src/mango.c @@ -2476,19 +2476,26 @@ void commitlayersurfacenotify(struct wl_listener *listener, void *data) { return; l->mapped = layer_surface->surface->mapped; - if (scene_layer != l->scene->node.parent) { - wlr_scene_node_reparent(&l->scene->node, scene_layer); - wl_list_remove(&l->link); - wl_list_insert(&l->mon->layers[layer_surface->current.layer], &l->link); - wlr_scene_node_reparent( - &l->popups->node, - (layer_surface->current.layer < ZWLR_LAYER_SHELL_V1_LAYER_TOP - ? layers[LyrTop] - : scene_layer)); + if (layer_surface->current.committed & WLR_LAYER_SURFACE_V1_STATE_LAYER) { + if (scene_layer != l->scene->node.parent) { + wlr_scene_node_reparent(&l->scene->node, scene_layer); + wl_list_remove(&l->link); + wl_list_insert(&l->mon->layers[layer_surface->current.layer], + &l->link); + wlr_scene_node_reparent( + &l->popups->node, + (layer_surface->current.layer < ZWLR_LAYER_SHELL_V1_LAYER_TOP + ? layers[LyrTop] + : scene_layer)); + } + + arrangelayers(l->mon); } - arrangelayers(l->mon); - reset_exclusive_layers_focus(l->mon); + if (layer_surface->current.committed & + WLR_LAYER_SURFACE_V1_STATE_KEYBOARD_INTERACTIVITY) { + reset_exclusive_layers_focus(l->mon); + } } void commitnotify(struct wl_listener *listener, void *data) { From ad754167b7d810dd63bbfd460e80bbd30e531778 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Mon, 2 Mar 2026 09:40:50 +0800 Subject: [PATCH 568/591] fix: last_cursor surface destroy detect error --- src/mango.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/mango.c b/src/mango.c index af82733d..7c6106f9 100644 --- a/src/mango.c +++ b/src/mango.c @@ -800,6 +800,8 @@ static void monitor_stop_skip_frame_timer(Monitor *m); static int monitor_skip_frame_timeout_callback(void *data); static Monitor *get_monitor_nearest_to(int32_t lx, int32_t ly); static bool match_monitor_spec(char *spec, Monitor *m); +static void last_cursor_surface_destroy(struct wl_listener *listener, + void *data); #include "data/static_keymap.h" #include "dispatch/bind_declare.h" @@ -914,15 +916,6 @@ static struct { int32_t hotspot_y; } last_cursor; -static void last_cursor_surface_destroy(struct wl_listener *listener, void *data) { - last_cursor.surface = NULL; - wl_list_remove(&listener->link); - wl_list_init(&listener->link); -} -static struct wl_listener last_cursor_surface_destroy_listener = { - .notify = last_cursor_surface_destroy -}; - #include "client/client.h" #include "config/preset.h" @@ -973,6 +966,8 @@ static struct wl_listener new_session_lock = {.notify = locksession}; static struct wl_listener drm_lease_request = {.notify = requestdrmlease}; static struct wl_listener keyboard_shortcuts_inhibit_new_inhibitor = { .notify = handle_keyboard_shortcuts_inhibit_new_inhibitor}; +static struct wl_listener last_cursor_surface_destroy_listener = { + .notify = last_cursor_surface_destroy}; #ifdef XWAYLAND static void fix_xwayland_unmanaged_coordinate(Client *c); @@ -2159,6 +2154,11 @@ void checkidleinhibitor(struct wlr_surface *exclude) { wlr_idle_notifier_v1_set_inhibited(idle_notifier, inhibited); } +void last_cursor_surface_destroy(struct wl_listener *listener, void *data) { + last_cursor.surface = NULL; + wl_list_remove(&listener->link); +} + void setcursorshape(struct wl_listener *listener, void *data) { struct wlr_cursor_shape_manager_v1_request_set_shape_event *event = data; if (cursor_mode != CurNormal && cursor_mode != CurPressed) @@ -2168,9 +2168,9 @@ void setcursorshape(struct wl_listener *listener, void *data) { * use the provided cursor shape. */ if (event->seat_client == seat->pointer_state.focused_client) { /* Remove surface destroy listener if active */ - if (!wl_list_empty(&last_cursor_surface_destroy_listener.link)) + if (last_cursor.surface && + last_cursor_surface_destroy_listener.link.prev != NULL) wl_list_remove(&last_cursor_surface_destroy_listener.link); - wl_list_init(&last_cursor_surface_destroy_listener.link); last_cursor.shape = event->shape; last_cursor.surface = NULL; @@ -4949,9 +4949,9 @@ void setcursor(struct wl_listener *listener, void *data) { * do so as the cursor moves between outputs. */ if (event->seat_client == seat->pointer_state.focused_client) { /* Clear previous surface destroy listener if any */ - if (!wl_list_empty(&last_cursor_surface_destroy_listener.link)) + if (last_cursor.surface && + last_cursor_surface_destroy_listener.link.prev != NULL) wl_list_remove(&last_cursor_surface_destroy_listener.link); - wl_list_init(&last_cursor_surface_destroy_listener.link); last_cursor.shape = 0; last_cursor.surface = event->surface; @@ -5425,8 +5425,6 @@ void handle_print_status(struct wl_listener *listener, void *data) { void setup(void) { - wl_list_init(&last_cursor_surface_destroy_listener.link); - setenv("XCURSOR_SIZE", "24", 1); setenv("XDG_CURRENT_DESKTOP", "mango", 1); @@ -5662,6 +5660,8 @@ void setup(void) { LISTEN_STATIC(&cursor->events.hold_end, hold_end); seat = wlr_seat_create(dpy, "seat0"); + + wl_list_init(&last_cursor_surface_destroy_listener.link); wl_signal_add(&seat->events.request_set_cursor, &request_cursor); wl_signal_add(&seat->events.request_set_selection, &request_set_sel); wl_signal_add(&seat->events.request_set_primary_selection, From 46e867deb9dfd58abb22ec92b19461d3761b1f3d Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Mon, 2 Mar 2026 20:53:52 +0800 Subject: [PATCH 569/591] opt: always arrangelayers if layer commit --- src/mango.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mango.c b/src/mango.c index 7c6106f9..3bfdfb77 100644 --- a/src/mango.c +++ b/src/mango.c @@ -2502,10 +2502,10 @@ void commitlayersurfacenotify(struct wl_listener *listener, void *data) { ? layers[LyrTop] : scene_layer)); } - - arrangelayers(l->mon); } + arrangelayers(l->mon); + if (layer_surface->current.committed & WLR_LAYER_SURFACE_V1_STATE_KEYBOARD_INTERACTIVITY) { reset_exclusive_layers_focus(l->mon); From 9aa2d3cd33ce233c3986263e52163112a0c0caec Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Tue, 3 Mar 2026 13:03:35 +0800 Subject: [PATCH 570/591] opt: rename hide_source var to hide_cursor_source --- src/config/parse_config.h | 12 ++++++------ src/mango.c | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/config/parse_config.h b/src/config/parse_config.h index b4fb37e9..d2946f60 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -3637,10 +3637,10 @@ void reapply_monitor_rules(void) { } void reapply_cursor_style(void) { - if (hide_source) { - wl_event_source_timer_update(hide_source, 0); - wl_event_source_remove(hide_source); - hide_source = NULL; + if (hide_cursor_source) { + wl_event_source_timer_update(hide_cursor_source, 0); + wl_event_source_remove(hide_cursor_source); + hide_cursor_source = NULL; } wlr_cursor_unset_image(cursor); @@ -3671,12 +3671,12 @@ void reapply_cursor_style(void) { wlr_cursor_set_xcursor(cursor, cursor_mgr, "left_ptr"); - hide_source = wl_event_loop_add_timer(wl_display_get_event_loop(dpy), + hide_cursor_source = wl_event_loop_add_timer(wl_display_get_event_loop(dpy), hidecursor, cursor); if (cursor_hidden) { wlr_cursor_unset_image(cursor); } else { - wl_event_source_timer_update(hide_source, cursor_hide_timeout * 1000); + wl_event_source_timer_update(hide_cursor_source, cursor_hide_timeout * 1000); } } diff --git a/src/mango.c b/src/mango.c index 3bfdfb77..d7245ded 100644 --- a/src/mango.c +++ b/src/mango.c @@ -898,7 +898,7 @@ struct dvec2 *baked_points_focus; struct dvec2 *baked_points_opafadein; struct dvec2 *baked_points_opafadeout; -static struct wl_event_source *hide_source; +static struct wl_event_source *hide_cursor_source; static bool cursor_hidden = false; static bool tag_combo = false; static const char *cli_config_path = NULL; @@ -5631,7 +5631,7 @@ void setup(void) { cursor_shape_mgr = wlr_cursor_shape_manager_v1_create(dpy, 1); wl_signal_add(&cursor_shape_mgr->events.request_set_shape, &request_set_cursor_shape); - hide_source = wl_event_loop_add_timer(wl_display_get_event_loop(dpy), + hide_cursor_source = wl_event_loop_add_timer(wl_display_get_event_loop(dpy), hidecursor, cursor); /* * Configures a seat, which is a single "seat" at which a user sits and @@ -5851,7 +5851,7 @@ void overview_restore(Client *c, const Arg *arg) { } void handlecursoractivity(void) { - wl_event_source_timer_update(hide_source, cursor_hide_timeout * 1000); + wl_event_source_timer_update(hide_cursor_source, cursor_hide_timeout * 1000); if (!cursor_hidden) return; From 1e1d41e626aa12057c03ec79ed11bcc5619f6748 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Tue, 3 Mar 2026 13:23:15 +0800 Subject: [PATCH 571/591] feat: add windowrule option indleinhibit_when_focus --- src/config/parse_config.h | 9 ++++++-- src/mango.c | 47 ++++++++++++++++++++++++++++++++++++--- 2 files changed, 51 insertions(+), 5 deletions(-) diff --git a/src/config/parse_config.h b/src/config/parse_config.h index d2946f60..8a965360 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -78,6 +78,7 @@ typedef struct { int32_t ignore_maximize; int32_t ignore_minimize; int32_t isnosizehint; + int32_t indleinhibit_when_focus; const char *monitor; int32_t offsetx; int32_t offsety; @@ -2022,6 +2023,7 @@ bool parse_option(Config *config, char *key, char *value) { rule->ignore_maximize = -1; rule->ignore_minimize = -1; rule->isnosizehint = -1; + rule->indleinhibit_when_focus = -1; rule->isterm = -1; rule->allow_csd = -1; rule->force_maximize = -1; @@ -2132,6 +2134,8 @@ bool parse_option(Config *config, char *key, char *value) { rule->ignore_minimize = atoi(val); } else if (strcmp(key, "isnosizehint") == 0) { rule->isnosizehint = atoi(val); + } else if (strcmp(key, "indleinhibit_when_focus") == 0) { + rule->indleinhibit_when_focus = atoi(val); } else if (strcmp(key, "isterm") == 0) { rule->isterm = atoi(val); } else if (strcmp(key, "allow_csd") == 0) { @@ -3672,11 +3676,12 @@ void reapply_cursor_style(void) { wlr_cursor_set_xcursor(cursor, cursor_mgr, "left_ptr"); hide_cursor_source = wl_event_loop_add_timer(wl_display_get_event_loop(dpy), - hidecursor, cursor); + hidecursor, cursor); if (cursor_hidden) { wlr_cursor_unset_image(cursor); } else { - wl_event_source_timer_update(hide_cursor_source, cursor_hide_timeout * 1000); + wl_event_source_timer_update(hide_cursor_source, + cursor_hide_timeout * 1000); } } diff --git a/src/mango.c b/src/mango.c index d7245ded..8a93a792 100644 --- a/src/mango.c +++ b/src/mango.c @@ -347,7 +347,7 @@ struct Client { struct wlr_foreign_toplevel_handle_v1 *foreign_toplevel; int32_t isfloating, isurgent, isfullscreen, isfakefullscreen, need_float_size_reduce, isminimized, isoverlay, isnosizehint, - ignore_maximize, ignore_minimize; + ignore_maximize, ignore_minimize, indleinhibit_when_focus; int32_t ismaximizescreen; int32_t overview_backup_bw; int32_t fullscreen_backup_x, fullscreen_backup_y, fullscreen_backup_w, @@ -802,6 +802,8 @@ static Monitor *get_monitor_nearest_to(int32_t lx, int32_t ly); static bool match_monitor_spec(char *spec, Monitor *m); static void last_cursor_surface_destroy(struct wl_listener *listener, void *data); +static int32_t keep_idle_inhibit(void *data); +static void check_keep_idle_inhibit(Client *c); #include "data/static_keymap.h" #include "dispatch/bind_declare.h" @@ -899,6 +901,7 @@ struct dvec2 *baked_points_opafadein; struct dvec2 *baked_points_opafadeout; static struct wl_event_source *hide_cursor_source; +static struct wl_event_source *keep_idle_inhibit_source; static bool cursor_hidden = false; static bool tag_combo = false; static const char *cli_config_path = NULL; @@ -1335,6 +1338,7 @@ static void apply_rule_properties(Client *c, const ConfigWinRule *r) { APPLY_INT_PROP(c, r, ignore_maximize); APPLY_INT_PROP(c, r, ignore_minimize); APPLY_INT_PROP(c, r, isnosizehint); + APPLY_INT_PROP(c, r, indleinhibit_when_focus); APPLY_INT_PROP(c, r, isunglobal); APPLY_INT_PROP(c, r, noblur); APPLY_INT_PROP(c, r, allow_shortcuts_inhibit); @@ -3482,6 +3486,8 @@ void focusclient(Client *c, int32_t lift) { selmon->sel = c; c->isfocusing = true; + check_keep_idle_inhibit(c); + if (last_focus_client && !last_focus_client->iskilling && last_focus_client != c) { last_focus_client->isfocusing = false; @@ -4029,6 +4035,7 @@ void init_client_properties(Client *c) { c->force_tiled_state = 1; c->force_tearing = 0; c->allow_shortcuts_inhibit = SHORTCUTS_INHIBIT_ENABLE; + c->indleinhibit_when_focus = 0; c->scroller_proportion_single = 0.0f; c->float_geom.width = 0; c->float_geom.height = 0; @@ -5564,6 +5571,9 @@ void setup(void) { idle_inhibit_mgr = wlr_idle_inhibit_v1_create(dpy); wl_signal_add(&idle_inhibit_mgr->events.new_inhibitor, &new_idle_inhibitor); + keep_idle_inhibit_source = wl_event_loop_add_timer( + wl_display_get_event_loop(dpy), keep_idle_inhibit, NULL); + layer_shell = wlr_layer_shell_v1_create(dpy, 4); wl_signal_add(&layer_shell->events.new_surface, &new_layer_surface); @@ -5632,7 +5642,7 @@ void setup(void) { wl_signal_add(&cursor_shape_mgr->events.request_set_shape, &request_set_cursor_shape); hide_cursor_source = wl_event_loop_add_timer(wl_display_get_event_loop(dpy), - hidecursor, cursor); + hidecursor, cursor); /* * Configures a seat, which is a single "seat" at which a user sits and * operates the computer. This conceptually includes up to one keyboard, @@ -5851,7 +5861,8 @@ void overview_restore(Client *c, const Arg *arg) { } void handlecursoractivity(void) { - wl_event_source_timer_update(hide_cursor_source, cursor_hide_timeout * 1000); + wl_event_source_timer_update(hide_cursor_source, + cursor_hide_timeout * 1000); if (!cursor_hidden) return; @@ -5872,6 +5883,36 @@ int32_t hidecursor(void *data) { return 1; } +void check_keep_idle_inhibit(Client *c) { + if (c && c->indleinhibit_when_focus && keep_idle_inhibit_source) { + wl_event_source_timer_update(keep_idle_inhibit_source, 1000); + } +} + +int32_t keep_idle_inhibit(void *data) { + + if (!idle_inhibit_mgr) { + wl_event_source_timer_update(keep_idle_inhibit_source, 0); + return 1; + } + + if (session && !session->active) { + wl_event_source_timer_update(keep_idle_inhibit_source, 0); + return 1; + } + + if (!selmon || !selmon->sel || !selmon->sel->indleinhibit_when_focus) { + wl_event_source_timer_update(keep_idle_inhibit_source, 0); + return 1; + } + + if (seat && idle_notifier) { + wlr_idle_notifier_v1_notify_activity(idle_notifier, seat); + wl_event_source_timer_update(keep_idle_inhibit_source, 1000); + } + return 1; +} + void unlocksession(struct wl_listener *listener, void *data) { SessionLock *lock = wl_container_of(listener, lock, unlock); destroylock(lock, 1); From 7f99b5ff4870aa44b5237a5eb16edbbf77671cff Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Wed, 4 Mar 2026 12:17:44 +0800 Subject: [PATCH 572/591] feat: use monitor spec to match windowrule monitor field --- src/config/parse_config.h | 2 +- src/mango.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/config/parse_config.h b/src/config/parse_config.h index 8a965360..ce5db532 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -79,7 +79,7 @@ typedef struct { int32_t ignore_minimize; int32_t isnosizehint; int32_t indleinhibit_when_focus; - const char *monitor; + char *monitor; int32_t offsetx; int32_t offsety; int32_t width; diff --git a/src/mango.c b/src/mango.c index 8a93a792..9a027a33 100644 --- a/src/mango.c +++ b/src/mango.c @@ -1443,7 +1443,7 @@ void applyrules(Client *c) { // set monitor of client wl_list_for_each(m, &mons, link) { - if (regex_match(r->monitor, m->wlr_output->name)) { + if (match_monitor_spec(r->monitor, m)) { mon = m; } } From bf10fabfc2ef43e024165df97056264c09e21fd6 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Thu, 5 Mar 2026 08:27:20 +0800 Subject: [PATCH 573/591] fix: popup unconstrain cross monitor --- src/mango.c | 44 ++++++++++++++++++-------------------------- 1 file changed, 18 insertions(+), 26 deletions(-) diff --git a/src/mango.c b/src/mango.c index 9a027a33..9edc25fb 100644 --- a/src/mango.c +++ b/src/mango.c @@ -488,7 +488,6 @@ typedef struct { typedef struct { struct wlr_xdg_popup *wlr_popup; - uint32_t type; struct wl_listener destroy; struct wl_listener commit; struct wl_listener reposition; @@ -2591,6 +2590,9 @@ void destroydecoration(struct wl_listener *listener, void *data) { static void popup_unconstrain(Popup *popup) { struct wlr_xdg_popup *wlr_popup = popup->wlr_popup; + Client *c = NULL; + LayerSurface *l = NULL; + int32_t type = -1; if (!wlr_popup || !wlr_popup->parent) { return; @@ -2601,16 +2603,17 @@ static void popup_unconstrain(Popup *popup) { wlr_log(WLR_ERROR, "Popup parent has no scene node"); return; } + + type = toplevel_from_wlr_surface(wlr_popup->base->surface, &c, &l); + if ((l && !l->mon) || (c && !c->mon)) { + wlr_xdg_popup_destroy(wlr_popup); + return; + } + int parent_lx, parent_ly; wlr_scene_node_coords(parent_node, &parent_lx, &parent_ly); - struct wlr_box *scheduled = &wlr_popup->scheduled.geometry; - int popup_lx = parent_lx + scheduled->x; - int popup_ly = parent_ly + scheduled->y; - - Monitor *mon = get_monitor_nearest_to(popup_lx, popup_ly); - - struct wlr_box usable = popup->type == LayerShell ? mon->m : mon->w; + struct wlr_box usable = type == LayerShell ? l->mon->m : c->mon->w; struct wlr_box constraint_box = { .x = usable.x - parent_lx, @@ -2633,33 +2636,22 @@ static void commitpopup(struct wl_listener *listener, void *data) { Popup *popup = wl_container_of(listener, popup, commit); struct wlr_surface *surface = data; - struct wlr_xdg_popup *wkr_popup = + struct wlr_xdg_popup *wlr_popup = wlr_xdg_popup_try_from_wlr_surface(surface); - Client *c = NULL; - LayerSurface *l = NULL; - int32_t type = -1; - - if (!wkr_popup || !wkr_popup->base->initial_commit) + if (!wlr_popup || !wlr_popup->base->initial_commit) goto commitpopup_listen_free; - type = toplevel_from_wlr_surface(wkr_popup->base->surface, &c, &l); - if (!wkr_popup->parent || !wkr_popup->parent->data || type < 0) { - wlr_xdg_popup_destroy(wkr_popup); + if (!wlr_popup->parent || !wlr_popup->parent->data) { goto commitpopup_listen_free; } - wlr_scene_node_raise_to_top(wkr_popup->parent->data); + wlr_scene_node_raise_to_top(wlr_popup->parent->data); - wkr_popup->base->surface->data = - wlr_scene_xdg_surface_create(wkr_popup->parent->data, wkr_popup->base); - if ((l && !l->mon) || (c && !c->mon)) { - wlr_xdg_popup_destroy(wkr_popup); - goto commitpopup_listen_free; - } + wlr_popup->base->surface->data = + wlr_scene_xdg_surface_create(wlr_popup->parent->data, wlr_popup->base); - popup->type = type; - popup->wlr_popup = wkr_popup; + popup->wlr_popup = wlr_popup; popup_unconstrain(popup); From 0f68187cd0a48d18f8f25dcc8f12bfa666524156 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Thu, 5 Mar 2026 11:47:17 +0800 Subject: [PATCH 574/591] opt: support restore size per when master change --- src/layout/arrange.h | 78 ++++++++++++++++++++++++++++++++------------ src/mango.c | 16 +++++++++ 2 files changed, 74 insertions(+), 20 deletions(-) diff --git a/src/layout/arrange.h b/src/layout/arrange.h index 1ef89c3a..53c64893 100644 --- a/src/layout/arrange.h +++ b/src/layout/arrange.h @@ -1,11 +1,31 @@ +void save_old_size_per(Monitor *m) { + Client *c = NULL; + + wl_list_for_each(c, &clients, link) { + if (VISIBLEON(c, m) && ISTILED(c)) { + c->old_master_inner_per = c->master_inner_per; + c->old_stack_inner_per = c->stack_inner_per; + } + } +} + void restore_size_per(Monitor *m, Client *c) { Client *fc = NULL; - double total_master_inner_per = 0; - double total_stack_inner_per = 0; if (!m || !c) return; + wl_list_for_each(fc, &clients, link) { + if (VISIBLEON(fc, m) && ISTILED(fc)) { + fc->old_ismaster = fc->ismaster; + } + } + + c->old_master_inner_per = c->master_inner_per; + c->old_stack_inner_per = c->stack_inner_per; + + pre_caculate_before_arrange(m, false, false, true); + const Layout *current_layout = m->pertag->ltidxs[m->pertag->curtag]; if (current_layout->id == SCROLLER || @@ -15,7 +35,7 @@ void restore_size_per(Monitor *m, Client *c) { return; } - if (current_layout->id == CENTER_TILE || c->ismaster) { + if (current_layout->id == CENTER_TILE) { wl_list_for_each(fc, &clients, link) { if (VISIBLEON(fc, m) && ISTILED(fc) && !c->ismaster) { set_size_per(m, fc); @@ -24,19 +44,28 @@ void restore_size_per(Monitor *m, Client *c) { return; } - wl_list_for_each(fc, &clients, link) { - if (VISIBLEON(fc, m) && ISTILED(fc) && fc != c) { - if (fc->ismaster) { - total_master_inner_per += fc->master_inner_per; - } else { - total_stack_inner_per += fc->stack_inner_per; - } - } + if (!c->ismaster && c->old_stack_inner_per < 1.0 && + c->stack_inner_per < 1.0) { + c->stack_inner_per = (1.0 - c->stack_inner_per) * + c->old_stack_inner_per / + (1.0 - c->old_stack_inner_per); } - if (!c->ismaster && total_stack_inner_per) { - c->stack_inner_per = total_stack_inner_per * c->stack_inner_per / - (1 - c->stack_inner_per); + if (c->ismaster && c->old_master_inner_per < 1.0 && + c->master_inner_per < 1.0) { + c->master_inner_per = (1.0 - c->master_inner_per) * + c->old_master_inner_per / + (1.0 - c->old_master_inner_per); + } + + wl_list_for_each(fc, &clients, link) { + if (VISIBLEON(fc, m) && ISTILED(fc) && fc != c && !fc->ismaster && + fc->old_ismaster && fc->old_stack_inner_per < 1.0 && + fc->stack_inner_per < 1.0) { + fc->stack_inner_per = (1.0 - fc->stack_inner_per) * + fc->old_stack_inner_per / + (1.0 - fc->old_stack_inner_per); + } } } @@ -705,8 +734,8 @@ void reset_size_per_mon(Monitor *m, int32_t tile_cilent_num, } } -void // 17 -arrange(Monitor *m, bool want_animation, bool from_view) { +void pre_caculate_before_arrange(Monitor *m, bool want_animation, + bool from_view, bool only_caculate) { Client *c = NULL; double total_stack_inner_percent = 0; double total_master_inner_percent = 0; @@ -795,14 +824,17 @@ arrange(Monitor *m, bool want_animation, bool from_view) { i++; } - set_arrange_visible(m, c, want_animation); + if (!only_caculate) + set_arrange_visible(m, c, want_animation); } else { - set_arrange_hidden(m, c, want_animation); + if (!only_caculate) + set_arrange_hidden(m, c, want_animation); } } - if (c->mon == m && c->ismaximizescreen && !c->animation.tagouted && - !c->animation.tagouting && VISIBLEON(c, m)) { + if (!only_caculate && c->mon == m && c->ismaximizescreen && + !c->animation.tagouted && !c->animation.tagouting && + VISIBLEON(c, m)) { reset_maximizescreen_size(c); } } @@ -811,6 +843,12 @@ arrange(Monitor *m, bool want_animation, bool from_view) { m, m->visible_tiling_clients, total_left_stack_hight_percent, total_right_stack_hight_percent, total_stack_inner_percent, total_master_inner_percent, master_num, stack_num); +} + +void // 17 +arrange(Monitor *m, bool want_animation, bool from_view) { + + pre_caculate_before_arrange(m, want_animation, from_view, false); if (m->isoverview) { overviewlayout.arrange(m); diff --git a/src/mango.c b/src/mango.c index 9edc25fb..3ae5ccc9 100644 --- a/src/mango.c +++ b/src/mango.c @@ -412,6 +412,7 @@ struct Client { double old_master_mfact_per, old_master_inner_per, old_stack_inner_per; double old_scroller_pproportion; bool ismaster; + bool old_ismaster; bool cursor_in_upper_half, cursor_in_left_half; bool isleftstack; int32_t tearing_hint; @@ -803,6 +804,8 @@ static void last_cursor_surface_destroy(struct wl_listener *listener, void *data); static int32_t keep_idle_inhibit(void *data); static void check_keep_idle_inhibit(Client *c); +static void pre_caculate_before_arrange(Monitor *m, bool want_animation, + bool from_view, bool only_caculate); #include "data/static_keymap.h" #include "dispatch/bind_declare.h" @@ -3981,6 +3984,7 @@ void init_client_properties(Client *c) { c->swallowing = NULL; c->swallowedby = NULL; c->ismaster = 0; + c->old_ismaster = 0; c->isleftstack = 0; c->ismaximizescreen = 0; c->isfullscreen = 0; @@ -5047,6 +5051,10 @@ setfloating(Client *c, int32_t floating) { restore_size_per(c->mon, c); } + if (c->isfloating && !old_floating_state) { + save_old_size_per(c->mon); + } + if (!c->force_maximize) client_set_maximized(c, false); @@ -5133,6 +5141,10 @@ void setmaximizescreen(Client *c, int32_t maximizescreen) { restore_size_per(c->mon, c); } + if (c->ismaximizescreen && !old_maximizescreen_state) { + save_old_size_per(c->mon); + } + if (!c->force_maximize && !c->ismaximizescreen) { client_set_maximized(c, false); } else if (!c->force_maximize && c->ismaximizescreen) { @@ -5204,6 +5216,10 @@ void setfullscreen(Client *c, int32_t fullscreen) // 用自定义全屏代理自 restore_size_per(c->mon, c); } + if (c->isfullscreen && !old_fullscreen_state) { + save_old_size_per(c->mon); + } + arrange(c->mon, false, false); } From 9df273cdf98cb28057ce20fd9adb9a73215800b1 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Thu, 5 Mar 2026 23:03:01 +0800 Subject: [PATCH 575/591] opt: clear some comment --- .github/workflows/stale.yml | 2 +- src/layout/arrange.h | 12 ++++-------- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 43e8badc..d0b19c1e 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -16,7 +16,7 @@ jobs: days-before-issue-stale: -1 # 手动标记后,14 天后关闭 days-before-issue-close: 7 - # 使用的标签(必须和你手动添加的标签一致) + # 使用的标签 stale-issue-label: "stale" # 自动关闭时自动加上的标签 close-issue-label: "automatic-closing" diff --git a/src/layout/arrange.h b/src/layout/arrange.h index 53c64893..69d221d1 100644 --- a/src/layout/arrange.h +++ b/src/layout/arrange.h @@ -119,8 +119,7 @@ void resize_tile_master_horizontal(Client *grabc, bool isdrag, int32_t offsetx, break; } - if (!begin_find_nextnext && VISIBLEON(tc, grabc->mon) && - ISTILED(tc)) { // 根据你的实际字段名调整 + if (!begin_find_nextnext && VISIBLEON(tc, grabc->mon) && ISTILED(tc)) { next = tc; begin_find_nextnext = true; continue; @@ -136,8 +135,7 @@ void resize_tile_master_horizontal(Client *grabc, bool isdrag, int32_t offsetx, break; } - if (!begin_find_prevprev && VISIBLEON(tc, grabc->mon) && - ISTILED(tc)) { // 根据你的实际字段名调整 + if (!begin_find_prevprev && VISIBLEON(tc, grabc->mon) && ISTILED(tc)) { prev = tc; begin_find_prevprev = true; continue; @@ -305,8 +303,7 @@ void resize_tile_master_vertical(Client *grabc, bool isdrag, int32_t offsetx, for (node = grabc->link.next; node != &clients; node = node->next) { tc = wl_container_of(node, tc, link); - if (VISIBLEON(tc, grabc->mon) && - ISTILED(tc)) { // 根据你的实际字段名调整 + if (VISIBLEON(tc, grabc->mon) && ISTILED(tc)) { next = tc; break; } @@ -316,8 +313,7 @@ void resize_tile_master_vertical(Client *grabc, bool isdrag, int32_t offsetx, for (node = grabc->link.prev; node != &clients; node = node->prev) { tc = wl_container_of(node, tc, link); - if (VISIBLEON(tc, grabc->mon) && - ISTILED(tc)) { // 根据你的实际字段名调整 + if (VISIBLEON(tc, grabc->mon) && ISTILED(tc)) { prev = tc; break; } From 6522e18d0839858711974f351a54fa20d3e05b68 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Fri, 6 Mar 2026 13:25:24 +0800 Subject: [PATCH 576/591] opt: fix potential issues caused by uninitialization --- src/layout/arrange.h | 20 +++++++++++++++++--- src/mango.c | 3 +++ 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/layout/arrange.h b/src/layout/arrange.h index 69d221d1..d674068e 100644 --- a/src/layout/arrange.h +++ b/src/layout/arrange.h @@ -5,6 +5,16 @@ void save_old_size_per(Monitor *m) { if (VISIBLEON(c, m) && ISTILED(c)) { c->old_master_inner_per = c->master_inner_per; c->old_stack_inner_per = c->stack_inner_per; + } else { + if (c->old_master_inner_per <= 0.0f || + c->old_master_inner_per > 1.0f) { + c->old_master_inner_per = 1.0f; + } + + if (c->old_stack_inner_per <= 0.0f || + c->old_stack_inner_per > 1.0f) { + c->old_stack_inner_per = 1.0f; + } } } } @@ -45,14 +55,16 @@ void restore_size_per(Monitor *m, Client *c) { } if (!c->ismaster && c->old_stack_inner_per < 1.0 && - c->stack_inner_per < 1.0) { + c->old_stack_inner_per > 0.0f && c->stack_inner_per < 1.0 && + c->stack_inner_per > 0.0f) { c->stack_inner_per = (1.0 - c->stack_inner_per) * c->old_stack_inner_per / (1.0 - c->old_stack_inner_per); } if (c->ismaster && c->old_master_inner_per < 1.0 && - c->master_inner_per < 1.0) { + c->old_master_inner_per > 0.0f && c->master_inner_per < 1.0 && + c->master_inner_per > 0.0f) { c->master_inner_per = (1.0 - c->master_inner_per) * c->old_master_inner_per / (1.0 - c->old_master_inner_per); @@ -61,10 +73,12 @@ void restore_size_per(Monitor *m, Client *c) { wl_list_for_each(fc, &clients, link) { if (VISIBLEON(fc, m) && ISTILED(fc) && fc != c && !fc->ismaster && fc->old_ismaster && fc->old_stack_inner_per < 1.0 && - fc->stack_inner_per < 1.0) { + fc->old_stack_inner_per > 0.0f && fc->stack_inner_per < 1.0 && + fc->stack_inner_per > 0.0f) { fc->stack_inner_per = (1.0 - fc->stack_inner_per) * fc->old_stack_inner_per / (1.0 - fc->old_stack_inner_per); + fc->old_ismaster = false; } } } diff --git a/src/mango.c b/src/mango.c index 3ae5ccc9..4c063cf4 100644 --- a/src/mango.c +++ b/src/mango.c @@ -4025,6 +4025,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 = 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; From 11b4bb03bfea2e914fc7b208f724d89f7a446060 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Fri, 6 Mar 2026 14:17:26 +0800 Subject: [PATCH 577/591] feat: support the repeated exchange of the same two clients --- src/dispatch/bind_define.h | 4 +++- src/mango.c | 5 +++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index 5cf41d6c..ac1f6022 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -110,7 +110,9 @@ int32_t exchange_client(const Arg *arg) { if ((c->isfullscreen || c->ismaximizescreen) && !is_scroller_layout(c->mon)) return 0; - exchange_two_client(c, direction_select(arg)); + Client *tc = direction_select(arg); + tc = get_focused_stack_client(tc); + exchange_two_client(c, tc); return 0; } diff --git a/src/mango.c b/src/mango.c index 4c063cf4..c28844fe 100644 --- a/src/mango.c +++ b/src/mango.c @@ -4830,6 +4830,11 @@ void exchange_two_client(Client *c1, Client *c2) { } else { arrange(c1->mon, false, false); } + + // In order to facilitate repeated exchanges for get_focused_stack_client + // set c2 focus order behind c1 + wl_list_remove(&c2->flink); + wl_list_insert(&c1->flink, &c2->flink); } void set_activation_env() { From 9a17a0279c39b330d155d50282d1d2641d519dc3 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Fri, 6 Mar 2026 18:21:49 +0800 Subject: [PATCH 578/591] feat: add custom option to monitorrule --- src/config/parse_config.h | 10 ++++++++-- src/mango.c | 5 +++-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/config/parse_config.h b/src/config/parse_config.h index ce5db532..59debcf2 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -112,6 +112,7 @@ typedef struct { int32_t width, height; // Monitor resolution float refresh; // Refresh rate int32_t vrr; // variable refresh rate + int32_t custom; // enable custom mode } ConfigMonitorRule; // 修改后的宏定义 @@ -1796,6 +1797,7 @@ bool parse_option(Config *config, char *key, char *value) { rule->height = -1; rule->refresh = 0.0f; rule->vrr = 0; + rule->custom = 0; bool parse_error = false; char *token = strtok(value, ","); @@ -1833,6 +1835,8 @@ 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, "custom") == 0) { + rule->custom = CLAMP_INT(atoi(val), 0, 1); } else { fprintf(stderr, "\033[1m\033[31m[ERROR]:\033[33m Unknown " @@ -3555,7 +3559,7 @@ void reset_blur_params(void) { void reapply_monitor_rules(void) { ConfigMonitorRule *mr; Monitor *m = NULL; - int32_t ji, vrr; + int32_t ji, vrr, custom; int32_t mx, my; struct wlr_output_state state; struct wlr_output_mode *internal_mode = NULL; @@ -3609,13 +3613,15 @@ void reapply_monitor_rules(void) { 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; if (mr->width > 0 && mr->height > 0 && mr->refresh > 0) { internal_mode = get_nearest_output_mode( m->wlr_output, mr->width, mr->height, mr->refresh); if (internal_mode) { wlr_output_state_set_mode(&state, internal_mode); - } else if (wlr_output_is_headless(m->wlr_output)) { + } else if (custom || + wlr_output_is_headless(m->wlr_output)) { wlr_output_state_set_custom_mode( &state, mr->width, mr->height, (int32_t)roundf(mr->refresh * 1000)); diff --git a/src/mango.c b/src/mango.c index c28844fe..94bddb6b 100644 --- a/src/mango.c +++ b/src/mango.c @@ -2884,7 +2884,7 @@ void createmon(struct wl_listener *listener, void *data) { struct wlr_output *wlr_output = data; const ConfigMonitorRule *r; uint32_t i; - int32_t ji, vrr; + int32_t ji, vrr, custom; struct wlr_output_state state; Monitor *m = NULL; struct wlr_output_mode *internal_mode = NULL; @@ -2976,6 +2976,7 @@ void createmon(struct wl_listener *listener, void *data) { m->m.x = r->x == INT32_MAX ? INT32_MAX : r->x; m->m.y = r->y == INT32_MAX ? INT32_MAX : r->y; vrr = r->vrr >= 0 ? r->vrr : 0; + custom = r->custom >= 0 ? r->custom : 0; scale = r->scale; rr = r->rr; @@ -2985,7 +2986,7 @@ void createmon(struct wl_listener *listener, void *data) { if (internal_mode) { custom_monitor_mode = true; wlr_output_state_set_mode(&state, internal_mode); - } else if (wlr_output_is_headless(m->wlr_output)) { + } else if (custom || wlr_output_is_headless(m->wlr_output)) { custom_monitor_mode = true; wlr_output_state_set_custom_mode( &state, r->width, r->height, From 10d7e5c6e3817d36ae8dbe5747ad23fe26944a45 Mon Sep 17 00:00:00 2001 From: kanvolu Date: Fri, 6 Mar 2026 22:23:59 -0500 Subject: [PATCH 579/591] Added cycling both ways for switch_proportion_preset Now switch_proportion_preset requires an argument "prev" or "next" to determine cycle direction --- src/config/parse_config.h | 1 + src/dispatch/bind_declare.h | 2 +- src/dispatch/bind_define.h | 29 ++++++++++++++++++++++------- 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/src/config/parse_config.h b/src/config/parse_config.h index 59debcf2..47d086a7 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -947,6 +947,7 @@ FuncType parse_func_name(char *func_name, Arg *arg, char *arg_value, (*arg).f = atof(arg_value); } else if (strcmp(func_name, "switch_proportion_preset") == 0) { func = switch_proportion_preset; + (*arg).i = parse_circle_direction(arg_value); } else if (strcmp(func_name, "viewtoleft") == 0) { func = viewtoleft; (*arg).i = atoi(arg_value); diff --git a/src/dispatch/bind_declare.h b/src/dispatch/bind_declare.h index 22ef6123..7dced532 100644 --- a/src/dispatch/bind_declare.h +++ b/src/dispatch/bind_declare.h @@ -69,4 +69,4 @@ 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 scroller_stack(const Arg *arg); \ No newline at end of file +int32_t scroller_stack(const Arg *arg); diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index ac1f6022..676be515 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -1056,13 +1056,28 @@ int32_t switch_proportion_preset(const Arg *arg) { for (int32_t i = 0; i < config.scroller_proportion_preset_count; i++) { if (config.scroller_proportion_preset[i] == tc->scroller_proportion) { - if (i == config.scroller_proportion_preset_count - 1) { - target_proportion = config.scroller_proportion_preset[0]; - break; + + if (arg->i == NEXT) { + if (i == config.scroller_proportion_preset_count - 1) { + target_proportion = + config.scroller_proportion_preset[0]; + break; + } else { + target_proportion = + config.scroller_proportion_preset[i + 1]; + break; + } } else { - target_proportion = - config.scroller_proportion_preset[i + 1]; - break; + if (i == 0) { + target_proportion = + config.scroller_proportion_preset + [config.scroller_proportion_preset_count - 1]; + break; + } else { + target_proportion = + config.scroller_proportion_preset[i - 1]; + break; + } } } } @@ -1847,4 +1862,4 @@ int32_t scroller_stack(const Arg *arg) { arrange(selmon, false, false); return 0; -} \ No newline at end of file +} From 63b9ffb1a422e34b8d2ce4121cf1aee6fd0e5dad Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sat, 7 Mar 2026 12:54:37 +0800 Subject: [PATCH 580/591] opt: opt the old size per init --- src/layout/arrange.h | 10 ---------- src/mango.c | 6 +++--- 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/src/layout/arrange.h b/src/layout/arrange.h index d674068e..058198bf 100644 --- a/src/layout/arrange.h +++ b/src/layout/arrange.h @@ -5,16 +5,6 @@ void save_old_size_per(Monitor *m) { if (VISIBLEON(c, m) && ISTILED(c)) { c->old_master_inner_per = c->master_inner_per; c->old_stack_inner_per = c->stack_inner_per; - } else { - if (c->old_master_inner_per <= 0.0f || - c->old_master_inner_per > 1.0f) { - c->old_master_inner_per = 1.0f; - } - - if (c->old_stack_inner_per <= 0.0f || - c->old_stack_inner_per > 1.0f) { - c->old_stack_inner_per = 1.0f; - } } } } diff --git a/src/mango.c b/src/mango.c index 94bddb6b..a256d8f0 100644 --- a/src/mango.c +++ b/src/mango.c @@ -4026,9 +4026,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 = 0.0f; - c->old_master_inner_per = 0.0f; - c->old_master_mfact_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->isterm = 0; c->allow_csd = 0; c->force_maximize = 0; From fd68f188c63e7595f55bbb326bcb7c7ad4ec7c1f Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sat, 7 Mar 2026 13:24:46 +0800 Subject: [PATCH 581/591] opt: add some comment --- src/layout/arrange.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/layout/arrange.h b/src/layout/arrange.h index 058198bf..36f6396a 100644 --- a/src/layout/arrange.h +++ b/src/layout/arrange.h @@ -44,6 +44,10 @@ void restore_size_per(Monitor *m, Client *c) { return; } + // it is possible that the current floating window is moved to another tag, + // but the tag has not executed save_old_size_per + // so it must be judged whether their old size values are initial values + if (!c->ismaster && c->old_stack_inner_per < 1.0 && c->old_stack_inner_per > 0.0f && c->stack_inner_per < 1.0 && c->stack_inner_per > 0.0f) { From 89a4ec83a0d24887d182209feca488f32fe3c071 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sat, 7 Mar 2026 13:46:18 +0800 Subject: [PATCH 582/591] fix: avoid mutual influence of monitor rules --- src/config/parse_config.h | 72 ++++--------------------- src/mango.c | 111 +++++++++++++++++--------------------- 2 files changed, 60 insertions(+), 123 deletions(-) diff --git a/src/config/parse_config.h b/src/config/parse_config.h index 47d086a7..d10bf0c2 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -372,6 +372,9 @@ typedef int32_t (*FuncType)(const Arg *); 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); +bool monitor_matches_rule(Monitor *m, const ConfigMonitorRule *rule); // Helper function to trim whitespace from start and end of a string void trim_whitespace(char *str) { @@ -3563,14 +3566,12 @@ void reapply_monitor_rules(void) { int32_t ji, vrr, custom; int32_t mx, my; struct wlr_output_state state; - struct wlr_output_mode *internal_mode = NULL; - wlr_output_state_init(&state); - bool match_rule = false; wl_list_for_each(m, &mons, link) { - if (!m->wlr_output->enabled) { + 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) @@ -3578,73 +3579,22 @@ void reapply_monitor_rules(void) { mr = &config.monitor_rules[ji]; - // 检查是否匹配的变量 - match_rule = true; - - // 检查四个标识字段的匹配 - if (mr->name != NULL) { - if (!regex_match(mr->name, m->wlr_output->name)) { - match_rule = false; - } - } - - if (mr->make != NULL) { - if (m->wlr_output->make == NULL || - strcmp(mr->make, m->wlr_output->make) != 0) { - match_rule = false; - } - } - - if (mr->model != NULL) { - if (m->wlr_output->model == NULL || - strcmp(mr->model, m->wlr_output->model) != 0) { - match_rule = false; - } - } - - if (mr->serial != NULL) { - if (m->wlr_output->serial == NULL || - strcmp(mr->serial, m->wlr_output->serial) != 0) { - match_rule = false; - } - } - - // 只有当所有指定的标识都匹配时才应用规则 - if (match_rule) { + 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; - if (mr->width > 0 && mr->height > 0 && mr->refresh > 0) { - internal_mode = get_nearest_output_mode( - m->wlr_output, mr->width, mr->height, mr->refresh); - if (internal_mode) { - wlr_output_state_set_mode(&state, internal_mode); - } else if (custom || - wlr_output_is_headless(m->wlr_output)) { - wlr_output_state_set_custom_mode( - &state, mr->width, mr->height, - (int32_t)roundf(mr->refresh * 1000)); - } - } - - if (vrr) { - enable_adaptive_sync(m, &state); - } else { - wlr_output_state_set_adaptive_sync_enabled(&state, false); - } - - wlr_output_state_set_scale(&state, mr->scale); - wlr_output_state_set_transform(&state, mr->rr); + (void)apply_rule_to_state(m, mr, &state, vrr, custom); wlr_output_layout_add(output_layout, m->wlr_output, mx, my); + wlr_output_commit_state(m->wlr_output, &state); + break; } } - wlr_output_commit_state(m->wlr_output, &state); wlr_output_state_finish(&state); - updatemons(NULL, NULL); } + updatemons(NULL, NULL); } void reapply_cursor_style(void) { diff --git a/src/mango.c b/src/mango.c index a256d8f0..2af2720f 100644 --- a/src/mango.c +++ b/src/mango.c @@ -806,7 +806,6 @@ static int32_t keep_idle_inhibit(void *data); static void check_keep_idle_inhibit(Client *c); static void pre_caculate_before_arrange(Monitor *m, bool want_animation, bool from_view, bool only_caculate); - #include "data/static_keymap.h" #include "dispatch/bind_declare.h" #include "layout/layout.h" @@ -2878,6 +2877,49 @@ void enable_adaptive_sync(Monitor *m, struct wlr_output_state *state) { } } +bool monitor_matches_rule(Monitor *m, const ConfigMonitorRule *rule) { + if (rule->name != NULL && !regex_match(rule->name, m->wlr_output->name)) + return false; + if (rule->make != NULL && (m->wlr_output->make == NULL || + strcmp(rule->make, m->wlr_output->make) != 0)) + return false; + if (rule->model != NULL && (m->wlr_output->model == NULL || + strcmp(rule->model, m->wlr_output->model) != 0)) + return false; + if (rule->serial != NULL && + (m->wlr_output->serial == NULL || + strcmp(rule->serial, m->wlr_output->serial) != 0)) + return false; + return true; +} + +/* 将规则中的显示参数应用到 wlr_output_state 中,返回是否设置了自定义模式 */ +bool apply_rule_to_state(Monitor *m, const ConfigMonitorRule *rule, + struct wlr_output_state *state, int vrr, int custom) { + bool mode_set = false; + if (rule->width > 0 && rule->height > 0 && rule->refresh > 0) { + struct wlr_output_mode *internal_mode = get_nearest_output_mode( + m->wlr_output, rule->width, rule->height, rule->refresh); + if (internal_mode) { + wlr_output_state_set_mode(state, internal_mode); + mode_set = true; + } else if (custom || wlr_output_is_headless(m->wlr_output)) { + wlr_output_state_set_custom_mode( + state, rule->width, rule->height, + (int32_t)roundf(rule->refresh * 1000)); + mode_set = true; + } + } + if (vrr) { + enable_adaptive_sync(m, state); + } else { + wlr_output_state_set_adaptive_sync_enabled(state, false); + } + wlr_output_state_set_scale(state, rule->scale); + wlr_output_state_set_transform(state, rule->rr); + return mode_set; +} + void createmon(struct wl_listener *listener, void *data) { /* This event is raised by the backend when a new output (aka a display or * monitor) becomes available. */ @@ -2887,9 +2929,7 @@ void createmon(struct wl_listener *listener, void *data) { int32_t ji, vrr, custom; struct wlr_output_state state; Monitor *m = NULL; - struct wlr_output_mode *internal_mode = NULL; bool custom_monitor_mode = false; - bool match_rule = false; if (!wlr_output_init_render(wlr_output, alloc, drw)) return; @@ -2919,7 +2959,6 @@ void createmon(struct wl_listener *listener, void *data) { for (i = 0; i < LENGTH(m->layers); i++) wl_list_init(&m->layers[i]); - wlr_output_state_init(&state); /* Initialize monitor state using configured rules */ m->gappih = gappih; m->gappiv = gappiv; @@ -2932,6 +2971,8 @@ void createmon(struct wl_listener *listener, void *data) { m->m.y = INT32_MAX; float scale = 1; enum wl_output_transform rr = WL_OUTPUT_TRANSFORM_NORMAL; + + wlr_output_state_init(&state); wlr_output_state_set_scale(&state, scale); wlr_output_state_set_transform(&state, rr); @@ -2941,38 +2982,7 @@ void createmon(struct wl_listener *listener, void *data) { r = &config.monitor_rules[ji]; - // 检查是否匹配的变量 - match_rule = true; - - // 检查四个标识字段的匹配 - if (r->name != NULL) { - if (!regex_match(r->name, m->wlr_output->name)) { - match_rule = false; - } - } - - if (r->make != NULL) { - if (m->wlr_output->make == NULL || - strcmp(r->make, m->wlr_output->make) != 0) { - match_rule = false; - } - } - - if (r->model != NULL) { - if (m->wlr_output->model == NULL || - strcmp(r->model, m->wlr_output->model) != 0) { - match_rule = false; - } - } - - if (r->serial != NULL) { - if (m->wlr_output->serial == NULL || - strcmp(r->serial, m->wlr_output->serial) != 0) { - match_rule = false; - } - } - - if (match_rule) { + if (monitor_matches_rule(m, r)) { m->m.x = r->x == INT32_MAX ? INT32_MAX : r->x; m->m.y = r->y == INT32_MAX ? INT32_MAX : r->y; vrr = r->vrr >= 0 ? r->vrr : 0; @@ -2980,36 +2990,13 @@ void createmon(struct wl_listener *listener, void *data) { scale = r->scale; rr = r->rr; - if (r->width > 0 && r->height > 0 && r->refresh > 0) { - internal_mode = get_nearest_output_mode(m->wlr_output, r->width, - r->height, r->refresh); - if (internal_mode) { - custom_monitor_mode = true; - wlr_output_state_set_mode(&state, internal_mode); - } else if (custom || wlr_output_is_headless(m->wlr_output)) { - custom_monitor_mode = true; - wlr_output_state_set_custom_mode( - &state, r->width, r->height, - (int32_t)roundf(r->refresh * 1000)); - } + if (apply_rule_to_state(m, r, &state, vrr, custom)) { + custom_monitor_mode = true; } - - if (vrr) { - enable_adaptive_sync(m, &state); - } else { - wlr_output_state_set_adaptive_sync_enabled(&state, false); - } - - wlr_output_state_set_scale(&state, r->scale); - wlr_output_state_set_transform(&state, r->rr); - break; + break; // 只应用第一个匹配规则 } } - /* The mode is a tuple of (width, height, refresh rate), and each - * monitor supports only a specific set of modes. We just pick the - * monitor's preferred mode; a more sophisticated compositor would let - * the user configure it. */ if (!custom_monitor_mode) wlr_output_state_set_mode(&state, wlr_output_preferred_mode(wlr_output)); From 75c888bbe4bc7efda789bbe1d8872a36b0b2a964 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sat, 7 Mar 2026 15:31:05 +0800 Subject: [PATCH 583/591] opt: optimize resizewin setp with keyboard --- src/layout/arrange.h | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/src/layout/arrange.h b/src/layout/arrange.h index 36f6396a..853e4692 100644 --- a/src/layout/arrange.h +++ b/src/layout/arrange.h @@ -276,6 +276,18 @@ void resize_tile_master_horizontal(Client *grabc, bool isdrag, int32_t offsetx, new_master_inner_per = fmaxf(0.1f, fminf(0.9f, new_master_inner_per)); new_stack_inner_per = fmaxf(0.1f, fminf(0.9f, new_stack_inner_per)); + if (!isdrag) { + new_stack_inner_per = + new_stack_inner_per + + (new_stack_inner_per - grabc->old_stack_inner_per) / + ((1 / new_stack_inner_per) - 1); + + new_master_inner_per = + new_master_inner_per + + (new_master_inner_per - grabc->old_master_inner_per) / + ((1 / new_master_inner_per) - 1); + } + // 应用到所有平铺窗口 wl_list_for_each(tc, &clients, link) { if (VISIBLEON(tc, grabc->mon) && ISTILED(tc)) { @@ -431,6 +443,18 @@ void resize_tile_master_vertical(Client *grabc, bool isdrag, int32_t offsetx, new_master_inner_per = fmaxf(0.1f, fminf(0.9f, new_master_inner_per)); new_stack_inner_per = fmaxf(0.1f, fminf(0.9f, new_stack_inner_per)); + if (!isdrag) { + new_stack_inner_per = + new_stack_inner_per + + (new_stack_inner_per - grabc->old_stack_inner_per) / + ((1 / new_stack_inner_per) - 1); + + new_master_inner_per = + new_master_inner_per + + (new_master_inner_per - grabc->old_master_inner_per) / + ((1 / new_master_inner_per) - 1); + } + // 应用到所有平铺窗口 wl_list_for_each(tc, &clients, link) { if (VISIBLEON(tc, grabc->mon) && ISTILED(tc)) { @@ -616,7 +640,14 @@ void resize_tile_scroller(Client *grabc, bool isdrag, int32_t offsetx, // 应用限制,确保比例在合理范围内 new_scroller_proportion = fmaxf(0.1f, fminf(1.0f, new_scroller_proportion)); - new_stack_proportion = fmaxf(0.1f, fminf(1.0f, new_stack_proportion)); + new_stack_proportion = fmaxf(0.1f, fminf(0.9f, new_stack_proportion)); + + if (!isdrag) { + new_stack_proportion = + new_stack_proportion + + (new_stack_proportion - grabc->old_stack_proportion) / + ((1 / new_stack_proportion) - 1); + } grabc->stack_proportion = new_stack_proportion; From b1d744ad1f493cba26fb31a87db5346ac9361c6b Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sat, 7 Mar 2026 17:21:50 +0800 Subject: [PATCH 584/591] feat: export drag interval to able configure --- assets/config.conf | 2 ++ src/config/parse_config.h | 15 +++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/assets/config.conf b/assets/config.conf index 15b654c1..77786649 100644 --- a/assets/config.conf +++ b/assets/config.conf @@ -74,6 +74,8 @@ overviewgappi=5 overviewgappo=30 # Misc +drag_tile_refresh_interval=16.0 +drag_floating_refresh_interval=8.0 no_border_when_single=0 axis_bind_apply_timeout=100 focus_on_activate=1 diff --git a/src/config/parse_config.h b/src/config/parse_config.h index d10bf0c2..3220b713 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -356,6 +356,8 @@ typedef struct { int32_t single_scratchpad; int32_t xwayland_persistence; int32_t syncobj_enable; + float drag_tile_refresh_interval; + float drag_floating_refresh_interval; int32_t allow_tearing; int32_t allow_shortcuts_inhibit; int32_t allow_lock_transparent; @@ -1399,6 +1401,10 @@ bool parse_option(Config *config, char *key, char *value) { config->xwayland_persistence = atoi(value); } else if (strcmp(key, "syncobj_enable") == 0) { config->syncobj_enable = atoi(value); + } else if (strcmp(key, "drag_tile_refresh_interval") == 0) { + config->drag_tile_refresh_interval = atof(value); + } else if (strcmp(key, "drag_floating_refresh_interval") == 0) { + config->drag_floating_refresh_interval = atof(value); } else if (strcmp(key, "allow_tearing") == 0) { config->allow_tearing = atoi(value); } else if (strcmp(key, "allow_shortcuts_inhibit") == 0) { @@ -3149,6 +3155,13 @@ void override_config(void) { // 杂项设置 xwayland_persistence = CLAMP_INT(config.xwayland_persistence, 0, 1); syncobj_enable = CLAMP_INT(config.syncobj_enable, 0, 1); + drag_tile_refresh_interval = + CLAMP_FLOAT(config.drag_tile_refresh_interval, 1.0f, 16.0f); + drag_floating_refresh_interval = + CLAMP_FLOAT(config.drag_floating_refresh_interval, 1.0f, 16.0f); + drag_tile_to_tile = CLAMP_INT(config.drag_tile_to_tile, 0, 1); + drag_floating_refresh_interval = + CLAMP_FLOAT(config.drag_floating_refresh_interval, 0.0f, 1000.0f); allow_tearing = CLAMP_INT(config.allow_tearing, 0, 2); allow_shortcuts_inhibit = CLAMP_INT(config.allow_shortcuts_inhibit, 0, 1); allow_lock_transparent = CLAMP_INT(config.allow_lock_transparent, 0, 1); @@ -3337,6 +3350,8 @@ void set_value_default() { config.single_scratchpad = single_scratchpad; config.xwayland_persistence = xwayland_persistence; config.syncobj_enable = syncobj_enable; + config.drag_tile_refresh_interval = drag_tile_refresh_interval; + config.drag_floating_refresh_interval = drag_floating_refresh_interval; config.allow_tearing = allow_tearing; config.allow_shortcuts_inhibit = allow_shortcuts_inhibit; config.allow_lock_transparent = allow_lock_transparent; From 636060972dc42c18a7abb1f533fc23be338ceb23 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sat, 7 Mar 2026 17:29:37 +0800 Subject: [PATCH 585/591] opt: change some default config --- assets/config.conf | 2 +- src/config/preset.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/assets/config.conf b/assets/config.conf index 77786649..d2587165 100644 --- a/assets/config.conf +++ b/assets/config.conf @@ -74,7 +74,7 @@ overviewgappi=5 overviewgappo=30 # Misc -drag_tile_refresh_interval=16.0 +drag_tile_refresh_interval=8.0 drag_floating_refresh_interval=8.0 no_border_when_single=0 axis_bind_apply_timeout=100 diff --git a/src/config/preset.h b/src/config/preset.h index d9824588..f91da11a 100644 --- a/src/config/preset.h +++ b/src/config/preset.h @@ -109,7 +109,7 @@ int32_t drag_warp_cursor = 1; int32_t xwayland_persistence = 1; /* xwayland persistence */ int32_t syncobj_enable = 0; int32_t allow_lock_transparent = 0; -double drag_tile_refresh_interval = 16.0; +double drag_tile_refresh_interval = 8.0; double drag_floating_refresh_interval = 8.0; int32_t allow_tearing = TEARING_DISABLED; int32_t allow_shortcuts_inhibit = SHORTCUTS_INHIBIT_ENABLE; From d0eb7d7114705877529045e6315de1c271a8e2a3 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sat, 7 Mar 2026 17:40:22 +0800 Subject: [PATCH 586/591] opt: remove some config in default config file --- assets/config.conf | 2 -- 1 file changed, 2 deletions(-) diff --git a/assets/config.conf b/assets/config.conf index d2587165..15b654c1 100644 --- a/assets/config.conf +++ b/assets/config.conf @@ -74,8 +74,6 @@ overviewgappi=5 overviewgappo=30 # Misc -drag_tile_refresh_interval=8.0 -drag_floating_refresh_interval=8.0 no_border_when_single=0 axis_bind_apply_timeout=100 focus_on_activate=1 From 09c170793177dcbdb4e0a7881260f4243caf2d59 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sat, 7 Mar 2026 18:51:12 +0800 Subject: [PATCH 587/591] opt: optimize size per caculate when resizewin --- src/layout/arrange.h | 93 ++++++++++++++++++++++++++++---------------- 1 file changed, 60 insertions(+), 33 deletions(-) diff --git a/src/layout/arrange.h b/src/layout/arrange.h index 853e4692..bbe735f7 100644 --- a/src/layout/arrange.h +++ b/src/layout/arrange.h @@ -276,21 +276,24 @@ void resize_tile_master_horizontal(Client *grabc, bool isdrag, int32_t offsetx, new_master_inner_per = fmaxf(0.1f, fminf(0.9f, new_master_inner_per)); new_stack_inner_per = fmaxf(0.1f, fminf(0.9f, new_stack_inner_per)); - if (!isdrag) { - new_stack_inner_per = - new_stack_inner_per + - (new_stack_inner_per - grabc->old_stack_inner_per) / - ((1 / new_stack_inner_per) - 1); - - new_master_inner_per = - new_master_inner_per + - (new_master_inner_per - grabc->old_master_inner_per) / - ((1 / new_master_inner_per) - 1); - } - // 应用到所有平铺窗口 wl_list_for_each(tc, &clients, link) { if (VISIBLEON(tc, grabc->mon) && ISTILED(tc)) { + + if (!isdrag && tc != grabc && type != CENTER_TILE) { + if (!tc->ismaster && new_stack_inner_per != 1.0f && + grabc->old_stack_inner_per != 1.0f) + tc->stack_inner_per = (1 - new_stack_inner_per) / + (1 - grabc->old_stack_inner_per) * + tc->stack_inner_per; + if (tc->ismaster && new_master_inner_per != 1.0f && + grabc->old_master_inner_per != 1.0f) + tc->master_inner_per = + (1.0f - new_master_inner_per) / + (1.0f - grabc->old_master_inner_per) * + tc->master_inner_per; + } + tc->master_mfact_per = new_master_mfact_per; } } @@ -443,21 +446,23 @@ void resize_tile_master_vertical(Client *grabc, bool isdrag, int32_t offsetx, new_master_inner_per = fmaxf(0.1f, fminf(0.9f, new_master_inner_per)); new_stack_inner_per = fmaxf(0.1f, fminf(0.9f, new_stack_inner_per)); - if (!isdrag) { - new_stack_inner_per = - new_stack_inner_per + - (new_stack_inner_per - grabc->old_stack_inner_per) / - ((1 / new_stack_inner_per) - 1); - - new_master_inner_per = - new_master_inner_per + - (new_master_inner_per - grabc->old_master_inner_per) / - ((1 / new_master_inner_per) - 1); - } - // 应用到所有平铺窗口 wl_list_for_each(tc, &clients, link) { if (VISIBLEON(tc, grabc->mon) && ISTILED(tc)) { + if (!isdrag && tc != grabc && type != CENTER_TILE) { + if (!tc->ismaster && new_stack_inner_per != 1.0f && + grabc->old_stack_inner_per != 1.0f) + tc->stack_inner_per = (1 - new_stack_inner_per) / + (1 - grabc->old_stack_inner_per) * + tc->stack_inner_per; + if (tc->ismaster && new_master_inner_per != 1.0f && + grabc->old_master_inner_per != 1.0f) + tc->master_inner_per = + (1.0f - new_master_inner_per) / + (1.0f - grabc->old_master_inner_per) * + tc->master_inner_per; + } + tc->master_mfact_per = new_master_mfact_per; } } @@ -480,6 +485,7 @@ void resize_tile_master_vertical(Client *grabc, bool isdrag, int32_t offsetx, void resize_tile_scroller(Client *grabc, bool isdrag, int32_t offsetx, int32_t offsety, uint32_t time, bool isvertical) { + Client *tc = NULL; float delta_x, delta_y; float new_scroller_proportion; float new_stack_proportion; @@ -642,17 +648,20 @@ void resize_tile_scroller(Client *grabc, bool isdrag, int32_t offsetx, fmaxf(0.1f, fminf(1.0f, new_scroller_proportion)); new_stack_proportion = fmaxf(0.1f, fminf(0.9f, new_stack_proportion)); - if (!isdrag) { - new_stack_proportion = - new_stack_proportion + - (new_stack_proportion - grabc->old_stack_proportion) / - ((1 / new_stack_proportion) - 1); - } - grabc->stack_proportion = new_stack_proportion; stack_head->scroller_proportion = new_scroller_proportion; + wl_list_for_each(tc, &clients, link) { + if (new_stack_proportion != 1.0f && + grabc->old_stack_proportion != 1.0f && tc != grabc && + ISTILED(tc) && get_scroll_stack_head(tc) == stack_head) { + tc->stack_proportion = (1.0f - new_stack_proportion) / + (1.0f - grabc->old_stack_proportion) * + tc->stack_proportion; + } + } + if (!isdrag) { arrange(grabc->mon, false, false); return; @@ -695,6 +704,18 @@ void resize_tile_client(Client *grabc, bool isdrag, int32_t offsetx, } } +/* If there are no calculation omissions, +these two functions will never be triggered. +Just in case to facilitate the final investigation*/ + +void check_size_per_valid(Client *c) { + if (c->ismaster) { + assert(c->master_inner_per > 0.0f && c->master_inner_per <= 1.0f); + } else { + assert(c->stack_inner_per > 0.0f && c->stack_inner_per <= 1.0f); + } +} + void reset_size_per_mon(Monitor *m, int32_t tile_cilent_num, double total_left_stack_hight_percent, double total_right_stack_hight_percent, @@ -710,6 +731,7 @@ void reset_size_per_mon(Monitor *m, int32_t tile_cilent_num, wl_list_for_each(c, &clients, link) { if (VISIBLEON(c, m) && ISTILED(c)) { + if (total_master_inner_percent > 0.0 && i < nmasters) { c->ismaster = true; c->stack_inner_per = stack_num ? 1.0f / stack_num : 1.0f; @@ -725,17 +747,20 @@ void reset_size_per_mon(Monitor *m, int32_t tile_cilent_num, : 1.0f; } i++; + + check_size_per_valid(c); } } } else { wl_list_for_each(c, &clients, link) { if (VISIBLEON(c, m) && ISTILED(c)) { + if (total_master_inner_percent > 0.0 && i < nmasters) { c->ismaster = true; if ((stack_index % 2) ^ (tile_cilent_num % 2 == 0)) { c->stack_inner_per = - stack_num > 1 ? 1.0f / ((stack_num - 1) / 2) : 1.0f; - + stack_num > 1 ? 1.0f / ((stack_num - 1) / 2.0f) + : 1.0f; } else { c->stack_inner_per = stack_num > 1 ? 2.0f / stack_num : 1.0f; @@ -764,6 +789,8 @@ void reset_size_per_mon(Monitor *m, int32_t tile_cilent_num, } } i++; + + check_size_per_valid(c); } } } From 31284b4b5db8785004cdb345c778f31424684a6f Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sat, 7 Mar 2026 22:54:13 +0800 Subject: [PATCH 588/591] opt: optimize center tile layout resizewin --- src/layout/arrange.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/layout/arrange.h b/src/layout/arrange.h index bbe735f7..33db8ec0 100644 --- a/src/layout/arrange.h +++ b/src/layout/arrange.h @@ -280,9 +280,11 @@ void resize_tile_master_horizontal(Client *grabc, bool isdrag, int32_t offsetx, wl_list_for_each(tc, &clients, link) { if (VISIBLEON(tc, grabc->mon) && ISTILED(tc)) { - if (!isdrag && tc != grabc && type != CENTER_TILE) { + if (!isdrag && tc != grabc) { if (!tc->ismaster && new_stack_inner_per != 1.0f && - grabc->old_stack_inner_per != 1.0f) + grabc->old_stack_inner_per != 1.0f && + (type != CENTER_TILE || + !(grabc->isleftstack ^ tc->isleftstack))) tc->stack_inner_per = (1 - new_stack_inner_per) / (1 - grabc->old_stack_inner_per) * tc->stack_inner_per; From cfe492fbc4af1b9518d1102680c3452e0e52d7b8 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sat, 7 Mar 2026 23:14:17 +0800 Subject: [PATCH 589/591] opt: fix a minor judgment error --- src/layout/arrange.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/layout/arrange.h b/src/layout/arrange.h index 33db8ec0..0284f8ca 100644 --- a/src/layout/arrange.h +++ b/src/layout/arrange.h @@ -89,7 +89,7 @@ void set_size_per(Monitor *m, Client *c) { wl_list_for_each(fc, &clients, link) { if (VISIBLEON(fc, m) && ISTILED(fc) && fc != c) { if (current_layout->id == CENTER_TILE && - !(fc->isleftstack ^ c->isleftstack)) + (fc->isleftstack ^ c->isleftstack)) continue; c->master_mfact_per = fc->master_mfact_per; c->master_inner_per = fc->master_inner_per; From 89a0f7e3155a9b4489a56302153a92e4a5f1f339 Mon Sep 17 00:00:00 2001 From: Nikita Mitasov Date: Sat, 7 Mar 2026 22:18:46 +0300 Subject: [PATCH 590/591] fix(guix): add deprecated package variable with old naming. --- mangowm.scm | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mangowm.scm b/mangowm.scm index 33d95045..7d94166d 100644 --- a/mangowm.scm +++ b/mangowm.scm @@ -61,4 +61,7 @@ inspired by dwl but aiming to be more feature-rich.") (license gpl3))) +(define-deprecated-package mangowc + mangowm-git) + mangowm-git From a4ad8d0d1945fa37063ac3d112926e061f158c73 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sun, 8 Mar 2026 08:45:56 +0800 Subject: [PATCH 591/591] fix: miss judge isdrag when resize stack in scroller --- src/layout/arrange.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/layout/arrange.h b/src/layout/arrange.h index 0284f8ca..e164a0f6 100644 --- a/src/layout/arrange.h +++ b/src/layout/arrange.h @@ -655,7 +655,7 @@ void resize_tile_scroller(Client *grabc, bool isdrag, int32_t offsetx, stack_head->scroller_proportion = new_scroller_proportion; wl_list_for_each(tc, &clients, link) { - if (new_stack_proportion != 1.0f && + if (!isdrag && new_stack_proportion != 1.0f && grabc->old_stack_proportion != 1.0f && tc != grabc && ISTILED(tc) && get_scroll_stack_head(tc) == stack_head) { tc->stack_proportion = (1.0f - new_stack_proportion) /