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 01/26] 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 0000000..94e80c0 --- /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 2c893c3345b4715f2d34eb23df41738267a9d99c Mon Sep 17 00:00:00 2001 From: 4zv4l <4zv4l@protonmail.com> Date: Sun, 30 Nov 2025 23:19:55 +0800 Subject: [PATCH 02/26] 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 94e80c0..9c55d43 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 03/26] 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 f896673..3b52bd4 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 0a7613d..ce6617d 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 3893a4c..b6dd27d 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 4a87c60..ce22e31 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 04/26] 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 4c8d8d3..e93b3e6 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 67f4c10..b4f70e0 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 2ff6744..0f662d6 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 e36ddd1..57e0c14 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 0479c6d..4da82c5 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 ed743a8..7b45315 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 ce22e31..45a0e64 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 05/26] 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 4da82c5..2e5549b 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 45a0e64..ae84091 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 06/26] 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 9780ac6..7818c36 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 07/26] 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 d4e0e51..8ff53cc 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 3f80e9f..2d781b3 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 e1d285b..a2a733b 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 ae84091..1bd2c1f 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 08/26] 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 3b52bd4..4a910aa 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 ce6617d..a9d6248 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 62a3227..169ab11 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 09/26] 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 b72977d..fd94bef 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 10/26] 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 fd94bef..f2676a1 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 11/26] 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 f2676a1..6085565 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 12/26] 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 2e5549b..8f11f14 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 13/26] 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 b4f70e0..b5b7c5d 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 14/26] 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 b5b7c5d..eb9ff4e 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 15/26] 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 92e264e..6544cab 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 16/26] 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 0bc8488..e31e89d 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 17/26] 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 e31e89d..5dc0edd 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 4a910aa..a7805af 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 1bd2c1f..766e098 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 18/26] 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 460328e..9f197ab 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 19/26] 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 766e098..c96126f 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 20/26] 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 c96126f..c538303 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 21/26] 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 e93b3e6..5483a14 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 8f11f14..08659c3 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 7b45315..e13be4d 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 c538303..291b815 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 22/26] 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 8f11f14..da9cc8d 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 7b45315..cae8814 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 c96126f..0ba3eab 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 23/26] 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 b025539..ac86bf9 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 24/26] 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 ac86bf9..5a9a5ad 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 25/26] 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 a371a42..31f514f 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 5a9a5ad..4d685ec 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 26/26] 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 eb9ff4e..596336f 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 1d66f34..074b522 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 4d685ec..4570a20 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;