From 1b2aeeec7ed964712601c942e36fc451eceb9392 Mon Sep 17 00:00:00 2001 From: atheeq-rhxn Date: Fri, 13 Mar 2026 23:40:44 +0530 Subject: [PATCH 01/29] docs: add AerynOS installation --- docs/installation.md | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/docs/installation.md b/docs/installation.md index 5e0e0e88..10d2bd47 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -1,6 +1,6 @@ --- title: Installation -description: Install mangowm on Arch, Fedora, Gentoo, Guix System, NixOS, PikaOS, or build from source. +description: Install mangowm on AerynOS, Arch, Fedora, Gentoo, Guix System, NixOS, PikaOS, or build from source. --- ## Package Installation @@ -9,6 +9,18 @@ mangowm is available as a pre-built package on several distributions. Choose you --- +### AerynOS + +mangowm is available in the **AerynOS package repository**. + +You can install it using the `moss` package manager: + +```bash +sudo moss install mangowm +``` + +--- + ### Arch Linux mangowm is available in the **Arch User Repository (AUR)**. From 427cf6f89ff4dc9cc774dbe58a9b38d60b5fdbc7 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sat, 14 Mar 2026 08:05:42 +0800 Subject: [PATCH 02/29] docs: update fcitx env suggest --- docs/configuration/input.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/configuration/input.md b/docs/configuration/input.md index 3ebc0f23..6d5eefdb 100644 --- a/docs/configuration/input.md +++ b/docs/configuration/input.md @@ -136,6 +136,7 @@ To use Fcitx5 or IBus, set these environment variables in your config file. ```ini env=GTK_IM_MODULE,fcitx env=QT_IM_MODULE,fcitx +env=QT_IM_MODULES,wayland;fcitx env=SDL_IM_MODULE,fcitx env=XMODIFIERS,@im=fcitx env=GLFW_IM_MODULE,ibus From 5c52d578a8958a87d60b11b0c13a8cbb4f2b6730 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sat, 14 Mar 2026 12:24:01 +0800 Subject: [PATCH 03/29] docs: fix some sample --- docs/configuration/monitors.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/configuration/monitors.md b/docs/configuration/monitors.md index 92c2082c..5501c77f 100644 --- a/docs/configuration/monitors.md +++ b/docs/configuration/monitors.md @@ -241,7 +241,7 @@ yay -S xwayland-satellite ```ini env=DISPLAY,:2 -exec=xwayland-satellite :2 +exec-once=xwayland-satellite :2 monitorrule=name:eDP-1,width:1920,height:1080,refresh:60,x:0,y:0,scale:1.4,vrr:0,rr:0 ``` From b0ec0b4275629e915060bfc46f8586b8ad653ff7 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sat, 14 Mar 2026 12:43:49 +0800 Subject: [PATCH 04/29] docs: remove some old describe --- docs/configuration/basics.md | 2 +- docs/visuals/theming.md | 3 --- docs/window-management/overview.md | 9 +-------- 3 files changed, 2 insertions(+), 12 deletions(-) diff --git a/docs/configuration/basics.md b/docs/configuration/basics.md index dbbe45f3..22b2679e 100644 --- a/docs/configuration/basics.md +++ b/docs/configuration/basics.md @@ -48,7 +48,7 @@ source-optional=~/.config/mango/optional.conf You can check your configuration for errors without starting mangowm: ```bash -mango -p /path/to/config.conf +mango -c /path/to/config.conf -p ``` Use with `source-optional` for shared configs across different setups. diff --git a/docs/visuals/theming.md b/docs/visuals/theming.md index 789ce478..8137eb4e 100644 --- a/docs/visuals/theming.md +++ b/docs/visuals/theming.md @@ -54,6 +54,3 @@ Set the size and theme of your mouse cursor. cursor_size=24 cursor_theme=Adwaita ``` - -> **Tip:** You may also want to set the `XCURSOR_SIZE` environment variable to match: -> `env=XCURSOR_SIZE,24` diff --git a/docs/window-management/overview.md b/docs/window-management/overview.md index 290d6139..7da6e690 100644 --- a/docs/window-management/overview.md +++ b/docs/window-management/overview.md @@ -26,11 +26,4 @@ description: Configure the overview mode for window navigation. When in overview mode: - **Left mouse button** — Jump to (focus) a window. -- **Right mouse button** — Close a window. - -To enable this behavior, add the following mouse bindings to your config: - -```ini -mousebind=NONE,btn_left,toggleoverview,1 -mousebind=NONE,btn_right,killclient,0 -``` +- **Right mouse button** — Close a window. \ No newline at end of file From 23af3c55957ef16bb61dee6bf7376e810c0c03dc Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sat, 14 Mar 2026 12:50:31 +0800 Subject: [PATCH 05/29] opt: auto sync XCURSOR_SIZE and XCURSOR_THEME env from config --- docs/configuration/basics.md | 4 ++-- src/mango.c | 22 +++++++++++++++++++--- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/docs/configuration/basics.md b/docs/configuration/basics.md index 22b2679e..7afa343b 100644 --- a/docs/configuration/basics.md +++ b/docs/configuration/basics.md @@ -60,8 +60,8 @@ You can define environment variables directly within your config file. These are > **Warning:** Environment variables defined here will be **reset** every time you reload the configuration. ```ini -env=GTK_THEME,Adwaita:dark -env=XCURSOR_SIZE,24 +env=QT_IM_MODULES,wayland;fcitx +env=XMODIFIERS,@im=fcitx ``` ## Autostart diff --git a/src/mango.c b/src/mango.c index aedf1d6e..915c47b1 100644 --- a/src/mango.c +++ b/src/mango.c @@ -912,8 +912,13 @@ static KeyMode keymode = { .isdefault = true, }; -static char *env_vars[] = {"DISPLAY", "WAYLAND_DISPLAY", "XDG_CURRENT_DESKTOP", - "XDG_SESSION_TYPE", NULL}; +static char *env_vars[] = {"DISPLAY", + "WAYLAND_DISPLAY", + "XDG_CURRENT_DESKTOP", + "XDG_SESSION_TYPE", + "XCURSOR_THEME", + "XCURSOR_SIZE", + NULL}; static struct { enum wp_cursor_shape_device_v1_shape shape; struct wlr_surface *surface; @@ -5463,7 +5468,6 @@ void handle_print_status(struct wl_listener *listener, void *data) { void setup(void) { - setenv("XCURSOR_SIZE", "24", 1); setenv("XDG_CURRENT_DESKTOP", "mango", 1); parse_config(); @@ -5653,6 +5657,18 @@ void setup(void) { cursor_mgr = wlr_xcursor_manager_create(config.cursor_theme, config.cursor_size); + if (config.cursor_size > 0) { + char size_str[16]; + snprintf(size_str, sizeof(size_str), "%d", config.cursor_size); + setenv("XCURSOR_SIZE", size_str, 1); + } else { + setenv("XCURSOR_SIZE", "24", 1); + } + + if (config.cursor_theme) { + setenv("XCURSOR_THEME", config.cursor_theme, 1); + } + /* * wlr_cursor *only* displays an image on screen. It does not move * around when the pointer moves. However, we can attach input devices From 32c36ba48548f1b30e929c8a739f838bac72db2f Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sat, 14 Mar 2026 13:09:41 +0800 Subject: [PATCH 06/29] opt: optimzie code struct --- src/config/parse_config.h | 26 ++++++++++++++++---------- src/mango.c | 17 +++-------------- 2 files changed, 19 insertions(+), 24 deletions(-) diff --git a/src/config/parse_config.h b/src/config/parse_config.h index ffb8414b..6ae97406 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -3604,6 +3604,20 @@ void reapply_monitor_rules(void) { updatemons(NULL, NULL); } +void set_xcursor_env() { + if (config.cursor_size > 0) { + char size_str[16]; + snprintf(size_str, sizeof(size_str), "%d", config.cursor_size); + setenv("XCURSOR_SIZE", size_str, 1); + } else { + setenv("XCURSOR_SIZE", "24", 1); + } + + if (config.cursor_theme) { + setenv("XCURSOR_THEME", config.cursor_theme, 1); + } +} + void reapply_cursor_style(void) { if (hide_cursor_source) { wl_event_source_timer_update(hide_cursor_source, 0); @@ -3620,19 +3634,11 @@ void reapply_cursor_style(void) { cursor_mgr = NULL; } + set_xcursor_env(); + cursor_mgr = wlr_xcursor_manager_create(config.cursor_theme, config.cursor_size); - if (config.cursor_size > 0) { - char size_str[16]; - snprintf(size_str, sizeof(size_str), "%d", config.cursor_size); - setenv("XCURSOR_SIZE", size_str, 1); - } - - if (config.cursor_theme) { - setenv("XCURSOR_THEME", config.cursor_theme, 1); - } - Monitor *m = NULL; wl_list_for_each(m, &mons, link) { wlr_xcursor_manager_load(cursor_mgr, m->wlr_output->scale); diff --git a/src/mango.c b/src/mango.c index 915c47b1..3d36dd81 100644 --- a/src/mango.c +++ b/src/mango.c @@ -5653,22 +5653,11 @@ void setup(void) { * cursor images are available at all scale factors on the screen * (necessary for HiDPI support). Scaled cursors will be loaded with * each output. */ - // cursor_mgr = wlr_xcursor_manager_create(cursor_theme, 24); + + set_xcursor_env(); + cursor_mgr = wlr_xcursor_manager_create(config.cursor_theme, config.cursor_size); - - if (config.cursor_size > 0) { - char size_str[16]; - snprintf(size_str, sizeof(size_str), "%d", config.cursor_size); - setenv("XCURSOR_SIZE", size_str, 1); - } else { - setenv("XCURSOR_SIZE", "24", 1); - } - - if (config.cursor_theme) { - setenv("XCURSOR_THEME", config.cursor_theme, 1); - } - /* * wlr_cursor *only* displays an image on screen. It does not move * around when the pointer moves. However, we can attach input devices From 14fc6ca99f1eb969f7ec8edac4e836bdd0f736cc Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sat, 14 Mar 2026 21:35:09 +0800 Subject: [PATCH 07/29] docs: add some note message to monitor rule --- docs/configuration/monitors.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/configuration/monitors.md b/docs/configuration/monitors.md index 5501c77f..28ef240b 100644 --- a/docs/configuration/monitors.md +++ b/docs/configuration/monitors.md @@ -48,11 +48,13 @@ monitorrule=name:Values,Parameter:Values,Parameter:Values > **Critical:** If you use XWayland applications, **never use negative coordinates** for your monitor positions. This is a known XWayland bug that causes click events to malfunction. Always arrange your monitors starting from `0,0` and extend into positive coordinates. +> **Note:** that "name" is a regular expression. If you want an exact match, you need to add `^` and `$` to the beginning and end of the expression, for example, `^eDP-1$` matches exactly the string `eDP-1`. + ### Examples ```ini # Laptop display: 1080p, 60Hz, positioned at origin -monitorrule=name:eDP-1,width:1920,height:1080,refresh:60,x:0,y:10 +monitorrule=name:^eDP-1$,width:1920,height:1080,refresh:60,x:0,y:10 # Match by make and model instead of name monitorrule=make:Chimei Innolux Corporation,model:0x15F5,width:1920,height:1080,refresh:60,x:0,y:0 From 7a1a3f0ca4c1a9bb65bf417faf3021faf87057d9 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sun, 15 Mar 2026 14:25:57 +0800 Subject: [PATCH 08/29] opt: preset _JAVA_AWT_WM_NONREPARENTING to 1 --- src/mango.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/mango.c b/src/mango.c index 3d36dd81..df1315a1 100644 --- a/src/mango.c +++ b/src/mango.c @@ -5469,6 +5469,7 @@ void handle_print_status(struct wl_listener *listener, void *data) { void setup(void) { setenv("XDG_CURRENT_DESKTOP", "mango", 1); + setenv("_JAVA_AWT_WM_NONREPARENTING", "1", 1); parse_config(); if (cli_debug_log) { From d4321cafacd974a24fd2fe5a3c295396040379b0 Mon Sep 17 00:00:00 2001 From: atheeq-rhxn Date: Sun, 15 Mar 2026 18:05:01 +0530 Subject: [PATCH 09/29] docs: add index files & separations for better navigation --- docs/bindings/index.mdx | 15 +++++++++++++++ docs/configuration/index.mdx | 21 +++++++++++++++++++++ docs/meta.json | 3 +++ docs/visuals/index.mdx | 19 +++++++++++++++++++ docs/window-management/index.mdx | 19 +++++++++++++++++++ 5 files changed, 77 insertions(+) create mode 100644 docs/bindings/index.mdx create mode 100644 docs/configuration/index.mdx create mode 100644 docs/visuals/index.mdx create mode 100644 docs/window-management/index.mdx diff --git a/docs/bindings/index.mdx b/docs/bindings/index.mdx new file mode 100644 index 00000000..4c3a5bda --- /dev/null +++ b/docs/bindings/index.mdx @@ -0,0 +1,15 @@ +--- +title: Bindings & Input +description: Keybindings, mouse gestures, and input devices. +icon: Keyboard +--- + +Configure how you interact with mangowm using flexible keybindings and input options. + + + + + + + + diff --git a/docs/configuration/index.mdx b/docs/configuration/index.mdx new file mode 100644 index 00000000..2bcd3a7e --- /dev/null +++ b/docs/configuration/index.mdx @@ -0,0 +1,21 @@ +--- +title: Configuration +description: Configure mangowm with config files, environment variables, and autostart. +icon: Settings +--- + +Configure mangowm through config files, environment variables, and autostart. + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/meta.json b/docs/meta.json index f8aac0ca..74818a9d 100644 --- a/docs/meta.json +++ b/docs/meta.json @@ -1,13 +1,16 @@ { "title": "mangowm", "pages": [ + "---Getting Started---", "index", "installation", "quick-start", + "---Configuration---", "configuration", "visuals", "window-management", "bindings", + "---Reference---", "ipc", "faq" ] diff --git a/docs/visuals/index.mdx b/docs/visuals/index.mdx new file mode 100644 index 00000000..f71ae2f8 --- /dev/null +++ b/docs/visuals/index.mdx @@ -0,0 +1,19 @@ +--- +title: Visuals +description: Customize borders, colors, effects, and animations. +icon: Palette +--- + +Customize the look of your desktop. + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/window-management/index.mdx b/docs/window-management/index.mdx new file mode 100644 index 00000000..b96c5891 --- /dev/null +++ b/docs/window-management/index.mdx @@ -0,0 +1,19 @@ +--- +title: Window Management +description: Layouts, rules, and window behavior. +icon: LayoutGrid +--- + +Window management with layouts, rules, and scratchpad support. + + + + + + + + + + + + \ No newline at end of file From 40a518fa84f2f5e6baed6754954b8fd856de5f9f Mon Sep 17 00:00:00 2001 From: atheeq-rhxn Date: Sun, 15 Mar 2026 18:20:50 +0530 Subject: [PATCH 10/29] fix: simplify sync commit message to use source URL only --- .github/workflows/sync-website.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/sync-website.yml b/.github/workflows/sync-website.yml index 3577a65b..57c99e71 100644 --- a/.github/workflows/sync-website.yml +++ b/.github/workflows/sync-website.yml @@ -40,5 +40,5 @@ jobs: git add apps/web/content/docs git diff --staged --quiet || git commit \ -m "docs: content update from mangowm/mango" \ - -m "${{ github.event.head_commit.message }}\nSource: ${{ github.server_url }}/${{ github.repository }}/commit/${{ github.sha }}" + -m "${{ github.server_url }}/${{ github.repository }}/commit/${{ github.sha }}" git push From 0d8aedf691bb740290ad5c447d157a8d26a35ffe Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Sun, 15 Mar 2026 23:26:16 +0800 Subject: [PATCH 11/29] fix: shouldn't arrange the closing monitor --- src/layout/arrange.h | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/layout/arrange.h b/src/layout/arrange.h index 87217c7b..04f4554b 100644 --- a/src/layout/arrange.h +++ b/src/layout/arrange.h @@ -15,6 +15,9 @@ void restore_size_per(Monitor *m, Client *c) { if (!m || !c) return; + if (!m->wlr_output->enabled) + return; + wl_list_for_each(fc, &clients, link) { if (VISIBLEON(fc, m) && ISTILED(fc)) { fc->old_ismaster = fc->ismaster; @@ -811,11 +814,6 @@ void pre_caculate_before_arrange(Monitor *m, bool want_animation, int32_t master_num = 0; int32_t stack_num = 0; - if (!m) - return; - - if (!m->wlr_output->enabled) - return; m->visible_clients = 0; m->visible_tiling_clients = 0; m->visible_scroll_tiling_clients = 0; @@ -912,6 +910,12 @@ void pre_caculate_before_arrange(Monitor *m, bool want_animation, void // 17 arrange(Monitor *m, bool want_animation, bool from_view) { + if (!m) + return; + + if (!m->wlr_output->enabled) + return; + pre_caculate_before_arrange(m, want_animation, from_view, false); if (m->isoverview) { From 028cf6e49ed91de967a38516522e2f91d1a830a7 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Mon, 16 Mar 2026 11:56:41 +0800 Subject: [PATCH 12/29] bump version to 0.12.7 --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index c538c927..5d09d536 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('mango', ['c', 'cpp'], - version : '0.12.6', + version : '0.12.7', ) subdir('protocols') From 47b5c9aa2e0135247a87cb01de9e32dacc674524 Mon Sep 17 00:00:00 2001 From: beeb5k Date: Mon, 16 Mar 2026 16:46:01 +0530 Subject: [PATCH 13/29] meta: update homepage repository links --- nix/default.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nix/default.nix b/nix/default.nix index 87d4bfd0..9ca7ded5 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -68,7 +68,7 @@ stdenv.mkDerivation { meta = { mainProgram = "mango"; description = "A streamlined but feature-rich Wayland compositor"; - homepage = "https://github.com/DreamMaoMao/mango"; + homepage = "https://github.com/mangowm/mango"; license = lib.licenses.gpl3Plus; maintainers = []; platforms = lib.platforms.unix; From 6c88999adac27306ce034670adc5c7584bbbcda2 Mon Sep 17 00:00:00 2001 From: beeb5k Date: Mon, 16 Mar 2026 19:02:36 +0530 Subject: [PATCH 14/29] meta(nix): update description --- nix/default.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nix/default.nix b/nix/default.nix index 9ca7ded5..cb6497b9 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -67,7 +67,7 @@ stdenv.mkDerivation { meta = { mainProgram = "mango"; - description = "A streamlined but feature-rich Wayland compositor"; + description = "Practical and Powerful wayland compositor (dwm but wayland)"; homepage = "https://github.com/mangowm/mango"; license = lib.licenses.gpl3Plus; maintainers = []; From 17434d62624f6a6b74e00a5f9fefab10419d34b4 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Tue, 17 Mar 2026 19:44:25 +0800 Subject: [PATCH 15/29] opt: allowe space on both sides of the plus sign when parse mod key --- src/config/parse_config.h | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/config/parse_config.h b/src/config/parse_config.h index 6ae97406..7816631e 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -634,9 +634,14 @@ uint32_t parse_mod(const char *mod_str) { // 分割处理每个部分 token = strtok_r(input_copy, "+", &saveptr); while (token != NULL) { - // 去除空白 - while (*token == ' ' || *token == '\t') - token++; + // 去除前后空白 + trim_whitespace(token); + + // 如果 token 变成空字符串则跳过 + if (*token == '\0') { + token = strtok_r(NULL, "+", &saveptr); + continue; + } if (strncmp(token, "code:", 5) == 0) { // 处理 code: 形式 From 6c81384c53bdf78ab764457a5ffe2d536f1c1937 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Wed, 18 Mar 2026 23:10:15 +0800 Subject: [PATCH 16/29] feat: add tag rule option open_as_floating --- src/config/parse_config.h | 6 ++++++ src/fetch/client.h | 10 ++++------ src/mango.c | 39 +++++++++++++++++++++++++++------------ 3 files changed, 37 insertions(+), 18 deletions(-) diff --git a/src/config/parse_config.h b/src/config/parse_config.h index 7816631e..f103c4f0 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -168,6 +168,7 @@ typedef struct { float mfact; int32_t nmaster; int32_t no_render_border; + int32_t open_as_floating; int32_t no_hide; } ConfigTagRule; @@ -1904,6 +1905,7 @@ bool parse_option(Config *config, char *key, char *value) { rule->nmaster = 0; rule->mfact = 0.0f; rule->no_render_border = 0; + rule->open_as_floating = 0; rule->no_hide = 0; bool parse_error = false; @@ -1932,6 +1934,8 @@ bool parse_option(Config *config, char *key, char *value) { rule->monitor_serial = strdup(val); } else if (strcmp(key, "no_render_border") == 0) { rule->no_render_border = CLAMP_INT(atoi(val), 0, 1); + } else if (strcmp(key, "open_as_floating") == 0) { + rule->open_as_floating = CLAMP_INT(atoi(val), 0, 1); } else if (strcmp(key, "no_hide") == 0) { rule->no_hide = CLAMP_INT(atoi(val), 0, 1); } else if (strcmp(key, "nmaster") == 0) { @@ -3785,6 +3789,8 @@ void parse_tagrule(Monitor *m) { m->pertag->mfacts[tr.id] = tr.mfact; if (tr.no_render_border >= 0) m->pertag->no_render_border[tr.id] = tr.no_render_border; + if (tr.open_as_floating >= 0) + m->pertag->open_as_floating[tr.id] = tr.open_as_floating; } } diff --git a/src/fetch/client.h b/src/fetch/client.h index 0b142847..abf684c1 100644 --- a/src/fetch/client.h +++ b/src/fetch/client.h @@ -1,15 +1,12 @@ bool check_hit_no_border(Client *c) { - int32_t i; bool hit_no_border = false; if (!render_border) { hit_no_border = true; } - for (i = 0; i < config.tag_rules_count; i++) { - if (c->tags & (1 << (config.tag_rules[i].id - 1)) && - config.tag_rules[i].no_render_border) { - hit_no_border = true; - } + if (c->mon && !c->mon->isoverview && + c->mon->pertag->no_render_border[get_tags_first_tag_num(c->tags) + 1]) { + hit_no_border = true; } if (config.no_border_when_single && c && c->mon && @@ -19,6 +16,7 @@ bool check_hit_no_border(Client *c) { } return hit_no_border; } + Client *termforwin(Client *w) { Client *c = NULL; diff --git a/src/mango.c b/src/mango.c index df1315a1..01de9545 100644 --- a/src/mango.c +++ b/src/mango.c @@ -933,8 +933,9 @@ struct Pertag { uint32_t curtag, prevtag; /* current and previous tag */ int32_t nmasters[LENGTH(tags) + 1]; /* number of windows in master area */ float mfacts[LENGTH(tags) + 1]; /* mfacts per tag */ - bool no_hide[LENGTH(tags) + 1]; /* no_hide per tag */ - bool no_render_border[LENGTH(tags) + 1]; /* no_render_border per tag */ + int32_t no_hide[LENGTH(tags) + 1]; /* no_hide per tag */ + int32_t no_render_border[LENGTH(tags) + 1]; /* no_render_border per tag */ + int32_t open_as_floating[LENGTH(tags) + 1]; /* open_as_floating per tag */ const Layout *ltidxs[LENGTH(tags) + 1]; /* matrix of tags and layouts indexes */ }; @@ -1402,6 +1403,25 @@ void set_float_malposition(Client *tc) { tc->float_geom.y = tc->geom.y = y; } +void client_reset_mon_tags(Client *c, Monitor *mon, uint32_t newtags) { + if (!newtags && mon && !mon->isoverview) { + c->tags = mon->tagset[mon->seltags]; + } else if (!newtags && mon && mon->isoverview) { + c->tags = mon->ovbk_current_tagset; + } else if (newtags) { + c->tags = newtags; + } else { + c->tags = mon->tagset[mon->seltags]; + } +} + +void check_match_tag_floating_rule(Client *c, Monitor *mon) { + if (c->tags && !c->isfloating && mon && !c->swallowedby && + mon->pertag->open_as_floating[get_tags_first_tag_num(c->tags) + 1]) { + c->isfloating = 1; + } +} + void applyrules(Client *c) { /* rule matching */ const char *appid, *title; @@ -1526,6 +1546,7 @@ void applyrules(Client *c) { int32_t fullscreen_state_backup = c->isfullscreen || client_wants_fullscreen(c); + setmon(c, mon, newtags, !c->isopensilent && !(client_is_x11_popup(c) && client_should_ignore_focus(c)) && @@ -5062,7 +5083,8 @@ setfloating(Client *c, int32_t floating) { // 让当前tag中的全屏窗口退出全屏参与平铺 wl_list_for_each(fc, &clients, link) if (fc && fc != c && VISIBLEON(fc, c->mon) && - c->tags & fc->tags && ISFULLSCREEN(fc)) { + c->tags & fc->tags && ISFULLSCREEN(fc) && + old_floating_state) { clear_fullscreen_flag(fc); } } @@ -5375,15 +5397,8 @@ void setmon(Client *c, Monitor *m, uint32_t newtags, bool focus) { /* Make sure window actually overlaps with the monitor */ reset_foreign_tolevel(c); resize(c, c->geom, 0); - if (!newtags && !m->isoverview) { - c->tags = m->tagset[m->seltags]; - } else if (!newtags && m->isoverview) { - c->tags = m->ovbk_current_tagset; - } else if (newtags) { - c->tags = newtags; - } else { - c->tags = m->tagset[m->seltags]; - } + client_reset_mon_tags(c, m, newtags); + check_match_tag_floating_rule(c, m); setfloating(c, c->isfloating); setfullscreen(c, c->isfullscreen); /* This will call arrange(c->mon) */ } From 17c037171a5502e65ed934260694dc0facfaf607 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Wed, 18 Mar 2026 23:51:05 +0800 Subject: [PATCH 17/29] docs: update docs --- docs/window-management/rules.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/window-management/rules.md b/docs/window-management/rules.md index 996c172f..d37120de 100644 --- a/docs/window-management/rules.md +++ b/docs/window-management/rules.md @@ -179,6 +179,7 @@ tagrule=id:Values,monitor_make:xxx,monitor_model:xxx,Parameter:Values | `monitor_serial` | string | monitor serial | Match by monitor serial number | | `layout_name` | string | layout name | Layout name to set | | `no_render_border` | integer | `0` / `1` | Disable render border | +| `open_as_floating` | integer | `0` / `1` | New open window will be floating| | `no_hide` | integer | `0` / `1` | Not hide even if the tag is empty | | `nmaster` | integer | 0, 99 | Number of master windows | | `mfact` | float | 0.1–0.9 | Master area factor | From 949063804a7393b487225787b29d9ca3211d52f6 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Thu, 19 Mar 2026 07:36:50 +0800 Subject: [PATCH 18/29] fix: open_as_floating not match tag correctly --- src/fetch/client.h | 2 +- src/mango.c | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/fetch/client.h b/src/fetch/client.h index abf684c1..8fe831be 100644 --- a/src/fetch/client.h +++ b/src/fetch/client.h @@ -5,7 +5,7 @@ bool check_hit_no_border(Client *c) { } if (c->mon && !c->mon->isoverview && - c->mon->pertag->no_render_border[get_tags_first_tag_num(c->tags) + 1]) { + c->mon->pertag->no_render_border[get_tags_first_tag_num(c->tags)]) { hit_no_border = true; } diff --git a/src/mango.c b/src/mango.c index 01de9545..dae16898 100644 --- a/src/mango.c +++ b/src/mango.c @@ -1417,7 +1417,7 @@ void client_reset_mon_tags(Client *c, Monitor *mon, uint32_t newtags) { void check_match_tag_floating_rule(Client *c, Monitor *mon) { if (c->tags && !c->isfloating && mon && !c->swallowedby && - mon->pertag->open_as_floating[get_tags_first_tag_num(c->tags) + 1]) { + mon->pertag->open_as_floating[get_tags_first_tag_num(c->tags)]) { c->isfloating = 1; } } @@ -4063,9 +4063,9 @@ void init_client_properties(Client *c) { c->master_mfact_per = 0.0f; c->master_inner_per = 0.0f; c->stack_inner_per = 0.0f; - c->old_stack_inner_per = 1.0f; - c->old_master_inner_per = 1.0f; - c->old_master_mfact_per = 1.0f; + c->old_stack_inner_per = 0.0f; + c->old_master_inner_per = 0.0f; + c->old_master_mfact_per = 0.0f; c->isterm = 0; c->allow_csd = 0; c->force_maximize = 0; @@ -5098,7 +5098,7 @@ setfloating(Client *c, int32_t floating) { layers[c->isfloating ? LyrTop : LyrTile]); } - if (!c->isfloating && old_floating_state) { + if (!c->isfloating && old_floating_state && (c->old_stack_inner_per > 0.0f || c->old_master_inner_per > 0.0f)) { restore_size_per(c->mon, c); } From c2559f6c7cd18bfc1808183af8738deacef23862 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Thu, 19 Mar 2026 07:56:29 +0800 Subject: [PATCH 19/29] feat: add dispatch toggle_all_floating --- docs/bindings/keys.md | 1 + src/config/parse_config.h | 2 ++ src/dispatch/bind_declare.h | 1 + src/dispatch/bind_define.h | 16 ++++++++++++++++ src/mango.c | 3 ++- 5 files changed, 22 insertions(+), 1 deletion(-) diff --git a/docs/bindings/keys.md b/docs/bindings/keys.md index 64ba64b7..4c318fb3 100644 --- a/docs/bindings/keys.md +++ b/docs/bindings/keys.md @@ -90,6 +90,7 @@ bindr=Super,Super_L,spawn,rofi -show run | :--- | :--- | :--- | | `killclient` | - | Close the focused window. | | `togglefloating` | - | Toggle floating state. | +| `toggle_all_floating` | - | Toggle all visible clients floating state. | | `togglefullscreen` | - | Toggle fullscreen. | | `togglefakefullscreen` | - | Toggle "fake" fullscreen (remains constrained). | | `togglemaximizescreen` | - | Maximize window (keep decoration/bar). | diff --git a/src/config/parse_config.h b/src/config/parse_config.h index f103c4f0..fda401d9 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -1202,6 +1202,8 @@ FuncType parse_func_name(char *func_name, Arg *arg, char *arg_value, } else if (strcmp(func_name, "scroller_stack") == 0) { func = scroller_stack; (*arg).i = parse_direction(arg_value); + } else if (strcmp(func_name, "toggle_all_floating") == 0) { + func = toggle_all_floating; } else { return NULL; } diff --git a/src/dispatch/bind_declare.h b/src/dispatch/bind_declare.h index 7dced532..dbeebd33 100644 --- a/src/dispatch/bind_declare.h +++ b/src/dispatch/bind_declare.h @@ -70,3 +70,4 @@ int32_t disable_monitor(const Arg *arg); int32_t enable_monitor(const Arg *arg); int32_t toggle_monitor(const Arg *arg); int32_t scroller_stack(const Arg *arg); +int32_t toggle_all_floating(const Arg *arg); \ No newline at end of file diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index 449adf3b..d6854a0c 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -1866,3 +1866,19 @@ int32_t scroller_stack(const Arg *arg) { arrange(selmon, false, false); return 0; } + +int32_t toggle_all_floating(const Arg *arg) { + if (!selmon || !selmon->sel) + return 0; + + Client *c = NULL; + bool should_floating = !selmon->sel->isfloating; + wl_list_for_each(c, &clients, link) { + if (VISIBLEON(c, selmon)) { + if (c->isfloating != should_floating) { + setfloating(c, should_floating); + } + } + } + return 0; +} diff --git a/src/mango.c b/src/mango.c index dae16898..9dac7bb4 100644 --- a/src/mango.c +++ b/src/mango.c @@ -5098,7 +5098,8 @@ setfloating(Client *c, int32_t floating) { layers[c->isfloating ? LyrTop : LyrTile]); } - if (!c->isfloating && old_floating_state && (c->old_stack_inner_per > 0.0f || c->old_master_inner_per > 0.0f)) { + if (!c->isfloating && old_floating_state && + (c->old_stack_inner_per > 0.0f || c->old_master_inner_per > 0.0f)) { restore_size_per(c->mon, c); } From 6eb3378c0c12ec0dadace80c70f45b24d66e1979 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Thu, 19 Mar 2026 08:44:42 +0800 Subject: [PATCH 20/29] opt: dont restore size per whe toggle_all_floating --- src/dispatch/bind_define.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index d6854a0c..68309356 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -1873,8 +1873,16 @@ int32_t toggle_all_floating(const Arg *arg) { Client *c = NULL; bool should_floating = !selmon->sel->isfloating; + wl_list_for_each(c, &clients, link) { if (VISIBLEON(c, selmon)) { + + if (c->isfloating && !should_floating) { + c->old_master_inner_per = 0.0f; + c->old_stack_inner_per = 0.0f; + set_size_per(selmon, c); + } + if (c->isfloating != should_floating) { setfloating(c, should_floating); } From c776356efe165dca09742f78f2a018e065b825be Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Thu, 19 Mar 2026 10:12:36 +0800 Subject: [PATCH 21/29] fix: size per not restroe when togglefloating --- src/mango.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/mango.c b/src/mango.c index 9dac7bb4..dcfd57ec 100644 --- a/src/mango.c +++ b/src/mango.c @@ -1554,6 +1554,11 @@ void applyrules(Client *c) { (!c->istagsilent || !newtags || newtags & mon->tagset[mon->seltags])); + if (!c->isfloating) { + c->old_stack_inner_per = c->stack_inner_per; + c->old_master_inner_per = c->master_inner_per; + } + if (c->mon && !(c->mon == selmon && c->tags & c->mon->tagset[c->mon->seltags]) && !c->isopensilent && !c->istagsilent) { @@ -5118,6 +5123,12 @@ setfloating(Client *c, int32_t floating) { } arrange(c->mon, false, false); + + if (!c->isfloating) { + c->old_master_inner_per = c->master_inner_per; + c->old_stack_inner_per = c->stack_inner_per; + } + setborder_color(c); printstatus(); } From ca665cc6f8f51b6c7cfcf49ff352327085b25337 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Thu, 19 Mar 2026 15:27:43 +0800 Subject: [PATCH 22/29] opt: optimize state change between flating maximizescrenn and fullscreen --- src/mango.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/mango.c b/src/mango.c index dcfd57ec..826294bd 100644 --- a/src/mango.c +++ b/src/mango.c @@ -5041,12 +5041,12 @@ setfloating(Client *c, int32_t floating) { if (floating == 1 && c != grabc) { - if (c->isfullscreen || c->ismaximizescreen) { - c->isfullscreen = 0; // 清除窗口全屏标志 - c->ismaximizescreen = 0; - c->bw = c->isnoborder ? 0 : config.borderpx; + if (c->isfullscreen) { + c->isfullscreen = 0; + client_set_fullscreen(c, 0); } + c->ismaximizescreen = 0; exit_scroller_stack(c); // 重新计算居中的坐标 @@ -5175,8 +5175,10 @@ void setmaximizescreen(Client *c, int32_t maximizescreen) { if (maximizescreen) { - if (c->isfullscreen) - setfullscreen(c, 0); + if (c->isfullscreen) { + c->isfullscreen = 0; + client_set_fullscreen(c, 0); + } exit_scroller_stack(c); @@ -5243,9 +5245,8 @@ void setfullscreen(Client *c, int32_t fullscreen) // 用自定义全屏代理自 client_set_fullscreen(c, fullscreen); if (fullscreen) { - if (c->ismaximizescreen) - setmaximizescreen(c, 0); + c->ismaximizescreen = 0; exit_scroller_stack(c); if (c->isfloating) From deb47e8ab957550e376c3fb0dfb2c6aeab1ce9fd Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Thu, 19 Mar 2026 17:02:48 +0800 Subject: [PATCH 23/29] opt: not need to reset float_geom in setfullscreen and setmaximizescreen --- src/mango.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/mango.c b/src/mango.c index 826294bd..93c049f4 100644 --- a/src/mango.c +++ b/src/mango.c @@ -5182,9 +5182,6 @@ void setmaximizescreen(Client *c, int32_t maximizescreen) { exit_scroller_stack(c); - if (c->isfloating) - c->float_geom = c->geom; - maximizescreen_box.x = c->mon->w.x + config.gappoh; maximizescreen_box.y = c->mon->w.y + config.gappov; maximizescreen_box.width = c->mon->w.width - 2 * config.gappoh; @@ -5249,9 +5246,6 @@ void setfullscreen(Client *c, int32_t fullscreen) // 用自定义全屏代理自 c->ismaximizescreen = 0; exit_scroller_stack(c); - if (c->isfloating) - c->float_geom = c->geom; - c->isfakefullscreen = 0; c->bw = 0; From ab6e8a6545e37b0ff78434896b7d84a5b2e6ec32 Mon Sep 17 00:00:00 2001 From: Kiki <138850119+kiikii-dev@users.noreply.github.com> Date: Thu, 19 Mar 2026 16:29:15 +0100 Subject: [PATCH 24/29] Add playback section to keys.md Under the "Media Controls" section on "keys.md", add playback keybindings through the Playerctl command-line utility. --- docs/bindings/keys.md | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/docs/bindings/keys.md b/docs/bindings/keys.md index 4c318fb3..b3a4ab64 100644 --- a/docs/bindings/keys.md +++ b/docs/bindings/keys.md @@ -195,6 +195,16 @@ bind=NONE,XF86AudioMute,spawn,wpctl set-mute @DEFAULT_SINK@ toggle bind=SHIFT,XF86AudioMute,spawn,wpctl set-mute @DEFAULT_SOURCE@ toggle ``` +#### Playback + +Requires: `playerctl` + +```ini +bind=NONE,XF86AudioNext,spawn,playerctl next +bind=NONE,XF86AudioPrev,spawn,playerctl previous +bind=NONE,XF86AudioPlay,spawn,playerctl play-pause +``` + ### Floating Window Movement | Command | Param | Description | @@ -202,4 +212,4 @@ bind=SHIFT,XF86AudioMute,spawn,wpctl set-mute @DEFAULT_SOURCE@ toggle | `smartmovewin` | `left/right/up/down` | Move floating window by snap distance. | | `smartresizewin` | `left/right/up/down` | Resize floating window by snap distance. | | `movewin` | `(x,y)` | Move floating window. | -| `resizewin` | `(width,height)` | Resize window. | \ No newline at end of file +| `resizewin` | `(width,height)` | Resize window. | From c55e0693645503ae270fe12a51e498d0471ced20 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Fri, 20 Mar 2026 09:15:47 +0800 Subject: [PATCH 25/29] docs: update wlroots build message --- README.md | 2 +- docs/installation.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b927b920..843780ba 100644 --- a/README.md +++ b/README.md @@ -137,7 +137,7 @@ And then rebuild your system. ## Other ```bash -git clone -b 0.19.2 https://gitlab.freedesktop.org/wlroots/wlroots.git +git clone -b 0.19.3 https://gitlab.freedesktop.org/wlroots/wlroots.git cd wlroots meson build -Dprefix=/usr sudo ninja -C build install diff --git a/docs/installation.md b/docs/installation.md index 10d2bd47..d3b9afaa 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -214,7 +214,7 @@ You will need to build `wlroots` and `scenefx` manually as well. 1. **Build wlroots** Clone and install the specific version required (check README for latest version). ```bash - git clone -b 0.19.2 https://gitlab.freedesktop.org/wlroots/wlroots.git + git clone -b 0.19.3 https://gitlab.freedesktop.org/wlroots/wlroots.git cd wlroots meson build -Dprefix=/usr sudo ninja -C build install From ccefa572e1cd221bb3d8b4edc44bf6c91f5be6f6 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Fri, 20 Mar 2026 22:43:09 +0800 Subject: [PATCH 26/29] fix: make sure run the last frame even if the animation time is unreasonable --- src/animation/client.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/animation/client.h b/src/animation/client.h index 8c9c3915..e94f872a 100644 --- a/src/animation/client.h +++ b/src/animation/client.h @@ -723,6 +723,8 @@ void client_animation_next_tick(Client *c) { c->is_pending_open_animation = false; + client_apply_clip(c, factor); + if (animation_passed >= 1.0) { // clear the open action state @@ -752,8 +754,6 @@ void client_animation_next_tick(Client *c) { // end flush in next frame, not the current frame c->need_output_flush = false; } - - client_apply_clip(c, factor); } void init_fadeout_client(Client *c) { From 0232dcda823ac672f308598dfbfaf0dcc4595843 Mon Sep 17 00:00:00 2001 From: quadratic Date: Sun, 22 Mar 2026 19:50:30 +0100 Subject: [PATCH 27/29] mmsg: fix -o flag causing subsequent flags to be ignored when used with -g --- mmsg/mmsg.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mmsg/mmsg.c b/mmsg/mmsg.c index 4e0e1d8c..83b116da 100644 --- a/mmsg/mmsg.c +++ b/mmsg/mmsg.c @@ -569,12 +569,12 @@ int32_t main(int32_t argc, char *argv[]) { mode = WATCH; break; case 'o': - if (mode == SET) + if (mode == GET || mode == WATCH) + oflag = 1; + else if (mode == SET) output_name = EARGF(usage()); else output_name = ARGF(); - if (!output_name) - oflag = 1; break; case 't': tflag = 1; From 064bcad6f73d320c700afb58d8b8e909dec2b170 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Mon, 23 Mar 2026 10:01:34 +0800 Subject: [PATCH 28/29] opt: optimize fullscreen state change --- src/mango.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/mango.c b/src/mango.c index 93c049f4..f8f323d0 100644 --- a/src/mango.c +++ b/src/mango.c @@ -5243,9 +5243,12 @@ void setfullscreen(Client *c, int32_t fullscreen) // 用自定义全屏代理自 if (fullscreen) { - c->ismaximizescreen = 0; - exit_scroller_stack(c); + if (c->ismaximizescreen) { + client_set_maximized(c, false); + c->ismaximizescreen = 0; + } + exit_scroller_stack(c); c->isfakefullscreen = 0; c->bw = 0; From e6429f873329597df4804a8c3db7ac4a2e9aaae9 Mon Sep 17 00:00:00 2001 From: DreamMaoMao <2523610504@qq.com> Date: Mon, 23 Mar 2026 22:15:28 +0800 Subject: [PATCH 29/29] opt: not unset maximize state if enable force_maximize --- mmsg/mmsg.c | 4 ++-- src/mango.c | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/mmsg/mmsg.c b/mmsg/mmsg.c index 83b116da..0191a635 100644 --- a/mmsg/mmsg.c +++ b/mmsg/mmsg.c @@ -569,8 +569,8 @@ int32_t main(int32_t argc, char *argv[]) { mode = WATCH; break; case 'o': - if (mode == GET || mode == WATCH) - oflag = 1; + if (mode == GET || mode == WATCH) + oflag = 1; else if (mode == SET) output_name = EARGF(usage()); else diff --git a/src/mango.c b/src/mango.c index f8f323d0..7a419cdd 100644 --- a/src/mango.c +++ b/src/mango.c @@ -5243,11 +5243,12 @@ void setfullscreen(Client *c, int32_t fullscreen) // 用自定义全屏代理自 if (fullscreen) { - if (c->ismaximizescreen) { + if (c->ismaximizescreen && !c->force_maximize) { client_set_maximized(c, false); - c->ismaximizescreen = 0; } + c->ismaximizescreen = 0; + exit_scroller_stack(c); c->isfakefullscreen = 0;